THRIFT-2753 Haxe support: Misc. improvements
Client: Haxe
Patch: Jens Geyer

This closes #229
diff --git a/test/haxe/Makefile.am b/test/haxe/Makefile.am
index 08c0369..127c45d 100644
--- a/test/haxe/Makefile.am
+++ b/test/haxe/Makefile.am
@@ -23,23 +23,23 @@
 
 BIN_CPP = bin/Main-debug
 
-gen-haxe/ThriftTest/ThriftTest.hx: $(THRIFTTEST)
+gen-haxe/thrift/test/ThriftTest.hx: $(THRIFTTEST)
 	$(THRIFTCMD) $(THRIFTTEST)
-	
+
 all-local: $(BIN_CPP)
-	
-$(BIN_CPP):	gen-haxe/ThriftTest/ThriftTest.hx
+
+$(BIN_CPP):    gen-haxe/thrift/test/ThriftTest.hx
 	$(HAXE) --cwd .  cpp.hxml
 
-	
+
 #TODO: other haxe targets
-#	$(HAXE)  --cwd .  csharp
-#	$(HAXE)  --cwd .  flash
-#	$(HAXE)  --cwd .  java
-#	$(HAXE)  --cwd .  javascript
-#	$(HAXE)  --cwd .  neko
-#	$(HAXE)  --cwd .  php
-#	$(HAXE)  --cwd .  python  # needs Haxe 3.1.4
+#    $(HAXE)  --cwd .  csharp
+#    $(HAXE)  --cwd .  flash
+#    $(HAXE)  --cwd .  java
+#    $(HAXE)  --cwd .  javascript
+#    $(HAXE)  --cwd .  neko
+#    $(HAXE)  --cwd .  php
+#    $(HAXE)  --cwd .  python  # needs Haxe 3.1.4
 
 
 clean-local:
diff --git a/test/haxe/project.hide b/test/haxe/project.hide
index f09030b..a1c09ba 100644
--- a/test/haxe/project.hide
+++ b/test/haxe/project.hide
@@ -29,7 +29,7 @@
         ,{
              "pathToHxml" : "cpp.hxml"
             ,"runActionType" : 2
-            ,"runActionText" : "bin/Main-debug.exe  client --json"
+            ,"runActionText" : "bin/Main-debug.exe  client --protocol json"
         }
         ,{
              "pathToHxml" : "java.hxml"
@@ -45,34 +45,25 @@
     ]
     ,"files" : [
          {
-             "path" : "src\\Arguments.hx"
-            ,"useTabs" : true
-            ,"indentSize" : 4
-            ,"foldedRegions" : [
-
-            ]
-            ,"activeLine" : 159
-        }
-        ,{
-             "path" : "..\\..\\lib\\haxe\\src\\org\\apache\\thrift\\protocol\\TJSONProtocol.hx"
-            ,"useTabs" : true
-            ,"indentSize" : 4
-            ,"foldedRegions" : [
-
-            ]
-            ,"activeLine" : 665
-        }
-        ,{
              "path" : "src\\TestClient.hx"
             ,"useTabs" : true
             ,"indentSize" : 4
             ,"foldedRegions" : [
 
             ]
-            ,"activeLine" : 325
+            ,"activeLine" : 188
+        }
+        ,{
+             "path" : "src\\TestServer.hx"
+            ,"useTabs" : true
+            ,"indentSize" : 4
+            ,"foldedRegions" : [
+
+            ]
+            ,"activeLine" : 88
         }
     ]
-    ,"activeFile" : "..\\..\\lib\\haxe\\src\\org\\apache\\thrift\\protocol\\TJSONProtocol.hx"
+    ,"activeFile" : "src\\TestClient.hx"
     ,"openFLTarget" : null
     ,"openFLBuildMode" : "Debug"
     ,"runActionType" : null
diff --git a/test/haxe/src/Arguments.hx b/test/haxe/src/Arguments.hx
index bcf3793..ae23fa1 100644
--- a/test/haxe/src/Arguments.hx
+++ b/test/haxe/src/Arguments.hx
@@ -24,34 +24,49 @@
 import org.apache.thrift.transport.*;
 import org.apache.thrift.server.*;
 import org.apache.thrift.meta_data.*;
+import haxe.io.Path;
 
 using StringTools;
 
 
-enum Prot {
+enum ProtocolType {
 	binary;
 	json;
 }
 
-enum Trns {
+enum EndpointTransport {
 	socket;
-	http;
+	http;	
+}
+
+enum ServerType {
+	simple;
+	/*
+	threadpool;	
+	threaded;
+	nonblocking;
+	*/
 }
 
 
 class Arguments
 {
+	public var printHelpOnly(default,null) : Bool = false;
+
 	public var server(default,null) : Bool = false;
-	public var framed(default,null) : Bool = false;
-	public var buffered(default,null) : Bool = false;
-	public var protocol(default,null) : Prot = binary;
-	public var transport(default,null) : Trns = socket;
-	
+	public var servertype(default,null) : ServerType = simple;
+
 	public var host(default,null) : String = "localhost";
 	public var port(default,null) : Int = 9090;
+	
+	public var protocol(default,null) : ProtocolType = binary;
+	public var transport(default,null) : EndpointTransport = socket;
+	public var framed(default,null) : Bool = false;
+	public var buffered(default,null) : Bool = false;
 
 	public var numIterations(default,null) : Int = 1;
 	public var numThreads(default,null) : Int = 1;
+	public var skipSpeedTest(default,null) : Bool = false;
 	
 	
 	public function new() {
@@ -70,112 +85,244 @@
 	#if sys
 		
 	private static function GetHelp() : String {
+		var sProg = Path.withoutDirectory( Sys.executablePath());
 		return "\n"
-			+Sys.executablePath()+"  [client|server]  [options]\n"
+			+sProg+"  [client|server]  [options]\n"
+			+"\n"
 			+"Modus: Either client or server, the default is client.\n"
 			+"\n"
-			+"Options:\n"
-			+"  -f, --framed         framed transport (supersedes buffered)\n"
-			+"  -b, --buffered       buffered transport\n"
-			+"  --json               JSON protocol\n"
-			+"  --protocol=<prot>    Choose protocol: json, binary (default binary).\n"
-			+"  --port=<port>        Port number for socket transport, default 9090\n"
+			+"Common options:\n"
+			+"  -h [ --help ]               produce help message\n"
+			+"  --port arg (=9090)          Port number to listen / connect to\n"
+			/* not supported yet
+			+"  --domain-socket arg         Unix Domain Socket (e.g. /tmp/ThriftTest.thrift)\n"
+            +"  --named-pipe arg            Windows Named Pipe (e.g. MyThriftPipe)\n"
+			*/
+			+"  --protocol arg (=binary)    protocol: binary, compact, json\n"
+			/* not supported yet
+			+"  --ssl                       Encrypted Transport using SSL\n"
+			*/
+			+"\n"
+			+"Server only options:\n"
+            +"  --transport arg (=sockets)  Transport: buffered, framed, http, anonpipe\n"
+			/* not supported yet
+			+"  --processor-events          processor-events\n"
+			+"  --server-type arg (=simple) type of server, \"simple\", \"thread-pool\", \n"
+			+"                              \"threaded\", or \"nonblocking\"\n"
+			+"  -n [ --workers ] arg (=4)   Number of thread pools workers. Only valid for \n"
+			+"                              thread-pool server type\n"
+			*/
 			+"\n"
 			+"Client only options:\n"
-			+"  --host=<host>        Host name, IP or URL, default localhost\n"
-			+"  -n=<iterations>      Number of test iterations\n"
-			+"  -t=<threads>         Number of test threads\n"
-			+"  -u=<url>             Target Host/URL (same as --host)\n"
+            +"  --host arg (=localhost)     Host to connect\n"
+            +"  --transport arg (=sockets)  Transport: buffered, framed, http, evhttp\n"
+			/* not supported yet
+            +"  --anon-pipes hRead hWrite   Windows Anonymous Pipes pair (handles)\n"
+			*/
+            +"  -n [ --testloops ] arg (=1) Number of Tests\n"
+            +"  -t [ --threads ] arg (=1)   Number of Test threads\n"
+            +"  --skip-speed-test           Skip the speed test\n"
 			+"\n"
-			+"All arguments are optional.\n";
+			+"All arguments are optional.\n"
+			;
 	}
 	
 
 	private function ParseArgs() : Void {
-		var step = 0;
-		for (arg in Sys.args()) {
+		
+		var args = Sys.args().copy();
+		if( (args == null) || (args.length <= 0)) {
+			server = false;
+			numThreads = 1;
+			return;
+		}
+		
+		var arg = args.shift();
+		if ( arg == "client") {
+			server = false;
+			numThreads = 1;
+		} 
+		else if ( arg == "server") {
+			server = true;
+			numThreads = 4;
+		} 
+		else if ( (arg == "-h") || (arg == "--help")) {
+			// -h [ --help ]               produce help message
+			Sys.println( GetHelp());
+			printHelpOnly = true;
+			return;
+		} 
+		else {
+			throw "First argument must be 'server' or 'client'";
+		}
+
 			
-			// server|client
-			switch(step) {
-			case 0:
-				++step;
-				if ( arg == "client") 
-					server = false;
-				else if ( arg == "server") 
-					server = true;
-				else
-					throw "First argument must be 'server' or 'client'";
-					
-			case 1:					
-				if ( (arg == "-f") || (arg == "--framed")) {
-					framed = true;
-				} else if (( arg == "-b") || ( arg == "--buffered")) {
-					buffered = true;
-				} else if (( arg == "--json") || (arg == "--protocol=json")){
-					protocol = json;
-				} else if (( arg == "--protocol=binary")){
-					protocol = binary;
-				} else if (arg.startsWith("--host=")) {
-					ClientOnlyOption(arg);
-					host = arg.substr(arg.indexOf("=") + 1);
-				} else if (arg.startsWith("--port=")) {
-					var tmp = Std.parseInt(arg.substr(arg.indexOf("=")+1));
-					if( tmp != null)
-						port = tmp;
-					else
-						throw "Invalid port number "+arg;
-				} else if (arg == "-n") {
-					ClientOnlyOption(arg);
-					step = 2;
-				} else if (arg == "-t") {
-					ClientOnlyOption(arg);
-					step = 3;
-				} else if (arg == "-u") {
-					ClientOnlyOption(arg);
-					step = 4;
+		while( args.length > 0) {
+			arg = args.shift();
+			
+			if ( (arg == "-h") || (arg == "--help")) {
+				// -h [ --help ]               produce help message
+			    Sys.println( GetHelp());
+				printHelpOnly = true;
+				return;
+			} 
+			else if (arg == "--port") {		
+				// --port arg (=9090)          Port number to listen
+				arg = args.shift();
+				var tmp = Std.parseInt(arg);
+				if( tmp != null) {
+					port = tmp;
 				} else {
-					throw "Unexpected argument "+arg;
-				}					
-					
-			case 2:  // num iterations
-				step = 1;
-				var tmp = Std.parseInt(arg);
-				if( tmp != null)
-					numIterations = tmp;
-				else
-					throw "Invalid numeric value "+arg;
-					
-			case 3: // num threads
-				step = 1;
-				var tmp = Std.parseInt(arg);
-				if( tmp != null)
-					numThreads = tmp;
-				else
-					throw "Invalid numeric value "+arg;
-					
-			case 4:  // url
-				step = 1;
-				host = arg;
-					
-			default:
-				throw "Unexpected state";
+					throw "Invalid port number "+arg;
+				}  
+			} 
+			else if (arg == "--domain-socket") {		
+				//   --domain-socket arg         Unix Domain Socket (e.g. /tmp/ThriftTest.thrift)
+				throw "domain sockets not supported yet";
+			} 
+			else if (arg == "--named-pipe") {		
+				//   --named-pipe arg            Windows Named Pipe (e.g. MyThriftPipe)
+				throw "named pipes not supported yet";
+			} 
+			else if (arg == "--protocol") {		
+				// --protocol arg (=binary)    protocol: binary, compact, json
+				arg = args.shift();
+				if( arg == "binary") {
+					protocol = binary;
+				} else if( arg == "compact") {
+					throw "Compact protocol not supported yet";
+				} else if( arg == "json") {
+					protocol = json;
+				} else {
+					InvalidArg(arg);
+				}
+			}  
+			else if (arg == "--ssl") {		
+				// --ssl                       Encrypted Transport using SSL
+				throw "SSL not supported yet";
+			} 
+			else {
+                //Server only options:
+				if( server) {
+					ParseServerArgument( arg, args);
+				} else {
+					ParseClientArgument( arg, args);
+				}
 			}
+		}
+	}
+	
 
-			
-			if ( framed && buffered)
-			{
-				trace("WN: framed supersedes buffered transport");
-			}
+	private function ParseServerArgument( arg : String, args : Array<String>) : Void {
+		if (arg == "--transport") {
+			//  --transport arg (=sockets)  Transport: buffered, framed, http, anonpipe
+			arg = args.shift();
+			if( arg == "buffered") {
+				buffered = true;
+			} else if( arg == "framed") {
+				framed = true;
+			} else if( arg == "http") {
+				transport = http;
+			} else if( arg == "anonpipe") {
+				throw "Anon pipes transport not supported yet";
+			} else {
+				InvalidArg(arg);
+			}  
+		}
+		else if (arg == "--processor-events") {
+			throw "Processor events not supported yet";
+		}
+		else if (arg == "--server-type") {
+			//  --server-type arg (=simple) type of server, 
+			// one of "simple", "thread-pool", "threaded", "nonblocking"
+			arg = args.shift();
+			if( arg == "simple") {
+				servertype = simple;
+			} else if( arg == "thread-pool") {
+				throw arg+" server not supported yet";
+			} else if( arg == "threaded") {
+				throw arg+" server not supported yet";
+			} else if( arg == "nonblocking") {
+				throw arg+" server not supported yet";
+			} else {
+				InvalidArg(arg);
+			}  
+		}
+		else if ((arg == "-n") || (arg == "--workers")) {
+			//  -n [ --workers ] arg (=4)   Number of thread pools workers. Only valid for 
+			//                              thread-pool server type
+			arg = args.shift();
+			var tmp = Std.parseInt(arg);
+			if( tmp != null) {
+				numThreads = tmp;
+			} else{
+				throw "Invalid number "+arg;
+			} 
+		}
+		else {
+			InvalidArg(arg);
+		}
+	}
+	
 
+	private function ParseClientArgument( arg : String, args : Array<String>) : Void {
+		if (arg == "--host") {
+            //  --host arg (=localhost)     Host to connect
+			host = args.shift();
+		}
+		else if (arg == "--transport") {
+            //  --transport arg (=sockets)  Transport: buffered, framed, http, evhttp
+			arg = args.shift();
+			if( arg == "buffered") {
+				buffered = true;
+			} else if( arg == "framed") {
+				framed = true;
+			} else if( arg == "http") {
+				transport = http;
+			} else if( arg == "evhttp") {
+				throw "evhttp transport not supported yet";
+			} else {
+				InvalidArg(arg);
+			}  
+		}
+		else if (arg == "--anon-pipes") {
+			//  --anon-pipes hRead hWrite   Windows Anonymous Pipes pair (handles)
+			throw "Anon pipes transport not supported yet";
+		}
+		else if ((arg == "-n") || (arg == "--testloops")) {
+			//  -n [ --testloops ] arg (=1) Number of Tests
+			arg = args.shift();
+			var tmp = Std.parseInt(arg);
+			if( tmp != null) {
+				numIterations = tmp;
+			} else {
+				throw "Invalid number "+arg;
+			}  
+		}
+		else if ((arg == "-t") || (arg == "--threads")) {
+			//  -t [ --threads ] arg (=1)   Number of Test threads
+			arg = args.shift();
+			var tmp = Std.parseInt(arg);
+			if( tmp != null) {
+				numThreads = tmp;
+			} else {
+				throw "Invalid number "+arg;
+			}  
+		}
+		else if (arg == "--skip-speed-test") {
+			//  --skip-speed-test  			Skip the speed test
+			skipSpeedTest = true;
+		}			
+		else {
+			InvalidArg(arg);
 		}
 	}
 
+	
 	#end
 		
 		
-	private function ClientOnlyOption( arg : String) {
-		if( server) {
-			throw "Unexpected argument in client mode: "+arg;
-		}
+	private function InvalidArg( arg : String) : Void {
+		throw 'Invalid argument $arg';
 	}
 }
diff --git a/test/haxe/src/Main.hx b/test/haxe/src/Main.hx
index a8ad147..6d80c21 100644
--- a/test/haxe/src/Main.hx
+++ b/test/haxe/src/Main.hx
@@ -34,6 +34,9 @@
 		try {
 			var args = new Arguments();
 			
+			if( args.printHelpOnly) 
+				return;
+			
 			if (args.server)
 				TestServer.Execute(args);
 			else 
diff --git a/test/haxe/src/TestClient.hx b/test/haxe/src/TestClient.hx
index 8698220..3c98e6a 100644
--- a/test/haxe/src/TestClient.hx
+++ b/test/haxe/src/TestClient.hx
@@ -47,16 +47,36 @@
 	private var errorCnt : Int = 0;
 	private var failedTests : String = "";
 	private var print_direct : Bool = false;
+	
+	public static var EXITCODE_SUCCESS            = 0x00;  // no errors bits set
+	//
+	public static var EXITCODE_FAILBIT_BASETYPES  = 0x01;
+	public static var EXITCODE_FAILBIT_STRUCTS    = 0x02;
+	public static var EXITCODE_FAILBIT_CONTAINERS = 0x04;
+	public static var EXITCODE_FAILBIT_EXCEPTIONS = 0x08;
+	//
+	public static var EXITCODE_ALL_FAILBITS 	  = 0x0F;
+	//
+	private var testsExecuted : Int = 0;
+	private var testsFailed : Int = 0;
+	private var currentTest : Int = 0;
 
+	
 	public function new(direct : Bool) {
 		print_direct = direct;
 	}
 	
+	public function StartTestGroup( groupBit : Int) : Void {
+		currentTest = groupBit;
+		testsExecuted |= groupBit;
+	}
+	
 	public function Expect( expr : Bool, msg : String) : Void {
 		if ( expr) {
 			++successCnt;
 		} else {
 			++errorCnt;
+			testsFailed |= currentTest;
 			failedTests += "\n  " + msg;
 			if( print_direct) {
 				trace('FAIL: $msg');
@@ -64,6 +84,10 @@
 		}
 	}
 
+	public function CalculateExitCode() : Int {
+		var notExecuted : Int = EXITCODE_ALL_FAILBITS & (~testsExecuted);
+		return testsFailed | notExecuted;
+	}
 
 	public function PrintSummary() : Void {
 		var total = successCnt + errorCnt;
@@ -88,57 +112,67 @@
 
 	public static function Execute(args : Arguments) :  Void
 	{
+		var exitCode = 0xFF;
 		try
 		{
 			var difft = Timer.stamp();
-			
+	
 			if( args.numThreads > 1) {
 				var threads = new List<Thread>();
 				for( test in 0 ... args.numThreads) {
 					threads.add( StartThread( args));
 				} 
+				exitCode = 0;
 				for( thread in threads) {
-					Thread.readMessage(true);
+					exitCode |= Thread.readMessage(true);
 				}
 			} else {
 				var rslt = new TestResults(true);
 				RunClient(args,rslt);
 				rslt.PrintSummary();
+				exitCode = rslt.CalculateExitCode();
 			}
 
-    		difft = Timer.stamp() - difft;
+			difft = Timer.stamp() - difft;
 			trace('total test time: $difft seconds');
 		}
 		catch (e : TException)
 		{
 			trace('$e');
+			exitCode = 0xFF;
 		}
 		catch (e : Dynamic)
 		{
 			trace('$e');
+			exitCode = 0xFF;
 		}
+	
+		#if sys
+		Sys.exit( exitCode);
+		#end
 	}
 
 	
 	private static function StartThread(args : Arguments) : Thread {
 		var thread = Thread.create(
 			function() : Void {
+				var rslt = new TestResults(false);
 				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)
 				{
+					rslt.Expect( false, '$e');
 					trace('$e');
 				}
 				catch (e : Dynamic)
 				{
+					rslt.Expect( false, '$e');
 					trace('$e');
 				}					
-				main.sendMessage("done");
+				main.sendMessage( rslt.CalculateExitCode());
 			});
 		
 		thread.sendMessage(Thread.current());
@@ -154,8 +188,7 @@
 			case socket:
 				transport = new TSocket(args.host, args.port);
 			case http:
-				throw "http transport not supported yet";
-				//transport = new THttpClient(args.host);
+				transport = new THttpClient(args.host);
 			default:
 				throw "Unhandled transport";
 		}
@@ -164,7 +197,8 @@
 		if ( args.framed) {
 			trace("- framed transport");
 			transport = new TFramedTransport(transport);
-		} else if ( args.buffered) {
+		} 
+		if ( args.buffered) {
 			trace("- buffered transport");
 			throw "TBufferedTransport not implemented yet";
 			//transport = new TBufferedTransport(transport);
@@ -186,16 +220,18 @@
 
 
 		// run the test code
-		HaxeBasicsTest( rslt);
-		ClientTest( transport, protocol, rslt);
-					
+		HaxeBasicsTest( args, rslt);
+		for( i in 0 ... args.numIterations) {
+			ClientTest( transport, protocol, args, rslt);
+		}
 	}
 
 
-	public static function HaxeBasicsTest( rslt : TestResults) : Void
+	public static function HaxeBasicsTest( args : Arguments, 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
+		rslt.StartTestGroup( 0);
 		
 		var map32 = new IntMap<Int32>();
 		var map64 = new Int64Map<Int32>();
@@ -272,7 +308,8 @@
 	}
 
 
-	public static function ClientTest( transport : TTransport, protocol : TProtocol, rslt : TestResults) : Void
+	public static function ClientTest( transport : TTransport, protocol : TProtocol, 
+									   args : Arguments, rslt : TestResults) : Void
 	{
 		var client = new ThriftTestImpl(protocol,protocol);
 		try
@@ -295,6 +332,54 @@
 
 		var start = Date.now();
 
+		rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_EXCEPTIONS);
+	
+		// if arg == "Xception" throw Xception with errorCode = 1001 and message = arg
+		trace('testException("Xception")');
+		try {
+			client.testException("Xception");
+			rslt.Expect( false, 'testException("Xception") should throw');
+		}
+		catch (e : Xception)
+		{
+			rslt.Expect( e.message == "Xception", 'testException("Xception")  -  e.message == "Xception"');
+			rslt.Expect( e.errorCode == 1001, 'testException("Xception")  -  e.errorCode == 1001');
+		}
+		catch (e : Dynamic)
+		{
+			rslt.Expect( false, 'testException("Xception")  -  $e');
+		} 
+	
+		// if arg == "TException" throw TException
+		trace('testException("TException")');
+		try {
+			client.testException("TException");
+			rslt.Expect( false, 'testException("TException") should throw');
+		}
+		catch (e : TException)
+		{
+			rslt.Expect( true, 'testException("TException")  -  $e');
+		}
+		catch (e : Dynamic)
+		{
+			rslt.Expect( false, 'testException("TException")  -  $e');
+		} 
+	
+		// else do not throw anything
+		trace('testException("bla")');
+		try {
+			client.testException("bla");
+			rslt.Expect( true, 'testException("bla") should not throw');
+		}
+		catch (e : Dynamic)
+		{
+			rslt.Expect( false, 'testException("bla")  -  $e');
+		} 
+			
+		
+
+		rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_BASETYPES);
+		
 		trace('testVoid()');
 		client.testVoid();
 		trace(' = void');
@@ -333,6 +418,9 @@
 		trace(' = $dub');
 		rslt.Expect(dub == 5.325098235, '$dub == 5.325098235');
 
+		
+		rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_STRUCTS);
+		
 		trace('testStruct({"Zero", 1, -3, -5})');
 		var o = new Xtruct();
 		o.string_thing = "Zero";
@@ -341,7 +429,7 @@
 		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) + '}');
+					  + 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");
@@ -364,6 +452,9 @@
 		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");
 
+		
+		rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_CONTAINERS);
+		
 		var mapout = new IntMap< haxe.Int32>();
 		for ( j in 0 ... 5)
 		{
@@ -497,6 +588,8 @@
 		rslt.Expect(setin.size == setout.size, "setin.length == setout.length");
 	
 
+		rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_BASETYPES);
+
 		trace("testEnum(ONE)");
 		var ret = client.testEnum(Numberz.ONE);
 		trace(" = " + ret);
@@ -528,6 +621,9 @@
 		rslt.Expect( Int64.compare( uid, Int64.make( 0x119D0, 0x7E08671B)) == 0,
 		             Int64.toStr(uid)+" == "+Int64.toStr(Int64.make( 0x119D0, 0x7E08671B)));
 
+
+		rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_CONTAINERS);
+
 		trace("testMapMap(1)");
 		var mm = client.testMapMap(1);
 		trace(" = {");
@@ -551,6 +647,9 @@
 			rslt.Expect( neg.get(-i) == -i, 'neg.get(-$i) == -$i');
 	 	}
 
+			
+		rslt.StartTestGroup( TestResults.EXITCODE_FAILBIT_STRUCTS);
+
 		var insane = new Insanity();
 		insane.userMap = new IntMap< Int64>();
 		insane.userMap.set( Numberz.FIVE, Int64.make(0,5000));
@@ -614,6 +713,7 @@
 		}
 		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)");
@@ -682,15 +782,19 @@
 		rslt.Expect( Int64.compare( multiResponse.i64_thing, arg2) == 0, 'multiResponse.I64_thing == arg2');
 
 
+		rslt.StartTestGroup( 0);
+
 		trace("Test Oneway(1)");
 		client.testOneway(1);
 
-		trace("Test Calltime()");
-		var difft = Timer.stamp();
-		for ( k in 0 ... 1000) {
-			client.testVoid();
+		if( ! args.skipSpeedTest) {
+			trace("Test Calltime()");
+			var difft = Timer.stamp();
+			for ( k in 0 ... 1000) {
+				client.testVoid();
+			}
+			difft = Timer.stamp() - difft;
+			trace('$difft ms per testVoid() call');
 		}
-		difft = Timer.stamp() - difft;
-		trace('$difft ms per testVoid() call');
 	}
 }
diff --git a/test/haxe/src/TestServer.hx b/test/haxe/src/TestServer.hx
index 66b06e0..92fab01 100644
--- a/test/haxe/src/TestServer.hx
+++ b/test/haxe/src/TestServer.hx
@@ -53,7 +53,8 @@
 			if ( args.framed) {
 				trace("- framed transport");
 				transfactory = new TFramedTransportFactory();
-			} else if ( args.buffered) {
+			} 
+			if ( args.buffered) {
 				trace("- buffered transport");
 				throw "TBufferedTransport not implemented yet";
 				//transfactory = new TBufferedTransportFactory();
@@ -79,14 +80,23 @@
 			var processor = new ThriftTestProcessor(handler);
 
 			// Simple Server
-			var server = new TSimpleServer( processor, transport, transfactory, protfactory);
+			var server : TServer = null; 
+			switch( args.servertype)
+			{
+			case simple:
+				server = new TSimpleServer( processor, transport, transfactory, protfactory);
+			default:
+				throw "Unhandled server type";
+			}
 				
 
 			/*
 			// Server event handler
-			var events = new TestServerEventHandler();
-			server.setEventHandler(serverEvents);
-			handler.server = serverEngine;
+			if( args.serverEvents) {
+				var events = new TestServerEventHandler();
+				server.setEventHandler(serverEvents);
+				handler.server = serverEngine;
+			}
 			*/
 
 			// Run it