• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  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 <cstdint>
9 #include <memory>
10 
11 #include <gmock/gmock.h>
12 #include <gtest/gtest.h>
13 #include "absl/container/flat_hash_map.h"
14 #include "absl/log/absl_check.h"
15 #include "absl/strings/str_format.h"
16 #include "absl/synchronization/barrier.h"
17 #include "absl/synchronization/blocking_counter.h"
18 #include "absl/types/optional.h"
19 #include "google/protobuf/arena.h"
20 #include "google/protobuf/arena_test_util.h"
21 #include "google/protobuf/map.h"
22 #include "google/protobuf/map_field_inl.h"
23 #include "google/protobuf/map_test_util.h"
24 #include "google/protobuf/map_unittest.pb.h"
25 #include "google/protobuf/message.h"
26 #include "google/protobuf/repeated_field.h"
27 #include "google/protobuf/unittest.pb.h"
28 #include "google/protobuf/wire_format_lite.h"
29 
30 // Must be included last.
31 #include "google/protobuf/port_def.inc"
32 
33 namespace google {
34 namespace protobuf {
35 
36 namespace internal {
37 
38 using unittest::TestAllTypes;
39 
40 struct MapFieldTestPeer {
GetArenagoogle::protobuf::internal::MapFieldTestPeer41   static auto GetArena(const RepeatedPtrFieldBase& v) { return v.GetArena(); }
42   template <typename T>
GetMapgoogle::protobuf::internal::MapFieldTestPeer43   static auto& GetMap(T& t) {
44     return t.map_;
45   }
46 };
47 
48 using TestMapField = ::google::protobuf::internal::MapField<
49     unittest::TestMap_MapInt32Int32Entry_DoNotUse, ::int32_t, ::int32_t,
50     ::google::protobuf::internal::WireFormatLite::TYPE_INT32,
51     ::google::protobuf::internal::WireFormatLite::TYPE_INT32>;
52 
53 class MapFieldBasePrimitiveTest : public testing::TestWithParam<bool> {
54  protected:
55   typedef unittest::TestMap_MapInt32Int32Entry_DoNotUse EntryType;
56   typedef MapField<EntryType, int32_t, int32_t, WireFormatLite::TYPE_INT32,
57                    WireFormatLite::TYPE_INT32>
58       MapFieldType;
59 
MapFieldBasePrimitiveTest()60   MapFieldBasePrimitiveTest()
61       : arena_(GetParam() ? new Arena() : nullptr),
62         map_field_(arena_.get()),
63         map_field_base_(map_field_.get()) {
64     // Get descriptors
65     map_descriptor_ = unittest::TestMap::descriptor()
66                           ->FindFieldByName("map_int32_int32")
67                           ->message_type();
68     key_descriptor_ = map_descriptor_->map_key();
69     value_descriptor_ = map_descriptor_->map_value();
70 
71     // Build map field
72     map_field_base_ = map_field_.get();
73     map_ = map_field_->MutableMap();
74     initial_value_map_[0] = 100;
75     initial_value_map_[1] = 101;
76     map_->insert(initial_value_map_.begin(), initial_value_map_.end());
77     EXPECT_EQ(2, map_->size());
78   }
79 
80   std::unique_ptr<Arena> arena_;
81   ArenaHolder<MapFieldType> map_field_;
82   MapFieldBase* map_field_base_;
83   Map<int32_t, int32_t>* map_;
84   const Descriptor* map_descriptor_;
85   const FieldDescriptor* key_descriptor_;
86   const FieldDescriptor* value_descriptor_;
87   absl::flat_hash_map<int32_t, int32_t>
88       initial_value_map_;  // copy of initial values inserted
89 };
90 
91 INSTANTIATE_TEST_SUITE_P(MapFieldBasePrimitiveTestInstance,
92                          MapFieldBasePrimitiveTest,
93                          testing::Values(true, false));
94 
TEST_P(MapFieldBasePrimitiveTest,SpaceUsedExcludingSelf)95 TEST_P(MapFieldBasePrimitiveTest, SpaceUsedExcludingSelf) {
96   EXPECT_LT(0, map_field_base_->SpaceUsedExcludingSelf());
97 }
98 
TEST_P(MapFieldBasePrimitiveTest,GetRepeatedField)99 TEST_P(MapFieldBasePrimitiveTest, GetRepeatedField) {
100   const RepeatedPtrField<Message>& repeated =
101       reinterpret_cast<const RepeatedPtrField<Message>&>(
102           map_field_base_->GetRepeatedField());
103   EXPECT_EQ(2, repeated.size());
104   for (int i = 0; i < repeated.size(); i++) {
105     const Message& message = repeated.Get(i);
106     int key = message.GetReflection()->GetInt32(message, key_descriptor_);
107     int value = message.GetReflection()->GetInt32(message, value_descriptor_);
108     EXPECT_EQ(value, initial_value_map_[key]);
109   }
110 }
111 
TEST_P(MapFieldBasePrimitiveTest,MutableRepeatedField)112 TEST_P(MapFieldBasePrimitiveTest, MutableRepeatedField) {
113   RepeatedPtrField<Message>* repeated =
114       reinterpret_cast<RepeatedPtrField<Message>*>(
115           map_field_base_->MutableRepeatedField());
116   EXPECT_EQ(2, repeated->size());
117   for (int i = 0; i < repeated->size(); i++) {
118     const Message& message = repeated->Get(i);
119     int key = message.GetReflection()->GetInt32(message, key_descriptor_);
120     int value = message.GetReflection()->GetInt32(message, value_descriptor_);
121     EXPECT_EQ(value, initial_value_map_[key]);
122   }
123 }
124 
TEST_P(MapFieldBasePrimitiveTest,Arena)125 TEST_P(MapFieldBasePrimitiveTest, Arena) {
126   // Allocate a large initial block to avoid mallocs during hooked test.
127   std::vector<char> arena_block(128 * 1024);
128   ArenaOptions options;
129   options.initial_block = &arena_block[0];
130   options.initial_block_size = arena_block.size();
131   Arena arena(options);
132 
133   {
134     // TODO: Re-write the test to ensure the memory for the map and
135     // repeated fields are allocated from arenas.
136     // NoHeapChecker no_heap;
137 
138     MapFieldType* map_field = Arena::Create<MapFieldType>(&arena);
139 
140     // Set content in map
141     (*map_field->MutableMap())[100] = 101;
142 
143     // Trigger conversion to repeated field.
144     map_field->GetRepeatedField();
145   }
146 
147   {
148     // TODO: Re-write the test to ensure the memory for the map and
149     // repeated fields are allocated from arenas.
150     // NoHeapChecker no_heap;
151 
152     TestMapField* map_field = Arena::Create<TestMapField>(&arena);
153 
154     // Trigger conversion to repeated field.
155     EXPECT_TRUE(map_field->MutableRepeatedField() != nullptr);
156 
157     EXPECT_EQ(MapFieldTestPeer::GetArena(map_field->GetRepeatedField()),
158               &arena);
159   }
160 }
161 
TEST_P(MapFieldBasePrimitiveTest,EnforceNoArena)162 TEST_P(MapFieldBasePrimitiveTest, EnforceNoArena) {
163   std::unique_ptr<TestMapField> map_field(Arena::Create<TestMapField>(nullptr));
164   EXPECT_EQ(MapFieldTestPeer::GetArena(map_field->GetRepeatedField()), nullptr);
165 }
166 
167 namespace {
168 enum State { CLEAN, MAP_DIRTY, REPEATED_DIRTY };
169 }  // anonymous namespace
170 
171 class MapFieldStateTest
172     : public testing::TestWithParam<std::tuple<State, bool>> {
173  protected:
174   typedef unittest::TestMap_MapInt32Int32Entry_DoNotUse EntryType;
175   typedef MapField<EntryType, int32_t, int32_t, WireFormatLite::TYPE_INT32,
176                    WireFormatLite::TYPE_INT32>
177       MapFieldType;
MapFieldStateTest()178   MapFieldStateTest()
179       : arena_(std::get<1>(GetParam()) ? new Arena() : nullptr),
180         map_field_(arena_.get()),
181         map_field_base_(map_field_.get()),
182         state_(std::get<0>(GetParam())) {
183     // Build map field
184     Expect(map_field_.get(), MAP_DIRTY, 0, 0);
185     switch (state_) {
186       case CLEAN:
187         AddOneStillClean(map_field_.get());
188         break;
189       case MAP_DIRTY:
190         MakeMapDirty(map_field_.get());
191         break;
192       case REPEATED_DIRTY:
193         MakeRepeatedDirty(map_field_.get());
194         break;
195       default:
196         break;
197     }
198   }
199 
AddOneStillClean(MapFieldType * map_field)200   void AddOneStillClean(MapFieldType* map_field) {
201     MapFieldBase* map_field_base = map_field;
202     Map<int32_t, int32_t>* map = map_field->MutableMap();
203     (*map)[0] = 0;
204     map_field_base->GetRepeatedField();
205     Expect(map_field, CLEAN, 1, 1);
206   }
207 
MakeMapDirty(MapFieldType * map_field)208   void MakeMapDirty(MapFieldType* map_field) {
209     Map<int32_t, int32_t>* map = map_field->MutableMap();
210     (*map)[0] = 0;
211     Expect(map_field, MAP_DIRTY, 1, 0);
212   }
213 
MakeRepeatedDirty(MapFieldType * map_field)214   void MakeRepeatedDirty(MapFieldType* map_field) {
215     MakeMapDirty(map_field);
216     MapFieldBase* map_field_base = map_field;
217     map_field_base->MutableRepeatedField();
218     // We use map_ because we don't want to disturb the syncing
219     map_field->map_.clear();
220 
221     Expect(map_field, REPEATED_DIRTY, 0, 1);
222   }
223 
Expect(MapFieldType * map_field,State state,int map_size,int repeated_size)224   void Expect(MapFieldType* map_field, State state, int map_size,
225               int repeated_size) {
226     // We use map_ because we don't want to disturb the syncing
227     Map<int32_t, int32_t>* map = &map_field->map_;
228 
229     switch (state) {
230       case MAP_DIRTY:
231         EXPECT_FALSE(map_field->state() != MapFieldType::STATE_MODIFIED_MAP);
232         EXPECT_TRUE(map_field->state() !=
233                     MapFieldType::STATE_MODIFIED_REPEATED);
234         break;
235       case REPEATED_DIRTY:
236         EXPECT_TRUE(map_field->state() != MapFieldType::STATE_MODIFIED_MAP);
237         EXPECT_FALSE(map_field->state() !=
238                      MapFieldType::STATE_MODIFIED_REPEATED);
239         break;
240       case CLEAN:
241         EXPECT_TRUE(map_field->state() != MapFieldType::STATE_MODIFIED_MAP);
242         EXPECT_TRUE(map_field->state() !=
243                     MapFieldType::STATE_MODIFIED_REPEATED);
244         break;
245       default:
246         FAIL();
247     }
248 
249     EXPECT_EQ(map_size, map->size());
250     EXPECT_EQ(repeated_size,
251               map_field->maybe_payload() == nullptr
252                   ? 0
253                   : map_field->maybe_payload()->repeated_field.size());
254   }
255 
256   std::unique_ptr<Arena> arena_;
257   ArenaHolder<MapFieldType> map_field_;
258   MapFieldBase* map_field_base_;
259   State state_;
260 };
261 
262 INSTANTIATE_TEST_SUITE_P(MapFieldStateTestInstance, MapFieldStateTest,
263                          testing::Combine(testing::Values(CLEAN, MAP_DIRTY,
264                                                           REPEATED_DIRTY),
265                                           testing::Values(true, false)));
266 
TEST_P(MapFieldStateTest,GetMap)267 TEST_P(MapFieldStateTest, GetMap) {
268   map_field_->GetMap();
269   if (state_ != MAP_DIRTY) {
270     Expect(map_field_.get(), CLEAN, 1, 1);
271   } else {
272     Expect(map_field_.get(), MAP_DIRTY, 1, 0);
273   }
274 }
275 
TEST_P(MapFieldStateTest,MutableMap)276 TEST_P(MapFieldStateTest, MutableMap) {
277   map_field_->MutableMap();
278   if (state_ != MAP_DIRTY) {
279     Expect(map_field_.get(), MAP_DIRTY, 1, 1);
280   } else {
281     Expect(map_field_.get(), MAP_DIRTY, 1, 0);
282   }
283 }
284 
TEST_P(MapFieldStateTest,MergeFromClean)285 TEST_P(MapFieldStateTest, MergeFromClean) {
286   ArenaHolder<MapFieldType> other(arena_.get());
287   AddOneStillClean(other.get());
288 
289   map_field_->MergeFrom(*other);
290 
291   if (state_ != MAP_DIRTY) {
292     Expect(map_field_.get(), MAP_DIRTY, 1, 1);
293   } else {
294     Expect(map_field_.get(), MAP_DIRTY, 1, 0);
295   }
296 
297   Expect(other.get(), CLEAN, 1, 1);
298 }
299 
TEST_P(MapFieldStateTest,MergeFromMapDirty)300 TEST_P(MapFieldStateTest, MergeFromMapDirty) {
301   ArenaHolder<MapFieldType> other(arena_.get());
302   MakeMapDirty(other.get());
303 
304   map_field_->MergeFrom(*other);
305 
306   if (state_ != MAP_DIRTY) {
307     Expect(map_field_.get(), MAP_DIRTY, 1, 1);
308   } else {
309     Expect(map_field_.get(), MAP_DIRTY, 1, 0);
310   }
311 
312   Expect(other.get(), MAP_DIRTY, 1, 0);
313 }
314 
TEST_P(MapFieldStateTest,MergeFromRepeatedDirty)315 TEST_P(MapFieldStateTest, MergeFromRepeatedDirty) {
316   ArenaHolder<MapFieldType> other(arena_.get());
317   MakeRepeatedDirty(other.get());
318 
319   map_field_->MergeFrom(*other);
320 
321   if (state_ != MAP_DIRTY) {
322     Expect(map_field_.get(), MAP_DIRTY, 1, 1);
323   } else {
324     Expect(map_field_.get(), MAP_DIRTY, 1, 0);
325   }
326 
327   Expect(other.get(), CLEAN, 1, 1);
328 }
329 
TEST_P(MapFieldStateTest,SwapClean)330 TEST_P(MapFieldStateTest, SwapClean) {
331   ArenaHolder<MapFieldType> other(arena_.get());
332   AddOneStillClean(other.get());
333 
334   map_field_->Swap(other.get());
335 
336   Expect(map_field_.get(), CLEAN, 1, 1);
337 
338   switch (state_) {
339     case CLEAN:
340       Expect(other.get(), CLEAN, 1, 1);
341       break;
342     case MAP_DIRTY:
343       Expect(other.get(), MAP_DIRTY, 1, 0);
344       break;
345     case REPEATED_DIRTY:
346       Expect(other.get(), REPEATED_DIRTY, 0, 1);
347       break;
348     default:
349       break;
350   }
351 }
352 
TEST_P(MapFieldStateTest,SwapMapDirty)353 TEST_P(MapFieldStateTest, SwapMapDirty) {
354   ArenaHolder<MapFieldType> other(arena_.get());
355   MakeMapDirty(other.get());
356 
357   map_field_->Swap(other.get());
358 
359   Expect(map_field_.get(), MAP_DIRTY, 1, 0);
360 
361   switch (state_) {
362     case CLEAN:
363       Expect(other.get(), CLEAN, 1, 1);
364       break;
365     case MAP_DIRTY:
366       Expect(other.get(), MAP_DIRTY, 1, 0);
367       break;
368     case REPEATED_DIRTY:
369       Expect(other.get(), REPEATED_DIRTY, 0, 1);
370       break;
371     default:
372       break;
373   }
374 }
375 
TEST_P(MapFieldStateTest,SwapRepeatedDirty)376 TEST_P(MapFieldStateTest, SwapRepeatedDirty) {
377   ArenaHolder<MapFieldType> other(arena_.get());
378   MakeRepeatedDirty(other.get());
379 
380   map_field_->Swap(other.get());
381 
382   Expect(map_field_.get(), REPEATED_DIRTY, 0, 1);
383 
384   switch (state_) {
385     case CLEAN:
386       Expect(other.get(), CLEAN, 1, 1);
387       break;
388     case MAP_DIRTY:
389       Expect(other.get(), MAP_DIRTY, 1, 0);
390       break;
391     case REPEATED_DIRTY:
392       Expect(other.get(), REPEATED_DIRTY, 0, 1);
393       break;
394     default:
395       break;
396   }
397 }
398 
TEST_P(MapFieldStateTest,Clear)399 TEST_P(MapFieldStateTest, Clear) {
400   map_field_->Clear();
401 
402   Expect(map_field_.get(), MAP_DIRTY, 0, 0);
403 }
404 
TEST_P(MapFieldStateTest,SpaceUsedExcludingSelf)405 TEST_P(MapFieldStateTest, SpaceUsedExcludingSelf) {
406   map_field_base_->SpaceUsedExcludingSelf();
407 
408   switch (state_) {
409     case CLEAN:
410       Expect(map_field_.get(), CLEAN, 1, 1);
411       break;
412     case MAP_DIRTY:
413       Expect(map_field_.get(), MAP_DIRTY, 1, 0);
414       break;
415     case REPEATED_DIRTY:
416       Expect(map_field_.get(), REPEATED_DIRTY, 0, 1);
417       break;
418     default:
419       break;
420   }
421 }
422 
TEST_P(MapFieldStateTest,GetMapField)423 TEST_P(MapFieldStateTest, GetMapField) {
424   map_field_base_->GetRepeatedField();
425 
426   if (state_ != REPEATED_DIRTY) {
427     Expect(map_field_.get(), CLEAN, 1, 1);
428   } else {
429     Expect(map_field_.get(), REPEATED_DIRTY, 0, 1);
430   }
431 }
432 
TEST_P(MapFieldStateTest,MutableMapField)433 TEST_P(MapFieldStateTest, MutableMapField) {
434   map_field_base_->MutableRepeatedField();
435 
436   if (state_ != REPEATED_DIRTY) {
437     Expect(map_field_.get(), REPEATED_DIRTY, 1, 1);
438   } else {
439     Expect(map_field_.get(), REPEATED_DIRTY, 0, 1);
440   }
441 }
442 
443 using MyMapField =
444     MapField<unittest::TestMap_MapInt32Int32Entry_DoNotUse, int32_t, int32_t,
445              internal::WireFormatLite::TYPE_INT32,
446              internal::WireFormatLite::TYPE_INT32>;
447 
TEST(MapFieldTest,ConstInit)448 TEST(MapFieldTest, ConstInit) {
449   // This tests that `MapField` and all its base classes can be constant
450   // initialized.
451   PROTOBUF_CONSTINIT static MyMapField field;  // NOLINT
452   EXPECT_EQ(field.size(), 0);
453 }
454 
455 
456 }  // namespace internal
457 }  // namespace protobuf
458 }  // namespace google
459 
460 #include "google/protobuf/port_undef.inc"
461