#include "ZUnitTest.hpp"

//Hijack the assert
#define ZSTL_ASSERT(condition, message) SST_OS_RuntimeAssert(condition, message)

#include <ZSTL/ZRingBuffer.hpp>

/* construction, size, capacity, empty and full */
static const char* test_Constructors_Array_Data_Length_Capacity();
static const char* test_Empty();
static const char* test_Full();

/* primary accessors */
static const char* test_Front();
static const char* test_Back();

/* primary removal operations */
static const char* test_PopFront();
static const char* test_PopBack();

/* primary add operations */
static const char* test_PushFront_OverflowUnsafe();
static const char* test_PushFront_OverflowAssert();
static const char* test_PushFront_OverflowIgnore();
static const char* test_PushFront_OverflowDropFront();
static const char* test_PushFront_OverflowDropBack();
static const char* test_PushFront_OverflowOverwrite();
static const char* test_PushFront_OverflowEvict();
static const char* test_PushFront_OverflowGrow();

static const char* test_PushBack_OverflowUnsafe();
static const char* test_PushBack_OverflowAssert();
static const char* test_PushBack_OverflowIgnore();
static const char* test_PushBack_OverflowDropFront();
static const char* test_PushBack_OverflowDropBack();
static const char* test_PushBack_OverflowOverwrite();
static const char* test_PushBack_OverflowEvict();
static const char* test_PushBack_OverflowGrow();

/* secondary accessors */
static const char* test_AbsoluteIndex();
static const char* test_At();

/* secondary removal operations */
static const char* test_Clear();
static const char* test_Erase();

/* secondary add operations */
static const char* test_Insert();
static const char* test_TryPushBack();
static const char* test_TryPushFront();

/* equivalence and assignment */
static const char* test_Equals();
static const char* test_Copy();

/* usage tests */
static const char* test_Stack();
static const char* test_Queue();
static const char* test_Alternating();

ZUnitTest ZRingBufferUnitTests[] =
{
	{ "ZRingBuffer: Constructors, Array, Size, Capacity",			test_Constructors_Array_Data_Length_Capacity },
	{ "ZRingBuffer: Empty",											test_Empty },
	{ "ZRingBuffer: Full",											test_Full },
	{ "ZRingBuffer: Front",											test_Front },
	{ "ZRingBuffer: Back",											test_Back },
	{ "ZRingBuffer: PopFront",										test_PopFront },
	{ "ZRingBuffer: PopBack",										test_PopBack },
	{ "ZRingBuffer: PushFront (OverflowUnsafe)",					test_PushFront_OverflowUnsafe },
	{ "ZRingBuffer: PushFront (OverflowAssert)",					test_PushFront_OverflowAssert },
	{ "ZRingBuffer: PushFront (OverflowIgnore)",					test_PushFront_OverflowIgnore },
	{ "ZRingBuffer: PushFront (OverflowDropFront)",					test_PushFront_OverflowDropFront },
	{ "ZRingBuffer: PushFront (OverflowDropBack)",					test_PushFront_OverflowDropBack },
	{ "ZRingBuffer: PushFront (OverflowOverwrite)",					test_PushFront_OverflowOverwrite },
	{ "ZRingBuffer: PushFront (OverflowEvict)",						test_PushFront_OverflowEvict },
	{ "ZRingBuffer: PushFront (OverflowGrow)",						test_PushFront_OverflowGrow },
	{ "ZRingBuffer: PushBack (OverflowUnsafe)",						test_PushBack_OverflowUnsafe },
	{ "ZRingBuffer: PushBack (OverflowAssert)",						test_PushBack_OverflowAssert },
	{ "ZRingBuffer: PushBack (OverflowIgnore)",						test_PushBack_OverflowIgnore },
	{ "ZRingBuffer: PushBack (OverflowDropFront)",					test_PushBack_OverflowDropFront },
	{ "ZRingBuffer: PushBack (OverflowDropBack)",					test_PushBack_OverflowDropBack },
	{ "ZRingBuffer: PushBack (OverflowOverwrite)",					test_PushBack_OverflowOverwrite },
	{ "ZRingBuffer: PushBack (OverflowEvict)",						test_PushBack_OverflowEvict },
	{ "ZRingBuffer: PushBack (OverflowGrow)",						test_PushBack_OverflowGrow },
	{ "ZRingBuffer: AbsoluteIndex",									test_AbsoluteIndex },
	{ "ZRingBuffer: At",											test_At },
	{ "ZRingBuffer: Clear",											test_Clear },
	{ "ZRingBuffer: Erase",											test_Erase },
	{ "ZRingBuffer: Insert",										test_Insert },
	{ "ZRingBuffer: TryPushBack",									test_TryPushBack },
	{ "ZRingBuffer: TryPushFront",									test_TryPushFront },
	{ "ZRingBuffer: Equals",										test_Equals },
	{ "ZRingBuffer: Copy",											test_Copy },

	{ "ZRingBuffer: Usage (Stack)",									test_Stack },
	{ "ZRingBuffer: Usage (Queue)",									test_Queue },
	{ "ZRingBuffer: Usage (Alternating)",							test_Alternating }
};

DECLARE_ZTESTBLOCK(ZRingBuffer);

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

static const char* test_Constructors_Array_Data_Length_Capacity()
{
	int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	ZArray<int> data1(testData, 10, 10);
	ZArray<int> data2(testData, 6, 20);

	ZRingBuffer<int> buf1;
	ZRingBuffer<int> buf2(10);
	ZRingBuffer<int> buf3(data1);
	ZRingBuffer<int> buf4(data2);

	TASSERT(buf1.Array().Size() == ZRINGBUFFER_DEFAULT_CAPACITY, "Default constructor fails to properly initialize storage array!");
	TASSERT(buf2.Array().Size() == 10, "Capacity constructor failed to properly initialize storage array!");
	TASSERT(buf3.Array().Size() == 10, "Storage constructor failed to properly initialize storage array!");

	for (int i = 0; i < (int)data1.Size(); i++)
	{
		TASSERT(buf3.Array()[i] == i, "Storage constructor failed to properly copy storage data!");
	}

	for (int i = 0; i < (int)data2.Size(); i++)
	{
		TASSERT(buf4.Array()[i] == i, "Storage constructor (2) failed to properly copy storage data!");
	}

	TASSERT(buf1.Size() == 0, "Default constructor initializes with incorrect size!");
	TASSERT(buf1.Capacity() == ZRINGBUFFER_DEFAULT_CAPACITY, "Default constructor initializes with incorrect capacity!");

	TASSERT(buf2.Size() == 0, "Capacity constructor initializes with incorrect size!");
	TASSERT(buf2.Capacity() == 10, "Capacity constructor initializes with incorrect capacity!");

	TASSERT(buf3.Size() == 10, "Storage constructor initializes with incorrect size!");
	TASSERT(buf3.Capacity() == 10, "Storage constructor initializes with incorrect capacity!");

	TASSERT(buf4.Size() == 6, "Storage constructor (2) initializes with incorrect size!");
	TASSERT(buf4.Capacity() == 20, "Storage constructor (2) initializes with incorrect capacity!");

	return ZTEST_SUCCESS;
}

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

static const char* test_Empty()
{
	int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	ZArray<int> data1(testData, 10, 10);
	ZArray<int> data2(testData, 6, 20);

	ZRingBuffer<int> buf1;
	ZRingBuffer<int> buf2(10);
	ZRingBuffer<int> buf3(data1);
	ZRingBuffer<int> buf4(data2);

	TASSERT(buf1.Empty(), "Empty() returns false on empty buffer!");
	TASSERT(buf2.Empty(), "Empty() returns false on empty buffer with low capacity!");
	TASSERT(!buf3.Empty(), "Empty() returns true on non-empty buffer with Size() = Capacity()!");
	TASSERT(!buf4.Empty(), "Empty() returns true on non-empty buffer with Size() != Capacity()!");

	return ZTEST_SUCCESS;
}

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

static const char* test_Full() 
{
	int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	ZArray<int> data1(testData, 10, 10);
	ZArray<int> data2(testData, 6, 20);

	ZRingBuffer<int> buf1;
	ZRingBuffer<int> buf2(10);
	ZRingBuffer<int> buf3(data1);
	ZRingBuffer<int> buf4(data2);

	TASSERT(!buf1.Full(), "Full() returns true on empty buffer!");
	TASSERT(!buf2.Full(), "Full() returns true on empty buffer with low capacity!");
	TASSERT(buf3.Full(), "Full() returns false on non-empty buffer with Size() = Capacity()!");
	TASSERT(!buf4.Full(), "Full() returns true on non-empty buffer with Size() != Capacity()!");

	return ZTEST_SUCCESS;
}

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

static const char* test_Front()
{
	int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	ZArray<int> data1(testData, 10, 10);
	ZArray<int> data2(testData, 6, 20);

	ZRingBuffer<int> buf1;
	ZRingBuffer<int> buf2(10);
	ZRingBuffer<int> buf3(data1);
	ZRingBuffer<int> buf4(data2);

	ZTEST_BeginHandleAssert();

	buf1.Front();	//This will ruin buf1, so don't use it anymore

	ZTEST_EndHandleAssert();

	TASSERT(ZTEST_CheckAssert(), "Front() on empty buffer failed to trigger assert!");

	TASSERT(buf3.Front() == 0, "Front() returns incorrect value on non-empty buffer!");
	TASSERT(buf4.Front() == 0, "Front() returns incorrect value on second non-empty buffer!");

	return ZTEST_SUCCESS;
}

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

static const char* test_Back() 
{
	int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	ZArray<int> data1(testData, 10, 10);
	ZArray<int> data2(testData, 6, 20);

	ZRingBuffer<int> buf1;
	ZRingBuffer<int> buf2(10);
	ZRingBuffer<int> buf3(data1);
	ZRingBuffer<int> buf4(data2);

	ZTEST_BeginHandleAssert();

	buf1.Back();	//This will ruin buf1, so don't use it anymore

	ZTEST_EndHandleAssert();

	TASSERT(ZTEST_CheckAssert(), "Back() on empty buffer failed to trigger assert!");

	TASSERT(buf3.Back() == 9, "Back() returns incorrect value on non-empty buffer!");
	TASSERT(buf4.Back() == 5, "Back() returns incorrect value on second non-empty buffer!");

	return ZTEST_SUCCESS;
}

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

static const char* test_PopFront() 
{
	int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	ZArray<int> data1(testData, 10, 10);
	ZArray<int> data2(testData, 6, 20);

	ZRingBuffer<int> buf1;
	ZRingBuffer<int> buf2(10);
	ZRingBuffer<int> buf3(data1);
	ZRingBuffer<int> buf4(data2);

	int i;

	ZTEST_BeginHandleAssert();

	buf1.PopFront();	//This will ruin buf1, so don't use it anymore

	ZTEST_EndHandleAssert();

	TASSERT(ZTEST_CheckAssert(), "PopFront() on empty buffer failed to trigger assert!");

	i = buf3.PopFront();

	TASSERT(i == 0, "PopFront() returned incorrect value for first element!");
	TASSERT(buf3.Size() == 9, "PopFront() failed to reduce buffer size!");
	TASSERT(buf3.Capacity() == 10, "PopFront improperly reduced capacity!");

	for (i = 1; i < 9; i++)
	{
		TASSERT(buf3.PopFront() == i, "PopFront() returned incorrect value when looping through buf3!");
	}

	TASSERT(buf3.Size() == 1, "PopFront() x 8 failed to reduce buffer to one element!");

	i = buf3.PopFront();

	TASSERT(i == 9, "PopFront() returned incorrect value on last element!");
	TASSERT(buf3.Size() == 0, "PopFront() on last element did not reduce buffer size to zero!");

	return ZTEST_SUCCESS;
}

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

static const char* test_PopBack() 
{
	int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	ZArray<int> data1(testData, 10, 10);
	ZArray<int> data2(testData, 6, 20);

	ZRingBuffer<int> buf1;
	ZRingBuffer<int> buf2(10);
	ZRingBuffer<int> buf3(data1);
	ZRingBuffer<int> buf4(data2);

	int i;

	ZTEST_BeginHandleAssert();

	buf1.PopBack();	//This will ruin buf1, so don't use it anymore

	ZTEST_EndHandleAssert();

	TASSERT(ZTEST_CheckAssert(), "PopBack() on empty buffer failed to trigger assert!");

	i = buf3.PopBack();

	TASSERT(i == 9, "PopBack() returned incorrect value for last element!");
	TASSERT(buf3.Size() == 9, "PopBack() failed to reduce buffer size!");
	TASSERT(buf3.Capacity() == 10, "PopBack improperly reduced capacity!");

	for (i = 8; i > 5; i--)
	{
		TASSERT(buf3.PopBack() == i, "PopBack() returned incorrect value when looping through buf3!");
	}

	for (i = 0; i < 5; i++)
		buf3.PopFront();

	TASSERT(buf3.Size() == 1, "PopBack() / PopFront() combo failed to reduce buffer to correct size!");

	return ZTEST_SUCCESS;
}

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

const char* test_PushFront_ErrorMsg = NULL;

#define PF_TASSERT(condition, msg)	if (!(condition)) { test_PushFront_ErrorMsg = msg; return false; }

/*
This little helper method will test an empty ring buffer push front function and return a full buffer
that has been wrap-around tested so you can test the specifics of overflow
looks like the following when done: [ (Back)0, (Front) 9, 8, 7, 6, 5, 4, 3, 2, 1 ]
*/
template <typename T, typename P, typename A>
inline bool test_PushFront(ZRingBuffer<T, P, A>& buffer)
{
	int i;

	buffer.PushFront(0);

	PF_TASSERT(buffer.Size() == 1, "PushFront() does not properly increment size!");
	PF_TASSERT(buffer.Front() == 0, "PushFront() does not properly set value for Front()!");
	PF_TASSERT(buffer.Back() == 0, "PushFront() does not properly set value for Back()!");

	for (i = 1; i < 10; i++)
		buffer.PushFront(i);

	PF_TASSERT(buffer.Size() == 10, "PushFront() does not properly handle wrap-around!");
	PF_TASSERT(buffer.Front() == 9, "PushFront() does not correctly set Front() value after wrap-around!");
	PF_TASSERT(buffer.Back() == 0, "PushFront() improperly modifies Back() value after wrap-around!");

	return true;
}

static const char* test_PushFront_OverflowUnsafe() 
{
	int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	ZArray<int> data1(testData, 10, 10);
	ZArray<int> data2(testData, 6, 20);

	ZRingBuffer<int, ZRingBuffer_OverflowUnsafe> buf1;
	ZRingBuffer<int, ZRingBuffer_OverflowUnsafe> buf2(10);
	ZRingBuffer<int, ZRingBuffer_OverflowUnsafe> buf3(data1);
	ZRingBuffer<int, ZRingBuffer_OverflowUnsafe> buf4(data2);

	if (!test_PushFront(buf2))
		return test_PushFront_ErrorMsg;

	//Test the unsafe behavior (this will actually invalidate the buffer, so BEWARE)
	buf2.PushFront(15);

	TASSERT(buf2.Front() == buf2.Back(), "PushFront() does not properly overwrite the back value when overflow occurs!");

	return ZTEST_SUCCESS;
}

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

static const char* test_PushFront_OverflowAssert() 
{
	int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	ZArray<int> data1(testData, 10, 10);
	ZArray<int> data2(testData, 6, 20);

	ZRingBuffer<int, ZRingBuffer_OverflowAssert> buf1;
	ZRingBuffer<int, ZRingBuffer_OverflowAssert> buf2(10);
	ZRingBuffer<int, ZRingBuffer_OverflowAssert> buf3(data1);
	ZRingBuffer<int, ZRingBuffer_OverflowAssert> buf4(data2);

	if (!test_PushFront(buf2))
		return test_PushFront_ErrorMsg;

	ZTEST_BeginHandleAssert();

	buf2.PushFront(15);	//This will ruin buf2, so don't use it anymore

	ZTEST_EndHandleAssert();

	TASSERT(ZTEST_CheckAssert(), "PushFront() on full buffer failed to assert!");

	return ZTEST_SUCCESS;
}

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

static const char* test_PushFront_OverflowIgnore() 
{
	int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	ZArray<int> data1(testData, 10, 10);
	ZArray<int> data2(testData, 6, 20);

	ZRingBuffer<int, ZRingBuffer_OverflowIgnore> buf1;
	ZRingBuffer<int, ZRingBuffer_OverflowIgnore> buf2(10);
	ZRingBuffer<int, ZRingBuffer_OverflowIgnore> buf3(data1);
	ZRingBuffer<int, ZRingBuffer_OverflowIgnore> buf4(data2);

	if (!test_PushFront(buf2))
		return test_PushFront_ErrorMsg;

	buf2.PushFront(15);

	TASSERT(buf2.Front() == 9, "PushFront() added element on full buffer with ZRingBuffer_OverflowIgnore policy (Front)!");
	TASSERT(buf2.Back() == 0, "PushFront() added element on full buffer with ZRingBuffer_OverflowIgnore policy (Back)!");
	TASSERT(buf2.Size() == 10, "PushFront() added element on full buffer with ZRingBuffer_OverflowIgnore policy (Size)!");
	TASSERT(buf2.Full(), "PushFront() added element on full buffer with ZRingBuffer_OverflowIgnore policy (Full)!");

	return ZTEST_SUCCESS;
}

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

static const char* test_PushFront_OverflowDropFront() 
{
	int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	ZArray<int> data1(testData, 10, 10);
	ZArray<int> data2(testData, 6, 20);

	ZRingBuffer<int, ZRingBuffer_OverflowDropFront> buf1;
	ZRingBuffer<int, ZRingBuffer_OverflowDropFront> buf2(10);
	ZRingBuffer<int, ZRingBuffer_OverflowDropFront> buf3(data1);
	ZRingBuffer<int, ZRingBuffer_OverflowDropFront> buf4(data2);

	if (!test_PushFront(buf2))
		return test_PushFront_ErrorMsg;

	buf2.PushFront(15);

	TASSERT(buf2.Front() == 15, "PushFront() failed to drop front element with ZRingBuffer_OverflowDropFront policy!");
	TASSERT(buf2.Back() == 0, "PushFront() improperly modified back element with ZRingBuffer_OverflowDropFront policy!");
	TASSERT(buf2.Size() == 10, "PushFront() failed to keep size with ZRingBuffer_OverflowDropFront policy!");
	TASSERT(buf2.Full(), "PushFront() failed to keep buffer full with ZRingBuffer_OverflowDropFront policy!");

	return ZTEST_SUCCESS;
}

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

static const char* test_PushFront_OverflowDropBack() 
{
	int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	ZArray<int> data1(testData, 10, 10);
	ZArray<int> data2(testData, 6, 20);

	ZRingBuffer<int, ZRingBuffer_OverflowDropBack> buf1;
	ZRingBuffer<int, ZRingBuffer_OverflowDropBack> buf2(10);
	ZRingBuffer<int, ZRingBuffer_OverflowDropBack> buf3(data1);
	ZRingBuffer<int, ZRingBuffer_OverflowDropBack> buf4(data2);

	if (!test_PushFront(buf2))
		return test_PushFront_ErrorMsg;

	buf2.PushFront(15);

	TASSERT(buf2.Front() == 15, "PushFront() failed to change front element with ZRingBuffer_OverflowDropBack policy!");
	TASSERT(buf2.Back() == 1, "PushFront() failed to drop back element with ZRingBuffer_OverflowDropBack policy!");
	TASSERT(buf2.Size() == 10, "PushFront() failed to keep size with ZRingBuffer_OverflowDropBack policy!");
	TASSERT(buf2.Full(), "PushFront() failed to keep buffer full with ZRingBuffer_OverflowDropBack policy!");

	return ZTEST_SUCCESS;
}

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

static const char* test_PushFront_OverflowOverwrite() 
{
	int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	ZArray<int> data1(testData, 10, 10);
	ZArray<int> data2(testData, 6, 20);

	ZRingBuffer<int, ZRingBuffer_OverflowOverwrite> buf1;
	ZRingBuffer<int, ZRingBuffer_OverflowOverwrite> buf2(10);
	ZRingBuffer<int, ZRingBuffer_OverflowOverwrite> buf3(data1);
	ZRingBuffer<int, ZRingBuffer_OverflowOverwrite> buf4(data2);

	if (!test_PushFront(buf2))
		return test_PushFront_ErrorMsg;

	buf2.PushFront(15);

	TASSERT(buf2.Front() == 15, "PushFront() failed to overwrite front element with ZRingBuffer_OverflowOverwrite policy!");
	TASSERT(buf2.Back() == 0, "PushFront() improperly modified back element with ZRingBuffer_OverflowOverwrite policy!");
	TASSERT(buf2.Size() == 10, "PushFront() failed to keep size with ZRingBuffer_OverflowOverwrite policy!");
	TASSERT(buf2.Full(), "PushFront() failed to keep buffer full with ZRingBuffer_OverflowOverwrite policy!");

	return ZTEST_SUCCESS;
}

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

static const char* test_PushFront_OverflowEvict() 
{
	int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	ZArray<int> data1(testData, 10, 10);
	ZArray<int> data2(testData, 6, 20);

	ZRingBuffer<int, ZRingBuffer_OverflowEvict> buf1;
	ZRingBuffer<int, ZRingBuffer_OverflowEvict> buf2(10);
	ZRingBuffer<int, ZRingBuffer_OverflowEvict> buf3(data1);
	ZRingBuffer<int, ZRingBuffer_OverflowEvict> buf4(data2);

	if (!test_PushFront(buf2))
		return test_PushFront_ErrorMsg;

	buf2.PushFront(15);

	TASSERT(buf2.Front() == 15, "PushFront() failed to change front element with ZRingBuffer_OverflowEvict policy!");
	TASSERT(buf2.Back() == 1, "PushFront() failed to evict back element with ZRingBuffer_OverflowEvict policy!");
	TASSERT(buf2.Size() == 10, "PushFront() failed to keep size with ZRingBuffer_OverflowEvict policy!");
	TASSERT(buf2.Full(), "PushFront() failed to keep buffer full with ZRingBuffer_OverflowEvict policy!");


	return ZTEST_SUCCESS;
}

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

static const char* test_PushFront_OverflowGrow() 
{
	int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	ZArray<int> data1(testData, 10, 10);
	ZArray<int> data2(testData, 6, 20);

	ZRingBuffer<int, ZRingBuffer_OverflowGrow> buf1;
	ZRingBuffer<int, ZRingBuffer_OverflowGrow> buf2(10);
	ZRingBuffer<int, ZRingBuffer_OverflowGrow> buf3(data1);
	ZRingBuffer<int, ZRingBuffer_OverflowGrow> buf4(data2);

	if (!test_PushFront(buf2))
		return test_PushFront_ErrorMsg;

	buf2.PushFront(15);

	TASSERT(buf2.Front() == 15, "PushFront() failed to add front element with ZRingBuffer_OverflowGrow policy!");
	TASSERT(buf2.Back() == 0, "PushFront() improperly modified back element with ZRingBuffer_OverflowGrow policy!");
	TASSERT(buf2.Size() == 11, "PushFront() did not properly increment size with ZRingBuffer_OverflowGrow policy!");
	TASSERT(buf2.Capacity() > 10, "PushFront() did not properly grow the buffer with ZRingBuffer_OverflowGrow policy!");

	return ZTEST_SUCCESS;
}

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

const char* test_PushBack_ErrorMsg = NULL;

#define PB_TASSERT(condition, msg)	if (!(condition)) { test_PushBack_ErrorMsg = msg; return false; }

/*
This little helper method will test an empty ring buffer push front function and return a full buffer
that has been wrap-around tested so you can test the specifics of overflow
looks like the following when done: [ 6, 7, 8, 9, (Front) 0, (Back) 1, 2, 3, 4, 5 ]
*/
template <typename T, typename P, typename A>
inline bool test_PushBack(ZRingBuffer<T, P, A>& buffer)
{
	int i;

	buffer.PushBack(0);

	PB_TASSERT(buffer.Size() == 1, "PushBack() does not properly increment size!");
	PB_TASSERT(buffer.Front() == 0, "PushBack() does not properly set value for Front()!");
	PB_TASSERT(buffer.Back() == 0, "PushBack() does not properly set value for Back()!");

	for (i = 1; i < 5; i++)
		buffer.PushBack(i);

	for (i = 5; i < 10; i++)
		buffer.PushFront(i);

	//Current layout: [ 0, 1, 2, 3, (Back) 4, (Front) 9, 8, 7, 6, 5 ]

	for (i = 0; i < 5; i++)
	{
		PB_TASSERT(buffer.Array()[i] == i, "PushBack() does not correctly set values!");
		PB_TASSERT(buffer.Array()[9 - i] == 5 + i, "PushFront() does not correctly set values!");
	}

	for (i = 0; i < 10; i++)
	{
		buffer.PopFront();
		buffer.PushBack(i);
	}

	//New layout: [ 5, 6, 7, 8, (Back) 9, (Front) 0, 1, 2, 3, 4 ]

	for (i = 0; i < 5; i++)
	{
		PB_TASSERT(buffer.Array()[i] == i + 5, "PopFront()/PushBack() does not correctly set values!");
		PB_TASSERT(buffer.Array()[i + 5] == i, "PopFront()/PushBack() does not correctly set values!");
	}

	PB_TASSERT(buffer.Size() == 10, "PushFront() does not properly handle wrap-around!");
	PB_TASSERT(buffer.Front() == 0, "Buffer does not correctly set Front() value after wrap-around!");
	PB_TASSERT(buffer.Back() == 9, "Buffer improperly modifies Back() value after wrap-around!");

	return true;
}

static const char* test_PushBack_OverflowUnsafe() 
{
	int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	ZArray<int> data1(testData, 10, 10);
	ZArray<int> data2(testData, 6, 20);

	ZRingBuffer<int, ZRingBuffer_OverflowUnsafe> buf1;
	ZRingBuffer<int, ZRingBuffer_OverflowUnsafe> buf2(10);
	ZRingBuffer<int, ZRingBuffer_OverflowUnsafe> buf3(data1);
	ZRingBuffer<int, ZRingBuffer_OverflowUnsafe> buf4(data2);

	if (!test_PushBack(buf2))
		return test_PushBack_ErrorMsg;

	//Test the unsafe behavior (this will actually invalidate the buffer, so BEWARE)
	buf2.PushBack(15);

	TASSERT(buf2.Front() == buf2.Back(), "PushBack() does not properly overwrite the back value when overflow occurs!");

	return ZTEST_SUCCESS;
}

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

static const char* test_PushBack_OverflowAssert() 
{
	int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	ZArray<int> data1(testData, 10, 10);
	ZArray<int> data2(testData, 6, 20);

	ZRingBuffer<int, ZRingBuffer_OverflowAssert> buf1;
	ZRingBuffer<int, ZRingBuffer_OverflowAssert> buf2(10);
	ZRingBuffer<int, ZRingBuffer_OverflowAssert> buf3(data1);
	ZRingBuffer<int, ZRingBuffer_OverflowAssert> buf4(data2);

	if (!test_PushBack(buf2))
		return test_PushBack_ErrorMsg;

	ZTEST_BeginHandleAssert();

	buf2.PushBack(15);	//This will ruin buf2, so don't use it anymore

	ZTEST_EndHandleAssert();

	TASSERT(ZTEST_CheckAssert(), "PushBack() on full buffer failed to assert!");

	return ZTEST_SUCCESS;
}

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

static const char* test_PushBack_OverflowIgnore() 
{
	int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	ZArray<int> data1(testData, 10, 10);
	ZArray<int> data2(testData, 6, 20);

	ZRingBuffer<int, ZRingBuffer_OverflowIgnore> buf1;
	ZRingBuffer<int, ZRingBuffer_OverflowIgnore> buf2(10);
	ZRingBuffer<int, ZRingBuffer_OverflowIgnore> buf3(data1);
	ZRingBuffer<int, ZRingBuffer_OverflowIgnore> buf4(data2);

	if (!test_PushBack(buf2))
		return test_PushBack_ErrorMsg;

	buf2.PushBack(15);

	TASSERT(buf2.Back() == 9, "PushBack() added element on full buffer with ZRingBuffer_OverflowIgnore policy (Back)!");
	TASSERT(buf2.Front() == 0, "PushBack() added element on full buffer with ZRingBuffer_OverflowIgnore policy (Front)!");
	TASSERT(buf2.Size() == 10, "PushBack() added element on full buffer with ZRingBuffer_OverflowIgnore policy (Size)!");
	TASSERT(buf2.Full(), "PushBack() added element on full buffer with ZRingBuffer_OverflowIgnore policy (Full)!");

	return ZTEST_SUCCESS;
}

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

static const char* test_PushBack_OverflowDropFront()
{
	int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	ZArray<int> data1(testData, 10, 10);
	ZArray<int> data2(testData, 6, 20);

	ZRingBuffer<int, ZRingBuffer_OverflowDropFront> buf1;
	ZRingBuffer<int, ZRingBuffer_OverflowDropFront> buf2(10);
	ZRingBuffer<int, ZRingBuffer_OverflowDropFront> buf3(data1);
	ZRingBuffer<int, ZRingBuffer_OverflowDropFront> buf4(data2);

	if (!test_PushBack(buf2))
		return test_PushBack_ErrorMsg;

	buf2.PushBack(15);

	TASSERT(buf2.Back() == 15, "PushBack() failed to correctly set back element with ZRingBuffer_OverflowDropFront policy!");
	TASSERT(buf2.Front() == 1, "PushBack() failed to drop front element with ZRingBuffer_OverflowDropFront policy!");
	TASSERT(buf2.Size() == 10, "PushBack() failed to keep size with ZRingBuffer_OverflowDropFront policy!");
	TASSERT(buf2.Full(), "PushBack() failed to keep buffer full with ZRingBuffer_OverflowDropFront policy!");

	return ZTEST_SUCCESS;
}

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

static const char* test_PushBack_OverflowDropBack() 
{
	int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	ZArray<int> data1(testData, 10, 10);
	ZArray<int> data2(testData, 6, 20);

	ZRingBuffer<int, ZRingBuffer_OverflowDropBack> buf1;
	ZRingBuffer<int, ZRingBuffer_OverflowDropBack> buf2(10);
	ZRingBuffer<int, ZRingBuffer_OverflowDropBack> buf3(data1);
	ZRingBuffer<int, ZRingBuffer_OverflowDropBack> buf4(data2);

	if (!test_PushBack(buf2))
		return test_PushBack_ErrorMsg;

	buf2.PushBack(15);

	TASSERT(buf2.Back() == 15, "PushBack() failed to correctly set back element with ZRingBuffer_OverflowDropBack policy!");
	TASSERT(buf2.Front() == 0, "PushBack() improperly modified front element with ZRingBuffer_OverflowDropBack policy!");
	TASSERT(buf2.Size() == 10, "PushBack() failed to keep size with ZRingBuffer_OverflowDropBack policy!");
	TASSERT(buf2.Full(), "PushBack() failed to keep buffer full with ZRingBuffer_OverflowDropBack policy!");

	return ZTEST_SUCCESS;
}

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

static const char* test_PushBack_OverflowOverwrite()
{
	int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	ZArray<int> data1(testData, 10, 10);
	ZArray<int> data2(testData, 6, 20);

	ZRingBuffer<int, ZRingBuffer_OverflowOverwrite> buf1;
	ZRingBuffer<int, ZRingBuffer_OverflowOverwrite> buf2(10);
	ZRingBuffer<int, ZRingBuffer_OverflowOverwrite> buf3(data1);
	ZRingBuffer<int, ZRingBuffer_OverflowOverwrite> buf4(data2);

	if (!test_PushBack(buf2))
		return test_PushBack_ErrorMsg;

	buf2.PushBack(15);

	TASSERT(buf2.Back() == 15, "PushBack() failed to correctly overwrite back element with ZRingBuffer_OverflowOverwrite policy!");
	TASSERT(buf2.Front() == 0, "PushBack() improperly modified front element with ZRingBuffer_OverflowOverwrite policy!");
	TASSERT(buf2.Size() == 10, "PushBack() failed to keep size with ZRingBuffer_OverflowOverwrite policy!");
	TASSERT(buf2.Full(), "PushBack() failed to keep buffer full with ZRingBuffer_OverflowOverwrite policy!");

	return ZTEST_SUCCESS;
}

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

static const char* test_PushBack_OverflowEvict() 
{
	int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	ZArray<int> data1(testData, 10, 10);
	ZArray<int> data2(testData, 6, 20);

	ZRingBuffer<int, ZRingBuffer_OverflowEvict> buf1;
	ZRingBuffer<int, ZRingBuffer_OverflowEvict> buf2(10);
	ZRingBuffer<int, ZRingBuffer_OverflowEvict> buf3(data1);
	ZRingBuffer<int, ZRingBuffer_OverflowEvict> buf4(data2);

	if (!test_PushBack(buf2))
		return test_PushBack_ErrorMsg;

	buf2.PushBack(15);

	TASSERT(buf2.Back() == 15, "PushBack() failed to correctly set back element with ZRingBuffer_OverflowEvict policy!");
	TASSERT(buf2.Front() == 1, "PushBack() failed to evict front element with ZRingBuffer_OverflowEvict policy!");
	TASSERT(buf2.Size() == 10, "PushBack() failed to keep size with ZRingBuffer_OverflowEvict policy!");
	TASSERT(buf2.Full(), "PushBack() failed to keep buffer full with ZRingBuffer_OverflowEvict policy!");

	return ZTEST_SUCCESS;
}

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

static const char* test_PushBack_OverflowGrow() 
{
	int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	ZArray<int> data1(testData, 10, 10);
	ZArray<int> data2(testData, 6, 20);

	ZRingBuffer<int, ZRingBuffer_OverflowGrow> buf1;
	ZRingBuffer<int, ZRingBuffer_OverflowGrow> buf2(10);
	ZRingBuffer<int, ZRingBuffer_OverflowGrow> buf3(data1);
	ZRingBuffer<int, ZRingBuffer_OverflowGrow> buf4(data2);

	if (!test_PushBack(buf2))
		return test_PushBack_ErrorMsg;

	buf2.PushBack(15);

	TASSERT(buf2.Back() == 15, "PushBack() failed to add back element with ZRingBuffer_OverflowGrow policy!");
	TASSERT(buf2.Front() == 0, "PushBack() improperly modified front element with ZRingBuffer_OverflowGrow policy!");
	TASSERT(buf2.Size() == 11, "PushBack() did not properly increment size with ZRingBuffer_OverflowGrow policy!");
	TASSERT(buf2.Capacity() > 10, "PushBack() did not properly grow the buffer with ZRingBuffer_OverflowGrow policy!");

	return ZTEST_SUCCESS;
}

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

static const char* test_AbsoluteIndex()
{
	int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	ZArray<int> data1(testData, 10, 10);
	ZArray<int> data2(testData, 6, 20);

	ZRingBuffer<int> buf1;
	ZRingBuffer<int> buf2(10);
	ZRingBuffer<int> buf3(data1);
	ZRingBuffer<int> buf4(data2);

	size_t i;

	for (i = 0; i < buf3.Size(); i++)
	{
		TASSERT(buf3.ActualIndex(i) == i, "AbsoluteIndex() does not return correct value on aligned buffer!");
	}

	buf3.PopBack();

	TASSERT(buf3.ActualIndex(0) == 0, "AbsoluteIndex(0) returns non-zero after PopBack()!");
	
	buf3.PopFront();

	TASSERT(buf3.ActualIndex(0) == 1, "AbsoluteIndex(0) returns incorrect value after PopFront()!");

	buf3.PushBack(9);
	buf3.PushBack(10);

	//New layout: [(Back) 10, (Front) 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

	TASSERT(buf3.ActualIndex(9) == 0, "AbsoluteIndex(9) returns incorrect value with Back < Front!");

	buf3.PopFront();

	ZTEST_BeginHandleAssert();

	buf3.ActualIndex(9);

	ZTEST_EndHandleAssert();

	TASSERT(ZTEST_CheckAssert(), "AbsoluteIndex(9) with 9 out-of-bounds did not trigger assert!");

	return ZTEST_SUCCESS;
}

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

static const char* test_At() 
{
	int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	ZArray<int> data1(testData, 10, 10);
	ZArray<int> data2(testData, 6, 20);

	ZRingBuffer<int> buf1;
	ZRingBuffer<int> buf2(10);
	ZRingBuffer<int> buf3(data1);
	ZRingBuffer<int> buf4(data2);

	int i;

	for (i = 0; i < (int)buf3.Size(); i++)
	{
		TASSERT(buf3.At(i) == i, "At() does not return correct value on aligned buffer!");
	}

	buf3.PopBack();

	TASSERT(buf3.At(0) == 0, "At(0) returns non-zero after PopBack()!");

	buf3.PopFront();

	TASSERT(buf3.At(0) == 1, "At(0) returns incorrect value after PopFront()!");

	buf3.PushBack(9);
	buf3.PushBack(10);

	//New layout: [(Back) 10, (Front) 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

	TASSERT(buf3.At(9) == 10, "At(9) returns incorrect value with Back < Front!");

	buf3.PopFront();

	ZTEST_BeginHandleAssert();

	buf3.At(9);

	ZTEST_EndHandleAssert();

	TASSERT(ZTEST_CheckAssert(), "At(9) with 9 out-of-bounds did not trigger assert!");

	return ZTEST_SUCCESS;
}

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

static const char* test_Clear() 
{
	int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	ZArray<int> data1(testData, 10, 10);
	ZArray<int> data2(testData, 6, 20);

	ZRingBuffer<int> buf1;
	ZRingBuffer<int> buf2(10);
	ZRingBuffer<int> buf3(data1);
	ZRingBuffer<int> buf4(data2);

	buf3.Clear();

	TASSERT(buf3.Size() == 0, "Clear() failed to reduce buffer size to zero!");
	TASSERT(buf3.Capacity() == 10, "Clear() improperly reduced capacity!");

	buf4.Clear(64);

	TASSERT(buf4.Size() == 0, "Clear(64) failed to reduce buffer size to zero!");
	TASSERT(buf4.Capacity() == 64, "Clear(64) failed to set proper capacity!");

	return ZTEST_SUCCESS;
}

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

static const char* test_Erase() 
{
	int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	ZArray<int> data1(testData, 10, 10);
	ZArray<int> data2(testData, 6, 20);

	ZRingBuffer<int> buf1;
	ZRingBuffer<int> buf2(10);
	ZRingBuffer<int> buf3(data1);
	ZRingBuffer<int> buf4(data2);

	buf3.PopFront();
	buf3.PushBack(10);

	//New layout: [(Back) 10, (Front) 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

	buf3.Erase(0);

	TASSERT(buf3.Size() == 9, "Erase() did not correctly reduce size!");
	TASSERT(buf3.At(0) == 2, "Erase() did not erase correct element!");

	buf3.Erase(4, 6);

	TASSERT(buf3.Size() == 7, "Erase(i, j) did not correctly reduce size!");
	TASSERT(buf3.At(4) == 8, "Erase(i, j) did not erase correct elements!");
	TASSERT(buf3.At(5) == 9, "Erase(i, j) did not erase correct elements!");

	return ZTEST_SUCCESS;
}

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

static const char* test_Insert() 
{
	int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	ZArray<int> data1(testData, 10, 10);
	ZArray<int> data2(testData, 6, 20);

	ZRingBuffer<int> buf1;
	ZRingBuffer<int> buf2(10);
	ZRingBuffer<int> buf3(data1);
	ZRingBuffer<int> buf4(data2);

	buf3.PopFront();
	buf3.PushBack(10);

	buf3.PopFront();
	buf3.PopFront();

	//New layout: [(Back) 10, x, x, (Front) 3, 4, 5, 6, 7, 8, 9 ]

	buf3.Insert(2, 15, 1); //Insert at index 2 the value 15, 1 time

	//New layout: [(Front) 3, 4, 15, 5, 6, 7, 8, 9, (Back) 10, x ]
	
	TASSERT(buf3.Size() == 9, "Insert(i, j, k) did not correctly increase buffer size!");
	TASSERT(buf3.Front() == 3, "Insert(i, j, k) improperly modified Front() value!");
	TASSERT(buf3.Back() == 10, "Insert(i, j, k) improperly modified Back() value!");
	TASSERT(buf3.At(2) == 15, "Insert(i, j, k) did not insert correct value at location 2!");

	buf3.PopFront();
	buf3.PopFront();

	//New layout: [ x, x, (Front) 15, 5, 6, 7, 8, 9, (Back) 10, x ]

	buf3.Insert(1, 15, 2); //Insert at index 1 the value 15, 2 times

	//New layout: [ (Front) 15, 15, 15, 5, 6, 7, 8, 9, (Back) 10, x ]

	TASSERT(buf3.Size() == 9, "Insert(i, j, 2k) did not correctly increase buffer size!");
	TASSERT(buf3.Front() == 15, "Insert(i, j, 2k) improperly modified Front() value!");
	TASSERT(buf3.Back() == 10, "Insert(i, j, 2k) improperly modified Back() value!");
	TASSERT(buf3.At(1) == 15, "Insert(i, j, 2k) did not insert correct value at location 1!");
	TASSERT(buf3.At(2) == 15, "Insert(i, j, 2k) did not insert correct value at location 2!");
	
	buf3.PopFront();
	buf3.PopFront();
	buf3.PopFront();

	//New layout: [ x, x, x, (Front) 5, 6, 7, 8, 9, (Back) 10, x ]

	ZArray<int> data3(testData, 4, 10);	//Array [0, 1, 2, 3] with capacity 10

	buf3.Insert(6, data3);

	//New layout: [	(Front) 5, 6, 7, 8, 9, 10, 0, 1, 2, (Back) 3 ]

	TASSERT(buf3.Size() == 10, "Insert(i, array) did not correctly increase buffer size!");
	TASSERT(buf3.Front() == 5, "Insert(i, array) improperly modified Front() value!");
	TASSERT(buf3.Back() == 3, "Insert(i, array) did not correctly set Back() value!");
	TASSERT(buf3.At(5) == 10, "Insert(i, array) improperly set At(5) value!");
	TASSERT(buf3.At(6) == 0, "Insert(i, array) did not correctly set At(6) value!");

	ZRingBuffer<int> buf5(data1);

	buf5.Insert(0, buf3, 6, 4);	//Insert at index 0 the values contained in buf3 starting at index 6 (4 values)

	//New layout: [ (Front) 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 8, (Back) 9 ]

	TASSERT(buf5.Size() == 14, "Insert(i, buffer) did not correctly increase buffer size!");
	TASSERT(buf5.Front() == 0, "Insert(i, buffer) did not correctly set Front() value!");
	TASSERT(buf5.Back() == 9, "Insert(i, buffer) improperly modified Back() value!");

	return ZTEST_SUCCESS;
}

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

static const char* test_TryPushBack()
{
	int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	ZArray<int> data1(testData, 10, 10);
	ZArray<int> data2(testData, 6, 20);

	ZRingBuffer<int> buf1;
	ZRingBuffer<int> buf2(10);
	ZRingBuffer<int> buf3(data1);
	ZRingBuffer<int> buf4(data2);

	bool val;

	val = buf1.TryPushBack(0);

	TASSERT(val == true, "TryPushBack() fails with empty buffer!");

	val = buf3.TryPushBack(0);

	TASSERT(val == false, "TryPushBack() succeeds with full buffer!");

	return ZTEST_SUCCESS;
}

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

static const char* test_TryPushFront()
{
	int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	ZArray<int> data1(testData, 10, 10);
	ZArray<int> data2(testData, 6, 20);

	ZRingBuffer<int> buf1;
	ZRingBuffer<int> buf2(10);
	ZRingBuffer<int> buf3(data1);
	ZRingBuffer<int> buf4(data2);

	bool val;

	val = buf1.TryPushFront(0);

	TASSERT(val == true, "TryPushFront() fails with empty buffer!");

	val = buf3.TryPushFront(0);

	TASSERT(val == false, "TryPushFront() succeeds with full buffer!");

	return ZTEST_SUCCESS;
}

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

static const char* test_Equals()
{
	int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	ZArray<int> data1(testData, 10, 10);
	ZArray<int> data2(testData, 6, 20);

	ZRingBuffer<int> buf1;
	ZRingBuffer<int> buf2(10);
	ZRingBuffer<int> buf3(data1);
	ZRingBuffer<int> buf4(data2);
	ZRingBuffer<int> buf5(data2);

	TASSERT(buf1.Equals(buf1), "Equals returns false on same buffer!");
	TASSERT(buf1.Equals(buf2), "Equals returns false on buffers with different capacity!");
	TASSERT(!buf1.Equals(buf3), "Equals returns true on empty buffer and 10-element buffer!");
	TASSERT(!buf1.Equals(buf4), "Equals returns true on empty buffer and 6-element buffer!");

	TASSERT(buf3.Equals(buf3), "Equals returns false on same (non-empty) buffer!");
	TASSERT(!buf3.Equals(buf4), "Equals returns true on non-equivalent buffers!");

	TASSERT(buf4.Equals(buf5), "Equals returns false on equivalent buffers!");

	return ZTEST_SUCCESS;
}

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

static const char* test_Copy()
{
	int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	ZArray<int> data1(testData, 10, 10);
	ZArray<int> data2(testData, 6, 20);

	ZRingBuffer<int> buf1;
	ZRingBuffer<int> buf2(10);
	ZRingBuffer<int> buf3(data1);
	ZRingBuffer<int> buf4(data2);

	buf1.Copy(buf2);

	TASSERT(buf1.Empty(), "Copy() fails on empty buffer source and target!");
	
	buf1.Copy(buf3);

	TASSERT(buf1.Equals(buf3), "Equals() returns false after Copy() with empty target!");

	buf4.Copy(buf3);

	TASSERT(buf4.Equals(buf3), "Equals() returns false after Copy() with non-empty target!");

	buf4.Copy(buf2);

	TASSERT(buf4.Empty(), "Copy() fails with empty buffer source and non-empty target!");

	return ZTEST_SUCCESS;
}

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

static const char* test_Stack()
{
	int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	//Test using front loading
	ZRingBuffer<int> buf1(10);
	
	for (int i = 0; i < 5; i++)
		buf1.PushFront(testData[i]);

	TASSERT (buf1.Size() == 5, "After 5 front pushes, Size() returned something other than 5!");

	for (int i = 0; i < 5; i++)
	{
		int temp = buf1.PopFront();
		
		TASSERT(temp == testData[4 - i], "Ring buffer corrupted while front loading as stack!");
	}

	//Test using back loading
	ZRingBuffer<int> buf2(10);

	for (int i = 0; i < 5; i++)
		buf2.PushBack(testData[i]);

	TASSERT(buf2.Size() == 5, "After 5 back pushes, Size() returned something other than 5!");

	for (int i = 0; i < 5; i++)
	{
		int temp = buf2.PopBack();

		TASSERT(temp == testData[4 - i], "Ring buffer corrupted while back loading as stack!");
	}

	return ZTEST_SUCCESS;
}

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

static const char* test_Queue()
{
	int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

	//Test front loading
	ZRingBuffer<int> buf1(10);

	for (int i = 0; i < 5; i++)
		buf1.PushFront(testData[i]);
	
	TASSERT(buf1.Size() == 5, "After 5 front pushes, Size() returned something other than 5!");

	for (int i = 0; i < 5; i++)
	{
		int temp = buf1.PopBack();

		TASSERT(temp == testData[i], "Ring buffer corrupted while front loading as queue!");
	}

	//Test back loading
	ZRingBuffer<int> buf2(10);

	for (int i = 0; i < 5; i++)
		buf2.PushBack(testData[i]);

	TASSERT(buf2.Size() == 5, "After 5 back pushes, GetSize() returned something other than 5!");

	for (int i = 0; i < 5; i++)
	{
		int temp = buf2.PopFront();

		TASSERT(temp == testData[i], "Ring buffer corrupted while back loading as queue!");
	}

	return ZTEST_SUCCESS;
}

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

static const char* test_Alternating()
{
	ZRingBuffer<int> buffer(10);

	int testArray[] = {0, 1, 2, 3, 4, 5, 6, 7};
	int correctResults[] = {7, 5, 3, 1, 0, 2, 4, 6};

	buffer.PushFront(testArray[0]);
	buffer.PushBack(testArray[1]);
	buffer.PushFront(testArray[2]);
	buffer.PushBack(testArray[3]);
	buffer.PushFront(testArray[4]);
	buffer.PushBack(testArray[5]);
	buffer.PushFront(testArray[6]);
	buffer.PushBack(testArray[7]);

	TASSERT(buffer.Size() == 8, "After 8 pushes, ring buffer returned something other than 8!");

	for (int i = 0; i < 8; i++)
	{
		int temp = buffer.PopBack();
		
		TASSERT(temp == correctResults[i], "Ring buffer corrupted while alternate loading!");
	}

	return ZTEST_SUCCESS;
}
