a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
107 lines
3.5 KiB
Go
107 lines
3.5 KiB
Go
package mcp
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/zzet/gortex/internal/graph"
|
|
)
|
|
|
|
func TestExploreLocalizableKind(t *testing.T) {
|
|
// Real edit targets are localizable; structural noise is not.
|
|
localizable := []graph.NodeKind{
|
|
graph.KindFunction, graph.KindMethod, graph.KindType,
|
|
graph.KindInterface, graph.KindField, graph.KindConstant,
|
|
graph.KindVariable,
|
|
}
|
|
for _, k := range localizable {
|
|
if !exploreLocalizableKind(k) {
|
|
t.Errorf("kind %q should be localizable", k)
|
|
}
|
|
}
|
|
noise := []graph.NodeKind{
|
|
graph.KindParam, graph.KindLocal, graph.KindClosure,
|
|
graph.KindGenericParam, graph.KindImport, graph.KindFile,
|
|
}
|
|
for _, k := range noise {
|
|
if exploreLocalizableKind(k) {
|
|
t.Errorf("kind %q should be filtered out", k)
|
|
}
|
|
}
|
|
}
|
|
|
|
func exploreTestTargets() []exploreTarget {
|
|
fn := &graph.Node{Name: "DoWithRetry", Kind: graph.KindFunction,
|
|
FilePath: "retry.go", StartLine: 11, EndLine: 20, Language: "go"}
|
|
helper := &graph.Node{Name: "Backoff", Kind: graph.KindFunction,
|
|
FilePath: "retry.go", StartLine: 6, EndLine: 8, Language: "go"}
|
|
caller := &graph.Node{Name: "Fetch", Kind: graph.KindFunction,
|
|
FilePath: "client.go", StartLine: 4, EndLine: 6, Language: "go"}
|
|
return []exploreTarget{
|
|
{node: fn, score: 0.9, callers: []*graph.Node{caller}, callees: []*graph.Node{helper},
|
|
source: "func DoWithRetry(max int) error {\n\treturn nil\n}"},
|
|
{node: helper, score: 0.5, callers: []*graph.Node{fn},
|
|
source: "func Backoff(n int) int {\n\treturn n\n}"},
|
|
}
|
|
}
|
|
|
|
func TestRenderExploreShape(t *testing.T) {
|
|
out := (&Server{}).renderExplore("the retry backoff never fires on 429", exploreTestTargets(), 9000)
|
|
|
|
// Ranked targets, with citeable path:line locations.
|
|
for _, want := range []string{
|
|
"EXPLORE — the retry backoff never fires on 429",
|
|
"## Likely targets",
|
|
"1. DoWithRetry function · retry.go:11-20",
|
|
"2. Backoff function · retry.go:6-8",
|
|
"^ callers: Fetch (client.go:4-6)",
|
|
"v calls: Backoff (retry.go:6-8)",
|
|
"func DoWithRetry(max int) error", // full body for hot target
|
|
"## Files to change",
|
|
"- retry.go · Backoff, DoWithRetry",
|
|
"— Completeness: 2 candidate symbol(s) across 1 file(s)",
|
|
"FILES / SYMBOLS / EVIDENCE",
|
|
} {
|
|
if !strings.Contains(out, want) {
|
|
t.Errorf("render missing %q\n--- got ---\n%s", want, out)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRenderExploreBudgetTruncation(t *testing.T) {
|
|
// A budget below the body cost forces demotion to signatures, but every
|
|
// candidate's LOCATION must still be listed (file-hit/symbol-hit never
|
|
// depend on the budget) and the truncation must be reported honestly.
|
|
out := (&Server{}).renderExplore("task", exploreTestTargets(), exploreMinBudgetTokens)
|
|
for _, want := range []string{
|
|
"1. DoWithRetry function · retry.go:11-20",
|
|
"2. Backoff function · retry.go:6-8",
|
|
"— Completeness:",
|
|
} {
|
|
if !strings.Contains(out, want) {
|
|
t.Errorf("truncated render missing %q", want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestExploreHelpers(t *testing.T) {
|
|
if got := clampInt(5, 1, 3); got != 3 {
|
|
t.Errorf("clampInt hi: got %d", got)
|
|
}
|
|
if got := clampInt(0, 2, 10); got != 2 {
|
|
t.Errorf("clampInt lo: got %d", got)
|
|
}
|
|
if got := truncateOneLine("a\n b\tc", 100); got != "a b c" {
|
|
t.Errorf("truncateOneLine collapse: %q", got)
|
|
}
|
|
if got := truncateOneLine(strings.Repeat("x", 10), 4); got != "xxxx…" {
|
|
t.Errorf("truncateOneLine cap: %q", got)
|
|
}
|
|
if got := firstLines("1\n2\n3\n4", 2); got != "1\n2" {
|
|
t.Errorf("firstLines: %q", got)
|
|
}
|
|
if got := dedupStrings([]string{"b", "a", "b"}); strings.Join(got, ",") != "a,b" {
|
|
t.Errorf("dedupStrings: %v", got)
|
|
}
|
|
}
|