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

141 lines
5.1 KiB
Go

package analysis
import (
"testing"
"github.com/zzet/gortex/internal/graph"
)
func TestBuildAdjacencySnapshot_Empty(t *testing.T) {
snap := BuildAdjacencySnapshot(graph.New())
if snap.NodeCount() != 0 {
t.Errorf("empty graph should have 0 nodes, got %d", snap.NodeCount())
}
if snap.EdgeCount() != 0 {
t.Errorf("empty graph should have 0 edges, got %d", snap.EdgeCount())
}
// A nil-safe PersonalizedPageRank on an empty snapshot returns an
// empty map, not a panic.
if got := snap.PersonalizedPageRank([]string{"x"}, 0); len(got) != 0 {
t.Errorf("expected empty result on empty snapshot, got %v", got)
}
}
func TestBuildAdjacencySnapshot_OnlyCallAndReferenceEdges(t *testing.T) {
g := graph.New()
for _, id := range []string{"a", "b", "c", "d"} {
g.AddNode(&graph.Node{ID: id, Kind: graph.KindFunction, Name: id})
}
// a -> b (calls), a -> c (references), a -> d (imports — excluded).
g.AddEdge(&graph.Edge{From: "a", To: "b", Kind: graph.EdgeCalls})
g.AddEdge(&graph.Edge{From: "a", To: "c", Kind: graph.EdgeReferences})
g.AddEdge(&graph.Edge{From: "a", To: "d", Kind: graph.EdgeImports})
snap := BuildAdjacencySnapshot(g)
if snap.NodeCount() != 4 {
t.Fatalf("expected 4 nodes, got %d", snap.NodeCount())
}
// Only the calls + references edges are captured.
if snap.EdgeCount() != 2 {
t.Errorf("expected 2 captured edges (calls+references), got %d", snap.EdgeCount())
}
}
func TestBuildAdjacencySnapshot_SkipsDanglingEndpoints(t *testing.T) {
g := graph.New()
g.AddNode(&graph.Node{ID: "a", Kind: graph.KindFunction, Name: "a"})
// Edge to a node that does not exist in the graph — must be skipped
// so the dense index stays consistent.
g.AddEdge(&graph.Edge{From: "a", To: "ghost", Kind: graph.EdgeCalls})
snap := BuildAdjacencySnapshot(g)
if snap.NodeCount() != 1 {
t.Fatalf("expected 1 node, got %d", snap.NodeCount())
}
if snap.EdgeCount() != 0 {
t.Errorf("dangling edge must be skipped, got %d edges", snap.EdgeCount())
}
}
func TestPersonalizedPageRank_ConcentratesNearSeed(t *testing.T) {
g := graph.New()
// Two disjoint chains. Seed one of them; the seeded chain must
// score far above the unrelated chain.
for _, id := range []string{"s", "s1", "s2", "u", "u1", "u2"} {
g.AddNode(&graph.Node{ID: id, Kind: graph.KindFunction, Name: id})
}
g.AddEdge(&graph.Edge{From: "s", To: "s1", Kind: graph.EdgeCalls})
g.AddEdge(&graph.Edge{From: "s1", To: "s2", Kind: graph.EdgeCalls})
g.AddEdge(&graph.Edge{From: "u", To: "u1", Kind: graph.EdgeCalls})
g.AddEdge(&graph.Edge{From: "u1", To: "u2", Kind: graph.EdgeCalls})
snap := BuildAdjacencySnapshot(g)
scores := snap.PersonalizedPageRank([]string{"s"}, 0)
// The seed and its reachable neighbours carry mass; the unrelated
// chain is never reached from the seed, so it stays at zero.
if scores["s"] <= 0 {
t.Errorf("seed should carry positive mass, got %f", scores["s"])
}
if scores["s1"] <= 0 {
t.Errorf("seed-reachable node should carry mass, got %f", scores["s1"])
}
if scores["u"] != 0 || scores["u1"] != 0 || scores["u2"] != 0 {
t.Errorf("the unrelated chain should be unreachable from the seed: u=%f u1=%f u2=%f",
scores["u"], scores["u1"], scores["u2"])
}
// The seed itself, kept warm by restart, outranks its downstream.
if scores["s"] <= scores["s2"] {
t.Errorf("restart should keep the seed (%f) above its downstream (%f)", scores["s"], scores["s2"])
}
}
func TestPersonalizedPageRank_MultiSeedSharesRestartMass(t *testing.T) {
g := graph.New()
for _, id := range []string{"p", "q", "x"} {
g.AddNode(&graph.Node{ID: id, Kind: graph.KindFunction, Name: id})
}
// Both seeds call a shared node x.
g.AddEdge(&graph.Edge{From: "p", To: "x", Kind: graph.EdgeCalls})
g.AddEdge(&graph.Edge{From: "q", To: "x", Kind: graph.EdgeCalls})
snap := BuildAdjacencySnapshot(g)
scores := snap.PersonalizedPageRank([]string{"p", "q"}, 0)
if scores["p"] <= 0 || scores["q"] <= 0 {
t.Errorf("both seeds should carry mass: p=%f q=%f", scores["p"], scores["q"])
}
// x is fed by both seeds.
if scores["x"] <= 0 {
t.Errorf("the shared downstream node should accumulate mass, got %f", scores["x"])
}
}
func TestPersonalizedPageRank_NoSeedInSnapshot(t *testing.T) {
g := graph.New()
g.AddNode(&graph.Node{ID: "a", Kind: graph.KindFunction, Name: "a"})
snap := BuildAdjacencySnapshot(g)
// A seed absent from the snapshot yields an empty result (no walk
// to run), never a panic.
if got := snap.PersonalizedPageRank([]string{"absent"}, 0); len(got) != 0 {
t.Errorf("expected empty result for absent seed, got %v", got)
}
}
func TestPersonalizedPageRank_ProvenanceWeightingMatchesPageRankEdgeSet(t *testing.T) {
g := graph.New()
for _, id := range []string{"a", "b"} {
g.AddNode(&graph.Node{ID: id, Kind: graph.KindFunction, Name: id})
}
// A high-confidence AST-resolved call: it must be captured with a
// non-zero weight so the seeded walk can flow along it.
g.AddEdge(&graph.Edge{From: "a", To: "b", Kind: graph.EdgeCalls, Origin: graph.OriginASTResolved})
snap := BuildAdjacencySnapshot(g)
scores := snap.PersonalizedPageRank([]string{"a"}, 0)
if scores["b"] <= 0 {
t.Errorf("mass should flow from seed a to b along the weighted edge, got b=%f", scores["b"])
}
}