#include "ZUnitTest.hpp" #include #include //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 arr1; ZArray arr2(5); ZArray 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 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 arr5; ZArray arr6(5); ZArray 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 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 list; list.PushBack(1); list.PushBack(2); list.PushBack(3); list.PushBack(4); list.PushBack(5); list.PushBack(6); ZArray 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 arr1; ZArray arr2(5); ZArray 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 arr1; ZArray arr2(5); ZArray 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 arr1; ZArray arr2(5); ZArray arr3(testData, 6, 10); ZArray arr4(testData, 10, 10); ZArray 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 arr1; ZArray arr2(5); ZArray 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 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 > 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 arr1; ZArray arr2(5); ZArray 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 arr1; ZArray arr2(5); ZArray 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 arr1; ZArray arr2(5); ZArray arr3(testData, 6, 10); ZArray::Iterator itr1_1 = arr1.Begin(); ZArray::Iterator itr1_2 = arr1.End(); TASSERT(itr1_1 == itr1_2, "Empty array does not return Begin() == End()!"); ZArray::Iterator itr3_1 = arr3.Begin(); ZArray::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 arr1; ZArray arr2(5); ZArray arr3(testData, 6, 10); ZArray::Iterator itr1_1 = arr1.Begin(); ZArray::Iterator itr3_1 = arr3.Begin(); ZArray::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; }