userver: /data/code/userver/libraries/protobuf/tests/json/repeated_from_json_test.cpp Source File
Loading...
Searching...
No Matches
repeated_from_json_test.cpp
1#include <gtest/gtest.h>
2
3#include <ostream>
4#include <string>
5
6#include <fmt/format.h>
7
8#include <userver/protobuf/json/convert.hpp>
9#include <userver/utest/assert_macros.hpp>
10
11#include "utils.hpp"
12
13USERVER_NAMESPACE_BEGIN
14
15namespace protobuf::json::tests {
16
17struct RepeatedFromJsonSuccessTestParam {
18 std::string input = {};
19 RepeatedMessageData expected_message = {};
20 ParseOptions options = {};
21};
22
23struct RepeatedFromJsonFailureTestParam {
24 std::string input = {};
25 ParseErrorCode expected_errc = {};
26 std::string expected_path = {};
27 ParseOptions options = {};
28
29 // Protobuf ProtoJSON legacy syntax supports some features which we want to prohibit (because
30 // we do not want our clients to use syntax that may break in the newer protobuf versions). This
31 // variable is used disable some checks that will fail for legacy syntax.
32 bool skip_native_check = false;
33};
34
35void PrintTo(const RepeatedFromJsonSuccessTestParam& param, std::ostream* os) {
36 *os << fmt::format("{{ input = '{}' }}", param.input);
37}
38
39void PrintTo(const RepeatedFromJsonFailureTestParam& param, std::ostream* os) {
40 *os << fmt::format("{{ input = '{}' }}", param.input);
41}
42
43class RepeatedFromJsonSuccessTest : public ::testing::TestWithParam<RepeatedFromJsonSuccessTestParam> {};
44class RepeatedFromJsonFailureTest : public ::testing::TestWithParam<RepeatedFromJsonFailureTestParam> {};
45
46INSTANTIATE_TEST_SUITE_P(
47 ,
48 RepeatedFromJsonSuccessTest,
49 ::testing::Values(
50 RepeatedFromJsonSuccessTestParam{R"({})", RepeatedMessageData{}},
51 RepeatedFromJsonSuccessTestParam{R"({"field1":[],"field2":[],"field3":[]})", RepeatedMessageData{}},
52 RepeatedFromJsonSuccessTestParam{R"({"field1":null,"field2":null,"field3":null})", RepeatedMessageData{}},
53 RepeatedFromJsonSuccessTestParam{
54 R"({
55 "field1":[100],
56 "field2":[{"field1":true}],
57 "field3":["123.987s"]
58 })",
59 RepeatedMessageData{{100}, {{true}}, {{.seconds = 123, .nanos = 987'000'000}}}
60 },
61 RepeatedFromJsonSuccessTestParam{
62 R"({
63 "field1":[100,0,200],
64 "field2":[{"field1":true},{"field1":false}],
65 "field3":["123.987s","0s","-987s"]
66 })",
67 RepeatedMessageData{
68 {100, 0, 200},
69 {{true}, {false}},
70 {{.seconds = 123, .nanos = 987'000'000}, {}, {.seconds = -987}}
71 }
72 }
73 )
74);
75
76INSTANTIATE_TEST_SUITE_P(
77 ,
78 RepeatedFromJsonFailureTest,
79 ::testing::Values(
80 RepeatedFromJsonFailureTestParam{R"({"field1":{}})", ParseErrorCode::kInvalidType, "field1"},
81 RepeatedFromJsonFailureTestParam{
82 R"({"field1":1})",
83 ParseErrorCode::kInvalidType,
84 "field1",
85 {},
86 true // legacy implementation treats single value as array of one item
87 },
88 RepeatedFromJsonFailureTestParam{R"({"field2":true})", ParseErrorCode::kInvalidType, "field2", {}, true},
89 RepeatedFromJsonFailureTestParam{R"({"field3":"test"})", ParseErrorCode::kInvalidType, "field3", {}, true},
90 RepeatedFromJsonFailureTestParam{
91 R"({"field1":[1, null, 2]})",
92 ParseErrorCode::kInvalidValue,
93 "field1[1]",
94 {},
95 true // legacy implementation ignores null as items
96 },
97 RepeatedFromJsonFailureTestParam{R"({"field2":[null]})", ParseErrorCode::kInvalidValue, "field2[0]", {}, true},
98 RepeatedFromJsonFailureTestParam{
99 R"({"field3":["123.100s", "-123.100s", null]})",
100 ParseErrorCode::kInvalidValue,
101 "field3[2]",
102 {},
103 true // legacy implementation ignores null as items
104 },
105 RepeatedFromJsonFailureTestParam{
106 R"({"field1":[[1,2,3]]})",
107 ParseErrorCode::kInvalidType,
108 "field1[0]",
109 {},
110 true // legacy implementation flattens array in this case
111 },
112 RepeatedFromJsonFailureTestParam{
113 R"({"field2":[[{"field1":true}]]})",
114 ParseErrorCode::kInvalidType,
115 "field2[0]",
116 {},
117 true // legacy implementation flattens array in this case
118 },
119 RepeatedFromJsonFailureTestParam{
120 R"({"field2":[{"field1":true},"oops"]})",
121 ParseErrorCode::kInvalidType,
122 "field2[1]"
123 },
124 RepeatedFromJsonFailureTestParam{
125 R"({"field3":["123.100s", "oops"]})",
126 ParseErrorCode::kInvalidValue,
127 "field3[1]"
128 }
129 )
130);
131
132TEST_P(RepeatedFromJsonSuccessTest, Test) {
133 using Message = proto_json::messages::RepeatedMessage;
134 const auto& param = GetParam();
135
136 Message message, expected_message, sample_message;
137 formats::json::Value input = PrepareJsonTestData(param.input);
138 expected_message = PrepareTestData(param.expected_message);
139
140 UASSERT_NO_THROW((message = JsonToMessage<Message>(input, param.options)));
141 UASSERT_NO_THROW(InitSampleMessage(param.input, sample_message, param.options));
142
143 CheckMessageEqual(message, sample_message);
144 CheckMessageEqual(message, expected_message);
145}
146
147TEST_P(RepeatedFromJsonFailureTest, Test) {
148 using Message = proto_json::messages::RepeatedMessage;
149 const auto& param = GetParam();
150
151 Message sample;
152 formats::json::Value input = PrepareJsonTestData(param.input);
153
154 EXPECT_PARSE_ERROR((void)JsonToMessage<Message>(input, param.options), param.expected_errc, param.expected_path);
155
156 if (!param.skip_native_check) {
157 UEXPECT_THROW(InitSampleMessage(param.input, sample, param.options), SampleError);
158 }
159}
160
161} // namespace protobuf::json::tests
162
163USERVER_NAMESPACE_END