package store import ( "testing" "time" "github.com/cosmic-clash/cosmic-clash/server/domain" ) func TestCandidateCacheRebuildRepairsLossAndKeepsDeterministicOrder(t *testing.T) { now := time.Unix(1000, 0) cache := NewCandidateCache() candidates := []domain.Candidate{{TicketID: "ticket-b", PlayerID: "player-b", EnqueuedAt: now}, {TicketID: "ticket-a", PlayerID: "player-a", EnqueuedAt: now}} if err := cache.Rebuild(candidates); err != nil { t.Fatal(err) } cache.Remove("ticket-a") if got := cache.Snapshot(now); len(got) != 1 || got[0].TicketID != "ticket-b" { t.Fatalf("stale cache snapshot = %+v", got) } if err := cache.Rebuild(candidates); err != nil { t.Fatal(err) } got := cache.Snapshot(now) if len(got) != 2 || got[0].TicketID != "ticket-a" || got[1].TicketID != "ticket-b" { t.Fatalf("repaired order = %+v", got) } } func TestCandidateCacheRejectsInvalidOrDuplicateDurableProjection(t *testing.T) { cache := NewCandidateCache() if err := cache.Upsert(domain.Candidate{TicketID: "", PlayerID: "p", EnqueuedAt: time.Unix(1000, 0)}); err == nil { t.Fatal("invalid candidate accepted") } candidate := domain.Candidate{TicketID: "ticket-a", PlayerID: "player-a", EnqueuedAt: time.Unix(1000, 0)} if err := cache.Rebuild([]domain.Candidate{candidate, candidate}); err == nil { t.Fatal("duplicate candidate accepted") } }