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

117 lines
5.0 KiB
Go

package resolver
import (
"testing"
"github.com/zzet/gortex/internal/graph"
)
// TestInferOverrides_MatchesByMethodName builds a small graph with
// child & parent classes, then asserts that InferOverrides materialises
// EdgeOverrides for each child method whose name matches a parent
// method.
func TestInferOverrides_MatchesByMethodName(t *testing.T) {
g := graph.New()
parent := &graph.Node{ID: "p.ts::Animal", Kind: graph.KindType, Name: "Animal", Language: "typescript"}
child := &graph.Node{ID: "p.ts::Dog", Kind: graph.KindType, Name: "Dog", Language: "typescript"}
parentSpeak := &graph.Node{ID: "p.ts::Animal.speak", Kind: graph.KindMethod, Name: "speak", Language: "typescript", FilePath: "p.ts", StartLine: 5}
parentEat := &graph.Node{ID: "p.ts::Animal.eat", Kind: graph.KindMethod, Name: "eat", Language: "typescript", FilePath: "p.ts", StartLine: 8}
childSpeak := &graph.Node{ID: "p.ts::Dog.speak", Kind: graph.KindMethod, Name: "speak", Language: "typescript", FilePath: "p.ts", StartLine: 15}
childRun := &graph.Node{ID: "p.ts::Dog.run", Kind: graph.KindMethod, Name: "run", Language: "typescript", FilePath: "p.ts", StartLine: 18}
for _, n := range []*graph.Node{parent, child, parentSpeak, parentEat, childSpeak, childRun} {
g.AddNode(n)
}
// Membership.
g.AddEdge(&graph.Edge{From: parentSpeak.ID, To: parent.ID, Kind: graph.EdgeMemberOf, FilePath: "p.ts", Line: 5})
g.AddEdge(&graph.Edge{From: parentEat.ID, To: parent.ID, Kind: graph.EdgeMemberOf, FilePath: "p.ts", Line: 8})
g.AddEdge(&graph.Edge{From: childSpeak.ID, To: child.ID, Kind: graph.EdgeMemberOf, FilePath: "p.ts", Line: 15})
g.AddEdge(&graph.Edge{From: childRun.ID, To: child.ID, Kind: graph.EdgeMemberOf, FilePath: "p.ts", Line: 18})
// Hierarchy edge.
g.AddEdge(&graph.Edge{From: child.ID, To: parent.ID, Kind: graph.EdgeExtends, FilePath: "p.ts", Line: 10, Origin: graph.OriginASTResolved})
r := New(g)
added := r.InferOverrides()
if added != 1 {
t.Fatalf("expected 1 override, got %d", added)
}
// Walk overrides edges from the child speak method and check it
// targets the parent speak method.
out := g.GetOutEdges(childSpeak.ID)
var found bool
for _, e := range out {
if e.Kind == graph.EdgeOverrides && e.To == parentSpeak.ID {
found = true
if e.Origin != graph.OriginASTResolved {
t.Errorf("expected origin ast_resolved, got %q", e.Origin)
}
}
}
if !found {
t.Fatal("expected EdgeOverrides Dog.speak → Animal.speak")
}
// The only-in-child method should have no override.
for _, e := range g.GetOutEdges(childRun.ID) {
if e.Kind == graph.EdgeOverrides {
t.Fatalf("Dog.run should not override anything; got %v", e)
}
}
}
// TestInferOverrides_RespectsMinTier promotes inferred edges to the
// appropriate origin based on the parent edge.
func TestInferOverrides_RespectsMinTier(t *testing.T) {
g := graph.New()
parent := &graph.Node{ID: "i.ts::I", Kind: graph.KindInterface, Name: "I", Language: "typescript"}
child := &graph.Node{ID: "i.ts::C", Kind: graph.KindType, Name: "C", Language: "typescript"}
pm := &graph.Node{ID: "i.ts::I.do", Kind: graph.KindMethod, Name: "do", Language: "typescript", FilePath: "i.ts", StartLine: 1}
cm := &graph.Node{ID: "i.ts::C.do", Kind: graph.KindMethod, Name: "do", Language: "typescript", FilePath: "i.ts", StartLine: 5}
for _, n := range []*graph.Node{parent, child, pm, cm} {
g.AddNode(n)
}
g.AddEdge(&graph.Edge{From: pm.ID, To: parent.ID, Kind: graph.EdgeMemberOf})
g.AddEdge(&graph.Edge{From: cm.ID, To: child.ID, Kind: graph.EdgeMemberOf})
// Implements with a heuristic origin.
g.AddEdge(&graph.Edge{From: child.ID, To: parent.ID, Kind: graph.EdgeImplements, Origin: graph.OriginASTInferred})
r := New(g)
added := r.InferOverrides()
if added != 1 {
t.Fatalf("added=%d", added)
}
for _, e := range g.GetOutEdges(cm.ID) {
if e.Kind == graph.EdgeOverrides {
if e.Origin != graph.OriginASTInferred {
t.Errorf("expected ast_inferred, got %q", e.Origin)
}
}
}
}
// TestInferOverrides_Idempotent runs the pass twice and confirms no
// duplicate edges are emitted.
func TestInferOverrides_Idempotent(t *testing.T) {
g := graph.New()
parent := &graph.Node{ID: "x.go::P", Kind: graph.KindType, Name: "P", Language: "go"}
child := &graph.Node{ID: "x.go::C", Kind: graph.KindType, Name: "C", Language: "go"}
pm := &graph.Node{ID: "x.go::P.f", Kind: graph.KindMethod, Name: "f", Language: "go"}
cm := &graph.Node{ID: "x.go::C.f", Kind: graph.KindMethod, Name: "f", Language: "go"}
for _, n := range []*graph.Node{parent, child, pm, cm} {
g.AddNode(n)
}
g.AddEdge(&graph.Edge{From: pm.ID, To: parent.ID, Kind: graph.EdgeMemberOf})
g.AddEdge(&graph.Edge{From: cm.ID, To: child.ID, Kind: graph.EdgeMemberOf})
g.AddEdge(&graph.Edge{From: child.ID, To: parent.ID, Kind: graph.EdgeExtends, Origin: graph.OriginASTResolved})
r := New(g)
if added := r.InferOverrides(); added != 1 {
t.Fatalf("first run added=%d", added)
}
if added := r.InferOverrides(); added != 0 {
t.Fatalf("second run should add 0, got %d", added)
}
}