added optional web component UI control
All checks were successful
CI / React UI Build (push) Successful in 12s
CI / Native Windows Build And Tests (push) Successful in 2m20s
CI / Windows Release Package (push) Successful in 2m56s

This commit is contained in:
Aiden
2026-05-30 22:57:59 +10:00
parent a6d2ee385e
commit 27690c3afa
26 changed files with 804 additions and 76 deletions

View File

@@ -50,12 +50,14 @@ void TestValidManifest()
WriteFile(root / "look" / "mask.png", "not a real png, but enough for existence checks");
WriteFile(root / "look" / "Inter.ttf", "not a real font, but enough for existence checks");
WriteFile(root / "look" / "Mono.ttf", "not a real font, but enough for existence checks");
WriteFile(root / "look" / "ui" / "controls.js", "customElements.define('look-controls', class extends HTMLElement {});\n");
WriteShaderPackage(root, "look", R"({
"id": "look-01",
"name": "Look 01",
"description": "Test package",
"category": "Tests",
"entryPoint": "shadeVideo",
"ui": { "type": "webComponent", "entry": "ui/controls.js", "tag": "look-controls" },
"textures": [{ "id": "maskTex", "path": "mask.png" }],
"fonts": [
{ "id": "inter", "path": "Inter.ttf" },
@@ -83,6 +85,8 @@ void TestValidManifest()
Expect(package.fontAssets.size() == 2 && package.fontAssets[0].id == "inter", "font assets parse");
Expect(package.temporal.enabled && package.temporal.effectiveHistoryLength == 4, "temporal history is capped");
Expect(package.feedback.enabled && package.feedback.writePassId == "main", "feedback defaults to the implicit main pass");
Expect(package.ui.enabled && package.ui.entryPath == "ui/controls.js", "custom UI entry parses");
Expect(package.ui.customElementTag == "look-controls", "custom UI tag parses");
Expect(package.parameters.size() == 4, "parameters parse");
Expect(package.parameters[0].description == "Scales the output intensity.", "parameter descriptions parse");
Expect(package.parameters[1].type == ShaderParameterType::Text && package.parameters[1].defaultTextValue == "LIVE", "text parameter parses");
@@ -93,6 +97,47 @@ void TestValidManifest()
std::filesystem::remove_all(root);
}
void TestInvalidUiDefinition()
{
struct Case
{
const char* directoryName;
const char* uiJson;
const char* expectedError;
bool writeEntry;
};
const Case cases[] = {
{ "bad-type", R"({ "type": "react", "entry": "ui/controls.js", "tag": "bad-type-controls" })", "webComponent", true },
{ "bad-path", R"({ "type": "webComponent", "entry": "../controls.js", "tag": "bad-path-controls" })", "safe relative", true },
{ "wrong-dir", R"({ "type": "webComponent", "entry": "controls.js", "tag": "wrong-dir-controls" })", "safe relative", true },
{ "bad-extension", R"({ "type": "webComponent", "entry": "ui/controls.txt", "tag": "bad-extension-controls" })", ".js or .mjs", true },
{ "bad-tag", R"({ "type": "webComponent", "entry": "ui/controls.js", "tag": "BadTag" })", "custom element", true },
{ "missing-entry", R"({ "type": "webComponent", "entry": "ui/missing.js", "tag": "missing-entry-controls" })", "UI entry not found", false },
};
const std::filesystem::path root = MakeTestRoot();
for (const Case& testCase : cases)
{
WriteShaderPackage(root, testCase.directoryName, std::string(R"({
"id": ")") + testCase.directoryName + R"(",
"name": "Bad UI",
"ui": )" + testCase.uiJson + R"(,
"parameters": []
})");
if (testCase.writeEntry)
WriteFile(root / testCase.directoryName / "ui" / "controls.js", "customElements.define('bad-controls', class extends HTMLElement {});\n");
ShaderPackageRegistry registry(4);
ShaderPackage package;
std::string error;
Expect(!registry.ParseManifest(root / testCase.directoryName / "shader.json", package, error), "invalid custom UI manifest is rejected");
Expect(error.find(testCase.expectedError) != std::string::npos, "invalid custom UI error explains the rejected field");
}
std::filesystem::remove_all(root);
}
void TestExplicitPassManifest()
{
const std::filesystem::path root = MakeTestRoot();
@@ -289,6 +334,7 @@ int main()
{
TestValidManifest();
TestExplicitPassManifest();
TestInvalidUiDefinition();
TestMissingFontAsset();
TestInvalidManifest();
TestInvalidTemporalSettings();