THRIFT-2641 Improvements to Haskell Compiler/Libraries

- test/test.sh integration
- add json and compact protocol

This closes #175

Signed-off-by: Roger Meier <roger@apache.org>
diff --git a/test/hs/DebugProtoTest_Main.hs b/test/hs/DebugProtoTest_Main.hs
index 29393db..fb28963 100755
--- a/test/hs/DebugProtoTest_Main.hs
+++ b/test/hs/DebugProtoTest_Main.hs
@@ -24,7 +24,9 @@
 
 import qualified Control.Exception
 import qualified Data.ByteString.Lazy as DBL
-import qualified Data.Maybe
+import qualified Data.HashMap.Strict as Map
+import qualified Data.HashSet as Set
+import qualified Data.Vector as Vector
 import qualified Network
 
 import Thrift.Protocol.Binary
@@ -61,61 +63,61 @@
     structMethod _ = do
         ThriftTestUtils.serverLog "Got structMethod call"
         return $ Types.CompactProtoTestStruct {
-            Types.f_CompactProtoTestStruct_a_byte = Just 0x01,
-            Types.f_CompactProtoTestStruct_a_i16 = Just 0x02,
-            Types.f_CompactProtoTestStruct_a_i32 = Just 0x03,
-            Types.f_CompactProtoTestStruct_a_i64 = Just 0x04,
-            Types.f_CompactProtoTestStruct_a_double = Just 0.1,
-            Types.f_CompactProtoTestStruct_a_string = Just "abcdef",
-            Types.f_CompactProtoTestStruct_a_binary = Just DBL.empty,
-            Types.f_CompactProtoTestStruct_true_field = Just True,
-            Types.f_CompactProtoTestStruct_false_field = Just False,
-            Types.f_CompactProtoTestStruct_empty_struct_field = Just Types.Empty,
+            Types.compactProtoTestStruct_a_byte = 0x01,
+            Types.compactProtoTestStruct_a_i16 = 0x02,
+            Types.compactProtoTestStruct_a_i32 = 0x03,
+            Types.compactProtoTestStruct_a_i64 = 0x04,
+            Types.compactProtoTestStruct_a_double = 0.1,
+            Types.compactProtoTestStruct_a_string = "abcdef",
+            Types.compactProtoTestStruct_a_binary = DBL.empty,
+            Types.compactProtoTestStruct_true_field = True,
+            Types.compactProtoTestStruct_false_field = False,
+            Types.compactProtoTestStruct_empty_struct_field = Types.Empty,
             
-            Types.f_CompactProtoTestStruct_byte_list = Nothing,
-            Types.f_CompactProtoTestStruct_i16_list = Nothing,
-            Types.f_CompactProtoTestStruct_i32_list = Nothing,
-            Types.f_CompactProtoTestStruct_i64_list = Nothing,
-            Types.f_CompactProtoTestStruct_double_list = Nothing,
-            Types.f_CompactProtoTestStruct_string_list = Nothing,
-            Types.f_CompactProtoTestStruct_binary_list = Nothing,
-            Types.f_CompactProtoTestStruct_boolean_list = Nothing,
-            Types.f_CompactProtoTestStruct_struct_list = Nothing,
+            Types.compactProtoTestStruct_byte_list = Vector.empty,
+            Types.compactProtoTestStruct_i16_list = Vector.empty,
+            Types.compactProtoTestStruct_i32_list = Vector.empty,
+            Types.compactProtoTestStruct_i64_list = Vector.empty,
+            Types.compactProtoTestStruct_double_list = Vector.empty,
+            Types.compactProtoTestStruct_string_list = Vector.empty,
+            Types.compactProtoTestStruct_binary_list = Vector.empty,
+            Types.compactProtoTestStruct_boolean_list = Vector.empty,
+            Types.compactProtoTestStruct_struct_list = Vector.empty,
 
-            Types.f_CompactProtoTestStruct_byte_set = Nothing,
-            Types.f_CompactProtoTestStruct_i16_set = Nothing,
-            Types.f_CompactProtoTestStruct_i32_set = Nothing,
-            Types.f_CompactProtoTestStruct_i64_set = Nothing,
-            Types.f_CompactProtoTestStruct_double_set = Nothing,
-            Types.f_CompactProtoTestStruct_string_set = Nothing,
-            Types.f_CompactProtoTestStruct_binary_set = Nothing,
-            Types.f_CompactProtoTestStruct_boolean_set = Nothing,
-            Types.f_CompactProtoTestStruct_struct_set = Nothing,
+            Types.compactProtoTestStruct_byte_set = Set.empty,
+            Types.compactProtoTestStruct_i16_set = Set.empty,
+            Types.compactProtoTestStruct_i32_set = Set.empty,
+            Types.compactProtoTestStruct_i64_set = Set.empty,
+            Types.compactProtoTestStruct_double_set = Set.empty,
+            Types.compactProtoTestStruct_string_set = Set.empty,
+            Types.compactProtoTestStruct_binary_set = Set.empty,
+            Types.compactProtoTestStruct_boolean_set = Set.empty,
+            Types.compactProtoTestStruct_struct_set = Set.empty,
 
-            Types.f_CompactProtoTestStruct_byte_byte_map = Nothing,
-            Types.f_CompactProtoTestStruct_i16_byte_map = Nothing,
-            Types.f_CompactProtoTestStruct_i32_byte_map = Nothing,
-            Types.f_CompactProtoTestStruct_i64_byte_map = Nothing,
-            Types.f_CompactProtoTestStruct_double_byte_map = Nothing,
-            Types.f_CompactProtoTestStruct_string_byte_map = Nothing,
-            Types.f_CompactProtoTestStruct_binary_byte_map = Nothing,
-            Types.f_CompactProtoTestStruct_boolean_byte_map = Nothing,
+            Types.compactProtoTestStruct_byte_byte_map = Map.empty,
+            Types.compactProtoTestStruct_i16_byte_map = Map.empty,
+            Types.compactProtoTestStruct_i32_byte_map = Map.empty,
+            Types.compactProtoTestStruct_i64_byte_map = Map.empty,
+            Types.compactProtoTestStruct_double_byte_map = Map.empty,
+            Types.compactProtoTestStruct_string_byte_map = Map.empty,
+            Types.compactProtoTestStruct_binary_byte_map = Map.empty,
+            Types.compactProtoTestStruct_boolean_byte_map = Map.empty,
 
-            Types.f_CompactProtoTestStruct_byte_i16_map = Nothing,
-            Types.f_CompactProtoTestStruct_byte_i32_map = Nothing,
-            Types.f_CompactProtoTestStruct_byte_i64_map = Nothing,
-            Types.f_CompactProtoTestStruct_byte_double_map = Nothing,
-            Types.f_CompactProtoTestStruct_byte_string_map = Nothing,
-            Types.f_CompactProtoTestStruct_byte_binary_map = Nothing,
-            Types.f_CompactProtoTestStruct_byte_boolean_map = Nothing,
+            Types.compactProtoTestStruct_byte_i16_map = Map.empty,
+            Types.compactProtoTestStruct_byte_i32_map = Map.empty,
+            Types.compactProtoTestStruct_byte_i64_map = Map.empty,
+            Types.compactProtoTestStruct_byte_double_map = Map.empty,
+            Types.compactProtoTestStruct_byte_string_map = Map.empty,
+            Types.compactProtoTestStruct_byte_binary_map = Map.empty,
+            Types.compactProtoTestStruct_byte_boolean_map = Map.empty,
 
-            Types.f_CompactProtoTestStruct_list_byte_map = Nothing,
-            Types.f_CompactProtoTestStruct_set_byte_map = Nothing,
-            Types.f_CompactProtoTestStruct_map_byte_map = Nothing,
+            Types.compactProtoTestStruct_list_byte_map = Map.empty,
+            Types.compactProtoTestStruct_set_byte_map = Map.empty,
+            Types.compactProtoTestStruct_map_byte_map = Map.empty,
 
-            Types.f_CompactProtoTestStruct_byte_map_map = Nothing,
-            Types.f_CompactProtoTestStruct_byte_set_map = Nothing,
-            Types.f_CompactProtoTestStruct_byte_list_map = Nothing }
+            Types.compactProtoTestStruct_byte_map_map = Map.empty,
+            Types.compactProtoTestStruct_byte_set_map = Map.empty,
+            Types.compactProtoTestStruct_byte_list_map = Map.empty }
 
     methodWithDefaultArgs _ arg = do
         ThriftTestUtils.serverLog $ "Got methodWithDefaultArgs: " ++ show arg
@@ -127,7 +129,7 @@
 instance IIface.Inherited_Iface InheritedHandler where
     identity _ arg = do
         ThriftTestUtils.serverLog $ "Got identity method: " ++ show arg
-        return $ Data.Maybe.fromJust arg
+        return arg
 
 client :: (String, Network.PortID) -> IO ()
 client addr = do
diff --git a/test/hs/Include_Main.hs b/test/hs/Include_Main.hs
index 697ffff..d3977a1 100644
--- a/test/hs/Include_Main.hs
+++ b/test/hs/Include_Main.hs
@@ -4,4 +4,4 @@
 import ThriftTest_Types
 
 main :: IO ()
-main = putStrLn ("Includes work: " ++ (show (IncludeTest (Just  (Bools (Just True) (Just False))))))
+main = putStrLn ("Includes work: " ++ (show (IncludeTest $ Bools True False)))
diff --git a/test/hs/Makefile.am b/test/hs/Makefile.am
index 2e016c4..2629ca1 100644
--- a/test/hs/Makefile.am
+++ b/test/hs/Makefile.am
@@ -35,3 +35,9 @@
 
 clean-local:
 	$(RM) -r gen-hs
+	$(RM) *.hi
+	$(RM) *.o
+
+all: check
+	ghc -igen-hs TestServer.hs
+	ghc -igen-hs TestClient.hs
\ No newline at end of file
diff --git a/test/hs/NameConflictTest_Main.hs b/test/hs/NameConflictTest_Main.hs
index 5d0b17a..7de0f4d 100644
--- a/test/hs/NameConflictTest_Main.hs
+++ b/test/hs/NameConflictTest_Main.hs
@@ -1,3 +1,4 @@
+{-# OPTIONS_GHC -fno-warn-unused-imports #-}
 module Main where
 
 import qualified Prelude as P
@@ -16,4 +17,4 @@
   P.putStrLn "Values:"
   P.print ([JUST, TRUE, FALSE] :: [Maybe])
   P.print ([LEFT, RIGHT] :: [Either])
-  P.print (Problem_ (P.Just P.True) (P.Just P.False))
+  P.print (Problem_ P.True P.False)
diff --git a/test/hs/TestClient.hs b/test/hs/TestClient.hs
new file mode 100644
index 0000000..35e8397
--- /dev/null
+++ b/test/hs/TestClient.hs
@@ -0,0 +1,231 @@
+--
+-- 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.
+--
+
+{-# LANGUAGE OverloadedStrings, RecordWildCards, ScopedTypeVariables #-}
+module Main where
+
+import Control.Exception
+import Control.Monad
+import Data.Functor
+import Data.String
+import Network
+import System.Environment
+import System.Exit
+import System.Posix.Unistd
+import qualified Data.HashMap.Strict as Map
+import qualified Data.HashSet as Set
+import qualified Data.Vector as Vector
+
+import ThriftTest_Iface
+import ThriftTest_Types
+import qualified ThriftTest_Client as Client
+
+import Thrift.Transport
+import Thrift.Transport.Handle
+import Thrift.Protocol
+import Thrift.Protocol.Binary
+import Thrift.Protocol.Compact
+import Thrift.Protocol.JSON
+
+data Options = Options
+  { host         :: String
+  , port         :: Int
+  , domainSocket :: String
+  , transport    :: String
+  , protocol     :: ProtocolType
+  , ssl          :: Bool
+  , testLoops    :: Int
+  }
+  deriving (Show, Eq)
+
+data ProtocolType = Binary
+                  | Compact
+                  | JSON
+                  deriving (Show, Eq)
+
+getProtocol :: String -> ProtocolType
+getProtocol "binary"  = Binary
+getProtocol "compact" = Compact
+getProtocol "json"    = JSON
+getProtocol p = error $ "Unsupported Protocol: " ++ p
+
+defaultOptions :: Options
+defaultOptions = Options
+  { port         = 9090
+  , domainSocket = ""
+  , host         = "localhost"
+  , transport    = "framed"
+  , protocol     = Binary
+  , ssl          = False
+  , testLoops    = 1
+  }
+
+runClient :: (Protocol p, Transport t) => p t -> IO ()
+runClient p = do
+  let prot = (p,p)
+  putStrLn "Starting Tests"
+              
+  -- VOID Test
+  Client.testVoid prot
+  
+  -- String Test
+  s <- Client.testString prot "Test"
+  when (s /= "Test") exitFailure
+
+  -- Byte Test
+  byte <- Client.testByte prot 1
+  when (byte /= 1) exitFailure
+  
+  -- I32 Test
+  i32 <- Client.testI32 prot (-1)
+  when (i32 /= -1) exitFailure
+  
+  -- I64 Test
+  i64 <- Client.testI64 prot (-34359738368)
+  when (i64 /= -34359738368) exitFailure
+
+  -- Double Test
+  dub <- Client.testDouble prot (-5.2098523)
+  when (abs (dub + 5.2098523) > 0.001) exitFailure
+
+  -- Struct Test
+  let structIn = Xtruct{ xtruct_string_thing = "Zero"
+                       , xtruct_byte_thing   = 1
+                       , xtruct_i32_thing    = -3
+                       , xtruct_i64_thing    = -5
+                       }
+  structOut <- Client.testStruct prot structIn 
+  when (structIn /= structOut) exitFailure
+
+  -- Nested Struct Test
+  let nestIn = Xtruct2{ xtruct2_byte_thing   = 1
+                      , xtruct2_struct_thing = structIn
+                      , xtruct2_i32_thing    = 5
+                      }
+  nestOut <- Client.testNest prot nestIn
+  when (nestIn /= nestOut) exitSuccess
+  
+  -- Map Test
+  let mapIn = Map.fromList $ map (\i -> (i, i-10)) [1..5]
+  mapOut <- Client.testMap prot mapIn
+  when (mapIn /= mapOut) exitSuccess
+  
+  -- Set Test
+  let setIn = Set.fromList [-2..3]
+  setOut <- Client.testSet prot setIn
+  when (setIn /= setOut) exitFailure
+  
+  -- List Test
+  let listIn = Vector.fromList [-2..3]
+  listOut <- Client.testList prot listIn
+  when (listIn /= listOut) exitFailure
+  
+  -- Enum Test
+  numz1 <- Client.testEnum prot ONE
+  when (numz1 /= ONE) exitFailure
+
+  numz2 <- Client.testEnum prot TWO
+  when (numz2 /= TWO) exitFailure
+
+  numz5 <- Client.testEnum prot FIVE
+  when (numz5 /= FIVE) exitFailure
+
+  -- Typedef Test
+  uid <- Client.testTypedef prot 309858235082523
+  when (uid /= 309858235082523) exitFailure
+  
+  -- Nested Map Test
+  _ <- Client.testMapMap prot 1
+  
+  -- Exception Test
+  exn1 <- try $ Client.testException prot "Xception"
+  case exn1 of
+    Left (Xception _ _) -> return ()
+    _ -> putStrLn (show exn1) >> exitFailure
+  
+  exn2 <- try $ Client.testException prot "TException"
+  case exn2 of
+    Left (_ :: SomeException) -> return ()
+    Right _ -> exitFailure
+  
+  exn3 <- try $ Client.testException prot "success"
+  case exn3 of
+    Left (_ :: SomeException) -> exitFailure
+    Right _ -> return ()
+  
+  -- Multi Exception Test
+  multi1 <- try $ Client.testMultiException prot "Xception" "test 1"
+  case multi1 of
+    Left (Xception _ _) -> return ()
+    _ -> exitFailure
+
+  multi2 <- try $ Client.testMultiException prot "Xception2" "test 2"
+  case multi2 of
+    Left (Xception2 _ _) -> return ()
+    _ -> exitFailure
+
+  multi3 <- try $ Client.testMultiException prot "success" "test 3"
+  case multi3 of
+    Left (_ :: SomeException) -> exitFailure
+    Right _ -> return ()
+
+
+main :: IO ()
+main = do
+  options <- flip parseFlags defaultOptions <$> getArgs
+  case options of
+    Nothing -> showHelp
+    Just Options{..} -> do
+      handle <- hOpen (host, PortNumber $ fromIntegral port)
+      let client = case protocol of
+            Binary  -> runClient $ BinaryProtocol handle
+            Compact -> runClient $ CompactProtocol handle
+            JSON    -> runClient $ JSONProtocol handle
+      replicateM_ testLoops client      
+      putStrLn "COMPLETED SUCCESSFULLY"
+
+parseFlags :: [String] -> Options -> Maybe Options
+parseFlags (flag : arg : flags) opts
+  | flag == "--port"          = parseFlags flags opts{ port = read arg }
+  | flag == "--domain-socket" = parseFlags flags opts{ domainSocket = arg }
+  | flag == "--host"          = parseFlags flags opts{ host = arg }
+  | flag == "--transport"     = parseFlags flags opts{ transport = arg }
+  | flag == "--protocol"      = parseFlags flags opts{ protocol = getProtocol arg }
+  | flag == "-n" ||
+    flag == "--testloops"     = parseFlags flags opts{ testLoops = read arg }
+parseFlags (flag : flags) opts
+  | flag == "-h"     = Nothing
+  | flag == "--help" = Nothing
+  | flag == "--ssl"  = parseFlags flags opts{ ssl = True }
+  | flag == "--processor-events" ||
+    otherwise = parseFlags flags opts
+parseFlags [] opts = Just opts
+
+showHelp :: IO ()
+showHelp = putStrLn
+  "Allowed options:\n\
+  \  -h [ --help ]               produce help message\n\
+  \  --host arg (=localhost)     Host to connect\n\
+  \  --port arg (=9090)          Port number to connect\n\
+  \  --domain-socket arg         Domain Socket (e.g. /tmp/ThriftTest.thrift),\n\ 
+  \                              instead of host and port\n\
+  \  --transport arg (=buffered) Transport: buffered, framed, http, evhttp\n\
+  \  --protocol arg (=binary)    Protocol: binary, compact, json\n\
+  \  --ssl                       Encrypted Transport using SSL\n\
+  \  -n [ --testloops ] arg (=1) Number of Tests"
\ No newline at end of file
diff --git a/test/hs/TestServer.hs b/test/hs/TestServer.hs
new file mode 100644
index 0000000..340b58b
--- /dev/null
+++ b/test/hs/TestServer.hs
@@ -0,0 +1,269 @@
+--
+-- 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.
+--
+
+{-# LANGUAGE OverloadedStrings,RecordWildCards #-}
+module Main where
+
+import Control.Exception
+import Control.Monad
+import Data.Functor
+import Data.HashMap.Strict (HashMap)
+import Data.List
+import Data.String
+import Network
+import System.Environment
+import System.Exit
+import System.IO
+import System.Posix.Unistd
+import qualified Data.HashMap.Strict as Map
+import qualified Data.HashSet as Set
+import qualified Data.Text.Lazy as Text
+import qualified Data.Vector as Vector
+
+import ThriftTest
+import ThriftTest_Iface
+import ThriftTest_Types
+
+import Thrift
+import Thrift.Server
+import Thrift.Transport.Framed
+import Thrift.Transport.Handle
+import Thrift.Protocol.Binary
+import Thrift.Protocol.Compact
+import Thrift.Protocol.JSON
+
+data Options = Options
+  { port         :: Int
+  , domainSocket :: String
+  , serverType   :: ServerType
+  , transport    :: String
+  , protocol     :: ProtocolType
+  , ssl          :: Bool
+  , workers      :: Int
+  }
+  
+data ServerType = Simple
+                | ThreadPool
+                | Threaded
+                | NonBlocking
+                deriving (Show, Eq)
+
+instance IsString ServerType where
+  fromString "simple"      = Simple
+  fromString "thread-pool" = ThreadPool
+  fromString "threaded"    = Threaded
+  fromString "nonblocking" = NonBlocking
+  fromString _ = error "not a valid server type"
+
+data ProtocolType = Binary
+                  | Compact
+                  | JSON
+
+getProtocol :: String -> ProtocolType
+getProtocol "binary"  = Binary
+getProtocol "compact" = Compact
+getProtocol "json"    = JSON
+getProtocol p = error $"Unsupported Protocol: " ++ p
+
+defaultOptions :: Options
+defaultOptions = Options
+  { port         = 9090
+  , domainSocket = ""
+  , serverType   = Threaded
+  , transport    = "framed"
+  , protocol     = Binary
+  , ssl          = False
+  , workers      = 4
+  }
+
+stringifyMap :: (Show a, Show b) => Map.HashMap a b -> String
+stringifyMap = intercalate ", " . map joinKV . Map.toList
+  where joinKV (k, v) = show k ++ " => " ++ show v
+
+stringifySet :: Show a => Set.HashSet a -> String
+stringifySet = intercalate ", " . map show . Set.toList
+
+stringifyList :: Show a => Vector.Vector a -> String
+stringifyList = intercalate ", " . map show . Vector.toList
+
+data TestHandler = TestHandler
+instance ThriftTest_Iface TestHandler where  
+  testVoid _ = putStrLn "testVoid()"
+
+  testString _ s = do
+    putStrLn $ "testString(" ++ show s ++ ")"
+    return s
+
+  testByte _ x = do
+    putStrLn $ "testByte(" ++ show x ++ ")"
+    return x
+
+  testI32 _ x = do
+    putStrLn $ "testI32(" ++ show x ++ ")"
+    return x
+
+  testI64 _ x = do
+    putStrLn $ "testI64(" ++ show x ++ ")"
+    return x
+    
+  testDouble _ x = do
+    putStrLn $ "testDouble(" ++ show x ++ ")"
+    return x
+
+  testStruct _ struct@Xtruct{..} = do
+    putStrLn $ "testStruct({" ++ show xtruct_string_thing
+                      ++ ", " ++ show xtruct_byte_thing 
+                      ++ ", " ++ show xtruct_i32_thing
+                      ++ ", " ++ show xtruct_i64_thing
+                      ++ "})"
+    return struct
+
+  testNest _ nest@Xtruct2{..} = do
+    let Xtruct{..} = xtruct2_struct_thing
+    putStrLn $ "testNest({" ++ show xtruct2_byte_thing
+                   ++ "{, " ++ show xtruct_string_thing
+                   ++  ", " ++ show xtruct_byte_thing
+                   ++  ", " ++ show xtruct_i32_thing
+                   ++  ", " ++ show xtruct_i64_thing
+                   ++ "}, " ++ show xtruct2_i32_thing
+    return nest
+
+  testMap _ m = do
+    putStrLn $ "testMap({" ++ stringifyMap m ++ "})"
+    return m
+            
+  testStringMap _ m = do
+    putStrLn $ "testStringMap(" ++ stringifyMap m ++ "})"
+    return m
+
+  testSet _ x = do
+    putStrLn $ "testSet({" ++ stringifySet x ++ "})"
+    return x
+
+  testList _ x = do
+    putStrLn $ "testList(" ++ stringifyList x ++ "})"
+    return x
+
+  testEnum _ x = do
+    putStrLn $ "testEnum(" ++ show x ++ ")"
+    return x
+
+  testTypedef _ x = do
+    putStrLn $ "testTypedef(" ++ show x ++ ")"
+    return x
+
+  testMapMap _ x = do
+    putStrLn $ "testMapMap(" ++ show x ++ ")"
+    return $ Map.fromList [ (-4, Map.fromList [ (-4, -4)
+                                              , (-3, -3)
+                                              , (-2, -2)
+                                              , (-1, -1)
+                                              ])
+                          , (4,  Map.fromList [ (1, 1)
+                                              , (2, 2)
+                                              , (3, 3)
+                                              , (4, 4)
+                                              ])
+                          ]
+
+  testInsanity _ x = do
+    putStrLn "testInsanity()"
+    return $ Map.fromList [ (1, Map.fromList [ (TWO  , x)
+                                             , (THREE, x)
+                                             ])
+                          , (2, Map.fromList [ (SIX, default_Insanity)
+                                             ])
+                          ]
+
+  testMulti _ byte i32 i64 _ _ _ = do
+    putStrLn "testMulti()"
+    return Xtruct{ xtruct_string_thing = Text.pack "Hello2"
+                 , xtruct_byte_thing   = byte
+                 , xtruct_i32_thing    = i32
+                 , xtruct_i64_thing    = i64
+                 }
+                                        
+  testException _ s = do
+    putStrLn $ "testException(" ++ show s ++ ")"
+    case s of
+      "Xception"   -> throw $ Xception 1001 s
+      "TException" -> throw ThriftException
+      _ -> return ()
+
+  testMultiException _ s1 s2 = do
+    putStrLn $ "testMultiException(" ++ show s1 ++ ", " ++ show s2 ++  ")"
+    case s1 of
+      "Xception"   -> throw $ Xception 1001 "This is an Xception" 
+      "Xception2"  -> throw $ Xception2 2002 default_Xtruct 
+      "TException" -> throw ThriftException
+      _ -> return default_Xtruct{ xtruct_string_thing = s2 }
+
+  testOneway _ i = do
+    putStrLn $ "testOneway(" ++ show i ++ "): Sleeping..."
+    sleep (fromIntegral i)
+    putStrLn $ "testOneway(" ++ show i ++ "): done sleeping!"
+
+main :: IO ()
+main = do
+  options <- flip parseFlags defaultOptions <$> getArgs
+  case options of
+    Nothing -> showHelp
+    Just Options{..} -> do
+      putStrLn $ "Starting \"" ++ show serverType ++ "\" server (" ++
+        show transport ++ ") listen on: " ++ domainSocket ++ show port
+      case protocol of
+        Binary  -> runServer BinaryProtocol port
+        Compact -> runServer CompactProtocol port
+        JSON    -> runServer JSONProtocol port
+      where
+        runServer p = runThreadedServer (accepter p) TestHandler ThriftTest.process . PortNumber . fromIntegral
+        accepter p s = do
+          (h, _, _) <- accept s
+          return (p h, p h)
+
+parseFlags :: [String] -> Options -> Maybe Options
+parseFlags (flag : arg : flags) opts
+  | flag == "--port"          = parseFlags flags opts{ port = read arg }
+  | flag == "--domain-socket" = parseFlags flags opts{ domainSocket = arg }
+  | flag == "--server-type"   = parseFlags flags opts{ serverType = fromString arg }
+  | flag == "--transport"     = parseFlags flags opts{ transport = arg }
+  | flag == "--protocol"      = parseFlags flags opts{ protocol = getProtocol arg }
+  | flag == "-n" ||
+    flag == "--workers"       = parseFlags flags opts{ workers = read arg }
+parseFlags (flag : flags) opts
+  | flag == "-h"     = Nothing
+  | flag == "--help" = Nothing
+  | flag == "--ssl"  = parseFlags flags opts{ ssl = True }
+  | flag == "--processor-events" = parseFlags flags opts
+parseFlags [] opts = Just opts
+
+showHelp :: IO ()
+showHelp = putStrLn
+  "Allowed options:\n\
+  \  -h [ --help ]               produce help message\n\
+  \  --port arg (=9090)          Port number to listen\n\
+  \  --domain-socket arg         Unix Domain Socket (e.g. /tmp/ThriftTest.thrift)\n\
+  \  --server-type arg (=simple) type of server, \"simple\", \"thread-pool\",\n\
+  \                              \"threaded\", or \"nonblocking\"\n\
+  \  --transport arg (=buffered) transport: buffered, framed, http\n\
+  \  --protocol arg (=binary)    protocol: binary, compact, json\n\
+  \  --ssl                       Encrypted Transport using SSL\n\
+  \  --processor-events          processor-events\n\
+  \  -n [ --workers ] arg (=4)   Number of thread pools workers. Only valid for\n\ 
+  \                              thread-pool server type"
\ No newline at end of file
diff --git a/test/hs/ThriftTestUtils.hs b/test/hs/ThriftTestUtils.hs
index 93fa122..9c19b56 100644
--- a/test/hs/ThriftTestUtils.hs
+++ b/test/hs/ThriftTestUtils.hs
@@ -60,6 +60,6 @@
     Control.Concurrent.threadDelay $ 500 * 1000 -- unit is in _micro_seconds
     Control.Concurrent.yield
 
-    _ <- client serverAddress
+    client serverAddress
 
     testLog "SUCCESS"
diff --git a/test/hs/ThriftTest_Main.hs b/test/hs/ThriftTest_Main.hs
index 3612935..1139506 100755
--- a/test/hs/ThriftTest_Main.hs
+++ b/test/hs/ThriftTest_Main.hs
@@ -47,124 +47,76 @@
 instance Iface.ThriftTest_Iface TestHandler where
     testVoid _ = return ()
 
-    testString _ (Just s) = do
+    testString _ s = do
         ThriftTestUtils.serverLog $ show s
         return s
 
-    testString _ Nothing = do
-        error $ "Unsupported testString form"
-
-    testByte _ (Just x) = do
+    testByte _ x = do
         ThriftTestUtils.serverLog $ show x
         return x
 
-    testByte _ Nothing = do
-        error $ "Unsupported testByte form"
-
-    testI32 _ (Just x) = do
+    testI32 _ x = do
         ThriftTestUtils.serverLog $ show x
         return x
 
-    testI32 _ Nothing = do
-        error $ "Unsupported testI32 form"
-
-    testI64 _ (Just x) = do
+    testI64 _ x = do
         ThriftTestUtils.serverLog $ show x
         return x
 
-    testI64 _ Nothing = do
-        error $ "Unsupported testI64 form"
-
-    testDouble _ (Just x) = do
+    testDouble _ x = do
         ThriftTestUtils.serverLog $ show x
         return x
 
-    testDouble _ Nothing = do
-        error $ "Unsupported testDouble form"
-
-    testStruct _ (Just x) = do
+    testStruct _ x = do
         ThriftTestUtils.serverLog $ show x
         return x
 
-    testStruct _ Nothing = do
-        error $ "Unsupported testStruct form"
-
-    testNest _ (Just x) = do
+    testNest _ x = do
         ThriftTestUtils.serverLog $ show x
         return x
 
-    testNest _ Nothing = do
-        error $ "Unsupported testNest form"
-
-    testMap _ (Just x) = do
+    testMap _ x = do
         ThriftTestUtils.serverLog $ show x
         return x
 
-    testMap _ Nothing = do
-        error $ "Unsupported testMap form"
-
-    testStringMap _ (Just x) = do
+    testStringMap _ x = do
         ThriftTestUtils.serverLog $ show x
         return x
 
-    testStringMap _ Nothing = do
-        error $ "Unsupported testMap form"
-
-    testSet _ (Just x) = do
+    testSet _ x = do
         ThriftTestUtils.serverLog $ show x
         return x
 
-    testSet _ Nothing = do
-        error $ "Unsupported testSet form"
-
-    testList _ (Just x) = do
+    testList _ x = do
         ThriftTestUtils.serverLog $ show x
         return x
 
-    testList _ Nothing = do
-        error $ "Unsupported testList form"
-
-    testEnum _ (Just x) = do
+    testEnum _ x = do
         ThriftTestUtils.serverLog $ show x
         return x
 
-    testEnum _ Nothing = do
-        error $ "Unsupported testEnum form"
-
-    testTypedef _ (Just x) = do
+    testTypedef _ x = do
         ThriftTestUtils.serverLog $ show x
         return x
 
-    testTypedef _ Nothing = do
-        error $ "Unsupported testTypedef form"
-
-    testMapMap _ (Just _) = do
+    testMapMap _ _ = do
         return (Map.fromList [(1, Map.fromList [(2, 2)])])
 
-    testMapMap _ Nothing = do
-        error $ "Unsupported testMapMap form"
-
-    testInsanity _ (Just x) = do
+    testInsanity _ x = do
         return (Map.fromList [(1, Map.fromList [(Types.ONE, x)])])
 
-    testInsanity _ Nothing = do
-        error $ "Unsupported testInsanity form"
-
     testMulti _ _ _ _ _ _ _ = do
-        return (Types.Xtruct Nothing Nothing Nothing Nothing)
+        return (Types.Xtruct "" 0 0 0)
 
     testException _ _ = do
-        Control.Exception.throw (Types.Xception (Just 1) (Just "bya"))
+        Control.Exception.throw (Types.Xception 1 "bya")
 
     testMultiException _ _ _ = do
-        Control.Exception.throw (Types.Xception (Just 1) (Just "xyz"))
+        Control.Exception.throw (Types.Xception 1 "xyz")
 
-    testOneway _ (Just i) = do
+    testOneway _ i = do
         ThriftTestUtils.serverLog $ show i
 
-    testOneway _ Nothing = do
-        error $ "Unsupported testOneway form"
-
 
 client :: (String, Network.PortID) -> IO ()
 client addr = do
@@ -210,7 +162,7 @@
     v13 <- Client.testSet ps (Set.fromList [1,2,3,4,5])
     ThriftTestUtils.clientLog $ show v13
 
-    v14 <- Client.testStruct ps (Types.Xtruct (Just "hi") (Just 4) (Just 5) Nothing)
+    v14 <- Client.testStruct ps (Types.Xtruct "hi" 4 5 0)
     ThriftTestUtils.clientLog $ show v14
 
     (testException ps "bad") `Control.Exception.catch` testExceptionHandler
@@ -222,7 +174,7 @@
 
     tClose to
   where testException ps msg = do
-            Client.testException ps "e"
+            _ <- Client.testException ps "e"
             ThriftTestUtils.clientLog msg
             return ()
 
diff --git a/test/hs/run-test.sh b/test/hs/run-test.sh
old mode 100644
new mode 100755
diff --git a/test/test.sh b/test/test.sh
index 2f74739..5d06e47 100755
--- a/test/test.sh
+++ b/test/test.sh
@@ -208,6 +208,95 @@
 ruby_transports="buffered framed"
 ruby_sockets="ip"
 
+hs_protocols="binary compact json"
+hs_transports="buffered"
+hs_sockets="ip"
+
+######### hs client - hs server ###############
+for proto in $hs_protocols; do
+  for trans in $hs_transports; do
+    for sock in $hs_sockets; do
+      case "$sock" in
+       "ip" )     extraparam="";;
+       "ip-ssl" ) extraparam="--ssl";;
+       "domain" ) extraparam="--domain-socket=/tmp/ThriftTest.thrift";;
+      esac
+      do_test "hs-hs"   "${proto}" "${trans}-${sock}" \
+              "hs/TestClient --protocol ${proto} --transport ${trans} ${extraparam}" \
+              "hs/TestServer --protocol ${proto} --transport ${trans} ${extraparam}" \
+              "2" "0.1"
+    done
+  done
+done
+
+######### hs client - cpp server ###############
+for proto in $(intersection "${hs_protocols}" "${cpp_protocols}"); do
+  for trans in  $(intersection "${hs_transports}" "${cpp_transports}"); do
+    for sock in $(intersection "${hs_sockets}" "${cpp_sockets}"); do
+      case "$sock" in
+       "ip" )     extraparam="";;
+       "ip-ssl" ) extraparam="--ssl";;
+       "domain" ) extraparam="--domain-socket=/tmp/ThriftTest.thrift";;
+      esac
+      do_test "hs-cpp"   "${proto}" "${trans}-${sock}" \
+              "hs/TestClient --protocol ${proto} --transport ${trans} ${extraparam}" \
+              "cpp/TestServer --protocol=${proto} --transport=${trans} ${extraparam}" \
+              "2" "0.1"
+    done
+  done
+done
+
+######### cpp client - hs server ###############
+for proto in $(intersection "${hs_protocols}" "${cpp_protocols}"); do
+  for trans in  $(intersection "${hs_transports}" "${cpp_transports}"); do
+    for sock in $(intersection "${hs_sockets}" "${cpp_sockets}"); do
+      case "$sock" in
+       "ip" )     extraparam="";;
+       "ip-ssl" ) extraparam="--ssl";;
+       "domain" ) extraparam="--domain-socket=/tmp/ThriftTest.thrift";;
+      esac
+      do_test "cpp-hs"   "${proto}" "${trans}-${sock}" \
+              "cpp/TestClient --protocol=${proto} --transport=${trans} ${extraparam}" \
+              "hs/TestServer --protocol ${proto} --transport ${trans} ${extraparam}" \
+              "2" "0.1"
+    done
+  done
+done
+
+######### hs client - java server ###############
+for proto in $(intersection "${hs_protocols}" "${java_protocols}"); do
+  for trans in  $(intersection "${hs_transports}" "${java_transports}"); do
+    for sock in $(intersection "${hs_sockets}" "${java_sockets}"); do
+      case "$sock" in
+       "ip" )     extraparam="";;
+       "ip-ssl" ) extraparam="--ssl";;
+       "domain" ) extraparam="--domain-socket=/tmp/ThriftTest.thrift";;
+      esac
+      do_test "hs-java" "${proto}" "${trans}-${sock}" \
+              "hs/TestClient --protocol ${proto} --transport ${trans} ${extraparam}" \
+	      "ant -f  ../lib/java/build.xml -Dno-gen-thrift=\"\" -Dtestargs \"--protocol=${proto} --transport=${trans} ${extraparam}\" run-testserver" \
+              "cpp/TestServer --protocol=${proto} --transport=${trans} ${extraparam}" \
+              "5" "1"
+    done
+  done
+done
+
+######### java client - hs server ###############
+for proto in $(intersection "${hs_protocols}" "${java_protocols}"); do
+  for trans in  $(intersection "${hs_transports}" "${java_transports}"); do
+    for sock in $(intersection "${hs_sockets}" "${java_sockets}"); do
+      case "$sock" in
+       "ip" )     extraparam="";;
+       "ip-ssl" ) extraparam="--ssl";;
+       "domain" ) extraparam="--domain-socket=/tmp/ThriftTest.thrift";;
+      esac
+      do_test "java-hs" "${proto}" "${trans}-${sock}" \
+              "ant -f  ../lib/java/build.xml -Dno-gen-thrift=\"\" -Dtestargs \"--protocol=${proto} --transport=${trans} ${extraparam}\" run-testclient" \
+              "hs/TestServer --protocol ${proto} --transport ${trans} ${extraparam}" \
+              "5" "1"
+    done
+  done
+done
 
 ######### java client - java server #############
 for proto in $java_protocols; do
@@ -860,7 +949,6 @@
   done
 done
 
-
 do_test "js-java"   "json"  "http-ip" \
         "" \
         "ant -f  ../lib/js/test/build.xml unittest" \