Kino Roy | a9da9eb | 2022-10-07 23:13:01 -0700 | [diff] [blame] | 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 | |
| 42 | 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 | |
| 55 | 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 | |
| 67 | 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 | |
| 101 | func testVoid() throws { |
| 102 | print("testVoid") |
| 103 | try client.testVoid() |
| 104 | } |
| 105 | |
| 106 | |
| 107 | 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 | |
| 116 | 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 | |
| 149 | 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 | |
| 158 | func testBool() throws { |
| 159 | try testBool1(true) |
| 160 | try testBool1(false) |
| 161 | } |
| 162 | |
| 163 | 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 | |
| 173 | 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 | |
| 183 | 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 | |
| 191 | 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 | |
| 200 | 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 | |
| 208 | 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 | |
| 216 | 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 | |
| 225 | 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 | |
| 233 | 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 | |
| 241 | 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 | |
| 249 | 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 | |
| 257 | 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 | |
| 265 | 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 | |
| 276 | 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 | |
| 293 | 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 | |
| 301 | 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 | |
| 328 | 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) |
| 357 | /*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() |