Files
MBN_STOCK_WEBVIEW/tests/MBN_STOCK_WEBVIEW.LegacyApplication.Tests/LegacyTabActivationParityTests.cs

217 lines
8.2 KiB
C#

using MMoneyCoderSharp.Data;
namespace MBN_STOCK_WEBVIEW.LegacyApplication.Tests;
public sealed class LegacyTabActivationParityTests
{
[Fact]
public async Task ThemeEachActivation_LoadsOriginalEmptyQueryOncePerActivation()
{
// Original evidence: Control/UC4.cs UC4_Load starts timer1 and its first
// timer1_Tick calls GetThemeByKeyword with the initially empty txts value.
var service = new CountingThemeService();
var controller = new LegacyOperatorController(
Lookup(),
themeWorkflow: new LegacyThemeWorkflow(service));
var first = await controller.SelectTabAsync(LegacyOperatorTabId.Theme);
Assert.Equal(string.Empty, service.Queries.Single());
Assert.Single(first.Theme!.SearchResults);
await controller.SelectTabAsync(LegacyOperatorTabId.Theme);
Assert.Single(service.Queries);
await controller.SelectTabAsync(LegacyOperatorTabId.Index);
var second = await controller.SelectTabAsync(LegacyOperatorTabId.Theme);
Assert.Collection(
service.Queries,
query => Assert.Equal(string.Empty, query),
query => Assert.Equal(string.Empty, query));
Assert.Single(second.Theme!.SearchResults);
}
[Fact]
public async Task ExpertEachActivation_LoadsOriginalFullListOncePerActivation()
{
// Original evidence: Control/UC6.cs UC6_Load calls Data_Load, whose query
// reads the complete EXPERT_LIST without a filter.
var service = new CountingExpertService();
var controller = new LegacyOperatorController(
Lookup(),
expertWorkflow: new LegacyExpertWorkflowController(service));
var first = await controller.SelectTabAsync(LegacyOperatorTabId.Expert);
Assert.Equal(string.Empty, service.Queries.Single());
Assert.Single(first.Expert!.Search.Results);
await controller.SelectTabAsync(LegacyOperatorTabId.Expert);
Assert.Single(service.Queries);
await controller.SelectTabAsync(LegacyOperatorTabId.Index);
var second = await controller.SelectTabAsync(LegacyOperatorTabId.Expert);
Assert.Collection(
service.Queries,
query => Assert.Equal(string.Empty, query),
query => Assert.Equal(string.Empty, query));
Assert.Single(second.Expert!.Search.Results);
}
[Fact]
public async Task DragSwapThatActivatesTheme_UsesTheSameNativeInitialLoad()
{
var service = new CountingThemeService();
var controller = new LegacyOperatorController(
Lookup(),
themeWorkflow: new LegacyThemeWorkflow(service));
var state = await controller.SwapTabsAsync(
LegacyOperatorTabId.Theme,
LegacyOperatorTabId.Exchange);
Assert.Equal(string.Empty, service.Queries.Single());
Assert.Single(state.Theme!.SearchResults);
Assert.Equal(
LegacyOperatorTabId.Theme,
Assert.Single(state.Tabs!, tab => tab.IsActive).Id);
}
[Fact]
public async Task SupersededThemeActivation_DoesNotCommitAndRetriesWhenNeeded()
{
var service = new DelayedThemeService();
var controller = new LegacyOperatorController(
Lookup(),
themeWorkflow: new LegacyThemeWorkflow(service));
var firstActivation = controller.SelectTabAsync(LegacyOperatorTabId.Theme);
await service.FirstRequestStarted.Task.WaitAsync(TimeSpan.FromSeconds(5));
controller.SelectTab(LegacyOperatorTabId.Index);
service.ReleaseFirstRequest.TrySetResult();
var superseded = await firstActivation;
Assert.Equal(
LegacyOperatorTabId.Index,
Assert.Single(superseded.Tabs!, tab => tab.IsActive).Id);
var retried = await controller.SelectTabAsync(LegacyOperatorTabId.Theme);
Assert.Equal(2, service.CallCount);
Assert.Single(retried.Theme!.SearchResults);
}
private static ILegacyStockLookup Lookup() =>
new StaticLookup(new LegacyStockSearchData(string.Empty, [], []));
private sealed class StaticLookup : ILegacyStockLookup
{
private readonly LegacyStockSearchData _data;
public StaticLookup(LegacyStockSearchData data)
{
_data = data;
}
public Task<LegacyStockSearchData> SearchAsync(
string text,
CancellationToken cancellationToken = default) => Task.FromResult(_data);
}
private sealed class CountingThemeService : IThemeSelectionService
{
private static readonly ThemeSelectionIdentity Identity = new(
ThemeMarket.Krx,
ThemeSession.NotApplicable,
"00000001",
"Theme A");
public List<string> Queries { get; } = [];
public Task<ThemeSearchResult> SearchAsync(
string query,
ThemeSession nxtSession,
int maximumResults = LegacyThemeSelectionService.DefaultMaximumResults,
CancellationToken cancellationToken = default)
{
Queries.Add(query);
return Task.FromResult(CreateThemeResult(query, nxtSession));
}
public Task<ThemePreviewResult> PreviewAsync(
ThemeSelectionIdentity identity,
int maximumItems = LegacyThemeSelectionService.DefaultMaximumPreviewItems,
CancellationToken cancellationToken = default) => Task.FromResult(
new ThemePreviewResult(identity, DateTimeOffset.UtcNow, [], false));
public static ThemeSearchResult CreateThemeResult(
string query,
ThemeSession nxtSession) => new(
query,
nxtSession,
DateTimeOffset.UtcNow,
[new ThemeSelectorItem(Identity, DataSourceKind.Oracle)],
false);
}
private sealed class DelayedThemeService : IThemeSelectionService
{
private int _callCount;
public TaskCompletionSource FirstRequestStarted { get; } = new(
TaskCreationOptions.RunContinuationsAsynchronously);
public TaskCompletionSource ReleaseFirstRequest { get; } = new(
TaskCreationOptions.RunContinuationsAsynchronously);
public int CallCount => Volatile.Read(ref _callCount);
public async Task<ThemeSearchResult> SearchAsync(
string query,
ThemeSession nxtSession,
int maximumResults = LegacyThemeSelectionService.DefaultMaximumResults,
CancellationToken cancellationToken = default)
{
if (Interlocked.Increment(ref _callCount) == 1)
{
FirstRequestStarted.TrySetResult();
await ReleaseFirstRequest.Task.WaitAsync(cancellationToken);
}
return CountingThemeService.CreateThemeResult(query, nxtSession);
}
public Task<ThemePreviewResult> PreviewAsync(
ThemeSelectionIdentity identity,
int maximumItems = LegacyThemeSelectionService.DefaultMaximumPreviewItems,
CancellationToken cancellationToken = default) => Task.FromResult(
new ThemePreviewResult(identity, DateTimeOffset.UtcNow, [], false));
}
private sealed class CountingExpertService : IExpertSelectionService
{
private static readonly ExpertSelectionIdentity Identity = new("0001", "Expert A");
public List<string> Queries { get; } = [];
public Task<ExpertSearchResult> SearchAsync(
string query = "",
int maximumResults = LegacyExpertSelectionService.DefaultMaximumResults,
CancellationToken cancellationToken = default)
{
Queries.Add(query);
return Task.FromResult(new ExpertSearchResult(
query,
DateTimeOffset.UtcNow,
[new ExpertSelectorItem(Identity, DataSourceKind.Oracle)],
false));
}
public Task<ExpertPreviewResult> PreviewAsync(
ExpertSelectionIdentity identity,
int maximumItems = LegacyExpertSelectionService.DefaultMaximumPreviewItems,
CancellationToken cancellationToken = default) => Task.FromResult(
new ExpertPreviewResult(identity, DateTimeOffset.UtcNow, [], false));
}
}