using System.Text.Json; using Dapper; using JdeScoping.Core.Models.Search; using Microsoft.Data.SqlClient; namespace JdeScoping.Database.Tests.Infrastructure; /// /// xUnit Collection definition to disable parallel execution for database tests. /// All test classes using [Collection("DatabaseTests")] run sequentially. /// [CollectionDefinition("DatabaseTests")] public class DatabaseTestCollection : ICollectionFixture { } /// /// Shared fixture for database tests. Ensures database is available. /// public class DatabaseTestFixture : IAsyncLifetime { /// /// Connection string for the test database. /// Uses SA credentials from db_info.md for local development. /// public const string ConnectionString = "Server=localhost,1434;Database=ScopingTool;User Id=sa;Password=ScopingTool_SA_2024Dev;TrustServerCertificate=true"; public async Task InitializeAsync() { // Verify database is accessible using var connection = new SqlConnection(ConnectionString); await connection.OpenAsync(); } public Task DisposeAsync() => Task.CompletedTask; } /// /// Base class for database function tests. /// Each test gets its own connection and cleans up created data. /// [Collection("DatabaseTests")] public abstract class DatabaseTestBase : IAsyncLifetime { protected SqlConnection Connection { get; private set; } = null!; private readonly List _createdSearchIds = []; public async Task InitializeAsync() { Connection = new SqlConnection(DatabaseTestFixture.ConnectionString); await Connection.OpenAsync(); } public async Task DisposeAsync() { // Clean up test data foreach (var id in _createdSearchIds) { await Connection.ExecuteAsync("DELETE FROM dbo.Search WHERE ID = @Id", new { Id = id }); } await Connection.DisposeAsync(); } /// /// Insert a test search with the given criteria and return the ID. /// protected async Task InsertTestSearchAsync(SearchCriteria criteria, string userName = "testuser", string name = "Test Search") { var criteriaJson = JsonSerializer.Serialize(criteria); var id = await Connection.QuerySingleAsync( @"INSERT INTO dbo.Search (UserName, Name, Status, Criteria) OUTPUT INSERTED.ID VALUES (@UserName, @Name, 0, @Criteria)", new { UserName = userName, Name = name, Criteria = criteriaJson }); _createdSearchIds.Add(id); return id; } /// /// Insert a test search with raw criteria JSON (for testing invalid JSON scenarios). /// protected async Task InsertTestSearchWithRawCriteriaAsync(string? criteriaJson, string userName = "testuser", string name = "Test Search") { var id = await Connection.QuerySingleAsync( @"INSERT INTO dbo.Search (UserName, Name, Status, Criteria) OUTPUT INSERTED.ID VALUES (@UserName, @Name, 0, @Criteria)", new { UserName = userName, Name = name, Criteria = criteriaJson }); _createdSearchIds.Add(id); return id; } }