Files
IBKRTrader/tests/IBKRTrader.Tests/Modules/CongressRepositoryTests.cs
T
RichardandClaude Opus 5 e1546bd1b1 Fruehjahrsputz: toter Code, ungenutzte Symbole, Dokumentenstand
Alles Entfernte war nachweislich ohne Aufrufer. Build, 198/198 Tests, Smoke-UI
und Daemon-Prueflauf sind vor und nach jedem Schritt gruen.

Code:
  - AIModelService: Platzhalter, der immer 0.5 lieferte. Im DI registriert,
    aber nie irgendwo injiziert. Ordner Core/AI faellt mit weg.
  - CtApiWrapper + CtMeta: JSON-Modelle fuer einen {data,meta}-Umschlag, den
    CapitolTrades nicht mehr liefert. Der Scraper deserialisiert seit laengerem
    direkt List<CtTrade>.
  - IBKRGatewayService: DisconnectAsync, InitBrokerageSessionAsync und
    SearchStocksBySymbolAsync. Der Dienst selbst bleibt - er versorgt
    Instrument-Sync, Kurshistorie und den Watchdog-Heartbeat.
  - Je eine Methode ohne Aufrufer: BudgetService.GetAvailableBudgetAsync,
    TradeHistoryService.GetRecentTradesAsync, CongressRepository.
    GetAllTradeIdsAsync und .ResetHistoryImportAsync, IbkrMapping.DefaultPortFor,
    SecretProtection.IsEncrypted.
  - CongressRepository bekam damit einen LoggingService injiziert, den es nicht
    mehr benutzt - Abhaengigkeit samt Konstruktorparameter raus.

Ressourcen:
  - 17 Symbole der WinForms-Oberflaeche entfernt. Das Wildcard-Muster im csproj
    nahm sie in die Binaerdatei auf, ViewIcons.cs bildet aber nur sieben
    Schluessel ab. Resources/ enthaelt jetzt genau die sieben.

NuGet-Allowlist:
  - Dapper und HtmlAgilityPack sind seit R3 bzw. R1 aus dem Projekt raus,
    Microsoft.WindowsDesktop.* seit L5. Muster entfernt.
  - MySqlConnector und Newtonsoft.Json stehen NUR transitiv in den
    Projektdateien und wurden zuerst mitentfernt - ein Restore in einen leeren
    Paket-Ordner scheiterte darauf mit NU1100. Beide wieder aufgenommen, jetzt
    mit Begruendung, damit der naechste Aufraeumlauf nicht dieselbe Falle tritt.

Dokumente an den tatsaechlichen Stand angeglichen:
  - ARCHITECTURE: R2 fuehrte die Umstellung auf IHostedService als offen, obwohl
    R4 sie erledigt hat. L6 und die Deploymentcenter-Phase fehlten ganz.
  - DC-Konzept: Schritte 0-8 standen auf "dieser Durchlauf", sind aber umgesetzt.
    Jetzt je Schritt der wirkliche Stand - inklusive der beiden Halbfertigen:
    Update-PRUEFUNG laeuft, das Anwenden hat keinen Aufrufer; die
    Release-Pipeline steht, ist aber nie gelaufen. P5 ist eingetreten.
  - Accounting und Supervisor trugen keinen Umsetzungsvermerk, obwohl beide
    Module gebaut sind. Vermerk nach dem Muster des Linux-Konzepts ergaenzt,
    mit dem, was jeweils offen bleibt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 12:25:03 +02:00

82 lines
3.1 KiB
C#

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;
/// <summary>EF-Repo des Moduls gegen EF-InMemory (deterministisch, kein externer DB-Zugriff).</summary>
[Trait("cat", "unit")]
public class CongressRepositoryTests
{
private sealed class Factory<T>(DbContextOptions<T> options) : IDbContextFactory<T> where T : DbContext
{
public T CreateDbContext() => (T)Activator.CreateInstance(typeof(T), options)!;
}
private static CongressRepository CreateSut()
{
var ctOpts = new DbContextOptionsBuilder<CongressTradingDbContext>()
.UseInMemoryDatabase(Guid.NewGuid().ToString()).Options;
var coreOpts = new DbContextOptionsBuilder<CoreDbContext>()
.UseInMemoryDatabase(Guid.NewGuid().ToString()).Options;
var settings = new CoreSettingsService(new Factory<CoreDbContext>(coreOpts));
return new CongressRepository(new Factory<CongressTradingDbContext>(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();
}
}