feat: consolidate legacy parity migration baseline
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
namespace MBN_STOCK_WEBVIEW.LegacyWeb.Tests;
|
||||
|
||||
public sealed class LegacyDatabaseHealthMonitorNativeContractTests
|
||||
{
|
||||
private static readonly string RepositoryRoot = FindRepositoryRoot();
|
||||
private static readonly string AppRoot = Path.Combine(
|
||||
RepositoryRoot,
|
||||
"src",
|
||||
"MBN_STOCK_WEBVIEW.LegacyParityApp");
|
||||
private static readonly string Window = File.ReadAllText(
|
||||
Path.Combine(AppRoot, "MainWindow.xaml.cs"));
|
||||
private static readonly string Monitor = File.ReadAllText(
|
||||
Path.Combine(AppRoot, "MainWindow.DatabaseHealth.cs"));
|
||||
private static readonly string Playout = File.ReadAllText(
|
||||
Path.Combine(AppRoot, "MainWindow.Playout.cs"));
|
||||
|
||||
[Fact]
|
||||
public void LegacyTenSecondMonitorStartsAndStopsWithTheActiveWindow()
|
||||
{
|
||||
Assert.Contains(
|
||||
"TimeSpan.FromSeconds(10)",
|
||||
Monitor,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains(
|
||||
"await Task.Delay(DatabaseHealthPollingInterval, cancellationToken)",
|
||||
Monitor,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains(
|
||||
"StartDatabaseHealthMonitor();",
|
||||
Window,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains(
|
||||
"_lifetimeCancellation.Cancel();\n CancelActiveDatabaseHealthCheck();",
|
||||
Normalize(Window),
|
||||
StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MonitorUsesBothConfiguredProvidersAndLogsOnlyClosedTransitions()
|
||||
{
|
||||
Assert.Contains(
|
||||
".HealthService\n .CheckAllAsync(healthCancellation.Token)",
|
||||
Normalize(Monitor),
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains(
|
||||
"foreach (var status in statuses)",
|
||||
Monitor,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains(
|
||||
"ObserveDatabaseHealthState(status.Source, status.State);",
|
||||
Monitor,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains(
|
||||
"_databaseHealthTransitions.TryObserveDatabaseState(",
|
||||
Monitor,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains(
|
||||
"_databaseHealthLogWriter.TryWrite(record)",
|
||||
Monitor,
|
||||
StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("status.UserMessage", Monitor, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("exception.Message", Monitor, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OperatorAndRefreshWorkCancelAndSerializeAgainstHealthProbes()
|
||||
{
|
||||
var dispatch = Slice(
|
||||
Window,
|
||||
"private async Task ProcessIntentAsync(",
|
||||
"private static bool IsNamedPlaylistModalIntent(");
|
||||
var databaseWait = RequiredIndex(
|
||||
dispatch,
|
||||
"await AcquirePriorityDatabaseActivityAsync(_lifetimeCancellation.Token)");
|
||||
var handle = RequiredIndex(dispatch, "await HandleIntentAsync(");
|
||||
Assert.True(databaseWait < handle);
|
||||
Assert.Contains("_databaseActivityGate.Release();", dispatch,
|
||||
StringComparison.Ordinal);
|
||||
|
||||
var refresh = Slice(
|
||||
Playout,
|
||||
"private async Task RunRefreshLoopAsync(",
|
||||
"private bool TrySetRefreshFault(");
|
||||
databaseWait = RequiredIndex(
|
||||
refresh,
|
||||
"await AcquirePriorityDatabaseActivityAsync(token)");
|
||||
var refreshCall = RequiredIndex(refresh, "workflow.RefreshOnAirAsync");
|
||||
Assert.True(databaseWait < refreshCall);
|
||||
Assert.Contains("_databaseActivityGate.Release();", refresh,
|
||||
StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OperatorPriorityClosesTheHealthProbeCancellationPublishRace()
|
||||
{
|
||||
var acquire = Slice(
|
||||
Monitor,
|
||||
"private async Task AcquirePriorityDatabaseActivityAsync(",
|
||||
"private void CancelActiveDatabaseHealthCheck()");
|
||||
var waiterIncrement = RequiredIndex(
|
||||
acquire,
|
||||
"Interlocked.Increment(ref _databaseActivityPriorityWaiterCount);");
|
||||
var cancel = RequiredIndex(acquire, "CancelActiveDatabaseHealthCheck();");
|
||||
var gateWait = RequiredIndex(
|
||||
acquire,
|
||||
"await _databaseActivityGate.WaitAsync(cancellationToken)");
|
||||
var waiterDecrement = RequiredIndex(
|
||||
acquire,
|
||||
"Interlocked.Decrement(ref _databaseActivityPriorityWaiterCount);");
|
||||
Assert.True(waiterIncrement < cancel);
|
||||
Assert.True(cancel < gateWait);
|
||||
Assert.True(gateWait < waiterDecrement);
|
||||
|
||||
var probe = Slice(
|
||||
Monitor,
|
||||
"private async Task CheckAndLogDatabaseHealthAsync(",
|
||||
"private async Task AcquirePriorityDatabaseActivityAsync(");
|
||||
var preAcquirePriorityCheck = RequiredIndex(
|
||||
probe,
|
||||
"Volatile.Read(ref _databaseActivityPriorityWaiterCount) != 0");
|
||||
var healthCancellationPublish = RequiredIndex(
|
||||
probe,
|
||||
"Interlocked.Exchange(\n ref _databaseHealthCheckCancellation,\n healthCancellation);");
|
||||
var postPublishPriorityCheck = RequiredIndex(
|
||||
probe,
|
||||
"Volatile.Read(ref _databaseActivityPriorityWaiterCount) != 0",
|
||||
healthCancellationPublish);
|
||||
var providerProbe = RequiredIndex(probe, ".CheckAllAsync(healthCancellation.Token)");
|
||||
Assert.True(preAcquirePriorityCheck < healthCancellationPublish);
|
||||
Assert.True(healthCancellationPublish < postPublishPriorityCheck);
|
||||
Assert.True(postPublishPriorityCheck < providerProbe);
|
||||
}
|
||||
|
||||
private static string Normalize(string value) =>
|
||||
value.Replace("\r\n", "\n", StringComparison.Ordinal);
|
||||
|
||||
private static string Slice(string value, string start, string end)
|
||||
{
|
||||
var startIndex = RequiredIndex(value, start);
|
||||
var endIndex = RequiredIndex(value, end, startIndex + start.Length);
|
||||
return value[startIndex..endIndex];
|
||||
}
|
||||
|
||||
private static int RequiredIndex(string value, string needle, int startIndex = 0)
|
||||
{
|
||||
var index = value.IndexOf(needle, startIndex, StringComparison.Ordinal);
|
||||
Assert.True(index >= 0, $"Required marker was not found: {needle}");
|
||||
return index;
|
||||
}
|
||||
|
||||
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("Repository root was not found.");
|
||||
}
|
||||
}
|
||||
@@ -86,6 +86,21 @@ public sealed class LegacyManualFinancialParityWebTests
|
||||
Assert.Contains("generation: generation", App, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GraphE_two_row_toolbar_keeps_find_controls_pointer_accessible()
|
||||
{
|
||||
Assert.Contains(
|
||||
".manual-financial-workspace { min-height: 0; display: grid; " +
|
||||
"grid-template-rows: auto minmax(0, 1fr);",
|
||||
Styles,
|
||||
StringComparison.Ordinal);
|
||||
Assert.DoesNotContain(
|
||||
".manual-financial-workspace { min-height: 0; display: grid; " +
|
||||
"grid-template-rows: 38px minmax(0, 1fr);",
|
||||
Styles,
|
||||
StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Manual_Web_section_sends_values_and_opaque_ids_without_DB_or_scene_authority()
|
||||
{
|
||||
@@ -113,7 +128,9 @@ public sealed class LegacyManualFinancialParityWebTests
|
||||
Assert.Contains("LegacyDeleteManualFinancialIntent", MainWindow, StringComparison.Ordinal);
|
||||
Assert.Contains("LegacyDeleteAllManualFinancialIntent", MainWindow, StringComparison.Ordinal);
|
||||
Assert.Contains("_intentGate.WaitAsync(", MainWindow, StringComparison.Ordinal);
|
||||
Assert.Contains("0,\n _lifetimeCancellation.Token", MainWindow, StringComparison.Ordinal);
|
||||
Assert.Matches(
|
||||
new Regex(@"_intentGate\.WaitAsync\(\s*0,\s*_lifetimeCancellation\.Token\)"),
|
||||
MainWindow);
|
||||
Assert.DoesNotContain("SaveManualFinancialAsync(", MainWindow[..MainWindow.IndexOf(
|
||||
"HandleIntentAsync",
|
||||
StringComparison.Ordinal)], StringComparison.Ordinal);
|
||||
|
||||
@@ -72,6 +72,49 @@ public sealed class LegacyPlayoutNativeContractTests
|
||||
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 AutomaticRefreshUsesTheCoreSchedulerAndGenerationOwnedState()
|
||||
{
|
||||
@@ -291,7 +334,7 @@ public sealed class LegacyPlayoutNativeContractTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PreparedProgramAndUnknownWriteOutcomesBlockOperatorMutations()
|
||||
public void PreparedProgramBlocksCutAppendButAllowsPureCutSelection()
|
||||
{
|
||||
Assert.Contains("CanAcceptOperatorMutation()", Window, StringComparison.Ordinal);
|
||||
Assert.Contains("IsOperatorMutationQuarantined()", Window,
|
||||
@@ -308,9 +351,17 @@ public sealed class LegacyPlayoutNativeContractTests
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("LegacyConfirmManualListIntent", Playout,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("LegacyCutPointerDownIntent", Playout,
|
||||
var mutationClassifier = Slice(
|
||||
Playout,
|
||||
"private static bool IsOperatorMutationIntent",
|
||||
"private static bool IsFixedSectionBatchMutationIntent");
|
||||
Assert.Contains("LegacyCutPointerDownIntent { AllowAppend: true }", mutationClassifier,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("LegacyClearCutSelectionIntent", Playout,
|
||||
Assert.DoesNotContain("LegacyCutKeyDownIntent", mutationClassifier,
|
||||
StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("LegacyClearCutSelectionIntent", mutationClassifier,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("pointer.AllowAppend", Window,
|
||||
StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ public sealed class LegacyRowDoubleClickParityTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Theme_double_click_is_atomic_while_single_click_selects_immediately()
|
||||
public void Theme_double_click_is_atomic_and_cancels_the_delayed_single_click()
|
||||
{
|
||||
var doubleClick = Extract(
|
||||
"categoryTree.addEventListener(\"dblclick\"",
|
||||
@@ -55,12 +55,17 @@ public sealed class LegacyRowDoubleClickParityTests
|
||||
StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("send(\"select-theme\"", doubleClick,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("clearDelayedClick(themeResultClickTimer)", doubleClick,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains(
|
||||
"send(\"select-theme\", { resultId: themeResult.dataset.themeResultId });",
|
||||
"send(\"select-theme\", { resultId: resultId });",
|
||||
themeClick,
|
||||
StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("window.setTimeout", themeClick, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("themeResultClickTimer", App, StringComparison.Ordinal);
|
||||
Assert.Contains("clearDelayedClick(themeResultClickTimer)", themeClick,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("themeResultClickTimer = window.setTimeout", themeClick,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("}, 250);", themeClick, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@@ -28,6 +28,7 @@ public sealed class LegacyWebContractTests
|
||||
"moving-average-5",
|
||||
"moving-average-20",
|
||||
"cut-list",
|
||||
"cut-drag-feedback",
|
||||
"playlist-drop-zone",
|
||||
"playlist-rows",
|
||||
"playlist-move-up",
|
||||
@@ -77,7 +78,7 @@ public sealed class LegacyWebContractTests
|
||||
Assert.Contains("timestampMilliseconds", App, StringComparison.Ordinal);
|
||||
Assert.Contains("event.ctrlKey", App, StringComparison.Ordinal);
|
||||
Assert.Contains("event.shiftKey", App, StringComparison.Ordinal);
|
||||
Assert.Contains("if (playlistMutationLocked) return", App,
|
||||
Assert.Contains("allowAppend: !playlistMutationLocked", App,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("send(\"clear-cut-selection\", {})", App,
|
||||
StringComparison.Ordinal);
|
||||
@@ -432,7 +433,7 @@ public sealed class LegacyWebContractTests
|
||||
public void SeparatorRowsPreserveOriginalDragGesture()
|
||||
{
|
||||
Assert.Contains(
|
||||
"element.dataset.cutDragEnabled = cutSelectionEnabled ? \"true\" : \"false\"",
|
||||
"element.dataset.cutDragEnabled = cutSelectionEnabled && !cutDragLocked",
|
||||
App,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("element.draggable = false", App, StringComparison.Ordinal);
|
||||
@@ -440,6 +441,22 @@ public sealed class LegacyWebContractTests
|
||||
StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CutDragFeedbackFollowsTheCapturedPointerWithoutOwningInput()
|
||||
{
|
||||
Assert.Contains("id=\"cut-drag-feedback\"", Markup, StringComparison.Ordinal);
|
||||
Assert.Contains("aria-hidden=\"true\"", Markup, StringComparison.Ordinal);
|
||||
Assert.Contains("function showCutDragFeedback", App, StringComparison.Ordinal);
|
||||
Assert.Contains("cutDragFeedback.dataset.dropAllowed", App,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("showCutDragFeedback(event, dropAllowed)", App,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains("cutDragFeedback.hidden = true", App,
|
||||
StringComparison.Ordinal);
|
||||
Assert.Contains(".cut-drag-feedback", Styles, StringComparison.Ordinal);
|
||||
Assert.Contains("pointer-events: none", Styles, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BusySnapshotFreezesControlsWithoutQueueingInput()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user