using FluentAssertions; using IBKRTrader.Core.Logging; using IBKRTrader.Core.Persistence; using IBKRTrader.Core.Persistence.Ef; using IBKRTrader.Modules.Accounting.Persistence; using IBKRTrader.Modules.Accounting.Services; using IBKRTrader.Modules.Accounting.Ui; using IBKRTrader.Modules.Supervisor.Agent; using IBKRTrader.Modules.Supervisor.Persistence; using IBKRTrader.Modules.Supervisor.Services; using IBKRTrader.Modules.Supervisor.Ui; using Microsoft.EntityFrameworkCore; namespace IBKRTrader.Tests; /// /// Konstruiert die neuen Modul-Fenster mit In-Memory-/Stub-Abhängigkeiten – gleichwertig zum /// Headless-Smoke-UI-Check (`--smoke-ui`), aber ohne die laufende App/DB. Forms bauen im Konstruktor /// nur Controls (DB-Zugriff erst auf Interaktion), daher genügt Instanziierbarkeit der Services. /// [Trait("cat", "unit")] public class UiConstructionTests { private sealed class Factory(DbContextOptions options) : IDbContextFactory where T : DbContext { public T CreateDbContext() => (T)Activator.CreateInstance(typeof(T), options)!; } private static Factory InMemory() where T : DbContext => new(new DbContextOptionsBuilder().UseInMemoryDatabase(Guid.NewGuid().ToString()).Options); private sealed class NoChat : IChatCompletionClient { public Task CompleteAsync(string m, IReadOnlyList msgs, IReadOnlyList tools, CancellationToken ct) => Task.FromResult(new ChatResponse()); } private static Exception? ConstructOnSta(Action action) { Exception? captured = null; var t = new Thread(() => { try { action(); } catch (Exception ex) { captured = ex; } }); t.SetApartmentState(ApartmentState.STA); t.Start(); t.Join(); return captured; } [Fact] public void AccountingMainForm_Constructs() { var ex = ConstructOnSta(() => { var logger = new LoggingService(); var accDbf = InMemory(); var ledger = new EfLedgerRepository(accDbf); var runs = new EfIngestRunRepository(accDbf); var report = new AccountingReportService(ledger, new EfFxRateRepository(accDbf)); var ingest = new AccountingIngestService( new NullAccountSource(), ledger, runs, new EfRawSnapshotRepository(accDbf), new NullStatementSource(), new NullBalanceAnchorSource(), logger); using var form = new AccountingMainForm(ledger, runs, report, ingest, logger); form.Text.Should().Be("Accounting"); }); ex.Should().BeNull(); } [Fact] public void SupervisorMainForm_Constructs() { var ex = ConstructOnSta(() => { var logger = new LoggingService(); var coreDbf = InMemory(); var supDbf = InMemory(); IDecisionJournal journal = new EfDecisionJournal(coreDbf, logger); IOrderEventLog orderLog = new EfOrderEventLog(coreDbf, logger); var dossiers = new DossierService(journal, orderLog, new TradeLogReader(coreDbf)); var agent = new SupervisorAgent(new NoChat(), new SupervisorToolRegistry()); var reports = new EfSupervisorReportRepository(supDbf, logger); using var form = new SupervisorMainForm(agent, dossiers, reports, logger); form.Text.Should().Be("Supervisor"); }); ex.Should().BeNull(); } }