Files
video-shader-toys/tests/ShaderCompilerLookupTests.cpp
Aiden fbc2851ccb
All checks were successful
CI / React UI Build (push) Successful in 12s
CI / Native Windows Build And Tests (push) Successful in 2m21s
CI / Windows Release Package (push) Has been skipped
Slang seperation
2026-05-30 21:05:30 +10:00

204 lines
6.3 KiB
C++

#include "ShaderCompiler.h"
#include <cstdlib>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <string>
namespace
{
int gFailures = 0;
void Expect(bool condition, const std::string& message)
{
if (condition)
return;
++gFailures;
std::cerr << "FAIL: " << message << "\n";
}
std::filesystem::path MakeTestRoot(const std::string& name)
{
const std::filesystem::path root =
std::filesystem::temp_directory_path() /
("shader-compiler-lookup-" + name + "-" + std::to_string(std::filesystem::file_time_type::clock::now().time_since_epoch().count()));
std::filesystem::create_directories(root);
return root;
}
void WriteFakeSlangCompiler(const std::filesystem::path& path)
{
std::filesystem::create_directories(path.parent_path());
std::ofstream output(path, std::ios::binary);
output << "not a real compiler";
}
std::string ReadEnvironmentVariable(const char* name)
{
#if defined(_MSC_VER)
char* value = nullptr;
std::size_t size = 0;
if (_dupenv_s(&value, &size, name) != 0 || value == nullptr)
return std::string();
std::string text(value);
std::free(value);
return text;
#else
const char* value = std::getenv(name);
return value ? std::string(value) : std::string();
#endif
}
void WriteEnvironmentVariable(const char* name, const std::string& value)
{
#if defined(_MSC_VER)
_putenv_s(name, value.c_str());
#else
if (value.empty())
unsetenv(name);
else
setenv(name, value.c_str(), 1);
#endif
}
class ScopedEnvironmentVariable
{
public:
ScopedEnvironmentVariable(const char* name, const std::string& value) :
mName(name),
mOriginal(ReadEnvironmentVariable(name))
{
WriteEnvironmentVariable(name, value);
}
~ScopedEnvironmentVariable()
{
WriteEnvironmentVariable(mName.c_str(), mOriginal);
}
ScopedEnvironmentVariable(const ScopedEnvironmentVariable&) = delete;
ScopedEnvironmentVariable& operator=(const ScopedEnvironmentVariable&) = delete;
private:
std::string mName;
std::string mOriginal;
};
bool SamePath(const std::filesystem::path& left, const std::filesystem::path& right)
{
std::error_code leftError;
std::error_code rightError;
return std::filesystem::weakly_canonical(left, leftError) == std::filesystem::weakly_canonical(right, rightError);
}
void TestSlangRootWinsOverThirdPartyRoot()
{
const std::filesystem::path root = MakeTestRoot("slang-root");
const std::filesystem::path expected = root / "env-slang" / "bin" / "slangc.exe";
const std::filesystem::path thirdPartyCompiler = root / "third-party" / "slang-2026.8-windows-x86_64" / "bin" / "slangc.exe";
WriteFakeSlangCompiler(expected);
WriteFakeSlangCompiler(thirdPartyCompiler);
ScopedEnvironmentVariable slangRoot("SLANG_ROOT", (root / "env-slang").string());
ScopedEnvironmentVariable thirdPartyRoot("THIRD_PARTY_ROOT", (root / "third-party").string());
std::filesystem::path actual;
std::string error;
Expect(ShaderCompiler::FindSlangCompilerPath(root, actual, error), "SLANG_ROOT compiler is found");
Expect(SamePath(actual, expected), "SLANG_ROOT has priority over THIRD_PARTY_ROOT");
std::filesystem::remove_all(root);
}
void TestThirdPartyRootUsesCMakeBundleLayout()
{
const std::filesystem::path root = MakeTestRoot("third-party-root");
const std::filesystem::path thirdPartyRootPath = root / "video-io-3rdParty";
const std::filesystem::path expected = thirdPartyRootPath / "slang-2026.8-windows-x86_64" / "bin" / "slangc.exe";
WriteFakeSlangCompiler(expected);
ScopedEnvironmentVariable slangRoot("SLANG_ROOT", "");
ScopedEnvironmentVariable thirdPartyRoot("THIRD_PARTY_ROOT", thirdPartyRootPath.string());
std::filesystem::path actual;
std::string error;
Expect(ShaderCompiler::FindSlangCompilerPath(root, actual, error), "THIRD_PARTY_ROOT compiler is found");
Expect(SamePath(actual, expected), "THIRD_PARTY_ROOT matches CMake's Slang bundle layout");
std::filesystem::remove_all(root);
}
void TestRepoVideoIoBundleWinsOverLegacyRepoBundle()
{
const std::filesystem::path root = MakeTestRoot("repo-video-io");
const std::filesystem::path expected = root / "video-io-3rdParty" / "slang-2026.8-windows-x86_64" / "bin" / "slangc.exe";
const std::filesystem::path legacy = root / "3rdParty" / "slang-2026.8-windows-x86_64" / "bin" / "slangc.exe";
WriteFakeSlangCompiler(expected);
WriteFakeSlangCompiler(legacy);
ScopedEnvironmentVariable slangRoot("SLANG_ROOT", "");
ScopedEnvironmentVariable thirdPartyRoot("THIRD_PARTY_ROOT", "");
std::filesystem::path actual;
std::string error;
Expect(ShaderCompiler::FindSlangCompilerPath(root, actual, error), "repo video-io-3rdParty compiler is found");
Expect(SamePath(actual, expected), "repo video-io-3rdParty has priority over repo 3rdParty");
std::filesystem::remove_all(root);
}
void TestPackagedSlangFolderIsAccepted()
{
const std::filesystem::path root = MakeTestRoot("packaged");
const std::filesystem::path expected = root / "3rdParty" / "slang" / "bin" / "slangc.exe";
WriteFakeSlangCompiler(expected);
ScopedEnvironmentVariable slangRoot("SLANG_ROOT", "");
ScopedEnvironmentVariable thirdPartyRoot("THIRD_PARTY_ROOT", "");
std::filesystem::path actual;
std::string error;
Expect(ShaderCompiler::FindSlangCompilerPath(root, actual, error), "packaged 3rdParty/slang compiler is found");
Expect(SamePath(actual, expected), "packaged Slang install layout is accepted");
std::filesystem::remove_all(root);
}
void TestLegacyThirdPartyScanStillAcceptsVersionedFolders()
{
const std::filesystem::path root = MakeTestRoot("legacy-scan");
const std::filesystem::path expected = root / "3rdParty" / "slang-custom-build" / "bin" / "slangc.exe";
WriteFakeSlangCompiler(expected);
ScopedEnvironmentVariable slangRoot("SLANG_ROOT", "");
ScopedEnvironmentVariable thirdPartyRoot("THIRD_PARTY_ROOT", "");
std::filesystem::path actual;
std::string error;
Expect(ShaderCompiler::FindSlangCompilerPath(root, actual, error), "legacy 3rdParty scan finds versioned Slang folders");
Expect(SamePath(actual, expected), "legacy scan returns the discovered compiler path");
std::filesystem::remove_all(root);
}
}
int main()
{
TestSlangRootWinsOverThirdPartyRoot();
TestThirdPartyRootUsesCMakeBundleLayout();
TestRepoVideoIoBundleWinsOverLegacyRepoBundle();
TestPackagedSlangFolderIsAccepted();
TestLegacyThirdPartyScanStillAcceptsVersionedFolders();
if (gFailures != 0)
{
std::cerr << gFailures << " ShaderCompiler lookup test failure(s).\n";
return 1;
}
std::cout << "ShaderCompiler lookup tests passed.\n";
return 0;
}