1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *   http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied.  See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 package org.apache.thrift.test
20 
21 import com.github.ajalt.clikt.core.CliktCommand
22 import com.github.ajalt.clikt.parameters.options.default
23 import com.github.ajalt.clikt.parameters.options.flag
24 import com.github.ajalt.clikt.parameters.options.option
25 import com.github.ajalt.clikt.parameters.types.enum
26 import com.github.ajalt.clikt.parameters.types.int
27 import java.nio.ByteBuffer
28 import kotlin.math.abs
29 import kotlin.system.exitProcess
30 import kotlinx.coroutines.runBlocking
31 import org.apache.thrift.TApplicationException
32 import org.apache.thrift.TException
33 import org.apache.thrift.TSerializer
34 import org.apache.thrift.async.TAsyncClientManager
35 import org.apache.thrift.protocol.TBinaryProtocol
36 import org.apache.thrift.protocol.TCompactProtocol
37 import org.apache.thrift.protocol.TJSONProtocol
38 import org.apache.thrift.protocol.TProtocol
39 import org.apache.thrift.protocol.TSimpleJSONProtocol
40 import org.apache.thrift.transport.TNonblockingSocket
41 import org.apache.thrift.transport.TNonblockingTransport
42 import org.apache.thrift.transport.TTransport
43 import thrift.test.Insanity
44 import thrift.test.Numberz
45 import thrift.test.SecondServiceClient
46 import thrift.test.ThriftTestClient
47 import thrift.test.Xception
48 import thrift.test.Xception2
49 import thrift.test.Xtruct
50 import thrift.test.Xtruct2
51 
52 /**
53  * Test Java client for thrift. Essentially just a copy of the C++ version, this makes a variety of
54  * requests to enable testing for both performance and correctness of the output.
55  */
56 const val ERR_BASETYPES = 1
57 const val ERR_STRUCTS = 2
58 const val ERR_CONTAINERS = 4
59 const val ERR_EXCEPTIONS = 8
60 const val ERR_PROTOCOLS = 16
61 const val ERR_UNKNOWN = 64
62 
63 enum class ProtocolType(val key: String) {
64     Binary("binary"),
65     Multi("multi"),
66     Json("json"),
67     MultiJson("multij"),
68     Compact("compact"),
69     MultiCompact("multic")
70 }
71 
72 enum class TransportType(val key: String) {
73     Buffered("buffered"),
74     Framed("framed"),
75     FastFramed("fastframed"),
76     Http("http")
77 }
78 
79 class TestClient : CliktCommand() {
80     private val host: String by
81         option(help = "The cross test host to connect to").default("localhost")
82     private val port: Int by option(help = "The cross test port to connect to").int().default(9090)
83     private val numTests: Int by
84         option("--testloops", "--n", help = "Number of runs in this test").int().default(1)
85     private val protocolType: ProtocolType by
86         option("--protocol", help = "Protocol type")
<lambda>null87             .enum<ProtocolType> { it.key }
88             .default(ProtocolType.Binary)
89     private val transportType: TransportType by
90         option("--transport", help = "Transport type")
<lambda>null91             .enum<TransportType> { it.key }
92             .default(TransportType.Buffered)
93     private val useHttpClient: Boolean by
94         option("--client", help = "Use http client").flag(default = false)
95     private val useSSL: Boolean by
96         option("--ssl", help = "Use SSL for encrypted transport").flag(default = false)
97     private val useZlib: Boolean by
98         option("--zlib", help = "Use zlib wrapper for compressed transport").flag(default = false)
99     private val socketTimeout: Int by
100         option("--timeout", help = "Socket timeout").int().default(1000)
101 
createProtocolnull102     private fun createProtocol(transport: TTransport): TProtocol =
103         when (protocolType) {
104             ProtocolType.Binary, ProtocolType.Multi -> TBinaryProtocol(transport)
105             ProtocolType.Compact, ProtocolType.MultiCompact -> TCompactProtocol(transport)
106             ProtocolType.Json, ProtocolType.MultiJson -> TJSONProtocol(transport)
107         }
108 
createTransportnull109     private fun createTransport(): TNonblockingTransport =
110         when (transportType) {
111             TransportType.Framed -> TNonblockingSocket(host, port, socketTimeout)
112             else ->
113                 throw UnsupportedOperationException(
114                     "only frame transport type is supported for now, got $transportType"
115                 )
116         }
117 
118     private val clientManager = TAsyncClientManager()
119 
createClientnull120     private fun createClient(): ThriftTestClient =
121         ThriftTestClient({ createProtocol(it) }, clientManager, createTransport())
122 
createSecondServiceClientnull123     private fun createSecondServiceClient(): SecondServiceClient =
124         SecondServiceClient({ createProtocol(it) }, clientManager, createTransport())
125 
<lambda>null126     override fun run() = runBlocking {
127         var testClient = createClient()
128         val insane = Insanity()
129         var timeMin: Long = 0
130         var timeMax: Long = 0
131         var timeTot: Long = 0
132         var returnCode = 0
133         for (test in 0 until numTests) {
134             try {
135                 /** CONNECT TEST */
136                 /** CONNECT TEST */
137                 //  if (!transport.isOpen) {
138                 //      try {
139                 //          transport.open()
140                 //      } catch (ttx: TTransportException) {
141                 //          ttx.printStackTrace()
142                 //          println("Connect failed: " + ttx.message)
143                 //          exitProcess(ERR_UNKNOWN)
144                 //      }
145                 //  }
146                 println("Test #${test + 1}, connect $host:$port")
147 
148                 val start = System.nanoTime()
149                 /** VOID TEST */
150                 /** VOID TEST */
151                 returnCode = testClient.voidTest(returnCode)
152                 /** STRING TEST */
153                 /** STRING TEST */
154                 returnCode = testClient.stringTest(returnCode)
155                 /** Multiplexed test */
156                 /** Multiplexed test */
157                 returnCode = multiplexTest(returnCode)
158                 /** BYTE TEST */
159                 /** BYTE TEST */
160                 returnCode = testClient.byteTest(returnCode)
161                 /** I32 TEST */
162                 /** I32 TEST */
163                 returnCode = testClient.i32Test(returnCode)
164                 /** I64 TEST */
165                 /** I64 TEST */
166                 returnCode = testClient.i64Test(returnCode)
167                 /** DOUBLE TEST */
168                 /** DOUBLE TEST */
169                 returnCode = testClient.doubleTest(returnCode)
170                 /** BINARY TEST */
171                 /** BINARY TEST */
172                 returnCode = testClient.binaryTest(returnCode)
173                 /** STRUCT TEST */
174                 /** STRUCT TEST */
175                 val pair = testClient.structTest(returnCode)
176                 val out = pair.first
177                 returnCode = pair.second
178                 /** NESTED STRUCT TEST */
179                 /** NESTED STRUCT TEST */
180                 returnCode = testClient.nestedStructTest(out, returnCode)
181                 /** MAP TEST */
182                 /** MAP TEST */
183                 val testMapParam = (0..4).associateBy { 10 - it }
184                 printMap(testMapParam)
185                 val testMapResult: Map<Int, Int> = testClient.testMap(testMapParam)
186                 printMap(testMapResult)
187                 if (testMapParam != testMapResult) {
188                     returnCode = returnCode or ERR_CONTAINERS
189                     println("*** FAILURE ***\n")
190                 }
191                 /** STRING MAP TEST */
192                 /** STRING MAP TEST */
193                 returnCode = testClient.stringMapTest(returnCode)
194                 /** SET TEST */
195                 /** SET TEST */
196                 val setout: MutableSet<Int> = HashSet()
197                 for (i in -2..2) {
198                     setout.add(i)
199                 }
200                 val setin: Set<Int> = testClient.testSet(setout)
201                 if (setout != setin) {
202                     returnCode = returnCode or ERR_CONTAINERS
203                     println("*** FAILURE ***\n")
204                 }
205                 /** LIST TEST */
206                 /** LIST TEST */
207                 val listout: MutableList<Int> = ArrayList()
208                 for (i in -2..2) {
209                     listout.add(i)
210                 }
211                 val listin: List<Int> = testClient.testList(listout)
212                 if (listout != listin) {
213                     returnCode = returnCode or ERR_CONTAINERS
214                     println("*** FAILURE ***\n")
215                 }
216                 /** ENUM TEST */
217                 /** ENUM TEST */
218                 returnCode = testClient.enumTest(returnCode)
219                 /** TYPEDEF TEST */
220                 /** TYPEDEF TEST */
221                 returnCode = testClient.typedefTest(returnCode)
222                 /** NESTED MAP TEST */
223                 /** NESTED MAP TEST */
224                 returnCode = testClient.nestedMapTest(returnCode)
225                 /** INSANITY TEST */
226                 /** INSANITY TEST */
227                 var insanityFailed = true
228                 try {
229                     val hello = Xtruct()
230                     hello.string_thing = "Hello2"
231                     hello.byte_thing = 2
232                     hello.i32_thing = 2
233                     hello.i64_thing = 2
234                     val goodbye = Xtruct()
235                     goodbye.string_thing = "Goodbye4"
236                     goodbye.byte_thing = 4.toByte()
237                     goodbye.i32_thing = 4
238                     goodbye.i64_thing = 4L
239                     insane.userMap =
240                         HashMap<Numberz, Long>().apply {
241                             put(Numberz.EIGHT, 8L)
242                             put(Numberz.FIVE, 5L)
243                         }
244 
245                     insane.xtructs =
246                         ArrayList<Xtruct>().apply {
247                             add(goodbye)
248                             add(hello)
249                         }
250 
251                     print("testInsanity()")
252                     val whoa: Map<Long, Map<Numberz, Insanity>> = testClient.testInsanity(insane)
253                     print(" = {")
254                     for (key in whoa.keys) {
255                         val `val` = whoa[key]!!
256                         print("$key => {")
257                         for (k2 in `val`.keys) {
258                             val v2 = `val`[k2]
259                             print("$k2 => {")
260                             val userMap = v2!!.userMap
261                             print("{")
262                             if (userMap != null) {
263                                 for (k3 in userMap.keys) {
264                                     print(k3.toString() + " => " + userMap[k3] + ", ")
265                                 }
266                             }
267                             print("}, ")
268                             val xtructs = v2.xtructs
269                             print("{")
270                             if (xtructs != null) {
271                                 for ((string_thing, byte_thing, i32_thing, i64_thing) in xtructs) {
272                                     print(
273                                         "{\"$string_thing\", $byte_thing, $i32_thing, $i64_thing}, "
274                                     )
275                                 }
276                             }
277                             print("}")
278                             print("}, ")
279                         }
280                         print("}, ")
281                     }
282                     print("}\n")
283                     if (whoa.size == 2 && whoa.containsKey(1L) && whoa.containsKey(2L)) {
284                         val firstMap = whoa[1L]!!
285                         val secondMap = whoa[2L]!!
286                         if (firstMap.size == 2 &&
287                                 firstMap.containsKey(Numberz.TWO) &&
288                                 firstMap.containsKey(Numberz.THREE) &&
289                                 secondMap.size == 1 &&
290                                 secondMap.containsKey(Numberz.SIX) &&
291                                 insane == firstMap[Numberz.TWO] &&
292                                 insane == firstMap[Numberz.THREE]
293                         ) {
294                             val six = secondMap[Numberz.SIX]!!
295                             // Cannot use "new Insanity().equals(six)" because as of now,
296                             // struct/container
297                             // fields with default requiredness have isset=false for local instances
298                             // and
299                             // yet
300                             // received empty values from other languages like C++ have isset=true .
301                             if ((six.userMap?.size ?: 0) == 0 && (six.xtructs?.size ?: 0) == 0) {
302                                 // OK
303                                 insanityFailed = false
304                             }
305                         }
306                     }
307                 } catch (ex: Exception) {
308                     returnCode = returnCode or ERR_STRUCTS
309                     println("*** FAILURE ***\n")
310                     ex.printStackTrace(System.out)
311                     insanityFailed = false
312                 }
313                 if (insanityFailed) {
314                     returnCode = returnCode or ERR_STRUCTS
315                     println("*** FAILURE ***\n")
316                 }
317                 /** EXECPTION TEST */
318                 /** EXECPTION TEST */
319                 val pair2 = exceptionTest(testClient, returnCode)
320                 returnCode = pair2.first
321                 testClient = pair2.second
322                 /** MULTI EXCEPTION TEST */
323                 /** MULTI EXCEPTION TEST */
324                 val pair3 = multiExceptionTest(testClient, returnCode)
325                 returnCode = pair3.first
326                 testClient = pair3.second
327                 /** ONEWAY TEST */
328                 /** ONEWAY TEST */
329                 returnCode = testClient.onewayTest(returnCode)
330                 val stop = System.nanoTime()
331                 val tot = stop - start
332                 println("Total time: " + tot / 1000 + "us")
333                 if (timeMin == 0L || tot < timeMin) {
334                     timeMin = tot
335                 }
336                 if (tot > timeMax) {
337                     timeMax = tot
338                 }
339                 timeTot += tot
340                 // transport.close()
341             } catch (x: Exception) {
342                 System.out.printf("*** FAILURE ***\n")
343                 x.printStackTrace()
344                 returnCode = returnCode or ERR_UNKNOWN
345             }
346         }
347         val timeAvg = timeTot / numTests
348         println("Min time: " + timeMin / 1000 + "us")
349         println("Max time: " + timeMax / 1000 + "us")
350         println("Avg time: " + timeAvg / 1000 + "us")
351         try {
352             val json = TSerializer(TSimpleJSONProtocol.Factory()).toString(insane)
353             println("\nSample TSimpleJSONProtocol output:\n$json")
354         } catch (x: TException) {
355             println("*** FAILURE ***")
356             x.printStackTrace()
357             returnCode = returnCode or ERR_BASETYPES
358         }
359         exitProcess(returnCode)
360     }
361 
multiplexTestnull362     private suspend fun multiplexTest(returnCode: Int): Int {
363         var code = returnCode
364         if (protocolType == ProtocolType.Multi ||
365                 protocolType == ProtocolType.MultiJson ||
366                 protocolType == ProtocolType.MultiCompact
367         ) {
368             val secondClient: SecondServiceClient = createSecondServiceClient()
369             print("secondtestString(\"Test2\")")
370             val s = secondClient.secondtestString("Test2")
371             print(" = \"$s\"\n")
372             if (s != "testString(\"Test2\")") {
373                 code = code or ERR_PROTOCOLS
374                 println("*** FAILURE ***\n")
375             }
376         }
377         return code
378     }
379 
enumTestnull380     private suspend fun ThriftTestClient.enumTest(returnCode: Int): Int {
381         var returnCode1 = returnCode
382         print("testEnum(ONE)")
383         var ret: Numberz = testEnum(Numberz.ONE)
384         print(" = $ret\n")
385         if (ret !== Numberz.ONE) {
386             returnCode1 = returnCode1 or ERR_STRUCTS
387             println("*** FAILURE ***\n")
388         }
389         print("testEnum(TWO)")
390         ret = testEnum(Numberz.TWO)
391         print(" = $ret\n")
392         if (ret !== Numberz.TWO) {
393             returnCode1 = returnCode1 or ERR_STRUCTS
394             println("*** FAILURE ***\n")
395         }
396         print("testEnum(THREE)")
397         ret = testEnum(Numberz.THREE)
398         print(" = $ret\n")
399         if (ret !== Numberz.THREE) {
400             returnCode1 = returnCode1 or ERR_STRUCTS
401             println("*** FAILURE ***\n")
402         }
403         print("testEnum(FIVE)")
404         ret = testEnum(Numberz.FIVE)
405         print(" = $ret\n")
406         if (ret !== Numberz.FIVE) {
407             returnCode1 = returnCode1 or ERR_STRUCTS
408             println("*** FAILURE ***\n")
409         }
410         print("testEnum(EIGHT)")
411         ret = testEnum(Numberz.EIGHT)
412         print(" = $ret\n")
413         if (ret !== Numberz.EIGHT) {
414             returnCode1 = returnCode1 or ERR_STRUCTS
415             println("*** FAILURE ***\n")
416         }
417         return returnCode1
418     }
419 
printMapnull420     private fun printMap(testMapParam: Map<Int, Int>) {
421         print("testMap({")
422         var first = true
423         for (key in testMapParam.keys) {
424             if (first) {
425                 first = false
426             } else {
427                 print(", ")
428             }
429             print(key.toString() + " => " + testMapParam[key])
430         }
431         print("})")
432     }
433 
exceptionTestnull434     private suspend fun exceptionTest(
435         testClient: ThriftTestClient,
436         returnCode: Int
437     ): Pair<Int, ThriftTestClient> {
438         var client = testClient
439         var code = returnCode
440         try {
441             print("testClient.testException(\"Xception\") =>")
442             client.testException("Xception")
443             print("  void\n*** FAILURE ***\n")
444             code = code or ERR_EXCEPTIONS
445         } catch (e: Xception) {
446             System.out.printf("  {%d, \"%s\"}\n", e.errorCode, e.message)
447             client = createClient()
448         }
449         try {
450             print("testClient.testException(\"TException\") =>")
451             client.testException("TException")
452             print("  void\n*** FAILURE ***\n")
453             code = code or ERR_EXCEPTIONS
454         } catch (e: TException) {
455             System.out.printf("  {\"%s\"}\n", e.message)
456             client = createClient()
457         }
458         try {
459             print("testClient.testException(\"success\") =>")
460             client.testException("success")
461             print("  void\n")
462         } catch (e: Exception) {
463             System.out.printf("  exception\n*** FAILURE ***\n")
464             code = code or ERR_EXCEPTIONS
465         }
466         return code to client
467     }
468 
multiExceptionTestnull469     private suspend fun multiExceptionTest(
470         testClient: ThriftTestClient,
471         returnCode: Int
472     ): Pair<Int, ThriftTestClient> {
473         var client = testClient
474         var code = returnCode
475         try {
476             System.out.printf("testClient.testMultiException(\"Xception\", \"test 1\") =>")
477             client.testMultiException("Xception", "test 1")
478             print("  result\n*** FAILURE ***\n")
479             code = code or ERR_EXCEPTIONS
480         } catch (e: Xception) {
481             System.out.printf("  {%d, \"%s\"}\n", e.errorCode, e.message)
482             client = createClient()
483         }
484         try {
485             System.out.printf("testClient.testMultiException(\"Xception2\", \"test 2\") =>")
486             client.testMultiException("Xception2", "test 2")
487             print("  result\n*** FAILURE ***\n")
488             code = code or ERR_EXCEPTIONS
489         } catch (e: Xception2) {
490             System.out.printf("  {%d, {\"%s\"}}\n", e.errorCode, e.struct_thing!!.string_thing)
491             client = createClient()
492         }
493         try {
494             print("testClient.testMultiException(\"success\", \"test 3\") =>")
495             val result: Xtruct = client.testMultiException("success", "test 3")
496             System.out.printf("  {{\"%s\"}}\n", result.string_thing)
497         } catch (e: Exception) {
498             System.out.printf("  exception\n*** FAILURE ***\n")
499             code = code or ERR_EXCEPTIONS
500         }
501         return code to client
502     }
503 }
504 
typedefTestnull505 private suspend fun ThriftTestClient.typedefTest(returnCode: Int): Int {
506     var returnCode1 = returnCode
507     print("testTypedef(309858235082523)")
508     val uid: Long = testTypedef(309858235082523L)
509     print(" = $uid\n")
510     if (uid != 309858235082523L) {
511         returnCode1 = returnCode1 or ERR_BASETYPES
512         println("*** FAILURE ***\n")
513     }
514     return returnCode1
515 }
516 
structTestnull517 private suspend fun ThriftTestClient.structTest(returnCode: Int): Pair<Xtruct, Int> {
518     var code = returnCode
519     print("testStruct({\"Zero\", 1, -3, -5})")
520     val out = Xtruct()
521     out.string_thing = "Zero"
522     out.byte_thing = 1.toByte()
523     out.i32_thing = -3
524     out.i64_thing = -5
525     val input: Xtruct = testStruct(out)
526     print(
527         """ = {"${input.string_thing}",${input.byte_thing}, ${input.i32_thing}, ${input.i64_thing}}"""
528     )
529     if (input != out) {
530         code = code or ERR_STRUCTS
531         println("*** FAILURE ***\n")
532     }
533     return out to code
534 }
535 
onewayTestnull536 private suspend fun ThriftTestClient.onewayTest(returnCode: Int): Int {
537     var returnCode1 = returnCode
538     print("testOneway(3)...")
539     val startOneway = System.nanoTime()
540     testOneway(3)
541     val onewayElapsedMillis = (System.nanoTime() - startOneway) / 1000000
542     if (onewayElapsedMillis > 200) {
543         println("Oneway test took too long to execute failed: took " + onewayElapsedMillis + "ms")
544         println("oneway calls are 'fire and forget' and therefore should not cause blocking.")
545         println("Some transports (HTTP) have a required response, and typically this failure")
546         println("means the transport response was delayed until after the execution")
547         println("of the RPC.  The server should post the transport response immediately and")
548         println("before executing the RPC.")
549         println("*** FAILURE ***")
550         returnCode1 = returnCode1 or ERR_BASETYPES
551     } else {
552         println("Success - fire and forget only took " + onewayElapsedMillis + "ms")
553     }
554     return returnCode1
555 }
556 
nestedMapTestnull557 private suspend fun ThriftTestClient.nestedMapTest(returnCode: Int): Int {
558     var returnCode1 = returnCode
559     print("testMapMap(1)")
560     val mm: Map<Int, Map<Int, Int>> = testMapMap(1)
561     print(" = {")
562     for (key in mm.keys) {
563         print("$key => {")
564         val m2 = mm[key]!!
565         for (k2 in m2.keys) {
566             print(k2.toString() + " => " + m2[k2] + ", ")
567         }
568         print("}, ")
569     }
570     print("}\n")
571     if (mm.size != 2 || !mm.containsKey(4) || !mm.containsKey(-4)) {
572         returnCode1 = returnCode1 or ERR_CONTAINERS
573         println("*** FAILURE ***\n")
574     } else {
575         val m1 = mm[4]!!
576         val m2 = mm[-4]!!
577         if (m1[1] != 1 ||
578                 m1[2] != 2 ||
579                 m1[3] != 3 ||
580                 m1[4] != 4 ||
581                 m2[-1] != -1 ||
582                 m2[-2] != -2 ||
583                 m2[-3] != -3 ||
584                 m2[-4] != -4
585         ) {
586             returnCode1 = returnCode1 or ERR_CONTAINERS
587             println("*** FAILURE ***\n")
588         }
589     }
590     return returnCode1
591 }
592 
stringMapTestnull593 private suspend fun ThriftTestClient.stringMapTest(returnCode: Int): Int {
594     var returnCode1 = returnCode
595     try {
596         val smapout: MutableMap<String, String> = HashMap()
597         smapout["a"] = "2"
598         smapout["b"] = "blah"
599         smapout["some"] = "thing"
600         var first = true
601         for (key in smapout.keys) {
602             if (first) {
603                 first = false
604             } else {
605                 print(", ")
606             }
607             print(key + " => " + smapout[key])
608         }
609         print("})")
610         val smapin: Map<String, String> = testStringMap(smapout)
611         print(" = {")
612         first = true
613         for (key in smapin.keys) {
614             if (first) {
615                 first = false
616             } else {
617                 print(", ")
618             }
619             print(key + " => " + smapout[key])
620         }
621         print("}\n")
622         if (smapout != smapin) {
623             returnCode1 = returnCode1 or ERR_CONTAINERS
624             println("*** FAILURE ***\n")
625         }
626     } catch (ex: Exception) {
627         returnCode1 = returnCode1 or ERR_CONTAINERS
628         println("*** FAILURE ***\n")
629         ex.printStackTrace(System.out)
630     }
631     return returnCode1
632 }
633 
nestedStructTestnull634 private suspend fun ThriftTestClient.nestedStructTest(out: Xtruct, returnCode: Int): Int {
635     var code = returnCode
636     print("testNest({1, {\"Zero\", 1, -3, -5}), 5}")
637     val out2 = Xtruct2()
638     out2.byte_thing = 1.toShort().toByte()
639     out2.struct_thing = out
640     out2.i32_thing = 5
641     val xstruct2: Xtruct2 = testNest(out2)
642     val input = xstruct2.struct_thing!!
643     print(
644         """ = {${xstruct2.byte_thing}, {"${input.string_thing}", ${input.byte_thing}, ${input.i32_thing}, ${input.i64_thing}}, ${xstruct2.i32_thing}}
645     """
646     )
647     if (xstruct2 != out2) {
648         code = code or ERR_STRUCTS
649         println("*** FAILURE ***\n")
650     }
651     return code
652 }
653 
binaryTestnull654 private suspend fun ThriftTestClient.binaryTest(returnCode: Int): Int {
655     var returnCode1 = returnCode
656     try {
657         print("testBinary(-128...127) = ")
658         val data = testByteArray
659         val bin: ByteBuffer = ByteBuffer.wrap(testBinary(data))
660         bin.mark()
661         val bytes = ByteArray(bin.limit() - bin.position())
662         bin[bytes]
663         bin.reset()
664         print("{")
665         var first = true
666         for (i in bytes.indices) {
667             if (first) first = false else print(", ")
668             print(bytes[i])
669         }
670         println("}")
671         if (ByteBuffer.wrap(data) != bin) {
672             returnCode1 = returnCode1 or ERR_BASETYPES
673             println("*** FAILURE ***\n")
674         }
675     } catch (ex: Exception) {
676         returnCode1 = returnCode1 or ERR_BASETYPES
677         println("\n*** FAILURE ***\n")
678         ex.printStackTrace(System.out)
679     }
680     return returnCode1
681 }
682 
doubleTestnull683 private suspend fun ThriftTestClient.doubleTest(returnCode: Int): Int {
684     var returnCode1 = returnCode
685     print("testDouble(-5.325098235)")
686     val dub: Double = testDouble(-5.325098235)
687     print(" = $dub\n")
688     if (abs(dub - -5.325098235) > 0.001) {
689         returnCode1 = returnCode1 or ERR_BASETYPES
690         println("*** FAILURE ***\n")
691     }
692     return returnCode1
693 }
694 
i64Testnull695 private suspend fun ThriftTestClient.i64Test(returnCode: Int): Int {
696     var returnCode1 = returnCode
697     print("testI64(-34359738368)")
698     val i64: Long = testI64(-34359738368L)
699     print(" = $i64\n")
700     if (i64 != -34359738368L) {
701         returnCode1 = returnCode1 or ERR_BASETYPES
702         println("*** FAILURE ***\n")
703     }
704     return returnCode1
705 }
706 
i32Testnull707 private suspend fun ThriftTestClient.i32Test(returnCode: Int): Int {
708     var returnCode1 = returnCode
709     print("testI32(-1)")
710     val i32: Int = testI32(-1)
711     print(" = $i32\n")
712     if (i32 != -1) {
713         returnCode1 = returnCode1 or ERR_BASETYPES
714         println("*** FAILURE ***\n")
715     }
716     return returnCode1
717 }
718 
byteTestnull719 private suspend fun ThriftTestClient.byteTest(returnCode: Int): Int {
720     var returnCode1 = returnCode
721     print("testByte(1)")
722     val i8: Byte = testByte(1.toByte())
723     print(" = $i8\n")
724     if (i8.toInt() != 1) {
725         returnCode1 = returnCode1 or ERR_BASETYPES
726         println("*** FAILURE ***\n")
727     }
728     return returnCode1
729 }
730 
stringTestnull731 private suspend fun ThriftTestClient.stringTest(returnCode: Int): Int {
732     var returnCode1 = returnCode
733     print("testString(\"Test\")")
734     val s: String = testString("Test")
735     print(" = \"$s\"\n")
736     if (s != "Test") {
737         returnCode1 = returnCode1 or ERR_BASETYPES
738         println("*** FAILURE ***\n")
739     }
740     return returnCode1
741 }
742 
voidTestnull743 private suspend fun ThriftTestClient.voidTest(returnCode: Int): Int {
744     var returnCode1 = returnCode
745     try {
746         print("testVoid()")
747         testVoid()
748         print(" = void\n")
749     } catch (tax: TApplicationException) {
750         tax.printStackTrace()
751         returnCode1 = returnCode1 or ERR_BASETYPES
752     }
753     return returnCode1
754 }
755 
mainnull756 fun main(args: Array<String>) {
757     TestClient().main(args)
758 }
759 
<lambda>null760 private val testByteArray = (-128..127).map { it.toByte() }.toByteArray()
761