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