• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2023 Google LLC.  All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7 
8 #include "upb/util/required_fields.h"
9 
10 #include <stdlib.h>
11 
12 #include <gtest/gtest.h>
13 #include "absl/strings/string_view.h"
14 #include "upb/base/status.hpp"
15 #include "upb/base/upcast.h"
16 #include "upb/json/decode.h"
17 #include "upb/mem/arena.h"
18 #include "upb/mem/arena.hpp"
19 #include "upb/reflection/common.h"
20 #include "upb/reflection/def.hpp"
21 #include "upb/util/required_fields_editions_test.upb.h"
22 #include "upb/util/required_fields_editions_test.upbdefs.h"
23 #include "upb/util/required_fields_test.upb.h"
24 #include "upb/util/required_fields_test.upbdefs.h"
25 
PathsToText(upb_FieldPathEntry * entry)26 std::vector<std::string> PathsToText(upb_FieldPathEntry* entry) {
27   std::vector<std::string> ret;
28   char buf[1024];  // Larger than anything we'll use in this test.
29   while (entry->field) {
30     upb_FieldPathEntry* before = entry;
31     size_t len = upb_FieldPath_ToText(&entry, buf, sizeof(buf));
32     EXPECT_LT(len, sizeof(buf));
33     assert(len <= sizeof(buf));
34     ret.push_back(buf);
35 
36     // Ensure that we can have a short buffer and that it will be
37     // NULL-terminated.
38     char shortbuf[4];
39     size_t len2 = upb_FieldPath_ToText(&before, shortbuf, sizeof(shortbuf));
40     EXPECT_EQ(len, len2);
41     EXPECT_EQ(ret.back().substr(0, sizeof(shortbuf) - 1),
42               std::string(shortbuf));
43   }
44   return ret;
45 }
46 
47 template <typename T>
48 class RequiredFieldsTest : public testing::Test {
49  public:
CheckRequired(absl::string_view json,const std::vector<std::string> & missing)50   void CheckRequired(absl::string_view json,
51                      const std::vector<std::string>& missing) {
52     upb::Arena arena;
53     upb::DefPool defpool;
54     auto* test_msg = T::NewMessage(arena.ptr());
55     upb::MessageDefPtr m = T::GetMessageDef(defpool.ptr());
56     upb::Status status;
57     EXPECT_TRUE(upb_JsonDecode(json.data(), json.size(), UPB_UPCAST(test_msg),
58                                m.ptr(), defpool.ptr(), 0, arena.ptr(),
59                                status.ptr()))
60         << status.error_message();
61     upb_FieldPathEntry* entries = nullptr;
62     EXPECT_EQ(!missing.empty(),
63               upb_util_HasUnsetRequired(UPB_UPCAST(test_msg), m.ptr(),
64                                         defpool.ptr(), &entries));
65     if (entries) {
66       EXPECT_EQ(missing, PathsToText(entries));
67       free(entries);
68     }
69 
70     // Verify that we can pass a NULL pointer to entries when we don't care
71     // about them.
72     EXPECT_EQ(!missing.empty(),
73               upb_util_HasUnsetRequired(UPB_UPCAST(test_msg), m.ptr(),
74                                         defpool.ptr(), nullptr));
75   }
76 };
77 
78 class Proto2Type {
79  public:
80   using MessageType = upb_util_test_TestRequiredFields;
NewMessage(upb_Arena * arena)81   static MessageType* NewMessage(upb_Arena* arena) {
82     return upb_util_test_TestRequiredFields_new(arena);
83   }
GetMessageDef(upb_DefPool * defpool)84   static upb::MessageDefPtr GetMessageDef(upb_DefPool* defpool) {
85     return upb::MessageDefPtr(
86         upb_util_test_TestRequiredFields_getmsgdef(defpool));
87   }
88 };
89 
90 class Edition2023Type {
91  public:
92   using MessageType = upb_util_2023_test_TestRequiredFields;
NewMessage(upb_Arena * arena)93   static MessageType* NewMessage(upb_Arena* arena) {
94     return upb_util_2023_test_TestRequiredFields_new(arena);
95   }
GetMessageDef(upb_DefPool * defpool)96   static upb::MessageDefPtr GetMessageDef(upb_DefPool* defpool) {
97     return upb::MessageDefPtr(
98         upb_util_2023_test_TestRequiredFields_getmsgdef(defpool));
99   }
100 };
101 
102 using MyTypes = ::testing::Types<Proto2Type, Edition2023Type>;
103 TYPED_TEST_SUITE(RequiredFieldsTest, MyTypes);
104 
105 // message HasRequiredField {
106 //   required int32 required_int32 = 1;
107 // }
108 //
109 // message TestRequiredFields {
110 //   required EmptyMessage required_message = 1;
111 //   optional TestRequiredFields optional_message = 2;
112 //   repeated HasRequiredField repeated_message = 3;
113 //   map<int32, HasRequiredField> map_int32_message = 4;
114 // }
TYPED_TEST(RequiredFieldsTest,TestRequired)115 TYPED_TEST(RequiredFieldsTest, TestRequired) {
116   TestFixture::CheckRequired(R"json({})json", {"required_message"});
117   TestFixture::CheckRequired(R"json({"required_message": {}})json", {});
118   TestFixture::CheckRequired(
119       R"json(
120       {
121         "optional_message": {}
122       }
123       )json",
124       {"required_message", "optional_message.required_message"});
125 
126   // Repeated field.
127   TestFixture::CheckRequired(
128       R"json(
129       {
130         "optional_message": {
131           "repeated_message": [
132             {"required_int32": 1},
133             {},
134             {"required_int32": 2}
135           ]
136         }
137       }
138       )json",
139       {"required_message", "optional_message.required_message",
140        "optional_message.repeated_message[1].required_int32"});
141 
142   // Int32 map key.
143   TestFixture::CheckRequired(
144       R"json(
145       {
146         "required_message": {},
147         "map_int32_message": {
148           "1": {"required_int32": 1},
149           "5": {},
150           "9": {"required_int32": 1}
151         }
152       }
153       )json",
154       {"map_int32_message[5].required_int32"});
155 
156   // Int64 map key.
157   TestFixture::CheckRequired(
158       R"json(
159       {
160         "required_message": {},
161         "map_int64_message": {
162           "1": {"required_int32": 1},
163           "5": {},
164           "9": {"required_int32": 1}
165         }
166       }
167       )json",
168       {"map_int64_message[5].required_int32"});
169 
170   // Uint32 map key.
171   TestFixture::CheckRequired(
172       R"json(
173       {
174         "required_message": {},
175         "map_uint32_message": {
176           "1": {"required_int32": 1},
177           "5": {},
178           "9": {"required_int32": 1}
179         }
180       }
181       )json",
182       {"map_uint32_message[5].required_int32"});
183 
184   // Uint64 map key.
185   TestFixture::CheckRequired(
186       R"json(
187       {
188         "required_message": {},
189         "map_uint64_message": {
190           "1": {"required_int32": 1},
191           "5": {},
192           "9": {"required_int32": 1}
193         }
194       }
195       )json",
196       {"map_uint64_message[5].required_int32"});
197 
198   // Bool map key.
199   TestFixture::CheckRequired(
200       R"json(
201       {
202         "required_message": {},
203         "map_bool_message": {
204           "false": {"required_int32": 1},
205           "true": {}
206         }
207       }
208       )json",
209       {"map_bool_message[true].required_int32"});
210 
211   // String map key.
212   TestFixture::CheckRequired(
213       R"json(
214       {
215         "required_message": {},
216         "map_string_message": {
217           "abc": {"required_int32": 1},
218           "d\"ef": {}
219         }
220       }
221       )json",
222       {R"(map_string_message["d\"ef"].required_int32)"});
223 }
224