package domain import ( "errors" "testing" ) func TestNormalizeTargetCount(t *testing.T) { for _, tc := range []struct { input, want int }{ {0, 20}, {-2, 20}, {1, 1}, {40, 40}, {41, 40}, } { if got := NormalizeTargetCount(tc.input); got != tc.want { t.Fatalf("NormalizeTargetCount(%d) = %d, want %d", tc.input, got, tc.want) } } } func TestRunTransitionGuarded(t *testing.T) { run := NewRun("run-1", "job-1", 9, RunBrief{Intent: "topic", TargetCount: 3}, 1_700_000_000_000_000_000) if run.Status != RunQueued || run.CreatedAt == 0 { t.Fatalf("new run not queued with timestamp: %+v", run) } if err := run.Transition(RunSucceeded, 2); !errors.Is(err, ErrIllegalRunStatus) { t.Fatalf("queued -> succeeded should be guarded, got %v", err) } if err := run.Transition(RunRunning, 2); err != nil { t.Fatalf("queued -> running: %v", err) } if run.StartedAt != 2 { t.Fatalf("started_at = %d, want 2", run.StartedAt) } if err := run.Transition(RunSucceeded, 3); err != nil { t.Fatalf("running -> succeeded: %v", err) } if run.CompletedAt != 3 || !IsRunTerminal(run.Status) { t.Fatalf("terminal timestamps/status not set: %+v", run) } if err := run.Transition(RunRunning, 4); !errors.Is(err, ErrIllegalRunStatus) { t.Fatalf("terminal -> running should be guarded, got %v", err) } } func TestRunShortfallReasonsAreStableConstants(t *testing.T) { reasons := []string{ ShortfallSourceExhausted, ShortfallDuplicateExhausted, ShortfallRelevanceExhausted, ShortfallSourceUnavailable, ShortfallLimitReached, } seen := map[string]bool{} for _, reason := range reasons { if reason == "" || seen[reason] { t.Fatalf("invalid duplicate reason %q", reason) } seen[reason] = true } }