using System.Reflection; using Data.SeaHavenIndustries; using Data.SeaHavenIndustries.Migrations; using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; namespace SeaHavenIndustries.Tests; // SH-249/SH-247: provider-backed evidence for the Trades reference table and // the client-confirmed replacement taxonomy. public class SH249TradesVocabularyMigrationTests { [Fact] public async Task Up_CreatesTradesTableSeededWithCanonicalCatalogOnEmptyDatabase() { await using var connection = new SqliteConnection("Data Source=:memory:"); await connection.OpenAsync(); var options = new DbContextOptionsBuilder() .UseSqlite(connection) .Options; await using var context = new ApplicationDbContext(options); await ApplyMigrationAsync(context, new SH249_TradesVocabulary(), "Up"); await ApplyMigrationAsync(context, new SH247_CanonicalTradeTaxonomy(), "Up"); var seeded = await context.Trades .OrderBy(t => t.SortOrder) .ToListAsync(); Assert.Equal( TradeCatalog.CanonicalTrades, seeded.Select(t => t.Name).ToArray()); Assert.All(seeded, t => Assert.True(t.IsActive)); Assert.Equal( TradeCatalog.CanonicalTrades.Select(TradeCatalog.Normalize).ToArray(), seeded.Select(t => t.NormalizedName).ToArray()); } [Fact] public async Task Down_DropsTradesTable() { await using var connection = new SqliteConnection("Data Source=:memory:"); await connection.OpenAsync(); var options = new DbContextOptionsBuilder() .UseSqlite(connection) .Options; await using var context = new ApplicationDbContext(options); await ApplyMigrationAsync(context, new SH249_TradesVocabulary(), "Up"); await ApplyMigrationAsync(context, new SH247_CanonicalTradeTaxonomy(), "Up"); await ApplyMigrationAsync(context, new SH247_CanonicalTradeTaxonomy(), "Down"); await ApplyMigrationAsync(context, new SH249_TradesVocabulary(), "Down"); await using var command = connection.CreateCommand(); command.CommandText = "SELECT COUNT(*) FROM sqlite_master WHERE type = 'table' AND name = 'Trades';"; var tableCount = Convert.ToInt32(await command.ExecuteScalarAsync()); Assert.Equal(0, tableCount); } // Mirrors Phase4SearchIndexesSqlServerTests: invoke the protected Up/Down // body, translate through the configured provider's SQL generator, and // execute the produced commands against the live database. private static async Task ApplyMigrationAsync( ApplicationDbContext context, Migration migration, string direction) { var builder = new MigrationBuilder(context.Database.ProviderName!); var operation = typeof(Migration).GetMethod(direction, BindingFlags.Instance | BindingFlags.NonPublic) ?? throw new InvalidOperationException($"Migration.{direction} not found."); operation.Invoke(migration, [builder]); var sqlGenerator = context.GetService(); // InsertData operations need model metadata for column type mapping. var commands = sqlGenerator.Generate(builder.Operations, context.Model); foreach (var command in commands) await context.Database.ExecuteSqlRawAsync(command.CommandText); } }