fix: complete legacy operator parity workflows
This commit is contained in:
@@ -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()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user