diff options
Diffstat (limited to 'gopls/internal/regtest/modfile/modfile_test.go')
-rw-r--r-- | gopls/internal/regtest/modfile/modfile_test.go | 349 |
1 files changed, 171 insertions, 178 deletions
diff --git a/gopls/internal/regtest/modfile/modfile_test.go b/gopls/internal/regtest/modfile/modfile_test.go index 868aa70aa..483118dd3 100644 --- a/gopls/internal/regtest/modfile/modfile_test.go +++ b/gopls/internal/regtest/modfile/modfile_test.go @@ -11,14 +11,16 @@ import ( "testing" "golang.org/x/tools/gopls/internal/hooks" - . "golang.org/x/tools/internal/lsp/regtest" + . "golang.org/x/tools/gopls/internal/lsp/regtest" + "golang.org/x/tools/gopls/internal/lsp/tests/compare" + "golang.org/x/tools/internal/bug" - "golang.org/x/tools/internal/lsp/protocol" - "golang.org/x/tools/internal/lsp/tests" + "golang.org/x/tools/gopls/internal/lsp/protocol" "golang.org/x/tools/internal/testenv" ) func TestMain(m *testing.M) { + bug.PanicOnBugs = true Main(m, hooks.Options) } @@ -65,8 +67,6 @@ const Name = "Hello" ` func TestModFileModification(t *testing.T) { - testenv.NeedsGo1Point(t, 14) - const untidyModule = ` -- a/go.mod -- module mod.com @@ -92,54 +92,59 @@ func main() { // modify the go.mod file. goModContent := env.ReadWorkspaceFile("a/go.mod") env.OpenFile("a/main.go") - env.Await( - env.DiagnosticAtRegexp("a/main.go", "\"example.com/blah\""), + env.AfterChange( + Diagnostics(env.AtRegexp("a/main.go", "\"example.com/blah\"")), ) if got := env.ReadWorkspaceFile("a/go.mod"); got != goModContent { - t.Fatalf("go.mod changed on disk:\n%s", tests.Diff(t, goModContent, got)) + t.Fatalf("go.mod changed on disk:\n%s", compare.Text(goModContent, got)) } // Save the buffer, which will format and organize imports. // Confirm that the go.mod file still does not change. env.SaveBuffer("a/main.go") - env.Await( - env.DiagnosticAtRegexp("a/main.go", "\"example.com/blah\""), + env.AfterChange( + Diagnostics(env.AtRegexp("a/main.go", "\"example.com/blah\"")), ) if got := env.ReadWorkspaceFile("a/go.mod"); got != goModContent { - t.Fatalf("go.mod changed on disk:\n%s", tests.Diff(t, goModContent, got)) + t.Fatalf("go.mod changed on disk:\n%s", compare.Text(goModContent, got)) } }) }) // Reproduce golang/go#40269 by deleting and recreating main.go. 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) { goModContent := env.ReadWorkspaceFile("a/go.mod") mainContent := env.ReadWorkspaceFile("a/main.go") env.OpenFile("a/main.go") env.SaveBuffer("a/main.go") + // Ensure that we're done processing all the changes caused by opening + // and saving above. If not, we may run into a file locking issue on + // windows. + // + // If this proves insufficient, env.RemoveWorkspaceFile can be updated to + // retry file lock errors on windows. + env.AfterChange() env.RemoveWorkspaceFile("a/main.go") - env.Await( - env.DoneWithOpen(), - env.DoneWithSave(), - env.DoneWithChangeWatchedFiles(), - ) - env.WriteWorkspaceFile("main.go", mainContent) - env.Await( - env.DiagnosticAtRegexp("main.go", "\"example.com/blah\""), + // TODO(rfindley): awaiting here shouldn't really be necessary. We should + // be consistent eventually. + // + // Probably this was meant to exercise a race with the change below. + env.AfterChange() + + env.WriteWorkspaceFile("a/main.go", mainContent) + env.AfterChange( + Diagnostics(env.AtRegexp("a/main.go", "\"example.com/blah\"")), ) - if got := env.ReadWorkspaceFile("go.mod"); got != goModContent { - t.Fatalf("go.mod changed on disk:\n%s", tests.Diff(t, goModContent, got)) + if got := env.ReadWorkspaceFile("a/go.mod"); got != goModContent { + t.Fatalf("go.mod changed on disk:\n%s", compare.Text(goModContent, got)) } }) }) } func TestGoGetFix(t *testing.T) { - testenv.NeedsGo1Point(t, 14) const mod = ` -- a/go.mod -- module mod.com @@ -170,11 +175,9 @@ require example.com v1.2.3 } env.OpenFile("a/main.go") var d protocol.PublishDiagnosticsParams - env.Await( - OnceMet( - env.DiagnosticAtRegexp("a/main.go", `"example.com/blah"`), - ReadDiagnostics("a/main.go", &d), - ), + env.AfterChange( + Diagnostics(env.AtRegexp("a/main.go", `"example.com/blah"`)), + ReadDiagnostics("a/main.go", &d), ) var goGetDiag protocol.Diagnostic for _, diag := range d.Diagnostics { @@ -184,14 +187,13 @@ require example.com v1.2.3 } env.ApplyQuickFixes("a/main.go", []protocol.Diagnostic{goGetDiag}) if got := env.ReadWorkspaceFile("a/go.mod"); got != want { - t.Fatalf("unexpected go.mod content:\n%s", tests.Diff(t, want, got)) + t.Fatalf("unexpected go.mod content:\n%s", compare.Text(want, got)) } }) } // Tests that multiple missing dependencies gives good single fixes. func TestMissingDependencyFixes(t *testing.T) { - testenv.NeedsGo1Point(t, 14) const mod = ` -- a/go.mod -- module mod.com @@ -220,11 +222,9 @@ require random.org v1.2.3 }.Run(t, mod, func(t *testing.T, env *Env) { env.OpenFile("a/main.go") var d protocol.PublishDiagnosticsParams - env.Await( - OnceMet( - env.DiagnosticAtRegexp("a/main.go", `"random.org/blah"`), - ReadDiagnostics("a/main.go", &d), - ), + env.AfterChange( + Diagnostics(env.AtRegexp("a/main.go", `"random.org/blah"`)), + ReadDiagnostics("a/main.go", &d), ) var randomDiag protocol.Diagnostic for _, diag := range d.Diagnostics { @@ -234,7 +234,7 @@ require random.org v1.2.3 } env.ApplyQuickFixes("a/main.go", []protocol.Diagnostic{randomDiag}) if got := env.ReadWorkspaceFile("a/go.mod"); got != want { - t.Fatalf("unexpected go.mod content:\n%s", tests.Diff(t, want, got)) + t.Fatalf("unexpected go.mod content:\n%s", compare.Text(want, got)) } }) } @@ -276,11 +276,9 @@ require random.org v1.2.3 }.Run(t, mod, func(t *testing.T, env *Env) { env.OpenFile("a/main.go") var d protocol.PublishDiagnosticsParams - env.Await( - OnceMet( - env.DiagnosticAtRegexp("a/main.go", `"random.org/blah"`), - ReadDiagnostics("a/main.go", &d), - ), + env.AfterChange( + Diagnostics(env.AtRegexp("a/main.go", `"random.org/blah"`)), + ReadDiagnostics("a/main.go", &d), ) var randomDiag protocol.Diagnostic for _, diag := range d.Diagnostics { @@ -290,14 +288,12 @@ require random.org v1.2.3 } env.ApplyQuickFixes("a/main.go", []protocol.Diagnostic{randomDiag}) if got := env.ReadWorkspaceFile("a/go.mod"); got != want { - t.Fatalf("unexpected go.mod content:\n%s", tests.Diff(t, want, got)) + t.Fatalf("unexpected go.mod content:\n%s", compare.Text(want, got)) } }) } func TestIndirectDependencyFix(t *testing.T) { - testenv.NeedsGo1Point(t, 14) - const mod = ` -- a/go.mod -- module mod.com @@ -329,21 +325,18 @@ require example.com v1.2.3 }.Run(t, mod, func(t *testing.T, env *Env) { env.OpenFile("a/go.mod") var d protocol.PublishDiagnosticsParams - env.Await( - OnceMet( - env.DiagnosticAtRegexp("a/go.mod", "// indirect"), - ReadDiagnostics("a/go.mod", &d), - ), + env.AfterChange( + Diagnostics(env.AtRegexp("a/go.mod", "// indirect")), + ReadDiagnostics("a/go.mod", &d), ) env.ApplyQuickFixes("a/go.mod", d.Diagnostics) - if got := env.Editor.BufferText("a/go.mod"); got != want { - t.Fatalf("unexpected go.mod content:\n%s", tests.Diff(t, want, got)) + if got := env.BufferText("a/go.mod"); got != want { + t.Fatalf("unexpected go.mod content:\n%s", compare.Text(want, got)) } }) } func TestUnusedDiag(t *testing.T) { - testenv.NeedsGo1Point(t, 14) const proxy = ` -- example.com@v1.0.0/x.go -- @@ -374,15 +367,13 @@ go 1.14 }.Run(t, files, func(t *testing.T, env *Env) { env.OpenFile("a/go.mod") var d protocol.PublishDiagnosticsParams - env.Await( - OnceMet( - env.DiagnosticAtRegexp("a/go.mod", `require example.com`), - ReadDiagnostics("a/go.mod", &d), - ), + env.AfterChange( + Diagnostics(env.AtRegexp("a/go.mod", `require example.com`)), + ReadDiagnostics("a/go.mod", &d), ) env.ApplyQuickFixes("a/go.mod", d.Diagnostics) - if got := env.Editor.BufferText("a/go.mod"); got != want { - t.Fatalf("unexpected go.mod content:\n%s", tests.Diff(t, want, got)) + if got := env.BufferText("a/go.mod"); got != want { + t.Fatalf("unexpected go.mod content:\n%s", compare.Text(want, got)) } }) } @@ -390,7 +381,6 @@ go 1.14 // Test to reproduce golang/go#39041. It adds a new require to a go.mod file // that already has an unused require. func TestNewDepWithUnusedDep(t *testing.T) { - testenv.NeedsGo1Point(t, 14) const proxy = ` -- github.com/esimov/caire@v1.2.5/go.mod -- @@ -437,11 +427,9 @@ func _() { }.Run(t, repro, func(t *testing.T, env *Env) { env.OpenFile("a/main.go") var d protocol.PublishDiagnosticsParams - env.Await( - OnceMet( - env.DiagnosticAtRegexp("a/main.go", `"github.com/esimov/caire"`), - ReadDiagnostics("a/main.go", &d), - ), + env.AfterChange( + Diagnostics(env.AtRegexp("a/main.go", `"github.com/esimov/caire"`)), + ReadDiagnostics("a/main.go", &d), ) env.ApplyQuickFixes("a/main.go", d.Diagnostics) want := `module mod.com @@ -454,7 +442,7 @@ require ( ) ` if got := env.ReadWorkspaceFile("a/go.mod"); got != want { - t.Fatalf("TestNewDepWithUnusedDep failed:\n%s", tests.Diff(t, want, got)) + t.Fatalf("TestNewDepWithUnusedDep failed:\n%s", compare.Text(want, got)) } }) } @@ -463,8 +451,6 @@ require ( // the file watching GlobPattern in the capability registration. See // golang/go#39384. func TestModuleChangesOnDisk(t *testing.T) { - testenv.NeedsGo1Point(t, 14) - const mod = ` -- a/go.mod -- module mod.com @@ -485,10 +471,13 @@ func main() { {"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.OnceMet( + InitialWorkspaceLoad, + Diagnostics(env.AtRegexp("a/go.mod", "require")), + ) env.RunGoCommandInDir("a", "mod", "tidy") - env.Await( - EmptyDiagnostics("a/go.mod"), + env.AfterChange( + NoDiagnostics(ForFile("a/go.mod")), ) }) } @@ -496,8 +485,6 @@ func main() { // Tests golang/go#39784: a missing indirect dependency, necessary // due to blah@v2.0.0's incomplete go.mod file. func TestBadlyVersionedModule(t *testing.T) { - testenv.NeedsGo1Point(t, 14) - const proxy = ` -- example.com/blah/@v/v1.0.0.mod -- module example.com @@ -544,13 +531,15 @@ var _ = blah.Name }.Run(t, files, func(t *testing.T, env *Env) { env.OpenFile("a/main.go") env.OpenFile("a/go.mod") - env.Await( + var modDiags protocol.PublishDiagnosticsParams + env.AfterChange( // We would like for the error to appear in the v2 module, but // as of writing non-workspace packages are not diagnosed. - env.DiagnosticAtRegexpWithMessage("a/main.go", `"example.com/blah/v2"`, "cannot find module providing"), - env.DiagnosticAtRegexpWithMessage("a/go.mod", `require example.com/blah/v2`, "cannot find module providing"), + Diagnostics(env.AtRegexp("a/main.go", `"example.com/blah/v2"`), WithMessage("cannot find module providing")), + Diagnostics(env.AtRegexp("a/go.mod", `require example.com/blah/v2`), WithMessage("cannot find module providing")), + ReadDiagnostics("a/go.mod", &modDiags), ) - env.ApplyQuickFixes("a/go.mod", env.DiagnosticsFor("a/go.mod").Diagnostics) + env.ApplyQuickFixes("a/go.mod", modDiags.Diagnostics) const want = `module mod.com go 1.12 @@ -561,9 +550,9 @@ require ( ) ` env.SaveBuffer("a/go.mod") - env.Await(EmptyDiagnostics("a/main.go")) - if got := env.Editor.BufferText("a/go.mod"); got != want { - t.Fatalf("suggested fixes failed:\n%s", tests.Diff(t, want, got)) + env.AfterChange(NoDiagnostics(ForFile("a/main.go"))) + if got := env.BufferText("a/go.mod"); got != want { + t.Fatalf("suggested fixes failed:\n%s", compare.Text(want, got)) } }) } @@ -573,9 +562,6 @@ func TestUnknownRevision(t *testing.T) { if runtime.GOOS == "plan9" { t.Skipf("skipping test that fails for unknown reasons on plan9; see https://go.dev/issue/50477") } - - testenv.NeedsGo1Point(t, 14) - const unknown = ` -- a/go.mod -- module mod.com @@ -601,19 +587,17 @@ func main() { t.Run("bad", func(t *testing.T) { 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"), + env.AfterChange( + Diagnostics(env.AtRegexp("a/go.mod", "example.com v1.2.2")), ) env.RegexpReplace("a/go.mod", "v1.2.2", "v1.2.3") env.SaveBuffer("a/go.mod") // Save to trigger diagnostics. d := protocol.PublishDiagnosticsParams{} - env.Await( - OnceMet( - // Make sure the diagnostic mentions the new version -- the old diagnostic is in the same place. - env.DiagnosticAtRegexpWithMessage("a/go.mod", "example.com v1.2.3", "example.com@v1.2.3"), - ReadDiagnostics("a/go.mod", &d), - ), + env.AfterChange( + // Make sure the diagnostic mentions the new version -- the old diagnostic is in the same place. + Diagnostics(env.AtRegexp("a/go.mod", "example.com v1.2.3"), WithMessage("example.com@v1.2.3")), + ReadDiagnostics("a/go.mod", &d), ) qfs := env.GetQuickFixes("a/go.mod", d.Diagnostics) if len(qfs) == 0 { @@ -621,9 +605,9 @@ func main() { } env.ApplyCodeAction(qfs[0]) // Arbitrarily pick a single fix to apply. Applying all of them seems to cause trouble in this particular test. env.SaveBuffer("a/go.mod") // Save to trigger diagnostics. - env.Await( - EmptyDiagnostics("a/go.mod"), - env.DiagnosticAtRegexp("a/main.go", "x = "), + env.AfterChange( + NoDiagnostics(ForFile("a/go.mod")), + Diagnostics(env.AtRegexp("a/main.go", "x = ")), ) }) }) @@ -652,18 +636,18 @@ func main() { t.Run("good", func(t *testing.T) { runner.Run(t, known, func(t *testing.T, env *Env) { env.OpenFile("a/go.mod") - env.Await( - env.DiagnosticAtRegexp("a/main.go", "x = "), + env.AfterChange( + Diagnostics(env.AtRegexp("a/main.go", "x = ")), ) env.RegexpReplace("a/go.mod", "v1.2.3", "v1.2.2") env.Editor.SaveBuffer(env.Ctx, "a/go.mod") // go.mod changes must be on disk - env.Await( - env.DiagnosticAtRegexp("a/go.mod", "example.com v1.2.2"), + env.AfterChange( + Diagnostics(env.AtRegexp("a/go.mod", "example.com v1.2.2")), ) env.RegexpReplace("a/go.mod", "v1.2.2", "v1.2.3") env.Editor.SaveBuffer(env.Ctx, "a/go.mod") // go.mod changes must be on disk - env.Await( - env.DiagnosticAtRegexp("a/main.go", "x = "), + env.AfterChange( + Diagnostics(env.AtRegexp("a/main.go", "x = ")), ) }) }) @@ -672,8 +656,6 @@ func main() { // Confirm that an error in an indirect dependency of a requirement is surfaced // as a diagnostic in the go.mod file. func TestErrorInIndirectDependency(t *testing.T) { - testenv.NeedsGo1Point(t, 14) - const badProxy = ` -- example.com@v1.2.3/go.mod -- module example.com @@ -715,8 +697,8 @@ func main() { {"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"), + env.AfterChange( + Diagnostics(env.AtRegexp("a/go.mod", "require example.com v1.2.3")), ) }) } @@ -738,35 +720,37 @@ func main() { } ` WithOptions( - EditorConfig{ - Env: map[string]string{ - "GOFLAGS": "-mod=readonly", - }, - }, + EnvVars{"GOFLAGS": "-mod=readonly"}, ProxyFiles(proxy), - Modes(Singleton), + Modes(Default), ).Run(t, mod, func(t *testing.T, env *Env) { env.OpenFile("main.go") original := env.ReadWorkspaceFile("go.mod") - env.Await( - env.DiagnosticAtRegexp("main.go", `"example.com/blah"`), + env.AfterChange( + Diagnostics(env.AtRegexp("main.go", `"example.com/blah"`)), ) got := env.ReadWorkspaceFile("go.mod") if got != original { - t.Fatalf("go.mod file modified:\n%s", tests.Diff(t, original, got)) + t.Fatalf("go.mod file modified:\n%s", compare.Text(original, got)) } env.RunGoCommand("get", "example.com/blah@v1.2.3") env.RunGoCommand("mod", "tidy") - env.Await( - EmptyDiagnostics("main.go"), + env.AfterChange( + NoDiagnostics(ForFile("main.go")), ) }) } func TestMultiModuleModDiagnostics(t *testing.T) { - testenv.NeedsGo1Point(t, 14) - + testenv.NeedsGo1Point(t, 18) // uses go.work const mod = ` +-- go.work -- +go 1.18 + +use ( + a + b +) -- a/go.mod -- module moda.com @@ -799,17 +783,17 @@ func main() { ` WithOptions( ProxyFiles(workspaceProxy), - Modes(Experimental), ).Run(t, mod, func(t *testing.T, env *Env) { - env.Await( - env.DiagnosticAtRegexpWithMessage("a/go.mod", "example.com v1.2.3", "is not used"), + env.AfterChange( + Diagnostics( + env.AtRegexp("a/go.mod", "example.com v1.2.3"), + WithMessage("is not used"), + ), ) }) } func TestModTidyWithBuildTags(t *testing.T) { - testenv.NeedsGo1Point(t, 14) - const mod = ` -- go.mod -- module mod.com @@ -828,12 +812,11 @@ func main() { ` WithOptions( ProxyFiles(workspaceProxy), - EditorConfig{ - BuildFlags: []string{"-tags", "bob"}, - }, + Settings{"buildFlags": []string{"-tags", "bob"}}, ).Run(t, mod, func(t *testing.T, env *Env) { - env.Await( - env.DiagnosticAtRegexp("main.go", `"example.com/blah"`), + env.OnceMet( + InitialWorkspaceLoad, + Diagnostics(env.AtRegexp("main.go", `"example.com/blah"`)), ) }) } @@ -852,15 +835,13 @@ func main() {} Run(t, mod, func(t *testing.T, env *Env) { env.OpenFile("go.mod") env.RegexpReplace("go.mod", "module", "modul") - env.Await( - env.DiagnosticAtRegexp("go.mod", "modul"), + env.AfterChange( + Diagnostics(env.AtRegexp("go.mod", "modul")), ) }) } func TestSumUpdateFixesDiagnostics(t *testing.T) { - testenv.NeedsGo1Point(t, 14) - const mod = ` -- go.mod -- module mod.com @@ -887,16 +868,17 @@ func main() { ).Run(t, mod, func(t *testing.T, env *Env) { d := &protocol.PublishDiagnosticsParams{} env.OpenFile("go.mod") - env.Await( - OnceMet( - env.GoSumDiagnostic("go.mod", `example.com v1.2.3`), - ReadDiagnostics("go.mod", d), + env.AfterChange( + Diagnostics( + env.AtRegexp("go.mod", `example.com v1.2.3`), + WithMessage("go.sum is out of sync"), ), + ReadDiagnostics("go.mod", d), ) env.ApplyQuickFixes("go.mod", d.Diagnostics) env.SaveBuffer("go.mod") // Save to trigger diagnostics. - env.Await( - EmptyDiagnostics("go.mod"), + env.AfterChange( + NoDiagnostics(ForFile("go.mod")), ) }) } @@ -924,20 +906,20 @@ func hello() {} // 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), + Modes(Default), ).Run(t, mod, func(t *testing.T, env *Env) { env.OpenFile("go.mod") env.Await(env.DoneWithOpen()) env.RegexpReplace("go.mod", "module", "modul") // Confirm that we still have metadata with only on-disk edits. env.OpenFile("main.go") - file, _ := env.GoToDefinition("main.go", env.RegexpSearch("main.go", "hello")) - if filepath.Base(file) != "hello.go" { - t.Fatalf("expected definition in hello.go, got %s", file) + loc := env.GoToDefinition(env.RegexpSearch("main.go", "hello")) + if filepath.Base(string(loc.URI)) != "hello.go" { + t.Fatalf("expected definition in hello.go, got %s", loc.URI) } // Confirm that we no longer have metadata when the file is saved. env.SaveBufferWithoutActions("go.mod") - _, _, err := env.Editor.GoToDefinition(env.Ctx, "main.go", env.RegexpSearch("main.go", "hello")) + _, err := env.Editor.GoToDefinition(env.Ctx, env.RegexpSearch("main.go", "hello")) if err == nil { t.Fatalf("expected error, got none") } @@ -945,8 +927,6 @@ func hello() {} } func TestRemoveUnusedDependency(t *testing.T) { - testenv.NeedsGo1Point(t, 14) - const proxy = ` -- hasdep.com@v1.2.3/go.mod -- module hasdep.com @@ -996,19 +976,17 @@ func main() {} ).Run(t, mod, func(t *testing.T, env *Env) { env.OpenFile("go.mod") d := &protocol.PublishDiagnosticsParams{} - env.Await( - OnceMet( - env.DiagnosticAtRegexp("go.mod", "require hasdep.com v1.2.3"), - ReadDiagnostics("go.mod", d), - ), + env.AfterChange( + Diagnostics(env.AtRegexp("go.mod", "require hasdep.com v1.2.3")), + ReadDiagnostics("go.mod", d), ) const want = `module mod.com go 1.12 ` env.ApplyQuickFixes("go.mod", d.Diagnostics) - if got := env.Editor.BufferText("go.mod"); got != want { - t.Fatalf("unexpected content in go.mod:\n%s", tests.Diff(t, want, got)) + if got := env.BufferText("go.mod"); got != want { + t.Fatalf("unexpected content in go.mod:\n%s", compare.Text(want, got)) } }) }) @@ -1039,12 +1017,10 @@ func main() {} ).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") - env.Await( - OnceMet( - DiagnosticAt("go.mod", pos.Line, pos.Column), - ReadDiagnostics("go.mod", d), - ), + pos := env.RegexpSearch("go.mod", "require hasdep.com v1.2.3").Range.Start + env.AfterChange( + Diagnostics(AtPosition("go.mod", pos.Line, pos.Character)), + ReadDiagnostics("go.mod", d), ) const want = `module mod.com @@ -1060,15 +1036,14 @@ require random.com v1.2.3 diagnostics = append(diagnostics, d) } env.ApplyQuickFixes("go.mod", diagnostics) - if got := env.Editor.BufferText("go.mod"); got != want { - t.Fatalf("unexpected content in go.mod:\n%s", tests.Diff(t, want, got)) + if got := env.BufferText("go.mod"); got != want { + t.Fatalf("unexpected content in go.mod:\n%s", compare.Text(want, got)) } }) }) } func TestSumUpdateQuickFix(t *testing.T) { - testenv.NeedsGo1Point(t, 14) const mod = ` -- go.mod -- module mod.com @@ -1092,29 +1067,28 @@ func main() { ` WithOptions( ProxyFiles(workspaceProxy), - Modes(Singleton), + Modes(Default), ).Run(t, mod, func(t *testing.T, env *Env) { env.OpenFile("go.mod") params := &protocol.PublishDiagnosticsParams{} - env.Await( - OnceMet( - env.GoSumDiagnostic("go.mod", "example.com"), - ReadDiagnostics("go.mod", params), + env.AfterChange( + Diagnostics( + env.AtRegexp("go.mod", `example.com`), + WithMessage("go.sum is out of sync"), ), + ReadDiagnostics("go.mod", params), ) env.ApplyQuickFixes("go.mod", params.Diagnostics) const want = `example.com v1.2.3 h1:Yryq11hF02fEf2JlOS2eph+ICE2/ceevGV3C9dl5V/c= example.com v1.2.3/go.mod h1:Y2Rc5rVWjWur0h3pd9aEvK5Pof8YKDANh9gHA2Maujo= ` if got := env.ReadWorkspaceFile("go.sum"); got != want { - t.Fatalf("unexpected go.sum contents:\n%s", tests.Diff(t, want, got)) + t.Fatalf("unexpected go.sum contents:\n%s", compare.Text(want, got)) } }) } func TestDownloadDeps(t *testing.T) { - testenv.NeedsGo1Point(t, 14) - const proxy = ` -- example.com@v1.2.3/go.mod -- module example.com @@ -1161,24 +1135,26 @@ func main() { ` WithOptions( ProxyFiles(proxy), - Modes(Singleton), + Modes(Default), ).Run(t, mod, func(t *testing.T, env *Env) { env.OpenFile("main.go") d := &protocol.PublishDiagnosticsParams{} - env.Await( - env.DiagnosticAtRegexpWithMessage("main.go", `"example.com/blah"`, `could not import example.com/blah (no required module provides package "example.com/blah")`), + env.AfterChange( + Diagnostics( + env.AtRegexp("main.go", `"example.com/blah"`), + WithMessage(`could not import example.com/blah (no required module provides package "example.com/blah")`), + ), ReadDiagnostics("main.go", d), ) env.ApplyQuickFixes("main.go", d.Diagnostics) - env.Await( - EmptyDiagnostics("main.go"), - NoDiagnostics("go.mod"), + env.AfterChange( + NoDiagnostics(ForFile("main.go")), + NoDiagnostics(ForFile("go.mod")), ) }) } func TestInvalidGoVersion(t *testing.T) { - testenv.NeedsGo1Point(t, 14) // Times out on 1.13 for reasons unclear. Not worth worrying about. const files = ` -- go.mod -- module mod.com @@ -1188,8 +1164,25 @@ go foo package main ` Run(t, files, func(t *testing.T, env *Env) { - env.Await(env.DiagnosticAtRegexpWithMessage("go.mod", `go foo`, "invalid go version")) + env.OnceMet( + InitialWorkspaceLoad, + Diagnostics(env.AtRegexp("go.mod", `go foo`), WithMessage("invalid go version")), + ) env.WriteWorkspaceFile("go.mod", "module mod.com \n\ngo 1.12\n") - env.Await(EmptyDiagnostics("go.mod")) + env.AfterChange(NoDiagnostics(ForFile("go.mod"))) + }) +} + +// This is a regression test for a bug in the line-oriented implementation +// of the "apply diffs" operation used by the fake editor. +func TestIssue57627(t *testing.T) { + const files = ` +-- go.work -- +package main +` + Run(t, files, func(t *testing.T, env *Env) { + env.OpenFile("go.work") + env.SetBufferContent("go.work", "go 1.18\nuse moda/a") + env.SaveBuffer("go.work") // doesn't fail }) } |