• 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/mini_descriptor/internal/encode.hpp"
9 
10 #include <stddef.h>
11 #include <stdint.h>
12 
13 #include <string_view>
14 #include <vector>
15 
16 #include <gtest/gtest.h>
17 #include "absl/container/flat_hash_set.h"
18 #include "google/protobuf/descriptor.h"
19 #include "upb/base/descriptor_constants.h"
20 #include "upb/base/status.hpp"
21 #include "upb/mem/arena.hpp"
22 #include "upb/message/internal/accessors.h"
23 #include "upb/mini_descriptor/decode.h"
24 #include "upb/mini_descriptor/internal/base92.h"
25 #include "upb/mini_descriptor/internal/modifiers.h"
26 #include "upb/mini_table/enum.h"
27 #include "upb/mini_table/field.h"
28 #include "upb/mini_table/message.h"
29 #include "upb/mini_table/sub.h"
30 
31 // Must be last.
32 #include "upb/port/def.inc"
33 
34 namespace protobuf = ::google::protobuf;
35 
36 class MiniTableTest : public testing::TestWithParam<upb_MiniTablePlatform> {};
37 
TEST_P(MiniTableTest,Empty)38 TEST_P(MiniTableTest, Empty) {
39   upb::Arena arena;
40   upb::Status status;
41   upb_MiniTable* table =
42       _upb_MiniTable_Build(nullptr, 0, GetParam(), arena.ptr(), status.ptr());
43   ASSERT_NE(nullptr, table);
44   EXPECT_EQ(0, upb_MiniTable_FieldCount(table));
45   EXPECT_EQ(0, table->UPB_PRIVATE(required_count));
46 }
47 
TEST_P(MiniTableTest,AllScalarTypes)48 TEST_P(MiniTableTest, AllScalarTypes) {
49   upb::Arena arena;
50   upb::MtDataEncoder e;
51   ASSERT_TRUE(e.StartMessage(0));
52   int count = 0;
53   for (int i = kUpb_FieldType_Double; i < kUpb_FieldType_SInt64; i++) {
54     ASSERT_TRUE(e.PutField(static_cast<upb_FieldType>(i), i, 0));
55     count++;
56   }
57   upb::Status status;
58   upb_MiniTable* table = _upb_MiniTable_Build(
59       e.data().data(), e.data().size(), GetParam(), arena.ptr(), status.ptr());
60   ASSERT_NE(nullptr, table);
61   EXPECT_EQ(count, table->UPB_PRIVATE(field_count));
62   absl::flat_hash_set<size_t> offsets;
63   for (int i = 0; i < 16; i++) {
64     const upb_MiniTableField* f = &table->UPB_PRIVATE(fields)[i];
65     EXPECT_EQ(i + 1, upb_MiniTableField_Number(f));
66     EXPECT_TRUE(upb_MiniTableField_IsScalar(f));
67     EXPECT_TRUE(offsets.insert(f->UPB_PRIVATE(offset)).second);
68     EXPECT_TRUE(f->UPB_PRIVATE(offset) < table->UPB_PRIVATE(size));
69   }
70   EXPECT_EQ(0, table->UPB_PRIVATE(required_count));
71 }
72 
TEST_P(MiniTableTest,AllRepeatedTypes)73 TEST_P(MiniTableTest, AllRepeatedTypes) {
74   upb::Arena arena;
75   upb::MtDataEncoder e;
76   ASSERT_TRUE(e.StartMessage(0));
77   int count = 0;
78   for (int i = kUpb_FieldType_Double; i < kUpb_FieldType_SInt64; i++) {
79     ASSERT_TRUE(e.PutField(static_cast<upb_FieldType>(i), i,
80                            kUpb_FieldModifier_IsRepeated));
81     count++;
82   }
83   upb::Status status;
84   upb_MiniTable* table = _upb_MiniTable_Build(
85       e.data().data(), e.data().size(), GetParam(), arena.ptr(), status.ptr());
86   ASSERT_NE(nullptr, table);
87   EXPECT_EQ(count, table->UPB_PRIVATE(field_count));
88   absl::flat_hash_set<size_t> offsets;
89   for (int i = 0; i < 16; i++) {
90     const upb_MiniTableField* f = &table->UPB_PRIVATE(fields)[i];
91     EXPECT_EQ(i + 1, upb_MiniTableField_Number(f));
92     EXPECT_TRUE(upb_MiniTableField_IsArray(f));
93     EXPECT_TRUE(offsets.insert(f->UPB_PRIVATE(offset)).second);
94     EXPECT_TRUE(f->UPB_PRIVATE(offset) < table->UPB_PRIVATE(size));
95   }
96   EXPECT_EQ(0, table->UPB_PRIVATE(required_count));
97 }
98 
TEST_P(MiniTableTest,Skips)99 TEST_P(MiniTableTest, Skips) {
100   upb::Arena arena;
101   upb::MtDataEncoder e;
102   ASSERT_TRUE(e.StartMessage(0));
103   int count = 0;
104   std::vector<int> field_numbers;
105   for (int i = 0; i < 25; i++) {
106     int field_number = 1 << i;
107     field_numbers.push_back(field_number);
108     ASSERT_TRUE(e.PutField(kUpb_FieldType_Float, field_number, 0));
109     count++;
110   }
111   upb::Status status;
112   upb_MiniTable* table = _upb_MiniTable_Build(
113       e.data().data(), e.data().size(), GetParam(), arena.ptr(), status.ptr());
114   ASSERT_NE(nullptr, table);
115   EXPECT_EQ(count, table->UPB_PRIVATE(field_count));
116   absl::flat_hash_set<size_t> offsets;
117   for (size_t i = 0; i < field_numbers.size(); i++) {
118     const upb_MiniTableField* f = &table->UPB_PRIVATE(fields)[i];
119     EXPECT_EQ(field_numbers[i], upb_MiniTableField_Number(f));
120     EXPECT_EQ(kUpb_FieldType_Float, upb_MiniTableField_Type(f));
121     EXPECT_TRUE(upb_MiniTableField_IsScalar(f));
122     EXPECT_TRUE(offsets.insert(f->UPB_PRIVATE(offset)).second);
123     EXPECT_TRUE(f->UPB_PRIVATE(offset) < table->UPB_PRIVATE(size));
124   }
125   EXPECT_EQ(0, table->UPB_PRIVATE(required_count));
126 }
127 
TEST_P(MiniTableTest,AllScalarTypesOneof)128 TEST_P(MiniTableTest, AllScalarTypesOneof) {
129   upb::Arena arena;
130   upb::MtDataEncoder e;
131   ASSERT_TRUE(e.StartMessage(0));
132   int count = 0;
133   for (int i = kUpb_FieldType_Double; i < kUpb_FieldType_SInt64; i++) {
134     ASSERT_TRUE(e.PutField(static_cast<upb_FieldType>(i), i, 0));
135     count++;
136   }
137   ASSERT_TRUE(e.StartOneof());
138   for (int i = kUpb_FieldType_Double; i < kUpb_FieldType_SInt64; i++) {
139     ASSERT_TRUE(e.PutOneofField(i));
140   }
141   upb::Status status;
142   upb_MiniTable* table = _upb_MiniTable_Build(
143       e.data().data(), e.data().size(), GetParam(), arena.ptr(), status.ptr());
144   ASSERT_NE(nullptr, table) << status.error_message();
145   EXPECT_EQ(count, table->UPB_PRIVATE(field_count));
146   absl::flat_hash_set<size_t> offsets;
147   for (int i = 0; i < 16; i++) {
148     const upb_MiniTableField* f = &table->UPB_PRIVATE(fields)[i];
149     EXPECT_EQ(i + 1, upb_MiniTableField_Number(f));
150     EXPECT_TRUE(upb_MiniTableField_IsScalar(f));
151     // For a oneof all fields have the same offset.
152     EXPECT_EQ(table->UPB_PRIVATE(fields)[0].UPB_PRIVATE(offset),
153               f->UPB_PRIVATE(offset));
154     // All presence fields should point to the same oneof case offset.
155     size_t case_ofs = UPB_PRIVATE(_upb_MiniTableField_OneofOffset)(f);
156     EXPECT_EQ(table->UPB_PRIVATE(fields)[0].presence, f->presence);
157     EXPECT_TRUE(f->UPB_PRIVATE(offset) < table->UPB_PRIVATE(size));
158     EXPECT_TRUE(case_ofs < table->UPB_PRIVATE(size));
159     EXPECT_TRUE(case_ofs != f->UPB_PRIVATE(offset));
160   }
161   EXPECT_EQ(0, table->UPB_PRIVATE(required_count));
162 }
163 
TEST_P(MiniTableTest,SizeOverflow)164 TEST_P(MiniTableTest, SizeOverflow) {
165   upb::Arena arena;
166   upb::MtDataEncoder e;
167   // upb can only handle messages up to UINT16_MAX.
168   size_t max_double_fields = UINT16_MAX / (sizeof(double) + 1);
169 
170   // A bit under max_double_fields is ok.
171   ASSERT_TRUE(e.StartMessage(0));
172   for (size_t i = 1; i < max_double_fields; i++) {
173     ASSERT_TRUE(e.PutField(kUpb_FieldType_Double, i, 0));
174   }
175   upb::Status status;
176   upb_MiniTable* table = _upb_MiniTable_Build(
177       e.data().data(), e.data().size(), GetParam(), arena.ptr(), status.ptr());
178   ASSERT_NE(nullptr, table) << status.error_message();
179 
180   // A bit over max_double_fields fails.
181   ASSERT_TRUE(e.StartMessage(0));
182   for (size_t i = 1; i < max_double_fields + 2; i++) {
183     ASSERT_TRUE(e.PutField(kUpb_FieldType_Double, i, 0));
184   }
185   upb_MiniTable* table2 = _upb_MiniTable_Build(
186       e.data().data(), e.data().size(), GetParam(), arena.ptr(), status.ptr());
187   ASSERT_EQ(nullptr, table2) << status.error_message();
188 }
189 
190 INSTANTIATE_TEST_SUITE_P(Platforms, MiniTableTest,
191                          testing::Values(kUpb_MiniTablePlatform_32Bit,
192                                          kUpb_MiniTablePlatform_64Bit));
193 
TEST(MiniTablePlatformIndependentTest,Base92Roundtrip)194 TEST(MiniTablePlatformIndependentTest, Base92Roundtrip) {
195   for (char i = 0; i < 92; i++) {
196     EXPECT_EQ(i, _upb_FromBase92(_upb_ToBase92(i)));
197   }
198 }
199 
TEST(MiniTablePlatformIndependentTest,IsTypePackable)200 TEST(MiniTablePlatformIndependentTest, IsTypePackable) {
201   for (int i = 1; i <= protobuf::FieldDescriptor::MAX_TYPE; i++) {
202     EXPECT_EQ(upb_FieldType_IsPackable(static_cast<upb_FieldType>(i)),
203               protobuf::FieldDescriptor::IsTypePackable(
204                   static_cast<protobuf::FieldDescriptor::Type>(i)));
205   }
206 }
207 
TEST(MiniTableEnumTest,Enum)208 TEST(MiniTableEnumTest, Enum) {
209   upb::Arena arena;
210   upb::MtDataEncoder e;
211 
212   ASSERT_TRUE(e.StartEnum());
213   absl::flat_hash_set<int32_t> values;
214   for (int i = 0; i < 256; i++) {
215     values.insert(i * 2);
216     e.PutEnumValue(i * 2);
217   }
218   e.EndEnum();
219 
220   upb::Status status;
221   upb_MiniTableEnum* table = upb_MiniTableEnum_Build(
222       e.data().data(), e.data().size(), arena.ptr(), status.ptr());
223   ASSERT_NE(nullptr, table) << status.error_message();
224 
225   for (int i = 0; i < UINT16_MAX; i++) {
226     EXPECT_EQ(values.contains(i), upb_MiniTableEnum_CheckValue(table, i)) << i;
227   }
228 }
229 
TEST_P(MiniTableTest,SubsInitializedToEmpty)230 TEST_P(MiniTableTest, SubsInitializedToEmpty) {
231   upb::Arena arena;
232   upb::MtDataEncoder e;
233   // Create mini table with 2 message fields.
234   ASSERT_TRUE(e.StartMessage(0));
235   ASSERT_TRUE(e.PutField(kUpb_FieldType_Message, 15, 0));
236   ASSERT_TRUE(e.PutField(kUpb_FieldType_Message, 16, 0));
237   upb::Status status;
238   upb_MiniTable* table = _upb_MiniTable_Build(
239       e.data().data(), e.data().size(), GetParam(), arena.ptr(), status.ptr());
240   ASSERT_NE(nullptr, table);
241   EXPECT_EQ(upb_MiniTable_FieldCount(table), 2);
242   EXPECT_FALSE(upb_MiniTable_FieldIsLinked(
243       table, upb_MiniTable_GetFieldByIndex(table, 0)));
244   EXPECT_FALSE(upb_MiniTable_FieldIsLinked(
245       table, upb_MiniTable_GetFieldByIndex(table, 1)));
246 }
247 
TEST(MiniTableEnumTest,PositiveAndNegative)248 TEST(MiniTableEnumTest, PositiveAndNegative) {
249   upb::Arena arena;
250   upb::MtDataEncoder e;
251 
252   ASSERT_TRUE(e.StartEnum());
253   absl::flat_hash_set<int32_t> values;
254   for (int i = 0; i < 100; i++) {
255     values.insert(i);
256     e.PutEnumValue(i);
257   }
258   for (int i = 100; i > 0; i--) {
259     values.insert(-i);
260     e.PutEnumValue(-i);
261   }
262   e.EndEnum();
263 
264   upb::Status status;
265   upb_MiniTableEnum* table = upb_MiniTableEnum_Build(
266       e.data().data(), e.data().size(), arena.ptr(), status.ptr());
267   ASSERT_NE(nullptr, table) << status.error_message();
268 
269   for (int i = -UINT16_MAX; i < UINT16_MAX; i++) {
270     EXPECT_EQ(values.contains(i), upb_MiniTableEnum_CheckValue(table, i)) << i;
271   }
272 }
273 
TEST_P(MiniTableTest,Extendible)274 TEST_P(MiniTableTest, Extendible) {
275   upb::Arena arena;
276   upb::MtDataEncoder e;
277   ASSERT_TRUE(e.StartMessage(kUpb_MessageModifier_IsExtendable));
278   for (int i = kUpb_FieldType_Double; i < kUpb_FieldType_SInt64; i++) {
279     ASSERT_TRUE(e.PutField(static_cast<upb_FieldType>(i), i, 0));
280   }
281   upb::Status status;
282   upb_MiniTable* table = _upb_MiniTable_Build(
283       e.data().data(), e.data().size(), GetParam(), arena.ptr(), status.ptr());
284   ASSERT_NE(nullptr, table);
285   EXPECT_EQ(kUpb_ExtMode_Extendable,
286             table->UPB_PRIVATE(ext) & kUpb_ExtMode_Extendable);
287 }
288