1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
|
package tuigen
import (
"testing"
)
func TestPackageContext_AddGoSource(t *testing.T) {
type tc struct {
src string
wantMethods map[string][]string
wantNotMethods map[string][]string
wantFuncs []string
wantTypes []string
}
tests := map[string]tc{
"pointer receiver method": {
src: `package x
import tui "github.com/grindlemire/go-tui"
func (r *row) UpdateProps(fresh tui.Component) {}`,
wantMethods: map[string][]string{"row": {"UpdateProps"}},
},
"value receiver method": {
src: `package x
func (r row) BindApp(app *App) {}`,
wantMethods: map[string][]string{"row": {"BindApp"}},
},
"unnamed receiver method": {
src: `package x
func (*row) UnbindApp() {}`,
wantMethods: map[string][]string{"row": {"UnbindApp"}},
},
"generic receiver method": {
src: `package x
func (r *box[T]) UpdateProps(fresh Component) {}`,
wantMethods: map[string][]string{"box": {"UpdateProps"}},
},
"plain function is not a method": {
src: `package x
func UpdateProps() {}`,
wantFuncs: []string{"UpdateProps"},
wantNotMethods: map[string][]string{"row": {"UpdateProps"}},
},
"type declarations including grouped": {
src: `package x
type FooView struct{ n int }
type (
BarView int
other string
)`,
wantTypes: []string{"FooView", "BarView", "other"},
},
"method mentioned only in a comment is ignored": {
src: `package x
// func (r *row) UpdateProps(fresh tui.Component) {}
func helper() {}`,
wantFuncs: []string{"helper"},
wantNotMethods: map[string][]string{"row": {"UpdateProps"}},
},
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
ctx := NewPackageContext()
if err := ctx.AddGoSource("sibling.go", tt.src); err != nil {
t.Fatalf("AddGoSource failed: %v", err)
}
for typeName, methods := range tt.wantMethods {
for _, m := range methods {
if !ctx.HasMethod(typeName, m) {
t.Errorf("HasMethod(%q, %q) = false, want true", typeName, m)
}
}
}
for typeName, methods := range tt.wantNotMethods {
for _, m := range methods {
if ctx.HasMethod(typeName, m) {
t.Errorf("HasMethod(%q, %q) = true, want false", typeName, m)
}
}
}
for _, f := range tt.wantFuncs {
if !ctx.HasFunc(f) {
t.Errorf("HasFunc(%q) = false, want true", f)
}
}
for _, ty := range tt.wantTypes {
if !ctx.HasType(ty) {
t.Errorf("HasType(%q) = false, want true", ty)
}
}
})
}
}
func TestPackageContext_AddGoSource_ParseError(t *testing.T) {
ctx := NewPackageContext()
if err := ctx.AddGoSource("bad.go", "package x\nfunc ("); err == nil {
t.Error("expected parse error, got nil")
}
}
func TestPackageContext_AddGSXFile(t *testing.T) {
input := `package x
import tui "github.com/grindlemire/go-tui"
type helper struct{}
func topLevel() string { return "x" }
func (h *helper) UpdateProps(fresh tui.Component) {}
templ FnTempl() {
<span>hi</span>
}
templ (h *helper) Render() {
<span>hi</span>
}`
lexer := NewLexer("sibling.gsx", input)
parser := NewParser(lexer)
file, err := parser.ParseFile()
if err != nil {
t.Fatalf("parse failed: %v", err)
}
ctx := NewPackageContext()
ctx.AddGSXFile(file)
if !ctx.HasFunc("topLevel") {
t.Error("HasFunc(topLevel) = false, want true")
}
if !ctx.HasType("helper") {
t.Error("HasType(helper) = false, want true")
}
if !ctx.HasMethod("helper", "UpdateProps") {
t.Error("HasMethod(helper, UpdateProps) = false, want true")
}
if !ctx.HasTempl("FnTempl") {
t.Error("HasTempl(FnTempl) = false, want true")
}
if !ctx.HasRenderTempl("helper") {
t.Error("HasRenderTempl(helper) = false, want true")
}
if ctx.HasTempl("helper") {
t.Error("HasTempl(helper) = true, want false (method templ, not function templ)")
}
}
|