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

268 lines
8.9 KiB
Go

package languages
import (
"testing"
"github.com/zzet/gortex/internal/graph"
)
// refEdge finds the first edge with the given kind whose To matches target
// and (when useKind != "") whose Meta["ref_context"] matches.
func findRefEdge(edges []*graph.Edge, kind graph.EdgeKind, target, useKind string) *graph.Edge {
for _, e := range edges {
if e.Kind != kind || e.To != target {
continue
}
if useKind != "" {
if uk, _ := e.Meta["ref_context"].(string); uk != useKind {
continue
}
}
return e
}
return nil
}
func hasEdgeTo(edges []*graph.Edge, target string) bool {
for _, e := range edges {
if e.To == target {
return true
}
}
return false
}
// TestPyRefForm_Instantiation: `HttpResponse(...)` emits an instantiates
// edge to the class, stamped OriginASTResolved with ref_context=instantiate.
func TestPyRefForm_Instantiation(t *testing.T) {
src := `from django.http import HttpResponse
def view(request):
return HttpResponse("ok")
`
_, edges := runPyExtract(t, "app/views.py", src)
e := findRefEdge(edges, graph.EdgeInstantiates, "unresolved::HttpResponse", "instantiate")
if e == nil {
t.Fatalf("expected EdgeInstantiates -> unresolved::HttpResponse (ref_context=instantiate); edges=%v", edgeDump(edges))
}
if e.Origin != graph.OriginASTResolved {
t.Errorf("instantiate edge Origin = %q, want OriginASTResolved", e.Origin)
}
if e.From != "app/views.py::view" {
t.Errorf("instantiate edge From = %q, want app/views.py::view", e.From)
}
}
// TestPyRefForm_DottedInstantiation: `http.HttpResponse(...)` — the
// Capitalized leaf attribute is the constructed type.
func TestPyRefForm_DottedInstantiation(t *testing.T) {
src := `import django.http as http
def view(request):
return http.HttpResponse("ok")
`
_, edges := runPyExtract(t, "app/v.py", src)
if findRefEdge(edges, graph.EdgeInstantiates, "unresolved::HttpResponse", "instantiate") == nil {
t.Fatalf("expected instantiate edge for http.HttpResponse(...); edges=%v", edgeDump(edges))
}
}
// TestPyRefForm_Inheritance: `class V(HttpResponse):` emits a references
// edge (ref_context=inherit), OriginASTResolved.
func TestPyRefForm_Inheritance(t *testing.T) {
src := `from django.http import HttpResponse
class MyResponse(HttpResponse):
pass
`
_, edges := runPyExtract(t, "app/r.py", src)
e := findRefEdge(edges, graph.EdgeReferences, "unresolved::HttpResponse", "inherit")
if e == nil {
t.Fatalf("expected EdgeReferences -> unresolved::HttpResponse (ref_context=inherit); edges=%v", edgeDump(edges))
}
if e.Origin != graph.OriginASTResolved {
t.Errorf("inherit edge Origin = %q, want OriginASTResolved (else cross_pkg_guard reverts it)", e.Origin)
}
}
// TestPyRefForm_DottedInheritance: `class V(http.HttpResponse):`.
func TestPyRefForm_DottedInheritance(t *testing.T) {
src := `import django.http as http
class MyResponse(http.HttpResponse):
pass
`
_, edges := runPyExtract(t, "app/r2.py", src)
if findRefEdge(edges, graph.EdgeReferences, "unresolved::HttpResponse", "inherit") == nil {
t.Fatalf("expected inherit edge for http.HttpResponse base; edges=%v", edgeDump(edges))
}
}
// TestPyRefForm_IsInstance: `isinstance(x, HttpResponse)` references the
// 2nd argument as a type (ref_context=cast). Tuple second arg references each.
func TestPyRefForm_IsInstance(t *testing.T) {
src := `from django.http import HttpResponse, JsonResponse
def check(x):
if isinstance(x, HttpResponse):
return True
return issubclass(type(x), (HttpResponse, JsonResponse))
`
_, edges := runPyExtract(t, "app/c.py", src)
e := findRefEdge(edges, graph.EdgeReferences, "unresolved::HttpResponse", "cast")
if e == nil {
t.Fatalf("expected EdgeReferences -> unresolved::HttpResponse (ref_context=cast); edges=%v", edgeDump(edges))
}
if e.Origin != graph.OriginASTResolved {
t.Errorf("cast edge Origin = %q, want OriginASTResolved", e.Origin)
}
if findRefEdge(edges, graph.EdgeReferences, "unresolved::JsonResponse", "cast") == nil {
t.Errorf("expected cast edge for JsonResponse in the issubclass tuple; edges=%v", edgeDump(edges))
}
// The first arg of isinstance (`x`) must NOT produce a type ref.
if hasEdgeTo(edges, "unresolved::x") {
t.Errorf("first isinstance arg `x` must not emit a type reference")
}
}
// TestPyRefForm_StaticAccess: `HttpResponse.status_code` emits a
// references edge (ref_context=static_access) to the class.
func TestPyRefForm_StaticAccess(t *testing.T) {
src := `from django.http import HttpResponse
def f():
return HttpResponse.status_code
`
_, edges := runPyExtract(t, "app/s.py", src)
e := findRefEdge(edges, graph.EdgeReferences, "unresolved::HttpResponse", "static_access")
if e == nil {
t.Fatalf("expected EdgeReferences -> unresolved::HttpResponse (ref_context=static_access); edges=%v", edgeDump(edges))
}
if e.Origin != graph.OriginASTResolved {
t.Errorf("static_access edge Origin = %q, want OriginASTResolved", e.Origin)
}
}
// TestPyRefForm_Decorator: `@Validator(...)` / `@Validator` references the
// Capitalized decorator name; lowercase `@property` / `@app.route` do not.
func TestPyRefForm_Decorator(t *testing.T) {
src := `from x import Validator
@Validator
def a():
pass
@Validator("strict")
def b():
pass
@property
def c(self):
pass
@app.route("/x")
def d():
pass
`
_, edges := runPyExtract(t, "app/d.py", src)
if findRefEdge(edges, graph.EdgeReferences, "unresolved::Validator", "static_access") == nil {
t.Fatalf("expected reference edge for @Validator decorator; edges=%v", edgeDump(edges))
}
if hasEdgeTo(edges, "unresolved::property") {
t.Errorf("lowercase decorator @property must not emit a type reference")
}
if hasEdgeTo(edges, "unresolved::route") {
t.Errorf("lowercase decorator @app.route must not emit a type reference")
}
}
// TestPyRefForm_NegativeCases: lowercase calls, method calls on instances,
// and bare builtins must not emit reference/instantiate edges.
func TestPyRefForm_NegativeCases(t *testing.T) {
src := `def run(obj):
foo()
obj.method()
x = dict()
y = list()
z = helper.compute()
return x, y, z
`
_, edges := runPyExtract(t, "app/n.py", src)
for _, bad := range []string{
"unresolved::foo", "unresolved::method", "unresolved::compute",
"unresolved::helper",
} {
for _, e := range edges {
if (e.Kind == graph.EdgeInstantiates || (e.Kind == graph.EdgeReferences && e.Meta["ref_context"] != nil)) && e.To == bad {
t.Errorf("lowercase callee/method %q must not emit an instantiate/reference type edge (got kind=%s)", bad, e.Kind)
}
}
}
// Lowercase builtins dict()/list() must not produce instantiate edges.
for _, b := range []string{"unresolved::dict", "unresolved::list"} {
if findRefEdge(edges, graph.EdgeInstantiates, b, "instantiate") != nil {
t.Errorf("lowercase builtin %q must not emit an instantiate edge", b)
}
}
}
// TestPyRefForm_GenericArgs: element types inside a type-annotation
// subscript (`List[Foo]`, `Dict[str, Bar]`, nested `Dict[str, List[Foo]]`,
// and a parameter annotation) emit a "generic_arg" reference to each named
// type, OriginASTResolved. Builtins (str/int) inside the subscript and a
// runtime subscript (`arr[0]`) emit NO type reference.
func TestPyRefForm_GenericArgs(t *testing.T) {
src := `from m import Foo, Bar, Baz
xs: List[Foo] = []
mapping: Dict[str, Bar] = {}
nested: Dict[str, List[Foo]] = {}
def handle(items: List[Baz]) -> None:
arr = [1, 2, 3]
return arr[0]
`
_, edges := runPyExtract(t, "app/g.py", src)
for _, want := range []string{"Foo", "Bar", "Baz"} {
e := findRefEdge(edges, graph.EdgeReferences, "unresolved::"+want, "generic_arg")
if e == nil {
t.Fatalf("expected EdgeReferences -> unresolved::%s (ref_context=generic_arg); edges=%v", want, edgeDump(edges))
}
if e.Origin != graph.OriginASTResolved {
t.Errorf("generic_arg edge for %s Origin = %q, want OriginASTResolved", want, e.Origin)
}
}
// The element type inside the parameter annotation is attributed to the
// enclosing function, not the file.
if e := findRefEdge(edges, graph.EdgeReferences, "unresolved::Baz", "generic_arg"); e != nil && e.From != "app/g.py::handle" {
t.Errorf("parameter generic_arg From = %q, want app/g.py::handle", e.From)
}
// Builtins inside the subscript (str, int) must not produce a type ref.
for _, bad := range []string{"unresolved::str", "unresolved::int"} {
if hasEdgeTo(edges, bad) {
t.Errorf("builtin %q inside a subscript must not emit a type reference", bad)
}
}
// A runtime subscript `arr[0]` must not emit any generic_arg reference.
for _, e := range edges {
if uk, _ := e.Meta["ref_context"].(string); uk == "generic_arg" && e.To == "unresolved::arr" {
t.Errorf("runtime subscript arr[0] must not emit a generic_arg reference")
}
}
}
// edgeDump renders edges compactly for failure messages.
func edgeDump(edges []*graph.Edge) []string {
out := make([]string, 0, len(edges))
for _, e := range edges {
uk, _ := e.Meta["ref_context"].(string)
out = append(out, string(e.Kind)+" "+e.From+" -> "+e.To+" ["+uk+"]")
}
return out
}