Move ComputeTest,GraphicsTest,RenderTest and Std140Debug to the tests folder
Also renamed NazaraUnitTests to UnitTests
This commit is contained in:
28
tests/UnitTests/Engine/Core/AbstractHashTest.cpp
Normal file
28
tests/UnitTests/Engine/Core/AbstractHashTest.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
#include <Nazara/Core/AbstractHash.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <Nazara/Core/ByteArray.hpp>
|
||||
|
||||
#include <array>
|
||||
|
||||
SCENARIO("AbstractHash", "[CORE][ABSTRACTHASH]")
|
||||
{
|
||||
GIVEN("The hash SHA512")
|
||||
{
|
||||
std::unique_ptr<Nz::AbstractHash> SHA512 = Nz::AbstractHash::Get(Nz::HashType::SHA512);
|
||||
SHA512->Begin();
|
||||
|
||||
WHEN("We introduce data")
|
||||
{
|
||||
std::array<Nz::UInt8, 4> array{ { 0, 1, 2, 3 } };
|
||||
SHA512->Append(array.data(), array.size());
|
||||
|
||||
THEN("We ask for the bytearray")
|
||||
{
|
||||
Nz::ByteArray byteArray = SHA512->End();
|
||||
CHECK(byteArray.GetSize() == SHA512->GetDigestLength());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
99
tests/UnitTests/Engine/Core/AlgorithmCoreTest.cpp
Normal file
99
tests/UnitTests/Engine/Core/AlgorithmCoreTest.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
#include <Nazara/Core/Algorithm.hpp>
|
||||
#include <Nazara/Core/File.hpp>
|
||||
#include <Nazara/Core/StringExt.hpp>
|
||||
#include <Nazara/Math/Vector2.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <array>
|
||||
#include <filesystem>
|
||||
#include <variant>
|
||||
|
||||
std::filesystem::path GetAssetDir();
|
||||
|
||||
TEST_CASE("ComputeHash", "[CORE][ALGORITHM]")
|
||||
{
|
||||
std::filesystem::path testFilePath = GetAssetDir() / "Logo.png";
|
||||
|
||||
struct Test
|
||||
{
|
||||
Nz::HashType hashType;
|
||||
std::variant<const char*, std::filesystem::path> input;
|
||||
const char* expectedOutput;
|
||||
};
|
||||
|
||||
static_assert(Nz::CRC32("Nazara Engine") == 0x8A2F5235);
|
||||
static_assert(Nz::CRC32("The quick brown fox jumps over the lazy dog") == 0x414FA339);
|
||||
|
||||
CHECK(Nz::CRC32("Nazara Engine") == 0x8A2F5235);
|
||||
CHECK(Nz::CRC32("The quick brown fox jumps over the lazy dog") == 0x414FA339);
|
||||
|
||||
// https://defuse.ca/checksums.htm
|
||||
// https://toolslick.com/programming/hashing/crc-calculator
|
||||
|
||||
std::array tests{
|
||||
//Test{ Nz::HashType::CRC16, "Nazara Engine", "9412" },
|
||||
Test{ Nz::HashType::CRC32, "Nazara Engine", "8A2F5235" },
|
||||
Test{ Nz::HashType::CRC64, "Nazara Engine", "87211217C5FFCDDD" },
|
||||
Test{ Nz::HashType::Fletcher16, "Nazara Engine", "71D7" },
|
||||
Test{ Nz::HashType::MD5, "Nazara Engine", "71FF4EC3B56010ABC03E4B2C1C8A14B9" },
|
||||
Test{ Nz::HashType::SHA1, "Nazara Engine", "FCE7C077A1ED0881A8C60C4822BB1369B672CA5B" },
|
||||
Test{ Nz::HashType::SHA224, "Nazara Engine", "673677224E9B0D24C3828FE6CD36A37C2D43BA27C31B6E6E54756BD4" },
|
||||
Test{ Nz::HashType::SHA256, "Nazara Engine", "7E66722931B65BF780FB55D41834C3D67455029CC1CB497976D2D41A90D3FD4C" },
|
||||
Test{ Nz::HashType::SHA384, "Nazara Engine", "80064D11A4E4C2A44DE03406E03025C52641E04BA80DE78B1BB0BA6EA577B4B6914F2BDED5B95BB7285F8EA785B9B996" },
|
||||
Test{ Nz::HashType::SHA512, "Nazara Engine", "C3A8212B61B88D77E8C4B40884D49BA6A54202865CAA847F676D2EA20E60F43B1C8024DE982A214EB3670B752AF3EE37189F1EBDCA608DD0DD427D8C19371FA5" },
|
||||
Test{ Nz::HashType::Whirlpool, "Nazara Engine", "92113DC95C25057C4154E9A8B2A4C4C800D24DD22FA7D796F300AF9C4EFA4FAAB6030F66B0DC74B270A911DA18E007544B79B84440A1D58AA7C79A73C39C29F8" },
|
||||
|
||||
//Test{ Nz::HashType::CRC16, "The quick brown fox jumps over the lazy dog", "FCDF" },
|
||||
Test{ Nz::HashType::CRC32, "The quick brown fox jumps over the lazy dog", "414FA339" },
|
||||
Test{ Nz::HashType::CRC64, "The quick brown fox jumps over the lazy dog", "41E05242FFA9883B" },
|
||||
Test{ Nz::HashType::Fletcher16, "The quick brown fox jumps over the lazy dog", "FEE8" },
|
||||
Test{ Nz::HashType::MD5, "The quick brown fox jumps over the lazy dog", "9E107D9D372BB6826BD81D3542A419D6" },
|
||||
Test{ Nz::HashType::SHA1, "The quick brown fox jumps over the lazy dog", "2FD4E1C67A2D28FCED849EE1BB76E7391B93EB12" },
|
||||
Test{ Nz::HashType::SHA224, "The quick brown fox jumps over the lazy dog", "730E109BD7A8A32B1CB9D9A09AA2325D2430587DDBC0C38BAD911525" },
|
||||
Test{ Nz::HashType::SHA256, "The quick brown fox jumps over the lazy dog", "D7A8FBB307D7809469CA9ABCB0082E4F8D5651E46D3CDB762D02D0BF37C9E592" },
|
||||
Test{ Nz::HashType::SHA384, "The quick brown fox jumps over the lazy dog", "CA737F1014A48F4C0B6DD43CB177B0AFD9E5169367544C494011E3317DBF9A509CB1E5DC1E85A941BBEE3D7F2AFBC9B1" },
|
||||
Test{ Nz::HashType::SHA512, "The quick brown fox jumps over the lazy dog", "07E547D9586F6A73F73FBAC0435ED76951218FB7D0C8D788A309D785436BBB642E93A252A954F23912547D1E8A3B5ED6E1BFD7097821233FA0538F3DB854FEE6" },
|
||||
Test{ Nz::HashType::Whirlpool, "The quick brown fox jumps over the lazy dog", "B97DE512E91E3828B40D2B0FDCE9CEB3C4A71F9BEA8D88E75C4FA854DF36725FD2B52EB6544EDCACD6F8BEDDFEA403CB55AE31F03AD62A5EF54E42EE82C3FB35" },
|
||||
|
||||
//Test{ Nz::HashType::CRC16, testFilePath, "30A6" },
|
||||
Test{ Nz::HashType::CRC32, testFilePath, "5A2024CD" },
|
||||
Test{ Nz::HashType::CRC64, testFilePath, "F92157F70C713EEC" },
|
||||
Test{ Nz::HashType::Fletcher16, testFilePath, "9152" },
|
||||
Test{ Nz::HashType::MD5, testFilePath, "75B35EDB2DB8B4ED5020821E401B1FA3" },
|
||||
Test{ Nz::HashType::SHA1, testFilePath, "FD6B51F6E176AA91BDDCFAFB6D65AF97116C3981" },
|
||||
Test{ Nz::HashType::SHA224, testFilePath, "77F8536DB2AEDDB0B18747EF7907AEFFE019C3EB6C9E64CC31D2E4DA" },
|
||||
Test{ Nz::HashType::SHA256, testFilePath, "5C4B9387327C039A6CE9ED51983D6C2ADA9F9DD01D024C2D5D588237ADFC7423" },
|
||||
Test{ Nz::HashType::SHA384, testFilePath, "BB11F442F14AED77C116C6CA05103C006D40F861D23D272263BBD9F0D260FA5449B728A94F80BB807BD16778C558EF05" },
|
||||
Test{ Nz::HashType::SHA512, testFilePath, "1EA50E73C1D7D8DFCD51AC2718D7EB953E4B2D1D9EFA06F5B89DC1B0315C6C57A007D733DFA4DA41BFCE0E73446EFAF3413E8C1D38A0C327773AFF49C010F091" },
|
||||
Test{ Nz::HashType::Whirlpool, testFilePath, "A1598870C7E5C59004CD0A2C7E17248606E2DDD832EED1B0E2D52A9A72842A073CC2F889D2EC71C061A21A86879FF009D4FED1010B454FF8535C401BC9A60F64" },
|
||||
};
|
||||
|
||||
for (const Test& test : tests)
|
||||
{
|
||||
auto hash = Nz::AbstractHash::Get(test.hashType);
|
||||
|
||||
if (std::holds_alternative<const char*>(test.input))
|
||||
{
|
||||
const char* inputStr = std::get<const char*>(test.input);
|
||||
WHEN("We compute " << hash->GetHashName() << " of '" << inputStr << "'")
|
||||
{
|
||||
auto result = Nz::ComputeHash(*hash, inputStr);
|
||||
CHECK(result.GetSize() == hash->GetDigestLength());
|
||||
CHECK(Nz::ToUpper(result.ToHex()) == test.expectedOutput);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(std::holds_alternative<std::filesystem::path>(test.input));
|
||||
const std::filesystem::path& filePath = std::get<std::filesystem::path>(test.input);
|
||||
Nz::File file(filePath);
|
||||
|
||||
WHEN("We compute " << hash->GetHashName() << " of " << filePath << " file")
|
||||
{
|
||||
auto result = Nz::ComputeHash(*hash, file);
|
||||
CHECK(result.GetSize() == hash->GetDigestLength());
|
||||
CHECK(Nz::ToUpper(result.ToHex()) == test.expectedOutput);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
85
tests/UnitTests/Engine/Core/BufferingTest.cpp
Normal file
85
tests/UnitTests/Engine/Core/BufferingTest.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
#include <Nazara/Core/MemoryView.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <cstring>
|
||||
|
||||
SCENARIO("Buffering", "[CORE][BUFFERING]")
|
||||
{
|
||||
const char mem[] = "abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
for (std::size_t bufferSize : { 1, 2, 3, 4, 6, 7, 0xFFFF })
|
||||
{
|
||||
Nz::MemoryView memView(mem, sizeof(mem));
|
||||
memView.EnableBuffering(true, bufferSize);
|
||||
|
||||
WHEN("Using a buffer size of " + std::to_string(bufferSize))
|
||||
{
|
||||
CHECK(memView.GetCursorPos() == 0);
|
||||
|
||||
std::vector<char> readBuffer;
|
||||
|
||||
WHEN("Reading the full buffer")
|
||||
{
|
||||
readBuffer.resize(sizeof(mem));
|
||||
REQUIRE(memView.Read(readBuffer.data(), readBuffer.size()) == readBuffer.size());
|
||||
CHECK(std::memcmp(readBuffer.data(), mem, readBuffer.size()) == 0);
|
||||
CHECK(memView.GetCursorPos() == sizeof(mem));
|
||||
}
|
||||
|
||||
WHEN("Reading 2 bytes")
|
||||
{
|
||||
readBuffer.resize(2);
|
||||
REQUIRE(memView.Read(readBuffer.data(), readBuffer.size()) == readBuffer.size());
|
||||
CHECK(std::memcmp(readBuffer.data(), "ab", readBuffer.size()) == 0);
|
||||
CHECK(memView.GetCursorPos() == 2);
|
||||
|
||||
REQUIRE(memView.Read(readBuffer.data(), readBuffer.size()) == readBuffer.size());
|
||||
CHECK(std::memcmp(readBuffer.data(), "cd", readBuffer.size()) == 0);
|
||||
CHECK(memView.GetCursorPos() == 4);
|
||||
|
||||
WHEN("Reading 4 bytes and reading")
|
||||
{
|
||||
readBuffer.resize(4);
|
||||
REQUIRE(memView.Read(readBuffer.data(), readBuffer.size()) == readBuffer.size());
|
||||
CHECK(std::memcmp(readBuffer.data(), "efgh", readBuffer.size()) == 0);
|
||||
CHECK(memView.GetCursorPos() == 8);
|
||||
|
||||
AND_WHEN("Seeking at 10")
|
||||
{
|
||||
memView.SetCursorPos(10);
|
||||
CHECK(memView.GetCursorPos() == 10);
|
||||
|
||||
readBuffer.resize(2);
|
||||
REQUIRE(memView.Read(readBuffer.data(), readBuffer.size()) == readBuffer.size());
|
||||
CHECK(std::memcmp(readBuffer.data(), "kl", readBuffer.size()) == 0);
|
||||
CHECK(memView.GetCursorPos() == 12);
|
||||
}
|
||||
|
||||
AND_WHEN("Seeking at 6 and reading")
|
||||
{
|
||||
memView.SetCursorPos(6);
|
||||
CHECK(memView.GetCursorPos() == 6);
|
||||
|
||||
readBuffer.resize(2);
|
||||
REQUIRE(memView.Read(readBuffer.data(), readBuffer.size()) == readBuffer.size());
|
||||
CHECK(std::memcmp(readBuffer.data(), "ghij", readBuffer.size()) == 0);
|
||||
CHECK(memView.GetCursorPos() == 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("Reading 6 then 2 bytes")
|
||||
{
|
||||
readBuffer.resize(6);
|
||||
REQUIRE(memView.Read(readBuffer.data(), readBuffer.size()) == readBuffer.size());
|
||||
CHECK(std::memcmp(readBuffer.data(), "abcdef", readBuffer.size()) == 0);
|
||||
CHECK(memView.GetCursorPos() == 6);
|
||||
|
||||
readBuffer.resize(2);
|
||||
REQUIRE(memView.Read(readBuffer.data(), readBuffer.size()) == readBuffer.size());
|
||||
CHECK(std::memcmp(readBuffer.data(), "gh", readBuffer.size()) == 0);
|
||||
CHECK(memView.GetCursorPos() == 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
237
tests/UnitTests/Engine/Core/ByteArrayTest.cpp
Normal file
237
tests/UnitTests/Engine/Core/ByteArrayTest.cpp
Normal file
@@ -0,0 +1,237 @@
|
||||
#include <Nazara/Core/ByteArray.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
SCENARIO("ByteArray", "[CORE][BYTEARRAY]")
|
||||
{
|
||||
GIVEN("Allocate and raw constructor")
|
||||
{
|
||||
Nz::ByteArray byteArray(3);
|
||||
|
||||
THEN("Capacity is 3 and size is 0")
|
||||
{
|
||||
REQUIRE(byteArray.GetSize() == 0);
|
||||
REQUIRE(byteArray.GetCapacity() >= 3);
|
||||
}
|
||||
|
||||
WHEN("We add 'data'")
|
||||
{
|
||||
byteArray.Append("data", 4);
|
||||
|
||||
THEN("We get 'data'")
|
||||
{
|
||||
REQUIRE(byteArray.GetSize() == 4);
|
||||
REQUIRE(byteArray.GetCapacity() >= 4);
|
||||
REQUIRE(byteArray == Nz::ByteArray("data", 4));
|
||||
REQUIRE(byteArray.ToString() == "data");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Iterator and default constructor")
|
||||
{
|
||||
std::string anotherDataString("anotherData");
|
||||
Nz::ByteArray defaultByte;
|
||||
Nz::ByteArray anotherData(anotherDataString.begin(), anotherDataString.end());
|
||||
|
||||
WHEN("We assign 'anotherData' with iterator")
|
||||
{
|
||||
defaultByte.Assign(anotherData.begin(), anotherData.end());
|
||||
REQUIRE(anotherData == defaultByte);
|
||||
REQUIRE(defaultByte.GetSize() == 11);
|
||||
REQUIRE(defaultByte.GetCapacity() >= 11);
|
||||
REQUIRE(anotherData.GetSize() == 11);
|
||||
REQUIRE(anotherData.GetCapacity() >= 11);
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Copy and Move constructor")
|
||||
{
|
||||
Nz::ByteArray originalArray(3, 64);
|
||||
|
||||
WHEN("We copy")
|
||||
{
|
||||
Nz::ByteArray copyByteArray(originalArray);
|
||||
|
||||
THEN("We get a copy")
|
||||
{
|
||||
REQUIRE(copyByteArray == originalArray);
|
||||
|
||||
AND_WHEN("We modify one")
|
||||
{
|
||||
for (Nz::ByteArray::size_type i = 0; i < copyByteArray.GetSize(); ++i)
|
||||
copyByteArray[i] = 46;
|
||||
|
||||
THEN("They are no more equal")
|
||||
{
|
||||
REQUIRE(copyByteArray != originalArray);
|
||||
REQUIRE(copyByteArray == Nz::ByteArray(3, 46));
|
||||
REQUIRE(copyByteArray.GetConstBuffer() != originalArray.GetConstBuffer());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We move")
|
||||
{
|
||||
Nz::ByteArray moveByteArray(std::move(originalArray));
|
||||
|
||||
THEN("These results are expected")
|
||||
{
|
||||
REQUIRE(moveByteArray == Nz::ByteArray(3, 64));
|
||||
CHECK(originalArray.IsEmpty());
|
||||
REQUIRE(originalArray.GetCapacity() == 0);
|
||||
REQUIRE(moveByteArray.GetConstBuffer() != originalArray.GetConstBuffer());
|
||||
|
||||
AND_WHEN("We modify the empty one")
|
||||
{
|
||||
originalArray.Prepend(Nz::ByteArray(3, 64));
|
||||
|
||||
THEN("They are no more equal")
|
||||
{
|
||||
REQUIRE(moveByteArray == originalArray);
|
||||
REQUIRE(moveByteArray.GetConstBuffer() != originalArray.GetConstBuffer());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Two byte array (abc) and (cba)")
|
||||
{
|
||||
Nz::ByteArray abc("abc", 3);
|
||||
Nz::ByteArray cba;
|
||||
cba = Nz::ByteArray("cba", 3);
|
||||
|
||||
WHEN("We do some antagonists operations")
|
||||
{
|
||||
THEN("These results are expected")
|
||||
{
|
||||
REQUIRE(abc.Back() == cba.Front());
|
||||
|
||||
abc.Erase(abc.begin(), abc.begin() + 1);
|
||||
abc.Erase(abc.begin());
|
||||
|
||||
cba.Erase(cba.end() - 1, cba.end());
|
||||
cba.Erase(cba.end() - 1);
|
||||
|
||||
REQUIRE(abc == Nz::ByteArray("c", 1));
|
||||
REQUIRE(cba == Nz::ByteArray("c", 1));
|
||||
|
||||
std::string ab("ab");
|
||||
abc.Insert(abc.begin(), ab.begin(), ab.end());
|
||||
cba += Nz::ByteArray("ba", 2);
|
||||
|
||||
REQUIRE(abc == Nz::ByteArray("abc", 3));
|
||||
REQUIRE(cba == Nz::ByteArray("cba", 3));
|
||||
|
||||
abc.PopBack();
|
||||
cba.PopFront();
|
||||
|
||||
REQUIRE(abc == Nz::ByteArray("ab", 2));
|
||||
REQUIRE(cba == Nz::ByteArray("ba", 2));
|
||||
|
||||
abc.PushBack('c');
|
||||
cba.PushFront('c');
|
||||
|
||||
REQUIRE(abc == Nz::ByteArray("abc", 3));
|
||||
REQUIRE(cba == Nz::ByteArray("cba", 3));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("One byte array of capacity 10")
|
||||
{
|
||||
Nz::ByteArray capacityArray(10);
|
||||
|
||||
WHEN("We reserve for 100")
|
||||
{
|
||||
capacityArray.Reserve(100);
|
||||
|
||||
THEN("Capacity is 100")
|
||||
{
|
||||
REQUIRE(capacityArray.GetCapacity() == 100);
|
||||
}
|
||||
|
||||
AND_WHEN("We add information and then shrink to fit")
|
||||
{
|
||||
capacityArray.Prepend("information", 11);
|
||||
capacityArray.ShrinkToFit();
|
||||
|
||||
THEN("Capacity is 11")
|
||||
{
|
||||
REQUIRE(capacityArray.GetCapacity() == 11);
|
||||
REQUIRE(capacityArray.GetSize() == 11);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Nz::ByteArray::const_pointer oldBuffer = capacityArray.GetConstBuffer();
|
||||
WHEN("We reserve for 5, add 'data' for 4 and then shrink to fit")
|
||||
{
|
||||
capacityArray.Reserve(5);
|
||||
THEN("Capacity is still 10")
|
||||
{
|
||||
REQUIRE(capacityArray.GetCapacity() == 10);
|
||||
REQUIRE(capacityArray.GetSize() == 0);
|
||||
REQUIRE(capacityArray.GetConstBuffer() == oldBuffer);
|
||||
}
|
||||
|
||||
capacityArray.Append("data", 4);
|
||||
capacityArray.ShrinkToFit();
|
||||
|
||||
THEN("Capacity is 4")
|
||||
{
|
||||
REQUIRE(capacityArray.GetConstBuffer() != oldBuffer);
|
||||
REQUIRE(capacityArray.GetCapacity() == 4);
|
||||
REQUIRE(capacityArray.GetSize() == 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Three byte array")
|
||||
{
|
||||
Nz::ByteArray first("hello", 5);
|
||||
Nz::ByteArray second("world", 5);
|
||||
Nz::ByteArray third;
|
||||
|
||||
WHEN("We swap first and third, then second and third and finally third and first")
|
||||
{
|
||||
Nz::ByteArray oldFirst(first);
|
||||
Nz::ByteArray oldSecond(second);
|
||||
|
||||
first.Swap(third);
|
||||
std::swap(second, third);
|
||||
third.Swap(first);
|
||||
|
||||
THEN("First and second have been swapped and third is still empty.")
|
||||
{
|
||||
REQUIRE(oldFirst == second);
|
||||
REQUIRE(oldSecond == first);
|
||||
REQUIRE(third.IsEmpty());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A default byte array")
|
||||
{
|
||||
Nz::ByteArray defaultByteArray;
|
||||
|
||||
WHEN("We resize")
|
||||
{
|
||||
Nz::UInt64 oldSize = defaultByteArray.GetSize();
|
||||
REQUIRE(oldSize == 0);
|
||||
defaultByteArray.Resize(10);
|
||||
|
||||
THEN("Capacity has increased")
|
||||
{
|
||||
REQUIRE(defaultByteArray[oldSize] == 0);
|
||||
|
||||
REQUIRE(defaultByteArray.GetCapacity() >= 10);
|
||||
REQUIRE(defaultByteArray.GetSize() == 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
74
tests/UnitTests/Engine/Core/ByteStreamTest.cpp
Normal file
74
tests/UnitTests/Engine/Core/ByteStreamTest.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
#include <Nazara/Core/ByteStream.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include <array>
|
||||
|
||||
SCENARIO("ByteStream", "[CORE][BYTESTREAM]")
|
||||
{
|
||||
GIVEN("A bytestream from a bunch of bytes")
|
||||
{
|
||||
const int numberOfBytes = 16;
|
||||
std::array<Nz::Int8, numberOfBytes> data;
|
||||
|
||||
Nz::ByteStream byteStream(data.data(), numberOfBytes);
|
||||
|
||||
WHEN("We write some data in it")
|
||||
{
|
||||
int value = 5;
|
||||
byteStream << value;
|
||||
std::string string = "string";
|
||||
byteStream << string;
|
||||
|
||||
byteStream.FlushBits();
|
||||
|
||||
THEN("We can retrieve them")
|
||||
{
|
||||
const void* const ptrData = data.data();
|
||||
Nz::ByteStream readStream;
|
||||
CHECK(readStream.GetSize() == 0);
|
||||
readStream = Nz::ByteStream(ptrData, byteStream.GetSize());
|
||||
int retrievedValue = 0;
|
||||
readStream >> retrievedValue;
|
||||
std::string retrievedString;
|
||||
readStream >> retrievedString;
|
||||
|
||||
CHECK(value == retrievedValue);
|
||||
CHECK(string == retrievedString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A bytestream with a byte array and a different endianness")
|
||||
{
|
||||
const int numberOfBytes = 16;
|
||||
Nz::ByteArray byteArray(numberOfBytes);
|
||||
Nz::ByteStream byteStream(&byteArray);
|
||||
|
||||
byteStream.SetDataEndianness(Nz::GetPlatformEndianness() == Nz::Endianness::BigEndian ? Nz::Endianness::LittleEndian : Nz::Endianness::BigEndian);
|
||||
|
||||
WHEN("We write an integer")
|
||||
{
|
||||
int value = 7;
|
||||
byteStream.Write(&value, sizeof(int));
|
||||
bool boolean = true;
|
||||
byteStream << boolean;
|
||||
byteStream.FlushBits();
|
||||
|
||||
THEN("We can retrieve it properly")
|
||||
{
|
||||
Nz::ByteStream tmpStream(&byteArray);
|
||||
tmpStream.SetDataEndianness(byteStream.GetDataEndianness());
|
||||
|
||||
int retrievedValue = 0;
|
||||
tmpStream.Read(&retrievedValue, sizeof(int));
|
||||
CHECK(value == retrievedValue);
|
||||
|
||||
Nz::ByteStream readStream(std::move(tmpStream));
|
||||
bool retrievedBoolean = false;
|
||||
readStream >> retrievedBoolean;
|
||||
CHECK(boolean == retrievedBoolean);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
51
tests/UnitTests/Engine/Core/ClockTest.cpp
Normal file
51
tests/UnitTests/Engine/Core/ClockTest.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
#include <Nazara/Core/Clock.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
SCENARIO("Clock", "[CORE][CLOCK]")
|
||||
{
|
||||
GIVEN("A clock paused")
|
||||
{
|
||||
Nz::UInt64 initialTime = 100;
|
||||
Nz::Clock clock(initialTime, true);
|
||||
|
||||
WHEN("We get time since it is paused")
|
||||
{
|
||||
THEN("Time must be the initialTime")
|
||||
{
|
||||
CHECK(clock.GetMicroseconds() == initialTime);
|
||||
CHECK(clock.IsPaused());
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We unpause it")
|
||||
{
|
||||
clock.Unpause();
|
||||
REQUIRE(!clock.IsPaused());
|
||||
|
||||
THEN("Time must not be the initialTime")
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
Nz::UInt64 microSeconds = clock.GetMicroseconds();
|
||||
CHECK(microSeconds != initialTime);
|
||||
CHECK(microSeconds / 1000 <= clock.GetMilliseconds());
|
||||
CHECK(microSeconds / (1000.f * 1000.f) <= clock.GetSeconds());
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We restart it")
|
||||
{
|
||||
clock.Restart();
|
||||
|
||||
THEN("It is unpaused and we can pause it")
|
||||
{
|
||||
CHECK(!clock.IsPaused());
|
||||
clock.Pause();
|
||||
CHECK(clock.IsPaused());
|
||||
CHECK(clock.GetMicroseconds() != initialTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
152
tests/UnitTests/Engine/Core/ColorTest.cpp
Normal file
152
tests/UnitTests/Engine/Core/ColorTest.cpp
Normal file
@@ -0,0 +1,152 @@
|
||||
#include <Nazara/Core/Color.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
void CompareColor(const Nz::Color& lhs, const Nz::Color& rhs)
|
||||
{
|
||||
constexpr float epsilon = 0.1f;
|
||||
|
||||
REQUIRE(lhs.r == Catch::Approx(rhs.r).margin(epsilon));
|
||||
REQUIRE(lhs.g == Catch::Approx(rhs.g).margin(epsilon));
|
||||
REQUIRE(lhs.b == Catch::Approx(rhs.b).margin(epsilon));
|
||||
REQUIRE(lhs.a == Catch::Approx(rhs.a).margin(epsilon));
|
||||
}
|
||||
|
||||
constexpr float epsilon = 1.f;
|
||||
|
||||
void CompareCMY(const Nz::Color& color, float cyan, float magenta, float yellow)
|
||||
{
|
||||
float retrievedCyan = 0.f, retrievedMagenta = 0.f, retrievedYellow = 0.f;
|
||||
Nz::Color::ToCMY(color, &retrievedCyan, &retrievedMagenta, &retrievedYellow);
|
||||
CHECK(retrievedCyan == Catch::Approx(cyan).margin(epsilon));
|
||||
CHECK(retrievedMagenta == Catch::Approx(magenta).margin(epsilon));
|
||||
CHECK(retrievedYellow == Catch::Approx(yellow).margin(epsilon));
|
||||
}
|
||||
|
||||
void CompareCMYK(const Nz::Color& color, float cyan, float magenta, float yellow, float black)
|
||||
{
|
||||
float retrievedCyan = 0.f, retrievedMagenta = 0.f, retrievedYellow = 0.f, retrievedBlack = 0.f;
|
||||
Nz::Color::ToCMYK(color, &retrievedCyan, &retrievedMagenta, &retrievedYellow, &retrievedBlack);
|
||||
CHECK(retrievedCyan == Catch::Approx(cyan).margin(epsilon));
|
||||
CHECK(retrievedMagenta == Catch::Approx(magenta).margin(epsilon));
|
||||
CHECK(retrievedYellow == Catch::Approx(yellow).margin(epsilon));
|
||||
CHECK(retrievedBlack == Catch::Approx(black).margin(epsilon));
|
||||
}
|
||||
|
||||
void CompareHSL(const Nz::Color& color, float hue, float saturation, float luminosity)
|
||||
{
|
||||
float retrievedHue = 0.f, retrievedSaturation = 0.f, retrievedLuminosity = 0.f;
|
||||
Nz::Color::ToHSL(color, &retrievedHue, &retrievedSaturation, &retrievedLuminosity);
|
||||
CHECK(retrievedHue == Catch::Approx(hue).margin(epsilon));
|
||||
CHECK(retrievedSaturation == Catch::Approx(saturation).margin(epsilon));
|
||||
CHECK(retrievedLuminosity == Catch::Approx(luminosity).margin(epsilon));
|
||||
}
|
||||
|
||||
void CompareHSV(const Nz::Color& color, float hue, float saturation, float value)
|
||||
{
|
||||
float retrievedHue = 0.f, retrievedSaturation = 0.f, retrievedValue = 0.f;
|
||||
Nz::Color::ToHSV(color, &retrievedHue, &retrievedSaturation, &retrievedValue);
|
||||
CHECK(retrievedHue == Catch::Approx(hue).margin(epsilon));
|
||||
CHECK(retrievedSaturation == Catch::Approx(saturation).margin(epsilon));
|
||||
CHECK(retrievedValue == Catch::Approx(value).margin(epsilon));
|
||||
}
|
||||
|
||||
void CompareXYZ(const Nz::Color& color, float x, float y, float z)
|
||||
{
|
||||
Nz::Vector3f retrievedValues = Nz::Vector3f::Zero();
|
||||
Nz::Color::ToXYZ(color, &retrievedValues);
|
||||
CHECK(retrievedValues.x == Catch::Approx(x).margin(epsilon));
|
||||
CHECK(retrievedValues.y == Catch::Approx(y).margin(epsilon));
|
||||
CHECK(retrievedValues.z == Catch::Approx(z).margin(epsilon));
|
||||
}
|
||||
|
||||
SCENARIO("Color", "[CORE][COLOR]")
|
||||
{
|
||||
GIVEN("Two colors, one red (255) and one gray (128)")
|
||||
{
|
||||
Nz::Color red(1.f, 0.f, 0.f);
|
||||
Nz::Color grey(0.5f);
|
||||
|
||||
WHEN("We do operations")
|
||||
{
|
||||
THEN("These results are expected")
|
||||
{
|
||||
red += Nz::Color(0, 0, 0);
|
||||
grey *= Nz::Color(1.f);
|
||||
|
||||
CompareColor(red + grey, Nz::Color(1.5f, 0.5f, 0.5f, 3.f));
|
||||
CompareColor(red * grey, Nz::Color(0.5f, 0.f, 0.f, 2.f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A special color in different formats")
|
||||
{
|
||||
struct ColorData
|
||||
{
|
||||
std::string name;
|
||||
Nz::Color rgb;
|
||||
float cyan, magenta, yellow;
|
||||
float cyanK, magentaK, yellowK, black;
|
||||
float hue, saturation, luminosity;
|
||||
float hueV, saturationV, valueV;
|
||||
float x, y, z;
|
||||
};
|
||||
|
||||
std::vector<ColorData> colors;
|
||||
|
||||
colors.push_back({
|
||||
"blue",
|
||||
Nz::Color(0.f, 0.f, 1.f),
|
||||
1.f, 1.f, 0.f, // cmy
|
||||
1.f, 1.f, 0.f, 0.f, // cmyk
|
||||
240.f, 1.f, 0.5f, // hsl
|
||||
240.f, 1.f, 1.f, // hsv
|
||||
18.05f, 7.22f, 95.05f // xyz
|
||||
});
|
||||
|
||||
colors.push_back({
|
||||
"white",
|
||||
Nz::Color(1.f, 1.f, 1.f),
|
||||
0.f, 0.f, 0.f, // cmy
|
||||
0.f, 0.f, 0.f, 0.f, // cmyk
|
||||
0.f, 0.f, 1.f, // hsl
|
||||
0.f, 0.f, 1.f, // hsv
|
||||
95.05f, 100.f, 108.09f // xyz
|
||||
});
|
||||
|
||||
colors.push_back({
|
||||
"greenish",
|
||||
Nz::Color(5 / 255.f, 191.f / 255.f, 25.f / 255.f),
|
||||
0.980f, 0.251f, 0.902f, // cmy
|
||||
0.974f, 0.000f, 0.869f, 0.251f, // cmyk
|
||||
126.f, 0.95f, 0.38f, // hsl
|
||||
126.f, 0.97f, 0.75f, // hsv
|
||||
18.869f, 37.364f, 7.137f // xyz
|
||||
});
|
||||
|
||||
for (const ColorData& color : colors)
|
||||
{
|
||||
WHEN("We perform conversion for: " + color.name)
|
||||
{
|
||||
THEN("From other color spaces")
|
||||
{
|
||||
CompareColor(color.rgb, Nz::Color::FromCMY(color.cyan, color.magenta, color.yellow));
|
||||
CompareColor(color.rgb, Nz::Color::FromCMYK(color.cyanK, color.magentaK, color.yellowK, color.black));
|
||||
CompareColor(color.rgb, Nz::Color::FromHSL(color.hue, color.saturation, color.luminosity));
|
||||
CompareColor(color.rgb, Nz::Color::FromHSV(color.hueV, color.saturationV, color.valueV));
|
||||
CompareColor(color.rgb, Nz::Color::FromXYZ(Nz::Vector3f(color.x, color.y, color.z)));
|
||||
}
|
||||
|
||||
THEN("To other color spaces")
|
||||
{
|
||||
CompareCMY(color.rgb, color.cyan, color.magenta, color.yellow);
|
||||
CompareCMYK(color.rgb, color.cyanK, color.magentaK, color.yellowK, color.black);
|
||||
CompareHSL(color.rgb, color.hue, color.saturation, color.luminosity);
|
||||
CompareHSV(color.rgb, color.hueV, color.saturationV, color.valueV);
|
||||
CompareXYZ(color.rgb, color.x, color.y, color.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
29
tests/UnitTests/Engine/Core/ErrorTest.cpp
Normal file
29
tests/UnitTests/Engine/Core/ErrorTest.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
SCENARIO("Error", "[CORE][ERROR]")
|
||||
{
|
||||
Nz::ErrorModeFlags oldFlags = Nz::Error::GetFlags();
|
||||
|
||||
GIVEN("Multiple errors")
|
||||
{
|
||||
WHEN("Calling to error")
|
||||
{
|
||||
THEN("These errors should be written in the log file")
|
||||
{
|
||||
Nz::Error::Trigger(Nz::ErrorType::Internal, "ErrorType::Internal");
|
||||
Nz::Error::Trigger(Nz::ErrorType::Internal, "ErrorType::Internal", 2, "Error.cpp", "2nd place Internal");
|
||||
REQUIRE("ErrorType::Internal" == Nz::Error::GetLastError());
|
||||
Nz::Error::Trigger(Nz::ErrorType::Normal, "ErrorType::Normal");
|
||||
Nz::Error::Trigger(Nz::ErrorType::Normal, "ErrorType::Normal", 2, "Error.cpp", "2nd place Normal");
|
||||
REQUIRE("ErrorType::Normal" == Nz::Error::GetLastError());
|
||||
Nz::Error::Trigger(Nz::ErrorType::Warning, "ErrorType::Warning");
|
||||
Nz::Error::Trigger(Nz::ErrorType::Warning, "ErrorType::Warning", 2, "Error.cpp", "2nd place Warning");
|
||||
REQUIRE("ErrorType::Warning" == Nz::Error::GetLastError());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Nz::Error::SetFlags(oldFlags);
|
||||
}
|
||||
84
tests/UnitTests/Engine/Core/FileTest.cpp
Normal file
84
tests/UnitTests/Engine/Core/FileTest.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
#include <Nazara/Core/File.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
std::filesystem::path GetAssetDir();
|
||||
|
||||
SCENARIO("File", "[CORE][FILE]")
|
||||
{
|
||||
GIVEN("One file")
|
||||
{
|
||||
WHEN("We create a new file")
|
||||
{
|
||||
Nz::File file("Test File.txt", Nz::OpenMode_ReadWrite);
|
||||
REQUIRE(file.GetDirectory() == std::filesystem::current_path());
|
||||
REQUIRE(file.IsOpen());
|
||||
|
||||
THEN("We are allowed to write 3 times 'Test String'")
|
||||
{
|
||||
const char message[12] = "Test String"; // 11 + '\0'
|
||||
Nz::ByteArray byteArray(message, 11);
|
||||
file.Write("Test String");
|
||||
file.Write(byteArray);
|
||||
file.Write(message, 11);
|
||||
}
|
||||
|
||||
AND_THEN("We can retrieve 3 times 'Test String'")
|
||||
{
|
||||
char message[12];
|
||||
REQUIRE(file.Read(message, 11) == 11);
|
||||
message[11] = '\0';
|
||||
REQUIRE(std::string(message) == "Test String");
|
||||
|
||||
REQUIRE(file.Read(message, 11) == 11);
|
||||
message[11] = '\0';
|
||||
REQUIRE(std::string(message) == "Test String");
|
||||
}
|
||||
|
||||
AND_THEN("We can get its size")
|
||||
{
|
||||
REQUIRE(file.GetSize() == 33U);
|
||||
}
|
||||
|
||||
AND_THEN("We close it")
|
||||
{
|
||||
file.Close();
|
||||
CHECK(!file.IsOpen());
|
||||
}
|
||||
|
||||
AND_THEN("Change its size")
|
||||
{
|
||||
file.SetSize(50U);
|
||||
REQUIRE(file.GetSize() == 50U);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We delete this file")
|
||||
{
|
||||
std::filesystem::remove("Test File.txt");
|
||||
|
||||
THEN("It doesn't exist anymore")
|
||||
{
|
||||
CHECK(!std::filesystem::exists("Test File.txt"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("The test file")
|
||||
{
|
||||
REQUIRE(std::filesystem::exists(GetAssetDir() / "Core/FileTest.txt"));
|
||||
|
||||
Nz::File fileTest(GetAssetDir() / "Core/FileTest.txt", Nz::OpenMode::ReadOnly | Nz::OpenMode::Text);
|
||||
|
||||
WHEN("We read the first line of the file")
|
||||
{
|
||||
REQUIRE(fileTest.IsOpen());
|
||||
std::string content = fileTest.ReadLine();
|
||||
|
||||
THEN("The content must be 'Test'")
|
||||
{
|
||||
REQUIRE(content == "Test");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
141
tests/UnitTests/Engine/Core/ObjectHandleTest.cpp
Normal file
141
tests/UnitTests/Engine/Core/ObjectHandleTest.cpp
Normal file
@@ -0,0 +1,141 @@
|
||||
#include <Nazara/Core/HandledObject.hpp>
|
||||
#include <Nazara/Core/ObjectHandle.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
struct ObjectHandle_Test : public Nz::HandledObject<ObjectHandle_Test>
|
||||
{
|
||||
ObjectHandle_Test(int value) :
|
||||
i(value)
|
||||
{
|
||||
}
|
||||
|
||||
int i;
|
||||
};
|
||||
|
||||
SCENARIO("Handle", "[CORE][HandledObject][ObjectHandle]")
|
||||
{
|
||||
GIVEN("One test with two handles")
|
||||
{
|
||||
int defaultValue = 1;
|
||||
ObjectHandle_Test test(defaultValue);
|
||||
|
||||
Nz::ObjectHandle<ObjectHandle_Test> handle1 = test.CreateHandle();
|
||||
Nz::ObjectHandle<ObjectHandle_Test> handle2 = test.CreateHandle();
|
||||
|
||||
WHEN("We modify from one")
|
||||
{
|
||||
const int newI = 2;
|
||||
handle1->i = newI;
|
||||
|
||||
THEN("The other one should also be modified")
|
||||
{
|
||||
REQUIRE(handle2->i == newI);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We copy construct")
|
||||
{
|
||||
ObjectHandle_Test other(test);
|
||||
Nz::ObjectHandle<ObjectHandle_Test> otherHandle = other.CreateHandle();
|
||||
|
||||
THEN("Handles should point to 1")
|
||||
{
|
||||
CHECK(handle1->i == defaultValue);
|
||||
CHECK(handle2->i == defaultValue);
|
||||
CHECK(otherHandle->i == defaultValue);
|
||||
CHECK(handle2.GetObject() == &test);
|
||||
CHECK(otherHandle.GetObject() == &other);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We move construct")
|
||||
{
|
||||
ObjectHandle_Test other(std::move(test));
|
||||
Nz::ObjectHandle<ObjectHandle_Test> otherHandle = other.CreateHandle();
|
||||
|
||||
THEN("Handles should point to 1")
|
||||
{
|
||||
CHECK(handle1->i == defaultValue);
|
||||
CHECK(handle2->i == defaultValue);
|
||||
CHECK(otherHandle->i == defaultValue);
|
||||
CHECK(handle1.GetObject() == &other);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We copy assign")
|
||||
{
|
||||
int copyValue = 3;
|
||||
ObjectHandle_Test other(copyValue);
|
||||
Nz::ObjectHandle<ObjectHandle_Test> otherHandle = other.CreateHandle();
|
||||
test = other;
|
||||
|
||||
THEN("Handles should point to 3")
|
||||
{
|
||||
CHECK(handle1->i == copyValue);
|
||||
CHECK(handle2->i == copyValue);
|
||||
CHECK(otherHandle->i == copyValue);
|
||||
CHECK(handle1.GetObject() == &test);
|
||||
CHECK(otherHandle.GetObject() == &other);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We move assign")
|
||||
{
|
||||
int moveValue = 4;
|
||||
ObjectHandle_Test other(moveValue);
|
||||
Nz::ObjectHandle<ObjectHandle_Test> otherHandle = other.CreateHandle();
|
||||
test = std::move(other);
|
||||
|
||||
THEN("Handles to previous objects should be invalid")
|
||||
{
|
||||
CHECK_FALSE(handle1.IsValid());
|
||||
CHECK_FALSE(handle2.IsValid());
|
||||
}
|
||||
|
||||
THEN("Handles should point to 4")
|
||||
{
|
||||
CHECK(otherHandle.GetObject() == &test);
|
||||
CHECK(otherHandle->i == moveValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("One handle pointing to a default test")
|
||||
{
|
||||
ObjectHandle_Test test(1);
|
||||
Nz::ObjectHandle<ObjectHandle_Test> invalidHandle(&test);
|
||||
|
||||
WHEN("We bind it to a HandledObject which is going to die")
|
||||
{
|
||||
{
|
||||
ObjectHandle_Test dyingTest(5);
|
||||
invalidHandle.Reset(&dyingTest);
|
||||
}
|
||||
|
||||
THEN("It should not be valid")
|
||||
{
|
||||
REQUIRE(!invalidHandle.IsValid());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("Two handle pointing to two different tests")
|
||||
{
|
||||
ObjectHandle_Test test1(1);
|
||||
Nz::ObjectHandle<ObjectHandle_Test> test1Handle = test1.CreateHandle();
|
||||
ObjectHandle_Test test2(2);
|
||||
Nz::ObjectHandle<ObjectHandle_Test> test2Handle = test2.CreateHandle();
|
||||
|
||||
WHEN("We swap their content")
|
||||
{
|
||||
test1Handle.Swap(test2Handle);
|
||||
|
||||
THEN("They should be pointing to the correct one")
|
||||
{
|
||||
CHECK(test1Handle.GetObject() == &test2);
|
||||
CHECK(test2Handle.GetObject() == &test1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
44
tests/UnitTests/Engine/Core/ObjectRefTest.cpp
Normal file
44
tests/UnitTests/Engine/Core/ObjectRefTest.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
#include <Nazara/Core/ObjectRef.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
class Test : public Nz::RefCounted
|
||||
{
|
||||
};
|
||||
|
||||
SCENARIO("ObjectRef", "[CORE][OBJECTREF]")
|
||||
{
|
||||
GIVEN("A ObjectRef")
|
||||
{
|
||||
Nz::ObjectRef<Test> objectRef;
|
||||
|
||||
WHEN("We have two objectRef handling the same object")
|
||||
{
|
||||
Test test;
|
||||
|
||||
objectRef = &test;
|
||||
Nz::ObjectRef<Test> otherRef(&test);
|
||||
|
||||
THEN("Pointers the same")
|
||||
{
|
||||
REQUIRE(objectRef.IsValid());
|
||||
REQUIRE(otherRef.IsValid());
|
||||
}
|
||||
|
||||
objectRef.Reset(nullptr);
|
||||
}
|
||||
|
||||
WHEN("We assign it to a simple font")
|
||||
{
|
||||
Test test;
|
||||
|
||||
THEN("Release suppress the reference to the object")
|
||||
{
|
||||
objectRef.Reset(&test);
|
||||
objectRef.Release();
|
||||
|
||||
REQUIRE(!objectRef.IsValid());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
247
tests/UnitTests/Engine/Core/ParameterListTest.cpp
Normal file
247
tests/UnitTests/Engine/Core/ParameterListTest.cpp
Normal file
@@ -0,0 +1,247 @@
|
||||
#include <Nazara/Core/ParameterList.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
void nullAction(void*)
|
||||
{
|
||||
}
|
||||
|
||||
SCENARIO("ParameterList", "[CORE][PARAMETERLIST]")
|
||||
{
|
||||
GIVEN("An empty ParameterList")
|
||||
{
|
||||
Nz::ParameterList parameterList;
|
||||
|
||||
WHEN("We add Bool 'true' and analogous")
|
||||
{
|
||||
bool boolean = true;
|
||||
parameterList.SetParameter("bool", boolean);
|
||||
|
||||
long long intTrue = 1;
|
||||
parameterList.SetParameter("intTrue", intTrue);
|
||||
long long intFalse = 0;
|
||||
parameterList.SetParameter("intFalse", intFalse);
|
||||
|
||||
std::string strTrue = "true";
|
||||
parameterList.SetParameter("strTrue", strTrue);
|
||||
std::string strFalse = "false";
|
||||
parameterList.SetParameter("strFalse", strFalse);
|
||||
|
||||
THEN("We can get it back")
|
||||
{
|
||||
CHECK(parameterList.GetBooleanParameter("bool").GetValue() == true);
|
||||
}
|
||||
|
||||
THEN("Conversion from int to bool should also work if strict mode is disabled")
|
||||
{
|
||||
CHECK(parameterList.GetBooleanParameter("intTrue", false).GetValue() == true);
|
||||
CHECK(parameterList.GetBooleanParameter("intFalse", false).GetValue() == false);
|
||||
}
|
||||
|
||||
THEN("Conversion from str to bool should also work if strict mode is disabled")
|
||||
{
|
||||
CHECK(parameterList.GetBooleanParameter("strTrue", false).GetValue() == true);
|
||||
CHECK(parameterList.GetBooleanParameter("strFalse", false).GetValue() == false);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We add Color 'rgb(1, 2, 3)'")
|
||||
{
|
||||
Nz::Color rgb(1, 2, 3);
|
||||
parameterList.SetParameter("color", rgb);
|
||||
|
||||
THEN("We can get it back")
|
||||
{
|
||||
CHECK(parameterList.GetColorParameter("color").GetValue() == rgb);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We add Double '3.0' and analogous")
|
||||
{
|
||||
double fl = 3.0;
|
||||
parameterList.SetParameter("double", fl);
|
||||
|
||||
long long intDouble = 3;
|
||||
parameterList.SetParameter("intDouble", intDouble);
|
||||
|
||||
std::string strDouble = "3.0";
|
||||
parameterList.SetParameter("strDouble", strDouble);
|
||||
|
||||
THEN("We can get it back")
|
||||
{
|
||||
CHECK(parameterList.GetDoubleParameter("double").GetValue() == fl);
|
||||
}
|
||||
|
||||
THEN("Conversion from int to double should also work if strict mode is disabled")
|
||||
{
|
||||
CHECK(parameterList.GetDoubleParameter("intDouble", false).GetValue() == fl);
|
||||
}
|
||||
|
||||
THEN("Conversion from string to double should also work if strict mode is disabled")
|
||||
{
|
||||
CHECK(parameterList.GetDoubleParameter("strDouble", false).GetValue() == fl);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We add Int '3' and analogous")
|
||||
{
|
||||
long long i = 3;
|
||||
parameterList.SetParameter("int", i);
|
||||
|
||||
bool trueInt = 1;
|
||||
parameterList.SetParameter("trueInt", trueInt);
|
||||
bool falseInt = 0;
|
||||
parameterList.SetParameter("falseInt", falseInt);
|
||||
|
||||
double doubleInt = 3;
|
||||
parameterList.SetParameter("doubleInt", doubleInt);
|
||||
|
||||
std::string strInt = "3";
|
||||
parameterList.SetParameter("strInt", strInt);
|
||||
|
||||
THEN("We can get it back")
|
||||
{
|
||||
CHECK(parameterList.GetIntegerParameter("int").GetValue() == i);
|
||||
}
|
||||
|
||||
THEN("Conversion from bool to int should also work if strict mode is disabled")
|
||||
{
|
||||
CHECK(parameterList.GetIntegerParameter("trueInt", false).GetValue() == trueInt);
|
||||
CHECK(parameterList.GetIntegerParameter("falseInt", false).GetValue() == falseInt);
|
||||
}
|
||||
|
||||
THEN("Conversion from double to int should also work if strict mode is disabled")
|
||||
{
|
||||
CHECK(parameterList.GetIntegerParameter("doubleInt", false).GetValue() == i);
|
||||
}
|
||||
|
||||
THEN("Conversion from string to int should also work if strict mode is disabled")
|
||||
{
|
||||
CHECK(parameterList.GetIntegerParameter("strInt", false).GetValue() == i);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We add String 'string' and analogous")
|
||||
{
|
||||
std::string string("string");
|
||||
parameterList.SetParameter("string", string);
|
||||
|
||||
bool trueString = 1;
|
||||
parameterList.SetParameter("trueString", trueString);
|
||||
bool falseString = 0;
|
||||
parameterList.SetParameter("falseString", falseString);
|
||||
|
||||
Nz::Color colorString(1, 2, 3);
|
||||
parameterList.SetParameter("colorString", colorString);
|
||||
|
||||
double doubleString = 3.0;
|
||||
parameterList.SetParameter("doubleString", doubleString);
|
||||
|
||||
long long intString = 3;
|
||||
parameterList.SetParameter("intString", intString);
|
||||
|
||||
THEN("We can get it back")
|
||||
{
|
||||
CHECK(parameterList.GetStringParameter("string").GetValue() == string);
|
||||
CHECK(parameterList.GetStringViewParameter("string").GetValue() == string);
|
||||
}
|
||||
|
||||
THEN("Conversion from bool to str should also work if strict mode is disabled")
|
||||
{
|
||||
CHECK(parameterList.GetStringParameter("trueString", false).GetValue() == "true");
|
||||
CHECK(parameterList.GetStringParameter("falseString", false).GetValue() == "false");
|
||||
CHECK(parameterList.GetStringViewParameter("trueString", false).GetValue() == "true");
|
||||
CHECK(parameterList.GetStringViewParameter("falseString", false).GetValue() == "false");
|
||||
}
|
||||
|
||||
THEN("Conversion from color to string should also work if strict mode is disabled")
|
||||
{
|
||||
CHECK(parameterList.GetStringParameter("colorString", false).GetValue() == colorString.ToString());
|
||||
}
|
||||
|
||||
THEN("Conversion from string to double should also work if strict mode is disabled")
|
||||
{
|
||||
CHECK(parameterList.GetStringParameter("doubleString", false).GetValue() == "3.000000");
|
||||
}
|
||||
|
||||
THEN("Conversion from string to int should also work if strict mode is disabled")
|
||||
{
|
||||
CHECK(parameterList.GetStringParameter("intString", false).GetValue() == "3");
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We add Pointer to stack value")
|
||||
{
|
||||
int stackValue = 3;
|
||||
void* ptrToStackValue = &stackValue; // Ugly conversion
|
||||
parameterList.SetParameter("ptr", ptrToStackValue);
|
||||
|
||||
THEN("We can get it back")
|
||||
{
|
||||
CHECK(parameterList.GetPointerParameter("ptr").GetValue() == ptrToStackValue);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We set our own data")
|
||||
{
|
||||
struct Data {
|
||||
int i;
|
||||
float f;
|
||||
};
|
||||
|
||||
Data data{ 1, 3.f };
|
||||
parameterList.SetParameter("userData", &data, nullAction);
|
||||
|
||||
THEN("We can get it back")
|
||||
{
|
||||
void* ptrToData;
|
||||
|
||||
CHECK_NOTHROW(ptrToData = parameterList.GetUserdataParameter("userData").GetValue());
|
||||
Data* dataPtr = static_cast<Data*>(ptrToData);
|
||||
CHECK(dataPtr->i == data.i);
|
||||
CHECK(dataPtr->f == data.f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A parameter list with some values")
|
||||
{
|
||||
Nz::ParameterList parameterList;
|
||||
|
||||
long long i = 3;
|
||||
parameterList.SetParameter("i", i);
|
||||
double d = 1.0;
|
||||
parameterList.SetParameter("d", d);
|
||||
|
||||
parameterList.SetParameter("toaster");
|
||||
parameterList.SetParameter("str", "ing");
|
||||
|
||||
WHEN("We remove two elements")
|
||||
{
|
||||
CHECK(parameterList.HasParameter("i"));
|
||||
CHECK(parameterList.HasParameter("toaster"));
|
||||
|
||||
parameterList.RemoveParameter("i");
|
||||
parameterList.RemoveParameter("toaster");
|
||||
|
||||
THEN("They do not exist anymore")
|
||||
{
|
||||
CHECK(!parameterList.HasParameter("i"));
|
||||
CHECK(!parameterList.HasParameter("toaster"));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We copy this list")
|
||||
{
|
||||
Nz::ParameterList copy = parameterList;
|
||||
|
||||
THEN("It has the same elements")
|
||||
{
|
||||
CHECK(parameterList.HasParameter("i"));
|
||||
CHECK(parameterList.HasParameter("d"));
|
||||
CHECK(parameterList.HasParameter("toaster"));
|
||||
CHECK(parameterList.HasParameter("str"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
44
tests/UnitTests/Engine/Core/PrimitiveListTest.cpp
Normal file
44
tests/UnitTests/Engine/Core/PrimitiveListTest.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
#include <Nazara/Core/PrimitiveList.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
SCENARIO("PrimitiveList", "[CORE][PRIMITIVELIST]")
|
||||
{
|
||||
GIVEN("An empty PrimitiveList")
|
||||
{
|
||||
Nz::PrimitiveList primitiveList;
|
||||
|
||||
WHEN("We add two primitives")
|
||||
{
|
||||
float size = 1.f;
|
||||
unsigned int subdivision = 1;
|
||||
Nz::Matrix4f identity = Nz::Matrix4f::Identity();
|
||||
|
||||
primitiveList.AddCubicSphere(size, subdivision, identity);
|
||||
primitiveList.AddBox(Nz::Vector3f(size), Nz::Vector3ui(subdivision), identity);
|
||||
primitiveList.AddIcoSphere(size, subdivision, identity);
|
||||
|
||||
THEN("There must be two items")
|
||||
{
|
||||
REQUIRE(primitiveList.GetSize() == 3);
|
||||
}
|
||||
|
||||
THEN("The first one is the cubic sphere")
|
||||
{
|
||||
REQUIRE(primitiveList(0).type == Nz::PrimitiveType::Sphere);
|
||||
REQUIRE(primitiveList(0).sphere.type == Nz::SphereType::Cubic);
|
||||
}
|
||||
|
||||
THEN("The second one is the box")
|
||||
{
|
||||
REQUIRE(primitiveList(1).type == Nz::PrimitiveType::Box);
|
||||
}
|
||||
|
||||
THEN("The third one is the ico sphere")
|
||||
{
|
||||
REQUIRE(primitiveList(2).type == Nz::PrimitiveType::Sphere);
|
||||
REQUIRE(primitiveList(2).sphere.type == Nz::SphereType::Ico);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
30
tests/UnitTests/Engine/Core/RefCountedTest.cpp
Normal file
30
tests/UnitTests/Engine/Core/RefCountedTest.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
#include <Nazara/Core/RefCounted.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
SCENARIO("RefCounted", "[CORE][REFCOUNTED]")
|
||||
{
|
||||
GIVEN("A refcounted persistent")
|
||||
{
|
||||
Nz::RefCounted refCounted;
|
||||
REQUIRE(refCounted.IsPersistent() == true);
|
||||
|
||||
WHEN("We add a reference to this persistent object")
|
||||
{
|
||||
THEN("Number of references should be one")
|
||||
{
|
||||
refCounted.AddReference();
|
||||
REQUIRE(refCounted.GetReferenceCount() == 1);
|
||||
REQUIRE(refCounted.RemoveReference() == false);
|
||||
}
|
||||
|
||||
AND_THEN("We suppress the reference, object is still alive")
|
||||
{
|
||||
refCounted.AddReference();
|
||||
REQUIRE(refCounted.IsPersistent());
|
||||
REQUIRE(refCounted.RemoveReference() == false);
|
||||
REQUIRE(refCounted.GetReferenceCount() == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
263
tests/UnitTests/Engine/Core/SerializationTest.cpp
Normal file
263
tests/UnitTests/Engine/Core/SerializationTest.cpp
Normal file
@@ -0,0 +1,263 @@
|
||||
#include <Nazara/Core/SerializationContext.hpp>
|
||||
|
||||
#include <Nazara/Core/Color.hpp>
|
||||
#include <Nazara/Core/MemoryView.hpp>
|
||||
#include <Nazara/Math/BoundingVolume.hpp>
|
||||
#include <Nazara/Math/Frustum.hpp>
|
||||
#include <Nazara/Math/Ray.hpp>
|
||||
#include <array>
|
||||
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
SCENARIO("Serialization", "[CORE][SERIALIZATION]")
|
||||
{
|
||||
GIVEN("A context of serialization")
|
||||
{
|
||||
std::array<char, 256> datas; // The array must be bigger than any of the serializable classes
|
||||
Nz::MemoryView stream(datas.data(), datas.size());
|
||||
|
||||
Nz::SerializationContext context;
|
||||
context.stream = &stream;
|
||||
|
||||
WHEN("We serialize basic types")
|
||||
{
|
||||
THEN("Arithmetical types")
|
||||
{
|
||||
context.stream->SetCursorPos(0);
|
||||
REQUIRE(Serialize(context, 3));
|
||||
int value = 0;
|
||||
context.stream->SetCursorPos(0);
|
||||
REQUIRE(Unserialize(context, &value));
|
||||
REQUIRE(value == 3);
|
||||
}
|
||||
|
||||
THEN("Boolean type")
|
||||
{
|
||||
context.stream->SetCursorPos(0);
|
||||
REQUIRE(Serialize(context, true));
|
||||
context.FlushBits(); //< Don't forget to flush bits (it is NOT done by the stream)
|
||||
context.stream->SetCursorPos(0);
|
||||
bool value = false;
|
||||
REQUIRE(Unserialize(context, &value));
|
||||
REQUIRE(value == true);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We serialize mathematical classes")
|
||||
{
|
||||
THEN("BoudingVolume")
|
||||
{
|
||||
context.stream->SetCursorPos(0);
|
||||
Nz::BoundingVolumef nullVolume = Nz::BoundingVolumef::Null();
|
||||
Nz::BoundingVolumef copy(nullVolume);
|
||||
REQUIRE(Serialize(context, nullVolume));
|
||||
nullVolume = Nz::BoundingVolumef::Infinite();
|
||||
REQUIRE(nullVolume != copy);
|
||||
context.stream->SetCursorPos(0);
|
||||
REQUIRE(Unserialize(context, &nullVolume));
|
||||
REQUIRE(nullVolume == copy);
|
||||
}
|
||||
|
||||
THEN("Box")
|
||||
{
|
||||
context.stream->SetCursorPos(0);
|
||||
Nz::Boxf zeroBox = Nz::Boxf::Zero();
|
||||
Nz::Boxf copy(zeroBox);
|
||||
REQUIRE(Serialize(context, zeroBox));
|
||||
zeroBox = Nz::Boxf(1, 1, 1, 1, 1, 1);
|
||||
REQUIRE(zeroBox != copy);
|
||||
context.stream->SetCursorPos(0);
|
||||
REQUIRE(Unserialize(context, &zeroBox));
|
||||
REQUIRE(zeroBox == copy);
|
||||
}
|
||||
|
||||
THEN("EulerAngles")
|
||||
{
|
||||
context.stream->SetCursorPos(0);
|
||||
Nz::EulerAnglesf zeroEuler = Nz::EulerAnglesf::Zero();
|
||||
Nz::EulerAnglesf copy(zeroEuler);
|
||||
REQUIRE(Serialize(context, zeroEuler));
|
||||
zeroEuler = Nz::EulerAnglesf(10, 24, 6); // Random values
|
||||
REQUIRE(zeroEuler != copy);
|
||||
context.stream->SetCursorPos(0);
|
||||
REQUIRE(Unserialize(context, &zeroEuler));
|
||||
REQUIRE(zeroEuler == copy);
|
||||
}
|
||||
|
||||
THEN("Frustum")
|
||||
{
|
||||
context.stream->SetCursorPos(0);
|
||||
Nz::Frustumf frustum = Nz::Frustumf::Build(10, 10, 10, 100, Nz::Vector3f::UnitX(), Nz::Vector3f::UnitZ()); // Random values
|
||||
Nz::Frustumf copy(frustum);
|
||||
REQUIRE(Serialize(context, frustum));
|
||||
frustum = Nz::Frustumf::Build(50, 40, 20, 100, Nz::Vector3f::UnitX(), Nz::Vector3f::UnitZ());
|
||||
for (std::size_t i = 0; i < Nz::FrustumPlaneCount; ++i)
|
||||
REQUIRE(frustum.GetPlane(static_cast<Nz::FrustumPlane>(i)) != copy.GetPlane(static_cast<Nz::FrustumPlane>(i)));
|
||||
context.stream->SetCursorPos(0);
|
||||
REQUIRE(Unserialize(context, &frustum));
|
||||
for (std::size_t i = 0; i < Nz::FrustumPlaneCount; ++i)
|
||||
REQUIRE(frustum.GetPlane(static_cast<Nz::FrustumPlane>(i)) == copy.GetPlane(static_cast<Nz::FrustumPlane>(i)));
|
||||
}
|
||||
|
||||
THEN("Matrix4")
|
||||
{
|
||||
context.stream->SetCursorPos(0);
|
||||
Nz::Matrix4f zeroMatrix = Nz::Matrix4f::Zero();
|
||||
Nz::Matrix4f copy(zeroMatrix);
|
||||
REQUIRE(Serialize(context, zeroMatrix));
|
||||
zeroMatrix = Nz::Matrix4f::Identity(); // Random values
|
||||
REQUIRE(zeroMatrix != copy);
|
||||
context.stream->SetCursorPos(0);
|
||||
REQUIRE(Unserialize(context, &zeroMatrix));
|
||||
REQUIRE(zeroMatrix == copy);
|
||||
}
|
||||
|
||||
THEN("OrientedBox")
|
||||
{
|
||||
context.stream->SetCursorPos(0);
|
||||
Nz::OrientedBoxf zeroOBB = Nz::OrientedBoxf::Zero();
|
||||
Nz::OrientedBoxf copy(zeroOBB);
|
||||
REQUIRE(Serialize(context, zeroOBB));
|
||||
zeroOBB = Nz::OrientedBoxf(Nz::Boxf(1, 1, 1, 1, 1, 1)); // Random values
|
||||
REQUIRE(zeroOBB != copy);
|
||||
context.stream->SetCursorPos(0);
|
||||
REQUIRE(Unserialize(context, &zeroOBB));
|
||||
REQUIRE(zeroOBB == copy);
|
||||
}
|
||||
|
||||
THEN("Plane")
|
||||
{
|
||||
context.stream->SetCursorPos(0);
|
||||
Nz::Planef planeXY = Nz::Planef::XY();
|
||||
Nz::Planef copy(planeXY);
|
||||
REQUIRE(Serialize(context, planeXY));
|
||||
planeXY = Nz::Planef::YZ();
|
||||
REQUIRE(planeXY != copy);
|
||||
context.stream->SetCursorPos(0);
|
||||
REQUIRE(Unserialize(context, &planeXY));
|
||||
REQUIRE(planeXY == copy);
|
||||
}
|
||||
|
||||
THEN("Quaternion")
|
||||
{
|
||||
context.stream->SetCursorPos(0);
|
||||
Nz::Quaternionf quaternionIdentity = Nz::Quaternionf::Identity();
|
||||
Nz::Quaternionf copy(quaternionIdentity);
|
||||
REQUIRE(Serialize(context, quaternionIdentity));
|
||||
quaternionIdentity = Nz::Quaternionf::Zero();
|
||||
REQUIRE(quaternionIdentity != copy);
|
||||
context.stream->SetCursorPos(0);
|
||||
REQUIRE(Unserialize(context, &quaternionIdentity));
|
||||
REQUIRE(quaternionIdentity == copy);
|
||||
}
|
||||
|
||||
THEN("Ray")
|
||||
{
|
||||
context.stream->SetCursorPos(0);
|
||||
Nz::Rayf axisX = Nz::Rayf::AxisX();
|
||||
Nz::Rayf copy(axisX);
|
||||
REQUIRE(Serialize(context, axisX));
|
||||
axisX = Nz::Rayf::AxisY();
|
||||
REQUIRE(axisX != copy);
|
||||
context.stream->SetCursorPos(0);
|
||||
REQUIRE(Unserialize(context, &axisX));
|
||||
REQUIRE(axisX == copy);
|
||||
}
|
||||
|
||||
THEN("Rect")
|
||||
{
|
||||
context.stream->SetCursorPos(0);
|
||||
Nz::Rectf zeroRect = Nz::Rectf::Zero();
|
||||
Nz::Rectf copy(zeroRect);
|
||||
REQUIRE(Serialize(context, zeroRect));
|
||||
zeroRect = Nz::Rectf(1, 1, 1, 1); // Random values
|
||||
REQUIRE(zeroRect != copy);
|
||||
context.stream->SetCursorPos(0);
|
||||
REQUIRE(Unserialize(context, &zeroRect));
|
||||
REQUIRE(zeroRect == copy);
|
||||
}
|
||||
|
||||
THEN("Sphere")
|
||||
{
|
||||
context.stream->SetCursorPos(0);
|
||||
Nz::Spheref zeroSphere = Nz::Spheref::Zero();
|
||||
Nz::Spheref copy(zeroSphere);
|
||||
REQUIRE(Serialize(context, zeroSphere));
|
||||
zeroSphere = Nz::Spheref::Unit();
|
||||
REQUIRE(zeroSphere != copy);
|
||||
context.stream->SetCursorPos(0);
|
||||
REQUIRE(Unserialize(context, &zeroSphere));
|
||||
REQUIRE(zeroSphere == copy);
|
||||
}
|
||||
|
||||
THEN("Vector2")
|
||||
{
|
||||
context.stream->SetCursorPos(0);
|
||||
Nz::Vector2f unitX = Nz::Vector2f::UnitX();
|
||||
Nz::Vector2f copy(unitX);
|
||||
REQUIRE(Serialize(context, unitX));
|
||||
unitX = Nz::Vector2f::UnitY();
|
||||
REQUIRE(unitX != copy);
|
||||
context.stream->SetCursorPos(0);
|
||||
REQUIRE(Unserialize(context, &unitX));
|
||||
REQUIRE(unitX == copy);
|
||||
}
|
||||
|
||||
THEN("Vector3")
|
||||
{
|
||||
context.stream->SetCursorPos(0);
|
||||
Nz::Vector3f unitX = Nz::Vector3f::UnitX();
|
||||
Nz::Vector3f copy(unitX);
|
||||
REQUIRE(Serialize(context, unitX));
|
||||
unitX = Nz::Vector3f::UnitY();
|
||||
REQUIRE(unitX != copy);
|
||||
context.stream->SetCursorPos(0);
|
||||
REQUIRE(Unserialize(context, &unitX));
|
||||
REQUIRE(unitX == copy);
|
||||
}
|
||||
|
||||
THEN("Vector4")
|
||||
{
|
||||
context.stream->SetCursorPos(0);
|
||||
Nz::Vector4f unitX = Nz::Vector4f::UnitX();
|
||||
Nz::Vector4f copy(unitX);
|
||||
REQUIRE(Serialize(context, unitX));
|
||||
unitX = Nz::Vector4f::UnitY();
|
||||
REQUIRE(unitX != copy);
|
||||
context.stream->SetCursorPos(0);
|
||||
REQUIRE(Unserialize(context, &unitX));
|
||||
REQUIRE(unitX == copy);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We serialize core classes")
|
||||
{
|
||||
THEN("Color")
|
||||
{
|
||||
context.stream->SetCursorPos(0);
|
||||
Nz::Color red = Nz::Color::Red;
|
||||
Nz::Color copy(red);
|
||||
REQUIRE(Serialize(context, red));
|
||||
red = Nz::Color::Black;
|
||||
REQUIRE(red != copy);
|
||||
context.stream->SetCursorPos(0);
|
||||
REQUIRE(Unserialize(context, &red));
|
||||
REQUIRE(red == copy);
|
||||
}
|
||||
|
||||
THEN("String")
|
||||
{
|
||||
context.stream->SetCursorPos(0);
|
||||
std::string string = "string";
|
||||
std::string copy(string);
|
||||
REQUIRE(Serialize(context, string));
|
||||
string = "another";
|
||||
REQUIRE(string != copy);
|
||||
context.stream->SetCursorPos(0);
|
||||
REQUIRE(Unserialize(context, &string));
|
||||
REQUIRE(string == copy);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
154
tests/UnitTests/Engine/Core/StringExtTest.cpp
Normal file
154
tests/UnitTests/Engine/Core/StringExtTest.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
#include <Nazara/Core/StringExt.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
SCENARIO("String", "[CORE][STRING]")
|
||||
{
|
||||
std::string unicodeString(u8"\u00E0\u00E9\u00E7\u0153\u00C2\u5B98\u46E1");
|
||||
|
||||
WHEN("Checking if string ends with")
|
||||
{
|
||||
CHECK(Nz::EndsWith("", ""));
|
||||
CHECK(Nz::EndsWith("Nazara Engine", ""));
|
||||
CHECK(Nz::EndsWith("Nazara Engine", "Engine"));
|
||||
CHECK_FALSE(Nz::EndsWith("Nazara Engine", "engine"));
|
||||
CHECK_FALSE(Nz::EndsWith("Nazara Engine", " ngine"));
|
||||
CHECK_FALSE(Nz::EndsWith("Nazara Engine", "NazaraEngine"));
|
||||
CHECK_FALSE(Nz::EndsWith("Nazara Engine", "Nazara"));
|
||||
CHECK_FALSE(Nz::EndsWith("Nazara Engine", "Sir Nazara van Engine"));
|
||||
|
||||
CHECK(Nz::EndsWith("", "", Nz::CaseIndependent{}));
|
||||
CHECK(Nz::EndsWith("Nazara Engine", "", Nz::CaseIndependent{}));
|
||||
CHECK(Nz::EndsWith("Nazara Engine", "Engine", Nz::CaseIndependent{}));
|
||||
CHECK(Nz::EndsWith("Nazara Engine", "engine", Nz::CaseIndependent{}));
|
||||
CHECK(Nz::EndsWith("Nazara engine", "EnGiNe", Nz::CaseIndependent{}));
|
||||
CHECK_FALSE(Nz::EndsWith("Nazara Engine", " ngine", Nz::CaseIndependent{}));
|
||||
CHECK_FALSE(Nz::EndsWith("Nazara Engine", "NazaraEngine", Nz::CaseIndependent{}));
|
||||
CHECK_FALSE(Nz::EndsWith("Nazara Engine", "Nazara", Nz::CaseIndependent{}));
|
||||
CHECK_FALSE(Nz::EndsWith("Nazara Engine", "Sir Nazara van Engine", Nz::CaseIndependent{}));
|
||||
|
||||
CHECK(Nz::EndsWith(u8"L'\u00CEle de R\u00E9", u8"", Nz::UnicodeAware{}));
|
||||
CHECK(Nz::EndsWith(u8"L'\u00CEle de R\u00E9", u8"R\u00E9", Nz::UnicodeAware{}));
|
||||
CHECK_FALSE(Nz::EndsWith(u8"L'\u00CEle de R\u00E9", u8"Long long j\u00F4hnson", Nz::UnicodeAware{}));
|
||||
|
||||
CHECK(Nz::EndsWith(u8"L'\u00CEle de R\u00E9", u8"", Nz::CaseIndependent{}, Nz::UnicodeAware{}));
|
||||
CHECK(Nz::EndsWith(u8"L'\u00CEle de R\u00E9", u8"R\u00C9", Nz::CaseIndependent{}, Nz::UnicodeAware{}));
|
||||
CHECK_FALSE(Nz::EndsWith(u8"L'\u00CEle de R\u00E9", u8"Long long j\u00F4hnson", Nz::CaseIndependent{}, Nz::UnicodeAware{}));
|
||||
}
|
||||
|
||||
WHEN("Converting string back and forth")
|
||||
{
|
||||
CHECK(Nz::FromUtf16String(Nz::ToUtf16String(unicodeString)) == unicodeString);
|
||||
CHECK(Nz::FromUtf32String(Nz::ToUtf32String(unicodeString)) == unicodeString);
|
||||
}
|
||||
|
||||
WHEN("Fetching words")
|
||||
{
|
||||
CHECK(Nz::GetWord({}, 0).empty());
|
||||
CHECK(Nz::GetWord(" ", 0).empty());
|
||||
|
||||
std::string sentence = u8"\nSay hello\tto Nazara\u00A0Engine\n\t! "; //< \u00A0 is a No-Break Space
|
||||
CHECK(Nz::GetWord(sentence, 0) == "Say");
|
||||
CHECK(Nz::GetWord(sentence, 1) == "hello");
|
||||
CHECK(Nz::GetWord(sentence, 2) == "to");
|
||||
CHECK(Nz::GetWord(sentence, 3) == u8"Nazara\u00A0Engine");
|
||||
CHECK(Nz::GetWord(sentence, 4) == "!");
|
||||
CHECK(Nz::GetWord(sentence, 5).empty());
|
||||
|
||||
// Try the same using Unicode aware overloads
|
||||
CHECK(Nz::GetWord(sentence, 0, Nz::UnicodeAware{}) == "Say");
|
||||
CHECK(Nz::GetWord(sentence, 1, Nz::UnicodeAware{}) == "hello");
|
||||
CHECK(Nz::GetWord(sentence, 2, Nz::UnicodeAware{}) == "to");
|
||||
CHECK(Nz::GetWord(sentence, 3, Nz::UnicodeAware{}) == "Nazara");
|
||||
CHECK(Nz::GetWord(sentence, 4, Nz::UnicodeAware{}) == "Engine");
|
||||
CHECK(Nz::GetWord(sentence, 5, Nz::UnicodeAware{}) == "!");
|
||||
CHECK(Nz::GetWord(sentence, 6, Nz::UnicodeAware{}).empty());
|
||||
}
|
||||
|
||||
WHEN("Checking if string is number")
|
||||
{
|
||||
CHECK(Nz::IsNumber("123456"));
|
||||
CHECK(Nz::IsNumber("-123456"));
|
||||
CHECK_FALSE(Nz::IsNumber("123 "));
|
||||
CHECK_FALSE(Nz::IsNumber("Nazara Engine"));
|
||||
CHECK_FALSE(Nz::IsNumber("12345Nazara Engine"));
|
||||
}
|
||||
|
||||
WHEN("Matching patterns")
|
||||
{
|
||||
CHECK(Nz::MatchPattern("Lynix", "?????"));
|
||||
CHECK(Nz::MatchPattern("Lynix", "*Lynix"));
|
||||
CHECK(Nz::MatchPattern("Lynox", "*Lyn?x"));
|
||||
CHECK_FALSE(Nz::MatchPattern("", "?"));
|
||||
CHECK_FALSE(Nz::MatchPattern("", "*"));
|
||||
|
||||
const char* pattern = "Naz?ra *gine";
|
||||
CHECK(Nz::MatchPattern("Nazara Engine", pattern));
|
||||
CHECK(Nz::MatchPattern("Nazora engine", pattern));
|
||||
CHECK(Nz::MatchPattern("Nazora Biggine", pattern));
|
||||
CHECK(Nz::MatchPattern("Nazora gine", pattern));
|
||||
|
||||
CHECK_FALSE(Nz::MatchPattern("Nazaragine", pattern));
|
||||
CHECK_FALSE(Nz::MatchPattern("Nazorra Engine", pattern));
|
||||
CHECK_FALSE(Nz::MatchPattern("Nazra Engine", pattern));
|
||||
CHECK_FALSE(Nz::MatchPattern("NazaraEngine", pattern));
|
||||
}
|
||||
|
||||
WHEN("Converting pointers to string")
|
||||
{
|
||||
CHECK(Nz::TrimRight(Nz::PointerToString(nullptr), '0') == "0x");
|
||||
|
||||
const void* ptr = reinterpret_cast<const void*>(static_cast<std::uintptr_t>(0xDEADBEEF));
|
||||
CHECK(Nz::MatchPattern(Nz::PointerToString(ptr), "0x*DEADBEEF"));
|
||||
}
|
||||
|
||||
WHEN("Replacing strings")
|
||||
{
|
||||
std::string str = "Nazara Engine";
|
||||
REQUIRE(Nz::ReplaceStr(str, "Nazara", "Unreal") == "Unreal Engine");
|
||||
REQUIRE(Nz::ReplaceStr(str, "Engine", "Reality") == "Unreal Reality");
|
||||
REQUIRE(Nz::ReplaceStr(str, "Unreal Reality", "Ungine") == "Ungine");
|
||||
}
|
||||
|
||||
WHEN("Checking if string starts with")
|
||||
{
|
||||
CHECK(Nz::StartsWith("Nazara Engine", ""));
|
||||
CHECK(Nz::StartsWith("Nazara Engine", "Nazara"));
|
||||
CHECK_FALSE(Nz::StartsWith("Nazara Engine", "Navara"));
|
||||
CHECK_FALSE(Nz::StartsWith("Nazara Engine", "NaZaRa"));
|
||||
CHECK_FALSE(Nz::StartsWith("Nazara Engine", "Long long johnson"));
|
||||
|
||||
CHECK(Nz::StartsWith("NAZARA Engine", "", Nz::CaseIndependent{}));
|
||||
CHECK(Nz::StartsWith("NAZARA Engine", "Nazara", Nz::CaseIndependent{}));
|
||||
CHECK(Nz::StartsWith("NAZARA Engine", "NaZaRa", Nz::CaseIndependent{}));
|
||||
CHECK_FALSE(Nz::StartsWith("NAZARA Engine", "NavaRa", Nz::CaseIndependent{}));
|
||||
CHECK_FALSE(Nz::StartsWith("NAZARA Engine", "Long long johnson", Nz::CaseIndependent{}));
|
||||
|
||||
CHECK(Nz::StartsWith(u8"L'\u00CEle de R\u00E9", u8"", Nz::UnicodeAware{}));
|
||||
CHECK(Nz::StartsWith(u8"L'\u00CEle de R\u00E9", u8"L'\u00CEle", Nz::UnicodeAware{}));
|
||||
CHECK_FALSE(Nz::StartsWith(u8"L'\u00CEle de R\u00E9", u8"Long long j\u00F4hnson", Nz::UnicodeAware{}));
|
||||
|
||||
CHECK(Nz::StartsWith(u8"L'\u00CEle de R\u00E9", u8"", Nz::CaseIndependent{}, Nz::UnicodeAware{}));
|
||||
CHECK(Nz::StartsWith(u8"L'\u00CEle de R\u00E9", u8"l'\u00EEle", Nz::CaseIndependent{}, Nz::UnicodeAware{}));
|
||||
CHECK_FALSE(Nz::StartsWith(u8"L'\u00CEle de R\u00E9", u8"Long long j\u00F4hnson", Nz::CaseIndependent{}, Nz::UnicodeAware{}));
|
||||
}
|
||||
|
||||
WHEN("Converting between lower and upper")
|
||||
{
|
||||
CHECK(Nz::ToLower("Nazara Engine") == "nazara engine");
|
||||
CHECK(Nz::ToLower(u8"L'\u00CELE DE R\u00C9", Nz::UnicodeAware{}) == u8"l'\u00EEle de r\u00E9");
|
||||
CHECK(Nz::ToUpper("Nazara Engine") == "NAZARA ENGINE");
|
||||
CHECK(Nz::ToUpper(u8"l'\u00EEle de r\u00E9", Nz::UnicodeAware{}) == u8"L'\u00CELE DE R\u00C9");
|
||||
}
|
||||
|
||||
WHEN("Trimming strings")
|
||||
{
|
||||
CHECK(Nz::Trim(" \n Hello World\t") == "Hello World");
|
||||
CHECK(Nz::Trim("Nazara Engin", 'n') == "Nazara Engi");
|
||||
CHECK(Nz::Trim("Nazara Engin", 'n', Nz::CaseIndependent{}) == "azara Engi");
|
||||
CHECK(Nz::Trim(unicodeString, Nz::UnicodeAware{}) == unicodeString);
|
||||
CHECK(Nz::Trim("\n\t" + unicodeString + "\t ", Nz::UnicodeAware{}) == unicodeString);
|
||||
CHECK(Nz::Trim(unicodeString, U'\u46E1', Nz::UnicodeAware{}) == u8"\u00E0\u00E9\u00E7\u0153\u00C2\u5B98");
|
||||
CHECK(Nz::Trim(unicodeString, Nz::Unicode::Category_Letter, Nz::UnicodeAware{}) == "");
|
||||
}
|
||||
}
|
||||
85
tests/UnitTests/Engine/Core/UuidTest.cpp
Normal file
85
tests/UnitTests/Engine/Core/UuidTest.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
#include <Nazara/Core/Uuid.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <regex>
|
||||
#include <set>
|
||||
#include <unordered_set>
|
||||
|
||||
SCENARIO("Uuid", "[CORE][UUID]")
|
||||
{
|
||||
WHEN("Parsing UUID")
|
||||
{
|
||||
CHECK(Nz::Uuid::FromString("00000000-0000-0000-0000-000000000000") == Nz::Uuid());
|
||||
CHECK(Nz::Uuid::FromString("1b0e29af-fd4a-43e0-ba4c-e9334183b1f1") == Nz::Uuid({ 0x1B, 0x0E, 0x29, 0xAF, 0xFD, 0x4A, 0x43, 0xE0, 0xBA, 0x4C, 0xE9, 0x33, 0x41, 0x83, 0xB1, 0xF1 }));
|
||||
|
||||
// Testing some invalid cases
|
||||
CHECK(Nz::Uuid::FromString("Nazara Engine") == Nz::Uuid());
|
||||
CHECK(Nz::Uuid::FromString("1b0e29af_fd4a_43e0_ba4c_e9334183b1f1") == Nz::Uuid());
|
||||
CHECK(Nz::Uuid::FromString("1b0e29af-fd4a_43e0_ba4c_e93341-3b1f1") == Nz::Uuid());
|
||||
CHECK(Nz::Uuid::FromString("Zb0e29af-fd4a-43e0-ba4c-e9334183b1f1") == Nz::Uuid());
|
||||
CHECK(Nz::Uuid::FromString("1b0e29a\t-fd4a-43e0-ba4c-e9334183b1f1") == Nz::Uuid());
|
||||
CHECK(Nz::Uuid::FromString("1b0e29af-fd4\v-43e0-ba4c-e9334183b1f1") == Nz::Uuid());
|
||||
CHECK(Nz::Uuid::FromString("1b0e29af-fd4a-\r3e0-ba4c-e9334183b1f1") == Nz::Uuid());
|
||||
CHECK(Nz::Uuid::FromString("1b0e29af-fd4a-43e\n-ba4c-e9334183b1f1") == Nz::Uuid());
|
||||
CHECK(Nz::Uuid::FromString("1b0e29af-fd4a-43e0-\0a4c-e9334183b1f1") == Nz::Uuid());
|
||||
CHECK(Nz::Uuid::FromString("1b0e29af-fd4a-43e0-ba4\n-e9334183b1f1") == Nz::Uuid());
|
||||
CHECK(Nz::Uuid::FromString("1b0e29af-fd4a-43e0-ba4c-g9334183b1f1") == Nz::Uuid());
|
||||
CHECK(Nz::Uuid::FromString("1b0e29af-fd4a-43e0-ba4c-e9334183b1fG") == Nz::Uuid());
|
||||
CHECK(Nz::Uuid::FromString("1b0e29af-HELL-OWOR-LDDD-e9334183b1f1") == Nz::Uuid());
|
||||
}
|
||||
|
||||
WHEN("Generating a null UUID")
|
||||
{
|
||||
Nz::Uuid nullUuid;
|
||||
CHECK(nullUuid.IsNull());
|
||||
CHECK(nullUuid.ToArray() == std::array<Nz::UInt8, 16>{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0});
|
||||
CHECK(nullUuid.ToString() == "00000000-0000-0000-0000-000000000000");
|
||||
CHECK(nullUuid.ToStringArray() == std::array<char, 37>{"00000000-0000-0000-0000-000000000000"});
|
||||
CHECK(nullUuid == Nz::Uuid{});
|
||||
CHECK(nullUuid >= Nz::Uuid{});
|
||||
CHECK(nullUuid <= Nz::Uuid{});
|
||||
CHECK_FALSE(nullUuid > Nz::Uuid{});
|
||||
CHECK_FALSE(nullUuid < Nz::Uuid{});
|
||||
CHECK(nullUuid != Nz::Uuid::Generate());
|
||||
CHECK(Nz::Uuid::FromString(nullUuid.ToString()) == nullUuid);
|
||||
}
|
||||
|
||||
WHEN("Generating a UUID")
|
||||
{
|
||||
// https://stackoverflow.com/questions/136505/searching-for-uuids-in-text-with-regex
|
||||
std::regex uuidRegex(R"(^\b[0-9a-f]{8}\b-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-\b[0-9a-f]{12}\b$)");
|
||||
|
||||
Nz::Uuid uuid = Nz::Uuid::Generate();
|
||||
INFO(uuid);
|
||||
CHECK_FALSE(uuid.IsNull());
|
||||
CHECK(std::regex_match(uuid.ToString(), uuidRegex));
|
||||
CHECK(uuid == uuid);
|
||||
CHECK(uuid == Nz::Uuid{uuid.ToArray()});
|
||||
CHECK(uuid >= uuid);
|
||||
CHECK(uuid <= uuid);
|
||||
CHECK_FALSE(uuid > uuid);
|
||||
CHECK_FALSE(uuid < uuid);
|
||||
CHECK(Nz::Uuid::FromString(uuid.ToString()) == uuid);
|
||||
}
|
||||
|
||||
WHEN("Generating multiple UUID, they are unique")
|
||||
{
|
||||
std::set<Nz::Uuid> uuidSet;
|
||||
std::unordered_set<Nz::Uuid> uuidUnorderedset;
|
||||
|
||||
auto InsertUniqueUuid = [](auto& container, const Nz::Uuid& uuid)
|
||||
{
|
||||
auto it = container.find(uuid);
|
||||
REQUIRE(it == container.end());
|
||||
container.insert(uuid);
|
||||
};
|
||||
|
||||
for (std::size_t i = 0; i < 1'000; ++i)
|
||||
{
|
||||
auto uuid = Nz::Uuid::Generate();
|
||||
|
||||
InsertUniqueUuid(uuidSet, uuid);
|
||||
InsertUniqueUuid(uuidUnorderedset, uuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
322
tests/UnitTests/Engine/Core/VirtualDirectoryTest.cpp
Normal file
322
tests/UnitTests/Engine/Core/VirtualDirectoryTest.cpp
Normal file
@@ -0,0 +1,322 @@
|
||||
#include <Nazara/Core/Algorithm.hpp>
|
||||
#include <Nazara/Core/File.hpp>
|
||||
#include <Nazara/Core/StringExt.hpp>
|
||||
#include <Nazara/Core/VirtualDirectory.hpp>
|
||||
#include <Nazara/Core/Hash/SHA256.hpp>
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <random>
|
||||
|
||||
std::filesystem::path GetAssetDir();
|
||||
|
||||
TEST_CASE("VirtualDirectory", "[Core][VirtualDirectory]")
|
||||
{
|
||||
SECTION("Creating a virtual directory")
|
||||
{
|
||||
std::shared_ptr<Nz::VirtualDirectory> virtualDir = std::make_shared<Nz::VirtualDirectory>();
|
||||
WHEN("Iterating it, it only has . and ..")
|
||||
{
|
||||
bool dot = false;
|
||||
bool dotDot = false;
|
||||
virtualDir->Foreach([&](std::string_view name, const Nz::VirtualDirectory::Entry& /*entry*/)
|
||||
{
|
||||
if (name == ".")
|
||||
{
|
||||
CHECK_FALSE(dot);
|
||||
dot = true;
|
||||
}
|
||||
else if (name == "..")
|
||||
{
|
||||
CHECK_FALSE(dotDot);
|
||||
dotDot = true;
|
||||
}
|
||||
if (name != "." && name != "..")
|
||||
FAIL("Got file " << name);
|
||||
}, true);
|
||||
|
||||
CHECK(dot);
|
||||
CHECK(dotDot);
|
||||
}
|
||||
AND_WHEN("Iterating it without dots, directory it empty")
|
||||
{
|
||||
virtualDir->Foreach([&](std::string_view name, const Nz::VirtualDirectory::Entry& /*entry*/)
|
||||
{
|
||||
FAIL("There should be nothing here, got " << name);
|
||||
});
|
||||
}
|
||||
AND_WHEN("We try to retrieve a non-existing file, it fails")
|
||||
{
|
||||
CHECK_FALSE(virtualDir->GetEntry("File.bin", [](const Nz::VirtualDirectory::Entry& /*entry*/)
|
||||
{
|
||||
return true;
|
||||
}));
|
||||
|
||||
CHECK_FALSE(virtualDir->GetEntry("Foo/File.bin", [](const Nz::VirtualDirectory::Entry& /*entry*/)
|
||||
{
|
||||
return true;
|
||||
}));
|
||||
|
||||
CHECK_FALSE(virtualDir->GetEntry("Foo/Bar/File.bin", [](const Nz::VirtualDirectory::Entry& /*entry*/)
|
||||
{
|
||||
return true;
|
||||
}));
|
||||
|
||||
virtualDir->StoreDirectory("Foo/Bar", std::make_shared<Nz::VirtualDirectory>());
|
||||
|
||||
CHECK(virtualDir->GetEntry("Foo", [](const Nz::VirtualDirectory::Entry& entry)
|
||||
{
|
||||
return std::holds_alternative<Nz::VirtualDirectory::VirtualDirectoryEntry>(entry);
|
||||
}));
|
||||
|
||||
CHECK(virtualDir->GetEntry("Foo/Bar", [](const Nz::VirtualDirectory::Entry& entry)
|
||||
{
|
||||
return std::holds_alternative<Nz::VirtualDirectory::VirtualDirectoryEntry>(entry);
|
||||
}));
|
||||
|
||||
CHECK_FALSE(virtualDir->GetEntry("Foo/Bar/File.bin", [](const Nz::VirtualDirectory::Entry& /*entry*/)
|
||||
{
|
||||
return true;
|
||||
}));
|
||||
}
|
||||
|
||||
std::mt19937 randGen(std::random_device{}());
|
||||
auto GenerateRandomData = [&]
|
||||
{
|
||||
std::vector<Nz::UInt8> randomData;
|
||||
for (std::size_t i = 0; i < 256; ++i)
|
||||
{
|
||||
unsigned int data = randGen();
|
||||
randomData.push_back(Nz::SafeCast<Nz::UInt8>((data & 0x000000FF) >> 0));
|
||||
randomData.push_back(Nz::SafeCast<Nz::UInt8>((data & 0x0000FF00) >> 8));
|
||||
randomData.push_back(Nz::SafeCast<Nz::UInt8>((data & 0x00FF0000) >> 16));
|
||||
randomData.push_back(Nz::SafeCast<Nz::UInt8>((data & 0xFF000000) >> 24));
|
||||
}
|
||||
|
||||
return randomData;
|
||||
};
|
||||
|
||||
auto CheckFile = [&](std::string_view path, const std::vector<Nz::UInt8>& expectedData)
|
||||
{
|
||||
return virtualDir->GetEntry(path, [&](const Nz::VirtualDirectory::Entry& entry)
|
||||
{
|
||||
if (!std::holds_alternative<Nz::VirtualDirectory::FileContentEntry>(entry))
|
||||
{
|
||||
FAIL("Target is not a file");
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& contentEntry = std::get<Nz::VirtualDirectory::FileContentEntry>(entry);
|
||||
return std::equal(expectedData.begin(), expectedData.end(), contentEntry.data.begin(), contentEntry.data.end());
|
||||
});
|
||||
};
|
||||
|
||||
auto CheckFileContent = [&](std::string_view path, const std::vector<Nz::UInt8>& expectedData)
|
||||
{
|
||||
return virtualDir->GetFileContent(path, [&](const void* data, std::size_t size)
|
||||
{
|
||||
if (expectedData.size() != size)
|
||||
{
|
||||
FAIL("size doesn't match");
|
||||
return false;
|
||||
}
|
||||
|
||||
return std::memcmp(expectedData.data(), data, expectedData.size()) == 0;
|
||||
});
|
||||
};
|
||||
|
||||
WHEN("Storing a file")
|
||||
{
|
||||
auto randomData = GenerateRandomData();
|
||||
virtualDir->StoreFile("File.bin", randomData);
|
||||
|
||||
WHEN("We retrieve it")
|
||||
{
|
||||
CHECK(CheckFile("File.bin", randomData));
|
||||
CHECK(CheckFileContent("File.bin", randomData));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("Storing multiples files")
|
||||
{
|
||||
std::array paths = {
|
||||
"Abc",
|
||||
"Ab/cd",
|
||||
"po/mme\\de/terre.o",
|
||||
"Nazara",
|
||||
"Engine.exe",
|
||||
"Un/Deux/Trois",
|
||||
"Gnocchi.fromage",
|
||||
"Karmeliet.triple",
|
||||
"Mogwai.gremlins"
|
||||
};
|
||||
|
||||
struct File
|
||||
{
|
||||
std::string path;
|
||||
std::vector<Nz::UInt8> data;
|
||||
};
|
||||
|
||||
std::vector<File> files;
|
||||
std::unordered_map<std::string, std::size_t> filePathToIndex;
|
||||
|
||||
for (const char* path : paths)
|
||||
{
|
||||
auto& file = files.emplace_back();
|
||||
file.data = GenerateRandomData();
|
||||
file.path = path;
|
||||
|
||||
filePathToIndex[file.path] = files.size() - 1;
|
||||
}
|
||||
|
||||
// Insert files into the virtual directory
|
||||
for (const File& file : files)
|
||||
{
|
||||
INFO("Storing " << file.path);
|
||||
CHECK_NOTHROW(virtualDir->StoreFile(file.path, file.data));
|
||||
}
|
||||
|
||||
// Try to retrieve them
|
||||
for (const File& file : files)
|
||||
{
|
||||
INFO("Retrieving " << file.path);
|
||||
CHECK(CheckFile(file.path, file.data));
|
||||
INFO("Retrieving " << file.path << " using GetFileContent");
|
||||
CHECK(CheckFileContent(file.path, file.data));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Accessing filesystem using a VirtualDirectory")
|
||||
{
|
||||
std::shared_ptr<Nz::VirtualDirectory> resourceDir = std::make_shared<Nz::VirtualDirectory>(GetAssetDir());
|
||||
|
||||
WHEN("Iterating, it's not empty")
|
||||
{
|
||||
bool empty = true;
|
||||
resourceDir->Foreach([&](std::string_view name, const Nz::VirtualDirectory::Entry& entry)
|
||||
{
|
||||
CHECK_FALSE(name == ".");
|
||||
CHECK_FALSE(name == "..");
|
||||
|
||||
INFO("Only physical files and directories are expected");
|
||||
CHECK((std::holds_alternative<Nz::VirtualDirectory::PhysicalDirectoryEntry>(entry) || std::holds_alternative<Nz::VirtualDirectory::PhysicalFileEntry>(entry)));
|
||||
empty = false;
|
||||
});
|
||||
|
||||
REQUIRE_FALSE(empty);
|
||||
}
|
||||
|
||||
auto CheckFileHash = [](const Nz::VirtualDirectoryPtr& dir, const char* filepath, const char* expectedHash)
|
||||
{
|
||||
return dir->GetEntry(filepath, [&](const Nz::VirtualDirectory::Entry& entry)
|
||||
{
|
||||
REQUIRE(std::holds_alternative<Nz::VirtualDirectory::PhysicalFileEntry>(entry));
|
||||
|
||||
const auto& physFileEntry = std::get<Nz::VirtualDirectory::PhysicalFileEntry>(entry);
|
||||
|
||||
Nz::File file(physFileEntry.filePath);
|
||||
|
||||
Nz::SHA256Hash hash;
|
||||
WHEN("We compute " << hash.GetHashName() << " of " << physFileEntry.filePath << " file")
|
||||
{
|
||||
CHECK(Nz::ToUpper(Nz::ComputeHash(hash, file).ToHex()) == expectedHash);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
auto CheckFileContentHash = [](const Nz::VirtualDirectoryPtr& dir, const char* filepath, const char* expectedHash)
|
||||
{
|
||||
return dir->GetFileContent(filepath, [&](const void* data, std::size_t size)
|
||||
{
|
||||
Nz::SHA256Hash hash;
|
||||
WHEN("We compute " << hash.GetHashName() << " of " << filepath << " file")
|
||||
{
|
||||
hash.Begin();
|
||||
hash.Append(static_cast<const Nz::UInt8*>(data), size);
|
||||
CHECK(Nz::ToUpper(hash.End().ToHex()) == expectedHash);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
WHEN("Accessing files")
|
||||
{
|
||||
CHECK(CheckFileHash(resourceDir, "Logo.png", "5C4B9387327C039A6CE9ED51983D6C2ADA9F9DD01D024C2D5D588237ADFC7423"));
|
||||
CHECK(CheckFileHash(resourceDir, "./Logo.png", "5C4B9387327C039A6CE9ED51983D6C2ADA9F9DD01D024C2D5D588237ADFC7423"));
|
||||
CHECK(CheckFileHash(resourceDir, "Audio/The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||
CHECK(CheckFileHash(resourceDir, "Audio/./The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||
CHECK_FALSE(CheckFileHash(resourceDir, "The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||
CHECK_FALSE(CheckFileHash(resourceDir, "The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||
CHECK_FALSE(CheckFileHash(resourceDir, "Audio/../The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||
|
||||
// We can't escape the virtual directory
|
||||
CHECK(CheckFileHash(resourceDir, "../Logo.png", "5C4B9387327C039A6CE9ED51983D6C2ADA9F9DD01D024C2D5D588237ADFC7423"));
|
||||
CHECK(CheckFileHash(resourceDir, "../../Logo.png", "5C4B9387327C039A6CE9ED51983D6C2ADA9F9DD01D024C2D5D588237ADFC7423"));
|
||||
CHECK(CheckFileHash(resourceDir, "../../Audio/The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||
CHECK(CheckFileHash(resourceDir, ".././Audio/The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||
CHECK_FALSE(CheckFileHash(resourceDir, "../Tests/Audio/The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||
|
||||
auto CheckOurselves = [&](const auto& entry)
|
||||
{
|
||||
REQUIRE(std::holds_alternative<Nz::VirtualDirectory::VirtualDirectoryEntry>(entry));
|
||||
const auto& dirEntry = std::get<Nz::VirtualDirectory::VirtualDirectoryEntry>(entry);
|
||||
return dirEntry.directory == resourceDir;
|
||||
};
|
||||
|
||||
CHECK(resourceDir->GetEntry("..", CheckOurselves));
|
||||
CHECK(resourceDir->GetEntry("../..", CheckOurselves));
|
||||
CHECK(resourceDir->GetEntry("./..", CheckOurselves));
|
||||
CHECK(resourceDir->GetEntry("./..", CheckOurselves));
|
||||
CHECK(resourceDir->GetEntry("Audio/../..", CheckOurselves));
|
||||
CHECK(resourceDir->GetEntry("Core/../Audio/../../..", CheckOurselves));
|
||||
}
|
||||
AND_THEN("Overriding the physical file with another one")
|
||||
{
|
||||
resourceDir->StoreFile("Logo.png", GetAssetDir() / "Audio/ambience.ogg");
|
||||
|
||||
CHECK(CheckFileHash(resourceDir, "Audio/ambience.ogg", "49C486F44E43F023D54C9F375D902C21375DDB2748D3FA1863C9581D30E17F94"));
|
||||
CHECK(CheckFileHash(resourceDir, "Logo.png", "49C486F44E43F023D54C9F375D902C21375DDB2748D3FA1863C9581D30E17F94"));
|
||||
CHECK(CheckFileContentHash(resourceDir, "Audio/ambience.ogg", "49C486F44E43F023D54C9F375D902C21375DDB2748D3FA1863C9581D30E17F94"));
|
||||
CHECK(CheckFileContentHash(resourceDir, "Logo.png", "49C486F44E43F023D54C9F375D902C21375DDB2748D3FA1863C9581D30E17F94"));
|
||||
}
|
||||
|
||||
WHEN("Accessing physical folder as a virtual folder")
|
||||
{
|
||||
CHECK(resourceDir->GetDirectoryEntry("Utility", [&](const Nz::VirtualDirectory::DirectoryEntry& directoryEntry)
|
||||
{
|
||||
bool found = false;
|
||||
directoryEntry.directory->Foreach([&](std::string_view entryName, const Nz::VirtualDirectory::Entry& entry)
|
||||
{
|
||||
if (entryName == "GIF")
|
||||
{
|
||||
CHECK(std::holds_alternative<Nz::VirtualDirectory::PhysicalDirectoryEntry>(entry));
|
||||
found = true;
|
||||
}
|
||||
});
|
||||
|
||||
return found;
|
||||
}));
|
||||
}
|
||||
|
||||
WHEN("Testing uproot escape")
|
||||
{
|
||||
std::shared_ptr<Nz::VirtualDirectory> engineDir = std::make_shared<Nz::VirtualDirectory>(GetAssetDir() / "Audio");
|
||||
|
||||
CHECK_FALSE(engineDir->IsUprootAllowed());
|
||||
|
||||
// We can't escape the virtual directory
|
||||
CHECK_FALSE(engineDir->Exists("../Logo.png"));
|
||||
CHECK_FALSE(engineDir->Exists("../../Logo.png"));
|
||||
CHECK_FALSE(engineDir->Exists("../Tests/Audio/Audio/The_Brabanconne.ogg"));
|
||||
CHECK(CheckFileHash(engineDir, "../../The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||
CHECK(CheckFileHash(engineDir, ".././The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||
|
||||
engineDir->AllowUproot(true);
|
||||
CHECK(engineDir->IsUprootAllowed());
|
||||
|
||||
// Now we're able to access the asset folder beneath
|
||||
CHECK(CheckFileHash(engineDir, "../Logo.png", "5C4B9387327C039A6CE9ED51983D6C2ADA9F9DD01D024C2D5D588237ADFC7423"));
|
||||
CHECK(CheckFileHash(engineDir, "../Audio/The_Brabanconne.ogg", "E07706E0BEEC7770CDE36008826743AF9EEE5C80CA0BD83C37771CBC8B52E738"));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user