Complete legacy operator UI and playout migration
This commit is contained in:
@@ -0,0 +1,193 @@
|
||||
using System.Text;
|
||||
using MBN_STOCK_WEBVIEW.Infrastructure;
|
||||
|
||||
namespace MBN_STOCK_WEBVIEW.Infrastructure.Tests;
|
||||
|
||||
public sealed class ViTrustedManualFileStoreTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task ReadAsync_imports_the_original_nine_column_cp949_shape()
|
||||
{
|
||||
using var directory = new TemporaryDirectory();
|
||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
var cp949 = Encoding.GetEncoding(949);
|
||||
await File.WriteAllBytesAsync(
|
||||
Path.Combine(directory.Path, "VI발동.dat"),
|
||||
cp949.GetBytes(
|
||||
"PKR7005930003^삼성전자^^^^^^^\r\n" +
|
||||
"PKR7016360000^삼성증권^^^^^^^\r\n"));
|
||||
using var store = CreateStore(directory.Path);
|
||||
|
||||
var actual = await store.ReadAsync();
|
||||
|
||||
Assert.Equal(
|
||||
[
|
||||
new ViTrustedManualItem("PKR7005930003", "삼성전자"),
|
||||
new ViTrustedManualItem("PKR7016360000", "삼성증권")
|
||||
],
|
||||
actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WriteAsync_round_trips_order_duplicates_and_version()
|
||||
{
|
||||
using var directory = new TemporaryDirectory();
|
||||
using var store = CreateStore(directory.Path);
|
||||
ViTrustedManualItem[] expected =
|
||||
[
|
||||
new("005930", "삼성전자"),
|
||||
new("016360", "삼성증권"),
|
||||
new("005930", "삼성전자")
|
||||
];
|
||||
|
||||
var write = await store.WriteAsync(expected);
|
||||
|
||||
Assert.True(write.Persisted);
|
||||
Assert.Matches("^[a-f0-9]{64}$", write.Snapshot.RowVersion);
|
||||
Assert.Equal(expected, await store.ReadAsync());
|
||||
Assert.Empty(Directory.EnumerateFiles(directory.Path, "*.tmp"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Empty_list_is_an_original_compatible_no_op()
|
||||
{
|
||||
using var directory = new TemporaryDirectory();
|
||||
using var store = CreateStore(directory.Path);
|
||||
|
||||
var firstNoOp = await store.WriteAsync(Array.Empty<ViTrustedManualItem>());
|
||||
Assert.False(firstNoOp.Persisted);
|
||||
Assert.False(File.Exists(Path.Combine(directory.Path, "VI발동.dat")));
|
||||
Assert.Empty(await store.ReadAsync());
|
||||
|
||||
var expected = new[] { new ViTrustedManualItem("005930", "삼성전자") };
|
||||
var written = await store.WriteAsync(expected);
|
||||
var secondNoOp = await store.WriteAsync(Array.Empty<ViTrustedManualItem>());
|
||||
|
||||
Assert.False(secondNoOp.Persisted);
|
||||
Assert.Equal(written.Snapshot.RowVersion, secondNoOp.Snapshot.RowVersion);
|
||||
Assert.Equal(expected, await store.ReadAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Missing_file_is_an_empty_versioned_first_run_list()
|
||||
{
|
||||
using var directory = new TemporaryDirectory();
|
||||
using var store = CreateStore(directory.Path);
|
||||
|
||||
var snapshot = await store.ReadSnapshotAsync();
|
||||
|
||||
Assert.Empty(snapshot.Items);
|
||||
Assert.Equal(
|
||||
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
snapshot.RowVersion);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ReadAsync_rejects_nonempty_legacy_extra_columns()
|
||||
{
|
||||
using var directory = new TemporaryDirectory();
|
||||
await File.WriteAllTextAsync(
|
||||
Path.Combine(directory.Path, "VI발동.dat"),
|
||||
"005930^삼성전자^unexpected^^^^^^\r\n");
|
||||
using var store = CreateStore(directory.Path);
|
||||
|
||||
await Assert.ThrowsAsync<ViTrustedManualDataException>(() => store.ReadAsync());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("", "삼성전자")]
|
||||
[InlineData("005930", "")]
|
||||
[InlineData("005^930", "삼성전자")]
|
||||
[InlineData("005930", "삼성\n전자")]
|
||||
[InlineData(" 005930", "삼성전자")]
|
||||
[InlineData("005930", "삼성전자 ")]
|
||||
[InlineData("005930", "삼성,전자")]
|
||||
[InlineData("005930", "😀")]
|
||||
public async Task WriteAsync_rejects_invalid_or_non_cp949_values(string code, string name)
|
||||
{
|
||||
using var directory = new TemporaryDirectory();
|
||||
using var store = CreateStore(directory.Path);
|
||||
|
||||
await Assert.ThrowsAsync<ViTrustedManualDataException>(() =>
|
||||
store.WriteAsync([new ViTrustedManualItem(code, name)]));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WriteAsync_caps_the_original_five_row_scene_at_twenty_pages()
|
||||
{
|
||||
using var directory = new TemporaryDirectory();
|
||||
using var store = CreateStore(directory.Path);
|
||||
var items = Enumerable.Range(1, ViTrustedManualFileStore.MaximumItemCount + 1)
|
||||
.Select(index => new ViTrustedManualItem(index.ToString("D6"), $"종목{index}"))
|
||||
.ToArray();
|
||||
|
||||
await Assert.ThrowsAsync<ViTrustedManualDataException>(() => store.WriteAsync(items));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WriteAsync_honors_pre_cancelled_token()
|
||||
{
|
||||
using var directory = new TemporaryDirectory();
|
||||
using var store = CreateStore(directory.Path);
|
||||
using var cancellation = new CancellationTokenSource();
|
||||
cancellation.Cancel();
|
||||
|
||||
await Assert.ThrowsAnyAsync<OperationCanceledException>(() =>
|
||||
store.WriteAsync(
|
||||
[new ViTrustedManualItem("005930", "삼성전자")],
|
||||
cancellation.Token));
|
||||
Assert.Empty(Directory.EnumerateFiles(directory.Path));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Canonical_snapshot_version_covers_all_twenty_pages()
|
||||
{
|
||||
using var directory = new TemporaryDirectory();
|
||||
using var store = CreateStore(directory.Path);
|
||||
var items = Enumerable.Range(1, ViTrustedManualFileStore.MaximumItemCount)
|
||||
.Select(index => new ViTrustedManualItem(
|
||||
$"P{index:D6}",
|
||||
$"현실적인긴종목명테스트{index}"))
|
||||
.ToArray();
|
||||
|
||||
var written = await store.WriteAsync(items);
|
||||
var snapshot = await store.ReadSnapshotAsync();
|
||||
|
||||
Assert.True(written.Persisted);
|
||||
Assert.Equal(100, snapshot.Items.Count);
|
||||
Assert.Equal(written.Snapshot.RowVersion, snapshot.RowVersion);
|
||||
Assert.Matches("^[a-f0-9]{64}$", snapshot.RowVersion);
|
||||
}
|
||||
|
||||
private static ViTrustedManualFileStore CreateStore(string directory)
|
||||
{
|
||||
TrustedManualDirectory.PreparePrivateWritableDirectory(directory);
|
||||
return new ViTrustedManualFileStore(directory);
|
||||
}
|
||||
|
||||
private sealed class TemporaryDirectory : IDisposable
|
||||
{
|
||||
public TemporaryDirectory()
|
||||
{
|
||||
Path = System.IO.Path.Combine(
|
||||
System.IO.Path.GetTempPath(),
|
||||
Guid.NewGuid().ToString("N"));
|
||||
Directory.CreateDirectory(Path);
|
||||
}
|
||||
|
||||
public string Path { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.Delete(Path, recursive: true);
|
||||
}
|
||||
catch (Exception exception) when (exception is
|
||||
IOException or UnauthorizedAccessException)
|
||||
{
|
||||
// Cleanup must not hide the test result.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user