userver: /data/code/userver/libraries/protobuf/tests/json/value_from_json_test.cpp Source File
Loading...
Searching...
No Matches
value_from_json_test.cpp
1#include <gtest/gtest.h>
2
3#include <memory>
4#include <ostream>
5#include <string>
6
7#include <fmt/format.h>
8#include <google/protobuf/dynamic_message.h>
9#include <google/protobuf/util/json_util.h>
10
11#include <userver/formats/json/serialize.hpp>
12#include <userver/protobuf/json/convert.hpp>
13#include <userver/utest/assert_macros.hpp>
14
15#include "utils.hpp"
16
17USERVER_NAMESPACE_BEGIN
18
19namespace protobuf::json::tests {
20
21struct ValueFromJsonSuccessTestParam {
22 std::string input = {};
23 ValueMessageData expected_message = {};
24 ParseOptions options = {};
25};
26
27struct ListValueFromJsonFailureTestParam {
28 std::string input = {};
29 ParseErrorCode expected_errc = {};
30 std::string expected_path = {};
31 ParseOptions options = {};
32
33 // We want to skip some native checks because userver implementation has stricter requirements.
34 bool skip_native_check = false;
35};
36
37struct StructFromJsonFailureTestParam {
38 std::string input = {};
39 ParseErrorCode expected_errc = {};
40 std::string expected_path = {};
41 ParseOptions options = {};
42};
43
44void PrintTo(const ValueFromJsonSuccessTestParam& param, std::ostream* os) {
45 *os << fmt::format("{{ input = '{}' }}", param.input);
46}
47
48void PrintTo(const ListValueFromJsonFailureTestParam& param, std::ostream* os) {
49 *os << fmt::format("{{ input = '{}' }}", param.input);
50}
51
52void PrintTo(const StructFromJsonFailureTestParam& param, std::ostream* os) {
53 *os << fmt::format("{{ input = '{}' }}", param.input);
54}
55
56class ValueFromJsonSuccessTest : public ::testing::TestWithParam<ValueFromJsonSuccessTestParam> {};
57class ListValueFromJsonFailureTest : public ::testing::TestWithParam<ListValueFromJsonFailureTestParam> {};
58class StructFromJsonFailureTest : public ::testing::TestWithParam<StructFromJsonFailureTestParam> {};
59
60INSTANTIATE_TEST_SUITE_P(
61 ,
62 ValueFromJsonSuccessTest,
63 ::
64 testing::
65 Values(
66 ValueFromJsonSuccessTestParam{R"({})", ValueMessageData{}},
67 ValueFromJsonSuccessTestParam{R"({"field1":null})", ValueMessageData{ProtoValue{kProtoNullValue}}},
68 ValueFromJsonSuccessTestParam{
69 R"({"field1":{}})",
70 ValueMessageData{ProtoValue{std::map<std::string, std::string>{}}}
71 },
72 ValueFromJsonSuccessTestParam{R"({"field1":[]})", ValueMessageData{ProtoValue{std::vector<double>{}}}},
73 ValueFromJsonSuccessTestParam{R"({"field1":1.5})", ValueMessageData{ProtoValue{1.5}}},
74 ValueFromJsonSuccessTestParam{R"({"field1":"hello"})", ValueMessageData{ProtoValue{"hello"}}},
75 ValueFromJsonSuccessTestParam{R"({"field1":true})", ValueMessageData{ProtoValue{true}}},
76 ValueFromJsonSuccessTestParam{
77 R"({"field1":[1.5, 1.5]})",
78 ValueMessageData{ProtoValue{std::vector<double>{1.5, 1.5}}}
79 },
80 ValueFromJsonSuccessTestParam{
81 R"({"field1":{"aaa":"hello","bbb":"world"}})",
82 ValueMessageData{ProtoValue{std::map<std::string, std::string>{{"aaa", "hello"}, {"bbb", "world"}}}}
83 },
84 ValueFromJsonSuccessTestParam{
85 R"({"field1":[[]]})",
86 ValueMessageData{std::vector<ProtoValue>{std::vector<double>{}}}
87 },
88 ValueFromJsonSuccessTestParam{
89 R"({"field1":[[1.5],[0,1.5]]})",
90 ValueMessageData{std::vector<ProtoValue>{std::vector<double>{1.5}, std::vector<double>{0, 1.5}}}
91 },
92 ValueFromJsonSuccessTestParam{
93 R"({"field1":[null,1.5,"hello",true,[1.5,1.5],{"aaa":"hello","bbb":"world"}]})",
94 ValueMessageData{std::vector<ProtoValue>{
95 kProtoNullValue,
96 1.5,
97 "hello",
98 true,
99 std::vector<double>{1.5, 1.5},
100 std::map<std::string, std::string>{{"aaa", "hello"}, {"bbb", "world"}}
101 }}
102 },
103 ValueFromJsonSuccessTestParam{
104 R"({"field1":{"aaa":{}}})",
105 ValueMessageData{std::map<std::string, ProtoValue>{{"aaa", std::map<std::string, std::string>{}}}}
106 },
107 ValueFromJsonSuccessTestParam{
108 R"({"field1":{"aaa":null,"bbb":1.5,"ccc":"hello","ddd":true,"eee":[1.5,1.5],"":{"":"hello","bbb":"world"}}})",
109 ValueMessageData{std::map<std::string, ProtoValue>{
110 {"aaa", kProtoNullValue},
111 {"bbb", 1.5},
112 {"ccc", "hello"},
113 {"ddd", true},
114 {"eee", std::vector<double>{1.5, 1.5}},
115 {"", std::map<std::string, std::string>{{"", "hello"}, {"bbb", "world"}}}
116 }}
117 }
118 )
119);
120
121INSTANTIATE_TEST_SUITE_P(
122 ,
123 ListValueFromJsonFailureTest,
124 ::testing::Values(
125 ListValueFromJsonFailureTestParam{R"({})", ParseErrorCode::kInvalidType, "/", {}, true},
126 ListValueFromJsonFailureTestParam{R"(true)", ParseErrorCode::kInvalidType, "/"},
127 ListValueFromJsonFailureTestParam{R"(10)", ParseErrorCode::kInvalidType, "/"},
128 ListValueFromJsonFailureTestParam{R"("")", ParseErrorCode::kInvalidType, "/"}
129 )
130);
131
132INSTANTIATE_TEST_SUITE_P(
133 ,
134 StructFromJsonFailureTest,
135 ::testing::Values(
136 StructFromJsonFailureTestParam{R"([])", ParseErrorCode::kInvalidType, "/"},
137 StructFromJsonFailureTestParam{R"(true)", ParseErrorCode::kInvalidType, "/"},
138 StructFromJsonFailureTestParam{R"(10)", ParseErrorCode::kInvalidType, "/"},
139 StructFromJsonFailureTestParam{R"("")", ParseErrorCode::kInvalidType, "/"}
140 )
141);
142
143TEST_P(ValueFromJsonSuccessTest, Test) {
144 const auto& param = GetParam();
145
146 proto_json::messages::ValueMessage message;
147 proto_json::messages::ValueMessage expected_message;
148 proto_json::messages::ValueMessage sample_message;
149 formats::json::Value input = PrepareJsonTestData(param.input);
150 expected_message = PrepareTestData(param.expected_message);
151
152 message.mutable_field1()->set_number_value(100001);
153
154 UASSERT_NO_THROW((message = JsonToMessage<proto_json::messages::ValueMessage>(input, param.options)));
155 UASSERT_NO_THROW(InitSampleMessage(param.input, sample_message, param.options));
156
157 CheckMessageEqual(message, sample_message);
158 CheckMessageEqual(message, expected_message);
159}
160
161TEST_P(ListValueFromJsonFailureTest, Test) {
162 using Message = ::google::protobuf::ListValue;
163 const auto& param = GetParam();
164
165 Message sample;
166 formats::json::Value input = PrepareJsonTestData(param.input);
167
168 EXPECT_PARSE_ERROR((void)JsonToMessage<Message>(input, param.options), param.expected_errc, param.expected_path);
169
170 if (!param.skip_native_check) {
171 EXPECT_FALSE(::google::protobuf::util::JsonStringToMessage(param.input, &sample, {}).ok());
172 }
173}
174
175TEST_P(StructFromJsonFailureTest, Test) {
176 using Message = ::google::protobuf::Struct;
177 const auto& param = GetParam();
178
179 Message sample;
180 formats::json::Value input = PrepareJsonTestData(param.input);
181
182 EXPECT_PARSE_ERROR((void)JsonToMessage<Message>(input, param.options), param.expected_errc, param.expected_path);
183 EXPECT_FALSE(::google::protobuf::util::JsonStringToMessage(param.input, &sample, {}).ok());
184}
185
186TEST(ValueFromJsonAdditionalTest, InlinedNonNullValue) {
187 using Message = ::google::protobuf::Value;
188
189 {
190 const char* json_str = "1.5";
191 const auto json = formats::json::FromString(json_str);
192 Message message;
193 Message sample;
194
195 message.set_number_value(100001);
196
197 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
198 UASSERT_NO_THROW(InitSampleMessage(json_str, sample));
199 EXPECT_EQ(message.number_value(), 1.5);
200 CheckMessageEqual(message, sample);
201 }
202
203 {
204 const char* json_str = R"("hello")";
205 const auto json = formats::json::FromString(json_str);
206 Message message;
207 Message sample;
208
209 message.set_number_value(100001);
210
211 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
212 UASSERT_NO_THROW(InitSampleMessage(json_str, sample));
213 EXPECT_EQ(message.string_value(), "hello");
214 CheckMessageEqual(message, sample);
215 }
216
217 {
218 const char* json_str = "true";
219 const auto json = formats::json::FromString(json_str);
220 Message message;
221 Message sample;
222
223 message.set_number_value(100001);
224
225 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
226 UASSERT_NO_THROW(InitSampleMessage(json_str, sample));
227 EXPECT_TRUE(message.has_bool_value());
228 EXPECT_TRUE(message.bool_value());
229 CheckMessageEqual(message, sample);
230 }
231
232 {
233 const char* json_str = "[]";
234 const auto json = formats::json::FromString(json_str);
235 Message message;
236 Message sample;
237
238 message.set_number_value(100001);
239
240 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
241 UASSERT_NO_THROW(InitSampleMessage(json_str, sample));
242 EXPECT_TRUE(message.has_list_value());
243 EXPECT_TRUE(message.list_value().values().empty());
244 CheckMessageEqual(message, sample);
245 }
246
247 {
248 const char* json_str = "[true, false]";
249 const auto json = formats::json::FromString(json_str);
250 Message message;
251 Message sample;
252
253 message.set_number_value(100001);
254
255 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
256 UASSERT_NO_THROW(InitSampleMessage(json_str, sample));
257 EXPECT_TRUE(message.has_list_value());
258 ASSERT_EQ(message.list_value().values().size(), 2);
259 EXPECT_TRUE(message.list_value().values()[0].has_bool_value());
260 EXPECT_TRUE(message.list_value().values()[0].bool_value());
261 EXPECT_TRUE(message.list_value().values()[1].has_bool_value());
262 EXPECT_FALSE(message.list_value().values()[1].bool_value());
263 CheckMessageEqual(message, sample);
264 }
265
266 {
267 const char* json_str = "{}";
268 const auto json = formats::json::FromString(json_str);
269 Message message;
270 Message sample;
271
272 message.set_number_value(100001);
273
274 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
275 UASSERT_NO_THROW(InitSampleMessage(json_str, sample));
276 EXPECT_TRUE(message.has_struct_value());
277 EXPECT_EQ(message.struct_value().fields().size(), std::size_t{0});
278 CheckMessageEqual(message, sample);
279 }
280
281 {
282 const char* json_str = R"({"aaa":true,"bbb":false})";
283 const auto json = formats::json::FromString(json_str);
284 Message message;
285 Message sample;
286
287 message.set_number_value(100001);
288
289 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
290 UASSERT_NO_THROW(InitSampleMessage(json_str, sample));
291 EXPECT_TRUE(message.has_struct_value());
292 EXPECT_EQ(message.struct_value().fields().size(), std::size_t{2});
293 ASSERT_TRUE(message.struct_value().fields().contains("aaa"));
294 ASSERT_TRUE(message.struct_value().fields().contains("bbb"));
295 EXPECT_TRUE(message.struct_value().fields().at("aaa").has_bool_value());
296 EXPECT_TRUE(message.struct_value().fields().at("aaa").bool_value());
297 EXPECT_TRUE(message.struct_value().fields().at("bbb").has_bool_value());
298 EXPECT_FALSE(message.struct_value().fields().at("bbb").bool_value());
299 CheckMessageEqual(message, sample);
300 }
301}
302
303TEST(ValueFromJsonAdditionalTest, InlinedNonNullListValue) {
304 using Message = ::google::protobuf::ListValue;
305
306 {
307 const char* json_str = "1.5";
308 const auto json = formats::json::FromString(json_str);
309 Message sample;
310
311 EXPECT_PARSE_ERROR((void)JsonToMessage<Message>(json), ParseErrorCode::kInvalidType, "/");
312 UEXPECT_THROW(InitSampleMessage(json_str, sample), SampleError);
313 }
314
315 {
316 const char* json_str = "[]";
317 const auto json = formats::json::FromString(json_str);
318 Message message;
319 Message sample;
320
321 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
322 UASSERT_NO_THROW(InitSampleMessage(json_str, sample));
323 EXPECT_TRUE(message.values().empty());
324 CheckMessageEqual(message, sample);
325 }
326
327 {
328 const char* json_str = R"([null, 1.5, "hello", true])";
329 const auto json = formats::json::FromString(json_str);
330 Message message;
331 Message sample;
332
333 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
334 UASSERT_NO_THROW(InitSampleMessage(json_str, sample));
335 ASSERT_EQ(message.values().size(), 4);
336 EXPECT_TRUE(message.values()[0].has_null_value());
337 EXPECT_TRUE(message.values()[1].has_number_value());
338 EXPECT_EQ(message.values()[1].number_value(), 1.5);
339 EXPECT_TRUE(message.values()[2].has_string_value());
340 EXPECT_EQ(message.values()[2].string_value(), "hello");
341 EXPECT_TRUE(message.values()[3].has_bool_value());
342 EXPECT_TRUE(message.values()[3].bool_value());
343 CheckMessageEqual(message, sample);
344 }
345}
346
347TEST(ValueFromJsonAdditionalTest, InlinedNonNullStruct) {
348 using Message = ::google::protobuf::Struct;
349
350 {
351 const char* json_str = "1.5";
352 const auto json = formats::json::FromString(json_str);
353 Message sample;
354
355 EXPECT_PARSE_ERROR((void)JsonToMessage<Message>(json), ParseErrorCode::kInvalidType, "/");
356 UEXPECT_THROW(InitSampleMessage(json_str, sample), SampleError);
357 }
358
359 {
360 const char* json_str = "{}";
361 const auto json = formats::json::FromString(json_str);
362 Message message;
363 Message sample;
364
365 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
366 UASSERT_NO_THROW(InitSampleMessage(json_str, sample));
367 EXPECT_EQ(message.fields().size(), std::size_t{0});
368 CheckMessageEqual(message, sample);
369 }
370
371 {
372 const char* json_str = R"({"aaa":1.5,"":false})";
373 const auto json = formats::json::FromString(json_str);
374 Message message;
375 Message sample;
376
377 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
378 UASSERT_NO_THROW(InitSampleMessage(json_str, sample));
379 ASSERT_EQ(message.fields().size(), std::size_t{2});
380 ASSERT_TRUE(message.fields().contains("aaa"));
381 EXPECT_TRUE(message.fields().at("aaa").has_number_value());
382 EXPECT_EQ(message.fields().at("aaa").number_value(), 1.5);
383 ASSERT_TRUE(message.fields().contains(""));
384 EXPECT_TRUE(message.fields().at("").has_bool_value());
385 EXPECT_FALSE(message.fields().at("").bool_value());
386 CheckMessageEqual(message, sample);
387 }
388}
389
390TEST(ValueFromJsonAdditionalTest, InlinedNullValue) {
391 using Message = ::google::protobuf::Value;
392
393 const char* json_str = "null";
394 const auto json = formats::json::FromString(json_str);
395 Message message;
396 Message sample;
397
398 message.set_number_value(100001);
399
400 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
401 UASSERT_NO_THROW(InitSampleMessage(json_str, sample));
402 EXPECT_TRUE(message.has_null_value());
403 CheckMessageEqual(message, sample);
404}
405
406TEST(ValueFromJsonAdditionalTest, InlinedNullListValue) {
407 using Message = ::google::protobuf::ListValue;
408
409 const char* json_str = "null";
410 const auto json = formats::json::FromString(json_str);
411 Message message;
412 Message sample;
413
414 message.add_values()->set_number_value(100001);
415
416 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
417 UASSERT_NO_THROW(InitSampleMessage(json_str, sample));
418 EXPECT_TRUE(message.values().empty());
419 CheckMessageEqual(message, sample);
420}
421
422TEST(ValueFromJsonAdditionalTest, InlinedNullStruct) {
423 using Message = ::google::protobuf::Struct;
424
425 const char* json_str = "null";
426 const auto json = formats::json::FromString(json_str);
427 Message message;
428 Message sample;
429
430 (*message.mutable_fields())["aaa"].set_number_value(100001);
431
432 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
433 UASSERT_NO_THROW(InitSampleMessage(json_str, sample));
434 EXPECT_TRUE(message.fields().empty());
435 CheckMessageEqual(message, sample);
436}
437
438TEST(ValueFromJsonAdditionalTest, DynamicMessage) {
439 using Message = ::google::protobuf::Value;
440
441 {
442 const char* json_str = "null";
443 const auto json = formats::json::FromString(json_str);
444 ::google::protobuf::DynamicMessageFactory factory;
445
446 {
447 std::unique_ptr<::google::protobuf::Message> message(factory.GetPrototype(Message::descriptor())->New());
448
449 UASSERT_NO_THROW(JsonToMessage(json, *message));
450
451 const auto reflection = message->GetReflection();
452 const auto field_desc = message->GetDescriptor()->FindFieldByName("null_value");
453
454 ASSERT_TRUE(reflection->HasField(*message, field_desc));
455 }
456 }
457
458 {
459 const char* json_str = "1.5";
460 const auto json = formats::json::FromString(json_str);
461 ::google::protobuf::DynamicMessageFactory factory;
462
463 {
464 std::unique_ptr<::google::protobuf::Message> message(factory.GetPrototype(Message::descriptor())->New());
465
466 UASSERT_NO_THROW(JsonToMessage(json, *message));
467
468 const auto reflection = message->GetReflection();
469 const auto field_desc = message->GetDescriptor()->FindFieldByName("number_value");
470
471 ASSERT_TRUE(reflection->HasField(*message, field_desc));
472 EXPECT_EQ(reflection->GetDouble(*message, field_desc), 1.5);
473 }
474 }
475
476 {
477 const char* json_str = R"("hello")";
478 const auto json = formats::json::FromString(json_str);
479 ::google::protobuf::DynamicMessageFactory factory;
480
481 {
482 std::unique_ptr<::google::protobuf::Message> message(factory.GetPrototype(Message::descriptor())->New());
483
484 UASSERT_NO_THROW(JsonToMessage(json, *message));
485
486 const auto reflection = message->GetReflection();
487 const auto field_desc = message->GetDescriptor()->FindFieldByName("string_value");
488
489 ASSERT_TRUE(reflection->HasField(*message, field_desc));
490 EXPECT_EQ(reflection->GetString(*message, field_desc), "hello");
491 }
492 }
493
494 {
495 const char* json_str = "true";
496 const auto json = formats::json::FromString(json_str);
497 ::google::protobuf::DynamicMessageFactory factory;
498
499 {
500 std::unique_ptr<::google::protobuf::Message> message(factory.GetPrototype(Message::descriptor())->New());
501
502 UASSERT_NO_THROW(JsonToMessage(json, *message));
503
504 const auto reflection = message->GetReflection();
505 const auto field_desc = message->GetDescriptor()->FindFieldByName("bool_value");
506
507 ASSERT_TRUE(reflection->HasField(*message, field_desc));
508 EXPECT_TRUE(reflection->GetBool(*message, field_desc));
509 }
510 }
511
512 {
513 const char* json_str = "[1.5]";
514 const auto json = formats::json::FromString(json_str);
515 ::google::protobuf::DynamicMessageFactory factory;
516
517 {
518 std::unique_ptr<::google::protobuf::Message> message(factory.GetPrototype(Message::descriptor())->New());
519
520 UASSERT_NO_THROW(JsonToMessage(json, *message));
521
522 const auto reflection = message->GetReflection();
523 const auto field_desc = message->GetDescriptor()->FindFieldByName("list_value");
524
525 ASSERT_TRUE(reflection->HasField(*message, field_desc));
526
527 const auto& list = reflection->GetMessage(*message, field_desc);
528 const auto list_reflection = list.GetReflection();
529 const auto values_desc = list.GetDescriptor()->FindFieldByName("values");
530
531 ASSERT_EQ(list_reflection->FieldSize(list, values_desc), 1);
532
533 const auto& item = list_reflection->GetRepeatedMessage(list, values_desc, 0);
534 const auto item_reflection = item.GetReflection();
535 const auto number_value_desc = item.GetDescriptor()->FindFieldByName("number_value");
536
537 EXPECT_EQ(item_reflection->GetDouble(item, number_value_desc), 1.5);
538 }
539 }
540
541 {
542 const char* json_str = R"({"aaa":"hello"})";
543 const auto json = formats::json::FromString(json_str);
544 ::google::protobuf::DynamicMessageFactory factory;
545
546 {
547 std::unique_ptr<::google::protobuf::Message> message(factory.GetPrototype(Message::descriptor())->New());
548
549 UASSERT_NO_THROW(JsonToMessage(json, *message));
550
551 const auto reflection = message->GetReflection();
552 const auto field_desc = message->GetDescriptor()->FindFieldByName("struct_value");
553
554 ASSERT_TRUE(reflection->HasField(*message, field_desc));
555
556 const auto& obj = reflection->GetMessage(*message, field_desc);
557 const auto obj_reflection = obj.GetReflection();
558 const auto fields_desc = obj.GetDescriptor()->FindFieldByName("fields");
559
560 ASSERT_EQ(obj_reflection->FieldSize(obj, fields_desc), 1);
561
562 const auto& item = obj_reflection->GetRepeatedMessage(obj, fields_desc, 0);
563 const auto item_reflection = item.GetReflection();
564 const auto map_key_desc = item.GetDescriptor()->map_key();
565 const auto map_value_desc = item.GetDescriptor()->map_value();
566 const auto& map_value = item_reflection->GetMessage(item, map_value_desc);
567 const auto map_value_reflection = map_value.GetReflection();
568 const auto string_value_desc = map_value.GetDescriptor()->FindFieldByName("string_value");
569
570 EXPECT_EQ(item_reflection->GetString(item, map_key_desc), "aaa");
571 EXPECT_EQ(map_value_reflection->GetString(map_value, string_value_desc), "hello");
572 }
573 }
574}
575
576} // namespace protobuf::json::tests
577
578USERVER_NAMESPACE_END