Split engine to packages NazaraUtils and NZSL (#375)

* Move code to NazaraUtils and NZSL packages

* Reorder includes

* Tests: Remove glslang and spirv-tools deps

* Tests: Remove glslang init

* Remove NazaraUtils tests and fix Vector4Test

* Fix Linux compilation

* Update msys2-build.yml

* Fix assimp package

* Update xmake.lua

* Update xmake.lua

* Fix shader compilation on MinGW

* Final fixes

* The final fix 2: the fix strikes back!

* Disable cache on CI

* The return of the fix™️
This commit is contained in:
Jérôme Leclercq
2022-05-25 19:36:10 +02:00
committed by GitHub
parent 3f8f1c4653
commit 03e2801dbe
483 changed files with 1139 additions and 59112 deletions

View File

@@ -9,31 +9,6 @@
std::filesystem::path GetResourceDir();
TEST_CASE("Apply", "[CORE][ALGORITHM]")
{
SECTION("Apply lambda to two vector2")
{
Nz::Vector2<int> vector = Nz::Vector2<int>::Unit();
auto lambda = [](const Nz::Vector2<int>& vec1, const Nz::Vector2<int>& vec2)
{
return vec1 + vec2;
};
Nz::Vector2<int> result = Nz::Apply(lambda, std::make_tuple(vector, vector));
REQUIRE(result == (Nz::Vector2<int>::Unit() * 2));
}
/*SECTION("Apply member function to vector2")
{
Nz::Vector2<int> vector = Nz::Vector2<int>::Unit();
int result = Nz::Apply(vector, (int(Nz::Vector2<int>::*)(const Nz::Vector2<int>&)) &Nz::Vector2<int>::Distance<int>, std::make_tuple(vector));
REQUIRE(result == 0);
}*/
}
TEST_CASE("ComputeHash", "[CORE][ALGORITHM]")
{
std::filesystem::path testFilePath = GetResourceDir() / "Logo.png";

View File

@@ -1,372 +0,0 @@
#include <Nazara/Core/Algorithm.hpp>
#include <Nazara/Core/Bitset.hpp>
#include <catch2/catch.hpp>
#include <array>
#include <string>
#include <iostream>
template<typename Block> void Check(const char* title);
template<typename Block> void CheckAppend(const char* title);
template<typename Block> void CheckBitOps(const char* title);
template<typename Block> void CheckBitOpsMultipleBlocks(const char* title);
template<typename Block> void CheckConstructor(const char* title);
template<typename Block> void CheckCopyMoveSwap(const char* title);
template<typename Block> void CheckRead(const char* title);
template<typename Block> void CheckReverse(const char* title);
SCENARIO("Bitset", "[CORE][BITSET]")
{
Check<Nz::UInt8>("Bitset made of 8bits blocks");
Check<Nz::UInt16>("Bitset made of 16bits blocks");
Check<Nz::UInt32>("Bitset made of 32bits blocks");
Check<Nz::UInt64>("Bitset made of 64bits blocks");
}
template<typename Block>
void Check(const char* title)
{
CheckConstructor<Block>(title);
CheckCopyMoveSwap<Block>(title);
CheckBitOps<Block>(title);
CheckBitOpsMultipleBlocks<Block>(title);
CheckAppend<Block>(title);
CheckRead<Block>(title);
CheckReverse<Block>(title);
}
template<typename Block>
void CheckAppend(const char* title)
{
SECTION(title)
{
GIVEN("An empty bitset filled by bytes")
{
#define BitVal1 00110111
#define BitVal2 11011110
#define BitVal3 01000010
std::array<Nz::UInt8, 3> data = {{NazaraPrefixMacro(BitVal1, 0b), NazaraPrefixMacro(BitVal2, 0b), NazaraPrefixMacro(BitVal3, 0b)}};
const char result[] = NazaraStringifyMacro(BitVal3) NazaraStringifyMacro(BitVal2) NazaraStringifyMacro(BitVal1);
std::size_t bitCount = data.size() * 8;
#undef BitVal1
#undef BitVal2
#undef BitVal3
std::array<std::pair<const char*, std::size_t>, 7> tests = {
{
{"We append bits one by one", 1},
{"We append bits two by two", 2},
{"We append bits three by three", 3},
{"We append bits four by four", 4},
{"We append bits six by six", 6},
{"We append bits byte by byte", 8},
{"We append bits twelve by twelve", 12}
}
};
for (auto& pair : tests)
{
WHEN(pair.first)
{
Nz::Bitset<Block> bitset;
for (std::size_t i = 0; i < bitCount; i += pair.second)
{
Nz::UInt16 value = data[i / 8] >> (i % 8);
if ((i % 8) + pair.second > 8 && i/8 != data.size()-1)
value |= static_cast<Nz::UInt16>(data[i / 8 + 1]) << (8 - (i % 8));
bitset.AppendBits(value, pair.second);
}
REQUIRE(bitset.GetSize() == bitCount);
Nz::Bitset<Block> expectedBitset(result);
CHECK(bitset == expectedBitset);
CHECK(bitset.GetBlockCount() == (bitCount / bitset.bitsPerBlock + std::min<std::size_t>(1, bitCount % bitset.bitsPerBlock)));
}
}
}
}
}
template<typename Block>
void CheckBitOps(const char* title)
{
SECTION(title)
{
GIVEN("Two bitsets")
{
Nz::Bitset<Block> first("01001");
Nz::Bitset<Block> second("10111");
WHEN("We perform operators")
{
Nz::Bitset<Block> andBitset = first & second;
Nz::Bitset<Block> orBitset = first | second;
Nz::Bitset<Block> xorBitset = first ^ second;
THEN("They should operate as logical operators")
{
CHECK(andBitset == Nz::Bitset<Block>("00001"));
CHECK(orBitset == Nz::Bitset<Block>("11111"));
CHECK(orBitset.TestAll());
CHECK(xorBitset == Nz::Bitset<Block>("11110"));
CHECK(!xorBitset.TestAll());
CHECK((~orBitset).TestNone());
}
}
WHEN("We perform bit shifts")
{
first.ShiftLeft(1);
second.ShiftRight(2);
THEN("We should obtain these")
{
CHECK(first == Nz::Bitset<Block>("10010"));
CHECK(second == Nz::Bitset<Block>("101"));
}
}
}
}
}
template<typename Block>
void CheckBitOpsMultipleBlocks(const char* title)
{
SECTION(title)
{
GIVEN("Two bitsets")
{
Nz::Bitset<Block> first("01001011010010101001010011010101001");
Nz::Bitset<Block> second("10111111101101110110111101101110110");
WHEN("We perform operators")
{
Nz::Bitset<Block> andBitset = first & second;
Nz::Bitset<Block> orBitset = first | second;
Nz::Bitset<Block> xorBitset = first ^ second;
THEN("They should operate as logical operators")
{
CHECK(andBitset == Nz::Bitset<Block>("00001011000000100000010001000100000"));
CHECK(orBitset == Nz::Bitset<Block>("11111111111111111111111111111111111"));
CHECK(orBitset.TestAll());
CHECK(xorBitset == Nz::Bitset<Block>("11110100111111011111101110111011111"));
CHECK(!xorBitset.TestAll());
CHECK((~orBitset).TestNone());
}
}
WHEN("We perform bit shifts")
{
first.ShiftLeft(16);
second.ShiftRight(16);
THEN("We should obtain these")
{
CHECK(first == Nz::Bitset<Block>("10010100110101010010000000000000000"));
first.ShiftLeft(1);
CHECK(first == Nz::Bitset<Block>("00101001101010100100000000000000000"));
CHECK(second == Nz::Bitset<Block>("1011111110110111011"));
second.ShiftRight(1);
CHECK(second == Nz::Bitset<Block>("101111111011011101"));
}
}
}
}
}
template<typename Block>
void CheckConstructor(const char* title)
{
SECTION(title)
{
GIVEN("Allocate and constructor")
{
Nz::Bitset<Block> bitset(3, false);
THEN("Capacity is 3 and size is 3")
{
CHECK(bitset.GetSize() == 3);
CHECK(bitset.GetCapacity() >= 3);
}
}
GIVEN("Iterator and default constructor")
{
std::string anotherDataString("0101");
Nz::Bitset<Block> defaultByte;
Nz::Bitset<Block> anotherData(anotherDataString.c_str());
WHEN("We assign 'anotherData'")
{
defaultByte = anotherDataString;
CHECK(anotherData == defaultByte);
CHECK(defaultByte.GetSize() == 4);
CHECK(defaultByte.GetCapacity() >= 4);
CHECK(anotherData.GetSize() == 4);
CHECK(anotherData.GetCapacity() >= 4);
}
}
}
}
template<typename Block>
void CheckCopyMoveSwap(const char* title)
{
SECTION(title)
{
GIVEN("Copy and Move constructor")
{
Nz::Bitset<Block> originalArray(3, true);
WHEN("We copy")
{
Nz::Bitset<Block> copyBitset(originalArray);
THEN("We get a copy")
{
CHECK(copyBitset == originalArray);
AND_WHEN("We modify one")
{
for (std::size_t i = 0; i < copyBitset.GetSize(); ++i)
copyBitset[i] = false;
THEN("They are no more equal")
{
CHECK(copyBitset != originalArray);
CHECK(copyBitset == Nz::Bitset<Block>(3, false));
}
}
}
}
WHEN("We move")
{
Nz::Bitset<Block> moveBitset(std::move(originalArray));
THEN("These results are expected")
{
CHECK(moveBitset == Nz::Bitset<Block>(3, true));
CHECK(originalArray.GetCapacity() == 0);
}
}
}
GIVEN("Three bitsets")
{
Nz::Bitset<Block> first("01001");
Nz::Bitset<Block> second("10110");
Nz::Bitset<Block> third;
WHEN("We swap first and third, then second and third and finally third and first")
{
Nz::Bitset<Block> oldFirst(first);
Nz::Bitset<Block> oldSecond(second);
first.Swap(third);
std::swap(second, third);
third.Swap(first);
THEN("First and second have been swapped and third is still empty.")
{
CHECK(oldFirst == second);
CHECK(oldSecond == first);
CHECK(third.GetSize() == 0);
}
}
}
}
}
template<typename Block>
void CheckRead(const char* title)
{
SECTION(title)
{
GIVEN("An empty bitset filled by reading")
{
#define BitVal1 10010101
#define BitVal2 11010010
#define BitVal3 01101010
std::array<Nz::UInt8, 3> data = {{NazaraPrefixMacro(BitVal1, 0b), NazaraPrefixMacro(BitVal2, 0b), NazaraPrefixMacro(BitVal3, 0b)}};
const char result[] = NazaraStringifyMacro(BitVal3) NazaraStringifyMacro(BitVal2) NazaraStringifyMacro(BitVal1);
std::size_t bitCount = data.size() * 8;
#undef BitVal1
#undef BitVal2
#undef BitVal3
std::array<std::pair<const char*, std::size_t>, 8> tests = {
{
{"We read bits one by one", 1},
{"We read bits two by two", 2},
{"We read bits three by three", 3},
{"We read bits four by four", 4},
{"We read bits six by six", 6},
{"We read bits byte by byte", 8},
{"We read bits twelve by twelve", 12},
{"We read bits all at once", 24}
}
};
for (auto& pair : tests)
{
WHEN(pair.first)
{
Nz::Bitset<Block> bitset;
auto seq = bitset.Write(data.data(), pair.second);
for (std::size_t i = pair.second; i < bitCount; i += pair.second)
seq = bitset.Write(seq, pair.second);
REQUIRE(bitset.GetSize() == bitCount);
Nz::Bitset<Block> expectedBitset(result);
CHECK(bitset == expectedBitset);
CHECK(bitset.GetBlockCount() == (bitCount / bitset.bitsPerBlock + std::min<std::size_t>(1, bitCount % bitset.bitsPerBlock)));
}
}
}
}
}
template<typename Block>
void CheckReverse(const char* title)
{
SECTION(title)
{
GIVEN("A bitset")
{
std::string bits = "010011100010001101001111";
Nz::Bitset<Block> expected(bits);
WHEN("We reverse the order of bits")
{
Nz::Bitset<Block> bitset(bits);
bitset.Reverse();
THEN("The order of bits should be reversed")
{
std::string reversedBits = bits;
std::reverse(reversedBits.begin(), reversedBits.end());
CHECK(bitset == Nz::Bitset<Block>(reversedBits));
}
AND_WHEN("We reverse the bit order again")
{
bitset.Reverse();
THEN("It should be back to normal")
{
CHECK(bitset == expected);
}
}
}
}
}
}

View File

@@ -1,141 +0,0 @@
#include <Nazara/Core/MemoryPool.hpp>
#include <catch2/catch.hpp>
#include <Nazara/Math/Vector2.hpp>
namespace
{
std::size_t allocationCount = 0;
template<typename T>
struct AllocatorTest : T
{
template<typename... Args>
AllocatorTest(Args&&... args) :
T(std::forward<Args>(args)...)
{
allocationCount++;
}
AllocatorTest(const AllocatorTest&) = delete;
AllocatorTest(AllocatorTest&&) = delete;
~AllocatorTest()
{
assert(allocationCount > 0);
allocationCount--;
}
};
}
SCENARIO("MemoryPool", "[CORE][MEMORYPOOL]")
{
GIVEN("A MemoryPool to contain one Nz::Vector2<int>")
{
using T = AllocatorTest<Nz::Vector2<int>>;
allocationCount = 0;
Nz::MemoryPool<T> memoryPool(2);
CHECK(memoryPool.GetAllocatedEntryCount() == 0);
CHECK(memoryPool.GetBlockCount() == 1);
CHECK(memoryPool.GetBlockSize() == 2);
CHECK(memoryPool.GetFreeEntryCount() == 2);
CHECK(allocationCount == 0);
WHEN("We construct a Nz::Vector2<int>")
{
std::size_t index;
T* vector2 = memoryPool.Allocate(index, 1, 2);
CHECK(allocationCount == 1);
CHECK(memoryPool.GetAllocatedEntryCount() == 1);
CHECK(memoryPool.GetFreeEntryCount() == 1);
CHECK(memoryPool.RetrieveEntryIndex(vector2) == index);
THEN("Memory is available")
{
vector2->x = 3;
REQUIRE(*vector2 == Nz::Vector2<int>(3, 2));
}
memoryPool.Free(index);
CHECK(allocationCount == 0);
CHECK(memoryPool.GetAllocatedEntryCount() == 0);
CHECK(memoryPool.GetFreeEntryCount() == 2);
}
WHEN("We construct three vectors")
{
CHECK(memoryPool.GetAllocatedEntryCount() == 0);
CHECK(memoryPool.GetFreeEntryCount() == 2);
std::size_t index1, index2, index3;
T* vector1 = memoryPool.Allocate(index1, 1, 2);
CHECK(allocationCount == 1);
CHECK(memoryPool.GetAllocatedEntryCount() == 1);
CHECK(memoryPool.GetBlockCount() == 1);
CHECK(memoryPool.GetFreeEntryCount() == 1);
T* vector2 = memoryPool.Allocate(index2, 3, 4);
CHECK(allocationCount == 2);
CHECK(memoryPool.GetAllocatedEntryCount() == 2);
CHECK(memoryPool.GetBlockCount() == 1);
CHECK(memoryPool.GetFreeEntryCount() == 0);
T* vector3 = memoryPool.Allocate(index3, 5, 6);
CHECK(allocationCount == 3);
CHECK(memoryPool.GetAllocatedEntryCount() == 3);
CHECK(memoryPool.GetBlockCount() == 2);
CHECK(memoryPool.GetFreeEntryCount() == 1); //< a new block has been allocated
CHECK(memoryPool.RetrieveEntryIndex(vector1) == index1);
CHECK(memoryPool.RetrieveEntryIndex(vector2) == index2);
CHECK(memoryPool.RetrieveEntryIndex(vector3) == index3);
THEN("Memory is available")
{
vector1->x = 3;
vector2->y = 5;
CHECK(*vector1 == Nz::Vector2<int>(3, 2));
CHECK(*vector2 == Nz::Vector2<int>(3, 5));
CHECK(vector3->GetSquaredLength() == Approx(61.f));
AND_THEN("We iterate on the memory pool")
{
std::size_t count = 0;
int sumX = 0;
int sumY = 0;
for (T& vec : memoryPool)
{
count++;
sumX += vec.x;
sumY += vec.y;
}
CHECK(count == 3);
CHECK(sumX == 11);
CHECK(sumY == 13);
}
}
memoryPool.Reset();
CHECK(allocationCount == 0);
CHECK(memoryPool.GetAllocatedEntryCount() == 0);
CHECK(memoryPool.GetBlockCount() == 2);
CHECK(memoryPool.GetFreeEntryCount() == 4);
bool failure = false;
for (T& vec : memoryPool)
{
NazaraUnused(vec);
failure = true;
}
CHECK_FALSE(failure);
memoryPool.Clear();
CHECK(allocationCount == 0);
CHECK(memoryPool.GetAllocatedEntryCount() == 0);
CHECK(memoryPool.GetBlockCount() == 0);
CHECK(memoryPool.GetFreeEntryCount() == 0);
}
}
}

View File

@@ -1,48 +0,0 @@
#include <Nazara/Core/Signal.hpp>
#include <catch2/catch.hpp>
struct Incrementer
{
void increment(int* inc)
{
*inc += 1;
}
};
void increment(int* inc)
{
*inc += 1;
}
SCENARIO("Signal", "[CORE][SIGNAL]")
{
GIVEN("A signal")
{
Nz::Signal<int*> signal;
WHEN("We connection different callbacks")
{
auto connection = signal.Connect(increment);
signal.Connect([](int* inc){ *inc += 1; });
Incrementer incrementer;
signal.Connect(incrementer, &Incrementer::increment);
THEN("The call of signal with inc = 0 must return 3")
{
int inc = 0;
signal(&inc);
REQUIRE(inc == 3);
}
AND_THEN("When we disconnect one function, there should be only two listeners")
{
connection.Disconnect();
REQUIRE(!connection.IsConnected());
int inc = 0;
signal(&inc);
REQUIRE(inc == 2);
}
}
}
}

View File

@@ -1,47 +0,0 @@
#include <Nazara/Core/SparsePtr.hpp>
#include <catch2/catch.hpp>
#include <array>
SCENARIO("SparsePtr", "[CORE][SPARSEPTR]")
{
GIVEN("A sparse pointer pointing to an array with a stride of 2")
{
std::array<int, 5> arrays = { {0, 1, 2, 3, 4} };
Nz::SparsePtr<int> sparsePtr(arrays.data(), 2 * sizeof(int));
WHEN("We use operators")
{
THEN("Operator[] with 2 should be 4")
{
CHECK(4 == sparsePtr[2]);
}
THEN("Operator++ and Operator-- should be opposite")
{
++sparsePtr;
CHECK(2 == *sparsePtr);
auto old = sparsePtr++;
CHECK(2 == *old);
CHECK(4 == *sparsePtr);
--sparsePtr;
CHECK(2 == *sparsePtr);
auto oldMinus = sparsePtr--;
CHECK(2 == *oldMinus);
CHECK(0 == *sparsePtr);
}
THEN("Operator+ and operator-")
{
auto offsetTwo = sparsePtr + 2;
CHECK(4 == *offsetTwo);
auto offsetZero = offsetTwo - 2;
CHECK(0 == *offsetZero);
CHECK((offsetTwo - offsetZero) == 2);
}
}
}
}

View File

@@ -1,350 +0,0 @@
#include <Nazara/Core/MovablePtr.hpp>
#include <Nazara/Core/StackVector.hpp>
#include <catch2/catch.hpp>
#include <array>
#include <numeric>
// This is a quick way to check that checks are valid
#define USE_STD_VECTOR 0
class DestructionCounter
{
public:
DestructionCounter() :
m_counter(nullptr),
m_value(0)
{
}
DestructionCounter(std::size_t* counter, int value) :
m_counter(counter),
m_value(value)
{
if (m_counter)
(*m_counter)++;
}
DestructionCounter(const DestructionCounter& counter) :
m_counter(counter.m_counter),
m_value(counter.m_value)
{
if (m_counter)
(*m_counter)++;
}
DestructionCounter(DestructionCounter&& counter) :
m_counter(counter.m_counter),
m_value(counter.m_value)
{
if (m_counter)
(*m_counter)++;
}
~DestructionCounter()
{
if (m_counter)
{
assert(*m_counter > 0);
(*m_counter)--;
}
}
operator int() const
{
return m_value;
}
DestructionCounter& operator=(const DestructionCounter& counter)
{
if (m_counter)
{
assert(*m_counter > 0);
(*m_counter)--;
}
m_counter = counter.m_counter;
m_value = counter.m_value;
if (m_counter)
(*m_counter)++;
return *this;
}
DestructionCounter& operator=(DestructionCounter&& counter)
{
if (this == &counter)
return *this;
if (m_counter)
{
assert(*m_counter > 0);
(*m_counter)--;
}
m_counter = counter.m_counter;
m_value = counter.m_value;
if (m_counter)
(*m_counter)++;
return *this;
}
private:
std::size_t* m_counter;
int m_value;
};
SCENARIO("StackVector", "[CORE][STACKVECTOR]")
{
GIVEN("A StackVector to contain multiple int")
{
std::size_t counter = 0;
{
volatile std::size_t capacity = 50;
#if USE_STD_VECTOR
std::vector<DestructionCounter> vector;
vector.reserve(capacity);
#else
Nz::StackVector<DestructionCounter> vector = NazaraStackVector(DestructionCounter, capacity);
#endif
WHEN("At construction, the vector is empty but has capacity")
{
CHECK(vector.capacity() == capacity);
CHECK(vector.empty());
CHECK(vector.size() == 0);
#if !USE_STD_VECTOR
CHECK(vector.max_size() == capacity);
#endif
}
WHEN("Resizing it changes its size and create/destroy elements")
{
vector.resize(vector.capacity());
CHECK(vector.size() == vector.capacity());
CHECK(counter == 0);
vector.resize(0);
CHECK(vector.empty());
CHECK(vector.size() == 0);
CHECK(counter == 0);
}
WHEN("Resizing it allocates elements")
{
vector.resize(vector.capacity(), DestructionCounter(&counter, 0));
CHECK(vector.size() == vector.capacity());
CHECK(counter == capacity);
vector.resize(0);
CHECK(vector.empty());
CHECK(vector.size() == 0);
CHECK(counter == 0);
}
WHEN("Emplacing five elements, vector size increase accordingly")
{
for (std::size_t i = 0; i < 5; ++i)
{
#if USE_STD_VECTOR
vector.emplace_back(&counter, int(i));
#else
CHECK(vector.emplace_back(&counter, int(i)) == int(i));
#endif
}
CHECK(!vector.empty());
CHECK(vector.size() == 5);
std::array<int, 5> expectedValues = { 0, 1, 2, 3, 4 };
CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
}
WHEN("Pushing three elements, vector size increase accordingly")
{
for (std::size_t i = 0; i < 3; ++i)
{
DestructionCounter val(&counter, int(i));
#if USE_STD_VECTOR
vector.push_back(val);
#else
CHECK(vector.push_back(val) == val);
#endif
}
CHECK(!vector.empty());
CHECK(vector.size() == 3);
{
std::array<int, 3> expectedValues = { 0, 1, 2 };
CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
}
THEN("We resize to five")
{
vector.resize(5);
CHECK(!vector.empty());
CHECK(vector.size() == 5);
std::array<int, 5> expectedValues = { 0, 1, 2, 0, 0 };
CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
AND_THEN("We resize it back to zero")
{
vector.resize(0);
CHECK(vector.empty());
CHECK(vector.size() == 0);
}
AND_THEN("We clear it")
{
vector.clear();
CHECK(vector.empty());
CHECK(vector.size() == 0);
CHECK(counter == 0);
}
}
}
WHEN("We generate its content will iota")
{
vector.resize(10);
for (std::size_t i = 0; i < vector.size(); ++i)
vector[i] = DestructionCounter(&counter, -5 + int(i));
{
std::array<int, 10> expectedValues = { -5, -4, -3, -2, -1, 0, 1, 2, 3, 4 };
CHECK(vector.size() == expectedValues.size());
CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
}
AND_WHEN("We pop back some elements")
{
for (std::size_t i = 0; i < 5; ++i)
vector.pop_back();
std::array<int, 5> expectedValues = { -5, -4, -3, -2, -1 };
CHECK(vector.size() == expectedValues.size());
CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
}
AND_WHEN("We erase elements at the beginning")
{
vector.erase(vector.begin());
vector.erase(vector.begin());
std::array<int, 8> expectedValues = { -3, -2, -1, 0, 1, 2, 3, 4 };
CHECK(vector.size() == expectedValues.size());
CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
}
AND_WHEN("We erase elements in the middle")
{
vector.erase(vector.begin() + 2);
vector.erase(vector.begin() + 2);
vector.erase(vector.begin() + 6);
std::array<int, 7> expectedValues = { -5, -4, -1, 0, 1, 2, 4 };
CHECK(vector.size() == expectedValues.size());
CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
}
AND_WHEN("We erase elements at the end")
{
vector.erase(vector.end() - 1);
vector.erase(vector.end() - 1);
std::array<int, 8> expectedValues = { -5, -4, -3, -2, -1, 0, 1, 2 };
CHECK(vector.size() == expectedValues.size());
CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
}
AND_WHEN("We erase a range")
{
vector.erase(vector.begin() + 2, vector.end() - 3);
std::array<int, 5> expectedValues = { -5, -4, 2, 3, 4 };
CHECK(vector.size() == expectedValues.size());
CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
}
AND_WHEN("We erase everything")
{
vector.erase(vector.begin(), vector.end());
CHECK(vector.empty());
}
}
WHEN("We generate its content using emplace")
{
for (std::size_t i = 0; i < 5; ++i)
CHECK(*vector.emplace(vector.end(), &counter, int(i)) == int(i));
CHECK(!vector.empty());
CHECK(vector.size() == 5);
std::array<int, 5> expectedValues = { 0, 1, 2, 3, 4 };
CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
}
WHEN("We generate its content using emplace, in reverse order")
{
for (std::size_t i = 0; i < 5; ++i)
CHECK(*vector.emplace(vector.begin(), &counter, int(i)) == int(i));
CHECK(!vector.empty());
CHECK(vector.size() == 5);
std::array<int, 5> expectedValues = { 4, 3, 2, 1, 0 };
CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
}
WHEN("We generate its content using emplace, at the middle")
{
for (std::size_t i = 0; i < 10; ++i)
CHECK(*vector.emplace(vector.begin() + i / 2, &counter, int(i)) == int(i));
CHECK(!vector.empty());
CHECK(vector.size() == 10);
std::array<int, 10> expectedValues = { 1, 3, 5, 7, 9, 8, 6, 4, 2, 0 };
CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
}
WHEN("We generate its content using insert")
{
for (std::size_t i = 0; i < 5; ++i)
CHECK(*vector.insert(vector.end(), DestructionCounter(&counter, int(i))) == int(i));
CHECK(!vector.empty());
CHECK(vector.size() == 5);
std::array<int, 5> expectedValues = { 0, 1, 2, 3, 4 };
CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
}
WHEN("We generate its content using insert, in reverse order")
{
for (std::size_t i = 0; i < 5; ++i)
CHECK(*vector.insert(vector.begin(), DestructionCounter(&counter, int(i))) == int(i));
CHECK(!vector.empty());
CHECK(vector.size() == 5);
std::array<int, 5> expectedValues = { 4, 3, 2, 1, 0 };
CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
}
WHEN("We generate its content using insert, at the middle")
{
for (std::size_t i = 0; i < 10; ++i)
CHECK(*vector.insert(vector.begin() + i / 2, DestructionCounter(&counter, int(i))) == int(i));
CHECK(!vector.empty());
CHECK(vector.size() == 10);
std::array<int, 10> expectedValues = { 1, 3, 5, 7, 9, 8, 6, 4, 2, 0 };
CHECK(std::equal(vector.begin(), vector.end(), expectedValues.begin(), expectedValues.end()));
}
}
CHECK(counter == 0);
}
}