Skip to content

Commit 4ecf02b

Browse files
authored
Unittest top-level-directory option (#19398)
* update unittest discovery to work with user defined top-level-directory * change to make top-level-dir optional * add top-level-dir to unittest run args * update test discovery to use top-level-directory
1 parent e60b51c commit 4ecf02b

File tree

4 files changed

+33
-11
lines changed

4 files changed

+33
-11
lines changed

pythonFiles/testing_tools/unittest_discovery.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
import unittest
21
import inspect
32
import os
43
import sys
54
import traceback
5+
import unittest
66

77
start_dir = sys.argv[1]
88
pattern = sys.argv[2]
9+
top_level_dir = sys.argv[3] if len(sys.argv) >= 4 else None
910
sys.path.insert(0, os.getcwd())
1011

1112

@@ -38,7 +39,7 @@ def generate_test_cases(suite):
3839

3940
try:
4041
loader = unittest.TestLoader()
41-
suite = loader.discover(start_dir, pattern=pattern)
42+
suite = loader.discover(start_dir, pattern=pattern, top_level_dir=top_level_dir)
4243

4344
print("start") # Don't remove this line
4445
loader_errors = []

pythonFiles/visualstudio_py_testlauncher.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,13 @@
1717
__author__ = "Microsoft Corporation <ptvshelp@microsoft.com>"
1818
__version__ = "3.0.0.0"
1919

20-
import os
21-
import sys
2220
import json
23-
import unittest
21+
import os
22+
import signal
2423
import socket
24+
import sys
2525
import traceback
26-
from types import CodeType, FunctionType
27-
import signal
26+
import unittest
2827

2928
try:
3029
import thread
@@ -295,8 +294,8 @@ def main():
295294
if opts.mixed_mode:
296295
# For mixed-mode attach, there's no ptvsd and hence no wait_for_attach(),
297296
# so we have to use Win32 API in a loop to do the same thing.
297+
from ctypes import c_char, windll
298298
from time import sleep
299-
from ctypes import windll, c_char
300299

301300
while True:
302301
if windll.kernel32.IsDebuggerPresent() != 0:
@@ -334,7 +333,9 @@ def main():
334333
# Easier approach is find the test suite and use that for running
335334
loader = unittest.TestLoader()
336335
# opts.us will be passed in
337-
suites = loader.discover(opts.us, pattern=os.path.basename(opts.testFile))
336+
suites = loader.discover(
337+
opts.us, pattern=os.path.basename(opts.testFile), top_level_dir=opts.ut
338+
)
338339
suite = None
339340
tests = None
340341
if opts.tests is None:

src/client/testing/testController/unittest/arguments.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,29 @@ export function unittestGetTestPattern(args: string[]): string {
7373
return 'test*.py';
7474
}
7575

76+
export function unittestGetTopLevelDirectory(args: string[]): string | null {
77+
const shortValue = getOptionValues(args, '-t');
78+
if (shortValue.length === 1) {
79+
return shortValue[0];
80+
}
81+
const longValue = getOptionValues(args, '--top-level-directory');
82+
if (longValue.length === 1) {
83+
return longValue[0];
84+
}
85+
return null;
86+
}
87+
7688
export function getTestRunArgs(args: string[]): string[] {
7789
const startTestDiscoveryDirectory = unittestGetTestFolders(args)[0];
7890
const pattern = unittestGetTestPattern(args);
91+
const topLevelDir = unittestGetTopLevelDirectory(args);
7992

8093
const failFast = args.some((arg) => arg.trim() === '-f' || arg.trim() === '--failfast');
8194
const verbosity = args.some((arg) => arg.trim().indexOf('-v') === 0) ? 2 : 1;
8295
const testArgs = [`--us=${startTestDiscoveryDirectory}`, `--up=${pattern}`, `--uvInt=${verbosity}`];
96+
if (topLevelDir) {
97+
testArgs.push(`--ut=${topLevelDir}`);
98+
}
8399
if (failFast) {
84100
testArgs.push('--uf');
85101
}

src/client/testing/testController/unittest/unittestController.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {
1919
RawTestParent,
2020
TestData,
2121
} from '../common/types';
22-
import { unittestGetTestFolders, unittestGetTestPattern } from './arguments';
22+
import { unittestGetTestFolders, unittestGetTestPattern, unittestGetTopLevelDirectory } from './arguments';
2323
import {
2424
createErrorTestItem,
2525
createWorkspaceRootTestItem,
@@ -130,16 +130,20 @@ export class UnittestController implements ITestFrameworkController {
130130

131131
const startDir = unittestGetTestFolders(options.args)[0];
132132
const pattern = unittestGetTestPattern(options.args);
133+
const topLevelDir = unittestGetTopLevelDirectory(options.args);
133134
let testDir = startDir;
134135
if (path.isAbsolute(startDir)) {
135136
const relative = path.relative(options.cwd, startDir);
136137
testDir = relative.length > 0 ? relative : '.';
137138
}
138139

140+
const runOptionsArgs: string[] =
141+
topLevelDir == null ? [startDir, pattern] : [startDir, pattern, topLevelDir];
142+
139143
const runOptions: Options = {
140144
// unittest needs to load modules in the workspace
141145
// isolating it breaks unittest discovery
142-
args: unittestDiscovery([startDir, pattern]),
146+
args: unittestDiscovery(runOptionsArgs),
143147
cwd: options.cwd,
144148
workspaceFolder: options.workspaceFolder,
145149
token: options.token,

0 commit comments

Comments
 (0)