feat: complete legacy UI and playout parity migration
This commit is contained in:
@@ -0,0 +1,516 @@
|
||||
using MBN_STOCK_WEBVIEW.Core.Playout.Scenes;
|
||||
|
||||
namespace MBN_STOCK_WEBVIEW.LegacyApplication.Tests;
|
||||
|
||||
public sealed class LegacyManualListsWorkflowTests
|
||||
{
|
||||
[Fact]
|
||||
public void Construction_is_side_effect_free_and_snapshot_has_no_file_or_stock_code_authority()
|
||||
{
|
||||
var store = new FakeStore();
|
||||
var workflow = new LegacyManualListsWorkflow(store, new FakeLookup());
|
||||
|
||||
var snapshot = workflow.Current;
|
||||
|
||||
Assert.Equal(0, store.ReadNetCalls);
|
||||
Assert.Equal(0, store.ReadViCalls);
|
||||
Assert.Equal(0, store.WriteNetCalls);
|
||||
Assert.Equal(0, store.WriteViCalls);
|
||||
Assert.DoesNotContain(
|
||||
typeof(LegacyManualListsSnapshot).GetProperties(),
|
||||
property => property.Name.Contains("Path", StringComparison.OrdinalIgnoreCase) ||
|
||||
property.Name.Contains("Version", StringComparison.OrdinalIgnoreCase));
|
||||
Assert.DoesNotContain(
|
||||
typeof(LegacyManualViItemView).GetProperties(),
|
||||
property => property.Name.Contains("Code", StringComparison.OrdinalIgnoreCase));
|
||||
Assert.True(snapshot.IsAvailable);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task FSell_saves_once_rereads_exact_five_rows_and_materializes_s5025()
|
||||
{
|
||||
var store = new FakeStore();
|
||||
var workflow = new LegacyManualListsWorkflow(store, new FakeLookup());
|
||||
await workflow.OpenNetSellAsync(S5025ManualAudience.Foreign);
|
||||
var row = workflow.Current.NetRows[0];
|
||||
workflow.SetNetSellCell(row.RowId, LegacyManualNetSellField.LeftName, "Alpha");
|
||||
|
||||
var saved = await workflow.SaveNetSellAsync();
|
||||
var draft = workflow.CreateNetSellPlaylistDraft();
|
||||
|
||||
Assert.Equal(1, store.WriteNetCalls);
|
||||
Assert.Equal(2, store.ReadNetCalls);
|
||||
Assert.True(saved.NetRowsAreFresh);
|
||||
Assert.Equal("Alpha", saved.NetRows[0].LeftName);
|
||||
Assert.Equal("5025", draft.SceneAlias);
|
||||
Assert.Equal("FOREIGN", draft.Selection.GroupCode);
|
||||
Assert.Equal("MANUAL_NET_SELL", draft.Selection.GraphicType);
|
||||
Assert.Equal("1/1", draft.PageText);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task FSell_ambiguous_failure_uses_one_readback_and_quarantines_on_mismatch()
|
||||
{
|
||||
var store = new FakeStore { ThrowNetWrite = true, PersistBeforeNetThrow = false };
|
||||
var workflow = new LegacyManualListsWorkflow(store, new FakeLookup());
|
||||
await workflow.OpenNetSellAsync(S5025ManualAudience.Individual);
|
||||
workflow.SetNetSellCell(
|
||||
workflow.Current.NetRows[0].RowId,
|
||||
LegacyManualNetSellField.LeftName,
|
||||
"Changed");
|
||||
|
||||
var result = await workflow.SaveNetSellAsync();
|
||||
var second = await workflow.SaveNetSellAsync();
|
||||
|
||||
Assert.True(result.WritesQuarantined);
|
||||
Assert.True(second.WritesQuarantined);
|
||||
Assert.Equal(1, store.WriteNetCalls);
|
||||
Assert.Equal(2, store.ReadNetCalls);
|
||||
Assert.False(result.CanSave);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task VI_search_uses_opaque_ids_and_save_binds_fresh_versioned_s5074_reference()
|
||||
{
|
||||
var store = new FakeStore();
|
||||
var workflow = new LegacyManualListsWorkflow(store, new FakeLookup());
|
||||
await workflow.OpenViAsync();
|
||||
var searched = await workflow.SearchViAsync("삼성");
|
||||
var result = Assert.Single(searched.SearchResults);
|
||||
Assert.DoesNotContain("005930", result.ResultId, StringComparison.Ordinal);
|
||||
var selected = workflow.SelectViSearchResult(result.ResultId);
|
||||
Assert.Equal(result.ResultId, selected.SelectedSearchResultId);
|
||||
Assert.Empty(selected.ViItems);
|
||||
workflow.AddViSearchResult(result.ResultId);
|
||||
|
||||
var saved = await workflow.SaveViAsync();
|
||||
var draft = workflow.CreateViPlaylistDraft();
|
||||
|
||||
Assert.Equal(1, store.WriteViCalls);
|
||||
Assert.Equal(3, store.ReadViCalls);
|
||||
Assert.True(saved.ViItemsAreFresh);
|
||||
Assert.Equal(1, saved.ViPageCount);
|
||||
Assert.Equal("5074", draft.SceneAlias);
|
||||
Assert.Equal("PAGED_VI", draft.Selection.GroupCode);
|
||||
Assert.Equal("@MBN_VI_SNAPSHOT_V1", draft.Selection.Subject);
|
||||
Assert.Equal(store.Vi.RowVersion, draft.Selection.DataCode);
|
||||
Assert.DoesNotContain("005930", draft.StockName, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task VI_stale_preflight_never_writes_or_retries()
|
||||
{
|
||||
var store = new FakeStore();
|
||||
var workflow = new LegacyManualListsWorkflow(store, new FakeLookup());
|
||||
await workflow.OpenViAsync();
|
||||
var searched = await workflow.SearchViAsync("삼성");
|
||||
workflow.AddViSearchResult(searched.SearchResults.Single().ResultId);
|
||||
store.Vi = store.Vi with { RowVersion = new string('b', 64) };
|
||||
|
||||
var result = await workflow.SaveViAsync();
|
||||
|
||||
Assert.Equal(0, store.WriteViCalls);
|
||||
Assert.False(result.ViItemsAreFresh);
|
||||
Assert.False(result.WritesQuarantined);
|
||||
Assert.Contains("변경", result.StatusMessage, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Import_outcome_unknown_latches_process_workflow_quarantine()
|
||||
{
|
||||
var store = new FakeStore { ImportOutcomeUnknown = true };
|
||||
var workflow = new LegacyManualListsWorkflow(store, new FakeLookup());
|
||||
|
||||
var result = await workflow.ImportAsync();
|
||||
|
||||
Assert.True(result.WritesQuarantined);
|
||||
Assert.False(result.CanSave);
|
||||
Assert.Equal(1, store.ImportCalls);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Operator_controller_appends_only_native_materialized_manual_rows()
|
||||
{
|
||||
var store = new FakeStore();
|
||||
var lookup = new FakeLookup();
|
||||
var controller = new LegacyOperatorController(
|
||||
lookup,
|
||||
manualListsWorkflow: new LegacyManualListsWorkflow(store, lookup));
|
||||
await controller.OpenManualNetSellAsync(S5025ManualAudience.Institution);
|
||||
var row = controller.Current.ManualLists!.NetRows[0];
|
||||
controller.SetManualNetSellCell(
|
||||
row.RowId,
|
||||
LegacyManualNetSellField.RightAmount,
|
||||
"-3,000");
|
||||
await controller.SaveManualNetSellAsync();
|
||||
|
||||
var result = controller.AddManualNetSellPlaylistRow();
|
||||
var playlist = Assert.Single(result.Playlist);
|
||||
|
||||
Assert.Equal("5025", playlist.SceneAlias);
|
||||
Assert.Equal("INSTITUTION", playlist.PlayoutSelection!.GroupCode);
|
||||
Assert.Equal("MANUAL_NET_SELL", playlist.PlayoutSelection.GraphicType);
|
||||
Assert.Equal("1/1", playlist.PageText);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Original_ok_saves_verifies_adds_one_cut_and_closes_the_editor()
|
||||
{
|
||||
var store = new FakeStore();
|
||||
var lookup = new FakeLookup();
|
||||
var controller = new LegacyOperatorController(
|
||||
lookup,
|
||||
manualListsWorkflow: new LegacyManualListsWorkflow(store, lookup));
|
||||
await controller.OpenManualNetSellAsync(S5025ManualAudience.Foreign);
|
||||
|
||||
var result = await controller.ConfirmManualListsAsync();
|
||||
|
||||
Assert.Equal(1, store.WriteNetCalls);
|
||||
Assert.Equal(2, store.ReadNetCalls);
|
||||
Assert.False(result.ManualLists!.IsOpen);
|
||||
var row = Assert.Single(result.Playlist);
|
||||
Assert.Equal("5025", row.SceneAlias);
|
||||
Assert.Equal("FOREIGN", row.PlayoutSelection!.GroupCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Original_ok_on_unknown_write_keeps_editor_open_and_never_adds_a_cut()
|
||||
{
|
||||
var store = new FakeStore
|
||||
{
|
||||
ThrowNetWrite = true,
|
||||
PersistBeforeNetThrow = false
|
||||
};
|
||||
var lookup = new FakeLookup();
|
||||
var controller = new LegacyOperatorController(
|
||||
lookup,
|
||||
manualListsWorkflow: new LegacyManualListsWorkflow(store, lookup));
|
||||
await controller.OpenManualNetSellAsync(S5025ManualAudience.Individual);
|
||||
var row = controller.Current.ManualLists!.NetRows[0];
|
||||
controller.SetManualNetSellCell(
|
||||
row.RowId,
|
||||
LegacyManualNetSellField.LeftAmount,
|
||||
"999");
|
||||
|
||||
var result = await controller.ConfirmManualListsAsync();
|
||||
|
||||
Assert.Equal(1, store.WriteNetCalls);
|
||||
Assert.Empty(result.Playlist);
|
||||
Assert.True(result.ManualLists!.IsOpen);
|
||||
Assert.True(result.ManualLists.WritesQuarantined);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("fixed-245", S5025ManualAudience.Individual)]
|
||||
[InlineData("fixed-246", S5025ManualAudience.Foreign)]
|
||||
[InlineData("fixed-247", S5025ManualAudience.Institution)]
|
||||
public async Task Original_manual_net_sell_tree_leaves_open_the_matching_editor(
|
||||
string actionId,
|
||||
S5025ManualAudience audience)
|
||||
{
|
||||
var store = new FakeStore();
|
||||
var lookup = new FakeLookup();
|
||||
var controller = new LegacyOperatorController(
|
||||
lookup,
|
||||
manualListsWorkflow: new LegacyManualListsWorkflow(store, lookup));
|
||||
await controller.SelectTabAsync(LegacyOperatorTabId.Index);
|
||||
|
||||
var result = await controller.ActivateFixedActionAsync(actionId);
|
||||
|
||||
Assert.True(result.ManualLists!.IsOpen);
|
||||
Assert.Equal(LegacyManualListScreen.NetSell, result.ManualLists.Screen);
|
||||
Assert.Equal(audience, result.ManualLists.Audience);
|
||||
Assert.Empty(result.Playlist);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("fixed-262")]
|
||||
[InlineData("fixed-293")]
|
||||
[InlineData("fixed-320")]
|
||||
public async Task Original_manual_vi_tree_leaves_open_the_vi_editor(string actionId)
|
||||
{
|
||||
var store = new FakeStore
|
||||
{
|
||||
Vi = new LegacyManualViStoreSnapshot(
|
||||
Enumerable.Range(1, 9)
|
||||
.Select(index => new LegacyManualViStoredItem(
|
||||
$"P{index:D6}",
|
||||
$"VI종목{index}"))
|
||||
.ToArray(),
|
||||
new string('a', 64))
|
||||
};
|
||||
var lookup = new FakeLookup();
|
||||
var controller = new LegacyOperatorController(
|
||||
lookup,
|
||||
manualListsWorkflow: new LegacyManualListsWorkflow(store, lookup));
|
||||
await controller.SelectTabAsync(LegacyOperatorTabId.Index);
|
||||
|
||||
var result = await controller.ActivateFixedActionAsync(actionId);
|
||||
|
||||
Assert.True(result.ManualLists!.IsOpen);
|
||||
Assert.Equal(LegacyManualListScreen.Vi, result.ManualLists.Screen);
|
||||
Assert.Equal(9, result.ManualLists.ViItems.Count);
|
||||
Assert.Equal(2, result.ManualLists.ViPageCount);
|
||||
Assert.True(result.ManualLists.ViItemsAreFresh);
|
||||
Assert.True(result.ManualLists.CanSave);
|
||||
Assert.True(result.ManualLists.CanMaterializePlaylist);
|
||||
Assert.Empty(result.Playlist);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Fixed_parent_stages_three_FSell_children_and_commits_once_in_original_order()
|
||||
{
|
||||
var store = new FakeStore();
|
||||
var lookup = new FakeLookup();
|
||||
var controller = new LegacyOperatorController(
|
||||
lookup,
|
||||
manualListsWorkflow: new LegacyManualListsWorkflow(store, lookup));
|
||||
await controller.SelectTabAsync(LegacyOperatorTabId.Index);
|
||||
var section = LegacyFixedActionCatalog.Default
|
||||
.GetSections(LegacyFixedMarket.Index)[6];
|
||||
|
||||
var first = await controller.ActivateFixedSection(6);
|
||||
|
||||
Assert.Empty(first.Playlist);
|
||||
Assert.Equal("fixed-245", first.FixedSectionBatch!.PendingActionId);
|
||||
Assert.Equal(1, first.FixedSectionBatch.ManualStepNumber);
|
||||
Assert.Equal(3, first.FixedSectionBatch.ManualStepCount);
|
||||
Assert.Equal(S5025ManualAudience.Individual, first.ManualLists!.Audience);
|
||||
|
||||
var second = await controller.ConfirmManualListsAsync();
|
||||
Assert.Empty(second.Playlist);
|
||||
Assert.Equal("fixed-246", second.FixedSectionBatch!.PendingActionId);
|
||||
Assert.Equal(S5025ManualAudience.Foreign, second.ManualLists!.Audience);
|
||||
|
||||
var third = await controller.ConfirmManualListsAsync();
|
||||
Assert.Empty(third.Playlist);
|
||||
Assert.Equal("fixed-247", third.FixedSectionBatch!.PendingActionId);
|
||||
Assert.Equal(S5025ManualAudience.Institution, third.ManualLists!.Audience);
|
||||
|
||||
var completed = await controller.ConfirmManualListsAsync();
|
||||
|
||||
Assert.Null(completed.FixedSectionBatch);
|
||||
Assert.False(completed.ManualLists!.IsOpen);
|
||||
Assert.Equal(3, store.WriteNetCalls);
|
||||
Assert.Equal(section.Actions.Count, completed.Playlist.Count);
|
||||
Assert.Equal(
|
||||
section.Actions.Select(action => action.Label),
|
||||
completed.Playlist.Select(row => row.StockName));
|
||||
Assert.Equal(
|
||||
new[] { "INDIVIDUAL", "FOREIGN", "INSTITUTION" },
|
||||
completed.Playlist.TakeLast(3).Select(row => row.PlayoutSelection!.GroupCode));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Fixed_parent_cancel_discards_all_playlist_staging_but_keeps_known_manual_save()
|
||||
{
|
||||
var store = new FakeStore();
|
||||
var lookup = new FakeLookup();
|
||||
var controller = new LegacyOperatorController(
|
||||
lookup,
|
||||
manualListsWorkflow: new LegacyManualListsWorkflow(store, lookup));
|
||||
await controller.SelectTabAsync(LegacyOperatorTabId.Index);
|
||||
await controller.ActivateFixedSection(6);
|
||||
await controller.ConfirmManualListsAsync();
|
||||
|
||||
var cancelled = controller.CloseManualLists();
|
||||
|
||||
Assert.Equal(1, store.WriteNetCalls);
|
||||
Assert.Empty(cancelled.Playlist);
|
||||
Assert.Null(cancelled.FixedSectionBatch);
|
||||
Assert.False(cancelled.ManualLists!.IsOpen);
|
||||
Assert.Equal(LegacyOperatorStatusKind.Warning, cancelled.StatusKind);
|
||||
Assert.Contains("아무 항목도 추가하지 않았습니다", cancelled.StatusMessage,
|
||||
StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Fixed_parent_outcome_unknown_keeps_same_step_and_never_retries_or_appends()
|
||||
{
|
||||
var store = new FakeStore
|
||||
{
|
||||
ThrowNetWrite = true,
|
||||
PersistBeforeNetThrow = false
|
||||
};
|
||||
var lookup = new FakeLookup();
|
||||
var controller = new LegacyOperatorController(
|
||||
lookup,
|
||||
manualListsWorkflow: new LegacyManualListsWorkflow(store, lookup));
|
||||
await controller.SelectTabAsync(LegacyOperatorTabId.Index);
|
||||
var opened = await controller.ActivateFixedSection(6);
|
||||
controller.SetManualNetSellCell(
|
||||
opened.ManualLists!.NetRows[0].RowId,
|
||||
LegacyManualNetSellField.LeftAmount,
|
||||
"999");
|
||||
|
||||
var unknown = await controller.ConfirmManualListsAsync();
|
||||
var blockedRepeat = await controller.ConfirmManualListsAsync();
|
||||
|
||||
Assert.Equal(1, store.WriteNetCalls);
|
||||
Assert.Empty(unknown.Playlist);
|
||||
Assert.Empty(blockedRepeat.Playlist);
|
||||
Assert.Equal("fixed-245", blockedRepeat.FixedSectionBatch!.PendingActionId);
|
||||
Assert.True(blockedRepeat.ManualLists!.IsOpen);
|
||||
Assert.True(blockedRepeat.ManualLists.WritesQuarantined);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Fixed_parent_VI_child_resumes_and_commits_at_its_original_child_position()
|
||||
{
|
||||
var store = new FakeStore();
|
||||
var lookup = new FakeLookup();
|
||||
var controller = new LegacyOperatorController(
|
||||
lookup,
|
||||
manualListsWorkflow: new LegacyManualListsWorkflow(store, lookup));
|
||||
await controller.SelectTabAsync(LegacyOperatorTabId.Index);
|
||||
var section = LegacyFixedActionCatalog.Default
|
||||
.GetSections(LegacyFixedMarket.Index)[7];
|
||||
var manualIndex = section.Actions.ToList().FindIndex(action => action.Id == "fixed-262");
|
||||
var opened = await controller.ActivateFixedSection(7);
|
||||
var searched = await controller.SearchManualViAsync("삼성");
|
||||
controller.AddManualViSearchResult(
|
||||
Assert.Single(searched.ManualLists!.SearchResults).ResultId);
|
||||
|
||||
var completed = await controller.ConfirmManualListsAsync();
|
||||
|
||||
Assert.Null(completed.FixedSectionBatch);
|
||||
Assert.Equal(section.Actions.Count, completed.Playlist.Count);
|
||||
Assert.Equal(
|
||||
section.Actions.Take(manualIndex).Select(action => action.Label),
|
||||
completed.Playlist.Take(manualIndex).Select(row => row.StockName));
|
||||
Assert.Equal(
|
||||
section.Actions.Skip(manualIndex + 1).Select(action => action.Label),
|
||||
completed.Playlist.Skip(manualIndex + 1).Select(row => row.StockName));
|
||||
Assert.Equal("5074", completed.Playlist[manualIndex].SceneAlias);
|
||||
Assert.Equal("PAGED_VI", completed.Playlist[manualIndex].PlayoutSelection!.GroupCode);
|
||||
Assert.Equal(1, store.WriteViCalls);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Fixed_parent_modal_contract_blocks_tab_and_manual_target_switches()
|
||||
{
|
||||
var store = new FakeStore();
|
||||
var lookup = new FakeLookup();
|
||||
var controller = new LegacyOperatorController(
|
||||
lookup,
|
||||
manualListsWorkflow: new LegacyManualListsWorkflow(store, lookup));
|
||||
await controller.SelectTabAsync(LegacyOperatorTabId.Index);
|
||||
await controller.ActivateFixedSection(6);
|
||||
|
||||
var obsoleteSave = await controller.SaveManualNetSellAsync();
|
||||
var obsoleteAdd = controller.AddManualNetSellPlaylistRow();
|
||||
var switchedManual = await controller.OpenManualNetSellAsync(
|
||||
S5025ManualAudience.Institution);
|
||||
var switchedTab = await controller.SelectTabAsync(LegacyOperatorTabId.Exchange);
|
||||
|
||||
Assert.Equal(0, store.WriteNetCalls);
|
||||
Assert.Empty(obsoleteSave.Playlist);
|
||||
Assert.Empty(obsoleteAdd.Playlist);
|
||||
Assert.Equal(S5025ManualAudience.Individual, switchedManual.ManualLists!.Audience);
|
||||
Assert.Equal(S5025ManualAudience.Individual, switchedTab.ManualLists!.Audience);
|
||||
Assert.Equal(
|
||||
LegacyOperatorTabId.Index,
|
||||
Assert.Single(switchedTab.Tabs!, tab => tab.IsActive).Id);
|
||||
Assert.Empty(switchedTab.Playlist);
|
||||
}
|
||||
|
||||
private sealed class FakeLookup : ILegacyStockLookup
|
||||
{
|
||||
public Task<LegacyStockSearchData> SearchAsync(
|
||||
string query,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
Task.FromResult(new LegacyStockSearchData(
|
||||
query,
|
||||
["삼성전자"],
|
||||
[new LegacyStockIdentity(
|
||||
LegacyDomesticStockMarket.Kospi,
|
||||
"삼성전자",
|
||||
"005930")]));
|
||||
}
|
||||
|
||||
private sealed class FakeStore : ILegacyManualListStore
|
||||
{
|
||||
private readonly Dictionary<S5025ManualAudience, IReadOnlyList<S5025TrustedManualRow>>
|
||||
_net = Enum.GetValues<S5025ManualAudience>().ToDictionary(
|
||||
audience => audience,
|
||||
_ => (IReadOnlyList<S5025TrustedManualRow>)Rows());
|
||||
|
||||
public LegacyManualListStoreAvailability Availability { get; } =
|
||||
new(true, "READY", null);
|
||||
|
||||
public LegacyManualViStoreSnapshot Vi { get; set; } = new(
|
||||
Array.Empty<LegacyManualViStoredItem>(),
|
||||
new string('a', 64));
|
||||
|
||||
public int ReadNetCalls { get; private set; }
|
||||
public int WriteNetCalls { get; private set; }
|
||||
public int ReadViCalls { get; private set; }
|
||||
public int WriteViCalls { get; private set; }
|
||||
public int ImportCalls { get; private set; }
|
||||
public bool ThrowNetWrite { get; init; }
|
||||
public bool PersistBeforeNetThrow { get; init; }
|
||||
public bool ImportOutcomeUnknown { get; init; }
|
||||
|
||||
public Task<IReadOnlyList<S5025TrustedManualRow>> ReadNetSellAsync(
|
||||
S5025ManualAudience audience,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ReadNetCalls++;
|
||||
return Task.FromResult(_net[audience]);
|
||||
}
|
||||
|
||||
public Task WriteNetSellAsync(
|
||||
S5025ManualAudience audience,
|
||||
IReadOnlyList<S5025TrustedManualRow> rows,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
WriteNetCalls++;
|
||||
if (!ThrowNetWrite || PersistBeforeNetThrow)
|
||||
{
|
||||
_net[audience] = rows.ToArray();
|
||||
}
|
||||
|
||||
return ThrowNetWrite
|
||||
? Task.FromException(new IOException("ambiguous"))
|
||||
: Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task<LegacyManualViStoreSnapshot> ReadViAsync(
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ReadViCalls++;
|
||||
return Task.FromResult(Vi);
|
||||
}
|
||||
|
||||
public Task<LegacyManualViWriteReceipt> WriteViAsync(
|
||||
IReadOnlyList<LegacyManualViStoredItem> items,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
WriteViCalls++;
|
||||
Vi = new LegacyManualViStoreSnapshot(items.ToArray(), new string('c', 64));
|
||||
return Task.FromResult(new LegacyManualViWriteReceipt(Vi, true));
|
||||
}
|
||||
|
||||
public Task<LegacyManualImportReceipt> ImportAsync(
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ImportCalls++;
|
||||
return ImportOutcomeUnknown
|
||||
? Task.FromException<LegacyManualImportReceipt>(
|
||||
new LegacyManualImportStoreException("ROLLBACK_FAILED", true))
|
||||
: Task.FromResult(new LegacyManualImportReceipt(
|
||||
1,
|
||||
new string('d', 64),
|
||||
DateTimeOffset.UnixEpoch,
|
||||
15,
|
||||
0));
|
||||
}
|
||||
|
||||
private static S5025TrustedManualRow[] Rows() =>
|
||||
Enumerable.Range(1, 5).Select(index => new S5025TrustedManualRow(
|
||||
$"L{index}",
|
||||
index.ToString(System.Globalization.CultureInfo.InvariantCulture),
|
||||
$"R{index}",
|
||||
(-index).ToString(System.Globalization.CultureInfo.InvariantCulture))).ToArray();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user