1#include <gtest/gtest.h>
10#include <fmt/ranges.h>
11#include <google/protobuf/dynamic_message.h>
13#include <userver/protobuf/json/convert.hpp>
14#include <userver/utest/assert_macros.hpp>
18USERVER_NAMESPACE_BEGIN
20namespace protobuf::json::tests {
22struct FieldMaskToJsonSuccessTestParam {
24 std::string expected_json = {};
25 PrintOptions options = {};
28struct FieldMaskToJsonFailureTestParam {
30 PrintErrorCode expected_errc = {};
31 std::string expected_path = {};
32 PrintOptions options = {};
35std::vector<std::string> ParseFieldMaskStr(std::string_view paths) {
36 std::vector<std::string> result;
40 auto comma_pos = paths.find(
',', pos);
42 if (comma_pos == std::string_view::npos) {
43 result.emplace_back(paths.substr(pos));
47 result.emplace_back(paths.substr(pos, comma_pos - pos));
54void PrintTo(
const FieldMaskToJsonSuccessTestParam& param, std::ostream* os) {
55 if (param.input.field1) {
56 *os << fmt::format(
"{{ input = {{.field1='{}'}} }}", param.input.field1.value());
58 *os << fmt::format(
"{{ input = {{.field1=nullopt}} }}");
62void PrintTo(
const FieldMaskToJsonFailureTestParam& param, std::ostream* os) {
63 if (param.input.field1) {
64 *os << fmt::format(
"{{ input = {{.field1='{}'}} }}", param.input.field1.value());
66 *os << fmt::format(
"{{ input = {{.field1=nullopt}} }}");
70class FieldMaskToJsonSuccessTest :
public ::testing::TestWithParam<FieldMaskToJsonSuccessTestParam> {};
71class FieldMaskToJsonFailureTest :
public ::testing::TestWithParam<FieldMaskToJsonFailureTestParam> {};
73INSTANTIATE_TEST_SUITE_P(
75 FieldMaskToJsonSuccessTest,
77 FieldMaskToJsonSuccessTestParam{FieldMaskMessageData{}, R"({})"},
78 FieldMaskToJsonSuccessTestParam{FieldMaskMessageData{std::vector<std::string>{}}, R"({"field1":""})"},
79 FieldMaskToJsonSuccessTestParam{FieldMaskMessageData{std::vector<std::string>{
""}}, R"({"field1":""})"},
80 FieldMaskToJsonSuccessTestParam{
81 FieldMaskMessageData{std::vector<std::string>{
"",
"",
"",
"aaa",
""}},
82 R"({"field1":",,,aaa,"})"
84 FieldMaskToJsonSuccessTestParam{
85 FieldMaskMessageData{std::vector<std::string>{
"some_field"}},
86 R"({"field1":"someField"})",
87 {.preserve_proto_field_names =
true}
89 FieldMaskToJsonSuccessTestParam{
90 FieldMaskMessageData{std::vector<std::string>{
"some_field.another_field..one_more",
"_a_b0_c"}},
91 R"({"field1":"someField.anotherField..oneMore,AB0C"})"
100INSTANTIATE_TEST_SUITE_P(
102 FieldMaskToJsonFailureTest,
104 FieldMaskToJsonFailureTestParam{
105 FieldMaskMessageData{std::vector<std::string>{
"Some_field"}},
106 PrintErrorCode::kInvalidValue,
109 FieldMaskToJsonFailureTestParam{
110 FieldMaskMessageData{std::vector<std::string>{
"some_Field"}},
111 PrintErrorCode::kInvalidValue,
114 FieldMaskToJsonFailureTestParam{
115 FieldMaskMessageData{std::vector<std::string>{
"some_fielD"}},
116 PrintErrorCode::kInvalidValue,
119 FieldMaskToJsonFailureTestParam{
120 FieldMaskMessageData{std::vector<std::string>{
"some_f!ield"}},
121 PrintErrorCode::kInvalidValue,
124 FieldMaskToJsonFailureTestParam{
125 FieldMaskMessageData{std::vector<std::string>{
"__some_field"}},
126 PrintErrorCode::kInvalidValue,
129 FieldMaskToJsonFailureTestParam{
130 FieldMaskMessageData{std::vector<std::string>{
"some__field"}},
131 PrintErrorCode::kInvalidValue,
134 FieldMaskToJsonFailureTestParam{
135 FieldMaskMessageData{std::vector<std::string>{
"some_field_"}},
136 PrintErrorCode::kInvalidValue,
139 FieldMaskToJsonFailureTestParam{
140 FieldMaskMessageData{std::vector<std::string>{
"some_0field"}},
141 PrintErrorCode::kInvalidValue,
147TEST_P(FieldMaskToJsonSuccessTest, Test) {
148 const auto& param = GetParam();
150 auto input = PrepareTestData(param.input);
153 UASSERT_NO_THROW((json = MessageToJson(input, param.options)));
154 UASSERT_NO_THROW((expected_json = PrepareJsonTestData(param.expected_json)));
155 UASSERT_NO_THROW((sample_json = CreateSampleJson(input, param.options)));
167 auto json_paths = ParseFieldMaskStr(json[
"field1"].As<std::string>());
168 auto expected_json_paths = ParseFieldMaskStr(expected_json[
"field1"].As<std::string>());
169 auto sample_json_paths = ParseFieldMaskStr(sample_json[
"field1"].As<std::string>());
171 std::sort(json_paths.begin(), json_paths.end());
172 std::sort(expected_json_paths.begin(), expected_json_paths.end());
173 std::sort(sample_json_paths.begin(), sample_json_paths.end());
175 EXPECT_EQ(json_paths, expected_json_paths);
176 EXPECT_EQ(expected_json_paths, sample_json_paths);
179TEST_P(FieldMaskToJsonFailureTest, Test) {
180 const auto& param = GetParam();
181 auto input = PrepareTestData(param.input);
183 EXPECT_PRINT_ERROR((
void)MessageToJson(input, param.options), param.expected_errc, param.expected_path);
186TEST(FieldMaskToJsonAdditionalTest, InlinedNonNull) {
188 auto message = PrepareTestData(data);
191 UASSERT_NO_THROW((json = MessageToJson(message.field1(), {})));
192 UASSERT_NO_THROW((sample = CreateSampleJson(message.field1())));
196 auto paths = ParseFieldMaskStr(json.As<std::string>());
197 auto sample_paths = ParseFieldMaskStr(sample.As<std::string>());
199 std::sort(paths.begin(), paths.end());
200 std::sort(sample_paths.begin(), sample_paths.end());
202 EXPECT_EQ(paths, sample_paths);
203 EXPECT_EQ(paths, std::vector<std::string>{
"someField.nestedField"});
206TEST(FieldMaskToJsonAdditionalTest, InlinedNull) {
208 auto message = PrepareTestData(data);
211 UASSERT_NO_THROW((json = MessageToJson(message.field1(), {})));
212 UASSERT_NO_THROW((sample = CreateSampleJson(message.field1())));
215 EXPECT_TRUE(json.As<std::string>().empty());
216 EXPECT_TRUE(sample.As<std::string>().empty());
219TEST(FieldMaskToJsonAdditionalTest, DynamicMessage) {
220 using Message = ::google::protobuf::FieldMask;
221 ::google::protobuf::DynamicMessageFactory factory;
224 std::unique_ptr<::google::protobuf::Message> message(factory.GetPrototype(Message::descriptor())->New());
225 const auto reflection = message->GetReflection();
226 const auto paths_desc = message->GetDescriptor()->FindFieldByName(
"paths");
228 reflection->AddString(message.get(), paths_desc,
"some_field.another_field");
229 reflection->AddString(message.get(), paths_desc,
"one_more");
233 UASSERT_NO_THROW((json = MessageToJson(*message, {})));
236 auto paths = ParseFieldMaskStr(json.As<std::string>());
237 std::sort(paths.begin(), paths.end());
239 ASSERT_EQ(paths.size(), std::size_t{2});
240 EXPECT_EQ(paths[0],
"oneMore");
241 EXPECT_EQ(paths[1],
"someField.anotherField");