1#include <gtest/gtest.h>
8#include <google/protobuf/dynamic_message.h>
10#include <userver/formats/json/serialize.hpp>
11#include <userver/protobuf/json/convert.hpp>
12#include <userver/utest/assert_macros.hpp>
16USERVER_NAMESPACE_BEGIN
18namespace protobuf::json::tests {
20struct AnyFromJsonSuccessTestParam {
21 std::string input = {};
26 bool skip_native_check =
false;
29struct AnyFromJsonFailureTestParam {
30 std::string input = {};
32 std::string expected_path = {};
36void PrintTo(
const AnyFromJsonSuccessTestParam& param, std::ostream* os) {
37 *os << fmt::format(
"{{ input = '{}' }}", param.input);
40void PrintTo(
const AnyFromJsonFailureTestParam& param, std::ostream* os) {
41 *os << fmt::format(
"{{ input = '{}' }}", param.input);
44class AnyFromJsonSuccessTest :
public ::testing::TestWithParam<AnyFromJsonSuccessTestParam> {};
45class AnyFromJsonFailureTest :
public ::testing::TestWithParam<AnyFromJsonFailureTestParam> {};
47INSTANTIATE_TEST_SUITE_P(
49 AnyFromJsonSuccessTest,
51 AnyFromJsonSuccessTestParam{R"({})", AnyMessageData{}},
52 AnyFromJsonSuccessTestParam{R"({"field1":null})", AnyMessageData{}},
53 AnyFromJsonSuccessTestParam{R"({"field1":{}})", AnyMessageData{RawAnyData{
"",
""}}},
54 AnyFromJsonSuccessTestParam{
56 "field1": {
57 "@type":"type.googleapis.com/proto_json.messages.Int32Message"
58 }
59 })",
60 AnyMessageData{Int32MessageData{}}
62 AnyFromJsonSuccessTestParam{
64 "field1": {
65 "@type":"type.googleapis.com/proto_json.messages.Int32Message",
66 "field1":0,"field2":0,"field3":0
67 }
68 })",
69 AnyMessageData{Int32MessageData{0, 0, 0}}
71 AnyFromJsonSuccessTestParam{
73 "field1": {
74 "@type":"type.googleapis.com/proto_json.messages.Int32Message",
75 "field1":null,"field2":null,"field3":1
76 }
77 })",
78 AnyMessageData{Int32MessageData{0, 0, 1}}
80 AnyFromJsonSuccessTestParam{
82 "field1": {
83 "@type":"type.googleapis.com/proto_json.messages.Int32Message",
84 "field1":10,"field2":20,"field3":30
85 }
86 })",
87 AnyMessageData{Int32MessageData{10, 20, 30}}
89 AnyFromJsonSuccessTestParam{
91 "field1": {
92 "@type":"type.googleapis.com/proto_json.messages.Int32Message",
93 "field1":10,"field2":20,"field3":30,"unknown_field":true
94 }
95 })",
96 AnyMessageData{Int32MessageData{10, 20, 30}},
97 {.ignore_unknown_fields =
true}
99 AnyFromJsonSuccessTestParam{
101 "field1": {
102 "@type":"type.googleapis.com/google.protobuf.Duration",
103 "value":"123.000000987s"
104 }
105 })",
106 AnyMessageData{DurationMessageData{123, 987}}
108 AnyFromJsonSuccessTestParam{
110 "field1": {
111 "@type":"type.googleapis.com/google.protobuf.Duration",
112 "value":"123.000000987s",
113 "unknown_field":true
114 }
115 })",
116 AnyMessageData{DurationMessageData{123, 987}},
117 {.ignore_unknown_fields =
true},
121 AnyFromJsonSuccessTestParam{
123 "field1": {
124 "@type":"type.googleapis.com/google.protobuf.Duration"
125 }
126 })",
127 AnyMessageData{DurationMessageData{0, 0}}
129 AnyFromJsonSuccessTestParam{
131 "field1": {
132 "@type":"type.googleapis.com/google.protobuf.Duration",
133 "value":null
134 }
135 })",
136 AnyMessageData{DurationMessageData{0, 0}}
138 AnyFromJsonSuccessTestParam{
140 "field1": {
141 "@type":"type.googleapis.com/google.protobuf.Value",
142 "value":null
143 }
144 })",
145 AnyMessageData{ValueMessageData{kProtoNullValue}}
147 AnyFromJsonSuccessTestParam{
149 "field1": {
150 "@type":"type.googleapis.com/google.protobuf.Value",
151 "value":"hello"
152 }
153 })",
154 AnyMessageData{ValueMessageData{
"hello"}}
156 AnyFromJsonSuccessTestParam{
158 "field1": {
159 "@type":"type.googleapis.com/google.protobuf.Value",
160 "value":[1.5,1.5]
161 }
162 })",
163 AnyMessageData{ValueMessageData{std::vector<
double>{1.5, 1.5}}}
165 AnyFromJsonSuccessTestParam{
167 "field1": {
168 "@type":"type.googleapis.com/google.protobuf.Value",
169 "value":{"aaa":"hello","bbb":"world"}
170 }
171 })",
172 AnyMessageData{ValueMessageData{std::map<std::string, std::string>{{
"aaa",
"hello"}, {
"bbb",
"world"}}}}
177INSTANTIATE_TEST_SUITE_P(
179 AnyFromJsonFailureTest,
185 AnyFromJsonFailureTestParam{
187 "field1": {
188 "@type":"oops"
189 }
190 })",
194 AnyFromJsonFailureTestParam{
196 "field1": {
197 "@type":"type.googleapis.com/proto_json.messages.NonExistent"
198 }
199 })",
203 AnyFromJsonFailureTestParam{
205 "field1": {
206 "@type":true
207 }
208 })",
212 AnyFromJsonFailureTestParam{
214 "field1": {
215 "value":"123.000000987s"
216 }
217 })",
221 AnyFromJsonFailureTestParam{
223 "field1": {
224 "field1":1
225 }
226 })",
230 AnyFromJsonFailureTestParam{
232 "field1": {
233 "@type":"type.googleapis.com/proto_json.messages.Int32Message",
234 "field1":10,"field2":20,"field3":30,"unknown_field":true
235 }
236 })",
238 "field1.unknown_field",
241 AnyFromJsonFailureTestParam{
243 "field1": {
244 "@type":"type.googleapis.com/google.protobuf.Duration",
245 "value":"123.000000987s",
246 "unknown_field":true
247 }
248 })",
250 "field1.unknown_field",
256TEST_P(AnyFromJsonSuccessTest, Test) {
257 const auto& param = GetParam();
259 proto_json::messages::AnyMessage message;
260 proto_json::messages::AnyMessage expected_message;
261 proto_json::messages::AnyMessage sample_message;
262 formats::
json::
Value input = PrepareJsonTestData(param.input);
263 expected_message = PrepareTestData(param.expected_message);
265 message.mutable_field1()->set_type_url(
"dump");
267 UASSERT_NO_THROW((message = JsonToMessage<proto_json::messages::AnyMessage>(input, param.options)));
269 if (!param.skip_native_check) {
270 UASSERT_NO_THROW(InitSampleMessage(param.input, sample_message, param.options));
271 CheckMessageEqual(message, sample_message);
274 CheckMessageEqual(message, expected_message);
277TEST_P(AnyFromJsonFailureTest, Test) {
278 const auto& param = GetParam();
280 proto_json::messages::AnyMessage sample_message;
281 formats::
json::
Value input = PrepareJsonTestData(param.input);
284 (
void)JsonToMessage<proto_json::messages::AnyMessage>(input, param.options),
291TEST(AnyFromJsonAdditionalTest, InlinedNonNull) {
292 using Message = ::google::protobuf::Any;
294 const char* json_str =
296 "@type":"type.googleapis.com/proto_json.messages.Int32Message",
297 "field1":1,"field2":2,"field3":3
298 })";
302 proto_json::messages::Int32Message payload;
304 message.set_type_url(
"dump");
308 ASSERT_TRUE(message.Is<proto_json::messages::Int32Message>());
309 ASSERT_TRUE(message.UnpackTo(&payload));
311 EXPECT_EQ(payload.field1(), 1);
312 EXPECT_EQ(payload.field2(), 2);
313 EXPECT_EQ(payload.field3(), 3);
314 CheckMessageEqual(message, sample);
317TEST(AnyFromJsonAdditionalTest, InlinedNull) {
318 using Message = ::google::protobuf::Any;
333 message.set_type_url(
"dump");
338 EXPECT_TRUE(message.type_url().empty());
339 EXPECT_TRUE(message.value().empty());
340 CheckMessageEqual(message, sample);
344TEST(AnyFromJsonAdditionalTest, DynamicMessage) {
345 using Message = ::google::protobuf::Any;
347 const char* json_str =
349 "@type":"type.googleapis.com/proto_json.messages.Int32Message",
350 "field1":1,"field2":2,"field3":3
351 })";
354 proto_json::messages::Int32Message payload;
355 ::google::protobuf::DynamicMessageFactory factory;
358 std::unique_ptr<::google::protobuf::Message> message(factory.GetPrototype(Message::descriptor())->New());
362 const auto reflection = message->GetReflection();
363 const auto type_url_desc = message->GetDescriptor()->FindFieldByName(
"type_url");
364 const auto value_desc = message->GetDescriptor()->FindFieldByName(
"value");
367 reflection->GetString(*message, type_url_desc),
368 "type.googleapis.com/proto_json.messages.Int32Message"
370 ASSERT_TRUE(payload.ParseFromString(reflection->GetString(*message, value_desc)));
371 EXPECT_EQ(payload.field1(), 1);
372 EXPECT_EQ(payload.field2(), 2);
373 EXPECT_EQ(payload.field3(), 3);