#include "../../src/ErrorSimulator.hpp" #include "../Tests.hpp" #include "core/data/HashMap.hpp" template class Core::HashMap; using IntMap = Core::HashMap; static void testAdd() { IntMap map; CORE_TEST_ERROR(map.add(5, 4)); int* value = map.search(5); if(CORE_TEST_NOT_NULL(value)) { CORE_TEST_EQUAL(4, *value); } } static void testMultipleAdd() { IntMap map; CORE_TEST_ERROR(map.add(5, 4)); CORE_TEST_ERROR(map.add(10, 3)); CORE_TEST_ERROR(map.add(15, 2)); CORE_TEST_TRUE(map.contains(5)); CORE_TEST_TRUE(map.contains(10)); CORE_TEST_TRUE(map.contains(15)); int* a = map.search(5); int* b = map.search(10); int* c = map.search(15); CORE_TEST_NOT_NULL(a); CORE_TEST_NOT_NULL(b); CORE_TEST_NOT_NULL(c); if(a != nullptr && b != nullptr && c != nullptr) { CORE_TEST_EQUAL(4, *a); CORE_TEST_EQUAL(3, *b); CORE_TEST_EQUAL(2, *c); } } static void testSearch() { IntMap map; CORE_TEST_NULL(map.search(6)); } static void testAddReplace() { IntMap map; CORE_TEST_ERROR(map.add(5, 4)); CORE_TEST_ERROR(map.add(5, 10)); CORE_TEST_TRUE(map.contains(5)); int* a = map.search(5); if(CORE_TEST_NOT_NULL(a)) { CORE_TEST_EQUAL(10, *a); } } static void testClear() { IntMap map; CORE_TEST_ERROR(map.add(5, 4)); CORE_TEST_ERROR(map.add(4, 10)); map.clear(); CORE_TEST_FALSE(map.contains(5)); CORE_TEST_FALSE(map.contains(4)); } static void testOverflow(bool light) { IntMap map; int limit = light ? 10000 : 100000; for(int i = 0; i < limit; i++) { CORE_TEST_ERROR(map.add(i, i)); } for(int i = 0; i < limit; i++) { CORE_TEST_TRUE(map.contains(i)); } } struct HashMapTestStruct final { int a; int b; HashMapTestStruct(int a_, int b_) : a(a_), b(b_) { } // none of these should be needed for the hashmap HashMapTestStruct(const HashMapTestStruct&) = delete; HashMapTestStruct(HashMapTestStruct&&) = delete; HashMapTestStruct& operator=(const HashMapTestStruct&) = delete; HashMapTestStruct& operator=(HashMapTestStruct&&) = delete; bool operator==(const HashMapTestStruct& other) const { return a == other.a && b == other.b; } template check_return Core::Error toString(String& s) const { CORE_RETURN_ERROR(s.append("A(")); CORE_RETURN_ERROR(s.append(a)); CORE_RETURN_ERROR(s.append(", ")); CORE_RETURN_ERROR(s.append(b)); CORE_RETURN_ERROR(s.append(")")); return Core::Error::NONE; } }; static void testEmplace() { Core::HashMap map; HashMapTestStruct* ar = nullptr; CORE_TEST_ERROR(map.tryEmplace(ar, 0, 3, 4)); CORE_TEST_ERROR(map.tryEmplace(ar, 3, 4, 5)); CORE_TEST_ERROR(map.tryEmplace(ar, 20, 5, 6)); CORE_TEST_EQUAL(Core::Error::EXISTING_KEY, map.tryEmplace(ar, 3, 6, 7)); CORE_TEST_EQUAL(Core::Error::EXISTING_KEY, map.tryEmplace(ar, 20, 7, 8)); HashMapTestStruct* a = map.search(0); HashMapTestStruct* b = map.search(3); HashMapTestStruct* c = map.search(20); CORE_TEST_NOT_NULL(a); CORE_TEST_NOT_NULL(b); CORE_TEST_NOT_NULL(c); if(a != nullptr && b != nullptr && c != nullptr) { CORE_TEST_EQUAL(HashMapTestStruct(3, 4), *a); CORE_TEST_EQUAL(HashMapTestStruct(4, 5), *b); CORE_TEST_EQUAL(HashMapTestStruct(5, 6), *c); } } static void testToString1() { IntMap map; CORE_TEST_ERROR(map.add(1, 3)); CORE_TEST_ERROR(map.add(2, 4)); CORE_TEST_ERROR(map.add(3, 5)); CORE_TEST_STRING("[1 = 3, 2 = 4, 3 = 5]", map); } static void testToString2() { IntMap map; CORE_TEST_ERROR(map.add(1, 3)); CORE_TEST_STRING("[1 = 3]", map); } static void testToString3() { IntMap map; CORE_TEST_STRING("[]", map); } static void testCopy() { IntMap map; CORE_TEST_ERROR(map.add(1, 3)); CORE_TEST_ERROR(map.add(2, 4)); CORE_TEST_ERROR(map.add(3, 5)); IntMap copy; CORE_TEST_ERROR(copy.copyFrom(map)); int* a[6] = {map.search(1), map.search(2), map.search(3), copy.search(1), copy.search(2), copy.search(3)}; for(int i = 0; i < 3; i++) { CORE_TEST_NOT_NULL(a[i]); CORE_TEST_NOT_NULL(a[i + 3]); if(a[i] != nullptr && a[i + 3] != nullptr) { CORE_TEST_EQUAL(*(a[i]), *(a[i + 3])); } } } static void testMove() { IntMap map; CORE_TEST_ERROR(map.add(1, 3)); CORE_TEST_ERROR(map.add(2, 4)); CORE_TEST_ERROR(map.add(3, 5)); IntMap move(Core::move(map)); int* a = move.search(1); int* b = move.search(2); int* c = move.search(3); CORE_TEST_NOT_NULL(a); CORE_TEST_NOT_NULL(b); CORE_TEST_NOT_NULL(c); if(a != nullptr && b != nullptr && c != nullptr) { CORE_TEST_EQUAL(3, *a); CORE_TEST_EQUAL(4, *b); CORE_TEST_EQUAL(5, *c); } } static void testMoveAssignment() { IntMap map; CORE_TEST_ERROR(map.add(1, 3)); CORE_TEST_ERROR(map.add(2, 4)); CORE_TEST_ERROR(map.add(3, 5)); IntMap move; move = Core::move(map); int* a = move.search(1); int* b = move.search(2); int* c = move.search(3); CORE_TEST_NOT_NULL(a); CORE_TEST_NOT_NULL(b); CORE_TEST_NOT_NULL(c); if(a != nullptr && b != nullptr && c != nullptr) { CORE_TEST_EQUAL(3, *a); CORE_TEST_EQUAL(4, *b); CORE_TEST_EQUAL(5, *c); } } static void testRemove() { IntMap map; CORE_TEST_ERROR(map.add(1, 3)); CORE_TEST_ERROR(map.add(2, 4)); CORE_TEST_ERROR(map.add(3, 5)); CORE_TEST_ERROR(map.remove(2)); CORE_TEST_EQUAL(Core::Error::NOT_FOUND, map.remove(7)); int* a = map.search(1); int* b = map.search(2); int* c = map.search(3); CORE_TEST_NOT_NULL(a); CORE_TEST_NULL(b); CORE_TEST_NOT_NULL(c); if(a != nullptr && c != nullptr) { CORE_TEST_EQUAL(3, *a); CORE_TEST_EQUAL(5, *c); } } static void testEntryForEach() { IntMap map; CORE_TEST_ERROR(map.add(5, 4)); CORE_TEST_ERROR(map.add(10, 3)); CORE_TEST_ERROR(map.add(15, 2)); int counter = 0; for(auto& entry : map) { counter += entry.getKey() + entry.value; } CORE_TEST_EQUAL(39, counter); const IntMap& cmap = map; counter = 0; for(const auto& entry : cmap) { counter += entry.getKey() + entry.value; } CORE_TEST_EQUAL(39, counter); } static void testKeyForEach() { IntMap map; CORE_TEST_ERROR(map.add(5, 4)); CORE_TEST_ERROR(map.add(10, 3)); CORE_TEST_ERROR(map.add(15, 2)); int counter = 0; for(const int& key : map.getKeys()) { counter += key; } CORE_TEST_EQUAL(30, counter); const IntMap& cmap = map; counter = 0; for(const int& key : cmap.getKeys()) { counter += key; } CORE_TEST_EQUAL(30, counter); } static void testValueForEach() { IntMap map; CORE_TEST_ERROR(map.add(5, 4)); CORE_TEST_ERROR(map.add(10, 3)); CORE_TEST_ERROR(map.add(15, 2)); int counter = 0; for(int& value : map.getValues()) { counter += value; } CORE_TEST_EQUAL(9, counter); const IntMap& cmap = map; counter = 0; for(const int& value : cmap.getValues()) { counter += value; } CORE_TEST_EQUAL(9, counter); } template static void testType() { Core::HashMap m; CORE_TEST_ERROR(m.add(T(), 3)); } static void testTypes() { testType(); testType(); testType(); testType(); testType(); testType(); testType(); testType(); testType(); testType(); testType(); } static void testOutOfMemory() { #ifdef ERROR_SIMULATOR IntMap map; int memFails = 0; for(int i = 0; i < 40; i++) { Core::Fail::leftAllocations = 2; int* v = nullptr; Core::Error e = map.put(v, 1, 1); if(e == Core::Error::OUT_OF_MEMORY) { memFails++; } } int* found = map.search(1); if(CORE_TEST_NOT_NULL(found)) { CORE_TEST_EQUAL(1, *found); } Core::Fail::leftAllocations = -1; CORE_TEST_TRUE(memFails != 0); #endif } void Core::testHashMap(bool light, bool outOfMemoryTest) { testAdd(); testMultipleAdd(); testSearch(); testAddReplace(); testClear(); testOverflow(light); testEmplace(); testToString1(); testToString2(); testToString3(); testCopy(); testMove(); testMoveAssignment(); testRemove(); testEntryForEach(); testKeyForEach(); testValueForEach(); testTypes(); if(outOfMemoryTest) { testOutOfMemory(); } }