using System;
using System.Collections.Generic;
using System.Data;
namespace Kit.Helpers.SqlHelperAbstract
{
///
/// Строка подключения для unit-тестов: единственный публичный вход в тестовое API (конвенция 1:1).
/// Фейк-транспорт (SqlHelperTest) — internal: недостижим из внешнего и прод-кода,
/// в том числе через new; тестирование репозиториев идёт только через этот интерфейс.
///
public interface IConnectionStringTest : IConnectionString
{
/// Падает, если открытая заготовка не израсходована вызовом транспорта.
void VerifyAll();
/// Снапшоты всех запросов к транспорту, в порядке вызовов (ассерты снаружи).
IReadOnlyList Requests { get; }
}
///
/// Строка подключения для unit-тестов: вместо соединения с БД возвращает внутренний фейк-транспорт.
/// Один экземпляр на тест-метод, конвенция 1:1 (одна заготовка = один вызов транспорта = один метод репозитория):
/// var expArgs = new ConnectionString().PrepareExecute("req.requirement_select")
/// .AsStoredProcedure()
/// .AddParameter("p_doc_code", "TEST-DOC")
/// .AddParameter("p_rid", DBNull.Value)
/// .BuildParams();
/// var cs = new ConnectionStringTest(expArgs, _fxRequirementTable); // один DataTable = один курсор
/// var rows = new RequirementRepository(cs).SelectRequirements(filter);
/// cs.VerifyAll();
/// // дополнительные ассерты: cs.Requests — журнал вызовов транспорта.
/// Скалярный ответ (ExecuteScalar/NonQuery) — фабрика ConnectionStringTest.Scalar(expArgs, 1).
/// Заготовкаввввake_case, типизированные DataColumn — значения в CLR-типах,
/// которые вернул бы Npgsql (integer → int, bigint → long, boolean → bool, text → string,
/// timestamptz → DateTime); null-ячейка — DBNull.Value (NULL-строка LEFT JOIN).
/// Беззначная заявка параметра (только наличие, значение не сверяется) — маркер ParamExpect.Any.
///
public class ConnectionStringTest : ConnectionString, IConnectionStringTest
{
private readonly SqlHelperTest _sqlHelper;
///
/// Заготовка выборки: таблицы DataTable — по одной на курсор (курсор ↔ конвертер),
/// порядок таблиц = порядок курсоров функции БД; пустой результат — таблица с колонками без строк.
///
public ConnectionStringTest(RequestParams requestParams, params DataTable[] resultTables)
: this(requestParams, resultTables, scalarResult: null)
{
}
///
/// Заготовка скалярного ответа (ExecuteScalar; для ExecuteNonQuery результат не читается,
/// но заготовка обязана быть описана — конвенция «ответ обязан быть описан»).
///
public static ConnectionStringTest Scalar(RequestParams requestParams, object scalarResult) =>
new(requestParams, Array.Empty(), scalarResult);
private ConnectionStringTest(RequestParams requestParams, DataTable[] resultTables, object? scalarResult)
{
_sqlHelper = new SqlHelperTest(requestParams, resultTables, scalarResult);
}
public override ISqlHelper GetSqlHelper() => _sqlHelper;
public void VerifyAll() => _sqlHelper.VerifyAll();
public IReadOnlyList Requests => _sqlHelper.Requests;
}
/// Маркеры ожиданий параметров заготовки ConnectionStringTest.
public static class ParamExpect
{
/// Беззначная заявка: параметр обязан уйти в запрос, значение не сверяется.
public static readonly object Any = new();
}
}