fix: complete legacy operator parity workflows

This commit is contained in:
2026-07-23 00:54:31 +09:00
parent 939c252d23
commit cf117de144
25 changed files with 2430 additions and 223 deletions

View File

@@ -24,6 +24,55 @@ public sealed class LegacyPackageInputSmokeContractTests
StringComparison.Ordinal);
}
[Fact]
public void NamedPlaylistDoubleClickSealUsesAsciiSafeUtf8Constants()
{
Assert.Contains("$ExpectedSavedFixtureGraphicType = $Utf8.GetString(", Runner,
StringComparison.Ordinal);
Assert.Contains("'MeyXtO2MkOq4sOuzuA=='", Runner,
StringComparison.Ordinal);
Assert.Contains("'7ZiE7J6s6rCA'", Runner, StringComparison.Ordinal);
Assert.Contains("'7Iuc6rCE7Jm464uo7J286rCA'", Runner,
StringComparison.Ordinal);
var doubleClick = Slice(
Runner,
"function Invoke-ExactNamedPlaylistDoubleClickRequest",
"function Get-BackgroundPickerWindowHandles");
Assert.Contains("$ExpectedSavedFixtureGraphicType", doubleClick,
StringComparison.Ordinal);
Assert.Contains("$ExpectedSavedFixtureCurrentSubtype", doubleClick,
StringComparison.Ordinal);
Assert.Contains("$ExpectedSavedFixtureAfterHoursSubtype", doubleClick,
StringComparison.Ordinal);
Assert.DoesNotContain("'1열판기본'", doubleClick,
StringComparison.Ordinal);
}
[Fact]
public void PhysicalPointerInputsCaptureGeometryAfterForegroundAcquisition()
{
foreach (var (start, end) in new[]
{
("public static void SendRowHeaderDragAfterThenHome(",
"public static void SendShiftClickRangeThenDeleteAndRestore("),
("public static void SendShiftClickRangeThenDeleteAndRestore(",
"public static void SendApplicationClick("),
("public static void SendApplicationClick(",
"public static void SendApplicationDoubleClick("),
("public static void SendApplicationDoubleClick(",
"public static IntPtr ReadForegroundWindow()")
})
{
var input = Slice(Runner, start, end);
AssertInOrder(
input,
"AcquireForeground(window, processId, forbiddenPort);",
"ClientGeometry baseline = ReadAndAssertClientGeometry(",
"SleepWithWindowGuard(");
}
}
[Fact]
public void DryRunFinalSealKeepsWindowsDragOrderAndRequiresTheSafeTailAppend()
{
@@ -56,13 +105,35 @@ public sealed class LegacyPackageInputSmokeContractTests
StringComparison.Ordinal);
}
[Fact]
public void ReadOnlyPhysicalPlaylistButtonsAndCheckboxUseTheClosedLocalAllowlist()
{
var harnessAllowlist = Slice(
Harness,
"const readOnlyAllowedOutboundMessageTypes",
"const fullUiDbAllowedOutboundMessageTypes");
Assert.Contains("\"move-selected-playlist-rows\"", harnessAllowlist,
StringComparison.Ordinal);
Assert.Contains("\"set-playlist-enabled\"", harnessAllowlist,
StringComparison.Ordinal);
var runnerAllowlist = Slice(
Runner,
"$allowedOutbound = @(",
"if ($HarnessProfile -ceq 'DryRunPlayout')");
Assert.Contains("'move-selected-playlist-rows'", runnerAllowlist,
StringComparison.Ordinal);
Assert.Contains("'set-playlist-enabled'", runnerAllowlist,
StringComparison.Ordinal);
}
[Fact]
public void DryRunSealPinsProgramEnableAndShortcutEvidenceExactly()
{
var seal = Slice(
Runner,
"$playoutIntentContractOk =",
"if ([int]$evidence.schemaVersion");
"$screenshotPathOk =");
foreach (var token in new[]
{
"programEnableParity.currentEntryId",
@@ -71,6 +142,9 @@ public sealed class LegacyPackageInputSmokeContractTests
"programEnableParity.setAllIntentCount -eq 2",
"programEnableParity.toggleActiveIntentCount -eq 1",
"programEnableParity.endOfPlaylistObserved -eq $true",
"programDragParity.appendIntentCount -eq 1",
"programDragParity.cleanupDeleteIntentCount -eq 1",
"programDragParity.onAirEntryPreserved -eq $true",
"shortcutParity.f8IntentCount -eq 1",
"shortcutParity.escapeIntentCount -eq 1",
"shortcutParity.finalPhase -ceq 'idle'",
@@ -91,6 +165,78 @@ public sealed class LegacyPackageInputSmokeContractTests
StringComparison.Ordinal);
}
[Fact]
public void DryRunPhysicallyCancelsF2PickerAndFailClosesMissingF3Default()
{
var nativeInput = Slice(
Runner,
"public static void SendBackgroundFunctionKey(",
"public static void SendEscapeToForegroundWindow");
Assert.Contains("key != VirtualKeyF2 && key != VirtualKeyF3", nativeInput,
StringComparison.Ordinal);
Assert.Contains("AssertNoForbiddenTcp(processId, forbiddenPort)", nativeInput,
StringComparison.Ordinal);
Assert.Contains("allowForegroundTransitionAfterKey", nativeInput,
StringComparison.Ordinal);
var fixture = Slice(
Runner,
"function Initialize-BackgroundShortcutFixture",
"function Assert-NoUnsafeEnvironment");
Assert.Contains("$Profile -cne 'DryRunPlayout'", fixture,
StringComparison.Ordinal);
Assert.Contains("$ExpectedInstallLocation", fixture,
StringComparison.Ordinal);
Assert.Contains("[IO.FileAttributes]::ReparsePoint", fixture,
StringComparison.Ordinal);
Assert.Contains("The F3 fail-closed test requires the external default background asset to be absent.",
fixture, StringComparison.Ordinal);
Assert.Contains("@(Get-ChildItem -LiteralPath $root -Force).Count -ne 0", fixture,
StringComparison.Ordinal);
Assert.Contains("[IO.Directory]::Delete($root, $false)", fixture,
StringComparison.Ordinal);
var picker = Slice(
Runner,
"function Get-BackgroundPickerWindowHandles",
"function Invoke-ExactWindowsInputRequest");
foreach (var token in new[]
{
"WindowClassName($handle) -cne '#32770'",
"$BackgroundPickerTitle",
"WindowProcessId($handle) -ne $Application.Id",
"OwnerChainContains(",
"The exact app-owned background picker is not modal.",
"SendEscapeToForegroundWindow($picker.Handle)",
"The exact background picker was not destroyed after the one Escape input.",
"The external default background appeared; the one F3 fail-closed input was not sent."
})
{
Assert.Contains(token, picker, StringComparison.Ordinal);
}
var harness = Slice(
Harness,
"async function requestPhysicalBackgroundShortcuts()",
"async function installProbe()");
AssertInOrder(
harness,
"operation: \"background-f2-picker-cancel\"",
"[\"choose-background\"]",
"operation: \"background-f3-none\"",
"snapshot.state.statusKind === \"error\"",
"[\"toggle-background\"]",
"defaultAssetAbsentFailClosed: true");
Assert.Contains("return 3", Runner, StringComparison.Ordinal);
Assert.Contains("backgroundShortcutParity.f2KeyCalls -eq 1", Runner,
StringComparison.Ordinal);
Assert.Contains("backgroundShortcutParity.f3KeyCalls -eq 1", Runner,
StringComparison.Ordinal);
Assert.Contains("backgroundShortcutParity.finalBackgroundEnabled -eq $false", Runner,
StringComparison.Ordinal);
}
[Fact]
public void NamedPlaylistRecoveryIsStrictlyScopedForwardedAndSealed()
{
@@ -126,7 +272,9 @@ public sealed class LegacyPackageInputSmokeContractTests
"$recoveryEvidence.writeCount -eq 1",
"@('committedFresh', 'committedOptimistic')",
"$namedPlaylistDeleteWriteCount -eq 2");
Assert.Contains("-not $namedPlaylistRecoveryContractOk", Runner,
Assert.Contains(
"namedPlaylistRecovery = [bool]$namedPlaylistRecoveryContractOk",
Runner,
StringComparison.Ordinal);
}
@@ -354,6 +502,11 @@ public sealed class LegacyPackageInputSmokeContractTests
sequence,
"const f8Authorization = authorizeDryRunPlayoutShortcut(",
"\"rapid DryRun F8 after row selection\"",
"PROGRAM captured-pointer safe-tail drag",
"PROGRAM captured-pointer tail append",
"delete PROGRAM drag-appended future tail",
"PROGRAM drag-appended tail cleanup",
"PROGRAM safe-tail double-click append",
"PROGRAM clear every enabled row",
"snapshot.state.playlist.every(row => row.isEnabled === false)",
"snapshot.state.playout.nextKind === \"endOfPlaylist\"",
@@ -377,6 +530,143 @@ public sealed class LegacyPackageInputSmokeContractTests
StringComparison.Ordinal);
Assert.Contains("toggleActiveIntentCount: 1", sequence,
StringComparison.Ordinal);
Assert.Contains("programDragParity =", sequence,
StringComparison.Ordinal);
Assert.Contains("onAirEntryPreserved: true", sequence,
StringComparison.Ordinal);
}
[Fact]
public void ProgramNamedPlaylistProfilePhysicallyCreatesSavesReadsAndDeletesWhileOnAir()
{
Assert.Contains("'ProgramPlaylistDb'", Runner, StringComparison.Ordinal);
Assert.Contains("'program-playlist-db'", Runner, StringComparison.Ordinal);
Assert.Contains("\"program-playlist-db\"", Harness, StringComparison.Ordinal);
var profile = Slice(
Harness,
"const programPlaylistDbProfile",
"const hardDeadlineEpochMilliseconds");
AssertInOrder(
profile,
"playout-background-file",
"playout-background-none",
"playout-prepare",
"playout-next",
"db-load-button");
foreach (var allowed in new[]
{
"create-named-playlist",
"save-current-named-playlist-to",
"delete-selected-named-playlist",
"dismiss-dialog",
"take-in",
"take-out"
})
{
Assert.Contains($"\"{allowed}\"", profile, StringComparison.Ordinal);
}
var sequence = Slice(
Harness,
"async function executeProgramNamedPlaylistCrud",
"const manualFinancialScreens");
AssertInOrder(
sequence,
"enter DryRun PROGRAM for named-playlist persistence",
"PROGRAM open named-playlist save dialog",
"PROGRAM create named-playlist definition",
"PROGRAM confirm named-playlist row save",
"PROGRAM reopen save dialog for fresh readback",
"PROGRAM named-playlist fresh readback",
"PROGRAM confirm named-playlist delete",
"PROGRAM named-playlist delete and absence",
"leave DryRun PROGRAM after named-playlist CRUD",
"PROGRAM named-playlist final IDLE");
Assert.DoesNotContain(
"document.getElementById(\"db-load-button\")",
sequence,
StringComparison.Ordinal);
var safeSequence = Slice(
Harness,
"async function executeSafeSequence",
"async function executeDryRunPlayoutSequence");
Assert.Contains("if (!programPlaylistDbProfile)", safeSequence,
StringComparison.Ordinal);
Assert.Contains("document.getElementById(\"db-load-button\")", safeSequence,
StringComparison.Ordinal);
Assert.Contains("writes.length !== 3", sequence, StringComparison.Ordinal);
Assert.Contains("\"저장되었습니다\"", sequence, StringComparison.Ordinal);
Assert.DoesNotContain("?€?λ릺?덉뒿?덈떎", sequence,
StringComparison.Ordinal);
Assert.Contains("definitionId: readback.definitionId", sequence,
StringComparison.Ordinal);
Assert.Contains("saveDefinitionId: created.definitionId", sequence,
StringComparison.Ordinal);
Assert.Contains(
"snapshot.state.namedPlaylist.documentFreshness === \"fresh\"",
sequence,
StringComparison.Ordinal);
Assert.Contains(
"snapshot.state.namedPlaylist.listFreshness === \"fresh\"",
sequence,
StringComparison.Ordinal);
Assert.Contains(
"snapshot.state.namedPlaylist.documentFreshness === \"none\"",
sequence,
StringComparison.Ordinal);
Assert.Contains("snapshot.state.namedPlaylist.rowCount === 0", sequence,
StringComparison.Ordinal);
Assert.Contains("rowCount: savedRowCount", sequence,
StringComparison.Ordinal);
Assert.Contains("freshDefinitionReadbackVerified: true", sequence,
StringComparison.Ordinal);
Assert.Contains("exactAbsenceVerified: true", sequence,
StringComparison.Ordinal);
Assert.Contains("beforeProgramDeleteWriteCount", sequence,
StringComparison.Ordinal);
Assert.Contains("waitForNamedPlaylistDeleteDispatch(", sequence,
StringComparison.Ordinal);
var finalIdle = Slice(
sequence,
"PROGRAM named-playlist final IDLE",
"restore deletion selection after PROGRAM named-playlist CRUD");
Assert.Contains("allowActiveDryRun: true", finalIdle,
StringComparison.Ordinal);
var deleteDispatch = Slice(
Harness,
"async function waitForNamedPlaylistDeleteDispatch",
"function assertNamedPlaylistRecoverySafe");
Assert.Contains("Date.now() + 5_000", deleteDispatch,
StringComparison.Ordinal);
Assert.Contains("writeCount === 1", deleteDispatch,
StringComparison.Ordinal);
Assert.Contains("produced no delete intent", deleteDispatch,
StringComparison.Ordinal);
Assert.Contains("failKnown", deleteDispatch, StringComparison.Ordinal);
Assert.Contains("failUnknown", deleteDispatch, StringComparison.Ordinal);
var seal = Slice(
Runner,
"elseif ($HarnessProfile -ceq 'ProgramPlaylistDb')",
"$playoutIntentContractOk =");
foreach (var token in new[]
{
"approvedDatabaseWriteMessages).Count -eq 3",
"create-named-playlist",
"save-current-named-playlist-to",
"delete-selected-named-playlist",
"saveDefinitionId",
"definitionId",
"requestId",
"freshDefinitionReadbackVerified -eq $true",
"exactAbsenceVerified -eq $true",
"finalPhase -ceq 'idle'"
})
{
Assert.Contains(token, seal, StringComparison.Ordinal);
}
}
[Fact]
@@ -460,6 +750,46 @@ public sealed class LegacyPackageInputSmokeContractTests
"SendMouseMove(restore.X, restore.Y)");
}
[Fact]
public void ReadOnlyPhysicalSequenceDirectlyClicksPlaylistButtonsAndIndividualCheckbox()
{
var sequence = Slice(
Harness,
"async function executeSafeSequence",
"async function executeDryRunPlayoutSequence");
AssertInOrder(
sequence,
"move selected playlist row with Up button",
"playlist Up button reorder",
"restore selected playlist row with Down button",
"playlist Down button reorder",
"disable playlist row with its checkbox",
"individual playlist checkbox disabled row",
"restore playlist row with its checkbox",
"individual playlist checkbox restored row",
"stage direct selected-delete button row",
"select direct button delete fixture",
"delete selected playlist row with button",
"selected-delete button removed exact fixture");
Assert.Contains(
"document.getElementById(\"playlist-move-up\")",
sequence,
StringComparison.Ordinal);
Assert.Contains(
"document.getElementById(\"playlist-move-down\")",
sequence,
StringComparison.Ordinal);
Assert.Contains(
"document.getElementById(\"playlist-delete-selected\")",
sequence,
StringComparison.Ordinal);
Assert.Contains(
"input[type=\"checkbox\"]",
sequence,
StringComparison.Ordinal);
}
[Fact]
public void FullUiDbPListUsesASecondPhysicalDoubleClickExchangeWithContentRestoration()
{