userver: /data/code/userver/libraries/protobuf/tests/json/value_to_json_test.cpp Source File
Loading...
Searching...
No Matches
value_to_json_test.cpp
1#include <gtest/gtest.h>
2
3#include <limits>
4#include <memory>
5#include <string>
6
7#include <fmt/format.h>
8#include <google/protobuf/dynamic_message.h>
9
10#include <userver/protobuf/json/convert.hpp>
11#include <userver/utest/assert_macros.hpp>
12
13#include "utils.hpp"
14
15USERVER_NAMESPACE_BEGIN
16
17namespace protobuf::json::tests {
18
19struct ValueToJsonSuccessTestParam {
20 ValueMessageData input = {};
21 std::string expected_json = {};
22 PrintOptions options = {};
23};
24
25struct ValueToJsonFailureTestParam {
26 ValueMessageData input = {};
27 PrintErrorCode expected_errc = {};
28 std::string expected_path = {};
29 PrintOptions options = {};
30
31 // We want to skip some native checks because userver implementation has stricter requirements.
32 bool skip_native_check = false;
33};
34
35class ValueToJsonSuccessTest : public ::testing::TestWithParam<ValueToJsonSuccessTestParam> {};
36class ValueToJsonFailureTest : public ::testing::TestWithParam<ValueToJsonFailureTestParam> {};
37
38INSTANTIATE_TEST_SUITE_P(
39 ,
40 ValueToJsonSuccessTest,
41 ::
42 testing::
43 Values(
44 ValueToJsonSuccessTestParam{ValueMessageData{}, R"({})"},
45 ValueToJsonSuccessTestParam{ValueMessageData{ProtoValue{std::monostate{}}}, R"({})"},
46 ValueToJsonSuccessTestParam{ValueMessageData{ProtoValue{kProtoNullValue}}, R"({"field1":null})"},
47 ValueToJsonSuccessTestParam{ValueMessageData{ProtoValue{1.5}}, R"({"field1":1.5})"},
48 ValueToJsonSuccessTestParam{ValueMessageData{ProtoValue{"hello"}}, R"({"field1":"hello"})"},
49 ValueToJsonSuccessTestParam{ValueMessageData{ProtoValue{true}}, R"({"field1":true})"},
50 ValueToJsonSuccessTestParam{ValueMessageData{ProtoValue{std::vector<double>{}}}, R"({"field1":[]})"},
51 ValueToJsonSuccessTestParam{
52 ValueMessageData{ProtoValue{std::vector<double>{1.5, 1.5}}},
53 R"({"field1":[1.5, 1.5]})"
54 },
55 ValueToJsonSuccessTestParam{
56 ValueMessageData{ProtoValue{std::map<std::string, std::string>{}}},
57 R"({"field1":{}})"
58 },
59 ValueToJsonSuccessTestParam{
60 ValueMessageData{ProtoValue{std::map<std::string, std::string>{{"aaa", "hello"}, {"bbb", "world"}}}
61 },
62 R"({"field1":{"aaa":"hello","bbb":"world"}})"
63 },
64 ValueToJsonSuccessTestParam{
65 ValueMessageData{
66 std::vector<ProtoValue>{},
67 },
68 R"({"field1":[]})"
69 },
70 ValueToJsonSuccessTestParam{
71 ValueMessageData{
72 std::vector<ProtoValue>{std::vector<double>{}},
73 },
74 R"({"field1":[[]]})"
75 },
76 ValueToJsonSuccessTestParam{
77 ValueMessageData{
78 std::vector<ProtoValue>{std::vector<double>{1.5}, std::vector<double>{0, 1.5}},
79 },
80 R"({"field1":[[1.5],[0,1.5]]})"
81 },
82 ValueToJsonSuccessTestParam{
83 ValueMessageData{
84 std::vector<ProtoValue>{
85 kProtoNullValue,
86 1.5,
87 "hello",
88 true,
89 std::vector<double>{1.5, 1.5},
90 std::map<std::string, std::string>{{"aaa", "hello"}, {"bbb", "world"}}
91 },
92 },
93 R"({"field1":[null,1.5,"hello",true,[1.5,1.5],{"aaa":"hello","bbb":"world"}]})"
94 },
95 ValueToJsonSuccessTestParam{
96 ValueMessageData{std::vector<
97 ProtoValue>{ProtoValue{1.5}, ProtoValue{std::monostate{}}, ProtoValue{true}}},
98 R"({"field1":[1.5,true]})"
99 },
100
101 ValueToJsonSuccessTestParam{
102 ValueMessageData{
103 std::map<std::string, ProtoValue>{},
104 },
105 R"({"field1":{}})"
106 },
107 ValueToJsonSuccessTestParam{
108 ValueMessageData{
109 std::map<std::string, ProtoValue>{{"aaa", ProtoValue{std::map<std::string, std::string>{}}}},
110 },
111 R"({"field1":{"aaa":{}}})"
112 },
113 ValueToJsonSuccessTestParam{
114 ValueMessageData{
115 std::map<std::string, ProtoValue>{
116 {"aaa", kProtoNullValue},
117 {"bbb", 1.5},
118 {"ccc", "hello"},
119 {"ddd", true},
120 {"eee", std::vector<double>{1.5, 1.5}},
121 {"", std::map<std::string, std::string>{{"", "hello"}, {"bbb", "world"}}}
122 },
123 },
124 R"({"field1":{"aaa":null,"bbb":1.5,"ccc":"hello","ddd":true,"eee":[1.5,1.5],"":{"":"hello","bbb":"world"}}})"
125 },
126 ValueToJsonSuccessTestParam{
127 ValueMessageData{
128 std::map<std::string, ProtoValue>{
129 {"aaa", ProtoValue{1.5}},
130 {"bbb", ProtoValue{std::monostate{}}},
131 {"ccc", ProtoValue{true}}
132 },
133 },
134 R"({"field1":{"aaa":1.5,"ccc":true}})"
135 }
136 )
137);
138
139INSTANTIATE_TEST_SUITE_P(
140 ,
141 ValueToJsonFailureTest,
142 ::testing::Values(
143 ValueToJsonFailureTestParam{
144 ValueMessageData{ProtoValue{std::numeric_limits<double>::quiet_NaN()}},
145 PrintErrorCode::kInvalidValue,
146 "field1.number_value",
147 {},
148 !kIsModernProtoJson
149 },
150 ValueToJsonFailureTestParam{
151 ValueMessageData{ProtoValue{std::numeric_limits<double>::signaling_NaN()}},
152 PrintErrorCode::kInvalidValue,
153 "field1.number_value",
154 {},
155 !kIsModernProtoJson
156 },
157 ValueToJsonFailureTestParam{
158 ValueMessageData{ProtoValue{std::numeric_limits<double>::infinity()}},
159 PrintErrorCode::kInvalidValue,
160 "field1.number_value",
161 {},
162 !kIsModernProtoJson,
163 },
164 ValueToJsonFailureTestParam{
165 ValueMessageData{ProtoValue{-std::numeric_limits<double>::infinity()}},
166 PrintErrorCode::kInvalidValue,
167 "field1.number_value",
168 {},
169 !kIsModernProtoJson
170 },
171 ValueToJsonFailureTestParam{
172 ValueMessageData{std::vector<ProtoValue>{
173 ProtoValue{1.5},
174 ProtoValue{std::vector<double>{1.5, std::numeric_limits<double>::infinity()}},
175 ProtoValue{true}
176 }},
177 PrintErrorCode::kInvalidValue,
178 "field1.list_value.values[1].list_value.values[1].number_value",
179 {},
180 !kIsModernProtoJson
181 }
182 )
183);
184
185TEST_P(ValueToJsonSuccessTest, Test) {
186 const auto& param = GetParam();
187
188 auto input = PrepareTestData(param.input);
189 formats::json::Value json;
190 formats::json::Value expected_json;
191 formats::json::Value sample_json;
192
193 UASSERT_NO_THROW((json = MessageToJson(input, param.options)));
194 UASSERT_NO_THROW((expected_json = PrepareJsonTestData(param.expected_json)));
195 UASSERT_NO_THROW((sample_json = CreateSampleJson(input, param.options)));
196
197 EXPECT_EQ(json, expected_json);
198 EXPECT_EQ(expected_json, sample_json);
199}
200
201TEST_P(ValueToJsonFailureTest, Test) {
202 const auto& param = GetParam();
203 auto input = PrepareTestData(param.input);
204
205 EXPECT_PRINT_ERROR((void)MessageToJson(input, param.options), param.expected_errc, param.expected_path);
206
207 if (!param.skip_native_check) {
208 UEXPECT_THROW((void)CreateSampleJson(input, param.options), SampleError);
209 }
210}
211
212TEST(ValueToJsonAdditionalTest, InlinedNonNull) {
213 {
214 ValueMessageData data{kProtoNullValue};
215 auto message = PrepareTestData(data);
216 formats::json::Value json;
217 formats::json::Value sample;
218
219 UASSERT_NO_THROW((json = MessageToJson(message.field1(), {})));
220 UASSERT_NO_THROW((sample = CreateSampleJson(message.field1())));
221 EXPECT_EQ(json, sample);
222 EXPECT_TRUE(json.IsNull());
223 }
224
225 {
226 ValueMessageData data{1.5};
227 auto message = PrepareTestData(data);
228 formats::json::Value json;
229 formats::json::Value sample;
230
231 UASSERT_NO_THROW((json = MessageToJson(message.field1(), {})));
232 UASSERT_NO_THROW((sample = CreateSampleJson(message.field1())));
233 EXPECT_EQ(json, sample);
234 ASSERT_TRUE(json.IsNumber());
235 EXPECT_EQ(json.As<double>(), 1.5);
236 }
237
238 {
239 ValueMessageData data{"hello"};
240 auto message = PrepareTestData(data);
241 formats::json::Value json;
242 formats::json::Value sample;
243
244 UASSERT_NO_THROW((json = MessageToJson(message.field1(), {})));
245 UASSERT_NO_THROW((sample = CreateSampleJson(message.field1())));
246 EXPECT_EQ(json, sample);
247 EXPECT_TRUE(json.IsString());
248 EXPECT_EQ(json.As<std::string>(), "hello");
249 }
250
251 {
252 ValueMessageData data{true};
253 auto message = PrepareTestData(data);
254 formats::json::Value json;
255 formats::json::Value sample;
256
257 UASSERT_NO_THROW((json = MessageToJson(message.field1(), {})));
258 UASSERT_NO_THROW((sample = CreateSampleJson(message.field1())));
259 EXPECT_EQ(json, sample);
260 EXPECT_TRUE(json.IsBool());
261 EXPECT_TRUE(json.As<bool>());
262 }
263
264 {
265 ValueMessageData data{std::vector<double>{}};
266 auto message = PrepareTestData(data);
267 formats::json::Value json;
268 formats::json::Value sample;
269
270 UASSERT_NO_THROW((json = MessageToJson(message.field1(), {})));
271 UASSERT_NO_THROW((sample = CreateSampleJson(message.field1())));
272 EXPECT_EQ(json, sample);
273 EXPECT_TRUE(json.IsArray());
274 ASSERT_EQ(json.GetSize(), std::size_t{0});
275 }
276
277 {
278 ValueMessageData data{std::vector<double>{1.5, 0}};
279 auto message = PrepareTestData(data);
280 formats::json::Value json;
281 formats::json::Value sample;
282
283 UASSERT_NO_THROW((json = MessageToJson(message.field1(), {})));
284 UASSERT_NO_THROW((sample = CreateSampleJson(message.field1())));
285 EXPECT_EQ(json, sample);
286 EXPECT_TRUE(json.IsArray());
287 ASSERT_EQ(json.GetSize(), std::size_t{2});
288 EXPECT_EQ(json[0].As<double>(), 1.5);
289 EXPECT_EQ(json[1].As<double>(), 0);
290 }
291
292 {
293 ValueMessageData data{std::map<std::string, std::string>{}};
294 auto message = PrepareTestData(data);
295 formats::json::Value json;
296 formats::json::Value sample;
297
298 UASSERT_NO_THROW((json = MessageToJson(message.field1(), {})));
299 UASSERT_NO_THROW((sample = CreateSampleJson(message.field1())));
300 EXPECT_EQ(json, sample);
301 EXPECT_TRUE(json.IsObject());
302 ASSERT_EQ(json.GetSize(), std::size_t{0});
303 }
304
305 {
306 ValueMessageData data{std::map<std::string, std::string>{{"aaa", "hello"}, {"bbb", "world"}}};
307 auto message = PrepareTestData(data);
308 formats::json::Value json;
309 formats::json::Value sample;
310
311 UASSERT_NO_THROW((json = MessageToJson(message.field1(), {})));
312 UASSERT_NO_THROW((sample = CreateSampleJson(message.field1())));
313 EXPECT_EQ(json, sample);
314 EXPECT_TRUE(json.IsObject());
315 ASSERT_EQ(json.GetSize(), std::size_t{2});
316 ASSERT_TRUE(json.HasMember("aaa"));
317 ASSERT_TRUE(json.HasMember("bbb"));
318 EXPECT_EQ(json["aaa"].As<std::string>(), "hello");
319 EXPECT_EQ(json["bbb"].As<std::string>(), "world");
320 }
321}
322
323TEST(ValueToJsonAdditionalTest, InlinedNull) {
324 ValueMessageData data{std::monostate{}};
325 auto message = PrepareTestData(data);
326
327 EXPECT_PRINT_ERROR((void)MessageToJson(message.field1(), {}), PrintErrorCode::kInvalidValue, "/");
328}
329
330TEST(ValueToJsonAdditionalTest, DynamicMessage) {
331 using Message = ::google::protobuf::Value;
332 ::google::protobuf::DynamicMessageFactory factory;
333
334 {
335 std::unique_ptr<::google::protobuf::Message> message(factory.GetPrototype(Message::descriptor())->New());
336 const auto reflection = message->GetReflection();
337 const auto null_value_desc = message->GetDescriptor()->FindFieldByName("null_value");
338
339 reflection->SetEnumValue(message.get(), null_value_desc, 0);
340
341 formats::json::Value json;
342
343 UASSERT_NO_THROW((json = MessageToJson(*message, {})));
344 ASSERT_TRUE(json.IsNull());
345 }
346
347 {
348 std::unique_ptr<::google::protobuf::Message> message(factory.GetPrototype(Message::descriptor())->New());
349 const auto reflection = message->GetReflection();
350 const auto number_value_desc = message->GetDescriptor()->FindFieldByName("number_value");
351
352 reflection->SetDouble(message.get(), number_value_desc, 1.5);
353
354 formats::json::Value json;
355
356 UASSERT_NO_THROW((json = MessageToJson(*message, {})));
357 ASSERT_TRUE(json.IsNumber());
358 EXPECT_EQ(json.As<double>(), 1.5);
359 }
360
361 {
362 std::unique_ptr<::google::protobuf::Message> message(factory.GetPrototype(Message::descriptor())->New());
363 const auto reflection = message->GetReflection();
364 const auto number_value_desc = message->GetDescriptor()->FindFieldByName("string_value");
365
366 reflection->SetString(message.get(), number_value_desc, "hello");
367
368 formats::json::Value json;
369
370 UASSERT_NO_THROW((json = MessageToJson(*message, {})));
371 ASSERT_TRUE(json.IsString());
372 EXPECT_EQ(json.As<std::string>(), "hello");
373 }
374
375 {
376 std::unique_ptr<::google::protobuf::Message> message(factory.GetPrototype(Message::descriptor())->New());
377 const auto reflection = message->GetReflection();
378 const auto bool_value_desc = message->GetDescriptor()->FindFieldByName("bool_value");
379
380 reflection->SetBool(message.get(), bool_value_desc, true);
381
382 formats::json::Value json;
383
384 UASSERT_NO_THROW((json = MessageToJson(*message, {})));
385 ASSERT_TRUE(json.IsBool());
386 EXPECT_EQ(json.As<bool>(), true);
387 }
388
389 {
390 std::unique_ptr<::google::protobuf::Message> message(factory.GetPrototype(Message::descriptor())->New());
391 const auto reflection = message->GetReflection();
392 const auto list_value_desc = message->GetDescriptor()->FindFieldByName("list_value");
393 const auto list_value_message = reflection->MutableMessage(message.get(), list_value_desc, &factory);
394 const auto list_value_reflection = list_value_message->GetReflection();
395 const auto values_desc = list_value_message->GetDescriptor()->FindFieldByName("values");
396 const auto item_message = list_value_reflection->AddMessage(list_value_message, values_desc, &factory);
397 const auto item_reflection = item_message->GetReflection();
398 const auto number_value_desc = item_message->GetDescriptor()->FindFieldByName("number_value");
399
400 item_reflection->SetDouble(item_message, number_value_desc, 1.5);
401
402 formats::json::Value json;
403
404 UASSERT_NO_THROW((json = MessageToJson(*message, {})));
405 ASSERT_TRUE(json.IsArray());
406 ASSERT_EQ(json.GetSize(), std::size_t{1});
407 EXPECT_EQ(json[0].As<double>(), 1.5);
408 }
409
410 {
411 std::unique_ptr<::google::protobuf::Message> message(factory.GetPrototype(Message::descriptor())->New());
412 const auto reflection = message->GetReflection();
413 const auto struct_value_desc = message->GetDescriptor()->FindFieldByName("struct_value");
414 const auto struct_value_message = reflection->MutableMessage(message.get(), struct_value_desc, &factory);
415 const auto struct_value_reflection = struct_value_message->GetReflection();
416 const auto fields_desc = struct_value_message->GetDescriptor()->FindFieldByName("fields");
417 const auto item_message = struct_value_reflection->AddMessage(struct_value_message, fields_desc, &factory);
418 const auto item_reflection = item_message->GetReflection();
419 const auto map_key_desc = item_message->GetDescriptor()->map_key();
420 const auto map_value_desc = item_message->GetDescriptor()->map_value();
421 const auto map_value_message = item_reflection->MutableMessage(item_message, map_value_desc, &factory);
422 const auto map_value_reflection = map_value_message->GetReflection();
423 const auto number_value_desc = map_value_message->GetDescriptor()->FindFieldByName("number_value");
424
425 item_reflection->SetString(item_message, map_key_desc, "aaa");
426 map_value_reflection->SetDouble(map_value_message, number_value_desc, 1.5);
427
428 formats::json::Value json;
429
430 UASSERT_NO_THROW((json = MessageToJson(*message, {})));
431 ASSERT_TRUE(json.IsObject());
432 ASSERT_EQ(json.GetSize(), std::size_t{1});
433 ASSERT_TRUE(json.HasMember("aaa"));
434 EXPECT_EQ(json["aaa"].As<double>(), 1.5);
435 }
436}
437
438} // namespace protobuf::json::tests
439
440USERVER_NAMESPACE_END