test/integration: use module mode for testing

With go1.16, the default build mode will be module mode and
the meaning of GO111MODULE='' will change. So, stop depending
on the default behavior during testing. This CL runs
extension.test.ts in GOPATH mode and module mode. And
explicitly sets GO111MODULE depending on the mode we want to
test.

Also, we place the fixtures in a temp directory when running
in module mode - that is 1) to test module mode works when
the source is outside of GOPATH/src, and 2) to avoid the conflicts
caused by the buffer (editor) in vscode when opening the same
file path twice (one for GOPATH mode, another for module mode)
if we lay out the code in the GOPATH/src. We use one instance
of vscode for all the integration test and the open file edit
buffer's lifetime is not controlled by us.

test.test.ts already tests both GOPATH and module modes.
Assuming GO111MODULE='', we switched between these two modes
by placing the test data under GOPATH/src and placing or not
placing go.mod.

For golang/vscode-go#983

Change-Id: Ia18d6672183b838203562095fefc3a3445a4cb66
Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/291313
Trust: Hyang-Ah Hana Kim <hyangah@gmail.com>
Run-TryBot: Hyang-Ah Hana Kim <hyangah@gmail.com>
TryBot-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
diff --git a/test/integration/codelens.test.ts b/test/integration/codelens.test.ts
index a96b957..91fb23a 100644
--- a/test/integration/codelens.test.ts
+++ b/test/integration/codelens.test.ts
@@ -47,14 +47,6 @@
 		fs.removeSync(repoPath);
 		fs.copySync(fixtureSourcePath, fixturePath, {
 			recursive: true,
-			// All of the tests run in GOPATH mode for now.
-			// TODO(rstambler): Run tests in GOPATH and module mode.
-			filter: (src: string): boolean => {
-				if (path.basename(src) === 'go.mod') {
-					return false;
-				}
-				return true;
-			},
 		});
 		goConfig = getGoConfig();
 		const uri = vscode.Uri.file(path.join(fixturePath, 'codelens_test.go'));
diff --git a/test/integration/extension.test.ts b/test/integration/extension.test.ts
index c33dca2..2e21a00 100644
--- a/test/integration/extension.test.ts
+++ b/test/integration/extension.test.ts
@@ -6,6 +6,7 @@
 import * as assert from 'assert';
 import cp = require('child_process');
 import * as fs from 'fs-extra';
+import os = require('os');
 import * as path from 'path';
 import * as sinon from 'sinon';
 import * as vscode from 'vscode';
@@ -41,9 +42,7 @@
 	isVendorSupported
 } from '../../src/util';
 
-suite('Go Extension Tests', function () {
-	this.timeout(20000);
-
+const testAll = (isModuleMode: boolean) => {
 	const dummyCancellationSource = new vscode.CancellationTokenSource();
 
 	// suiteSetup will initialize the following vars.
@@ -54,9 +53,12 @@
 	let generateTestsSourcePath: string;
 	let generateFunctionTestSourcePath: string;
 	let generatePackageTestSourcePath: string;
-	let toolsGopath: string;
+	let previousEnv: any;
 
 	suiteSetup(async () => {
+		previousEnv = Object.assign({}, process.env);
+		process.env.GO111MODULE = isModuleMode ? 'on' : 'off';
+
 		await updateGoVarsFromConfig();
 
 		gopath = getCurrentGoPath();
@@ -66,25 +68,17 @@
 		}
 		console.log(`Using GOPATH: ${gopath}`);
 
-		repoPath = path.join(gopath, 'src', 'test');
+		repoPath = isModuleMode ? fs.mkdtempSync(path.join(os.tmpdir(), 'legacy')) : path.join(gopath, 'src', 'test');
 		fixturePath = path.join(repoPath, 'testfixture');
 		fixtureSourcePath = path.join(__dirname, '..', '..', '..', 'test', 'testdata');
 		generateTestsSourcePath = path.join(repoPath, 'generatetests');
 		generateFunctionTestSourcePath = path.join(repoPath, 'generatefunctiontest');
 		generatePackageTestSourcePath = path.join(repoPath, 'generatePackagetest');
-		toolsGopath = getToolsGopath() || gopath;
 
 		fs.removeSync(repoPath);
 		fs.copySync(fixtureSourcePath, fixturePath, {
-			recursive: true,
-			// All of the tests run in GOPATH mode for now.
-			// TODO(rstambler): Run tests in GOPATH and module mode.
-			filter: (src: string): boolean => {
-				if (path.basename(src) === 'go.mod') {
-					return false;
-				}
-				return true;
-			},
+			recursive: true
+			// TODO(hyangah): should we enable GOPATH mode
 		});
 		fs.copySync(
 			path.join(fixtureSourcePath, 'generatetests', 'generatetests.go'),
@@ -118,6 +112,7 @@
 
 	suiteTeardown(() => {
 		fs.removeSync(repoPath);
+		process.env = previousEnv;
 	});
 
 	teardown(() => {
@@ -191,14 +186,17 @@
 		return Promise.all(promises);
 	}
 
-	test('Test Definition Provider using godoc', async () => {
+	test('Test Definition Provider using godoc', async function () {
+		if (isModuleMode) { this.skip(); } // not working in module mode.
+
 		const config = Object.create(getGoConfig(), {
 			docsTool: { value: 'godoc' }
 		});
 		await testDefinitionProvider(config);
 	});
 
-	test('Test Definition Provider using gogetdoc', async () => {
+	test('Test Definition Provider using gogetdoc', async function () {
+		if (isModuleMode) {	this.skip(); }  // not working in module mode.
 		const gogetdocPath = getBinPath('gogetdoc');
 		if (gogetdocPath === 'gogetdoc') {
 			// gogetdoc is not installed, so skip the test
@@ -210,7 +208,9 @@
 		await testDefinitionProvider(config);
 	});
 
-	test('Test SignatureHelp Provider using godoc', async () => {
+	test('Test SignatureHelp Provider using godoc', async function () {
+		if (isModuleMode) { this.skip(); }  // not working in module mode
+
 		const printlnDoc = `Println formats using the default formats for its operands and writes to
 standard output. Spaces are always added between operands and a newline is
 appended. It returns the number of bytes written and any write error
@@ -249,7 +249,8 @@
 		await testSignatureHelpProvider(config, testCases);
 	});
 
-	test('Test SignatureHelp Provider using gogetdoc', async () => {
+	test('Test SignatureHelp Provider using gogetdoc', async function () {
+		if (isModuleMode) {	this.skip(); }  // not working in module mode.
 		const gogetdocPath = getBinPath('gogetdoc');
 		if (gogetdocPath === 'gogetdoc') {
 			// gogetdoc is not installed, so skip the test
@@ -292,7 +293,9 @@
 		await testSignatureHelpProvider(config, testCases);
 	});
 
-	test('Test Hover Provider using godoc', async () => {
+	test('Test Hover Provider using godoc', async function () {
+		if (isModuleMode) { this.skip(); }  // not working in module mode
+
 		const printlnDoc = `Println formats using the default formats for its operands and writes to
 standard output. Spaces are always added between operands and a newline is
 appended. It returns the number of bytes written and any write error
@@ -319,7 +322,9 @@
 		await testHoverProvider(config, testCases);
 	});
 
-	test('Test Hover Provider using gogetdoc', async () => {
+	test('Test Hover Provider using gogetdoc', async function () {
+		if (isModuleMode) {	this.skip(); }  // not working in module mode.
+
 		const gogetdocPath = getBinPath('gogetdoc');
 		if (gogetdocPath === 'gogetdoc') {
 			// gogetdoc is not installed, so skip the test
@@ -454,11 +459,11 @@
 		assert.equal(matchCount.length >= expected.length, true, `Failed to match expected errors \n${JSON.stringify(sortedDiagnostics)} \n VS\n ${JSON.stringify(expected)}`);
 	});
 
-	test('Test Generate unit tests skeleton for file', async () => {
+	test('Test Generate unit tests skeleton for file', async function () {
 		const gotestsPath = getBinPath('gotests');
 		if (gotestsPath === 'gotests') {
 			// gotests is not installed, so skip the test
-			return;
+			this.skip();
 		}
 
 		const uri = vscode.Uri.file(path.join(generateTestsSourcePath, 'generatetests.go'));
@@ -470,11 +475,11 @@
 		assert.equal(testFileGenerated, true, 'Test file not generated.');
 	});
 
-	test('Test Generate unit tests skeleton for a function', async () => {
+	test('Test Generate unit tests skeleton for a function', async function () {
 		const gotestsPath = getBinPath('gotests');
 		if (gotestsPath === 'gotests') {
 			// gotests is not installed, so skip the test
-			return;
+			this.skip();
 		}
 
 		const uri = vscode.Uri.file(path.join(generateFunctionTestSourcePath, 'generatetests.go'));
@@ -487,11 +492,11 @@
 		assert.equal(testFileGenerated, true, 'Test file not generated.');
 	});
 
-	test('Test Generate unit tests skeleton for package', async () => {
+	test('Test Generate unit tests skeleton for package', async function () {
 		const gotestsPath = getBinPath('gotests');
 		if (gotestsPath === 'gotests') {
 			// gotests is not installed, so skip the test
-			return;
+			this.skip();
 		}
 
 		const uri = vscode.Uri.file(path.join(generatePackageTestSourcePath, 'generatetests.go'));
@@ -504,6 +509,9 @@
 	});
 
 	test('Test diffUtils.getEditsFromUnifiedDiffStr', async function () {
+		// Run this test only in module mode.
+		if (!isModuleMode) { this.skip(); }
+
 		if (process.platform === 'win32') {
 			// This test requires diff tool that's not available on windows
 			this.skip();
@@ -543,7 +551,9 @@
 		assert.equal(editor.document.getText(), file2contents);
 	});
 
-	test('Test diffUtils.getEdits', async () => {
+	test('Test diffUtils.getEdits', async function () {
+		if (!isModuleMode) { this.skip(); }  // Run this test only in module mode.
+
 		const file1path = path.join(fixturePath, 'diffTest2Data', 'file1.go');
 		const file2path = path.join(fixturePath, 'diffTest2Data', 'file2.go');
 		const file1uri = vscode.Uri.file(file1path);
@@ -663,7 +673,8 @@
 		assert.equal(excludeImportedPkgs.indexOf('fmt') > -1, false);
 	});
 
-	test('Replace vendor packages with relative path', async () => {
+	test('Replace vendor packages with relative path', async function () {
+		if (isModuleMode) {	this.skip(); }  // not working in module mode.
 		const vendorSupport = await isVendorSupported();
 		const filePath = path.join(fixturePath, 'vendoring', 'main.go');
 		const workDir = path.dirname(filePath);
@@ -723,7 +734,8 @@
 		}
 	});
 
-	test('Vendor pkgs from other projects should not be allowed to import', async () => {
+	test('Vendor pkgs from other projects should not be allowed to import', async function () {
+		if (isModuleMode) {	this.skip(); }  // not working in module mode.
 		const vendorSupport = await isVendorSupported();
 		const filePath = path.join(fixturePath, 'baseTest', 'test.go');
 		const vendorPkgs = [
@@ -1145,7 +1157,11 @@
 		await Promise.all([symbolFollowedByBrackets, symbolAsLastParameter, symbolsAsNonLastParameter]);
 	});
 
-	test('Test Completion on unimported packages', async () => {
+	test('Test Completion on unimported packages', async function () {
+		if (isModuleMode) { this.skip(); }
+		// gocode-gomod does not handle unimported package completion.
+		// Skip if we run in module mode.
+
 		const config = Object.create(getGoConfig(), {
 			autocompleteUnimportedPackages: { value: true }
 		});
@@ -1568,4 +1584,14 @@
 		await runFillStruct(editor);
 		assert.equal(vscode.window.activeTextEditor && vscode.window.activeTextEditor.document.getText(), golden);
 	});
+};
+
+suite('Go Extension Tests (GOPATH mode)', function () {
+	this.timeout(20000);
+	testAll(false);
+});
+
+suite('Go Extension Tests (Module mode)', function () {
+	this.timeout(20000);
+	testAll(true);
 });
diff --git a/test/integration/test.test.ts b/test/integration/test.test.ts
index 27ef442..58e26fc 100644
--- a/test/integration/test.test.ts
+++ b/test/integration/test.test.ts
@@ -115,20 +115,21 @@
 		rmdirRecursive(tmpGopath);
 	});
 
-	function setupRepo(modulesMode: boolean) {
+	function setupRepo(isModuleMode: boolean) {
 		tmpGopath = fs.mkdtempSync(path.join(os.tmpdir(), 'go-test-test'));
 		fs.mkdirSync(path.join(tmpGopath, 'src'));
 		repoPath = path.join(tmpGopath, 'src', 'goTestTest');
 		fs.copySync(sourcePath, repoPath, {
 			recursive: true,
 			filter: (src: string): boolean => {
-				if (modulesMode) {
+				if (isModuleMode) {
 					return true;
 				}
 				return path.basename(src) !== 'go.mod';  // skip go.mod file.
 			},
 		});
 		process.env.GOPATH = tmpGopath;
+		process.env.GO111MODULE = isModuleMode ? 'on' : 'off';
 	}
 
 	async function runTest(