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:
parent
8b46e15d24
commit
97d06c1e90
31 changed files with 478 additions and 478 deletions
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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"))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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" +
|
||||
|
|
|
|||
|
|
@ -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("///"))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"))
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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" {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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()}
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}))
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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{
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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"}))
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue