userver: /data/code/userver/libraries/protobuf/tests/json/duration_from_json_test.cpp Source File
Loading...
Searching...
No Matches
duration_from_json_test.cpp
1#include <gtest/gtest.h>
2
3#include <memory>
4#include <ostream>
5#include <string>
6
7#include <fmt/format.h>
8#include <google/protobuf/dynamic_message.h>
9
10#include <userver/formats/json/serialize.hpp>
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
21struct DurationFromJsonSuccessTestParam {
22 std::string input = {};
23 DurationMessageData expected_message = {};
24 ParseOptions options = {};
25};
26
27struct DurationFromJsonFailureTestParam {
28 std::string input = {};
29 ParseErrorCode expected_errc = {};
30 std::string expected_path = {};
31 ParseOptions options = {};
32
33 // Protobuf ProtoJSON legacy syntax supports some features, which we want to prohibit (because
34 // we do not want our clients to use syntax that may break in the newer protobuf versions).
35 // This variable is used disable some checks that will fail for legacy syntax.
36 bool skip_native_check = false;
37};
38
39void PrintTo(const DurationFromJsonSuccessTestParam& param, std::ostream* os) {
40 *os << fmt::format("{{ input = '{}' }}", param.input);
41}
42
43void PrintTo(const DurationFromJsonFailureTestParam& param, std::ostream* os) {
44 *os << fmt::format("{{ input = '{}' }}", param.input);
45}
46
47class DurationFromJsonSuccessTest : public ::testing::TestWithParam<DurationFromJsonSuccessTestParam> {};
48class DurationFromJsonFailureTest : public ::testing::TestWithParam<DurationFromJsonFailureTestParam> {};
49
50INSTANTIATE_TEST_SUITE_P(
51 ,
52 DurationFromJsonSuccessTest,
53 ::testing::Values(
54 DurationFromJsonSuccessTestParam{R"({})", DurationMessageData{0, 0, true}},
55 DurationFromJsonSuccessTestParam{R"({"field1":null})", DurationMessageData{0, 0, true}},
56 DurationFromJsonSuccessTestParam{R"({"field1":"0s"})", DurationMessageData{0, 0}},
57 DurationFromJsonSuccessTestParam{R"({"field1":"0.0s"})", DurationMessageData{0, 0}},
58 DurationFromJsonSuccessTestParam{R"({"field1":"-0.0s"})", DurationMessageData{0, 0}},
59 DurationFromJsonSuccessTestParam{
60 R"({"field1":"315576000000.999999999s"})",
61 DurationMessageData{kMaxDurationSeconds, kMaxDurationNanos}
62 },
63 DurationFromJsonSuccessTestParam{
64 R"({"field1":"-315576000000.999999999s"})",
65 DurationMessageData{kMinDurationSeconds, kMinDurationNanos}
66 },
67 DurationFromJsonSuccessTestParam{R"({"field1":"123.987654321s"})", DurationMessageData{123, 987654321}},
68 DurationFromJsonSuccessTestParam{R"({"field1":"-123.98765432s"})", DurationMessageData{-123, -987654320}},
69 DurationFromJsonSuccessTestParam{R"({"field1":"123.9876543s"})", DurationMessageData{123, 987654300}},
70 DurationFromJsonSuccessTestParam{R"({"field1":"-123.987654s"})", DurationMessageData{-123, -987654000}},
71 DurationFromJsonSuccessTestParam{R"({"field1":"123.987654000s"})", DurationMessageData{123, 987654000}},
72 DurationFromJsonSuccessTestParam{R"({"field1":"-123.9s"})", DurationMessageData{-123, -900000000}},
73 DurationFromJsonSuccessTestParam{R"({"field1":"123.000000009s"})", DurationMessageData{123, 9}}
74 )
75);
76
77INSTANTIATE_TEST_SUITE_P(
78 ,
79 DurationFromJsonFailureTest,
80 ::testing::Values(
81 DurationFromJsonFailureTestParam{R"({"field1":[]})", ParseErrorCode::kInvalidType, "field1"},
82 DurationFromJsonFailureTestParam{R"({"field1":{}})", ParseErrorCode::kInvalidType, "field1", {}, true},
83 DurationFromJsonFailureTestParam{R"({"field1":true})", ParseErrorCode::kInvalidType, "field1"},
84 DurationFromJsonFailureTestParam{R"({"field1":1})", ParseErrorCode::kInvalidType, "field1"},
85 DurationFromJsonFailureTestParam{R"({"field1":""})", ParseErrorCode::kInvalidValue, "field1"},
86 DurationFromJsonFailureTestParam{R"({"field1":"abc"})", ParseErrorCode::kInvalidValue, "field1"},
87 DurationFromJsonFailureTestParam{R"({"field1":"0"})", ParseErrorCode::kInvalidValue, "field1"},
88 DurationFromJsonFailureTestParam{R"({"field1":"0.-0s"})", ParseErrorCode::kInvalidValue, "field1"},
89 DurationFromJsonFailureTestParam{R"({"field1":"0ss"})", ParseErrorCode::kInvalidValue, "field1"},
90 DurationFromJsonFailureTestParam{R"({"field1":"123-s"})", ParseErrorCode::kInvalidValue, "field1"},
91 DurationFromJsonFailureTestParam{R"({"field1":"-123.-1s"})", ParseErrorCode::kInvalidValue, "field1"},
92 DurationFromJsonFailureTestParam{R"({"field1":"315576000001.0s"})", ParseErrorCode::kInvalidValue, "field1"},
93 DurationFromJsonFailureTestParam{R"({"field1":"-315576000001.0s"})", ParseErrorCode::kInvalidValue, "field1"},
94 DurationFromJsonFailureTestParam{R"({"field1":"0.1000000000s"})", ParseErrorCode::kInvalidValue, "field1"},
95 DurationFromJsonFailureTestParam{R"({"field1":"-0.1000000000s"})", ParseErrorCode::kInvalidValue, "field1"},
96 DurationFromJsonFailureTestParam{R"({"field1":"1..1s"})", ParseErrorCode::kInvalidValue, "field1"},
97 DurationFromJsonFailureTestParam{R"({"field1":".1s"})", ParseErrorCode::kInvalidValue, "field1"},
98 DurationFromJsonFailureTestParam{R"({"field1":"1.1.s"})", ParseErrorCode::kInvalidValue, "field1"}
99 )
100);
101
102TEST_P(DurationFromJsonSuccessTest, Test) {
103 const auto& param = GetParam();
104
105 proto_json::messages::DurationMessage message;
106 proto_json::messages::DurationMessage expected_message;
107 proto_json::messages::DurationMessage sample_message;
108 formats::json::Value input = PrepareJsonTestData(param.input);
109 expected_message = PrepareTestData(param.expected_message);
110
111 message.mutable_field1()->set_seconds(100001);
112
113 UASSERT_NO_THROW((message = JsonToMessage<proto_json::messages::DurationMessage>(input, param.options)));
114 UASSERT_NO_THROW(InitSampleMessage(param.input, sample_message, param.options));
115
116 CheckMessageEqual(message, sample_message);
117 CheckMessageEqual(message, expected_message);
118}
119
120TEST_P(DurationFromJsonFailureTest, Test) {
121 const auto& param = GetParam();
122
123 proto_json::messages::DurationMessage sample_message;
124 formats::json::Value input = PrepareJsonTestData(param.input);
125
127 (void)JsonToMessage<proto_json::messages::DurationMessage>(input, param.options),
128 param.expected_errc,
129 param.expected_path
130 );
131
132 if (!param.skip_native_check) {
133 UEXPECT_THROW(InitSampleMessage(param.input, sample_message, param.options), SampleError);
134 }
135}
136
137TEST(DurationFromJsonAdditionalTest, InlinedNonNull) {
138 using Message = ::google::protobuf::Duration;
139
140 const char* json_str = "\"123.987654321s\"";
141 const auto json = formats::json::FromString(json_str);
142 Message message;
143 Message sample;
144
145 message.set_seconds(100001);
146
147 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
148 UASSERT_NO_THROW(InitSampleMessage(json_str, sample));
149
150 EXPECT_EQ(message.seconds(), 123);
151 EXPECT_EQ(message.nanos(), 987654321);
152 CheckMessageEqual(message, sample);
153}
154
155TEST(DurationFromJsonAdditionalTest, InlinedNull) {
156 using Message = ::google::protobuf::Duration;
157
158 const auto json = formats::json::FromString("null");
159 Message message;
160 Message sample;
161
162 message.set_seconds(100001);
163
164 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
165 UASSERT_NO_THROW(InitSampleMessage("null", sample));
166
167 EXPECT_EQ(message.seconds(), 0);
168 EXPECT_EQ(message.nanos(), 0);
169 CheckMessageEqual(message, sample);
170}
171
172TEST(DurationFromJsonAdditionalTest, DynamicMessage) {
173 using Message = ::google::protobuf::Duration;
174
175 const char* json_str = "\"123.000000987s\"";
176 const auto json = formats::json::FromString(json_str);
177 ::google::protobuf::DynamicMessageFactory factory;
178
179 {
180 std::unique_ptr<::google::protobuf::Message> message(factory.GetPrototype(Message::descriptor())->New());
181
182 UASSERT_NO_THROW(JsonToMessage(json, *message));
183
184 const auto reflection = message->GetReflection();
185 const auto seconds_desc = message->GetDescriptor()->FindFieldByName("seconds");
186 const auto nanos_desc = message->GetDescriptor()->FindFieldByName("nanos");
187
188 EXPECT_EQ(reflection->GetInt64(*message, seconds_desc), 123);
189 EXPECT_EQ(reflection->GetInt32(*message, nanos_desc), 987);
190 }
191}
192
193} // namespace protobuf::json::tests
194
195USERVER_NAMESPACE_END