Phase 7: Mapping-Randfälle + Parser-/Repo-Randfälle (78 Tests)
- DbContextModelTests: feinkörnige Modell-Invarianten - Dezimal-Präzision (18,6) auf Geldfeldern (Core + Settings), MaxLength auf Strings, manuell gesetzte Keys (ValueGeneratedNever), AssignedAccountIds hat Value-Converter + text-Spalte, MarketData JSON-Spalten = text, Indizes (TradeRecord.ClosedAt, MasterTraderHistory TraderId/ClosedAt). (GetColumnType() wirft unter InMemory -> Spaltentyp via Relational:ColumnType- Annotation ausgelesen.) - MongoExportParserTests erweitert: numerische statt String-Dezimale, unbekannte Felder ignoriert, mehrere Dokumente in Reihenfolge, AssignedAccountIds als String-Zahlen, IsActive-Default. - RepositoryEdgeCaseTests: GetAll leer != null, Update-Alias, Factory-Isolation, History-Exists/GetByTraderSince inklusive an den Grenzen. Alle 78 gruen. (Copytrading-Service-Logik bewusst noch nicht getestet - wird parallel ueberarbeitet.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
b8d2c8094b
commit
92a88e8be8
@@ -0,0 +1,72 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using PolyTrader.Modules.CopyTrading.Persistence.Ef;
|
||||
using PolyTrader.Tests.TestSupport;
|
||||
using PolyTraderSharp.Models;
|
||||
using Xunit;
|
||||
|
||||
namespace PolyTrader.Tests
|
||||
{
|
||||
public class RepositoryEdgeCaseTests
|
||||
{
|
||||
private static EfTrackedTraderRepository TraderRepo() =>
|
||||
new(new InMemoryContextFactory<CopyTradingDbContext>(o => new CopyTradingDbContext(o)));
|
||||
|
||||
private static EfMasterTraderHistoryRepository HistoryRepo() =>
|
||||
new(new InMemoryContextFactory<CopyTradingDbContext>(o => new CopyTradingDbContext(o)));
|
||||
|
||||
[Fact]
|
||||
public void GetAll_on_empty_repo_returns_empty_not_null()
|
||||
{
|
||||
var repo = TraderRepo();
|
||||
var all = repo.GetAll();
|
||||
Assert.NotNull(all);
|
||||
Assert.Empty(all);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Update_alias_behaves_like_upsert_for_existing()
|
||||
{
|
||||
var repo = TraderRepo();
|
||||
repo.Upsert(new TrackedTrader { Id = 1, DisplayName = "A" });
|
||||
repo.Update(new TrackedTrader { Id = 1, DisplayName = "B" });
|
||||
|
||||
Assert.Equal("B", Assert.Single(repo.GetAll()).DisplayName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Two_factories_are_isolated_from_each_other()
|
||||
{
|
||||
var a = TraderRepo();
|
||||
var b = TraderRepo();
|
||||
a.Upsert(new TrackedTrader { Id = 1 });
|
||||
|
||||
Assert.Single(a.GetAll());
|
||||
Assert.Empty(b.GetAll());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void History_Exists_is_inclusive_on_window_boundaries()
|
||||
{
|
||||
var repo = HistoryRepo();
|
||||
var t = new DateTime(2026, 7, 1, 12, 0, 0, DateTimeKind.Utc);
|
||||
repo.Insert(new MasterTraderHistoryRecord { TraderId = 1, TokenId = "tok", ClosedAt = t });
|
||||
|
||||
// Fenster endet exakt auf dem Zeitpunkt (untere Grenze)
|
||||
Assert.True(repo.Exists(1, "tok", t, t.AddSeconds(2)));
|
||||
// Fenster beginnt exakt auf dem Zeitpunkt (obere Grenze)
|
||||
Assert.True(repo.Exists(1, "tok", t.AddSeconds(-2), t));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetByTraderSince_is_inclusive_on_cutoff()
|
||||
{
|
||||
var repo = HistoryRepo();
|
||||
var cutoff = new DateTime(2026, 7, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
repo.Insert(new MasterTraderHistoryRecord { TraderId = 1, ClosedAt = cutoff }); // genau am Cutoff -> drin
|
||||
repo.Insert(new MasterTraderHistoryRecord { TraderId = 1, ClosedAt = cutoff.AddTicks(-1) }); // knapp davor -> raus
|
||||
|
||||
Assert.Single(repo.GetByTraderSince(1, cutoff));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user