THRIFT-4547: Swift crosstests (#2670)

Co-authored-by: Jiayu Liu <Jimexist@users.noreply.github.com>
diff --git a/test/swift/CrossTests/Sources/TestServer/ThriftTestService.swift b/test/swift/CrossTests/Sources/TestServer/ThriftTestService.swift
new file mode 100644
index 0000000..5548e90
--- /dev/null
+++ b/test/swift/CrossTests/Sources/TestServer/ThriftTestService.swift
@@ -0,0 +1,389 @@
+// 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
+
+class ThriftTestImpl : ThriftTest {
+
+  /// Prints "testVoid()" and returns nothing.
+  ///
+  /// - Throws: 
+  func testVoid() throws {
+    print("testVoid()")
+  }
+
+  /// Prints 'testString("%s")' with thing as '%s'
+  /// @param string thing - the string to print
+  /// @return string - returns the string 'thing'
+  ///
+  /// - Parameters:
+  ///   - thing: 
+  /// - Returns: String
+  /// - Throws: 
+  func testString(thing: String) throws -> String {
+    print("testString(\"\(thing)\")")
+    return thing
+  }
+
+  /// Prints 'testBool("%s")' where '%s' with thing as 'true' or 'false'
+  /// @param bool  thing - the bool data to print
+  /// @return bool  - returns the bool 'thing'
+  ///
+  /// - Parameters:
+  ///   - thing: 
+  /// - Returns: Bool
+  /// - Throws: 
+  func testBool(thing: Bool) throws -> Bool {
+    print("testBool\"(\(thing ? "true" : "false")\")")
+    return thing
+  }
+
+  /// Prints 'testByte("%d")' with thing as '%d'
+  /// The types i8 and byte are synonyms, use of i8 is encouraged, byte still exists for the sake of compatibility.
+  /// @param byte thing - the i8/byte to print
+  /// @return i8 - returns the i8/byte 'thing'
+  ///
+  /// - Parameters:
+  ///   - thing: 
+  /// - Returns: Int8
+  /// - Throws: 
+  func testByte(thing: Int8) throws -> Int8 {
+    print("testByte(\"\(thing)\")")
+    return thing
+  }
+
+
+  /// Prints 'testI32("%d")' with thing as '%d'
+  /// @param i32 thing - the i32 to print
+  /// @return i32 - returns the i32 'thing'
+  ///
+  /// - Parameters:
+  ///   - thing: 
+  /// - Returns: Int32
+  /// - Throws: 
+  func testI32(thing: Int32) throws -> Int32 {
+    print("testI32(\"\(thing)\")")
+    return thing
+  }
+
+
+  /// Prints 'testI64("%d")' with thing as '%d'
+  /// @param i64 thing - the i64 to print
+  /// @return i64 - returns the i64 'thing'
+  ///
+  /// - Parameters:
+  ///   - thing: 
+  /// - Returns: Int64
+  /// - Throws: 
+  func testI64(thing: Int64) throws -> Int64 {
+    print("testI64(\"\(thing)\")")
+    return thing
+  }
+
+
+  /// Prints 'testDouble("%f")' with thing as '%f'
+  /// @param double thing - the double to print
+  /// @return double - returns the double 'thing'
+  ///
+  /// - Parameters:
+  ///   - thing: 
+  /// - Returns: Double
+  /// - Throws: 
+  func testDouble(thing: Double) throws -> Double {
+    print("testDouble(\"\(thing)\")")
+    return thing
+  }
+
+
+  /// Prints 'testBinary("%s")' where '%s' is a hex-formatted string of thing's data
+  /// @param binary  thing - the binary data to print
+  /// @return binary  - returns the binary 'thing'
+  ///
+  /// - Parameters:
+  ///   - thing: 
+  /// - Returns: Data
+  /// - Throws: 
+  func testBinary(thing: Data) throws -> Data {
+    print("testBinary(\"\(thing)\")")
+    return thing
+  }
+
+
+  /// Prints 'testStruct("{%s}")' where thing has been formatted into a string of comma separated values
+  /// @param Xtruct thing - the Xtruct to print
+  /// @return Xtruct - returns the Xtruct 'thing'
+  ///
+  /// - Parameters:
+  ///   - thing: 
+  /// - Returns: Xtruct
+  /// - Throws: 
+  func testStruct(thing: Xtruct) throws -> Xtruct {
+    print("testStruct({\([thing.string_thing, "\(thing.byte_thing)", "\(thing.i32_thing)", "\(thing.i64_thing)"].joined(separator: ", "))})")
+    return thing
+  }
+
+
+  /// Prints 'testNest("{%s}")' where thing has been formatted into a string of the nested struct
+  /// @param Xtruct2 thing - the Xtruct2 to print
+  /// @return Xtruct2 - returns the Xtruct2 'thing'
+  ///
+  /// - Parameters:
+  ///   - thing: 
+  /// - Returns: Xtruct2
+  /// - Throws: 
+  func testNest(thing: Xtruct2) throws -> Xtruct2 {
+    print("testNest(\(thing)")
+    return thing
+  }
+
+
+  /// Prints 'testMap("{%s")' where thing has been formatted into a string of 'key => value' pairs
+  ///  separated by commas and new lines
+  /// @param map<i32,i32> thing - the map<i32,i32> to print
+  /// @return map<i32,i32> - returns the map<i32,i32> 'thing'
+  ///
+  /// - Parameters:
+  ///   - thing: 
+  /// - Returns: TMap<Int32, Int32>
+  /// - Throws: 
+  func testMap(thing: TMap<Int32, Int32>) throws -> TMap<Int32, Int32> {
+    print("testMap(\(thing)")
+    return thing
+  }
+
+
+  /// Prints 'testStringMap("{%s}")' where thing has been formatted into a string of 'key => value' pairs
+  ///  separated by commas and new lines
+  /// @param map<string,string> thing - the map<string,string> to print
+  /// @return map<string,string> - returns the map<string,string> 'thing'
+  ///
+  /// - Parameters:
+  ///   - thing: 
+  /// - Returns: TMap<String, String>
+  /// - Throws: 
+  func testStringMap(thing: TMap<String, String>) throws -> TMap<String, String> {
+    print("testStringMap(\(thing)")
+    return thing
+  }
+
+
+  /// Prints 'testSet("{%s}")' where thing has been formatted into a string of values
+  ///  separated by commas and new lines
+  /// @param set<i32> thing - the set<i32> to print
+  /// @return set<i32> - returns the set<i32> 'thing'
+  ///
+  /// - Parameters:
+  ///   - thing: 
+  /// - Returns: TSet<Int32>
+  /// - Throws: 
+  func testSet(thing: TSet<Int32>) throws -> TSet<Int32> {
+    print("testSet\(thing)")
+    return thing
+  }
+
+
+  /// Prints 'testList("{%s}")' where thing has been formatted into a string of values
+  ///  separated by commas and new lines
+  /// @param list<i32> thing - the list<i32> to print
+  /// @return list<i32> - returns the list<i32> 'thing'
+  ///
+  /// - Parameters:
+  ///   - thing: 
+  /// - Returns: TList<Int32>
+  /// - Throws: 
+  func testList(thing: TList<Int32>) throws -> TList<Int32> {
+    print("testList\(thing)")
+    return thing
+  }
+
+
+  /// Prints 'testEnum("%d")' where thing has been formatted into its numeric value
+  /// @param Numberz thing - the Numberz to print
+  /// @return Numberz - returns the Numberz 'thing'
+  ///
+  /// - Parameters:
+  ///   - thing: 
+  /// - Returns: Numberz
+  /// - Throws: 
+  func testEnum(thing: Numberz) throws -> Numberz {
+    print("testEnum\(thing.rawValue)")
+    return thing
+  }
+
+
+  /// Prints 'testTypedef("%d")' with thing as '%d'
+  /// @param UserId thing - the UserId to print
+  /// @return UserId - returns the UserId 'thing'
+  ///
+  /// - Parameters:
+  ///   - thing: 
+  /// - Returns: UserId
+  /// - Throws: 
+  func testTypedef(thing: UserId) throws -> UserId {
+    print("testTypedef(\(thing)")
+    return thing
+  }
+
+
+  /// Prints 'testMapMap("%d")' with hello as '%d'
+  /// @param i32 hello - the i32 to print
+  /// @return map<i32,map<i32,i32>> - returns a dictionary with these values:
+  ///   {-4 => {-4 => -4, -3 => -3, -2 => -2, -1 => -1, }, 4 => {1 => 1, 2 => 2, 3 => 3, 4 => 4, }, }
+  ///
+  /// - Parameters:
+  ///   - hello: 
+  /// - Returns: TMap<Int32, TMap<Int32, Int32>>
+  /// - Throws: 
+  func testMapMap(hello: Int32) throws -> TMap<Int32, TMap<Int32, Int32>> {
+    print("testMapMap(\(hello)")
+    return TMap<Int32, TMap<Int32, Int32>>([
+      -4: [-4: -4, -3: -3, -2: -2, -1: -1],
+       4: [4: 4, 3: 3, 2: 2, 1: 1]
+    ])
+  }
+
+
+  /// So you think you've got this all worked out, eh?
+  /// Creates a map with these values and prints it out:
+  ///   { 1 => { 2 => argument,
+  ///            3 => argument,
+  ///          },
+  ///     2 => { 6 => <empty Insanity struct>, },
+  ///   }
+  /// @return map<UserId, map<Numberz,Insanity>> - a map with the above values
+  ///
+  /// - Parameters:
+  ///   - argument: 
+  /// - Returns: TMap<UserId, TMap<Numberz, Insanity>>
+  /// - Throws: 
+  func testInsanity(argument: Insanity) throws -> TMap<UserId, TMap<Numberz, Insanity>> {
+    return TMap<UserId, TMap<Numberz, Insanity>>([
+      1: [
+        .two: argument,
+        .three: argument
+      ],
+      2: [
+        .six: Insanity(userMap: [:], xtructs: [])
+      ]
+    ])
+  }
+
+
+  /// Prints 'testMulti()'
+  /// @param i8 arg0 -
+  /// @param i32 arg1 -
+  /// @param i64 arg2 -
+  /// @param map<i16, string> arg3 -
+  /// @param Numberz arg4 -
+  /// @param UserId arg5 -
+  /// @return Xtruct - returns an Xtruct with string_thing = "Hello2, byte_thing = arg0, i32_thing = arg1
+  ///    and i64_thing = arg2
+  ///
+  /// - Parameters:
+  ///   - arg0: 
+  ///   - arg1: 
+  ///   - arg2: 
+  ///   - arg3: 
+  ///   - arg4: 
+  ///   - arg5: 
+  /// - Returns: Xtruct
+  /// - Throws: 
+  func testMulti(arg0: Int8, arg1: Int32, arg2: Int64, arg3: TMap<Int16, String>, arg4: Numberz, arg5: UserId) throws -> Xtruct {
+    print("testMulti()")
+    return Xtruct(string_thing: "Hello2", byte_thing: arg0, i32_thing: arg1, i64_thing: arg2)
+  }
+
+
+  /// Print 'testException(%s)' with arg as '%s'
+  /// @param string arg - a string indication what type of exception to throw
+  /// if arg == "Xception" throw Xception with errorCode = 1001 and message = arg
+  /// else if arg == "TException" throw TException
+  /// else do not throw anything
+  ///
+  /// - Parameters:
+  ///   - arg: 
+  /// - Throws: Xception
+  func testException(arg: String) throws {
+    print("testException(\(arg)")
+    if arg == "Xception" {
+      throw Xception(errorCode: 1001, message: arg)
+    } else if arg == "TException" {
+      throw TApplicationError() // is type TError (TException Swift equiv)
+    }
+  }
+
+
+  /// Print 'testMultiException(%s, %s)' with arg0 as '%s' and arg1 as '%s'
+  /// @param string arg - a string indicating what type of exception to throw
+  /// if arg0 == "Xception" throw Xception with errorCode = 1001 and message = "This is an Xception"
+  /// else if arg0 == "Xception2" throw Xception2 with errorCode = 2002 and struct_thing.string_thing = "This is an Xception2"
+  /// else do not throw anything
+  /// @return Xtruct - an Xtruct with string_thing = arg1
+  ///
+  /// - Parameters:
+  ///   - arg0: 
+  ///   - arg1: 
+  /// - Returns: Xtruct
+  /// - Throws: Xception, Xception2
+  func testMultiException(arg0: String, arg1: String) throws -> Xtruct {
+    print("testMultiException(\(arg0), \(arg1)")
+    if arg0 == "Xception" {
+      throw Xception(errorCode: 1001, message: "This is an Xception")
+    } else if arg0 == "Xception2" {
+      throw Xception2(errorCode: 2002, struct_thing: Xtruct(string_thing: "This is an Xception2", byte_thing: 0, i32_thing: 0, i64_thing: 0))
+    }
+    return Xtruct(string_thing: arg1, byte_thing: 0, i32_thing: 0, i64_thing: 0)
+  }
+
+
+  /// Print 'testOneway(%d): Sleeping...' with secondsToSleep as '%d'
+  /// sleep 'secondsToSleep'
+  /// Print 'testOneway(%d): done sleeping!' with secondsToSleep as '%d'
+  /// @param i32 secondsToSleep - the number of seconds to sleep
+  ///
+  /// - Parameters:
+  ///   - secondsToSleep: 
+  /// - Throws: 
+  func testOneway(secondsToSleep: Int32) throws {
+    print("testOneway(\(secondsToSleep): Sleeping...")
+    Thread.sleep(forTimeInterval: TimeInterval(secondsToSleep))
+  }
+  
+  func testUuid(thing: UUID) throws -> UUID {
+    print("testUuid(\(thing))")
+    return thing
+  }
+}
+
+class SecondServiceImpl : SecondService {
+
+  /// Prints 'testString("%s")' with thing as '%s'
+  /// @param string thing - the string to print
+  /// @return string - returns the string 'thing'
+  ///
+  /// - Parameters:
+  ///   - thing: 
+  /// - Returns: String
+  /// - Throws: 
+  func secondtestString(thing: String) throws -> String {
+    print("testString(\"\(thing)\")")
+    return thing
+  }
+}
+