OLD | NEW |
(Empty) | |
| 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 |
OLD | NEW |