• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 #include <map>
32 #include <memory>
33 #include <unordered_map>
34 
35 #include <google/protobuf/stubs/logging.h>
36 #include <google/protobuf/stubs/common.h>
37 #include <google/protobuf/arena_test_util.h>
38 #include <google/protobuf/map_test_util.h>
39 #include <google/protobuf/map_unittest.pb.h>
40 #include <google/protobuf/unittest.pb.h>
41 #include <google/protobuf/arena.h>
42 #include <google/protobuf/map.h>
43 #include <google/protobuf/map_field_inl.h>
44 #include <google/protobuf/message.h>
45 #include <google/protobuf/repeated_field.h>
46 #include <gtest/gtest.h>
47 
48 // Must be included last.
49 #include <google/protobuf/port_def.inc>
50 
51 namespace google {
52 namespace protobuf {
53 
54 namespace internal {
55 
56 using unittest::TestAllTypes;
57 
58 class MapFieldBaseStub : public MapFieldBase {
59  public:
60   typedef void InternalArenaConstructable_;
61   typedef void DestructorSkippable_;
MapFieldBaseStub()62   MapFieldBaseStub() {}
MapFieldBaseStub(Arena * arena)63   explicit MapFieldBaseStub(Arena* arena) : MapFieldBase(arena) {}
64   // Get underlined repeated field without synchronizing map.
InternalRepeatedField()65   RepeatedPtrField<Message>* InternalRepeatedField() { return repeated_field_; }
IsMapClean()66   bool IsMapClean() {
67     return state_.load(std::memory_order_relaxed) != STATE_MODIFIED_MAP;
68   }
IsRepeatedClean()69   bool IsRepeatedClean() {
70     return state_.load(std::memory_order_relaxed) != STATE_MODIFIED_REPEATED;
71   }
SetMapDirty()72   void SetMapDirty() {
73     state_.store(STATE_MODIFIED_MAP, std::memory_order_relaxed);
74   }
SetRepeatedDirty()75   void SetRepeatedDirty() {
76     state_.store(STATE_MODIFIED_REPEATED, std::memory_order_relaxed);
77   }
ContainsMapKey(const MapKey & map_key) const78   bool ContainsMapKey(const MapKey& map_key) const override { return false; }
InsertOrLookupMapValue(const MapKey & map_key,MapValueRef * val)79   bool InsertOrLookupMapValue(const MapKey& map_key,
80                               MapValueRef* val) override {
81     return false;
82   }
LookupMapValue(const MapKey & map_key,MapValueConstRef * val) const83   bool LookupMapValue(const MapKey& map_key,
84                       MapValueConstRef* val) const override {
85     return false;
86   }
DeleteMapValue(const MapKey & map_key)87   bool DeleteMapValue(const MapKey& map_key) override { return false; }
EqualIterator(const MapIterator & a,const MapIterator & b) const88   bool EqualIterator(const MapIterator& a,
89                      const MapIterator& b) const override {
90     return false;
91   }
size() const92   int size() const override { return 0; }
Clear()93   void Clear() override {}
MapBegin(MapIterator * map_iter) const94   void MapBegin(MapIterator* map_iter) const override {}
MapEnd(MapIterator * map_iter) const95   void MapEnd(MapIterator* map_iter) const override {}
MergeFrom(const MapFieldBase & other)96   void MergeFrom(const MapFieldBase& other) override {}
Swap(MapFieldBase * other)97   void Swap(MapFieldBase* other) override {}
InitializeIterator(MapIterator * map_iter) const98   void InitializeIterator(MapIterator* map_iter) const override {}
DeleteIterator(MapIterator * map_iter) const99   void DeleteIterator(MapIterator* map_iter) const override {}
CopyIterator(MapIterator * this_iterator,const MapIterator & other_iterator) const100   void CopyIterator(MapIterator* this_iterator,
101                     const MapIterator& other_iterator) const override {}
IncreaseIterator(MapIterator * map_iter) const102   void IncreaseIterator(MapIterator* map_iter) const override {}
103 };
104 
105 class MapFieldBasePrimitiveTest : public ::testing::Test {
106  protected:
107   typedef unittest::TestMap_MapInt32Int32Entry_DoNotUse EntryType;
108   typedef MapField<EntryType, int32, int32, WireFormatLite::TYPE_INT32,
109                    WireFormatLite::TYPE_INT32>
110       MapFieldType;
111 
MapFieldBasePrimitiveTest()112   MapFieldBasePrimitiveTest() {
113     // Get descriptors
114     map_descriptor_ = unittest::TestMap::descriptor()
115                           ->FindFieldByName("map_int32_int32")
116                           ->message_type();
117     key_descriptor_ = map_descriptor_->map_key();
118     value_descriptor_ = map_descriptor_->map_value();
119 
120     // Build map field
121     map_field_.reset(new MapFieldType);
122     map_field_base_ = map_field_.get();
123     map_ = map_field_->MutableMap();
124     initial_value_map_[0] = 100;
125     initial_value_map_[1] = 101;
126     map_->insert(initial_value_map_.begin(), initial_value_map_.end());
127     EXPECT_EQ(2, map_->size());
128   }
129 
130   std::unique_ptr<MapFieldType> map_field_;
131   MapFieldBase* map_field_base_;
132   Map<int32, int32>* map_;
133   const Descriptor* map_descriptor_;
134   const FieldDescriptor* key_descriptor_;
135   const FieldDescriptor* value_descriptor_;
136   std::map<int32, int32> initial_value_map_;  // copy of initial values inserted
137 };
138 
TEST_F(MapFieldBasePrimitiveTest,SpaceUsedExcludingSelf)139 TEST_F(MapFieldBasePrimitiveTest, SpaceUsedExcludingSelf) {
140   EXPECT_LT(0, map_field_base_->SpaceUsedExcludingSelf());
141 }
142 
TEST_F(MapFieldBasePrimitiveTest,GetRepeatedField)143 TEST_F(MapFieldBasePrimitiveTest, GetRepeatedField) {
144   const RepeatedPtrField<Message>& repeated =
145       reinterpret_cast<const RepeatedPtrField<Message>&>(
146           map_field_base_->GetRepeatedField());
147   EXPECT_EQ(2, repeated.size());
148   for (int i = 0; i < repeated.size(); i++) {
149     const Message& message = repeated.Get(i);
150     int key = message.GetReflection()->GetInt32(message, key_descriptor_);
151     int value = message.GetReflection()->GetInt32(message, value_descriptor_);
152     EXPECT_EQ(value, initial_value_map_[key]);
153   }
154 }
155 
TEST_F(MapFieldBasePrimitiveTest,MutableRepeatedField)156 TEST_F(MapFieldBasePrimitiveTest, MutableRepeatedField) {
157   RepeatedPtrField<Message>* repeated =
158       reinterpret_cast<RepeatedPtrField<Message>*>(
159           map_field_base_->MutableRepeatedField());
160   EXPECT_EQ(2, repeated->size());
161   for (int i = 0; i < repeated->size(); i++) {
162     const Message& message = repeated->Get(i);
163     int key = message.GetReflection()->GetInt32(message, key_descriptor_);
164     int value = message.GetReflection()->GetInt32(message, value_descriptor_);
165     EXPECT_EQ(value, initial_value_map_[key]);
166   }
167 }
168 
TEST_F(MapFieldBasePrimitiveTest,Arena)169 TEST_F(MapFieldBasePrimitiveTest, Arena) {
170   // Allocate a large initial block to avoid mallocs during hooked test.
171   std::vector<char> arena_block(128 * 1024);
172   ArenaOptions options;
173   options.initial_block = &arena_block[0];
174   options.initial_block_size = arena_block.size();
175   Arena arena(options);
176 
177   {
178     // TODO(liujisi): Re-write the test to ensure the memory for the map and
179     // repeated fields are allocated from arenas.
180     // NoHeapChecker no_heap;
181 
182     MapFieldType* map_field = Arena::CreateMessage<MapFieldType>(&arena);
183 
184     // Set content in map
185     (*map_field->MutableMap())[100] = 101;
186 
187     // Trigger conversion to repeated field.
188     map_field->GetRepeatedField();
189   }
190 
191   {
192     // TODO(liujisi): Re-write the test to ensure the memory for the map and
193     // repeated fields are allocated from arenas.
194     // NoHeapChecker no_heap;
195 
196     MapFieldBaseStub* map_field =
197         Arena::CreateMessage<MapFieldBaseStub>(&arena);
198 
199     // Trigger conversion to repeated field.
200     EXPECT_TRUE(map_field->MutableRepeatedField() != NULL);
201   }
202 }
203 
204 namespace {
205 enum State { CLEAN, MAP_DIRTY, REPEATED_DIRTY };
206 }  // anonymous namespace
207 
208 class MapFieldStateTest : public testing::TestWithParam<State> {
209  public:
210  protected:
211   typedef unittest::TestMap_MapInt32Int32Entry_DoNotUse EntryType;
212   typedef MapField<EntryType, int32, int32, WireFormatLite::TYPE_INT32,
213                    WireFormatLite::TYPE_INT32>
214       MapFieldType;
MapFieldStateTest()215   MapFieldStateTest() : state_(GetParam()) {
216     // Build map field
217     map_field_.reset(new MapFieldType());
218     map_field_base_ = map_field_.get();
219 
220     Expect(map_field_.get(), MAP_DIRTY, 0, 0, true);
221     switch (state_) {
222       case CLEAN:
223         AddOneStillClean(map_field_.get());
224         break;
225       case MAP_DIRTY:
226         MakeMapDirty(map_field_.get());
227         break;
228       case REPEATED_DIRTY:
229         MakeRepeatedDirty(map_field_.get());
230         break;
231       default:
232         break;
233     }
234   }
235 
AddOneStillClean(MapFieldType * map_field)236   void AddOneStillClean(MapFieldType* map_field) {
237     MapFieldBase* map_field_base = map_field;
238     Map<int32, int32>* map = map_field->MutableMap();
239     (*map)[0] = 0;
240     map_field_base->GetRepeatedField();
241     Expect(map_field, CLEAN, 1, 1, false);
242   }
243 
MakeMapDirty(MapFieldType * map_field)244   void MakeMapDirty(MapFieldType* map_field) {
245     Map<int32, int32>* map = map_field->MutableMap();
246     (*map)[0] = 0;
247     Expect(map_field, MAP_DIRTY, 1, 0, true);
248   }
249 
MakeRepeatedDirty(MapFieldType * map_field)250   void MakeRepeatedDirty(MapFieldType* map_field) {
251     MakeMapDirty(map_field);
252     MapFieldBase* map_field_base = map_field;
253     map_field_base->MutableRepeatedField();
254     // We use MutableMap on impl_ because we don't want to disturb the syncing
255     Map<int32, int32>* map = map_field->impl_.MutableMap();
256     map->clear();
257 
258     Expect(map_field, REPEATED_DIRTY, 0, 1, false);
259   }
260 
Expect(MapFieldType * map_field,State state,int map_size,int repeated_size,bool is_repeated_null)261   void Expect(MapFieldType* map_field, State state, int map_size,
262               int repeated_size, bool is_repeated_null) {
263     MapFieldBase* map_field_base = map_field;
264     MapFieldBaseStub* stub =
265         reinterpret_cast<MapFieldBaseStub*>(map_field_base);
266 
267     // We use MutableMap on impl_ because we don't want to disturb the syncing
268     Map<int32, int32>* map = map_field->impl_.MutableMap();
269     RepeatedPtrField<Message>* repeated_field = stub->InternalRepeatedField();
270 
271     switch (state) {
272       case MAP_DIRTY:
273         EXPECT_FALSE(stub->IsMapClean());
274         EXPECT_TRUE(stub->IsRepeatedClean());
275         break;
276       case REPEATED_DIRTY:
277         EXPECT_TRUE(stub->IsMapClean());
278         EXPECT_FALSE(stub->IsRepeatedClean());
279         break;
280       case CLEAN:
281         EXPECT_TRUE(stub->IsMapClean());
282         EXPECT_TRUE(stub->IsRepeatedClean());
283         break;
284       default:
285         FAIL();
286     }
287 
288     EXPECT_EQ(map_size, map->size());
289     if (is_repeated_null) {
290       EXPECT_TRUE(repeated_field == NULL);
291     } else {
292       if (repeated_field == nullptr) {
293         EXPECT_EQ(repeated_size, 0);
294       } else {
295         EXPECT_EQ(repeated_size, repeated_field->size());
296       }
297     }
298   }
299 
300   std::unique_ptr<MapFieldType> map_field_;
301   MapFieldBase* map_field_base_;
302   State state_;
303 };
304 
305 INSTANTIATE_TEST_SUITE_P(MapFieldStateTestInstance, MapFieldStateTest,
306                          ::testing::Values(CLEAN, MAP_DIRTY, REPEATED_DIRTY));
307 
TEST_P(MapFieldStateTest,GetMap)308 TEST_P(MapFieldStateTest, GetMap) {
309   map_field_->GetMap();
310   if (state_ != MAP_DIRTY) {
311     Expect(map_field_.get(), CLEAN, 1, 1, false);
312   } else {
313     Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
314   }
315 }
316 
TEST_P(MapFieldStateTest,MutableMap)317 TEST_P(MapFieldStateTest, MutableMap) {
318   map_field_->MutableMap();
319   if (state_ != MAP_DIRTY) {
320     Expect(map_field_.get(), MAP_DIRTY, 1, 1, false);
321   } else {
322     Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
323   }
324 }
325 
TEST_P(MapFieldStateTest,MergeFromClean)326 TEST_P(MapFieldStateTest, MergeFromClean) {
327   MapFieldType other;
328   AddOneStillClean(&other);
329 
330   map_field_->MergeFrom(other);
331 
332   if (state_ != MAP_DIRTY) {
333     Expect(map_field_.get(), MAP_DIRTY, 1, 1, false);
334   } else {
335     Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
336   }
337 
338   Expect(&other, CLEAN, 1, 1, false);
339 }
340 
TEST_P(MapFieldStateTest,MergeFromMapDirty)341 TEST_P(MapFieldStateTest, MergeFromMapDirty) {
342   MapFieldType other;
343   MakeMapDirty(&other);
344 
345   map_field_->MergeFrom(other);
346 
347   if (state_ != MAP_DIRTY) {
348     Expect(map_field_.get(), MAP_DIRTY, 1, 1, false);
349   } else {
350     Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
351   }
352 
353   Expect(&other, MAP_DIRTY, 1, 0, true);
354 }
355 
TEST_P(MapFieldStateTest,MergeFromRepeatedDirty)356 TEST_P(MapFieldStateTest, MergeFromRepeatedDirty) {
357   MapFieldType other;
358   MakeRepeatedDirty(&other);
359 
360   map_field_->MergeFrom(other);
361 
362   if (state_ != MAP_DIRTY) {
363     Expect(map_field_.get(), MAP_DIRTY, 1, 1, false);
364   } else {
365     Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
366   }
367 
368   Expect(&other, CLEAN, 1, 1, false);
369 }
370 
TEST_P(MapFieldStateTest,SwapClean)371 TEST_P(MapFieldStateTest, SwapClean) {
372   MapFieldType other;
373   AddOneStillClean(&other);
374 
375   map_field_->Swap(&other);
376 
377   Expect(map_field_.get(), CLEAN, 1, 1, false);
378 
379   switch (state_) {
380     case CLEAN:
381       Expect(&other, CLEAN, 1, 1, false);
382       break;
383     case MAP_DIRTY:
384       Expect(&other, MAP_DIRTY, 1, 0, true);
385       break;
386     case REPEATED_DIRTY:
387       Expect(&other, REPEATED_DIRTY, 0, 1, false);
388       break;
389     default:
390       break;
391   }
392 }
393 
TEST_P(MapFieldStateTest,SwapMapDirty)394 TEST_P(MapFieldStateTest, SwapMapDirty) {
395   MapFieldType other;
396   MakeMapDirty(&other);
397 
398   map_field_->Swap(&other);
399 
400   Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
401 
402   switch (state_) {
403     case CLEAN:
404       Expect(&other, CLEAN, 1, 1, false);
405       break;
406     case MAP_DIRTY:
407       Expect(&other, MAP_DIRTY, 1, 0, true);
408       break;
409     case REPEATED_DIRTY:
410       Expect(&other, REPEATED_DIRTY, 0, 1, false);
411       break;
412     default:
413       break;
414   }
415 }
416 
TEST_P(MapFieldStateTest,SwapRepeatedDirty)417 TEST_P(MapFieldStateTest, SwapRepeatedDirty) {
418   MapFieldType other;
419   MakeRepeatedDirty(&other);
420 
421   map_field_->Swap(&other);
422 
423   Expect(map_field_.get(), REPEATED_DIRTY, 0, 1, false);
424 
425   switch (state_) {
426     case CLEAN:
427       Expect(&other, CLEAN, 1, 1, false);
428       break;
429     case MAP_DIRTY:
430       Expect(&other, MAP_DIRTY, 1, 0, true);
431       break;
432     case REPEATED_DIRTY:
433       Expect(&other, REPEATED_DIRTY, 0, 1, false);
434       break;
435     default:
436       break;
437   }
438 }
439 
TEST_P(MapFieldStateTest,Clear)440 TEST_P(MapFieldStateTest, Clear) {
441   map_field_->Clear();
442 
443   Expect(map_field_.get(), MAP_DIRTY, 0, 0, false);
444 }
445 
TEST_P(MapFieldStateTest,SpaceUsedExcludingSelf)446 TEST_P(MapFieldStateTest, SpaceUsedExcludingSelf) {
447   map_field_base_->SpaceUsedExcludingSelf();
448 
449   switch (state_) {
450     case CLEAN:
451       Expect(map_field_.get(), CLEAN, 1, 1, false);
452       break;
453     case MAP_DIRTY:
454       Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
455       break;
456     case REPEATED_DIRTY:
457       Expect(map_field_.get(), REPEATED_DIRTY, 0, 1, false);
458       break;
459     default:
460       break;
461   }
462 }
463 
TEST_P(MapFieldStateTest,GetMapField)464 TEST_P(MapFieldStateTest, GetMapField) {
465   map_field_base_->GetRepeatedField();
466 
467   if (state_ != REPEATED_DIRTY) {
468     Expect(map_field_.get(), CLEAN, 1, 1, false);
469   } else {
470     Expect(map_field_.get(), REPEATED_DIRTY, 0, 1, false);
471   }
472 }
473 
TEST_P(MapFieldStateTest,MutableMapField)474 TEST_P(MapFieldStateTest, MutableMapField) {
475   map_field_base_->MutableRepeatedField();
476 
477   if (state_ != REPEATED_DIRTY) {
478     Expect(map_field_.get(), REPEATED_DIRTY, 1, 1, false);
479   } else {
480     Expect(map_field_.get(), REPEATED_DIRTY, 0, 1, false);
481   }
482 }
483 
484 class MyMapField
485     : public MapField<unittest::TestMap_MapInt32Int32Entry_DoNotUse, int32,
486                       int32, internal::WireFormatLite::TYPE_INT32,
487                       internal::WireFormatLite::TYPE_INT32> {
488  public:
MyMapField()489   constexpr MyMapField()
490       : MyMapField::MapField(internal::ConstantInitialized{}) {}
491 };
492 
TEST(MapFieldTest,ConstInit)493 TEST(MapFieldTest, ConstInit) {
494   // This tests that `MapField` and all its base classes can be constant
495   // initialized.
496   PROTOBUF_CONSTINIT static MyMapField field;  // NOLINT
497   EXPECT_EQ(field.size(), 0);
498 }
499 
500 
501 }  // namespace internal
502 }  // namespace protobuf
503 }  // namespace google
504