1
+ import { describe , it , expect } from "vitest" ;
2
+ import { GoSymbolExtractor } from "./go-symbol-extractor" ;
3
+ import { FunctionSymbol , TypeSymbol } from "./types" ;
4
+
5
+ const extractor = new GoSymbolExtractor ( ) ;
6
+
7
+ function extractFunctionSymbols ( code : string ) : FunctionSymbol [ ] {
8
+ const symbols = extractor [ "extractFromFile" ] ( "test.go" , code ) ;
9
+ return symbols . filter ( ( s ) => s . type === "function" ) as FunctionSymbol [ ] ;
10
+ }
11
+
12
+ function extractTypeSymbols ( code : string ) : TypeSymbol [ ] {
13
+ const symbols = extractor [ "extractFromFile" ] ( "test.go" , code ) ;
14
+ return symbols . filter ( ( s ) => s . type === "type" ) as TypeSymbol [ ] ;
15
+ }
16
+
17
+ describe ( "go-symbol-extractor" , ( ) => {
18
+ describe ( "FunctionSymbol" , ( ) => {
19
+ it ( "should extract a simple function" , ( ) => {
20
+ const code = `
21
+ package main
22
+
23
+ func Hello() {
24
+ }
25
+ ` ;
26
+ const [ symbol ] = extractFunctionSymbols ( code ) ;
27
+ expect ( symbol ) . toBeDefined ( ) ;
28
+ expect ( symbol ?. name ) . toBe ( "Hello" ) ;
29
+ expect ( symbol ?. type ) . toBe ( "function" ) ;
30
+ expect ( symbol ?. meta . returnType ) . toBe ( "void" ) ;
31
+ expect ( symbol ?. meta . parameters ) . toHaveLength ( 0 ) ;
32
+ expect ( symbol ?. meta . isAsync ) . toBe ( false ) ;
33
+ expect ( symbol ?. meta . isStatic ) . toBe ( true ) ;
34
+ } ) ;
35
+
36
+ it ( "should extract a function with parameters" , ( ) => {
37
+ const code = `
38
+ package main
39
+
40
+ func Add(a int, b int) int {
41
+ return a + b
42
+ }
43
+ ` ;
44
+ const [ symbol ] = extractFunctionSymbols ( code ) ;
45
+ expect ( symbol ) . toBeDefined ( ) ;
46
+ expect ( symbol ?. name ) . toBe ( "Add" ) ;
47
+ expect ( symbol ?. type ) . toBe ( "function" ) ;
48
+ expect ( symbol ?. meta . returnType ) . toBe ( "int" ) ;
49
+ expect ( symbol ?. meta . parameters ) . toHaveLength ( 2 ) ;
50
+ expect ( symbol ?. meta . parameters ) . toEqual ( [
51
+ {
52
+ name : "a" ,
53
+ type : "int" ,
54
+ optional : false ,
55
+ } ,
56
+ {
57
+ name : "b" ,
58
+ type : "int" ,
59
+ optional : false ,
60
+ } ,
61
+ ] ) ;
62
+ } ) ;
63
+
64
+ it ( "should extract a function with multiple return types" , ( ) => {
65
+ const code = `
66
+ package main
67
+
68
+ func Divide(a int, b int) (int, error) {
69
+ if b == 0 {
70
+ return 0, errors.New("division by zero")
71
+ }
72
+ return a / b, nil
73
+ }
74
+ ` ;
75
+ const [ symbol ] = extractFunctionSymbols ( code ) ;
76
+ expect ( symbol ) . toBeDefined ( ) ;
77
+ expect ( symbol ?. name ) . toBe ( "Divide" ) ;
78
+ expect ( symbol ?. type ) . toBe ( "function" ) ;
79
+ expect ( symbol ?. meta . returnType ) . toBe ( "(int, error)" ) ;
80
+ expect ( symbol ?. meta . parameters ) . toHaveLength ( 2 ) ;
81
+ } ) ;
82
+
83
+ it ( "should extract a function with pointer parameters" , ( ) => {
84
+ const code = `
85
+ package main
86
+
87
+ func Process(data *string) *int {
88
+ return nil
89
+ }
90
+ ` ;
91
+ const [ symbol ] = extractFunctionSymbols ( code ) ;
92
+ expect ( symbol ) . toBeDefined ( ) ;
93
+ expect ( symbol ?. name ) . toBe ( "Process" ) ;
94
+ expect ( symbol ?. type ) . toBe ( "function" ) ;
95
+ expect ( symbol ?. meta . returnType ) . toBe ( "*int" ) ;
96
+ expect ( symbol ?. meta . parameters ) . toHaveLength ( 1 ) ;
97
+ expect ( symbol ?. meta . parameters [ 0 ] ) . toEqual ( {
98
+ name : "data" ,
99
+ type : "*string" ,
100
+ optional : false ,
101
+ } ) ;
102
+ } ) ;
103
+
104
+ it ( "should extract a method declaration" , ( ) => {
105
+ const code = `
106
+ package main
107
+
108
+ type Person struct {
109
+ Name string
110
+ }
111
+
112
+ func (p *Person) GetName() string {
113
+ return p.Name
114
+ }
115
+ ` ;
116
+ const [ symbol ] = extractFunctionSymbols ( code ) ;
117
+ expect ( symbol ) . toBeDefined ( ) ;
118
+ expect ( symbol ?. name ) . toBe ( "GetName" ) ;
119
+ expect ( symbol ?. type ) . toBe ( "function" ) ;
120
+ expect ( symbol ?. meta . returnType ) . toBe ( "string" ) ;
121
+ expect ( symbol ?. meta . isStatic ) . toBe ( false ) ; // methods are not static
122
+ } ) ;
123
+
124
+ it ( "should not extract unexported functions" , ( ) => {
125
+ const code = `
126
+ package main
127
+
128
+ func hello() {
129
+ }
130
+
131
+ func Hello() {
132
+ }
133
+ ` ;
134
+ const symbols = extractFunctionSymbols ( code ) ;
135
+ expect ( symbols ) . toHaveLength ( 1 ) ;
136
+ expect ( symbols [ 0 ] ?. name ) . toBe ( "Hello" ) ;
137
+ } ) ;
138
+
139
+ it ( "should extract multiple functions" , ( ) => {
140
+ const code = `
141
+ package main
142
+
143
+ func First() {
144
+ }
145
+
146
+ func Second() {
147
+ }
148
+
149
+ func Third() {
150
+ }
151
+ ` ;
152
+ const symbols = extractFunctionSymbols ( code ) ;
153
+ expect ( symbols ) . toHaveLength ( 3 ) ;
154
+ expect ( symbols [ 0 ] ?. name ) . toBe ( "First" ) ;
155
+ expect ( symbols [ 1 ] ?. name ) . toBe ( "Second" ) ;
156
+ expect ( symbols [ 2 ] ?. name ) . toBe ( "Third" ) ;
157
+ } ) ;
158
+ } ) ;
159
+
160
+ describe ( "TypeSymbol" , ( ) => {
161
+ it ( "should extract a simple type alias" , ( ) => {
162
+ const code = `
163
+ package main
164
+
165
+ type UserID string
166
+ ` ;
167
+ const [ symbol ] = extractTypeSymbols ( code ) ;
168
+ expect ( symbol ) . toBeDefined ( ) ;
169
+ expect ( symbol ?. name ) . toBe ( "UserID" ) ;
170
+ expect ( symbol ?. type ) . toBe ( "type" ) ;
171
+ expect ( symbol ?. meta . kind ) . toBe ( "alias" ) ;
172
+ } ) ;
173
+
174
+ it ( "should extract a struct type" , ( ) => {
175
+ const code = `
176
+ package main
177
+
178
+ type User struct {
179
+ ID int
180
+ Name string
181
+ }
182
+ ` ;
183
+ const [ symbol ] = extractTypeSymbols ( code ) ;
184
+ expect ( symbol ) . toBeDefined ( ) ;
185
+ expect ( symbol ?. name ) . toBe ( "User" ) ;
186
+ expect ( symbol ?. type ) . toBe ( "type" ) ;
187
+ expect ( symbol ?. meta . kind ) . toBe ( "type" ) ;
188
+ } ) ;
189
+
190
+ it ( "should extract an interface type" , ( ) => {
191
+ const code = `
192
+ package main
193
+
194
+ type Writer interface {
195
+ Write([]byte) (int, error)
196
+ }
197
+ ` ;
198
+ const [ symbol ] = extractTypeSymbols ( code ) ;
199
+ expect ( symbol ) . toBeDefined ( ) ;
200
+ expect ( symbol ?. name ) . toBe ( "Writer" ) ;
201
+ expect ( symbol ?. type ) . toBe ( "type" ) ;
202
+ expect ( symbol ?. meta . kind ) . toBe ( "interface" ) ;
203
+ } ) ;
204
+
205
+ it ( "should extract multiple types" , ( ) => {
206
+ const code = `
207
+ package main
208
+
209
+ type UserID string
210
+
211
+ type User struct {
212
+ ID UserID
213
+ Name string
214
+ }
215
+
216
+ type UserRepo interface {
217
+ GetUser(id UserID) (*User, error)
218
+ }
219
+ ` ;
220
+ const symbols = extractTypeSymbols ( code ) ;
221
+ expect ( symbols ) . toHaveLength ( 3 ) ;
222
+ expect ( symbols [ 0 ] ?. name ) . toBe ( "UserID" ) ;
223
+ expect ( symbols [ 0 ] ?. meta . kind ) . toBe ( "alias" ) ;
224
+ expect ( symbols [ 1 ] ?. name ) . toBe ( "User" ) ;
225
+ expect ( symbols [ 1 ] ?. meta . kind ) . toBe ( "type" ) ;
226
+ expect ( symbols [ 2 ] ?. name ) . toBe ( "UserRepo" ) ;
227
+ expect ( symbols [ 2 ] ?. meta . kind ) . toBe ( "interface" ) ;
228
+ } ) ;
229
+
230
+ it ( "should not extract unexported types" , ( ) => {
231
+ const code = `
232
+ package main
233
+
234
+ type userID string
235
+
236
+ type User struct {
237
+ ID userID
238
+ Name string
239
+ }
240
+ ` ;
241
+ const symbols = extractTypeSymbols ( code ) ;
242
+ expect ( symbols ) . toHaveLength ( 1 ) ;
243
+ expect ( symbols [ 0 ] ?. name ) . toBe ( "User" ) ;
244
+ } ) ;
245
+
246
+ it ( "should extract a type with definition" , ( ) => {
247
+ const code = `
248
+ package main
249
+
250
+ type Status int
251
+
252
+ const (
253
+ Active Status = iota
254
+ Inactive
255
+ )
256
+ ` ;
257
+ const [ symbol ] = extractTypeSymbols ( code ) ;
258
+ expect ( symbol ) . toBeDefined ( ) ;
259
+ expect ( symbol ?. name ) . toBe ( "Status" ) ;
260
+ expect ( symbol ?. type ) . toBe ( "type" ) ;
261
+ expect ( symbol ?. meta . kind ) . toBe ( "alias" ) ;
262
+ expect ( symbol ?. meta . definition ) . toContain ( "type Status int" ) ;
263
+ } ) ;
264
+ } ) ;
265
+
266
+ describe ( "Combined extraction" , ( ) => {
267
+ it ( "should extract both functions and types from the same code" , ( ) => {
268
+ const code = `
269
+ package main
270
+
271
+ type User struct {
272
+ ID int
273
+ Name string
274
+ }
275
+
276
+ func NewUser(id int, name string) *User {
277
+ return &User{ID: id, Name: name}
278
+ }
279
+
280
+ func (u *User) GetName() string {
281
+ return u.Name
282
+ }
283
+
284
+ type UserRepo interface {
285
+ GetUser(id int) (*User, error)
286
+ }
287
+ ` ;
288
+ const allSymbols = extractor [ "extractFromFile" ] ( "test.go" , code ) ;
289
+ const functions = allSymbols . filter ( ( s ) => s . type === "function" ) ;
290
+ const types = allSymbols . filter ( ( s ) => s . type === "type" ) ;
291
+
292
+ expect ( functions ) . toHaveLength ( 2 ) ;
293
+ expect ( types ) . toHaveLength ( 2 ) ;
294
+
295
+ expect ( functions [ 0 ] ?. name ) . toBe ( "NewUser" ) ;
296
+ expect ( functions [ 1 ] ?. name ) . toBe ( "GetName" ) ;
297
+ expect ( types [ 0 ] ?. name ) . toBe ( "User" ) ;
298
+ expect ( types [ 1 ] ?. name ) . toBe ( "UserRepo" ) ;
299
+ } ) ;
300
+ } ) ;
301
+ } ) ;
0 commit comments