#include "../Tests.hpp"
#include "core/utils/New.hpp"
#include "core/utils/UniquePointer.hpp"

struct B final {
    static int instances;

    bool b = false;

    B() {
        instances++;
    }

    ~B() {
        instances--;
    }

    void test() {
        b = true;
    }
};

int B::instances = 0;

template class Core::UniquePointer<B>;
using UniqueB = Core::UniquePointer<B>;

static void testDestroy() {
    {
        UniqueB p(new(noThrow) B());
        CORE_TEST_EQUAL(1, B::instances);
    }
    CORE_TEST_EQUAL(0, B::instances);
}

static void testMoveConstructDestroys() {
    UniqueB p1(new(noThrow) B());
    CORE_TEST_EQUAL(1, B::instances);
    UniqueB p2(Core::move(p1));
    CORE_TEST_EQUAL(1, B::instances);
    p2 = nullptr;
    CORE_TEST_EQUAL(0, B::instances);
}

static void testMoveDestroys() {
    {
        UniqueB p1(new(noThrow) B());
        UniqueB p2(new(noThrow) B());
        CORE_TEST_EQUAL(2, B::instances);
        p1 = Core::move(p2);
        CORE_TEST_EQUAL(1, B::instances);
    }
    CORE_TEST_EQUAL(0, B::instances);
}

static void testEmpty() {
    UniqueB p;
    CORE_TEST_TRUE(p == nullptr);
    CORE_TEST_TRUE(static_cast<const UniqueB&>(p) == nullptr);
}

static void testCall() {
    UniqueB p(new(noThrow) B());
    CORE_TEST_FALSE(p->b);
    p->test();
    CORE_TEST_TRUE(p->b);
    CORE_TEST_TRUE(static_cast<const UniqueB&>(p)->b);
}

void Core::testUniquePointer() {
    testDestroy();
    testMoveConstructDestroys();
    testMoveDestroys();
    testEmpty();
    testCall();
}