feat: add configurable operator appearance and layout
This commit is contained in:
@@ -134,6 +134,46 @@ public sealed class LegacyPlayoutWebContractTests
|
||||
Assert.Contains("마지막 항목", Script, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StatusStateUsesFailSafePriorityAndIsReassignedOnEveryRender()
|
||||
{
|
||||
var resolver = ExtractFunction(Script, "function statusState(playout, busy)");
|
||||
|
||||
foreach (var state in new[]
|
||||
{
|
||||
"outcome-unknown",
|
||||
"busy",
|
||||
"error",
|
||||
"program",
|
||||
"prepared",
|
||||
"idle"
|
||||
})
|
||||
{
|
||||
Assert.Contains($"\"{state}\"", resolver, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
Assert.True(
|
||||
resolver.IndexOf("playout.outcomeUnknown === true", StringComparison.Ordinal) <
|
||||
resolver.IndexOf("if (busy)", StringComparison.Ordinal),
|
||||
"OutcomeUnknown must remain visually dominant while a command is busy.");
|
||||
Assert.True(
|
||||
resolver.IndexOf("if (busy)", StringComparison.Ordinal) <
|
||||
resolver.IndexOf("playout.mode === \"disabled\"", StringComparison.Ordinal),
|
||||
"Busy must win over an unavailable engine after OutcomeUnknown is excluded.");
|
||||
Assert.True(
|
||||
resolver.IndexOf("playout.mode === \"disabled\"", StringComparison.Ordinal) <
|
||||
resolver.IndexOf("playout.phase === \"program\"", StringComparison.Ordinal),
|
||||
"Engine errors must win over ordinary phase styling.");
|
||||
Assert.Contains(
|
||||
"status.dataset.state = statusState(playout, busy);",
|
||||
Script,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains(
|
||||
"status.dataset.state = \"error\";",
|
||||
Script,
|
||||
StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
private static int CountOccurrences(string source, string value)
|
||||
{
|
||||
var count = 0;
|
||||
@@ -156,6 +196,28 @@ public sealed class LegacyPlayoutWebContractTests
|
||||
return source[start..(end + closingTag.Length)];
|
||||
}
|
||||
|
||||
private static string ExtractFunction(string source, string signature)
|
||||
{
|
||||
var start = source.IndexOf(signature, StringComparison.Ordinal);
|
||||
Assert.True(start >= 0, $"Function '{signature}' was not found.");
|
||||
var bodyStart = source.IndexOf('{', start);
|
||||
Assert.True(bodyStart >= 0, $"Function '{signature}' has no body.");
|
||||
var depth = 0;
|
||||
for (var index = bodyStart; index < source.Length; index++)
|
||||
{
|
||||
if (source[index] == '{')
|
||||
{
|
||||
depth++;
|
||||
}
|
||||
else if (source[index] == '}' && --depth == 0)
|
||||
{
|
||||
return source[start..(index + 1)];
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidDataException($"Function '{signature}' is incomplete.");
|
||||
}
|
||||
|
||||
private static string FindRepositoryRoot()
|
||||
{
|
||||
var current = new DirectoryInfo(AppContext.BaseDirectory);
|
||||
|
||||
Reference in New Issue
Block a user