refactor
This commit is contained in:
120
tests/RuntimeParameterUtilsTests.cpp
Normal file
120
tests/RuntimeParameterUtilsTests.cpp
Normal file
@@ -0,0 +1,120 @@
|
||||
#include "RuntimeParameterUtils.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
namespace
|
||||
{
|
||||
int gFailures = 0;
|
||||
|
||||
void Expect(bool condition, const char* message)
|
||||
{
|
||||
if (condition)
|
||||
return;
|
||||
|
||||
std::cerr << "FAIL: " << message << "\n";
|
||||
++gFailures;
|
||||
}
|
||||
|
||||
ShaderParameterDefinition MakeFloatDefinition()
|
||||
{
|
||||
ShaderParameterDefinition definition;
|
||||
definition.id = "gain";
|
||||
definition.type = ShaderParameterType::Float;
|
||||
definition.defaultNumbers = { 0.5 };
|
||||
definition.minNumbers = { 0.0 };
|
||||
definition.maxNumbers = { 1.0 };
|
||||
return definition;
|
||||
}
|
||||
|
||||
void TestSafePresetFileStems()
|
||||
{
|
||||
Expect(MakeSafePresetFileStem(" Show Look 01 ") == "show-look-01", "preset names are trimmed and dashed");
|
||||
Expect(MakeSafePresetFileStem("A__B---C") == "a-b-c", "duplicate separators collapse");
|
||||
Expect(MakeSafePresetFileStem("../Unsafe Name!") == "unsafe-name", "unsafe punctuation is dropped");
|
||||
Expect(MakeSafePresetFileStem("!!!") == "", "names without alphanumeric characters become empty");
|
||||
}
|
||||
|
||||
void TestFloatNormalization()
|
||||
{
|
||||
ShaderParameterDefinition definition = MakeFloatDefinition();
|
||||
ShaderParameterValue value;
|
||||
std::string error;
|
||||
|
||||
Expect(NormalizeAndValidateParameterValue(definition, JsonValue(2.0), value, error), "float parameter accepts numeric values");
|
||||
Expect(value.numberValues.size() == 1 && value.numberValues.front() == 1.0, "float parameter clamps to max");
|
||||
|
||||
error.clear();
|
||||
Expect(NormalizeAndValidateParameterValue(definition, JsonValue(-10.0), value, error), "float parameter accepts low numeric values");
|
||||
Expect(value.numberValues.size() == 1 && value.numberValues.front() == 0.0, "float parameter clamps to min");
|
||||
|
||||
error.clear();
|
||||
Expect(!NormalizeAndValidateParameterValue(definition, JsonValue("bad"), value, error), "float parameter rejects non-numeric values");
|
||||
Expect(!error.empty(), "float rejection includes an error");
|
||||
}
|
||||
|
||||
void TestVectorNormalization()
|
||||
{
|
||||
ShaderParameterDefinition definition;
|
||||
definition.id = "offset";
|
||||
definition.type = ShaderParameterType::Vec2;
|
||||
definition.defaultNumbers = { 0.0, 0.0 };
|
||||
definition.minNumbers = { -1.0, -2.0 };
|
||||
definition.maxNumbers = { 1.0, 2.0 };
|
||||
|
||||
JsonValue input = JsonValue::MakeArray();
|
||||
input.pushBack(JsonValue(5.0));
|
||||
input.pushBack(JsonValue(-5.0));
|
||||
|
||||
ShaderParameterValue value;
|
||||
std::string error;
|
||||
Expect(NormalizeAndValidateParameterValue(definition, input, value, error), "vec2 parameter accepts arrays");
|
||||
Expect(value.numberValues.size() == 2 && value.numberValues[0] == 1.0 && value.numberValues[1] == -2.0, "vec2 parameter clamps each component");
|
||||
|
||||
JsonValue shortInput = JsonValue::MakeArray();
|
||||
shortInput.pushBack(JsonValue(0.0));
|
||||
error.clear();
|
||||
Expect(!NormalizeAndValidateParameterValue(definition, shortInput, value, error), "vec2 parameter rejects wrong component count");
|
||||
}
|
||||
|
||||
void TestEnumAndDefaults()
|
||||
{
|
||||
ShaderParameterDefinition definition;
|
||||
definition.id = "mode";
|
||||
definition.type = ShaderParameterType::Enum;
|
||||
definition.defaultEnumValue = "soft";
|
||||
definition.enumOptions = {
|
||||
{ "soft", "Soft" },
|
||||
{ "hard", "Hard" }
|
||||
};
|
||||
|
||||
ShaderParameterValue defaultValue = DefaultValueForDefinition(definition);
|
||||
Expect(defaultValue.enumValue == "soft", "enum default is copied from definition");
|
||||
|
||||
ShaderParameterValue value;
|
||||
std::string error;
|
||||
Expect(NormalizeAndValidateParameterValue(definition, JsonValue("hard"), value, error), "enum accepts listed options");
|
||||
Expect(value.enumValue == "hard", "enum stores selected option");
|
||||
|
||||
error.clear();
|
||||
Expect(!NormalizeAndValidateParameterValue(definition, JsonValue("other"), value, error), "enum rejects unknown options");
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
TestSafePresetFileStems();
|
||||
TestFloatNormalization();
|
||||
TestVectorNormalization();
|
||||
TestEnumAndDefaults();
|
||||
|
||||
if (gFailures != 0)
|
||||
{
|
||||
std::cerr << gFailures << " RuntimeParameterUtils test failure(s).\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::cout << "RuntimeParameterUtils tests passed.\n";
|
||||
return 0;
|
||||
}
|
||||
129
tests/ShaderPackageRegistryTests.cpp
Normal file
129
tests/ShaderPackageRegistryTests.cpp
Normal file
@@ -0,0 +1,129 @@
|
||||
#include "ShaderPackageRegistry.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace
|
||||
{
|
||||
int gFailures = 0;
|
||||
|
||||
void Expect(bool condition, const char* message)
|
||||
{
|
||||
if (condition)
|
||||
return;
|
||||
|
||||
std::cerr << "FAIL: " << message << "\n";
|
||||
++gFailures;
|
||||
}
|
||||
|
||||
std::filesystem::path MakeTestRoot()
|
||||
{
|
||||
const auto stamp = std::chrono::steady_clock::now().time_since_epoch().count();
|
||||
std::filesystem::path root = std::filesystem::temp_directory_path() / ("video-shader-registry-tests-" + std::to_string(stamp));
|
||||
std::filesystem::create_directories(root);
|
||||
return root;
|
||||
}
|
||||
|
||||
void WriteFile(const std::filesystem::path& path, const std::string& contents)
|
||||
{
|
||||
std::filesystem::create_directories(path.parent_path());
|
||||
std::ofstream output(path, std::ios::binary);
|
||||
output << contents;
|
||||
}
|
||||
|
||||
void WriteShaderPackage(const std::filesystem::path& root, const std::string& directoryName, const std::string& manifest)
|
||||
{
|
||||
const std::filesystem::path packageRoot = root / directoryName;
|
||||
WriteFile(packageRoot / "shader.json", manifest);
|
||||
WriteFile(packageRoot / "shader.slang", "float4 shadeVideo(float2 uv) { return float4(uv, 0.0, 1.0); }\n");
|
||||
}
|
||||
|
||||
void TestValidManifest()
|
||||
{
|
||||
const std::filesystem::path root = MakeTestRoot();
|
||||
WriteFile(root / "look" / "mask.png", "not a real png, but enough for existence checks");
|
||||
WriteShaderPackage(root, "look", R"({
|
||||
"id": "look-01",
|
||||
"name": "Look 01",
|
||||
"description": "Test package",
|
||||
"category": "Tests",
|
||||
"entryPoint": "shadeVideo",
|
||||
"textures": [{ "id": "maskTex", "path": "mask.png" }],
|
||||
"temporal": { "enabled": true, "historySource": "source", "historyLength": 8 },
|
||||
"parameters": [
|
||||
{ "id": "gain", "label": "Gain", "type": "float", "default": 0.5, "min": 0, "max": 1 },
|
||||
{ "id": "mode", "label": "Mode", "type": "enum", "default": "soft", "options": [
|
||||
{ "value": "soft", "label": "Soft" },
|
||||
{ "value": "hard", "label": "Hard" }
|
||||
] }
|
||||
]
|
||||
})");
|
||||
|
||||
ShaderPackageRegistry registry(4);
|
||||
ShaderPackage package;
|
||||
std::string error;
|
||||
Expect(registry.ParseManifest(root / "look" / "shader.json", package, error), "valid manifest parses");
|
||||
Expect(package.id == "look-01", "manifest id is preserved");
|
||||
Expect(package.textureAssets.size() == 1 && package.textureAssets[0].id == "maskTex", "texture assets parse");
|
||||
Expect(package.temporal.enabled && package.temporal.effectiveHistoryLength == 4, "temporal history is capped");
|
||||
Expect(package.parameters.size() == 2, "parameters parse");
|
||||
|
||||
std::filesystem::remove_all(root);
|
||||
}
|
||||
|
||||
void TestInvalidManifest()
|
||||
{
|
||||
const std::filesystem::path root = MakeTestRoot();
|
||||
WriteShaderPackage(root, "bad", R"({
|
||||
"id": "bad",
|
||||
"name": "Bad",
|
||||
"entryPoint": "not-valid!",
|
||||
"parameters": []
|
||||
})");
|
||||
|
||||
ShaderPackageRegistry registry(4);
|
||||
ShaderPackage package;
|
||||
std::string error;
|
||||
Expect(!registry.ParseManifest(root / "bad" / "shader.json", package, error), "invalid shader identifier is rejected");
|
||||
Expect(error.find("entryPoint") != std::string::npos, "invalid manifest error names the bad field");
|
||||
|
||||
std::filesystem::remove_all(root);
|
||||
}
|
||||
|
||||
void TestDuplicateScan()
|
||||
{
|
||||
const std::filesystem::path root = MakeTestRoot();
|
||||
WriteShaderPackage(root, "a", R"({ "id": "dupe", "name": "A", "parameters": [] })");
|
||||
WriteShaderPackage(root, "b", R"({ "id": "dupe", "name": "B", "parameters": [] })");
|
||||
|
||||
ShaderPackageRegistry registry(4);
|
||||
std::map<std::string, ShaderPackage> packages;
|
||||
std::vector<std::string> order;
|
||||
std::string error;
|
||||
Expect(!registry.Scan(root, packages, order, error), "duplicate package ids are rejected");
|
||||
Expect(error.find("Duplicate shader id") != std::string::npos, "duplicate scan error is clear");
|
||||
|
||||
std::filesystem::remove_all(root);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
TestValidManifest();
|
||||
TestInvalidManifest();
|
||||
TestDuplicateScan();
|
||||
|
||||
if (gFailures != 0)
|
||||
{
|
||||
std::cerr << gFailures << " ShaderPackageRegistry test failure(s).\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::cout << "ShaderPackageRegistry tests passed.\n";
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user