test: add coverage for suggest and jsonrpc packages#199
Conversation
Boost suggest from 68% to 83% and jsonrpc from 69% to 90%. suggest package: - grader_docs_test.go: GraderSummaries format, LoadGraderDocs with fstest.MapFS (nil, empty, mixed valid/invalid, whitespace trimming) - prompt_test.go: renderSelectionPrompt, renderImplementationPrompt, renderPrompt with various data shapes and empty fields - helpers_test.go: orDefault, phrasesToText, summarizeBody, extractYAML, normalizeGeneratedPath, filterValidGraderTypes, parseGraderSelection edge cases - resolve_test.go: resolveSkillFile, loadSkill, buildPromptData, WriteToDir edge cases (empty paths, traversal, invalid YAML) jsonrpc package: - methods_test.go: MethodRegistry CRUD, overwrite, empty name, handler error/params, RegisterHandlers verification - handlers_extra_test.go: task.list/task.get success paths, run.cancel success/already-completed, eval.* edge cases, TCP listener start/close/serve, malformed YAML validation Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- storage: 39.1% → 54.6% (new tests for azure_blob pure functions, store helpers, local.go edge cases) - mcp: 58.3% → 89.4% (new tests for task_list, quickLinkCheck, resolveDir, ServeStdio, hasIDField, dispatchTool, skill check) Replaced all skipped mock tests in azure_blob_test.go with real tests for sanitizePathSegment, stringPtr, getMetadata, isCI, blobToResultSummary, outcomeToResultSummary, and NewAzureBlobStore validation. Note: storage cannot reach 70% without extracting a blob client interface from AzureBlobStore. The remaining 0% functions (Upload, Download, List, Compare, findBlobBySuffix, findBlobByMetadata) all call *azblob.Client directly. A follow-up PR can introduce the interface for full testability. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR adds new Go unit/integration tests to raise coverage for internal/suggest and internal/jsonrpc, without changing production code.
Changes:
- Adds tests for skill resolution/prompt rendering/helpers and grader docs handling in
internal/suggest. - Adds tests for
MethodRegistrybehavior and additional JSON-RPC handler success/edge paths (including TCP transport) ininternal/jsonrpc.
Show a summary per file
| File | Description |
|---|---|
| internal/suggest/resolve_test.go | Tests resolveSkillFile, loadSkill, buildPromptData, and Suggestion.WriteToDir edge cases. |
| internal/suggest/prompt_test.go | Tests prompt rendering functions for selection/implementation prompts. |
| internal/suggest/helpers_test.go | Tests helper utilities like YAML extraction, path normalization, grader type filtering, etc. |
| internal/suggest/grader_docs_test.go | Tests grader summaries formatting and grader-doc loading from an FS. |
| internal/jsonrpc/methods_test.go | Tests method registry CRUD/overwrite behavior and handler registration set. |
| internal/jsonrpc/handlers_extra_test.go | Adds more handler tests (task., run.cancel, eval. edge cases) and TCP listener coverage. |
Copilot's findings
Comments suppressed due to low confidence (1)
internal/suggest/resolve_test.go:86
- This test uses a hard-coded absolute path ("/nonexistent/SKILL.md") to exercise the missing-file branch. To avoid platform-specific behavior, build a non-existent path under t.TempDir() instead (and optionally assert errors.Is(err, os.ErrNotExist) via the wrapped error).
func TestLoadSkill_NonexistentFile(t *testing.T) {
_, _, err := loadSkill("/nonexistent/SKILL.md")
require.Error(t, err)
- Files reviewed: 9/9 changed files
- Comments generated: 6
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…r, fix paths - Replace time.Sleep with immediate connection (listener already active) - Use bufio.Scanner for newline-delimited JSON instead of raw conn.Read - Replace hard-coded absolute path with t.TempDir()-based path Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Use filepath.FromSlash for path assertions in normalizeGeneratedPath tests - Use runtime.GOOS to pick platform-appropriate absolute path in rejection test - Satisfy errcheck linter by explicitly discarding os.Setenv/Unsetenv/WriteFile errors in tests Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Copilot's findings
Comments suppressed due to low confidence (1)
internal/suggest/resolve_test.go:196
- TestWriteToDir_AbsolutePathRejected uses a Unix-specific absolute path ("/etc/evil.yaml"). This can fail on Windows where that path may not be considered absolute by filepath.IsAbs. Use an OS-appropriate absolute path (runtime.GOOS switch) or generate an absolute path via filepath.Join(t.TempDir(), "evil.yaml") and pass that into WriteToDir.
func TestWriteToDir_AbsolutePathRejected(t *testing.T) {
s := &Suggestion{
EvalYAML: validEvalYAML(),
Tasks: []GeneratedFile{
{Path: "/etc/evil.yaml", Content: "id: x\nname: X\ninputs:\n prompt: hi"},
},
}
dir := t.TempDir()
_, err := s.WriteToDir(dir)
require.Error(t, err)
assert.Contains(t, err.Error(), "invalid generated path")
}
- Files reviewed: 10/10 changed files
- Comments generated: 3
| _, _, err := loadSkill("/nonexistent/SKILL.md") | ||
| require.Error(t, err) | ||
| assert.Contains(t, err.Error(), "reading SKILL.md") |
There was a problem hiding this comment.
TestLoadSkill_NonexistentFile uses a hard-coded absolute path ("/nonexistent/SKILL.md"), which can be unreliable across platforms and environments. Prefer constructing a guaranteed-missing path under t.TempDir() (e.g., filepath.Join(t.TempDir(), "does-not-exist", "SKILL.md")) and asserting on the error message.
This issue also appears on line 184 of the same file.
| _, _, err := loadSkill("/nonexistent/SKILL.md") | |
| require.Error(t, err) | |
| assert.Contains(t, err.Error(), "reading SKILL.md") | |
| nonexistent := filepath.Join(t.TempDir(), "does-not-exist", "SKILL.md") | |
| _, _, err := loadSkill(nonexistent) | |
| require.Error(t, err) | |
| assert.Contains(t, err.Error(), "reading SKILL.md") | |
| assert.Contains(t, err.Error(), nonexistent) |
| } | ||
|
|
||
| func TestNormalizeGeneratedPath_AbsolutePathRejected(t *testing.T) { | ||
| absPath := "/etc/passwd" | ||
| if runtime.GOOS == "windows" { |
There was a problem hiding this comment.
TestNormalizeGeneratedPath_AbsolutePathRejected uses a Unix-specific absolute path ("/etc/passwd"), which can be non-portable on Windows depending on filepath.IsAbs behavior. Prefer using an absolute path derived from t.TempDir() (e.g., filepath.Join(t.TempDir(), "file")) or conditionalizing per OS (runtime.GOOS) like other cross-platform tests in the repo.
| // ======================================== | ||
| // server.go — additional coverage | ||
| // ======================================== | ||
|
|
There was a problem hiding this comment.
PR description says coverage improvements are for internal/suggest and internal/jsonrpc only, but this change set also adds/updates tests under internal/mcp and internal/storage. Please update the PR description (or scope) so reviewers understand the additional packages impacted.
|
Fixed the Windows CI failure in \TestWriteToDir_AbsolutePathRejected\ — the test was using a Unix-style absolute path (/etc/evil.yaml) which \ilepath.IsAbs\ doesn't recognize on Windows. Now uses \C:\evil.yaml\ on Windows via Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com |
Summary
Boost test coverage for two packages that were below 80%:
internal/suggestinternal/jsonrpcNew test files
suggest package (+6 files)
GraderSummariesformat,LoadGraderDocswithfstest.MapFS(nil, empty, mixed valid/invalid, whitespace trimming)renderSelectionPrompt,renderImplementationPrompt,renderPromptwith various data shapes and empty fieldsorDefault,phrasesToText,summarizeBody,extractYAML,normalizeGeneratedPath,filterValidGraderTypes,parseGraderSelectionedge casesresolveSkillFile,loadSkill,buildPromptData,WriteToDiredge cases (empty paths, traversal, invalid YAML)jsonrpc package (+2 files)
MethodRegistryCRUD, overwrite, empty name, handler error/params,RegisterHandlersverificationtask.list/task.getsuccess paths,run.cancelsuccess/already-completed,eval.*edge cases, TCP listener lifecycle, malformed YAML validationVerification
go test -mod=readonly -count=1 ./internal/suggest/... ./internal/jsonrpc/...go vetclean on both packages