#include "tests/ObjectPoolTests.h"
#include "tests/Test.h"
#include "memory/ObjectPool.h"

struct A {
    static int instances;
    int a;

    A(int a) : a(a) {
        instances += a;
    }

    ~A() {
        instances -= a;
    }
};

int A::instances = 0;

static void testAllocateAndFree(Test& test) {
    ObjectPool<A, 3> pool;
    int a = pool.allocate(1);
    int b = pool.allocate(2);
    int c = pool.allocate(3);
    int d = pool.allocate(4);
    int e = pool.allocate(5);
    test.checkEqual(0, a, "int pointer allocate 1");
    test.checkEqual(1, b, "int pointer allocate 2");
    test.checkEqual(2, c, "int pointer allocate 3");
    test.checkEqual(-1, d, "int pointer allocate 4");
    test.checkEqual(-1, e, "int pointer allocate 5");
    pool.free(a);
    pool.free(b);
    pool.free(c);
    test.checkEqual(0, A::instances, "all destructors are called 1");
}

static void testAllocateAfterFree(Test& test) {
    ObjectPool<A, 3> pool;
    int a = pool.allocate(1);
    int b = pool.allocate(2);
    int c = pool.allocate(3);
    
    pool.free(b);
    b = pool.allocate(7);
    test.checkEqual(1, b, "int pointer allocate after free 1");
    
    pool.free(c);
    c = pool.allocate(9);
    test.checkEqual(2, c, "int pointer allocate after free 2");
    
    pool.free(a);
    a = pool.allocate(11);
    test.checkEqual(0, a, "int pointer allocate after free 3");
    
    pool.free(a);
    pool.free(b);
    b = pool.allocate(23);
    a = pool.allocate(17);
    test.checkEqual(0, a, "int pointer allocate after free 4");
    test.checkEqual(1, b, "int pointer allocate after free 5");
    test.checkEqual(-1, pool.allocate(50), "int pointer allocate after free 6");

    pool.free(a);
    pool.free(b);
    pool.free(c);
    test.checkEqual(0, A::instances, "all destructors are called 2");
}

void ObjectPoolTests::test() {
    Test test("ObjectPool");
    testAllocateAndFree(test);
    testAllocateAfterFree(test);
    test.finalize();
}