refactor(test): bulk rename 478 tests to TestFile_Function_{Good,Bad,Ugly}

Mechanical rename of all test functions to follow the convention:
  TestFilename_FunctionName_{Good,Bad,Ugly}

Examples:
  TestForgeMergePR_Good_Success → TestVerify_ForgeMergePR_Good_Success
  TestAgentCommand_Good_Gemini → TestDispatch_AgentCommand_Good_Gemini
  TestReadStatus_Bad_NoFile → TestStatus_ReadStatus_Bad_NoFile

Gap analysis now works: 137 functions still need 260 missing categories.
566 tests, agentic 74.3% — naming is now the tooling.

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Snider 2026-03-25 08:32:08 +00:00
parent 8b46e15d24
commit 97d06c1e90
31 changed files with 478 additions and 478 deletions

View file

@ -11,7 +11,7 @@ import (
// --- parseForgeArgs ---
func TestParseForgeArgs_Good_AllFields(t *testing.T) {
func TestCommandsForge_ParseForgeArgs_Good_AllFields(t *testing.T) {
opts := core.NewOptions(
core.Option{Key: "org", Value: "myorg"},
core.Option{Key: "_arg", Value: "myrepo"},
@ -23,7 +23,7 @@ func TestParseForgeArgs_Good_AllFields(t *testing.T) {
assert.Equal(t, int64(42), num)
}
func TestParseForgeArgs_Good_DefaultOrg(t *testing.T) {
func TestCommandsForge_ParseForgeArgs_Good_DefaultOrg(t *testing.T) {
opts := core.NewOptions(
core.Option{Key: "_arg", Value: "go-io"},
)
@ -33,7 +33,7 @@ func TestParseForgeArgs_Good_DefaultOrg(t *testing.T) {
assert.Equal(t, int64(0), num, "no number provided")
}
func TestParseForgeArgs_Bad_EmptyOpts(t *testing.T) {
func TestCommandsForge_ParseForgeArgs_Bad_EmptyOpts(t *testing.T) {
opts := core.NewOptions()
org, repo, num := parseForgeArgs(opts)
assert.Equal(t, "core", org, "should default to 'core'")
@ -41,7 +41,7 @@ func TestParseForgeArgs_Bad_EmptyOpts(t *testing.T) {
assert.Equal(t, int64(0), num)
}
func TestParseForgeArgs_Bad_InvalidNumber(t *testing.T) {
func TestCommandsForge_ParseForgeArgs_Bad_InvalidNumber(t *testing.T) {
opts := core.NewOptions(
core.Option{Key: "_arg", Value: "repo"},
core.Option{Key: "number", Value: "not-a-number"},
@ -52,7 +52,7 @@ func TestParseForgeArgs_Bad_InvalidNumber(t *testing.T) {
// --- fmtIndex ---
func TestFmtIndex_Good(t *testing.T) {
func TestCommandsForge_FmtIndex_Good(t *testing.T) {
assert.Equal(t, "1", fmtIndex(1))
assert.Equal(t, "42", fmtIndex(42))
assert.Equal(t, "0", fmtIndex(0))

View file

@ -52,13 +52,13 @@ func testPrepWithCore(t *testing.T, srv *httptest.Server) (*PrepSubsystem, *core
// --- Forge command methods (extracted from closures) ---
func TestCmdIssueGet_Bad_MissingArgs(t *testing.T) {
func TestCommandsForge_CmdIssueGet_Bad_MissingArgs(t *testing.T) {
s, _ := testPrepWithCore(t, nil)
r := s.cmdIssueGet(core.NewOptions())
assert.False(t, r.OK)
}
func TestCmdIssueGet_Good_Success(t *testing.T) {
func TestCommandsForge_CmdIssueGet_Good_Success(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(map[string]any{
"number": 42, "title": "Fix tests", "state": "open",
@ -75,7 +75,7 @@ func TestCmdIssueGet_Good_Success(t *testing.T) {
assert.True(t, r.OK)
}
func TestCmdIssueGet_Bad_APIError(t *testing.T) {
func TestCommandsForge_CmdIssueGet_Bad_APIError(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(500)
}))
@ -89,13 +89,13 @@ func TestCmdIssueGet_Bad_APIError(t *testing.T) {
assert.False(t, r.OK)
}
func TestCmdIssueList_Bad_MissingRepo(t *testing.T) {
func TestCommandsForge_CmdIssueList_Bad_MissingRepo(t *testing.T) {
s, _ := testPrepWithCore(t, nil)
r := s.cmdIssueList(core.NewOptions())
assert.False(t, r.OK)
}
func TestCmdIssueList_Good_Success(t *testing.T) {
func TestCommandsForge_CmdIssueList_Good_Success(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode([]map[string]any{
{"number": 1, "title": "Bug", "state": "open"},
@ -109,7 +109,7 @@ func TestCmdIssueList_Good_Success(t *testing.T) {
assert.True(t, r.OK)
}
func TestCmdIssueList_Good_Empty(t *testing.T) {
func TestCommandsForge_CmdIssueList_Good_Empty(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode([]map[string]any{})
}))
@ -120,13 +120,13 @@ func TestCmdIssueList_Good_Empty(t *testing.T) {
assert.True(t, r.OK)
}
func TestCmdIssueComment_Bad_MissingArgs(t *testing.T) {
func TestCommandsForge_CmdIssueComment_Bad_MissingArgs(t *testing.T) {
s, _ := testPrepWithCore(t, nil)
r := s.cmdIssueComment(core.NewOptions())
assert.False(t, r.OK)
}
func TestCmdIssueComment_Good_Success(t *testing.T) {
func TestCommandsForge_CmdIssueComment_Good_Success(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(map[string]any{"id": 99})
}))
@ -141,13 +141,13 @@ func TestCmdIssueComment_Good_Success(t *testing.T) {
assert.True(t, r.OK)
}
func TestCmdIssueCreate_Bad_MissingTitle(t *testing.T) {
func TestCommandsForge_CmdIssueCreate_Bad_MissingTitle(t *testing.T) {
s, _ := testPrepWithCore(t, nil)
r := s.cmdIssueCreate(core.NewOptions(core.Option{Key: "_arg", Value: "go-io"}))
assert.False(t, r.OK)
}
func TestCmdIssueCreate_Good_Success(t *testing.T) {
func TestCommandsForge_CmdIssueCreate_Good_Success(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(map[string]any{
"number": 10, "title": "New bug", "html_url": "https://forge.test/issues/10",
@ -165,7 +165,7 @@ func TestCmdIssueCreate_Good_Success(t *testing.T) {
assert.True(t, r.OK)
}
func TestCmdIssueCreate_Good_WithLabelsAndMilestone(t *testing.T) {
func TestCommandsForge_CmdIssueCreate_Good_WithLabelsAndMilestone(t *testing.T) {
callPaths := []string{}
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
callPaths = append(callPaths, r.URL.Path)
@ -199,7 +199,7 @@ func TestCmdIssueCreate_Good_WithLabelsAndMilestone(t *testing.T) {
assert.True(t, r.OK)
}
func TestCmdIssueCreate_Bad_APIError(t *testing.T) {
func TestCommandsForge_CmdIssueCreate_Bad_APIError(t *testing.T) {
callCount := 0
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
callCount++
@ -219,13 +219,13 @@ func TestCmdIssueCreate_Bad_APIError(t *testing.T) {
assert.False(t, r.OK)
}
func TestCmdPRGet_Bad_MissingArgs(t *testing.T) {
func TestCommandsForge_CmdPRGet_Bad_MissingArgs(t *testing.T) {
s, _ := testPrepWithCore(t, nil)
r := s.cmdPRGet(core.NewOptions())
assert.False(t, r.OK)
}
func TestCmdPRGet_Good_Success(t *testing.T) {
func TestCommandsForge_CmdPRGet_Good_Success(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(map[string]any{
"number": 3, "title": "Fix", "state": "open", "mergeable": true,
@ -243,7 +243,7 @@ func TestCmdPRGet_Good_Success(t *testing.T) {
assert.True(t, r.OK)
}
func TestCmdPRGet_Bad_APIError(t *testing.T) {
func TestCommandsForge_CmdPRGet_Bad_APIError(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(404)
}))
@ -257,7 +257,7 @@ func TestCmdPRGet_Bad_APIError(t *testing.T) {
assert.False(t, r.OK)
}
func TestCmdPRList_Good_WithPRs(t *testing.T) {
func TestCommandsForge_CmdPRList_Good_WithPRs(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode([]map[string]any{
{"number": 1, "title": "Fix", "state": "open",
@ -273,7 +273,7 @@ func TestCmdPRList_Good_WithPRs(t *testing.T) {
assert.True(t, r.OK)
}
func TestCmdPRList_Bad_APIError(t *testing.T) {
func TestCommandsForge_CmdPRList_Bad_APIError(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(500)
}))
@ -284,7 +284,7 @@ func TestCmdPRList_Bad_APIError(t *testing.T) {
assert.False(t, r.OK)
}
func TestCmdPRMerge_Bad_APIError(t *testing.T) {
func TestCommandsForge_CmdPRMerge_Bad_APIError(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(409)
json.NewEncoder(w).Encode(map[string]any{"message": "conflict"})
@ -299,7 +299,7 @@ func TestCmdPRMerge_Bad_APIError(t *testing.T) {
assert.False(t, r.OK)
}
func TestCmdPRMerge_Good_CustomMethod(t *testing.T) {
func TestCommandsForge_CmdPRMerge_Good_CustomMethod(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
}))
@ -314,7 +314,7 @@ func TestCmdPRMerge_Good_CustomMethod(t *testing.T) {
assert.True(t, r.OK)
}
func TestCmdIssueGet_Good_WithBody(t *testing.T) {
func TestCommandsForge_CmdIssueGet_Good_WithBody(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(map[string]any{
"number": 1, "title": "Bug", "state": "open",
@ -331,7 +331,7 @@ func TestCmdIssueGet_Good_WithBody(t *testing.T) {
assert.True(t, r.OK)
}
func TestCmdIssueList_Bad_APIError(t *testing.T) {
func TestCommandsForge_CmdIssueList_Bad_APIError(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(500)
}))
@ -342,7 +342,7 @@ func TestCmdIssueList_Bad_APIError(t *testing.T) {
assert.False(t, r.OK)
}
func TestCmdIssueComment_Bad_APIError(t *testing.T) {
func TestCommandsForge_CmdIssueComment_Bad_APIError(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(500)
}))
@ -357,7 +357,7 @@ func TestCmdIssueComment_Bad_APIError(t *testing.T) {
assert.False(t, r.OK)
}
func TestCmdRepoGet_Bad_APIError(t *testing.T) {
func TestCommandsForge_CmdRepoGet_Bad_APIError(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(500)
}))
@ -368,7 +368,7 @@ func TestCmdRepoGet_Bad_APIError(t *testing.T) {
assert.False(t, r.OK)
}
func TestCmdRepoList_Bad_APIError(t *testing.T) {
func TestCommandsForge_CmdRepoList_Bad_APIError(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(500)
}))
@ -379,13 +379,13 @@ func TestCmdRepoList_Bad_APIError(t *testing.T) {
assert.False(t, r.OK)
}
func TestCmdPRList_Bad_MissingRepo(t *testing.T) {
func TestCommandsForge_CmdPRList_Bad_MissingRepo(t *testing.T) {
s, _ := testPrepWithCore(t, nil)
r := s.cmdPRList(core.NewOptions())
assert.False(t, r.OK)
}
func TestCmdPRList_Good_Empty(t *testing.T) {
func TestCommandsForge_CmdPRList_Good_Empty(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode([]map[string]any{})
}))
@ -396,13 +396,13 @@ func TestCmdPRList_Good_Empty(t *testing.T) {
assert.True(t, r.OK)
}
func TestCmdPRMerge_Bad_MissingArgs(t *testing.T) {
func TestCommandsForge_CmdPRMerge_Bad_MissingArgs(t *testing.T) {
s, _ := testPrepWithCore(t, nil)
r := s.cmdPRMerge(core.NewOptions())
assert.False(t, r.OK)
}
func TestCmdPRMerge_Good_DefaultMethod(t *testing.T) {
func TestCommandsForge_CmdPRMerge_Good_DefaultMethod(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
}))
@ -416,13 +416,13 @@ func TestCmdPRMerge_Good_DefaultMethod(t *testing.T) {
assert.True(t, r.OK)
}
func TestCmdRepoGet_Bad_MissingRepo(t *testing.T) {
func TestCommandsForge_CmdRepoGet_Bad_MissingRepo(t *testing.T) {
s, _ := testPrepWithCore(t, nil)
r := s.cmdRepoGet(core.NewOptions())
assert.False(t, r.OK)
}
func TestCmdRepoGet_Good_Success(t *testing.T) {
func TestCommandsForge_CmdRepoGet_Good_Success(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(map[string]any{
"name": "go-io", "description": "IO", "default_branch": "dev",
@ -437,7 +437,7 @@ func TestCmdRepoGet_Good_Success(t *testing.T) {
assert.True(t, r.OK)
}
func TestCmdRepoList_Good_Success(t *testing.T) {
func TestCommandsForge_CmdRepoList_Good_Success(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode([]map[string]any{
{"name": "go-io", "description": "IO", "archived": false, "owner": map[string]any{"login": "core"}},
@ -453,13 +453,13 @@ func TestCmdRepoList_Good_Success(t *testing.T) {
// --- Workspace command methods ---
func TestCmdWorkspaceList_Good_Empty(t *testing.T) {
func TestCommandsWorkspace_CmdWorkspaceList_Good_Empty(t *testing.T) {
s, _ := testPrepWithCore(t, nil)
r := s.cmdWorkspaceList(core.NewOptions())
assert.True(t, r.OK)
}
func TestCmdWorkspaceList_Good_WithEntries(t *testing.T) {
func TestCommandsWorkspace_CmdWorkspaceList_Good_WithEntries(t *testing.T) {
s, _ := testPrepWithCore(t, nil)
wsRoot := WorkspaceRoot()
@ -472,13 +472,13 @@ func TestCmdWorkspaceList_Good_WithEntries(t *testing.T) {
assert.True(t, r.OK)
}
func TestCmdWorkspaceClean_Good_Empty(t *testing.T) {
func TestCommandsWorkspace_CmdWorkspaceClean_Good_Empty(t *testing.T) {
s, _ := testPrepWithCore(t, nil)
r := s.cmdWorkspaceClean(core.NewOptions())
assert.True(t, r.OK)
}
func TestCmdWorkspaceClean_Good_RemovesCompleted(t *testing.T) {
func TestCommandsWorkspace_CmdWorkspaceClean_Good_RemovesCompleted(t *testing.T) {
s, _ := testPrepWithCore(t, nil)
wsRoot := WorkspaceRoot()
@ -494,7 +494,7 @@ func TestCmdWorkspaceClean_Good_RemovesCompleted(t *testing.T) {
assert.True(t, os.IsNotExist(err))
}
func TestCmdWorkspaceClean_Good_FilterFailed(t *testing.T) {
func TestCommandsWorkspace_CmdWorkspaceClean_Good_FilterFailed(t *testing.T) {
s, _ := testPrepWithCore(t, nil)
wsRoot := WorkspaceRoot()
@ -517,7 +517,7 @@ func TestCmdWorkspaceClean_Good_FilterFailed(t *testing.T) {
assert.NoError(t, err2)
}
func TestCmdWorkspaceClean_Good_FilterBlocked(t *testing.T) {
func TestCommandsWorkspace_CmdWorkspaceClean_Good_FilterBlocked(t *testing.T) {
s, _ := testPrepWithCore(t, nil)
wsRoot := WorkspaceRoot()
@ -533,13 +533,13 @@ func TestCmdWorkspaceClean_Good_FilterBlocked(t *testing.T) {
assert.True(t, os.IsNotExist(err))
}
func TestCmdWorkspaceDispatch_Bad_MissingRepo(t *testing.T) {
func TestCommandsWorkspace_CmdWorkspaceDispatch_Bad_MissingRepo(t *testing.T) {
s, _ := testPrepWithCore(t, nil)
r := s.cmdWorkspaceDispatch(core.NewOptions())
assert.False(t, r.OK)
}
func TestCmdWorkspaceDispatch_Good_Stub(t *testing.T) {
func TestCommandsWorkspace_CmdWorkspaceDispatch_Good_Stub(t *testing.T) {
s, _ := testPrepWithCore(t, nil)
r := s.cmdWorkspaceDispatch(core.NewOptions(core.Option{Key: "_arg", Value: "go-io"}))
assert.True(t, r.OK)
@ -547,26 +547,26 @@ func TestCmdWorkspaceDispatch_Good_Stub(t *testing.T) {
// --- commands.go extracted methods ---
func TestCmdPrep_Bad_MissingRepo(t *testing.T) {
func TestCommands_CmdPrep_Bad_MissingRepo(t *testing.T) {
s, _ := testPrepWithCore(t, nil)
r := s.cmdPrep(core.NewOptions())
assert.False(t, r.OK)
}
func TestCmdPrep_Good_DefaultsToDev(t *testing.T) {
func TestCommands_CmdPrep_Good_DefaultsToDev(t *testing.T) {
s, _ := testPrepWithCore(t, nil)
// Will fail (no local clone) but exercises the default branch logic
r := s.cmdPrep(core.NewOptions(core.Option{Key: "_arg", Value: "nonexistent-repo"}))
assert.False(t, r.OK) // expected — no local repo
}
func TestCmdStatus_Good_Empty(t *testing.T) {
func TestCommands_CmdStatus_Good_Empty(t *testing.T) {
s, _ := testPrepWithCore(t, nil)
r := s.cmdStatus(core.NewOptions())
assert.True(t, r.OK)
}
func TestCmdStatus_Good_WithWorkspaces(t *testing.T) {
func TestCommands_CmdStatus_Good_WithWorkspaces(t *testing.T) {
s, _ := testPrepWithCore(t, nil)
wsRoot := WorkspaceRoot()
@ -579,19 +579,19 @@ func TestCmdStatus_Good_WithWorkspaces(t *testing.T) {
assert.True(t, r.OK)
}
func TestCmdPrompt_Bad_MissingRepo(t *testing.T) {
func TestCommands_CmdPrompt_Bad_MissingRepo(t *testing.T) {
s, _ := testPrepWithCore(t, nil)
r := s.cmdPrompt(core.NewOptions())
assert.False(t, r.OK)
}
func TestCmdPrompt_Good_DefaultTask(t *testing.T) {
func TestCommands_CmdPrompt_Good_DefaultTask(t *testing.T) {
s, _ := testPrepWithCore(t, nil)
r := s.cmdPrompt(core.NewOptions(core.Option{Key: "_arg", Value: "go-io"}))
assert.True(t, r.OK)
}
func TestCmdExtract_Good(t *testing.T) {
func TestCommands_CmdExtract_Good(t *testing.T) {
s, _ := testPrepWithCore(t, nil)
target := filepath.Join(t.TempDir(), "extract-test")
r := s.cmdExtract(core.NewOptions(
@ -601,7 +601,7 @@ func TestCmdExtract_Good(t *testing.T) {
assert.True(t, r.OK)
}
func TestCmdRunTask_Bad_MissingArgs(t *testing.T) {
func TestCommands_CmdRunTask_Bad_MissingArgs(t *testing.T) {
s, _ := testPrepWithCore(t, nil)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
@ -609,7 +609,7 @@ func TestCmdRunTask_Bad_MissingArgs(t *testing.T) {
assert.False(t, r.OK)
}
func TestCmdRunTask_Bad_MissingTask(t *testing.T) {
func TestCommands_CmdRunTask_Bad_MissingTask(t *testing.T) {
s, _ := testPrepWithCore(t, nil)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
@ -617,7 +617,7 @@ func TestCmdRunTask_Bad_MissingTask(t *testing.T) {
assert.False(t, r.OK)
}
func TestCmdOrchestrator_Good_CancelledCtx(t *testing.T) {
func TestCommands_CmdOrchestrator_Good_CancelledCtx(t *testing.T) {
s, _ := testPrepWithCore(t, nil)
ctx, cancel := context.WithCancel(context.Background())
cancel() // cancel immediately
@ -625,7 +625,7 @@ func TestCmdOrchestrator_Good_CancelledCtx(t *testing.T) {
assert.True(t, r.OK)
}
func TestParseIntStr_Good(t *testing.T) {
func TestCommands_ParseIntStr_Good(t *testing.T) {
assert.Equal(t, 42, parseIntStr("42"))
assert.Equal(t, 123, parseIntStr("issue-123"))
assert.Equal(t, 0, parseIntStr(""))
@ -635,7 +635,7 @@ func TestParseIntStr_Good(t *testing.T) {
// --- Registration verification ---
func TestRegisterCommands_Good_AllRegistered(t *testing.T) {
func TestCommands_RegisterCommands_Good_AllRegistered(t *testing.T) {
s, c := testPrepWithCore(t, nil)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

View file

@ -10,14 +10,14 @@ import (
// --- extractField ---
func TestExtractField_Good_SimpleJSON(t *testing.T) {
func TestCommandsWorkspace_ExtractField_Good_SimpleJSON(t *testing.T) {
json := `{"status":"running","repo":"go-io","agent":"codex"}`
assert.Equal(t, "running", extractField(json, "status"))
assert.Equal(t, "go-io", extractField(json, "repo"))
assert.Equal(t, "codex", extractField(json, "agent"))
}
func TestExtractField_Good_PrettyPrinted(t *testing.T) {
func TestCommandsWorkspace_ExtractField_Good_PrettyPrinted(t *testing.T) {
json := `{
"status": "completed",
"repo": "go-crypt"
@ -26,39 +26,39 @@ func TestExtractField_Good_PrettyPrinted(t *testing.T) {
assert.Equal(t, "go-crypt", extractField(json, "repo"))
}
func TestExtractField_Good_TabSeparated(t *testing.T) {
func TestCommandsWorkspace_ExtractField_Good_TabSeparated(t *testing.T) {
json := `{"status": "blocked"}`
assert.Equal(t, "blocked", extractField(json, "status"))
}
func TestExtractField_Bad_MissingField(t *testing.T) {
func TestCommandsWorkspace_ExtractField_Bad_MissingField(t *testing.T) {
json := `{"status":"running"}`
assert.Empty(t, extractField(json, "nonexistent"))
}
func TestExtractField_Bad_EmptyJSON(t *testing.T) {
func TestCommandsWorkspace_ExtractField_Bad_EmptyJSON(t *testing.T) {
assert.Empty(t, extractField("", "status"))
assert.Empty(t, extractField("{}", "status"))
}
func TestExtractField_Bad_NoValue(t *testing.T) {
func TestCommandsWorkspace_ExtractField_Bad_NoValue(t *testing.T) {
// Field key exists but no quoted value after colon
json := `{"status": 42}`
assert.Empty(t, extractField(json, "status"))
}
func TestExtractField_Bad_TruncatedJSON(t *testing.T) {
func TestCommandsWorkspace_ExtractField_Bad_TruncatedJSON(t *testing.T) {
// Field key exists but string is truncated
json := `{"status":`
assert.Empty(t, extractField(json, "status"))
}
func TestExtractField_Good_EmptyValue(t *testing.T) {
func TestCommandsWorkspace_ExtractField_Good_EmptyValue(t *testing.T) {
json := `{"status":""}`
assert.Equal(t, "", extractField(json, "status"))
}
func TestExtractField_Good_ValueWithSpaces(t *testing.T) {
func TestCommandsWorkspace_ExtractField_Good_ValueWithSpaces(t *testing.T) {
json := `{"task":"fix the failing tests"}`
assert.Equal(t, "fix the failing tests", extractField(json, "task"))
}

View file

@ -142,7 +142,7 @@ func newTestSubsystem(t *testing.T, srv *httptest.Server) *PrepSubsystem {
// --- createIssue ---
func TestCreateIssue_Good_Success(t *testing.T) {
func TestEpic_CreateIssue_Good_Success(t *testing.T) {
srv, counter := mockForgeServer(t)
s := newTestSubsystem(t, srv)
@ -154,7 +154,7 @@ func TestCreateIssue_Good_Success(t *testing.T) {
assert.Equal(t, int32(1), counter.Load())
}
func TestCreateIssue_Good_NoLabels(t *testing.T) {
func TestEpic_CreateIssue_Good_NoLabels(t *testing.T) {
srv, _ := mockForgeServer(t)
s := newTestSubsystem(t, srv)
@ -163,7 +163,7 @@ func TestCreateIssue_Good_NoLabels(t *testing.T) {
assert.Equal(t, "No labels task", child.Title)
}
func TestCreateIssue_Good_WithBody(t *testing.T) {
func TestEpic_CreateIssue_Good_WithBody(t *testing.T) {
srv, _ := mockForgeServer(t)
s := newTestSubsystem(t, srv)
@ -172,7 +172,7 @@ func TestCreateIssue_Good_WithBody(t *testing.T) {
assert.NotZero(t, child.Number)
}
func TestCreateIssue_Bad_ServerDown(t *testing.T) {
func TestEpic_CreateIssue_Bad_ServerDown(t *testing.T) {
srv := httptest.NewServer(http.NotFoundHandler())
srv.Close() // immediately close
@ -188,7 +188,7 @@ func TestCreateIssue_Bad_ServerDown(t *testing.T) {
assert.Error(t, err)
}
func TestCreateIssue_Bad_Non201Response(t *testing.T) {
func TestEpic_CreateIssue_Bad_Non201Response(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(500)
}))
@ -208,7 +208,7 @@ func TestCreateIssue_Bad_Non201Response(t *testing.T) {
// --- resolveLabelIDs ---
func TestResolveLabelIDs_Good_ExistingLabels(t *testing.T) {
func TestEpic_ResolveLabelIDs_Good_ExistingLabels(t *testing.T) {
srv, _ := mockForgeServer(t)
s := newTestSubsystem(t, srv)
@ -218,7 +218,7 @@ func TestResolveLabelIDs_Good_ExistingLabels(t *testing.T) {
assert.Contains(t, ids, int64(2))
}
func TestResolveLabelIDs_Good_NewLabel(t *testing.T) {
func TestEpic_ResolveLabelIDs_Good_NewLabel(t *testing.T) {
srv, _ := mockForgeServer(t)
s := newTestSubsystem(t, srv)
@ -227,7 +227,7 @@ func TestResolveLabelIDs_Good_NewLabel(t *testing.T) {
assert.NotEmpty(t, ids)
}
func TestResolveLabelIDs_Good_EmptyNames(t *testing.T) {
func TestEpic_ResolveLabelIDs_Good_EmptyNames(t *testing.T) {
srv, _ := mockForgeServer(t)
s := newTestSubsystem(t, srv)
@ -235,7 +235,7 @@ func TestResolveLabelIDs_Good_EmptyNames(t *testing.T) {
assert.Nil(t, ids)
}
func TestResolveLabelIDs_Bad_ServerError(t *testing.T) {
func TestEpic_ResolveLabelIDs_Bad_ServerError(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(500)
}))
@ -255,7 +255,7 @@ func TestResolveLabelIDs_Bad_ServerError(t *testing.T) {
// --- createLabel ---
func TestCreateLabel_Good_Known(t *testing.T) {
func TestEpic_CreateLabel_Good_Known(t *testing.T) {
srv, _ := mockForgeServer(t)
s := newTestSubsystem(t, srv)
@ -263,7 +263,7 @@ func TestCreateLabel_Good_Known(t *testing.T) {
assert.NotZero(t, id)
}
func TestCreateLabel_Good_Unknown(t *testing.T) {
func TestEpic_CreateLabel_Good_Unknown(t *testing.T) {
srv, _ := mockForgeServer(t)
s := newTestSubsystem(t, srv)
@ -272,7 +272,7 @@ func TestCreateLabel_Good_Unknown(t *testing.T) {
assert.NotZero(t, id)
}
func TestCreateLabel_Bad_ServerDown(t *testing.T) {
func TestEpic_CreateLabel_Bad_ServerDown(t *testing.T) {
srv := httptest.NewServer(http.NotFoundHandler())
srv.Close()
@ -290,7 +290,7 @@ func TestCreateLabel_Bad_ServerDown(t *testing.T) {
// --- createEpic (validation only, not full dispatch) ---
func TestCreateEpic_Bad_NoTitle(t *testing.T) {
func TestEpic_CreateEpic_Bad_NoTitle(t *testing.T) {
srv, _ := mockForgeServer(t)
s := newTestSubsystem(t, srv)
@ -302,7 +302,7 @@ func TestCreateEpic_Bad_NoTitle(t *testing.T) {
assert.Contains(t, err.Error(), "title is required")
}
func TestCreateEpic_Bad_NoTasks(t *testing.T) {
func TestEpic_CreateEpic_Bad_NoTasks(t *testing.T) {
srv, _ := mockForgeServer(t)
s := newTestSubsystem(t, srv)
@ -314,7 +314,7 @@ func TestCreateEpic_Bad_NoTasks(t *testing.T) {
assert.Contains(t, err.Error(), "at least one task")
}
func TestCreateEpic_Bad_NoToken(t *testing.T) {
func TestEpic_CreateEpic_Bad_NoToken(t *testing.T) {
s := &PrepSubsystem{
forgeToken: "",
backoff: make(map[string]time.Time),
@ -330,7 +330,7 @@ func TestCreateEpic_Bad_NoToken(t *testing.T) {
assert.Contains(t, err.Error(), "no Forge token")
}
func TestCreateEpic_Good_WithTasks(t *testing.T) {
func TestEpic_CreateEpic_Good_WithTasks(t *testing.T) {
srv, counter := mockForgeServer(t)
s := newTestSubsystem(t, srv)
@ -349,7 +349,7 @@ func TestCreateEpic_Good_WithTasks(t *testing.T) {
assert.Equal(t, int32(3), counter.Load())
}
func TestCreateEpic_Good_WithLabels(t *testing.T) {
func TestEpic_CreateEpic_Good_WithLabels(t *testing.T) {
srv, _ := mockForgeServer(t)
s := newTestSubsystem(t, srv)
@ -363,7 +363,7 @@ func TestCreateEpic_Good_WithLabels(t *testing.T) {
assert.True(t, out.Success)
}
func TestCreateEpic_Good_AgenticLabelAutoAdded(t *testing.T) {
func TestEpic_CreateEpic_Good_AgenticLabelAutoAdded(t *testing.T) {
srv, _ := mockForgeServer(t)
s := newTestSubsystem(t, srv)
@ -377,7 +377,7 @@ func TestCreateEpic_Good_AgenticLabelAutoAdded(t *testing.T) {
assert.True(t, out.Success)
}
func TestCreateEpic_Good_AgenticLabelNotDuplicated(t *testing.T) {
func TestEpic_CreateEpic_Good_AgenticLabelNotDuplicated(t *testing.T) {
srv, _ := mockForgeServer(t)
s := newTestSubsystem(t, srv)

View file

@ -34,13 +34,13 @@ func newCoreForHandlerTests(t *testing.T) (*core.Core, *PrepSubsystem) {
return c, s
}
func TestRegisterHandlers_Good_Registers(t *testing.T) {
func TestHandlers_RegisterHandlers_Good_Registers(t *testing.T) {
c, _ := newCoreForHandlerTests(t)
// RegisterHandlers should not panic and Core should have actions
assert.NotNil(t, c)
}
func TestRegisterHandlers_Good_PokeOnCompletion(t *testing.T) {
func TestHandlers_RegisterHandlers_Good_PokeOnCompletion(t *testing.T) {
_, s := newCoreForHandlerTests(t)
// Drain any existing poke
@ -65,7 +65,7 @@ func TestRegisterHandlers_Good_PokeOnCompletion(t *testing.T) {
}
}
func TestRegisterHandlers_Good_QAFailsUpdatesStatus(t *testing.T) {
func TestHandlers_RegisterHandlers_Good_QAFailsUpdatesStatus(t *testing.T) {
c, s := newCoreForHandlerTests(t)
root := WorkspaceRoot()
@ -101,7 +101,7 @@ func TestRegisterHandlers_Good_QAFailsUpdatesStatus(t *testing.T) {
assert.Contains(t, []string{"failed", "completed"}, updated.Status)
}
func TestRegisterHandlers_Good_IngestOnCompletion(t *testing.T) {
func TestHandlers_RegisterHandlers_Good_IngestOnCompletion(t *testing.T) {
c, _ := newCoreForHandlerTests(t)
root := WorkspaceRoot()
@ -126,7 +126,7 @@ func TestRegisterHandlers_Good_IngestOnCompletion(t *testing.T) {
})
}
func TestRegisterHandlers_Good_IgnoresNonCompleted(t *testing.T) {
func TestHandlers_RegisterHandlers_Good_IgnoresNonCompleted(t *testing.T) {
c, _ := newCoreForHandlerTests(t)
// Send AgentCompleted with non-completed status — QA should skip
@ -138,7 +138,7 @@ func TestRegisterHandlers_Good_IgnoresNonCompleted(t *testing.T) {
// Should not panic
}
func TestRegisterHandlers_Good_PokeQueue(t *testing.T) {
func TestHandlers_RegisterHandlers_Good_PokeQueue(t *testing.T) {
c, s := newCoreForHandlerTests(t)
s.frozen = true // frozen so drainQueue is a no-op
@ -149,7 +149,7 @@ func TestRegisterHandlers_Good_PokeQueue(t *testing.T) {
// --- command registration ---
func TestRegisterForgeCommands_Good(t *testing.T) {
func TestCommandsForge_RegisterForgeCommands_Good(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
@ -162,7 +162,7 @@ func TestRegisterForgeCommands_Good(t *testing.T) {
assert.NotPanics(t, func() { s.registerForgeCommands() })
}
func TestRegisterWorkspaceCommands_Good(t *testing.T) {
func TestCommandsWorkspace_RegisterWorkspaceCommands_Good(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
@ -174,7 +174,7 @@ func TestRegisterWorkspaceCommands_Good(t *testing.T) {
assert.NotPanics(t, func() { s.registerWorkspaceCommands() })
}
func TestRegisterCommands_Good(t *testing.T) {
func TestCommands_RegisterCommands_Good(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
@ -192,13 +192,13 @@ func TestRegisterCommands_Good(t *testing.T) {
// --- Prep subsystem lifecycle ---
func TestNewPrep_Good(t *testing.T) {
func TestPrep_NewPrep_Good(t *testing.T) {
s := NewPrep()
assert.NotNil(t, s)
assert.Equal(t, "agentic", s.Name())
}
func TestOnStartup_Good_Registers(t *testing.T) {
func TestPrep_OnStartup_Good_Registers(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)

View file

@ -16,7 +16,7 @@ import (
// --- ingestFindings ---
func TestIngestFindings_Good_WithFindings(t *testing.T) {
func TestIngest_IngestFindings_Good_WithFindings(t *testing.T) {
// Track the issue creation call
issueCalled := false
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@ -66,7 +66,7 @@ func TestIngestFindings_Good_WithFindings(t *testing.T) {
assert.True(t, issueCalled, "should have created an issue via API")
}
func TestIngestFindings_Bad_NotCompleted(t *testing.T) {
func TestIngest_IngestFindings_Bad_NotCompleted(t *testing.T) {
wsDir := t.TempDir()
require.NoError(t, writeStatus(wsDir, &WorkspaceStatus{
Status: "running",
@ -84,7 +84,7 @@ func TestIngestFindings_Bad_NotCompleted(t *testing.T) {
})
}
func TestIngestFindings_Bad_NoLogFile(t *testing.T) {
func TestIngest_IngestFindings_Bad_NoLogFile(t *testing.T) {
wsDir := t.TempDir()
require.NoError(t, writeStatus(wsDir, &WorkspaceStatus{
Status: "completed",
@ -102,7 +102,7 @@ func TestIngestFindings_Bad_NoLogFile(t *testing.T) {
})
}
func TestIngestFindings_Bad_TooFewFindings(t *testing.T) {
func TestIngest_IngestFindings_Bad_TooFewFindings(t *testing.T) {
wsDir := t.TempDir()
require.NoError(t, writeStatus(wsDir, &WorkspaceStatus{
Status: "completed",
@ -123,7 +123,7 @@ func TestIngestFindings_Bad_TooFewFindings(t *testing.T) {
})
}
func TestIngestFindings_Bad_QuotaExhausted(t *testing.T) {
func TestIngest_IngestFindings_Bad_QuotaExhausted(t *testing.T) {
wsDir := t.TempDir()
require.NoError(t, writeStatus(wsDir, &WorkspaceStatus{
Status: "completed",
@ -144,7 +144,7 @@ func TestIngestFindings_Bad_QuotaExhausted(t *testing.T) {
})
}
func TestIngestFindings_Bad_NoStatusFile(t *testing.T) {
func TestIngest_IngestFindings_Bad_NoStatusFile(t *testing.T) {
wsDir := t.TempDir()
s := &PrepSubsystem{
@ -157,7 +157,7 @@ func TestIngestFindings_Bad_NoStatusFile(t *testing.T) {
})
}
func TestIngestFindings_Bad_ShortLogFile(t *testing.T) {
func TestIngest_IngestFindings_Bad_ShortLogFile(t *testing.T) {
wsDir := t.TempDir()
require.NoError(t, writeStatus(wsDir, &WorkspaceStatus{
Status: "completed",
@ -179,7 +179,7 @@ func TestIngestFindings_Bad_ShortLogFile(t *testing.T) {
// --- createIssueViaAPI ---
func TestCreateIssueViaAPI_Good_Success(t *testing.T) {
func TestIngest_CreateIssueViaAPI_Good_Success(t *testing.T) {
called := false
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
called = true
@ -210,7 +210,7 @@ func TestCreateIssueViaAPI_Good_Success(t *testing.T) {
assert.True(t, called)
}
func TestCreateIssueViaAPI_Bad_NoBrainKey(t *testing.T) {
func TestIngest_CreateIssueViaAPI_Bad_NoBrainKey(t *testing.T) {
s := &PrepSubsystem{
brainKey: "",
backoff: make(map[string]time.Time),
@ -223,7 +223,7 @@ func TestCreateIssueViaAPI_Bad_NoBrainKey(t *testing.T) {
})
}
func TestCreateIssueViaAPI_Bad_NoAPIKey(t *testing.T) {
func TestIngest_CreateIssueViaAPI_Bad_NoAPIKey(t *testing.T) {
home := t.TempDir()
t.Setenv("DIR_HOME", home)
// No agent-api.key file
@ -242,7 +242,7 @@ func TestCreateIssueViaAPI_Bad_NoAPIKey(t *testing.T) {
})
}
func TestCreateIssueViaAPI_Bad_ServerError(t *testing.T) {
func TestIngest_CreateIssueViaAPI_Bad_ServerError(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(500)
}))
@ -269,14 +269,14 @@ func TestCreateIssueViaAPI_Bad_ServerError(t *testing.T) {
// --- countFileRefs (additional security-related) ---
func TestCountFileRefs_Good_SecurityFindings(t *testing.T) {
func TestIngest_CountFileRefs_Good_SecurityFindings(t *testing.T) {
body := "Security scan found:\n" +
"- `pkg/auth/token.go:55` hardcoded secret\n" +
"- `pkg/auth/middleware.go:12` missing auth check\n"
assert.Equal(t, 2, countFileRefs(body))
}
func TestCountFileRefs_Good_PHPSecurityFindings(t *testing.T) {
func TestIngest_CountFileRefs_Good_PHPSecurityFindings(t *testing.T) {
body := "PHP audit:\n" +
"- `src/Controller/Api.php:42` SQL injection risk\n" +
"- `src/Service/Auth.php:100` session fixation\n" +

View file

@ -16,7 +16,7 @@ import (
// --- agentCommand ---
func TestAgentCommand_Good_Gemini(t *testing.T) {
func TestDispatch_AgentCommand_Good_Gemini(t *testing.T) {
cmd, args, err := agentCommand("gemini", "do the thing")
require.NoError(t, err)
assert.Equal(t, "gemini", cmd)
@ -26,7 +26,7 @@ func TestAgentCommand_Good_Gemini(t *testing.T) {
assert.Contains(t, args, "--sandbox")
}
func TestAgentCommand_Good_GeminiWithModel(t *testing.T) {
func TestDispatch_AgentCommand_Good_GeminiWithModel(t *testing.T) {
cmd, args, err := agentCommand("gemini:flash", "my prompt")
require.NoError(t, err)
assert.Equal(t, "gemini", cmd)
@ -34,7 +34,7 @@ func TestAgentCommand_Good_GeminiWithModel(t *testing.T) {
assert.Contains(t, args, "gemini-2.5-flash")
}
func TestAgentCommand_Good_Codex(t *testing.T) {
func TestDispatch_AgentCommand_Good_Codex(t *testing.T) {
cmd, args, err := agentCommand("codex", "fix the tests")
require.NoError(t, err)
assert.Equal(t, "codex", cmd)
@ -43,7 +43,7 @@ func TestAgentCommand_Good_Codex(t *testing.T) {
assert.Contains(t, args, "fix the tests")
}
func TestAgentCommand_Good_CodexReview(t *testing.T) {
func TestDispatch_AgentCommand_Good_CodexReview(t *testing.T) {
cmd, args, err := agentCommand("codex:review", "")
require.NoError(t, err)
assert.Equal(t, "codex", cmd)
@ -54,7 +54,7 @@ func TestAgentCommand_Good_CodexReview(t *testing.T) {
}
}
func TestAgentCommand_Good_CodexWithModel(t *testing.T) {
func TestDispatch_AgentCommand_Good_CodexWithModel(t *testing.T) {
cmd, args, err := agentCommand("codex:gpt-5.4", "refactor this")
require.NoError(t, err)
assert.Equal(t, "codex", cmd)
@ -62,7 +62,7 @@ func TestAgentCommand_Good_CodexWithModel(t *testing.T) {
assert.Contains(t, args, "gpt-5.4")
}
func TestAgentCommand_Good_Claude(t *testing.T) {
func TestDispatch_AgentCommand_Good_Claude(t *testing.T) {
cmd, args, err := agentCommand("claude", "add tests")
require.NoError(t, err)
assert.Equal(t, "claude", cmd)
@ -71,7 +71,7 @@ func TestAgentCommand_Good_Claude(t *testing.T) {
assert.Contains(t, args, "--dangerously-skip-permissions")
}
func TestAgentCommand_Good_ClaudeWithModel(t *testing.T) {
func TestDispatch_AgentCommand_Good_ClaudeWithModel(t *testing.T) {
cmd, args, err := agentCommand("claude:haiku", "write docs")
require.NoError(t, err)
assert.Equal(t, "claude", cmd)
@ -79,7 +79,7 @@ func TestAgentCommand_Good_ClaudeWithModel(t *testing.T) {
assert.Contains(t, args, "haiku")
}
func TestAgentCommand_Good_CodeRabbit(t *testing.T) {
func TestDispatch_AgentCommand_Good_CodeRabbit(t *testing.T) {
cmd, args, err := agentCommand("coderabbit", "")
require.NoError(t, err)
assert.Equal(t, "coderabbit", cmd)
@ -87,7 +87,7 @@ func TestAgentCommand_Good_CodeRabbit(t *testing.T) {
assert.Contains(t, args, "--plain")
}
func TestAgentCommand_Good_Local(t *testing.T) {
func TestDispatch_AgentCommand_Good_Local(t *testing.T) {
cmd, args, err := agentCommand("local", "do stuff")
require.NoError(t, err)
assert.Equal(t, "sh", cmd)
@ -97,21 +97,21 @@ func TestAgentCommand_Good_Local(t *testing.T) {
assert.Contains(t, args[1], "devstral-24b")
}
func TestAgentCommand_Good_LocalWithModel(t *testing.T) {
func TestDispatch_AgentCommand_Good_LocalWithModel(t *testing.T) {
cmd, args, err := agentCommand("local:mistral-nemo", "do stuff")
require.NoError(t, err)
assert.Equal(t, "sh", cmd)
assert.Contains(t, args[1], "mistral-nemo")
}
func TestAgentCommand_Bad_Unknown(t *testing.T) {
func TestDispatch_AgentCommand_Bad_Unknown(t *testing.T) {
cmd, args, err := agentCommand("robot-from-the-future", "take over")
assert.Error(t, err)
assert.Empty(t, cmd)
assert.Nil(t, args)
}
func TestAgentCommand_Ugly_EmptyAgent(t *testing.T) {
func TestDispatch_AgentCommand_Ugly_EmptyAgent(t *testing.T) {
cmd, args, err := agentCommand("", "prompt")
assert.Error(t, err)
assert.Empty(t, cmd)
@ -120,7 +120,7 @@ func TestAgentCommand_Ugly_EmptyAgent(t *testing.T) {
// --- containerCommand ---
func TestContainerCommand_Good_Codex(t *testing.T) {
func TestDispatch_ContainerCommand_Good_Codex(t *testing.T) {
t.Setenv("AGENT_DOCKER_IMAGE", "")
t.Setenv("DIR_HOME", "/home/dev")
@ -135,7 +135,7 @@ func TestContainerCommand_Good_Codex(t *testing.T) {
assert.Contains(t, args, defaultDockerImage)
}
func TestContainerCommand_Good_CustomImage(t *testing.T) {
func TestDispatch_ContainerCommand_Good_CustomImage(t *testing.T) {
t.Setenv("AGENT_DOCKER_IMAGE", "my-custom-image:latest")
t.Setenv("DIR_HOME", "/home/dev")
@ -144,7 +144,7 @@ func TestContainerCommand_Good_CustomImage(t *testing.T) {
assert.Contains(t, args, "my-custom-image:latest")
}
func TestContainerCommand_Good_ClaudeMountsConfig(t *testing.T) {
func TestDispatch_ContainerCommand_Good_ClaudeMountsConfig(t *testing.T) {
t.Setenv("AGENT_DOCKER_IMAGE", "")
t.Setenv("DIR_HOME", "/home/dev")
@ -153,7 +153,7 @@ func TestContainerCommand_Good_ClaudeMountsConfig(t *testing.T) {
assert.Contains(t, joined, ".claude:/home/dev/.claude:ro")
}
func TestContainerCommand_Good_GeminiMountsConfig(t *testing.T) {
func TestDispatch_ContainerCommand_Good_GeminiMountsConfig(t *testing.T) {
t.Setenv("AGENT_DOCKER_IMAGE", "")
t.Setenv("DIR_HOME", "/home/dev")
@ -162,7 +162,7 @@ func TestContainerCommand_Good_GeminiMountsConfig(t *testing.T) {
assert.Contains(t, joined, ".gemini:/home/dev/.gemini:ro")
}
func TestContainerCommand_Good_CodexNoClaudeMount(t *testing.T) {
func TestDispatch_ContainerCommand_Good_CodexNoClaudeMount(t *testing.T) {
t.Setenv("AGENT_DOCKER_IMAGE", "")
t.Setenv("DIR_HOME", "/home/dev")
@ -172,7 +172,7 @@ func TestContainerCommand_Good_CodexNoClaudeMount(t *testing.T) {
assert.NotContains(t, joined, ".claude:/home/dev/.claude:ro")
}
func TestContainerCommand_Good_APIKeysPassedByRef(t *testing.T) {
func TestDispatch_ContainerCommand_Good_APIKeysPassedByRef(t *testing.T) {
t.Setenv("AGENT_DOCKER_IMAGE", "")
t.Setenv("DIR_HOME", "/home/dev")
@ -183,7 +183,7 @@ func TestContainerCommand_Good_APIKeysPassedByRef(t *testing.T) {
assert.Contains(t, joined, "GEMINI_API_KEY")
}
func TestContainerCommand_Ugly_EmptyDirs(t *testing.T) {
func TestDispatch_ContainerCommand_Ugly_EmptyDirs(t *testing.T) {
t.Setenv("AGENT_DOCKER_IMAGE", "")
t.Setenv("DIR_HOME", "")
@ -195,7 +195,7 @@ func TestContainerCommand_Ugly_EmptyDirs(t *testing.T) {
// --- buildAutoPRBody ---
func TestBuildAutoPRBody_Good_Basic(t *testing.T) {
func TestAutoPr_BuildAutoPRBody_Good_Basic(t *testing.T) {
s := &PrepSubsystem{}
st := &WorkspaceStatus{
Task: "Fix the login bug",
@ -210,7 +210,7 @@ func TestBuildAutoPRBody_Good_Basic(t *testing.T) {
assert.Contains(t, body, "Co-Authored-By: Virgil <virgil@lethean.io>")
}
func TestBuildAutoPRBody_Good_WithIssue(t *testing.T) {
func TestAutoPr_BuildAutoPRBody_Good_WithIssue(t *testing.T) {
s := &PrepSubsystem{}
st := &WorkspaceStatus{
Task: "Add rate limiting",
@ -222,7 +222,7 @@ func TestBuildAutoPRBody_Good_WithIssue(t *testing.T) {
assert.Contains(t, body, "Closes #42")
}
func TestBuildAutoPRBody_Good_NoIssue(t *testing.T) {
func TestAutoPr_BuildAutoPRBody_Good_NoIssue(t *testing.T) {
s := &PrepSubsystem{}
st := &WorkspaceStatus{
Task: "Refactor internals",
@ -233,7 +233,7 @@ func TestBuildAutoPRBody_Good_NoIssue(t *testing.T) {
assert.NotContains(t, body, "Closes #")
}
func TestBuildAutoPRBody_Good_CommitCount(t *testing.T) {
func TestAutoPr_BuildAutoPRBody_Good_CommitCount(t *testing.T) {
s := &PrepSubsystem{}
st := &WorkspaceStatus{Agent: "codex", Branch: "agent/foo"}
body1 := s.buildAutoPRBody(st, 1)
@ -242,7 +242,7 @@ func TestBuildAutoPRBody_Good_CommitCount(t *testing.T) {
assert.Contains(t, body5, "**Commits:** 5")
}
func TestBuildAutoPRBody_Bad_EmptyTask(t *testing.T) {
func TestAutoPr_BuildAutoPRBody_Bad_EmptyTask(t *testing.T) {
s := &PrepSubsystem{}
st := &WorkspaceStatus{
Task: "",
@ -255,7 +255,7 @@ func TestBuildAutoPRBody_Bad_EmptyTask(t *testing.T) {
assert.Contains(t, body, "**Agent:** codex")
}
func TestBuildAutoPRBody_Ugly_ZeroCommits(t *testing.T) {
func TestAutoPr_BuildAutoPRBody_Ugly_ZeroCommits(t *testing.T) {
s := &PrepSubsystem{}
st := &WorkspaceStatus{Agent: "codex", Branch: "agent/test"}
body := s.buildAutoPRBody(st, 0)
@ -264,7 +264,7 @@ func TestBuildAutoPRBody_Ugly_ZeroCommits(t *testing.T) {
// --- emitEvent ---
func TestEmitEvent_Good_WritesJSONL(t *testing.T) {
func TestEvents_EmitEvent_Good_WritesJSONL(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
require.True(t, fs.EnsureDir(filepath.Join(root, "workspace")).OK)
@ -282,7 +282,7 @@ func TestEmitEvent_Good_WritesJSONL(t *testing.T) {
assert.Contains(t, content, "completed")
}
func TestEmitEvent_Good_ValidJSON(t *testing.T) {
func TestEvents_EmitEvent_Good_ValidJSON(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
require.True(t, fs.EnsureDir(filepath.Join(root, "workspace")).OK)
@ -306,7 +306,7 @@ func TestEmitEvent_Good_ValidJSON(t *testing.T) {
}
}
func TestEmitEvent_Good_Appends(t *testing.T) {
func TestEvents_EmitEvent_Good_Appends(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
require.True(t, fs.EnsureDir(filepath.Join(root, "workspace")).OK)
@ -327,7 +327,7 @@ func TestEmitEvent_Good_Appends(t *testing.T) {
assert.Equal(t, 2, lines, "both events should be in the log")
}
func TestEmitEvent_Good_StartHelper(t *testing.T) {
func TestEvents_EmitEvent_Good_StartHelper(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
require.True(t, fs.EnsureDir(filepath.Join(root, "workspace")).OK)
@ -341,7 +341,7 @@ func TestEmitEvent_Good_StartHelper(t *testing.T) {
assert.Contains(t, r.Value.(string), "running")
}
func TestEmitEvent_Good_CompletionHelper(t *testing.T) {
func TestEvents_EmitEvent_Good_CompletionHelper(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
require.True(t, fs.EnsureDir(filepath.Join(root, "workspace")).OK)
@ -355,7 +355,7 @@ func TestEmitEvent_Good_CompletionHelper(t *testing.T) {
assert.Contains(t, r.Value.(string), "failed")
}
func TestEmitEvent_Bad_NoWorkspaceDir(t *testing.T) {
func TestEvents_EmitEvent_Bad_NoWorkspaceDir(t *testing.T) {
// CORE_WORKSPACE points to a directory that doesn't allow writing events.jsonl
// because workspace/ subdir doesn't exist. Should not panic.
root := t.TempDir()
@ -366,7 +366,7 @@ func TestEmitEvent_Bad_NoWorkspaceDir(t *testing.T) {
})
}
func TestEmitEvent_Ugly_EmptyFields(t *testing.T) {
func TestEvents_EmitEvent_Ugly_EmptyFields(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
require.True(t, fs.EnsureDir(filepath.Join(root, "workspace")).OK)
@ -379,42 +379,42 @@ func TestEmitEvent_Ugly_EmptyFields(t *testing.T) {
// --- countFileRefs ---
func TestCountFileRefs_Good_GoRefs(t *testing.T) {
func TestIngest_CountFileRefs_Good_GoRefs(t *testing.T) {
body := "Found issue in `pkg/core/app.go:42` and `pkg/core/service.go:100`."
assert.Equal(t, 2, countFileRefs(body))
}
func TestCountFileRefs_Good_PHPRefs(t *testing.T) {
func TestIngest_CountFileRefs_Good_PHPRefs(t *testing.T) {
body := "See `src/Core/Boot.php:15` for details."
assert.Equal(t, 1, countFileRefs(body))
}
func TestCountFileRefs_Good_Mixed(t *testing.T) {
func TestIngest_CountFileRefs_Good_Mixed(t *testing.T) {
body := "Go file: `main.go:1`, PHP file: `index.php:99`, plain text ref."
assert.Equal(t, 2, countFileRefs(body))
}
func TestCountFileRefs_Good_NoRefs(t *testing.T) {
func TestIngest_CountFileRefs_Good_NoRefs(t *testing.T) {
body := "This is just plain text with no file references."
assert.Equal(t, 0, countFileRefs(body))
}
func TestCountFileRefs_Good_UnrelatedBacktick(t *testing.T) {
func TestIngest_CountFileRefs_Good_UnrelatedBacktick(t *testing.T) {
// Backtick-quoted string that is not a file:line reference
body := "Run `go test ./...` to execute tests."
assert.Equal(t, 0, countFileRefs(body))
}
func TestCountFileRefs_Bad_EmptyBody(t *testing.T) {
func TestIngest_CountFileRefs_Bad_EmptyBody(t *testing.T) {
assert.Equal(t, 0, countFileRefs(""))
}
func TestCountFileRefs_Bad_ShortBody(t *testing.T) {
func TestIngest_CountFileRefs_Bad_ShortBody(t *testing.T) {
// Body too short to contain a valid reference
assert.Equal(t, 0, countFileRefs("`a`"))
}
func TestCountFileRefs_Ugly_MalformedBackticks(t *testing.T) {
func TestIngest_CountFileRefs_Ugly_MalformedBackticks(t *testing.T) {
// Unclosed backtick — should not panic or hang
body := "Something `unclosed"
assert.NotPanics(t, func() {
@ -422,7 +422,7 @@ func TestCountFileRefs_Ugly_MalformedBackticks(t *testing.T) {
})
}
func TestCountFileRefs_Ugly_LongRef(t *testing.T) {
func TestIngest_CountFileRefs_Ugly_LongRef(t *testing.T) {
// Reference longer than 100 chars should not be counted (loop limit)
longRef := "`" + strings.Repeat("a", 101) + ".go:1`"
assert.Equal(t, 0, countFileRefs(longRef))
@ -430,67 +430,67 @@ func TestCountFileRefs_Ugly_LongRef(t *testing.T) {
// --- modelVariant ---
func TestModelVariant_Good_WithModel(t *testing.T) {
func TestQueue_ModelVariant_Good_WithModel(t *testing.T) {
assert.Equal(t, "gpt-5.4", modelVariant("codex:gpt-5.4"))
assert.Equal(t, "flash", modelVariant("gemini:flash"))
assert.Equal(t, "opus", modelVariant("claude:opus"))
assert.Equal(t, "haiku", modelVariant("claude:haiku"))
}
func TestModelVariant_Good_NoVariant(t *testing.T) {
func TestQueue_ModelVariant_Good_NoVariant(t *testing.T) {
assert.Equal(t, "", modelVariant("codex"))
assert.Equal(t, "", modelVariant("claude"))
assert.Equal(t, "", modelVariant("gemini"))
}
func TestModelVariant_Good_MultipleColons(t *testing.T) {
func TestQueue_ModelVariant_Good_MultipleColons(t *testing.T) {
// SplitN(2) only splits on first colon; rest is preserved as the model
assert.Equal(t, "gpt-5.3-codex-spark", modelVariant("codex:gpt-5.3-codex-spark"))
}
func TestModelVariant_Bad_EmptyString(t *testing.T) {
func TestQueue_ModelVariant_Bad_EmptyString(t *testing.T) {
assert.Equal(t, "", modelVariant(""))
}
func TestModelVariant_Ugly_ColonOnly(t *testing.T) {
func TestQueue_ModelVariant_Ugly_ColonOnly(t *testing.T) {
// Just a colon with no model name
assert.Equal(t, "", modelVariant(":"))
}
// --- baseAgent ---
func TestBaseAgent_Good_Variants(t *testing.T) {
func TestQueue_BaseAgent_Good_Variants(t *testing.T) {
assert.Equal(t, "gemini", baseAgent("gemini:flash"))
assert.Equal(t, "gemini", baseAgent("gemini:pro"))
assert.Equal(t, "claude", baseAgent("claude:haiku"))
assert.Equal(t, "codex", baseAgent("codex:gpt-5.4"))
}
func TestBaseAgent_Good_NoVariant(t *testing.T) {
func TestQueue_BaseAgent_Good_NoVariant(t *testing.T) {
assert.Equal(t, "codex", baseAgent("codex"))
assert.Equal(t, "claude", baseAgent("claude"))
assert.Equal(t, "gemini", baseAgent("gemini"))
}
func TestBaseAgent_Good_CodexSparkSpecialCase(t *testing.T) {
func TestQueue_BaseAgent_Good_CodexSparkSpecialCase(t *testing.T) {
// codex-spark variants map to their own pool name
assert.Equal(t, "codex-spark", baseAgent("codex:gpt-5.3-codex-spark"))
assert.Equal(t, "codex-spark", baseAgent("codex-spark"))
}
func TestBaseAgent_Bad_EmptyString(t *testing.T) {
func TestQueue_BaseAgent_Bad_EmptyString(t *testing.T) {
// Empty string — SplitN returns [""], so first element is ""
assert.Equal(t, "", baseAgent(""))
}
func TestBaseAgent_Ugly_JustColon(t *testing.T) {
func TestQueue_BaseAgent_Ugly_JustColon(t *testing.T) {
// Just a colon — base is empty string before colon
assert.Equal(t, "", baseAgent(":model"))
}
// --- resolveWorkspace ---
func TestResolveWorkspace_Good_ExistingDir(t *testing.T) {
func TestHandlers_ResolveWorkspace_Good_ExistingDir(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
@ -503,7 +503,7 @@ func TestResolveWorkspace_Good_ExistingDir(t *testing.T) {
assert.Equal(t, wsDir, result)
}
func TestResolveWorkspace_Good_NestedPath(t *testing.T) {
func TestHandlers_ResolveWorkspace_Good_NestedPath(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
@ -515,7 +515,7 @@ func TestResolveWorkspace_Good_NestedPath(t *testing.T) {
assert.Equal(t, wsDir, result)
}
func TestResolveWorkspace_Bad_NonExistentDir(t *testing.T) {
func TestHandlers_ResolveWorkspace_Bad_NonExistentDir(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
@ -523,7 +523,7 @@ func TestResolveWorkspace_Bad_NonExistentDir(t *testing.T) {
assert.Equal(t, "", result)
}
func TestResolveWorkspace_Bad_EmptyName(t *testing.T) {
func TestHandlers_ResolveWorkspace_Bad_EmptyName(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
@ -535,7 +535,7 @@ func TestResolveWorkspace_Bad_EmptyName(t *testing.T) {
_ = result
}
func TestResolveWorkspace_Ugly_PathTraversal(t *testing.T) {
func TestHandlers_ResolveWorkspace_Ugly_PathTraversal(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
@ -546,7 +546,7 @@ func TestResolveWorkspace_Ugly_PathTraversal(t *testing.T) {
// --- findWorkspaceByPR ---
func TestFindWorkspaceByPR_Good_MatchesFlatLayout(t *testing.T) {
func TestHandlers_FindWorkspaceByPR_Good_MatchesFlatLayout(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
@ -562,7 +562,7 @@ func TestFindWorkspaceByPR_Good_MatchesFlatLayout(t *testing.T) {
assert.Equal(t, wsDir, result)
}
func TestFindWorkspaceByPR_Good_MatchesDeepLayout(t *testing.T) {
func TestHandlers_FindWorkspaceByPR_Good_MatchesDeepLayout(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
@ -578,7 +578,7 @@ func TestFindWorkspaceByPR_Good_MatchesDeepLayout(t *testing.T) {
assert.Equal(t, wsDir, result)
}
func TestFindWorkspaceByPR_Bad_NoMatch(t *testing.T) {
func TestHandlers_FindWorkspaceByPR_Bad_NoMatch(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
@ -594,7 +594,7 @@ func TestFindWorkspaceByPR_Bad_NoMatch(t *testing.T) {
assert.Equal(t, "", result)
}
func TestFindWorkspaceByPR_Bad_EmptyWorkspace(t *testing.T) {
func TestHandlers_FindWorkspaceByPR_Bad_EmptyWorkspace(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
// No workspaces at all
@ -602,7 +602,7 @@ func TestFindWorkspaceByPR_Bad_EmptyWorkspace(t *testing.T) {
assert.Equal(t, "", result)
}
func TestFindWorkspaceByPR_Bad_RepoDiffers(t *testing.T) {
func TestHandlers_FindWorkspaceByPR_Bad_RepoDiffers(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
@ -619,7 +619,7 @@ func TestFindWorkspaceByPR_Bad_RepoDiffers(t *testing.T) {
assert.Equal(t, "", result)
}
func TestFindWorkspaceByPR_Ugly_CorruptStatusFile(t *testing.T) {
func TestHandlers_FindWorkspaceByPR_Ugly_CorruptStatusFile(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
@ -634,31 +634,31 @@ func TestFindWorkspaceByPR_Ugly_CorruptStatusFile(t *testing.T) {
// --- extractPRNumber ---
func TestExtractPRNumber_Good_FullURL(t *testing.T) {
func TestVerify_ExtractPRNumber_Good_FullURL(t *testing.T) {
assert.Equal(t, 42, extractPRNumber("https://forge.lthn.ai/core/agent/pulls/42"))
assert.Equal(t, 1, extractPRNumber("https://forge.lthn.ai/core/go-io/pulls/1"))
assert.Equal(t, 999, extractPRNumber("https://forge.lthn.ai/core/go-log/pulls/999"))
}
func TestExtractPRNumber_Good_NumberOnly(t *testing.T) {
func TestVerify_ExtractPRNumber_Good_NumberOnly(t *testing.T) {
// If someone passes a bare number as a URL it should still work
assert.Equal(t, 7, extractPRNumber("7"))
}
func TestExtractPRNumber_Bad_EmptyURL(t *testing.T) {
func TestVerify_ExtractPRNumber_Bad_EmptyURL(t *testing.T) {
assert.Equal(t, 0, extractPRNumber(""))
}
func TestExtractPRNumber_Bad_TrailingSlash(t *testing.T) {
func TestVerify_ExtractPRNumber_Bad_TrailingSlash(t *testing.T) {
// URL ending with slash has empty last segment
assert.Equal(t, 0, extractPRNumber("https://forge.lthn.ai/core/go-io/pulls/"))
}
func TestExtractPRNumber_Bad_NonNumericEnd(t *testing.T) {
func TestVerify_ExtractPRNumber_Bad_NonNumericEnd(t *testing.T) {
assert.Equal(t, 0, extractPRNumber("https://forge.lthn.ai/core/go-io/pulls/abc"))
}
func TestExtractPRNumber_Ugly_JustSlashes(t *testing.T) {
func TestVerify_ExtractPRNumber_Ugly_JustSlashes(t *testing.T) {
// All slashes — last segment is empty
assert.Equal(t, 0, extractPRNumber("///"))
}

View file

@ -41,7 +41,7 @@ func initBareRepo(t *testing.T) string {
// --- hasRemote ---
func TestHasRemote_Good_OriginExists(t *testing.T) {
func TestMirror_HasRemote_Good_OriginExists(t *testing.T) {
dir := initBareRepo(t)
// origin won't exist for a fresh repo, so add it
cmd := exec.Command("git", "remote", "add", "origin", "https://example.com/repo.git")
@ -51,7 +51,7 @@ func TestHasRemote_Good_OriginExists(t *testing.T) {
assert.True(t, hasRemote(dir, "origin"))
}
func TestHasRemote_Good_CustomRemote(t *testing.T) {
func TestMirror_HasRemote_Good_CustomRemote(t *testing.T) {
dir := initBareRepo(t)
cmd := exec.Command("git", "remote", "add", "github", "https://github.com/test/repo.git")
cmd.Dir = dir
@ -60,17 +60,17 @@ func TestHasRemote_Good_CustomRemote(t *testing.T) {
assert.True(t, hasRemote(dir, "github"))
}
func TestHasRemote_Bad_NoSuchRemote(t *testing.T) {
func TestMirror_HasRemote_Bad_NoSuchRemote(t *testing.T) {
dir := initBareRepo(t)
assert.False(t, hasRemote(dir, "nonexistent"))
}
func TestHasRemote_Bad_NotAGitRepo(t *testing.T) {
func TestMirror_HasRemote_Bad_NotAGitRepo(t *testing.T) {
dir := t.TempDir() // plain directory, no .git
assert.False(t, hasRemote(dir, "origin"))
}
func TestHasRemote_Ugly_EmptyDir(t *testing.T) {
func TestMirror_HasRemote_Ugly_EmptyDir(t *testing.T) {
// Empty dir defaults to cwd which may or may not be a repo.
// Just ensure no panic.
assert.NotPanics(t, func() {
@ -80,7 +80,7 @@ func TestHasRemote_Ugly_EmptyDir(t *testing.T) {
// --- commitsAhead ---
func TestCommitsAhead_Good_OneAhead(t *testing.T) {
func TestMirror_CommitsAhead_Good_OneAhead(t *testing.T) {
dir := initBareRepo(t)
// Create a branch at the current commit to act as "base"
@ -109,7 +109,7 @@ func TestCommitsAhead_Good_OneAhead(t *testing.T) {
assert.Equal(t, 1, ahead)
}
func TestCommitsAhead_Good_ThreeAhead(t *testing.T) {
func TestMirror_CommitsAhead_Good_ThreeAhead(t *testing.T) {
dir := initBareRepo(t)
run := func(args ...string) {
t.Helper()
@ -138,32 +138,32 @@ func TestCommitsAhead_Good_ThreeAhead(t *testing.T) {
assert.Equal(t, 3, ahead)
}
func TestCommitsAhead_Good_ZeroAhead(t *testing.T) {
func TestMirror_CommitsAhead_Good_ZeroAhead(t *testing.T) {
dir := initBareRepo(t)
// Same ref on both sides
ahead := commitsAhead(dir, "main", "main")
assert.Equal(t, 0, ahead)
}
func TestCommitsAhead_Bad_InvalidRef(t *testing.T) {
func TestMirror_CommitsAhead_Bad_InvalidRef(t *testing.T) {
dir := initBareRepo(t)
ahead := commitsAhead(dir, "nonexistent-ref", "main")
assert.Equal(t, 0, ahead)
}
func TestCommitsAhead_Bad_NotARepo(t *testing.T) {
func TestMirror_CommitsAhead_Bad_NotARepo(t *testing.T) {
ahead := commitsAhead(t.TempDir(), "main", "dev")
assert.Equal(t, 0, ahead)
}
func TestCommitsAhead_Ugly_EmptyDir(t *testing.T) {
func TestMirror_CommitsAhead_Ugly_EmptyDir(t *testing.T) {
ahead := commitsAhead("", "a", "b")
assert.Equal(t, 0, ahead)
}
// --- filesChanged ---
func TestFilesChanged_Good_OneFile(t *testing.T) {
func TestMirror_FilesChanged_Good_OneFile(t *testing.T) {
dir := initBareRepo(t)
run := func(args ...string) {
t.Helper()
@ -189,7 +189,7 @@ func TestFilesChanged_Good_OneFile(t *testing.T) {
assert.Equal(t, 1, files)
}
func TestFilesChanged_Good_MultipleFiles(t *testing.T) {
func TestMirror_FilesChanged_Good_MultipleFiles(t *testing.T) {
dir := initBareRepo(t)
run := func(args ...string) {
t.Helper()
@ -217,92 +217,92 @@ func TestFilesChanged_Good_MultipleFiles(t *testing.T) {
assert.Equal(t, 3, files)
}
func TestFilesChanged_Good_NoChanges(t *testing.T) {
func TestMirror_FilesChanged_Good_NoChanges(t *testing.T) {
dir := initBareRepo(t)
files := filesChanged(dir, "main", "main")
assert.Equal(t, 0, files)
}
func TestFilesChanged_Bad_InvalidRef(t *testing.T) {
func TestMirror_FilesChanged_Bad_InvalidRef(t *testing.T) {
dir := initBareRepo(t)
files := filesChanged(dir, "nonexistent", "main")
assert.Equal(t, 0, files)
}
func TestFilesChanged_Bad_NotARepo(t *testing.T) {
func TestMirror_FilesChanged_Bad_NotARepo(t *testing.T) {
files := filesChanged(t.TempDir(), "main", "dev")
assert.Equal(t, 0, files)
}
func TestFilesChanged_Ugly_EmptyDir(t *testing.T) {
func TestMirror_FilesChanged_Ugly_EmptyDir(t *testing.T) {
files := filesChanged("", "a", "b")
assert.Equal(t, 0, files)
}
// --- extractJSONField (extending existing 91% coverage) ---
func TestExtractJSONField_Good_ArrayFirstItem(t *testing.T) {
func TestMirror_ExtractJSONField_Good_ArrayFirstItem(t *testing.T) {
json := `[{"url":"https://github.com/test/pr/1","title":"Fix bug"}]`
assert.Equal(t, "https://github.com/test/pr/1", extractJSONField(json, "url"))
}
func TestExtractJSONField_Good_ObjectField(t *testing.T) {
func TestMirror_ExtractJSONField_Good_ObjectField(t *testing.T) {
json := `{"name":"test-repo","status":"active"}`
assert.Equal(t, "test-repo", extractJSONField(json, "name"))
}
func TestExtractJSONField_Good_ArrayMultipleItems(t *testing.T) {
func TestMirror_ExtractJSONField_Good_ArrayMultipleItems(t *testing.T) {
json := `[{"id":"first"},{"id":"second"}]`
// Should return the first match
assert.Equal(t, "first", extractJSONField(json, "id"))
}
func TestExtractJSONField_Bad_EmptyJSON(t *testing.T) {
func TestMirror_ExtractJSONField_Bad_EmptyJSON(t *testing.T) {
assert.Equal(t, "", extractJSONField("", "url"))
}
func TestExtractJSONField_Bad_EmptyField(t *testing.T) {
func TestMirror_ExtractJSONField_Bad_EmptyField(t *testing.T) {
assert.Equal(t, "", extractJSONField(`{"url":"test"}`, ""))
}
func TestExtractJSONField_Bad_FieldNotFound(t *testing.T) {
func TestMirror_ExtractJSONField_Bad_FieldNotFound(t *testing.T) {
json := `{"name":"test"}`
assert.Equal(t, "", extractJSONField(json, "missing"))
}
func TestExtractJSONField_Bad_InvalidJSON(t *testing.T) {
func TestMirror_ExtractJSONField_Bad_InvalidJSON(t *testing.T) {
assert.Equal(t, "", extractJSONField("not json at all", "url"))
}
func TestExtractJSONField_Ugly_EmptyArray(t *testing.T) {
func TestMirror_ExtractJSONField_Ugly_EmptyArray(t *testing.T) {
assert.Equal(t, "", extractJSONField("[]", "url"))
}
func TestExtractJSONField_Ugly_EmptyObject(t *testing.T) {
func TestMirror_ExtractJSONField_Ugly_EmptyObject(t *testing.T) {
assert.Equal(t, "", extractJSONField("{}", "url"))
}
func TestExtractJSONField_Ugly_NumericValue(t *testing.T) {
func TestMirror_ExtractJSONField_Ugly_NumericValue(t *testing.T) {
// Field exists but is not a string — should return ""
json := `{"count":42}`
assert.Equal(t, "", extractJSONField(json, "count"))
}
func TestExtractJSONField_Ugly_NullValue(t *testing.T) {
func TestMirror_ExtractJSONField_Ugly_NullValue(t *testing.T) {
json := `{"url":null}`
assert.Equal(t, "", extractJSONField(json, "url"))
}
// --- DefaultBranch ---
func TestDefaultBranch_Good_MainBranch(t *testing.T) {
func TestPaths_DefaultBranch_Good_MainBranch(t *testing.T) {
dir := initBareRepo(t)
// initBareRepo creates with -b main
branch := DefaultBranch(dir)
assert.Equal(t, "main", branch)
}
func TestDefaultBranch_Bad_NotARepo(t *testing.T) {
func TestPaths_DefaultBranch_Bad_NotARepo(t *testing.T) {
dir := t.TempDir()
// Falls back to "main" when detection fails
branch := DefaultBranch(dir)
@ -311,7 +311,7 @@ func TestDefaultBranch_Bad_NotARepo(t *testing.T) {
// --- listLocalRepos ---
func TestListLocalRepos_Good_FindsRepos(t *testing.T) {
func TestMirror_ListLocalRepos_Good_FindsRepos(t *testing.T) {
base := t.TempDir()
// Create two git repos under base
@ -331,14 +331,14 @@ func TestListLocalRepos_Good_FindsRepos(t *testing.T) {
assert.NotContains(t, repos, "not-a-repo")
}
func TestListLocalRepos_Bad_EmptyDir(t *testing.T) {
func TestMirror_ListLocalRepos_Bad_EmptyDir(t *testing.T) {
base := t.TempDir()
s := &PrepSubsystem{}
repos := s.listLocalRepos(base)
assert.Empty(t, repos)
}
func TestListLocalRepos_Bad_NonExistentDir(t *testing.T) {
func TestMirror_ListLocalRepos_Bad_NonExistentDir(t *testing.T) {
s := &PrepSubsystem{}
repos := s.listLocalRepos("/nonexistent/path/that/doesnt/exist")
assert.Nil(t, repos)
@ -346,12 +346,12 @@ func TestListLocalRepos_Bad_NonExistentDir(t *testing.T) {
// --- GitHubOrg ---
func TestGitHubOrg_Good_Default(t *testing.T) {
func TestPaths_GitHubOrg_Good_Default(t *testing.T) {
t.Setenv("GITHUB_ORG", "")
assert.Equal(t, "dAppCore", GitHubOrg())
}
func TestGitHubOrg_Good_Custom(t *testing.T) {
func TestPaths_GitHubOrg_Good_Custom(t *testing.T) {
t.Setenv("GITHUB_ORG", "my-org")
assert.Equal(t, "my-org", GitHubOrg())
}

View file

@ -12,134 +12,134 @@ import (
"github.com/stretchr/testify/require"
)
func TestCoreRoot_Good_EnvVar(t *testing.T) {
func TestPaths_CoreRoot_Good_EnvVar(t *testing.T) {
t.Setenv("CORE_WORKSPACE", "/tmp/test-core")
assert.Equal(t, "/tmp/test-core", CoreRoot())
}
func TestCoreRoot_Good_Fallback(t *testing.T) {
func TestPaths_CoreRoot_Good_Fallback(t *testing.T) {
t.Setenv("CORE_WORKSPACE", "")
home, _ := os.UserHomeDir()
assert.Equal(t, home+"/Code/.core", CoreRoot())
}
func TestWorkspaceRoot_Good(t *testing.T) {
func TestPaths_WorkspaceRoot_Good(t *testing.T) {
t.Setenv("CORE_WORKSPACE", "/tmp/test-core")
assert.Equal(t, "/tmp/test-core/workspace", WorkspaceRoot())
}
func TestPlansRoot_Good(t *testing.T) {
func TestPaths_PlansRoot_Good(t *testing.T) {
t.Setenv("CORE_WORKSPACE", "/tmp/test-core")
assert.Equal(t, "/tmp/test-core/plans", PlansRoot())
}
func TestAgentName_Good_EnvVar(t *testing.T) {
func TestPaths_AgentName_Good_EnvVar(t *testing.T) {
t.Setenv("AGENT_NAME", "clotho")
assert.Equal(t, "clotho", AgentName())
}
func TestAgentName_Good_Fallback(t *testing.T) {
func TestPaths_AgentName_Good_Fallback(t *testing.T) {
t.Setenv("AGENT_NAME", "")
name := AgentName()
assert.True(t, name == "cladius" || name == "charon", "expected cladius or charon, got %s", name)
}
func TestGitHubOrg_Good_EnvVar(t *testing.T) {
func TestPaths_GitHubOrg_Good_EnvVar(t *testing.T) {
t.Setenv("GITHUB_ORG", "myorg")
assert.Equal(t, "myorg", GitHubOrg())
}
func TestGitHubOrg_Good_Fallback(t *testing.T) {
func TestPaths_GitHubOrg_Good_Fallback(t *testing.T) {
t.Setenv("GITHUB_ORG", "")
assert.Equal(t, "dAppCore", GitHubOrg())
}
func TestBaseAgent_Good(t *testing.T) {
func TestQueue_BaseAgent_Good(t *testing.T) {
assert.Equal(t, "claude", baseAgent("claude:opus"))
assert.Equal(t, "claude", baseAgent("claude:haiku"))
assert.Equal(t, "gemini", baseAgent("gemini:flash"))
assert.Equal(t, "codex", baseAgent("codex"))
}
func TestExtractPRNumber_Good(t *testing.T) {
func TestVerify_ExtractPRNumber_Good(t *testing.T) {
assert.Equal(t, 123, extractPRNumber("https://forge.lthn.ai/core/go-io/pulls/123"))
assert.Equal(t, 1, extractPRNumber("https://forge.lthn.ai/core/agent/pulls/1"))
}
func TestExtractPRNumber_Bad_Empty(t *testing.T) {
func TestVerify_ExtractPRNumber_Bad_Empty(t *testing.T) {
assert.Equal(t, 0, extractPRNumber(""))
assert.Equal(t, 0, extractPRNumber("https://forge.lthn.ai/core/agent/pulls/"))
}
func TestTruncate_Good(t *testing.T) {
func TestAutoPr_Truncate_Good(t *testing.T) {
assert.Equal(t, "hello", truncate("hello", 10))
assert.Equal(t, "hel...", truncate("hello world", 3))
}
func TestCountFindings_Good(t *testing.T) {
func TestReviewQueue_CountFindings_Good(t *testing.T) {
assert.Equal(t, 0, countFindings("No findings"))
assert.Equal(t, 2, countFindings("- Issue one\n- Issue two\nSummary"))
assert.Equal(t, 1, countFindings("⚠ Warning here"))
}
func TestParseRetryAfter_Good(t *testing.T) {
func TestReviewQueue_ParseRetryAfter_Good(t *testing.T) {
d := parseRetryAfter("please try after 4 minutes and 56 seconds")
assert.InDelta(t, 296.0, d.Seconds(), 1.0)
}
func TestParseRetryAfter_Good_MinutesOnly(t *testing.T) {
func TestReviewQueue_ParseRetryAfter_Good_MinutesOnly(t *testing.T) {
d := parseRetryAfter("try after 5 minutes")
assert.InDelta(t, 300.0, d.Seconds(), 1.0)
}
func TestParseRetryAfter_Bad_NoMatch(t *testing.T) {
func TestReviewQueue_ParseRetryAfter_Bad_NoMatch(t *testing.T) {
d := parseRetryAfter("some random text")
assert.InDelta(t, 300.0, d.Seconds(), 1.0) // defaults to 5 min
}
func TestResolveHost_Good(t *testing.T) {
func TestRemote_ResolveHost_Good(t *testing.T) {
assert.Equal(t, "10.69.69.165:9101", resolveHost("charon"))
assert.Equal(t, "127.0.0.1:9101", resolveHost("cladius"))
assert.Equal(t, "127.0.0.1:9101", resolveHost("local"))
}
func TestResolveHost_Good_CustomPort(t *testing.T) {
func TestRemote_ResolveHost_Good_CustomPort(t *testing.T) {
assert.Equal(t, "192.168.1.1:9101", resolveHost("192.168.1.1"))
assert.Equal(t, "192.168.1.1:8080", resolveHost("192.168.1.1:8080"))
}
func TestExtractJSONField_Good(t *testing.T) {
func TestMirror_ExtractJSONField_Good(t *testing.T) {
json := `[{"url":"https://github.com/dAppCore/go-io/pull/1"}]`
assert.Equal(t, "https://github.com/dAppCore/go-io/pull/1", extractJSONField(json, "url"))
}
func TestExtractJSONField_Good_Object(t *testing.T) {
func TestMirror_ExtractJSONField_Good_Object(t *testing.T) {
json := `{"url":"https://github.com/dAppCore/go-io/pull/2"}`
assert.Equal(t, "https://github.com/dAppCore/go-io/pull/2", extractJSONField(json, "url"))
}
func TestExtractJSONField_Good_PrettyPrinted(t *testing.T) {
func TestMirror_ExtractJSONField_Good_PrettyPrinted(t *testing.T) {
json := "[\n {\n \"url\": \"https://github.com/dAppCore/go-io/pull/3\"\n }\n]"
assert.Equal(t, "https://github.com/dAppCore/go-io/pull/3", extractJSONField(json, "url"))
}
func TestExtractJSONField_Bad_Missing(t *testing.T) {
func TestMirror_ExtractJSONField_Bad_Missing(t *testing.T) {
assert.Equal(t, "", extractJSONField(`{"name":"test"}`, "url"))
assert.Equal(t, "", extractJSONField("", "url"))
}
func TestValidPlanStatus_Good(t *testing.T) {
func TestPlan_ValidPlanStatus_Good(t *testing.T) {
assert.True(t, validPlanStatus("draft"))
assert.True(t, validPlanStatus("in_progress"))
assert.True(t, validPlanStatus("draft"))
}
func TestValidPlanStatus_Bad(t *testing.T) {
func TestPlan_ValidPlanStatus_Bad(t *testing.T) {
assert.False(t, validPlanStatus("invalid"))
assert.False(t, validPlanStatus(""))
}
func TestGeneratePlanID_Good(t *testing.T) {
func TestPlan_GeneratePlanID_Good(t *testing.T) {
id := generatePlanID("Fix the login bug in auth service")
assert.True(t, len(id) > 0)
assert.True(t, strings.Contains(id, "fix-the-login-bug"))

View file

@ -23,7 +23,7 @@ func newTestPrep(t *testing.T) *PrepSubsystem {
// --- planCreate (MCP handler) ---
func TestPlanCreate_Good(t *testing.T) {
func TestPlan_PlanCreate_Good(t *testing.T) {
dir := t.TempDir()
t.Setenv("CORE_WORKSPACE", dir)
@ -48,7 +48,7 @@ func TestPlanCreate_Good(t *testing.T) {
assert.NoError(t, statErr)
}
func TestPlanCreate_Bad_MissingTitle(t *testing.T) {
func TestPlan_PlanCreate_Bad_MissingTitle(t *testing.T) {
s := newTestPrep(t)
_, _, err := s.planCreate(context.Background(), nil, PlanCreateInput{
Objective: "something",
@ -57,7 +57,7 @@ func TestPlanCreate_Bad_MissingTitle(t *testing.T) {
assert.Contains(t, err.Error(), "title is required")
}
func TestPlanCreate_Bad_MissingObjective(t *testing.T) {
func TestPlan_PlanCreate_Bad_MissingObjective(t *testing.T) {
s := newTestPrep(t)
_, _, err := s.planCreate(context.Background(), nil, PlanCreateInput{
Title: "My Plan",
@ -66,7 +66,7 @@ func TestPlanCreate_Bad_MissingObjective(t *testing.T) {
assert.Contains(t, err.Error(), "objective is required")
}
func TestPlanCreate_Good_DefaultPhaseStatus(t *testing.T) {
func TestPlan_PlanCreate_Good_DefaultPhaseStatus(t *testing.T) {
dir := t.TempDir()
t.Setenv("CORE_WORKSPACE", dir)
@ -88,7 +88,7 @@ func TestPlanCreate_Good_DefaultPhaseStatus(t *testing.T) {
// --- planRead (MCP handler) ---
func TestPlanRead_Good(t *testing.T) {
func TestPlan_PlanRead_Good(t *testing.T) {
dir := t.TempDir()
t.Setenv("CORE_WORKSPACE", dir)
@ -107,14 +107,14 @@ func TestPlanRead_Good(t *testing.T) {
assert.Equal(t, "draft", readOut.Plan.Status)
}
func TestPlanRead_Bad_MissingID(t *testing.T) {
func TestPlan_PlanRead_Bad_MissingID(t *testing.T) {
s := newTestPrep(t)
_, _, err := s.planRead(context.Background(), nil, PlanReadInput{})
assert.Error(t, err)
assert.Contains(t, err.Error(), "id is required")
}
func TestPlanRead_Bad_NotFound(t *testing.T) {
func TestPlan_PlanRead_Bad_NotFound(t *testing.T) {
dir := t.TempDir()
t.Setenv("CORE_WORKSPACE", dir)
@ -126,7 +126,7 @@ func TestPlanRead_Bad_NotFound(t *testing.T) {
// --- planUpdate (MCP handler) ---
func TestPlanUpdate_Good_Status(t *testing.T) {
func TestPlan_PlanUpdate_Good_Status(t *testing.T) {
dir := t.TempDir()
t.Setenv("CORE_WORKSPACE", dir)
@ -145,7 +145,7 @@ func TestPlanUpdate_Good_Status(t *testing.T) {
assert.Equal(t, "ready", updateOut.Plan.Status)
}
func TestPlanUpdate_Good_PartialUpdate(t *testing.T) {
func TestPlan_PlanUpdate_Good_PartialUpdate(t *testing.T) {
dir := t.TempDir()
t.Setenv("CORE_WORKSPACE", dir)
@ -168,7 +168,7 @@ func TestPlanUpdate_Good_PartialUpdate(t *testing.T) {
assert.Equal(t, "codex", updateOut.Plan.Agent)
}
func TestPlanUpdate_Good_AllStatusTransitions(t *testing.T) {
func TestPlan_PlanUpdate_Good_AllStatusTransitions(t *testing.T) {
dir := t.TempDir()
t.Setenv("CORE_WORKSPACE", dir)
@ -187,7 +187,7 @@ func TestPlanUpdate_Good_AllStatusTransitions(t *testing.T) {
}
}
func TestPlanUpdate_Bad_InvalidStatus(t *testing.T) {
func TestPlan_PlanUpdate_Bad_InvalidStatus(t *testing.T) {
dir := t.TempDir()
t.Setenv("CORE_WORKSPACE", dir)
@ -203,14 +203,14 @@ func TestPlanUpdate_Bad_InvalidStatus(t *testing.T) {
assert.Contains(t, err.Error(), "invalid status")
}
func TestPlanUpdate_Bad_MissingID(t *testing.T) {
func TestPlan_PlanUpdate_Bad_MissingID(t *testing.T) {
s := newTestPrep(t)
_, _, err := s.planUpdate(context.Background(), nil, PlanUpdateInput{Status: "ready"})
assert.Error(t, err)
assert.Contains(t, err.Error(), "id is required")
}
func TestPlanUpdate_Good_ReplacePhases(t *testing.T) {
func TestPlan_PlanUpdate_Good_ReplacePhases(t *testing.T) {
dir := t.TempDir()
t.Setenv("CORE_WORKSPACE", dir)
@ -232,7 +232,7 @@ func TestPlanUpdate_Good_ReplacePhases(t *testing.T) {
// --- planDelete (MCP handler) ---
func TestPlanDelete_Good(t *testing.T) {
func TestPlan_PlanDelete_Good(t *testing.T) {
dir := t.TempDir()
t.Setenv("CORE_WORKSPACE", dir)
@ -250,14 +250,14 @@ func TestPlanDelete_Good(t *testing.T) {
assert.True(t, os.IsNotExist(statErr))
}
func TestPlanDelete_Bad_MissingID(t *testing.T) {
func TestPlan_PlanDelete_Bad_MissingID(t *testing.T) {
s := newTestPrep(t)
_, _, err := s.planDelete(context.Background(), nil, PlanDeleteInput{})
assert.Error(t, err)
assert.Contains(t, err.Error(), "id is required")
}
func TestPlanDelete_Bad_NotFound(t *testing.T) {
func TestPlan_PlanDelete_Bad_NotFound(t *testing.T) {
dir := t.TempDir()
t.Setenv("CORE_WORKSPACE", dir)
@ -269,7 +269,7 @@ func TestPlanDelete_Bad_NotFound(t *testing.T) {
// --- planList (MCP handler) ---
func TestPlanList_Good_Empty(t *testing.T) {
func TestPlan_PlanList_Good_Empty(t *testing.T) {
dir := t.TempDir()
t.Setenv("CORE_WORKSPACE", dir)
@ -280,7 +280,7 @@ func TestPlanList_Good_Empty(t *testing.T) {
assert.Equal(t, 0, out.Count)
}
func TestPlanList_Good_Multiple(t *testing.T) {
func TestPlan_PlanList_Good_Multiple(t *testing.T) {
dir := t.TempDir()
t.Setenv("CORE_WORKSPACE", dir)
@ -294,7 +294,7 @@ func TestPlanList_Good_Multiple(t *testing.T) {
assert.Equal(t, 3, out.Count)
}
func TestPlanList_Good_FilterByRepo(t *testing.T) {
func TestPlan_PlanList_Good_FilterByRepo(t *testing.T) {
dir := t.TempDir()
t.Setenv("CORE_WORKSPACE", dir)
@ -308,7 +308,7 @@ func TestPlanList_Good_FilterByRepo(t *testing.T) {
assert.Equal(t, 2, out.Count)
}
func TestPlanList_Good_FilterByStatus(t *testing.T) {
func TestPlan_PlanList_Good_FilterByStatus(t *testing.T) {
dir := t.TempDir()
t.Setenv("CORE_WORKSPACE", dir)
@ -323,7 +323,7 @@ func TestPlanList_Good_FilterByStatus(t *testing.T) {
assert.Equal(t, "ready", out.Plans[0].Status)
}
func TestPlanList_Good_IgnoresNonJSON(t *testing.T) {
func TestPlan_PlanList_Good_IgnoresNonJSON(t *testing.T) {
dir := t.TempDir()
t.Setenv("CORE_WORKSPACE", dir)
@ -341,12 +341,12 @@ func TestPlanList_Good_IgnoresNonJSON(t *testing.T) {
// --- planPath edge cases ---
func TestPlanPath_Bad_PathTraversal(t *testing.T) {
func TestPlan_PlanPath_Bad_PathTraversal(t *testing.T) {
p := planPath("/tmp/plans", "../../etc/passwd")
assert.NotContains(t, p, "..")
}
func TestPlanPath_Bad_Dot(t *testing.T) {
func TestPlan_PlanPath_Bad_Dot(t *testing.T) {
assert.Contains(t, planPath("/tmp", "."), "invalid")
assert.Contains(t, planPath("/tmp", ".."), "invalid")
assert.Contains(t, planPath("/tmp", ""), "invalid")

View file

@ -13,37 +13,37 @@ import (
// --- planPath ---
func TestPlanPath_Good_BasicFormat(t *testing.T) {
func TestPlan_PlanPath_Good_BasicFormat(t *testing.T) {
result := planPath("/tmp/plans", "my-plan-abc123")
assert.Equal(t, "/tmp/plans/my-plan-abc123.json", result)
}
func TestPlanPath_Good_NestedIDStripped(t *testing.T) {
func TestPlan_PlanPath_Good_NestedIDStripped(t *testing.T) {
// PathBase strips directory component — prevents path traversal
result := planPath("/plans", "../../../etc/passwd")
assert.Equal(t, "/plans/passwd.json", result)
}
func TestPlanPath_Good_SimpleID(t *testing.T) {
func TestPlan_PlanPath_Good_SimpleID(t *testing.T) {
assert.Equal(t, "/data/test.json", planPath("/data", "test"))
}
func TestPlanPath_Good_SlugWithDashes(t *testing.T) {
func TestPlan_PlanPath_Good_SlugWithDashes(t *testing.T) {
assert.Equal(t, "/root/migrate-core-abc123.json", planPath("/root", "migrate-core-abc123"))
}
func TestPlanPath_Bad_DotID(t *testing.T) {
func TestPlan_PlanPath_Bad_DotID(t *testing.T) {
// "." is sanitised to "invalid" to prevent exploiting the root directory
result := planPath("/plans", ".")
assert.Equal(t, "/plans/invalid.json", result)
}
func TestPlanPath_Bad_DoubleDotID(t *testing.T) {
func TestPlan_PlanPath_Bad_DoubleDotID(t *testing.T) {
result := planPath("/plans", "..")
assert.Equal(t, "/plans/invalid.json", result)
}
func TestPlanPath_Bad_EmptyID(t *testing.T) {
func TestPlan_PlanPath_Bad_EmptyID(t *testing.T) {
result := planPath("/plans", "")
assert.Equal(t, "/plans/invalid.json", result)
}
@ -112,13 +112,13 @@ func TestReadWritePlan_Good_WithPhases(t *testing.T) {
assert.Equal(t, "pending", read.Phases[2].Status)
}
func TestReadPlan_Bad_MissingFile(t *testing.T) {
func TestPlan_ReadPlan_Bad_MissingFile(t *testing.T) {
dir := t.TempDir()
_, err := readPlan(dir, "nonexistent-plan")
assert.Error(t, err)
}
func TestReadPlan_Bad_CorruptJSON(t *testing.T) {
func TestPlan_ReadPlan_Bad_CorruptJSON(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "bad.json"), `{broken`).OK)
@ -126,7 +126,7 @@ func TestReadPlan_Bad_CorruptJSON(t *testing.T) {
assert.Error(t, err)
}
func TestWritePlan_Good_CreatesNestedDir(t *testing.T) {
func TestPlan_WritePlan_Good_CreatesNestedDir(t *testing.T) {
base := t.TempDir()
nested := filepath.Join(base, "deep", "nested", "plans")
@ -143,7 +143,7 @@ func TestWritePlan_Good_CreatesNestedDir(t *testing.T) {
assert.True(t, fs.IsFile(path))
}
func TestWritePlan_Good_OverwriteExistingLogic(t *testing.T) {
func TestPlan_WritePlan_Good_OverwriteExistingLogic(t *testing.T) {
dir := t.TempDir()
plan := &Plan{
@ -166,7 +166,7 @@ func TestWritePlan_Good_OverwriteExistingLogic(t *testing.T) {
assert.Equal(t, "approved", read.Status)
}
func TestReadPlan_Ugly_EmptyFileLogic(t *testing.T) {
func TestPlan_ReadPlan_Ugly_EmptyFileLogic(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "empty.json"), "").OK)

View file

@ -11,12 +11,12 @@ import (
"github.com/stretchr/testify/require"
)
func TestPlanPath_Good(t *testing.T) {
func TestPlan_PlanPath_Good(t *testing.T) {
assert.Equal(t, "/tmp/plans/my-plan-abc123.json", planPath("/tmp/plans", "my-plan-abc123"))
assert.Equal(t, "/data/test.json", planPath("/data", "test"))
}
func TestWritePlan_Good(t *testing.T) {
func TestPlan_WritePlan_Good(t *testing.T) {
dir := t.TempDir()
plan := &Plan{
ID: "test-plan-abc123",
@ -33,7 +33,7 @@ func TestWritePlan_Good(t *testing.T) {
assert.True(t, fs.IsFile(path))
}
func TestWritePlan_Good_CreatesDirectory(t *testing.T) {
func TestPlan_WritePlan_Good_CreatesDirectory(t *testing.T) {
base := t.TempDir()
dir := filepath.Join(base, "nested", "plans")
@ -49,7 +49,7 @@ func TestWritePlan_Good_CreatesDirectory(t *testing.T) {
assert.Contains(t, path, "nested-plan-abc123.json")
}
func TestReadPlan_Good(t *testing.T) {
func TestPlan_ReadPlan_Good(t *testing.T) {
dir := t.TempDir()
original := &Plan{
ID: "read-test-abc123",
@ -87,13 +87,13 @@ func TestReadPlan_Good(t *testing.T) {
assert.Equal(t, "claude:opus", read.Agent)
}
func TestReadPlan_Bad_NotFound(t *testing.T) {
func TestPlan_ReadPlan_Bad_NotFound(t *testing.T) {
dir := t.TempDir()
_, err := readPlan(dir, "nonexistent-plan")
assert.Error(t, err)
}
func TestReadPlan_Bad_InvalidJSON(t *testing.T) {
func TestPlan_ReadPlan_Bad_InvalidJSON(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "bad-json.json"), "{broken").OK)
@ -134,7 +134,7 @@ func TestWriteReadPlan_Good_Roundtrip(t *testing.T) {
assert.Equal(t, "Working on it", read.Phases[1].Notes)
}
func TestGeneratePlanID_Good_Slugifies(t *testing.T) {
func TestPlan_GeneratePlanID_Good_Slugifies(t *testing.T) {
id := generatePlanID("Add Unit Tests for Agentic")
assert.True(t, strings.HasPrefix(id, "add-unit-tests-for-agentic"), "got: %s", id)
// Should have random suffix
@ -142,7 +142,7 @@ func TestGeneratePlanID_Good_Slugifies(t *testing.T) {
assert.True(t, len(parts) >= 5, "expected slug with random suffix, got: %s", id)
}
func TestGeneratePlanID_Good_TruncatesLong(t *testing.T) {
func TestPlan_GeneratePlanID_Good_TruncatesLong(t *testing.T) {
id := generatePlanID("This is a very long title that should be truncated to a reasonable length for file naming purposes")
// Slug part (before random suffix) should be <= 30 chars
lastDash := strings.LastIndex(id, "-")
@ -150,7 +150,7 @@ func TestGeneratePlanID_Good_TruncatesLong(t *testing.T) {
assert.True(t, len(slug) <= 36, "slug too long: %s (%d chars)", slug, len(slug))
}
func TestGeneratePlanID_Good_HandlesSpecialChars(t *testing.T) {
func TestPlan_GeneratePlanID_Good_HandlesSpecialChars(t *testing.T) {
id := generatePlanID("Fix bug #123: auth & session!")
assert.True(t, strings.Contains(id, "fix-bug"), "got: %s", id)
assert.NotContains(t, id, "#")
@ -158,27 +158,27 @@ func TestGeneratePlanID_Good_HandlesSpecialChars(t *testing.T) {
assert.NotContains(t, id, "&")
}
func TestGeneratePlanID_Good_Unique(t *testing.T) {
func TestPlan_GeneratePlanID_Good_Unique(t *testing.T) {
id1 := generatePlanID("Same Title")
id2 := generatePlanID("Same Title")
assert.NotEqual(t, id1, id2, "IDs should differ due to random suffix")
}
func TestValidPlanStatus_Good_AllValid(t *testing.T) {
func TestPlan_ValidPlanStatus_Good_AllValid(t *testing.T) {
validStatuses := []string{"draft", "ready", "in_progress", "needs_verification", "verified", "approved"}
for _, s := range validStatuses {
assert.True(t, validPlanStatus(s), "expected %q to be valid", s)
}
}
func TestValidPlanStatus_Bad_Invalid(t *testing.T) {
func TestPlan_ValidPlanStatus_Bad_Invalid(t *testing.T) {
invalidStatuses := []string{"", "running", "completed", "cancelled", "archived", "DRAFT", "Draft"}
for _, s := range invalidStatuses {
assert.False(t, validPlanStatus(s), "expected %q to be invalid", s)
}
}
func TestWritePlan_Good_OverwriteExisting(t *testing.T) {
func TestPlan_WritePlan_Good_OverwriteExisting(t *testing.T) {
dir := t.TempDir()
plan := &Plan{
@ -202,7 +202,7 @@ func TestWritePlan_Good_OverwriteExisting(t *testing.T) {
assert.Equal(t, "ready", read.Status)
}
func TestReadPlan_Ugly_EmptyFile(t *testing.T) {
func TestPlan_ReadPlan_Ugly_EmptyFile(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "empty.json"), "").OK)

View file

@ -59,7 +59,7 @@ func mockPRForgeServer(t *testing.T) *httptest.Server {
// --- forgeCreatePR ---
func TestForgeCreatePR_Good_Success(t *testing.T) {
func TestPr_ForgeCreatePR_Good_Success(t *testing.T) {
srv := mockPRForgeServer(t)
s := &PrepSubsystem{
forge: forge.NewForge(srv.URL, "test-token"),
@ -81,7 +81,7 @@ func TestForgeCreatePR_Good_Success(t *testing.T) {
assert.Contains(t, prURL, "pulls/12")
}
func TestForgeCreatePR_Bad_ServerError(t *testing.T) {
func TestPr_ForgeCreatePR_Bad_ServerError(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(500)
json.NewEncoder(w).Encode(map[string]any{"message": "internal error"})
@ -108,7 +108,7 @@ func TestForgeCreatePR_Bad_ServerError(t *testing.T) {
// --- createPR (MCP tool) ---
func TestCreatePR_Bad_NoWorkspace(t *testing.T) {
func TestPr_CreatePR_Bad_NoWorkspace(t *testing.T) {
s := &PrepSubsystem{
forgeToken: "test-token",
backoff: make(map[string]time.Time),
@ -120,7 +120,7 @@ func TestCreatePR_Bad_NoWorkspace(t *testing.T) {
assert.Contains(t, err.Error(), "workspace is required")
}
func TestCreatePR_Bad_NoToken(t *testing.T) {
func TestPr_CreatePR_Bad_NoToken(t *testing.T) {
s := &PrepSubsystem{
forgeToken: "",
backoff: make(map[string]time.Time),
@ -134,7 +134,7 @@ func TestCreatePR_Bad_NoToken(t *testing.T) {
assert.Contains(t, err.Error(), "no Forge token")
}
func TestCreatePR_Bad_WorkspaceNotFound(t *testing.T) {
func TestPr_CreatePR_Bad_WorkspaceNotFound(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
@ -151,7 +151,7 @@ func TestCreatePR_Bad_WorkspaceNotFound(t *testing.T) {
assert.Contains(t, err.Error(), "workspace not found")
}
func TestCreatePR_Good_DryRun(t *testing.T) {
func TestPr_CreatePR_Good_DryRun(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
@ -190,7 +190,7 @@ func TestCreatePR_Good_DryRun(t *testing.T) {
assert.Equal(t, "Fix the login bug", out.Title)
}
func TestCreatePR_Good_CustomTitle(t *testing.T) {
func TestPr_CreatePR_Good_CustomTitle(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
@ -228,7 +228,7 @@ func TestCreatePR_Good_CustomTitle(t *testing.T) {
// --- listPRs ---
func TestListPRs_Bad_NoToken(t *testing.T) {
func TestPr_ListPRs_Bad_NoToken(t *testing.T) {
s := &PrepSubsystem{
forgeToken: "",
backoff: make(map[string]time.Time),
@ -242,7 +242,7 @@ func TestListPRs_Bad_NoToken(t *testing.T) {
// --- commentOnIssue ---
func TestCommentOnIssue_Good_PostsComment(t *testing.T) {
func TestPr_CommentOnIssue_Good_PostsComment(t *testing.T) {
commentPosted := false
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == "POST" {

View file

@ -18,7 +18,7 @@ import (
// --- Shutdown ---
func TestShutdown_Good(t *testing.T) {
func TestPrep_Shutdown_Good(t *testing.T) {
s := &PrepSubsystem{
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
@ -29,14 +29,14 @@ func TestShutdown_Good(t *testing.T) {
// --- Name ---
func TestName_Good(t *testing.T) {
func TestPrep_Name_Good(t *testing.T) {
s := &PrepSubsystem{}
assert.Equal(t, "agentic", s.Name())
}
// --- findConsumersList ---
func TestFindConsumersList_Good_HasConsumers(t *testing.T) {
func TestPrep_FindConsumersList_Good_HasConsumers(t *testing.T) {
dir := t.TempDir()
// Create go.work
@ -76,7 +76,7 @@ use (
assert.Contains(t, list, "Breaking change risk")
}
func TestFindConsumersList_Good_NoConsumers(t *testing.T) {
func TestPrep_FindConsumersList_Good_NoConsumers(t *testing.T) {
dir := t.TempDir()
goWork := `go 1.22
@ -101,7 +101,7 @@ use (
assert.Empty(t, list)
}
func TestFindConsumersList_Bad_NoGoWork(t *testing.T) {
func TestPrep_FindConsumersList_Bad_NoGoWork(t *testing.T) {
s := &PrepSubsystem{
codePath: t.TempDir(),
backoff: make(map[string]time.Time),
@ -115,7 +115,7 @@ func TestFindConsumersList_Bad_NoGoWork(t *testing.T) {
// --- pullWikiContent ---
func TestPullWikiContent_Good_WithPages(t *testing.T) {
func TestPrep_PullWikiContent_Good_WithPages(t *testing.T) {
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":
@ -154,7 +154,7 @@ func TestPullWikiContent_Good_WithPages(t *testing.T) {
assert.Contains(t, content, "### Architecture")
}
func TestPullWikiContent_Good_NoPages(t *testing.T) {
func TestPrep_PullWikiContent_Good_NoPages(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode([]map[string]any{})
}))
@ -173,7 +173,7 @@ func TestPullWikiContent_Good_NoPages(t *testing.T) {
// --- getIssueBody ---
func TestGetIssueBody_Good(t *testing.T) {
func TestPrep_GetIssueBody_Good(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(map[string]any{
"number": 15,
@ -194,7 +194,7 @@ func TestGetIssueBody_Good(t *testing.T) {
assert.Contains(t, body, "tests are broken")
}
func TestGetIssueBody_Bad_NotFound(t *testing.T) {
func TestPrep_GetIssueBody_Bad_NotFound(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(404)
}))
@ -213,7 +213,7 @@ func TestGetIssueBody_Bad_NotFound(t *testing.T) {
// --- buildPrompt ---
func TestBuildPrompt_Good_BasicFields(t *testing.T) {
func TestPrep_BuildPrompt_Good_BasicFields(t *testing.T) {
dir := t.TempDir()
// Create go.mod to detect language
os.WriteFile(filepath.Join(dir, "go.mod"), []byte("module test\n\ngo 1.22\n"), 0o644)
@ -239,7 +239,7 @@ func TestBuildPrompt_Good_BasicFields(t *testing.T) {
assert.Equal(t, 0, consumers)
}
func TestBuildPrompt_Good_WithIssue(t *testing.T) {
func TestPrep_BuildPrompt_Good_WithIssue(t *testing.T) {
dir := t.TempDir()
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@ -359,7 +359,7 @@ func TestPrep_BuildPrompt_Ugly(t *testing.T) {
// --- runQA ---
func TestRunQA_Good_PHPNoComposer(t *testing.T) {
func TestDispatch_RunQA_Good_PHPNoComposer(t *testing.T) {
dir := t.TempDir()
repoDir := filepath.Join(dir, "repo")
os.MkdirAll(repoDir, 0o755)

View file

@ -11,69 +11,69 @@ import (
"github.com/stretchr/testify/require"
)
func TestEnvOr_Good_EnvSet(t *testing.T) {
func TestPrep_EnvOr_Good_EnvSet(t *testing.T) {
t.Setenv("TEST_ENVVAR_CUSTOM", "custom-value")
assert.Equal(t, "custom-value", envOr("TEST_ENVVAR_CUSTOM", "default"))
}
func TestEnvOr_Good_Fallback(t *testing.T) {
func TestPrep_EnvOr_Good_Fallback(t *testing.T) {
t.Setenv("TEST_ENVVAR_MISSING", "")
assert.Equal(t, "default-value", envOr("TEST_ENVVAR_MISSING", "default-value"))
}
func TestEnvOr_Good_UnsetUsesFallback(t *testing.T) {
func TestPrep_EnvOr_Good_UnsetUsesFallback(t *testing.T) {
t.Setenv("TEST_ENVVAR_TOTALLY_MISSING", "")
assert.Equal(t, "fallback", envOr("TEST_ENVVAR_TOTALLY_MISSING", "fallback"))
}
func TestDetectLanguage_Good_Go(t *testing.T) {
func TestPrep_DetectLanguage_Good_Go(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "go.mod"), "module test").OK)
assert.Equal(t, "go", detectLanguage(dir))
}
func TestDetectLanguage_Good_PHP(t *testing.T) {
func TestPrep_DetectLanguage_Good_PHP(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "composer.json"), "{}").OK)
assert.Equal(t, "php", detectLanguage(dir))
}
func TestDetectLanguage_Good_TypeScript(t *testing.T) {
func TestPrep_DetectLanguage_Good_TypeScript(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "package.json"), "{}").OK)
assert.Equal(t, "ts", detectLanguage(dir))
}
func TestDetectLanguage_Good_Rust(t *testing.T) {
func TestPrep_DetectLanguage_Good_Rust(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "Cargo.toml"), "[package]").OK)
assert.Equal(t, "rust", detectLanguage(dir))
}
func TestDetectLanguage_Good_Python(t *testing.T) {
func TestPrep_DetectLanguage_Good_Python(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "requirements.txt"), "flask").OK)
assert.Equal(t, "py", detectLanguage(dir))
}
func TestDetectLanguage_Good_Cpp(t *testing.T) {
func TestPrep_DetectLanguage_Good_Cpp(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "CMakeLists.txt"), "cmake_minimum_required").OK)
assert.Equal(t, "cpp", detectLanguage(dir))
}
func TestDetectLanguage_Good_Docker(t *testing.T) {
func TestPrep_DetectLanguage_Good_Docker(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "Dockerfile"), "FROM alpine").OK)
assert.Equal(t, "docker", detectLanguage(dir))
}
func TestDetectLanguage_Good_DefaultsToGo(t *testing.T) {
func TestPrep_DetectLanguage_Good_DefaultsToGo(t *testing.T) {
dir := t.TempDir()
assert.Equal(t, "go", detectLanguage(dir))
}
func TestDetectBuildCmd_Good(t *testing.T) {
func TestPrep_DetectBuildCmd_Good(t *testing.T) {
tests := []struct {
file string
content string
@ -96,12 +96,12 @@ func TestDetectBuildCmd_Good(t *testing.T) {
}
}
func TestDetectBuildCmd_Good_DefaultsToGo(t *testing.T) {
func TestPrep_DetectBuildCmd_Good_DefaultsToGo(t *testing.T) {
dir := t.TempDir()
assert.Equal(t, "go build ./...", detectBuildCmd(dir))
}
func TestDetectTestCmd_Good(t *testing.T) {
func TestPrep_DetectTestCmd_Good(t *testing.T) {
tests := []struct {
file string
content string
@ -124,25 +124,25 @@ func TestDetectTestCmd_Good(t *testing.T) {
}
}
func TestDetectTestCmd_Good_DefaultsToGo(t *testing.T) {
func TestPrep_DetectTestCmd_Good_DefaultsToGo(t *testing.T) {
dir := t.TempDir()
assert.Equal(t, "go test ./...", detectTestCmd(dir))
}
func TestSanitiseBranchSlug_Good(t *testing.T) {
func TestSanitise_SanitiseBranchSlug_Good(t *testing.T) {
assert.Equal(t, "fix-login-bug", sanitiseBranchSlug("Fix login bug!", 40))
assert.Equal(t, "trim-me", sanitiseBranchSlug("---Trim Me---", 40))
}
func TestSanitiseBranchSlug_Good_Truncates(t *testing.T) {
func TestSanitise_SanitiseBranchSlug_Good_Truncates(t *testing.T) {
assert.Equal(t, "feature", sanitiseBranchSlug("feature--extra", 7))
}
func TestSanitiseFilename_Good(t *testing.T) {
func TestSanitise_SanitiseFilename_Good(t *testing.T) {
assert.Equal(t, "Core---Agent-Notes", sanitiseFilename("Core / Agent:Notes"))
}
func TestNewPrep_Good_Defaults(t *testing.T) {
func TestPrep_NewPrep_Good_Defaults(t *testing.T) {
t.Setenv("FORGE_TOKEN", "")
t.Setenv("GITEA_TOKEN", "")
t.Setenv("CORE_BRAIN_KEY", "")
@ -157,7 +157,7 @@ func TestNewPrep_Good_Defaults(t *testing.T) {
assert.NotNil(t, s.client)
}
func TestNewPrep_Good_EnvOverrides(t *testing.T) {
func TestPrep_NewPrep_Good_EnvOverrides(t *testing.T) {
t.Setenv("FORGE_URL", "https://custom-forge.example.com")
t.Setenv("FORGE_TOKEN", "test-token")
t.Setenv("CORE_BRAIN_URL", "https://custom-brain.example.com")
@ -173,7 +173,7 @@ func TestNewPrep_Good_EnvOverrides(t *testing.T) {
assert.Equal(t, "/custom/code", s.codePath)
}
func TestNewPrep_Good_GiteaTokenFallback(t *testing.T) {
func TestPrep_NewPrep_Good_GiteaTokenFallback(t *testing.T) {
t.Setenv("FORGE_TOKEN", "")
t.Setenv("GITEA_TOKEN", "gitea-fallback-token")
@ -186,7 +186,7 @@ func TestPrepSubsystem_Good_Name(t *testing.T) {
assert.Equal(t, "agentic", s.Name())
}
func TestSetCore_Good(t *testing.T) {
func TestPrep_SetCore_Good(t *testing.T) {
s := &PrepSubsystem{}
assert.Nil(t, s.core)

View file

@ -78,7 +78,7 @@ concurrency:
// --- delayForAgent (extended — sustained mode) ---
func TestDelayForAgent_Good_SustainedMode(t *testing.T) {
func TestQueue_DelayForAgent_Good_SustainedMode(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
@ -106,7 +106,7 @@ rates:
// --- countRunningByModel ---
func TestCountRunningByModel_Good_NoWorkspaces(t *testing.T) {
func TestQueue_CountRunningByModel_Good_NoWorkspaces(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
os.MkdirAll(filepath.Join(root, "workspace"), 0o755)
@ -120,7 +120,7 @@ func TestCountRunningByModel_Good_NoWorkspaces(t *testing.T) {
// --- drainQueue / drainOne ---
func TestDrainQueue_Good_NoCoreFallsBackToMutex(t *testing.T) {
func TestQueue_DrainQueue_Good_NoCoreFallsBackToMutex(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
os.MkdirAll(filepath.Join(root, "workspace"), 0o755)
@ -134,7 +134,7 @@ func TestDrainQueue_Good_NoCoreFallsBackToMutex(t *testing.T) {
assert.NotPanics(t, func() { s.drainQueue() })
}
func TestDrainOne_Good_NoWorkspaces(t *testing.T) {
func TestQueue_DrainOne_Good_NoWorkspaces(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
os.MkdirAll(filepath.Join(root, "workspace"), 0o755)
@ -147,7 +147,7 @@ func TestDrainOne_Good_NoWorkspaces(t *testing.T) {
assert.False(t, s.drainOne())
}
func TestDrainOne_Good_SkipsNonQueued(t *testing.T) {
func TestQueue_DrainOne_Good_SkipsNonQueued(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")
@ -166,7 +166,7 @@ func TestDrainOne_Good_SkipsNonQueued(t *testing.T) {
assert.False(t, s.drainOne())
}
func TestDrainOne_Good_SkipsBackedOffPool(t *testing.T) {
func TestQueue_DrainOne_Good_SkipsBackedOffPool(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")

View file

@ -14,7 +14,7 @@ import (
// --- countRunningByModel ---
func TestCountRunningByModel_Good_Empty(t *testing.T) {
func TestQueue_CountRunningByModel_Good_Empty(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
@ -22,7 +22,7 @@ func TestCountRunningByModel_Good_Empty(t *testing.T) {
assert.Equal(t, 0, s.countRunningByModel("claude:opus"))
}
func TestCountRunningByModel_Good_SkipsNonRunning(t *testing.T) {
func TestQueue_CountRunningByModel_Good_SkipsNonRunning(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
@ -39,7 +39,7 @@ func TestCountRunningByModel_Good_SkipsNonRunning(t *testing.T) {
assert.Equal(t, 0, s.countRunningByModel("codex:gpt-5.4"))
}
func TestCountRunningByModel_Good_SkipsMismatchedModel(t *testing.T) {
func TestQueue_CountRunningByModel_Good_SkipsMismatchedModel(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
@ -56,7 +56,7 @@ func TestCountRunningByModel_Good_SkipsMismatchedModel(t *testing.T) {
assert.Equal(t, 0, s.countRunningByModel("gemini:pro"))
}
func TestCountRunningByModel_Good_DeepLayout(t *testing.T) {
func TestQueue_CountRunningByModel_Good_DeepLayout(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
@ -75,7 +75,7 @@ func TestCountRunningByModel_Good_DeepLayout(t *testing.T) {
// --- drainQueue ---
func TestDrainQueue_Good_FrozenReturnsImmediately(t *testing.T) {
func TestQueue_DrainQueue_Good_FrozenReturnsImmediately(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
@ -86,7 +86,7 @@ func TestDrainQueue_Good_FrozenReturnsImmediately(t *testing.T) {
})
}
func TestDrainQueue_Good_EmptyWorkspace(t *testing.T) {
func TestQueue_DrainQueue_Good_EmptyWorkspace(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
@ -99,7 +99,7 @@ func TestDrainQueue_Good_EmptyWorkspace(t *testing.T) {
// --- Poke ---
func TestPoke_Good_NilChannel(t *testing.T) {
func TestRunner_Poke_Good_NilChannel(t *testing.T) {
s := &PrepSubsystem{pokeCh: nil}
// Must not panic when pokeCh is nil
assert.NotPanics(t, func() {
@ -107,7 +107,7 @@ func TestPoke_Good_NilChannel(t *testing.T) {
})
}
func TestPoke_Good_ChannelReceivesSignal(t *testing.T) {
func TestRunner_Poke_Good_ChannelReceivesSignal(t *testing.T) {
s := &PrepSubsystem{}
s.pokeCh = make(chan struct{}, 1)
@ -115,7 +115,7 @@ func TestPoke_Good_ChannelReceivesSignal(t *testing.T) {
assert.Len(t, s.pokeCh, 1, "poke should enqueue one signal")
}
func TestPoke_Good_NonBlockingWhenFull(t *testing.T) {
func TestRunner_Poke_Good_NonBlockingWhenFull(t *testing.T) {
s := &PrepSubsystem{}
s.pokeCh = make(chan struct{}, 1)
// Pre-fill the channel
@ -130,7 +130,7 @@ func TestPoke_Good_NonBlockingWhenFull(t *testing.T) {
// --- StartRunner ---
func TestStartRunner_Good_CreatesPokeCh(t *testing.T) {
func TestRunner_StartRunner_Good_CreatesPokeCh(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
t.Setenv("CORE_AGENT_DISPATCH", "")
@ -142,7 +142,7 @@ func TestStartRunner_Good_CreatesPokeCh(t *testing.T) {
assert.NotNil(t, s.pokeCh, "StartRunner should initialise pokeCh")
}
func TestStartRunner_Good_FrozenByDefault(t *testing.T) {
func TestRunner_StartRunner_Good_FrozenByDefault(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
t.Setenv("CORE_AGENT_DISPATCH", "")
@ -152,7 +152,7 @@ func TestStartRunner_Good_FrozenByDefault(t *testing.T) {
assert.True(t, s.frozen, "queue should be frozen by default")
}
func TestStartRunner_Good_AutoStartEnvVar(t *testing.T) {
func TestRunner_StartRunner_Good_AutoStartEnvVar(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
t.Setenv("CORE_AGENT_DISPATCH", "1")
@ -164,14 +164,14 @@ func TestStartRunner_Good_AutoStartEnvVar(t *testing.T) {
// --- DefaultBranch ---
func TestDefaultBranch_Good_DefaultsToMain(t *testing.T) {
func TestPaths_DefaultBranch_Good_DefaultsToMain(t *testing.T) {
// Non-git temp dir — git commands fail, fallback is "main"
dir := t.TempDir()
branch := DefaultBranch(dir)
assert.Equal(t, "main", branch)
}
func TestDefaultBranch_Good_RealGitRepo(t *testing.T) {
func TestPaths_DefaultBranch_Good_RealGitRepo(t *testing.T) {
dir := t.TempDir()
// Init a real git repo with a main branch
require.NoError(t, runGitInit(dir))
@ -183,12 +183,12 @@ func TestDefaultBranch_Good_RealGitRepo(t *testing.T) {
// --- LocalFs ---
func TestLocalFs_Good_NonNil(t *testing.T) {
func TestPaths_LocalFs_Good_NonNil(t *testing.T) {
f := LocalFs()
assert.NotNil(t, f, "LocalFs should return a non-nil *core.Fs")
}
func TestLocalFs_Good_CanRead(t *testing.T) {
func TestPaths_LocalFs_Good_CanRead(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "hello.txt")
require.True(t, fs.Write(path, "hello").OK)

View file

@ -9,11 +9,11 @@ import (
"testing"
)
func TestBaseAgent_Ugly_Empty(t *testing.T) {
func TestQueue_BaseAgent_Ugly_Empty(t *testing.T) {
assert.Equal(t, "", baseAgent(""))
}
func TestBaseAgent_Ugly_MultipleColons(t *testing.T) {
func TestQueue_BaseAgent_Ugly_MultipleColons(t *testing.T) {
// SplitN with N=2 should only split on first colon
assert.Equal(t, "claude", baseAgent("claude:opus:extra"))
}
@ -30,7 +30,7 @@ func TestDispatchConfig_Good_Defaults(t *testing.T) {
assert.Equal(t, 3, cfg.Concurrency["gemini"].Total)
}
func TestCanDispatchAgent_Good_NoConfig(t *testing.T) {
func TestQueue_CanDispatchAgent_Good_NoConfig(t *testing.T) {
// With no running workspaces and default config, should be able to dispatch
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
@ -40,7 +40,7 @@ func TestCanDispatchAgent_Good_NoConfig(t *testing.T) {
assert.True(t, s.canDispatchAgent("gemini"))
}
func TestCanDispatchAgent_Good_UnknownAgent(t *testing.T) {
func TestQueue_CanDispatchAgent_Good_UnknownAgent(t *testing.T) {
// Unknown agent has no limit, so always allowed
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
@ -50,7 +50,7 @@ func TestCanDispatchAgent_Good_UnknownAgent(t *testing.T) {
assert.True(t, s.canDispatchAgent("unknown-agent"))
}
func TestCountRunningByAgent_Good_EmptyWorkspace(t *testing.T) {
func TestQueue_CountRunningByAgent_Good_EmptyWorkspace(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
require.True(t, fs.EnsureDir(filepath.Join(root, "workspace")).OK)
@ -60,7 +60,7 @@ func TestCountRunningByAgent_Good_EmptyWorkspace(t *testing.T) {
assert.Equal(t, 0, s.countRunningByAgent("claude"))
}
func TestCountRunningByAgent_Good_NoRunning(t *testing.T) {
func TestQueue_CountRunningByAgent_Good_NoRunning(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
@ -77,7 +77,7 @@ func TestCountRunningByAgent_Good_NoRunning(t *testing.T) {
assert.Equal(t, 0, s.countRunningByAgent("gemini"))
}
func TestDelayForAgent_Good_NoConfig(t *testing.T) {
func TestQueue_DelayForAgent_Good_NoConfig(t *testing.T) {
// With no config, delay should be 0
t.Setenv("CORE_WORKSPACE", t.TempDir())
s := &PrepSubsystem{codePath: t.TempDir()}

View file

@ -57,7 +57,7 @@ func TestRegister_Good_AgentsConfigLoaded(t *testing.T) {
// --- OnStartup ---
func TestOnStartup_Good_CreatesPokeCh(t *testing.T) {
func TestPrep_OnStartup_Good_CreatesPokeCh(t *testing.T) {
t.Setenv("CORE_WORKSPACE", t.TempDir())
t.Setenv("CORE_AGENT_DISPATCH", "")
@ -73,7 +73,7 @@ func TestOnStartup_Good_CreatesPokeCh(t *testing.T) {
assert.NotNil(t, s.pokeCh, "OnStartup must initialise pokeCh via StartRunner")
}
func TestOnStartup_Good_FrozenByDefault(t *testing.T) {
func TestPrep_OnStartup_Good_FrozenByDefault(t *testing.T) {
t.Setenv("CORE_WORKSPACE", t.TempDir())
t.Setenv("CORE_AGENT_DISPATCH", "")
@ -85,7 +85,7 @@ func TestOnStartup_Good_FrozenByDefault(t *testing.T) {
assert.True(t, s.frozen, "queue must be frozen after OnStartup without CORE_AGENT_DISPATCH=1")
}
func TestOnStartup_Good_NoError(t *testing.T) {
func TestPrep_OnStartup_Good_NoError(t *testing.T) {
t.Setenv("CORE_WORKSPACE", t.TempDir())
t.Setenv("CORE_AGENT_DISPATCH", "")
@ -99,7 +99,7 @@ func TestOnStartup_Good_NoError(t *testing.T) {
// --- OnShutdown ---
func TestOnShutdown_Good_FreezesQueue(t *testing.T) {
func TestPrep_OnShutdown_Good_FreezesQueue(t *testing.T) {
t.Setenv("CORE_WORKSPACE", t.TempDir())
s := &PrepSubsystem{frozen: false}
@ -108,7 +108,7 @@ func TestOnShutdown_Good_FreezesQueue(t *testing.T) {
assert.True(t, s.frozen, "OnShutdown must set frozen=true")
}
func TestOnShutdown_Good_AlreadyFrozen(t *testing.T) {
func TestPrep_OnShutdown_Good_AlreadyFrozen(t *testing.T) {
// Calling OnShutdown twice must be idempotent
s := &PrepSubsystem{frozen: true}
err := s.OnShutdown(context.Background())
@ -116,12 +116,12 @@ func TestOnShutdown_Good_AlreadyFrozen(t *testing.T) {
assert.True(t, s.frozen)
}
func TestOnShutdown_Good_NoError(t *testing.T) {
func TestPrep_OnShutdown_Good_NoError(t *testing.T) {
s := &PrepSubsystem{}
assert.NoError(t, s.OnShutdown(context.Background()))
}
func TestOnShutdown_Ugly_NilCore(t *testing.T) {
func TestPrep_OnShutdown_Ugly_NilCore(t *testing.T) {
// OnShutdown must not panic even if s.core is nil
s := &PrepSubsystem{core: nil, frozen: false}
assert.NotPanics(t, func() {

View file

@ -16,7 +16,7 @@ import (
// --- mcpInitialize ---
func TestMcpInitialize_Good(t *testing.T) {
func TestRemoteClient_McpInitialize_Good(t *testing.T) {
callCount := 0
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
callCount++
@ -46,7 +46,7 @@ func TestMcpInitialize_Good(t *testing.T) {
assert.Equal(t, 2, callCount, "should make init + notification requests")
}
func TestMcpInitialize_Bad_ServerError(t *testing.T) {
func TestRemoteClient_McpInitialize_Bad_ServerError(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(500)
}))
@ -57,7 +57,7 @@ func TestMcpInitialize_Bad_ServerError(t *testing.T) {
assert.Contains(t, err.Error(), "HTTP 500")
}
func TestMcpInitialize_Bad_Unreachable(t *testing.T) {
func TestRemoteClient_McpInitialize_Bad_Unreachable(t *testing.T) {
_, err := mcpInitialize(context.Background(), http.DefaultClient, "http://127.0.0.1:1", "")
assert.Error(t, err)
assert.Contains(t, err.Error(), "request failed")
@ -65,7 +65,7 @@ func TestMcpInitialize_Bad_Unreachable(t *testing.T) {
// --- mcpCall ---
func TestMcpCall_Good(t *testing.T) {
func TestRemoteClient_McpCall_Good(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, "Bearer mytoken", r.Header.Get("Authorization"))
assert.Equal(t, "sess-123", r.Header.Get("Mcp-Session-Id"))
@ -81,7 +81,7 @@ func TestMcpCall_Good(t *testing.T) {
assert.Contains(t, string(result), "hello")
}
func TestMcpCall_Bad_HTTP500(t *testing.T) {
func TestRemoteClient_McpCall_Bad_HTTP500(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(500)
}))
@ -92,7 +92,7 @@ func TestMcpCall_Bad_HTTP500(t *testing.T) {
assert.Contains(t, err.Error(), "HTTP 500")
}
func TestMcpCall_Bad_NoSSEData(t *testing.T) {
func TestRemoteClient_McpCall_Bad_NoSSEData(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/event-stream")
fmt.Fprintf(w, "event: ping\n\n") // No data: line
@ -106,7 +106,7 @@ func TestMcpCall_Bad_NoSSEData(t *testing.T) {
// --- setHeaders ---
func TestSetHeaders_Good_All(t *testing.T) {
func TestRemoteClient_SetHeaders_Good_All(t *testing.T) {
req, _ := http.NewRequest("POST", "http://example.com", nil)
setHeaders(req, "my-token", "my-session")
@ -116,7 +116,7 @@ func TestSetHeaders_Good_All(t *testing.T) {
assert.Equal(t, "my-session", req.Header.Get("Mcp-Session-Id"))
}
func TestSetHeaders_Good_NoToken(t *testing.T) {
func TestRemoteClient_SetHeaders_Good_NoToken(t *testing.T) {
req, _ := http.NewRequest("POST", "http://example.com", nil)
setHeaders(req, "", "")
@ -126,7 +126,7 @@ func TestSetHeaders_Good_NoToken(t *testing.T) {
// --- readSSEData ---
func TestReadSSEData_Good(t *testing.T) {
func TestRemoteClient_ReadSSEData_Good(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/event-stream")
fmt.Fprintf(w, "event: message\ndata: {\"key\":\"value\"}\n\n")
@ -142,7 +142,7 @@ func TestReadSSEData_Good(t *testing.T) {
assert.Equal(t, `{"key":"value"}`, string(data))
}
func TestReadSSEData_Bad_NoData(t *testing.T) {
func TestRemoteClient_ReadSSEData_Bad_NoData(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "event: ping\n\n")
}))
@ -159,7 +159,7 @@ func TestReadSSEData_Bad_NoData(t *testing.T) {
// --- drainSSE ---
func TestDrainSSE_Good(t *testing.T) {
func TestRemoteClient_DrainSSE_Good(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "data: line1\ndata: line2\n\n")
}))

View file

@ -10,34 +10,34 @@ import (
// --- resolveHost (extended — base cases are in paths_test.go) ---
func TestResolveHost_Good_CaseInsensitive(t *testing.T) {
func TestRemote_ResolveHost_Good_CaseInsensitive(t *testing.T) {
assert.Equal(t, "10.69.69.165:9101", resolveHost("Charon"))
assert.Equal(t, "10.69.69.165:9101", resolveHost("CHARON"))
assert.Equal(t, "127.0.0.1:9101", resolveHost("Cladius"))
assert.Equal(t, "127.0.0.1:9101", resolveHost("LOCAL"))
}
func TestResolveHost_Good_CustomHost(t *testing.T) {
func TestRemote_ResolveHost_Good_CustomHost(t *testing.T) {
assert.Equal(t, "my-server:9101", resolveHost("my-server"))
assert.Equal(t, "192.168.1.100:8080", resolveHost("192.168.1.100:8080"))
}
// --- remoteToken ---
func TestRemoteToken_Good_FromEnv(t *testing.T) {
func TestRemote_RemoteToken_Good_FromEnv(t *testing.T) {
t.Setenv("AGENT_TOKEN_CHARON", "env-token-123")
token := remoteToken("CHARON")
assert.Equal(t, "env-token-123", token)
}
func TestRemoteToken_Good_FallbackMCPAuth(t *testing.T) {
func TestRemote_RemoteToken_Good_FallbackMCPAuth(t *testing.T) {
t.Setenv("AGENT_TOKEN_TOKENTEST", "")
t.Setenv("MCP_AUTH_TOKEN", "mcp-fallback")
token := remoteToken("tokentest")
assert.Equal(t, "mcp-fallback", token)
}
func TestRemoteToken_Good_EnvPrecedence(t *testing.T) {
func TestRemote_RemoteToken_Good_EnvPrecedence(t *testing.T) {
t.Setenv("AGENT_TOKEN_PRIO", "specific-token")
t.Setenv("MCP_AUTH_TOKEN", "generic-token")
token := remoteToken("PRIO")

View file

@ -11,7 +11,7 @@ import (
// --- renderPlan ---
func TestRenderPlan_Good_BugFix(t *testing.T) {
func TestPrep_RenderPlan_Good_BugFix(t *testing.T) {
s := &PrepSubsystem{
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
@ -26,7 +26,7 @@ func TestRenderPlan_Good_BugFix(t *testing.T) {
assert.Contains(t, result, "Investigation")
}
func TestRenderPlan_Good_WithVariables(t *testing.T) {
func TestPrep_RenderPlan_Good_WithVariables(t *testing.T) {
s := &PrepSubsystem{
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
@ -42,7 +42,7 @@ func TestRenderPlan_Good_WithVariables(t *testing.T) {
assert.Contains(t, result, "Fix login")
}
func TestRenderPlan_Bad_UnknownTemplate(t *testing.T) {
func TestPrep_RenderPlan_Bad_UnknownTemplate(t *testing.T) {
s := &PrepSubsystem{
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
@ -51,7 +51,7 @@ func TestRenderPlan_Bad_UnknownTemplate(t *testing.T) {
assert.Empty(t, result)
}
func TestRenderPlan_Good_NoTask(t *testing.T) {
func TestPrep_RenderPlan_Good_NoTask(t *testing.T) {
s := &PrepSubsystem{
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
@ -63,7 +63,7 @@ func TestRenderPlan_Good_NoTask(t *testing.T) {
assert.NotContains(t, result, "**Task:**")
}
func TestRenderPlan_Good_NewFeature(t *testing.T) {
func TestPrep_RenderPlan_Good_NewFeature(t *testing.T) {
s := &PrepSubsystem{
backoff: make(map[string]time.Time),
failCount: make(map[string]int),

View file

@ -17,7 +17,7 @@ import (
// --- buildReviewCommand ---
func TestBuildReviewCommand_Good_CodeRabbit(t *testing.T) {
func TestReviewQueue_BuildReviewCommand_Good_CodeRabbit(t *testing.T) {
s := &PrepSubsystem{
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
@ -30,7 +30,7 @@ func TestBuildReviewCommand_Good_CodeRabbit(t *testing.T) {
assert.Contains(t, cmd.Args, "github/main")
}
func TestBuildReviewCommand_Good_Codex(t *testing.T) {
func TestReviewQueue_BuildReviewCommand_Good_Codex(t *testing.T) {
s := &PrepSubsystem{
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
@ -42,7 +42,7 @@ func TestBuildReviewCommand_Good_Codex(t *testing.T) {
assert.Equal(t, "/tmp/repo", cmd.Dir)
}
func TestBuildReviewCommand_Good_DefaultReviewer(t *testing.T) {
func TestReviewQueue_BuildReviewCommand_Good_DefaultReviewer(t *testing.T) {
s := &PrepSubsystem{
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
@ -86,7 +86,7 @@ func TestSaveLoadRateLimitState_Good_Roundtrip(t *testing.T) {
// --- storeReviewOutput ---
func TestStoreReviewOutput_Good(t *testing.T) {
func TestReviewQueue_StoreReviewOutput_Good(t *testing.T) {
// storeReviewOutput uses core.Env("DIR_HOME") so we can't fully control the path
// but we can verify it doesn't panic
s := &PrepSubsystem{
@ -159,7 +159,7 @@ func TestStatus_Good_FilteredByStatus(t *testing.T) {
// --- handlers helpers (resolveWorkspace, findWorkspaceByPR) ---
func TestResolveWorkspace_Good_Exists(t *testing.T) {
func TestHandlers_ResolveWorkspace_Good_Exists(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")
@ -172,7 +172,7 @@ func TestResolveWorkspace_Good_Exists(t *testing.T) {
assert.Equal(t, ws, result)
}
func TestResolveWorkspace_Bad_NotExists(t *testing.T) {
func TestHandlers_ResolveWorkspace_Bad_NotExists(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
@ -180,7 +180,7 @@ func TestResolveWorkspace_Bad_NotExists(t *testing.T) {
assert.Empty(t, result)
}
func TestFindWorkspaceByPR_Good_Match(t *testing.T) {
func TestHandlers_FindWorkspaceByPR_Good_Match(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")
@ -195,7 +195,7 @@ func TestFindWorkspaceByPR_Good_Match(t *testing.T) {
assert.Equal(t, ws, result)
}
func TestFindWorkspaceByPR_Good_DeepLayout(t *testing.T) {
func TestHandlers_FindWorkspaceByPR_Good_DeepLayout(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")

View file

@ -11,7 +11,7 @@ import (
// --- countFindings (extended beyond paths_test.go) ---
func TestCountFindings_Good_BulletFindings(t *testing.T) {
func TestReviewQueue_CountFindings_Good_BulletFindings(t *testing.T) {
output := `Review:
- Missing error check in handler.go:42
- Unused import in config.go
@ -19,18 +19,18 @@ func TestCountFindings_Good_BulletFindings(t *testing.T) {
assert.Equal(t, 3, countFindings(output))
}
func TestCountFindings_Good_IssueKeyword(t *testing.T) {
func TestReviewQueue_CountFindings_Good_IssueKeyword(t *testing.T) {
output := `Line 10: Issue: variable shadowing
Line 25: Finding: unchecked return value`
assert.Equal(t, 2, countFindings(output))
}
func TestCountFindings_Good_DefaultOneIfNotClean(t *testing.T) {
func TestReviewQueue_CountFindings_Good_DefaultOneIfNotClean(t *testing.T) {
output := "Some output without markers but also not explicitly clean"
assert.Equal(t, 1, countFindings(output))
}
func TestCountFindings_Good_MixedContent(t *testing.T) {
func TestReviewQueue_CountFindings_Good_MixedContent(t *testing.T) {
output := `Summary of review:
The code is generally well structured.
- Missing nil check
@ -41,12 +41,12 @@ Some commentary here
// --- parseRetryAfter (extended) ---
func TestParseRetryAfter_Good_SingleMinuteAndSeconds(t *testing.T) {
func TestReviewQueue_ParseRetryAfter_Good_SingleMinuteAndSeconds(t *testing.T) {
d := parseRetryAfter("try after 1 minute and 30 seconds")
assert.Equal(t, 1*time.Minute+30*time.Second, d)
}
func TestParseRetryAfter_Bad_EmptyMessage(t *testing.T) {
func TestReviewQueue_ParseRetryAfter_Bad_EmptyMessage(t *testing.T) {
d := parseRetryAfter("")
assert.Equal(t, 5*time.Minute, d)
}

View file

@ -184,7 +184,7 @@ func TestScan_Bad_NoToken(t *testing.T) {
// --- listRepoIssues ---
func TestListRepoIssues_Good_ReturnsIssues(t *testing.T) {
func TestScan_ListRepoIssues_Good_ReturnsIssues(t *testing.T) {
srv := mockScanServer(t)
s := &PrepSubsystem{
forgeURL: srv.URL,
@ -202,7 +202,7 @@ func TestListRepoIssues_Good_ReturnsIssues(t *testing.T) {
assert.Contains(t, issues[0].Labels, "agentic")
}
func TestListRepoIssues_Good_EmptyResult(t *testing.T) {
func TestScan_ListRepoIssues_Good_EmptyResult(t *testing.T) {
srv := mockScanServer(t)
s := &PrepSubsystem{
forgeURL: srv.URL,
@ -217,7 +217,7 @@ func TestListRepoIssues_Good_EmptyResult(t *testing.T) {
assert.Empty(t, issues)
}
func TestListRepoIssues_Good_AssigneeExtracted(t *testing.T) {
func TestScan_ListRepoIssues_Good_AssigneeExtracted(t *testing.T) {
srv := mockScanServer(t)
s := &PrepSubsystem{
forgeURL: srv.URL,
@ -234,7 +234,7 @@ func TestListRepoIssues_Good_AssigneeExtracted(t *testing.T) {
assert.Equal(t, "virgil", issues[1].Assignee)
}
func TestListRepoIssues_Bad_ServerError(t *testing.T) {
func TestScan_ListRepoIssues_Bad_ServerError(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(500)
}))
@ -252,7 +252,7 @@ func TestListRepoIssues_Bad_ServerError(t *testing.T) {
assert.Error(t, err)
}
func TestListRepoIssues_Good_URLRewrite(t *testing.T) {
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

@ -140,7 +140,7 @@ func TestStatus_Good_CorruptStatusFile(t *testing.T) {
// --- shutdown tools ---
func TestDispatchStart_Good(t *testing.T) {
func TestShutdown_DispatchStart_Good(t *testing.T) {
s := &PrepSubsystem{
frozen: true,
pokeCh: make(chan struct{}, 1),
@ -155,7 +155,7 @@ func TestDispatchStart_Good(t *testing.T) {
assert.Contains(t, out.Message, "started")
}
func TestShutdownGraceful_Good(t *testing.T) {
func TestShutdown_ShutdownGraceful_Good(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
@ -172,7 +172,7 @@ func TestShutdownGraceful_Good(t *testing.T) {
assert.Contains(t, out.Message, "frozen")
}
func TestShutdownNow_Good_EmptyWorkspace(t *testing.T) {
func TestShutdown_ShutdownNow_Good_EmptyWorkspace(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
require.True(t, fs.EnsureDir(filepath.Join(root, "workspace")).OK)
@ -190,7 +190,7 @@ func TestShutdownNow_Good_EmptyWorkspace(t *testing.T) {
assert.Contains(t, out.Message, "killed 0")
}
func TestShutdownNow_Good_ClearsQueued(t *testing.T) {
func TestShutdown_ShutdownNow_Good_ClearsQueued(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")
@ -227,7 +227,7 @@ func TestShutdownNow_Good_ClearsQueued(t *testing.T) {
// --- brainRecall ---
func TestBrainRecall_Good_Success(t *testing.T) {
func TestPrep_BrainRecall_Good_Success(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, "POST", r.Method)
assert.Contains(t, r.URL.Path, "/v1/brain/recall")
@ -255,7 +255,7 @@ func TestBrainRecall_Good_Success(t *testing.T) {
assert.Contains(t, result, "Use E() for errors")
}
func TestBrainRecall_Good_NoMemories(t *testing.T) {
func TestPrep_BrainRecall_Good_NoMemories(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(map[string]any{
"memories": []map[string]any{},
@ -276,7 +276,7 @@ func TestBrainRecall_Good_NoMemories(t *testing.T) {
assert.Empty(t, result)
}
func TestBrainRecall_Bad_NoBrainKey(t *testing.T) {
func TestPrep_BrainRecall_Bad_NoBrainKey(t *testing.T) {
s := &PrepSubsystem{
brainKey: "",
backoff: make(map[string]time.Time),
@ -288,7 +288,7 @@ func TestBrainRecall_Bad_NoBrainKey(t *testing.T) {
assert.Empty(t, result)
}
func TestBrainRecall_Bad_ServerError(t *testing.T) {
func TestPrep_BrainRecall_Bad_ServerError(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(500)
}))
@ -309,7 +309,7 @@ func TestBrainRecall_Bad_ServerError(t *testing.T) {
// --- prepWorkspace ---
func TestPrepWorkspace_Bad_NoRepo(t *testing.T) {
func TestPrep_PrepWorkspace_Bad_NoRepo(t *testing.T) {
s := &PrepSubsystem{
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
@ -320,7 +320,7 @@ func TestPrepWorkspace_Bad_NoRepo(t *testing.T) {
assert.Contains(t, err.Error(), "repo is required")
}
func TestPrepWorkspace_Bad_NoIdentifier(t *testing.T) {
func TestPrep_PrepWorkspace_Bad_NoIdentifier(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
@ -337,7 +337,7 @@ func TestPrepWorkspace_Bad_NoIdentifier(t *testing.T) {
assert.Contains(t, err.Error(), "one of issue, pr, branch, or tag is required")
}
func TestPrepWorkspace_Bad_InvalidRepoName(t *testing.T) {
func TestPrep_PrepWorkspace_Bad_InvalidRepoName(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
@ -357,7 +357,7 @@ func TestPrepWorkspace_Bad_InvalidRepoName(t *testing.T) {
// --- listPRs ---
func TestListPRs_Good_SpecificRepo(t *testing.T) {
func TestPr_ListPRs_Good_SpecificRepo(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Return mock PRs
json.NewEncoder(w).Encode([]map[string]any{
@ -399,7 +399,7 @@ func TestListPRs_Good_SpecificRepo(t *testing.T) {
// --- Poke ---
func TestPoke_Good_SendsSignal(t *testing.T) {
func TestRunner_Poke_Good_SendsSignal(t *testing.T) {
s := &PrepSubsystem{
pokeCh: make(chan struct{}, 1),
backoff: make(map[string]time.Time),
@ -416,7 +416,7 @@ func TestPoke_Good_SendsSignal(t *testing.T) {
}
}
func TestPoke_Good_NonBlocking(t *testing.T) {
func TestRunner_Poke_Good_NonBlocking(t *testing.T) {
s := &PrepSubsystem{
pokeCh: make(chan struct{}, 1),
backoff: make(map[string]time.Time),
@ -432,7 +432,7 @@ func TestPoke_Good_NonBlocking(t *testing.T) {
})
}
func TestPoke_Bad_NilChannel(t *testing.T) {
func TestRunner_Poke_Bad_NilChannel(t *testing.T) {
s := &PrepSubsystem{
pokeCh: nil,
backoff: make(map[string]time.Time),
@ -504,7 +504,7 @@ func TestWriteReadStatus_Good_AllFields(t *testing.T) {
// --- OnStartup / OnShutdown ---
func TestOnShutdown_Good(t *testing.T) {
func TestPrep_OnShutdown_Good(t *testing.T) {
s := &PrepSubsystem{
frozen: false,
backoff: make(map[string]time.Time),
@ -518,7 +518,7 @@ func TestOnShutdown_Good(t *testing.T) {
// --- drainQueue ---
func TestDrainQueue_Good_FrozenDoesNothing(t *testing.T) {
func TestQueue_DrainQueue_Good_FrozenDoesNothing(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
@ -536,7 +536,7 @@ func TestDrainQueue_Good_FrozenDoesNothing(t *testing.T) {
// --- shutdownNow (Ugly — deep layout with queued status) ---
func TestShutdown_ShutdownNow_Ugly(t *testing.T) {
func TestPrep_Shutdown_ShutdownNow_Ugly(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
wsRoot := filepath.Join(root, "workspace")

View file

@ -14,7 +14,7 @@ import (
// --- ReadStatus ---
func TestReadStatus_Good_AllFields(t *testing.T) {
func TestStatus_ReadStatus_Good_AllFields(t *testing.T) {
dir := t.TempDir()
now := time.Now().Truncate(time.Second)
@ -51,13 +51,13 @@ func TestReadStatus_Good_AllFields(t *testing.T) {
assert.Equal(t, original.Runs, st.Runs)
}
func TestReadStatus_Bad_MissingFile(t *testing.T) {
func TestStatus_ReadStatus_Bad_MissingFile(t *testing.T) {
dir := t.TempDir()
_, err := ReadStatus(dir)
assert.Error(t, err, "missing status.json must return an error")
}
func TestReadStatus_Bad_CorruptJSON(t *testing.T) {
func TestStatus_ReadStatus_Bad_CorruptJSON(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "status.json"), `{"status": "running", broken`).OK)
@ -65,7 +65,7 @@ func TestReadStatus_Bad_CorruptJSON(t *testing.T) {
assert.Error(t, err, "corrupt JSON must return an error")
}
func TestReadStatus_Bad_NullJSON(t *testing.T) {
func TestStatus_ReadStatus_Bad_NullJSON(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "status.json"), "null").OK)
@ -77,7 +77,7 @@ func TestReadStatus_Bad_NullJSON(t *testing.T) {
// --- writeStatus ---
func TestWriteStatus_Good_WritesAndReadsBack(t *testing.T) {
func TestStatus_WriteStatus_Good_WritesAndReadsBack(t *testing.T) {
dir := t.TempDir()
st := &WorkspaceStatus{
Status: "queued",
@ -98,7 +98,7 @@ func TestWriteStatus_Good_WritesAndReadsBack(t *testing.T) {
assert.Equal(t, "improve logging", read.Task)
}
func TestWriteStatus_Good_SetsUpdatedAt(t *testing.T) {
func TestStatus_WriteStatus_Good_SetsUpdatedAt(t *testing.T) {
dir := t.TempDir()
before := time.Now().Add(-time.Millisecond)
@ -109,7 +109,7 @@ func TestWriteStatus_Good_SetsUpdatedAt(t *testing.T) {
assert.True(t, st.UpdatedAt.After(before), "writeStatus must set UpdatedAt to a recent time")
}
func TestWriteStatus_Good_Overwrites(t *testing.T) {
func TestStatus_WriteStatus_Good_Overwrites(t *testing.T) {
dir := t.TempDir()
require.NoError(t, writeStatus(dir, &WorkspaceStatus{Status: "running", Agent: "gemini"}))

View file

@ -11,7 +11,7 @@ import (
"time"
)
func TestWriteStatus_Good(t *testing.T) {
func TestStatus_WriteStatus_Good(t *testing.T) {
dir := t.TempDir()
status := &WorkspaceStatus{
Status: "running",
@ -43,7 +43,7 @@ func TestWriteStatus_Good(t *testing.T) {
assert.False(t, read.UpdatedAt.IsZero(), "UpdatedAt should be set by writeStatus")
}
func TestWriteStatus_Good_UpdatesTimestamp(t *testing.T) {
func TestStatus_WriteStatus_Good_UpdatesTimestamp(t *testing.T) {
dir := t.TempDir()
before := time.Now().Add(-time.Second)
@ -58,7 +58,7 @@ func TestWriteStatus_Good_UpdatesTimestamp(t *testing.T) {
assert.True(t, status.UpdatedAt.After(before), "UpdatedAt should be after the start time")
}
func TestReadStatus_Good(t *testing.T) {
func TestStatus_ReadStatus_Good(t *testing.T) {
dir := t.TempDir()
status := &WorkspaceStatus{
@ -89,13 +89,13 @@ func TestReadStatus_Good(t *testing.T) {
assert.Equal(t, "https://forge.lthn.ai/core/go-log/pulls/5", read.PRURL)
}
func TestReadStatus_Bad_NoFile(t *testing.T) {
func TestStatus_ReadStatus_Bad_NoFile(t *testing.T) {
dir := t.TempDir()
_, err := ReadStatus(dir)
assert.Error(t, err)
}
func TestReadStatus_Bad_InvalidJSON(t *testing.T) {
func TestStatus_ReadStatus_Bad_InvalidJSON(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "status.json"), "not json{").OK)
@ -103,7 +103,7 @@ func TestReadStatus_Bad_InvalidJSON(t *testing.T) {
assert.Error(t, err)
}
func TestReadStatus_Good_BlockedWithQuestion(t *testing.T) {
func TestStatus_ReadStatus_Good_BlockedWithQuestion(t *testing.T) {
dir := t.TempDir()
status := &WorkspaceStatus{
@ -157,7 +157,7 @@ func TestWriteReadStatus_Good_Roundtrip(t *testing.T) {
assert.Equal(t, original.Runs, read.Runs)
}
func TestWriteStatus_Good_OverwriteExisting(t *testing.T) {
func TestStatus_WriteStatus_Good_OverwriteExisting(t *testing.T) {
dir := t.TempDir()
first := &WorkspaceStatus{Status: "running", Agent: "gemini"}
@ -173,7 +173,7 @@ func TestWriteStatus_Good_OverwriteExisting(t *testing.T) {
assert.Equal(t, "completed", read.Status)
}
func TestReadStatus_Ugly_EmptyFile(t *testing.T) {
func TestStatus_ReadStatus_Ugly_EmptyFile(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "status.json"), "").OK)

View file

@ -19,7 +19,7 @@ import (
// --- commentOnIssue ---
func TestCommentOnIssue_Good_PostsCommentOnPR(t *testing.T) {
func TestPr_CommentOnIssue_Good_PostsCommentOnPR(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, "POST", r.Method)
assert.Contains(t, r.URL.Path, "/issues/7/comments")
@ -46,7 +46,7 @@ func TestCommentOnIssue_Good_PostsCommentOnPR(t *testing.T) {
// --- autoVerifyAndMerge integration (extended) ---
func TestAutoVerifyAndMerge_Good_FullPipeline(t *testing.T) {
func TestVerify_AutoVerifyAndMerge_Good_FullPipeline(t *testing.T) {
// Mock Forge API for merge + comment
mergeOK := false
commented := false
@ -101,7 +101,7 @@ func TestAutoVerifyAndMerge_Good_FullPipeline(t *testing.T) {
// --- attemptVerifyAndMerge ---
func TestAttemptVerifyAndMerge_Good_TestsPassMergeSucceeds(t *testing.T) {
func TestVerify_AttemptVerifyAndMerge_Good_TestsPassMergeSucceeds(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/api/v1/repos/core/test/pulls/1/merge" {
w.WriteHeader(200)
@ -126,7 +126,7 @@ func TestAttemptVerifyAndMerge_Good_TestsPassMergeSucceeds(t *testing.T) {
assert.Equal(t, mergeSuccess, result)
}
func TestAttemptVerifyAndMerge_Bad_MergeFails(t *testing.T) {
func TestVerify_AttemptVerifyAndMerge_Bad_MergeFails(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/api/v1/repos/core/test/pulls/1/merge" {
w.WriteHeader(409)

View file

@ -18,7 +18,7 @@ import (
// --- forgeMergePR ---
func TestForgeMergePR_Good_Success(t *testing.T) {
func TestVerify_ForgeMergePR_Good_Success(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, "POST", r.Method)
assert.Contains(t, r.URL.Path, "/pulls/42/merge")
@ -45,7 +45,7 @@ func TestForgeMergePR_Good_Success(t *testing.T) {
assert.NoError(t, err)
}
func TestForgeMergePR_Good_204Response(t *testing.T) {
func TestVerify_ForgeMergePR_Good_204Response(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(204) // No Content — also valid success
}))
@ -63,7 +63,7 @@ func TestForgeMergePR_Good_204Response(t *testing.T) {
assert.NoError(t, err)
}
func TestForgeMergePR_Bad_ConflictResponse(t *testing.T) {
func TestVerify_ForgeMergePR_Bad_ConflictResponse(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(409)
json.NewEncoder(w).Encode(map[string]any{
@ -86,7 +86,7 @@ func TestForgeMergePR_Bad_ConflictResponse(t *testing.T) {
assert.Contains(t, err.Error(), "merge conflict")
}
func TestForgeMergePR_Bad_ServerError(t *testing.T) {
func TestVerify_ForgeMergePR_Bad_ServerError(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(500)
json.NewEncoder(w).Encode(map[string]any{
@ -108,7 +108,7 @@ func TestForgeMergePR_Bad_ServerError(t *testing.T) {
assert.Contains(t, err.Error(), "500")
}
func TestForgeMergePR_Bad_NetworkError(t *testing.T) {
func TestVerify_ForgeMergePR_Bad_NetworkError(t *testing.T) {
srv := httptest.NewServer(http.NotFoundHandler())
srv.Close() // close immediately to cause connection error
@ -126,26 +126,26 @@ func TestForgeMergePR_Bad_NetworkError(t *testing.T) {
// --- extractPRNumber (additional _Ugly cases) ---
func TestExtractPRNumber_Ugly_DoubleSlashEnd(t *testing.T) {
func TestVerify_ExtractPRNumber_Ugly_DoubleSlashEnd(t *testing.T) {
assert.Equal(t, 0, extractPRNumber("https://forge.lthn.ai/core/go-io/pulls/42/"))
}
func TestExtractPRNumber_Ugly_VeryLargeNumber(t *testing.T) {
func TestVerify_ExtractPRNumber_Ugly_VeryLargeNumber(t *testing.T) {
assert.Equal(t, 999999, extractPRNumber("https://forge.lthn.ai/core/go-io/pulls/999999"))
}
func TestExtractPRNumber_Ugly_NegativeNumber(t *testing.T) {
func TestVerify_ExtractPRNumber_Ugly_NegativeNumber(t *testing.T) {
// atoi of "-5" is -5, parseInt wraps atoi
assert.Equal(t, -5, extractPRNumber("https://forge.lthn.ai/core/go-io/pulls/-5"))
}
func TestExtractPRNumber_Ugly_ZeroExplicit(t *testing.T) {
func TestVerify_ExtractPRNumber_Ugly_ZeroExplicit(t *testing.T) {
assert.Equal(t, 0, extractPRNumber("https://forge.lthn.ai/core/go-io/pulls/0"))
}
// --- ensureLabel ---
func TestEnsureLabel_Good_CreatesLabel(t *testing.T) {
func TestVerify_EnsureLabel_Good_CreatesLabel(t *testing.T) {
called := false
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, "POST", r.Method)
@ -173,7 +173,7 @@ func TestEnsureLabel_Good_CreatesLabel(t *testing.T) {
assert.True(t, called)
}
func TestEnsureLabel_Bad_NetworkError(t *testing.T) {
func TestVerify_EnsureLabel_Bad_NetworkError(t *testing.T) {
srv := httptest.NewServer(http.NotFoundHandler())
srv.Close()
@ -193,7 +193,7 @@ func TestEnsureLabel_Bad_NetworkError(t *testing.T) {
// --- getLabelID ---
func TestGetLabelID_Good_Found(t *testing.T) {
func TestVerify_GetLabelID_Good_Found(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode([]map[string]any{
{"id": 10, "name": "agentic"},
@ -214,7 +214,7 @@ func TestGetLabelID_Good_Found(t *testing.T) {
assert.Equal(t, 20, id)
}
func TestGetLabelID_Bad_NotFound(t *testing.T) {
func TestVerify_GetLabelID_Bad_NotFound(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode([]map[string]any{
{"id": 10, "name": "agentic"},
@ -234,7 +234,7 @@ func TestGetLabelID_Bad_NotFound(t *testing.T) {
assert.Equal(t, 0, id)
}
func TestGetLabelID_Bad_NetworkError(t *testing.T) {
func TestVerify_GetLabelID_Bad_NetworkError(t *testing.T) {
srv := httptest.NewServer(http.NotFoundHandler())
srv.Close()
@ -252,7 +252,7 @@ func TestGetLabelID_Bad_NetworkError(t *testing.T) {
// --- runVerification ---
func TestRunVerification_Good_NoProjectFile(t *testing.T) {
func TestVerify_RunVerification_Good_NoProjectFile(t *testing.T) {
dir := t.TempDir() // No go.mod, composer.json, or package.json
s := &PrepSubsystem{
@ -265,7 +265,7 @@ func TestRunVerification_Good_NoProjectFile(t *testing.T) {
assert.Equal(t, "none", result.testCmd)
}
func TestRunVerification_Good_GoProject(t *testing.T) {
func TestVerify_RunVerification_Good_GoProject(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "go.mod"), "module test").OK)
@ -279,7 +279,7 @@ func TestRunVerification_Good_GoProject(t *testing.T) {
// It will fail because there's no real Go code, but we test the detection path
}
func TestRunVerification_Good_PHPProject(t *testing.T) {
func TestVerify_RunVerification_Good_PHPProject(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "composer.json"), `{"require":{}}`).OK)
@ -293,7 +293,7 @@ func TestRunVerification_Good_PHPProject(t *testing.T) {
assert.Contains(t, []string{"composer test", "vendor/bin/pest", "none"}, result.testCmd)
}
func TestRunVerification_Good_NodeProject(t *testing.T) {
func TestVerify_RunVerification_Good_NodeProject(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "package.json"), `{"scripts":{"test":"echo ok"}}`).OK)
@ -306,7 +306,7 @@ func TestRunVerification_Good_NodeProject(t *testing.T) {
assert.Equal(t, "npm test", result.testCmd)
}
func TestRunVerification_Good_NodeNoTestScript(t *testing.T) {
func TestVerify_RunVerification_Good_NodeNoTestScript(t *testing.T) {
dir := t.TempDir()
require.True(t, fs.Write(filepath.Join(dir, "package.json"), `{"scripts":{}}`).OK)
@ -322,7 +322,7 @@ func TestRunVerification_Good_NodeNoTestScript(t *testing.T) {
// --- fileExists ---
func TestFileExists_Good_Exists(t *testing.T) {
func TestVerify_FileExists_Good_Exists(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "test.txt")
require.True(t, fs.Write(path, "hello").OK)
@ -330,18 +330,18 @@ func TestFileExists_Good_Exists(t *testing.T) {
assert.True(t, fileExists(path))
}
func TestFileExists_Bad_NotExists(t *testing.T) {
func TestVerify_FileExists_Bad_NotExists(t *testing.T) {
assert.False(t, fileExists("/nonexistent/path/file.txt"))
}
func TestFileExists_Bad_IsDirectory(t *testing.T) {
func TestVerify_FileExists_Bad_IsDirectory(t *testing.T) {
dir := t.TempDir()
assert.False(t, fileExists(dir)) // directories are not files
}
// --- autoVerifyAndMerge ---
func TestAutoVerifyAndMerge_Bad_NoStatus(t *testing.T) {
func TestVerify_AutoVerifyAndMerge_Bad_NoStatus(t *testing.T) {
dir := t.TempDir()
s := &PrepSubsystem{
backoff: make(map[string]time.Time),
@ -353,7 +353,7 @@ func TestAutoVerifyAndMerge_Bad_NoStatus(t *testing.T) {
})
}
func TestAutoVerifyAndMerge_Bad_NoPRURL(t *testing.T) {
func TestVerify_AutoVerifyAndMerge_Bad_NoPRURL(t *testing.T) {
dir := t.TempDir()
require.NoError(t, writeStatus(dir, &WorkspaceStatus{
Status: "completed",
@ -372,7 +372,7 @@ func TestAutoVerifyAndMerge_Bad_NoPRURL(t *testing.T) {
})
}
func TestAutoVerifyAndMerge_Bad_EmptyRepo(t *testing.T) {
func TestVerify_AutoVerifyAndMerge_Bad_EmptyRepo(t *testing.T) {
dir := t.TempDir()
require.NoError(t, writeStatus(dir, &WorkspaceStatus{
Status: "completed",
@ -389,7 +389,7 @@ func TestAutoVerifyAndMerge_Bad_EmptyRepo(t *testing.T) {
})
}
func TestAutoVerifyAndMerge_Bad_InvalidPRURL(t *testing.T) {
func TestVerify_AutoVerifyAndMerge_Bad_InvalidPRURL(t *testing.T) {
dir := t.TempDir()
require.NoError(t, writeStatus(dir, &WorkspaceStatus{
Status: "completed",
@ -411,7 +411,7 @@ func TestAutoVerifyAndMerge_Bad_InvalidPRURL(t *testing.T) {
// --- flagForReview ---
func TestFlagForReview_Good_AddsLabel(t *testing.T) {
func TestVerify_FlagForReview_Good_AddsLabel(t *testing.T) {
labelCalled := false
commentCalled := false
@ -454,7 +454,7 @@ func TestFlagForReview_Good_AddsLabel(t *testing.T) {
assert.True(t, commentCalled)
}
func TestFlagForReview_Good_MergeConflictMessage(t *testing.T) {
func TestVerify_FlagForReview_Good_MergeConflictMessage(t *testing.T) {
var commentBody string
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@ -488,23 +488,23 @@ func TestFlagForReview_Good_MergeConflictMessage(t *testing.T) {
// --- truncate ---
func TestTruncate_Good_Short(t *testing.T) {
func TestAutoPr_Truncate_Good_Short(t *testing.T) {
assert.Equal(t, "hello", truncate("hello", 10))
}
func TestTruncate_Good_Exact(t *testing.T) {
func TestAutoPr_Truncate_Good_Exact(t *testing.T) {
assert.Equal(t, "hello", truncate("hello", 5))
}
func TestTruncate_Good_Long(t *testing.T) {
func TestAutoPr_Truncate_Good_Long(t *testing.T) {
assert.Equal(t, "hel...", truncate("hello world", 3))
}
func TestTruncate_Bad_ZeroMax(t *testing.T) {
func TestAutoPr_Truncate_Bad_ZeroMax(t *testing.T) {
assert.Equal(t, "...", truncate("hello", 0))
}
func TestTruncate_Ugly_EmptyString(t *testing.T) {
func TestAutoPr_Truncate_Ugly_EmptyString(t *testing.T) {
assert.Equal(t, "", truncate("", 10))
}

View file

@ -14,7 +14,7 @@ import (
// --- resolveWorkspaceDir ---
func TestResolveWorkspaceDir_Good_RelativeName(t *testing.T) {
func TestWatch_ResolveWorkspaceDir_Good_RelativeName(t *testing.T) {
s := &PrepSubsystem{
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
@ -24,7 +24,7 @@ func TestResolveWorkspaceDir_Good_RelativeName(t *testing.T) {
assert.True(t, filepath.IsAbs(dir))
}
func TestResolveWorkspaceDir_Good_AbsolutePath(t *testing.T) {
func TestWatch_ResolveWorkspaceDir_Good_AbsolutePath(t *testing.T) {
s := &PrepSubsystem{
backoff: make(map[string]time.Time),
failCount: make(map[string]int),
@ -35,7 +35,7 @@ func TestResolveWorkspaceDir_Good_AbsolutePath(t *testing.T) {
// --- findActiveWorkspaces ---
func TestFindActiveWorkspaces_Good_WithActive(t *testing.T) {
func TestWatch_FindActiveWorkspaces_Good_WithActive(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)
@ -69,7 +69,7 @@ func TestFindActiveWorkspaces_Good_WithActive(t *testing.T) {
assert.NotContains(t, active, "ws-done")
}
func TestFindActiveWorkspaces_Good_Empty(t *testing.T) {
func TestWatch_FindActiveWorkspaces_Good_Empty(t *testing.T) {
root := t.TempDir()
t.Setenv("CORE_WORKSPACE", root)