THRIFT-3347 Improve cross test servers and clients
Client: TestSuite, C++, Perl, NodeJS, c_glib, Haskell, Python
Patch: Nobuaki Sukegawa <nsukeg@gmail.com>

This closes #621
diff --git a/test/cpp/src/TestClient.cpp b/test/cpp/src/TestClient.cpp
index 1c0254b..7c425a9 100644
--- a/test/cpp/src/TestClient.cpp
+++ b/test/cpp/src/TestClient.cpp
@@ -266,7 +266,12 @@
   uint64_t time_max = 0;
   uint64_t time_tot = 0;
 
-  int failCount = 0;
+  int return_code = 0;
+  int ERR_BASETYPES = 1;
+  int ERR_STRUCTS = 2;
+  int ERR_CONTAINERS = 4;
+  int ERR_EXCEPTIONS = 8;
+
   int test = 0;
   for (test = 0; test < numTests; ++test) {
 
@@ -292,8 +297,9 @@
       testClient.testVoid();
       printf(" = void\n");
     } catch (TApplicationException& tax) {
+      printf("*** FAILED ***\n");
       printf("%s\n", tax.what());
-      failCount++;
+      return_code |= ERR_BASETYPES;
     }
 
     /**
@@ -303,8 +309,10 @@
     string s;
     testClient.testString(s, "Test");
     printf(" = \"%s\"\n", s.c_str());
-    if (s != "Test")
-      failCount++;
+    if (s != "Test") {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_BASETYPES;
+    }
 
     /**
      * BOOL TEST
@@ -312,14 +320,18 @@
     printf("testBool(true)");
     bool bl = testClient.testBool(true);
     printf(" = %s\n", bl ? "true" : "false");
-    if (bl != true)
-      failCount++;
+    if (bl != true) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_BASETYPES;
+    }
 
     printf("testBool(false)");
     bl = testClient.testBool(false);
     printf(" = %s\n", bl ? "true" : "false");
-    if (bl != false)
-      failCount++;
+    if (bl != false) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_BASETYPES;
+    }
 
     /**
      * BYTE TEST
@@ -327,8 +339,10 @@
     printf("testByte(1)");
     uint8_t u8 = testClient.testByte(1);
     printf(" = %d\n", (int)u8);
-    if (u8 != 1)
-      failCount++;
+    if (u8 != 1) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_BASETYPES;
+    }
 
     /**
      * I32 TEST
@@ -336,8 +350,10 @@
     printf("testI32(-1)");
     int32_t i32 = testClient.testI32(-1);
     printf(" = %d\n", i32);
-    if (i32 != -1)
-      failCount++;
+    if (i32 != -1) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_BASETYPES;
+    }
 
     /**
      * I64 TEST
@@ -345,8 +361,10 @@
     printf("testI64(-34359738368)");
     int64_t i64 = testClient.testI64(-34359738368LL);
     printf(" = %" PRId64 "\n", i64);
-    if (i64 != -34359738368LL)
-      failCount++;
+    if (i64 != -34359738368LL) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_BASETYPES;
+    }
 
     /**
      * DOUBLE TEST
@@ -354,13 +372,66 @@
     printf("testDouble(-5.2098523)");
     double dub = testClient.testDouble(-5.2098523);
     printf(" = %f\n", dub);
-    if ((dub - (-5.2098523)) > 0.001)
-      failCount++;
+    if ((dub - (-5.2098523)) > 0.001) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_BASETYPES;
+    }
 
     /**
      * BINARY TEST
      */
-    // TODO: add testBinary() call
+    printf("testBinary([-128..127]) = {");
+    const char bin_data[256]
+        = {-128, -127, -126, -125, -124, -123, -122, -121, -120, -119, -118, -117, -116, -115, -114,
+           -113, -112, -111, -110, -109, -108, -107, -106, -105, -104, -103, -102, -101, -100, -99,
+           -98,  -97,  -96,  -95,  -94,  -93,  -92,  -91,  -90,  -89,  -88,  -87,  -86,  -85,  -84,
+           -83,  -82,  -81,  -80,  -79,  -78,  -77,  -76,  -75,  -74,  -73,  -72,  -71,  -70,  -69,
+           -68,  -67,  -66,  -65,  -64,  -63,  -62,  -61,  -60,  -59,  -58,  -57,  -56,  -55,  -54,
+           -53,  -52,  -51,  -50,  -49,  -48,  -47,  -46,  -45,  -44,  -43,  -42,  -41,  -40,  -39,
+           -38,  -37,  -36,  -35,  -34,  -33,  -32,  -31,  -30,  -29,  -28,  -27,  -26,  -25,  -24,
+           -23,  -22,  -21,  -20,  -19,  -18,  -17,  -16,  -15,  -14,  -13,  -12,  -11,  -10,  -9,
+           -8,   -7,   -6,   -5,   -4,   -3,   -2,   -1,   0,    1,    2,    3,    4,    5,    6,
+           7,    8,    9,    10,   11,   12,   13,   14,   15,   16,   17,   18,   19,   20,   21,
+           22,   23,   24,   25,   26,   27,   28,   29,   30,   31,   32,   33,   34,   35,   36,
+           37,   38,   39,   40,   41,   42,   43,   44,   45,   46,   47,   48,   49,   50,   51,
+           52,   53,   54,   55,   56,   57,   58,   59,   60,   61,   62,   63,   64,   65,   66,
+           67,   68,   69,   70,   71,   72,   73,   74,   75,   76,   77,   78,   79,   80,   81,
+           82,   83,   84,   85,   86,   87,   88,   89,   90,   91,   92,   93,   94,   95,   96,
+           97,   98,   99,   100,  101,  102,  103,  104,  105,  106,  107,  108,  109,  110,  111,
+           112,  113,  114,  115,  116,  117,  118,  119,  120,  121,  122,  123,  124,  125,  126,
+           127};
+    try {
+      string bin_result;
+      testClient.testBinary(bin_result, string(bin_data, 256));
+      if (bin_result.size() != 256) {
+        printf("}\n*** FAILED ***\n");
+        printf("invalid length: %lu\n", bin_result.size());
+        return_code |= ERR_BASETYPES;
+      } else {
+        bool first = true;
+        bool failed = false;
+        for (int i = 0; i < 256; ++i) {
+          if (!first)
+            printf(" ,");
+          else
+            first = false;
+          printf("%d", bin_result[i]);
+          if (!failed && bin_result[i] != i - 128) {
+            failed = true;
+          }
+        }
+        printf("}\n");
+        if (failed) {
+          printf("*** FAILED ***\n");
+          return_code |= ERR_BASETYPES;
+        }
+      }
+    } catch (exception& ex) {
+      printf("}\n*** FAILED ***\n");
+      printf("%s\n", ex.what());
+      return_code |= ERR_BASETYPES;
+    }
+
 
     /**
      * STRUCT TEST
@@ -378,8 +449,10 @@
            (int)in.byte_thing,
            in.i32_thing,
            in.i64_thing);
-    if (in != out)
-      failCount++;
+    if (in != out) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_STRUCTS;
+    }
 
     /**
      * NESTED STRUCT TEST
@@ -399,8 +472,10 @@
            in.i32_thing,
            in.i64_thing,
            in2.i32_thing);
-    if (in2 != out2)
-      failCount++;
+    if (in2 != out2) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_STRUCTS;
+    }
 
     /**
      * MAP TEST
@@ -434,13 +509,40 @@
       printf("%d => %d", m_iter->first, m_iter->second);
     }
     printf("}\n");
-    if (mapin != mapout)
-      failCount++;
+    if (mapin != mapout) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_CONTAINERS;
+    }
 
     /**
      * STRING MAP TEST
-     *  missing
      */
+    printf("testStringMap({a => 2, b => blah, some => thing}) = {");
+    map<string, string> smapin;
+    map<string, string> smapout;
+    smapin["a"] = "2";
+    smapin["b"] = "blah";
+    smapin["some"] = "thing";
+    try {
+      testClient.testStringMap(smapout, smapin);
+      first = true;
+      for (map<string, string>::const_iterator it = smapout.begin(); it != smapout.end(); ++it) {
+        if (first)
+          printf(",");
+        else
+          first = false;
+        printf("%s => %s", it->first.c_str(), it->second.c_str());
+      }
+      printf("}\n");
+      if (smapin != smapout) {
+        printf("*** FAILED ***\n");
+        return_code |= ERR_CONTAINERS;
+      }
+    } catch (exception& ex) {
+      printf("}\n*** FAILED ***\n");
+      printf("%s\n", ex.what());
+      return_code |= ERR_CONTAINERS;
+    }
 
     /**
      * SET TEST
@@ -474,8 +576,10 @@
       printf("%d", *s_iter);
     }
     printf("}\n");
-    if (setin != setout)
-      failCount++;
+    if (setin != setout) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_CONTAINERS;
+    }
 
     /**
      * LIST TEST
@@ -509,8 +613,10 @@
       printf("%d", *l_iter);
     }
     printf("}\n");
-    if (listin != listout)
-      failCount++;
+    if (listin != listout) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_CONTAINERS;
+    }
 
     /**
      * ENUM TEST
@@ -518,32 +624,42 @@
     printf("testEnum(ONE)");
     Numberz::type ret = testClient.testEnum(Numberz::ONE);
     printf(" = %d\n", ret);
-    if (ret != Numberz::ONE)
-      failCount++;
+    if (ret != Numberz::ONE) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_STRUCTS;
+    }
 
     printf("testEnum(TWO)");
     ret = testClient.testEnum(Numberz::TWO);
     printf(" = %d\n", ret);
-    if (ret != Numberz::TWO)
-      failCount++;
+    if (ret != Numberz::TWO) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_STRUCTS;
+    }
 
     printf("testEnum(THREE)");
     ret = testClient.testEnum(Numberz::THREE);
     printf(" = %d\n", ret);
-    if (ret != Numberz::THREE)
-      failCount++;
+    if (ret != Numberz::THREE) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_STRUCTS;
+    }
 
     printf("testEnum(FIVE)");
     ret = testClient.testEnum(Numberz::FIVE);
     printf(" = %d\n", ret);
-    if (ret != Numberz::FIVE)
-      failCount++;
+    if (ret != Numberz::FIVE) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_STRUCTS;
+    }
 
     printf("testEnum(EIGHT)");
     ret = testClient.testEnum(Numberz::EIGHT);
     printf(" = %d\n", ret);
-    if (ret != Numberz::EIGHT)
-      failCount++;
+    if (ret != Numberz::EIGHT) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_STRUCTS;
+    }
 
     /**
      * TYPEDEF TEST
@@ -551,8 +667,10 @@
     printf("testTypedef(309858235082523)");
     UserId uid = testClient.testTypedef(309858235082523LL);
     printf(" = %" PRId64 "\n", uid);
-    if (uid != 309858235082523LL)
-      failCount++;
+    if (uid != 309858235082523LL) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_STRUCTS;
+    }
 
     /**
      * NESTED MAP TEST
@@ -571,19 +689,38 @@
       printf("}, ");
     }
     printf("}\n");
+    if (mm.size() != 2 ||
+        mm[-4][-4] != -4 ||
+        mm[-4][-3] != -3 ||
+        mm[-4][-2] != -2 ||
+        mm[-4][-1] != -1 ||
+        mm[4][4] != 4 ||
+        mm[4][3] != 3 ||
+        mm[4][2] != 2 ||
+        mm[4][1] != 1) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_CONTAINERS;
+    }
 
     /**
      * INSANITY TEST
      */
     if (!noinsane) {
       Insanity insane;
-      insane.userMap.insert(make_pair(Numberz::FIVE, 5000));
+      insane.userMap.insert(make_pair(Numberz::FIVE, 5));
+      insane.userMap.insert(make_pair(Numberz::EIGHT, 8));
       Xtruct truck;
-      truck.string_thing = "Truck";
-      truck.byte_thing = 8;
-      truck.i32_thing = 8;
-      truck.i64_thing = 8;
+      truck.string_thing = "Goodbye4";
+      truck.byte_thing = 4;
+      truck.i32_thing = 4;
+      truck.i64_thing = 4;
+      Xtruct truck2;
+      truck2.string_thing = "Hello2";
+      truck2.byte_thing = 2;
+      truck2.i32_thing = 2;
+      truck2.i64_thing = 2;
       insane.xtructs.push_back(truck);
+      insane.xtructs.push_back(truck2);
       printf("testInsanity()");
       map<UserId, map<Numberz::type, Insanity> > whoa;
       testClient.testInsanity(whoa, insane);
@@ -619,14 +756,69 @@
         printf("}, ");
       }
       printf("}\n");
+      bool failed = false;
+      map<UserId, map<Numberz::type, Insanity> >::const_iterator it1 = whoa.find(UserId(1));
+      if (whoa.size() != 2) {
+        failed = true;
+      }
+      if (it1 == whoa.end()) {
+        failed = true;
+      } else {
+        map<Numberz::type, Insanity>::const_iterator it12 = it1->second.find(Numberz::TWO);
+        if (it12 == it1->second.end() || it12->second != insane) {
+          failed = true;
+        }
+        map<Numberz::type, Insanity>::const_iterator it13 = it1->second.find(Numberz::THREE);
+        if (it13 == it1->second.end() || it13->second != insane) {
+          failed = true;
+        }
+      }
+      map<UserId, map<Numberz::type, Insanity> >::const_iterator it2 = whoa.find(UserId(2));
+      if (it2 == whoa.end()) {
+        failed = true;
+      } else {
+        map<Numberz::type, Insanity>::const_iterator it26 = it2->second.find(Numberz::SIX);
+        if (it26 == it1->second.end() || it26->second != Insanity()) {
+          failed = true;
+        }
+      }
+      if (failed) {
+        printf("*** FAILED ***\n");
+        return_code |= ERR_STRUCTS;
+      }
     }
+
+    /**
+     * MULTI TEST
+     */
+    printf("testMulti()\n");
+    try {
+      map<int16_t, string> mul_map;
+      Xtruct mul_result;
+      mul_map[1] = "blah";
+      mul_map[2] = "thing";
+      testClient.testMulti(mul_result, 42, 4242, 424242, mul_map, Numberz::EIGHT, UserId(24));
+      Xtruct xxs;
+      xxs.string_thing = "Hello2";
+      xxs.byte_thing = 42;
+      xxs.i32_thing = 4242;
+      xxs.i64_thing = 424242;
+      if (mul_result != xxs) {
+        printf("*** FAILED ***\n");
+        return_code |= ERR_STRUCTS;
+      }
+    } catch (exception& ex) {
+      printf("*** FAILED ***\n");
+      return_code |= ERR_STRUCTS;
+    }
+
     /* test exception */
 
     try {
       printf("testClient.testException(\"Xception\") =>");
       testClient.testException("Xception");
-      printf("  void\nFAILURE\n");
-      failCount++;
+      printf("  void\n*** FAILED ***\n");
+      return_code |= ERR_EXCEPTIONS;
 
     } catch (Xception& e) {
       printf("  {%u, \"%s\"}\n", e.errorCode, e.message.c_str());
@@ -635,8 +827,8 @@
     try {
       printf("testClient.testException(\"TException\") =>");
       testClient.testException("TException");
-      printf("  void\nFAILURE\n");
-      failCount++;
+      printf("  void\n*** FAILED ***\n");
+      return_code |= ERR_EXCEPTIONS;
 
     } catch (const TException&) {
       printf("  Caught TException\n");
@@ -647,8 +839,8 @@
       testClient.testException("success");
       printf("  void\n");
     } catch (...) {
-      printf("  exception\nFAILURE\n");
-      failCount++;
+      printf("  exception\n*** FAILED ***\n");
+      return_code |= ERR_EXCEPTIONS;
     }
 
     /* test multi exception */
@@ -657,8 +849,8 @@
       printf("testClient.testMultiException(\"Xception\", \"test 1\") =>");
       Xtruct result;
       testClient.testMultiException(result, "Xception", "test 1");
-      printf("  result\nFAILURE\n");
-      failCount++;
+      printf("  result\n*** FAILED ***\n");
+      return_code |= ERR_EXCEPTIONS;
     } catch (Xception& e) {
       printf("  {%u, \"%s\"}\n", e.errorCode, e.message.c_str());
     }
@@ -667,8 +859,8 @@
       printf("testClient.testMultiException(\"Xception2\", \"test 2\") =>");
       Xtruct result;
       testClient.testMultiException(result, "Xception2", "test 2");
-      printf("  result\nFAILURE\n");
-      failCount++;
+      printf("  result\n*** FAILED ***\n");
+      return_code |= ERR_EXCEPTIONS;
 
     } catch (Xception2& e) {
       printf("  {%u, {\"%s\"}}\n", e.errorCode, e.struct_thing.string_thing.c_str());
@@ -680,8 +872,8 @@
       testClient.testMultiException(result, "success", "test 3");
       printf("  {{\"%s\"}}\n", result.string_thing.c_str());
     } catch (...) {
-      printf("  exception\nFAILURE\n");
-      failCount++;
+      printf("  exception\n*** FAILED ***\n");
+      return_code |= ERR_EXCEPTIONS;
     }
 
     /* test oneway void */
@@ -691,8 +883,8 @@
       testClient.testOneway(1);
       uint64_t elapsed = now() - startOneway;
       if (elapsed > 200 * 1000) { // 0.2 seconds
-        printf("  FAILURE - took %.2f ms\n", (double)elapsed / 1000.0);
-        failCount++;
+        printf("*** FAILED *** - took %.2f ms\n", (double)elapsed / 1000.0);
+      return_code |= ERR_BASETYPES;
       } else {
         printf("  success - took %.2f ms\n", (double)elapsed / 1000.0);
       }
@@ -713,7 +905,7 @@
     i32 = testClient.testI32(-1);
     printf(" = %d\n", i32);
     if (i32 != -1)
-      failCount++;
+      return_code |= ERR_BASETYPES;
 
     uint64_t stop = now();
     uint64_t tot = stop - start;
@@ -739,5 +931,5 @@
   printf("Max time: %" PRIu64 " us\n", time_max);
   printf("Avg time: %" PRIu64 " us\n", time_avg);
 
-  return failCount;
+  return return_code;
 }