Files
libsst/ZTestSuite/Test-ZArray.cpp
2026-04-03 00:22:39 -05:00

549 lines
18 KiB
C++

#include "ZUnitTest.hpp"
#include <ZSTL/ZArray.hpp>
#include <string.h> //for memcmp
static const char* test_Constructors_Size_Capacity();
static const char* test_SliceConstructor();
static const char* test_At_Data();
static const char* test_Copy_Equals_Swap();
static const char* test_Allocator();
static const char* test_Reserve_Resize_Clear_Empty();
static const char* test_Push_Pop();
static const char* test_Insert_Erase();
static const char* test_Begin_End();
static const char* test_Find_Iterator();
//List of unit tests
ZUnitTest ZArrayUnitTests[] =
{
{ "ZArray: Constructors, Size, Capacity", test_Constructors_Size_Capacity },
{ "ZArray: Slice Constructor", test_SliceConstructor },
{ "ZArray: At, Data", test_At_Data },
{ "ZArray: Copy, Equals, Swap", test_Copy_Equals_Swap },
{ "ZArray: Allocator", test_Allocator },
{ "ZArray: Reserve, Resize, Clear, Empty", test_Reserve_Resize_Clear_Empty },
{ "ZArray: Push, Pop", test_Push_Pop },
{ "ZArray: Insert, Erase", test_Insert_Erase },
{ "ZArray: Begin, End", test_Begin_End },
{ "ZArray: Iterator", test_Find_Iterator }
};
DECLARE_ZTESTBLOCK(ZArray);
/*************************************************************************/
namespace ZArrayTestObjects
{
struct TestObject
{
//Constructor
TestObject() { TestObject::Instances++; }
//Destructor
~TestObject() { TestObject::Instances--; }
//Static Instance Count
static size_t Instances;
};
//Defaults to zero
size_t TestObject::Instances = 0;
//We use this allocator to ensure that allocator-agnostic functions work correctly
class IntArrayAllocator
{
public:
int* Allocate(size_t _size)
{
return new (std::nothrow) int[_size];
}
void Deallocate(int* _ptr, size_t _size)
{
(void)_size;
delete[] _ptr;
}
};
}
static const char* test_Constructors_Size_Capacity()
{
int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
//First we test our basic constructors with default allocator
ZArray<int> arr1;
ZArray<int> arr2(5);
ZArray<int> arr3(testData, 6, 10);
TASSERT(arr1.Capacity() == ZARRAY_DEFAULT_CAPACITY, "Capacity() returns wrong value after default constructor!");
TASSERT(arr1.Size() == 0, "Size() returns wrong value after default constructor!");
TASSERT(arr2.Capacity() == 5, "Capacity() returns wrong value after constructing with explicit capacity");
TASSERT(arr2.Size() == 0, "Size() returns wrong value after constructing with explicit capacity!");
TASSERT(arr3.Capacity() == 10, "Capacity() returns wrong value after data constructor!");
TASSERT(arr3.Size() == 6, "Size() returns wrong value after data constructor!");
//Test our copy constructor with typename A == typename B
ZArray<int> arr4(arr3);
TASSERT(arr3.Capacity() == 10, "arr3 modified after copy constructor! (Capacity)");
TASSERT(arr3.Size() == 6, "arr3 modified after copy constructor! (Size)");
TASSERT(arr4.Capacity() == 10, "Capacity() returns wrong value after copy constructor!");
TASSERT(arr4.Size() == 6, "Size() returns wrong value after copy constructor!");
//Test our basic constructors with provided allocator
ZArray<int, ZArrayTestObjects::IntArrayAllocator> arr5;
ZArray<int, ZArrayTestObjects::IntArrayAllocator> arr6(5);
ZArray<int, ZArrayTestObjects::IntArrayAllocator> arr7(testData, 6, 10);
TASSERT(arr5.Capacity() == ZARRAY_DEFAULT_CAPACITY, "Capacity() returns wrong value after default constructor! (IntArrayAllocator)");
TASSERT(arr5.Size() == 0, "Size() returns wrong value after default constructor! (IntArrayAllocator)");
TASSERT(arr6.Capacity() == 5, "Capacity() returns wrong value after constructing with explicit capacity! (IntArrayAllocator)");
TASSERT(arr6.Size() == 0, "Size() returns wrong value after constructing with explicit capacity! (IntArrayAllocator)");
TASSERT(arr7.Capacity() == 10, "Capacity() returns wrong value after data constructor! (IntArrayAllocator)");
TASSERT(arr7.Size() == 6, "Size() returns wrong value after data constructor! (IntArrayAllocator)");
//Test our copy constructor with typename A != typename B
ZArray<int> arr8(arr7);
TASSERT(arr7.Capacity() == 10, "arr7 modified after copy constructor! (Capacity)");
TASSERT(arr7.Size() == 6, "arr7 modified after copy constructor! (Size)");
TASSERT(arr8.Capacity() == 10, "Capacity() returns wrong value after copy constructor! (IntArrayAllocator)");
TASSERT(arr8.Size() == 6, "Size() returns wrong value after copy constructor! (IntArrayAllocator)");
return ZTEST_SUCCESS;
}
/*************************************************************************/
static const char* test_SliceConstructor()
{
ZArray<int> list;
list.PushBack(1);
list.PushBack(2);
list.PushBack(3);
list.PushBack(4);
list.PushBack(5);
list.PushBack(6);
ZArray<int> slice(list, 2, 5);
TASSERT(slice.Size() == 3, "Slice() created slice of incorrect size!");
TASSERT(slice.PopFront() == 3, "Slice() created incorrect slice!");
TASSERT(slice.PopFront() == 4, "Slice() created incorrect slice!");
TASSERT(slice.PopFront() == 5, "Slice() created incorrect slice!");
return ZTEST_SUCCESS;
}
/*************************************************************************/
static const char* test_At_Data()
{
int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
ZArray<int> arr1;
ZArray<int> arr2(5);
ZArray<int> arr3(testData, 6, 10);
//Ensure that 'At' returns proper data
TASSERT(arr3.At(0) == testData[0], "arr3[0] != testData[0]");
TASSERT(arr3.At(1) == testData[1], "arr3[1] != testData[1]");
TASSERT(arr3.At(2) == testData[2], "arr3[2] != testData[2]");
TASSERT(arr3.At(3) == testData[3], "arr3[3] != testData[3]");
TASSERT(arr3.At(4) == testData[4], "arr3[4] != testData[4]");
TASSERT(arr3.At(5) == testData[5], "arr3[5] != testData[5]");
//Ensure that Data() != testData (this would be bad)
TASSERT(arr3.Data() != testData, "Data constructor failed to copy data, instead took ownership of array!");
//Ensure that 'At(i)' returns the same as 'Data()[i]'
TASSERT(arr3.At(0) == arr3.Data()[0], "arr3[0] != arr3.Data()[0]");
TASSERT(arr3.At(1) == arr3.Data()[1], "arr3[1] != arr3.Data()[1]");
TASSERT(arr3.At(2) == arr3.Data()[2], "arr3[2] != arr3.Data()[2]");
TASSERT(arr3.At(3) == arr3.Data()[3], "arr3[3] != arr3.Data()[3]");
TASSERT(arr3.At(4) == arr3.Data()[4], "arr3[4] != arr3.Data()[4]");
TASSERT(arr3.At(5) == arr3.Data()[5], "arr3[5] != arr3.Data()[5]");
return ZTEST_SUCCESS;
}
/*************************************************************************/
static const char* test_Copy_Equals_Swap()
{
int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
ZArray<int> arr1;
ZArray<int> arr2(5);
ZArray<int> arr3(testData, 6, 10);
arr2.Copy(arr3);
TASSERT(arr3.At(0) == arr2.At(0), "arr3.At(0) != arr2.At(0) after Copy()!");
TASSERT(arr3.At(1) == arr2.At(1), "arr3.At(1) != arr2.At(1) after Copy()!");
TASSERT(arr3.At(2) == arr2.At(2), "arr3.At(2) != arr2.At(2) after Copy()!");
TASSERT(arr3.At(3) == arr2.At(3), "arr3.At(3) != arr2.At(3) after Copy()!");
TASSERT(arr3.At(4) == arr2.At(4), "arr3.At(4) != arr2.At(4) after Copy()!");
TASSERT(arr3.At(5) == arr2.At(5), "arr3.At(5) != arr2.At(5) after Copy()!");
TASSERT(arr2.Equals(arr3), "arr2.Equals(arr3) returns false after Copy()!")
TASSERT(arr3.Equals(arr2), "arr3.Equals(arr2) returns false after Copy()!")
arr1.Swap(arr3);
TASSERT(arr2.Equals(arr1), "arr2.Equals(arr2) returns false after Swap()!");
TASSERT(!arr3.Equals(arr1), "arr3.Equals(arr1) returns true after Swap()!");
return ZTEST_SUCCESS;
}
/*************************************************************************/
class PooledIntArrayAllocator
{
public:
static size_t GlobalArray[256];
static size_t GlobalTracker;
size_t CurrentSize;
size_t* Allocate(size_t _size)
{
GlobalTracker = GlobalTracker + _size;
CurrentSize = _size;
return &GlobalArray[GlobalTracker - _size];
}
void Deallocate(size_t* _ptr, size_t _size)
{
(void)_ptr;
(void)_size;
}
};
size_t PooledIntArrayAllocator::GlobalTracker = 0;
size_t PooledIntArrayAllocator::GlobalArray[256];
static const char* test_Allocator()
{
size_t testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
ZArray<size_t> arr1;
ZArray<size_t> arr2(5);
ZArray<size_t> arr3(testData, 6, 10);
ZArray<size_t, PooledIntArrayAllocator> arr4(testData, 10, 10);
ZArray<size_t, PooledIntArrayAllocator> arr5(testData, 5, 5);
TASSERT(arr4.Allocator().CurrentSize != arr5.Allocator().CurrentSize,
"Allocator returns invalid allocator instances!");
for (int i = 0; i < 10; i++)
{
TASSERT(memcmp(arr4.Allocator().GlobalArray, arr5.Allocator().GlobalArray, 256 * sizeof(size_t)) == 0,
"arr4 and arr5 do not share static global data with pooled allocator!");
}
return ZTEST_SUCCESS;
}
/*************************************************************************/
using namespace ZArrayTestObjects;
static const char* test_Reserve_Resize_Clear_Empty()
{
int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
ZArray<int> arr1;
ZArray<int> arr2(5);
ZArray<int> arr3(testData, 6, 10);
arr3.Reserve(arr3.Size());
TASSERT(arr3.Capacity() != arr3.Size(), "Reserve(Size()) improperly reduced capacity!");
arr3.Reserve(arr3.Size(), true);
TASSERT(arr3.Capacity() == arr3.Size(), "Reserve(Size(), true) did not reduce capacity to proper value!");
arr3.Reserve(10);
TASSERT(arr3.Capacity() == 10, "Reserve(10) did not reserve enough capacity!");
TASSERT(arr3.Size() == 6, "Reserve(10) modified the size!");
for (size_t i = 0; i < arr3.Size(); i++)
{
TASSERT(arr3[i] == (int)i, "Reserve(10) modified elements!");
}
arr3.Resize(arr3.Capacity());
TASSERT(arr3.Capacity() == 10, "Resize(Capacity()) improperly modified capacity!");
TASSERT(arr3.Size() == 10, "Resize(Capacity() did not grow arr3 to the correct size!");
for (int i = 0; i < 6; i++)
{
TASSERT(arr3[i] == i, "Resize(Capacity() improperly modifed existing elements!");
}
arr3.Resize(6);
TASSERT(arr3.Capacity() == 10, "Resize(6) with _size < Capacity() improperly modified capacity!");
TASSERT(arr3.Size() == 6, "Resize(6) did not shrink arr3 to the correct size!");
for (size_t i = 0; i < arr3.Size(); i++)
{
TASSERT(arr3[i] == (int)i, "Resize(6) improperly modified existing elements!");
}
arr3.Resize(arr3.Capacity(), -1);
TASSERT(arr3.Capacity() == 10, "Resize(Capacity(), -1) improperly modified capacity!");
TASSERT(arr3.Size() == 10, "Resize(Capacity(), -1) did not grow arr3 to the correct size!");
for (int i = 0; i < 6; i++)
{
TASSERT(arr3[i] == i, "Resize(Capacity(), -1) improperly modified existing elements!");
}
for (size_t i = 6; i < arr3.Size(); i++)
{
TASSERT(arr3[i] == -1, "Resize(Capacity(), -1) improperly set new values!");
}
arr3.Resize(32, -1);
TASSERT(arr3.Capacity() == 32, "Resize(32, -1) did not grow capacity!");
TASSERT(arr3.Size() == 32, "Resize(32, -1) did not grow arr3 to the correct size!");
TASSERT(!arr3.Empty(), "Empty() did not return false when Size() == 32!");
arr3.Clear();
TASSERT(arr3.Capacity() == 32, "Clear() improperly reduced capacity!");
TASSERT(arr3.Size() == 0, "Clear() did not correctly reduce size!");
TASSERT(arr3.Empty(), "Empty() did not return true when Size() == 0!");
arr3.Clear(arr3.Capacity());
TASSERT(arr3.Capacity() == 32, "Clear(Capacity()) improperly reduced capacity!");
TASSERT(arr3.Empty(), "Empty() did not return true when Size() == 0!");
arr3.Clear(256);
TASSERT(arr3.Capacity() == 256, "Clear(256) did not correctly grow capacity!");
TASSERT(arr3.Empty(), "Empty() did not return true when Size() == 0!");
/* Testing memory allocator guarantees */
{
ZArray<TestObject> arr4;
TASSERT(TestObject::Instances == ZARRAY_DEFAULT_ALLOCATOR_STORAGE, "TestObject array constructed invalid number of instances with default constructor!");
}
TASSERT(TestObject::Instances == 0, "TestObject array failed to deallocate instances when out of scope!");
ZArray<TestObject, ZArrayAllocator<ZArrayTestObjects::TestObject, 0> > arr5(0);
TASSERT(TestObject::Instances == 0, "TestObject array constructed instances with zero capacity constructor!");
arr5.Reserve(5);
TASSERT(TestObject::Instances == 5, "TestObject array constructed invalid number of instances after Reserve(5)!");
arr5.Reserve(2);
TASSERT(TestObject::Instances == 5, "TestObject array destructed instances when _reallocate was false!");
arr5.Reserve(2, true);
TASSERT(TestObject::Instances == 2, "TestObject array failed to deallocate instances when _reallocate was true!");
arr5.Reserve(0);
TASSERT(TestObject::Instances == 0, "TestObject array failed to deallocate all instances when Reserve(0) was called!");
return ZTEST_SUCCESS;
}
/*************************************************************************/
static const char* test_Push_Pop()
{
int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
ZArray<int> arr1;
ZArray<int> arr2(5);
ZArray<int> arr3(testData, 6, 10);
int val;
val = arr3.PopBack();
TASSERT(val == 5, "Pop() did not return correct value!");
TASSERT(arr3.Size() == 5, "Pop() did not correctly reduce size!");
TASSERT(arr3.Capacity() == 10, "Pop() incorrectly modified capacity!");
arr3.PushBack(10);
TASSERT(arr3[arr3.Size() - 1] == 10, "PushBack(10) did not push correct value!");
TASSERT(arr3[arr3.Size() - 2] == 4, "PushBack(10) incorrectly modified earlier elements!");
TASSERT(arr3.Size() == 6, "PushBack(10) did not correctly increase size!");
TASSERT(arr3.Capacity() == 10, "Pop() incorrectly modified capacity!");
arr3.PushBack(10);
arr3.PushBack(10);
arr3.PushBack(10);
arr3.PushBack(10);
arr3.PushBack(15); //This one should trigger a capacity increase
TASSERT(arr3.Size() == 11, "PushBack(...) did not correctly increase size!");
TASSERT(arr3.Capacity() > 11, "PushBack(...) with Size() == Capacity() did not increase capacity!");
return ZTEST_SUCCESS;
}
/*************************************************************************/
static const char* test_Insert_Erase()
{
int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
ZArray<int> arr1;
ZArray<int> arr2(5);
ZArray<int> arr3(testData, 6, 10);
//a1 = [1,2,3,4]
arr1.PushBack(1);
arr1.PushBack(2);
arr1.PushBack(3);
arr1.PushBack(4);
//a1 = [0xFF, 1, 2, 3, 4]
arr1.Insert(0, 0xFF);
TASSERT(arr1[0] == 0xFF, "Insert(0, 0xFF) did not set element [0] to 0xFF");
TASSERT(arr1.Size() == 5, "Insert(0, 0xFF) did not set the size correctly");
for(size_t i = 1; i < arr1.Size(); i++)
{
//Elements [1] .. [Size()-1] should be unmodified.
TASSERT(arr1[i] == (int)i, "Insert(0, 0xFF) did not preserve remaining elements' values!");
}
int test = arr1.Erase(0);
TASSERT(test == 0xFF, "Erase(0) returned the wrong value!");
TASSERT(arr1.Size() == 4, "Erase(0) did not correctly set the size!");
for(size_t i = 0; i < arr1.Size(); i++)
{
//Now elements [0..3] should be the values {1, 2, 3, 4} again.
TASSERT(arr1[i] == (int)(i+1), "Erase(0) did not preserve remaining elements' values");
}
return ZTEST_SUCCESS;
}
/*************************************************************************/
static const char* test_Begin_End()
{
int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
ZArray<int> arr1;
ZArray<int> arr2(5);
ZArray<int> arr3(testData, 6, 10);
ZArray<int>::Iterator itr1_1 = arr1.Begin();
ZArray<int>::Iterator itr1_2 = arr1.End();
TASSERT(itr1_1 == itr1_2, "Empty array does not return Begin() == End()!");
ZArray<int>::Iterator itr3_1 = arr3.Begin();
ZArray<int>::Iterator itr3_2 = arr3.End();
TASSERT(itr3_1 != itr3_2, "Non-empty array returns Begin() == End()!");
return ZTEST_SUCCESS;
}
/*************************************************************************/
static const char* test_Find_Iterator()
{
int testData[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
ZArray<int> arr1;
ZArray<int> arr2(5);
ZArray<int> arr3(testData, 6, 10);
ZArray<int>::Iterator itr1_1 = arr1.Begin();
ZArray<int>::Iterator itr3_1 = arr3.Begin();
ZArray<int>::Iterator itr3_2 = arr3.End();
TASSERT(itr1_1.HasNext() == false, "Iterator HasNext() returns true on empty array iterator!");
TASSERT(itr1_1.HasPrev() == false, "Iterator HasPrev() returns true on empty array iterator!");
TASSERT(itr1_1.HasCurrent() == false, "Iterator HasCurrent() returns false on empty array iterator!");
TASSERT(itr3_1.HasNext() == true, "Iterator HasNext() returns false when elements remain!");
TASSERT(itr3_1.HasPrev() == false, "Iterator HasPrev() returns true on Begin() Iterator!");
TASSERT(itr3_1.HasCurrent() == true, "Iterator HasCurrent() returns false on Begin() Iterator!");
TASSERT(itr1_1 >= arr1.Begin(), "Iterator >= did not return true when equal to Begin()!");
TASSERT(itr1_1 <= arr1.Begin(), "Iterator <= did not return true when equal to Begin()!");
TASSERT(itr3_1 <= arr3.End(), "Iterator <= did not return true when less than End()!");
size_t i = 0;
TASSERT(itr3_1.HasCurrent() == true, "Iterator HasCurrent() does not return true when elements exist!");
TASSERT(itr3_1.Get() == arr3[i], "Iterator Get() does not return value at beginning of array with Begin() Iterator!");
TASSERT(*itr3_1 == arr3[i], "Iterator operator * does not return value at beginning of array with Begin() Iterator!");
TASSERT(itr3_1 + 1 == (size_t)arr3[i + 1], "Iterator + operator does not return correct iterator!");
itr3_1 += 1;
TASSERT(*itr3_1 == arr3[i + 1], "Iterator += operator did not correctly update iterator!");
TASSERT((size_t)*itr3_1 > arr3.Begin(), "Iterator > operator did not return true when compared to Begin()!");
for (i = 1; itr3_1 != itr3_2 && i < arr3.Size(); ++i, ++itr3_1)
{
TASSERT(itr3_1 != itr3_2, "Iterator != returns true when iterators not equal!");
TASSERT(itr3_1 == (size_t)i, "Iterator does not cast correctly to size_t!");
TASSERT(itr3_1.HasCurrent() == true, "Iterator HasCurrent() does not return true when elements exist!");
TASSERT(itr3_1.HasPrev() == true, "Iterator HasPrev() returns false when previous elements exist!");
TASSERT(itr3_1.Get() == arr3[i], "Iterator Get() does not return correct value!");
TASSERT(*itr3_1 == arr3[i], "Iterator operator * does not return correct value!");
TASSERT(itr3_1 - 1 == (size_t)arr3[i - 1], "Iterator - operator does not return correct iterator!");
}
TASSERT(itr3_1 == itr3_2, "Iterator did not iterate to end!");
itr3_1 -= 1;
TASSERT(itr3_1 != itr3_2, "Iterator operator -= did not correctly update iterator!");
for (i = itr3_1; itr3_1 != arr3.Begin() && i < arr3.Size(); --i, --itr3_1)
{
TASSERT(itr3_1 != itr3_2, "Iterator != returns true when iterators not equal!");
}
TASSERT(itr3_1 == arr3.Begin(), "Iterator did not iterate to beginning!");
itr3_1 = itr3_2;
TASSERT(itr3_1 == itr3_2, "Iterator operator = did not correctly assign iterator!");
return ZTEST_SUCCESS;
}