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"
25#define EXPECT_PRINT_ERROR(EXPR, CODE, PATH)
28 ADD_FAILURE
() << "Should throw 'PrintError' exception";
29 } catch (const protobuf::json::PrintError& error) {
30 EXPECT_EQ
(error.GetErrorInfo().GetCode(), (CODE));
31 EXPECT_EQ
(error.GetErrorInfo().GetPath(), (PATH));
33 ADD_FAILURE
() << "Unexpected exception, should be 'PrintError'";
37#define EXPECT_PARSE_ERROR(EXPR, CODE, PATH)
40 ADD_FAILURE
() << "Should throw 'ParseError' exception";
41 } catch (const protobuf::json::ParseError& error) {
42 EXPECT_EQ
(error.GetErrorInfo().GetCode(), (CODE));
43 EXPECT_EQ
(error.GetErrorInfo().GetPath(), (PATH));
45 ADD_FAILURE
() << "Unexpected exception, should be 'ParseError'";
49struct fmt::formatter<USERVER_NAMESPACE::protobuf::json::PrintOptions> {
50 auto parse(fmt::format_parse_context& ctx) {
51 auto it = ctx.begin();
52 if (it != ctx.end() && *it !=
'}') {
53 throw fmt::format_error(
"invalid format");
58 template <
typename FormatContext>
59 auto format(
const USERVER_NAMESPACE::protobuf::json::PrintOptions& options, FormatContext& ctx)
const
60 ->
decltype(ctx.out()) {
61 return fmt::format_to(
63 "{{always_print_fields_with_no_presence={}, always_print_enums_as_ints={}, preserve_proto_field_names={}}}",
64 options.always_print_fields_with_no_presence,
65 options.always_print_enums_as_ints,
66 options.preserve_proto_field_names
72struct fmt::formatter<USERVER_NAMESPACE::protobuf::json::ParseOptions> {
73 auto parse(fmt::format_parse_context& ctx) {
74 auto it = ctx.begin();
75 if (it != ctx.end() && *it !=
'}') {
76 throw fmt::format_error(
"invalid format");
81 template <
typename FormatContext>
82 auto format(
const USERVER_NAMESPACE::protobuf::json::ParseOptions& options, FormatContext& ctx)
const
83 ->
decltype(ctx.out()) {
84 return fmt::format_to(ctx.out(),
"{{ignore_unknown_fields={}}}", options.ignore_unknown_fields);
89struct fmt::formatter<USERVER_NAMESPACE::protobuf::json::PrintErrorCode> {
90 auto parse(fmt::format_parse_context& ctx) {
91 auto it = ctx.begin();
92 if (it != ctx.end() && *it !=
'}') {
93 throw fmt::format_error(
"invalid format");
98 template <
typename FormatContext>
99 auto format(
const USERVER_NAMESPACE::protobuf::json::PrintErrorCode& code, FormatContext& ctx)
const
100 ->
decltype(ctx.out()) {
102 case USERVER_NAMESPACE::protobuf::json::PrintErrorCode::kInvalidValue:
103 return fmt::format_to(ctx.out(),
"kInvalidValue");
105 return fmt::format_to(ctx.out(),
"UNKNOWN");
111struct fmt::formatter<USERVER_NAMESPACE::protobuf::json::ParseErrorCode> {
112 auto parse(fmt::format_parse_context& ctx) {
113 auto it = ctx.begin();
114 if (it != ctx.end() && *it !=
'}') {
115 throw fmt::format_error(
"invalid format");
120 template <
typename FormatContext>
121 auto format(
const USERVER_NAMESPACE::protobuf::json::ParseErrorCode& code, FormatContext& ctx)
const
122 ->
decltype(ctx.out()) {
124 case USERVER_NAMESPACE::protobuf::json::ParseErrorCode::kUnknownField:
125 return fmt::format_to(ctx.out(),
"kUnknownField");
126 case USERVER_NAMESPACE::protobuf::json::ParseErrorCode::kUnknownEnum:
127 return fmt::format_to(ctx.out(),
"kUnknownEnum");
128 case USERVER_NAMESPACE::protobuf::json::ParseErrorCode::kMultipleOneofFields:
129 return fmt::format_to(ctx.out(),
"kMultipleOneofFields");
130 case USERVER_NAMESPACE::protobuf::json::ParseErrorCode::kInvalidType:
131 return fmt::format_to(ctx.out(),
"kInvalidType");
132 case USERVER_NAMESPACE::protobuf::json::ParseErrorCode::kInvalidValue:
133 return fmt::format_to(ctx.out(),
"kInvalidValue");
135 return fmt::format_to(ctx.out(),
"UNKNOWN");
140USERVER_NAMESPACE_BEGIN
142namespace protobuf::json::tests {
144constexpr inline ::google::protobuf::NullValue kNullConst = ::google::protobuf::NullValue::NULL_VALUE;
148 using std::runtime_error::runtime_error;
154using ProtoValue = std::variant<
161 std::map<std::string, std::string>>;
165formats::
json::
Value CreateSampleJson(
const ::google::protobuf::Message& message,
const PrintOptions& options = {});
167void InitSampleMessage(
const std::string& json, ::google::protobuf::Message& message,
const ParseOptions& options = {});
169::google::protobuf::Value ProtoValueToNative(
const ProtoValue& data);
172 std::int32_t field1 = 0;
173 std::int32_t field2 = 0;
174 std::int32_t field3 = 0;
178 std::uint32_t field1 = 0;
179 std::uint32_t field2 = 0;
183 std::int64_t field1 = 0;
184 std::int64_t field2 = 0;
185 std::int64_t field3 = 0;
189 std::uint64_t field1 = 0;
190 std::uint64_t field2 = 0;
206 std::string field1 = {};
210 std::string field1 = {};
218 std::optional<std::int32_t> field1 = {};
222 std::optional<
double> field1 = {};
223 std::optional<
float> field2 = {};
224 std::optional<std::int64_t> field3 = {};
225 std::optional<std::uint64_t> field4 = {};
226 std::optional<std::int32_t> field5 = {};
227 std::optional<std::uint32_t> field6 = {};
228 std::optional<
bool> field7 = {};
229 std::optional<std::string> field8 = {};
230 std::optional<std::string> field9 = {};
234 std::optional<std::vector<std::string>> field1 = {};
238 std::int64_t seconds = 0;
239 std::int32_t nanos = 0;
240 bool do_not_set =
false;
244 std::int64_t seconds = 0;
245 std::int32_t nanos = 0;
246 bool do_not_set =
false;
254 std::string type_url = {};
255 std::string value = {};
260 bool add_nesting =
false;
264 std::optional<std::int32_t> field1 = {};
265 std::optional<std::string> field2 = {};
269 std::vector<std::int32_t> field1 = {};
270 std::vector<BoolMessageData> field2 = {};
271 std::vector<DurationMessageData> field3 = {};
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 = {};
285 ::google::protobuf::NullValue field1 = {};
286 std::optional<::google::protobuf::NullValue> field2 = {};
287 std::vector<::google::protobuf::NullValue> field3 = {};
288 std::map<std::int32_t, ::google::protobuf::NullValue> field4 = {};
293 std::optional<
bool> field2 = {};
295 std::vector<
bool> field4 = {};
296 std::map<std::int32_t,
bool> field5 = {};
301 std::vector<StringMessageData> field2 = {};
302 std::map<std::int32_t, StringMessageData> field3 = {};
305proto_json::messages::Int32Message PrepareTestData(
const Int32MessageData& message_data);
306void CheckMessageEqual(
const proto_json::messages::Int32Message& lhs,
const proto_json::messages::Int32Message& rhs);
308proto_json::messages::UInt32Message PrepareTestData(
const UInt32MessageData& message_data);
309void CheckMessageEqual(
const proto_json::messages::UInt32Message& lhs,
const proto_json::messages::UInt32Message& rhs);
311proto_json::messages::Int64Message PrepareTestData(
const Int64MessageData& message_data);
312void CheckMessageEqual(
const proto_json::messages::Int64Message& lhs,
const proto_json::messages::Int64Message& rhs);
314proto_json::messages::UInt64Message PrepareTestData(
const UInt64MessageData& message_data);
315void CheckMessageEqual(
const proto_json::messages::UInt64Message& lhs,
const proto_json::messages::UInt64Message& rhs);
317proto_json::messages::FloatMessage PrepareTestData(
const FloatMessageData& message_data);
318void CheckMessageEqual(
const proto_json::messages::FloatMessage& lhs,
const proto_json::messages::FloatMessage& rhs);
320proto_json::messages::DoubleMessage PrepareTestData(
const DoubleMessageData& message_data);
321void CheckMessageEqual(
const proto_json::messages::DoubleMessage& lhs,
const proto_json::messages::DoubleMessage& rhs);
323proto_json::messages::BoolMessage PrepareTestData(
const BoolMessageData& message_data);
324void CheckMessageEqual(
const proto_json::messages::BoolMessage& lhs,
const proto_json::messages::BoolMessage& rhs);
326proto_json::messages::StringMessage PrepareTestData(
const StringMessageData& message_data);
327void CheckMessageEqual(
const proto_json::messages::StringMessage& lhs,
const proto_json::messages::StringMessage& rhs);
329proto_json::messages::BytesMessage PrepareTestData(
const BytesMessageData& message_data);
330void CheckMessageEqual(
const proto_json::messages::BytesMessage& lhs,
const proto_json::messages::BytesMessage& rhs);
332proto_json::messages::EnumMessage PrepareTestData(
const EnumMessageData& message_data);
333void CheckMessageEqual(
const proto_json::messages::EnumMessage& lhs,
const proto_json::messages::EnumMessage& rhs);
335proto_json::messages::NestedMessage PrepareTestData(
const NestedMessageData& message_data);
336void CheckMessageEqual(
const proto_json::messages::NestedMessage& lhs,
const proto_json::messages::NestedMessage& rhs);
338proto_json::messages::WrapperMessage PrepareTestData(
const WrapperMessageData& message_data);
339void CheckMessageEqual(
340 const proto_json::messages::WrapperMessage& lhs,
341 const proto_json::messages::WrapperMessage& rhs
344proto_json::messages::FieldMaskMessage PrepareTestData(
const FieldMaskMessageData& message_data);
345void CheckMessageEqual(
const ::google::protobuf::FieldMask& lhs,
const ::google::protobuf::FieldMask& rhs);
346void CheckMessageEqual(
347 const proto_json::messages::FieldMaskMessage& lhs,
348 const proto_json::messages::FieldMaskMessage& rhs
351proto_json::messages::DurationMessage PrepareTestData(
const DurationMessageData& message_data);
352void CheckMessageEqual(
const ::google::protobuf::Duration& lhs,
const ::google::protobuf::Duration& rhs);
353void CheckMessageEqual(
354 const proto_json::messages::DurationMessage& lhs,
355 const proto_json::messages::DurationMessage& rhs
358proto_json::messages::TimestampMessage PrepareTestData(
const TimestampMessageData& message_data);
359void CheckMessageEqual(
const ::google::protobuf::Timestamp& lhs,
const ::google::protobuf::Timestamp& rhs);
360void CheckMessageEqual(
361 const proto_json::messages::TimestampMessage& lhs,
362 const proto_json::messages::TimestampMessage& rhs
365proto_json::messages::ValueMessage PrepareTestData(
const ValueMessageData& message_data);
366void CheckMessageEqual(
const ::google::protobuf::Value& lhs,
const ::google::protobuf::Value& rhs);
367void CheckMessageEqual(
const ::google::protobuf::ListValue& lhs,
const ::google::protobuf::ListValue& rhs);
368void CheckMessageEqual(
const ::google::protobuf::Struct& lhs,
const ::google::protobuf::Struct& rhs);
369void CheckMessageEqual(
const proto_json::messages::ValueMessage& lhs,
const proto_json::messages::ValueMessage& rhs);
371proto_json::messages::AnyMessage PrepareTestData(
const AnyMessageData& message_data);
372void CheckMessageEqual(
const ::google::protobuf::Any& lhs,
const ::google::protobuf::Any& rhs);
373void CheckMessageEqual(
const proto_json::messages::AnyMessage& lhs,
const proto_json::messages::AnyMessage& rhs);
375proto_json::messages::OneofMessage PrepareTestData(
const OneofMessageData& message_data);
376void CheckMessageEqual(
const proto_json::messages::OneofMessage& lhs,
const proto_json::messages::OneofMessage& rhs);
378proto_json::messages::RepeatedMessage PrepareTestData(
const RepeatedMessageData& message_data);
379void CheckMessageEqual(
380 const proto_json::messages::RepeatedMessage& lhs,
381 const proto_json::messages::RepeatedMessage& rhs
384proto_json::messages::MapMessage PrepareTestData(
const MapMessageData& message_data);
385void CheckMessageEqual(
const proto_json::messages::MapMessage& lhs,
const proto_json::messages::MapMessage& rhs);
387proto_json::messages::NullValueMessage PrepareTestData(
const NullValueMessageData& message_data);
388void CheckMessageEqual(
389 const proto_json::messages::NullValueMessage& lhs,
390 const proto_json::messages::NullValueMessage& rhs
393proto_json::messages::PresenceMessage PrepareTestData(
const PresenceMessageData& message_data);
394void CheckMessageEqual(
395 const proto_json::messages::PresenceMessage& lhs,
396 const proto_json::messages::PresenceMessage& rhs
400void CheckMessageEqual(
401 const proto_json::messages::UnknownFieldMessage& lhs,
402 const proto_json::messages::UnknownFieldMessage& rhs
407 static constexpr const char* kJson = R"({"field1":"NaN"})";
408 static constexpr FloatMessageData kValue = {std::numeric_limits<
float>::quiet_NaN()};
409 static constexpr bool kSkip = !std::numeric_limits<
float>::has_quiet_NaN;
414 static constexpr const char* kJson = R"({"field1":"NaN"})";
415 static constexpr FloatMessageData kValue = {std::numeric_limits<
float>::signaling_NaN()};
416 static constexpr bool kSkip = !std::numeric_limits<
float>::has_signaling_NaN;
421 static constexpr const char* kJson = R"({"field1":"Infinity"})";
422 static constexpr FloatMessageData kValue = {std::numeric_limits<
float>::infinity()};
423 static constexpr bool kSkip = !std::numeric_limits<
float>::has_infinity;
428 static constexpr const char* kJson = R"({"field1":"-Infinity"})";
429 static constexpr FloatMessageData kValue = {-std::numeric_limits<
float>::infinity()};
430 static constexpr bool kSkip = !std::numeric_limits<
float>::has_infinity;
435 static constexpr const char* kJson = R"({"field1":"NaN"})";
436 static constexpr DoubleMessageData kValue = {std::numeric_limits<
double>::quiet_NaN()};
437 static constexpr bool kSkip = !std::numeric_limits<
double>::has_quiet_NaN;
442 static constexpr const char* kJson = R"({"field1":"NaN"})";
443 static constexpr DoubleMessageData kValue = {std::numeric_limits<
double>::signaling_NaN()};
444 static constexpr bool kSkip = !std::numeric_limits<
double>::has_signaling_NaN;
449 static constexpr const char* kJson = R"({"field1":"Infinity"})";
450 static constexpr DoubleMessageData kValue = {std::numeric_limits<
double>::infinity()};
451 static constexpr bool kSkip = !std::numeric_limits<
double>::has_infinity;
456 static constexpr const char* kJson = R"({"field1":"-Infinity"})";
457 static constexpr DoubleMessageData kValue = {-std::numeric_limits<
double>::infinity()};
458 static constexpr bool kSkip = !std::numeric_limits<
double>::has_infinity;
463 static constexpr double kValue = 1.5;
464 static constexpr const char* kJson =
"1.5";
469 static constexpr float kValue = 1.5;
470 static constexpr const char* kJson =
"1.5";
475 static constexpr std::int64_t kValue = -123;
476 static constexpr const char* kJson =
"-123";
481 static constexpr std::uint64_t kValue = 123;
482 static constexpr const char* kJson =
"123";
487 static constexpr std::int32_t kValue = -321;
488 static constexpr const char* kJson =
"-321";
493 static constexpr std::uint32_t kValue = 321;
494 static constexpr const char* kJson =
"321";
499 static constexpr bool kValue =
true;
500 static constexpr const char* kJson =
"true";
505 static constexpr std::string_view kValue =
"hello";
506 static constexpr const char* kJson =
"\"hello\"";
511 static constexpr std::string_view kValue =
"world";
512 static constexpr const char* kJson =
"\"d29ybGQ=\"";
515template <
typename TParam>
516using WrappedType = std::conditional_t<
517 !std::is_same_v<std::decay_t<
decltype(TParam::kValue)>, std::string_view>,
518 std::decay_t<
decltype(TParam::kValue)>,