summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/AllProtocolTests.cpp42
-rw-r--r--test/AllProtocolTests.tcc227
-rw-r--r--test/AnnotationTest.thrift31
-rw-r--r--test/Benchmark.cpp108
-rw-r--r--test/BrokenConstants.thrift25
-rw-r--r--test/ConstantsDemo.thrift69
-rw-r--r--test/DebugProtoTest.cpp105
-rw-r--r--test/DebugProtoTest.thrift253
-rw-r--r--test/DebugProtoTest_extras.cpp32
-rw-r--r--test/DenseLinkingTest.thrift92
-rw-r--r--test/DenseProtoTest.cpp384
-rw-r--r--test/DocTest.thrift247
-rwxr-xr-xtest/FastbinaryTest.py222
-rw-r--r--test/GenericHelpers.h102
-rw-r--r--test/JSONProtoTest.cpp159
-rw-r--r--test/JavaBeansTest.thrift34
-rw-r--r--test/Makefile.am178
-rw-r--r--test/ManyTypedefs.thrift50
-rw-r--r--test/OptionalRequiredTest.cpp242
-rw-r--r--test/OptionalRequiredTest.thrift72
-rw-r--r--test/SmallTest.thrift60
-rw-r--r--test/StressTest.thrift33
-rw-r--r--test/TBufferBaseTest.cpp639
-rw-r--r--test/TFDTransportTest.cpp56
-rw-r--r--test/TMemoryBufferTest.cpp107
-rw-r--r--test/TPipedTransportTest.cpp54
-rw-r--r--test/ThriftTest.thrift172
-rw-r--r--test/ThriftTest_extras.cpp33
-rw-r--r--test/UnitTestMain.cpp21
-rw-r--r--test/ZlibTest.cpp310
-rw-r--r--test/cpp/Stress-test.mk71
-rw-r--r--test/cpp/Thrift-test.mk78
-rw-r--r--test/cpp/realloc/Makefile40
-rw-r--r--test/cpp/realloc/realloc_test.c107
-rw-r--r--test/cpp/src/TestClient.cpp497
-rw-r--r--test/cpp/src/TestServer.cpp424
-rw-r--r--test/cpp/src/main.cpp509
-rw-r--r--test/cpp/src/nb-main.cpp502
-rw-r--r--test/csharp/CSharpClient.cs87
-rw-r--r--test/csharp/CSharpServer.cs129
-rw-r--r--test/csharp/ThriftTest/Program.cs61
-rw-r--r--test/csharp/ThriftTest/Properties/AssemblyInfo.cs55
-rw-r--r--test/csharp/ThriftTest/TestClient.cs425
-rw-r--r--test/csharp/ThriftTest/TestServer.cs348
-rw-r--r--test/csharp/ThriftTest/ThriftTest.csproj111
-rwxr-xr-xtest/csharp/ThriftTest/maketest.sh23
-rw-r--r--test/erl/Makefile66
-rw-r--r--test/erl/src/stress_server.erl64
-rw-r--r--test/erl/src/test_disklog.erl81
-rw-r--r--test/erl/src/test_membuffer.erl81
-rw-r--r--test/erl/src/test_server.erl174
-rw-r--r--test/hs/Client.hs58
-rw-r--r--test/hs/Server.hs57
-rw-r--r--test/hs/runclient.sh26
-rw-r--r--test/hs/runserver.sh27
-rw-r--r--test/ocaml/Makefile24
-rw-r--r--test/ocaml/client/Makefile26
-rw-r--r--test/ocaml/client/TestClient.ml82
-rw-r--r--test/ocaml/server/Makefile27
-rw-r--r--test/ocaml/server/TestServer.ml136
-rw-r--r--test/perl/Makefile30
-rw-r--r--test/perl/TestClient.pl338
-rw-r--r--test/php/Makefile39
-rw-r--r--test/php/TestClient.php398
-rw-r--r--test/php/TestInline.php24
-rw-r--r--test/py/Makefile.am48
-rwxr-xr-xtest/py/RunClientServer.py60
-rwxr-xr-xtest/py/SerializationTest.py133
-rwxr-xr-xtest/py/TestClient.py156
-rwxr-xr-xtest/py/TestEof.py121
-rwxr-xr-xtest/py/TestServer.py115
-rwxr-xr-xtest/py/TestSocket.py84
-rwxr-xr-xtest/py/TestSyntax.py28
-rwxr-xr-xtest/py/explicit_module/runtest.sh34
-rw-r--r--test/py/explicit_module/test1.thrift24
-rw-r--r--test/py/explicit_module/test2.thrift24
-rw-r--r--test/rb/Makefile.am28
-rw-r--r--test/rb/benchmarks/protocol_benchmark.rb174
-rw-r--r--test/rb/core/test_backwards_compatability.rb30
-rw-r--r--test/rb/core/test_exceptions.rb30
-rw-r--r--test/rb/core/transport/test_transport.rb70
-rw-r--r--test/rb/fixtures/structs.rb298
-rw-r--r--test/rb/generation/test_enum.rb28
-rw-r--r--test/rb/generation/test_struct.rb48
-rw-r--r--test/rb/integration/accelerated_buffered_client.rb163
-rw-r--r--test/rb/integration/accelerated_buffered_server.rb65
-rw-r--r--test/rb/integration/buffered_client.rb163
-rw-r--r--test/rb/integration/simple_client.rb163
-rw-r--r--test/rb/integration/simple_server.rb64
-rw-r--r--test/rb/integration/test_simple_handler.rb211
-rw-r--r--test/rb/test_helper.rb35
-rw-r--r--test/rb/test_suite.rb20
-rw-r--r--test/threads/Makefile63
-rw-r--r--test/threads/ThreadsClient.cpp63
-rw-r--r--test/threads/ThreadsServer.cpp141
-rw-r--r--test/threads/ThreadsTest.thrift28
96 files changed, 12096 insertions, 0 deletions
diff --git a/test/AllProtocolTests.cpp b/test/AllProtocolTests.cpp
new file mode 100644
index 000000000..db29cccf8
--- /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 000000000..a5a31156f
--- /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 000000000..dcc41b0bf
--- /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 000000000..d315fca73
--- /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 000000000..c5aab4abe
--- /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 000000000..7e97f02c8
--- /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 000000000..8c9aabec2
--- /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 000000000..d3d25802b
--- /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 000000000..e68c544bb
--- /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 000000000..cf61496aa
--- /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 000000000..99f78655f
--- /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 000000000..cb355ae37
--- /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 000000000..7f6efae60
--- /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 000000000..d661d8ba3
--- /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 000000000..668135691
--- /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 000000000..02bf98d63
--- /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 000000000..1226935de
--- /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 000000000..d194b63c2
--- /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 000000000..5743ce303
--- /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 000000000..f7d1fd6a1
--- /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 000000000..d0821c7ff
--- /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 000000000..87c6e4761
--- /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 000000000..da3ce8567
--- /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 000000000..1ec538e3a
--- /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 000000000..49bd10b5d
--- /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 000000000..5708fd21c
--- /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 000000000..3517640a6
--- /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 000000000..b78f27635
--- /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 000000000..d90c54f48
--- /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 000000000..45d3ecc4b
--- /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 000000000..1a753b3a1
--- /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 000000000..fb3e38bc6
--- /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 000000000..f89bbb3c5
--- /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 000000000..f9763adf4
--- /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 000000000..5ddfa0601
--- /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 000000000..83454dcaf
--- /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 000000000..46ee950d8
--- /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 000000000..8c74a815d
--- /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 000000000..641d5c9bb
--- /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 000000000..f9ab8fd28
--- /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 000000000..4c63ca478
--- /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 000000000..504ca8de7
--- /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 000000000..2d278b7f1
--- /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 000000000..e37064040
--- /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 000000000..3f427fd77
--- /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 000000000..5580de802
--- /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 000000000..17e30da6f
--- /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 000000000..35fff0693
--- /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 000000000..7b0be72db
--- /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 000000000..7bd23a0f1
--- /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 000000000..cd439ccdf
--- /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 000000000..c5e4d9074
--- /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 000000000..0ca9d9fea
--- /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 000000000..b93bbb147
--- /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 000000000..b23301b48
--- /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 000000000..a543ce587
--- /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 000000000..806ed20a9
--- /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 000000000..91783ae42
--- /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 000000000..44dcac761
--- /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 000000000..3f5c9ee15
--- /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 000000000..e2d81d452
--- /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 000000000..af80d4694
--- /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 000000000..aa35c6e93
--- /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 000000000..6d640dac3
--- /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 000000000..7066c461f
--- /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 000000000..63b7a890b
--- /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 000000000..2bd6094dd
--- /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 000000000..52bedd5e3
--- /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 000000000..64e5e872b
--- /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 000000000..7d64289d0
--- /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 000000000..3d379eaeb
--- /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 000000000..2f7353fb1
--- /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 000000000..df67d4851
--- /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 000000000..2e5a4f1be
--- /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 000000000..ec600d7d4
--- /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 000000000..68f9da4dd
--- /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 000000000..a6f431c8e
--- /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 000000000..05a8ee534
--- /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 000000000..0577515d3
--- /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 000000000..f41587a7b
--- /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 000000000..52755c1da
--- /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 000000000..ebbeb0a7d
--- /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 000000000..7d3f08ba5
--- /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 000000000..3bd4fc9bb
--- /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 000000000..7cec1df51
--- /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 000000000..1ca66e543
--- /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 000000000..1a925ccf4
--- /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 000000000..1064822ac
--- /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 000000000..3518d2e14
--- /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 000000000..c34aa7e51
--- /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 000000000..c1ed779ef
--- /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 000000000..b157c2c50
--- /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 000000000..14f1a5890
--- /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 000000000..85274a632
--- /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 000000000..8734ee893
--- /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 000000000..caa934605
--- /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();
+
+}