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 ReadOptions options = {};
25};
26
27struct ListValueFromJsonFailureTestParam {
28 std::string input = {};
29 ReadErrorCode expected_errc = {};
30 std::string expected_path = {};
31 ReadOptions 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 ReadErrorCode expected_errc = {};
40 std::string expected_path = {};
41 ReadOptions 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"({})", ReadErrorCode::kInvalidType, "/", {}, true},
126 ListValueFromJsonFailureTestParam{R"(true)", ReadErrorCode::kInvalidType, "/"},
127 ListValueFromJsonFailureTestParam{R"(10)", ReadErrorCode::kInvalidType, "/"},
128 ListValueFromJsonFailureTestParam{R"("")", ReadErrorCode::kInvalidType, "/"}
129 )
130);
131
132INSTANTIATE_TEST_SUITE_P(
133 ,
134 StructFromJsonFailureTest,
135 ::testing::Values(
136 StructFromJsonFailureTestParam{R"([])", ReadErrorCode::kInvalidType, "/"},
137 StructFromJsonFailureTestParam{R"(true)", ReadErrorCode::kInvalidType, "/"},
138 StructFromJsonFailureTestParam{R"(10)", ReadErrorCode::kInvalidType, "/"},
139 StructFromJsonFailureTestParam{R"("")", ReadErrorCode::kInvalidType, "/"}
140 )
141);
142
143TEST_P(ValueFromJsonSuccessTest, Test) {
144 const auto& param = GetParam();
145
146 proto_json::messages::ValueMessage message, expected_message, sample_message;
147 formats::json::Value input = PrepareJsonTestData(param.input);
148 expected_message = PrepareTestData(param.expected_message);
149
150 message.mutable_field1()->set_number_value(100001);
151
152 UASSERT_NO_THROW((message = JsonToMessage<proto_json::messages::ValueMessage>(input, param.options)));
153 UASSERT_NO_THROW(InitSampleMessage(param.input, param.options, sample_message));
154
155 CheckMessageEqual(message, sample_message);
156 CheckMessageEqual(message, expected_message);
157}
158
159TEST_P(ListValueFromJsonFailureTest, Test) {
160 using Message = ::google::protobuf::ListValue;
161 const auto& param = GetParam();
162
163 Message sample;
164 formats::json::Value input = PrepareJsonTestData(param.input);
165
166 EXPECT_READ_ERROR((void)JsonToMessage<Message>(input, param.options), param.expected_errc, param.expected_path);
167
168 if (!param.skip_native_check) {
169 EXPECT_FALSE(::google::protobuf::util::JsonStringToMessage(param.input, &sample, {}).ok());
170 }
171}
172
173TEST_P(StructFromJsonFailureTest, Test) {
174 using Message = ::google::protobuf::Struct;
175 const auto& param = GetParam();
176
177 Message sample;
178 formats::json::Value input = PrepareJsonTestData(param.input);
179
180 EXPECT_READ_ERROR((void)JsonToMessage<Message>(input, param.options), param.expected_errc, param.expected_path);
181 EXPECT_FALSE(::google::protobuf::util::JsonStringToMessage(param.input, &sample, {}).ok());
182}
183
184TEST(ValueFromJsonAdditionalTest, InlinedNonNullValue) {
185 using Message = ::google::protobuf::Value;
186
187 {
188 const char* json_str = "1.5";
189 const auto json = formats::json::FromString(json_str);
190 Message message, sample;
191
192 message.set_number_value(100001);
193
194 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
195 UASSERT_NO_THROW(InitSampleMessage(json_str, {}, sample));
196 EXPECT_EQ(message.number_value(), 1.5);
197 CheckMessageEqual(message, sample);
198 }
199
200 {
201 const char* json_str = "\"hello\"";
202 const auto json = formats::json::FromString(json_str);
203 Message message, sample;
204
205 message.set_number_value(100001);
206
207 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
208 UASSERT_NO_THROW(InitSampleMessage(json_str, {}, sample));
209 EXPECT_EQ(message.string_value(), "hello");
210 CheckMessageEqual(message, sample);
211 }
212
213 {
214 const char* json_str = "true";
215 const auto json = formats::json::FromString(json_str);
216 Message message, sample;
217
218 message.set_number_value(100001);
219
220 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
221 UASSERT_NO_THROW(InitSampleMessage(json_str, {}, sample));
222 EXPECT_TRUE(message.has_bool_value());
223 EXPECT_TRUE(message.bool_value());
224 CheckMessageEqual(message, sample);
225 }
226
227 {
228 const char* json_str = "[]";
229 const auto json = formats::json::FromString(json_str);
230 Message message, sample;
231
232 message.set_number_value(100001);
233
234 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
235 UASSERT_NO_THROW(InitSampleMessage(json_str, {}, sample));
236 EXPECT_TRUE(message.has_list_value());
237 EXPECT_TRUE(message.list_value().values().empty());
238 CheckMessageEqual(message, sample);
239 }
240
241 {
242 const char* json_str = "[true, false]";
243 const auto json = formats::json::FromString(json_str);
244 Message message, sample;
245
246 message.set_number_value(100001);
247
248 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
249 UASSERT_NO_THROW(InitSampleMessage(json_str, {}, sample));
250 EXPECT_TRUE(message.has_list_value());
251 ASSERT_EQ(message.list_value().values().size(), 2);
252 EXPECT_TRUE(message.list_value().values()[0].has_bool_value());
253 EXPECT_TRUE(message.list_value().values()[0].bool_value());
254 EXPECT_TRUE(message.list_value().values()[1].has_bool_value());
255 EXPECT_FALSE(message.list_value().values()[1].bool_value());
256 CheckMessageEqual(message, sample);
257 }
258
259 {
260 const char* json_str = "{}";
261 const auto json = formats::json::FromString(json_str);
262 Message message, sample;
263
264 message.set_number_value(100001);
265
266 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
267 UASSERT_NO_THROW(InitSampleMessage(json_str, {}, sample));
268 EXPECT_TRUE(message.has_struct_value());
269 EXPECT_EQ(message.struct_value().fields().size(), std::size_t{0});
270 CheckMessageEqual(message, sample);
271 }
272
273 {
274 const char* json_str = "{\"aaa\":true,\"bbb\":false}";
275 const auto json = formats::json::FromString(json_str);
276 Message message, sample;
277
278 message.set_number_value(100001);
279
280 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
281 UASSERT_NO_THROW(InitSampleMessage(json_str, {}, sample));
282 EXPECT_TRUE(message.has_struct_value());
283 EXPECT_EQ(message.struct_value().fields().size(), std::size_t{2});
284 ASSERT_TRUE(message.struct_value().fields().contains("aaa"));
285 ASSERT_TRUE(message.struct_value().fields().contains("bbb"));
286 EXPECT_TRUE(message.struct_value().fields().at("aaa").has_bool_value());
287 EXPECT_TRUE(message.struct_value().fields().at("aaa").bool_value());
288 EXPECT_TRUE(message.struct_value().fields().at("bbb").has_bool_value());
289 EXPECT_FALSE(message.struct_value().fields().at("bbb").bool_value());
290 CheckMessageEqual(message, sample);
291 }
292}
293
294TEST(ValueFromJsonAdditionalTest, InlinedNonNullListValue) {
295 using Message = ::google::protobuf::ListValue;
296
297 {
298 const char* json_str = "1.5";
299 const auto json = formats::json::FromString(json_str);
300 Message sample;
301
302 EXPECT_READ_ERROR((void)JsonToMessage<Message>(json), ReadErrorCode::kInvalidType, "/");
303 UEXPECT_THROW(InitSampleMessage(json_str, {}, sample), SampleError);
304 }
305
306 {
307 const char* json_str = "[]";
308 const auto json = formats::json::FromString(json_str);
309 Message message, sample;
310
311 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
312 UASSERT_NO_THROW(InitSampleMessage(json_str, {}, sample));
313 EXPECT_TRUE(message.values().empty());
314 CheckMessageEqual(message, sample);
315 }
316
317 {
318 const char* json_str = "[null, 1.5, \"hello\", true]";
319 const auto json = formats::json::FromString(json_str);
320 Message message, sample;
321
322 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
323 UASSERT_NO_THROW(InitSampleMessage(json_str, {}, sample));
324 ASSERT_EQ(message.values().size(), 4);
325 EXPECT_TRUE(message.values()[0].has_null_value());
326 EXPECT_TRUE(message.values()[1].has_number_value());
327 EXPECT_EQ(message.values()[1].number_value(), 1.5);
328 EXPECT_TRUE(message.values()[2].has_string_value());
329 EXPECT_EQ(message.values()[2].string_value(), "hello");
330 EXPECT_TRUE(message.values()[3].has_bool_value());
331 EXPECT_TRUE(message.values()[3].bool_value());
332 CheckMessageEqual(message, sample);
333 }
334}
335
336TEST(ValueFromJsonAdditionalTest, InlinedNonNullStruct) {
337 using Message = ::google::protobuf::Struct;
338
339 {
340 const char* json_str = "1.5";
341 const auto json = formats::json::FromString(json_str);
342 Message sample;
343
344 EXPECT_READ_ERROR((void)JsonToMessage<Message>(json), ReadErrorCode::kInvalidType, "/");
345 UEXPECT_THROW(InitSampleMessage(json_str, {}, sample), SampleError);
346 }
347
348 {
349 const char* json_str = "{}";
350 const auto json = formats::json::FromString(json_str);
351 Message message, sample;
352
353 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
354 UASSERT_NO_THROW(InitSampleMessage(json_str, {}, sample));
355 EXPECT_EQ(message.fields().size(), std::size_t{0});
356 CheckMessageEqual(message, sample);
357 }
358
359 {
360 const char* json_str = "{\"aaa\":1.5,\"\":false}";
361 const auto json = formats::json::FromString(json_str);
362 Message message, sample;
363
364 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
365 UASSERT_NO_THROW(InitSampleMessage(json_str, {}, sample));
366 ASSERT_EQ(message.fields().size(), std::size_t{2});
367 ASSERT_TRUE(message.fields().contains("aaa"));
368 EXPECT_TRUE(message.fields().at("aaa").has_number_value());
369 EXPECT_EQ(message.fields().at("aaa").number_value(), 1.5);
370 ASSERT_TRUE(message.fields().contains(""));
371 EXPECT_TRUE(message.fields().at("").has_bool_value());
372 EXPECT_FALSE(message.fields().at("").bool_value());
373 CheckMessageEqual(message, sample);
374 }
375}
376
377TEST(ValueFromJsonAdditionalTest, InlinedNullValue) {
378 using Message = ::google::protobuf::Value;
379
380 const char* json_str = "null";
381 const auto json = formats::json::FromString(json_str);
382 Message message, sample;
383
384 message.set_number_value(100001);
385
386 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
387 UASSERT_NO_THROW(InitSampleMessage(json_str, {}, sample));
388 EXPECT_TRUE(message.has_null_value());
389 CheckMessageEqual(message, sample);
390}
391
392TEST(ValueFromJsonAdditionalTest, InlinedNullListValue) {
393 using Message = ::google::protobuf::ListValue;
394
395 const char* json_str = "null";
396 const auto json = formats::json::FromString(json_str);
397 Message message, sample;
398
399 message.add_values()->set_number_value(100001);
400
401 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
402 UASSERT_NO_THROW(InitSampleMessage(json_str, {}, sample));
403 EXPECT_TRUE(message.values().empty());
404 CheckMessageEqual(message, sample);
405}
406
407TEST(ValueFromJsonAdditionalTest, InlinedNullStruct) {
408 using Message = ::google::protobuf::Struct;
409
410 const char* json_str = "null";
411 const auto json = formats::json::FromString(json_str);
412 Message message, sample;
413
414 (*message.mutable_fields())["aaa"].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.fields().empty());
419 CheckMessageEqual(message, sample);
420}
421
422TEST(ValueFromJsonAdditionalTest, DynamicMessage) {
423 using Message = ::google::protobuf::Value;
424
425 {
426 const char* json_str = "null";
427 const auto json = formats::json::FromString(json_str);
428 ::google::protobuf::DynamicMessageFactory factory;
429
430 {
431 std::unique_ptr<::google::protobuf::Message> message(factory.GetPrototype(Message::descriptor())->New());
432
433 UASSERT_NO_THROW(JsonToMessage(json, {}, *message));
434
435 const auto reflection = message->GetReflection();
436 const auto field_desc = message->GetDescriptor()->FindFieldByName("null_value");
437
438 ASSERT_TRUE(reflection->HasField(*message, field_desc));
439 }
440 }
441
442 {
443 const char* json_str = "1.5";
444 const auto json = formats::json::FromString(json_str);
445 ::google::protobuf::DynamicMessageFactory factory;
446
447 {
448 std::unique_ptr<::google::protobuf::Message> message(factory.GetPrototype(Message::descriptor())->New());
449
450 UASSERT_NO_THROW(JsonToMessage(json, {}, *message));
451
452 const auto reflection = message->GetReflection();
453 const auto field_desc = message->GetDescriptor()->FindFieldByName("number_value");
454
455 ASSERT_TRUE(reflection->HasField(*message, field_desc));
456 EXPECT_EQ(reflection->GetDouble(*message, field_desc), 1.5);
457 }
458 }
459
460 {
461 const char* json_str = "\"hello\"";
462 const auto json = formats::json::FromString(json_str);
463 ::google::protobuf::DynamicMessageFactory factory;
464
465 {
466 std::unique_ptr<::google::protobuf::Message> message(factory.GetPrototype(Message::descriptor())->New());
467
468 UASSERT_NO_THROW(JsonToMessage(json, {}, *message));
469
470 const auto reflection = message->GetReflection();
471 const auto field_desc = message->GetDescriptor()->FindFieldByName("string_value");
472
473 ASSERT_TRUE(reflection->HasField(*message, field_desc));
474 EXPECT_EQ(reflection->GetString(*message, field_desc), "hello");
475 }
476 }
477
478 {
479 const char* json_str = "true";
480 const auto json = formats::json::FromString(json_str);
481 ::google::protobuf::DynamicMessageFactory factory;
482
483 {
484 std::unique_ptr<::google::protobuf::Message> message(factory.GetPrototype(Message::descriptor())->New());
485
486 UASSERT_NO_THROW(JsonToMessage(json, {}, *message));
487
488 const auto reflection = message->GetReflection();
489 const auto field_desc = message->GetDescriptor()->FindFieldByName("bool_value");
490
491 ASSERT_TRUE(reflection->HasField(*message, field_desc));
492 EXPECT_TRUE(reflection->GetBool(*message, field_desc));
493 }
494 }
495
496 {
497 const char* json_str = "[1.5]";
498 const auto json = formats::json::FromString(json_str);
499 ::google::protobuf::DynamicMessageFactory factory;
500
501 {
502 std::unique_ptr<::google::protobuf::Message> message(factory.GetPrototype(Message::descriptor())->New());
503
504 UASSERT_NO_THROW(JsonToMessage(json, {}, *message));
505
506 const auto reflection = message->GetReflection();
507 const auto field_desc = message->GetDescriptor()->FindFieldByName("list_value");
508
509 ASSERT_TRUE(reflection->HasField(*message, field_desc));
510
511 const auto& list = reflection->GetMessage(*message, field_desc);
512 const auto list_reflection = list.GetReflection();
513 const auto values_desc = list.GetDescriptor()->FindFieldByName("values");
514
515 ASSERT_EQ(list_reflection->FieldSize(list, values_desc), 1);
516
517 const auto& item = list_reflection->GetRepeatedMessage(list, values_desc, 0);
518 const auto item_reflection = item.GetReflection();
519 const auto number_value_desc = item.GetDescriptor()->FindFieldByName("number_value");
520
521 EXPECT_EQ(item_reflection->GetDouble(item, number_value_desc), 1.5);
522 }
523 }
524
525 {
526 const char* json_str = "{\"aaa\":\"hello\"}";
527 const auto json = formats::json::FromString(json_str);
528 ::google::protobuf::DynamicMessageFactory factory;
529
530 {
531 std::unique_ptr<::google::protobuf::Message> message(factory.GetPrototype(Message::descriptor())->New());
532
533 UASSERT_NO_THROW(JsonToMessage(json, {}, *message));
534
535 const auto reflection = message->GetReflection();
536 const auto field_desc = message->GetDescriptor()->FindFieldByName("struct_value");
537
538 ASSERT_TRUE(reflection->HasField(*message, field_desc));
539
540 const auto& obj = reflection->GetMessage(*message, field_desc);
541 const auto obj_reflection = obj.GetReflection();
542 const auto fields_desc = obj.GetDescriptor()->FindFieldByName("fields");
543
544 ASSERT_EQ(obj_reflection->FieldSize(obj, fields_desc), 1);
545
546 const auto& item = obj_reflection->GetRepeatedMessage(obj, fields_desc, 0);
547 const auto item_reflection = item.GetReflection();
548 const auto map_key_desc = item.GetDescriptor()->map_key();
549 const auto map_value_desc = item.GetDescriptor()->map_value();
550 const auto& map_value = item_reflection->GetMessage(item, map_value_desc);
551 const auto map_value_reflection = map_value.GetReflection();
552 const auto string_value_desc = map_value.GetDescriptor()->FindFieldByName("string_value");
553
554 EXPECT_EQ(item_reflection->GetString(item, map_key_desc), "aaa");
555 EXPECT_EQ(map_value_reflection->GetString(map_value, string_value_desc), "hello");
556 }
557 }
558}
559
560} // namespace protobuf::json::tests
561
562USERVER_NAMESPACE_END