Serenity Operating System
at master 412 lines 10 kB view raw
1/* 2 * Copyright (c) 2021, thislooksfun <tlf@thislooks.fun> 3 * Copyright (c) 2023, Jelle Raaijmakers <jelle@gmta.nl> 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#include <LibTest/TestCase.h> 9 10#include <AK/DeprecatedString.h> 11#include <AK/HashTable.h> 12#include <AK/NonnullOwnPtr.h> 13 14TEST_CASE(construct) 15{ 16 using IntTable = HashTable<int>; 17 EXPECT(IntTable().is_empty()); 18 EXPECT_EQ(IntTable().size(), 0u); 19} 20 21TEST_CASE(basic_move) 22{ 23 HashTable<int> foo; 24 foo.set(1); 25 EXPECT_EQ(foo.size(), 1u); 26 auto bar = move(foo); 27 EXPECT_EQ(bar.size(), 1u); 28 EXPECT_EQ(foo.size(), 0u); 29 foo = move(bar); 30 EXPECT_EQ(bar.size(), 0u); 31 EXPECT_EQ(foo.size(), 1u); 32} 33 34TEST_CASE(move_is_not_swap) 35{ 36 HashTable<int> foo; 37 foo.set(1); 38 HashTable<int> bar; 39 bar.set(2); 40 foo = move(bar); 41 EXPECT(foo.contains(2)); 42 EXPECT(!bar.contains(1)); 43 EXPECT_EQ(bar.size(), 0u); 44} 45 46TEST_CASE(populate) 47{ 48 HashTable<DeprecatedString> strings; 49 strings.set("One"); 50 strings.set("Two"); 51 strings.set("Three"); 52 53 EXPECT_EQ(strings.is_empty(), false); 54 EXPECT_EQ(strings.size(), 3u); 55} 56 57TEST_CASE(range_loop) 58{ 59 HashTable<DeprecatedString> strings; 60 EXPECT_EQ(strings.set("One"), AK::HashSetResult::InsertedNewEntry); 61 EXPECT_EQ(strings.set("Two"), AK::HashSetResult::InsertedNewEntry); 62 EXPECT_EQ(strings.set("Three"), AK::HashSetResult::InsertedNewEntry); 63 64 int loop_counter = 0; 65 for (auto& it : strings) { 66 EXPECT_EQ(it.is_null(), false); 67 ++loop_counter; 68 } 69 EXPECT_EQ(loop_counter, 3); 70} 71 72TEST_CASE(table_remove) 73{ 74 HashTable<DeprecatedString> strings; 75 EXPECT_EQ(strings.set("One"), AK::HashSetResult::InsertedNewEntry); 76 EXPECT_EQ(strings.set("Two"), AK::HashSetResult::InsertedNewEntry); 77 EXPECT_EQ(strings.set("Three"), AK::HashSetResult::InsertedNewEntry); 78 79 EXPECT_EQ(strings.remove("One"), true); 80 EXPECT_EQ(strings.size(), 2u); 81 EXPECT(strings.find("One") == strings.end()); 82 83 EXPECT_EQ(strings.remove("Three"), true); 84 EXPECT_EQ(strings.size(), 1u); 85 EXPECT(strings.find("Three") == strings.end()); 86 EXPECT(strings.find("Two") != strings.end()); 87} 88 89TEST_CASE(remove_all_matching) 90{ 91 HashTable<int> ints; 92 93 ints.set(1); 94 ints.set(2); 95 ints.set(3); 96 ints.set(4); 97 98 EXPECT_EQ(ints.size(), 4u); 99 100 EXPECT_EQ(ints.remove_all_matching([&](int value) { return value > 2; }), true); 101 EXPECT_EQ(ints.remove_all_matching([&](int) { return false; }), false); 102 103 EXPECT_EQ(ints.size(), 2u); 104 105 EXPECT(ints.contains(1)); 106 EXPECT(ints.contains(2)); 107 108 EXPECT_EQ(ints.remove_all_matching([&](int) { return true; }), true); 109 110 EXPECT(ints.is_empty()); 111 112 EXPECT_EQ(ints.remove_all_matching([&](int) { return true; }), false); 113} 114 115TEST_CASE(case_insensitive) 116{ 117 HashTable<DeprecatedString, CaseInsensitiveStringTraits> casetable; 118 EXPECT_EQ(DeprecatedString("nickserv").to_lowercase(), DeprecatedString("NickServ").to_lowercase()); 119 EXPECT_EQ(casetable.set("nickserv"), AK::HashSetResult::InsertedNewEntry); 120 EXPECT_EQ(casetable.set("NickServ"), AK::HashSetResult::ReplacedExistingEntry); 121 EXPECT_EQ(casetable.size(), 1u); 122} 123 124TEST_CASE(many_strings) 125{ 126 HashTable<DeprecatedString> strings; 127 for (int i = 0; i < 999; ++i) { 128 EXPECT_EQ(strings.set(DeprecatedString::number(i)), AK::HashSetResult::InsertedNewEntry); 129 } 130 EXPECT_EQ(strings.size(), 999u); 131 for (int i = 0; i < 999; ++i) { 132 EXPECT_EQ(strings.remove(DeprecatedString::number(i)), true); 133 } 134 EXPECT_EQ(strings.is_empty(), true); 135} 136 137TEST_CASE(many_collisions) 138{ 139 struct StringCollisionTraits : public GenericTraits<DeprecatedString> { 140 static unsigned hash(DeprecatedString const&) { return 0; } 141 }; 142 143 HashTable<DeprecatedString, StringCollisionTraits> strings; 144 for (int i = 0; i < 999; ++i) { 145 EXPECT_EQ(strings.set(DeprecatedString::number(i)), AK::HashSetResult::InsertedNewEntry); 146 } 147 148 EXPECT_EQ(strings.set("foo"), AK::HashSetResult::InsertedNewEntry); 149 EXPECT_EQ(strings.size(), 1000u); 150 151 for (int i = 0; i < 999; ++i) { 152 EXPECT_EQ(strings.remove(DeprecatedString::number(i)), true); 153 } 154 155 EXPECT(strings.find("foo") != strings.end()); 156} 157 158TEST_CASE(space_reuse) 159{ 160 struct StringCollisionTraits : public GenericTraits<DeprecatedString> { 161 static unsigned hash(DeprecatedString const&) { return 0; } 162 }; 163 164 HashTable<DeprecatedString, StringCollisionTraits> strings; 165 166 // Add a few items to allow it to do initial resizing. 167 EXPECT_EQ(strings.set("0"), AK::HashSetResult::InsertedNewEntry); 168 for (int i = 1; i < 5; ++i) { 169 EXPECT_EQ(strings.set(DeprecatedString::number(i)), AK::HashSetResult::InsertedNewEntry); 170 EXPECT_EQ(strings.remove(DeprecatedString::number(i - 1)), true); 171 } 172 173 auto capacity = strings.capacity(); 174 175 for (int i = 5; i < 999; ++i) { 176 EXPECT_EQ(strings.set(DeprecatedString::number(i)), AK::HashSetResult::InsertedNewEntry); 177 EXPECT_EQ(strings.remove(DeprecatedString::number(i - 1)), true); 178 } 179 180 EXPECT_EQ(strings.capacity(), capacity); 181} 182 183TEST_CASE(basic_remove) 184{ 185 HashTable<int> table; 186 table.set(1); 187 table.set(2); 188 table.set(3); 189 190 EXPECT_EQ(table.remove(3), true); 191 EXPECT_EQ(table.remove(3), false); 192 EXPECT_EQ(table.size(), 2u); 193 194 EXPECT_EQ(table.remove(1), true); 195 EXPECT_EQ(table.remove(1), false); 196 EXPECT_EQ(table.size(), 1u); 197 198 EXPECT_EQ(table.remove(2), true); 199 EXPECT_EQ(table.remove(2), false); 200 EXPECT_EQ(table.size(), 0u); 201} 202 203TEST_CASE(basic_contains) 204{ 205 HashTable<int> table; 206 table.set(1); 207 table.set(2); 208 table.set(3); 209 210 EXPECT_EQ(table.contains(1), true); 211 EXPECT_EQ(table.contains(2), true); 212 EXPECT_EQ(table.contains(3), true); 213 EXPECT_EQ(table.contains(4), false); 214 215 EXPECT_EQ(table.remove(3), true); 216 EXPECT_EQ(table.contains(3), false); 217 EXPECT_EQ(table.contains(1), true); 218 EXPECT_EQ(table.contains(2), true); 219 220 EXPECT_EQ(table.remove(2), true); 221 EXPECT_EQ(table.contains(2), false); 222 EXPECT_EQ(table.contains(3), false); 223 EXPECT_EQ(table.contains(1), true); 224 225 EXPECT_EQ(table.remove(1), true); 226 EXPECT_EQ(table.contains(1), false); 227} 228 229TEST_CASE(capacity_leak) 230{ 231 HashTable<int> table; 232 for (size_t i = 0; i < 10000; ++i) { 233 table.set(i); 234 table.remove(i); 235 } 236 EXPECT(table.capacity() < 100u); 237} 238 239TEST_CASE(non_trivial_type_table) 240{ 241 HashTable<NonnullOwnPtr<int>> table; 242 243 table.set(make<int>(3)); 244 table.set(make<int>(11)); 245 246 for (int i = 0; i < 1'000; ++i) { 247 table.set(make<int>(-i)); 248 } 249 for (int i = 0; i < 10'000; ++i) { 250 table.set(make<int>(i)); 251 table.remove(make<int>(i)); 252 } 253 254 EXPECT_EQ(table.remove_all_matching([&](auto&) { return true; }), true); 255 EXPECT(table.is_empty()); 256 EXPECT_EQ(table.remove_all_matching([&](auto&) { return true; }), false); 257} 258 259TEST_CASE(floats) 260{ 261 HashTable<float> table; 262 table.set(0); 263 table.set(1.0f); 264 table.set(2.0f); 265 EXPECT_EQ(table.size(), 3u); 266 EXPECT(table.contains(0)); 267 EXPECT(table.contains(1.0f)); 268 EXPECT(table.contains(2.0f)); 269} 270 271TEST_CASE(doubles) 272{ 273 HashTable<double> table; 274 table.set(0); 275 table.set(1.0); 276 table.set(2.0); 277 EXPECT_EQ(table.size(), 3u); 278 EXPECT(table.contains(0)); 279 EXPECT(table.contains(1.0)); 280 EXPECT(table.contains(2.0)); 281} 282 283TEST_CASE(reinsertion) 284{ 285 OrderedHashTable<DeprecatedString> map; 286 map.set("ytidb::LAST_RESULT_ENTRY_KEY"); 287 map.set("__sak"); 288 map.remove("__sak"); 289 map.set("__sak"); 290} 291 292TEST_CASE(clear_with_capacity_when_empty) 293{ 294 HashTable<int> map; 295 map.clear_with_capacity(); 296 map.set(0); 297 map.set(1); 298 VERIFY(map.size() == 2); 299} 300 301TEST_CASE(iterator_removal) 302{ 303 HashTable<int> map; 304 map.set(0); 305 map.set(1); 306 307 auto it = map.begin(); 308 map.remove(it); 309 EXPECT_EQ(it, map.end()); 310 EXPECT_EQ(map.size(), 1u); 311} 312 313TEST_CASE(ordered_insertion_and_deletion) 314{ 315 OrderedHashTable<int> table; 316 EXPECT_EQ(table.set(0), HashSetResult::InsertedNewEntry); 317 EXPECT_EQ(table.set(1), HashSetResult::InsertedNewEntry); 318 EXPECT_EQ(table.set(2), HashSetResult::InsertedNewEntry); 319 EXPECT_EQ(table.set(3), HashSetResult::InsertedNewEntry); 320 EXPECT_EQ(table.size(), 4u); 321 322 auto expect_table = [](OrderedHashTable<int>& table, Span<int> values) { 323 auto index = 0u; 324 for (auto it = table.begin(); it != table.end(); ++it, ++index) { 325 EXPECT_EQ(*it, values[index]); 326 EXPECT(table.contains(values[index])); 327 } 328 }; 329 330 expect_table(table, Array<int, 4> { 0, 1, 2, 3 }); 331 332 EXPECT(table.remove(0)); 333 EXPECT(table.remove(2)); 334 EXPECT(!table.remove(4)); 335 EXPECT_EQ(table.size(), 2u); 336 337 expect_table(table, Array<int, 2> { 1, 3 }); 338} 339 340TEST_CASE(ordered_deletion_and_reinsertion) 341{ 342 OrderedHashTable<int> table; 343 table.set(1); 344 table.set(3); 345 table.remove(1); 346 EXPECT_EQ(table.size(), 1u); 347 348 // By adding 1 again but this time in a different position, we 349 // test whether the bucket's neighbours are reset properly. 350 table.set(1); 351 EXPECT_EQ(table.size(), 2u); 352 353 auto it = table.begin(); 354 EXPECT_EQ(*it, 3); 355 ++it; 356 EXPECT_EQ(*it, 1); 357 ++it; 358 EXPECT_EQ(it, table.end()); 359} 360 361TEST_CASE(ordered_take_last) 362{ 363 OrderedHashTable<int> table; 364 table.set(1); 365 table.set(2); 366 table.set(3); 367 368 EXPECT_EQ(table.take_last(), 3); 369 EXPECT_EQ(table.take_last(), 2); 370 EXPECT_EQ(table.take_last(), 1); 371 EXPECT(table.is_empty()); 372} 373 374TEST_CASE(ordered_iterator_removal) 375{ 376 OrderedHashTable<int> map; 377 map.set(0); 378 map.set(1); 379 380 auto it = map.begin(); 381 map.remove(it); 382 EXPECT_EQ(it, map.end()); 383 EXPECT_EQ(map.size(), 1u); 384} 385 386TEST_CASE(ordered_remove_from_head) 387{ 388 OrderedHashTable<int> map; 389 map.set(1); 390 map.set(2); 391 map.set(3); 392 map.set(4); 393 map.set(5); 394 map.set(6); 395 396 EXPECT_EQ(map.size(), 6u); 397 398 auto it = map.begin(); 399 map.remove(it); 400 it = map.begin(); 401 map.remove(it); 402 it = map.begin(); 403 map.remove(it); 404 it = map.begin(); 405 map.remove(it); 406 it = map.begin(); 407 map.remove(it); 408 it = map.begin(); 409 map.remove(it); 410 411 EXPECT_EQ(map.size(), 0u); 412}