feat: advance legacy UI behavior parity

This commit is contained in:
2026-07-18 10:18:29 +09:00
parent d7ec571343
commit 1302b1b92f
71 changed files with 11244 additions and 1153 deletions

View File

@@ -295,7 +295,7 @@ public sealed class LegacyBridgeProtocolTests
}
[Fact]
public void ParseIndustryIntents_AcceptsOnlyIndexAndOpaqueActionId()
public void ParseIndustryIntents_AcceptsOnlyClosedSelectionTextAndOpaqueActionId()
{
Assert.True(LegacyBridgeProtocol.TryParseIntent(
"{\"type\":\"select-industry\",\"payload\":{\"index\":2}}",
@@ -325,22 +325,53 @@ public sealed class LegacyBridgeProtocolTests
out _));
Assert.IsType<LegacySwapIndustriesIntent>(swap);
Assert.True(LegacyBridgeProtocol.TryParseIntent(
"{\"type\":\"set-industry-comparison-text\",\"payload\":{\"slot\":\"first\",\"value\":\"직접 입력_%\"}}",
out var edit,
out _));
var editIntent = Assert.IsType<LegacySetIndustryComparisonTextIntent>(edit);
Assert.Equal(LegacyIndustryComparisonSlot.First, editIntent.Slot);
Assert.Equal("직접 입력_%", editIntent.Value);
Assert.True(LegacyBridgeProtocol.TryParseIntent(
"{\"type\":\"set-industry-comparison-text\",\"payload\":{\"slot\":\"second\",\"value\":\"\"}}",
out var clear,
out _));
Assert.Equal(string.Empty,
Assert.IsType<LegacySetIndustryComparisonTextIntent>(clear).Value);
Assert.False(LegacyBridgeProtocol.TryParseIntent(
"{\"type\":\"activate-industry-action\",\"payload\":{\"actionId\":\"../5001\"}}",
out _,
out _));
Assert.False(LegacyBridgeProtocol.TryParseIntent(
"{\"type\":\"set-industry-comparison-text\",\"payload\":{\"slot\":\"third\",\"value\":\"업종\"}}",
out _,
out _));
Assert.False(LegacyBridgeProtocol.TryParseIntent(
"{\"type\":\"set-industry-comparison-text\",\"payload\":{\"slot\":\"first\",\"value\":\"업종\\n이름\"}}",
out _,
out _));
Assert.False(LegacyBridgeProtocol.TryParseIntent(
"{\"type\":\"set-industry-comparison-text\",\"payload\":{\"slot\":\"first\",\"value\":\"업종\",\"actionId\":\"two-column\"}}",
out _,
out _));
var oversized = new string('가',
LegacyIndustrySelectionWorkflow.MaximumComparisonTextLength + 1);
var oversizedJson = "{\"type\":\"set-industry-comparison-text\",\"payload\":{\"slot\":\"first\",\"value\":" +
System.Text.Json.JsonSerializer.Serialize(oversized) + "}}";
Assert.False(LegacyBridgeProtocol.TryParseIntent(oversizedJson, out _, out _));
}
[Fact]
public void ParseThemeIntents_UsesClosedSessionSortAndOpaqueIds()
public void ParseThemeIntents_UsesQueryOnlySearchSortAndOpaqueIds()
{
Assert.True(LegacyBridgeProtocol.TryParseIntent(
"{\"type\":\"search-themes\",\"payload\":{\"query\":\"AI\",\"nxtSession\":\"preMarket\"}}",
"{\"type\":\"search-themes\",\"payload\":{\"query\":\"AI\"}}",
out var search,
out _));
Assert.Equal(
ThemeSession.PreMarket,
Assert.IsType<LegacySearchThemesIntent>(search).NxtSession);
Assert.Equal("AI", Assert.IsType<LegacySearchThemesIntent>(search).Query);
Assert.True(LegacyBridgeProtocol.TryParseIntent(
"{\"type\":\"select-theme\",\"payload\":{\"resultId\":\"theme-result-001\"}}",
@@ -365,7 +396,7 @@ public sealed class LegacyBridgeProtocolTests
Assert.IsType<LegacyActivateThemeActionIntent>(action).ActionId);
Assert.False(LegacyBridgeProtocol.TryParseIntent(
"{\"type\":\"search-themes\",\"payload\":{\"query\":\"AI\",\"nxtSession\":\"auto\"}}",
"{\"type\":\"search-themes\",\"payload\":{\"query\":\"AI\",\"nxtSession\":\"preMarket\"}}",
out _,
out _));
}
@@ -531,6 +562,41 @@ public sealed class LegacyBridgeProtocolTests
Assert.Equal(expected, LegacyBridgeProtocol.IsTrustedSource(source));
}
[Fact]
public void SerializedIndustryStateProjectsAuthoritativeEditedTextNotTypedIdentityName()
{
var identity = new IndustrySelection(IndustryMarket.Kospi, "DB 업종명", "013");
var industry = new LegacyIndustrySelectionSnapshot(
3,
IndustryMarket.Kospi,
[identity],
LegacyIndustryActionCatalog.GetActions(IndustryMarket.Kospi),
0,
identity,
identity,
null,
"직접 입력 첫째",
"직접 입력 둘째");
var snapshot = new LegacyOperatorSnapshot(
1,
string.Empty,
[],
null,
[],
[],
null,
string.Empty,
LegacyOperatorStatusKind.Neutral,
Industry: industry);
using var document = JsonDocument.Parse(LegacyBridgeProtocol.SerializeState(snapshot));
var projected = document.RootElement.GetProperty("payload").GetProperty("industry");
Assert.Equal("직접 입력 첫째", projected.GetProperty("firstName").GetString());
Assert.Equal("직접 입력 둘째", projected.GetProperty("secondName").GetString());
Assert.NotEqual("DB 업종명", projected.GetProperty("firstName").GetString());
}
[Fact]
public void SerializedState_DoesNotExposeHiddenDbOrSceneAuthority()
{