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 ReadOptions options = {};
25};
26
27struct DurationFromJsonFailureTestParam {
28 std::string input = {};
29 ReadErrorCode expected_errc = {};
30 std::string expected_path = {};
31 ReadOptions 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":[]})", ReadErrorCode::kInvalidType, "field1"},
82 DurationFromJsonFailureTestParam{R"({"field1":{}})", ReadErrorCode::kInvalidType, "field1", {}, true},
83 DurationFromJsonFailureTestParam{R"({"field1":true})", ReadErrorCode::kInvalidType, "field1"},
84 DurationFromJsonFailureTestParam{R"({"field1":1})", ReadErrorCode::kInvalidType, "field1"},
85 DurationFromJsonFailureTestParam{R"({"field1":""})", ReadErrorCode::kInvalidValue, "field1"},
86 DurationFromJsonFailureTestParam{R"({"field1":"abc"})", ReadErrorCode::kInvalidValue, "field1"},
87 DurationFromJsonFailureTestParam{R"({"field1":"0"})", ReadErrorCode::kInvalidValue, "field1"},
88 DurationFromJsonFailureTestParam{R"({"field1":"0.-0s"})", ReadErrorCode::kInvalidValue, "field1"},
89 DurationFromJsonFailureTestParam{R"({"field1":"0ss"})", ReadErrorCode::kInvalidValue, "field1"},
90 DurationFromJsonFailureTestParam{R"({"field1":"123-s"})", ReadErrorCode::kInvalidValue, "field1"},
91 DurationFromJsonFailureTestParam{R"({"field1":"-123.-1s"})", ReadErrorCode::kInvalidValue, "field1"},
92 DurationFromJsonFailureTestParam{R"({"field1":"315576000001.0s"})", ReadErrorCode::kInvalidValue, "field1"},
93 DurationFromJsonFailureTestParam{R"({"field1":"-315576000001.0s"})", ReadErrorCode::kInvalidValue, "field1"},
94 DurationFromJsonFailureTestParam{R"({"field1":"0.1000000000s"})", ReadErrorCode::kInvalidValue, "field1"},
95 DurationFromJsonFailureTestParam{R"({"field1":"-0.1000000000s"})", ReadErrorCode::kInvalidValue, "field1"},
96 DurationFromJsonFailureTestParam{R"({"field1":"1..1s"})", ReadErrorCode::kInvalidValue, "field1"},
97 DurationFromJsonFailureTestParam{R"({"field1":".1s"})", ReadErrorCode::kInvalidValue, "field1"},
98 DurationFromJsonFailureTestParam{R"({"field1":"1.1.s"})", ReadErrorCode::kInvalidValue, "field1"}
99 )
100);
101
102TEST_P(DurationFromJsonSuccessTest, Test) {
103 const auto& param = GetParam();
104
105 proto_json::messages::DurationMessage message, expected_message, sample_message;
106 formats::json::Value input = PrepareJsonTestData(param.input);
107 expected_message = PrepareTestData(param.expected_message);
108
109 message.mutable_field1()->set_seconds(100001);
110
111 UASSERT_NO_THROW((message = JsonToMessage<proto_json::messages::DurationMessage>(input, param.options)));
112 UASSERT_NO_THROW(InitSampleMessage(param.input, param.options, sample_message));
113
114 CheckMessageEqual(message, sample_message);
115 CheckMessageEqual(message, expected_message);
116}
117
118TEST_P(DurationFromJsonFailureTest, Test) {
119 const auto& param = GetParam();
120
121 proto_json::messages::DurationMessage sample_message;
122 formats::json::Value input = PrepareJsonTestData(param.input);
123
124 EXPECT_READ_ERROR(
125 (void)JsonToMessage<proto_json::messages::DurationMessage>(input, param.options),
126 param.expected_errc,
127 param.expected_path
128 );
129
130 if (!param.skip_native_check) {
131 UEXPECT_THROW(InitSampleMessage(param.input, param.options, sample_message), SampleError);
132 }
133}
134
135TEST(DurationFromJsonAdditionalTest, InlinedNonNull) {
136 using Message = ::google::protobuf::Duration;
137
138 const char* json_str = "\"123.987654321s\"";
139 const auto json = formats::json::FromString(json_str);
140 Message message, sample;
141
142 message.set_seconds(100001);
143
144 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
145 UASSERT_NO_THROW(InitSampleMessage(json_str, {}, sample));
146
147 EXPECT_EQ(message.seconds(), 123);
148 EXPECT_EQ(message.nanos(), 987654321);
149 CheckMessageEqual(message, sample);
150}
151
152TEST(DurationFromJsonAdditionalTest, InlinedNull) {
153 using Message = ::google::protobuf::Duration;
154
155 const auto json = formats::json::FromString("null");
156 Message message, sample;
157
158 message.set_seconds(100001);
159
160 UASSERT_NO_THROW((message = JsonToMessage<Message>(json)));
161 UASSERT_NO_THROW(InitSampleMessage("null", {}, sample));
162
163 EXPECT_EQ(message.seconds(), 0);
164 EXPECT_EQ(message.nanos(), 0);
165 CheckMessageEqual(message, sample);
166}
167
168TEST(DurationFromJsonAdditionalTest, DynamicMessage) {
169 using Message = ::google::protobuf::Duration;
170
171 const char* json_str = "\"123.000000987s\"";
172 const auto json = formats::json::FromString(json_str);
173 ::google::protobuf::DynamicMessageFactory factory;
174
175 {
176 std::unique_ptr<::google::protobuf::Message> message(factory.GetPrototype(Message::descriptor())->New());
177
178 UASSERT_NO_THROW(JsonToMessage(json, {}, *message));
179
180 const auto reflection = message->GetReflection();
181 const auto seconds_desc = message->GetDescriptor()->FindFieldByName("seconds");
182 const auto nanos_desc = message->GetDescriptor()->FindFieldByName("nanos");
183
184 EXPECT_EQ(reflection->GetInt64(*message, seconds_desc), 123);
185 EXPECT_EQ(reflection->GetInt32(*message, nanos_desc), 987);
186 }
187}
188
189} // namespace protobuf::json::tests
190
191USERVER_NAMESPACE_END