Thrift now a TLP - INFRA-3116

git-svn-id: https://svn.apache.org/repos/asf/thrift/branches/0.1.x@1028168 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/test/AllProtocolTests.cpp b/test/AllProtocolTests.cpp
new file mode 100644
index 0000000..db29ccc
--- /dev/null
+++ b/test/AllProtocolTests.cpp
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+
+#include <protocol/TBinaryProtocol.h>
+#include <protocol/TCompactProtocol.h>
+#include <transport/TBufferTransports.h>
+#include "AllProtocolTests.tcc"
+
+using namespace apache::thrift;
+using namespace apache::thrift::protocol;
+using namespace apache::thrift::transport;
+
+char errorMessage[ERR_LEN];
+
+int main(int argc, char** argv) {
+  try {
+    testProtocol<TBinaryProtocol>("TBinaryProtocol");
+    testProtocol<TCompactProtocol>("TCompactProtocol");
+  } catch (TException e) {
+    printf("%s\n", e.what());
+    return 1;
+  }
+  return 0;
+}
diff --git a/test/AllProtocolTests.tcc b/test/AllProtocolTests.tcc
new file mode 100644
index 0000000..a5a3115
--- /dev/null
+++ b/test/AllProtocolTests.tcc
@@ -0,0 +1,227 @@
+/*
+ * 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.
+ */
+
+#ifndef _THRIFT_TEST_GENERICPROTOCOLTEST_TCC_
+#define _THRIFT_TEST_GENERICPROTOCOLTEST_TCC_ 1
+
+#include <limits>
+
+#include <protocol/TBinaryProtocol.h>
+#include <transport/TBufferTransports.h>
+#include <Thrift.h>
+
+#include "GenericHelpers.h"
+
+using boost::shared_ptr;
+using namespace apache::thrift;
+using namespace apache::thrift::protocol;
+using namespace apache::thrift::transport;
+
+#define ERR_LEN 512
+extern char errorMessage[ERR_LEN];
+
+template <typename TProto, typename Val>
+void testNaked(Val val) {
+  shared_ptr<TTransport> transport(new TMemoryBuffer());
+  shared_ptr<TProtocol> protocol(new TProto(transport));
+
+  GenericIO::write(protocol, val);
+  Val out;
+  GenericIO::read(protocol, out);
+  if (out != val) {
+    snprintf(errorMessage, ERR_LEN, "Invalid naked test (type: %s)", ClassNames::getName<Val>());
+    throw TException(errorMessage);
+  }
+}
+
+template <typename TProto, TType type, typename Val>
+void testField(const Val val) {
+  shared_ptr<TTransport> transport(new TMemoryBuffer());
+  shared_ptr<TProtocol> protocol(new TProto(transport));
+
+  protocol->writeStructBegin("test_struct");
+  protocol->writeFieldBegin("test_field", type, (int16_t)15);
+
+  GenericIO::write(protocol, val);
+
+  protocol->writeFieldEnd();
+  protocol->writeStructEnd();
+
+  std::string name;
+  TType fieldType;
+  int16_t fieldId;
+
+  protocol->readStructBegin(name);
+  protocol->readFieldBegin(name, fieldType, fieldId);
+
+  if (fieldId != 15) {
+    snprintf(errorMessage, ERR_LEN, "Invalid ID (type: %s)", typeid(val).name());
+    throw TException(errorMessage);
+  }
+  if (fieldType != type) {
+    snprintf(errorMessage, ERR_LEN, "Invalid Field Type (type: %s)", typeid(val).name());
+    throw TException(errorMessage);
+  }
+
+  Val out;
+  GenericIO::read(protocol, out);
+
+  if (out != val) {
+    snprintf(errorMessage, ERR_LEN, "Invalid value read (type: %s)", typeid(val).name());
+    throw TException(errorMessage);
+  }
+
+  protocol->readFieldEnd();
+  protocol->readStructEnd();
+}
+
+template <typename TProto>
+void testMessage() {
+  struct TMessage {
+    const char* name;
+    TMessageType type;
+    int32_t seqid;
+  } messages[4] = {
+    {"short message name", T_CALL, 0},
+    {"1", T_REPLY, 12345},
+    {"loooooooooooooooooooooooooooooooooong", T_EXCEPTION, 1 << 16},
+    {"Janky", T_CALL, 0}
+  };
+
+  for (int i = 0; i < 4; i++) {
+    shared_ptr<TTransport> transport(new TMemoryBuffer());
+    shared_ptr<TProtocol> protocol(new TProto(transport));
+
+    protocol->writeMessageBegin(messages[i].name,
+                                messages[i].type,
+                                messages[i].seqid);
+    protocol->writeMessageEnd();
+
+    std::string name;
+    TMessageType type;
+    int32_t seqid;
+
+    protocol->readMessageBegin(name, type, seqid);
+    if (name != messages[i].name ||
+        type != messages[i].type ||
+        seqid != messages[i].seqid) {
+      throw TException("readMessageBegin failed.");
+    }
+  }
+}
+
+template <typename TProto>
+void testProtocol(const char* protoname) {
+  try {
+    testNaked<TProto, int8_t>((int8_t)123);
+
+    for (int32_t i = 0; i < 128; i++) {
+      testField<TProto, T_BYTE, int8_t>((int8_t)i);
+      testField<TProto, T_BYTE, int8_t>((int8_t)-i);
+    }
+
+    testNaked<TProto, int16_t>((int16_t)0);
+    testNaked<TProto, int16_t>((int16_t)1);
+    testNaked<TProto, int16_t>((int16_t)15000);
+    testNaked<TProto, int16_t>((int16_t)0x7fff);
+    testNaked<TProto, int16_t>((int16_t)-1);
+    testNaked<TProto, int16_t>((int16_t)-15000);
+    testNaked<TProto, int16_t>((int16_t)-0x7fff);
+    testNaked<TProto, int16_t>(std::numeric_limits<int16_t>::min());
+    testNaked<TProto, int16_t>(std::numeric_limits<int16_t>::max());
+
+    testField<TProto, T_I16, int16_t>((int16_t)0);
+    testField<TProto, T_I16, int16_t>((int16_t)1);
+    testField<TProto, T_I16, int16_t>((int16_t)7);
+    testField<TProto, T_I16, int16_t>((int16_t)150);
+    testField<TProto, T_I16, int16_t>((int16_t)15000);
+    testField<TProto, T_I16, int16_t>((int16_t)0x7fff);
+    testField<TProto, T_I16, int16_t>((int16_t)-1);
+    testField<TProto, T_I16, int16_t>((int16_t)-7);
+    testField<TProto, T_I16, int16_t>((int16_t)-150);
+    testField<TProto, T_I16, int16_t>((int16_t)-15000);
+    testField<TProto, T_I16, int16_t>((int16_t)-0x7fff);
+
+    testNaked<TProto, int32_t>(0);
+    testNaked<TProto, int32_t>(1);
+    testNaked<TProto, int32_t>(15000);
+    testNaked<TProto, int32_t>(0xffff);
+    testNaked<TProto, int32_t>(-1);
+    testNaked<TProto, int32_t>(-15000);
+    testNaked<TProto, int32_t>(-0xffff);
+    testNaked<TProto, int32_t>(std::numeric_limits<int32_t>::min());
+    testNaked<TProto, int32_t>(std::numeric_limits<int32_t>::max());
+
+    testField<TProto, T_I32, int32_t>(0);
+    testField<TProto, T_I32, int32_t>(1);
+    testField<TProto, T_I32, int32_t>(7);
+    testField<TProto, T_I32, int32_t>(150);
+    testField<TProto, T_I32, int32_t>(15000);
+    testField<TProto, T_I32, int32_t>(31337);
+    testField<TProto, T_I32, int32_t>(0xffff);
+    testField<TProto, T_I32, int32_t>(0xffffff);
+    testField<TProto, T_I32, int32_t>(-1);
+    testField<TProto, T_I32, int32_t>(-7);
+    testField<TProto, T_I32, int32_t>(-150);
+    testField<TProto, T_I32, int32_t>(-15000);
+    testField<TProto, T_I32, int32_t>(-0xffff);
+    testField<TProto, T_I32, int32_t>(-0xffffff);
+    testNaked<TProto, int64_t>(std::numeric_limits<int32_t>::min());
+    testNaked<TProto, int64_t>(std::numeric_limits<int32_t>::max());
+    testNaked<TProto, int64_t>(std::numeric_limits<int32_t>::min() + 10);
+    testNaked<TProto, int64_t>(std::numeric_limits<int32_t>::max() - 16);
+    testNaked<TProto, int64_t>(std::numeric_limits<int64_t>::min());
+    testNaked<TProto, int64_t>(std::numeric_limits<int64_t>::max());
+
+
+    testNaked<TProto, int64_t>(0);
+    for (int64_t i = 0; i < 62; i++) {
+      testNaked<TProto, int64_t>(1L << i);
+      testNaked<TProto, int64_t>(-(1L << i));
+    }
+
+    testField<TProto, T_I64, int64_t>(0);
+    for (int i = 0; i < 62; i++) {
+      testField<TProto, T_I64, int64_t>(1L << i);
+      testField<TProto, T_I64, int64_t>(-(1L << i));
+    }
+
+    testNaked<TProto, double>(123.456);
+
+    testNaked<TProto, std::string>("");
+    testNaked<TProto, std::string>("short");
+    testNaked<TProto, std::string>("borderlinetiny");
+    testNaked<TProto, std::string>("a bit longer than the smallest possible");
+    testNaked<TProto, std::string>("\x1\x2\x3\x4\x5\x6\x7\x8\x9\xA"); //kinda binary test
+
+    testField<TProto, T_STRING, std::string>("");
+    testField<TProto, T_STRING, std::string>("short");
+    testField<TProto, T_STRING, std::string>("borderlinetiny");
+    testField<TProto, T_STRING, std::string>("a bit longer than the smallest possible");
+
+    testMessage<TProto>();
+
+    printf("%s => OK\n", protoname);
+  } catch (TException e) {
+    snprintf(errorMessage, ERR_LEN, "%s => Test FAILED: %s", protoname, e.what());
+    throw TException(errorMessage);
+  }
+}
+
+#endif
diff --git a/test/AnnotationTest.thrift b/test/AnnotationTest.thrift
new file mode 100644
index 0000000..dcc41b0
--- /dev/null
+++ b/test/AnnotationTest.thrift
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+typedef list<i32> ( cpp.template = "std::list" ) int_linked_list
+
+struct foo {
+  1: i32 bar;
+  2: i32 baz;
+  3: i32 qux;
+  4: i32 bop;
+} (
+  cpp.type = "DenseFoo",
+  python.type = "DenseFoo",
+  java.final = "",
+)
diff --git a/test/Benchmark.cpp b/test/Benchmark.cpp
new file mode 100644
index 0000000..d315fca
--- /dev/null
+++ b/test/Benchmark.cpp
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ */
+
+#include <iostream>
+#include <cmath>
+#include <transport/TBufferTransports.h>
+#include <protocol/TBinaryProtocol.h>
+#include <protocol/TJSONProtocol.h>
+#include "gen-cpp/DebugProtoTest_types.h"
+#include <time.h>
+#include "../lib/cpp/src/protocol/TDebugProtocol.h"
+#include <sys/time.h>
+
+class Timer {
+public:
+  timeval vStart;
+
+  Timer() {
+    gettimeofday(&vStart, 0);
+  }
+  void start() {
+    gettimeofday(&vStart, 0);
+  }
+
+  double frame() {
+    timeval vEnd;
+    gettimeofday(&vEnd, 0);
+    double dstart = vStart.tv_sec + ((double)vStart.tv_usec / 1000000.0);
+    double dend = vEnd.tv_sec + ((double)vEnd.tv_usec / 1000000.0);
+    return dend - dstart;
+  }
+
+};
+
+int main() {
+  using namespace std;
+  using namespace thrift::test::debug;
+  using namespace apache::thrift::transport;
+  using namespace apache::thrift::protocol;
+  using namespace boost;
+
+  OneOfEach ooe;
+  ooe.im_true   = true;
+  ooe.im_false  = false;
+  ooe.a_bite    = 0xd6;
+  ooe.integer16 = 27000;
+  ooe.integer32 = 1<<24;
+  ooe.integer64 = (uint64_t)6000 * 1000 * 1000;
+  ooe.double_precision = M_PI;
+  ooe.some_characters  = "JSON THIS! \"\1";
+  ooe.zomg_unicode     = "\xd7\n\a\t";
+  ooe.base64 = "\1\2\3\255";
+
+  shared_ptr<TMemoryBuffer> buf(new TMemoryBuffer());
+
+  int num = 1000000;
+
+  {
+    Timer timer;
+
+    for (int i = 0; i < num; i ++) {
+      buf->resetBuffer();
+      TBinaryProtocol prot(buf);
+      ooe.write(&prot);
+    }
+    cout << "Write: " << num / (1000 * timer.frame()) << " kHz" << endl;
+  }
+
+  uint8_t* data;
+  uint32_t datasize;
+
+  buf->getBuffer(&data, &datasize);
+
+  {
+
+    Timer timer;
+
+    for (int i = 0; i < num; i ++) {
+      OneOfEach ooe2;
+      shared_ptr<TMemoryBuffer> buf2(new TMemoryBuffer(data, datasize));
+      //buf2->resetBuffer(data, datasize);
+      TBinaryProtocol prot(buf2);
+      ooe2.read(&prot);
+
+      //cout << apache::thrift::ThriftDebugString(ooe2) << endl << endl;
+    }
+    cout << " Read: " << num / (1000 * timer.frame()) << " kHz" << endl;
+  }
+
+
+  return 0;
+}
diff --git a/test/BrokenConstants.thrift b/test/BrokenConstants.thrift
new file mode 100644
index 0000000..c5aab4a
--- /dev/null
+++ b/test/BrokenConstants.thrift
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+const i64 myint = 68719476736
+const i64 broken = 9876543210987654321  // A little over 2^63
+
+enum foo {
+  bar = 68719476736
+}
diff --git a/test/ConstantsDemo.thrift b/test/ConstantsDemo.thrift
new file mode 100644
index 0000000..7e97f02
--- /dev/null
+++ b/test/ConstantsDemo.thrift
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+namespace cpp yozone
+
+struct thing {
+  1: i32 hello,
+  2: i32 goodbye
+}
+
+enum enumconstants {
+  ONE = 1,
+  TWO = 2
+}
+
+struct thing2 {
+  1: enumconstants val = TWO
+}
+
+typedef i32 myIntType
+const myIntType myInt = 3
+
+const map<enumconstants,string> GEN_ENUM_NAMES = {ONE : "HOWDY", TWO: PARTNER}
+
+const i32 hex_const = 0x0001F
+
+const i32 GEN_ME = -3523553
+const double GEn_DUB = 325.532
+const double GEn_DU = 085.2355
+const string GEN_STRING = "asldkjasfd"
+
+const map<i32,i32> GEN_MAP = { 35532 : 233, 43523 : 853 }
+const list<i32> GEN_LIST = [ 235235, 23598352, 3253523 ]
+
+const map<i32, map<i32, i32>> GEN_MAPMAP = { 235 : { 532 : 53255, 235:235}}
+
+const map<string,i32> GEN_MAP2 = { "hello" : 233, "lkj98d" : 853, 'lkjsdf' : 098325 }
+
+const thing GEN_THING = { 'hello' : 325, 'goodbye' : 325352 }
+
+const map<i32,thing> GEN_WHAT = { 35 : { 'hello' : 325, 'goodbye' : 325352 } }
+
+const set<i32> GEN_SET = [ 235, 235, 53235 ]
+
+exception Blah {
+  1:  i32 bing }
+
+exception Gak {}
+
+service yowza {
+  void blingity(),
+  i32 blangity() throws (1: Blah hoot )
+}
diff --git a/test/DebugProtoTest.cpp b/test/DebugProtoTest.cpp
new file mode 100644
index 0000000..8c9aabe
--- /dev/null
+++ b/test/DebugProtoTest.cpp
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+#include <iostream>
+#include <cmath>
+#include "gen-cpp/DebugProtoTest_types.h"
+#include "../lib/cpp/src/protocol/TDebugProtocol.h"
+
+int main() {
+  using std::cout;
+  using std::endl;
+  using namespace thrift::test::debug;
+
+
+  OneOfEach ooe;
+  ooe.im_true   = true;
+  ooe.im_false  = false;
+  ooe.a_bite    = 0xd6;
+  ooe.integer16 = 27000;
+  ooe.integer32 = 1<<24;
+  ooe.integer64 = (uint64_t)6000 * 1000 * 1000;
+  ooe.double_precision = M_PI;
+  ooe.some_characters  = "Debug THIS!";
+  ooe.zomg_unicode     = "\xd7\n\a\t";
+
+  cout << apache::thrift::ThriftDebugString(ooe) << endl << endl;
+
+
+  Nesting n;
+  n.my_ooe = ooe;
+  n.my_ooe.integer16 = 16;
+  n.my_ooe.integer32 = 32;
+  n.my_ooe.integer64 = 64;
+  n.my_ooe.double_precision = (std::sqrt(5)+1)/2;
+  n.my_ooe.some_characters  = ":R (me going \"rrrr\")";
+  n.my_ooe.zomg_unicode     = "\xd3\x80\xe2\x85\xae\xce\x9d\x20"
+                              "\xd0\x9d\xce\xbf\xe2\x85\xbf\xd0\xbe\xc9\xa1\xd0\xb3\xd0\xb0\xcf\x81\xe2\x84\x8e"
+                              "\x20\xce\x91\x74\x74\xce\xb1\xe2\x85\xbd\xce\xba\xc7\x83\xe2\x80\xbc";
+  n.my_bonk.type    = 31337;
+  n.my_bonk.message = "I am a bonk... xor!";
+
+  cout << apache::thrift::ThriftDebugString(n) << endl << endl;
+
+
+  HolyMoley hm;
+
+  hm.big.push_back(ooe);
+  hm.big.push_back(n.my_ooe);
+  hm.big[0].a_bite = 0x22;
+  hm.big[1].a_bite = 0x33;
+
+  std::vector<std::string> stage1;
+  stage1.push_back("and a one");
+  stage1.push_back("and a two");
+  hm.contain.insert(stage1);
+  stage1.clear();
+  stage1.push_back("then a one, two");
+  stage1.push_back("three!");
+  stage1.push_back("FOUR!!");
+  hm.contain.insert(stage1);
+  stage1.clear();
+  hm.contain.insert(stage1);
+
+  std::vector<Bonk> stage2;
+  hm.bonks["nothing"] = stage2;
+  stage2.resize(stage2.size()+1);
+  stage2.back().type = 1;
+  stage2.back().message = "Wait.";
+  stage2.resize(stage2.size()+1);
+  stage2.back().type = 2;
+  stage2.back().message = "What?";
+  hm.bonks["something"] = stage2;
+  stage2.clear();
+  stage2.resize(stage2.size()+1);
+  stage2.back().type = 3;
+  stage2.back().message = "quoth";
+  stage2.resize(stage2.size()+1);
+  stage2.back().type = 4;
+  stage2.back().message = "the raven";
+  stage2.resize(stage2.size()+1);
+  stage2.back().type = 5;
+  stage2.back().message = "nevermore";
+  hm.bonks["poe"] = stage2;
+
+  cout << apache::thrift::ThriftDebugString(hm) << endl << endl;
+
+
+  return 0;
+}
diff --git a/test/DebugProtoTest.thrift b/test/DebugProtoTest.thrift
new file mode 100644
index 0000000..d3d2580
--- /dev/null
+++ b/test/DebugProtoTest.thrift
@@ -0,0 +1,253 @@
+/*
+ * 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.
+ */
+
+namespace cpp thrift.test.debug
+namespace java thrift.test
+
+struct Doubles {
+ 1: double nan,
+ 2: double inf,
+ 3: double neginf,
+ 4: double repeating,
+ 5: double big,
+ 6: double small,
+ 7: double zero,
+ 8: double negzero,
+}
+
+struct OneOfEach {
+  1: bool im_true,
+  2: bool im_false,
+  3: byte a_bite = 200,
+  4: i16 integer16 = 33000,
+  5: i32 integer32,
+  6: i64 integer64 = 10000000000,
+  7: double double_precision,
+  8: string some_characters,
+  9: string zomg_unicode,
+  10: bool what_who,
+  11: binary base64,
+  12: list<byte> byte_list = [1, 2, 3],
+  13: list<i16> i16_list = [1,2,3],
+  14: list<i64> i64_list = [1,2,3]
+}
+
+struct Bonk {
+  1: i32 type,
+  2: string message,
+}
+
+struct Nesting {
+  1: Bonk my_bonk,
+  2: OneOfEach my_ooe,
+}
+
+struct HolyMoley {
+  1: list<OneOfEach> big,
+  2: set<list<string>> contain,
+  3: map<string,list<Bonk>> bonks,
+}
+
+struct Backwards {
+  2: i32 first_tag2,
+  1: i32 second_tag1,
+}
+
+struct Empty {
+}
+
+struct Wrapper {
+  1: Empty foo
+}
+
+struct RandomStuff {
+  1: i32 a,
+  2: i32 b,
+  3: i32 c,
+  4: i32 d,
+  5: list<i32> myintlist,
+  6: map<i32,Wrapper> maps,
+  7: i64 bigint,
+  8: double triple,
+}
+
+struct Base64 {
+  1: i32 a,
+  2: binary b1,
+  3: binary b2,
+  4: binary b3,
+  5: binary b4,
+  6: binary b5,
+  7: binary b6,
+}
+
+struct CompactProtoTestStruct {
+  // primitive fields
+  1: byte   a_byte;
+  2: i16    a_i16;
+  3: i32    a_i32;
+  4: i64    a_i64;
+  5: double a_double;
+  6: string a_string;
+  7: binary a_binary;
+  8: bool   true_field;
+  9: bool   false_field;
+  10: Empty empty_struct_field;
+  
+  // primitives in lists
+  11: list<byte>    byte_list;
+  12: list<i16>     i16_list;
+  13: list<i32>     i32_list;
+  14: list<i64>     i64_list;
+  15: list<double>  double_list;
+  16: list<string>  string_list;
+  17: list<binary>  binary_list;
+  18: list<bool>    boolean_list;
+  19: list<Empty>   struct_list;
+  
+  // primitives in sets
+  20: set<byte>     byte_set;
+  21: set<i16>      i16_set;
+  22: set<i32>      i32_set;
+  23: set<i64>      i64_set;
+  24: set<double>   double_set;
+  25: set<string>   string_set;
+  26: set<binary>   binary_set;
+  27: set<bool>     boolean_set;
+  28: set<Empty>    struct_set;
+  
+  // maps
+  // primitives as keys
+  29: map<byte, byte>             byte_byte_map;
+  30: map<i16, byte>              i16_byte_map;
+  31: map<i32, byte>              i32_byte_map;
+  32: map<i64, byte>              i64_byte_map;
+  33: map<double, byte>           double_byte_map;
+  34: map<string, byte>           string_byte_map;
+  35: map<binary, byte>           binary_byte_map;
+  36: map<bool, byte>             boolean_byte_map;
+  // primitives as values
+  37: map<byte, i16>              byte_i16_map;
+  38: map<byte, i32>              byte_i32_map;
+  39: map<byte, i64>              byte_i64_map;
+  40: map<byte, double>           byte_double_map;
+  41: map<byte, string>           byte_string_map;
+  42: map<byte, binary>           byte_binary_map;
+  43: map<byte, bool>             byte_boolean_map;
+  // collections as keys
+  44: map<list<byte>, byte>       list_byte_map;
+  45: map<set<byte>, byte>        set_byte_map;
+  46: map<map<byte,byte>, byte>   map_byte_map;
+  // collections as values
+  47: map<byte, map<byte,byte>>   byte_map_map;
+  48: map<byte, set<byte>>        byte_set_map;
+  49: map<byte, list<byte>>       byte_list_map;
+}
+
+
+const CompactProtoTestStruct COMPACT_TEST = {
+  'a_byte'             : 127,
+  'a_i16'              : 32000,
+  'a_i32'              : 1000000000,
+  'a_i64'              : 0xffffffffff,
+  'a_double'           : 5.6789,
+  'a_string'           : "my string",
+//'a_binary,'
+  'true_field'         : 1,
+  'false_field'        : 0,
+  'empty_struct_field' : {},
+  'byte_list'          : [-127, -1, 0, 1, 127],
+  'i16_list'           : [-1, 0, 1, 0x7fff],
+  'i32_list'           : [-1, 0, 0xff, 0xffff, 0xffffff, 0x7fffffff],
+  'i64_list'           : [-1, 0, 0xff, 0xffff, 0xffffff, 0xffffffff, 0xffffffffff, 0xffffffffffff, 0xffffffffffffff, 0x7fffffffffffffff],
+  'double_list'        : [0.1, 0.2, 0.3],
+  'string_list'        : ["first", "second", "third"],
+//'binary_list,'
+  'boolean_list'       : [1, 1, 1, 0, 0, 0],
+  'struct_list'        : [{}, {}],
+  'byte_set'           : [-127, -1, 0, 1, 127],
+  'i16_set'            : [-1, 0, 1, 0x7fff],
+  'i32_set'            : [1, 2, 3],
+  'i64_set'            : [-1, 0, 0xff, 0xffff, 0xffffff, 0xffffffff, 0xffffffffff, 0xffffffffffff, 0xffffffffffffff, 0x7fffffffffffffff],
+  'double_set'         : [0.1, 0.2, 0.3],
+  'string_set'         : ["first", "second", "third"],
+//'binary_set,'
+  'boolean_set'        : [1, 0],
+  'struct_set'         : [{}],
+  'byte_byte_map'      : {1 : 2},
+  'i16_byte_map'       : {1 : 1, -1 : 1, 0x7fff : 1},
+  'i32_byte_map'       : {1 : 1, -1 : 1, 0x7fffffff : 1},
+  'i64_byte_map'       : {0 : 1,  1 : 1, -1 : 1, 0x7fffffffffffffff : 1},
+  'double_byte_map'    : {-1.1 : 1, 1.1 : 1},
+  'string_byte_map'    : {"first" : 1, "second" : 2, "third" : 3, "" : 0},
+//'binary_byte_map,'
+  'boolean_byte_map'   : {1 : 1, 0 : 0},
+  'byte_i16_map'       : {1 : 1, 2 : -1, 3 : 0x7fff},
+  'byte_i32_map'       : {1 : 1, 2 : -1, 3 : 0x7fffffff},
+  'byte_i64_map'       : {1 : 1, 2 : -1, 3 : 0x7fffffffffffffff},
+  'byte_double_map'    : {1 : 0.1, 2 : -0.1, 3 : 1000000.1},
+  'byte_string_map'    : {1 : "", 2 : "blah", 3 : "loooooooooooooong string"},
+//'byte_binary_map,'
+  'byte_boolean_map'   : {1 : 1, 2 : 0},
+  'list_byte_map'      : {[1, 2, 3] : 1, [0, 1] : 2, [] : 0},
+  'set_byte_map'       : {[1, 2, 3] : 1, [0, 1] : 2, [] : 0},
+  'map_byte_map'       : {{1 : 1} : 1, {2 : 2} : 2, {} : 0},
+  'byte_map_map'       : {0 : {}, 1 : {1 : 1}, 2 : {1 : 1, 2 : 2}},
+  'byte_set_map'       : {0 : [], 1 : [1], 2 : [1, 2]},
+  'byte_list_map'      : {0 : [], 1 : [1], 2 : [1, 2]},
+}
+
+
+
+service Srv {
+  i32 Janky(1: i32 arg);
+  
+  // return type only methods
+  
+  void voidMethod();
+  i32 primitiveMethod();
+  CompactProtoTestStruct structMethod();
+}
+
+service Inherited extends Srv {
+  i32 identity(1: i32 arg)
+}
+
+service EmptyService {}
+
+// The only purpose of this thing is to increase the size of the generated code
+// so that ZlibTest has more highly compressible data to play with.
+struct BlowUp {
+  1: map<list<i32>,set<map<i32,string>>> b1;
+  2: map<list<i32>,set<map<i32,string>>> b2;
+  3: map<list<i32>,set<map<i32,string>>> b3;
+  4: map<list<i32>,set<map<i32,string>>> b4;
+}
+
+
+struct ReverseOrderStruct {
+  4: string first;
+  3: i16 second;
+  2: i32 third;
+  1: i64 fourth;
+}
+
+service ReverseOrderService {
+  void myMethod(4: string first, 3: i16 second, 2: i32 third, 1: i64 fourth);
+}
\ No newline at end of file
diff --git a/test/DebugProtoTest_extras.cpp b/test/DebugProtoTest_extras.cpp
new file mode 100644
index 0000000..e68c544
--- /dev/null
+++ b/test/DebugProtoTest_extras.cpp
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+// Extra functions required for DebugProtoTest_types to work
+
+#include "gen-cpp/DebugProtoTest_types.h"
+
+
+namespace thrift { namespace test { namespace debug {
+
+bool Empty::operator<(Empty const& other) const {
+  // It is empty, so all are equal.
+  return false;
+}
+
+}}}
diff --git a/test/DenseLinkingTest.thrift b/test/DenseLinkingTest.thrift
new file mode 100644
index 0000000..cf61496
--- /dev/null
+++ b/test/DenseLinkingTest.thrift
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+/*
+../compiler/cpp/thrift -gen cpp:dense DebugProtoTest.thrift
+../compiler/cpp/thrift -gen cpp:dense DenseLinkingTest.thrift
+g++ -Wall -g -I../lib/cpp/src -I/usr/local/include/boost-1_33_1 \
+  DebugProtoTest.cpp gen-cpp/DebugProtoTest_types.cpp \
+  gen-cpp/DenseLinkingTest_types.cpp \
+  ../lib/cpp/.libs/libthrift.a -o DebugProtoTest
+./DebugProtoTest
+*/
+
+/*
+The idea of this test is that everything is structurally identical to DebugProtoTest.
+If I messed up the naming of the reflection local typespecs,
+then compiling this should give errors because of doubly defined symbols.
+*/
+
+namespace cpp thrift.test
+
+struct OneOfEachZZ {
+  1: bool im_true,
+  2: bool im_false,
+  3: byte a_bite,
+  4: i16 integer16,
+  5: i32 integer32,
+  6: i64 integer64,
+  7: double double_precision,
+  8: string some_characters,
+  9: string zomg_unicode,
+  10: bool what_who,
+}
+
+struct BonkZZ {
+  1: i32 type,
+  2: string message,
+}
+
+struct NestingZZ {
+  1: BonkZZ my_bonk,
+  2: OneOfEachZZ my_ooe,
+}
+
+struct HolyMoleyZZ {
+  1: list<OneOfEachZZ> big,
+  2: set<list<string>> contain,
+  3: map<string,list<BonkZZ>> bonks,
+}
+
+struct BackwardsZZ {
+  2: i32 first_tag2,
+  1: i32 second_tag1,
+}
+
+struct EmptyZZ {
+}
+
+struct WrapperZZ {
+  1: EmptyZZ foo
+}
+
+struct RandomStuffZZ {
+  1: i32 a,
+  2: i32 b,
+  3: i32 c,
+  4: i32 d,
+  5: list<i32> myintlist,
+  6: map<i32,WrapperZZ> maps,
+  7: i64 bigint,
+  8: double triple,
+}
+
+service Srv {
+  i32 Janky(1: i32 arg)
+}
diff --git a/test/DenseProtoTest.cpp b/test/DenseProtoTest.cpp
new file mode 100644
index 0000000..99f7865
--- /dev/null
+++ b/test/DenseProtoTest.cpp
@@ -0,0 +1,384 @@
+/*
+ * 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.
+ */
+
+/*
+../compiler/cpp/thrift --gen cpp:dense DebugProtoTest.thrift
+../compiler/cpp/thrift --gen cpp:dense OptionalRequiredTest.thrift
+g++ -Wall -g -I../lib/cpp/src -I/usr/local/include/boost-1_33_1 \
+  gen-cpp/OptionalRequiredTest_types.cpp \
+  gen-cpp/DebugProtoTest_types.cpp \
+  DenseProtoTest.cpp ../lib/cpp/.libs/libthrift.a -o DenseProtoTest
+./DenseProtoTest
+*/
+
+// I do this to reach into the guts of TDenseProtocol.  Sorry.
+#define private public
+#define inline
+
+#undef NDEBUG
+#include <cstdlib>
+#include <cassert>
+#include <iostream>
+#include <cmath>
+#include <string>
+#include "gen-cpp/DebugProtoTest_types.h"
+#include "gen-cpp/OptionalRequiredTest_types.h"
+#include <protocol/TDenseProtocol.h>
+#include <transport/TBufferTransports.h>
+
+
+// Can't use memcmp here.  GCC is too smart.
+bool my_memeq(const char* str1, const char* str2, int len) {
+  for (int i = 0; i < len; i++) {
+    if (str1[i] != str2[i]) {
+      return false;
+    }
+  }
+  return true;
+}
+
+
+int main() {
+  using std::string;
+  using std::cout;
+  using std::endl;
+  using boost::shared_ptr;
+  using namespace thrift::test::debug;
+  using namespace apache::thrift::transport;
+  using namespace apache::thrift::protocol;
+
+
+  OneOfEach ooe;
+  ooe.im_true   = true;
+  ooe.im_false  = false;
+  ooe.a_bite    = 0xd6;
+  ooe.integer16 = 27000;
+  ooe.integer32 = 1<<24;
+  ooe.integer64 = (uint64_t)6000 * 1000 * 1000;
+  ooe.double_precision = M_PI;
+  ooe.some_characters  = "Debug THIS!";
+  ooe.zomg_unicode     = "\xd7\n\a\t";
+
+  //cout << apache::thrift::ThriftDebugString(ooe) << endl << endl;
+
+
+  Nesting n;
+  n.my_ooe = ooe;
+  n.my_ooe.integer16 = 16;
+  n.my_ooe.integer32 = 32;
+  n.my_ooe.integer64 = 64;
+  n.my_ooe.double_precision = (std::sqrt(5)+1)/2;
+  n.my_ooe.some_characters  = ":R (me going \"rrrr\")";
+  n.my_ooe.zomg_unicode     = "\xd3\x80\xe2\x85\xae\xce\x9d\x20"
+                              "\xd0\x9d\xce\xbf\xe2\x85\xbf\xd0\xbe\xc9\xa1\xd0\xb3\xd0\xb0\xcf\x81\xe2\x84\x8e"
+                              "\x20\xce\x91\x74\x74\xce\xb1\xe2\x85\xbd\xce\xba\xc7\x83\xe2\x80\xbc";
+  n.my_bonk.type    = 31337;
+  n.my_bonk.message = "I am a bonk... xor!";
+
+  //cout << apache::thrift::ThriftDebugString(n) << endl << endl;
+
+
+  HolyMoley hm;
+
+  hm.big.push_back(ooe);
+  hm.big.push_back(n.my_ooe);
+  hm.big[0].a_bite = 0x22;
+  hm.big[1].a_bite = 0x33;
+
+  std::vector<std::string> stage1;
+  stage1.push_back("and a one");
+  stage1.push_back("and a two");
+  hm.contain.insert(stage1);
+  stage1.clear();
+  stage1.push_back("then a one, two");
+  stage1.push_back("three!");
+  stage1.push_back("FOUR!!");
+  hm.contain.insert(stage1);
+  stage1.clear();
+  hm.contain.insert(stage1);
+
+  std::vector<Bonk> stage2;
+  hm.bonks["nothing"] = stage2;
+  stage2.resize(stage2.size()+1);
+  stage2.back().type = 1;
+  stage2.back().message = "Wait.";
+  stage2.resize(stage2.size()+1);
+  stage2.back().type = 2;
+  stage2.back().message = "What?";
+  hm.bonks["something"] = stage2;
+  stage2.clear();
+  stage2.resize(stage2.size()+1);
+  stage2.back().type = 3;
+  stage2.back().message = "quoth";
+  stage2.resize(stage2.size()+1);
+  stage2.back().type = 4;
+  stage2.back().message = "the raven";
+  stage2.resize(stage2.size()+1);
+  stage2.back().type = 5;
+  stage2.back().message = "nevermore";
+  hm.bonks["poe"] = stage2;
+
+  //cout << apache::thrift::ThriftDebugString(hm) << endl << endl;
+
+  shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer());
+  shared_ptr<TDenseProtocol> proto(new TDenseProtocol(buffer));
+  proto->setTypeSpec(HolyMoley::local_reflection);
+
+  hm.write(proto.get());
+  HolyMoley hm2;
+  hm2.read(proto.get());
+
+  assert(hm == hm2);
+
+
+  // Let's test out the variable-length ints, shall we?
+  uint64_t vlq;
+  #define checkout(i, c) { \
+    buffer->resetBuffer(); \
+    proto->vlqWrite(i); \
+    proto->getTransport()->flush(); \
+    assert(my_memeq(buffer->getBufferAsString().data(), c, sizeof(c)-1)); \
+    proto->vlqRead(vlq); \
+    assert(vlq == i); \
+  }
+
+  checkout(0x00000000, "\x00");
+  checkout(0x00000040, "\x40");
+  checkout(0x0000007F, "\x7F");
+  checkout(0x00000080, "\x81\x00");
+  checkout(0x00002000, "\xC0\x00");
+  checkout(0x00003FFF, "\xFF\x7F");
+  checkout(0x00004000, "\x81\x80\x00");
+  checkout(0x00100000, "\xC0\x80\x00");
+  checkout(0x001FFFFF, "\xFF\xFF\x7F");
+  checkout(0x00200000, "\x81\x80\x80\x00");
+  checkout(0x08000000, "\xC0\x80\x80\x00");
+  checkout(0x0FFFFFFF, "\xFF\xFF\xFF\x7F");
+  checkout(0x10000000, "\x81\x80\x80\x80\x00");
+  checkout(0x20000000, "\x82\x80\x80\x80\x00");
+  checkout(0x1FFFFFFF, "\x81\xFF\xFF\xFF\x7F");
+  checkout(0xFFFFFFFF, "\x8F\xFF\xFF\xFF\x7F");
+
+  checkout(0x0000000100000000ull, "\x90\x80\x80\x80\x00");
+  checkout(0x0000000200000000ull, "\xA0\x80\x80\x80\x00");
+  checkout(0x0000000300000000ull, "\xB0\x80\x80\x80\x00");
+  checkout(0x0000000700000000ull, "\xF0\x80\x80\x80\x00");
+  checkout(0x00000007F0000000ull, "\xFF\x80\x80\x80\x00");
+  checkout(0x00000007FFFFFFFFull, "\xFF\xFF\xFF\xFF\x7F");
+  checkout(0x0000000800000000ull, "\x81\x80\x80\x80\x80\x00");
+  checkout(0x1FFFFFFFFFFFFFFFull, "\x9F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F");
+  checkout(0x7FFFFFFFFFFFFFFFull, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F");
+  checkout(0xFFFFFFFFFFFFFFFFull, "\x81\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F");
+
+  // Test out the slow path with a TBufferedTransport.
+  shared_ptr<TBufferedTransport> buff_trans(new TBufferedTransport(buffer, 3));
+  proto.reset(new TDenseProtocol(buff_trans));
+  checkout(0x0000000100000000ull, "\x90\x80\x80\x80\x00");
+  checkout(0x0000000200000000ull, "\xA0\x80\x80\x80\x00");
+  checkout(0x0000000300000000ull, "\xB0\x80\x80\x80\x00");
+  checkout(0x0000000700000000ull, "\xF0\x80\x80\x80\x00");
+  checkout(0x00000007F0000000ull, "\xFF\x80\x80\x80\x00");
+  checkout(0x00000007FFFFFFFFull, "\xFF\xFF\xFF\xFF\x7F");
+  checkout(0x0000000800000000ull, "\x81\x80\x80\x80\x80\x00");
+  checkout(0x1FFFFFFFFFFFFFFFull, "\x9F\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F");
+  checkout(0x7FFFFFFFFFFFFFFFull, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F");
+  checkout(0xFFFFFFFFFFFFFFFFull, "\x81\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F");
+
+  // Test optional stuff.
+  proto.reset(new TDenseProtocol(buffer));
+  proto->setTypeSpec(ManyOpt::local_reflection);
+  ManyOpt mo1, mo2, mo3, mo4, mo5, mo6;
+  mo1.opt1 = 923759347;
+  mo1.opt2 = 392749274;
+  mo1.opt3 = 395739402;
+  mo1.def4 = 294730928;
+  mo1.opt5 = 394309218;
+  mo1.opt6 = 832194723;
+  mo1.__isset.opt1 = true;
+  mo1.__isset.opt2 = true;
+  mo1.__isset.opt3 = true;
+  mo1.__isset.def4 = true;
+  mo1.__isset.opt5 = true;
+  mo1.__isset.opt6 = true;
+
+  mo1.write(proto.get());
+  mo2.read(proto.get());
+
+  assert(mo2.__isset.opt1 == true);
+  assert(mo2.__isset.opt2 == true);
+  assert(mo2.__isset.opt3 == true);
+  assert(mo2.__isset.def4 == true);
+  assert(mo2.__isset.opt5 == true);
+  assert(mo2.__isset.opt6 == true);
+
+  assert(mo1 == mo2);
+
+  mo1.__isset.opt1 = false;
+  mo1.__isset.opt3 = false;
+  mo1.__isset.opt5 = false;
+
+  mo1.write(proto.get());
+  mo3.read(proto.get());
+
+  assert(mo3.__isset.opt1 == false);
+  assert(mo3.__isset.opt2 == true);
+  assert(mo3.__isset.opt3 == false);
+  assert(mo3.__isset.def4 == true);
+  assert(mo3.__isset.opt5 == false);
+  assert(mo3.__isset.opt6 == true);
+
+  assert(mo1 == mo3);
+
+  mo1.__isset.opt1 = true;
+  mo1.__isset.opt3 = true;
+  mo1.__isset.opt5 = true;
+  mo1.__isset.opt2 = false;
+  mo1.__isset.opt6 = false;
+
+  mo1.write(proto.get());
+  mo4.read(proto.get());
+
+  assert(mo4.__isset.opt1 == true);
+  assert(mo4.__isset.opt2 == false);
+  assert(mo4.__isset.opt3 == true);
+  assert(mo4.__isset.def4 == true);
+  assert(mo4.__isset.opt5 == true);
+  assert(mo4.__isset.opt6 == false);
+
+  assert(mo1 == mo4);
+
+  mo1.__isset.opt1 = false;
+  mo1.__isset.opt5 = false;
+
+  mo1.write(proto.get());
+  mo5.read(proto.get());
+
+  assert(mo5.__isset.opt1 == false);
+  assert(mo5.__isset.opt2 == false);
+  assert(mo5.__isset.opt3 == true);
+  assert(mo5.__isset.def4 == true);
+  assert(mo5.__isset.opt5 == false);
+  assert(mo5.__isset.opt6 == false);
+
+  assert(mo1 == mo5);
+
+  mo1.__isset.opt3 = false;
+
+  mo1.write(proto.get());
+  mo6.read(proto.get());
+
+  assert(mo6.__isset.opt1 == false);
+  assert(mo6.__isset.opt2 == false);
+  assert(mo6.__isset.opt3 == false);
+  assert(mo6.__isset.def4 == true);
+  assert(mo6.__isset.opt5 == false);
+  assert(mo6.__isset.opt6 == false);
+
+  assert(mo1 == mo6);
+
+
+  // Test fingerprint checking stuff.
+
+  {
+    // Default and required have the same fingerprint.
+    Tricky1 t1;
+    Tricky3 t3;
+    assert(string(Tricky1::ascii_fingerprint) == Tricky3::ascii_fingerprint);
+    proto->setTypeSpec(Tricky1::local_reflection);
+    t1.im_default = 227;
+    t1.write(proto.get());
+    proto->setTypeSpec(Tricky3::local_reflection);
+    t3.read(proto.get());
+    assert(t3.im_required == 227);
+  }
+
+  {
+    // Optional changes things.
+    Tricky1 t1;
+    Tricky2 t2;
+    assert(string(Tricky1::ascii_fingerprint) != Tricky2::ascii_fingerprint);
+    proto->setTypeSpec(Tricky1::local_reflection);
+    t1.im_default = 227;
+    t1.write(proto.get());
+    try {
+      proto->setTypeSpec(Tricky2::local_reflection);
+      t2.read(proto.get());
+      assert(false);
+    } catch (TProtocolException& ex) {
+      buffer->resetBuffer();
+    }
+  }
+
+  {
+    // Holy cow.  We can use the Tricky1 typespec with the Tricky2 structure.
+    Tricky1 t1;
+    Tricky2 t2;
+    proto->setTypeSpec(Tricky1::local_reflection);
+    t1.im_default = 227;
+    t1.write(proto.get());
+    t2.read(proto.get());
+    assert(t2.__isset.im_optional == true);
+    assert(t2.im_optional == 227);
+  }
+
+  {
+    // And totally off the wall.
+    Tricky1 t1;
+    OneOfEach ooe2;
+    assert(string(Tricky1::ascii_fingerprint) != OneOfEach::ascii_fingerprint);
+    proto->setTypeSpec(Tricky1::local_reflection);
+    t1.im_default = 227;
+    t1.write(proto.get());
+    try {
+      proto->setTypeSpec(OneOfEach::local_reflection);
+      ooe2.read(proto.get());
+      assert(false);
+    } catch (TProtocolException& ex) {
+      buffer->resetBuffer();
+    }
+  }
+
+  // Okay, this is really off the wall.
+  // Just don't crash.
+  cout << "Starting fuzz test.  This takes a while.  (20 dots.)" << endl;
+  std::srand(12345);
+  for (int i = 0; i < 2000; i++) {
+    if (i % 100 == 0) {
+      cout << ".";
+      cout.flush();
+    }
+    buffer->resetBuffer();
+    // Make sure the fingerprint prefix is right.
+    buffer->write(Nesting::binary_fingerprint, 4);
+    for (int j = 0; j < 1024*1024; j++) {
+      uint8_t r = std::rand();
+      buffer->write(&r, 1);
+    }
+    Nesting n;
+    proto->setTypeSpec(OneOfEach::local_reflection);
+    try {
+      n.read(proto.get());
+    } catch (TProtocolException& ex) {
+    } catch (TTransportException& ex) {
+    }
+  }
+  cout << endl;
+
+  return 0;
+}
diff --git a/test/DocTest.thrift b/test/DocTest.thrift
new file mode 100644
index 0000000..cb355ae
--- /dev/null
+++ b/test/DocTest.thrift
@@ -0,0 +1,247 @@
+/*
+ * 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.
+ */
+
+/**
+ * Program doctext.
+ *
+ * Seriously, this is the documentation for this whole program.
+ */
+
+namespace java thrift.test
+namespace cpp thrift.test
+
+// C++ comment
+/* c style comment */
+
+# the new unix comment
+
+/** Some doc text goes here.  Wow I am [nesting these] (no more nesting.) */
+enum Numberz
+{
+
+  /** This is how to document a parameter */
+  ONE = 1,
+
+  /** And this is a doc for a parameter that has no specific value assigned */
+  TWO,
+
+  THREE,
+  FIVE = 5,
+  SIX,
+  EIGHT = 8
+}
+
+/** This is how you would do a typedef doc */
+typedef i64 UserId
+
+/** And this is where you would document a struct */
+struct Xtruct
+{
+
+  /** And the members of a struct */
+  1:  string string_thing
+
+  /** doct text goes before a comma */
+  4:  byte   byte_thing,
+
+  9:  i32    i32_thing,
+  11: i64    i64_thing
+}
+
+/**
+ * You can document constants now too.  Yeehaw!
+ */
+const i32 INT32CONSTANT = 9853
+const i16 INT16CONSTANT = 1616
+/** Everyone get in on the docu-action! */
+const map<string,string> MAPCONSTANT = {'hello':'world', 'goodnight':'moon'}
+
+struct Xtruct2
+{
+  1: byte   byte_thing,
+  2: Xtruct struct_thing,
+  3: i32    i32_thing
+}
+
+/** Struct insanity */
+struct Insanity
+{
+
+  /** This is doc for field 1 */
+  1: map<Numberz, UserId> userMap,
+
+  /** And this is doc for field 2 */
+  2: list<Xtruct> xtructs
+}
+
+exception Xception {
+  1: i32 errorCode,
+  2: string message
+}
+
+exception Xception2 {
+  1: i32 errorCode,
+  2: Xtruct struct_thing
+}
+
+/* C1 */
+/** Doc */
+/* C2 */
+/* C3 */
+struct EmptyStruct {}
+
+struct OneField {
+  1: EmptyStruct field
+}
+
+/** This is where you would document a Service */
+service ThriftTest
+{
+
+  /** And this is how you would document functions in a service */
+  void         testVoid(),
+  string       testString(1: string thing),
+  byte         testByte(1: byte thing),
+  i32          testI32(1: i32 thing),
+
+  /** Like this one */
+  i64          testI64(1: i64 thing),
+  double       testDouble(1: double thing),
+  Xtruct       testStruct(1: Xtruct thing),
+  Xtruct2      testNest(1: Xtruct2 thing),
+  map<i32,i32> testMap(1: map<i32,i32> thing),
+  set<i32>     testSet(1: set<i32> thing),
+  list<i32>    testList(1: list<i32> thing),
+
+  /** This is an example of a function with params documented */
+  Numberz      testEnum(
+
+    /** This param is a thing */
+    1: Numberz thing
+
+  ),
+
+  UserId       testTypedef(1: UserId thing),
+
+  map<i32,map<i32,i32>> testMapMap(1: i32 hello),
+
+  /* So you think you've got this all worked, out eh? */
+  map<UserId, map<Numberz,Insanity>> testInsanity(1: Insanity argument),
+
+}
+
+/// This style of Doxy-comment doesn't work.
+typedef i32 SorryNoGo
+
+/**
+ * This is a trivial example of a multiline docstring.
+ */
+typedef i32 TrivialMultiLine
+
+/**
+ * This is the cannonical example
+ * of a multiline docstring.
+ */
+typedef i32 StandardMultiLine
+
+/**
+ * The last line is non-blank.
+ * I said non-blank! */
+typedef i32 LastLine
+
+/** Both the first line
+ * are non blank. ;-)
+ * and the last line */
+typedef i32 FirstAndLastLine
+
+/**
+ *    INDENTED TITLE
+ * The text is less indented.
+ */
+typedef i32 IndentedTitle
+
+/**       First line indented.
+ * Unfortunately, this does not get indented.
+ */
+typedef i32 FirstLineIndent
+
+
+/**
+ * void code_in_comment() {
+ *   printf("hooray code!");
+ * }
+ */
+typedef i32 CodeInComment
+
+    /**
+     * Indented Docstring.
+     * This whole docstring is indented.
+     *   This line is indented further.
+     */
+typedef i32 IndentedDocstring
+
+/** Irregular docstring.
+ * We will have to punt
+  * on this thing */
+typedef i32 Irregular1
+
+/**
+ * note the space
+ * before these lines
+* but not this
+ * one
+ */
+typedef i32 Irregular2
+
+/**
+* Flush against
+* the left.
+*/
+typedef i32 Flush
+
+/**
+  No stars in this one.
+  It should still work fine, though.
+    Including indenting.
+    */
+typedef i32 NoStars
+
+/** Trailing whitespace   
+Sloppy trailing whitespace   
+is truncated.   */
+typedef i32 TrailingWhitespace
+
+/**
+ * This is a big one.
+ *
+ * We'll have some blank lines in it.
+ * 
+ * void as_well_as(some code) {
+ *   puts("YEEHAW!");
+ * }
+ */
+typedef i32 BigDog
+
+/**
+*
+*
+*/
+typedef i32 TotallyDegenerate
+
+/* THE END */
diff --git a/test/FastbinaryTest.py b/test/FastbinaryTest.py
new file mode 100755
index 0000000..7f6efae
--- /dev/null
+++ b/test/FastbinaryTest.py
@@ -0,0 +1,222 @@
+#!/usr/bin/env python
+
+#
+# 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.
+#
+
+r"""
+thrift --gen py DebugProtoTest.thrift
+./FastbinaryTest.py
+"""
+
+# TODO(dreiss): Test error cases.  Check for memory leaks.
+
+import sys
+sys.path.append('./gen-py')
+
+import math
+from DebugProtoTest import Srv
+from DebugProtoTest.ttypes import *
+from thrift.transport import TTransport
+from thrift.protocol import TBinaryProtocol
+
+import timeit
+from cStringIO import StringIO
+from copy import deepcopy
+from pprint import pprint
+
+class TDevNullTransport(TTransport.TTransportBase):
+  def __init__(self):
+    pass
+  def isOpen(self):
+    return True
+
+ooe1 = OneOfEach()
+ooe1.im_true   = True;
+ooe1.im_false  = False;
+ooe1.a_bite    = 0xd6;
+ooe1.integer16 = 27000;
+ooe1.integer32 = 1<<24;
+ooe1.integer64 = 6000 * 1000 * 1000;
+ooe1.double_precision = math.pi;
+ooe1.some_characters  = "Debug THIS!";
+ooe1.zomg_unicode     = "\xd7\n\a\t";
+
+ooe2 = OneOfEach();
+ooe2.integer16 = 16;
+ooe2.integer32 = 32;
+ooe2.integer64 = 64;
+ooe2.double_precision = (math.sqrt(5)+1)/2;
+ooe2.some_characters  = ":R (me going \"rrrr\")";
+ooe2.zomg_unicode     = "\xd3\x80\xe2\x85\xae\xce\x9d\x20"\
+                        "\xd0\x9d\xce\xbf\xe2\x85\xbf\xd0\xbe"\
+                        "\xc9\xa1\xd0\xb3\xd0\xb0\xcf\x81\xe2\x84\x8e"\
+                        "\x20\xce\x91\x74\x74\xce\xb1\xe2\x85\xbd\xce\xba"\
+                        "\xc7\x83\xe2\x80\xbc";
+
+hm = HolyMoley({"big":[], "contain":set(), "bonks":{}})
+hm.big.append(ooe1)
+hm.big.append(ooe2)
+hm.big[0].a_bite = 0x22;
+hm.big[1].a_bite = 0x22;
+
+hm.contain.add(("and a one", "and a two"))
+hm.contain.add(("then a one, two", "three!", "FOUR!"))
+hm.contain.add(())
+
+hm.bonks["nothing"] = [];
+hm.bonks["something"] = [
+  Bonk({"type":1, "message":"Wait."}),
+  Bonk({"type":2, "message":"What?"}),
+]
+hm.bonks["poe"] = [
+  Bonk({"type":3, "message":"quoth"}),
+  Bonk({"type":4, "message":"the raven"}),
+  Bonk({"type":5, "message":"nevermore"}),
+]
+
+rs = RandomStuff()
+rs.a = 1
+rs.b = 2
+rs.c = 3
+rs.myintlist = range(20)
+rs.maps = {1:Wrapper({"foo":Empty()}),2:Wrapper({"foo":Empty()})}
+rs.bigint = 124523452435L
+rs.triple = 3.14
+
+# make sure this splits two buffers in a buffered protocol
+rshuge = RandomStuff()
+rshuge.myintlist=range(10000)
+
+my_zero = Srv.Janky_result({"arg":5})
+
+def checkWrite(o):
+  trans_fast = TTransport.TMemoryBuffer()
+  trans_slow = TTransport.TMemoryBuffer()
+  prot_fast = TBinaryProtocol.TBinaryProtocolAccelerated(trans_fast)
+  prot_slow = TBinaryProtocol.TBinaryProtocol(trans_slow)
+
+  o.write(prot_fast)
+  o.write(prot_slow)
+  ORIG = trans_slow.getvalue()
+  MINE = trans_fast.getvalue()
+  if ORIG != MINE:
+    print "mine: %s\norig: %s" % (repr(MINE), repr(ORIG))
+
+def checkRead(o):
+  prot = TBinaryProtocol.TBinaryProtocol(TTransport.TMemoryBuffer())
+  o.write(prot)
+
+  slow_version_binary = prot.trans.getvalue()
+
+  prot = TBinaryProtocol.TBinaryProtocolAccelerated(
+           TTransport.TMemoryBuffer(slow_version_binary))
+  c = o.__class__()
+  c.read(prot)
+  if c != o:
+    print "copy: "
+    pprint(eval(repr(c)))
+    print "orig: "
+    pprint(eval(repr(o)))
+
+  prot = TBinaryProtocol.TBinaryProtocolAccelerated(
+           TTransport.TBufferedTransport(
+             TTransport.TMemoryBuffer(slow_version_binary)))
+  c = o.__class__()
+  c.read(prot)
+  if c != o:
+    print "copy: "
+    pprint(eval(repr(c)))
+    print "orig: "
+    pprint(eval(repr(o)))
+
+
+def doTest():
+  checkWrite(hm)
+  no_set = deepcopy(hm)
+  no_set.contain = set()
+  checkRead(no_set)
+  checkWrite(rs)
+  checkRead(rs)
+  checkWrite(rshuge)
+  checkRead(rshuge)
+  checkWrite(my_zero)
+  checkRead(my_zero)
+  checkRead(Backwards({"first_tag2":4, "second_tag1":2}))
+
+  # One case where the serialized form changes, but only superficially.
+  o = Backwards({"first_tag2":4, "second_tag1":2})
+  trans_fast = TTransport.TMemoryBuffer()
+  trans_slow = TTransport.TMemoryBuffer()
+  prot_fast = TBinaryProtocol.TBinaryProtocolAccelerated(trans_fast)
+  prot_slow = TBinaryProtocol.TBinaryProtocol(trans_slow)
+
+  o.write(prot_fast)
+  o.write(prot_slow)
+  ORIG = trans_slow.getvalue()
+  MINE = trans_fast.getvalue()
+  if ORIG == MINE:
+    print "That shouldn't happen."
+
+
+  prot = TBinaryProtocol.TBinaryProtocolAccelerated(TTransport.TMemoryBuffer())
+  o.write(prot)
+  prot = TBinaryProtocol.TBinaryProtocol(
+           TTransport.TMemoryBuffer(
+             prot.trans.getvalue()))
+  c = o.__class__()
+  c.read(prot)
+  if c != o:
+    print "copy: "
+    pprint(eval(repr(c)))
+    print "orig: "
+    pprint(eval(repr(o)))
+
+
+
+def doBenchmark():
+
+  iters = 25000
+
+  setup = """
+from __main__ import hm, rs, TDevNullTransport
+from thrift.protocol import TBinaryProtocol
+trans = TDevNullTransport()
+prot = TBinaryProtocol.TBinaryProtocol%s(trans)
+"""
+
+  setup_fast = setup % "Accelerated"
+  setup_slow = setup % ""
+
+  print "Starting Benchmarks"
+
+  print "HolyMoley Standard = %f" % \
+      timeit.Timer('hm.write(prot)', setup_slow).timeit(number=iters)
+  print "HolyMoley Acceler. = %f" % \
+      timeit.Timer('hm.write(prot)', setup_fast).timeit(number=iters)
+
+  print "FastStruct Standard = %f" % \
+      timeit.Timer('rs.write(prot)', setup_slow).timeit(number=iters)
+  print "FastStruct Acceler. = %f" % \
+      timeit.Timer('rs.write(prot)', setup_fast).timeit(number=iters)
+
+
+
+doTest()
+doBenchmark()
+
diff --git a/test/GenericHelpers.h b/test/GenericHelpers.h
new file mode 100644
index 0000000..d661d8b
--- /dev/null
+++ b/test/GenericHelpers.h
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+
+#ifndef _THRIFT_TEST_GENERICHELPERS_H_
+#define _THRIFT_TEST_GENERICHELPERS_H_ 1
+
+#include <protocol/TBinaryProtocol.h>
+#include <transport/TBufferTransports.h>
+#include <Thrift.h>
+
+using boost::shared_ptr;
+using namespace apache::thrift::protocol;
+
+/* ClassName Helper for cleaner exceptions */
+class ClassNames {
+ public:
+  template <typename T>
+  static const char* getName() { return "Unknown type"; }
+};
+
+template <> const char* ClassNames::getName<int8_t>() { return "byte"; }
+template <> const char* ClassNames::getName<int16_t>() { return "short"; }
+template <> const char* ClassNames::getName<int32_t>() { return "int"; }
+template <> const char* ClassNames::getName<int64_t>() { return "long"; }
+template <> const char* ClassNames::getName<double>() { return "double"; }
+template <> const char* ClassNames::getName<std::string>() { return "string"; }
+
+/* Generic Protocol I/O function for tests */
+class GenericIO {
+ public:
+
+  /* Write functions */
+
+  static uint32_t write(shared_ptr<TProtocol> proto, const int8_t& val) {
+    return proto->writeByte(val);
+  }
+
+  static uint32_t write(shared_ptr<TProtocol> proto, const int16_t& val) {
+    return proto->writeI16(val);
+  }
+
+  static uint32_t write(shared_ptr<TProtocol> proto, const int32_t& val) {
+    return proto->writeI32(val);
+  }
+
+  static uint32_t write(shared_ptr<TProtocol> proto, const double& val) {
+    return proto->writeDouble(val);
+  }
+
+  static uint32_t write(shared_ptr<TProtocol> proto, const int64_t& val) {
+    return proto->writeI64(val);
+  }
+
+  static uint32_t write(shared_ptr<TProtocol> proto, const std::string& val) {
+    return proto->writeString(val);
+  }
+
+  /* Read functions */
+
+  static uint32_t read(shared_ptr<TProtocol> proto, int8_t& val) {
+    return proto->readByte(val);
+  }
+
+  static uint32_t read(shared_ptr<TProtocol> proto, int16_t& val) {
+    return proto->readI16(val);
+  }
+
+  static uint32_t read(shared_ptr<TProtocol> proto, int32_t& val) {
+    return proto->readI32(val);
+  }
+
+  static uint32_t read(shared_ptr<TProtocol> proto, int64_t& val) {
+    return proto->readI64(val);
+  }
+
+  static uint32_t read(shared_ptr<TProtocol> proto, double& val) {
+    return proto->readDouble(val);
+  }
+
+  static uint32_t read(shared_ptr<TProtocol> proto, std::string& val) {
+    return proto->readString(val);
+  }
+
+};
+
+#endif
diff --git a/test/JSONProtoTest.cpp b/test/JSONProtoTest.cpp
new file mode 100644
index 0000000..6681356
--- /dev/null
+++ b/test/JSONProtoTest.cpp
@@ -0,0 +1,159 @@
+/*
+ * 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.
+ */
+
+#include <iostream>
+#include <cmath>
+#include <transport/TBufferTransports.h>
+#include <protocol/TJSONProtocol.h>
+#include "gen-cpp/DebugProtoTest_types.h"
+
+int main() {
+  using std::cout;
+  using std::endl;
+  using namespace thrift::test::debug;
+  using apache::thrift::transport::TMemoryBuffer;
+  using apache::thrift::protocol::TJSONProtocol;
+
+  OneOfEach ooe;
+  ooe.im_true   = true;
+  ooe.im_false  = false;
+  ooe.a_bite    = 0xd6;
+  ooe.integer16 = 27000;
+  ooe.integer32 = 1<<24;
+  ooe.integer64 = (uint64_t)6000 * 1000 * 1000;
+  ooe.double_precision = M_PI;
+  ooe.some_characters  = "JSON THIS! \"\1";
+  ooe.zomg_unicode     = "\xd7\n\a\t";
+  ooe.base64 = "\1\2\3\255";
+  cout << apache::thrift::ThriftJSONString(ooe) << endl << endl;
+
+
+  Nesting n;
+  n.my_ooe = ooe;
+  n.my_ooe.integer16 = 16;
+  n.my_ooe.integer32 = 32;
+  n.my_ooe.integer64 = 64;
+  n.my_ooe.double_precision = (std::sqrt(5)+1)/2;
+  n.my_ooe.some_characters  = ":R (me going \"rrrr\")";
+  n.my_ooe.zomg_unicode     = "\xd3\x80\xe2\x85\xae\xce\x9d\x20"
+                              "\xd0\x9d\xce\xbf\xe2\x85\xbf\xd0\xbe\xc9\xa1\xd0\xb3\xd0\xb0\xcf\x81\xe2\x84\x8e"
+                              "\x20\xce\x91\x74\x74\xce\xb1\xe2\x85\xbd\xce\xba\xc7\x83\xe2\x80\xbc";
+  n.my_bonk.type    = 31337;
+  n.my_bonk.message = "I am a bonk... xor!";
+
+  cout << apache::thrift::ThriftJSONString(n) << endl << endl;
+
+
+  HolyMoley hm;
+
+  hm.big.push_back(ooe);
+  hm.big.push_back(n.my_ooe);
+  hm.big[0].a_bite = 0x22;
+  hm.big[1].a_bite = 0x33;
+
+  std::vector<std::string> stage1;
+  stage1.push_back("and a one");
+  stage1.push_back("and a two");
+  hm.contain.insert(stage1);
+  stage1.clear();
+  stage1.push_back("then a one, two");
+  stage1.push_back("three!");
+  stage1.push_back("FOUR!!");
+  hm.contain.insert(stage1);
+  stage1.clear();
+  hm.contain.insert(stage1);
+
+  std::vector<Bonk> stage2;
+  hm.bonks["nothing"] = stage2;
+  stage2.resize(stage2.size()+1);
+  stage2.back().type = 1;
+  stage2.back().message = "Wait.";
+  stage2.resize(stage2.size()+1);
+  stage2.back().type = 2;
+  stage2.back().message = "What?";
+  hm.bonks["something"] = stage2;
+  stage2.clear();
+  stage2.resize(stage2.size()+1);
+  stage2.back().type = 3;
+  stage2.back().message = "quoth";
+  stage2.resize(stage2.size()+1);
+  stage2.back().type = 4;
+  stage2.back().message = "the raven";
+  stage2.resize(stage2.size()+1);
+  stage2.back().type = 5;
+  stage2.back().message = "nevermore";
+  hm.bonks["poe"] = stage2;
+
+  cout << apache::thrift::ThriftJSONString(hm) << endl << endl;
+
+  boost::shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer());
+  boost::shared_ptr<TJSONProtocol> proto(new TJSONProtocol(buffer));
+
+
+  cout << "Testing ooe" << endl;
+
+  ooe.write(proto.get());
+  OneOfEach ooe2;
+  ooe2.read(proto.get());
+
+  assert(ooe == ooe2);
+
+
+  cout << "Testing hm" << endl;
+
+  hm.write(proto.get());
+  HolyMoley hm2;
+  hm2.read(proto.get());
+
+  assert(hm == hm2);
+
+  hm2.big[0].a_bite = 0xFF;
+
+  assert(hm != hm2);
+
+  Doubles dub;
+  dub.nan = HUGE_VAL/HUGE_VAL;
+  dub.inf = HUGE_VAL;
+  dub.neginf = -HUGE_VAL;
+  dub.repeating = 10.0/3.0;
+  dub.big = 1E+305;
+  dub.small = 1E-305;
+  dub.zero = 0.0;
+  dub.negzero = -0.0;
+  cout << apache::thrift::ThriftJSONString(dub) << endl << endl;
+
+  cout << "Testing base" << endl;
+
+  Base64 base;
+  base.a = 123;
+  base.b1 = "1";
+  base.b2 = "12";
+  base.b3 = "123";
+  base.b4 = "1234";
+  base.b5 = "12345";
+  base.b6 = "123456";
+
+  base.write(proto.get());
+  Base64 base2;
+  base2.read(proto.get());
+
+  assert(base == base2);
+
+  return 0;
+}
diff --git a/test/JavaBeansTest.thrift b/test/JavaBeansTest.thrift
new file mode 100644
index 0000000..02bf98d
--- /dev/null
+++ b/test/JavaBeansTest.thrift
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+namespace java thrift.test
+
+struct OneOfEachBeans {
+  1: bool boolean_field,
+  2: byte a_bite,
+  3: i16 integer16,
+  4: i32 integer32,
+  5: i64 integer64,
+  6: double double_precision,
+  7: string some_characters,
+  8: binary base64,
+  9: list<byte> byte_list,
+  10: list<i16> i16_list,
+  11: list<i64> i64_list
+}
diff --git a/test/Makefile.am b/test/Makefile.am
new file mode 100644
index 0000000..1226935
--- /dev/null
+++ b/test/Makefile.am
@@ -0,0 +1,178 @@
+#
+# 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.
+#
+
+SUBDIRS =
+
+if WITH_PYTHON
+SUBDIRS += py
+endif
+
+if WITH_RUBY
+SUBDIRS += rb
+endif
+
+noinst_LTLIBRARIES = libtestgencpp.la
+libtestgencpp_la_SOURCES = \
+	gen-cpp/DebugProtoTest_types.cpp \
+	gen-cpp/OptionalRequiredTest_types.cpp \
+	gen-cpp/DebugProtoTest_types.cpp \
+	gen-cpp/ThriftTest_types.cpp \
+	gen-cpp/DebugProtoTest_types.h \
+	gen-cpp/OptionalRequiredTest_types.h \
+	gen-cpp/ThriftTest_types.h \
+	ThriftTest_extras.cpp \
+	DebugProtoTest_extras.cpp
+
+ThriftTest_extras.o: gen-cpp/ThriftTest_types.h
+DebugProtoTest_extras.o: gen-cpp/DebugProtoTest_types.h
+
+libtestgencpp_la_LIBADD = $(top_builddir)/lib/cpp/libthrift.la
+
+noinst_PROGRAMS = Benchmark
+
+Benchmark_SOURCES = \
+	Benchmark.cpp
+
+Benchmark_LDADD = libtestgencpp.la
+
+check_PROGRAMS = \
+	TFDTransportTest \
+	TPipedTransportTest \
+	DebugProtoTest \
+	JSONProtoTest \
+	OptionalRequiredTest \
+	AllProtocolsTest \
+	UnitTests
+
+TESTS = \
+	$(check_PROGRAMS)
+
+UnitTests_SOURCES = \
+	UnitTestMain.cpp \
+	TMemoryBufferTest.cpp \
+	TBufferBaseTest.cpp
+
+UnitTests_LDADD = libtestgencpp.la
+
+#
+# TFDTransportTest
+#
+TFDTransportTest_SOURCES = \
+	TFDTransportTest.cpp
+
+TFDTransportTest_LDADD = \
+	$(top_builddir)/lib/cpp/libthrift.la
+
+
+#
+# TPipedTransportTest
+#
+TPipedTransportTest_SOURCES = \
+	TPipedTransportTest.cpp
+
+TPipedTransportTest_LDADD = \
+	$(top_builddir)/lib/cpp/libthrift.la
+
+#
+# AllProtocolsTest
+#
+AllProtocolsTest_SOURCES = \
+	AllProtocolTests.cpp \
+	AllProtocolTests.tcc \
+	GenericHelpers.h
+
+AllProtocolsTest_LDADD = libtestgencpp.la
+
+#
+# DebugProtoTest
+#
+DebugProtoTest_SOURCES = \
+	DebugProtoTest.cpp
+
+DebugProtoTest_LDADD = libtestgencpp.la
+
+
+#
+# JSONProtoTest
+#
+JSONProtoTest_SOURCES = \
+	JSONProtoTest.cpp
+
+JSONProtoTest_LDADD = libtestgencpp.la
+
+#
+# OptionalRequiredTest
+#
+OptionalRequiredTest_SOURCES = \
+	OptionalRequiredTest.cpp
+
+OptionalRequiredTest_LDADD = libtestgencpp.la
+
+
+#
+# Common thrift code generation rules
+#
+THRIFT = $(top_builddir)/compiler/cpp/thrift
+
+gen-cpp/DebugProtoTest_types.cpp gen-cpp/DebugProtoTest_types.h: DebugProtoTest.thrift
+	$(THRIFT) --gen cpp:dense $<
+
+gen-cpp/OptionalRequiredTest_types.cpp gen-cpp/OptionalRequiredTest_types.h: OptionalRequiredTest.thrift
+	$(THRIFT) --gen cpp:dense $<
+
+gen-cpp/Service.cpp gen-cpp/StressTest_types.cpp: StressTest.thrift
+	$(THRIFT) --gen cpp:dense $<
+
+gen-cpp/SecondService.cpp gen-cpp/ThriftTest_constants.cpp gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest_types.cpp gen-cpp/ThriftTest_types.h: ThriftTest.thrift
+	$(THRIFT) --gen cpp:dense $<
+
+INCLUDES = \
+	-I$(top_srcdir)/lib/cpp/src
+
+AM_CPPFLAGS = $(BOOST_CPPFLAGS)
+
+clean-local:
+	$(RM) -r gen-cpp
+
+EXTRA_DIST = \
+	cpp \
+	threads \
+	csharp \
+	py \
+	rb \
+	perl \
+	php \
+	erl \
+	hs \
+	ocaml \
+	AnnotationTest.thrift \
+	BrokenConstants.thrift \
+	ConstantsDemo.thrift \
+	DebugProtoTest.thrift \
+	DenseLinkingTest.thrift \
+	DocTest.thrift \
+	JavaBeansTest.thrift \
+	ManyTypedefs.thrift \
+	OptionalRequiredTest.thrift \
+	SmallTest.thrift \
+	StressTest.thrift \
+	ThriftTest.thrift \
+	ZlibTest.cpp \
+	DenseProtoTest.cpp \
+	FastbinaryTest.py
diff --git a/test/ManyTypedefs.thrift b/test/ManyTypedefs.thrift
new file mode 100644
index 0000000..d194b63
--- /dev/null
+++ b/test/ManyTypedefs.thrift
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+// This is to make sure you don't mess something up when you change typedef code.
+// Generate it with the old and new thrift and make sure they are the same.
+/*
+rm -rf gen-* orig-*
+mkdir old new
+thrift --gen cpp --gen java --gen php --gen phpi --gen py --gen rb --gen xsd --gen perl --gen ocaml --gen erl --gen hs --strict ManyTypedefs.thrift
+mv gen-* old
+../compiler/cpp/thrift --gen cpp --gen java --gen php --gen phpi --gen py --gen rb --gen xsd --gen perl --gen ocaml --gen erl --gen hs --strict ManyTypedefs.thrift
+mv gen-* new
+diff -ur old new
+rm -rf old new
+# There should be no output.
+*/
+
+typedef i32 int32
+typedef list<map<int32, string>> biglist
+
+struct struct1 {
+  1: int32 myint;
+  2: biglist mylist;
+}
+
+exception exception1 {
+  1: biglist alist;
+  2: struct1 mystruct;
+}
+
+service AService {
+  struct1 method1(1: int32 myint) throws (1: exception1 exn);
+  biglist method2();
+}
diff --git a/test/OptionalRequiredTest.cpp b/test/OptionalRequiredTest.cpp
new file mode 100644
index 0000000..5743ce3
--- /dev/null
+++ b/test/OptionalRequiredTest.cpp
@@ -0,0 +1,242 @@
+/*
+ * 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.
+ */
+
+#include <cassert>
+#include <map>
+#include <iostream>
+#include <protocol/TDebugProtocol.h>
+#include <protocol/TBinaryProtocol.h>
+#include <transport/TBufferTransports.h>
+#include "gen-cpp/OptionalRequiredTest_types.h"
+
+using std::cout;
+using std::endl;
+using std::map;
+using std::string;
+using namespace thrift::test;
+using namespace apache::thrift;
+using namespace apache::thrift::transport;
+using namespace apache::thrift::protocol;
+
+
+/*
+template<typename Struct>
+void trywrite(const Struct& s, bool should_work) {
+  bool worked;
+  try {
+    TBinaryProtocol protocol(boost::shared_ptr<TTransport>(new TMemoryBuffer));
+    s.write(&protocol);
+    worked = true;
+  } catch (TProtocolException & ex) {
+    worked = false;
+  }
+  assert(worked == should_work);
+}
+*/
+
+template <typename Struct1, typename Struct2>
+void write_to_read(const Struct1 & w, Struct2 & r) {
+  TBinaryProtocol protocol(boost::shared_ptr<TTransport>(new TMemoryBuffer));
+  w.write(&protocol);
+  r.read(&protocol);
+}
+
+
+int main() {
+
+  cout << "This old school struct should have three fields." << endl;
+  {
+    OldSchool o;
+    cout << ThriftDebugString(o) << endl;
+  }
+  cout << endl;
+
+  cout << "Setting a value before setting isset." << endl;
+  {
+    Simple s;
+    cout << ThriftDebugString(s) << endl;
+    s.im_optional = 10;
+    cout << ThriftDebugString(s) << endl;
+    s.__isset.im_optional = true;
+    cout << ThriftDebugString(s) << endl;
+  }
+  cout << endl;
+
+  cout << "Setting isset before setting a value." << endl;
+  {
+    Simple s;
+    cout << ThriftDebugString(s) << endl;
+    s.__isset.im_optional = true;
+    cout << ThriftDebugString(s) << endl;
+    s.im_optional = 10;
+    cout << ThriftDebugString(s) << endl;
+  }
+  cout << endl;
+
+  // Write-to-read with optional fields.
+  {
+    Simple s1, s2, s3;
+    s1.im_optional = 10;
+    assert(!s1.__isset.im_default);
+  //assert(!s1.__isset.im_required);  // Compile error.
+    assert(!s1.__isset.im_optional);
+
+    write_to_read(s1, s2);
+
+    assert( s2.__isset.im_default);
+  //assert( s2.__isset.im_required);  // Compile error.
+    assert(!s2.__isset.im_optional);
+    assert(s3.im_optional == 0);
+
+    s1.__isset.im_optional = true;
+    write_to_read(s1, s3);
+
+    assert( s3.__isset.im_default);
+  //assert( s3.__isset.im_required);  // Compile error.
+    assert( s3.__isset.im_optional);
+    assert(s3.im_optional == 10);
+  }
+
+  // Writing between optional and default.
+  {
+    Tricky1 t1;
+    Tricky2 t2;
+
+    t2.im_optional = 10;
+    write_to_read(t2, t1);
+    write_to_read(t1, t2);
+    assert(!t1.__isset.im_default);
+    assert( t2.__isset.im_optional);
+    assert(t1.im_default == t2.im_optional);
+    assert(t1.im_default == 0);
+  }
+
+  // Writing between default and required.
+  {
+    Tricky1 t1;
+    Tricky3 t3;
+    write_to_read(t1, t3);
+    write_to_read(t3, t1);
+    assert(t1.__isset.im_default);
+  }
+
+  // Writing between optional and required.
+  {
+    Tricky2 t2;
+    Tricky3 t3;
+    t2.__isset.im_optional = true;
+    write_to_read(t2, t3);
+    write_to_read(t3, t2);
+  }
+
+  // Mu-hu-ha-ha-ha!
+  {
+    Tricky2 t2;
+    Tricky3 t3;
+    try {
+      write_to_read(t2, t3);
+      abort();
+    }
+    catch (TProtocolException& ex) {}
+
+    write_to_read(t3, t2);
+    assert(t2.__isset.im_optional);
+  }
+
+  cout << "Complex struct, simple test." << endl;
+  {
+    Complex c;
+    cout << ThriftDebugString(c) << endl;
+  }
+
+
+  {
+    Tricky1 t1;
+    Tricky2 t2;
+    // Compile error.
+    //(void)(t1 == t2);
+  }
+
+  {
+    OldSchool o1, o2, o3;
+    assert(o1 == o2);
+    o1.im_int = o2.im_int = 10;
+    assert(o1 == o2);
+    o1.__isset.im_int = true;
+    o2.__isset.im_int = false;
+    assert(o1 == o2);
+    o1.im_int = 20;
+    o1.__isset.im_int = false;
+    assert(o1 != o2);
+    o1.im_int = 10;
+    assert(o1 == o2);
+    o1.im_str = o2.im_str = "foo";
+    assert(o1 == o2);
+    o1.__isset.im_str = o2.__isset.im_str = true;
+    assert(o1 == o2);
+    map<int32_t,string> mymap;
+    mymap[1] = "bar";
+    mymap[2] = "baz";
+    o1.im_big.push_back(map<int32_t,string>());
+    assert(o1 != o2);
+    o2.im_big.push_back(map<int32_t,string>());
+    assert(o1 == o2);
+    o2.im_big.push_back(mymap);
+    assert(o1 != o2);
+    o1.im_big.push_back(mymap);
+    assert(o1 == o2);
+
+    TBinaryProtocol protocol(boost::shared_ptr<TTransport>(new TMemoryBuffer));
+    o1.write(&protocol);
+
+    o1.im_big.push_back(mymap);
+    mymap[3] = "qux";
+    o2.im_big.push_back(mymap);
+    assert(o1 != o2);
+    o1.im_big.back()[3] = "qux";
+    assert(o1 == o2);
+
+    o3.read(&protocol);
+    o3.im_big.push_back(mymap);
+    assert(o1 == o3);
+
+    //cout << ThriftDebugString(o3) << endl;
+  }
+
+  {
+    Tricky2 t1, t2;
+    assert(t1.__isset.im_optional == false);
+    assert(t2.__isset.im_optional == false);
+    assert(t1 == t2);
+    t1.im_optional = 5;
+    assert(t1 == t2);
+    t2.im_optional = 5;
+    assert(t1 == t2);
+    t1.__isset.im_optional = true;
+    assert(t1 != t2);
+    t2.__isset.im_optional = true;
+    assert(t1 == t2);
+    t1.im_optional = 10;
+    assert(t1 != t2);
+    t2.__isset.im_optional = false;
+    assert(t1 != t2);
+  }
+
+  return 0;
+}
diff --git a/test/OptionalRequiredTest.thrift b/test/OptionalRequiredTest.thrift
new file mode 100644
index 0000000..f7d1fd6
--- /dev/null
+++ b/test/OptionalRequiredTest.thrift
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+namespace cpp thrift.test
+namespace java thrift.test
+
+struct OldSchool {
+  1: i16    im_int;
+  2: string im_str;
+  3: list<map<i32,string>> im_big;
+}
+
+struct Simple {
+  1: /* :) */ i16 im_default;
+  2: required i16 im_required;
+  3: optional i16 im_optional;
+}
+
+struct Tricky1 {
+  1: /* :) */ i16 im_default;
+}
+
+struct Tricky2 {
+  1: optional i16 im_optional;
+}
+
+struct Tricky3 {
+  1: required i16 im_required;
+}
+
+struct Complex {
+  1:          i16 cp_default;
+  2: required i16 cp_required;
+  3: optional i16 cp_optional;
+  4:          map<i16,Simple> the_map;
+  5: required Simple req_simp;
+  6: optional Simple opt_simp;
+}
+
+struct ManyOpt {
+  1: optional i32 opt1;
+  2: optional i32 opt2;
+  3: optional i32 opt3;
+  4:          i32 def4;
+  5: optional i32 opt5;
+  6: optional i32 opt6;
+}
+
+struct JavaTestHelper {
+  1: required i32    req_int;
+  2: optional i32    opt_int;
+  3: required string req_obj;
+  4: optional string opt_obj;
+  5: required binary req_bin;
+  6: optional binary opt_bin;
+}
diff --git a/test/SmallTest.thrift b/test/SmallTest.thrift
new file mode 100644
index 0000000..d0821c7
--- /dev/null
+++ b/test/SmallTest.thrift
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+
+namespace rb TestNamespace
+
+struct Goodbyez {
+  1: i32 val = 325;
+}
+
+senum Thinger {
+  "ASDFKJ",
+  "r32)*F#@",
+  "ASDFLJASDF"
+}
+
+struct BoolPasser {
+  1: bool value = 1
+}
+
+struct Hello {
+  1: i32 simple = 53,
+  2: map<i32,i32> complex = {23:532, 6243:632, 2355:532},
+  3: map<i32, map<i32,i32>> complexer,
+  4: string words = "words",
+  5: Goodbyez thinz = {'val' : 36632}
+}
+
+const map<i32,map<i32,i32>> CMAP = { 235: {235:235}, 53:{53:53} }
+const i32 CINT = 325;
+const Hello WHOA = {'simple' : 532}
+
+exception Goodbye {
+  1: i32 simple,
+  2: map<i32,i32> complex,
+  3: map<i32, map<i32,i32>> complexer,
+}
+
+service SmallService {
+  Thinger testThinger(1:Thinger bootz),
+  Hello testMe(1:i32 hello=64, 2: Hello wonk) throws (1: Goodbye g),
+  void testVoid() throws (1: Goodbye g),
+  i32 testI32(1:i32 boo)
+}
diff --git a/test/StressTest.thrift b/test/StressTest.thrift
new file mode 100644
index 0000000..87c6e47
--- /dev/null
+++ b/test/StressTest.thrift
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+namespace cpp test.stress
+
+service Service {
+
+  void echoVoid(),
+  byte echoByte(1: byte arg),
+  i32 echoI32(1: i32 arg),
+  i64 echoI64(1: i64 arg),
+  string echoString(1: string arg),
+  list<byte>  echoList(1: list<byte> arg),
+  set<byte>  echoSet(1: set<byte> arg),
+  map<byte, byte>  echoMap(1: map<byte, byte> arg),
+}
+
diff --git a/test/TBufferBaseTest.cpp b/test/TBufferBaseTest.cpp
new file mode 100644
index 0000000..da3ce85
--- /dev/null
+++ b/test/TBufferBaseTest.cpp
@@ -0,0 +1,639 @@
+/*
+ * 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.
+ */
+
+#include <algorithm>
+#include <boost/foreach.hpp>
+#include <boost/test/unit_test.hpp>
+#include <transport/TBufferTransports.h>
+#include <transport/TShortReadTransport.h>
+
+using std::string;
+using boost::shared_ptr;
+using apache::thrift::transport::TMemoryBuffer;
+using apache::thrift::transport::TBufferedTransport;
+using apache::thrift::transport::TFramedTransport;
+using apache::thrift::transport::test::TShortReadTransport;
+
+#define foreach BOOST_FOREACH
+
+// Shamelessly copied from ZlibTransport.  TODO: refactor.
+unsigned int dist[][5000] = {
+ { 1<<15 },
+
+ {
+  5,13,9,1,8,9,11,13,18,48,24,13,21,13,5,11,35,2,4,20,17,72,27,14,15,4,7,26,
+  12,1,14,9,2,16,29,41,7,24,4,27,14,4,1,4,25,3,6,34,10,8,50,2,14,13,55,29,3,
+  43,53,49,14,4,10,32,27,48,1,3,1,11,5,17,16,51,17,30,15,11,9,2,2,11,52,12,2,
+  13,94,1,19,1,38,2,8,43,8,33,7,30,8,17,22,2,15,14,12,34,2,12,6,37,29,74,3,
+  165,16,11,17,5,14,3,10,7,37,11,24,7,1,3,12,37,8,9,34,17,12,8,21,13,37,1,4,
+  30,14,78,4,15,2,40,37,17,12,36,82,14,4,1,4,7,17,11,16,88,77,2,3,15,3,34,11,
+  5,79,22,34,8,4,4,40,22,24,28,9,13,3,34,27,9,16,39,16,39,13,2,4,3,41,26,10,4,
+  33,4,7,12,5,6,3,10,30,8,21,16,58,19,9,0,47,7,13,11,19,15,7,53,57,2,13,28,22,
+  3,16,9,25,33,12,40,7,12,64,7,14,24,44,9,2,14,11,2,58,1,26,30,11,9,5,24,7,9,
+  94,2,10,21,5,5,4,5,6,179,9,18,2,7,13,31,41,17,4,36,3,21,6,26,8,15,18,44,27,
+  11,9,25,7,0,14,2,12,20,23,13,2,163,9,5,15,65,2,14,6,8,98,11,15,14,34,2,3,10,
+  22,9,92,7,10,32,67,13,3,4,35,8,2,1,5,0,26,381,7,27,8,2,16,93,4,19,5,8,25,9,
+  31,14,4,21,5,3,9,22,56,4,18,3,11,18,6,4,3,40,12,16,110,8,35,14,1,18,40,9,12,
+  14,3,11,7,57,13,18,116,53,19,22,7,16,11,5,8,21,16,1,75,21,20,1,28,2,6,1,7,
+  19,38,5,6,9,9,4,1,7,55,36,62,5,4,4,24,15,1,12,35,48,20,5,17,1,5,26,15,4,54,
+  13,5,5,15,5,19,32,29,31,7,6,40,7,80,11,18,8,128,48,6,12,84,13,4,7,2,13,9,16,
+  17,3,254,1,4,181,8,44,7,6,24,27,9,23,14,34,16,22,25,10,3,3,4,4,12,2,12,6,7,
+  13,58,13,6,11,19,53,11,66,18,19,10,4,13,2,5,49,58,1,67,7,21,64,14,11,14,8,3,
+  26,33,91,31,20,7,9,42,39,4,3,55,11,10,0,7,4,75,8,12,0,27,3,8,9,0,12,12,23,
+  28,23,20,4,13,30,2,22,20,19,30,6,22,2,6,4,24,7,19,55,86,5,33,2,161,6,7,1,62,
+  13,3,72,12,12,9,7,12,10,5,10,29,1,5,22,13,13,5,2,12,3,7,14,18,2,3,46,21,17,
+  15,19,3,27,5,16,45,31,10,8,17,18,18,3,7,24,6,55,9,3,6,12,10,12,8,91,9,4,4,4,
+  27,29,16,5,7,22,43,28,11,14,8,11,28,109,55,71,40,3,8,22,26,15,44,3,25,29,5,
+  3,32,17,12,3,29,27,25,15,11,8,40,39,38,17,3,9,11,2,32,11,6,20,48,75,27,3,7,
+  54,12,95,12,7,24,23,2,13,8,15,16,5,12,4,17,7,19,88,2,6,13,115,45,12,21,2,86,
+  74,9,7,5,16,32,16,2,21,18,6,34,5,18,260,7,12,16,44,19,92,31,7,8,2,9,0,0,15,
+  8,38,4,8,20,18,2,83,3,3,4,9,5,3,10,3,5,29,15,7,11,8,48,17,23,2,17,4,11,22,
+  21,64,8,8,4,19,95,0,17,28,9,11,20,71,5,11,18,12,13,45,49,4,1,33,32,23,13,5,
+  52,2,2,16,3,4,7,12,2,1,12,6,24,1,22,155,21,3,45,4,12,44,26,5,40,36,9,9,8,20,
+  35,31,3,2,32,50,10,8,37,2,75,35,22,15,192,8,11,23,1,4,29,6,8,8,5,12,18,32,4,
+  7,12,2,0,0,9,5,48,11,35,3,1,123,6,29,8,11,8,23,51,16,6,63,12,2,5,4,14,2,15,
+  7,14,3,2,7,17,32,8,8,10,1,23,62,2,49,6,49,47,23,3,20,7,11,39,10,24,6,15,5,5,
+  11,8,16,36,8,13,20,3,10,44,7,52,7,10,36,6,15,10,5,11,4,14,19,17,10,12,3,6,
+  23,4,13,94,70,7,36,7,38,7,28,8,4,15,3,19,4,33,39,21,109,4,80,6,40,4,432,4,4,
+  7,8,3,31,8,28,37,34,10,2,21,5,22,0,7,36,14,12,6,24,1,21,5,9,2,29,20,54,113,
+  13,31,39,27,6,0,27,4,5,2,43,7,8,57,8,62,7,9,12,22,90,30,6,19,7,10,20,6,5,58,
+  32,30,41,4,10,25,13,3,8,7,10,2,9,6,151,44,16,12,16,20,8,3,18,11,17,4,10,45,
+  15,8,56,38,52,25,40,14,4,17,15,8,2,19,7,8,26,30,2,3,180,8,26,17,38,35,5,16,
+  28,5,15,56,13,14,18,9,15,83,27,3,9,4,11,8,27,27,44,10,12,8,3,48,14,7,9,4,4,
+  8,4,5,9,122,8,14,12,19,17,21,4,29,63,21,17,10,12,18,47,10,10,53,4,18,16,4,8,
+  118,9,5,12,9,11,9,3,12,32,3,23,2,15,3,3,30,3,17,235,15,22,9,299,14,17,1,5,
+  16,8,3,7,3,13,2,7,6,4,8,66,2,13,6,15,16,47,3,36,5,7,10,24,1,9,9,8,13,16,26,
+  12,7,24,21,18,49,23,39,10,41,4,13,4,27,11,12,12,19,4,147,8,10,9,40,21,2,83,
+  10,5,6,11,25,9,50,57,40,12,12,21,1,3,24,23,9,3,9,13,2,3,12,57,8,11,13,15,26,
+  15,10,47,36,4,25,1,5,8,5,4,0,12,49,5,19,4,6,16,14,6,10,69,10,33,29,7,8,61,
+  12,4,0,3,7,6,3,16,29,27,38,4,21,0,24,3,2,1,19,16,22,2,8,138,11,7,7,3,12,22,
+  3,16,5,7,3,53,9,10,32,14,5,7,3,6,22,9,59,26,8,7,58,5,16,11,55,7,4,11,146,91,
+  8,13,18,14,6,8,8,31,26,22,6,11,30,11,30,15,18,31,3,48,17,7,6,4,9,2,25,3,35,
+  13,13,7,8,4,31,10,8,10,4,3,45,10,23,2,7,259,17,21,13,14,3,26,3,8,27,4,18,9,
+  66,7,12,5,8,17,4,23,55,41,51,2,32,26,66,4,21,14,12,65,16,22,17,5,14,2,29,24,
+  7,3,36,2,43,53,86,5,28,4,58,13,49,121,6,2,73,2,1,47,4,2,27,10,35,28,27,10,
+  17,10,56,7,10,14,28,20,24,40,7,4,7,3,10,11,32,6,6,3,15,11,54,573,2,3,6,2,3,
+  14,64,4,16,12,16,42,10,26,4,6,11,69,18,27,2,2,17,22,9,13,22,11,6,1,15,49,3,
+  14,1
+ },
+
+ {
+  11,11,11,15,47,1,3,1,23,5,8,18,3,23,15,21,1,7,19,10,26,1,17,11,31,21,41,18,
+  34,4,9,58,19,3,3,36,5,18,13,3,14,4,9,10,4,19,56,15,3,5,3,11,27,9,4,10,13,4,
+  11,6,9,2,18,3,10,19,11,4,53,4,2,2,3,4,58,16,3,0,5,30,2,11,93,10,2,14,10,6,2,
+  115,2,25,16,22,38,101,4,18,13,2,145,51,45,15,14,15,13,20,7,24,5,13,14,30,40,
+  10,4,107,12,24,14,39,12,6,13,20,7,7,11,5,18,18,45,22,6,39,3,2,1,51,9,11,4,
+  13,9,38,44,8,11,9,15,19,9,23,17,17,17,13,9,9,1,10,4,18,6,2,9,5,27,32,72,8,
+  37,9,4,10,30,17,20,15,17,66,10,4,73,35,37,6,4,16,117,45,13,4,75,5,24,65,10,
+  4,9,4,13,46,5,26,29,10,4,4,52,3,13,18,63,6,14,9,24,277,9,88,2,48,27,123,14,
+  61,7,5,10,8,7,90,3,10,3,3,48,17,13,10,18,33,2,19,36,6,21,1,16,12,5,6,2,16,
+  15,29,88,28,2,15,6,11,4,6,11,3,3,4,18,9,53,5,4,3,33,8,9,8,6,7,36,9,62,14,2,
+  1,10,1,16,7,32,7,23,20,11,10,23,2,1,0,9,16,40,2,81,5,22,8,5,4,37,51,37,10,
+  19,57,11,2,92,31,6,39,10,13,16,8,20,6,9,3,10,18,25,23,12,30,6,2,26,7,64,18,
+  6,30,12,13,27,7,10,5,3,33,24,99,4,23,4,1,27,7,27,49,8,20,16,3,4,13,9,22,67,
+  28,3,10,16,3,2,10,4,8,1,8,19,3,85,6,21,1,9,16,2,30,10,33,12,4,9,3,1,60,38,6,
+  24,32,3,14,3,40,8,34,115,5,9,27,5,96,3,40,6,15,5,8,22,112,5,5,25,17,58,2,7,
+  36,21,52,1,3,95,12,21,4,11,8,59,24,5,21,4,9,15,8,7,21,3,26,5,11,6,7,17,65,
+  14,11,10,2,17,5,12,22,4,4,2,21,8,112,3,34,63,35,2,25,1,2,15,65,23,0,3,5,15,
+  26,27,9,5,48,11,15,4,9,5,33,20,15,1,18,19,11,24,40,10,21,74,6,6,32,30,40,5,
+  4,7,44,10,25,46,16,12,5,40,7,18,5,18,9,12,8,4,25,5,6,36,4,43,8,9,12,35,17,4,
+  8,9,11,27,5,10,17,40,8,12,4,18,9,18,12,20,25,39,42,1,24,13,22,15,7,112,35,3,
+  7,17,33,2,5,5,19,8,4,12,24,14,13,2,1,13,6,5,19,11,7,57,0,19,6,117,48,14,8,
+  10,51,17,12,14,2,5,8,9,15,4,48,53,13,22,4,25,12,11,19,45,5,2,6,54,22,9,15,9,
+  13,2,7,11,29,82,16,46,4,26,14,26,40,22,4,26,6,18,13,4,4,20,3,3,7,12,17,8,9,
+  23,6,20,7,25,23,19,5,15,6,23,15,11,19,11,3,17,59,8,18,41,4,54,23,44,75,13,
+  20,6,11,2,3,1,13,10,3,7,12,3,4,7,8,30,6,6,7,3,32,9,5,28,6,114,42,13,36,27,
+  59,6,93,13,74,8,69,140,3,1,17,48,105,6,11,5,15,1,10,10,14,8,53,0,8,24,60,2,
+  6,35,2,12,32,47,16,17,75,2,5,4,37,28,10,5,9,57,4,59,5,12,13,7,90,5,11,5,24,
+  22,13,30,1,2,10,9,6,19,3,18,47,2,5,7,9,35,15,3,6,1,21,14,14,18,14,9,12,8,73,
+  6,19,3,32,9,14,17,17,5,55,23,6,16,28,3,11,48,4,6,6,6,12,16,30,10,30,27,51,
+  18,29,2,3,15,1,76,0,16,33,4,27,3,62,4,10,2,4,8,15,9,41,26,22,2,4,20,4,49,0,
+  8,1,57,13,12,39,3,63,10,19,34,35,2,7,8,29,72,4,10,0,77,8,6,7,9,15,21,9,4,1,
+  20,23,1,9,18,9,15,36,4,7,6,15,5,7,7,40,2,9,22,2,3,20,4,12,34,13,6,18,15,1,
+  38,20,12,7,16,3,19,85,12,16,18,16,2,17,1,13,8,6,12,15,97,17,12,9,3,21,15,12,
+  23,44,81,26,30,2,5,17,6,6,0,22,42,19,6,19,41,14,36,7,3,56,7,9,3,2,6,9,69,3,
+  15,4,30,28,29,7,9,15,17,17,6,1,6,153,9,33,5,12,14,16,28,3,8,7,14,12,4,6,36,
+  9,24,13,13,4,2,9,15,19,9,53,7,13,4,150,17,9,2,6,12,7,3,5,58,19,58,28,8,14,3,
+  20,3,0,32,56,7,5,4,27,1,68,4,29,13,5,58,2,9,65,41,27,16,15,12,14,2,10,9,24,
+  3,2,9,2,2,3,14,32,10,22,3,13,11,4,6,39,17,0,10,5,5,10,35,16,19,14,1,8,63,19,
+  14,8,56,10,2,12,6,12,6,7,16,2,9,9,12,20,73,25,13,21,17,24,5,32,8,12,25,8,14,
+  16,5,23,3,7,6,3,11,24,6,30,4,21,13,28,4,6,29,15,5,17,6,26,8,15,8,3,7,7,50,
+  11,30,6,2,28,56,16,24,25,23,24,89,31,31,12,7,22,4,10,17,3,3,8,11,13,5,3,27,
+  1,12,1,14,8,10,29,2,5,2,2,20,10,0,31,10,21,1,48,3,5,43,4,5,18,13,5,18,25,34,
+  18,3,5,22,16,3,4,20,3,9,3,25,6,6,44,21,3,12,7,5,42,3,2,14,4,36,5,3,45,51,15,
+  9,11,28,9,7,6,6,12,26,5,14,10,11,42,55,13,21,4,28,6,7,23,27,11,1,41,36,0,32,
+  15,26,2,3,23,32,11,2,15,7,29,26,144,33,20,12,7,21,10,7,11,65,46,10,13,20,32,
+  4,4,5,19,2,19,15,49,41,1,75,10,11,25,1,2,45,11,8,27,18,10,60,28,29,12,30,19,
+  16,4,24,11,19,27,17,49,18,7,40,13,19,22,8,55,12,11,3,6,5,11,8,10,22,5,9,9,
+  25,7,17,7,64,1,24,2,12,17,44,4,12,27,21,11,10,7,47,5,9,13,12,38,27,21,7,29,
+  7,1,17,3,3,5,48,62,10,3,11,17,15,15,6,3,8,10,8,18,19,13,3,9,7,6,44,9,10,4,
+  43,8,6,6,14,20,38,24,2,4,5,5,7,5,9,39,8,44,40,9,19,7,3,15,25,2,37,18,15,9,5,
+  8,32,10,5,18,4,7,46,20,17,23,4,11,16,18,31,11,3,11,1,14,1,25,4,27,13,13,39,
+  14,6,6,35,6,16,13,11,122,21,15,20,24,10,5,152,15,39,5,20,16,9,14,7,53,6,3,8,
+  19,63,32,6,2,3,20,1,19,5,13,42,15,4,6,68,31,46,11,38,10,24,5,5,8,9,12,3,35,
+  46,26,16,2,8,4,74,16,44,4,5,1,16,4,14,23,16,69,15,42,31,14,7,7,6,97,14,40,1,
+  8,7,34,9,39,19,13,15,10,21,18,10,5,15,38,7,5,12,7,20,15,4,11,6,14,5,17,7,39,
+  35,36,18,20,26,22,4,2,36,21,64,0,5,9,10,6,4,1,7,3,1,3,3,4,10,20,90,2,22,48,
+  16,23,2,33,40,1,21,21,17,20,8,8,12,4,83,14,48,4,21,3,9,27,5,11,40,15,9,3,16,
+  17,9,11,4,24,31,17,3,4,2,11,1,8,4,8,6,41,17,4,13,3,7,17,8,27,5,13,6,10,7,13,
+  12,18,13,60,18,3,8,1,12,125,2,7,16,2,11,2,4,7,26,5,9,14,14,16,8,14,7,14,6,9,
+  13,9,6,4,26,35,49,36,55,3,9,6,40,26,23,31,19,41,2,10,31,6,54,5,69,16,7,8,16,
+  1,5,7,4,22,7,7,5,4,48,11,13,3,98,4,11,19,4,2,14,7,34,7,10,3,2,12,7,6,2,5,118
+ },
+};
+
+uint8_t data[1<<15];
+string data_str;
+void init_data() {
+  static bool initted = false;
+  if (initted) return;
+  initted = true;
+
+  // Repeatability.  Kind of.
+  std::srand(42);
+  for (int i = 0; i < (int)(sizeof(data)/sizeof(data[0])); ++i) {
+    data[i] = (uint8_t)rand();
+  }
+
+  data_str.assign((char*)data, sizeof(data));
+}
+
+
+BOOST_AUTO_TEST_SUITE( TBufferBaseTest )
+
+BOOST_AUTO_TEST_CASE( test_MemoryBuffer_Write_GetBuffer ) {
+  init_data();
+
+  for (int d1 = 0; d1 < 3; d1++) {
+    TMemoryBuffer buffer(16);
+    int offset = 0;
+    int index = 0;
+
+    while (offset < 1<<15) {
+      buffer.write(&data[offset], dist[d1][index]);
+      offset += dist[d1][index];
+      index++;
+    }
+
+    string output = buffer.getBufferAsString();
+    BOOST_CHECK_EQUAL(data_str, output);
+  }
+}
+
+BOOST_AUTO_TEST_CASE( test_MemoryBuffer_Write_Read ) {
+  init_data();
+
+  for (int d1 = 0; d1 < 3; d1++) {
+    for (int d2 = 0; d2 < 3; d2++) {
+      TMemoryBuffer buffer(16);
+      uint8_t data_out[1<<15];
+      int offset;
+      int index;
+
+      offset = 0;
+      index = 0;
+      while (offset < 1<<15) {
+        buffer.write(&data[offset], dist[d1][index]);
+        offset += dist[d1][index];
+        index++;
+      }
+
+      offset = 0;
+      index = 0;
+      while (offset < 1<<15) {
+        unsigned int got = buffer.read(&data_out[offset], dist[d2][index]);
+        BOOST_CHECK_EQUAL(got, dist[d2][index]);
+        offset += dist[d2][index];
+        index++;
+      }
+
+      BOOST_CHECK(!memcmp(data, data_out, sizeof(data)));
+    }
+  }
+}
+
+BOOST_AUTO_TEST_CASE( test_MemoryBuffer_Write_ReadString ) {
+  init_data();
+
+  for (int d1 = 0; d1 < 3; d1++) {
+    for (int d2 = 0; d2 < 3; d2++) {
+      TMemoryBuffer buffer(16);
+      string output;
+      int offset;
+      int index;
+
+      offset = 0;
+      index = 0;
+      while (offset < 1<<15) {
+        buffer.write(&data[offset], dist[d1][index]);
+        offset += dist[d1][index];
+        index++;
+      }
+
+      offset = 0;
+      index = 0;
+      while (offset < 1<<15) {
+        unsigned int got = buffer.readAppendToString(output, dist[d2][index]);
+        BOOST_CHECK_EQUAL(got, dist[d2][index]);
+        offset += dist[d2][index];
+        index++;
+      }
+
+      BOOST_CHECK_EQUAL(output, data_str);
+    }
+  }
+}
+
+BOOST_AUTO_TEST_CASE( test_MemoryBuffer_Write_Read_Multi1 ) {
+  init_data();
+
+  // Do shorter writes and reads so we don't align to power-of-two boundaries.
+
+  for (int d1 = 0; d1 < 3; d1++) {
+    for (int d2 = 0; d2 < 3; d2++) {
+      TMemoryBuffer buffer(16);
+      uint8_t data_out[1<<15];
+      int offset;
+      int index;
+
+      for (int iter = 0; iter < 6; iter++) {
+        offset = 0;
+        index = 0;
+        while (offset < (1<<15)-42) {
+          buffer.write(&data[offset], dist[d1][index]);
+          offset += dist[d1][index];
+          index++;
+        }
+
+        offset = 0;
+        index = 0;
+        while (offset < (1<<15)-42) {
+          buffer.read(&data_out[offset], dist[d2][index]);
+          offset += dist[d2][index];
+          index++;
+        }
+
+        BOOST_CHECK(!memcmp(data, data_out, (1<<15)-42));
+
+        // Pull out the extra data.
+        buffer.read(data_out, 42);
+      }
+    }
+  }
+}
+
+BOOST_AUTO_TEST_CASE( test_MemoryBuffer_Write_Read_Multi2 ) {
+  init_data();
+
+  // Do shorter writes and reads so we don't align to power-of-two boundaries.
+  // Pull the buffer out of the loop so its state gets worked harder.
+  TMemoryBuffer buffer(16);
+
+  for (int d1 = 0; d1 < 3; d1++) {
+    for (int d2 = 0; d2 < 3; d2++) {
+      uint8_t data_out[1<<15];
+      int offset;
+      int index;
+
+      for (int iter = 0; iter < 6; iter++) {
+        offset = 0;
+        index = 0;
+        while (offset < (1<<15)-42) {
+          buffer.write(&data[offset], dist[d1][index]);
+          offset += dist[d1][index];
+          index++;
+        }
+
+        offset = 0;
+        index = 0;
+        while (offset < (1<<15)-42) {
+          buffer.read(&data_out[offset], dist[d2][index]);
+          offset += dist[d2][index];
+          index++;
+        }
+
+        BOOST_CHECK(!memcmp(data, data_out, (1<<15)-42));
+
+        // Pull out the extra data.
+        buffer.read(data_out, 42);
+      }
+    }
+  }
+}
+
+BOOST_AUTO_TEST_CASE( test_MemoryBuffer_Write_Read_Incomplete ) {
+  init_data();
+
+  // Do shorter writes and reads so we don't align to power-of-two boundaries.
+  // Pull the buffer out of the loop so its state gets worked harder.
+
+  for (int d1 = 0; d1 < 3; d1++) {
+    for (int d2 = 0; d2 < 3; d2++) {
+      TMemoryBuffer buffer(16);
+      uint8_t data_out[1<<13];
+
+      int write_offset = 0;
+      int write_index = 0;
+      unsigned int to_write = (1<<14)-42;
+      while (to_write > 0) {
+        int write_amt = std::min(dist[d1][write_index], to_write);
+        buffer.write(&data[write_offset], write_amt);
+        write_offset += write_amt;
+        write_index++;
+        to_write -= write_amt;
+      }
+
+      int read_offset = 0;
+      int read_index = 0;
+      unsigned int to_read = (1<<13)-42;
+      while (to_read > 0) {
+        int read_amt = std::min(dist[d2][read_index], to_read);
+        int got = buffer.read(&data_out[read_offset], read_amt);
+        BOOST_CHECK_EQUAL(got, read_amt);
+        read_offset += read_amt;
+        read_index++;
+        to_read -= read_amt;
+      }
+
+      BOOST_CHECK(!memcmp(data, data_out, (1<<13)-42));
+
+      int second_offset = write_offset;
+      int second_index = write_index-1;
+      unsigned int to_second = (1<<14)+42;
+      while (to_second > 0) {
+        int second_amt = std::min(dist[d1][second_index], to_second);
+        //printf("%d\n", second_amt);
+        buffer.write(&data[second_offset], second_amt);
+        second_offset += second_amt;
+        second_index++;
+        to_second -= second_amt;
+      }
+
+      string output = buffer.getBufferAsString();
+      BOOST_CHECK_EQUAL(data_str.substr((1<<13)-42), output);
+    }
+  }
+}
+
+BOOST_AUTO_TEST_CASE( test_BufferedTransport_Write ) {
+  init_data();
+
+  int sizes[] = {
+    12, 15, 16, 17, 20,
+    501, 512, 523,
+    2000, 2048, 2096,
+    1<<14, 1<<17,
+  };
+
+  foreach (int size, sizes) {
+    for (int d1 = 0; d1 < 3; d1++) {
+      shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer(16));
+      TBufferedTransport trans(buffer, size);
+
+      int offset = 0;
+      int index = 0;
+      while (offset < 1<<15) {
+        trans.write(&data[offset], dist[d1][index]);
+        offset += dist[d1][index];
+        index++;
+      }
+      trans.flush();
+
+      string output = buffer->getBufferAsString();
+      BOOST_CHECK_EQUAL(data_str, output);
+    }
+  }
+}
+
+BOOST_AUTO_TEST_CASE( test_BufferedTransport_Read_Full ) {
+  init_data();
+
+  int sizes[] = {
+    12, 15, 16, 17, 20,
+    501, 512, 523,
+    2000, 2048, 2096,
+    1<<14, 1<<17,
+  };
+
+  foreach (int size, sizes) {
+    for (int d1 = 0; d1 < 3; d1++) {
+      shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer(data, sizeof(data)));
+      TBufferedTransport trans(buffer, size);
+      uint8_t data_out[1<<15];
+
+      int offset = 0;
+      int index = 0;
+      while (offset < 1<<15) {
+        // Note: this doesn't work with "read" because TBufferedTransport
+        // doesn't try loop over reads, so we get short reads.  We don't
+        // check the return value, so that messes us up.
+        trans.readAll(&data_out[offset], dist[d1][index]);
+        offset += dist[d1][index];
+        index++;
+      }
+
+      BOOST_CHECK(!memcmp(data, data_out, sizeof(data)));
+    }
+  }
+}
+
+BOOST_AUTO_TEST_CASE( test_BufferedTransport_Read_Short ) {
+  init_data();
+
+  int sizes[] = {
+    12, 15, 16, 17, 20,
+    501, 512, 523,
+    2000, 2048, 2096,
+    1<<14, 1<<17,
+  };
+
+  foreach (int size, sizes) {
+    for (int d1 = 0; d1 < 3; d1++) {
+      shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer(data, sizeof(data)));
+      shared_ptr<TShortReadTransport> tshort(new TShortReadTransport(buffer, 0.125));
+      TBufferedTransport trans(buffer, size);
+      uint8_t data_out[1<<15];
+
+      int offset = 0;
+      int index = 0;
+      while (offset < 1<<15) {
+        // Note: this doesn't work with "read" because TBufferedTransport
+        // doesn't try loop over reads, so we get short reads.  We don't
+        // check the return value, so that messes us up.
+        trans.readAll(&data_out[offset], dist[d1][index]);
+        offset += dist[d1][index];
+        index++;
+      }
+
+      BOOST_CHECK(!memcmp(data, data_out, sizeof(data)));
+    }
+  }
+}
+
+BOOST_AUTO_TEST_CASE( test_FramedTransport_Write ) {
+  init_data();
+
+  int sizes[] = {
+    12, 15, 16, 17, 20,
+    501, 512, 523,
+    2000, 2048, 2096,
+    1<<14, 1<<17,
+  };
+
+  foreach (int size, sizes) {
+    for (int d1 = 0; d1 < 3; d1++) {
+      shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer(16));
+      TFramedTransport trans(buffer, size);
+
+      int offset = 0;
+      int index = 0;
+      while (offset < 1<<15) {
+        trans.write(&data[offset], dist[d1][index]);
+        offset += dist[d1][index];
+        index++;
+      }
+      trans.flush();
+
+      int32_t frame_size = -1;
+      buffer->read(reinterpret_cast<uint8_t*>(&frame_size), sizeof(frame_size));
+      frame_size = (int32_t)ntohl((uint32_t)frame_size);
+      BOOST_CHECK_EQUAL(frame_size, 1<<15);
+      BOOST_CHECK_EQUAL(data_str.size(), (unsigned int)frame_size);
+      string output = buffer->getBufferAsString();
+      BOOST_CHECK_EQUAL(data_str, output);
+    }
+  }
+}
+
+BOOST_AUTO_TEST_CASE( test_FramedTransport_Read ) {
+  init_data();
+
+  for (int d1 = 0; d1 < 3; d1++) {
+    uint8_t data_out[1<<15];
+    shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer());
+    TFramedTransport trans(buffer);
+    int32_t length = sizeof(data);
+    length = (int32_t)htonl((uint32_t)length);
+    buffer->write(reinterpret_cast<uint8_t*>(&length), sizeof(length));
+    buffer->write(data, sizeof(data));
+
+    int offset = 0;
+    int index = 0;
+    while (offset < 1<<15) {
+      // This should work with read because we have one huge frame.
+      trans.read(&data_out[offset], dist[d1][index]);
+      offset += dist[d1][index];
+      index++;
+    }
+
+    BOOST_CHECK(!memcmp(data, data_out, sizeof(data)));
+  }
+}
+
+BOOST_AUTO_TEST_CASE( test_FramedTransport_Write_Read ) {
+  init_data();
+
+  int sizes[] = {
+    12, 15, 16, 17, 20,
+    501, 512, 523,
+    2000, 2048, 2096,
+    1<<14, 1<<17,
+  };
+
+  int probs[] = { 1, 2, 4, 8, 16, 32, };
+
+  foreach (int size, sizes) {
+    foreach (int prob, probs) {
+      for (int d1 = 0; d1 < 3; d1++) {
+        shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer(16));
+        TFramedTransport trans(buffer, size);
+        uint8_t data_out[1<<15];
+        std::vector<int> flush_sizes;
+
+        int write_offset = 0;
+        int write_index = 0;
+        int flush_size = 0;
+        while (write_offset < 1<<15) {
+          trans.write(&data[write_offset], dist[d1][write_index]);
+          write_offset += dist[d1][write_index];
+          flush_size += dist[d1][write_index];
+          write_index++;
+          if (flush_size > 0 && rand()%prob == 0) {
+            flush_sizes.push_back(flush_size);
+            flush_size = 0;
+            trans.flush();
+          }
+        }
+        if (flush_size != 0) {
+          flush_sizes.push_back(flush_size);
+          flush_size = 0;
+          trans.flush();
+        }
+
+        int read_offset = 0;
+        int read_index = 0;
+        foreach (int fsize, flush_sizes) {
+          // We are exploiting an implementation detail of TFramedTransport.
+          // The read buffer starts empty and it will never do more than one
+          // readFrame per read, so we should always get exactly one frame.
+          int got = trans.read(&data_out[read_offset], 1<<15);
+          BOOST_CHECK_EQUAL(got, fsize);
+          read_offset += got;
+          read_index++;
+        }
+
+        BOOST_CHECK_EQUAL((unsigned int)read_offset, sizeof(data));
+        BOOST_CHECK(!memcmp(data, data_out, sizeof(data)));
+      }
+    }
+  }
+}
+
+BOOST_AUTO_TEST_CASE( test_FramedTransport_Empty_Flush ) {
+  init_data();
+
+  string output1("\x00\x00\x00\x01""a", 5);
+  string output2("\x00\x00\x00\x01""a\x00\x00\x00\x02""bc", 11);
+
+  shared_ptr<TMemoryBuffer> buffer(new TMemoryBuffer());
+  TFramedTransport trans(buffer);
+
+  BOOST_CHECK_EQUAL(buffer->getBufferAsString(), "");
+  trans.flush();
+  BOOST_CHECK_EQUAL(buffer->getBufferAsString(), "");
+  trans.flush();
+  trans.flush();
+  BOOST_CHECK_EQUAL(buffer->getBufferAsString(), "");
+  trans.write((const uint8_t*)"a", 1);
+  BOOST_CHECK_EQUAL(buffer->getBufferAsString(), "");
+  trans.flush();
+  BOOST_CHECK_EQUAL(buffer->getBufferAsString(), output1);
+  trans.flush();
+  trans.flush();
+  BOOST_CHECK_EQUAL(buffer->getBufferAsString(), output1);
+  trans.write((const uint8_t*)"bc", 2);
+  BOOST_CHECK_EQUAL(buffer->getBufferAsString(), output1);
+  trans.flush();
+  BOOST_CHECK_EQUAL(buffer->getBufferAsString(), output2);
+  trans.flush();
+  trans.flush();
+  BOOST_CHECK_EQUAL(buffer->getBufferAsString(), output2);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/TFDTransportTest.cpp b/test/TFDTransportTest.cpp
new file mode 100644
index 0000000..1ec538e
--- /dev/null
+++ b/test/TFDTransportTest.cpp
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#include <cstdlib>
+#include <stdexcept>
+#include <Thrift.h>
+#include <transport/TFDTransport.h>
+using apache::thrift::transport::TTransportException;
+using apache::thrift::transport::TFDTransport;
+
+class DummyException : std::exception {
+};
+
+int main() {
+  {
+    TFDTransport t(256, TFDTransport::NO_CLOSE_ON_DESTROY);
+  }
+
+  try {
+    {
+      TFDTransport t(256, TFDTransport::CLOSE_ON_DESTROY);
+    }
+    std::abort();
+  } catch (TTransportException) {
+  }
+
+  try {
+    {
+      TFDTransport t(256, TFDTransport::CLOSE_ON_DESTROY);
+      throw DummyException();
+    }
+    std::abort();
+  } catch (TTransportException&) {
+    abort();
+  } catch (DummyException&) {
+  }
+
+  return 0;
+
+}
diff --git a/test/TMemoryBufferTest.cpp b/test/TMemoryBufferTest.cpp
new file mode 100644
index 0000000..49bd10b
--- /dev/null
+++ b/test/TMemoryBufferTest.cpp
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ */
+
+#include <boost/test/unit_test.hpp>
+#include <iostream>
+#include <climits>
+#include <cassert>
+#include <transport/TBufferTransports.h>
+#include <protocol/TBinaryProtocol.h>
+#include "gen-cpp/ThriftTest_types.h"
+
+BOOST_AUTO_TEST_SUITE( TMemoryBufferTest )
+
+BOOST_AUTO_TEST_CASE( test_roundtrip ) {
+    using apache::thrift::transport::TMemoryBuffer;
+    using apache::thrift::protocol::TBinaryProtocol;
+    using boost::shared_ptr;
+
+    shared_ptr<TMemoryBuffer> strBuffer(new TMemoryBuffer());
+    shared_ptr<TBinaryProtocol> binaryProtcol(new TBinaryProtocol(strBuffer));
+
+    thrift::test::Xtruct a;
+    a.i32_thing = 10;
+    a.i64_thing = 30;
+    a.string_thing ="holla back a";
+
+    a.write(binaryProtcol.get());
+    std::string serialized = strBuffer->getBufferAsString();
+
+    shared_ptr<TMemoryBuffer> strBuffer2(new TMemoryBuffer());
+    shared_ptr<TBinaryProtocol> binaryProtcol2(new TBinaryProtocol(strBuffer2));
+
+    strBuffer2->resetBuffer((uint8_t*)serialized.data(), serialized.length());
+    thrift::test::Xtruct a2;
+    a2.read(binaryProtcol2.get());
+
+    assert(a == a2);
+  }
+
+BOOST_AUTO_TEST_CASE( test_copy )
+  {
+    using apache::thrift::transport::TMemoryBuffer;
+    using std::string;
+    using std::cout;
+    using std::endl;
+
+    string* str1 = new string("abcd1234");
+    const char* data1 = str1->data();
+    TMemoryBuffer buf((uint8_t*)str1->data(), str1->length(), TMemoryBuffer::COPY);
+    delete str1;
+    string* str2 = new string("plsreuse");
+    bool obj_reuse = (str1 == str2);
+    bool dat_reuse = (data1 == str2->data());
+    cout << "Object reuse: " << obj_reuse << "   Data reuse: " << dat_reuse
+      << ((obj_reuse && dat_reuse) ? "   YAY!" : "") << endl;
+    delete str2;
+
+    string str3 = "wxyz", str4 = "6789";
+    buf.readAppendToString(str3, 4);
+    buf.readAppendToString(str4, INT_MAX);
+
+    assert(str3 == "wxyzabcd");
+    assert(str4 == "67891234");
+  }
+
+BOOST_AUTO_TEST_CASE( test_exceptions )
+  {
+    using apache::thrift::transport::TTransportException;
+    using apache::thrift::transport::TMemoryBuffer;
+    using std::string;
+
+    char data[] = "foo\0bar";
+
+    TMemoryBuffer buf1((uint8_t*)data, 7, TMemoryBuffer::OBSERVE);
+    string str = buf1.getBufferAsString();
+    assert(str.length() == 7);
+    buf1.resetBuffer();
+    try {
+      buf1.write((const uint8_t*)"foo", 3);
+      assert(false);
+    } catch (TTransportException& ex) {}
+
+    TMemoryBuffer buf2((uint8_t*)data, 7, TMemoryBuffer::COPY);
+    try {
+      buf2.write((const uint8_t*)"bar", 3);
+    } catch (TTransportException& ex) {
+      assert(false);
+    }
+  }
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/TPipedTransportTest.cpp b/test/TPipedTransportTest.cpp
new file mode 100644
index 0000000..5708fd2
--- /dev/null
+++ b/test/TPipedTransportTest.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+#include <cstdlib>
+#include <stdexcept>
+#include <Thrift.h>
+#include <transport/TTransportUtils.h>
+#include <transport/TBufferTransports.h>
+using namespace std;
+using boost::shared_ptr;
+using apache::thrift::transport::TTransportException;
+using apache::thrift::transport::TPipedTransport;
+using apache::thrift::transport::TMemoryBuffer;
+
+int main() {
+  shared_ptr<TMemoryBuffer> underlying(new TMemoryBuffer);
+  shared_ptr<TMemoryBuffer> pipe(new TMemoryBuffer);
+  shared_ptr<TPipedTransport> trans(new TPipedTransport(underlying, pipe));
+
+  uint8_t buffer[4];
+
+  underlying->write((uint8_t*)"abcd", 4);
+  trans->readAll(buffer, 2);
+  assert( string((char*)buffer, 2) == "ab" );
+  trans->readEnd();
+  assert( pipe->getBufferAsString() == "ab" );
+  pipe->resetBuffer();
+  underlying->write((uint8_t*)"ef", 2);
+  trans->readAll(buffer, 2);
+  assert( string((char*)buffer, 2) == "cd" );
+  trans->readAll(buffer, 2);
+  assert( string((char*)buffer, 2) == "ef" );
+  trans->readEnd();
+  assert( pipe->getBufferAsString() == "cdef" );
+
+  return 0;
+
+}
diff --git a/test/ThriftTest.thrift b/test/ThriftTest.thrift
new file mode 100644
index 0000000..3517640
--- /dev/null
+++ b/test/ThriftTest.thrift
@@ -0,0 +1,172 @@
+/*
+ * 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.
+ */
+
+namespace java thrift.test
+namespace cpp thrift.test
+namespace rb Thrift.Test
+namespace perl ThriftTest
+namespace csharp Thrift.Test
+
+enum Numberz
+{
+  ONE = 1,
+  TWO,
+  THREE,
+  FIVE = 5,
+  SIX,
+  EIGHT = 8
+}
+
+typedef i64 UserId
+
+struct Bonk
+{
+  1: string message,
+  2: i32 type
+}
+
+struct Bools {
+  1: bool im_true,
+  2: bool im_false,
+}
+
+struct Xtruct
+{
+  1:  string string_thing,
+  4:  byte   byte_thing,
+  9:  i32    i32_thing,
+  11: i64    i64_thing
+}
+
+struct Xtruct2
+{
+  1: byte   byte_thing,
+  2: Xtruct struct_thing,
+  3: i32    i32_thing
+}
+
+struct Xtruct3
+{
+  1:  string string_thing,
+  4:  i32    changed,
+  9:  i32    i32_thing,
+  11: i64    i64_thing
+}
+
+
+struct Insanity
+{
+  1: map<Numberz, UserId> userMap,
+  2: list<Xtruct> xtructs
+}
+
+struct CrazyNesting {
+  1: string string_field,
+  2: optional set<Insanity> set_field,
+  3: required list< map<set<i32>,map<i32,set<list<map<Insanity,string>>>>>> list_field
+}
+
+exception Xception {
+  1: i32 errorCode,
+  2: string message
+}
+
+exception Xception2 {
+  1: i32 errorCode,
+  2: Xtruct struct_thing
+}
+
+struct EmptyStruct {}
+
+struct OneField {
+  1: EmptyStruct field
+}
+
+service ThriftTest
+{
+  void         testVoid(),
+  string       testString(1: string thing),
+  byte         testByte(1: byte thing),
+  i32          testI32(1: i32 thing),
+  i64          testI64(1: i64 thing),
+  double       testDouble(1: double thing),
+  Xtruct       testStruct(1: Xtruct thing),
+  Xtruct2      testNest(1: Xtruct2 thing),
+  map<i32,i32> testMap(1: map<i32,i32> thing),
+  set<i32>     testSet(1: set<i32> thing),
+  list<i32>    testList(1: list<i32> thing),
+  Numberz      testEnum(1: Numberz thing),
+  UserId       testTypedef(1: UserId thing),
+
+  map<i32,map<i32,i32>> testMapMap(1: i32 hello),
+
+  /* So you think you've got this all worked, out eh? */
+  map<UserId, map<Numberz,Insanity>> testInsanity(1: Insanity argument),
+
+  /* Multiple parameters */
+  Xtruct testMulti(1: byte arg0, 2: i32 arg1, 3: i64 arg2, 4: map<i16, string> arg3, 5: Numberz arg4, 6: UserId arg5),
+
+  /* Exception specifier */
+
+  void testException(1: string arg) throws(1: Xception err1),
+
+  /* Multiple exceptions specifier */
+
+  Xtruct testMultiException(1: string arg0, 2: string arg1) throws(1: Xception err1, 2: Xception2 err2)
+
+  /* Test oneway void */
+  oneway void testOneway(1:i32 secondsToSleep)
+}
+
+service SecondService
+{
+  void blahBlah()
+}
+
+struct VersioningTestV1 {
+       1: i32 begin_in_both,
+       3: string old_string,
+       12: i32 end_in_both
+}
+
+struct VersioningTestV2 {
+       1: i32 begin_in_both,
+
+       2: i32 newint,
+       3: byte newbyte,
+       4: i16 newshort,
+       5: i64 newlong,
+       6: double newdouble
+       7: Bonk newstruct,
+       8: list<i32> newlist,
+       9: set<i32> newset,
+       10: map<i32, i32> newmap,
+       11: string newstring,
+       12: i32 end_in_both
+}
+
+struct ListTypeVersioningV1 {
+       1: list<i32> myints;
+       2: string hello;
+}
+
+struct ListTypeVersioningV2 {
+       1: list<string> strings;
+       2: string hello;
+}
diff --git a/test/ThriftTest_extras.cpp b/test/ThriftTest_extras.cpp
new file mode 100644
index 0000000..b78f276
--- /dev/null
+++ b/test/ThriftTest_extras.cpp
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+// Extra functions required for ThriftTest_types to work
+
+#include <protocol/TDebugProtocol.h>
+#include "gen-cpp/ThriftTest_types.h"
+
+
+namespace thrift { namespace test {
+
+bool Insanity::operator<(thrift::test::Insanity const& other) const {
+  using apache::thrift::ThriftDebugString;
+  return ThriftDebugString(*this) < ThriftDebugString(other);
+}
+
+}}
diff --git a/test/UnitTestMain.cpp b/test/UnitTestMain.cpp
new file mode 100644
index 0000000..d90c54f
--- /dev/null
+++ b/test/UnitTestMain.cpp
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+#define BOOST_TEST_MODULE thrift
+#include <boost/test/included/unit_test.hpp>
diff --git a/test/ZlibTest.cpp b/test/ZlibTest.cpp
new file mode 100644
index 0000000..45d3ecc
--- /dev/null
+++ b/test/ZlibTest.cpp
@@ -0,0 +1,310 @@
+/*
+ * 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.
+ */
+
+/*
+thrift --gen cpp DebugProtoTest.thrift
+g++ -Wall -g -I../lib/cpp/src -I/usr/local/include/boost-1_33_1 \
+  ZlibTest.cpp \
+  ../lib/cpp/.libs/libthriftz.a ../lib/cpp/.libs/libthrift.a \
+  -lz -o ZlibTest
+./ZlibTest
+*/
+
+#include <cstddef>
+#include <cassert>
+#include <fstream>
+#include <iostream>
+#include <transport/TBufferTransports.h>
+#include <transport/TZlibTransport.h>
+
+
+// Distributions of reads and writes meant to approximate a real load,
+// mixing up small and large while also hitting various boundary conditions.
+// Generated by Python: int(random.lognormvariate(2.5, 1))
+unsigned int dist[][5000] = {
+ { 1<<15 },
+
+ {
+  5,13,9,1,8,9,11,13,18,48,24,13,21,13,5,11,35,2,4,20,17,72,27,14,15,4,7,26,
+  12,1,14,9,2,16,29,41,7,24,4,27,14,4,1,4,25,3,6,34,10,8,50,2,14,13,55,29,3,
+  43,53,49,14,4,10,32,27,48,1,3,1,11,5,17,16,51,17,30,15,11,9,2,2,11,52,12,2,
+  13,94,1,19,1,38,2,8,43,8,33,7,30,8,17,22,2,15,14,12,34,2,12,6,37,29,74,3,
+  165,16,11,17,5,14,3,10,7,37,11,24,7,1,3,12,37,8,9,34,17,12,8,21,13,37,1,4,
+  30,14,78,4,15,2,40,37,17,12,36,82,14,4,1,4,7,17,11,16,88,77,2,3,15,3,34,11,
+  5,79,22,34,8,4,4,40,22,24,28,9,13,3,34,27,9,16,39,16,39,13,2,4,3,41,26,10,4,
+  33,4,7,12,5,6,3,10,30,8,21,16,58,19,9,0,47,7,13,11,19,15,7,53,57,2,13,28,22,
+  3,16,9,25,33,12,40,7,12,64,7,14,24,44,9,2,14,11,2,58,1,26,30,11,9,5,24,7,9,
+  94,2,10,21,5,5,4,5,6,179,9,18,2,7,13,31,41,17,4,36,3,21,6,26,8,15,18,44,27,
+  11,9,25,7,0,14,2,12,20,23,13,2,163,9,5,15,65,2,14,6,8,98,11,15,14,34,2,3,10,
+  22,9,92,7,10,32,67,13,3,4,35,8,2,1,5,0,26,381,7,27,8,2,16,93,4,19,5,8,25,9,
+  31,14,4,21,5,3,9,22,56,4,18,3,11,18,6,4,3,40,12,16,110,8,35,14,1,18,40,9,12,
+  14,3,11,7,57,13,18,116,53,19,22,7,16,11,5,8,21,16,1,75,21,20,1,28,2,6,1,7,
+  19,38,5,6,9,9,4,1,7,55,36,62,5,4,4,24,15,1,12,35,48,20,5,17,1,5,26,15,4,54,
+  13,5,5,15,5,19,32,29,31,7,6,40,7,80,11,18,8,128,48,6,12,84,13,4,7,2,13,9,16,
+  17,3,254,1,4,181,8,44,7,6,24,27,9,23,14,34,16,22,25,10,3,3,4,4,12,2,12,6,7,
+  13,58,13,6,11,19,53,11,66,18,19,10,4,13,2,5,49,58,1,67,7,21,64,14,11,14,8,3,
+  26,33,91,31,20,7,9,42,39,4,3,55,11,10,0,7,4,75,8,12,0,27,3,8,9,0,12,12,23,
+  28,23,20,4,13,30,2,22,20,19,30,6,22,2,6,4,24,7,19,55,86,5,33,2,161,6,7,1,62,
+  13,3,72,12,12,9,7,12,10,5,10,29,1,5,22,13,13,5,2,12,3,7,14,18,2,3,46,21,17,
+  15,19,3,27,5,16,45,31,10,8,17,18,18,3,7,24,6,55,9,3,6,12,10,12,8,91,9,4,4,4,
+  27,29,16,5,7,22,43,28,11,14,8,11,28,109,55,71,40,3,8,22,26,15,44,3,25,29,5,
+  3,32,17,12,3,29,27,25,15,11,8,40,39,38,17,3,9,11,2,32,11,6,20,48,75,27,3,7,
+  54,12,95,12,7,24,23,2,13,8,15,16,5,12,4,17,7,19,88,2,6,13,115,45,12,21,2,86,
+  74,9,7,5,16,32,16,2,21,18,6,34,5,18,260,7,12,16,44,19,92,31,7,8,2,9,0,0,15,
+  8,38,4,8,20,18,2,83,3,3,4,9,5,3,10,3,5,29,15,7,11,8,48,17,23,2,17,4,11,22,
+  21,64,8,8,4,19,95,0,17,28,9,11,20,71,5,11,18,12,13,45,49,4,1,33,32,23,13,5,
+  52,2,2,16,3,4,7,12,2,1,12,6,24,1,22,155,21,3,45,4,12,44,26,5,40,36,9,9,8,20,
+  35,31,3,2,32,50,10,8,37,2,75,35,22,15,192,8,11,23,1,4,29,6,8,8,5,12,18,32,4,
+  7,12,2,0,0,9,5,48,11,35,3,1,123,6,29,8,11,8,23,51,16,6,63,12,2,5,4,14,2,15,
+  7,14,3,2,7,17,32,8,8,10,1,23,62,2,49,6,49,47,23,3,20,7,11,39,10,24,6,15,5,5,
+  11,8,16,36,8,13,20,3,10,44,7,52,7,10,36,6,15,10,5,11,4,14,19,17,10,12,3,6,
+  23,4,13,94,70,7,36,7,38,7,28,8,4,15,3,19,4,33,39,21,109,4,80,6,40,4,432,4,4,
+  7,8,3,31,8,28,37,34,10,2,21,5,22,0,7,36,14,12,6,24,1,21,5,9,2,29,20,54,113,
+  13,31,39,27,6,0,27,4,5,2,43,7,8,57,8,62,7,9,12,22,90,30,6,19,7,10,20,6,5,58,
+  32,30,41,4,10,25,13,3,8,7,10,2,9,6,151,44,16,12,16,20,8,3,18,11,17,4,10,45,
+  15,8,56,38,52,25,40,14,4,17,15,8,2,19,7,8,26,30,2,3,180,8,26,17,38,35,5,16,
+  28,5,15,56,13,14,18,9,15,83,27,3,9,4,11,8,27,27,44,10,12,8,3,48,14,7,9,4,4,
+  8,4,5,9,122,8,14,12,19,17,21,4,29,63,21,17,10,12,18,47,10,10,53,4,18,16,4,8,
+  118,9,5,12,9,11,9,3,12,32,3,23,2,15,3,3,30,3,17,235,15,22,9,299,14,17,1,5,
+  16,8,3,7,3,13,2,7,6,4,8,66,2,13,6,15,16,47,3,36,5,7,10,24,1,9,9,8,13,16,26,
+  12,7,24,21,18,49,23,39,10,41,4,13,4,27,11,12,12,19,4,147,8,10,9,40,21,2,83,
+  10,5,6,11,25,9,50,57,40,12,12,21,1,3,24,23,9,3,9,13,2,3,12,57,8,11,13,15,26,
+  15,10,47,36,4,25,1,5,8,5,4,0,12,49,5,19,4,6,16,14,6,10,69,10,33,29,7,8,61,
+  12,4,0,3,7,6,3,16,29,27,38,4,21,0,24,3,2,1,19,16,22,2,8,138,11,7,7,3,12,22,
+  3,16,5,7,3,53,9,10,32,14,5,7,3,6,22,9,59,26,8,7,58,5,16,11,55,7,4,11,146,91,
+  8,13,18,14,6,8,8,31,26,22,6,11,30,11,30,15,18,31,3,48,17,7,6,4,9,2,25,3,35,
+  13,13,7,8,4,31,10,8,10,4,3,45,10,23,2,7,259,17,21,13,14,3,26,3,8,27,4,18,9,
+  66,7,12,5,8,17,4,23,55,41,51,2,32,26,66,4,21,14,12,65,16,22,17,5,14,2,29,24,
+  7,3,36,2,43,53,86,5,28,4,58,13,49,121,6,2,73,2,1,47,4,2,27,10,35,28,27,10,
+  17,10,56,7,10,14,28,20,24,40,7,4,7,3,10,11,32,6,6,3,15,11,54,573,2,3,6,2,3,
+  14,64,4,16,12,16,42,10,26,4,6,11,69,18,27,2,2,17,22,9,13,22,11,6,1,15,49,3,
+  14,1
+ },
+
+ {
+  11,11,11,15,47,1,3,1,23,5,8,18,3,23,15,21,1,7,19,10,26,1,17,11,31,21,41,18,
+  34,4,9,58,19,3,3,36,5,18,13,3,14,4,9,10,4,19,56,15,3,5,3,11,27,9,4,10,13,4,
+  11,6,9,2,18,3,10,19,11,4,53,4,2,2,3,4,58,16,3,0,5,30,2,11,93,10,2,14,10,6,2,
+  115,2,25,16,22,38,101,4,18,13,2,145,51,45,15,14,15,13,20,7,24,5,13,14,30,40,
+  10,4,107,12,24,14,39,12,6,13,20,7,7,11,5,18,18,45,22,6,39,3,2,1,51,9,11,4,
+  13,9,38,44,8,11,9,15,19,9,23,17,17,17,13,9,9,1,10,4,18,6,2,9,5,27,32,72,8,
+  37,9,4,10,30,17,20,15,17,66,10,4,73,35,37,6,4,16,117,45,13,4,75,5,24,65,10,
+  4,9,4,13,46,5,26,29,10,4,4,52,3,13,18,63,6,14,9,24,277,9,88,2,48,27,123,14,
+  61,7,5,10,8,7,90,3,10,3,3,48,17,13,10,18,33,2,19,36,6,21,1,16,12,5,6,2,16,
+  15,29,88,28,2,15,6,11,4,6,11,3,3,4,18,9,53,5,4,3,33,8,9,8,6,7,36,9,62,14,2,
+  1,10,1,16,7,32,7,23,20,11,10,23,2,1,0,9,16,40,2,81,5,22,8,5,4,37,51,37,10,
+  19,57,11,2,92,31,6,39,10,13,16,8,20,6,9,3,10,18,25,23,12,30,6,2,26,7,64,18,
+  6,30,12,13,27,7,10,5,3,33,24,99,4,23,4,1,27,7,27,49,8,20,16,3,4,13,9,22,67,
+  28,3,10,16,3,2,10,4,8,1,8,19,3,85,6,21,1,9,16,2,30,10,33,12,4,9,3,1,60,38,6,
+  24,32,3,14,3,40,8,34,115,5,9,27,5,96,3,40,6,15,5,8,22,112,5,5,25,17,58,2,7,
+  36,21,52,1,3,95,12,21,4,11,8,59,24,5,21,4,9,15,8,7,21,3,26,5,11,6,7,17,65,
+  14,11,10,2,17,5,12,22,4,4,2,21,8,112,3,34,63,35,2,25,1,2,15,65,23,0,3,5,15,
+  26,27,9,5,48,11,15,4,9,5,33,20,15,1,18,19,11,24,40,10,21,74,6,6,32,30,40,5,
+  4,7,44,10,25,46,16,12,5,40,7,18,5,18,9,12,8,4,25,5,6,36,4,43,8,9,12,35,17,4,
+  8,9,11,27,5,10,17,40,8,12,4,18,9,18,12,20,25,39,42,1,24,13,22,15,7,112,35,3,
+  7,17,33,2,5,5,19,8,4,12,24,14,13,2,1,13,6,5,19,11,7,57,0,19,6,117,48,14,8,
+  10,51,17,12,14,2,5,8,9,15,4,48,53,13,22,4,25,12,11,19,45,5,2,6,54,22,9,15,9,
+  13,2,7,11,29,82,16,46,4,26,14,26,40,22,4,26,6,18,13,4,4,20,3,3,7,12,17,8,9,
+  23,6,20,7,25,23,19,5,15,6,23,15,11,19,11,3,17,59,8,18,41,4,54,23,44,75,13,
+  20,6,11,2,3,1,13,10,3,7,12,3,4,7,8,30,6,6,7,3,32,9,5,28,6,114,42,13,36,27,
+  59,6,93,13,74,8,69,140,3,1,17,48,105,6,11,5,15,1,10,10,14,8,53,0,8,24,60,2,
+  6,35,2,12,32,47,16,17,75,2,5,4,37,28,10,5,9,57,4,59,5,12,13,7,90,5,11,5,24,
+  22,13,30,1,2,10,9,6,19,3,18,47,2,5,7,9,35,15,3,6,1,21,14,14,18,14,9,12,8,73,
+  6,19,3,32,9,14,17,17,5,55,23,6,16,28,3,11,48,4,6,6,6,12,16,30,10,30,27,51,
+  18,29,2,3,15,1,76,0,16,33,4,27,3,62,4,10,2,4,8,15,9,41,26,22,2,4,20,4,49,0,
+  8,1,57,13,12,39,3,63,10,19,34,35,2,7,8,29,72,4,10,0,77,8,6,7,9,15,21,9,4,1,
+  20,23,1,9,18,9,15,36,4,7,6,15,5,7,7,40,2,9,22,2,3,20,4,12,34,13,6,18,15,1,
+  38,20,12,7,16,3,19,85,12,16,18,16,2,17,1,13,8,6,12,15,97,17,12,9,3,21,15,12,
+  23,44,81,26,30,2,5,17,6,6,0,22,42,19,6,19,41,14,36,7,3,56,7,9,3,2,6,9,69,3,
+  15,4,30,28,29,7,9,15,17,17,6,1,6,153,9,33,5,12,14,16,28,3,8,7,14,12,4,6,36,
+  9,24,13,13,4,2,9,15,19,9,53,7,13,4,150,17,9,2,6,12,7,3,5,58,19,58,28,8,14,3,
+  20,3,0,32,56,7,5,4,27,1,68,4,29,13,5,58,2,9,65,41,27,16,15,12,14,2,10,9,24,
+  3,2,9,2,2,3,14,32,10,22,3,13,11,4,6,39,17,0,10,5,5,10,35,16,19,14,1,8,63,19,
+  14,8,56,10,2,12,6,12,6,7,16,2,9,9,12,20,73,25,13,21,17,24,5,32,8,12,25,8,14,
+  16,5,23,3,7,6,3,11,24,6,30,4,21,13,28,4,6,29,15,5,17,6,26,8,15,8,3,7,7,50,
+  11,30,6,2,28,56,16,24,25,23,24,89,31,31,12,7,22,4,10,17,3,3,8,11,13,5,3,27,
+  1,12,1,14,8,10,29,2,5,2,2,20,10,0,31,10,21,1,48,3,5,43,4,5,18,13,5,18,25,34,
+  18,3,5,22,16,3,4,20,3,9,3,25,6,6,44,21,3,12,7,5,42,3,2,14,4,36,5,3,45,51,15,
+  9,11,28,9,7,6,6,12,26,5,14,10,11,42,55,13,21,4,28,6,7,23,27,11,1,41,36,0,32,
+  15,26,2,3,23,32,11,2,15,7,29,26,144,33,20,12,7,21,10,7,11,65,46,10,13,20,32,
+  4,4,5,19,2,19,15,49,41,1,75,10,11,25,1,2,45,11,8,27,18,10,60,28,29,12,30,19,
+  16,4,24,11,19,27,17,49,18,7,40,13,19,22,8,55,12,11,3,6,5,11,8,10,22,5,9,9,
+  25,7,17,7,64,1,24,2,12,17,44,4,12,27,21,11,10,7,47,5,9,13,12,38,27,21,7,29,
+  7,1,17,3,3,5,48,62,10,3,11,17,15,15,6,3,8,10,8,18,19,13,3,9,7,6,44,9,10,4,
+  43,8,6,6,14,20,38,24,2,4,5,5,7,5,9,39,8,44,40,9,19,7,3,15,25,2,37,18,15,9,5,
+  8,32,10,5,18,4,7,46,20,17,23,4,11,16,18,31,11,3,11,1,14,1,25,4,27,13,13,39,
+  14,6,6,35,6,16,13,11,122,21,15,20,24,10,5,152,15,39,5,20,16,9,14,7,53,6,3,8,
+  19,63,32,6,2,3,20,1,19,5,13,42,15,4,6,68,31,46,11,38,10,24,5,5,8,9,12,3,35,
+  46,26,16,2,8,4,74,16,44,4,5,1,16,4,14,23,16,69,15,42,31,14,7,7,6,97,14,40,1,
+  8,7,34,9,39,19,13,15,10,21,18,10,5,15,38,7,5,12,7,20,15,4,11,6,14,5,17,7,39,
+  35,36,18,20,26,22,4,2,36,21,64,0,5,9,10,6,4,1,7,3,1,3,3,4,10,20,90,2,22,48,
+  16,23,2,33,40,1,21,21,17,20,8,8,12,4,83,14,48,4,21,3,9,27,5,11,40,15,9,3,16,
+  17,9,11,4,24,31,17,3,4,2,11,1,8,4,8,6,41,17,4,13,3,7,17,8,27,5,13,6,10,7,13,
+  12,18,13,60,18,3,8,1,12,125,2,7,16,2,11,2,4,7,26,5,9,14,14,16,8,14,7,14,6,9,
+  13,9,6,4,26,35,49,36,55,3,9,6,40,26,23,31,19,41,2,10,31,6,54,5,69,16,7,8,16,
+  1,5,7,4,22,7,7,5,4,48,11,13,3,98,4,11,19,4,2,14,7,34,7,10,3,2,12,7,6,2,5,118
+ },
+};
+
+
+int main() {
+  using namespace std;
+  using namespace boost;
+  using namespace apache::thrift::transport;
+
+  char *file_names[] = {
+    // Highly compressible.
+    "./gen-cpp/DebugProtoTest_types.cpp",
+    // Uncompressible.
+    "/dev/urandom",
+    // Null-terminated.
+    NULL,
+  };
+
+
+  for (char** fnamep = &file_names[0]; *fnamep != NULL; fnamep++) {
+    ifstream file(*fnamep);
+    char buf[32*1024];
+    file.read(buf, sizeof(buf));
+    vector<uint8_t> content(buf, buf+file.gcount());
+    vector<uint8_t> mirror;
+    file.close();
+
+    assert(content.size() == 32*1024);
+
+    // Let's just start with the big dog!
+    {
+      mirror.clear();
+      shared_ptr<TMemoryBuffer> membuf(new TMemoryBuffer());
+      shared_ptr<TZlibTransport> zlib_trans(new TZlibTransport(membuf, false));
+      zlib_trans->write(&content[0], content.size());
+      zlib_trans->flush();
+      mirror.resize(content.size());
+      uint32_t got = zlib_trans->read(&mirror[0], mirror.size());
+      assert(got == content.size());
+      assert(mirror == content);
+      zlib_trans->verifyChecksum();
+    }
+
+    // This one is tricky.  I separate the last byte of the stream out
+    // into a separate crbuf_.  The last byte is part of the checksum,
+    // so the entire read goes fine, but when I go to verify the checksum
+    // it isn't there.  The original implementation complained that
+    // the stream was not complete.  I'm about to go fix that.
+    // It worked.  Awesome.
+    {
+      mirror.clear();
+      shared_ptr<TMemoryBuffer> membuf(new TMemoryBuffer());
+      shared_ptr<TZlibTransport> zlib_trans(new TZlibTransport(membuf, false));
+      zlib_trans->write(&content[0], content.size());
+      zlib_trans->flush();
+      string tmp_buf;
+      membuf->appendBufferToString(tmp_buf);
+      zlib_trans.reset(new TZlibTransport(membuf, false,
+            TZlibTransport::DEFAULT_URBUF_SIZE,
+            tmp_buf.length()-1));
+      mirror.resize(content.size());
+      uint32_t got = zlib_trans->read(&mirror[0], mirror.size());
+      assert(got == content.size());
+      assert(mirror == content);
+      zlib_trans->verifyChecksum();
+    }
+
+    // Make sure we still get that "not complete" error if
+    // it really isn't complete.
+    {
+      mirror.clear();
+      shared_ptr<TMemoryBuffer> membuf(new TMemoryBuffer());
+      shared_ptr<TZlibTransport> zlib_trans(new TZlibTransport(membuf, false));
+      zlib_trans->write(&content[0], content.size());
+      zlib_trans->flush();
+      string tmp_buf;
+      membuf->appendBufferToString(tmp_buf);
+      tmp_buf.erase(tmp_buf.length() - 1);
+      membuf->resetFromString(tmp_buf);
+      mirror.resize(content.size());
+      uint32_t got = zlib_trans->read(&mirror[0], mirror.size());
+      assert(got == content.size());
+      assert(mirror == content);
+      try {
+        zlib_trans->verifyChecksum();
+        assert(false);
+      } catch (TTransportException& ex) {
+        assert(ex.getType() == TTransportException::CORRUPTED_DATA);
+      }
+    }
+
+    // Try it with a mix of read/write sizes.
+    for (int d1 = 0; d1 < 3; d1++) {
+      for (int d2 = 0; d2 < 3; d2++) {
+        mirror.clear();
+        shared_ptr<TMemoryBuffer> membuf(new TMemoryBuffer());
+        shared_ptr<TZlibTransport> zlib_trans(new TZlibTransport(membuf, false));
+        int idx;
+        unsigned int tot;
+
+        idx = 0;
+        tot = 0;
+        while (tot < content.size()) {
+          zlib_trans->write(&content[tot], dist[d1][idx]);
+          tot += dist[d1][idx];
+          idx++;
+        }
+
+        zlib_trans->flush();
+        mirror.resize(content.size());
+
+        idx = 0;
+        tot = 0;
+        while (tot < mirror.size()) {
+          uint32_t got = zlib_trans->read(&mirror[tot], dist[d2][idx]);
+          assert(got == dist[d2][idx]);
+          tot += dist[d2][idx];
+          idx++;
+        }
+
+        assert(mirror == content);
+        zlib_trans->verifyChecksum();
+      }
+    }
+
+    // Verify checksum checking.
+    {
+      mirror.clear();
+      shared_ptr<TMemoryBuffer> membuf(new TMemoryBuffer());
+      shared_ptr<TZlibTransport> zlib_trans(new TZlibTransport(membuf, false));
+      zlib_trans->write(&content[0], content.size());
+      zlib_trans->flush();
+      string tmp_buf;
+      membuf->appendBufferToString(tmp_buf);
+      tmp_buf[57]++;
+      membuf->resetFromString(tmp_buf);
+      mirror.resize(content.size());
+      try {
+        zlib_trans->read(&mirror[0], mirror.size());
+        zlib_trans->verifyChecksum();
+        assert(false);
+      } catch (TZlibTransportException& ex) {
+        assert(ex.getType() == TTransportException::INTERNAL_ERROR);
+      }
+    }
+  }
+
+  return 0;
+}
diff --git a/test/cpp/Stress-test.mk b/test/cpp/Stress-test.mk
new file mode 100644
index 0000000..1a753b3
--- /dev/null
+++ b/test/cpp/Stress-test.mk
@@ -0,0 +1,71 @@
+#
+# 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.
+#
+
+ifndef thrift_home
+thrift_home=../..
+endif #thrift_home
+
+target: all
+
+ifndef boost_home
+#boost_home=../../../../../thirdparty/boost_1_33_1
+boost_home=/usr/local/include/boost-1_33_1
+endif #boost_home
+target: all
+
+include_paths = $(thrift_home)/lib/cpp/src \
+                $(thrift_home)/lib/cpp \
+                $(thrift_home)/ \
+                $(boost_home)
+
+include_flags = $(patsubst %,-I%, $(include_paths))
+
+# Tools
+ifndef THRIFT
+THRIFT = ../../compiler/cpp/thrift
+endif # THRIFT
+
+CC     = g++
+LD     = g++
+
+# Compiler flags
+DCFL  = -Wall -O3 -g -I./gen-cpp $(include_flags) -L$(thrift_home)/lib/cpp/.libs -lthrift -lthriftnb -levent
+CFL   = -Wall -O3 -I./gen-cpp $(include_flags) -L$(thrift_home)/lib/cpp/.libs -lthrift -lthriftnb -levent
+
+all: stress-test stress-test-nb
+
+debug: stress-test-debug stress-test-debug-nb
+
+stubs: ../StressTest.thrift
+	$(THRIFT) --gen cpp --gen php ../StressTest.thrift
+
+stress-test-debug-nb: stubs
+	g++ -o stress-test-nb $(DCFL) src/nb-main.cpp ./gen-cpp/Service.cpp gen-cpp/StressTest_types.cpp
+
+stress-test-nb: stubs
+	g++ -o stress-test-nb $(CFL) src/nb-main.cpp ./gen-cpp/Service.cpp gen-cpp/StressTest_types.cpp
+
+stress-test-debug: stubs
+	g++ -o stress-test $(DCFL) src/main.cpp ./gen-cpp/Service.cpp gen-cpp/StressTest_types.cpp
+
+stress-test: stubs
+	g++ -o stress-test $(CFL) src/main.cpp ./gen-cpp/Service.cpp gen-cpp/StressTest_types.cpp
+
+clean:
+	rm -fr stress-test stress-test-nb gen-cpp
diff --git a/test/cpp/Thrift-test.mk b/test/cpp/Thrift-test.mk
new file mode 100644
index 0000000..fb3e38b
--- /dev/null
+++ b/test/cpp/Thrift-test.mk
@@ -0,0 +1,78 @@
+#
+# 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.
+#
+
+# Makefile for Thrift test project.
+# Default target is everything
+
+ifndef thrift_home
+thrift_home=../..
+endif #thrift_home
+
+target: all
+
+ifndef boost_home
+#boost_home=../../../../../thirdparty/boost_1_33_1
+boost_home=/usr/local/include/boost-1_33_1
+endif #boost_home
+target: all
+
+include_paths = $(thrift_home)/lib/cpp/src \
+		$(boost_home)
+
+include_flags = $(patsubst %,-I%, $(include_paths))
+
+# Tools
+ifndef THRIFT
+THRIFT = ../../compiler/cpp/thrift
+endif # THRIFT
+
+CC     = g++
+LD     = g++
+
+# Compiler flags
+DCFL  = -Wall -O3 -g -I. -I./gen-cpp $(include_flags) -L$(thrift_home)/lib/cpp/.libs -lthrift -lthriftnb -levent
+LFL   =  -L$(thrift_home)/lib/cpp/.libs -lthrift -lthriftnb -levent
+CCFL  = -Wall -O3 -I. -I./gen-cpp $(include_flags)
+CFL   = $(CCFL) $(LFL)
+
+all: server client
+
+debug: server-debug client-debug
+
+stubs: ../ThriftTest.thrift
+	$(THRIFT) --gen cpp ../ThriftTest.thrift
+
+server-debug: stubs
+	g++ -o TestServer $(DCFL) src/TestServer.cpp ./gen-cpp/ThriftTest.cpp ./gen-cpp/ThriftTest_types.cpp ../ThriftTest_extras.cpp
+
+client-debug: stubs
+	g++ -o TestClient $(DCFL) src/TestClient.cpp ./gen-cpp/ThriftTest.cpp ./gen-cpp/ThriftTest_types.cpp ../ThriftTest_extras.cpp
+
+server: stubs
+	g++ -o TestServer $(CFL) src/TestServer.cpp ./gen-cpp/ThriftTest.cpp ./gen-cpp/ThriftTest_types.cpp ../ThriftTest_extras.cpp
+
+client: stubs
+	g++ -o TestClient $(CFL) src/TestClient.cpp ./gen-cpp/ThriftTest.cpp ./gen-cpp/ThriftTest_types.cpp ../ThriftTest_extras.cpp
+
+small:
+	$(THRIFT) --gen cpp ../SmallTest.thrift
+	g++ -c $(CCFL) ./gen-cpp/SmallService.cpp ./gen-cpp/SmallTest_types.cpp
+
+clean:
+	rm -fr *.o TestServer TestClient gen-cpp
diff --git a/test/cpp/realloc/Makefile b/test/cpp/realloc/Makefile
new file mode 100644
index 0000000..f89bbb3
--- /dev/null
+++ b/test/cpp/realloc/Makefile
@@ -0,0 +1,40 @@
+#
+# 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.
+#
+
+# This probably should not go into "make check", because it is an experiment,
+# not a test.  Specifically, it is meant to determine how likely realloc is
+# to avoid a copy.  This is poorly documented.
+
+run: realloc_test
+	for it in 1 4 64 ; do \
+		for nb in 1 8 64 512 ; do \
+			for mins in 64 512 ; do \
+				for maxs in 2048 262144 ; do \
+					for db in 8 64 ; do \
+						./realloc_test $$nb $$mins $$maxs $$db $$it \
+					; done \
+				; done \
+			; done \
+		; done \
+	; done \
+	> raw_stats
+
+CFLAGS = -Wall -g -std=c99
+LDLIBS = -ldl
+realloc_test: realloc_test.c
diff --git a/test/cpp/realloc/realloc_test.c b/test/cpp/realloc/realloc_test.c
new file mode 100644
index 0000000..f9763ad
--- /dev/null
+++ b/test/cpp/realloc/realloc_test.c
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <dlfcn.h>
+
+int copies;
+int non_copies;
+
+void *realloc(void *ptr, size_t size) {
+  static void *(*real_realloc)(void*, size_t) = NULL;
+  if (real_realloc == NULL) {
+    real_realloc = (void* (*) (void*, size_t)) dlsym(RTLD_NEXT, "realloc");
+  }
+
+  void *ret_ptr = (*real_realloc)(ptr, size);
+
+  if (ret_ptr == ptr) {
+    non_copies++;
+  } else {
+    copies++;
+  }
+
+  return ret_ptr;
+}
+
+
+struct TMemoryBuffer {
+  void* ptr;
+  int size;
+};
+
+int main(int argc, char *argv[]) {
+  int num_buffers;
+  int init_size;
+  int max_size;
+  int doublings;
+  int iterations;
+
+  if (argc < 6 ||
+      argc > 7 ||
+      (num_buffers = atoi(argv[1])) == 0 ||
+      (init_size = atoi(argv[2])) == 0 ||
+      (max_size = atoi(argv[3])) == 0 ||
+      init_size > max_size ||
+      (iterations = atoi(argv[4])) == 0 ||
+      (doublings = atoi(argv[5])) == 0 ||
+      (argc == 7 && atoi(argv[6]) == 0)) {
+    fprintf(stderr, "usage: realloc_test <num_buffers> <init_size> <max_size> <doublings> <iterations> [seed]\n");
+    exit(EXIT_FAILURE);
+  }
+
+  for ( int i = 0 ; i < argc ; i++ ) {
+    printf("%s ", argv[i]);
+  }
+  printf("\n");
+
+  if (argc == 7) {
+    srand(atoi(argv[6]));
+  } else {
+    srand(time(NULL));
+  }
+
+  struct TMemoryBuffer* buffers = calloc(num_buffers, sizeof(*buffers));
+  if (buffers == NULL) abort();
+
+  for ( int i = 0 ; i < num_buffers ; i++ ) {
+    buffers[i].size = max_size;
+  }
+
+  while (iterations --> 0) {
+    for ( int i = 0 ; i < doublings * num_buffers ; i++ ) {
+      struct TMemoryBuffer* buf = &buffers[rand() % num_buffers];
+      buf->size *= 2;
+      if (buf->size <= max_size) {
+        buf->ptr = realloc(buf->ptr, buf->size);
+      } else {
+        free(buf->ptr);
+        buf->size = init_size;
+        buf->ptr = malloc(buf->size);
+      }
+      if (buf->ptr == NULL) abort();
+    }
+  }
+
+  printf("Non-copied %d/%d (%.2f%%)\n", non_copies, copies + non_copies, 100.0 * non_copies / (copies + non_copies));
+  return 0;
+}
diff --git a/test/cpp/src/TestClient.cpp b/test/cpp/src/TestClient.cpp
new file mode 100644
index 0000000..5ddfa06
--- /dev/null
+++ b/test/cpp/src/TestClient.cpp
@@ -0,0 +1,497 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <protocol/TBinaryProtocol.h>
+#include <transport/TTransportUtils.h>
+#include <transport/TSocket.h>
+
+#include <boost/shared_ptr.hpp>
+#include "ThriftTest.h"
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+using namespace boost;
+using namespace std;
+using namespace apache::thrift;
+using namespace apache::thrift::protocol;
+using namespace apache::thrift::transport;
+using namespace thrift::test;
+
+//extern uint32_t g_socket_syscalls;
+
+// Current time, microseconds since the epoch
+uint64_t now()
+{
+  long long ret;
+  struct timeval tv;
+
+  gettimeofday(&tv, NULL);
+  ret = tv.tv_sec;
+  ret = ret*1000*1000 + tv.tv_usec;
+  return ret;
+}
+
+int main(int argc, char** argv) {
+  string host = "localhost";
+  int port = 9090;
+  int numTests = 1;
+  bool framed = false;
+
+  for (int i = 0; i < argc; ++i) {
+    if (strcmp(argv[i], "-h") == 0) {
+      char* pch = strtok(argv[++i], ":");
+      if (pch != NULL) {
+        host = string(pch);
+      }
+      pch = strtok(NULL, ":");
+      if (pch != NULL) {
+        port = atoi(pch);
+      }
+    } else if (strcmp(argv[i], "-n") == 0) {
+      numTests = atoi(argv[++i]);
+    } else if (strcmp(argv[i], "-f") == 0) {
+      framed = true;
+    }
+  }
+
+
+  shared_ptr<TTransport> transport;
+
+  shared_ptr<TSocket> socket(new TSocket(host, port));
+
+  if (framed) {
+    shared_ptr<TFramedTransport> framedSocket(new TFramedTransport(socket));
+    transport = framedSocket;
+  } else {
+    shared_ptr<TBufferedTransport> bufferedSocket(new TBufferedTransport(socket));
+    transport = bufferedSocket;
+  }
+
+  shared_ptr<TBinaryProtocol> protocol(new TBinaryProtocol(transport));
+  ThriftTestClient testClient(protocol);
+
+  uint64_t time_min = 0;
+  uint64_t time_max = 0;
+  uint64_t time_tot = 0;
+
+  int test = 0;
+  for (test = 0; test < numTests; ++test) {
+
+    try {
+      transport->open();
+    } catch (TTransportException& ttx) {
+      printf("Connect failed: %s\n", ttx.what());
+      continue;
+    }
+
+    /**
+     * CONNECT TEST
+     */
+    printf("Test #%d, connect %s:%d\n", test+1, host.c_str(), port);
+
+    uint64_t start = now();
+
+    /**
+     * VOID TEST
+     */
+    try {
+      printf("testVoid()");
+      testClient.testVoid();
+      printf(" = void\n");
+    } catch (TApplicationException tax) {
+      printf("%s\n", tax.what());
+    }
+
+    /**
+     * STRING TEST
+     */
+    printf("testString(\"Test\")");
+    string s;
+    testClient.testString(s, "Test");
+    printf(" = \"%s\"\n", s.c_str());
+
+    /**
+     * BYTE TEST
+     */
+    printf("testByte(1)");
+    uint8_t u8 = testClient.testByte(1);
+    printf(" = %d\n", (int)u8);
+
+    /**
+     * I32 TEST
+     */
+    printf("testI32(-1)");
+    int32_t i32 = testClient.testI32(-1);
+    printf(" = %d\n", i32);
+
+    /**
+     * I64 TEST
+     */
+    printf("testI64(-34359738368)");
+    int64_t i64 = testClient.testI64(-34359738368LL);
+    printf(" = %"PRId64"\n", i64);
+
+    /**
+     * DOUBLE TEST
+     */
+    printf("testDouble(-5.2098523)");
+    double dub = testClient.testDouble(-5.2098523);
+    printf(" = %lf\n", dub);
+
+    /**
+     * STRUCT TEST
+     */
+    printf("testStruct({\"Zero\", 1, -3, -5})");
+    Xtruct out;
+    out.string_thing = "Zero";
+    out.byte_thing = 1;
+    out.i32_thing = -3;
+    out.i64_thing = -5;
+    Xtruct in;
+    testClient.testStruct(in, out);
+    printf(" = {\"%s\", %d, %d, %"PRId64"}\n",
+           in.string_thing.c_str(),
+           (int)in.byte_thing,
+           in.i32_thing,
+           in.i64_thing);
+
+    /**
+     * NESTED STRUCT TEST
+     */
+    printf("testNest({1, {\"Zero\", 1, -3, -5}), 5}");
+    Xtruct2 out2;
+    out2.byte_thing = 1;
+    out2.struct_thing = out;
+    out2.i32_thing = 5;
+    Xtruct2 in2;
+    testClient.testNest(in2, out2);
+    in = in2.struct_thing;
+    printf(" = {%d, {\"%s\", %d, %d, %"PRId64"}, %d}\n",
+           in2.byte_thing,
+           in.string_thing.c_str(),
+           (int)in.byte_thing,
+           in.i32_thing,
+           in.i64_thing,
+           in2.i32_thing);
+
+    /**
+     * MAP TEST
+     */
+    map<int32_t,int32_t> mapout;
+    for (int32_t i = 0; i < 5; ++i) {
+      mapout.insert(make_pair(i, i-10));
+    }
+    printf("testMap({");
+    map<int32_t, int32_t>::const_iterator m_iter;
+    bool first = true;
+    for (m_iter = mapout.begin(); m_iter != mapout.end(); ++m_iter) {
+      if (first) {
+        first = false;
+      } else {
+        printf(", ");
+      }
+      printf("%d => %d", m_iter->first, m_iter->second);
+    }
+    printf("})");
+    map<int32_t,int32_t> mapin;
+    testClient.testMap(mapin, mapout);
+    printf(" = {");
+    first = true;
+    for (m_iter = mapin.begin(); m_iter != mapin.end(); ++m_iter) {
+      if (first) {
+        first = false;
+      } else {
+        printf(", ");
+      }
+      printf("%d => %d", m_iter->first, m_iter->second);
+    }
+    printf("}\n");
+
+    /**
+     * SET TEST
+     */
+    set<int32_t> setout;
+    for (int32_t i = -2; i < 3; ++i) {
+      setout.insert(i);
+    }
+    printf("testSet({");
+    set<int32_t>::const_iterator s_iter;
+    first = true;
+    for (s_iter = setout.begin(); s_iter != setout.end(); ++s_iter) {
+      if (first) {
+        first = false;
+      } else {
+        printf(", ");
+      }
+      printf("%d", *s_iter);
+    }
+    printf("})");
+    set<int32_t> setin;
+    testClient.testSet(setin, setout);
+    printf(" = {");
+    first = true;
+    for (s_iter = setin.begin(); s_iter != setin.end(); ++s_iter) {
+      if (first) {
+        first = false;
+      } else {
+        printf(", ");
+      }
+      printf("%d", *s_iter);
+    }
+    printf("}\n");
+
+    /**
+     * LIST TEST
+     */
+    vector<int32_t> listout;
+    for (int32_t i = -2; i < 3; ++i) {
+      listout.push_back(i);
+    }
+    printf("testList({");
+    vector<int32_t>::const_iterator l_iter;
+    first = true;
+    for (l_iter = listout.begin(); l_iter != listout.end(); ++l_iter) {
+      if (first) {
+        first = false;
+      } else {
+        printf(", ");
+      }
+      printf("%d", *l_iter);
+    }
+    printf("})");
+    vector<int32_t> listin;
+    testClient.testList(listin, listout);
+    printf(" = {");
+    first = true;
+    for (l_iter = listin.begin(); l_iter != listin.end(); ++l_iter) {
+      if (first) {
+        first = false;
+      } else {
+        printf(", ");
+      }
+      printf("%d", *l_iter);
+    }
+    printf("}\n");
+
+    /**
+     * ENUM TEST
+     */
+    printf("testEnum(ONE)");
+    Numberz ret = testClient.testEnum(ONE);
+    printf(" = %d\n", ret);
+
+    printf("testEnum(TWO)");
+    ret = testClient.testEnum(TWO);
+    printf(" = %d\n", ret);
+
+    printf("testEnum(THREE)");
+    ret = testClient.testEnum(THREE);
+    printf(" = %d\n", ret);
+
+    printf("testEnum(FIVE)");
+    ret = testClient.testEnum(FIVE);
+    printf(" = %d\n", ret);
+
+    printf("testEnum(EIGHT)");
+    ret = testClient.testEnum(EIGHT);
+    printf(" = %d\n", ret);
+
+    /**
+     * TYPEDEF TEST
+     */
+    printf("testTypedef(309858235082523)");
+    UserId uid = testClient.testTypedef(309858235082523LL);
+    printf(" = %"PRId64"\n", uid);
+
+    /**
+     * NESTED MAP TEST
+     */
+    printf("testMapMap(1)");
+    map<int32_t, map<int32_t, int32_t> > mm;
+    testClient.testMapMap(mm, 1);
+    printf(" = {");
+    map<int32_t, map<int32_t, int32_t> >::const_iterator mi;
+    for (mi = mm.begin(); mi != mm.end(); ++mi) {
+      printf("%d => {", mi->first);
+      map<int32_t, int32_t>::const_iterator mi2;
+      for (mi2 = mi->second.begin(); mi2 != mi->second.end(); ++mi2) {
+        printf("%d => %d, ", mi2->first, mi2->second);
+      }
+      printf("}, ");
+    }
+    printf("}\n");
+
+    /**
+     * INSANITY TEST
+     */
+    Insanity insane;
+    insane.userMap.insert(make_pair(FIVE, 5000));
+    Xtruct truck;
+    truck.string_thing = "Truck";
+    truck.byte_thing = 8;
+    truck.i32_thing = 8;
+    truck.i64_thing = 8;
+    insane.xtructs.push_back(truck);
+    printf("testInsanity()");
+    map<UserId, map<Numberz,Insanity> > whoa;
+    testClient.testInsanity(whoa, insane);
+    printf(" = {");
+    map<UserId, map<Numberz,Insanity> >::const_iterator i_iter;
+    for (i_iter = whoa.begin(); i_iter != whoa.end(); ++i_iter) {
+      printf("%"PRId64" => {", i_iter->first);
+      map<Numberz,Insanity>::const_iterator i2_iter;
+      for (i2_iter = i_iter->second.begin();
+           i2_iter != i_iter->second.end();
+           ++i2_iter) {
+        printf("%d => {", i2_iter->first);
+        map<Numberz, UserId> userMap = i2_iter->second.userMap;
+        map<Numberz, UserId>::const_iterator um;
+        printf("{");
+        for (um = userMap.begin(); um != userMap.end(); ++um) {
+          printf("%d => %"PRId64", ", um->first, um->second);
+        }
+        printf("}, ");
+
+        vector<Xtruct> xtructs = i2_iter->second.xtructs;
+        vector<Xtruct>::const_iterator x;
+        printf("{");
+        for (x = xtructs.begin(); x != xtructs.end(); ++x) {
+          printf("{\"%s\", %d, %d, %"PRId64"}, ",
+                 x->string_thing.c_str(),
+                 (int)x->byte_thing,
+                 x->i32_thing,
+                 x->i64_thing);
+        }
+        printf("}");
+
+        printf("}, ");
+      }
+      printf("}, ");
+    }
+    printf("}\n");
+
+    /* test exception */
+
+    try {
+      printf("testClient.testException(\"Xception\") =>");
+      testClient.testException("Xception");
+      printf("  void\nFAILURE\n");
+
+    } catch(Xception& e) {
+      printf("  {%u, \"%s\"}\n", e.errorCode, e.message.c_str());
+    }
+
+    try {
+      printf("testClient.testException(\"success\") =>");
+      testClient.testException("success");
+      printf("  void\n");
+    } catch(...) {
+      printf("  exception\nFAILURE\n");
+    }
+
+    /* test multi exception */
+
+    try {
+      printf("testClient.testMultiException(\"Xception\", \"test 1\") =>");
+      Xtruct result;
+      testClient.testMultiException(result, "Xception", "test 1");
+      printf("  result\nFAILURE\n");
+    } catch(Xception& e) {
+      printf("  {%u, \"%s\"}\n", e.errorCode, e.message.c_str());
+    }
+
+    try {
+      printf("testClient.testMultiException(\"Xception2\", \"test 2\") =>");
+      Xtruct result;
+      testClient.testMultiException(result, "Xception2", "test 2");
+      printf("  result\nFAILURE\n");
+
+    } catch(Xception2& e) {
+      printf("  {%u, {\"%s\"}}\n", e.errorCode, e.struct_thing.string_thing.c_str());
+    }
+
+    try {
+      printf("testClient.testMultiException(\"success\", \"test 3\") =>");
+      Xtruct result;
+      testClient.testMultiException(result, "success", "test 3");
+      printf("  {{\"%s\"}}\n", result.string_thing.c_str());
+    } catch(...) {
+      printf("  exception\nFAILURE\n");
+    }
+
+    /* test oneway void */
+    {
+        printf("testClient.testOneway(3) =>");
+        uint64_t startOneway = now();
+        testClient.testOneway(3);
+        uint64_t elapsed = now() - startOneway;
+        if (elapsed > 200 * 1000) { // 0.2 seconds
+            printf("  FAILURE - took %.2f ms\n", (double)elapsed/1000.0);
+        } else {
+            printf("  success - took %.2f ms\n", (double)elapsed/1000.0);
+        }
+    }
+
+    /**
+     * redo a simple test after the oneway to make sure we aren't "off by one" --
+     * if the server treated oneway void like normal void, this next test will
+     * fail since it will get the void confirmation rather than the correct
+     * result. In this circumstance, the client will throw the exception:
+     *
+     *   TApplicationException: Wrong method namea
+     */
+    /**
+     * I32 TEST
+     */
+    printf("re-test testI32(-1)");
+    i32 = testClient.testI32(-1);
+    printf(" = %d\n", i32);
+
+
+    uint64_t stop = now();
+    uint64_t tot = stop-start;
+
+    printf("Total time: %"PRIu64" us\n", stop-start);
+
+    time_tot += tot;
+    if (time_min == 0 || tot < time_min) {
+      time_min = tot;
+    }
+    if (tot > time_max) {
+      time_max = tot;
+    }
+
+    transport->close();
+  }
+
+  //  printf("\nSocket syscalls: %u", g_socket_syscalls);
+  printf("\nAll tests done.\n");
+
+  uint64_t time_avg = time_tot / numTests;
+
+  printf("Min time: %"PRIu64" us\n", time_min);
+  printf("Max time: %"PRIu64" us\n", time_max);
+  printf("Avg time: %"PRIu64" us\n", time_avg);
+
+  return 0;
+}
diff --git a/test/cpp/src/TestServer.cpp b/test/cpp/src/TestServer.cpp
new file mode 100644
index 0000000..83454dc
--- /dev/null
+++ b/test/cpp/src/TestServer.cpp
@@ -0,0 +1,424 @@
+/*
+ * 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.
+ */
+
+#include <concurrency/ThreadManager.h>
+#include <concurrency/PosixThreadFactory.h>
+#include <protocol/TBinaryProtocol.h>
+#include <server/TSimpleServer.h>
+#include <server/TThreadedServer.h>
+#include <server/TThreadPoolServer.h>
+#include <server/TNonblockingServer.h>
+#include <transport/TServerSocket.h>
+#include <transport/TTransportUtils.h>
+#include "ThriftTest.h"
+
+#include <iostream>
+#include <stdexcept>
+#include <sstream>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+using namespace std;
+using namespace boost;
+
+using namespace apache::thrift;
+using namespace apache::thrift::concurrency;
+using namespace apache::thrift::protocol;
+using namespace apache::thrift::transport;
+using namespace apache::thrift::server;
+
+using namespace thrift::test;
+
+class TestHandler : public ThriftTestIf {
+ public:
+  TestHandler() {}
+
+  void testVoid() {
+    printf("testVoid()\n");
+  }
+
+  void testString(string& out, const string &thing) {
+    printf("testString(\"%s\")\n", thing.c_str());
+    out = thing;
+  }
+
+  int8_t testByte(const int8_t thing) {
+    printf("testByte(%d)\n", (int)thing);
+    return thing;
+  }
+
+  int32_t testI32(const int32_t thing) {
+    printf("testI32(%d)\n", thing);
+    return thing;
+  }
+
+  int64_t testI64(const int64_t thing) {
+    printf("testI64(%"PRId64")\n", thing);
+    return thing;
+  }
+
+  double testDouble(const double thing) {
+    printf("testDouble(%lf)\n", thing);
+    return thing;
+  }
+
+  void testStruct(Xtruct& out, const Xtruct &thing) {
+    printf("testStruct({\"%s\", %d, %d, %"PRId64"})\n", thing.string_thing.c_str(), (int)thing.byte_thing, thing.i32_thing, thing.i64_thing);
+    out = thing;
+  }
+
+  void testNest(Xtruct2& out, const Xtruct2& nest) {
+    const Xtruct &thing = nest.struct_thing;
+    printf("testNest({%d, {\"%s\", %d, %d, %"PRId64"}, %d})\n", (int)nest.byte_thing, thing.string_thing.c_str(), (int)thing.byte_thing, thing.i32_thing, thing.i64_thing, nest.i32_thing);
+    out = nest;
+  }
+
+  void testMap(map<int32_t, int32_t> &out, const map<int32_t, int32_t> &thing) {
+    printf("testMap({");
+    map<int32_t, int32_t>::const_iterator m_iter;
+    bool first = true;
+    for (m_iter = thing.begin(); m_iter != thing.end(); ++m_iter) {
+      if (first) {
+        first = false;
+      } else {
+        printf(", ");
+      }
+      printf("%d => %d", m_iter->first, m_iter->second);
+    }
+    printf("})\n");
+    out = thing;
+  }
+
+  void testSet(set<int32_t> &out, const set<int32_t> &thing) {
+    printf("testSet({");
+    set<int32_t>::const_iterator s_iter;
+    bool first = true;
+    for (s_iter = thing.begin(); s_iter != thing.end(); ++s_iter) {
+      if (first) {
+        first = false;
+      } else {
+        printf(", ");
+      }
+      printf("%d", *s_iter);
+    }
+    printf("})\n");
+    out = thing;
+  }
+
+  void testList(vector<int32_t> &out, const vector<int32_t> &thing) {
+    printf("testList({");
+    vector<int32_t>::const_iterator l_iter;
+    bool first = true;
+    for (l_iter = thing.begin(); l_iter != thing.end(); ++l_iter) {
+      if (first) {
+        first = false;
+      } else {
+        printf(", ");
+      }
+      printf("%d", *l_iter);
+    }
+    printf("})\n");
+    out = thing;
+  }
+
+  Numberz testEnum(const Numberz thing) {
+    printf("testEnum(%d)\n", thing);
+    return thing;
+  }
+
+  UserId testTypedef(const UserId thing) {
+    printf("testTypedef(%"PRId64")\n", thing);
+    return thing;
+  }
+
+  void testMapMap(map<int32_t, map<int32_t,int32_t> > &mapmap, const int32_t hello) {
+    printf("testMapMap(%d)\n", hello);
+
+    map<int32_t,int32_t> pos;
+    map<int32_t,int32_t> neg;
+    for (int i = 1; i < 5; i++) {
+      pos.insert(make_pair(i,i));
+      neg.insert(make_pair(-i,-i));
+    }
+
+    mapmap.insert(make_pair(4, pos));
+    mapmap.insert(make_pair(-4, neg));
+
+  }
+
+  void testInsanity(map<UserId, map<Numberz,Insanity> > &insane, const Insanity &argument) {
+    printf("testInsanity()\n");
+
+    Xtruct hello;
+    hello.string_thing = "Hello2";
+    hello.byte_thing = 2;
+    hello.i32_thing = 2;
+    hello.i64_thing = 2;
+
+    Xtruct goodbye;
+    goodbye.string_thing = "Goodbye4";
+    goodbye.byte_thing = 4;
+    goodbye.i32_thing = 4;
+    goodbye.i64_thing = 4;
+
+    Insanity crazy;
+    crazy.userMap.insert(make_pair(EIGHT, 8));
+    crazy.xtructs.push_back(goodbye);
+
+    Insanity looney;
+    crazy.userMap.insert(make_pair(FIVE, 5));
+    crazy.xtructs.push_back(hello);
+
+    map<Numberz, Insanity> first_map;
+    map<Numberz, Insanity> second_map;
+
+    first_map.insert(make_pair(TWO, crazy));
+    first_map.insert(make_pair(THREE, crazy));
+
+    second_map.insert(make_pair(SIX, looney));
+
+    insane.insert(make_pair(1, first_map));
+    insane.insert(make_pair(2, second_map));
+
+    printf("return");
+    printf(" = {");
+    map<UserId, map<Numberz,Insanity> >::const_iterator i_iter;
+    for (i_iter = insane.begin(); i_iter != insane.end(); ++i_iter) {
+      printf("%"PRId64" => {", i_iter->first);
+      map<Numberz,Insanity>::const_iterator i2_iter;
+      for (i2_iter = i_iter->second.begin();
+           i2_iter != i_iter->second.end();
+           ++i2_iter) {
+        printf("%d => {", i2_iter->first);
+        map<Numberz, UserId> userMap = i2_iter->second.userMap;
+        map<Numberz, UserId>::const_iterator um;
+        printf("{");
+        for (um = userMap.begin(); um != userMap.end(); ++um) {
+          printf("%d => %"PRId64", ", um->first, um->second);
+        }
+        printf("}, ");
+
+        vector<Xtruct> xtructs = i2_iter->second.xtructs;
+        vector<Xtruct>::const_iterator x;
+        printf("{");
+        for (x = xtructs.begin(); x != xtructs.end(); ++x) {
+          printf("{\"%s\", %d, %d, %"PRId64"}, ", x->string_thing.c_str(), (int)x->byte_thing, x->i32_thing, x->i64_thing);
+        }
+        printf("}");
+
+        printf("}, ");
+      }
+      printf("}, ");
+    }
+    printf("}\n");
+
+
+  }
+
+  void testMulti(Xtruct &hello, const int8_t arg0, const int32_t arg1, const int64_t arg2, const std::map<int16_t, std::string>  &arg3, const Numberz arg4, const UserId arg5) {
+    printf("testMulti()\n");
+
+    hello.string_thing = "Hello2";
+    hello.byte_thing = arg0;
+    hello.i32_thing = arg1;
+    hello.i64_thing = (int64_t)arg2;
+  }
+
+  void testException(const std::string &arg)
+    throw(Xception, apache::thrift::TException)
+  {
+    printf("testException(%s)\n", arg.c_str());
+    if (arg.compare("Xception") == 0) {
+      Xception e;
+      e.errorCode = 1001;
+      e.message = arg;
+      throw e;
+    } else if (arg.compare("ApplicationException") == 0) {
+      apache::thrift::TException e;
+      throw e;
+    } else {
+      Xtruct result;
+      result.string_thing = arg;
+      return;
+    }
+  }
+
+  void testMultiException(Xtruct &result, const std::string &arg0, const std::string &arg1) throw(Xception, Xception2) {
+
+    printf("testMultiException(%s, %s)\n", arg0.c_str(), arg1.c_str());
+
+    if (arg0.compare("Xception") == 0) {
+      Xception e;
+      e.errorCode = 1001;
+      e.message = "This is an Xception";
+      throw e;
+    } else if (arg0.compare("Xception2") == 0) {
+      Xception2 e;
+      e.errorCode = 2002;
+      e.struct_thing.string_thing = "This is an Xception2";
+      throw e;
+    } else {
+      result.string_thing = arg1;
+      return;
+    }
+  }
+
+  void testOneway(int sleepFor) {
+    printf("testOneway(%d): Sleeping...\n", sleepFor);
+    sleep(sleepFor);
+    printf("testOneway(%d): done sleeping!\n", sleepFor);
+  }
+};
+
+int main(int argc, char **argv) {
+
+  int port = 9090;
+  string serverType = "simple";
+  string protocolType = "binary";
+  size_t workerCount = 4;
+
+  ostringstream usage;
+
+  usage <<
+    argv[0] << " [--port=<port number>] [--server-type=<server-type>] [--protocol-type=<protocol-type>] [--workers=<worker-count>]" << endl <<
+
+    "\t\tserver-type\t\ttype of server, \"simple\", \"thread-pool\", \"threaded\", or \"nonblocking\".  Default is " << serverType << endl <<
+
+    "\t\tprotocol-type\t\ttype of protocol, \"binary\", \"ascii\", or \"xml\".  Default is " << protocolType << endl <<
+
+    "\t\tworkers\t\tNumber of thread pools workers.  Only valid for thread-pool server type.  Default is " << workerCount << endl;
+
+  map<string, string>  args;
+
+  for (int ix = 1; ix < argc; ix++) {
+    string arg(argv[ix]);
+    if (arg.compare(0,2, "--") == 0) {
+      size_t end = arg.find_first_of("=", 2);
+      if (end != string::npos) {
+	args[string(arg, 2, end - 2)] = string(arg, end + 1);
+      } else {
+	args[string(arg, 2)] = "true";
+      }
+    } else {
+      throw invalid_argument("Unexcepted command line token: "+arg);
+    }
+  }
+
+  try {
+
+    if (!args["port"].empty()) {
+      port = atoi(args["port"].c_str());
+    }
+
+    if (!args["server-type"].empty()) {
+      serverType = args["server-type"];
+      if (serverType == "simple") {
+      } else if (serverType == "thread-pool") {
+      } else if (serverType == "threaded") {
+      } else if (serverType == "nonblocking") {
+      } else {
+	throw invalid_argument("Unknown server type "+serverType);
+      }
+    }
+
+    if (!args["protocol-type"].empty()) {
+      protocolType = args["protocol-type"];
+      if (protocolType == "binary") {
+      } else if (protocolType == "ascii") {
+	throw invalid_argument("ASCII protocol not supported");
+      } else if (protocolType == "xml") {
+	throw invalid_argument("XML protocol not supported");
+      } else {
+	throw invalid_argument("Unknown protocol type "+protocolType);
+      }
+    }
+
+    if (!args["workers"].empty()) {
+      workerCount = atoi(args["workers"].c_str());
+    }
+  } catch (exception& e) {
+    cerr << e.what() << endl;
+    cerr << usage;
+  }
+
+  // Dispatcher
+  shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
+
+  shared_ptr<TestHandler> testHandler(new TestHandler());
+
+  shared_ptr<ThriftTestProcessor> testProcessor(new ThriftTestProcessor(testHandler));
+
+  // Transport
+  shared_ptr<TServerSocket> serverSocket(new TServerSocket(port));
+
+  // Factory
+  shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
+
+  if (serverType == "simple") {
+
+    // Server
+    TSimpleServer simpleServer(testProcessor,
+			       serverSocket,
+                               transportFactory,
+                               protocolFactory);
+
+    printf("Starting the server on port %d...\n", port);
+    simpleServer.serve();
+
+  } else if (serverType == "thread-pool") {
+
+    shared_ptr<ThreadManager> threadManager =
+      ThreadManager::newSimpleThreadManager(workerCount);
+
+    shared_ptr<PosixThreadFactory> threadFactory =
+      shared_ptr<PosixThreadFactory>(new PosixThreadFactory());
+
+    threadManager->threadFactory(threadFactory);
+
+    threadManager->start();
+
+    TThreadPoolServer threadPoolServer(testProcessor,
+				       serverSocket,
+                                       transportFactory,
+                                       protocolFactory,
+				       threadManager);
+
+    printf("Starting the server on port %d...\n", port);
+    threadPoolServer.serve();
+
+  } else if (serverType == "threaded") {
+
+    TThreadedServer threadedServer(testProcessor,
+                                   serverSocket,
+                                   transportFactory,
+                                   protocolFactory);
+
+    printf("Starting the server on port %d...\n", port);
+    threadedServer.serve();
+
+  } else if (serverType == "nonblocking") {
+    TNonblockingServer nonblockingServer(testProcessor, port);
+    printf("Starting the nonblocking server on port %d...\n", port);
+    nonblockingServer.serve();
+  }
+
+  printf("done.\n");
+  return 0;
+}
diff --git a/test/cpp/src/main.cpp b/test/cpp/src/main.cpp
new file mode 100644
index 0000000..46ee950
--- /dev/null
+++ b/test/cpp/src/main.cpp
@@ -0,0 +1,509 @@
+/*
+ * 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.
+ */
+
+#include <concurrency/ThreadManager.h>
+#include <concurrency/PosixThreadFactory.h>
+#include <concurrency/Monitor.h>
+#include <concurrency/Util.h>
+#include <concurrency/Mutex.h>
+#include <protocol/TBinaryProtocol.h>
+#include <server/TSimpleServer.h>
+#include <server/TThreadPoolServer.h>
+#include <server/TThreadedServer.h>
+#include <transport/TServerSocket.h>
+#include <transport/TSocket.h>
+#include <transport/TTransportUtils.h>
+#include <transport/TFileTransport.h>
+#include <TLogging.h>
+
+#include "Service.h"
+
+#include <iostream>
+#include <set>
+#include <stdexcept>
+#include <sstream>
+
+#include <map>
+#include <ext/hash_map>
+using __gnu_cxx::hash_map;
+using __gnu_cxx::hash;
+
+using namespace std;
+using namespace boost;
+
+using namespace apache::thrift;
+using namespace apache::thrift::protocol;
+using namespace apache::thrift::transport;
+using namespace apache::thrift::server;
+using namespace apache::thrift::concurrency;
+
+using namespace test::stress;
+
+struct eqstr {
+  bool operator()(const char* s1, const char* s2) const {
+    return strcmp(s1, s2) == 0;
+  }
+};
+
+struct ltstr {
+  bool operator()(const char* s1, const char* s2) const {
+    return strcmp(s1, s2) < 0;
+  }
+};
+
+
+// typedef hash_map<const char*, int, hash<const char*>, eqstr> count_map;
+typedef map<const char*, int, ltstr> count_map;
+
+class Server : public ServiceIf {
+ public:
+  Server() {}
+
+  void count(const char* method) {
+    Guard m(lock_);
+    int ct = counts_[method];
+    counts_[method] = ++ct;
+  }
+
+  void echoVoid() {
+    count("echoVoid");
+    return;
+  }
+
+  count_map getCount() {
+    Guard m(lock_);
+    return counts_;
+  }
+
+  int8_t echoByte(const int8_t arg) {return arg;}
+  int32_t echoI32(const int32_t arg) {return arg;}
+  int64_t echoI64(const int64_t arg) {return arg;}
+  void echoString(string& out, const string &arg) {
+    if (arg != "hello") {
+      T_ERROR_ABORT("WRONG STRING!!!!");
+    }
+    out = arg;
+  }
+  void echoList(vector<int8_t> &out, const vector<int8_t> &arg) { out = arg; }
+  void echoSet(set<int8_t> &out, const set<int8_t> &arg) { out = arg; }
+  void echoMap(map<int8_t, int8_t> &out, const map<int8_t, int8_t> &arg) { out = arg; }
+
+private:
+  count_map counts_;
+  Mutex lock_;
+
+};
+
+class ClientThread: public Runnable {
+public:
+
+  ClientThread(shared_ptr<TTransport>transport, shared_ptr<ServiceClient> client, Monitor& monitor, size_t& workerCount, size_t loopCount, TType loopType) :
+    _transport(transport),
+    _client(client),
+    _monitor(monitor),
+    _workerCount(workerCount),
+    _loopCount(loopCount),
+    _loopType(loopType)
+  {}
+
+  void run() {
+
+    // Wait for all worker threads to start
+
+    {Synchronized s(_monitor);
+      while(_workerCount == 0) {
+        _monitor.wait();
+      }
+    }
+
+    _startTime = Util::currentTime();
+
+    _transport->open();
+
+    switch(_loopType) {
+    case T_VOID: loopEchoVoid(); break;
+    case T_BYTE: loopEchoByte(); break;
+    case T_I32: loopEchoI32(); break;
+    case T_I64: loopEchoI64(); break;
+    case T_STRING: loopEchoString(); break;
+    default: cerr << "Unexpected loop type" << _loopType << endl; break;
+    }
+
+    _endTime = Util::currentTime();
+
+    _transport->close();
+
+    _done = true;
+
+    {Synchronized s(_monitor);
+
+      _workerCount--;
+
+      if (_workerCount == 0) {
+
+        _monitor.notify();
+      }
+    }
+  }
+
+  void loopEchoVoid() {
+    for (size_t ix = 0; ix < _loopCount; ix++) {
+      _client->echoVoid();
+    }
+  }
+
+  void loopEchoByte() {
+    for (size_t ix = 0; ix < _loopCount; ix++) {
+      int8_t arg = 1;
+      int8_t result;
+      result =_client->echoByte(arg);
+      assert(result == arg);
+    }
+  }
+
+  void loopEchoI32() {
+    for (size_t ix = 0; ix < _loopCount; ix++) {
+      int32_t arg = 1;
+      int32_t result;
+      result =_client->echoI32(arg);
+      assert(result == arg);
+    }
+  }
+
+  void loopEchoI64() {
+    for (size_t ix = 0; ix < _loopCount; ix++) {
+      int64_t arg = 1;
+      int64_t result;
+      result =_client->echoI64(arg);
+      assert(result == arg);
+    }
+  }
+
+  void loopEchoString() {
+    for (size_t ix = 0; ix < _loopCount; ix++) {
+      string arg = "hello";
+      string result;
+      _client->echoString(result, arg);
+      assert(result == arg);
+    }
+  }
+
+  shared_ptr<TTransport> _transport;
+  shared_ptr<ServiceClient> _client;
+  Monitor& _monitor;
+  size_t& _workerCount;
+  size_t _loopCount;
+  TType _loopType;
+  long long _startTime;
+  long long _endTime;
+  bool _done;
+  Monitor _sleep;
+};
+
+
+int main(int argc, char **argv) {
+
+  int port = 9091;
+  string serverType = "thread-pool";
+  string protocolType = "binary";
+  size_t workerCount = 4;
+  size_t clientCount = 20;
+  size_t loopCount = 50000;
+  TType loopType  = T_VOID;
+  string callName = "echoVoid";
+  bool runServer = true;
+  bool logRequests = false;
+  string requestLogPath = "./requestlog.tlog";
+  bool replayRequests = false;
+
+  ostringstream usage;
+
+  usage <<
+    argv[0] << " [--port=<port number>] [--server] [--server-type=<server-type>] [--protocol-type=<protocol-type>] [--workers=<worker-count>] [--clients=<client-count>] [--loop=<loop-count>]" << endl <<
+    "\tclients        Number of client threads to create - 0 implies no clients, i.e. server only.  Default is " << clientCount << endl <<
+    "\thelp           Prints this help text." << endl <<
+    "\tcall           Service method to call.  Default is " << callName << endl <<
+    "\tloop           The number of remote thrift calls each client makes.  Default is " << loopCount << endl <<
+    "\tport           The port the server and clients should bind to for thrift network connections.  Default is " << port << endl <<
+    "\tserver         Run the Thrift server in this process.  Default is " << runServer << endl <<
+    "\tserver-type    Type of server, \"simple\" or \"thread-pool\".  Default is " << serverType << endl <<
+    "\tprotocol-type  Type of protocol, \"binary\", \"ascii\", or \"xml\".  Default is " << protocolType << endl <<
+    "\tlog-request    Log all request to ./requestlog.tlog. Default is " << logRequests << endl <<
+    "\treplay-request Replay requests from log file (./requestlog.tlog) Default is " << replayRequests << endl <<
+    "\tworkers        Number of thread pools workers.  Only valid for thread-pool server type.  Default is " << workerCount << endl;
+
+
+  map<string, string>  args;
+
+  for (int ix = 1; ix < argc; ix++) {
+
+    string arg(argv[ix]);
+
+    if (arg.compare(0,2, "--") == 0) {
+
+      size_t end = arg.find_first_of("=", 2);
+
+      string key = string(arg, 2, end - 2);
+
+      if (end != string::npos) {
+        args[key] = string(arg, end + 1);
+      } else {
+        args[key] = "true";
+      }
+    } else {
+      throw invalid_argument("Unexcepted command line token: "+arg);
+    }
+  }
+
+  try {
+
+    if (!args["clients"].empty()) {
+      clientCount = atoi(args["clients"].c_str());
+    }
+
+    if (!args["help"].empty()) {
+      cerr << usage.str();
+      return 0;
+    }
+
+    if (!args["loop"].empty()) {
+      loopCount = atoi(args["loop"].c_str());
+    }
+
+    if (!args["call"].empty()) {
+      callName = args["call"];
+    }
+
+    if (!args["port"].empty()) {
+      port = atoi(args["port"].c_str());
+    }
+
+    if (!args["server"].empty()) {
+      runServer = args["server"] == "true";
+    }
+
+    if (!args["log-request"].empty()) {
+      logRequests = args["log-request"] == "true";
+    }
+
+    if (!args["replay-request"].empty()) {
+      replayRequests = args["replay-request"] == "true";
+    }
+
+    if (!args["server-type"].empty()) {
+      serverType = args["server-type"];
+
+      if (serverType == "simple") {
+
+      } else if (serverType == "thread-pool") {
+
+      } else if (serverType == "threaded") {
+
+      } else {
+
+        throw invalid_argument("Unknown server type "+serverType);
+      }
+    }
+
+    if (!args["workers"].empty()) {
+      workerCount = atoi(args["workers"].c_str());
+    }
+
+  } catch(exception& e) {
+    cerr << e.what() << endl;
+    cerr << usage;
+  }
+
+  shared_ptr<PosixThreadFactory> threadFactory = shared_ptr<PosixThreadFactory>(new PosixThreadFactory());
+
+  // Dispatcher
+  shared_ptr<Server> serviceHandler(new Server());
+
+  if (replayRequests) {
+    shared_ptr<Server> serviceHandler(new Server());
+    shared_ptr<ServiceProcessor> serviceProcessor(new ServiceProcessor(serviceHandler));
+
+    // Transports
+    shared_ptr<TFileTransport> fileTransport(new TFileTransport(requestLogPath));
+    fileTransport->setChunkSize(2 * 1024 * 1024);
+    fileTransport->setMaxEventSize(1024 * 16);
+    fileTransport->seekToEnd();
+
+    // Protocol Factory
+    shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
+
+    TFileProcessor fileProcessor(serviceProcessor,
+                                 protocolFactory,
+                                 fileTransport);
+
+    fileProcessor.process(0, true);
+    exit(0);
+  }
+
+
+  if (runServer) {
+
+    shared_ptr<ServiceProcessor> serviceProcessor(new ServiceProcessor(serviceHandler));
+
+    // Transport
+    shared_ptr<TServerSocket> serverSocket(new TServerSocket(port));
+
+    // Transport Factory
+    shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
+
+    // Protocol Factory
+    shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
+
+    if (logRequests) {
+      // initialize the log file
+      shared_ptr<TFileTransport> fileTransport(new TFileTransport(requestLogPath));
+      fileTransport->setChunkSize(2 * 1024 * 1024);
+      fileTransport->setMaxEventSize(1024 * 16);
+
+      transportFactory =
+        shared_ptr<TTransportFactory>(new TPipedTransportFactory(fileTransport));
+    }
+
+    shared_ptr<Thread> serverThread;
+
+    if (serverType == "simple") {
+
+      serverThread = threadFactory->newThread(shared_ptr<TServer>(new TSimpleServer(serviceProcessor, serverSocket, transportFactory, protocolFactory)));
+
+    } else if (serverType == "threaded") {
+
+      serverThread = threadFactory->newThread(shared_ptr<TServer>(new TThreadedServer(serviceProcessor, serverSocket, transportFactory, protocolFactory)));
+
+    } else if (serverType == "thread-pool") {
+
+      shared_ptr<ThreadManager> threadManager = ThreadManager::newSimpleThreadManager(workerCount);
+
+      threadManager->threadFactory(threadFactory);
+      threadManager->start();
+      serverThread = threadFactory->newThread(shared_ptr<TServer>(new TThreadPoolServer(serviceProcessor, serverSocket, transportFactory, protocolFactory, threadManager)));
+    }
+
+    cerr << "Starting the server on port " << port << endl;
+
+    serverThread->start();
+
+    // If we aren't running clients, just wait forever for external clients
+
+    if (clientCount == 0) {
+      serverThread->join();
+    }
+  }
+
+  if (clientCount > 0) {
+
+    Monitor monitor;
+
+    size_t threadCount = 0;
+
+    set<shared_ptr<Thread> > clientThreads;
+
+    if (callName == "echoVoid") { loopType = T_VOID;}
+    else if (callName == "echoByte") { loopType = T_BYTE;}
+    else if (callName == "echoI32") { loopType = T_I32;}
+    else if (callName == "echoI64") { loopType = T_I64;}
+    else if (callName == "echoString") { loopType = T_STRING;}
+    else {throw invalid_argument("Unknown service call "+callName);}
+
+    for (size_t ix = 0; ix < clientCount; ix++) {
+
+      shared_ptr<TSocket> socket(new TSocket("127.0.01", port));
+      shared_ptr<TBufferedTransport> bufferedSocket(new TBufferedTransport(socket, 2048));
+      shared_ptr<TProtocol> protocol(new TBinaryProtocol(bufferedSocket));
+      shared_ptr<ServiceClient> serviceClient(new ServiceClient(protocol));
+
+      clientThreads.insert(threadFactory->newThread(shared_ptr<ClientThread>(new ClientThread(socket, serviceClient, monitor, threadCount, loopCount, loopType))));
+    }
+
+    for (std::set<shared_ptr<Thread> >::const_iterator thread = clientThreads.begin(); thread != clientThreads.end(); thread++) {
+      (*thread)->start();
+    }
+
+    long long time00;
+    long long time01;
+
+    {Synchronized s(monitor);
+      threadCount = clientCount;
+
+      cerr << "Launch "<< clientCount << " client threads" << endl;
+
+      time00 =  Util::currentTime();
+
+      monitor.notifyAll();
+
+      while(threadCount > 0) {
+        monitor.wait();
+      }
+
+      time01 =  Util::currentTime();
+    }
+
+    long long firstTime = 9223372036854775807LL;
+    long long lastTime = 0;
+
+    double averageTime = 0;
+    long long minTime = 9223372036854775807LL;
+    long long maxTime = 0;
+
+    for (set<shared_ptr<Thread> >::iterator ix = clientThreads.begin(); ix != clientThreads.end(); ix++) {
+
+      shared_ptr<ClientThread> client = dynamic_pointer_cast<ClientThread>((*ix)->runnable());
+
+      long long delta = client->_endTime - client->_startTime;
+
+      assert(delta > 0);
+
+      if (client->_startTime < firstTime) {
+        firstTime = client->_startTime;
+      }
+
+      if (client->_endTime > lastTime) {
+        lastTime = client->_endTime;
+      }
+
+      if (delta < minTime) {
+        minTime = delta;
+      }
+
+      if (delta > maxTime) {
+        maxTime = delta;
+      }
+
+      averageTime+= delta;
+    }
+
+    averageTime /= clientCount;
+
+
+    cout <<  "workers :" << workerCount << ", client : " << clientCount << ", loops : " << loopCount << ", rate : " << (clientCount * loopCount * 1000) / ((double)(time01 - time00)) << endl;
+
+    count_map count = serviceHandler->getCount();
+    count_map::iterator iter;
+    for (iter = count.begin(); iter != count.end(); ++iter) {
+      printf("%s => %d\n", iter->first, iter->second);
+    }
+    cerr << "done." << endl;
+  }
+
+  return 0;
+}
diff --git a/test/cpp/src/nb-main.cpp b/test/cpp/src/nb-main.cpp
new file mode 100644
index 0000000..8c74a81
--- /dev/null
+++ b/test/cpp/src/nb-main.cpp
@@ -0,0 +1,502 @@
+/*
+ * 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.
+ */
+
+#include <concurrency/ThreadManager.h>
+#include <concurrency/PosixThreadFactory.h>
+#include <concurrency/Monitor.h>
+#include <concurrency/Util.h>
+#include <concurrency/Mutex.h>
+#include <protocol/TBinaryProtocol.h>
+#include <server/TSimpleServer.h>
+#include <server/TThreadPoolServer.h>
+#include <server/TThreadedServer.h>
+#include <server/TNonblockingServer.h>
+#include <transport/TServerSocket.h>
+#include <transport/TSocket.h>
+#include <transport/TTransportUtils.h>
+#include <transport/TFileTransport.h>
+#include <TLogging.h>
+
+#include "Service.h"
+
+#include <unistd.h>
+#include <boost/shared_ptr.hpp>
+
+#include <iostream>
+#include <set>
+#include <stdexcept>
+#include <sstream>
+
+#include <map>
+#include <ext/hash_map>
+using __gnu_cxx::hash_map;
+using __gnu_cxx::hash;
+
+using namespace std;
+using namespace boost;
+
+using namespace apache::thrift;
+using namespace apache::thrift::protocol;
+using namespace apache::thrift::transport;
+using namespace apache::thrift::server;
+using namespace apache::thrift::concurrency;
+
+using namespace test::stress;
+
+struct eqstr {
+  bool operator()(const char* s1, const char* s2) const {
+    return strcmp(s1, s2) == 0;
+  }
+};
+
+struct ltstr {
+  bool operator()(const char* s1, const char* s2) const {
+    return strcmp(s1, s2) < 0;
+  }
+};
+
+
+// typedef hash_map<const char*, int, hash<const char*>, eqstr> count_map;
+typedef map<const char*, int, ltstr> count_map;
+
+class Server : public ServiceIf {
+ public:
+  Server() {}
+
+  void count(const char* method) {
+    Guard m(lock_);
+    int ct = counts_[method];
+    counts_[method] = ++ct;
+  }
+
+  void echoVoid() {
+    count("echoVoid");
+    // Sleep to simulate work
+    usleep(5000);
+    return;
+  }
+
+  count_map getCount() {
+    Guard m(lock_);
+    return counts_;
+  }
+
+  int8_t echoByte(const int8_t arg) {return arg;}
+  int32_t echoI32(const int32_t arg) {return arg;}
+  int64_t echoI64(const int64_t arg) {return arg;}
+  void echoString(string& out, const string &arg) {
+    if (arg != "hello") {
+      T_ERROR_ABORT("WRONG STRING!!!!");
+    }
+    out = arg;
+  }
+  void echoList(vector<int8_t> &out, const vector<int8_t> &arg) { out = arg; }
+  void echoSet(set<int8_t> &out, const set<int8_t> &arg) { out = arg; }
+  void echoMap(map<int8_t, int8_t> &out, const map<int8_t, int8_t> &arg) { out = arg; }
+
+private:
+  count_map counts_;
+  Mutex lock_;
+
+};
+
+class ClientThread: public Runnable {
+public:
+
+  ClientThread(shared_ptr<TTransport>transport, shared_ptr<ServiceClient> client, Monitor& monitor, size_t& workerCount, size_t loopCount, TType loopType) :
+    _transport(transport),
+    _client(client),
+    _monitor(monitor),
+    _workerCount(workerCount),
+    _loopCount(loopCount),
+    _loopType(loopType)
+  {}
+
+  void run() {
+
+    // Wait for all worker threads to start
+
+    {Synchronized s(_monitor);
+        while(_workerCount == 0) {
+          _monitor.wait();
+        }
+    }
+
+    _startTime = Util::currentTime();
+
+    _transport->open();
+
+    switch(_loopType) {
+    case T_VOID: loopEchoVoid(); break;
+    case T_BYTE: loopEchoByte(); break;
+    case T_I32: loopEchoI32(); break;
+    case T_I64: loopEchoI64(); break;
+    case T_STRING: loopEchoString(); break;
+    default: cerr << "Unexpected loop type" << _loopType << endl; break;
+    }
+
+    _endTime = Util::currentTime();
+
+    _transport->close();
+
+    _done = true;
+
+    {Synchronized s(_monitor);
+
+      _workerCount--;
+
+      if (_workerCount == 0) {
+
+        _monitor.notify();
+      }
+    }
+  }
+
+  void loopEchoVoid() {
+    for (size_t ix = 0; ix < _loopCount; ix++) {
+      _client->echoVoid();
+    }
+  }
+
+  void loopEchoByte() {
+    for (size_t ix = 0; ix < _loopCount; ix++) {
+      int8_t arg = 1;
+      int8_t result;
+      result =_client->echoByte(arg);
+      assert(result == arg);
+    }
+  }
+
+  void loopEchoI32() {
+    for (size_t ix = 0; ix < _loopCount; ix++) {
+      int32_t arg = 1;
+      int32_t result;
+      result =_client->echoI32(arg);
+      assert(result == arg);
+    }
+  }
+
+  void loopEchoI64() {
+    for (size_t ix = 0; ix < _loopCount; ix++) {
+      int64_t arg = 1;
+      int64_t result;
+      result =_client->echoI64(arg);
+      assert(result == arg);
+    }
+  }
+
+  void loopEchoString() {
+    for (size_t ix = 0; ix < _loopCount; ix++) {
+      string arg = "hello";
+      string result;
+      _client->echoString(result, arg);
+      assert(result == arg);
+    }
+  }
+
+  shared_ptr<TTransport> _transport;
+  shared_ptr<ServiceClient> _client;
+  Monitor& _monitor;
+  size_t& _workerCount;
+  size_t _loopCount;
+  TType _loopType;
+  long long _startTime;
+  long long _endTime;
+  bool _done;
+  Monitor _sleep;
+};
+
+
+int main(int argc, char **argv) {
+
+  int port = 9091;
+  string serverType = "simple";
+  string protocolType = "binary";
+  size_t workerCount = 4;
+  size_t clientCount = 20;
+  size_t loopCount = 50000;
+  TType loopType  = T_VOID;
+  string callName = "echoVoid";
+  bool runServer = true;
+  bool logRequests = false;
+  string requestLogPath = "./requestlog.tlog";
+  bool replayRequests = false;
+
+  ostringstream usage;
+
+  usage <<
+    argv[0] << " [--port=<port number>] [--server] [--server-type=<server-type>] [--protocol-type=<protocol-type>] [--workers=<worker-count>] [--clients=<client-count>] [--loop=<loop-count>]" << endl <<
+    "\tclients        Number of client threads to create - 0 implies no clients, i.e. server only.  Default is " << clientCount << endl <<
+    "\thelp           Prints this help text." << endl <<
+    "\tcall           Service method to call.  Default is " << callName << endl <<
+    "\tloop           The number of remote thrift calls each client makes.  Default is " << loopCount << endl <<
+    "\tport           The port the server and clients should bind to for thrift network connections.  Default is " << port << endl <<
+    "\tserver         Run the Thrift server in this process.  Default is " << runServer << endl <<
+    "\tserver-type    Type of server, \"simple\" or \"thread-pool\".  Default is " << serverType << endl <<
+    "\tprotocol-type  Type of protocol, \"binary\", \"ascii\", or \"xml\".  Default is " << protocolType << endl <<
+    "\tlog-request    Log all request to ./requestlog.tlog. Default is " << logRequests << endl <<
+    "\treplay-request Replay requests from log file (./requestlog.tlog) Default is " << replayRequests << endl <<
+    "\tworkers        Number of thread pools workers.  Only valid for thread-pool server type.  Default is " << workerCount << endl;
+
+
+  map<string, string>  args;
+
+  for (int ix = 1; ix < argc; ix++) {
+
+    string arg(argv[ix]);
+
+    if (arg.compare(0,2, "--") == 0) {
+
+      size_t end = arg.find_first_of("=", 2);
+
+      string key = string(arg, 2, end - 2);
+
+      if (end != string::npos) {
+        args[key] = string(arg, end + 1);
+      } else {
+        args[key] = "true";
+      }
+    } else {
+      throw invalid_argument("Unexcepted command line token: "+arg);
+    }
+  }
+
+  try {
+
+    if (!args["clients"].empty()) {
+      clientCount = atoi(args["clients"].c_str());
+    }
+
+    if (!args["help"].empty()) {
+      cerr << usage.str();
+      return 0;
+    }
+
+    if (!args["loop"].empty()) {
+      loopCount = atoi(args["loop"].c_str());
+    }
+
+    if (!args["call"].empty()) {
+      callName = args["call"];
+    }
+
+    if (!args["port"].empty()) {
+      port = atoi(args["port"].c_str());
+    }
+
+    if (!args["server"].empty()) {
+      runServer = args["server"] == "true";
+    }
+
+    if (!args["log-request"].empty()) {
+      logRequests = args["log-request"] == "true";
+    }
+
+    if (!args["replay-request"].empty()) {
+      replayRequests = args["replay-request"] == "true";
+    }
+
+    if (!args["server-type"].empty()) {
+      serverType = args["server-type"];
+    }
+
+    if (!args["workers"].empty()) {
+      workerCount = atoi(args["workers"].c_str());
+    }
+
+  } catch(exception& e) {
+    cerr << e.what() << endl;
+    cerr << usage;
+  }
+
+  shared_ptr<PosixThreadFactory> threadFactory = shared_ptr<PosixThreadFactory>(new PosixThreadFactory());
+
+  // Dispatcher
+  shared_ptr<Server> serviceHandler(new Server());
+
+  if (replayRequests) {
+    shared_ptr<Server> serviceHandler(new Server());
+    shared_ptr<ServiceProcessor> serviceProcessor(new ServiceProcessor(serviceHandler));
+
+    // Transports
+    shared_ptr<TFileTransport> fileTransport(new TFileTransport(requestLogPath));
+    fileTransport->setChunkSize(2 * 1024 * 1024);
+    fileTransport->setMaxEventSize(1024 * 16);
+    fileTransport->seekToEnd();
+
+    // Protocol Factory
+    shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
+
+    TFileProcessor fileProcessor(serviceProcessor,
+                                 protocolFactory,
+                                 fileTransport);
+
+    fileProcessor.process(0, true);
+    exit(0);
+  }
+
+
+  if (runServer) {
+
+    shared_ptr<ServiceProcessor> serviceProcessor(new ServiceProcessor(serviceHandler));
+
+    // Protocol Factory
+    shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
+
+    // Transport Factory
+    shared_ptr<TTransportFactory>      transportFactory;
+
+    if (logRequests) {
+      // initialize the log file
+      shared_ptr<TFileTransport> fileTransport(new TFileTransport(requestLogPath));
+      fileTransport->setChunkSize(2 * 1024 * 1024);
+      fileTransport->setMaxEventSize(1024 * 16);
+
+      transportFactory =
+        shared_ptr<TTransportFactory>(new TPipedTransportFactory(fileTransport));
+    }
+
+    shared_ptr<Thread> serverThread;
+    shared_ptr<Thread> serverThread2;
+
+    if (serverType == "simple") {
+
+      serverThread = threadFactory->newThread(shared_ptr<TServer>(new TNonblockingServer(serviceProcessor, protocolFactory, port)));
+      serverThread2 = threadFactory->newThread(shared_ptr<TServer>(new TNonblockingServer(serviceProcessor, protocolFactory, port+1)));
+
+    } else if (serverType == "thread-pool") {
+
+      shared_ptr<ThreadManager> threadManager = ThreadManager::newSimpleThreadManager(workerCount);
+
+      threadManager->threadFactory(threadFactory);
+      threadManager->start();
+      serverThread = threadFactory->newThread(shared_ptr<TServer>(new TNonblockingServer(serviceProcessor, protocolFactory, port, threadManager)));
+      serverThread2 = threadFactory->newThread(shared_ptr<TServer>(new TNonblockingServer(serviceProcessor, protocolFactory, port+1, threadManager)));
+    }
+
+    cerr << "Starting the server on port " << port << " and " << (port + 1) << endl;
+    serverThread->start();
+    serverThread2->start();
+
+    // If we aren't running clients, just wait forever for external clients
+
+    if (clientCount == 0) {
+      serverThread->join();
+      serverThread2->join();
+    }
+  }
+  sleep(1);
+
+  if (clientCount > 0) {
+
+    Monitor monitor;
+
+    size_t threadCount = 0;
+
+    set<shared_ptr<Thread> > clientThreads;
+
+    if (callName == "echoVoid") { loopType = T_VOID;}
+    else if (callName == "echoByte") { loopType = T_BYTE;}
+    else if (callName == "echoI32") { loopType = T_I32;}
+    else if (callName == "echoI64") { loopType = T_I64;}
+    else if (callName == "echoString") { loopType = T_STRING;}
+    else {throw invalid_argument("Unknown service call "+callName);}
+
+    for (size_t ix = 0; ix < clientCount; ix++) {
+
+      shared_ptr<TSocket> socket(new TSocket("127.0.0.1", port + (ix % 2)));
+      shared_ptr<TFramedTransport> framedSocket(new TFramedTransport(socket));
+      shared_ptr<TProtocol> protocol(new TBinaryProtocol(framedSocket));
+      shared_ptr<ServiceClient> serviceClient(new ServiceClient(protocol));
+
+      clientThreads.insert(threadFactory->newThread(shared_ptr<ClientThread>(new ClientThread(socket, serviceClient, monitor, threadCount, loopCount, loopType))));
+    }
+
+    for (std::set<shared_ptr<Thread> >::const_iterator thread = clientThreads.begin(); thread != clientThreads.end(); thread++) {
+      (*thread)->start();
+    }
+
+    long long time00;
+    long long time01;
+
+    {Synchronized s(monitor);
+      threadCount = clientCount;
+
+      cerr << "Launch "<< clientCount << " client threads" << endl;
+
+      time00 =  Util::currentTime();
+
+      monitor.notifyAll();
+
+      while(threadCount > 0) {
+        monitor.wait();
+      }
+
+      time01 =  Util::currentTime();
+    }
+
+    long long firstTime = 9223372036854775807LL;
+    long long lastTime = 0;
+
+    double averageTime = 0;
+    long long minTime = 9223372036854775807LL;
+    long long maxTime = 0;
+
+    for (set<shared_ptr<Thread> >::iterator ix = clientThreads.begin(); ix != clientThreads.end(); ix++) {
+
+      shared_ptr<ClientThread> client = dynamic_pointer_cast<ClientThread>((*ix)->runnable());
+
+      long long delta = client->_endTime - client->_startTime;
+
+      assert(delta > 0);
+
+      if (client->_startTime < firstTime) {
+        firstTime = client->_startTime;
+      }
+
+      if (client->_endTime > lastTime) {
+        lastTime = client->_endTime;
+      }
+
+      if (delta < minTime) {
+        minTime = delta;
+      }
+
+      if (delta > maxTime) {
+        maxTime = delta;
+      }
+
+      averageTime+= delta;
+    }
+
+    averageTime /= clientCount;
+
+
+    cout <<  "workers :" << workerCount << ", client : " << clientCount << ", loops : " << loopCount << ", rate : " << (clientCount * loopCount * 1000) / ((double)(time01 - time00)) << endl;
+
+    count_map count = serviceHandler->getCount();
+    count_map::iterator iter;
+    for (iter = count.begin(); iter != count.end(); ++iter) {
+      printf("%s => %d\n", iter->first, iter->second);
+    }
+    cerr << "done." << endl;
+  }
+
+  return 0;
+}
diff --git a/test/csharp/CSharpClient.cs b/test/csharp/CSharpClient.cs
new file mode 100644
index 0000000..641d5c9
--- /dev/null
+++ b/test/csharp/CSharpClient.cs
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ */
+
+using System;
+using Thrift;
+using Thrift.Protocol;
+using Thrift.Server;
+using Thrift.Transport;
+
+
+namespace CSharpTutorial
+{
+    public class CSharpClient
+    {
+        public static void Main()
+        {
+            try
+            {
+                TTransport transport = new TSocket("localhost", 9090);
+                TProtocol protocol = new TBinaryProtocol(transport);
+                Calculator.Client client = new Calculator.Client(protocol);
+
+                transport.Open();
+
+                client.ping();
+                Console.WriteLine("ping()");
+
+                int sum = client.add(1, 1);
+                Console.WriteLine("1+1={0}", sum);
+
+                Work work = new Work();
+
+                work.op = Operation.DIVIDE;
+                work.num1 = 1;
+                work.num2 = 0;
+                try
+                {
+                    int quotient = client.calculate(1, work);
+                    Console.WriteLine("Whoa we can divide by 0");
+                }
+                catch (InvalidOperation io)
+                {
+                    Console.WriteLine("Invalid operation: " + io.why);
+                }
+
+                work.op = Operation.SUBTRACT;
+                work.num1 = 15;
+                work.num2 = 10;
+                try
+                {
+                    int diff = client.calculate(1, work);
+                    Console.WriteLine("15-10={0}", diff);
+                }
+                catch (InvalidOperation io)
+                {
+                    Console.WriteLine("Invalid operation: " + io.why);
+                }
+
+                SharedStruct log = client.getStruct(1);
+                Console.WriteLine("Check log: {0}", log.value);
+
+                transport.Close();
+            }
+            catch (TApplicationException x)
+            {
+                Console.WriteLine(x.StackTrace);
+            }
+
+        }
+    }
+}
diff --git a/test/csharp/CSharpServer.cs b/test/csharp/CSharpServer.cs
new file mode 100644
index 0000000..f9ab8fd
--- /dev/null
+++ b/test/csharp/CSharpServer.cs
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+
+using System;
+using System.Collections.Generic;
+using Thrift.Server;
+using Thrift.Transport;
+
+namespace CSharpTutorial
+{
+    public class CalculatorHandler : Calculator.Iface
+    {
+        Dictionary<int, SharedStruct> log;
+
+        public CalculatorHandler()
+        {
+            log = new Dictionary<int, SharedStruct>();
+        }
+
+        public void ping()
+        {
+            Console.WriteLine("ping()");
+        }
+
+        public int add(int n1, int n2)
+        {
+            Console.WriteLine("add({0},{1})", n1, n2);
+            return n1 + n2;
+        }
+
+        public int calculate(int logid, Work work)
+        {
+            Console.WriteLine("calculate({0}, [{1},{2},{3}])", logid, work.op, work.num1, work.num2);
+            int val = 0;
+            switch (work.op)
+            {
+                case Operation.ADD:
+                    val = work.num1 + work.num2;
+                    break;
+
+                case Operation.SUBTRACT:
+                    val = work.num1 - work.num2;
+                    break;
+
+                case Operation.MULTIPLY:
+                    val = work.num1 * work.num2;
+                    break;
+
+                case Operation.DIVIDE:
+                    if (work.num2 == 0)
+                    {
+                        InvalidOperation io = new InvalidOperation();
+                        io.what = (int)work.op;
+                        io.why = "Cannot divide by 0";
+                        throw io;
+                    }
+                    val = work.num1 / work.num2;
+                    break;
+
+                default:
+                    {
+                        InvalidOperation io = new InvalidOperation();
+                        io.what = (int)work.op;
+                        io.why = "Unknown operation";
+                        throw io;
+                    }
+            }
+
+            SharedStruct entry = new SharedStruct();
+            entry.key = logid;
+            entry.value = val.ToString();
+            log[logid] = entry;
+
+            return val;
+        }
+
+        public SharedStruct getStruct(int key)
+        {
+            Console.WriteLine("getStruct({0})", key);
+            return log[key];
+        }
+
+        public void zip()
+        {
+            Console.WriteLine("zip()");
+        }
+    }
+
+    public class CSharpServer
+    {
+        public static void Main()
+        {
+            try
+            {
+                CalculatorHandler handler = new CalculatorHandler();
+                Calculator.Processor processor = new Calculator.Processor(handler);
+                TServerTransport serverTransport = new TServerSocket(9090);
+                TServer server = new TSimpleServer(processor, serverTransport);
+
+                // Use this for a multithreaded server
+                // server = new TThreadPoolServer(processor, serverTransport);
+
+                Console.WriteLine("Starting the server...");
+                server.Serve();
+            }
+            catch (Exception x)
+            {
+                Console.WriteLine(x.StackTrace);
+            }
+            Console.WriteLine("done.");
+        }
+    }
+}
diff --git a/test/csharp/ThriftTest/Program.cs b/test/csharp/ThriftTest/Program.cs
new file mode 100644
index 0000000..4c63ca4
--- /dev/null
+++ b/test/csharp/ThriftTest/Program.cs
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+// Distributed under the Thrift Software License
+//
+// See accompanying file LICENSE or visit the Thrift site at:
+// http://developers.facebook.com/thrift/
+
+using System;
+using Thrift.Transport;
+using Thrift.Protocol;
+using Thrift.Test; //generated code
+
+namespace Test
+{
+	class Program
+	{
+		static void Main(string[] args)
+		{
+			if (args.Length == 0)
+			{
+				Console.WriteLine("must provide 'server' or 'client' arg");
+				return;
+			}
+
+			string[] subArgs = new string[args.Length - 1];
+			for(int i = 1; i < args.Length; i++)
+			{
+				subArgs[i-1] = args[i];
+			}
+			if (args[0] == "client")
+			{
+				TestClient.Execute(subArgs);
+			}
+			else if (args[0] == "server")
+			{
+				TestServer.Execute(subArgs);
+			}
+			else
+			{
+				Console.WriteLine("first argument must be 'server' or 'client'");
+			}
+		}
+	}
+}
diff --git a/test/csharp/ThriftTest/Properties/AssemblyInfo.cs b/test/csharp/ThriftTest/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..504ca8d
--- /dev/null
+++ b/test/csharp/ThriftTest/Properties/AssemblyInfo.cs
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("ThriftTest")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("ThriftTest")]
+[assembly: AssemblyCopyright("Copyright © 2009 The Apache Software Foundation")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components.  If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("f41b193b-f1ab-48ee-8843-f88e43084e26")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/test/csharp/ThriftTest/TestClient.cs b/test/csharp/ThriftTest/TestClient.cs
new file mode 100644
index 0000000..2d278b7
--- /dev/null
+++ b/test/csharp/ThriftTest/TestClient.cs
@@ -0,0 +1,425 @@
+/*
+ * 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.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using Thrift.Collections;
+using Thrift.Protocol;
+using Thrift.Transport;
+using Thrift.Test;
+
+namespace Test
+{
+	public class TestClient
+	{
+		private static int numIterations = 1;
+
+		public static void Execute(string[] args)
+		{
+			try
+			{
+				string host = "localhost";
+				int port = 9090;
+				string url = null;
+				int numThreads = 1;
+				bool buffered = false;
+
+				try
+				{
+					for (int i = 0; i < args.Length; i++)
+					{
+						if (args[i] == "-h")
+						{
+							string[] hostport = args[++i].Split(':');
+							host = hostport[0];
+							if (hostport.Length > 1)
+							{
+								port = Convert.ToInt32(hostport[1]);
+							}
+						}
+						else if (args[i] == "-u")
+						{
+							url = args[++i];
+						}
+						else if (args[i] == "-n")
+						{
+							numIterations = Convert.ToInt32(args[++i]);
+						}
+						else if (args[i] == "-b" || args[i] == "-buffered")
+						{
+							buffered = true;
+							Console.WriteLine("Using buffered sockets");
+						}
+						else if (args[i] == "-t")
+						{
+							numThreads = Convert.ToInt32(args[++i]);
+						}
+					}
+				}
+				catch (Exception e)
+				{
+					Console.WriteLine(e.StackTrace);
+				}
+
+
+
+				//issue tests on separate threads simultaneously
+				Thread[] threads = new Thread[numThreads];
+				DateTime start = DateTime.Now;
+				for (int test = 0; test < numThreads; test++)
+				{
+					Thread t = new Thread(new ParameterizedThreadStart(ClientThread));
+					threads[test] = t;
+					TSocket socket = new TSocket(host, port);
+					if (buffered)
+					{
+						TBufferedTransport buffer = new TBufferedTransport(socket);
+						t.Start(buffer);
+					}
+					else
+					{
+						t.Start(socket);
+					}
+				}
+
+				for (int test = 0; test < numThreads; test++)
+				{
+					threads[test].Join();
+				}
+				Console.Write("Total time: " + (DateTime.Now - start));
+			}
+			catch (Exception outerEx)
+			{
+				Console.WriteLine(outerEx.Message + " ST: " + outerEx.StackTrace);
+			}
+
+			Console.WriteLine();
+			Console.WriteLine();
+		}
+
+		public static void ClientThread(object obj)
+		{
+			TTransport transport = (TTransport)obj;
+			for (int i = 0; i < numIterations; i++)
+			{
+				ClientTest(transport);
+			}
+			transport.Close();
+		}
+
+		public static void ClientTest(TTransport transport)
+		{
+			TBinaryProtocol binaryProtocol = new TBinaryProtocol(transport);
+
+			ThriftTest.Client client = new ThriftTest.Client(binaryProtocol);
+			try
+			{
+				if (!transport.IsOpen)
+				{
+					transport.Open();
+				}
+			}
+			catch (TTransportException ttx)
+			{
+				Console.WriteLine("Connect failed: " + ttx.Message);
+				return;
+			}
+
+			long start = DateTime.Now.ToFileTime();
+
+			Console.Write("testVoid()");
+			client.testVoid();
+			Console.WriteLine(" = void");
+
+			Console.Write("testString(\"Test\")");
+			string s = client.testString("Test");
+			Console.WriteLine(" = \"" + s + "\"");
+
+			Console.Write("testByte(1)");
+			byte i8 = client.testByte((byte)1);
+			Console.WriteLine(" = " + i8);
+
+			Console.Write("testI32(-1)");
+			int i32 = client.testI32(-1);
+			Console.WriteLine(" = " + i32);
+
+			Console.Write("testI64(-34359738368)");
+			long i64 = client.testI64(-34359738368);
+			Console.WriteLine(" = " + i64);
+
+			Console.Write("testDouble(5.325098235)");
+			double dub = client.testDouble(5.325098235);
+			Console.WriteLine(" = " + dub);
+
+			Console.Write("testStruct({\"Zero\", 1, -3, -5})");
+			Xtruct o = new Xtruct();
+			o.String_thing = "Zero";
+			o.Byte_thing = (byte)1;
+			o.I32_thing = -3;
+			o.I64_thing = -5;
+			Xtruct i = client.testStruct(o);
+			Console.WriteLine(" = {\"" + i.String_thing + "\", " + i.Byte_thing + ", " + i.I32_thing + ", " + i.I64_thing + "}");
+
+			Console.Write("testNest({1, {\"Zero\", 1, -3, -5}, 5})");
+			Xtruct2 o2 = new Xtruct2();
+			o2.Byte_thing = (byte)1;
+			o2.Struct_thing = o;
+			o2.I32_thing = 5;
+			Xtruct2 i2 = client.testNest(o2);
+			i = i2.Struct_thing;
+			Console.WriteLine(" = {" + i2.Byte_thing + ", {\"" + i.String_thing + "\", " + i.Byte_thing + ", " + i.I32_thing + ", " + i.I64_thing + "}, " + i2.I32_thing + "}");
+
+			Dictionary<int, int> mapout = new Dictionary<int, int>();
+			for (int j = 0; j < 5; j++)
+			{
+				mapout[j] = j - 10;
+			}
+			Console.Write("testMap({");
+			bool first = true;
+			foreach (int key in mapout.Keys)
+			{
+				if (first)
+				{
+					first = false;
+				}
+				else
+				{
+					Console.Write(", ");
+				}
+				Console.Write(key + " => " + mapout[key]);
+			}
+			Console.Write("})");
+
+			Dictionary<int, int> mapin = client.testMap(mapout);
+
+			Console.Write(" = {");
+			first = true;
+			foreach (int key in mapin.Keys)
+			{
+				if (first)
+				{
+					first = false;
+				}
+				else
+				{
+					Console.Write(", ");
+				}
+				Console.Write(key + " => " + mapin[key]);
+			}
+			Console.WriteLine("}");
+
+			List<int> listout = new List<int>();
+			for (int j = -2; j < 3; j++)
+			{
+				listout.Add(j);
+			}
+			Console.Write("testList({");
+			first = true;
+			foreach (int j in listout)
+			{
+				if (first)
+				{
+					first = false;
+				}
+				else
+				{
+					Console.Write(", ");
+				}
+				Console.Write(j);
+			}
+			Console.Write("})");
+
+			List<int> listin = client.testList(listout);
+
+			Console.Write(" = {");
+			first = true;
+			foreach (int j in listin)
+			{
+				if (first)
+				{
+					first = false;
+				}
+				else
+				{
+					Console.Write(", ");
+				}
+				Console.Write(j);
+			}
+			Console.WriteLine("}");
+
+			//set
+			THashSet<int> setout = new THashSet<int>();
+			for (int j = -2; j < 3; j++)
+			{
+				setout.Add(j);
+			}
+			Console.Write("testSet({");
+			first = true;
+			foreach (int j in setout)
+			{
+				if (first)
+				{
+					first = false;
+				}
+				else
+				{
+					Console.Write(", ");
+				}
+				Console.Write(j);
+			}
+			Console.Write("})");
+
+			THashSet<int> setin = client.testSet(setout);
+
+			Console.Write(" = {");
+			first = true;
+			foreach (int j in setin)
+			{
+				if (first)
+				{
+					first = false;
+				}
+				else
+				{
+					Console.Write(", ");
+				}
+				Console.Write(j);
+			}
+			Console.WriteLine("}");
+
+
+			Console.Write("testEnum(ONE)");
+			Numberz ret = client.testEnum(Numberz.ONE);
+			Console.WriteLine(" = " + ret);
+
+			Console.Write("testEnum(TWO)");
+			ret = client.testEnum(Numberz.TWO);
+			Console.WriteLine(" = " + ret);
+
+			Console.Write("testEnum(THREE)");
+			ret = client.testEnum(Numberz.THREE);
+			Console.WriteLine(" = " + ret);
+
+			Console.Write("testEnum(FIVE)");
+			ret = client.testEnum(Numberz.FIVE);
+			Console.WriteLine(" = " + ret);
+
+			Console.Write("testEnum(EIGHT)");
+			ret = client.testEnum(Numberz.EIGHT);
+			Console.WriteLine(" = " + ret);
+
+			Console.Write("testTypedef(309858235082523)");
+			long uid = client.testTypedef(309858235082523L);
+			Console.WriteLine(" = " + uid);
+
+			Console.Write("testMapMap(1)");
+			Dictionary<int, Dictionary<int, int>> mm = client.testMapMap(1);
+			Console.Write(" = {");
+			foreach (int key in mm.Keys)
+			{
+				Console.Write(key + " => {");
+				Dictionary<int, int> m2 = mm[key];
+				foreach (int k2 in m2.Keys)
+				{
+					Console.Write(k2 + " => " + m2[k2] + ", ");
+				}
+				Console.Write("}, ");
+			}
+			Console.WriteLine("}");
+
+			Insanity insane = new Insanity();
+			insane.UserMap = new Dictionary<Numberz, long>();
+			insane.UserMap[Numberz.FIVE] = 5000L;
+			Xtruct truck = new Xtruct();
+			truck.String_thing = "Truck";
+			truck.Byte_thing = (byte)8;
+			truck.I32_thing = 8;
+			truck.I64_thing = 8;
+			insane.Xtructs = new List<Xtruct>();
+			insane.Xtructs.Add(truck);
+			Console.Write("testInsanity()");
+			Dictionary<long, Dictionary<Numberz, Insanity>> whoa = client.testInsanity(insane);
+			Console.Write(" = {");
+			foreach (long key in whoa.Keys)
+			{
+				Dictionary<Numberz, Insanity> val = whoa[key];
+				Console.Write(key + " => {");
+
+				foreach (Numberz k2 in val.Keys)
+				{
+					Insanity v2 = val[k2];
+
+					Console.Write(k2 + " => {");
+					Dictionary<Numberz, long> userMap = v2.UserMap;
+
+					Console.Write("{");
+					if (userMap != null)
+					{
+						foreach (Numberz k3 in userMap.Keys)
+						{
+							Console.Write(k3 + " => " + userMap[k3] + ", ");
+						}
+					}
+					else
+					{
+						Console.Write("null");
+					}
+					Console.Write("}, ");
+
+					List<Xtruct> xtructs = v2.Xtructs;
+
+					Console.Write("{");
+					if (xtructs != null)
+					{
+						foreach (Xtruct x in xtructs)
+						{
+							Console.Write("{\"" + x.String_thing + "\", " + x.Byte_thing + ", " + x.I32_thing + ", " + x.I32_thing + "}, ");
+						}
+					}
+					else
+					{
+						Console.Write("null");
+					}
+					Console.Write("}");
+
+					Console.Write("}, ");
+				}
+				Console.Write("}, ");
+			}
+			Console.WriteLine("}");
+
+
+			byte arg0 = 1;
+			int arg1 = 2;
+			long arg2 = long.MaxValue;
+			Dictionary<short, string> multiDict = new Dictionary<short, string>();
+			multiDict[1] = "one";
+			Numberz arg4 = Numberz.FIVE;
+			long arg5 = 5000000;
+			Console.Write("Test Multi(" + arg0 + "," + arg1 + "," + arg2 + "," + multiDict + "," + arg4 + "," + arg5 + ")");
+			Xtruct multiResponse = client.testMulti(arg0, arg1, arg2, multiDict, arg4, arg5);
+			Console.Write(" = Xtruct(byte_thing:" + multiResponse.Byte_thing + ",String_thing:" + multiResponse.String_thing
+						+ ",i32_thing:" + multiResponse.I32_thing + ",i64_thing:" + multiResponse.I64_thing + ")\n");
+
+			Console.WriteLine("Test Oneway(1)");
+			client.testOneway(1);
+		}
+	}
+}
diff --git a/test/csharp/ThriftTest/TestServer.cs b/test/csharp/ThriftTest/TestServer.cs
new file mode 100644
index 0000000..e370640
--- /dev/null
+++ b/test/csharp/ThriftTest/TestServer.cs
@@ -0,0 +1,348 @@
+/*
+ * 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.
+ */
+
+// Distributed under the Thrift Software License
+//
+// See accompanying file LICENSE or visit the Thrift site at:
+// http://developers.facebook.com/thrift/
+using System;
+using System.Collections.Generic;
+using Thrift.Collections;
+using Thrift.Test; //generated code
+using Thrift.Transport;
+using Thrift.Protocol;
+using Thrift.Server;
+
+namespace Test
+{
+	public class TestServer
+	{
+		public class TestHandler : ThriftTest.Iface
+		{
+			public TServer server;
+
+			public TestHandler() { }
+
+			public void testVoid()
+			{
+				Console.WriteLine("testVoid()");
+			}
+
+			public string testString(string thing)
+			{
+				Console.WriteLine("teststring(\"" + thing + "\")");
+				return thing;
+			}
+
+			public byte testByte(byte thing)
+			{
+				Console.WriteLine("testByte(" + thing + ")");
+				return thing;
+			}
+
+			public int testI32(int thing)
+			{
+				Console.WriteLine("testI32(" + thing + ")");
+				return thing;
+			}
+
+			public long testI64(long thing)
+			{
+				Console.WriteLine("testI64(" + thing + ")");
+				return thing;
+			}
+
+			public double testDouble(double thing)
+			{
+				Console.WriteLine("testDouble(" + thing + ")");
+				return thing;
+			}
+
+			public Xtruct testStruct(Xtruct thing)
+			{
+				Console.WriteLine("testStruct({" +
+								 "\"" + thing.String_thing + "\", " +
+								 thing.Byte_thing + ", " +
+								 thing.I32_thing + ", " +
+								 thing.I64_thing + "})");
+				return thing;
+			}
+
+			public Xtruct2 testNest(Xtruct2 nest)
+			{
+				Xtruct thing = nest.Struct_thing;
+				Console.WriteLine("testNest({" +
+								 nest.Byte_thing + ", {" +
+								 "\"" + thing.String_thing + "\", " +
+								 thing.Byte_thing + ", " +
+								 thing.I32_thing + ", " +
+								 thing.I64_thing + "}, " +
+								 nest.I32_thing + "})");
+				return nest;
+			}
+
+			public Dictionary<int, int> testMap(Dictionary<int, int> thing)
+			{
+				Console.WriteLine("testMap({");
+				bool first = true;
+				foreach (int key in thing.Keys)
+				{
+					if (first)
+					{
+						first = false;
+					}
+					else
+					{
+						Console.WriteLine(", ");
+					}
+					Console.WriteLine(key + " => " + thing[key]);
+				}
+				Console.WriteLine("})");
+				return thing;
+			}
+
+			public THashSet<int> testSet(THashSet<int> thing)
+			{
+				Console.WriteLine("testSet({");
+				bool first = true;
+				foreach (int elem in thing)
+				{
+					if (first)
+					{
+						first = false;
+					}
+					else
+					{
+						Console.WriteLine(", ");
+					}
+					Console.WriteLine(elem);
+				}
+				Console.WriteLine("})");
+				return thing;
+			}
+
+			public List<int> testList(List<int> thing)
+			{
+				Console.WriteLine("testList({");
+				bool first = true;
+				foreach (int elem in thing)
+				{
+					if (first)
+					{
+						first = false;
+					}
+					else
+					{
+						Console.WriteLine(", ");
+					}
+					Console.WriteLine(elem);
+				}
+				Console.WriteLine("})");
+				return thing;
+			}
+
+			public Numberz testEnum(Numberz thing)
+			{
+				Console.WriteLine("testEnum(" + thing + ")");
+				return thing;
+			}
+
+			public long testTypedef(long thing)
+			{
+				Console.WriteLine("testTypedef(" + thing + ")");
+				return thing;
+			}
+
+			public Dictionary<int, Dictionary<int, int>> testMapMap(int hello)
+			{
+				Console.WriteLine("testMapMap(" + hello + ")");
+				Dictionary<int, Dictionary<int, int>> mapmap =
+				  new Dictionary<int, Dictionary<int, int>>();
+
+				Dictionary<int, int> pos = new Dictionary<int, int>();
+				Dictionary<int, int> neg = new Dictionary<int, int>();
+				for (int i = 1; i < 5; i++)
+				{
+					pos[i] = i;
+					neg[-i] = -i;
+				}
+
+				mapmap[4] = pos;
+				mapmap[-4] = neg;
+
+				return mapmap;
+			}
+
+			public Dictionary<long, Dictionary<Numberz, Insanity>> testInsanity(Insanity argument)
+			{
+				Console.WriteLine("testInsanity()");
+
+				Xtruct hello = new Xtruct();
+				hello.String_thing = "Hello2";
+				hello.Byte_thing = 2;
+				hello.I32_thing = 2;
+				hello.I64_thing = 2;
+
+				Xtruct goodbye = new Xtruct();
+				goodbye.String_thing = "Goodbye4";
+				goodbye.Byte_thing = (byte)4;
+				goodbye.I32_thing = 4;
+				goodbye.I64_thing = (long)4;
+
+				Insanity crazy = new Insanity();
+				crazy.UserMap = new Dictionary<Numberz, long>();
+				crazy.UserMap[Numberz.EIGHT] = (long)8;
+				crazy.Xtructs = new List<Xtruct>();
+				crazy.Xtructs.Add(goodbye);
+
+				Insanity looney = new Insanity();
+				crazy.UserMap[Numberz.FIVE] = (long)5;
+				crazy.Xtructs.Add(hello);
+
+				Dictionary<Numberz, Insanity> first_map = new Dictionary<Numberz, Insanity>();
+				Dictionary<Numberz, Insanity> second_map = new Dictionary<Numberz, Insanity>(); ;
+
+				first_map[Numberz.TWO] = crazy;
+				first_map[Numberz.THREE] = crazy;
+
+				second_map[Numberz.SIX] = looney;
+
+				Dictionary<long, Dictionary<Numberz, Insanity>> insane =
+				  new Dictionary<long, Dictionary<Numberz, Insanity>>();
+				insane[(long)1] = first_map;
+				insane[(long)2] = second_map;
+
+				return insane;
+			}
+
+			public Xtruct testMulti(byte arg0, int arg1, long arg2, Dictionary<short, string> arg3, Numberz arg4, long arg5)
+			{
+				Console.WriteLine("testMulti()");
+
+				Xtruct hello = new Xtruct(); ;
+				hello.String_thing = "Hello2";
+				hello.Byte_thing = arg0;
+				hello.I32_thing = arg1;
+				hello.I64_thing = arg2;
+				return hello;
+			}
+
+			public void testException(string arg)
+			{
+				Console.WriteLine("testException(" + arg + ")");
+				if (arg == "Xception")
+				{
+					Xception x = new Xception();
+					x.ErrorCode = 1001;
+					x.Message = "This is an Xception";
+					throw x;
+				}
+				return;
+			}
+
+			public Xtruct testMultiException(string arg0, string arg1)
+			{
+				Console.WriteLine("testMultiException(" + arg0 + ", " + arg1 + ")");
+				if (arg0 == "Xception")
+				{
+					Xception x = new Xception();
+					x.ErrorCode = 1001;
+					x.Message = "This is an Xception";
+					throw x;
+				}
+				else if (arg0 == "Xception2")
+				{
+					Xception2 x = new Xception2();
+					x.ErrorCode = 2002;
+					x.Struct_thing = new Xtruct();
+					x.Struct_thing.String_thing = "This is an Xception2";
+					throw x;
+				}
+
+				Xtruct result = new Xtruct();
+				result.String_thing = arg1;
+				return result;
+			}
+
+			public void testStop()
+			{
+				if (server != null)
+				{
+					server.Stop();
+				}
+			}
+
+			public void testOneway(int arg)
+			{
+				Console.WriteLine("testOneway(" + arg + "), sleeping...");
+				System.Threading.Thread.Sleep(arg * 1000);
+				Console.WriteLine("testOneway finished");
+			}
+
+		} // class TestHandler
+
+		public static void Execute(string[] args)
+		{
+			try
+			{
+				bool useBufferedSockets = false;
+				int port = 9090;
+				if (args.Length > 0)
+				{
+					port = int.Parse(args[0]);
+
+					if (args.Length > 1)
+					{
+						bool.TryParse(args[1], out useBufferedSockets);
+					}
+				}
+
+				// Processor
+				TestHandler testHandler = new TestHandler();
+				ThriftTest.Processor testProcessor = new ThriftTest.Processor(testHandler);
+
+				// Transport
+				TServerSocket tServerSocket = new TServerSocket(port, 0, useBufferedSockets);
+
+				TServer serverEngine;
+
+				// Simple Server
+				serverEngine = new TSimpleServer(testProcessor, tServerSocket);
+
+				// ThreadPool Server
+				// serverEngine = new TThreadPoolServer(testProcessor, tServerSocket);
+
+				// Threaded Server
+				// serverEngine = new TThreadedServer(testProcessor, tServerSocket);
+
+				testHandler.server = serverEngine;
+
+				// Run it
+				Console.WriteLine("Starting the server on port " + port + (useBufferedSockets ? " with buffered socket" : "") + "...");
+				serverEngine.Serve();
+
+			}
+			catch (Exception x)
+			{
+				Console.Error.Write(x);
+			}
+			Console.WriteLine("done.");
+		}
+	}
+}
diff --git a/test/csharp/ThriftTest/ThriftTest.csproj b/test/csharp/ThriftTest/ThriftTest.csproj
new file mode 100644
index 0000000..3f427fd
--- /dev/null
+++ b/test/csharp/ThriftTest/ThriftTest.csproj
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.21022</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{48DD757F-CA95-4DD7-BDA4-58DB6F108C2C}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>ThriftTest</RootNamespace>
+    <AssemblyName>ThriftTest</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <PublishUrl>publish\</PublishUrl>
+    <Install>true</Install>
+    <InstallFrom>Disk</InstallFrom>
+    <UpdateEnabled>false</UpdateEnabled>
+    <UpdateMode>Foreground</UpdateMode>
+    <UpdateInterval>7</UpdateInterval>
+    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+    <UpdatePeriodically>false</UpdatePeriodically>
+    <UpdateRequired>false</UpdateRequired>
+    <MapFileExtensions>true</MapFileExtensions>
+    <ApplicationRevision>0</ApplicationRevision>
+    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+    <IsWebBootstrapper>false</IsWebBootstrapper>
+    <UseApplicationTrust>false</UseApplicationTrust>
+    <BootstrapperEnabled>true</BootstrapperEnabled>
+    <SccProjectName>SAK</SccProjectName>
+    <SccLocalPath>SAK</SccLocalPath>
+    <SccAuxPath>SAK</SccAuxPath>
+    <SccProvider>SAK</SccProvider>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="ThriftImpl, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>.\ThriftImpl.dll</HintPath>
+    </Reference>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="TestClient.cs" />
+    <Compile Include="TestServer.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 2.0 %28x86%29</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.0">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.0 %28x86%29</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+      <Visible>False</Visible>
+      <ProductName>Windows Installer 3.1</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\lib\csharp\src\Thrift.csproj">
+      <Project>{499EB63C-D74C-47E8-AE48-A2FC94538E9D}</Project>
+      <Name>Thrift</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+  <PropertyGroup>
+    <PreBuildEvent>rmdir /s /q $(ProjectDir)gen-csharp
+del /f /q $(ProjectDir)ThriftImpl.dll
+
+$(ProjectDir)\..\..\..\compiler\cpp\thrift.exe -csharp -o $(ProjectDir) $(ProjectDir)\..\..\ThriftTest.thrift
+
+cd $(ProjectDir)
+
+$(MSBuildToolsPath)\Csc.exe /t:library /out:.\ThriftImpl.dll /recurse:.\gen-csharp\* /reference:$(ProjectDir)..\..\..\lib\csharp\src\bin\Debug\Thrift.dll</PreBuildEvent>
+  </PropertyGroup>
+</Project>
diff --git a/test/csharp/ThriftTest/maketest.sh b/test/csharp/ThriftTest/maketest.sh
new file mode 100755
index 0000000..5580de8
--- /dev/null
+++ b/test/csharp/ThriftTest/maketest.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+#
+# 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.
+#
+
+../../../compiler/cpp/thrift --gen csharp -o . ../../ThriftTest.thrift
+gmcs /t:library /out:./ThriftImpl.dll /recurse:./gen-csharp/* /reference:../../../lib/csharp/Thrift.dll
diff --git a/test/erl/Makefile b/test/erl/Makefile
new file mode 100644
index 0000000..17e30da
--- /dev/null
+++ b/test/erl/Makefile
@@ -0,0 +1,66 @@
+#
+# 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.
+#
+
+GENDIR=gen
+GEN_INCLUDEDIR=$(GENDIR)/include
+GEN_SRCDIR=$(GENDIR)/src
+GEN_TARGETDIR=$(GENDIR)/ebin
+
+INCLUDEDIR=include
+TARGETDIR=ebin
+SRCDIR=src
+
+ALL_INCLUDEDIR=$(GEN_INCLUDEDIR) $(INCLUDEDIR) ../../lib/erl/include
+INCLUDEFLAGS=$(patsubst %,-I%, ${ALL_INCLUDEDIR})
+
+MODULES = stress_server test_server test_disklog test_membuffer
+
+INCLUDES = 
+TARGETS = $(patsubst %,${TARGETDIR}/%.beam,${MODULES})
+HEADERS = $(patsubst %,${INCLUDEDIR}/%.hrl,${INCLUDES})
+
+all: ${GEN_TARGETDIR}/ ${TARGETS}
+
+TEST_RPCFILE = ../ThriftTest.thrift
+STRESS_RPCFILE = ../StressTest.thrift
+THRIFT = ../../compiler/cpp/thrift
+
+${GENDIR}/: ${RPCFILE}
+	rm -rf ${GENDIR}
+	${THRIFT} --gen erl ${TEST_RPCFILE}
+	${THRIFT} --gen erl ${STRESS_RPCFILE}
+	mkdir -p ${GEN_INCLUDEDIR}
+	mkdir -p ${GEN_SRCDIR}
+	mkdir -p ${GEN_TARGETDIR}
+	mv -t ${GEN_INCLUDEDIR} gen-erl/*.hrl
+	mv -t ${GEN_SRCDIR} gen-erl/*.erl
+	rm -rf gen-erl
+
+${GEN_TARGETDIR}/: ${GENDIR}/
+	rm -rf ${GEN_TARGETDIR}
+	mkdir -p ${GEN_TARGETDIR}
+	erlc ${INCLUDEFLAGS} -o ${GEN_TARGETDIR} ${GEN_SRCDIR}/*.erl
+
+$(TARGETS): ${TARGETDIR}/%.beam: ${SRCDIR}/%.erl ${GEN_INCLUDEDIR}/ ${HEADERS}
+	mkdir -p ${TARGETDIR}
+	erlc ${INCLUDEFLAGS} -o ${TARGETDIR} $<
+
+clean:
+	rm -f ${TARGETDIR}/*.beam
+	rm -rf ${GENDIR}
diff --git a/test/erl/src/stress_server.erl b/test/erl/src/stress_server.erl
new file mode 100644
index 0000000..35fff06
--- /dev/null
+++ b/test/erl/src/stress_server.erl
@@ -0,0 +1,64 @@
+%%
+%% 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.
+%%
+
+-module(stress_server).
+
+
+-export([start_link/1,
+
+         handle_function/2,
+
+         echoVoid/0,
+         echoByte/1,
+         echoI32/1,
+         echoI64/1,
+         echoString/1,
+         echoList/1,
+         echoSet/1,
+         echoMap/1
+        ]).
+
+start_link(Port) ->
+    thrift_server:start_link(Port, service_thrift, ?MODULE).
+
+
+handle_function(Function, Args) ->
+    case apply(?MODULE, Function, tuple_to_list(Args)) of
+        ok ->
+             ok;
+        Else -> {reply, Else}
+    end.
+
+
+echoVoid() ->
+    ok.
+echoByte(X) ->
+    X.
+echoI32(X) ->
+    X.
+echoI64(X) ->
+    X.
+echoString(X) ->
+    X.
+echoList(X) ->
+    X.
+echoSet(X) ->
+    X.
+echoMap(X) ->
+    X.
diff --git a/test/erl/src/test_disklog.erl b/test/erl/src/test_disklog.erl
new file mode 100644
index 0000000..7b0be72
--- /dev/null
+++ b/test/erl/src/test_disklog.erl
@@ -0,0 +1,81 @@
+%%
+%% 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.
+%%
+
+-module(test_disklog).
+
+-compile(export_all).
+
+t() ->
+    {ok, TransportFactory} =
+        thrift_disk_log_transport:new_transport_factory(
+          test_disklog,
+          [{file, "/tmp/test_log"},
+           {size, {1024*1024, 10}}]),
+    {ok, ProtocolFactory} = thrift_binary_protocol:new_protocol_factory(
+                              TransportFactory, []),
+    {ok, Client} = thrift_client:start_link(ProtocolFactory, thriftTest_thrift),
+
+    io:format("Client started~n"),
+
+    % We have to make oneway calls into this client only since otherwise it will try
+    % to read from the disklog and go boom.
+    {ok, ok} = thrift_client:call(Client, testOneway, [16#deadbeef]),
+    io:format("Call written~n"),
+
+    % Use the send_call method to write a non-oneway call into the log
+    ok = thrift_client:send_call(Client, testString, [<<"hello world">>]),
+    io:format("Non-oneway call sent~n"),
+
+    ok = thrift_client:close(Client),
+    io:format("Client closed~n"),
+
+    ok.
+
+
+
+t_base64() ->
+    {ok, TransportFactory} =
+        thrift_disk_log_transport:new_transport_factory(
+          test_disklog,
+          [{file, "/tmp/test_b64_log"},
+           {size, {1024*1024, 10}}]),
+    {ok, B64Factory} =
+        thrift_base64_transport:new_transport_factory(TransportFactory),
+    {ok, BufFactory} =
+        thrift_buffered_transport:new_transport_factory(B64Factory),
+    {ok, ProtocolFactory} = thrift_binary_protocol:new_protocol_factory(
+                              BufFactory, []),
+    {ok, Client} = thrift_client:start_link(ProtocolFactory, thriftTest_thrift),
+
+    io:format("Client started~n"),
+
+    % We have to make oneway calls into this client only since otherwise it will try
+    % to read from the disklog and go boom.
+    {ok, ok} = thrift_client:call(Client, testOneway, [16#deadbeef]),
+    io:format("Call written~n"),
+
+    % Use the send_call method to write a non-oneway call into the log
+    ok = thrift_client:send_call(Client, testString, [<<"hello world">>]),
+    io:format("Non-oneway call sent~n"),
+
+    ok = thrift_client:close(Client),
+    io:format("Client closed~n"),
+
+    ok.
+    
diff --git a/test/erl/src/test_membuffer.erl b/test/erl/src/test_membuffer.erl
new file mode 100644
index 0000000..7bd23a0
--- /dev/null
+++ b/test/erl/src/test_membuffer.erl
@@ -0,0 +1,81 @@
+%%
+%% 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.
+%%
+
+-module(test_membuffer).
+-export([t/0]).
+
+-include("thriftTest_types.hrl").
+
+test_data() ->
+    #xtruct{string_thing = <<"foobar">>,
+	    byte_thing = 123,
+	    i32_thing = 1234567,
+	    i64_thing = 12345678900}.
+
+t1() ->
+    {ok, Transport} = thrift_memory_buffer:new(),
+    {ok, Protocol} = thrift_binary_protocol:new(Transport),
+    TestData = test_data(),
+    ok = thrift_protocol:write(Protocol,
+			       {{struct, element(2, thriftTest_types:struct_info('xtruct'))},
+				TestData}),
+    {ok, Result} = thrift_protocol:read(Protocol,
+					{struct, element(2, thriftTest_types:struct_info('xtruct'))},
+					'xtruct'),
+
+    Result = TestData.
+
+
+t2() ->
+    {ok, Transport} = thrift_memory_buffer:new(),
+    {ok, Protocol} = thrift_binary_protocol:new(Transport),
+    TestData = test_data(),
+    ok = thrift_protocol:write(Protocol,
+			       {{struct, element(2, thriftTest_types:struct_info('xtruct'))},
+				TestData}),
+    {ok, Result} = thrift_protocol:read(Protocol,
+					{struct, element(2, thriftTest_types:struct_info('xtruct3'))},
+					'xtruct3'),
+
+    Result = #xtruct3{string_thing = TestData#xtruct.string_thing,
+                      changed = undefined,
+                      i32_thing = TestData#xtruct.i32_thing,
+                      i64_thing = TestData#xtruct.i64_thing}.
+
+
+t3() ->
+    {ok, Transport} = thrift_memory_buffer:new(),
+    {ok, Protocol} = thrift_binary_protocol:new(Transport),
+    TestData = #bools{im_true = true, im_false = false},
+    ok = thrift_protocol:write(Protocol,
+			       {{struct, element(2, thriftTest_types:struct_info('bools'))},
+				TestData}),
+    {ok, Result} = thrift_protocol:read(Protocol,
+					{struct, element(2, thriftTest_types:struct_info('bools'))},
+					'bools'),
+
+    true = TestData#bools.im_true  =:= Result#bools.im_true,
+    true = TestData#bools.im_false =:= Result#bools.im_false.
+
+
+t() ->
+    t1(),
+    t2(),
+    t3().
+
diff --git a/test/erl/src/test_server.erl b/test/erl/src/test_server.erl
new file mode 100644
index 0000000..cd439cc
--- /dev/null
+++ b/test/erl/src/test_server.erl
@@ -0,0 +1,174 @@
+%%
+%% 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.
+%%
+
+-module(test_server).
+
+-export([start_link/1, handle_function/2]).
+
+-include("thriftTest_types.hrl").
+
+start_link(Port) ->
+    thrift_server:start_link(Port, thriftTest_thrift, ?MODULE).
+
+
+handle_function(testVoid, {}) ->
+    io:format("testVoid~n"),
+    ok;
+
+handle_function(testString, {S}) when is_binary(S) ->
+    io:format("testString: ~p~n", [S]),
+    {reply, S};
+
+handle_function(testByte, {I8}) when is_integer(I8) ->
+    io:format("testByte: ~p~n", [I8]),
+    {reply, I8};
+
+handle_function(testI32, {I32}) when is_integer(I32) ->
+    io:format("testI32: ~p~n", [I32]),
+    {reply, I32};
+
+handle_function(testI64, {I64}) when is_integer(I64) ->
+    io:format("testI64: ~p~n", [I64]),
+    {reply, I64};
+
+handle_function(testDouble, {Double}) when is_float(Double) ->
+    io:format("testDouble: ~p~n", [Double]),
+    {reply, Double};
+
+handle_function(testStruct,
+                {Struct = #xtruct{string_thing = String,
+                                 byte_thing = Byte,
+                                 i32_thing = I32,
+                                 i64_thing = I64}})
+when is_binary(String),
+     is_integer(Byte),
+     is_integer(I32),
+     is_integer(I64) ->
+    io:format("testStruct: ~p~n", [Struct]),
+    {reply, Struct};
+
+handle_function(testNest,
+                {Nest}) when is_record(Nest, xtruct2),
+                             is_record(Nest#xtruct2.struct_thing, xtruct) ->
+    io:format("testNest: ~p~n", [Nest]),
+    {reply, Nest};
+
+handle_function(testMap, {Map}) ->
+    io:format("testMap: ~p~n", [dict:to_list(Map)]),
+    {reply, Map};
+
+handle_function(testSet, {Set}) ->
+    true = sets:is_set(Set),
+    io:format("testSet: ~p~n", [sets:to_list(Set)]),
+    {reply, Set};
+
+handle_function(testList, {List}) when is_list(List) ->
+    io:format("testList: ~p~n", [List]),
+    {reply, List};
+
+handle_function(testEnum, {Enum}) when is_integer(Enum) ->
+    io:format("testEnum: ~p~n", [Enum]),
+    {reply, Enum};
+
+handle_function(testTypedef, {UserID}) when is_integer(UserID) ->
+    io:format("testTypedef: ~p~n", [UserID]),
+    {reply, UserID};
+
+handle_function(testMapMap, {Hello}) ->
+    io:format("testMapMap: ~p~n", [Hello]),
+
+    PosList = [{I, I}   || I <- lists:seq(1, 5)],
+    NegList = [{-I, -I} || I <- lists:seq(1, 5)],
+
+    MapMap = dict:from_list([{4,  dict:from_list(PosList)},
+                             {-4, dict:from_list(NegList)}]),
+    {reply, MapMap};
+
+handle_function(testInsanity, {Insanity}) when is_record(Insanity, insanity) ->
+    Hello = #xtruct{string_thing = <<"Hello2">>,
+                    byte_thing = 2,
+                    i32_thing = 2,
+                    i64_thing = 2},
+
+    Goodbye = #xtruct{string_thing = <<"Goodbye4">>,
+                      byte_thing = 4,
+                      i32_thing = 4,
+                      i64_thing = 4},
+    Crazy = #insanity{
+      userMap = dict:from_list([{?thriftTest_EIGHT, 8}]),
+      xtructs = [Goodbye]
+      },
+
+    Looney = #insanity{
+      userMap = dict:from_list([{?thriftTest_FIVE, 5}]),
+      xtructs = [Hello]
+      },
+
+    FirstMap = dict:from_list([{?thriftTest_TWO, Crazy},
+                               {?thriftTest_THREE, Crazy}]),
+
+    SecondMap = dict:from_list([{?thriftTest_SIX, Looney}]),
+    
+    Insane = dict:from_list([{1, FirstMap},
+                             {2, SecondMap}]),
+    
+    io:format("Return = ~p~n", [Insane]),
+    
+    {reply, Insane};
+
+handle_function(testMulti, Args = {Arg0, Arg1, Arg2, _Arg3, Arg4, Arg5})
+  when is_integer(Arg0),
+       is_integer(Arg1),
+       is_integer(Arg2),
+       is_integer(Arg4),
+       is_integer(Arg5) ->
+
+    io:format("testMulti(~p)~n", [Args]),
+    {reply, #xtruct{string_thing = <<"Hello2">>,
+                    byte_thing = Arg0,
+                    i32_thing = Arg1,
+                    i64_thing = Arg2}};
+
+handle_function(testException, {String}) when is_binary(String) ->
+    io:format("testException(~p)~n", [String]),
+    case String of
+        <<"Xception">> ->
+            throw(#xception{errorCode = 1001,
+                            message = <<"This is an Xception">>});
+        _ ->
+            ok
+    end;
+
+handle_function(testMultiException, {Arg0, Arg1}) ->
+    io:format("testMultiException(~p, ~p)~n", [Arg0, Arg1]),
+    case Arg0 of
+        <<"Xception">> ->
+            throw(#xception{errorCode = 1001,
+                                   message = <<"This is an Xception">>});
+        <<"Xception2">> ->
+            throw(#xception2{errorCode = 2002,
+                                    struct_thing =
+                                    #xtruct{string_thing = <<"This is an Xception2">>}});
+        _ ->
+            {reply, #xtruct{string_thing = Arg1}}
+    end;
+
+handle_function(testOneway, {Seconds}) ->
+    timer:sleep(1000 * Seconds),
+    ok.
diff --git a/test/hs/Client.hs b/test/hs/Client.hs
new file mode 100644
index 0000000..c5e4d90
--- /dev/null
+++ b/test/hs/Client.hs
@@ -0,0 +1,58 @@
+--
+-- 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.
+--
+
+module Client where
+
+import ThriftTest_Client
+import ThriftTest_Types
+import qualified Data.Map as Map
+import qualified Data.Set as Set
+import Control.Monad
+import Control.Exception as CE
+
+import Network
+
+import Thrift
+import Thrift.Transport.Handle
+import Thrift.Protocol.Binary
+
+
+serverAddress = ("127.0.0.1", PortNumber 9090)
+
+main = do to <- hOpen serverAddress
+          let p =  BinaryProtocol to
+          let ps = (p,p)
+          print =<< testString ps "bya"
+          print =<< testByte ps 8
+          print =<< testByte ps (-8)
+          print =<< testI32 ps 32
+          print =<< testI32 ps (-32)
+          print =<< testI64 ps 64
+          print =<< testI64 ps (-64)
+          print =<< testDouble ps 3.14
+          print =<< testDouble ps (-3.14)
+          print =<< testMap ps (Map.fromList [(1,1),(2,2),(3,3)])
+          print =<< testList ps [1,2,3,4,5]
+          print =<< testSet ps (Set.fromList [1,2,3,4,5])
+          print =<< testStruct ps (Xtruct (Just "hi") (Just 4) (Just 5) Nothing)
+          CE.catch (testException ps "e" >> print "bad") (\e -> print (e :: Xception))
+          CE.catch (testMultiException ps "e" "e2" >> print "ok") (\e -> print (e :: Xception))
+          CE.catch (CE.catch (testMultiException ps "e" "e2">> print "bad") (\e -> print (e :: Xception2))) (\(e :: SomeException) -> print "ok")
+          tClose to
+
diff --git a/test/hs/Server.hs b/test/hs/Server.hs
new file mode 100644
index 0000000..0ca9d9f
--- /dev/null
+++ b/test/hs/Server.hs
@@ -0,0 +1,57 @@
+--
+-- 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.
+--
+
+module Server where
+
+import ThriftTest
+import ThriftTest_Iface
+import Data.Map as Map
+import Control.Exception
+import ThriftTest_Types
+
+import Thrift
+import Thrift.Server
+
+
+data TestHandler = TestHandler
+instance ThriftTest_Iface TestHandler where
+    testVoid a = return ()
+    testString a (Just s) = do print s; return s
+    testByte a (Just x) = do print x; return x
+    testI32 a (Just x) = do print x; return x
+    testI64 a (Just x) = do print x; return x
+    testDouble a (Just x) = do print x; return x
+    testStruct a (Just x) = do print x; return x
+    testNest a (Just x) = do print x; return x
+    testMap a (Just x) = do print x; return x
+    testSet a (Just x) = do print x; return x
+    testList a (Just x) = do print x; return x
+    testEnum a (Just x) = do print x; return x
+    testTypedef a (Just x) = do print x; return x
+    testMapMap a (Just x) = return (Map.fromList [(1,Map.fromList [(2,2)])])
+    testInsanity a (Just x) = return (Map.fromList [(1,Map.fromList [(ONE,x)])])
+    testMulti a a1 a2 a3 a4 a5 a6 = return (Xtruct Nothing Nothing Nothing Nothing)
+    testException a c = throw (Xception (Just 1) (Just "bya"))
+    testMultiException a c1 c2 = throw (Xception (Just 1) (Just "xyz"))
+    testOneway a (Just i) = do print i
+
+
+main = do (runBasicServer TestHandler process 9090)
+          `Control.Exception.catch`
+          (\(TransportExn s t) -> print s)
diff --git a/test/hs/runclient.sh b/test/hs/runclient.sh
new file mode 100644
index 0000000..b93bbb1
--- /dev/null
+++ b/test/hs/runclient.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+#
+# 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.
+#
+
+if [ -z $BASE ]; then
+    BASE=../..
+fi
+
+ghci -fglasgow-exts -i$BASE/lib/hs/src -i$BASE/test/hs/gen-hs Client.hs
diff --git a/test/hs/runserver.sh b/test/hs/runserver.sh
new file mode 100644
index 0000000..b23301b
--- /dev/null
+++ b/test/hs/runserver.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+#
+# 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.
+#
+
+if [ -z $BASE ]; then
+    BASE=../..
+fi
+
+printf "Starting server... "
+ghc -fglasgow-exts -i$BASE/lib/hs/src -i$BASE/test/hs/gen-hs Server.hs -e "putStrLn \"ready.\" >> Server.main"
diff --git a/test/ocaml/Makefile b/test/ocaml/Makefile
new file mode 100644
index 0000000..a543ce5
--- /dev/null
+++ b/test/ocaml/Makefile
@@ -0,0 +1,24 @@
+#
+# 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.
+#
+
+all:
+	cd client; make; cd ..; cd server; make
+clean:
+	cd client; make clean; cd ..; cd server; make clean
+
diff --git a/test/ocaml/client/Makefile b/test/ocaml/client/Makefile
new file mode 100644
index 0000000..806ed20
--- /dev/null
+++ b/test/ocaml/client/Makefile
@@ -0,0 +1,26 @@
+#
+# 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.
+#
+
+SOURCES = ../gen-ocaml/ThriftTest_types.ml ../gen-ocaml/ThriftTest_consts.ml ../gen-ocaml/SecondService.ml ../gen-ocaml/ThriftTest.ml TestClient.ml
+RESULT = tc
+INCDIRS = "../../../lib/ocaml/src/" "../gen-ocaml/"
+LIBS = unix thrift
+all: nc
+OCAMLMAKEFILE = ../../../lib/ocaml/OCamlMakefile
+include $(OCAMLMAKEFILE)
diff --git a/test/ocaml/client/TestClient.ml b/test/ocaml/client/TestClient.ml
new file mode 100644
index 0000000..91783ae
--- /dev/null
+++ b/test/ocaml/client/TestClient.ml
@@ -0,0 +1,82 @@
+(*
+ 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.
+*)
+
+open Thrift;;
+open ThriftTest_types;;
+
+let s = new TSocket.t "127.0.0.1" 9090;;
+let p = new TBinaryProtocol.t s;;
+let c = new ThriftTest.client p p;;
+let sod = function
+    Some v -> v
+  | None -> raise Thrift_error;;
+
+s#opn;
+print_string (c#testString "bya");
+print_char '\n';
+print_int (c#testByte 8);
+print_char '\n';
+print_int (c#testByte (-8));
+print_char '\n';
+print_int (c#testI32 32);
+print_char '\n';
+print_string (Int64.to_string (c#testI64 64L));
+print_char '\n';
+print_float (c#testDouble 3.14);
+print_char '\n';
+
+let l = [1;2;3;4] in
+  if l = (c#testList l) then print_string "list ok\n" else print_string "list fail\n";;
+let h = Hashtbl.create 5 in
+let a = Hashtbl.add h in
+  for i=1 to 10 do
+    a i (10*i)
+  done;
+  let r = c#testMap h in
+    for i=1 to 10 do
+      try
+        let g = Hashtbl.find r i in
+          print_int i;
+          print_char ' ';
+          print_int g;
+          print_char '\n'
+      with Not_found -> print_string ("Can't find "^(string_of_int i)^"\n")
+    done;;
+
+let s = Hashtbl.create 5 in
+let a = Hashtbl.add s in
+  for i = 1 to 10 do
+    a i true
+  done;
+  let r = c#testSet s in
+    for i = 1 to 10 do
+      try
+        let g = Hashtbl.find r i in
+          print_int i;
+          print_char '\n'
+      with Not_found -> print_string ("Can't find "^(string_of_int i)^"\n")
+    done;;
+try
+  c#testException "Xception"
+with Xception _ -> print_string "testException ok\n";;
+try
+  ignore(c#testMultiException "Xception" "bya")
+with Xception e -> Printf.printf "%d %s\n" (sod e#get_errorCode) (sod e#get_message);;
+
+
diff --git a/test/ocaml/server/Makefile b/test/ocaml/server/Makefile
new file mode 100644
index 0000000..44dcac7
--- /dev/null
+++ b/test/ocaml/server/Makefile
@@ -0,0 +1,27 @@
+#
+# 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.
+#
+
+SOURCES = ../gen-ocaml/ThriftTest_types.ml ../gen-ocaml/ThriftTest_consts.ml ../gen-ocaml/SecondService.ml ../gen-ocaml/ThriftTest.ml TestServer.ml
+RESULT = ts
+INCDIRS = "../../../lib/ocaml/src/" "../gen-ocaml/"
+LIBS = thrift
+THREADS = yes
+all: nc
+OCAMLMAKEFILE = ../../../lib/ocaml/OCamlMakefile
+include $(OCAMLMAKEFILE)
diff --git a/test/ocaml/server/TestServer.ml b/test/ocaml/server/TestServer.ml
new file mode 100644
index 0000000..3f5c9ee
--- /dev/null
+++ b/test/ocaml/server/TestServer.ml
@@ -0,0 +1,136 @@
+(*
+ 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.
+*)
+
+open Thrift
+open ThriftTest_types
+
+let p = Printf.printf;;
+exception Die;;
+let sod = function
+    Some v -> v
+  | None -> raise Die;;
+
+
+class test_handler =
+object (self)
+  inherit ThriftTest.iface
+  method testVoid = p "testVoid()\n"
+  method testString x = p "testString(%s)\n" (sod x); (sod x)
+  method testByte x = p "testByte(%d)\n" (sod x); (sod x)
+  method testI32 x = p "testI32(%d)\n" (sod x); (sod x)
+  method testI64 x = p "testI64(%s)\n" (Int64.to_string (sod x)); (sod x)
+  method testDouble x = p "testDouble(%f)\n" (sod x); (sod x)
+  method testStruct x = p "testStruct(---)\n"; (sod x)
+  method testNest x = p "testNest(---)\n"; (sod x)
+  method testMap x = p "testMap(---)\n"; (sod x)
+  method testSet x = p "testSet(---)\n"; (sod x)
+  method testList x = p "testList(---)\n"; (sod x)
+  method testEnum x = p "testEnum(---)\n"; (sod x)
+  method testTypedef x = p "testTypedef(---)\n"; (sod x)
+  method testMapMap x = p "testMapMap(%d)\n" (sod x);
+    let mm = Hashtbl.create 3 in
+    let pos = Hashtbl.create 7 in
+    let neg = Hashtbl.create 7 in
+      for i=1 to 4 do
+        Hashtbl.add pos i i;
+        Hashtbl.add neg (-i) (-i);
+      done;
+      Hashtbl.add mm 4 pos;
+      Hashtbl.add mm (-4) neg;
+      mm
+  method testInsanity x = p "testInsanity()\n";
+    p "testinsanity()\n";
+    let hello = new xtruct in
+    let goodbye = new xtruct in
+    let crazy = new insanity in
+    let looney = new insanity in
+    let cumap = Hashtbl.create 7 in
+    let insane = Hashtbl.create 7 in
+    let firstmap = Hashtbl.create 7 in
+    let secondmap = Hashtbl.create 7 in
+      hello#set_string_thing "Hello2";
+      hello#set_byte_thing 2;
+      hello#set_i32_thing 2;
+      hello#set_i64_thing 2L;
+      goodbye#set_string_thing "Goodbye4";
+      goodbye#set_byte_thing 4;
+      goodbye#set_i32_thing 4;
+      goodbye#set_i64_thing 4L;
+      Hashtbl.add cumap Numberz.EIGHT 8L;
+      Hashtbl.add cumap Numberz.FIVE 5L;
+      crazy#set_userMap cumap;
+      crazy#set_xtructs [goodbye; hello];
+      Hashtbl.add firstmap Numberz.TWO crazy;
+      Hashtbl.add firstmap Numberz.THREE crazy;
+      Hashtbl.add secondmap Numberz.SIX looney;
+      Hashtbl.add insane 1L firstmap;
+      Hashtbl.add insane 2L secondmap;
+      insane
+  method testMulti a0 a1 a2 a3 a4 a5 =
+    p "testMulti()\n";
+    let hello = new xtruct in
+      hello#set_string_thing "Hello2";
+      hello#set_byte_thing (sod a0);
+      hello#set_i32_thing (sod a1);
+      hello#set_i64_thing (sod a2);
+      hello
+  method testException s =
+    p "testException(%S)\n" (sod s);
+    if (sod s) = "Xception" then
+      let x = new xception in
+        x#set_errorCode 1001;
+        x#set_message "This is an Xception";
+        raise (Xception x)
+    else ()
+  method testMultiException a0 a1 =
+    p "testMultiException(%S, %S)\n" (sod a0) (sod a1);
+    if (sod a0) = "Xception" then
+      let x = new xception in
+        x#set_errorCode 1001;
+        x#set_message "This is an Xception";
+        raise (Xception x)
+    else (if (sod a0) = "Xception2" then
+              let x = new xception2 in
+              let s = new xtruct in
+                x#set_errorCode 2002;
+                s#set_string_thing "This as an Xception2";
+                x#set_struct_thing s;
+                raise (Xception2 x)
+          else ());
+    let res = new xtruct in
+      res#set_string_thing (sod a1);
+      res
+  method testOneway i =
+    Unix.sleep (sod i)
+end;;
+
+let h = new test_handler in
+let proc = new ThriftTest.processor h in
+let port = 9090 in
+let pf = new TBinaryProtocol.factory in
+let server = new TThreadedServer.t
+  proc
+  (new TServerSocket.t port)
+  (new Transport.factory)
+  pf
+  pf
+in
+  server#serve
+
+
diff --git a/test/perl/Makefile b/test/perl/Makefile
new file mode 100644
index 0000000..e2d81d4
--- /dev/null
+++ b/test/perl/Makefile
@@ -0,0 +1,30 @@
+#
+# 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.
+#
+
+# Default target is everything
+target: all
+
+# Tools
+THRIFT = ../../compiler/cpp/thrift
+
+all: ../ThriftTest.thrift
+	$(THRIFT) --gen perl ../ThriftTest.thrift
+
+clean:
+	$(RM) -r gen-perl
diff --git a/test/perl/TestClient.pl b/test/perl/TestClient.pl
new file mode 100644
index 0000000..af80d46
--- /dev/null
+++ b/test/perl/TestClient.pl
@@ -0,0 +1,338 @@
+#!/usr/bin/env perl
+
+#
+# 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.
+#
+
+require 5.6.0;
+use strict;
+use warnings;
+use Data::Dumper;
+use Time::HiRes qw(gettimeofday);
+
+use lib '../../lib/perl/lib';
+use lib 'gen-perl';
+
+use Thrift;
+use Thrift::BinaryProtocol;
+use Thrift::Socket;
+use Thrift::BufferedTransport;
+
+use ThriftTest::ThriftTest;
+use ThriftTest::Types;
+
+$|++;
+
+my $host = 'localhost';
+my $port = 9090;
+
+
+my $socket = new Thrift::Socket($host, $port);
+
+my $bufferedSocket = new Thrift::BufferedTransport($socket, 1024, 1024);
+my $transport = $bufferedSocket;
+my $protocol = new Thrift::BinaryProtocol($transport);
+my $testClient = new ThriftTest::ThriftTestClient($protocol);
+
+eval{
+$transport->open();
+}; if($@){
+    die(Dumper($@));
+}
+my $start = gettimeofday();
+
+#
+# VOID TEST
+#
+print("testVoid()");
+$testClient->testVoid();
+print(" = void\n");
+
+#
+# STRING TEST
+#
+print("testString(\"Test\")");
+my $s = $testClient->testString("Test");
+print(" = \"$s\"\n");
+
+#
+# BYTE TEST
+#
+print("testByte(1)");
+my $u8 = $testClient->testByte(1);
+print(" = $u8\n");
+
+#
+# I32 TEST
+#
+print("testI32(-1)");
+my $i32 = $testClient->testI32(-1);
+print(" = $i32\n");
+
+#
+#I64 TEST
+#
+print("testI64(-34359738368)");
+my $i64 = $testClient->testI64(-34359738368);
+print(" = $i64\n");
+
+#
+# DOUBLE TEST
+#
+print("testDouble(-852.234234234)");
+my $dub = $testClient->testDouble(-852.234234234);
+print(" = $dub\n");
+
+#
+# STRUCT TEST
+#
+print("testStruct({\"Zero\", 1, -3, -5})");
+my $out = new ThriftTest::Xtruct();
+$out->string_thing("Zero");
+$out->byte_thing(1);
+$out->i32_thing(-3);
+$out->i64_thing(-5);
+my $in = $testClient->testStruct($out);
+print(" = {\"".$in->string_thing."\", ".
+        $in->byte_thing.", ".
+        $in->i32_thing.", ".
+        $in->i64_thing."}\n");
+
+#
+# NESTED STRUCT TEST
+#
+print("testNest({1, {\"Zero\", 1, -3, -5}, 5}");
+my $out2 = new ThriftTest::Xtruct2();
+$out2->byte_thing(1);
+$out2->struct_thing($out);
+$out2->i32_thing(5);
+my $in2 = $testClient->testNest($out2);
+$in = $in2->struct_thing;
+print(" = {".$in2->byte_thing.", {\"".
+      $in->string_thing."\", ".
+      $in->byte_thing.", ".
+      $in->i32_thing.", ".
+      $in->i64_thing."}, ".
+      $in2->i32_thing."}\n");
+
+#
+# MAP TEST
+#
+my $mapout = {};
+for (my $i = 0; $i < 5; ++$i) {
+  $mapout->{$i} = $i-10;
+}
+print("testMap({");
+my $first = 1;
+while( my($key,$val) = each %$mapout) {
+    if ($first) {
+        $first = 0;
+    } else {
+        print(", ");
+    }
+    print("$key => $val");
+}
+print("})");
+
+
+my $mapin = $testClient->testMap($mapout);
+print(" = {");
+
+$first = 1;
+while( my($key,$val) = each %$mapin){
+    if ($first) {
+        $first = 0;
+    } else {
+        print(", ");
+    }
+    print("$key => $val");
+}
+print("}\n");
+
+#
+# SET TEST
+#
+my $setout = [];
+for (my $i = -2; $i < 3; ++$i) {
+    push(@$setout, $i);
+}
+
+print("testSet({".join(",",@$setout)."})");
+
+my $setin = $testClient->testSet($setout);
+
+print(" = {".join(",",@$setout)."}\n");
+
+#
+# LIST TEST
+#
+my $listout = [];
+for (my $i = -2; $i < 3; ++$i) {
+    push(@$listout, $i);
+}
+
+print("testList({".join(",",@$listout)."})");
+
+my $listin = $testClient->testList($listout);
+
+print(" = {".join(",",@$listin)."}\n");
+
+#
+# ENUM TEST
+#
+print("testEnum(ONE)");
+my $ret = $testClient->testEnum(ThriftTest::Numberz::ONE);
+print(" = $ret\n");
+
+print("testEnum(TWO)");
+$ret = $testClient->testEnum(ThriftTest::Numberz::TWO);
+print(" = $ret\n");
+
+print("testEnum(THREE)");
+$ret = $testClient->testEnum(ThriftTest::Numberz::THREE);
+print(" = $ret\n");
+
+print("testEnum(FIVE)");
+$ret = $testClient->testEnum(ThriftTest::Numberz::FIVE);
+print(" = $ret\n");
+
+print("testEnum(EIGHT)");
+$ret = $testClient->testEnum(ThriftTest::Numberz::EIGHT);
+print(" = $ret\n");
+
+#
+# TYPEDEF TEST
+#
+print("testTypedef(309858235082523)");
+my $uid = $testClient->testTypedef(309858235082523);
+print(" = $uid\n");
+
+#
+# NESTED MAP TEST
+#
+print("testMapMap(1)");
+my $mm = $testClient->testMapMap(1);
+print(" = {");
+while( my ($key,$val) = each %$mm) {
+    print("$key => {");
+    while( my($k2,$v2) = each %$val) {
+        print("$k2 => $v2, ");
+    }
+    print("}, ");
+}
+print("}\n");
+
+#
+# INSANITY TEST
+#
+my $insane = new ThriftTest::Insanity();
+$insane->{userMap}->{ThriftTest::Numberz::FIVE} = 5000;
+my $truck = new ThriftTest::Xtruct();
+$truck->string_thing("Truck");
+$truck->byte_thing(8);
+$truck->i32_thing(8);
+$truck->i64_thing(8);
+push(@{$insane->{xtructs}}, $truck);
+
+print("testInsanity()");
+my $whoa = $testClient->testInsanity($insane);
+print(" = {");
+while( my ($key,$val) = each %$whoa) {
+    print("$key => {");
+    while( my($k2,$v2) = each %$val) {
+        print("$k2 => {");
+        my $userMap = $v2->{userMap};
+        print("{");
+        if (ref($userMap) eq "HASH") {
+            while( my($k3,$v3) = each %$userMap) {
+                print("$k3 => $v3, ");
+            }
+        }
+        print("}, ");
+
+        my $xtructs = $v2->{xtructs};
+        print("{");
+        if (ref($xtructs) eq "ARRAY") {
+            foreach my $x (@$xtructs) {
+                print("{\"".$x->{string_thing}."\", ".
+                      $x->{byte_thing}.", ".$x->{i32_thing}.", ".$x->{i64_thing}."}, ");
+            }
+        }
+        print("}");
+
+        print("}, ");
+    }
+    print("}, ");
+}
+print("}\n");
+
+#
+# EXCEPTION TEST
+#
+print("testException('Xception')");
+eval {
+    $testClient->testException('Xception');
+    print("  void\nFAILURE\n");
+}; if($@ && $@->UNIVERSAL::isa('ThriftTest::Xception')) {
+    print(' caught xception '.$@->{errorCode}.': '.$@->{message}."\n");
+}
+
+
+#
+# Normal tests done.
+#
+my $stop = gettimeofday();
+my $elp  = sprintf("%d",1000*($stop - $start), 0);
+print("Total time: $elp ms\n");
+
+#
+# Extraneous "I don't trust PHP to pack/unpack integer" tests
+#
+
+# Max I32
+my $num = 2**30 + 2**30 - 1;
+my $num2 = $testClient->testI32($num);
+if ($num != $num2) {
+    print "Missed max32 $num = $num2\n";
+}
+
+# Min I32
+$num = 0 - 2**31;
+$num2 = $testClient->testI32($num);
+if ($num != $num2) {
+    print "Missed min32 $num = $num2\n";
+}
+
+# Max Number I can get out of my perl
+$num = 2**40;
+$num2 = $testClient->testI64($num);
+if ($num != $num2) {
+    print "Missed max64 $num = $num2\n";
+}
+
+# Max Number I can get out of my perl
+$num = 0 - 2**40;
+$num2 = $testClient->testI64($num);
+if ($num != $num2) {
+    print "Missed min64 $num = $num2\n";
+}
+
+$transport->close();
+
+
+
diff --git a/test/php/Makefile b/test/php/Makefile
new file mode 100644
index 0000000..aa35c6e
--- /dev/null
+++ b/test/php/Makefile
@@ -0,0 +1,39 @@
+#
+# 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.
+#
+
+# Default target is everything
+target: all
+
+# Tools
+THRIFT = ../../compiler/cpp/thrift
+
+all: normal inline
+
+normal: stubs
+
+inline: stubs-inline
+
+stubs: ../ThriftTest.thrift
+	$(THRIFT) --gen php ../ThriftTest.thrift
+
+stubs-inline: ../ThriftTest.thrift
+	$(THRIFT) --gen php:inlined ../ThriftTest.thrift
+
+clean:
+	$(RM) -r gen-php gen-phpi
diff --git a/test/php/TestClient.php b/test/php/TestClient.php
new file mode 100644
index 0000000..6d640da
--- /dev/null
+++ b/test/php/TestClient.php
@@ -0,0 +1,398 @@
+/*
+ * 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.
+ */
+
+<?php
+
+if (!isset($GEN_DIR)) {
+  $GEN_DIR = 'gen-php';
+}
+if (!isset($MODE)) {
+  $MODE = 'normal';
+}
+
+/** Set the Thrift root */
+$GLOBALS['THRIFT_ROOT'] = '../../lib/php/src';
+
+/** Include the Thrift base */
+require_once $GLOBALS['THRIFT_ROOT'].'/Thrift.php';
+
+/** Include the binary protocol */
+require_once $GLOBALS['THRIFT_ROOT'].'/protocol/TBinaryProtocol.php';
+
+/** Include the socket layer */
+require_once $GLOBALS['THRIFT_ROOT'].'/transport/TSocketPool.php';
+
+/** Include the socket layer */
+require_once $GLOBALS['THRIFT_ROOT'].'/transport/TBufferedTransport.php';
+
+echo '==============================='."\n";
+echo ' SAFE TO IGNORE THESE IN TEST'."\n";
+echo '==============================='."\n";
+
+/** Include the generated code */
+require_once $GEN_DIR.'/ThriftTest.php';
+require_once $GEN_DIR.'/ThriftTest_types.php';
+
+echo '==============================='."\n";
+echo ' END OF SAFE ERRORS SECTION'."\n";
+echo '==============================='."\n\n";
+
+$host = 'localhost';
+$port = 9090;
+
+if ($argc > 1) {
+  $host = $argv[0];
+}
+
+if ($argc > 2) {
+  $host = $argv[1];
+}
+
+$hosts = array('localhost');
+
+$socket = new TSocket($host, $port);
+$socket = new TSocketPool($hosts, $port);
+$socket->setDebug(TRUE);
+
+if ($MODE == 'inline') {
+  $transport = $socket;
+  $testClient = new ThriftTestClient($transport);
+} else {
+  $bufferedSocket = new TBufferedTransport($socket, 1024, 1024);
+  $transport = $bufferedSocket;
+  $protocol = new TBinaryProtocol($transport);
+  $testClient = new ThriftTestClient($protocol);
+}
+
+$transport->open();
+
+$start = microtime(true);
+
+/**
+ * VOID TEST
+ */
+print_r("testVoid()");
+$testClient->testVoid();
+print_r(" = void\n");
+
+/**
+ * STRING TEST
+ */
+print_r("testString(\"Test\")");
+$s = $testClient->testString("Test");
+print_r(" = \"$s\"\n");
+
+/**
+ * BYTE TEST
+ */
+print_r("testByte(1)");
+$u8 = $testClient->testByte(1);
+print_r(" = $u8\n");
+
+/**
+ * I32 TEST
+ */
+print_r("testI32(-1)");
+$i32 = $testClient->testI32(-1);
+print_r(" = $i32\n");
+
+/**
+ * I64 TEST
+ */
+print_r("testI64(-34359738368)");
+$i64 = $testClient->testI64(-34359738368);
+print_r(" = $i64\n");
+
+/**
+ * DOUBLE TEST
+ */
+print_r("testDouble(-852.234234234)");
+$dub = $testClient->testDouble(-852.234234234);
+print_r(" = $dub\n");
+
+/**
+ * STRUCT TEST
+ */
+print_r("testStruct({\"Zero\", 1, -3, -5})");
+$out = new Xtruct();
+$out->string_thing = "Zero";
+$out->byte_thing = 1;
+$out->i32_thing = -3;
+$out->i64_thing = -5;
+$in = $testClient->testStruct($out);
+print_r(" = {\"".$in->string_thing."\", ".
+        $in->byte_thing.", ".
+        $in->i32_thing.", ".
+        $in->i64_thing."}\n");
+
+/**
+ * NESTED STRUCT TEST
+ */
+print_r("testNest({1, {\"Zero\", 1, -3, -5}), 5}");
+$out2 = new Xtruct2();
+$out2->byte_thing = 1;
+$out2->struct_thing = $out;
+$out2->i32_thing = 5;
+$in2 = $testClient->testNest($out2);
+$in = $in2->struct_thing;
+print_r(" = {".$in2->byte_thing.", {\"".
+        $in->string_thing."\", ".
+        $in->byte_thing.", ".
+        $in->i32_thing.", ".
+        $in->i64_thing."}, ".
+        $in2->i32_thing."}\n");
+
+/**
+ * MAP TEST
+ */
+$mapout = array();
+for ($i = 0; $i < 5; ++$i) {
+  $mapout[$i] = $i-10;
+}
+print_r("testMap({");
+$first = true;
+foreach ($mapout as $key => $val) {
+  if ($first) {
+    $first = false;
+  } else {
+    print_r(", ");
+  }
+  print_r("$key => $val");
+}
+print_r("})");
+
+$mapin = $testClient->testMap($mapout);
+print_r(" = {");
+$first = true;
+foreach ($mapin as $key => $val) {
+  if ($first) {
+    $first = false;
+  } else {
+    print_r(", ");
+  }
+  print_r("$key => $val");
+}
+print_r("}\n");
+
+/**
+ * SET TEST
+ */
+$setout = array();;
+for ($i = -2; $i < 3; ++$i) {
+  $setout []= $i;
+}
+print_r("testSet({");
+$first = true;
+foreach ($setout as $val) {
+  if ($first) {
+    $first = false;
+  } else {
+    print_r(", ");
+  }
+  print_r($val);
+}
+print_r("})");
+$setin = $testClient->testSet($setout);
+print_r(" = {");
+$first = true;
+foreach ($setin as $val) {
+  if ($first) {
+    $first = false;
+  } else {
+    print_r(", ");
+  }
+  print_r($val);
+}
+print_r("}\n");
+
+/**
+ * LIST TEST
+ */
+$listout = array();
+for ($i = -2; $i < 3; ++$i) {
+  $listout []= $i;
+}
+print_r("testList({");
+$first = true;
+foreach ($listout as $val) {
+  if ($first) {
+    $first = false;
+  } else {
+    print_r(", ");
+  }
+  print_r($val);
+}
+print_r("})");
+$listin = $testClient->testList($listout);
+print_r(" = {");
+$first = true;
+foreach ($listin as $val) {
+  if ($first) {
+    $first = false;
+  } else {
+    print_r(", ");
+  }
+  print_r($val);
+}
+print_r("}\n");
+
+/**
+ * ENUM TEST
+ */
+print_r("testEnum(ONE)");
+$ret = $testClient->testEnum(Numberz::ONE);
+print_r(" = $ret\n");
+
+print_r("testEnum(TWO)");
+$ret = $testClient->testEnum(Numberz::TWO);
+print_r(" = $ret\n");
+
+print_r("testEnum(THREE)");
+$ret = $testClient->testEnum(Numberz::THREE);
+print_r(" = $ret\n");
+
+print_r("testEnum(FIVE)");
+$ret = $testClient->testEnum(Numberz::FIVE);
+print_r(" = $ret\n");
+
+print_r("testEnum(EIGHT)");
+$ret = $testClient->testEnum(Numberz::EIGHT);
+print_r(" = $ret\n");
+
+/**
+ * TYPEDEF TEST
+ */
+print_r("testTypedef(309858235082523)");
+$uid = $testClient->testTypedef(309858235082523);
+print_r(" = $uid\n");
+
+/**
+ * NESTED MAP TEST
+ */
+print_r("testMapMap(1)");
+$mm = $testClient->testMapMap(1);
+print_r(" = {");
+foreach ($mm as $key => $val) {
+  print_r("$key => {");
+  foreach ($val as $k2 => $v2) {
+    print_r("$k2 => $v2, ");
+  }
+  print_r("}, ");
+}
+print_r("}\n");
+
+/**
+ * INSANITY TEST
+ */
+$insane = new Insanity();
+$insane->userMap[Numberz::FIVE] = 5000;
+$truck = new Xtruct();
+$truck->string_thing = "Truck";
+$truck->byte_thing = 8;
+$truck->i32_thing = 8;
+$truck->i64_thing = 8;
+$insane->xtructs []= $truck;
+print_r("testInsanity()");
+$whoa = $testClient->testInsanity($insane);
+print_r(" = {");
+foreach ($whoa as $key => $val) {
+  print_r("$key => {");
+  foreach ($val as $k2 => $v2) {
+    print_r("$k2 => {");
+    $userMap = $v2->userMap;
+    print_r("{");
+    if (is_array($usermap)) {
+      foreach ($userMap as $k3 => $v3) {
+        print_r("$k3 => $v3, ");
+      }
+    }
+    print_r("}, ");
+
+    $xtructs = $v2->xtructs;
+    print_r("{");
+    if (is_array($xtructs)) {
+      foreach ($xtructs as $x) {
+        print_r("{\"".$x->string_thing."\", ".
+                $x->byte_thing.", ".$x->i32_thing.", ".$x->i64_thing."}, ");
+      }
+    }
+    print_r("}");
+
+    print_r("}, ");
+  }
+  print_r("}, ");
+}
+print_r("}\n");
+
+/**
+ * EXCEPTION TEST
+ */
+print_r("testException('Xception')");
+try {
+  $testClient->testException('Xception');
+  print_r("  void\nFAILURE\n");
+} catch (Xception $x) {
+  print_r(' caught xception '.$x->errorCode.': '.$x->message."\n");
+}
+
+
+/**
+ * Normal tests done.
+ */
+
+$stop = microtime(true);
+$elp = round(1000*($stop - $start), 0);
+print_r("Total time: $elp ms\n");
+
+/**
+ * Extraneous "I don't trust PHP to pack/unpack integer" tests
+ */
+
+// Max I32
+$num = pow(2, 30) + (pow(2, 30) - 1);
+$num2 = $testClient->testI32($num);
+if ($num != $num2) {
+  print "Missed $num = $num2\n";
+}
+
+// Min I32
+$num = 0 - pow(2, 31);
+$num2 = $testClient->testI32($num);
+if ($num != $num2) {
+  print "Missed $num = $num2\n";
+}
+
+// Max I64
+$num = pow(2, 62) + (pow(2, 62) - 1);
+$num2 = $testClient->testI64($num);
+if ($num != $num2) {
+  print "Missed $num = $num2\n";
+}
+
+// Min I64
+$num = 0 - pow(2, 63);
+$num2 = $testClient->testI64($num);
+if ($num != $num2) {
+  print "Missed $num = $num2\n";
+}
+
+$transport->close();
+return;
+
+?>
diff --git a/test/php/TestInline.php b/test/php/TestInline.php
new file mode 100644
index 0000000..7066c46
--- /dev/null
+++ b/test/php/TestInline.php
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+<?php
+$GEN_DIR = 'gen-phpi';
+$MODE = 'inline';
+include_once('TestClient.php');
+?>
diff --git a/test/py/Makefile.am b/test/py/Makefile.am
new file mode 100644
index 0000000..63b7a89
--- /dev/null
+++ b/test/py/Makefile.am
@@ -0,0 +1,48 @@
+#
+# 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.
+#
+
+THRIFT = $(top_srcdir)/compiler/cpp/thrift
+
+py_unit_tests =                                 \
+        SerializationTest.py                    \
+        TestEof.py                              \
+        TestSyntax.py                           \
+        RunClientServer.py
+
+thrift_gen =                                    \
+        gen-py/ThriftTest/__init__.py           \
+        gen-py/DebugProtoTest/__init__.py
+
+helper_scripts=                                 \
+        TestClient.py                           \
+        TestServer.py
+
+check_SCRIPTS=                                  \
+        $(thrift_gen)                           \
+        $(py_unit_tests)                        \
+        $(helper_scripts)
+
+TESTS= $(py_unit_tests)
+
+
+gen-py/%/__init__.py: ../%.thrift
+	$(THRIFT) --gen py $<
+
+clean-local:
+	$(RM) -r gen-py
diff --git a/test/py/RunClientServer.py b/test/py/RunClientServer.py
new file mode 100755
index 0000000..2bd6094
--- /dev/null
+++ b/test/py/RunClientServer.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+
+#
+# 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.
+#
+
+import time
+import subprocess
+import sys
+import os
+import signal
+
+def relfile(fname):
+    return os.path.join(os.path.dirname(__file__), fname)
+
+FRAMED = ["TNonblockingServer"]
+
+def runTest(server_class):
+    print "Testing ", server_class
+    serverproc = subprocess.Popen([sys.executable, relfile("TestServer.py"), server_class])
+    time.sleep(0.25)
+    try:
+        argv = [sys.executable, relfile("TestClient.py")]
+        if server_class in FRAMED:
+            argv.append('--framed')
+        if server_class == 'THttpServer':
+            argv.append('--http=/')
+        ret = subprocess.call(argv)
+        if ret != 0:
+            raise Exception("subprocess failed")
+    finally:
+        # fixme: should check that server didn't die
+        os.kill(serverproc.pid, signal.SIGKILL)
+
+    # wait for shutdown
+    time.sleep(1)
+
+map(runTest, [
+  "TSimpleServer",
+  "TThreadedServer",
+  "TThreadPoolServer",
+  "TForkingServer",
+  "TNonblockingServer",
+  "THttpServer",
+  ])
diff --git a/test/py/SerializationTest.py b/test/py/SerializationTest.py
new file mode 100755
index 0000000..52bedd5
--- /dev/null
+++ b/test/py/SerializationTest.py
@@ -0,0 +1,133 @@
+#!/usr/bin/env python
+
+#
+# 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.
+#
+
+import sys, glob
+sys.path.insert(0, './gen-py')
+sys.path.insert(0, glob.glob('../../lib/py/build/lib.*')[0])
+
+from ThriftTest.ttypes import *
+from thrift.transport import TTransport
+from thrift.transport import TSocket
+from thrift.protocol import TBinaryProtocol
+import unittest
+import time
+
+class AbstractTest(unittest.TestCase):
+
+  def setUp(self):
+      self.v1obj = VersioningTestV1(
+          begin_in_both=12345,
+          old_string='aaa',
+          end_in_both=54321,
+          )
+
+      self.v2obj = VersioningTestV2(
+          begin_in_both=12345,
+          newint=1,
+          newbyte=2,
+          newshort=3,
+          newlong=4,
+          newdouble=5.0,
+          newstruct=Bonk(message="Hello!", type=123),
+          newlist=[7,8,9],
+          newset=[42,1,8],
+          newmap={1:2,2:3},
+          newstring="Hola!",
+          end_in_both=54321,
+          )
+
+  def _serialize(self, obj):
+      trans = TTransport.TMemoryBuffer()
+      prot = self.protocol_factory.getProtocol(trans)
+      obj.write(prot)
+      return trans.getvalue()
+
+  def _deserialize(self, objtype, data):
+      prot = self.protocol_factory.getProtocol(TTransport.TMemoryBuffer(data))
+      ret = objtype()
+      ret.read(prot)
+      return ret
+
+  def testForwards(self):
+      obj = self._deserialize(VersioningTestV2, self._serialize(self.v1obj))
+      self.assertEquals(obj.begin_in_both, self.v1obj.begin_in_both)
+      self.assertEquals(obj.end_in_both, self.v1obj.end_in_both)
+
+  def testBackwards(self):
+      obj = self._deserialize(VersioningTestV1, self._serialize(self.v2obj))
+      self.assertEquals(obj.begin_in_both, self.v2obj.begin_in_both)
+      self.assertEquals(obj.end_in_both, self.v2obj.end_in_both)
+
+
+class NormalBinaryTest(AbstractTest):
+  protocol_factory = TBinaryProtocol.TBinaryProtocolFactory()
+
+class AcceleratedBinaryTest(AbstractTest):
+  protocol_factory = TBinaryProtocol.TBinaryProtocolAcceleratedFactory()
+
+
+class AcceleratedFramedTest(unittest.TestCase):
+  def testSplit(self):
+    """Test FramedTransport and BinaryProtocolAccelerated
+
+    Tests that TBinaryProtocolAccelerated and TFramedTransport
+    play nicely together when a read spans a frame"""
+
+    protocol_factory = TBinaryProtocol.TBinaryProtocolAcceleratedFactory()
+    bigstring = "".join(chr(byte) for byte in range(ord("a"), ord("z")+1))
+
+    databuf = TTransport.TMemoryBuffer()
+    prot = protocol_factory.getProtocol(databuf)
+    prot.writeI32(42)
+    prot.writeString(bigstring)
+    prot.writeI16(24)
+    data = databuf.getvalue()
+    cutpoint = len(data)/2
+    parts = [ data[:cutpoint], data[cutpoint:] ]
+
+    framed_buffer = TTransport.TMemoryBuffer()
+    framed_writer = TTransport.TFramedTransport(framed_buffer)
+    for part in parts:
+      framed_writer.write(part)
+      framed_writer.flush()
+    self.assertEquals(len(framed_buffer.getvalue()), len(data) + 8)
+
+    # Recreate framed_buffer so we can read from it.
+    framed_buffer = TTransport.TMemoryBuffer(framed_buffer.getvalue())
+    framed_reader = TTransport.TFramedTransport(framed_buffer)
+    prot = protocol_factory.getProtocol(framed_reader)
+    self.assertEqual(prot.readI32(), 42)
+    self.assertEqual(prot.readString(), bigstring)
+    self.assertEqual(prot.readI16(), 24)
+
+
+
+def suite():
+  suite = unittest.TestSuite()
+  loader = unittest.TestLoader()
+
+  suite.addTest(loader.loadTestsFromTestCase(NormalBinaryTest))
+  suite.addTest(loader.loadTestsFromTestCase(AcceleratedBinaryTest))
+  suite.addTest(loader.loadTestsFromTestCase(AcceleratedFramedTest))
+  return suite
+
+if __name__ == "__main__":
+  unittest.main(defaultTest="suite", testRunner=unittest.TextTestRunner(verbosity=2))
diff --git a/test/py/TestClient.py b/test/py/TestClient.py
new file mode 100755
index 0000000..64e5e87
--- /dev/null
+++ b/test/py/TestClient.py
@@ -0,0 +1,156 @@
+#!/usr/bin/env python
+
+#
+# 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.
+#
+
+import sys, glob
+sys.path.insert(0, './gen-py')
+sys.path.insert(0, glob.glob('../../lib/py/build/lib.*')[0])
+
+from ThriftTest import ThriftTest
+from ThriftTest.ttypes import *
+from thrift.transport import TTransport
+from thrift.transport import TSocket
+from thrift.transport import THttpClient
+from thrift.protocol import TBinaryProtocol
+import unittest
+import time
+from optparse import OptionParser
+
+
+parser = OptionParser()
+parser.set_defaults(framed=False, http_path=None, verbose=1, host='localhost', port=9090)
+parser.add_option("--port", type="int", dest="port",
+    help="connect to server at port")
+parser.add_option("--host", type="string", dest="host",
+    help="connect to server")
+parser.add_option("--framed", action="store_true", dest="framed",
+    help="use framed transport")
+parser.add_option("--http", dest="http_path",
+    help="Use the HTTP transport with the specified path")
+parser.add_option('-v', '--verbose', action="store_const", 
+    dest="verbose", const=2,
+    help="verbose output")
+parser.add_option('-q', '--quiet', action="store_const", 
+    dest="verbose", const=0,
+    help="minimal output")
+
+options, args = parser.parse_args()
+
+class AbstractTest(unittest.TestCase):
+  def setUp(self):
+    if options.http_path:
+      self.transport = THttpClient.THttpClient(
+          options.host, options.port, options.http_path)
+    else:
+      socket = TSocket.TSocket(options.host, options.port)
+
+      # frame or buffer depending upon args
+      if options.framed:
+        self.transport = TTransport.TFramedTransport(socket)
+      else:
+        self.transport = TTransport.TBufferedTransport(socket)
+
+    self.transport.open()
+
+    protocol = self.protocol_factory.getProtocol(self.transport)
+    self.client = ThriftTest.Client(protocol)
+
+  def tearDown(self):
+    # Close!
+    self.transport.close()
+
+  def testVoid(self):
+    self.client.testVoid()
+
+  def testString(self):
+    self.assertEqual(self.client.testString('Python'), 'Python')
+
+  def testByte(self):
+    self.assertEqual(self.client.testByte(63), 63)
+
+  def testI32(self):
+    self.assertEqual(self.client.testI32(-1), -1)
+    self.assertEqual(self.client.testI32(0), 0)
+
+  def testI64(self):
+    self.assertEqual(self.client.testI64(-34359738368), -34359738368)
+
+  def testDouble(self):
+    self.assertEqual(self.client.testDouble(-5.235098235), -5.235098235)
+
+  def testStruct(self):
+    x = Xtruct()
+    x.string_thing = "Zero"
+    x.byte_thing = 1
+    x.i32_thing = -3
+    x.i64_thing = -5
+    y = self.client.testStruct(x)
+
+    self.assertEqual(y.string_thing, "Zero")
+    self.assertEqual(y.byte_thing, 1)
+    self.assertEqual(y.i32_thing, -3)
+    self.assertEqual(y.i64_thing, -5)
+
+  def testException(self):
+    self.client.testException('Safe')
+    try:
+      self.client.testException('Xception')
+      self.fail("should have gotten exception")
+    except Xception, x:
+      self.assertEqual(x.errorCode, 1001)
+      self.assertEqual(x.message, 'Xception')
+
+    try:
+      self.client.testException("throw_undeclared")
+      self.fail("should have thrown exception")
+    except Exception: # type is undefined
+      pass
+
+  def testOneway(self):
+    start = time.time()
+    self.client.testOneway(0.5)
+    end = time.time()
+    self.assertTrue(end - start < 0.2,
+                    "oneway sleep took %f sec" % (end - start))
+
+class NormalBinaryTest(AbstractTest):
+  protocol_factory = TBinaryProtocol.TBinaryProtocolFactory()
+
+class AcceleratedBinaryTest(AbstractTest):
+  protocol_factory = TBinaryProtocol.TBinaryProtocolAcceleratedFactory()
+
+def suite():
+  suite = unittest.TestSuite()
+  loader = unittest.TestLoader()
+
+  suite.addTest(loader.loadTestsFromTestCase(NormalBinaryTest))
+  suite.addTest(loader.loadTestsFromTestCase(AcceleratedBinaryTest))
+  return suite
+
+class OwnArgsTestProgram(unittest.TestProgram):
+    def parseArgs(self, argv):
+        if args:
+            self.testNames = args
+        else:
+            self.testNames = (self.defaultTest,)
+        self.createTests()
+
+if __name__ == "__main__":
+  OwnArgsTestProgram(defaultTest="suite", testRunner=unittest.TextTestRunner(verbosity=2))
diff --git a/test/py/TestEof.py b/test/py/TestEof.py
new file mode 100755
index 0000000..7d64289
--- /dev/null
+++ b/test/py/TestEof.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python
+
+#
+# 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.
+#
+
+import sys, glob
+sys.path.insert(0, './gen-py')
+sys.path.insert(0, glob.glob('../../lib/py/build/lib.*')[0])
+
+from ThriftTest import ThriftTest
+from ThriftTest.ttypes import *
+from thrift.transport import TTransport
+from thrift.transport import TSocket
+from thrift.protocol import TBinaryProtocol
+import unittest
+import time
+
+class TestEof(unittest.TestCase):
+
+  def setUp(self):
+    trans = TTransport.TMemoryBuffer()
+    prot = TBinaryProtocol.TBinaryProtocol(trans)
+
+    x = Xtruct()
+    x.string_thing = "Zero"
+    x.byte_thing = 0
+
+    x.write(prot)
+
+    x = Xtruct()
+    x.string_thing = "One"
+    x.byte_thing = 1
+
+    x.write(prot)
+
+    self.data = trans.getvalue()
+
+  def testTransportReadAll(self):
+    """Test that readAll on any type of transport throws an EOFError"""
+    trans = TTransport.TMemoryBuffer(self.data)
+    trans.readAll(1)
+
+    try:
+      trans.readAll(10000)
+    except EOFError:
+      return
+
+    self.fail("Should have gotten EOFError")
+
+  def eofTestHelper(self, pfactory):
+    trans = TTransport.TMemoryBuffer(self.data)
+    prot = pfactory.getProtocol(trans)
+
+    x = Xtruct()
+    x.read(prot)
+    self.assertEqual(x.string_thing, "Zero")
+    self.assertEqual(x.byte_thing, 0)
+
+    x = Xtruct()
+    x.read(prot)
+    self.assertEqual(x.string_thing, "One")
+    self.assertEqual(x.byte_thing, 1)
+
+    try:
+      x = Xtruct()
+      x.read(prot)
+    except EOFError:
+      return
+
+    self.fail("Should have gotten EOFError")
+
+  def eofTestHelperStress(self, pfactory):
+    """Teest the ability of TBinaryProtocol to deal with the removal of every byte in the file"""
+    # TODO: we should make sure this covers more of the code paths
+
+    for i in xrange(0, len(self.data) + 1):
+      trans = TTransport.TMemoryBuffer(self.data[0:i])
+      prot = pfactory.getProtocol(trans)
+      try:
+        x = Xtruct()
+        x.read(prot)
+        x.read(prot)
+        x.read(prot)
+      except EOFError:
+        continue
+      self.fail("Should have gotten an EOFError")
+
+  def testBinaryProtocolEof(self):
+    """Test that TBinaryProtocol throws an EOFError when it reaches the end of the stream"""
+    self.eofTestHelper(TBinaryProtocol.TBinaryProtocolFactory())
+    self.eofTestHelperStress(TBinaryProtocol.TBinaryProtocolFactory())
+
+  def testBinaryProtocolAcceleratedEof(self):
+    """Test that TBinaryProtocolAccelerated throws an EOFError when it reaches the end of the stream"""
+    self.eofTestHelper(TBinaryProtocol.TBinaryProtocolAcceleratedFactory())
+    self.eofTestHelperStress(TBinaryProtocol.TBinaryProtocolAcceleratedFactory())
+
+def suite():
+  suite = unittest.TestSuite()
+  loader = unittest.TestLoader()
+  suite.addTest(loader.loadTestsFromTestCase(TestEof))
+  return suite
+
+if __name__ == "__main__":
+  unittest.main(defaultTest="suite", testRunner=unittest.TextTestRunner(verbosity=2))
diff --git a/test/py/TestServer.py b/test/py/TestServer.py
new file mode 100755
index 0000000..3d379ea
--- /dev/null
+++ b/test/py/TestServer.py
@@ -0,0 +1,115 @@
+#!/usr/bin/env python
+
+#
+# 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.
+#
+
+import sys, glob, time
+sys.path.insert(0, './gen-py')
+sys.path.insert(0, glob.glob('../../lib/py/build/lib.*')[0])
+
+from ThriftTest import ThriftTest
+from ThriftTest.ttypes import *
+from thrift.transport import TTransport
+from thrift.transport import TSocket
+from thrift.protocol import TBinaryProtocol
+from thrift.server import TServer, TNonblockingServer, THttpServer
+
+class TestHandler:
+
+  def testVoid(self):
+    print 'testVoid()'
+
+  def testString(self, str):
+    print 'testString(%s)' % str
+    return str
+
+  def testByte(self, byte):
+    print 'testByte(%d)' % byte
+    return byte
+
+  def testI16(self, i16):
+    print 'testI16(%d)' % i16
+    return i16
+
+  def testI32(self, i32):
+    print 'testI32(%d)' % i32
+    return i32
+
+  def testI64(self, i64):
+    print 'testI64(%d)' % i64
+    return i64
+
+  def testDouble(self, dub):
+    print 'testDouble(%f)' % dub
+    return dub
+
+  def testStruct(self, thing):
+    print 'testStruct({%s, %d, %d, %d})' % (thing.string_thing, thing.byte_thing, thing.i32_thing, thing.i64_thing)
+    return thing
+
+  def testException(self, str):
+    print 'testException(%s)' % str
+    if str == 'Xception':
+      x = Xception()
+      x.errorCode = 1001
+      x.message = str
+      raise x
+    elif str == "throw_undeclared":
+      raise ValueError("foo")
+
+  def testOneway(self, seconds):
+    print 'testOneway(%d) => sleeping...' % seconds
+    time.sleep(seconds)
+    print 'done sleeping'
+
+  def testNest(self, thing):
+    return thing
+
+  def testMap(self, thing):
+    return thing
+
+  def testSet(self, thing):
+    return thing
+
+  def testList(self, thing):
+    return thing
+
+  def testEnum(self, thing):
+    return thing
+
+  def testTypedef(self, thing):
+    return thing
+
+pfactory = TBinaryProtocol.TBinaryProtocolFactory()
+handler = TestHandler()
+processor = ThriftTest.Processor(handler)
+
+if sys.argv[1] == "THttpServer":
+  server = THttpServer.THttpServer(processor, ('', 9090), pfactory)
+else:
+  transport = TSocket.TServerSocket(9090)
+  tfactory = TTransport.TBufferedTransportFactory()
+
+  if sys.argv[1] == "TNonblockingServer":
+    server = TNonblockingServer.TNonblockingServer(processor, transport)
+  else:
+    ServerClass = getattr(TServer, sys.argv[1])
+    server = ServerClass(processor, transport, tfactory, pfactory)
+
+server.serve()
diff --git a/test/py/TestSocket.py b/test/py/TestSocket.py
new file mode 100755
index 0000000..2f7353f
--- /dev/null
+++ b/test/py/TestSocket.py
@@ -0,0 +1,84 @@
+#!/usr/bin/env python
+
+#
+# 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.
+#
+
+import sys, glob
+sys.path.insert(0, './gen-py')
+sys.path.insert(0, glob.glob('../../lib/py/build/lib.*')[0])
+
+from ThriftTest import ThriftTest
+from ThriftTest.ttypes import *
+from thrift.transport import TTransport
+from thrift.transport import TSocket
+from thrift.protocol import TBinaryProtocol
+import unittest
+import time
+import socket
+import random
+from optparse import OptionParser
+
+class TimeoutTest(unittest.TestCase):
+    def setUp(self):
+        for i in xrange(50):
+            try:
+                # find a port we can use
+                self.listen_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+                self.port = random.randint(10000, 30000)
+                self.listen_sock.bind(('localhost', self.port))
+                self.listen_sock.listen(5)
+                break
+            except:
+                if i == 49:
+                    raise
+
+    def testConnectTimeout(self):
+        starttime = time.time()
+
+        try:
+            leaky = []
+            for i in xrange(100):
+                socket = TSocket.TSocket('localhost', self.port)
+                socket.setTimeout(10)
+                socket.open()
+                leaky.append(socket)
+        except:
+            self.assert_(time.time() - starttime < 5.0)
+
+    def testWriteTimeout(self):
+        starttime = time.time()
+
+        try:
+            socket = TSocket.TSocket('localhost', self.port)
+            socket.setTimeout(10)
+            socket.open()
+            lsock = self.listen_sock.accept()
+            while True:
+                socket.write("hi" * 100)
+
+        except:
+            self.assert_(time.time() - starttime < 5.0)
+
+suite = unittest.TestSuite()
+loader = unittest.TestLoader()
+
+suite.addTest(loader.loadTestsFromTestCase(TimeoutTest))
+
+testRunner = unittest.TextTestRunner(verbosity=2)
+testRunner.run(suite)
diff --git a/test/py/TestSyntax.py b/test/py/TestSyntax.py
new file mode 100755
index 0000000..df67d48
--- /dev/null
+++ b/test/py/TestSyntax.py
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+
+#
+# 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.
+#
+
+import sys, glob
+sys.path.insert(0, './gen-py')
+sys.path.insert(0, glob.glob('../../lib/py/build/lib.*')[0])
+
+# Just import these generated files to make sure they are syntactically valid
+from DebugProtoTest import EmptyService
+from DebugProtoTest import Inherited
diff --git a/test/py/explicit_module/runtest.sh b/test/py/explicit_module/runtest.sh
new file mode 100755
index 0000000..2e5a4f1
--- /dev/null
+++ b/test/py/explicit_module/runtest.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+
+#
+# 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.
+#
+
+rm -rf gen-py
+../../../compiler/cpp/thrift --gen py test1.thrift || exit 1
+../../../compiler/cpp/thrift --gen py test2.thrift || exit 1
+PYTHONPATH=./gen-py python -c 'import foo.bar.baz' || exit 1
+PYTHONPATH=./gen-py python -c 'import test2' || exit 1
+PYTHONPATH=./gen-py python -c 'import test1' &>/dev/null && exit 1  # Should fail.
+cp -r gen-py simple
+../../../compiler/cpp/thrift -r --gen py test2.thrift || exit 1
+PYTHONPATH=./gen-py python -c 'import test2' || exit 1
+diff -ur simple gen-py > thediffs
+file thediffs | grep -s -q empty || exit 1
+rm -rf simple thediffs
+echo 'All tests pass!'
diff --git a/test/py/explicit_module/test1.thrift b/test/py/explicit_module/test1.thrift
new file mode 100644
index 0000000..ec600d7
--- /dev/null
+++ b/test/py/explicit_module/test1.thrift
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+namespace py foo.bar.baz
+
+struct astruct {
+  1: i32 how_unoriginal;
+}
diff --git a/test/py/explicit_module/test2.thrift b/test/py/explicit_module/test2.thrift
new file mode 100644
index 0000000..68f9da4
--- /dev/null
+++ b/test/py/explicit_module/test2.thrift
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+include "test1.thrift"
+
+struct another {
+  1: test1.astruct something;
+}
diff --git a/test/rb/Makefile.am b/test/rb/Makefile.am
new file mode 100644
index 0000000..a6f431c
--- /dev/null
+++ b/test/rb/Makefile.am
@@ -0,0 +1,28 @@
+#
+# 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.
+#
+
+THRIFT = $(top_srcdir)/compiler/cpp/thrift
+
+stubs: ../ThriftTest.thrift ../SmallTest.thrift
+	$(THRIFT) --gen rb ../ThriftTest.thrift
+	$(THRIFT) --gen rb ../SmallTest.thrift
+
+check: stubs
+	$(RUBY) test_suite.rb
+
diff --git a/test/rb/benchmarks/protocol_benchmark.rb b/test/rb/benchmarks/protocol_benchmark.rb
new file mode 100644
index 0000000..05a8ee5
--- /dev/null
+++ b/test/rb/benchmarks/protocol_benchmark.rb
@@ -0,0 +1,174 @@
+#
+# 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.
+#
+
+$LOAD_PATH.unshift File.join(File.dirname(__FILE__), *%w[.. .. .. lib rb lib])
+$LOAD_PATH.unshift File.join(File.dirname(__FILE__), *%w[.. .. .. lib rb ext])
+
+require 'thrift'
+
+require 'benchmark'
+require 'rubygems'
+require 'set'
+require 'pp'
+
+# require 'ruby-debug'
+# require 'ruby-prof'
+
+require File.join(File.dirname(__FILE__), '../fixtures/structs')
+
+transport1 = Thrift::MemoryBuffer.new
+ruby_binary_protocol = Thrift::BinaryProtocol.new(transport1)
+
+transport2 = Thrift::MemoryBuffer.new
+c_fast_binary_protocol = Thrift::BinaryProtocolAccelerated.new(transport2)
+
+
+ooe = Fixtures::Structs::OneOfEach.new
+ooe.im_true   = true
+ooe.im_false  = false
+ooe.a_bite    = -42
+ooe.integer16 = 27000
+ooe.integer32 = 1<<24
+ooe.integer64 = 6000 * 1000 * 1000
+ooe.double_precision = Math::PI
+ooe.some_characters  = "Debug THIS!"
+ooe.zomg_unicode     = "\xd7\n\a\t"
+
+n1 = Fixtures::Structs::Nested1.new
+n1.a_list = []
+n1.a_list << ooe << ooe << ooe << ooe
+n1.i32_map = {}
+n1.i32_map[1234] = ooe
+n1.i32_map[46345] = ooe
+n1.i32_map[-34264] = ooe
+n1.i64_map = {}
+n1.i64_map[43534986783945] = ooe
+n1.i64_map[-32434639875122] = ooe
+n1.dbl_map = {}
+n1.dbl_map[324.65469834] = ooe
+n1.dbl_map[-9458672340.4986798345112] = ooe
+n1.str_map = {}
+n1.str_map['sdoperuix'] = ooe
+n1.str_map['pwoerxclmn'] = ooe
+
+n2 = Fixtures::Structs::Nested2.new
+n2.a_list = []
+n2.a_list << n1 << n1 << n1 << n1 << n1
+n2.i32_map = {}
+n2.i32_map[398345] = n1
+n2.i32_map[-2345] = n1
+n2.i32_map[12312] = n1
+n2.i64_map = {}
+n2.i64_map[2349843765934] = n1
+n2.i64_map[-123234985495] = n1
+n2.i64_map[0] = n1
+n2.dbl_map = {}
+n2.dbl_map[23345345.38927834] = n1
+n2.dbl_map[-1232349.5489345] = n1
+n2.dbl_map[-234984574.23498725] = n1
+n2.str_map = {}
+n2.str_map[''] = n1
+n2.str_map['sdflkertpioux'] = n1
+n2.str_map['sdfwepwdcjpoi'] = n1
+
+n3 = Fixtures::Structs::Nested3.new
+n3.a_list = []
+n3.a_list << n2 << n2 << n2 << n2 << n2
+n3.i32_map = {}
+n3.i32_map[398345] = n2
+n3.i32_map[-2345] = n2
+n3.i32_map[12312] = n2
+n3.i64_map = {}
+n3.i64_map[2349843765934] = n2
+n3.i64_map[-123234985495] = n2
+n3.i64_map[0] = n2
+n3.dbl_map = {}
+n3.dbl_map[23345345.38927834] = n2
+n3.dbl_map[-1232349.5489345] = n2
+n3.dbl_map[-234984574.23498725] = n2
+n3.str_map = {}
+n3.str_map[''] = n2
+n3.str_map['sdflkertpioux'] = n2
+n3.str_map['sdfwepwdcjpoi'] = n2
+
+n4 = Fixtures::Structs::Nested4.new
+n4.a_list = []
+n4.a_list << n3
+n4.i32_map = {}
+n4.i32_map[-2345] = n3
+n4.i64_map = {}
+n4.i64_map[2349843765934] = n3
+n4.dbl_map = {}
+n4.dbl_map[-1232349.5489345] = n3
+n4.str_map = {}
+n4.str_map[''] = n3
+
+
+# prof = RubyProf.profile do
+#   n4.write(c_fast_binary_protocol)
+#   Fixtures::Structs::Nested4.new.read(c_fast_binary_protocol)
+# end
+# 
+# printer = RubyProf::GraphHtmlPrinter.new(prof)
+# printer.print(STDOUT, :min_percent=>0)
+
+Benchmark.bmbm do |x|
+  x.report("ruby write large (1MB) structure once") do
+    n4.write(ruby_binary_protocol)
+  end
+  
+  x.report("ruby read large (1MB) structure once") do
+    Fixtures::Structs::Nested4.new.read(ruby_binary_protocol)
+  end
+  
+  x.report("c write large (1MB) structure once") do    
+    n4.write(c_fast_binary_protocol)
+  end
+  
+  x.report("c read large (1MB) structure once") do
+    Fixtures::Structs::Nested4.new.read(c_fast_binary_protocol)
+  end
+  
+  
+  
+  x.report("ruby write 10_000 small structures") do
+    10_000.times do
+      ooe.write(ruby_binary_protocol)
+    end
+  end
+  
+  x.report("ruby read 10_000 small structures") do
+    10_000.times do
+      Fixtures::Structs::OneOfEach.new.read(ruby_binary_protocol)
+    end
+  end
+  
+  x.report("c write 10_000 small structures") do
+    10_000.times do
+      ooe.write(c_fast_binary_protocol)
+    end
+  end
+  
+  x.report("c read 10_000 small structures") do
+    10_000.times do
+      Fixtures::Structs::OneOfEach.new.read(c_fast_binary_protocol)
+    end
+  end
+  
+end
diff --git a/test/rb/core/test_backwards_compatability.rb b/test/rb/core/test_backwards_compatability.rb
new file mode 100644
index 0000000..0577515
--- /dev/null
+++ b/test/rb/core/test_backwards_compatability.rb
@@ -0,0 +1,30 @@
+#
+# 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.
+#
+
+require File.join(File.dirname(__FILE__), '../test_helper')
+
+require 'thrift'
+
+class TestThriftException < Test::Unit::TestCase
+  def test_has_accessible_message
+    msg = "hi there thrift"
+    assert_equal msg, Thrift::Exception.new(msg).message
+  end
+end
+
diff --git a/test/rb/core/test_exceptions.rb b/test/rb/core/test_exceptions.rb
new file mode 100644
index 0000000..f41587a
--- /dev/null
+++ b/test/rb/core/test_exceptions.rb
@@ -0,0 +1,30 @@
+#
+# 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.
+#
+
+require File.join(File.dirname(__FILE__), '../test_helper')
+
+require 'thrift'
+
+class TestException < Test::Unit::TestCase
+  def test_has_accessible_message
+    msg = "hi there thrift"
+    assert_equal msg, Thrift::Exception.new(msg).message
+  end
+end
+
diff --git a/test/rb/core/transport/test_transport.rb b/test/rb/core/transport/test_transport.rb
new file mode 100644
index 0000000..52755c1
--- /dev/null
+++ b/test/rb/core/transport/test_transport.rb
@@ -0,0 +1,70 @@
+#
+# 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.
+#
+
+require File.join(File.dirname(__FILE__), '../../test_helper')
+
+require 'thrift'
+
+class DummyTransport < Thrift::BaseTransport
+  def initialize(data)
+    @data = data
+  end
+  
+  def read(size)
+    @data.slice!(0, size)
+  end
+end
+
+# TTransport is basically an abstract class, but isn't raising NotImplementedError
+class TestThriftTransport < Test::Unit::TestCase
+  def setup
+    @trans = Thrift::BaseTransport.new
+  end
+  
+  def test_open?
+    assert_nil @trans.open?
+  end
+  
+  def test_open
+    assert_nil @trans.open
+  end
+  
+  def test_close
+    assert_nil @trans.close
+  end
+  
+  # TODO:
+  # This doesn't necessarily test he right thing.
+  # It _looks_ like read isn't guarenteed to return the length
+  # you ask for and read_all is. This means our test needs to check
+  # for blocking. -- Kevin Clark 3/27/08
+  def test_read_all
+    # Implements read
+    t = DummyTransport.new("hello")
+    assert_equal "hello", t.read_all(5)
+  end
+  
+  def test_write
+    assert_nil @trans.write(5) # arbitrary value
+  end
+  
+  def test_flush
+    assert_nil @trans.flush
+  end
+end
diff --git a/test/rb/fixtures/structs.rb b/test/rb/fixtures/structs.rb
new file mode 100644
index 0000000..ebbeb0a
--- /dev/null
+++ b/test/rb/fixtures/structs.rb
@@ -0,0 +1,298 @@
+#
+# 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.
+#
+
+require 'thrift'
+
+module Fixtures
+  module Structs
+    class OneBool
+      include Thrift::Struct
+      attr_accessor :bool
+      FIELDS = {
+        1 => {:type => Thrift::Types::BOOL, :name => 'bool'}
+      }
+
+      def validate
+      end
+    end
+    
+    class OneByte
+      include Thrift::Struct
+      attr_accessor :byte
+      FIELDS = {
+        1 => {:type => Thrift::Types::BYTE, :name => 'byte'}
+      }
+
+      def validate
+      end
+    end
+    
+    class OneI16
+      include Thrift::Struct
+      attr_accessor :i16
+      FIELDS = {
+        1 => {:type => Thrift::Types::I16, :name => 'i16'}
+      }
+
+      def validate
+      end
+    end
+    
+    class OneI32
+      include Thrift::Struct
+      attr_accessor :i32
+      FIELDS = {
+        1 => {:type => Thrift::Types::I32, :name => 'i32'}
+      }
+
+      def validate
+      end
+    end
+    
+    class OneI64
+      include Thrift::Struct
+      attr_accessor :i64
+      FIELDS = {
+        1 => {:type => Thrift::Types::I64, :name => 'i64'}
+      }
+
+      def validate
+      end
+    end
+    
+    class OneDouble
+      include Thrift::Struct
+      attr_accessor :double
+      FIELDS = {
+        1 => {:type => Thrift::Types::DOUBLE, :name => 'double'}
+      }
+
+      def validate
+      end
+    end
+    
+    class OneString
+      include Thrift::Struct
+      attr_accessor :string
+      FIELDS = {
+        1 => {:type => Thrift::Types::STRING, :name => 'string'}
+      }
+
+      def validate
+      end
+    end
+    
+    class OneMap
+      include Thrift::Struct
+      attr_accessor :map
+      FIELDS = {
+        1 => {:type => Thrift::Types::MAP, :name => 'map', :key => {:type => Thrift::Types::STRING}, :value => {:type => Thrift::Types::STRING}}
+      }
+
+      def validate
+      end
+    end
+    
+    class NestedMap
+      include Thrift::Struct
+      attr_accessor :map
+      FIELDS = {
+        0 => {:type => Thrift::Types::MAP, :name => 'map', :key => {:type => Thrift::Types::I32}, :value => {:type => Thrift::Types::MAP, :key => {:type => Thrift::Types::I32}, :value => {:type => Thrift::Types::I32}}}
+      }
+
+      def validate
+      end
+    end
+    
+    class OneList
+      include Thrift::Struct
+      attr_accessor :list
+      FIELDS = {
+        1 => {:type => Thrift::Types::LIST, :name => 'list', :element => {:type => Thrift::Types::STRING}}
+      }
+
+      def validate
+      end
+    end
+    
+    class NestedList
+      include Thrift::Struct
+      attr_accessor :list
+      FIELDS = {
+        0 => {:type => Thrift::Types::LIST, :name => 'list', :element => {:type => Thrift::Types::LIST, :element => { :type => Thrift::Types::I32 } } }
+      }
+
+      def validate
+      end
+    end
+    
+    class OneSet
+      include Thrift::Struct
+      attr_accessor :set
+      FIELDS = {
+        1 => {:type => Thrift::Types::SET, :name => 'set', :element => {:type => Thrift::Types::STRING}}
+      }
+
+      def validate
+      end
+    end
+    
+    class NestedSet
+      include Thrift::Struct
+      attr_accessor :set
+      FIELDS = {
+        1 => {:type => Thrift::Types::SET, :name => 'set', :element => {:type => Thrift::Types::SET, :element => { :type => Thrift::Types::STRING } }}
+      }
+
+      def validate
+      end
+    end
+    
+    # struct OneOfEach {
+    #   1: bool im_true,
+    #   2: bool im_false,
+    #   3: byte a_bite,
+    #   4: i16 integer16,
+    #   5: i32 integer32,
+    #   6: i64 integer64,
+    #   7: double double_precision,
+    #   8: string some_characters,
+    #   9: string zomg_unicode,
+    #   10: bool what_who,
+    #   11: binary base64,
+    # }
+    class OneOfEach
+      include Thrift::Struct
+      attr_accessor :im_true, :im_false, :a_bite, :integer16, :integer32, :integer64, :double_precision, :some_characters, :zomg_unicode, :what_who, :base64
+      FIELDS = {
+        1 => {:type => Thrift::Types::BOOL, :name => 'im_true'},
+        2 => {:type => Thrift::Types::BOOL, :name => 'im_false'},
+        3 => {:type => Thrift::Types::BYTE, :name => 'a_bite'},
+        4 => {:type => Thrift::Types::I16, :name => 'integer16'},
+        5 => {:type => Thrift::Types::I32, :name => 'integer32'},
+        6 => {:type => Thrift::Types::I64, :name => 'integer64'},
+        7 => {:type => Thrift::Types::DOUBLE, :name => 'double_precision'},
+        8 => {:type => Thrift::Types::STRING, :name => 'some_characters'},
+        9 => {:type => Thrift::Types::STRING, :name => 'zomg_unicode'},
+        10 => {:type => Thrift::Types::BOOL, :name => 'what_who'},
+        11 => {:type => Thrift::Types::STRING, :name => 'base64'}
+      }
+
+      # Added for assert_equal
+      def ==(other)
+        [:im_true, :im_false, :a_bite, :integer16, :integer32, :integer64, :double_precision, :some_characters, :zomg_unicode, :what_who, :base64].each do |f|
+          var = "@#{f}"
+          return false if instance_variable_get(var) != other.instance_variable_get(var)
+        end
+        true
+      end
+
+      def validate
+      end
+    end
+
+    # struct Nested1 {
+    #   1: list<OneOfEach> a_list
+    #   2: map<i32, OneOfEach> i32_map
+    #   3: map<i64, OneOfEach> i64_map
+    #   4: map<double, OneOfEach> dbl_map
+    #   5: map<string, OneOfEach> str_map
+    # }
+    class Nested1
+      include Thrift::Struct
+      attr_accessor :a_list, :i32_map, :i64_map, :dbl_map, :str_map
+      FIELDS = {
+        1 => {:type => Thrift::Types::LIST, :name => 'a_list', :element => {:type => Thrift::Types::STRUCT, :class => OneOfEach}},
+        2 => {:type => Thrift::Types::MAP, :name => 'i32_map', :key => {:type => Thrift::Types::I32}, :value => {:type => Thrift::Types::STRUCT, :class => OneOfEach}},
+        3 => {:type => Thrift::Types::MAP, :name => 'i64_map', :key => {:type => Thrift::Types::I64}, :value => {:type => Thrift::Types::STRUCT, :class => OneOfEach}},
+        4 => {:type => Thrift::Types::MAP, :name => 'dbl_map', :key => {:type => Thrift::Types::DOUBLE}, :value => {:type => Thrift::Types::STRUCT, :class => OneOfEach}},
+        5 => {:type => Thrift::Types::MAP, :name => 'str_map', :key => {:type => Thrift::Types::STRING}, :value => {:type => Thrift::Types::STRUCT, :class => OneOfEach}}
+      }
+
+      def validate
+      end
+    end
+
+    # struct Nested2 {
+    #   1: list<Nested1> a_list
+    #   2: map<i32, Nested1> i32_map
+    #   3: map<i64, Nested1> i64_map
+    #   4: map<double, Nested1> dbl_map
+    #   5: map<string, Nested1> str_map
+    # }
+    class Nested2
+      include Thrift::Struct
+      attr_accessor :a_list, :i32_map, :i64_map, :dbl_map, :str_map
+      FIELDS = {
+        1 => {:type => Thrift::Types::LIST, :name => 'a_list', :element => {:type => Thrift::Types::STRUCT, :class => Nested1}},
+        2 => {:type => Thrift::Types::MAP, :name => 'i32_map', :key => {:type => Thrift::Types::I32}, :value => {:type => Thrift::Types::STRUCT, :class => Nested1}},
+        3 => {:type => Thrift::Types::MAP, :name => 'i64_map', :key => {:type => Thrift::Types::I64}, :value => {:type => Thrift::Types::STRUCT, :class => Nested1}},
+        4 => {:type => Thrift::Types::MAP, :name => 'dbl_map', :key => {:type => Thrift::Types::DOUBLE}, :value => {:type => Thrift::Types::STRUCT, :class => Nested1}},
+        5 => {:type => Thrift::Types::MAP, :name => 'str_map', :key => {:type => Thrift::Types::STRING}, :value => {:type => Thrift::Types::STRUCT, :class => Nested1}}
+      }
+
+      def validate
+      end
+    end
+
+    # struct Nested3 {
+    #   1: list<Nested2> a_list
+    #   2: map<i32, Nested2> i32_map
+    #   3: map<i64, Nested2> i64_map
+    #   4: map<double, Nested2> dbl_map
+    #   5: map<string, Nested2> str_map
+    # }
+    class Nested3
+      include Thrift::Struct
+      attr_accessor :a_list, :i32_map, :i64_map, :dbl_map, :str_map
+      FIELDS = {
+        1 => {:type => Thrift::Types::LIST, :name => 'a_list', :element => {:type => Thrift::Types::STRUCT, :class => Nested2}},
+        2 => {:type => Thrift::Types::MAP, :name => 'i32_map', :key => {:type => Thrift::Types::I32}, :value => {:type => Thrift::Types::STRUCT, :class => Nested2}},
+        3 => {:type => Thrift::Types::MAP, :name => 'i64_map', :key => {:type => Thrift::Types::I64}, :value => {:type => Thrift::Types::STRUCT, :class => Nested2}},
+        4 => {:type => Thrift::Types::MAP, :name => 'dbl_map', :key => {:type => Thrift::Types::DOUBLE}, :value => {:type => Thrift::Types::STRUCT, :class => Nested2}},
+        5 => {:type => Thrift::Types::MAP, :name => 'str_map', :key => {:type => Thrift::Types::STRING}, :value => {:type => Thrift::Types::STRUCT, :class => Nested2}}
+      }
+
+      def validate
+      end
+    end
+
+    # struct Nested4 {
+    #   1: list<Nested3> a_list
+    #   2: map<i32, Nested3> i32_map
+    #   3: map<i64, Nested3> i64_map
+    #   4: map<double, Nested3> dbl_map
+    #   5: map<string, Nested3> str_map
+    # }
+    class Nested4
+      include Thrift::Struct
+      attr_accessor :a_list, :i32_map, :i64_map, :dbl_map, :str_map
+      FIELDS = {
+        1 => {:type => Thrift::Types::LIST, :name => 'a_list', :element => {:type => Thrift::Types::STRUCT, :class => Nested3}},
+        2 => {:type => Thrift::Types::MAP, :name => 'i32_map', :key => {:type => Thrift::Types::I32}, :value => {:type => Thrift::Types::STRUCT, :class => Nested3}},
+        3 => {:type => Thrift::Types::MAP, :name => 'i64_map', :key => {:type => Thrift::Types::I64}, :value => {:type => Thrift::Types::STRUCT, :class => Nested3}},
+        4 => {:type => Thrift::Types::MAP, :name => 'dbl_map', :key => {:type => Thrift::Types::DOUBLE}, :value => {:type => Thrift::Types::STRUCT, :class => Nested3}},
+        5 => {:type => Thrift::Types::MAP, :name => 'str_map', :key => {:type => Thrift::Types::STRING}, :value => {:type => Thrift::Types::STRUCT, :class => Nested3}}
+      }
+
+      def validate
+      end
+    end
+  end
+end
diff --git a/test/rb/generation/test_enum.rb b/test/rb/generation/test_enum.rb
new file mode 100644
index 0000000..7d3f08b
--- /dev/null
+++ b/test/rb/generation/test_enum.rb
@@ -0,0 +1,28 @@
+#
+# 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.
+#
+
+require File.join(File.dirname(__FILE__), '../test_helper')
+require 'thrift_test'
+
+class TestEnumGeneration < Test::Unit::TestCase
+  include Thrift::Test
+  def test_enum_valid_values
+    assert_equal(Numberz::VALID_VALUES, Set.new([Numberz::ONE, Numberz::TWO, Numberz::THREE, Numberz::FIVE, Numberz::SIX, Numberz::EIGHT]))
+  end
+end
\ No newline at end of file
diff --git a/test/rb/generation/test_struct.rb b/test/rb/generation/test_struct.rb
new file mode 100644
index 0000000..3bd4fc9
--- /dev/null
+++ b/test/rb/generation/test_struct.rb
@@ -0,0 +1,48 @@
+#
+# 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.
+#
+
+require File.join(File.dirname(__FILE__), '../test_helper')
+require 'small_service'
+
+class TestStructGeneration < Test::Unit::TestCase
+
+  def test_default_values
+    hello = TestNamespace::Hello.new
+
+    assert_kind_of(TestNamespace::Hello, hello)
+    assert_nil(hello.complexer)
+
+    assert_equal(hello.simple, 53)
+    assert_equal(hello.words, 'words')
+
+    assert_kind_of(TestNamespace::Goodbyez, hello.thinz)
+    assert_equal(hello.thinz.val, 36632)
+
+    assert_kind_of(Hash, hello.complex)
+    assert_equal(hello.complex, { 6243 => 632, 2355 => 532, 23 => 532})
+    
+    bool_passer = TestNamespace::BoolPasser.new(:value => false)
+    assert_equal false, bool_passer.value
+  end
+
+  def test_goodbyez
+    assert_equal(TestNamespace::Goodbyez.new.val, 325)
+  end
+
+end
diff --git a/test/rb/integration/accelerated_buffered_client.rb b/test/rb/integration/accelerated_buffered_client.rb
new file mode 100644
index 0000000..7cec1df
--- /dev/null
+++ b/test/rb/integration/accelerated_buffered_client.rb
@@ -0,0 +1,163 @@
+#
+# 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.
+#
+
+require File.join(File.dirname(__FILE__), '../test_helper')
+
+require 'thrift'
+require 'ThriftTest'
+
+class AcceleratedBufferedClientTest < Test::Unit::TestCase
+  def setup
+    unless @socket
+      @socket   = Thrift::Socket.new('localhost', 9090)
+      @protocol = Thrift::BinaryProtocolAccelerated.new(Thrift::BufferedTransport.new(@socket))
+      @client   = Thrift::Test::ThriftTest::Client.new(@protocol)
+      @socket.open
+    end
+  end
+  
+  def test_string
+    assert_equal(@client.testString('string'), 'string')
+  end
+
+  def test_byte
+    val = 8
+    assert_equal(@client.testByte(val), val)
+    assert_equal(@client.testByte(-val), -val)
+  end
+
+  def test_i32
+    val = 32
+    assert_equal(@client.testI32(val), val)
+    assert_equal(@client.testI32(-val), -val)
+  end
+
+  def test_i64
+    val = 64
+    assert_equal(@client.testI64(val), val)
+    assert_equal(@client.testI64(-val), -val)
+  end
+
+  def test_double
+    val = 3.14
+    assert_equal(@client.testDouble(val), val)
+    assert_equal(@client.testDouble(-val), -val)
+    assert_kind_of(Float, @client.testDouble(val))
+  end
+
+  def test_map
+    val = {1 => 1, 2 => 2, 3 => 3}
+    assert_equal(@client.testMap(val), val)
+    assert_kind_of(Hash, @client.testMap(val))
+  end
+
+  def test_list
+    val = [1,2,3,4,5]
+    assert_equal(@client.testList(val), val)
+    assert_kind_of(Array, @client.testList(val))
+  end
+
+  def test_enum
+    val = Thrift::Test::Numberz::SIX
+    ret = @client.testEnum(val)
+
+    assert_equal(ret, 6)
+    assert_kind_of(Fixnum, ret)
+  end
+
+  def test_typedef
+    #UserId  testTypedef(1: UserId thing),
+    true
+  end
+
+  def test_set
+    val = Set.new([1,2,3])
+    assert_equal(@client.testSet(val), val)
+    assert_kind_of(Set, @client.testSet(val))
+  end
+
+  def get_struct
+    Thrift::Test::Xtruct.new({'string_thing' => 'hi!', 'i32_thing' => 4 })
+  end
+
+  def test_struct
+    ret = @client.testStruct(get_struct)
+
+    assert_nil(ret.byte_thing, nil)
+    assert_nil(ret.i64_thing, nil)
+    assert_equal(ret.string_thing, 'hi!')
+    assert_equal(ret.i32_thing, 4)
+    assert_kind_of(Thrift::Test::Xtruct, ret)
+  end
+
+  def test_nest
+    struct2 = Thrift::Test::Xtruct2.new({'struct_thing' => get_struct, 'i32_thing' => 10})
+
+    ret = @client.testNest(struct2)
+
+    assert_nil(ret.struct_thing.byte_thing, nil)
+    assert_nil(ret.struct_thing.i64_thing, nil)
+    assert_equal(ret.struct_thing.string_thing, 'hi!')
+    assert_equal(ret.struct_thing.i32_thing, 4)
+    assert_equal(ret.i32_thing, 10)
+
+    assert_kind_of(Thrift::Test::Xtruct, ret.struct_thing)
+    assert_kind_of(Thrift::Test::Xtruct2, ret)
+  end
+
+  def test_insane
+    insane = Thrift::Test::Insanity.new({
+      'userMap' => { Thrift::Test::Numberz::ONE => 44 },
+      'xtructs' => [get_struct,
+        Thrift::Test::Xtruct.new({
+          'string_thing' => 'hi again',
+          'i32_thing' => 12
+        })
+      ]
+    })
+
+    ret = @client.testInsanity(insane)
+
+    assert_not_nil(ret[44])
+    assert_not_nil(ret[44][1])
+
+    struct = ret[44][1]
+
+    assert_equal(struct.userMap[Thrift::Test::Numberz::ONE], 44)
+    assert_equal(struct.xtructs[1].string_thing, 'hi again')
+    assert_equal(struct.xtructs[1].i32_thing, 12)
+
+    assert_kind_of(Hash, struct.userMap)
+    assert_kind_of(Array, struct.xtructs)
+    assert_kind_of(Thrift::Test::Insanity, struct)
+  end
+
+  def test_map_map
+    ret = @client.testMapMap(4)
+    assert_kind_of(Hash, ret)
+    assert_equal(ret, { 4 => { 4 => 4}})
+  end
+
+  def test_exception
+    assert_raise Thrift::Test::Xception do
+      @client.testException('foo')
+    end
+  end
+end
+
diff --git a/test/rb/integration/accelerated_buffered_server.rb b/test/rb/integration/accelerated_buffered_server.rb
new file mode 100644
index 0000000..1ca66e5
--- /dev/null
+++ b/test/rb/integration/accelerated_buffered_server.rb
@@ -0,0 +1,65 @@
+#
+# 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.
+#
+
+$:.push File.dirname(__FILE__) + '/../gen-rb'
+$:.push File.join(File.dirname(__FILE__), '../../../lib/rb/lib')
+$:.push File.join(File.dirname(__FILE__), '../../../lib/rb/ext')
+
+require 'thrift'
+require 'ThriftTest'
+
+class SimpleHandler
+  [:testString, :testByte, :testI32, :testI64, :testDouble,
+   :testStruct, :testMap, :testSet, :testList, :testNest,
+   :testEnum, :testTypedef].each do |meth|
+
+    define_method(meth) do |thing|
+      thing
+    end
+
+  end
+
+  def testInsanity(thing)
+    num, uid = thing.userMap.find { true }
+    return {uid => {num => thing}}
+  end
+
+  def testMapMap(thing)
+    return {thing => {thing => thing}}
+  end
+
+  def testEnum(thing)
+    return thing
+  end
+
+  def testTypedef(thing)
+    return thing
+  end
+
+  def testException(thing)
+    raise Thrift::Test::Xception, :message => 'error'
+  end
+end
+
+@handler   = SimpleHandler.new
+@processor = Thrift::Test::ThriftTest::Processor.new(@handler)
+@transport = Thrift::ServerSocket.new(9090)
+@server    = Thrift::ThreadedServer.new(@processor, @transport, Thrift::BufferedTransportFactory.new, Thrift::BinaryProtocolAcceleratedFactory.new)
+
+@server.serve
diff --git a/test/rb/integration/buffered_client.rb b/test/rb/integration/buffered_client.rb
new file mode 100644
index 0000000..1a925cc
--- /dev/null
+++ b/test/rb/integration/buffered_client.rb
@@ -0,0 +1,163 @@
+#
+# 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.
+#
+
+require File.join(File.dirname(__FILE__), '../test_helper')
+
+require 'thrift'
+require 'ThriftTest'
+
+class BufferedClientTest < Test::Unit::TestCase
+  def setup
+    unless @socket
+      @socket   = Thrift::Socket.new('localhost', 9090)
+      @protocol = Thrift::BinaryProtocol.new(Thrift::BufferedTransport.new(@socket))
+      @client   = Thrift::Test::ThriftTest::Client.new(@protocol)
+      @socket.open
+    end
+  end
+  
+  def test_string
+    assert_equal(@client.testString('string'), 'string')
+  end
+
+  def test_byte
+    val = 8
+    assert_equal(@client.testByte(val), val)
+    assert_equal(@client.testByte(-val), -val)
+  end
+
+  def test_i32
+    val = 32
+    assert_equal(@client.testI32(val), val)
+    assert_equal(@client.testI32(-val), -val)
+  end
+
+  def test_i64
+    val = 64
+    assert_equal(@client.testI64(val), val)
+    assert_equal(@client.testI64(-val), -val)
+  end
+
+  def test_double
+    val = 3.14
+    assert_equal(@client.testDouble(val), val)
+    assert_equal(@client.testDouble(-val), -val)
+    assert_kind_of(Float, @client.testDouble(val))
+  end
+
+  def test_map
+    val = {1 => 1, 2 => 2, 3 => 3}
+    assert_equal(@client.testMap(val), val)
+    assert_kind_of(Hash, @client.testMap(val))
+  end
+
+  def test_list
+    val = [1,2,3,4,5]
+    assert_equal(@client.testList(val), val)
+    assert_kind_of(Array, @client.testList(val))
+  end
+
+  def test_enum
+    val = Thrift::Test::Numberz::SIX
+    ret = @client.testEnum(val)
+
+    assert_equal(ret, 6)
+    assert_kind_of(Fixnum, ret)
+  end
+
+  def test_typedef
+    #UserId  testTypedef(1: UserId thing),
+    true
+  end
+
+  def test_set
+    val = Set.new([1,2,3])
+    assert_equal(@client.testSet(val), val)
+    assert_kind_of(Set, @client.testSet(val))
+  end
+
+  def get_struct
+    Thrift::Test::Xtruct.new({'string_thing' => 'hi!', 'i32_thing' => 4 })
+  end
+
+  def test_struct
+    ret = @client.testStruct(get_struct)
+
+    assert_nil(ret.byte_thing, nil)
+    assert_nil(ret.i64_thing, nil)
+    assert_equal(ret.string_thing, 'hi!')
+    assert_equal(ret.i32_thing, 4)
+    assert_kind_of(Thrift::Test::Xtruct, ret)
+  end
+
+  def test_nest
+    struct2 = Thrift::Test::Xtruct2.new({'struct_thing' => get_struct, 'i32_thing' => 10})
+
+    ret = @client.testNest(struct2)
+
+    assert_nil(ret.struct_thing.byte_thing, nil)
+    assert_nil(ret.struct_thing.i64_thing, nil)
+    assert_equal(ret.struct_thing.string_thing, 'hi!')
+    assert_equal(ret.struct_thing.i32_thing, 4)
+    assert_equal(ret.i32_thing, 10)
+
+    assert_kind_of(Thrift::Test::Xtruct, ret.struct_thing)
+    assert_kind_of(Thrift::Test::Xtruct2, ret)
+  end
+
+  def test_insane
+    insane = Thrift::Test::Insanity.new({
+      'userMap' => { Thrift::Test::Numberz::ONE => 44 },
+      'xtructs' => [get_struct,
+        Thrift::Test::Xtruct.new({
+          'string_thing' => 'hi again',
+          'i32_thing' => 12
+        })
+      ]
+    })
+
+    ret = @client.testInsanity(insane)
+
+    assert_not_nil(ret[44])
+    assert_not_nil(ret[44][1])
+
+    struct = ret[44][1]
+
+    assert_equal(struct.userMap[Thrift::Test::Numberz::ONE], 44)
+    assert_equal(struct.xtructs[1].string_thing, 'hi again')
+    assert_equal(struct.xtructs[1].i32_thing, 12)
+
+    assert_kind_of(Hash, struct.userMap)
+    assert_kind_of(Array, struct.xtructs)
+    assert_kind_of(Thrift::Test::Insanity, struct)
+  end
+
+  def test_map_map
+    ret = @client.testMapMap(4)
+    assert_kind_of(Hash, ret)
+    assert_equal(ret, { 4 => { 4 => 4}})
+  end
+
+  def test_exception
+    assert_raise Thrift::Test::Xception do
+      @client.testException('foo')
+    end
+  end
+end
+
diff --git a/test/rb/integration/simple_client.rb b/test/rb/integration/simple_client.rb
new file mode 100644
index 0000000..1064822
--- /dev/null
+++ b/test/rb/integration/simple_client.rb
@@ -0,0 +1,163 @@
+#
+# 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.
+#
+
+require File.join(File.dirname(__FILE__), '../test_helper')
+
+require 'thrift'
+require 'ThriftTest'
+
+class SimpleClientTest < Test::Unit::TestCase
+  def setup    
+    unless @socket
+      @socket   = Thrift::Socket.new('localhost', 9090)
+      @protocol = Thrift::BinaryProtocol.new(@socket)
+      @client   = Thrift::Test::ThriftTest::Client.new(@protocol)
+      @socket.open
+    end
+  end
+  
+  def test_string
+    assert_equal(@client.testString('string'), 'string')
+  end
+
+  def test_byte
+    val = 8
+    assert_equal(@client.testByte(val), val)
+    assert_equal(@client.testByte(-val), -val)
+  end
+
+  def test_i32
+    val = 32
+    assert_equal(@client.testI32(val), val)
+    assert_equal(@client.testI32(-val), -val)
+  end
+
+  def test_i64
+    val = 64
+    assert_equal(@client.testI64(val), val)
+    assert_equal(@client.testI64(-val), -val)
+  end
+
+  def test_double
+    val = 3.14
+    assert_equal(@client.testDouble(val), val)
+    assert_equal(@client.testDouble(-val), -val)
+    assert_kind_of(Float, @client.testDouble(val))
+  end
+
+  def test_map
+    val = {1 => 1, 2 => 2, 3 => 3}
+    assert_equal(@client.testMap(val), val)
+    assert_kind_of(Hash, @client.testMap(val))
+  end
+
+  def test_list
+    val = [1,2,3,4,5]
+    assert_equal(@client.testList(val), val)
+    assert_kind_of(Array, @client.testList(val))
+  end
+
+  def test_enum
+    val = Thrift::Test::Numberz::SIX
+    ret = @client.testEnum(val)
+
+    assert_equal(ret, 6)
+    assert_kind_of(Fixnum, ret)
+  end
+
+  def test_typedef
+    #UserId  testTypedef(1: UserId thing),
+    true
+  end
+
+  def test_set
+    val = Set.new([1,2,3])
+    assert_equal(@client.testSet(val), val)
+    assert_kind_of(Set, @client.testSet(val))
+  end
+
+  def get_struct
+    Thrift::Test::Xtruct.new({'string_thing' => 'hi!', 'i32_thing' => 4 })
+  end
+
+  def test_struct
+    ret = @client.testStruct(get_struct)
+
+    assert_nil(ret.byte_thing, nil)
+    assert_nil(ret.i64_thing, nil)
+    assert_equal(ret.string_thing, 'hi!')
+    assert_equal(ret.i32_thing, 4)
+    assert_kind_of(Thrift::Test::Xtruct, ret)
+  end
+
+  def test_nest
+    struct2 = Thrift::Test::Xtruct2.new({'struct_thing' => get_struct, 'i32_thing' => 10})
+
+    ret = @client.testNest(struct2)
+
+    assert_nil(ret.struct_thing.byte_thing, nil)
+    assert_nil(ret.struct_thing.i64_thing, nil)
+    assert_equal(ret.struct_thing.string_thing, 'hi!')
+    assert_equal(ret.struct_thing.i32_thing, 4)
+    assert_equal(ret.i32_thing, 10)
+
+    assert_kind_of(Thrift::Test::Xtruct, ret.struct_thing)
+    assert_kind_of(Thrift::Test::Xtruct2, ret)
+  end
+
+  def test_insane
+    insane = Thrift::Test::Insanity.new({
+      'userMap' => { Thrift::Test::Numberz::ONE => 44 },
+      'xtructs' => [get_struct,
+        Thrift::Test::Xtruct.new({
+          'string_thing' => 'hi again',
+          'i32_thing' => 12
+        })
+      ]
+    })
+
+    ret = @client.testInsanity(insane)
+
+    assert_not_nil(ret[44])
+    assert_not_nil(ret[44][1])
+
+    struct = ret[44][1]
+
+    assert_equal(struct.userMap[Thrift::Test::Numberz::ONE], 44)
+    assert_equal(struct.xtructs[1].string_thing, 'hi again')
+    assert_equal(struct.xtructs[1].i32_thing, 12)
+
+    assert_kind_of(Hash, struct.userMap)
+    assert_kind_of(Array, struct.xtructs)
+    assert_kind_of(Thrift::Test::Insanity, struct)
+  end
+
+  def test_map_map
+    ret = @client.testMapMap(4)
+    assert_kind_of(Hash, ret)
+    assert_equal(ret, { 4 => { 4 => 4}})
+  end
+
+  def test_exception
+    assert_raise Thrift::Test::Xception do
+      @client.testException('foo')
+    end
+  end
+end
+
diff --git a/test/rb/integration/simple_server.rb b/test/rb/integration/simple_server.rb
new file mode 100644
index 0000000..3518d2e
--- /dev/null
+++ b/test/rb/integration/simple_server.rb
@@ -0,0 +1,64 @@
+#
+# 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.
+#
+
+$:.push File.dirname(__FILE__) + '/../gen-rb'
+$:.push File.join(File.dirname(__FILE__), '../../../lib/rb/lib')
+
+require 'thrift'
+require 'ThriftTest'
+
+class SimpleHandler
+  [:testString, :testByte, :testI32, :testI64, :testDouble,
+   :testStruct, :testMap, :testSet, :testList, :testNest,
+   :testEnum, :testTypedef].each do |meth|
+
+    define_method(meth) do |thing|
+      thing
+    end
+
+  end
+
+  def testInsanity(thing)
+    num, uid = thing.userMap.find { true }
+    return {uid => {num => thing}}
+  end
+
+  def testMapMap(thing)
+    return {thing => {thing => thing}}
+  end
+
+  def testEnum(thing)
+    return thing
+  end
+
+  def testTypedef(thing)
+    return thing
+  end
+
+  def testException(thing)
+    raise Thrift::Test::Xception, :message => 'error'
+  end
+end
+
+@handler   = SimpleHandler.new
+@processor = Thrift::Test::ThriftTest::Processor.new(@handler)
+@transport = Thrift::ServerSocket.new(9090)
+@server    = Thrift::ThreadedServer.new(@processor, @transport)
+
+@server.serve
diff --git a/test/rb/integration/test_simple_handler.rb b/test/rb/integration/test_simple_handler.rb
new file mode 100644
index 0000000..c34aa7e
--- /dev/null
+++ b/test/rb/integration/test_simple_handler.rb
@@ -0,0 +1,211 @@
+#
+# 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.
+#
+
+require File.join(File.dirname(__FILE__), '../test_helper')
+
+require 'thrift'
+require 'ThriftTest'
+
+class TestHandler
+  [:testString, :testByte, :testI32, :testI64, :testDouble,
+   :testStruct, :testMap, :testSet, :testList, :testNest,
+   :testEnum, :testTypedef].each do |meth|
+
+    define_method(meth) do |thing|
+      thing
+    end
+
+  end
+
+  def testInsanity(thing)
+    num, uid = thing.userMap.find { true }
+    return {uid => {num => thing}}
+  end
+
+  def testMapMap(thing)
+    return {thing => {thing => thing}}
+  end
+
+  def testEnum(thing)
+    return thing
+  end
+
+  def testTypedef(thing)
+    return thing
+  end
+
+  def testException(thing)
+    raise Thrift::Test::Xception, :message => 'error'
+  end
+
+end
+class TestThrift < Test::Unit::TestCase
+
+  @@INIT = nil
+
+  def setup
+    if @@INIT.nil?
+      # Initialize the server
+      @handler   = TestHandler.new()
+      @processor = Thrift::Test::ThriftTest::Processor.new(@handler)
+      @transport = Thrift::ServerSocket.new(9090)
+      @server    = Thrift::ThreadedServer.new(@processor, @transport)
+
+      @thread    = Thread.new { @server.serve }
+
+      # And the Client
+      @socket   = Thrift::Socket.new('localhost', 9090)
+      @protocol = Thrift::BinaryProtocol.new(@socket)
+      @client   = Thrift::Test::ThriftTest::Client.new(@protocol)
+      @socket.open
+    end
+  end
+
+  def test_string
+    assert_equal(@client.testString('string'), 'string')
+  end
+
+  def test_byte
+    val = 8
+    assert_equal(@client.testByte(val), val)
+    assert_equal(@client.testByte(-val), -val)
+  end
+
+  def test_i32
+    val = 32
+    assert_equal(@client.testI32(val), val)
+    assert_equal(@client.testI32(-val), -val)
+  end
+
+  def test_i64
+    val = 64
+    assert_equal(@client.testI64(val), val)
+    assert_equal(@client.testI64(-val), -val)
+  end
+
+  def test_double
+    val = 3.14
+    assert_equal(@client.testDouble(val), val)
+    assert_equal(@client.testDouble(-val), -val)
+    assert_kind_of(Float, @client.testDouble(val))
+  end
+
+  def test_map
+    val = {1 => 1, 2 => 2, 3 => 3}
+    assert_equal(@client.testMap(val), val)
+    assert_kind_of(Hash, @client.testMap(val))
+  end
+
+  def test_list
+    val = [1,2,3,4,5]
+    assert_equal(@client.testList(val), val)
+    assert_kind_of(Array, @client.testList(val))
+  end
+
+  def test_enum
+    val = Thrift::Test::Numberz::SIX
+    ret = @client.testEnum(val)
+
+    assert_equal(ret, 6)
+    assert_kind_of(Fixnum, ret)
+  end
+
+  def test_typedef
+    #UserId  testTypedef(1: UserId thing),
+    true
+  end
+
+  def test_set
+    val = Set.new([1, 2, 3])
+    assert_equal(val, @client.testSet(val))
+    assert_kind_of(Set, @client.testSet(val))
+  end
+
+  def get_struct
+    Thrift::Test::Xtruct.new({'string_thing' => 'hi!', 'i32_thing' => 4 })
+  end
+
+  def test_struct
+    ret = @client.testStruct(get_struct)
+
+    assert_nil(ret.byte_thing, nil)
+    assert_nil(ret.i64_thing, nil)
+    assert_equal(ret.string_thing, 'hi!')
+    assert_equal(ret.i32_thing, 4)
+    assert_kind_of(Thrift::Test::Xtruct, ret)
+  end
+
+  def test_nest
+    struct2 = Thrift::Test::Xtruct2.new({'struct_thing' => get_struct, 'i32_thing' => 10})
+
+    ret = @client.testNest(struct2)
+
+    assert_nil(ret.struct_thing.byte_thing, nil)
+    assert_nil(ret.struct_thing.i64_thing, nil)
+    assert_equal(ret.struct_thing.string_thing, 'hi!')
+    assert_equal(ret.struct_thing.i32_thing, 4)
+    assert_equal(ret.i32_thing, 10)
+
+    assert_kind_of(Thrift::Test::Xtruct, ret.struct_thing)
+    assert_kind_of(Thrift::Test::Xtruct2, ret)
+  end
+
+  def test_insane
+    insane = Thrift::Test::Insanity.new({
+      'userMap' => { Thrift::Test::Numberz::ONE => 44 },
+      'xtructs' => [get_struct,
+        Thrift::Test::Xtruct.new({
+          'string_thing' => 'hi again',
+          'i32_thing' => 12
+        })
+      ]
+    })
+
+    ret = @client.testInsanity(insane)
+
+    assert_not_nil(ret[44])
+    assert_not_nil(ret[44][1])
+
+    struct = ret[44][1]
+
+    assert_equal(struct.userMap[Thrift::Test::Numberz::ONE], 44)
+    assert_equal(struct.xtructs[1].string_thing, 'hi again')
+    assert_equal(struct.xtructs[1].i32_thing, 12)
+
+    assert_kind_of(Hash, struct.userMap)
+    assert_kind_of(Array, struct.xtructs)
+    assert_kind_of(Thrift::Test::Insanity, struct)
+  end
+
+  def test_map_map
+    ret = @client.testMapMap(4)
+    assert_kind_of(Hash, ret)
+    assert_equal(ret, { 4 => { 4 => 4}})
+  end
+
+  def test_exception
+    assert_raise Thrift::Test::Xception do
+      @client.testException('foo')
+    end
+  end
+
+  def teardown
+  end
+
+end
diff --git a/test/rb/test_helper.rb b/test/rb/test_helper.rb
new file mode 100644
index 0000000..c1ed779
--- /dev/null
+++ b/test/rb/test_helper.rb
@@ -0,0 +1,35 @@
+#
+# 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.
+#
+
+$:.unshift File.dirname(__FILE__) + '/gen-rb'
+$:.unshift File.join(File.dirname(__FILE__), '../../lib/rb/lib')
+$:.unshift File.join(File.dirname(__FILE__), '../../lib/rb/ext')
+
+require 'test/unit'
+
+module Thrift
+  module Struct
+    def ==(other)
+      return false unless other.is_a? self.class
+      self.class.const_get(:FIELDS).collect {|fid, data| data[:name] }.all? do |field|
+        send(field) == other.send(field)
+      end
+    end
+  end
+end
diff --git a/test/rb/test_suite.rb b/test/rb/test_suite.rb
new file mode 100644
index 0000000..b157c2c
--- /dev/null
+++ b/test/rb/test_suite.rb
@@ -0,0 +1,20 @@
+#
+# 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.
+#
+
+Dir["{core,generation}/**/*.rb"].each {|f| require f }
\ No newline at end of file
diff --git a/test/threads/Makefile b/test/threads/Makefile
new file mode 100644
index 0000000..14f1a58
--- /dev/null
+++ b/test/threads/Makefile
@@ -0,0 +1,63 @@
+#
+# 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.
+#
+
+# Default target is everything
+
+ifndef thrift_home
+thrift_home=../../
+endif #thrift_home
+
+target: all
+
+ifndef boost_home
+boost_home=/usr/local/include/boost-1_33_1
+endif #boost_home
+target: all
+
+include_paths = $(thrift_home)/lib/cpp/src \
+		$(boost_home)
+
+include_flags = $(patsubst %,-I%, $(include_paths))
+
+# Tools
+ifndef THRIFT
+THRIFT = ../../compiler/cpp/thrift
+endif # THRIFT
+
+CC     = g++
+LD     = g++
+
+# Compiler flags
+LFL   =  -L$(thrift_home)/lib/cpp/.libs -lthrift
+CCFL  = -Wall -O3 -g -I./gen-cpp $(include_flags)
+CFL   = $(CCFL) $(LFL)
+
+all: server client
+
+stubs: ThreadsTest.thrift
+	$(THRIFT) --gen cpp --gen py ThreadsTest.thrift
+
+server: stubs
+	g++ -o ThreadsServer $(CFL) ThreadsServer.cpp ./gen-cpp/ThreadsTest.cpp ./gen-cpp/ThreadsTest_types.cpp
+
+client: stubs
+	g++ -o ThreadsClient $(CFL) ThreadsClient.cpp ./gen-cpp/ThreadsTest.cpp ./gen-cpp/ThreadsTest_types.cpp
+
+clean:
+	$(RM) -r *.o ThreadsServer ThreadsClient gen-cpp gen-py
diff --git a/test/threads/ThreadsClient.cpp b/test/threads/ThreadsClient.cpp
new file mode 100644
index 0000000..85274a6
--- /dev/null
+++ b/test/threads/ThreadsClient.cpp
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+// This autogenerated skeleton file illustrates how to build a server.
+// You should copy it to another filename to avoid overwriting it.
+
+#include "ThreadsTest.h"
+#include <protocol/TBinaryProtocol.h>
+#include <server/TThreadPoolServer.h>
+#include <transport/TSocket.h>
+#include <transport/TTransportUtils.h>
+#include <thrift/concurrency/Monitor.h>
+#include <thrift/concurrency/ThreadManager.h>
+#include <thrift/concurrency/PosixThreadFactory.h>
+
+using boost::shared_ptr;
+using namespace apache::thrift;
+using namespace apache::thrift::protocol;
+using namespace apache::thrift::transport;
+using namespace apache::thrift::server;
+using namespace apache::thrift::concurrency;
+
+int main(int argc, char **argv) {
+  int port = 9090;
+  std::string host = "localhost";
+
+  shared_ptr<TTransport> transport(new TSocket(host, port));
+  shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
+
+  transport->open();
+
+  ThreadsTestClient client(protocol);
+  int val;
+  val = client.threadOne(5);
+  fprintf(stderr, "%d\n", val);
+  val = client.stop();
+  fprintf(stderr, "%d\n", val);
+  val = client.threadTwo(5);
+  fprintf(stderr, "%d\n", val);
+
+  transport->close();
+
+  fprintf(stderr, "done.\n");
+
+  return 0;
+}
+
diff --git a/test/threads/ThreadsServer.cpp b/test/threads/ThreadsServer.cpp
new file mode 100644
index 0000000..8734ee8
--- /dev/null
+++ b/test/threads/ThreadsServer.cpp
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ */
+
+// This autogenerated skeleton file illustrates how to build a server.
+// You should copy it to another filename to avoid overwriting it.
+
+#include "ThreadsTest.h"
+#include <protocol/TBinaryProtocol.h>
+#include <server/TThreadPoolServer.h>
+#include <server/TThreadedServer.h>
+#include <transport/TServerSocket.h>
+#include <transport/TTransportUtils.h>
+#include <thrift/concurrency/Monitor.h>
+#include <thrift/concurrency/ThreadManager.h>
+#include <thrift/concurrency/PosixThreadFactory.h>
+
+using boost::shared_ptr;
+using namespace apache::thrift;
+using namespace apache::thrift::protocol;
+using namespace apache::thrift::transport;
+using namespace apache::thrift::server;
+using namespace apache::thrift::concurrency;
+
+
+class ThreadsTestHandler : virtual public ThreadsTestIf {
+ public:
+  ThreadsTestHandler() {
+    // Your initialization goes here
+  }
+
+  int32_t threadOne(const int32_t sleep) {
+    // Your implementation goes here
+    printf("threadOne\n");
+    go2sleep(1, sleep);
+    return 1;
+  }
+
+  int32_t threadTwo(const int32_t sleep) {
+    // Your implementation goes here
+    printf("threadTwo\n");
+    go2sleep(2, sleep);
+    return 1;
+  }
+
+  int32_t threadThree(const int32_t sleep) {
+    // Your implementation goes here
+    printf("threadThree\n");
+    go2sleep(3, sleep);
+    return 1;
+  }
+
+  int32_t threadFour(const int32_t sleep) {
+    // Your implementation goes here
+    printf("threadFour\n");
+    go2sleep(4, sleep);
+    return 1;
+  }
+
+  int32_t stop() {
+    printf("stop\n");
+    server_->stop();
+    return 1;
+  }
+
+  void setServer(boost::shared_ptr<TServer> server) {
+    server_ = server;
+  }
+
+protected:
+  void go2sleep(int thread, int seconds) {
+    Monitor m;
+    for (int i = 0; i < seconds; ++i) {
+      fprintf(stderr, "Thread %d: sleep %d\n", thread, i);
+      try {
+        m.wait(1000);
+      } catch(TimedOutException& e) {
+      }
+    }
+    fprintf(stderr, "THREAD %d DONE\n", thread);
+  }
+
+private:
+  boost::shared_ptr<TServer> server_;
+
+};
+
+int main(int argc, char **argv) {
+  int port = 9090;
+  shared_ptr<ThreadsTestHandler> handler(new ThreadsTestHandler());
+  shared_ptr<TProcessor> processor(new ThreadsTestProcessor(handler));
+  shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
+  shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
+  shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
+
+  /*
+  shared_ptr<ThreadManager> threadManager =
+    ThreadManager::newSimpleThreadManager(10);
+  shared_ptr<PosixThreadFactory> threadFactory =
+    shared_ptr<PosixThreadFactory>(new PosixThreadFactory());
+  threadManager->threadFactory(threadFactory);
+  threadManager->start();
+
+  shared_ptr<TServer> server =
+    shared_ptr<TServer>(new TThreadPoolServer(processor,
+                                              serverTransport,
+                                              transportFactory,
+                                              protocolFactory,
+                                              threadManager));
+  */
+
+  shared_ptr<TServer> server =
+    shared_ptr<TServer>(new TThreadedServer(processor,
+                                            serverTransport,
+                                            transportFactory,
+                                            protocolFactory));
+
+  handler->setServer(server);
+
+  server->serve();
+
+  fprintf(stderr, "done.\n");
+
+  return 0;
+}
+
diff --git a/test/threads/ThreadsTest.thrift b/test/threads/ThreadsTest.thrift
new file mode 100644
index 0000000..caa9346
--- /dev/null
+++ b/test/threads/ThreadsTest.thrift
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+service ThreadsTest {
+  i32 threadOne(1: i32 sleep=15),
+  i32 threadTwo(2: i32 sleep=15),
+  i32 threadThree(3: i32 sleep=15),
+  i32 threadFour(4: i32 sleep=15)
+
+  i32 stop();
+
+}