Home | History | Annotate | Download | only in processor
      1 // Copyright (c) 2010 Google Inc.
      2 // All rights reserved.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are
      6 // met:
      7 //
      8 //     * Redistributions of source code must retain the above copyright
      9 // notice, this list of conditions and the following disclaimer.
     10 //     * Redistributions in binary form must reproduce the above
     11 // copyright notice, this list of conditions and the following disclaimer
     12 // in the documentation and/or other materials provided with the
     13 // distribution.
     14 //     * Neither the name of Google Inc. nor the names of its
     15 // contributors may be used to endorse or promote products derived from
     16 // this software without specific prior written permission.
     17 //
     18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 
     30 // static_map_unittest.cc: Unit tests for StaticMap.
     31 //
     32 // Author: Siyang Xie (lambxsy (at) google.com)
     33 
     34 #include <climits>
     35 #include <map>
     36 
     37 #include "breakpad_googletest_includes.h"
     38 #include "processor/static_map-inl.h"
     39 
     40 
     41 typedef int ValueType;
     42 typedef int KeyType;
     43 typedef google_breakpad::StaticMap< KeyType, ValueType > TestMap;
     44 typedef std::map< KeyType, ValueType > StdMap;
     45 
     46 template<typename Key, typename Value>
     47 class SimpleMapSerializer {
     48  public:
     49   static char* Serialize(const std::map<Key, Value> &stdmap,
     50                    unsigned int* size = NULL) {
     51     unsigned int size_per_node =
     52         sizeof(uint32_t) + sizeof(Key) + sizeof(Value);
     53     unsigned int memsize = sizeof(int32_t) + size_per_node * stdmap.size();
     54     if (size) *size = memsize;
     55 
     56     // Allocate memory for serialized data:
     57     char* mem = reinterpret_cast<char*>(operator new(memsize));
     58     char* address = mem;
     59 
     60     // Writer the number of nodes:
     61     new (address) uint32_t(static_cast<uint32_t>(stdmap.size()));
     62     address += sizeof(uint32_t);
     63 
     64     // Nodes' offset:
     65     uint32_t* offsets = reinterpret_cast<uint32_t*>(address);
     66     address += sizeof(uint32_t) * stdmap.size();
     67 
     68     // Keys:
     69     Key* keys = reinterpret_cast<Key*>(address);
     70     address += sizeof(Key) * stdmap.size();
     71 
     72     // Traversing map:
     73     typename std::map<Key, Value>::const_iterator iter = stdmap.begin();
     74     for (int index = 0; iter != stdmap.end(); ++iter, ++index) {
     75       offsets[index] = static_cast<unsigned int>(address - mem);
     76       keys[index] = iter->first;
     77       new (address) Value(iter->second);
     78       address += sizeof(Value);
     79     }
     80     return mem;
     81   }
     82 };
     83 
     84 
     85 class TestInvalidMap : public ::testing::Test {
     86  protected:
     87   void SetUp() {
     88     memset(data, 0, kMemorySize);
     89   }
     90 
     91   // 40 Bytes memory can hold a StaticMap with up to 3 nodes.
     92   static const int kMemorySize = 40;
     93   char data[kMemorySize];
     94   TestMap test_map;
     95 };
     96 
     97 TEST_F(TestInvalidMap, TestNegativeNumberNodes) {
     98   memset(data, 0xff, sizeof(uint32_t));  // Set the number of nodes = -1
     99   test_map = TestMap(data);
    100   ASSERT_FALSE(test_map.ValidateInMemoryStructure());
    101 }
    102 
    103 TEST_F(TestInvalidMap, TestWrongOffsets) {
    104   uint32_t* header = reinterpret_cast<uint32_t*>(data);
    105   const uint32_t kNumNodes = 2;
    106   const uint32_t kHeaderOffset =
    107         sizeof(uint32_t) + kNumNodes * (sizeof(uint32_t) + sizeof(KeyType));
    108 
    109   header[0] = kNumNodes;
    110   header[1] = kHeaderOffset + 3;   // Wrong offset for first node
    111   test_map = TestMap(data);
    112   ASSERT_FALSE(test_map.ValidateInMemoryStructure());
    113 
    114   header[1] = kHeaderOffset;       // Correct offset for first node
    115   header[2] = kHeaderOffset - 1;   // Wrong offset for second node
    116   test_map = TestMap(data);
    117   ASSERT_FALSE(test_map.ValidateInMemoryStructure());
    118 }
    119 
    120 TEST_F(TestInvalidMap, TestUnSortedKeys) {
    121   uint32_t* header = reinterpret_cast<uint32_t*>(data);
    122   const uint32_t kNumNodes = 2;
    123   const uint32_t kHeaderOffset =
    124       sizeof(uint32_t) + kNumNodes * (sizeof(uint32_t) + sizeof(KeyType));
    125   header[0] = kNumNodes;
    126   header[1] = kHeaderOffset;
    127   header[2] = kHeaderOffset + sizeof(ValueType);
    128 
    129   KeyType* keys = reinterpret_cast<KeyType*>(
    130       data + (kNumNodes + 1) * sizeof(uint32_t));
    131   // Set keys in non-increasing order.
    132   keys[0] = 10;
    133   keys[1] = 7;
    134   test_map = TestMap(data);
    135   ASSERT_FALSE(test_map.ValidateInMemoryStructure());
    136 }
    137 
    138 
    139 class TestValidMap : public ::testing::Test {
    140  protected:
    141   void SetUp() {
    142     int testcase = 0;
    143 
    144     // Empty map.
    145     map_data[testcase] =
    146         serializer.Serialize(std_map[testcase], &size[testcase]);
    147     test_map[testcase] = TestMap(map_data[testcase]);
    148     ++testcase;
    149 
    150     // Single element.
    151     std_map[testcase].insert(std::make_pair(2, 8));
    152     map_data[testcase] =
    153         serializer.Serialize(std_map[testcase], &size[testcase]);
    154     test_map[testcase] = TestMap(map_data[testcase]);
    155     ++testcase;
    156 
    157     // 100 elements.
    158     for (int i = 0; i < 100; ++i)
    159           std_map[testcase].insert(std::make_pair(i, 2 * i));
    160     map_data[testcase] =
    161         serializer.Serialize(std_map[testcase], &size[testcase]);
    162     test_map[testcase] = TestMap(map_data[testcase]);
    163     ++testcase;
    164 
    165     // 1000 random elements.
    166     for (int i = 0; i < 1000; ++i)
    167       std_map[testcase].insert(std::make_pair(rand(), rand()));
    168     map_data[testcase] =
    169         serializer.Serialize(std_map[testcase], &size[testcase]);
    170     test_map[testcase] = TestMap(map_data[testcase]);
    171 
    172     // Set correct size of memory allocation for each test case.
    173     unsigned int size_per_node =
    174         sizeof(uint32_t) + sizeof(KeyType) + sizeof(ValueType);
    175     for (testcase = 0; testcase < kNumberTestCases; ++testcase) {
    176       correct_size[testcase] =
    177           sizeof(uint32_t) + std_map[testcase].size() * size_per_node;
    178     }
    179   }
    180 
    181   void TearDown() {
    182     for (int i = 0;i < kNumberTestCases; ++i)
    183       delete map_data[i];
    184   }
    185 
    186 
    187   void IteratorTester(int test_case) {
    188     // scan through:
    189     iter_test = test_map[test_case].begin();
    190     iter_std = std_map[test_case].begin();
    191 
    192     for (; iter_test != test_map[test_case].end() &&
    193            iter_std != std_map[test_case].end();
    194          ++iter_test, ++iter_std) {
    195       ASSERT_EQ(iter_test.GetKey(), iter_std->first);
    196       ASSERT_EQ(*(iter_test.GetValuePtr()), iter_std->second);
    197     }
    198     ASSERT_TRUE(iter_test == test_map[test_case].end()
    199              && iter_std == std_map[test_case].end());
    200 
    201     // Boundary testcase.
    202     if (!std_map[test_case].empty()) {
    203       // rear boundary case:
    204       iter_test = test_map[test_case].end();
    205       iter_std = std_map[test_case].end();
    206       --iter_std;
    207       --iter_test;
    208       ASSERT_EQ(iter_test.GetKey(), iter_std->first);
    209       ASSERT_EQ(*(iter_test.GetValuePtr()), iter_std->second);
    210 
    211       ++iter_test;
    212       ++iter_std;
    213       ASSERT_TRUE(iter_test == test_map[test_case].end());
    214 
    215       --iter_test;
    216       --iter_std;
    217       ASSERT_TRUE(iter_test != test_map[test_case].end());
    218       ASSERT_TRUE(iter_test == test_map[test_case].last());
    219       ASSERT_EQ(iter_test.GetKey(), iter_std->first);
    220       ASSERT_EQ(*(iter_test.GetValuePtr()), iter_std->second);
    221 
    222       // front boundary case:
    223       iter_test = test_map[test_case].begin();
    224       --iter_test;
    225       ASSERT_TRUE(iter_test == test_map[test_case].begin());
    226     }
    227   }
    228 
    229   void CompareLookupResult(int test_case) {
    230     bool found1 = (iter_test != test_map[test_case].end());
    231     bool found2 = (iter_std != std_map[test_case].end());
    232     ASSERT_EQ(found1, found2);
    233 
    234     if (found1 && found2) {
    235       ASSERT_EQ(iter_test.GetKey(), iter_std->first);
    236       ASSERT_EQ(*(iter_test.GetValuePtr()), iter_std->second);
    237     }
    238   }
    239 
    240   void FindTester(int test_case, const KeyType &key) {
    241     iter_test = test_map[test_case].find(key);
    242     iter_std = std_map[test_case].find(key);
    243     CompareLookupResult(test_case);
    244   }
    245 
    246   void LowerBoundTester(int test_case, const KeyType &key) {
    247     iter_test = test_map[test_case].lower_bound(key);
    248     iter_std = std_map[test_case].lower_bound(key);
    249     CompareLookupResult(test_case);
    250   }
    251 
    252   void UpperBoundTester(int test_case, const KeyType &key) {
    253     iter_test = test_map[test_case].upper_bound(key);
    254     iter_std = std_map[test_case].upper_bound(key);
    255     CompareLookupResult(test_case);
    256   }
    257 
    258   void LookupTester(int test_case) {
    259     StdMap::const_iterator iter;
    260     // Test find():
    261     for (iter = std_map[test_case].begin();
    262         iter != std_map[test_case].end();
    263         ++iter) {
    264       FindTester(test_case, iter->first);
    265       FindTester(test_case, iter->first + 1);
    266       FindTester(test_case, iter->first - 1);
    267     }
    268     FindTester(test_case, INT_MIN);
    269     FindTester(test_case, INT_MAX);
    270     // random test:
    271     for (int i = 0; i < rand()%5000 + 5000; ++i)
    272       FindTester(test_case, rand());
    273 
    274     // Test lower_bound():
    275     for (iter = std_map[test_case].begin();
    276         iter != std_map[test_case].end();
    277         ++iter) {
    278       LowerBoundTester(test_case, iter->first);
    279       LowerBoundTester(test_case, iter->first + 1);
    280       LowerBoundTester(test_case, iter->first - 1);
    281     }
    282     LowerBoundTester(test_case, INT_MIN);
    283     LowerBoundTester(test_case, INT_MAX);
    284     // random test:
    285     for (int i = 0; i < rand()%5000 + 5000; ++i)
    286       LowerBoundTester(test_case, rand());
    287 
    288     // Test upper_bound():
    289     for (iter = std_map[test_case].begin();
    290         iter != std_map[test_case].end();
    291         ++iter) {
    292       UpperBoundTester(test_case, iter->first);
    293       UpperBoundTester(test_case, iter->first + 1);
    294       UpperBoundTester(test_case, iter->first - 1);
    295     }
    296     UpperBoundTester(test_case, INT_MIN);
    297     UpperBoundTester(test_case, INT_MAX);
    298     // random test:
    299     for (int i = 0; i < rand()%5000 + 5000; ++i)
    300       UpperBoundTester(test_case, rand());
    301   }
    302 
    303   static const int kNumberTestCases = 4;
    304   StdMap std_map[kNumberTestCases];
    305   TestMap test_map[kNumberTestCases];
    306   TestMap::const_iterator iter_test;
    307   StdMap::const_iterator iter_std;
    308   char* map_data[kNumberTestCases];
    309   unsigned int size[kNumberTestCases];
    310   unsigned int correct_size[kNumberTestCases];
    311   SimpleMapSerializer<KeyType, ValueType> serializer;
    312 };
    313 
    314 TEST_F(TestValidMap, TestEmptyMap) {
    315   int test_case = 0;
    316   // Assert memory size allocated during serialization is correct.
    317   ASSERT_EQ(correct_size[test_case], size[test_case]);
    318 
    319   // Sanity check of serialized data:
    320   ASSERT_TRUE(test_map[test_case].ValidateInMemoryStructure());
    321   ASSERT_EQ(std_map[test_case].empty(), test_map[test_case].empty());
    322   ASSERT_EQ(std_map[test_case].size(), test_map[test_case].size());
    323 
    324   // Test Iterator.
    325   IteratorTester(test_case);
    326 
    327   // Test lookup operations.
    328   LookupTester(test_case);
    329 }
    330 
    331 TEST_F(TestValidMap, TestSingleElement) {
    332   int test_case = 1;
    333   // Assert memory size allocated during serialization is correct.
    334   ASSERT_EQ(correct_size[test_case], size[test_case]);
    335 
    336   // Sanity check of serialized data:
    337   ASSERT_TRUE(test_map[test_case].ValidateInMemoryStructure());
    338   ASSERT_EQ(std_map[test_case].empty(), test_map[test_case].empty());
    339   ASSERT_EQ(std_map[test_case].size(), test_map[test_case].size());
    340 
    341   // Test Iterator.
    342   IteratorTester(test_case);
    343 
    344   // Test lookup operations.
    345   LookupTester(test_case);
    346 }
    347 
    348 TEST_F(TestValidMap, Test100Elements) {
    349   int test_case = 2;
    350   // Assert memory size allocated during serialization is correct.
    351   ASSERT_EQ(correct_size[test_case], size[test_case]);
    352 
    353   // Sanity check of serialized data:
    354   ASSERT_TRUE(test_map[test_case].ValidateInMemoryStructure());
    355   ASSERT_EQ(std_map[test_case].empty(), test_map[test_case].empty());
    356   ASSERT_EQ(std_map[test_case].size(), test_map[test_case].size());
    357 
    358   // Test Iterator.
    359   IteratorTester(test_case);
    360 
    361   // Test lookup operations.
    362   LookupTester(test_case);
    363 }
    364 
    365 TEST_F(TestValidMap, Test1000RandomElements) {
    366   int test_case = 3;
    367   // Assert memory size allocated during serialization is correct.
    368   ASSERT_EQ(correct_size[test_case], size[test_case]);
    369 
    370   // Sanity check of serialized data:
    371   ASSERT_TRUE(test_map[test_case].ValidateInMemoryStructure());
    372   ASSERT_EQ(std_map[test_case].empty(), test_map[test_case].empty());
    373   ASSERT_EQ(std_map[test_case].size(), test_map[test_case].size());
    374 
    375   // Test Iterator.
    376   IteratorTester(test_case);
    377 
    378   // Test lookup operations.
    379   LookupTester(test_case);
    380 }
    381 
    382 int main(int argc, char *argv[]) {
    383   ::testing::InitGoogleTest(&argc, argv);
    384 
    385   return RUN_ALL_TESTS();
    386 }
    387