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) {
58 auto it = ctx.begin();
59 if (it != ctx.end() && *it !=
'}') {
60 throw fmt::format_error(
"invalid format");
65 template <
typename FormatContext>
66 auto format(
const USERVER_NAMESPACE::protobuf::json::PrintOptions& options, FormatContext& ctx)
const
67 ->
decltype(ctx.out()) {
68 return fmt::format_to(
70 "{{always_print_fields_with_no_presence={}, always_print_enums_as_ints={}, preserve_proto_field_names={}}}",
71 options.always_print_fields_with_no_presence,
72 options.always_print_enums_as_ints,
73 options.preserve_proto_field_names
79struct fmt::formatter<USERVER_NAMESPACE::protobuf::json::ParseOptions> {
80 constexpr auto parse(fmt::format_parse_context& ctx) {
81 auto it = ctx.begin();
82 if (it != ctx.end() && *it !=
'}') {
83 throw fmt::format_error(
"invalid format");
88 template <
typename FormatContext>
89 auto format(
const USERVER_NAMESPACE::protobuf::json::ParseOptions& options, FormatContext& ctx)
const
90 ->
decltype(ctx.out()) {
91 return fmt::format_to(ctx.out(),
"{{ignore_unknown_fields={}}}", options.ignore_unknown_fields);
96struct fmt::formatter<USERVER_NAMESPACE::protobuf::json::PrintErrorCode> {
97 constexpr auto parse(fmt::format_parse_context& ctx) {
98 auto it = ctx.begin();
99 if (it != ctx.end() && *it !=
'}') {
100 throw fmt::format_error(
"invalid format");
105 template <
typename FormatContext>
106 auto format(
const USERVER_NAMESPACE::protobuf::json::PrintErrorCode& code, FormatContext& ctx)
const
107 ->
decltype(ctx.out()) {
109 case USERVER_NAMESPACE::protobuf::json::PrintErrorCode::kInvalidValue:
110 return fmt::format_to(ctx.out(),
"kInvalidValue");
112 return fmt::format_to(ctx.out(),
"UNKNOWN");
118struct fmt::formatter<USERVER_NAMESPACE::protobuf::json::ParseErrorCode> {
119 constexpr auto parse(fmt::format_parse_context& ctx) {
120 auto it = ctx.begin();
121 if (it != ctx.end() && *it !=
'}') {
122 throw fmt::format_error(
"invalid format");
127 template <
typename FormatContext>
128 auto format(
const USERVER_NAMESPACE::protobuf::json::ParseErrorCode& code, FormatContext& ctx)
const
129 ->
decltype(ctx.out()) {
131 case USERVER_NAMESPACE::protobuf::json::ParseErrorCode::kUnknownField:
132 return fmt::format_to(ctx.out(),
"kUnknownField");
133 case USERVER_NAMESPACE::protobuf::json::ParseErrorCode::kUnknownEnum:
134 return fmt::format_to(ctx.out(),
"kUnknownEnum");
135 case USERVER_NAMESPACE::protobuf::json::ParseErrorCode::kMultipleOneofFields:
136 return fmt::format_to(ctx.out(),
"kMultipleOneofFields");
137 case USERVER_NAMESPACE::protobuf::json::ParseErrorCode::kInvalidType:
138 return fmt::format_to(ctx.out(),
"kInvalidType");
139 case USERVER_NAMESPACE::protobuf::json::ParseErrorCode::kInvalidValue:
140 return fmt::format_to(ctx.out(),
"kInvalidValue");
142 return fmt::format_to(ctx.out(),
"UNKNOWN");
147USERVER_NAMESPACE_BEGIN
149namespace protobuf::json::tests {
151constexpr inline ::google::protobuf::NullValue kNullConst = ::google::protobuf::NullValue::NULL_VALUE;
155 using std::runtime_error::runtime_error;
161using ProtoValue = std::variant<
168 std::map<std::string, std::string>>;
170formats::
json::
Value PrepareJsonTestData(
const std::string& json_data);
172formats::
json::
Value CreateSampleJson(
const ::google::protobuf::Message& message,
const PrintOptions& options = {});
174void InitSampleMessage(
const std::string& json, ::google::protobuf::Message& message,
const ParseOptions& options = {});
176::google::protobuf::Value ProtoValueToNative(
const ProtoValue& data);
179 std::int32_t field1 = 0;
180 std::int32_t field2 = 0;
181 std::int32_t field3 = 0;
185 std::uint32_t field1 = 0;
186 std::uint32_t field2 = 0;
190 std::int64_t field1 = 0;
191 std::int64_t field2 = 0;
192 std::int64_t field3 = 0;
196 std::uint64_t field1 = 0;
197 std::uint64_t field2 = 0;
213 std::string field1 = {};
217 std::string field1 = {};
222 std::optional<proto_json::messages::EnumMessage::Test> field2 = {};
226 std::optional<std::int32_t> field1 = {};
230 std::optional<
double> field1 = {};
231 std::optional<
float> field2 = {};
232 std::optional<std::int64_t> field3 = {};
233 std::optional<std::uint64_t> field4 = {};
234 std::optional<std::int32_t> field5 = {};
235 std::optional<std::uint32_t> field6 = {};
236 std::optional<
bool> field7 = {};
237 std::optional<std::string> field8 = {};
238 std::optional<std::string> field9 = {};
242 std::optional<std::vector<std::string>> field1 = {};
246 std::int64_t seconds = 0;
247 std::int32_t nanos = 0;
248 bool do_not_set =
false;
252 std::int64_t seconds = 0;
253 std::int32_t nanos = 0;
254 bool do_not_set =
false;
262 std::string type_url = {};
263 std::string value = {};
268 bool add_nesting =
false;
272 std::optional<std::int32_t> field1 = {};
273 std::optional<std::string> field2 = {};
277 std::vector<std::int32_t> field1 = {};
278 std::vector<BoolMessageData> field2 = {};
279 std::vector<DurationMessageData> field3 = {};
280 std::vector<ProtoValue> field4 = {};
281 std::vector<std::uint32_t> field5 = {};
282 std::vector<std::int64_t> field6 = {};
283 std::vector<std::uint64_t> field7 = {};
284 std::vector<
float> field8 = {};
285 std::vector<
double> field9 = {};
286 std::vector<
bool> field10 = {};
287 std::vector<std::string> field11 = {};
288 std::vector<proto_json::messages::RepeatedMessage::Test> field12 = {};
292 std::map<std::int32_t, std::int32_t> field1 = {};
293 std::map<std::uint32_t,
double> field2 = {};
294 std::map<std::int64_t,
bool> field3 = {};
295 std::map<std::uint64_t, std::string> field4 = {};
296 std::map<
bool, proto_json::messages::MapMessage::TestEnum> field5 = {};
297 std::map<std::string, BoolMessageData> field6 = {};
298 std::map<std::string, DurationMessageData> field7 = {};
299 std::map<std::int32_t, ProtoValue> field8 = {};
303 ::google::protobuf::NullValue field1 = {};
304 std::optional<::google::protobuf::NullValue> field2 = {};
305 std::vector<::google::protobuf::NullValue> field3 = {};
306 std::map<std::int32_t, ::google::protobuf::NullValue> field4 = {};
311 std::optional<
bool> field2 = {};
313 std::vector<
bool> field4 = {};
314 std::map<std::int32_t,
bool> field5 = {};
319 std::vector<StringMessageData> field2 = {};
320 std::map<std::int32_t, StringMessageData> field3 = {};
323proto_json::messages::Int32Message PrepareTestData(
const Int32MessageData& message_data);
324void CheckMessageEqual(
const proto_json::messages::Int32Message& lhs,
const proto_json::messages::Int32Message& rhs);
326proto_json::messages::UInt32Message PrepareTestData(
const UInt32MessageData& message_data);
327void CheckMessageEqual(
const proto_json::messages::UInt32Message& lhs,
const proto_json::messages::UInt32Message& rhs);
329proto_json::messages::Int64Message PrepareTestData(
const Int64MessageData& message_data);
330void CheckMessageEqual(
const proto_json::messages::Int64Message& lhs,
const proto_json::messages::Int64Message& rhs);
332proto_json::messages::UInt64Message PrepareTestData(
const UInt64MessageData& message_data);
333void CheckMessageEqual(
const proto_json::messages::UInt64Message& lhs,
const proto_json::messages::UInt64Message& rhs);
335proto_json::messages::FloatMessage PrepareTestData(
const FloatMessageData& message_data);
336void CheckMessageEqual(
const proto_json::messages::FloatMessage& lhs,
const proto_json::messages::FloatMessage& rhs);
338proto_json::messages::DoubleMessage PrepareTestData(
const DoubleMessageData& message_data);
339void CheckMessageEqual(
const proto_json::messages::DoubleMessage& lhs,
const proto_json::messages::DoubleMessage& rhs);
341proto_json::messages::BoolMessage PrepareTestData(
const BoolMessageData& message_data);
342void CheckMessageEqual(
const proto_json::messages::BoolMessage& lhs,
const proto_json::messages::BoolMessage& rhs);
344proto_json::messages::StringMessage PrepareTestData(
const StringMessageData& message_data);
345void CheckMessageEqual(
const proto_json::messages::StringMessage& lhs,
const proto_json::messages::StringMessage& rhs);
347proto_json::messages::BytesMessage PrepareTestData(
const BytesMessageData& message_data);
348void CheckMessageEqual(
const proto_json::messages::BytesMessage& lhs,
const proto_json::messages::BytesMessage& rhs);
350proto_json::messages::EnumMessage PrepareTestData(
const EnumMessageData& message_data);
351void CheckMessageEqual(
const proto_json::messages::EnumMessage& lhs,
const proto_json::messages::EnumMessage& rhs);
353proto_json::messages::NestedMessage PrepareTestData(
const NestedMessageData& message_data);
354void CheckMessageEqual(
const proto_json::messages::NestedMessage& lhs,
const proto_json::messages::NestedMessage& rhs);
356proto_json::messages::WrapperMessage PrepareTestData(
const WrapperMessageData& message_data);
357void CheckMessageEqual(
358 const proto_json::messages::WrapperMessage& lhs,
359 const proto_json::messages::WrapperMessage& rhs
362proto_json::messages::FieldMaskMessage PrepareTestData(
const FieldMaskMessageData& message_data);
363void CheckMessageEqual(
const ::google::protobuf::FieldMask& lhs,
const ::google::protobuf::FieldMask& rhs);
364void CheckMessageEqual(
365 const proto_json::messages::FieldMaskMessage& lhs,
366 const proto_json::messages::FieldMaskMessage& rhs
369proto_json::messages::DurationMessage PrepareTestData(
const DurationMessageData& message_data);
370void CheckMessageEqual(
const ::google::protobuf::Duration& lhs,
const ::google::protobuf::Duration& rhs);
371void CheckMessageEqual(
372 const proto_json::messages::DurationMessage& lhs,
373 const proto_json::messages::DurationMessage& rhs
376proto_json::messages::TimestampMessage PrepareTestData(
const TimestampMessageData& message_data);
377void CheckMessageEqual(
const ::google::protobuf::Timestamp& lhs,
const ::google::protobuf::Timestamp& rhs);
378void CheckMessageEqual(
379 const proto_json::messages::TimestampMessage& lhs,
380 const proto_json::messages::TimestampMessage& rhs
383proto_json::messages::ValueMessage PrepareTestData(
const ValueMessageData& message_data);
384void CheckMessageEqual(
const ::google::protobuf::Value& lhs,
const ::google::protobuf::Value& rhs);
385void CheckMessageEqual(
const ::google::protobuf::ListValue& lhs,
const ::google::protobuf::ListValue& rhs);
386void CheckMessageEqual(
const ::google::protobuf::Struct& lhs,
const ::google::protobuf::Struct& rhs);
387void CheckMessageEqual(
const proto_json::messages::ValueMessage& lhs,
const proto_json::messages::ValueMessage& rhs);
389proto_json::messages::AnyMessage PrepareTestData(
const AnyMessageData& message_data);
390void CheckMessageEqual(
const ::google::protobuf::Any& lhs,
const ::google::protobuf::Any& rhs);
391void CheckMessageEqual(
const proto_json::messages::AnyMessage& lhs,
const proto_json::messages::AnyMessage& rhs);
393proto_json::messages::OneofMessage PrepareTestData(
const OneofMessageData& message_data);
394void CheckMessageEqual(
const proto_json::messages::OneofMessage& lhs,
const proto_json::messages::OneofMessage& rhs);
396proto_json::messages::RepeatedMessage PrepareTestData(
const RepeatedMessageData& message_data);
397void CheckMessageEqual(
398 const proto_json::messages::RepeatedMessage& lhs,
399 const proto_json::messages::RepeatedMessage& rhs
402proto_json::messages::MapMessage PrepareTestData(
const MapMessageData& message_data);
403void CheckMessageEqual(
const proto_json::messages::MapMessage& lhs,
const proto_json::messages::MapMessage& rhs);
405proto_json::messages::NullValueMessage PrepareTestData(
const NullValueMessageData& message_data);
406void CheckMessageEqual(
407 const proto_json::messages::NullValueMessage& lhs,
408 const proto_json::messages::NullValueMessage& rhs
411proto_json::messages::PresenceMessage PrepareTestData(
const PresenceMessageData& message_data);
412void CheckMessageEqual(
413 const proto_json::messages::PresenceMessage& lhs,
414 const proto_json::messages::PresenceMessage& rhs
418void CheckMessageEqual(
419 const proto_json::messages::UnknownFieldMessage& lhs,
420 const proto_json::messages::UnknownFieldMessage& rhs
425 static constexpr const char* kJson = R"({"field1":"NaN"})";
426 static constexpr FloatMessageData kValue = {std::numeric_limits<
float>::quiet_NaN()};
427 static constexpr bool kSkip = !std::numeric_limits<
float>::has_quiet_NaN;
432 static constexpr const char* kJson = R"({"field1":"NaN"})";
433 static constexpr FloatMessageData kValue = {std::numeric_limits<
float>::signaling_NaN()};
434 static constexpr bool kSkip = !std::numeric_limits<
float>::has_signaling_NaN;
439 static constexpr const char* kJson = R"({"field1":"Infinity"})";
440 static constexpr FloatMessageData kValue = {std::numeric_limits<
float>::infinity()};
441 static constexpr bool kSkip = !std::numeric_limits<
float>::has_infinity;
446 static constexpr const char* kJson = R"({"field1":"-Infinity"})";
447 static constexpr FloatMessageData kValue = {-std::numeric_limits<
float>::infinity()};
448 static constexpr bool kSkip = !std::numeric_limits<
float>::has_infinity;
453 static constexpr const char* kJson = R"({"field1":"NaN"})";
454 static constexpr DoubleMessageData kValue = {std::numeric_limits<
double>::quiet_NaN()};
455 static constexpr bool kSkip = !std::numeric_limits<
double>::has_quiet_NaN;
460 static constexpr const char* kJson = R"({"field1":"NaN"})";
461 static constexpr DoubleMessageData kValue = {std::numeric_limits<
double>::signaling_NaN()};
462 static constexpr bool kSkip = !std::numeric_limits<
double>::has_signaling_NaN;
467 static constexpr const char* kJson = R"({"field1":"Infinity"})";
468 static constexpr DoubleMessageData kValue = {std::numeric_limits<
double>::infinity()};
469 static constexpr bool kSkip = !std::numeric_limits<
double>::has_infinity;
474 static constexpr const char* kJson = R"({"field1":"-Infinity"})";
475 static constexpr DoubleMessageData kValue = {-std::numeric_limits<
double>::infinity()};
476 static constexpr bool kSkip = !std::numeric_limits<
double>::has_infinity;
481 static constexpr double kValue = 1.5;
482 static constexpr const char* kJson =
"1.5";
487 static constexpr float kValue = 1.5;
488 static constexpr const char* kJson =
"1.5";
493 static constexpr std::int64_t kValue = -123;
494 static constexpr const char* kJson =
"-123";
499 static constexpr std::uint64_t kValue = 123;
500 static constexpr const char* kJson =
"123";
505 static constexpr std::int32_t kValue = -321;
506 static constexpr const char* kJson =
"-321";
511 static constexpr std::uint32_t kValue = 321;
512 static constexpr const char* kJson =
"321";
517 static constexpr bool kValue =
true;
518 static constexpr const char* kJson =
"true";
523 static constexpr std::string_view kValue =
"hello";
524 static constexpr const char* kJson =
"\"hello\"";
529 static constexpr std::string_view kValue =
"world";
530 static constexpr const char* kJson =
"\"d29ybGQ=\"";
533template <
typename TParam>
534using WrappedType = std::conditional_t<
535 !std::is_same_v<std::decay_t<
decltype(TParam::kValue)>, std::string_view>,
536 std::decay_t<
decltype(TParam::kValue)>,