chore: import upstream snapshot with attribution
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
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
This commit is contained in:
@@ -0,0 +1,175 @@
|
||||
package languages
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/zzet/gortex/internal/graph"
|
||||
)
|
||||
|
||||
func TestPascalExtractor_Unit(t *testing.T) {
|
||||
src := []byte(`unit Shapes;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
SysUtils, Classes;
|
||||
|
||||
type
|
||||
TCircle = class
|
||||
public
|
||||
constructor Create(R: Double);
|
||||
function Area: Double;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
constructor TCircle.Create(R: Double);
|
||||
begin
|
||||
end;
|
||||
|
||||
function TCircle.Area: Double;
|
||||
begin
|
||||
Result := 3.14 * 1.0;
|
||||
end;
|
||||
|
||||
procedure Hello;
|
||||
begin
|
||||
WriteLn('hi');
|
||||
end;
|
||||
|
||||
end.
|
||||
`)
|
||||
e := NewPascalExtractor()
|
||||
require.Equal(t, "pascal", e.Language())
|
||||
|
||||
res, err := e.Extract("Shapes.pas", src)
|
||||
require.NoError(t, err)
|
||||
|
||||
var gotUnit, gotType, gotCreate, gotArea, gotHello bool
|
||||
for _, n := range res.Nodes {
|
||||
// Methods carry the bare name and a class-qualified ID — the
|
||||
// convention shared with every other language — instead of jamming
|
||||
// the qualified name into Name as the old regex extractor did.
|
||||
switch n.ID {
|
||||
case "Shapes.pas::Shapes":
|
||||
gotUnit = true
|
||||
case "Shapes.pas::TCircle":
|
||||
gotType = true
|
||||
case "Shapes.pas::TCircle.Create":
|
||||
gotCreate = true
|
||||
case "Shapes.pas::TCircle.Area":
|
||||
gotArea = true
|
||||
case "Shapes.pas::Hello":
|
||||
gotHello = true
|
||||
}
|
||||
}
|
||||
var gotUses bool
|
||||
for _, ed := range res.Edges {
|
||||
if ed.Kind == graph.EdgeImports && ed.To == "unresolved::import::SysUtils" {
|
||||
gotUses = true
|
||||
}
|
||||
}
|
||||
assert.True(t, gotUnit)
|
||||
assert.True(t, gotType)
|
||||
assert.True(t, gotCreate)
|
||||
assert.True(t, gotArea)
|
||||
assert.True(t, gotHello)
|
||||
assert.True(t, gotUses)
|
||||
}
|
||||
|
||||
func TestPascalExtractor_EmptyInput(t *testing.T) {
|
||||
res, err := NewPascalExtractor().Extract("e.pas", []byte(""))
|
||||
require.NoError(t, err)
|
||||
require.Len(t, res.Nodes, 1)
|
||||
assert.Equal(t, graph.KindFile, res.Nodes[0].Kind)
|
||||
}
|
||||
|
||||
// TestPascalParenlessCallEdges is the C1 named test: the tree-sitter extractor
|
||||
// emits call edges for both parenthesised (`Compute(x)`) and paren-less (`Baz;`)
|
||||
// calls — the sharpest regression, since the old regex extractor emitted zero —
|
||||
// and resolves same-file callees directly to their definition at a higher
|
||||
// provenance tier than an unresolved external call.
|
||||
func TestPascalParenlessCallEdges(t *testing.T) {
|
||||
src := []byte(`unit MyUnit;
|
||||
interface
|
||||
type
|
||||
TFoo = class
|
||||
public
|
||||
function Bar(x: Integer): string;
|
||||
procedure Baz;
|
||||
end;
|
||||
implementation
|
||||
function TFoo.Bar(x: Integer): string;
|
||||
begin
|
||||
Result := Compute(x);
|
||||
Baz;
|
||||
end;
|
||||
procedure TFoo.Baz;
|
||||
begin
|
||||
DoThing;
|
||||
end;
|
||||
end.
|
||||
`)
|
||||
res, err := NewPascalExtractor().Extract("MyUnit.pas", src)
|
||||
require.NoError(t, err)
|
||||
|
||||
type edge struct {
|
||||
from, to string
|
||||
origin string
|
||||
}
|
||||
var calls []edge
|
||||
for _, e := range res.Edges {
|
||||
if e.Kind == graph.EdgeCalls {
|
||||
calls = append(calls, edge{e.From, e.To, e.Origin})
|
||||
}
|
||||
}
|
||||
|
||||
has := func(from, to, origin string) bool {
|
||||
for _, c := range calls {
|
||||
if c.from == from && c.to == to && c.origin == origin {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Parenthesised call to an external proc — unresolved, name-only tier.
|
||||
assert.True(t, has("MyUnit.pas::TFoo.Bar", "unresolved::*.Compute", graph.OriginTextMatched),
|
||||
"parenthesised call Compute(x) should emit an edge; got %v", calls)
|
||||
// Paren-less call to a same-file method — resolved directly, higher tier.
|
||||
assert.True(t, has("MyUnit.pas::TFoo.Bar", "MyUnit.pas::TFoo.Baz", graph.OriginASTResolved),
|
||||
"paren-less call Baz; should resolve in-file to TFoo.Baz; got %v", calls)
|
||||
// Paren-less call to an external proc — unresolved.
|
||||
assert.True(t, has("MyUnit.pas::TFoo.Baz", "unresolved::*.DoThing", graph.OriginTextMatched),
|
||||
"paren-less call DoThing; should emit an edge; got %v", calls)
|
||||
}
|
||||
|
||||
func TestPascalExtractor_FactoryChainReceiver(t *testing.T) {
|
||||
src := []byte("procedure Run;\nbegin\n Builder().WithX().Build();\nend;\n")
|
||||
res, err := NewPascalExtractor().Extract("w.pas", src)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var build *graph.Edge
|
||||
seen := map[string]int{}
|
||||
for _, e := range res.Edges {
|
||||
if e.Kind == graph.EdgeCalls {
|
||||
seen[e.To]++
|
||||
if e.To == "unresolved::*.Build" {
|
||||
build = e
|
||||
}
|
||||
}
|
||||
}
|
||||
if build == nil {
|
||||
t.Fatal("Build() call edge not found")
|
||||
}
|
||||
if got, _ := build.Meta["receiver_expr"].(string); got != "Builder().WithX()" {
|
||||
t.Errorf("receiver_expr = %q, want Builder().WithX()", got)
|
||||
}
|
||||
if seen["unresolved::*.Build"] != 1 {
|
||||
t.Errorf("Build() emitted %d times, want exactly 1", seen["unresolved::*.Build"])
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user