userver: /data/code/userver/libraries/protobuf/tests/json/timestamp_to_json_test.cpp Source File
Loading...
Searching...
No Matches
timestamp_to_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/protobuf/datetime.hpp>
12#include <userver/protobuf/json/convert.hpp>
13#include <userver/utest/assert_macros.hpp>
14
15#include "utils.hpp"
16
17USERVER_NAMESPACE_BEGIN
18
19namespace protobuf::json::tests {
20
21using namespace std::chrono_literals;
22
23constexpr auto kTestSeconds = 1s + 1min + 1h + 24h + (31 * 24h) + (365 * 24h);
24
25struct TimestampToJsonSuccessTestParam {
26 TimestampMessageData input = {};
27 std::string expected_json = {};
28 PrintOptions options = {};
29};
30
31struct TimestampToJsonFailureTestParam {
32 TimestampMessageData input = {};
33 PrintErrorCode expected_errc = {};
34 std::string expected_path = {};
35 PrintOptions options = {};
36
37 // Older protobuf versions erroneously pass some checks, we need a way to disable them.
38 bool skip_native_check = false;
39};
40
41void PrintTo(const TimestampToJsonSuccessTestParam& param, std::ostream* os) {
42 *os << fmt::format("{{ input = {{.seconds={}, .nanos={}}} }}", param.input.seconds, param.input.nanos);
43}
44
45void PrintTo(const TimestampToJsonFailureTestParam& param, std::ostream* os) {
46 *os << fmt::format("{{ input = {{.seconds={}, .nanos={}}} }}", param.input.seconds, param.input.nanos);
47}
48
49class TimestampToJsonSuccessTest : public ::testing::TestWithParam<TimestampToJsonSuccessTestParam> {};
50class TimestampToJsonFailureTest : public ::testing::TestWithParam<TimestampToJsonFailureTestParam> {};
51
52INSTANTIATE_TEST_SUITE_P(
53 ,
54 TimestampToJsonSuccessTest,
55 ::testing::Values(
56 TimestampToJsonSuccessTestParam{TimestampMessageData{0, 0, true}, R"({})"},
57 TimestampToJsonSuccessTestParam{TimestampMessageData{0, 0}, R"({"field1": "1970-01-01T00:00:00Z"})"},
58 TimestampToJsonSuccessTestParam{
59 TimestampMessageData{kTestSeconds.count(), 123456789},
60 R"({"field1": "1971-02-02T01:01:01.123456789Z"})"
61 },
62 TimestampToJsonSuccessTestParam{
63 TimestampMessageData{-kTestSeconds.count(), 987654321},
64 R"({"field1": "1968-11-29T22:58:59.987654321Z"})"
65 },
66 TimestampToJsonSuccessTestParam{
67 TimestampMessageData{kMaxTimestampSeconds, kMaxTimestampNanos},
68 R"({"field1": "9999-12-31T23:59:59.999999999Z"})"
69 },
70 TimestampToJsonSuccessTestParam{
71 TimestampMessageData{kMinTimestampSeconds, kMinTimestampNanos},
72 R"({"field1": "0001-01-01T00:00:00Z"})"
73 },
74 TimestampToJsonSuccessTestParam{
75 TimestampMessageData{0, 123456780},
76 R"({"field1": "1970-01-01T00:00:00.123456780Z"})"
77 },
78 TimestampToJsonSuccessTestParam{
79 TimestampMessageData{0, 123456000},
80 R"({"field1": "1970-01-01T00:00:00.123456Z"})"
81 },
82 TimestampToJsonSuccessTestParam{
83 TimestampMessageData{0, 123400000},
84 R"({"field1": "1970-01-01T00:00:00.123400Z"})"
85 },
86 TimestampToJsonSuccessTestParam{
87 TimestampMessageData{0, 100000000},
88 R"({"field1": "1970-01-01T00:00:00.100Z"})"
89 },
90 TimestampToJsonSuccessTestParam{
91 TimestampMessageData{1456704000, 123450000},
92 R"({"field1": "2016-02-29T00:00:00.123450Z"})"
93 },
94 TimestampToJsonSuccessTestParam{TimestampMessageData{0, 9}, R"({"field1": "1970-01-01T00:00:00.000000009Z"})"}
95 )
96);
97
98#if GOOGLE_PROTOBUF_VERSION >= 6033000
99constexpr bool kNanosSkipNativeCheck = false;
100#else
101constexpr bool kNanosSkipNativeCheck = true;
102#endif
103
104INSTANTIATE_TEST_SUITE_P(
105 ,
106 TimestampToJsonFailureTest,
107 ::testing::Values(
108 TimestampToJsonFailureTestParam{
109 TimestampMessageData{kMaxTimestampSeconds + 1, 0},
111 "field1"
112 },
113 TimestampToJsonFailureTestParam{
114 TimestampMessageData{kMinTimestampSeconds - 1, 0},
116 "field1"
117 },
118 TimestampToJsonFailureTestParam{
119 TimestampMessageData{0, kMaxTimestampNanos + 1},
121 "field1",
122 {},
123 kNanosSkipNativeCheck
124 },
125 TimestampToJsonFailureTestParam{
126 TimestampMessageData{0, kMinTimestampNanos - 1},
128 "field1",
129 {},
130 kNanosSkipNativeCheck
131 }
132 )
133);
134
135TEST_P(TimestampToJsonSuccessTest, Test) {
136 const auto& param = GetParam();
137
138 auto input = PrepareTestData(param.input);
139 formats::json::Value json;
140 formats::json::Value expected_json;
141 formats::json::Value sample_json;
142
143 UASSERT_NO_THROW((json = MessageToJson(input, param.options)));
144 UASSERT_NO_THROW((expected_json = PrepareJsonTestData(param.expected_json)));
145 UASSERT_NO_THROW((sample_json = CreateSampleJson(input, param.options)));
146
147 EXPECT_EQ(json, expected_json);
148 EXPECT_EQ(expected_json, sample_json);
149}
150
151TEST_P(TimestampToJsonFailureTest, Test) {
152 const auto& param = GetParam();
153 auto input = PrepareTestData(param.input);
154
155 EXPECT_PRINT_ERROR((void)MessageToJson(input, param.options), param.expected_errc, param.expected_path);
156
157 if (!param.skip_native_check) {
158 UEXPECT_THROW((void)CreateSampleJson(input, param.options), SampleError);
159 }
160}
161
162TEST(TimestampToJsonAdditionalTest, InlinedNonNull) {
163 TimestampMessageData data{123, 321};
164 auto message = PrepareTestData(data);
165 formats::json::Value json;
166 formats::json::Value sample;
167
168 UASSERT_NO_THROW((json = MessageToJson(message.field1(), {})));
169 UASSERT_NO_THROW((sample = CreateSampleJson(message.field1())));
170 ASSERT_TRUE(json.IsString());
171 EXPECT_EQ(json, sample);
172 EXPECT_EQ(json.As<std::string>(), "1970-01-01T00:02:03.000000321Z");
173}
174
175TEST(TimestampToJsonAdditionalTest, InlinedNull) {
176 proto_json::messages::TimestampMessage message;
177 formats::json::Value json;
178 formats::json::Value sample;
179
180 UASSERT_NO_THROW((json = MessageToJson(message.field1(), {})));
181 UASSERT_NO_THROW((sample = CreateSampleJson(message.field1())));
182 ASSERT_TRUE(json.IsString());
183 EXPECT_EQ(json, sample);
184 EXPECT_EQ(json.As<std::string>(), "1970-01-01T00:00:00Z");
185}
186
187TEST(TimestampToJsonAdditionalTest, DynamicMessage) {
188 using Message = ::google::protobuf::Timestamp;
189 ::google::protobuf::DynamicMessageFactory factory;
190
191 {
192 std::unique_ptr<::google::protobuf::Message> message(factory.GetPrototype(Message::descriptor())->New());
193 const auto reflection = message->GetReflection();
194 const auto seconds_desc = message->GetDescriptor()->FindFieldByName("seconds");
195 const auto nanos_desc = message->GetDescriptor()->FindFieldByName("nanos");
196
197 reflection->SetInt64(message.get(), seconds_desc, 1456704000);
198 reflection->SetInt32(message.get(), nanos_desc, 123450000);
199
200 formats::json::Value json;
201
202 UASSERT_NO_THROW((json = MessageToJson(*message, {})));
203 ASSERT_TRUE(json.IsString());
204 EXPECT_EQ(json.As<std::string>(), "2016-02-29T00:00:00.123450Z");
205 }
206}
207
208} // namespace protobuf::json::tests
209
210USERVER_NAMESPACE_END