THRIFT-2644 Haxe support
Client: Haxe
Patch: Jens Geyer

This closes #214
diff --git a/test/haxe/src/TestClient.hx b/test/haxe/src/TestClient.hx
new file mode 100644
index 0000000..8698220
--- /dev/null
+++ b/test/haxe/src/TestClient.hx
@@ -0,0 +1,696 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package;
+
+import haxe.Int32;
+import haxe.Int64;
+import haxe.Timer;
+import haxe.ds.IntMap;
+import haxe.ds.StringMap;
+import haxe.ds.ObjectMap;
+
+import org.apache.thrift.*;
+import org.apache.thrift.helper.*;
+import org.apache.thrift.protocol.*;
+import org.apache.thrift.transport.*;
+import org.apache.thrift.server.*;
+import org.apache.thrift.meta_data.*;
+
+#if cpp
+import cpp.vm.Thread;
+#else
+// no thread support (yet)
+#end
+
+import thrift.test.*;  // generated code
+
+
+class TestResults {
+	private var successCnt : Int = 0;
+	private var errorCnt : Int = 0;
+	private var failedTests : String = "";
+	private var print_direct : Bool = false;
+
+	public function new(direct : Bool) {
+		print_direct = direct;
+	}
+	
+	public function Expect( expr : Bool, msg : String) : Void {
+		if ( expr) {
+			++successCnt;
+		} else {
+			++errorCnt;
+			failedTests += "\n  " + msg;
+			if( print_direct) {
+				trace('FAIL: $msg');
+			}
+		}
+	}
+
+
+	public function PrintSummary() : Void {
+		var total = successCnt + errorCnt;
+		var sp = (100 * successCnt) / total;
+		var ep = (100 * errorCnt) / total;
+		
+		trace('===========================');
+		trace('Tests executed    $total');
+		trace('Tests succeeded   $successCnt ($sp%)');
+		trace('Tests failed      $errorCnt ($ep%)');
+		if ( errorCnt > 0)
+		{
+			trace('===========================');
+  			trace('FAILED TESTS: $failedTests');
+		}
+		trace('===========================');
+	}
+}
+
+
+class TestClient {
+
+	public static function Execute(args : Arguments) :  Void
+	{
+		try
+		{
+			var difft = Timer.stamp();
+			
+			if( args.numThreads > 1) {
+				var threads = new List<Thread>();
+				for( test in 0 ... args.numThreads) {
+					threads.add( StartThread( args));
+				} 
+				for( thread in threads) {
+					Thread.readMessage(true);
+				}
+			} else {
+				var rslt = new TestResults(true);
+				RunClient(args,rslt);
+				rslt.PrintSummary();
+			}
+
+    		difft = Timer.stamp() - difft;
+			trace('total test time: $difft seconds');
+		}
+		catch (e : TException)
+		{
+			trace('$e');
+		}
+		catch (e : Dynamic)
+		{
+			trace('$e');
+		}
+	}
+
+	
+	private static function StartThread(args : Arguments) : Thread {
+		var thread = Thread.create(
+			function() : Void {
+				var main : Thread = Thread.readMessage(true);
+				try 
+				{
+					var rslt = new TestResults(false);
+					RunClient(args,rslt);
+					// TODO: promote rslt values to main thread
+				}
+				catch (e : TException)
+				{
+					trace('$e');
+				}
+				catch (e : Dynamic)
+				{
+					trace('$e');
+				}					
+				main.sendMessage("done");
+			});
+		
+		thread.sendMessage(Thread.current());
+		return thread;
+	}
+
+	
+	public static function RunClient(args : Arguments, rslt : TestResults)
+	{
+		var transport : TTransport = null;
+		switch (args.transport)
+		{
+			case socket:
+				transport = new TSocket(args.host, args.port);
+			case http:
+				throw "http transport not supported yet";
+				//transport = new THttpClient(args.host);
+			default:
+				throw "Unhandled transport";
+		}
+
+		// optional: layered transport
+		if ( args.framed) {
+			trace("- framed transport");
+			transport = new TFramedTransport(transport);
+		} else if ( args.buffered) {
+			trace("- buffered transport");
+			throw "TBufferedTransport not implemented yet";
+			//transport = new TBufferedTransport(transport);
+		}
+
+		// protocol
+		var protocol : TProtocol = null;
+		switch( args.protocol)
+		{
+		case binary:
+			trace("- binary protocol");
+			protocol = new TBinaryProtocol(transport);
+		case json:
+			trace("- json protocol");
+			protocol = new TJSONProtocol(transport);
+		default:
+			throw "Unhandled protocol";
+		}
+
+
+		// run the test code
+		HaxeBasicsTest( rslt);
+		ClientTest( transport, protocol, rslt);
+					
+	}
+
+
+	public static function HaxeBasicsTest( rslt : TestResults) : Void
+	{
+		// We need to test a few basic things used in the ClientTest
+		// Anything else beyond this scope should go into /lib/haxe/ instead
+		
+		var map32 = new IntMap<Int32>();
+		var map64 = new Int64Map<Int32>();
+
+		rslt.Expect( map32.keys().hasNext() == map64.keys().hasNext(), "Int64Map<Int32> Test #1");
+		rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map<Int32> Test #2");
+		rslt.Expect( map32.remove( 4711) == map64.remove( Int64.make(47,11)), "Int64Map<Int32> Test #3");
+		rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map<Int32> Test #4");
+		
+		map32.set( 42, 815);
+		map64.set( Int64.make(0,42), 815);
+		map32.set( -517, 23);
+		map64.set( Int64.make(-5,17), 23);
+		map32.set( 0, -123);
+		map64.set( Int64.make(0,0), -123);
+
+		rslt.Expect( map32.keys().hasNext() == map64.keys().hasNext(), "Int64Map<Int32> Test #10");
+		rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map<Int32> Test #11");
+		rslt.Expect( map32.exists( -517) == map64.exists( Int64.make(-5,17)), "Int64Map<Int32> Test #12");
+		rslt.Expect( map32.exists( 42) == map64.exists( Int64.make(0,42)), "Int64Map<Int32> Test #13");
+		rslt.Expect( map32.exists( 0) == map64.exists( Int64.make(0,0)), "Int64Map<Int32> Test #14");
+		rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map<Int32> Test #15");
+		rslt.Expect( map32.get( -517) == map64.get( Int64.make(-5,17)), "Int64Map<Int32> Test #16");
+		rslt.Expect( map32.get( 42) == map64.get( Int64.make(0,42)), "Int64Map<Int32> Test #Int64.make(-5,17)");
+		rslt.Expect( map32.get( 0) == map64.get( Int64.make(0,0)), "Int64Map<Int32> Test #18");
+		rslt.Expect( map32.remove( 4711) == map64.remove( Int64.make(47,11)), "Int64Map<Int32> Test #19");
+		rslt.Expect( map32.remove( -517) == map64.remove( Int64.make(-5,17)), "Int64Map<Int32> Test #20");
+		rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map<Int32> Test #21");
+		rslt.Expect( map32.exists( -517) == map64.exists( Int64.make(-5,17)), "Int64Map<Int32> Test #22");
+		rslt.Expect( map32.exists( 42) == map64.exists( Int64.make(0,42)), "Int64Map<Int32> Test #23");
+		rslt.Expect( map32.exists( 0) == map64.exists( Int64.make(0,0)), "Int64Map<Int32> Test #24");
+		rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map<Int32> Test #25");
+		rslt.Expect( map32.get( -517) == map64.get( Int64.make(-5,17)), "Int64Map<Int32> Test #26");
+		rslt.Expect( map32.get( 42) == map64.get( Int64.make(0,42)), "Int64Map<Int32> Test #27");
+		rslt.Expect( map32.get( 0) == map64.get( Int64.make(0,0)), "Int64Map<Int32> Test #28");
+
+		map32.set( 42, 1);
+		map64.set( Int64.make(0,42), 1);
+		map32.set( -517, -2);
+		map64.set( Int64.make(-5,17), -2);
+		map32.set( 0, 3);
+		map64.set( Int64.make(0,0), 3);
+
+		var c32 = 0;
+		for (key in map32.keys()) {
+			++c32;
+		}
+		var c64 = 0;
+		for (key in map64.keys()) {
+			++c64;
+		}
+		rslt.Expect( c32 == c64, "Int64Map<Int32> Test #30");
+
+		var s32 = map32.toString();
+		var s64 = map64.toString();
+		trace("Int64Map<Int32>.toString(): " + ' ("$s32" == "$s64")');
+
+		map32.remove( 42);
+		map64.remove( Int64.make(0,42));
+		map32.remove( -517);
+		map64.remove( Int64.make(-5,17));
+		map32.remove( 0);
+		map64.remove( Int64.make(0,0));
+		
+		rslt.Expect( map32.keys().hasNext() == map64.keys().hasNext(), "Int64Map<Int32> Test #90");
+		rslt.Expect( map32.exists( 4711) == map64.exists( Int64.make(47,11)), "Int64Map<Int32> Test #91");
+		rslt.Expect( map32.exists( -517) == map64.exists( Int64.make(-5,17)), "Int64Map<Int32> Test #92");
+		rslt.Expect( map32.exists( 42) == map64.exists( Int64.make(0,42)), "Int64Map<Int32> Test #93");
+		rslt.Expect( map32.exists( 0) == map64.exists( Int64.make(0,0)), "Int64Map<Int32> Test #94");
+		rslt.Expect( map32.get( 4711) == map64.get( Int64.make(47,11)), "Int64Map<Int32> Test #95");
+		rslt.Expect( map32.get( -517) == map64.get( Int64.make(-5,17)), "Int64Map<Int32> Test #96");
+		rslt.Expect( map32.get( 42) == map64.get( Int64.make(0,42)), "Int64Map<Int32> Test #97");
+		rslt.Expect( map32.get( 0) == map64.get( Int64.make(0,0)), "Int64Map<Int32> Test #98");
+	}
+
+
+	public static function ClientTest( transport : TTransport, protocol : TProtocol, rslt : TestResults) : Void
+	{
+		var client = new ThriftTestImpl(protocol,protocol);
+		try
+		{
+			if (!transport.isOpen())
+			{
+				transport.open();
+			}
+		}
+		catch (e : TException)
+		{
+			trace('$e');
+			return;
+		}
+		catch (e : Dynamic)
+		{
+			trace('$e');
+			return;
+		}
+
+		var start = Date.now();
+
+		trace('testVoid()');
+		client.testVoid();
+		trace(' = void');
+		rslt.Expect(true,"testVoid()");  // bump counter
+
+		trace('testString("Test")');
+		var s = client.testString("Test");
+		trace(' = "$s"');
+		rslt.Expect(s == "Test", '$s == "Test"');
+
+		trace('testByte(1)');
+		var i8 = client.testByte(1);
+		trace(' = $i8');
+		rslt.Expect(i8 == 1, '$i8 == 1');
+
+		trace('testI32(-1)');
+		var i32 = client.testI32(-1);
+		trace(' = $i32');
+		rslt.Expect(i32 == -1, '$i32 == -1');
+
+		trace('testI64(-34359738368)');
+		var i64 = client.testI64( Int64.make( 0xFFFFFFF8, 0x00000000)); // -34359738368
+		trace(' = $i64');
+		rslt.Expect( Int64.compare( i64, Int64.make( 0xFFFFFFF8, 0x00000000)) == 0, 
+		             Int64.toStr(i64) +" == "+Int64.toStr(Int64.make( 0xFFFFFFF8, 0x00000000)));
+
+		// edge case: the largest negative Int64 has no positive Int64 equivalent
+		trace('testI64(-9223372036854775808)');
+		i64 = client.testI64( Int64.make( 0x80000000, 0x00000000)); // -9223372036854775808
+		trace(' = $i64');
+		rslt.Expect( Int64.compare( i64, Int64.make( 0x80000000, 0x00000000)) == 0, 
+		             Int64.toStr(i64) +" == "+Int64.toStr(Int64.make( 0x80000000, 0x00000000)));
+
+		trace('testDouble(5.325098235)');
+		var dub = client.testDouble(5.325098235);
+		trace(' = $dub');
+		rslt.Expect(dub == 5.325098235, '$dub == 5.325098235');
+
+		trace('testStruct({"Zero", 1, -3, -5})');
+		var o = new Xtruct();
+		o.string_thing = "Zero";
+		o.byte_thing = 1;
+		o.i32_thing = -3;
+		o.i64_thing = Int64.make(0,-5);
+		var i = client.testStruct(o);
+		trace(' = {"' + i.string_thing + '", ' + i.byte_thing +', ' 
+                      + i.i32_thing +', '+ Int64.toStr(i.i64_thing) + '}');
+		rslt.Expect( i.string_thing == o.string_thing, "i.string_thing == o.string_thing");
+		rslt.Expect( i.byte_thing == o.byte_thing, "i.byte_thing == o.byte_thing");
+		rslt.Expect( i.i32_thing == o.i32_thing, "i.i64_thing == o.i64_thing");
+		rslt.Expect( i.i32_thing == o.i32_thing, "i.i64_thing == o.i64_thing");
+
+		trace('testNest({1, {\"Zero\", 1, -3, -5}, 5})');
+		var o2 = new Xtruct2();
+		o2.byte_thing = 1;
+		o2.struct_thing = o;
+		o2.i32_thing = 5;
+		var i2 = client.testNest(o2);
+		i = i2.struct_thing;
+		trace(" = {" + i2.byte_thing + ", {\"" + i.string_thing + "\", " 
+			  + i.byte_thing + ", " + i.i32_thing + ", " + Int64.toStr(i.i64_thing) + "}, " 
+			  + i2.i32_thing + "}");
+		rslt.Expect( i2.byte_thing == o2.byte_thing, "i2.byte_thing == o2.byte_thing");
+		rslt.Expect( i2.i32_thing == o2.i32_thing, "i2.i32_thing == o2.i32_thing");
+		rslt.Expect( i.string_thing == o.string_thing, "i.string_thing == o.string_thing");
+		rslt.Expect( i.byte_thing == o.byte_thing, "i.byte_thing == o.byte_thing");
+		rslt.Expect( i.i32_thing == o.i32_thing, "i.i32_thing == o.i32_thing");
+		rslt.Expect( Int64.compare( i.i64_thing, o.i64_thing) == 0, "i.i64_thing == o.i64_thing");
+
+		var mapout = new IntMap< haxe.Int32>();
+		for ( j in 0 ... 5)
+		{
+			mapout.set(j, j - 10);
+		}
+		trace("testMap({");
+		var first : Bool = true;
+		for( key in mapout.keys())
+		{
+			if (first)
+			{
+				first = false;
+			}
+			else
+			{
+				trace(", ");
+			}
+			trace(key + " => " + mapout.get(key));
+		}
+		trace("})");
+
+		var mapin = client.testMap(mapout);
+
+		trace(" = {");
+		first = true;
+		for( key in mapin.keys())
+		{
+			if (first)
+			{
+				first = false;
+			}
+			else
+			{
+				trace(", ");
+			}
+			trace(key + " => " + mapin.get(key));
+			rslt.Expect( mapin.get(key) == mapout.get(key), ' mapin.get($key) == mapout.get($key)');
+		}
+		trace("}");
+		for( key in mapout.keys())
+		{
+			rslt.Expect(mapin.exists(key), 'mapin.exists($key)');
+		}
+
+		var listout = new List<Int>();
+		for (j in -2 ... 3)
+		{
+			listout.add(j);
+		}
+		trace("testList({");
+		first = true;
+		for( j in listout)
+		{
+			if (first)
+			{
+				first = false;
+			}
+			else
+			{
+				trace(", ");
+			}
+			trace(j);
+		}
+		trace("})");
+
+		var listin = client.testList(listout);
+
+		trace(" = {");
+		first = true;
+		for( j in listin)
+		{
+			if (first)
+			{
+				first = false;
+			}
+			else
+			{
+				trace(", ");
+			}
+			trace(j);
+		}
+		trace("}");
+
+		rslt.Expect(listin.length == listout.length, "listin.length == listout.length");
+		var literout = listout.iterator();
+		var literin = listin.iterator();
+		while( literin.hasNext()) {
+			rslt.Expect(literin.next() == literout.next(), "literin[i] == literout[i]");
+		}
+	
+		//set
+		var setout = new IntSet();
+		for (j in -2 ... 3)
+		{
+			setout.add(j);
+		}
+		trace("testSet({");
+		first = true;
+		for( j in setout)
+		{
+			if (first)
+			{
+				first = false;
+			}
+			else
+			{
+				trace(", ");
+			}
+			trace(j);
+		}
+		trace("})");
+
+		var setin = client.testSet(setout);
+
+		trace(" = {");
+		first = true;
+		for( j in setin)
+		{
+			if (first)
+			{
+				first = false;
+			}
+			else
+			{
+				trace(", ");
+			}
+			trace(j);
+			rslt.Expect(setout.contains(j), 'setout.contains($j)');
+		}
+		trace("}");
+		rslt.Expect(setin.size == setout.size, "setin.length == setout.length");
+	
+
+		trace("testEnum(ONE)");
+		var ret = client.testEnum(Numberz.ONE);
+		trace(" = " + ret);
+		rslt.Expect(ret == Numberz.ONE, '$ret == Numberz.ONE');
+
+		trace("testEnum(TWO)");
+		ret = client.testEnum(Numberz.TWO);
+		trace(" = " + ret);
+		rslt.Expect(ret == Numberz.TWO, '$ret == Numberz.TWO');
+
+		trace("testEnum(THREE)");
+		ret = client.testEnum(Numberz.THREE);
+		trace(" = " + ret);
+		rslt.Expect(ret == Numberz.THREE, '$ret == Numberz.THREE');
+
+		trace("testEnum(FIVE)");
+		ret = client.testEnum(Numberz.FIVE);
+		trace(" = " + ret);
+		rslt.Expect(ret == Numberz.FIVE, '$ret == Numberz.FIVE');
+
+		trace("testEnum(EIGHT)");
+		ret = client.testEnum(Numberz.EIGHT);
+		trace(" = " + ret);
+		rslt.Expect(ret == Numberz.EIGHT, '$ret == Numberz.EIGHT');
+
+		trace("testTypedef(309858235082523)");
+		var uid = client.testTypedef( Int64.make( 0x119D0, 0x7E08671B));  // 309858235082523
+		trace(" = " + uid);
+		rslt.Expect( Int64.compare( uid, Int64.make( 0x119D0, 0x7E08671B)) == 0,
+		             Int64.toStr(uid)+" == "+Int64.toStr(Int64.make( 0x119D0, 0x7E08671B)));
+
+		trace("testMapMap(1)");
+		var mm = client.testMapMap(1);
+		trace(" = {");
+		for( key in mm.keys())
+		{
+			trace(key + " => {");
+			var m2 = mm.get(key);
+			for( k2 in m2.keys())
+			{
+				trace(k2 + " => " + m2.get(k2) + ", ");
+			}
+			trace("}, ");
+		}
+		trace("}");
+
+		var pos = mm.get(4);
+		var neg = mm.get(-4);
+		rslt.Expect( (pos != null) && (neg != null), "(pos != null) && (neg != null)");
+		for (i in 0 ... 5) {
+			rslt.Expect( pos.get(i) == i, 'pos.get($i) == $i');
+			rslt.Expect( neg.get(-i) == -i, 'neg.get(-$i) == -$i');
+	 	}
+
+		var insane = new Insanity();
+		insane.userMap = new IntMap< Int64>();
+		insane.userMap.set( Numberz.FIVE, Int64.make(0,5000));
+		var truck = new Xtruct();
+		truck.string_thing = "Truck";
+		truck.byte_thing = 8;
+		truck.i32_thing = 8;
+		truck.i64_thing = Int64.make(0,8);
+		insane.xtructs = new List<Xtruct>();
+		insane.xtructs.add(truck);
+		trace("testInsanity()");
+		var whoa = client.testInsanity(insane);
+		trace(" = {");
+		for( key in whoa.keys())
+		{
+			var val = whoa.get(key);
+			trace(key + " => {");
+
+			for( k2 in val.keys())
+			{
+				var v2 = val.get(k2);
+
+				trace(k2 + " => {");
+				var userMap = v2.userMap;
+
+				trace("{");
+				if (userMap != null)
+				{
+					for( k3 in userMap.keys())
+					{
+						trace(k3 + " => " + userMap.get(k3) + ", ");
+					}
+				}
+				else
+				{
+					trace("null");
+				}
+				trace("}, ");
+
+				var xtructs = v2.xtructs;
+
+				trace("{");
+				if (xtructs != null)
+				{
+					for( x in xtructs)
+					{
+						trace("{\"" + x.string_thing + "\", " 
+							  + x.byte_thing + ", " + x.i32_thing + ", " 
+							  + x.i32_thing + "}, ");
+					}
+				}
+				else
+				{
+					trace("null");
+				}
+				trace("}");
+
+				trace("}, ");
+			}
+			trace("}, ");
+		}
+		trace("}");
+
+		var first_map = whoa.get(Int64.make(0,1));
+		var second_map = whoa.get(Int64.make(0,2));
+		rslt.Expect( (first_map != null) && (second_map != null), "(first_map != null) && (second_map != null)");
+		if ((first_map != null) && (second_map != null))
+		{
+			var crazy2 = first_map.get(Numberz.TWO);
+			var crazy3 = first_map.get(Numberz.THREE);
+			var looney = second_map.get(Numberz.SIX);
+			rslt.Expect( (crazy2 != null) && (crazy3 != null) && (looney != null), 
+						"(crazy2 != null) && (crazy3 != null) && (looney != null)");
+
+			rslt.Expect( Int64.compare( crazy2.userMap.get(Numberz.EIGHT), Int64.make(0,8)) == 0, 
+						"crazy2.UserMap.get(Numberz.EIGHT) == 8");
+			rslt.Expect( Int64.compare( crazy3.userMap.get(Numberz.EIGHT), Int64.make(0,8)) == 0, 
+						"crazy3.UserMap.get(Numberz.EIGHT) == 8");
+			rslt.Expect( Int64.compare( crazy2.userMap.get(Numberz.FIVE), Int64.make(0,5)) == 0, 
+						"crazy2.UserMap.get(Numberz.FIVE) == 5");
+			rslt.Expect( Int64.compare( crazy3.userMap.get(Numberz.FIVE), Int64.make(0,5)) == 0, 
+						"crazy3.UserMap.get(Numberz.FIVE) == 5");
+
+			var crz2iter = crazy2.xtructs.iterator();
+			var crz3iter = crazy3.xtructs.iterator();
+			rslt.Expect( crz2iter.hasNext() && crz3iter.hasNext(), "crz2iter.hasNext() && crz3iter.hasNext()");
+			var goodbye2 = crz2iter.next();
+			var goodbye3 = crz3iter.next();
+			rslt.Expect( crz2iter.hasNext() && crz3iter.hasNext(), "crz2iter.hasNext() && crz3iter.hasNext()");
+			var hello2 = crz2iter.next();
+			var hello3 = crz3iter.next();
+			rslt.Expect( ! (crz2iter.hasNext() || crz3iter.hasNext()), "! (crz2iter.hasNext() || crz3iter.hasNext())");
+
+			rslt.Expect( hello2.string_thing == "Hello2", 'hello2.String_thing == "Hello2"');
+			rslt.Expect( hello2.byte_thing == 2, 'hello2.Byte_thing == 2');
+			rslt.Expect( hello2.i32_thing == 2, 'hello2.I32_thing == 2');
+			rslt.Expect( Int64.compare( hello2.i64_thing, Int64.make(0,2)) == 0, 'hello2.I64_thing == 2');
+			rslt.Expect( hello3.string_thing == "Hello2", 'hello3.String_thing == "Hello2"');
+			rslt.Expect( hello3.byte_thing == 2, 'hello3.Byte_thing == 2');
+			rslt.Expect( hello3.i32_thing == 2, 'hello3.I32_thing == 2');
+			rslt.Expect( Int64.compare( hello3.i64_thing, Int64.make(0,2)) == 0, 'hello3.I64_thing == 2');
+
+			rslt.Expect( goodbye2.string_thing == "Goodbye4", 'goodbye2.String_thing == "Goodbye4"');
+			rslt.Expect( goodbye2.byte_thing == 4, 'goodbye2.Byte_thing == 4');
+			rslt.Expect( goodbye2.i32_thing == 4, 'goodbye2.I32_thing == 4');
+			rslt.Expect( Int64.compare( goodbye2.i64_thing, Int64.make(0,4)) == 0, 'goodbye2.I64_thing == 4');
+			rslt.Expect( goodbye3.string_thing == "Goodbye4", 'goodbye3.String_thing == "Goodbye4"');
+			rslt.Expect( goodbye3.byte_thing == 4, 'goodbye3.Byte_thing == 4');
+			rslt.Expect( goodbye3.i32_thing == 4, 'goodbye3.I32_thing == 4');
+			rslt.Expect( Int64.compare( goodbye3.i64_thing, Int64.make(0,4)) == 0, 'goodbye3.I64_thing == 4');
+		}
+
+		var arg0 = 1;
+		var arg1 = 2;
+		var arg2 = Int64.make( 0x7FFFFFFF,0xFFFFFFFF);
+		var multiDict = new IntMap< String>();
+		multiDict.set(1, "one");
+		var arg4 = Numberz.FIVE;
+		var arg5 = Int64.make(0,5000000);
+		trace("Test Multi(" + arg0 + "," + arg1 + "," + arg2 + "," + multiDict + "," + arg4 + "," + arg5 + ")");
+		var multiResponse = client.testMulti(arg0, arg1, arg2, multiDict, arg4, arg5);
+		trace(" = Xtruct(byte_thing:" + multiResponse.byte_thing + ",string_thing:" + multiResponse.string_thing
+					+ ",i32_thing:" + multiResponse.i32_thing 
+			        + ",i64_thing:" + Int64.toStr(multiResponse.i64_thing) + ")");
+
+		rslt.Expect( multiResponse.string_thing == "Hello2", 'multiResponse.String_thing == "Hello2"');
+		rslt.Expect( multiResponse.byte_thing == arg0, 'multiResponse.Byte_thing == arg0');
+		rslt.Expect( multiResponse.i32_thing == arg1, 'multiResponse.I32_thing == arg1');
+		rslt.Expect( Int64.compare( multiResponse.i64_thing, arg2) == 0, 'multiResponse.I64_thing == arg2');
+
+
+		trace("Test Oneway(1)");
+		client.testOneway(1);
+
+		trace("Test Calltime()");
+		var difft = Timer.stamp();
+		for ( k in 0 ... 1000) {
+			client.testVoid();
+		}
+		difft = Timer.stamp() - difft;
+		trace('$difft ms per testVoid() call');
+	}
+}