212 lines
8.8 KiB
C#
212 lines
8.8 KiB
C#
namespace MBN_STOCK_WEBVIEW.LegacyWeb.Tests;
|
|
|
|
public sealed class LegacyOperatorSettingsNativeContractTests
|
|
{
|
|
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 Settings = File.ReadAllText(
|
|
Path.Combine(AppRoot, "MainWindow.Settings.cs"));
|
|
private static readonly string Playout = File.ReadAllText(
|
|
Path.Combine(AppRoot, "MainWindow.Playout.cs"));
|
|
|
|
[Fact]
|
|
public void FolderPathsComeOnlyFromTheWindowOwnedNativePicker()
|
|
{
|
|
Assert.Contains("var picker = new FolderPicker", Settings, StringComparison.Ordinal);
|
|
Assert.Contains("picker.FileTypeFilter.Add(\"*\")", Settings,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains("InitializeWithWindow.Initialize(picker, owner);", Settings,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains("await picker.PickSingleFolderAsync()", Settings,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains("selected.Path", Settings, StringComparison.Ordinal);
|
|
Assert.Contains("LegacyOperatorFolderValidator.TryValidate(", Settings,
|
|
StringComparison.Ordinal);
|
|
Assert.DoesNotContain("intent.Path", Settings, StringComparison.Ordinal);
|
|
Assert.DoesNotContain("choose.Path", Settings, StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void SelectedFoldersAreLoadedAtStartupAndAppliedOnlyAtCompositionBoundaries()
|
|
{
|
|
Assert.Contains("_operatorSettingsStore.Load()", Window, StringComparison.Ordinal);
|
|
Assert.Contains("_appliedOperatorSettings = operatorSettingsLoad.Settings", Window,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains("ResolveFromResourceDirectory(", Window, StringComparison.Ordinal);
|
|
Assert.Contains("preferLegacyOverride: selectedLegacyDatabaseIni is not null", Window,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains(
|
|
"operatorSceneDirectory: _appliedOperatorSettings.SceneDirectory",
|
|
Playout,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains(
|
|
"operatorBackgroundDirectory: _appliedOperatorSettings.BackgroundDirectory",
|
|
Playout,
|
|
StringComparison.Ordinal);
|
|
Assert.DoesNotContain("InitializePlayoutRuntime();", Settings, StringComparison.Ordinal);
|
|
Assert.DoesNotContain("CreateLegacyExecutableDefault(", Settings,
|
|
StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void GateAUsesOnlyThePinnedJsonDatabaseProfile()
|
|
{
|
|
var databaseComposition = Slice(
|
|
Window,
|
|
"string? initializationError = null;",
|
|
"DataQueryExecutor.Configure(_databaseRuntime.Executor);");
|
|
var gateA = RequiredIndex(
|
|
databaseComposition,
|
|
"_playoutLaunchAuthorization.IsGateA");
|
|
var pinnedJson = RequiredIndex(
|
|
databaseComposition,
|
|
"DatabaseRuntime.CreateDefault()",
|
|
gateA);
|
|
var legacyIni = RequiredIndex(
|
|
databaseComposition,
|
|
"DatabaseRuntime.CreateLegacyExecutableDefault(",
|
|
pinnedJson);
|
|
|
|
Assert.True(gateA < pinnedJson);
|
|
Assert.True(pinnedJson < legacyIni);
|
|
}
|
|
|
|
[Fact]
|
|
public void SettingsWritesAreGateABlockedAndDoNotWaitForDatabaseHealthActivity()
|
|
{
|
|
var process = Slice(
|
|
Window,
|
|
"private async Task ProcessIntentAsync(LegacyUiIntent intent)",
|
|
"private static bool IsOrderedPlayoutIntent");
|
|
var gateABlock = RequiredIndex(process, "IsPersistentWriteIntent(intent)");
|
|
var settingsDispatch = RequiredIndex(
|
|
process,
|
|
"await HandleOperatorSettingsIntentAsync(",
|
|
gateABlock);
|
|
var databaseWait = RequiredIndex(
|
|
process,
|
|
"await AcquirePriorityDatabaseActivityAsync(_lifetimeCancellation.Token)");
|
|
|
|
Assert.True(gateABlock < settingsDispatch);
|
|
Assert.True(settingsDispatch < databaseWait);
|
|
Assert.Contains("HandleOperatorSettingsIntentAsync(", process,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains("LegacyChooseOperatorFolderIntent", Playout,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains("LegacyResetOperatorFolderIntent", Playout,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains("LegacySetOperatorNavigationExpandedIntent", Playout,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains("LegacySetOperatorAppearanceIntent", Playout,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains("ReconcileRejectedOperatorSettingsIntent(", process,
|
|
StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void AppearanceIntentIsPersistedRoutedAndProjectedAsOneClosedUpdate()
|
|
{
|
|
Assert.Contains(
|
|
"case LegacySetOperatorAppearanceIntent appearance:",
|
|
Settings,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains("ColorTheme = appearance.ColorTheme", Settings,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains("ViewMode = appearance.ViewMode", Settings,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains("StartWorkspace = appearance.StartWorkspace", Settings,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains("_operatorSettings.ColorTheme", Settings,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains("_operatorSettings.ViewMode", Settings,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains("_operatorSettings.StartWorkspace", Settings,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains("LegacySetOperatorAppearanceIntent", Window,
|
|
StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void SettingsStateIsProjectedWithoutPublishingFullNativePaths()
|
|
{
|
|
Assert.Contains("operatorSettings: CreateOperatorSettingsSnapshot()", Window,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains("AbbreviatedPath", Settings, StringComparison.Ordinal);
|
|
Assert.DoesNotContain("CanonicalPath,\n _operatorSettingsMessage", Settings,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains("DatabasePollingSeconds: (int)DatabaseHealthPollingInterval.TotalSeconds",
|
|
Settings,
|
|
StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void FailedSettingsSaveRevisionsTheSnapshotToUndoOptimisticNavigation()
|
|
{
|
|
Assert.Contains(
|
|
"if (!result.Succeeded || result.SavedSettings is null)",
|
|
Settings,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains(
|
|
"Interlocked.Increment(ref _operatorSettingsRevision);",
|
|
Settings,
|
|
StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void SettingsUsesConciseRoutineStatusCopy()
|
|
{
|
|
var cancelledPicker = Slice(
|
|
Settings,
|
|
"if (selected is null)",
|
|
"cancellationToken.ThrowIfCancellationRequested();");
|
|
|
|
Assert.DoesNotContain(
|
|
"SetOperatorSettingsMessage",
|
|
cancelledPicker,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains("\"저장됨\"", Settings, StringComparison.Ordinal);
|
|
Assert.Contains("\"저장됨 · 재시작 필요\"", Settings, StringComparison.Ordinal);
|
|
Assert.Contains("\"초기화됨 · 재시작 필요\"", Settings, StringComparison.Ordinal);
|
|
Assert.Contains("\"앱 기본값\"", Settings, StringComparison.Ordinal);
|
|
Assert.Contains("\"자동\"", Settings, StringComparison.Ordinal);
|
|
Assert.Contains("\"사용 가능\"", Settings, StringComparison.Ordinal);
|
|
Assert.DoesNotContain("외부 영상", Settings, StringComparison.Ordinal);
|
|
Assert.DoesNotContain("핵심 자산 확인됨", Settings, 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.");
|
|
}
|
|
}
|