Files
zzet--gortex/internal/mcp/manifest_skeletonize_test.go
wehub-resource-sync 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
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

181 lines
6.3 KiB
Go

package mcp
import (
"context"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/zzet/gortex/internal/graph"
)
// manifestEntryByID finds the manifest entry for a node ID.
func manifestEntryByID(entries []map[string]any, id string) map[string]any {
for _, e := range entries {
if e["id"] == id {
return e
}
}
return nil
}
// writeManifestFixture writes a multi-line source file whose full and
// compressed renderings differ, and returns its absolute path.
func writeManifestFixture(t *testing.T, dir, name, body string) string {
t.Helper()
abs := filepath.Join(dir, name)
require.NoError(t, os.WriteFile(abs, []byte(body), 0o644))
return abs
}
// TestManifest_SkeletonizesLargeInterfaceFamily proves a focus interface
// with more than the sibling threshold of implementors is skeletonized
// (compressed, with sibling_count surfaced) rather than embedded full,
// while a control interface with a single implementor stays full.
func TestManifest_SkeletonizesLargeInterfaceFamily(t *testing.T) {
srv, dir := setupTestServer(t)
g := srv.graph
ctx := context.Background()
// Body source with a real function body so full != compressed.
bigBody := `package fam
// BigFamily is implemented by many interchangeable types.
type BigFamily interface {
Do(x int) int
Name() string
}
`
soleBody := `package fam
// Lonely has a single implementation.
type Lonely interface {
Only() error
}
`
bigPath := writeManifestFixture(t, dir, "big.go", bigBody)
solePath := writeManifestFixture(t, dir, "sole.go", soleBody)
add := func(id, name string, kind graph.NodeKind, file string, start, end int) {
g.AddNode(&graph.Node{
ID: id, Kind: kind, Name: name,
FilePath: file, Language: "go",
StartLine: start, EndLine: end,
})
}
impl := func(from, to string) {
g.AddEdge(&graph.Edge{From: from, To: to, Kind: graph.EdgeImplements, Origin: graph.OriginLSPResolved, FilePath: "x.go"})
}
// The big interface spans lines 4-7 of big.go.
add("big.go::BigFamily", "BigFamily", graph.KindInterface, bigPath, 4, 7)
// Five implementors — well past the threshold of 3.
for _, n := range []string{"A", "B", "C", "D", "E"} {
id := "impl.go::" + n
add(id, n, graph.KindType, bigPath, 1, 1)
impl(id, "big.go::BigFamily")
}
// The sole interface spans lines 4-6 of sole.go, with one implementor.
add("sole.go::Lonely", "Lonely", graph.KindInterface, solePath, 4, 6)
add("impl.go::Single", "Single", graph.KindType, solePath, 1, 1)
impl("impl.go::Single", "sole.go::Lonely")
focus := []*graph.Node{
g.GetNode("big.go::BigFamily"),
g.GetNode("sole.go::Lonely"),
}
require.NotNil(t, focus[0])
require.NotNil(t, focus[1])
mani := srv.buildContextManifest(ctx, focus, nil, 8000)
entries, _ := mani["entries"].([]map[string]any)
require.NotEmpty(t, entries)
big := manifestEntryByID(entries, "big.go::BigFamily")
require.NotNil(t, big, "big-family interface must be in the manifest")
assert.Equal(t, "focus", big["tier"])
assert.Equal(t, true, big["compressed"],
"a large interface family must be skeletonized (compressed)")
sc, _ := big["sibling_count"].(int)
assert.Equal(t, 5, sc, "sibling_count must report the implementor family size")
sole := manifestEntryByID(entries, "sole.go::Lonely")
require.NotNil(t, sole, "sole interface must be in the manifest")
assert.Equal(t, "focus", sole["tier"])
assert.Equal(t, false, sole["compressed"],
"a single-implementor interface must stay full, not skeletonized")
}
// TestManifest_SkeletonizesLargeMethodFamily proves a focus method with
// more than the threshold of overriders is skeletonized.
func TestManifest_SkeletonizesLargeMethodFamily(t *testing.T) {
srv, dir := setupTestServer(t)
g := srv.graph
ctx := context.Background()
body := `package fam
// Base.Run is overridden by many subtypes.
func (b *Base) Run(n int) int {
total := 0
for i := 0; i < n; i++ {
total += i
}
return total
}
`
p := writeManifestFixture(t, dir, "base.go", body)
g.AddNode(&graph.Node{
ID: "base.go::Base.Run", Kind: graph.KindMethod, Name: "Base.Run",
FilePath: p, Language: "go", StartLine: 4, EndLine: 10,
})
for _, n := range []string{"W", "X", "Y", "Z"} {
id := "ov.go::" + n + ".Run"
g.AddNode(&graph.Node{ID: id, Kind: graph.KindMethod, Name: n + ".Run", FilePath: p, Language: "go", StartLine: 1, EndLine: 1})
// EdgeOverrides points child -> parent; FindOverrides reads
// the inverse to collect children.
g.AddEdge(&graph.Edge{From: id, To: "base.go::Base.Run", Kind: graph.EdgeOverrides, Origin: graph.OriginLSPResolved, FilePath: "x.go"})
}
focus := []*graph.Node{g.GetNode("base.go::Base.Run")}
require.NotNil(t, focus[0])
mani := srv.buildContextManifest(ctx, focus, nil, 8000)
entries, _ := mani["entries"].([]map[string]any)
e := manifestEntryByID(entries, "base.go::Base.Run")
require.NotNil(t, e)
assert.Equal(t, true, e["compressed"], "an over-threshold method family must skeletonize")
sc, _ := e["sibling_count"].(int)
assert.Equal(t, 4, sc)
}
// TestManifest_SiblingCountCounting verifies the per-kind counting rules
// of manifestSiblingCount directly.
func TestManifest_SiblingCountCounting(t *testing.T) {
srv, _ := setupTestServer(t)
g := srv.graph
ctx := context.Background()
g.AddNode(&graph.Node{ID: "i.go::Iface", Kind: graph.KindInterface, Name: "Iface", FilePath: "i.go", Language: "go"})
for _, n := range []string{"P", "Q"} {
id := "t.go::" + n
g.AddNode(&graph.Node{ID: id, Kind: graph.KindType, Name: n, FilePath: "t.go", Language: "go"})
g.AddEdge(&graph.Edge{From: id, To: "i.go::Iface", Kind: graph.EdgeImplements, Origin: graph.OriginLSPResolved, FilePath: "x.go"})
}
// Interface family size = 2 implementors.
assert.Equal(t, 2, srv.manifestSiblingCount(ctx, g.GetNode("i.go::Iface")))
// A concrete type's co-implementor count excludes itself: P sees Q.
assert.Equal(t, 1, srv.manifestSiblingCount(ctx, g.GetNode("t.go::P")))
// A function is never a polymorphic family.
g.AddNode(&graph.Node{ID: "f.go::Fn", Kind: graph.KindFunction, Name: "Fn", FilePath: "f.go", Language: "go"})
assert.Equal(t, 0, srv.manifestSiblingCount(ctx, g.GetNode("f.go::Fn")))
assert.False(t, skeletonizableKind(graph.KindFunction))
assert.True(t, skeletonizableKind(graph.KindInterface))
assert.True(t, skeletonizableKind(graph.KindType))
assert.True(t, skeletonizableKind(graph.KindMethod))
}