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  * Contains some contributions under the Thrift Software License.
20  * Please see doc/old-thrift-license.txt in the Thrift distribution for
21  * details.
22  */
23 
24 #include <map>
25 #include <thrift/protocol/TDebugProtocol.h>
26 #include <thrift/protocol/TBinaryProtocol.h>
27 #include <thrift/transport/TBufferTransports.h>
28 #include "gen-cpp/OptionalRequiredTest_types.h"
29 
30 #define BOOST_TEST_MODULE OptionalRequiredTest
31 #include <boost/test/unit_test.hpp>
32 
33 using namespace thrift::test;
34 using namespace apache::thrift;
35 using namespace apache::thrift::transport;
36 using namespace apache::thrift::protocol;
37 
38 /*
39 template<typename Struct>
40 void trywrite(const Struct& s, bool should_work) {
41   bool worked;
42   try {
43     TBinaryProtocol protocol(std::shared_ptr<TTransport>(new TMemoryBuffer));
44     s.write(&protocol);
45     worked = true;
46   } catch (TProtocolException & ex) {
47     worked = false;
48   }
49   BOOST_CHECK(worked == should_work);
50 }
51 */
52 
53 template <typename Struct1, typename Struct2>
write_to_read(const Struct1 & w,Struct2 & r)54 void write_to_read(const Struct1& w, Struct2& r) {
55   TBinaryProtocol protocol(std::shared_ptr<TTransport>(new TMemoryBuffer));
56   w.write(&protocol);
57   r.read(&protocol);
58 }
59 
BOOST_AUTO_TEST_CASE(test_optional_required_1)60 BOOST_AUTO_TEST_CASE(test_optional_required_1) {
61   OldSchool o;
62 
63   const std::string expected_result(
64     "OldSchool {\n"
65     "  01: im_int (i16) = 0,\n"
66     "  02: im_str (string) = \"\",\n"
67     "  03: im_big (list) = list<map>[0] {\n"
68     "  },\n"
69     "}");
70   const std::string result(apache::thrift::ThriftDebugString(o));
71 
72   BOOST_CHECK_MESSAGE(!expected_result.compare(result),
73     "Expected:\n" << expected_result << "\nGotten:\n" << result);
74 }
75 
BOOST_AUTO_TEST_CASE(test_optional_required_2_1)76 BOOST_AUTO_TEST_CASE(test_optional_required_2_1) {
77   Simple s;
78 
79   const std::string expected_result(
80     "Simple {\n"
81     "  01: im_default (i16) = 0,\n"
82     "  02: im_required (i16) = 0,\n"
83     "}");
84   const std::string result(apache::thrift::ThriftDebugString(s));
85 
86   BOOST_CHECK_MESSAGE(!expected_result.compare(result),
87     "Expected:\n" << expected_result << "\nGotten:\n" << result);
88 }
89 
BOOST_AUTO_TEST_CASE(test_optional_required_2_2)90 BOOST_AUTO_TEST_CASE(test_optional_required_2_2) {
91   Simple s;
92   s.im_optional = 10;
93 
94   const std::string expected_result(
95     "Simple {\n"
96     "  01: im_default (i16) = 0,\n"
97     "  02: im_required (i16) = 0,\n"
98     "}");
99   const std::string result(apache::thrift::ThriftDebugString(s));
100 
101   BOOST_CHECK_MESSAGE(!expected_result.compare(result),
102     "Expected:\n" << expected_result << "\nGotten:\n" << result);
103 }
104 
BOOST_AUTO_TEST_CASE(test_optional_required_2_3)105 BOOST_AUTO_TEST_CASE(test_optional_required_2_3) {
106   Simple s;
107   s.im_optional = 10;
108   s.__isset.im_optional = true;
109 
110   const std::string expected_result(
111     "Simple {\n"
112     "  01: im_default (i16) = 0,\n"
113     "  02: im_required (i16) = 0,\n"
114     "  03: im_optional (i16) = 10,\n"
115     "}");
116   const std::string result(apache::thrift::ThriftDebugString(s));
117 
118   BOOST_CHECK_MESSAGE(!expected_result.compare(result),
119     "Expected:\n" << expected_result << "\nGotten:\n" << result);
120 }
121 
BOOST_AUTO_TEST_CASE(test_optional_required_2_4)122 BOOST_AUTO_TEST_CASE(test_optional_required_2_4) {
123   Simple s;
124   s.__isset.im_optional = true;
125 
126   const std::string expected_result(
127     "Simple {\n"
128     "  01: im_default (i16) = 0,\n"
129     "  02: im_required (i16) = 0,\n"
130     "  03: im_optional (i16) = 0,\n"
131     "}");
132   const std::string result(apache::thrift::ThriftDebugString(s));
133 
134   BOOST_CHECK_MESSAGE(!expected_result.compare(result),
135     "Expected:\n" << expected_result << "\nGotten:\n" << result);
136 }
137 
BOOST_AUTO_TEST_CASE(test_optional_required_2_5)138 BOOST_AUTO_TEST_CASE(test_optional_required_2_5) {
139   Simple s;
140   s.__isset.im_optional = true;
141   s.im_optional = 10;
142 
143   const std::string expected_result(
144     "Simple {\n"
145     "  01: im_default (i16) = 0,\n"
146     "  02: im_required (i16) = 0,\n"
147     "  03: im_optional (i16) = 10,\n"
148     "}");
149   const std::string result(apache::thrift::ThriftDebugString(s));
150 
151   BOOST_CHECK_MESSAGE(!expected_result.compare(result),
152     "Expected:\n" << expected_result << "\nGotten:\n" << result);
153 }
154 
BOOST_AUTO_TEST_CASE(test_optional_required_3)155 BOOST_AUTO_TEST_CASE(test_optional_required_3) {
156   // assign/copy-construct with non-required fields
157 
158   Simple s1, s2;
159   s1.__isset.im_default = true;
160   s1.__set_im_optional(10);
161   BOOST_CHECK(s1.__isset.im_default);
162   BOOST_CHECK(s1.__isset.im_optional);
163 
164   s2 = s1;
165 
166   BOOST_CHECK(s2.__isset.im_default);
167   BOOST_CHECK(s2.__isset.im_optional);
168 
169   Simple s3(s1);
170 
171   BOOST_CHECK(s3.__isset.im_default);
172   BOOST_CHECK(s3.__isset.im_optional);
173 }
174 
BOOST_AUTO_TEST_CASE(test_optional_required_4)175 BOOST_AUTO_TEST_CASE(test_optional_required_4) {
176   // Write-to-read with optional fields.
177 
178   Simple s1, s2, s3;
179   s1.im_optional = 10;
180   BOOST_CHECK(!s1.__isset.im_default);
181   // BOOST_CHECK(!s1.__isset.im_required);  // Compile error.
182   BOOST_CHECK(!s1.__isset.im_optional);
183 
184   write_to_read(s1, s2);
185 
186   BOOST_CHECK(s2.__isset.im_default);
187   // BOOST_CHECK( s2.__isset.im_required);  // Compile error.
188   BOOST_CHECK(!s2.__isset.im_optional);
189   BOOST_CHECK(s3.im_optional == 0);
190 
191   s1.__isset.im_optional = true;
192   write_to_read(s1, s3);
193 
194   BOOST_CHECK(s3.__isset.im_default);
195   // BOOST_CHECK( s3.__isset.im_required);  // Compile error.
196   BOOST_CHECK(s3.__isset.im_optional);
197   BOOST_CHECK(s3.im_optional == 10);
198 }
199 
BOOST_AUTO_TEST_CASE(test_optional_required_5)200 BOOST_AUTO_TEST_CASE(test_optional_required_5) {
201   // Writing between optional and default.
202 
203   Tricky1 t1;
204   Tricky2 t2;
205 
206   t2.im_optional = 10;
207   write_to_read(t2, t1);
208   write_to_read(t1, t2);
209   BOOST_CHECK(!t1.__isset.im_default);
210   BOOST_CHECK(t2.__isset.im_optional);
211   BOOST_CHECK(t1.im_default == t2.im_optional);
212   BOOST_CHECK(t1.im_default == 0);
213 }
214 
BOOST_AUTO_TEST_CASE(test_optional_required_6)215 BOOST_AUTO_TEST_CASE(test_optional_required_6) {
216   // Writing between default and required.
217 
218   Tricky1 t1;
219   Tricky3 t3;
220   write_to_read(t1, t3);
221   write_to_read(t3, t1);
222   BOOST_CHECK(t1.__isset.im_default);
223 }
224 
BOOST_AUTO_TEST_CASE(test_optional_required_7)225 BOOST_AUTO_TEST_CASE(test_optional_required_7) {
226   // Writing between optional and required.
227 
228   Tricky2 t2;
229   Tricky3 t3;
230   t2.__isset.im_optional = true;
231   write_to_read(t2, t3);
232   write_to_read(t3, t2);
233 }
234 
BOOST_AUTO_TEST_CASE(test_optional_required_8)235 BOOST_AUTO_TEST_CASE(test_optional_required_8) {
236   // Mu-hu-ha-ha-ha!
237 
238   Tricky2 t2;
239   Tricky3 t3;
240   try {
241     write_to_read(t2, t3);
242     abort();
243   } catch (const TProtocolException&) {
244   }
245 
246   write_to_read(t3, t2);
247   BOOST_CHECK(t2.__isset.im_optional);
248 }
249 
BOOST_AUTO_TEST_CASE(test_optional_required_9)250 BOOST_AUTO_TEST_CASE(test_optional_required_9) {
251   Complex c;
252 
253   const std::string expected_result(
254     "Complex {\n"
255     "  01: cp_default (i16) = 0,\n"
256     "  02: cp_required (i16) = 0,\n"
257     "  04: the_map (map) = map<i16,struct>[0] {\n"
258     "  },\n"
259     "  05: req_simp (struct) = Simple {\n"
260     "    01: im_default (i16) = 0,\n"
261     "    02: im_required (i16) = 0,\n"
262     "  },\n"
263     "}");
264   const std::string result(apache::thrift::ThriftDebugString(c));
265 
266   BOOST_CHECK_MESSAGE(!expected_result.compare(result),
267     "Expected:\n" << expected_result << "\nGotten:\n" << result);
268 }
269 
BOOST_AUTO_TEST_CASE(test_optional_required_10)270 BOOST_AUTO_TEST_CASE(test_optional_required_10) {
271   Tricky1 t1;
272   Tricky2 t2;
273   // Compile error.
274   //(void)(t1 == t2);
275 }
276 
BOOST_AUTO_TEST_CASE(test_optional_required_11)277 BOOST_AUTO_TEST_CASE(test_optional_required_11) {
278   OldSchool o1, o2, o3;
279   BOOST_CHECK(o1 == o2);
280   o1.im_int = o2.im_int = 10;
281   BOOST_CHECK(o1 == o2);
282   o1.__isset.im_int = true;
283   o2.__isset.im_int = false;
284   BOOST_CHECK(o1 == o2);
285   o1.im_int = 20;
286   o1.__isset.im_int = false;
287   BOOST_CHECK(o1 != o2);
288   o1.im_int = 10;
289   BOOST_CHECK(o1 == o2);
290   o1.im_str = o2.im_str = "foo";
291   BOOST_CHECK(o1 == o2);
292   o1.__isset.im_str = o2.__isset.im_str = true;
293   BOOST_CHECK(o1 == o2);
294   std::map<int32_t, std::string> mymap;
295   mymap[1] = "bar";
296   mymap[2] = "baz";
297   o1.im_big.push_back(std::map<int32_t, std::string>());
298   BOOST_CHECK(o1 != o2);
299   o2.im_big.push_back(std::map<int32_t, std::string>());
300   BOOST_CHECK(o1 == o2);
301   o2.im_big.push_back(mymap);
302   BOOST_CHECK(o1 != o2);
303   o1.im_big.push_back(mymap);
304   BOOST_CHECK(o1 == o2);
305 
306   TBinaryProtocol protocol(std::shared_ptr<TTransport>(new TMemoryBuffer));
307   o1.write(&protocol);
308 
309   o1.im_big.push_back(mymap);
310   mymap[3] = "qux";
311   o2.im_big.push_back(mymap);
312   BOOST_CHECK(o1 != o2);
313   o1.im_big.back()[3] = "qux";
314   BOOST_CHECK(o1 == o2);
315 
316   o3.read(&protocol);
317   o3.im_big.push_back(mymap);
318   BOOST_CHECK(o1 == o3);
319 
320   const std::string expected_result(
321     "OldSchool {\n"
322     "  01: im_int (i16) = 10,\n"
323     "  02: im_str (string) = \"foo\",\n"
324     "  03: im_big (list) = list<map>[3] {\n"
325     "    [0] = map<i32,string>[0] {\n"
326     "    },\n"
327     "    [1] = map<i32,string>[2] {\n"
328     "      1 -> \"bar\",\n"
329     "      2 -> \"baz\",\n"
330     "    },\n"
331     "    [2] = map<i32,string>[3] {\n"
332     "      1 -> \"bar\",\n"
333     "      2 -> \"baz\",\n"
334     "      3 -> \"qux\",\n"
335     "    },\n"
336     "  },\n"
337     "}");
338   const std::string result(apache::thrift::ThriftDebugString(o3));
339 
340   BOOST_CHECK_MESSAGE(!expected_result.compare(result),
341     "Expected:\n" << expected_result << "\nGotten:\n" << result);
342 }
343 
BOOST_AUTO_TEST_CASE(test_optional_required_12)344 BOOST_AUTO_TEST_CASE(test_optional_required_12) {
345   Tricky2 t1, t2;
346   BOOST_CHECK(t1.__isset.im_optional == false);
347   BOOST_CHECK(t2.__isset.im_optional == false);
348   BOOST_CHECK(t1 == t2);
349   t1.im_optional = 5;
350   BOOST_CHECK(t1 == t2);
351   t2.im_optional = 5;
352   BOOST_CHECK(t1 == t2);
353   t1.__isset.im_optional = true;
354   BOOST_CHECK(t1 != t2);
355   t2.__isset.im_optional = true;
356   BOOST_CHECK(t1 == t2);
357   t1.im_optional = 10;
358   BOOST_CHECK(t1 != t2);
359   t2.__isset.im_optional = false;
360   BOOST_CHECK(t1 != t2);
361 }
362 
BOOST_AUTO_TEST_CASE(test_optional_required_13)363 BOOST_AUTO_TEST_CASE(test_optional_required_13) {
364   OptionalDefault t1, t2;
365 
366   BOOST_CHECK(t1.__isset.opt_int == true);
367   BOOST_CHECK(t1.__isset.opt_str == true);
368   BOOST_CHECK(t1.opt_int == t2.opt_int);
369   BOOST_CHECK(t1.opt_str == t2.opt_str);
370 
371   write_to_read(t1, t2);
372   BOOST_CHECK(t2.__isset.opt_int == true);
373   BOOST_CHECK(t2.__isset.opt_str == true);
374   BOOST_CHECK(t1.opt_int == t2.opt_int);
375   BOOST_CHECK(t1.opt_str == t2.opt_str);
376 
377   const std::string expected_result(
378     "OptionalDefault {\n"
379     "  01: opt_int (i16) = 1234,\n"
380     "  02: opt_str (string) = \"default\",\n"
381     "}");
382   const std::string result(apache::thrift::ThriftDebugString(t2));
383 
384   BOOST_CHECK_MESSAGE(!expected_result.compare(result),
385     "Expected:\n" << expected_result << "\nGotten:\n" << result);
386 }
387