using System.Text.RegularExpressions; namespace MBN_STOCK_WEBVIEW.LegacyWeb.Tests; public sealed class LegacyManualFinancialParityWebTests { private static readonly string RepositoryRoot = FindRepositoryRoot(); private static readonly string WebRoot = Path.Combine( RepositoryRoot, "src", "MBN_STOCK_WEBVIEW.LegacyParityApp", "Web"); private static readonly string Markup = File.ReadAllText(Path.Combine(WebRoot, "index.html")); private static readonly string App = File.ReadAllText(Path.Combine(WebRoot, "app.js")); private static readonly string Styles = File.ReadAllText(Path.Combine(WebRoot, "styles.css")); private static readonly string MainWindow = File.ReadAllText(Path.Combine( RepositoryRoot, "src", "MBN_STOCK_WEBVIEW.LegacyParityApp", "MainWindow.xaml.cs")); [Theory] [InlineData("revenue-composition", "주요매출 구성")] [InlineData("growth-metrics", "성장성 지표")] [InlineData("sales", "매출액")] [InlineData("operating-profit", "영업이익")] public void Original_left_GraphE_buttons_are_enabled_closed_screen_intents( string screen, string label) { Assert.Matches( $"]*disabled)[^>]*data-manual-screen=\"{screen}\"[^>]*>{label}", Markup); } [Fact] public void Modal_exposes_list_stock_editor_CRUD_and_playlist_controls() { foreach (var id in new[] { "manual-financial-modal", "manual-financial-title", "manual-financial-close", "manual-financial-workspace" }) { Assert.Contains($"id=\"{id}\"", Markup, StringComparison.Ordinal); } foreach (var intent in new[] { "open-manual-financial", "close-manual-financial", "search-manual-financial", "find-manual-financial", "toggle-manual-financial-name-sort", "load-manual-financial", "begin-manual-financial-create", "search-manual-financial-stocks", "select-manual-financial-stock", "save-manual-financial", "delete-manual-financial", "delete-all-manual-financial", "activate-manual-financial-action" }) { Assert.Contains($"\"{intent}\"", App, StringComparison.Ordinal); } Assert.Contains(".manual-financial-dialog", Styles, StringComparison.Ordinal); Assert.Contains(".manual-financial-grid", Styles, StringComparison.Ordinal); } [Fact] public void GraphE_find_and_name_header_sort_are_generation_bound_native_intents() { Assert.Contains("manual-financial-find-query", App, StringComparison.Ordinal); Assert.Contains("dataset.manualFindDirection", App, StringComparison.Ordinal); Assert.Contains("dataset.manualNameSort", App, StringComparison.Ordinal); Assert.Contains("dataset.manualGeneration", App, StringComparison.Ordinal); Assert.Contains("send(\"find-manual-financial\"", App, StringComparison.Ordinal); Assert.Contains( "send(\"toggle-manual-financial-name-sort\"", App, StringComparison.Ordinal); 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() { var start = App.IndexOf("function blankManualRecord", StringComparison.Ordinal); var end = App.IndexOf("function renderDialog", start, StringComparison.Ordinal); Assert.True(start >= 0 && end > start); var manualSection = App[start..end]; Assert.DoesNotMatch( new Regex("(?:INPUT_PIE|INPUT_GROW|INPUT_SELL|INPUT_PROFIT|s5076|s5079|s5080|s5081|rowVersion|builderKey|cutCode|dataCode|confirmationToken)"), manualSection); Assert.Contains("dataset.manualResultId", manualSection, StringComparison.Ordinal); Assert.Contains("dataset.manualStockResultId", manualSection, StringComparison.Ordinal); Assert.Contains("dataset.manualActionId", manualSection, StringComparison.Ordinal); } [Fact] public void MainWindow_composes_real_read_and_one_shot_write_services_and_busy_dispatch() { Assert.Contains("new LegacyManualFinancialScreenService(", MainWindow, StringComparison.Ordinal); Assert.Contains("new OracleManualFinancialMutationExecutor(", MainWindow, StringComparison.Ordinal); Assert.Contains("new LegacyStockSearchService(", MainWindow, StringComparison.Ordinal); Assert.Contains("manualFinancialWorkflow: new LegacyManualFinancialWorkflow(", MainWindow, StringComparison.Ordinal); Assert.Contains("LegacySaveManualFinancialIntent", MainWindow, StringComparison.Ordinal); Assert.Contains("LegacyDeleteManualFinancialIntent", MainWindow, StringComparison.Ordinal); Assert.Contains("LegacyDeleteAllManualFinancialIntent", MainWindow, StringComparison.Ordinal); Assert.Contains("_intentGate.WaitAsync(", 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); } 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."); } }