package main import ( "context" "strings" "testing" llm "gitea.stevedudenhoeffer.com/steve/majordomo/llm" "gitea.stevedudenhoeffer.com/steve/majordomo/provider/fake" ) func TestShouldRecheck(t *testing.T) { t.Setenv("GADFLY_RECHECK", "") // default on if shouldRecheck("VERDICT: Blocking issues found\n- something is wrong") != true { t.Error("a draft with findings should be rechecked") } if shouldRecheck("No material issues found.") != false { t.Error("a clean draft should skip recheck") } if shouldRecheck("### review\n\nNo material issues found.\n") != false { t.Error("clean draft detection should be case/whitespace tolerant") } // Explicit disable wins even when there are findings. t.Setenv("GADFLY_RECHECK", "0") if shouldRecheck("Blocking issues found\n- x") != false { t.Error("GADFLY_RECHECK=0 must disable recheck") } t.Setenv("GADFLY_RECHECK", "false") if shouldRecheck("Blocking issues found\n- x") != false { t.Error("GADFLY_RECHECK=false must disable recheck") } } func TestRecheckEnabled(t *testing.T) { for _, v := range []string{"", "1", "true", "yes", "anything"} { t.Setenv("GADFLY_RECHECK", v) if !recheckEnabled() { t.Errorf("GADFLY_RECHECK=%q should be enabled", v) } } for _, v := range []string{"0", "false", "no", "off", "OFF", " False "} { t.Setenv("GADFLY_RECHECK", v) if recheckEnabled() { t.Errorf("GADFLY_RECHECK=%q should be disabled", v) } } } func TestBuildRecheckTask(t *testing.T) { t.Setenv("GADFLY_MAX_DIFF_CHARS", "") draft := "VERDICT: Blocking issues found\n- foo.go:1 broken" out := buildRecheckTask(draft, "diff --git a/x b/x\n+y\n") if !strings.Contains(out, draft) { t.Error("recheck task must include the draft review") } if !strings.Contains(out, "Verify") || !strings.Contains(out, "drop every finding you cannot confirm") { t.Errorf("recheck task missing the verify instruction:\n%s", out) } if !strings.Contains(out, "diff --git") { t.Error("recheck task should include the diff") } } // fakeModel builds a fake majordomo model that always replies with the given // text (no tool calls), so the agent loop ends on its first step. func fakeModel(t *testing.T, reply string) llm.Model { t.Helper() p := fake.New("fake", fake.WithDefault(func(string, llm.Request) fake.Step { return fake.Reply(reply) })) m, err := p.Model("mock") if err != nil { t.Fatal(err) } return m } func TestRunAgent_ReturnsOutput(t *testing.T) { fs, err := newRepoFS(t.TempDir(), "diff") if err != nil { t.Fatal(err) } mdl := fakeModel(t, " corrected review: No material issues found. ") out, err := runAgent(context.Background(), mdl, fs, "sys", "task", 4) if err != nil { t.Fatalf("runAgent: %v", err) } if out != "corrected review: No material issues found." { t.Errorf("runAgent should return trimmed model output, got %q", out) } } func TestRunAgent_EmptyIsError(t *testing.T) { fs, _ := newRepoFS(t.TempDir(), "diff") mdl := fakeModel(t, " ") if _, err := runAgent(context.Background(), mdl, fs, "sys", "task", 4); err == nil { t.Error("runAgent should error on empty model output") } }