using System; using System.Linq; using PolyTrader.Modules.ResolutionFarming.Models; using PolyTrader.Modules.ResolutionFarming.Persistence.Ef; using PolyTrader.Tests.TestSupport; using Xunit; namespace PolyTrader.Tests { /// EF-InMemory-Tests der ResolutionFarming-Repositories (rf_-Tabellen). public class RfRepositoryTests { private static InMemoryContextFactory Factory() => new(o => new ResolutionFarmingDbContext(o)); // ----- Settings ----- [Fact] public void Settings_upsert_inserts_then_updates() { var f = Factory(); var repo = new EfRfSettingsRepository(f); repo.Upsert(new RfSettings { AccountId = 1, MaxPerMarketUsd = 25m }); repo.Upsert(new RfSettings { AccountId = 1, MaxPerMarketUsd = 50m }); Assert.Single(repo.GetAll()); Assert.Equal(50m, repo.Get(1)!.MaxPerMarketUsd); Assert.Null(repo.Get(99)); } // ----- Candidates ----- [Fact] public void Candidates_getrecent_orders_desc_and_limits() { var f = Factory(); var repo = new EfRfCandidateRepository(f); var t0 = new DateTime(2026, 7, 1, 0, 0, 0, DateTimeKind.Utc); for (int i = 0; i < 5; i++) repo.Insert(new RfCandidate { AccountId = 1, TokenId = "t" + i, ScannedAt = t0.AddMinutes(i) }); repo.Insert(new RfCandidate { AccountId = 2, TokenId = "other", ScannedAt = t0.AddMinutes(99) }); var recent = repo.GetRecent(1, 3); Assert.Equal(3, recent.Count); Assert.Equal("t4", recent[0].TokenId); // neuester zuerst Assert.DoesNotContain(recent, c => c.AccountId == 2); } [Fact] public void Candidate_id_is_db_generated() { var f = Factory(); var repo = new EfRfCandidateRepository(f); repo.Insert(new RfCandidate { AccountId = 1, TokenId = "a" }); repo.Insert(new RfCandidate { AccountId = 1, TokenId = "b" }); var ids = repo.GetRecent(1, 10).Select(c => c.Id).ToList(); Assert.Equal(2, ids.Distinct().Count()); Assert.DoesNotContain(0L, ids); // Autoincrement, keine code-vergebene 0 } // ----- Positions ----- [Fact] public void Positions_upsert_find_delete_and_exposure() { var f = Factory(); var repo = new EfRfPositionRepository(f); var now = DateTime.UtcNow; repo.Upsert(new RfPosition { AccountId = 1, TokenId = "a", AmountUsd = 10m, OpenedAt = now }); repo.Upsert(new RfPosition { AccountId = 1, TokenId = "b", AmountUsd = 15m, OpenedAt = now }); repo.Upsert(new RfPosition { AccountId = 2, TokenId = "c", AmountUsd = 99m, OpenedAt = now }); Assert.Equal(2, repo.GetOpen(1).Count); Assert.Equal(3, repo.GetAllOpen().Count); Assert.Equal(15m, repo.Find(1, "b")!.AmountUsd); // Update über denselben zusammengesetzten Schlüssel repo.Upsert(new RfPosition { AccountId = 1, TokenId = "a", AmountUsd = 12m, OpenedAt = now }); Assert.Equal(12m, repo.Find(1, "a")!.AmountUsd); Assert.Equal(2, repo.GetOpen(1).Count); // kein Duplikat repo.Delete(1, "a"); Assert.Null(repo.Find(1, "a")); } [Fact] public void Positions_countopenedsince_respects_account_and_time() { var f = Factory(); var repo = new EfRfPositionRepository(f); var today = DateTime.UtcNow; repo.Upsert(new RfPosition { AccountId = 1, TokenId = "a", OpenedAt = today }); repo.Upsert(new RfPosition { AccountId = 1, TokenId = "b", OpenedAt = today.AddDays(-2) }); repo.Upsert(new RfPosition { AccountId = 2, TokenId = "c", OpenedAt = today }); Assert.Equal(1, repo.CountOpenedSince(1, today.AddHours(-1))); } // ----- ClosedTrades ----- [Fact] public void ClosedTrades_insert_find_and_pnl_sum() { var f = Factory(); var repo = new EfRfClosedTradeRepository(f); var since = new DateTime(2026, 7, 9, 0, 0, 0, DateTimeKind.Utc); repo.Insert(new RfClosedTrade { AccountId = 1, TokenId = "a", RealizedPnl = 5m, ClosedAt = since.AddHours(1) }); repo.Insert(new RfClosedTrade { AccountId = 1, TokenId = "b", RealizedPnl = -8m, ClosedAt = since.AddHours(2) }); repo.Insert(new RfClosedTrade { AccountId = 1, TokenId = "c", RealizedPnl = 100m, ClosedAt = since.AddDays(-1) }); // vor dem Fenster repo.Insert(new RfClosedTrade { AccountId = 2, TokenId = "d", RealizedPnl = 50m, ClosedAt = since.AddHours(1) }); Assert.Equal(-3m, repo.RealizedPnlSince(1, since)); // 5 - 8, ohne 100 (zu alt), ohne Account 2 Assert.Equal(2, repo.Find(t => t.RealizedPnl > 0 && t.AccountId == 1).Count); // a (5) + c (100) } } }