using System.Globalization; using System.Text.Json; using MBN_STOCK_WEBVIEW.LegacyApplication; using MMoneyCoderSharp.Data; namespace MBN_STOCK_WEBVIEW.LegacyBridge.Tests; public sealed class LegacyThemeBridgeTests { [Fact] public async Task ProjectionPreservesFiveThousandRowsAndExplicitTruncationWarningState() { var workflow = new LegacyThemeWorkflow(new TruncatedThemeService()); var theme = await workflow.SearchAsync( workflow.CreateInitial(), string.Empty, ThemeSession.PreMarket); var snapshot = new LegacyOperatorSnapshot( 1, string.Empty, [], null, [], [], null, "테마 검색 결과가 최대 5,000건으로 제한되었습니다.", LegacyOperatorStatusKind.Warning, Theme: theme); using var document = JsonDocument.Parse( LegacyBridgeProtocol.SerializeState(snapshot)); var payload = document.RootElement.GetProperty("payload"); var projected = payload.GetProperty("theme"); Assert.True(projected.GetProperty("searchIsTruncated").GetBoolean()); Assert.Equal(5_000, projected.GetProperty("searchResults").GetArrayLength()); Assert.Equal("warning", payload.GetProperty("statusKind").GetString()); Assert.Contains("5,000", payload.GetProperty("statusMessage").GetString()); Assert.DoesNotContain("themeCode", projected.GetRawText(), StringComparison.OrdinalIgnoreCase); } [Fact] public async Task ProjectionPreservesRawLegacyTitlesExplicitMarketAndEmptyPreviewGuards() { var workflow = new LegacyThemeWorkflow(new CompatibilityThemeService()); var search = await workflow.SearchAsync( workflow.CreateInitial(), string.Empty, ThemeSession.PreMarket); var theme = await workflow.SelectAsync(search, "theme-result-005"); var snapshot = new LegacyOperatorSnapshot( 1, string.Empty, [], null, [], [], null, "Theme compatibility", LegacyOperatorStatusKind.Information, Theme: theme); using var document = JsonDocument.Parse( LegacyBridgeProtocol.SerializeState(snapshot)); var projected = document.RootElement.GetProperty("payload").GetProperty("theme"); var rows = projected.GetProperty("searchResults").EnumerateArray().ToArray(); Assert.Equal(5, rows.Length); Assert.Equal(" Legacy ", rows[0].GetProperty("displayTitle").GetString()); Assert.Equal("Same", rows[1].GetProperty("displayTitle").GetString()); Assert.Equal("Same", rows[2].GetProperty("displayTitle").GetString()); Assert.Equal("Desk(NXT)", rows[3].GetProperty("displayTitle").GetString()); Assert.Equal("krx", rows[3].GetProperty("market").GetString()); Assert.Equal(" Empty NXT(NXT)", rows[4].GetProperty("displayTitle").GetString()); Assert.Equal("nxt", rows[4].GetProperty("market").GetString()); Assert.Equal(0, projected.GetProperty("previewItems").GetArrayLength()); Assert.All(projected.GetProperty("actions").EnumerateArray(), action => { Assert.False(action.GetProperty("isAvailable").GetBoolean()); Assert.Equal( "theme-preview-is-empty", action.GetProperty("unavailableReason").GetString()); }); Assert.DoesNotContain("themeCode", projected.GetRawText(), StringComparison.OrdinalIgnoreCase); } private sealed class TruncatedThemeService : IThemeSelectionService { public Task SearchAsync( string query, ThemeSession nxtSession, int maximumResults = LegacyThemeSelectionService.DefaultMaximumResults, CancellationToken cancellationToken = default) { Assert.Equal(LegacyThemeWorkflow.MaximumSearchResults, maximumResults); var rows = Enumerable.Range(0, maximumResults) .Select(index => new ThemeSelectorItem( new ThemeSelectionIdentity( ThemeMarket.Krx, ThemeSession.NotApplicable, index.ToString("D8", CultureInfo.InvariantCulture), $"Theme {index}"), DataSourceKind.Oracle)) .ToArray(); return Task.FromResult(new ThemeSearchResult( query, nxtSession, DateTimeOffset.UtcNow, rows, IsTruncated: true)); } public Task PreviewAsync( ThemeSelectionIdentity identity, int maximumItems = LegacyThemeSelectionService.DefaultMaximumPreviewItems, CancellationToken cancellationToken = default) => Task.FromResult(new ThemePreviewResult( identity, DateTimeOffset.UtcNow, [], IsTruncated: false)); } private sealed class CompatibilityThemeService : IThemeSelectionService { public Task SearchAsync( string query, ThemeSession nxtSession, int maximumResults = LegacyThemeSelectionService.DefaultMaximumResults, CancellationToken cancellationToken = default) => Task.FromResult(new ThemeSearchResult( query, nxtSession, DateTimeOffset.UtcNow, [ Item(ThemeMarket.Krx, ThemeSession.NotApplicable, "00000001", " Legacy "), Item(ThemeMarket.Krx, ThemeSession.NotApplicable, "00000002", "Same"), Item(ThemeMarket.Krx, ThemeSession.NotApplicable, "00000003", "Same"), Item(ThemeMarket.Krx, ThemeSession.NotApplicable, "00000004", "Desk(NXT)"), Item(ThemeMarket.Nxt, nxtSession, "00000005", " Empty NXT") ], IsTruncated: false)); public Task PreviewAsync( ThemeSelectionIdentity identity, int maximumItems = LegacyThemeSelectionService.DefaultMaximumPreviewItems, CancellationToken cancellationToken = default) => Task.FromResult(new ThemePreviewResult( identity, DateTimeOffset.UtcNow, [], IsTruncated: false)); private static ThemeSelectorItem Item( ThemeMarket market, ThemeSession session, string code, string title) => new( new ThemeSelectionIdentity(market, session, code, title), market == ThemeMarket.Krx ? DataSourceKind.Oracle : DataSourceKind.MariaDb); } }