userver: /data/code/userver/libraries/protobuf/tests/json/utils.hpp Source File
Loading...
Searching...
No Matches
utils.hpp
1#pragma once
2
3#include <cstdint>
4#include <limits>
5#include <map>
6#include <optional>
7#include <string>
8#include <string_view>
9#include <type_traits>
10#include <variant>
11#include <vector>
12
13#include <fmt/format.h>
14#include <google/protobuf/message.h>
15#include <gtest/gtest.h>
16
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>
21
22#include "proto_json/messages.pb.h"
23
24// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
25#define EXPECT_PRINT_ERROR(EXPR, CODE, PATH)
26 try {
27 (EXPR);
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));
32 } catch (...) {
33 ADD_FAILURE() << "Unexpected exception, should be 'PrintError'";
34 }
35
36// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
37#define EXPECT_PARSE_ERROR(EXPR, CODE, PATH)
38 try {
39 (EXPR);
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));
44 } catch (...) {
45 ADD_FAILURE() << "Unexpected exception, should be 'ParseError'";
46 }
47
48template <>
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");
54 }
55 return it;
56 }
57
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(
62 ctx.out(),
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
67 );
68 }
69};
70
71template <>
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");
77 }
78 return it;
79 }
80
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);
85 }
86};
87
88template <>
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");
94 }
95 return it;
96 }
97
98 template <typename FormatContext>
99 auto format(const USERVER_NAMESPACE::protobuf::json::PrintErrorCode& code, FormatContext& ctx) const
100 -> decltype(ctx.out()) {
101 switch (code) {
102 case USERVER_NAMESPACE::protobuf::json::PrintErrorCode::kInvalidValue:
103 return fmt::format_to(ctx.out(), "kInvalidValue");
104 default:
105 return fmt::format_to(ctx.out(), "UNKNOWN");
106 }
107 }
108};
109
110template <>
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");
116 }
117 return it;
118 }
119
120 template <typename FormatContext>
121 auto format(const USERVER_NAMESPACE::protobuf::json::ParseErrorCode& code, FormatContext& ctx) const
122 -> decltype(ctx.out()) {
123 switch (code) {
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");
134 default:
135 return fmt::format_to(ctx.out(), "UNKNOWN");
136 }
137 }
138};
139
140USERVER_NAMESPACE_BEGIN
141
142namespace protobuf::json::tests {
143
144constexpr inline ::google::protobuf::NullValue kNullConst = ::google::protobuf::NullValue::NULL_VALUE;
145
146class SampleError : public std::runtime_error {
147public:
148 using std::runtime_error::runtime_error;
149};
150
152constexpr inline ProtoNullValue kProtoNullValue{};
153
154using ProtoValue = std::variant<
155 std::monostate,
156 ProtoNullValue,
157 double,
158 std::string,
159 bool,
160 std::vector<double>,
161 std::map<std::string, std::string>>;
162
163formats::json::Value PrepareJsonTestData(const std::string& json_data);
164
165formats::json::Value CreateSampleJson(const ::google::protobuf::Message& message, const PrintOptions& options = {});
166
167void InitSampleMessage(const std::string& json, ::google::protobuf::Message& message, const ParseOptions& options = {});
168
169::google::protobuf::Value ProtoValueToNative(const ProtoValue& data);
170
172 std::int32_t field1 = 0;
173 std::int32_t field2 = 0;
174 std::int32_t field3 = 0;
175};
176
178 std::uint32_t field1 = 0;
179 std::uint32_t field2 = 0;
180};
181
183 std::int64_t field1 = 0;
184 std::int64_t field2 = 0;
185 std::int64_t field3 = 0;
186};
187
189 std::uint64_t field1 = 0;
190 std::uint64_t field2 = 0;
191};
192
194 float field1 = 0;
195};
196
198 double field1 = 0;
199};
200
202 bool field1 = false;
203};
204
206 std::string field1 = {};
207};
208
210 std::string field1 = {};
211};
212
214 proto_json::messages::EnumMessage::Test field1 = proto_json::messages::EnumMessage::TEST_UNSPECIFIED;
215};
216
218 std::optional<std::int32_t> field1 = {};
219};
220
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 = {};
231};
232
234 std::optional<std::vector<std::string>> field1 = {};
235};
236
238 std::int64_t seconds = 0;
239 std::int32_t nanos = 0;
240 bool do_not_set = false;
241};
242
244 std::int64_t seconds = 0;
245 std::int32_t nanos = 0;
246 bool do_not_set = false;
247};
248
252
254 std::string type_url = {};
255 std::string value = {};
256};
257
259 std::optional<std::variant<Int32MessageData, DurationMessageData, ValueMessageData, RawAnyData>> field1 = {};
260 bool add_nesting = false;
261};
262
264 std::optional<std::int32_t> field1 = {};
265 std::optional<std::string> field2 = {};
266};
267
269 std::vector<std::int32_t> field1 = {};
270 std::vector<BoolMessageData> field2 = {};
271 std::vector<DurationMessageData> field3 = {};
272};
273
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};
283
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 = {};
289};
290
292 bool field1 = false;
293 std::optional<bool> field2 = {};
294 std::optional<Int32MessageData> field3 = {};
295 std::vector<bool> field4 = {};
296 std::map<std::int32_t, bool> field5 = {};
297};
298
300 StringMessageData field1 = {};
301 std::vector<StringMessageData> field2 = {};
302 std::map<std::int32_t, StringMessageData> field3 = {};
303};
304
305proto_json::messages::Int32Message PrepareTestData(const Int32MessageData& message_data);
306void CheckMessageEqual(const proto_json::messages::Int32Message& lhs, const proto_json::messages::Int32Message& rhs);
307
308proto_json::messages::UInt32Message PrepareTestData(const UInt32MessageData& message_data);
309void CheckMessageEqual(const proto_json::messages::UInt32Message& lhs, const proto_json::messages::UInt32Message& rhs);
310
311proto_json::messages::Int64Message PrepareTestData(const Int64MessageData& message_data);
312void CheckMessageEqual(const proto_json::messages::Int64Message& lhs, const proto_json::messages::Int64Message& rhs);
313
314proto_json::messages::UInt64Message PrepareTestData(const UInt64MessageData& message_data);
315void CheckMessageEqual(const proto_json::messages::UInt64Message& lhs, const proto_json::messages::UInt64Message& rhs);
316
317proto_json::messages::FloatMessage PrepareTestData(const FloatMessageData& message_data);
318void CheckMessageEqual(const proto_json::messages::FloatMessage& lhs, const proto_json::messages::FloatMessage& rhs);
319
320proto_json::messages::DoubleMessage PrepareTestData(const DoubleMessageData& message_data);
321void CheckMessageEqual(const proto_json::messages::DoubleMessage& lhs, const proto_json::messages::DoubleMessage& rhs);
322
323proto_json::messages::BoolMessage PrepareTestData(const BoolMessageData& message_data);
324void CheckMessageEqual(const proto_json::messages::BoolMessage& lhs, const proto_json::messages::BoolMessage& rhs);
325
326proto_json::messages::StringMessage PrepareTestData(const StringMessageData& message_data);
327void CheckMessageEqual(const proto_json::messages::StringMessage& lhs, const proto_json::messages::StringMessage& rhs);
328
329proto_json::messages::BytesMessage PrepareTestData(const BytesMessageData& message_data);
330void CheckMessageEqual(const proto_json::messages::BytesMessage& lhs, const proto_json::messages::BytesMessage& rhs);
331
332proto_json::messages::EnumMessage PrepareTestData(const EnumMessageData& message_data);
333void CheckMessageEqual(const proto_json::messages::EnumMessage& lhs, const proto_json::messages::EnumMessage& rhs);
334
335proto_json::messages::NestedMessage PrepareTestData(const NestedMessageData& message_data);
336void CheckMessageEqual(const proto_json::messages::NestedMessage& lhs, const proto_json::messages::NestedMessage& rhs);
337
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
342);
343
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
349);
350
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
356);
357
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
363);
364
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);
370
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);
374
375proto_json::messages::OneofMessage PrepareTestData(const OneofMessageData& message_data);
376void CheckMessageEqual(const proto_json::messages::OneofMessage& lhs, const proto_json::messages::OneofMessage& rhs);
377
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
382);
383
384proto_json::messages::MapMessage PrepareTestData(const MapMessageData& message_data);
385void CheckMessageEqual(const proto_json::messages::MapMessage& lhs, const proto_json::messages::MapMessage& rhs);
386
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
391);
392
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
397);
398
399proto_json::messages::UnknownFieldMessage PrepareTestData(const UnknownFieldMessageData& message_data);
400void CheckMessageEqual(
401 const proto_json::messages::UnknownFieldMessage& lhs,
402 const proto_json::messages::UnknownFieldMessage& rhs
403);
404
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;
410};
411
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;
417};
418
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;
424};
425
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;
431};
432
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;
438};
439
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;
445};
446
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;
452};
453
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;
459};
460
463 static constexpr double kValue = 1.5;
464 static constexpr const char* kJson = "1.5";
465};
466
468 using Message = ::google::protobuf::FloatValue;
469 static constexpr float kValue = 1.5;
470 static constexpr const char* kJson = "1.5";
471};
472
474 using Message = ::google::protobuf::Int64Value;
475 static constexpr std::int64_t kValue = -123;
476 static constexpr const char* kJson = "-123";
477};
478
481 static constexpr std::uint64_t kValue = 123;
482 static constexpr const char* kJson = "123";
483};
484
486 using Message = ::google::protobuf::Int32Value;
487 static constexpr std::int32_t kValue = -321;
488 static constexpr const char* kJson = "-321";
489};
490
493 static constexpr std::uint32_t kValue = 321;
494 static constexpr const char* kJson = "321";
495};
496
497struct BoolValue {
498 using Message = ::google::protobuf::BoolValue;
499 static constexpr bool kValue = true;
500 static constexpr const char* kJson = "true";
501};
502
505 static constexpr std::string_view kValue = "hello";
506 static constexpr const char* kJson = "\"hello\"";
507};
508
510 using Message = ::google::protobuf::BytesValue;
511 static constexpr std::string_view kValue = "world";
512 static constexpr const char* kJson = "\"d29ybGQ=\"";
513};
514
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)>,
519 std::string>;
520
521} // namespace protobuf::json::tests
522
523USERVER_NAMESPACE_END