197 lines
7.7 KiB
C#
197 lines
7.7 KiB
C#
namespace MBN_STOCK_WEBVIEW.LegacyWeb.Tests;
|
|
|
|
public sealed class LegacyProgramNamedPlaylistPersistenceContractTests
|
|
{
|
|
private static readonly string Playout = File.ReadAllText(Path.Combine(
|
|
FindRepositoryRoot(),
|
|
"src",
|
|
"MBN_STOCK_WEBVIEW.LegacyParityApp",
|
|
"MainWindow.Playout.cs"));
|
|
|
|
private static readonly string Window = File.ReadAllText(Path.Combine(
|
|
FindRepositoryRoot(),
|
|
"src",
|
|
"MBN_STOCK_WEBVIEW.LegacyParityApp",
|
|
"MainWindow.xaml.cs"));
|
|
|
|
private static readonly string Web = File.ReadAllText(Path.Combine(
|
|
FindRepositoryRoot(),
|
|
"src",
|
|
"MBN_STOCK_WEBVIEW.LegacyParityApp",
|
|
"Web",
|
|
"app.js"));
|
|
|
|
[Fact]
|
|
public void ProgramAllowsNamedPlaylistWritesWithoutOpeningDbLoadReplacement()
|
|
{
|
|
var admission = Slice(
|
|
Playout,
|
|
"private bool CanAcceptOperatorMutation(",
|
|
"private static bool RequiresIdlePlaylistMutation");
|
|
var safeWrites = Slice(
|
|
admission,
|
|
"var isSafeNamedPlaylistPersistenceMutation",
|
|
"var refreshAllowsMutation");
|
|
|
|
Assert.Contains("LegacyCreateNamedPlaylistIntent", safeWrites,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains("LegacySaveCurrentNamedPlaylistIntent", safeWrites,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains("LegacySaveCurrentNamedPlaylistToIntent", safeWrites,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains("LegacyDeleteSelectedNamedPlaylistIntent", safeWrites,
|
|
StringComparison.Ordinal);
|
|
Assert.DoesNotContain("LegacyRefreshNamedPlaylistsIntent", safeWrites,
|
|
StringComparison.Ordinal);
|
|
Assert.DoesNotContain("LegacyLoadSelectedNamedPlaylistIntent", safeWrites,
|
|
StringComparison.Ordinal);
|
|
Assert.DoesNotContain("LegacyLoadNamedPlaylistByIdIntent", safeWrites,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains("isSafeNamedPlaylistPersistenceMutation ||", admission,
|
|
StringComparison.Ordinal);
|
|
|
|
var idleOnly = Slice(
|
|
Playout,
|
|
"private static bool RequiresIdlePlaylistMutation",
|
|
"private static bool IsPlaylistMutationIdle");
|
|
Assert.Contains("LegacyLoadSelectedNamedPlaylistIntent", idleOnly,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains("LegacyLoadNamedPlaylistByIdIntent", idleOnly,
|
|
StringComparison.Ordinal);
|
|
Assert.DoesNotContain("LegacyCreateNamedPlaylistIntent", idleOnly,
|
|
StringComparison.Ordinal);
|
|
Assert.DoesNotContain("LegacySaveCurrentNamedPlaylistIntent", idleOnly,
|
|
StringComparison.Ordinal);
|
|
Assert.DoesNotContain("LegacySaveCurrentNamedPlaylistToIntent", idleOnly,
|
|
StringComparison.Ordinal);
|
|
Assert.DoesNotContain("LegacyDeleteSelectedNamedPlaylistIntent", idleOnly,
|
|
StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void NamedPlaylistModalRequestsUseOnePendingSlotBehindRefresh()
|
|
{
|
|
Assert.Contains(
|
|
"private readonly SemaphoreSlim _orderedNamedPlaylistIntentGate = new(1, 1);",
|
|
Window,
|
|
StringComparison.Ordinal);
|
|
|
|
var process = Slice(
|
|
Window,
|
|
"private async Task ProcessIntentAsync",
|
|
"private LegacyOperatorSnapshot SelectCutWithoutAppend");
|
|
var queued = Slice(
|
|
process,
|
|
"else if (IsNamedPlaylistModalIntent(intent))",
|
|
"// Keep the zero-timeout admission used by database and edit intents;");
|
|
Assert.Contains("_orderedNamedPlaylistIntentGate.WaitAsync(", queued,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains("0,", queued, StringComparison.Ordinal);
|
|
Assert.Contains("await _intentGate.WaitAsync", queued,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains("_orderedNamedPlaylistIntentGate.Release();", process,
|
|
StringComparison.Ordinal);
|
|
|
|
var classifier = Slice(
|
|
Window,
|
|
"private static bool IsNamedPlaylistModalIntent",
|
|
"private LegacyOperatorSnapshot ReportIntentFailure");
|
|
foreach (var intent in new[]
|
|
{
|
|
"LegacyRefreshNamedPlaylistsIntent",
|
|
"LegacySelectNamedPlaylistIntent",
|
|
"LegacyLoadSelectedNamedPlaylistIntent",
|
|
"LegacyLoadNamedPlaylistByIdIntent",
|
|
"LegacyCreateNamedPlaylistIntent",
|
|
"LegacySaveCurrentNamedPlaylistIntent",
|
|
"LegacySaveCurrentNamedPlaylistToIntent",
|
|
"LegacyDeleteSelectedNamedPlaylistIntent",
|
|
"LegacyDismissDialogIntent"
|
|
})
|
|
{
|
|
Assert.Contains(intent, classifier, StringComparison.Ordinal);
|
|
}
|
|
|
|
Assert.Contains("else if (intent is LegacyDismissDialogIntent)", process,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains("PostState(_controller.Current);", process,
|
|
StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void OneButtonResultDialogCannotLoseItsClickToBackgroundBusyState()
|
|
{
|
|
Assert.Contains(
|
|
"dialogOk.disabled = legacyDialogIsConfirmation && state.isBusy === true;",
|
|
Web,
|
|
StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void NamedPlaylistConfirmationReenablesBothActionsWhenItOpens()
|
|
{
|
|
var open = Slice(
|
|
Web,
|
|
"function openNamedPlaylistConfirmation",
|
|
"function restoreNamedPlaylistAfterConfirmation");
|
|
|
|
Assert.Contains("if (!options || isNamedPlaylistActionLocked()) return false;",
|
|
open,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains("namedPlaylistConfirmationYes.disabled = false;",
|
|
open,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains("namedPlaylistConfirmationNo.disabled = false;",
|
|
open,
|
|
StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void OpenNamedPlaylistConfirmationDoesNotLoseClickToProgramRefresh()
|
|
{
|
|
var render = Slice(
|
|
Web,
|
|
"function renderNamedPlaylist",
|
|
"function clearOperatorCatalogDragVisuals");
|
|
var confirmationLock = Slice(
|
|
render,
|
|
"namedPlaylistConfirmationYes.disabled =",
|
|
"if (deferredSelectionAction)");
|
|
|
|
Assert.Contains("pendingNamedPlaylistCommand !== null", confirmationLock,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains("namedPlaylistState.isWriteInProgress === true", confirmationLock,
|
|
StringComparison.Ordinal);
|
|
Assert.DoesNotContain("operatorMutationLocked", confirmationLock,
|
|
StringComparison.Ordinal);
|
|
Assert.DoesNotContain("uiBusy", confirmationLock,
|
|
StringComparison.Ordinal);
|
|
}
|
|
|
|
private static string Slice(string source, string startMarker, string endMarker)
|
|
{
|
|
var start = source.IndexOf(startMarker, StringComparison.Ordinal);
|
|
var end = source.IndexOf(endMarker, start + startMarker.Length,
|
|
StringComparison.Ordinal);
|
|
Assert.True(start >= 0, $"Missing source marker: {startMarker}");
|
|
Assert.True(end > start, $"Missing source marker: {endMarker}");
|
|
return source[start..end];
|
|
}
|
|
|
|
private static string FindRepositoryRoot()
|
|
{
|
|
var directory = new DirectoryInfo(AppContext.BaseDirectory);
|
|
while (directory is not null)
|
|
{
|
|
if (File.Exists(Path.Combine(directory.FullName, "MBN_STOCK_WEBVIEW.sln")))
|
|
{
|
|
return directory.FullName;
|
|
}
|
|
|
|
directory = directory.Parent;
|
|
}
|
|
|
|
throw new DirectoryNotFoundException("Could not locate the repository root.");
|
|
}
|
|
}
|