Browse Source

New test system with more convenient source logging, ring buffer wip

Kajetan Johannes Hammerle 1 year ago
parent
commit
d771bd002e

+ 4 - 5
data/ArrayList.h

@@ -65,14 +65,13 @@ namespace Core {
             return begin() + length;
         }
 
-        // returns true on error
+        // returns a nullptr on error
         template<typename... Args>
-        check_return bool add(Args&&... args) {
+        check_return T* add(Args&&... args) {
             if(length >= N) {
-                return true;
+                return nullptr;
             }
-            new(begin() + length++) T(Core::forward<Args>(args)...);
-            return false;
+            return new(begin() + length++) T(Core::forward<Args>(args)...);
         }
 
         T& operator[](int index) {

+ 1 - 1
data/BitArray.cpp

@@ -101,7 +101,7 @@ int Core::BitArray::getInternalByteSize() const {
     if(bits <= 0 || length <= 0) {
         return 0;
     }
-    return getArrayLength(length, bits) * CoreSize(int);
+    return getArrayLength(length, bits) * CORE_SIZE(int);
 }
 
 int Core::BitArray::select(int index) const {

+ 25 - 23
data/HashMap.h

@@ -28,6 +28,8 @@ namespace Core {
                 : key(key_), value(Core::forward<Args>(args)...) {
             }
         };
+
+    private:
         using NodePointer = LinkedList<Node>::Node*;
         using NodePointerList = List<NodePointer>;
         using NodeIterator = LinkedList<Node>::Iterator;
@@ -117,7 +119,7 @@ namespace Core {
         check_return bool copyFrom(const HashMap& other) {
             HashMap copy;
             for(const auto& e : other) {
-                if(copy.add(e.getKey(), e.value)) {
+                if(copy.add(e.getKey(), e.value) == nullptr) {
                     return true;
                 }
             }
@@ -139,7 +141,7 @@ namespace Core {
             for(NodePointerList& list : nodePointers) {
                 for(NodePointer& n : list) {
                     int h = map.hashIndex(n->data.key);
-                    if(map.nodePointers[h].add(n)) {
+                    if(map.nodePointers[h].add(n) == nullptr) {
                         return true;
                     }
                 }
@@ -148,47 +150,47 @@ namespace Core {
             return false;
         }
 
-        // returns true on error
+        // returns a nullptr on error
         template<typename... Args>
-        check_return bool tryEmplace(const K& key, Args&&... args) {
+        check_return V* tryEmplace(const K& key, Args&&... args) {
             if(rehash(nodes.getLength() + 1)) {
-                return true;
+                return nullptr;
             }
             int h = hashIndex(key);
             V* v = searchList(key, h);
             if(v != nullptr) {
-                return true;
+                return nullptr;
             }
             NodePointer np = nodes.add(key, Core::forward<Args>(args)...);
             if(np == nullptr) {
-                return true;
-            } else if(nodePointers[h].add(np)) {
+                return nullptr;
+            } else if(nodePointers[h].add(np) == nullptr) {
                 nodes.remove(np);
-                return true;
+                return nullptr;
             }
-            return false;
+            return &(np->data.value);
         }
 
-        // returns true on error
+        // returns a nullptr on error
         template<typename VA>
-        check_return bool add(const K& key, VA&& value) {
+        check_return V* add(const K& key, VA&& value) {
             if(rehash(nodes.getLength() + 1)) {
-                return true;
+                return nullptr;
             }
             int h = hashIndex(key);
             V* v = searchList(key, h);
-            if(v == nullptr) {
-                NodePointer np = nodes.add(key, Core::forward<VA>(value));
-                if(np == nullptr) {
-                    return true;
-                } else if(nodePointers[h].add(np)) {
-                    nodes.remove(np);
-                    return true;
-                }
-            } else {
+            if(v != nullptr) {
                 *v = Core::forward<VA>(value);
+                return v;
             }
-            return false;
+            NodePointer np = nodes.add(key, Core::forward<VA>(value));
+            if(np == nullptr) {
+                return nullptr;
+            } else if(nodePointers[h].add(np) == nullptr) {
+                nodes.remove(np);
+                return nullptr;
+            }
+            return &(np->data.value);
         }
 
         // returns true when a value was removed

+ 6 - 7
data/List.h

@@ -135,14 +135,13 @@ namespace Core {
             return false;
         }
 
-        // returns true on error
+        // returns a nullptr on error
         template<typename... Args>
-        check_return bool add(Args&&... args) {
+        check_return T* add(Args&&... args) {
             if(ensureCapacity()) {
-                return true;
+                return nullptr;
             }
-            unsafeAdd(Core::forward<Args>(args)...);
-            return false;
+            return unsafeAdd(Core::forward<Args>(args)...);
         }
 
         T& operator[](int index) {
@@ -239,8 +238,8 @@ namespace Core {
 
         // does not check for capacity
         template<typename... Args>
-        void unsafeAdd(Args&&... args) {
-            new(data + length++) T(Core::forward<Args>(args)...);
+        T* unsafeAdd(Args&&... args) {
+            return new(data + length++) T(Core::forward<Args>(args)...);
         }
     };
 }

+ 58 - 0
data/RingBuffer.h

@@ -0,0 +1,58 @@
+#ifndef CORE_RINGBUFFER_H
+#define CORE_RINGBUFFER_H
+
+#include "data/Array.h"
+
+namespace Core {
+    template<typename T, int N>
+    class RingBuffer final {
+        Array<T, N> data;
+        int writeIndex = 0;
+        int readIndex = 0;
+        int values = 0;
+
+    public:
+        bool add(const T& t) {
+            if(values >= N) {
+                return true;
+            }
+            data[writeIndex] = t;
+            writeIndex = (writeIndex + 1) % N;
+            values++;
+            return false;
+        }
+
+        int getLength() const {
+            return values;
+        }
+
+        bool canRemove() const {
+            return values > 0;
+        }
+
+        bool remove() {
+            if(values <= 0) {
+                return true;
+            }
+            values--;
+            readIndex = (readIndex + 1) % N;
+            return false;
+        }
+
+        T& operator[](int index) {
+            return data[(index + readIndex) % N];
+        }
+
+        const T& operator[](int index) const {
+            return data[(index + readIndex) % N];
+        }
+
+        void clear() {
+            writeIndex = 0;
+            readIndex = 0;
+            values = 0;
+        }
+    };
+}
+
+#endif

+ 2 - 2
data/Stack.h

@@ -11,9 +11,9 @@ namespace Core {
             S data;
 
         public:
-            // returns true on error
+            // returns a nullptr on error
             template<typename... Args>
-            check_return bool push(Args&&... args) {
+            check_return T* push(Args&&... args) {
                 return data.add(Core::forward<Args>(args)...);
             }
 

+ 1 - 0
meson.build

@@ -21,6 +21,7 @@ src_tests = [
     'tests/UniquePointerTests.cpp',
     'tests/HashMapTests.cpp',
     'tests/StackTests.cpp',
+    'tests/RingBufferTests.cpp',
 ]
 
 compiler = meson.get_compiler('cpp')

+ 5 - 0
test/Main.cpp

@@ -1,5 +1,6 @@
 #include <stdio.h>
 
+#include "test/Test.h"
 #include "tests/ArrayListTests.h"
 #include "tests/ArrayStringTests.h"
 #include "tests/ArrayTests.h"
@@ -8,6 +9,7 @@
 #include "tests/LinkedListTests.h"
 #include "tests/ListTests.h"
 #include "tests/MathTests.h"
+#include "tests/RingBufferTests.h"
 #include "tests/StackTests.h"
 #include "tests/UniquePointerTests.h"
 #include "tests/UtilityTests.h"
@@ -27,10 +29,13 @@ int main() {
     Core::LinkedListTests::test();
     Core::ListTests::test();
     Core::MathTests::test();
+    Core::RingBufferTests::test();
     Core::StackTests::test();
     Core::UniquePointerTests::test();
     Core::UtilityTests::test();
 
+    Core::Test::finalize();
+
     unsigned int data = 0x1234;
     Core::setExitHandler(onExit, &data);
     Core::exitWithHandler(0);

+ 32 - 28
test/Test.cpp

@@ -1,40 +1,44 @@
 #include "test/Test.h"
 
-Core::Test::Test(const char* name_) : tests(0), successTests(0), name(name_) {
-}
+Core::HashMap<Core::Test::Internal::FileName, Core::Test::Internal::Result>
+    Core::Test::Internal::results;
 
-void Core::Test::finalize() {
-    if(successTests == tests) {
-        CORE_LOG_DEBUG("# Tests: # / # succeeded", name, successTests, tests);
-    } else {
-        CORE_LOG_ERROR("# Tests: # / # succeeded", name, successTests, tests);
+void Core::Test::Internal::checkFloat(const char* file, int line, float wanted,
+                                      float actual, float error) {
+    FileName fileName;
+    if(fileName.append(file)) {
+        CORE_LOG_WARNING("cannot append file name: #", file);
+        return;
     }
-    tests = 0;
-    successTests = 0;
-}
-
-void Core::Test::checkEqual(float wanted, float actual, const char* text) {
-    checkFloat(wanted, actual, 0.0000001f, text);
-}
-
-void Core::Test::checkFloat(float wanted, float actual, float error,
-                            const char* text) {
-    tests++;
+    Result* result = results.search(fileName);
+    if(result == nullptr) {
+        result = results.add(fileName, Result());
+        if(result == nullptr) {
+            CORE_LOG_WARNING("cannot add test result for #", file);
+            return;
+        }
+    }
+    result->tests++;
     float diff = wanted - actual;
     diff = diff < 0.0f ? -diff : diff;
     if(diff < error) {
-        successTests++;
+        result->successTests++;
     } else {
-        (void)text;
-        CORE_LOG_ERROR("# Test #: # - expected '#' got '#'", name, tests, text,
-                       wanted, actual)
+        CORE_LOG_ERROR("#:# - expected '#' got '#'", fileName, line, wanted,
+                       actual)
     }
 }
 
-void Core::Test::checkTrue(bool actual, const char* text) {
-    checkEqual(true, actual, text);
-}
-
-void Core::Test::checkFalse(bool actual, const char* text) {
-    checkEqual(false, actual, text);
+void Core::Test::finalize() {
+    using namespace Internal;
+    for(const auto& e : results) {
+        if(e.value.successTests == e.value.tests) {
+            CORE_LOG_DEBUG("# - # / # tests succeeded", e.getKey(),
+                           e.value.successTests, e.value.tests);
+        } else {
+            CORE_LOG_ERROR("# - # / # tests succeeded", e.getKey(),
+                           e.value.successTests, e.value.tests);
+        }
+    }
+    results.clear();
 }

+ 42 - 21
test/Test.h

@@ -1,36 +1,57 @@
 #ifndef CORE_TEST_H
 #define CORE_TEST_H
 
+#include "data/HashMap.h"
 #include "utils/Logger.h"
 
-namespace Core {
-    class Test final {
-        int tests;
-        int successTests;
-        const char* name;
-
-    public:
-        Test(const char* name);
-        void finalize();
+namespace Core::Test {
+    namespace Internal {
+        struct Result {
+            int tests = 0;
+            int successTests = 0;
+        };
+        using FileName = ArrayString<256>;
+        extern HashMap<FileName, Result> results;
 
         template<typename T>
-        void checkEqual(const T& wanted, const T& actual, const char* text) {
-            tests++;
+        void checkEqual(const char* file, int line, const T& wanted,
+                        const T& actual) {
+            FileName fileName;
+            if(fileName.append(file)) {
+                CORE_LOG_WARNING("cannot append file name: #", file);
+                return;
+            }
+            Result* result = results.search(fileName);
+            if(result == nullptr) {
+                result = results.tryEmplace(fileName);
+                if(result == nullptr) {
+                    CORE_LOG_WARNING("cannot add test result for #", file);
+                    return;
+                }
+            }
+            result->tests++;
             if(wanted == actual) {
-                successTests++;
+                result->successTests++;
             } else {
-                (void)text;
-                CORE_LOG_ERROR("# Test #: # - expected '#' got '#'", name,
-                               tests, text, wanted, actual)
+                CORE_LOG_ERROR("#:# - expected '#' got '#'", fileName, line,
+                               wanted, actual)
             }
         }
 
-        void checkEqual(float wanted, float actual, const char* text);
-        void checkFloat(float wanted, float actual, float error,
-                        const char* text);
-        void checkTrue(bool actual, const char* text);
-        void checkFalse(bool actual, const char* text);
-    };
+        void checkFloat(const char* file, int line, float wanted, float actual,
+                        float error);
+    }
+    void finalize();
 }
 
+#define CORE_TEST_EQUAL(wanted, actual)                                        \
+    Core::Test::Internal::checkEqual<Core::RemoveReference<decltype(actual)>>( \
+        __FILE__, __LINE__, wanted, actual);
+#define CORE_TEST_FALSE(actual) CORE_TEST_EQUAL(false, actual);
+#define CORE_TEST_TRUE(actual) CORE_TEST_EQUAL(true, actual);
+#define CORE_TEST_NULL(actual) CORE_TEST_EQUAL(true, actual == nullptr);
+#define CORE_TEST_NOT_NULL(actual) CORE_TEST_EQUAL(true, actual != nullptr);
+#define CORE_TEST_FLOAT(wanted, actual, error)                                 \
+    Core::Test::Internal::checkFloat(__FILE__, __LINE__, wanted, actual, error);
+
 #endif

+ 92 - 96
tests/ArrayListTests.cpp

@@ -7,166 +7,162 @@ using IntList = Core::ArrayList<int, 20>;
 using String = Core::ArrayString<128>;
 
 template<typename T>
-static String build(Core::Test& test, const T& t) {
+static String build(const T& t) {
     String s;
-    test.checkFalse(s.append(t), "append works");
+    CORE_TEST_FALSE(s.append(t));
     return s;
 }
 
-static void testAdd(Core::Test& test) {
+static void testAdd() {
     IntList list;
-    test.checkFalse(list.add(5), "add works 1");
+    CORE_TEST_NOT_NULL(list.add(5));
 
-    test.checkEqual(5, list[0], "contains added value");
-    test.checkEqual(1, list.getLength(), "sizes is increased by add");
+    CORE_TEST_EQUAL(5, list[0]);
+    CORE_TEST_EQUAL(1, list.getLength());
 }
 
-static void testMultipleAdd(Core::Test& test) {
+static void testMultipleAdd() {
     IntList list;
-    test.checkFalse(list.add(4), "add works 2");
-    test.checkFalse(list.add(3), "add works 3");
-    test.checkFalse(list.add(2), "add works 4");
-    test.checkEqual(4, list[0], "contains added value 1");
-    test.checkEqual(3, list[1], "contains added value 2");
-    test.checkEqual(2, list[2], "contains added value 3");
-    test.checkEqual(3, list.getLength(), "sizes is increased by add");
+    CORE_TEST_NOT_NULL(list.add(4));
+    CORE_TEST_NOT_NULL(list.add(3));
+    CORE_TEST_NOT_NULL(list.add(2));
+    CORE_TEST_EQUAL(4, list[0]);
+    CORE_TEST_EQUAL(3, list[1]);
+    CORE_TEST_EQUAL(2, list[2]);
+    CORE_TEST_EQUAL(3, list.getLength());
 }
 
-static void testAddReplace(Core::Test& test) {
+static void testAddReplace() {
     IntList list;
-    test.checkFalse(list.add(5), "add works 5");
+    CORE_TEST_NOT_NULL(list.add(5));
     list[0] = 3;
-    test.checkEqual(3, list[0], "value is overwritten");
+    CORE_TEST_EQUAL(3, list[0]);
 }
 
-static void testClear(Core::Test& test) {
+static void testClear() {
     IntList list;
-    test.checkFalse(list.add(5), "add works 6");
-    test.checkFalse(list.add(4), "add works 7");
+    CORE_TEST_NOT_NULL(list.add(5));
+    CORE_TEST_NOT_NULL(list.add(4));
     list.clear();
-    test.checkEqual(0, list.getLength(), "length is 0 after clear");
+    CORE_TEST_EQUAL(0, list.getLength());
 }
 
-static void testOverflow(Core::Test& test) {
+static void testOverflow() {
     IntList list;
     for(int i = 0; i < 20; i++) {
-        test.checkFalse(list.add(i), "add returns false without overflow");
+        CORE_TEST_NOT_NULL(list.add(i));
     }
-    for(int i = 0; i < 1000000; i++) {
-        test.checkTrue(list.add(i), "add returns true with overflow");
+    for(int i = 0; i < 100000; i++) {
+        CORE_TEST_NULL(list.add(i));
     }
     for(int i = 0; i < list.getLength(); i++) {
-        test.checkEqual(i, list[i], "still contains values after overflow");
+        CORE_TEST_EQUAL(i, list[i]);
     }
 }
 
-static void testCopy(Core::Test& test) {
+static void testCopy() {
     IntList list;
-    test.checkFalse(list.add(1), "add works 8");
-    test.checkFalse(list.add(2), "add works 9");
-    test.checkFalse(list.add(3), "add works 10");
+    CORE_TEST_NOT_NULL(list.add(1));
+    CORE_TEST_NOT_NULL(list.add(2));
+    CORE_TEST_NOT_NULL(list.add(3));
 
     IntList copy(list);
-    test.checkEqual(list.getLength(), copy.getLength(), "copy has same length");
+    CORE_TEST_EQUAL(list.getLength(), copy.getLength());
     for(int i = 0; i < copy.getLength() && i < list.getLength(); i++) {
-        test.checkEqual(list[i], copy[i], "copy has same values");
+        CORE_TEST_EQUAL(list[i], copy[i]);
     }
 }
 
-static void testCopyAssignment(Core::Test& test) {
+static void testCopyAssignment() {
     IntList list;
-    test.checkFalse(list.add(1), "add works 11");
-    test.checkFalse(list.add(2), "add works 12");
-    test.checkFalse(list.add(3), "add works 13");
+    CORE_TEST_NOT_NULL(list.add(1));
+    CORE_TEST_NOT_NULL(list.add(2));
+    CORE_TEST_NOT_NULL(list.add(3));
 
     IntList copy;
     copy = list;
-    test.checkEqual(list.getLength(), copy.getLength(),
-                    "copy assignment has same length");
+    CORE_TEST_EQUAL(list.getLength(), copy.getLength());
     for(int i = 0; i < copy.getLength() && i < list.getLength(); i++) {
-        test.checkEqual(list[i], copy[i], "copy assignment has same values");
+        CORE_TEST_EQUAL(list[i], copy[i]);
     }
 }
 
-static void testMove(Core::Test& test) {
+static void testMove() {
     IntList list;
-    test.checkFalse(list.add(1), "add works 14");
-    test.checkFalse(list.add(2), "add works 15");
-    test.checkFalse(list.add(3), "add works 16");
+    CORE_TEST_NOT_NULL(list.add(1));
+    CORE_TEST_NOT_NULL(list.add(2));
+    CORE_TEST_NOT_NULL(list.add(3));
 
     IntList move(Core::move(list));
-    test.checkEqual(0, list.getLength(), "moved has length 0");
-    test.checkEqual(3, move.getLength(), "moved passes length");
-    test.checkEqual(1, move[0], "moved passes values");
-    test.checkEqual(2, move[1], "moved passes values");
-    test.checkEqual(3, move[2], "moved passes values");
+    CORE_TEST_EQUAL(0, list.getLength());
+    CORE_TEST_EQUAL(3, move.getLength());
+    CORE_TEST_EQUAL(1, move[0]);
+    CORE_TEST_EQUAL(2, move[1]);
+    CORE_TEST_EQUAL(3, move[2]);
 }
 
-static void testMoveAssignment(Core::Test& test) {
+static void testMoveAssignment() {
     IntList list;
-    test.checkFalse(list.add(1), "add works 17");
-    test.checkFalse(list.add(2), "add works 18");
-    test.checkFalse(list.add(3), "add works 19");
+    CORE_TEST_NOT_NULL(list.add(1));
+    CORE_TEST_NOT_NULL(list.add(2));
+    CORE_TEST_NOT_NULL(list.add(3));
 
     IntList move;
     move = Core::move(list);
-    test.checkEqual(0, list.getLength(), "assignment moved has length 0");
-    test.checkEqual(3, move.getLength(), "assignment moved passes length");
-    test.checkEqual(1, move[0], "assignment moved passes values");
-    test.checkEqual(2, move[1], "assignment moved passes values");
-    test.checkEqual(3, move[2], "assignment moved passes values");
+    CORE_TEST_EQUAL(0, list.getLength());
+    CORE_TEST_EQUAL(3, move.getLength());
+    CORE_TEST_EQUAL(1, move[0]);
+    CORE_TEST_EQUAL(2, move[1]);
+    CORE_TEST_EQUAL(3, move[2]);
 }
 
-static void testToString1(Core::Test& test) {
+static void testToString1() {
     IntList list;
-    test.checkFalse(list.add(1), "add works 20");
-    test.checkFalse(list.add(243), "add works 21");
-    test.checkFalse(list.add(-423), "add works 22");
-    test.checkEqual(build(test, "[1, 243, -423]"), build(test, list),
-                    "to string 1");
+    CORE_TEST_NOT_NULL(list.add(1));
+    CORE_TEST_NOT_NULL(list.add(243));
+    CORE_TEST_NOT_NULL(list.add(-423));
+    CORE_TEST_EQUAL(build("[1, 243, -423]"), build(list));
 }
 
-static void testToString2(Core::Test& test) {
+static void testToString2() {
     IntList list;
-    test.checkFalse(list.add(1), "add works 23");
-    test.checkEqual(build(test, "[1]"), build(test, list), "to string 2");
+    CORE_TEST_NOT_NULL(list.add(1));
+    CORE_TEST_EQUAL(build("[1]"), build(list));
 }
 
-static void testToString3(Core::Test& test) {
+static void testToString3() {
     IntList list;
-    test.checkEqual(build(test, "[]"), build(test, list), "to string 3");
+    CORE_TEST_EQUAL(build("[]"), build(list));
 }
 
-static void testRemove(Core::Test& test) {
+static void testRemove() {
     IntList list;
-    test.checkFalse(list.add(4), "add works 24");
-    test.checkFalse(list.add(3), "add works 25");
-    test.checkFalse(list.add(2), "add works 26");
-    test.checkFalse(list.removeBySwap(0), "remove by swap works 1");
-    test.checkEqual(2, list[0], "remove by swap 1");
-    test.checkEqual(3, list[1], "remove by swap 2");
-    test.checkEqual(2, list.getLength(), "remove by swap 3");
-    test.checkFalse(list.removeBySwap(1), "remove by swap works 2");
-    test.checkEqual(2, list[0], "remove by swap 4");
-    test.checkEqual(1, list.getLength(), "remove by swap 5");
-    test.checkFalse(list.removeBySwap(0), "remove by swap works 3");
-    test.checkEqual(0, list.getLength(), "remove by swap 6");
+    CORE_TEST_NOT_NULL(list.add(4));
+    CORE_TEST_NOT_NULL(list.add(3));
+    CORE_TEST_NOT_NULL(list.add(2));
+    CORE_TEST_FALSE(list.removeBySwap(0));
+    CORE_TEST_EQUAL(2, list[0]);
+    CORE_TEST_EQUAL(3, list[1]);
+    CORE_TEST_EQUAL(2, list.getLength());
+    CORE_TEST_FALSE(list.removeBySwap(1));
+    CORE_TEST_EQUAL(2, list[0]);
+    CORE_TEST_EQUAL(1, list.getLength());
+    CORE_TEST_FALSE(list.removeBySwap(0));
+    CORE_TEST_EQUAL(0, list.getLength());
 }
 
 void Core::ArrayListTests::test() {
-    Core::Test test("ArrayList");
-    testAdd(test);
-    testMultipleAdd(test);
-    testAddReplace(test);
-    testClear(test);
-    testOverflow(test);
-    testCopy(test);
-    testCopyAssignment(test);
-    testMove(test);
-    testMoveAssignment(test);
-    testToString1(test);
-    testToString2(test);
-    testToString3(test);
-    testRemove(test);
-    test.finalize();
+    testAdd();
+    testMultipleAdd();
+    testAddReplace();
+    testClear();
+    testOverflow();
+    testCopy();
+    testCopyAssignment();
+    testMove();
+    testMoveAssignment();
+    testToString1();
+    testToString2();
+    testToString3();
+    testRemove();
 }

+ 178 - 189
tests/ArrayStringTests.cpp

@@ -6,301 +6,290 @@
 
 using String = Core::ArrayString<128>;
 
-static String build(Core::Test& test, const char* cs) {
+static String build(const char* cs) {
     String s;
-    test.checkFalse(s.append(cs), "append works");
+    CORE_TEST_FALSE(s.append(cs));
     return s;
 }
 
-static void testEquality(Core::Test& test) {
-    String s = build(test, "test");
-    test.checkTrue(s == "test", "equality with c-string");
-    test.checkTrue(s == build(test, "test"), "equality with another string");
-    test.checkTrue("test" == s, "inverse equality with c-string");
-    test.checkTrue(build(test, "test") == s,
-                   "inverse equality with another string");
-    test.checkTrue(s == s, "equality with itself");
+static void testEquality() {
+    String s = build("test");
+    CORE_TEST_TRUE(s == "test");
+    CORE_TEST_TRUE(s == build("test"));
+    CORE_TEST_TRUE("test" == s);
+    CORE_TEST_TRUE(build("test") == s);
+    CORE_TEST_TRUE(s == s);
 }
 
-static void testUnicodeEquality(Core::Test& test) {
+static void testUnicodeEquality() {
     const char* cs = "\u0040\u0400\u8000\U00100000";
-    String s = build(test, cs);
-    test.checkTrue(s == cs, "unicode equality with c-string");
-    test.checkTrue(s == build(test, cs),
-                   "unicode equality with another string");
-    test.checkTrue(cs == s, "unicode inverse equality with c-string");
-    test.checkTrue(build(test, cs) == s,
-                   "unicode inverse equality with another string");
-    test.checkTrue(s == s, "unicode equality with itself");
+    String s = build(cs);
+    CORE_TEST_TRUE(s == cs);
+    CORE_TEST_TRUE(s == build(cs));
+    CORE_TEST_TRUE(cs == s);
+    CORE_TEST_TRUE(build(cs) == s);
+    CORE_TEST_TRUE(s == s);
 }
 
-static void testInequality(Core::Test& test) {
-    String s = build(test, "test");
-    test.checkFalse(s != "test", "inequality with c-string");
-    test.checkFalse(s != build(test, "test"), "inequality with another string");
-    test.checkFalse("test" != s, "inverse inequality with c-string");
-    test.checkFalse(build(test, "test") != s,
-                    "inverse inequality with another string");
-    test.checkFalse(s != s, "inequality with itself");
+static void testInequality() {
+    String s = build("test");
+    CORE_TEST_FALSE(s != "test");
+    CORE_TEST_FALSE(s != build("test"));
+    CORE_TEST_FALSE("test" != s);
+    CORE_TEST_FALSE(build("test") != s);
+    CORE_TEST_FALSE(s != s);
 }
 
-static void testStringAppend(Core::Test& test) {
-    String s = build(test, "test");
-    test.checkFalse(s.append("22"), "multiple append works");
-    test.checkFalse(s.append("333"), "multiple append works");
-    test.checkFalse(s.append("4444"), "multiple append works");
-    test.checkEqual(build(test, "test223334444"), s, "multiple appends");
+static void testStringAppend() {
+    String s = build("test");
+    CORE_TEST_FALSE(s.append("22"));
+    CORE_TEST_FALSE(s.append("333"));
+    CORE_TEST_FALSE(s.append("4444"));
+    CORE_TEST_EQUAL(build("test223334444"), s);
 }
 
-static void testStringAppendOverflow(Core::Test& test) {
+static void testStringAppendOverflow() {
     Core::ArrayString<20> s;
-    test.checkFalse(s.append("te"), "overflow test 1");
-    test.checkTrue(s.append("23334444"), "overflow test 2");
-    test.checkTrue(build(test, "te23334444") != s, "overflow test 3");
+    CORE_TEST_FALSE(s.append("te"));
+    CORE_TEST_TRUE(s.append("23334444"));
+    CORE_TEST_TRUE(build("te23334444") != s);
 }
 
-static void testCharacters(Core::Test& test) {
-    String s = build(test, "test");
-    test.checkEqual<u32>('t', s[0], "character read 1");
-    test.checkEqual<u32>('e', s[1], "character read 2");
-    test.checkEqual<u32>('s', s[2], "character read 3");
-    test.checkEqual<u32>('t', s[3], "character read 4");
+static void testCharacters() {
+    String s = build("test");
+    CORE_TEST_EQUAL('t', s[0]);
+    CORE_TEST_EQUAL('e', s[1]);
+    CORE_TEST_EQUAL('s', s[2]);
+    CORE_TEST_EQUAL('t', s[3]);
 }
 
-static void testLength(Core::Test& test) {
-    String s = build(test, "test");
-    test.checkEqual(4, s.getLength(), "length 1");
-    test.checkFalse(s.append("aaa"), "length append works");
-    test.checkEqual(7, s.getLength(), "length 2");
+static void testLength() {
+    String s = build("test");
+    CORE_TEST_EQUAL(4, s.getLength());
+    CORE_TEST_FALSE(s.append("aaa"));
+    CORE_TEST_EQUAL(7, s.getLength());
 }
 
-static void testChar(Core::Test& test) {
-    String s = build(test, "test");
+static void testChar() {
+    String s = build("test");
     for(char i = 'a'; i < 'd'; i++) {
-        test.checkFalse(s.append(i), "char append");
+        CORE_TEST_FALSE(s.append(i));
     }
-    test.checkEqual(build(test, "testabc"), s, "char append");
+    CORE_TEST_EQUAL(build("testabc"), s);
 }
 
-static void testSignedChar(Core::Test& test) {
-    String s = build(test, "test");
+static void testSignedChar() {
+    String s = build("test");
     for(signed char i = 'b'; i < 'e'; i++) {
-        test.checkFalse(s.append(i), "signed char append");
+        CORE_TEST_FALSE(s.append(i));
     }
-    test.checkEqual(build(test, "testbcd"), s, "signed char append");
+    CORE_TEST_EQUAL(build("testbcd"), s);
 }
 
-static void testUnsignedChar(Core::Test& test) {
-    String s = build(test, "test");
+static void testUnsignedChar() {
+    String s = build("test");
     for(unsigned char i = 'c'; i < 'f'; i++) {
-        test.checkFalse(s.append(i), "unsigned char append");
+        CORE_TEST_FALSE(s.append(i));
     }
-    test.checkEqual(build(test, "testcde"), s, "unsigned char append");
+    CORE_TEST_EQUAL(build("testcde"), s);
 }
 
-static void testSignedShort(Core::Test& test) {
-    String s = build(test, "test");
+static void testSignedShort() {
+    String s = build("test");
     for(signed short i = 100; i < 103; i++) {
-        test.checkFalse(s.append(i), "signed short append");
+        CORE_TEST_FALSE(s.append(i));
     }
-    test.checkEqual(build(test, "test100101102"), s, "signed short append");
+    CORE_TEST_EQUAL(build("test100101102"), s);
 }
 
-static void testUnsignedShort(Core::Test& test) {
-    String s = build(test, "test");
+static void testUnsignedShort() {
+    String s = build("test");
     for(unsigned short i = 101; i < 104; i++) {
-        test.checkFalse(s.append(i), "unsigned short append");
+        CORE_TEST_FALSE(s.append(i));
     }
-    test.checkEqual(build(test, "test101102103"), s, "unsigned short append");
+    CORE_TEST_EQUAL(build("test101102103"), s);
 }
 
-static void testSignedInt(Core::Test& test) {
-    String s = build(test, "test");
+static void testSignedInt() {
+    String s = build("test");
     for(signed int i = 102; i < 105; i++) {
-        test.checkFalse(s.append(i), "signed int append");
+        CORE_TEST_FALSE(s.append(i));
     }
-    test.checkEqual(build(test, "test102103104"), s, "signed int append");
+    CORE_TEST_EQUAL(build("test102103104"), s);
 }
 
-static void testUnsignedInt(Core::Test& test) {
-    String s = build(test, "test");
+static void testUnsignedInt() {
+    String s = build("test");
     for(unsigned int i = 103; i < 106; i++) {
-        test.checkFalse(s.append(i), "unsigned int append");
+        CORE_TEST_FALSE(s.append(i));
     }
-    test.checkEqual(build(test, "test103104105"), s, "unsigned int append");
+    CORE_TEST_EQUAL(build("test103104105"), s);
 }
 
-static void testSignedLong(Core::Test& test) {
-    String s = build(test, "test");
+static void testSignedLong() {
+    String s = build("test");
     for(signed long i = 104; i < 107; i++) {
-        test.checkFalse(s.append(i), "signed long append");
+        CORE_TEST_FALSE(s.append(i));
     }
-    test.checkEqual(build(test, "test104105106"), s, "signed long append");
+    CORE_TEST_EQUAL(build("test104105106"), s);
 }
 
-static void testUnsignedLong(Core::Test& test) {
-    String s = build(test, "test");
+static void testUnsignedLong() {
+    String s = build("test");
     for(unsigned long i = 105; i < 108; i++) {
-        test.checkFalse(s.append(i), "unsigned long append");
+        CORE_TEST_FALSE(s.append(i));
     }
-    test.checkEqual(build(test, "test105106107"), s, "unsigned long append");
+    CORE_TEST_EQUAL(build("test105106107"), s);
 }
 
-static void testSignedLongLong(Core::Test& test) {
-    String s = build(test, "test");
+static void testSignedLongLong() {
+    String s = build("test");
     for(signed long long i = 106; i < 109; i++) {
-        test.checkFalse(s.append(i), "signed long long append");
+        CORE_TEST_FALSE(s.append(i));
     }
-    test.checkEqual(build(test, "test106107108"), s, "signed long long append");
+    CORE_TEST_EQUAL(build("test106107108"), s);
 }
 
-static void testUnsignedLongLong(Core::Test& test) {
-    String s = build(test, "test");
+static void testUnsignedLongLong() {
+    String s = build("test");
     for(unsigned long long i = 107; i < 110; i++) {
-        test.checkFalse(s.append(i), "unsigned long long append");
+        CORE_TEST_FALSE(s.append(i));
     }
-    test.checkEqual(build(test, "test107108109"), s,
-                    "unsigned long long append");
+    CORE_TEST_EQUAL(build("test107108109"), s);
 }
 
-static void testFloat(Core::Test& test) {
-    String s = build(test, "test");
+static void testFloat() {
+    String s = build("test");
     for(float i = 108; i < 111; i++) {
-        test.checkFalse(s.append(i), "float append");
+        CORE_TEST_FALSE(s.append(i));
     }
-    test.checkEqual(build(test, "test108.00109.00110.00"), s, "float append");
+    CORE_TEST_EQUAL(build("test108.00109.00110.00"), s);
 }
 
-static void testDouble(Core::Test& test) {
-    String s = build(test, "test");
+static void testDouble() {
+    String s = build("test");
     for(double i = 109; i < 112; i++) {
-        test.checkFalse(s.append(i), "double append");
+        CORE_TEST_FALSE(s.append(i));
     }
-    test.checkEqual(build(test, "test109.00110.00111.00"), s, "double append");
+    CORE_TEST_EQUAL(build("test109.00110.00111.00"), s);
 }
 
-static void testLongDouble(Core::Test& test) {
-    String s = build(test, "test");
+static void testLongDouble() {
+    String s = build("test");
     for(long double i = 110; i < 113; i++) {
-        test.checkFalse(s.append(i), "long double append");
+        CORE_TEST_FALSE(s.append(i));
     }
-    test.checkEqual(build(test, "test110.00111.00112.00"), s,
-                    "long double append");
+    CORE_TEST_EQUAL(build("test110.00111.00112.00"), s);
 }
 
-static void testBool(Core::Test& test) {
-    String s = build(test, "test");
-    test.checkFalse(s.append(true), "bool append 1");
-    test.checkFalse(s.append(false), "bool append 2");
-    test.checkFalse(s.append(true), "bool append 3");
-    test.checkEqual(build(test, "testtruefalsetrue"), s, "bool append 4");
+static void testBool() {
+    String s = build("test");
+    CORE_TEST_FALSE(s.append(true));
+    CORE_TEST_FALSE(s.append(false));
+    CORE_TEST_FALSE(s.append(true));
+    CORE_TEST_EQUAL(build("testtruefalsetrue"), s);
 }
 
-static void testIntOverflow(Core::Test& test) {
+static void testIntOverflow() {
     Core::ArrayString<20> s;
-    test.checkTrue(s.append(123456), "int overflow");
+    CORE_TEST_TRUE(s.append(123456));
 
     String o;
     for(int i = 0; i < s.getCapacity(); i++) {
-        test.checkFalse(o.append(i + 1), "int overflow compare build");
+        CORE_TEST_FALSE(o.append(i + 1));
     }
 
-    test.checkTrue(o == s, "int overflow compare");
+    CORE_TEST_TRUE(o == s);
 }
 
-static void testUnicode(Core::Test& test) {
+static void testUnicode() {
     String s;
-    test.checkFalse(s.appendUnicode('\u0040'), "unicode 1");
-    test.checkFalse(s.appendUnicode(L'\u0400'), "unicode 2");
-    test.checkFalse(s.appendUnicode(L'\u8000'), "unicode 3");
-    test.checkFalse(s.appendUnicode(U'\U00100000'), "unicode 4");
-    test.checkEqual(build(test, "\u0040\u0400\u8000\U00100000"), s,
-                    "unicode append");
+    CORE_TEST_FALSE(s.appendUnicode('\u0040'));
+    CORE_TEST_FALSE(s.appendUnicode(L'\u0400'));
+    CORE_TEST_FALSE(s.appendUnicode(L'\u8000'));
+    CORE_TEST_FALSE(s.appendUnicode(U'\U00100000'));
+    CORE_TEST_EQUAL(build("\u0040\u0400\u8000\U00100000"), s);
 }
 
-static void testClear(Core::Test& test) {
-    String s = build(test, "test");
-    test.checkFalse(s.append(1234), "clear 1");
+static void testClear() {
+    String s = build("test");
+    CORE_TEST_FALSE(s.append(1234));
     s.clear();
-    test.checkFalse(s.append("wusi"), "clear 2");
-    test.checkFalse(s.append("1234"), "clear 3");
-    test.checkEqual(build(test, "wusi1234"), s, "clear 4");
+    CORE_TEST_FALSE(s.append("wusi"));
+    CORE_TEST_FALSE(s.append("1234"));
+    CORE_TEST_EQUAL(build("wusi1234"), s);
 }
 
-static void testHashCode(Core::Test& test) {
+static void testHashCode() {
     String s;
-    test.checkFalse(s.append("a"), "hash code 1");
-    test.checkFalse(s.append("bc"), "hash code 2");
-    test.checkFalse(s.append(20), "hash code 3");
-    test.checkFalse(s.append(25.5f), "hash code 4");
-    test.checkFalse(s.append(true), "hash code 5");
-    test.checkEqual(build(test, "abc2025.50true").hashCode(), s.hashCode(),
-                    "string modification recalculates hash 1");
+    CORE_TEST_FALSE(s.append("a"));
+    CORE_TEST_FALSE(s.append("bc"));
+    CORE_TEST_FALSE(s.append(20));
+    CORE_TEST_FALSE(s.append(25.5f));
+    CORE_TEST_FALSE(s.append(true));
+    CORE_TEST_EQUAL(build("abc2025.50true").hashCode(), s.hashCode());
     s.clear();
-    test.checkEqual(String().hashCode(), s.hashCode(),
-                    "string modification recalculates hash 2");
+    CORE_TEST_EQUAL(String().hashCode(), s.hashCode());
 }
 
-static void testAddSelf(Core::Test& test) {
+static void testAddSelf() {
     String s;
-    test.checkFalse(s.append("test1"), "add self 1");
-    test.checkFalse(s.append(s), "add self 2");
-    test.checkFalse(s.append(s), "add self 3");
-    test.checkEqual(build(test, "test1test1test1test1"), s, "add self 4");
+    CORE_TEST_FALSE(s.append("test1"));
+    CORE_TEST_FALSE(s.append(s));
+    CORE_TEST_FALSE(s.append(s));
+    CORE_TEST_EQUAL(build("test1test1test1test1"), s);
 }
 
-static void testAsHashMapKey(Core::Test& test) {
+static void testAsHashMapKey() {
     Core::HashMap<String, int> map;
-    test.checkFalse(map.add(build(test, "wusi"), 3), "as hashmap key 1");
-    test.checkFalse(map.add(build(test, "hiThere"), 7), "as hashmap key 2");
-    test.checkFalse(map.add(build(test, "baum123"), 5), "as hashmap key 3");
+    CORE_TEST_NOT_NULL(map.add(build("wusi"), 3));
+    CORE_TEST_NOT_NULL(map.add(build("hiThere"), 7));
+    CORE_TEST_NOT_NULL(map.add(build("baum123"), 5));
 
-    int* a = map.search(build(test, "wusi"));
-    int* b = map.search(build(test, "hiThere"));
-    int* c = map.search(build(test, "baum123"));
-    int* d = map.search(build(test, "423hifd"));
+    int* a = map.search(build("wusi"));
+    int* b = map.search(build("hiThere"));
+    int* c = map.search(build("baum123"));
+    int* d = map.search(build("423hifd"));
 
-    test.checkTrue(a != nullptr, "strings works as hash key 1");
-    test.checkTrue(b != nullptr, "strings works as hash key 2");
-    test.checkTrue(c != nullptr, "strings works as hash key 3");
-    test.checkTrue(d == nullptr, "strings works as hash key 4");
+    CORE_TEST_NOT_NULL(a);
+    CORE_TEST_NOT_NULL(b);
+    CORE_TEST_NOT_NULL(c);
+    CORE_TEST_NULL(d);
 
     if(a != nullptr && b != nullptr && c != nullptr) {
-        test.checkEqual(3, *a, "strings works as hash key 1");
-        test.checkEqual(7, *b, "strings works as hash key 2");
-        test.checkEqual(5, *c, "strings works as hash key 3");
+        CORE_TEST_EQUAL(3, *a);
+        CORE_TEST_EQUAL(7, *b);
+        CORE_TEST_EQUAL(5, *c);
     }
 }
 
 void Core::ArrayStringTests::test() {
-    Core::Test test("String");
-    testEquality(test);
-    testUnicodeEquality(test);
-    testInequality(test);
-    testStringAppend(test);
-    testStringAppendOverflow(test);
-    testCharacters(test);
-    testLength(test);
-    testChar(test);
-    testSignedChar(test);
-    testUnsignedChar(test);
-    testSignedShort(test);
-    testUnsignedShort(test);
-    testSignedInt(test);
-    testUnsignedInt(test);
-    testSignedLong(test);
-    testUnsignedLong(test);
-    testSignedLongLong(test);
-    testUnsignedLongLong(test);
-    testFloat(test);
-    testDouble(test);
-    testLongDouble(test);
-    testBool(test);
-    testIntOverflow(test);
-    testUnicode(test);
-    testClear(test);
-    testHashCode(test);
-    testAddSelf(test);
-    testAsHashMapKey(test);
-    test.finalize();
+    testEquality();
+    testUnicodeEquality();
+    testInequality();
+    testStringAppend();
+    testStringAppendOverflow();
+    testCharacters();
+    testLength();
+    testChar();
+    testSignedChar();
+    testUnsignedChar();
+    testSignedShort();
+    testUnsignedShort();
+    testSignedInt();
+    testUnsignedInt();
+    testSignedLong();
+    testUnsignedLong();
+    testSignedLongLong();
+    testUnsignedLongLong();
+    testFloat();
+    testDouble();
+    testLongDouble();
+    testBool();
+    testIntOverflow();
+    testUnicode();
+    testClear();
+    testHashCode();
+    testAddSelf();
+    testAsHashMapKey();
 }

+ 8 - 11
tests/ArrayTests.cpp

@@ -6,30 +6,27 @@
 using String = Core::ArrayString<128>;
 
 template<typename T>
-static String build(Core::Test& test, const T& t) {
+static String build(const T& t) {
     String s;
-    test.checkFalse(s.append(t), "append works");
+    CORE_TEST_FALSE(s.append(t));
     return s;
 }
 
-static void testToString1(Core::Test& test) {
+static void testToString1() {
     Core::Array<int, 3> a;
     a[0] = 1;
     a[1] = 243;
     a[2] = -423;
-    test.checkEqual(build(test, "[1, 243, -423]"), build(test, a),
-                    "to string 1");
+    CORE_TEST_EQUAL(build("[1, 243, -423]"), build(a));
 }
 
-static void testToString2(Core::Test& test) {
+static void testToString2() {
     Core::Array<int, 1> a;
     a[0] = 1;
-    test.checkEqual(build(test, "[1]"), build(test, a), "to string 2");
+    CORE_TEST_EQUAL(build("[1]"), build(a));
 }
 
 void Core::ArrayTests::test() {
-    Core::Test test("Array");
-    testToString1(test);
-    testToString2(test);
-    test.finalize();
+    testToString1();
+    testToString2();
 }

+ 59 - 69
tests/BitArrayTests.cpp

@@ -6,48 +6,47 @@
 using String = Core::ArrayString<128>;
 
 template<typename T>
-static String build(Core::Test& test, const T& t) {
+static String build(const T& t) {
     String s;
-    test.checkFalse(s.append(t), "append works");
+    CORE_TEST_FALSE(s.append(t));
     return s;
 }
 
-static void testSetRead(Core::Test& test) {
+static void testSetRead() {
     Core::BitArray bits;
-    test.checkFalse(bits.resize(4, 3), "resize works 1");
+    CORE_TEST_FALSE(bits.resize(4, 3));
     bits.set(0, 1).set(1, 2).set(2, 3).set(3, 4);
-    test.checkEqual(1, bits.get(0), "set and read correct value 1");
-    test.checkEqual(2, bits.get(1), "set and read correct value 2");
-    test.checkEqual(3, bits.get(2), "set and read correct value 3");
-    test.checkEqual(4, bits.get(3), "set and read correct value 4");
+    CORE_TEST_EQUAL(1, bits.get(0));
+    CORE_TEST_EQUAL(2, bits.get(1));
+    CORE_TEST_EQUAL(3, bits.get(2));
+    CORE_TEST_EQUAL(4, bits.get(3));
 }
 
-static void testOutOfBoundsSetRead(Core::Test& test) {
+static void testOutOfBoundsSetRead() {
     Core::BitArray bits;
     bits.set(0, 1).set(1, 2).set(2, 3).set(3, 4);
-    test.checkEqual(0, bits.get(0), "set and read default value 1");
-    test.checkEqual(0, bits.get(1), "set and read default value 2");
-    test.checkEqual(0, bits.get(2), "set and read default value 3");
-    test.checkEqual(0, bits.get(3), "set and read default value 4");
+    CORE_TEST_EQUAL(0, bits.get(0));
+    CORE_TEST_EQUAL(0, bits.get(1));
+    CORE_TEST_EQUAL(0, bits.get(2));
+    CORE_TEST_EQUAL(0, bits.get(3));
 }
 
-static void testBigSetRead(Core::Test& test) {
+static void testBigSetRead() {
     Core::BitArray bits;
-    test.checkFalse(bits.resize(100, 13), "resize works 2");
+    CORE_TEST_FALSE(bits.resize(100, 13));
     for(int i = 0; i < bits.getLength(); i++) {
         bits.set(i, i);
     }
     for(int i = 0; i < bits.getLength(); i++) {
-        test.checkEqual(i, bits.get(i),
-                        "set and read correct value over long array");
+        CORE_TEST_EQUAL(i, bits.get(i));
     }
 }
 
-static void testRandomSetReadResize(Core::Test& test) {
+static void testRandomSetReadResize() {
     const int length = 100;
     int data[length];
     Core::BitArray bits;
-    test.checkFalse(bits.resize(100, 13), "resize works 3");
+    CORE_TEST_FALSE(bits.resize(100, 13));
     int seed = 534;
     for(int k = 0; k < 20; k++) {
         for(int i = 0; i < bits.getLength(); i++) {
@@ -57,83 +56,74 @@ static void testRandomSetReadResize(Core::Test& test) {
         }
     }
     for(int i = 0; i < bits.getLength(); i++) {
-        test.checkEqual(data[i], bits.get(i),
-                        "set and read correct value with random input");
+        CORE_TEST_EQUAL(data[i], bits.get(i));
     }
-    test.checkFalse(bits.resize(bits.getLength(), bits.getBits() + 1),
-                    "resize works 4");
-    test.checkEqual(14, bits.getBits(), "corrects bits after resize");
-    test.checkEqual(100, bits.getLength(), "correct length after resize");
+    CORE_TEST_FALSE(bits.resize(bits.getLength(), bits.getBits() + 1));
+    CORE_TEST_EQUAL(14, bits.getBits());
+    CORE_TEST_EQUAL(100, bits.getLength());
     for(int i = 0; i < bits.getLength(); i++) {
-        test.checkEqual(
-            data[i], bits.get(i),
-            "set and read correct value with random input after resize");
+        CORE_TEST_EQUAL(data[i], bits.get(i));
     }
 }
 
-static void testReadOnly(Core::Test& test) {
+static void testReadOnly() {
     Core::BitArray bits;
-    test.checkFalse(bits.resize(4, 3), "resize works 5");
+    CORE_TEST_FALSE(bits.resize(4, 3));
     bits.set(0, 1).set(1, 2).set(2, 3).set(3, 4);
     Core::BitArray copy;
-    test.checkFalse(copy.copyFrom(bits), "copy works");
+    CORE_TEST_FALSE(copy.copyFrom(bits));
     const Core::BitArray bits2 = Core::move(copy);
-    test.checkEqual(1, bits2.get(0), "can read from const 1");
-    test.checkEqual(2, bits2.get(1), "can read from const 2");
-    test.checkEqual(3, bits2.get(2), "can read from const 3");
-    test.checkEqual(4, bits2.get(3), "can read from const 4");
+    CORE_TEST_EQUAL(1, bits2.get(0));
+    CORE_TEST_EQUAL(2, bits2.get(1));
+    CORE_TEST_EQUAL(3, bits2.get(2));
+    CORE_TEST_EQUAL(4, bits2.get(3));
 }
 
-static void testSelect(Core::Test& test) {
+static void testSelect() {
     Core::BitArray bits;
-    test.checkFalse(bits.resize(90, 1), "resize works 6");
+    CORE_TEST_FALSE(bits.resize(90, 1));
     bits.fill(0);
     bits.set(0, 1).set(5, 1).set(20, 1).set(31, 1);
     bits.set(32, 1).set(33, 1).set(60, 1);
-    test.checkEqual(-1, bits.select(-1), "select -1 bit");
-    test.checkEqual(-1, bits.select(0), "select 0 bit");
-    test.checkEqual(0, bits.select(1), "select 1 bit");
-    test.checkEqual(5, bits.select(2), "select 2 bit");
-    test.checkEqual(20, bits.select(3), "select 3 bit");
-    test.checkEqual(31, bits.select(4), "select 4 bit");
-    test.checkEqual(32, bits.select(5), "select 5 bit");
-    test.checkEqual(33, bits.select(6), "select 6 bit");
-    test.checkEqual(60, bits.select(7), "select 7 bit");
-    test.checkEqual(-1, bits.select(8), "select 8 bit");
+    CORE_TEST_EQUAL(-1, bits.select(-1));
+    CORE_TEST_EQUAL(-1, bits.select(0));
+    CORE_TEST_EQUAL(0, bits.select(1));
+    CORE_TEST_EQUAL(5, bits.select(2));
+    CORE_TEST_EQUAL(20, bits.select(3));
+    CORE_TEST_EQUAL(31, bits.select(4));
+    CORE_TEST_EQUAL(32, bits.select(5));
+    CORE_TEST_EQUAL(33, bits.select(6));
+    CORE_TEST_EQUAL(60, bits.select(7));
+    CORE_TEST_EQUAL(-1, bits.select(8));
 }
 
-static void testToString1(Core::Test& test) {
+static void testToString1() {
     Core::BitArray bits;
-    test.checkFalse(bits.resize(4, 3), "resize works 7");
+    CORE_TEST_FALSE(bits.resize(4, 3));
     bits.set(0, 1).set(1, 2).set(2, 3).set(3, 4);
-    test.checkEqual(build(test, "[1, 2, 3, 4]"), build(test, bits),
-                    "bit array to string 1");
+    CORE_TEST_EQUAL(build("[1, 2, 3, 4]"), build(bits));
 }
 
-static void testToString2(Core::Test& test) {
+static void testToString2() {
     Core::BitArray bits;
-    test.checkFalse(bits.resize(1, 3), "resize works 8");
+    CORE_TEST_FALSE(bits.resize(1, 3));
     bits.set(0, 1);
-    test.checkEqual(build(test, "[1]"), build(test, bits),
-                    "bit array to string 2");
+    CORE_TEST_EQUAL(build("[1]"), build(bits));
 }
 
-static void testToString3(Core::Test& test) {
+static void testToString3() {
     Core::BitArray bits;
-    test.checkEqual(build(test, "[]"), build(test, bits),
-                    "bit array to string 3");
+    CORE_TEST_EQUAL(build("[]"), build(bits));
 }
 
 void Core::BitArrayTests::test() {
-    Core::Test test("Core::BitArray");
-    testSetRead(test);
-    testOutOfBoundsSetRead(test);
-    testBigSetRead(test);
-    testRandomSetReadResize(test);
-    testReadOnly(test);
-    testSelect(test);
-    testToString1(test);
-    testToString2(test);
-    testToString3(test);
-    test.finalize();
+    testSetRead();
+    testOutOfBoundsSetRead();
+    testBigSetRead();
+    testRandomSetReadResize();
+    testReadOnly();
+    testSelect();
+    testToString1();
+    testToString2();
+    testToString3();
 }

+ 148 - 158
tests/HashMapTests.cpp

@@ -7,77 +7,76 @@ using IntMap = Core::HashMap<int, int>;
 using String = Core::ArrayString<128>;
 
 template<typename T>
-static String build(Core::Test& test, const T& t) {
+static String build(const T& t) {
     String s;
-    test.checkFalse(s.append(t), "append works");
+    CORE_TEST_FALSE(s.append(t));
     return s;
 }
 
-static void testAdd(Core::Test& test) {
+static void testAdd() {
     IntMap map;
-    test.checkFalse(map.add(5, 4), "add works 1");
+    CORE_TEST_NOT_NULL(map.add(5, 4));
     int* value = map.search(5);
-    test.checkTrue(value != nullptr, "contains added value");
+    CORE_TEST_NOT_NULL(value);
     if(value != nullptr) {
-        test.checkEqual(4, *value, "search finds added value");
+        CORE_TEST_EQUAL(4, *value);
     }
 }
 
-static void testMultipleAdd(Core::Test& test) {
+static void testMultipleAdd() {
     IntMap map;
-    test.checkFalse(map.add(5, 4), "add works 2");
-    test.checkFalse(map.add(10, 3), "add works 3");
-    test.checkFalse(map.add(15, 2), "add works 4");
-    test.checkTrue(map.contains(5), "contains added value 1");
-    test.checkTrue(map.contains(10), "contains added value 2");
-    test.checkTrue(map.contains(15), "contains added value 3");
+    CORE_TEST_NOT_NULL(map.add(5, 4));
+    CORE_TEST_NOT_NULL(map.add(10, 3));
+    CORE_TEST_NOT_NULL(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);
-    test.checkTrue(a != nullptr, "contains added value 1");
-    test.checkTrue(b != nullptr, "contains added value 2");
-    test.checkTrue(c != nullptr, "contains added value 3");
+    CORE_TEST_NOT_NULL(a);
+    CORE_TEST_NOT_NULL(b);
+    CORE_TEST_NOT_NULL(c);
     if(a != nullptr && b != nullptr && c != nullptr) {
-        test.checkEqual(4, *a, "search finds added value 1");
-        test.checkEqual(3, *b, "search finds added value 2");
-        test.checkEqual(2, *c, "search finds added value 3");
+        CORE_TEST_EQUAL(4, *a);
+        CORE_TEST_EQUAL(3, *b);
+        CORE_TEST_EQUAL(2, *c);
     }
 }
 
-static void testSearch(Core::Test& test) {
+static void testSearch() {
     IntMap map;
-    test.checkTrue(nullptr == map.search(6),
-                   "search does not find missing key");
+    CORE_TEST_NULL(map.search(6));
 }
 
-static void testAddReplace(Core::Test& test) {
+static void testAddReplace() {
     IntMap map;
-    test.checkFalse(map.add(5, 4), "add works 5");
-    test.checkFalse(map.add(5, 10), "add works 6");
-    test.checkTrue(map.contains(5), "contains replaced value");
+    CORE_TEST_NOT_NULL(map.add(5, 4));
+    CORE_TEST_NOT_NULL(map.add(5, 10));
+    CORE_TEST_TRUE(map.contains(5));
     int* a = map.search(5);
-    test.checkTrue(a != nullptr, "contains replaced value");
+    CORE_TEST_NOT_NULL(a);
     if(a != nullptr) {
-        test.checkEqual(10, *a, "search finds replaced value");
+        CORE_TEST_EQUAL(10, *a);
     }
 }
 
-static void testClear(Core::Test& test) {
+static void testClear() {
     IntMap map;
-    test.checkFalse(map.add(5, 4), "add works 7");
-    test.checkFalse(map.add(4, 10), "add works 8");
+    CORE_TEST_NOT_NULL(map.add(5, 4));
+    CORE_TEST_NOT_NULL(map.add(4, 10));
     map.clear();
-    test.checkFalse(map.contains(5), "does not contain cleared values 1");
-    test.checkFalse(map.contains(4), "does not contain cleared values 2");
+    CORE_TEST_FALSE(map.contains(5));
+    CORE_TEST_FALSE(map.contains(4));
 }
 
-static void testOverflow(Core::Test& test) {
+static void testOverflow() {
     IntMap map;
-    for(int i = 0; i < 1000000; i++) {
-        test.checkFalse(map.add(i, i), "add works in overflow");
+    for(int i = 0; i < 100000; i++) {
+        CORE_TEST_NOT_NULL(map.add(i, i));
     }
-    for(int i = 0; i < 1000000; i++) {
-        test.checkTrue(map.contains(i), "still contains values after overflow");
+    for(int i = 0; i < 100000; i++) {
+        CORE_TEST_TRUE(map.contains(i));
     }
 }
 
@@ -105,102 +104,95 @@ struct A {
     }
 };
 
-static void testEmplace(Core::Test& test) {
+static void testEmplace() {
     Core::HashMap<int, A> map;
 
-    bool r1 = map.tryEmplace(0, 3, 4);
-    bool r2 = map.tryEmplace(3, 4, 5);
-    bool r3 = map.tryEmplace(20, 5, 6);
-    bool r4 = map.tryEmplace(3, 6, 7);
-    bool r5 = map.tryEmplace(20, 7, 8);
+    CORE_TEST_NOT_NULL(map.tryEmplace(0, 3, 4));
+    CORE_TEST_NOT_NULL(map.tryEmplace(3, 4, 5));
+    CORE_TEST_NOT_NULL(map.tryEmplace(20, 5, 6));
+    CORE_TEST_NULL(map.tryEmplace(3, 6, 7));
+    CORE_TEST_NULL(map.tryEmplace(20, 7, 8));
 
     A* a = map.search(0);
     A* b = map.search(3);
     A* c = map.search(20);
 
-    test.checkTrue(a != nullptr, "contains emplaced value 1");
-    test.checkTrue(b != nullptr, "contains emplaced value 2");
-    test.checkTrue(c != nullptr, "contains emplaced value 3");
+    CORE_TEST_NOT_NULL(a);
+    CORE_TEST_NOT_NULL(b);
+    CORE_TEST_NOT_NULL(c);
 
     if(a != nullptr && b != nullptr && c != nullptr) {
-        test.checkEqual(A(3, 4), *a, "contains emplaced value 1");
-        test.checkEqual(A(4, 5), *b, "contains emplaced value 2");
-        test.checkEqual(A(5, 6), *c, "contains emplaced value 3");
+        CORE_TEST_EQUAL(A(3, 4), *a);
+        CORE_TEST_EQUAL(A(4, 5), *b);
+        CORE_TEST_EQUAL(A(5, 6), *c);
     }
-
-    test.checkFalse(r1, "emplacing returns correct value 1");
-    test.checkFalse(r2, "emplacing returns correct value 2");
-    test.checkFalse(r3, "emplacing returns correct value 3");
-    test.checkTrue(r4, "emplacing returns correct value 4");
-    test.checkTrue(r5, "emplacing returns correct value 5");
 }
 
-static void testToString1(Core::Test& test) {
+static void testToString1() {
     IntMap map;
-    test.checkFalse(map.add(1, 3), "add works to string 1");
-    test.checkFalse(map.add(2, 4), "add works to string 2");
-    test.checkFalse(map.add(3, 5), "add works to string 3");
-    test.checkEqual(build(test, "[1 = 3, 2 = 4, 3 = 5]"), build(test, map),
-                    "to string 1");
+    CORE_TEST_NOT_NULL(map.add(1, 3));
+    CORE_TEST_NOT_NULL(map.add(2, 4));
+    CORE_TEST_NOT_NULL(map.add(3, 5));
+    CORE_TEST_EQUAL(build("[1 = 3, 2 = 4, 3 = 5]"), build(map));
 }
 
-static void testToString2(Core::Test& test) {
+static void testToString2() {
     IntMap map;
-    test.checkFalse(map.add(1, 3), "add works to string 4");
-    test.checkEqual(build(test, "[1 = 3]"), build(test, map), "to string 2");
+    CORE_TEST_NOT_NULL(map.add(1, 3));
+    CORE_TEST_EQUAL(build("[1 = 3]"), build(map));
 }
 
-static void testToString3(Core::Test& test) {
+static void testToString3() {
     IntMap map;
-    test.checkEqual(build(test, "[]"), build(test, map), "to string 3");
+    CORE_TEST_EQUAL(build("[]"), build(map));
 }
 
-static void testCopy(Core::Test& test) {
+static void testCopy() {
     IntMap map;
-    test.checkFalse(map.add(1, 3), "add works copy 1");
-    test.checkFalse(map.add(2, 4), "add works copy 2");
-    test.checkFalse(map.add(3, 5), "add works copy 3");
+    CORE_TEST_NOT_NULL(map.add(1, 3));
+    CORE_TEST_NOT_NULL(map.add(2, 4));
+    CORE_TEST_NOT_NULL(map.add(3, 5));
     IntMap copy;
-    test.checkFalse(copy.copyFrom(map), "copy works");
+    CORE_TEST_FALSE(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++) {
-        test.checkTrue(a[i] != nullptr && a[i + 3] != nullptr,
-                       "copy has same values");
+        CORE_TEST_NOT_NULL(a[i]);
+        CORE_TEST_NOT_NULL(a[i + 3]);
         if(a[i] != nullptr && a[i + 3] != nullptr) {
-            test.checkEqual(*(a[i]), *(a[i + 3]), "copy has same values");
+            CORE_TEST_EQUAL(*(a[i]), *(a[i + 3]));
         }
     }
 }
 
-static void testMove(Core::Test& test) {
+static void testMove() {
     IntMap map;
-    test.checkFalse(map.add(1, 3), "add works move 5");
-    test.checkFalse(map.add(2, 4), "add works move 6");
-    test.checkFalse(map.add(3, 5), "add works move 7");
+    CORE_TEST_NOT_NULL(map.add(1, 3));
+    CORE_TEST_NOT_NULL(map.add(2, 4));
+    CORE_TEST_NOT_NULL(map.add(3, 5));
     IntMap move(Core::move(map));
 
     int* a = move.search(1);
     int* b = move.search(2);
     int* c = move.search(3);
 
-    test.checkTrue(a != nullptr, "move moves values 1");
-    test.checkTrue(b != nullptr, "move moves values 2");
-    test.checkTrue(c != nullptr, "move moves values 3");
+    CORE_TEST_NOT_NULL(a);
+    CORE_TEST_NOT_NULL(b);
+    CORE_TEST_NOT_NULL(c);
 
     if(a != nullptr && b != nullptr && c != nullptr) {
-        test.checkEqual(3, *a, "move moves values 1");
-        test.checkEqual(4, *b, "move moves values 2");
-        test.checkEqual(5, *c, "move moves values 3");
+        CORE_TEST_EQUAL(3, *a);
+        CORE_TEST_EQUAL(4, *b);
+        CORE_TEST_EQUAL(5, *c);
     }
 }
 
-static void testMoveAssignment(Core::Test& test) {
+static void testMoveAssignment() {
     IntMap map;
-    test.checkFalse(map.add(1, 3), "add works move assignment 1");
-    test.checkFalse(map.add(2, 4), "add works move assignment 2");
-    test.checkFalse(map.add(3, 5), "add works move assignment 3");
+    CORE_TEST_NOT_NULL(map.add(1, 3));
+    CORE_TEST_NOT_NULL(map.add(2, 4));
+    CORE_TEST_NOT_NULL(map.add(3, 5));
 
     IntMap move;
     move = Core::move(map);
@@ -209,22 +201,22 @@ static void testMoveAssignment(Core::Test& test) {
     int* b = move.search(2);
     int* c = move.search(3);
 
-    test.checkTrue(a != nullptr, "move moves values 1");
-    test.checkTrue(b != nullptr, "move moves values 2");
-    test.checkTrue(c != nullptr, "move moves values 3");
+    CORE_TEST_NOT_NULL(a);
+    CORE_TEST_NOT_NULL(b);
+    CORE_TEST_NOT_NULL(c);
 
     if(a != nullptr && b != nullptr && c != nullptr) {
-        test.checkEqual(3, *a, "move moves values 1");
-        test.checkEqual(4, *b, "move moves values 2");
-        test.checkEqual(5, *c, "move moves values 3");
+        CORE_TEST_EQUAL(3, *a);
+        CORE_TEST_EQUAL(4, *b);
+        CORE_TEST_EQUAL(5, *c);
     }
 }
 
-static void testRemove(Core::Test& test) {
+static void testRemove() {
     IntMap map;
-    test.checkFalse(map.add(1, 3), "add works remove 1");
-    test.checkFalse(map.add(2, 4), "add works remove 2");
-    test.checkFalse(map.add(3, 5), "add works remove 3");
+    CORE_TEST_NOT_NULL(map.add(1, 3));
+    CORE_TEST_NOT_NULL(map.add(2, 4));
+    CORE_TEST_NOT_NULL(map.add(3, 5));
 
     bool remove1 = map.remove(2);
     bool remove2 = map.remove(7);
@@ -233,118 +225,116 @@ static void testRemove(Core::Test& test) {
     int* b = map.search(2);
     int* c = map.search(3);
 
-    test.checkTrue(a != nullptr, "move moves values 1");
-    test.checkTrue(b == nullptr, "move moves values 2");
-    test.checkTrue(c != nullptr, "move moves values 3");
+    CORE_TEST_NOT_NULL(a);
+    CORE_TEST_NULL(b);
+    CORE_TEST_NOT_NULL(c);
 
-    test.checkTrue(remove1, "remove returns true");
-    test.checkFalse(remove2, "remove returns false");
+    CORE_TEST_TRUE(remove1);
+    CORE_TEST_FALSE(remove2);
 
     if(a != nullptr && c != nullptr) {
-        test.checkEqual(3, *a, "move moves values 1");
-        test.checkEqual(5, *c, "move moves values 3");
+        CORE_TEST_EQUAL(3, *a);
+        CORE_TEST_EQUAL(5, *c);
     }
 }
 
-static void testEntryForEach(Core::Test& test) {
+static void testEntryForEach() {
     IntMap map;
-    test.checkFalse(map.add(5, 4), "add works entry for each 1");
-    test.checkFalse(map.add(10, 3), "add works entry for each 2");
-    test.checkFalse(map.add(15, 2), "add works entry for each 3");
+    CORE_TEST_NOT_NULL(map.add(5, 4));
+    CORE_TEST_NOT_NULL(map.add(10, 3));
+    CORE_TEST_NOT_NULL(map.add(15, 2));
 
     int counter = 0;
     for(auto& entry : map.entries()) {
         counter += entry.getKey() + entry.value;
     }
-    test.checkEqual(39, counter, "entry iterator");
+    CORE_TEST_EQUAL(39, counter);
 
     const IntMap& cmap = map;
     counter = 0;
     for(const auto& entry : cmap.entries()) {
         counter += entry.getKey() + entry.value;
     }
-    test.checkEqual(39, counter, "const entry iterator");
+    CORE_TEST_EQUAL(39, counter);
 }
 
-static void testKeyForEach(Core::Test& test) {
+static void testKeyForEach() {
     IntMap map;
-    test.checkFalse(map.add(5, 4), "add works key for each 1");
-    test.checkFalse(map.add(10, 3), "add works key for each 2");
-    test.checkFalse(map.add(15, 2), "add works key for each 3");
+    CORE_TEST_NOT_NULL(map.add(5, 4));
+    CORE_TEST_NOT_NULL(map.add(10, 3));
+    CORE_TEST_NOT_NULL(map.add(15, 2));
 
     int counter = 0;
     for(const int& key : map.keys()) {
         counter += key;
     }
-    test.checkEqual(30, counter, "key iterator");
+    CORE_TEST_EQUAL(30, counter);
 
     const IntMap& cmap = map;
     counter = 0;
     for(const int& key : cmap.keys()) {
         counter += key;
     }
-    test.checkEqual(30, counter, "const key iterator");
+    CORE_TEST_EQUAL(30, counter);
 }
 
-static void testValueForEach(Core::Test& test) {
+static void testValueForEach() {
     IntMap map;
-    test.checkFalse(map.add(5, 4), "add works value for each 1");
-    test.checkFalse(map.add(10, 3), "add works value for each 2");
-    test.checkFalse(map.add(15, 2), "add works value for each 3");
+    CORE_TEST_NOT_NULL(map.add(5, 4));
+    CORE_TEST_NOT_NULL(map.add(10, 3));
+    CORE_TEST_NOT_NULL(map.add(15, 2));
 
     int counter = 0;
     for(int& value : map.values()) {
         counter += value;
     }
-    test.checkEqual(9, counter, "value iterator");
+    CORE_TEST_EQUAL(9, counter);
 
     const IntMap& cmap = map;
     counter = 0;
     for(const int& value : cmap.values()) {
         counter += value;
     }
-    test.checkEqual(9, counter, "const value iterator");
+    CORE_TEST_EQUAL(9, counter);
 }
 
 template<typename T>
-static void testType(Core::Test& test) {
+static void testType() {
     Core::HashMap<T, int> m;
-    test.checkFalse(m.add(T(), 3), "test type");
+    CORE_TEST_NOT_NULL(m.add(T(), 3));
 }
 
-static void testTypes(Core::Test& test) {
-    testType<char>(test);
-    testType<signed char>(test);
-    testType<signed short>(test);
-    testType<signed int>(test);
-    testType<signed long>(test);
-    testType<signed long long>(test);
-    testType<unsigned char>(test);
-    testType<unsigned short>(test);
-    testType<unsigned int>(test);
-    testType<unsigned long>(test);
-    testType<unsigned long long>(test);
+static void testTypes() {
+    testType<char>();
+    testType<signed char>();
+    testType<signed short>();
+    testType<signed int>();
+    testType<signed long>();
+    testType<signed long long>();
+    testType<unsigned char>();
+    testType<unsigned short>();
+    testType<unsigned int>();
+    testType<unsigned long>();
+    testType<unsigned long long>();
 }
 
 void Core::HashMapTests::test() {
-    Core::Test test("HashMap");
-    testAdd(test);
-    testMultipleAdd(test);
-    testSearch(test);
-    testAddReplace(test);
-    testClear(test);
-    testOverflow(test);
-    testEmplace(test);
-    testToString1(test);
-    testToString2(test);
-    testToString3(test);
-    testCopy(test);
-    testMove(test);
-    testMoveAssignment(test);
-    testRemove(test);
-    testEntryForEach(test);
-    testKeyForEach(test);
-    testValueForEach(test);
-    testTypes(test);
-    test.finalize();
+    testAdd();
+    testMultipleAdd();
+    testSearch();
+    testAddReplace();
+    testClear();
+    testOverflow();
+    testEmplace();
+    testToString1();
+    testToString2();
+    testToString3();
+    testCopy();
+    testMove();
+    testMoveAssignment();
+    testRemove();
+    testEntryForEach();
+    testKeyForEach();
+    testValueForEach();
+    testTypes();
 }

+ 131 - 139
tests/LinkedListTests.cpp

@@ -17,255 +17,247 @@ using IntList = Core::LinkedList<int>;
 using String = Core::ArrayString<128>;
 
 template<typename T>
-static String build(Core::Test& test, const T& t) {
+static String build(const T& t) {
     String s;
-    test.checkFalse(s.append(t), "append works");
+    CORE_TEST_FALSE(s.append(t));
     return s;
 }
 
-static void testWithoutCopyOrMove(Core::Test& test) {
+static void testWithoutCopyOrMove() {
     Core::LinkedList<LinkedListTester> list;
-    test.checkFalse(list.add(3) == nullptr, "without copy or move");
+    CORE_TEST_NOT_NULL(list.add(3));
 }
 
-static void testAdd(Core::Test& test) {
+static void testAdd() {
     IntList list;
-    test.checkFalse(list.add(5) == nullptr, "add works 1");
+    CORE_TEST_NOT_NULL(list.add(5));
     auto iter = list.begin();
-    test.checkEqual(5, *iter, "contains added value");
-    test.checkEqual(1, list.getLength(), "sizes is increased by add");
+    CORE_TEST_EQUAL(5, *iter);
+    CORE_TEST_EQUAL(1, list.getLength());
 }
 
-static void testMultipleAdd(Core::Test& test) {
+static void testMultipleAdd() {
     IntList list;
-    test.checkFalse(list.add(4) == nullptr, "add works 2");
-    test.checkFalse(list.add(3) == nullptr, "add works 3");
-    test.checkFalse(list.add(2) == nullptr, "add works 4");
+    CORE_TEST_NOT_NULL(list.add(4));
+    CORE_TEST_NOT_NULL(list.add(3));
+    CORE_TEST_NOT_NULL(list.add(2));
     auto iter = list.begin();
-    test.checkEqual(4, *iter, "contains added value 1");
-    test.checkEqual(3, *(++iter), "contains added value 2");
-    test.checkEqual(2, *(++iter), "contains added value 3");
-    test.checkEqual(3, list.getLength(), "sizes is increased by add");
+    CORE_TEST_EQUAL(4, *iter);
+    CORE_TEST_EQUAL(3, *(++iter));
+    CORE_TEST_EQUAL(2, *(++iter));
+    CORE_TEST_EQUAL(3, list.getLength());
 }
 
-static void testClear(Core::Test& test) {
+static void testClear() {
     IntList list;
-    test.checkFalse(list.add(5) == nullptr, "add works 6");
-    test.checkFalse(list.add(4) == nullptr, "add works 7");
+    CORE_TEST_NOT_NULL(list.add(5));
+    CORE_TEST_NOT_NULL(list.add(4));
     list.clear();
-    test.checkEqual(0, list.getLength(), "length is 0 after clear");
-    test.checkFalse(list.begin() != list.end(),
-                    "iterator is at end after clear");
+    CORE_TEST_EQUAL(0, list.getLength());
+    CORE_TEST_FALSE(list.begin() != list.end());
 }
 
-static void testBigAdd(Core::Test& test) {
+static void testBigAdd() {
     IntList list;
-    for(int i = 0; i < 1000000; i++) {
-        test.checkFalse(list.add(i) == nullptr, "add works in big add");
+    for(int i = 0; i < 100000; i++) {
+        CORE_TEST_NOT_NULL(list.add(i));
     }
     auto iter = list.begin();
     for(int i = 0; i < list.getLength(); i++) {
-        test.checkEqual(i, *iter, "big add");
+        CORE_TEST_EQUAL(i, *iter);
         ++iter;
     }
-    test.checkEqual(1000000, list.getLength(), "big add length");
+    CORE_TEST_EQUAL(100000, list.getLength());
 }
 
-static void testCopy(Core::Test& test) {
+static void testCopy() {
     IntList list;
-    test.checkFalse(list.add(1) == nullptr, "add works 11");
-    test.checkFalse(list.add(2) == nullptr, "add works 12");
-    test.checkFalse(list.add(3) == nullptr, "add works 13");
+    CORE_TEST_NOT_NULL(list.add(1));
+    CORE_TEST_NOT_NULL(list.add(2));
+    CORE_TEST_NOT_NULL(list.add(3));
 
     IntList copy;
-    test.checkFalse(copy.copyFrom(list), "copy works 1");
-    test.checkEqual(list.getLength(), copy.getLength(), "copy has same length");
+    CORE_TEST_FALSE(copy.copyFrom(list));
+    CORE_TEST_EQUAL(list.getLength(), copy.getLength());
     auto iterA = list.begin();
     auto iterB = copy.begin();
     for(int i = 0; i < copy.getLength() && i < list.getLength(); i++) {
-        test.checkEqual(*iterA, *iterB, "copy has same values");
+        CORE_TEST_EQUAL(*iterA, *iterB);
         ++iterA;
         ++iterB;
     }
 }
 
-static void testMove(Core::Test& test) {
+static void testMove() {
     IntList list;
-    test.checkFalse(list.add(1) == nullptr, "add works 14");
-    test.checkFalse(list.add(2) == nullptr, "add works 15");
-    test.checkFalse(list.add(3) == nullptr, "add works 16");
+    CORE_TEST_NOT_NULL(list.add(1));
+    CORE_TEST_NOT_NULL(list.add(2));
+    CORE_TEST_NOT_NULL(list.add(3));
 
     const IntList move(Core::move(list));
-    test.checkEqual(0, list.getLength(), "moved has length 0");
-    test.checkEqual(3, move.getLength(), "moved passes length");
+    CORE_TEST_EQUAL(0, list.getLength());
+    CORE_TEST_EQUAL(3, move.getLength());
     auto iter = move.begin();
-    test.checkEqual(1, *iter, "moved passes values");
-    test.checkEqual(2, *(++iter), "moved passes values");
-    test.checkEqual(3, *(++iter), "moved passes values");
+    CORE_TEST_EQUAL(1, *iter);
+    CORE_TEST_EQUAL(2, *(++iter));
+    CORE_TEST_EQUAL(3, *(++iter));
 }
 
-static void testMoveAssignment(Core::Test& test) {
+static void testMoveAssignment() {
     IntList list;
-    test.checkFalse(list.add(1) == nullptr, "add works 17");
-    test.checkFalse(list.add(2) == nullptr, "add works 18");
-    test.checkFalse(list.add(3) == nullptr, "add works 19");
+    CORE_TEST_NOT_NULL(list.add(1));
+    CORE_TEST_NOT_NULL(list.add(2));
+    CORE_TEST_NOT_NULL(list.add(3));
 
     IntList move;
     move = Core::move(list);
-    test.checkEqual(0, list.getLength(), "assignment moved has length 0");
-    test.checkEqual(3, move.getLength(), "assignment moved passes length");
+    CORE_TEST_EQUAL(0, list.getLength());
+    CORE_TEST_EQUAL(3, move.getLength());
     auto iter = move.begin();
-    test.checkEqual(1, *iter, "assignment moved passes values");
-    test.checkEqual(2, *(++iter), "assignment moved passes values");
-    test.checkEqual(3, *(++iter), "assignment moved passes values");
+    CORE_TEST_EQUAL(1, *iter);
+    CORE_TEST_EQUAL(2, *(++iter));
+    CORE_TEST_EQUAL(3, *(++iter));
 }
 
-static void testToString1(Core::Test& test) {
+static void testToString1() {
     IntList list;
-    test.checkFalse(list.add(1) == nullptr, "add works 20");
-    test.checkFalse(list.add(243) == nullptr, "add works 21");
-    test.checkFalse(list.add(-423) == nullptr, "add works 22");
-    test.checkEqual(build(test, "[1, 243, -423]"), build(test, list),
-                    "to string 1");
+    CORE_TEST_NOT_NULL(list.add(1));
+    CORE_TEST_NOT_NULL(list.add(243));
+    CORE_TEST_NOT_NULL(list.add(-423));
+    CORE_TEST_EQUAL(build("[1, 243, -423]"), build(list));
 }
 
-static void testToString2(Core::Test& test) {
+static void testToString2() {
     IntList list;
-    test.checkFalse(list.add(1) == nullptr, "add works 23");
-    test.checkEqual(build(test, "[1]"), build(test, list), "to string 2");
+    CORE_TEST_NOT_NULL(list.add(1));
+    CORE_TEST_EQUAL(build("[1]"), build(list));
 }
 
-static void testToString3(Core::Test& test) {
+static void testToString3() {
     IntList list;
-    test.checkEqual(build(test, "[]"), build(test, list), "to string 3");
+    CORE_TEST_EQUAL(build("[]"), build(list));
 }
 
-static void testRemove(Core::Test& test) {
+static void testRemove() {
     IntList list;
     IntList::Node* a = list.add(4);
     IntList::Node* b = list.add(3);
     IntList::Node* c = list.add(2);
     IntList::Node* d = list.add(1);
-    test.checkFalse(a == nullptr, "add works 24");
-    test.checkFalse(b == nullptr, "add works 25");
-    test.checkFalse(c == nullptr, "add works 26");
-    test.checkFalse(c == nullptr, "add works 27");
+    CORE_TEST_NOT_NULL(a);
+    CORE_TEST_NOT_NULL(b);
+    CORE_TEST_NOT_NULL(c);
+    CORE_TEST_NOT_NULL(c);
 
     list.remove(b);
     auto iter = list.begin();
-    test.checkEqual(4, *iter, "value after remove 1");
-    test.checkEqual(2, *(++iter), "value after remove 2");
-    test.checkEqual(1, *(++iter), "value after remove 3");
-    test.checkEqual(3, list.getLength(), "size after remove 1");
+    CORE_TEST_EQUAL(4, *iter);
+    CORE_TEST_EQUAL(2, *(++iter));
+    CORE_TEST_EQUAL(1, *(++iter));
+    CORE_TEST_EQUAL(3, list.getLength());
 
     list.remove(a);
     iter = list.begin();
-    test.checkEqual(2, *iter, "value after remove 4");
-    test.checkEqual(1, *(++iter), "value after remove 5");
-    test.checkEqual(2, list.getLength(), "size after remove 2");
+    CORE_TEST_EQUAL(2, *iter);
+    CORE_TEST_EQUAL(1, *(++iter));
+    CORE_TEST_EQUAL(2, list.getLength());
 
     list.remove(d);
     iter = list.begin();
-    test.checkEqual(2, *iter, "value after remove 6");
-    test.checkEqual(1, list.getLength(), "size after remove 3");
+    CORE_TEST_EQUAL(2, *iter);
+    CORE_TEST_EQUAL(1, list.getLength());
 
     list.remove(c);
-    test.checkFalse(list.begin() != list.end(), "empty iterator after remove");
-    test.checkEqual(0, list.getLength(), "size after remove 4");
+    CORE_TEST_FALSE(list.begin() != list.end());
+    CORE_TEST_EQUAL(0, list.getLength());
 
-    test.checkTrue(a == nullptr, "nodes are null after remove 1");
-    test.checkTrue(b == nullptr, "nodes are null after remove 2");
-    test.checkTrue(c == nullptr, "nodes are null after remove 3");
-    test.checkTrue(c == nullptr, "nodes are null after remove 4");
+    CORE_TEST_NULL(a);
+    CORE_TEST_NULL(b);
+    CORE_TEST_NULL(c);
+    CORE_TEST_NULL(c);
 }
 
-static void testRemoveFirst(Core::Test& test) {
+static void testRemoveFirst() {
     IntList list;
-    test.checkFalse(list.add(4) == nullptr, "add works 28");
-    test.checkFalse(list.add(3) == nullptr, "add works 29");
-    test.checkFalse(list.add(2) == nullptr, "add works 30");
-    test.checkFalse(list.add(1) == nullptr, "add works 31");
+    CORE_TEST_NOT_NULL(list.add(4));
+    CORE_TEST_NOT_NULL(list.add(3));
+    CORE_TEST_NOT_NULL(list.add(2));
+    CORE_TEST_NOT_NULL(list.add(1));
 
     list.removeFirst();
     auto iter = list.begin();
-    test.checkEqual(3, *iter, "value after remove first 1");
-    test.checkEqual(2, *(++iter), "value after remove first 2");
-    test.checkEqual(1, *(++iter), "value after remove first 3");
-    test.checkEqual(3, list.getLength(), "size after remove first 1");
+    CORE_TEST_EQUAL(3, *iter);
+    CORE_TEST_EQUAL(2, *(++iter));
+    CORE_TEST_EQUAL(1, *(++iter));
+    CORE_TEST_EQUAL(3, list.getLength());
 
     list.removeFirst();
     iter = list.begin();
-    test.checkEqual(2, *iter, "value after remove first 4");
-    test.checkEqual(1, *(++iter), "value after remove first 5");
-    test.checkEqual(2, list.getLength(), "size after remove first 2");
+    CORE_TEST_EQUAL(2, *iter);
+    CORE_TEST_EQUAL(1, *(++iter));
+    CORE_TEST_EQUAL(2, list.getLength());
 
     list.removeFirst();
     iter = list.begin();
-    test.checkEqual(1, *iter, "value after remove first 6");
-    test.checkEqual(1, list.getLength(), "size after remove first 3");
+    CORE_TEST_EQUAL(1, *iter);
+    CORE_TEST_EQUAL(1, list.getLength());
 
     list.removeFirst();
-    test.checkFalse(list.begin() != list.end(),
-                    "empty iterator after remove first");
-    test.checkEqual(0, list.getLength(), "size after remove first 4");
+    CORE_TEST_FALSE(list.begin() != list.end());
+    CORE_TEST_EQUAL(0, list.getLength());
 
     list.removeFirst();
-    test.checkFalse(list.begin() != list.end(),
-                    "empty iterator after remove first");
-    test.checkEqual(0, list.getLength(), "size after remove first 5");
+    CORE_TEST_FALSE(list.begin() != list.end());
+    CORE_TEST_EQUAL(0, list.getLength());
 }
 
-static void testRemoveLast(Core::Test& test) {
+static void testRemoveLast() {
     IntList list;
-    test.checkFalse(list.add(4) == nullptr, "add works 32");
-    test.checkFalse(list.add(3) == nullptr, "add works 33");
-    test.checkFalse(list.add(2) == nullptr, "add works 34");
-    test.checkFalse(list.add(1) == nullptr, "add works 35");
+    CORE_TEST_NOT_NULL(list.add(4));
+    CORE_TEST_NOT_NULL(list.add(3));
+    CORE_TEST_NOT_NULL(list.add(2));
+    CORE_TEST_NOT_NULL(list.add(1));
 
     list.removeLast();
     auto iter = list.begin();
-    test.checkEqual(4, *iter, "value after remove last 1");
-    test.checkEqual(3, *(++iter), "value after remove last 2");
-    test.checkEqual(2, *(++iter), "value after remove last 3");
-    test.checkEqual(3, list.getLength(), "size after remove last 1");
+    CORE_TEST_EQUAL(4, *iter);
+    CORE_TEST_EQUAL(3, *(++iter));
+    CORE_TEST_EQUAL(2, *(++iter));
+    CORE_TEST_EQUAL(3, list.getLength());
 
     list.removeLast();
     iter = list.begin();
-    test.checkEqual(4, *iter, "value after remove last 4");
-    test.checkEqual(3, *(++iter), "value after remove last 5");
-    test.checkEqual(2, list.getLength(), "size after remove last 2");
+    CORE_TEST_EQUAL(4, *iter);
+    CORE_TEST_EQUAL(3, *(++iter));
+    CORE_TEST_EQUAL(2, list.getLength());
 
     list.removeLast();
     iter = list.begin();
-    test.checkEqual(4, *iter, "value after remove last 6");
-    test.checkEqual(1, list.getLength(), "size after remove last 3");
+    CORE_TEST_EQUAL(4, *iter);
+    CORE_TEST_EQUAL(1, list.getLength());
 
     list.removeLast();
-    test.checkFalse(list.begin() != list.end(),
-                    "empty iterator after remove last");
-    test.checkEqual(0, list.getLength(), "size after remove last 4");
+    CORE_TEST_FALSE(list.begin() != list.end());
+    CORE_TEST_EQUAL(0, list.getLength());
 
     list.removeLast();
-    test.checkFalse(list.begin() != list.end(),
-                    "empty iterator after remove last");
-    test.checkEqual(0, list.getLength(), "size after remove 5");
+    CORE_TEST_FALSE(list.begin() != list.end());
+    CORE_TEST_EQUAL(0, list.getLength());
 }
 
 void Core::LinkedListTests::test() {
-    Core::Test test("LinkedList");
-    testWithoutCopyOrMove(test);
-    testAdd(test);
-    testMultipleAdd(test);
-    testClear(test);
-    testBigAdd(test);
-    testCopy(test);
-    testMove(test);
-    testMoveAssignment(test);
-    testToString1(test);
-    testToString2(test);
-    testToString3(test);
-    testRemove(test);
-    testRemoveFirst(test);
-    testRemoveLast(test);
-    test.finalize();
+    testWithoutCopyOrMove();
+    testAdd();
+    testMultipleAdd();
+    testClear();
+    testBigAdd();
+    testCopy();
+    testMove();
+    testMoveAssignment();
+    testToString1();
+    testToString2();
+    testToString3();
+    testRemove();
+    testRemoveFirst();
+    testRemoveLast();
 }

+ 128 - 131
tests/ListTests.cpp

@@ -7,206 +7,203 @@ using IntList = Core::List<int>;
 using String = Core::ArrayString<128>;
 
 template<typename T>
-static String build(Core::Test& test, const T& t) {
+static String build(const T& t) {
     String s;
-    test.checkFalse(s.append(t), "append works");
+    CORE_TEST_FALSE(s.append(t));
     return s;
 }
 
-static void testAdd(Core::Test& test) {
+static void testAdd() {
     IntList list;
-    test.checkFalse(list.add(5), "add works 1");
-    test.checkEqual(5, list[0], "contains added value");
-    test.checkEqual(1, list.getLength(), "sizes is increased by add");
+    CORE_TEST_NOT_NULL(list.add(5));
+    CORE_TEST_EQUAL(5, list[0]);
+    CORE_TEST_EQUAL(1, list.getLength());
 }
 
-static void testMultipleAdd(Core::Test& test) {
+static void testMultipleAdd() {
     IntList list;
-    test.checkFalse(list.add(4), "add works 2");
-    test.checkFalse(list.add(3), "add works 3");
-    test.checkFalse(list.add(2), "add works 4");
-    test.checkEqual(4, list[0], "contains added value 1");
-    test.checkEqual(3, list[1], "contains added value 2");
-    test.checkEqual(2, list[2], "contains added value 3");
-    test.checkEqual(3, list.getLength(), "sizes is increased by add");
+    CORE_TEST_NOT_NULL(list.add(4));
+    CORE_TEST_NOT_NULL(list.add(3));
+    CORE_TEST_NOT_NULL(list.add(2));
+    CORE_TEST_EQUAL(4, list[0]);
+    CORE_TEST_EQUAL(3, list[1]);
+    CORE_TEST_EQUAL(2, list[2]);
+    CORE_TEST_EQUAL(3, list.getLength());
 }
 
-static void testAddReplace(Core::Test& test) {
+static void testAddReplace() {
     IntList list;
-    test.checkFalse(list.add(5), "add works 5");
+    CORE_TEST_NOT_NULL(list.add(5));
     list[0] = 3;
-    test.checkEqual(3, list[0], "value is overwritten");
+    CORE_TEST_EQUAL(3, list[0]);
 }
 
-static void testClear(Core::Test& test) {
+static void testClear() {
     IntList list;
-    test.checkFalse(list.add(5), "add works 6");
-    test.checkFalse(list.add(4), "add works 7");
+    CORE_TEST_NOT_NULL(list.add(5));
+    CORE_TEST_NOT_NULL(list.add(4));
     list.clear();
-    test.checkEqual(0, list.getLength(), "length is 0 after clear");
+    CORE_TEST_EQUAL(0, list.getLength());
 }
 
-static void testShrink(Core::Test& test) {
+static void testShrink() {
     IntList list;
-    test.checkFalse(list.add(5), "add works 8");
-    test.checkFalse(list.add(4), "add works 9");
-    test.checkFalse(list.add(3), "add works 10");
-    test.checkTrue(list.getCapacity() >= 3, "capacity is >= 3 after adding");
-    test.checkFalse(list.shrink(), "shrink works 1");
-    test.checkTrue(list.getLength() == 3, "length is 3 after shrink");
-    test.checkTrue(list.getCapacity() == 3, "capacity is 3 after shrink");
-    test.checkEqual(5, list[0], "data ok after shrink 1");
-    test.checkEqual(4, list[1], "data ok after shrink 2");
-    test.checkEqual(3, list[2], "data ok after shrink 3");
+    CORE_TEST_NOT_NULL(list.add(5));
+    CORE_TEST_NOT_NULL(list.add(4));
+    CORE_TEST_NOT_NULL(list.add(3));
+    CORE_TEST_TRUE(list.getCapacity() >= 3);
+    CORE_TEST_FALSE(list.shrink());
+    CORE_TEST_TRUE(list.getLength() == 3);
+    CORE_TEST_TRUE(list.getCapacity() == 3);
+    CORE_TEST_EQUAL(5, list[0]);
+    CORE_TEST_EQUAL(4, list[1]);
+    CORE_TEST_EQUAL(3, list[2]);
 }
 
-static void testBigAdd(Core::Test& test) {
+static void testBigAdd() {
     IntList list;
-    for(int i = 0; i < 1000000; i++) {
-        test.checkFalse(list.add(i), "add works in big add");
+    for(int i = 0; i < 100000; i++) {
+        CORE_TEST_NOT_NULL(list.add(i));
     }
     for(int i = 0; i < list.getLength(); i++) {
-        test.checkEqual(i, list[i], "big add");
+        CORE_TEST_EQUAL(i, list[i]);
     }
-    test.checkEqual(1000000, list.getLength(), "big add length");
+    CORE_TEST_EQUAL(100000, list.getLength());
 }
 
-static void testCopy(Core::Test& test) {
+static void testCopy() {
     IntList list;
-    test.checkFalse(list.add(1), "add works 11");
-    test.checkFalse(list.add(2), "add works 12");
-    test.checkFalse(list.add(3), "add works 13");
+    CORE_TEST_NOT_NULL(list.add(1));
+    CORE_TEST_NOT_NULL(list.add(2));
+    CORE_TEST_NOT_NULL(list.add(3));
 
     IntList copy;
-    test.checkFalse(copy.copyFrom(list), "copy works 1");
-    test.checkEqual(list.getLength(), copy.getLength(), "copy has same length");
+    CORE_TEST_FALSE(copy.copyFrom(list));
+    CORE_TEST_EQUAL(list.getLength(), copy.getLength());
     for(int i = 0; i < copy.getLength() && i < list.getLength(); i++) {
-        test.checkEqual(list[i], copy[i], "copy has same values");
+        CORE_TEST_EQUAL(list[i], copy[i]);
     }
 }
 
-static void testMove(Core::Test& test) {
+static void testMove() {
     IntList list;
-    test.checkFalse(list.add(1), "add works 14");
-    test.checkFalse(list.add(2), "add works 15");
-    test.checkFalse(list.add(3), "add works 16");
+    CORE_TEST_NOT_NULL(list.add(1));
+    CORE_TEST_NOT_NULL(list.add(2));
+    CORE_TEST_NOT_NULL(list.add(3));
 
     IntList move(Core::move(list));
-    test.checkEqual(0, list.getLength(), "moved has length 0");
-    test.checkEqual(3, move.getLength(), "moved passes length");
-    test.checkEqual(1, move[0], "moved passes values");
-    test.checkEqual(2, move[1], "moved passes values");
-    test.checkEqual(3, move[2], "moved passes values");
+    CORE_TEST_EQUAL(0, list.getLength());
+    CORE_TEST_EQUAL(3, move.getLength());
+    CORE_TEST_EQUAL(1, move[0]);
+    CORE_TEST_EQUAL(2, move[1]);
+    CORE_TEST_EQUAL(3, move[2]);
 }
 
-static void testMoveAssignment(Core::Test& test) {
+static void testMoveAssignment() {
     IntList list;
-    test.checkFalse(list.add(1), "add works 17");
-    test.checkFalse(list.add(2), "add works 18");
-    test.checkFalse(list.add(3), "add works 19");
+    CORE_TEST_NOT_NULL(list.add(1));
+    CORE_TEST_NOT_NULL(list.add(2));
+    CORE_TEST_NOT_NULL(list.add(3));
 
     IntList move;
     move = Core::move(list);
-    test.checkEqual(0, list.getLength(), "assignment moved has length 0");
-    test.checkEqual(3, move.getLength(), "assignment moved passes length");
-    test.checkEqual(1, move[0], "assignment moved passes values");
-    test.checkEqual(2, move[1], "assignment moved passes values");
-    test.checkEqual(3, move[2], "assignment moved passes values");
+    CORE_TEST_EQUAL(0, list.getLength());
+    CORE_TEST_EQUAL(3, move.getLength());
+    CORE_TEST_EQUAL(1, move[0]);
+    CORE_TEST_EQUAL(2, move[1]);
+    CORE_TEST_EQUAL(3, move[2]);
 }
 
-static void testToString1(Core::Test& test) {
+static void testToString1() {
     IntList list;
-    test.checkFalse(list.add(1), "add works 20");
-    test.checkFalse(list.add(243), "add works 21");
-    test.checkFalse(list.add(-423), "add works 22");
-    test.checkEqual(build(test, "[1, 243, -423]"), build(test, list),
-                    "to string 1");
+    CORE_TEST_NOT_NULL(list.add(1));
+    CORE_TEST_NOT_NULL(list.add(243));
+    CORE_TEST_NOT_NULL(list.add(-423));
+    CORE_TEST_EQUAL(build("[1, 243, -423]"), build(list));
 }
 
-static void testToString2(Core::Test& test) {
+static void testToString2() {
     IntList list;
-    test.checkFalse(list.add(1), "add works 23");
-    test.checkEqual(build(test, "[1]"), build(test, list), "to string 2");
+    CORE_TEST_NOT_NULL(list.add(1));
+    CORE_TEST_EQUAL(build("[1]"), build(list));
 }
 
-static void testToString3(Core::Test& test) {
+static void testToString3() {
     IntList list;
-    test.checkEqual(build(test, "[]"), build(test, list), "to string 3");
+    CORE_TEST_EQUAL(build("[]"), build(list));
 }
 
-static void testRemoveBySwap(Core::Test& test) {
+static void testRemoveBySwap() {
     IntList list;
-    test.checkFalse(list.add(4), "add works 24");
-    test.checkFalse(list.add(3), "add works 25");
-    test.checkFalse(list.add(2), "add works 26");
-    test.checkTrue(list.removeBySwap(-1), "remove by swap does not work 1");
-    test.checkFalse(list.removeBySwap(0), "remove by swap works 1");
-    test.checkTrue(list.removeBySwap(2), "remove by swap does not work 2");
-    test.checkEqual(2, list[0], "remove by swap 1");
-    test.checkEqual(3, list[1], "remove by swap 2");
-    test.checkEqual(2, list.getLength(), "remove by swap 3");
-    test.checkFalse(list.removeBySwap(1), "remove by swap works 2");
-    test.checkEqual(2, list[0], "remove by swap 4");
-    test.checkEqual(1, list.getLength(), "remove by swap 5");
-    test.checkFalse(list.removeBySwap(0), "remove by swap works 3");
-    test.checkEqual(0, list.getLength(), "remove by swap 6");
-    test.checkTrue(list.removeBySwap(0), "remove by swap does not work 3");
+    CORE_TEST_NOT_NULL(list.add(4));
+    CORE_TEST_NOT_NULL(list.add(3));
+    CORE_TEST_NOT_NULL(list.add(2));
+    CORE_TEST_TRUE(list.removeBySwap(-1));
+    CORE_TEST_FALSE(list.removeBySwap(0));
+    CORE_TEST_TRUE(list.removeBySwap(2));
+    CORE_TEST_EQUAL(2, list[0]);
+    CORE_TEST_EQUAL(3, list[1]);
+    CORE_TEST_EQUAL(2, list.getLength());
+    CORE_TEST_FALSE(list.removeBySwap(1));
+    CORE_TEST_EQUAL(2, list[0]);
+    CORE_TEST_EQUAL(1, list.getLength());
+    CORE_TEST_FALSE(list.removeBySwap(0));
+    CORE_TEST_EQUAL(0, list.getLength());
+    CORE_TEST_TRUE(list.removeBySwap(0));
 }
 
-static void testRemove(Core::Test& test) {
+static void testRemove() {
     IntList list;
-    test.checkFalse(list.add(4), "add works 27");
-    test.checkFalse(list.add(3), "add works 28");
-    test.checkFalse(list.add(2), "add works 29");
-    test.checkTrue(list.remove(-1), "remove does not work 1");
-    test.checkFalse(list.remove(0), "remove works 1");
-    test.checkTrue(list.remove(2), "remove does not work 2");
-    test.checkEqual(3, list[0], "remove 1");
-    test.checkEqual(2, list[1], "remove 2");
-    test.checkEqual(2, list.getLength(), "remove 3");
-    test.checkFalse(list.remove(1), "remove works 2");
-    test.checkEqual(3, list[0], "remove 4");
-    test.checkEqual(1, list.getLength(), "remove 5");
-    test.checkFalse(list.remove(0), "remove works 3");
-    test.checkEqual(0, list.getLength(), "remove 6");
-    test.checkTrue(list.remove(0), "remove does not work 3");
+    CORE_TEST_NOT_NULL(list.add(4));
+    CORE_TEST_NOT_NULL(list.add(3));
+    CORE_TEST_NOT_NULL(list.add(2));
+    CORE_TEST_TRUE(list.remove(-1));
+    CORE_TEST_FALSE(list.remove(0));
+    CORE_TEST_TRUE(list.remove(2));
+    CORE_TEST_EQUAL(3, list[0]);
+    CORE_TEST_EQUAL(2, list[1]);
+    CORE_TEST_EQUAL(2, list.getLength());
+    CORE_TEST_FALSE(list.remove(1));
+    CORE_TEST_EQUAL(3, list[0]);
+    CORE_TEST_EQUAL(1, list.getLength());
+    CORE_TEST_FALSE(list.remove(0));
+    CORE_TEST_EQUAL(0, list.getLength());
+    CORE_TEST_TRUE(list.remove(0));
 }
 
-static void testResize(Core::Test& test) {
+static void testResize() {
     IntList list;
-    test.checkFalse(list.resize(5, 10), "resize works");
-    test.checkEqual(5, list.getLength(), "correct size after resize");
+    CORE_TEST_FALSE(list.resize(5, 10));
+    CORE_TEST_EQUAL(5, list.getLength());
     for(int i = 0; i < 5; i++) {
-        test.checkEqual(10, list[i], "correct content after resize");
+        CORE_TEST_EQUAL(10, list[i]);
     }
 }
 
-static void testDefaultResize(Core::Test& test) {
+static void testDefaultResize() {
     IntList list;
-    test.checkFalse(list.resize(5), "default resize works 1");
-    test.checkEqual(5, list.getLength(), "correct size after default resize");
+    CORE_TEST_FALSE(list.resize(5));
+    CORE_TEST_EQUAL(5, list.getLength());
     for(int i = 0; i < 5; i++) {
-        test.checkEqual(0, list[i], "correct content after default resize");
+        CORE_TEST_EQUAL(0, list[i]);
     }
 }
 
 void Core::ListTests::test() {
-    Core::Test test("List");
-    testAdd(test);
-    testMultipleAdd(test);
-    testAddReplace(test);
-    testClear(test);
-    testShrink(test);
-    testBigAdd(test);
-    testCopy(test);
-    testMove(test);
-    testMoveAssignment(test);
-    testToString1(test);
-    testToString2(test);
-    testToString3(test);
-    testRemoveBySwap(test);
-    testRemove(test);
-    testResize(test);
-    testDefaultResize(test);
-    test.finalize();
+    testAdd();
+    testMultipleAdd();
+    testAddReplace();
+    testClear();
+    testShrink();
+    testBigAdd();
+    testCopy();
+    testMove();
+    testMoveAssignment();
+    testToString1();
+    testToString2();
+    testToString3();
+    testRemoveBySwap();
+    testRemove();
+    testResize();
+    testDefaultResize();
 }

+ 38 - 46
tests/MathTests.cpp

@@ -5,61 +5,53 @@
 
 constexpr float eps = 0.0001f;
 
-static void testInterpolate(Core::Test& test) {
-    test.checkFloat(7.5f, Core::Math::interpolate(5.0f, 10.0f, 0.5f), eps,
-                    "interpolate 1");
-    test.checkFloat(-2.0, Core::Math::interpolate(-10.0f, 10.0f, 0.4f), eps,
-                    "interpolate 2");
-    test.checkFloat(10.0f, Core::Math::interpolate(-3.0f, 10.0f, 1.0f), eps,
-                    "interpolate 3");
-    test.checkFloat(7.0f, Core::Math::interpolate(7.0f, 10.0f, 0.0f), eps,
-                    "interpolate 4");
-    test.checkFloat(6.0f, Core::Math::interpolate(0.0f, 10.0f, 0.6f), eps,
-                    "interpolate 5");
+static void testInterpolate() {
+    CORE_TEST_FLOAT(7.5f, Core::Math::interpolate(5.0f, 10.0f, 0.5f), eps);
+    CORE_TEST_FLOAT(-2.0, Core::Math::interpolate(-10.0f, 10.0f, 0.4f), eps);
+    CORE_TEST_FLOAT(10.0f, Core::Math::interpolate(-3.0f, 10.0f, 1.0f), eps);
+    CORE_TEST_FLOAT(7.0f, Core::Math::interpolate(7.0f, 10.0f, 0.0f), eps);
+    CORE_TEST_FLOAT(6.0f, Core::Math::interpolate(0.0f, 10.0f, 0.6f), eps);
 }
 
-static void testRoundUpLog2(Core::Test& test) {
-    test.checkEqual(0, Core::Math::roundUpLog2(-5), "round up log2 1");
-    test.checkEqual(0, Core::Math::roundUpLog2(0), "round up log2 2");
-    test.checkEqual(1, Core::Math::roundUpLog2(1), "round up log2 3");
-    test.checkEqual(1, Core::Math::roundUpLog2(2), "round up log2 4");
-    test.checkEqual(2, Core::Math::roundUpLog2(3), "round up log2 5");
-    test.checkEqual(2, Core::Math::roundUpLog2(4), "round up log2 6");
-    test.checkEqual(3, Core::Math::roundUpLog2(5), "round up log2 7");
-    test.checkEqual(4, Core::Math::roundUpLog2(10), "round up log2 8");
-    test.checkEqual(5, Core::Math::roundUpLog2(20), "round up log2 9");
-    test.checkEqual(16, Core::Math::roundUpLog2(35345), "round up log2 10");
-    test.checkEqual(31, Core::Math::roundUpLog2(0x7FFFFFFF),
-                    "round up log2 11");
+static void testRoundUpLog2() {
+    CORE_TEST_EQUAL(0, Core::Math::roundUpLog2(-5));
+    CORE_TEST_EQUAL(0, Core::Math::roundUpLog2(0));
+    CORE_TEST_EQUAL(1, Core::Math::roundUpLog2(1));
+    CORE_TEST_EQUAL(1, Core::Math::roundUpLog2(2));
+    CORE_TEST_EQUAL(2, Core::Math::roundUpLog2(3));
+    CORE_TEST_EQUAL(2, Core::Math::roundUpLog2(4));
+    CORE_TEST_EQUAL(3, Core::Math::roundUpLog2(5));
+    CORE_TEST_EQUAL(4, Core::Math::roundUpLog2(10));
+    CORE_TEST_EQUAL(5, Core::Math::roundUpLog2(20));
+    CORE_TEST_EQUAL(16, Core::Math::roundUpLog2(35345));
+    CORE_TEST_EQUAL(31, Core::Math::roundUpLog2(0x7FFFFFFF));
 }
 
-static void testMin(Core::Test& test) {
-    test.checkEqual(-5, Core::Math::min(-5), "min 1");
-    test.checkEqual(-10, Core::Math::min(-5, 4, 3, 2, -10), "min 2");
-    test.checkEqual(4, Core::Math::min(5, 20, 4, 30), "min 3");
+static void testMin() {
+    CORE_TEST_EQUAL(-5, Core::Math::min(-5));
+    CORE_TEST_EQUAL(-10, Core::Math::min(-5, 4, 3, 2, -10));
+    CORE_TEST_EQUAL(4, Core::Math::min(5, 20, 4, 30));
 }
 
-static void testMax(Core::Test& test) {
-    test.checkEqual(-5, Core::Math::max(-5), "max 1");
-    test.checkEqual(4, Core::Math::max(-5, 4, 3, 2, -10), "max 2");
-    test.checkEqual(30, Core::Math::max(5, 20, 4, 30), "max 3");
+static void testMax() {
+    CORE_TEST_EQUAL(-5, Core::Math::max(-5));
+    CORE_TEST_EQUAL(4, Core::Math::max(-5, 4, 3, 2, -10));
+    CORE_TEST_EQUAL(30, Core::Math::max(5, 20, 4, 30));
 }
 
-static void testClamp(Core::Test& test) {
-    test.checkEqual(5, Core::Math::clamp(1, 5, 10), "clamp 1");
-    test.checkEqual(7, Core::Math::clamp(7, 5, 10), "clamp 2");
-    test.checkEqual(10, Core::Math::clamp(20, 5, 10), "clamp 3");
-    test.checkEqual(5, Core::Math::clamp(1, 10, 5), "clamp 4");
-    test.checkEqual(7, Core::Math::clamp(7, 10, 5), "clamp 5");
-    test.checkEqual(10, Core::Math::clamp(20, 10, 5), "clamp 6");
+static void testClamp() {
+    CORE_TEST_EQUAL(5, Core::Math::clamp(1, 5, 10));
+    CORE_TEST_EQUAL(7, Core::Math::clamp(7, 5, 10));
+    CORE_TEST_EQUAL(10, Core::Math::clamp(20, 5, 10));
+    CORE_TEST_EQUAL(5, Core::Math::clamp(1, 10, 5));
+    CORE_TEST_EQUAL(7, Core::Math::clamp(7, 10, 5));
+    CORE_TEST_EQUAL(10, Core::Math::clamp(20, 10, 5));
 }
 
 void Core::MathTests::test() {
-    Core::Test test("Math");
-    testInterpolate(test);
-    testRoundUpLog2(test);
-    testMin(test);
-    testMax(test);
-    testClamp(test);
-    test.finalize();
+    testInterpolate();
+    testRoundUpLog2();
+    testMin();
+    testMax();
+    testClamp();
 }

+ 88 - 0
tests/RingBufferTests.cpp

@@ -0,0 +1,88 @@
+#include "tests/RingBufferTests.h"
+
+#include "data/RingBuffer.h"
+#include "test/Test.h"
+
+static void testReadAndWrite() {
+    Core::RingBuffer<int, 5> buffer;
+    CORE_TEST_FALSE(buffer.canRemove());
+    CORE_TEST_EQUAL(0, buffer.getLength());
+    buffer.add(4);
+    CORE_TEST_EQUAL(1, buffer.getLength());
+    CORE_TEST_TRUE(buffer.canRemove());
+    CORE_TEST_EQUAL(4, buffer[0]);
+    CORE_TEST_FALSE(buffer.remove());
+    CORE_TEST_FALSE(buffer.canRemove());
+    CORE_TEST_EQUAL(0, buffer.getLength());
+}
+
+static void testOverflow() {
+    Core::RingBuffer<int, 3> buffer;
+    bool r1 = buffer.add(1);
+    bool r2 = buffer.add(2);
+    bool r3 = buffer.add(3);
+    bool r4 = buffer.add(4);
+    bool r5 = buffer.add(5);
+    CORE_TEST_EQUAL(3, buffer.getLength());
+    CORE_TEST_FALSE(r1);
+    CORE_TEST_FALSE(r2);
+    CORE_TEST_FALSE(r3);
+    CORE_TEST_TRUE(r4);
+    CORE_TEST_TRUE(r5);
+    CORE_TEST_EQUAL(1, buffer[0]);
+    CORE_TEST_FALSE(buffer.remove());
+    CORE_TEST_EQUAL(2, buffer.getLength());
+    CORE_TEST_EQUAL(2, buffer[0]);
+    CORE_TEST_FALSE(buffer.remove());
+    CORE_TEST_EQUAL(1, buffer.getLength());
+    CORE_TEST_EQUAL(3, buffer[0]);
+    CORE_TEST_FALSE(buffer.remove());
+    CORE_TEST_FALSE(buffer.canRemove());
+    CORE_TEST_EQUAL(0, buffer.getLength());
+}
+
+static void testRefill() {
+    Core::RingBuffer<int, 3> buffer;
+    buffer.add(1);
+    buffer.add(2);
+    buffer.add(3);
+    buffer.add(4);
+    CORE_TEST_EQUAL(3, buffer.getLength());
+    CORE_TEST_TRUE(buffer.canRemove());
+    CORE_TEST_EQUAL(1, buffer[0]);
+    CORE_TEST_FALSE(buffer.remove());
+    CORE_TEST_EQUAL(2, buffer[0]);
+    CORE_TEST_FALSE(buffer.remove());
+    CORE_TEST_EQUAL(3, buffer[0]);
+    CORE_TEST_FALSE(buffer.remove());
+    CORE_TEST_EQUAL(0, buffer.getLength());
+
+    CORE_TEST_FALSE(buffer.canRemove());
+    buffer.add(5);
+    buffer.add(6);
+    CORE_TEST_EQUAL(2, buffer.getLength());
+    CORE_TEST_TRUE(buffer.canRemove());
+    CORE_TEST_EQUAL(5, buffer[0]);
+    CORE_TEST_FALSE(buffer.remove());
+    CORE_TEST_EQUAL(6, buffer[0]);
+    CORE_TEST_FALSE(buffer.remove());
+    CORE_TEST_FALSE(buffer.canRemove());
+    CORE_TEST_EQUAL(0, buffer.getLength());
+}
+
+static void testClear() {
+    Core::RingBuffer<int, 3> buffer;
+    buffer.add(1);
+    buffer.add(2);
+    CORE_TEST_EQUAL(2, buffer.getLength());
+    buffer.clear();
+    CORE_TEST_FALSE(buffer.canRemove());
+    CORE_TEST_EQUAL(0, buffer.getLength());
+}
+
+void Core::RingBufferTests::test() {
+    testReadAndWrite();
+    testOverflow();
+    testRefill();
+    testClear();
+}

+ 8 - 0
tests/RingBufferTests.h

@@ -0,0 +1,8 @@
+#ifndef CORE_RINGBUFFER_TESTS_H
+#define CORE_RINGBUFFER_TESTS_H
+
+namespace Core::RingBufferTests {
+    void test();
+}
+
+#endif

+ 39 - 42
tests/StackTests.cpp

@@ -6,83 +6,80 @@
 using String = Core::ArrayString<128>;
 
 template<typename T>
-static String build(Core::Test& test, const T& t) {
+static String build(const T& t) {
     String s;
-    test.checkFalse(s.append(t), "append works");
+    CORE_TEST_FALSE(s.append(t));
     return s;
 }
 
 template<typename T>
-static void testPushPopPeek(Core::Test& test) {
+static void testPushPopPeek() {
     T stack;
-    test.checkFalse(stack.push(1), "push works 1");
-    test.checkFalse(stack.push(2), "push works 2");
-    test.checkFalse(stack.push(3), "push works 3");
-    test.checkEqual(3, stack.peek(), "push pop peek 1");
-    test.checkFalse(stack.pop(), "pop without error 1");
-    test.checkEqual(2, stack.peek(), "push pop peek 2");
-    test.checkFalse(stack.pop(), "pop without error 2");
-    test.checkEqual(1, stack.peek(), "push pop peek 3");
-    test.checkFalse(stack.pop(), "pop without error 3");
-    test.checkTrue(stack.isEmpty(), "empty after popping all");
+    CORE_TEST_NOT_NULL(stack.push(1));
+    CORE_TEST_NOT_NULL(stack.push(2));
+    CORE_TEST_NOT_NULL(stack.push(3));
+    CORE_TEST_EQUAL(3, stack.peek());
+    CORE_TEST_FALSE(stack.pop());
+    CORE_TEST_EQUAL(2, stack.peek());
+    CORE_TEST_FALSE(stack.pop());
+    CORE_TEST_EQUAL(1, stack.peek());
+    CORE_TEST_FALSE(stack.pop());
+    CORE_TEST_TRUE(stack.isEmpty());
 }
 
 template<typename T>
-static void testBigPushPop(Core::Test& test, int amount) {
+static void testBigPushPop(int amount) {
     T stack;
     for(int i = 0; i < amount; i++) {
-        test.checkFalse(stack.push(i), "big push works");
+        CORE_TEST_NOT_NULL(stack.push(i));
     }
     for(int i = 0; i < amount; i++) {
-        test.checkFalse(stack.pop(), "big push and pop");
+        CORE_TEST_FALSE(stack.pop());
     }
-    test.checkTrue(stack.isEmpty(), "empty after all pops");
+    CORE_TEST_TRUE(stack.isEmpty());
 }
 
 template<typename T>
-static void testToString1(Core::Test& test) {
+static void testToString1() {
     T stack;
-    test.checkFalse(stack.push(1), "to string push works 1");
-    test.checkFalse(stack.push(243), "to string push works 1");
-    test.checkFalse(stack.push(-423), "to string push works 1");
-    test.checkEqual(build(test, "[1, 243, -423]"), build(test, stack),
-                    "to string 1");
+    CORE_TEST_NOT_NULL(stack.push(1));
+    CORE_TEST_NOT_NULL(stack.push(243));
+    CORE_TEST_NOT_NULL(stack.push(-423));
+    CORE_TEST_EQUAL(build("[1, 243, -423]"), build(stack));
 }
 
 template<typename T>
-static void testToString2(Core::Test& test) {
+static void testToString2() {
     T stack;
-    test.checkFalse(stack.push(1), "to string 2 push works 1");
-    test.checkEqual(build(test, "[1]"), build(test, stack), "to string 2");
+    CORE_TEST_NOT_NULL(stack.push(1));
+    CORE_TEST_EQUAL(build("[1]"), build(stack));
 }
 
 template<typename T>
-static void testToString3(Core::Test& test) {
+static void testToString3() {
     T stack;
-    test.checkEqual(build(test, "[]"), build(test, stack), "to string 3");
+    CORE_TEST_EQUAL(build("[]"), build(stack));
 }
 
 template<typename T>
-static void testPop(Core::Test& test) {
+static void testPop() {
     T stack;
-    for(int i = 0; i < 1000000; i++) {
-        test.checkTrue(stack.pop(), "popping empty stack is safe");
+    for(int i = 0; i < 100000; i++) {
+        CORE_TEST_TRUE(stack.pop());
     }
 }
 
 template<typename T>
-static void testType(Core::Test& test, int amount) {
-    testPushPopPeek<T>(test);
-    testBigPushPop<T>(test, amount);
-    testToString1<T>(test);
-    testToString2<T>(test);
-    testToString3<T>(test);
-    testPop<T>(test);
+static void testType(int amount) {
+    testPushPopPeek<T>();
+    testBigPushPop<T>(amount);
+    testToString1<T>();
+    testToString2<T>();
+    testToString3<T>();
+    testPop<T>();
 }
 
 void Core::StackTests::test() {
-    Test test("Stack");
-    testType<Core::ListStack<int>>(test, 1000000);
-    testType<Core::ArrayStack<int, 100>>(test, 100);
-    test.finalize();
+    testType<Core::ListStack<int>>(100000);
+    testType<Core::ArrayStack<int, 100>>(100);
 }

+ 9 - 12
tests/UniquePointerTests.cpp

@@ -18,29 +18,26 @@ struct B {
 
 int B::instances = 0;
 
-static void testDestroy(Core::Test& test) {
+static void testDestroy() {
     {
         Core::UniquePointer<B> p(new B());
-        test.checkEqual(1, B::instances, "one instance");
+        CORE_TEST_EQUAL(1, B::instances);
     }
-    test.checkEqual(0, B::instances, "instance is destroyed");
+    CORE_TEST_EQUAL(0, B::instances);
 }
 
-static void testMoveDestroys(Core::Test& test) {
+static void testMoveDestroys() {
     {
         Core::UniquePointer<B> p1(new B());
         Core::UniquePointer<B> p2(new B());
-        test.checkEqual(2, B::instances, "two instances");
+        CORE_TEST_EQUAL(2, B::instances);
         p1 = Core::move(p2);
-        test.checkEqual(1, B::instances, "one after move");
+        CORE_TEST_EQUAL(1, B::instances);
     }
-    test.checkEqual(0, B::instances,
-                    "everything destroyed correctly after move");
+    CORE_TEST_EQUAL(0, B::instances);
 }
 
 void Core::UniquePointerTests::test() {
-    Test test("UniquePointer");
-    testDestroy(test);
-    testMoveDestroys(test);
-    test.finalize();
+    testDestroy();
+    testMoveDestroys();
 }

+ 11 - 13
tests/UtilityTests.cpp

@@ -3,20 +3,18 @@
 #include "test/Test.h"
 #include "utils/Utility.h"
 
-static void testPopCount(Core::Test& test) {
-    test.checkEqual(4, Core::popCount(0xF), "pop count 1");
-    test.checkEqual(0, Core::popCount(0x0), "pop count 2");
-    test.checkEqual(2, Core::popCount(0x6), "pop count 3");
-    test.checkEqual(7, Core::popCount(0x7F), "pop count 4");
-    test.checkEqual(3, Core::popCount(0x2A), "pop count 5");
-    test.checkEqual(32, Core::popCount(0xFFFFFFFF), "pop count 6");
-    test.checkEqual(64, Core::popCount(0xFFFFFFFFFFFFFFFFL), "pop count 7");
-    test.checkEqual(44, Core::popCount(0xFFFF0FFFFFFF), "pop count 8");
-    test.checkEqual(32, Core::popCount(-1), "pop count 9");
+static void testPopCount() {
+    CORE_TEST_EQUAL(4, Core::popCount(0xF));
+    CORE_TEST_EQUAL(0, Core::popCount(0x0));
+    CORE_TEST_EQUAL(2, Core::popCount(0x6));
+    CORE_TEST_EQUAL(7, Core::popCount(0x7F));
+    CORE_TEST_EQUAL(3, Core::popCount(0x2A));
+    CORE_TEST_EQUAL(32, Core::popCount(0xFFFFFFFF));
+    CORE_TEST_EQUAL(64, Core::popCount(0xFFFFFFFFFFFFFFFFL));
+    CORE_TEST_EQUAL(44, Core::popCount(0xFFFF0FFFFFFF));
+    CORE_TEST_EQUAL(32, Core::popCount(-1));
 }
 
 void Core::UtilityTests::test() {
-    Core::Test test("Utility");
-    testPopCount(test);
-    test.finalize();
+    testPopCount();
 }

+ 4 - 2
utils/ArrayString.h

@@ -16,7 +16,8 @@ namespace Core {
         int length;
         u32 hash;
         static constexpr int DATA_LENGTH =
-            (N - Math::max(CoreSize(length), CoreSize(hash))) / CoreSize(u32);
+            (N - Math::max(CORE_SIZE(length), CORE_SIZE(hash))) /
+            CORE_SIZE(u32);
         static_assert(DATA_LENGTH > 0, "Size of array string too small");
         u32 data[static_cast<unsigned int>(DATA_LENGTH)];
 
@@ -317,7 +318,8 @@ namespace Core {
             while(index < length) {
                 u32 u = data[index++];
                 if(u == '#') {
-                    if(index < length && data[index] != '#') {
+                    if(index >= length ||
+                       (index < length && data[index] != '#')) {
                         break;
                     }
                     index++;

+ 2 - 18
utils/Utility.h

@@ -3,7 +3,7 @@
 
 #include <stdlib.h>
 
-#define CoreSize(t) static_cast<int>(sizeof(t))
+#define CORE_SIZE(t) static_cast<int>(sizeof(t))
 
 namespace Core {
     namespace Internal {
@@ -66,7 +66,7 @@ namespace Core {
         static constexpr int map[16] = {0, 1, 1, 2, 1, 2, 2, 3,
                                         1, 2, 2, 3, 2, 3, 3, 4};
         int sum = 0;
-        for(int i = 0; i < CoreSize(T) * 8; i += 4) {
+        for(int i = 0; i < CORE_SIZE(T) * 8; i += 4) {
             sum += map[(t >> i) & 0xF];
         }
         return sum;
@@ -76,22 +76,6 @@ namespace Core {
 
     void exitWithHandler(int value);
     void setExitHandler(ExitHandler eh, void*);
-
-    template<typename T, typename W>
-    struct HasToString {
-        typedef char one;
-        struct two {
-            char x[2];
-        };
-
-        template<typename C>
-        static one test(decltype(&C::toString));
-        template<typename C>
-        static two test(...);
-
-    public:
-        enum { value = sizeof(test<T>(0)) == sizeof(char) };
-    };
 }
 
 void* operator new(size_t bytes) noexcept;