using System.Text.Json; using MBN_STOCK_WEBVIEW.Core.Playout.Scenes; using MBN_STOCK_WEBVIEW.LegacyApplication; namespace MBN_STOCK_WEBVIEW.LegacyBridge.Tests; public sealed class LegacyManualListsBridgeTests { [Fact] public void OriginalOkActionHasOneClosedEmptyPayloadIntent() { Assert.True(LegacyBridgeProtocol.TryParseIntent( "{\"type\":\"confirm-manual-list\",\"payload\":{}}", out var intent, out _)); Assert.IsType(intent); Assert.False(LegacyBridgeProtocol.TryParseIntent( "{\"type\":\"confirm-manual-list\",\"payload\":{\"retry\":true}}", out _, out _)); } [Theory] [InlineData("individual", LegacyManualListScreen.NetSell, S5025ManualAudience.Individual)] [InlineData("foreign", LegacyManualListScreen.NetSell, S5025ManualAudience.Foreign)] [InlineData("institution", LegacyManualListScreen.NetSell, S5025ManualAudience.Institution)] [InlineData("vi", LegacyManualListScreen.Vi, S5025ManualAudience.Individual)] public void Open_accepts_only_closed_screen_identifiers( string screen, LegacyManualListScreen expectedScreen, S5025ManualAudience expectedAudience) { var json = JsonSerializer.Serialize(new { type = "open-manual-list", payload = new { screen } }); Assert.True(LegacyBridgeProtocol.TryParseIntent(json, out var intent, out _)); var opened = Assert.IsType(intent); Assert.Equal(expectedScreen, opened.Screen); Assert.Equal(expectedAudience, opened.Audience); Assert.False(LegacyBridgeProtocol.TryParseIntent( "{\"type\":\"open-manual-list\",\"payload\":{\"screen\":\"vi\",\"path\":\"C:\\\\Data\"}}", out _, out _)); } [Fact] public void Net_cell_accepts_one_opaque_row_and_safe_value_only() { Assert.True(LegacyBridgeProtocol.TryParseIntent( "{\"type\":\"set-manual-net-sell-cell\",\"payload\":{\"rowId\":\"manual-net-row-1\",\"field\":\"leftAmount\",\"value\":\"1,000\"}}", out var intent, out _)); var cell = Assert.IsType(intent); Assert.Equal(LegacyManualNetSellField.LeftAmount, cell.Field); foreach (var invalid in new[] { "{\"rowId\":\"manual-net-row-1\",\"field\":\"leftAmount\",\"value\":\"bad^value\"}", "{\"rowId\":\"manual-net-row-1\",\"field\":\"leftAmount\",\"value\":\"1\",\"audience\":\"FOREIGN\"}", "{\"rowId\":\"manual-net-row-1\",\"field\":\"code\",\"value\":\"005930\"}" }) { Assert.False(LegacyBridgeProtocol.TryParseIntent( $"{{\"type\":\"set-manual-net-sell-cell\",\"payload\":{invalid}}}", out _, out _)); } } [Fact] public void VI_mutations_accept_opaque_ids_and_never_codes_items_or_versions() { Assert.True(Parse("select-manual-vi-result", "{\"resultId\":\"manual-vi-result-0001\"}")); Assert.True(Parse("add-manual-vi-result", "{\"resultId\":\"manual-vi-result-0001\"}")); Assert.True(Parse("move-manual-vi-item", "{\"itemId\":\"manual-vi-item-0001\",\"direction\":\"up\"}")); Assert.True(Parse("delete-manual-vi-item", "{\"itemId\":\"manual-vi-item-0001\"}")); Assert.True(Parse("save-manual-vi", "{}")); Assert.False(Parse("save-manual-vi", "{\"version\":\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"}")); Assert.False(Parse("add-manual-vi-result", "{\"code\":\"005930\",\"name\":\"삼성전자\"}")); } [Fact] public void State_projects_display_rows_but_not_native_codes_versions_or_paths() { var viItems = Enumerable.Range(1, 9) .Select(index => new LegacyManualViItemView( $"manual-vi-item-{index}", index, $"VI종목{index}")) .ToArray(); var manual = new LegacyManualListsSnapshot( true, LegacyManualListScreen.Vi, S5025ManualAudience.Individual, true, "READY", null, false, Array.Empty(), false, viItems, 2, true, "삼성", [new LegacyManualViSearchResultView( "manual-vi-result-1", "삼성전자", "코스피")], "조회 완료", LegacyOperatorStatusKind.Information, true, true) { SelectedSearchResultId = "manual-vi-result-1" }; var snapshot = new LegacyOperatorSnapshot( 1, string.Empty, Array.Empty(), null, Array.Empty(), Array.Empty(), null, string.Empty, LegacyOperatorStatusKind.Neutral, ManualLists: manual); var json = LegacyBridgeProtocol.SerializeState(snapshot); using var document = JsonDocument.Parse(json); var projected = document.RootElement.GetProperty("payload").GetProperty("manualLists"); Assert.Equal( "manual-vi-result-1", projected.GetProperty("selectedSearchResultId").GetString()); Assert.True(projected.GetProperty("isOpen").GetBoolean()); Assert.Equal(9, projected.GetProperty("viItems").GetArrayLength()); Assert.Equal("VI종목1", projected.GetProperty("viItems")[0].GetProperty("name").GetString()); Assert.Equal(2, projected.GetProperty("viPageCount").GetInt32()); Assert.True(projected.GetProperty("viItemsAreFresh").GetBoolean()); Assert.True(projected.GetProperty("canSave").GetBoolean()); Assert.True(projected.GetProperty("canMaterializePlaylist").GetBoolean()); Assert.False(projected.TryGetProperty("rowVersion", out _)); Assert.DoesNotContain("005930", projected.GetRawText(), StringComparison.Ordinal); Assert.DoesNotContain("path", projected.GetRawText(), StringComparison.OrdinalIgnoreCase); Assert.DoesNotContain("version", projected.GetRawText(), StringComparison.OrdinalIgnoreCase); } private static bool Parse(string type, string payload) => LegacyBridgeProtocol.TryParseIntent( $"{{\"type\":\"{type}\",\"payload\":{payload}}}", out _, out _); }