1#include <gtest/gtest.h>
10#include <google/protobuf/dynamic_message.h>
12#include <userver/protobuf/json/convert.hpp>
13#include <userver/utest/assert_macros.hpp>
17USERVER_NAMESPACE_BEGIN
19namespace protobuf::json::tests {
21struct FieldMaskToJsonSuccessTestParam {
23 std::string expected_json = {};
27 bool skip_native_check =
false;
30struct FieldMaskToJsonFailureTestParam {
33 std::string expected_path = {};
37std::vector<std::string> ParseFieldMaskStr(std::string_view paths) {
38 std::vector<std::string> result;
42 auto comma_pos = paths.find(
',', pos);
44 if (comma_pos == std::string_view::npos) {
45 result.emplace_back(paths.substr(pos));
49 result.emplace_back(paths.substr(pos, comma_pos - pos));
62std::string FmtFormatCrutch(
const std::optional<std::vector<std::string>>& items) {
66 constexpr std::string_view sep =
", ";
67 std::string result =
"[";
68 for (
const auto& s : *items) {
74 if (!items->empty()) {
75 result.resize(result.size() - sep.size());
82void PrintTo(
const FieldMaskToJsonSuccessTestParam& param, std::ostream* os) {
83 *os <<
"{ input = {.field1=" << FmtFormatCrutch(param.input.field1) <<
"} }";
86void PrintTo(
const FieldMaskToJsonFailureTestParam& param, std::ostream* os) {
87 *os <<
"{ input = {.field1=" << FmtFormatCrutch(param.input.field1) <<
"} }";
90class FieldMaskToJsonSuccessTest :
public ::testing::TestWithParam<FieldMaskToJsonSuccessTestParam> {};
91class FieldMaskToJsonFailureTest :
public ::testing::TestWithParam<FieldMaskToJsonFailureTestParam> {};
93INSTANTIATE_TEST_SUITE_P(
95 FieldMaskToJsonSuccessTest,
97 FieldMaskToJsonSuccessTestParam{FieldMaskMessageData{}, R"({})"},
98 FieldMaskToJsonSuccessTestParam{FieldMaskMessageData{std::vector<std::string>{}}, R"({"field1":""})"},
99 FieldMaskToJsonSuccessTestParam{FieldMaskMessageData{std::vector<std::string>{
""}}, R"({"field1":""})"},
100 FieldMaskToJsonSuccessTestParam{
101 FieldMaskMessageData{std::vector<std::string>{
"",
"",
"",
"aaa",
""}},
102 R"({"field1":",,,aaa,"})",
106 FieldMaskToJsonSuccessTestParam{
107 FieldMaskMessageData{std::vector<std::string>{
"some_field"}},
108 R"({"field1":"someField"})",
110 {.preserve_proto_field_names =
true}
112 FieldMaskToJsonSuccessTestParam{
113 FieldMaskMessageData{std::vector<std::string>{
"some_field.another_field..one_more",
"_a_b0_c"}},
114 R"({"field1":"someField.anotherField..oneMore,AB0C"})",
125INSTANTIATE_TEST_SUITE_P(
127 FieldMaskToJsonFailureTest,
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_fielD"}},
141 PrintErrorCode::kInvalidValue,
144 FieldMaskToJsonFailureTestParam{
145 FieldMaskMessageData{std::vector<std::string>{
"some_f!ield"}},
146 PrintErrorCode::kInvalidValue,
149 FieldMaskToJsonFailureTestParam{
150 FieldMaskMessageData{std::vector<std::string>{
"__some_field"}},
151 PrintErrorCode::kInvalidValue,
154 FieldMaskToJsonFailureTestParam{
155 FieldMaskMessageData{std::vector<std::string>{
"some__field"}},
156 PrintErrorCode::kInvalidValue,
159 FieldMaskToJsonFailureTestParam{
160 FieldMaskMessageData{std::vector<std::string>{
"some_field_"}},
161 PrintErrorCode::kInvalidValue,
164 FieldMaskToJsonFailureTestParam{
165 FieldMaskMessageData{std::vector<std::string>{
"some_0field"}},
166 PrintErrorCode::kInvalidValue,
172TEST_P(FieldMaskToJsonSuccessTest, Test) {
173 const auto& param = GetParam();
175 auto input = PrepareTestData(param.input);
180 UASSERT_NO_THROW((expected_json = PrepareJsonTestData(param.expected_json)));
190 auto json_paths = ParseFieldMaskStr(json[
"field1"].As<std::string>());
191 auto expected_json_paths = ParseFieldMaskStr(expected_json[
"field1"].As<std::string>());
193 std::ranges::sort(json_paths);
194 std::ranges::sort(expected_json_paths);
196 EXPECT_EQ(json_paths, expected_json_paths);
198 if (!param.skip_native_check) {
210 auto sample_json_paths = ParseFieldMaskStr(sample_json[
"field1"].As<std::string>());
211 std::ranges::sort(sample_json_paths);
213 EXPECT_EQ(expected_json_paths, sample_json_paths);
217TEST_P(FieldMaskToJsonFailureTest, Test) {
218 const auto& param = GetParam();
219 auto input = PrepareTestData(param.input);
221 EXPECT_PRINT_ERROR((
void)MessageToJson(input, param.options), param.expected_errc, param.expected_path);
224TEST(FieldMaskToJsonAdditionalTest, InlinedNonNull) {
226 auto message = PrepareTestData(data);
235 auto paths = ParseFieldMaskStr(json.As<std::string>());
236 auto sample_paths = ParseFieldMaskStr(sample.As<std::string>());
238 std::ranges::sort(paths);
239 std::ranges::sort(sample_paths);
241 EXPECT_EQ(paths, sample_paths);
242 EXPECT_EQ(paths, std::vector<std::string>{
"someField.nestedField"});
245TEST(FieldMaskToJsonAdditionalTest, InlinedNull) {
247 auto message = PrepareTestData(data);
255 EXPECT_TRUE(json.As<std::string>().empty());
256 EXPECT_TRUE(sample.As<std::string>().empty());
259TEST(FieldMaskToJsonAdditionalTest, DynamicMessage) {
260 using Message = ::google::protobuf::FieldMask;
261 ::google::protobuf::DynamicMessageFactory factory;
264 std::unique_ptr<::google::protobuf::Message> message(factory.GetPrototype(Message::descriptor())->New());
265 const auto reflection = message->GetReflection();
266 const auto paths_desc = message->GetDescriptor()->FindFieldByName(
"paths");
268 reflection->AddString(message.get(), paths_desc,
"some_field.another_field");
269 reflection->AddString(message.get(), paths_desc,
"one_more");
276 auto paths = ParseFieldMaskStr(json.As<std::string>());
277 std::ranges::sort(paths);
279 ASSERT_EQ(paths.size(), std::size_t{2});
280 EXPECT_EQ(paths[0],
"oneMore");
281 EXPECT_EQ(paths[1],
"someField.anotherField");