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