#nullable enable using System.Data; using MBN_STOCK_WEBVIEW.DbWriteSmoke; using MMoneyCoderSharp.Data; namespace MBN_STOCK_WEBVIEW.DbWriteSmoke.Tests; public sealed class ExistingChildRowGuardTests { [Fact] public async Task ZeroCount_UsesBoundProductionSourceSpecificPreflights() { var executor = new RecordingExecutor("0"); var guard = new ExistingChildRowGuard(executor); await guard.EnsureNamedPlaylistChildrenAbsentAsync("00000042", default); await guard.EnsureThemeChildrenAbsentAsync(ThemeMarket.Krx, "00000043", default); await guard.EnsureThemeChildrenAbsentAsync(ThemeMarket.Nxt, "00000044", default); await guard.EnsureExpertChildrenAbsentAsync("0045", default); Assert.Equal(4, executor.Calls.Count); Assert.Equal( [DataSourceKind.Oracle, DataSourceKind.Oracle, DataSourceKind.MariaDb, DataSourceKind.Oracle], executor.Calls.Select(call => call.Source)); Assert.All(executor.Calls, call => { var parameter = Assert.Single(call.Spec.Parameters); Assert.Equal("parent_code", parameter.Name); Assert.Equal(DbType.String, parameter.DbType); Assert.DoesNotContain((string)parameter.Value!, call.Spec.Sql, StringComparison.Ordinal); }); } [Fact] public async Task ExistingOrInvalidChildCount_FailsClosedBeforeMutation() { var guard = new ExistingChildRowGuard(new RecordingExecutor("1")); await Assert.ThrowsAsync(() => guard.EnsureNamedPlaylistChildrenAbsentAsync("00000042", default)); } private sealed class RecordingExecutor(string count) : IDataQueryExecutor { public List Calls { get; } = []; public DataTable Execute(DataSourceKind source, string tableName, string query) => throw new NotSupportedException(); public Task ExecuteAsync( DataSourceKind source, string tableName, string query, CancellationToken cancellationToken = default) => throw new NotSupportedException(); public Task ExecuteAsync( DataSourceKind source, string tableName, DataQuerySpec query, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); Calls.Add(new QueryCall(source, tableName, query)); var table = new DataTable(); table.Columns.Add("ROW_COUNT", typeof(string)); table.Rows.Add(count); return Task.FromResult(table); } } private sealed record QueryCall( DataSourceKind Source, string QueryName, DataQuerySpec Spec); }