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