1 /*
2  * Copyright (c) Facebook, Inc. and its affiliates.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <thrift/test/reflection/gen-cpp2/simple_reflection_fatal_types.h>
18 #include <thrift/test/reflection/gen-cpp2/simple_reflection_types_custom_protocol.h>
19 
20 #include <thrift/test/reflection/gen-cpp2/service_reflection_fatal_types.h>
21 #include <thrift/test/reflection/gen-cpp2/service_reflection_types_custom_protocol.h>
22 
23 #include <thrift/lib/cpp2/reflection/internal/test_helpers.h>
24 #include <thrift/lib/cpp2/reflection/pretty_print.h>
25 #include <thrift/lib/cpp2/reflection/serializer.h>
26 
27 #include <folly/Memory.h>
28 
29 #include <thrift/test/reflection/fatal_serialization_common.h>
30 
31 #include <iomanip>
32 
33 using namespace apache::thrift;
34 using namespace apache::thrift::test;
35 
36 TYPED_TEST_CASE(MultiProtocolTest, protocol_type_pairs);
37 TYPED_TEST_CASE(CompareProtocolTest, protocol_type_pairs);
38 
39 // using apache::thrift::serializer_read;
40 // using apache::thrift::serializer_write;
41 // using apache::thrift::serializer_serialized_size;
42 // using apache::thrift::serializer_serialized_size_zc;
43 
44 template <typename Type, typename Protocol>
expect_same_serialized_size(Type & type,Protocol & protocol)45 void expect_same_serialized_size(Type& type, Protocol& protocol) {
46   EXPECT_EQ(
47       Cpp2Ops<Type>::serializedSize(&protocol, &type),
48       serializer_serialized_size(type, protocol));
49   EXPECT_EQ(
50       Cpp2Ops<Type>::serializedSizeZC(&protocol, &type),
51       serializer_serialized_size_zc(type, protocol));
52 }
53 
54 // simply tests if we can compile the structs related to services
55 namespace service_reflection {
56 namespace cpp2 {
TYPED_TEST(MultiProtocolTest,service_reflection_test)57 TYPED_TEST(MultiProtocolTest, service_reflection_test) {
58   struct1 a;
59   serializer_write(a, this->writer);
60   this->prep_read();
61   this->debug_buffer();
62 
63   struct1 b;
64   serializer_read(b, this->reader);
65   EXPECT_EQ(a, b);
66   expect_same_serialized_size(a, this->writer);
67 }
68 } // namespace cpp2
69 } // namespace service_reflection
70 
71 namespace test_cpp2 {
72 namespace simple_cpp_reflection {
73 
init_struct_1(struct1 & a)74 void init_struct_1(struct1& a) {
75   *a.field0_ref() = 10;
76   a.field1_ref() = "this is a string";
77   a.field2_ref() = enum1::field1;
78   *a.field3_ref() = {{1, 2, 3}, {4, 5, 6, 7}};
79   *a.field4_ref() = {1, 1, 2, 3, 4, 10, 4, 6};
80   *a.field5_ref() = {{42, "<answer>"}, {55, "schwifty five"}};
81   a.field6_ref()->nfield00_ref() = 5.678;
82   a.field6_ref()->nfield01_ref() = 0x42;
83   *a.field7_ref() = 0xCAFEBABEA4DAFACE;
84   *a.field8_ref() = "this field isn't set";
85 
86   *a.field10_ref() = {true, false, true, false, false, true, true};
87 
88   apache::thrift::ensure_isset_unsafe(a.field1_ref());
89   apache::thrift::ensure_isset_unsafe(a.field2_ref());
90   apache::thrift::ensure_isset_unsafe(a.field6_ref()->nfield00_ref());
91   apache::thrift::ensure_isset_unsafe(a.field6_ref()->nfield01_ref());
92   a.field7_ref().ensure();
93 }
94 
TYPED_TEST(MultiProtocolTest,test_serialization)95 TYPED_TEST(MultiProtocolTest, test_serialization) {
96   // test/reflection.thrift
97   struct1 a, b;
98   init_struct_1(a);
99 
100   EXPECT_EQ(*a.field4_ref(), (std::set<int32_t>{1, 2, 3, 4, 6, 10}));
101 
102   serializer_write(a, this->writer);
103   this->prep_read();
104 
105   serializer_read(b, this->reader);
106 
107   EXPECT_EQ(*a.field0_ref(), *b.field0_ref());
108   EXPECT_EQ(a.field1_ref(), b.field1_ref());
109   EXPECT_EQ(a.field2_ref(), b.field2_ref());
110   EXPECT_EQ(*a.field3_ref(), *b.field3_ref());
111   EXPECT_EQ(*a.field4_ref(), *b.field4_ref());
112   EXPECT_EQ(*a.field5_ref(), *b.field5_ref());
113 
114   EXPECT_EQ(a.field6_ref()->nfield00_ref(), b.field6_ref()->nfield00_ref());
115   EXPECT_EQ(a.field6_ref()->nfield01_ref(), b.field6_ref()->nfield01_ref());
116   EXPECT_EQ(*a.field6_ref(), *b.field6_ref());
117   EXPECT_EQ(*a.field7_ref(), *b.field7_ref());
118   EXPECT_EQ(
119       *a.field8_ref(),
120       *b.field8_ref()); // default fields are always written out
121   EXPECT_EQ(*a.field10_ref(), *b.field10_ref());
122 
123   EXPECT_TRUE(b.field1_ref().has_value());
124   EXPECT_TRUE(b.field2_ref().has_value());
125   EXPECT_TRUE(b.field7_ref().has_value());
126   EXPECT_TRUE(b.field8_ref().has_value());
127 }
128 
TYPED_TEST(MultiProtocolTest,test_legacy_serialization)129 TYPED_TEST(MultiProtocolTest, test_legacy_serialization) {
130   // test/reflection.thrift
131   struct1 a;
132   init_struct_1(a);
133 
134   serializer_write(a, this->writer);
135   this->prep_read();
136 
137   struct1 b;
138   b.read(&this->reader);
139 
140   EXPECT_EQ(*a.field0_ref(), *b.field0_ref());
141   EXPECT_EQ(a.field1_ref(), b.field1_ref());
142   EXPECT_EQ(a.field2_ref(), b.field2_ref());
143   EXPECT_EQ(*a.field3_ref(), *b.field3_ref());
144   EXPECT_EQ(*a.field4_ref(), *b.field4_ref());
145   EXPECT_EQ(*a.field5_ref(), *b.field5_ref());
146 
147   EXPECT_EQ(a.field6_ref()->nfield00_ref(), b.field6_ref()->nfield00_ref());
148   EXPECT_EQ(a.field6_ref()->nfield01_ref(), b.field6_ref()->nfield01_ref());
149   EXPECT_EQ(*a.field6_ref(), *b.field6_ref());
150   EXPECT_EQ(*a.field7_ref(), *b.field7_ref());
151   EXPECT_EQ(
152       *a.field8_ref(),
153       *b.field8_ref()); // default fields are always written out
154 
155   EXPECT_TRUE(b.field1_ref().has_value());
156   EXPECT_TRUE(b.field2_ref().has_value());
157   EXPECT_TRUE(b.field7_ref().has_value());
158   EXPECT_TRUE(b.field8_ref().has_value());
159 }
160 
TYPED_TEST(MultiProtocolTest,test_other_containers)161 TYPED_TEST(MultiProtocolTest, test_other_containers) {
162   struct4 a, b;
163 
164   *a.um_field_ref() = {{42, "answer"}, {5, "five"}};
165   *a.us_field_ref() = {7, 11, 13, 17, 13, 19, 11};
166   *a.deq_field_ref() = {10, 20, 30, 40};
167 
168   serializer_write(a, this->writer);
169   this->prep_read();
170   serializer_read(b, this->reader);
171 
172   EXPECT_TRUE(b.um_field_ref().has_value());
173   EXPECT_TRUE(b.us_field_ref().has_value());
174   EXPECT_TRUE(b.deq_field_ref().has_value());
175   EXPECT_EQ(*a.um_field_ref(), *b.um_field_ref());
176   EXPECT_EQ(*a.us_field_ref(), *b.us_field_ref());
177   EXPECT_EQ(*a.deq_field_ref(), *b.deq_field_ref());
178   expect_same_serialized_size(a, this->writer);
179 }
180 
TYPED_TEST(MultiProtocolTest,test_blank_default_ref_field)181 TYPED_TEST(MultiProtocolTest, test_blank_default_ref_field) {
182   struct3 a, b;
183   a.opt_nested_ref() = std::make_unique<smallstruct>();
184   a.req_nested_ref() = std::make_unique<smallstruct>();
185 
186   *a.opt_nested_ref()->f1_ref() = 5;
187   *a.req_nested_ref()->f1_ref() = 10;
188 
189   // ref fields, interesting enough, do not have an __isset,
190   // but are xfered based on the pointer value (nullptr or not)
191 
192   serializer_write(a, this->writer);
193   this->prep_read();
194   this->debug_buffer();
195   serializer_read(b, this->reader);
196 
197   EXPECT_EQ(smallstruct(), *(b.def_nested_ref()));
198   EXPECT_EQ(*(a.opt_nested_ref()), *(b.opt_nested_ref()));
199   EXPECT_EQ(*(a.req_nested_ref()), *(b.req_nested_ref()));
200   expect_same_serialized_size(a, this->writer);
201 }
202 
TYPED_TEST(MultiProtocolTest,test_blank_optional_ref_field)203 TYPED_TEST(MultiProtocolTest, test_blank_optional_ref_field) {
204   struct3 a, b;
205   a.def_nested_ref() = std::make_unique<smallstruct>();
206   a.req_nested_ref() = std::make_unique<smallstruct>();
207 
208   *a.def_nested_ref()->f1_ref() = 5;
209   *a.req_nested_ref()->f1_ref() = 10;
210 
211   serializer_write(a, this->writer);
212   this->prep_read();
213   this->debug_buffer();
214   serializer_read(b, this->reader);
215 
216   // null optional fields are deserialized to nullptr
217   EXPECT_EQ(*(a.def_nested_ref()), *(b.def_nested_ref()));
218   EXPECT_EQ(nullptr, b.opt_nested_ref().get());
219   EXPECT_EQ(*(a.req_nested_ref()), *(b.req_nested_ref()));
220   expect_same_serialized_size(a, this->writer);
221 }
222 
TYPED_TEST(MultiProtocolTest,test_blank_required_ref_field)223 TYPED_TEST(MultiProtocolTest, test_blank_required_ref_field) {
224   struct3 a, b;
225   a.def_nested_ref() = std::make_unique<smallstruct>();
226   a.opt_nested_ref() = std::make_unique<smallstruct>();
227 
228   *a.def_nested_ref()->f1_ref() = 5;
229   *a.opt_nested_ref()->f1_ref() = 10;
230 
231   serializer_write(a, this->writer);
232   this->prep_read();
233   this->debug_buffer();
234   serializer_read(b, this->reader);
235 
236   EXPECT_EQ(*(a.def_nested_ref()), *(b.def_nested_ref()));
237   EXPECT_EQ(*(a.opt_nested_ref()), *(b.opt_nested_ref()));
238   EXPECT_EQ(smallstruct(), *(b.req_nested_ref()));
239   expect_same_serialized_size(a, this->writer);
240 }
241 
TYPED_TEST(MultiProtocolTest,test_blank_optional_boxed_field)242 TYPED_TEST(MultiProtocolTest, test_blank_optional_boxed_field) {
243   struct3 a, b;
244   a.box_nested1_ref().ensure().f1_ref() = 5;
245 
246   serializer_write(a, this->writer);
247   this->prep_read();
248   this->debug_buffer();
249   serializer_read(b, this->reader);
250 
251   EXPECT_EQ(*a.box_nested1_ref(), *b.box_nested1_ref());
252   EXPECT_FALSE(a.box_nested2_ref().has_value());
253   EXPECT_FALSE(b.box_nested2_ref().has_value());
254   expect_same_serialized_size(a, this->writer);
255 }
256 
TYPED_TEST(MultiProtocolTest,test_empty_containers)257 TYPED_TEST(MultiProtocolTest, test_empty_containers) {
258   struct1 a, b;
259   serializer_write(a, this->writer);
260   this->prep_read();
261   this->debug_buffer();
262   serializer_read(b, this->reader);
263 
264   EXPECT_EQ(a, b);
265 }
266 
TYPED_TEST(CompareProtocolTest,test_struct_xfer)267 TYPED_TEST(CompareProtocolTest, test_struct_xfer) {
268   struct1 a1, a2, b1, b2;
269   init_struct_1(a1);
270   init_struct_1(a2);
271   const std::size_t legacy_write_xfer = a1.write(&this->st1.writer);
272   const std::size_t new_write_xfer = serializer_write(a2, this->st2.writer);
273   EXPECT_EQ(legacy_write_xfer, new_write_xfer);
274 
275   this->prep_read();
276   this->debug_buffer();
277 
278   const std::size_t legacy_read_xfer = b1.read(&this->st1.reader);
279   const std::size_t new_read_xfer = serializer_read(b2, this->st2.reader);
280 
281   EXPECT_EQ(legacy_read_xfer, new_read_xfer);
282   EXPECT_EQ(b1, b2);
283 
284   expect_same_serialized_size(a1, this->st1.writer);
285 }
286 
TYPED_TEST(CompareProtocolTest,test_larger_containers)287 TYPED_TEST(CompareProtocolTest, test_larger_containers) {
288   struct1 a1;
289   struct1 a2;
290   init_struct_1(a1);
291   init_struct_1(a2);
292 
293   std::map<int32_t, std::string> large_map;
294   for (int32_t i = 0; i < 1000; i++) {
295     large_map.emplace(i, std::string("string"));
296   }
297 
298   *a1.field5_ref() = large_map;
299   *a2.field5_ref() = large_map;
300 
301   EXPECT_EQ(a1, a2);
302   EXPECT_EQ(
303       a1.write(&this->st1.writer), serializer_write(a2, this->st2.writer));
304 
305   this->prep_read();
306   this->debug_buffer();
307 
308   struct1 b1;
309   struct1 b2;
310 
311   EXPECT_EQ(b1.read(&this->st1.reader), serializer_read(b2, this->st2.reader));
312   EXPECT_EQ(b1, b2);
313   expect_same_serialized_size(a1, this->st1.writer);
314 }
315 
TYPED_TEST(CompareProtocolTest,test_union_xfer)316 TYPED_TEST(CompareProtocolTest, test_union_xfer) {
317   union1 a1, a2, b1, b2;
318   a1.set_field_i64(0x1ABBADABAD00);
319   a2.set_field_i64(0x1ABBADABAD00);
320   const std::size_t lwx = a1.write(&this->st1.writer);
321   const std::size_t nwx = serializer_write(a2, this->st2.writer);
322   EXPECT_EQ(lwx, nwx);
323 
324   this->prep_read();
325   this->debug_buffer();
326 
327   const std::size_t lrx = b1.read(&this->st1.reader);
328   const std::size_t nrx = serializer_read(b2, this->st2.reader);
329   EXPECT_EQ(lrx, nrx);
330   EXPECT_EQ(b1, b2);
331 
332   expect_same_serialized_size(a1, this->st1.writer);
333 }
334 
335 namespace {
336 const std::array<uint8_t, 5> test_buffer{{0xBA, 0xDB, 0xEE, 0xF0, 0x42}};
337 const folly::ByteRange test_range(test_buffer.begin(), test_buffer.end());
338 const folly::StringPiece test_string(test_range);
339 
340 const std::array<uint8_t, 6> test_buffer2{{0xFA, 0xCE, 0xB0, 0x01, 0x10, 0x0C}};
341 const folly::ByteRange test_range2(test_buffer2.begin(), test_buffer2.end());
342 const folly::StringPiece test_string2(test_range2);
343 } // namespace
344 
TYPED_TEST(MultiProtocolTest,test_binary_containers)345 TYPED_TEST(MultiProtocolTest, test_binary_containers) {
346   struct5 a, b;
347 
348   *a.def_field_ref() = test_string.str();
349   *a.iobuf_field_ref() = folly::IOBuf::wrapBufferAsValue(test_range);
350   *a.iobufptr_field_ref() = folly::IOBuf::wrapBuffer(test_range2);
351 
352   serializer_write(a, this->writer);
353   this->prep_read();
354   this->debug_buffer();
355 
356   serializer_read(b, this->reader);
357 
358   EXPECT_TRUE(b.def_field_ref().has_value());
359   EXPECT_TRUE(b.iobuf_field_ref().has_value());
360   EXPECT_TRUE(b.iobufptr_field_ref().has_value());
361   EXPECT_EQ(*a.def_field_ref(), *b.def_field_ref());
362 
363   EXPECT_EQ(test_range, b.iobuf_field_ref()->coalesce());
364   EXPECT_EQ(test_range2, (*b.iobufptr_field_ref())->coalesce());
365   expect_same_serialized_size(a, this->writer);
366 }
367 
TYPED_TEST(MultiProtocolTest,test_workaround_binary)368 TYPED_TEST(MultiProtocolTest, test_workaround_binary) {
369   struct5_workaround a, b;
370   *a.def_field_ref() = test_string.str();
371   *a.iobuf_field_ref() = folly::IOBuf::wrapBufferAsValue(test_range2);
372 
373   serializer_write(a, this->writer);
374   this->prep_read();
375   serializer_read(b, this->reader);
376 
377   EXPECT_TRUE(b.def_field_ref().has_value());
378   EXPECT_TRUE(b.iobuf_field_ref().has_value());
379   EXPECT_EQ(test_string.str(), *b.def_field_ref());
380   EXPECT_EQ(test_range2, b.iobuf_field_ref()->coalesce());
381   expect_same_serialized_size(a, this->writer);
382 }
383 
TYPED_TEST(MultiProtocolTest,shared_ptr_test)384 TYPED_TEST(MultiProtocolTest, shared_ptr_test) {
385   struct6 a, b;
386   a.def_field_ref() = std::make_shared<smallstruct>();
387   a.req_field_ref() = std::make_shared<smallstruct>();
388   a.opt_field_ref() = a.req_field_ref();
389 
390   serializer_write(a, this->writer);
391   this->prep_read();
392   this->debug_buffer();
393   serializer_read(b, this->reader);
394 
395   EXPECT_EQ(a, b);
396   expect_same_serialized_size(a, this->writer);
397 }
398 
TYPED_TEST(MultiProtocolTest,shared_const_ptr_test)399 TYPED_TEST(MultiProtocolTest, shared_const_ptr_test) {
400   struct8 a, b;
401 
402   auto def_field = std::make_unique<smallstruct>();
403   *def_field->f1_ref() = 10;
404   a.def_field_ref() = std::move(def_field);
405 
406   auto opt_field = std::make_unique<smallstruct>();
407   *opt_field->f1_ref() = 20;
408   a.opt_field_ref() = std::move(opt_field);
409 
410   auto req_field = std::make_unique<smallstruct>();
411   *req_field->f1_ref() = 30;
412   a.req_field_ref() = std::move(req_field);
413 
414   serializer_write(a, this->writer);
415   this->prep_read();
416   this->debug_buffer();
417   serializer_read(b, this->reader);
418 
419   EXPECT_EQ(a, b);
420   expect_same_serialized_size(a, this->writer);
421 }
422 
423 template <typename Pair>
424 class UnionTest : public TypedTestCommon<Pair> {
425  protected:
426   union1 a, b;
427 
xfer()428   void xfer() {
429     serializer_write(this->a, this->writer);
430     this->prep_read();
431 
432     print_underlying<Pair::printable::value>(*this->underlying);
433 
434     serializer_read(b, this->reader);
435     EXPECT_EQ(this->b.getType(), this->a.getType());
436   }
437 };
438 
439 TYPED_TEST_CASE(UnionTest, protocol_type_pairs);
440 
TYPED_TEST(UnionTest,can_read_union_i64s)441 TYPED_TEST(UnionTest, can_read_union_i64s) {
442   this->a.set_field_i64(0xFACEB00CFACEDEAD);
443   this->xfer();
444   EXPECT_EQ(this->b.get_field_i64(), this->a.get_field_i64());
445   expect_same_serialized_size(this->a, this->writer);
446 }
TYPED_TEST(UnionTest,can_read_strings)447 TYPED_TEST(UnionTest, can_read_strings) {
448   this->a.set_field_string("test string? oh my!");
449   this->xfer();
450   EXPECT_EQ(this->b.get_field_string(), this->a.get_field_string());
451   expect_same_serialized_size(this->a, this->writer);
452 }
TYPED_TEST(UnionTest,can_read_refstrings)453 TYPED_TEST(UnionTest, can_read_refstrings) {
454   this->a.set_field_string_reference("also reference strings!");
455   this->xfer();
456   EXPECT_EQ(
457       *(this->b.get_field_string_reference().get()),
458       *(this->a.get_field_string_reference().get()));
459   expect_same_serialized_size(this->a, this->writer);
460 }
TYPED_TEST(UnionTest,can_read_iobufs)461 TYPED_TEST(UnionTest, can_read_iobufs) {
462   this->a.set_field_binary(test_string.str());
463   this->xfer();
464   EXPECT_EQ(test_string.str(), this->b.get_field_binary());
465   expect_same_serialized_size(this->a, this->writer);
466 }
TYPED_TEST(UnionTest,can_read_nestedstructs)467 TYPED_TEST(UnionTest, can_read_nestedstructs) {
468   smallstruct nested;
469   *nested.f1_ref() = 6;
470   this->a.set_field_smallstruct(nested);
471   this->xfer();
472   EXPECT_EQ(6, *this->b.get_field_smallstruct()->f1_ref());
473   expect_same_serialized_size(this->a, this->writer);
474 }
475 
476 template <typename Pair>
477 class BinaryInContainersTest : public TypedTestCommon<Pair> {
478  protected:
479   struct5_listworkaround a, b;
480 
xfer()481   void xfer() {
482     serializer_write(this->a, this->writer);
483     this->prep_read();
484     serializer_read(this->b, this->reader);
485   }
486 };
487 TYPED_TEST_CASE(BinaryInContainersTest, protocol_type_pairs);
488 
TYPED_TEST(BinaryInContainersTest,lists_of_binary_fields_work)489 TYPED_TEST(BinaryInContainersTest, lists_of_binary_fields_work) {
490   *this->a.binary_list_field_ref() = {test_string.str()};
491   *this->a.binary_map_field1_ref() = {
492       {5, test_string.str()},
493       {-9999, test_string2.str()},
494   };
495 
496   this->xfer();
497 
498   EXPECT_EQ(
499       std::vector<std::string>({test_string.str()}),
500       *this->b.binary_list_field_ref());
501   expect_same_serialized_size(this->a, this->writer);
502 }
503 
504 struct SimpleJsonTest : public ::testing::Test {
505   SimpleJSONProtocolReader reader;
506   std::unique_ptr<folly::IOBuf> underlying;
507 
set_inputtest_cpp2::simple_cpp_reflection::SimpleJsonTest508   void set_input(std::string&& str) {
509     underlying = folly::IOBuf::copyBuffer(str);
510     reader.setInput(underlying.get());
511 
512     if (VLOG_IS_ON(5)) {
513       auto range = underlying->coalesce();
514       VLOG(5) << "buffer: "
515               << std::string((const char*)range.data(), range.size());
516     }
517   }
518 };
519 
TEST_F(SimpleJsonTest,doesnt_throws_on_unset_required_value)520 TEST_F(SimpleJsonTest, doesnt_throws_on_unset_required_value) {
521   set_input("{}");
522   struct2 a;
523   serializer_read(a, reader);
524   EXPECT_EQ("", *a.req_string_ref());
525 }
526 
527 // wrap in quotes
528 #define Q(val) "\"" val "\""
529 // emit key/value json pair
530 #define KV(key, value) "\"" key "\":" value
531 // emit key/value json pair, where value is a string
532 #define KVS(key, value) KV(key, Q(value))
533 
TEST_F(SimpleJsonTest,handles_unset_default_member)534 TEST_F(SimpleJsonTest, handles_unset_default_member) {
535   set_input("{" KVS("req_string", "required") "}");
536   struct2 a;
537   serializer_read(a, reader);
538   EXPECT_FALSE(a.opt_string_ref().has_value()); // gcc bug?
539   EXPECT_FALSE(a.def_string_ref().has_value());
540   EXPECT_EQ("required", *a.req_string_ref());
541   EXPECT_EQ("", *a.def_string_ref());
542 }
TEST_F(SimpleJsonTest,sets_opt_members)543 TEST_F(SimpleJsonTest, sets_opt_members) {
544   set_input(
545       "{" KVS("req_string", "required") "," KVS("opt_string", "optional") "}");
546   struct2 a;
547   serializer_read(a, reader);
548   EXPECT_TRUE(a.opt_string_ref().has_value()); // gcc bug?
549   EXPECT_FALSE(a.def_string_ref().has_value());
550   EXPECT_EQ("required", *a.req_string_ref());
551   EXPECT_EQ("optional", *a.opt_string_ref());
552   EXPECT_EQ("", *a.def_string_ref());
553 }
TEST_F(SimpleJsonTest,sets_def_members)554 TEST_F(SimpleJsonTest, sets_def_members) {
555   set_input(
556       "{" KVS("req_string", "required") "," KVS("def_string", "default") "}");
557   struct2 a;
558   serializer_read(a, reader);
559   EXPECT_FALSE(a.opt_string_ref().has_value());
560   EXPECT_TRUE(a.def_string_ref().has_value());
561   EXPECT_EQ("required", *a.req_string_ref());
562   EXPECT_EQ("default", *a.def_string_ref());
563 }
TEST_F(SimpleJsonTest,doesnt_throws_on_missing_required_ref)564 TEST_F(SimpleJsonTest, doesnt_throws_on_missing_required_ref) {
565   // clang-format off
566   set_input("{"
567     KV("opt_nested", "{"
568       KV("f1", "10")
569     "}")","
570     KV("def_nested", "{"
571       KV("f1", "5")
572     "}")
573   "}");
574   // clang-format on
575 
576   struct3 a;
577 
578   serializer_read(a, reader);
579   EXPECT_EQ(0, *a.req_nested_ref()->f1_ref());
580 }
TEST_F(SimpleJsonTest,doesnt_throw_when_req_field_present)581 TEST_F(SimpleJsonTest, doesnt_throw_when_req_field_present) {
582   // clang-format off
583   set_input("{"
584     KV("opt_nested", "{"
585       KV("f1", "10")
586     "}")","
587     KV("def_nested", "{"
588       KV("f1", "5")
589     "}")","
590     KV("req_nested", "{"
591       KV("f1", "15")
592     "}")
593   "}");
594   // clang-format on
595 
596   struct3 a;
597   serializer_read(a, reader);
598   EXPECT_EQ(10, *a.opt_nested_ref()->f1_ref());
599   EXPECT_EQ(5, *a.def_nested_ref()->f1_ref());
600   EXPECT_EQ(15, *a.req_nested_ref()->f1_ref());
601 }
602 #undef KV
603 } // namespace simple_cpp_reflection
604 } // namespace test_cpp2
605