namespace MBN_STOCK_WEBVIEW.LegacyWeb.Tests; public sealed class LegacyPlayoutNativeContractTests { private static readonly string RepositoryRoot = FindRepositoryRoot(); private static readonly string AppRoot = Path.Combine( RepositoryRoot, "src", "MBN_STOCK_WEBVIEW.LegacyParityApp"); private static readonly string Playout = File.ReadAllText( 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")); [Fact] public void ParityAppComposesTheVerifiedThirtyFiveSceneRuntime() { Assert.Contains("LegacySceneRuntimeFactory.cs", Project, StringComparison.Ordinal); Assert.Contains("LegacySceneRuntimeFactory.Create(", Playout, StringComparison.Ordinal); Assert.Contains("trustedManualSource: _manualNetSellStore", Playout, StringComparison.Ordinal); Assert.Contains("trustedViSource: _manualViStore", Playout, StringComparison.Ordinal); } [Fact] public void StartupDefaultBackgroundDependsOnAbsentLocalConfigAndSurfacesWarning() { Assert.Contains("File.Exists(", Playout, StringComparison.Ordinal); Assert.Contains("PlayoutOptionsLoader.DefaultPath", Playout, StringComparison.Ordinal); Assert.Contains("LegacyParityStartupCompositionResolver.Resolve(", Playout, StringComparison.Ordinal); Assert.Contains("_playoutInitializationWarning ?? status?.Message", Playout, StringComparison.Ordinal); } [Fact] public void OperatorCommandsUseTheNativeWorkflowAndCSharpPlaylist() { Assert.Contains("_controller.CreatePlayoutRequest(", Playout, StringComparison.Ordinal); Assert.Contains("_compositionOptions!.Current.FadeDuration", Playout, StringComparison.Ordinal); Assert.Contains("workflow.PrepareAsync(", Playout, StringComparison.Ordinal); Assert.Contains("workflow.TakeSelectedAsync(", Playout, StringComparison.Ordinal); Assert.DoesNotContain("workflow.TakeInAsync(", Playout, StringComparison.Ordinal); Assert.DoesNotContain( "string.IsNullOrWhiteSpace(workflow.State.PreparedCutCode)", Playout, StringComparison.Ordinal); Assert.Contains("workflow.NextAsync(", Playout, StringComparison.Ordinal); Assert.Contains("workflow.TakeOutAsync(", Playout, StringComparison.Ordinal); Assert.Contains("_controller.ReflectSuccessfulPlayout(", Playout, StringComparison.Ordinal); Assert.Contains("workflow.State.CurrentEntryId", Playout, StringComparison.Ordinal); Assert.Contains("LegacyOperatorPlayoutCommand.Prepare or", Playout, StringComparison.Ordinal); Assert.Contains( "command != LegacyOperatorPlayoutCommand.TakeOut", Playout, StringComparison.Ordinal); Assert.Contains("LegacyWorkflowNextKind.PlaylistNext", Playout, StringComparison.Ordinal); Assert.Contains("LegacySceneRefreshPolicy.TryGetInterval", Playout, StringComparison.Ordinal); Assert.Contains("WaitForPlayCompletionAsync", Playout, StringComparison.Ordinal); } [Fact] public void PlayoutIntentsWaitBehindEarlierUiWorkWithoutQueuingDuplicates() { var process = Normalize(Slice( Window, "private async Task ProcessIntentAsync(LegacyUiIntent intent)", "private static bool IsOrderedPlayoutIntent")); var classifier = Slice( Window, "private static bool IsOrderedPlayoutIntent", "private static bool IsNamedPlaylistModalIntent"); var admission = RequiredIndex( process, "_orderedPlayoutIntentGate.WaitAsync("); var orderedWait = RequiredIndex( process, "await _intentGate.WaitAsync(_lifetimeCancellation.Token)", admission); var zeroTimeoutWait = RequiredIndex( process, "gateEntered = await _intentGate.WaitAsync(\n 0,", orderedWait); var intentRelease = RequiredIndex(process, "_intentGate.Release();", zeroTimeoutWait); var admissionRelease = RequiredIndex( process, "_orderedPlayoutIntentGate.Release();", intentRelease); Assert.True(admission < orderedWait); Assert.True(orderedWait < zeroTimeoutWait); Assert.True(zeroTimeoutWait < intentRelease); Assert.True(intentRelease < admissionRelease); Assert.Contains("if (orderedPlayoutIntentEntered)", process, StringComparison.Ordinal); Assert.Contains("LegacyExecutePlayoutIntent", classifier, StringComparison.Ordinal); Assert.Contains("LegacyGateAPrepareIntent", classifier, StringComparison.Ordinal); Assert.Contains("_lifetimeCancellation.Token", process, StringComparison.Ordinal); } [Fact] public void LocalSelectionDoubleClickAndCutDropQueueBehindRefreshInArrivalOrder() { 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("LegacyDropSelectedCutsIntent", 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("LegacyExecutePlayoutIntent", classifier, StringComparison.Ordinal); Assert.DoesNotContain("LegacySave", classifier, StringComparison.Ordinal); } [Fact] public void AutomaticRefreshUsesTheCoreSchedulerAndGenerationOwnedState() { Assert.Contains("new LegacyRefreshScheduler(", Playout, StringComparison.Ordinal); Assert.Contains( "LegacyRefreshEpoch", Playout, StringComparison.Ordinal); Assert.Contains("_refreshEpoch.ReadState()", Playout, StringComparison.Ordinal); Assert.Contains("_refreshEpoch.Replace(", Playout, StringComparison.Ordinal); Assert.Contains("_refreshEpoch.TryUpdate(", Playout, StringComparison.Ordinal); Assert.Contains("_refreshEpoch.TryComplete(", Playout, StringComparison.Ordinal); Assert.DoesNotContain("Task.Delay(", Playout, StringComparison.Ordinal); foreach (var obsoleteRawField in new[] { "_refreshCancellation", "_refreshCts", "_refreshStateGate", "_refreshActive", "_refreshCompletedCount", "_refreshMaximumCount", "_refreshLimitReached", "_refreshNextAtUtc", "_refreshLastSuccessAtUtc", "_refreshFaultCode", "_refreshMessage" }) { Assert.DoesNotContain(obsoleteRawField, Playout, StringComparison.Ordinal); } } [Fact] public void ZeroRefreshLimitReturnsBeforeCreatingAnEpochOrLoop() { var start = Slice( Playout, "private void StartRefreshLoop(LegacyPlayoutWorkflow workflow)", "private void StopRefreshLoop()"); var limitCheck = RequiredIndex(start, "if (scheduler.HasReachedMaximum)"); var linkedEpoch = RequiredIndex( start, "CancellationTokenSource.CreateLinkedTokenSource("); var loopAssignment = RequiredIndex( start, "_refreshTask = RunRefreshLoopAsync(workflow, scheduler, cancellation);"); Assert.True(limitCheck < linkedEpoch); Assert.True(linkedEpoch < loopAssignment); var zeroLimitBranch = start[limitCheck..linkedEpoch]; Assert.Contains("_refreshTask = Task.CompletedTask;", zeroLimitBranch, StringComparison.Ordinal); Assert.Contains("_refreshEpoch.Stop(", zeroLimitBranch, StringComparison.Ordinal); Assert.Contains("return;", zeroLimitBranch, StringComparison.Ordinal); Assert.DoesNotContain("RunRefreshLoopAsync(", zeroLimitBranch, StringComparison.Ordinal); } [Fact] public void AutomaticRefreshSerializesDbThenPlayoutAndPublishesBothBusyStates() { var loop = Slice( Playout, "private async Task RunRefreshLoopAsync(", "private bool TrySetRefreshFault("); var intentWait = RequiredIndex(loop, "await _intentGate.WaitAsync(token)"); var intentBusy = RequiredIndex(loop, "_intentBusy = true;", intentWait); var intentBusyState = RequiredIndex(loop, "QueueOperatorState();", intentBusy); var playoutWait = RequiredIndex( loop, "await _playoutCommandGate.WaitAsync(token)", intentBusyState); var playoutBusy = RequiredIndex( loop, "Interlocked.Exchange(ref _playoutBusy, 1);", playoutWait); var playoutBusyState = RequiredIndex(loop, "QueueOperatorState();", playoutBusy); var refreshDispatch = RequiredIndex( loop, "workflow.RefreshOnAirAsync", playoutBusyState); Assert.True(intentWait < intentBusy); Assert.True(intentBusy < intentBusyState); Assert.True(intentBusyState < playoutWait); Assert.True(playoutWait < playoutBusy); Assert.True(playoutBusy < playoutBusyState); Assert.True(playoutBusyState < refreshDispatch); } [Fact] public void KnownRefreshInputFailuresStopWithoutQuarantineButUnknownsDoQuarantine() { var loop = Normalize(Slice( Playout, "private async Task RunRefreshLoopAsync(", "private bool TrySetRefreshFault(")); var databaseFailure = Slice( loop, "catch (DatabaseInfrastructureException)", "catch (LegacySceneDataException)"); var sceneDataFailure = Slice( loop, "catch (LegacySceneDataException)", "catch (ArgumentException)"); var argumentFailure = Slice( loop, "catch (ArgumentException)", "catch\n {"); var unknownFailure = Slice( loop, "catch\n {", "finally"); AssertKnownFailureDoesNotQuarantine( databaseFailure, "DATABASE_UNAVAILABLE"); AssertKnownFailureDoesNotQuarantine( sceneDataFailure, "SCENE_DATA_INVALID"); AssertKnownFailureDoesNotQuarantine( argumentFailure, "SCENE_ARGUMENT_INVALID"); Assert.Contains("REFRESH_OUTCOME_UNKNOWN", unknownFailure, StringComparison.Ordinal); Assert.Contains("QuarantinePlayoutAsync", unknownFailure, StringComparison.Ordinal); Assert.Contains( "result.Code is PlayoutResultCode.OutcomeUnknown or\n" + " PlayoutResultCode.TimedOut", loop, StringComparison.Ordinal); AssertEveryFaultBranchQuarantines(loop, "PLAY_CALLBACK_TIMEOUT"); } [Fact] public void ExternalIdleStatusResetsNormalRefreshState() { var handler = Slice( Playout, "private void OnPlayoutStatusChanged(", "private async Task ExecuteOperatorPlayoutAsync("); Assert.Contains( "string.IsNullOrWhiteSpace(args.Current.PreparedSceneName)", handler, StringComparison.Ordinal); Assert.Contains( "string.IsNullOrWhiteSpace(args.Current.OnAirSceneName)", handler, StringComparison.Ordinal); Assert.Contains( "args.Current.State == PlayoutConnectionState.OutcomeUnknown", handler, StringComparison.Ordinal); var stop = RequiredIndex(handler, "StopRefreshLoop();"); var normalElse = RequiredIndex(handler, "else", stop); var reset = RequiredIndex(handler, "ResetRefreshState();", normalElse); Assert.True(stop < normalElse && normalElse < reset); var resetHelper = Slice( Playout, "private void ResetRefreshState()", "private async Task RunRefreshLoopAsync("); Assert.Contains( "_refreshEpoch.Stop(_ => LegacyRefreshRuntimeStatus.Empty", resetHelper, StringComparison.Ordinal); } [Fact] public void UnknownOutcomeQuarantinesWithoutAutomaticCommandRetry() { Assert.Contains("PlayoutResultCode.OutcomeUnknown", Playout, StringComparison.Ordinal); Assert.Contains("PlayoutResultCode.TimedOut", Playout, StringComparison.Ordinal); Assert.Contains("QuarantinePlayoutAsync", Playout, StringComparison.Ordinal); Assert.DoesNotContain("MaximumReconnectAttempts", Playout, StringComparison.Ordinal); Assert.DoesNotContain("ReconnectAsync", Playout, StringComparison.Ordinal); } [Fact] public void OriginalDissolveComboAcceptsOnlyItsZeroBasedTwentyItemIndex() { Assert.Contains("fadeDuration is < 0 or > 19", Playout, StringComparison.Ordinal); Assert.DoesNotContain("fadeDuration is < 0 or > 60", Playout, 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 ToggleBackgroundAsync(", "private async Task 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 ExecuteOperatorPlayoutAsync(", "private async Task 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 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() { Assert.Contains( "LegacySelectPlaylistBoundaryIntent boundary =>\n" + " SelectPlaylistBoundaryAndStopRefresh(boundary.Last)", Window.Replace("\r\n", "\n", StringComparison.Ordinal), StringComparison.Ordinal); Assert.Contains( "private LegacyOperatorSnapshot SelectPlaylistBoundaryAndStopRefresh(bool last)", Playout, StringComparison.Ordinal); var helperStart = Playout.IndexOf( "private LegacyOperatorSnapshot SelectPlaylistBoundaryAndStopRefresh(bool last)", StringComparison.Ordinal); var helperEnd = Playout.IndexOf( "private async Task ToggleBackgroundAsync", helperStart, StringComparison.Ordinal); Assert.True(helperStart >= 0 && helperEnd > helperStart); var helper = Playout[helperStart..helperEnd]; Assert.True( helper.IndexOf("StopRefreshLoop();", StringComparison.Ordinal) < helper.IndexOf("_controller.SelectPlaylistBoundary(last)", StringComparison.Ordinal)); } [Fact] public void ProgramAllowsOriginalEnabledGesturesAndSafeTailAppendButKeepsStructuralEditsLocked() { 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("CanAppendCutToPlaylistTail(status, workflow)", Playout, StringComparison.Ordinal); var safeCutTailClassifier = Slice( Playout, "var isSafeCutTailAppend", "// MainForm kept its Space"); Assert.Contains("LegacyCutPointerDownIntent { AllowAppend: true }", safeCutTailClassifier, StringComparison.Ordinal); Assert.Contains("LegacyDropSelectedCutsIntent", safeCutTailClassifier, StringComparison.Ordinal); Assert.Contains("isSafeProgramEnabledStateMutation", Playout, StringComparison.Ordinal); Assert.Contains("isSafeProgramTailDelete", 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, StringComparison.Ordinal); Assert.Contains("ManualFinancial?.WritesQuarantined", Playout, StringComparison.Ordinal); Assert.Contains("NamedPlaylist?.IsWriteQuarantined", Playout, StringComparison.Ordinal); Assert.Contains("ManualLists?.WritesQuarantined", Playout, StringComparison.Ordinal); Assert.Contains("OperatorCatalog?.WritesQuarantined", Playout, 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", "private static bool IsFixedSectionBatchMutationIntent"); Assert.Contains("LegacyCutPointerDownIntent { AllowAppend: true }", mutationClassifier, StringComparison.Ordinal); Assert.Contains("LegacyDropSelectedCutsIntent", mutationClassifier, StringComparison.Ordinal); Assert.DoesNotContain("LegacyCutKeyDownIntent", mutationClassifier, StringComparison.Ordinal); Assert.DoesNotContain("LegacyClearCutSelectionIntent", mutationClassifier, 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); var queuedLocalIntents = Slice( Window, "private static bool IsQueuedLocalSelectionIntent", "private static bool IsOperatorSettingsIntent"); Assert.Contains("LegacyDropSelectedCutsIntent", queuedLocalIntents, StringComparison.Ordinal); var safeTailAdmission = Slice( Playout, "private bool CanAppendCutToPlaylistTail(", "private static bool RequiresIdlePlaylistMutation"); Assert.Contains("status.OnAirSceneName", safeTailAdmission, StringComparison.Ordinal); Assert.Contains("workflow.OnAirCutCode", safeTailAdmission, StringComparison.Ordinal); Assert.Contains("workflow.CurrentEntryId", safeTailAdmission, StringComparison.Ordinal); Assert.Contains("workflow.CurrentCueIndexZeroBased", safeTailAdmission, StringComparison.Ordinal); Assert.Contains("currentIndex < playlist.Count", safeTailAdmission, StringComparison.Ordinal); Assert.Contains("playlist.Count(row => string.Equals(", safeTailAdmission, StringComparison.Ordinal); var orderedTailDelete = Slice( Window, "else if (IsOrderedPlaylistTailMutationIntent(intent))", "else if (IsQueuedLocalSelectionIntent(intent))"); Assert.Contains("_orderedPlaylistTailMutationIntentGate.WaitAsync(", orderedTailDelete, StringComparison.Ordinal); Assert.Contains("0,", orderedTailDelete, StringComparison.Ordinal); Assert.Contains("_orderedLocalSelectionIntentGate.WaitAsync(", orderedTailDelete, StringComparison.Ordinal); Assert.Contains("await _intentGate.WaitAsync", orderedTailDelete, StringComparison.Ordinal); Assert.Contains( "intent is LegacyDeleteSelectedPlaylistRowsIntent", Window, StringComparison.Ordinal); Assert.Contains("_orderedPlaylistTailMutationIntentGate.Release();", Window, StringComparison.Ordinal); } private static void AssertKnownFailureDoesNotQuarantine( string failureBlock, string expectedFaultCode) { Assert.Contains(expectedFaultCode, failureBlock, StringComparison.Ordinal); Assert.DoesNotContain( "QuarantinePlayoutAsync", failureBlock, StringComparison.Ordinal); } private static void AssertEveryFaultBranchQuarantines( string source, string faultCode) { var occurrence = 0; var count = 0; while ((occurrence = source.IndexOf( faultCode, occurrence, StringComparison.Ordinal)) >= 0) { var branchEnd = source.IndexOf("return;", occurrence, StringComparison.Ordinal); Assert.True(branchEnd > occurrence, $"{faultCode} branch has no return."); Assert.Contains( "QuarantinePlayoutAsync", source[occurrence..branchEnd], StringComparison.Ordinal); count++; occurrence = branchEnd + "return;".Length; } Assert.True(count > 0, $"No {faultCode} branch was found."); } private static string Slice(string source, string startMarker, string endMarker) { var start = RequiredIndex(source, startMarker); var end = RequiredIndex(source, endMarker, start + startMarker.Length); return source[start..end]; } private static int RequiredIndex(string source, string marker, int startIndex = 0) { var index = source.IndexOf(marker, startIndex, StringComparison.Ordinal); Assert.True(index >= 0, $"Required source marker was not found: {marker}"); return index; } private static string Normalize(string source) => source.Replace("\r\n", "\n", StringComparison.Ordinal); private static string FindRepositoryRoot() { var current = new DirectoryInfo(AppContext.BaseDirectory); while (current is not null) { if (File.Exists(Path.Combine(current.FullName, "MBN_STOCK_WEBVIEW.sln"))) { return current.FullName; } current = current.Parent; } throw new DirectoryNotFoundException("Repository root was not found."); } }