userver: /data/code/userver/libraries/protobuf/tests/json/wrapper_to_json_test.cpp Source File
Loading...
Searching...
No Matches
wrapper_to_json_test.cpp
1#include <gtest/gtest.h>
2
3#include <memory>
4#include <string>
5
6#include <fmt/format.h>
7#include <google/protobuf/dynamic_message.h>
8
9#include <userver/crypto/base64.hpp>
10#include <userver/protobuf/json/convert.hpp>
11#include <userver/utest/assert_macros.hpp>
12#include <userver/utils/from_string.hpp>
13
14#include "utils.hpp"
15
16USERVER_NAMESPACE_BEGIN
17
18namespace protobuf::json::tests {
19
20template <typename T>
21void SetWrappedValue(::google::protobuf::Message& msg, T value) {
22 const auto reflection = msg.GetReflection();
23 const auto value_desc = msg.GetDescriptor()->FindFieldByName("value");
24
25 if (!value_desc) {
26 throw std::runtime_error("Field 'value' is not found in wrapper message");
27 }
28
29 if constexpr (std::is_same_v<T, double>) {
30 return reflection->SetDouble(&msg, value_desc, value);
31 } else if constexpr (std::is_same_v<T, float>) {
32 return reflection->SetFloat(&msg, value_desc, value);
33 } else if constexpr (std::is_same_v<T, std::int64_t>) {
34 return reflection->SetInt64(&msg, value_desc, value);
35 } else if constexpr (std::is_same_v<T, std::uint64_t>) {
36 return reflection->SetUInt64(&msg, value_desc, value);
37 } else if constexpr (std::is_same_v<T, std::int32_t>) {
38 return reflection->SetInt32(&msg, value_desc, value);
39 } else if constexpr (std::is_same_v<T, std::uint32_t>) {
40 return reflection->SetUInt32(&msg, value_desc, value);
41 } else if constexpr (std::is_same_v<T, bool>) {
42 return reflection->SetBool(&msg, value_desc, value);
43 } else if constexpr (std::is_same_v<T, std::string_view>) {
44 return reflection->SetString(&msg, value_desc, {value.begin(), value.end()});
45 } else {
46 static_assert(sizeof(T) && false, "unexpected type");
47 }
48}
49
50template <typename TParam>
51auto GetJsonValue(const formats::json::Value& json) {
52 using Type = WrappedType<TParam>;
53
54 if constexpr (std::is_same_v<Type, double>) {
55 return json.As<double>();
56 } else if constexpr (std::is_same_v<Type, float>) {
57 return json.As<float>();
58 } else if constexpr (std::is_same_v<Type, std::int64_t> || std::is_same_v<Type, std::uint64_t>) {
59 return utils::FromString<Type>(json.As<std::string>());
60 } else if constexpr (std::is_same_v<Type, std::int32_t>) {
61 return json.As<std::int32_t>();
62 } else if constexpr (std::is_same_v<Type, std::uint32_t>) {
63 return json.As<std::uint32_t>();
64 } else if constexpr (std::is_same_v<Type, bool>) {
65 return json.As<bool>();
66 } else if constexpr (std::is_same_v<Type, std::string>) {
67 if constexpr (!std::is_same_v<TParam, BytesValue>) {
68 return json.As<std::string>();
69 } else {
70 return crypto::base64::Base64Decode(json.As<std::string>());
71 }
72 } else {
73 static_assert(sizeof(TParam) && false, "unexpected type");
74 }
75}
76
77struct WrapperToJsonSuccessTestParam {
78 WrapperMessageData input = {};
79 std::string expected_json = {};
80 PrintOptions options = {};
81};
82
83class WrapperToJsonSuccessTest : public ::testing::TestWithParam<WrapperToJsonSuccessTestParam> {};
84
85INSTANTIATE_TEST_SUITE_P(
86 ,
87 WrapperToJsonSuccessTest,
88 ::testing::Values(
89 WrapperToJsonSuccessTestParam{WrapperMessageData{}, R"({})"},
90 WrapperToJsonSuccessTestParam{
91 WrapperMessageData{0, 0, 0, 0, 0, 0, false, "", ""},
92 R"({
93 "field1":0,
94 "field2":0,
95 "field3":"0",
96 "field4":"0",
97 "field5":0,
98 "field6":0,
99 "field7":false,
100 "field8":"",
101 "field9":""
102 })"
103 },
104 WrapperToJsonSuccessTestParam{
105 // using 1.5 for doubles because it is represented without precision loss in IEEE 754
106 WrapperMessageData{1.5, 1.5, -123, 123, -321, 321, true, "hello", "world"},
107 R"({
108 "field1":1.5,
109 "field2":1.5,
110 "field3":"-123",
111 "field4":"123",
112 "field5":-321,
113 "field6":321,
114 "field7":true,
115 "field8":"hello",
116 "field9":"d29ybGQ="
117 })"
118 },
119 WrapperToJsonSuccessTestParam{
120 WrapperMessageData{
121 std::nullopt,
122 std::nullopt,
123 -123,
124 std::nullopt,
125 -321,
126 std::nullopt,
127 true,
128 std::nullopt,
129 "world"
130 },
131 R"({
132 "field3":"-123",
133 "field5":-321,
134 "field7":true,
135 "field9":"d29ybGQ="
136 })"
137 }
138 )
139);
140
141TEST_P(WrapperToJsonSuccessTest, Test) {
142 const auto& param = GetParam();
143
144 auto input = PrepareTestData(param.input);
145 formats::json::Value json, expected_json, sample_json;
146
147 UASSERT_NO_THROW((json = MessageToJson(input, param.options)));
148 UASSERT_NO_THROW((expected_json = PrepareJsonTestData(param.expected_json)));
149 UASSERT_NO_THROW((sample_json = CreateSampleJson(input, param.options)));
150
151 EXPECT_EQ(json, expected_json);
152 EXPECT_EQ(expected_json, sample_json);
153}
154
155template <typename T>
156class WrapperToJsonAdditionalTest : public ::testing::Test {
157public:
158 using Param = T;
159};
160
161using WrapperTypes = ::testing::Types<
162 DoubleValue,
163 FloatValue,
164 Int64Value,
165 UInt64Value,
166 Int32Value,
167 UInt32Value,
168 BoolValue,
169 StringValue,
170 BytesValue>;
171
172TYPED_TEST_SUITE(WrapperToJsonAdditionalTest, WrapperTypes);
173
174TYPED_TEST(WrapperToJsonAdditionalTest, InlinedNonNull) {
175 using Param = typename TestFixture::Param;
176 using Message = typename Param::Message;
177
178 formats::json::Value json, sample;
179 Message message;
180 SetWrappedValue(message, Param::kValue);
181
182 UASSERT_NO_THROW((json = MessageToJson(message, {})));
183 UASSERT_NO_THROW((sample = CreateSampleJson(message)));
184 EXPECT_EQ(json, sample);
185 EXPECT_EQ(GetJsonValue<Param>(json), Param::kValue);
186}
187
188TYPED_TEST(WrapperToJsonAdditionalTest, InlinedNull) {
189 using Param = typename TestFixture::Param;
190 using Message = typename Param::Message;
191
192 formats::json::Value json, sample;
193 Message message;
194
195 UASSERT_NO_THROW((json = MessageToJson(message, {})));
196 UASSERT_NO_THROW((sample = CreateSampleJson(message)));
197 EXPECT_EQ(json, sample);
198}
199
200TYPED_TEST(WrapperToJsonAdditionalTest, DynamicMessage) {
201 using Param = typename TestFixture::Param;
202 using Message = typename Param::Message;
203
204 ::google::protobuf::DynamicMessageFactory factory;
205
206 {
207 std::unique_ptr<::google::protobuf::Message> message(factory.GetPrototype(Message::descriptor())->New());
208 SetWrappedValue(*message, Param::kValue);
209
210 formats::json::Value json;
211
212 UASSERT_NO_THROW((json = MessageToJson(*message, {})));
213 EXPECT_EQ(GetJsonValue<Param>(json), Param::kValue);
214 }
215}
216
217} // namespace protobuf::json::tests
218
219USERVER_NAMESPACE_END