13#include <fmt/format.h>
14#include <google/protobuf/message.h>
15#include <gtest/gtest.h>
17#include <userver/formats/json/value.hpp>
18#include <userver/formats/parse/common.hpp>
19#include <userver/protobuf/json/convert_options.hpp>
20#include <userver/protobuf/json/exceptions.hpp>
22#include "proto_json/messages.pb.h"
29 kIsModernProtoJson = (GOOGLE_PROTOBUF_VERSION >= 4022005);
32#define EXPECT_PRINT_ERROR(EXPR, CODE, PATH)
35 ADD_FAILURE
() << "Should throw 'PrintError' exception";
36 } catch (const protobuf::json::PrintError& error) {
37 EXPECT_EQ
(error.GetErrorInfo().GetCode(), (CODE));
38 EXPECT_EQ
(error.GetErrorInfo().GetPath(), (PATH));
40 ADD_FAILURE
() << "Unexpected exception, should be 'PrintError'";
44#define EXPECT_PARSE_ERROR(EXPR, CODE, PATH)
47 ADD_FAILURE
() << "Should throw 'ParseError' exception";
48 } catch (const protobuf::json::ParseError& error) {
49 EXPECT_EQ
(error.GetErrorInfo().GetCode(), (CODE));
50 EXPECT_EQ
(error.GetErrorInfo().GetPath(), (PATH));
52 ADD_FAILURE
() << "Unexpected exception, should be 'ParseError'";
56struct fmt::formatter<USERVER_NAMESPACE::protobuf::json::PrintOptions> {
57 constexpr auto parse(fmt::format_parse_context& ctx) {
return ctx.begin(); }
59 template <
typename FormatContext>
60 auto format(
const USERVER_NAMESPACE::protobuf::json::PrintOptions& options, FormatContext& ctx)
const
61 ->
decltype(ctx.out()) {
62 return fmt::format_to(
64 "{{always_print_fields_with_no_presence={}, always_print_enums_as_ints={}, preserve_proto_field_names={}, "
65 "nonportable_raw_any={}}}",
66 options.always_print_fields_with_no_presence,
67 options.always_print_enums_as_ints,
68 options.preserve_proto_field_names,
69 options.nonportable_raw_any
75struct fmt::formatter<USERVER_NAMESPACE::protobuf::json::ParseOptions> {
76 constexpr auto parse(fmt::format_parse_context& ctx) {
return ctx.begin(); }
78 template <
typename FormatContext>
79 auto format(
const USERVER_NAMESPACE::protobuf::json::ParseOptions& options, FormatContext& ctx)
const
80 ->
decltype(ctx.out()) {
81 return fmt::format_to(
83 "{{ignore_unknown_fields={}, nonportable_raw_any={}}}",
84 options.ignore_unknown_fields,
85 options.nonportable_raw_any
91struct fmt::formatter<USERVER_NAMESPACE::protobuf::json::PrintErrorCode> {
92 constexpr auto parse(fmt::format_parse_context& ctx) {
return ctx.begin(); }
94 template <
typename FormatContext>
95 auto format(
const USERVER_NAMESPACE::protobuf::json::PrintErrorCode& code, FormatContext& ctx)
const
96 ->
decltype(ctx.out()) {
98 case USERVER_NAMESPACE::protobuf::json::PrintErrorCode::kInvalidValue:
99 return fmt::format_to(ctx.out(),
"kInvalidValue");
101 return fmt::format_to(ctx.out(),
"UNKNOWN");
107struct fmt::formatter<USERVER_NAMESPACE::protobuf::json::ParseErrorCode> {
108 constexpr auto parse(fmt::format_parse_context& ctx) {
return ctx.begin(); }
110 template <
typename FormatContext>
111 auto format(
const USERVER_NAMESPACE::protobuf::json::ParseErrorCode& code, FormatContext& ctx)
const
112 ->
decltype(ctx.out()) {
114 case USERVER_NAMESPACE::protobuf::json::ParseErrorCode::kUnknownField:
115 return fmt::format_to(ctx.out(),
"kUnknownField");
116 case USERVER_NAMESPACE::protobuf::json::ParseErrorCode::kUnknownEnum:
117 return fmt::format_to(ctx.out(),
"kUnknownEnum");
118 case USERVER_NAMESPACE::protobuf::json::ParseErrorCode::kMultipleOneofFields:
119 return fmt::format_to(ctx.out(),
"kMultipleOneofFields");
120 case USERVER_NAMESPACE::protobuf::json::ParseErrorCode::kInvalidType:
121 return fmt::format_to(ctx.out(),
"kInvalidType");
122 case USERVER_NAMESPACE::protobuf::json::ParseErrorCode::kInvalidValue:
123 return fmt::format_to(ctx.out(),
"kInvalidValue");
125 return fmt::format_to(ctx.out(),
"UNKNOWN");
130USERVER_NAMESPACE_BEGIN
132namespace protobuf::json::tests {
134constexpr inline ::google::protobuf::NullValue kNullConst = ::google::protobuf::NullValue::NULL_VALUE;
138 using std::runtime_error::runtime_error;
144using ProtoValue = std::variant<
151 std::map<std::string, std::string>>;
153formats::
json::
Value PrepareJsonTestData(
const std::string& json_data);
155formats::
json::
Value CreateSampleJson(
const ::google::protobuf::Message& message,
const PrintOptions& options = {});
157void InitSampleMessage(
const std::string& json, ::google::protobuf::Message& message,
const ParseOptions& options = {});
159::google::protobuf::Value ProtoValueToNative(
const ProtoValue& data);
162 std::int32_t field1 = 0;
163 std::int32_t field2 = 0;
164 std::int32_t field3 = 0;
168 std::uint32_t field1 = 0;
169 std::uint32_t field2 = 0;
173 std::int64_t field1 = 0;
174 std::int64_t field2 = 0;
175 std::int64_t field3 = 0;
179 std::uint64_t field1 = 0;
180 std::uint64_t field2 = 0;
196 std::string field1 = {};
200 std::string field1 = {};
205 std::optional<proto_json::messages::EnumMessage::Test> field2 = {};
209 std::optional<std::int32_t> field1 = {};
213 std::optional<
double> field1 = {};
214 std::optional<
float> field2 = {};
215 std::optional<std::int64_t> field3 = {};
216 std::optional<std::uint64_t> field4 = {};
217 std::optional<std::int32_t> field5 = {};
218 std::optional<std::uint32_t> field6 = {};
219 std::optional<
bool> field7 = {};
220 std::optional<std::string> field8 = {};
221 std::optional<std::string> field9 = {};
225 std::optional<std::vector<std::string>> field1 = {};
229 std::int64_t seconds = 0;
230 std::int32_t nanos = 0;
231 bool do_not_set =
false;
235 std::int64_t seconds = 0;
236 std::int32_t nanos = 0;
237 bool do_not_set =
false;
245 std::string type_url = {};
246 std::string value = {};
251 bool add_nesting =
false;
255 std::optional<std::int32_t> field1 = {};
256 std::optional<std::string> field2 = {};
260 std::vector<std::int32_t> field1 = {};
261 std::vector<BoolMessageData> field2 = {};
262 std::vector<DurationMessageData> field3 = {};
263 std::vector<ProtoValue> field4 = {};
264 std::vector<std::uint32_t> field5 = {};
265 std::vector<std::int64_t> field6 = {};
266 std::vector<std::uint64_t> field7 = {};
267 std::vector<
float> field8 = {};
268 std::vector<
double> field9 = {};
269 std::vector<
bool> field10 = {};
270 std::vector<std::string> field11 = {};
271 std::vector<proto_json::messages::RepeatedMessage::Test> field12 = {};
275 std::map<std::int32_t, std::int32_t> field1 = {};
276 std::map<std::uint32_t,
double> field2 = {};
277 std::map<std::int64_t,
bool> field3 = {};
278 std::map<std::uint64_t, std::string> field4 = {};
279 std::map<
bool, proto_json::messages::MapMessage::TestEnum> field5 = {};
280 std::map<std::string, BoolMessageData> field6 = {};
281 std::map<std::string, DurationMessageData> field7 = {};
282 std::map<std::int32_t, ProtoValue> field8 = {};
286 ::google::protobuf::NullValue field1 = {};
287 std::optional<::google::protobuf::NullValue> field2 = {};
288 std::vector<::google::protobuf::NullValue> field3 = {};
289 std::map<std::int32_t, ::google::protobuf::NullValue> field4 = {};
294 std::optional<
bool> field2 = {};
296 std::vector<
bool> field4 = {};
297 std::map<std::int32_t,
bool> field5 = {};
302 std::vector<StringMessageData> field2 = {};
303 std::map<std::int32_t, StringMessageData> field3 = {};
306proto_json::messages::Int32Message PrepareTestData(
const Int32MessageData& message_data);
307void CheckMessageEqual(
const proto_json::messages::Int32Message& lhs,
const proto_json::messages::Int32Message& rhs);
309proto_json::messages::UInt32Message PrepareTestData(
const UInt32MessageData& message_data);
310void CheckMessageEqual(
const proto_json::messages::UInt32Message& lhs,
const proto_json::messages::UInt32Message& rhs);
312proto_json::messages::Int64Message PrepareTestData(
const Int64MessageData& message_data);
313void CheckMessageEqual(
const proto_json::messages::Int64Message& lhs,
const proto_json::messages::Int64Message& rhs);
315proto_json::messages::UInt64Message PrepareTestData(
const UInt64MessageData& message_data);
316void CheckMessageEqual(
const proto_json::messages::UInt64Message& lhs,
const proto_json::messages::UInt64Message& rhs);
318proto_json::messages::FloatMessage PrepareTestData(
const FloatMessageData& message_data);
319void CheckMessageEqual(
const proto_json::messages::FloatMessage& lhs,
const proto_json::messages::FloatMessage& rhs);
321proto_json::messages::DoubleMessage PrepareTestData(
const DoubleMessageData& message_data);
322void CheckMessageEqual(
const proto_json::messages::DoubleMessage& lhs,
const proto_json::messages::DoubleMessage& rhs);
324proto_json::messages::BoolMessage PrepareTestData(
const BoolMessageData& message_data);
325void CheckMessageEqual(
const proto_json::messages::BoolMessage& lhs,
const proto_json::messages::BoolMessage& rhs);
327proto_json::messages::StringMessage PrepareTestData(
const StringMessageData& message_data);
328void CheckMessageEqual(
const proto_json::messages::StringMessage& lhs,
const proto_json::messages::StringMessage& rhs);
330proto_json::messages::BytesMessage PrepareTestData(
const BytesMessageData& message_data);
331void CheckMessageEqual(
const proto_json::messages::BytesMessage& lhs,
const proto_json::messages::BytesMessage& rhs);
333proto_json::messages::EnumMessage PrepareTestData(
const EnumMessageData& message_data);
334void CheckMessageEqual(
const proto_json::messages::EnumMessage& lhs,
const proto_json::messages::EnumMessage& rhs);
336proto_json::messages::NestedMessage PrepareTestData(
const NestedMessageData& message_data);
337void CheckMessageEqual(
const proto_json::messages::NestedMessage& lhs,
const proto_json::messages::NestedMessage& rhs);
339proto_json::messages::WrapperMessage PrepareTestData(
const WrapperMessageData& message_data);
340void CheckMessageEqual(
341 const proto_json::messages::WrapperMessage& lhs,
342 const proto_json::messages::WrapperMessage& rhs
345proto_json::messages::FieldMaskMessage PrepareTestData(
const FieldMaskMessageData& message_data);
346void CheckMessageEqual(
const ::google::protobuf::FieldMask& lhs,
const ::google::protobuf::FieldMask& rhs);
347void CheckMessageEqual(
348 const proto_json::messages::FieldMaskMessage& lhs,
349 const proto_json::messages::FieldMaskMessage& rhs
352proto_json::messages::DurationMessage PrepareTestData(
const DurationMessageData& message_data);
353void CheckMessageEqual(
const ::google::protobuf::Duration& lhs,
const ::google::protobuf::Duration& rhs);
354void CheckMessageEqual(
355 const proto_json::messages::DurationMessage& lhs,
356 const proto_json::messages::DurationMessage& rhs
359proto_json::messages::TimestampMessage PrepareTestData(
const TimestampMessageData& message_data);
360void CheckMessageEqual(
const ::google::protobuf::Timestamp& lhs,
const ::google::protobuf::Timestamp& rhs);
361void CheckMessageEqual(
362 const proto_json::messages::TimestampMessage& lhs,
363 const proto_json::messages::TimestampMessage& rhs
366proto_json::messages::ValueMessage PrepareTestData(
const ValueMessageData& message_data);
367void CheckMessageEqual(
const ::google::protobuf::Value& lhs,
const ::google::protobuf::Value& rhs);
368void CheckMessageEqual(
const ::google::protobuf::ListValue& lhs,
const ::google::protobuf::ListValue& rhs);
369void CheckMessageEqual(
const ::google::protobuf::Struct& lhs,
const ::google::protobuf::Struct& rhs);
370void CheckMessageEqual(
const proto_json::messages::ValueMessage& lhs,
const proto_json::messages::ValueMessage& rhs);
372proto_json::messages::AnyMessage PrepareTestData(
const AnyMessageData& message_data);
373void CheckMessageEqual(
const ::google::protobuf::Any& lhs,
const ::google::protobuf::Any& rhs);
374void CheckMessageEqual(
const proto_json::messages::AnyMessage& lhs,
const proto_json::messages::AnyMessage& rhs);
376proto_json::messages::OneofMessage PrepareTestData(
const OneofMessageData& message_data);
377void CheckMessageEqual(
const proto_json::messages::OneofMessage& lhs,
const proto_json::messages::OneofMessage& rhs);
379proto_json::messages::RepeatedMessage PrepareTestData(
const RepeatedMessageData& message_data);
380void CheckMessageEqual(
381 const proto_json::messages::RepeatedMessage& lhs,
382 const proto_json::messages::RepeatedMessage& rhs
385proto_json::messages::MapMessage PrepareTestData(
const MapMessageData& message_data);
386void CheckMessageEqual(
const proto_json::messages::MapMessage& lhs,
const proto_json::messages::MapMessage& rhs);
388proto_json::messages::NullValueMessage PrepareTestData(
const NullValueMessageData& message_data);
389void CheckMessageEqual(
390 const proto_json::messages::NullValueMessage& lhs,
391 const proto_json::messages::NullValueMessage& rhs
394proto_json::messages::PresenceMessage PrepareTestData(
const PresenceMessageData& message_data);
395void CheckMessageEqual(
396 const proto_json::messages::PresenceMessage& lhs,
397 const proto_json::messages::PresenceMessage& rhs
400proto_json::messages::UnknownFieldMessage PrepareTestData(
const UnknownFieldMessageData& message_data);
401void CheckMessageEqual(
402 const proto_json::messages::UnknownFieldMessage& lhs,
403 const proto_json::messages::UnknownFieldMessage& rhs
408 static constexpr const char* kJson = R"({"field1":"NaN"})";
409 static constexpr FloatMessageData kValue = {std::numeric_limits<
float>::quiet_NaN()};
410 static constexpr bool kSkip = !std::numeric_limits<
float>::has_quiet_NaN;
415 static constexpr const char* kJson = R"({"field1":"NaN"})";
416 static constexpr FloatMessageData kValue = {std::numeric_limits<
float>::signaling_NaN()};
417 static constexpr bool kSkip = !std::numeric_limits<
float>::has_signaling_NaN;
422 static constexpr const char* kJson = R"({"field1":"Infinity"})";
423 static constexpr FloatMessageData kValue = {std::numeric_limits<
float>::infinity()};
424 static constexpr bool kSkip = !std::numeric_limits<
float>::has_infinity;
429 static constexpr const char* kJson = R"({"field1":"-Infinity"})";
430 static constexpr FloatMessageData kValue = {-std::numeric_limits<
float>::infinity()};
431 static constexpr bool kSkip = !std::numeric_limits<
float>::has_infinity;
436 static constexpr const char* kJson = R"({"field1":"NaN"})";
437 static constexpr DoubleMessageData kValue = {std::numeric_limits<
double>::quiet_NaN()};
438 static constexpr bool kSkip = !std::numeric_limits<
double>::has_quiet_NaN;
443 static constexpr const char* kJson = R"({"field1":"NaN"})";
444 static constexpr DoubleMessageData kValue = {std::numeric_limits<
double>::signaling_NaN()};
445 static constexpr bool kSkip = !std::numeric_limits<
double>::has_signaling_NaN;
450 static constexpr const char* kJson = R"({"field1":"Infinity"})";
451 static constexpr DoubleMessageData kValue = {std::numeric_limits<
double>::infinity()};
452 static constexpr bool kSkip = !std::numeric_limits<
double>::has_infinity;
457 static constexpr const char* kJson = R"({"field1":"-Infinity"})";
458 static constexpr DoubleMessageData kValue = {-std::numeric_limits<
double>::infinity()};
459 static constexpr bool kSkip = !std::numeric_limits<
double>::has_infinity;
464 static constexpr double kValue = 1.5;
465 static constexpr const char* kJson =
"1.5";
470 static constexpr float kValue = 1.5;
471 static constexpr const char* kJson =
"1.5";
476 static constexpr std::int64_t kValue = -123;
477 static constexpr const char* kJson =
"-123";
482 static constexpr std::uint64_t kValue = 123;
483 static constexpr const char* kJson =
"123";
488 static constexpr std::int32_t kValue = -321;
489 static constexpr const char* kJson =
"-321";
494 static constexpr std::uint32_t kValue = 321;
495 static constexpr const char* kJson =
"321";
500 static constexpr bool kValue =
true;
501 static constexpr const char* kJson =
"true";
506 static constexpr std::string_view kValue =
"hello";
507 static constexpr const char* kJson =
"\"hello\"";
512 static constexpr std::string_view kValue =
"world";
513 static constexpr const char* kJson =
"\"d29ybGQ=\"";
516template <
typename TParam>
517using WrappedType = std::conditional_t<
518 !std::is_same_v<std::decay_t<
decltype(TParam::kValue)>, std::string_view>,
519 std::decay_t<
decltype(TParam::kValue)>,