using FluentAssertions;
using IBKRTrader.Core.Logging;
using IBKRTrader.Core.Persistence.Ef;
using IBKRTrader.Core.Settings;
using IBKRTrader.Modules.CongressTrading.Database;
using IBKRTrader.Modules.CongressTrading.Models;
using IBKRTrader.Modules.CongressTrading.Persistence.Ef;
using Microsoft.EntityFrameworkCore;
namespace IBKRTrader.Tests.Modules;
/// EF-Repo des Moduls gegen EF-InMemory (deterministisch, kein externer DB-Zugriff).
[Trait("cat", "unit")]
public class CongressRepositoryTests
{
private sealed class Factory(DbContextOptions options) : IDbContextFactory where T : DbContext
{
public T CreateDbContext() => (T)Activator.CreateInstance(typeof(T), options)!;
}
private static CongressRepository CreateSut()
{
var ctOpts = new DbContextOptionsBuilder()
.UseInMemoryDatabase(Guid.NewGuid().ToString()).Options;
var coreOpts = new DbContextOptionsBuilder()
.UseInMemoryDatabase(Guid.NewGuid().ToString()).Options;
var settings = new CoreSettingsService(new Factory(coreOpts));
return new CongressRepository(new Factory(ctOpts), settings);
}
[Fact]
public async Task UpsertMember_IsIdempotent_ByBioId()
{
var repo = CreateSut();
await repo.UpsertMemberAsync(new CongressMember { BioId = "W1", Name = "Alice" });
await repo.UpsertMemberAsync(new CongressMember { BioId = "W1", Name = "Alice B." });
(await repo.MemberExistsAsync("W1")).Should().BeTrue();
(await repo.GetMemberCountAsync()).Should().Be(1);
(await repo.GetAllMemberBioIdsAsync()).Should().Contain("W1");
}
[Fact]
public async Task InsertTrade_IgnoresDuplicateTradeId()
{
var repo = CreateSut();
await repo.InsertTradeAsync(new CongressTrade { TradeId = "T1", MemberBioId = "W1", Ticker = "AAPL", TradeType = "buy" });
await repo.InsertTradeAsync(new CongressTrade { TradeId = "T1", MemberBioId = "W1", Ticker = "AAPL" });
(await repo.TradeExistsAsync("T1")).Should().BeTrue();
(await repo.GetTradeCountAsync()).Should().Be(1);
}
[Fact]
public async Task DetailsFlow_MarksTradeComplete()
{
var repo = CreateSut();
await repo.InsertTradeAsync(new CongressTrade { TradeId = "T2" }, detailsFetched: false);
(await repo.GetTradesWithoutDetailsAsync()).Should().Contain("T2");
await repo.UpdateTradeDetailsAsync(new CongressTrade { TradeId = "T2", Ticker = "MSFT", TradeType = "sell" });
(await repo.GetTradesWithoutDetailsAsync()).Should().NotContain("T2");
}
[Fact]
public async Task Settings_RoundTripThroughCoreSettings()
{
var repo = CreateSut();
await repo.SetSettingAsync("ct.history_import_page", "7");
(await repo.GetSettingAsync("ct.history_import_page")).Should().Be("7");
await repo.DeleteSettingAsync("ct.history_import_page");
(await repo.GetSettingAsync("ct.history_import_page")).Should().BeNull();
}
}