222 lines
8.4 KiB
C#
222 lines
8.4 KiB
C#
using MBN_STOCK_WEBVIEW.LegacyApplication;
|
|
|
|
namespace MBN_STOCK_WEBVIEW.LegacyApplication.Tests;
|
|
|
|
public sealed class LegacyOperatorControllerTests
|
|
{
|
|
[Fact]
|
|
public async Task EmptyButtonIsNoOpButEmptyEnterSearches()
|
|
{
|
|
var lookup = Lookup();
|
|
var controller = new LegacyOperatorController(lookup);
|
|
|
|
await controller.SearchStocksAsync(string.Empty, LegacySearchTrigger.Button);
|
|
Assert.Equal(0, lookup.CallCount);
|
|
|
|
await controller.SearchStocksAsync(string.Empty, LegacySearchTrigger.Enter);
|
|
Assert.Equal(1, lookup.CallCount);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ExactPointerDoubleClick_AppendsOneLegacyRow()
|
|
{
|
|
var controller = new LegacyOperatorController(Lookup());
|
|
await controller.SearchStocksAsync("삼성", LegacySearchTrigger.Button);
|
|
controller.SelectStock(0);
|
|
|
|
controller.CutPointerDown(1, false, false, 20, 45, 1_000);
|
|
var state = controller.CutPointerDown(1, false, false, 20, 45, 1_400);
|
|
|
|
var row = Assert.Single(state.Playlist);
|
|
Assert.Equal("코스피", row.MarketText);
|
|
Assert.Equal("삼성전자", row.StockName);
|
|
Assert.Equal("1열판기본", row.GraphicType);
|
|
Assert.Equal("현재가", row.Subtype);
|
|
Assert.Equal("005930", row.StockCode);
|
|
Assert.Equal("5001", row.ToPlayoutEntry().CutCode);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ExactPointerDoubleClick_AllowsZeroBasedWebTimestamp()
|
|
{
|
|
var controller = new LegacyOperatorController(Lookup());
|
|
await controller.SearchStocksAsync("삼성", LegacySearchTrigger.Button);
|
|
controller.SelectStock(0);
|
|
|
|
controller.CutPointerDown(1, false, false, 20, 45, 0);
|
|
var state = controller.CutPointerDown(1, false, false, 20, 45, 499);
|
|
|
|
Assert.Single(state.Playlist);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task DifferentPointerPosition_DoesNotCountAsLegacyDoubleClick()
|
|
{
|
|
var controller = new LegacyOperatorController(Lookup());
|
|
await controller.SearchStocksAsync("삼성", LegacySearchTrigger.Button);
|
|
controller.SelectStock(0);
|
|
|
|
controller.CutPointerDown(1, false, false, 20, 45, 1_000);
|
|
var state = controller.CutPointerDown(1, false, false, 21, 45, 1_200);
|
|
|
|
Assert.Empty(state.Playlist);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task NativeSelectionAndLegacyDoubleClickRowsStaySeparateAtShiftEdges()
|
|
{
|
|
var controller = new LegacyOperatorController(Lookup());
|
|
await controller.SearchStocksAsync("삼성", LegacySearchTrigger.Button);
|
|
controller.SelectStock(0);
|
|
|
|
var firstShift = controller.CutPointerDown(2, false, true, 20, 69, 1_000);
|
|
Assert.Equal(
|
|
[0, 1, 2],
|
|
firstShift.CutRows.Where(row => row.IsSelected).Select(row => row.PhysicalIndex));
|
|
|
|
var noDoubleClick = controller.CutPointerDown(2, false, false, 20, 69, 1_400);
|
|
Assert.Empty(noDoubleClick.Playlist);
|
|
|
|
var sameRowShift = controller.CutPointerDown(2, false, true, 21, 69, 2_000);
|
|
Assert.Equal(
|
|
[2],
|
|
sameRowShift.CutRows.Where(row => row.IsSelected).Select(row => row.PhysicalIndex));
|
|
|
|
var stillNoDoubleClick = controller.CutPointerDown(2, false, false, 21, 69, 2_400);
|
|
Assert.Empty(stillNoDoubleClick.Playlist);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ControlAndShiftSelection_DropsInPhysicalOrderAndKeepsDuplicates()
|
|
{
|
|
var controller = new LegacyOperatorController(Lookup());
|
|
await controller.SearchStocksAsync("삼성", LegacySearchTrigger.Button);
|
|
controller.SelectStock(0);
|
|
controller.CutPointerDown(0, false, false, 1, 1, 1_000);
|
|
controller.CutPointerDown(2, true, false, 1, 47, 2_000);
|
|
controller.CutPointerDown(1, true, true, 1, 24, 3_000);
|
|
|
|
var first = controller.DropSelectedCutsOnPlaylist();
|
|
var second = controller.DropSelectedCutsOnPlaylist();
|
|
|
|
Assert.Equal(3, first.Playlist.Count);
|
|
Assert.Equal(6, second.Playlist.Count);
|
|
Assert.Equal(
|
|
["예상체결가", "현재가", "시간외단일가"],
|
|
first.Playlist.Select(row => row.Subtype));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task SameRowShiftStillDropsTheNativeListViewSelection()
|
|
{
|
|
var controller = new LegacyOperatorController(Lookup());
|
|
await controller.SearchStocksAsync("삼성", LegacySearchTrigger.Button);
|
|
controller.SelectStock(0);
|
|
controller.CutPointerDown(1, false, false, 1, 24, 1_000);
|
|
controller.CutPointerDown(1, false, true, 2, 24, 2_000);
|
|
|
|
var state = controller.DropSelectedCutsOnPlaylist();
|
|
|
|
Assert.Equal("현재가", Assert.Single(state.Playlist).Subtype);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task NxtOnlyAllowsCurrentAndShowsOriginalWarning()
|
|
{
|
|
var controller = new LegacyOperatorController(Lookup());
|
|
await controller.SearchStocksAsync("넥스트", LegacySearchTrigger.Button);
|
|
controller.SelectStock(1);
|
|
controller.CutPointerDown(0, false, false, 1, 1, 1_000);
|
|
var warning = controller.DropSelectedCutsOnPlaylist();
|
|
|
|
Assert.Empty(warning.Playlist);
|
|
Assert.Equal("NXT는 제공하지 않습니다.", warning.Dialog?.Message);
|
|
|
|
controller.DismissDialog();
|
|
controller.CutPointerDown(1, false, false, 1, 24, 2_000);
|
|
var accepted = controller.DropSelectedCutsOnPlaylist();
|
|
Assert.Equal("N5001", Assert.Single(accepted.Playlist).ToPlayoutEntry().CutCode);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task NxtMultiSelection_PausesAtEachOriginalModalBeforeContinuing()
|
|
{
|
|
var controller = new LegacyOperatorController(Lookup());
|
|
await controller.SearchStocksAsync("넥스트", LegacySearchTrigger.Button);
|
|
controller.SelectStock(1);
|
|
controller.CutPointerDown(0, false, false, 1, 1, 1_000);
|
|
controller.CutPointerDown(1, true, false, 1, 24, 2_000);
|
|
controller.CutPointerDown(2, true, false, 1, 47, 3_000);
|
|
|
|
var firstWarning = controller.DropSelectedCutsOnPlaylist();
|
|
Assert.Empty(firstWarning.Playlist);
|
|
Assert.Equal("NXT는 제공하지 않습니다.", firstWarning.Dialog?.Message);
|
|
|
|
var secondWarning = controller.DismissDialog();
|
|
Assert.Equal("N5001", Assert.Single(secondWarning.Playlist).ToPlayoutEntry().CutCode);
|
|
Assert.Equal("NXT는 제공하지 않습니다.", secondWarning.Dialog?.Message);
|
|
|
|
var finished = controller.DismissDialog();
|
|
Assert.Single(finished.Playlist);
|
|
Assert.Null(finished.Dialog);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task NxtSeparatorStillShowsOriginalWarning()
|
|
{
|
|
var controller = new LegacyOperatorController(Lookup());
|
|
await controller.SearchStocksAsync("넥스트", LegacySearchTrigger.Button);
|
|
controller.SelectStock(1);
|
|
controller.CutPointerDown(3, false, false, 1, 70, 1_000);
|
|
|
|
var warning = controller.DropSelectedCutsOnPlaylist();
|
|
|
|
Assert.Empty(warning.Playlist);
|
|
Assert.Equal("NXT는 제공하지 않습니다.", warning.Dialog?.Message);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task NewSearchClearsStockSelectionButNotCutCatalogOrPlaylist()
|
|
{
|
|
var controller = new LegacyOperatorController(Lookup());
|
|
await controller.SearchStocksAsync("삼성", LegacySearchTrigger.Button);
|
|
controller.SelectStock(0);
|
|
controller.CutPointerDown(1, false, false, 1, 24, 1_000);
|
|
controller.DropSelectedCutsOnPlaylist();
|
|
|
|
var state = await controller.SearchStocksAsync("다시", LegacySearchTrigger.Button);
|
|
|
|
Assert.Null(state.SelectedStockIndex);
|
|
Assert.Equal(33, state.CutRows.Count);
|
|
Assert.Single(state.Playlist);
|
|
}
|
|
|
|
private static FakeLookup Lookup() => new(new LegacyStockSearchData(
|
|
"query",
|
|
["삼성전자", "넥스트(NXT)"],
|
|
[
|
|
new LegacyStockIdentity(LegacyDomesticStockMarket.Kospi, "삼성전자", "005930"),
|
|
new LegacyStockIdentity(LegacyDomesticStockMarket.NxtKospi, "넥스트(NXT)", "A00001")
|
|
]));
|
|
|
|
private sealed class FakeLookup : ILegacyStockLookup
|
|
{
|
|
private readonly LegacyStockSearchData _result;
|
|
|
|
public FakeLookup(LegacyStockSearchData result)
|
|
{
|
|
_result = result;
|
|
}
|
|
|
|
public int CallCount { get; private set; }
|
|
|
|
public Task<LegacyStockSearchData> SearchAsync(
|
|
string query,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
CallCount++;
|
|
return Task.FromResult(_result);
|
|
}
|
|
}
|
|
}
|