/ src / common / simple_string_dictionary_unittest.cc
simple_string_dictionary_unittest.cc
  1  // Copyright 2008 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  #ifdef HAVE_CONFIG_H
 30  #include <config.h>  // Must come first
 31  #endif
 32  
 33  #include "breakpad_googletest_includes.h"
 34  #include "common/simple_string_dictionary.h"
 35  
 36  namespace google_breakpad {
 37  
 38  TEST(NonAllocatingMapTest, Entry) {
 39    typedef NonAllocatingMap<5, 9, 15> TestMap;
 40    TestMap map;
 41  
 42    const TestMap::Entry* entry = TestMap::Iterator(map).Next();
 43    EXPECT_FALSE(entry);
 44  
 45    // Try setting a key/value and then verify.
 46    map.SetKeyValue("key1", "value1");
 47    entry = TestMap::Iterator(map).Next();
 48    ASSERT_TRUE(entry);
 49    EXPECT_STREQ(entry->key, "key1");
 50    EXPECT_STREQ(entry->value, "value1");
 51  
 52    // Try setting a new value.
 53    map.SetKeyValue("key1", "value3");
 54    EXPECT_STREQ(entry->value, "value3");
 55  
 56    // Make sure the key didn't change.
 57    EXPECT_STREQ(entry->key, "key1");
 58  
 59    // Clear the entry and verify the key and value are empty strings.
 60    map.RemoveKey("key1");
 61    EXPECT_FALSE(entry->is_active());
 62    EXPECT_EQ(strlen(entry->key), 0u);
 63    EXPECT_EQ(strlen(entry->value), 0u);
 64  }
 65  
 66  TEST(NonAllocatingMapTest, SimpleStringDictionary) {
 67    // Make a new dictionary
 68    SimpleStringDictionary dict;
 69  
 70    // Set three distinct values on three keys
 71    dict.SetKeyValue("key1", "value1");
 72    dict.SetKeyValue("key2", "value2");
 73    dict.SetKeyValue("key3", "value3");
 74  
 75    EXPECT_NE(dict.GetValueForKey("key1"), "value1");
 76    EXPECT_NE(dict.GetValueForKey("key2"), "value2");
 77    EXPECT_NE(dict.GetValueForKey("key3"), "value3");
 78    EXPECT_EQ(dict.GetCount(), 3u);
 79    // try an unknown key
 80    EXPECT_FALSE(dict.GetValueForKey("key4"));
 81  
 82    // Remove a key
 83    dict.RemoveKey("key3");
 84  
 85    // Now make sure it's not there anymore
 86    EXPECT_FALSE(dict.GetValueForKey("key3"));
 87  
 88    // Remove by setting value to NULL
 89    dict.SetKeyValue("key2", NULL);
 90  
 91    // Now make sure it's not there anymore
 92    EXPECT_FALSE(dict.GetValueForKey("key2"));
 93  }
 94  
 95  TEST(NonAllocatingMapTest, CopyAndAssign) {
 96    NonAllocatingMap<10, 10, 10> map;
 97    map.SetKeyValue("one", "a");
 98    map.SetKeyValue("two", "b");
 99    map.SetKeyValue("three", "c");
100    map.RemoveKey("two");
101    EXPECT_EQ(2u, map.GetCount());
102  
103    // Test copy.
104    NonAllocatingMap<10, 10, 10> map_copy(map);
105    EXPECT_EQ(2u, map_copy.GetCount());
106    EXPECT_STREQ("a", map_copy.GetValueForKey("one"));
107    EXPECT_STREQ("c", map_copy.GetValueForKey("three"));
108    map_copy.SetKeyValue("four", "d");
109    EXPECT_STREQ("d", map_copy.GetValueForKey("four"));
110    EXPECT_FALSE(map.GetValueForKey("four"));
111  
112    // Test assign.
113    NonAllocatingMap<10, 10, 10> map_assign;
114    map_assign = map;
115    EXPECT_EQ(2u, map_assign.GetCount());
116    EXPECT_STREQ("a", map_assign.GetValueForKey("one"));
117    EXPECT_STREQ("c", map_assign.GetValueForKey("three"));
118    map_assign.SetKeyValue("four", "d");
119    EXPECT_STREQ("d", map_assign.GetValueForKey("four"));
120    EXPECT_FALSE(map.GetValueForKey("four"));
121  
122    map.RemoveKey("one");
123    EXPECT_FALSE(map.GetValueForKey("one"));
124    EXPECT_STREQ("a", map_copy.GetValueForKey("one"));
125    EXPECT_STREQ("a", map_assign.GetValueForKey("one"));
126  }
127  
128  // Add a bunch of values to the dictionary, remove some entries in the middle,
129  // and then add more.
130  TEST(NonAllocatingMapTest, Iterator) {
131    SimpleStringDictionary* dict = new SimpleStringDictionary();
132    ASSERT_TRUE(dict);
133  
134    char key[SimpleStringDictionary::key_size];
135    char value[SimpleStringDictionary::value_size];
136  
137    const int kDictionaryCapacity = SimpleStringDictionary::num_entries;
138    const int kPartitionIndex = kDictionaryCapacity - 5;
139  
140    // We assume at least this size in the tests below
141    ASSERT_GE(kDictionaryCapacity, 64);
142  
143    // We'll keep track of the number of key/value pairs we think should
144    // be in the dictionary
145    int expectedDictionarySize = 0;
146  
147    // Set a bunch of key/value pairs like key0/value0, key1/value1, ...
148    for (int i = 0; i < kPartitionIndex; ++i) {
149      sprintf(key, "key%d", i);
150      sprintf(value, "value%d", i);
151      dict->SetKeyValue(key, value);
152    }
153    expectedDictionarySize = kPartitionIndex;
154  
155    // set a couple of the keys twice (with the same value) - should be nop
156    dict->SetKeyValue("key2", "value2");
157    dict->SetKeyValue("key4", "value4");
158    dict->SetKeyValue("key15", "value15");
159  
160    // Remove some random elements in the middle
161    dict->RemoveKey("key7");
162    dict->RemoveKey("key18");
163    dict->RemoveKey("key23");
164    dict->RemoveKey("key31");
165    expectedDictionarySize -= 4;  // we just removed four key/value pairs
166  
167    // Set some more key/value pairs like key59/value59, key60/value60, ...
168    for (int i = kPartitionIndex; i < kDictionaryCapacity; ++i) {
169      sprintf(key, "key%d", i);
170      sprintf(value, "value%d", i);
171      dict->SetKeyValue(key, value);
172    }
173    expectedDictionarySize += kDictionaryCapacity - kPartitionIndex;
174  
175    // Now create an iterator on the dictionary
176    SimpleStringDictionary::Iterator iter(*dict);
177  
178    // We then verify that it iterates through exactly the number of
179    // key/value pairs we expect, and that they match one-for-one with what we
180    // would expect.  The ordering of the iteration does not matter...
181  
182    // used to keep track of number of occurrences found for key/value pairs
183    int count[kDictionaryCapacity];
184    memset(count, 0, sizeof(count));
185  
186    int totalCount = 0;
187  
188    const SimpleStringDictionary::Entry* entry;
189    while ((entry = iter.Next())) {
190      totalCount++;
191  
192      // Extract keyNumber from a string of the form key<keyNumber>
193      int keyNumber;
194      sscanf(entry->key, "key%d", &keyNumber);
195  
196      // Extract valueNumber from a string of the form value<valueNumber>
197      int valueNumber;
198      sscanf(entry->value, "value%d", &valueNumber);
199  
200      // The value number should equal the key number since that's how we set them
201      EXPECT_EQ(keyNumber, valueNumber);
202  
203      // Key and value numbers should be in proper range:
204      // 0 <= keyNumber < kDictionaryCapacity
205      bool isKeyInGoodRange =
206        (keyNumber >= 0 && keyNumber < kDictionaryCapacity);
207      bool isValueInGoodRange =
208        (valueNumber >= 0 && valueNumber < kDictionaryCapacity);
209      EXPECT_TRUE(isKeyInGoodRange);
210      EXPECT_TRUE(isValueInGoodRange);
211  
212      if (isKeyInGoodRange && isValueInGoodRange) {
213        ++count[keyNumber];
214      }
215    }
216  
217    // Make sure each of the key/value pairs showed up exactly one time, except
218    // for the ones which we removed.
219    for (size_t i = 0; i < kDictionaryCapacity; ++i) {
220      // Skip over key7, key18, key23, and key31, since we removed them
221      if (!(i == 7 || i == 18 || i == 23 || i == 31)) {
222        EXPECT_EQ(count[i], 1);
223      }
224    }
225  
226    // Make sure the number of iterations matches the expected dictionary size.
227    EXPECT_EQ(totalCount, expectedDictionarySize);
228  }
229  
230  
231  TEST(NonAllocatingMapTest, AddRemove) {
232    NonAllocatingMap<5, 7, 6> map;
233    map.SetKeyValue("rob", "ert");
234    map.SetKeyValue("mike", "pink");
235    map.SetKeyValue("mark", "allays");
236  
237    EXPECT_EQ(3u, map.GetCount());
238    EXPECT_STREQ("ert", map.GetValueForKey("rob"));
239    EXPECT_STREQ("pink", map.GetValueForKey("mike"));
240    EXPECT_STREQ("allays", map.GetValueForKey("mark"));
241  
242    map.RemoveKey("mike");
243  
244    EXPECT_EQ(2u, map.GetCount());
245    EXPECT_FALSE(map.GetValueForKey("mike"));
246  
247    map.SetKeyValue("mark", "mal");
248    EXPECT_EQ(2u, map.GetCount());
249    EXPECT_STREQ("mal", map.GetValueForKey("mark"));
250  
251    map.RemoveKey("mark");
252    EXPECT_EQ(1u, map.GetCount());
253    EXPECT_FALSE(map.GetValueForKey("mark"));
254  }
255  
256  TEST(NonAllocatingMapTest, Serialize) {
257    typedef NonAllocatingMap<4, 5, 7> TestMap;
258    TestMap map;
259    map.SetKeyValue("one", "abc");
260    map.SetKeyValue("two", "def");
261    map.SetKeyValue("tre", "hig");
262  
263    EXPECT_STREQ("abc", map.GetValueForKey("one"));
264    EXPECT_STREQ("def", map.GetValueForKey("two"));
265    EXPECT_STREQ("hig", map.GetValueForKey("tre"));
266  
267    const SerializedNonAllocatingMap* serialized;
268    size_t size = map.Serialize(&serialized);
269  
270    SerializedNonAllocatingMap* serialized_copy =
271        reinterpret_cast<SerializedNonAllocatingMap*>(malloc(size));
272    ASSERT_TRUE(serialized_copy);
273    memcpy(serialized_copy, serialized, size);
274  
275    TestMap deserialized(serialized_copy, size);
276    free(serialized_copy);
277  
278    EXPECT_EQ(3u, deserialized.GetCount());
279    EXPECT_STREQ("abc", deserialized.GetValueForKey("one"));
280    EXPECT_STREQ("def", deserialized.GetValueForKey("two"));
281    EXPECT_STREQ("hig", deserialized.GetValueForKey("tre"));
282  }
283  
284  // Running out of space shouldn't crash.
285  TEST(NonAllocatingMapTest, OutOfSpace) {
286    NonAllocatingMap<3, 2, 2> map;
287    map.SetKeyValue("a", "1");
288    map.SetKeyValue("b", "2");
289    map.SetKeyValue("c", "3");
290    EXPECT_EQ(2u, map.GetCount());
291    EXPECT_FALSE(map.GetValueForKey("c"));
292  }
293  
294  TEST(NonAllocatingMapTest, ByIndex) {
295    NonAllocatingMap<10, 10, 3> map;
296  
297    size_t index1 = map.SetKeyValue("test", "one");
298    EXPECT_TRUE(index1 >= 0 && index1 <= map.num_entries);
299  
300    size_t index2 = map.SetKeyValue("moo", "foo");
301    EXPECT_TRUE(index2 >= 0 && index2 <= map.num_entries);
302    EXPECT_NE(index1, index2);
303  
304    size_t index3 = map.SetKeyValue("blob", "kebab");
305    EXPECT_TRUE(index3 >= 0 && index3 <= map.num_entries);
306    EXPECT_NE(index2, index3);
307  
308    size_t index4 = map.SetKeyValue("nogo", "full");
309    EXPECT_TRUE(index4 == map.num_entries);
310  
311    EXPECT_STREQ("one", map.GetValueForKey("test"));
312    EXPECT_STREQ("foo", map.GetValueForKey("moo"));
313    EXPECT_STREQ("kebab", map.GetValueForKey("blob"));
314  
315    map.SetValueAtIndex(index2, "booo");
316    EXPECT_STREQ("booo", map.GetValueForKey("moo"));
317  
318    EXPECT_TRUE(map.RemoveAtIndex(index1));
319    EXPECT_FALSE(map.GetValueForKey("test"));
320  
321    EXPECT_FALSE(map.RemoveAtIndex(map.num_entries));
322    EXPECT_FALSE(map.RemoveAtIndex(9999));
323  }
324  
325  #ifndef NDEBUG
326  
327  TEST(NonAllocatingMapTest, NullKey) {
328    NonAllocatingMap<4, 6, 6> map;
329    ASSERT_DEATH(map.SetKeyValue(NULL, "hello"), "");
330  
331    map.SetKeyValue("hi", "there");
332    ASSERT_DEATH(map.GetValueForKey(NULL), "");
333    EXPECT_STREQ("there", map.GetValueForKey("hi"));
334  
335    ASSERT_DEATH(map.GetValueForKey(NULL), "");
336    map.RemoveKey("hi");
337    EXPECT_EQ(0u, map.GetCount());
338  }
339  
340  #endif  // !NDEBUG
341  
342  }  // namespace google_breakpad