• 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 #ifndef _SHARED_PTR_H
34 #include <google/protobuf/stubs/shared_ptr.h>
35 #endif
36 
37 #include <google/protobuf/stubs/logging.h>
38 #include <google/protobuf/stubs/common.h>
39 #include <google/protobuf/arena.h>
40 #include <google/protobuf/map.h>
41 #include <google/protobuf/arena_test_util.h>
42 #include <google/protobuf/map_unittest.pb.h>
43 #include <google/protobuf/map_test_util.h>
44 #include <google/protobuf/unittest.pb.h>
45 #include <google/protobuf/map_field_inl.h>
46 #include <google/protobuf/message.h>
47 #include <google/protobuf/repeated_field.h>
48 #include <google/protobuf/wire_format_lite_inl.h>
49 #include <gtest/gtest.h>
50 namespace google {
51 
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) {}
SyncRepeatedFieldWithMap() const64   void SyncRepeatedFieldWithMap() const {
65     MapFieldBase::SyncRepeatedFieldWithMap();
66   }
SyncMapWithRepeatedField() const67   void SyncMapWithRepeatedField() const {
68     MapFieldBase::SyncMapWithRepeatedField();
69   }
70   // Get underlined repeated field without synchronizing map.
InternalRepeatedField()71   RepeatedPtrField<Message>* InternalRepeatedField() {
72     return repeated_field_;
73   }
IsMapClean()74   bool IsMapClean() { return state_ != 0; }
IsRepeatedClean()75   bool IsRepeatedClean() { return state_ != 1; }
SetMapDirty()76   void SetMapDirty() { state_ = 0; }
SetRepeatedDirty()77   void SetRepeatedDirty() { state_ = 1; }
ContainsMapKey(const MapKey & map_key) const78   bool ContainsMapKey(const MapKey& map_key) const {
79     return false;
80   }
InsertOrLookupMapValue(const MapKey & map_key,MapValueRef * val)81   bool InsertOrLookupMapValue(const MapKey& map_key, MapValueRef* val) {
82     return false;
83   }
DeleteMapValue(const MapKey & map_key)84   bool DeleteMapValue(const MapKey& map_key) {
85     return false;
86   }
EqualIterator(const MapIterator & a,const MapIterator & b) const87   bool EqualIterator(const MapIterator& a, const MapIterator& b) const {
88     return false;
89   }
size() const90   int size() const { return 0; }
MapBegin(MapIterator * map_iter) const91   void MapBegin(MapIterator* map_iter) const {}
MapEnd(MapIterator * map_iter) const92   void MapEnd(MapIterator* map_iter) const {}
InitializeIterator(MapIterator * map_iter) const93   void InitializeIterator(MapIterator* map_iter) const {}
DeleteIterator(MapIterator * map_iter) const94   void DeleteIterator(MapIterator* map_iter) const {}
CopyIterator(MapIterator * this_iterator,const MapIterator & other_iterator) const95   void CopyIterator(MapIterator* this_iterator,
96                     const MapIterator& other_iterator) const {}
IncreaseIterator(MapIterator * map_iter) const97   void IncreaseIterator(MapIterator* map_iter) const {}
SetDefaultMessageEntry(const Message * message) const98   void SetDefaultMessageEntry(const Message* message) const {}
GetDefaultMessageEntry() const99   const Message* GetDefaultMessageEntry() const { return NULL; }
100 };
101 
102 class MapFieldBasePrimitiveTest : public ::testing::Test {
103  protected:
104   typedef MapField<int32, int32, WireFormatLite::TYPE_INT32,
105                    WireFormatLite::TYPE_INT32, false> MapFieldType;
106 
MapFieldBasePrimitiveTest()107   MapFieldBasePrimitiveTest() {
108     // Get descriptors
109     map_descriptor_ = unittest::TestMap::descriptor()
110                           ->FindFieldByName("map_int32_int32")
111                           ->message_type();
112     key_descriptor_ = map_descriptor_->FindFieldByName("key");
113     value_descriptor_ = map_descriptor_->FindFieldByName("value");
114 
115     // Build map field
116     default_entry_ =
117         MessageFactory::generated_factory()->GetPrototype(map_descriptor_);
118     map_field_.reset(new MapFieldType(default_entry_));
119     map_field_base_ = map_field_.get();
120     map_ = map_field_->MutableMap();
121     initial_value_map_[0] = 100;
122     initial_value_map_[1] = 101;
123     map_->insert(initial_value_map_.begin(), initial_value_map_.end());
124     EXPECT_EQ(2, map_->size());
125   }
126 
127   google::protobuf::scoped_ptr<MapFieldType> map_field_;
128   MapFieldBase* map_field_base_;
129   Map<int32, int32>* map_;
130   const Descriptor* map_descriptor_;
131   const FieldDescriptor* key_descriptor_;
132   const FieldDescriptor* value_descriptor_;
133   const Message* default_entry_;
134   std::map<int32, int32> initial_value_map_;  // copy of initial values inserted
135 };
136 
TEST_F(MapFieldBasePrimitiveTest,SpaceUsedExcludingSelf)137 TEST_F(MapFieldBasePrimitiveTest, SpaceUsedExcludingSelf) {
138   EXPECT_LT(0, map_field_base_->SpaceUsedExcludingSelf());
139 }
140 
TEST_F(MapFieldBasePrimitiveTest,GetRepeatedField)141 TEST_F(MapFieldBasePrimitiveTest, GetRepeatedField) {
142   const RepeatedPtrField<Message>& repeated =
143       reinterpret_cast<const RepeatedPtrField<Message>&>(
144           map_field_base_->GetRepeatedField());
145   EXPECT_EQ(2, repeated.size());
146   for (int i = 0; i < repeated.size(); i++) {
147     const Message& message = repeated.Get(i);
148     int key = message.GetReflection()->GetInt32(message, key_descriptor_);
149     int value = message.GetReflection()->GetInt32(message, value_descriptor_);
150     EXPECT_EQ(value, initial_value_map_[key]);
151   }
152 }
153 
TEST_F(MapFieldBasePrimitiveTest,MutableRepeatedField)154 TEST_F(MapFieldBasePrimitiveTest, MutableRepeatedField) {
155   RepeatedPtrField<Message>* repeated =
156       reinterpret_cast<RepeatedPtrField<Message>*>(
157           map_field_base_->MutableRepeatedField());
158   EXPECT_EQ(2, repeated->size());
159   for (int i = 0; i < repeated->size(); i++) {
160     const Message& message = repeated->Get(i);
161     int key = message.GetReflection()->GetInt32(message, key_descriptor_);
162     int value = message.GetReflection()->GetInt32(message, value_descriptor_);
163     EXPECT_EQ(value, initial_value_map_[key]);
164   }
165 }
166 
TEST_F(MapFieldBasePrimitiveTest,Arena)167 TEST_F(MapFieldBasePrimitiveTest, Arena) {
168   // Allocate a large initial block to avoid mallocs during hooked test.
169   std::vector<char> arena_block(128 * 1024);
170   ArenaOptions options;
171   options.initial_block = &arena_block[0];
172   options.initial_block_size = arena_block.size();
173   Arena arena(options);
174 
175   {
176     // TODO(liujisi): Re-write the test to ensure the memory for the map and
177     // repeated fields are allocated from arenas.
178     // NoHeapChecker no_heap;
179 
180     MapFieldType* map_field =
181         Arena::CreateMessage<MapFieldType>(&arena, default_entry_);
182 
183     // Set content in map
184     (*map_field->MutableMap())[100] = 101;
185 
186     // Trigger conversion to repeated field.
187     map_field->GetRepeatedField();
188   }
189 
190   {
191     // TODO(liujisi): Re-write the test to ensure the memory for the map and
192     // repeated fields are allocated from arenas.
193     // NoHeapChecker no_heap;
194 
195     MapFieldBaseStub* map_field =
196         Arena::CreateMessage<MapFieldBaseStub>(&arena);
197 
198     // Trigger conversion to repeated field.
199     EXPECT_TRUE(map_field->MutableRepeatedField() != NULL);
200   }
201 }
202 
203 namespace {
204 enum State { CLEAN, MAP_DIRTY, REPEATED_DIRTY };
205 }  // anonymous namespace
206 
207 class MapFieldStateTest
208     : public testing::TestWithParam<State> {
209  public:
210  protected:
211   typedef MapField<int32, int32, WireFormatLite::TYPE_INT32,
212                    WireFormatLite::TYPE_INT32, false> MapFieldType;
213   typedef MapFieldLite<int32, int32, WireFormatLite::TYPE_INT32,
214                        WireFormatLite::TYPE_INT32, false> MapFieldLiteType;
MapFieldStateTest()215   MapFieldStateTest() : state_(GetParam()) {
216     // Build map field
217     const Descriptor* map_descriptor =
218         unittest::TestMap::descriptor()
219             ->FindFieldByName("map_int32_int32")
220             ->message_type();
221     default_entry_ =
222         MessageFactory::generated_factory()->GetPrototype(map_descriptor);
223     map_field_.reset(new MapFieldType(default_entry_));
224     map_field_base_ = map_field_.get();
225 
226     Expect(map_field_.get(), MAP_DIRTY, 0, 0, true);
227     switch (state_) {
228       case CLEAN:
229         AddOneStillClean(map_field_.get());
230         break;
231       case MAP_DIRTY:
232         MakeMapDirty(map_field_.get());
233         break;
234       case REPEATED_DIRTY:
235         MakeRepeatedDirty(map_field_.get());
236         break;
237       default:
238         break;
239     }
240   }
241 
AddOneStillClean(MapFieldType * map_field)242   void AddOneStillClean(MapFieldType* map_field) {
243     MapFieldBase* map_field_base = map_field;
244     Map<int32, int32>* map = map_field->MutableMap();
245     (*map)[0] = 0;
246     map_field_base->GetRepeatedField();
247     Expect(map_field, CLEAN, 1, 1, false);
248   }
249 
MakeMapDirty(MapFieldType * map_field)250   void MakeMapDirty(MapFieldType* map_field) {
251     Map<int32, int32>* map = map_field->MutableMap();
252     (*map)[0] = 0;
253     Expect(map_field, MAP_DIRTY, 1, 0, true);
254   }
255 
MakeRepeatedDirty(MapFieldType * map_field)256   void MakeRepeatedDirty(MapFieldType* map_field) {
257     MakeMapDirty(map_field);
258     MapFieldBase* map_field_base = map_field;
259     map_field_base->MutableRepeatedField();
260     Map<int32, int32>* map = implicit_cast<MapFieldLiteType*>(map_field)
261                                  ->MapFieldLiteType::MutableMap();
262     map->clear();
263 
264     Expect(map_field, REPEATED_DIRTY, 0, 1, false);
265   }
266 
Expect(MapFieldType * map_field,State state,int map_size,int repeated_size,bool is_repeated_null)267   void Expect(MapFieldType* map_field, State state, int map_size,
268               int repeated_size, bool is_repeated_null) {
269     MapFieldBase* map_field_base = map_field;
270     MapFieldBaseStub* stub =
271         reinterpret_cast<MapFieldBaseStub*>(map_field_base);
272 
273     Map<int32, int32>* map = implicit_cast<MapFieldLiteType*>(map_field)
274                                  ->MapFieldLiteType::MutableMap();
275     RepeatedPtrField<Message>* repeated_field = stub->InternalRepeatedField();
276 
277     switch (state) {
278       case MAP_DIRTY:
279         EXPECT_FALSE(stub->IsMapClean());
280         EXPECT_TRUE(stub->IsRepeatedClean());
281         break;
282       case REPEATED_DIRTY:
283         EXPECT_TRUE(stub->IsMapClean());
284         EXPECT_FALSE(stub->IsRepeatedClean());
285         break;
286       case CLEAN:
287         EXPECT_TRUE(stub->IsMapClean());
288         EXPECT_TRUE(stub->IsRepeatedClean());
289         break;
290       default:
291         FAIL();
292     }
293 
294     EXPECT_EQ(map_size, map->size());
295     if (is_repeated_null) {
296       EXPECT_TRUE(repeated_field == NULL);
297     } else {
298       EXPECT_EQ(repeated_size, repeated_field->size());
299     }
300   }
301 
302   google::protobuf::scoped_ptr<MapFieldType> map_field_;
303   MapFieldBase* map_field_base_;
304   State state_;
305   const Message* default_entry_;
306 };
307 
308 INSTANTIATE_TEST_CASE_P(MapFieldStateTestInstance, MapFieldStateTest,
309                         ::testing::Values(CLEAN, MAP_DIRTY, REPEATED_DIRTY));
310 
TEST_P(MapFieldStateTest,GetMap)311 TEST_P(MapFieldStateTest, GetMap) {
312   map_field_->GetMap();
313   if (state_ != MAP_DIRTY) {
314     Expect(map_field_.get(), CLEAN, 1, 1, false);
315   } else {
316     Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
317   }
318 }
319 
TEST_P(MapFieldStateTest,MutableMap)320 TEST_P(MapFieldStateTest, MutableMap) {
321   map_field_->MutableMap();
322   if (state_ != MAP_DIRTY) {
323     Expect(map_field_.get(), MAP_DIRTY, 1, 1, false);
324   } else {
325     Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
326   }
327 }
328 
TEST_P(MapFieldStateTest,MergeFromClean)329 TEST_P(MapFieldStateTest, MergeFromClean) {
330   MapFieldType other(default_entry_);
331   AddOneStillClean(&other);
332 
333   map_field_->MergeFrom(other);
334 
335   if (state_ != MAP_DIRTY) {
336     Expect(map_field_.get(), MAP_DIRTY, 1, 1, false);
337   } else {
338     Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
339   }
340 
341   Expect(&other, CLEAN, 1, 1, false);
342 }
343 
TEST_P(MapFieldStateTest,MergeFromMapDirty)344 TEST_P(MapFieldStateTest, MergeFromMapDirty) {
345   MapFieldType other(default_entry_);
346   MakeMapDirty(&other);
347 
348   map_field_->MergeFrom(other);
349 
350   if (state_ != MAP_DIRTY) {
351     Expect(map_field_.get(), MAP_DIRTY, 1, 1, false);
352   } else {
353     Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
354   }
355 
356   Expect(&other, MAP_DIRTY, 1, 0, true);
357 }
358 
TEST_P(MapFieldStateTest,MergeFromRepeatedDirty)359 TEST_P(MapFieldStateTest, MergeFromRepeatedDirty) {
360   MapFieldType other(default_entry_);
361   MakeRepeatedDirty(&other);
362 
363   map_field_->MergeFrom(other);
364 
365   if (state_ != MAP_DIRTY) {
366     Expect(map_field_.get(), MAP_DIRTY, 1, 1, false);
367   } else {
368     Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
369   }
370 
371   Expect(&other, CLEAN, 1, 1, false);
372 }
373 
TEST_P(MapFieldStateTest,SwapClean)374 TEST_P(MapFieldStateTest, SwapClean) {
375   MapFieldType other(default_entry_);
376   AddOneStillClean(&other);
377 
378   map_field_->Swap(&other);
379 
380   Expect(map_field_.get(), CLEAN, 1, 1, false);
381 
382   switch (state_) {
383     case CLEAN:
384       Expect(&other, CLEAN, 1, 1, false);
385       break;
386     case MAP_DIRTY:
387       Expect(&other, MAP_DIRTY, 1, 0, true);
388       break;
389     case REPEATED_DIRTY:
390       Expect(&other, REPEATED_DIRTY, 0, 1, false);
391       break;
392     default:
393       break;
394   }
395 }
396 
TEST_P(MapFieldStateTest,SwapMapDirty)397 TEST_P(MapFieldStateTest, SwapMapDirty) {
398   MapFieldType other(default_entry_);
399   MakeMapDirty(&other);
400 
401   map_field_->Swap(&other);
402 
403   Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
404 
405   switch (state_) {
406     case CLEAN:
407       Expect(&other, CLEAN, 1, 1, false);
408       break;
409     case MAP_DIRTY:
410       Expect(&other, MAP_DIRTY, 1, 0, true);
411       break;
412     case REPEATED_DIRTY:
413       Expect(&other, REPEATED_DIRTY, 0, 1, false);
414       break;
415     default:
416       break;
417   }
418 }
419 
TEST_P(MapFieldStateTest,SwapRepeatedDirty)420 TEST_P(MapFieldStateTest, SwapRepeatedDirty) {
421   MapFieldType other(default_entry_);
422   MakeRepeatedDirty(&other);
423 
424   map_field_->Swap(&other);
425 
426   Expect(map_field_.get(), REPEATED_DIRTY, 0, 1, false);
427 
428   switch (state_) {
429     case CLEAN:
430       Expect(&other, CLEAN, 1, 1, false);
431       break;
432     case MAP_DIRTY:
433       Expect(&other, MAP_DIRTY, 1, 0, true);
434       break;
435     case REPEATED_DIRTY:
436       Expect(&other, REPEATED_DIRTY, 0, 1, false);
437       break;
438     default:
439       break;
440   }
441 }
442 
TEST_P(MapFieldStateTest,Clear)443 TEST_P(MapFieldStateTest, Clear) {
444   map_field_->Clear();
445 
446   if (state_ != MAP_DIRTY) {
447     Expect(map_field_.get(), MAP_DIRTY, 0, 1, false);
448   } else {
449     Expect(map_field_.get(), MAP_DIRTY, 0, 0, true);
450   }
451 }
452 
TEST_P(MapFieldStateTest,SpaceUsedExcludingSelf)453 TEST_P(MapFieldStateTest, SpaceUsedExcludingSelf) {
454   map_field_base_->SpaceUsedExcludingSelf();
455 
456   switch (state_) {
457     case CLEAN:
458       Expect(map_field_.get(), CLEAN, 1, 1, false);
459       break;
460     case MAP_DIRTY:
461       Expect(map_field_.get(), MAP_DIRTY, 1, 0, true);
462       break;
463     case REPEATED_DIRTY:
464       Expect(map_field_.get(), REPEATED_DIRTY, 0, 1, false);
465       break;
466     default:
467       break;
468   }
469 }
470 
TEST_P(MapFieldStateTest,GetMapField)471 TEST_P(MapFieldStateTest, GetMapField) {
472   map_field_base_->GetRepeatedField();
473 
474   if (state_ != REPEATED_DIRTY) {
475     Expect(map_field_.get(), CLEAN, 1, 1, false);
476   } else {
477     Expect(map_field_.get(), REPEATED_DIRTY, 0, 1, false);
478   }
479 }
480 
TEST_P(MapFieldStateTest,MutableMapField)481 TEST_P(MapFieldStateTest, MutableMapField) {
482   map_field_base_->MutableRepeatedField();
483 
484   if (state_ != REPEATED_DIRTY) {
485     Expect(map_field_.get(), REPEATED_DIRTY, 1, 1, false);
486   } else {
487     Expect(map_field_.get(), REPEATED_DIRTY, 0, 1, false);
488   }
489 }
490 
491 
492 }  // namespace internal
493 }  // namespace protobuf
494 }  // namespace google
495