From db4c57db23ae595a757c609d3640fa4ee9718272 Mon Sep 17 00:00:00 2001 From: Rob Findley Date: Thu, 28 Jan 2021 09:41:07 -0500 Subject: [PATCH] gopls/internal/regtest: split regtests up into multiple packages Regtests have gotten large, and started timing out on some slow builders. They also can't yet be run in parallel, due to some process-level shared state (e.g. gc_details). Furthermore, there seems to be some per-process resource leak that we don't yet fully understand causing slowdown as the tests progress. Address these problems by splitting the regtests up into multiple packages. This also makes it easier to run only relevant tests during development. For golang/go#42789 For golang/go#39384 Change-Id: I1a74e4c379f3a650f4c434db44f9368e527aa459 Reviewed-on: https://go-review.googlesource.com/c/tools/+/287572 Trust: Robert Findley Run-TryBot: Robert Findley Reviewed-by: Rebecca Stambler gopls-CI: kokoro TryBot-Result: Go Bot --- .../regtest/{ => bench}/bench_test.go | 12 +- .../{ => bench}/completion_bench_test.go | 6 +- .../regtest/{ => bench}/stress_test.go | 6 +- .../regtest/{ => codelens}/codelens_test.go | 26 ++- .../{ => completion}/completion_test.go | 37 +++- .../{ => diagnostics}/diagnostics_test.go | 175 ++++++++++-------- .../regtest/{ => misc}/configuration_test.go | 8 +- .../regtest/{ => misc}/definition_test.go | 12 +- .../regtest/{ => misc}/failures_test.go | 8 +- gopls/internal/regtest/{ => misc}/fix_test.go | 6 +- .../regtest/{ => misc}/formatting_test.go | 18 +- .../regtest/{ => misc}/generate_test.go | 6 +- .../regtest/{ => misc}/imports_test.go | 16 +- .../internal/regtest/{ => misc}/link_test.go | 10 +- gopls/internal/regtest/misc/misc_test.go | 15 ++ .../regtest/{ => misc}/references_test.go | 6 +- .../regtest/{ => misc}/shared_test.go | 16 +- .../regtest/{ => misc}/vendor_test.go | 8 +- .../regtest/{ => modfile}/modfile_test.go | 149 +++++++++------ .../regtest/{reg_test.go => regtest.go} | 37 ++-- .../regtest/{ => watch}/watch_test.go | 50 ++--- .../regtest/{ => workspace}/workspace_test.go | 54 +++--- gopls/internal/regtest/wrappers.go | 2 +- 23 files changed, 421 insertions(+), 262 deletions(-) rename gopls/internal/regtest/{ => bench}/bench_test.go (92%) rename gopls/internal/regtest/{ => bench}/completion_bench_test.go (98%) rename gopls/internal/regtest/{ => bench}/stress_test.go (94%) rename gopls/internal/regtest/{ => codelens}/codelens_test.go (94%) rename gopls/internal/regtest/{ => completion}/completion_test.go (93%) rename gopls/internal/regtest/{ => diagnostics}/diagnostics_test.go (90%) rename gopls/internal/regtest/{ => misc}/configuration_test.go (84%) rename gopls/internal/regtest/{ => misc}/definition_test.go (91%) rename gopls/internal/regtest/{ => misc}/failures_test.go (89%) rename gopls/internal/regtest/{ => misc}/fix_test.go (92%) rename gopls/internal/regtest/{ => misc}/formatting_test.go (90%) rename gopls/internal/regtest/{ => misc}/generate_test.go (87%) rename gopls/internal/regtest/{ => misc}/imports_test.go (92%) rename gopls/internal/regtest/{ => misc}/link_test.go (94%) create mode 100644 gopls/internal/regtest/misc/misc_test.go rename gopls/internal/regtest/{ => misc}/references_test.go (88%) rename gopls/internal/regtest/{ => misc}/shared_test.go (78%) rename gopls/internal/regtest/{ => misc}/vendor_test.go (93%) rename gopls/internal/regtest/{ => modfile}/modfile_test.go (88%) rename gopls/internal/regtest/{reg_test.go => regtest.go} (75%) rename gopls/internal/regtest/{ => watch}/watch_test.go (93%) rename gopls/internal/regtest/{ => workspace}/workspace_test.go (94%) diff --git a/gopls/internal/regtest/bench_test.go b/gopls/internal/regtest/bench/bench_test.go similarity index 92% rename from gopls/internal/regtest/bench_test.go rename to gopls/internal/regtest/bench/bench_test.go index 5ad93589c87..1702e841feb 100644 --- a/gopls/internal/regtest/bench_test.go +++ b/gopls/internal/regtest/bench/bench_test.go @@ -2,16 +2,22 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package regtest +package bench import ( "flag" "fmt" "testing" + . "golang.org/x/tools/gopls/internal/regtest" + "golang.org/x/tools/internal/lsp/protocol" ) +func TestMain(m *testing.M) { + Main(m) +} + func printBenchmarkResults(result testing.BenchmarkResult) { fmt.Println("Benchmark Statistics:") fmt.Println(result.String()) @@ -37,7 +43,7 @@ func TestBenchmarkIWL(t *testing.T) { results := testing.Benchmark(func(b *testing.B) { for i := 0; i < b.N; i++ { - withOptions(opts...).run(t, "", func(t *testing.T, env *Env) {}) + WithOptions(opts...).Run(t, "", func(t *testing.T, env *Env) {}) } }) @@ -72,7 +78,7 @@ func TestBenchmarkSymbols(t *testing.T) { } opts = append(opts, conf) - withOptions(opts...).run(t, "", func(t *testing.T, env *Env) { + WithOptions(opts...).Run(t, "", func(t *testing.T, env *Env) { // We can't Await in this test, since we have disabled hooks. Instead, run // one symbol request to completion to ensure all necessary cache entries // are populated. diff --git a/gopls/internal/regtest/completion_bench_test.go b/gopls/internal/regtest/bench/completion_bench_test.go similarity index 98% rename from gopls/internal/regtest/completion_bench_test.go rename to gopls/internal/regtest/bench/completion_bench_test.go index 267eeb6b326..be36d45ac09 100644 --- a/gopls/internal/regtest/completion_bench_test.go +++ b/gopls/internal/regtest/bench/completion_bench_test.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package regtest +package bench import ( "flag" @@ -11,6 +11,8 @@ import ( "strings" "testing" + . "golang.org/x/tools/gopls/internal/regtest" + "golang.org/x/tools/internal/lsp/fake" ) @@ -45,7 +47,7 @@ func benchmarkCompletion(options completionBenchOptions, t *testing.T) { // it first (and therefore need hooks). opts = append(opts, SkipHooks(false)) - withOptions(opts...).run(t, "", func(t *testing.T, env *Env) { + WithOptions(opts...).Run(t, "", func(t *testing.T, env *Env) { env.OpenFile(options.file) // Run edits required for this completion. diff --git a/gopls/internal/regtest/stress_test.go b/gopls/internal/regtest/bench/stress_test.go similarity index 94% rename from gopls/internal/regtest/stress_test.go rename to gopls/internal/regtest/bench/stress_test.go index 77f4ff23db7..8cdbcfe5399 100644 --- a/gopls/internal/regtest/stress_test.go +++ b/gopls/internal/regtest/bench/stress_test.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package regtest +package bench import ( "context" @@ -10,6 +10,8 @@ import ( "fmt" "testing" "time" + + . "golang.org/x/tools/gopls/internal/regtest" ) // Pilosa is a repository that has historically caused significant memory @@ -50,7 +52,7 @@ func TestPilosaStress(t *testing.T) { } opts := stressTestOptions(*pilosaPath) - withOptions(opts...).run(t, "", func(t *testing.T, env *Env) { + WithOptions(opts...).Run(t, "", func(t *testing.T, env *Env) { files := []string{ "cmd.go", "internal/private.pb.go", diff --git a/gopls/internal/regtest/codelens_test.go b/gopls/internal/regtest/codelens/codelens_test.go similarity index 94% rename from gopls/internal/regtest/codelens_test.go rename to gopls/internal/regtest/codelens/codelens_test.go index 4d16dc573c3..305047fbfd2 100644 --- a/gopls/internal/regtest/codelens_test.go +++ b/gopls/internal/regtest/codelens/codelens_test.go @@ -2,13 +2,15 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package regtest +package codelens import ( "runtime" "strings" "testing" + . "golang.org/x/tools/gopls/internal/regtest" + "golang.org/x/tools/internal/lsp/fake" "golang.org/x/tools/internal/lsp/protocol" "golang.org/x/tools/internal/lsp/source" @@ -16,6 +18,10 @@ import ( "golang.org/x/tools/internal/testenv" ) +func TestMain(m *testing.M) { + Main(m) +} + func TestDisablingCodeLens(t *testing.T) { const workspace = ` -- go.mod -- @@ -52,11 +58,11 @@ const ( } for _, test := range tests { t.Run(test.label, func(t *testing.T) { - withOptions( + WithOptions( EditorConfig{ CodeLenses: test.enabled, }, - ).run(t, workspace, func(t *testing.T, env *Env) { + ).Run(t, workspace, func(t *testing.T, env *Env) { env.OpenFile("lib.go") lens := env.CodeLens("lib.go") if gotCodeLens := len(lens) > 0; gotCodeLens != test.wantCodeLens { @@ -115,9 +121,9 @@ func main() { "Upgrade direct dependencies", } { t.Run(commandTitle, func(t *testing.T) { - withOptions( + WithOptions( ProxyFiles(proxyWithLatest), - ).run(t, shouldUpdateDep, func(t *testing.T, env *Env) { + ).Run(t, shouldUpdateDep, func(t *testing.T, env *Env) { env.OpenFile("go.mod") var lens protocol.CodeLens var found bool @@ -195,7 +201,7 @@ func main() { _ = hi.Goodbye } ` - runner.Run(t, shouldRemoveDep, func(t *testing.T, env *Env) { + WithOptions(ProxyFiles(proxy)).Run(t, shouldRemoveDep, func(t *testing.T, env *Env) { env.OpenFile("go.mod") env.ExecuteCodeLensCommand("go.mod", source.CommandTidy) env.Await(env.DoneWithChangeWatchedFiles()) @@ -209,7 +215,7 @@ require golang.org/x/hello v1.0.0 if got != wantGoMod { t.Fatalf("go.mod tidy failed:\n%s", tests.Diff(t, wantGoMod, got)) } - }, ProxyFiles(proxy)) + }) } func TestRegenerateCgo(t *testing.T) { @@ -233,7 +239,7 @@ func Foo() { print(C.fortytwo()) } ` - runner.Run(t, workspace, func(t *testing.T, env *Env) { + Run(t, workspace, func(t *testing.T, env *Env) { // Open the file. We should have a nonexistant symbol. env.OpenFile("cgo.go") env.Await(env.DiagnosticAtRegexp("cgo.go", `C\.(fortytwo)`)) // could not determine kind of name for C.fortytwo @@ -270,12 +276,12 @@ func main() { fmt.Println(x) } ` - withOptions( + WithOptions( EditorConfig{ CodeLenses: map[string]bool{ "gc_details": true, }}, - ).run(t, mod, func(t *testing.T, env *Env) { + ).Run(t, mod, func(t *testing.T, env *Env) { env.OpenFile("main.go") env.ExecuteCodeLensCommand("main.go", source.CommandToggleDetails) d := &protocol.PublishDiagnosticsParams{} diff --git a/gopls/internal/regtest/completion_test.go b/gopls/internal/regtest/completion/completion_test.go similarity index 93% rename from gopls/internal/regtest/completion_test.go rename to gopls/internal/regtest/completion/completion_test.go index 4c7276825dd..7b8f9669999 100644 --- a/gopls/internal/regtest/completion_test.go +++ b/gopls/internal/regtest/completion/completion_test.go @@ -2,18 +2,43 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package regtest +package completion import ( "fmt" "strings" "testing" + . "golang.org/x/tools/gopls/internal/regtest" + "golang.org/x/tools/internal/lsp/fake" "golang.org/x/tools/internal/lsp/protocol" "golang.org/x/tools/internal/testenv" ) +func TestMain(m *testing.M) { + Main(m) +} + +const proxy = ` +-- example.com@v1.2.3/go.mod -- +module example.com + +go 1.12 +-- example.com@v1.2.3/blah/blah.go -- +package blah + +const Name = "Blah" +-- random.org@v1.2.3/go.mod -- +module random.org + +go 1.12 +-- random.org@v1.2.3/blah/blah.go -- +package hello + +const Name = "Hello" +` + func TestPackageCompletion(t *testing.T) { testenv.NeedsGo1Point(t, 14) const files = ` @@ -123,7 +148,7 @@ pac }, } { t.Run(tc.name, func(t *testing.T) { - run(t, files, func(t *testing.T, env *Env) { + Run(t, files, func(t *testing.T, env *Env) { if tc.content != nil { env.WriteWorkspaceFile(tc.filename, *tc.content) env.Await( @@ -180,7 +205,7 @@ package ma ` want := []string{"ma", "ma_test", "main", "math", "math_test"} - run(t, files, func(t *testing.T, env *Env) { + Run(t, files, func(t *testing.T, env *Env) { env.OpenFile("math/add.go") completions := env.Completion("math/add.go", fake.Pos{ Line: 0, @@ -241,9 +266,9 @@ func _() { _ = blah.Hello } ` - withOptions( + WithOptions( ProxyFiles(proxy), - ).run(t, mod, func(t *testing.T, env *Env) { + ).Run(t, mod, func(t *testing.T, env *Env) { // Make sure the dependency is in the module cache and accessible for // unimported completions, and then remove it before proceeding. env.RemoveWorkspaceFile("main2.go") @@ -310,7 +335,7 @@ package mainmod const Name = "mainmod" ` - withOptions(ProxyFiles(proxy)).run(t, files, func(t *testing.T, env *Env) { + WithOptions(ProxyFiles(proxy)).Run(t, files, func(t *testing.T, env *Env) { env.CreateBuffer("import.go", "package pkg\nvar _ = mainmod.Name\n") env.SaveBuffer("import.go") content := env.ReadWorkspaceFile("import.go") diff --git a/gopls/internal/regtest/diagnostics_test.go b/gopls/internal/regtest/diagnostics/diagnostics_test.go similarity index 90% rename from gopls/internal/regtest/diagnostics_test.go rename to gopls/internal/regtest/diagnostics/diagnostics_test.go index 04a2b0dacaa..50ea0b2d278 100644 --- a/gopls/internal/regtest/diagnostics_test.go +++ b/gopls/internal/regtest/diagnostics/diagnostics_test.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package regtest +package diagnostics import ( "context" @@ -11,6 +11,8 @@ import ( "os" "testing" + . "golang.org/x/tools/gopls/internal/regtest" + "golang.org/x/tools/internal/lsp" "golang.org/x/tools/internal/lsp/fake" "golang.org/x/tools/internal/lsp/protocol" @@ -18,6 +20,10 @@ import ( "golang.org/x/tools/internal/testenv" ) +func TestMain(m *testing.M) { + Main(m) +} + // Use mod.com for all go.mod files due to golang/go#35230. const exampleProgram = ` -- go.mod -- @@ -37,7 +43,7 @@ func TestDiagnosticErrorInEditedFile(t *testing.T) { // This test is very basic: start with a clean Go program, make an error, and // get a diagnostic for that error. However, it also demonstrates how to // combine Expectations to await more complex state in the editor. - runner.Run(t, exampleProgram, func(t *testing.T, env *Env) { + Run(t, exampleProgram, func(t *testing.T, env *Env) { // Deleting the 'n' at the end of Println should generate a single error // diagnostic. env.OpenFile("main.go") @@ -65,7 +71,7 @@ module mod.com go 1.12 ` - runner.Run(t, onlyMod, func(t *testing.T, env *Env) { + Run(t, onlyMod, func(t *testing.T, env *Env) { env.CreateBuffer("main.go", `package main func m() { @@ -87,7 +93,7 @@ func TestDiagnosticErrorInNewFile(t *testing.T) { const Foo = "abc ` - runner.Run(t, brokenFile, func(t *testing.T, env *Env) { + Run(t, brokenFile, func(t *testing.T, env *Env) { env.CreateBuffer("broken.go", brokenFile) env.Await(env.DiagnosticAtRegexp("broken.go", "\"abc")) }) @@ -110,7 +116,7 @@ const a = 2 ` func TestDiagnosticClearingOnEdit(t *testing.T) { - runner.Run(t, badPackage, func(t *testing.T, env *Env) { + Run(t, badPackage, func(t *testing.T, env *Env) { env.OpenFile("b.go") env.Await(env.DiagnosticAtRegexp("a.go", "a = 1"), env.DiagnosticAtRegexp("b.go", "a = 2")) @@ -124,7 +130,7 @@ func TestDiagnosticClearingOnEdit(t *testing.T) { } func TestDiagnosticClearingOnDelete_Issue37049(t *testing.T) { - runner.Run(t, badPackage, func(t *testing.T, env *Env) { + Run(t, badPackage, func(t *testing.T, env *Env) { env.OpenFile("a.go") env.Await(env.DiagnosticAtRegexp("a.go", "a = 1"), env.DiagnosticAtRegexp("b.go", "a = 2")) env.RemoveWorkspaceFile("b.go") @@ -134,7 +140,7 @@ func TestDiagnosticClearingOnDelete_Issue37049(t *testing.T) { } func TestDiagnosticClearingOnClose(t *testing.T) { - runner.Run(t, badPackage, func(t *testing.T, env *Env) { + Run(t, badPackage, func(t *testing.T, env *Env) { env.CreateBuffer("c.go", `package consts const a = 3`) @@ -152,7 +158,7 @@ const a = 3`) // Tests golang/go#37978. func TestIssue37978(t *testing.T) { - runner.Run(t, exampleProgram, func(t *testing.T, env *Env) { + Run(t, exampleProgram, func(t *testing.T, env *Env) { // Create a new workspace-level directory and empty file. env.CreateBuffer("c/c.go", "") @@ -203,7 +209,7 @@ func TestA(t *testing.T) { // Tests golang/go#38878: deleting a test file should clear its errors, and // not break the workspace. func TestDeleteTestVariant(t *testing.T) { - runner.Run(t, test38878, func(t *testing.T, env *Env) { + Run(t, test38878, func(t *testing.T, env *Env) { env.Await(env.DiagnosticAtRegexp("a_test.go", `f\((3)\)`)) env.RemoveWorkspaceFile("a_test.go") env.Await(EmptyDiagnostics("a_test.go")) @@ -220,7 +226,7 @@ func TestDeleteTestVariant(t *testing.T) { // should not clear its errors. func TestDeleteTestVariant_DiskOnly(t *testing.T) { log.SetFlags(log.Lshortfile) - runner.Run(t, test38878, func(t *testing.T, env *Env) { + Run(t, test38878, func(t *testing.T, env *Env) { env.OpenFile("a_test.go") env.Await(DiagnosticAt("a_test.go", 5, 3)) env.Sandbox.Workdir.RemoveFile(context.Background(), "a_test.go") @@ -251,7 +257,7 @@ func Hello() { ` t.Run("manual", func(t *testing.T) { - runner.Run(t, noMod, func(t *testing.T, env *Env) { + Run(t, noMod, func(t *testing.T, env *Env) { env.Await( env.DiagnosticAtRegexp("main.go", `"mod.com/bob"`), ) @@ -276,7 +282,7 @@ func Hello() { }) }) t.Run("initialized", func(t *testing.T) { - runner.Run(t, noMod, func(t *testing.T, env *Env) { + Run(t, noMod, func(t *testing.T, env *Env) { env.Await( env.DiagnosticAtRegexp("main.go", `"mod.com/bob"`), ) @@ -289,9 +295,9 @@ func Hello() { }) t.Run("without workspace module", func(t *testing.T) { - withOptions( + WithOptions( Modes(Singleton), - ).run(t, noMod, func(t *testing.T, env *Env) { + ).Run(t, noMod, func(t *testing.T, env *Env) { env.Await( env.DiagnosticAtRegexp("main.go", `"mod.com/bob"`), ) @@ -339,7 +345,7 @@ func TestHello(t *testing.T) { } ` - runner.Run(t, testPackage, func(t *testing.T, env *Env) { + Run(t, testPackage, func(t *testing.T, env *Env) { env.OpenFile("lib_test.go") env.Await( DiagnosticAt("lib_test.go", 10, 2), @@ -365,7 +371,7 @@ go 1.12 package foo func main() {} ` - runner.Run(t, packageChange, func(t *testing.T, env *Env) { + Run(t, packageChange, func(t *testing.T, env *Env) { env.OpenFile("a.go") env.RegexpReplace("a.go", "foo", "foox") env.Await( @@ -418,17 +424,19 @@ const Answer = 42 ` func TestResolveDiagnosticWithDownload(t *testing.T) { - runner.Run(t, testPackageWithRequire, func(t *testing.T, env *Env) { + WithOptions( + ProxyFiles(testPackageWithRequireProxy), + ).Run(t, testPackageWithRequire, func(t *testing.T, env *Env) { env.OpenFile("print.go") // Check that gopackages correctly loaded this dependency. We should get a // diagnostic for the wrong formatting type. // TODO: we should be able to easily also match the diagnostic message. env.Await(env.DiagnosticAtRegexp("print.go", "fmt.Printf")) - }, ProxyFiles(testPackageWithRequireProxy)) + }) } func TestMissingDependency(t *testing.T) { - runner.Run(t, testPackageWithRequire, func(t *testing.T, env *Env) { + Run(t, testPackageWithRequire, func(t *testing.T, env *Env) { env.OpenFile("print.go") env.Await(LogMatching(protocol.Error, "initial workspace load failed", 1)) }) @@ -444,7 +452,7 @@ func Hello() { var x int } ` - runner.Run(t, adHoc, func(t *testing.T, env *Env) { + Run(t, adHoc, func(t *testing.T, env *Env) { env.OpenFile("b/b.go") env.Await(env.DiagnosticAtRegexp("b/b.go", "x")) }) @@ -460,13 +468,13 @@ func _() { fmt.Println("Hello World") } ` - withOptions( + WithOptions( EditorConfig{ Env: map[string]string{ "GOPATH": "", "GO111MODULE": "off", }, - }).run(t, files, func(t *testing.T, env *Env) { + }).Run(t, files, func(t *testing.T, env *Env) { env.OpenFile("main.go") env.Await(env.DiagnosticAtRegexp("main.go", "fmt")) env.SaveBuffer("main.go") @@ -491,7 +499,7 @@ package x var X = 0 ` editorConfig := EditorConfig{Env: map[string]string{"GOFLAGS": "-tags=foo"}} - withOptions(editorConfig).run(t, files, func(t *testing.T, env *Env) { + WithOptions(editorConfig).Run(t, files, func(t *testing.T, env *Env) { env.OpenFile("main.go") env.OrganizeImports("main.go") env.Await(EmptyDiagnostics("main.go")) @@ -516,7 +524,7 @@ func _() { } } ` - runner.Run(t, generated, func(t *testing.T, env *Env) { + Run(t, generated, func(t *testing.T, env *Env) { env.OpenFile("main.go") original := env.ReadWorkspaceFile("main.go") var d protocol.PublishDiagnosticsParams @@ -549,7 +557,7 @@ func f() { hello.Goodbye() } ` - runner.Run(t, noModule, func(t *testing.T, env *Env) { + Run(t, noModule, func(t *testing.T, env *Env) { env.OpenFile("a.go") env.Await( OutstandingWork(lsp.WorkspaceLoadFailure, "outside of a module"), @@ -568,9 +576,9 @@ hi mom ` for _, go111module := range []string{"on", "off", ""} { t.Run(fmt.Sprintf("GO111MODULE_%v", go111module), func(t *testing.T) { - withOptions(EditorConfig{ + WithOptions(EditorConfig{ Env: map[string]string{"GO111MODULE": go111module}, - }).run(t, files, func(t *testing.T, env *Env) { + }).Run(t, files, func(t *testing.T, env *Env) { env.OpenFile("hello.txt") env.Await( OnceMet( @@ -601,7 +609,7 @@ func main() { fmt.Println("") } ` - runner.Run(t, collision, func(t *testing.T, env *Env) { + WithOptions(InGOPATH()).Run(t, collision, func(t *testing.T, env *Env) { env.OpenFile("x/main.go") env.Await( env.DiagnosticAtRegexp("x/main.go", "fmt.Println"), @@ -623,7 +631,7 @@ func main() { ), NoDiagnostics(badFile), ) - }, InGOPATH()) + }) } const ardanLabsProxy = ` @@ -654,9 +662,9 @@ func main() { _ = conf.ErrHelpWanted } ` - withOptions( + WithOptions( ProxyFiles(ardanLabsProxy), - ).run(t, ardanLabs, func(t *testing.T, env *Env) { + ).Run(t, ardanLabs, func(t *testing.T, env *Env) { // Expect a diagnostic with a suggested fix to add // "github.com/ardanlabs/conf" to the go.mod file. env.OpenFile("go.mod") @@ -712,9 +720,9 @@ module mod.com go 1.12 -- main.go -- ` - withOptions( + WithOptions( ProxyFiles(ardanLabsProxy), - ).run(t, emptyFile, func(t *testing.T, env *Env) { + ).Run(t, emptyFile, func(t *testing.T, env *Env) { env.OpenFile("main.go") env.EditBuffer("main.go", fake.NewEdit(0, 0, 0, 0, `package main @@ -757,7 +765,7 @@ func _() { fmt.Println("hi") } ` - runner.Run(t, simplePackage, func(t *testing.T, env *Env) { + Run(t, simplePackage, func(t *testing.T, env *Env) { env.OpenFile("a/a1.go") env.CreateBuffer("a/a2.go", ``) env.SaveBufferWithoutActions("a/a2.go") @@ -802,7 +810,7 @@ func TestHello(t *testing.T) { Hello() } ` - runner.Run(t, testVariant, func(t *testing.T, env *Env) { + Run(t, testVariant, func(t *testing.T, env *Env) { // Open the file, triggering the workspace load. // There are errors in the code to ensure all is working as expected. env.OpenFile("hello/hello.go") @@ -858,7 +866,7 @@ go 1.12 package foo -- foo/bar_test.go -- ` - run(t, mod, func(t *testing.T, env *Env) { + Run(t, mod, func(t *testing.T, env *Env) { env.OpenFile("foo/bar_test.go") env.EditBuffer("foo/bar_test.go", fake.NewEdit(0, 0, 0, 0, "package foo")) env.Await(env.DoneWithChange()) @@ -889,7 +897,7 @@ package foo -- foo/bar_test.go -- package foo_ ` - run(t, mod, func(t *testing.T, env *Env) { + Run(t, mod, func(t *testing.T, env *Env) { env.OpenFile("foo/bar_test.go") env.RegexpReplace("foo/bar_test.go", "package foo_", "package foo_test") env.SaveBuffer("foo/bar_test.go") @@ -914,7 +922,7 @@ package x -- x_test.go -- ` - withOptions(InGOPATH()).run(t, files, func(t *testing.T, env *Env) { + WithOptions(InGOPATH()).Run(t, files, func(t *testing.T, env *Env) { env.OpenFile("x_test.go") env.EditBuffer("x_test.go", fake.NewEdit(0, 0, 0, 0, "pack")) env.Await( @@ -935,7 +943,7 @@ package x var _ = foo.Bar ` - runner.Run(t, ws, func(t *testing.T, env *Env) { + Run(t, ws, func(t *testing.T, env *Env) { env.OpenFile("_foo/x.go") env.Await( OnceMet( @@ -973,7 +981,7 @@ import "mod.com/a" const C = a.A ` - runner.Run(t, ws, func(t *testing.T, env *Env) { + Run(t, ws, func(t *testing.T, env *Env) { env.OpenFile("b/b.go") env.Await(env.DoneWithOpen()) // Delete c/c.go, the only file in package c. @@ -1026,7 +1034,7 @@ func main() { // A simple version of the test that reproduces most of the problems it // exposes. t.Run("short", func(t *testing.T) { - runner.Run(t, mod, func(t *testing.T, env *Env) { + Run(t, mod, func(t *testing.T, env *Env) { writeGoVim(env, "p/p.go", p) writeGoVim(env, "main.go", main) env.Await(env.DiagnosticAtRegexp("main.go", "5")) @@ -1035,7 +1043,7 @@ func main() { // A full version that replicates the whole flow of the test. t.Run("full", func(t *testing.T) { - runner.Run(t, mod, func(t *testing.T, env *Env) { + Run(t, mod, func(t *testing.T, env *Env) { writeGoVim(env, "p/p.go", p) writeGoVim(env, "main.go", main) writeGoVim(env, "p/p_test.go", `package p @@ -1086,10 +1094,10 @@ func _() { var x int } ` - withOptions( + WithOptions( // Empty workspace folders. WorkspaceFolders(), - ).run(t, mod, func(t *testing.T, env *Env) { + ).Run(t, mod, func(t *testing.T, env *Env) { env.OpenFile("a/a.go") env.Await( env.DiagnosticAtRegexp("a/a.go", "x"), @@ -1114,7 +1122,7 @@ func Foo() { fmt.Println("") } ` - runner.Run(t, basic, func(t *testing.T, env *Env) { + Run(t, basic, func(t *testing.T, env *Env) { testenv.NeedsGo1Point(t, 15) env.WriteWorkspaceFile("foo/foo_test.go", `package main @@ -1144,7 +1152,7 @@ package main func main() {} ` - runner.Run(t, basic, func(t *testing.T, env *Env) { + Run(t, basic, func(t *testing.T, env *Env) { env.Editor.CreateBuffer(env.Ctx, "foo.go", `package main`) env.Await( env.DoneWithOpen(), @@ -1169,7 +1177,7 @@ go 1.14 -- main2.go -- package main ` - runner.Run(t, basic, func(t *testing.T, env *Env) { + Run(t, basic, func(t *testing.T, env *Env) { env.CreateBuffer("main.go", "") env.Await(env.DoneWithOpen()) @@ -1215,7 +1223,7 @@ package default func main() {} ` - runner.Run(t, pkgDefault, func(t *testing.T, env *Env) { + Run(t, pkgDefault, func(t *testing.T, env *Env) { env.OpenFile("main.go") env.Await( env.DiagnosticAtRegexp("main.go", "default"), @@ -1241,18 +1249,18 @@ func main() { var x int } ` - withOptions( + WithOptions( WorkspaceFolders("a"), - ).run(t, mod, func(t *testing.T, env *Env) { + ).Run(t, mod, func(t *testing.T, env *Env) { env.OpenFile("a/main.go") env.Await( env.DiagnosticAtRegexp("main.go", "x"), ) }) - withOptions( + WithOptions( WorkspaceFolders("a"), LimitWorkspaceScope(), - ).run(t, mod, func(t *testing.T, env *Env) { + ).Run(t, mod, func(t *testing.T, env *Env) { env.OpenFile("a/main.go") env.Await( NoDiagnostics("main.go"), @@ -1281,9 +1289,9 @@ func main() { } ` - withOptions( + WithOptions( EditorConfig{EnableStaticcheck: true}, - ).run(t, files, func(t *testing.T, env *Env) { + ).Run(t, files, func(t *testing.T, env *Env) { env.OpenFile("main.go") // Staticcheck should generate a diagnostic to simplify this literal. env.Await(env.DiagnosticAtRegexp("main.go", `t{"msg"}`)) @@ -1306,7 +1314,7 @@ func main() { package main func main() {} ` - runner.Run(t, dir, func(t *testing.T, env *Env) { + Run(t, dir, func(t *testing.T, env *Env) { log.SetFlags(log.Lshortfile) env.OpenFile("main.go") env.OpenFile("other.go") @@ -1357,7 +1365,7 @@ func _() { var x int } ` - run(t, files, func(t *testing.T, env *Env) { + Run(t, files, func(t *testing.T, env *Env) { env.OpenFile("a/a.go") env.Await( env.DiagnosticAtRegexp("a/a.go", "x"), @@ -1384,11 +1392,11 @@ func b(c bytes.Buffer) { _ = 1 } ` - withOptions( + WithOptions( EditorConfig{ AllExperiments: true, }, - ).run(t, mod, func(t *testing.T, env *Env) { + ).Run(t, mod, func(t *testing.T, env *Env) { // Confirm that the setting doesn't cause any warnings. env.Await(NoShowMessage()) }) @@ -1431,7 +1439,7 @@ func main() { var x int } ` - run(t, mod, func(t *testing.T, env *Env) { + Run(t, mod, func(t *testing.T, env *Env) { env.Await( OnceMet( InitialWorkspaceLoad, @@ -1448,6 +1456,25 @@ func main() { func TestRenamePackage(t *testing.T) { testenv.NeedsGo1Point(t, 16) + const proxy = ` +-- example.com@v1.2.3/go.mod -- +module example.com + +go 1.12 +-- example.com@v1.2.3/blah/blah.go -- +package blah + +const Name = "Blah" +-- random.org@v1.2.3/go.mod -- +module random.org + +go 1.12 +-- random.org@v1.2.3/blah/blah.go -- +package hello + +const Name = "Hello" +` + const contents = ` -- go.mod -- module mod.com @@ -1469,10 +1496,10 @@ package foo package foo_ ` - withOptions( + WithOptions( ProxyFiles(proxy), InGOPATH(), - ).run(t, contents, func(t *testing.T, env *Env) { + ).Run(t, contents, func(t *testing.T, env *Env) { // Simulate typing character by character. env.OpenFile("foo/foo_test.go") env.Await(env.DoneWithOpen()) @@ -1501,7 +1528,7 @@ go 1.12 -- main.go -- package main ` - run(t, pkg, func(t *testing.T, env *Env) { + Run(t, pkg, func(t *testing.T, env *Env) { env.OpenFile("go.mod") env.Await( OutstandingWork(lsp.WorkspaceLoadFailure, "unknown directive"), @@ -1545,7 +1572,7 @@ func main() { bob.Hello() } ` - run(t, mod, func(t *testing.T, env *Env) { + Run(t, mod, func(t *testing.T, env *Env) { env.RemoveWorkspaceFile("bob") env.Await( env.DiagnosticAtRegexp("main.go", `"mod.com/bob"`), @@ -1587,7 +1614,7 @@ package c import _ "mod.com/triple/a" ` - run(t, mod, func(t *testing.T, env *Env) { + Run(t, mod, func(t *testing.T, env *Env) { env.Await( env.DiagnosticAtRegexpWithMessage("self/self.go", `_ "mod.com/self"`, "import cycle not allowed"), env.DiagnosticAtRegexpWithMessage("double/a/a.go", `_ "mod.com/double/b"`, "import cycle not allowed"), @@ -1612,20 +1639,20 @@ import ( ) ` t.Run("module", func(t *testing.T) { - run(t, mod, func(t *testing.T, env *Env) { + Run(t, mod, func(t *testing.T, env *Env) { env.Await( env.DiagnosticAtRegexpWithMessage("main.go", `"nosuchpkg"`, `could not import nosuchpkg (no required module provides package "nosuchpkg"`), ) }) }) t.Run("GOPATH", func(t *testing.T) { - withOptions( + WithOptions( InGOPATH(), EditorConfig{ Env: map[string]string{"GO111MODULE": "off"}, }, Modes(Singleton), - ).run(t, mod, func(t *testing.T, env *Env) { + ).Run(t, mod, func(t *testing.T, env *Env) { env.Await( env.DiagnosticAtRegexpWithMessage("main.go", `"nosuchpkg"`, `cannot find package "nosuchpkg" in any of`), ) @@ -1650,14 +1677,14 @@ package b ` for _, go111module := range []string{"on", "auto"} { t.Run("GO111MODULE="+go111module, func(t *testing.T) { - withOptions( + WithOptions( Modes(Singleton), EditorConfig{ Env: map[string]string{ "GO111MODULE": go111module, }, }, - ).run(t, modules, func(t *testing.T, env *Env) { + ).Run(t, modules, func(t *testing.T, env *Env) { env.OpenFile("a/a.go") env.OpenFile("b/go.mod") env.Await( @@ -1671,7 +1698,7 @@ package b // Expect no warning if GO111MODULE=auto in a directory in GOPATH. t.Run("GOPATH_GO111MODULE_auto", func(t *testing.T) { - withOptions( + WithOptions( Modes(Singleton), EditorConfig{ Env: map[string]string{ @@ -1679,7 +1706,7 @@ package b }, }, InGOPATH(), - ).run(t, modules, func(t *testing.T, env *Env) { + ).Run(t, modules, func(t *testing.T, env *Env) { env.OpenFile("a/a.go") env.Await( OnceMet( @@ -1736,10 +1763,10 @@ package hello func helloHelper() {} ` - withOptions( + WithOptions( ProxyFiles(proxy), Modes(Singleton), - ).run(t, nested, func(t *testing.T, env *Env) { + ).Run(t, nested, func(t *testing.T, env *Env) { // Expect a diagnostic in a nested module. env.OpenFile("nested/hello/hello.go") didOpen := env.DoneWithOpen() @@ -1767,7 +1794,7 @@ package main func main() {} ` - run(t, nomod, func(t *testing.T, env *Env) { + Run(t, nomod, func(t *testing.T, env *Env) { env.OpenFile("main.go") env.RegexpReplace("main.go", "{}", "{ var x int; }") // simulate typing env.Await( diff --git a/gopls/internal/regtest/configuration_test.go b/gopls/internal/regtest/misc/configuration_test.go similarity index 84% rename from gopls/internal/regtest/configuration_test.go rename to gopls/internal/regtest/misc/configuration_test.go index a197da70191..d299e3f40a3 100644 --- a/gopls/internal/regtest/configuration_test.go +++ b/gopls/internal/regtest/misc/configuration_test.go @@ -2,11 +2,13 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package regtest +package misc import ( "testing" + . "golang.org/x/tools/gopls/internal/regtest" + "golang.org/x/tools/internal/lsp/fake" ) @@ -24,7 +26,7 @@ package a // NotThisVariable should really start with ThisVariable. const ThisVariable = 7 ` - run(t, files, func(t *testing.T, env *Env) { + Run(t, files, func(t *testing.T, env *Env) { env.OpenFile("a/a.go") env.Await( env.DoneWithOpen(), @@ -33,7 +35,7 @@ const ThisVariable = 7 cfg := &fake.EditorConfig{} *cfg = env.Editor.Config cfg.EnableStaticcheck = true - env.changeConfiguration(t, cfg) + env.ChangeConfiguration(t, cfg) env.Await( DiagnosticAt("a/a.go", 2, 0), ) diff --git a/gopls/internal/regtest/definition_test.go b/gopls/internal/regtest/misc/definition_test.go similarity index 91% rename from gopls/internal/regtest/definition_test.go rename to gopls/internal/regtest/misc/definition_test.go index 36a935238ef..a5e220c6e31 100644 --- a/gopls/internal/regtest/definition_test.go +++ b/gopls/internal/regtest/misc/definition_test.go @@ -2,13 +2,15 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package regtest +package misc import ( "path" "strings" "testing" + . "golang.org/x/tools/gopls/internal/regtest" + "golang.org/x/tools/internal/lsp/tests" ) @@ -32,7 +34,7 @@ const message = "Hello World." ` func TestGoToInternalDefinition(t *testing.T) { - runner.Run(t, internalDefinition, func(t *testing.T, env *Env) { + Run(t, internalDefinition, func(t *testing.T, env *Env) { env.OpenFile("main.go") name, pos := env.GoToDefinition("main.go", env.RegexpSearch("main.go", "message")) if want := "const.go"; name != want { @@ -59,7 +61,7 @@ func main() { }` func TestGoToStdlibDefinition_Issue37045(t *testing.T) { - runner.Run(t, stdlibDefinition, func(t *testing.T, env *Env) { + Run(t, stdlibDefinition, func(t *testing.T, env *Env) { env.OpenFile("main.go") name, pos := env.GoToDefinition("main.go", env.RegexpSearch("main.go", `fmt.(Printf)`)) if got, want := path.Base(name), "print.go"; got != want { @@ -79,7 +81,7 @@ func TestGoToStdlibDefinition_Issue37045(t *testing.T) { } func TestUnexportedStdlib_Issue40809(t *testing.T) { - runner.Run(t, stdlibDefinition, func(t *testing.T, env *Env) { + Run(t, stdlibDefinition, func(t *testing.T, env *Env) { env.OpenFile("main.go") name, _ := env.GoToDefinition("main.go", env.RegexpSearch("main.go", `fmt.(Printf)`)) env.OpenFile(name) @@ -120,7 +122,7 @@ func main() { var err error err.Error() }` - run(t, mod, func(t *testing.T, env *Env) { + Run(t, mod, func(t *testing.T, env *Env) { env.OpenFile("main.go") content, _ := env.Hover("main.go", env.RegexpSearch("main.go", "Error")) if content == nil { diff --git a/gopls/internal/regtest/failures_test.go b/gopls/internal/regtest/misc/failures_test.go similarity index 89% rename from gopls/internal/regtest/failures_test.go rename to gopls/internal/regtest/misc/failures_test.go index 4da6ce826cc..68bbded8c42 100644 --- a/gopls/internal/regtest/failures_test.go +++ b/gopls/internal/regtest/misc/failures_test.go @@ -2,11 +2,13 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package regtest +package misc import ( "log" "testing" + + . "golang.org/x/tools/gopls/internal/regtest" ) // This test passes (TestHoverOnError in definition_test.go) without @@ -28,7 +30,7 @@ func main() { var err error err.Error() }` - withOptions(SkipLogs()).run(t, mod, func(t *testing.T, env *Env) { + WithOptions(SkipLogs()).Run(t, mod, func(t *testing.T, env *Env) { env.OpenFile("main.go") content, _ := env.Hover("main.go", env.RegexpSearch("main.go", "Error")) // without the //line comment content would be non-nil @@ -56,7 +58,7 @@ const a = 2 ` func TestFailingDiagnosticClearingOnEdit(t *testing.T) { - runner.Run(t, badPackageDup, func(t *testing.T, env *Env) { + Run(t, badPackageDup, func(t *testing.T, env *Env) { log.SetFlags(log.Lshortfile) env.OpenFile("b.go") env.Await(env.AnyDiagnosticAtCurrentVersion("a.go")) diff --git a/gopls/internal/regtest/fix_test.go b/gopls/internal/regtest/misc/fix_test.go similarity index 92% rename from gopls/internal/regtest/fix_test.go rename to gopls/internal/regtest/misc/fix_test.go index e513148de12..a2566093316 100644 --- a/gopls/internal/regtest/fix_test.go +++ b/gopls/internal/regtest/misc/fix_test.go @@ -2,11 +2,13 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package regtest +package misc import ( "testing" + . "golang.org/x/tools/gopls/internal/regtest" + "golang.org/x/tools/internal/lsp/protocol" "golang.org/x/tools/internal/lsp/tests" ) @@ -27,7 +29,7 @@ func Foo() { _ = types.Info{} } ` - runner.Run(t, basic, func(t *testing.T, env *Env) { + Run(t, basic, func(t *testing.T, env *Env) { env.OpenFile("main.go") if err := env.Editor.RefactorRewrite(env.Ctx, "main.go", &protocol.Range{ Start: protocol.Position{ diff --git a/gopls/internal/regtest/formatting_test.go b/gopls/internal/regtest/misc/formatting_test.go similarity index 90% rename from gopls/internal/regtest/formatting_test.go rename to gopls/internal/regtest/misc/formatting_test.go index e6dba332858..0ad5fbb7870 100644 --- a/gopls/internal/regtest/formatting_test.go +++ b/gopls/internal/regtest/misc/formatting_test.go @@ -2,12 +2,14 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package regtest +package misc import ( "strings" "testing" + . "golang.org/x/tools/gopls/internal/regtest" + "golang.org/x/tools/internal/lsp/tests" ) @@ -29,7 +31,7 @@ func main() { ` func TestFormatting(t *testing.T) { - runner.Run(t, unformattedProgram, func(t *testing.T, env *Env) { + Run(t, unformattedProgram, func(t *testing.T, env *Env) { env.OpenFile("main.go") env.FormatBuffer("main.go") got := env.Editor.BufferText("main.go") @@ -51,7 +53,7 @@ package main func f() {} ` - runner.Run(t, onelineProgram, func(t *testing.T, env *Env) { + Run(t, onelineProgram, func(t *testing.T, env *Env) { env.OpenFile("a.go") env.FormatBuffer("a.go") got := env.Editor.BufferText("a.go") @@ -75,7 +77,7 @@ import "fmt" func f() { fmt.Println() } ` - runner.Run(t, onelineProgramA, func(t *testing.T, env *Env) { + Run(t, onelineProgramA, func(t *testing.T, env *Env) { env.OpenFile("a.go") env.OrganizeImports("a.go") got := env.Editor.BufferText("a.go") @@ -96,7 +98,7 @@ package x func f() {} ` - runner.Run(t, onelineProgramB, func(t *testing.T, env *Env) { + Run(t, onelineProgramB, func(t *testing.T, env *Env) { env.OpenFile("a.go") env.OrganizeImports("a.go") got := env.Editor.BufferText("a.go") @@ -142,7 +144,7 @@ func main() { ` func TestOrganizeImports(t *testing.T) { - runner.Run(t, disorganizedProgram, func(t *testing.T, env *Env) { + Run(t, disorganizedProgram, func(t *testing.T, env *Env) { env.OpenFile("main.go") env.OrganizeImports("main.go") got := env.Editor.BufferText("main.go") @@ -154,7 +156,7 @@ func TestOrganizeImports(t *testing.T) { } func TestFormattingOnSave(t *testing.T) { - runner.Run(t, disorganizedProgram, func(t *testing.T, env *Env) { + Run(t, disorganizedProgram, func(t *testing.T, env *Env) { env.OpenFile("main.go") env.SaveBuffer("main.go") got := env.Editor.BufferText("main.go") @@ -224,7 +226,7 @@ type Tree struct { }, } { t.Run(tt.issue, func(t *testing.T) { - run(t, "-- main.go --", func(t *testing.T, env *Env) { + Run(t, "-- main.go --", func(t *testing.T, env *Env) { crlf := strings.ReplaceAll(tt.want, "\n", "\r\n") env.CreateBuffer("main.go", crlf) env.Await(env.DoneWithOpen()) diff --git a/gopls/internal/regtest/generate_test.go b/gopls/internal/regtest/misc/generate_test.go similarity index 87% rename from gopls/internal/regtest/generate_test.go rename to gopls/internal/regtest/misc/generate_test.go index 8e6751f5efe..69879242ba0 100644 --- a/gopls/internal/regtest/generate_test.go +++ b/gopls/internal/regtest/misc/generate_test.go @@ -6,10 +6,12 @@ // +build !android -package regtest +package misc import ( "testing" + + . "golang.org/x/tools/gopls/internal/regtest" ) func TestGenerateProgress(t *testing.T) { @@ -38,7 +40,7 @@ func GetAnswer() int { //go:generate go run generate.go ` - runner.Run(t, generatedWorkspace, func(t *testing.T, env *Env) { + Run(t, generatedWorkspace, func(t *testing.T, env *Env) { env.Await( env.DiagnosticAtRegexp("lib/lib.go", "answer"), ) diff --git a/gopls/internal/regtest/imports_test.go b/gopls/internal/regtest/misc/imports_test.go similarity index 92% rename from gopls/internal/regtest/imports_test.go rename to gopls/internal/regtest/misc/imports_test.go index 1c52d59fc4a..9a95208cb5b 100644 --- a/gopls/internal/regtest/imports_test.go +++ b/gopls/internal/regtest/misc/imports_test.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package regtest +package misc import ( "io/ioutil" @@ -11,6 +11,8 @@ import ( "strings" "testing" + . "golang.org/x/tools/gopls/internal/regtest" + "golang.org/x/tools/internal/lsp/protocol" "golang.org/x/tools/internal/testenv" ) @@ -42,7 +44,7 @@ func TestZ(t *testing.T) { // it was returning // "package main\nimport \"testing\"\npackage main..." - runner.Run(t, needs, func(t *testing.T, env *Env) { + Run(t, needs, func(t *testing.T, env *Env) { env.CreateBuffer("a_test.go", ntest) env.SaveBuffer("a_test.go") got := env.Editor.BufferText("a_test.go") @@ -69,7 +71,7 @@ func main() { // The file remains unchanged, but if there are any CodeActions returned, they confuse vim. // Therefore check for no CodeActions - runner.Run(t, "", func(t *testing.T, env *Env) { + Run(t, "", func(t *testing.T, env *Env) { env.CreateBuffer("main.go", vim1) env.OrganizeImports("main.go") actions := env.CodeAction("main.go") @@ -102,7 +104,7 @@ func main() { } ` - runner.Run(t, "", func(t *testing.T, env *Env) { + Run(t, "", func(t *testing.T, env *Env) { env.CreateBuffer("main.go", vim2) env.OrganizeImports("main.go") actions := env.CodeAction("main.go") @@ -152,10 +154,10 @@ var _, _ = x.X, y.Y } defer os.RemoveAll(modcache) editorConfig := EditorConfig{Env: map[string]string{"GOMODCACHE": modcache}} - withOptions( + WithOptions( editorConfig, ProxyFiles(proxy), - ).run(t, files, func(t *testing.T, env *Env) { + ).Run(t, files, func(t *testing.T, env *Env) { env.OpenFile("main.go") env.Await(env.DiagnosticAtRegexp("main.go", `y.Y`)) env.SaveBuffer("main.go") @@ -197,7 +199,7 @@ func TestA(t *testing.T) { os.Stat("") } ` - run(t, pkg, func(t *testing.T, env *Env) { + Run(t, pkg, func(t *testing.T, env *Env) { env.OpenFile("a/a.go") var d protocol.PublishDiagnosticsParams env.Await( diff --git a/gopls/internal/regtest/link_test.go b/gopls/internal/regtest/misc/link_test.go similarity index 94% rename from gopls/internal/regtest/link_test.go rename to gopls/internal/regtest/misc/link_test.go index 1e662a4ed4e..320a3eac421 100644 --- a/gopls/internal/regtest/link_test.go +++ b/gopls/internal/regtest/misc/link_test.go @@ -2,12 +2,14 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package regtest +package misc import ( "strings" "testing" + . "golang.org/x/tools/gopls/internal/regtest" + "golang.org/x/tools/internal/testenv" ) @@ -42,7 +44,9 @@ package pkg const Hello = "Hello" ` - runner.Run(t, program, func(t *testing.T, env *Env) { + WithOptions( + ProxyFiles(proxy), + ).Run(t, program, func(t *testing.T, env *Env) { env.OpenFile("main.go") env.OpenFile("go.mod") @@ -87,5 +91,5 @@ const Hello = "Hello" if len(links) != 0 { t.Errorf("documentLink: got %d document links for go.mod, want 0\nlinks: %v", len(links), links) } - }, ProxyFiles(proxy)) + }) } diff --git a/gopls/internal/regtest/misc/misc_test.go b/gopls/internal/regtest/misc/misc_test.go new file mode 100644 index 00000000000..0f424706071 --- /dev/null +++ b/gopls/internal/regtest/misc/misc_test.go @@ -0,0 +1,15 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package misc + +import ( + "testing" + + "golang.org/x/tools/gopls/internal/regtest" +) + +func TestMain(m *testing.M) { + regtest.Main(m) +} diff --git a/gopls/internal/regtest/references_test.go b/gopls/internal/regtest/misc/references_test.go similarity index 88% rename from gopls/internal/regtest/references_test.go rename to gopls/internal/regtest/misc/references_test.go index db94ed8c19a..93276362af8 100644 --- a/gopls/internal/regtest/references_test.go +++ b/gopls/internal/regtest/misc/references_test.go @@ -2,10 +2,12 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package regtest +package misc import ( "testing" + + . "golang.org/x/tools/gopls/internal/regtest" ) func TestStdlibReferences(t *testing.T) { @@ -24,7 +26,7 @@ func main() { } ` - run(t, files, func(t *testing.T, env *Env) { + Run(t, files, func(t *testing.T, env *Env) { env.OpenFile("main.go") file, pos := env.GoToDefinition("main.go", env.RegexpSearch("main.go", `fmt.(Print)`)) refs, err := env.Editor.References(env.Ctx, file, pos) diff --git a/gopls/internal/regtest/shared_test.go b/gopls/internal/regtest/misc/shared_test.go similarity index 78% rename from gopls/internal/regtest/shared_test.go rename to gopls/internal/regtest/misc/shared_test.go index 10c39b068af..376d378ae7d 100644 --- a/gopls/internal/regtest/shared_test.go +++ b/gopls/internal/regtest/misc/shared_test.go @@ -2,10 +2,12 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package regtest +package misc import ( "testing" + + . "golang.org/x/tools/gopls/internal/regtest" ) const sharedProgram = ` @@ -22,19 +24,19 @@ func main() { fmt.Println("Hello World.") }` -func runShared(t *testing.T, program string, testFunc func(env1 *Env, env2 *Env)) { +func runShared(t *testing.T, testFunc func(env1 *Env, env2 *Env)) { // Only run these tests in forwarded modes. - modes := runner.DefaultModes & (Forwarded | SeparateProcess) - runner.Run(t, sharedProgram, func(t *testing.T, env1 *Env) { + modes := DefaultModes() & (Forwarded | SeparateProcess) + WithOptions(Modes(modes)).Run(t, sharedProgram, func(t *testing.T, env1 *Env) { // Create a second test session connected to the same workspace and server // as the first. env2 := NewEnv(env1.Ctx, t, env1.Sandbox, env1.Server, env1.Editor.Config, true) testFunc(env1, env2) - }, Modes(modes)) + }) } func TestSimultaneousEdits(t *testing.T) { - runShared(t, exampleProgram, func(env1 *Env, env2 *Env) { + runShared(t, func(env1 *Env, env2 *Env) { // In editor #1, break fmt.Println as before. env1.OpenFile("main.go") env1.RegexpReplace("main.go", "Printl(n)", "") @@ -49,7 +51,7 @@ func TestSimultaneousEdits(t *testing.T) { } func TestShutdown(t *testing.T) { - runShared(t, sharedProgram, func(env1 *Env, env2 *Env) { + runShared(t, func(env1 *Env, env2 *Env) { env1.CloseEditor() // Now make an edit in editor #2 to trigger diagnostics. env2.OpenFile("main.go") diff --git a/gopls/internal/regtest/vendor_test.go b/gopls/internal/regtest/misc/vendor_test.go similarity index 93% rename from gopls/internal/regtest/vendor_test.go rename to gopls/internal/regtest/misc/vendor_test.go index dd318ffdbfa..026309095e7 100644 --- a/gopls/internal/regtest/vendor_test.go +++ b/gopls/internal/regtest/misc/vendor_test.go @@ -2,11 +2,13 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package regtest +package misc import ( "testing" + . "golang.org/x/tools/gopls/internal/regtest" + "golang.org/x/tools/internal/lsp/protocol" "golang.org/x/tools/internal/lsp/source" "golang.org/x/tools/internal/testenv" @@ -48,10 +50,10 @@ func _() { } ` // TODO(rstambler): Remove this when golang/go#41819 is resolved. - withOptions( + WithOptions( Modes(Singleton), ProxyFiles(basicProxy), - ).run(t, pkgThatUsesVendoring, func(t *testing.T, env *Env) { + ).Run(t, pkgThatUsesVendoring, func(t *testing.T, env *Env) { env.OpenFile("a/a1.go") env.Await( // The editor should pop up a message suggesting that the user diff --git a/gopls/internal/regtest/modfile_test.go b/gopls/internal/regtest/modfile/modfile_test.go similarity index 88% rename from gopls/internal/regtest/modfile_test.go rename to gopls/internal/regtest/modfile/modfile_test.go index 4cfc063cd38..c7c3d636baf 100644 --- a/gopls/internal/regtest/modfile_test.go +++ b/gopls/internal/regtest/modfile/modfile_test.go @@ -2,18 +2,47 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package regtest +package modfile import ( "path/filepath" "strings" "testing" + . "golang.org/x/tools/gopls/internal/regtest" + "golang.org/x/tools/internal/lsp/protocol" "golang.org/x/tools/internal/lsp/tests" "golang.org/x/tools/internal/testenv" ) +func TestMain(m *testing.M) { + Main(m) +} + +const workspaceProxy = ` +-- example.com@v1.2.3/go.mod -- +module example.com + +go 1.12 +-- example.com@v1.2.3/blah/blah.go -- +package blah + +func SaySomething() { + fmt.Println("something") +} +-- random.org@v1.2.3/go.mod -- +module random.org + +go 1.12 +-- random.org@v1.2.3/bye/bye.go -- +package bye + +func Goodbye() { + println("Bye") +} +` + const proxy = ` -- example.com@v1.2.3/go.mod -- module example.com @@ -50,13 +79,13 @@ func main() { } ` - runner := runMultiple{ - {"default", withOptions(ProxyFiles(proxy), WorkspaceFolders("a"))}, - {"nested", withOptions(ProxyFiles(proxy))}, + runner := RunMultiple{ + {"default", WithOptions(ProxyFiles(proxy), WorkspaceFolders("a"))}, + {"nested", WithOptions(ProxyFiles(proxy))}, } t.Run("basic", func(t *testing.T) { - runner.run(t, untidyModule, func(t *testing.T, env *Env) { + runner.Run(t, untidyModule, func(t *testing.T, env *Env) { // Open the file and make sure that the initial workspace load does not // modify the go.mod file. goModContent := env.ReadWorkspaceFile("a/go.mod") @@ -83,7 +112,7 @@ func main() { t.Run("delete main.go", func(t *testing.T) { t.Skip("This test will be flaky until golang/go#40269 is resolved.") - runner.run(t, untidyModule, func(t *testing.T, env *Env) { + runner.Run(t, untidyModule, func(t *testing.T, env *Env) { goModContent := env.ReadWorkspaceFile("a/go.mod") mainContent := env.ReadWorkspaceFile("a/main.go") env.OpenFile("a/main.go") @@ -130,10 +159,10 @@ go 1.12 require example.com v1.2.3 ` - runMultiple{ - {"default", withOptions(ProxyFiles(proxy), WorkspaceFolders("a"))}, - {"nested", withOptions(ProxyFiles(proxy))}, - }.run(t, mod, func(t *testing.T, env *Env) { + RunMultiple{ + {"default", WithOptions(ProxyFiles(proxy), WorkspaceFolders("a"))}, + {"nested", WithOptions(ProxyFiles(proxy))}, + }.Run(t, mod, func(t *testing.T, env *Env) { if strings.Contains(t.Name(), "workspace_module") { t.Skip("workspace module mode doesn't set -mod=readonly") } @@ -183,10 +212,10 @@ go 1.12 require random.org v1.2.3 ` - runMultiple{ - {"default", withOptions(ProxyFiles(proxy), WorkspaceFolders("a"))}, - {"nested", withOptions(ProxyFiles(proxy))}, - }.run(t, mod, func(t *testing.T, env *Env) { + RunMultiple{ + {"default", WithOptions(ProxyFiles(proxy), WorkspaceFolders("a"))}, + {"nested", WithOptions(ProxyFiles(proxy))}, + }.Run(t, mod, func(t *testing.T, env *Env) { env.OpenFile("a/main.go") var d protocol.PublishDiagnosticsParams env.Await( @@ -236,10 +265,10 @@ go 1.12 require example.com v1.2.3 ` - runMultiple{ - {"default", withOptions(ProxyFiles(proxy), WorkspaceFolders("a"))}, - {"nested", withOptions(ProxyFiles(proxy))}, - }.run(t, mod, func(t *testing.T, env *Env) { + RunMultiple{ + {"default", WithOptions(ProxyFiles(proxy), WorkspaceFolders("a"))}, + {"nested", WithOptions(ProxyFiles(proxy))}, + }.Run(t, mod, func(t *testing.T, env *Env) { env.OpenFile("a/go.mod") var d protocol.PublishDiagnosticsParams env.Await( @@ -281,10 +310,10 @@ func main() {} go 1.14 ` - runMultiple{ - {"default", withOptions(ProxyFiles(proxy), WorkspaceFolders("a"))}, - {"nested", withOptions(ProxyFiles(proxy))}, - }.run(t, files, func(t *testing.T, env *Env) { + RunMultiple{ + {"default", WithOptions(ProxyFiles(proxy), WorkspaceFolders("a"))}, + {"nested", WithOptions(ProxyFiles(proxy))}, + }.Run(t, files, func(t *testing.T, env *Env) { env.OpenFile("a/go.mod") var d protocol.PublishDiagnosticsParams env.Await( @@ -344,10 +373,10 @@ func _() { caire.RemoveTempImage() }` - runMultiple{ - {"default", withOptions(ProxyFiles(proxy), WorkspaceFolders("a"))}, - {"nested", withOptions(ProxyFiles(proxy))}, - }.run(t, repro, func(t *testing.T, env *Env) { + RunMultiple{ + {"default", WithOptions(ProxyFiles(proxy), WorkspaceFolders("a"))}, + {"nested", WithOptions(ProxyFiles(proxy))}, + }.Run(t, repro, func(t *testing.T, env *Env) { env.OpenFile("a/main.go") var d protocol.PublishDiagnosticsParams env.Await( @@ -394,10 +423,10 @@ package main func main() { fmt.Println(blah.Name) ` - runMultiple{ - {"default", withOptions(ProxyFiles(proxy), WorkspaceFolders("a"))}, - {"nested", withOptions(ProxyFiles(proxy))}, - }.run(t, mod, func(t *testing.T, env *Env) { + RunMultiple{ + {"default", WithOptions(ProxyFiles(proxy), WorkspaceFolders("a"))}, + {"nested", WithOptions(ProxyFiles(proxy))}, + }.Run(t, mod, func(t *testing.T, env *Env) { env.Await(env.DiagnosticAtRegexp("a/go.mod", "require")) env.RunGoCommandInDir("a", "mod", "tidy") env.Await( @@ -451,10 +480,10 @@ import "example.com/blah/v2" var _ = blah.Name ` - runMultiple{ - {"default", withOptions(ProxyFiles(proxy), WorkspaceFolders("a"))}, - {"nested", withOptions(ProxyFiles(proxy))}, - }.run(t, files, func(t *testing.T, env *Env) { + RunMultiple{ + {"default", WithOptions(ProxyFiles(proxy), WorkspaceFolders("a"))}, + {"nested", WithOptions(ProxyFiles(proxy))}, + }.Run(t, files, func(t *testing.T, env *Env) { env.OpenFile("a/main.go") env.OpenFile("a/go.mod") var d protocol.PublishDiagnosticsParams @@ -502,13 +531,13 @@ func main() { } ` - runner := runMultiple{ - {"default", withOptions(ProxyFiles(proxy), WorkspaceFolders("a"))}, - {"nested", withOptions(ProxyFiles(proxy))}, + runner := RunMultiple{ + {"default", WithOptions(ProxyFiles(proxy), WorkspaceFolders("a"))}, + {"nested", WithOptions(ProxyFiles(proxy))}, } // Start from a bad state/bad IWL, and confirm that we recover. t.Run("bad", func(t *testing.T) { - runner.run(t, unknown, func(t *testing.T, env *Env) { + runner.Run(t, unknown, func(t *testing.T, env *Env) { env.OpenFile("a/go.mod") env.Await( env.DiagnosticAtRegexp("a/go.mod", "example.com v1.2.2"), @@ -554,7 +583,7 @@ func main() { // Start from a good state, transform to a bad state, and confirm that we // still recover. t.Run("good", func(t *testing.T) { - runner.run(t, known, func(t *testing.T, env *Env) { + runner.Run(t, known, func(t *testing.T, env *Env) { env.OpenFile("a/go.mod") env.Await( env.DiagnosticAtRegexp("a/main.go", "x = "), @@ -614,10 +643,10 @@ func main() { println(blah.Name) } ` - runMultiple{ - {"default", withOptions(ProxyFiles(badProxy), WorkspaceFolders("a"))}, - {"nested", withOptions(ProxyFiles(badProxy))}, - }.run(t, module, func(t *testing.T, env *Env) { + RunMultiple{ + {"default", WithOptions(ProxyFiles(badProxy), WorkspaceFolders("a"))}, + {"nested", WithOptions(ProxyFiles(badProxy))}, + }.Run(t, module, func(t *testing.T, env *Env) { env.OpenFile("a/go.mod") env.Await( env.DiagnosticAtRegexp("a/go.mod", "require example.com v1.2.3"), @@ -641,7 +670,7 @@ func main() { println(blah.Name) } ` - withOptions( + WithOptions( EditorConfig{ Env: map[string]string{ "GOFLAGS": "-mod=readonly", @@ -649,7 +678,7 @@ func main() { }, ProxyFiles(proxy), Modes(Singleton), - ).run(t, mod, func(t *testing.T, env *Env) { + ).Run(t, mod, func(t *testing.T, env *Env) { env.OpenFile("main.go") original := env.ReadWorkspaceFile("go.mod") env.Await( @@ -696,10 +725,10 @@ func main() { blah.SaySomething() } ` - withOptions( + WithOptions( ProxyFiles(workspaceProxy), Modes(Experimental), - ).run(t, mod, func(t *testing.T, env *Env) { + ).Run(t, mod, func(t *testing.T, env *Env) { env.Await( env.DiagnosticAtRegexp("a/go.mod", "example.com v1.2.3"), env.DiagnosticAtRegexp("b/go.mod", "module mod.com"), @@ -726,12 +755,12 @@ func main() { blah.SaySomething() } ` - withOptions( + WithOptions( ProxyFiles(workspaceProxy), EditorConfig{ BuildFlags: []string{"-tags", "bob"}, }, - ).run(t, mod, func(t *testing.T, env *Env) { + ).Run(t, mod, func(t *testing.T, env *Env) { env.Await( env.DiagnosticAtRegexp("main.go", `"example.com/blah"`), ) @@ -749,7 +778,7 @@ package main func main() {} ` - run(t, mod, func(t *testing.T, env *Env) { + Run(t, mod, func(t *testing.T, env *Env) { env.OpenFile("go.mod") env.RegexpReplace("go.mod", "module", "modul") env.Await( @@ -782,10 +811,10 @@ func main() { println(blah.Name) } ` - withOptions( + WithOptions( Modes(Singleton), // workspace modules don't use -mod=readonly (golang/go#43346) ProxyFiles(workspaceProxy), - ).run(t, mod, func(t *testing.T, env *Env) { + ).Run(t, mod, func(t *testing.T, env *Env) { d := &protocol.PublishDiagnosticsParams{} env.OpenFile("go.mod") env.Await( @@ -820,12 +849,12 @@ package main func hello() {} ` - withOptions( + WithOptions( // TODO(rFindley) this doesn't work in multi-module workspace mode, because // it keeps around the last parsing modfile. Update this test to also // exercise the workspace module. Modes(Singleton), - ).run(t, mod, func(t *testing.T, env *Env) { + ).Run(t, mod, func(t *testing.T, env *Env) { env.OpenFile("go.mod") env.Await(env.DoneWithOpen()) env.RegexpReplace("go.mod", "module", "modul") @@ -891,9 +920,9 @@ package main func main() {} ` - withOptions( + WithOptions( ProxyFiles(proxy), - ).run(t, mod, func(t *testing.T, env *Env) { + ).Run(t, mod, func(t *testing.T, env *Env) { d := &protocol.PublishDiagnosticsParams{} env.Await( OnceMet( @@ -933,9 +962,9 @@ package main func main() {} ` - withOptions( + WithOptions( ProxyFiles(proxy), - ).run(t, mod, func(t *testing.T, env *Env) { + ).Run(t, mod, func(t *testing.T, env *Env) { d := &protocol.PublishDiagnosticsParams{} env.OpenFile("go.mod") pos := env.RegexpSearch("go.mod", "require hasdep.com v1.2.3") @@ -991,10 +1020,10 @@ func main() { blah.Hello() } ` - withOptions( + WithOptions( ProxyFiles(workspaceProxy), Modes(Singleton), - ).run(t, mod, func(t *testing.T, env *Env) { + ).Run(t, mod, func(t *testing.T, env *Env) { env.OpenFile("go.mod") pos := env.RegexpSearch("go.mod", "example.com") params := &protocol.PublishDiagnosticsParams{} diff --git a/gopls/internal/regtest/reg_test.go b/gopls/internal/regtest/regtest.go similarity index 75% rename from gopls/internal/regtest/reg_test.go rename to gopls/internal/regtest/regtest.go index 25accb1d09b..87ff3f6201a 100644 --- a/gopls/internal/regtest/reg_test.go +++ b/gopls/internal/regtest/regtest.go @@ -30,14 +30,14 @@ var ( var runner *Runner type regtestRunner interface { - run(t *testing.T, files string, f TestFunc) + Run(t *testing.T, files string, f TestFunc) } -func run(t *testing.T, files string, f TestFunc) { +func Run(t *testing.T, files string, f TestFunc) { runner.Run(t, files, f) } -func withOptions(opts ...RunOption) configuredRunner { +func WithOptions(opts ...RunOption) configuredRunner { return configuredRunner{opts: opts} } @@ -45,23 +45,35 @@ type configuredRunner struct { opts []RunOption } -func (r configuredRunner) run(t *testing.T, files string, f TestFunc) { +func (r configuredRunner) Run(t *testing.T, files string, f TestFunc) { runner.Run(t, files, f, r.opts...) } -type runMultiple []struct { - name string - runner regtestRunner +type RunMultiple []struct { + Name string + Runner regtestRunner } -func (r runMultiple) run(t *testing.T, files string, f TestFunc) { +func (r RunMultiple) Run(t *testing.T, files string, f TestFunc) { for _, runner := range r { - t.Run(runner.name, func(t *testing.T) { - runner.runner.run(t, files, f) + t.Run(runner.Name, func(t *testing.T) { + runner.Runner.Run(t, files, f) }) } } -func TestMain(m *testing.M) { + +func DefaultModes() Mode { + if *runSubprocessTests { + return NormalModes | SeparateProcess + } + return NormalModes +} + +// Main sets up and tears down the shared regtest state. +// +// TODO(rFindley): This is probably not necessary, and complicates things now +// that we have multiple regtest suites. Consider removing. +func Main(m *testing.M) { flag.Parse() if os.Getenv("_GOPLS_TEST_BINARY_RUN_AS_GOPLS") == "true" { tool.Main(context.Background(), cmd.New("gopls", "", nil, nil), os.Args[1:]) @@ -69,7 +81,7 @@ func TestMain(m *testing.M) { } runner = &Runner{ - DefaultModes: NormalModes, + DefaultModes: DefaultModes(), Timeout: *regtestTimeout, PrintGoroutinesOnFailure: *printGoroutinesOnFailure, SkipCleanup: *skipCleanup, @@ -83,7 +95,6 @@ func TestMain(m *testing.M) { panic(fmt.Sprintf("finding test binary path: %v", err)) } } - runner.DefaultModes = NormalModes | SeparateProcess runner.GoplsPath = goplsPath } dir, err := ioutil.TempDir("", "gopls-regtest-") diff --git a/gopls/internal/regtest/watch_test.go b/gopls/internal/regtest/watch/watch_test.go similarity index 93% rename from gopls/internal/regtest/watch_test.go rename to gopls/internal/regtest/watch/watch_test.go index 5b5321a7b84..436c09153a0 100644 --- a/gopls/internal/regtest/watch_test.go +++ b/gopls/internal/regtest/watch/watch_test.go @@ -7,11 +7,17 @@ package regtest import ( "testing" + . "golang.org/x/tools/gopls/internal/regtest" + "golang.org/x/tools/internal/lsp/fake" "golang.org/x/tools/internal/lsp/protocol" "golang.org/x/tools/internal/testenv" ) +func TestMain(m *testing.M) { + Main(m) +} + func TestEditFile(t *testing.T) { const pkg = ` -- go.mod -- @@ -28,7 +34,7 @@ func _() { // Edit the file when it's *not open* in the workspace, and check that // diagnostics are updated. t.Run("unopened", func(t *testing.T) { - runner.Run(t, pkg, func(t *testing.T, env *Env) { + Run(t, pkg, func(t *testing.T, env *Env) { env.Await( env.DiagnosticAtRegexp("a/a.go", "x"), ) @@ -42,7 +48,7 @@ func _() { // Edit the file when it *is open* in the workspace, and check that // diagnostics are *not* updated. t.Run("opened", func(t *testing.T) { - runner.Run(t, pkg, func(t *testing.T, env *Env) { + Run(t, pkg, func(t *testing.T, env *Env) { env.OpenFile("a/a.go") // Insert a trivial edit so that we don't automatically update the buffer // (see CL 267577). @@ -80,7 +86,7 @@ func _() { _ = b.B() } ` - runner.Run(t, pkg, func(t *testing.T, env *Env) { + Run(t, pkg, func(t *testing.T, env *Env) { env.OpenFile("a/a.go") env.Await(env.DoneWithOpen()) env.WriteWorkspaceFile("b/b.go", `package b; func B() {};`) @@ -114,7 +120,7 @@ func _() { _ = b.B() } ` - runner.Run(t, pkg, func(t *testing.T, env *Env) { + Run(t, pkg, func(t *testing.T, env *Env) { env.Await( env.DiagnosticAtRegexp("a/a.go", "x"), ) @@ -157,7 +163,7 @@ func _() { _ = b.B() } ` - runner.Run(t, pkg, func(t *testing.T, env *Env) { + Run(t, pkg, func(t *testing.T, env *Env) { env.OpenFile("a/a.go") env.Await(env.DoneWithOpen()) env.RemoveWorkspaceFile("b/b.go") @@ -189,7 +195,7 @@ func _() { c.C() } ` - runner.Run(t, missing, func(t *testing.T, env *Env) { + Run(t, missing, func(t *testing.T, env *Env) { t.Skip("the initial workspace load fails and never retries") env.Await( @@ -215,7 +221,7 @@ package a func _() {} ` - runner.Run(t, original, func(t *testing.T, env *Env) { + Run(t, original, func(t *testing.T, env *Env) { env.WriteWorkspaceFile("c/c.go", `package c; func C() {};`) env.WriteWorkspaceFile("a/a.go", `package a; import "mod.com/c"; func _() { c.C() }`) env.Await( @@ -238,7 +244,7 @@ func _() { hello() } ` - runner.Run(t, pkg, func(t *testing.T, env *Env) { + Run(t, pkg, func(t *testing.T, env *Env) { env.Await( env.DiagnosticAtRegexp("a/a.go", "hello"), ) @@ -313,7 +319,7 @@ func _() { // Add the new method before the implementation. Expect diagnostics. t.Run("method before implementation", func(t *testing.T) { - runner.Run(t, pkg, func(t *testing.T, env *Env) { + Run(t, pkg, func(t *testing.T, env *Env) { env.WriteWorkspaceFile("b/b.go", newMethod) env.Await( OnceMet( @@ -329,7 +335,7 @@ func _() { }) // Add the new implementation before the new method. Expect no diagnostics. t.Run("implementation before method", func(t *testing.T) { - runner.Run(t, pkg, func(t *testing.T, env *Env) { + Run(t, pkg, func(t *testing.T, env *Env) { env.WriteWorkspaceFile("a/a.go", implementation) env.Await( OnceMet( @@ -345,7 +351,7 @@ func _() { }) // Add both simultaneously. Expect no diagnostics. t.Run("implementation and method simultaneously", func(t *testing.T) { - runner.Run(t, pkg, func(t *testing.T, env *Env) { + Run(t, pkg, func(t *testing.T, env *Env) { env.WriteWorkspaceFiles(map[string]string{ "a/a.go": implementation, "b/b.go": newMethod, @@ -379,9 +385,9 @@ func _() { package a ` t.Run("close then delete", func(t *testing.T) { - withOptions(EditorConfig{ + WithOptions(EditorConfig{ VerboseOutput: true, - }).run(t, pkg, func(t *testing.T, env *Env) { + }).Run(t, pkg, func(t *testing.T, env *Env) { env.OpenFile("a/a.go") env.OpenFile("a/a_unneeded.go") env.Await( @@ -413,9 +419,9 @@ package a }) t.Run("delete then close", func(t *testing.T) { - withOptions( + WithOptions( EditorConfig{VerboseOutput: true}, - ).run(t, pkg, func(t *testing.T, env *Env) { + ).Run(t, pkg, func(t *testing.T, env *Env) { env.OpenFile("a/a.go") env.OpenFile("a/a_unneeded.go") env.Await( @@ -478,7 +484,7 @@ package a func _() {} ` - runner.Run(t, pkg, func(t *testing.T, env *Env) { + Run(t, pkg, func(t *testing.T, env *Env) { env.ChangeFilesOnDisk([]fake.FileEvent{ { Path: "a/a3.go", @@ -564,7 +570,7 @@ func main() { blah.X() } ` - withOptions(ProxyFiles(proxy)).run(t, mod, func(t *testing.T, env *Env) { + WithOptions(ProxyFiles(proxy)).Run(t, mod, func(t *testing.T, env *Env) { env.WriteWorkspaceFiles(map[string]string{ "go.mod": `module mod.com @@ -608,10 +614,10 @@ func main() { _ = blah.Name } ` - withOptions( + WithOptions( InGOPATH(), Modes(Experimental), // module is in a subdirectory - ).run(t, files, func(t *testing.T, env *Env) { + ).Run(t, files, func(t *testing.T, env *Env) { env.OpenFile("foo/main.go") env.Await(env.DiagnosticAtRegexp("foo/main.go", `"blah"`)) if err := env.Sandbox.RunGoCommand(env.Ctx, "foo", "mod", []string{"init", "mod.com"}); err != nil { @@ -652,9 +658,9 @@ func main() { _ = blah.Name } ` - withOptions( + WithOptions( InGOPATH(), - ).run(t, files, func(t *testing.T, env *Env) { + ).Run(t, files, func(t *testing.T, env *Env) { env.OpenFile("foo/main.go") env.RemoveWorkspaceFile("foo/go.mod") env.Await( @@ -689,7 +695,7 @@ func TestBob(t *testing.T) { bob() } ` - run(t, files, func(t *testing.T, env *Env) { + Run(t, files, func(t *testing.T, env *Env) { // Add a new symbol to the package under test and use it in the test // variant. Expect no diagnostics. env.WriteWorkspaceFiles(map[string]string{ diff --git a/gopls/internal/regtest/workspace_test.go b/gopls/internal/regtest/workspace/workspace_test.go similarity index 94% rename from gopls/internal/regtest/workspace_test.go rename to gopls/internal/regtest/workspace/workspace_test.go index ae89b8db96c..534174e5855 100644 --- a/gopls/internal/regtest/workspace_test.go +++ b/gopls/internal/regtest/workspace/workspace_test.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package regtest +package workspace import ( "fmt" @@ -12,11 +12,17 @@ import ( "strings" "testing" + . "golang.org/x/tools/gopls/internal/regtest" + "golang.org/x/tools/internal/lsp/fake" "golang.org/x/tools/internal/lsp/protocol" "golang.org/x/tools/internal/testenv" ) +func TestMain(m *testing.M) { + Main(m) +} + const workspaceProxy = ` -- example.com@v1.2.3/go.mod -- module example.com @@ -116,7 +122,7 @@ func TestReferences(t *testing.T) { if tt.rootPath != "" { opts = append(opts, WorkspaceFolders(tt.rootPath)) } - withOptions(opts...).run(t, workspaceModule, func(t *testing.T, env *Env) { + WithOptions(opts...).Run(t, workspaceModule, func(t *testing.T, env *Env) { f := "pkg/inner/inner.go" env.OpenFile(f) locations := env.References(f, env.RegexpSearch(f, `SaySomething`)) @@ -134,10 +140,10 @@ func TestReferences(t *testing.T) { // VS Code, where clicking on a reference result triggers a // textDocument/didOpen without a corresponding textDocument/didClose. func TestClearAnalysisDiagnostics(t *testing.T) { - withOptions( + WithOptions( ProxyFiles(workspaceProxy), WorkspaceFolders("pkg/inner"), - ).run(t, workspaceModule, func(t *testing.T, env *Env) { + ).Run(t, workspaceModule, func(t *testing.T, env *Env) { env.OpenFile("pkg/main.go") env.Await( env.DiagnosticAtRegexp("pkg/main2.go", "fmt.Print"), @@ -152,10 +158,10 @@ func TestClearAnalysisDiagnostics(t *testing.T) { // This test checks that gopls updates the set of files it watches when a // replace target is added to the go.mod. func TestWatchReplaceTargets(t *testing.T) { - withOptions( + WithOptions( ProxyFiles(workspaceProxy), WorkspaceFolders("pkg"), - ).run(t, workspaceModule, func(t *testing.T, env *Env) { + ).Run(t, workspaceModule, func(t *testing.T, env *Env) { // Add a replace directive and expect the files that gopls is watching // to change. dir := env.Sandbox.Workdir.URI("goodbye").SpanURI().Filename() @@ -220,10 +226,10 @@ func Hello() int { var x int } ` - withOptions( + WithOptions( ProxyFiles(workspaceModuleProxy), Modes(Experimental), - ).run(t, multiModule, func(t *testing.T, env *Env) { + ).Run(t, multiModule, func(t *testing.T, env *Env) { env.Await( env.DiagnosticAtRegexp("moda/a/a.go", "x"), env.DiagnosticAtRegexp("modb/b/b.go", "x"), @@ -262,10 +268,10 @@ func Hello() int { var x int } ` - withOptions( + WithOptions( ProxyFiles(workspaceModuleProxy), Modes(Experimental), - ).run(t, multiModule, func(t *testing.T, env *Env) { + ).Run(t, multiModule, func(t *testing.T, env *Env) { env.OpenFile("moda/a/a.go") original, _ := env.GoToDefinition("moda/a/a.go", env.RegexpSearch("moda/a/a.go", "Hello")) @@ -318,10 +324,10 @@ func main() { _ = b.Hello() } ` - withOptions( + WithOptions( Modes(Experimental), ProxyFiles(workspaceModuleProxy), - ).run(t, multiModule, func(t *testing.T, env *Env) { + ).Run(t, multiModule, func(t *testing.T, env *Env) { env.OpenFile("moda/a/a.go") original, _ := env.GoToDefinition("moda/a/a.go", env.RegexpSearch("moda/a/a.go", "Hello")) if want := "b.com@v1.2.3/b/b.go"; !strings.HasSuffix(original, want) { @@ -380,10 +386,10 @@ func Hello() int { var x int } ` - withOptions( + WithOptions( ProxyFiles(workspaceModuleProxy), Modes(Experimental), - ).run(t, multiModule, func(t *testing.T, env *Env) { + ).Run(t, multiModule, func(t *testing.T, env *Env) { env.OpenFile("modb/go.mod") env.Await( OnceMet( @@ -440,10 +446,10 @@ require ( replace a.com => $SANDBOX_WORKDIR/moda/a ` - withOptions( + WithOptions( ProxyFiles(workspaceModuleProxy), Modes(Experimental), - ).run(t, multiModule, func(t *testing.T, env *Env) { + ).Run(t, multiModule, func(t *testing.T, env *Env) { // Initially, the gopls.mod should cause only the a.com module to be // loaded. Validate this by jumping to a definition in b.com and ensuring // that we go to the module cache. @@ -546,7 +552,7 @@ package foo import "fmt" var _ = fmt.Printf ` - run(t, files, func(t *testing.T, env *Env) { + Run(t, files, func(t *testing.T, env *Env) { env.CreateBuffer("/tmp/foo.go", "") env.EditBuffer("/tmp/foo.go", fake.NewEdit(0, 0, 0, 0, code)) env.GoToDefinition("/tmp/foo.go", env.RegexpSearch("/tmp/foo.go", `Printf`)) @@ -597,9 +603,9 @@ func main() { var x int } ` - withOptions( + WithOptions( Modes(Experimental), - ).run(t, multiModule, func(t *testing.T, env *Env) { + ).Run(t, multiModule, func(t *testing.T, env *Env) { env.Await( env.DiagnosticAtRegexp("moda/a/a.go", "x"), env.DiagnosticAtRegexp("modb/b/b.go", "x"), @@ -629,10 +635,10 @@ func main() { fmt.Println("World") } ` - withOptions( + WithOptions( Modes(Experimental), SendPID(), - ).run(t, multiModule, func(t *testing.T, env *Env) { + ).Run(t, multiModule, func(t *testing.T, env *Env) { pid := os.Getpid() // Don't factor this out of Server.addFolders. vscode-go expects this // directory. @@ -686,7 +692,7 @@ const _ = Nonexistant cfg := EditorConfig{ DirectoryFilters: []string{"-exclude"}, } - withOptions(cfg).run(t, files, func(t *testing.T, env *Env) { + WithOptions(cfg).Run(t, files, func(t *testing.T, env *Env) { env.Await(NoDiagnostics("exclude/x.go")) }) } @@ -714,7 +720,7 @@ const X = 1 cfg := EditorConfig{ DirectoryFilters: []string{"-exclude"}, } - withOptions(cfg).run(t, files, func(t *testing.T, env *Env) { + WithOptions(cfg).Run(t, files, func(t *testing.T, env *Env) { env.Await( NoDiagnostics("exclude/exclude.go"), // filtered out NoDiagnostics("include/include.go"), // successfully builds @@ -764,7 +770,7 @@ package exclude cfg := EditorConfig{ DirectoryFilters: []string{"-exclude"}, } - withOptions(cfg, Modes(Experimental), ProxyFiles(proxy)).run(t, files, func(t *testing.T, env *Env) { + WithOptions(cfg, Modes(Experimental), ProxyFiles(proxy)).Run(t, files, func(t *testing.T, env *Env) { env.Await(env.DiagnosticAtRegexp("include/include.go", `exclude.(X)`)) }) } diff --git a/gopls/internal/regtest/wrappers.go b/gopls/internal/regtest/wrappers.go index cdc30900d15..bb614a5ed5d 100644 --- a/gopls/internal/regtest/wrappers.go +++ b/gopls/internal/regtest/wrappers.go @@ -361,7 +361,7 @@ func (e *Env) CodeAction(path string) []protocol.CodeAction { return actions } -func (e *Env) changeConfiguration(t *testing.T, config *fake.EditorConfig) { +func (e *Env) ChangeConfiguration(t *testing.T, config *fake.EditorConfig) { e.Editor.Config = *config if err := e.Editor.Server.DidChangeConfiguration(e.Ctx, &protocol.DidChangeConfigurationParams{ // gopls currently ignores the Settings field