diff --git a/.travis.yml b/.travis.yml index 45c73062ebf5..4631c982bbdb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -48,6 +48,7 @@ before_install: | pyenv install $PYTHON pyenv global $PYTHON fi + export TRAVIS_PYTHON_PATH=`which python` install: - pip install --upgrade -r requirements.txt - npm install diff --git a/.vscode/launch.json b/.vscode/launch.json index 149fe6c0addc..8c80fc1679cd 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -33,7 +33,7 @@ "outFiles": [ "${workspaceRoot}/out/**/*.js" ], - "preLaunchTask": "npm" + "preLaunchTask": "compile" }, { "name": "Launch Extension as debugServer", // https://code.visualstudio.com/docs/extensions/example-debuggers @@ -65,7 +65,7 @@ "outFiles": [ "${workspaceRoot}/out/**/*.js" ], - "preLaunchTask": "npm" + "preLaunchTask": "compile" }, { "name": "Launch Multiroot Tests", @@ -73,7 +73,7 @@ "request": "launch", "runtimeExecutable": "${execPath}", "args": [ - "${workspaceRoot}/src/test/multiRootWkspc/multi.code-workspace", + "${workspaceRoot}/src/testMultiRootWkspc/multi.code-workspace", "--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/out/test" ], diff --git a/src/client/debugger/configProviders/simpleProvider.ts b/src/client/debugger/configProviders/simpleProvider.ts index efb069a67b16..391edd782d99 100644 --- a/src/client/debugger/configProviders/simpleProvider.ts +++ b/src/client/debugger/configProviders/simpleProvider.ts @@ -51,7 +51,7 @@ export class SimpleConfigurationProvider implements DebugConfigurationProvider { type: 'python', request: 'launch', stopOnEntry: true, - pythonPath: PythonSettings.getInstance().pythonPath, + pythonPath: PythonSettings.getInstance(workspaceFolder ? Uri.file(workspaceFolder) : undefined).pythonPath, program: defaultProgram, cwd: workspaceFolder, envFile, diff --git a/src/client/providers/execInTerminalProvider.ts b/src/client/providers/execInTerminalProvider.ts index e248e32bc432..0487f7362cf4 100644 --- a/src/client/providers/execInTerminalProvider.ts +++ b/src/client/providers/execInTerminalProvider.ts @@ -33,7 +33,7 @@ function execInTerminal(fileUri?: vscode.Uri) { const terminalShellSettings = vscode.workspace.getConfiguration('terminal.integrated.shell'); const IS_POWERSHELL = /powershell/.test(terminalShellSettings.get('windows')); - let pythonSettings = settings.PythonSettings.getInstance(); + let pythonSettings = settings.PythonSettings.getInstance(fileUri); let filePath: string; let currentPythonPath = pythonSettings.pythonPath; diff --git a/src/client/providers/shebangCodeLensProvider.ts b/src/client/providers/shebangCodeLensProvider.ts index 2be8598a8463..8988d6161644 100644 --- a/src/client/providers/shebangCodeLensProvider.ts +++ b/src/client/providers/shebangCodeLensProvider.ts @@ -15,7 +15,7 @@ export class ShebangCodeLensProvider implements vscode.CodeLensProvider { private async createShebangCodeLens(document: TextDocument) { const shebang = await ShebangCodeLensProvider.detectShebang(document); - if (!shebang || shebang === settings.PythonSettings.getInstance().pythonPath) { + if (!shebang || shebang === settings.PythonSettings.getInstance(document.uri).pythonPath) { return []; } diff --git a/src/client/unittests/common/baseTestManager.ts b/src/client/unittests/common/baseTestManager.ts index 1dc38f7259b2..e1f3dde1e5ab 100644 --- a/src/client/unittests/common/baseTestManager.ts +++ b/src/client/unittests/common/baseTestManager.ts @@ -4,6 +4,7 @@ import * as vscode from 'vscode'; import { resetTestResults, displayTestErrorMessage, storeDiscoveredTests } from './testUtils'; import { Installer, Product } from '../../common/installer'; import { isNotInstalledError } from '../../common/helpers'; +import { IPythonSettings, PythonSettings } from '../../common/configSettings'; export abstract class BaseTestManager { private tests: Tests; @@ -25,9 +26,11 @@ export abstract class BaseTestManager { this.cancellationTokenSource.cancel(); } } + protected readonly settings: IPythonSettings; constructor(private testProvider: string, private product: Product, protected rootDirectory: string, protected outputChannel: vscode.OutputChannel) { this._status = TestStatus.Unknown; this.installer = new Installer(); + this.settings = PythonSettings.getInstance(vscode.Uri.file(this.rootDirectory)); } public reset() { this._status = TestStatus.Unknown; @@ -179,4 +182,4 @@ export abstract class BaseTestManager { }); } abstract runTestImpl(tests: Tests, testsToRun?: TestsToRun, runFailedTests?: boolean, debug?: boolean): Promise; -} \ No newline at end of file +} diff --git a/src/client/unittests/common/debugLauncher.ts b/src/client/unittests/common/debugLauncher.ts index 099bfaa5b377..026a46759eff 100644 --- a/src/client/unittests/common/debugLauncher.ts +++ b/src/client/unittests/common/debugLauncher.ts @@ -4,8 +4,8 @@ import { PythonSettings } from '../../common/configSettings'; import { execPythonFile } from './../../common/utils'; import { createDeferred } from './../../common/helpers'; -const pythonSettings = PythonSettings.getInstance(); export function launchDebugger(rootDirectory: string, testArgs: string[], token?: CancellationToken, outChannel?: OutputChannel) { + const pythonSettings = PythonSettings.getInstance(rootDirectory ? Uri.file(rootDirectory) : undefined); const def = createDeferred(); const launchDef = createDeferred(); let outputChannelShown = false; diff --git a/src/client/unittests/configuration.ts b/src/client/unittests/configuration.ts index 0c1f47f7bf45..cd2b7614179e 100644 --- a/src/client/unittests/configuration.ts +++ b/src/client/unittests/configuration.ts @@ -9,8 +9,6 @@ import * as unittest from './unittest/testConfigurationManager'; import { getSubDirectories } from '../common/utils'; import * as path from 'path'; -const settings = PythonSettings.getInstance(); - function promptToEnableAndConfigureTestFramework(outputChannel: vscode.OutputChannel, messageToDisplay: string = 'Select a test framework/tool to enable', enableOnly: boolean = false): Thenable { const items = [{ label: 'unittest', @@ -76,8 +74,9 @@ function promptToEnableAndConfigureTestFramework(outputChannel: vscode.OutputCha // Cuz we don't want the test engine (in main.ts file - tests get discovered when config changes are detected) // to start discovering tests when tests haven't been configured properly function enableTest(): Thenable { + // TODO: Enable multi workspace root support const pythonConfig = vscode.workspace.getConfiguration('python'); - if (settings.unitTest.promptToConfigure) { + if (pythonConfig.get('unitTest.promptToConfigure')) { return configMgr.enable(); } return pythonConfig.update('unitTest.promptToConfigure', undefined).then(() => { @@ -94,6 +93,8 @@ function promptToEnableAndConfigureTestFramework(outputChannel: vscode.OutputCha }); } export function displayTestFrameworkError(outputChannel: vscode.OutputChannel): Thenable { + // TODO: Enable multi workspace root support + const settings = PythonSettings.getInstance(); let enabledCount = settings.unitTest.pyTestEnabled ? 1 : 0; enabledCount += settings.unitTest.nosetestsEnabled ? 1 : 0; enabledCount += settings.unitTest.unittestEnabled ? 1 : 0; @@ -111,6 +112,7 @@ export function displayTestFrameworkError(outputChannel: vscode.OutputChannel): } } export function displayPromptToEnableTests(rootDir: string, outputChannel: vscode.OutputChannel): Thenable { + const settings = PythonSettings.getInstance(vscode.Uri.file(rootDir)); if (settings.unitTest.pyTestEnabled || settings.unitTest.nosetestsEnabled || settings.unitTest.unittestEnabled) { @@ -147,4 +149,4 @@ function checkIfHasTestDirs(rootDir: string): Promise { return getSubDirectories(rootDir).then(subDirs => { return subDirs.map(dir => path.relative(rootDir, dir)).filter(dir => dir.match(/test/i)).length > 0; }); -} \ No newline at end of file +} diff --git a/src/client/unittests/main.ts b/src/client/unittests/main.ts index 6ab1f22b2e71..2fab50340bb5 100644 --- a/src/client/unittests/main.ts +++ b/src/client/unittests/main.ts @@ -14,14 +14,13 @@ import { } from './common/contracts'; import { resolveValueAsTestToRun, getDiscoveredTests } from './common/testUtils'; import { BaseTestManager } from './common/baseTestManager'; -import { PythonSettings } from '../common/configSettings'; +import { PythonSettings, IUnitTestSettings } from '../common/configSettings'; import { TestResultDisplay } from './display/main'; import { TestDisplay } from './display/picker'; import { activateCodeLenses } from './codeLenses/main'; import { displayTestFrameworkError } from './configuration'; import { PythonSymbolProvider } from '../providers/symbolProvider'; -const settings = PythonSettings.getInstance(); let testManager: BaseTestManager | undefined | null; let pyTestManager: pytest.TestManager | undefined | null; let unittestManager: unittest.TestManager | undefined | null; @@ -32,6 +31,9 @@ let outChannel: vscode.OutputChannel; let onDidChange: vscode.EventEmitter = new vscode.EventEmitter(); export function activate(context: vscode.ExtensionContext, outputChannel: vscode.OutputChannel, symboldProvider: PythonSymbolProvider) { + // TODO: Add multi workspace support + const settings = PythonSettings.getInstance(); + uniTestSettingsString = JSON.stringify(settings.unitTest); context.subscriptions.push({ dispose: dispose }); outChannel = outputChannel; let disposables = registerCommands(); @@ -51,6 +53,8 @@ export function activate(context: vscode.ExtensionContext, outputChannel: vscode } function getTestWorkingDirectory() { + // TODO: Add multi workspace support + const settings = PythonSettings.getInstance(); return settings.unitTest.cwd && settings.unitTest.cwd.length > 0 ? settings.unitTest.cwd : vscode.workspace.rootPath!; } @@ -184,9 +188,11 @@ function displayStopUI(message: string) { testDisplay = testDisplay ? testDisplay : new TestDisplay(); testDisplay.displayStopTestUI(message); } -let uniTestSettingsString = JSON.stringify(settings.unitTest); +let uniTestSettingsString: string; function onConfigChanged() { + // TODO: Add multi workspace support + const settings = PythonSettings.getInstance(); // Possible that a test framework has been enabled or some settings have changed // Meaning we need to re-load the discovered tests (as something could have changed) const newSettings = JSON.stringify(settings.unitTest); @@ -230,6 +236,7 @@ function onConfigChanged() { } function getTestRunner() { const rootDirectory = getTestWorkingDirectory(); + const settings = PythonSettings.getInstance(vscode.Uri.file(rootDirectory)); if (settings.unitTest.nosetestsEnabled) { return nosetestManager = nosetestManager ? nosetestManager : new nosetests.TestManager(rootDirectory, outChannel); } @@ -317,4 +324,4 @@ function runTestsImpl(arg?: vscode.Uri | TestsToRun | boolean | FlattenedTestFun }); testResultDisplay.DisplayProgressStatus(runPromise, debug); -} \ No newline at end of file +} diff --git a/src/client/unittests/nosetest/collector.ts b/src/client/unittests/nosetest/collector.ts index 7c8888d19459..1926aa694237 100644 --- a/src/client/unittests/nosetest/collector.ts +++ b/src/client/unittests/nosetest/collector.ts @@ -6,9 +6,8 @@ import * as os from 'os'; import { extractBetweenDelimiters, convertFileToPackage, flattenTestFiles } from '../common/testUtils'; import { CancellationToken } from 'vscode'; import { PythonSettings } from '../../common/configSettings'; -import { OutputChannel } from 'vscode'; +import { OutputChannel, Uri } from 'vscode'; -const pythonSettings = PythonSettings.getInstance(); const NOSE_WANT_FILE_PREFIX = 'nose.selector: DEBUG: wantFile '; const NOSE_WANT_FILE_SUFFIX = '.py? True'; const NOSE_WANT_FILE_SUFFIX_WITHOUT_EXT = '? True'; @@ -78,7 +77,7 @@ export function discoverTests(rootDirectory: string, args: string[], token: Canc }); } - return execPythonFile(pythonSettings.unitTest.nosetestPath, args.concat(['--collect-only', '-vvv']), rootDirectory, true) + return execPythonFile(PythonSettings.getInstance(Uri.file(rootDirectory)).unitTest.nosetestPath, args.concat(['--collect-only', '-vvv']), rootDirectory, true) .then(data => { outChannel.appendLine(data); processOutput(data); diff --git a/src/client/unittests/nosetest/main.ts b/src/client/unittests/nosetest/main.ts index 1f3def92cfb8..12ced38c9a7d 100644 --- a/src/client/unittests/nosetest/main.ts +++ b/src/client/unittests/nosetest/main.ts @@ -8,18 +8,16 @@ import { BaseTestManager } from '../common/baseTestManager'; import { runTest } from './runner'; import { Product } from '../../common/installer'; -const settings = PythonSettings.getInstance(); - export class TestManager extends BaseTestManager { constructor(rootDirectory: string, outputChannel: vscode.OutputChannel) { super('nosetest', Product.nosetest, rootDirectory, outputChannel); } discoverTestsImpl(ignoreCache: boolean): Promise { - let args = settings.unitTest.nosetestArgs.slice(0); + let args = this.settings.unitTest.nosetestArgs.slice(0); return discoverTests(this.rootDirectory, args, this.cancellationToken, ignoreCache, this.outputChannel); } runTestImpl(tests: Tests, testsToRun?: TestsToRun, runFailedTests?: boolean, debug?: boolean): Promise { - let args = settings.unitTest.nosetestArgs.slice(0); + let args = this.settings.unitTest.nosetestArgs.slice(0); if (runFailedTests === true && args.indexOf('--failed') === -1) { args.push('--failed'); } diff --git a/src/client/unittests/nosetest/runner.ts b/src/client/unittests/nosetest/runner.ts index fdaba3ff8254..3f6f73bb2532 100644 --- a/src/client/unittests/nosetest/runner.ts +++ b/src/client/unittests/nosetest/runner.ts @@ -1,6 +1,6 @@ 'use strict'; import { createTemporaryFile } from '../../common/helpers'; -import { OutputChannel, CancellationToken } from 'vscode'; +import { OutputChannel, CancellationToken, Uri } from 'vscode'; import { TestsToRun, Tests } from '../common/contracts'; import { updateResults } from '../common/testUtils'; import { updateResultsFromXmlLogFile, PassCalculationFormulae } from '../common/xUnitParser'; @@ -9,7 +9,6 @@ import { PythonSettings } from '../../common/configSettings'; import * as path from 'path'; import { launchDebugger } from '../common/debugLauncher'; -const pythonSettings = PythonSettings.getInstance(); const WITH_XUNIT = '--with-xunit'; const XUNIT_FILE = '--xunit-file'; @@ -61,6 +60,7 @@ export function runTest(rootDirectory: string, tests: Tests, args: string[], tes } return promiseToGetXmlLogFile.then(() => { + const pythonSettings = PythonSettings.getInstance(Uri.file(rootDirectory)); if (debug === true) { const testLauncherFile = path.join(__dirname, '..', '..', '..', '..', 'pythonFiles', 'PythonTools', 'testlauncher.py'); const nosetestlauncherargs = [rootDirectory, 'my_secret', pythonSettings.unitTest.debugPort.toString(), 'nose']; diff --git a/src/client/unittests/pytest/collector.ts b/src/client/unittests/pytest/collector.ts index af36b2b9fb97..eecc8055fa11 100644 --- a/src/client/unittests/pytest/collector.ts +++ b/src/client/unittests/pytest/collector.ts @@ -8,8 +8,6 @@ import * as path from 'path'; import { PythonSettings } from '../../common/configSettings'; import { OutputChannel } from 'vscode'; -const pythonSettings = PythonSettings.getInstance(); - const argsToExcludeForDiscovery = ['-x', '--exitfirst', '--fixtures-per-test', '--pdb', '--runxfail', '--lf', '--last-failed', '--ff', '--failed-first', @@ -85,7 +83,7 @@ export function discoverTests(rootDirectory: string, args: string[], token: vsco }); } - return execPythonFile(pythonSettings.unitTest.pyTestPath, args.concat(['--collect-only']), rootDirectory, false, null, token) + return execPythonFile(PythonSettings.getInstance(vscode.Uri.file(rootDirectory)).unitTest.pyTestPath, args.concat(['--collect-only']), rootDirectory, false, null, token) .then(data => { outChannel.appendLine(data); processOutput(data); diff --git a/src/client/unittests/pytest/main.ts b/src/client/unittests/pytest/main.ts index 8be3477c1b81..06e86e75fd34 100644 --- a/src/client/unittests/pytest/main.ts +++ b/src/client/unittests/pytest/main.ts @@ -1,5 +1,4 @@ 'use strict'; -import { PythonSettings } from '../../common/configSettings'; import { TestsToRun, Tests } from '../common/contracts'; import { runTest } from './runner'; import * as vscode from 'vscode'; @@ -7,17 +6,16 @@ import { discoverTests } from './collector'; import { BaseTestManager } from '../common/baseTestManager'; import { Product } from '../../common/installer'; -const settings = PythonSettings.getInstance(); export class TestManager extends BaseTestManager { constructor(rootDirectory: string, outputChannel: vscode.OutputChannel) { super('pytest', Product.pytest, rootDirectory, outputChannel); } discoverTestsImpl(ignoreCache: boolean): Promise { - let args = settings.unitTest.pyTestArgs.slice(0); + let args = this.settings.unitTest.pyTestArgs.slice(0); return discoverTests(this.rootDirectory, args, this.cancellationToken, ignoreCache, this.outputChannel); } runTestImpl(tests: Tests, testsToRun?: TestsToRun, runFailedTests?: boolean, debug?: boolean): Promise { - let args = settings.unitTest.pyTestArgs.slice(0); + let args = this.settings.unitTest.pyTestArgs.slice(0); if (runFailedTests === true && args.indexOf('--lf') === -1 && args.indexOf('--last-failed') === -1) { args.push('--last-failed'); } diff --git a/src/client/unittests/pytest/runner.ts b/src/client/unittests/pytest/runner.ts index eb564b57c015..963ad150b5c9 100644 --- a/src/client/unittests/pytest/runner.ts +++ b/src/client/unittests/pytest/runner.ts @@ -4,15 +4,13 @@ import { createTemporaryFile } from '../../common/helpers'; import { TestsToRun, Tests } from '../common/contracts'; import { updateResults } from '../common/testUtils'; -import { CancellationToken, OutputChannel } from 'vscode'; +import { CancellationToken, OutputChannel, Uri } from 'vscode'; import { updateResultsFromXmlLogFile, PassCalculationFormulae } from '../common/xUnitParser'; import { run } from '../common/runner'; import { PythonSettings } from '../../common/configSettings'; import * as path from 'path'; import { launchDebugger } from '../common/debugLauncher'; -const pythonSettings = PythonSettings.getInstance(); - export function runTest(rootDirectory: string, tests: Tests, args: string[], testsToRun?: TestsToRun, token?: CancellationToken, outChannel?: OutputChannel, debug?: boolean): Promise { let testPaths = []; if (testsToRun && testsToRun.testFolder) { @@ -39,6 +37,7 @@ export function runTest(rootDirectory: string, tests: Tests, args: string[], tes args = args.filter(arg => arg.trim().startsWith('-')); } const testArgs = testPaths.concat(args, [`--junitxml=${xmlLogFile}`]); + const pythonSettings = PythonSettings.getInstance(Uri.file(rootDirectory)); if (debug) { const testLauncherFile = path.join(__dirname, '..', '..', '..', '..', 'pythonFiles', 'PythonTools', 'testlauncher.py'); const pytestlauncherargs = [rootDirectory, 'my_secret', pythonSettings.unitTest.debugPort.toString(), 'pytest']; diff --git a/src/client/unittests/unittest/collector.ts b/src/client/unittests/unittest/collector.ts index 91affb058814..49e34b4232f0 100644 --- a/src/client/unittests/unittest/collector.ts +++ b/src/client/unittests/unittest/collector.ts @@ -7,8 +7,6 @@ import * as path from 'path'; import { PythonSettings } from '../../common/configSettings'; import { OutputChannel } from 'vscode'; -const pythonSettings = PythonSettings.getInstance(); - export function discoverTests(rootDirectory: string, args: string[], token: vscode.CancellationToken, ignoreCache: boolean, outChannel: OutputChannel): Promise { let startDirectory = '.'; let pattern = 'test*.py'; @@ -73,7 +71,7 @@ for suite in suites._tests: }); } args = []; - return execPythonFile(pythonSettings.pythonPath, args.concat(['-c', pythonScript]), rootDirectory, true, null, token) + return execPythonFile(PythonSettings.getInstance(vscode.Uri.file(rootDirectory)).pythonPath, args.concat(['-c', pythonScript]), rootDirectory, true, null, token) .then(data => { outChannel.appendLine(data); processOutput(data); @@ -152,4 +150,4 @@ function addTestId(rootDirectory: string, testId: string, testFiles: TestFile[]) }; testSuite.functions.push(testFunction); -} \ No newline at end of file +} diff --git a/src/client/unittests/unittest/main.ts b/src/client/unittests/unittest/main.ts index 51cee1b32ac1..665406886146 100644 --- a/src/client/unittests/unittest/main.ts +++ b/src/client/unittests/unittest/main.ts @@ -6,8 +6,6 @@ import * as vscode from 'vscode'; import { discoverTests } from './collector'; import { BaseTestManager } from '../common/baseTestManager'; import { Product } from '../../common/installer'; - -const settings = PythonSettings.getInstance(); export class TestManager extends BaseTestManager { constructor(rootDirectory: string, outputChannel: vscode.OutputChannel) { super('unitest', Product.unittest, rootDirectory, outputChannel); @@ -15,11 +13,11 @@ export class TestManager extends BaseTestManager { configure() { } discoverTestsImpl(ignoreCache: boolean): Promise { - let args = settings.unitTest.unittestArgs.slice(0); + let args = this.settings.unitTest.unittestArgs.slice(0); return discoverTests(this.rootDirectory, args, this.cancellationToken, ignoreCache, this.outputChannel); } runTestImpl(tests: Tests, testsToRun?: TestsToRun, runFailedTests?: boolean, debug?: boolean): Promise { - let args = settings.unitTest.unittestArgs.slice(0); + let args = this.settings.unitTest.unittestArgs.slice(0); if (runFailedTests === true) { testsToRun = { testFile: [], testFolder: [], testSuite: [], testFunction: [] }; testsToRun.testFunction = tests.testFunctions.filter(fn => { diff --git a/src/client/unittests/unittest/runner.ts b/src/client/unittests/unittest/runner.ts index 1435dc8b3062..d6f98e8365aa 100644 --- a/src/client/unittests/unittest/runner.ts +++ b/src/client/unittests/unittest/runner.ts @@ -5,13 +5,11 @@ import * as path from 'path'; import { TestsToRun, Tests, TestStatus } from '../common/contracts'; import { updateResults } from '../common/testUtils'; import { BaseTestManager } from '../common/baseTestManager'; -import { CancellationToken, OutputChannel } from 'vscode'; +import { CancellationToken, OutputChannel, Uri } from 'vscode'; import { run } from '../common/runner'; import { Server } from './socketServer'; import { PythonSettings } from '../../common/configSettings'; import { launchDebugger } from '../common/debugLauncher'; - -const settings = PythonSettings.getInstance(); interface TestStatusMap { status: TestStatus; summaryProperty: string; @@ -96,7 +94,7 @@ export function runTest(testManager: BaseTestManager, rootDirectory: string, tes return launchDebugger(rootDirectory, [testLauncherFile].concat(testArgs), token, outChannel); } else { - return run(settings.pythonPath, [testLauncherFile].concat(testArgs), rootDirectory, token, outChannel); + return run(PythonSettings.getInstance(Uri.file(rootDirectory)).pythonPath, [testLauncherFile].concat(testArgs), rootDirectory, token, outChannel); } } diff --git a/src/test/autocomplete/base.test.ts b/src/test/autocomplete/base.test.ts index 83123b308f91..a1e3feeb9491 100644 --- a/src/test/autocomplete/base.test.ts +++ b/src/test/autocomplete/base.test.ts @@ -10,7 +10,7 @@ import { EOL } from 'os'; import * as vscode from 'vscode'; import * as path from 'path'; import * as settings from '../../client/common/configSettings'; -import { initialize, closeActiveWindows } from '../initialize'; +import { initialize, closeActiveWindows, initializeTest } from '../initialize'; import { execPythonFile } from '../../client/common/utils'; const pythonSettings = settings.PythonSettings.getInstance(); @@ -30,7 +30,7 @@ suite('Autocomplete', () => { let version = await execPythonFile(pythonSettings.pythonPath, ['--version'], __dirname, true); isPython3 = Promise.resolve(version.indexOf('3.') >= 0); }); - + setup(() => initializeTest()); suiteTeardown(() => closeActiveWindows()); teardown(() => closeActiveWindows()); diff --git a/src/test/autocomplete/pep484.test.ts b/src/test/autocomplete/pep484.test.ts index 6108b3e8c1b4..546c26d1253d 100644 --- a/src/test/autocomplete/pep484.test.ts +++ b/src/test/autocomplete/pep484.test.ts @@ -11,7 +11,7 @@ import * as vscode from 'vscode'; import * as path from 'path'; import * as settings from '../../client/common/configSettings'; import { execPythonFile } from '../../client/common/utils'; -import { initialize, closeActiveWindows } from '../initialize'; +import { initialize, closeActiveWindows, initializeTest } from '../initialize'; const pythonSettings = settings.PythonSettings.getInstance(); const autoCompPath = path.join(__dirname, '..', '..', '..', 'src', 'test', 'pythonFiles', 'autocomp'); @@ -24,6 +24,7 @@ suite('Autocomplete PEP 484', () => { const version = await execPythonFile(pythonSettings.pythonPath, ['--version'], __dirname, true); isPython3 = Promise.resolve(version.indexOf('3.') >= 0); }); + setup(() => initializeTest()); suiteTeardown(() => closeActiveWindows()); teardown(() => closeActiveWindows()); diff --git a/src/test/autocomplete/pep526.test.ts b/src/test/autocomplete/pep526.test.ts index 1d09d8168682..b7c4b37de08a 100644 --- a/src/test/autocomplete/pep526.test.ts +++ b/src/test/autocomplete/pep526.test.ts @@ -11,7 +11,7 @@ import * as vscode from 'vscode'; import * as path from 'path'; import * as settings from '../../client/common/configSettings'; import { execPythonFile } from '../../client/common/utils'; -import { initialize, closeActiveWindows } from '../initialize'; +import { initialize, closeActiveWindows, initializeTest } from '../initialize'; const pythonSettings = settings.PythonSettings.getInstance(); const autoCompPath = path.join(__dirname, '..', '..', '..', 'src', 'test', 'pythonFiles', 'autocomp'); @@ -24,6 +24,7 @@ suite('Autocomplete PEP 526', () => { const version = await execPythonFile(pythonSettings.pythonPath, ['--version'], __dirname, true); isPython3 = Promise.resolve(version.indexOf('3.') >= 0); }); + setup(() => initializeTest()); suiteTeardown(() => closeActiveWindows()); teardown(() => closeActiveWindows()); diff --git a/src/test/common.ts b/src/test/common.ts new file mode 100644 index 000000000000..cbab3da30f19 --- /dev/null +++ b/src/test/common.ts @@ -0,0 +1,38 @@ +import * as path from 'path'; +import { ConfigurationTarget, Uri, workspace } from 'vscode'; +import { PythonSettings } from '../client/common/configSettings'; + +const fileInNonRootWorkspace = path.join(__dirname, '..', '..', 'src', 'test', 'pythonFiles', 'dummy.py'); +export const rootWorkspaceUri = getWorkspaceRoot(); + +export type PythonSettingKeys = 'workspaceSymbols.enabled' | 'pythonPath' | + 'linting.lintOnSave' | 'linting.lintOnTextChange' | + 'linting.enabled' | 'linting.pylintEnabled' | + 'linting.flake8Enabled' | 'linting.pep8Enabled' | + 'linting.prospectorEnabled' | 'linting.pydocstyleEnabled' | + 'unitTest.nosetestArgs' | 'unitTest.pyTestArgs' | 'unitTest.unittestArgs' | + 'formatting.formatOnSave' | 'formatting.provider' | 'sortImports.args'; + + +export async function updateSetting(setting: PythonSettingKeys, value: any, resource: Uri, configTarget: ConfigurationTarget) { + let settings = workspace.getConfiguration('python', resource); + const currentValue = settings.inspect(setting); + if ((configTarget === ConfigurationTarget.Global && currentValue && currentValue.globalValue === value) || + (configTarget === ConfigurationTarget.Workspace && currentValue && currentValue.workspaceValue === value) || + (configTarget === ConfigurationTarget.WorkspaceFolder && currentValue && currentValue.workspaceFolderValue === value)) { + PythonSettings.dispose(); + return; + } + await settings.update(setting, value, configTarget); + PythonSettings.dispose(); +} + +function getWorkspaceRoot() { + if (!Array.isArray(workspace.workspaceFolders) || workspace.workspaceFolders.length === 0) { + return Uri.file(path.join(__dirname, '..', '..', 'src', 'test')); + } + if (workspace.workspaceFolders.length === 1) { + return workspace.workspaceFolders[0].uri; + } + return workspace.getWorkspaceFolder(Uri.file(fileInNonRootWorkspace)).uri; +} diff --git a/src/test/common/configSettings.multiroot.test.ts b/src/test/common/configSettings.multiroot.test.ts index 08e73f4f9908..08172cb10171 100644 --- a/src/test/common/configSettings.multiroot.test.ts +++ b/src/test/common/configSettings.multiroot.test.ts @@ -1,16 +1,17 @@ import * as assert from 'assert'; import * as path from 'path'; import { ConfigurationTarget, Uri, workspace } from 'vscode'; -import { initialize, closeActiveWindows } from '../initialize'; +import { initialize, closeActiveWindows, initializeTest } from '../initialize'; import { PythonSettings } from '../../client/common/configSettings'; -const multirootPath = path.join(__dirname, '..', '..', '..', 'src', 'test', 'multiRootWkspc'); +const multirootPath = path.join(__dirname, '..', '..', '..', 'src', 'testMultiRootWkspc'); suite('Multiroot Config Settings', () => { suiteSetup(async () => { await initialize(); await resetSettings(); }); + setup(() => initializeTest()); suiteTeardown(() => closeActiveWindows()); teardown(async () => { await resetSettings(); diff --git a/src/test/common/configSettings.test.ts b/src/test/common/configSettings.test.ts index 07cfe597033a..826ff1b9633d 100644 --- a/src/test/common/configSettings.test.ts +++ b/src/test/common/configSettings.test.ts @@ -14,17 +14,17 @@ import { initialize, IS_TRAVIS } from './../initialize'; import { PythonSettings } from '../../client/common/configSettings'; import { SystemVariables } from '../../client/common/systemVariables'; -const pythonSettings = PythonSettings.getInstance(); const workspaceRoot = path.join(__dirname, '..', '..', '..', 'src', 'test'); // Defines a Mocha test suite to group tests of similar kind together suite('Configuration Settings', () => { setup(() => initialize()); - + if (!IS_TRAVIS) { test('Check Values', done => { const systemVariables: SystemVariables = new SystemVariables(workspaceRoot); const pythonConfig = vscode.workspace.getConfiguration('python'); + const pythonSettings = PythonSettings.getInstance(vscode.Uri.file(workspaceRoot)); Object.keys(pythonSettings).forEach(key => { let settingValue = pythonConfig.get(key, 'Not a config'); if (settingValue === 'Not a config') { diff --git a/src/test/common/installer.test.ts b/src/test/common/installer.test.ts index 4f30f16e05bc..d49b32c0a066 100644 --- a/src/test/common/installer.test.ts +++ b/src/test/common/installer.test.ts @@ -1,5 +1,5 @@ import * as assert from 'assert'; -import { closeActiveWindows, IS_TRAVIS } from './../initialize'; +import { closeActiveWindows, IS_TRAVIS, initializeTest } from './../initialize'; import { MockOutputChannel } from './../mockClasses'; import { Installer, Product } from '../../client/common/installer'; import { EnumEx } from '../../client/common/enumUtils'; @@ -15,6 +15,7 @@ suite('Installer', () => { outputChannel = new MockOutputChannel('Installer'); installer = new Installer(outputChannel); }); + setup(() => initializeTest()); suiteTeardown(() => closeActiveWindows()); teardown(() => closeActiveWindows()); diff --git a/src/test/definitions/hover.test.ts b/src/test/definitions/hover.test.ts index 194d325edab6..07f06b8843ca 100644 --- a/src/test/definitions/hover.test.ts +++ b/src/test/definitions/hover.test.ts @@ -9,7 +9,7 @@ import { EOL } from 'os'; // as well as import your extension to test it import * as vscode from 'vscode'; import * as path from 'path'; -import { initialize, closeActiveWindows } from '../initialize'; +import { initialize, closeActiveWindows, initializeTest } from '../initialize'; import { normalizeMarkedString } from '../textUtils'; const autoCompPath = path.join(__dirname, '..', '..', '..', 'src', 'test', 'pythonFiles', 'autocomp'); @@ -23,6 +23,7 @@ const fileStringFormat = path.join(hoverPath, 'stringFormat.py'); suite('Hover Definition', () => { suiteSetup(() => initialize()); + setup(() => initializeTest()); suiteTeardown(() => closeActiveWindows()); teardown(() => closeActiveWindows()); diff --git a/src/test/format/extension.format.test.ts b/src/test/format/extension.format.test.ts index 986d64e976a9..1f47e8ea247d 100644 --- a/src/test/format/extension.format.test.ts +++ b/src/test/format/extension.format.test.ts @@ -1,3 +1,4 @@ +import { updateSetting } from '../common'; // Note: This example test is leveraging the Mocha test framework. // Please refer to their documentation on https://mochajs.org/ for help. @@ -10,16 +11,14 @@ import * as assert from 'assert'; // as well as import your extension to test it import * as vscode from 'vscode'; import * as path from 'path'; -import * as settings from '../../client/common/configSettings'; import * as fs from 'fs-extra'; import { EOL } from 'os'; +import { PythonSettings } from '../../client/common/configSettings'; import { AutoPep8Formatter } from '../../client/formatters/autoPep8Formatter'; -import { initialize, IS_TRAVIS, closeActiveWindows } from '../initialize'; +import { initialize, IS_TRAVIS, closeActiveWindows, initializeTest } from '../initialize'; import { YapfFormatter } from '../../client/formatters/yapfFormatter'; import { execPythonFile } from '../../client/common/utils'; -const pythonSettings = settings.PythonSettings.getInstance(); - const ch = vscode.window.createOutputChannel('Tests'); const pythoFilesPath = path.join(__dirname, '..', '..', '..', 'src', 'test', 'pythonFiles', 'formatting'); const workspaceRootPath = path.join(__dirname, '..', '..', '..', 'src', 'test'); @@ -47,13 +46,18 @@ suite('Formatting', () => { formattedAutoPep8 = formattedResults[1]; }).then(() => { }); }); - suiteTeardown(() => { + setup(async () => { + await initializeTest(); + updateSetting('formatting.formatOnSave', false, vscode.Uri.file(pythoFilesPath), vscode.ConfigurationTarget.Workspace) + }); + suiteTeardown(async () => { [autoPep8FileToFormat, autoPep8FileToAutoFormat, yapfFileToFormat, yapfFileToAutoFormat].forEach(file => { if (fs.existsSync(file)) { fs.unlinkSync(file); } }); - return closeActiveWindows(); + await updateSetting('formatting.formatOnSave', false, vscode.Uri.file(pythoFilesPath), vscode.ConfigurationTarget.Workspace) + await closeActiveWindows(); }); teardown(() => closeActiveWindows()); @@ -85,30 +89,23 @@ suite('Formatting', () => { testFormatting(new YapfFormatter(ch), formattedYapf, yapfFileToFormat).then(done, done); }); - function testAutoFormatting(formatter: string, formattedContents: string, fileToFormat: string): PromiseLike { - let textDocument: vscode.TextDocument; - pythonSettings.formatting.formatOnSave = true; - pythonSettings.formatting.provider = formatter; - return vscode.workspace.openTextDocument(fileToFormat).then(document => { - textDocument = document; - return vscode.window.showTextDocument(textDocument); - }).then(editor => { - assert(vscode.window.activeTextEditor, 'No active editor'); - return editor.edit(editBuilder => { - editBuilder.insert(new vscode.Position(0, 0), '#\n'); - }); - }).then(edited => { - return textDocument.save(); - }).then(saved => { - return new Promise((resolve, reject) => { - setTimeout(() => { - resolve(); - }, 5000); - }); - }).then(() => { - const text = textDocument.getText(); - assert.equal(text === formattedContents, true, 'Formatted contents are not the same'); + async function testAutoFormatting(formatter: string, formattedContents: string, fileToFormat: string): Promise { + await updateSetting('formatting.formatOnSave', true, vscode.Uri.file(fileToFormat), vscode.ConfigurationTarget.Workspace); + await updateSetting('formatting.provider', formatter, vscode.Uri.file(fileToFormat), vscode.ConfigurationTarget.Workspace); + const textDocument = await vscode.workspace.openTextDocument(fileToFormat); + const editor = await vscode.window.showTextDocument(textDocument); + assert(vscode.window.activeTextEditor, 'No active editor'); + const edited = await editor.edit(editBuilder => { + editBuilder.insert(new vscode.Position(0, 0), '#\n'); + }); + const saved = await textDocument.save(); + await new Promise((resolve, reject) => { + setTimeout(() => { + resolve(); + }, 5000); }); + const text = textDocument.getText(); + assert.equal(text === formattedContents, true, 'Formatted contents are not the same'); } test('AutoPep8 autoformat on save', done => { testAutoFormatting('autopep8', `#${EOL}` + formattedAutoPep8, autoPep8FileToAutoFormat).then(done, done); diff --git a/src/test/format/extension.onTypeFormat.test.ts b/src/test/format/extension.onTypeFormat.test.ts index 4ede98a39bac..097922e9010e 100644 --- a/src/test/format/extension.onTypeFormat.test.ts +++ b/src/test/format/extension.onTypeFormat.test.ts @@ -11,7 +11,7 @@ import * as assert from 'assert'; import * as vscode from 'vscode'; import * as path from 'path'; import * as fs from 'fs-extra'; -import { initialize, closeActiveWindows } from '../initialize'; +import { initialize, closeActiveWindows, initializeTest } from '../initialize'; import { BlockFormatProviders } from '../../client/typeFormatters/blockFormatProvider'; const srcPythoFilesPath = path.join(__dirname, '..', '..', '..', 'src', 'test', 'pythonFiles', 'typeFormatFiles'); @@ -676,6 +676,7 @@ suite('Else blocks with indentation of Tab', () => { fs.copySync(path.join(srcPythoFilesPath, file), targetFile); }); }); + setup(() => initializeTest()); suiteTeardown(() => closeActiveWindows()); teardown(() => closeActiveWindows()); diff --git a/src/test/format/extension.sort.test.ts b/src/test/format/extension.sort.test.ts index 15b1f0898e57..31ddcf26b1f4 100644 --- a/src/test/format/extension.sort.test.ts +++ b/src/test/format/extension.sort.test.ts @@ -1,3 +1,4 @@ +import { updateSetting } from '../common'; // Note: This example test is leveraging the Mocha test framework. // Please refer to their documentation on https://mochajs.org/ for help. @@ -14,9 +15,7 @@ import * as settings from '../../client/common/configSettings'; import * as fs from 'fs'; import { EOL } from 'os'; import { PythonImportSortProvider } from '../../client/providers/importSortProvider'; -import { initialize, IS_TRAVIS, closeActiveWindows } from '../initialize'; - -const pythonSettings = settings.PythonSettings.getInstance(); +import { initialize, IS_TRAVIS, closeActiveWindows, initializeTest } from '../initialize'; const sortingPath = path.join(__dirname, '..', '..', '..', 'src', 'test', 'pythonFiles', 'sorting'); const fileToFormatWithoutConfig = path.join(sortingPath, 'noconfig', 'before.py'); @@ -29,18 +28,20 @@ const extensionDir = path.join(__dirname, '..', '..', '..'); suite('Sorting', () => { suiteSetup(() => initialize()); - suiteTeardown(() => { + setup(() => initializeTest()); + suiteTeardown(async () => { fs.writeFileSync(fileToFormatWithConfig, fs.readFileSync(originalFileToFormatWithConfig)); fs.writeFileSync(fileToFormatWithConfig1, fs.readFileSync(originalFileToFormatWithConfig1)); fs.writeFileSync(fileToFormatWithoutConfig, fs.readFileSync(originalFileToFormatWithoutConfig)); - return closeActiveWindows(); + await updateSetting('sortImports.args', [], vscode.Uri.file(sortingPath), vscode.ConfigurationTarget.Workspace); + await closeActiveWindows(); }); - setup(() => { - pythonSettings.sortImports.args = []; + setup(async () => { fs.writeFileSync(fileToFormatWithConfig, fs.readFileSync(originalFileToFormatWithConfig)); fs.writeFileSync(fileToFormatWithoutConfig, fs.readFileSync(originalFileToFormatWithoutConfig)); fs.writeFileSync(fileToFormatWithConfig1, fs.readFileSync(originalFileToFormatWithConfig1)); - return closeActiveWindows(); + await updateSetting('sortImports.args', [], vscode.Uri.file(sortingPath), vscode.ConfigurationTarget.Workspace); + await closeActiveWindows(); }); test('Without Config', done => { @@ -118,8 +119,36 @@ suite('Sorting', () => { test('With Changes and Config in Args', done => { let textEditor: vscode.TextEditor; let textDocument: vscode.TextDocument; - pythonSettings.sortImports.args = ['-sp', path.join(sortingPath, 'withconfig')]; - vscode.workspace.openTextDocument(fileToFormatWithConfig).then(document => { + updateSetting('sortImports.args', ['-sp', path.join(sortingPath, 'withconfig')], vscode.Uri.file(sortingPath), vscode.ConfigurationTarget.Workspace) + .then(() => vscode.workspace.openTextDocument(fileToFormatWithConfig)) + .then(document => { + textDocument = document; + return vscode.window.showTextDocument(textDocument); + }).then(editor => { + assert(vscode.window.activeTextEditor, 'No active editor'); + textEditor = editor; + return editor.edit(editor => { + editor.insert(new vscode.Position(0, 0), 'from third_party import lib0' + EOL); + }); + }).then(() => { + const sorter = new PythonImportSortProvider(); + return sorter.sortImports(extensionDir, textDocument); + }).then(edits => { + const newValue = `from third_party import lib2${EOL}from third_party import lib3${EOL}from third_party import lib4${EOL}from third_party import lib5${EOL}from third_party import lib6${EOL}from third_party import lib7${EOL}from third_party import lib8${EOL}from third_party import lib9${EOL}`; + assert.equal(edits.length, 1, 'Incorrect number of edits'); + assert.equal(edits[0].newText, newValue, 'New Value is not the same'); + assert.equal(`${edits[0].range.start.line},${edits[0].range.start.character}`, '1,0', 'Start position is not the same'); + assert.equal(`${edits[0].range.end.line},${edits[0].range.end.character}`, '4,0', 'End position is not the same'); + }).then(done, done); + }); + } + test('With Changes and Config in Args (via Command)', done => { + let textEditor: vscode.TextEditor; + let textDocument: vscode.TextDocument; + let originalContent = ''; + updateSetting('sortImports.args', ['-sp', path.join(sortingPath, 'withconfig')], vscode.Uri.file(sortingPath), vscode.ConfigurationTarget.Workspace) + .then(() => vscode.workspace.openTextDocument(fileToFormatWithConfig)) + .then(document => { textDocument = document; return vscode.window.showTextDocument(textDocument); }).then(editor => { @@ -129,36 +158,10 @@ suite('Sorting', () => { editor.insert(new vscode.Position(0, 0), 'from third_party import lib0' + EOL); }); }).then(() => { - const sorter = new PythonImportSortProvider(); - return sorter.sortImports(extensionDir, textDocument); + originalContent = textDocument.getText(); + return vscode.commands.executeCommand('python.sortImports'); }).then(edits => { - const newValue = `from third_party import lib2${EOL}from third_party import lib3${EOL}from third_party import lib4${EOL}from third_party import lib5${EOL}from third_party import lib6${EOL}from third_party import lib7${EOL}from third_party import lib8${EOL}from third_party import lib9${EOL}`; - assert.equal(edits.length, 1, 'Incorrect number of edits'); - assert.equal(edits[0].newText, newValue, 'New Value is not the same'); - assert.equal(`${edits[0].range.start.line},${edits[0].range.start.character}`, '1,0', 'Start position is not the same'); - assert.equal(`${edits[0].range.end.line},${edits[0].range.end.character}`, '4,0', 'End position is not the same'); + assert.notEqual(originalContent, textDocument.getText(), 'Contents have not changed'); }).then(done, done); - }); - } - test('With Changes and Config in Args (via Command)', done => { - let textEditor: vscode.TextEditor; - let textDocument: vscode.TextDocument; - let originalContent = ''; - pythonSettings.sortImports.args = ['-sp', path.join(sortingPath, 'withconfig')]; - vscode.workspace.openTextDocument(fileToFormatWithConfig).then(document => { - textDocument = document; - return vscode.window.showTextDocument(textDocument); - }).then(editor => { - assert(vscode.window.activeTextEditor, 'No active editor'); - textEditor = editor; - return editor.edit(editor => { - editor.insert(new vscode.Position(0, 0), 'from third_party import lib0' + EOL); - }); - }).then(() => { - originalContent = textDocument.getText(); - return vscode.commands.executeCommand('python.sortImports'); - }).then(edits => { - assert.notEqual(originalContent, textDocument.getText(), 'Contents have not changed'); - }).then(done, done); }); }); diff --git a/src/test/index.ts b/src/test/index.ts index e5fe465f9647..defee3a510e4 100644 --- a/src/test/index.ts +++ b/src/test/index.ts @@ -1,4 +1,4 @@ -import { initializePython, isMultitrootTest } from './initialize'; +import { initializePython, IS_MULTI_ROOT_TEST } from './initialize'; // // PLEASE DO NOT MODIFY / DELETE UNLESS YOU KNOW WHAT YOU ARE DOING // @@ -12,7 +12,7 @@ import { initializePython, isMultitrootTest } from './initialize'; // a possible error to the callback or null if none. const testRunner = require('vscode/lib/testrunner'); -const invert = isMultitrootTest() ? undefined : 'invert'; +const invert = IS_MULTI_ROOT_TEST ? undefined : 'invert'; // You can directly control Mocha options by uncommenting the following lines // See https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options for more info @@ -20,10 +20,8 @@ testRunner.configure({ ui: 'tdd', // the TDD UI is being used in extension.test.ts (suite, test, etc.) useColors: true, // colored output from test results timeout: 25000, - grep : 'Multiroot', + grep: 'Multiroot', invert }); -initializePython(); - module.exports = testRunner; diff --git a/src/test/initialize.ts b/src/test/initialize.ts index 97b22674894f..91721a2b44f5 100644 --- a/src/test/initialize.ts +++ b/src/test/initialize.ts @@ -3,25 +3,39 @@ // Please refer to their documentation on https://mochajs.org/ for help. // -//First thing to be executed -process.env['PYTHON_DONJAYAMANNE_TEST'] = "1"; - -// The module 'assert' provides assertion methods from node -import * as assert from "assert"; -import * as fs from 'fs'; - // You can import and use all API from the 'vscode' module // as well as import your extension to test it -import * as vscode from "vscode"; -import * as path from "path"; -let dummyPythonFile = path.join(__dirname, "..", "..", "src", "test", "pythonFiles", "dummy.py"); +import * as assert from 'assert'; +import * as fs from 'fs'; +import * as vscode from 'vscode'; +import * as path from 'path'; +let dummyPythonFile = path.join(__dirname, '..', '..', 'src', 'test', 'pythonFiles', 'dummy.py'); -export function initialize(): Promise { +//First thing to be executed +process.env['PYTHON_DONJAYAMANNE_TEST'] = '1'; + +let configSettings: any = undefined; +export async function initialize(): Promise { + await initializePython(); + if (!configSettings) { + configSettings = await require('../client/common/configSettings'); + } + // Dispose any cached python settings (used only in test env) + configSettings.PythonSettings.dispose(); // Opening a python file activates the extension - return new Promise((resolve, reject) => { + return await new Promise((resolve, reject) => { vscode.workspace.openTextDocument(dummyPythonFile).then(() => resolve(), reject); }); } +export async function initializeTest(): Promise { + await initializePython(); + await closeActiveWindows(); + if (!configSettings) { + configSettings = await require('../client/common/configSettings'); + } + // Dispose any cached python settings (used only in test env) + configSettings.PythonSettings.dispose(); +} export async function wait(timeoutMilliseconds: number) { return new Promise(resolve => { @@ -64,32 +78,29 @@ export async function closeActiveWindows(): Promise { }); } -export const IS_TRAVIS = (process.env['TRAVIS'] + '') === 'true'; -export const TEST_TIMEOUT = 25000; function getPythonPath(): string { - const pythonPaths = ['/home/travis/virtualenv/python3.5.2/bin/python', - '/xUsers/travis/.pyenv/versions/3.5.1/envs/MYVERSION/bin/python', - '/xUsers/donjayamanne/Projects/PythonEnvs/p361/bin/python', - 'cC:/Users/dojayama/nine/python.exe', - 'C:/Development/PythonEnvs/p27/scripts/python.exe', - '/Users/donjayamanne/Projects/PythonEnvs/p27/bin/python']; - for (let counter = 0; counter < pythonPaths.length; counter++) { - if (fs.existsSync(pythonPaths[counter])) { - return pythonPaths[counter]; - } + if (process.env.TRAVIS_PYTHON_PATH && fs.existsSync(process.env.TRAVIS_PYTHON_PATH)) { + return process.env.TRAVIS_PYTHON_PATH; } return 'python'; } +function isMultitrootTest() { + return Array.isArray(vscode.workspace.workspaceFolders) && vscode.workspace.workspaceFolders.length > 1; +} + const PYTHON_PATH = getPythonPath(); +export const IS_TRAVIS = (process.env['TRAVIS'] + '') === 'true'; +export const TEST_TIMEOUT = 25000; +export const IS_MULTI_ROOT_TEST = isMultitrootTest(); // Ability to use custom python environments for testing -export function initializePython() { +export async function initializePython() { const pythonConfig = vscode.workspace.getConfiguration('python'); - pythonConfig.update('pythonPath', PYTHON_PATH); + const value = pythonConfig.inspect('pythonPath'); + if (value && value.workspaceValue !== PYTHON_PATH) { + return await pythonConfig.update('pythonPath', PYTHON_PATH, vscode.ConfigurationTarget.Workspace); + } } -export function isMultitrootTest() { - return Array.isArray(vscode.workspace.workspaceFolders) && vscode.workspace.workspaceFolders.length > 1; -} diff --git a/src/test/interpreters/condaEnvFileService.test.ts b/src/test/interpreters/condaEnvFileService.test.ts index 9778179149c8..26bd45c9928d 100644 --- a/src/test/interpreters/condaEnvFileService.test.ts +++ b/src/test/interpreters/condaEnvFileService.test.ts @@ -2,7 +2,7 @@ import * as assert from 'assert'; import * as path from 'path'; import * as fs from 'fs-extra'; import { EOL } from 'os'; -import { initialize } from '../initialize'; +import { initialize, initializeTest } from '../initialize'; import { IS_WINDOWS } from '../../client/common/utils'; import { MockInterpreterVersionProvider } from './mocks'; import { CondaEnvFileService } from '../../client/interpreter/locators/services/condaEnvFileService'; @@ -18,6 +18,7 @@ const environmentsFilePath = path.join(environmentsPath, 'environments.txt'); suite('Interpreters from Conda Environments Text File', () => { suiteSetup(() => initialize()); + setup(() => initializeTest()); suiteTeardown(async () => { // Clear the file so we don't get unwanted changes prompting for a checkin of this file await updateEnvWithInterpreters([]); diff --git a/src/test/interpreters/condaEnvService.test.ts b/src/test/interpreters/condaEnvService.test.ts index 0441b93cd7f4..823f773ede6c 100644 --- a/src/test/interpreters/condaEnvService.test.ts +++ b/src/test/interpreters/condaEnvService.test.ts @@ -1,26 +1,18 @@ import * as assert from 'assert'; import * as path from 'path'; -import * as settings from '../../client/common/configSettings'; -import { initialize } from '../initialize'; +import { PythonSettings } from '../../client/common/configSettings'; +import { initialize, initializeTest } from '../initialize'; import { IS_WINDOWS } from '../../client/common/utils'; import { CondaEnvService } from '../../client/interpreter/locators/services/condaEnvService'; import { AnacondaCompanyName } from '../../client/interpreter/locators/services/conda'; import { MockProvider } from './mocks'; import { PythonInterpreter } from '../../client/interpreter/contracts'; -const pythonSettings = settings.PythonSettings.getInstance(); const environmentsPath = path.join(__dirname, '..', '..', '..', 'src', 'test', 'pythonFiles', 'environments'); -let originalPythonPath; suite('Interpreters from Conda Environments', () => { - suiteSetup(() => { - originalPythonPath = pythonSettings.pythonPath; - return initialize(); - }); - teardown(() => { - pythonSettings.pythonPath = originalPythonPath; - }); - + suiteSetup(() => initialize()); + setup(() => initializeTest()); test('Must return an empty list for empty json', async () => { const condaProvider = new CondaEnvService(); const interpreters = await condaProvider.parseCondaInfo({} as any) @@ -113,7 +105,7 @@ suite('Interpreters from Conda Environments', () => { test('Must detect conda environments from a list', async () => { const registryInterpreters: PythonInterpreter[] = [ { displayName: 'One', path: 'c:/path1/one.exe', companyDisplayName: 'One 1' }, - { displayName: 'Two', path: pythonSettings.pythonPath, companyDisplayName: 'Two 2' }, + { displayName: 'Two', path: PythonSettings.getInstance().pythonPath, companyDisplayName: 'Two 2' }, { displayName: 'Three', path: path.join(environmentsPath, 'path1', 'one.exe'), companyDisplayName: 'Three 3' }, { displayName: 'Anaconda', path: path.join(environmentsPath, 'path2', 'one.exe'), companyDisplayName: 'Three 3' }, { displayName: 'xAnaconda', path: path.join(environmentsPath, 'path2', 'one.exe'), companyDisplayName: 'Three 3' }, @@ -134,7 +126,7 @@ suite('Interpreters from Conda Environments', () => { test('Correctly identifies latest version when major version is different', async () => { const registryInterpreters: PythonInterpreter[] = [ { displayName: 'One', path: path.join(environmentsPath, 'path1', 'one.exe'), companyDisplayName: 'One 1', version: '1' }, - { displayName: 'Two', path: pythonSettings.pythonPath, companyDisplayName: 'Two 2', version: '3.1.3' }, + { displayName: 'Two', path: PythonSettings.getInstance().pythonPath, companyDisplayName: 'Two 2', version: '3.1.3' }, { displayName: 'Three', path: path.join(environmentsPath, 'path2', 'one.exe'), companyDisplayName: 'Three 3', version: '2.10.1' }, { displayName: 'Four', path: path.join(environmentsPath, 'conda', 'envs', 'scipy'), companyDisplayName: 'Three 3', version: null }, { displayName: 'Five', path: path.join(environmentsPath, 'conda', 'envs', 'numpy'), companyDisplayName: 'Three 3', version: undefined }, @@ -149,7 +141,7 @@ suite('Interpreters from Conda Environments', () => { test('Correctly identifies latest version when major version is same', async () => { const registryInterpreters: PythonInterpreter[] = [ { displayName: 'One', path: path.join(environmentsPath, 'path1', 'one.exe'), companyDisplayName: 'One 1', version: '1' }, - { displayName: 'Two', path: pythonSettings.pythonPath, companyDisplayName: 'Two 2', version: '2.11.3' }, + { displayName: 'Two', path: PythonSettings.getInstance().pythonPath, companyDisplayName: 'Two 2', version: '2.11.3' }, { displayName: 'Three', path: path.join(environmentsPath, 'path2', 'one.exe'), companyDisplayName: 'Three 3', version: '2.10.1' }, { displayName: 'Four', path: path.join(environmentsPath, 'conda', 'envs', 'scipy'), companyDisplayName: 'Three 3', version: null }, { displayName: 'Five', path: path.join(environmentsPath, 'conda', 'envs', 'numpy'), companyDisplayName: 'Three 3', version: undefined }, diff --git a/src/test/interpreters/display.test.ts b/src/test/interpreters/display.test.ts index 2f38d272125a..8c5b3b517c2b 100644 --- a/src/test/interpreters/display.test.ts +++ b/src/test/interpreters/display.test.ts @@ -1,9 +1,8 @@ +import { PythonSettings } from '../../client/common/configSettings'; import * as assert from 'assert'; import * as child_process from 'child_process'; -import * as settings from '../../client/common/configSettings'; import * as path from 'path'; -import * as utils from '../../client/common/utils'; -import { initialize } from '../initialize'; +import { closeActiveWindows, initialize, initializeTest } from '../initialize'; import { MockStatusBarItem } from '../mockClasses'; import { MockInterpreterVersionProvider } from './mocks'; import { InterpreterDisplay } from '../../client/interpreter/display'; @@ -11,17 +10,15 @@ import { MockProvider, MockVirtualEnv } from './mocks'; import { EOL } from 'os'; import { VirtualEnvironmentManager } from '../../client/interpreter/virtualEnvs'; import { getFirstNonEmptyLineFromMultilineString } from '../../client/interpreter/helpers'; - -let pythonSettings = settings.PythonSettings.getInstance(); -let originalPythonPath; +import { rootWorkspaceUri, updateSetting } from '../common'; +import { ConfigurationTarget } from 'vscode'; suite('Interpreters Display', () => { - suiteSetup(() => { - originalPythonPath = pythonSettings.pythonPath; - return initialize(); - }); - teardown(() => { - pythonSettings.pythonPath = originalPythonPath; + suiteSetup(() => initialize()); + setup(() => initializeTest()); + teardown(async () => { + await initialize(); + await closeActiveWindows(); }); test('Must have command name', () => { @@ -59,7 +56,8 @@ suite('Interpreters Display', () => { const displayNameProvider = new MockInterpreterVersionProvider(displayName, true); const display = new InterpreterDisplay(statusBar, provider, new VirtualEnvironmentManager([]), displayNameProvider); // Change interpreter to an invalid value - const pythonPath = pythonSettings.pythonPath = 'c:/some/unknonw/Python Interpreter.exe'; + const pythonPath = 'UnknownInterpreter'; + await updateSetting('pythonPath', pythonPath, rootWorkspaceUri, ConfigurationTarget.Workspace); await display.refresh(); const defaultDisplayName = `${path.basename(pythonPath)} [Environment]`; @@ -67,10 +65,10 @@ suite('Interpreters Display', () => { }); test('Must get display name from a list of interpreters', async () => { const pythonPath = await new Promise(resolve => { - child_process.execFile(pythonSettings.pythonPath, ["-c", "import sys;print(sys.executable)"], (_, stdout) => { + child_process.execFile(PythonSettings.getInstance().pythonPath, ["-c", "import sys;print(sys.executable)"], (_, stdout) => { resolve(getFirstNonEmptyLineFromMultilineString(stdout)); }); - }).then(value => value.length === 0 ? pythonSettings.pythonPath : value); + }).then(value => value.length === 0 ? PythonSettings.getInstance().pythonPath : value); const statusBar = new MockStatusBarItem(); const interpreters = [ { displayName: 'One', path: 'c:/path1/one.exe', type: 'One 1' }, @@ -87,10 +85,10 @@ suite('Interpreters Display', () => { }); test('Must suffix tooltip with the companyDisplayName of interpreter', async () => { const pythonPath = await new Promise(resolve => { - child_process.execFile(pythonSettings.pythonPath, ["-c", "import sys;print(sys.executable)"], (_, stdout) => { + child_process.execFile(PythonSettings.getInstance().pythonPath, ["-c", "import sys;print(sys.executable)"], (_, stdout) => { resolve(getFirstNonEmptyLineFromMultilineString(stdout)); }); - }).then(value => value.length === 0 ? pythonSettings.pythonPath : value); + }).then(value => value.length === 0 ? PythonSettings.getInstance().pythonPath : value); const statusBar = new MockStatusBarItem(); const interpreters = [ @@ -117,19 +115,10 @@ suite('Interpreters Display', () => { const displayNameProvider = new MockInterpreterVersionProvider('', true); const display = new InterpreterDisplay(statusBar, provider, new VirtualEnvironmentManager([]), displayNameProvider); // Change interpreter to an invalid value - pythonSettings.pythonPath = 'c:/some/unknonw/Python Interpreter.exe'; + const pythonPath = 'UnknownInterpreter'; + await updateSetting('pythonPath', pythonPath, rootWorkspaceUri, ConfigurationTarget.Workspace); await display.refresh(); assert.equal(statusBar.text, '$(alert) Select Python Environment', 'Incorrect display name'); }); }); - -async function getInterpreterDisplayName(pythonPath: string, defaultValue: string) { - return utils.execPythonFile(pythonPath, ['--version'], __dirname, true) - .then(version => { - version = version.split(/\r?\n/g).map(line => line.trim()).filter(line => line.length > 0).join(''); - return version.length > 0 ? version : defaultValue; - }) - .catch(() => defaultValue); -} - diff --git a/src/test/interpreters/windowsRegistryService.test.ts b/src/test/interpreters/windowsRegistryService.test.ts index 71a68c62f4bc..aedad057a4d0 100644 --- a/src/test/interpreters/windowsRegistryService.test.ts +++ b/src/test/interpreters/windowsRegistryService.test.ts @@ -1,25 +1,16 @@ import * as assert from 'assert'; import * as path from 'path'; -import * as settings from '../../client/common/configSettings'; -import { initialize } from '../initialize'; +import { initialize, initializeTest } from '../initialize'; import { IS_WINDOWS } from '../../client/debugger/Common/Utils'; import { WindowsRegistryService } from '../../client/interpreter/locators/services/windowsRegistryService'; import { MockRegistry } from './mocks'; import { Architecture, Hive } from '../../client/common/registry'; -const pythonSettings = settings.PythonSettings.getInstance(); const environmentsPath = path.join(__dirname, '..', '..', '..', 'src', 'test', 'pythonFiles', 'environments'); -let originalPythonPath; suite('Interpreters from Windows Registry', () => { - suiteSetup(() => { - originalPythonPath = pythonSettings.pythonPath; - return initialize(); - }); - teardown(() => { - pythonSettings.pythonPath = originalPythonPath; - }); - + suiteSetup(() => initialize()); + setup(() => initializeTest()); if (IS_WINDOWS) { test('Must return an empty list (x86)', async () => { const registry = new MockRegistry([], []); diff --git a/src/test/jupyter/jupyter.codeHelper.test.ts b/src/test/jupyter/jupyter.codeHelper.test.ts index b0a25bb906c3..60643f2d6b2b 100644 --- a/src/test/jupyter/jupyter.codeHelper.test.ts +++ b/src/test/jupyter/jupyter.codeHelper.test.ts @@ -1,7 +1,7 @@ import * as assert from 'assert'; import * as vscode from 'vscode'; import * as path from 'path'; -import { initialize, closeActiveWindows } from './../initialize'; +import { initialize, closeActiveWindows, initializeTest } from './../initialize'; import { CodeHelper } from '../../client/jupyter/common/codeHelper'; import { JupyterCodeLensProvider } from '../../client/jupyter/editorIntegration/codeLensProvider'; @@ -9,8 +9,7 @@ const FILE_WITH_CELLS = path.join(__dirname, '..', '..', '..', 'src', 'test', 'p suite('Jupyter Code Helper', () => { suiteSetup(() => initialize()); - - setup(() => closeActiveWindows()); + setup(() => initializeTest()); teardown(() => closeActiveWindows()); const codeLensProvider = new JupyterCodeLensProvider(); const codeHelper = new CodeHelper(codeLensProvider); diff --git a/src/test/jupyter/jupyterClient.test.ts b/src/test/jupyter/jupyterClient.test.ts index 5250443df1be..c74d027db47c 100644 --- a/src/test/jupyter/jupyterClient.test.ts +++ b/src/test/jupyter/jupyterClient.test.ts @@ -1,6 +1,6 @@ import * as assert from 'assert'; import { MockOutputChannel } from './mocks'; -import { initialize } from './../initialize'; +import { initialize, initializeTest } from './../initialize'; import { JupyterClientAdapter } from '../../client/jupyter/jupyter_client/main'; import { KernelRestartedError, KernelShutdownError } from '../../client/jupyter/common/errors'; import { createDeferred } from '../../client/common/helpers'; @@ -13,6 +13,7 @@ suite('JupyterClient', () => { process.env['DEBUG_DJAYAMANNE_IPYTHON'] = '1'; output = new MockOutputChannel('Jupyter'); jupyter = new JupyterClientAdapter(output, __dirname); + return initializeTest(); }); teardown(() => { process.env['PYTHON_DONJAYAMANNE_TEST'] = '1'; diff --git a/src/test/jupyter/jupyterKernel.test.ts b/src/test/jupyter/jupyterKernel.test.ts index 3893178d74ec..fddedbe166c1 100644 --- a/src/test/jupyter/jupyterKernel.test.ts +++ b/src/test/jupyter/jupyterKernel.test.ts @@ -1,6 +1,6 @@ import * as assert from 'assert'; import { MockOutputChannel } from './mocks'; -import { initialize } from './../initialize'; +import { initialize, initializeTest } from './../initialize'; import { JupyterClientAdapter } from '../../client/jupyter/jupyter_client/main'; import { KernelShutdownError } from '../../client/jupyter/common/errors'; import { createDeferred } from '../../client/common/helpers'; @@ -17,6 +17,7 @@ suite('Jupyter Kernel', () => { disposables.push(output); jupyter = new JupyterClientAdapter(output, __dirname); disposables.push(jupyter); + return initializeTest(); }); teardown(() => { process.env['PYTHON_DONJAYAMANNE_TEST'] = '1'; diff --git a/src/test/jupyter/jupyterKernelManager.test.ts b/src/test/jupyter/jupyterKernelManager.test.ts index b4581e6889c1..f4c5e9f51c4f 100644 --- a/src/test/jupyter/jupyterKernelManager.test.ts +++ b/src/test/jupyter/jupyterKernelManager.test.ts @@ -1,7 +1,7 @@ import * as assert from 'assert'; import * as vscode from 'vscode'; import { MockOutputChannel } from './mocks'; -import { initialize } from './../initialize'; +import { initialize, initializeTest } from './../initialize'; import { JupyterClientAdapter } from '../../client/jupyter/jupyter_client/main'; import { KernelManagerImpl } from '../../client/jupyter/kernel-manager'; @@ -17,6 +17,7 @@ suite('Kernel Manager', () => { disposables.push(jupyter); // Hack hack hack hack hack :) cmds.registerCommand = function () { }; + return initializeTest(); }); teardown(() => { process.env['PYTHON_DONJAYAMANNE_TEST'] = '1'; diff --git a/src/test/linters/lint.multiroot.test.ts b/src/test/linters/lint.multiroot.test.ts index e038ac9a1339..17089260ab49 100644 --- a/src/test/linters/lint.multiroot.test.ts +++ b/src/test/linters/lint.multiroot.test.ts @@ -3,18 +3,16 @@ import * as path from 'path'; import * as baseLinter from '../../client/linters/baseLinter'; import * as pyLint from '../../client/linters/pylint'; import * as flake8 from '../../client/linters/flake8'; -import { PythonSettings } from '../../client/common/configSettings'; import { CancellationTokenSource, ConfigurationTarget, Uri, window, workspace } from 'vscode'; -import { initialize, closeActiveWindows } from '../initialize'; +import { closeActiveWindows, initialize, initializeTest } from '../initialize'; import { MockOutputChannel } from '../mockClasses'; +import { PythonSettings } from '../../client/common/configSettings'; -const multirootPath = path.join(__dirname, '..', '..', '..', 'src', 'test', 'multiRootWkspc'); +const multirootPath = path.join(__dirname, '..', '..', '..', 'src', 'testMultiRootWkspc'); suite('Multiroot Linting', () => { - suiteSetup(async () => { - await initialize(); - PythonSettings.dispose(); - }); + suiteSetup(() => initialize()); + setup(() => initializeTest()); suiteTeardown(() => closeActiveWindows()); teardown(async () => { await closeActiveWindows(); diff --git a/src/test/linters/lint.test.ts b/src/test/linters/lint.test.ts index bf96de28cfc3..c5d06918b801 100644 --- a/src/test/linters/lint.test.ts +++ b/src/test/linters/lint.test.ts @@ -1,11 +1,4 @@ -// -// Note: This example test is leveraging the Mocha test framework. -// Please refer to their documentation on https://mochajs.org/ for help. -// The module \'assert\' provides assertion methods from node import * as assert from 'assert'; - -// You can import and use all API from the \'vscode\' module -// as well as import your extension to test it import * as vscode from 'vscode'; import * as baseLinter from '../../client/linters/baseLinter'; import * as pyLint from '../../client/linters/pylint'; @@ -14,16 +7,16 @@ import * as flake8 from '../../client/linters/flake8'; import * as prospector from '../../client/linters/prospector'; import * as pydocstyle from '../../client/linters/pydocstyle'; import * as path from 'path'; -import * as settings from '../../client/common/configSettings'; import * as fs from 'fs-extra'; -import { initialize, IS_TRAVIS, closeActiveWindows } from '../initialize'; +import { rootWorkspaceUri, updateSetting, PythonSettingKeys } from '../common'; +import { PythonSettings } from '../../client/common/configSettings'; +import { initialize, IS_TRAVIS, closeActiveWindows, IS_MULTI_ROOT_TEST, initializeTest } from '../initialize'; import { execPythonFile } from '../../client/common/utils'; import { createDeferred } from '../../client/common/helpers'; import { Product, SettingToDisableProduct, Linters } from '../../client/common/installer'; import { EnumEx } from '../../client/common/enumUtils'; import { MockOutputChannel } from '../mockClasses'; -const pythonSettings = settings.PythonSettings.getInstance(); const pythoFilesPath = path.join(__dirname, '..', '..', '..', 'src', 'test', 'pythonFiles', 'linting'); const flake8ConfigPath = path.join(pythoFilesPath, 'flake8config'); const pep8ConfigPath = path.join(pythoFilesPath, 'pep8config'); @@ -127,35 +120,30 @@ suite('Linting', () => { suiteSetup(async () => { pylintFileToLintLines = fs.readFileSync(fileToLint).toString('utf-8').split(/\r?\n/g); await initialize(); - const version = await execPythonFile(pythonSettings.pythonPath, ['--version'], __dirname, true); + const version = await execPythonFile(PythonSettings.getInstance().pythonPath, ['--version'], __dirname, true); isPython3Deferred.resolve(version.indexOf('3.') >= 0); }); - setup(() => { - pythonSettings.linting.lintOnSave = false; - pythonSettings.linting.lintOnTextChange = false; - pythonSettings.linting.enabled = true; - pythonSettings.linting.pylintEnabled = true; - pythonSettings.linting.flake8Enabled = true; - pythonSettings.linting.pep8Enabled = true; - pythonSettings.linting.prospectorEnabled = true; - pythonSettings.linting.pydocstyleEnabled = true; + setup(async () => { + await initializeTest(); + await resetSettings(); }); suiteTeardown(() => closeActiveWindows()); - teardown(() => { - closeActiveWindows(); - pythonSettings.linting.lintOnSave = false; - pythonSettings.linting.lintOnTextChange = false; - pythonSettings.linting.enabled = true; - pythonSettings.linting.pylintEnabled = true; - pythonSettings.linting.flake8Enabled = true; - pythonSettings.linting.pep8Enabled = true; - pythonSettings.linting.prospectorEnabled = true; - pythonSettings.linting.pydocstyleEnabled = true; + teardown(async () => { + await closeActiveWindows(); + await resetSettings(); }); - - async function testEnablingDisablingOfLinter(linter: baseLinter.BaseLinter, propertyName: string) { - pythonSettings.linting[propertyName] = true; - + async function resetSettings() { + await updateSetting('linting.lintOnSave', false, rootWorkspaceUri, vscode.ConfigurationTarget.Workspace); + await updateSetting('linting.lintOnTextChange', false, rootWorkspaceUri, vscode.ConfigurationTarget.Workspace); + await updateSetting('linting.enabled', true, rootWorkspaceUri, vscode.ConfigurationTarget.Workspace); + await updateSetting('linting.pylintEnabled', true, rootWorkspaceUri, vscode.ConfigurationTarget.Workspace); + await updateSetting('linting.flake8Enabled', true, rootWorkspaceUri, vscode.ConfigurationTarget.Workspace); + await updateSetting('linting.pep8Enabled', true, rootWorkspaceUri, vscode.ConfigurationTarget.Workspace); + await updateSetting('linting.prospectorEnabled', true, rootWorkspaceUri, vscode.ConfigurationTarget.Workspace); + await updateSetting('linting.pydocstyleEnabled', true, rootWorkspaceUri, vscode.ConfigurationTarget.Workspace); + } + async function testEnablingDisablingOfLinter(linter: baseLinter.BaseLinter, setting: PythonSettingKeys) { + updateSetting(setting, true, rootWorkspaceUri, IS_MULTI_ROOT_TEST ? vscode.ConfigurationTarget.Workspace : vscode.ConfigurationTarget.WorkspaceFolder) let cancelToken = new vscode.CancellationTokenSource(); disableAllButThisLinter(linter.product); const document = await vscode.workspace.openTextDocument(fileToLint); @@ -169,39 +157,40 @@ suite('Linting', () => { } test('Enable and Disable Pylint', () => { let ch = new MockOutputChannel('Lint'); - testEnablingDisablingOfLinter(new pyLint.Linter(ch), 'pylintEnabled'); + testEnablingDisablingOfLinter(new pyLint.Linter(ch), 'linting.pylintEnabled'); }); test('Enable and Disable Pep8', () => { let ch = new MockOutputChannel('Lint'); - testEnablingDisablingOfLinter(new pep8.Linter(ch), 'pep8Enabled'); + testEnablingDisablingOfLinter(new pep8.Linter(ch), 'linting.pep8Enabled'); }); test('Enable and Disable Flake8', () => { let ch = new MockOutputChannel('Lint'); - testEnablingDisablingOfLinter(new flake8.Linter(ch), 'flake8Enabled'); + testEnablingDisablingOfLinter(new flake8.Linter(ch), 'linting.flake8Enabled'); }); test('Enable and Disable Prospector', () => { let ch = new MockOutputChannel('Lint'); - testEnablingDisablingOfLinter(new prospector.Linter(ch), 'prospectorEnabled'); + testEnablingDisablingOfLinter(new prospector.Linter(ch), 'linting.prospectorEnabled'); }); test('Enable and Disable Pydocstyle', () => { let ch = new MockOutputChannel('Lint'); - testEnablingDisablingOfLinter(new pydocstyle.Linter(ch), 'pydocstyleEnabled'); + testEnablingDisablingOfLinter(new pydocstyle.Linter(ch), 'linting.pydocstyleEnabled'); }); - function disableAllButThisLinter(linterToEnable: Product) { - EnumEx.getNamesAndValues(Product).map(linter => { + async function disableAllButThisLinter(linterToEnable: Product) { + const promises = EnumEx.getNamesAndValues(Product).map(async linter => { if (Linters.indexOf(linter.value) === -1) { return; } - var setting = path.extname(SettingToDisableProduct.get(linter.value)).substring(1); - pythonSettings.linting[setting] = linterToEnable === linter.value; + var setting = SettingToDisableProduct.get(linter.value); + return updateSetting(setting as any, true, rootWorkspaceUri, IS_MULTI_ROOT_TEST ? vscode.ConfigurationTarget.Workspace : vscode.ConfigurationTarget.WorkspaceFolder); }); + await Promise.all(promises); } function testLinterMessages(linter: baseLinter.BaseLinter, outputChannel: MockOutputChannel, pythonFile: string, messagesToBeReceived: baseLinter.ILintMessage[]): Thenable { let cancelToken = new vscode.CancellationTokenSource(); - disableAllButThisLinter(linter.product); - return vscode.workspace.openTextDocument(pythonFile) + return disableAllButThisLinter(linter.product) + .then(() => vscode.workspace.openTextDocument(pythonFile)) .then(document => vscode.window.showTextDocument(document)) .then(editor => { return linter.lint(editor.document, cancelToken.token); diff --git a/src/test/multiRootTest.ts b/src/test/multiRootTest.ts index b7ad307ef20c..57bf5368ccb7 100644 --- a/src/test/multiRootTest.ts +++ b/src/test/multiRootTest.ts @@ -1,8 +1,9 @@ import * as path from 'path'; -process.env.CODE_TESTS_WORKSPACE = path.join(__dirname, '..', '..', 'src', 'test', 'multiRootWkspc', 'multi.code-workspace'); +process.env.CODE_TESTS_WORKSPACE = path.join(__dirname, '..', '..', 'src', 'testMultiRootWkspc', 'multi.code-workspace'); function start() { + console.log('start Multiroot tests'); require('../../node_modules/vscode/bin/test'); } start(); diff --git a/src/test/providers/shebangCodeLenseProvider.test.ts b/src/test/providers/shebangCodeLenseProvider.test.ts index edf66bf9fb02..c8e914f40afd 100644 --- a/src/test/providers/shebangCodeLenseProvider.test.ts +++ b/src/test/providers/shebangCodeLenseProvider.test.ts @@ -2,11 +2,12 @@ import * as assert from 'assert'; import * as path from 'path'; import * as vscode from 'vscode'; import * as child_process from 'child_process'; -import { IS_WINDOWS } from '../../client/common/configSettings'; +import { IS_WINDOWS, PythonSettings } from '../../client/common/configSettings'; +import { rootWorkspaceUri, updateSetting } from '../common'; import { ShebangCodeLensProvider } from '../../client/providers/shebangCodeLensProvider'; - -import { initialize, IS_TRAVIS, closeActiveWindows } from '../initialize'; +import { closeActiveWindows, initialize, initializeTest, IS_MULTI_ROOT_TEST } from '../initialize'; import { getFirstNonEmptyLineFromMultilineString } from '../../client/interpreter/helpers'; +import { ConfigurationTarget } from 'vscode'; const autoCompPath = path.join(__dirname, '..', '..', '..', 'src', 'test', 'pythonFiles', 'shebang'); const fileShebang = path.join(autoCompPath, 'shebang.py'); @@ -14,50 +15,46 @@ const fileShebangEnv = path.join(autoCompPath, 'shebangEnv.py'); const fileShebangInvalid = path.join(autoCompPath, 'shebangInvalid.py'); const filePlain = path.join(autoCompPath, 'plain.py'); -var settings = vscode.workspace.getConfiguration('python'); -const origPythonPath = settings.get('pythonPath'); - suite('Shebang detection', () => { suiteSetup(() => initialize()); - suiteTeardown(() => vscode.workspace.getConfiguration('python').update('pythonPath', origPythonPath)); - teardown(async () => { + suiteTeardown(async () => { + await initialize(); await closeActiveWindows(); - await vscode.workspace.getConfiguration('python').update('pythonPath', origPythonPath); }); + setup(() => initializeTest()); - test('Shebang available, CodeLens showing', async () => { - await settings.update('pythonPath', 'someUnknownInterpreter'); + test('A code lens will appear when sheban python and python in settings are different', async () => { + const pythonPath = 'someUnknownInterpreter'; const editor = await openFile(fileShebang); + PythonSettings.getInstance(editor.document.uri).pythonPath = pythonPath; const codeLenses = await setupCodeLens(editor); assert.equal(codeLenses.length, 1, 'No CodeLens available'); let codeLens = codeLenses[0]; assert(codeLens.range.isSingleLine, 'Invalid CodeLens Range'); assert.equal(codeLens.command.command, 'python.setShebangInterpreter'); - }); - test('Shebang available, CodeLens hiding', async () => { + test('Code lens will not appear when sheban python and python in settings are the same', async () => { + PythonSettings.dispose(); const pythonPath = await getFullyQualifiedPathToInterpreter('python'); - await settings.update('pythonPath', pythonPath); const editor = await openFile(fileShebang); + PythonSettings.getInstance(editor.document.uri).pythonPath = pythonPath; const codeLenses = await setupCodeLens(editor); assert.equal(codeLenses.length, 0, 'CodeLens available although interpreters are equal'); }); - test('Shebang not available (invalid shebang)', async () => { - const pythonPath = await getFullyQualifiedPathToInterpreter('python'); - await settings.update('pythonPath', pythonPath); + test('Code lens will not appear when sheban python is invalid', async () => { const editor = await openFile(fileShebangInvalid); const codeLenses = await setupCodeLens(editor); - assert.equal(codeLenses.length, 0, 'CodeLens available although shebang is invalid'); + assert.equal(codeLenses.length, 0, 'CodeLens available even when shebang is invalid'); }); if (!IS_WINDOWS) { - test('Shebang available, CodeLens showing with env', async () => { - await settings.update('pythonPath', 'p1'); + test('A code lens will appear when shebang python uses env and python settings are different', async () => { const editor = await openFile(fileShebangEnv); + PythonSettings.getInstance(editor.document.uri).pythonPath = 'p1'; const codeLenses = await setupCodeLens(editor); assert.equal(codeLenses.length, 1, 'No CodeLens available'); @@ -67,16 +64,16 @@ suite('Shebang detection', () => { }); - test('Shebang available, CodeLens hiding with env', async () => { + test('Code lens will not appear even when shebang python uses env and python settings are the same', async () => { const pythonPath = await getFullyQualifiedPathToInterpreter('python'); - await settings.update('pythonPath', pythonPath); const editor = await openFile(fileShebangEnv); + PythonSettings.getInstance(editor.document.uri).pythonPath = pythonPath; const codeLenses = await setupCodeLens(editor); assert.equal(codeLenses.length, 0, 'CodeLens available although interpreters are equal'); }); } - test('Shebang missing, CodeLens hiding', async () => { + test('Code lens will not appear as there is no shebang', async () => { const editor = await openFile(filePlain); const codeLenses = await setupCodeLens(editor); assert.equal(codeLenses.length, 0, 'CodeLens available although no shebang'); diff --git a/src/test/pythonFiles/testFiles/standard/.cache/v/cache/lastfailed b/src/test/pythonFiles/testFiles/standard/.cache/v/cache/lastfailed deleted file mode 100644 index 5ca32881aadf..000000000000 --- a/src/test/pythonFiles/testFiles/standard/.cache/v/cache/lastfailed +++ /dev/null @@ -1,3 +0,0 @@ -{ - "test_root.py::Test_Root_test1::test_Root_A": true -} \ No newline at end of file diff --git a/src/test/refactor/extension.refactor.extract.method.test.ts b/src/test/refactor/extension.refactor.extract.method.test.ts index 021bb90532ff..436c1f8f519f 100644 --- a/src/test/refactor/extension.refactor.extract.method.test.ts +++ b/src/test/refactor/extension.refactor.extract.method.test.ts @@ -4,9 +4,9 @@ import * as assert from 'assert'; // as well as import your extension to test it import * as vscode from 'vscode'; import * as path from 'path'; -import * as settings from '../../client/common/configSettings'; import * as fs from 'fs-extra'; -import { initialize, closeActiveWindows, IS_TRAVIS, wait } from './../initialize'; +import { PythonSettings } from '../../client/common/configSettings'; +import { initialize, closeActiveWindows, IS_TRAVIS, wait, initializeTest } from './../initialize'; import { Position } from 'vscode'; import { extractMethod } from '../../client/providers/simpleRefactorProvider'; import { RefactorProxy } from '../../client/refactor/proxy'; @@ -14,7 +14,6 @@ import { getTextEditsFromPatch } from '../../client/common/editor'; import { MockOutputChannel } from './../mockClasses'; const EXTENSION_DIR = path.join(__dirname, '..', '..', '..'); -const pythonSettings = settings.PythonSettings.getInstance(); const refactorSourceFile = path.join(__dirname, '..', '..', '..', 'src', 'test', 'pythonFiles', 'refactoring', 'standAlone', 'refactor.py'); const refactorTargetFile = path.join(__dirname, '..', '..', '..', 'out', 'test', 'pythonFiles', 'refactoring', 'standAlone', 'refactor.py'); @@ -41,7 +40,7 @@ suite('Method Extraction', () => { fs.unlinkSync(refactorTargetFile); } fs.copySync(refactorSourceFile, refactorTargetFile, { overwrite: true }); - await closeActiveWindows(); + await initializeTest(); (vscode).commands.executeCommand = (cmd) => Promise.resolve(); }); teardown(() => { @@ -49,7 +48,8 @@ suite('Method Extraction', () => { return closeActiveWindows(); }); - function testingMethodExtraction(shouldError: boolean, pythonSettings: settings.IPythonSettings, startPos: Position, endPos: Position) { + function testingMethodExtraction(shouldError: boolean, startPos: Position, endPos: Position) { + const pythonSettings = PythonSettings.getInstance(vscode.Uri.file(refactorTargetFile)); let rangeOfTextToExtract = new vscode.Range(startPos, endPos); let proxy = new RefactorProxy(EXTENSION_DIR, pythonSettings, path.dirname(refactorTargetFile)); let expectedTextEdits: vscode.TextEdit[]; @@ -61,7 +61,7 @@ suite('Method Extraction', () => { mockTextDoc = textDocument; expectedTextEdits = getTextEditsFromPatch(textDocument.getText(), DIFF); resolve(); - }, error => reject(error)) + }, error => reject(error)); }) .then(() => proxy.extractMethod(mockTextDoc, 'myNewMethod', refactorTargetFile, rangeOfTextToExtract, options)) .then(response => { @@ -93,16 +93,16 @@ suite('Method Extraction', () => { test('Extract Method', done => { let startPos = new vscode.Position(239, 0); let endPos = new vscode.Position(241, 35); - testingMethodExtraction(false, pythonSettings, startPos, endPos).then(() => done(), done); + testingMethodExtraction(false, startPos, endPos).then(() => done(), done); }); test('Extract Method will fail if complete statements are not selected', done => { let startPos = new vscode.Position(239, 30); let endPos = new vscode.Position(241, 35); - testingMethodExtraction(true, pythonSettings, startPos, endPos).then(() => done(), done); + testingMethodExtraction(true, startPos, endPos).then(() => done(), done); }); - function testingMethodExtractionEndToEnd(shouldError: boolean, pythonSettings: settings.IPythonSettings, startPos: Position, endPos: Position) { + function testingMethodExtractionEndToEnd(shouldError: boolean, startPos: Position, endPos: Position) { let ch = new MockOutputChannel('Python'); let textDocument: vscode.TextDocument; let textEditor: vscode.TextEditor; @@ -161,13 +161,13 @@ suite('Method Extraction', () => { test('Extract Method (end to end)', done => { let startPos = new vscode.Position(239, 0); let endPos = new vscode.Position(241, 35); - testingMethodExtractionEndToEnd(false, pythonSettings, startPos, endPos).then(() => done(), done); + testingMethodExtractionEndToEnd(false, startPos, endPos).then(() => done(), done); }); } test('Extract Method will fail if complete statements are not selected', done => { let startPos = new vscode.Position(239, 30); let endPos = new vscode.Position(241, 35); - testingMethodExtractionEndToEnd(true, pythonSettings, startPos, endPos).then(() => done(), done); + testingMethodExtractionEndToEnd(true, startPos, endPos).then(() => done(), done); }); }); diff --git a/src/test/refactor/extension.refactor.extract.var.test.ts b/src/test/refactor/extension.refactor.extract.var.test.ts index 1e2a896a4e56..06144c333e18 100644 --- a/src/test/refactor/extension.refactor.extract.var.test.ts +++ b/src/test/refactor/extension.refactor.extract.var.test.ts @@ -4,9 +4,9 @@ import * as assert from 'assert'; // as well as import your extension to test it import * as vscode from 'vscode'; import * as path from 'path'; -import * as settings from '../../client/common/configSettings'; import * as fs from 'fs-extra'; -import { initialize, closeActiveWindows, IS_TRAVIS, wait } from './../initialize'; +import { PythonSettings } from '../../client/common/configSettings'; +import { closeActiveWindows, initialize, initializeTest, IS_TRAVIS, wait } from './../initialize'; import { Position } from 'vscode'; import { extractVariable } from '../../client/providers/simpleRefactorProvider'; import { RefactorProxy } from '../../client/refactor/proxy'; @@ -14,7 +14,6 @@ import { getTextEditsFromPatch } from '../../client/common/editor'; import { MockOutputChannel } from './../mockClasses'; const EXTENSION_DIR = path.join(__dirname, '..', '..', '..'); -const pythonSettings = settings.PythonSettings.getInstance(); const refactorSourceFile = path.join(__dirname, '..', '..', '..', 'src', 'test', 'pythonFiles', 'refactoring', 'standAlone', 'refactor.py'); const refactorTargetFile = path.join(__dirname, '..', '..', '..', 'out', 'test', 'pythonFiles', 'refactoring', 'standAlone', 'refactor.py'); @@ -26,9 +25,9 @@ suite('Variable Extraction', () => { // Hack hac hack const oldExecuteCommand = vscode.commands.executeCommand; const options: vscode.TextEditorOptions = { cursorStyle: vscode.TextEditorCursorStyle.Line, insertSpaces: true, lineNumbers: vscode.TextEditorLineNumbersStyle.Off, tabSize: 4 }; - suiteSetup(done => { + suiteSetup(async () => { fs.copySync(refactorSourceFile, refactorTargetFile, { overwrite: true }); - initialize().then(() => done(), () => done()); + await initialize(); }); suiteTeardown(() => { vscode.commands.executeCommand = oldExecuteCommand; @@ -40,7 +39,7 @@ suite('Variable Extraction', () => { fs.unlinkSync(refactorTargetFile); } fs.copySync(refactorSourceFile, refactorTargetFile, { overwrite: true }); - await closeActiveWindows(); + await initializeTest(); (vscode).commands.executeCommand = (cmd) => Promise.resolve(); }); teardown(() => { @@ -48,7 +47,8 @@ suite('Variable Extraction', () => { return closeActiveWindows(); }); - function testingVariableExtraction(shouldError: boolean, pythonSettings: settings.IPythonSettings, startPos: Position, endPos: Position) { + function testingVariableExtraction(shouldError: boolean, startPos: Position, endPos: Position) { + const pythonSettings = PythonSettings.getInstance(vscode.Uri.file(refactorTargetFile)); let rangeOfTextToExtract = new vscode.Range(startPos, endPos); let proxy = new RefactorProxy(EXTENSION_DIR, pythonSettings, path.dirname(refactorTargetFile)); let expectedTextEdits: vscode.TextEdit[]; @@ -92,16 +92,16 @@ suite('Variable Extraction', () => { test('Extract Variable', done => { let startPos = new vscode.Position(234, 29); let endPos = new vscode.Position(234, 38); - testingVariableExtraction(false, pythonSettings, startPos, endPos).then(() => done(), done); + testingVariableExtraction(false, startPos, endPos).then(() => done(), done); }); test('Extract Variable fails if whole string not selected', done => { let startPos = new vscode.Position(234, 20); let endPos = new vscode.Position(234, 38); - testingVariableExtraction(true, pythonSettings, startPos, endPos).then(() => done(), done); + testingVariableExtraction(true, startPos, endPos).then(() => done(), done); }); - function testingVariableExtractionEndToEnd(shouldError: boolean, pythonSettings: settings.IPythonSettings, startPos: Position, endPos: Position) { + function testingVariableExtractionEndToEnd(shouldError: boolean, startPos: Position, endPos: Position) { let ch = new MockOutputChannel('Python'); let textDocument: vscode.TextDocument; let textEditor: vscode.TextEditor; @@ -160,13 +160,13 @@ suite('Variable Extraction', () => { test('Extract Variable (end to end)', done => { let startPos = new vscode.Position(234, 29); let endPos = new vscode.Position(234, 38); - testingVariableExtractionEndToEnd(false, pythonSettings, startPos, endPos).then(() => done(), done); + testingVariableExtractionEndToEnd(false, startPos, endPos).then(() => done(), done); }); } test('Extract Variable fails if whole string not selected (end to end)', done => { let startPos = new vscode.Position(234, 20); let endPos = new vscode.Position(234, 38); - testingVariableExtractionEndToEnd(true, pythonSettings, startPos, endPos).then(() => done(), done); + testingVariableExtractionEndToEnd(true, startPos, endPos).then(() => done(), done); }); }); diff --git a/src/test/unittests/nosetest.test.ts b/src/test/unittests/nosetest.test.ts index 26f4bd39a0ea..870ae5639aa1 100644 --- a/src/test/unittests/nosetest.test.ts +++ b/src/test/unittests/nosetest.test.ts @@ -2,28 +2,28 @@ import * as assert from 'assert'; import * as vscode from 'vscode'; import * as fs from 'fs'; import * as path from 'path'; -import * as configSettings from '../../client/common/configSettings'; import * as nose from '../../client/unittests/nosetest/main'; -import { initialize } from './../initialize'; +import { rootWorkspaceUri, updateSetting } from '../common'; +import { initialize, initializeTest, IS_MULTI_ROOT_TEST } from './../initialize'; import { TestsToRun } from '../../client/unittests/common/contracts'; import { TestResultDisplay } from '../../client/unittests/display/main'; import { MockOutputChannel } from './../mockClasses'; -const pythonSettings = configSettings.PythonSettings.getInstance(); const UNITTEST_TEST_FILES_PATH = path.join(__dirname, '..', '..', '..', 'src', 'test', 'pythonFiles', 'testFiles', 'standard'); const UNITTEST_SINGLE_TEST_FILE_PATH = path.join(__dirname, '..', '..', '..', 'src', 'test', 'pythonFiles', 'testFiles', 'single'); const filesToDelete = [path.join(__dirname, '..', '..', '..', 'src', 'test', 'pythonFiles', 'testFiles', 'standard', '.noseids'), path.join(__dirname, '..', '..', '..', 'src', 'test', 'pythonFiles', 'testFiles', 'cwd', 'src', '.noseids')]; const unitTestTestFilesCwdPath = path.join(__dirname, '..', '..', '..', 'src', 'test', 'pythonFiles', 'testFiles', 'cwd', 'src'); -const originalArgs = pythonSettings.unitTest.nosetestArgs; suite('Unit Tests (nosetest)', () => { + const configTarget = IS_MULTI_ROOT_TEST ? vscode.ConfigurationTarget.WorkspaceFolder : vscode.ConfigurationTarget.Workspace; suiteSetup(async () => { filesToDelete.forEach(file => { if (fs.existsSync(file)) { fs.unlinkSync(file); } }); + await updateSetting('unitTest.nosetestArgs', [], rootWorkspaceUri, configTarget); await initialize(); }); suiteTeardown(() => { @@ -33,15 +33,16 @@ suite('Unit Tests (nosetest)', () => { } }); }); - setup(() => { - pythonSettings.unitTest.nosetestArgs = originalArgs; + setup(async () => { outChannel = new MockOutputChannel('Python Test Log'); testResultDisplay = new TestResultDisplay(outChannel); + await initializeTest(); }); teardown(() => { outChannel.dispose(); testManager.dispose(); testResultDisplay.dispose(); + return updateSetting('unitTest.nosetestArgs', [], rootWorkspaceUri, configTarget); }); function createTestManager(rootDir: string = rootDirectory) { testManager = new nose.TestManager(rootDir, outChannel); @@ -52,7 +53,6 @@ suite('Unit Tests (nosetest)', () => { let outChannel: vscode.OutputChannel; test('Discover Tests (single test file)', async () => { - pythonSettings.unitTest.nosetestArgs = []; testManager = new nose.TestManager(UNITTEST_SINGLE_TEST_FILE_PATH, outChannel); const tests = await testManager.discoverTests(true, true) assert.equal(tests.testFiles.length, 2, 'Incorrect number of test files'); @@ -62,7 +62,6 @@ suite('Unit Tests (nosetest)', () => { }); test('Check that nameToRun in testSuits has class name after : (single test file)', async () => { - pythonSettings.unitTest.nosetestArgs = []; testManager = new nose.TestManager(UNITTEST_SINGLE_TEST_FILE_PATH, outChannel); const tests = await testManager.discoverTests(true, true); assert.equal(tests.testFiles.length, 2, 'Incorrect number of test files'); @@ -72,7 +71,6 @@ suite('Unit Tests (nosetest)', () => { }); test('Discover Tests (pattern = test_)', async () => { - pythonSettings.unitTest.nosetestArgs = []; createTestManager(); const tests = await testManager.discoverTests(true, true); assert.equal(tests.testFiles.length, 6, 'Incorrect number of test files'); @@ -87,9 +85,7 @@ suite('Unit Tests (nosetest)', () => { }); test('Discover Tests (pattern = _test_)', async () => { - pythonSettings.unitTest.nosetestArgs = [ - '-m=*test*' - ]; + await updateSetting('unitTest.nosetestArgs', ['-m=*test*'], rootWorkspaceUri, configTarget); createTestManager(); const tests = await testManager.discoverTests(true, true); assert.equal(tests.testFiles.length, 6, 'Incorrect number of test files'); @@ -104,7 +100,6 @@ suite('Unit Tests (nosetest)', () => { }); test('Run Tests', async () => { - pythonSettings.unitTest.nosetestArgs = []; createTestManager(); const results = await testManager.runTest(); assert.equal(results.summary.errors, 5, 'Errors'); @@ -114,7 +109,6 @@ suite('Unit Tests (nosetest)', () => { }); test('Run Failed Tests', async () => { - pythonSettings.unitTest.nosetestArgs = []; createTestManager(); let results = await testManager.runTest(); assert.equal(results.summary.errors, 5, 'Errors'); @@ -130,7 +124,6 @@ suite('Unit Tests (nosetest)', () => { }); test('Run Specific Test File', async () => { - pythonSettings.unitTest.nosetestArgs = []; createTestManager(); const tests = await testManager.discoverTests(true, true); const testFile: TestsToRun = { testFile: [tests.testFiles[0]], testFolder: [], testFunction: [], testSuite: [] }; @@ -142,7 +135,6 @@ suite('Unit Tests (nosetest)', () => { }); test('Run Specific Test Suite', async () => { - pythonSettings.unitTest.nosetestArgs = []; createTestManager(); const tests = await testManager.discoverTests(true, true); const testSuite: TestsToRun = { testFile: [], testFolder: [], testFunction: [], testSuite: [tests.testSuits[0].testSuite] }; @@ -154,7 +146,6 @@ suite('Unit Tests (nosetest)', () => { }); test('Run Specific Test Function', async () => { - pythonSettings.unitTest.nosetestArgs = []; createTestManager(); const tests = await testManager.discoverTests(true, true); const testFn: TestsToRun = { testFile: [], testFolder: [], testFunction: [tests.testFunctions[0].testFunction], testSuite: [] }; @@ -166,7 +157,7 @@ suite('Unit Tests (nosetest)', () => { }); test('Setting cwd should return tests', async () => { - pythonSettings.unitTest.nosetestArgs = ['tests']; + await updateSetting('unitTest.nosetestArgs', ['tests'], rootWorkspaceUri, configTarget); createTestManager(unitTestTestFilesCwdPath); const tests = await testManager.discoverTests(true, true); diff --git a/src/test/unittests/pytest.test.ts b/src/test/unittests/pytest.test.ts index 4d7dcdcbc664..7156c76ecab1 100644 --- a/src/test/unittests/pytest.test.ts +++ b/src/test/unittests/pytest.test.ts @@ -3,28 +3,34 @@ import * as vscode from 'vscode'; import * as pytest from '../../client/unittests/pytest/main'; import * as path from 'path'; import * as configSettings from '../../client/common/configSettings'; -import { initialize } from './../initialize'; +import { initialize, initializeTest, IS_MULTI_ROOT_TEST } from './../initialize'; import { TestsToRun, TestFile } from '../../client/unittests/common/contracts'; import { TestResultDisplay } from '../../client/unittests/display/main'; import { MockOutputChannel } from './../mockClasses'; +import { rootWorkspaceUri, updateSetting } from '../common'; -const pythonSettings = configSettings.PythonSettings.getInstance(); const UNITTEST_TEST_FILES_PATH = path.join(__dirname, '..', '..', '..', 'src', 'test', 'pythonFiles', 'testFiles', 'standard'); const UNITTEST_SINGLE_TEST_FILE_PATH = path.join(__dirname, '..', '..', '..', 'src', 'test', 'pythonFiles', 'testFiles', 'single'); const UNITTEST_TEST_FILES_PATH_WITH_CONFIGS = path.join(__dirname, '..', '..', '..', 'src', 'test', 'pythonFiles', 'testFiles', 'unitestsWithConfigs'); const unitTestTestFilesCwdPath = path.join(__dirname, '..', '..', '..', 'src', 'test', 'pythonFiles', 'testFiles', 'cwd', 'src'); suite('Unit Tests (PyTest)', () => { - suiteSetup(() => initialize()); + const configTarget = IS_MULTI_ROOT_TEST ? vscode.ConfigurationTarget.WorkspaceFolder : vscode.ConfigurationTarget.Workspace; + suiteSetup(async () => { + await initialize(); + await updateSetting('unitTest.pyTestArgs', [], rootWorkspaceUri, configTarget); + }); setup(() => { rootDirectory = UNITTEST_TEST_FILES_PATH; outChannel = new MockOutputChannel('Python Test Log'); testResultDisplay = new TestResultDisplay(outChannel); + return initializeTest(); }); teardown(() => { outChannel.dispose(); testManager.dispose(); testResultDisplay.dispose(); + return updateSetting('unitTest.pyTestArgs', [], rootWorkspaceUri, configTarget); }); function createTestManager(rootDir: string = rootDirectory) { testManager = new pytest.TestManager(rootDir, outChannel); @@ -35,8 +41,6 @@ suite('Unit Tests (PyTest)', () => { let outChannel: vscode.OutputChannel; test('Discover Tests (single test file)', async () => { - pythonSettings.unitTest.nosetestArgs = [ - ]; testManager = new pytest.TestManager(UNITTEST_SINGLE_TEST_FILE_PATH, outChannel); const tests = await testManager.discoverTests(true, true); assert.equal(tests.testFiles.length, 2, 'Incorrect number of test files'); @@ -47,9 +51,7 @@ suite('Unit Tests (PyTest)', () => { }); test('Discover Tests (pattern = test_)', async () => { - pythonSettings.unitTest.pyTestArgs = [ - '-k=test_' - ]; + await updateSetting('unitTest.pyTestArgs', ['-k=test_'], rootWorkspaceUri, configTarget); createTestManager(); const tests = await testManager.discoverTests(true, true); assert.equal(tests.testFiles.length, 6, 'Incorrect number of test files'); @@ -64,9 +66,7 @@ suite('Unit Tests (PyTest)', () => { }); test('Discover Tests (pattern = _test)', async () => { - pythonSettings.unitTest.pyTestArgs = [ - '-k=_test.py' - ]; + await updateSetting('unitTest.pyTestArgs', ['-k=_test.py'], rootWorkspaceUri, configTarget); createTestManager(); const tests = await testManager.discoverTests(true, true); assert.equal(tests.testFiles.length, 1, 'Incorrect number of test files'); @@ -77,7 +77,7 @@ suite('Unit Tests (PyTest)', () => { test('Discover Tests (with config)', async () => { - pythonSettings.unitTest.pyTestArgs = []; + await updateSetting('unitTest.pyTestArgs', [], rootWorkspaceUri, configTarget); rootDirectory = UNITTEST_TEST_FILES_PATH_WITH_CONFIGS; createTestManager(); const tests = await testManager.discoverTests(true, true); @@ -89,9 +89,7 @@ suite('Unit Tests (PyTest)', () => { }); test('Run Tests', async () => { - pythonSettings.unitTest.pyTestArgs = [ - '-k=test_' - ]; + await updateSetting('unitTest.pyTestArgs', ['-k=test_'], rootWorkspaceUri, configTarget); createTestManager(); const results = await testManager.runTest(); assert.equal(results.summary.errors, 0, 'Errors'); @@ -101,11 +99,9 @@ suite('Unit Tests (PyTest)', () => { }); test('Run Failed Tests', async () => { - pythonSettings.unitTest.pyTestArgs = [ - '-k=test_' - ]; + await updateSetting('unitTest.pyTestArgs', ['-k=test_'], rootWorkspaceUri, configTarget); createTestManager(); - let results = await testManager.runTest() + let results = await testManager.runTest(); assert.equal(results.summary.errors, 0, 'Errors'); assert.equal(results.summary.failures, 9, 'Failures'); assert.equal(results.summary.passed, 17, 'Passed'); @@ -119,9 +115,7 @@ suite('Unit Tests (PyTest)', () => { }); test('Run Specific Test File', async () => { - pythonSettings.unitTest.pyTestArgs = [ - '-k=test_' - ]; + await updateSetting('unitTest.pyTestArgs', ['-k=test_'], rootWorkspaceUri, configTarget); createTestManager(); await testManager.discoverTests(true, true); const testFile: TestFile = { @@ -142,13 +136,11 @@ suite('Unit Tests (PyTest)', () => { }); test('Run Specific Test Suite', async () => { - pythonSettings.unitTest.pyTestArgs = [ - '-k=test_' - ]; + await updateSetting('unitTest.pyTestArgs', ['-k=test_'], rootWorkspaceUri, configTarget); createTestManager(); const tests = await testManager.discoverTests(true, true); const testSuite: TestsToRun = { testFile: [], testFolder: [], testFunction: [], testSuite: [tests.testSuits[0].testSuite] }; - const results = await testManager.runTest(testSuite) + const results = await testManager.runTest(testSuite); assert.equal(results.summary.errors, 0, 'Errors'); assert.equal(results.summary.failures, 1, 'Failures'); assert.equal(results.summary.passed, 1, 'Passed'); @@ -156,9 +148,7 @@ suite('Unit Tests (PyTest)', () => { }); test('Run Specific Test Function', async () => { - pythonSettings.unitTest.pyTestArgs = [ - '-k=test_' - ]; + await updateSetting('unitTest.pyTestArgs', ['-k=test_'], rootWorkspaceUri, configTarget); createTestManager(); const tests = await testManager.discoverTests(true, true); const testFn: TestsToRun = { testFile: [], testFolder: [], testFunction: [tests.testFunctions[0].testFunction], testSuite: [] }; @@ -171,10 +161,7 @@ suite('Unit Tests (PyTest)', () => { test('Setting cwd should return tests', async () => { - pythonSettings.unitTest.unittestArgs = [ - '-s=./tests', - '-p=test*.py' - ]; + await updateSetting('unitTest.pyTestArgs', ['-k=test_'], rootWorkspaceUri, configTarget); createTestManager(unitTestTestFilesCwdPath); const tests = await testManager.discoverTests(true, true); diff --git a/src/test/unittests/unittest.test.ts b/src/test/unittests/unittest.test.ts index 43d4fdab710f..211423086476 100644 --- a/src/test/unittests/unittest.test.ts +++ b/src/test/unittests/unittest.test.ts @@ -1,24 +1,38 @@ import * as assert from 'assert'; import * as path from 'path'; -import * as configSettings from '../../client/common/configSettings'; +import * as fs from 'fs-extra'; import * as unittest from '../../client/unittests/unittest/main'; -import { initialize } from './../initialize'; +import { initialize, initializeTest, IS_MULTI_ROOT_TEST } from './../initialize'; import { TestsToRun } from '../../client/unittests/common/contracts'; import { TestResultDisplay } from '../../client/unittests/display/main'; import { MockOutputChannel } from './../mockClasses'; +import { ConfigurationTarget } from 'vscode'; +import { rootWorkspaceUri, updateSetting } from '../common'; -const pythonSettings = configSettings.PythonSettings.getInstance(); const testFilesPath = path.join(__dirname, '..', '..', '..', 'src', 'test', 'pythonFiles', 'testFiles'); const UNITTEST_TEST_FILES_PATH = path.join(testFilesPath, 'standard'); const UNITTEST_SINGLE_TEST_FILE_PATH = path.join(testFilesPath, 'single'); const unitTestTestFilesCwdPath = path.join(testFilesPath, 'cwd', 'src'); const unitTestSpecificTestFilesPath = path.join(testFilesPath, 'specificTest'); +const defaultUnitTestArgs = [ + "-v", + "-s", + ".", + "-p", + "*test*.py" +]; suite('Unit Tests (unittest)', () => { - suiteSetup(() => initialize()); - setup(() => { + const configTarget = IS_MULTI_ROOT_TEST ? ConfigurationTarget.WorkspaceFolder : ConfigurationTarget.Workspace; + suiteSetup(async () => { + await initialize(); + await updateSetting('unitTest.unittestArgs', defaultUnitTestArgs, rootWorkspaceUri, configTarget); + }); + setup(async () => { outChannel = new MockOutputChannel('Python Test Log'); testResultDisplay = new TestResultDisplay(outChannel); + await fs.remove(path.join(UNITTEST_TEST_FILES_PATH, '.cache')).catch(() => undefined); + await initializeTest(); }); teardown(() => { outChannel.dispose(); @@ -34,10 +48,7 @@ suite('Unit Tests (unittest)', () => { let outChannel: MockOutputChannel; test('Discover Tests (single test file)', async () => { - pythonSettings.unitTest.unittestArgs = [ - '-s=./tests', - '-p=test_*.py' - ]; + await updateSetting('unitTest.unittestArgs', ['-s=./tests', '-p=test_*.py'], rootWorkspaceUri, configTarget); testManager = new unittest.TestManager(UNITTEST_SINGLE_TEST_FILE_PATH, outChannel); const tests = await testManager.discoverTests(true, true); assert.equal(tests.testFiles.length, 1, 'Incorrect number of test files'); @@ -47,10 +58,7 @@ suite('Unit Tests (unittest)', () => { }); test('Discover Tests', async () => { - pythonSettings.unitTest.unittestArgs = [ - '-s=./tests', - '-p=test_*.py' - ]; + await updateSetting('unitTest.unittestArgs', ['-s=./tests', '-p=test_*.py'], rootWorkspaceUri, configTarget); createTestManager(); const tests = await testManager.discoverTests(true, true); assert.equal(tests.testFiles.length, 2, 'Incorrect number of test files'); @@ -61,10 +69,7 @@ suite('Unit Tests (unittest)', () => { }); test('Discover Tests (pattern = *_test_*.py)', async () => { - pythonSettings.unitTest.unittestArgs = [ - '-s=./tests', - '-p=*_test*.py' - ]; + await updateSetting('unitTest.unittestArgs', ['-s=./tests', '-p=*_test*.py'], rootWorkspaceUri, configTarget); createTestManager(); const tests = await testManager.discoverTests(true, true); assert.equal(tests.testFiles.length, 1, 'Incorrect number of test files'); @@ -74,10 +79,7 @@ suite('Unit Tests (unittest)', () => { }); test('Run Tests', async () => { - pythonSettings.unitTest.unittestArgs = [ - '-v', '-s', './tests', - '-p', 'test_unittest*.py' - ]; + await updateSetting('unitTest.unittestArgs', ['-v', '-s', './tests', '-p', 'test_unittest*.py'], rootWorkspaceUri, configTarget); createTestManager(); const results = await testManager.runTest(); assert.equal(results.summary.errors, 1, 'Errors'); @@ -103,10 +105,7 @@ suite('Unit Tests (unittest)', () => { // }); test('Run Failed Tests', async () => { - pythonSettings.unitTest.unittestArgs = [ - '-s=./tests', - '-p=test_unittest*.py' - ]; + await updateSetting('unitTest.unittestArgs', ['-s=./tests', '-p=test_unittest*.py'], rootWorkspaceUri, configTarget); createTestManager(); let results = await testManager.runTest(); assert.equal(results.summary.errors, 1, 'Errors'); @@ -122,10 +121,7 @@ suite('Unit Tests (unittest)', () => { }); test('Run Specific Test File', async () => { - pythonSettings.unitTest.unittestArgs = [ - '-s=./tests', - '-p=test_unittest*.py' - ]; + await updateSetting('unitTest.unittestArgs', ['-s=./tests', '-p=test_unittest*.py'], rootWorkspaceUri, configTarget); createTestManager(unitTestSpecificTestFilesPath); const tests = await testManager.discoverTests(true, true); @@ -140,10 +136,7 @@ suite('Unit Tests (unittest)', () => { }); test('Run Specific Test Suite', async () => { - pythonSettings.unitTest.unittestArgs = [ - '-s=./tests', - '-p=test_unittest*.py' - ]; + await updateSetting('unitTest.unittestArgs', ['-s=./tests', '-p=test_unittest*.py'], rootWorkspaceUri, configTarget); createTestManager(unitTestSpecificTestFilesPath); const tests = await testManager.discoverTests(true, true); @@ -158,10 +151,7 @@ suite('Unit Tests (unittest)', () => { }); test('Run Specific Test Function', async () => { - pythonSettings.unitTest.unittestArgs = [ - '-s=./tests', - '-p=test_unittest*.py' - ]; + await updateSetting('unitTest.unittestArgs', ['-s=./tests', '-p=test_unittest*.py'], rootWorkspaceUri, configTarget); createTestManager(); const tests = await testManager.discoverTests(true, true); const testFn: TestsToRun = { testFile: [], testFolder: [], testFunction: [tests.testFunctions[0].testFunction], testSuite: [] }; @@ -173,10 +163,7 @@ suite('Unit Tests (unittest)', () => { }); test('Setting cwd should return tests', async () => { - pythonSettings.unitTest.unittestArgs = [ - '-s=./tests', - '-p=test_*.py' - ]; + await updateSetting('unitTest.unittestArgs', ['-s=./tests', '-p=test_*.py'], rootWorkspaceUri, configTarget); createTestManager(unitTestTestFilesCwdPath); const tests = await testManager.discoverTests(true, true); diff --git a/src/test/workspaceSymbols/multiroot.test.ts b/src/test/workspaceSymbols/multiroot.test.ts index 270920898526..bbd352f11d6f 100644 --- a/src/test/workspaceSymbols/multiroot.test.ts +++ b/src/test/workspaceSymbols/multiroot.test.ts @@ -1,30 +1,29 @@ import * as assert from 'assert'; import * as path from 'path'; import { CancellationTokenSource, ConfigurationTarget, Uri } from 'vscode'; -import { initialize, closeActiveWindows } from '../initialize'; +import { closeActiveWindows, initialize, initializeTest } from '../initialize'; import { Generator } from '../../client/workspaceSymbols/generator'; import { MockOutputChannel } from '../mockClasses'; import { WorkspaceSymbolProvider } from '../../client/workspaceSymbols/provider'; -import { enableDisableWorkspaceSymbols } from './common'; -import { PythonSettings } from '../../client/common/configSettings'; +import { updateSetting } from './../common'; -const multirootPath = path.join(__dirname, '..', '..', '..', 'src', 'test', 'multiRootWkspc'); +const multirootPath = path.join(__dirname, '..', '..', '..', 'src', 'testMultiRootWkspc'); suite('Multiroot Workspace Symbols', () => { suiteSetup(() => initialize()); - setup(() => PythonSettings.dispose()); + setup(() => initializeTest()); suiteTeardown(() => closeActiveWindows()); teardown(async () => { await closeActiveWindows(); - await enableDisableWorkspaceSymbols(Uri.file(path.join(multirootPath, 'parent', 'child')), false, ConfigurationTarget.WorkspaceFolder); - await enableDisableWorkspaceSymbols(Uri.file(path.join(multirootPath, 'workspace2')), false, ConfigurationTarget.WorkspaceFolder); + await updateSetting('workspaceSymbols.enabled', false, Uri.file(path.join(multirootPath, 'parent', 'child')), ConfigurationTarget.WorkspaceFolder); + await updateSetting('workspaceSymbols.enabled', false, Uri.file(path.join(multirootPath, 'workspace2')), ConfigurationTarget.WorkspaceFolder); }); test(`symbols should be returned when enabeld and vice versa`, async () => { const childWorkspaceUri = Uri.file(path.join(multirootPath, 'parent', 'child')); const outputChannel = new MockOutputChannel('Output'); - await enableDisableWorkspaceSymbols(childWorkspaceUri, false, ConfigurationTarget.WorkspaceFolder); + await updateSetting('workspaceSymbols.enabled', false, childWorkspaceUri, ConfigurationTarget.WorkspaceFolder); let generator = new Generator(childWorkspaceUri, outputChannel); let provider = new WorkspaceSymbolProvider([generator], outputChannel); @@ -32,7 +31,7 @@ suite('Multiroot Workspace Symbols', () => { assert.equal(symbols.length, 0, 'Symbols returned even when workspace symbols are turned off'); generator.dispose(); - await enableDisableWorkspaceSymbols(childWorkspaceUri, true, ConfigurationTarget.WorkspaceFolder); + await updateSetting('workspaceSymbols.enabled', true, childWorkspaceUri, ConfigurationTarget.WorkspaceFolder); generator = new Generator(childWorkspaceUri, outputChannel); provider = new WorkspaceSymbolProvider([generator], outputChannel); @@ -44,8 +43,8 @@ suite('Multiroot Workspace Symbols', () => { const workspace2Uri = Uri.file(path.join(multirootPath, 'workspace2')); const outputChannel = new MockOutputChannel('Output'); - await enableDisableWorkspaceSymbols(childWorkspaceUri, true, ConfigurationTarget.WorkspaceFolder); - await enableDisableWorkspaceSymbols(workspace2Uri, true, ConfigurationTarget.WorkspaceFolder); + await updateSetting('workspaceSymbols.enabled', true, childWorkspaceUri, ConfigurationTarget.WorkspaceFolder); + await updateSetting('workspaceSymbols.enabled', true, workspace2Uri, ConfigurationTarget.WorkspaceFolder); const generators = [ new Generator(childWorkspaceUri, outputChannel), diff --git a/src/test/workspaceSymbols/standard.test.ts b/src/test/workspaceSymbols/standard.test.ts index f32a9de3efa7..3251ad85ccdb 100644 --- a/src/test/workspaceSymbols/standard.test.ts +++ b/src/test/workspaceSymbols/standard.test.ts @@ -1,11 +1,11 @@ import * as assert from 'assert'; import * as path from 'path'; import { CancellationTokenSource, ConfigurationTarget, Uri } from 'vscode'; -import { initialize, closeActiveWindows } from '../initialize'; +import { closeActiveWindows, initialize, initializeTest } from '../initialize'; import { Generator } from '../../client/workspaceSymbols/generator'; import { MockOutputChannel } from '../mockClasses'; import { WorkspaceSymbolProvider } from '../../client/workspaceSymbols/provider'; -import { enableDisableWorkspaceSymbols } from './common'; +import { updateSetting } from './../common'; import { PythonSettings } from '../../client/common/configSettings'; const workspaceUri = Uri.file(path.join(__dirname, '..', '..', '..', 'src', 'test')); @@ -13,15 +13,15 @@ const workspaceUri = Uri.file(path.join(__dirname, '..', '..', '..', 'src', 'tes suite('Workspace Symbols', () => { suiteSetup(() => initialize()); suiteTeardown(() => closeActiveWindows()); - setup(() => PythonSettings.dispose()); + setup(() => initializeTest()); teardown(async () => { await closeActiveWindows(); - await enableDisableWorkspaceSymbols(workspaceUri, false, ConfigurationTarget.Workspace); + await updateSetting('workspaceSymbols.enabled', false, workspaceUri, ConfigurationTarget.Workspace); }); test(`symbols should be returned when enabeld and vice versa`, async () => { const outputChannel = new MockOutputChannel('Output'); - await enableDisableWorkspaceSymbols(workspaceUri, false, ConfigurationTarget.Workspace); + await updateSetting('workspaceSymbols.enabled', false, workspaceUri, ConfigurationTarget.Workspace); // The workspace will be in the output test folder // So lets modify the settings so it sees the source test folder @@ -34,7 +34,7 @@ suite('Workspace Symbols', () => { assert.equal(symbols.length, 0, 'Symbols returned even when workspace symbols are turned off'); generator.dispose(); - await enableDisableWorkspaceSymbols(workspaceUri, true, ConfigurationTarget.Workspace); + await updateSetting('workspaceSymbols.enabled', true, workspaceUri, ConfigurationTarget.Workspace); // The workspace will be in the output test folder // So lets modify the settings so it sees the source test folder @@ -48,7 +48,8 @@ suite('Workspace Symbols', () => { }); test(`symbols should be filtered correctly`, async () => { const outputChannel = new MockOutputChannel('Output'); - await enableDisableWorkspaceSymbols(workspaceUri, true, ConfigurationTarget.Workspace); + + await updateSetting('workspaceSymbols.enabled', true, workspaceUri, ConfigurationTarget.Workspace); // The workspace will be in the output test folder // So lets modify the settings so it sees the source test folder diff --git a/src/testMultiRootWkspc/disableLinters/.vscode/tags b/src/testMultiRootWkspc/disableLinters/.vscode/tags new file mode 100644 index 000000000000..4739b4629cfb --- /dev/null +++ b/src/testMultiRootWkspc/disableLinters/.vscode/tags @@ -0,0 +1,19 @@ +!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ +!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/ +!_TAG_OUTPUT_MODE u-ctags /u-ctags or e-ctags/ +!_TAG_PROGRAM_AUTHOR Universal Ctags Team // +!_TAG_PROGRAM_NAME Universal Ctags /Derived from Exuberant Ctags/ +!_TAG_PROGRAM_URL https://ctags.io/ /official site/ +!_TAG_PROGRAM_VERSION 0.0.0 /f9e6e3c1/ +Foo ..\\file.py /^class Foo(object):$/;" kind:class line:5 +__init__ ..\\file.py /^ def __init__(self):$/;" kind:member line:8 +__revision__ ..\\file.py /^__revision__ = None$/;" kind:variable line:3 +file.py ..\\file.py 1;" kind:file line:1 +meth1 ..\\file.py /^ def meth1(self, arg):$/;" kind:member line:11 +meth2 ..\\file.py /^ def meth2(self, arg):$/;" kind:member line:15 +meth3 ..\\file.py /^ def meth3(self):$/;" kind:member line:21 +meth4 ..\\file.py /^ def meth4(self):$/;" kind:member line:28 +meth5 ..\\file.py /^ def meth5(self):$/;" kind:member line:38 +meth6 ..\\file.py /^ def meth6(self):$/;" kind:member line:53 +meth7 ..\\file.py /^ def meth7(self):$/;" kind:member line:68 +meth8 ..\\file.py /^ def meth8(self):$/;" kind:member line:80 diff --git a/src/testMultiRootWkspc/disableLinters/file.py b/src/testMultiRootWkspc/disableLinters/file.py new file mode 100644 index 000000000000..439f899e9e22 --- /dev/null +++ b/src/testMultiRootWkspc/disableLinters/file.py @@ -0,0 +1,87 @@ +"""pylint option block-disable""" + +__revision__ = None + +class Foo(object): + """block-disable test""" + + def __init__(self): + pass + + def meth1(self, arg): + """this issues a message""" + print self + + def meth2(self, arg): + """and this one not""" + # pylint: disable=unused-argument + print self\ + + "foo" + + def meth3(self): + """test one line disabling""" + # no error + print self.bla # pylint: disable=no-member + # error + print self.blop + + def meth4(self): + """test re-enabling""" + # pylint: disable=no-member + # no error + print self.bla + print self.blop + # pylint: enable=no-member + # error + print self.blip + + def meth5(self): + """test IF sub-block re-enabling""" + # pylint: disable=no-member + # no error + print self.bla + if self.blop: + # pylint: enable=no-member + # error + print self.blip + else: + # no error + print self.blip + # no error + print self.blip + + def meth6(self): + """test TRY/EXCEPT sub-block re-enabling""" + # pylint: disable=no-member + # no error + print self.bla + try: + # pylint: enable=no-member + # error + print self.blip + except UndefinedName: # pylint: disable=undefined-variable + # no error + print self.blip + # no error + print self.blip + + def meth7(self): + """test one line block opening disabling""" + if self.blop: # pylint: disable=no-member + # error + print self.blip + else: + # error + print self.blip + # error + print self.blip + + + def meth8(self): + """test late disabling""" + # error + print self.blip + # pylint: disable=no-member + # no error + print self.bla + print self.blop diff --git a/src/testMultiRootWkspc/multi.code-workspace b/src/testMultiRootWkspc/multi.code-workspace new file mode 100644 index 000000000000..891cdf0bd28d --- /dev/null +++ b/src/testMultiRootWkspc/multi.code-workspace @@ -0,0 +1,33 @@ +{ + "folders": [ + { + "path": "workspace1" + }, + { + "path": "workspace2" + }, + { + "path": "workspace3" + }, + { + "path": "parent\\child" + }, + { + "path": "disableLinters" + }, + { + "path": "../test" + } + ], + "settings": { + "python.linting.flake8Enabled": false, + "python.linting.mypyEnabled": true, + "python.linting.pydocstyleEnabled": true, + "python.linting.pylamaEnabled": true, + "python.linting.pylintEnabled": false, + "python.linting.pep8Enabled": true, + "python.linting.prospectorEnabled": true, + "python.workspaceSymbols.enabled": true, + "python.pythonPath": "python" + } +} diff --git a/src/testMultiRootWkspc/parent/child/.vscode/settings.json b/src/testMultiRootWkspc/parent/child/.vscode/settings.json new file mode 100644 index 000000000000..c404e94945a9 --- /dev/null +++ b/src/testMultiRootWkspc/parent/child/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.workspaceSymbols.enabled": false +} \ No newline at end of file diff --git a/src/testMultiRootWkspc/parent/child/.vscode/tags b/src/testMultiRootWkspc/parent/child/.vscode/tags new file mode 100644 index 000000000000..e6791c755b0f --- /dev/null +++ b/src/testMultiRootWkspc/parent/child/.vscode/tags @@ -0,0 +1,24 @@ +!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ +!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/ +!_TAG_OUTPUT_MODE u-ctags /u-ctags or e-ctags/ +!_TAG_PROGRAM_AUTHOR Universal Ctags Team // +!_TAG_PROGRAM_NAME Universal Ctags /Derived from Exuberant Ctags/ +!_TAG_PROGRAM_URL https://ctags.io/ /official site/ +!_TAG_PROGRAM_VERSION 0.0.0 /f9e6e3c1/ +Child2Class ..\\childFile.py /^class Child2Class(object):$/;" kind:class line:5 +Foo ..\\file.py /^class Foo(object):$/;" kind:class line:5 +__init__ ..\\childFile.py /^ def __init__(self):$/;" kind:member line:8 +__init__ ..\\file.py /^ def __init__(self):$/;" kind:member line:8 +__revision__ ..\\childFile.py /^__revision__ = None$/;" kind:variable line:3 +__revision__ ..\\file.py /^__revision__ = None$/;" kind:variable line:3 +childFile.py ..\\childFile.py 1;" kind:file line:1 +file.py ..\\file.py 1;" kind:file line:1 +meth1 ..\\file.py /^ def meth1(self, arg):$/;" kind:member line:11 +meth1OfChild ..\\childFile.py /^ def meth1OfChild(self, arg):$/;" kind:member line:11 +meth2 ..\\file.py /^ def meth2(self, arg):$/;" kind:member line:15 +meth3 ..\\file.py /^ def meth3(self):$/;" kind:member line:21 +meth4 ..\\file.py /^ def meth4(self):$/;" kind:member line:28 +meth5 ..\\file.py /^ def meth5(self):$/;" kind:member line:38 +meth6 ..\\file.py /^ def meth6(self):$/;" kind:member line:53 +meth7 ..\\file.py /^ def meth7(self):$/;" kind:member line:68 +meth8 ..\\file.py /^ def meth8(self):$/;" kind:member line:80 diff --git a/src/testMultiRootWkspc/parent/child/childFile.py b/src/testMultiRootWkspc/parent/child/childFile.py new file mode 100644 index 000000000000..31d6fc7b4a18 --- /dev/null +++ b/src/testMultiRootWkspc/parent/child/childFile.py @@ -0,0 +1,13 @@ +"""pylint option block-disable""" + +__revision__ = None + +class Child2Class(object): + """block-disable test""" + + def __init__(self): + pass + + def meth1OfChild(self, arg): + """this issues a message""" + print (self) diff --git a/src/testMultiRootWkspc/parent/child/file.py b/src/testMultiRootWkspc/parent/child/file.py new file mode 100644 index 000000000000..439f899e9e22 --- /dev/null +++ b/src/testMultiRootWkspc/parent/child/file.py @@ -0,0 +1,87 @@ +"""pylint option block-disable""" + +__revision__ = None + +class Foo(object): + """block-disable test""" + + def __init__(self): + pass + + def meth1(self, arg): + """this issues a message""" + print self + + def meth2(self, arg): + """and this one not""" + # pylint: disable=unused-argument + print self\ + + "foo" + + def meth3(self): + """test one line disabling""" + # no error + print self.bla # pylint: disable=no-member + # error + print self.blop + + def meth4(self): + """test re-enabling""" + # pylint: disable=no-member + # no error + print self.bla + print self.blop + # pylint: enable=no-member + # error + print self.blip + + def meth5(self): + """test IF sub-block re-enabling""" + # pylint: disable=no-member + # no error + print self.bla + if self.blop: + # pylint: enable=no-member + # error + print self.blip + else: + # no error + print self.blip + # no error + print self.blip + + def meth6(self): + """test TRY/EXCEPT sub-block re-enabling""" + # pylint: disable=no-member + # no error + print self.bla + try: + # pylint: enable=no-member + # error + print self.blip + except UndefinedName: # pylint: disable=undefined-variable + # no error + print self.blip + # no error + print self.blip + + def meth7(self): + """test one line block opening disabling""" + if self.blop: # pylint: disable=no-member + # error + print self.blip + else: + # error + print self.blip + # error + print self.blip + + + def meth8(self): + """test late disabling""" + # error + print self.blip + # pylint: disable=no-member + # no error + print self.bla + print self.blop diff --git a/src/testMultiRootWkspc/workspace1/.vscode/settings.json b/src/testMultiRootWkspc/workspace1/.vscode/settings.json new file mode 100644 index 000000000000..a783cfe01962 --- /dev/null +++ b/src/testMultiRootWkspc/workspace1/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "python.linting.pylintEnabled": true, + "python.linting.enabled": false, + "python.linting.flake8Enabled": true +} diff --git a/src/testMultiRootWkspc/workspace1/.vscode/tags b/src/testMultiRootWkspc/workspace1/.vscode/tags new file mode 100644 index 000000000000..4739b4629cfb --- /dev/null +++ b/src/testMultiRootWkspc/workspace1/.vscode/tags @@ -0,0 +1,19 @@ +!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ +!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/ +!_TAG_OUTPUT_MODE u-ctags /u-ctags or e-ctags/ +!_TAG_PROGRAM_AUTHOR Universal Ctags Team // +!_TAG_PROGRAM_NAME Universal Ctags /Derived from Exuberant Ctags/ +!_TAG_PROGRAM_URL https://ctags.io/ /official site/ +!_TAG_PROGRAM_VERSION 0.0.0 /f9e6e3c1/ +Foo ..\\file.py /^class Foo(object):$/;" kind:class line:5 +__init__ ..\\file.py /^ def __init__(self):$/;" kind:member line:8 +__revision__ ..\\file.py /^__revision__ = None$/;" kind:variable line:3 +file.py ..\\file.py 1;" kind:file line:1 +meth1 ..\\file.py /^ def meth1(self, arg):$/;" kind:member line:11 +meth2 ..\\file.py /^ def meth2(self, arg):$/;" kind:member line:15 +meth3 ..\\file.py /^ def meth3(self):$/;" kind:member line:21 +meth4 ..\\file.py /^ def meth4(self):$/;" kind:member line:28 +meth5 ..\\file.py /^ def meth5(self):$/;" kind:member line:38 +meth6 ..\\file.py /^ def meth6(self):$/;" kind:member line:53 +meth7 ..\\file.py /^ def meth7(self):$/;" kind:member line:68 +meth8 ..\\file.py /^ def meth8(self):$/;" kind:member line:80 diff --git a/src/testMultiRootWkspc/workspace1/file.py b/src/testMultiRootWkspc/workspace1/file.py new file mode 100644 index 000000000000..439f899e9e22 --- /dev/null +++ b/src/testMultiRootWkspc/workspace1/file.py @@ -0,0 +1,87 @@ +"""pylint option block-disable""" + +__revision__ = None + +class Foo(object): + """block-disable test""" + + def __init__(self): + pass + + def meth1(self, arg): + """this issues a message""" + print self + + def meth2(self, arg): + """and this one not""" + # pylint: disable=unused-argument + print self\ + + "foo" + + def meth3(self): + """test one line disabling""" + # no error + print self.bla # pylint: disable=no-member + # error + print self.blop + + def meth4(self): + """test re-enabling""" + # pylint: disable=no-member + # no error + print self.bla + print self.blop + # pylint: enable=no-member + # error + print self.blip + + def meth5(self): + """test IF sub-block re-enabling""" + # pylint: disable=no-member + # no error + print self.bla + if self.blop: + # pylint: enable=no-member + # error + print self.blip + else: + # no error + print self.blip + # no error + print self.blip + + def meth6(self): + """test TRY/EXCEPT sub-block re-enabling""" + # pylint: disable=no-member + # no error + print self.bla + try: + # pylint: enable=no-member + # error + print self.blip + except UndefinedName: # pylint: disable=undefined-variable + # no error + print self.blip + # no error + print self.blip + + def meth7(self): + """test one line block opening disabling""" + if self.blop: # pylint: disable=no-member + # error + print self.blip + else: + # error + print self.blip + # error + print self.blip + + + def meth8(self): + """test late disabling""" + # error + print self.blip + # pylint: disable=no-member + # no error + print self.bla + print self.blop diff --git a/src/testMultiRootWkspc/workspace2/.vscode/settings.json b/src/testMultiRootWkspc/workspace2/.vscode/settings.json new file mode 100644 index 000000000000..750d19764931 --- /dev/null +++ b/src/testMultiRootWkspc/workspace2/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "python.workspaceSymbols.tagFilePath": "${workspaceRoot}/workspace2.tags.file", + "python.workspaceSymbols.enabled": false +} diff --git a/src/testMultiRootWkspc/workspace2/file.py b/src/testMultiRootWkspc/workspace2/file.py new file mode 100644 index 000000000000..439f899e9e22 --- /dev/null +++ b/src/testMultiRootWkspc/workspace2/file.py @@ -0,0 +1,87 @@ +"""pylint option block-disable""" + +__revision__ = None + +class Foo(object): + """block-disable test""" + + def __init__(self): + pass + + def meth1(self, arg): + """this issues a message""" + print self + + def meth2(self, arg): + """and this one not""" + # pylint: disable=unused-argument + print self\ + + "foo" + + def meth3(self): + """test one line disabling""" + # no error + print self.bla # pylint: disable=no-member + # error + print self.blop + + def meth4(self): + """test re-enabling""" + # pylint: disable=no-member + # no error + print self.bla + print self.blop + # pylint: enable=no-member + # error + print self.blip + + def meth5(self): + """test IF sub-block re-enabling""" + # pylint: disable=no-member + # no error + print self.bla + if self.blop: + # pylint: enable=no-member + # error + print self.blip + else: + # no error + print self.blip + # no error + print self.blip + + def meth6(self): + """test TRY/EXCEPT sub-block re-enabling""" + # pylint: disable=no-member + # no error + print self.bla + try: + # pylint: enable=no-member + # error + print self.blip + except UndefinedName: # pylint: disable=undefined-variable + # no error + print self.blip + # no error + print self.blip + + def meth7(self): + """test one line block opening disabling""" + if self.blop: # pylint: disable=no-member + # error + print self.blip + else: + # error + print self.blip + # error + print self.blip + + + def meth8(self): + """test late disabling""" + # error + print self.blip + # pylint: disable=no-member + # no error + print self.bla + print self.blop diff --git a/src/testMultiRootWkspc/workspace2/workspace2.tags.file b/src/testMultiRootWkspc/workspace2/workspace2.tags.file new file mode 100644 index 000000000000..375785e2a94e --- /dev/null +++ b/src/testMultiRootWkspc/workspace2/workspace2.tags.file @@ -0,0 +1,24 @@ +!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ +!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/ +!_TAG_OUTPUT_MODE u-ctags /u-ctags or e-ctags/ +!_TAG_PROGRAM_AUTHOR Universal Ctags Team // +!_TAG_PROGRAM_NAME Universal Ctags /Derived from Exuberant Ctags/ +!_TAG_PROGRAM_URL https://ctags.io/ /official site/ +!_TAG_PROGRAM_VERSION 0.0.0 /f9e6e3c1/ +Foo C:\\Users\\dojayama\\.vscode\\extensions\\pythonVSCode\\src\\testMultiRootWkspc\\workspace2\\file.py /^class Foo(object):$/;" kind:class line:5 +Workspace2Class C:\\Users\\dojayama\\.vscode\\extensions\\pythonVSCode\\src\\testMultiRootWkspc\\workspace2\\workspace2File.py /^class Workspace2Class(object):$/;" kind:class line:5 +__init__ C:\\Users\\dojayama\\.vscode\\extensions\\pythonVSCode\\src\\testMultiRootWkspc\\workspace2\\file.py /^ def __init__(self):$/;" kind:member line:8 +__init__ C:\\Users\\dojayama\\.vscode\\extensions\\pythonVSCode\\src\\testMultiRootWkspc\\workspace2\\workspace2File.py /^ def __init__(self):$/;" kind:member line:8 +__revision__ C:\\Users\\dojayama\\.vscode\\extensions\\pythonVSCode\\src\\testMultiRootWkspc\\workspace2\\file.py /^__revision__ = None$/;" kind:variable line:3 +__revision__ C:\\Users\\dojayama\\.vscode\\extensions\\pythonVSCode\\src\\testMultiRootWkspc\\workspace2\\workspace2File.py /^__revision__ = None$/;" kind:variable line:3 +file.py C:\\Users\\dojayama\\.vscode\\extensions\\pythonVSCode\\src\\testMultiRootWkspc\\workspace2\\file.py 1;" kind:file line:1 +meth1 C:\\Users\\dojayama\\.vscode\\extensions\\pythonVSCode\\src\\testMultiRootWkspc\\workspace2\\file.py /^ def meth1(self, arg):$/;" kind:member line:11 +meth1OfWorkspace2 C:\\Users\\dojayama\\.vscode\\extensions\\pythonVSCode\\src\\testMultiRootWkspc\\workspace2\\workspace2File.py /^ def meth1OfWorkspace2(self, arg):$/;" kind:member line:11 +meth2 C:\\Users\\dojayama\\.vscode\\extensions\\pythonVSCode\\src\\testMultiRootWkspc\\workspace2\\file.py /^ def meth2(self, arg):$/;" kind:member line:15 +meth3 C:\\Users\\dojayama\\.vscode\\extensions\\pythonVSCode\\src\\testMultiRootWkspc\\workspace2\\file.py /^ def meth3(self):$/;" kind:member line:21 +meth4 C:\\Users\\dojayama\\.vscode\\extensions\\pythonVSCode\\src\\testMultiRootWkspc\\workspace2\\file.py /^ def meth4(self):$/;" kind:member line:28 +meth5 C:\\Users\\dojayama\\.vscode\\extensions\\pythonVSCode\\src\\testMultiRootWkspc\\workspace2\\file.py /^ def meth5(self):$/;" kind:member line:38 +meth6 C:\\Users\\dojayama\\.vscode\\extensions\\pythonVSCode\\src\\testMultiRootWkspc\\workspace2\\file.py /^ def meth6(self):$/;" kind:member line:53 +meth7 C:\\Users\\dojayama\\.vscode\\extensions\\pythonVSCode\\src\\testMultiRootWkspc\\workspace2\\file.py /^ def meth7(self):$/;" kind:member line:68 +meth8 C:\\Users\\dojayama\\.vscode\\extensions\\pythonVSCode\\src\\testMultiRootWkspc\\workspace2\\file.py /^ def meth8(self):$/;" kind:member line:80 +workspace2File.py C:\\Users\\dojayama\\.vscode\\extensions\\pythonVSCode\\src\\testMultiRootWkspc\\workspace2\\workspace2File.py 1;" kind:file line:1 diff --git a/src/testMultiRootWkspc/workspace2/workspace2File.py b/src/testMultiRootWkspc/workspace2/workspace2File.py new file mode 100644 index 000000000000..61aa87c55fed --- /dev/null +++ b/src/testMultiRootWkspc/workspace2/workspace2File.py @@ -0,0 +1,13 @@ +"""pylint option block-disable""" + +__revision__ = None + +class Workspace2Class(object): + """block-disable test""" + + def __init__(self): + pass + + def meth1OfWorkspace2(self, arg): + """this issues a message""" + print (self) diff --git a/src/testMultiRootWkspc/workspace3/.vscode/settings.json b/src/testMultiRootWkspc/workspace3/.vscode/settings.json new file mode 100644 index 000000000000..8779a0c08efe --- /dev/null +++ b/src/testMultiRootWkspc/workspace3/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "python.workspaceSymbols.tagFilePath": "${workspaceRoot}/workspace3.tags.file" +} diff --git a/src/testMultiRootWkspc/workspace3/file.py b/src/testMultiRootWkspc/workspace3/file.py new file mode 100644 index 000000000000..439f899e9e22 --- /dev/null +++ b/src/testMultiRootWkspc/workspace3/file.py @@ -0,0 +1,87 @@ +"""pylint option block-disable""" + +__revision__ = None + +class Foo(object): + """block-disable test""" + + def __init__(self): + pass + + def meth1(self, arg): + """this issues a message""" + print self + + def meth2(self, arg): + """and this one not""" + # pylint: disable=unused-argument + print self\ + + "foo" + + def meth3(self): + """test one line disabling""" + # no error + print self.bla # pylint: disable=no-member + # error + print self.blop + + def meth4(self): + """test re-enabling""" + # pylint: disable=no-member + # no error + print self.bla + print self.blop + # pylint: enable=no-member + # error + print self.blip + + def meth5(self): + """test IF sub-block re-enabling""" + # pylint: disable=no-member + # no error + print self.bla + if self.blop: + # pylint: enable=no-member + # error + print self.blip + else: + # no error + print self.blip + # no error + print self.blip + + def meth6(self): + """test TRY/EXCEPT sub-block re-enabling""" + # pylint: disable=no-member + # no error + print self.bla + try: + # pylint: enable=no-member + # error + print self.blip + except UndefinedName: # pylint: disable=undefined-variable + # no error + print self.blip + # no error + print self.blip + + def meth7(self): + """test one line block opening disabling""" + if self.blop: # pylint: disable=no-member + # error + print self.blip + else: + # error + print self.blip + # error + print self.blip + + + def meth8(self): + """test late disabling""" + # error + print self.blip + # pylint: disable=no-member + # no error + print self.bla + print self.blop diff --git a/src/testMultiRootWkspc/workspace3/workspace3.tags.file b/src/testMultiRootWkspc/workspace3/workspace3.tags.file new file mode 100644 index 000000000000..3a65841e2aff --- /dev/null +++ b/src/testMultiRootWkspc/workspace3/workspace3.tags.file @@ -0,0 +1,19 @@ +!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ +!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/ +!_TAG_OUTPUT_MODE u-ctags /u-ctags or e-ctags/ +!_TAG_PROGRAM_AUTHOR Universal Ctags Team // +!_TAG_PROGRAM_NAME Universal Ctags /Derived from Exuberant Ctags/ +!_TAG_PROGRAM_URL https://ctags.io/ /official site/ +!_TAG_PROGRAM_VERSION 0.0.0 /f9e6e3c1/ +Foo C:\\Users\\dojayama\\.vscode\\extensions\\pythonVSCode\\src\\testMultiRootWkspc\\workspace3\\file.py /^class Foo(object):$/;" kind:class line:5 +__init__ C:\\Users\\dojayama\\.vscode\\extensions\\pythonVSCode\\src\\testMultiRootWkspc\\workspace3\\file.py /^ def __init__(self):$/;" kind:member line:8 +__revision__ C:\\Users\\dojayama\\.vscode\\extensions\\pythonVSCode\\src\\testMultiRootWkspc\\workspace3\\file.py /^__revision__ = None$/;" kind:variable line:3 +file.py C:\\Users\\dojayama\\.vscode\\extensions\\pythonVSCode\\src\\testMultiRootWkspc\\workspace3\\file.py 1;" kind:file line:1 +meth1 C:\\Users\\dojayama\\.vscode\\extensions\\pythonVSCode\\src\\testMultiRootWkspc\\workspace3\\file.py /^ def meth1(self, arg):$/;" kind:member line:11 +meth2 C:\\Users\\dojayama\\.vscode\\extensions\\pythonVSCode\\src\\testMultiRootWkspc\\workspace3\\file.py /^ def meth2(self, arg):$/;" kind:member line:15 +meth3 C:\\Users\\dojayama\\.vscode\\extensions\\pythonVSCode\\src\\testMultiRootWkspc\\workspace3\\file.py /^ def meth3(self):$/;" kind:member line:21 +meth4 C:\\Users\\dojayama\\.vscode\\extensions\\pythonVSCode\\src\\testMultiRootWkspc\\workspace3\\file.py /^ def meth4(self):$/;" kind:member line:28 +meth5 C:\\Users\\dojayama\\.vscode\\extensions\\pythonVSCode\\src\\testMultiRootWkspc\\workspace3\\file.py /^ def meth5(self):$/;" kind:member line:38 +meth6 C:\\Users\\dojayama\\.vscode\\extensions\\pythonVSCode\\src\\testMultiRootWkspc\\workspace3\\file.py /^ def meth6(self):$/;" kind:member line:53 +meth7 C:\\Users\\dojayama\\.vscode\\extensions\\pythonVSCode\\src\\testMultiRootWkspc\\workspace3\\file.py /^ def meth7(self):$/;" kind:member line:68 +meth8 C:\\Users\\dojayama\\.vscode\\extensions\\pythonVSCode\\src\\testMultiRootWkspc\\workspace3\\file.py /^ def meth8(self):$/;" kind:member line:80