internal/lsp: add a test that reproduces golang/go#37069

Also, add a directory parameter to RunGoCommand. To make sure that the
parameters aren't misused, change args to a []string.

Updates golang/go#40340

Change-Id: Ib5ce606a401a18c29c904b570ec9339f067a3961
Reviewed-on: https://go-review.googlesource.com/c/tools/+/245818
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
diff --git a/internal/lsp/fake/sandbox.go b/internal/lsp/fake/sandbox.go
index 0f6213c..e443fc3 100644
--- a/internal/lsp/fake/sandbox.go
+++ b/internal/lsp/fake/sandbox.go
@@ -179,7 +179,7 @@
 }
 
 // RunGoCommand executes a go command in the sandbox.
-func (sb *Sandbox) RunGoCommand(ctx context.Context, verb string, args ...string) error {
+func (sb *Sandbox) RunGoCommand(ctx context.Context, dir, verb string, args []string) error {
 	var vars []string
 	for k, v := range sb.GoEnv() {
 		vars = append(vars, fmt.Sprintf("%s=%s", k, v))
@@ -189,10 +189,13 @@
 		Args: args,
 		Env:  vars,
 	}
+	// Use the provided directory for the working directory, if available.
 	// sb.Workdir may be nil if we exited the constructor with errors (we call
 	// Close to clean up any partial state from the constructor, which calls
 	// RunGoCommand).
-	if sb.Workdir != nil {
+	if dir != "" {
+		inv.WorkingDir = sb.Workdir.filePath(dir)
+	} else if sb.Workdir != nil {
 		inv.WorkingDir = sb.Workdir.workdir
 	}
 	gocmdRunner := &gocommand.Runner{}
@@ -214,7 +217,7 @@
 func (sb *Sandbox) Close() error {
 	var goCleanErr error
 	if sb.gopath != "" {
-		goCleanErr = sb.RunGoCommand(context.Background(), "clean", "-modcache")
+		goCleanErr = sb.RunGoCommand(context.Background(), "", "clean", []string{"-modcache"})
 	}
 	err := os.RemoveAll(sb.basedir)
 	if err != nil || goCleanErr != nil {
diff --git a/internal/lsp/regtest/diagnostics_test.go b/internal/lsp/regtest/diagnostics_test.go
index 23ed172..779d820 100644
--- a/internal/lsp/regtest/diagnostics_test.go
+++ b/internal/lsp/regtest/diagnostics_test.go
@@ -276,7 +276,7 @@
 			env.Await(
 				env.DiagnosticAtRegexp("main.go", `"mod.com/bob"`),
 			)
-			if err := env.Sandbox.RunGoCommand(env.Ctx, "mod", "init", "mod.com"); err != nil {
+			if err := env.Sandbox.RunGoCommand(env.Ctx, "", "mod", []string{"init", "mod.com"}); err != nil {
 				t.Fatal(err)
 			}
 			env.Await(
diff --git a/internal/lsp/regtest/modfile_test.go b/internal/lsp/regtest/modfile_test.go
index 50e98ae..3069629 100644
--- a/internal/lsp/regtest/modfile_test.go
+++ b/internal/lsp/regtest/modfile_test.go
@@ -238,7 +238,7 @@
 			CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromInitialWorkspaceLoad), 1),
 			env.DiagnosticAtRegexp("go.mod", "require"),
 		)
-		env.Sandbox.RunGoCommand(env.Ctx, "mod", "tidy")
+		env.Sandbox.RunGoCommand(env.Ctx, "", "mod", []string{"tidy"})
 		env.Await(
 			EmptyDiagnostics("go.mod"),
 		)
diff --git a/internal/lsp/regtest/watch_test.go b/internal/lsp/regtest/watch_test.go
index 75cac13..cbea6ef 100644
--- a/internal/lsp/regtest/watch_test.go
+++ b/internal/lsp/regtest/watch_test.go
@@ -573,3 +573,48 @@
 		)
 	})
 }
+
+// Reproduces golang/go#37069.
+func TestSwitchFromGOPATHToModules(t *testing.T) {
+	t.Skipf("golang/go#37069 is not yet resolved.")
+
+	const files = `
+-- foo/blah/blah.go --
+package blah
+
+const Name = ""
+-- foo/main.go --
+package main
+
+import "blah"
+
+func main() {
+	_ = blah.Name
+}
+`
+	withOptions(InGOPATH()).run(t, files, func(t *testing.T, env *Env) {
+		env.OpenFile("foo/main.go")
+		env.Await(
+			OnceMet(
+				CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromInitialWorkspaceLoad), 1),
+				env.DiagnosticAtRegexp("foo/main.go", `"blah"`),
+			),
+		)
+		if err := env.Sandbox.RunGoCommand(env.Ctx, "foo", "mod", []string{"init", "mod.com"}); err != nil {
+			t.Fatal(err)
+		}
+		env.Await(
+			OnceMet(
+				CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidChangeWatchedFiles), 1),
+				env.DiagnosticAtRegexp("foo/main.go", `"blah`),
+			),
+		)
+		env.RegexpReplace("foo/main.go", `"blah"`, `"mod.com/blah"`)
+		env.Await(
+			OnceMet(
+				CompletedWork(lsp.DiagnosticWorkTitle(lsp.FromDidChange), 1),
+				NoDiagnostics("foo/main.go"),
+			),
+		)
+	})
+}