From 376b68f37f91752140406ea709116017598401fe Mon Sep 17 00:00:00 2001 From: SirLynix Date: Sun, 13 Oct 2024 16:16:55 +0200 Subject: [PATCH] Add nzsla tests --- .../modules/Archive/InstanceData.nzslb | Bin 0 -> 375 bytes bin/resources/modules/Archive/LightData.nzslb | Bin 0 -> 3410 bytes .../modules/Archive/SkeletalData.nzslb | Bin 0 -> 436 bytes .../modules/Archive/SkinningData.nzslb | Bin 0 -> 816 bytes .../modules/Archive/ViewerData.nzslb | Bin 0 -> 1198 bytes include/NZSL/Archive.hpp | 4 +- src/NZSL/Archive.cpp | 14 ++- src/ShaderArchiver/Archiver.cpp | 14 ++- tests/src/Tests/NzslaTests.cpp | 99 +++++++++++++++ tests/src/Tests/NzslcTests.cpp | 79 +----------- tests/src/Tests/ShaderUtils.cpp | 8 +- tests/src/Tests/ToolUtils.cpp | 118 ++++++++++++++++++ tests/src/Tests/ToolUtils.hpp | 12 ++ tests/xmake.lua | 12 ++ 14 files changed, 273 insertions(+), 87 deletions(-) create mode 100644 bin/resources/modules/Archive/InstanceData.nzslb create mode 100644 bin/resources/modules/Archive/LightData.nzslb create mode 100644 bin/resources/modules/Archive/SkeletalData.nzslb create mode 100644 bin/resources/modules/Archive/SkinningData.nzslb create mode 100644 bin/resources/modules/Archive/ViewerData.nzslb create mode 100644 tests/src/Tests/NzslaTests.cpp create mode 100644 tests/src/Tests/ToolUtils.cpp create mode 100644 tests/src/Tests/ToolUtils.hpp diff --git a/bin/resources/modules/Archive/InstanceData.nzslb b/bin/resources/modules/Archive/InstanceData.nzslb new file mode 100644 index 0000000000000000000000000000000000000000..893ff87db032a43b4ccbd42f11e164a942c65fd0 GIT binary patch literal 375 zcma)2y9xp^5KL6W7h2f*1s2IqC}^RD7S`cz(ZI0>Nj$}`cSk)qe1HS9vl-agB)ipq z+gD0Wg-bqqCbQ<49A~s}$>m~ygBEipgsK*rk(A~n%o^y2!b=&7eB)B^S6JZd&5Qbw4wA?p{`xLYs34B0+I3(19_&}?w`31&y+eN{SY^SaI>zQW{AF+c| zUTOShXJ_8stY>$<^<%hks@LmX6#EwMs5t8XR6D!*nxFfj_}Xw%oVUfim`OX=t?d?ex%_Vw4k`RRfqP2XStWeOl8|ZW} z6DOZPj3x}G)A7+~CD&Az`>|{ma+b_KBBY9Pby;BoVbCVz{Cg_e-%OL=>wcc9>HrIj zqDLaMigKXK;$|QiFwnFhev`rTifvIydLQ6K!lT?a6BXx;9l&`~R57s~JK&~-5C(%H zmj>HuoMejK)}h55Z;25GgK9c${_%g*KL--BFldv(->6@b{!#xdDIqXu(iL_XASDyI?tyLH5Y}Z! z9_EoW94F1H!Jx>c!6-*Lcex`GgF!7HN3{++CP(hF7-2A|rqgb# zKP}6{EF)nCrp@89B1QxZ+GOxI%23O;>vD8+e-i?OM!s_%rHo%l5~46@Eo16R#c`B= zjdw=+CYw>pl*dak6k$+LcAjLC&nNdvGLVA-a%D0eUgf;Iqc5?j!Jw9lgN3dg)(3>o zJoe4o;tm{$5ekE*5MCB&KS@WSzFFqc<_>%X9jZpX?MmG%V5_qnOO)p3NgPte{GvDjd{3wPp3}))kN!^qS(k0J1 n@<|MN7_=zhrud2_>C#2xvlzNCXbRvpf0O4I+j`sT9U5ZqYttrssIJcxSo(0+spBIrTCAZXBPNuf7Rz}DVEYy9)mM8@f8qn*A&{ud316F@a_41t4w@8i(Ab(~oTE_5glN4riGNFQK9 zK$KeH;`>2j(l|>lCJl6QxrZ;~OzMLASA6?PqdD9yU{+?O@;P84i&C4GS>@w7QDj+Z zWu_;uE>#r52$bFVfSK{rjbdTv$ue{A Hugc}WBW5q0 literal 0 HcmV?d00001 diff --git a/bin/resources/modules/Archive/SkinningData.nzslb b/bin/resources/modules/Archive/SkinningData.nzslb new file mode 100644 index 0000000000000000000000000000000000000000..d922ea73218f7e6929f9388737d661c0effc83b2 GIT binary patch literal 816 zcma))%}&EG5QH5Nlz$}t4@lfOBrgFHrxsCOASzL?C{C5Q9C&)>b5q4pL1Croc3H85b1po((z+s@epu(MD<5*7ziIoo*w*H)kZ`!g;!HnuK39$PwsMoDUo1Vx z1a*7DqCKT$gh&t&uOmtBwM^5jE}Cjt&x$6?>)E^gDtyuSEcTYV?`D3a>XES1vZ!|v z`Rb0f1(@n!pCs77(IU1#uIkTx-XDU({|%u+W3YBCa2ZU*?c}?H3s?R9BGj1!;Y2_T zCc0*_Zpza(I~0d0(GFAIX|XxwYwpUz`TnqcoY?JvKZd;!@COrdJ9+1KK#XB81;k*Y gYbN89`<3khEgs=YKno_KZqn}MuG@@1^X4uRKa@yc4gdfE literal 0 HcmV?d00001 diff --git a/bin/resources/modules/Archive/ViewerData.nzslb b/bin/resources/modules/Archive/ViewerData.nzslb new file mode 100644 index 0000000000000000000000000000000000000000..118d73249cdb882b0b316d7e310c641d196a5e0a GIT binary patch literal 1198 zcmb7@%}&EG5QH6y`2U9^55OsT36Qveq84$t(xn(x4st?(K0W)Ttx8EMl9ASvPQ0_* zwKKdQJ?R^py7ka zMtWvCo!w70=|}^27&MJgIj2SMy((O29{o}Q2CZJa;NXM!v4kfZCQ^>vOi0{iY1}i_ z=3aEn4j8oApf65**slV2hdEIJ1{<7s#UaVJq^?^DbDK2)wgV{Q(l$oLc|@ literal 0 HcmV?d00001 diff --git a/include/NZSL/Archive.hpp b/include/NZSL/Archive.hpp index 48d94ee..d218292 100644 --- a/include/NZSL/Archive.hpp +++ b/include/NZSL/Archive.hpp @@ -26,7 +26,7 @@ namespace nzsl enum class ArchiveEntryFlag { - CompressedLZ4HC, + CompressedLZ4HC = 0, Max = CompressedLZ4HC }; @@ -37,7 +37,7 @@ namespace nzsl enum class ArchiveEntryKind { - BinaryShaderModule + BinaryShaderModule = 0 }; class NZSL_API Archive diff --git a/src/NZSL/Archive.cpp b/src/NZSL/Archive.cpp index 0576673..d823918 100644 --- a/src/NZSL/Archive.cpp +++ b/src/NZSL/Archive.cpp @@ -132,6 +132,7 @@ namespace nzsl std::string moduleName; std::uint32_t offset; std::uint32_t size; + ArchiveEntryKind kind; ArchiveEntryFlags flags; }; @@ -140,12 +141,17 @@ namespace nzsl { auto& data = entries.emplace_back(); deserializer.Deserialize(data.moduleName); - deserializer.Deserialize(data.offset); - deserializer.Deserialize(data.size); + + std::uint32_t kind; + deserializer.Deserialize(kind); + data.kind = static_cast(kind); std::uint32_t flags; deserializer.Deserialize(flags); data.flags = ArchiveEntryFlags(Nz::SafeCast(flags)); + + deserializer.Deserialize(data.offset); + deserializer.Deserialize(data.size); } Archive archive; @@ -155,6 +161,7 @@ namespace nzsl Archive::ModuleData module; module.name = std::move(entry.moduleName); + module.kind = entry.kind; module.flags = entry.flags; module.data.resize(entry.size); @@ -178,9 +185,10 @@ namespace nzsl for (const auto& module : modules) { serializer.Serialize(module.name); + serializer.Serialize(std::uint32_t(module.kind)); + serializer.Serialize(std::uint32_t(module.flags)); moduleOffsets.push_back(serializer.Serialize(std::uint32_t(0))); // reserve space serializer.Serialize(Nz::SafeCast(module.data.size())); - serializer.Serialize(std::uint32_t(module.flags)); } auto offsetIt = moduleOffsets.begin(); diff --git a/src/ShaderArchiver/Archiver.cpp b/src/ShaderArchiver/Archiver.cpp index b6e8e5e..5c6a301 100644 --- a/src/ShaderArchiver/Archiver.cpp +++ b/src/ShaderArchiver/Archiver.cpp @@ -49,8 +49,9 @@ namespace nzsla { m_outputPath = Nz::Utf8Path(outputPath); - if (!std::filesystem::is_directory(m_outputPath) && !std::filesystem::create_directories(m_outputPath)) - throw std::runtime_error(fmt::format("failed to create {} directory", Nz::PathToString(m_outputPath))); + std::filesystem::path parentPath = m_outputPath.parent_path(); + if (!std::filesystem::is_directory(parentPath) && !std::filesystem::create_directories(parentPath)) + throw std::runtime_error(fmt::format("failed to create {} directory", Nz::PathToString(parentPath))); } } } @@ -162,6 +163,7 @@ namespace nzsla void Archiver::DoShow() { + bool first = true; for (const std::filesystem::path& filePath : m_inputFiles) { if (filePath.extension() != Nz::Utf8Path(".nzsla")) @@ -171,7 +173,13 @@ namespace nzsla nzsl::Deserializer deserializer(fileContent.data(), fileContent.size()); nzsl::Archive archive = nzsl::DeserializeArchive(deserializer); - fmt::print("archive info for {}\n", Nz::PathToString(filePath)); + + if (!first) + fmt::print("---\n"); + + first = false; + + fmt::print("archive info for {}\n\n", Nz::PathToString(filePath)); const auto& modules = archive.GetModules(); fmt::print("{} module(s) are stored in this archive:\n", modules.size()); diff --git a/tests/src/Tests/NzslaTests.cpp b/tests/src/Tests/NzslaTests.cpp new file mode 100644 index 0000000..1e408d6 --- /dev/null +++ b/tests/src/Tests/NzslaTests.cpp @@ -0,0 +1,99 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +TEST_CASE("Standalone archiver", "[NZSLA]") +{ + WHEN("Printing help") + { + ExecuteCommand("./nzsla -h", R"(Tool for managing NZSL shader archives)"); + } + + WHEN("Printing version") + { + ExecuteCommand("./nzsla --version", fmt::format(R"(nzsla version \d\.\d\.\d using nzsl {}\.{}\.{})", NZSL_VERSION_MAJOR, NZSL_VERSION_MINOR, NZSL_VERSION_PATCH)); + } + + WHEN("Compiling shader modules") + { + REQUIRE(std::filesystem::is_directory("../resources/modules/Archive")); + + auto Cleanup = [] + { + std::filesystem::remove_all("test_files"); + }; + + Cleanup(); + + Nz::CallOnExit cleanupOnExit(std::move(Cleanup)); + + // Archive each modules + ExecuteCommand("./nzsla --archive -o test_files/test_archive.nzsla ../resources/modules/Archive/InstanceData.nzslb ../resources/modules/Archive/LightData.nzslb ../resources/modules/Archive/SkeletalData.nzslb ../resources/modules/Archive/SkinningData.nzslb ../resources/modules/Archive/ViewerData.nzslb"); + ExecuteCommand("./nzsla test_files/test_archive.nzsla", {}, R"(archive info for test_files/test_archive.nzsla + +5 module(s) are stored in this archive: +module name: Engine.InstanceData +- kind: BinaryShaderModule +- flags: +- size: 375 +module name: Engine.LightData +- kind: BinaryShaderModule +- flags: +- size: 3410 +module name: Engine.SkeletalData +- kind: BinaryShaderModule +- flags: +- size: 436 +module name: Engine.SkinningData +- kind: BinaryShaderModule +- flags: +- size: 816 +module name: Engine.ViewerData +- kind: BinaryShaderModule +- flags: +- size: 1198)"); + + // Archive and compress + ExecuteCommand("./nzsla --archive --compress -o test_files/test_archive.nzsla ../resources/modules/Archive/InstanceData.nzslb ../resources/modules/Archive/LightData.nzslb ../resources/modules/Archive/SkeletalData.nzslb ../resources/modules/Archive/SkinningData.nzslb ../resources/modules/Archive/ViewerData.nzslb"); + ExecuteCommand("./nzsla test_files/test_archive.nzsla", {}, R"(archive info for test_files/test_archive.nzsla + +5 module(s) are stored in this archive: +module name: Engine.InstanceData +- kind: BinaryShaderModule +- flags: CompressedLZ4HC +- size: 211 +module name: Engine.LightData +- kind: BinaryShaderModule +- flags: CompressedLZ4HC +- size: 1064 +module name: Engine.SkeletalData +- kind: BinaryShaderModule +- flags: CompressedLZ4HC +- size: 267 +module name: Engine.SkinningData +- kind: BinaryShaderModule +- flags: CompressedLZ4HC +- size: 333 +module name: Engine.ViewerData +- kind: BinaryShaderModule +- flags: CompressedLZ4HC +- size: 459)"); + + // Register each module + nzsl::FilesystemModuleResolver moduleResolver; + moduleResolver.RegisterFile(Nz::Utf8Path("test_files/test_archive.nzsla")); + + CHECK(moduleResolver.Resolve("Engine.InstanceData")); + CHECK(moduleResolver.Resolve("Engine.LightData")); + CHECK(moduleResolver.Resolve("Engine.SkeletalData")); + CHECK(moduleResolver.Resolve("Engine.SkinningData")); + CHECK(moduleResolver.Resolve("Engine.ViewerData")); + CHECK_FALSE(moduleResolver.Resolve("NonExistent")); + } +} diff --git a/tests/src/Tests/NzslcTests.cpp b/tests/src/Tests/NzslcTests.cpp index d292527..383ab51 100644 --- a/tests/src/Tests/NzslcTests.cpp +++ b/tests/src/Tests/NzslcTests.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -11,84 +12,6 @@ #include #include -void CheckHeaderMatch(const std::filesystem::path& originalFilepath) -{ - std::ifstream originalFile(originalFilepath, std::ios::in | std::ios::binary); - REQUIRE(originalFile); - - originalFile.seekg(0, std::ios::end); - - std::streamsize length = originalFile.tellg(); - REQUIRE(length > 0); - if (length == 0) - return; //< ignore empty files - - originalFile.seekg(0, std::ios::beg); - - std::vector originalContent(Nz::SafeCast(length)); - REQUIRE(originalFile.read(&originalContent[0], length)); - - std::filesystem::path headerFilepath = originalFilepath; - headerFilepath.concat(".h"); - - std::ifstream headerFile(headerFilepath, std::ios::in); - REQUIRE(headerFile); - - std::vector content; - - for (std::size_t i = 0; i < originalContent.size(); ++i) - { - std::uint8_t referenceValue = static_cast(originalContent[i]); - - unsigned int value; - headerFile >> value; - - if (value != referenceValue) - REQUIRE(value == referenceValue); - - char sep; - headerFile >> sep; - - if (sep != ',') - REQUIRE(sep == ','); - } - - CHECK(headerFile.eof()); -} - -void ExecuteCommand(const std::string& command, const std::string& pattern = {}) -{ - std::string output; - auto ReadStdout = [&](const char* str, std::size_t size) - { - output.append(str, size); - }; - - std::string errOutput; - auto ReadStderr = [&](const char* str, std::size_t size) - { - errOutput.append(str, size); - }; - - TinyProcessLib::Process compiler(command, {}, ReadStdout, ReadStderr); - int exitCode = compiler.get_exit_status(); - if (exitCode != 0) - { - INFO("Command-line: " << command << "\nstdout: " << output << "\nstderr: " << errOutput); - REQUIRE(exitCode == 0); - } - - if (!pattern.empty()) - { - INFO("Full output: " << output); - // matcher doesn't like multilines, keep only the first one - if (std::size_t i = output.find_first_of("\r\n"); i != output.npos) - output.resize(i); - - CHECK_THAT(output, Catch::Matchers::Matches(pattern)); - } -} - TEST_CASE("Standalone compiler", "[NZSLC]") { WHEN("Printing help") diff --git a/tests/src/Tests/ShaderUtils.cpp b/tests/src/Tests/ShaderUtils.cpp index 42d1964..4f2b10f 100644 --- a/tests/src/Tests/ShaderUtils.cpp +++ b/tests/src/Tests/ShaderUtils.cpp @@ -12,7 +12,7 @@ #include #include -namespace +namespace NAZARA_ANONYMOUS_NAMESPACE { // Use OpenGL default minimal values (from https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glGet.xhtml, https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glGet.xhtml and https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/) const TBuiltInResource s_minResources = { @@ -218,6 +218,8 @@ namespace void ExpectGLSL(nzsl::ShaderStageType stageType, const nzsl::Ast::Module& shaderModule, std::string_view expectedOutput, const nzsl::ShaderWriter::States& options, const nzsl::GlslWriter::Environment& env, bool testShaderCompilation) { + NAZARA_USE_ANONYMOUS_NAMESPACE + std::string expectedSource = SanitizeSource(expectedOutput); std::string_view stageName; @@ -319,6 +321,8 @@ void ExpectGLSL(const nzsl::Ast::Module& shaderModule, std::string_view expected void ExpectNZSL(const nzsl::Ast::Module& shaderModule, std::string_view expectedOutput, const nzsl::ShaderWriter::States& options) { + NAZARA_USE_ANONYMOUS_NAMESPACE + std::string source = SanitizeSource(expectedOutput); SECTION("Generating NZSL") @@ -349,6 +353,8 @@ void ExpectNZSL(const nzsl::Ast::Module& shaderModule, std::string_view expected void ExpectSPIRV(const nzsl::Ast::Module& shaderModule, std::string_view expectedOutput, const nzsl::ShaderWriter::States& options, const nzsl::SpirvWriter::Environment& env, bool outputParameter) { + NAZARA_USE_ANONYMOUS_NAMESPACE + std::string source = SanitizeSource(expectedOutput); SECTION("Generating SPIR-V") diff --git a/tests/src/Tests/ToolUtils.cpp b/tests/src/Tests/ToolUtils.cpp new file mode 100644 index 0000000..09500a9 --- /dev/null +++ b/tests/src/Tests/ToolUtils.cpp @@ -0,0 +1,118 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace NAZARA_ANONYMOUS_NAMESPACE +{ + std::string& ReplaceStr(std::string& str, const std::string_view& from, const std::string_view& to) + { + if (str.empty()) + return str; + + std::size_t startPos = 0; + while ((startPos = str.find(from, startPos)) != std::string::npos) + { + str.replace(startPos, from.length(), to); + startPos += to.length(); + } + + return str; + } +} + +void CheckHeaderMatch(const std::filesystem::path& originalFilepath) +{ + std::ifstream originalFile(originalFilepath, std::ios::in | std::ios::binary); + REQUIRE(originalFile); + + originalFile.seekg(0, std::ios::end); + + std::streamsize length = originalFile.tellg(); + REQUIRE(length > 0); + if (length == 0) + return; //< ignore empty files + + originalFile.seekg(0, std::ios::beg); + + std::vector originalContent(Nz::SafeCast(length)); + REQUIRE(originalFile.read(&originalContent[0], length)); + + std::filesystem::path headerFilepath = originalFilepath; + headerFilepath.concat(".h"); + + std::ifstream headerFile(headerFilepath, std::ios::in); + REQUIRE(headerFile); + + for (std::size_t i = 0; i < originalContent.size(); ++i) + { + std::uint8_t referenceValue = static_cast(originalContent[i]); + + unsigned int value; + headerFile >> value; + + if (value != referenceValue) + REQUIRE(value == referenceValue); + + char sep; + headerFile >> sep; + + if (sep != ',') + REQUIRE(sep == ','); + } + + CHECK(headerFile.eof()); +} + +void ExecuteCommand(const std::string& command, const std::string& pattern, std::string expectedOutput) +{ + NAZARA_USE_ANONYMOUS_NAMESPACE + + std::string output; + auto ReadStdout = [&](const char* str, std::size_t size) + { + output.append(str, size); + }; + + std::string errOutput; + auto ReadStderr = [&](const char* str, std::size_t size) + { + errOutput.append(str, size); + }; + + TinyProcessLib::Process compiler(command, {}, ReadStdout, ReadStderr); + int exitCode = compiler.get_exit_status(); + if (exitCode != 0) + { + INFO("Command-line: " << command << "\nstdout: " << output << "\nstderr: " << errOutput); + REQUIRE(exitCode == 0); + } + + if (!pattern.empty()) + { + INFO("Full output: " << output); + // matcher doesn't like multilines, keep only the first one + if (std::size_t i = output.find_first_of("\r\n"); i != output.npos) + output.resize(i); + + CHECK_THAT(output, Catch::Matchers::Matches(pattern)); + } + else if (!expectedOutput.empty()) + { + ReplaceStr(output, "\r\n", "\n"); + ReplaceStr(expectedOutput, "\r\n", "\n"); + + while (!output.empty() && output.back() == '\n') + output.pop_back(); + + CHECK(output == expectedOutput); + } +} diff --git a/tests/src/Tests/ToolUtils.hpp b/tests/src/Tests/ToolUtils.hpp new file mode 100644 index 0000000..2739ed3 --- /dev/null +++ b/tests/src/Tests/ToolUtils.hpp @@ -0,0 +1,12 @@ +#pragma once + +#ifndef NAZARA_UNITTESTS_TOOLS_TOOLUTILS_HPP +#define NAZARA_UNITTESTS_TOOLS_TOOLUTILS_HPP + +#include +#include + +void CheckHeaderMatch(const std::filesystem::path& originalFilepath); +void ExecuteCommand(const std::string& command, const std::string& pattern = {}, std::string expectedOutput = {}); + +#endif diff --git a/tests/xmake.lua b/tests/xmake.lua index 4084e53..e9e6897 100644 --- a/tests/xmake.lua +++ b/tests/xmake.lua @@ -27,5 +27,17 @@ if has_config("tests") then else remove_files("src/Tests/NzslcTests.cpp") end + + if has_config("with_nzsla") then + add_deps("nzsla", { links = {} }) + add_packages("fmt", "tiny-process-library") + else + remove_files("src/Tests/NzslaTests.cpp") + end + + if not has_config("with_nzsla", "with_nzslc") then + remove_headerfiles("src/Tests/ToolTests.hpp") + remove_files("src/Tests/ToolTests.cpp") + end end) end