feat: complete legacy parity and modernize operator UI
This commit is contained in:
@@ -11,6 +11,8 @@ public sealed class LegacyPlayoutNativeContractTests
|
||||
Path.Combine(AppRoot, "MainWindow.Playout.cs"));
|
||||
private static readonly string Window = File.ReadAllText(
|
||||
Path.Combine(AppRoot, "MainWindow.xaml.cs"));
|
||||
private static readonly string BackgroundPicker = File.ReadAllText(
|
||||
Path.Combine(AppRoot, "MainWindow.BackgroundPicker.cs"));
|
||||
private static readonly string Project = File.ReadAllText(
|
||||
Path.Combine(AppRoot, "MBN_STOCK_WEBVIEW.LegacyParityApp.csproj"));
|
||||
|
||||
@@ -115,6 +117,44 @@ public sealed class LegacyPlayoutNativeContractTests
|
||||
StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LocalSelectionAndDoubleClickGesturesQueueBehindRefreshInArrivalOrder()
|
||||
{
|
||||
var process = Normalize(Slice(
|
||||
Window,
|
||||
"private async Task ProcessIntentAsync(LegacyUiIntent intent)",
|
||||
"private LegacyOperatorSnapshot SelectCutWithoutAppend("));
|
||||
var classifier = Slice(
|
||||
Window,
|
||||
"private static bool IsQueuedLocalSelectionIntent",
|
||||
"private static bool IsOperatorSettingsIntent");
|
||||
|
||||
Assert.Contains("_orderedLocalSelectionIntentGate.WaitAsync(", process,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("else if (IsQueuedLocalSelectionIntent(intent))", process,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("await _intentGate.WaitAsync(_lifetimeCancellation.Token)", process,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("_orderedLocalSelectionIntentGate.Release();", process,
|
||||
StringComparison.Ordinal);
|
||||
|
||||
Assert.Contains("LegacySelectStockIntent", classifier, StringComparison.Ordinal);
|
||||
Assert.Contains("LegacySelectOperatorCatalogStockIntent", classifier,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("LegacyActivateOperatorCatalogStockIntent", classifier,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("LegacyCutPointerDownIntent", classifier, StringComparison.Ordinal);
|
||||
Assert.Contains("LegacyCutKeyDownIntent", classifier, StringComparison.Ordinal);
|
||||
Assert.Contains("LegacyClearCutSelectionIntent", classifier, StringComparison.Ordinal);
|
||||
Assert.Contains("LegacySelectPlaylistRowIntent", classifier, StringComparison.Ordinal);
|
||||
Assert.Contains("LegacyActivatePlaylistRowIntent", classifier, StringComparison.Ordinal);
|
||||
Assert.Contains("LegacySelectPlaylistBoundaryIntent", classifier, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("LegacySearchStocksIntent", classifier, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("LegacyDropSelectedCutsIntent", classifier, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("LegacyExecutePlayoutIntent", classifier, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("LegacySave", classifier, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AutomaticRefreshUsesTheCoreSchedulerAndGenerationOwnedState()
|
||||
{
|
||||
@@ -307,6 +347,96 @@ public sealed class LegacyPlayoutNativeContractTests
|
||||
StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BackgroundControlsStageTheNextCueWithoutChangingTheOnAirRefreshSource()
|
||||
{
|
||||
Assert.Contains("_stagedCompositionOptions", Playout, StringComparison.Ordinal);
|
||||
Assert.Contains(
|
||||
"_stagedCompositionOptions = new MutableLegacySceneCueCompositionOptionsSource(\n" +
|
||||
" initialComposition);",
|
||||
Normalize(Playout),
|
||||
StringComparison.Ordinal);
|
||||
|
||||
var toggle = Slice(
|
||||
Playout,
|
||||
"private async Task<LegacyOperatorSnapshot> ToggleBackgroundAsync(",
|
||||
"private async Task<LegacyOperatorSnapshot> ChooseBackgroundAsync(");
|
||||
Assert.Contains("if (!CanStageBackground())", toggle, StringComparison.Ordinal);
|
||||
Assert.Contains("var source = _stagedCompositionOptions!;", toggle,
|
||||
StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("var source = _compositionOptions!;", toggle,
|
||||
StringComparison.Ordinal);
|
||||
|
||||
var stageGuard = Slice(
|
||||
Playout,
|
||||
"private bool CanStageBackground()",
|
||||
"private void ApplyStagedCompositionForNextCue()");
|
||||
Assert.Contains("status.State != PlayoutConnectionState.OutcomeUnknown", stageGuard,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("!status.IsPlayCompletionPending", stageGuard,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("!status.IsTakeOutCompletionPending", stageGuard,
|
||||
StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("PreparedSceneName", stageGuard, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("OnAirSceneName", stageGuard, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("refresh.IsActive", stageGuard, StringComparison.Ordinal);
|
||||
|
||||
var execute = Slice(
|
||||
Playout,
|
||||
"private async Task<LegacyOperatorSnapshot> ExecuteOperatorPlayoutAsync(",
|
||||
"private async Task<LegacyOperatorPlayoutRequest> CreateFreshPagedPlayoutRequestAsync(");
|
||||
var stopRefresh = RequiredIndex(execute, "StopRefreshLoop();");
|
||||
var promote = RequiredIndex(execute, "ApplyStagedCompositionForNextCue();");
|
||||
var dispatch = RequiredIndex(execute, "switch (command)");
|
||||
Assert.True(stopRefresh < promote && promote < dispatch);
|
||||
Assert.Contains("LegacyOperatorPlayoutCommand.Prepare or", execute,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("LegacyOperatorPlayoutCommand.TakeIn or", execute,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("LegacyOperatorPlayoutCommand.Next", execute,
|
||||
StringComparison.Ordinal);
|
||||
|
||||
var promotion = Slice(
|
||||
Playout,
|
||||
"private void ApplyStagedCompositionForNextCue()",
|
||||
"private bool CanAcceptOperatorMutation(");
|
||||
Assert.Contains("active.Update(staged.Current);", promotion,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("var composition = _stagedCompositionOptions?.Current", Playout,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("CanStageBackground(),", Playout, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void F2PickerStartsInsideTheValidatedBackgroundRootAndKeepsClosedExtensions()
|
||||
{
|
||||
var choose = Slice(
|
||||
Playout,
|
||||
"private async Task<LegacyOperatorSnapshot> ChooseBackgroundAsync(",
|
||||
"private bool CanChangeComposition()");
|
||||
Assert.Contains("TryGetTrustedBackgroundDirectory(", choose,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("PickBackgroundFileAsync(\n trustedBackgroundDirectory)",
|
||||
Normalize(choose), StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("PickerLocationId.PicturesLibrary", Playout,
|
||||
StringComparison.Ordinal);
|
||||
|
||||
Assert.Contains("dialog.SetFolder(initialFolder);", BackgroundPicker,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("dialog.SetDefaultFolder(initialFolder);", BackgroundPicker,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("*.vrv;*.jpg;*.jpeg;*.png", BackgroundPicker,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("FileOpenOptions.ForceFileSystem", BackgroundPicker,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("FileOpenOptions.NoDereferenceLinks", BackgroundPicker,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("WindowNative.GetWindowHandle(this)", BackgroundPicker,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("DispatcherQueue.HasThreadAccess", BackgroundPicker,
|
||||
StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HomeAndEndStopAutomaticRefreshBeforeChangingTheCandidateRow()
|
||||
{
|
||||
@@ -334,9 +464,23 @@ public sealed class LegacyPlayoutNativeContractTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PreparedProgramBlocksCutAppendButAllowsPureCutSelection()
|
||||
public void ProgramAllowsOriginalEnabledGesturesAndSafeTailAppendButKeepsStructuralEditsLocked()
|
||||
{
|
||||
Assert.Contains("CanAcceptOperatorMutation()", Window, StringComparison.Ordinal);
|
||||
Assert.Contains("CanAcceptOperatorMutation(intent, out var mutationRejectionMessage)",
|
||||
Window, StringComparison.Ordinal);
|
||||
Assert.Contains("CanAcceptOperatorMutation(", Playout, StringComparison.Ordinal);
|
||||
Assert.Contains("RequiresIdlePlaylistMutation(intent)", Playout,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("CanDeleteSelectedPlaylistTail(status, workflow)", Playout,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("isSafeCutTailAppend", Playout, StringComparison.Ordinal);
|
||||
Assert.Contains("isSafeProgramEnabledStateMutation", Playout,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("refreshAllowsMutation", Playout, StringComparison.Ordinal);
|
||||
Assert.Contains("!status.IsPlayCompletionPending", Playout, StringComparison.Ordinal);
|
||||
Assert.Contains("!status.IsTakeOutCompletionPending", Playout, StringComparison.Ordinal);
|
||||
Assert.Contains("status.State != PlayoutConnectionState.OutcomeUnknown", Playout,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("IsOperatorMutationQuarantined()", Window,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("ObserveOperatorMutationQuarantine(state)", Window,
|
||||
@@ -351,6 +495,44 @@ public sealed class LegacyPlayoutNativeContractTests
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("LegacyConfirmManualListIntent", Playout,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("CanMutatePlaylistEnabledState(status, workflow)", Playout,
|
||||
StringComparison.Ordinal);
|
||||
var idleOnlyMutations = Slice(
|
||||
Playout,
|
||||
"private static bool RequiresIdlePlaylistMutation",
|
||||
"private static bool IsPlaylistMutationIdle");
|
||||
Assert.Contains("LegacySetPlaylistEnabledIntent", idleOnlyMutations,
|
||||
StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("LegacySetAllPlaylistEnabledIntent", idleOnlyMutations,
|
||||
StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("LegacyToggleActivePlaylistEnabledIntent", idleOnlyMutations,
|
||||
StringComparison.Ordinal);
|
||||
var programEnabledAdmission = Slice(
|
||||
Playout,
|
||||
"private bool CanMutatePlaylistEnabledState(",
|
||||
"private static bool IsOperatorMutationIntent");
|
||||
Assert.Contains("status.OnAirSceneName", programEnabledAdmission,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("workflow.OnAirCutCode", programEnabledAdmission,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("workflow.CurrentEntryId", programEnabledAdmission,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("workflow.CurrentCueIndexZeroBased", programEnabledAdmission,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("IsPlaylistMutationIdle(status, workflow)", programEnabledAdmission,
|
||||
StringComparison.Ordinal);
|
||||
var nextKindProjection = Slice(
|
||||
Playout,
|
||||
"private LegacyWorkflowNextKind ResolveOperatorNextKind(",
|
||||
"private LegacyOperatorPlayoutSnapshot CreatePlayoutSnapshot()");
|
||||
Assert.Contains("workflow.IsLastPage", nextKindProjection,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("LegacyWorkflowNextKind.PageNext", nextKindProjection,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("Skip(currentIndex + 1)", nextKindProjection,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("Any(static row => row.IsEnabled)", nextKindProjection,
|
||||
StringComparison.Ordinal);
|
||||
var mutationClassifier = Slice(
|
||||
Playout,
|
||||
"private static bool IsOperatorMutationIntent",
|
||||
@@ -363,6 +545,15 @@ public sealed class LegacyPlayoutNativeContractTests
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("pointer.AllowAppend", Window,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Equal(2, Window.Split(
|
||||
"PostState(SelectCutWithoutAppend(cutPointer));",
|
||||
StringSplitOptions.None).Length - 1);
|
||||
var selectionOnly = Slice(
|
||||
Window,
|
||||
"private LegacyOperatorSnapshot SelectCutWithoutAppend(",
|
||||
"private static bool IsOrderedPlayoutIntent");
|
||||
Assert.Contains("allowAppend: false", selectionOnly,
|
||||
StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
private static void AssertKnownFailureDoesNotQuarantine(
|
||||
|
||||
Reference in New Issue
Block a user