192 lines
8.3 KiB
C#
192 lines
8.3 KiB
C#
using MBN_STOCK_WEBVIEW.LegacyApplication;
|
|
using MMoneyCoderSharp.Data;
|
|
|
|
namespace MBN_STOCK_WEBVIEW.LegacyApplication.Tests;
|
|
|
|
public sealed class LegacyOverseasOperatorControllerTests
|
|
{
|
|
private static readonly DateTimeOffset RetrievedAt =
|
|
new(2026, 7, 15, 10, 0, 0, TimeSpan.FromHours(9));
|
|
|
|
[Fact]
|
|
public void OverseasSnapshotAndFixedIndexActionRemainControllerAuthoritative()
|
|
{
|
|
var controller = CreateController();
|
|
|
|
var selectedTab = controller.SelectTab(LegacyOperatorTabId.OverseasStocks);
|
|
|
|
Assert.NotNull(selectedTab.Overseas);
|
|
Assert.Equal(10, selectedTab.Overseas.FixedIndexTargets.Count);
|
|
Assert.Equal(12, selectedTab.Overseas.Actions.Count);
|
|
Assert.Equal(new LegacyMovingAverageSelection(true, true), selectedTab.MovingAverages);
|
|
Assert.Equal(
|
|
new LegacyOverseasMovingAverageSelection(true, true),
|
|
selectedTab.Overseas.MovingAverages);
|
|
|
|
controller.SelectOverseasFixedIndex("nasdaq");
|
|
controller.SetMovingAverages(ma5: false, ma20: true);
|
|
var state = controller.ActivateOverseasAction("index-candle-20d");
|
|
var row = Assert.Single(state.Playlist);
|
|
var entry = row.ToPlayoutEntry();
|
|
var selection = Assert.IsType<MBN_STOCK_WEBVIEW.Core.Playout.Scenes.LegacySceneSelection>(
|
|
entry.Selection);
|
|
|
|
Assert.Equal("legacy-overseas-00000001", row.RowId);
|
|
Assert.Equal("해외지수", row.MarketText);
|
|
Assert.Equal("나스닥", row.StockName);
|
|
Assert.Equal("캔들그래프", row.GraphicType);
|
|
Assert.Equal("20일", row.Subtype);
|
|
Assert.Equal("1/1", row.PageText);
|
|
Assert.Equal("8040", entry.CutCode);
|
|
Assert.Equal("FOREIGN_INDEX", selection.GroupCode);
|
|
Assert.Equal("나스닥", selection.Subject);
|
|
Assert.Equal("NAS@IXIC|US|0", selection.DataCode);
|
|
Assert.Equal(
|
|
"MA20",
|
|
Assert.Single(controller.CreatePlayoutRequest().Playlist).Selection!.GraphicType);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task OverseasIndustryAndStockSearchSelectionsMaterializeExactPlaylistRows()
|
|
{
|
|
var controller = CreateController(
|
|
industries: [new("반도체", "US Semiconductor", "NAS@SOX")],
|
|
stocks: [new("Apple", "NAS@AAPL", "US")]);
|
|
controller.SelectTab(LegacyOperatorTabId.OverseasStocks);
|
|
|
|
var industries = await controller.SearchOverseasIndustriesAsync("반도체");
|
|
var industryId = Assert.Single(industries.Overseas!.Industry.Results).SelectionId;
|
|
controller.SelectOverseasIndustry(industryId);
|
|
var industryState = controller.ActivateOverseasAction("industry-current");
|
|
|
|
var industryRow = Assert.Single(industryState.Playlist);
|
|
Assert.Equal("5001", industryRow.ToPlayoutEntry().CutCode);
|
|
Assert.Equal("FOREIGN_INDUSTRY", industryRow.PlayoutSelection!.GroupCode);
|
|
Assert.Equal("반도체", industryRow.PlayoutSelection.Subject);
|
|
Assert.Equal("1열판기본", industryRow.PlayoutSelection.GraphicType);
|
|
Assert.Equal("CURRENT", industryRow.PlayoutSelection.Subtype);
|
|
Assert.Equal("US Semiconductor|NAS@SOX|US|0", industryRow.PlayoutSelection.DataCode);
|
|
|
|
var stocks = await controller.SearchOverseasStocksAsync("apple");
|
|
var stockId = Assert.Single(stocks.Overseas!.Stock.Results).SelectionId;
|
|
controller.SelectOverseasStock(stockId);
|
|
var stockState = controller.ActivateOverseasAction("stock-candle-5d");
|
|
|
|
Assert.Equal(2, stockState.Playlist.Count);
|
|
var stockRow = stockState.Playlist[1];
|
|
Assert.Equal("8061", stockRow.ToPlayoutEntry().CutCode);
|
|
Assert.Equal("캔들그래프", stockRow.GraphicType);
|
|
Assert.Equal("FOREIGN_STOCK", stockRow.PlayoutSelection!.GroupCode);
|
|
Assert.Equal("Apple", stockRow.PlayoutSelection.Subject);
|
|
Assert.Equal(string.Empty, stockRow.PlayoutSelection.GraphicType);
|
|
Assert.Equal("PRICE", stockRow.PlayoutSelection.Subtype);
|
|
Assert.Equal("NAS@AAPL|US|1", stockRow.PlayoutSelection.DataCode);
|
|
Assert.Equal(
|
|
"MA5,MA20",
|
|
controller.CreatePlayoutRequest().Playlist[1].Selection!.GraphicType);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task NonUsStockKeepsOneExactIdentityThroughBothActualUc5SceneAliases()
|
|
{
|
|
var controller = CreateController(
|
|
stocks: [new("London Stock", "LNS@LON", "GB")]);
|
|
controller.SelectTab(LegacyOperatorTabId.OverseasStocks);
|
|
|
|
// UC5's first inserted result is immediately the active RowMode row.
|
|
var searched = await controller.SearchOverseasStocksAsync("london");
|
|
Assert.Equal("London Stock", searched.Overseas!.Stock.Selected?.InputName);
|
|
|
|
var oneColumn = controller.ActivateOverseasAction("stock-current");
|
|
var candle = controller.ActivateOverseasAction("stock-candle-5d");
|
|
var rows = candle.Playlist;
|
|
|
|
Assert.Equal("5001", rows[0].ToPlayoutEntry().CutCode);
|
|
Assert.Equal("8061", rows[1].ToPlayoutEntry().CutCode);
|
|
Assert.All(rows, row =>
|
|
{
|
|
Assert.Equal("FOREIGN_STOCK", row.PlayoutSelection?.GroupCode);
|
|
Assert.Equal("London Stock", row.PlayoutSelection?.Subject);
|
|
Assert.Equal("LNS@LON|GB|1", row.PlayoutSelection?.DataCode);
|
|
});
|
|
Assert.Single(oneColumn.Playlist);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task OverseasActionsRejectInactiveTabAndStaleSearchIds()
|
|
{
|
|
var controller = CreateController(
|
|
industries: [new("반도체", "US Semiconductor", "NAS@SOX")]);
|
|
|
|
var inactive = controller.SelectOverseasFixedIndex("nasdaq");
|
|
Assert.Equal(LegacyOperatorStatusKind.Error, inactive.StatusKind);
|
|
Assert.Null(inactive.Overseas);
|
|
|
|
controller.SelectTab(LegacyOperatorTabId.OverseasStocks);
|
|
var first = await controller.SearchOverseasIndustriesAsync("");
|
|
var staleId = Assert.Single(first.Overseas!.Industry.Results).SelectionId;
|
|
await controller.SearchOverseasIndustriesAsync("new generation");
|
|
|
|
var stale = controller.SelectOverseasIndustry(staleId);
|
|
Assert.Equal(LegacyOperatorStatusKind.Error, stale.StatusKind);
|
|
Assert.Equal("반도체", stale.Overseas!.Industry.Selected?.KoreanName);
|
|
}
|
|
|
|
private static LegacyOperatorController CreateController(
|
|
IReadOnlyList<OverseasIndustryIndexItem>? industries = null,
|
|
IReadOnlyList<WorldStockSearchItem>? stocks = null)
|
|
{
|
|
var workflow = new LegacyOverseasSelectionWorkflow(
|
|
new StaticIndustryService(industries ?? []),
|
|
new StaticStockService(stocks ?? []));
|
|
return new LegacyOperatorController(
|
|
new EmptyStockLookup(),
|
|
overseasWorkflow: workflow);
|
|
}
|
|
|
|
private sealed class EmptyStockLookup : ILegacyStockLookup
|
|
{
|
|
public Task<LegacyStockSearchData> SearchAsync(
|
|
string query,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
cancellationToken.ThrowIfCancellationRequested();
|
|
return Task.FromResult(new LegacyStockSearchData(query, [], []));
|
|
}
|
|
}
|
|
|
|
private sealed class StaticIndustryService(
|
|
IReadOnlyList<OverseasIndustryIndexItem> items) : IOverseasIndustryIndexSearchService
|
|
{
|
|
public Task<OverseasIndustryIndexSearchResult> SearchAsync(
|
|
string query,
|
|
int maximumResults = LegacyOverseasIndustryIndexSearchService.DefaultMaximumResults,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
cancellationToken.ThrowIfCancellationRequested();
|
|
return Task.FromResult(new OverseasIndustryIndexSearchResult(
|
|
query.Trim(),
|
|
RetrievedAt,
|
|
items,
|
|
IsTruncated: false));
|
|
}
|
|
}
|
|
|
|
private sealed class StaticStockService(
|
|
IReadOnlyList<WorldStockSearchItem> items) : IOverseasStockSearchService
|
|
{
|
|
public Task<WorldStockSearchResult> SearchAsync(
|
|
string query,
|
|
int maximumResults = LegacyOverseasStockSearchService.DefaultMaximumResults,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
cancellationToken.ThrowIfCancellationRequested();
|
|
return Task.FromResult(new WorldStockSearchResult(
|
|
query.Trim(),
|
|
RetrievedAt,
|
|
items,
|
|
IsTruncated: false));
|
|
}
|
|
}
|
|
}
|