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
20package;
21
22import haxe.Int32;
23import haxe.Int64;
24import haxe.io.Bytes;
25import haxe.Timer;
26import haxe.ds.IntMap;
27import haxe.ds.StringMap;
28import haxe.ds.ObjectMap;
29
30import uuid.Uuid;
31
32import org.apache.thrift.*;
33import org.apache.thrift.helper.*;
34import org.apache.thrift.protocol.*;
35import org.apache.thrift.transport.*;
36import org.apache.thrift.server.*;
37import org.apache.thrift.meta_data.*;
38
39#if cpp
40import sys.thread.Thread;
41#else
42// no thread support (yet)
43#end
44
45import thrift.test.*;  // generated code
46
47
48using StringTools;
49
50class TestResults {
51    private var successCnt : Int = 0;
52    private var errorCnt : Int = 0;
53    private var failedTests : String = "";
54    private var print_direct : Bool = false;
55
56    public static var EXITCODE_SUCCESS            = 0x00;  // no errors bits set
57    //
58    public static var EXITCODE_FAILBIT_BASETYPES  = 0x01;
59    public static var EXITCODE_FAILBIT_STRUCTS    = 0x02;
60    public static var EXITCODE_FAILBIT_CONTAINERS = 0x04;
61    public static var EXITCODE_FAILBIT_EXCEPTIONS = 0x08;
62    //
63    public static var EXITCODE_ALL_FAILBITS       = 0x0F;
64    //
65    private var testsExecuted : Int = 0;
66    private var testsFailed : Int = 0;
67    private var currentTest : Int = 0;
68
69
70    public function new(direct : Bool) {
71        print_direct = direct;
72    }
73
74    public function StartTestGroup( groupBit : Int) : Void {
75        currentTest = groupBit;
76        testsExecuted |= groupBit;
77    }
78
79    public function Expect( expr : Bool, msg : String) : Void {
80        if ( expr) {
81            ++successCnt;
82        } else {
83            ++errorCnt;
84            testsFailed |= currentTest;
85            failedTests += "\n  " + msg;
86            if( print_direct) {
87                trace('FAIL: $msg');
88            }
89        }
90    }
91
92    public function CalculateExitCode() : Int {
93        var notExecuted : Int = EXITCODE_ALL_FAILBITS & (~testsExecuted);
94        return testsFailed | notExecuted;
95    }
96
97    public function PrintSummary() : Void {
98        var total = successCnt + errorCnt;
99        var sp = Math.round((1000 * successCnt) / total) / 10;
100        var ep = Math.round((1000 * errorCnt) / total) / 10;
101
102        trace('===========================');
103        trace('Tests executed    $total');
104        trace('Tests succeeded   $successCnt ($sp%)');
105        trace('Tests failed      $errorCnt ($ep%)');
106        if ( errorCnt > 0)
107        {
108            trace('===========================');
109            trace('FAILED TESTS: $failedTests');
110        }
111        trace('===========================');
112    }
113}
114
115
116class TestClient {
117
118    public static function Execute(args : Arguments) :  Void
119    {
120        var exitCode = 0xFF;
121        try
122        {
123            var difft = Timer.stamp();
124
125            if ( args.numThreads > 1) {
126                #if cpp
127                exitCode = MultiThreadClient(args);
128                #else
129                trace('Threads not supported/implemented for this platform.');
130                exitCode = SingleThreadClient(args);
131                #end
132            } else {
133                exitCode = SingleThreadClient(args);
134            }
135
136            difft = Math.round( 1000 * (Timer.stamp() - difft)) / 1000;
137            trace('total test time: $difft seconds');
138        }
139        catch (e : TException)
140        {
141            trace('TException: $e');
142            exitCode = 0xFF;
143        }
144        catch (e : Dynamic)
145        {
146            trace('Exception: $e');
147            exitCode = 0xFF;
148        }
149
150        #if sys
151        Sys.exit( exitCode);
152        #end
153    }
154
155
156    public static function SingleThreadClient(args : Arguments) :  Int
157    {
158        var rslt = new TestResults(true);
159        RunClient(args,rslt);
160        rslt.PrintSummary();
161        return rslt.CalculateExitCode();
162    }
163
164
165    #if cpp
166    public static function MultiThreadClient(args : Arguments) :  Int
167    {
168        var threads = new List<Thread>();
169        for( test in 0 ... args.numThreads) {
170            threads.add( StartThread( args));
171        }
172        var exitCode : Int = 0;
173        for( thread in threads) {
174            exitCode |= Thread.readMessage(true);
175        }
176        return exitCode;
177    }
178    #end
179
180    #if cpp
181    private static function StartThread(args : Arguments) : Thread {
182        var thread = Thread.create(
183            function() : Void {
184                var rslt = new TestResults(false);
185                var main : Thread = Thread.readMessage(true);
186                try
187                {
188                    RunClient(args,rslt);
189                }
190                catch (e : TException)
191                {
192                    rslt.Expect( false, '$e');
193                    trace('$e');
194                }
195                catch (e : Dynamic)
196                {
197                    rslt.Expect( false, '$e');
198                    trace('$e');
199                }
200                main.sendMessage( rslt.CalculateExitCode());
201            });
202
203        thread.sendMessage(Thread.current());
204        return thread;
205    }
206    #end
207
208
209    public static function RunClient(args : Arguments, rslt : TestResults)
210    {
211        var transport : TTransport = null;
212        switch (args.transport)
213        {
214            case socket:
215                transport = new TSocket(args.host, args.port);
216            case http:
217                var uri = 'http://${args.host}:${args.port}';
218                trace('- http client : ${uri}');
219                transport = new THttpClient(uri);
220            default:
221                throw "Unhandled transport";
222        }
223
224        // optional: layered transport
225        if ( args.framed) {
226            trace("- framed transport");
227            transport = new TFramedTransport(transport);
228        }
229        if ( args.buffered) {
230            trace("- buffered transport");
231            transport = new TBufferedTransport(transport);
232        }
233
234        // protocol
235        var protocol : TProtocol = null;
236        switch( args.protocol)
237        {
238        case binary:
239            trace("- binary protocol");
240            protocol = new TBinaryProtocol(transport);
241        case json:
242            trace("- json protocol");
243            protocol = new TJSONProtocol(transport);
244        case compact:
245            trace("- compact protocol");
246            protocol = new TCompactProtocol(transport);
247        }
248
249        // some quick and basic unit tests
250        HaxeBasicsTest( args, rslt);
251        ModuleUnitTests( args, rslt);
252
253        // now run the test code
254        trace('- ${args.numIterations} iterations');
255        for( i in 0 ... args.numIterations) {
256            ClientTest( transport, protocol, args, rslt);
257        }
258    }
259
260
261    public static function HaxeBasicsTest( args : Arguments, rslt : TestResults) : Void
262    {
263        // We need to test a few basic things used in the ClientTest
264        // Anything else beyond this scope should go into /lib/haxe/ instead
265        rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_BASETYPES);
266
267        var map32 = new IntMap<Int32>();
268        var map64 = new Int64Map<Int32>();
269
270        rslt.Expect( map32.keys().hasNext() == map64.keys().hasNext(), "Int64Map<Int32> Test #1");
271        rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map<Int32> Test #2");
272        rslt.Expect( map32.remove( 4711) == map64.remove( Int64.make(47,11)), "Int64Map<Int32> Test #3");
273        rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map<Int32> Test #4");
274
275        map32.set( 42, 815);
276        map64.set( Int64.make(0,42), 815);
277        map32.set( -517, 23);
278        map64.set( Int64.neg(Int64.make(0,517)), 23);
279        map32.set( 0, -123);
280        map64.set( Int64.make(0,0), -123);
281
282        //trace('map32 = $map32');
283        //trace('map64 = $map64');
284
285        rslt.Expect( map32.keys().hasNext() == map64.keys().hasNext(), "Int64Map<Int32> Test #10");
286        rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map<Int32> Test #11");
287        rslt.Expect( map32.exists( -517) == map64.exists( Int64.neg(Int64.make(0,517))), "Int64Map<Int32> Test #12");
288        rslt.Expect( map32.exists( 42) == map64.exists( Int64.make(0,42)), "Int64Map<Int32> Test #13");
289        rslt.Expect( map32.exists( 0) == map64.exists( Int64.make(0,0)), "Int64Map<Int32> Test #14");
290        rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map<Int32> Test #15");
291        rslt.Expect( map32.get( -517) == map64.get( Int64.neg(Int64.make(0,517))), "Int64Map<Int32> Test #16");
292        rslt.Expect( map32.get( 42) == map64.get( Int64.make(0,42)), "Int64Map<Int32> Test #Int64.make(-5,17)");
293        rslt.Expect( map32.get( 0) == map64.get( Int64.make(0,0)), "Int64Map<Int32> Test #18");
294        rslt.Expect( map32.remove( 4711) == map64.remove( Int64.make(47,11)), "Int64Map<Int32> Test #19");
295        rslt.Expect( map32.remove( -517) == map64.remove( Int64.neg(Int64.make(0,517))), "Int64Map<Int32> Test #20");
296        rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map<Int32> Test #21");
297        rslt.Expect( map32.exists( -517) == map64.exists( Int64.neg(Int64.make(0,517))), "Int64Map<Int32> Test #22");
298        rslt.Expect( map32.exists( 42) == map64.exists( Int64.make(0,42)), "Int64Map<Int32> Test #23");
299        rslt.Expect( map32.exists( 0) == map64.exists( Int64.make(0,0)), "Int64Map<Int32> Test #24");
300        rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map<Int32> Test #25");
301        rslt.Expect( map32.get( -517) == map64.get( Int64.neg(Int64.make(0,517))), "Int64Map<Int32> Test #26");
302        rslt.Expect( map32.get( 42) == map64.get( Int64.make(0,42)), "Int64Map<Int32> Test #27");
303        rslt.Expect( map32.get( 0) == map64.get( Int64.make(0,0)), "Int64Map<Int32> Test #28");
304
305        map32.set( 42, 1);
306        map64.set( Int64.make(0,42), 1);
307        map32.set( -517, -2);
308        map64.set( Int64.neg(Int64.make(0,517)), -2);
309        map32.set( 0, 3);
310        map64.set( Int64.make(0,0), 3);
311
312        var c32 = 0;
313        var ksum32 = 0;
314        for (key in map32.keys()) {
315            ++c32;
316            ksum32 += key;
317        }
318        var c64 = 0;
319        var ksum64 = Int64.make(0,0);
320        for (key in map64.keys()) {
321            ++c64;
322            ksum64 = Int64.add( ksum64, key);
323        }
324        rslt.Expect( c32 == c64, "Int64Map<Int32> Test #30");
325        rslt.Expect( '$ksum64' == '$ksum32', '$ksum64 == $ksum32   Test #31');
326
327        //compare without spaces because differ in php and cpp
328        var s32 = map32.toString().replace(' ', '');
329        var s64 = map64.toString().replace(' ', '');
330        rslt.Expect( s32 == s64, "Int64Map<Int32>.toString(): " + ' ("$s32" == "$s64") Test #32');
331
332        map32.remove( 42);
333        map64.remove( Int64.make(0,42));
334        map32.remove( -517);
335        map64.remove( Int64.neg(Int64.make(0,517)));
336        map32.remove( 0);
337        map64.remove( Int64.make(0,0));
338
339        rslt.Expect( map32.keys().hasNext() == map64.keys().hasNext(), "Int64Map<Int32> Test #90");
340        rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map<Int32> Test #91");
341        rslt.Expect( map32.exists( -517) == map64.exists( Int64.neg(Int64.make(0,517))), "Int64Map<Int32> Test #92");
342        rslt.Expect( map32.exists( 42) == map64.exists( Int64.make(0,42)), "Int64Map<Int32> Test #93");
343        rslt.Expect( map32.exists( 0) == map64.exists( Int64.make(0,0)), "Int64Map<Int32> Test #94");
344        rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map<Int32> Test #95");
345        rslt.Expect( map32.get( -517) == map64.get( Int64.make(-5,17)), "Int64Map<Int32> Test #96");
346        rslt.Expect( map32.get( 42) == map64.get( Int64.make(0,42)), "Int64Map<Int32> Test #97");
347        rslt.Expect( map32.get( 0) == map64.get( Int64.make(0, 0)), "Int64Map<Int32> Test #98");
348    }
349
350
351    // core module unit tests
352    public static function ModuleUnitTests( args : Arguments, rslt : TestResults) : Void {
353        #if debug
354
355        try {
356            BitConverter.UnitTest();
357            rslt.Expect( true, 'BitConverter.UnitTest  Test #100');
358        }
359        catch( e : Dynamic) {
360            rslt.Expect( false, 'BitConverter.UnitTest: $e  Test #100');
361        }
362
363        try {
364            ZigZag.UnitTest();
365            rslt.Expect( true, 'ZigZag.UnitTest  Test #101');
366        }
367        catch( e : Dynamic) {
368            rslt.Expect( false, 'ZigZag.UnitTest: $e  Test #101');
369        }
370
371        try {
372            UuidHelper.UnitTest();
373            rslt.Expect( true, 'UuidHelper.UnitTest  Test #102');
374        }
375        catch( e : Dynamic) {
376            rslt.Expect( false, 'UuidHelper.UnitTest: $e  Test #102');
377        }
378
379        #end
380    }
381
382
383    public static function BytesToHex(data : Bytes) : String {
384        var hex = "";
385        for ( i in 0 ... data.length) {
386            hex += StringTools.hex( data.get(i), 2);
387        }
388        return hex;
389    }
390
391    public static function PrepareTestData(randomDist : Bool) : Bytes    {
392        var retval = Bytes.alloc(0x100);
393        var initLen : Int = (retval.length > 0x100 ? 0x100 : retval.length);
394
395        // linear distribution, unless random is requested
396        if (!randomDist) {
397            for (i in 0 ... initLen) {
398                retval.set(i, i % 0x100);
399            }
400            return retval;
401        }
402
403        // random distribution
404        for (i in 0 ... initLen) {
405            retval.set(i, 0);
406        }
407        for (i in 1 ... initLen) {
408            while( true) {
409                var nextPos = Std.random(initLen);
410                if (retval.get(nextPos) == 0) {
411                    retval.set( nextPos, i % 0x100);
412                    break;
413                }
414            }
415        }
416        return retval;
417    }
418
419
420    public static function ClientTest( transport : TTransport, protocol : TProtocol,
421                                       args : Arguments, rslt : TestResults) : Void
422    {
423        var client = new ThriftTestImpl(protocol,protocol);
424        try
425        {
426            if (!transport.isOpen())
427            {
428                transport.open();
429            }
430        }
431        catch (e : TException)
432        {
433            rslt.Expect( false, 'unable to open transport: $e');
434            return;
435        }
436        catch (e : Dynamic)
437        {
438            rslt.Expect( false, 'unable to open transport: $e');
439            return;
440        }
441
442        var start = Date.now();
443
444        rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_EXCEPTIONS);
445
446        // if arg == "Xception" throw Xception with errorCode = 1001 and message = arg
447        trace('testException("Xception")');
448        try {
449            client.testException("Xception");
450            rslt.Expect( false, 'testException("Xception") should throw');
451        }
452        catch (e : Xception)
453        {
454            rslt.Expect( e.message == "Xception", 'testException("Xception")  -  e.message == "Xception"');
455            rslt.Expect( e.errorCode == 1001, 'testException("Xception")  -  e.errorCode == 1001');
456        }
457        catch (e : TException)
458        {
459            rslt.Expect( false, 'testException("Xception")  -  ${e} : ${e.errorMsg}');
460        }
461        catch (e : Dynamic)
462        {
463            rslt.Expect( false, 'testException("Xception")  -  $e');
464        }
465
466        // if arg == "TException" throw TException
467        trace('testException("TException")');
468        try {
469            client.testException("TException");
470            rslt.Expect( false, 'testException("TException") should throw');
471        }
472        catch (e : TException)
473        {
474            rslt.Expect( true, 'testException("TException")  -  $e : ${e.errorMsg}');
475        }
476        catch (e : Dynamic)
477        {
478            rslt.Expect( false, 'testException("TException")  -  $e');
479        }
480
481        // reopen the transport, just in case the server closed his end
482        if (transport.isOpen())
483            transport.close();
484        transport.open();
485
486        // else do not throw anything
487        trace('testException("bla")');
488        try {
489            client.testException("bla");
490            rslt.Expect( true, 'testException("bla") should not throw');
491        }
492        catch (e : TException)
493        {
494            rslt.Expect( false, 'testException("bla")  -  ${e} : ${e.errorMsg}');
495        }
496        catch (e : Dynamic)
497        {
498            rslt.Expect( false, 'testException("bla")  -  $e');
499        }
500
501        rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_BASETYPES);
502
503        trace('testVoid()');
504        client.testVoid();
505        trace(' = void');
506        rslt.Expect(true,"testVoid()");  // bump counter
507
508        trace('testBool(${true})');
509        var b = client.testBool(true);
510        trace(' = $b');
511        rslt.Expect(b, '$b == "${true}"');
512        trace('testBool(${false})');
513        b = client.testBool(false);
514        trace(' = $b');
515        rslt.Expect( ! b, '$b == "${false}"');
516
517        trace('testString("Test")');
518        var s = client.testString("Test");
519        trace(' = "$s"');
520        rslt.Expect(s == "Test", '$s == "Test"');
521
522        trace('testByte(1)');
523        var i8 = client.testByte(1);
524        trace(' = $i8');
525        rslt.Expect(i8 == 1, '$i8 == 1');
526
527        trace('testI32(-1)');
528        var i32 = client.testI32(-1);
529        trace(' = $i32');
530        rslt.Expect(i32 == -1, '$i32 == -1');
531
532        trace('testI64(-34359738368)');
533        var i64 = client.testI64( Int64.make( 0xFFFFFFF8, 0x00000000)); // -34359738368
534        trace(' = $i64');
535        rslt.Expect( Int64.compare( i64, Int64.make( 0xFFFFFFF8, 0x00000000)) == 0,
536                     Int64.toStr(i64) +" == "+Int64.toStr(Int64.make( 0xFFFFFFF8, 0x00000000)));
537
538        // edge case: the largest negative Int64 has no positive Int64 equivalent
539        trace('testI64(-9223372036854775808)');
540        i64 = client.testI64( Int64.make( 0x80000000, 0x00000000)); // -9223372036854775808
541        trace(' = $i64');
542        rslt.Expect( Int64.compare( i64, Int64.make( 0x80000000, 0x00000000)) == 0,
543                     Int64.toStr(i64) +" == "+Int64.toStr(Int64.make( 0x80000000, 0x00000000)));
544
545        trace('testDouble(5.325098235)');
546        var dub = client.testDouble(5.325098235);
547        trace(' = $dub');
548        rslt.Expect(dub == 5.325098235, '$dub == 5.325098235');
549
550
551		var uuidOut : String = UuidHelper.CanonicalUuid("{00112233-4455-6677-8899-AABBCCDDEEFF}");
552        trace('testUuid(${uuidOut}');
553        try {
554            var uuidIn = client.testUuid(uuidOut);
555            trace('testUuid() = ${uuidIn}');
556            rslt.Expect( uuidIn == uuidOut, '${uuidIn} == ${uuidOut}');
557        }
558        catch (e : TApplicationException) {
559            trace('testUuid(${uuidOut}): '+e.errorMsg);  // may not be supported by the server
560        }
561
562
563        var binOut = PrepareTestData(true);
564        trace('testBinary('+BytesToHex(binOut)+')');
565        try {
566            var binIn = client.testBinary(binOut);
567            trace('testBinary() = '+BytesToHex(binIn));
568            rslt.Expect( binIn.length == binOut.length, '${binIn.length} == ${binOut.length}');
569            var len = ((binIn.length < binOut.length)  ?  binIn.length  : binOut.length);
570            for (ofs in 0 ... len) {
571                if (binIn.get(ofs) != binOut.get(ofs)) {
572                    rslt.Expect( false, 'testBinary('+BytesToHex(binOut)+'): content mismatch at offset $ofs');
573                }
574            }
575        }
576        catch (e : TApplicationException) {
577            trace('testBinary('+BytesToHex(binOut)+'): '+e.errorMsg);  // may not be supported by the server
578        }
579
580
581        rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_STRUCTS);
582
583        trace('testStruct({"Zero", 1, -3, -5})');
584        var o = new Xtruct();
585        o.string_thing = "Zero";
586        o.byte_thing = 1;
587        o.i32_thing = -3;
588        o.i64_thing = Int64.make(0,-5);
589        var i = client.testStruct(o);
590        trace(' = {"' + i.string_thing + '", ' + i.byte_thing +', '
591                      + i.i32_thing +', '+ Int64.toStr(i.i64_thing) + '}');
592        rslt.Expect( i.string_thing == o.string_thing, "i.string_thing == o.string_thing");
593        rslt.Expect( i.byte_thing == o.byte_thing, "i.byte_thing == o.byte_thing");
594        rslt.Expect( i.i32_thing == o.i32_thing, "i.i64_thing == o.i64_thing");
595        rslt.Expect( i.i32_thing == o.i32_thing, "i.i64_thing == o.i64_thing");
596
597        trace('testNest({1, {\"Zero\", 1, -3, -5}, 5})');
598        var o2 = new Xtruct2();
599        o2.byte_thing = 1;
600        o2.struct_thing = o;
601        o2.i32_thing = 5;
602        var i2 = client.testNest(o2);
603        i = i2.struct_thing;
604        trace(" = {" + i2.byte_thing + ", {\"" + i.string_thing + "\", "
605              + i.byte_thing + ", " + i.i32_thing + ", " + Int64.toStr(i.i64_thing) + "}, "
606              + i2.i32_thing + "}");
607        rslt.Expect( i2.byte_thing == o2.byte_thing, "i2.byte_thing == o2.byte_thing");
608        rslt.Expect( i2.i32_thing == o2.i32_thing, "i2.i32_thing == o2.i32_thing");
609        rslt.Expect( i.string_thing == o.string_thing, "i.string_thing == o.string_thing");
610        rslt.Expect( i.byte_thing == o.byte_thing, "i.byte_thing == o.byte_thing");
611        rslt.Expect( i.i32_thing == o.i32_thing, "i.i32_thing == o.i32_thing");
612        rslt.Expect( Int64.compare( i.i64_thing, o.i64_thing) == 0, "i.i64_thing == o.i64_thing");
613
614
615        rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_CONTAINERS);
616
617        var mapout = new IntMap< haxe.Int32>();
618        for ( j in 0 ... 5)
619        {
620            mapout.set(j, j - 10);
621        }
622        trace("testMap({");
623        var first : Bool = true;
624        for( key in mapout.keys())
625        {
626            if (first)
627            {
628                first = false;
629            }
630            else
631            {
632                trace(", ");
633            }
634            trace(key + " => " + mapout.get(key));
635        }
636        trace("})");
637
638        var mapin = client.testMap(mapout);
639
640        trace(" = {");
641        first = true;
642        for( key in mapin.keys())
643        {
644            if (first)
645            {
646                first = false;
647            }
648            else
649            {
650                trace(", ");
651            }
652            trace(key + " => " + mapin.get(key));
653            rslt.Expect( mapin.get(key) == mapout.get(key), ' mapin.get($key) == mapout.get($key)');
654        }
655        trace("}");
656        for( key in mapout.keys())
657        {
658            rslt.Expect(mapin.exists(key), 'mapin.exists($key)');
659        }
660
661        var listout = new List<Int>();
662        for (j in -2 ... 3)
663        {
664            listout.add(j);
665        }
666        trace("testList({");
667        first = true;
668        for( j in listout)
669        {
670            if (first)
671            {
672                first = false;
673            }
674            else
675            {
676                trace(", ");
677            }
678            trace(j);
679        }
680        trace("})");
681
682        var listin = client.testList(listout);
683
684        trace(" = {");
685        first = true;
686        for( j in listin)
687        {
688            if (first)
689            {
690                first = false;
691            }
692            else
693            {
694                trace(", ");
695            }
696            trace(j);
697        }
698        trace("}");
699
700        rslt.Expect(listin.length == listout.length, "listin.length == listout.length");
701        var literout = listout.iterator();
702        var literin = listin.iterator();
703        while( literin.hasNext()) {
704            rslt.Expect(literin.next() == literout.next(), "literin[i] == literout[i]");
705        }
706
707        //set
708        var setout = new IntSet();
709        for (j in -2 ... 3)
710        {
711            setout.add(j);
712        }
713        trace("testSet({");
714        first = true;
715        for( j in setout)
716        {
717            if (first)
718            {
719                first = false;
720            }
721            else
722            {
723                trace(", ");
724            }
725            trace(j);
726        }
727        trace("})");
728
729        var setin = client.testSet(setout);
730
731        trace(" = {");
732        first = true;
733        for( j in setin)
734        {
735            if (first)
736            {
737                first = false;
738            }
739            else
740            {
741                trace(", ");
742            }
743            trace(j);
744            rslt.Expect(setout.contains(j), 'setout.contains($j)');
745        }
746        trace("}");
747        rslt.Expect(setin.size == setout.size, "setin.length == setout.length");
748
749
750        rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_BASETYPES);
751
752        trace("testEnum(ONE)");
753        var ret = client.testEnum(Numberz.ONE);
754        trace(" = " + ret);
755        rslt.Expect(ret == Numberz.ONE, '$ret == Numberz.ONE');
756
757        trace("testEnum(TWO)");
758        ret = client.testEnum(Numberz.TWO);
759        trace(" = " + ret);
760        rslt.Expect(ret == Numberz.TWO, '$ret == Numberz.TWO');
761
762        trace("testEnum(THREE)");
763        ret = client.testEnum(Numberz.THREE);
764        trace(" = " + ret);
765        rslt.Expect(ret == Numberz.THREE, '$ret == Numberz.THREE');
766
767        trace("testEnum(FIVE)");
768        ret = client.testEnum(Numberz.FIVE);
769        trace(" = " + ret);
770        rslt.Expect(ret == Numberz.FIVE, '$ret == Numberz.FIVE');
771
772        trace("testEnum(EIGHT)");
773        ret = client.testEnum(Numberz.EIGHT);
774        trace(" = " + ret);
775        rslt.Expect(ret == Numberz.EIGHT, '$ret == Numberz.EIGHT');
776
777        trace("testTypedef(309858235082523)");
778        var uid = client.testTypedef( Int64.make( 0x119D0, 0x7E08671B));  // 309858235082523
779        trace(" = " + uid);
780        rslt.Expect( Int64.compare( uid, Int64.make( 0x119D0, 0x7E08671B)) == 0,
781                     Int64.toStr(uid)+" == "+Int64.toStr(Int64.make( 0x119D0, 0x7E08671B)));
782
783
784        rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_CONTAINERS);
785
786        trace("testMapMap(1)");
787        var mm = client.testMapMap(1);
788        trace(" = {");
789        for( key in mm.keys())
790        {
791            trace(key + " => {");
792            var m2 = mm.get(key);
793            for( k2 in m2.keys())
794            {
795                trace(k2 + " => " + m2.get(k2) + ", ");
796            }
797            trace("}, ");
798        }
799        trace("}");
800
801        var pos = mm.get(4);
802        var neg = mm.get(-4);
803        rslt.Expect( (pos != null) && (neg != null), "(pos != null) && (neg != null)");
804        for (i in 1 ... 5) {
805            rslt.Expect( pos.get(i) == i, 'pos.get($i) == $i');
806            rslt.Expect( neg.get(-i) == -i, 'neg.get(-$i) == -$i');
807        }
808        rslt.Expect( ! pos.exists(0), '!pos.exists(0)');
809        rslt.Expect( ! neg.exists(-0), '!neg.exists(-0)');
810        rslt.Expect( ! pos.exists(42), '!pos.exists(42)');
811        rslt.Expect( ! neg.exists(-42), '!neg.exists(-42)');
812
813
814        rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_STRUCTS);
815
816        var insane = new Insanity();
817        insane.userMap = new IntMap< Int64>();
818        insane.userMap.set( Numberz.FIVE, Int64.make(0,5000));
819        var truck = new Xtruct();
820        truck.string_thing = "Truck";
821        truck.byte_thing = 8;
822        truck.i32_thing = 8;
823        truck.i64_thing = Int64.make(0,8);
824        insane.xtructs = new List<Xtruct>();
825        insane.xtructs.add(truck);
826        trace("testInsanity()");
827        var whoa = client.testInsanity(insane);
828        trace(" = {");
829        for( key in whoa.keys())
830        {
831            var val = whoa.get(key);
832            trace(key + " => {");
833
834            for( k2 in val.keys())
835            {
836                var v2 = val.get(k2);
837
838                trace(k2 + " => {");
839                var userMap = v2.userMap;
840
841                trace("{");
842                if (userMap != null)
843                {
844                    for( k3 in userMap.keys())
845                    {
846                        trace(k3 + " => " + userMap.get(k3) + ", ");
847                    }
848                }
849                else
850                {
851                    trace("null");
852                }
853                trace("}, ");
854
855                var xtructs = v2.xtructs;
856
857                trace("{");
858                if (xtructs != null)
859                {
860                    for( x in xtructs)
861                    {
862                        trace("{\"" + x.string_thing + "\", "
863                              + x.byte_thing + ", " + x.i32_thing + ", "
864                              + x.i32_thing + "}, ");
865                    }
866                }
867                else
868                {
869                    trace("null");
870                }
871                trace("}");
872
873                trace("}, ");
874            }
875            trace("}, ");
876        }
877        trace("}");
878
879
880		/**
881		* So you think you've got this all worked, out eh?
882		*
883		* Creates a the returned map with these values and prints it out:
884		*   { 1 => { 2 => argument,
885		*            3 => argument,
886		*          },
887		*     2 => { 6 => <empty Insanity struct>, },
888		*   }
889		* @return map<UserId, map<Numberz,Insanity>> - a map with the above values
890		*/
891
892        var first_map = whoa.get(Int64.make(0,1));
893        var second_map = whoa.get(Int64.make(0,2));
894        rslt.Expect( (first_map != null) && (second_map != null), "(first_map != null) && (second_map != null)");
895        if ((first_map != null) && (second_map != null))
896        {
897            var crazy2 = first_map.get(Numberz.TWO);
898            var crazy3 = first_map.get(Numberz.THREE);
899            var looney = second_map.get(Numberz.SIX);
900            rslt.Expect( (crazy2 != null) && (crazy3 != null) && (looney != null),
901                        "(crazy2 != null) && (crazy3 != null) && (looney != null)");
902
903            var crz2iter = crazy2.xtructs.iterator();
904            var crz3iter = crazy3.xtructs.iterator();
905            rslt.Expect( crz2iter.hasNext() && crz3iter.hasNext(), "crz2iter.hasNext() && crz3iter.hasNext()");
906            var goodbye2 = crz2iter.next();
907            var goodbye3 = crz3iter.next();
908            rslt.Expect( ! (crz2iter.hasNext() || crz3iter.hasNext()), "! (crz2iter.hasNext() || crz3iter.hasNext())");
909
910			rslt.Expect( Int64.compare( crazy2.userMap.get(Numberz.FIVE), insane.userMap.get(Numberz.FIVE)) == 0, "crazy2.userMap[5] == insane.userMap[5]");
911			rslt.Expect( truck.string_thing == goodbye2.string_thing, "truck.string_thing == goodbye2.string_thing");
912			rslt.Expect( truck.byte_thing  == goodbye2.byte_thing, "truck.byte_thing  == goodbye2.byte_thing");
913			rslt.Expect( truck.i32_thing  == goodbye2.i32_thing, "truck.i32_thing  == goodbye2.i32_thing");
914			rslt.Expect( Int64.compare( truck.i64_thing, goodbye2.i64_thing) == 0, "truck.i64_thing  == goodbye2.i64_thing");
915
916			rslt.Expect( Int64.compare( crazy3.userMap.get(Numberz.FIVE), insane.userMap.get(Numberz.FIVE)) == 0, "crazy3.userMap[5] == insane.userMap[5]");
917			rslt.Expect( truck.string_thing == goodbye3.string_thing, "truck.string_thing == goodbye3.string_thing");
918			rslt.Expect( truck.byte_thing  == goodbye3.byte_thing, "truck.byte_thing  == goodbye3.byte_thing");
919			rslt.Expect( truck.i32_thing  == goodbye3.i32_thing, "truck.i32_thing  == goodbye3.i32_thing");
920			rslt.Expect( Int64.compare( truck.i64_thing, goodbye3.i64_thing) == 0, "truck.i64_thing  == goodbye3.i64_thing");
921
922			rslt.Expect( ! looney.isSet(1), "! looney.isSet(1)");
923			rslt.Expect( ! looney.isSet(2), "! looney.isSet(2)");
924        }
925
926        var arg0 = 1;
927        var arg1 = 2;
928        var arg2 = Int64.make( 0x7FFFFFFF,0xFFFFFFFF);
929        var multiDict = new IntMap< String>();
930        multiDict.set(1, "one");
931        var arg4 = Numberz.FIVE;
932        var arg5 = Int64.make(0,5000000);
933        trace("Test Multi(" + arg0 + "," + arg1 + "," + arg2 + "," + multiDict + "," + arg4 + "," + arg5 + ")");
934        var multiResponse = client.testMulti(arg0, arg1, arg2, multiDict, arg4, arg5);
935        trace(" = Xtruct(byte_thing:" + multiResponse.byte_thing + ",string_thing:" + multiResponse.string_thing
936                    + ",i32_thing:" + multiResponse.i32_thing
937                    + ",i64_thing:" + Int64.toStr(multiResponse.i64_thing) + ")");
938
939        rslt.Expect( multiResponse.string_thing == "Hello2", 'multiResponse.String_thing == "Hello2"');
940        rslt.Expect( multiResponse.byte_thing == arg0, 'multiResponse.Byte_thing == arg0');
941        rslt.Expect( multiResponse.i32_thing == arg1, 'multiResponse.I32_thing == arg1');
942        rslt.Expect( Int64.compare( multiResponse.i64_thing, arg2) == 0, 'multiResponse.I64_thing == arg2');
943
944
945        rslt.StartTestGroup( 0);
946
947        trace("Test Oneway(1)");
948        client.testOneway(1);
949
950        if( ! args.skipSpeedTest) {
951            trace("Test Calltime()");
952            var difft = Timer.stamp();
953            for ( k in 0 ... 1000) {
954                client.testVoid();
955            }
956            difft = Math.round( 1000 * (Timer.stamp() - difft)) / 1000;
957            trace('$difft ms per testVoid() call');
958        }
959    }
960}
961