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>>;
163formats::json::
Value PrepareJsonTestData(
const std::string& json_data);
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 = {};
215 std::optional<proto_json::messages::EnumMessage::Test> field2 = {};
219 std::optional<std::int32_t> field1 = {};
223 std::optional<
double> field1 = {};
224 std::optional<
float> field2 = {};
225 std::optional<std::int64_t> field3 = {};
226 std::optional<std::uint64_t> field4 = {};
227 std::optional<std::int32_t> field5 = {};
228 std::optional<std::uint32_t> field6 = {};
229 std::optional<
bool> field7 = {};
230 std::optional<std::string> field8 = {};
231 std::optional<std::string> field9 = {};
235 std::optional<std::vector<std::string>> field1 = {};
239 std::int64_t seconds = 0;
240 std::int32_t nanos = 0;
241 bool do_not_set =
false;
245 std::int64_t seconds = 0;
246 std::int32_t nanos = 0;
247 bool do_not_set =
false;
255 std::string type_url = {};
256 std::string value = {};
261 bool add_nesting =
false;
265 std::optional<std::int32_t> field1 = {};
266 std::optional<std::string> field2 = {};
270 std::vector<std::int32_t> field1 = {};
271 std::vector<BoolMessageData> field2 = {};
272 std::vector<DurationMessageData> field3 = {};
273 std::vector<ProtoValue> field4 = {};
274 std::vector<std::uint32_t> field5 = {};
275 std::vector<std::int64_t> field6 = {};
276 std::vector<std::uint64_t> field7 = {};
277 std::vector<
float> field8 = {};
278 std::vector<
double> field9 = {};
279 std::vector<
bool> field10 = {};
280 std::vector<std::string> field11 = {};
281 std::vector<proto_json::messages::RepeatedMessage::Test> field12 = {};
285 std::map<std::int32_t, std::int32_t> field1 = {};
286 std::map<std::uint32_t,
double> field2 = {};
287 std::map<std::int64_t,
bool> field3 = {};
288 std::map<std::uint64_t, std::string> field4 = {};
289 std::map<
bool, proto_json::messages::MapMessage::TestEnum> field5 = {};
290 std::map<std::string, BoolMessageData> field6 = {};
291 std::map<std::string, DurationMessageData> field7 = {};
292 std::map<std::int32_t, ProtoValue> field8 = {};
296 ::google::protobuf::NullValue field1 = {};
297 std::optional<::google::protobuf::NullValue> field2 = {};
298 std::vector<::google::protobuf::NullValue> field3 = {};
299 std::map<std::int32_t, ::google::protobuf::NullValue> field4 = {};
304 std::optional<
bool> field2 = {};
306 std::vector<
bool> field4 = {};
307 std::map<std::int32_t,
bool> field5 = {};
312 std::vector<StringMessageData> field2 = {};
313 std::map<std::int32_t, StringMessageData> field3 = {};
316proto_json::messages::Int32Message PrepareTestData(
const Int32MessageData& message_data);
317void CheckMessageEqual(
const proto_json::messages::Int32Message& lhs,
const proto_json::messages::Int32Message& rhs);
319proto_json::messages::UInt32Message PrepareTestData(
const UInt32MessageData& message_data);
320void CheckMessageEqual(
const proto_json::messages::UInt32Message& lhs,
const proto_json::messages::UInt32Message& rhs);
322proto_json::messages::Int64Message PrepareTestData(
const Int64MessageData& message_data);
323void CheckMessageEqual(
const proto_json::messages::Int64Message& lhs,
const proto_json::messages::Int64Message& rhs);
325proto_json::messages::UInt64Message PrepareTestData(
const UInt64MessageData& message_data);
326void CheckMessageEqual(
const proto_json::messages::UInt64Message& lhs,
const proto_json::messages::UInt64Message& rhs);
328proto_json::messages::FloatMessage PrepareTestData(
const FloatMessageData& message_data);
329void CheckMessageEqual(
const proto_json::messages::FloatMessage& lhs,
const proto_json::messages::FloatMessage& rhs);
331proto_json::messages::DoubleMessage PrepareTestData(
const DoubleMessageData& message_data);
332void CheckMessageEqual(
const proto_json::messages::DoubleMessage& lhs,
const proto_json::messages::DoubleMessage& rhs);
334proto_json::messages::BoolMessage PrepareTestData(
const BoolMessageData& message_data);
335void CheckMessageEqual(
const proto_json::messages::BoolMessage& lhs,
const proto_json::messages::BoolMessage& rhs);
337proto_json::messages::StringMessage PrepareTestData(
const StringMessageData& message_data);
338void CheckMessageEqual(
const proto_json::messages::StringMessage& lhs,
const proto_json::messages::StringMessage& rhs);
340proto_json::messages::BytesMessage PrepareTestData(
const BytesMessageData& message_data);
341void CheckMessageEqual(
const proto_json::messages::BytesMessage& lhs,
const proto_json::messages::BytesMessage& rhs);
343proto_json::messages::EnumMessage PrepareTestData(
const EnumMessageData& message_data);
344void CheckMessageEqual(
const proto_json::messages::EnumMessage& lhs,
const proto_json::messages::EnumMessage& rhs);
346proto_json::messages::NestedMessage PrepareTestData(
const NestedMessageData& message_data);
347void CheckMessageEqual(
const proto_json::messages::NestedMessage& lhs,
const proto_json::messages::NestedMessage& rhs);
349proto_json::messages::WrapperMessage PrepareTestData(
const WrapperMessageData& message_data);
350void CheckMessageEqual(
351 const proto_json::messages::WrapperMessage& lhs,
352 const proto_json::messages::WrapperMessage& rhs
355proto_json::messages::FieldMaskMessage PrepareTestData(
const FieldMaskMessageData& message_data);
356void CheckMessageEqual(
const ::google::protobuf::FieldMask& lhs,
const ::google::protobuf::FieldMask& rhs);
357void CheckMessageEqual(
358 const proto_json::messages::FieldMaskMessage& lhs,
359 const proto_json::messages::FieldMaskMessage& rhs
362proto_json::messages::DurationMessage PrepareTestData(
const DurationMessageData& message_data);
363void CheckMessageEqual(
const ::google::protobuf::Duration& lhs,
const ::google::protobuf::Duration& rhs);
364void CheckMessageEqual(
365 const proto_json::messages::DurationMessage& lhs,
366 const proto_json::messages::DurationMessage& rhs
369proto_json::messages::TimestampMessage PrepareTestData(
const TimestampMessageData& message_data);
370void CheckMessageEqual(
const ::google::protobuf::Timestamp& lhs,
const ::google::protobuf::Timestamp& rhs);
371void CheckMessageEqual(
372 const proto_json::messages::TimestampMessage& lhs,
373 const proto_json::messages::TimestampMessage& rhs
376proto_json::messages::ValueMessage PrepareTestData(
const ValueMessageData& message_data);
377void CheckMessageEqual(
const ::google::protobuf::Value& lhs,
const ::google::protobuf::Value& rhs);
378void CheckMessageEqual(
const ::google::protobuf::ListValue& lhs,
const ::google::protobuf::ListValue& rhs);
379void CheckMessageEqual(
const ::google::protobuf::Struct& lhs,
const ::google::protobuf::Struct& rhs);
380void CheckMessageEqual(
const proto_json::messages::ValueMessage& lhs,
const proto_json::messages::ValueMessage& rhs);
382proto_json::messages::AnyMessage PrepareTestData(
const AnyMessageData& message_data);
383void CheckMessageEqual(
const ::google::protobuf::Any& lhs,
const ::google::protobuf::Any& rhs);
384void CheckMessageEqual(
const proto_json::messages::AnyMessage& lhs,
const proto_json::messages::AnyMessage& rhs);
386proto_json::messages::OneofMessage PrepareTestData(
const OneofMessageData& message_data);
387void CheckMessageEqual(
const proto_json::messages::OneofMessage& lhs,
const proto_json::messages::OneofMessage& rhs);
389proto_json::messages::RepeatedMessage PrepareTestData(
const RepeatedMessageData& message_data);
390void CheckMessageEqual(
391 const proto_json::messages::RepeatedMessage& lhs,
392 const proto_json::messages::RepeatedMessage& rhs
395proto_json::messages::MapMessage PrepareTestData(
const MapMessageData& message_data);
396void CheckMessageEqual(
const proto_json::messages::MapMessage& lhs,
const proto_json::messages::MapMessage& rhs);
398proto_json::messages::NullValueMessage PrepareTestData(
const NullValueMessageData& message_data);
399void CheckMessageEqual(
400 const proto_json::messages::NullValueMessage& lhs,
401 const proto_json::messages::NullValueMessage& rhs
404proto_json::messages::PresenceMessage PrepareTestData(
const PresenceMessageData& message_data);
405void CheckMessageEqual(
406 const proto_json::messages::PresenceMessage& lhs,
407 const proto_json::messages::PresenceMessage& rhs
411void CheckMessageEqual(
412 const proto_json::messages::UnknownFieldMessage& lhs,
413 const proto_json::messages::UnknownFieldMessage& rhs
418 static constexpr const char* kJson = R"({"field1":"NaN"})";
419 static constexpr FloatMessageData kValue = {std::numeric_limits<
float>::quiet_NaN()};
420 static constexpr bool kSkip = !std::numeric_limits<
float>::has_quiet_NaN;
425 static constexpr const char* kJson = R"({"field1":"NaN"})";
426 static constexpr FloatMessageData kValue = {std::numeric_limits<
float>::signaling_NaN()};
427 static constexpr bool kSkip = !std::numeric_limits<
float>::has_signaling_NaN;
432 static constexpr const char* kJson = R"({"field1":"Infinity"})";
433 static constexpr FloatMessageData kValue = {std::numeric_limits<
float>::infinity()};
434 static constexpr bool kSkip = !std::numeric_limits<
float>::has_infinity;
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":"NaN"})";
447 static constexpr DoubleMessageData kValue = {std::numeric_limits<
double>::quiet_NaN()};
448 static constexpr bool kSkip = !std::numeric_limits<
double>::has_quiet_NaN;
453 static constexpr const char* kJson = R"({"field1":"NaN"})";
454 static constexpr DoubleMessageData kValue = {std::numeric_limits<
double>::signaling_NaN()};
455 static constexpr bool kSkip = !std::numeric_limits<
double>::has_signaling_NaN;
460 static constexpr const char* kJson = R"({"field1":"Infinity"})";
461 static constexpr DoubleMessageData kValue = {std::numeric_limits<
double>::infinity()};
462 static constexpr bool kSkip = !std::numeric_limits<
double>::has_infinity;
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 double kValue = 1.5;
475 static constexpr const char* kJson =
"1.5";
480 static constexpr float kValue = 1.5;
481 static constexpr const char* kJson =
"1.5";
486 static constexpr std::int64_t kValue = -123;
487 static constexpr const char* kJson =
"-123";
492 static constexpr std::uint64_t kValue = 123;
493 static constexpr const char* kJson =
"123";
498 static constexpr std::int32_t kValue = -321;
499 static constexpr const char* kJson =
"-321";
504 static constexpr std::uint32_t kValue = 321;
505 static constexpr const char* kJson =
"321";
510 static constexpr bool kValue =
true;
511 static constexpr const char* kJson =
"true";
516 static constexpr std::string_view kValue =
"hello";
517 static constexpr const char* kJson =
"\"hello\"";
522 static constexpr std::string_view kValue =
"world";
523 static constexpr const char* kJson =
"\"d29ybGQ=\"";
526template <
typename TParam>
527using WrappedType = std::conditional_t<
528 !std::is_same_v<std::decay_t<
decltype(TParam::kValue)>, std::string_view>,
529 std::decay_t<
decltype(TParam::kValue)>,