Browse Source

More tests for coverage

Kajetan Johannes Hammerle 2 months ago
parent
commit
6b5bd6968c

+ 7 - 1
CMakeLists.txt

@@ -22,6 +22,7 @@ set(SRC
     "src/View.cpp"
     "src/Thread.cpp"
     "src/FileReader.cpp"
+    "src/ErrorSimulator.cpp"
 )
 
 set(SRC_TESTS
@@ -57,6 +58,7 @@ set(SRC_TESTS
     "test/modules/ThreadTests.cpp"
     "test/modules/FileReaderTests.cpp"
     "test/modules/ErrorTests.cpp"
+    "test/modules/NewTests.cpp"
 )
 
 set(SRC_PERFORMANCE
@@ -163,7 +165,10 @@ target_compile_options(core PUBLIC
     -Wwrite-strings
     -Wzero-as-null-pointer-constant
 )
-target_compile_definitions(core PUBLIC CORE_LOG_LEVEL=4)
+target_compile_definitions(core 
+    PUBLIC CORE_LOG_LEVEL=4
+    PRIVATE ERROR_SIMULATOR=true
+)
 target_link_libraries(core 
     PUBLIC -nodefaultlibs c m
     PRIVATE gcov
@@ -215,6 +220,7 @@ install(TARGETS core FILE_SET HEADERS)
 
 add_executable(test ${SRC_TESTS})
 target_link_libraries(test PRIVATE core)
+target_compile_definitions(test PRIVATE ERROR_SIMULATOR=true)
 
 add_executable(performance ${SRC_PERFORMANCE})
 target_link_libraries(performance PRIVATE core)

+ 1 - 1
include/core/data/List.hpp

@@ -197,7 +197,7 @@ namespace Core {
     private:
         static Error allocate(T*& t, int n) {
             if(n <= 0) {
-                return Error::NEGATIVE_ARGUMENT;
+                return Error::NONE;
             }
             t = reinterpret_cast<T*>(
                 new AlignedType<T>[static_cast<size_t>(n)]);

+ 19 - 18
include/core/data/ProbingHashMap.hpp

@@ -184,11 +184,9 @@ namespace Core {
             if(key == emptyValue<K>()) {
                 return Error::INVALID_ARGUMENT;
             }
-            CORE_RETURN_ERROR(rehash(entries * 2 + 1));
-            int index = searchSlot(key);
-            if(index < 0) {
-                return Error::CAPACITY_REACHED;
-            } else if(keys[index] == key) {
+            int index = 0;
+            CORE_RETURN_ERROR(searchSlot(index, key));
+            if(keys[index] == key) {
                 return Error::EXISTING_KEY;
             }
             keys[index] = key;
@@ -202,11 +200,8 @@ namespace Core {
             if(key == emptyValue<K>()) {
                 return Error::INVALID_ARGUMENT;
             }
-            CORE_RETURN_ERROR(rehash(entries * 2 + 1));
-            int index = searchSlot(key);
-            if(index < 0) {
-                return Error::CAPACITY_REACHED;
-            }
+            int index = 0;
+            CORE_RETURN_ERROR(searchSlot(index, key));
             if(keys[index] == key) {
                 values[index] = Core::forward<VA>(value);
             } else {
@@ -282,16 +277,22 @@ namespace Core {
         }
 
     private:
-        int searchSlot(const K& key) const {
-            int baseHash = static_cast<int>(hashCode(key) * 514685581u);
-            int end = keys.getLength() - 1;
-            for(int i = 0; i <= end; i++) {
-                int hash = (baseHash + i) & end;
-                if(keys[hash] == emptyValue<K>() || keys[hash] == key) {
-                    return hash;
+        check_return Error searchSlot(int& slot, const K& key) {
+            int rehashFactor = 2;
+            while(true) {
+                CORE_RETURN_ERROR(rehash(entries * rehashFactor + 1));
+                int baseHash = static_cast<int>(hashCode(key) * 514685581u);
+                int end = keys.getLength() - 1;
+                // rehash on bad clustering
+                for(int i = 0; i <= 5; i++) {
+                    int hash = (baseHash + i) & end;
+                    if(keys[hash] == emptyValue<K>() || keys[hash] == key) {
+                        slot = hash;
+                        return Core::Error::NONE;
+                    }
                 }
+                rehashFactor *= 2;
             }
-            return -1;
         }
 
         template<typename Value>

+ 1 - 2
include/core/utils/ArrayString.hpp

@@ -361,6 +361,7 @@ namespace Core {
         template<unsigned int L>
         void unicodeToChar(c32 c, char (&buffer)[L]) {
             static_assert(L >= 5, "to small char buffer");
+            buffer[0] = '\0';
             if(c < (1 << 7)) {
                 buffer[0] = static_cast<char>(((c >> 0) & 0x7F) | 0x0);
                 buffer[1] = '\0';
@@ -379,8 +380,6 @@ namespace Core {
                 buffer[2] = static_cast<char>(((c >> 6) & 0x3F) | 0x80);
                 buffer[3] = static_cast<char>(((c >> 0) & 0x3F) | 0x80);
                 buffer[4] = '\0';
-            } else {
-                buffer[0] = '\0';
             }
         }
 

+ 0 - 1
include/core/utils/New.hpp

@@ -10,6 +10,5 @@ void operator delete[](void* p) noexcept;
 void operator delete(void* p, size_t bytes) noexcept;
 void operator delete[](void* p, size_t bytes) noexcept;
 void* operator new(size_t bytes, void* p) noexcept;
-// void* operator new[](size_t bytes, void* p) noexcept;
 
 #endif

+ 3 - 1
src/Clock.cpp

@@ -3,6 +3,8 @@
 #include <threads.h>
 #include <time.h>
 
+#include "ErrorSimulator.hpp"
+
 Core::Clock::Clock() : index(0), last(0), sum(0), time(0) {
 }
 
@@ -29,7 +31,7 @@ float Core::Clock::getUpdatesPerSecond() const {
 
 Core::Error Core::Clock::getNanos(Clock::Nanos& n) {
     timespec ts;
-    if(timespec_get(&ts, TIME_UTC) == 0) {
+    if(timespec_get(&ts, TIME_UTC) == 0 || CORE_TIME_GET_FAIL) {
         return Error::TIME_NOT_AVAILABLE;
     }
     n = static_cast<Clock::Nanos>(ts.tv_sec) * 1'000'000'000L +

+ 10 - 0
src/ErrorSimulator.cpp

@@ -0,0 +1,10 @@
+#include "ErrorSimulator.hpp"
+
+#ifdef ERROR_SIMULATOR
+
+bool Core::Fail::realloc = false;
+bool Core::Fail::fileClose = false;
+bool Core::Fail::timeGet = false;
+int Core::Fail::leftAllocations = -1;
+
+#endif

+ 20 - 0
src/ErrorSimulator.hpp

@@ -0,0 +1,20 @@
+#ifndef CORE_ERROR_SIMULATOR_HPP
+#define CORE_ERROR_SIMULATOR_HPP
+
+#ifdef ERROR_SIMULATOR
+namespace Core::Fail {
+    extern bool realloc;
+    extern bool fileClose;
+    extern bool timeGet;
+    extern int leftAllocations;
+}
+#define CORE_REALLOC_FAIL Core::Fail::realloc
+#define CORE_FILE_CLOSE_FAIL Core::Fail::fileClose
+#define CORE_TIME_GET_FAIL Core::Fail::timeGet
+#else
+#define CORE_REALLOC_FAIL false
+#define CORE_FILE_CLOSE_FAIL false
+#define CORE_TIME_GET_FAIL false
+#endif
+
+#endif

+ 2 - 1
src/FileReader.cpp

@@ -2,6 +2,7 @@
 
 #include <stdio.h>
 
+#include "ErrorSimulator.hpp"
 #include "core/utils/Logger.hpp"
 
 Core::FileReader::FileReader() : file(nullptr), path() {
@@ -14,7 +15,7 @@ Core::FileReader::FileReader(FileReader&& other) : FileReader() {
 Core::FileReader::~FileReader() {
     if(file != nullptr) {
         int r = fclose(static_cast<FILE*>(file));
-        if(r != 0) {
+        if(r != 0 || CORE_FILE_CLOSE_FAIL) {
             CORE_LOG_WARNING("Cannot close file #: #", path, r);
         }
         file = nullptr;

+ 17 - 6
src/New.cpp

@@ -2,11 +2,27 @@
 
 #include <stdlib.h>
 
+#include "ErrorSimulator.hpp"
+
 void* operator new(size_t bytes) noexcept {
+#ifdef ERROR_SIMULATOR
+    if(Core::Fail::leftAllocations > 0) {
+        Core::Fail::leftAllocations--;
+    } else if(Core::Fail::leftAllocations == 0) {
+        return nullptr;
+    }
+#endif
     return malloc(bytes);
 }
 
 void* operator new[](size_t bytes) noexcept {
+#ifdef ERROR_SIMULATOR
+    if(Core::Fail::leftAllocations > 0) {
+        Core::Fail::leftAllocations--;
+    } else if(Core::Fail::leftAllocations == 0) {
+        return nullptr;
+    }
+#endif
     return malloc(bytes);
 }
 
@@ -20,7 +36,7 @@ void operator delete[](void* p) noexcept {
 
 void operator delete(void* p, size_t bytes) noexcept {
     (void)bytes;
-    free(p);
+    operator delete(p);
 }
 
 void operator delete[](void* p, size_t bytes) noexcept {
@@ -32,8 +48,3 @@ void* operator new(size_t bytes, void* p) noexcept {
     (void)bytes;
     return p;
 }
-
-/*void* operator new[](size_t bytes, void* p) noexcept {
-    (void)bytes;
-    return p;
-}*/

+ 3 - 1
src/Utility.cpp

@@ -4,6 +4,8 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include "ErrorSimulator.hpp"
+
 static Core::ExitHandler exitHandler = nullptr;
 static void* exitData = nullptr;
 
@@ -75,7 +77,7 @@ Core::Error Core::reallocate(char*& p, int n) {
         return Error::NONE;
     }
     char* newP = static_cast<char*>(realloc(p, static_cast<unsigned int>(n)));
-    if(newP == nullptr) {
+    if(newP == nullptr || CORE_REALLOC_FAIL) {
         return Error::OUT_OF_MEMORY;
     }
     p = newP;

+ 9 - 1
test/Main.cpp

@@ -1,3 +1,4 @@
+#include "../src/ErrorSimulator.hpp"
 #include "Test.hpp"
 #include "Tests.hpp"
 #include "core/utils/ArrayString.hpp"
@@ -33,6 +34,7 @@ int main(int argAmount, const char**) {
     Core::testMath();
     Core::testMatrixStack(light);
     Core::testMatrix();
+    Core::testNew();
     Core::testPlane();
     Core::testProbingHashMap(light);
     Core::testQuaternion();
@@ -45,9 +47,15 @@ int main(int argAmount, const char**) {
     Core::testVector();
     Core::testView();
 
+    Core::Logger::level = Core::Logger::Level::WARNING;
+    CORE_LOG_DEBUG("You won't see this!");
+    Core::Logger::level = Core::Logger::Level::DEBUG;
+
     unsigned int data = 123456789;
     Core::setExitHandler(onExit, &data);
-    CORE_EXIT(1);
+
+    char buffer[] = {-100, 0};
+    CORE_LOG_DEBUG(buffer);
 
     return 0;
 }

+ 1 - 0
test/Tests.hpp

@@ -23,6 +23,7 @@ namespace Core {
     void testMath();
     void testMatrixStack(bool light);
     void testMatrix();
+    void testNew();
     void testPlane();
     void testProbingHashMap(bool light);
     void testQuaternion();

+ 115 - 0
test/modules/ArrayStringTests.cpp

@@ -437,6 +437,49 @@ static void testCastAppendSelf8() {
     CORE_TEST_STRING("abcabcabcabc", s);
 }
 
+static void testCompareWithShorter8() {
+    String8 s;
+    CORE_TEST_ERROR(s.append("abc"));
+    CORE_TEST_FALSE(s == "ab");
+}
+
+static void testAppendSignedChar8() {
+    const signed char buffer[] = {'a', 'b', 'c', '\0'};
+    String8 s;
+    CORE_TEST_ERROR(s.append(buffer));
+    CORE_TEST_TRUE(s == "abc");
+}
+
+static void testAppendUnsignedChar8() {
+    const unsigned char buffer[] = {'a', 'b', 'c', '\0'};
+    String8 s;
+    CORE_TEST_ERROR(s.append(buffer));
+    CORE_TEST_TRUE(s == "abc");
+}
+
+static void testAppendError8() {
+    String8 s;
+    CORE_TEST_ERROR(s.append(Core::Error::NONE));
+    CORE_TEST_TRUE(s == "NONE");
+}
+
+static void testPrint8() {
+    String8 s;
+    CORE_TEST_ERROR(s.append('\u0040'));
+    CORE_TEST_ERROR(s.append(L'\u0400'));
+    CORE_TEST_ERROR(s.append(L'\u8000'));
+    CORE_TEST_ERROR(s.append(U'\U00100000'));
+    CORE_TEST_EQUAL(build("\u0040\u0400\u8000\U00100000"), s);
+    CORE_TEST_ERROR(s.print());
+}
+
+static void testKeepHash8() {
+    String8 s;
+    CORE_TEST_ERROR(s.append("a ## test #### #####"));
+    CORE_TEST_ERROR(s.format(1, 2, 3, 4, 5, 6, 7, 8, 9));
+    CORE_TEST_STRING("a # test ## ##123456789", s);
+}
+
 static String32 build(const c32* cs) {
     String32 s;
     CORE_TEST_ERROR(s.append(cs));
@@ -875,6 +918,65 @@ static void testCastAppendSelf32() {
     CORE_TEST_STRING("abcabcabcabc", s);
 }
 
+static void testCompareWithShorter32() {
+    String32 s;
+    CORE_TEST_ERROR(s.append("abc"));
+    CORE_TEST_FALSE(s == U"ab");
+}
+
+static void testAppendSignedChar32() {
+    const signed char buffer[] = {'a', 'b', 'c', '\0'};
+    String32 s;
+    CORE_TEST_ERROR(s.append(buffer));
+    CORE_TEST_TRUE(s == U"abc");
+}
+
+static void testAppendUnsignedChar32() {
+    const unsigned char buffer[] = {'a', 'b', 'c', '\0'};
+    String32 s;
+    CORE_TEST_ERROR(s.append(buffer));
+    CORE_TEST_TRUE(s == U"abc");
+}
+
+static void testAppendError32() {
+    String32 s;
+    CORE_TEST_ERROR(s.append(Core::Error::NONE));
+    CORE_TEST_TRUE(s == U"NONE");
+}
+
+static void testPrint32() {
+    String32 s;
+    CORE_TEST_ERROR(s.append('\u0040'));
+    CORE_TEST_ERROR(s.append(L'\u0400'));
+    CORE_TEST_ERROR(s.append(L'\u8000'));
+    CORE_TEST_ERROR(s.append(U'\U00100000'));
+    CORE_TEST_EQUAL(build(U"\u0040\u0400\u8000\U00100000"), s);
+    CORE_TEST_ERROR(s.print());
+}
+
+static void testVariousUnicode32() {
+    const unsigned char buffer[] = {0xC0, 0};
+    const unsigned char buffer2[] = {0xE0, 0};
+    const unsigned char buffer3[] = {0xE0, 1, 2, 0};
+    const unsigned char buffer4[] = {0xF0, 0};
+    const unsigned char buffer5[] = {0xF0, 1, 2, 3, 0};
+    const unsigned char buffer6[] = {0xFF, 0};
+    String32 s;
+    CORE_TEST_EQUAL(Core::Error::INVALID_CHAR, s.append(buffer));
+    CORE_TEST_EQUAL(Core::Error::INVALID_CHAR, s.append(buffer2));
+    CORE_TEST_EQUAL(Core::Error::NONE, s.append(buffer3));
+    CORE_TEST_EQUAL(Core::Error::INVALID_CHAR, s.append(buffer4));
+    CORE_TEST_EQUAL(Core::Error::NONE, s.append(buffer5));
+    CORE_TEST_EQUAL(Core::Error::INVALID_CHAR, s.append(buffer6));
+}
+
+static void testKeepHash32() {
+    String32 s;
+    CORE_TEST_ERROR(s.append("a ## test #### #####"));
+    CORE_TEST_ERROR(s.format(1, 2, 3, 4, 5, 6, 7, 8, 9));
+    CORE_TEST_STRING("a # test ## ##123456789", s);
+}
+
 static void testConversion() {
     const c32* a = U"öüewfde_§$§%$ädsf";
     const char* b = "öüewfde_§$§%$ädsf";
@@ -931,6 +1033,12 @@ void Core::testArrayString() {
     testReplace8();
     testReplaceChar8();
     testCastAppendSelf8();
+    testCompareWithShorter8();
+    testAppendSignedChar8();
+    testAppendUnsignedChar8();
+    testAppendError8();
+    testPrint8();
+    testKeepHash8();
 
     testEquality32();
     testUnicodeEquality32();
@@ -969,6 +1077,13 @@ void Core::testArrayString() {
     testReplace32();
     testReplaceChar32();
     testCastAppendSelf32();
+    testCompareWithShorter32();
+    testAppendSignedChar32();
+    testAppendUnsignedChar32();
+    testAppendError32();
+    testPrint32();
+    testVariousUnicode32();
+    testKeepHash32();
 
     testConversion();
 }

+ 9 - 0
test/modules/BitArrayTests.cpp

@@ -1,3 +1,4 @@
+#include "../../src/ErrorSimulator.hpp"
 #include "../Tests.hpp"
 #include "core/data/BitArray.hpp"
 
@@ -141,6 +142,13 @@ static void testNegativeArgument() {
     CORE_TEST_EQUAL(Core::Error::NEGATIVE_ARGUMENT, bits.resize(-1, -1));
 }
 
+static void testOutOfMemory() {
+    Core::BitArray bits;
+    Core::Fail::leftAllocations = 0;
+    CORE_TEST_EQUAL(Core::Error::OUT_OF_MEMORY, bits.resize(8, 4));
+    Core::Fail::leftAllocations = -1;
+}
+
 void Core::testBitArray() {
     testSetRead();
     testOutOfBoundsSetRead();
@@ -154,4 +162,5 @@ void Core::testBitArray() {
     testResizeExact();
     testMoveAssignment();
     testNegativeArgument();
+    testOutOfMemory();
 }

+ 9 - 0
test/modules/ClockTests.cpp

@@ -1,3 +1,4 @@
+#include "../../src/ErrorSimulator.hpp"
 #include "../Tests.hpp"
 #include "core/utils/Clock.hpp"
 
@@ -36,9 +37,17 @@ static void testWait(Core::Clock::Nanos wait) {
     CORE_TEST_TRUE(n2 >= wait && n2 <= wait * 12 / 10);
 }
 
+static void testFail() {
+    Core::Clock::Nanos n = 0;
+    Core::Fail::timeGet = true;
+    CORE_TEST_EQUAL(Core::Error::TIME_NOT_AVAILABLE, Core::Clock::getNanos(n));
+    Core::Fail::timeGet = false;
+}
+
 void Core::testClock(bool light) {
     testUpdate();
     testUpdatesPerSecond();
     testWait(light ? 5'000'000 : 50'000'000);
     testWait(light ? 50'000'000 : 1'300'000'000);
+    testFail();
 }

+ 65 - 0
test/modules/ComponentsTests.cpp

@@ -1,3 +1,4 @@
+#include "../../src/ErrorSimulator.hpp"
 #include "../Tests.hpp"
 #include "core/data/Components.hpp"
 
@@ -48,6 +49,40 @@ static void testAddForEach() {
     CORE_TEST_FALSE(pos != end);
 }
 
+static void testAddConstForEach() {
+    IntComponent c;
+    int* i1 = nullptr;
+    int* i2 = nullptr;
+    int* i3 = nullptr;
+    CORE_TEST_ERROR(c.put(i1, 1, 10));
+    CORE_TEST_ERROR(c.put(i2, 5, 20));
+    CORE_TEST_ERROR(c.put(i3, 10, 30));
+
+    auto iter = static_cast<const IntComponent&>(c).entities();
+    auto pos = iter.begin();
+    auto end = iter.end();
+
+    CORE_TEST_EQUAL(1, (*pos).entity);
+    CORE_TEST_EQUAL(10, (*pos).component);
+    CORE_TEST_TRUE(pos != end);
+
+    ++pos;
+
+    CORE_TEST_EQUAL(5, (*pos).entity);
+    CORE_TEST_EQUAL(20, (*pos).component);
+    CORE_TEST_TRUE(pos != end);
+
+    ++pos;
+
+    CORE_TEST_EQUAL(10, (*pos).entity);
+    CORE_TEST_EQUAL(30, (*pos).component);
+    CORE_TEST_TRUE(pos != end);
+
+    ++pos;
+
+    CORE_TEST_FALSE(pos != end);
+}
+
 static void testAddComponentForEach() {
     IntComponent c;
     int* i1 = nullptr;
@@ -151,8 +186,38 @@ static void testRemove() {
     CORE_TEST_NULL(c.search(10));
 }
 
+static void testOutOfMemory() {
+    IntComponent c;
+    int* i1 = nullptr;
+    int memFails = 0;
+    for(int i = 0; i < 40; i++) {
+        Core::Fail::leftAllocations = 2;
+        Core::Error e = c.put(i1, 1, 10);
+        if(e == Core::Error::OUT_OF_MEMORY) {
+            memFails++;
+        }
+    }
+    Core::Fail::leftAllocations = -1;
+    CORE_TEST_TRUE(memFails > 0);
+}
+
+static void testConstSearch() {
+    IntComponent c;
+    int* i = nullptr;
+    CORE_TEST_ERROR(c.put(i, 1, 10));
+    const IntComponent& cc = c;
+    const int* component = cc.search(1);
+    if(CORE_TEST_TRUE(component != nullptr)) {
+        CORE_TEST_EQUAL(10, *component);
+    }
+    CORE_TEST_NULL(cc.search(2));
+}
+
 void Core::testComponents() {
     testAddForEach();
+    testAddConstForEach();
     testAddComponentForEach();
     testRemove();
+    testOutOfMemory();
+    testConstSearch();
 }

+ 11 - 0
test/modules/FileReaderTests.cpp

@@ -1,3 +1,4 @@
+#include "../../src/ErrorSimulator.hpp"
 #include "../Tests.hpp"
 #include "core/io/FileReader.hpp"
 
@@ -95,6 +96,15 @@ static void testInvalidAccessPath() {
     CORE_TEST_EQUAL(Core::Error::INVALID_STATE, r.open(path));
 }
 
+static void testCloseFail() {
+    Core::Fail::fileClose = true;
+    {
+        Core::FileReader r;
+        CORE_TEST_ERROR(r.open(TEST_FILE));
+    }
+    Core::Fail::fileClose = false;
+}
+
 void Core::testFileReader() {
     testReadChar();
     testReadCharPath();
@@ -104,4 +114,5 @@ void Core::testFileReader() {
     testMoveAssignment();
     testInvalidAccess();
     testInvalidAccessPath();
+    testCloseFail();
 }

+ 21 - 0
test/modules/HashMapTests.cpp

@@ -1,3 +1,4 @@
+#include "../../src/ErrorSimulator.hpp"
 #include "../Tests.hpp"
 #include "core/data/HashMap.hpp"
 
@@ -312,6 +313,25 @@ static void testTypes() {
     testType<unsigned long long>();
 }
 
+static void testOutOfMemory() {
+    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);
+}
+
 void Core::testHashMap(bool light) {
     testAdd();
     testMultipleAdd();
@@ -331,4 +351,5 @@ void Core::testHashMap(bool light) {
     testKeyForEach();
     testValueForEach();
     testTypes();
+    testOutOfMemory();
 }

+ 19 - 0
test/modules/LinkedListTests.cpp

@@ -1,3 +1,4 @@
+#include "../../src/ErrorSimulator.hpp"
 #include "../Tests.hpp"
 #include "core/data/LinkedList.hpp"
 
@@ -273,6 +274,23 @@ static void testRemoveLast() {
     CORE_TEST_EQUAL(0, list.getLength());
 }
 
+static void testOutOfMemory() {
+    IntList list;
+    int memFails = 0;
+    for(int i = 0; i < 40; i++) {
+        Core::Fail::leftAllocations = i;
+        Core::Error e = list.add(1);
+        if(e == Core::Error::OUT_OF_MEMORY) {
+            memFails++;
+        }
+    }
+    if(CORE_TEST_TRUE(list.getLength() > 0)) {
+        CORE_TEST_EQUAL(1, *list.begin());
+    }
+    Core::Fail::leftAllocations = -1;
+    CORE_TEST_TRUE(memFails > 0);
+}
+
 void Core::testLinkedList(bool light) {
     testWithoutCopyOrMove();
     testAdd();
@@ -288,4 +306,5 @@ void Core::testLinkedList(bool light) {
     testRemove();
     testRemoveFirst();
     testRemoveLast();
+    testOutOfMemory();
 }

+ 30 - 0
test/modules/ListTests.cpp

@@ -1,3 +1,4 @@
+#include "../../src/ErrorSimulator.hpp"
 #include "../Tests.hpp"
 #include "core/data/List.hpp"
 
@@ -183,6 +184,31 @@ static void testDefaultResize() {
     }
 }
 
+static void testInvalidReserve() {
+    IntList list;
+    CORE_TEST_ERROR(list.reserve(0));
+    CORE_TEST_ERROR(list.reserve(-5));
+}
+
+static void testShrinkExact() {
+    IntList list;
+    CORE_TEST_ERROR(list.resize(50));
+    CORE_TEST_ERROR(list.shrink());
+}
+
+static void testShrinkResize() {
+    IntList list;
+    CORE_TEST_ERROR(list.resize(50));
+    CORE_TEST_ERROR(list.resize(20, 5));
+    CORE_TEST_ERROR(list.resize(10));
+}
+
+static void testCopyEmpty() {
+    IntList list;
+    IntList copy;
+    CORE_TEST_ERROR(copy.copyFrom(list));
+}
+
 void Core::testList(bool light) {
     testAdd();
     testMultipleAdd();
@@ -200,4 +226,8 @@ void Core::testList(bool light) {
     testRemove();
     testResize();
     testDefaultResize();
+    testInvalidReserve();
+    testShrinkExact();
+    testShrinkResize();
+    testCopyEmpty();
 }

+ 26 - 0
test/modules/NewTests.cpp

@@ -0,0 +1,26 @@
+#include "../Tests.hpp"
+
+struct NewTestClass {
+    int i;
+};
+
+static void testNewArray() {
+    NewTestClass* n = new NewTestClass[5];
+    delete[] n;
+}
+
+static void testNewFlat() {
+    NewTestClass* n = new NewTestClass();
+    delete n;
+}
+
+static void testNewArrayWithSize() {
+    NewTestClass* n = new NewTestClass[5];
+    operator delete[](n, 5);
+}
+
+void Core::testNew() {
+    testNewArray();
+    testNewFlat();
+    testNewArrayWithSize();
+}

+ 43 - 2
test/modules/ProbingHashMapTests.cpp

@@ -1,5 +1,4 @@
-#include <stdio.h>
-
+#include "../../src/ErrorSimulator.hpp"
 #include "../Tests.hpp"
 #include "core/data/ProbingHashMap.hpp"
 
@@ -40,6 +39,10 @@ static void testMultipleAdd() {
 static void testSearch() {
     IntMap map;
     CORE_TEST_NULL(map.search(6));
+    CORE_TEST_ERROR(map.add(5, 4));
+    CORE_TEST_ERROR(map.add(10, 3));
+    CORE_TEST_ERROR(map.add(15, 2));
+    CORE_TEST_NULL(map.search(6));
 }
 
 static void testAddReplace() {
@@ -309,6 +312,41 @@ static void testTypes() {
     testType<unsigned long long>();
 }
 
+static void testOutOfMemory() {
+    IntMap map;
+    int memFails = 0;
+    for(int i = 0; i < 40; i++) {
+        Core::Fail::leftAllocations = i;
+        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);
+}
+
+static void testInsertInvalid() {
+    IntMap map;
+    int* v;
+    CORE_TEST_EQUAL(Core::Error::INVALID_ARGUMENT,
+                    map.tryEmplace(v, Core::emptyValue<int>(), 2));
+    CORE_TEST_EQUAL(Core::Error::INVALID_ARGUMENT,
+                    map.put(v, Core::emptyValue<int>(), 2));
+}
+
+static void testAddCollisions() {
+    IntMap map;
+    for(int i = 0; i < 8; i++) {
+        CORE_TEST_ERROR(map.add(i * 16, i));
+    }
+}
+
 void Core::testProbingHashMap(bool light) {
     testAdd();
     testMultipleAdd();
@@ -327,4 +365,7 @@ void Core::testProbingHashMap(bool light) {
     testKeyForEach();
     testValueForEach();
     testTypes();
+    testOutOfMemory();
+    testInsertInvalid();
+    testAddCollisions();
 }

+ 10 - 0
test/modules/UtilityTests.cpp

@@ -1,3 +1,4 @@
+#include "../../src/ErrorSimulator.hpp"
 #include "../Tests.hpp"
 #include "core/utils/Utility.hpp"
 
@@ -36,9 +37,18 @@ static void testNegativeRellocate() {
     CORE_TEST_TRUE(buffer == nullptr);
 }
 
+static void testReallocateFail() {
+    char* buffer = nullptr;
+    Core::Fail::realloc = true;
+    CORE_TEST_EQUAL(Core::Error::OUT_OF_MEMORY, Core::reallocate(buffer, 16));
+    CORE_TEST_TRUE(buffer == nullptr);
+    Core::Fail::realloc = false;
+}
+
 void Core::testUtility() {
     testPopCount();
     testIf();
     testNegativeArguments();
     testNegativeRellocate();
+    testReallocateFail();
 }