Files
zzet--gortex/internal/codegen/annotations_test.go
T
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

175 lines
7.2 KiB
Go

package codegen
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/zzet/gortex/internal/graph"
)
func annoNode(id, name string) *graph.Node {
return &graph.Node{ID: id, Kind: graph.KindType, Name: name, Meta: map[string]any{"kind": "annotation"}}
}
func TestMarkAnnotatedGenerated_Lombok(t *testing.T) {
nodes := []*graph.Node{
{ID: "User.java::User", Kind: graph.KindType, Name: "User", FilePath: "User.java"},
annoNode("annotation::java::Data", "Data"),
}
edges := []*graph.Edge{
{From: "User.java::User", To: "annotation::java::Data", Kind: graph.EdgeAnnotated},
}
extra, stats := MarkAnnotatedGenerated(nodes, edges)
require.Equal(t, 1, stats.NodesMarked)
require.Len(t, extra, 1)
require.Equal(t, graph.EdgeGeneratedBy, extra[0].Kind)
require.Equal(t, "external::generator-tool:lombok", extra[0].To)
host := nodes[0]
require.Equal(t, true, host.Meta["has_generated_members"])
require.Equal(t, "lombok", host.Meta["codegen_tool"])
require.Contains(t, host.Meta["generated_members"].([]string), "getters")
}
func TestMarkAnnotatedGenerated_MapStruct(t *testing.T) {
nodes := []*graph.Node{
{ID: "M.java::M", Kind: graph.KindInterface, Name: "M", FilePath: "M.java"},
annoNode("annotation::java::Mapper", "org.mapstruct.Mapper"),
}
edges := []*graph.Edge{{From: "M.java::M", To: "annotation::java::Mapper", Kind: graph.EdgeAnnotated}}
_, stats := MarkAnnotatedGenerated(nodes, edges)
require.Equal(t, 1, stats.NodesMarked)
require.Equal(t, "mapstruct", nodes[0].Meta["codegen_tool"])
}
func TestMarkAnnotatedGenerated_IgnoresNonCodegen(t *testing.T) {
nodes := []*graph.Node{
{ID: "C.java::C", Kind: graph.KindType, Name: "C"},
annoNode("annotation::java::Override", "Override"),
}
edges := []*graph.Edge{{From: "C.java::C", To: "annotation::java::Override", Kind: graph.EdgeAnnotated}}
extra, stats := MarkAnnotatedGenerated(nodes, edges)
require.Equal(t, 0, stats.NodesMarked)
require.Empty(t, extra)
require.Nil(t, nodes[0].Meta)
}
func TestMarkAnnotatedGenerated_MergesAndDedups(t *testing.T) {
nodes := []*graph.Node{
{ID: "C::C", Kind: graph.KindType, Name: "C"},
annoNode("annotation::java::Getter", "Getter"),
annoNode("annotation::java::Setter", "Setter"),
}
edges := []*graph.Edge{
{From: "C::C", To: "annotation::java::Getter", Kind: graph.EdgeAnnotated},
{From: "C::C", To: "annotation::java::Setter", Kind: graph.EdgeAnnotated},
}
extra, stats := MarkAnnotatedGenerated(nodes, edges)
require.Equal(t, 2, stats.NodesMarked)
require.Len(t, extra, 1, "one EdgeGeneratedBy per (symbol, tool)")
members := nodes[0].Meta["generated_members"].([]string)
require.Contains(t, members, "getters")
require.Contains(t, members, "setters")
}
func TestMarkAnnotatedGenerated_MVVMSourceGenerators(t *testing.T) {
nodes := []*graph.Node{
{ID: "vm.cs::name", Kind: graph.KindField, Name: "name", FilePath: "vm.cs"},
annoNode("annotation::csharp::ObservableProperty", "ObservableProperty"),
}
edges := []*graph.Edge{
{From: "vm.cs::name", To: "annotation::csharp::ObservableProperty", Kind: graph.EdgeAnnotated},
}
_, stats := MarkAnnotatedGenerated(nodes, edges)
require.Equal(t, 1, stats.NodesMarked)
require.Equal(t, "mvvm_toolkit", nodes[0].Meta["codegen_tool"])
require.Contains(t, nodes[0].Meta["generated_members"].([]string), "observable_property")
}
func TestNormalizeAnnotationName(t *testing.T) {
require.Equal(t, "Data", normalizeAnnotationName("@Data"))
require.Equal(t, "Data", normalizeAnnotationName("lombok.Data"))
require.Equal(t, "Mapper", normalizeAnnotationName(" @org.mapstruct.Mapper "))
}
func TestMaterializeLombokAccessors_GettersSetters(t *testing.T) {
nodes := []*graph.Node{
{ID: "User.java::User", Kind: graph.KindType, Name: "User", FilePath: "User.java"},
annoNode("annotation::java::Data", "Data"),
{ID: "User.java::User.name", Kind: graph.KindField, Name: "name", FilePath: "User.java", Meta: map[string]any{"receiver": "User", "field_type": "String"}},
{ID: "User.java::User.active", Kind: graph.KindField, Name: "active", FilePath: "User.java", Meta: map[string]any{"receiver": "User", "field_type": "boolean"}},
}
edges := []*graph.Edge{{From: "User.java::User", To: "annotation::java::Data", Kind: graph.EdgeAnnotated}}
MarkAnnotatedGenerated(nodes, edges)
newNodes, newEdges := MaterializeLombokAccessors(nodes)
byID := map[string]*graph.Node{}
for _, n := range newNodes {
byID[n.ID] = n
}
getName := byID["User.java::User.getName"]
require.NotNil(t, getName, "getName accessor minted")
require.Equal(t, graph.KindMethod, getName.Kind)
require.Equal(t, "getName", getName.Name)
require.Equal(t, "User", getName.Meta["receiver"])
require.Equal(t, true, getName.Meta["synthesized"])
require.Equal(t, true, getName.Meta["generated"])
require.Equal(t, "lombok", getName.Meta["codegen_tool"])
require.NotNil(t, byID["User.java::User.setName"], "setName minted")
require.NotNil(t, byID["User.java::User.isActive"], "boolean getter is-prefixed")
require.NotNil(t, byID["User.java::User.setActive"], "boolean setter minted")
var hasDefines, hasGenBy bool
for _, e := range newEdges {
if e.Kind == graph.EdgeDefines && e.From == "User.java::User" && e.To == "User.java::User.getName" {
hasDefines = true
}
if e.Kind == graph.EdgeGeneratedBy && e.From == "User.java::User.getName" && e.To == "external::generator-tool:lombok" {
hasGenBy = true
}
}
require.True(t, hasDefines, "EdgeDefines class→getName")
require.True(t, hasGenBy, "EdgeGeneratedBy getName→lombok")
}
func TestMaterializeLombokAccessors_NoDuplicateHandWrittenWins(t *testing.T) {
nodes := []*graph.Node{
{ID: "U.java::U", Kind: graph.KindType, Name: "U", FilePath: "U.java", Meta: map[string]any{"codegen_tool": "lombok", "generated_members": []string{"getters", "setters"}}},
{ID: "U.java::U.id", Kind: graph.KindField, Name: "id", FilePath: "U.java", Meta: map[string]any{"receiver": "U", "field_type": "int"}},
{ID: "U.java::U.getId", Kind: graph.KindMethod, Name: "getId", FilePath: "U.java", Meta: map[string]any{"receiver": "U"}},
}
newNodes, _ := MaterializeLombokAccessors(nodes)
for _, n := range newNodes {
if n.ID == "U.java::U.getId" {
t.Errorf("hand-written getId must not be re-minted")
}
}
var sawSetId bool
for _, n := range newNodes {
if n.ID == "U.java::U.setId" {
sawSetId = true
}
}
require.True(t, sawSetId, "setId minted (no hand-written version)")
all := append(append([]*graph.Node{}, nodes...), newNodes...)
again, _ := MaterializeLombokAccessors(all)
require.Empty(t, again, "a reindex / re-run mints no duplicate accessors")
}
func TestMaterializeLombokAccessors_BuilderAndLogger(t *testing.T) {
nodes := []*graph.Node{
{ID: "S.java::S", Kind: graph.KindType, Name: "S", FilePath: "S.java", Meta: map[string]any{"codegen_tool": "lombok", "generated_members": []string{"builder", "logger"}}},
}
newNodes, _ := MaterializeLombokAccessors(nodes)
byID := map[string]*graph.Node{}
for _, n := range newNodes {
byID[n.ID] = n
}
require.NotNil(t, byID["S.java::S.builder"], "builder() minted")
require.NotNil(t, byID["S.java::SBuilder"], "Builder type minted")
require.NotNil(t, byID["S.java::S.log"], "log field minted")
require.Equal(t, "org.slf4j.Logger", byID["S.java::S.log"].Meta["field_type"])
}