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