1 // Licensed to the Apache Software Foundation (ASF) under one
2 // or more contributor license agreements. See the NOTICE file
3 // distributed with this work for additional information
4 // regarding copyright ownership. The ASF licenses this file
5 // to you under the Apache License, Version 2.0 (the
6 // "License"); you may not use this file except in compliance
7 // with the License. You may obtain a copy of the License at
8 //
9 //   http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing,
12 // software distributed under the License is distributed on an
13 // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 // KIND, either express or implied. See the License for the
15 // specific language governing permissions and limitations
16 // under the License.
17 
18 import Foundation
19 import Thrift
20 import Common
21 import XCTest
22 
23 enum Error: Int32 {
24   case baseTypes = 1
25   case structs = 2
26   case containers = 4
27   case exceptions = 8
28   case unknown = 64
29   case timeout = 128
30 }
31 
32 class TestClient {
33   var client: ThriftTestClient
34   var resultCode: Int32 = 0
35 
36   public init(parameters: TestClientParameters) throws {
37     let transport = try TestClient.getTransport(parameters: parameters)
38     let proto = try TestClient.getProtocol(parameters: parameters, transport: transport)
39     client = ThriftTestClient(inoutProtocol: proto)
40   }
41 
getTransportnull42   static func getTransport(parameters: TestClientParameters) throws -> TTransport {
43     let socketTransport = try TSocketTransport(hostname: parameters.host!, port: parameters.port!)
44     if parameters.transport == .framed {
45       return TFramedTransport(transport: socketTransport)
46     }
47 
48     if parameters.transport == .buffered {
49       return socketTransport
50     }
51 
52     throw ParserError.unsupportedOption
53   }
54 
getProtocolnull55   static func getProtocol(parameters: TestClientParameters, transport: TTransport) throws -> TProtocol {
56     if parameters.proto == .binary {
57       return TBinaryProtocol(on: transport)
58     }
59 
60     if parameters.proto == .compact {
61       return TCompactProtocol(on: transport)
62     }
63 
64     throw ParserError.unsupportedOption
65   }
66 
runnull67   func run() throws {
68     do {
69       try testVoid()
70       try testString()
71       try testBool()
72       try testByte()
73       try testI32()
74       try testI64()
75       try testDouble()
76       try testBinary()
77       try testStruct()
78       try testNest()
79       try testMap()
80       try testSet()
81       try testList()
82       try testEnum()
83       try testTypedef()
84       try testMapMap()
85       try testInsanity()
86       try testMulti()
87       try testException()
88       try testMultiException()
89       // Swift generator doesn't yet support one way functions (THRIFT-5468)
90       /*try testOneway()
91        try testOnewayThenNormal()*/
92       try testUuid()
93 
94     } catch let error {
95       print("\(error)")
96       resultCode |= Error.unknown.rawValue
97     }
98     exit(resultCode)
99   }
100 
testVoidnull101   func testVoid() throws {
102     print("testVoid")
103     try client.testVoid()
104   }
105 
106 
testString1null107   func testString1(_ s1: String) throws {
108     print("testString(\(s1))")
109     let r1 = try client.testString(thing: s1)
110     print(r1)
111     if s1 != r1 {
112       resultCode |= Error.baseTypes.rawValue
113     }
114   }
115 
testStringnull116   func testString() throws {
117     try testString1(String(repeating: "Python", count: 20))
118     try testString1("")
119     try testString1("\t\n/\\\\\r{}:パイソン")
120     try testString1("""
121 Afrikaans, Alemannisch, Aragonés, العربية, مصرى,
122 Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška,
123 Беларуская, Беларуская (тарашкевіца), Български, Bamanankan,
124 বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн,
125 Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg,
126 Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English,
127 Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt,
128 Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego,
129 Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski,
130 Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia,
131 Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa,
132 ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар,
133 Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino,
134 Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa
135 Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, مازِرونی, Bahasa
136 Melayu, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪
137 Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad,
138 Occitan, Иронау, Papiamentu, Deitsch, Polski, پنجابی, پښتو,
139 Norfuk / Pitkern, Português, Runa Simi, Rumantsch, Romani, Română,
140 Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple
141 English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk,
142 Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog,
143 Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük,
144 Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文,
145 Bân-lâm-gú, 粵語
146 """)
147   }
148 
testBool1null149   func testBool1(_ s1: Bool) throws {
150     print("testBool(\(s1))")
151     let r1 = try client.testBool(thing: s1)
152     print(r1)
153     if s1 != r1 {
154       resultCode |= Error.baseTypes.rawValue
155     }
156   }
157 
testBoolnull158   func testBool() throws {
159     try testBool1(true)
160     try testBool1(false)
161   }
162 
testBytenull163   func testByte() throws {
164     print("testByte")
165     if try client.testByte(thing: 63) != 63 {
166       resultCode |= Error.baseTypes.rawValue
167     }
168     if try client.testByte(thing: -127) != -127 {
169       resultCode |= Error.baseTypes.rawValue
170     }
171   }
172 
testI32null173   func testI32() throws {
174     print("testI32")
175     if try client.testI32(thing: -1) != -1 {
176       resultCode |= Error.baseTypes.rawValue
177     }
178     if try client.testI32(thing: 0) != 0 {
179       resultCode |= Error.baseTypes.rawValue
180     }
181   }
182 
testI64null183   func testI64() throws {
184     print("testI64")
185     if try client.testI64(thing: 1) != 1 ||
186         client.testI64(thing: -34359738368) != -34359738368 {
187       resultCode |= Error.baseTypes.rawValue
188     }
189   }
190 
testDoublenull191   func testDouble() throws {
192     print("testDouble")
193     for testValue in [-5.235098235, 0, -1, -0.000341012439638598279] {
194       if try client.testDouble(thing: testValue) != testValue {
195         resultCode |= Error.baseTypes.rawValue
196       }
197     }
198   }
199 
testBinarynull200   func testBinary() throws {
201     print("testBinary")
202     let val = Data(Array(0...255))
203     if try client.testBinary(thing: val) != val {
204       resultCode |= Error.baseTypes.rawValue
205     }
206   }
207 
testStructnull208   func testStruct() throws {
209     print("testStruct")
210     let x = Xtruct(string_thing: "Zero", byte_thing: 1, i32_thing: -3, i64_thing: -5)
211     if try client.testStruct(thing: x) != x {
212       resultCode |= Error.structs.rawValue
213     }
214   }
215 
testNestnull216   func testNest() throws {
217     print("testNest")
218     let inner = Xtruct(string_thing: "Zero", byte_thing: 1, i32_thing: -3, i64_thing: -5)
219     let x = Xtruct2(byte_thing: 0, struct_thing: inner, i32_thing: 0)
220     if try client.testNest(thing: x) != x {
221       resultCode |= Error.structs.rawValue
222     }
223   }
224 
testMapnull225   func testMap() throws {
226     print("testMap")
227     let x = TMap<Int32, Int32>([0: 1, 1: 2, 2: 3, 3: 4, -1: -2])
228     if try client.testMap(thing: x) != x {
229       resultCode |= Error.containers.rawValue
230     }
231   }
232 
testSetnull233   func testSet() throws {
234     print("testSet")
235     let x = TSet<Int32>([8, 1, 42])
236     if try client.testSet(thing: x) != x {
237       resultCode |= Error.containers.rawValue
238     }
239   }
240 
testListnull241   func testList() throws {
242     print("testList")
243     let x = TList<Int32>([1, 4, 9, -42])
244     if try client.testList(thing: x) != x {
245       resultCode |= Error.containers.rawValue
246     }
247   }
248 
testEnumnull249   func testEnum() throws {
250     print("testEnum")
251     let x = Numberz.five
252     if try client.testEnum(thing: x) != x {
253       resultCode |= Error.containers.rawValue
254     }
255   }
256 
testTypedefnull257   func testTypedef() throws {
258     print("testTypedef")
259     let x = UserId(bitPattern: 0xffffffffffffff)
260     if try client.testTypedef(thing: x) != x {
261       resultCode |= Error.containers.rawValue
262     }
263   }
264 
testMapMapnull265   func testMapMap() throws {
266     print("testMapMap")
267     let x = TMap<Int32, TMap<Int32, Int32>>([
268       -4: [-4: -4, -3: -3, -2: -2, -1: -1],
269        4: [4: 4, 3: 3, 2: 2, 1: 1]
270     ])
271     if try client.testMapMap(hello: 42) != x {
272       resultCode |= Error.containers.rawValue
273     }
274   }
275 
testInsanitynull276   func testInsanity() throws {
277     print("testInsanity()")
278     let argument = Insanity(userMap: [.eight: 8], xtructs: [])
279     let expected = TMap<UserId, TMap<Numberz, Insanity>>([
280       1: [
281         .two: argument,
282         .three: argument
283       ],
284       2: [
285         .six: Insanity(userMap: [:], xtructs: [])
286       ]
287     ])
288     if try client.testInsanity(argument: argument) != expected {
289       resultCode |= Error.containers.rawValue
290     }
291   }
292 
testMultinull293   func testMulti() throws {
294     print("testMulti")
295     let x = Xtruct(string_thing: "Hello2", byte_thing: 74, i32_thing: 0xff00ff, i64_thing: 0xffffffffd0d0)
296     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 {
297       resultCode |= Error.containers.rawValue
298     }
299   }
300 
testExceptionnull301   func testException() throws {
302     print("testException")
303     try client.testException(arg: "Safe")
304     do {
305       try client.testException(arg: "Xception")
306       resultCode |= Error.exceptions.rawValue
307     } catch let error as Xception {
308       guard error.errorCode == 1001, error.message == "Xception" else {
309         resultCode |= Error.exceptions.rawValue
310         return
311       }
312     } catch {
313       resultCode |= Error.exceptions.rawValue
314     }
315 
316     do {
317       try client.testException(arg: "TException")
318       resultCode |= Error.exceptions.rawValue
319     } catch is TError {
320 
321     } catch {
322       resultCode |= Error.exceptions.rawValue
323     }
324 
325     try client.testException(arg: "success")
326   }
327 
testMultiExceptionnull328   func testMultiException() throws {
329     print("testMultiException")
330     do {
331       _ = try client.testMultiException(arg0: "Xception", arg1: "ignore")
332     } catch let error as Xception {
333       guard error.errorCode == 1001, error.message == "This is an Xception" else {
334         resultCode |= Error.exceptions.rawValue
335         return
336       }
337     } catch {
338       resultCode |= Error.exceptions.rawValue
339     }
340 
341     do {
342       _ = try client.testMultiException(arg0: "Xception2", arg1: "ignore")
343     } catch let error as Xception2 {
344       guard error.errorCode == 2002, error.struct_thing.string_thing == "This is an Xception2" else {
345         resultCode |= Error.exceptions.rawValue
346         return
347       }
348     }
349 
350     let y = try client.testMultiException(arg0: "success", arg1: "foobar")
351     if y.string_thing != "foobar" {
352       resultCode |= Error.exceptions.rawValue
353     }
354   }
355 
356   // Swift generator doesn't yet support one way functions (THRIFT-5468)
testOnewaynull357   /*func testOneway() throws {
358    print("testOneway")
359    let start = CACurrentMediaTime()
360    try client.testOneway(secondsToSleep: 1)
361    let end = CACurrentMediaTime()
362    let duration = end - start
363    let delta = abs(1 - duration)
364    print("oneway sleep took \(end - start) sec")
365 
366    guard delta < 0.5 else {
367    print("oneway sleep took \(end - start) sec")
368    resultCode |= Error.unknown.rawValue
369    return
370    }
371    }
372 
373    func testOnewayThenNormal() throws {
374    print("testOnewayThenNormal")
375    try client.testOneway(secondsToSleep: 1)
376    if try client.testString(thing: "Swift") != "Swift" {
377    resultCode |= Error.baseTypes.rawValue
378    }
379    }*/
380 
381   func testUuid() throws {
382     let uuid = UUID()
383     guard try client.testUuid(thing: uuid) == uuid else {
384       resultCode |= Error.baseTypes.rawValue
385       return
386     }
387   }
388 }
389 
390 
391 let parameters = try TestClientParameters(arguments: CommandLine.arguments)
392 
393 if parameters.showHelp {
394   parameters.printHelp()
395   exit(0)
396 }
397 
398 Thread.sleep(forTimeInterval: 1)
399 
400 try TestClient(parameters: parameters).run()
401