1
2
3
4
5 package modfile
6
7 import (
8 "bytes"
9 "os"
10 "path/filepath"
11 "strings"
12 "testing"
13 )
14
15
16 var workAddUseTests = []struct {
17 desc string
18 in string
19 path string
20 modulePath string
21 out string
22 }{
23 {
24 `empty`,
25 ``,
26 `foo`, `bar`,
27 `use foo`,
28 },
29 {
30 `go_stmt_only`,
31 `go 1.17
32 `,
33 `foo`, `bar`,
34 `go 1.17
35 use foo
36 `,
37 },
38 {
39 `use_line_present`,
40 `go 1.17
41 use baz`,
42 `foo`, `bar`,
43 `go 1.17
44 use (
45 baz
46 foo
47 )
48 `,
49 },
50 {
51 `use_block_present`,
52 `go 1.17
53 use (
54 baz
55 quux
56 )
57 `,
58 `foo`, `bar`,
59 `go 1.17
60 use (
61 baz
62 quux
63 foo
64 )
65 `,
66 },
67 {
68 `use_and_replace_present`,
69 `go 1.17
70 use baz
71 replace a => ./b
72 `,
73 `foo`, `bar`,
74 `go 1.17
75 use (
76 baz
77 foo
78 )
79 replace a => ./b
80 `,
81 },
82 }
83
84 var workDropUseTests = []struct {
85 desc string
86 in string
87 path string
88 out string
89 }{
90 {
91 `empty`,
92 ``,
93 `foo`,
94 ``,
95 },
96 {
97 `go_stmt_only`,
98 `go 1.17
99 `,
100 `foo`,
101 `go 1.17
102 `,
103 },
104 {
105 `single_use`,
106 `go 1.17
107 use foo`,
108 `foo`,
109 `go 1.17
110 `,
111 },
112 {
113 `use_block`,
114 `go 1.17
115 use (
116 foo
117 bar
118 baz
119 )`,
120 `bar`,
121 `go 1.17
122 use (
123 foo
124 baz
125 )`,
126 },
127 {
128 `use_multi`,
129 `go 1.17
130 use (
131 foo
132 bar
133 baz
134 )
135 use foo
136 use quux
137 use foo`,
138 `foo`,
139 `go 1.17
140 use (
141 bar
142 baz
143 )
144 use quux`,
145 },
146 }
147
148 var workAddGoTests = []struct {
149 desc string
150 in string
151 version string
152 out string
153 }{
154 {
155 `empty`,
156 ``,
157 `1.17`,
158 `go 1.17
159 `,
160 },
161 {
162 `comment`,
163 `// this is a comment`,
164 `1.17`,
165 `// this is a comment
166
167 go 1.17`,
168 },
169 {
170 `use_after_replace`,
171 `
172 replace example.com/foo => ../bar
173 use foo
174 `,
175 `1.17`,
176 `
177 go 1.17
178 replace example.com/foo => ../bar
179 use foo
180 `,
181 },
182 {
183 `use_before_replace`,
184 `use foo
185 replace example.com/foo => ../bar
186 `,
187 `1.17`,
188 `
189 go 1.17
190 use foo
191 replace example.com/foo => ../bar
192 `,
193 },
194 {
195 `use_only`,
196 `use foo
197 `,
198 `1.17`,
199 `
200 go 1.17
201 use foo
202 `,
203 },
204 {
205 `already_have_go`,
206 `go 1.17
207 `,
208 `1.18`,
209 `
210 go 1.18
211 `,
212 },
213 }
214
215 var workAddToolchainTests = []struct {
216 desc string
217 in string
218 version string
219 out string
220 }{
221 {
222 `empty`,
223 ``,
224 `go1.17`,
225 `toolchain go1.17
226 `,
227 },
228 {
229 `aftergo`,
230 `// this is a comment
231 use foo
232
233 go 1.17
234
235 use bar
236 `,
237 `go1.17`,
238 `// this is a comment
239 use foo
240
241 go 1.17
242
243 toolchain go1.17
244
245 use bar
246 `,
247 },
248 {
249 `already_have_toolchain`,
250 `go 1.17
251
252 toolchain go1.18
253 `,
254 `go1.19`,
255 `go 1.17
256
257 toolchain go1.19
258 `,
259 },
260 }
261
262 var workSortBlocksTests = []struct {
263 desc, in, out string
264 }{
265 {
266 `use_duplicates_not_removed`,
267 `go 1.17
268 use foo
269 use bar
270 use (
271 foo
272 )`,
273 `go 1.17
274 use foo
275 use bar
276 use (
277 foo
278 )`,
279 },
280 {
281 `replace_duplicates_removed`,
282 `go 1.17
283 use foo
284 replace x.y/z v1.0.0 => ./a
285 replace x.y/z v1.1.0 => ./b
286 replace (
287 x.y/z v1.0.0 => ./c
288 )
289 `,
290 `go 1.17
291 use foo
292 replace x.y/z v1.1.0 => ./b
293 replace (
294 x.y/z v1.0.0 => ./c
295 )
296 `,
297 },
298 }
299
300 func TestAddUse(t *testing.T) {
301 for _, tt := range workAddUseTests {
302 t.Run(tt.desc, func(t *testing.T) {
303 testWorkEdit(t, tt.in, tt.out, func(f *WorkFile) error {
304 return f.AddUse(tt.path, tt.modulePath)
305 })
306 })
307 }
308 }
309
310 func TestDropUse(t *testing.T) {
311 for _, tt := range workDropUseTests {
312 t.Run(tt.desc, func(t *testing.T) {
313 testWorkEdit(t, tt.in, tt.out, func(f *WorkFile) error {
314 if err := f.DropUse(tt.path); err != nil {
315 return err
316 }
317 f.Cleanup()
318 return nil
319 })
320 })
321 }
322 }
323
324 func TestWorkAddGo(t *testing.T) {
325 for _, tt := range workAddGoTests {
326 t.Run(tt.desc, func(t *testing.T) {
327 testWorkEdit(t, tt.in, tt.out, func(f *WorkFile) error {
328 return f.AddGoStmt(tt.version)
329 })
330 })
331 }
332 }
333
334 func TestWorkAddToolchain(t *testing.T) {
335 for _, tt := range workAddToolchainTests {
336 t.Run(tt.desc, func(t *testing.T) {
337 testWorkEdit(t, tt.in, tt.out, func(f *WorkFile) error {
338 return f.AddToolchainStmt(tt.version)
339 })
340 })
341 }
342 }
343
344 func TestWorkSortBlocks(t *testing.T) {
345 for _, tt := range workSortBlocksTests {
346 t.Run(tt.desc, func(t *testing.T) {
347 testWorkEdit(t, tt.in, tt.out, func(f *WorkFile) error {
348 f.SortBlocks()
349 return nil
350 })
351 })
352 }
353 }
354
355
356
357
358 func TestWorkPrintParse(t *testing.T) {
359 outs, err := filepath.Glob("testdata/work/*")
360 if err != nil {
361 t.Fatal(err)
362 }
363 for _, out := range outs {
364 out := out
365 name := filepath.Base(out)
366 t.Run(name, func(t *testing.T) {
367 t.Parallel()
368 data, err := os.ReadFile(out)
369 if err != nil {
370 t.Fatal(err)
371 }
372
373 base := "testdata/work/" + filepath.Base(out)
374 f, err := parse(base, data)
375 if err != nil {
376 t.Fatalf("parsing original: %v", err)
377 }
378
379 ndata := Format(f)
380 f2, err := parse(base, ndata)
381 if err != nil {
382 t.Fatalf("parsing reformatted: %v", err)
383 }
384
385 eq := eqchecker{file: base}
386 if err := eq.check(f, f2); err != nil {
387 t.Errorf("not equal (parse/Format/parse): %v", err)
388 }
389
390 pf1, err := ParseWork(base, data, nil)
391 if err != nil {
392 t.Errorf("should parse %v: %v", base, err)
393 }
394 if err == nil {
395 pf2, err := ParseWork(base, ndata, nil)
396 if err != nil {
397 t.Fatalf("Parsing reformatted: %v", err)
398 }
399 eq := eqchecker{file: base}
400 if err := eq.check(pf1, pf2); err != nil {
401 t.Errorf("not equal (parse/Format/Parse): %v", err)
402 }
403
404 ndata2 := Format(pf1.Syntax)
405 pf3, err := ParseWork(base, ndata2, nil)
406 if err != nil {
407 t.Fatalf("Parsing reformatted2: %v", err)
408 }
409 eq = eqchecker{file: base}
410 if err := eq.check(pf1, pf3); err != nil {
411 t.Errorf("not equal (Parse/Format/Parse): %v", err)
412 }
413 ndata = ndata2
414 }
415
416 if strings.HasSuffix(out, ".in") {
417 golden, err := os.ReadFile(strings.TrimSuffix(out, ".in") + ".golden")
418 if err != nil {
419 t.Fatal(err)
420 }
421 if !bytes.Equal(ndata, golden) {
422 t.Errorf("formatted %s incorrectly: diff shows -golden, +ours", base)
423 tdiff(t, string(golden), string(ndata))
424 return
425 }
426 }
427 })
428 }
429 }
430
431 func testWorkEdit(t *testing.T, in, want string, transform func(f *WorkFile) error) *WorkFile {
432 t.Helper()
433 parse := ParseWork
434 f, err := parse("in", []byte(in), nil)
435 if err != nil {
436 t.Fatal(err)
437 }
438 g, err := parse("out", []byte(want), nil)
439 if err != nil {
440 t.Fatal(err)
441 }
442 golden := Format(g.Syntax)
443
444 if err := transform(f); err != nil {
445 t.Fatal(err)
446 }
447 out := Format(f.Syntax)
448 if err != nil {
449 t.Fatal(err)
450 }
451 if !bytes.Equal(out, golden) {
452 t.Errorf("have:\n%s\nwant:\n%s", out, golden)
453 }
454
455 return f
456 }
457
View as plain text