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

177 lines
4.7 KiB
Go

package semantic
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/zzet/gortex/internal/graph"
)
func TestSymbolMap(t *testing.T) {
m := NewSymbolMap()
m.Add("scip::Foo", "main.go::Foo")
m.Add("scip::Bar", "lib.go::Bar")
assert.Equal(t, 2, m.Size())
id, ok := m.GortexID("scip::Foo")
assert.True(t, ok)
assert.Equal(t, "main.go::Foo", id)
ext, ok := m.ExternalID("lib.go::Bar")
assert.True(t, ok)
assert.Equal(t, "scip::Bar", ext)
_, ok = m.GortexID("scip::Unknown")
assert.False(t, ok)
}
func TestMatchNodeByFileLine(t *testing.T) {
g := graph.New()
g.AddNode(&graph.Node{
ID: "main.go::main", Kind: graph.KindFunction, Name: "main",
FilePath: "main.go", StartLine: 10, EndLine: 20,
})
g.AddNode(&graph.Node{
ID: "main.go::helper", Kind: graph.KindFunction, Name: "helper",
FilePath: "main.go", StartLine: 22, EndLine: 30,
})
g.AddNode(&graph.Node{
ID: "main.go", Kind: graph.KindFile, Name: "main.go",
FilePath: "main.go", StartLine: 1, EndLine: 30,
})
// Exact start line match.
n := MatchNodeByFileLine(g, "main.go", 10)
assert.NotNil(t, n)
assert.Equal(t, "main.go::main", n.ID)
// Within range.
n = MatchNodeByFileLine(g, "main.go", 15)
assert.NotNil(t, n)
assert.Equal(t, "main.go::main", n.ID)
// Second function.
n = MatchNodeByFileLine(g, "main.go", 25)
assert.NotNil(t, n)
assert.Equal(t, "main.go::helper", n.ID)
// Line in gap between functions — may or may not find a match.
n = MatchNodeByFileLine(g, "main.go", 21)
// Within tolerance of 2 lines from helper (line 22), should find it.
if n != nil {
assert.Equal(t, "main.go::helper", n.ID)
}
}
func TestMatchNodeByQualName(t *testing.T) {
g := graph.New()
g.AddNode(&graph.Node{
ID: "main.go::Foo", Kind: graph.KindFunction, Name: "Foo",
QualName: "github.com/test/pkg.Foo", FilePath: "main.go",
})
n := MatchNodeByQualName(g, "github.com/test/pkg.Foo")
assert.NotNil(t, n)
assert.Equal(t, "main.go::Foo", n.ID)
n = MatchNodeByQualName(g, "unknown")
assert.Nil(t, n)
}
func TestMatchNodeByNameInFile(t *testing.T) {
g := graph.New()
g.AddNode(&graph.Node{
ID: "main.go::Foo", Kind: graph.KindFunction, Name: "Foo",
FilePath: "main.go",
})
n := MatchNodeByNameInFile(g, "Foo", "main.go")
assert.NotNil(t, n)
assert.Equal(t, "main.go::Foo", n.ID)
n = MatchNodeByNameInFile(g, "Foo", "other.go")
assert.Nil(t, n)
}
func TestParseGortexID(t *testing.T) {
tests := []struct {
id string
wantFile string
wantSym string
}{
{"main.go::Foo", "main.go", "Foo"},
{"pkg/auth/token.go::ValidateToken", "pkg/auth/token.go", "ValidateToken"},
{"main.go", "main.go", ""},
}
for _, tt := range tests {
file, sym := ParseGortexID(tt.id)
assert.Equal(t, tt.wantFile, file, "file for %s", tt.id)
assert.Equal(t, tt.wantSym, sym, "sym for %s", tt.id)
}
}
func TestNormalizeFilePath(t *testing.T) {
result := NormalizeFilePath("/home/user/repo/pkg/foo.go", "/home/user/repo")
assert.Equal(t, "pkg/foo.go", result)
}
func TestMatchCallableByFileLine(t *testing.T) {
g := graph.New()
// Function with a param decoy sharing its declaration line — the
// zero-height param span wins MatchNodeByFileLine's innermost tie,
// which is exactly what the callable matcher must NOT return.
g.AddNode(&graph.Node{
ID: "a.go::TestFoo", Kind: graph.KindFunction, Name: "TestFoo",
FilePath: "a.go", StartLine: 10, EndLine: 20,
})
g.AddNode(&graph.Node{
ID: "a.go::TestFoo#param:t", Kind: graph.KindParam, Name: "t",
FilePath: "a.go", StartLine: 10, EndLine: 10,
})
g.AddNode(&graph.Node{
ID: "a.go::TestFoo#closure:1", Kind: graph.KindClosure, Name: "closure",
FilePath: "a.go", StartLine: 14, EndLine: 16,
})
g.AddNode(&graph.Node{
ID: "a.go::Recv.M", Kind: graph.KindMethod, Name: "M",
FilePath: "a.go", StartLine: 25, EndLine: 27,
})
g.AddNode(&graph.Node{
ID: "a.go::topVar", Kind: graph.KindVariable, Name: "topVar",
FilePath: "a.go", StartLine: 40, EndLine: 40,
})
g.AddNode(&graph.Node{
ID: "a.go", Kind: graph.KindFile, Name: "a.go",
FilePath: "a.go", StartLine: 1, EndLine: 50,
})
cases := []struct {
name string
line int
want string // "" = nil expected
}{
{"declaration line beats param decoy", 10, "a.go::TestFoo"},
{"body line inside function", 12, "a.go::TestFoo"},
{"innermost closure wins inside its span", 15, "a.go::TestFoo#closure:1"},
{"method declaration line", 25, "a.go::Recv.M"},
{"near-miss within tolerance snaps to method", 23, "a.go::Recv.M"},
{"variable line far from any callable", 40, ""},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
n := MatchCallableByFileLine(g, "a.go", tc.line)
if tc.want == "" {
assert.Nil(t, n)
return
}
if assert.NotNil(t, n) {
assert.Equal(t, tc.want, n.ID)
}
})
}
}