Files
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

230 lines
6.8 KiB
Go

package query
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/zzet/gortex/internal/graph"
)
func TestParseEdgeKindsCSV(t *testing.T) {
t.Run("single", func(t *testing.T) {
got, err := ParseEdgeKindsCSV("calls")
require.NoError(t, err)
assert.Equal(t, []graph.EdgeKind{graph.EdgeCalls}, got)
})
t.Run("multiple with whitespace", func(t *testing.T) {
got, err := ParseEdgeKindsCSV(" calls , references ")
require.NoError(t, err)
assert.Equal(t, []graph.EdgeKind{graph.EdgeCalls, graph.EdgeReferences}, got)
})
t.Run("empty tokens skipped", func(t *testing.T) {
got, err := ParseEdgeKindsCSV("calls,,implements")
require.NoError(t, err)
assert.Equal(t, []graph.EdgeKind{graph.EdgeCalls, graph.EdgeImplements}, got)
})
t.Run("dedup", func(t *testing.T) {
got, err := ParseEdgeKindsCSV("calls,calls,references")
require.NoError(t, err)
assert.Equal(t, []graph.EdgeKind{graph.EdgeCalls, graph.EdgeReferences}, got)
})
t.Run("empty input is nil no error", func(t *testing.T) {
got, err := ParseEdgeKindsCSV(" ")
require.NoError(t, err)
assert.Nil(t, got)
})
t.Run("case insensitive", func(t *testing.T) {
got, err := ParseEdgeKindsCSV("CALLS")
require.NoError(t, err)
assert.Equal(t, []graph.EdgeKind{graph.EdgeCalls}, got)
})
t.Run("unknown kind errors", func(t *testing.T) {
_, err := ParseEdgeKindsCSV("calls,bogus")
require.Error(t, err)
assert.Contains(t, err.Error(), "bogus")
})
}
func TestWalkBudgeted_Direction(t *testing.T) {
e := NewEngine(buildTestGraph())
t.Run("out follows callees", func(t *testing.T) {
sg := e.WalkBudgeted("main.go::main", WalkOptions{
EdgeKinds: []graph.EdgeKind{graph.EdgeCalls},
Direction: "out",
})
ids := nodeIDs(sg.Nodes)
assert.Contains(t, ids, "main.go::main")
assert.Contains(t, ids, "pkg/server.go::Start")
assert.Contains(t, ids, "pkg/db.go::Connect")
assert.Contains(t, ids, "pkg/db.go::Ping")
})
t.Run("in follows callers", func(t *testing.T) {
sg := e.WalkBudgeted("pkg/db.go::Ping", WalkOptions{
EdgeKinds: []graph.EdgeKind{graph.EdgeCalls},
Direction: "in",
})
ids := nodeIDs(sg.Nodes)
assert.Contains(t, ids, "pkg/db.go::Connect")
assert.Contains(t, ids, "pkg/server.go::Start")
assert.Contains(t, ids, "main.go::main")
// Forward-only callees of Ping must not appear.
assert.NotContains(t, ids, "pkg/db.go::DBImpl")
})
t.Run("both is undirected", func(t *testing.T) {
sg := e.WalkBudgeted("pkg/server.go::Start", WalkOptions{
EdgeKinds: []graph.EdgeKind{graph.EdgeCalls},
Direction: "both",
})
ids := nodeIDs(sg.Nodes)
// Reaches both the caller (main) and the callee chain.
assert.Contains(t, ids, "main.go::main")
assert.Contains(t, ids, "pkg/db.go::Connect")
assert.Contains(t, ids, "pkg/db.go::Ping")
})
t.Run("empty direction defaults to out", func(t *testing.T) {
sg := e.WalkBudgeted("main.go::main", WalkOptions{
EdgeKinds: []graph.EdgeKind{graph.EdgeCalls},
})
ids := nodeIDs(sg.Nodes)
assert.Contains(t, ids, "pkg/server.go::Start")
})
}
func TestWalkBudgeted_EdgeKindFiltering(t *testing.T) {
e := NewEngine(buildTestGraph())
t.Run("calls only ignores references", func(t *testing.T) {
sg := e.WalkBudgeted("main.go::main", WalkOptions{
EdgeKinds: []graph.EdgeKind{graph.EdgeCalls},
Direction: "out",
})
ids := nodeIDs(sg.Nodes)
// main references DBImpl, but references is not in the kind set.
assert.NotContains(t, ids, "pkg/db.go::DBImpl")
})
t.Run("references reaches DBImpl", func(t *testing.T) {
sg := e.WalkBudgeted("main.go::main", WalkOptions{
EdgeKinds: []graph.EdgeKind{graph.EdgeReferences},
Direction: "out",
})
ids := nodeIDs(sg.Nodes)
assert.Contains(t, ids, "pkg/db.go::DBImpl")
})
t.Run("multiple kinds reach both", func(t *testing.T) {
sg := e.WalkBudgeted("main.go::main", WalkOptions{
EdgeKinds: []graph.EdgeKind{graph.EdgeCalls, graph.EdgeReferences},
Direction: "out",
})
ids := nodeIDs(sg.Nodes)
assert.Contains(t, ids, "pkg/server.go::Start")
assert.Contains(t, ids, "pkg/db.go::DBImpl")
})
t.Run("empty kinds follows every edge", func(t *testing.T) {
sg := e.WalkBudgeted("main.go::main", WalkOptions{
Direction: "out",
})
ids := nodeIDs(sg.Nodes)
assert.Contains(t, ids, "pkg/server.go::Start")
assert.Contains(t, ids, "pkg/db.go::DBImpl")
})
}
func TestWalkBudgeted_DepthCap(t *testing.T) {
e := NewEngine(buildTestGraph())
// Depth 1 from main reaches Start but not Connect (depth 2).
sg := e.WalkBudgeted("main.go::main", WalkOptions{
EdgeKinds: []graph.EdgeKind{graph.EdgeCalls},
Direction: "out",
MaxDepth: 1,
})
ids := nodeIDs(sg.Nodes)
assert.Contains(t, ids, "pkg/server.go::Start")
assert.NotContains(t, ids, "pkg/db.go::Connect")
assert.Equal(t, 1, sg.StoppedAtDepth)
assert.False(t, sg.BudgetHit)
}
func TestWalkBudgeted_TokenBudget(t *testing.T) {
e := NewEngine(buildTestGraph())
t.Run("tight budget stops early", func(t *testing.T) {
// A budget that admits only the seed plus a node or two.
sg := e.WalkBudgeted("main.go::main", WalkOptions{
EdgeKinds: []graph.EdgeKind{graph.EdgeCalls},
Direction: "out",
TokenBudget: 10,
})
assert.True(t, sg.BudgetHit)
assert.True(t, sg.Truncated)
// The whole 4-node call chain must not have been walked.
assert.Less(t, len(sg.Nodes), 4)
})
t.Run("generous budget completes", func(t *testing.T) {
sg := e.WalkBudgeted("main.go::main", WalkOptions{
EdgeKinds: []graph.EdgeKind{graph.EdgeCalls},
Direction: "out",
TokenBudget: 100000,
})
assert.False(t, sg.BudgetHit)
ids := nodeIDs(sg.Nodes)
assert.Contains(t, ids, "pkg/db.go::Ping")
})
}
func TestWalkBudgeted_MissingSeed(t *testing.T) {
e := NewEngine(buildTestGraph())
sg := e.WalkBudgeted("does/not::Exist", WalkOptions{
EdgeKinds: []graph.EdgeKind{graph.EdgeCalls},
})
assert.Empty(t, sg.Nodes)
assert.Empty(t, sg.Edges)
}
func TestWalkBudgeted_WorkspaceScope(t *testing.T) {
g := buildTestGraph()
// Tag every node in the test graph with workspace "main", then add
// a foreign node in workspace "other" reachable by a call edge.
for _, n := range g.AllNodes() {
n.WorkspaceID = "main"
}
g.AddNode(&graph.Node{
ID: "other/x.go::Foreign", Kind: graph.KindFunction, Name: "Foreign",
FilePath: "other/x.go", Language: "go", WorkspaceID: "other",
})
g.AddEdge(&graph.Edge{
From: "pkg/db.go::Ping", To: "other/x.go::Foreign",
Kind: graph.EdgeCalls, FilePath: "pkg/db.go", Line: 20,
})
e := NewEngine(g)
scoped := e.WalkBudgeted("main.go::main", WalkOptions{
EdgeKinds: []graph.EdgeKind{graph.EdgeCalls},
Direction: "out",
WorkspaceID: "main",
})
assert.NotContains(t, nodeIDs(scoped.Nodes), "other/x.go::Foreign")
unscoped := e.WalkBudgeted("main.go::main", WalkOptions{
EdgeKinds: []graph.EdgeKind{graph.EdgeCalls},
Direction: "out",
})
assert.Contains(t, nodeIDs(unscoped.Nodes), "other/x.go::Foreign")
}