.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools / gopls@v0.6.9 / internal / regtest / watch / watch_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         "testing"
9
10         . "golang.org/x/tools/gopls/internal/regtest"
11
12         "golang.org/x/tools/internal/lsp/fake"
13         "golang.org/x/tools/internal/lsp/protocol"
14         "golang.org/x/tools/internal/testenv"
15 )
16
17 func TestMain(m *testing.M) {
18         Main(m)
19 }
20
21 func TestEditFile(t *testing.T) {
22         const pkg = `
23 -- go.mod --
24 module mod.com
25
26 go 1.14
27 -- a/a.go --
28 package a
29
30 func _() {
31         var x int
32 }
33 `
34         // Edit the file when it's *not open* in the workspace, and check that
35         // diagnostics are updated.
36         t.Run("unopened", func(t *testing.T) {
37                 Run(t, pkg, func(t *testing.T, env *Env) {
38                         env.Await(
39                                 env.DiagnosticAtRegexp("a/a.go", "x"),
40                         )
41                         env.WriteWorkspaceFile("a/a.go", `package a; func _() {};`)
42                         env.Await(
43                                 EmptyDiagnostics("a/a.go"),
44                         )
45                 })
46         })
47
48         // Edit the file when it *is open* in the workspace, and check that
49         // diagnostics are *not* updated.
50         t.Run("opened", func(t *testing.T) {
51                 Run(t, pkg, func(t *testing.T, env *Env) {
52                         env.OpenFile("a/a.go")
53                         // Insert a trivial edit so that we don't automatically update the buffer
54                         // (see CL 267577).
55                         env.EditBuffer("a/a.go", fake.NewEdit(0, 0, 0, 0, " "))
56                         env.Await(env.DoneWithOpen())
57                         env.WriteWorkspaceFile("a/a.go", `package a; func _() {};`)
58                         env.Await(
59                                 OnceMet(
60                                         env.DoneWithChangeWatchedFiles(),
61                                         env.DiagnosticAtRegexp("a/a.go", "x"),
62                                 ))
63                 })
64         })
65 }
66
67 // Edit a dependency on disk and expect a new diagnostic.
68 func TestEditDependency(t *testing.T) {
69         const pkg = `
70 -- go.mod --
71 module mod.com
72
73 go 1.14
74 -- b/b.go --
75 package b
76
77 func B() int { return 0 }
78 -- a/a.go --
79 package a
80
81 import (
82         "mod.com/b"
83 )
84
85 func _() {
86         _ = b.B()
87 }
88 `
89         Run(t, pkg, func(t *testing.T, env *Env) {
90                 env.OpenFile("a/a.go")
91                 env.Await(env.DoneWithOpen())
92                 env.WriteWorkspaceFile("b/b.go", `package b; func B() {};`)
93                 env.Await(
94                         env.DiagnosticAtRegexp("a/a.go", "b.B"),
95                 )
96         })
97 }
98
99 // Edit both the current file and one of its dependencies on disk and
100 // expect diagnostic changes.
101 func TestEditFileAndDependency(t *testing.T) {
102         const pkg = `
103 -- go.mod --
104 module mod.com
105
106 go 1.14
107 -- b/b.go --
108 package b
109
110 func B() int { return 0 }
111 -- a/a.go --
112 package a
113
114 import (
115         "mod.com/b"
116 )
117
118 func _() {
119         var x int
120         _ = b.B()
121 }
122 `
123         Run(t, pkg, func(t *testing.T, env *Env) {
124                 env.Await(
125                         env.DiagnosticAtRegexp("a/a.go", "x"),
126                 )
127                 env.WriteWorkspaceFiles(map[string]string{
128                         "b/b.go": `package b; func B() {};`,
129                         "a/a.go": `package a
130
131 import "mod.com/b"
132
133 func _() {
134         b.B()
135 }`,
136                 })
137                 env.Await(
138                         EmptyDiagnostics("a/a.go"),
139                         NoDiagnostics("b/b.go"),
140                 )
141         })
142 }
143
144 // Delete a dependency and expect a new diagnostic.
145 func TestDeleteDependency(t *testing.T) {
146         const pkg = `
147 -- go.mod --
148 module mod.com
149
150 go 1.14
151 -- b/b.go --
152 package b
153
154 func B() int { return 0 }
155 -- a/a.go --
156 package a
157
158 import (
159         "mod.com/b"
160 )
161
162 func _() {
163         _ = b.B()
164 }
165 `
166         Run(t, pkg, func(t *testing.T, env *Env) {
167                 env.OpenFile("a/a.go")
168                 env.Await(env.DoneWithOpen())
169                 env.RemoveWorkspaceFile("b/b.go")
170                 env.Await(
171                         env.DiagnosticAtRegexp("a/a.go", "\"mod.com/b\""),
172                 )
173         })
174 }
175
176 // Create a dependency on disk and expect the diagnostic to go away.
177 func TestCreateDependency(t *testing.T) {
178         const missing = `
179 -- go.mod --
180 module mod.com
181
182 go 1.14
183 -- b/b.go --
184 package b
185
186 func B() int { return 0 }
187 -- a/a.go --
188 package a
189
190 import (
191         "mod.com/c"
192 )
193
194 func _() {
195         c.C()
196 }
197 `
198         Run(t, missing, func(t *testing.T, env *Env) {
199                 t.Skip("the initial workspace load fails and never retries")
200
201                 env.Await(
202                         env.DiagnosticAtRegexp("a/a.go", "\"mod.com/c\""),
203                 )
204                 env.WriteWorkspaceFile("c/c.go", `package c; func C() {};`)
205                 env.Await(
206                         EmptyDiagnostics("c/c.go"),
207                 )
208         })
209 }
210
211 // Create a new dependency and add it to the file on disk.
212 // This is similar to what might happen if you switch branches.
213 func TestCreateAndAddDependency(t *testing.T) {
214         const original = `
215 -- go.mod --
216 module mod.com
217
218 go 1.14
219 -- a/a.go --
220 package a
221
222 func _() {}
223 `
224         Run(t, original, func(t *testing.T, env *Env) {
225                 env.WriteWorkspaceFile("c/c.go", `package c; func C() {};`)
226                 env.WriteWorkspaceFile("a/a.go", `package a; import "mod.com/c"; func _() { c.C() }`)
227                 env.Await(
228                         NoDiagnostics("a/a.go"),
229                 )
230         })
231 }
232
233 // Create a new file that defines a new symbol, in the same package.
234 func TestCreateFile(t *testing.T) {
235         const pkg = `
236 -- go.mod --
237 module mod.com
238
239 go 1.14
240 -- a/a.go --
241 package a
242
243 func _() {
244         hello()
245 }
246 `
247         Run(t, pkg, func(t *testing.T, env *Env) {
248                 env.Await(
249                         env.DiagnosticAtRegexp("a/a.go", "hello"),
250                 )
251                 env.WriteWorkspaceFile("a/a2.go", `package a; func hello() {};`)
252                 env.Await(
253                         EmptyDiagnostics("a/a.go"),
254                 )
255         })
256 }
257
258 // Add a new method to an interface and implement it.
259 // Inspired by the structure of internal/lsp/source and internal/lsp/cache.
260 func TestCreateImplementation(t *testing.T) {
261         const pkg = `
262 -- go.mod --
263 module mod.com
264
265 go 1.14
266 -- b/b.go --
267 package b
268
269 type B interface{
270         Hello() string
271 }
272
273 func SayHello(bee B) {
274         println(bee.Hello())
275 }
276 -- a/a.go --
277 package a
278
279 import "mod.com/b"
280
281 type X struct {}
282
283 func (_ X) Hello() string {
284         return ""
285 }
286
287 func _() {
288         x := X{}
289         b.SayHello(x)
290 }
291 `
292         const newMethod = `package b
293 type B interface{
294         Hello() string
295         Bye() string
296 }
297
298 func SayHello(bee B) {
299         println(bee.Hello())
300 }`
301         const implementation = `package a
302
303 import "mod.com/b"
304
305 type X struct {}
306
307 func (_ X) Hello() string {
308         return ""
309 }
310
311 func (_ X) Bye() string {
312         return ""
313 }
314
315 func _() {
316         x := X{}
317         b.SayHello(x)
318 }`
319
320         // Add the new method before the implementation. Expect diagnostics.
321         t.Run("method before implementation", func(t *testing.T) {
322                 Run(t, pkg, func(t *testing.T, env *Env) {
323                         env.WriteWorkspaceFile("b/b.go", newMethod)
324                         env.Await(
325                                 OnceMet(
326                                         env.DoneWithChangeWatchedFiles(),
327                                         DiagnosticAt("a/a.go", 12, 12),
328                                 ),
329                         )
330                         env.WriteWorkspaceFile("a/a.go", implementation)
331                         env.Await(
332                                 EmptyDiagnostics("a/a.go"),
333                         )
334                 })
335         })
336         // Add the new implementation before the new method. Expect no diagnostics.
337         t.Run("implementation before method", func(t *testing.T) {
338                 Run(t, pkg, func(t *testing.T, env *Env) {
339                         env.WriteWorkspaceFile("a/a.go", implementation)
340                         env.Await(
341                                 OnceMet(
342                                         env.DoneWithChangeWatchedFiles(),
343                                         NoDiagnostics("a/a.go"),
344                                 ),
345                         )
346                         env.WriteWorkspaceFile("b/b.go", newMethod)
347                         env.Await(
348                                 NoDiagnostics("a/a.go"),
349                         )
350                 })
351         })
352         // Add both simultaneously. Expect no diagnostics.
353         t.Run("implementation and method simultaneously", func(t *testing.T) {
354                 Run(t, pkg, func(t *testing.T, env *Env) {
355                         env.WriteWorkspaceFiles(map[string]string{
356                                 "a/a.go": implementation,
357                                 "b/b.go": newMethod,
358                         })
359                         env.Await(
360                                 OnceMet(
361                                         env.DoneWithChangeWatchedFiles(),
362                                         NoDiagnostics("a/a.go"),
363                                 ),
364                                 NoDiagnostics("b/b.go"),
365                         )
366                 })
367         })
368 }
369
370 // Tests golang/go#38498. Delete a file and then force a reload.
371 // Assert that we no longer try to load the file.
372 func TestDeleteFiles(t *testing.T) {
373         testenv.NeedsGo1Point(t, 13) // Poor overlay support causes problems on 1.12.
374         const pkg = `
375 -- go.mod --
376 module mod.com
377
378 go 1.14
379 -- a/a.go --
380 package a
381
382 func _() {
383         var _ int
384 }
385 -- a/a_unneeded.go --
386 package a
387 `
388         t.Run("close then delete", func(t *testing.T) {
389                 WithOptions(EditorConfig{
390                         VerboseOutput: true,
391                 }).Run(t, pkg, func(t *testing.T, env *Env) {
392                         env.OpenFile("a/a.go")
393                         env.OpenFile("a/a_unneeded.go")
394                         env.Await(
395                                 OnceMet(
396                                         env.DoneWithOpen(),
397                                         LogMatching(protocol.Info, "a_unneeded.go", 1),
398                                 ),
399                         )
400
401                         // Close and delete the open file, mimicking what an editor would do.
402                         env.CloseBuffer("a/a_unneeded.go")
403                         env.RemoveWorkspaceFile("a/a_unneeded.go")
404                         env.RegexpReplace("a/a.go", "var _ int", "fmt.Println(\"\")")
405                         env.Await(
406                                 env.DiagnosticAtRegexp("a/a.go", "fmt"),
407                         )
408                         env.SaveBuffer("a/a.go")
409                         env.Await(
410                                 OnceMet(
411                                         env.DoneWithSave(),
412                                         // There should only be one log message containing
413                                         // a_unneeded.go, from the initial workspace load, which we
414                                         // check for earlier. If there are more, there's a bug.
415                                         LogMatching(protocol.Info, "a_unneeded.go", 1),
416                                 ),
417                                 EmptyDiagnostics("a/a.go"),
418                         )
419                 })
420         })
421
422         t.Run("delete then close", func(t *testing.T) {
423                 WithOptions(
424                         EditorConfig{VerboseOutput: true},
425                 ).Run(t, pkg, func(t *testing.T, env *Env) {
426                         env.OpenFile("a/a.go")
427                         env.OpenFile("a/a_unneeded.go")
428                         env.Await(
429                                 OnceMet(
430                                         env.DoneWithOpen(),
431                                         LogMatching(protocol.Info, "a_unneeded.go", 1),
432                                 ),
433                         )
434
435                         // Delete and then close the file.
436                         env.RemoveWorkspaceFile("a/a_unneeded.go")
437                         env.CloseBuffer("a/a_unneeded.go")
438                         env.RegexpReplace("a/a.go", "var _ int", "fmt.Println(\"\")")
439                         env.Await(
440                                 env.DiagnosticAtRegexp("a/a.go", "fmt"),
441                         )
442                         env.SaveBuffer("a/a.go")
443                         env.Await(
444                                 OnceMet(
445                                         env.DoneWithSave(),
446                                         // There should only be one log message containing
447                                         // a_unneeded.go, from the initial workspace load, which we
448                                         // check for earlier. If there are more, there's a bug.
449                                         LogMatching(protocol.Info, "a_unneeded.go", 1),
450                                 ),
451                                 EmptyDiagnostics("a/a.go"),
452                         )
453                 })
454         })
455 }
456
457 // This change reproduces the behavior of switching branches, with multiple
458 // files being created and deleted. The key change here is the movement of a
459 // symbol from one file to another in a given package through a deletion and
460 // creation. To reproduce an issue with metadata invalidation in batched
461 // changes, the last change in the batch is an on-disk file change that doesn't
462 // require metadata invalidation.
463 func TestMoveSymbol(t *testing.T) {
464         const pkg = `
465 -- go.mod --
466 module mod.com
467
468 go 1.14
469 -- main.go --
470 package main
471
472 import "mod.com/a"
473
474 func main() {
475         var x int
476         x = a.Hello
477         println(x)
478 }
479 -- a/a1.go --
480 package a
481
482 var Hello int
483 -- a/a2.go --
484 package a
485
486 func _() {}
487 `
488         Run(t, pkg, func(t *testing.T, env *Env) {
489                 env.ChangeFilesOnDisk([]fake.FileEvent{
490                         {
491                                 Path: "a/a3.go",
492                                 Content: `package a
493
494 var Hello int
495 `,
496                                 ProtocolEvent: protocol.FileEvent{
497                                         URI:  env.Sandbox.Workdir.URI("a/a3.go"),
498                                         Type: protocol.Created,
499                                 },
500                         },
501                         {
502                                 Path: "a/a1.go",
503                                 ProtocolEvent: protocol.FileEvent{
504                                         URI:  env.Sandbox.Workdir.URI("a/a1.go"),
505                                         Type: protocol.Deleted,
506                                 },
507                         },
508                         {
509                                 Path:    "a/a2.go",
510                                 Content: `package a; func _() {};`,
511                                 ProtocolEvent: protocol.FileEvent{
512                                         URI:  env.Sandbox.Workdir.URI("a/a2.go"),
513                                         Type: protocol.Changed,
514                                 },
515                         },
516                 })
517                 env.Await(
518                         OnceMet(
519                                 env.DoneWithChangeWatchedFiles(),
520                                 NoDiagnostics("main.go"),
521                         ),
522                 )
523         })
524 }
525
526 // Reproduce golang/go#40456.
527 func TestChangeVersion(t *testing.T) {
528         const proxy = `
529 -- example.com@v1.2.3/go.mod --
530 module example.com
531
532 go 1.12
533 -- example.com@v1.2.3/blah/blah.go --
534 package blah
535
536 const Name = "Blah"
537
538 func X(x int) {}
539 -- example.com@v1.2.2/go.mod --
540 module example.com
541
542 go 1.12
543 -- example.com@v1.2.2/blah/blah.go --
544 package blah
545
546 const Name = "Blah"
547
548 func X() {}
549 -- random.org@v1.2.3/go.mod --
550 module random.org
551
552 go 1.12
553 -- random.org@v1.2.3/blah/blah.go --
554 package hello
555
556 const Name = "Hello"
557 `
558         const mod = `
559 -- go.mod --
560 module mod.com
561
562 go 1.12
563
564 require example.com v1.2.2
565 -- main.go --
566 package main
567
568 import "example.com/blah"
569
570 func main() {
571         blah.X()
572 }
573 `
574         WithOptions(ProxyFiles(proxy)).Run(t, mod, func(t *testing.T, env *Env) {
575                 env.WriteWorkspaceFiles(map[string]string{
576                         "go.mod": `module mod.com
577
578 go 1.12
579
580 require example.com v1.2.3
581 `,
582                         "main.go": `package main
583
584 import (
585         "example.com/blah"
586 )
587
588 func main() {
589         blah.X(1)
590 }
591 `,
592                 })
593                 env.Await(
594                         env.DoneWithChangeWatchedFiles(),
595                         NoDiagnostics("main.go"),
596                 )
597         })
598 }
599
600 // Reproduces golang/go#40340.
601 func TestSwitchFromGOPATHToModules(t *testing.T) {
602         testenv.NeedsGo1Point(t, 13)
603
604         const files = `
605 -- foo/blah/blah.go --
606 package blah
607
608 const Name = ""
609 -- foo/main.go --
610 package main
611
612 import "blah"
613
614 func main() {
615         _ = blah.Name
616 }
617 `
618         WithOptions(
619                 InGOPATH(),
620                 Modes(Experimental), // module is in a subdirectory
621         ).Run(t, files, func(t *testing.T, env *Env) {
622                 env.OpenFile("foo/main.go")
623                 env.Await(env.DiagnosticAtRegexp("foo/main.go", `"blah"`))
624                 if err := env.Sandbox.RunGoCommand(env.Ctx, "foo", "mod", []string{"init", "mod.com"}); err != nil {
625                         t.Fatal(err)
626                 }
627                 env.Await(
628                         OnceMet(
629                                 env.DoneWithChangeWatchedFiles(),
630                                 env.DiagnosticAtRegexp("foo/main.go", `"blah"`),
631                         ),
632                 )
633                 env.RegexpReplace("foo/main.go", `"blah"`, `"mod.com/blah"`)
634                 env.Await(
635                         EmptyDiagnostics("foo/main.go"),
636                 )
637         })
638 }
639
640 // Reproduces golang/go#40487.
641 func TestSwitchFromModulesToGOPATH(t *testing.T) {
642         testenv.NeedsGo1Point(t, 13)
643
644         const files = `
645 -- foo/go.mod --
646 module mod.com
647
648 go 1.14
649 -- foo/blah/blah.go --
650 package blah
651
652 const Name = ""
653 -- foo/main.go --
654 package main
655
656 import "mod.com/blah"
657
658 func main() {
659         _ = blah.Name
660 }
661 `
662         WithOptions(
663                 InGOPATH(),
664         ).Run(t, files, func(t *testing.T, env *Env) {
665                 env.OpenFile("foo/main.go")
666                 env.RemoveWorkspaceFile("foo/go.mod")
667                 env.Await(
668                         OnceMet(
669                                 env.DoneWithChangeWatchedFiles(),
670                                 env.DiagnosticAtRegexp("foo/main.go", `"mod.com/blah"`),
671                         ),
672                 )
673                 env.RegexpReplace("foo/main.go", `"mod.com/blah"`, `"foo/blah"`)
674                 env.Await(
675                         EmptyDiagnostics("foo/main.go"),
676                 )
677         })
678 }
679
680 func TestNewSymbolInTestVariant(t *testing.T) {
681         const files = `
682 -- go.mod --
683 module mod.com
684
685 go 1.12
686 -- a/a.go --
687 package a
688
689 func bob() {}
690 -- a/a_test.go --
691 package a
692
693 import "testing"
694
695 func TestBob(t *testing.T) {
696         bob()
697 }
698 `
699         Run(t, files, func(t *testing.T, env *Env) {
700                 // Add a new symbol to the package under test and use it in the test
701                 // variant. Expect no diagnostics.
702                 env.WriteWorkspaceFiles(map[string]string{
703                         "a/a.go": `package a
704
705 func bob() {}
706 func george() {}
707 `,
708                         "a/a_test.go": `package a
709
710 import "testing"
711
712 func TestAll(t *testing.T) {
713         bob()
714         george()
715 }
716 `,
717                 })
718                 env.Await(
719                         OnceMet(
720                                 env.DoneWithChangeWatchedFiles(),
721                                 NoDiagnostics("a/a.go"),
722                         ),
723                         OnceMet(
724                                 env.DoneWithChangeWatchedFiles(),
725                                 NoDiagnostics("a/a_test.go"),
726                         ),
727                 )
728                 // Now, add a new file to the test variant and use its symbol in the
729                 // original test file. Expect no diagnostics.
730                 env.WriteWorkspaceFiles(map[string]string{
731                         "a/a_test.go": `package a
732
733 import "testing"
734
735 func TestAll(t *testing.T) {
736         bob()
737         george()
738         hi()
739 }
740 `,
741                         "a/a2_test.go": `package a
742
743 import "testing"
744
745 func hi() {}
746
747 func TestSomething(t *testing.T) {}
748 `,
749                 })
750                 env.Await(
751                         OnceMet(
752                                 env.DoneWithChangeWatchedFiles(),
753                                 NoDiagnostics("a/a_test.go"),
754                         ),
755                         OnceMet(
756                                 env.DoneWithChangeWatchedFiles(),
757                                 NoDiagnostics("a/a2_test.go"),
758                         ),
759                 )
760         })
761 }