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
20struct AnyFromJsonSuccessTestParam {
21 std::string input = {};
23 ReadOptions options = {};
26 bool skip_native_check =
false;
29struct AnyFromJsonFailureTestParam {
30 std::string input = {};
31 ReadErrorCode expected_errc = {};
32 std::string expected_path = {};
33 ReadOptions options = {};
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},
120 AnyFromJsonSuccessTestParam{
122 "field1": {
123 "@type":"type.googleapis.com/google.protobuf.Duration"
124 }
125 })",
126 AnyMessageData{DurationMessageData{0, 0}}
128 AnyFromJsonSuccessTestParam{
130 "field1": {
131 "@type":"type.googleapis.com/google.protobuf.Duration",
132 "value":null
133 }
134 })",
135 AnyMessageData{DurationMessageData{0, 0}}
137 AnyFromJsonSuccessTestParam{
139 "field1": {
140 "@type":"type.googleapis.com/google.protobuf.Value",
141 "value":null
142 }
143 })",
144 AnyMessageData{ValueMessageData{kProtoNullValue}}
146 AnyFromJsonSuccessTestParam{
148 "field1": {
149 "@type":"type.googleapis.com/google.protobuf.Value",
150 "value":"hello"
151 }
152 })",
153 AnyMessageData{ValueMessageData{
"hello"}}
155 AnyFromJsonSuccessTestParam{
157 "field1": {
158 "@type":"type.googleapis.com/google.protobuf.Value",
159 "value":[1.5,1.5]
160 }
161 })",
162 AnyMessageData{ValueMessageData{std::vector<
double>{1.5, 1.5}}}
164 AnyFromJsonSuccessTestParam{
166 "field1": {
167 "@type":"type.googleapis.com/google.protobuf.Value",
168 "value":{"aaa":"hello","bbb":"world"}
169 }
170 })",
171 AnyMessageData{ValueMessageData{std::map<std::string, std::string>{{
"aaa",
"hello"}, {
"bbb",
"world"}}}}
176INSTANTIATE_TEST_SUITE_P(
178 AnyFromJsonFailureTest,
180 AnyFromJsonFailureTestParam{R"({"field1":[]})", ReadErrorCode::kInvalidType,
"field1"},
181 AnyFromJsonFailureTestParam{R"({"field1":true})", ReadErrorCode::kInvalidType,
"field1"},
182 AnyFromJsonFailureTestParam{R"({"field1":1})", ReadErrorCode::kInvalidType,
"field1"},
183 AnyFromJsonFailureTestParam{R"({"field1":"hello"})", ReadErrorCode::kInvalidType,
"field1"},
184 AnyFromJsonFailureTestParam{
186 "field1": {
187 "@type":"oops"
188 }
189 })",
190 ReadErrorCode::kInvalidValue,
193 AnyFromJsonFailureTestParam{
195 "field1": {
196 "@type":"type.googleapis.com/proto_json.messages.NonExistent"
197 }
198 })",
199 ReadErrorCode::kInvalidValue,
202 AnyFromJsonFailureTestParam{
204 "field1": {
205 "@type":true
206 }
207 })",
208 ReadErrorCode::kInvalidValue,
211 AnyFromJsonFailureTestParam{
213 "field1": {
214 "value":"123.000000987s"
215 }
216 })",
217 ReadErrorCode::kInvalidValue,
220 AnyFromJsonFailureTestParam{
222 "field1": {
223 "field1":1
224 }
225 })",
226 ReadErrorCode::kInvalidValue,
229 AnyFromJsonFailureTestParam{
231 "field1": {
232 "@type":"type.googleapis.com/proto_json.messages.Int32Message",
233 "field1":10,"field2":20,"field3":30,"unknown_field":true
234 }
235 })",
236 ReadErrorCode::kUnknownField,
237 "field1.unknown_field",
238 {.ignore_unknown_fields =
false}
240 AnyFromJsonFailureTestParam{
242 "field1": {
243 "@type":"type.googleapis.com/google.protobuf.Duration",
244 "value":"123.000000987s",
245 "unknown_field":true
246 }
247 })",
248 ReadErrorCode::kUnknownField,
249 "field1.unknown_field",
250 {.ignore_unknown_fields =
false}
255TEST_P(AnyFromJsonSuccessTest, Test) {
256 const auto& param = GetParam();
258 proto_json::messages::AnyMessage message, expected_message, sample_message;
259 formats::json::Value input = PrepareJsonTestData(param.input);
260 expected_message = PrepareTestData(param.expected_message);
262 message.mutable_field1()->set_type_url(
"dump");
264 UASSERT_NO_THROW((message = JsonToMessage<proto_json::messages::AnyMessage>(input, param.options)));
266 if (!param.skip_native_check) {
267 UASSERT_NO_THROW(InitSampleMessage(param.input, param.options, sample_message));
268 CheckMessageEqual(message, sample_message);
271 CheckMessageEqual(message, expected_message);
274TEST_P(AnyFromJsonFailureTest, Test) {
275 const auto& param = GetParam();
277 proto_json::messages::AnyMessage sample_message;
278 formats::json::Value input = PrepareJsonTestData(param.input);
281 (
void)JsonToMessage<proto_json::messages::AnyMessage>(input, param.options),
285 UEXPECT_THROW(InitSampleMessage(param.input, param.options, sample_message), SampleError);
288TEST(AnyFromJsonAdditionalTest, InlinedNonNull) {
289 using Message = ::google::protobuf::Any;
291 const char* json_str =
293 "@type":"type.googleapis.com/proto_json.messages.Int32Message",
294 "field1":1,"field2":2,"field3":3
295 })";
296 const auto json = formats::json::FromString(json_str);
297 Message message, sample;
298 proto_json::messages::Int32Message payload;
300 message.set_type_url(
"dump");
302 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
303 UASSERT_NO_THROW(InitSampleMessage(json_str, {}, sample));
304 ASSERT_TRUE(message.Is<proto_json::messages::Int32Message>());
305 ASSERT_TRUE(message.UnpackTo(&payload));
307 EXPECT_EQ(payload.field1(), 1);
308 EXPECT_EQ(payload.field2(), 2);
309 EXPECT_EQ(payload.field3(), 3);
310 CheckMessageEqual(message, sample);
313TEST(AnyFromJsonAdditionalTest, InlinedNull) {
314 using Message = ::google::protobuf::Any;
317 const auto json = formats::json::FromString(
"null");
320 EXPECT_READ_ERROR((message = JsonToMessage<Message>(json)), ReadErrorCode::kInvalidType,
"/");
321 UEXPECT_THROW(InitSampleMessage(
"null", {}, message), SampleError);
325 const auto json = formats::json::FromString(
"{}");
326 Message message, sample;
328 message.set_type_url(
"dump");
330 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
331 UASSERT_NO_THROW(InitSampleMessage(
"{}", {}, sample));
333 EXPECT_TRUE(message.type_url().empty());
334 EXPECT_TRUE(message.value().empty());
335 CheckMessageEqual(message, sample);
339TEST(AnyFromJsonAdditionalTest, DynamicMessage) {
340 using Message = ::google::protobuf::Any;
342 const char* json_str =
344 "@type":"type.googleapis.com/proto_json.messages.Int32Message",
345 "field1":1,"field2":2,"field3":3
346 })";
347 const auto json = formats::json::FromString(json_str);
349 proto_json::messages::Int32Message payload;
350 ::google::protobuf::DynamicMessageFactory factory;
353 std::unique_ptr<::google::protobuf::Message> message(factory.GetPrototype(Message::descriptor())->New());
355 UASSERT_NO_THROW(JsonToMessage(json, {}, *message));
357 const auto reflection = message->GetReflection();
358 const auto type_url_desc = message->GetDescriptor()->FindFieldByName(
"type_url");
359 const auto value_desc = message->GetDescriptor()->FindFieldByName(
"value");
362 reflection->GetString(*message, type_url_desc),
363 "type.googleapis.com/proto_json.messages.Int32Message"
365 ASSERT_TRUE(payload.ParseFromString(reflection->GetString(*message, value_desc)));
366 EXPECT_EQ(payload.field1(), 1);
367 EXPECT_EQ(payload.field2(), 2);
368 EXPECT_EQ(payload.field3(), 3);