1#include <gtest/gtest.h>
7#include <google/protobuf/dynamic_message.h>
9#include <userver/protobuf/json/convert.hpp>
10#include <userver/utest/assert_macros.hpp>
14USERVER_NAMESPACE_BEGIN
18struct AnyToJsonSuccessTestParam {
20 std::string expected_json = {};
21 WriteOptions options = {};
24 bool skip_native_check =
false;
27struct AnyToJsonFailureTestParam {
29 WriteErrorCode expected_errc = {};
30 std::string expected_path = {};
31 WriteOptions options = {};
34 bool skip_native_check =
false;
37class AnyToJsonSuccessTest :
public ::testing::TestWithParam<AnyToJsonSuccessTestParam> {};
38class AnyToJsonFailureTest :
public ::testing::TestWithParam<AnyToJsonFailureTestParam> {};
40INSTANTIATE_TEST_SUITE_P(
44 AnyToJsonSuccessTestParam{AnyMessageData{}, R"({})"},
45 AnyToJsonSuccessTestParam{AnyMessageData{RawAnyData{
"",
""}}, R"({"field1":{}})"},
46 AnyToJsonSuccessTestParam{
47 AnyMessageData{Int32MessageData{}},
49 "field1": {
50 "@type":"type.googleapis.com/proto_json.messages.Int32Message"
51 }
52 })",
56 AnyToJsonSuccessTestParam{
57 AnyMessageData{Int32MessageData{}},
59 "field1": {
60 "@type":"type.googleapis.com/proto_json.messages.Int32Message",
61 "field1":0,"field2":0,"field3":0
62 }
63 })",
64 {.always_print_fields_with_no_presence =
true},
67 AnyToJsonSuccessTestParam{
68 AnyMessageData{Int32MessageData{10, 20, 30}},
70 "field1": {
71 "@type":"type.googleapis.com/proto_json.messages.Int32Message",
72 "field1":10,"field2":20,"field3":30
73 }
74 })"
76 AnyToJsonSuccessTestParam{
77 AnyMessageData{DurationMessageData{123, 987}},
79 "field1": {
80 "@type":"type.googleapis.com/google.protobuf.Duration",
81 "value":"123.000000987s"
82 }
83 })"
85 AnyToJsonSuccessTestParam{
86 AnyMessageData{ValueMessageData{kProtoNullValue}},
88 "field1": {
89 "@type":"type.googleapis.com/google.protobuf.Value",
90 "value":null
91 }
92 })"
94 AnyToJsonSuccessTestParam{
95 AnyMessageData{ValueMessageData{1.5}},
97 "field1": {
98 "@type":"type.googleapis.com/google.protobuf.Value",
99 "value":1.5
100 }
101 })"
103 AnyToJsonSuccessTestParam{
104 AnyMessageData{ValueMessageData{std::vector<
double>{1.5, 1.5}}},
106 "field1": {
107 "@type":"type.googleapis.com/google.protobuf.Value",
108 "value":[1.5,1.5]
109 }
110 })"
112 AnyToJsonSuccessTestParam{
113 AnyMessageData{ValueMessageData{std::map<std::string, std::string>{{
"aaa",
"hello"}}}},
115 "field1": {
116 "@type":"type.googleapis.com/google.protobuf.Value",
117 "value":{"aaa":"hello"}
118 }
119 })"
121 AnyToJsonSuccessTestParam{
122 AnyMessageData{Int32MessageData{100, 200, 300},
true},
124 "field1": {
125 "@type":"type.googleapis.com/google.protobuf.Any",
126 "value": {
127 "@type":"type.googleapis.com/proto_json.messages.Int32Message",
128 "field1":100,"field2":200,"field3":300
129 }
130 }
131 })"
133 AnyToJsonSuccessTestParam{
134 AnyMessageData{DurationMessageData{-123, -567},
true},
136 "field1": {
137 "@type":"type.googleapis.com/google.protobuf.Any",
138 "value": {
139 "@type":"type.googleapis.com/google.protobuf.Duration",
140 "value":"-123.000000567s"
141 }
142 }
143 })"
145 AnyToJsonSuccessTestParam{
146 AnyMessageData{ValueMessageData{
true},
true},
148 "field1": {
149 "@type":"type.googleapis.com/google.protobuf.Any",
150 "value": {
151 "@type":"type.googleapis.com/google.protobuf.Value",
152 "value":true
153 }
154 }
155 })"
160INSTANTIATE_TEST_SUITE_P(
162 AnyToJsonFailureTest,
164 AnyToJsonFailureTestParam{AnyMessageData{RawAnyData{
"",
"\x08\x01"}}, WriteErrorCode::kInvalidValue,
"field1"},
165 AnyToJsonFailureTestParam{AnyMessageData{RawAnyData{
"oops",
""}}, WriteErrorCode::kInvalidValue,
"field1"},
166 AnyToJsonFailureTestParam{
167 AnyMessageData{RawAnyData{
"type.googleapis.com/proto_json.messages.NonExistent",
"\x08\x01"}},
168 WriteErrorCode::kInvalidValue,
172 AnyToJsonFailureTestParam{
173 AnyMessageData{RawAnyData{
"type.googleapis.com/proto_json.messages.Int32Message",
"\x80"}},
174 WriteErrorCode::kInvalidValue,
179 AnyToJsonFailureTestParam{AnyMessageData{DurationMessageData{1, -1}}, WriteErrorCode::kInvalidValue,
"field1"},
180 AnyToJsonFailureTestParam{
181 AnyMessageData{ValueMessageData{std::vector<
double>{std::numeric_limits<
double>::infinity()}}},
182 WriteErrorCode::kInvalidValue,
183 "field1.list_value.values[0].number_value"
188TEST_P(AnyToJsonSuccessTest, Test) {
189 const auto& param = GetParam();
191 auto input = PrepareTestData(param.input);
192 formats::json::Value json, expected_json, sample_json;
194 UASSERT_NO_THROW((json = MessageToJson(input, param.options)));
195 UASSERT_NO_THROW((expected_json = PrepareJsonTestData(param.expected_json)));
197 if (!param.skip_native_check) {
198 UASSERT_NO_THROW((sample_json = CreateSampleJson(input, param.options)));
199 EXPECT_EQ(json, sample_json);
202 EXPECT_EQ(json, expected_json);
205TEST_P(AnyToJsonFailureTest, Test) {
206 const auto& param = GetParam();
207 auto input = PrepareTestData(param.input);
209 EXPECT_WRITE_ERROR((
void)MessageToJson(input, param.options), param.expected_errc, param.expected_path);
211 if (!param.skip_native_check) {
212 UEXPECT_THROW((
void)CreateSampleJson(input, param.options), SampleError);
216TEST(AnyToJsonAdditionalTest, InlinedNonNull) {
218 auto message = PrepareTestData(data);
219 formats::json::Value json, sample;
221 UASSERT_NO_THROW((json = MessageToJson(message.field1())));
222 UASSERT_NO_THROW((sample = CreateSampleJson(message.field1())));
223 ASSERT_TRUE(json.IsObject());
224 EXPECT_EQ(json, sample);
225 EXPECT_EQ(json[
"@type"].As<std::string>(),
"type.googleapis.com/proto_json.messages.Int32Message");
226 EXPECT_EQ(json[
"field1"].As<std::int32_t>(), 1);
227 EXPECT_EQ(json[
"field2"].As<std::int32_t>(), 2);
228 EXPECT_EQ(json[
"field3"].As<std::int32_t>(), 3);
231TEST(AnyToJsonAdditionalTest, InlinedNull) {
232 proto_json::messages::AnyMessage message;
233 formats::json::Value json, sample;
235 UASSERT_NO_THROW((json = MessageToJson(message.field1())));
236 UASSERT_NO_THROW((sample = CreateSampleJson(message.field1())));
237 ASSERT_TRUE(json.IsObject());
238 EXPECT_EQ(json, sample);
239 EXPECT_EQ(json.GetSize(), std::size_t{0});
242TEST(AnyToJsonAdditionalTest, DynamicMessage) {
243 using Message = ::google::protobuf::Any;
244 using ProtobufStringType =
245 decltype(std::declval<::google::protobuf::Reflection>()
246 .GetString(std::declval<
const ::google::protobuf::Message&>(),
nullptr));
248 ::google::protobuf::DynamicMessageFactory factory;
249 proto_json::messages::Int32Message payload;
250 ProtobufStringType payload_str;
252 payload.set_field1(1001);
253 payload.set_field2(1002);
254 payload.set_field3(1003);
256 ASSERT_TRUE(payload.SerializeToString(&payload_str));
257 proto_json::messages::Int32Message payload2;
260 std::unique_ptr<::google::protobuf::Message> message(factory.GetPrototype(Message::descriptor())->New());
261 const auto reflection = message->GetReflection();
262 const auto type_url_desc = message->GetDescriptor()->FindFieldByName(
"type_url");
263 const auto value_desc = message->GetDescriptor()->FindFieldByName(
"value");
265 reflection->SetString(message.get(), type_url_desc,
"type.googleapis.com/proto_json.messages.Int32Message");
266 reflection->SetString(message.get(), value_desc, payload_str);
268 formats::json::Value json;
270 UASSERT_NO_THROW((json = MessageToJson(*message)));
271 ASSERT_TRUE(json.IsObject());
272 ASSERT_EQ(json.GetSize(), std::size_t{4});
273 EXPECT_EQ(json[
"@type"].As<std::string>(),
"type.googleapis.com/proto_json.messages.Int32Message");
274 EXPECT_EQ(json[
"field1"].As<std::int32_t>(), 1001);
275 EXPECT_EQ(json[
"field2"].As<std::int32_t>(), 1002);
276 EXPECT_EQ(json[
"field3"].As<std::int32_t>(), 1003);