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 FolderPicker = File.ReadAllText( Path.Combine(AppRoot, "MainWindow.BackgroundPicker.cs")); private static readonly string Playout = File.ReadAllText( Path.Combine(AppRoot, "MainWindow.Playout.cs")); [Fact] public void FolderPathsComeOnlyFromTheWindowOwnedNativePicker() { Assert.Contains( "var initialDirectory = ResolveOperatorFolderPickerStartDirectory(kind)", Settings, StringComparison.Ordinal); Assert.Contains("await PickOperatorFolderAsync(", Settings, StringComparison.Ordinal); Assert.Contains("LegacyFileDialog.ShowFolder(", FolderPicker, StringComparison.Ordinal); Assert.Contains("WindowNative.GetWindowHandle(this)", FolderPicker, StringComparison.Ordinal); Assert.Contains("FileOpenOptions.PickFolders", FolderPicker, StringComparison.Ordinal); Assert.Contains("FileOpenOptions.ForceFileSystem", FolderPicker, StringComparison.Ordinal); Assert.Contains("FileOpenOptions.PathMustExist", FolderPicker, StringComparison.Ordinal); Assert.Contains("FileOpenOptions.NoDereferenceLinks", FolderPicker, StringComparison.Ordinal); Assert.Contains("dialog.SetFolder(initialFolder);", FolderPicker, StringComparison.Ordinal); Assert.Contains("dialog.SetDefaultFolder(initialFolder);", FolderPicker, StringComparison.Ordinal); Assert.Contains("selectedPath", Settings, StringComparison.Ordinal); Assert.Contains("LegacyOperatorFolderValidator.TryValidate(", Settings, StringComparison.Ordinal); Assert.DoesNotContain("PickerLocationId.ComputerFolder", Settings, StringComparison.Ordinal); Assert.DoesNotContain("intent.Path", Settings, StringComparison.Ordinal); Assert.DoesNotContain("choose.Path", Settings, StringComparison.Ordinal); } [Fact] public void FolderPickerStartsAtTheLatestSavedPathOrItsNearestExistingParent() { var resolver = Slice( Settings, "private string? ResolveOperatorFolderPickerStartDirectory(", "private static string ResolveOperatorFolderPickerTitle("); Assert.Contains("_operatorSettings.SceneDirectory", resolver, StringComparison.Ordinal); Assert.Contains("_operatorSettings.ResourceDirectory", resolver, StringComparison.Ordinal); Assert.Contains("_operatorSettings.BackgroundDirectory", resolver, StringComparison.Ordinal); Assert.DoesNotContain("_appliedOperatorSettings", resolver, StringComparison.Ordinal); Assert.Contains("Path.Combine(AppContext.BaseDirectory, \"Cuts\")", resolver, StringComparison.Ordinal); Assert.Contains("Path.Combine(AppContext.BaseDirectory, \"Res\")", resolver, StringComparison.Ordinal); Assert.Contains("ResolveAutomaticBackgroundDirectory()", resolver, StringComparison.Ordinal); Assert.Contains("FindNearestExistingDirectory(preferredPath)", resolver, StringComparison.Ordinal); Assert.Contains("candidate = candidate.Parent", resolver, StringComparison.Ordinal); Assert.Contains("FindNearestExistingDirectory(AppContext.BaseDirectory)", resolver, StringComparison.Ordinal); } [Fact] public void FolderPickerTitleAndButtonRemainCompatibleWithTheLocalStateSmoke() { Assert.Contains("\"폴더 선택 - 디자인\"", Settings, StringComparison.Ordinal); Assert.Contains("\"폴더 선택 - 설정\"", Settings, StringComparison.Ordinal); Assert.Contains("\"폴더 선택 - 배경\"", Settings, StringComparison.Ordinal); Assert.Contains("dialog.SetOkButtonLabel(\"폴더 선택\")", FolderPicker, 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 (selectedPath 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."); } }