THRIFT-4547: Swift crosstests (#2670)
Co-authored-by: Jiayu Liu <Jimexist@users.noreply.github.com>
diff --git a/test/swift/CrossTests/Sources/TestClient/main.swift b/test/swift/CrossTests/Sources/TestClient/main.swift
new file mode 100644
index 0000000..6817981
--- /dev/null
+++ b/test/swift/CrossTests/Sources/TestClient/main.swift
@@ -0,0 +1,400 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+import Foundation
+import Thrift
+import Common
+import XCTest
+
+enum Error: Int32 {
+ case baseTypes = 1
+ case structs = 2
+ case containers = 4
+ case exceptions = 8
+ case unknown = 64
+ case timeout = 128
+}
+
+class TestClient {
+ var client: ThriftTestClient
+ var resultCode: Int32 = 0
+
+ public init(parameters: TestClientParameters) throws {
+ let transport = try TestClient.getTransport(parameters: parameters)
+ let proto = try TestClient.getProtocol(parameters: parameters, transport: transport)
+ client = ThriftTestClient(inoutProtocol: proto)
+ }
+
+ static func getTransport(parameters: TestClientParameters) throws -> TTransport {
+ let socketTransport = try TSocketTransport(hostname: parameters.host!, port: parameters.port!)
+ if parameters.transport == .framed {
+ return TFramedTransport(transport: socketTransport)
+ }
+
+ if parameters.transport == .buffered {
+ return socketTransport
+ }
+
+ throw ParserError.unsupportedOption
+ }
+
+ static func getProtocol(parameters: TestClientParameters, transport: TTransport) throws -> TProtocol {
+ if parameters.proto == .binary {
+ return TBinaryProtocol(on: transport)
+ }
+
+ if parameters.proto == .compact {
+ return TCompactProtocol(on: transport)
+ }
+
+ throw ParserError.unsupportedOption
+ }
+
+ func run() throws {
+ do {
+ try testVoid()
+ try testString()
+ try testBool()
+ try testByte()
+ try testI32()
+ try testI64()
+ try testDouble()
+ try testBinary()
+ try testStruct()
+ try testNest()
+ try testMap()
+ try testSet()
+ try testList()
+ try testEnum()
+ try testTypedef()
+ try testMapMap()
+ try testInsanity()
+ try testMulti()
+ try testException()
+ try testMultiException()
+ // Swift generator doesn't yet support one way functions (THRIFT-5468)
+ /*try testOneway()
+ try testOnewayThenNormal()*/
+ try testUuid()
+
+ } catch let error {
+ print("\(error)")
+ resultCode |= Error.unknown.rawValue
+ }
+ exit(resultCode)
+ }
+
+ func testVoid() throws {
+ print("testVoid")
+ try client.testVoid()
+ }
+
+
+ func testString1(_ s1: String) throws {
+ print("testString(\(s1))")
+ let r1 = try client.testString(thing: s1)
+ print(r1)
+ if s1 != r1 {
+ resultCode |= Error.baseTypes.rawValue
+ }
+ }
+
+ func testString() throws {
+ try testString1(String(repeating: "Python", count: 20))
+ try testString1("")
+ try testString1("\t\n/\\\\\r{}:パイソン")
+ try testString1("""
+Afrikaans, Alemannisch, Aragonés, العربية, مصرى,
+Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška,
+Беларуская, Беларуская (тарашкевіца), Български, Bamanankan,
+বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн,
+Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg,
+Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English,
+Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt,
+Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego,
+Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski,
+Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia,
+Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa,
+ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар,
+Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino,
+Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa
+Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, مازِرونی, Bahasa
+Melayu, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands,
+Norsk (nynorsk), Norsk (bokmål), Nouormand, Diné bizaad,
+Occitan, Иронау, Papiamentu, Deitsch, Polski, پنجابی, پښتو,
+Norfuk / Pitkern, Português, Runa Simi, Rumantsch, Romani, Română,
+Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple
+English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk,
+Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog,
+Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük,
+Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文,
+Bân-lâm-gú, 粵語
+""")
+ }
+
+ func testBool1(_ s1: Bool) throws {
+ print("testBool(\(s1))")
+ let r1 = try client.testBool(thing: s1)
+ print(r1)
+ if s1 != r1 {
+ resultCode |= Error.baseTypes.rawValue
+ }
+ }
+
+ func testBool() throws {
+ try testBool1(true)
+ try testBool1(false)
+ }
+
+ func testByte() throws {
+ print("testByte")
+ if try client.testByte(thing: 63) != 63 {
+ resultCode |= Error.baseTypes.rawValue
+ }
+ if try client.testByte(thing: -127) != -127 {
+ resultCode |= Error.baseTypes.rawValue
+ }
+ }
+
+ func testI32() throws {
+ print("testI32")
+ if try client.testI32(thing: -1) != -1 {
+ resultCode |= Error.baseTypes.rawValue
+ }
+ if try client.testI32(thing: 0) != 0 {
+ resultCode |= Error.baseTypes.rawValue
+ }
+ }
+
+ func testI64() throws {
+ print("testI64")
+ if try client.testI64(thing: 1) != 1 ||
+ client.testI64(thing: -34359738368) != -34359738368 {
+ resultCode |= Error.baseTypes.rawValue
+ }
+ }
+
+ func testDouble() throws {
+ print("testDouble")
+ for testValue in [-5.235098235, 0, -1, -0.000341012439638598279] {
+ if try client.testDouble(thing: testValue) != testValue {
+ resultCode |= Error.baseTypes.rawValue
+ }
+ }
+ }
+
+ func testBinary() throws {
+ print("testBinary")
+ let val = Data(Array(0...255))
+ if try client.testBinary(thing: val) != val {
+ resultCode |= Error.baseTypes.rawValue
+ }
+ }
+
+ func testStruct() throws {
+ print("testStruct")
+ let x = Xtruct(string_thing: "Zero", byte_thing: 1, i32_thing: -3, i64_thing: -5)
+ if try client.testStruct(thing: x) != x {
+ resultCode |= Error.structs.rawValue
+ }
+ }
+
+ func testNest() throws {
+ print("testNest")
+ let inner = Xtruct(string_thing: "Zero", byte_thing: 1, i32_thing: -3, i64_thing: -5)
+ let x = Xtruct2(byte_thing: 0, struct_thing: inner, i32_thing: 0)
+ if try client.testNest(thing: x) != x {
+ resultCode |= Error.structs.rawValue
+ }
+ }
+
+ func testMap() throws {
+ print("testMap")
+ let x = TMap<Int32, Int32>([0: 1, 1: 2, 2: 3, 3: 4, -1: -2])
+ if try client.testMap(thing: x) != x {
+ resultCode |= Error.containers.rawValue
+ }
+ }
+
+ func testSet() throws {
+ print("testSet")
+ let x = TSet<Int32>([8, 1, 42])
+ if try client.testSet(thing: x) != x {
+ resultCode |= Error.containers.rawValue
+ }
+ }
+
+ func testList() throws {
+ print("testList")
+ let x = TList<Int32>([1, 4, 9, -42])
+ if try client.testList(thing: x) != x {
+ resultCode |= Error.containers.rawValue
+ }
+ }
+
+ func testEnum() throws {
+ print("testEnum")
+ let x = Numberz.five
+ if try client.testEnum(thing: x) != x {
+ resultCode |= Error.containers.rawValue
+ }
+ }
+
+ func testTypedef() throws {
+ print("testTypedef")
+ let x = UserId(bitPattern: 0xffffffffffffff)
+ if try client.testTypedef(thing: x) != x {
+ resultCode |= Error.containers.rawValue
+ }
+ }
+
+ func testMapMap() throws {
+ print("testMapMap")
+ let x = TMap<Int32, TMap<Int32, Int32>>([
+ -4: [-4: -4, -3: -3, -2: -2, -1: -1],
+ 4: [4: 4, 3: 3, 2: 2, 1: 1]
+ ])
+ if try client.testMapMap(hello: 42) != x {
+ resultCode |= Error.containers.rawValue
+ }
+ }
+
+ func testInsanity() throws {
+ print("testInsanity()")
+ let argument = Insanity(userMap: [.eight: 8], xtructs: [])
+ let expected = TMap<UserId, TMap<Numberz, Insanity>>([
+ 1: [
+ .two: argument,
+ .three: argument
+ ],
+ 2: [
+ .six: Insanity(userMap: [:], xtructs: [])
+ ]
+ ])
+ if try client.testInsanity(argument: argument) != expected {
+ resultCode |= Error.containers.rawValue
+ }
+ }
+
+ func testMulti() throws {
+ print("testMulti")
+ let x = Xtruct(string_thing: "Hello2", byte_thing: 74, i32_thing: 0xff00ff, i64_thing: 0xffffffffd0d0)
+ if try client.testMulti(arg0: x.byte_thing, arg1: x.i32_thing, arg2: x.i64_thing, arg3: .init([0: "abc"]), arg4: Numberz.five, arg5: 0xf0f0f0) != x {
+ resultCode |= Error.containers.rawValue
+ }
+ }
+
+ func testException() throws {
+ print("testException")
+ try client.testException(arg: "Safe")
+ do {
+ try client.testException(arg: "Xception")
+ resultCode |= Error.exceptions.rawValue
+ } catch let error as Xception {
+ guard error.errorCode == 1001, error.message == "Xception" else {
+ resultCode |= Error.exceptions.rawValue
+ return
+ }
+ } catch {
+ resultCode |= Error.exceptions.rawValue
+ }
+
+ do {
+ try client.testException(arg: "TException")
+ resultCode |= Error.exceptions.rawValue
+ } catch is TError {
+
+ } catch {
+ resultCode |= Error.exceptions.rawValue
+ }
+
+ try client.testException(arg: "success")
+ }
+
+ func testMultiException() throws {
+ print("testMultiException")
+ do {
+ _ = try client.testMultiException(arg0: "Xception", arg1: "ignore")
+ } catch let error as Xception {
+ guard error.errorCode == 1001, error.message == "This is an Xception" else {
+ resultCode |= Error.exceptions.rawValue
+ return
+ }
+ } catch {
+ resultCode |= Error.exceptions.rawValue
+ }
+
+ do {
+ _ = try client.testMultiException(arg0: "Xception2", arg1: "ignore")
+ } catch let error as Xception2 {
+ guard error.errorCode == 2002, error.struct_thing.string_thing == "This is an Xception2" else {
+ resultCode |= Error.exceptions.rawValue
+ return
+ }
+ }
+
+ let y = try client.testMultiException(arg0: "success", arg1: "foobar")
+ if y.string_thing != "foobar" {
+ resultCode |= Error.exceptions.rawValue
+ }
+ }
+
+ // Swift generator doesn't yet support one way functions (THRIFT-5468)
+ /*func testOneway() throws {
+ print("testOneway")
+ let start = CACurrentMediaTime()
+ try client.testOneway(secondsToSleep: 1)
+ let end = CACurrentMediaTime()
+ let duration = end - start
+ let delta = abs(1 - duration)
+ print("oneway sleep took \(end - start) sec")
+
+ guard delta < 0.5 else {
+ print("oneway sleep took \(end - start) sec")
+ resultCode |= Error.unknown.rawValue
+ return
+ }
+ }
+
+ func testOnewayThenNormal() throws {
+ print("testOnewayThenNormal")
+ try client.testOneway(secondsToSleep: 1)
+ if try client.testString(thing: "Swift") != "Swift" {
+ resultCode |= Error.baseTypes.rawValue
+ }
+ }*/
+
+ func testUuid() throws {
+ let uuid = UUID()
+ guard try client.testUuid(thing: uuid) == uuid else {
+ resultCode |= Error.baseTypes.rawValue
+ return
+ }
+ }
+}
+
+
+let parameters = try TestClientParameters(arguments: CommandLine.arguments)
+
+if parameters.showHelp {
+ parameters.printHelp()
+ exit(0)
+}
+
+Thread.sleep(forTimeInterval: 1)
+
+try TestClient(parameters: parameters).run()