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 if (kIsModernProtoJson) {
418 UASSERT_NO_THROW(InitSampleMessage(json_str, sample));
419 }
420 EXPECT_TRUE(message.values().empty());
421 CheckMessageEqual(message, sample);
422}
423
424TEST(ValueFromJsonAdditionalTest, InlinedNullStruct) {
425 using Message = ::google::protobuf::Struct;
426
427 const char* json_str = "null";
428 const auto json = formats::json::FromString(json_str);
429 Message message;
430 Message sample;
431
432 (*message.mutable_fields())["aaa"].set_number_value(100001);
433
434 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
435 if (kIsModernProtoJson) {
436 UASSERT_NO_THROW(InitSampleMessage(json_str, sample));
437 }
438 EXPECT_TRUE(message.fields().empty());
439 CheckMessageEqual(message, sample);
440}
441
442TEST(ValueFromJsonAdditionalTest, DynamicMessage) {
443 using Message = ::google::protobuf::Value;
444
445 {
446 const char* json_str = "null";
447 const auto json = formats::json::FromString(json_str);
448 ::google::protobuf::DynamicMessageFactory factory;
449
450 {
451 std::unique_ptr<::google::protobuf::Message> message(factory.GetPrototype(Message::descriptor())->New());
452
453 UASSERT_NO_THROW(JsonToMessage(json, *message));
454
455 const auto reflection = message->GetReflection();
456 const auto field_desc = message->GetDescriptor()->FindFieldByName("null_value");
457
458 ASSERT_TRUE(reflection->HasField(*message, field_desc));
459 }
460 }
461
462 {
463 const char* json_str = "1.5";
464 const auto json = formats::json::FromString(json_str);
465 ::google::protobuf::DynamicMessageFactory factory;
466
467 {
468 std::unique_ptr<::google::protobuf::Message> message(factory.GetPrototype(Message::descriptor())->New());
469
470 UASSERT_NO_THROW(JsonToMessage(json, *message));
471
472 const auto reflection = message->GetReflection();
473 const auto field_desc = message->GetDescriptor()->FindFieldByName("number_value");
474
475 ASSERT_TRUE(reflection->HasField(*message, field_desc));
476 EXPECT_EQ(reflection->GetDouble(*message, field_desc), 1.5);
477 }
478 }
479
480 {
481 const char* json_str = R"("hello")";
482 const auto json = formats::json::FromString(json_str);
483 ::google::protobuf::DynamicMessageFactory factory;
484
485 {
486 std::unique_ptr<::google::protobuf::Message> message(factory.GetPrototype(Message::descriptor())->New());
487
488 UASSERT_NO_THROW(JsonToMessage(json, *message));
489
490 const auto reflection = message->GetReflection();
491 const auto field_desc = message->GetDescriptor()->FindFieldByName("string_value");
492
493 ASSERT_TRUE(reflection->HasField(*message, field_desc));
494 EXPECT_EQ(reflection->GetString(*message, field_desc), "hello");
495 }
496 }
497
498 {
499 const char* json_str = "true";
500 const auto json = formats::json::FromString(json_str);
501 ::google::protobuf::DynamicMessageFactory factory;
502
503 {
504 std::unique_ptr<::google::protobuf::Message> message(factory.GetPrototype(Message::descriptor())->New());
505
506 UASSERT_NO_THROW(JsonToMessage(json, *message));
507
508 const auto reflection = message->GetReflection();
509 const auto field_desc = message->GetDescriptor()->FindFieldByName("bool_value");
510
511 ASSERT_TRUE(reflection->HasField(*message, field_desc));
512 EXPECT_TRUE(reflection->GetBool(*message, field_desc));
513 }
514 }
515
516 {
517 const char* json_str = "[1.5]";
518 const auto json = formats::json::FromString(json_str);
519 ::google::protobuf::DynamicMessageFactory factory;
520
521 {
522 std::unique_ptr<::google::protobuf::Message> message(factory.GetPrototype(Message::descriptor())->New());
523
524 UASSERT_NO_THROW(JsonToMessage(json, *message));
525
526 const auto reflection = message->GetReflection();
527 const auto field_desc = message->GetDescriptor()->FindFieldByName("list_value");
528
529 ASSERT_TRUE(reflection->HasField(*message, field_desc));
530
531 const auto& list = reflection->GetMessage(*message, field_desc);
532 const auto list_reflection = list.GetReflection();
533 const auto values_desc = list.GetDescriptor()->FindFieldByName("values");
534
535 ASSERT_EQ(list_reflection->FieldSize(list, values_desc), 1);
536
537 const auto& item = list_reflection->GetRepeatedMessage(list, values_desc, 0);
538 const auto item_reflection = item.GetReflection();
539 const auto number_value_desc = item.GetDescriptor()->FindFieldByName("number_value");
540
541 EXPECT_EQ(item_reflection->GetDouble(item, number_value_desc), 1.5);
542 }
543 }
544
545 {
546 const char* json_str = R"({"aaa":"hello"})";
547 const auto json = formats::json::FromString(json_str);
548 ::google::protobuf::DynamicMessageFactory factory;
549
550 {
551 std::unique_ptr<::google::protobuf::Message> message(factory.GetPrototype(Message::descriptor())->New());
552
553 UASSERT_NO_THROW(JsonToMessage(json, *message));
554
555 const auto reflection = message->GetReflection();
556 const auto field_desc = message->GetDescriptor()->FindFieldByName("struct_value");
557
558 ASSERT_TRUE(reflection->HasField(*message, field_desc));
559
560 const auto& obj = reflection->GetMessage(*message, field_desc);
561 const auto obj_reflection = obj.GetReflection();
562 const auto fields_desc = obj.GetDescriptor()->FindFieldByName("fields");
563
564 ASSERT_EQ(obj_reflection->FieldSize(obj, fields_desc), 1);
565
566 const auto& item = obj_reflection->GetRepeatedMessage(obj, fields_desc, 0);
567 const auto item_reflection = item.GetReflection();
568 const auto map_key_desc = item.GetDescriptor()->map_key();
569 const auto map_value_desc = item.GetDescriptor()->map_value();
570 const auto& map_value = item_reflection->GetMessage(item, map_value_desc);
571 const auto map_value_reflection = map_value.GetReflection();
572 const auto string_value_desc = map_value.GetDescriptor()->FindFieldByName("string_value");
573
574 EXPECT_EQ(item_reflection->GetString(item, map_key_desc), "aaa");
575 EXPECT_EQ(map_value_reflection->GetString(map_value, string_value_desc), "hello");
576 }
577 }
578}
579
580} // namespace protobuf::json::tests
581
582USERVER_NAMESPACE_END