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

	Purpose: Unit Test the ZAllocWindow class.
*/

#include "ZUnitTest.hpp"

#include <ZUtil/ZAllocWindow.hpp>

static const char* test_ConstructResizeSetBuffer();
static const char* test_AllocDealloc();

//List of unit tests
ZUnitTest ZAllocWindowUnitTests[] =
{
	{ "ZAllocWindow: Construction, Resize, SetBuffer",	test_ConstructResizeSetBuffer },
	{ "ZAllocWindow: Allocate, Deallocate",				test_AllocDealloc },
};

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

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

namespace ZAllocWindowTestObjects
{
	struct IntStruct {
		int data;

		IntStruct() : data(0xFFFFFFFF) { }
		~IntStruct() { data = 0xFEEEFEEE; }
	};
}

using namespace ZAllocWindowTestObjects;

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

static const char* test_ConstructResizeSetBuffer()
{
	ZAllocWindow buf1;
	ZAllocWindow buf2(1024);

	TASSERT(buf1.Size() == 0, "Buffer 1 does not return a size of 0!");
	TASSERT(buf2.Size() == 1024, "Buffer 2 does not return a size of 1024!");

	buf1.Resize(100);

	TASSERT(buf1.Size() == 100, "Buffer 1 does not return a size of 100 after resize!");

	buf1.Resize<int>(50);

	TASSERT(buf1.Size() >= ((sizeof(int) + 8) * 50), "Template Resize does not size correctly!");

	char local_buffer[500];

	buf2.SetBuffer(local_buffer, 500);

	TASSERT(buf2.Size() == 500, "Buffer 2 does not return a size of 500 after resize!");

	return ZTEST_SUCCESS;
}

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

static const char* test_AllocDealloc()
{
	ZAllocWindow buf1;
	ZAllocWindow buf2(1024);

	buf1.Resize<IntStruct>(5);

	IntStruct* alloc1 = buf1.Allocate<IntStruct>();
	IntStruct* alloc2 = buf1.Allocate<IntStruct>();
	IntStruct* alloc3 = buf1.Allocate<IntStruct>();
	IntStruct* alloc4 = buf1.Allocate<IntStruct>();
	IntStruct* alloc5 = buf1.Allocate<IntStruct>();
	IntStruct* alloc6 = buf1.Allocate<IntStruct>();

	TASSERT(alloc1 != NULL, "Allocation 1 returned NULL!");
	TASSERT(alloc2 != NULL, "Allocation 2 returned NULL!");
	TASSERT(alloc3 != NULL, "Allocation 3 returned NULL!");
	TASSERT(alloc4 != NULL, "Allocation 4 returned NULL!");
	TASSERT(alloc5 != NULL, "Allocation 5 returned NULL!");
	TASSERT(alloc6 == NULL, "Allocation 6 returned valid pointer - should be NULL!");

	alloc1->data = 0xA;
	alloc2->data = 0xB; 
	alloc3->data = 0xC;
	alloc4->data = 0xD;
	alloc5->data = 0xE;

	buf1.Deallocate(alloc2);

	alloc6 = buf1.Allocate<IntStruct>();

	TASSERT(alloc6 == NULL, "Allocation window frees space before earliest dealloc!");

	buf1.Deallocate(alloc1);

	IntStruct* alloc7;

	alloc6 = buf1.Allocate<IntStruct>();
	alloc7 = buf1.Allocate<IntStruct>();

	TASSERT(alloc6 != NULL, "Allocation window fails to free space after dealloc!");
	TASSERT(alloc7 != NULL, "Allocation window fails to roll up multiple deallocs!");

	buf1.Deallocate(alloc3);
	buf1.Deallocate(alloc4);
	buf1.Deallocate(alloc5);
	buf1.Deallocate(alloc6);
	buf1.Deallocate(alloc7);

	//TODO - test buf2

	return ZTEST_SUCCESS;	
}
