Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools / gopls@v0.5.2 / internal / regtest / modfile_test.go
1 // Copyright 2020 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package regtest
6
7 import (
8         "strings"
9         "testing"
10
11         "golang.org/x/tools/internal/lsp"
12         "golang.org/x/tools/internal/lsp/protocol"
13         "golang.org/x/tools/internal/lsp/tests"
14         "golang.org/x/tools/internal/testenv"
15 )
16
17 const proxy = `
18 -- example.com@v1.2.3/go.mod --
19 module example.com
20
21 go 1.12
22 -- example.com@v1.2.3/blah/blah.go --
23 package blah
24
25 const Name = "Blah"
26 -- random.org@v1.2.3/go.mod --
27 module random.org
28
29 go 1.12
30 -- random.org@v1.2.3/blah/blah.go --
31 package hello
32
33 const Name = "Hello"
34 `
35
36 func TestModFileModification(t *testing.T) {
37         testenv.NeedsGo1Point(t, 14)
38
39         const untidyModule = `
40 -- go.mod --
41 module mod.com
42
43 -- main.go --
44 package main
45
46 import "example.com/blah"
47
48 func main() {
49         println(blah.Name)
50 }
51 `
52         t.Run("basic", func(t *testing.T) {
53                 withOptions(WithProxyFiles(proxy)).run(t, untidyModule, func(t *testing.T, env *Env) {
54                         // Open the file and make sure that the initial workspace load does not
55                         // modify the go.mod file.
56                         goModContent := env.ReadWorkspaceFile("go.mod")
57                         env.OpenFile("main.go")
58                         env.Await(
59                                 env.DiagnosticAtRegexp("main.go", "\"example.com/blah\""),
60                         )
61                         if got := env.ReadWorkspaceFile("go.mod"); got != goModContent {
62                                 t.Fatalf("go.mod changed on disk:\n%s", tests.Diff(goModContent, got))
63                         }
64                         // Save the buffer, which will format and organize imports.
65                         // Confirm that the go.mod file still does not change.
66                         env.SaveBuffer("main.go")
67                         env.Await(
68                                 env.DiagnosticAtRegexp("main.go", "\"example.com/blah\""),
69                         )
70                         if got := env.ReadWorkspaceFile("go.mod"); got != goModContent {
71                                 t.Fatalf("go.mod changed on disk:\n%s", tests.Diff(goModContent, got))
72                         }
73                 })
74         })
75
76         // Reproduce golang/go#40269 by deleting and recreating main.go.
77         t.Run("delete main.go", func(t *testing.T) {
78                 t.Skip("This test will be flaky until golang/go#40269 is resolved.")
79
80                 withOptions(WithProxyFiles(proxy)).run(t, untidyModule, func(t *testing.T, env *Env) {
81                         goModContent := env.ReadWorkspaceFile("go.mod")
82                         mainContent := env.ReadWorkspaceFile("main.go")
83                         env.OpenFile("main.go")
84                         env.SaveBuffer("main.go")
85
86                         env.RemoveWorkspaceFile("main.go")
87                         env.Await(
88                                 CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidOpen), 1),
89                                 CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidSave), 1),
90                                 CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidChangeWatchedFiles), 2),
91                         )
92
93                         env.WriteWorkspaceFile("main.go", mainContent)
94                         env.Await(
95                                 env.DiagnosticAtRegexp("main.go", "\"example.com/blah\""),
96                         )
97                         if got := env.ReadWorkspaceFile("go.mod"); got != goModContent {
98                                 t.Fatalf("go.mod changed on disk:\n%s", tests.Diff(goModContent, got))
99                         }
100                 })
101         })
102 }
103
104 // Tests that multiple missing dependencies gives good single fixes.
105 func TestMissingDependencyFixes(t *testing.T) {
106         testenv.NeedsGo1Point(t, 14)
107         const mod = `
108 -- go.mod --
109 module mod.com
110
111 go 1.12
112
113 -- main.go --
114 package main
115
116 import "example.com/blah"
117 import "random.org/blah"
118
119 var _, _ = blah.Name, hello.Name
120 `
121
122         const want = `module mod.com
123
124 go 1.12
125
126 require random.org v1.2.3
127 `
128
129         withOptions(WithProxyFiles(proxy)).run(t, mod, func(t *testing.T, env *Env) {
130                 env.OpenFile("main.go")
131                 var d protocol.PublishDiagnosticsParams
132                 env.Await(
133                         OnceMet(
134                                 env.DiagnosticAtRegexp("main.go", `"random.org/blah"`),
135                                 ReadDiagnostics("main.go", &d),
136                         ),
137                 )
138                 var randomDiag protocol.Diagnostic
139                 for _, diag := range d.Diagnostics {
140                         if strings.Contains(diag.Message, "random.org") {
141                                 randomDiag = diag
142                         }
143                 }
144                 env.OpenFile("go.mod")
145                 env.ApplyQuickFixes("main.go", []protocol.Diagnostic{randomDiag})
146                 if got := env.Editor.BufferText("go.mod"); got != want {
147                         t.Fatalf("unexpected go.mod content:\n%s", tests.Diff(want, got))
148                 }
149         })
150 }
151
152 func TestIndirectDependencyFix(t *testing.T) {
153         testenv.NeedsGo1Point(t, 14)
154
155         const mod = `
156 -- go.mod --
157 module mod.com
158
159 go 1.12
160
161 require example.com v1.2.3 // indirect
162 -- main.go --
163 package main
164
165 import "example.com/blah"
166
167 func main() {
168         fmt.Println(blah.Name)
169 `
170         const want = `module mod.com
171
172 go 1.12
173
174 require example.com v1.2.3
175 `
176         runner.Run(t, mod, func(t *testing.T, env *Env) {
177                 env.OpenFile("go.mod")
178                 var d protocol.PublishDiagnosticsParams
179                 env.Await(
180                         OnceMet(
181                                 env.DiagnosticAtRegexp("go.mod", "// indirect"),
182                                 ReadDiagnostics("go.mod", &d),
183                         ),
184                 )
185                 env.ApplyQuickFixes("go.mod", d.Diagnostics)
186                 if got := env.Editor.BufferText("go.mod"); got != want {
187                         t.Fatalf("unexpected go.mod content:\n%s", tests.Diff(want, got))
188                 }
189         }, WithProxyFiles(proxy))
190 }
191
192 func TestUnusedDiag(t *testing.T) {
193         testenv.NeedsGo1Point(t, 14)
194
195         const proxy = `
196 -- example.com@v1.0.0/x.go --
197 package pkg
198 const X = 1
199 `
200         const files = `
201 -- go.mod --
202 module mod.com
203 go 1.14
204 require example.com v1.0.0
205
206 -- main.go --
207 package main
208 func main() {}
209 `
210
211         const want = `module mod.com
212
213 go 1.14
214 `
215
216         withOptions(WithProxyFiles(proxy)).run(t, files, func(t *testing.T, env *Env) {
217                 env.OpenFile("go.mod")
218                 var d protocol.PublishDiagnosticsParams
219                 env.Await(
220                         OnceMet(
221                                 env.DiagnosticAtRegexp("go.mod", `require example.com`),
222                                 ReadDiagnostics("go.mod", &d),
223                         ),
224                 )
225                 env.ApplyQuickFixes("go.mod", d.Diagnostics)
226                 if got := env.Editor.BufferText("go.mod"); got != want {
227                         t.Fatalf("unexpected go.mod content:\n%s", tests.Diff(want, got))
228                 }
229         })
230 }
231
232 // Test to reproduce golang/go#39041. It adds a new require to a go.mod file
233 // that already has an unused require.
234 func TestNewDepWithUnusedDep(t *testing.T) {
235         testenv.NeedsGo1Point(t, 14)
236
237         const proxy = `
238 -- github.com/esimov/caire@v1.2.5/go.mod --
239 module github.com/esimov/caire
240
241 go 1.12
242 -- github.com/esimov/caire@v1.2.5/caire.go --
243 package caire
244
245 func RemoveTempImage() {}
246 -- google.golang.org/protobuf@v1.20.0/go.mod --
247 module google.golang.org/protobuf
248
249 go 1.12
250 -- google.golang.org/protobuf@v1.20.0/hello/hello.go --
251 package hello
252 `
253         const repro = `
254 -- go.mod --
255 module mod.com
256
257 go 1.14
258
259 require google.golang.org/protobuf v1.20.0
260 -- main.go --
261 package main
262
263 import (
264     "github.com/esimov/caire"
265 )
266
267 func _() {
268     caire.RemoveTempImage()
269 }`
270         runner.Run(t, repro, func(t *testing.T, env *Env) {
271                 env.OpenFile("go.mod")
272                 env.OpenFile("main.go")
273                 var d protocol.PublishDiagnosticsParams
274                 env.Await(
275                         OnceMet(
276                                 env.DiagnosticAtRegexp("main.go", `"github.com/esimov/caire"`),
277                                 ReadDiagnostics("main.go", &d),
278                         ),
279                 )
280                 env.ApplyQuickFixes("main.go", d.Diagnostics)
281                 want := `module mod.com
282
283 go 1.14
284
285 require (
286         github.com/esimov/caire v1.2.5
287         google.golang.org/protobuf v1.20.0
288 )
289 `
290                 if got := env.Editor.BufferText("go.mod"); got != want {
291                         t.Fatalf("TestNewDepWithUnusedDep failed:\n%s", tests.Diff(want, got))
292                 }
293         }, WithProxyFiles(proxy))
294 }
295
296 // TODO: For this test to be effective, the sandbox's file watcher must respect
297 // the file watching GlobPattern in the capability registration. See
298 // golang/go#39384.
299 func TestModuleChangesOnDisk(t *testing.T) {
300         testenv.NeedsGo1Point(t, 14)
301
302         const mod = `
303 -- go.mod --
304 module mod.com
305
306 go 1.12
307
308 require example.com v1.2.3
309 -- main.go --
310 package main
311
312 func main() {
313         fmt.Println(blah.Name)
314 `
315         runner.Run(t, mod, func(t *testing.T, env *Env) {
316                 env.Await(env.DiagnosticAtRegexp("go.mod", "require"))
317                 env.RunGoCommand("mod", "tidy")
318                 env.Await(
319                         EmptyDiagnostics("go.mod"),
320                 )
321         }, WithProxyFiles(proxy))
322 }
323
324 func TestBadlyVersionedModule(t *testing.T) {
325         testenv.NeedsGo1Point(t, 14)
326
327         const badModule = `
328 -- example.com/blah/@v/list --
329 v1.0.0
330 -- example.com/blah/@v/v1.0.0.mod --
331 module example.com
332
333 go 1.12
334 -- example.com/blah@v1.0.0/blah.go --
335 package blah
336
337 const Name = "Blah"
338 -- example.com/blah@v1.0.0/blah_test.go --
339 package blah_test
340
341 import (
342         "testing"
343 )
344
345 func TestBlah(t *testing.T) {}
346
347 -- example.com/blah/v2/@v/list --
348 v2.0.0
349 -- example.com/blah/v2/@v/v2.0.0.mod --
350 module example.com
351
352 go 1.12
353 -- example.com/blah/v2@v2.0.0/blah.go --
354 package blah
355
356 const Name = "Blah"
357 -- example.com/blah/v2@v2.0.0/blah_test.go --
358 package blah_test
359
360 import (
361         "testing"
362
363         "example.com/blah"
364 )
365
366 func TestBlah(t *testing.T) {}
367 `
368         const pkg = `
369 -- go.mod --
370 module mod.com
371
372 require (
373         example.com/blah/v2 v2.0.0
374 )
375 -- main.go --
376 package main
377
378 import "example.com/blah/v2"
379
380 func main() {
381         println(blah.Name)
382 }
383 `
384         runner.Run(t, pkg, func(t *testing.T, env *Env) {
385                 env.OpenFile("main.go")
386                 env.OpenFile("go.mod")
387                 var d protocol.PublishDiagnosticsParams
388                 env.Await(
389                         OnceMet(
390                                 DiagnosticAt("go.mod", 0, 0),
391                                 ReadDiagnostics("go.mod", &d),
392                         ),
393                 )
394                 env.ApplyQuickFixes("main.go", d.Diagnostics)
395                 const want = `module mod.com
396
397 require (
398         example.com/blah v1.0.0
399         example.com/blah/v2 v2.0.0
400 )
401 `
402                 if got := env.Editor.BufferText("go.mod"); got != want {
403                         t.Fatalf("suggested fixes failed:\n%s", tests.Diff(want, got))
404                 }
405         }, WithProxyFiles(badModule))
406 }
407
408 // Reproduces golang/go#38232.
409 func TestUnknownRevision(t *testing.T) {
410         testenv.NeedsGo1Point(t, 14)
411
412         const unknown = `
413 -- go.mod --
414 module mod.com
415
416 require (
417         example.com v1.2.2
418 )
419 -- main.go --
420 package main
421
422 import "example.com/blah"
423
424 func main() {
425         var x = blah.Name
426 }
427 `
428
429         // Start from a bad state/bad IWL, and confirm that we recover.
430         t.Run("bad", func(t *testing.T) {
431                 runner.Run(t, unknown, func(t *testing.T, env *Env) {
432                         env.OpenFile("go.mod")
433                         env.Await(
434                                 env.DiagnosticAtRegexp("go.mod", "example.com v1.2.2"),
435                         )
436                         env.RegexpReplace("go.mod", "v1.2.2", "v1.2.3")
437                         env.Editor.SaveBufferWithoutActions(env.Ctx, "go.mod") // go.mod changes must be on disk
438                         env.Await(
439                                 env.DiagnosticAtRegexp("main.go", "x = "),
440                         )
441                 }, WithProxyFiles(proxy))
442         })
443
444         const known = `
445 -- go.mod --
446 module mod.com
447
448 require (
449         example.com v1.2.3
450 )
451 -- main.go --
452 package main
453
454 import "example.com/blah"
455
456 func main() {
457         var x = blah.Name
458 }
459 `
460         // Start from a good state, transform to a bad state, and confirm that we
461         // still recover.
462         t.Run("good", func(t *testing.T) {
463                 runner.Run(t, known, func(t *testing.T, env *Env) {
464                         env.OpenFile("go.mod")
465                         env.Await(
466                                 env.DiagnosticAtRegexp("main.go", "x = "),
467                         )
468                         env.RegexpReplace("go.mod", "v1.2.3", "v1.2.2")
469                         env.Editor.SaveBufferWithoutActions(env.Ctx, "go.mod") // go.mod changes must be on disk
470                         env.Await(
471                                 env.DiagnosticAtRegexp("go.mod", "example.com v1.2.2"),
472                         )
473                         env.RegexpReplace("go.mod", "v1.2.2", "v1.2.3")
474                         env.Editor.SaveBufferWithoutActions(env.Ctx, "go.mod") // go.mod changes must be on disk
475                         env.Await(
476                                 env.DiagnosticAtRegexp("main.go", "x = "),
477                         )
478                 }, WithProxyFiles(proxy))
479         })
480 }
481
482 func TestTidyOnSave(t *testing.T) {
483         testenv.NeedsGo1Point(t, 14)
484
485         const untidyModule = `
486 -- go.mod --
487 module mod.com
488
489 go 1.14
490
491 require random.org v1.2.3
492 -- main.go --
493 package main
494
495 import "example.com/blah"
496
497 func main() {
498         fmt.Println(blah.Name)
499 }
500 `
501         withOptions(WithProxyFiles(proxy)).run(t, untidyModule, func(t *testing.T, env *Env) {
502                 env.OpenFile("go.mod")
503                 env.Await(
504                         env.DiagnosticAtRegexp("main.go", `"example.com/blah"`),
505                         env.DiagnosticAtRegexp("go.mod", `require random.org v1.2.3`),
506                 )
507                 env.SaveBuffer("go.mod")
508                 const want = `module mod.com
509
510 go 1.14
511
512 require example.com v1.2.3
513 `
514                 if got := env.ReadWorkspaceFile("go.mod"); got != want {
515                         t.Fatalf("unexpected go.mod content:\n%s", tests.Diff(want, got))
516                 }
517         })
518 }
519
520 // Confirm that an error in an indirect dependency of a requirement is surfaced
521 // as a diagnostic in the go.mod file.
522 func TestErrorInIndirectDependency(t *testing.T) {
523         testenv.NeedsGo1Point(t, 14)
524
525         const badProxy = `
526 -- example.com@v1.2.3/go.mod --
527 module example.com
528
529 go 1.12
530
531 require random.org v1.2.3 // indirect
532 -- example.com@v1.2.3/blah/blah.go --
533 package blah
534
535 const Name = "Blah"
536 -- random.org@v1.2.3/go.mod --
537 module bob.org
538
539 go 1.12
540 -- random.org@v1.2.3/blah/blah.go --
541 package hello
542
543 const Name = "Hello"
544 `
545         const module = `
546 -- go.mod --
547 module mod.com
548
549 go 1.14
550
551 require example.com v1.2.3
552 -- main.go --
553 package main
554
555 import "example.com/blah"
556
557 func main() {
558         println(blah.Name)
559 }
560 `
561         withOptions(WithProxyFiles(badProxy)).run(t, module, func(t *testing.T, env *Env) {
562                 env.OpenFile("go.mod")
563                 env.Await(
564                         env.DiagnosticAtRegexp("go.mod", "require example.com v1.2.3"),
565                 )
566         })
567 }
568
569 // A copy of govim's config_set_env_goflags_mod_readonly test.
570 func TestGovimModReadonly(t *testing.T) {
571         const mod = `
572 -- go.mod --
573 module mod.com
574
575 go 1.13
576 -- main.go --
577 package main
578
579 import "example.com/blah"
580
581 func main() {
582         println(blah.Name)
583 }
584 `
585         withOptions(
586                 EditorConfig{
587                         Env: map[string]string{
588                                 "GOFLAGS": "-mod=readonly",
589                         },
590                 },
591                 WithProxyFiles(proxy),
592                 WithModes(WithoutExperiments),
593         ).run(t, mod, func(t *testing.T, env *Env) {
594                 env.OpenFile("main.go")
595                 original := env.ReadWorkspaceFile("go.mod")
596                 env.Await(
597                         env.DiagnosticAtRegexp("main.go", `"example.com/blah"`),
598                 )
599                 got := env.ReadWorkspaceFile("go.mod")
600                 if got != original {
601                         t.Fatalf("go.mod file modified:\n%s", tests.Diff(original, got))
602                 }
603                 env.RunGoCommand("get", "example.com/blah@v1.2.3")
604                 env.RunGoCommand("mod", "tidy")
605                 env.Await(
606                         EmptyDiagnostics("main.go"),
607                 )
608         })
609 }
610
611 func TestMultiModuleModDiagnostics(t *testing.T) {
612         testenv.NeedsGo1Point(t, 14)
613
614         const mod = `
615 -- a/go.mod --
616 module mod.com
617
618 go 1.14
619
620 require (
621         example.com v1.2.3
622 )
623 -- a/main.go --
624 package main
625
626 func main() {}
627 -- b/go.mod --
628 module mod.com
629
630 go 1.14
631 -- b/main.go --
632 package main
633
634 import "example.com/blah"
635
636 func main() {
637         blah.SaySomething()
638 }
639 `
640         withOptions(
641                 WithProxyFiles(workspaceProxy),
642                 WithModes(Experimental),
643         ).run(t, mod, func(t *testing.T, env *Env) {
644                 env.Await(
645                         env.DiagnosticAtRegexp("a/go.mod", "example.com v1.2.3"),
646                         env.DiagnosticAtRegexp("b/go.mod", "module mod.com"),
647                 )
648         })
649 }
650
651 func TestModTidyWithBuildTags(t *testing.T) {
652         testenv.NeedsGo1Point(t, 14)
653
654         const mod = `
655 -- go.mod --
656 module mod.com
657
658 go 1.14
659 -- main.go --
660 // +build bob
661
662 package main
663
664 import "example.com/blah"
665
666 func main() {
667         blah.SaySomething()
668 }
669 `
670         withOptions(
671                 WithProxyFiles(workspaceProxy),
672                 EditorConfig{
673                         BuildFlags: []string{"-tags", "bob"},
674                 },
675         ).run(t, mod, func(t *testing.T, env *Env) {
676                 env.Await(
677                         env.DiagnosticAtRegexp("main.go", `"example.com/blah"`),
678                 )
679         })
680 }