src/goDebugConfiguration.ts: use `program` to determine mode if file

If the `program` attribute is a go file, then we can use this to
determine whether to run 'debug' or 'test'.

If the program for 'test' mode is a test file, we run it instead in
the package.

Updates golang/vscode-go#1422

Change-Id: I869b0cb7422634d74dee5a04f6cc131be17ddc2f
Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/316509
Trust: Suzy Mueller <suzmue@golang.org>
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
diff --git a/docs/debugging.md b/docs/debugging.md
index a66ae0d..193162d 100644
--- a/docs/debugging.md
+++ b/docs/debugging.md
@@ -78,7 +78,7 @@
 
 ## Launch Configurations
 
-To get started debugging, run the command `Debug: Open launch.json`. If you did not already have a `launch.json` file for your project, this will create one for you. It will contain this default configuration, which can be used to debug the current package.
+To get started debugging, run the command `Debug: Open launch.json`. If you did not already have a `launch.json` file for your project, this will create one for you. It will contain this default configuration, which can be used to debug the current package. With mode `auto`, the file that is currently open will determine whether to debug the program as a test. If `program` is instead set to a Go file, that file will determine which mode to run in.
 
 ```json5
 {
@@ -437,7 +437,7 @@
     "name": "Launch remote",
     "type": "go",
     "request": "launch",
-    "mode": "auto",
+    "mode": "debug",
     "program": "/path/to/hello",
     "substitutePath": [
 		{
diff --git a/src/goDebugConfiguration.ts b/src/goDebugConfiguration.ts
index 27cd8c4..dad70f3 100644
--- a/src/goDebugConfiguration.ts
+++ b/src/goDebugConfiguration.ts
@@ -253,8 +253,19 @@
 		}
 
 		if (debugConfiguration['mode'] === 'auto') {
-			debugConfiguration['mode'] =
-				activeEditor && activeEditor.document.fileName.endsWith('_test.go') ? 'test' : 'debug';
+			let filename = activeEditor?.document?.fileName;
+			if (debugConfiguration['program'] && debugConfiguration['program'].endsWith('.go')) {
+				// If the 'program' attribute is a file, not a directory, then we will determine the mode from that
+				// file path instead of the currently active file.
+				filename = debugConfiguration['program'];
+			}
+			debugConfiguration['mode'] = filename.endsWith('_test.go') ? 'test' : 'debug';
+		}
+
+		if (debugConfiguration['mode'] === 'test' && debugConfiguration['program'].endsWith('_test.go')) {
+			// Running a test file in file mode does not make sense, so change the program
+			// to the directory.
+			debugConfiguration['program'] = path.dirname(debugConfiguration['program']);
 		}
 
 		if (debugConfiguration.request === 'launch' && debugConfiguration['mode'] === 'remote') {
diff --git a/test/integration/goDebugConfiguration.test.ts b/test/integration/goDebugConfiguration.test.ts
index 804df3b..d2c112d 100644
--- a/test/integration/goDebugConfiguration.test.ts
+++ b/test/integration/goDebugConfiguration.test.ts
@@ -423,3 +423,34 @@
 		assert.strictEqual(config.program, '${fileDirname}');
 	});
 });
+
+suite('Debug Configuration Auto Mode', () => {
+	const debugConfigProvider = new GoDebugConfigurationProvider();
+	test('resolve auto to debug with non-test file', () => {
+		const config = {
+			name: 'Launch',
+			type: 'go',
+			request: 'launch',
+			mode: 'auto',
+			program: '/path/to/main.go'
+		};
+
+		debugConfigProvider.resolveDebugConfiguration(undefined, config);
+		assert.strictEqual(config.mode, 'debug');
+		assert.strictEqual(config.program, '/path/to/main.go');
+	});
+
+	test('resolve auto to debug with test file', () => {
+		const config = {
+			name: 'Launch',
+			type: 'go',
+			request: 'launch',
+			mode: 'auto',
+			program: '/path/to/main_test.go'
+		};
+
+		debugConfigProvider.resolveDebugConfiguration(undefined, config);
+		assert.strictEqual(config.mode, 'test');
+		assert.strictEqual(config.program, '/path/to');
+	});
+});