diff --git a/pythonFiles/testing_tools/unittest_discovery.py b/pythonFiles/testing_tools/unittest_discovery.py index d13ea1c10dd9..2988092c387c 100644 --- a/pythonFiles/testing_tools/unittest_discovery.py +++ b/pythonFiles/testing_tools/unittest_discovery.py @@ -1,11 +1,12 @@ -import unittest import inspect import os import sys import traceback +import unittest start_dir = sys.argv[1] pattern = sys.argv[2] +top_level_dir = sys.argv[3] if len(sys.argv) >= 4 else None sys.path.insert(0, os.getcwd()) @@ -38,7 +39,7 @@ def generate_test_cases(suite): try: loader = unittest.TestLoader() - suite = loader.discover(start_dir, pattern=pattern) + suite = loader.discover(start_dir, pattern=pattern, top_level_dir=top_level_dir) print("start") # Don't remove this line loader_errors = [] diff --git a/pythonFiles/visualstudio_py_testlauncher.py b/pythonFiles/visualstudio_py_testlauncher.py index 7f80dfa3ba88..0b0ef3242f65 100644 --- a/pythonFiles/visualstudio_py_testlauncher.py +++ b/pythonFiles/visualstudio_py_testlauncher.py @@ -17,14 +17,13 @@ __author__ = "Microsoft Corporation " __version__ = "3.0.0.0" -import os -import sys import json -import unittest +import os +import signal import socket +import sys import traceback -from types import CodeType, FunctionType -import signal +import unittest try: import thread @@ -295,8 +294,8 @@ def main(): if opts.mixed_mode: # For mixed-mode attach, there's no ptvsd and hence no wait_for_attach(), # so we have to use Win32 API in a loop to do the same thing. + from ctypes import c_char, windll from time import sleep - from ctypes import windll, c_char while True: if windll.kernel32.IsDebuggerPresent() != 0: @@ -334,7 +333,9 @@ def main(): # Easier approach is find the test suite and use that for running loader = unittest.TestLoader() # opts.us will be passed in - suites = loader.discover(opts.us, pattern=os.path.basename(opts.testFile)) + suites = loader.discover( + opts.us, pattern=os.path.basename(opts.testFile), top_level_dir=opts.ut + ) suite = None tests = None if opts.tests is None: diff --git a/src/client/testing/testController/unittest/arguments.ts b/src/client/testing/testController/unittest/arguments.ts index 52ae484a87c2..caff87999f6e 100644 --- a/src/client/testing/testController/unittest/arguments.ts +++ b/src/client/testing/testController/unittest/arguments.ts @@ -73,13 +73,29 @@ export function unittestGetTestPattern(args: string[]): string { return 'test*.py'; } +export function unittestGetTopLevelDirectory(args: string[]): string | null { + const shortValue = getOptionValues(args, '-t'); + if (shortValue.length === 1) { + return shortValue[0]; + } + const longValue = getOptionValues(args, '--top-level-directory'); + if (longValue.length === 1) { + return longValue[0]; + } + return null; +} + export function getTestRunArgs(args: string[]): string[] { const startTestDiscoveryDirectory = unittestGetTestFolders(args)[0]; const pattern = unittestGetTestPattern(args); + const topLevelDir = unittestGetTopLevelDirectory(args); const failFast = args.some((arg) => arg.trim() === '-f' || arg.trim() === '--failfast'); const verbosity = args.some((arg) => arg.trim().indexOf('-v') === 0) ? 2 : 1; const testArgs = [`--us=${startTestDiscoveryDirectory}`, `--up=${pattern}`, `--uvInt=${verbosity}`]; + if (topLevelDir) { + testArgs.push(`--ut=${topLevelDir}`); + } if (failFast) { testArgs.push('--uf'); } diff --git a/src/client/testing/testController/unittest/unittestController.ts b/src/client/testing/testController/unittest/unittestController.ts index 2fb4cb91c539..ee79103c4e3e 100644 --- a/src/client/testing/testController/unittest/unittestController.ts +++ b/src/client/testing/testController/unittest/unittestController.ts @@ -19,7 +19,7 @@ import { RawTestParent, TestData, } from '../common/types'; -import { unittestGetTestFolders, unittestGetTestPattern } from './arguments'; +import { unittestGetTestFolders, unittestGetTestPattern, unittestGetTopLevelDirectory } from './arguments'; import { createErrorTestItem, createWorkspaceRootTestItem, @@ -130,16 +130,20 @@ export class UnittestController implements ITestFrameworkController { const startDir = unittestGetTestFolders(options.args)[0]; const pattern = unittestGetTestPattern(options.args); + const topLevelDir = unittestGetTopLevelDirectory(options.args); let testDir = startDir; if (path.isAbsolute(startDir)) { const relative = path.relative(options.cwd, startDir); testDir = relative.length > 0 ? relative : '.'; } + const runOptionsArgs: string[] = + topLevelDir == null ? [startDir, pattern] : [startDir, pattern, topLevelDir]; + const runOptions: Options = { // unittest needs to load modules in the workspace // isolating it breaks unittest discovery - args: unittestDiscovery([startDir, pattern]), + args: unittestDiscovery(runOptionsArgs), cwd: options.cwd, workspaceFolder: options.workspaceFolder, token: options.token,