xref: /aosp_15_r20/external/google-breakpad/src/common/simple_string_dictionary_unittest.cc (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
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 
TEST(NonAllocatingMapTest,Entry)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 
TEST(NonAllocatingMapTest,SimpleStringDictionary)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 
TEST(NonAllocatingMapTest,CopyAndAssign)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.
TEST(NonAllocatingMapTest,Iterator)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 
TEST(NonAllocatingMapTest,AddRemove)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 
TEST(NonAllocatingMapTest,Serialize)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.
TEST(NonAllocatingMapTest,OutOfSpace)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 
TEST(NonAllocatingMapTest,ByIndex)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 
TEST(NonAllocatingMapTest,NullKey)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
343