/*
	Test-ZSlabAllocator.cpp
	Author: James Russell <jcrussell@762studios.com>

	Purpose: Unit Test the ZSlabAllocator class.

	Changelog:
	12/18/2011 - Removed dependency on ZString (crertel)
	07/17/2011 - creation (jcrussell)
*/

#include "ZUnitTest.hpp"

#include <ZUtil/ZSlabAllocator.hpp>

static const char* testCapacity();
static const char* testCount();
static const char* testExcessCount();
static const char* testCheckInCheckOut();

//List of unit tests
ZUnitTest ZSlabAllocatorUnitTests[] =
{
	{ "ZObjectPool: Capacity",				testCapacity },
	{ "ZObjectPool: CheckOut",				testCount },
	{ "ZObjectPool: CheckIn, CheckOut",		testCheckInCheckOut	}
};

//Now declare the ZUnitTestBlock associated with this.
DECLARE_ZTESTBLOCK(ZSlabAllocator);

/*************************************************************************/

struct PoolTestObject
{
	//Just some data
	int Data;

	//Static Counter
	static int StaticCount;

	PoolTestObject() : Data(StaticCount++) { }
};

int PoolTestObject::StaticCount = 0;


static const char* testCapacity()
{
	ZSlabAllocator<PoolTestObject, 4> testPool;
	ZSlabAllocator<PoolTestObject, 14> testPool2;

	TASSERT(testPool.Capacity() == 4, "ZSlabAllocator: Capacity reports not 4 despite being inited to 4!");
	TASSERT(testPool2.Capacity() == 14, "ZSlabAllocator: Capacity reports not 14 despite being inited to 14!");

	return ZTEST_SUCCESS;
}

static const char* testCount()
{
	ZSlabAllocator<PoolTestObject, 4> testPool;
	PoolTestObject* objs[4];

	TASSERT(testPool.Available() == 4, "ZSlabAllocator: AvailableCount reports not 4 despite being unused!");

	for (size_t i = 0; i < 4; i++)
	{
		objs[i] = testPool.Allocate();
		TASSERT(testPool.Available() == 3 - i, "ZSlabAllocator: AvailableCount reports incorrect available count during checkouts!");
	}

	for (size_t i = 0; i < 4; i++)
	{
		testPool.Deallocate(objs[i]);
		TASSERT(testPool.Available() == i + 1, "ZSlabAllocator: AvailableCount reports incorrect available count during checkins!");
	}

	TASSERT(testPool.Available() == 4, "ZSlabAllocator: AvailableCount reports not 4 despite all objects checked in!");

	return ZTEST_SUCCESS;
}

static const char* testCheckInCheckOut()
{
	ZSlabAllocator<PoolTestObject, 4> testPool;

	TASSERT(testPool.Available() == 4, "ZSlabAllocator: Contains wrong number of objects!");
	TASSERT(testPool.Capacity() == 4, "ZSlabAllocator: Capacity is incorrect!");

	//Allocated: 0 -> 2
	PoolTestObject *testObj1 = testPool.Allocate();
	PoolTestObject *testObj2 = testPool.Allocate();

	TASSERT(testPool.Available() == testPool.Capacity()-2, "ZSlabAllocator: Contains wrong number of objects after CheckOut!");

	//Allocated: 2 -> 4
	PoolTestObject *testObj3 = testPool.Allocate();
	PoolTestObject *testObj4 = testPool.Allocate();

	TASSERT(testPool.Available() == testPool.Capacity()-4, "ZSlabAllocator: Contains objects when none should remain!");

	//Allocated: 4 -> 6
	PoolTestObject *testObj5 = testPool.Allocate();
	PoolTestObject *testObj6 = testPool.Allocate();


	//Allocated: 6 -> 4
	testPool.Deallocate(testObj1);
	testPool.Deallocate(testObj4);

	TASSERT(testPool.Available() == testPool.Capacity()-4, "ZSlabAllocator: Failed to return objects correctly!");

	//Allocated: 4 -> 2
	testPool.Deallocate(testObj6);
	testPool.Deallocate(testObj5);


	//Allocated: 4 -> 2 == 0
	testPool.Deallocate(testObj3);
	testPool.Deallocate(testObj2);

	TASSERT(testPool.Available() == testPool.Capacity(), "ZSlabAllocator: Failed to return objects to full count!");

	return ZTEST_SUCCESS;
}