test: batch 3 — add 73 Good/Bad/Ugly tests across 9 files

Fill missing categories for:
- prep.go: 25 lifecycle/detect/env tests
- prep_extra.go: pullWikiContent/renderPlan/brainRecall/findConsumers Ugly
- pr.go: buildPRBody/commentOnIssue/createPR/listPRs/listRepoPRs GBU
- epic.go: createEpic/createIssue/resolveLabelIDs/createLabel Ugly
- scan.go: scan/listOrgRepos/listRepoIssues GBU
- events (logic_test.go): emitStartEvent/emitCompletionEvent GBU
- review_queue_extra.go: buildReviewCommand/countFindings/parseRetryAfter/store/save/load
- watch.go: findActiveWorkspaces/resolveWorkspaceDir Bad/Ugly
- paths.go: newFs/parseInt Good
- plan_crud.go: generatePlanID/planList/writePlan Bad/Ugly

AX-7 scorecard: 425/516 categories filled (82%)
Gap: 166 → 91 missing categories
Tests: 690 → 765 (+75)
Coverage: 76.0% → 76.8%

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Snider 2026-03-25 09:19:05 +00:00
parent 9002b7ca8a
commit eeaed52256
10 changed files with 1239 additions and 1 deletions

View file

@ -7,6 +7,7 @@ import (
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"sync/atomic"
"testing"
"time"
@ -391,3 +392,55 @@ func TestEpic_CreateEpic_Good_AgenticLabelNotDuplicated(t *testing.T) {
require.NoError(t, err)
assert.True(t, out.Success)
}
// --- Ugly tests ---
func TestEpic_CreateEpic_Ugly(t *testing.T) {
// Very long title/description
srv, _ := mockForgeServer(t)
s := newTestSubsystem(t, srv)
longTitle := strings.Repeat("Very Long Epic Title ", 50)
longBody := strings.Repeat("Detailed description of the epic work to be done. ", 100)
_, out, err := s.createEpic(context.Background(), nil, EpicInput{
Repo: "test-repo",
Title: longTitle,
Body: longBody,
Tasks: []string{"Task 1"},
})
require.NoError(t, err)
assert.True(t, out.Success)
assert.NotZero(t, out.EpicNumber)
}
func TestEpic_CreateIssue_Ugly(t *testing.T) {
// Issue with HTML in body
srv, _ := mockForgeServer(t)
s := newTestSubsystem(t, srv)
htmlBody := "<h1>Issue</h1><p>This has <b>bold</b> and <script>alert('xss')</script></p>"
child, err := s.createIssue(context.Background(), "core", "test-repo", "HTML Issue", htmlBody, []int64{1})
require.NoError(t, err)
assert.Equal(t, "HTML Issue", child.Title)
assert.NotZero(t, child.Number)
}
func TestEpic_ResolveLabelIDs_Ugly(t *testing.T) {
// Label names with special chars
srv, _ := mockForgeServer(t)
s := newTestSubsystem(t, srv)
ids := s.resolveLabelIDs(context.Background(), "core", "test-repo", []string{"bug/fix", "feature:new", "label with spaces"})
// These will all be created as new labels since they don't match existing ones
assert.NotNil(t, ids)
}
func TestEpic_CreateLabel_Ugly(t *testing.T) {
// Label with unicode name
srv, _ := mockForgeServer(t)
s := newTestSubsystem(t, srv)
id := s.createLabel(context.Background(), "core", "test-repo", "\u00e9nhancement-\u00fc\u00f1ic\u00f6de")
assert.NotZero(t, id)
}

View file

@ -377,6 +377,106 @@ func TestEvents_EmitEvent_Ugly_EmptyFields(t *testing.T) {
})
}
// --- emitStartEvent/emitCompletionEvent (Good/Bad/Ugly) ---
func TestEvents_EmitStartEvent_Good(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
require.True(t, fs.EnsureDir(filepath.Join(root, "workspace")).OK)
emitStartEvent("codex", "core/go-io/task-10")
eventsFile := filepath.Join(root, "workspace", "events.jsonl")
r := fs.Read(eventsFile)
require.True(t, r.OK)
content := r.Value.(string)
assert.Contains(t, content, "agent_started")
assert.Contains(t, content, "codex")
assert.Contains(t, content, "core/go-io/task-10")
}
func TestEvents_EmitStartEvent_Bad(t *testing.T) {
// Empty agent name
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
require.True(t, fs.EnsureDir(filepath.Join(root, "workspace")).OK)
assert.NotPanics(t, func() {
emitStartEvent("", "core/go-io/task-10")
})
eventsFile := filepath.Join(root, "workspace", "events.jsonl")
r := fs.Read(eventsFile)
require.True(t, r.OK)
content := r.Value.(string)
assert.Contains(t, content, "agent_started")
}
func TestEvents_EmitStartEvent_Ugly(t *testing.T) {
// Very long workspace name
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
require.True(t, fs.EnsureDir(filepath.Join(root, "workspace")).OK)
longName := strings.Repeat("very-long-workspace-name-", 50)
assert.NotPanics(t, func() {
emitStartEvent("claude", longName)
})
eventsFile := filepath.Join(root, "workspace", "events.jsonl")
r := fs.Read(eventsFile)
require.True(t, r.OK)
assert.Contains(t, r.Value.(string), "agent_started")
}
func TestEvents_EmitCompletionEvent_Good(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
require.True(t, fs.EnsureDir(filepath.Join(root, "workspace")).OK)
emitCompletionEvent("gemini", "core/go-log/task-5", "completed")
eventsFile := filepath.Join(root, "workspace", "events.jsonl")
r := fs.Read(eventsFile)
require.True(t, r.OK)
content := r.Value.(string)
assert.Contains(t, content, "agent_completed")
assert.Contains(t, content, "gemini")
assert.Contains(t, content, "completed")
}
func TestEvents_EmitCompletionEvent_Bad(t *testing.T) {
// Empty status
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
require.True(t, fs.EnsureDir(filepath.Join(root, "workspace")).OK)
assert.NotPanics(t, func() {
emitCompletionEvent("claude", "core/agent/task-1", "")
})
eventsFile := filepath.Join(root, "workspace", "events.jsonl")
r := fs.Read(eventsFile)
require.True(t, r.OK)
assert.Contains(t, r.Value.(string), "agent_completed")
}
func TestEvents_EmitCompletionEvent_Ugly(t *testing.T) {
// Unicode in agent name
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
require.True(t, fs.EnsureDir(filepath.Join(root, "workspace")).OK)
assert.NotPanics(t, func() {
emitCompletionEvent("\u00e9nchantr\u00efx-\u2603", "core/agent/task-1", "completed")
})
eventsFile := filepath.Join(root, "workspace", "events.jsonl")
r := fs.Read(eventsFile)
require.True(t, r.OK)
assert.Contains(t, r.Value.(string), "\u00e9nchantr\u00efx")
}
// --- countFileRefs ---
func TestIngest_CountFileRefs_Good_GoRefs(t *testing.T) {

View file

@ -321,7 +321,20 @@ func TestPaths_ParseInt_Ugly_LeadingTrailingWhitespace(t *testing.T) {
assert.Equal(t, 42, parseInt(" 42 "))
}
// --- newFs Bad/Ugly ---
// --- newFs Good/Bad/Ugly ---
func TestPaths_NewFs_Good(t *testing.T) {
f := newFs("/tmp")
assert.NotNil(t, f, "newFs should return a non-nil Fs")
assert.IsType(t, &core.Fs{}, f)
}
// --- parseInt Good ---
func TestPaths_ParseInt_Good(t *testing.T) {
assert.Equal(t, 42, parseInt("42"))
assert.Equal(t, 0, parseInt("0"))
}
func TestPaths_NewFs_Bad_EmptyRoot(t *testing.T) {
f := newFs("")

View file

@ -506,3 +506,92 @@ func TestPlan_ValidPlanStatus_Ugly_NearMissStatus(t *testing.T) {
assert.False(t, validPlanStatus(" draft")) // leading space
assert.False(t, validPlanStatus("draft ")) // trailing space
}
// --- generatePlanID Bad/Ugly ---
func TestPlan_GeneratePlanID_Bad(t *testing.T) {
// Empty title — slug will be empty, but random suffix is still appended
id := generatePlanID("")
assert.NotEmpty(t, id, "should still generate an ID with random suffix")
assert.Contains(t, id, "-", "should have random suffix separated by dash")
}
func TestPlan_GeneratePlanID_Ugly(t *testing.T) {
// Title with only special chars — slug will be empty
id := generatePlanID("!@#$%^&*()")
assert.NotEmpty(t, id, "should still generate an ID with random suffix")
}
// --- planList Bad/Ugly ---
func TestPlan_PlanList_Bad(t *testing.T) {
// Plans dir doesn't exist yet — should create it
dir := t.TempDir()
t.Setenv("CORE_WORKSPACE", dir)
s := newTestPrep(t)
_, out, err := s.planList(context.Background(), nil, PlanListInput{})
require.NoError(t, err)
assert.True(t, out.Success)
assert.Equal(t, 0, out.Count)
}
func TestPlan_PlanList_Ugly(t *testing.T) {
// Plans dir has corrupt JSON files
dir := t.TempDir()
t.Setenv("CORE_WORKSPACE", dir)
s := newTestPrep(t)
// Create a real plan
s.planCreate(context.Background(), nil, PlanCreateInput{Title: "Real Plan", Objective: "Test"})
// Write corrupt JSON file in plans dir
plansDir := PlansRoot()
os.WriteFile(plansDir+"/corrupt-plan.json", []byte("not valid json {{{"), 0o644)
_, out, err := s.planList(context.Background(), nil, PlanListInput{})
require.NoError(t, err)
assert.Equal(t, 1, out.Count, "corrupt JSON file should be skipped")
}
// --- writePlan Bad/Ugly ---
func TestPlan_WritePlan_Bad(t *testing.T) {
// Plan with empty ID
dir := t.TempDir()
plan := &Plan{
ID: "",
Title: "No ID Plan",
Status: "draft",
Objective: "Test empty ID",
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
// Should write with planPath sanitising empty ID to "invalid"
path, err := writePlan(dir, plan)
require.NoError(t, err)
assert.Contains(t, path, "invalid.json")
}
func TestPlan_WritePlan_Ugly(t *testing.T) {
// Plan with moderately long ID (within filesystem limits)
dir := t.TempDir()
longID := strings.Repeat("a", 100)
plan := &Plan{
ID: longID,
Title: "Long ID Plan",
Status: "draft",
Objective: "Test long ID",
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
path, err := writePlan(dir, plan)
require.NoError(t, err)
assert.NotEmpty(t, path)
assert.Contains(t, path, ".json")
// Verify we can read it back
readBack, err := readPlan(dir, longID)
require.NoError(t, err)
assert.Equal(t, "Long ID Plan", readBack.Title)
}

View file

@ -7,8 +7,10 @@ import (
"encoding/json"
"net/http"
"net/http/httptest"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
"time"
@ -264,3 +266,275 @@ func TestPr_CommentOnIssue_Good_PostsComment(t *testing.T) {
s.commentOnIssue(context.Background(), "core", "go-io", 42, "Test comment")
assert.True(t, commentPosted)
}
// --- buildPRBody ---
func TestPr_BuildPRBody_Good(t *testing.T) {
s := &PrepSubsystem{}
st := &WorkspaceStatus{
Status: "completed",
Repo: "go-io",
Task: "Fix the login bug",
Agent: "codex",
Branch: "agent/fix-login",
Issue: 42,
Runs: 3,
}
body := s.buildPRBody(st)
assert.Contains(t, body, "## Summary")
assert.Contains(t, body, "Fix the login bug")
assert.Contains(t, body, "Closes #42")
assert.Contains(t, body, "**Agent:** codex")
assert.Contains(t, body, "**Runs:** 3")
}
func TestPr_BuildPRBody_Bad(t *testing.T) {
// Empty status struct
s := &PrepSubsystem{}
st := &WorkspaceStatus{}
body := s.buildPRBody(st)
assert.Contains(t, body, "## Summary")
assert.Contains(t, body, "**Agent:**")
assert.NotContains(t, body, "Closes #")
}
func TestPr_BuildPRBody_Ugly(t *testing.T) {
// Very long task string
s := &PrepSubsystem{}
longTask := strings.Repeat("This is a very long task description. ", 100)
st := &WorkspaceStatus{
Task: longTask,
Agent: "claude",
Runs: 1,
}
body := s.buildPRBody(st)
assert.Contains(t, body, "## Summary")
assert.Contains(t, body, "very long task")
}
// --- commentOnIssue Bad/Ugly ---
func TestPr_CommentOnIssue_Bad(t *testing.T) {
// Forge returns error (500)
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(500)
}))
t.Cleanup(srv.Close)
s := &PrepSubsystem{
forge: forge.NewForge(srv.URL, "test-token"),
forgeURL: srv.URL,
forgeToken: "test-token",
client: srv.Client(),
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
// Should not panic even on server error
assert.NotPanics(t, func() {
s.commentOnIssue(context.Background(), "core", "go-io", 42, "Test comment")
})
}
func TestPr_CommentOnIssue_Ugly(t *testing.T) {
// Very long comment body
commentPosted := false
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == "POST" {
commentPosted = true
w.WriteHeader(201)
}
}))
t.Cleanup(srv.Close)
s := &PrepSubsystem{
forge: forge.NewForge(srv.URL, "test-token"),
forgeURL: srv.URL,
forgeToken: "test-token",
client: srv.Client(),
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
longComment := strings.Repeat("This is a very long comment with details. ", 1000)
s.commentOnIssue(context.Background(), "core", "go-io", 42, longComment)
assert.True(t, commentPosted)
}
// --- createPR Ugly ---
func TestPr_CreatePR_Ugly(t *testing.T) {
// Workspace with no branch in status (auto-detect from git)
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsDir := filepath.Join(root, "workspace", "test-ws-ugly")
repoDir := filepath.Join(wsDir, "repo")
require.NoError(t, exec.Command("git", "init", "-b", "main", repoDir).Run())
gitCmd := exec.Command("git", "config", "user.name", "Test")
gitCmd.Dir = repoDir
gitCmd.Run()
gitCmd = exec.Command("git", "config", "user.email", "test@test.com")
gitCmd.Dir = repoDir
gitCmd.Run()
// Need an initial commit so HEAD exists for branch detection
require.NoError(t, os.WriteFile(filepath.Join(repoDir, "README.md"), []byte("# Test"), 0o644))
addCmd := exec.Command("git", "add", ".")
addCmd.Dir = repoDir
require.NoError(t, addCmd.Run())
commitCmd := exec.Command("git", "commit", "-m", "init")
commitCmd.Dir = repoDir
require.NoError(t, commitCmd.Run())
// Write status with empty branch
require.NoError(t, writeStatus(wsDir, &WorkspaceStatus{
Status: "completed",
Repo: "go-io",
Branch: "", // empty branch — should auto-detect
Task: "Fix something",
}))
s := &PrepSubsystem{
forgeToken: "test-token",
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
_, out, err := s.createPR(context.Background(), nil, CreatePRInput{
Workspace: "test-ws-ugly",
DryRun: true,
})
require.NoError(t, err)
assert.True(t, out.Success)
assert.NotEmpty(t, out.Branch, "branch should be auto-detected from git")
}
// --- forgeCreatePR Ugly ---
func TestPr_ForgeCreatePR_Ugly(t *testing.T) {
// Server returns 201 with unexpected JSON
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == "POST" {
w.WriteHeader(201)
json.NewEncoder(w).Encode(map[string]any{
"unexpected": "fields",
"number": 0,
})
return
}
w.WriteHeader(200)
}))
t.Cleanup(srv.Close)
s := &PrepSubsystem{
forge: forge.NewForge(srv.URL, "test-token"),
forgeURL: srv.URL,
forgeToken: "test-token",
client: srv.Client(),
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
// Should not panic — may return zero values for missing fields
assert.NotPanics(t, func() {
_, _, _ = s.forgeCreatePR(
context.Background(),
"core", "test-repo",
"agent/fix", "dev",
"Title", "Body",
)
})
}
// --- listPRs Ugly ---
func TestPr_ListPRs_Ugly(t *testing.T) {
// State filter "all"
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if containsStr(r.URL.Path, "/repos") && !containsStr(r.URL.Path, "/pulls") {
json.NewEncoder(w).Encode([]map[string]any{
{"name": "go-io", "full_name": "core/go-io"},
})
return
}
json.NewEncoder(w).Encode([]map[string]any{})
}))
t.Cleanup(srv.Close)
s := &PrepSubsystem{
forge: forge.NewForge(srv.URL, "test-token"),
forgeURL: srv.URL,
forgeToken: "test-token",
client: srv.Client(),
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
_, out, err := s.listPRs(context.Background(), nil, ListPRsInput{
State: "all",
})
require.NoError(t, err)
assert.True(t, out.Success)
}
// --- listRepoPRs Good/Bad/Ugly ---
func TestPr_ListRepoPRs_Good(t *testing.T) {
// Specific repo with PRs
srv := mockPRForgeServer(t)
s := &PrepSubsystem{
forge: forge.NewForge(srv.URL, "test-token"),
forgeURL: srv.URL,
forgeToken: "test-token",
client: srv.Client(),
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
prs, err := s.listRepoPRs(context.Background(), "core", "test-repo", "open")
require.NoError(t, err)
// May be empty depending on mock, but should not error
_ = prs
}
func TestPr_ListRepoPRs_Bad(t *testing.T) {
// Forge returns error
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(500)
}))
t.Cleanup(srv.Close)
s := &PrepSubsystem{
forge: forge.NewForge(srv.URL, "test-token"),
forgeURL: srv.URL,
forgeToken: "test-token",
client: srv.Client(),
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
_, err := s.listRepoPRs(context.Background(), "core", "go-io", "open")
assert.Error(t, err)
}
func TestPr_ListRepoPRs_Ugly(t *testing.T) {
// Repo with no PRs
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode([]map[string]any{})
}))
t.Cleanup(srv.Close)
s := &PrepSubsystem{
forge: forge.NewForge(srv.URL, "test-token"),
forgeURL: srv.URL,
forgeToken: "test-token",
client: srv.Client(),
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
prs, err := s.listRepoPRs(context.Background(), "core", "empty-repo", "open")
require.NoError(t, err)
assert.Empty(t, prs)
}

View file

@ -374,3 +374,155 @@ func TestDispatch_RunQA_Good_PHPNoComposer(t *testing.T) {
result := s.runQA(dir)
assert.False(t, result)
}
// --- pullWikiContent Bad/Ugly ---
func TestPrep_PullWikiContent_Bad(t *testing.T) {
// Forge returns error on wiki pages
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(500)
}))
t.Cleanup(srv.Close)
s := &PrepSubsystem{
forge: forge.NewForge(srv.URL, "test-token"),
client: srv.Client(),
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
content := s.pullWikiContent(context.Background(), "core", "go-io")
assert.Empty(t, content)
}
func TestPrep_PullWikiContent_Ugly(t *testing.T) {
// Forge returns pages with empty content
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch {
case r.URL.Path == "/api/v1/repos/core/go-io/wiki/pages":
json.NewEncoder(w).Encode([]map[string]any{
{"title": "EmptyPage", "sub_url": "EmptyPage"},
})
case r.URL.Path == "/api/v1/repos/core/go-io/wiki/page/EmptyPage":
json.NewEncoder(w).Encode(map[string]any{
"title": "EmptyPage",
"content_base64": "",
})
default:
w.WriteHeader(404)
}
}))
t.Cleanup(srv.Close)
s := &PrepSubsystem{
forge: forge.NewForge(srv.URL, "test-token"),
client: srv.Client(),
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
content := s.pullWikiContent(context.Background(), "core", "go-io")
// Empty content_base64 means the page is skipped
assert.Empty(t, content)
}
// --- renderPlan Ugly ---
func TestPrep_RenderPlan_Ugly(t *testing.T) {
// Template with variables that don't exist in template — variables just won't match
s := &PrepSubsystem{
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
// Passing variables that won't match any {{placeholder}} in the template
result := s.renderPlan("coding", map[string]string{
"nonexistent_var": "value1",
"another_missing": "value2",
}, "Test task")
// Should return the template rendered without substitution (if template exists)
// or empty if template doesn't exist. Either way, no panic.
_ = result
}
// --- brainRecall Ugly ---
func TestPrep_BrainRecall_Ugly(t *testing.T) {
// Server returns unexpected JSON structure
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
// Return JSON that doesn't have "memories" key
json.NewEncoder(w).Encode(map[string]any{
"unexpected_key": "unexpected_value",
"data": []string{"not", "the", "right", "shape"},
})
}))
t.Cleanup(srv.Close)
s := &PrepSubsystem{
brainURL: srv.URL,
brainKey: "test-key",
client: srv.Client(),
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
recall, count := s.brainRecall(context.Background(), "go-io")
assert.Empty(t, recall, "unexpected JSON structure should yield no memories")
assert.Equal(t, 0, count)
}
// --- findConsumersList Ugly ---
func TestPrep_FindConsumersList_Ugly(t *testing.T) {
// go.work with modules that don't have go.mod
dir := t.TempDir()
goWork := "go 1.22\n\nuse (\n\t./core/go\n\t./core/missing\n)"
os.WriteFile(filepath.Join(dir, "go.work"), []byte(goWork), 0o644)
// Create only the first module dir with go.mod
modDir := filepath.Join(dir, "core", "go")
os.MkdirAll(modDir, 0o755)
os.WriteFile(filepath.Join(modDir, "go.mod"), []byte("module forge.lthn.ai/core/go\n"), 0o644)
// core/missing has no go.mod
os.MkdirAll(filepath.Join(dir, "core", "missing"), 0o755)
s := &PrepSubsystem{
codePath: dir,
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
// Should not panic, just skip missing go.mod entries
list, count := s.findConsumersList("go")
assert.Equal(t, 0, count)
assert.Empty(t, list)
}
// --- getIssueBody Ugly ---
func TestPrep_GetIssueBody_Ugly(t *testing.T) {
// Issue body with HTML/special chars
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(map[string]any{
"number": 99,
"title": "Issue with <script>alert('xss')</script>",
"body": "Body has &amp; HTML &lt;tags&gt; and \"quotes\" and 'apostrophes' <b>bold</b>",
})
}))
t.Cleanup(srv.Close)
s := &PrepSubsystem{
forge: forge.NewForge(srv.URL, "test-token"),
client: srv.Client(),
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
body := s.getIssueBody(context.Background(), "core", "go-io", 99)
assert.NotEmpty(t, body)
assert.Contains(t, body, "HTML")
assert.Contains(t, body, "<script>")
}

View file

@ -3,9 +3,11 @@
package agentic
import (
"context"
"path/filepath"
"strings"
"testing"
"time"
core "dappco.re/go/core"
"github.com/stretchr/testify/assert"
@ -327,3 +329,201 @@ func TestSanitise_TrimRuneEdges_Ugly_Unicode(t *testing.T) {
func TestSanitise_TrimRuneEdges_Ugly_NoMatch(t *testing.T) {
assert.Equal(t, "hello", trimRuneEdges("hello", '-'))
}
// --- PrepSubsystem Name Bad/Ugly ---
func TestPrep_Name_Bad(t *testing.T) {
s := &PrepSubsystem{}
name := s.Name()
assert.NotEmpty(t, name, "Name should never return empty")
assert.Equal(t, "agentic", name)
}
func TestPrep_Name_Ugly(t *testing.T) {
// Zero-value struct — Name() should still work
var s PrepSubsystem
assert.NotPanics(t, func() {
name := s.Name()
assert.Equal(t, "agentic", name)
})
}
// --- NewPrep Bad/Ugly ---
func TestPrep_NewPrep_Bad(t *testing.T) {
// Call without any env — verify doesn't panic, returns valid struct
t.Setenv("FORGE_TOKEN", "")
t.Setenv("GITEA_TOKEN", "")
t.Setenv("CORE_BRAIN_KEY", "")
t.Setenv("FORGE_URL", "")
t.Setenv("CORE_BRAIN_URL", "")
t.Setenv("SPECS_PATH", "")
t.Setenv("CODE_PATH", "")
assert.NotPanics(t, func() {
s := NewPrep()
assert.NotNil(t, s)
})
}
func TestPrep_NewPrep_Ugly(t *testing.T) {
// Verify returned struct has non-nil backoff/failCount maps
t.Setenv("FORGE_TOKEN", "")
t.Setenv("GITEA_TOKEN", "")
s := NewPrep()
assert.NotNil(t, s.backoff, "backoff map must not be nil")
assert.NotNil(t, s.failCount, "failCount map must not be nil")
assert.NotNil(t, s.client, "HTTP client must not be nil")
assert.NotNil(t, s.forge, "Forge client must not be nil")
}
// --- SetCore Bad/Ugly ---
func TestPrep_SetCore_Bad(t *testing.T) {
// SetCore with nil — should not panic
s := &PrepSubsystem{}
assert.NotPanics(t, func() {
s.SetCore(nil)
})
assert.Nil(t, s.core)
}
func TestPrep_SetCore_Ugly(t *testing.T) {
// SetCore twice — second overwrites first
s := &PrepSubsystem{}
c1 := core.New(core.WithOption("name", "first"))
c2 := core.New(core.WithOption("name", "second"))
s.SetCore(c1)
assert.Equal(t, c1, s.core)
s.SetCore(c2)
assert.Equal(t, c2, s.core, "second SetCore should overwrite first")
}
// --- OnStartup Bad/Ugly ---
func TestPrep_OnStartup_Bad(t *testing.T) {
// OnStartup without SetCore (nil core) — panics because registerCommands
// needs core.Command(). Verify the panic is from nil core, not a logic error.
s := &PrepSubsystem{
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
assert.Panics(t, func() {
_ = s.OnStartup(context.Background())
}, "OnStartup without core should panic on registerCommands")
}
func TestPrep_OnStartup_Ugly(t *testing.T) {
// OnStartup called twice with valid core — second call should not panic
s := &PrepSubsystem{
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
c := core.New(core.WithOption("name", "test"))
s.SetCore(c)
assert.NotPanics(t, func() {
_ = s.OnStartup(context.Background())
_ = s.OnStartup(context.Background())
})
}
// --- OnShutdown Bad ---
func TestPrep_OnShutdown_Bad(t *testing.T) {
// OnShutdown without Core
s := &PrepSubsystem{
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
assert.NotPanics(t, func() {
err := s.OnShutdown(context.Background())
assert.NoError(t, err)
})
assert.True(t, s.frozen)
}
// --- Shutdown Bad/Ugly ---
func TestPrep_Shutdown_Bad(t *testing.T) {
// Shutdown always returns nil
s := &PrepSubsystem{
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
err := s.Shutdown(context.Background())
assert.NoError(t, err)
assert.Nil(t, err)
}
func TestPrep_Shutdown_Ugly(t *testing.T) {
// Shutdown on zero-value struct
var s PrepSubsystem
assert.NotPanics(t, func() {
err := s.Shutdown(context.Background())
assert.NoError(t, err)
})
}
// --- EnvOr Bad/Ugly ---
func TestPrep_EnvOr_Bad(t *testing.T) {
// Both env empty and fallback empty
t.Setenv("TEST_ENVVAR_EMPTY_ALL", "")
assert.Equal(t, "", envOr("TEST_ENVVAR_EMPTY_ALL", ""))
}
func TestPrep_EnvOr_Ugly(t *testing.T) {
// Env set to whitespace — whitespace is non-empty, so returned as-is
t.Setenv("TEST_ENVVAR_WHITESPACE", " ")
assert.Equal(t, " ", envOr("TEST_ENVVAR_WHITESPACE", "fallback"))
}
// --- DetectLanguage Bad/Ugly ---
func TestPrep_DetectLanguage_Bad(t *testing.T) {
// Empty dir — defaults to go
dir := t.TempDir()
assert.Equal(t, "go", detectLanguage(dir))
}
func TestPrep_DetectLanguage_Ugly(t *testing.T) {
// Dir with multiple project files (go.mod + package.json) — go wins (first match)
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "go.mod"), "module test").OK)
require.True(t, fs.Write(filepath.Join(dir, "package.json"), "{}").OK)
assert.Equal(t, "go", detectLanguage(dir), "go.mod checked first, so go wins")
}
// --- DetectBuildCmd Bad/Ugly ---
func TestPrep_DetectBuildCmd_Bad(t *testing.T) {
// Unknown/non-existent path — defaults to go build
assert.Equal(t, "go build ./...", detectBuildCmd("/nonexistent/path/that/does/not/exist"))
}
func TestPrep_DetectBuildCmd_Ugly(t *testing.T) {
// Path that doesn't exist at all — defaults to go build
assert.NotPanics(t, func() {
result := detectBuildCmd("")
assert.Equal(t, "go build ./...", result)
})
}
// --- DetectTestCmd Bad/Ugly ---
func TestPrep_DetectTestCmd_Bad(t *testing.T) {
// Unknown path — defaults to go test
assert.Equal(t, "go test ./...", detectTestCmd("/nonexistent/path/that/does/not/exist"))
}
func TestPrep_DetectTestCmd_Ugly(t *testing.T) {
// Path that doesn't exist — defaults to go test
assert.NotPanics(t, func() {
result := detectTestCmd("")
assert.Equal(t, "go test ./...", result)
})
}

View file

@ -7,6 +7,7 @@ import (
"encoding/json"
"os"
"path/filepath"
"strings"
"testing"
"time"
@ -243,3 +244,145 @@ func TestReviewQueue_LoadRateLimitState_Ugly(t *testing.T) {
result := s.loadRateLimitState()
assert.Nil(t, result, "corrupt JSON should return nil")
}
// --- buildReviewCommand Bad/Ugly ---
func TestReviewQueue_BuildReviewCommand_Bad(t *testing.T) {
// Empty reviewer string — defaults to coderabbit
s := &PrepSubsystem{
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
cmd := s.buildReviewCommand(context.Background(), "/tmp/repo", "")
assert.Contains(t, cmd.Args, "--plain")
assert.Contains(t, cmd.Args, "review")
}
func TestReviewQueue_BuildReviewCommand_Ugly(t *testing.T) {
// Unknown reviewer type — defaults to coderabbit
s := &PrepSubsystem{
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
cmd := s.buildReviewCommand(context.Background(), "/tmp/repo", "unknown-reviewer")
assert.Contains(t, cmd.Args, "--plain", "unknown reviewer should fall through to coderabbit default")
}
// --- countFindings Bad/Ugly ---
func TestReviewQueue_CountFindings_Bad(t *testing.T) {
// Empty string
count := countFindings("")
// Empty string doesn't contain "No findings" so defaults to 1
assert.Equal(t, 1, count)
}
func TestReviewQueue_CountFindings_Ugly(t *testing.T) {
// Only whitespace
count := countFindings(" \n \n ")
// No markers, no "No findings", so defaults to 1
assert.Equal(t, 1, count)
}
// --- parseRetryAfter Ugly ---
func TestReviewQueue_ParseRetryAfter_Ugly(t *testing.T) {
// Seconds only "try after 30 seconds" — no minutes match
d := parseRetryAfter("try after 30 seconds")
// Regex expects minutes first, so this won't match — defaults to 5 min
assert.Equal(t, 5*time.Minute, d)
}
// --- storeReviewOutput Bad/Ugly ---
func TestReviewQueue_StoreReviewOutput_Bad(t *testing.T) {
// Empty output
s := &PrepSubsystem{
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
assert.NotPanics(t, func() {
s.storeReviewOutput(t.TempDir(), "test-repo", "coderabbit", "")
})
}
func TestReviewQueue_StoreReviewOutput_Ugly(t *testing.T) {
// Very large output
s := &PrepSubsystem{
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
largeOutput := strings.Repeat("Finding: something is wrong on this line\n", 10000)
assert.NotPanics(t, func() {
s.storeReviewOutput(t.TempDir(), "test-repo", "coderabbit", largeOutput)
})
}
// --- saveRateLimitState Good/Bad/Ugly ---
func TestReviewQueue_SaveRateLimitState_Good(t *testing.T) {
s := &PrepSubsystem{
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
info := &RateLimitInfo{
Limited: true,
RetryAt: time.Now().Add(5 * time.Minute).Truncate(time.Second),
Message: "rate limited",
}
assert.NotPanics(t, func() {
s.saveRateLimitState(info)
})
}
func TestReviewQueue_SaveRateLimitState_Bad(t *testing.T) {
// Save nil info
s := &PrepSubsystem{
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
assert.NotPanics(t, func() {
s.saveRateLimitState(nil)
})
}
func TestReviewQueue_SaveRateLimitState_Ugly(t *testing.T) {
// Save with far-future RetryAt
s := &PrepSubsystem{
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
info := &RateLimitInfo{
Limited: true,
RetryAt: time.Date(2099, 12, 31, 23, 59, 59, 0, time.UTC),
Message: "far future rate limit",
}
assert.NotPanics(t, func() {
s.saveRateLimitState(info)
})
}
// --- loadRateLimitState Good ---
func TestReviewQueue_LoadRateLimitState_Good(t *testing.T) {
// Write then load valid state
s := &PrepSubsystem{
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
info := &RateLimitInfo{
Limited: true,
RetryAt: time.Now().Add(5 * time.Minute).Truncate(time.Second),
Message: "test rate limit",
}
s.saveRateLimitState(info)
loaded := s.loadRateLimitState()
if loaded != nil {
assert.True(t, loaded.Limited)
assert.Equal(t, "test rate limit", loaded.Message)
}
// If loaded is nil, DIR_HOME path wasn't writable — acceptable in test
}

View file

@ -7,6 +7,7 @@ import (
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
@ -252,6 +253,148 @@ func TestScan_ListRepoIssues_Bad_ServerError(t *testing.T) {
assert.Error(t, err)
}
// --- scan Bad/Ugly ---
func TestScan_Scan_Bad(t *testing.T) {
// Forge returns error for org repos
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(500)
}))
t.Cleanup(srv.Close)
s := &PrepSubsystem{
forge: forge.NewForge(srv.URL, "test-token"),
forgeURL: srv.URL,
forgeToken: "test-token",
client: srv.Client(),
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
_, _, err := s.scan(context.Background(), nil, ScanInput{})
assert.Error(t, err)
}
func TestScan_Scan_Ugly(t *testing.T) {
// Org with no repos
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if strings.Contains(r.URL.Path, "/orgs/") {
json.NewEncoder(w).Encode([]map[string]any{})
return
}
w.WriteHeader(404)
}))
t.Cleanup(srv.Close)
s := &PrepSubsystem{
forge: forge.NewForge(srv.URL, "test-token"),
forgeURL: srv.URL,
forgeToken: "test-token",
client: srv.Client(),
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
_, out, err := s.scan(context.Background(), nil, ScanInput{})
require.NoError(t, err)
assert.True(t, out.Success)
assert.Equal(t, 0, out.Count)
}
// --- listOrgRepos Good/Bad/Ugly ---
func TestScan_ListOrgRepos_Good(t *testing.T) {
srv := mockScanServer(t)
s := &PrepSubsystem{
forge: forge.NewForge(srv.URL, "test-token"),
forgeURL: srv.URL,
forgeToken: "test-token",
client: srv.Client(),
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
repos, err := s.listOrgRepos(context.Background(), "core")
require.NoError(t, err)
assert.Len(t, repos, 3)
assert.Contains(t, repos, "go-io")
assert.Contains(t, repos, "go-log")
assert.Contains(t, repos, "agent")
}
func TestScan_ListOrgRepos_Bad(t *testing.T) {
// Forge returns error
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(500)
}))
t.Cleanup(srv.Close)
s := &PrepSubsystem{
forge: forge.NewForge(srv.URL, "test-token"),
forgeURL: srv.URL,
forgeToken: "test-token",
client: srv.Client(),
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
_, err := s.listOrgRepos(context.Background(), "core")
assert.Error(t, err)
}
func TestScan_ListOrgRepos_Ugly(t *testing.T) {
// Empty org name
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode([]map[string]any{})
}))
t.Cleanup(srv.Close)
s := &PrepSubsystem{
forge: forge.NewForge(srv.URL, "test-token"),
forgeURL: srv.URL,
forgeToken: "test-token",
client: srv.Client(),
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
repos, err := s.listOrgRepos(context.Background(), "")
require.NoError(t, err)
assert.Empty(t, repos)
}
// --- listRepoIssues Ugly ---
func TestScan_ListRepoIssues_Ugly(t *testing.T) {
// Issues with very long titles
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
longTitle := strings.Repeat("Very Long Issue Title ", 50)
json.NewEncoder(w).Encode([]map[string]any{
{
"number": 1,
"title": longTitle,
"labels": []map[string]any{{"name": "agentic"}},
"assignee": nil,
"html_url": "https://forge.lthn.ai/core/go-io/issues/1",
},
})
}))
t.Cleanup(srv.Close)
s := &PrepSubsystem{
forgeURL: srv.URL,
forgeToken: "test-token",
client: srv.Client(),
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
issues, err := s.listRepoIssues(context.Background(), "core", "go-io", "agentic")
require.NoError(t, err)
assert.Len(t, issues, 1)
assert.True(t, len(issues[0].Title) > 100)
}
func TestScan_ListRepoIssues_Good_URLRewrite(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode([]map[string]any{

View file

@ -83,3 +83,74 @@ func TestWatch_FindActiveWorkspaces_Good_Empty(t *testing.T) {
active := s.findActiveWorkspaces()
assert.Empty(t, active)
}
// --- findActiveWorkspaces Bad/Ugly ---
func TestWatch_FindActiveWorkspaces_Bad(t *testing.T) {
// Workspace dir doesn't exist
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", filepath.Join(root, "nonexistent"))
s := &PrepSubsystem{
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
assert.NotPanics(t, func() {
active := s.findActiveWorkspaces()
assert.Empty(t, active)
})
}
func TestWatch_FindActiveWorkspaces_Ugly(t *testing.T) {
// Workspaces with corrupt status.json
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")
// Create workspace with corrupt status.json
ws1 := filepath.Join(wsRoot, "ws-corrupt")
os.MkdirAll(ws1, 0o755)
os.WriteFile(filepath.Join(ws1, "status.json"), []byte("not-valid-json{{{"), 0o644)
// Create valid running workspace
ws2 := filepath.Join(wsRoot, "ws-valid")
os.MkdirAll(ws2, 0o755)
st, _ := json.Marshal(WorkspaceStatus{Status: "running", Repo: "go-io", Agent: "codex"})
os.WriteFile(filepath.Join(ws2, "status.json"), st, 0o644)
s := &PrepSubsystem{
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
active := s.findActiveWorkspaces()
// Corrupt workspace should be skipped, valid one should be found
assert.Contains(t, active, "ws-valid")
assert.NotContains(t, active, "ws-corrupt")
}
// --- resolveWorkspaceDir Bad/Ugly ---
func TestWatch_ResolveWorkspaceDir_Bad(t *testing.T) {
// Empty name
s := &PrepSubsystem{
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
dir := s.resolveWorkspaceDir("")
assert.NotEmpty(t, dir, "empty name should still resolve to workspace root")
assert.True(t, filepath.IsAbs(dir))
}
func TestWatch_ResolveWorkspaceDir_Ugly(t *testing.T) {
// Name with path traversal "../.."
s := &PrepSubsystem{
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
}
assert.NotPanics(t, func() {
dir := s.resolveWorkspaceDir("../..")
// JoinPath handles traversal; result should be absolute
assert.True(t, filepath.IsAbs(dir))
})
}