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