You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Gems/Atom/Feature/Common/Code/Tests/SparseVectorTests.cpp

289 lines
9.1 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AzCore/UnitTest/TestTypes.h>
#include <Atom/Feature/Utils/SparseVector.h>
#include <Atom/Feature/Utils/MultiSparseVector.h>
namespace UnitTest
{
using namespace AZ;
using namespace AZ::Render;
class SparseVectorTests
: public UnitTest::AllocatorsTestFixture
{
public:
void SetUp() override
{
UnitTest::AllocatorsTestFixture::SetUp();
}
void TearDown() override
{
UnitTest::AllocatorsTestFixture::TearDown();
}
};
struct TestData
{
static constexpr int DefaultValueA = 100;
static constexpr float DefaultValueB = 123.45f;
static constexpr bool DefaultValueC = true;
int a = DefaultValueA;
float b = DefaultValueB;
bool c = DefaultValueC;
};
TEST_F(SparseVectorTests, SparseVectorCreate)
{
// Simple test to make sure we can create a SparseVector and it initializes with no values.
SparseVector<TestData> container;
EXPECT_EQ(0, container.GetSize());
container.Clear();
EXPECT_EQ(0, container.GetSize());
}
TEST_F(SparseVectorTests, SparseVectorReserveRelease)
{
SparseVector<TestData> container;
constexpr size_t Count = 10;
size_t indices[Count];
// Create some elements
for (size_t i = 0; i < Count; ++i)
{
indices[i] = container.Reserve();
}
EXPECT_EQ(container.GetSize(), Count);
// Ensure that the elements were created with valid indices
for (size_t i = 0; i < Count; ++i)
{
EXPECT_EQ(indices[i], i);
}
// Check default initialization of struct and initialize primitive types
for (size_t i = 0; i < Count; ++i)
{
TestData& data = container.GetElement(indices[i]);
// Ensure that the data was initialized properly.
EXPECT_EQ(data.a, TestData::DefaultValueA);
EXPECT_EQ(data.b, TestData::DefaultValueB);
EXPECT_EQ(data.c, TestData::DefaultValueC);
// Assign new unique values
data.a = TestData::DefaultValueA * static_cast<int>(i);
data.b = TestData::DefaultValueB * float(i);
data.c = i % 2 == 0;
}
// Release every other element.
for (size_t i = 0; i < Count; i += 2)
{
container.Release(indices[i]);
}
// Size should be unaffected by release since it just leaves empty slots.
EXPECT_EQ(container.GetSize(), Count);
// Check the remaining slots to make sure the data is still correct
for (size_t i = 1; i < Count; i += 2)
{
TestData& data = container.GetElement(indices[i]);
EXPECT_EQ(data.a, TestData::DefaultValueA * i);
EXPECT_EQ(data.b, TestData::DefaultValueB * float(i));
EXPECT_EQ(data.c, i % 2 == 0);
}
// Re-reserve the previously deleted elements
for (size_t i = 0; i < Count; i += 2)
{
indices[i] = container.Reserve();
}
// Make sure the new elements data is initialized to default.
for (size_t i = 0; i < Count; i += 2)
{
TestData& data = container.GetElement(indices[i]);
// Ensure that the data was initialized properly.
EXPECT_EQ(data.a, TestData::DefaultValueA);
EXPECT_EQ(data.b, TestData::DefaultValueB);
EXPECT_EQ(data.c, TestData::DefaultValueC);
}
}
TEST_F(SparseVectorTests, SparseVectorGetRawData)
{
SparseVector<TestData> container;
constexpr size_t Count = 10;
size_t indices[Count];
// Create some elements
for (size_t i = 0; i < Count; ++i)
{
indices[i] = container.Reserve();
}
// Get the raw data pointer
const TestData* testData = container.GetRawData();
// Make sure the data in the raw array matches what's expected.
for (size_t i = 0; i < container.GetSize(); ++i)
{
const TestData& data = testData[i];
EXPECT_EQ(data.a, TestData::DefaultValueA);
EXPECT_EQ(data.b, TestData::DefaultValueB);
EXPECT_EQ(data.c, TestData::DefaultValueC);
}
container.Clear();
EXPECT_EQ(0, container.GetSize());
}
TEST_F(SparseVectorTests, MultiSparseVectorCreate)
{
// Simple test to make sure we can create a MultiSparseVector and it initializes with no values.
MultiSparseVector<TestData, int, float> container;
EXPECT_EQ(0, container.GetSize());
container.Clear();
EXPECT_EQ(0, container.GetSize());
}
TEST_F(SparseVectorTests, MultiSparseVectorReserve)
{
MultiSparseVector<TestData, int, float> container;
constexpr size_t Count = 10;
size_t indices[Count];
// Create some elements
for (size_t i = 0; i < Count; ++i)
{
indices[i] = container.Reserve();
}
EXPECT_EQ(container.GetSize(), Count);
// Ensure that the elements were created with valid indices
for (size_t i = 0; i < Count; ++i)
{
EXPECT_EQ(indices[i], i);
}
// Ensure that the data was initialized properly.
for (size_t i = 0; i < Count; ++i)
{
TestData& data = container.GetElement<0>(indices[i]);
EXPECT_EQ(data.a, TestData::DefaultValueA);
EXPECT_EQ(data.b, TestData::DefaultValueB);
EXPECT_EQ(data.c, TestData::DefaultValueC);
data.a = TestData::DefaultValueA * static_cast<int>(i);
data.b = TestData::DefaultValueB * float(i);
data.c = i % 2 == 0;
// Assign some values to the uninitialized primitive types
container.GetElement<1>(indices[i]) = static_cast<int>(i * 10);
container.GetElement<2>(indices[i]) = i * 20.0f;
}
// Release every other element
for (size_t i = 0; i < Count; i += 2)
{
container.Release(indices[i]);
}
// Size should be unaffected by release since it just leaves empty slots.
EXPECT_EQ(container.GetSize(), Count);
// Check the remaining slots to make sure the data is still correct
for (size_t i = 1; i < Count; i += 2)
{
TestData& data = container.GetElement<0>(indices[i]);
EXPECT_EQ(data.a, TestData::DefaultValueA * i);
EXPECT_EQ(data.b, TestData::DefaultValueB * float(i));
EXPECT_EQ(data.c, i % 2 == 0);
EXPECT_EQ(container.GetElement<1>(indices[i]), i * 10);
EXPECT_EQ(container.GetElement<2>(indices[i]), i * 20.0f);
}
// Re-reserve the previously deleted elements
for (size_t i = 0; i < Count; i += 2)
{
indices[i] = container.Reserve();
}
// Make sure the new elements data is initialized to default.
for (size_t i = 0; i < Count; i += 2)
{
TestData& data = container.GetElement<0>(indices[i]);
// Ensure that the data was initialized properly.
EXPECT_EQ(data.a, TestData::DefaultValueA);
EXPECT_EQ(data.b, TestData::DefaultValueB);
EXPECT_EQ(data.c, TestData::DefaultValueC);
EXPECT_EQ(container.GetElement<1>(indices[i]), 0);
EXPECT_EQ(container.GetElement<2>(indices[i]), 0.0f);
}
}
TEST_F(SparseVectorTests, MultiSparseVectorGetRawData)
{
MultiSparseVector<TestData, int, float> container;
constexpr size_t Count = 10;
size_t indices[Count];
// Create some elements and give them values to check later.
for (size_t i = 0; i < Count; ++i)
{
indices[i] = container.Reserve();
container.GetElement<1>(i) = static_cast<int>(i * 10);
container.GetElement<2>(i) = i * 20.0f;
}
// Get raw data arrays
const TestData* testData = container.GetRawData<0>();
const int* testints = container.GetRawData<1>();
const float* testfloats = container.GetRawData<2>();
// Check all the data to make sure it's accurate.
for (size_t i = 0; i < container.GetSize(); ++i)
{
const TestData& data = testData[i];
EXPECT_EQ(data.a, TestData::DefaultValueA);
EXPECT_EQ(data.b, TestData::DefaultValueB);
EXPECT_EQ(data.c, TestData::DefaultValueC);
}
for (size_t i = 0; i < container.GetSize(); ++i)
{
EXPECT_EQ(testints[i], i * 10);
}
for (size_t i = 0; i < container.GetSize(); ++i)
{
EXPECT_EQ(testfloats[i], i * 20.0f);
}
container.Clear();
EXPECT_EQ(0, container.GetSize());
}
}