userver: /data/code/userver/libraries/protobuf/tests/json/timestamp_from_json_test.cpp Source File
Loading...
Searching...
No Matches
timestamp_from_json_test.cpp
1#include <gtest/gtest.h>
2
3#include <chrono>
4#include <memory>
5#include <ostream>
6#include <string>
7
8#include <fmt/format.h>
9#include <google/protobuf/dynamic_message.h>
10
11#include <userver/formats/json/serialize.hpp>
12#include <userver/protobuf/datetime.hpp>
13#include <userver/protobuf/json/convert.hpp>
14#include <userver/utest/assert_macros.hpp>
15
16#include "utils.hpp"
17
18USERVER_NAMESPACE_BEGIN
19
20namespace protobuf::json::tests {
21
22using namespace std::chrono_literals;
23
24constexpr auto kTestSeconds = 1s + 1min + 1h + 24h + (31 * 24h) + (365 * 24h);
25
26struct TimestampFromJsonSuccessTestParam {
27 std::string input = {};
28 TimestampMessageData expected_message = {};
29 ParseOptions options = {};
30};
31
32struct TimestampFromJsonFailureTestParam {
33 std::string input = {};
34 ParseErrorCode expected_errc = {};
35 std::string expected_path = {};
36 ParseOptions options = {};
37
38 // Protobuf ProtoJSON legacy syntax supports some features, which we want to prohibit (because
39 // we do not want our clients to use syntax that may break in the newer protobuf versions).
40 // This variable is used disable some checks that will fail for legacy syntax.
41 bool skip_native_check = false;
42};
43
44void PrintTo(const TimestampFromJsonSuccessTestParam& param, std::ostream* os) {
45 *os << fmt::format("{{ input = '{}' }}", param.input);
46}
47
48void PrintTo(const TimestampFromJsonFailureTestParam& param, std::ostream* os) {
49 *os << fmt::format("{{ input = '{}' }}", param.input);
50}
51
52class TimestampFromJsonSuccessTest : public ::testing::TestWithParam<TimestampFromJsonSuccessTestParam> {};
53class TimestampFromJsonFailureTest : public ::testing::TestWithParam<TimestampFromJsonFailureTestParam> {};
54
55INSTANTIATE_TEST_SUITE_P(
56 ,
57 TimestampFromJsonSuccessTest,
58 ::testing::Values(
59 TimestampFromJsonSuccessTestParam{R"({})", TimestampMessageData{0, 0, true}},
60 TimestampFromJsonSuccessTestParam{R"({"field1":null})", TimestampMessageData{0, 0, true}},
61 TimestampFromJsonSuccessTestParam{R"({"field1":"1970-01-01T00:00:00Z"})", TimestampMessageData{0, 0}},
62 TimestampFromJsonSuccessTestParam{
63 R"({"field1":"1971-02-02T01:01:01.123456789Z"})",
64 TimestampMessageData{kTestSeconds.count(), 123456789}
65 },
66 TimestampFromJsonSuccessTestParam{
67 R"({"field1":"1968-11-29T22:58:59.987654321Z"})",
68 TimestampMessageData{-kTestSeconds.count(), 987654321}
69 },
70 TimestampFromJsonSuccessTestParam{
71 R"({"field1":"9999-12-31T23:59:59.999999999Z"})",
72 TimestampMessageData{kMaxTimestampSeconds, kMaxTimestampNanos}
73 },
74 TimestampFromJsonSuccessTestParam{
75 R"({"field1":"0001-01-01T00:00:00Z"})",
76 TimestampMessageData{kMinTimestampSeconds, kMinTimestampNanos}
77 },
78 TimestampFromJsonSuccessTestParam{
79 R"({"field1":"1970-01-01T00:00:00.123456780Z"})",
80 TimestampMessageData{0, 123456780}
81 },
82 TimestampFromJsonSuccessTestParam{
83 R"({"field1":"1970-01-01T00:00:00.123456Z"})",
84 TimestampMessageData{0, 123456000}
85 },
86 TimestampFromJsonSuccessTestParam{
87 R"({"field1":"1970-01-01T00:00:00.123400Z"})",
88 TimestampMessageData{0, 123400000}
89 },
90 TimestampFromJsonSuccessTestParam{
91 R"({"field1":"1970-01-01T00:00:00.100Z"})",
92 TimestampMessageData{0, 100000000}
93 },
94 TimestampFromJsonSuccessTestParam{R"({"field1":"1970-01-01T00:00:00.000000009Z"})", TimestampMessageData{0, 9}},
95 TimestampFromJsonSuccessTestParam{
96 R"({"field1":"1970-01-01T00:01:13.123+02:00"})",
97 TimestampMessageData{-(2 * 60 * 60) + 60 + 13, 123000000}
98 },
99 TimestampFromJsonSuccessTestParam{
100 R"({"field1":"1970-01-01T00:01:13.123-02:00"})",
101 TimestampMessageData{(2 * 60 * 60) + 60 + 13, 123000000}
102 },
103 TimestampFromJsonSuccessTestParam{
104 R"({"field1":"1970-01-01T00:01:13.123+02:10"})",
105 TimestampMessageData{-(2 * 60 * 60 + 10 * 60) + 60 + 13, 123000000}
106 },
107 TimestampFromJsonSuccessTestParam{
108 R"({"field1":"1970-01-01T00:01:13.123-02:10"})",
109 TimestampMessageData{(2 * 60 * 60 + 10 * 60) + 60 + 13, 123000000}
110 },
111 TimestampFromJsonSuccessTestParam{
112 R"({"field1":"1970-01-01T00:01:13.123+00:00"})",
113 TimestampMessageData{60 + 13, 123000000}
114 },
115 TimestampFromJsonSuccessTestParam{
116 R"({"field1":"1970-01-01T00:01:13.123-00:00"})",
117 TimestampMessageData{60 + 13, 123000000}
118 }
119 )
120);
121
122INSTANTIATE_TEST_SUITE_P(
123 ,
124 TimestampFromJsonFailureTest,
125 ::testing::Values(
126 TimestampFromJsonFailureTestParam{R"({"field1":[]})", ParseErrorCode::kInvalidType, "field1"},
127 TimestampFromJsonFailureTestParam{R"({"field1":{}})", ParseErrorCode::kInvalidType, "field1", {}, true},
128 TimestampFromJsonFailureTestParam{R"({"field1":true})", ParseErrorCode::kInvalidType, "field1"},
129 TimestampFromJsonFailureTestParam{R"({"field1":10})", ParseErrorCode::kInvalidType, "field1"},
130 TimestampFromJsonFailureTestParam{R"({"field1":""})", ParseErrorCode::kInvalidValue, "field1"},
131 TimestampFromJsonFailureTestParam{R"({"field1":"abc"})", ParseErrorCode::kInvalidValue, "field1"},
132 TimestampFromJsonFailureTestParam{R"({"field1":"-"})", ParseErrorCode::kInvalidValue, "field1"},
133 TimestampFromJsonFailureTestParam{R"({"field1":"2010"})", ParseErrorCode::kInvalidValue, "field1"},
134 TimestampFromJsonFailureTestParam{R"({"field1":"2010-"})", ParseErrorCode::kInvalidValue, "field1"},
135 TimestampFromJsonFailureTestParam{R"({"field1":"2010-10"})", ParseErrorCode::kInvalidValue, "field1"},
136 TimestampFromJsonFailureTestParam{R"({"field1":"2010-10-"})", ParseErrorCode::kInvalidValue, "field1"},
137 TimestampFromJsonFailureTestParam{R"({"field1":"2010-10-10"})", ParseErrorCode::kInvalidValue, "field1"},
138 TimestampFromJsonFailureTestParam{R"({"field1":"2010-10-10T"})", ParseErrorCode::kInvalidValue, "field1"},
139 TimestampFromJsonFailureTestParam{R"({"field1":"2010-10-10T10"})", ParseErrorCode::kInvalidValue, "field1"},
140 TimestampFromJsonFailureTestParam{R"({"field1":"2010-10-10T10:10"})", ParseErrorCode::kInvalidValue, "field1"},
141 TimestampFromJsonFailureTestParam{
142 R"({"field1":"2010-10-10T10:10:10"})",
143 ParseErrorCode::kInvalidValue,
144 "field1"
145 },
146 TimestampFromJsonFailureTestParam{
147 R"({"field1":"2010-10-10T10:10:10z"})",
148 ParseErrorCode::kInvalidValue,
149 "field1"
150 },
151 TimestampFromJsonFailureTestParam{
152 R"({"field1":"2010-10-10T10:10:10ZZ"})",
153 ParseErrorCode::kInvalidValue,
154 "field1"
155 },
156 TimestampFromJsonFailureTestParam{
157 R"({"field1":"2010-10-10T10:10:10+"})",
158 ParseErrorCode::kInvalidValue,
159 "field1"
160 },
161 TimestampFromJsonFailureTestParam{
162 R"({"field1":"2010-10-10T10:10:10+02"})",
163 ParseErrorCode::kInvalidValue,
164 "field1"
165 },
166 TimestampFromJsonFailureTestParam{
167 R"({"field1":"2010-10-10T10:10:10-02:"})",
168 ParseErrorCode::kInvalidValue,
169 "field1"
170 },
171 TimestampFromJsonFailureTestParam{
172 R"({"field1":"2010-10-10T10:10:10+02:00Z"})",
173 ParseErrorCode::kInvalidValue,
174 "field1"
175 },
176 TimestampFromJsonFailureTestParam{
177 R"({"field1":"2010-10-10T10:10:10+02:0"})",
178 ParseErrorCode::kInvalidValue,
179 "field1"
180 },
181 TimestampFromJsonFailureTestParam{
182 R"({"field1":"2010-10-10T10:10:10+2:00"})",
183 ParseErrorCode::kInvalidValue,
184 "field1"
185 },
186 TimestampFromJsonFailureTestParam{
187 R"({"field1":"2010-10-10T10:10:10Z+02:00"})",
188 ParseErrorCode::kInvalidValue,
189 "field1"
190 },
191 TimestampFromJsonFailureTestParam{
192 R"({"field1":"2010-10-10T10:10:1Z"})",
193 ParseErrorCode::kInvalidValue,
194 "field1"
195 },
196 TimestampFromJsonFailureTestParam{
197 R"({"field1":"2010-10-10T10:1:10Z"})",
198 ParseErrorCode::kInvalidValue,
199 "field1"
200 },
201 TimestampFromJsonFailureTestParam{
202 R"({"field1":"2010-10-10T1:10:10Z"})",
203 ParseErrorCode::kInvalidValue,
204 "field1"
205 },
206 TimestampFromJsonFailureTestParam{
207 R"({"field1":"2010-10-10T1:10:10Z"})",
208 ParseErrorCode::kInvalidValue,
209 "field1"
210 },
211 TimestampFromJsonFailureTestParam{
212 R"({"field1":"2010-10-10t10:10:10Z"})",
213 ParseErrorCode::kInvalidValue,
214 "field1"
215 },
216 TimestampFromJsonFailureTestParam{
217 R"({"field1":"2010-10-10TT10:10:10Z"})",
218 ParseErrorCode::kInvalidValue,
219 "field1"
220 },
221 TimestampFromJsonFailureTestParam{
222 R"({"field1":"2010-10-1T10:10:10Z"})",
223 ParseErrorCode::kInvalidValue,
224 "field1"
225 },
226 TimestampFromJsonFailureTestParam{
227 R"({"field1":"2010-1-10T10:10:10Z"})",
228 ParseErrorCode::kInvalidValue,
229 "field1"
230 },
231 TimestampFromJsonFailureTestParam{
232 R"({"field1":"201-10-10T10:10:10Z"})",
233 ParseErrorCode::kInvalidValue,
234 "field1"
235 },
236 TimestampFromJsonFailureTestParam{
237 R"({"field1":"201A-10-10T10:10:10Z"})",
238 ParseErrorCode::kInvalidValue,
239 "field1"
240 },
241 TimestampFromJsonFailureTestParam{
242 R"({"field1":"2010--10-10T10:10:10Z"})",
243 ParseErrorCode::kInvalidValue,
244 "field1"
245 },
246 TimestampFromJsonFailureTestParam{
247 R"({"field1":"2010-1A-10T10:10:10Z"})",
248 ParseErrorCode::kInvalidValue,
249 "field1"
250 },
251 TimestampFromJsonFailureTestParam{
252 R"({"field1":"2010-10--10T10:10:10Z"})",
253 ParseErrorCode::kInvalidValue,
254 "field1"
255 },
256 TimestampFromJsonFailureTestParam{
257 R"({"field1":"2010-10-1AT10:10:10Z"})",
258 ParseErrorCode::kInvalidValue,
259 "field1"
260 },
261 TimestampFromJsonFailureTestParam{
262 R"({"field1":"2010-10-10T1A:10:10Z"})",
263 ParseErrorCode::kInvalidValue,
264 "field1"
265 },
266 TimestampFromJsonFailureTestParam{
267 R"({"field1":"2010-10-10T10-10:10Z"})",
268 ParseErrorCode::kInvalidValue,
269 "field1"
270 },
271 TimestampFromJsonFailureTestParam{
272 R"({"field1":"2010-10-10T10:1A:10Z"})",
273 ParseErrorCode::kInvalidValue,
274 "field1"
275 },
276 TimestampFromJsonFailureTestParam{
277 R"({"field1":"2010-10-10T10:10::10Z"})",
278 ParseErrorCode::kInvalidValue,
279 "field1"
280 },
281 TimestampFromJsonFailureTestParam{
282 R"({"field1":"2010-10-10T10:10:1AZ"})",
283 ParseErrorCode::kInvalidValue,
284 "field1"
285 },
286 TimestampFromJsonFailureTestParam{
287 R"({"field1":"2010-10-10T10:10:10+-02:00"})",
288 ParseErrorCode::kInvalidValue,
289 "field1"
290 }
291 )
292);
293
294TEST_P(TimestampFromJsonSuccessTest, Test) {
295 const auto& param = GetParam();
296
297 proto_json::messages::TimestampMessage message, expected_message, sample_message;
298 formats::json::Value input = PrepareJsonTestData(param.input);
299 expected_message = PrepareTestData(param.expected_message);
300
301 message.mutable_field1()->set_seconds(100001);
302
303 UASSERT_NO_THROW((message = JsonToMessage<proto_json::messages::TimestampMessage>(input, param.options)));
304 UASSERT_NO_THROW(InitSampleMessage(param.input, sample_message, param.options));
305
306 CheckMessageEqual(message, sample_message);
307 CheckMessageEqual(message, expected_message);
308}
309
310TEST_P(TimestampFromJsonFailureTest, Test) {
311 const auto& param = GetParam();
312
313 proto_json::messages::TimestampMessage sample_message;
314 formats::json::Value input = PrepareJsonTestData(param.input);
315
317 (void)JsonToMessage<proto_json::messages::TimestampMessage>(input, param.options),
318 param.expected_errc,
319 param.expected_path
320 );
321
322 if (!param.skip_native_check) {
323 UEXPECT_THROW(InitSampleMessage(param.input, sample_message, param.options), SampleError);
324 }
325}
326
327TEST(TimestampFromJsonAdditionalTest, InlinedNonNull) {
328 using Message = ::google::protobuf::Timestamp;
329
330 const char* json_str = "\"1970-01-01T00:02:03.000000321Z\"";
331 const auto json = formats::json::FromString(json_str);
332 Message message, sample;
333
334 message.set_seconds(100001);
335
336 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
337 UASSERT_NO_THROW(InitSampleMessage(json_str, sample));
338
339 EXPECT_EQ(message.seconds(), 123);
340 EXPECT_EQ(message.nanos(), 321);
341 CheckMessageEqual(message, sample);
342}
343
344TEST(TimestampFromJsonAdditionalTest, InlinedNull) {
345 using Message = ::google::protobuf::Timestamp;
346
347 const auto json = formats::json::FromString("null");
348 Message message, sample;
349
350 message.set_seconds(100001);
351
352 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
353 UASSERT_NO_THROW(InitSampleMessage("null", sample));
354
355 EXPECT_EQ(message.seconds(), 0);
356 EXPECT_EQ(message.nanos(), 0);
357 CheckMessageEqual(message, sample);
358}
359
360TEST(TimestampFromJsonAdditionalTest, DynamicMessage) {
361 using Message = ::google::protobuf::Timestamp;
362
363 const char* json_str = "\"2016-02-29T00:00:00.123450Z\"";
364 const auto json = formats::json::FromString(json_str);
365 ::google::protobuf::DynamicMessageFactory factory;
366
367 {
368 std::unique_ptr<::google::protobuf::Message> message(factory.GetPrototype(Message::descriptor())->New());
369
370 UASSERT_NO_THROW(JsonToMessage(json, *message));
371
372 const auto reflection = message->GetReflection();
373 const auto seconds_desc = message->GetDescriptor()->FindFieldByName("seconds");
374 const auto nanos_desc = message->GetDescriptor()->FindFieldByName("nanos");
375
376 EXPECT_EQ(reflection->GetInt64(*message, seconds_desc), 1456704000);
377 EXPECT_EQ(reflection->GetInt32(*message, nanos_desc), 123450000);
378 }
379}
380
381} // namespace protobuf::json::tests
382
383USERVER_NAMESPACE_END