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