1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  *   http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 #include <limits>
21 #include <locale>
22 #include <ios>
23 #include <iostream>
24 #include <sstream>
25 #include <thrift/protocol/TBinaryProtocol.h>
26 #include <thrift/protocol/TCompactProtocol.h>
27 #include <thrift/protocol/THeaderProtocol.h>
28 #include <thrift/protocol/TJSONProtocol.h>
29 #include <thrift/protocol/TMultiplexedProtocol.h>
30 #include <thrift/transport/THttpClient.h>
31 #include <thrift/transport/TTransportUtils.h>
32 #include <thrift/transport/TSocket.h>
33 #include <thrift/transport/TSSLSocket.h>
34 #include <thrift/transport/TZlibTransport.h>
35 #include <thrift/async/TEvhttpClientChannel.h>
36 #include <thrift/server/TNonblockingServer.h> // <event.h>
37 
38 #ifdef HAVE_STDINT_H
39 #include <stdint.h>
40 #endif
41 #ifdef HAVE_INTTYPES_H
42 #include <inttypes.h>
43 #endif
44 
45 #include <boost/algorithm/string.hpp>
46 #include <boost/filesystem.hpp>
47 #include <boost/program_options.hpp>
48 #include <boost/random/random_device.hpp>
49 #if _WIN32
50 #include <thrift/windows/TWinsockSingleton.h>
51 #endif
52 
53 #include "SecondService.h"
54 #include "ThriftTest.h"
55 
56 using namespace std;
57 using namespace apache::thrift;
58 using namespace apache::thrift::async;
59 using namespace apache::thrift::protocol;
60 using namespace apache::thrift::transport;
61 using namespace thrift::test;
62 
63 //
64 // A pedantic protocol that checks to make sure the response sequence ID
65 // is the same as the sent sequence ID.  lib/cpp always sends zero for
66 // synchronous clients, so this bumps the number to make sure it gets
67 // returned properly from the remote server.  Any server that does not
68 // respond with the same sequence number is violating the sequence ID
69 // agreement between client and server.
70 //
71 
72 template<typename Proto>
73 class TPedanticProtocol : public Proto
74 {
75     public:
TPedanticProtocol(std::shared_ptr<TTransport> & transport)76         TPedanticProtocol(std::shared_ptr<TTransport>& transport)
77           : Proto(transport), m_last_seqid((std::numeric_limits<int32_t>::max)() - 10) { }
78 
writeMessageBegin_virt(const std::string & name,const TMessageType messageType,const int32_t in_seqid)79         virtual uint32_t writeMessageBegin_virt(const std::string& name,
80                                            const TMessageType messageType,
81                                            const int32_t in_seqid) override
82         {
83             int32_t seqid = in_seqid;
84             if (!seqid) { // this is typical for normal cpp generated code
85                 seqid = ++m_last_seqid;
86             }
87 
88             return Proto::writeMessageBegin_virt(name, messageType, seqid);
89         }
90 
readMessageBegin_virt(std::string & name,TMessageType & messageType,int32_t & seqid)91         virtual uint32_t readMessageBegin_virt(std::string& name,
92                                           TMessageType& messageType,
93                                           int32_t& seqid) override
94         {
95             uint32_t result = Proto::readMessageBegin_virt(name, messageType, seqid);
96             if (seqid != m_last_seqid) {
97                 std::stringstream ss;
98                 ss << "ERROR: send request with seqid " << m_last_seqid << " and got reply with seqid " << seqid;
99                 throw std::logic_error(ss.str());
100             } /* else {
101                 std::cout << "verified seqid " << m_last_seqid << " round trip OK" << std::endl;
102             } */
103             return result;
104         }
105 
106     private:
107         int32_t m_last_seqid;
108 };
109 
110 // Current time, microseconds since the epoch
now()111 uint64_t now() {
112   int64_t ret;
113   struct timeval tv;
114 
115   THRIFT_GETTIMEOFDAY(&tv, nullptr);
116   ret = tv.tv_sec;
117   ret = ret * 1000 * 1000 + tv.tv_usec;
118   return ret;
119 }
120 
testString_clientReturn(event_base * base,int testNr,ThriftTestCobClient * client)121 static void testString_clientReturn(event_base* base,
122                                     int testNr,
123                                     ThriftTestCobClient* client) {
124   try {
125     string s;
126     client->recv_testString(s);
127     std::ostringstream os;
128     os << "test" << testNr;
129     const bool ok = (s == os.str());
130     cout << "testString: " << s << " " << ((ok) ? "ok" : "failed") << endl;
131   } catch (TException& exn) {
132     cout << "Error: " << exn.what() << endl;
133   }
134 
135   if (testNr == 9)
136     event_base_loopbreak(base); // end test
137 }
138 
testVoid_clientReturn(event_base * base,ThriftTestCobClient * client)139 static void testVoid_clientReturn(event_base* base, ThriftTestCobClient* client) {
140   try {
141     client->recv_testVoid();
142     cout << "testVoid" << endl;
143 
144     for (int testNr = 0; testNr < 10; ++testNr) {
145       std::ostringstream os;
146       os << "test" << testNr;
147       client->testString(std::bind(testString_clientReturn,
148                                     base,
149                                     testNr,
150                                     std::placeholders::_1),
151                        os.str());
152     }
153   } catch (TException& exn) {
154     cout << "Error: " << exn.what() << endl;
155   }
156 }
157 
158 // Workaround for absense of C++11 "auto" keyword.
159 template <typename T>
print_eq(T expected,T actual)160 bool print_eq(T expected, T actual) {
161   cout << "(" << actual << ")" << endl;
162   if (expected != actual) {
163     cout << "*** FAILED ***" << endl << "Expected: " << expected << " but got: " << actual << endl;
164     return false;
165   }
166   return true;
167 }
168 
169 #define BASETYPE_IDENTITY_TEST(func, value)                                                        \
170   cout << #func "(" << value << ") = ";                                                            \
171   try {                                                                                            \
172     if (!print_eq(value, testClient.func(value)))                                                  \
173       return_code |= ERR_BASETYPES;                                                                \
174   } catch (TTransportException&) {                                                                 \
175     throw;                                                                                         \
176   } catch (exception & ex) {                                                                       \
177     cout << "*** FAILED ***" << endl << ex.what() << endl;                                         \
178     return_code |= ERR_BASETYPES;                                                                  \
179   }
180 
181 int binary_test(ThriftTestClient& testClient, string::size_type siz);
182 
183 BOOST_CONSTEXPR_OR_CONST int ERR_BASETYPES = 1;
184 BOOST_CONSTEXPR_OR_CONST int ERR_STRUCTS = 2;
185 BOOST_CONSTEXPR_OR_CONST int ERR_CONTAINERS = 4;
186 BOOST_CONSTEXPR_OR_CONST int ERR_EXCEPTIONS = 8;
187 BOOST_CONSTEXPR_OR_CONST int ERR_UNKNOWN = 64;
188 
main(int argc,char ** argv)189 int main(int argc, char** argv) {
190   cout.precision(19);
191 
192   string testDir  = boost::filesystem::system_complete(argv[0]).parent_path().parent_path().parent_path().string();
193   string caPath   = testDir + "/keys/CA.pem";
194   string certPath = testDir + "/keys/client.crt";
195   string keyPath  = testDir + "/keys/client.key";
196 
197 #if _WIN32
198   transport::TWinsockSingleton::create();
199 #endif
200   string host = "localhost";
201   int port = 9090;
202   int numTests = 1;
203   bool ssl = false;
204   bool zlib = false;
205   string transport_type = "buffered";
206   string protocol_type = "binary";
207   string domain_socket = "";
208   bool abstract_namespace = false;
209   bool noinsane = false;
210 
211   int return_code = 0;
212 
213   boost::program_options::options_description desc("Allowed options");
214   desc.add_options()
215       ("help,h", "produce help message")
216       ("host",
217           boost::program_options::value<string>(&host)->default_value(host),
218           "Host to connect")
219       ("port",
220           boost::program_options::value<int>(&port)->default_value(port),
221           "Port number to connect")
222       ("domain-socket",
223           boost::program_options::value<string>(&domain_socket)->default_value(domain_socket),
224           "Domain Socket (e.g. /tmp/ThriftTest.thrift), instead of host and port")
225       ("abstract-namespace",
226           "Look for the domain socket in the Abstract Namespace"
227           " (no connection with filesystem pathnames)")
228       ("transport",
229           boost::program_options::value<string>(&transport_type)->default_value(transport_type),
230           "Transport: buffered, framed, http, evhttp, zlib")
231       ("protocol",
232           boost::program_options::value<string>(&protocol_type)->default_value(protocol_type),
233           "Protocol: binary, compact, header, json, multi, multic, multih, multij")
234       ("ssl",
235           "Encrypted Transport using SSL")
236       ("zlib",
237           "Wrap Transport with Zlib")
238       ("testloops,n",
239           boost::program_options::value<int>(&numTests)->default_value(numTests),
240           "Number of Tests")
241       ("noinsane",
242           "Do not run insanity test");
243 
244   boost::program_options::variables_map vm;
245   boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm);
246   boost::program_options::notify(vm);
247 
248   if (vm.count("help")) {
249     cout << desc << endl;
250     return ERR_UNKNOWN;
251   }
252 
253   try {
254     if (!protocol_type.empty()) {
255       if (protocol_type == "binary") {
256       } else if (protocol_type == "compact") {
257       } else if (protocol_type == "header") {
258       } else if (protocol_type == "json") {
259       } else if (protocol_type == "multi") {
260       } else if (protocol_type == "multic") {
261       } else if (protocol_type == "multih") {
262       } else if (protocol_type == "multij") {
263       } else {
264         throw invalid_argument("Unknown protocol type " + protocol_type);
265       }
266     }
267 
268     if (!transport_type.empty()) {
269       if (transport_type == "buffered") {
270       } else if (transport_type == "framed") {
271       } else if (transport_type == "http") {
272       } else if (transport_type == "evhttp") {
273       } else if (transport_type == "zlib") {
274         // crosstest will pass zlib as a transport and as a flag right now..
275       } else {
276         throw invalid_argument("Unknown transport type " + transport_type);
277       }
278     }
279 
280   } catch (exception& e) {
281     cerr << e.what() << endl;
282     cout << desc << endl;
283     return ERR_UNKNOWN;
284   }
285 
286   if (vm.count("ssl")) {
287     ssl = true;
288   }
289 
290   if (vm.count("zlib")) {
291     zlib = true;
292   }
293 
294   if (vm.count("abstract-namespace")) {
295     abstract_namespace = true;
296   }
297 
298   if (vm.count("noinsane")) {
299     noinsane = true;
300   }
301 
302   // THRIFT-4164: The factory MUST outlive any sockets it creates for correct behavior!
303   std::shared_ptr<TSSLSocketFactory> factory;
304   std::shared_ptr<TSocket> socket;
305   std::shared_ptr<TTransport> transport;
306   std::shared_ptr<TProtocol> protocol;
307   std::shared_ptr<TProtocol> protocol2;  // SecondService for multiplexed
308 
309   if (ssl) {
310     cout << "Client Certificate File: " << certPath << endl;
311     cout << "Client Key         File: " << keyPath << endl;
312     cout << "CA                 File: " << caPath << endl;
313 
314     factory = std::shared_ptr<TSSLSocketFactory>(new TSSLSocketFactory());
315     factory->ciphers("ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH");
316     factory->loadTrustedCertificates(caPath.c_str());
317     factory->loadCertificate(certPath.c_str());
318     factory->loadPrivateKey(keyPath.c_str());
319     factory->authenticate(true);
320     socket = factory->createSocket(host, port);
321   } else {
322     if (domain_socket != "") {
323       if (abstract_namespace) {
324         std::string abstract_socket("\0", 1);
325         abstract_socket += domain_socket;
326         socket = std::shared_ptr<TSocket>(new TSocket(abstract_socket));
327       } else {
328         socket = std::shared_ptr<TSocket>(new TSocket(domain_socket));
329       }
330       port = 0;
331     } else {
332       socket = std::shared_ptr<TSocket>(new TSocket(host, port));
333     }
334   }
335 
336   if (transport_type.compare("http") == 0) {
337     transport = std::make_shared<THttpClient>(socket, host, "/service");
338   } else if (transport_type.compare("framed") == 0) {
339     transport = std::make_shared<TFramedTransport>(socket);
340   } else {
341     transport = std::make_shared<TBufferedTransport>(socket);
342   }
343 
344   if (zlib) {
345     transport = std::make_shared<TZlibTransport>(transport);
346   }
347 
348   if (protocol_type == "json" || protocol_type == "multij") {
349     typedef TPedanticProtocol<TJSONProtocol> TPedanticJSONProtocol;
350     protocol = std::make_shared<TPedanticJSONProtocol>(transport);
351   } else if (protocol_type == "compact" || protocol_type == "multic") {
352     typedef TPedanticProtocol<TCompactProtocol> TPedanticCompactProtocol;
353     protocol = std::make_shared<TPedanticCompactProtocol>(transport);
354   } else if (protocol_type == "header" || protocol_type == "multih") {
355     typedef TPedanticProtocol<THeaderProtocol> TPedanticHeaderProtocol;
356     protocol = std::make_shared<TPedanticHeaderProtocol>(transport);
357   } else {
358     typedef TPedanticProtocol<TBinaryProtocol> TPedanticBinaryProtocol;
359     protocol = std::make_shared<TPedanticBinaryProtocol>(transport);
360   }
361 
362   if (boost::starts_with(protocol_type, "multi")) {
363     protocol2 = std::make_shared<TMultiplexedProtocol>(protocol, "SecondService");
364     // we don't need access to the original protocol any more, so...
365     protocol = std::make_shared<TMultiplexedProtocol>(protocol, "ThriftTest");
366   }
367 
368   // Connection info
369   cout << "Connecting (" << transport_type << "/" << protocol_type << ") to: ";
370   if (abstract_namespace) {
371     cout << '@';
372   }
373   cout << domain_socket;
374   if (port != 0) {
375     cout << host << ":" << port;
376   }
377   cout << endl;
378 
379   if (transport_type.compare("evhttp") == 0) {
380     event_base* base = event_base_new();
381     cout << "Libevent Version: " << event_get_version() << endl;
382     cout << "Libevent Method: " << event_base_get_method(base) << endl;
383 #if LIBEVENT_VERSION_NUMBER >= 0x02000000
384     cout << "Libevent Features: 0x" << hex << event_base_get_features(base) << endl;
385 #endif
386 
387     std::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
388 
389     std::shared_ptr<TAsyncChannel> channel(
390         new TEvhttpClientChannel(host.c_str(), "/", host.c_str(), port, base));
391     ThriftTestCobClient* client = new ThriftTestCobClient(channel, protocolFactory.get());
392     client->testVoid(std::bind(testVoid_clientReturn,
393                                 base,
394                                 std::placeholders::_1));
395 
396     event_base_loop(base, 0);
397     return 0;
398   }
399 
400   ThriftTestClient testClient(protocol);
401 
402   uint64_t time_min = 0;
403   uint64_t time_max = 0;
404   uint64_t time_tot = 0;
405 
406   int test = 0;
407   for (test = 0; test < numTests; ++test) {
408 
409     try {
410       transport->open();
411     } catch (TTransportException& ex) {
412       cout << "Connect failed: " << ex.what() << endl;
413       return ERR_UNKNOWN;
414     }
415 
416     /**
417      * CONNECT TEST
418      */
419     printf("Test #%d, connect %s:%d\n", test + 1, host.c_str(), port);
420 
421     uint64_t start = now();
422 
423     /**
424      * VOID TEST
425      */
426     try {
427       cout << "testVoid()" << flush;
428       testClient.testVoid();
429       cout << " = void" << endl;
430     } catch (TTransportException&) {
431       // Stop here if transport got broken
432       throw;
433     } catch (exception& ex) {
434       cout << "*** FAILED ***" << endl << ex.what() << endl;
435       return_code |= ERR_BASETYPES;
436     }
437 
438     /**
439      * STRING TEST
440      */
441     cout << "testString(\"Test\")" << flush;
442     string s;
443     testClient.testString(s, "Test");
444     cout << " = " << s << endl;
445     if (s != "Test") {
446       cout << "*** FAILED ***" << endl;
447       return_code |= ERR_BASETYPES;
448     }
449 
450     //
451     // Multiplexed protocol - call another service method
452     // in the middle of the ThriftTest
453     //
454     if (boost::starts_with(protocol_type, "multi")) {
455     SecondServiceClient ssc(protocol2);
456     // transport is already open...
457 
458         try {
459           cout << "secondService.secondTestString(\"foo\") => " << flush;
460         std::string result;
461       ssc.secondtestString(result, "foo");
462       cout << "{" << result << "}" << endl;
463       } catch (std::exception& e) {
464       cout << "  *** FAILED *** " << e.what() << endl;
465       return_code |= ERR_EXCEPTIONS;
466     }
467     }
468 
469     try {
470 #ifdef _MSC_VER
471 #pragma warning( push )
472 #pragma warning( disable : 4566 )
473 #endif
474       string str(
475           "}{Afrikaans, Alemannisch, Aragonés, العربية, مصرى, "
476           "Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, "
477           "Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, "
478           "বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, "
479           "Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, "
480           "Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, "
481           "Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, "
482           "Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, "
483           "Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, "
484           "Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, "
485           "Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, "
486           "ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, "
487           "Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, "
488           "Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa "
489           "Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, مازِرونی, Bahasa "
490           "Melayu, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪"
491           "Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, "
492           "Occitan, Иронау, Papiamentu, Deitsch, Polski, پنجابی, پښتو, "
493           "Norfuk / Pitkern, Português, Runa Simi, Rumantsch, Romani, Română, "
494           "Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple "
495           "English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, "
496           "Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, "
497           "Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, "
498           "Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, "
499           "Bân-lâm-gú, 粵語");
500 #ifdef _MSC_VER
501 #pragma warning( pop )
502 #endif
503       cout << "testString(" << str << ") = " << flush;
504       testClient.testString(s, str);
505       cout << s << endl;
506       if (s != str) {
507         cout.imbue(locale("en_US.UTF8"));
508         cout << "*** FAILED ***" << endl << "Expected string: " << str << " but got: " << s << endl << "CLEAR";
509         return_code |= ERR_BASETYPES;
510       }
511     } catch (TTransportException&) {
512       throw;
513     } catch (exception& ex) {
514       cout << "*** FAILED ***" << endl << ex.what() << endl;
515       return_code |= ERR_BASETYPES;
516       return return_code;
517     }
518     try {
519       string str(
520           "quote: \" backslash:"
521           " forwardslash-escaped: \\/ "
522           " backspace: \b formfeed: \f newline: \n return: \r tab: "
523           " now-all-of-them-together: \"\\\\/\b\n\r\t"
524           " now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><"
525           " char-to-test-json-parsing: ]] \"]] \\\" }}}{ [[[ ");
526       cout << "testString(" << str << ") = " << flush;
527       testClient.testString(s, str);
528       cout << s << endl;
529       if (s != str) {
530         cout.imbue(locale("en_US.UTF8"));
531         cout << "*** FAILED ***" << endl
532              << "Expected string: " << str << " but got: " << s << endl
533              << "CLEAR";
534         ;
535         return_code |= ERR_BASETYPES;
536       }
537     } catch (TTransportException&) {
538       throw;
539     } catch (exception& ex) {
540       cout << "*** FAILED ***" << endl << ex.what() << endl;
541       return_code |= ERR_BASETYPES;
542       return return_code;
543     }
544 
545     /**
546      * BOOL TEST
547      */
548     cout << boolalpha;
549     BASETYPE_IDENTITY_TEST(testBool, true);
550     BASETYPE_IDENTITY_TEST(testBool, false);
551 
552     /**
553      * BYTE TEST
554      */
555     BASETYPE_IDENTITY_TEST(testByte, (int8_t)0);
556     BASETYPE_IDENTITY_TEST(testByte, (int8_t)-1);
557     BASETYPE_IDENTITY_TEST(testByte, (int8_t)42);
558     BASETYPE_IDENTITY_TEST(testByte, (int8_t)-42);
559     BASETYPE_IDENTITY_TEST(testByte, (int8_t)127);
560     BASETYPE_IDENTITY_TEST(testByte, (int8_t)-128);
561 
562     /**
563      * I32 TEST
564      */
565     BASETYPE_IDENTITY_TEST(testI32, 0);
566     BASETYPE_IDENTITY_TEST(testI32, -1);
567     BASETYPE_IDENTITY_TEST(testI32, 190000013);
568     BASETYPE_IDENTITY_TEST(testI32, -190000013);
569     BASETYPE_IDENTITY_TEST(testI32, (numeric_limits<int32_t>::max)());
570     BASETYPE_IDENTITY_TEST(testI32, (numeric_limits<int32_t>::min)());
571 
572     /**
573      * I64 TEST
574      */
575     BASETYPE_IDENTITY_TEST(testI64, (int64_t)0);
576     BASETYPE_IDENTITY_TEST(testI64, (int64_t)-1);
577     BASETYPE_IDENTITY_TEST(testI64, (int64_t)7000000000000000123LL);
578     BASETYPE_IDENTITY_TEST(testI64, (int64_t)-7000000000000000123LL);
579     BASETYPE_IDENTITY_TEST(testI64, (int64_t)pow(static_cast<double>(2LL), 32));
580     BASETYPE_IDENTITY_TEST(testI64, (int64_t)-pow(static_cast<double>(2LL), 32));
581     BASETYPE_IDENTITY_TEST(testI64, (int64_t)pow(static_cast<double>(2LL), 32) + 1);
582     BASETYPE_IDENTITY_TEST(testI64, (int64_t)-pow(static_cast<double>(2LL), 32) - 1);
583     BASETYPE_IDENTITY_TEST(testI64, (numeric_limits<int64_t>::max)());
584     BASETYPE_IDENTITY_TEST(testI64, (numeric_limits<int64_t>::min)());
585 
586     /**
587      * DOUBLE TEST
588      */
589     // Comparing double values with plain equality because Thrift handles full precision of double
590     BASETYPE_IDENTITY_TEST(testDouble, 0.0);
591     BASETYPE_IDENTITY_TEST(testDouble, -1.0);
592     BASETYPE_IDENTITY_TEST(testDouble, -5.2098523);
593     BASETYPE_IDENTITY_TEST(testDouble, -0.000341012439638598279);
594     BASETYPE_IDENTITY_TEST(testDouble, pow(static_cast<double>(2), 32));
595     BASETYPE_IDENTITY_TEST(testDouble, pow(static_cast<double>(2), 32) + 1);
596     BASETYPE_IDENTITY_TEST(testDouble, pow(static_cast<double>(2), 53) - 1);
597     BASETYPE_IDENTITY_TEST(testDouble, -pow(static_cast<double>(2), 32));
598     BASETYPE_IDENTITY_TEST(testDouble, -pow(static_cast<double>(2), 32) - 1);
599     BASETYPE_IDENTITY_TEST(testDouble, -pow(static_cast<double>(2), 53) + 1);
600 
601     try {
602       double expected = pow(static_cast<double>(10), 307);
603       cout << "testDouble(" << expected << ") = " << flush;
604       double actual = testClient.testDouble(expected);
605       cout << "(" << actual << ")" << endl;
606       if (expected - actual > pow(static_cast<double>(10), 292)) {
607         cout << "*** FAILED ***" << endl
608              << "Expected: " << expected << " but got: " << actual << endl;
609       }
610     } catch (TTransportException&) {
611       throw;
612     } catch (exception& ex) {
613       cout << "*** FAILED ***" << endl << ex.what() << endl;
614       return_code |= ERR_BASETYPES;
615     }
616 
617     try {
618       double expected = pow(static_cast<double>(10), -292);
619       cout << "testDouble(" << expected << ") = " << flush;
620       double actual = testClient.testDouble(expected);
621       cout << "(" << actual << ")" << endl;
622       if (expected - actual > pow(static_cast<double>(10), -307)) {
623         cout << "*** FAILED ***" << endl
624              << "Expected: " << expected << " but got: " << actual << endl;
625       }
626     } catch (TTransportException&) {
627       throw;
628     } catch (exception& ex) {
629       cout << "*** FAILED ***" << endl << ex.what() << endl;
630       return_code |= ERR_BASETYPES;
631     }
632 
633     /**
634      * BINARY TEST
635      */
636     for (string::size_type i = 0; i < 131073 && !return_code; ) {
637       return_code |= binary_test(testClient, i);
638       if (i > 0) { i *= 2; } else { ++i; }
639     }
640 
641 
642     /**
643      * STRUCT TEST
644      */
645     cout << "testStruct({\"Zero\", 1, -3, -5})" << flush;
646     Xtruct out;
647     out.string_thing = "Zero";
648     out.byte_thing = 1;
649     out.i32_thing = -3;
650     out.i64_thing = -5;
651     Xtruct in;
652     testClient.testStruct(in, out);
653     printf(" = {\"%s\", %d, %d, %" PRId64 "}\n",
654            in.string_thing.c_str(),
655            (int)in.byte_thing,
656            in.i32_thing,
657            in.i64_thing);
658     if (in != out) {
659       cout << "*** FAILED ***" << endl;
660       return_code |= ERR_STRUCTS;
661     }
662 
663     /**
664      * NESTED STRUCT TEST
665      */
666     cout << "testNest({1, {\"Zero\", 1, -3, -5}), 5}" << flush;
667     Xtruct2 out2;
668     out2.byte_thing = 1;
669     out2.struct_thing = out;
670     out2.i32_thing = 5;
671     Xtruct2 in2;
672     testClient.testNest(in2, out2);
673     in = in2.struct_thing;
674     printf(" = {%d, {\"%s\", %d, %d, %" PRId64 "}, %d}\n",
675            in2.byte_thing,
676            in.string_thing.c_str(),
677            (int)in.byte_thing,
678            in.i32_thing,
679            in.i64_thing,
680            in2.i32_thing);
681     if (in2 != out2) {
682       cout << "*** FAILED ***" << endl;
683       return_code |= ERR_STRUCTS;
684     }
685 
686     /**
687      * MAP TEST
688      */
689     map<int32_t, int32_t> mapout;
690     for (int32_t i = 0; i < 5; ++i) {
691       mapout.insert(make_pair(i, i - 10));
692     }
693     cout << "testMap({" << flush;
694     map<int32_t, int32_t>::const_iterator m_iter;
695     bool first = true;
696     for (m_iter = mapout.begin(); m_iter != mapout.end(); ++m_iter) {
697       if (first) {
698         first = false;
699       } else {
700         cout << ",";
701       }
702       cout << m_iter->first << " => " << m_iter->second;
703     }
704     cout << "})";
705     map<int32_t, int32_t> mapin;
706     testClient.testMap(mapin, mapout);
707     cout << " = {";
708     first = true;
709     for (m_iter = mapin.begin(); m_iter != mapin.end(); ++m_iter) {
710       if (first) {
711         first = false;
712       } else {
713         cout << ",";
714       }
715       cout << m_iter->first << " => " << m_iter->second;
716     }
717     cout << "}" << endl;
718     if (mapin != mapout) {
719       cout << "*** FAILED ***" << endl;
720       return_code |= ERR_CONTAINERS;
721     }
722 
723     /**
724      * STRING MAP TEST
725      */
726     cout << "testStringMap({a => 2, b => blah, some => thing}) = {" << flush;
727     map<string, string> smapin;
728     map<string, string> smapout;
729     smapin["a"] = "2";
730     smapin["b"] = "blah";
731     smapin["some"] = "thing";
732     try {
733       testClient.testStringMap(smapout, smapin);
734       first = true;
735       for (map<string, string>::const_iterator it = smapout.begin(); it != smapout.end(); ++it) {
736         if (first)
737           cout << ",";
738         else
739           first = false;
740         cout << it->first << " => " << it->second;
741       }
742       cout << "}" << endl;
743       if (smapin != smapout) {
744         cout << "*** FAILED ***" << endl;
745         return_code |= ERR_CONTAINERS;
746       }
747     } catch (TTransportException&) {
748       throw;
749     } catch (exception& ex) {
750       cout << "*** FAILED ***" << endl << ex.what() << endl;
751       return_code |= ERR_CONTAINERS;
752     }
753 
754     /**
755      * SET TEST
756      */
757     set<int32_t> setout;
758     for (int32_t i = -2; i < 3; ++i) {
759       setout.insert(i);
760     }
761     cout << "testSet({" << flush;
762     set<int32_t>::const_iterator s_iter;
763     first = true;
764     for (s_iter = setout.begin(); s_iter != setout.end(); ++s_iter) {
765       if (first) {
766         first = false;
767       } else {
768         cout << ",";
769       }
770       cout << *s_iter;
771     }
772     cout << "})";
773     set<int32_t> setin;
774     testClient.testSet(setin, setout);
775     cout << " = {";
776     first = true;
777     for (s_iter = setin.begin(); s_iter != setin.end(); ++s_iter) {
778       if (first) {
779         first = false;
780       } else {
781         cout << ",";
782       }
783       cout << *s_iter;
784     }
785     cout << "}" << endl;
786     if (setin != setout) {
787       cout << "*** FAILED ***" << endl;
788       return_code |= ERR_CONTAINERS;
789     }
790 
791     /**
792      * LIST TEST
793      */
794     cout << "testList(empty)" << flush;
795     try {
796       vector<int32_t> listout;
797       testClient.testList(listout, vector<int32_t>());
798       if (!listout.empty()) {
799         cout << "*** FAILED ***" << endl;
800         cout << "invalid length: " << listout.size() << endl;
801         return_code |= ERR_CONTAINERS;
802       }
803     } catch (TTransportException&) {
804       throw;
805     } catch (exception& ex) {
806       cout << "*** FAILED ***" << endl << ex.what() << endl;
807       return_code |= ERR_CONTAINERS;
808     }
809     try {
810       vector<int32_t> listout;
811       for (int32_t i = -2; i < 3; ++i) {
812         listout.push_back(i);
813       }
814       cout << "testList({" << flush;
815       vector<int32_t>::const_iterator l_iter;
816       first = true;
817       for (l_iter = listout.begin(); l_iter != listout.end(); ++l_iter) {
818         if (first) {
819           first = false;
820         } else {
821           cout << ",";
822         }
823         cout << *l_iter;
824       }
825       cout << "})";
826       vector<int32_t> listin;
827       testClient.testList(listin, listout);
828       cout << " = {";
829       first = true;
830       for (l_iter = listin.begin(); l_iter != listin.end(); ++l_iter) {
831         if (first) {
832           first = false;
833         } else {
834           cout << ",";
835         }
836         cout << *l_iter;
837       }
838       cout << "}" << endl;
839       if (listin != listout) {
840         cout << "*** FAILED ***" << endl;
841         return_code |= ERR_CONTAINERS;
842       }
843     } catch (TTransportException&) {
844       throw;
845     } catch (exception& ex) {
846       cout << "*** FAILED ***" << endl << ex.what() << endl;
847       return_code |= ERR_CONTAINERS;
848     }
849 
850     /**
851      * ENUM TEST
852      */
853     cout << "testEnum(ONE)" << flush;
854     Numberz::type ret = testClient.testEnum(Numberz::ONE);
855     cout << " = " << ret << endl;
856     if (ret != Numberz::ONE) {
857       cout << "*** FAILED ***" << endl;
858       return_code |= ERR_STRUCTS;
859     }
860 
861     cout << "testEnum(TWO)" << flush;
862     ret = testClient.testEnum(Numberz::TWO);
863     cout << " = " << ret << endl;
864     if (ret != Numberz::TWO) {
865       cout << "*** FAILED ***" << endl;
866       return_code |= ERR_STRUCTS;
867     }
868 
869     cout << "testEnum(THREE)" << flush;
870     ret = testClient.testEnum(Numberz::THREE);
871     cout << " = " << ret << endl;
872     if (ret != Numberz::THREE) {
873       cout << "*** FAILED ***" << endl;
874       return_code |= ERR_STRUCTS;
875     }
876 
877     cout << "testEnum(FIVE)" << flush;
878     ret = testClient.testEnum(Numberz::FIVE);
879     cout << " = " << ret << endl;
880     if (ret != Numberz::FIVE) {
881       cout << "*** FAILED ***" << endl;
882       return_code |= ERR_STRUCTS;
883     }
884 
885     cout << "testEnum(EIGHT)" << flush;
886     ret = testClient.testEnum(Numberz::EIGHT);
887     cout << " = " << ret << endl;
888     if (ret != Numberz::EIGHT) {
889       cout << "*** FAILED ***" << endl;
890       return_code |= ERR_STRUCTS;
891     }
892 
893     /**
894      * TYPEDEF TEST
895      */
896     cout << "testTypedef(309858235082523)" << flush;
897     UserId uid = testClient.testTypedef(309858235082523LL);
898     cout << " = " << uid << endl;
899     if (uid != 309858235082523LL) {
900       cout << "*** FAILED ***" << endl;
901       return_code |= ERR_STRUCTS;
902     }
903 
904     /**
905      * NESTED MAP TEST
906      */
907     cout << "testMapMap(1)" << flush;
908     map<int32_t, map<int32_t, int32_t> > mm;
909     testClient.testMapMap(mm, 1);
910     cout << " = {";
911     map<int32_t, map<int32_t, int32_t> >::const_iterator mi;
912     for (mi = mm.begin(); mi != mm.end(); ++mi) {
913       printf("%d => {", mi->first);
914       map<int32_t, int32_t>::const_iterator mi2;
915       for (mi2 = mi->second.begin(); mi2 != mi->second.end(); ++mi2) {
916         cout << mi2->first << " => " << mi2->second;
917       }
918       cout << "}, ";
919     }
920     cout << "}" << endl;
921     if (mm.size() != 2 ||
922         mm[-4][-4] != -4 ||
923         mm[-4][-3] != -3 ||
924         mm[-4][-2] != -2 ||
925         mm[-4][-1] != -1 ||
926         mm[4][4] != 4 ||
927         mm[4][3] != 3 ||
928         mm[4][2] != 2 ||
929         mm[4][1] != 1) {
930       cout << "*** FAILED ***" << endl;
931       return_code |= ERR_CONTAINERS;
932     }
933 
934     /**
935      * INSANITY TEST
936      */
937     if (!noinsane) {
938       Insanity insane;
939       insane.userMap.insert(make_pair(Numberz::FIVE, 5));
940       insane.userMap.insert(make_pair(Numberz::EIGHT, 8));
941       Xtruct truck;
942       truck.string_thing = "Goodbye4";
943       truck.byte_thing = 4;
944       truck.i32_thing = 4;
945       truck.i64_thing = 4;
946       Xtruct truck2;
947       truck2.string_thing = "Hello2";
948       truck2.byte_thing = 2;
949       truck2.i32_thing = 2;
950       truck2.i64_thing = 2;
951       insane.xtructs.push_back(truck);
952       insane.xtructs.push_back(truck2);
953       cout << "testInsanity()" << flush;
954       map<UserId, map<Numberz::type, Insanity> > whoa;
955       testClient.testInsanity(whoa, insane);
956       cout << " = {";
957       map<UserId, map<Numberz::type, Insanity> >::const_iterator i_iter;
958       for (i_iter = whoa.begin(); i_iter != whoa.end(); ++i_iter) {
959         printf("%" PRId64 " => {", i_iter->first);
960         map<Numberz::type, Insanity>::const_iterator i2_iter;
961         for (i2_iter = i_iter->second.begin(); i2_iter != i_iter->second.end(); ++i2_iter) {
962           printf("%d => {", i2_iter->first);
963           map<Numberz::type, UserId> userMap = i2_iter->second.userMap;
964           map<Numberz::type, UserId>::const_iterator um;
965           cout << "{";
966           for (um = userMap.begin(); um != userMap.end(); ++um) {
967             cout << um->first << " => " << um->second;
968           }
969           cout << "}, ";
970 
971           vector<Xtruct> xtructs = i2_iter->second.xtructs;
972           vector<Xtruct>::const_iterator x;
973           cout << "{";
974           for (x = xtructs.begin(); x != xtructs.end(); ++x) {
975             printf("{\"%s\", %d, %d, %" PRId64 "}, ",
976                    x->string_thing.c_str(),
977                    (int)x->byte_thing,
978                    x->i32_thing,
979                    x->i64_thing);
980           }
981           cout << "}";
982 
983           cout << "}, ";
984         }
985         cout << "}, ";
986       }
987       cout << "}" << endl;
988       bool failed = false;
989       map<UserId, map<Numberz::type, Insanity> >::const_iterator it1 = whoa.find(UserId(1));
990       if (whoa.size() != 2) {
991         failed = true;
992       }
993       if (it1 == whoa.end()) {
994         failed = true;
995       } else {
996         auto it12 = it1->second.find(Numberz::TWO);
997         if (it12 == it1->second.end() || it12->second != insane) {
998           failed = true;
999         }
1000         auto it13 = it1->second.find(Numberz::THREE);
1001         if (it13 == it1->second.end() || it13->second != insane) {
1002           failed = true;
1003         }
1004       }
1005       map<UserId, map<Numberz::type, Insanity> >::const_iterator it2 = whoa.find(UserId(2));
1006       if (it2 == whoa.end()) {
1007         failed = true;
1008       } else {
1009         auto it26 = it2->second.find(Numberz::SIX);
1010         if (it26 == it2->second.end() || it26->second != Insanity()) {
1011           failed = true;
1012         }
1013       }
1014       if (failed) {
1015         cout << "*** FAILED ***" << endl;
1016         return_code |= ERR_STRUCTS;
1017       }
1018     }
1019 
1020     /**
1021      * MULTI TEST
1022      */
1023     cout << "testMulti()" << endl;
1024     try {
1025       map<int16_t, string> mul_map;
1026       Xtruct mul_result;
1027       mul_map[1] = "blah";
1028       mul_map[2] = "thing";
1029       testClient.testMulti(mul_result, 42, 4242, 424242, mul_map, Numberz::EIGHT, UserId(24));
1030       Xtruct xxs;
1031       xxs.string_thing = "Hello2";
1032       xxs.byte_thing = 42;
1033       xxs.i32_thing = 4242;
1034       xxs.i64_thing = 424242;
1035       if (mul_result != xxs) {
1036         cout << "*** FAILED ***" << endl;
1037         return_code |= ERR_STRUCTS;
1038       }
1039     } catch (TTransportException&) {
1040       throw;
1041     } catch (exception& ex) {
1042       cout << "*** FAILED ***" << endl << ex.what() << endl;
1043       return_code |= ERR_STRUCTS;
1044     }
1045 
1046     /* test exception */
1047 
1048     try {
1049       cout << "testClient.testException(\"Xception\") =>" << flush;
1050       testClient.testException("Xception");
1051       cout << "  void\n*** FAILED ***" << endl;
1052       return_code |= ERR_EXCEPTIONS;
1053 
1054     } catch (Xception& e) {
1055       printf("  {%u, \"%s\"}\n", e.errorCode, e.message.c_str());
1056     }
1057 
1058     try {
1059       cout << "testClient.testException(\"TException\") =>" << flush;
1060       testClient.testException("TException");
1061       cout << "  void\n*** FAILED ***" << endl;
1062       return_code |= ERR_EXCEPTIONS;
1063 
1064     } catch (const TException&) {
1065       cout << "  Caught TException" << endl;
1066     }
1067 
1068     try {
1069       cout << "testClient.testException(\"success\") =>" << flush;
1070       testClient.testException("success");
1071       cout << "  void" << endl;
1072     } catch (exception & ex) {                                                                       \
1073       cout << "*** FAILED ***" << endl << ex.what() << endl;
1074       return_code |= ERR_EXCEPTIONS;
1075     }
1076 
1077     /* test multi exception */
1078 
1079     try {
1080       cout << "testClient.testMultiException(\"Xception\", \"test 1\") =>" << flush;
1081       Xtruct result;
1082       testClient.testMultiException(result, "Xception", "test 1");
1083       cout << "  result\n*** FAILED ***" << endl;
1084       return_code |= ERR_EXCEPTIONS;
1085     } catch (Xception& e) {
1086       printf("  {%u, \"%s\"}\n", e.errorCode, e.message.c_str());
1087     }
1088 
1089     try {
1090       cout << "testClient.testMultiException(\"Xception2\", \"test 2\") =>" << flush;
1091       Xtruct result;
1092       testClient.testMultiException(result, "Xception2", "test 2");
1093       cout << "  result\n*** FAILED ***" << endl;
1094       return_code |= ERR_EXCEPTIONS;
1095 
1096     } catch (Xception2& e) {
1097       printf("  {%u, {\"%s\"}}\n", e.errorCode, e.struct_thing.string_thing.c_str());
1098     }
1099 
1100     try {
1101       cout << "testClient.testMultiException(\"success\", \"test 3\") =>" << flush;
1102       Xtruct result;
1103       testClient.testMultiException(result, "success", "test 3");
1104       printf("  {{\"%s\"}}\n", result.string_thing.c_str());
1105     } catch (exception & ex) {                                                                       \
1106       cout << "*** FAILED ***" << endl << ex.what() << endl;
1107       return_code |= ERR_EXCEPTIONS;
1108     }
1109 
1110     /* test oneway void */
1111     {
1112       cout << "testClient.testOneway(1) =>" << flush;
1113       uint64_t startOneway = now();
1114       testClient.testOneway(1);
1115       uint64_t elapsed = now() - startOneway;
1116       if (elapsed > 200 * 1000) { // 0.2 seconds
1117         printf("*** FAILED *** - took %.2f ms\n", (double)elapsed / 1000.0);
1118       return_code |= ERR_BASETYPES;
1119       } else {
1120         printf("  success - took %.2f ms\n", (double)elapsed / 1000.0);
1121       }
1122     }
1123 
1124     /**
1125      * redo a simple test after the oneway to make sure we aren't "off by one" --
1126      * if the server treated oneway void like normal void, this next test will
1127      * fail since it will get the void confirmation rather than the correct
1128      * result. In this circumstance, the client will throw the exception:
1129      *
1130      *   TApplicationException: Wrong method namea
1131      */
1132     /**
1133      * I32 TEST
1134      */
1135     cout << "re-test testI32(-1)" << flush;
1136     int i32 = testClient.testI32(-1);
1137     cout << " = " << i32 << endl;
1138     if (i32 != -1)
1139       return_code |= ERR_BASETYPES;
1140 
1141     cout << endl << "All tests done." << endl << flush;
1142 
1143     uint64_t stop = now();
1144     uint64_t tot = stop - start;
1145 
1146     cout << "Total time: " << stop - start << " us" << endl;
1147 
1148     time_tot += tot;
1149     if (time_min == 0 || tot < time_min) {
1150       time_min = tot;
1151     }
1152     if (tot > time_max) {
1153       time_max = tot;
1154     }
1155 
1156     cout << flush;
1157     transport->close();
1158   }
1159 
1160 
1161   uint64_t time_avg = time_tot / numTests;
1162 
1163   cout << "Min time: " << time_min << " us" << endl;
1164   cout << "Max time: " << time_max << " us" << endl;
1165   cout << "Avg time: " << time_avg << " us" << endl;
1166 
1167   return return_code;
1168 }
1169 
binary_fill(std::string & str,string::size_type siz)1170 void binary_fill(std::string& str, string::size_type siz)
1171 {
1172     static const signed char bin_data[256]
1173         = {-128, -127, -126, -125, -124, -123, -122, -121, -120, -119, -118, -117, -116, -115, -114,
1174            -113, -112, -111, -110, -109, -108, -107, -106, -105, -104, -103, -102, -101, -100, -99,
1175            -98,  -97,  -96,  -95,  -94,  -93,  -92,  -91,  -90,  -89,  -88,  -87,  -86,  -85,  -84,
1176            -83,  -82,  -81,  -80,  -79,  -78,  -77,  -76,  -75,  -74,  -73,  -72,  -71,  -70,  -69,
1177            -68,  -67,  -66,  -65,  -64,  -63,  -62,  -61,  -60,  -59,  -58,  -57,  -56,  -55,  -54,
1178            -53,  -52,  -51,  -50,  -49,  -48,  -47,  -46,  -45,  -44,  -43,  -42,  -41,  -40,  -39,
1179            -38,  -37,  -36,  -35,  -34,  -33,  -32,  -31,  -30,  -29,  -28,  -27,  -26,  -25,  -24,
1180            -23,  -22,  -21,  -20,  -19,  -18,  -17,  -16,  -15,  -14,  -13,  -12,  -11,  -10,  -9,
1181            -8,   -7,   -6,   -5,   -4,   -3,   -2,   -1,   0,    1,    2,    3,    4,    5,    6,
1182            7,    8,    9,    10,   11,   12,   13,   14,   15,   16,   17,   18,   19,   20,   21,
1183            22,   23,   24,   25,   26,   27,   28,   29,   30,   31,   32,   33,   34,   35,   36,
1184            37,   38,   39,   40,   41,   42,   43,   44,   45,   46,   47,   48,   49,   50,   51,
1185            52,   53,   54,   55,   56,   57,   58,   59,   60,   61,   62,   63,   64,   65,   66,
1186            67,   68,   69,   70,   71,   72,   73,   74,   75,   76,   77,   78,   79,   80,   81,
1187            82,   83,   84,   85,   86,   87,   88,   89,   90,   91,   92,   93,   94,   95,   96,
1188            97,   98,   99,   100,  101,  102,  103,  104,  105,  106,  107,  108,  109,  110,  111,
1189            112,  113,  114,  115,  116,  117,  118,  119,  120,  121,  122,  123,  124,  125,  126,
1190            127};
1191 
1192     str.resize(siz);
1193     char *ptr = &str[0];
1194     string::size_type pos = 0;
1195     for (string::size_type i = 0; i < siz; ++i)
1196     {
1197         if (pos == 255) { pos = 0; } else { ++pos; }
1198         *ptr++ = bin_data[pos];
1199     }
1200 }
1201 
binary_test(ThriftTestClient & testClient,string::size_type siz)1202 int binary_test(ThriftTestClient& testClient, string::size_type siz)
1203 {
1204     string bin_request;
1205     string bin_result;
1206 
1207     cout << "testBinary(siz = " << siz << ")" << endl;
1208     binary_fill(bin_request, siz);
1209     try {
1210         testClient.testBinary(bin_result, bin_request);
1211 
1212         if (bin_request.size() != bin_result.size()) {
1213             cout << "*** FAILED: request size " << bin_request.size() << "; result size " << bin_result.size() << endl;
1214             return ERR_BASETYPES;
1215         }
1216 
1217         for (string::size_type i = 0; i < siz; ++i) {
1218             if (bin_request.at(i) != bin_result.at(i)) {
1219                 cout << "*** FAILED: at position " << i << " request[i] is h" << hex << bin_request.at(i) << " result[i] is h" << hex << bin_result.at(i) << endl;
1220                 return ERR_BASETYPES;
1221             }
1222         }
1223     } catch (TTransportException&) {
1224         throw;
1225     } catch (exception& ex) {
1226         cout << "*** FAILED ***" << endl << ex.what() << endl;
1227         return ERR_BASETYPES;
1228     }
1229 
1230     return 0;
1231 }
1232