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
111 lines
3.9 KiB
Go
111 lines
3.9 KiB
Go
package resolver
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/zzet/gortex/internal/graph"
|
|
)
|
|
|
|
// myBatisTestGraph builds the minimal shape ResolveMyBatisCalls consumes:
|
|
// a SQL-statement node with a mybatis.mapper placeholder call edge, plus a
|
|
// Java DAO interface method node it should land on.
|
|
type myBatisTestGraph struct {
|
|
g graph.Store
|
|
}
|
|
|
|
func newMyBatisTestGraph() *myBatisTestGraph { return &myBatisTestGraph{g: graph.New()} }
|
|
|
|
// addStatement adds the mapper-XML statement node and its placeholder call
|
|
// edge, exactly as the MyBatis extractor would emit them.
|
|
func (b *myBatisTestGraph) addStatement(namespace, stmtID, filePath string) (*graph.Node, *graph.Edge) {
|
|
nodeID := namespace + "::" + stmtID
|
|
n := &graph.Node{
|
|
ID: nodeID, Kind: graph.KindMethod, Name: stmtID,
|
|
FilePath: filePath, Language: "mybatis",
|
|
Meta: map[string]any{
|
|
"mybatis_namespace": namespace,
|
|
"mybatis_statement": stmtID,
|
|
"mybatis_sql_kind": "select",
|
|
},
|
|
}
|
|
b.g.AddNode(n)
|
|
e := &graph.Edge{
|
|
From: nodeID, To: myBatisStubPlaceholder(namespace, stmtID),
|
|
Kind: graph.EdgeCalls, FilePath: filePath, Line: 4,
|
|
Meta: map[string]any{
|
|
"via": "mybatis.mapper",
|
|
"mybatis_namespace": namespace,
|
|
"mybatis_statement": stmtID,
|
|
},
|
|
}
|
|
b.g.AddEdge(e)
|
|
return n, e
|
|
}
|
|
|
|
// addJavaMethod adds a Java DAO/Mapper interface method node shaped like
|
|
// the Java extractor's output: ID `<filePath>::<Class>.<method>` with a
|
|
// `receiver` Meta.
|
|
func (b *myBatisTestGraph) addJavaMethod(filePath, class, method, repo string) *graph.Node {
|
|
id := filePath + "::" + class + "." + method
|
|
n := &graph.Node{
|
|
ID: id, Kind: graph.KindMethod, Name: method,
|
|
FilePath: filePath, RepoPrefix: repo, Language: "java",
|
|
Meta: map[string]any{"receiver": class},
|
|
}
|
|
b.g.AddNode(n)
|
|
return n
|
|
}
|
|
|
|
func TestResolveMyBatisCalls_LandsOnJavaMethod(t *testing.T) {
|
|
b := newMyBatisTestGraph()
|
|
_, stubEdge := b.addStatement("com.app.UserMapper", "findUser", "mappers/UserMapper.xml")
|
|
javaMethod := b.addJavaMethod("src/com/app/UserMapper.java", "UserMapper", "findUser", "")
|
|
// A same-named method on an unrelated class must not be matched.
|
|
b.addJavaMethod("src/com/app/OrderMapper.java", "OrderMapper", "findUser", "")
|
|
|
|
resolved := ResolveMyBatisCalls(b.g)
|
|
require.Equal(t, 1, resolved)
|
|
|
|
require.Equal(t, javaMethod.ID, stubEdge.To, "stub edge should land on the Java DAO method")
|
|
require.Equal(t, graph.OriginASTInferred, stubEdge.Origin)
|
|
require.Equal(t, "mybatis", stubEdge.Meta["synthesized_by"])
|
|
require.Equal(t, "heuristic", stubEdge.Meta["provenance"])
|
|
}
|
|
|
|
func TestResolveMyBatisCalls_Idempotent(t *testing.T) {
|
|
b := newMyBatisTestGraph()
|
|
_, stubEdge := b.addStatement("com.app.UserMapper", "findUser", "mappers/UserMapper.xml")
|
|
javaMethod := b.addJavaMethod("src/com/app/UserMapper.java", "UserMapper", "findUser", "")
|
|
|
|
require.Equal(t, 1, ResolveMyBatisCalls(b.g))
|
|
require.Equal(t, 1, ResolveMyBatisCalls(b.g)) // stable re-run
|
|
require.Equal(t, javaMethod.ID, stubEdge.To)
|
|
}
|
|
|
|
func TestResolveMyBatisCalls_NoMatchStaysPlaceholder(t *testing.T) {
|
|
b := newMyBatisTestGraph()
|
|
_, stubEdge := b.addStatement("com.app.UserMapper", "findUser", "mappers/UserMapper.xml")
|
|
// No matching Java method present.
|
|
|
|
require.Equal(t, 0, ResolveMyBatisCalls(b.g))
|
|
require.Equal(t, myBatisStubPlaceholder("com.app.UserMapper", "findUser"), stubEdge.To)
|
|
require.Empty(t, stubEdge.Origin)
|
|
require.Nil(t, stubEdge.Meta["synthesized_by"])
|
|
}
|
|
|
|
func TestResolveMyBatisCalls_PrefersSameRepo(t *testing.T) {
|
|
b := newMyBatisTestGraph()
|
|
stmt, stubEdge := b.addStatement("com.app.UserMapper", "findUser", "mappers/UserMapper.xml")
|
|
// Place the statement's caller (the From node) in repo "svc-a".
|
|
stmt.RepoPrefix = "svc-a"
|
|
b.g.AddNode(stmt)
|
|
|
|
want := b.addJavaMethod("a/com/app/UserMapper.java", "UserMapper", "findUser", "svc-a")
|
|
b.addJavaMethod("b/com/app/UserMapper.java", "UserMapper", "findUser", "svc-b")
|
|
|
|
require.Equal(t, 1, ResolveMyBatisCalls(b.g))
|
|
require.Equal(t, want.ID, stubEdge.To)
|
|
}
|