From 843ff4b5c36b52c6782b380a6a66c510223d1e5f Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Fri, 16 Jul 2021 10:10:45 -0700 Subject: [PATCH 01/39] migrating User PR to test branch: Fix broken unittest test discovery (#16703) * Fix broken unittest test discovery Test discovery with unittest was not working at all. This is now fixed with a more reliable method. (Issue 16593) * Fix typo Somehow I managed to typo such a simple change. Co-authored-by: Julian Edwards --- news/2 Fixes/16593.md | 1 + .../unittest/services/discoveryService.ts | 16 ++++++++-------- 2 files changed, 9 insertions(+), 8 deletions(-) create mode 100644 news/2 Fixes/16593.md diff --git a/news/2 Fixes/16593.md b/news/2 Fixes/16593.md new file mode 100644 index 000000000000..7c07ec087340 --- /dev/null +++ b/news/2 Fixes/16593.md @@ -0,0 +1 @@ +Fix unittest discovery. (thanks [JulianEdwards](https://github.com/bigjools)) diff --git a/src/client/testing/unittest/services/discoveryService.ts b/src/client/testing/unittest/services/discoveryService.ts index 0f42d36d1fcc..351341eb6665 100644 --- a/src/client/testing/unittest/services/discoveryService.ts +++ b/src/client/testing/unittest/services/discoveryService.ts @@ -56,16 +56,16 @@ export class TestDiscoveryService implements ITestDiscoveryService { const unitTestOptions = this.translateOptions(options); return ` import unittest +def generate_test_cases(suite): + for test in suite: + if isinstance(test, unittest.TestCase): + yield test + else: + yield from generate_test_cases(test) loader = unittest.TestLoader() -suites = loader.discover("${unitTestOptions.startDirectory}", pattern="${unitTestOptions.pattern}") +suite = loader.discover("${unitTestOptions.startDirectory}", pattern="${unitTestOptions.pattern}") print("start") #Don't remove this line -for suite in suites._tests: - for cls in suite._tests: - try: - for m in cls._tests: - print(m.id()) - except: - pass`; +print("\n".join(s.id() for s in generate_test_cases(suite)))`; } public translateOptions(options: TestDiscoveryOptions): UnitTestDiscoveryOptions { return { From 5819912b3762fa8322709d22132a4d9e6903e97c Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Mon, 10 May 2021 16:11:38 -0700 Subject: [PATCH 02/39] Remove code lenses used in tests (#16200) --- src/client/testing/codeLenses/main.ts | 27 -- src/client/testing/codeLenses/testFiles.ts | 321 ------------------ src/client/testing/main.ts | 21 +- .../testing/codeLenses/testFiles.unit.test.ts | 154 --------- src/test/testing/main.unit.test.ts | 4 +- 5 files changed, 2 insertions(+), 525 deletions(-) delete mode 100644 src/client/testing/codeLenses/main.ts delete mode 100644 src/client/testing/codeLenses/testFiles.ts delete mode 100644 src/test/testing/codeLenses/testFiles.unit.test.ts diff --git a/src/client/testing/codeLenses/main.ts b/src/client/testing/codeLenses/main.ts deleted file mode 100644 index 9c2a7e688ee9..000000000000 --- a/src/client/testing/codeLenses/main.ts +++ /dev/null @@ -1,27 +0,0 @@ -import * as vscode from 'vscode'; -import { IServiceContainer } from '../../../client/ioc/types'; -import { PYTHON } from '../../common/constants'; -import { ITestCollectionStorageService } from '../common/types'; -import { TestFileCodeLensProvider } from './testFiles'; - -export function activateCodeLenses( - onDidChange: vscode.EventEmitter, - symbolProvider: vscode.DocumentSymbolProvider, - testCollectionStorage: ITestCollectionStorageService, - serviceContainer: IServiceContainer, -): vscode.Disposable { - const disposables: vscode.Disposable[] = []; - const codeLensProvider = new TestFileCodeLensProvider( - onDidChange, - symbolProvider, - testCollectionStorage, - serviceContainer, - ); - disposables.push(vscode.languages.registerCodeLensProvider(PYTHON, codeLensProvider)); - - return { - dispose: () => { - disposables.forEach((d) => d.dispose()); - }, - }; -} diff --git a/src/client/testing/codeLenses/testFiles.ts b/src/client/testing/codeLenses/testFiles.ts deleted file mode 100644 index 16cb2f5ef8de..000000000000 --- a/src/client/testing/codeLenses/testFiles.ts +++ /dev/null @@ -1,321 +0,0 @@ -'use strict'; - -import { - CancellationToken, - CancellationTokenSource, - CodeLens, - CodeLensProvider, - DocumentSymbolProvider, - Event, - EventEmitter, - Position, - Range, - SymbolInformation, - SymbolKind, - TextDocument, - Uri, -} from 'vscode'; -import { IWorkspaceService } from '../../../client/common/application/types'; -import { IFileSystem } from '../../../client/common/platform/types'; -import { IServiceContainer } from '../../../client/ioc/types'; -import * as constants from '../../common/constants'; -import { - ITestCollectionStorageService, - TestFile, - TestFunction, - TestStatus, - TestsToRun, - TestSuite, -} from '../common/types'; - -type FunctionsAndSuites = { - functions: TestFunction[]; - suites: TestSuite[]; -}; - -export class TestFileCodeLensProvider implements CodeLensProvider { - private workspaceService: IWorkspaceService; - private fileSystem: IFileSystem; - - constructor( - private _onDidChange: EventEmitter, - private symbolProvider: DocumentSymbolProvider, - private testCollectionStorage: ITestCollectionStorageService, - serviceContainer: IServiceContainer, - ) { - this.workspaceService = serviceContainer.get(IWorkspaceService); - this.fileSystem = serviceContainer.get(IFileSystem); - } - - get onDidChangeCodeLenses(): Event { - return this._onDidChange.event; - } - - public async provideCodeLenses(document: TextDocument, token: CancellationToken) { - const wkspace = this.workspaceService.getWorkspaceFolder(document.uri); - if (!wkspace) { - return []; - } - const testItems = this.testCollectionStorage.getTests(wkspace.uri); - if (!testItems || testItems.testFiles.length === 0 || testItems.testFunctions.length === 0) { - return []; - } - - const cancelTokenSrc = new CancellationTokenSource(); - token.onCancellationRequested(() => { - cancelTokenSrc.cancel(); - }); - - // Strop trying to build the code lenses if unable to get a list of - // symbols in this file afrer x time. - setTimeout(() => { - if (!cancelTokenSrc.token.isCancellationRequested) { - cancelTokenSrc.cancel(); - } - }, constants.Delays.MaxUnitTestCodeLensDelay); - - return this.getCodeLenses(document, cancelTokenSrc.token, this.symbolProvider); - } - - public resolveCodeLens(codeLens: CodeLens, _token: CancellationToken): CodeLens | Thenable { - codeLens.command = { command: 'python.runtests', title: 'Test' }; - return Promise.resolve(codeLens); - } - - public getTestFileWhichNeedsCodeLens(document: TextDocument): TestFile | undefined { - const wkspace = this.workspaceService.getWorkspaceFolder(document.uri); - if (!wkspace) { - return; - } - const tests = this.testCollectionStorage.getTests(wkspace.uri); - if (!tests) { - return; - } - return tests.testFiles.find((item) => this.fileSystem.arePathsSame(item.fullPath, document.uri.fsPath)); - } - - private async getCodeLenses( - document: TextDocument, - token: CancellationToken, - symbolProvider: DocumentSymbolProvider, - ) { - const file = this.getTestFileWhichNeedsCodeLens(document); - if (!file) { - return []; - } - const allFuncsAndSuites = getAllTestSuitesAndFunctionsPerFile(file); - - try { - const symbols = (await symbolProvider.provideDocumentSymbols(document, token)) as SymbolInformation[]; - if (!symbols) { - return []; - } - return symbols - .filter( - (symbol) => - symbol.kind === SymbolKind.Function || - symbol.kind === SymbolKind.Method || - symbol.kind === SymbolKind.Class, - ) - .map((symbol) => { - // This is crucial, if the start and end columns are the same then vscode bugs out - // whenever you edit a line (start scrolling magically). - const range = new Range( - symbol.location.range.start, - new Position(symbol.location.range.end.line, symbol.location.range.end.character + 1), - ); - - return this.getCodeLens( - document.uri, - allFuncsAndSuites, - range, - symbol.name, - symbol.kind, - symbol.containerName, - ); - }) - .reduce((previous, current) => previous.concat(current), []) - .filter((codeLens) => codeLens !== null); - } catch (reason) { - if (token.isCancellationRequested) { - return []; - } - return Promise.reject(reason); - } - } - - private getCodeLens( - file: Uri, - allFuncsAndSuites: FunctionsAndSuites, - range: Range, - symbolName: string, - symbolKind: SymbolKind, - symbolContainer: string, - ): CodeLens[] { - switch (symbolKind) { - case SymbolKind.Function: - case SymbolKind.Method: { - return getFunctionCodeLens(file, allFuncsAndSuites, symbolName, range, symbolContainer); - } - case SymbolKind.Class: { - const cls = allFuncsAndSuites.suites.find((item) => item.name === symbolName); - if (!cls) { - return []; - } - return [ - new CodeLens(range, { - title: getTestStatusIcon(cls.status) + constants.Text.CodeLensRunUnitTest, - command: constants.Commands.Tests_Run, - arguments: [ - undefined, - constants.CommandSource.codelens, - file, - { testSuite: [cls] }, - ], - }), - new CodeLens(range, { - title: getTestStatusIcon(cls.status) + constants.Text.CodeLensDebugUnitTest, - command: constants.Commands.Tests_Debug, - arguments: [ - undefined, - constants.CommandSource.codelens, - file, - { testSuite: [cls] }, - ], - }), - ]; - } - default: { - return []; - } - } - } -} - -function getTestStatusIcon(status?: TestStatus): string { - switch (status) { - case TestStatus.Pass: { - return `${constants.Octicons.Test_Pass} `; - } - case TestStatus.Error: { - return `${constants.Octicons.Test_Error} `; - } - case TestStatus.Fail: { - return `${constants.Octicons.Test_Fail} `; - } - case TestStatus.Skipped: { - return `${constants.Octicons.Test_Skip} `; - } - default: { - return ''; - } - } -} - -function getTestStatusIcons(fns: TestFunction[]): string { - const statuses: string[] = []; - let count = fns.filter((fn) => fn.status === TestStatus.Pass).length; - if (count > 0) { - statuses.push(`${constants.Octicons.Test_Pass} ${count}`); - } - count = fns.filter((fn) => fn.status === TestStatus.Skipped).length; - if (count > 0) { - statuses.push(`${constants.Octicons.Test_Skip} ${count}`); - } - count = fns.filter((fn) => fn.status === TestStatus.Fail).length; - if (count > 0) { - statuses.push(`${constants.Octicons.Test_Fail} ${count}`); - } - count = fns.filter((fn) => fn.status === TestStatus.Error).length; - if (count > 0) { - statuses.push(`${constants.Octicons.Test_Error} ${count}`); - } - - return statuses.join(' '); -} -function getFunctionCodeLens( - file: Uri, - functionsAndSuites: FunctionsAndSuites, - symbolName: string, - range: Range, - symbolContainer: string, -): CodeLens[] { - let fn: TestFunction | undefined; - if (symbolContainer.length === 0) { - fn = functionsAndSuites.functions.find((func) => func.name === symbolName); - } else { - // Assume single levels for now. - functionsAndSuites.suites - .filter((s) => s.name === symbolContainer) - .forEach((s) => { - const f = s.functions.find((item) => item.name === symbolName); - if (f) { - fn = f; - } - }); - } - - if (fn) { - return [ - new CodeLens(range, { - title: getTestStatusIcon(fn.status) + constants.Text.CodeLensRunUnitTest, - command: constants.Commands.Tests_Run, - arguments: [undefined, constants.CommandSource.codelens, file, { testFunction: [fn] }], - }), - new CodeLens(range, { - title: getTestStatusIcon(fn.status) + constants.Text.CodeLensDebugUnitTest, - command: constants.Commands.Tests_Debug, - arguments: [undefined, constants.CommandSource.codelens, file, { testFunction: [fn] }], - }), - ]; - } - - // Ok, possible we're dealing with parameterized unit tests. - // If we have [ in the name, then this is a parameterized function. - const functions = functionsAndSuites.functions.filter( - (func) => func.name.startsWith(`${symbolName}[`) && func.name.endsWith(']'), - ); - if (functions.length === 0) { - return []; - } - - // Find all flattened functions. - return [ - new CodeLens(range, { - title: `${getTestStatusIcons(functions)} ${constants.Text.CodeLensRunUnitTest} (Multiple)`, - command: constants.Commands.Tests_Picker_UI, - arguments: [undefined, constants.CommandSource.codelens, file, functions], - }), - new CodeLens(range, { - title: `${getTestStatusIcons(functions)} ${constants.Text.CodeLensDebugUnitTest} (Multiple)`, - command: constants.Commands.Tests_Picker_UI_Debug, - arguments: [undefined, constants.CommandSource.codelens, file, functions], - }), - ]; -} - -function getAllTestSuitesAndFunctionsPerFile(testFile: TestFile): FunctionsAndSuites { - const all = { functions: [...testFile.functions], suites: [] as TestSuite[] }; - testFile.suites.forEach((suite) => { - all.suites.push(suite); - - const allChildItems = getAllTestSuitesAndFunctions(suite); - all.functions.push(...allChildItems.functions); - all.suites.push(...allChildItems.suites); - }); - return all; -} -function getAllTestSuitesAndFunctions(testSuite: TestSuite): FunctionsAndSuites { - const all: { functions: TestFunction[]; suites: TestSuite[] } = { functions: [], suites: [] }; - testSuite.functions.forEach((fn) => { - all.functions.push(fn); - }); - testSuite.suites.forEach((suite) => { - all.suites.push(suite); - - const allChildItems = getAllTestSuitesAndFunctions(suite); - all.functions.push(...allChildItems.functions); - all.suites.push(...allChildItems.suites); - }); - return all; -} diff --git a/src/client/testing/main.ts b/src/client/testing/main.ts index 965a81c5d713..4eb2bafc6c67 100644 --- a/src/client/testing/main.ts +++ b/src/client/testing/main.ts @@ -21,7 +21,6 @@ import { IInterpreterService } from '../interpreter/contracts'; import { IServiceContainer } from '../ioc/types'; import { EventName } from '../telemetry/constants'; import { captureTelemetry, sendTelemetryEvent } from '../telemetry/index'; -import { activateCodeLenses } from './codeLenses/main'; import { CANCELLATION_REASON } from './common/constants'; import { selectTestWorkspace } from './common/testUtils'; import { TestSettingsPropertyNames } from './configuration/types'; @@ -103,7 +102,7 @@ export class UnitTestManagementService implements ITestManagementService, Dispos public get onDidStatusChange(): Event { return this._onDidStatusChange.event; } - public async activate(symbolProvider: DocumentSymbolProvider): Promise { + public async activate(): Promise { if (this.activatedOnce) { return; } @@ -117,7 +116,6 @@ export class UnitTestManagementService implements ITestManagementService, Dispos this.autoDiscoverTests(undefined).catch((ex) => traceError('Failed to auto discover tests upon activation', ex), ); - await this.registerSymbolProvider(symbolProvider); } public async getTestManager( displayTestNotConfiguredMessage: boolean, @@ -432,23 +430,6 @@ export class UnitTestManagementService implements ITestManagementService, Dispos await promise; } - public async registerSymbolProvider(symbolProvider: DocumentSymbolProvider): Promise { - const testCollectionStorage = this.serviceContainer.get( - ITestCollectionStorageService, - ); - const event = new EventEmitter(); - this.disposableRegistry.push(event); - const handler = this._onDidStatusChange.event((e) => { - if (e.status !== TestStatus.Discovering && e.status !== TestStatus.Running) { - event.fire(); - } - }); - this.disposableRegistry.push(handler); - this.disposableRegistry.push( - activateCodeLenses(event, symbolProvider, testCollectionStorage, this.serviceContainer), - ); - } - @captureTelemetry(EventName.UNITTEST_CONFIGURE, undefined, false) public async configureTests(resource?: Uri) { let wkspace: Uri | undefined; diff --git a/src/test/testing/codeLenses/testFiles.unit.test.ts b/src/test/testing/codeLenses/testFiles.unit.test.ts deleted file mode 100644 index 5a42bac1b5aa..000000000000 --- a/src/test/testing/codeLenses/testFiles.unit.test.ts +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { assert, expect } from 'chai'; -import { mock } from 'ts-mockito'; -import * as typemoq from 'typemoq'; -import { DocumentSymbolProvider, EventEmitter, Uri } from 'vscode'; -import { IWorkspaceService } from '../../../client/common/application/types'; -import { IFileSystem } from '../../../client/common/platform/types'; -import { IServiceContainer } from '../../../client/ioc/types'; -import { LanguageServerSymbolProvider } from '../../../client/providers/symbolProvider'; -import { TestFileCodeLensProvider } from '../../../client/testing/codeLenses/testFiles'; -import { ITestCollectionStorageService } from '../../../client/testing/common/types'; - -suite('Code lenses - Test files', () => { - let testCollectionStorage: typemoq.IMock; - let workspaceService: typemoq.IMock; - let fileSystem: typemoq.IMock; - let serviceContainer: typemoq.IMock; - let symbolProvider: DocumentSymbolProvider; - let onDidChange: EventEmitter; - let codeLensProvider: TestFileCodeLensProvider; - setup(() => { - workspaceService = typemoq.Mock.ofType(); - fileSystem = typemoq.Mock.ofType(); - testCollectionStorage = typemoq.Mock.ofType(); - serviceContainer = typemoq.Mock.ofType(); - symbolProvider = mock(LanguageServerSymbolProvider); - onDidChange = new EventEmitter(); - serviceContainer - .setup((c) => c.get(typemoq.It.isValue(IWorkspaceService))) - .returns(() => workspaceService.object); - serviceContainer.setup((c) => c.get(typemoq.It.isValue(IFileSystem))).returns(() => fileSystem.object); - codeLensProvider = new TestFileCodeLensProvider( - onDidChange, - symbolProvider, - testCollectionStorage.object, - serviceContainer.object, - ); - }); - - teardown(() => { - onDidChange.dispose(); - }); - - test('Function getTestFileWhichNeedsCodeLens() returns `undefined` if there are no workspace corresponding to document', async () => { - const document = { - uri: Uri.file('path/to/document'), - }; - workspaceService - .setup((w) => w.getWorkspaceFolder(document.uri)) - .returns(() => undefined) - .verifiable(typemoq.Times.once()); - testCollectionStorage - .setup((w) => w.getTests(typemoq.It.isAny())) - .returns(() => undefined) - .verifiable(typemoq.Times.never()); - const files = codeLensProvider.getTestFileWhichNeedsCodeLens(document as any); - expect(files).to.equal(undefined, 'No files should be returned'); - workspaceService.verifyAll(); - testCollectionStorage.verifyAll(); - }); - - test('Function getTestFileWhichNeedsCodeLens() returns `undefined` if test storage is empty', async () => { - const document = { - uri: Uri.file('path/to/document'), - }; - const workspaceUri = Uri.file('path/to/workspace'); - const workspace = { uri: workspaceUri }; - workspaceService - .setup((w) => w.getWorkspaceFolder(document.uri)) - .returns(() => workspace as any) - .verifiable(typemoq.Times.once()); - testCollectionStorage - .setup((w) => w.getTests(workspaceUri)) - .returns(() => undefined) - .verifiable(typemoq.Times.once()); - const files = codeLensProvider.getTestFileWhichNeedsCodeLens(document as any); - expect(files).to.equal(undefined, 'No files should be returned'); - workspaceService.verifyAll(); - testCollectionStorage.verifyAll(); - }); - - test('Function getTestFileWhichNeedsCodeLens() returns `undefined` if tests returned from storage does not contain document', async () => { - const document = { - uri: Uri.file('path/to/document5'), - }; - const workspaceUri = Uri.file('path/to/workspace'); - const workspace = { uri: workspaceUri }; - const tests = { - testFiles: [ - { - fullPath: 'path/to/document1', - }, - { - fullPath: 'path/to/document2', - }, - ], - }; - workspaceService - .setup((w) => w.getWorkspaceFolder(document.uri)) - .returns(() => workspace as any) - .verifiable(typemoq.Times.once()); - testCollectionStorage - .setup((w) => w.getTests(workspaceUri)) - .returns(() => tests as any) - .verifiable(typemoq.Times.once()); - fileSystem.setup((f) => f.arePathsSame('path/to/document1', 'path/to/document5')).returns(() => false); - fileSystem.setup((f) => f.arePathsSame('path/to/document2', 'path/to/document5')).returns(() => false); - const files = codeLensProvider.getTestFileWhichNeedsCodeLens(document as any); - expect(files).to.equal(undefined, 'No files should be returned'); - workspaceService.verifyAll(); - testCollectionStorage.verifyAll(); - }); - - test('Function getTestFileWhichNeedsCodeLens() returns test file if tests returned from storage contains document', async () => { - const document = { - uri: Uri.file('path/to/document2'), - }; - const workspaceUri = Uri.file('path/to/workspace'); - const workspace = { uri: workspaceUri }; - const testFile2 = { - fullPath: Uri.file('path/to/document2').fsPath, - }; - const tests = { - testFiles: [ - { - fullPath: Uri.file('path/to/document1').fsPath, - }, - testFile2, - ], - }; - workspaceService - .setup((w) => w.getWorkspaceFolder(typemoq.It.isValue(document.uri))) - .returns(() => workspace as any) - .verifiable(typemoq.Times.once()); - testCollectionStorage - .setup((w) => w.getTests(typemoq.It.isValue(workspaceUri))) - .returns(() => tests as any) - .verifiable(typemoq.Times.once()); - fileSystem - .setup((f) => f.arePathsSame(Uri.file('/path/to/document1').fsPath, Uri.file('/path/to/document2').fsPath)) - .returns(() => false); - fileSystem - .setup((f) => f.arePathsSame(Uri.file('/path/to/document2').fsPath, Uri.file('/path/to/document2').fsPath)) - .returns(() => true); - const files = codeLensProvider.getTestFileWhichNeedsCodeLens(document as any); - assert.deepEqual(files, testFile2 as any); - workspaceService.verifyAll(); - testCollectionStorage.verifyAll(); - }); -}); diff --git a/src/test/testing/main.unit.test.ts b/src/test/testing/main.unit.test.ts index bef1c18e3358..821eb1a408b3 100644 --- a/src/test/testing/main.unit.test.ts +++ b/src/test/testing/main.unit.test.ts @@ -11,7 +11,6 @@ import { ICommandManager } from '../../client/common/application/types'; import { IDisposableRegistry } from '../../client/common/types'; import { ServiceContainer } from '../../client/ioc/container'; import { IServiceContainer } from '../../client/ioc/types'; -import { JediSymbolProvider } from '../../client/providers/symbolProvider'; import { UnitTestManagementService } from '../../client/testing/main'; suite('Unit Tests - ManagementService', () => { @@ -24,7 +23,6 @@ suite('Unit Tests - ManagementService', () => { serviceContainer = mock(ServiceContainer); sandbox = sinon.createSandbox(); - sandbox.stub(UnitTestManagementService.prototype, 'registerSymbolProvider'); sandbox.stub(UnitTestManagementService.prototype, 'registerCommands'); sandbox.stub(UnitTestManagementService.prototype, 'registerHandlers'); sandbox.stub(UnitTestManagementService.prototype, 'autoDiscoverTests').callsFake(() => Promise.resolve()); @@ -42,7 +40,7 @@ suite('Unit Tests - ManagementService', () => { }); test('Do not execute command', async () => { - await testManagementService.activate(instance(mock(JediSymbolProvider))); + await testManagementService.activate(); verify(commandManager.executeCommand('setContext', 'testsDiscovered', anything())).never(); }); From e72ccc04cff15c2db4f7c620f0c678d2ae5f155a Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Tue, 11 May 2021 17:42:02 -0700 Subject: [PATCH 03/39] Add test view with a welcome button (#16215) * Add test view with a welcome button * Register registerTestController only when available. --- package.json | 16 +- src/client/testing/explorer/treeView.ts | 45 -- src/client/testing/main.ts | 6 + src/client/testing/serviceRegistry.ts | 2 - .../testing/testController/controller.ts | 18 + .../testing/explorer/treeView.unit.test.ts | 68 -- types/vscode.proposed.d.ts | 584 ++++++++++++++++++ 7 files changed, 615 insertions(+), 124 deletions(-) delete mode 100644 src/client/testing/explorer/treeView.ts create mode 100644 src/client/testing/testController/controller.ts delete mode 100644 src/test/testing/explorer/treeView.unit.test.ts diff --git a/package.json b/package.json index c44e607457de..59d3df7bb51f 100644 --- a/package.json +++ b/package.json @@ -2161,15 +2161,13 @@ } ] }, - "views": { - "test": [ - { - "id": "python_tests", - "name": "Python", - "when": "testsDiscovered" - } - ] - }, + "viewsWelcome": [ + { + "view": "testing", + "contents": "Configure a test framework to see your tests here.\n[Configure Python Tests](command:python.configureTests)", + "when": "!testsDiscovered" + } + ], "yamlValidation": [ { "fileMatch": ".condarc", diff --git a/src/client/testing/explorer/treeView.ts b/src/client/testing/explorer/treeView.ts deleted file mode 100644 index 3354de051b6f..000000000000 --- a/src/client/testing/explorer/treeView.ts +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { inject, injectable } from 'inversify'; -import { TreeView } from 'vscode'; -import { IExtensionSingleActivationService } from '../../activation/types'; -import { IApplicationShell, ICommandManager } from '../../common/application/types'; -import { Commands } from '../../common/constants'; -import { IDisposable, IDisposableRegistry } from '../../common/types'; -import { ITestTreeViewProvider, TestDataItem } from '../common/types'; - -@injectable() -export class TreeViewService implements IExtensionSingleActivationService, IDisposable { - private _treeView!: TreeView; - private readonly disposables: IDisposable[] = []; - public get treeView(): TreeView { - return this._treeView; - } - constructor( - @inject(ITestTreeViewProvider) private readonly treeViewProvider: ITestTreeViewProvider, - @inject(IDisposableRegistry) disposableRegistry: IDisposableRegistry, - @inject(IApplicationShell) private readonly appShell: IApplicationShell, - @inject(ICommandManager) private readonly commandManager: ICommandManager, - ) { - disposableRegistry.push(this); - } - public dispose() { - this.disposables.forEach((d) => d.dispose()); - } - public async activate(): Promise { - this._treeView = this.appShell.createTreeView('python_tests', { - showCollapseAll: true, - treeDataProvider: this.treeViewProvider, - }); - this.disposables.push(this._treeView); - this.disposables.push( - this.commandManager.registerCommand(Commands.Test_Reveal_Test_Item, this.onRevealTestItem, this), - ); - } - public async onRevealTestItem(testItem: TestDataItem): Promise { - await this.treeView.reveal(testItem, { select: false }); - } -} diff --git a/src/client/testing/main.ts b/src/client/testing/main.ts index 4eb2bafc6c67..9d4723ad223e 100644 --- a/src/client/testing/main.ts +++ b/src/client/testing/main.ts @@ -8,6 +8,7 @@ import { Event, EventEmitter, OutputChannel, + test, TextDocument, Uri, } from 'vscode'; @@ -43,6 +44,7 @@ import { } from './common/types'; import { TEST_OUTPUT_CHANNEL } from './constants'; import { ITestingService } from './types'; +import { PythonTestController } from './testController/controller'; @injectable() export class TestingService implements ITestingService { @@ -116,6 +118,10 @@ export class UnitTestManagementService implements ITestManagementService, Dispos this.autoDiscoverTests(undefined).catch((ex) => traceError('Failed to auto discover tests upon activation', ex), ); + + if (test && test.registerTestController) { + this.disposableRegistry.push(test.registerTestController(new PythonTestController())); + } } public async getTestManager( displayTestNotConfiguredMessage: boolean, diff --git a/src/client/testing/serviceRegistry.ts b/src/client/testing/serviceRegistry.ts index 4580de322f18..28342b97b04c 100644 --- a/src/client/testing/serviceRegistry.ts +++ b/src/client/testing/serviceRegistry.ts @@ -65,7 +65,6 @@ import { TestDisplay } from './display/picker'; import { TestExplorerCommandHandler } from './explorer/commandHandlers'; import { FailedTestHandler } from './explorer/failedTestHandler'; import { TestTreeViewProvider } from './explorer/testTreeViewProvider'; -import { TreeViewService } from './explorer/treeView'; import { TestingService, UnitTestManagementService } from './main'; import { registerTypes as registerNavigationTypes } from './navigation/serviceRegistry'; import { ITestExplorerCommandHandler } from './navigation/types'; @@ -148,7 +147,6 @@ export function registerTypes(serviceManager: IServiceManager) { serviceManager.addSingleton(ITestTreeViewProvider, TestTreeViewProvider); serviceManager.addSingleton(ITestDataItemResource, TestTreeViewProvider); serviceManager.addSingleton(ITestExplorerCommandHandler, TestExplorerCommandHandler); - serviceManager.addSingleton(IExtensionSingleActivationService, TreeViewService); serviceManager.addSingleton( IExtensionSingleActivationService, FailedTestHandler, diff --git a/src/client/testing/testController/controller.ts b/src/client/testing/testController/controller.ts new file mode 100644 index 000000000000..97f45a90a1a9 --- /dev/null +++ b/src/client/testing/testController/controller.ts @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { TestController } from 'vscode'; +/* eslint-disable */ + +// This is a place holder for a controller +export class PythonTestController implements TestController { + public createWorkspaceTestRoot() { + return undefined; + } + + public createDocumentTestRoot() { + return undefined; + } + + public runTests() {} +} diff --git a/src/test/testing/explorer/treeView.unit.test.ts b/src/test/testing/explorer/treeView.unit.test.ts deleted file mode 100644 index 8002eb6dc5f0..000000000000 --- a/src/test/testing/explorer/treeView.unit.test.ts +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { anything, deepEqual, instance, mock, verify, when } from 'ts-mockito'; -import * as typemoq from 'typemoq'; -import { TreeView } from 'vscode'; -import { ApplicationShell } from '../../../client/common/application/applicationShell'; -import { CommandManager } from '../../../client/common/application/commandManager'; -import { IApplicationShell, ICommandManager } from '../../../client/common/application/types'; -import { Commands } from '../../../client/common/constants'; -import { ITestTreeViewProvider, TestDataItem } from '../../../client/testing/common/types'; -import { TestTreeViewProvider } from '../../../client/testing/explorer/testTreeViewProvider'; -import { TreeViewService } from '../../../client/testing/explorer/treeView'; - -suite('Unit Tests Test Explorer Tree View', () => { - let treeViewService: TreeViewService; - let treeView: typemoq.IMock>; - let commandManager: ICommandManager; - let appShell: IApplicationShell; - let treeViewProvider: ITestTreeViewProvider; - setup(() => { - commandManager = mock(CommandManager); - treeViewProvider = mock(TestTreeViewProvider); - appShell = mock(ApplicationShell); - treeView = typemoq.Mock.ofType>(); - treeViewService = new TreeViewService( - instance(treeViewProvider), - [], - instance(appShell), - instance(commandManager), - ); - }); - - test('Activation will create the treeview', async () => { - await treeViewService.activate(); - verify( - appShell.createTreeView( - 'python_tests', - deepEqual({ showCollapseAll: true, treeDataProvider: instance(treeViewProvider) }), - ), - ).once(); - }); - test('Activation will add command handlers', async () => { - await treeViewService.activate(); - verify( - commandManager.registerCommand( - Commands.Test_Reveal_Test_Item, - treeViewService.onRevealTestItem, - treeViewService, - ), - ).once(); - }); - test('Invoking the command handler will reveal the node in the tree', async () => { - const data = {} as any; - treeView - .setup((t) => t.reveal(typemoq.It.isAny(), { select: false })) - .returns(() => Promise.resolve()) - .verifiable(typemoq.Times.once()); - when(appShell.createTreeView('python_tests', anything())).thenReturn(treeView.object); - - await treeViewService.activate(); - await treeViewService.onRevealTestItem(data); - - treeView.verifyAll(); - }); -}); diff --git a/types/vscode.proposed.d.ts b/types/vscode.proposed.d.ts index c81c63d8a2ca..ef765c720354 100644 --- a/types/vscode.proposed.d.ts +++ b/types/vscode.proposed.d.ts @@ -930,5 +930,589 @@ declare module 'vscode' { } //#endregion + + //#region https://github.com/microsoft/vscode/issues/107467 + export namespace test { + /** + * Registers a controller that can discover and + * run tests in workspaces and documents. + */ + export function registerTestController(testController: TestController): Disposable; + + /** + * Requests that tests be run by their controller. + * @param run Run options to use + * @param token Cancellation token for the test run + */ + export function runTests(run: TestRunRequest, token?: CancellationToken): Thenable; + + /** + * Returns an observer that retrieves tests in the given workspace folder. + * @stability experimental + */ + export function createWorkspaceTestObserver(workspaceFolder: WorkspaceFolder): TestObserver; + + /** + * Returns an observer that retrieves tests in the given text document. + * @stability experimental + */ + export function createDocumentTestObserver(document: TextDocument): TestObserver; + + /** + * Creates a {@link TestRun}. This should be called by the + * {@link TestRunner} when a request is made to execute tests, and may also + * be called if a test run is detected externally. Once created, tests + * that are included in the results will be moved into the + * {@link TestResultState.Pending} state. + * + * @param request Test run request. Only tests inside the `include` may be + * modified, and tests in its `exclude` are ignored. + * @param name The human-readable name of the run. This can be used to + * disambiguate multiple sets of results in a test run. It is useful if + * tests are run across multiple platforms, for example. + * @param persist Whether the results created by the run should be + * persisted in VS Code. This may be false if the results are coming from + * a file already saved externally, such as a coverage information file. + */ + export function createTestRun(request: TestRunRequest, name?: string, persist?: boolean): TestRun; + + /** + * Creates a new managed {@link TestItem} instance. + * @param options Initial/required options for the item + * @param data Custom data to be stored in {@link TestItem.data} + */ + export function createTestItem(options: TestItemOptions, data: T): TestItem; + + /** + * Creates a new managed {@link TestItem} instance. + * @param options Initial/required options for the item + */ + export function createTestItem(options: TestItemOptions): TestItem; + + /** + * List of test results stored by VS Code, sorted in descnding + * order by their `completedAt` time. + * @stability experimental + */ + export const testResults: ReadonlyArray; + + /** + * Event that fires when the {@link testResults} array is updated. + * @stability experimental + */ + export const onDidChangeTestResults: Event; + } + + /** + * @stability experimental + */ + export interface TestObserver { + /** + * List of tests returned by test provider for files in the workspace. + */ + readonly tests: ReadonlyArray>; + + /** + * An event that fires when an existing test in the collection changes, or + * null if a top-level test was added or removed. When fired, the consumer + * should check the test item and all its children for changes. + */ + readonly onDidChangeTest: Event; + + /** + * An event that fires when all test providers have signalled that the tests + * the observer references have been discovered. Providers may continue to + * watch for changes and cause {@link onDidChangeTest} to fire as files + * change, until the observer is disposed. + * + * @todo as below + */ + readonly onDidDiscoverInitialTests: Event; + + /** + * Dispose of the observer, allowing VS Code to eventually tell test + * providers that they no longer need to update tests. + */ + dispose(): void; + } + + /** + * @stability experimental + */ + export interface TestsChangeEvent { + /** + * List of all tests that are newly added. + */ + readonly added: ReadonlyArray>; + + /** + * List of existing tests that have updated. + */ + readonly updated: ReadonlyArray>; + + /** + * List of existing tests that have been removed. + */ + readonly removed: ReadonlyArray>; + } + + /** + * Interface to discover and execute tests. + */ + export interface TestController { + /** + * Requests that tests be provided for the given workspace. This will + * be called when tests need to be enumerated for the workspace, such as + * when the user opens the test explorer. + * + * It's guaranteed that this method will not be called again while + * there is a previous uncancelled call for the given workspace folder. + * + * @param workspace The workspace in which to observe tests + * @param cancellationToken Token that signals the used asked to abort the test run. + * @returns the root test item for the workspace + */ + createWorkspaceTestRoot(workspace: WorkspaceFolder, token: CancellationToken): ProviderResult>; + + /** + * Requests that tests be provided for the given document. This will be + * called when tests need to be enumerated for a single open file, for + * instance by code lens UI. + * + * It's suggested that the provider listen to change events for the text + * document to provide information for tests that might not yet be + * saved. + * + * If the test system is not able to provide or estimate for tests on a + * per-file basis, this method may not be implemented. In that case, the + * editor will request and use the information from the workspace tree. + * + * @param document The document in which to observe tests + * @param cancellationToken Token that signals the used asked to abort the test run. + * @returns the root test item for the document + */ + createDocumentTestRoot?(document: TextDocument, token: CancellationToken): ProviderResult>; + + /** + * Starts a test run. When called, the controller should call + * {@link vscode.test.createTestRun}. All tasks associated with the + * run should be created before the function returns or the reutrned + * promise is resolved. + * + * @param options Options for this test run + * @param cancellationToken Token that signals the used asked to abort the test run. + */ + runTests(options: TestRunRequest, token: CancellationToken): Thenable | void; + } + + /** + * Options given to {@link test.runTests}. + */ + export interface TestRunRequest { + /** + * Array of specific tests to run. The controllers should run all of the + * given tests and all children of the given tests, excluding any tests + * that appear in {@link TestRunRequest.exclude}. + */ + tests: TestItem[]; + + /** + * An array of tests the user has marked as excluded in VS Code. May be + * omitted if no exclusions were requested. Test controllers should not run + * excluded tests or any children of excluded tests. + */ + exclude?: TestItem[]; + + /** + * Whether tests in this run should be debugged. + */ + debug: boolean; + } + + /** + * Options given to {@link TestController.runTests} + */ + export interface TestRun { + /** + * The human-readable name of the run. This can be used to + * disambiguate multiple sets of results in a test run. It is useful if + * tests are run across multiple platforms, for example. + */ + readonly name?: string; + + /** + * Updates the state of the test in the run. Calling with method with nodes + * outside the {@link TestRunRequest.tests} or in the + * {@link TestRunRequest.exclude} array will no-op. + * + * @param test The test to update + * @param state The state to assign to the test + * @param duration Optionally sets how long the test took to run + */ + setState(test: TestItem, state: TestResultState, duration?: number): void; + + /** + * Appends a message, such as an assertion error, to the test item. + * + * Calling with method with nodes outside the {@link TestRunRequest.tests} + * or in the {@link TestRunRequest.exclude} array will no-op. + * + * @param test The test to update + * @param state The state to assign to the test + * + */ + appendMessage(test: TestItem, message: TestMessage): void; + + /** + * Appends raw output from the test runner. On the user's request, the + * output will be displayed in a terminal. ANSI escape sequences, + * such as colors and text styles, are supported. + * + * @param output Output text to append + * @param associateTo Optionally, associate the given segment of output + */ + appendOutput(output: string): void; + + /** + * Signals that the end of the test run. Any tests whose states have not + * been updated will be moved into the {@link TestResultState.Unset} state. + */ + end(): void; + } + + /** + * Indicates the the activity state of the {@link TestItem}. + */ + export enum TestItemStatus { + /** + * All children of the test item, if any, have been discovered. + */ + Resolved = 1, + + /** + * The test item may have children who have not been discovered yet. + */ + Pending = 0, + } + + /** + * Options initially passed into `vscode.test.createTestItem` + */ + export interface TestItemOptions { + /** + * Unique identifier for the TestItem. This is used to correlate + * test results and tests in the document with those in the workspace + * (test explorer). This cannot change for the lifetime of the TestItem. + */ + id: string; + + /** + * URI this TestItem is associated with. May be a file or directory. + */ + uri?: Uri; + + /** + * Display name describing the test item. + */ + label: string; + } + + /** + * A test item is an item shown in the "test explorer" view. It encompasses + * both a suite and a test, since they have almost or identical capabilities. + */ + export interface TestItem { + /** + * Unique identifier for the TestItem. This is used to correlate + * test results and tests in the document with those in the workspace + * (test explorer). This must not change for the lifetime of the TestItem. + */ + readonly id: string; + + /** + * URI this TestItem is associated with. May be a file or directory. + */ + readonly uri?: Uri; + + /** + * A mapping of children by ID to the associated TestItem instances. + */ + readonly children: ReadonlyMap>; + + /** + * The parent of this item, if any. Assigned automatically when calling + * {@link TestItem.addChild}. + */ + readonly parent?: TestItem; + + /** + * Indicates the state of the test item's children. The editor will show + * TestItems in the `Pending` state and with a `resolveHandler` as being + * expandable, and will call the `resolveHandler` to request items. + * + * A TestItem in the `Resolved` state is assumed to have discovered and be + * watching for changes in its children if applicable. TestItems are in the + * `Resolved` state when initially created; if the editor should call + * the `resolveHandler` to discover children, set the state to `Pending` + * after creating the item. + */ + status: TestItemStatus; + + /** + * Display name describing the test case. + */ + label: string; + + /** + * Optional description that appears next to the label. + */ + description?: string; + + /** + * Location of the test item in its `uri`. This is only meaningful if the + * `uri` points to a file. + */ + range?: Range; + + /** + * May be set to an error associated with loading the test. Note that this + * is not a test result and should only be used to represent errors in + * discovery, such as syntax errors. + */ + error?: string | MarkdownString; + + /** + * Whether this test item can be run by providing it in the + * {@link TestRunRequest.tests} array. Defaults to `true`. + */ + runnable: boolean; + + /** + * Whether this test item can be debugged by providing it in the + * {@link TestRunRequest.tests} array. Defaults to `false`. + */ + debuggable: boolean; + + /** + * Custom extension data on the item. This data will never be serialized + * or shared outside the extenion who created the item. + */ + data: T; + + /** + * Marks the test as outdated. This can happen as a result of file changes, + * for example. In "auto run" mode, tests that are outdated will be + * automatically rerun after a short delay. Invoking this on a + * test with children will mark the entire subtree as outdated. + * + * Extensions should generally not override this method. + */ + invalidate(): void; + + /** + * A function provided by the extension that the editor may call to request + * children of the item, if the {@link TestItem.status} is `Pending`. + * + * When called, the item should discover tests and call {@link TestItem.addChild}. + * The items should set its {@link TestItem.status} to `Resolved` when + * discovery is finished. + * + * The item should continue watching for changes to the children and + * firing updates until the token is cancelled. The process of watching + * the tests may involve creating a file watcher, for example. After the + * token is cancelled and watching stops, the TestItem should set its + * {@link TestItem.status} back to `Pending`. + * + * The editor will only call this method when it's interested in refreshing + * the children of the item, and will not call it again while there's an + * existing, uncancelled discovery for an item. + * + * @param token Cancellation for the request. Cancellation will be + * requested if the test changes before the previous call completes. + */ + resolveHandler?: (token: CancellationToken) => void; + + /** + * Attaches a child, created from the {@link test.createTestItem} function, + * to this item. A `TestItem` may be a child of at most one other item. + */ + addChild(child: TestItem): void; + + /** + * Removes the test and its children from the tree. Any tokens passed to + * child `resolveHandler` methods will be cancelled. + */ + dispose(): void; + } + + /** + * Possible states of tests in a test run. + */ + export enum TestResultState { + // Initial state + Unset = 0, + // Test will be run, but is not currently running. + Queued = 1, + // Test is currently running + Running = 2, + // Test run has passed + Passed = 3, + // Test run has failed (on an assertion) + Failed = 4, + // Test run has been skipped + Skipped = 5, + // Test run failed for some other reason (compilation error, timeout, etc) + Errored = 6, + } + + /** + * Represents the severity of test messages. + */ + export enum TestMessageSeverity { + Error = 0, + Warning = 1, + Information = 2, + Hint = 3, + } + + /** + * Message associated with the test state. Can be linked to a specific + * source range -- useful for assertion failures, for example. + */ + export class TestMessage { + /** + * Human-readable message text to display. + */ + message: string | MarkdownString; + + /** + * Message severity. Defaults to "Error". + */ + severity: TestMessageSeverity; + + /** + * Expected test output. If given with `actualOutput`, a diff view will be shown. + */ + expectedOutput?: string; + + /** + * Actual test output. If given with `expectedOutput`, a diff view will be shown. + */ + actualOutput?: string; + + /** + * Associated file location. + */ + location?: Location; + + /** + * Creates a new TestMessage that will present as a diff in the editor. + * @param message Message to display to the user. + * @param expected Expected output. + * @param actual Actual output. + */ + static diff(message: string | MarkdownString, expected: string, actual: string): TestMessage; + + /** + * Creates a new TestMessage instance. + * @param message The message to show to the user. + */ + constructor(message: string | MarkdownString); + } + + /** + * TestResults can be provided to VS Code in {@link test.publishTestResult}, + * or read from it in {@link test.testResults}. + * + * The results contain a 'snapshot' of the tests at the point when the test + * run is complete. Therefore, information such as its {@link Range} may be + * out of date. If the test still exists in the workspace, consumers can use + * its `id` to correlate the result instance with the living test. + * + * @todo coverage and other info may eventually be provided here + */ + export interface TestRunResult { + /** + * Unix milliseconds timestamp at which the test run was completed. + */ + completedAt: number; + + /** + * Optional raw output from the test run. + */ + output?: string; + + /** + * List of test results. The items in this array are the items that + * were passed in the {@link test.runTests} method. + */ + results: ReadonlyArray>; + } + + /** + * A {@link TestItem}-like interface with an associated result, which appear + * or can be provided in {@link TestResult} interfaces. + */ + export interface TestResultSnapshot { + /** + * Unique identifier that matches that of the associated TestItem. + * This is used to correlate test results and tests in the document with + * those in the workspace (test explorer). + */ + readonly id: string; + + /** + * URI this TestItem is associated with. May be a file or file. + */ + readonly uri?: Uri; + + /** + * Display name describing the test case. + */ + readonly label: string; + + /** + * Optional description that appears next to the label. + */ + readonly description?: string; + + /** + * Location of the test item in its `uri`. This is only meaningful if the + * `uri` points to a file. + */ + readonly range?: Range; + + /** + * State of the test in each task. In the common case, a test will only + * be executed in a single task and the length of this array will be 1. + */ + readonly taskStates: ReadonlyArray; + + /** + * Optional list of nested tests for this item. + */ + readonly children: Readonly[]; + } + + export interface TestSnapshoptTaskState { + /** + * Current result of the test. + */ + readonly state: TestResultState; + + /** + * The number of milliseconds the test took to run. This is set once the + * `state` is `Passed`, `Failed`, or `Errored`. + */ + readonly duration?: number; + + /** + * Associated test run message. Can, for example, contain assertion + * failure information if the test fails. + */ + readonly messages: ReadonlyArray; + } + + //#endregion } //#endregion From 6ee0305ca68a9662ec3dc278753c977ed761aa0d Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Wed, 12 May 2021 15:23:02 -0700 Subject: [PATCH 04/39] Remove nosetest support (#16217) * Remove nosetest support * Fix enablement tests * Update src/client/testing/common/xUnitParser.ts Co-authored-by: Kim-Adeline Miguel <51720070+kimadeline@users.noreply.github.com> Co-authored-by: Kim-Adeline Miguel <51720070+kimadeline@users.noreply.github.com> --- .eslintignore | 9 - .github/test_plan.md | 16 - README.md | 2 +- build/test-requirements.txt | 1 - news/.vscode/settings.json | 1 - package.json | 21 - pythonFiles/testlauncher.py | 11 +- .../testing_tools/adapter/test___main__.py | 11 - src/client/common/configSettings.ts | 11 - .../common/installer/moduleInstaller.ts | 9 +- .../common/installer/productInstaller.ts | 7 +- src/client/common/installer/productNames.ts | 1 - src/client/common/installer/productPath.ts | 10 +- src/client/common/installer/productService.ts | 1 - src/client/common/types.ts | 8 +- src/client/telemetry/index.ts | 1 - src/client/telemetry/types.ts | 2 +- src/client/testing/common/constants.ts | 3 +- src/client/testing/common/debugLauncher.ts | 3 +- .../testing/common/enablementTracker.ts | 4 +- src/client/testing/common/runner.ts | 9 +- .../common/services/configSettingService.ts | 4 - .../common/services/testManagerService.ts | 4 +- src/client/testing/common/testUtils.ts | 11 - src/client/testing/common/types.ts | 2 +- src/client/testing/common/xUnitParser.ts | 2 +- src/client/testing/configuration/index.ts | 11 +- src/client/testing/configuration/types.ts | 3 - src/client/testing/configurationFactory.ts | 4 - src/client/testing/display/main.ts | 7 +- src/client/testing/main.ts | 12 +- src/client/testing/nosetest/main.ts | 86 --- src/client/testing/nosetest/runner.ts | 125 ---- .../testing/nosetest/services/argsService.ts | 205 ------- .../nosetest/services/discoveryService.ts | 50 -- .../nosetest/services/parserService.ts | 193 ------ .../nosetest/testConfigurationManager.ts | 40 -- src/client/testing/serviceRegistry.ts | 14 +- src/client/testing/types.ts | 2 +- src/test/.vscode/settings.json | 11 +- src/test/common.ts | 2 - src/test/common/installer.test.ts | 3 +- .../installer/moduleInstaller.unit.test.ts | 3 +- .../common/installer/productPath.unit.test.ts | 15 +- .../testFiles/noseFiles/five.output | 121 ---- .../testFiles/noseFiles/four.output | 205 ------- .../testFiles/noseFiles/one.output | 211 ------- .../testFiles/noseFiles/run.five.output | 567 ------------------ .../testFiles/noseFiles/run.five.result | 11 - .../testFiles/noseFiles/run.four.output | 565 ----------------- .../testFiles/noseFiles/run.four.result | 12 - .../testFiles/noseFiles/run.one.output | 558 ----------------- .../testFiles/noseFiles/run.one.result | 83 --- .../testFiles/noseFiles/run.three.output | 563 ----------------- .../testFiles/noseFiles/run.three.result | 12 - .../testFiles/noseFiles/run.two.again.result | 81 --- .../testFiles/noseFiles/run.two.output | 560 ----------------- .../testFiles/noseFiles/run.two.result | 83 --- .../noseFiles/specific/tst_unittest_one.py | 15 - .../noseFiles/specific/tst_unittest_two.py | 18 - .../testFiles/noseFiles/test_root.py | 19 - .../testFiles/noseFiles/tests/test4.py | 13 - .../noseFiles/tests/test_unittest_one.py | 19 - .../noseFiles/tests/test_unittest_two.py | 32 - .../noseFiles/tests/unittest_three_test.py | 13 - .../testFiles/noseFiles/three.output | 555 ----------------- .../testFiles/noseFiles/two.output | 211 ------- src/test/testing/argsService.test.ts | 6 - .../testing/common/debugLauncher.unit.test.ts | 5 +- .../managers/baseTestManager.unit.test.ts | 2 - .../configSettingService.unit.test.ts | 8 - .../common/trackEnablement.unit.test.ts | 70 +-- .../testing/common/xUnitParser.unit.test.ts | 1 - src/test/testing/configuration.unit.test.ts | 14 +- .../testing/configurationFactory.unit.test.ts | 5 - src/test/testing/debugger.test.ts | 28 +- src/test/testing/display/main.unit.test.ts | 7 +- .../nosetest/nose_discovery_output.txt | 561 ----------------- .../nosetest.argsService.unit.test.ts | 46 -- .../nosetest/nosetest.discovery.test.ts | 172 ------ .../nosetest/nosetest.discovery.unit.test.ts | 211 ------- .../testing/nosetest/nosetest.run.test.ts | 207 ------- src/test/testing/nosetest/nosetest.test.ts | 77 --- src/test/testing/rediscover.test.ts | 6 - src/test/testing/serviceRegistry.ts | 14 +- 85 files changed, 60 insertions(+), 6857 deletions(-) delete mode 100644 src/client/testing/nosetest/main.ts delete mode 100644 src/client/testing/nosetest/runner.ts delete mode 100644 src/client/testing/nosetest/services/argsService.ts delete mode 100644 src/client/testing/nosetest/services/discoveryService.ts delete mode 100644 src/client/testing/nosetest/services/parserService.ts delete mode 100644 src/client/testing/nosetest/testConfigurationManager.ts delete mode 100644 src/test/pythonFiles/testFiles/noseFiles/five.output delete mode 100644 src/test/pythonFiles/testFiles/noseFiles/four.output delete mode 100644 src/test/pythonFiles/testFiles/noseFiles/one.output delete mode 100644 src/test/pythonFiles/testFiles/noseFiles/run.five.output delete mode 100644 src/test/pythonFiles/testFiles/noseFiles/run.five.result delete mode 100644 src/test/pythonFiles/testFiles/noseFiles/run.four.output delete mode 100644 src/test/pythonFiles/testFiles/noseFiles/run.four.result delete mode 100644 src/test/pythonFiles/testFiles/noseFiles/run.one.output delete mode 100644 src/test/pythonFiles/testFiles/noseFiles/run.one.result delete mode 100644 src/test/pythonFiles/testFiles/noseFiles/run.three.output delete mode 100644 src/test/pythonFiles/testFiles/noseFiles/run.three.result delete mode 100644 src/test/pythonFiles/testFiles/noseFiles/run.two.again.result delete mode 100644 src/test/pythonFiles/testFiles/noseFiles/run.two.output delete mode 100644 src/test/pythonFiles/testFiles/noseFiles/run.two.result delete mode 100644 src/test/pythonFiles/testFiles/noseFiles/specific/tst_unittest_one.py delete mode 100644 src/test/pythonFiles/testFiles/noseFiles/specific/tst_unittest_two.py delete mode 100644 src/test/pythonFiles/testFiles/noseFiles/test_root.py delete mode 100644 src/test/pythonFiles/testFiles/noseFiles/tests/test4.py delete mode 100644 src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py delete mode 100644 src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py delete mode 100644 src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py delete mode 100644 src/test/pythonFiles/testFiles/noseFiles/three.output delete mode 100644 src/test/pythonFiles/testFiles/noseFiles/two.output delete mode 100644 src/test/testing/nosetest/nose_discovery_output.txt delete mode 100644 src/test/testing/nosetest/nosetest.argsService.unit.test.ts delete mode 100644 src/test/testing/nosetest/nosetest.discovery.test.ts delete mode 100644 src/test/testing/nosetest/nosetest.discovery.unit.test.ts delete mode 100644 src/test/testing/nosetest/nosetest.run.test.ts delete mode 100644 src/test/testing/nosetest/nosetest.test.ts diff --git a/.eslintignore b/.eslintignore index 57cc8abca260..fdad96bd2456 100644 --- a/.eslintignore +++ b/.eslintignore @@ -106,9 +106,6 @@ src/test/testing/unittest/unittest.discovery.test.ts src/test/testing/unittest/unittest.run.test.ts src/test/testing/unittest/unittest.unit.test.ts src/test/testing/codeLenses/testFiles.unit.test.ts -src/test/testing/nosetest/nosetest.test.ts -src/test/testing/nosetest/nosetest.disovery.test.ts -src/test/testing/nosetest/nosetest.run.test.ts src/test/testing/rediscover.test.ts src/test/testing/helper.ts src/test/testing/navigation/fileNavigator.unit.test.ts @@ -379,12 +376,6 @@ src/client/testing/unittest/services/argsService.ts src/client/testing/unittest/services/discoveryService.ts src/client/testing/codeLenses/main.ts src/client/testing/codeLenses/testFiles.ts -src/client/testing/nosetest/main.ts -src/client/testing/nosetest/testConfigurationManager.ts -src/client/testing/nosetest/runner.ts -src/client/testing/nosetest/services/parserService.ts -src/client/testing/nosetest/services/argsService.ts -src/client/testing/nosetest/services/discoveryService.ts src/client/testing/main.ts src/client/testing/configurationFactory.ts src/client/testing/navigation/serviceRegistry.ts diff --git a/.github/test_plan.md b/.github/test_plan.md index b22e1121efae..bafe2aadb43c 100644 --- a/.github/test_plan.md +++ b/.github/test_plan.md @@ -342,22 +342,6 @@ def test_failure(): - [ ] The appropriate `DiagnosticRelatedInformation` is shown for each `Diagnostic` - [ ] The `DiagnosticRelatedInformation` reflects the traceback for the test -#### [`nose`](https://code.visualstudio.com/docs/python/unit-testing#_nose-configuration-settings) - -```python -def test_passing(): - assert 42 == 42 - -def test_failure(): - assert 42 == -13 -``` - -- [ ] `Run All Unit Tests` triggers the prompt to configure the test runner - - [ ] Nose gets installed -- [ ] Tests are discovered (as shown by code lenses on each test) - - [ ] `Run Test` works - - [ ] `Debug Test` works - #### General - [ ] Code lenses appears diff --git a/README.md b/README.md index 37037584df04..d742ca233a64 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ Learn more about the rich features of the Python extension: - [Debugging](https://code.visualstudio.com/docs/python/debugging): Debug your Python scripts, web apps, remote or multi-threaded processes -- [Testing](https://code.visualstudio.com/docs/python/unit-testing): Run and debug tests through the Test Explorer with unittest, pytest or nose +- [Testing](https://code.visualstudio.com/docs/python/unit-testing): Run and debug tests through the Test Explorer with unittest or pytest. - [Jupyter Notebooks](https://code.visualstudio.com/docs/python/jupyter-support): Create and edit Jupyter Notebooks, add and run code cells, render plots, visualize variables through the variable explorer, visualize dataframes with the data viewer, and more diff --git a/build/test-requirements.txt b/build/test-requirements.txt index 4cc0fddc27b6..9bb14d923427 100644 --- a/build/test-requirements.txt +++ b/build/test-requirements.txt @@ -9,7 +9,6 @@ pylint pycodestyle pydocstyle prospector ; python_version > '2.7' -nose pytest<6 ; python_version > '2.7' # Tests currently fail against pytest 6. rope flask diff --git a/news/.vscode/settings.json b/news/.vscode/settings.json index 16cc867210e7..5f54ccecb0b6 100644 --- a/news/.vscode/settings.json +++ b/news/.vscode/settings.json @@ -4,6 +4,5 @@ "editor.formatOnSave": true, "python.testing.pytestArgs": ["."], "python.testing.unittestEnabled": false, - "python.testing.nosetestsEnabled": false, "python.testing.pytestEnabled": true } diff --git a/package.json b/package.json index 59d3df7bb51f..460e2bf01fa7 100644 --- a/package.json +++ b/package.json @@ -1288,27 +1288,6 @@ "scope": "resource", "type": "number" }, - "python.testing.nosetestArgs": { - "default": [], - "description": "Arguments passed in. Each argument is a separate item in the array.", - "items": { - "type": "string" - }, - "scope": "resource", - "type": "array" - }, - "python.testing.nosetestPath": { - "default": "nosetests", - "description": "Path to nosetests, you can use a custom version of nosetests by modifying this setting to include the full path.", - "scope": "resource", - "type": "string" - }, - "python.testing.nosetestsEnabled": { - "default": false, - "description": "Enable testing using nosetests.", - "scope": "resource", - "type": "boolean" - }, "python.testing.promptToConfigure": { "default": true, "description": "Prompt to configure a test framework if potential tests directories are discovered.", diff --git a/pythonFiles/testlauncher.py b/pythonFiles/testlauncher.py index 25b56b7c0604..3278815b380c 100644 --- a/pythonFiles/testlauncher.py +++ b/pythonFiles/testlauncher.py @@ -9,15 +9,12 @@ def parse_argv(): """Parses arguments for use with the test launcher. Arguments are: 1. Working directory. - 2. Test runner, `pytest` or `nose` + 2. Test runner `pytest` 3. Rest of the arguments are passed into the test runner. """ cwd = sys.argv[1] testRunner = sys.argv[2] args = sys.argv[3:] - if testRunner == "nose": - # Nose expects the program name to be first argument in vargs - args.insert(0, sys.argv[0]) return (cwd, testRunner, args) @@ -25,7 +22,7 @@ def parse_argv(): def run(cwd, testRunner, args): """Runs the test cwd -- the current directory to be set - testRunner -- test runner to be used `pytest` or `nose` + testRunner -- test runner to be used `pytest` args -- arguments passed into the test runner """ @@ -37,10 +34,6 @@ def run(cwd, testRunner, args): import pytest pytest.main(args) - else: - import nose - - nose.run(argv=args) sys.exit(0) finally: pass diff --git a/pythonFiles/tests/testing_tools/adapter/test___main__.py b/pythonFiles/tests/testing_tools/adapter/test___main__.py index 53500a2f4afe..d0a778c1d024 100644 --- a/pythonFiles/tests/testing_tools/adapter/test___main__.py +++ b/pythonFiles/tests/testing_tools/adapter/test___main__.py @@ -110,8 +110,6 @@ def test_pytest_opts(self): def test_unsupported_tool(self): with self.assertRaises(SystemExit): parse_args(["discover", "unittest"]) - with self.assertRaises(SystemExit): - parse_args(["discover", "nose"]) with self.assertRaises(SystemExit): parse_args(["discover", "???"]) @@ -159,15 +157,6 @@ def test_unsupported_tool(self): _tools={"pytest": None}, _reporters=None, ) - with self.assertRaises(UnsupportedToolError): - main( - "nose", - "discover", - {"spam": "eggs"}, - [], - _tools={"pytest": None}, - _reporters=None, - ) with self.assertRaises(UnsupportedToolError): main( "???", diff --git a/src/client/common/configSettings.ts b/src/client/common/configSettings.ts index fc06923aba8e..15239764306c 100644 --- a/src/client/common/configSettings.ts +++ b/src/client/common/configSettings.ts @@ -512,15 +512,12 @@ export class PythonSettings implements IPythonSettings { this.testing = testSettings; if (isTestExecution() && !this.testing) { this.testing = { - nosetestArgs: [], pytestArgs: [], unittestArgs: [], promptToConfigure: true, debugPort: 3000, - nosetestsEnabled: false, pytestEnabled: false, unittestEnabled: false, - nosetestPath: 'nosetests', pytestPath: 'pytest', autoTestDiscoverOnSaveEnabled: true, } as ITestingSettings; @@ -533,9 +530,6 @@ export class PythonSettings implements IPythonSettings { : { promptToConfigure: true, debugPort: 3000, - nosetestArgs: [], - nosetestPath: 'nosetest', - nosetestsEnabled: false, pytestArgs: [], pytestEnabled: false, pytestPath: 'pytest', @@ -544,16 +538,11 @@ export class PythonSettings implements IPythonSettings { autoTestDiscoverOnSaveEnabled: true, }; this.testing.pytestPath = getAbsolutePath(systemVariables.resolveAny(this.testing.pytestPath), workspaceRoot); - this.testing.nosetestPath = getAbsolutePath( - systemVariables.resolveAny(this.testing.nosetestPath), - workspaceRoot, - ); if (this.testing.cwd) { this.testing.cwd = getAbsolutePath(systemVariables.resolveAny(this.testing.cwd), workspaceRoot); } // Resolve any variables found in the test arguments. - this.testing.nosetestArgs = this.testing.nosetestArgs.map((arg) => systemVariables.resolveAny(arg)); this.testing.pytestArgs = this.testing.pytestArgs.map((arg) => systemVariables.resolveAny(arg)); this.testing.unittestArgs = this.testing.unittestArgs.map((arg) => systemVariables.resolveAny(arg)); diff --git a/src/client/common/installer/moduleInstaller.ts b/src/client/common/installer/moduleInstaller.ts index 23ad720fb817..13e5ba12c378 100644 --- a/src/client/common/installer/moduleInstaller.ts +++ b/src/client/common/installer/moduleInstaller.ts @@ -15,7 +15,7 @@ import { STANDARD_OUTPUT_CHANNEL } from '../constants'; import { IFileSystem } from '../platform/types'; import * as internalPython from '../process/internal/python'; import { ITerminalServiceFactory, TerminalCreationOptions } from '../terminal/types'; -import { ExecutionInfo, IConfigurationService, IOutputChannel, ModuleNamePurpose, Product } from '../types'; +import { ExecutionInfo, IConfigurationService, IOutputChannel, Product } from '../types'; import { Products } from '../utils/localize'; import { isResource } from '../utils/misc'; import { ProductNames } from './productNames'; @@ -39,7 +39,7 @@ export abstract class ModuleInstaller implements IModuleInstaller { const name = typeof productOrModuleName == 'string' ? productOrModuleName - : translateProductToModule(productOrModuleName, ModuleNamePurpose.install); + : translateProductToModule(productOrModuleName); const productName = typeof productOrModuleName === 'string' ? name : ProductNames.get(productOrModuleName); sendTelemetryEvent(EventName.PYTHON_INSTALL_PACKAGE, undefined, { installer: this.displayName, productName }); const uri = isResource(resource) ? resource : undefined; @@ -153,13 +153,10 @@ export abstract class ModuleInstaller implements IModuleInstaller { } } -export function translateProductToModule(product: Product, purpose: ModuleNamePurpose): string { +export function translateProductToModule(product: Product): string { switch (product) { case Product.mypy: return 'mypy'; - case Product.nosetest: { - return purpose === ModuleNamePurpose.install ? 'nose' : 'nosetests'; - } case Product.pylama: return 'pylama'; case Product.prospector: diff --git a/src/client/common/installer/productInstaller.ts b/src/client/common/installer/productInstaller.ts index b1697a998220..add920fbb176 100644 --- a/src/client/common/installer/productInstaller.ts +++ b/src/client/common/installer/productInstaller.ts @@ -24,7 +24,6 @@ import { IOutputChannel, IPersistentStateFactory, ProductInstallStatus, - ModuleNamePurpose, Product, ProductType, } from '../types'; @@ -467,7 +466,7 @@ export class DataScienceInstaller extends BaseInstaller { .getInstallationChannels(interpreter); // Pick an installerModule based on whether the interpreter is conda or not. Default is pip. - const moduleName = translateProductToModule(product, ModuleNamePurpose.install); + const moduleName = translateProductToModule(product); const isAvailableThroughConda = !UnsupportedChannelsForProduct.get(product)?.has(EnvironmentType.Conda); let requiredInstaller = ModuleInstallerType.Unknown; @@ -604,8 +603,8 @@ export class ProductInstaller implements IInstaller { } // eslint-disable-next-line class-methods-use-this - public translateProductToModuleName(product: Product, purpose: ModuleNamePurpose): string { - return translateProductToModule(product, purpose); + public translateProductToModuleName(product: Product): string { + return translateProductToModule(product); } private createInstaller(product: Product): BaseInstaller { diff --git a/src/client/common/installer/productNames.ts b/src/client/common/installer/productNames.ts index ff0fcf75b44c..bcee1a53a239 100644 --- a/src/client/common/installer/productNames.ts +++ b/src/client/common/installer/productNames.ts @@ -9,7 +9,6 @@ ProductNames.set(Product.bandit, 'bandit'); ProductNames.set(Product.black, 'black'); ProductNames.set(Product.flake8, 'flake8'); ProductNames.set(Product.mypy, 'mypy'); -ProductNames.set(Product.nosetest, 'nosetest'); ProductNames.set(Product.pycodestyle, 'pycodestyle'); ProductNames.set(Product.pylama, 'pylama'); ProductNames.set(Product.prospector, 'prospector'); diff --git a/src/client/common/installer/productPath.ts b/src/client/common/installer/productPath.ts index 3e20acced587..2ac48ed35d62 100644 --- a/src/client/common/installer/productPath.ts +++ b/src/client/common/installer/productPath.ts @@ -10,7 +10,7 @@ import { IFormatterHelper } from '../../formatters/types'; import { IServiceContainer } from '../../ioc/types'; import { ILinterManager } from '../../linters/types'; import { ITestingService } from '../../testing/types'; -import { IConfigurationService, IInstaller, ModuleNamePurpose, Product } from '../types'; +import { IConfigurationService, IInstaller, Product } from '../types'; import { IProductPathService } from './types'; @injectable() @@ -25,7 +25,7 @@ export abstract class BaseProductPathsService implements IProductPathService { public isExecutableAModule(product: Product, resource?: Uri): boolean { let moduleName: string | undefined; try { - moduleName = this.productInstaller.translateProductToModuleName(product, ModuleNamePurpose.run); + moduleName = this.productInstaller.translateProductToModuleName(product); } catch {} // User may have customized the module name or provided the fully qualifieid path. @@ -82,7 +82,7 @@ export class TestFrameworkProductPathService extends BaseProductPathsService { const settingsPropNames = testHelper.getSettingsPropertyNames(product); if (!settingsPropNames.pathName) { // E.g. in the case of UnitTests we don't allow customizing the paths. - return this.productInstaller.translateProductToModuleName(product, ModuleNamePurpose.run); + return this.productInstaller.translateProductToModuleName(product); } const settings = this.configService.getSettings(resource); return settings.testing[settingsPropNames.pathName] as string; @@ -95,7 +95,7 @@ export class RefactoringLibraryProductPathService extends BaseProductPathsServic super(serviceContainer); } public getExecutableNameFromSettings(product: Product, _?: Uri): string { - return this.productInstaller.translateProductToModuleName(product, ModuleNamePurpose.run); + return this.productInstaller.translateProductToModuleName(product); } } @@ -105,6 +105,6 @@ export class DataScienceProductPathService extends BaseProductPathsService { super(serviceContainer); } public getExecutableNameFromSettings(product: Product, _?: Uri): string { - return this.productInstaller.translateProductToModuleName(product, ModuleNamePurpose.run); + return this.productInstaller.translateProductToModuleName(product); } } diff --git a/src/client/common/installer/productService.ts b/src/client/common/installer/productService.ts index 837b70f36d1e..569a302e06df 100644 --- a/src/client/common/installer/productService.ts +++ b/src/client/common/installer/productService.ts @@ -21,7 +21,6 @@ export class ProductService implements IProductService { this.ProductTypes.set(Product.pylama, ProductType.Linter); this.ProductTypes.set(Product.pylint, ProductType.Linter); this.ProductTypes.set(Product.ctags, ProductType.WorkspaceSymbols); - this.ProductTypes.set(Product.nosetest, ProductType.TestFramework); this.ProductTypes.set(Product.pytest, ProductType.TestFramework); this.ProductTypes.set(Product.unittest, ProductType.TestFramework); this.ProductTypes.set(Product.autopep8, ProductType.Formatter); diff --git a/src/client/common/types.ts b/src/client/common/types.ts index bf437ff3d493..7ff71aa96aea 100644 --- a/src/client/common/types.ts +++ b/src/client/common/types.ts @@ -83,7 +83,6 @@ export enum ProductType { export enum Product { pytest = 1, - nosetest = 2, pylint = 3, flake8 = 4, pycodestyle = 5, @@ -110,11 +109,6 @@ export enum Product { torchProfilerImportName = 26, } -export enum ModuleNamePurpose { - install = 1, - run = 2, -} - export const IInstaller = Symbol('IInstaller'); export interface IInstaller { @@ -136,7 +130,7 @@ export interface IInstaller { semVerRequirement: string, resource?: InterpreterUri, ): Promise; - translateProductToModuleName(product: Product, purpose: ModuleNamePurpose): string; + translateProductToModuleName(product: Product): string; } // TODO: Drop IPathUtils in favor of IFileSystemPathUtils. diff --git a/src/client/telemetry/index.ts b/src/client/telemetry/index.ts index db98680a919e..267a317a28d9 100644 --- a/src/client/telemetry/index.ts +++ b/src/client/telemetry/index.ts @@ -1609,7 +1609,6 @@ export interface IEventNamePropertyMapping { * Values sent include: * unittest - If this value is `true`, then unittest has been enabled by the user. * pytest - If this value is `true`, then pytest has been enabled by the user. - * nosetest - If this value is `true`, then nose has been enabled by the user. * @type {(never | undefined)} * @memberof IEventNamePropertyMapping */ diff --git a/src/client/telemetry/types.ts b/src/client/telemetry/types.ts index 65a4bb0c12d0..4aa008f0a886 100644 --- a/src/client/telemetry/types.ts +++ b/src/client/telemetry/types.ts @@ -14,7 +14,7 @@ export type LintingTelemetry = IEventNamePropertyMapping[EventName.LINTING]; export type PythonInterpreterTelemetry = IEventNamePropertyMapping[EventName.PYTHON_INTERPRETER]; export type DebuggerTelemetry = IEventNamePropertyMapping[EventName.DEBUGGER]; -export type TestTool = 'nosetest' | 'pytest' | 'unittest'; +export type TestTool = 'pytest' | 'unittest'; export type TestRunTelemetry = IEventNamePropertyMapping[EventName.UNITTEST_RUN]; export type TestDiscoveryTelemetry = IEventNamePropertyMapping[EventName.UNITTEST_DISCOVER]; export type TestConfiguringTelemetry = IEventNamePropertyMapping[EventName.UNITTEST_CONFIGURING]; diff --git a/src/client/testing/common/constants.ts b/src/client/testing/common/constants.ts index c07cb304663b..07c5071973f6 100644 --- a/src/client/testing/common/constants.ts +++ b/src/client/testing/common/constants.ts @@ -4,8 +4,7 @@ import { UnitTestProduct } from './types'; export const CANCELLATION_REASON = 'cancelled_user_request'; -export const UNIT_TEST_PRODUCTS: UnitTestProduct[] = [Product.pytest, Product.unittest, Product.nosetest]; -export const NOSETEST_PROVIDER: TestProvider = 'nosetest'; +export const UNIT_TEST_PRODUCTS: UnitTestProduct[] = [Product.pytest, Product.unittest]; export const PYTEST_PROVIDER: TestProvider = 'pytest'; export const UNITTEST_PROVIDER: TestProvider = 'unittest'; diff --git a/src/client/testing/common/debugLauncher.ts b/src/client/testing/common/debugLauncher.ts index 5330af6b32b5..17a5d6bec786 100644 --- a/src/client/testing/common/debugLauncher.ts +++ b/src/client/testing/common/debugLauncher.ts @@ -212,8 +212,7 @@ export class DebugLauncher implements ITestDebugLauncher { case 'unittest': { return internalScripts.visualstudio_py_testlauncher; } - case 'pytest': - case 'nosetest': { + case 'pytest': { return internalScripts.testlauncher; } default: { diff --git a/src/client/testing/common/enablementTracker.ts b/src/client/testing/common/enablementTracker.ts index b847ac67f8df..0f99939450ec 100644 --- a/src/client/testing/common/enablementTracker.ts +++ b/src/client/testing/common/enablementTracker.ts @@ -30,7 +30,7 @@ export class EnablementTracker implements IExtensionSingleActivationService { this.workspaceService.workspaceFolders.forEach((item) => resourcesToCheck.push(item.uri)); } - const testProviders: TestProvider[] = ['nosetest', 'pytest', 'unittest']; + const testProviders: TestProvider[] = ['pytest', 'unittest']; resourcesToCheck.forEach((resource) => { const telemetry: Partial> = {}; testProviders.forEach((item) => { @@ -46,7 +46,7 @@ export class EnablementTracker implements IExtensionSingleActivationService { } }); // If anyone of the items have been enabled, then send telemetry. - if (telemetry.nosetest || telemetry.pytest || telemetry.unittest) { + if (telemetry.pytest || telemetry.unittest) { this.sendTelemetry(telemetry); } }); diff --git a/src/client/testing/common/runner.ts b/src/client/testing/common/runner.ts index 6a6d8709d704..96deeaab5939 100644 --- a/src/client/testing/common/runner.ts +++ b/src/client/testing/common/runner.ts @@ -12,7 +12,7 @@ import { import { ExecutionInfo, IConfigurationService, IPythonSettings } from '../../common/types'; import { IServiceContainer } from '../../ioc/types'; import { TestProvider } from '../types'; -import { NOSETEST_PROVIDER, PYTEST_PROVIDER, UNITTEST_PROVIDER } from './constants'; +import { PYTEST_PROVIDER, UNITTEST_PROVIDER } from './constants'; import { ITestRunner, ITestsHelper, Options } from './types'; export { Options } from './types'; @@ -105,10 +105,6 @@ async function run(serviceContainer: IServiceContainer, testProvider: TestProvid function getExecutablePath(testProvider: TestProvider, settings: IPythonSettings): string | undefined { let testRunnerExecutablePath: string | undefined; switch (testProvider) { - case NOSETEST_PROVIDER: { - testRunnerExecutablePath = settings.testing.nosetestPath; - break; - } case PYTEST_PROVIDER: { testRunnerExecutablePath = settings.testing.pytestPath; break; @@ -121,9 +117,6 @@ function getExecutablePath(testProvider: TestProvider, settings: IPythonSettings } function getTestModuleName(testProvider: TestProvider) { switch (testProvider) { - case NOSETEST_PROVIDER: { - return 'nose'; - } case PYTEST_PROVIDER: { return 'pytest'; } diff --git a/src/client/testing/common/services/configSettingService.ts b/src/client/testing/common/services/configSettingService.ts index 807653a20867..1c4a3d87ef1c 100644 --- a/src/client/testing/common/services/configSettingService.ts +++ b/src/client/testing/common/services/configSettingService.ts @@ -31,8 +31,6 @@ export class TestConfigSettingsService implements ITestConfigSettingsService { return 'testing.unittestEnabled'; case Product.pytest: return 'testing.pytestEnabled'; - case Product.nosetest: - return 'testing.nosetestsEnabled'; default: throw new Error('Invalid Test Product'); } @@ -43,8 +41,6 @@ export class TestConfigSettingsService implements ITestConfigSettingsService { return 'testing.unittestArgs'; case Product.pytest: return 'testing.pytestArgs'; - case Product.nosetest: - return 'testing.nosetestArgs'; default: throw new Error('Invalid Test Product'); } diff --git a/src/client/testing/common/services/testManagerService.ts b/src/client/testing/common/services/testManagerService.ts index 4559e68f5574..53c3d60a75d0 100644 --- a/src/client/testing/common/services/testManagerService.ts +++ b/src/client/testing/common/services/testManagerService.ts @@ -37,9 +37,7 @@ export class TestManagerService implements ITestManagerService { } public getPreferredTestManager(): UnitTestProduct | undefined { const settings = this.configurationService.getSettings(this.wkspace); - if (settings.testing.nosetestsEnabled) { - return Product.nosetest; - } else if (settings.testing.pytestEnabled) { + if (settings.testing.pytestEnabled) { return Product.pytest; } else if (settings.testing.unittestEnabled) { return Product.unittest; diff --git a/src/client/testing/common/testUtils.ts b/src/client/testing/common/testUtils.ts index 09cb34ef0588..9331620af54c 100644 --- a/src/client/testing/common/testUtils.ts +++ b/src/client/testing/common/testUtils.ts @@ -57,8 +57,6 @@ export class TestsHelper implements ITestsHelper { } public parseProviderName(product: UnitTestProduct): TestProvider { switch (product) { - case Product.nosetest: - return 'nosetest'; case Product.pytest: return 'pytest'; case Product.unittest: @@ -70,8 +68,6 @@ export class TestsHelper implements ITestsHelper { } public parseProduct(provider: TestProvider): UnitTestProduct { switch (provider) { - case 'nosetest': - return Product.nosetest; case 'pytest': return Product.pytest; case 'unittest': @@ -91,13 +87,6 @@ export class TestsHelper implements ITestsHelper { enabledName: 'pytestEnabled' as keyof ITestingSettings, }; } - case 'nosetest': { - return { - argsName: 'nosetestArgs' as keyof ITestingSettings, - pathName: 'nosetestPath' as keyof ITestingSettings, - enabledName: 'nosetestsEnabled' as keyof ITestingSettings, - }; - } case 'unittest': { return { argsName: 'unittestArgs' as keyof ITestingSettings, diff --git a/src/client/testing/common/types.ts b/src/client/testing/common/types.ts index dc5290e9d42e..acd481125069 100644 --- a/src/client/testing/common/types.ts +++ b/src/client/testing/common/types.ts @@ -21,7 +21,7 @@ import { TestProvider } from '../types'; import { TestSettingsPropertyNames } from '../configuration/types'; import { CommandSource } from '../../common/constants'; -export type UnitTestProduct = Product.nosetest | Product.pytest | Product.unittest; +export type UnitTestProduct = Product.pytest | Product.unittest; // **************** // test args/options diff --git a/src/client/testing/common/xUnitParser.ts b/src/client/testing/common/xUnitParser.ts index 8588ade7c171..5f69b68dfe5c 100644 --- a/src/client/testing/common/xUnitParser.ts +++ b/src/client/testing/common/xUnitParser.ts @@ -116,7 +116,7 @@ function updateTests(tests: Tests, testSuiteResult: TestSuiteResult) { // Possible we're dealing with nosetests, where the file name isn't returned to us // When dealing with nose tests // It is possible to have a test file named x in two separate test sub directories and have same functions/classes - // And unforutnately xunit log doesn't ouput the filename + // And unfortunately xunit log doesn't output the filename // result = tests.testFunctions.find(fn => fn.testFunction.name === testcase.$.name && // fn.parentTestSuite && fn.parentTestSuite.name === testcase.$.classname); diff --git a/src/client/testing/configuration/index.ts b/src/client/testing/configuration/index.ts index 93d8d2c518b2..ba9233549f70 100644 --- a/src/client/testing/configuration/index.ts +++ b/src/client/testing/configuration/index.ts @@ -38,18 +38,17 @@ export class UnitTestConfigurationService implements ITestConfigurationService { public async displayTestFrameworkError(wkspace: Uri): Promise { const settings = this.configurationService.getSettings(wkspace); let enabledCount = settings.testing.pytestEnabled ? 1 : 0; - enabledCount += settings.testing.nosetestsEnabled ? 1 : 0; enabledCount += settings.testing.unittestEnabled ? 1 : 0; if (enabledCount > 1) { return this._promptToEnableAndConfigureTestFramework( wkspace, - 'Enable only one of the test frameworks (unittest, pytest or nosetest).', + 'Enable only one of the test frameworks (unittest or pytest).', true, ); } const option = 'Enable and configure a Test Framework'; const item = await this.appShell.showInformationMessage( - 'No test framework configured (unittest, pytest or nosetest)', + 'No test framework configured (unittest, or pytest)', option, ); if (item !== option) { @@ -73,12 +72,6 @@ export class UnitTestConfigurationService implements ITestConfigurationService { detail: 'http://docs.pytest.org/', }, - { - label: 'nose', - product: Product.nosetest, - description: 'nose framework', - detail: 'https://nose.readthedocs.io/', - }, ]; const options = { ignoreFocusOut: true, diff --git a/src/client/testing/configuration/types.ts b/src/client/testing/configuration/types.ts index 79c903c21821..5da99398283b 100644 --- a/src/client/testing/configuration/types.ts +++ b/src/client/testing/configuration/types.ts @@ -4,9 +4,6 @@ export interface ITestingSettings { readonly promptToConfigure: boolean; readonly debugPort: number; - readonly nosetestsEnabled: boolean; - nosetestPath: string; - nosetestArgs: string[]; readonly pytestEnabled: boolean; pytestPath: string; pytestArgs: string[]; diff --git a/src/client/testing/configurationFactory.ts b/src/client/testing/configurationFactory.ts index 18c87f477c81..61f830325545 100644 --- a/src/client/testing/configurationFactory.ts +++ b/src/client/testing/configurationFactory.ts @@ -7,7 +7,6 @@ import { inject, injectable } from 'inversify'; import { Uri } from 'vscode'; import { Product } from '../common/types'; import { IServiceContainer } from '../ioc/types'; -import * as nose from './nosetest/testConfigurationManager'; import * as pytest from './pytest/testConfigurationManager'; import { ITestConfigSettingsService, @@ -27,9 +26,6 @@ export class TestConfigurationManagerFactory implements ITestConfigurationManage case Product.pytest: { return new pytest.ConfigurationManager(wkspace, this.serviceContainer, cfg); } - case Product.nosetest: { - return new nose.ConfigurationManager(wkspace, this.serviceContainer, cfg); - } default: { throw new Error('Invalid test configuration'); } diff --git a/src/client/testing/display/main.ts b/src/client/testing/display/main.ts index 24990656e098..c4928b18f3ac 100644 --- a/src/client/testing/display/main.ts +++ b/src/client/testing/display/main.ts @@ -152,12 +152,7 @@ export class TestResultDisplay implements ITestResultDisplay { @captureTelemetry(EventName.UNITTEST_DISABLE) private async disableTests(): Promise { const configurationService = this.serviceContainer.get(IConfigurationService); - const settingsToDisable = [ - 'testing.promptToConfigure', - 'testing.pytestEnabled', - 'testing.unittestEnabled', - 'testing.nosetestsEnabled', - ]; + const settingsToDisable = ['testing.promptToConfigure', 'testing.pytestEnabled', 'testing.unittestEnabled']; for (const setting of settingsToDisable) { await configurationService.updateSetting(setting, false).catch(noop); diff --git a/src/client/testing/main.ts b/src/client/testing/main.ts index 9d4723ad223e..7e20f09274c9 100644 --- a/src/client/testing/main.ts +++ b/src/client/testing/main.ts @@ -173,11 +173,7 @@ export class UnitTestManagementService implements ITestManagementService, Dispos const settings = this.serviceContainer .get(IConfigurationService) .getSettings(workspaceUri); - if ( - !settings.testing.nosetestsEnabled && - !settings.testing.pytestEnabled && - !settings.testing.unittestEnabled - ) { + if (!settings.testing.pytestEnabled && !settings.testing.unittestEnabled) { if (this.testResultDisplay) { this.testResultDisplay.enabled = false; } @@ -227,11 +223,7 @@ export class UnitTestManagementService implements ITestManagementService, Dispos } const configurationService = this.serviceContainer.get(IConfigurationService); const settings = configurationService.getSettings(resource); - if ( - !settings.testing.nosetestsEnabled && - !settings.testing.pytestEnabled && - !settings.testing.unittestEnabled - ) { + if (!settings.testing.pytestEnabled && !settings.testing.unittestEnabled) { return; } diff --git a/src/client/testing/nosetest/main.ts b/src/client/testing/nosetest/main.ts deleted file mode 100644 index 91b22b6e0a09..000000000000 --- a/src/client/testing/nosetest/main.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { inject, injectable } from 'inversify'; -import { Uri } from 'vscode'; -import { Product } from '../../common/types'; -import { IServiceContainer } from '../../ioc/types'; -import { NOSETEST_PROVIDER } from '../common/constants'; -import { BaseTestManager } from '../common/managers/baseTestManager'; -import { - IArgumentsService, - ITestManagerRunner, - ITestsHelper, - TestDiscoveryOptions, - TestFilter, - TestRunOptions, - Tests, - TestsToRun, -} from '../common/types'; - -@injectable() -export class TestManager extends BaseTestManager { - private readonly argsService: IArgumentsService; - private readonly helper: ITestsHelper; - private readonly runner: ITestManagerRunner; - public get enabled() { - return this.settings.testing.nosetestsEnabled; - } - constructor( - workspaceFolder: Uri, - rootDirectory: string, - @inject(IServiceContainer) serviceContainer: IServiceContainer, - ) { - super(NOSETEST_PROVIDER, Product.nosetest, workspaceFolder, rootDirectory, serviceContainer); - this.argsService = this.serviceContainer.get(IArgumentsService, this.testProvider); - this.helper = this.serviceContainer.get(ITestsHelper); - this.runner = this.serviceContainer.get(ITestManagerRunner, this.testProvider); - } - public getDiscoveryOptions(ignoreCache: boolean): TestDiscoveryOptions { - const args = this.settings.testing.nosetestArgs.slice(0); - return { - workspaceFolder: this.workspaceFolder, - cwd: this.rootDirectory, - args, - token: this.testDiscoveryCancellationToken!, - ignoreCache, - outChannel: this.outputChannel, - }; - } - public runTestImpl( - tests: Tests, - testsToRun?: TestsToRun, - runFailedTests?: boolean, - debug?: boolean, - ): Promise { - let args: string[]; - - const runAllTests = this.helper.shouldRunAllTests(testsToRun); - if (debug) { - args = this.argsService.filterArguments( - this.settings.testing.nosetestArgs, - runAllTests ? TestFilter.debugAll : TestFilter.debugSpecific, - ); - } else { - args = this.argsService.filterArguments( - this.settings.testing.nosetestArgs, - runAllTests ? TestFilter.runAll : TestFilter.runSpecific, - ); - } - - if (runFailedTests === true && args.indexOf('--failed') === -1) { - args.splice(0, 0, '--failed'); - } - if (!runFailedTests && args.indexOf('--with-id') === -1) { - args.splice(0, 0, '--with-id'); - } - const options: TestRunOptions = { - workspaceFolder: Uri.file(this.rootDirectory), - cwd: this.rootDirectory, - tests, - args, - testsToRun, - token: this.testRunnerCancellationToken!, - outChannel: this.outputChannel, - debug, - }; - return this.runner.runTest(this.testResultsService, options, this); - } -} diff --git a/src/client/testing/nosetest/runner.ts b/src/client/testing/nosetest/runner.ts deleted file mode 100644 index ef3cf74f3ad6..000000000000 --- a/src/client/testing/nosetest/runner.ts +++ /dev/null @@ -1,125 +0,0 @@ -'use strict'; - -import { inject, injectable } from 'inversify'; -import { IFileSystem, TemporaryFile } from '../../common/platform/types'; -import { noop } from '../../common/utils/misc'; -import { IServiceContainer } from '../../ioc/types'; -import { NOSETEST_PROVIDER } from '../common/constants'; -import { Options } from '../common/runner'; -import { - IArgumentsHelper, - IArgumentsService, - ITestDebugLauncher, - ITestManager, - ITestManagerRunner, - ITestResultsService, - ITestRunner, - IXUnitParser, - LaunchOptions, - TestRunOptions, - Tests, -} from '../common/types'; - -const WITH_XUNIT = '--with-xunit'; -const XUNIT_FILE = '--xunit-file'; - -@injectable() -export class TestManagerRunner implements ITestManagerRunner { - private readonly argsService: IArgumentsService; - private readonly argsHelper: IArgumentsHelper; - private readonly testRunner: ITestRunner; - private readonly xUnitParser: IXUnitParser; - private readonly fs: IFileSystem; - constructor(@inject(IServiceContainer) private serviceContainer: IServiceContainer) { - this.argsService = serviceContainer.get(IArgumentsService, NOSETEST_PROVIDER); - this.argsHelper = serviceContainer.get(IArgumentsHelper); - this.testRunner = serviceContainer.get(ITestRunner); - this.xUnitParser = this.serviceContainer.get(IXUnitParser); - this.fs = this.serviceContainer.get(IFileSystem); - } - public async runTest( - testResultsService: ITestResultsService, - options: TestRunOptions, - _: ITestManager, - ): Promise { - let testPaths: string[] = []; - if (options.testsToRun && options.testsToRun.testFolder) { - testPaths = testPaths.concat(options.testsToRun.testFolder.map((f) => f.nameToRun)); - } - if (options.testsToRun && options.testsToRun.testFile) { - testPaths = testPaths.concat(options.testsToRun.testFile.map((f) => f.nameToRun)); - } - if (options.testsToRun && options.testsToRun.testSuite) { - testPaths = testPaths.concat(options.testsToRun.testSuite.map((f) => f.nameToRun)); - } - if (options.testsToRun && options.testsToRun.testFunction) { - testPaths = testPaths.concat(options.testsToRun.testFunction.map((f) => f.nameToRun)); - } - - let deleteJUnitXmlFile: Function = noop; - const args = options.args; - // Check if '--with-xunit' is in args list - if (args.indexOf(WITH_XUNIT) === -1) { - args.splice(0, 0, WITH_XUNIT); - } - - try { - const xmlLogResult = await this.getUnitXmlFile(args); - const xmlLogFile = xmlLogResult.filePath; - deleteJUnitXmlFile = xmlLogResult.dispose; - // Remove the '--unixml' if it exists, and add it with our path. - const testArgs = this.argsService.filterArguments(args, [XUNIT_FILE]); - testArgs.splice(0, 0, `${XUNIT_FILE}=${xmlLogFile}`); - - // Positional arguments control the tests to be run. - testArgs.push(...testPaths); - - if (options.debug === true) { - const debugLauncher = this.serviceContainer.get(ITestDebugLauncher); - const debuggerArgs = [options.cwd, 'nose'].concat(testArgs); - const launchOptions: LaunchOptions = { - cwd: options.cwd, - args: debuggerArgs, - token: options.token, - outChannel: options.outChannel, - testProvider: NOSETEST_PROVIDER, - }; - await debugLauncher.launchDebugger(launchOptions); - } else { - const runOptions: Options = { - args: testArgs, - cwd: options.cwd, - outChannel: options.outChannel, - token: options.token, - workspaceFolder: options.workspaceFolder, - }; - await this.testRunner.run(NOSETEST_PROVIDER, runOptions); - } - - // Promise must resolve before return as result file will be deleted in finally block. - return await this.updateResultsFromLogFiles(options.tests, xmlLogFile, testResultsService); - } catch (ex) { - return Promise.reject(ex); - } finally { - deleteJUnitXmlFile(); - } - } - - private async updateResultsFromLogFiles( - tests: Tests, - outputXmlFile: string, - testResultsService: ITestResultsService, - ): Promise { - await this.xUnitParser.updateResultsFromXmlLogFile(tests, outputXmlFile); - testResultsService.updateResults(tests); - return tests; - } - private async getUnitXmlFile(args: string[]): Promise { - const xmlFile = this.argsHelper.getOptionValues(args, XUNIT_FILE); - if (typeof xmlFile === 'string') { - return { filePath: xmlFile, dispose: noop }; - } - - return this.fs.createTemporaryFile('.xml'); - } -} diff --git a/src/client/testing/nosetest/services/argsService.ts b/src/client/testing/nosetest/services/argsService.ts deleted file mode 100644 index 9ae3c5e81ea3..000000000000 --- a/src/client/testing/nosetest/services/argsService.ts +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { inject, injectable } from 'inversify'; -import { IServiceContainer } from '../../../ioc/types'; -import { IArgumentsHelper, IArgumentsService, TestFilter } from '../../common/types'; - -const OptionsWithArguments = [ - '--attr', - '--config', - '--cover-html-dir', - '--cover-min-percentage', - '--cover-package', - '--cover-xml-file', - '--debug', - '--debug-log', - '--doctest-extension', - '--doctest-fixtures', - '--doctest-options', - '--doctest-result-variable', - '--eval-attr', - '--exclude', - '--id-file', - '--ignore-files', - '--include', - '--log-config', - '--logging-config', - '--logging-datefmt', - '--logging-filter', - '--logging-format', - '--logging-level', - '--match', - '--process-timeout', - '--processes', - '--py3where', - '--testmatch', - '--tests', - '--verbosity', - '--where', - '--xunit-file', - '--xunit-testsuite-name', - '-A', - '-a', - '-c', - '-e', - '-i', - '-I', - '-l', - '-m', - '-w', - '--profile-restrict', - '--profile-sort', - '--profile-stats-file', -]; - -const OptionsWithoutArguments = [ - '-h', - '--help', - '-V', - '--version', - '-p', - '--plugins', - '-v', - '--verbose', - '--quiet', - '-x', - '--stop', - '-P', - '--no-path-adjustment', - '--exe', - '--noexe', - '--traverse-namespace', - '--first-package-wins', - '--first-pkg-wins', - '--1st-pkg-wins', - '--no-byte-compile', - '-s', - '--nocapture', - '--nologcapture', - '--logging-clear-handlers', - '--with-coverage', - '--cover-erase', - '--cover-tests', - '--cover-inclusive', - '--cover-html', - '--cover-branches', - '--cover-xml', - '--pdb', - '--pdb-failures', - '--pdb-errors', - '--no-deprecated', - '--with-doctest', - '--doctest-tests', - '--with-isolation', - '-d', - '--detailed-errors', - '--failure-detail', - '--no-skip', - '--with-id', - '--failed', - '--process-restartworker', - '--with-xunit', - '--all-modules', - '--collect-only', - '--with-profile', -]; - -@injectable() -export class ArgumentsService implements IArgumentsService { - private readonly helper: IArgumentsHelper; - constructor(@inject(IServiceContainer) serviceContainer: IServiceContainer) { - this.helper = serviceContainer.get(IArgumentsHelper); - } - public getKnownOptions(): { withArgs: string[]; withoutArgs: string[] } { - return { - withArgs: OptionsWithArguments, - withoutArgs: OptionsWithoutArguments, - }; - } - public getOptionValue(args: string[], option: string): string | string[] | undefined { - return this.helper.getOptionValues(args, option); - } - - public filterArguments(args: string[], argumentToRemoveOrFilter: string[] | TestFilter): string[] { - const optionsWithoutArgsToRemove: string[] = []; - const optionsWithArgsToRemove: string[] = []; - // Positional arguments in nosetest are test directories and files. - // So if we want to run a specific test, then remove positional args. - let removePositionalArgs = false; - if (Array.isArray(argumentToRemoveOrFilter)) { - argumentToRemoveOrFilter.forEach((item) => { - if (OptionsWithArguments.indexOf(item) >= 0) { - optionsWithArgsToRemove.push(item); - } - if (OptionsWithoutArguments.indexOf(item) >= 0) { - optionsWithoutArgsToRemove.push(item); - } - }); - } else { - switch (argumentToRemoveOrFilter) { - case TestFilter.removeTests: { - removePositionalArgs = true; - break; - } - case TestFilter.discovery: { - optionsWithoutArgsToRemove.push( - ...[ - '-v', - '--verbose', - '-q', - '--quiet', - '-x', - '--stop', - '--with-coverage', - ...OptionsWithoutArguments.filter((item) => item.startsWith('--cover')), - ...OptionsWithoutArguments.filter((item) => item.startsWith('--logging')), - ...OptionsWithoutArguments.filter((item) => item.startsWith('--pdb')), - ...OptionsWithoutArguments.filter((item) => item.indexOf('xunit') >= 0), - ], - ); - optionsWithArgsToRemove.push( - ...[ - '--verbosity', - '-l', - '--debug', - '--cover-package', - ...OptionsWithoutArguments.filter((item) => item.startsWith('--cover')), - ...OptionsWithArguments.filter((item) => item.startsWith('--logging')), - ...OptionsWithoutArguments.filter((item) => item.indexOf('xunit') >= 0), - ], - ); - break; - } - case TestFilter.debugAll: - case TestFilter.runAll: { - break; - } - case TestFilter.debugSpecific: - case TestFilter.runSpecific: { - removePositionalArgs = true; - break; - } - default: { - throw new Error(`Unsupported Filter '${argumentToRemoveOrFilter}'`); - } - } - } - - let filteredArgs = args.slice(); - if (removePositionalArgs) { - const positionalArgs = this.helper.getPositionalArguments( - filteredArgs, - OptionsWithArguments, - OptionsWithoutArguments, - ); - filteredArgs = filteredArgs.filter((item) => positionalArgs.indexOf(item) === -1); - } - return this.helper.filterArguments(filteredArgs, optionsWithArgsToRemove, optionsWithoutArgsToRemove); - } - public getTestFolders(args: string[]): string[] { - return this.helper.getPositionalArguments(args, OptionsWithArguments, OptionsWithoutArguments); - } -} diff --git a/src/client/testing/nosetest/services/discoveryService.ts b/src/client/testing/nosetest/services/discoveryService.ts deleted file mode 100644 index b6ebb7aec3fb..000000000000 --- a/src/client/testing/nosetest/services/discoveryService.ts +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -import { inject, injectable, named } from 'inversify'; -import { CancellationTokenSource } from 'vscode'; -import { IServiceContainer } from '../../../ioc/types'; -import { NOSETEST_PROVIDER } from '../../common/constants'; -import { Options } from '../../common/runner'; -import { - IArgumentsService, - ITestDiscoveryService, - ITestRunner, - ITestsParser, - TestDiscoveryOptions, - TestFilter, - Tests, -} from '../../common/types'; - -@injectable() -export class TestDiscoveryService implements ITestDiscoveryService { - private argsService: IArgumentsService; - private runner: ITestRunner; - constructor( - @inject(IServiceContainer) private serviceContainer: IServiceContainer, - @inject(ITestsParser) @named(NOSETEST_PROVIDER) private testParser: ITestsParser, - ) { - this.argsService = this.serviceContainer.get(IArgumentsService, NOSETEST_PROVIDER); - this.runner = this.serviceContainer.get(ITestRunner); - } - public async discoverTests(options: TestDiscoveryOptions): Promise { - // Remove unwanted arguments. - const args = this.argsService.filterArguments(options.args, TestFilter.discovery); - - const token = options.token ? options.token : new CancellationTokenSource().token; - const runOptions: Options = { - args: ['--collect-only', '-vvv'].concat(args), - cwd: options.cwd, - workspaceFolder: options.workspaceFolder, - token, - outChannel: options.outChannel, - }; - - const data = await this.runner.run(NOSETEST_PROVIDER, runOptions); - if (options.token && options.token.isCancellationRequested) { - return Promise.reject('cancelled'); - } - - return this.testParser.parse(data, options); - } -} diff --git a/src/client/testing/nosetest/services/parserService.ts b/src/client/testing/nosetest/services/parserService.ts deleted file mode 100644 index adf4058ea467..000000000000 --- a/src/client/testing/nosetest/services/parserService.ts +++ /dev/null @@ -1,193 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -import { inject, injectable } from 'inversify'; -import * as os from 'os'; -import * as path from 'path'; -import { Uri } from 'vscode'; -import { convertFileToPackage, extractBetweenDelimiters } from '../../common/testUtils'; -import { - ITestsHelper, - ITestsParser, - ParserOptions, - TestFile, - TestFunction, - Tests, - TestSuite, -} from '../../common/types'; - -const NOSE_WANT_FILE_PREFIX = 'nose.selector: DEBUG: wantFile '; -const NOSE_WANT_FILE_SUFFIX = '.py? True'; -const NOSE_WANT_FILE_SUFFIX_WITHOUT_EXT = '? True'; - -@injectable() -export class TestsParser implements ITestsParser { - constructor(@inject(ITestsHelper) private testsHelper: ITestsHelper) {} - public parse(content: string, options: ParserOptions): Tests { - let testFiles = this.getTestFiles(content, options); - // Exclude tests that don't have any functions or test suites. - testFiles = testFiles.filter((testFile) => { - testFile.suites = testFile.suites.filter((suite) => suite.functions.length > 0); - return testFile.suites.length > 0 || testFile.functions.length > 0; - }); - return this.testsHelper.flattenTestFiles(testFiles, options.cwd); - } - - private getTestFiles(content: string, options: ParserOptions) { - let logOutputLines: string[] = ['']; - const testFiles: TestFile[] = []; - content.split(/\r?\n/g).forEach((line, index, lines) => { - if ( - (line.startsWith(NOSE_WANT_FILE_PREFIX) && line.endsWith(NOSE_WANT_FILE_SUFFIX)) || - index === lines.length - 1 - ) { - // process the previous lines. - this.parseNoseTestModuleCollectionResult(options.cwd, logOutputLines, testFiles); - logOutputLines = ['']; - } - - if (index === 0) { - if (content.startsWith(os.EOL) || lines.length > 1) { - this.appendLine(line, logOutputLines); - return; - } - logOutputLines[logOutputLines.length - 1] += line; - return; - } - if (index === lines.length - 1) { - logOutputLines[logOutputLines.length - 1] += line; - return; - } - this.appendLine(line, logOutputLines); - return; - }); - - return testFiles; - } - private appendLine(line: string, logOutputLines: string[]) { - const lastLineIndex = logOutputLines.length - 1; - logOutputLines[lastLineIndex] += line; - - // Check whether the previous line is something that we need. - // What we need is a line that ends with ? True, - // and starts with nose.selector: DEBUG: want. - if (logOutputLines[lastLineIndex].endsWith('? True')) { - logOutputLines.push(''); - } else { - // We don't need this line - logOutputLines[lastLineIndex] = ''; - } - } - - private parseNoseTestModuleCollectionResult(rootDirectory: string, lines: string[], testFiles: TestFile[]) { - let currentPackage: string = ''; - let fileName = ''; - let testFile: TestFile; - const resource = Uri.file(rootDirectory); - - lines.forEach((line) => { - if (line.startsWith(NOSE_WANT_FILE_PREFIX) && line.endsWith(NOSE_WANT_FILE_SUFFIX)) { - fileName = line.substring(NOSE_WANT_FILE_PREFIX.length); - fileName = fileName.substring(0, fileName.lastIndexOf(NOSE_WANT_FILE_SUFFIX_WITHOUT_EXT)); - - // We need to display the path relative to the current directory. - fileName = fileName.substring(rootDirectory.length + 1); - // we don't care about the compiled file. - if (path.extname(fileName) === '.pyc' || path.extname(fileName) === '.pyo') { - fileName = fileName.substring(0, fileName.length - 1); - } - currentPackage = convertFileToPackage(fileName); - const fullyQualifiedName = path.isAbsolute(fileName) ? fileName : path.resolve(rootDirectory, fileName); - const baseName = path.basename(fullyQualifiedName); - testFile = { - resource, - functions: [], - suites: [], - name: baseName, - nameToRun: fileName, - xmlName: currentPackage, - time: 0, - functionsFailed: 0, - functionsPassed: 0, - fullPath: fullyQualifiedName, - }; - testFiles.push(testFile); - return; - } - - if (line.startsWith("nose.selector: DEBUG: wantClass ? True"); - const clsName = path.extname(name).substring(1); - const testSuite: TestSuite = { - resource, - name: clsName, - nameToRun: `${fileName}:${clsName}`, - functions: [], - suites: [], - xmlName: name, - time: 0, - isUnitTest: false, - isInstance: false, - functionsFailed: 0, - functionsPassed: 0, - }; - testFile.suites.push(testSuite); - return; - } - if (line.startsWith('nose.selector: DEBUG: wantClass ')) { - const name = extractBetweenDelimiters(line, 'nose.selector: DEBUG: wantClass ', '? True'); - const testSuite: TestSuite = { - resource, - name: path.extname(name).substring(1), - nameToRun: `${fileName}:.${name}`, - functions: [], - suites: [], - xmlName: name, - time: 0, - isUnitTest: false, - isInstance: false, - functionsFailed: 0, - functionsPassed: 0, - }; - testFile.suites.push(testSuite); - return; - } - if (line.startsWith('nose.selector: DEBUG: wantMethod ? True', - ); - const fnName = path.extname(name).substring(1); - const clsName = path.basename(name, path.extname(name)); - const fn: TestFunction = { - resource, - name: fnName, - nameToRun: `${fileName}:${clsName}.${fnName}`, - time: 0, - functionsFailed: 0, - functionsPassed: 0, - }; - - const cls = testFile.suites.find((suite) => suite.name === clsName); - if (cls) { - cls.functions.push(fn); - } - return; - } - if (line.startsWith('nose.selector: DEBUG: wantFunction { - const fs = this.serviceContainer.get(IFileSystem); - for (const cfg of ['.noserc', 'nose.cfg']) { - if (await fs.fileExists(path.join(wkspace.fsPath, cfg))) { - return true; - } - } - return false; - } - public async configure(wkspace: Uri): Promise { - const args: string[] = []; - const configFileOptionLabel = 'Use existing config file'; - // If a config file exits, there's nothing to be configured. - if (await this.requiresUserToConfigure(wkspace)) { - return; - } - const subDirs = await this.getTestDirs(wkspace.fsPath); - const testDir = await this.selectTestDir(wkspace.fsPath, subDirs); - if (typeof testDir === 'string' && testDir !== configFileOptionLabel) { - args.push(testDir); - } - const installed = await this.installer.isInstalled(Product.nosetest); - if (!installed) { - await this.installer.install(Product.nosetest); - } - await this.testConfigSettingsService.updateTestArgs(wkspace.fsPath, Product.nosetest, args); - } -} diff --git a/src/client/testing/serviceRegistry.ts b/src/client/testing/serviceRegistry.ts index 28342b97b04c..3250d79605ed 100644 --- a/src/client/testing/serviceRegistry.ts +++ b/src/client/testing/serviceRegistry.ts @@ -5,7 +5,7 @@ import { Uri } from 'vscode'; import { IExtensionActivationService, IExtensionSingleActivationService } from '../activation/types'; import { IServiceContainer, IServiceManager } from '../ioc/types'; import { ArgumentsHelper } from './common/argumentsHelper'; -import { NOSETEST_PROVIDER, PYTEST_PROVIDER, UNITTEST_PROVIDER } from './common/constants'; +import { PYTEST_PROVIDER, UNITTEST_PROVIDER } from './common/constants'; import { DebugLauncher } from './common/debugLauncher'; import { EnablementTracker } from './common/enablementTracker'; import { TestRunner } from './common/runner'; @@ -68,11 +68,6 @@ import { TestTreeViewProvider } from './explorer/testTreeViewProvider'; import { TestingService, UnitTestManagementService } from './main'; import { registerTypes as registerNavigationTypes } from './navigation/serviceRegistry'; import { ITestExplorerCommandHandler } from './navigation/types'; -import { TestManager as NoseTestManager } from './nosetest/main'; -import { TestManagerRunner as NoseTestManagerRunner } from './nosetest/runner'; -import { ArgumentsService as NoseTestArgumentsService } from './nosetest/services/argsService'; -import { TestDiscoveryService as NoseTestDiscoveryService } from './nosetest/services/discoveryService'; -import { TestsParser as NoseTestTestsParser } from './nosetest/services/parserService'; import { TestManager as PyTestTestManager } from './pytest/main'; import { TestManagerRunner as PytestManagerRunner } from './pytest/runner'; import { ArgumentsService as PyTestArgumentsService } from './pytest/services/argsService'; @@ -112,11 +107,9 @@ export function registerTypes(serviceManager: IServiceManager) { serviceManager.add(ITestVisitor, TestResultResetVisitor, 'TestResultResetVisitor'); serviceManager.add(ITestsParser, UnitTestTestsParser, UNITTEST_PROVIDER); - serviceManager.add(ITestsParser, NoseTestTestsParser, NOSETEST_PROVIDER); serviceManager.add(ITestDiscoveryService, UnitTestTestDiscoveryService, UNITTEST_PROVIDER); serviceManager.add(ITestDiscoveryService, PytestTestDiscoveryService, PYTEST_PROVIDER); - serviceManager.add(ITestDiscoveryService, NoseTestDiscoveryService, NOSETEST_PROVIDER); serviceManager.add(IArgumentsHelper, ArgumentsHelper); serviceManager.add(ITestRunner, TestRunner); @@ -124,10 +117,8 @@ export function registerTypes(serviceManager: IServiceManager) { serviceManager.add(IUnitTestHelper, UnitTestHelper); serviceManager.add(IArgumentsService, PyTestArgumentsService, PYTEST_PROVIDER); - serviceManager.add(IArgumentsService, NoseTestArgumentsService, NOSETEST_PROVIDER); serviceManager.add(IArgumentsService, UnitTestArgumentsService, UNITTEST_PROVIDER); serviceManager.add(ITestManagerRunner, PytestManagerRunner, PYTEST_PROVIDER); - serviceManager.add(ITestManagerRunner, NoseTestManagerRunner, NOSETEST_PROVIDER); serviceManager.add(ITestManagerRunner, UnitTestTestManagerRunner, UNITTEST_PROVIDER); serviceManager.addSingleton(ITestConfigurationService, UnitTestConfigurationService); @@ -162,9 +153,6 @@ export function registerTypes(serviceManager: IServiceManager) { const serviceContainer = context.container.get(IServiceContainer); switch (testProvider) { - case NOSETEST_PROVIDER: { - return new NoseTestManager(workspaceFolder, rootDirectory, serviceContainer); - } case PYTEST_PROVIDER: { return new PyTestTestManager(workspaceFolder, rootDirectory, serviceContainer); } diff --git a/src/client/testing/types.ts b/src/client/testing/types.ts index 9a67854ebbb2..a362f898d22d 100644 --- a/src/client/testing/types.ts +++ b/src/client/testing/types.ts @@ -7,7 +7,7 @@ import { DocumentSymbolProvider } from 'vscode'; import { Product } from '../common/types'; import { TestSettingsPropertyNames } from './configuration/types'; -export type TestProvider = 'nosetest' | 'pytest' | 'unittest'; +export type TestProvider = 'pytest' | 'unittest'; // **************** // interfaces diff --git a/src/test/.vscode/settings.json b/src/test/.vscode/settings.json index 3d68e9e0284c..ad72e930aca3 100644 --- a/src/test/.vscode/settings.json +++ b/src/test/.vscode/settings.json @@ -2,17 +2,8 @@ "python.linting.pylintEnabled": false, "python.linting.flake8Enabled": false, "python.workspaceSymbols.enabled": false, - "python.testing.nosetestArgs": [], "python.testing.pytestArgs": [], - "python.testing.unittestArgs": [ - "-s=./tests", - "-p=test_*.py", - "-v", - "-s", - ".", - "-p", - "*test*.py" - ], + "python.testing.unittestArgs": ["-s=./tests", "-p=test_*.py", "-v", "-s", ".", "-p", "*test*.py"], "python.sortImports.args": [], "python.linting.lintOnSave": false, "python.linting.enabled": true, diff --git a/src/test/common.ts b/src/test/common.ts index 38f89a075a90..f9e9480493f1 100644 --- a/src/test/common.ts +++ b/src/test/common.ts @@ -49,12 +49,10 @@ export type PythonSettingKeys = | 'linting.pydocstyleEnabled' | 'linting.mypyEnabled' | 'linting.banditEnabled' - | 'testing.nosetestArgs' | 'testing.pytestArgs' | 'testing.unittestArgs' | 'formatting.provider' | 'sortImports.args' - | 'testing.nosetestsEnabled' | 'testing.pytestEnabled' | 'testing.unittestEnabled' | 'envFile' diff --git a/src/test/common/installer.test.ts b/src/test/common/installer.test.ts index 6735ec5d31ce..c8f46a1aca4c 100644 --- a/src/test/common/installer.test.ts +++ b/src/test/common/installer.test.ts @@ -108,7 +108,6 @@ import { IPersistentStateFactory, IRandom, IsWindows, - ModuleNamePurpose, Product, ProductType, } from '../../client/common/types'; @@ -303,7 +302,7 @@ suite('Installer', () => { .create()) as MockProcessService; const checkInstalledDef = createDeferred(); processService.onExec((_file, args, _options, callback) => { - const moduleName = installer.translateProductToModuleName(product, ModuleNamePurpose.run); + const moduleName = installer.translateProductToModuleName(product); if (args.length > 1 && args[0] === '-c' && args[1] === `import ${moduleName}`) { checkInstalledDef.resolve(true); } diff --git a/src/test/common/installer/moduleInstaller.unit.test.ts b/src/test/common/installer/moduleInstaller.unit.test.ts index 53b5cf8936ea..df0f734d32ed 100644 --- a/src/test/common/installer/moduleInstaller.unit.test.ts +++ b/src/test/common/installer/moduleInstaller.unit.test.ts @@ -41,7 +41,6 @@ import { IExperimentService, IOutputChannel, IPythonSettings, - ModuleNamePurpose, Product, } from '../../../client/common/types'; import { getNamesAndValues } from '../../../client/common/utils/enum'; @@ -672,7 +671,7 @@ function getModuleNamesForTesting(): { name: string; value: Product; moduleName: const mockOutChnl = TypeMoq.Mock.ofType().object; try { const prodInstaller = new ProductInstaller(mockSvc, mockOutChnl); - moduleName = prodInstaller.translateProductToModuleName(product.value, ModuleNamePurpose.install); + moduleName = prodInstaller.translateProductToModuleName(product.value); return { name: product.name, value: product.value, moduleName }; } catch { return undefined; diff --git a/src/test/common/installer/productPath.unit.test.ts b/src/test/common/installer/productPath.unit.test.ts index ab561f9d6167..a01fd5a40c0f 100644 --- a/src/test/common/installer/productPath.unit.test.ts +++ b/src/test/common/installer/productPath.unit.test.ts @@ -26,7 +26,6 @@ import { IInstaller, IPythonSettings, IWorkspaceSymbolSettings, - ModuleNamePurpose, Product, ProductType, } from '../../../client/common/types'; @@ -178,10 +177,7 @@ suite('Product Path', () => { const productPathService = new RefactoringLibraryProductPathService(serviceContainer.object); const value = productPathService.getExecutableNameFromSettings(product.value, resource); - const moduleName = productInstaller.translateProductToModuleName( - product.value, - ModuleNamePurpose.run, - ); + const moduleName = productInstaller.translateProductToModuleName(product.value); expect(value).to.be.equal(moduleName); }); break; @@ -219,12 +215,12 @@ suite('Product Path', () => { return { argsName: 'autoTestDiscoverOnSaveEnabled', enabledName: 'autoTestDiscoverOnSaveEnabled', - pathName: 'nosetestPath', + pathName: 'pytestPath', }; }) .verifiable(TypeMoq.Times.once()); unitTestSettings - .setup((u) => u.nosetestPath) + .setup((u) => u.pytestPath) .returns(() => expectedPath) .verifiable(TypeMoq.Times.atLeastOnce()); @@ -253,10 +249,7 @@ suite('Product Path', () => { .verifiable(TypeMoq.Times.once()); const value = productPathService.getExecutableNameFromSettings(product.value, resource); - const moduleName = productInstaller.translateProductToModuleName( - product.value, - ModuleNamePurpose.run, - ); + const moduleName = productInstaller.translateProductToModuleName(product.value); expect(value).to.be.equal(moduleName); testHelper.verifyAll(); }); diff --git a/src/test/pythonFiles/testFiles/noseFiles/five.output b/src/test/pythonFiles/testFiles/noseFiles/five.output deleted file mode 100644 index 8b0d557303f7..000000000000 --- a/src/test/pythonFiles/testFiles/noseFiles/five.output +++ /dev/null @@ -1,121 +0,0 @@ -nose.config: INFO: Ignoring files matching ['^\\.', '^_', '^setup\\.py$'] -nose.plugins.manager: DEBUG: Configuring plugins -nose.plugins.manager: DEBUG: Plugins enabled: [, , , , ] -nose.core: DEBUG: configured Config(addPaths=True, args=(), configSection='nosetests', debug=None, debugLog=None, env={}, exclude=None, files=[], firstPackageWins=False, getTestCaseNamesCompat=False, ignoreFiles=[re.compile('^\\.'), re.compile('^_'), re.compile('^setup\\.py$')], ignoreFilesDefaultStrings=['^\\.', '^_', '^setup\\.py$'], include=None, includeExe=False, logStream=<_io.TextIOWrapper name='' mode='w' encoding='UTF-8'>, loggingConfig=None, options=, parser=, parserClass=, plugins=, py3where=(), runOnInit=True, srcDirs=('lib', 'src'), stopOnError=False, stream=<_io.TextIOWrapper name='' mode='w' encoding='UTF-8'>, testMatch=re.compile('test_'), testMatchPat='(?:^|[\\b_\\./-])[Tt]est', testNames=[], traverseNamespace=False, verbosity=4, where=(), worker=False, workingDir='/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles') -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.importer: DEBUG: insert /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles into sys.path -nose.plugins.collect: DEBUG: Preparing test loader -nose.core: DEBUG: test loader is -nose.core: DEBUG: defaultTest . -nose.core: DEBUG: Test names are ['.'] -nose.core: DEBUG: createTests called with None -nose.loader: DEBUG: load from . (None) -nose.selector: DEBUG: Test name . resolved to file ., module None, call None -nose.selector: DEBUG: Final resolution of test name .: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles module None call None -nose.plugins.collect: DEBUG: TestSuite([]) -nose.plugins.collect: DEBUG: Add test -nose.core: DEBUG: runTests called -nose.suite: DEBUG: precache is [] -nose.loader: DEBUG: load from dir /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/four.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/one.output? False -nose.selector: DEBUG: wantDirectory /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/specific? False -nose.selector: DEBUG: wantDirectory /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/three.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/two.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py module test_root call None -nose.importer: DEBUG: Import test_root from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.importer: DEBUG: find module part test_root (test_root) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_Root_A (test_root.Test_Root_test1) -nose.plugins.collect: DEBUG: Add test test_Root_B (test_root.Test_Root_test1) -nose.plugins.collect: DEBUG: Add test test_Root_c (test_root.Test_Root_test1) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test(), Test()]> -nose.plugins.collect: DEBUG: Preparing test case test_Root_A (test_root.Test_Root_test1) -test_Root_A (test_root.Test_Root_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_Root_B (test_root.Test_Root_test1) -test_Root_B (test_root.Test_Root_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_Root_c (test_root.Test_Root_test1) -test_Root_c (test_root.Test_Root_test1) ... ok -nose.suite: DEBUG: precache is [] - ----------------------------------------------------------------------- -Ran 3 tests in 0.022s - -OK diff --git a/src/test/pythonFiles/testFiles/noseFiles/four.output b/src/test/pythonFiles/testFiles/noseFiles/four.output deleted file mode 100644 index 511f0b1c863c..000000000000 --- a/src/test/pythonFiles/testFiles/noseFiles/four.output +++ /dev/null @@ -1,205 +0,0 @@ -nose.config: INFO: Set working dir to /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/specific -nose.config: INFO: Ignoring files matching ['^\\.', '^_', '^setup\\.py$'] -nose.plugins.manager: DEBUG: Configuring plugins -nose.plugins.manager: DEBUG: Plugins enabled: [, , , , ] -nose.core: DEBUG: configured Config(addPaths=True, args=(), configSection='nosetests', debug=None, debugLog=None, env={}, exclude=None, files=[], firstPackageWins=False, getTestCaseNamesCompat=False, ignoreFiles=[re.compile('^\\.'), re.compile('^_'), re.compile('^setup\\.py$')], ignoreFilesDefaultStrings=['^\\.', '^_', '^setup\\.py$'], include=None, includeExe=False, logStream=<_io.TextIOWrapper name='' mode='w' encoding='UTF-8'>, loggingConfig=None, options=, parser=, parserClass=, plugins=, py3where=(), runOnInit=True, srcDirs=('lib', 'src'), stopOnError=False, stream=<_io.TextIOWrapper name='' mode='w' encoding='UTF-8'>, testMatch=re.compile('tst'), testMatchPat='(?:^|[\\b_\\./-])[Tt]est', testNames=[], traverseNamespace=False, verbosity=4, where=(), worker=False, workingDir='/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/specific') -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/specific -nose.importer: DEBUG: insert /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/specific into sys.path -nose.plugins.collect: DEBUG: Preparing test loader -nose.core: DEBUG: test loader is -nose.core: DEBUG: defaultTest . -nose.core: DEBUG: Test names are ['.'] -nose.core: DEBUG: createTests called with None -nose.loader: DEBUG: load from . (None) -nose.selector: DEBUG: Test name . resolved to file ., module None, call None -nose.selector: DEBUG: Final resolution of test name .: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/specific module None call None -nose.plugins.collect: DEBUG: TestSuite([]) -nose.plugins.collect: DEBUG: Add test -nose.core: DEBUG: runTests called -nose.suite: DEBUG: precache is [] -nose.loader: DEBUG: load from dir /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/specific -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/specific -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/specific/tst_unittest_one.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/specific/tst_unittest_one.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/specific/tst_unittest_one.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/specific/tst_unittest_one.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/specific/tst_unittest_one.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/specific/tst_unittest_one.py module tst_unittest_one call None -nose.importer: DEBUG: Import tst_unittest_one from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/specific -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/specific -nose.importer: DEBUG: find module part tst_unittest_one (tst_unittest_one) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/specific'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test tst_A (tst_unittest_one.Test_test1) -nose.plugins.collect: DEBUG: Add test tst_B (tst_unittest_one.Test_test1) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test()]> -nose.plugins.collect: DEBUG: Preparing test case tst_A (tst_unittest_one.Test_test1) -tst_A (tst_unittest_one.Test_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case tst_B (tst_unittest_one.Test_test1) -tst_B (tst_unittest_one.Test_test1) ... ok -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/specific/tst_unittest_two.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/specific/tst_unittest_two.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/specific/tst_unittest_two.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/specific/tst_unittest_two.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/specific/tst_unittest_two.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/specific/tst_unittest_two.py module tst_unittest_two call None -nose.importer: DEBUG: Import tst_unittest_two from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/specific -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/specific -nose.importer: DEBUG: find module part tst_unittest_two (tst_unittest_two) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/specific'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test tst_A2 (tst_unittest_two.Tst_test2) -nose.plugins.collect: DEBUG: Add test tst_B2 (tst_unittest_two.Tst_test2) -nose.plugins.collect: DEBUG: Add test tst_C2 (tst_unittest_two.Tst_test2) -nose.plugins.collect: DEBUG: Add test tst_D2 (tst_unittest_two.Tst_test2) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test(), Test(), Test()]> -nose.plugins.collect: DEBUG: Preparing test case tst_A2 (tst_unittest_two.Tst_test2) -tst_A2 (tst_unittest_two.Tst_test2) ... ok -nose.plugins.collect: DEBUG: Preparing test case tst_B2 (tst_unittest_two.Tst_test2) -tst_B2 (tst_unittest_two.Tst_test2) ... ok -nose.plugins.collect: DEBUG: Preparing test case tst_C2 (tst_unittest_two.Tst_test2) -tst_C2 (tst_unittest_two.Tst_test2) ... ok -nose.plugins.collect: DEBUG: Preparing test case tst_D2 (tst_unittest_two.Tst_test2) -tst_D2 (tst_unittest_two.Tst_test2) ... ok -nose.suite: DEBUG: precache is [] - ----------------------------------------------------------------------- -Ran 6 tests in 0.033s - -OK diff --git a/src/test/pythonFiles/testFiles/noseFiles/one.output b/src/test/pythonFiles/testFiles/noseFiles/one.output deleted file mode 100644 index cafdaf5b906a..000000000000 --- a/src/test/pythonFiles/testFiles/noseFiles/one.output +++ /dev/null @@ -1,211 +0,0 @@ -nose.config: INFO: Ignoring files matching ['^\\.', '^_', '^setup\\.py$'] -nose.plugins.manager: DEBUG: Configuring plugins -nose.plugins.manager: DEBUG: Plugins enabled: [, , , , ] -nose.core: DEBUG: configured Config(addPaths=True, args=(), configSection='nosetests', debug=None, debugLog=None, env={}, exclude=None, files=[], firstPackageWins=False, getTestCaseNamesCompat=False, ignoreFiles=[re.compile('^\\.'), re.compile('^_'), re.compile('^setup\\.py$')], ignoreFilesDefaultStrings=['^\\.', '^_', '^setup\\.py$'], include=None, includeExe=False, logStream=<_io.TextIOWrapper name='' mode='w' encoding='UTF-8'>, loggingConfig=None, options=, parser=, parserClass=, plugins=, py3where=(), runOnInit=True, srcDirs=('lib', 'src'), stopOnError=False, stream=<_io.TextIOWrapper name='' mode='w' encoding='UTF-8'>, testMatch=re.compile('(?:^|[\\b_\\./-])[Tt]est'), testMatchPat='(?:^|[\\b_\\./-])[Tt]est', testNames=[], traverseNamespace=False, verbosity=4, where=(), worker=False, workingDir='/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single') -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single -nose.importer: DEBUG: insert /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single into sys.path -nose.plugins.collect: DEBUG: Preparing test loader -nose.core: DEBUG: test loader is -nose.core: DEBUG: defaultTest . -nose.core: DEBUG: Test names are ['.'] -nose.core: DEBUG: createTests called with None -nose.loader: DEBUG: load from . (None) -nose.selector: DEBUG: Test name . resolved to file ., module None, call None -nose.selector: DEBUG: Final resolution of test name .: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single module None call None -nose.plugins.collect: DEBUG: TestSuite([]) -nose.plugins.collect: DEBUG: Add test -nose.core: DEBUG: runTests called -nose.suite: DEBUG: precache is [] -nose.loader: DEBUG: load from dir /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/test_root.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/test_root.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/test_root.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/test_root.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/test_root.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/test_root.py module test_root call None -nose.importer: DEBUG: Import test_root from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single -nose.importer: DEBUG: find module part test_root (test_root) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_Root_A (test_root.Test_Root_test1) -nose.plugins.collect: DEBUG: Add test test_Root_B (test_root.Test_Root_test1) -nose.plugins.collect: DEBUG: Add test test_Root_c (test_root.Test_Root_test1) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test(), Test()]> -nose.plugins.collect: DEBUG: Preparing test case test_Root_A (test_root.Test_Root_test1) -test_Root_A (test_root.Test_Root_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_Root_B (test_root.Test_Root_test1) -test_Root_B (test_root.Test_Root_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_Root_c (test_root.Test_Root_test1) -test_Root_c (test_root.Test_Root_test1) ... ok -nose.selector: DEBUG: wantDirectory /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/tests? True -nose.plugins.collect: DEBUG: TestSuite() -nose.loader: DEBUG: load from dir /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/tests -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/tests -nose.importer: DEBUG: insert /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/tests into sys.path -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/tests/test_one.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/tests/test_one.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/tests/test_one.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/tests/test_one.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/tests/test_one.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/tests/test_one.py module test_one call None -nose.importer: DEBUG: Import test_one from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/tests -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/tests -nose.importer: DEBUG: find module part test_one (test_one) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/tests'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_A (test_one.Test_test1) -nose.plugins.collect: DEBUG: Add test test_B (test_one.Test_test1) -nose.plugins.collect: DEBUG: Add test test_c (test_one.Test_test1) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test(), Test()]> -nose.plugins.collect: DEBUG: Add test ), Test(), Test()]>]> -nose.importer: DEBUG: Remove path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/tests -nose.plugins.collect: DEBUG: Preparing test case test_A (test_one.Test_test1) -test_A (test_one.Test_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_B (test_one.Test_test1) -test_B (test_one.Test_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_c (test_one.Test_test1) -test_c (test_one.Test_test1) ... ok -nose.suite: DEBUG: precache is [] - ----------------------------------------------------------------------- -Ran 6 tests in 0.023s - -OK diff --git a/src/test/pythonFiles/testFiles/noseFiles/run.five.output b/src/test/pythonFiles/testFiles/noseFiles/run.five.output deleted file mode 100644 index 640132ffe72e..000000000000 --- a/src/test/pythonFiles/testFiles/noseFiles/run.five.output +++ /dev/null @@ -1,567 +0,0 @@ -nose.config: INFO: Ignoring files matching ['^\\.', '^_', '^setup\\.py$'] -nose.plugins.manager: DEBUG: Configuring plugins -nose.plugins.manager: DEBUG: Plugins enabled: [, , , , ] -nose.core: DEBUG: configured Config(addPaths=True, args=(), configSection='nosetests', debug=None, debugLog=None, env={}, exclude=None, files=[], firstPackageWins=False, getTestCaseNamesCompat=False, ignoreFiles=[re.compile('^\\.'), re.compile('^_'), re.compile('^setup\\.py$')], ignoreFilesDefaultStrings=['^\\.', '^_', '^setup\\.py$'], include=None, includeExe=False, logStream=<_io.TextIOWrapper name='' mode='w' encoding='UTF-8'>, loggingConfig=None, options=, parser=, parserClass=, plugins=, py3where=(), runOnInit=True, srcDirs=('lib', 'src'), stopOnError=False, stream=<_io.TextIOWrapper name='' mode='w' encoding='UTF-8'>, testMatch=re.compile('test'), testMatchPat='(?:^|[\\b_\\./-])[Tt]est', testNames=[], traverseNamespace=False, verbosity=4, where=(), worker=False, workingDir='/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles') -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.importer: DEBUG: insert /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles into sys.path -nose.plugins.collect: DEBUG: Preparing test loader -nose.core: DEBUG: test loader is -nose.core: DEBUG: defaultTest . -nose.core: DEBUG: Test names are ['.'] -nose.core: DEBUG: createTests called with None -nose.loader: DEBUG: load from . (None) -nose.selector: DEBUG: Test name . resolved to file ., module None, call None -nose.selector: DEBUG: Final resolution of test name .: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles module None call None -nose.plugins.collect: DEBUG: TestSuite([]) -nose.plugins.collect: DEBUG: Add test -nose.core: DEBUG: runTests called -nose.suite: DEBUG: precache is [] -nose.loader: DEBUG: load from dir /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/five.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/four.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/one.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/run.four.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/run.four.result? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/run.one.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/run.one.result? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/run.three.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/run.three.result? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/run.two.again.result? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/run.two.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/run.two.result? False -nose.selector: DEBUG: wantDirectory /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/specific? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/three.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/two.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py module test_root call None -nose.importer: DEBUG: Import test_root from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.importer: DEBUG: find module part test_root (test_root) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_Root_A (test_root.Test_Root_test1) -nose.plugins.collect: DEBUG: Add test test_Root_B (test_root.Test_Root_test1) -nose.plugins.collect: DEBUG: Add test test_Root_c (test_root.Test_Root_test1) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test(), Test()]> -nose.plugins.collect: DEBUG: Preparing test case test_Root_A (test_root.Test_Root_test1) -test_Root_A (test_root.Test_Root_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_Root_B (test_root.Test_Root_test1) -test_Root_B (test_root.Test_Root_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_Root_c (test_root.Test_Root_test1) -test_Root_c (test_root.Test_Root_test1) ... ok -nose.selector: DEBUG: wantDirectory /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests? True -nose.plugins.collect: DEBUG: TestSuite() -nose.loader: DEBUG: load from dir /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: insert /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests into sys.path -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py module test4 call None -nose.importer: DEBUG: Import test4 from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: find module part test4 (test4) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test4A (test4.Test_test3) -nose.plugins.collect: DEBUG: Add test test4B (test4.Test_test3) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test()]> -nose.plugins.collect: DEBUG: Add test ), Test()]>]> -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py module test_unittest_one call None -nose.importer: DEBUG: Import test_unittest_one from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: find module part test_unittest_one (test_unittest_one) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_A (test_unittest_one.Test_test1) -nose.plugins.collect: DEBUG: Add test test_B (test_unittest_one.Test_test1) -nose.plugins.collect: DEBUG: Add test test_c (test_unittest_one.Test_test1) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test(), Test()]> -nose.plugins.collect: DEBUG: Add test ), Test(), Test()]>]> -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py module test_unittest_two call None -nose.importer: DEBUG: Import test_unittest_two from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: find module part test_unittest_two (test_unittest_two) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_A2 (test_unittest_two.Test_test2) -nose.plugins.collect: DEBUG: Add test test_B2 (test_unittest_two.Test_test2) -nose.plugins.collect: DEBUG: Add test test_C2 (test_unittest_two.Test_test2) -nose.plugins.collect: DEBUG: Add test test_D2 (test_unittest_two.Test_test2) -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_222A2 (test_unittest_two.Test_test2a) -nose.plugins.collect: DEBUG: Add test test_222B2 (test_unittest_two.Test_test2a) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test(), Test(), Test()]> -nose.plugins.collect: DEBUG: Add test ), Test()]> -nose.plugins.collect: DEBUG: Add test ), Test(), Test(), Test()]>, ), Test()]>]> -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py module unittest_three_test call None -nose.importer: DEBUG: Import unittest_three_test from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: find module part unittest_three_test (unittest_three_test) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_A (unittest_three_test.Test_test3) -nose.plugins.collect: DEBUG: Add test test_B (unittest_three_test.Test_test3) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test()]> -nose.plugins.collect: DEBUG: Add test ), Test()]>]> -nose.importer: DEBUG: Remove path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.plugins.collect: DEBUG: Preparing test case test4A (test4.Test_test3) -test4A (test4.Test_test3) ... ok -nose.plugins.collect: DEBUG: Preparing test case test4B (test4.Test_test3) -test4B (test4.Test_test3) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_A (test_unittest_one.Test_test1) -test_A (test_unittest_one.Test_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_B (test_unittest_one.Test_test1) -test_B (test_unittest_one.Test_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_c (test_unittest_one.Test_test1) -test_c (test_unittest_one.Test_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_A2 (test_unittest_two.Test_test2) -test_A2 (test_unittest_two.Test_test2) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_B2 (test_unittest_two.Test_test2) -test_B2 (test_unittest_two.Test_test2) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_C2 (test_unittest_two.Test_test2) -test_C2 (test_unittest_two.Test_test2) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_D2 (test_unittest_two.Test_test2) -test_D2 (test_unittest_two.Test_test2) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_222A2 (test_unittest_two.Test_test2a) -test_222A2 (test_unittest_two.Test_test2a) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_222B2 (test_unittest_two.Test_test2a) -test_222B2 (test_unittest_two.Test_test2a) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_A (unittest_three_test.Test_test3) -test_A (unittest_three_test.Test_test3) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_B (unittest_three_test.Test_test3) -test_B (unittest_three_test.Test_test3) ... ok -nose.suite: DEBUG: precache is [] - ----------------------------------------------------------------------- -Ran 16 tests in 0.048s - -OK diff --git a/src/test/pythonFiles/testFiles/noseFiles/run.five.result b/src/test/pythonFiles/testFiles/noseFiles/run.five.result deleted file mode 100644 index 97c7e0e0216f..000000000000 --- a/src/test/pythonFiles/testFiles/noseFiles/run.five.result +++ /dev/null @@ -1,11 +0,0 @@ - diff --git a/src/test/pythonFiles/testFiles/noseFiles/run.four.output b/src/test/pythonFiles/testFiles/noseFiles/run.four.output deleted file mode 100644 index aa01067d7925..000000000000 --- a/src/test/pythonFiles/testFiles/noseFiles/run.four.output +++ /dev/null @@ -1,565 +0,0 @@ -nose.config: INFO: Ignoring files matching ['^\\.', '^_', '^setup\\.py$'] -nose.plugins.manager: DEBUG: Configuring plugins -nose.plugins.manager: DEBUG: Plugins enabled: [, , , , ] -nose.core: DEBUG: configured Config(addPaths=True, args=(), configSection='nosetests', debug=None, debugLog=None, env={}, exclude=None, files=[], firstPackageWins=False, getTestCaseNamesCompat=False, ignoreFiles=[re.compile('^\\.'), re.compile('^_'), re.compile('^setup\\.py$')], ignoreFilesDefaultStrings=['^\\.', '^_', '^setup\\.py$'], include=None, includeExe=False, logStream=<_io.TextIOWrapper name='' mode='w' encoding='UTF-8'>, loggingConfig=None, options=, parser=, parserClass=, plugins=, py3where=(), runOnInit=True, srcDirs=('lib', 'src'), stopOnError=False, stream=<_io.TextIOWrapper name='' mode='w' encoding='UTF-8'>, testMatch=re.compile('test'), testMatchPat='(?:^|[\\b_\\./-])[Tt]est', testNames=[], traverseNamespace=False, verbosity=4, where=(), worker=False, workingDir='/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles') -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.importer: DEBUG: insert /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles into sys.path -nose.plugins.collect: DEBUG: Preparing test loader -nose.core: DEBUG: test loader is -nose.core: DEBUG: defaultTest . -nose.core: DEBUG: Test names are ['.'] -nose.core: DEBUG: createTests called with None -nose.loader: DEBUG: load from . (None) -nose.selector: DEBUG: Test name . resolved to file ., module None, call None -nose.selector: DEBUG: Final resolution of test name .: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles module None call None -nose.plugins.collect: DEBUG: TestSuite([]) -nose.plugins.collect: DEBUG: Add test -nose.core: DEBUG: runTests called -nose.suite: DEBUG: precache is [] -nose.loader: DEBUG: load from dir /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/five.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/four.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/one.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/run.one.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/run.one.result? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/run.three.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/run.three.result? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/run.two.again.result? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/run.two.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/run.two.result? False -nose.selector: DEBUG: wantDirectory /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/specific? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/three.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/two.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py module test_root call None -nose.importer: DEBUG: Import test_root from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.importer: DEBUG: find module part test_root (test_root) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_Root_A (test_root.Test_Root_test1) -nose.plugins.collect: DEBUG: Add test test_Root_B (test_root.Test_Root_test1) -nose.plugins.collect: DEBUG: Add test test_Root_c (test_root.Test_Root_test1) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test(), Test()]> -nose.plugins.collect: DEBUG: Preparing test case test_Root_A (test_root.Test_Root_test1) -test_Root_A (test_root.Test_Root_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_Root_B (test_root.Test_Root_test1) -test_Root_B (test_root.Test_Root_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_Root_c (test_root.Test_Root_test1) -test_Root_c (test_root.Test_Root_test1) ... ok -nose.selector: DEBUG: wantDirectory /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests? True -nose.plugins.collect: DEBUG: TestSuite() -nose.loader: DEBUG: load from dir /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: insert /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests into sys.path -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py module test4 call None -nose.importer: DEBUG: Import test4 from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: find module part test4 (test4) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test4A (test4.Test_test3) -nose.plugins.collect: DEBUG: Add test test4B (test4.Test_test3) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test()]> -nose.plugins.collect: DEBUG: Add test ), Test()]>]> -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py module test_unittest_one call None -nose.importer: DEBUG: Import test_unittest_one from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: find module part test_unittest_one (test_unittest_one) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_A (test_unittest_one.Test_test1) -nose.plugins.collect: DEBUG: Add test test_B (test_unittest_one.Test_test1) -nose.plugins.collect: DEBUG: Add test test_c (test_unittest_one.Test_test1) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test(), Test()]> -nose.plugins.collect: DEBUG: Add test ), Test(), Test()]>]> -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py module test_unittest_two call None -nose.importer: DEBUG: Import test_unittest_two from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: find module part test_unittest_two (test_unittest_two) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_A2 (test_unittest_two.Test_test2) -nose.plugins.collect: DEBUG: Add test test_B2 (test_unittest_two.Test_test2) -nose.plugins.collect: DEBUG: Add test test_C2 (test_unittest_two.Test_test2) -nose.plugins.collect: DEBUG: Add test test_D2 (test_unittest_two.Test_test2) -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_222A2 (test_unittest_two.Test_test2a) -nose.plugins.collect: DEBUG: Add test test_222B2 (test_unittest_two.Test_test2a) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test(), Test(), Test()]> -nose.plugins.collect: DEBUG: Add test ), Test()]> -nose.plugins.collect: DEBUG: Add test ), Test(), Test(), Test()]>, ), Test()]>]> -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py module unittest_three_test call None -nose.importer: DEBUG: Import unittest_three_test from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: find module part unittest_three_test (unittest_three_test) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_A (unittest_three_test.Test_test3) -nose.plugins.collect: DEBUG: Add test test_B (unittest_three_test.Test_test3) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test()]> -nose.plugins.collect: DEBUG: Add test ), Test()]>]> -nose.importer: DEBUG: Remove path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.plugins.collect: DEBUG: Preparing test case test4A (test4.Test_test3) -test4A (test4.Test_test3) ... ok -nose.plugins.collect: DEBUG: Preparing test case test4B (test4.Test_test3) -test4B (test4.Test_test3) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_A (test_unittest_one.Test_test1) -test_A (test_unittest_one.Test_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_B (test_unittest_one.Test_test1) -test_B (test_unittest_one.Test_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_c (test_unittest_one.Test_test1) -test_c (test_unittest_one.Test_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_A2 (test_unittest_two.Test_test2) -test_A2 (test_unittest_two.Test_test2) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_B2 (test_unittest_two.Test_test2) -test_B2 (test_unittest_two.Test_test2) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_C2 (test_unittest_two.Test_test2) -test_C2 (test_unittest_two.Test_test2) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_D2 (test_unittest_two.Test_test2) -test_D2 (test_unittest_two.Test_test2) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_222A2 (test_unittest_two.Test_test2a) -test_222A2 (test_unittest_two.Test_test2a) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_222B2 (test_unittest_two.Test_test2a) -test_222B2 (test_unittest_two.Test_test2a) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_A (unittest_three_test.Test_test3) -test_A (unittest_three_test.Test_test3) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_B (unittest_three_test.Test_test3) -test_B (unittest_three_test.Test_test3) ... ok -nose.suite: DEBUG: precache is [] - ----------------------------------------------------------------------- -Ran 16 tests in 0.061s - -OK diff --git a/src/test/pythonFiles/testFiles/noseFiles/run.four.result b/src/test/pythonFiles/testFiles/noseFiles/run.four.result deleted file mode 100644 index 828e4a74b06a..000000000000 --- a/src/test/pythonFiles/testFiles/noseFiles/run.four.result +++ /dev/null @@ -1,12 +0,0 @@ - diff --git a/src/test/pythonFiles/testFiles/noseFiles/run.one.output b/src/test/pythonFiles/testFiles/noseFiles/run.one.output deleted file mode 100644 index 475ac92d3bb4..000000000000 --- a/src/test/pythonFiles/testFiles/noseFiles/run.one.output +++ /dev/null @@ -1,558 +0,0 @@ -nose.config: INFO: Ignoring files matching ['^\\.', '^_', '^setup\\.py$'] -nose.plugins.manager: DEBUG: Configuring plugins -nose.plugins.manager: DEBUG: Plugins enabled: [, , , , ] -nose.core: DEBUG: configured Config(addPaths=True, args=(), configSection='nosetests', debug=None, debugLog=None, env={}, exclude=None, files=[], firstPackageWins=False, getTestCaseNamesCompat=False, ignoreFiles=[re.compile('^\\.'), re.compile('^_'), re.compile('^setup\\.py$')], ignoreFilesDefaultStrings=['^\\.', '^_', '^setup\\.py$'], include=None, includeExe=False, logStream=<_io.TextIOWrapper name='' mode='w' encoding='UTF-8'>, loggingConfig=None, options=, parser=, parserClass=, plugins=, py3where=(), runOnInit=True, srcDirs=('lib', 'src'), stopOnError=False, stream=<_io.TextIOWrapper name='' mode='w' encoding='UTF-8'>, testMatch=re.compile('test'), testMatchPat='(?:^|[\\b_\\./-])[Tt]est', testNames=[], traverseNamespace=False, verbosity=4, where=(), worker=False, workingDir='/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles') -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.importer: DEBUG: insert /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles into sys.path -nose.plugins.collect: DEBUG: Preparing test loader -nose.core: DEBUG: test loader is -nose.core: DEBUG: defaultTest . -nose.core: DEBUG: Test names are ['.'] -nose.core: DEBUG: createTests called with None -nose.loader: DEBUG: load from . (None) -nose.selector: DEBUG: Test name . resolved to file ., module None, call None -nose.selector: DEBUG: Final resolution of test name .: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles module None call None -nose.plugins.collect: DEBUG: TestSuite([]) -nose.plugins.collect: DEBUG: Add test -nose.core: DEBUG: runTests called -nose.suite: DEBUG: precache is [] -nose.loader: DEBUG: load from dir /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/five.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/four.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/one.output? False -nose.selector: DEBUG: wantDirectory /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/specific? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/three.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/two.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py module test_root call None -nose.importer: DEBUG: Import test_root from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.importer: DEBUG: find module part test_root (test_root) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_Root_A (test_root.Test_Root_test1) -nose.plugins.collect: DEBUG: Add test test_Root_B (test_root.Test_Root_test1) -nose.plugins.collect: DEBUG: Add test test_Root_c (test_root.Test_Root_test1) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test(), Test()]> -nose.plugins.collect: DEBUG: Preparing test case test_Root_A (test_root.Test_Root_test1) -test_Root_A (test_root.Test_Root_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_Root_B (test_root.Test_Root_test1) -test_Root_B (test_root.Test_Root_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_Root_c (test_root.Test_Root_test1) -test_Root_c (test_root.Test_Root_test1) ... ok -nose.selector: DEBUG: wantDirectory /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests? True -nose.plugins.collect: DEBUG: TestSuite() -nose.loader: DEBUG: load from dir /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: insert /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests into sys.path -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py module test4 call None -nose.importer: DEBUG: Import test4 from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: find module part test4 (test4) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test4A (test4.Test_test3) -nose.plugins.collect: DEBUG: Add test test4B (test4.Test_test3) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test()]> -nose.plugins.collect: DEBUG: Add test ), Test()]>]> -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py module test_unittest_one call None -nose.importer: DEBUG: Import test_unittest_one from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: find module part test_unittest_one (test_unittest_one) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_A (test_unittest_one.Test_test1) -nose.plugins.collect: DEBUG: Add test test_B (test_unittest_one.Test_test1) -nose.plugins.collect: DEBUG: Add test test_c (test_unittest_one.Test_test1) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test(), Test()]> -nose.plugins.collect: DEBUG: Add test ), Test(), Test()]>]> -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py module test_unittest_two call None -nose.importer: DEBUG: Import test_unittest_two from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: find module part test_unittest_two (test_unittest_two) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_A2 (test_unittest_two.Test_test2) -nose.plugins.collect: DEBUG: Add test test_B2 (test_unittest_two.Test_test2) -nose.plugins.collect: DEBUG: Add test test_C2 (test_unittest_two.Test_test2) -nose.plugins.collect: DEBUG: Add test test_D2 (test_unittest_two.Test_test2) -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_222A2 (test_unittest_two.Test_test2a) -nose.plugins.collect: DEBUG: Add test test_222B2 (test_unittest_two.Test_test2a) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test(), Test(), Test()]> -nose.plugins.collect: DEBUG: Add test ), Test()]> -nose.plugins.collect: DEBUG: Add test ), Test(), Test(), Test()]>, ), Test()]>]> -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py module unittest_three_test call None -nose.importer: DEBUG: Import unittest_three_test from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: find module part unittest_three_test (unittest_three_test) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_A (unittest_three_test.Test_test3) -nose.plugins.collect: DEBUG: Add test test_B (unittest_three_test.Test_test3) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test()]> -nose.plugins.collect: DEBUG: Add test ), Test()]>]> -nose.importer: DEBUG: Remove path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.plugins.collect: DEBUG: Preparing test case test4A (test4.Test_test3) -test4A (test4.Test_test3) ... ok -nose.plugins.collect: DEBUG: Preparing test case test4B (test4.Test_test3) -test4B (test4.Test_test3) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_A (test_unittest_one.Test_test1) -test_A (test_unittest_one.Test_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_B (test_unittest_one.Test_test1) -test_B (test_unittest_one.Test_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_c (test_unittest_one.Test_test1) -test_c (test_unittest_one.Test_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_A2 (test_unittest_two.Test_test2) -test_A2 (test_unittest_two.Test_test2) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_B2 (test_unittest_two.Test_test2) -test_B2 (test_unittest_two.Test_test2) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_C2 (test_unittest_two.Test_test2) -test_C2 (test_unittest_two.Test_test2) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_D2 (test_unittest_two.Test_test2) -test_D2 (test_unittest_two.Test_test2) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_222A2 (test_unittest_two.Test_test2a) -test_222A2 (test_unittest_two.Test_test2a) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_222B2 (test_unittest_two.Test_test2a) -test_222B2 (test_unittest_two.Test_test2a) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_A (unittest_three_test.Test_test3) -test_A (unittest_three_test.Test_test3) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_B (unittest_three_test.Test_test3) -test_B (unittest_three_test.Test_test3) ... ok -nose.suite: DEBUG: precache is [] - ----------------------------------------------------------------------- -Ran 16 tests in 0.048s - -OK diff --git a/src/test/pythonFiles/testFiles/noseFiles/run.one.result b/src/test/pythonFiles/testFiles/noseFiles/run.one.result deleted file mode 100644 index 59de2cfcdcc8..000000000000 --- a/src/test/pythonFiles/testFiles/noseFiles/run.one.result +++ /dev/null @@ -1,83 +0,0 @@ - diff --git a/src/test/pythonFiles/testFiles/noseFiles/run.three.output b/src/test/pythonFiles/testFiles/noseFiles/run.three.output deleted file mode 100644 index da1ec6bc25c9..000000000000 --- a/src/test/pythonFiles/testFiles/noseFiles/run.three.output +++ /dev/null @@ -1,563 +0,0 @@ -nose.config: INFO: Ignoring files matching ['^\\.', '^_', '^setup\\.py$'] -nose.plugins.manager: DEBUG: Configuring plugins -nose.plugins.manager: DEBUG: Plugins enabled: [, , , , ] -nose.core: DEBUG: configured Config(addPaths=True, args=(), configSection='nosetests', debug=None, debugLog=None, env={}, exclude=None, files=[], firstPackageWins=False, getTestCaseNamesCompat=False, ignoreFiles=[re.compile('^\\.'), re.compile('^_'), re.compile('^setup\\.py$')], ignoreFilesDefaultStrings=['^\\.', '^_', '^setup\\.py$'], include=None, includeExe=False, logStream=<_io.TextIOWrapper name='' mode='w' encoding='UTF-8'>, loggingConfig=None, options=, parser=, parserClass=, plugins=, py3where=(), runOnInit=True, srcDirs=('lib', 'src'), stopOnError=False, stream=<_io.TextIOWrapper name='' mode='w' encoding='UTF-8'>, testMatch=re.compile('test'), testMatchPat='(?:^|[\\b_\\./-])[Tt]est', testNames=[], traverseNamespace=False, verbosity=4, where=(), worker=False, workingDir='/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles') -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.importer: DEBUG: insert /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles into sys.path -nose.plugins.collect: DEBUG: Preparing test loader -nose.core: DEBUG: test loader is -nose.core: DEBUG: defaultTest . -nose.core: DEBUG: Test names are ['.'] -nose.core: DEBUG: createTests called with None -nose.loader: DEBUG: load from . (None) -nose.selector: DEBUG: Test name . resolved to file ., module None, call None -nose.selector: DEBUG: Final resolution of test name .: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles module None call None -nose.plugins.collect: DEBUG: TestSuite([]) -nose.plugins.collect: DEBUG: Add test -nose.core: DEBUG: runTests called -nose.suite: DEBUG: precache is [] -nose.loader: DEBUG: load from dir /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/five.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/four.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/one.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/run.one.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/run.one.result? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/run.two.again.result? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/run.two.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/run.two.result? False -nose.selector: DEBUG: wantDirectory /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/specific? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/three.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/two.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py module test_root call None -nose.importer: DEBUG: Import test_root from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.importer: DEBUG: find module part test_root (test_root) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_Root_A (test_root.Test_Root_test1) -nose.plugins.collect: DEBUG: Add test test_Root_B (test_root.Test_Root_test1) -nose.plugins.collect: DEBUG: Add test test_Root_c (test_root.Test_Root_test1) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test(), Test()]> -nose.plugins.collect: DEBUG: Preparing test case test_Root_A (test_root.Test_Root_test1) -test_Root_A (test_root.Test_Root_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_Root_B (test_root.Test_Root_test1) -test_Root_B (test_root.Test_Root_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_Root_c (test_root.Test_Root_test1) -test_Root_c (test_root.Test_Root_test1) ... ok -nose.selector: DEBUG: wantDirectory /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests? True -nose.plugins.collect: DEBUG: TestSuite() -nose.loader: DEBUG: load from dir /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: insert /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests into sys.path -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py module test4 call None -nose.importer: DEBUG: Import test4 from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: find module part test4 (test4) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test4A (test4.Test_test3) -nose.plugins.collect: DEBUG: Add test test4B (test4.Test_test3) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test()]> -nose.plugins.collect: DEBUG: Add test ), Test()]>]> -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py module test_unittest_one call None -nose.importer: DEBUG: Import test_unittest_one from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: find module part test_unittest_one (test_unittest_one) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_A (test_unittest_one.Test_test1) -nose.plugins.collect: DEBUG: Add test test_B (test_unittest_one.Test_test1) -nose.plugins.collect: DEBUG: Add test test_c (test_unittest_one.Test_test1) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test(), Test()]> -nose.plugins.collect: DEBUG: Add test ), Test(), Test()]>]> -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py module test_unittest_two call None -nose.importer: DEBUG: Import test_unittest_two from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: find module part test_unittest_two (test_unittest_two) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_A2 (test_unittest_two.Test_test2) -nose.plugins.collect: DEBUG: Add test test_B2 (test_unittest_two.Test_test2) -nose.plugins.collect: DEBUG: Add test test_C2 (test_unittest_two.Test_test2) -nose.plugins.collect: DEBUG: Add test test_D2 (test_unittest_two.Test_test2) -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_222A2 (test_unittest_two.Test_test2a) -nose.plugins.collect: DEBUG: Add test test_222B2 (test_unittest_two.Test_test2a) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test(), Test(), Test()]> -nose.plugins.collect: DEBUG: Add test ), Test()]> -nose.plugins.collect: DEBUG: Add test ), Test(), Test(), Test()]>, ), Test()]>]> -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py module unittest_three_test call None -nose.importer: DEBUG: Import unittest_three_test from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: find module part unittest_three_test (unittest_three_test) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_A (unittest_three_test.Test_test3) -nose.plugins.collect: DEBUG: Add test test_B (unittest_three_test.Test_test3) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test()]> -nose.plugins.collect: DEBUG: Add test ), Test()]>]> -nose.importer: DEBUG: Remove path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.plugins.collect: DEBUG: Preparing test case test4A (test4.Test_test3) -test4A (test4.Test_test3) ... ok -nose.plugins.collect: DEBUG: Preparing test case test4B (test4.Test_test3) -test4B (test4.Test_test3) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_A (test_unittest_one.Test_test1) -test_A (test_unittest_one.Test_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_B (test_unittest_one.Test_test1) -test_B (test_unittest_one.Test_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_c (test_unittest_one.Test_test1) -test_c (test_unittest_one.Test_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_A2 (test_unittest_two.Test_test2) -test_A2 (test_unittest_two.Test_test2) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_B2 (test_unittest_two.Test_test2) -test_B2 (test_unittest_two.Test_test2) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_C2 (test_unittest_two.Test_test2) -test_C2 (test_unittest_two.Test_test2) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_D2 (test_unittest_two.Test_test2) -test_D2 (test_unittest_two.Test_test2) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_222A2 (test_unittest_two.Test_test2a) -test_222A2 (test_unittest_two.Test_test2a) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_222B2 (test_unittest_two.Test_test2a) -test_222B2 (test_unittest_two.Test_test2a) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_A (unittest_three_test.Test_test3) -test_A (unittest_three_test.Test_test3) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_B (unittest_three_test.Test_test3) -test_B (unittest_three_test.Test_test3) ... ok -nose.suite: DEBUG: precache is [] - ----------------------------------------------------------------------- -Ran 16 tests in 0.047s - -OK diff --git a/src/test/pythonFiles/testFiles/noseFiles/run.three.result b/src/test/pythonFiles/testFiles/noseFiles/run.three.result deleted file mode 100644 index 828e4a74b06a..000000000000 --- a/src/test/pythonFiles/testFiles/noseFiles/run.three.result +++ /dev/null @@ -1,12 +0,0 @@ - diff --git a/src/test/pythonFiles/testFiles/noseFiles/run.two.again.result b/src/test/pythonFiles/testFiles/noseFiles/run.two.again.result deleted file mode 100644 index b60e8229c55d..000000000000 --- a/src/test/pythonFiles/testFiles/noseFiles/run.two.again.result +++ /dev/null @@ -1,81 +0,0 @@ - diff --git a/src/test/pythonFiles/testFiles/noseFiles/run.two.output b/src/test/pythonFiles/testFiles/noseFiles/run.two.output deleted file mode 100644 index 31a5a5e9c34b..000000000000 --- a/src/test/pythonFiles/testFiles/noseFiles/run.two.output +++ /dev/null @@ -1,560 +0,0 @@ -nose.config: INFO: Ignoring files matching ['^\\.', '^_', '^setup\\.py$'] -nose.plugins.manager: DEBUG: Configuring plugins -nose.plugins.manager: DEBUG: Plugins enabled: [, , , , ] -nose.core: DEBUG: configured Config(addPaths=True, args=(), configSection='nosetests', debug=None, debugLog=None, env={}, exclude=None, files=[], firstPackageWins=False, getTestCaseNamesCompat=False, ignoreFiles=[re.compile('^\\.'), re.compile('^_'), re.compile('^setup\\.py$')], ignoreFilesDefaultStrings=['^\\.', '^_', '^setup\\.py$'], include=None, includeExe=False, logStream=<_io.TextIOWrapper name='' mode='w' encoding='UTF-8'>, loggingConfig=None, options=, parser=, parserClass=, plugins=, py3where=(), runOnInit=True, srcDirs=('lib', 'src'), stopOnError=False, stream=<_io.TextIOWrapper name='' mode='w' encoding='UTF-8'>, testMatch=re.compile('test'), testMatchPat='(?:^|[\\b_\\./-])[Tt]est', testNames=[], traverseNamespace=False, verbosity=4, where=(), worker=False, workingDir='/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles') -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.importer: DEBUG: insert /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles into sys.path -nose.plugins.collect: DEBUG: Preparing test loader -nose.core: DEBUG: test loader is -nose.core: DEBUG: defaultTest . -nose.core: DEBUG: Test names are ['.'] -nose.core: DEBUG: createTests called with None -nose.loader: DEBUG: load from . (None) -nose.selector: DEBUG: Test name . resolved to file ., module None, call None -nose.selector: DEBUG: Final resolution of test name .: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles module None call None -nose.plugins.collect: DEBUG: TestSuite([]) -nose.plugins.collect: DEBUG: Add test -nose.core: DEBUG: runTests called -nose.suite: DEBUG: precache is [] -nose.loader: DEBUG: load from dir /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/five.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/four.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/one.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/run.one.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/run.one.result? False -nose.selector: DEBUG: wantDirectory /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/specific? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/three.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/two.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py module test_root call None -nose.importer: DEBUG: Import test_root from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.importer: DEBUG: find module part test_root (test_root) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_Root_A (test_root.Test_Root_test1) -nose.plugins.collect: DEBUG: Add test test_Root_B (test_root.Test_Root_test1) -nose.plugins.collect: DEBUG: Add test test_Root_c (test_root.Test_Root_test1) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test(), Test()]> -nose.plugins.collect: DEBUG: Preparing test case test_Root_A (test_root.Test_Root_test1) -test_Root_A (test_root.Test_Root_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_Root_B (test_root.Test_Root_test1) -test_Root_B (test_root.Test_Root_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_Root_c (test_root.Test_Root_test1) -test_Root_c (test_root.Test_Root_test1) ... ok -nose.selector: DEBUG: wantDirectory /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests? True -nose.plugins.collect: DEBUG: TestSuite() -nose.loader: DEBUG: load from dir /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: insert /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests into sys.path -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py module test4 call None -nose.importer: DEBUG: Import test4 from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: find module part test4 (test4) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test4A (test4.Test_test3) -nose.plugins.collect: DEBUG: Add test test4B (test4.Test_test3) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test()]> -nose.plugins.collect: DEBUG: Add test ), Test()]>]> -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py module test_unittest_one call None -nose.importer: DEBUG: Import test_unittest_one from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: find module part test_unittest_one (test_unittest_one) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_A (test_unittest_one.Test_test1) -nose.plugins.collect: DEBUG: Add test test_B (test_unittest_one.Test_test1) -nose.plugins.collect: DEBUG: Add test test_c (test_unittest_one.Test_test1) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test(), Test()]> -nose.plugins.collect: DEBUG: Add test ), Test(), Test()]>]> -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py module test_unittest_two call None -nose.importer: DEBUG: Import test_unittest_two from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: find module part test_unittest_two (test_unittest_two) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_A2 (test_unittest_two.Test_test2) -nose.plugins.collect: DEBUG: Add test test_B2 (test_unittest_two.Test_test2) -nose.plugins.collect: DEBUG: Add test test_C2 (test_unittest_two.Test_test2) -nose.plugins.collect: DEBUG: Add test test_D2 (test_unittest_two.Test_test2) -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_222A2 (test_unittest_two.Test_test2a) -nose.plugins.collect: DEBUG: Add test test_222B2 (test_unittest_two.Test_test2a) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test(), Test(), Test()]> -nose.plugins.collect: DEBUG: Add test ), Test()]> -nose.plugins.collect: DEBUG: Add test ), Test(), Test(), Test()]>, ), Test()]>]> -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py module unittest_three_test call None -nose.importer: DEBUG: Import unittest_three_test from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: find module part unittest_three_test (unittest_three_test) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_A (unittest_three_test.Test_test3) -nose.plugins.collect: DEBUG: Add test test_B (unittest_three_test.Test_test3) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test()]> -nose.plugins.collect: DEBUG: Add test ), Test()]>]> -nose.importer: DEBUG: Remove path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.plugins.collect: DEBUG: Preparing test case test4A (test4.Test_test3) -test4A (test4.Test_test3) ... ok -nose.plugins.collect: DEBUG: Preparing test case test4B (test4.Test_test3) -test4B (test4.Test_test3) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_A (test_unittest_one.Test_test1) -test_A (test_unittest_one.Test_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_B (test_unittest_one.Test_test1) -test_B (test_unittest_one.Test_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_c (test_unittest_one.Test_test1) -test_c (test_unittest_one.Test_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_A2 (test_unittest_two.Test_test2) -test_A2 (test_unittest_two.Test_test2) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_B2 (test_unittest_two.Test_test2) -test_B2 (test_unittest_two.Test_test2) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_C2 (test_unittest_two.Test_test2) -test_C2 (test_unittest_two.Test_test2) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_D2 (test_unittest_two.Test_test2) -test_D2 (test_unittest_two.Test_test2) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_222A2 (test_unittest_two.Test_test2a) -test_222A2 (test_unittest_two.Test_test2a) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_222B2 (test_unittest_two.Test_test2a) -test_222B2 (test_unittest_two.Test_test2a) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_A (unittest_three_test.Test_test3) -test_A (unittest_three_test.Test_test3) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_B (unittest_three_test.Test_test3) -test_B (unittest_three_test.Test_test3) ... ok -nose.suite: DEBUG: precache is [] - ----------------------------------------------------------------------- -Ran 16 tests in 0.137s - -OK diff --git a/src/test/pythonFiles/testFiles/noseFiles/run.two.result b/src/test/pythonFiles/testFiles/noseFiles/run.two.result deleted file mode 100644 index 59de2cfcdcc8..000000000000 --- a/src/test/pythonFiles/testFiles/noseFiles/run.two.result +++ /dev/null @@ -1,83 +0,0 @@ - diff --git a/src/test/pythonFiles/testFiles/noseFiles/specific/tst_unittest_one.py b/src/test/pythonFiles/testFiles/noseFiles/specific/tst_unittest_one.py deleted file mode 100644 index 4825f3a4db3b..000000000000 --- a/src/test/pythonFiles/testFiles/noseFiles/specific/tst_unittest_one.py +++ /dev/null @@ -1,15 +0,0 @@ -import sys -import os - -import unittest - -class Test_test1(unittest.TestCase): - def tst_A(self): - self.fail("Not implemented") - - def tst_B(self): - self.assertEqual(1, 1, 'Not equal') - - -if __name__ == '__main__': - unittest.main() diff --git a/src/test/pythonFiles/testFiles/noseFiles/specific/tst_unittest_two.py b/src/test/pythonFiles/testFiles/noseFiles/specific/tst_unittest_two.py deleted file mode 100644 index c9a76c07f933..000000000000 --- a/src/test/pythonFiles/testFiles/noseFiles/specific/tst_unittest_two.py +++ /dev/null @@ -1,18 +0,0 @@ -import unittest - -class Tst_test2(unittest.TestCase): - def tst_A2(self): - self.fail("Not implemented") - - def tst_B2(self): - self.assertEqual(1,1,'Not equal') - - def tst_C2(self): - self.assertEqual(1,2,'Not equal') - - def tst_D2(self): - raise ArithmeticError() - pass - -if __name__ == '__main__': - unittest.main() diff --git a/src/test/pythonFiles/testFiles/noseFiles/test_root.py b/src/test/pythonFiles/testFiles/noseFiles/test_root.py deleted file mode 100644 index 452813e9a079..000000000000 --- a/src/test/pythonFiles/testFiles/noseFiles/test_root.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import unittest - -class Test_Root_test1(unittest.TestCase): - def test_Root_A(self): - self.fail("Not implemented") - - def test_Root_B(self): - self.assertEqual(1, 1, 'Not equal') - - @unittest.skip("demonstrating skipping") - def test_Root_c(self): - self.assertEqual(1, 1, 'Not equal') - - -if __name__ == '__main__': - unittest.main() diff --git a/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py b/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py deleted file mode 100644 index 734b84cd342e..000000000000 --- a/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py +++ /dev/null @@ -1,13 +0,0 @@ -import unittest - - -class Test_test3(unittest.TestCase): - def test4A(self): - self.fail("Not implemented") - - def test4B(self): - self.assertEqual(1, 1, 'Not equal') - - -if __name__ == '__main__': - unittest.main() diff --git a/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py b/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py deleted file mode 100644 index e869986b6ead..000000000000 --- a/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -import os - -import unittest - -class Test_test1(unittest.TestCase): - def test_A(self): - self.fail("Not implemented") - - def test_B(self): - self.assertEqual(1, 1, 'Not equal') - - @unittest.skip("demonstrating skipping") - def test_c(self): - self.assertEqual(1, 1, 'Not equal') - - -if __name__ == '__main__': - unittest.main() diff --git a/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py b/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py deleted file mode 100644 index ad89d873e879..000000000000 --- a/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py +++ /dev/null @@ -1,32 +0,0 @@ -import unittest - -class Test_test2(unittest.TestCase): - def test_A2(self): - self.fail("Not implemented") - - def test_B2(self): - self.assertEqual(1,1,'Not equal') - - def test_C2(self): - self.assertEqual(1,2,'Not equal') - - def test_D2(self): - raise ArithmeticError() - pass - -class Test_test2a(unittest.TestCase): - def test_222A2(self): - self.fail("Not implemented") - - def test_222B2(self): - self.assertEqual(1,1,'Not equal') - - class Test_test2a1(unittest.TestCase): - def test_222A2wow(self): - self.fail("Not implemented") - - def test_222B2wow(self): - self.assertEqual(1,1,'Not equal') - -if __name__ == '__main__': - unittest.main() diff --git a/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py b/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py deleted file mode 100644 index 507e6af02063..000000000000 --- a/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py +++ /dev/null @@ -1,13 +0,0 @@ -import unittest - - -class Test_test3(unittest.TestCase): - def test_A(self): - self.fail("Not implemented") - - def test_B(self): - self.assertEqual(1, 1, 'Not equal') - - -if __name__ == '__main__': - unittest.main() diff --git a/src/test/pythonFiles/testFiles/noseFiles/three.output b/src/test/pythonFiles/testFiles/noseFiles/three.output deleted file mode 100644 index a57dae74d180..000000000000 --- a/src/test/pythonFiles/testFiles/noseFiles/three.output +++ /dev/null @@ -1,555 +0,0 @@ -nose.config: INFO: Ignoring files matching ['^\\.', '^_', '^setup\\.py$'] -nose.plugins.manager: DEBUG: Configuring plugins -nose.plugins.manager: DEBUG: Plugins enabled: [, , , , ] -nose.core: DEBUG: configured Config(addPaths=True, args=(), configSection='nosetests', debug=None, debugLog=None, env={}, exclude=None, files=[], firstPackageWins=False, getTestCaseNamesCompat=False, ignoreFiles=[re.compile('^\\.'), re.compile('^_'), re.compile('^setup\\.py$')], ignoreFilesDefaultStrings=['^\\.', '^_', '^setup\\.py$'], include=None, includeExe=False, logStream=<_io.TextIOWrapper name='' mode='w' encoding='UTF-8'>, loggingConfig=None, options=, parser=, parserClass=, plugins=, py3where=(), runOnInit=True, srcDirs=('lib', 'src'), stopOnError=False, stream=<_io.TextIOWrapper name='' mode='w' encoding='UTF-8'>, testMatch=re.compile('test'), testMatchPat='(?:^|[\\b_\\./-])[Tt]est', testNames=[], traverseNamespace=False, verbosity=4, where=(), worker=False, workingDir='/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles') -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.importer: DEBUG: insert /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles into sys.path -nose.plugins.collect: DEBUG: Preparing test loader -nose.core: DEBUG: test loader is -nose.core: DEBUG: defaultTest . -nose.core: DEBUG: Test names are ['.'] -nose.core: DEBUG: createTests called with None -nose.loader: DEBUG: load from . (None) -nose.selector: DEBUG: Test name . resolved to file ., module None, call None -nose.selector: DEBUG: Final resolution of test name .: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles module None call None -nose.plugins.collect: DEBUG: TestSuite([]) -nose.plugins.collect: DEBUG: Add test -nose.core: DEBUG: runTests called -nose.suite: DEBUG: precache is [] -nose.loader: DEBUG: load from dir /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/one.output? False -nose.selector: DEBUG: wantDirectory /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/specific? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/two.output? False -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/test_root.py module test_root call None -nose.importer: DEBUG: Import test_root from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles -nose.importer: DEBUG: find module part test_root (test_root) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_Root_A (test_root.Test_Root_test1) -nose.plugins.collect: DEBUG: Add test test_Root_B (test_root.Test_Root_test1) -nose.plugins.collect: DEBUG: Add test test_Root_c (test_root.Test_Root_test1) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test(), Test()]> -nose.plugins.collect: DEBUG: Preparing test case test_Root_A (test_root.Test_Root_test1) -test_Root_A (test_root.Test_Root_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_Root_B (test_root.Test_Root_test1) -test_Root_B (test_root.Test_Root_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_Root_c (test_root.Test_Root_test1) -test_Root_c (test_root.Test_Root_test1) ... ok -nose.selector: DEBUG: wantDirectory /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests? True -nose.plugins.collect: DEBUG: TestSuite() -nose.loader: DEBUG: load from dir /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: insert /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests into sys.path -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test4.py module test4 call None -nose.importer: DEBUG: Import test4 from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: find module part test4 (test4) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test4A (test4.Test_test3) -nose.plugins.collect: DEBUG: Add test test4B (test4.Test_test3) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test()]> -nose.plugins.collect: DEBUG: Add test ), Test()]>]> -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_one.py module test_unittest_one call None -nose.importer: DEBUG: Import test_unittest_one from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: find module part test_unittest_one (test_unittest_one) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_A (test_unittest_one.Test_test1) -nose.plugins.collect: DEBUG: Add test test_B (test_unittest_one.Test_test1) -nose.plugins.collect: DEBUG: Add test test_c (test_unittest_one.Test_test1) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test(), Test()]> -nose.plugins.collect: DEBUG: Add test ), Test(), Test()]>]> -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/test_unittest_two.py module test_unittest_two call None -nose.importer: DEBUG: Import test_unittest_two from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: find module part test_unittest_two (test_unittest_two) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_A2 (test_unittest_two.Test_test2) -nose.plugins.collect: DEBUG: Add test test_B2 (test_unittest_two.Test_test2) -nose.plugins.collect: DEBUG: Add test test_C2 (test_unittest_two.Test_test2) -nose.plugins.collect: DEBUG: Add test test_D2 (test_unittest_two.Test_test2) -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_222A2 (test_unittest_two.Test_test2a) -nose.plugins.collect: DEBUG: Add test test_222B2 (test_unittest_two.Test_test2a) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test(), Test(), Test()]> -nose.plugins.collect: DEBUG: Add test ), Test()]> -nose.plugins.collect: DEBUG: Add test ), Test(), Test(), Test()]>, ), Test()]>]> -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests/unittest_three_test.py module unittest_three_test call None -nose.importer: DEBUG: Import unittest_three_test from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.importer: DEBUG: find module part unittest_three_test (unittest_three_test) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_A (unittest_three_test.Test_test3) -nose.plugins.collect: DEBUG: Add test test_B (unittest_three_test.Test_test3) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test()]> -nose.plugins.collect: DEBUG: Add test ), Test()]>]> -nose.importer: DEBUG: Remove path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/noseFiles/tests -nose.plugins.collect: DEBUG: Preparing test case test4A (test4.Test_test3) -test4A (test4.Test_test3) ... ok -nose.plugins.collect: DEBUG: Preparing test case test4B (test4.Test_test3) -test4B (test4.Test_test3) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_A (test_unittest_one.Test_test1) -test_A (test_unittest_one.Test_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_B (test_unittest_one.Test_test1) -test_B (test_unittest_one.Test_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_c (test_unittest_one.Test_test1) -test_c (test_unittest_one.Test_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_A2 (test_unittest_two.Test_test2) -test_A2 (test_unittest_two.Test_test2) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_B2 (test_unittest_two.Test_test2) -test_B2 (test_unittest_two.Test_test2) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_C2 (test_unittest_two.Test_test2) -test_C2 (test_unittest_two.Test_test2) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_D2 (test_unittest_two.Test_test2) -test_D2 (test_unittest_two.Test_test2) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_222A2 (test_unittest_two.Test_test2a) -test_222A2 (test_unittest_two.Test_test2a) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_222B2 (test_unittest_two.Test_test2a) -test_222B2 (test_unittest_two.Test_test2a) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_A (unittest_three_test.Test_test3) -test_A (unittest_three_test.Test_test3) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_B (unittest_three_test.Test_test3) -test_B (unittest_three_test.Test_test3) ... ok -nose.suite: DEBUG: precache is [] - ----------------------------------------------------------------------- -Ran 16 tests in 0.052s - -OK diff --git a/src/test/pythonFiles/testFiles/noseFiles/two.output b/src/test/pythonFiles/testFiles/noseFiles/two.output deleted file mode 100644 index 25fcf10c93d5..000000000000 --- a/src/test/pythonFiles/testFiles/noseFiles/two.output +++ /dev/null @@ -1,211 +0,0 @@ -nose.config: INFO: Ignoring files matching ['^\\.', '^_', '^setup\\.py$'] -nose.plugins.manager: DEBUG: Configuring plugins -nose.plugins.manager: DEBUG: Plugins enabled: [, , , , ] -nose.core: DEBUG: configured Config(addPaths=True, args=(), configSection='nosetests', debug=None, debugLog=None, env={}, exclude=None, files=[], firstPackageWins=False, getTestCaseNamesCompat=False, ignoreFiles=[re.compile('^\\.'), re.compile('^_'), re.compile('^setup\\.py$')], ignoreFilesDefaultStrings=['^\\.', '^_', '^setup\\.py$'], include=None, includeExe=False, logStream=<_io.TextIOWrapper name='' mode='w' encoding='UTF-8'>, loggingConfig=None, options=, parser=, parserClass=, plugins=, py3where=(), runOnInit=True, srcDirs=('lib', 'src'), stopOnError=False, stream=<_io.TextIOWrapper name='' mode='w' encoding='UTF-8'>, testMatch=re.compile('(?:^|[\\b_\\./-])[Tt]est'), testMatchPat='(?:^|[\\b_\\./-])[Tt]est', testNames=[], traverseNamespace=False, verbosity=4, where=(), worker=False, workingDir='/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single') -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single -nose.importer: DEBUG: insert /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single into sys.path -nose.plugins.collect: DEBUG: Preparing test loader -nose.core: DEBUG: test loader is -nose.core: DEBUG: defaultTest . -nose.core: DEBUG: Test names are ['.'] -nose.core: DEBUG: createTests called with None -nose.loader: DEBUG: load from . (None) -nose.selector: DEBUG: Test name . resolved to file ., module None, call None -nose.selector: DEBUG: Final resolution of test name .: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single module None call None -nose.plugins.collect: DEBUG: TestSuite([]) -nose.plugins.collect: DEBUG: Add test -nose.core: DEBUG: runTests called -nose.suite: DEBUG: precache is [] -nose.loader: DEBUG: load from dir /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/test_root.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/test_root.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/test_root.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/test_root.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/test_root.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/test_root.py module test_root call None -nose.importer: DEBUG: Import test_root from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single -nose.importer: DEBUG: find module part test_root (test_root) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_Root_A (test_root.Test_Root_test1) -nose.plugins.collect: DEBUG: Add test test_Root_B (test_root.Test_Root_test1) -nose.plugins.collect: DEBUG: Add test test_Root_c (test_root.Test_Root_test1) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test(), Test()]> -nose.plugins.collect: DEBUG: Preparing test case test_Root_A (test_root.Test_Root_test1) -test_Root_A (test_root.Test_Root_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_Root_B (test_root.Test_Root_test1) -test_Root_B (test_root.Test_Root_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_Root_c (test_root.Test_Root_test1) -test_Root_c (test_root.Test_Root_test1) ... ok -nose.selector: DEBUG: wantDirectory /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/tests? True -nose.plugins.collect: DEBUG: TestSuite() -nose.loader: DEBUG: load from dir /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/tests -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/tests -nose.importer: DEBUG: insert /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/tests into sys.path -nose.selector: DEBUG: wantFile /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/tests/test_one.py? True -nose.loader: DEBUG: load from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/tests/test_one.py (None) -nose.selector: DEBUG: Test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/tests/test_one.py resolved to file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/tests/test_one.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/tests/test_one.py: file /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/tests/test_one.py module test_one call None -nose.importer: DEBUG: Import test_one from /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/tests -nose.importer: DEBUG: Add path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/tests -nose.importer: DEBUG: find module part test_one (test_one) in ['/Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/tests'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test test_A (test_one.Test_test1) -nose.plugins.collect: DEBUG: Add test test_B (test_one.Test_test1) -nose.plugins.collect: DEBUG: Add test test_c (test_one.Test_test1) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test ), Test(), Test()]> -nose.plugins.collect: DEBUG: Add test ), Test(), Test()]>]> -nose.importer: DEBUG: Remove path /Users/donjayamanne/.vscode/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single/tests -nose.plugins.collect: DEBUG: Preparing test case test_A (test_one.Test_test1) -test_A (test_one.Test_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_B (test_one.Test_test1) -test_B (test_one.Test_test1) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_c (test_one.Test_test1) -test_c (test_one.Test_test1) ... ok -nose.suite: DEBUG: precache is [] - ----------------------------------------------------------------------- -Ran 6 tests in 0.188s - -OK diff --git a/src/test/testing/argsService.test.ts b/src/test/testing/argsService.test.ts index eb72747e43c8..4bcfa3b24538 100644 --- a/src/test/testing/argsService.test.ts +++ b/src/test/testing/argsService.test.ts @@ -13,7 +13,6 @@ import { IServiceContainer } from '../../client/ioc/types'; import { ArgumentsHelper } from '../../client/testing/common/argumentsHelper'; import { UNIT_TEST_PRODUCTS } from '../../client/testing/common/constants'; import { IArgumentsHelper, IArgumentsService } from '../../client/testing/common/types'; -import { ArgumentsService as NoseTestArgumentsService } from '../../client/testing/nosetest/services/argsService'; import { ArgumentsService as PyTestArgumentsService } from '../../client/testing/pytest/services/argsService'; import { ArgumentsService as UnitTestArgumentsService } from '../../client/testing/unittest/services/argsService'; import { PYTHON_PATH } from '../common'; @@ -47,11 +46,6 @@ suite('ArgsService: Common', () => { moduleName = 'unittest'; break; } - case Product.nosetest: { - argumentsService = new NoseTestArgumentsService(serviceContainer.object); - moduleName = 'nose'; - break; - } case Product.pytest: { moduleName = 'pytest'; argumentsService = new PyTestArgumentsService(serviceContainer.object); diff --git a/src/test/testing/common/debugLauncher.unit.test.ts b/src/test/testing/common/debugLauncher.unit.test.ts index 5d77f4f291c3..378bf2265572 100644 --- a/src/test/testing/common/debugLauncher.unit.test.ts +++ b/src/test/testing/common/debugLauncher.unit.test.ts @@ -145,8 +145,7 @@ suite('Unit Tests - Debug Launcher', () => { case 'unittest': { return path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'visualstudio_py_testlauncher.py'); } - case 'pytest': - case 'nosetest': { + case 'pytest': { return path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'testlauncher.py'); } default: { @@ -245,7 +244,7 @@ suite('Unit Tests - Debug Launcher', () => { setupDebugManager(workspaceFolders[0], expected, testProvider); } - const testProviders: TestProvider[] = ['nosetest', 'pytest', 'unittest']; + const testProviders: TestProvider[] = ['pytest', 'unittest']; testProviders.forEach((testProvider) => { const testTitleSuffix = `(Test Framework '${testProvider}')`; diff --git a/src/test/testing/common/managers/baseTestManager.unit.test.ts b/src/test/testing/common/managers/baseTestManager.unit.test.ts index 4072a1c85022..91e2897649a5 100644 --- a/src/test/testing/common/managers/baseTestManager.unit.test.ts +++ b/src/test/testing/common/managers/baseTestManager.unit.test.ts @@ -42,7 +42,6 @@ import { TestDiscoveryOptions, } from '../../../../client/testing/common/types'; import { TEST_OUTPUT_CHANNEL } from '../../../../client/testing/constants'; -import { TestManager as NoseTestManager } from '../../../../client/testing/nosetest/main'; import { TestManager as PyTestTestManager } from '../../../../client/testing/pytest/main'; import { ArgumentsService } from '../../../../client/testing/pytest/services/argsService'; import { TestDiscoveryService } from '../../../../client/testing/pytest/services/discoveryService'; @@ -56,7 +55,6 @@ const IGNORED_OPTIONS = ({} as unknown) as TestDiscoveryOptions; suite('Unit Tests - Base Test Manager', () => { [ - { name: 'nose', class: NoseTestManager }, { name: 'pytest', class: PyTestTestManager }, { name: 'unittest', class: UnitTestTestManager }, ].forEach((item) => { diff --git a/src/test/testing/common/services/configSettingService.unit.test.ts b/src/test/testing/common/services/configSettingService.unit.test.ts index 0269d668a275..bc5dce03235d 100644 --- a/src/test/testing/common/services/configSettingService.unit.test.ts +++ b/src/test/testing/common/services/configSettingService.unit.test.ts @@ -50,8 +50,6 @@ suite('Unit Tests - ConfigSettingsService', () => { return 'testing.unittestArgs'; case Product.pytest: return 'testing.pytestArgs'; - case Product.nosetest: - return 'testing.nosetestArgs'; default: throw new Error('Invalid Test Product'); } @@ -62,8 +60,6 @@ suite('Unit Tests - ConfigSettingsService', () => { return 'testing.unittestEnabled'; case Product.pytest: return 'testing.pytestEnabled'; - case Product.nosetest: - return 'testing.nosetestsEnabled'; default: throw new Error('Invalid Test Product'); } @@ -241,9 +237,6 @@ suite('Unit Tests - BufferedTestConfigSettingsService', () => { cfg.setup((c) => c.disable(typeMoq.It.isValue(testDir), typeMoq.It.isValue(Product.unittest))) .returns(() => Promise.resolve()) .verifiable(typeMoq.Times.once()); - cfg.setup((c) => c.disable(typeMoq.It.isValue(testDir), typeMoq.It.isValue(Product.nosetest))) - .returns(() => Promise.resolve()) - .verifiable(typeMoq.Times.once()); cfg.setup((c) => c.enable(typeMoq.It.isValue(testDir), typeMoq.It.isValue(Product.pytest))) .returns(() => Promise.resolve()) .verifiable(typeMoq.Times.once()); @@ -251,7 +244,6 @@ suite('Unit Tests - BufferedTestConfigSettingsService', () => { const delayed = new BufferedTestConfigSettingsService(); await delayed.updateTestArgs(testDir, Product.pytest, newArgs); await delayed.disable(testDir, Product.unittest); - await delayed.disable(testDir, Product.nosetest); await delayed.enable(testDir, Product.pytest); await delayed.apply(cfg.object); diff --git a/src/test/testing/common/trackEnablement.unit.test.ts b/src/test/testing/common/trackEnablement.unit.test.ts index c2324cbe5ca3..d1b7c647103f 100644 --- a/src/test/testing/common/trackEnablement.unit.test.ts +++ b/src/test/testing/common/trackEnablement.unit.test.ts @@ -68,12 +68,8 @@ suite('Unit Tests - Track Enablement', () => { assert.ok(telemetryReporter.notCalled); assert.ok(affectsConfiguration.callCount > 0); }); - test('Check whether unittest, pytest and nose settings have been enabled', async () => { - const expectedSettingsChecked = [ - 'python.testing.nosetestEnabled', - 'python.testing.unittestEnabled', - 'python.testing.pytestEnabled', - ]; + test('Check whether unittest, pytest settings have been enabled', async () => { + const expectedSettingsChecked = ['python.testing.unittestEnabled', 'python.testing.pytestEnabled']; const telemetryReporter = sandbox.stub(EnablementTracker.prototype, 'sendTelemetry'); telemetryReporter.callsFake(noop); @@ -81,7 +77,6 @@ suite('Unit Tests - Track Enablement', () => { when(workspaceService.workspaceFolders).thenReturn([]); when(configService.getTestEnablingSetting(Product.unittest)).thenReturn('testing.unittestEnabled'); when(configService.getTestEnablingSetting(Product.pytest)).thenReturn('testing.pytestEnabled'); - when(configService.getTestEnablingSetting(Product.nosetest)).thenReturn('testing.nosetestEnabled'); enablementTracker = createEnablementTracker(); enablementTracker.onDidChangeConfiguration({ affectsConfiguration }); @@ -89,24 +84,12 @@ suite('Unit Tests - Track Enablement', () => { verify(workspaceService.getConfiguration(anything(), anything())).never(); assert.ok(telemetryReporter.notCalled); assert.ok(affectsConfiguration.callCount > 0); - const settingsChecked = [ - affectsConfiguration.args[0][0], - affectsConfiguration.args[1][0], - affectsConfiguration.args[2][0], - ]; + const settingsChecked = [affectsConfiguration.args[0][0], affectsConfiguration.args[1][0]]; assert.deepEqual(settingsChecked.sort(), expectedSettingsChecked.sort()); }); test('Check settings related to unittest, pytest and nose', async () => { - const expectedSettingsChecked = [ - 'python.testing.nosetestEnabled', - 'python.testing.unittestEnabled', - 'python.testing.pytestEnabled', - ]; - const expectedSettingsRetrieved = [ - 'testing.nosetestEnabled', - 'testing.unittestEnabled', - 'testing.pytestEnabled', - ]; + const expectedSettingsChecked = ['python.testing.unittestEnabled', 'python.testing.pytestEnabled']; + const expectedSettingsRetrieved = ['testing.unittestEnabled', 'testing.pytestEnabled']; const telemetryReporter = sandbox.stub(EnablementTracker.prototype, 'sendTelemetry'); telemetryReporter.callsFake(noop); @@ -118,39 +101,22 @@ suite('Unit Tests - Track Enablement', () => { when(workspaceService.getConfiguration('python', anything())).thenReturn({ get: getConfigSettings } as any); when(configService.getTestEnablingSetting(Product.unittest)).thenReturn('testing.unittestEnabled'); when(configService.getTestEnablingSetting(Product.pytest)).thenReturn('testing.pytestEnabled'); - when(configService.getTestEnablingSetting(Product.nosetest)).thenReturn('testing.nosetestEnabled'); enablementTracker = createEnablementTracker(); enablementTracker.onDidChangeConfiguration({ affectsConfiguration }); - verify(workspaceService.getConfiguration(anything(), anything())).atLeast(3); + verify(workspaceService.getConfiguration(anything(), anything())).atLeast(2); assert.ok(telemetryReporter.notCalled); assert.ok(affectsConfiguration.callCount > 0); - const settingsChecked = [ - affectsConfiguration.args[0][0], - affectsConfiguration.args[1][0], - affectsConfiguration.args[2][0], - ]; + const settingsChecked = [affectsConfiguration.args[0][0], affectsConfiguration.args[1][0]]; assert.deepEqual(settingsChecked.sort(), expectedSettingsChecked.sort()); - const settingsRetrieved = [ - getConfigSettings.args[0][0], - getConfigSettings.args[1][0], - getConfigSettings.args[2][0], - ]; + const settingsRetrieved = [getConfigSettings.args[0][0], getConfigSettings.args[1][0]]; assert.deepEqual(settingsRetrieved.sort(), expectedSettingsRetrieved.sort()); }); function testSendingTelemetry(sendForProvider: TestProvider) { - const expectedSettingsChecked = [ - 'python.testing.nosetestEnabled', - 'python.testing.unittestEnabled', - 'python.testing.pytestEnabled', - ]; - const expectedSettingsRetrieved = [ - 'testing.nosetestEnabled', - 'testing.unittestEnabled', - 'testing.pytestEnabled', - ]; + const expectedSettingsChecked = ['python.testing.unittestEnabled', 'python.testing.pytestEnabled']; + const expectedSettingsRetrieved = ['testing.unittestEnabled', 'testing.pytestEnabled']; const telemetryReporter = sandbox.stub(EnablementTracker.prototype, 'sendTelemetry'); telemetryReporter.callsFake(noop); @@ -164,30 +130,20 @@ suite('Unit Tests - Track Enablement', () => { when(workspaceService.getConfiguration('python', anything())).thenReturn({ get: getConfigSettings } as any); when(configService.getTestEnablingSetting(Product.unittest)).thenReturn('testing.unittestEnabled'); when(configService.getTestEnablingSetting(Product.pytest)).thenReturn('testing.pytestEnabled'); - when(configService.getTestEnablingSetting(Product.nosetest)).thenReturn('testing.nosetestEnabled'); enablementTracker = createEnablementTracker(); enablementTracker.onDidChangeConfiguration({ affectsConfiguration }); - verify(workspaceService.getConfiguration(anything(), anything())).atLeast(3); + verify(workspaceService.getConfiguration(anything(), anything())).atLeast(2); assert.equal(telemetryReporter.callCount, 1); assert.deepEqual(telemetryReporter.args[0][0], { [sendForProvider]: true }); assert.ok(affectsConfiguration.callCount > 0); - const settingsChecked = [ - affectsConfiguration.args[0][0], - affectsConfiguration.args[1][0], - affectsConfiguration.args[2][0], - ]; + const settingsChecked = [affectsConfiguration.args[0][0], affectsConfiguration.args[1][0]]; assert.deepEqual(settingsChecked.sort(), expectedSettingsChecked.sort()); - const settingsRetrieved = [ - getConfigSettings.args[0][0], - getConfigSettings.args[1][0], - getConfigSettings.args[2][0], - ]; + const settingsRetrieved = [getConfigSettings.args[0][0], getConfigSettings.args[1][0]]; assert.deepEqual(settingsRetrieved.sort(), expectedSettingsRetrieved.sort()); } test('Send telemetry for unittest', () => testSendingTelemetry('unittest')); test('Send telemetry for pytest', () => testSendingTelemetry('pytest')); - test('Send telemetry for nosetest', () => testSendingTelemetry('nosetest')); }); diff --git a/src/test/testing/common/xUnitParser.unit.test.ts b/src/test/testing/common/xUnitParser.unit.test.ts index 21f2fcd379c0..de93424fb55b 100644 --- a/src/test/testing/common/xUnitParser.unit.test.ts +++ b/src/test/testing/common/xUnitParser.unit.test.ts @@ -139,7 +139,6 @@ suite('Testing - parse JUnit XML file', () => { // Missing tests (see https://github.com/microsoft/vscode-python/issues/7447): // * simple pytest - // * simple nose // * complex // * error // * failure diff --git a/src/test/testing/configuration.unit.test.ts b/src/test/testing/configuration.unit.test.ts index 864834e15eff..58f9a5b452ac 100644 --- a/src/test/testing/configuration.unit.test.ts +++ b/src/test/testing/configuration.unit.test.ts @@ -215,11 +215,11 @@ suite('Unit Tests - ConfigurationService', () => { workspaceService.verifyAll(); workspaceConfig.verifyAll(); }); - test('Select Test runner displays 3 items', async () => { + test('Select Test runner displays 2 items', async () => { const placeHolder = 'Some message'; appShell .setup((s) => s.showQuickPick(typeMoq.It.isAny(), typeMoq.It.isObjectWith({ placeHolder }))) - .callback((items) => expect(items).be.lengthOf(3)) + .callback((items) => expect(items).be.lengthOf(2)) .verifiable(typeMoq.Times.once()); await testConfigService.target.selectTestRunner(placeHolder); @@ -227,10 +227,10 @@ suite('Unit Tests - ConfigurationService', () => { }); test('Ensure selected item is returned', async () => { const placeHolder = 'Some message'; - const indexes = [Product.unittest, Product.pytest, Product.nosetest]; + const indexes = [Product.unittest, Product.pytest]; appShell .setup((s) => s.showQuickPick(typeMoq.It.isAny(), typeMoq.It.isObjectWith({ placeHolder }))) - .callback((items) => expect(items).be.lengthOf(3)) + .callback((items) => expect(items).be.lengthOf(2)) .returns((items) => items[indexes.indexOf(product)]) .verifiable(typeMoq.Times.once()); @@ -252,7 +252,6 @@ suite('Unit Tests - ConfigurationService', () => { test('Prompt to enable a test if a test framework is not enabled', async () => { unitTestSettings.setup((u) => u.pytestEnabled).returns(() => false); unitTestSettings.setup((u) => u.unittestEnabled).returns(() => false); - unitTestSettings.setup((u) => u.nosetestsEnabled).returns(() => false); appShell .setup((s) => s.showInformationMessage(typeMoq.It.isAny(), typeMoq.It.isAny())) @@ -275,7 +274,6 @@ suite('Unit Tests - ConfigurationService', () => { test('Prompt to select a test if a test framework is not enabled', async () => { unitTestSettings.setup((u) => u.pytestEnabled).returns(() => false); unitTestSettings.setup((u) => u.unittestEnabled).returns(() => false); - unitTestSettings.setup((u) => u.nosetestsEnabled).returns(() => false); appShell .setup((s) => s.showInformationMessage(typeMoq.It.isAny(), typeMoq.It.isAny())) @@ -307,7 +305,6 @@ suite('Unit Tests - ConfigurationService', () => { test('Configure selected test framework and disable others', async () => { unitTestSettings.setup((u) => u.pytestEnabled).returns(() => false); unitTestSettings.setup((u) => u.unittestEnabled).returns(() => false); - unitTestSettings.setup((u) => u.nosetestsEnabled).returns(() => false); const workspaceConfig = typeMoq.Mock.ofType( undefined, @@ -367,7 +364,6 @@ suite('Unit Tests - ConfigurationService', () => { test('If more than one test framework is enabled, then prompt to select a test framework', async () => { unitTestSettings.setup((u) => u.pytestEnabled).returns(() => true); unitTestSettings.setup((u) => u.unittestEnabled).returns(() => true); - unitTestSettings.setup((u) => u.nosetestsEnabled).returns(() => true); appShell .setup((s) => s.showInformationMessage(typeMoq.It.isAny(), typeMoq.It.isAny())) @@ -394,7 +390,6 @@ suite('Unit Tests - ConfigurationService', () => { test('If more than one test framework is enabled, then prompt to select a test framework and enable test, but do not configure', async () => { unitTestSettings.setup((u) => u.pytestEnabled).returns(() => true); unitTestSettings.setup((u) => u.unittestEnabled).returns(() => true); - unitTestSettings.setup((u) => u.nosetestsEnabled).returns(() => true); appShell .setup((s) => s.showInformationMessage(typeMoq.It.isAny(), typeMoq.It.isAny())) @@ -450,7 +445,6 @@ suite('Unit Tests - ConfigurationService', () => { test('Prompt to enable and configure selected test framework', async () => { unitTestSettings.setup((u) => u.pytestEnabled).returns(() => false); unitTestSettings.setup((u) => u.unittestEnabled).returns(() => false); - unitTestSettings.setup((u) => u.nosetestsEnabled).returns(() => false); const workspaceConfig = typeMoq.Mock.ofType( undefined, diff --git a/src/test/testing/configurationFactory.unit.test.ts b/src/test/testing/configurationFactory.unit.test.ts index 04251048f399..3d0c157d141b 100644 --- a/src/test/testing/configurationFactory.unit.test.ts +++ b/src/test/testing/configurationFactory.unit.test.ts @@ -12,7 +12,6 @@ import { IServiceContainer } from '../../client/ioc/types'; import { ITestConfigSettingsService, ITestConfigurationManagerFactory } from '../../client/testing/common/types'; import { TestConfigurationManagerFactory } from '../../client/testing/configurationFactory'; import { TEST_OUTPUT_CHANNEL } from '../../client/testing/constants'; -import * as nose from '../../client/testing/nosetest/testConfigurationManager'; import * as pytest from '../../client/testing/pytest/testConfigurationManager'; import * as unittest from '../../client/testing/unittest/testConfigurationManager'; @@ -43,8 +42,4 @@ suite('Unit Tests - ConfigurationManagerFactory', () => { const configMgr = factory.create(Uri.file(__filename), Product.pytest); expect(configMgr).to.be.instanceOf(pytest.ConfigurationManager); }); - test('Create nose Configuration', async () => { - const configMgr = factory.create(Uri.file(__filename), Product.nosetest); - expect(configMgr).to.be.instanceOf(nose.ConfigurationManager); - }); }); diff --git a/src/test/testing/debugger.test.ts b/src/test/testing/debugger.test.ts index 5959427bdf8d..52be16c6060c 100644 --- a/src/test/testing/debugger.test.ts +++ b/src/test/testing/debugger.test.ts @@ -8,16 +8,10 @@ import { createDeferred } from '../../client/common/utils/async'; import { ICondaService, IInterpreterService } from '../../client/interpreter/contracts'; import { InterpreterService } from '../../client/interpreter/interpreterService'; import { CondaService } from '../../client/pythonEnvironments/discovery/locators/services/condaService'; -import { TestManagerRunner as NoseTestManagerRunner } from '../../client/testing//nosetest/runner'; import { TestManagerRunner as PytestManagerRunner } from '../../client/testing//pytest/runner'; import { TestManagerRunner as UnitTestTestManagerRunner } from '../../client/testing//unittest/runner'; import { ArgumentsHelper } from '../../client/testing/common/argumentsHelper'; -import { - CANCELLATION_REASON, - NOSETEST_PROVIDER, - PYTEST_PROVIDER, - UNITTEST_PROVIDER, -} from '../../client/testing/common/constants'; +import { CANCELLATION_REASON, PYTEST_PROVIDER, UNITTEST_PROVIDER } from '../../client/testing/common/constants'; import { TestRunner } from '../../client/testing/common/runner'; import { IArgumentsHelper, @@ -31,7 +25,6 @@ import { IXUnitParser, } from '../../client/testing/common/types'; import { XUnitParser } from '../../client/testing/common/xUnitParser'; -import { ArgumentsService as NoseTestArgumentsService } from '../../client/testing/nosetest/services/argsService'; import { ArgumentsService as PyTestArgumentsService } from '../../client/testing/pytest/services/argsService'; import { TestMessageService } from '../../client/testing/pytest/services/testMessageService'; import { TestProvider } from '../../client/testing/types'; @@ -56,7 +49,6 @@ suite('Unit Tests - debugging', () => { await initialize(); await Promise.all([ updateSetting('testing.unittestArgs', defaultUnitTestArgs, rootWorkspaceUri, configTarget), - updateSetting('testing.nosetestArgs', [], rootWorkspaceUri, configTarget), updateSetting('testing.pytestArgs', [], rootWorkspaceUri, configTarget), ]); }); @@ -73,7 +65,6 @@ suite('Unit Tests - debugging', () => { await ioc.dispose(); await Promise.all([ updateSetting('testing.unittestArgs', defaultUnitTestArgs, rootWorkspaceUri, configTarget), - updateSetting('testing.nosetestArgs', [], rootWorkspaceUri, configTarget), updateSetting('testing.pytestArgs', [], rootWorkspaceUri, configTarget), ]); }); @@ -99,11 +90,9 @@ suite('Unit Tests - debugging', () => { ioc.serviceManager.add(ITestRunner, TestRunner); ioc.serviceManager.add(IXUnitParser, XUnitParser); ioc.serviceManager.add(IUnitTestHelper, UnitTestHelper); - ioc.serviceManager.add(IArgumentsService, NoseTestArgumentsService, NOSETEST_PROVIDER); ioc.serviceManager.add(IArgumentsService, PyTestArgumentsService, PYTEST_PROVIDER); ioc.serviceManager.add(IArgumentsService, UnitTestArgumentsService, UNITTEST_PROVIDER); ioc.serviceManager.add(ITestManagerRunner, PytestManagerRunner, PYTEST_PROVIDER); - ioc.serviceManager.add(ITestManagerRunner, NoseTestManagerRunner, NOSETEST_PROVIDER); ioc.serviceManager.add(ITestManagerRunner, UnitTestTestManagerRunner, UNITTEST_PROVIDER); ioc.serviceManager.addSingleton(ITestDebugLauncher, MockDebugLauncher); ioc.serviceManager.addSingleton(ITestMessageService, TestMessageService, PYTEST_PROVIDER); @@ -155,11 +144,6 @@ suite('Unit Tests - debugging', () => { await testStartingDebugger('pytest'); }); - test('Debugger should start (nosetest)', async () => { - await updateSetting('testing.nosetestArgs', ['-m', 'test'], rootWorkspaceUri, configTarget); - await testStartingDebugger('nosetest'); - }); - async function testStoppingDebugger(testProvider: TestProvider) { const testManager = ioc.serviceContainer.get(ITestManagerFactory)( testProvider, @@ -199,11 +183,6 @@ suite('Unit Tests - debugging', () => { await testStoppingDebugger('pytest'); }); - test('Debugger should stop when user invokes a test discovery (nosetest)', async () => { - await updateSetting('testing.nosetestArgs', ['-m', 'test'], rootWorkspaceUri, configTarget); - await testStoppingDebugger('nosetest'); - }); - async function testDebuggerWhenRediscoveringTests(testProvider: TestProvider) { const testManager = ioc.serviceContainer.get(ITestManagerFactory)( testProvider, @@ -252,9 +231,4 @@ suite('Unit Tests - debugging', () => { await updateSetting('testing.pytestArgs', ['-k=test_'], rootWorkspaceUri, configTarget); await testDebuggerWhenRediscoveringTests('pytest'); }); - - test('Debugger should not stop when test discovery is invoked automatically by extension (nosetest)', async () => { - await updateSetting('testing.nosetestArgs', ['-m', 'test'], rootWorkspaceUri, configTarget); - await testDebuggerWhenRediscoveringTests('nosetest'); - }); }); diff --git a/src/test/testing/display/main.unit.test.ts b/src/test/testing/display/main.unit.test.ts index d7e563b1465f..b9bc80dc0640 100644 --- a/src/test/testing/display/main.unit.test.ts +++ b/src/test/testing/display/main.unit.test.ts @@ -384,12 +384,7 @@ suite('Unit Tests - TestResultDisplay', () => { .returns(() => Promise.resolve(Testing.disableTests())) .verifiable(typeMoq.Times.once()); - for (const setting of [ - 'testing.promptToConfigure', - 'testing.pytestEnabled', - 'testing.unittestEnabled', - 'testing.nosetestsEnabled', - ]) { + for (const setting of ['testing.promptToConfigure', 'testing.pytestEnabled', 'testing.unittestEnabled']) { configurationService .setup((c) => c.updateSetting(typeMoq.It.isValue(setting), typeMoq.It.isValue(false))) .returns(() => Promise.resolve()) diff --git a/src/test/testing/nosetest/nose_discovery_output.txt b/src/test/testing/nosetest/nose_discovery_output.txt deleted file mode 100644 index 8d2612d9d4e8..000000000000 --- a/src/test/testing/nosetest/nose_discovery_output.txt +++ /dev/null @@ -1,561 +0,0 @@ -nose.config: INFO: Set working dir to /home/user/dev/tests -nose.config: INFO: Ignoring files matching ['^\\.', '^_', '^setup\\.py$'] -nose.plugins.manager: DEBUG: Configuring plugins -nose.plugins.manager: DEBUG: Plugins enabled: [, , , , ] -nose.core: DEBUG: configured Config(addPaths=True, args=(), configSection='nosetests', debug=None, debugLog=None, env={}, exclude=None, files=[], firstPackageWins=False, getTestCaseNamesCompat=False, ignoreFiles=[<_sre.SRE_Pattern object at 0x0000000002FBB830>, <_sre.SRE_Pattern object at 0x0000000002FBB9B0>, <_sre.SRE_Pattern object at 0x00000000029761B0>], ignoreFilesDefaultStrings=['^\\.', '^_', '^setup\\.py$'], include=None, includeExe=True, logStream=', mode 'w' at 0x000000000296F1E0>, loggingConfig=None, options=, parser=, parserClass=, plugins=, py3where=(), runOnInit=True, srcDirs=('lib', 'src'), stopOnError=False, stream=', mode 'w' at 0x000000000296F1E0>, testMatch=<_sre.SRE_Pattern object at 0x00000000039D0430>, testMatchPat='(?:^|[\\b_\\.\\-])[Tt]est', testNames=[], traverseNamespace=False, verbosity=4, where=(), worker=False, workingDir='/home/user/dev/tests') -nose.importer: DEBUG: Add path /home/user/dev/tests -nose.importer: DEBUG: insert /home/user/dev/tests into sys.path -nose.plugins.collect: DEBUG: Preparing test loader -nose.core: DEBUG: test loader is -nose.core: DEBUG: defaultTest . -nose.core: DEBUG: Test names are ['.'] -nose.core: DEBUG: createTests called with None -nose.loader: DEBUG: load from . (None) -nose.selector: DEBUG: Test name . resolved to file ., module None, call None -nose.selector: DEBUG: Final resolution of test name .: file /home/user/dev/tests module None call None -nose.plugins.collect: DEBUG: TestSuite([]) -nose.plugins.collect: DEBUG: Add test -nose.core: DEBUG: runTests called -nose.suite: DEBUG: precache is [] -nose.loader: DEBUG: load from dir /home/user/dev/tests -nose.importer: DEBUG: Add path /home/user/dev/tests -nose.selector: DEBUG: wantDirectory /home/user/dev/tests/apptests? True -nose.loader: DEBUG: load from /home/user/dev/tests/apptests (None) -nose.selector: DEBUG: Test name /home/user/dev/tests/apptests resolved to file /home/user/dev/tests/apptests, module None, call None -nose.selector: DEBUG: Final resolution of test name /home/user/dev/tests/apptests: file /home/user/dev/tests/apptests module apptests call None -nose.importer: DEBUG: Import apptests from /home/user/dev/tests -nose.importer: DEBUG: Add path /home/user/dev/tests -nose.importer: DEBUG: find module part apptests (apptests) in ['/home/user/dev/tests'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? False -nose.loader: DEBUG: Load tests from module path /home/user/dev/tests/apptests? -nose.loader: DEBUG: path: /home/user/dev/tests/apptests os.path.realpath(/home/user/dev/tests/apptests): /home/user/dev/tests/apptests -nose.loader: DEBUG: load from dir /home/user/dev/tests/apptests -nose.importer: DEBUG: Add path /home/user/dev/tests/apptests -nose.importer: DEBUG: Add path /home/user/dev/tests -nose.selector: DEBUG: __init__.py matches ignoreFiles pattern; skipped -nose.selector: DEBUG: __init__.pyc matches ignoreFiles pattern; skipped -nose.selector: DEBUG: wantDirectory /home/user/dev/tests/apptests/debug? True -nose.loader: DEBUG: load from /home/user/dev/tests/apptests/debug (None) -nose.selector: DEBUG: Test name /home/user/dev/tests/apptests/debug resolved to file /home/user/dev/tests/apptests/debug, module None, call None -nose.selector: DEBUG: Final resolution of test name /home/user/dev/tests/apptests/debug: file /home/user/dev/tests/apptests/debug module apptests.debug call None -nose.importer: DEBUG: Import apptests.debug from /home/user/dev/tests -nose.importer: DEBUG: Add path /home/user/dev/tests -nose.importer: DEBUG: find module part apptests (apptests) in ['/home/user/dev/tests'] -nose.importer: DEBUG: sys.modules has apptests as -nose.importer: DEBUG: module already loaded? mod: /home/user/dev/tests/apptests new: /home/user/dev/tests/apptests -nose.importer: DEBUG: find module part debug (apptests.debug) in ['/home/user/dev/tests/apptests'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? False -nose.loader: DEBUG: Load tests from module path /home/user/dev/tests/apptests/debug? -nose.loader: DEBUG: path: /home/user/dev/tests/apptests/debug os.path.realpath(/home/user/dev/tests/apptests/debug): /home/user/dev/tests/apptests/debug -nose.loader: DEBUG: load from dir /home/user/dev/tests/apptests/debug -nose.importer: DEBUG: Add path /home/user/dev/tests/apptests/debug -nose.importer: DEBUG: Add path /home/user/dev/tests/apptests -nose.importer: DEBUG: Add path /home/user/dev/tests -nose.selector: DEBUG: __init__.py matches ignoreFiles pattern; skipped -nose.selector: DEBUG: __init__.pyc matches ignoreFiles pattern; skipped -nose.selector: DEBUG: wantDirectory /home/user/dev/tests/apptests/debug/first? True -nose.loader: DEBUG: load from /home/user/dev/tests/apptests/debug/first (None) -nose.selector: DEBUG: Test name /home/user/dev/tests/apptests/debug/first resolved to file /home/user/dev/tests/apptests/debug/first, module None, call None -nose.selector: DEBUG: Final resolution of test name /home/user/dev/tests/apptests/debug/first: file /home/user/dev/tests/apptests/debug/first module apptests.debug.first call None -nose.importer: DEBUG: Import apptests.debug.first from /home/user/dev/tests -nose.importer: DEBUG: Add path /home/user/dev/tests -nose.importer: DEBUG: find module part apptests (apptests) in ['/home/user/dev/tests'] -nose.importer: DEBUG: sys.modules has apptests as -nose.importer: DEBUG: module already loaded? mod: /home/user/dev/tests/apptests new: /home/user/dev/tests/apptests -nose.importer: DEBUG: find module part debug (apptests.debug) in ['/home/user/dev/tests/apptests'] -nose.importer: DEBUG: sys.modules has apptests.debug as -nose.importer: DEBUG: module already loaded? mod: /home/user/dev/tests/apptests/debug new: /home/user/dev/tests/apptests/debug -nose.importer: DEBUG: find module part first (apptests.debug.first) in ['/home/user/dev/tests/apptests/debug'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? False -nose.loader: DEBUG: Load tests from module path /home/user/dev/tests/apptests/debug/first? -nose.loader: DEBUG: path: /home/user/dev/tests/apptests/debug/first os.path.realpath(/home/user/dev/tests/apptests/debug/first): /home/user/dev/tests/apptests/debug/first -nose.loader: DEBUG: load from dir /home/user/dev/tests/apptests/debug/first -nose.importer: DEBUG: Add path /home/user/dev/tests/apptests/debug/first -nose.importer: DEBUG: Add path /home/user/dev/tests/apptests/debug -nose.importer: DEBUG: Add path /home/user/dev/tests/apptests -nose.importer: DEBUG: Add path /home/user/dev/tests -nose.selector: DEBUG: __init__.py matches ignoreFiles pattern; skipped -nose.selector: DEBUG: __init__.pyc matches ignoreFiles pattern; skipped -nose.selector: DEBUG: wantFile /home/user/dev/tests/apptests/debug/first/test_module_name.py? True -nose.loader: DEBUG: load from /home/user/dev/tests/apptests/debug/first/test_module_name.py (None) -nose.selector: DEBUG: Test name /home/user/dev/tests/apptests/debug/first/test_module_name.py resolved to file /home/user/dev/tests/apptests/debug/first/test_module_name.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /home/user/dev/tests/apptests/debug/first/test_module_name.py: file /home/user/dev/tests/apptests/debug/first/test_module_name.py module apptests.debug.first.test_module_name call None -nose.importer: DEBUG: Import apptests.debug.first.test_module_name from /home/user/dev/tests -nose.importer: DEBUG: Add path /home/user/dev/tests -nose.importer: DEBUG: find module part apptests (apptests) in ['/home/user/dev/tests'] -nose.importer: DEBUG: sys.modules has apptests as -nose.importer: DEBUG: module already loaded? mod: /home/user/dev/tests/apptests new: /home/user/dev/tests/apptests -nose.importer: DEBUG: find module part debug (apptests.debug) in ['/home/user/dev/tests/apptests'] -nose.importer: DEBUG: sys.modules has apptests.debug as -nose.importer: DEBUG: module already loaded? mod: /home/user/dev/tests/apptests/debug new: /home/user/dev/tests/apptests/debug -nose.importer: DEBUG: find module part first (apptests.debug.first) in ['/home/user/dev/tests/apptests/debug'] -nose.importer: DEBUG: sys.modules has apptests.debug.first as -nose.importer: DEBUG: module already loaded? mod: /home/user/dev/tests/apptests/debug/first new: /home/user/dev/tests/apptests/debug/first -nose.importer: DEBUG: find module part test_module_name (apptests.debug.first.test_module_name) in ['/home/user/dev/tests/apptests/debug/first'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.plugins.collect: DEBUG: TestSuite([]) -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite([, ]) -nose.plugins.collect: DEBUG: Add test test_first (apptests.debug.first.test_module_name.TestFirstLevelClassName) -nose.plugins.collect: DEBUG: Add test test_first_other (apptests.debug.first.test_module_name.TestFirstLevelClassName) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test -nose.plugins.collect: DEBUG: Add test ), Test()]> -nose.selector: DEBUG: wantFile /home/user/dev/tests/apptests/debug/first/test_module_name.pyc? False -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test , ), Test()]>]> -nose.selector: DEBUG: wantDirectory /home/user/dev/tests/apptests/debug/second? True -nose.loader: DEBUG: load from /home/user/dev/tests/apptests/debug/second (None) -nose.selector: DEBUG: Test name /home/user/dev/tests/apptests/debug/second resolved to file /home/user/dev/tests/apptests/debug/second, module None, call None -nose.selector: DEBUG: Final resolution of test name /home/user/dev/tests/apptests/debug/second: file /home/user/dev/tests/apptests/debug/second module apptests.debug.second call None -nose.importer: DEBUG: Import apptests.debug.second from /home/user/dev/tests -nose.importer: DEBUG: Add path /home/user/dev/tests -nose.importer: DEBUG: find module part apptests (apptests) in ['/home/user/dev/tests'] -nose.importer: DEBUG: sys.modules has apptests as -nose.importer: DEBUG: module already loaded? mod: /home/user/dev/tests/apptests new: /home/user/dev/tests/apptests -nose.importer: DEBUG: find module part debug (apptests.debug) in ['/home/user/dev/tests/apptests'] -nose.importer: DEBUG: sys.modules has apptests.debug as -nose.importer: DEBUG: module already loaded? mod: /home/user/dev/tests/apptests/debug new: /home/user/dev/tests/apptests/debug -nose.importer: DEBUG: find module part second (apptests.debug.second) in ['/home/user/dev/tests/apptests/debug'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? False -nose.loader: DEBUG: Load tests from module path /home/user/dev/tests/apptests/debug/second? -nose.loader: DEBUG: path: /home/user/dev/tests/apptests/debug/second os.path.realpath(/home/user/dev/tests/apptests/debug/second): /home/user/dev/tests/apptests/debug/second -nose.loader: DEBUG: load from dir /home/user/dev/tests/apptests/debug/second -nose.importer: DEBUG: Add path /home/user/dev/tests/apptests/debug/second -nose.importer: DEBUG: Add path /home/user/dev/tests/apptests/debug -nose.importer: DEBUG: Add path /home/user/dev/tests/apptests -nose.importer: DEBUG: Add path /home/user/dev/tests -nose.selector: DEBUG: __init__.py matches ignoreFiles pattern; skipped -nose.selector: DEBUG: __init__.pyc matches ignoreFiles pattern; skipped -nose.selector: DEBUG: wantFile /home/user/dev/tests/apptests/debug/second/test_module_name.py? True -nose.loader: DEBUG: load from /home/user/dev/tests/apptests/debug/second/test_module_name.py (None) -nose.selector: DEBUG: Test name /home/user/dev/tests/apptests/debug/second/test_module_name.py resolved to file /home/user/dev/tests/apptests/debug/second/test_module_name.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /home/user/dev/tests/apptests/debug/second/test_module_name.py: file /home/user/dev/tests/apptests/debug/second/test_module_name.py module apptests.debug.second.test_module_name call None -nose.importer: DEBUG: Import apptests.debug.second.test_module_name from /home/user/dev/tests -nose.importer: DEBUG: Add path /home/user/dev/tests -nose.importer: DEBUG: find module part apptests (apptests) in ['/home/user/dev/tests'] -nose.importer: DEBUG: sys.modules has apptests as -nose.importer: DEBUG: module already loaded? mod: /home/user/dev/tests/apptests new: /home/user/dev/tests/apptests -nose.importer: DEBUG: find module part debug (apptests.debug) in ['/home/user/dev/tests/apptests'] -nose.importer: DEBUG: sys.modules has apptests.debug as -nose.importer: DEBUG: module already loaded? mod: /home/user/dev/tests/apptests/debug new: /home/user/dev/tests/apptests/debug -nose.importer: DEBUG: find module part second (apptests.debug.second) in ['/home/user/dev/tests/apptests/debug'] -nose.importer: DEBUG: sys.modules has apptests.debug.second as -nose.importer: DEBUG: module already loaded? mod: /home/user/dev/tests/apptests/debug/second new: /home/user/dev/tests/apptests/debug/second -nose.importer: DEBUG: find module part test_module_name (apptests.debug.second.test_module_name) in ['/home/user/dev/tests/apptests/debug/second'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.plugins.collect: DEBUG: TestSuite([]) -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite([, ]) -nose.plugins.collect: DEBUG: Add test test_second (apptests.debug.second.test_module_name.TestSecondLevelClassName) -nose.plugins.collect: DEBUG: Add test test_second_other (apptests.debug.second.test_module_name.TestSecondLevelClassName) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test -nose.plugins.collect: DEBUG: Add test ), Test()]> -nose.selector: DEBUG: wantFile /home/user/dev/tests/apptests/debug/second/test_module_name.pyc? False -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test , ), Test()]>]> -nose.selector: DEBUG: wantFile /home/user/dev/tests/apptests/debug/test_module_name.py? True -nose.loader: DEBUG: load from /home/user/dev/tests/apptests/debug/test_module_name.py (None) -nose.selector: DEBUG: Test name /home/user/dev/tests/apptests/debug/test_module_name.py resolved to file /home/user/dev/tests/apptests/debug/test_module_name.py, module None, call None -nose.selector: DEBUG: Final resolution of test name /home/user/dev/tests/apptests/debug/test_module_name.py: file /home/user/dev/tests/apptests/debug/test_module_name.py module apptests.debug.test_module_name call None -nose.importer: DEBUG: Import apptests.debug.test_module_name from /home/user/dev/tests -nose.importer: DEBUG: Add path /home/user/dev/tests -nose.importer: DEBUG: find module part apptests (apptests) in ['/home/user/dev/tests'] -nose.importer: DEBUG: sys.modules has apptests as -nose.importer: DEBUG: module already loaded? mod: /home/user/dev/tests/apptests new: /home/user/dev/tests/apptests -nose.importer: DEBUG: find module part debug (apptests.debug) in ['/home/user/dev/tests/apptests'] -nose.importer: DEBUG: sys.modules has apptests.debug as -nose.importer: DEBUG: module already loaded? mod: /home/user/dev/tests/apptests/debug new: /home/user/dev/tests/apptests/debug -nose.importer: DEBUG: find module part test_module_name (apptests.debug.test_module_name) in ['/home/user/dev/tests/apptests/debug'] -nose.loader: DEBUG: Load from module -nose.selector: DEBUG: wantModule ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantClass ? True -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.plugins.collect: DEBUG: TestSuite([]) -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod ? None -nose.selector: DEBUG: wantMethod >? None -nose.selector: DEBUG: wantMethod ? True -nose.selector: DEBUG: wantMethod ? True -nose.plugins.collect: DEBUG: TestSuite([, ]) -nose.plugins.collect: DEBUG: Add test test_root (apptests.debug.test_module_name.TestRootClassName) -nose.plugins.collect: DEBUG: Add test test_root_other (apptests.debug.test_module_name.TestRootClassName) -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test -nose.plugins.collect: DEBUG: Add test ), Test()]> -nose.selector: DEBUG: wantFile /home/user/dev/tests/apptests/debug/test_module_name.pyc? False -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test , ), Test()]>]>]> -nose.plugins.collect: DEBUG: Add test , ), Test()]>]>]> -nose.plugins.collect: DEBUG: Add test , ), Test()]>]> -nose.plugins.collect: DEBUG: TestSuite() -nose.plugins.collect: DEBUG: Add test , ), Test()]>]>]>, , ), Test()]>]>]>, , ), Test()]>]>]> -nose.plugins.collect: DEBUG: Preparing test case test_first (apptests.debug.first.test_module_name.TestFirstLevelClassName) -test_first (apptests.debug.first.test_module_name.TestFirstLevelClassName) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_first_other (apptests.debug.first.test_module_name.TestFirstLevelClassName) -test_first_other (apptests.debug.first.test_module_name.TestFirstLevelClassName) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_second (apptests.debug.second.test_module_name.TestSecondLevelClassName) -test_second (apptests.debug.second.test_module_name.TestSecondLevelClassName) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_second_other (apptests.debug.second.test_module_name.TestSecondLevelClassName) -test_second_other (apptests.debug.second.test_module_name.TestSecondLevelClassName) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_root (apptests.debug.test_module_name.TestRootClassName) -test_root (apptests.debug.test_module_name.TestRootClassName) ... ok -nose.plugins.collect: DEBUG: Preparing test case test_root_other (apptests.debug.test_module_name.TestRootClassName) -test_root_other (apptests.debug.test_module_name.TestRootClassName) ... ok - ----------------------------------------------------------------------- -Ran 6 tests in 0.490s - -OK diff --git a/src/test/testing/nosetest/nosetest.argsService.unit.test.ts b/src/test/testing/nosetest/nosetest.argsService.unit.test.ts deleted file mode 100644 index 2a7d78eb7218..000000000000 --- a/src/test/testing/nosetest/nosetest.argsService.unit.test.ts +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { expect } from 'chai'; -import * as path from 'path'; -import * as typeMoq from 'typemoq'; -import { IServiceContainer } from '../../../client/ioc/types'; -import { ArgumentsHelper } from '../../../client/testing/common/argumentsHelper'; -import { IArgumentsHelper } from '../../../client/testing/common/types'; -import { ArgumentsService as NoseTestArgumentsService } from '../../../client/testing/nosetest/services/argsService'; - -suite('ArgsService: nosetest', () => { - let argumentsService: NoseTestArgumentsService; - - suiteSetup(() => { - const serviceContainer = typeMoq.Mock.ofType(); - - const argsHelper = new ArgumentsHelper(); - - serviceContainer - .setup((s) => s.get(typeMoq.It.isValue(IArgumentsHelper), typeMoq.It.isAny())) - .returns(() => argsHelper); - - argumentsService = new NoseTestArgumentsService(serviceContainer.object); - }); - - test('Test getting the test folder in nosetest', () => { - const dir = path.join('a', 'b', 'c'); - const args = ['--one', '--three', dir]; - const testDirs = argumentsService.getTestFolders(args); - expect(testDirs).to.be.lengthOf(1); - expect(testDirs[0]).to.equal(dir); - }); - test('Test getting the test folder in nosetest (with multiple dirs)', () => { - const dir = path.join('a', 'b', 'c'); - const dir2 = path.join('a', 'b', '2'); - const args = ['anzy', '--one', '--three', dir, dir2]; - const testDirs = argumentsService.getTestFolders(args); - expect(testDirs).to.be.lengthOf(3); - expect(testDirs[0]).to.equal('anzy'); - expect(testDirs[1]).to.equal(dir); - expect(testDirs[2]).to.equal(dir2); - }); -}); diff --git a/src/test/testing/nosetest/nosetest.discovery.test.ts b/src/test/testing/nosetest/nosetest.discovery.test.ts deleted file mode 100644 index c612ca39b101..000000000000 --- a/src/test/testing/nosetest/nosetest.discovery.test.ts +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -import * as assert from 'assert'; -import * as fs from 'fs'; -import * as path from 'path'; -import { instance, mock } from 'ts-mockito'; -import * as vscode from 'vscode'; -import { CommandSource, EXTENSION_ROOT_DIR } from '../../../client/common/constants'; -import { IProcessServiceFactory } from '../../../client/common/process/types'; -import { ICondaService, IInterpreterService } from '../../../client/interpreter/contracts'; -import { InterpreterService } from '../../../client/interpreter/interpreterService'; -import { CondaService } from '../../../client/pythonEnvironments/discovery/locators/services/condaService'; -import { ITestManagerFactory } from '../../../client/testing/common/types'; -import { rootWorkspaceUri, updateSetting } from '../../common'; -import { MockProcessService } from '../../mocks/proc'; -import { registerForIOC } from '../../pythonEnvironments/legacyIOC'; -import { lookForTestFile } from '../helper'; -import { UnitTestIocContainer } from '../serviceRegistry'; -import { initialize, initializeTest, IS_MULTI_ROOT_TEST } from '../../initialize'; - -const PYTHON_FILES_PATH = path.join(EXTENSION_ROOT_DIR, 'src', 'test', 'pythonFiles'); -const UNITTEST_TEST_FILES_PATH = path.join(EXTENSION_ROOT_DIR, 'src', 'test', 'pythonFiles', 'testFiles', 'noseFiles'); -const UNITTEST_SINGLE_TEST_FILE_PATH = path.join( - EXTENSION_ROOT_DIR, - 'src', - 'test', - 'pythonFiles', - 'testFiles', - 'single', -); -const filesToDelete = [ - path.join(UNITTEST_TEST_FILES_PATH, '.noseids'), - path.join(UNITTEST_SINGLE_TEST_FILE_PATH, '.noseids'), -]; - -suite('Unit Tests - nose - discovery with mocked process output', () => { - let ioc: UnitTestIocContainer; - 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('testing.nosetestArgs', [], rootWorkspaceUri, configTarget); - await initialize(); - }); - suiteTeardown(async () => { - await updateSetting('testing.nosetestArgs', [], rootWorkspaceUri, configTarget); - filesToDelete.forEach((file) => { - if (fs.existsSync(file)) { - fs.unlinkSync(file); - } - }); - }); - setup(async () => { - await initializeTest(); - await initializeDI(); - }); - teardown(async () => { - await ioc.dispose(); - await updateSetting('testing.nosetestArgs', [], rootWorkspaceUri, configTarget); - }); - - async function initializeDI() { - ioc = new UnitTestIocContainer(); - ioc.registerCommonTypes(); - ioc.registerUnitTestTypes(); - ioc.registerVariableTypes(); - - ioc.registerMockProcessTypes(); - ioc.registerInterpreterStorageTypes(); - - ioc.serviceManager.addSingletonInstance( - IInterpreterService, - instance(mock(InterpreterService)), - ); - - await registerForIOC(ioc.serviceManager, ioc.serviceContainer); - ioc.serviceManager.rebindInstance(ICondaService, instance(mock(CondaService))); - } - - async function injectTestDiscoveryOutput(outputFileName: string) { - const procService = (await ioc.serviceContainer - .get(IProcessServiceFactory) - .create()) as MockProcessService; - procService.onExecObservable((_file, args, _options, callback) => { - if (args.indexOf('--collect-only') >= 0) { - let out = fs.readFileSync(path.join(UNITTEST_TEST_FILES_PATH, outputFileName), 'utf8'); - // Value in the test files. - out = out.replace( - /\/Users\/donjayamanne\/.vscode\/extensions\/pythonVSCode\/src\/test\/pythonFiles/g, - PYTHON_FILES_PATH, - ); - callback({ - out, - source: 'stdout', - }); - } - }); - } - - test('Discover Tests (single test file)', async () => { - await injectTestDiscoveryOutput('one.output'); - const factory = ioc.serviceContainer.get(ITestManagerFactory); - const testManager = factory('nosetest', rootWorkspaceUri!, UNITTEST_SINGLE_TEST_FILE_PATH); - const tests = await testManager.discoverTests(CommandSource.ui, true, true); - assert.equal(tests.testFiles.length, 2, 'Incorrect number of test files'); - assert.equal(tests.testFunctions.length, 6, 'Incorrect number of test functions'); - assert.equal(tests.testSuites.length, 2, 'Incorrect number of test suites'); - lookForTestFile(tests, path.join('tests', 'test_one.py')); - }); - - test('Check that nameToRun in testSuites has class name after : (single test file)', async () => { - await injectTestDiscoveryOutput('two.output'); - const factory = ioc.serviceContainer.get(ITestManagerFactory); - const testManager = factory('nosetest', rootWorkspaceUri!, UNITTEST_SINGLE_TEST_FILE_PATH); - const tests = await testManager.discoverTests(CommandSource.ui, true, true); - assert.equal(tests.testFiles.length, 2, 'Incorrect number of test files'); - assert.equal(tests.testFunctions.length, 6, 'Incorrect number of test functions'); - assert.equal(tests.testSuites.length, 2, 'Incorrect number of test suites'); - assert.equal( - tests.testSuites.every((t) => t.testSuite.name === t.testSuite.nameToRun.split(':')[1]), - true, - 'Suite name does not match class name', - ); - }); - test('Discover Tests (-m=test)', async () => { - await injectTestDiscoveryOutput('three.output'); - await updateSetting('testing.nosetestArgs', ['-m', 'test'], rootWorkspaceUri, configTarget); - const factory = ioc.serviceContainer.get(ITestManagerFactory); - const testManager = factory('nosetest', rootWorkspaceUri!, UNITTEST_TEST_FILES_PATH); - const tests = await testManager.discoverTests(CommandSource.ui, true, true); - assert.equal(tests.testFiles.length, 5, 'Incorrect number of test files'); - assert.equal(tests.testFunctions.length, 16, 'Incorrect number of test functions'); - assert.equal(tests.testSuites.length, 6, 'Incorrect number of test suites'); - lookForTestFile(tests, path.join('tests', 'test_unittest_one.py')); - lookForTestFile(tests, path.join('tests', 'test_unittest_two.py')); - lookForTestFile(tests, path.join('tests', 'unittest_three_test.py')); - lookForTestFile(tests, path.join('tests', 'test4.py')); - lookForTestFile(tests, 'test_root.py'); - }); - - test('Discover Tests (-w=specific -m=tst)', async () => { - await injectTestDiscoveryOutput('four.output'); - await updateSetting('testing.nosetestArgs', ['-w', 'specific', '-m', 'tst'], rootWorkspaceUri, configTarget); - const factory = ioc.serviceContainer.get(ITestManagerFactory); - const testManager = factory('nosetest', rootWorkspaceUri!, UNITTEST_TEST_FILES_PATH); - const tests = await testManager.discoverTests(CommandSource.ui, true, true); - assert.equal(tests.testFiles.length, 2, 'Incorrect number of test files'); - assert.equal(tests.testFunctions.length, 6, 'Incorrect number of test functions'); - assert.equal(tests.testSuites.length, 2, 'Incorrect number of test suites'); - lookForTestFile(tests, path.join('specific', 'tst_unittest_one.py')); - lookForTestFile(tests, path.join('specific', 'tst_unittest_two.py')); - }); - - test('Discover Tests (-m=test_)', async () => { - await injectTestDiscoveryOutput('five.output'); - await updateSetting('testing.nosetestArgs', ['-m', 'test_'], rootWorkspaceUri, configTarget); - const factory = ioc.serviceContainer.get(ITestManagerFactory); - const testManager = factory('nosetest', rootWorkspaceUri!, UNITTEST_TEST_FILES_PATH); - const tests = await testManager.discoverTests(CommandSource.ui, true, true); - assert.equal(tests.testFiles.length, 1, 'Incorrect number of test files'); - assert.equal(tests.testFunctions.length, 3, 'Incorrect number of test functions'); - assert.equal(tests.testSuites.length, 1, 'Incorrect number of test suites'); - lookForTestFile(tests, 'test_root.py'); - }); -}); diff --git a/src/test/testing/nosetest/nosetest.discovery.unit.test.ts b/src/test/testing/nosetest/nosetest.discovery.unit.test.ts deleted file mode 100644 index cc9af61e62c0..000000000000 --- a/src/test/testing/nosetest/nosetest.discovery.unit.test.ts +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { expect, use } from 'chai'; -import * as chaipromise from 'chai-as-promised'; -import * as typeMoq from 'typemoq'; -import * as path from 'path'; -import * as fs from 'fs-extra'; -import { CancellationToken, Uri } from 'vscode'; -import { IServiceContainer } from '../../../client/ioc/types'; -import { NOSETEST_PROVIDER } from '../../../client/testing/common/constants'; -import { TestsHelper } from '../../../client/testing/common/testUtils'; -import { TestFlatteningVisitor } from '../../../client/testing/common/testVisitors/flatteningVisitor'; -import { - IArgumentsService, - ITestDiscoveryService, - ITestRunner, - ITestsParser, - Options, - TestDiscoveryOptions, - TestFilter, - Tests, - UnitTestParserOptions, -} from '../../../client/testing/common/types'; -import { TestDiscoveryService } from '../../../client/testing/nosetest/services/discoveryService'; -import { TestsParser } from '../../../client/testing/nosetest/services/parserService'; -import { EXTENSION_ROOT_DIR_FOR_TESTS } from '../../constants'; - -const DISCOVERY_OUTPUT = path.join( - EXTENSION_ROOT_DIR_FOR_TESTS, - 'src', - 'test', - 'testing', - 'nosetest', - 'nose_discovery_output.txt', -); - -use(chaipromise); - -suite('Unit Tests - nose - Discovery', () => { - let discoveryService: ITestDiscoveryService; - let argsService: typeMoq.IMock; - let testParser: typeMoq.IMock; - let runner: typeMoq.IMock; - let serviceContainer: typeMoq.IMock; - - setup(() => { - serviceContainer = typeMoq.Mock.ofType(); - argsService = typeMoq.Mock.ofType(); - testParser = typeMoq.Mock.ofType(); - runner = typeMoq.Mock.ofType(); - - serviceContainer - .setup((s) => s.get(typeMoq.It.isValue(IArgumentsService), typeMoq.It.isAny())) - .returns(() => argsService.object); - serviceContainer - .setup((s) => s.get(typeMoq.It.isValue(ITestRunner), typeMoq.It.isAny())) - .returns(() => runner.object); - - discoveryService = new TestDiscoveryService(serviceContainer.object, testParser.object); - }); - test('Ensure discovery is invoked with the right args', async () => { - const args: string[] = []; - const runOutput = 'xyz'; - const tests: Tests = { - summary: { errors: 1, failures: 0, passed: 0, skipped: 0 }, - testFiles: [], - testFunctions: [], - testSuites: [], - rootTestFolders: [], - testFolders: [], - }; - argsService - .setup((a) => a.filterArguments(typeMoq.It.isValue(args), typeMoq.It.isValue(TestFilter.discovery))) - .returns(() => []) - .verifiable(typeMoq.Times.once()); - runner - .setup((r) => r.run(typeMoq.It.isValue(NOSETEST_PROVIDER), typeMoq.It.isAny())) - .callback((_, opts: Options) => { - expect(opts.args).to.include('--collect-only'); - expect(opts.args).to.include('-vvv'); - }) - .returns(() => Promise.resolve(runOutput)) - .verifiable(typeMoq.Times.once()); - testParser - .setup((t) => t.parse(typeMoq.It.isValue(runOutput), typeMoq.It.isAny())) - .returns(() => tests) - .verifiable(typeMoq.Times.once()); - - const options = typeMoq.Mock.ofType(); - const token = typeMoq.Mock.ofType(); - options.setup((o) => o.args).returns(() => args); - options.setup((o) => o.token).returns(() => token.object); - token.setup((t) => t.isCancellationRequested).returns(() => false); - - const result = await discoveryService.discoverTests(options.object); - - expect(result).to.be.equal(tests); - argsService.verifyAll(); - runner.verifyAll(); - testParser.verifyAll(); - }); - test('Ensure discovery is cancelled', async () => { - const args: string[] = []; - const runOutput = 'xyz'; - const tests: Tests = { - summary: { errors: 1, failures: 0, passed: 0, skipped: 0 }, - testFiles: [], - testFunctions: [], - testSuites: [], - rootTestFolders: [], - testFolders: [], - }; - argsService - .setup((a) => a.filterArguments(typeMoq.It.isValue(args), typeMoq.It.isValue(TestFilter.discovery))) - .returns(() => []) - .verifiable(typeMoq.Times.once()); - runner - .setup((r) => r.run(typeMoq.It.isValue(NOSETEST_PROVIDER), typeMoq.It.isAny())) - .callback((_, opts: Options) => { - expect(opts.args).to.include('--collect-only'); - expect(opts.args).to.include('-vvv'); - }) - .returns(() => Promise.resolve(runOutput)) - .verifiable(typeMoq.Times.once()); - testParser - .setup((t) => t.parse(typeMoq.It.isAny(), typeMoq.It.isAny())) - .returns(() => tests) - .verifiable(typeMoq.Times.never()); - - const options = typeMoq.Mock.ofType(); - const token = typeMoq.Mock.ofType(); - token - .setup((t) => t.isCancellationRequested) - .returns(() => true) - .verifiable(typeMoq.Times.once()); - - options.setup((o) => o.args).returns(() => args); - options.setup((o) => o.token).returns(() => token.object); - const promise = discoveryService.discoverTests(options.object); - - await expect(promise).to.eventually.be.rejectedWith('cancelled'); - argsService.verifyAll(); - runner.verifyAll(); - testParser.verifyAll(); - }); - - test('Ensure discovery resolves test files in n-depth directories', async () => { - const discoveryOutput = await fs.readFile(DISCOVERY_OUTPUT, 'utf8'); - const testHelper: TestsHelper = new TestsHelper(new TestFlatteningVisitor(), serviceContainer.object); - - const testsParser: TestsParser = new TestsParser(testHelper); - - const opts = typeMoq.Mock.ofType(); - const token = typeMoq.Mock.ofType(); - const wspace = typeMoq.Mock.ofType(); - opts.setup((o) => o.token).returns(() => token.object); - opts.setup((o) => o.workspaceFolder).returns(() => wspace.object); - token.setup((t) => t.isCancellationRequested).returns(() => true); - opts.setup((o) => o.cwd).returns(() => '/home/user/dev'); - opts.setup((o) => o.startDirectory).returns(() => '/home/user/dev/tests'); - - const tests: Tests = testsParser.parse(discoveryOutput, opts.object); - - expect(tests.testFiles.length).to.be.equal(3); - expect(tests.testFunctions.length).to.be.equal(6); - expect(tests.testSuites.length).to.be.equal(3); - expect(tests.testFolders.length).to.be.equal(5); - - // now ensure that the 'nameToRun' for each test function begins with its file's a single test suite... - tests.testFunctions.forEach((fn) => { - if (fn.parentTestSuite) { - const testPrefix: boolean = fn.testFunction.nameToRun.startsWith(fn.parentTestFile.nameToRun); - expect(testPrefix).to.equal( - true, - [ - `function ${fn.testFunction.name} was found in file ${fn.parentTestFile.name}, `, - `but the parent file 'nameToRun' (${fn.parentTestFile.nameToRun}) isn't the `, - `prefix to the functions 'nameToRun' (${fn.testFunction.nameToRun})`, - ].join(''), - ); - } - }); - - // Check we didn't report the unittest TestCase base class as a suite - tests.testSuites.forEach((suite) => { - expect(suite.testSuite.name).to.not.equal( - 'unittest.case.TestCase', - 'unittest.case.TestCase found in discovered tests', - ); - expect(suite.testSuite.functions.length).to.be.greaterThan( - 0, - `${suite.testSuite.name} has no runnable tests`, - ); - }); - - // Check that the visible folder name is just the last item in the path, not the whole path - tests.testFolders.forEach((folder) => { - const pathItems = folder.nameToRun.split(path.sep); - expect(pathItems[pathItems.length - 1]).to.equal(folder.name); - }); - - // Check that the visible file name is just the last item in the path, not the whole path - tests.testFiles.forEach((file) => { - const pathItems = file.nameToRun.split('/'); // Not path.sep because test input is from posix discovery - expect(pathItems[pathItems.length - 1]).to.equal(file.name); - }); - }); -}); diff --git a/src/test/testing/nosetest/nosetest.run.test.ts b/src/test/testing/nosetest/nosetest.run.test.ts deleted file mode 100644 index 715c55844eb4..000000000000 --- a/src/test/testing/nosetest/nosetest.run.test.ts +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -import * as assert from 'assert'; -import * as fs from 'fs'; -import * as path from 'path'; -import * as vscode from 'vscode'; -import { CommandSource, EXTENSION_ROOT_DIR } from '../../../client/common/constants'; -import { IProcessServiceFactory } from '../../../client/common/process/types'; -import { ITestManagerFactory, TestsToRun } from '../../../client/testing/common/types'; -import { rootWorkspaceUri, updateSetting } from '../../common'; -import { MockProcessService } from '../../mocks/proc'; -import { UnitTestIocContainer } from '../serviceRegistry'; -import { initialize, initializeTest, IS_MULTI_ROOT_TEST } from './../../initialize'; - -const UNITTEST_TEST_FILES_PATH = path.join(EXTENSION_ROOT_DIR, 'src', 'test', 'pythonFiles', 'testFiles', 'noseFiles'); -const UNITTEST_SINGLE_TEST_FILE_PATH = path.join( - EXTENSION_ROOT_DIR, - 'src', - 'test', - 'pythonFiles', - 'testFiles', - 'single', -); -const filesToDelete = [ - path.join(UNITTEST_TEST_FILES_PATH, '.noseids'), - path.join(UNITTEST_SINGLE_TEST_FILE_PATH, '.noseids'), -]; - -suite('Unit Tests - nose - run against actual python process', () => { - let ioc: UnitTestIocContainer; - 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('testing.nosetestArgs', [], rootWorkspaceUri, configTarget); - await initialize(); - }); - suiteTeardown(async () => { - await updateSetting('testing.nosetestArgs', [], rootWorkspaceUri, configTarget); - filesToDelete.forEach((file) => { - if (fs.existsSync(file)) { - fs.unlinkSync(file); - } - }); - }); - setup(async () => { - await initializeTest(); - await initializeDI(); - }); - teardown(async () => { - await ioc.dispose(); - await updateSetting('testing.nosetestArgs', [], rootWorkspaceUri, configTarget); - }); - - async function initializeDI() { - ioc = new UnitTestIocContainer(); - ioc.registerCommonTypes(); - ioc.registerUnitTestTypes(); - ioc.registerVariableTypes(); - - ioc.registerMockProcessTypes(); - await ioc.registerMockInterpreterTypes(); - ioc.registerInterpreterStorageTypes(); - } - - async function injectTestDiscoveryOutput(outputFileName: string) { - const procService = (await ioc.serviceContainer - .get(IProcessServiceFactory) - .create()) as MockProcessService; - procService.onExecObservable((_file, args, _options, callback) => { - if (args.indexOf('--collect-only') >= 0) { - callback({ - out: fs - .readFileSync(path.join(UNITTEST_TEST_FILES_PATH, outputFileName), 'utf8') - .replace( - /\/Users\/donjayamanne\/.vscode\/extensions\/pythonVSCode\/src\/test\/pythonFiles\/testFiles\/noseFiles/g, - UNITTEST_TEST_FILES_PATH, - ), - source: 'stdout', - }); - } - }); - } - - async function injectTestRunOutput(outputFileName: string, failedOutput: boolean = false) { - const procService = (await ioc.serviceContainer - .get(IProcessServiceFactory) - .create()) as MockProcessService; - procService.onExecObservable((_file, args, _options, callback) => { - if (failedOutput && args.indexOf('--failed') === -1) { - return; - } - - const index = args.findIndex((arg) => arg.startsWith('--xunit-file=')); - if (index >= 0) { - const fileName = args[index].substr('--xunit-file='.length); - const contents = fs.readFileSync(path.join(UNITTEST_TEST_FILES_PATH, outputFileName), 'utf8'); - fs.writeFileSync(fileName, contents, 'utf8'); - callback({ out: '', source: 'stdout' }); - } - }); - } - - test('Run Tests', async () => { - await injectTestDiscoveryOutput('run.one.output'); - await injectTestRunOutput('run.one.result'); - await updateSetting('testing.nosetestArgs', ['-m', 'test'], rootWorkspaceUri, configTarget); - const factory = ioc.serviceContainer.get(ITestManagerFactory); - const testManager = factory('nosetest', rootWorkspaceUri!, UNITTEST_TEST_FILES_PATH); - const results = await testManager.runTest(CommandSource.ui); - assert.equal(results.summary.errors, 1, 'Errors'); - assert.equal(results.summary.failures, 7, 'Failures'); - assert.equal(results.summary.passed, 6, 'Passed'); - assert.equal(results.summary.skipped, 2, 'skipped'); - }); - - test('Run Failed Tests', async () => { - await injectTestDiscoveryOutput('run.two.output'); - await injectTestRunOutput('run.two.result'); - await injectTestRunOutput('run.two.again.result', true); - await updateSetting('testing.nosetestArgs', ['-m', 'test'], rootWorkspaceUri, configTarget); - const factory = ioc.serviceContainer.get(ITestManagerFactory); - const testManager = factory('nosetest', rootWorkspaceUri!, UNITTEST_TEST_FILES_PATH); - let results = await testManager.runTest(CommandSource.ui); - assert.equal(results.summary.errors, 1, 'Errors'); - assert.equal(results.summary.failures, 7, 'Failures'); - assert.equal(results.summary.passed, 6, 'Passed'); - assert.equal(results.summary.skipped, 2, 'skipped'); - - results = await testManager.runTest(CommandSource.ui, undefined, true); - assert.equal(results.summary.errors, 1, 'Errors again'); - assert.equal(results.summary.failures, 7, 'Failures again'); - assert.equal(results.summary.passed, 0, 'Passed again'); - assert.equal(results.summary.skipped, 0, 'skipped again'); - }); - - test('Run Specific Test File', async () => { - await injectTestDiscoveryOutput('run.three.output'); - await injectTestRunOutput('run.three.result'); - await updateSetting('testing.nosetestArgs', ['-m', 'test'], rootWorkspaceUri, configTarget); - const factory = ioc.serviceContainer.get(ITestManagerFactory); - const testManager = factory('nosetest', rootWorkspaceUri!, UNITTEST_TEST_FILES_PATH); - const tests = await testManager.discoverTests(CommandSource.ui, true, true); - const testFileToRun = tests.testFiles.find((t) => t.fullPath.endsWith('test_root.py')); - assert.ok(testFileToRun, 'Test file not found'); - - const testFile: TestsToRun = { testFile: [testFileToRun!], testFolder: [], testFunction: [], testSuite: [] }; - const results = await testManager.runTest(CommandSource.ui, testFile); - assert.equal(results.summary.errors, 0, 'Errors'); - assert.equal(results.summary.failures, 1, 'Failures'); - assert.equal(results.summary.passed, 1, 'Passed'); - assert.equal(results.summary.skipped, 1, 'skipped'); - }); - - test('Run Specific Test Suite', async () => { - await injectTestDiscoveryOutput('run.four.output'); - await injectTestRunOutput('run.four.result'); - await updateSetting('testing.nosetestArgs', ['-m', 'test'], rootWorkspaceUri, configTarget); - const factory = ioc.serviceContainer.get(ITestManagerFactory); - const testManager = factory('nosetest', rootWorkspaceUri!, UNITTEST_TEST_FILES_PATH); - const tests = await testManager.discoverTests(CommandSource.ui, true, true); - const testSuiteToRun = tests.testSuites.find((s) => s.xmlClassName === 'test_root.Test_Root_test1'); - assert.ok(testSuiteToRun, 'Test suite not found'); - - const testSuite: TestsToRun = { - testFile: [], - testFolder: [], - testFunction: [], - testSuite: [testSuiteToRun!.testSuite], - }; - const results = await testManager.runTest(CommandSource.ui, testSuite); - assert.equal(results.summary.errors, 0, 'Errors'); - assert.equal(results.summary.failures, 1, 'Failures'); - assert.equal(results.summary.passed, 1, 'Passed'); - assert.equal(results.summary.skipped, 1, 'skipped'); - }); - - test('Run Specific Test Function', async () => { - await injectTestDiscoveryOutput('run.five.output'); - await injectTestRunOutput('run.five.result'); - await updateSetting('testing.nosetestArgs', ['-m', 'test'], rootWorkspaceUri, configTarget); - const factory = ioc.serviceContainer.get(ITestManagerFactory); - const testManager = factory('nosetest', rootWorkspaceUri!, UNITTEST_TEST_FILES_PATH); - const tests = await testManager.discoverTests(CommandSource.ui, true, true); - const testFnToRun = tests.testFunctions.find((f) => f.xmlClassName === 'test_root.Test_Root_test1'); - assert.ok(testFnToRun, 'Test function not found'); - - const testFn: TestsToRun = { - testFile: [], - testFolder: [], - testFunction: [testFnToRun!.testFunction], - testSuite: [], - }; - const results = await testManager.runTest(CommandSource.ui, testFn); - assert.equal(results.summary.errors, 0, 'Errors'); - assert.equal(results.summary.failures, 1, 'Failures'); - assert.equal(results.summary.passed, 0, 'Passed'); - assert.equal(results.summary.skipped, 0, 'skipped'); - }); -}); diff --git a/src/test/testing/nosetest/nosetest.test.ts b/src/test/testing/nosetest/nosetest.test.ts deleted file mode 100644 index e99f65cbaf4b..000000000000 --- a/src/test/testing/nosetest/nosetest.test.ts +++ /dev/null @@ -1,77 +0,0 @@ -import * as assert from 'assert'; -import * as fs from 'fs'; -import * as path from 'path'; -import * as vscode from 'vscode'; -import { CommandSource, EXTENSION_ROOT_DIR } from '../../../client/common/constants'; -import { ITestManagerFactory } from '../../../client/testing/common/types'; -import { rootWorkspaceUri, updateSetting } from '../../common'; -import { lookForTestFile } from '../helper'; -import { UnitTestIocContainer } from '../serviceRegistry'; -import { initialize, initializeTest, IS_MULTI_ROOT_TEST } from './../../initialize'; - -const UNITTEST_TEST_FILES_PATH = path.join(EXTENSION_ROOT_DIR, 'src', 'test', 'pythonFiles', 'testFiles', 'noseFiles'); -const UNITTEST_SINGLE_TEST_FILE_PATH = path.join( - EXTENSION_ROOT_DIR, - 'src', - 'test', - 'pythonFiles', - 'testFiles', - 'single', -); -const filesToDelete = [ - path.join(UNITTEST_TEST_FILES_PATH, '.noseids'), - path.join(UNITTEST_SINGLE_TEST_FILE_PATH, '.noseids'), -]; - -suite('Unit Tests - nose - discovery against actual python process', () => { - let ioc: UnitTestIocContainer; - 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('testing.nosetestArgs', [], rootWorkspaceUri, configTarget); - await initialize(); - }); - suiteTeardown(async () => { - await updateSetting('testing.nosetestArgs', [], rootWorkspaceUri, configTarget); - filesToDelete.forEach((file) => { - if (fs.existsSync(file)) { - fs.unlinkSync(file); - } - }); - }); - setup(async () => { - await initializeTest(); - await initializeDI(); - }); - teardown(async () => { - await ioc.dispose(); - await updateSetting('testing.nosetestArgs', [], rootWorkspaceUri, configTarget); - }); - - async function initializeDI() { - ioc = new UnitTestIocContainer(); - ioc.registerCommonTypes(); - ioc.registerProcessTypes(); - ioc.registerUnitTestTypes(); - ioc.registerVariableTypes(); - await ioc.registerMockInterpreterTypes(); - ioc.registerInterpreterStorageTypes(); - } - - test('Discover Tests (single test file)', async () => { - const factory = ioc.serviceContainer.get(ITestManagerFactory); - const testManager = factory('nosetest', rootWorkspaceUri!, UNITTEST_SINGLE_TEST_FILE_PATH); - const tests = await testManager.discoverTests(CommandSource.ui, true, true); - assert.equal(tests.testFiles.length, 2, 'Incorrect number of test files'); - assert.equal(tests.testFunctions.length, 6, 'Incorrect number of test functions'); - assert.equal(tests.testSuites.length, 2, 'Incorrect number of test suites'); - lookForTestFile(tests, path.join('tests', 'test_one.py')); - }); -}); diff --git a/src/test/testing/rediscover.test.ts b/src/test/testing/rediscover.test.ts index f0e3fab3c0c5..3ac1ec17c148 100644 --- a/src/test/testing/rediscover.test.ts +++ b/src/test/testing/rediscover.test.ts @@ -45,7 +45,6 @@ suite('Unit Tests re-discovery', () => { async function resetSettings() { await updateSetting('testing.unittestArgs', defaultUnitTestArgs, rootWorkspaceUri, configTarget); - await updateSetting('testing.nosetestArgs', [], rootWorkspaceUri, configTarget); await updateSetting('testing.pytestArgs', [], rootWorkspaceUri, configTarget); } @@ -86,9 +85,4 @@ suite('Unit Tests re-discovery', () => { await updateSetting('testing.pytestArgs', ['-k=test_'], rootWorkspaceUri, configTarget); await discoverUnitTests('pytest'); }); - - test('Re-discover tests (nosetest)', async () => { - await updateSetting('testing.nosetestArgs', ['-m', 'test'], rootWorkspaceUri, configTarget); - await discoverUnitTests('nosetest'); - }); }); diff --git a/src/test/testing/serviceRegistry.ts b/src/test/testing/serviceRegistry.ts index 1d98fdb1d866..8b1f32956b48 100644 --- a/src/test/testing/serviceRegistry.ts +++ b/src/test/testing/serviceRegistry.ts @@ -9,7 +9,7 @@ import { IProcessServiceFactory } from '../../client/common/process/types'; import { IInterpreterHelper } from '../../client/interpreter/contracts'; import { InterpreterHelper } from '../../client/interpreter/helpers'; import { IServiceContainer } from '../../client/ioc/types'; -import { NOSETEST_PROVIDER, PYTEST_PROVIDER, UNITTEST_PROVIDER } from '../../client/testing/common/constants'; +import { PYTEST_PROVIDER, UNITTEST_PROVIDER } from '../../client/testing/common/constants'; import { TestContextService } from '../../client/testing/common/services/contextService'; import { TestDiscoveredTestParser } from '../../client/testing/common/services/discoveredTestParser'; import { TestsDiscoveryService } from '../../client/testing/common/services/discovery'; @@ -38,9 +38,6 @@ import { ITestVisitor, IUnitTestSocketServer, } from '../../client/testing/common/types'; -import { TestManager as NoseTestManager } from '../../client/testing/nosetest/main'; -import { TestDiscoveryService as NoseTestDiscoveryService } from '../../client/testing/nosetest/services/discoveryService'; -import { TestsParser as NoseTestTestsParser } from '../../client/testing/nosetest/services/parserService'; import { TestManager as PyTestTestManager } from '../../client/testing/pytest/main'; import { TestDiscoveryService as PytestTestDiscoveryService } from '../../client/testing/pytest/services/discoveryService'; import { TestProvider } from '../../client/testing/types'; @@ -89,7 +86,6 @@ export class UnitTestIocContainer extends IocContainer { public registerTestParsers(): void { this.serviceManager.add(ITestsParser, UnitTestTestsParser, UNITTEST_PROVIDER); - this.serviceManager.add(ITestsParser, NoseTestTestsParser, NOSETEST_PROVIDER); } public registerTestDiscoveryServices(): void { @@ -103,11 +99,6 @@ export class UnitTestIocContainer extends IocContainer { PytestTestDiscoveryService, PYTEST_PROVIDER, ); - this.serviceManager.add( - ITestDiscoveryService, - NoseTestDiscoveryService, - NOSETEST_PROVIDER, - ); this.serviceManager.add(ITestDiscoveryService, TestsDiscoveryService, 'common'); this.serviceManager.add(ITestDiscoveredTestParser, TestDiscoveredTestParser); } @@ -123,9 +114,6 @@ export class UnitTestIocContainer extends IocContainer { const serviceContainer = context.container.get(IServiceContainer); switch (testProvider) { - case NOSETEST_PROVIDER: { - return new NoseTestManager(workspaceFolder, rootDirectory, serviceContainer); - } case PYTEST_PROVIDER: { return new PyTestTestManager(workspaceFolder, rootDirectory, serviceContainer); } From 92b855f3f2b63f728ad815ca3de28479b797d4f5 Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Thu, 20 May 2021 17:58:10 -0700 Subject: [PATCH 05/39] Remove navigation commands (#16276) --- package.json | 29 - src/client/common/application/commands.ts | 5 - src/client/common/constants.ts | 4 - src/client/extensionActivation.ts | 3 - .../testing/explorer/commandHandlers.ts | 96 -- .../testing/explorer/failedTestHandler.ts | 52 - .../testing/explorer/testTreeViewItem.ts | 161 --- .../testing/explorer/testTreeViewProvider.ts | 211 ---- .../testing/navigation/commandHandler.ts | 56 - .../testing/navigation/fileNavigator.ts | 22 - .../testing/navigation/functionNavigator.ts | 57 - src/client/testing/navigation/helper.ts | 39 - .../testing/navigation/serviceRegistry.ts | 38 - .../testing/navigation/suiteNavigator.ts | 56 - src/client/testing/navigation/types.ts | 40 - src/client/testing/serviceRegistry.ts | 15 - src/test/testing/explorer/explorerTestData.ts | 256 ----- .../explorer/failedTestHandler.unit.test.ts | 113 -- .../testExplorerCommandHandler.unit.test.ts | 137 --- .../explorer/testTreeViewItem.unit.test.ts | 69 -- .../testTreeViewProvider.unit.test.ts | 993 ------------------ .../navigation/commandHandlers.unit.test.ts | 102 -- .../navigation/fileNavigator.unit.test.ts | 41 - .../navigation/functionNavigator.unit.test.ts | 115 -- .../testing/navigation/helper.unit.test.ts | 84 -- .../navigation/serviceRegistry.unit.test.ts | 63 -- .../navigation/suiteNavigator.unit.test.ts | 142 --- 27 files changed, 2999 deletions(-) delete mode 100644 src/client/testing/explorer/commandHandlers.ts delete mode 100644 src/client/testing/explorer/failedTestHandler.ts delete mode 100644 src/client/testing/explorer/testTreeViewItem.ts delete mode 100644 src/client/testing/explorer/testTreeViewProvider.ts delete mode 100644 src/client/testing/navigation/commandHandler.ts delete mode 100644 src/client/testing/navigation/fileNavigator.ts delete mode 100644 src/client/testing/navigation/functionNavigator.ts delete mode 100644 src/client/testing/navigation/helper.ts delete mode 100644 src/client/testing/navigation/serviceRegistry.ts delete mode 100644 src/client/testing/navigation/suiteNavigator.ts delete mode 100644 src/client/testing/navigation/types.ts delete mode 100644 src/test/testing/explorer/explorerTestData.ts delete mode 100644 src/test/testing/explorer/failedTestHandler.unit.test.ts delete mode 100644 src/test/testing/explorer/testExplorerCommandHandler.unit.test.ts delete mode 100644 src/test/testing/explorer/testTreeViewItem.unit.test.ts delete mode 100644 src/test/testing/explorer/testTreeViewProvider.unit.test.ts delete mode 100644 src/test/testing/navigation/commandHandlers.unit.test.ts delete mode 100644 src/test/testing/navigation/fileNavigator.unit.test.ts delete mode 100644 src/test/testing/navigation/functionNavigator.unit.test.ts delete mode 100644 src/test/testing/navigation/helper.unit.test.ts delete mode 100644 src/test/testing/navigation/serviceRegistry.unit.test.ts delete mode 100644 src/test/testing/navigation/suiteNavigator.unit.test.ts diff --git a/package.json b/package.json index 460e2bf01fa7..8db9a37ee96e 100644 --- a/package.json +++ b/package.json @@ -394,14 +394,6 @@ "command": "python.launchTensorBoard", "title": "%python.command.python.launchTensorBoard.title%" }, - { - "command": "python.openTestNodeInEditor", - "icon": { - "dark": "resources/dark/open-file.svg", - "light": "resources/light/open-file.svg" - }, - "title": "Open" - }, { "category": "Python Refactor", "command": "python.refactorExtractMethod", @@ -1917,12 +1909,6 @@ "category": "Python", "command": "python.launchTensorBoard" }, - { - "category": "Python", - "command": "python.openTestNodeInEditor", - "title": "Open", - "when": "config.noExists" - }, { "category": "Python", "command": "python.runTestNode", @@ -2061,21 +2047,6 @@ "group": "inline@2", "when": "view == python_tests && viewItem == testWorkspaceFolder && !busyTests" }, - { - "command": "python.openTestNodeInEditor", - "group": "inline@2", - "when": "view == python_tests && viewItem == file" - }, - { - "command": "python.openTestNodeInEditor", - "group": "inline@2", - "when": "view == python_tests && viewItem == function" - }, - { - "command": "python.openTestNodeInEditor", - "group": "inline@2", - "when": "view == python_tests && viewItem == suite" - }, { "command": "python.runTestNode", "group": "inline@0", diff --git a/src/client/common/application/commands.ts b/src/client/common/application/commands.ts index fa6735a6d0fa..6dea465e02a0 100644 --- a/src/client/common/application/commands.ts +++ b/src/client/common/application/commands.ts @@ -127,10 +127,5 @@ export interface ICommandNameArgumentTypeMapping extends ICommandNameWithoutArgu [Commands.runTestNode]: [TestDataItem]; // When command is invoked from a tree node, first argument is the node data. [Commands.debugTestNode]: [TestDataItem]; - // When command is invoked from a tree node, first argument is the node data. - [Commands.openTestNodeInEditor]: [TestDataItem]; - [Commands.navigateToTestFile]: [Uri, TestDataItem, boolean]; - [Commands.navigateToTestFunction]: [Uri, TestDataItem, boolean]; - [Commands.navigateToTestSuite]: [Uri, TestDataItem, boolean]; [Commands.LaunchTensorBoard]: [TensorBoardEntrypoint, TensorBoardEntrypointTrigger]; } diff --git a/src/client/common/constants.ts b/src/client/common/constants.ts index 3435966dd2ac..e0905f41ed65 100644 --- a/src/client/common/constants.ts +++ b/src/client/common/constants.ts @@ -67,10 +67,6 @@ export namespace Commands { export const Enable_Linter = 'python.enableLinting'; export const Run_Linter = 'python.runLinting'; export const Enable_SourceMap_Support = 'python.enableSourceMapSupport'; - export const navigateToTestFunction = 'navigateToTestFunction'; - export const navigateToTestSuite = 'navigateToTestSuite'; - export const navigateToTestFile = 'navigateToTestFile'; - export const openTestNodeInEditor = 'python.openTestNodeInEditor'; export const runTestNode = 'python.runTestNode'; export const debugTestNode = 'python.debugTestNode'; export const SwitchOffInsidersChannel = 'python.switchOffInsidersChannel'; diff --git a/src/client/extensionActivation.ts b/src/client/extensionActivation.ts index 56aa7b112d70..034cde341f49 100644 --- a/src/client/extensionActivation.ts +++ b/src/client/extensionActivation.ts @@ -47,7 +47,6 @@ import { setExtensionInstallTelemetryProperties } from './telemetry/extensionIns import { registerTypes as tensorBoardRegisterTypes } from './tensorBoard/serviceRegistry'; import { registerTypes as commonRegisterTerminalTypes } from './terminals/serviceRegistry'; import { ICodeExecutionManager, ITerminalAutoActivation } from './terminals/types'; -import { ITestCodeNavigatorCommandHandler, ITestExplorerCommandHandler } from './testing/navigation/types'; import { registerTypes as unitTestsRegisterTypes } from './testing/serviceRegistry'; import { ITestingService } from './testing/types'; import { registerTypes as interpretersRegisterTypes } from './interpreter/serviceRegistry'; @@ -161,8 +160,6 @@ async function activateLegacy(ext: ExtensionState): Promise { cmdManager.executeCommand('setContext', 'python.vscode.channel', applicationEnv.channel).then(noop, noop); serviceContainer.get(IApplicationDiagnostics).register(); - serviceContainer.get(ITestCodeNavigatorCommandHandler).register(); - serviceContainer.get(ITestExplorerCommandHandler).register(); serviceContainer.get(ILanguageServerExtension).register(); serviceContainer.get(ITestingService).register(); diff --git a/src/client/testing/explorer/commandHandlers.ts b/src/client/testing/explorer/commandHandlers.ts deleted file mode 100644 index 6b724efd7e5d..000000000000 --- a/src/client/testing/explorer/commandHandlers.ts +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { inject, injectable } from 'inversify'; -import { ICommandManager } from '../../common/application/types'; -import { Commands, CommandSource } from '../../common/constants'; -import { traceDecorators } from '../../common/logger'; -import { IDisposable } from '../../common/types'; -import { swallowExceptions } from '../../common/utils/decorators'; -import { getTestDataItemType } from '../common/testUtils'; -import { TestFile, TestFolder, TestFunction, TestsToRun, TestSuite } from '../common/types'; -import { ITestDataItemResource, TestDataItem, TestDataItemType } from '../common/types'; -import { ITestExplorerCommandHandler } from '../navigation/types'; - -type NavigationCommands = - | typeof Commands.navigateToTestFile - | typeof Commands.navigateToTestFunction - | typeof Commands.navigateToTestSuite; -const testNavigationCommandMapping: { [key: string]: NavigationCommands } = { - [TestDataItemType.file]: Commands.navigateToTestFile, - [TestDataItemType.function]: Commands.navigateToTestFunction, - [TestDataItemType.suite]: Commands.navigateToTestSuite, -}; - -@injectable() -export class TestExplorerCommandHandler implements ITestExplorerCommandHandler { - private readonly disposables: IDisposable[] = []; - constructor( - @inject(ICommandManager) private readonly cmdManager: ICommandManager, - @inject(ITestDataItemResource) private readonly testResource: ITestDataItemResource, - ) {} - public register(): void { - this.disposables.push(this.cmdManager.registerCommand(Commands.runTestNode, this.onRunTestNode, this)); - this.disposables.push(this.cmdManager.registerCommand(Commands.debugTestNode, this.onDebugTestNode, this)); - this.disposables.push( - this.cmdManager.registerCommand(Commands.openTestNodeInEditor, this.onOpenTestNodeInEditor, this), - ); - } - public dispose(): void { - this.disposables.forEach((item) => item.dispose()); - } - @swallowExceptions('Run test node') - @traceDecorators.error('Run test node failed') - protected async onRunTestNode(item: TestDataItem): Promise { - await this.runDebugTestNode(item, 'run'); - } - @swallowExceptions('Debug test node') - @traceDecorators.error('Debug test node failed') - protected async onDebugTestNode(item: TestDataItem): Promise { - await this.runDebugTestNode(item, 'debug'); - } - @swallowExceptions('Open test node in Editor') - @traceDecorators.error('Open test node in editor failed') - protected async onOpenTestNodeInEditor(item: TestDataItem): Promise { - const testType = getTestDataItemType(item); - if (testType === TestDataItemType.folder) { - throw new Error('Unknown Test Type'); - } - const command = testNavigationCommandMapping[testType]; - const testUri = this.testResource.getResource(item); - if (!command) { - throw new Error('Unknown Test Type'); - } - this.cmdManager.executeCommand(command, testUri, item, true); - } - - protected async runDebugTestNode(item: TestDataItem, runType: 'run' | 'debug'): Promise { - let testToRun: TestsToRun; - - switch (getTestDataItemType(item)) { - case TestDataItemType.file: { - testToRun = { testFile: [item as TestFile] }; - break; - } - case TestDataItemType.folder: { - testToRun = { testFolder: [item as TestFolder] }; - break; - } - case TestDataItemType.suite: { - testToRun = { testSuite: [item as TestSuite] }; - break; - } - case TestDataItemType.function: { - testToRun = { testFunction: [item as TestFunction] }; - break; - } - default: - throw new Error('Unknown Test Type'); - } - const testUri = this.testResource.getResource(item); - const cmd = runType === 'run' ? Commands.Tests_Run : Commands.Tests_Debug; - this.cmdManager.executeCommand(cmd, undefined, CommandSource.testExplorer, testUri, testToRun); - } -} diff --git a/src/client/testing/explorer/failedTestHandler.ts b/src/client/testing/explorer/failedTestHandler.ts deleted file mode 100644 index ebe1fa84e345..000000000000 --- a/src/client/testing/explorer/failedTestHandler.ts +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { inject, injectable } from 'inversify'; -import { Uri } from 'vscode'; -import { IExtensionSingleActivationService } from '../../activation/types'; -import { ICommandManager } from '../../common/application/types'; -import { Commands } from '../../common/constants'; -import '../../common/extensions'; -import { IDisposable, IDisposableRegistry } from '../../common/types'; -import { debounceAsync } from '../../common/utils/decorators'; -import { getTestDataItemType } from '../common/testUtils'; -import { TestDataItem, TestDataItemType, ITestCollectionStorageService, TestStatus } from '../common/types'; - -@injectable() -export class FailedTestHandler implements IExtensionSingleActivationService, IDisposable { - private readonly disposables: IDisposable[] = []; - private readonly failedItems: TestDataItem[] = []; - constructor( - @inject(IDisposableRegistry) disposableRegistry: IDisposableRegistry, - @inject(ICommandManager) private readonly commandManager: ICommandManager, - @inject(ITestCollectionStorageService) private readonly storage: ITestCollectionStorageService, - ) { - disposableRegistry.push(this); - } - public dispose() { - this.disposables.forEach((d) => d.dispose()); - } - public async activate(): Promise { - this.storage.onDidChange(this.onDidChangeTestData, this, this.disposables); - } - public onDidChangeTestData(args: { uri: Uri; data?: TestDataItem }): void { - if ( - args.data && - (args.data.status === TestStatus.Error || args.data.status === TestStatus.Fail) && - getTestDataItemType(args.data) === TestDataItemType.function - ) { - this.failedItems.push(args.data); - this.revealFailedNodes().ignoreErrors(); - } - } - - @debounceAsync(500) - private async revealFailedNodes(): Promise { - while (this.failedItems.length > 0) { - const item = this.failedItems.pop()!; - await this.commandManager.executeCommand(Commands.Test_Reveal_Test_Item, item); - } - } -} diff --git a/src/client/testing/explorer/testTreeViewItem.ts b/src/client/testing/explorer/testTreeViewItem.ts deleted file mode 100644 index 7ea83445fbb7..000000000000 --- a/src/client/testing/explorer/testTreeViewItem.ts +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri } from 'vscode'; -import { Commands } from '../../common/constants'; -import { getIcon } from '../../common/utils/icons'; -import { noop } from '../../common/utils/misc'; -import { Icons } from '../common/constants'; -import { getTestDataItemType, isSubtestsParent } from '../common/testUtils'; -import { TestDataItem, TestDataItemType, TestResult, TestStatus, TestSuite } from '../common/types'; - -function getDefaultCollapsibleState(data: TestDataItem): TreeItemCollapsibleState { - return getTestDataItemType(data) === TestDataItemType.function - ? TreeItemCollapsibleState.None - : TreeItemCollapsibleState.Collapsed; -} - -/** - * Class that represents a visual node on the - * Test Explorer tree view. Is essentially a wrapper for the underlying - * TestDataItem. - */ -export class TestTreeItem extends TreeItem { - public readonly testType: TestDataItemType; - - constructor( - public readonly resource: Uri, - public readonly data: Readonly, - collapsibleStatue: TreeItemCollapsibleState = getDefaultCollapsibleState(data), - ) { - super(data.name, collapsibleStatue); - this.testType = getTestDataItemType(this.data); - this.setCommand(); - } - - // @ts-ignore https://devblogs.microsoft.com/typescript/announcing-typescript-4-0-rc/#properties-overridding-accessors-and-vice-versa-is-an-error - public get contextValue(): string { - return this.testType; - } - - // @ts-ignore https://devblogs.microsoft.com/typescript/announcing-typescript-4-0-rc/#properties-overridding-accessors-and-vice-versa-is-an-error - public get iconPath(): string | Uri | { light: string | Uri; dark: string | Uri } | ThemeIcon { - if (this.testType === TestDataItemType.workspaceFolder) { - return ThemeIcon.Folder; - } - if (!this.data) { - return ''; - } - const status = this.data.status; - switch (status) { - case TestStatus.Error: - case TestStatus.Fail: { - return getIcon(Icons.failed); - } - case TestStatus.Pass: { - return getIcon(Icons.passed); - } - case TestStatus.Discovering: - case TestStatus.Running: { - return getIcon(Icons.discovering); - } - case TestStatus.Idle: - case TestStatus.Unknown: { - return getIcon(Icons.unknown); - } - default: { - return getIcon(Icons.unknown); - } - } - } - - // @ts-ignore https://devblogs.microsoft.com/typescript/announcing-typescript-4-0-rc/#properties-overridding-accessors-and-vice-versa-is-an-error - public get tooltip(): string { - if (!this.data || this.testType === TestDataItemType.workspaceFolder) { - return ''; - } - const result = this.data as TestResult; - if ( - !result.status || - result.status === TestStatus.Idle || - result.status === TestStatus.Unknown || - result.status === TestStatus.Skipped - ) { - return ''; - } - if (this.testType !== TestDataItemType.function) { - if (result.functionsPassed === undefined) { - return ''; - } - if (result.functionsDidNotRun) { - return `${result.functionsFailed} failed, ${result.functionsDidNotRun} not run and ${result.functionsPassed} passed`; - } - return `${result.functionsFailed} failed, ${result.functionsPassed} passed`; - } - switch (this.data.status) { - case TestStatus.Error: - case TestStatus.Fail: { - return `Failed in ${+result.time.toFixed(3)} seconds`; - } - case TestStatus.Pass: { - return `Passed in ${+result.time.toFixed(3)} seconds`; - } - case TestStatus.Discovering: - case TestStatus.Running: { - return 'Loading...'; - } - default: { - return ''; - } - } - } - - /** - * Tooltip for our tree nodes is the test status - */ - public get testStatus(): string { - return this.data.status ? this.data.status : TestStatus.Unknown; - } - - private setCommand() { - switch (this.testType) { - case TestDataItemType.file: { - this.command = { - command: Commands.navigateToTestFile, - title: 'Open', - arguments: [this.resource, this.data], - }; - break; - } - case TestDataItemType.function: { - this.command = { - command: Commands.navigateToTestFunction, - title: 'Open', - arguments: [this.resource, this.data, false], - }; - break; - } - case TestDataItemType.suite: { - if (isSubtestsParent(this.data as TestSuite)) { - this.command = { - command: Commands.navigateToTestFunction, - title: 'Open', - arguments: [this.resource, this.data, false], - }; - break; - } - this.command = { - command: Commands.navigateToTestSuite, - title: 'Open', - arguments: [this.resource, this.data, false], - }; - break; - } - default: { - noop(); - } - } - } -} diff --git a/src/client/testing/explorer/testTreeViewProvider.ts b/src/client/testing/explorer/testTreeViewProvider.ts deleted file mode 100644 index 15e430a65f4a..000000000000 --- a/src/client/testing/explorer/testTreeViewProvider.ts +++ /dev/null @@ -1,211 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { inject, injectable } from 'inversify'; -import { Event, EventEmitter, TreeItem, TreeItemCollapsibleState, Uri } from 'vscode'; -import { ICommandManager, IWorkspaceService } from '../../common/application/types'; -import { Commands, CommandSource } from '../../common/constants'; -import { IDisposable, IDisposableRegistry } from '../../common/types'; -import { sendTelemetryEvent } from '../../telemetry'; -import { EventName } from '../../telemetry/constants'; -import { getChildren, getParent, getTestDataItemType } from '../common/testUtils'; -import { - ITestCollectionStorageService, - ITestDataItemResource, - ITestManagementService, - ITestTreeViewProvider, - TestDataItem, - TestDataItemType, - Tests, - TestStatus, - TestWorkspaceFolder, - WorkspaceTestStatus, -} from '../common/types'; -import { TestTreeItem } from './testTreeViewItem'; - -@injectable() -export class TestTreeViewProvider implements ITestTreeViewProvider, ITestDataItemResource, IDisposable { - public readonly onDidChangeTreeData: Event; - public readonly discovered = new Set(); - public readonly testsAreBeingDiscovered: Map; - - private _onDidChangeTreeData = new EventEmitter(); - private disposables: IDisposable[] = []; - - constructor( - @inject(ITestCollectionStorageService) private testStore: ITestCollectionStorageService, - @inject(ITestManagementService) private testService: ITestManagementService, - @inject(IWorkspaceService) private readonly workspace: IWorkspaceService, - @inject(ICommandManager) private readonly commandManager: ICommandManager, - @inject(IDisposableRegistry) disposableRegistry: IDisposableRegistry, - ) { - this.onDidChangeTreeData = this._onDidChangeTreeData.event; - - disposableRegistry.push(this); - this.testsAreBeingDiscovered = new Map(); - this.disposables.push(this.testService.onDidStatusChange(this.onTestStatusChanged, this)); - this.testStore.onDidChange((e) => this._onDidChangeTreeData.fire(e.data), this, this.disposables); - this.workspace.onDidChangeWorkspaceFolders( - () => this._onDidChangeTreeData.fire(undefined), - this, - this.disposables, - ); - - if (Array.isArray(workspace.workspaceFolders) && workspace.workspaceFolders.length > 0) { - this.refresh(workspace.workspaceFolders[0].uri); - } - } - - /** - * We need a way to map a given TestDataItem to a Uri, so that other consumers (such - * as the commandHandler for the Test Explorer) have a way of accessing the Uri outside - * the purview off the TestTreeView. - * - * @param testData Test data item to map to a Uri - * @returns A Uri representing the workspace that the test data item exists within - */ - public getResource(testData: Readonly): Uri { - return testData.resource; - } - - /** - * As the TreeViewProvider itself is getting disposed, ensure all registered listeners are disposed - * from our internal emitter. - */ - public dispose() { - this.disposables.forEach((d) => d.dispose()); - this._onDidChangeTreeData.dispose(); - } - - /** - * Get [TreeItem](#TreeItem) representation of the `element` - * - * @param element The element for which [TreeItem](#TreeItem) representation is asked for. - * @return [TreeItem](#TreeItem) representation of the element - */ - public async getTreeItem(element: TestDataItem): Promise { - const defaultCollapsibleState = (await this.shouldElementBeExpandedByDefault(element)) - ? TreeItemCollapsibleState.Expanded - : undefined; - return new TestTreeItem(element.resource, element, defaultCollapsibleState); - } - - /** - * Get the children of `element` or root if no element is passed. - * - * @param element The element from which the provider gets children. Can be `undefined`. - * @return Children of `element` or root if no element is passed. - */ - public async getChildren(element?: TestDataItem): Promise { - if (element) { - if (element instanceof TestWorkspaceFolder) { - let tests = this.testStore.getTests(element.workspaceFolder.uri); - if (!tests && !this.discovered.has(element.workspaceFolder.uri.fsPath)) { - this.discovered.add(element.workspaceFolder.uri.fsPath); - await this.commandManager.executeCommand( - Commands.Tests_Discover, - element, - CommandSource.testExplorer, - undefined, - ); - tests = this.testStore.getTests(element.workspaceFolder.uri); - } - return this.getRootNodes(tests); - } - return getChildren(element); - } - - if (!Array.isArray(this.workspace.workspaceFolders) || this.workspace.workspaceFolders.length === 0) { - return []; - } - - sendTelemetryEvent(EventName.UNITTEST_EXPLORER_WORK_SPACE_COUNT, undefined, { - count: this.workspace.workspaceFolders.length, - }); - - // If we are in a single workspace - if (this.workspace.workspaceFolders.length === 1) { - const tests = this.testStore.getTests(this.workspace.workspaceFolders[0].uri); - return this.getRootNodes(tests); - } - - // If we are in a mult-root workspace, then nest the test data within a - // virtual node, represending the workspace folder. - return this.workspace.workspaceFolders.map((workspaceFolder) => new TestWorkspaceFolder(workspaceFolder)); - } - - /** - * Optional method to return the parent of `element`. - * Return `null` or `undefined` if `element` is a child of root. - * - * **NOTE:** This method should be implemented in order to access [reveal](#TreeView.reveal) API. - * - * @param element The element for which the parent has to be returned. - * @return Parent of `element`. - */ - public async getParent(element: TestDataItem): Promise { - if (element instanceof TestWorkspaceFolder) { - return; - } - const tests = this.testStore.getTests(element.resource); - return tests ? getParent(tests, element) : undefined; - } - /** - * If we have test files directly in root directory, return those. - * If we have test folders and no test files under the root directory, then just return the test directories. - * The goal is not avoid returning an empty root node, when all it contains are child nodes for folders. - * - * @param {Tests} [tests] - * @returns - * @memberof TestTreeViewProvider - */ - public getRootNodes(tests?: Tests) { - if (tests && tests.rootTestFolders && tests.rootTestFolders.length === 1) { - return [...tests.rootTestFolders[0].testFiles, ...tests.rootTestFolders[0].folders]; - } - return tests ? tests.rootTestFolders : []; - } - /** - * Refresh the view by rebuilding the model and signaling the tree view to update itself. - * - * @param resource The resource 'root' for this refresh to occur under. - */ - public refresh(resource: Uri): void { - const workspaceFolder = this.workspace.getWorkspaceFolder(resource); - if (!workspaceFolder) { - return; - } - const tests = this.testStore.getTests(resource); - if (tests && tests.testFolders) { - this._onDidChangeTreeData.fire(new TestWorkspaceFolder(workspaceFolder)); - } - } - - /** - * Event handler for TestStatusChanged (coming from the ITestManagementService). - * ThisThe TreeView needs to know when we begin discovery and when discovery completes. - * - * @param e The event payload containing context for the status change - */ - private onTestStatusChanged(e: WorkspaceTestStatus) { - if (e.status === TestStatus.Discovering) { - this.testsAreBeingDiscovered.set(e.workspace.fsPath, true); - return; - } - if (!this.testsAreBeingDiscovered.get(e.workspace.fsPath)) { - return; - } - this.testsAreBeingDiscovered.set(e.workspace.fsPath, false); - this.refresh(e.workspace); - } - - private async shouldElementBeExpandedByDefault(element: TestDataItem) { - const parent = await this.getParent(element); - if (!parent || getTestDataItemType(parent) === TestDataItemType.workspaceFolder) { - return true; - } - return false; - } -} diff --git a/src/client/testing/navigation/commandHandler.ts b/src/client/testing/navigation/commandHandler.ts deleted file mode 100644 index dec32de9d490..000000000000 --- a/src/client/testing/navigation/commandHandler.ts +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { inject, injectable, named } from 'inversify'; -import { ICommandManager } from '../../common/application/types'; -import { Commands } from '../../common/constants'; -import { IDisposable, IDisposableRegistry } from '../../common/types'; -import { ITestCodeNavigator, ITestCodeNavigatorCommandHandler, NavigableItemType } from './types'; - -@injectable() -export class TestCodeNavigatorCommandHandler implements ITestCodeNavigatorCommandHandler { - private disposables: IDisposable[] = []; - constructor( - @inject(ICommandManager) private readonly commandManager: ICommandManager, - @inject(ITestCodeNavigator) - @named(NavigableItemType.testFile) - private readonly testFileNavigator: ITestCodeNavigator, - @inject(ITestCodeNavigator) - @named(NavigableItemType.testFunction) - private readonly testFunctionNavigator: ITestCodeNavigator, - @inject(ITestCodeNavigator) - @named(NavigableItemType.testSuite) - private readonly testSuiteNavigator: ITestCodeNavigator, - @inject(IDisposableRegistry) disposableRegistry: IDisposableRegistry, - ) { - disposableRegistry.push(this); - } - public dispose() { - this.disposables.forEach((item) => item.dispose()); - } - public register(): void { - if (this.disposables.length > 0) { - return; - } - let disposable = this.commandManager.registerCommand( - Commands.navigateToTestFile, - this.testFileNavigator.navigateTo, - this.testFileNavigator, - ); - this.disposables.push(disposable); - disposable = this.commandManager.registerCommand( - Commands.navigateToTestFunction, - this.testFunctionNavigator.navigateTo, - this.testFunctionNavigator, - ); - this.disposables.push(disposable); - disposable = this.commandManager.registerCommand( - Commands.navigateToTestSuite, - this.testSuiteNavigator.navigateTo, - this.testSuiteNavigator, - ); - this.disposables.push(disposable); - } -} diff --git a/src/client/testing/navigation/fileNavigator.ts b/src/client/testing/navigation/fileNavigator.ts deleted file mode 100644 index 12f5ac69f8ab..000000000000 --- a/src/client/testing/navigation/fileNavigator.ts +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { inject, injectable } from 'inversify'; -import { Uri } from 'vscode'; -import { swallowExceptions } from '../../common/utils/decorators'; -import { captureTelemetry } from '../../telemetry'; -import { EventName } from '../../telemetry/constants'; -import { TestFile } from '../common/types'; -import { ITestCodeNavigator, ITestNavigatorHelper } from './types'; - -@injectable() -export class TestFileCodeNavigator implements ITestCodeNavigator { - constructor(@inject(ITestNavigatorHelper) private readonly helper: ITestNavigatorHelper) {} - @swallowExceptions('Navigate to test file') - @captureTelemetry(EventName.UNITTEST_NAVIGATE, { byFile: true }) - public async navigateTo(_: Uri, item: TestFile, __: boolean): Promise { - await this.helper.openFile(Uri.file(item.fullPath)); - } -} diff --git a/src/client/testing/navigation/functionNavigator.ts b/src/client/testing/navigation/functionNavigator.ts deleted file mode 100644 index 7968c5ee3dca..000000000000 --- a/src/client/testing/navigation/functionNavigator.ts +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { inject, injectable } from 'inversify'; -import { CancellationTokenSource, Range, SymbolInformation, SymbolKind, TextEditorRevealType, Uri } from 'vscode'; -import { IDocumentManager } from '../../common/application/types'; -import { traceError } from '../../common/logger'; -import { swallowExceptions } from '../../common/utils/decorators'; -import { captureTelemetry, sendTelemetryEvent } from '../../telemetry'; -import { EventName } from '../../telemetry/constants'; -import { ITestCollectionStorageService, TestFunction } from '../common/types'; -import { ITestCodeNavigator, ITestNavigatorHelper } from './types'; - -@injectable() -export class TestFunctionCodeNavigator implements ITestCodeNavigator { - private cancellationToken?: CancellationTokenSource; - constructor( - @inject(ITestNavigatorHelper) private readonly helper: ITestNavigatorHelper, - @inject(IDocumentManager) private readonly docManager: IDocumentManager, - @inject(ITestCollectionStorageService) private readonly storage: ITestCollectionStorageService, - ) {} - @swallowExceptions('Navigate to test function') - @captureTelemetry(EventName.UNITTEST_NAVIGATE, { byFunction: true }, true) // To measure execution time. - public async navigateTo(resource: Uri, fn: TestFunction, focus: boolean = true): Promise { - sendTelemetryEvent(EventName.UNITTEST_NAVIGATE, undefined, { focusCode: focus, byFunction: true }); - if (this.cancellationToken) { - this.cancellationToken.cancel(); - } - const item = this.storage.findFlattendTestFunction(resource, fn); - if (!item) { - throw new Error('Flattend test function not found'); - } - this.cancellationToken = new CancellationTokenSource(); - const [doc, editor] = await this.helper.openFile(Uri.file(item.parentTestFile.fullPath)); - let range: Range | undefined; - if (item.testFunction.line) { - range = new Range(item.testFunction.line, 0, item.testFunction.line, 0); - } else { - const predicate = (s: SymbolInformation) => - s.name === item.testFunction.name && (s.kind === SymbolKind.Method || s.kind === SymbolKind.Function); - const symbol = await this.helper.findSymbol(doc, predicate, this.cancellationToken.token); - range = symbol ? symbol.location.range : undefined; - } - if (!range) { - traceError('Unable to navigate to test function', new Error('Test Function not found')); - return; - } - if (focus) { - range = new Range(range.start.line, range.start.character, range.start.line, range.start.character); - await this.docManager.showTextDocument(doc, { preserveFocus: false, selection: range }); - } else { - editor.revealRange(range, TextEditorRevealType.Default); - } - } -} diff --git a/src/client/testing/navigation/helper.ts b/src/client/testing/navigation/helper.ts deleted file mode 100644 index 767bd53b1df9..000000000000 --- a/src/client/testing/navigation/helper.ts +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { inject, injectable, named } from 'inversify'; -import { CancellationToken, SymbolInformation, TextDocument, TextEditor, Uri } from 'vscode'; -import { IDocumentManager } from '../../common/application/types'; -import { traceError } from '../../common/logger'; -import { IDocumentSymbolProvider } from '../../common/types'; -import { ITestNavigatorHelper, SymbolSearch } from './types'; - -@injectable() -export class TestNavigatorHelper implements ITestNavigatorHelper { - constructor( - @inject(IDocumentManager) private readonly documentManager: IDocumentManager, - @inject(IDocumentSymbolProvider) @named('test') private readonly symbolProvider: IDocumentSymbolProvider, - ) {} - public async openFile(file?: Uri): Promise<[TextDocument, TextEditor]> { - if (!file) { - throw new Error('Unable to navigate to an undefined test file'); - } - const doc = await this.documentManager.openTextDocument(file); - const editor = await this.documentManager.showTextDocument(doc); - return [doc, editor]; - } - public async findSymbol( - doc: TextDocument, - search: SymbolSearch, - token: CancellationToken, - ): Promise { - const symbols = (await this.symbolProvider.provideDocumentSymbols(doc, token)) as SymbolInformation[]; - if (!Array.isArray(symbols) || symbols.length === 0) { - traceError('Symbol information not found', new Error('Symbol information not found')); - return; - } - return symbols.find(search); - } -} diff --git a/src/client/testing/navigation/serviceRegistry.ts b/src/client/testing/navigation/serviceRegistry.ts deleted file mode 100644 index e1a1194ec94f..000000000000 --- a/src/client/testing/navigation/serviceRegistry.ts +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { IDocumentSymbolProvider } from '../../common/types'; -import { IServiceManager } from '../../ioc/types'; -import { TestCodeNavigatorCommandHandler } from './commandHandler'; -import { TestFileCodeNavigator } from './fileNavigator'; -import { TestFunctionCodeNavigator } from './functionNavigator'; -import { TestNavigatorHelper } from './helper'; -import { TestSuiteCodeNavigator } from './suiteNavigator'; -import { TestFileSymbolProvider } from './symbolProvider'; -import { ITestCodeNavigator, ITestCodeNavigatorCommandHandler, ITestNavigatorHelper, NavigableItemType } from './types'; - -export function registerTypes(serviceManager: IServiceManager) { - serviceManager.addSingleton(ITestNavigatorHelper, TestNavigatorHelper); - serviceManager.addSingleton( - ITestCodeNavigatorCommandHandler, - TestCodeNavigatorCommandHandler, - ); - serviceManager.addSingleton( - ITestCodeNavigator, - TestFileCodeNavigator, - NavigableItemType.testFile, - ); - serviceManager.addSingleton( - ITestCodeNavigator, - TestFunctionCodeNavigator, - NavigableItemType.testFunction, - ); - serviceManager.addSingleton( - ITestCodeNavigator, - TestSuiteCodeNavigator, - NavigableItemType.testSuite, - ); - serviceManager.addSingleton(IDocumentSymbolProvider, TestFileSymbolProvider, 'test'); -} diff --git a/src/client/testing/navigation/suiteNavigator.ts b/src/client/testing/navigation/suiteNavigator.ts deleted file mode 100644 index a5e0e596a678..000000000000 --- a/src/client/testing/navigation/suiteNavigator.ts +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { inject, injectable } from 'inversify'; -import { CancellationTokenSource, Range, SymbolInformation, SymbolKind, TextEditorRevealType, Uri } from 'vscode'; -import { IDocumentManager } from '../../common/application/types'; -import { traceError } from '../../common/logger'; -import { swallowExceptions } from '../../common/utils/decorators'; -import { captureTelemetry, sendTelemetryEvent } from '../../telemetry'; -import { EventName } from '../../telemetry/constants'; -import { ITestCollectionStorageService, TestSuite } from '../common/types'; -import { ITestCodeNavigator, ITestNavigatorHelper } from './types'; - -@injectable() -export class TestSuiteCodeNavigator implements ITestCodeNavigator { - private cancellationToken?: CancellationTokenSource; - constructor( - @inject(ITestNavigatorHelper) private readonly helper: ITestNavigatorHelper, - @inject(IDocumentManager) private readonly docManager: IDocumentManager, - @inject(ITestCollectionStorageService) private readonly storage: ITestCollectionStorageService, - ) {} - @swallowExceptions('Navigate to test suite') - @captureTelemetry(EventName.UNITTEST_NAVIGATE, { bySuite: true }, true) // For measuring execution time. - public async navigateTo(resource: Uri, suite: TestSuite, focus: boolean = true): Promise { - sendTelemetryEvent(EventName.UNITTEST_NAVIGATE, undefined, { focusCode: focus, bySuite: true }); - if (this.cancellationToken) { - this.cancellationToken.cancel(); - } - const item = this.storage.findFlattendTestSuite(resource, suite); - if (!item) { - throw new Error('Flattened test suite not found'); - } - this.cancellationToken = new CancellationTokenSource(); - const [doc, editor] = await this.helper.openFile(Uri.file(item.parentTestFile.fullPath)); - let range: Range | undefined; - if (item.testSuite.line) { - range = new Range(item.testSuite.line, 0, item.testSuite.line, 0); - } else { - const predicate = (s: SymbolInformation) => s.name === item.testSuite.name && s.kind === SymbolKind.Class; - const symbol = await this.helper.findSymbol(doc, predicate, this.cancellationToken.token); - range = symbol ? symbol.location.range : undefined; - } - if (!range) { - traceError('Unable to navigate to test suite', new Error('Test Suite not found')); - return; - } - if (focus) { - range = new Range(range.start.line, range.start.character, range.start.line, range.start.character); - await this.docManager.showTextDocument(doc, { preserveFocus: false, selection: range }); - } else { - editor.revealRange(range, TextEditorRevealType.Default); - } - } -} diff --git a/src/client/testing/navigation/types.ts b/src/client/testing/navigation/types.ts deleted file mode 100644 index decc8d0a3d93..000000000000 --- a/src/client/testing/navigation/types.ts +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { CancellationToken, SymbolInformation, TextDocument, TextEditor, Uri } from 'vscode'; -import { IDisposable } from '../../common/types'; -import { TestFile, TestFunction, TestSuite } from '../common/types'; - -export const ITestCodeNavigatorCommandHandler = Symbol('ITestCodeNavigatorCommandHandler'); -export interface ITestCodeNavigatorCommandHandler extends IDisposable { - register(): void; -} -type NavigableItem = TestFile | TestFunction | TestSuite; -export enum NavigableItemType { - testFile = 'testFile', - testFunction = 'testFunction', - testSuite = 'testSuite', -} - -export const ITestCodeNavigator = Symbol('ITestCodeNavigator'); -export interface ITestCodeNavigator { - navigateTo(resource: Uri, item: NavigableItem, focus: boolean): Promise; -} - -export const ITestNavigatorHelper = Symbol('ITestNavigatorHelper'); -export interface ITestNavigatorHelper { - openFile(file?: Uri): Promise<[TextDocument, TextEditor]>; - findSymbol( - doc: TextDocument, - predicate: SymbolSearch, - token: CancellationToken, - ): Promise; -} -export type SymbolSearch = (item: SymbolInformation) => boolean; - -export const ITestExplorerCommandHandler = Symbol('ITestExplorerCommandHandler'); -export interface ITestExplorerCommandHandler extends IDisposable { - register(): void; -} diff --git a/src/client/testing/serviceRegistry.ts b/src/client/testing/serviceRegistry.ts index 3250d79605ed..c1334e9d0ed2 100644 --- a/src/client/testing/serviceRegistry.ts +++ b/src/client/testing/serviceRegistry.ts @@ -31,7 +31,6 @@ import { ITestConfigurationManagerFactory, ITestConfigurationService, ITestContextService, - ITestDataItemResource, ITestDebugLauncher, ITestDiagnosticService, ITestDiscoveryService, @@ -49,7 +48,6 @@ import { ITestsHelper, ITestsParser, ITestsStatusUpdaterService, - ITestTreeViewProvider, ITestVisitor, IUnitTestHelper, IUnitTestSocketServer, @@ -62,12 +60,7 @@ import { UnitTestConfigurationService } from './configuration'; import { TestConfigurationManagerFactory } from './configurationFactory'; import { TestResultDisplay } from './display/main'; import { TestDisplay } from './display/picker'; -import { TestExplorerCommandHandler } from './explorer/commandHandlers'; -import { FailedTestHandler } from './explorer/failedTestHandler'; -import { TestTreeViewProvider } from './explorer/testTreeViewProvider'; import { TestingService, UnitTestManagementService } from './main'; -import { registerTypes as registerNavigationTypes } from './navigation/serviceRegistry'; -import { ITestExplorerCommandHandler } from './navigation/types'; import { TestManager as PyTestTestManager } from './pytest/main'; import { TestManagerRunner as PytestManagerRunner } from './pytest/runner'; import { ArgumentsService as PyTestArgumentsService } from './pytest/services/argsService'; @@ -83,7 +76,6 @@ import { TestsParser as UnitTestTestsParser } from './unittest/services/parserSe import { UnitTestSocketServer } from './unittest/socketServer'; export function registerTypes(serviceManager: IServiceManager) { - registerNavigationTypes(serviceManager); serviceManager.addSingleton(ITestDebugLauncher, DebugLauncher); serviceManager.addSingleton( ITestCollectionStorageService, @@ -135,13 +127,6 @@ export function registerTypes(serviceManager: IServiceManager) { serviceManager.addSingleton(ITestDiagnosticService, UnitTestDiagnosticService); serviceManager.addSingleton(ITestMessageService, TestMessageService, PYTEST_PROVIDER); - serviceManager.addSingleton(ITestTreeViewProvider, TestTreeViewProvider); - serviceManager.addSingleton(ITestDataItemResource, TestTreeViewProvider); - serviceManager.addSingleton(ITestExplorerCommandHandler, TestExplorerCommandHandler); - serviceManager.addSingleton( - IExtensionSingleActivationService, - FailedTestHandler, - ); serviceManager.addSingleton( IExtensionSingleActivationService, EnablementTracker, diff --git a/src/test/testing/explorer/explorerTestData.ts b/src/test/testing/explorer/explorerTestData.ts deleted file mode 100644 index 7e47f0dcce2e..000000000000 --- a/src/test/testing/explorer/explorerTestData.ts +++ /dev/null @@ -1,256 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -/** - * Test utilities for testing the TestViewTreeProvider class. - */ - -import { join, parse as path_parse } from 'path'; -import * as tsmockito from 'ts-mockito'; -import * as typemoq from 'typemoq'; -import { Uri, WorkspaceFolder } from 'vscode'; -import { CommandManager } from '../../../client/common/application/commandManager'; -import { IApplicationShell, ICommandManager, IWorkspaceService } from '../../../client/common/application/types'; -import { IDisposable, IDisposableRegistry } from '../../../client/common/types'; -import { IServiceContainer } from '../../../client/ioc/types'; -import { TestsHelper } from '../../../client/testing/common/testUtils'; -import { TestFlatteningVisitor } from '../../../client/testing/common/testVisitors/flatteningVisitor'; -import { - ITestCollectionStorageService, - TestFile, - TestFolder, - TestFunction, - ITestManagementService, - Tests, - TestSuite, -} from '../../../client/testing/common/types'; -import { TestTreeViewProvider } from '../../../client/testing/explorer/testTreeViewProvider'; - -/** - * Disposable class that doesn't do anything, help for event-registration against - * ITestManagementService. - */ -export class ExplorerTestsDisposable implements IDisposable { - public dispose() {} -} - -export function getMockTestFolder(folderPath: string, testFiles: TestFile[] = []): TestFolder { - const folder: TestFolder = { - resource: Uri.file(__filename), - folders: [], - name: folderPath, - nameToRun: folderPath, - testFiles: testFiles, - time: 0, - }; - - return folder; -} - -export function getMockTestFile( - filePath: string, - testSuites: TestSuite[] = [], - testFunctions: TestFunction[] = [], -): TestFile { - const testFile: TestFile = { - resource: Uri.file(__filename), - name: path_parse(filePath).base, - nameToRun: filePath, - time: 0, - fullPath: join(__dirname, filePath), - functions: testFunctions, - suites: testSuites, - xmlName: filePath.replace(/\//g, '.'), - }; - - return testFile; -} - -export function getMockTestSuite( - suiteNameToRun: string, - testFunctions: TestFunction[] = [], - subSuites: TestSuite[] = [], - instance: boolean = true, - unitTest: boolean = true, -): TestSuite { - const suiteNameChunks = suiteNameToRun.split('::'); - const suiteName = suiteNameChunks[suiteNameChunks.length - 1]; - - const testSuite: TestSuite = { - resource: Uri.file(__filename), - functions: testFunctions, - isInstance: instance, - isUnitTest: unitTest, - name: suiteName, - nameToRun: suiteNameToRun, - suites: subSuites, - time: 0, - xmlName: suiteNameToRun.replace(/\//g, '.').replace(/\:\:/g, ':'), - }; - return testSuite; -} - -export function getMockTestFunction(fnNameToRun: string): TestFunction { - const fnNameChunks = fnNameToRun.split('::'); - const fnName = fnNameChunks[fnNameChunks.length - 1]; - - const fn: TestFunction = { - resource: Uri.file(__filename), - name: fnName, - nameToRun: fnNameToRun, - time: 0, - }; - - return fn; -} - -/** - * Return a basic hierarchy of test data items for use in testing. - * - * @returns Array containing the items broken out from the hierarchy (all items are linked to one another) - */ -export function getTestExplorerViewItemData(): [TestFolder, TestFile, TestFunction, TestSuite, TestFunction] { - let testFolder: TestFolder; - let testFile: TestFile; - let testSuite: TestSuite; - let testFunction: TestFunction; - let testSuiteFunction: TestFunction; - - testSuiteFunction = getMockTestFunction('workspace/test_folder/test_file.py::test_suite::test_suite_function'); - testSuite = getMockTestSuite('workspace/test_folder/test_file.py::test_suite', [testSuiteFunction]); - testFunction = getMockTestFunction('workspace/test_folder/test_file.py::test_function'); - testFile = getMockTestFile('workspace/test_folder/test_file.py', [testSuite], [testFunction]); - testFolder = getMockTestFolder('workspace/test_folder', [testFile]); - - return [testFolder, testFile, testFunction, testSuite, testSuiteFunction]; -} - -/** - * Return an instance of `TestsHelper` that can be used in a unit test scenario. - * - * @returns An instance of `TestsHelper` class with mocked AppShell & ICommandManager members. - */ -export function getTestHelperInstance(): TestsHelper { - const appShellMoq = typemoq.Mock.ofType(); - const commMgrMoq = typemoq.Mock.ofType(); - const serviceContainerMoq = typemoq.Mock.ofType(); - - serviceContainerMoq - .setup((a) => a.get(typemoq.It.isValue(IApplicationShell), typemoq.It.isAny())) - .returns(() => appShellMoq.object); - serviceContainerMoq - .setup((a) => a.get(typemoq.It.isValue(ICommandManager), typemoq.It.isAny())) - .returns(() => commMgrMoq.object); - - return new TestsHelper(new TestFlatteningVisitor(), serviceContainerMoq.object); -} - -/** - * Creates mock `Tests` data suitable for testing the TestTreeViewProvider with. - */ -export function createMockTestsData(testData?: TestFile[]): Tests { - if (testData === undefined) { - let testFile: TestFile; - - [, testFile] = getTestExplorerViewItemData(); - - testData = [testFile]; - } - - const testHelper = getTestHelperInstance(); - return testHelper.flattenTestFiles(testData, __dirname); -} - -export function createMockTestStorageService(testData?: Tests): typemoq.IMock { - const testStoreMoq = typemoq.Mock.ofType(); - - if (!testData) { - testData = createMockTestsData(); - } - - testStoreMoq.setup((t) => t.getTests(typemoq.It.isAny())).returns(() => testData); - - return testStoreMoq; -} - -/** - * Create an ITestManagementService that will work for the TeestTreeViewProvider in a unit test scenario. - * - * Provider an 'onDidStatusChange' hook that can be called, but that does nothing. - */ -export function createMockUnitTestMgmtService(): typemoq.IMock { - const unitTestMgmtSrvMoq = typemoq.Mock.ofType(); - unitTestMgmtSrvMoq - .setup((u) => u.onDidStatusChange(typemoq.It.isAny())) - .returns(() => new ExplorerTestsDisposable()); - return unitTestMgmtSrvMoq; -} - -/** - * Create an IWorkspaceService mock that will work with the TestTreeViewProvider class. - * - * @param workspaceFolderPath Optional, the path to use as the current Resource-path for - * the tests within the TestTree. - */ -export function createMockWorkspaceService(): typemoq.IMock { - const workspcSrvMoq = typemoq.Mock.ofType(); - class ExplorerTestsWorkspaceFolder implements WorkspaceFolder { - public get uri(): Uri { - return Uri.parse(''); - } - public get name(): string { - return path_parse(this.uri.fsPath).base; - } - public get index(): number { - return 0; - } - } - workspcSrvMoq.setup((w) => w.workspaceFolders).returns(() => [new ExplorerTestsWorkspaceFolder()]); - return workspcSrvMoq; -} - -/** - * Create a testable mocked up version of the TestExplorerViewProvider. Creates any - * mocked dependencies not provided in the parameters. - * - * @param {ITestCollectionStorageService} [testStore] Test storage service, provides access to the Tests structure that the view is built from. - * @param {Tests} [testsData] - * @param {ITestManagementService} [unitTestMgmtService] Unit test management service that provides the 'onTestStatusUpdated' event. - * @param {IWorkspaceService} [workspaceService] Workspace service used to determine the current workspace that the test view is showing. - * @param {ICommandManager} [commandManager] - */ -export function createMockTestExplorer( - testStore?: ITestCollectionStorageService, - testsData?: Tests, - unitTestMgmtService?: ITestManagementService, - workspaceService?: IWorkspaceService, - commandManager?: ICommandManager, -): TestTreeViewProvider { - if (!testStore) { - testStore = createMockTestStorageService(testsData).object; - } - - if (!unitTestMgmtService) { - unitTestMgmtService = createMockUnitTestMgmtService().object; - } - - if (!workspaceService) { - workspaceService = createMockWorkspaceService().object; - } - if (!commandManager) { - commandManager = tsmockito.instance(tsmockito.mock(CommandManager)); - } - - const dispRegMoq = typemoq.Mock.ofType(); - dispRegMoq.setup((d) => d.push(typemoq.It.isAny())); - - return new TestTreeViewProvider( - testStore, - unitTestMgmtService, - workspaceService, - commandManager, - dispRegMoq.object, - ); -} diff --git a/src/test/testing/explorer/failedTestHandler.unit.test.ts b/src/test/testing/explorer/failedTestHandler.unit.test.ts deleted file mode 100644 index c4bbacaf972d..000000000000 --- a/src/test/testing/explorer/failedTestHandler.unit.test.ts +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { anything, instance, mock, verify, when } from 'ts-mockito'; -import { Uri } from 'vscode'; -import { CommandManager } from '../../../client/common/application/commandManager'; -import { ICommandManager } from '../../../client/common/application/types'; -import { Commands } from '../../../client/common/constants'; -import { TestCollectionStorageService } from '../../../client/testing/common/services/storageService'; -import { - ITestCollectionStorageService, - TestFile, - TestFolder, - TestFunction, - TestStatus, - TestSuite, -} from '../../../client/testing/common/types'; -import { FailedTestHandler } from '../../../client/testing/explorer/failedTestHandler'; -import { noop, sleep } from '../../core'; - -suite('Unit Tests Test Explorer View Items', () => { - let failedTestHandler: FailedTestHandler; - let commandManager: ICommandManager; - let testStorageService: ITestCollectionStorageService; - setup(() => { - commandManager = mock(CommandManager); - testStorageService = mock(TestCollectionStorageService); - failedTestHandler = new FailedTestHandler([], instance(commandManager), instance(testStorageService)); - }); - - test('Activation will add command handlers', async () => { - when(testStorageService.onDidChange).thenReturn(noop as any); - - await failedTestHandler.activate(); - - verify(testStorageService.onDidChange).once(); - }); - test('Change handler will invoke the command to reveal the nodes (for failed and errored items)', async () => { - const uri = Uri.file(__filename); - const failedFunc1: TestFunction = { - name: 'fn1', - time: 0, - resource: uri, - nameToRun: 'fn1', - status: TestStatus.Error, - }; - const failedFunc2: TestFunction = { - name: 'fn2', - time: 0, - resource: uri, - nameToRun: 'fn2', - status: TestStatus.Fail, - }; - when(commandManager.executeCommand(Commands.Test_Reveal_Test_Item, anything())).thenResolve(); - - failedTestHandler.onDidChangeTestData({ uri, data: failedFunc1 }); - failedTestHandler.onDidChangeTestData({ uri, data: failedFunc2 }); - - // wait for debouncing to take effect. - await sleep(1); - - verify(commandManager.executeCommand(Commands.Test_Reveal_Test_Item, anything())).times(2); - verify(commandManager.executeCommand(Commands.Test_Reveal_Test_Item, failedFunc1)).once(); - verify(commandManager.executeCommand(Commands.Test_Reveal_Test_Item, failedFunc2)).once(); - }); - test('Change handler will not invoke the command to reveal the nodes (for failed and errored suites, files & folders)', async () => { - const uri = Uri.file(__filename); - const failedSuite: TestSuite = { - name: 'suite1', - time: 0, - resource: uri, - nameToRun: 'suite1', - functions: [], - isInstance: false, - isUnitTest: false, - suites: [], - xmlName: 'suite1', - status: TestStatus.Error, - }; - const failedFile: TestFile = { - name: 'suite1', - time: 0, - resource: uri, - nameToRun: 'file', - functions: [], - suites: [], - xmlName: 'file', - status: TestStatus.Error, - fullPath: '', - }; - const failedFolder: TestFolder = { - name: 'suite1', - time: 0, - resource: uri, - nameToRun: 'file', - testFiles: [], - folders: [], - status: TestStatus.Error, - }; - when(commandManager.executeCommand(Commands.Test_Reveal_Test_Item, anything())).thenResolve(); - - failedTestHandler.onDidChangeTestData({ uri, data: failedSuite }); - failedTestHandler.onDidChangeTestData({ uri, data: failedFile }); - failedTestHandler.onDidChangeTestData({ uri, data: failedFolder }); - - // wait for debouncing to take effect. - await sleep(1); - - verify(commandManager.executeCommand(Commands.Test_Reveal_Test_Item, anything())).never(); - }); -}); diff --git a/src/test/testing/explorer/testExplorerCommandHandler.unit.test.ts b/src/test/testing/explorer/testExplorerCommandHandler.unit.test.ts deleted file mode 100644 index ffe1d5c46185..000000000000 --- a/src/test/testing/explorer/testExplorerCommandHandler.unit.test.ts +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { anything, capture, deepEqual, instance, mock, verify, when } from 'ts-mockito'; -import * as typemoq from 'typemoq'; -import { Uri } from 'vscode'; -import { CommandManager } from '../../../client/common/application/commandManager'; -import { ICommandManager } from '../../../client/common/application/types'; -import { Commands, CommandSource } from '../../../client/common/constants'; -import { IDisposable } from '../../../client/common/types'; -import { - ITestDataItemResource, - TestFile, - TestFunction, - TestsToRun, - TestSuite, -} from '../../../client/testing/common/types'; -import { TestExplorerCommandHandler } from '../../../client/testing/explorer/commandHandlers'; -import { TestTreeViewProvider } from '../../../client/testing/explorer/testTreeViewProvider'; -import { ITestExplorerCommandHandler } from '../../../client/testing/navigation/types'; - -suite('Unit Tests - Test Explorer Command Handler', () => { - let commandHandler: ITestExplorerCommandHandler; - let cmdManager: ICommandManager; - let testResourceMapper: ITestDataItemResource; - - setup(() => { - cmdManager = mock(CommandManager); - testResourceMapper = mock(TestTreeViewProvider); - commandHandler = new TestExplorerCommandHandler(instance(cmdManager), instance(testResourceMapper)); - }); - test('Commands are registered', () => { - commandHandler.register(); - - verify(cmdManager.registerCommand(Commands.runTestNode, anything(), commandHandler)).once(); - verify(cmdManager.registerCommand(Commands.debugTestNode, anything(), commandHandler)).once(); - verify(cmdManager.registerCommand(Commands.openTestNodeInEditor, anything(), commandHandler)).once(); - }); - test('Handlers are disposed', () => { - const disposable1 = typemoq.Mock.ofType(); - const disposable2 = typemoq.Mock.ofType(); - const disposable3 = typemoq.Mock.ofType(); - - when(cmdManager.registerCommand(Commands.runTestNode, anything(), commandHandler)).thenReturn( - disposable1.object, - ); - when(cmdManager.registerCommand(Commands.debugTestNode, anything(), commandHandler)).thenReturn( - disposable2.object, - ); - when(cmdManager.registerCommand(Commands.openTestNodeInEditor, anything(), commandHandler)).thenReturn( - disposable3.object, - ); - - commandHandler.register(); - commandHandler.dispose(); - - disposable1.verify((d) => d.dispose(), typemoq.Times.once()); - disposable2.verify((d) => d.dispose(), typemoq.Times.once()); - disposable3.verify((d) => d.dispose(), typemoq.Times.once()); - }); - async function testOpeningTestNode( - data: TestFile | TestSuite | TestFunction, - expectedCommand: 'navigateToTestFunction' | 'navigateToTestSuite' | 'navigateToTestFile', - ) { - const resource = Uri.file(__filename); - when(testResourceMapper.getResource(data)).thenReturn(resource); - - commandHandler.register(); - - const handler = (capture(cmdManager.registerCommand as any).last()[1] as any) as Function; - await handler.bind(commandHandler)(data); - - verify(cmdManager.executeCommand(expectedCommand, resource, data, true)).once(); - } - test('Opening a file will invoke correct command', async () => { - const testFilePath = 'some file path'; - const data: TestFile = { fullPath: testFilePath } as any; - await testOpeningTestNode(data, Commands.navigateToTestFile); - }); - test('Opening a test suite will invoke correct command', async () => { - const data: TestSuite = { suites: [] } as any; - await testOpeningTestNode(data, Commands.navigateToTestSuite); - }); - test('Opening a test function will invoke correct command', async () => { - const data: TestFunction = { name: 'hello' } as any; - await testOpeningTestNode(data, Commands.navigateToTestFunction); - }); - async function testRunOrDebugTestNode( - data: TestFile | TestSuite | TestFunction, - expectedTestRun: TestsToRun, - runType: 'run' | 'debug', - ) { - const resource = Uri.file(__filename); - when(testResourceMapper.getResource(data)).thenReturn(resource); - - commandHandler.register(); - - const capturedCommand = capture(cmdManager.registerCommand as any); - const handler = ((runType === 'run' - ? capturedCommand.first()[1] - : capturedCommand.second()[1]) as any) as Function; - await handler.bind(commandHandler)(data); - - const cmd = runType === 'run' ? Commands.Tests_Run : Commands.Tests_Debug; - verify( - cmdManager.executeCommand(cmd, undefined, CommandSource.testExplorer, resource, deepEqual(expectedTestRun)), - ).once(); - } - test('Running a file will invoke correct command', async () => { - const testFilePath = 'some file path'; - const data: TestFile = { fullPath: testFilePath } as any; - await testRunOrDebugTestNode(data, { testFile: [data] }, 'run'); - }); - test('Running a suite will invoke correct command', async () => { - const data: TestSuite = { suites: [] } as any; - await testRunOrDebugTestNode(data, { testSuite: [data] }, 'run'); - }); - test('Running a function will invoke correct command', async () => { - const data: TestSuite = { suites: [] } as any; - await testRunOrDebugTestNode(data, { testSuite: [data] }, 'run'); - }); - test('Debugging a file will invoke correct command', async () => { - const testFilePath = 'some file path'; - const data: TestFile = { fullPath: testFilePath } as any; - await testRunOrDebugTestNode(data, { testFile: [data] }, 'debug'); - }); - test('Debugging a suite will invoke correct command', async () => { - const data: TestSuite = { suites: [] } as any; - await testRunOrDebugTestNode(data, { testSuite: [data] }, 'debug'); - }); - test('Debugging a function will invoke correct command', async () => { - const data: TestSuite = { suites: [] } as any; - await testRunOrDebugTestNode(data, { testSuite: [data] }, 'debug'); - }); -}); diff --git a/src/test/testing/explorer/testTreeViewItem.unit.test.ts b/src/test/testing/explorer/testTreeViewItem.unit.test.ts deleted file mode 100644 index 7a31114c51f9..000000000000 --- a/src/test/testing/explorer/testTreeViewItem.unit.test.ts +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { expect } from 'chai'; -import { Uri } from 'vscode'; -import { Commands } from '../../../client/common/constants'; -import { TestDataItemType, TestFile, TestFolder, TestFunction, TestSuite } from '../../../client/testing/common/types'; -import { TestTreeItem } from '../../../client/testing/explorer/testTreeViewItem'; -import { createMockTestDataItem, createSubtestParent } from '../common/testUtils.unit.test'; -import { getTestExplorerViewItemData } from './explorerTestData'; - -suite('Unit Tests Test Explorer View Items', () => { - let testFolder: TestFolder; - let testFile: TestFile; - let testSuite: TestSuite; - let testFunction: TestFunction; - let testSuiteFunction: TestFunction; - const resource = Uri.file(__filename); - setup(() => { - [testFolder, testFile, testFunction, testSuite, testSuiteFunction] = getTestExplorerViewItemData(); - }); - - test('Test root folder created into test view item', () => { - const viewItem = new TestTreeItem(resource, testFolder); - expect(viewItem.contextValue).is.equal('folder'); - }); - - test('Test file created into test view item', () => { - const viewItem = new TestTreeItem(resource, testFile); - expect(viewItem.contextValue).is.equal('file'); - }); - - test('Test suite created into test view item', () => { - const viewItem = new TestTreeItem(resource, testSuite); - expect(viewItem.contextValue).is.equal('suite'); - }); - - test('Test function created into test view item', () => { - const viewItem = new TestTreeItem(resource, testFunction); - expect(viewItem.contextValue).is.equal('function'); - }); - - test('Test suite function created into test view item', () => { - const viewItem = new TestTreeItem(resource, testSuiteFunction); - expect(viewItem.contextValue).is.equal('function'); - }); - - test('Test subtest parent created into test view item', () => { - const subtestParent = createSubtestParent([ - createMockTestDataItem(TestDataItemType.function, 'test_x'), - createMockTestDataItem(TestDataItemType.function, 'test_y'), - ]); - - const viewItem = new TestTreeItem(resource, subtestParent.asSuite); - - expect(viewItem.contextValue).is.equal('suite'); - expect(viewItem.command!.command).is.equal(Commands.navigateToTestFunction); - }); - - test('Test subtest created into test view item', () => { - createSubtestParent([testFunction]); // sets testFunction.subtestParent - - const viewItem = new TestTreeItem(resource, testFunction); - - expect(viewItem.contextValue).is.equal('function'); - }); -}); diff --git a/src/test/testing/explorer/testTreeViewProvider.unit.test.ts b/src/test/testing/explorer/testTreeViewProvider.unit.test.ts deleted file mode 100644 index c1d3f6b365e1..000000000000 --- a/src/test/testing/explorer/testTreeViewProvider.unit.test.ts +++ /dev/null @@ -1,993 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { expect } from 'chai'; -import * as path from 'path'; -import { instance, mock, verify, when } from 'ts-mockito'; -import * as typemoq from 'typemoq'; -import { TreeItemCollapsibleState, Uri } from 'vscode'; -import { CommandManager } from '../../../client/common/application/commandManager'; -import { WorkspaceService } from '../../../client/common/application/workspace'; -import { Commands, CommandSource } from '../../../client/common/constants'; -import { IDisposable } from '../../../client/common/types'; -import { TestCollectionStorageService } from '../../../client/testing/common/services/storageService'; -import { getTestDataItemType } from '../../../client/testing/common/testUtils'; -import { - ITestCollectionStorageService, - TestDataItem, - TestDataItemType, - TestFile, - TestFolder, - Tests, - TestStatus, - TestWorkspaceFolder, -} from '../../../client/testing/common/types'; -import { TestTreeItem } from '../../../client/testing/explorer/testTreeViewItem'; -import { TestTreeViewProvider } from '../../../client/testing/explorer/testTreeViewProvider'; -import { UnitTestManagementService } from '../../../client/testing/main'; -import { noop } from '../../core'; -import { - createMockTestExplorer as createMockTestTreeProvider, - createMockTestsData, - getMockTestFile, - getMockTestFolder, - getMockTestFunction, - getMockTestSuite, -} from './explorerTestData'; - -/** - * Class that is useful to track any Tree View update requests made by the view provider. - */ -class TestExplorerCaptureRefresh implements IDisposable { - public refreshCount: number = 0; // this counts the number of times 'onDidChangeTreeData' is emitted. - - private disposable: IDisposable; - - constructor(private testViewProvider: TestTreeViewProvider, disposableContainer: IDisposable[]) { - this.disposable = this.testViewProvider.onDidChangeTreeData(this.onRefreshOcured.bind(this)); - disposableContainer.push(this); - } - - public dispose() { - this.disposable.dispose(); - } - - private onRefreshOcured(_testDataItem?: TestDataItem): void { - this.refreshCount = this.refreshCount + 1; - } -} - -suite('Unit Tests Test Explorer TestTreeViewProvider', () => { - suite('Misc', () => { - const testResource: Uri = Uri.parse('anything'); - let disposables: IDisposable[] = []; - - teardown(() => { - disposables.forEach((disposableItem: IDisposable) => { - disposableItem.dispose(); - }); - disposables = []; - }); - - test('Create the initial view and ensure it provides a default view', async () => { - const testTreeProvider = createMockTestTreeProvider(); - expect(testTreeProvider).is.not.equal( - undefined, - 'Could not create a mock test explorer, check the parameters of the test setup.', - ); - const treeRoot = await testTreeProvider.getChildren(); - expect(treeRoot.length).to.be.greaterThan( - 0, - 'No children returned from default view of the TreeViewProvider.', - ); - }); - - test('Ensure that updates from the test manager propagate to the TestExplorer', async () => { - const testsData = createMockTestsData(); - const workspaceService = mock(WorkspaceService); - const testStore = mock(TestCollectionStorageService); - const workspaceFolder = { uri: Uri.file(''), name: 'root', index: 0 }; - when(workspaceService.getWorkspaceFolder(testResource)).thenReturn(workspaceFolder); - when(workspaceService.onDidChangeWorkspaceFolders).thenReturn(noop as any); - when(testStore.getTests(testResource)).thenReturn(testsData); - when(testStore.onDidChange).thenReturn(noop as any); - const changeItem = testsData.testFolders[1].testFiles[0].functions[0]; - const testTreeProvider = createMockTestTreeProvider( - instance(testStore), - testsData, - undefined, - instance(workspaceService), - ); - const refreshCap = new TestExplorerCaptureRefresh(testTreeProvider, disposables); - - testTreeProvider.refresh(testResource); - const originalTreeItem = (await testTreeProvider.getTreeItem(changeItem)) as TestTreeItem; - const origStatus = originalTreeItem.testStatus; - - changeItem.status = TestStatus.Fail; - testTreeProvider.refresh(testResource); - const changedTreeItem = (await testTreeProvider.getTreeItem(changeItem)) as TestTreeItem; - const updatedStatus = changedTreeItem.testStatus; - - expect(origStatus).to.not.equal(updatedStatus); - expect(refreshCap.refreshCount).to.equal(2); - }); - - test('When the test data is updated, the update event is emitted', () => { - const testsData = createMockTestsData(); - const workspaceService = mock(WorkspaceService); - const testStore = mock(TestCollectionStorageService); - const workspaceFolder = { uri: Uri.file(''), name: 'root', index: 0 }; - when(workspaceService.getWorkspaceFolder(testResource)).thenReturn(workspaceFolder); - when(workspaceService.onDidChangeWorkspaceFolders).thenReturn(noop as any); - when(testStore.getTests(testResource)).thenReturn(testsData); - when(testStore.onDidChange).thenReturn(noop as any); - const testView = createMockTestTreeProvider( - instance(testStore), - testsData, - undefined, - instance(workspaceService), - ); - - const refreshCap = new TestExplorerCaptureRefresh(testView, disposables); - testView.refresh(testResource); - - expect(refreshCap.refreshCount).to.be.equal(1); - }); - - test('A test file is added/removed/renamed', async () => { - // create an inital test tree with a single file. - const fn = getMockTestFunction('test/test_fl.py::test_fn1'); - const fl1 = getMockTestFile('test/test_fl.py', [], [fn]); - const originalTestData = createMockTestsData([fl1]); - - // create an updated test tree, similar to the first, but with a new file - const origName = 'test_fl2'; - const afn = getMockTestFunction(`test/${origName}.py::test_2fn1`); - const fl2 = getMockTestFile(`test/${origName}.py`, [], [afn]); - const updatedTestData = createMockTestsData([fl1, fl2]); - - let testData = originalTestData; - const testStoreMoq = typemoq.Mock.ofType(); - testStoreMoq.setup((a) => a.getTests(typemoq.It.isAny())).returns(() => testData); - - const testTreeProvider = createMockTestTreeProvider(testStoreMoq.object); - - testTreeProvider.refresh(testResource); - let unchangedItem = await testTreeProvider.getTreeItem(fl1); - expect(unchangedItem).to.not.be.equal(undefined, 'The file that will always be present, is not present.'); - - testData = updatedTestData; - testTreeProvider.refresh(testResource); - - unchangedItem = await testTreeProvider.getTreeItem(fl1); - expect(unchangedItem).to.not.be.equal(undefined, 'The file that will always be present, is not present.'); - let addedTreeItem = (await testTreeProvider.getTreeItem(fl2)) as TestTreeItem; - expect(addedTreeItem).to.not.be.equal( - undefined, - 'The file has been added to the tests tree but not found?', - ); - expect(addedTreeItem.data.name).to.be.equal(`${origName}.py`); - - // change the name of the added file... - const newName = 'test_file_two'; - afn.name = afn.name.replace(origName, newName); - afn.nameToRun = afn.nameToRun.replace(origName, newName); - fl2.name = fl2.name.replace(origName, newName); - fl2.fullPath = fl2.fullPath.replace(origName, newName); - fl2.nameToRun = fl2.nameToRun.replace(origName, newName); - fl2.xmlName = fl2.xmlName.replace(origName, newName); - - testTreeProvider.refresh(testResource); - - unchangedItem = await testTreeProvider.getTreeItem(fl1); - expect(unchangedItem).to.not.be.equal(undefined, 'The file that will always be present, is not present.'); - addedTreeItem = (await testTreeProvider.getTreeItem(fl2)) as TestTreeItem; - expect(addedTreeItem).to.not.be.equal( - undefined, - 'The file has been updated in the tests tree but in tree view?', - ); - expect(addedTreeItem.data.name).to.be.equal(`${newName}.py`); - }); - - test('A test suite is added/removed/renamed', async () => { - // create an inital test tree with a single file containing a single suite. - const sfn = getMockTestFunction('test/test_fl.py::suite1::test_fn'); - const suite = getMockTestSuite('test/test_fl.py::suite1', [sfn]); - const fl1 = getMockTestFile('test/test_fl.py', [suite]); - const originalTestData = createMockTestsData([fl1]); - - // create an updated test tree, similar to the first, but with a new file - const origName = 'suite2'; - const sfn2 = getMockTestFunction(`test/test_fl.py::${origName}::test_fn`); - const suite2 = getMockTestSuite(`test/test_fl.py::${origName}`, [sfn2]); - const fl1_update = getMockTestFile('test/test_fl.py', [suite, suite2]); - const updatedTestData = createMockTestsData([fl1_update]); - - let testData = originalTestData; - const testStoreMoq = typemoq.Mock.ofType(); - testStoreMoq.setup((a) => a.getTests(typemoq.It.isAny())).returns(() => testData); - - const testTreeProvider = createMockTestTreeProvider(testStoreMoq.object); - - testTreeProvider.refresh(testResource); - let unchangedItem = await testTreeProvider.getTreeItem(suite); - expect(unchangedItem).to.not.be.equal(undefined, 'The suite that will always be present, is not present.'); - - testData = updatedTestData; - testTreeProvider.refresh(testResource); - - unchangedItem = await testTreeProvider.getTreeItem(suite); - expect(unchangedItem).to.not.be.equal(undefined, 'The suite that will always be present, is not present.'); - let addedTreeItem = (await testTreeProvider.getTreeItem(suite2)) as TestTreeItem; - expect(addedTreeItem).to.not.be.equal( - undefined, - 'The suite has been added to the tests tree but not found?', - ); - - const newName = 'suite_two'; - suite2.name = suite2.name.replace(origName, newName); - suite2.nameToRun = suite2.nameToRun.replace(origName, newName); - suite2.xmlName = suite2.xmlName.replace(origName, newName); - - testTreeProvider.refresh(testResource); - - unchangedItem = await testTreeProvider.getTreeItem(suite); - expect(unchangedItem).to.not.be.equal(undefined, 'The suite that will always be present, is not present.'); - addedTreeItem = (await testTreeProvider.getTreeItem(suite2)) as TestTreeItem; - expect(addedTreeItem).to.not.be.equal( - undefined, - 'The suite has been updated in the tests tree but in tree view?', - ); - expect(addedTreeItem.data.name).to.be.equal(newName); - }); - - test('A test function is added/removed/renamed', async () => { - // create an inital test tree with a single file containing a single suite. - const fn = getMockTestFunction('test/test_fl.py::test_fn'); - const fl1 = getMockTestFile('test/test_fl.py', [], [fn]); - const originalTestData = createMockTestsData([fl1]); - - // create an updated test tree, similar to the first, but with a new function - const origName = 'test_fn2'; - const fn2 = getMockTestFunction(`test/test_fl.py::${origName}`); - const fl1_update = getMockTestFile('test/test_fl.py', [], [fn, fn2]); - const updatedTestData = createMockTestsData([fl1_update]); - - let testData = originalTestData; - const testStoreMoq = typemoq.Mock.ofType(); - testStoreMoq.setup((a) => a.getTests(typemoq.It.isAny())).returns(() => testData); - - const testTreeProvider = createMockTestTreeProvider(testStoreMoq.object); - - testTreeProvider.refresh(testResource); - let unchangedItem = await testTreeProvider.getTreeItem(fn); - expect(unchangedItem).to.not.be.equal( - undefined, - 'The function that will always be present, is not present.', - ); - - testData = updatedTestData; - testTreeProvider.refresh(testResource); - - unchangedItem = await testTreeProvider.getTreeItem(fn); - expect(unchangedItem).to.not.be.equal( - undefined, - 'The function that will always be present, is not present.', - ); - let addedTreeItem = (await testTreeProvider.getTreeItem(fn2)) as TestTreeItem; - expect(addedTreeItem).to.not.be.equal( - undefined, - 'The function has been added to the tests tree but not found?', - ); - expect(addedTreeItem.data.name).to.be.equal('test_fn2'); - - const newName = 'test_func_two'; - fn2.name = fn2.name.replace(origName, newName); - fn2.nameToRun = fn2.nameToRun.replace(origName, newName); - - testTreeProvider.refresh(testResource); - - unchangedItem = await testTreeProvider.getTreeItem(fn); - expect(unchangedItem).to.not.be.equal( - undefined, - 'The function that will always be present, is not present.', - ); - addedTreeItem = (await testTreeProvider.getTreeItem(fn2)) as TestTreeItem; - expect(addedTreeItem).to.not.be.equal( - undefined, - 'The function has been updated in the tests tree but in tree view?', - ); - expect(addedTreeItem.data.name).to.be.equal(newName); - }); - - test('A test status changes and is reflected in the tree view', async () => { - // create a single file with a single function - const testFunction = getMockTestFunction('test/test_file.py::test_fn'); - testFunction.status = TestStatus.Pass; - const testFile = getMockTestFile('test/test_file.py', [], [testFunction]); - const testData = createMockTestsData([testFile]); - - const testTreeProvider = createMockTestTreeProvider(undefined, testData); - - // test's initial state is success - testTreeProvider.refresh(testResource); - const treeItem = (await testTreeProvider.getTreeItem(testFunction)) as TestTreeItem; - expect(treeItem.testStatus).to.be.equal(TestStatus.Pass); - - // test's next state is fail - testFunction.status = TestStatus.Fail; - testTreeProvider.refresh(testResource); - let updatedTreeItem = (await testTreeProvider.getTreeItem(testFunction)) as TestTreeItem; - expect(updatedTreeItem.testStatus).to.be.equal(TestStatus.Fail); - - // test's next state is skip - testFunction.status = TestStatus.Skipped; - testTreeProvider.refresh(testResource); - updatedTreeItem = (await testTreeProvider.getTreeItem(testFunction)) as TestTreeItem; - expect(updatedTreeItem.testStatus).to.be.equal(TestStatus.Skipped); - }); - - test('Get parent is working for each item type', async () => { - // create a single folder/file/suite/test setup - const testFunction = getMockTestFunction('test/test_file.py::test_suite::test_fn'); - const testSuite = getMockTestSuite('test/test_file.py::test_suite', [testFunction]); - const outerTestFunction = getMockTestFunction('test/test_file.py::test_outer_fn'); - const testFile = getMockTestFile('test/test_file.py', [testSuite], [outerTestFunction]); - const testData = createMockTestsData([testFile]); - - const testTreeProvider = createMockTestTreeProvider(undefined, testData); - - // build up the view item tree - testTreeProvider.refresh(testResource); - - let parent = (await testTreeProvider.getParent(testFunction))!; - expect(parent.name).to.be.equal( - testSuite.name, - 'Function within a test suite not returning the suite as parent.', - ); - let parentType = getTestDataItemType(parent); - expect(parentType).to.be.equal(TestDataItemType.suite); - - parent = (await testTreeProvider.getParent(testSuite))!; - expect(parent.name).to.be.equal( - testFile.name, - 'Suite within a test file not returning the test file as parent.', - ); - parentType = getTestDataItemType(parent); - expect(parentType).to.be.equal(TestDataItemType.file); - - parent = (await testTreeProvider.getParent(outerTestFunction))!; - expect(parent.name).to.be.equal( - testFile.name, - 'Function within a test file not returning the test file as parent.', - ); - parentType = getTestDataItemType(parent); - expect(parentType).to.be.equal(TestDataItemType.file); - - parent = (await testTreeProvider.getParent(testFile))!; - parentType = getTestDataItemType(parent!); - expect(parentType).to.be.equal(TestDataItemType.folder); - }); - - test('Get children is working for each item type', async () => { - // create a single folder/file/suite/test setup - const testFunction = getMockTestFunction('test/test_file.py::test_suite::test_fn'); - const testSuite = getMockTestSuite('test/test_file.py::test_suite', [testFunction]); - const outerTestFunction = getMockTestFunction('test/test_file.py::test_outer_fn'); - const testFile = getMockTestFile('test/test_file.py', [testSuite], [outerTestFunction]); - const testData = createMockTestsData([testFile]); - - const testTreeProvider = createMockTestTreeProvider(undefined, testData); - - // build up the view item tree - testTreeProvider.refresh(testResource); - - let children = await testTreeProvider.getChildren(testFunction); - expect(children.length).to.be.equal(0, 'A function should never have children.'); - - children = await testTreeProvider.getChildren(testSuite); - expect(children.length).to.be.equal(1, 'Suite a single function should only return one child.'); - children.forEach((child: TestDataItem) => { - expect(child.name).oneOf(['test_fn']); - expect(getTestDataItemType(child)).to.be.equal(TestDataItemType.function); - }); - - children = await testTreeProvider.getChildren(outerTestFunction); - expect(children.length).to.be.equal(0, 'A function should never have children.'); - - children = await testTreeProvider.getChildren(testFile); - expect(children.length).to.be.equal( - 2, - 'A file with one suite and one function should have a total of 2 children.', - ); - children.forEach((child: TestDataItem) => { - expect(child.name).oneOf(['test_suite', 'test_outer_fn']); - }); - }); - - test('Tree items for subtests are correct', async () => { - const resource = Uri.file(__filename); - // Set up the folder & file. - const folder = getMockTestFolder('tests'); - const file = getMockTestFile(`${folder.name}/test_file.py`); - folder.testFiles.push(file); - // Set up the file-level tests. - const func1 = getMockTestFunction(`${file.name}::test_spam`); - file.functions.push(func1); - const func2 = getMockTestFunction(`${file.name}::test_ham[1-2]`); - func2.subtestParent = { - name: 'test_ham', - nameToRun: `${file.name}::test_ham`, - asSuite: { - resource: resource, - name: 'test_ham', - nameToRun: `${file.name}::test_ham`, - functions: [func2], - suites: [], - isUnitTest: false, - isInstance: false, - xmlName: 'test_ham', - time: 0, - }, - time: 0, - }; - file.functions.push(func2); - const func3 = getMockTestFunction(`${file.name}::test_ham[3-4]`); - func3.subtestParent = func2.subtestParent; - func3.subtestParent.asSuite.functions.push(func3); - file.functions.push(func3); - // Set up the suite. - const suite = getMockTestSuite(`${file.name}::MyTests`); - file.suites.push(suite); - const func4 = getMockTestFunction('MyTests::test_foo'); - suite.functions.push(func4); - const func5 = getMockTestFunction('MyTests::test_bar[2-3]'); - func5.subtestParent = { - name: 'test_bar', - nameToRun: `${file.name}::MyTests::test_bar`, - asSuite: { - resource: resource, - name: 'test_bar', - nameToRun: `${file.name}::MyTests::test_bar`, - functions: [func5], - suites: [], - isUnitTest: false, - isInstance: false, - xmlName: 'test_bar', - time: 0, - }, - time: 0, - }; - suite.functions.push(func5); - // Set up the tests data. - const testData = createMockTestsData([file]); - - const testExplorer = createMockTestTreeProvider(undefined, testData); - const items = [ - await testExplorer.getTreeItem(func1), - await testExplorer.getTreeItem(func2), - await testExplorer.getTreeItem(func3), - await testExplorer.getTreeItem(func4), - await testExplorer.getTreeItem(func5), - await testExplorer.getTreeItem(file), - await testExplorer.getTreeItem(suite), - await testExplorer.getTreeItem(func2.subtestParent.asSuite), - await testExplorer.getTreeItem(func5.subtestParent.asSuite), - ]; - - expect(items).to.deep.equal([ - new TestTreeItem(func1.resource, func1), - new TestTreeItem(func2.resource, func2), - new TestTreeItem(func3.resource, func3), - new TestTreeItem(func4.resource, func4), - new TestTreeItem(func5.resource, func5), - new TestTreeItem(file.resource, file), - new TestTreeItem(suite.resource, suite), - new TestTreeItem(resource, func2.subtestParent.asSuite), - new TestTreeItem(resource, func5.subtestParent.asSuite), - ]); - }); - - test('Parents for subtests are correct', async () => { - const resource = Uri.file(__filename); - // Set up the folder & file. - const folder = getMockTestFolder('tests'); - const file = getMockTestFile(`${folder.name}/test_file.py`); - folder.testFiles.push(file); - // Set up the file-level tests. - const func1 = getMockTestFunction(`${file.name}::test_spam`); - file.functions.push(func1); - const func2 = getMockTestFunction(`${file.name}::test_ham[1-2]`); - func2.subtestParent = { - name: 'test_ham', - nameToRun: `${file.name}::test_ham`, - asSuite: { - resource: resource, - name: 'test_ham', - nameToRun: `${file.name}::test_ham`, - functions: [func2], - suites: [], - isUnitTest: false, - isInstance: false, - xmlName: 'test_ham', - time: 0, - }, - time: 0, - }; - file.functions.push(func2); - const func3 = getMockTestFunction(`${file.name}::test_ham[3-4]`); - func3.subtestParent = func2.subtestParent; - func3.subtestParent.asSuite.functions.push(func3); - file.functions.push(func3); - // Set up the suite. - const suite = getMockTestSuite(`${file.name}::MyTests`); - file.suites.push(suite); - const func4 = getMockTestFunction('MyTests::test_foo'); - suite.functions.push(func4); - const func5 = getMockTestFunction('MyTests::test_bar[2-3]'); - func5.subtestParent = { - name: 'test_bar', - nameToRun: `${file.name}::MyTests::test_bar`, - asSuite: { - resource: resource, - name: 'test_bar', - nameToRun: `${file.name}::MyTests::test_bar`, - functions: [func5], - suites: [], - isUnitTest: false, - isInstance: false, - xmlName: 'test_bar', - time: 0, - }, - time: 0, - }; - suite.functions.push(func5); - // Set up the tests data. - const testData = createMockTestsData([file]); - - const testExplorer = createMockTestTreeProvider(undefined, testData); - const parents = [ - await testExplorer.getParent(func1), - await testExplorer.getParent(func2), - await testExplorer.getParent(func3), - await testExplorer.getParent(func4), - await testExplorer.getParent(func5), - await testExplorer.getParent(suite), - await testExplorer.getParent(func2.subtestParent.asSuite), - await testExplorer.getParent(func3.subtestParent.asSuite), - await testExplorer.getParent(func5.subtestParent.asSuite), - ]; - - expect(parents).to.deep.equal([ - file, - func2.subtestParent.asSuite, - func3.subtestParent.asSuite, - suite, - func5.subtestParent.asSuite, - file, - file, - file, - suite, - ]); - }); - test('Children for subtests are correct', async () => { - const resource = Uri.file(__filename); - // Set up the folder & file. - const folder = getMockTestFolder('tests'); - const file = getMockTestFile(`${folder.name}/test_file.py`); - folder.testFiles.push(file); - // Set up the file-level tests. - const func1 = getMockTestFunction(`${file.name}::test_spam`); - file.functions.push(func1); - const func2 = getMockTestFunction(`${file.name}::test_ham[1-2]`); - func2.subtestParent = { - name: 'test_ham', - nameToRun: `${file.name}::test_ham`, - asSuite: { - resource: resource, - name: 'test_ham', - nameToRun: `${file.name}::test_ham`, - functions: [func2], - suites: [], - isUnitTest: false, - isInstance: false, - xmlName: 'test_ham', - time: 0, - }, - time: 0, - }; - file.functions.push(func2); - const func3 = getMockTestFunction(`${file.name}::test_ham[3-4]`); - func3.subtestParent = func2.subtestParent; - func3.subtestParent.asSuite.functions.push(func3); - file.functions.push(func3); - // Set up the suite. - const suite = getMockTestSuite(`${file.name}::MyTests`); - file.suites.push(suite); - const func4 = getMockTestFunction('MyTests::test_foo'); - suite.functions.push(func4); - const func5 = getMockTestFunction('MyTests::test_bar[2-3]'); - func5.subtestParent = { - name: 'test_bar', - nameToRun: `${file.name}::MyTests::test_bar`, - asSuite: { - resource: resource, - name: 'test_bar', - nameToRun: `${file.name}::MyTests::test_bar`, - functions: [func5], - suites: [], - isUnitTest: false, - isInstance: false, - xmlName: 'test_bar', - time: 0, - }, - time: 0, - }; - suite.functions.push(func5); - // Set up the tests data. - const testData = createMockTestsData([file]); - - const testExplorer = createMockTestTreeProvider(undefined, testData); - const childrens = [ - await testExplorer.getChildren(func1), - await testExplorer.getChildren(func2), - await testExplorer.getChildren(func3), - await testExplorer.getChildren(func4), - await testExplorer.getChildren(func5), - await testExplorer.getChildren(file), - await testExplorer.getChildren(suite), - await testExplorer.getChildren(func2.subtestParent.asSuite), - await testExplorer.getChildren(func3.subtestParent.asSuite), - await testExplorer.getChildren(func5.subtestParent.asSuite), - ]; - - expect(childrens).to.deep.equal([ - [], - [], - [], - [], - [], - [func1, suite, func2.subtestParent.asSuite], - [func4, func5.subtestParent.asSuite], - [func2, func3], - [func2, func3], - [func5], - ]); - test('Get children will discover only once', async () => { - const commandManager = mock(CommandManager); - const testStore = mock(TestCollectionStorageService); - const testWorkspaceFolder = new TestWorkspaceFolder({ uri: Uri.file(__filename), name: '', index: 0 }); - when(testStore.getTests(testWorkspaceFolder.workspaceFolder.uri)).thenReturn(); - when(testStore.onDidChange).thenReturn(noop as any); - - const testTreeProvider = createMockTestTreeProvider( - instance(testStore), - undefined, - undefined, - undefined, - instance(commandManager), - ); - - let tests = await testTreeProvider.getChildren(testWorkspaceFolder); - - expect(tests).to.be.lengthOf(0); - verify( - commandManager.executeCommand( - Commands.Tests_Discover, - testWorkspaceFolder, - CommandSource.testExplorer, - undefined, - ), - ).once(); - - tests = await testTreeProvider.getChildren(testWorkspaceFolder); - expect(tests).to.be.lengthOf(0); - verify( - commandManager.executeCommand( - Commands.Tests_Discover, - testWorkspaceFolder, - CommandSource.testExplorer, - undefined, - ), - ).once(); - }); - }); - test('Expand tree item if it does not have any parent', async () => { - const commandManager = mock(CommandManager); - const testStore = mock(TestCollectionStorageService); - const testWorkspaceFolder = new TestWorkspaceFolder({ uri: Uri.file(__filename), name: '', index: 0 }); - when(testStore.getTests(testWorkspaceFolder.workspaceFolder.uri)).thenReturn(); - when(testStore.onDidChange).thenReturn(noop as any); - const testTreeProvider = createMockTestTreeProvider( - instance(testStore), - undefined, - undefined, - undefined, - instance(commandManager), - ); - - // No parent - testTreeProvider.getParent = () => Promise.resolve(undefined); - - const element: TestFile = { - fullPath: __filename, - functions: [], - suites: [], - name: 'name', - time: 0, - resource: Uri.file(__filename), - xmlName: '', - nameToRun: '', - }; - - const node = await testTreeProvider.getTreeItem(element); - - expect(node.collapsibleState).to.equal(TreeItemCollapsibleState.Expanded); - }); - test('Expand tree item if the parent is the Workspace Folder in a multiroot scenario', async () => { - const commandManager = mock(CommandManager); - const testStore = mock(TestCollectionStorageService); - const testWorkspaceFolder = new TestWorkspaceFolder({ uri: Uri.file(__filename), name: '', index: 0 }); - when(testStore.getTests(testWorkspaceFolder.workspaceFolder.uri)).thenReturn(); - when(testStore.onDidChange).thenReturn(noop as any); - const testTreeProvider = createMockTestTreeProvider( - instance(testStore), - undefined, - undefined, - undefined, - instance(commandManager), - ); - - // Has a workspace folder as parent. - const parentFolder = new TestWorkspaceFolder({ name: '', index: 0, uri: Uri.file(__filename) }); - - testTreeProvider.getParent = () => Promise.resolve(parentFolder); - - const element: TestFile = { - fullPath: __filename, - functions: [], - suites: [], - name: 'name', - time: 0, - resource: Uri.file(__filename), - xmlName: '', - nameToRun: '', - }; - - const node = await testTreeProvider.getTreeItem(element); - - expect(node.collapsibleState).to.equal(TreeItemCollapsibleState.Expanded); - }); - test('Do not expand tree item if it does not have any parent', async () => { - const commandManager = mock(CommandManager); - const testStore = mock(TestCollectionStorageService); - const testWorkspaceFolder = new TestWorkspaceFolder({ uri: Uri.file(__filename), name: '', index: 0 }); - when(testStore.getTests(testWorkspaceFolder.workspaceFolder.uri)).thenReturn(); - when(testStore.onDidChange).thenReturn(noop as any); - const testTreeProvider = createMockTestTreeProvider( - instance(testStore), - undefined, - undefined, - undefined, - instance(commandManager), - ); - - // Has a parent folder - const parentFolder: TestFolder = { - name: '', - nameToRun: '', - resource: Uri.file(__filename), - time: 0, - testFiles: [], - folders: [], - }; - - testTreeProvider.getParent = () => Promise.resolve(parentFolder); - - const element: TestFile = { - fullPath: __filename, - functions: [], - suites: [], - name: 'name', - time: 0, - resource: Uri.file(__filename), - xmlName: '', - nameToRun: '', - }; - - const node = await testTreeProvider.getTreeItem(element); - - expect(node.collapsibleState).to.not.equal(TreeItemCollapsibleState.Expanded); - }); - }); - suite('Root Nodes', () => { - let treeProvider: TestTreeViewProvider; - setup(() => { - const store = mock(TestCollectionStorageService); - const managementService = mock(UnitTestManagementService); - when(managementService.onDidStatusChange).thenReturn(noop as any); - when(store.onDidChange).thenReturn(noop as any); - const workspace = mock(WorkspaceService); - when(workspace.onDidChangeWorkspaceFolders).thenReturn(noop as any); - const commandManager = mock(CommandManager); - treeProvider = new TestTreeViewProvider( - instance(store), - instance(managementService), - instance(workspace), - instance(commandManager), - [], - ); - }); - test('The root folder will not be displayed if there are no tests', async () => { - const children = treeProvider.getRootNodes(); - - expect(children).to.deep.equal([]); - }); - test('The root folder will not be displayed if there are no test files directly under the root', async () => { - const folder1: TestFolder = { - folders: [], - name: 'child', - nameToRun: 'child', - testFiles: [], - time: 0, - resource: Uri.file(__filename), - }; - const tests: Tests = { - rootTestFolders: [folder1], - summary: { errors: 0, skipped: 0, passed: 0, failures: 0 }, - testFiles: [], - testFunctions: [], - testFolders: [], - testSuites: [], - }; - const children = treeProvider.getRootNodes(tests); - - expect(children).to.deep.equal([]); - }); - test('Files & folders under root folder are returned as children', async () => { - const rootFolderPath = path.join('a', 'b', 'root'); - const child1FolderPath = path.join('a', 'b', 'root', 'child1'); - const child2FolderPath = path.join('a', 'b', 'root', 'child2'); - const file1: TestFile = { - fullPath: path.join(rootFolderPath, 'file1'), - functions: [], - name: 'file', - nameToRun: 'file', - resource: Uri.file('file'), - suites: [], - time: 0, - xmlName: 'file', - }; - const file2: TestFile = { - fullPath: path.join(rootFolderPath, 'file2'), - functions: [], - name: 'file2', - nameToRun: 'file2', - resource: Uri.file('file2'), - suites: [], - time: 0, - xmlName: 'file2', - }; - const file3: TestFile = { - fullPath: path.join(child1FolderPath, 'file1'), - functions: [], - name: 'file3', - nameToRun: 'file3', - resource: Uri.file('file3'), - suites: [], - time: 0, - xmlName: 'file3', - }; - const child2Folder: TestFolder = { - folders: [], - name: child2FolderPath, - nameToRun: 'child3', - testFiles: [], - time: 0, - resource: Uri.file(__filename), - }; - const child1Folder: TestFolder = { - folders: [child2Folder], - name: child1FolderPath, - nameToRun: 'child2', - testFiles: [file3], - time: 0, - resource: Uri.file(__filename), - }; - const rootFolder: TestFolder = { - folders: [child1Folder], - name: rootFolderPath, - nameToRun: 'child', - testFiles: [file1, file2], - time: 0, - resource: Uri.file(__filename), - }; - const tests: Tests = { - rootTestFolders: [rootFolder], - summary: { errors: 0, skipped: 0, passed: 0, failures: 0 }, - testFiles: [file1, file2, file3], - testFunctions: [], - testFolders: [rootFolder, child1Folder, child2Folder], - testSuites: [], - }; - const children = treeProvider.getRootNodes(tests); - - expect(children).to.be.lengthOf(3); - expect(children).to.deep.equal([file1, file2, child1Folder]); - }); - test('Root folders are returned as children', async () => { - const child1FolderPath = path.join('a', 'b', 'root1', 'child1'); - const child2FolderPath = path.join('a', 'b', 'root1', 'child1', 'child2'); - const child3FolderPath = path.join('a', 'b', 'root2', 'child3'); - const file1: TestFile = { - fullPath: path.join(child3FolderPath, 'file1'), - functions: [], - name: 'file', - nameToRun: 'file', - resource: Uri.file('file'), - suites: [], - time: 0, - xmlName: 'file', - }; - const file2: TestFile = { - fullPath: path.join(child3FolderPath, 'file2'), - functions: [], - name: 'file2', - nameToRun: 'file2', - resource: Uri.file('file2'), - suites: [], - time: 0, - xmlName: 'file2', - }; - const file3: TestFile = { - fullPath: path.join(child3FolderPath, 'file3'), - functions: [], - name: 'file3', - nameToRun: 'file3', - resource: Uri.file('file3'), - suites: [], - time: 0, - xmlName: 'file3', - }; - const child2Folder: TestFolder = { - folders: [], - name: child2FolderPath, - nameToRun: 'child3', - testFiles: [file2], - time: 0, - resource: Uri.file(__filename), - }; - const child1Folder: TestFolder = { - folders: [child2Folder], - name: child1FolderPath, - nameToRun: 'child2', - testFiles: [file1], - time: 0, - resource: Uri.file(__filename), - }; - const child3Folder: TestFolder = { - folders: [], - name: child3FolderPath, - nameToRun: 'child', - testFiles: [file3], - time: 0, - resource: Uri.file(__filename), - }; - const tests: Tests = { - rootTestFolders: [child1Folder, child3Folder], - summary: { errors: 0, skipped: 0, passed: 0, failures: 0 }, - testFiles: [file1, file2, file3], - testFunctions: [], - testFolders: [child3Folder, child1Folder, child2Folder], - testSuites: [], - }; - const children = treeProvider.getRootNodes(tests); - - expect(children).to.be.lengthOf(2); - expect(children).to.deep.equal([child1Folder, child3Folder]); - }); - }); -}); diff --git a/src/test/testing/navigation/commandHandlers.unit.test.ts b/src/test/testing/navigation/commandHandlers.unit.test.ts deleted file mode 100644 index 31ed1fc6092a..000000000000 --- a/src/test/testing/navigation/commandHandlers.unit.test.ts +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { instance, mock, verify, when } from 'ts-mockito'; -import * as typemoq from 'typemoq'; -import { CommandManager } from '../../../client/common/application/commandManager'; -import { ICommandManager } from '../../../client/common/application/types'; -import { AsyncDisposableRegistry } from '../../../client/common/asyncDisposableRegistry'; -import { Commands } from '../../../client/common/constants'; -import { IDisposable, IDisposableRegistry } from '../../../client/common/types'; -import { TestCodeNavigatorCommandHandler } from '../../../client/testing/navigation/commandHandler'; -import { TestFileCodeNavigator } from '../../../client/testing/navigation/fileNavigator'; -import { TestFunctionCodeNavigator } from '../../../client/testing/navigation/functionNavigator'; -import { TestSuiteCodeNavigator } from '../../../client/testing/navigation/suiteNavigator'; -import { ITestCodeNavigator, ITestCodeNavigatorCommandHandler } from '../../../client/testing/navigation/types'; - -suite('Unit Tests - Navigation Command Handler', () => { - let commandHandler: ITestCodeNavigatorCommandHandler; - let cmdManager: ICommandManager; - let fileHandler: ITestCodeNavigator; - let functionHandler: ITestCodeNavigator; - let suiteHandler: ITestCodeNavigator; - let disposableRegistry: IDisposableRegistry; - setup(() => { - cmdManager = mock(CommandManager); - fileHandler = mock(TestFileCodeNavigator); - functionHandler = mock(TestFunctionCodeNavigator); - suiteHandler = mock(TestSuiteCodeNavigator); - - disposableRegistry = mock(AsyncDisposableRegistry) as any; - commandHandler = new TestCodeNavigatorCommandHandler( - instance(cmdManager), - instance(fileHandler), - instance(functionHandler), - instance(suiteHandler), - instance(disposableRegistry), - ); - }); - test('Ensure Navigation handlers are registered', async () => { - commandHandler.register(); - verify( - cmdManager.registerCommand( - Commands.navigateToTestFile, - instance(fileHandler).navigateTo, - instance(fileHandler), - ), - ).once(); - verify( - cmdManager.registerCommand( - Commands.navigateToTestFunction, - instance(functionHandler).navigateTo, - instance(functionHandler), - ), - ).once(); - verify( - cmdManager.registerCommand( - Commands.navigateToTestSuite, - instance(suiteHandler).navigateTo, - instance(suiteHandler), - ), - ).once(); - }); - test('Ensure handlers are disposed', async () => { - const disposable1 = typemoq.Mock.ofType(); - const disposable2 = typemoq.Mock.ofType(); - const disposable3 = typemoq.Mock.ofType(); - when( - cmdManager.registerCommand( - Commands.navigateToTestFile, - instance(fileHandler).navigateTo, - instance(fileHandler), - ), - ).thenReturn(disposable1.object); - when( - cmdManager.registerCommand( - Commands.navigateToTestFunction, - instance(functionHandler).navigateTo, - instance(functionHandler), - ), - ).thenReturn(disposable2.object); - when( - cmdManager.registerCommand( - Commands.navigateToTestSuite, - instance(suiteHandler).navigateTo, - instance(suiteHandler), - ), - ).thenReturn(disposable3.object); - - commandHandler.register(); - commandHandler.dispose(); - - disposable1.verify((d) => d.dispose(), typemoq.Times.once()); - disposable2.verify((d) => d.dispose(), typemoq.Times.once()); - disposable3.verify((d) => d.dispose(), typemoq.Times.once()); - }); - test('Ensure command handler is reigstered to be disposed', async () => { - commandHandler.register(); - verify(disposableRegistry.push(commandHandler)).once(); - }); -}); diff --git a/src/test/testing/navigation/fileNavigator.unit.test.ts b/src/test/testing/navigation/fileNavigator.unit.test.ts deleted file mode 100644 index 5ff862b7b9b2..000000000000 --- a/src/test/testing/navigation/fileNavigator.unit.test.ts +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { expect, use } from 'chai'; -import * as chaisAsPromised from 'chai-as-promised'; -import { anything, capture, instance, mock, verify, when } from 'ts-mockito'; -import { Uri } from 'vscode'; -import { TestFileCodeNavigator } from '../../../client/testing/navigation/fileNavigator'; -import { TestNavigatorHelper } from '../../../client/testing/navigation/helper'; -import { ITestNavigatorHelper } from '../../../client/testing/navigation/types'; - -use(chaisAsPromised); - -suite('Unit Tests - Navigation File', () => { - let navigator: TestFileCodeNavigator; - let helper: ITestNavigatorHelper; - setup(() => { - helper = mock(TestNavigatorHelper); - navigator = new TestFileCodeNavigator(instance(helper)); - }); - test('Ensure file is opened', async () => { - const filePath = Uri.file('some file Path'); - when(helper.openFile(anything())).thenResolve(); - - await navigator.navigateTo(filePath, { fullPath: filePath.fsPath } as any, false); - - verify(helper.openFile(anything())).once(); - expect(capture(helper.openFile).first()[0]!.fsPath).to.equal(filePath.fsPath); - }); - test('Ensure errors are swallowed', async () => { - const filePath = Uri.file('some file Path'); - when(helper.openFile(anything())).thenReject(new Error('kaboom')); - - await navigator.navigateTo(filePath, { fullPath: filePath.fsPath } as any, false); - - verify(helper.openFile(anything())).once(); - expect(capture(helper.openFile).first()[0]!.fsPath).to.equal(filePath.fsPath); - }); -}); diff --git a/src/test/testing/navigation/functionNavigator.unit.test.ts b/src/test/testing/navigation/functionNavigator.unit.test.ts deleted file mode 100644 index cc7d75eefcb2..000000000000 --- a/src/test/testing/navigation/functionNavigator.unit.test.ts +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { expect, use } from 'chai'; -import * as chaisAsPromised from 'chai-as-promised'; -import { anything, capture, deepEqual, instance, mock, verify, when } from 'ts-mockito'; -import * as typemoq from 'typemoq'; -import { - Location, - Range, - SymbolInformation, - SymbolKind, - TextDocument, - TextEditor, - TextEditorRevealType, - Uri, -} from 'vscode'; -import { DocumentManager } from '../../../client/common/application/documentManager'; -import { IDocumentManager } from '../../../client/common/application/types'; -import { TestCollectionStorageService } from '../../../client/testing/common/services/storageService'; -import { ITestCollectionStorageService } from '../../../client/testing/common/types'; -import { TestFunctionCodeNavigator } from '../../../client/testing/navigation/functionNavigator'; -import { TestNavigatorHelper } from '../../../client/testing/navigation/helper'; -import { ITestNavigatorHelper } from '../../../client/testing/navigation/types'; - -use(chaisAsPromised); - -suite('Unit Tests - Navigation Function', () => { - let navigator: TestFunctionCodeNavigator; - let helper: ITestNavigatorHelper; - let docManager: IDocumentManager; - let doc: typemoq.IMock; - let editor: typemoq.IMock; - let storage: ITestCollectionStorageService; - setup(() => { - doc = typemoq.Mock.ofType(); - editor = typemoq.Mock.ofType(); - helper = mock(TestNavigatorHelper); - docManager = mock(DocumentManager); - storage = mock(TestCollectionStorageService); - navigator = new TestFunctionCodeNavigator(instance(helper), instance(docManager), instance(storage)); - }); - test('Ensure file is opened', async () => { - const filePath = Uri.file('some file Path'); - when(helper.openFile(anything())).thenResolve([doc.object, editor.object]); - const flattenedFn = { parentTestFile: { fullPath: filePath.fsPath }, testFunction: {} }; - when(storage.findFlattendTestFunction(filePath, anything())).thenReturn(flattenedFn as any); - - await navigator.navigateTo(filePath, {} as any); - - verify(helper.openFile(anything())).once(); - expect(capture(helper.openFile).first()[0]!.fsPath).to.equal(filePath.fsPath); - }); - test('Ensure errors are swallowed', async () => { - const filePath = Uri.file('some file Path'); - when(helper.openFile(anything())).thenReject(new Error('kaboom')); - const flattenedFn = { parentTestFile: { fullPath: filePath.fsPath }, testFunction: {} }; - when(storage.findFlattendTestFunction(filePath, anything())).thenReturn(flattenedFn as any); - - await navigator.navigateTo(filePath, {} as any); - - verify(helper.openFile(anything())).once(); - expect(capture(helper.openFile).first()[0]!.fsPath).to.equal(filePath.fsPath); - }); - async function navigateToFunction(focusCode: boolean) { - const filePath = Uri.file('some file Path'); - const line = 999; - when(helper.openFile(anything())).thenResolve([doc.object, editor.object]); - const flattenedFn = { parentTestFile: { fullPath: filePath.fsPath }, testFunction: { name: 'function_name' } }; - when(storage.findFlattendTestFunction(filePath, anything())).thenReturn(flattenedFn as any); - const range = new Range(line, 0, line, 0); - const symbol: SymbolInformation = { - containerName: '', - kind: SymbolKind.Function, - name: 'function_name', - location: new Location(Uri.file(__filename), range), - }; - when(helper.findSymbol(doc.object, anything(), anything())).thenResolve(symbol); - - await navigator.navigateTo(filePath, { name: 'function_name' } as any, focusCode); - - verify(helper.openFile(anything())).once(); - verify(helper.findSymbol(doc.object, anything(), anything())).once(); - expect(capture(helper.openFile).first()[0]!.fsPath).to.equal(filePath.fsPath); - if (focusCode) { - verify( - docManager.showTextDocument(doc.object, deepEqual({ preserveFocus: false, selection: range })), - ).once(); - } else { - editor.verify((e) => e.revealRange(typemoq.It.isAny(), TextEditorRevealType.Default), typemoq.Times.once()); - } - } - test('Ensure we use line number from test function when navigating in file (without focusing code)', async () => { - await navigateToFunction(false); - }); - test('Ensure we use line number from test function when navigating in file (focusing code)', async () => { - await navigateToFunction(true); - }); - test('Ensure file is opened and range not revealed', async () => { - const filePath = Uri.file('some file Path'); - when(helper.openFile(anything())).thenResolve([doc.object, editor.object]); - const flattenedFn = { parentTestFile: { fullPath: filePath.fsPath }, testFunction: {} }; - when(storage.findFlattendTestFunction(filePath, anything())).thenReturn(flattenedFn as any); - const search = (s: SymbolInformation) => s.kind === SymbolKind.Function && s.name === 'Hello'; - when(helper.findSymbol(doc.object, search, anything())).thenResolve(); - - await navigator.navigateTo(filePath, {} as any); - - verify(helper.openFile(anything())).once(); - expect(capture(helper.openFile).first()[0]!.fsPath).to.equal(filePath.fsPath); - editor.verify((e) => e.revealRange(typemoq.It.isAny(), typemoq.It.isAny()), typemoq.Times.never()); - }); -}); diff --git a/src/test/testing/navigation/helper.unit.test.ts b/src/test/testing/navigation/helper.unit.test.ts deleted file mode 100644 index a734744d1b35..000000000000 --- a/src/test/testing/navigation/helper.unit.test.ts +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { expect, use } from 'chai'; -import * as chaisAsPromised from 'chai-as-promised'; -import { anything, instance, mock, verify, when } from 'ts-mockito'; -import * as typemoq from 'typemoq'; -import { - CancellationTokenSource, - DocumentSymbolProvider, - SymbolInformation, - SymbolKind, - TextDocument, - TextEditor, - Uri, -} from 'vscode'; -import { DocumentManager } from '../../../client/common/application/documentManager'; -import { IDocumentManager } from '../../../client/common/application/types'; -import { LanguageServerSymbolProvider } from '../../../client/providers/symbolProvider'; -import { TestNavigatorHelper } from '../../../client/testing/navigation/helper'; - -use(chaisAsPromised); - -suite('Unit Tests - Navigation Helper', () => { - let helper: TestNavigatorHelper; - let docManager: IDocumentManager; - let doc: typemoq.IMock; - let editor: typemoq.IMock; - let symbolProvider: DocumentSymbolProvider; - setup(() => { - doc = typemoq.Mock.ofType(); - editor = typemoq.Mock.ofType(); - doc.setup((d: any) => d.then).returns(() => undefined); - editor.setup((e: any) => e.then).returns(() => undefined); - docManager = mock(DocumentManager); - symbolProvider = mock(LanguageServerSymbolProvider); - helper = new TestNavigatorHelper(instance(docManager), instance(symbolProvider)); - }); - test('Ensure file is opened', async () => { - const filePath = Uri.file('some file Path'); - when(docManager.openTextDocument(anything())).thenResolve(doc.object as any); - when(docManager.showTextDocument(doc.object)).thenResolve(editor.object as any); - - const [d, e] = await helper.openFile(filePath); - - verify(docManager.openTextDocument(filePath)).once(); - verify(docManager.showTextDocument(doc.object)).once(); - expect(d).to.deep.equal(doc.object); - expect(e).to.deep.equal(editor.object); - }); - test('No symbols if symbol provider is not registered', async () => { - const token = new CancellationTokenSource().token; - const predicate = (s: SymbolInformation) => s.kind === SymbolKind.Function && s.name === ''; - const symbol = await helper.findSymbol(doc.object, predicate, token); - expect(symbol).to.equal(undefined, 'Must be undefined'); - }); - test('No symbols if no symbols', async () => { - const token = new CancellationTokenSource().token; - when(symbolProvider.provideDocumentSymbols(doc.object, token)).thenResolve([] as any); - - const predicate = (s: SymbolInformation) => s.kind === SymbolKind.Function && s.name === ''; - const symbol = await helper.findSymbol(doc.object, predicate, token); - - expect(symbol).to.equal(undefined, 'Must be undefined'); - verify(symbolProvider.provideDocumentSymbols(doc.object, token)).once(); - }); - test('Returns matching symbol', async () => { - const symbols: SymbolInformation[] = [ - { containerName: '', kind: SymbolKind.Function, name: '1', location: undefined as any }, - { containerName: '', kind: SymbolKind.Class, name: '2', location: undefined as any }, - { containerName: '', kind: SymbolKind.File, name: '2', location: undefined as any }, - ]; - const token = new CancellationTokenSource().token; - when(symbolProvider.provideDocumentSymbols(doc.object, token)).thenResolve(symbols as any); - - const predicate = (s: SymbolInformation) => s.kind === SymbolKind.Class && s.name === '2'; - const symbol = await helper.findSymbol(doc.object, predicate, token); - - expect(symbol).to.deep.equal(symbols[1]); - verify(symbolProvider.provideDocumentSymbols(doc.object, token)).once(); - }); -}); diff --git a/src/test/testing/navigation/serviceRegistry.unit.test.ts b/src/test/testing/navigation/serviceRegistry.unit.test.ts deleted file mode 100644 index d6607c644a36..000000000000 --- a/src/test/testing/navigation/serviceRegistry.unit.test.ts +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { use } from 'chai'; -import * as chaisAsPromised from 'chai-as-promised'; -import { anything, instance, mock, verify } from 'ts-mockito'; -import { IDocumentSymbolProvider } from '../../../client/common/types'; -import { ServiceManager } from '../../../client/ioc/serviceManager'; -import { TestCodeNavigatorCommandHandler } from '../../../client/testing/navigation/commandHandler'; -import { TestFileCodeNavigator } from '../../../client/testing/navigation/fileNavigator'; -import { TestFunctionCodeNavigator } from '../../../client/testing/navigation/functionNavigator'; -import { TestNavigatorHelper } from '../../../client/testing/navigation/helper'; -import { registerTypes } from '../../../client/testing/navigation/serviceRegistry'; -import { TestSuiteCodeNavigator } from '../../../client/testing/navigation/suiteNavigator'; -import { TestFileSymbolProvider } from '../../../client/testing/navigation/symbolProvider'; -import { - ITestCodeNavigator, - ITestCodeNavigatorCommandHandler, - ITestNavigatorHelper, - NavigableItemType, -} from '../../../client/testing/navigation/types'; - -use(chaisAsPromised); - -suite('Unit Tests - Navigation Service Registry', () => { - test('Ensure services are registered', async () => { - const serviceManager = mock(ServiceManager); - - registerTypes(instance(serviceManager)); - - verify(serviceManager.addSingleton(ITestNavigatorHelper, TestNavigatorHelper)).once(); - verify( - serviceManager.addSingleton( - ITestCodeNavigatorCommandHandler, - TestCodeNavigatorCommandHandler, - ), - ).once(); - verify( - serviceManager.addSingleton( - ITestCodeNavigator, - TestFileCodeNavigator, - NavigableItemType.testFile, - ), - ).once(); - verify( - serviceManager.addSingleton( - ITestCodeNavigator, - TestFunctionCodeNavigator, - NavigableItemType.testFunction, - ), - ).once(); - verify( - serviceManager.addSingleton( - ITestCodeNavigator, - TestSuiteCodeNavigator, - NavigableItemType.testSuite, - ), - ).once(); - verify(serviceManager.addSingleton(anything(), TestFileSymbolProvider, 'test')).once(); - }); -}); diff --git a/src/test/testing/navigation/suiteNavigator.unit.test.ts b/src/test/testing/navigation/suiteNavigator.unit.test.ts deleted file mode 100644 index 361f47d915f2..000000000000 --- a/src/test/testing/navigation/suiteNavigator.unit.test.ts +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { expect, use } from 'chai'; -import * as chaisAsPromised from 'chai-as-promised'; -import { anything, capture, deepEqual, instance, mock, verify, when } from 'ts-mockito'; -import * as typemoq from 'typemoq'; -import { - Location, - Range, - SymbolInformation, - SymbolKind, - TextDocument, - TextEditor, - TextEditorRevealType, - Uri, -} from 'vscode'; -import { DocumentManager } from '../../../client/common/application/documentManager'; -import { IDocumentManager } from '../../../client/common/application/types'; -import { TestCollectionStorageService } from '../../../client/testing/common/services/storageService'; -import { ITestCollectionStorageService } from '../../../client/testing/common/types'; -import { TestNavigatorHelper } from '../../../client/testing/navigation/helper'; -import { TestSuiteCodeNavigator } from '../../../client/testing/navigation/suiteNavigator'; -import { ITestNavigatorHelper } from '../../../client/testing/navigation/types'; - -use(chaisAsPromised); - -suite('Unit Tests - Navigation Suite', () => { - let navigator: TestSuiteCodeNavigator; - let helper: ITestNavigatorHelper; - let docManager: IDocumentManager; - let doc: typemoq.IMock; - let editor: typemoq.IMock; - let storage: ITestCollectionStorageService; - setup(() => { - doc = typemoq.Mock.ofType(); - editor = typemoq.Mock.ofType(); - helper = mock(TestNavigatorHelper); - docManager = mock(DocumentManager); - storage = mock(TestCollectionStorageService); - navigator = new TestSuiteCodeNavigator(instance(helper), instance(docManager), instance(storage)); - }); - test('Ensure file is opened', async () => { - const filePath = Uri.file('some file Path'); - when(helper.openFile(anything())).thenResolve([doc.object, editor.object]); - const flattenedSuite = { parentTestFile: { fullPath: filePath.fsPath }, testSuite: {} }; - when(storage.findFlattendTestSuite(filePath, anything())).thenReturn(flattenedSuite as any); - - await navigator.navigateTo(filePath, {} as any); - - verify(helper.openFile(anything())).once(); - expect(capture(helper.openFile).first()[0]!.fsPath).to.equal(filePath.fsPath); - }); - test('Ensure errors are swallowed', async () => { - const filePath = Uri.file('some file Path'); - when(helper.openFile(anything())).thenReject(new Error('kaboom')); - const flattenedSuite = { parentTestFile: { fullPath: filePath.fsPath }, testSuite: {} }; - when(storage.findFlattendTestSuite(filePath, anything())).thenReturn(flattenedSuite as any); - - await navigator.navigateTo(filePath, {} as any); - - verify(helper.openFile(anything())).once(); - expect(capture(helper.openFile).first()[0]!.fsPath).to.equal(filePath.fsPath); - }); - async function navigateUsingLineFromSuite(focusCode: boolean) { - const filePath = Uri.file('some file Path'); - const line = 999; - when(helper.openFile(anything())).thenResolve([doc.object, editor.object]); - const flattenedSuite = { parentTestFile: { fullPath: filePath.fsPath }, testSuite: { name: 'suite_name' } }; - when(storage.findFlattendTestSuite(filePath, anything())).thenReturn(flattenedSuite as any); - const range = new Range(line, 0, line, 0); - const symbol: SymbolInformation = { - containerName: '', - kind: SymbolKind.Class, - name: 'suite_name', - location: new Location(Uri.file(__filename), range), - }; - when(helper.findSymbol(doc.object, anything(), anything())).thenResolve(symbol); - - await navigator.navigateTo(filePath, { name: 'suite_name' } as any, focusCode); - - verify(helper.openFile(anything())).once(); - verify(helper.findSymbol(doc.object, anything(), anything())).once(); - expect(capture(helper.openFile).first()[0]!.fsPath).to.equal(filePath.fsPath); - if (focusCode) { - verify( - docManager.showTextDocument(doc.object, deepEqual({ preserveFocus: false, selection: range })), - ).once(); - } else { - editor.verify((e) => e.revealRange(range, TextEditorRevealType.Default), typemoq.Times.once()); - } - } - test('Ensure we use line number from test suite when navigating in file (without focusing code)', async () => { - await navigateUsingLineFromSuite(false); - }); - test('Ensure we use line number from test suite when navigating in file (focusing code)', async () => { - await navigateUsingLineFromSuite(true); - }); - async function navigateFromSuite(focusCode: boolean) { - const filePath = Uri.file('some file Path'); - const line = 999; - when(helper.openFile(anything())).thenResolve([doc.object, editor.object]); - const flattenedSuite = { parentTestFile: { fullPath: filePath.fsPath }, testSuite: { line } }; - when(storage.findFlattendTestSuite(filePath, anything())).thenReturn(flattenedSuite as any); - const range = new Range(line, 0, line, 0); - - await navigator.navigateTo(filePath, { line } as any, focusCode); - - verify(helper.openFile(anything())).once(); - verify(helper.findSymbol(anything(), anything(), anything())).never(); - expect(capture(helper.openFile).first()[0]!.fsPath).to.equal(filePath.fsPath); - if (focusCode) { - verify( - docManager.showTextDocument(doc.object, deepEqual({ preserveFocus: false, selection: range })), - ).once(); - } else { - editor.verify((e) => e.revealRange(range, TextEditorRevealType.Default), typemoq.Times.once()); - } - } - test('Navigating in file (without focusing code)', async () => { - await navigateFromSuite(false); - }); - test('Navigating in file (focusing code)', async () => { - await navigateFromSuite(true); - }); - test('Ensure file is opened and range not revealed', async () => { - const filePath = Uri.file('some file Path'); - when(helper.openFile(anything())).thenResolve([doc.object, editor.object]); - const flattenedSuite = { parentTestFile: { fullPath: filePath.fsPath }, testSuite: {} }; - when(storage.findFlattendTestSuite(filePath, anything())).thenReturn(flattenedSuite as any); - const search = (s: SymbolInformation) => s.kind === SymbolKind.Class && s.name === 'Hello'; - when(helper.findSymbol(doc.object, search, anything())).thenResolve(); - - await navigator.navigateTo(filePath, {} as any); - - verify(helper.openFile(anything())).once(); - expect(capture(helper.openFile).first()[0]!.fsPath).to.equal(filePath.fsPath); - editor.verify((e) => e.revealRange(typemoq.It.isAny(), typemoq.It.isAny()), typemoq.Times.never()); - }); -}); From 34ddf557ed777ebb1b4982496d8356d3be7e2073 Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Mon, 24 May 2021 14:06:00 -0700 Subject: [PATCH 06/39] Removing view test ui and view test output commands (#16298) --- src/client/common/application/commands.ts | 2 -- src/client/common/constants.ts | 3 -- .../common/managers/baseTestManager.ts | 11 +------ src/client/testing/common/testUtils.ts | 23 ++------------ src/client/testing/common/types.ts | 4 --- src/client/testing/display/main.ts | 8 +---- src/client/testing/display/picker.ts | 27 ----------------- src/client/testing/main.ts | 30 ++----------------- .../common/trackEnablement.unit.test.ts | 3 +- src/test/testing/configuration.unit.test.ts | 2 +- src/test/testing/display/main.unit.test.ts | 13 -------- src/test/testing/display/picker.unit.test.ts | 10 ------- .../unittest/unittest.discovery.unit.test.ts | 14 ++++----- 13 files changed, 15 insertions(+), 135 deletions(-) diff --git a/src/client/common/application/commands.ts b/src/client/common/application/commands.ts index 6dea465e02a0..c7bd705757a3 100644 --- a/src/client/common/application/commands.ts +++ b/src/client/common/application/commands.ts @@ -40,7 +40,6 @@ interface ICommandNameWithoutArgumentTypeMapping { [Commands.Exec_Selection_In_Terminal]: []; [Commands.Exec_Selection_In_Django_Shell]: []; [Commands.Create_Terminal]: []; - [Commands.Tests_View_UI]: []; [Commands.Tests_Ask_To_Stop_Discovery]: []; [Commands.Tests_Ask_To_Stop_Test]: []; [Commands.Tests_Discovering]: []; @@ -95,7 +94,6 @@ export interface ICommandNameArgumentTypeMapping extends ICommandNameWithoutArgu [Commands.Sort_Imports]: [undefined, Uri]; [Commands.Exec_In_Terminal]: [undefined, Uri]; [Commands.Exec_In_Terminal_Icon]: [undefined, Uri]; - [Commands.Tests_ViewOutput]: [undefined, CommandSource]; [Commands.Tests_Select_And_Run_File]: [undefined, CommandSource]; [Commands.Tests_Run_Current_File]: [undefined, CommandSource]; [Commands.Tests_Stop]: [undefined, Uri]; diff --git a/src/client/common/constants.ts b/src/client/common/constants.ts index e0905f41ed65..cb07c28ba905 100644 --- a/src/client/common/constants.ts +++ b/src/client/common/constants.ts @@ -37,7 +37,6 @@ export namespace Commands { export const Exec_In_Terminal_Icon = 'python.execInTerminal-icon'; export const Exec_Selection_In_Terminal = 'python.execSelectionInTerminal'; export const Exec_Selection_In_Django_Shell = 'python.execSelectionInDjangoShell'; - export const Tests_View_UI = 'python.viewTestUI'; export const Tests_Picker_UI = 'python.selectTestToRun'; export const Tests_Picker_UI_Debug = 'python.selectTestToDebug'; export const Tests_Configure = 'python.configureTests'; @@ -94,8 +93,6 @@ export namespace Octicons { export const Star = '$(star)'; } -export const Button_Text_Tests_View_Output = 'View Output'; - export namespace Text { export const CodeLensRunUnitTest = 'Run Test'; export const CodeLensDebugUnitTest = 'Debug Test'; diff --git a/src/client/testing/common/managers/baseTestManager.ts b/src/client/testing/common/managers/baseTestManager.ts index fa20a9d72476..34f626bfd802 100644 --- a/src/client/testing/common/managers/baseTestManager.ts +++ b/src/client/testing/common/managers/baseTestManager.ts @@ -42,7 +42,6 @@ import { ITestManager, ITestNonPassingMessage, ITestResultsService, - ITestsHelper, ITestsStatusUpdaterService, TestDiscoveryOptions, Tests, @@ -254,21 +253,15 @@ export abstract class BaseTestManager implements ITestManager { this.updateStatus(TestStatus.Idle); this.discoverTestsPromise = undefined; - // have errors in Discovering - let haveErrorsInDiscovering = false; tests.testFiles.forEach((file) => { if (file.errorsWhenDiscovering && file.errorsWhenDiscovering.length > 0) { - haveErrorsInDiscovering = true; this.outputChannel.append('_'.repeat(10)); this.outputChannel.append(`There was an error in identifying unit tests in ${file.nameToRun}`); this.outputChannel.appendLine('_'.repeat(10)); this.outputChannel.appendLine(file.errorsWhenDiscovering); } }); - if (haveErrorsInDiscovering && !quietMode) { - const testsHelper = this.serviceContainer.get(ITestsHelper); - testsHelper.displayTestErrorMessage('There were some errors in discovering unit tests'); - } + this.disposeCancellationToken(CancellationTokenType.testDiscovery); sendTelemetryEvent(EventName.UNITTEST_DISCOVER, undefined, telementryProperties); return tests; @@ -384,8 +377,6 @@ export abstract class BaseTestManager implements ITestManager { ) { return Promise.reject(reason); } - const testsHelper = this.serviceContainer.get(ITestsHelper); - testsHelper.displayTestErrorMessage('Errors in discovering tests, continuing with tests'); return { rootTestFolders: [], testFiles: [], diff --git a/src/client/testing/common/testUtils.ts b/src/client/testing/common/testUtils.ts index 9331620af54c..99a7d38172e7 100644 --- a/src/client/testing/common/testUtils.ts +++ b/src/client/testing/common/testUtils.ts @@ -1,10 +1,8 @@ import { inject, injectable, named } from 'inversify'; import * as path from 'path'; import { Uri, workspace } from 'vscode'; -import { IApplicationShell, ICommandManager } from '../../common/application/types'; -import * as constants from '../../common/constants'; +import { IApplicationShell } from '../../common/application/types'; import { Product } from '../../common/types'; -import { IServiceContainer } from '../../ioc/types'; import { ITestingSettings, TestSettingsPropertyNames } from '../configuration/types'; import { TestProvider } from '../types'; import { TestFlatteningVisitor } from './testVisitors/flatteningVisitor'; @@ -46,15 +44,9 @@ export function convertFileToPackage(filePath: string): string { @injectable() export class TestsHelper implements ITestsHelper { - private readonly appShell: IApplicationShell; - private readonly commandManager: ICommandManager; constructor( @inject(ITestVisitor) @named('TestFlatteningVisitor') private readonly flatteningVisitor: TestFlatteningVisitor, - @inject(IServiceContainer) serviceContainer: IServiceContainer, - ) { - this.appShell = serviceContainer.get(IApplicationShell); - this.commandManager = serviceContainer.get(ICommandManager); - } + ) {} public parseProviderName(product: UnitTestProduct): TestProvider { switch (product) { case Product.pytest: @@ -215,17 +207,6 @@ export class TestsHelper implements ITestsHelper { ], }; } - public displayTestErrorMessage(message: string) { - this.appShell.showErrorMessage(message, constants.Button_Text_Tests_View_Output).then((action) => { - if (action === constants.Button_Text_Tests_View_Output) { - this.commandManager.executeCommand( - constants.Commands.Tests_ViewOutput, - undefined, - constants.CommandSource.ui, - ); - } - }); - } public mergeTests(items: Tests[]): Tests { return items.reduce((tests, otherTests, index) => { if (index === 0) { diff --git a/src/client/testing/common/types.ts b/src/client/testing/common/types.ts index acd481125069..934d79c563b7 100644 --- a/src/client/testing/common/types.ts +++ b/src/client/testing/common/types.ts @@ -300,7 +300,6 @@ export interface ITestManagementService { ): Promise; stopTests(resource: Uri): Promise; displayStopUI(message: string): Promise; - displayUI(cmdSource: CommandSource): Promise; displayPickerUI(cmdSource: CommandSource, file: Uri, testFunctions: TestFunction[], debug?: boolean): Promise; runTestsImpl( cmdSource: CommandSource, @@ -314,8 +313,6 @@ export interface ITestManagementService { selectAndRunTestFile(cmdSource: CommandSource): Promise; selectAndRunTestMethod(cmdSource: CommandSource, resource: Uri, debug?: boolean): Promise; - - viewOutput(cmdSource: CommandSource): void; } export interface ITestManagerService extends Disposable { @@ -381,7 +378,6 @@ export interface ITestsHelper { getSettingsPropertyNames(product: Product): TestSettingsPropertyNames; flattenTestFiles(testFiles: TestFile[], workspaceFolder: string): Tests; placeTestFilesIntoFolders(tests: Tests, workspaceFolder: string): void; - displayTestErrorMessage(message: string): void; shouldRunAllTests(testsToRun?: TestsToRun): boolean; mergeTests(items: Tests[]): Tests; } diff --git a/src/client/testing/display/main.ts b/src/client/testing/display/main.ts index c4928b18f3ac..7374f2458fae 100644 --- a/src/client/testing/display/main.ts +++ b/src/client/testing/display/main.ts @@ -13,7 +13,7 @@ import { IServiceContainer } from '../../ioc/types'; import { captureTelemetry } from '../../telemetry'; import { EventName } from '../../telemetry/constants'; import { CANCELLATION_REASON } from '../common/constants'; -import { ITestsHelper, ITestResultDisplay, Tests } from '../common/types'; +import { ITestResultDisplay, Tests } from '../common/types'; @injectable() export class TestResultDisplay implements ITestResultDisplay { @@ -25,7 +25,6 @@ export class TestResultDisplay implements ITestResultDisplay { private progressPrefix!: string; private readonly didChange = new EventEmitter(); private readonly appShell: IApplicationShell; - private readonly testsHelper: ITestsHelper; private readonly cmdManager: ICommandManager; public get onDidChange(): Event { return this.didChange.event; @@ -34,7 +33,6 @@ export class TestResultDisplay implements ITestResultDisplay { constructor(@inject(IServiceContainer) private serviceContainer: IServiceContainer) { this.appShell = serviceContainer.get(IApplicationShell); this.statusBar = this.appShell.createStatusBarItem(StatusBarAlignment.Left); - this.testsHelper = serviceContainer.get(ITestsHelper); this.cmdManager = serviceContainer.get(ICommandManager); } public dispose() { @@ -106,7 +104,6 @@ export class TestResultDisplay implements ITestResultDisplay { } this.statusBar.tooltip = toolTip.length === 0 ? 'No Tests Ran' : `${toolTip.join(', ')} (Tests)`; this.statusBar.text = statusText.length === 0 ? 'No Tests Ran' : statusText.join(' '); - this.statusBar.command = constants.Commands.Tests_View_UI; this.didChange.fire(); if (statusText.length === 0 && !debug) { this.appShell.showWarningMessage('No tests ran, please check the configuration settings for the tests.'); @@ -116,14 +113,12 @@ export class TestResultDisplay implements ITestResultDisplay { private updateTestRunWithFailure(reason: any): Promise { this.clearProgressTicker(); - this.statusBar.command = constants.Commands.Tests_View_UI; if (reason === CANCELLATION_REASON) { this.statusBar.text = '$(zap) Run Tests'; this.statusBar.tooltip = 'Run Tests'; } else { this.statusBar.text = '$(alert) Tests Failed'; this.statusBar.tooltip = 'Running Tests Failed'; - this.testsHelper.displayTestErrorMessage('There was an error in running the tests.'); } return Promise.reject(reason); } @@ -165,7 +160,6 @@ export class TestResultDisplay implements ITestResultDisplay { const haveTests = tests && tests.testFunctions.length > 0; this.statusBar.text = '$(zap) Run Tests'; this.statusBar.tooltip = 'Run Tests'; - this.statusBar.command = constants.Commands.Tests_View_UI; this.statusBar.show(); if (this.didChange) { this.didChange.fire(); diff --git a/src/client/testing/display/picker.ts b/src/client/testing/display/picker.ts index cd50ff544173..81ac389410fe 100644 --- a/src/client/testing/display/picker.ts +++ b/src/client/testing/display/picker.ts @@ -116,7 +116,6 @@ export enum Type { RunFile = 4, RunClass = 5, RunMethod = 6, - ViewTestOutput = 7, Null = 8, SelectAndRunMethod = 9, DebugMethod = 10, @@ -140,26 +139,6 @@ type TestFileItem = QuickPickItem & { testFile?: TestFile; }; -function getSummary(tests?: Tests) { - if (!tests || !tests.summary) { - return ''; - } - const statusText: string[] = []; - if (tests.summary.passed > 0) { - statusText.push(`${constants.Octicons.Test_Pass} ${tests.summary.passed} Passed`); - } - if (tests.summary.failures > 0) { - statusText.push(`${constants.Octicons.Test_Fail} ${tests.summary.failures} Failed`); - } - if (tests.summary.errors > 0) { - const plural = tests.summary.errors === 1 ? '' : 's'; - statusText.push(`${constants.Octicons.Test_Error} ${tests.summary.errors} Error${plural}`); - } - if (tests.summary.skipped > 0) { - statusText.push(`${constants.Octicons.Test_Skip} ${tests.summary.skipped} Skipped`); - } - return statusText.join(', ').trim(); -} function buildItems(tests?: Tests): TestItem[] { const items: TestItem[] = []; items.push({ description: '', label: 'Run All Tests', type: Type.RunAll }); @@ -167,9 +146,6 @@ function buildItems(tests?: Tests): TestItem[] { items.push({ description: '', label: 'Run Test Method ...', type: Type.SelectAndRunMethod }); items.push({ description: '', label: 'Configure Tests', type: Type.Configure }); - const summary = getSummary(tests); - items.push({ description: '', label: 'View Test Output', type: Type.ViewTestOutput, detail: summary }); - if (tests && tests.summary.failures > 0) { items.push({ description: '', @@ -310,9 +286,6 @@ export function onItemSelected( case Type.ReDiscover: { return commandManager.executeCommand(constants.Commands.Tests_Discover, undefined, cmdSource, wkspace); } - case Type.ViewTestOutput: { - return commandManager.executeCommand(constants.Commands.Tests_ViewOutput, undefined, cmdSource); - } case Type.RunFailed: { return commandManager.executeCommand(constants.Commands.Tests_Run_Failed, undefined, cmdSource, wkspace); } diff --git a/src/client/testing/main.ts b/src/client/testing/main.ts index 7e20f09274c9..8289fb1f963e 100644 --- a/src/client/testing/main.ts +++ b/src/client/testing/main.ts @@ -277,21 +277,7 @@ export class UnitTestManagementService implements ITestManagementService, Dispos const testDisplay = this.serviceContainer.get(ITestDisplay); testDisplay.displayStopTestUI(testManager.workspaceFolder, message); } - public async displayUI(cmdSource: constants.CommandSource) { - const testManager = await this.getTestManager(true); - if (!testManager) { - return; - } - - const testDisplay = this.serviceContainer.get(ITestDisplay); - testDisplay.displayTestUI(cmdSource, testManager.workspaceFolder); - } - public async displayPickerUI( - cmdSource: constants.CommandSource, - file: Uri, - testFunctions: TestFunction[], - debug?: boolean, - ) { + public async displayPickerUI(cmdSource: CommandSource, file: Uri, testFunctions: TestFunction[], debug?: boolean) { const testManager = await this.getTestManager(true, file); if (!testManager) { return; @@ -319,11 +305,7 @@ export class UnitTestManagementService implements ITestManagementService, Dispos } await this.runTestsImpl(cmdSource, resource, { testFunction: testFunctions }, undefined, debug); } - public viewOutput(_cmdSource: constants.CommandSource) { - sendTelemetryEvent(EventName.UNITTEST_VIEW_OUTPUT); - this.outputChannel.show(); - } - public async selectAndRunTestMethod(cmdSource: constants.CommandSource, resource: Uri, debug?: boolean) { + public async selectAndRunTestMethod(cmdSource: CommandSource, resource: Uri, debug?: boolean) { const testManager = await this.getTestManager(true, resource); if (!testManager) { return; @@ -509,9 +491,6 @@ export class UnitTestManagementService implements ITestManagementService, Dispos return this.runTestsImpl(cmdSource, resource, testToRun, false, true); }, ), - commandManager.registerCommand(constants.Commands.Tests_View_UI, () => - this.displayUI(constants.CommandSource.commandPalette), - ), commandManager.registerCommand( constants.Commands.Tests_Picker_UI, ( @@ -543,11 +522,6 @@ export class UnitTestManagementService implements ITestManagementService, Dispos commandManager.registerCommand(constants.Commands.Tests_Stop, (_, resource: Uri) => this.stopTests(resource), ), - commandManager.registerCommand( - constants.Commands.Tests_ViewOutput, - (_, cmdSource: constants.CommandSource = constants.CommandSource.commandPalette) => - this.viewOutput(cmdSource), - ), commandManager.registerCommand(constants.Commands.Tests_Ask_To_Stop_Discovery, () => this.displayStopUI('Stop discovering tests'), ), diff --git a/src/test/testing/common/trackEnablement.unit.test.ts b/src/test/testing/common/trackEnablement.unit.test.ts index d1b7c647103f..d45f3280a412 100644 --- a/src/test/testing/common/trackEnablement.unit.test.ts +++ b/src/test/testing/common/trackEnablement.unit.test.ts @@ -9,7 +9,6 @@ import { anything, instance, mock, verify, when } from 'ts-mockito'; import { IWorkspaceService } from '../../../client/common/application/types'; import { WorkspaceService } from '../../../client/common/application/workspace'; import { Product } from '../../../client/common/types'; -import { ServiceContainer } from '../../../client/ioc/container'; import { EnablementTracker } from '../../../client/testing/common/enablementTracker'; import { TestConfigSettingsService } from '../../../client/testing/common/services/configSettingService'; import { TestsHelper } from '../../../client/testing/common/testUtils'; @@ -28,7 +27,7 @@ suite('Unit Tests - Track Enablement', () => { sandbox.restore(); workspaceService = mock(WorkspaceService); configService = mock(TestConfigSettingsService); - testsHelper = new TestsHelper(instance(mock(TestFlatteningVisitor)), instance(mock(ServiceContainer))); + testsHelper = new TestsHelper(instance(mock(TestFlatteningVisitor))); }); teardown(() => { sandbox.restore(); diff --git a/src/test/testing/configuration.unit.test.ts b/src/test/testing/configuration.unit.test.ts index 58f9a5b452ac..96c627d13fce 100644 --- a/src/test/testing/configuration.unit.test.ts +++ b/src/test/testing/configuration.unit.test.ts @@ -82,7 +82,7 @@ suite('Unit Tests - ConfigurationService', () => { const flattener = typeMoq.Mock.ofType(undefined, typeMoq.MockBehavior.Strict); serviceContainer .setup((c) => c.get(typeMoq.It.isValue(ITestsHelper))) - .returns(() => new TestsHelper(flattener.object, serviceContainer.object)); + .returns(() => new TestsHelper(flattener.object)); testConfigService = typeMoq.Mock.ofType( UnitTestConfigurationService, typeMoq.MockBehavior.Loose, diff --git a/src/test/testing/display/main.unit.test.ts b/src/test/testing/display/main.unit.test.ts index b9bc80dc0640..ceda525268fb 100644 --- a/src/test/testing/display/main.unit.test.ts +++ b/src/test/testing/display/main.unit.test.ts @@ -166,7 +166,6 @@ suite('Unit Tests - TestResultDisplay', () => { tests.verifyAll(); appShell.verifyAll(); - statusBar.verify((s) => (s.command = typeMoq.It.isValue(Commands.Tests_View_UI)), typeMoq.Times.atLeastOnce()); }); test('Ensure status bar is updated with success with ability to view ui with results', async () => { const statusBar = typeMoq.Mock.ofType(); @@ -210,7 +209,6 @@ suite('Unit Tests - TestResultDisplay', () => { tests.verifyAll(); appShell.verifyAll(); - statusBar.verify((s) => (s.command = typeMoq.It.isValue(Commands.Tests_View_UI)), typeMoq.Times.atLeastOnce()); }); test('Ensure status bar is updated with error when cancelled by user with ability to view ui with results', async () => { const statusBar = typeMoq.Mock.ofType(); @@ -233,14 +231,10 @@ suite('Unit Tests - TestResultDisplay', () => { ); statusBar.verify((s) => (s.text = typeMoq.It.isValue('$(stop) Running Tests')), typeMoq.Times.atLeastOnce()); - testsHelper.setup((t) => t.displayTestErrorMessage(typeMoq.It.isAny())).verifiable(typeMoq.Times.never()); - def.reject(CANCELLATION_REASON); await sleep(1); appShell.verifyAll(); - statusBar.verify((s) => (s.command = typeMoq.It.isValue(Commands.Tests_View_UI)), typeMoq.Times.atLeastOnce()); - testsHelper.verifyAll(); }); test('Ensure status bar is updated, and error message display with error in running tests, with ability to view ui with results', async () => { const statusBar = typeMoq.Mock.ofType(); @@ -263,14 +257,10 @@ suite('Unit Tests - TestResultDisplay', () => { ); statusBar.verify((s) => (s.text = typeMoq.It.isValue('$(stop) Running Tests')), typeMoq.Times.atLeastOnce()); - testsHelper.setup((t) => t.displayTestErrorMessage(typeMoq.It.isAny())).verifiable(typeMoq.Times.once()); - def.reject('Some other reason'); await sleep(1); appShell.verifyAll(); - statusBar.verify((s) => (s.command = typeMoq.It.isValue(Commands.Tests_View_UI)), typeMoq.Times.atLeastOnce()); - testsHelper.verifyAll(); }); test('Ensure status bar is displayed and updated with progress with ability to stop test discovery', async () => { @@ -337,7 +327,6 @@ suite('Unit Tests - TestResultDisplay', () => { tests.verifyAll(); appShell.verifyAll(); - statusBar.verify((s) => (s.command = typeMoq.It.isValue(Commands.Tests_View_UI)), typeMoq.Times.atLeastOnce()); }); test('Ensure tests are disabled when there are errors and user choses to disable tests', async () => { const statusBar = typeMoq.Mock.ofType(); @@ -395,7 +384,6 @@ suite('Unit Tests - TestResultDisplay', () => { tests.verifyAll(); appShell.verifyAll(); - statusBar.verify((s) => (s.command = typeMoq.It.isValue(Commands.Tests_View_UI)), typeMoq.Times.atLeastOnce()); configurationService.verifyAll(); cmdManager.verifyAll(); }); @@ -453,7 +441,6 @@ suite('Unit Tests - TestResultDisplay', () => { tests.verifyAll(); appShell.verifyAll(); - statusBar.verify((s) => (s.command = typeMoq.It.isValue(Commands.Tests_View_UI)), typeMoq.Times.atLeastOnce()); cmdManager.verifyAll(); }); test('Ensure status bar is displayed and updated with error info when test discovery is cancelled by the user', async () => { diff --git a/src/test/testing/display/picker.unit.test.ts b/src/test/testing/display/picker.unit.test.ts index cba35d852dfe..1d1c656eb27e 100644 --- a/src/test/testing/display/picker.unit.test.ts +++ b/src/test/testing/display/picker.unit.test.ts @@ -102,16 +102,6 @@ suite('Unit Tests - Picker (execution of commands)', () => { ).once(); return; } - case Type.ViewTestOutput: { - verify( - commandManager.executeCommand( - Commands.Tests_ViewOutput, - undefined, - commandSource.value, - ), - ).once(); - return; - } case Type.RunFailed: { verify( commandManager.executeCommand( diff --git a/src/test/testing/unittest/unittest.discovery.unit.test.ts b/src/test/testing/unittest/unittest.discovery.unit.test.ts index 86d19299390f..9d5b00fac89b 100644 --- a/src/test/testing/unittest/unittest.discovery.unit.test.ts +++ b/src/test/testing/unittest/unittest.discovery.unit.test.ts @@ -360,7 +360,7 @@ suite('Unit Tests - Unittest - Discovery', () => { testParser.verifyAll(); }); test('Ensure discovery resolves test suites in n-depth directories', async () => { - const testHelper: TestsHelper = new TestsHelper(new TestFlatteningVisitor(), serviceContainer.object); + const testHelper: TestsHelper = new TestsHelper(new TestFlatteningVisitor()); const testsParser: TestsParser = new TestsParser(testHelper); @@ -407,7 +407,7 @@ suite('Unit Tests - Unittest - Discovery', () => { }); }); test('Ensure discovery resolves test files in n-depth directories', async () => { - const testHelper: TestsHelper = new TestsHelper(new TestFlatteningVisitor(), serviceContainer.object); + const testHelper: TestsHelper = new TestsHelper(new TestFlatteningVisitor()); const testsParser: TestsParser = new TestsParser(testHelper); @@ -467,7 +467,7 @@ suite('Unit Tests - Unittest - Discovery', () => { }); test('Ensure discovery resolves test suites in n-depth directories when no start directory is given', async () => { - const testHelper: TestsHelper = new TestsHelper(new TestFlatteningVisitor(), serviceContainer.object); + const testHelper: TestsHelper = new TestsHelper(new TestFlatteningVisitor()); const testsParser: TestsParser = new TestsParser(testHelper); @@ -514,7 +514,7 @@ suite('Unit Tests - Unittest - Discovery', () => { }); }); test('Ensure discovery resolves test suites in n-depth directories when a relative start directory is given', async () => { - const testHelper: TestsHelper = new TestsHelper(new TestFlatteningVisitor(), serviceContainer.object); + const testHelper: TestsHelper = new TestsHelper(new TestFlatteningVisitor()); const testsParser: TestsParser = new TestsParser(testHelper); @@ -561,7 +561,7 @@ suite('Unit Tests - Unittest - Discovery', () => { }); }); test('Ensure discovery will not fail with blank content', async () => { - const testHelper: TestsHelper = new TestsHelper(new TestFlatteningVisitor(), serviceContainer.object); + const testHelper: TestsHelper = new TestsHelper(new TestFlatteningVisitor()); const testsParser: TestsParser = new TestsParser(testHelper); @@ -582,7 +582,7 @@ suite('Unit Tests - Unittest - Discovery', () => { expect(tests.testFolders.length).to.be.equal(0); }); test('Ensure discovery will not fail with corrupt content', async () => { - const testHelper: TestsHelper = new TestsHelper(new TestFlatteningVisitor(), serviceContainer.object); + const testHelper: TestsHelper = new TestsHelper(new TestFlatteningVisitor()); const testsParser: TestsParser = new TestsParser(testHelper); @@ -611,7 +611,7 @@ suite('Unit Tests - Unittest - Discovery', () => { expect(tests.testFolders.length).to.be.equal(0); }); test('Ensure discovery resolves when no tests are found in the given path', async () => { - const testHelper: TestsHelper = new TestsHelper(new TestFlatteningVisitor(), serviceContainer.object); + const testHelper: TestsHelper = new TestsHelper(new TestFlatteningVisitor()); const testsParser: TestsParser = new TestsParser(testHelper); From 2be18de96d9a9676463fbb1de9142a8d68041e86 Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Mon, 24 May 2021 15:05:59 -0700 Subject: [PATCH 07/39] Remove test picker (#16300) --- src/client/testing/display/main.ts | 207 ------- src/client/testing/display/picker.ts | 325 ----------- src/client/testing/serviceRegistry.ts | 6 - src/test/testing/display/main.unit.test.ts | 512 ------------------ .../testing/display/picker.functional.test.ts | 131 ----- src/test/testing/display/picker.unit.test.ts | 255 --------- 6 files changed, 1436 deletions(-) delete mode 100644 src/client/testing/display/main.ts delete mode 100644 src/client/testing/display/picker.ts delete mode 100644 src/test/testing/display/main.unit.test.ts delete mode 100644 src/test/testing/display/picker.functional.test.ts delete mode 100644 src/test/testing/display/picker.unit.test.ts diff --git a/src/client/testing/display/main.ts b/src/client/testing/display/main.ts deleted file mode 100644 index 7374f2458fae..000000000000 --- a/src/client/testing/display/main.ts +++ /dev/null @@ -1,207 +0,0 @@ -'use strict'; -import { inject, injectable } from 'inversify'; -import { clearInterval, setInterval } from 'timers'; -import { Event, EventEmitter, StatusBarAlignment, StatusBarItem } from 'vscode'; -import { IApplicationShell, ICommandManager } from '../../common/application/types'; -import * as constants from '../../common/constants'; -import { isNotInstalledError } from '../../common/helpers'; -import { traceError } from '../../common/logger'; -import { IConfigurationService } from '../../common/types'; -import { Testing } from '../../common/utils/localize'; -import { noop } from '../../common/utils/misc'; -import { IServiceContainer } from '../../ioc/types'; -import { captureTelemetry } from '../../telemetry'; -import { EventName } from '../../telemetry/constants'; -import { CANCELLATION_REASON } from '../common/constants'; -import { ITestResultDisplay, Tests } from '../common/types'; - -@injectable() -export class TestResultDisplay implements ITestResultDisplay { - private statusBar: StatusBarItem; - private discoverCounter = 0; - private ticker = ['|', '/', '-', '|', '/', '-', '\\']; - private progressTimeout: NodeJS.Timer | null = null; - private _enabled: boolean = false; - private progressPrefix!: string; - private readonly didChange = new EventEmitter(); - private readonly appShell: IApplicationShell; - private readonly cmdManager: ICommandManager; - public get onDidChange(): Event { - return this.didChange.event; - } - - constructor(@inject(IServiceContainer) private serviceContainer: IServiceContainer) { - this.appShell = serviceContainer.get(IApplicationShell); - this.statusBar = this.appShell.createStatusBarItem(StatusBarAlignment.Left); - this.cmdManager = serviceContainer.get(ICommandManager); - } - public dispose() { - this.clearProgressTicker(); - this.statusBar.dispose(); - } - public get enabled() { - return this._enabled; - } - public set enabled(enable: boolean) { - this._enabled = enable; - if (enable) { - this.statusBar.show(); - } else { - this.statusBar.hide(); - } - } - public displayProgressStatus(testRunResult: Promise, debug: boolean = false) { - this.displayProgress( - 'Running Tests', - 'Running Tests (Click to Stop)', - constants.Commands.Tests_Ask_To_Stop_Test, - ); - testRunResult - .then((tests) => this.updateTestRunWithSuccess(tests, debug)) - .catch(this.updateTestRunWithFailure.bind(this)) - // We don't care about any other exceptions returned by updateTestRunWithFailure - .catch(noop); - } - public displayDiscoverStatus(testDiscovery: Promise, quietMode: boolean = false) { - this.displayProgress( - 'Discovering Tests', - 'Discovering tests (click to stop)', - constants.Commands.Tests_Ask_To_Stop_Discovery, - ); - return testDiscovery - .then((tests) => { - this.updateWithDiscoverSuccess(tests, quietMode); - return tests; - }) - .catch((reason) => { - this.updateWithDiscoverFailure(reason); - return Promise.reject(reason); - }); - } - - private updateTestRunWithSuccess(tests: Tests, debug: boolean = false): Tests { - this.clearProgressTicker(); - - // Treat errors as a special case, as we generally wouldn't have any errors - const statusText: string[] = []; - const toolTip: string[] = []; - - if (tests.summary.passed > 0) { - statusText.push(`${constants.Octicons.Test_Pass} ${tests.summary.passed}`); - toolTip.push(`${tests.summary.passed} Passed`); - } - if (tests.summary.skipped > 0) { - statusText.push(`${constants.Octicons.Test_Skip} ${tests.summary.skipped}`); - toolTip.push(`${tests.summary.skipped} Skipped`); - } - if (tests.summary.failures > 0) { - statusText.push(`${constants.Octicons.Test_Fail} ${tests.summary.failures}`); - toolTip.push(`${tests.summary.failures} Failed`); - } - if (tests.summary.errors > 0) { - statusText.push(`${constants.Octicons.Test_Error} ${tests.summary.errors}`); - toolTip.push(`${tests.summary.errors} Error${tests.summary.errors > 1 ? 's' : ''}`); - } - this.statusBar.tooltip = toolTip.length === 0 ? 'No Tests Ran' : `${toolTip.join(', ')} (Tests)`; - this.statusBar.text = statusText.length === 0 ? 'No Tests Ran' : statusText.join(' '); - this.didChange.fire(); - if (statusText.length === 0 && !debug) { - this.appShell.showWarningMessage('No tests ran, please check the configuration settings for the tests.'); - } - return tests; - } - - private updateTestRunWithFailure(reason: any): Promise { - this.clearProgressTicker(); - if (reason === CANCELLATION_REASON) { - this.statusBar.text = '$(zap) Run Tests'; - this.statusBar.tooltip = 'Run Tests'; - } else { - this.statusBar.text = '$(alert) Tests Failed'; - this.statusBar.tooltip = 'Running Tests Failed'; - } - return Promise.reject(reason); - } - - private displayProgress(message: string, tooltip: string, command: string) { - this.progressPrefix = this.statusBar.text = `$(stop) ${message}`; - this.statusBar.command = command; - this.statusBar.tooltip = tooltip; - this.statusBar.show(); - this.clearProgressTicker(); - this.progressTimeout = setInterval(() => this.updateProgressTicker(), 1000); - } - private updateProgressTicker() { - const text = `${this.progressPrefix} ${this.ticker[this.discoverCounter % 7]}`; - this.discoverCounter += 1; - this.statusBar.text = text; - } - private clearProgressTicker() { - if (this.progressTimeout) { - clearInterval(this.progressTimeout); - } - this.progressTimeout = null; - this.discoverCounter = 0; - } - - @captureTelemetry(EventName.UNITTEST_DISABLE) - private async disableTests(): Promise { - const configurationService = this.serviceContainer.get(IConfigurationService); - const settingsToDisable = ['testing.promptToConfigure', 'testing.pytestEnabled', 'testing.unittestEnabled']; - - for (const setting of settingsToDisable) { - await configurationService.updateSetting(setting, false).catch(noop); - } - this.cmdManager.executeCommand('setContext', 'testsDiscovered', false); - } - - private updateWithDiscoverSuccess(tests: Tests, quietMode: boolean = false) { - this.clearProgressTicker(); - const haveTests = tests && tests.testFunctions.length > 0; - this.statusBar.text = '$(zap) Run Tests'; - this.statusBar.tooltip = 'Run Tests'; - this.statusBar.show(); - if (this.didChange) { - this.didChange.fire(); - } - - if (!haveTests && !quietMode) { - this.appShell - .showInformationMessage( - 'No tests discovered, please check the configuration settings for the tests.', - Testing.disableTests(), - Testing.configureTests(), - ) - .then((item) => { - if (item === Testing.disableTests()) { - this.disableTests().catch((ex) => traceError('Python Extension: disableTests', ex)); - } else if (item === Testing.configureTests()) { - this.cmdManager - .executeCommand(constants.Commands.Tests_Configure, undefined, undefined, undefined) - .then(noop); - } - }); - } - } - - private updateWithDiscoverFailure(reason: any) { - this.clearProgressTicker(); - this.statusBar.text = '$(zap) Discover Tests'; - this.statusBar.tooltip = 'Discover Tests'; - this.statusBar.command = constants.Commands.Tests_Discover; - this.statusBar.show(); - if (reason !== CANCELLATION_REASON) { - this.statusBar.text = '$(alert) Test discovery failed'; - this.statusBar.tooltip = "Discovering Tests failed (view 'Python Test Log' output panel for details)"; - - // TODO: ignore this quitemode, always display the error message (inform the user). - if (!isNotInstalledError(reason)) { - // TODO: show an option that will invoke a command 'python.test.configureTest' or similar. - // This will be hanlded by main.ts that will capture input from user and configure the tests. - this.appShell.showErrorMessage( - 'Test discovery error, please check the configuration settings for the tests.', - ); - } - } - } -} diff --git a/src/client/testing/display/picker.ts b/src/client/testing/display/picker.ts deleted file mode 100644 index 81ac389410fe..000000000000 --- a/src/client/testing/display/picker.ts +++ /dev/null @@ -1,325 +0,0 @@ -import { inject, injectable } from 'inversify'; -import * as path from 'path'; -import { QuickPickItem, Uri } from 'vscode'; -import { IApplicationShell, ICommandManager } from '../../common/application/types'; -import * as constants from '../../common/constants'; -import { IFileSystem } from '../../common/platform/types'; -import { IServiceContainer } from '../../ioc/types'; -import { - FlattenedTestFunction, - ITestCollectionStorageService, - ITestDisplay, - TestFile, - TestFunction, - Tests, - TestStatus, - TestsToRun, -} from '../common/types'; - -@injectable() -export class TestDisplay implements ITestDisplay { - private readonly testCollectionStorage: ITestCollectionStorageService; - private readonly appShell: IApplicationShell; - constructor( - @inject(IServiceContainer) private readonly serviceRegistry: IServiceContainer, - @inject(ICommandManager) private readonly commandManager: ICommandManager, - ) { - this.testCollectionStorage = serviceRegistry.get(ITestCollectionStorageService); - this.appShell = serviceRegistry.get(IApplicationShell); - } - public displayStopTestUI(workspace: Uri, message: string) { - this.appShell.showQuickPick([message]).then((item) => { - if (item === message) { - this.commandManager.executeCommand(constants.Commands.Tests_Stop, undefined, workspace); - } - }); - } - public displayTestUI(cmdSource: constants.CommandSource, wkspace: Uri) { - const tests = this.testCollectionStorage.getTests(wkspace); - this.appShell - .showQuickPick(buildItems(tests), { matchOnDescription: true, matchOnDetail: true }) - .then((item) => - item ? onItemSelected(this.commandManager, cmdSource, wkspace, item, false) : Promise.resolve(), - ); - } - public selectTestFunction(rootDirectory: string, tests: Tests): Promise { - return new Promise((resolve, reject) => { - this.appShell - .showQuickPick(buildItemsForFunctions(rootDirectory, tests.testFunctions), { - matchOnDescription: true, - matchOnDetail: true, - }) - .then((item) => { - if (item && item.fn) { - return resolve(item.fn); - } - return reject(); - }, reject); - }); - } - public selectTestFile(rootDirectory: string, tests: Tests): Promise { - return new Promise((resolve, reject) => { - this.appShell - .showQuickPick(buildItemsForTestFiles(rootDirectory, tests.testFiles), { - matchOnDescription: true, - matchOnDetail: true, - }) - .then((item) => { - if (item && item.testFile) { - return resolve(item.testFile); - } - return reject(); - }, reject); - }); - } - public displayFunctionTestPickerUI( - cmdSource: constants.CommandSource, - wkspace: Uri, - rootDirectory: string, - file: Uri, - testFunctions: TestFunction[], - debug?: boolean, - ) { - const tests = this.testCollectionStorage.getTests(wkspace); - if (!tests) { - return; - } - const fileName = file.fsPath; - const fs = this.serviceRegistry.get(IFileSystem); - const testFile = tests.testFiles.find( - (item) => item.name === fileName || fs.arePathsSame(item.fullPath, fileName), - ); - if (!testFile) { - return; - } - const flattenedFunctions = tests.testFunctions.filter((fn) => { - return ( - fn.parentTestFile.name === testFile.name && - testFunctions.some((testFunc) => testFunc.nameToRun === fn.testFunction.nameToRun) - ); - }); - const runAllItem = buildRunAllParametrizedItem(flattenedFunctions, debug); - const functionItems = buildItemsForFunctions(rootDirectory, flattenedFunctions, undefined, undefined, debug); - this.appShell - .showQuickPick(runAllItem.concat(...functionItems), { matchOnDescription: true, matchOnDetail: true }) - .then((testItem) => - testItem ? onItemSelected(this.commandManager, cmdSource, wkspace, testItem, debug) : Promise.resolve(), - ); - } -} - -export enum Type { - RunAll = 0, - ReDiscover = 1, - RunFailed = 2, - RunFolder = 3, - RunFile = 4, - RunClass = 5, - RunMethod = 6, - Null = 8, - SelectAndRunMethod = 9, - DebugMethod = 10, - Configure = 11, - RunParametrized = 12, -} -const statusIconMapping = new Map(); -statusIconMapping.set(TestStatus.Pass, constants.Octicons.Test_Pass); -statusIconMapping.set(TestStatus.Fail, constants.Octicons.Test_Fail); -statusIconMapping.set(TestStatus.Error, constants.Octicons.Test_Error); -statusIconMapping.set(TestStatus.Skipped, constants.Octicons.Test_Skip); - -type TestItem = QuickPickItem & { - type: Type; - fn?: FlattenedTestFunction; - fns?: TestFunction[]; -}; - -type TestFileItem = QuickPickItem & { - type: Type; - testFile?: TestFile; -}; - -function buildItems(tests?: Tests): TestItem[] { - const items: TestItem[] = []; - items.push({ description: '', label: 'Run All Tests', type: Type.RunAll }); - items.push({ description: '', label: 'Discover Tests', type: Type.ReDiscover }); - items.push({ description: '', label: 'Run Test Method ...', type: Type.SelectAndRunMethod }); - items.push({ description: '', label: 'Configure Tests', type: Type.Configure }); - - if (tests && tests.summary.failures > 0) { - items.push({ - description: '', - label: 'Run Failed Tests', - type: Type.RunFailed, - detail: `${constants.Octicons.Test_Fail} ${tests.summary.failures} Failed`, - }); - } - - return items; -} - -const statusSortPrefix = { - [TestStatus.Error]: '1', - [TestStatus.Fail]: '2', - [TestStatus.Skipped]: '3', - [TestStatus.Pass]: '4', - [TestStatus.Discovering]: undefined, - [TestStatus.Idle]: undefined, - [TestStatus.Running]: undefined, - [TestStatus.Unknown]: undefined, -}; - -function buildRunAllParametrizedItem(tests: FlattenedTestFunction[], debug: boolean = false): TestItem[] { - const testFunctions: TestFunction[] = []; - tests.forEach((fn) => { - testFunctions.push(fn.testFunction); - }); - return [ - { - description: '', - label: debug ? 'Debug All' : 'Run All', - type: Type.RunParametrized, - fns: testFunctions, - }, - ]; -} -function buildItemsForFunctions( - rootDirectory: string, - tests: FlattenedTestFunction[], - sortBasedOnResults: boolean = false, - displayStatusIcons: boolean = false, - debug: boolean = false, -): TestItem[] { - const functionItems: TestItem[] = []; - tests.forEach((fn) => { - let icon = ''; - if (displayStatusIcons && fn.testFunction.status && statusIconMapping.has(fn.testFunction.status)) { - icon = `${statusIconMapping.get(fn.testFunction.status)} `; - } - - functionItems.push({ - description: '', - detail: path.relative(rootDirectory, fn.parentTestFile.fullPath), - label: icon + fn.testFunction.name, - type: debug === true ? Type.DebugMethod : Type.RunMethod, - fn: fn, - }); - }); - functionItems.sort((a, b) => { - let sortAPrefix = '5-'; - let sortBPrefix = '5-'; - if (sortBasedOnResults && a.fn && a.fn.testFunction.status && b.fn && b.fn.testFunction.status) { - sortAPrefix = statusSortPrefix[a.fn.testFunction.status] - ? statusSortPrefix[a.fn.testFunction.status]! - : sortAPrefix; - sortBPrefix = statusSortPrefix[b.fn.testFunction.status] - ? statusSortPrefix[b.fn.testFunction.status]! - : sortBPrefix; - } - if (`${sortAPrefix}${a.detail}${a.label}` < `${sortBPrefix}${b.detail}${b.label}`) { - return -1; - } - if (`${sortAPrefix}${a.detail}${a.label}` > `${sortBPrefix}${b.detail}${b.label}`) { - return 1; - } - return 0; - }); - return functionItems; -} -function buildItemsForTestFiles(rootDirectory: string, testFiles: TestFile[]): TestFileItem[] { - const fileItems: TestFileItem[] = testFiles.map((testFile) => { - return { - description: '', - detail: path.relative(rootDirectory, testFile.fullPath), - type: Type.RunFile, - label: path.basename(testFile.fullPath), - testFile: testFile, - }; - }); - fileItems.sort((a, b) => { - if (!a.detail && !b.detail) { - return 0; - } - if (!a.detail || a.detail < b.detail!) { - return -1; - } - if (!b.detail || a.detail! > b.detail) { - return 1; - } - return 0; - }); - return fileItems; -} -export function onItemSelected( - commandManager: ICommandManager, - cmdSource: constants.CommandSource, - wkspace: Uri, - selection: TestItem, - debug?: boolean, -) { - if (!selection || typeof selection.type !== 'number') { - return; - } - switch (selection.type) { - case Type.Null: { - return; - } - case Type.RunAll: { - return commandManager.executeCommand( - constants.Commands.Tests_Run, - undefined, - cmdSource, - wkspace, - undefined, - ); - } - case Type.RunParametrized: { - return commandManager.executeCommand( - constants.Commands.Tests_Run_Parametrized, - undefined, - cmdSource, - wkspace, - selection.fns!, - debug!, - ); - } - case Type.ReDiscover: { - return commandManager.executeCommand(constants.Commands.Tests_Discover, undefined, cmdSource, wkspace); - } - case Type.RunFailed: { - return commandManager.executeCommand(constants.Commands.Tests_Run_Failed, undefined, cmdSource, wkspace); - } - case Type.SelectAndRunMethod: { - const cmd = debug - ? constants.Commands.Tests_Select_And_Debug_Method - : constants.Commands.Tests_Select_And_Run_Method; - return commandManager.executeCommand(cmd, undefined, cmdSource, wkspace); - } - case Type.RunMethod: { - const testsToRun: TestsToRun = { testFunction: [selection.fn!.testFunction] }; - return commandManager.executeCommand( - constants.Commands.Tests_Run, - undefined, - cmdSource, - wkspace, - testsToRun, - ); - } - case Type.DebugMethod: { - const testsToRun: TestsToRun = { testFunction: [selection.fn!.testFunction] }; - return commandManager.executeCommand( - constants.Commands.Tests_Debug, - undefined, - cmdSource, - wkspace, - testsToRun, - ); - } - case Type.Configure: { - return commandManager.executeCommand(constants.Commands.Tests_Configure, undefined, cmdSource, wkspace); - } - default: { - return; - } - } -} diff --git a/src/client/testing/serviceRegistry.ts b/src/client/testing/serviceRegistry.ts index c1334e9d0ed2..7053d365a17e 100644 --- a/src/client/testing/serviceRegistry.ts +++ b/src/client/testing/serviceRegistry.ts @@ -34,7 +34,6 @@ import { ITestDebugLauncher, ITestDiagnosticService, ITestDiscoveryService, - ITestDisplay, ITestManagementService, ITestManager, ITestManagerFactory, @@ -42,7 +41,6 @@ import { ITestManagerService, ITestManagerServiceFactory, ITestMessageService, - ITestResultDisplay, ITestResultsService, ITestRunner, ITestsHelper, @@ -58,8 +56,6 @@ import { UpdateTestSettingService } from './common/updateTestSettings'; import { XUnitParser } from './common/xUnitParser'; import { UnitTestConfigurationService } from './configuration'; import { TestConfigurationManagerFactory } from './configurationFactory'; -import { TestResultDisplay } from './display/main'; -import { TestDisplay } from './display/picker'; import { TestingService, UnitTestManagementService } from './main'; import { TestManager as PyTestTestManager } from './pytest/main'; import { TestManagerRunner as PytestManagerRunner } from './pytest/runner'; @@ -117,8 +113,6 @@ export function registerTypes(serviceManager: IServiceManager) { serviceManager.addSingleton(ITestManagementService, UnitTestManagementService); serviceManager.addSingleton(ITestingService, TestingService); - serviceManager.addSingleton(ITestResultDisplay, TestResultDisplay); - serviceManager.addSingleton(ITestDisplay, TestDisplay); serviceManager.addSingleton(ITestConfigSettingsService, TestConfigSettingsService); serviceManager.addSingleton( ITestConfigurationManagerFactory, diff --git a/src/test/testing/display/main.unit.test.ts b/src/test/testing/display/main.unit.test.ts deleted file mode 100644 index ceda525268fb..000000000000 --- a/src/test/testing/display/main.unit.test.ts +++ /dev/null @@ -1,512 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { expect } from 'chai'; -import * as typeMoq from 'typemoq'; -import { StatusBarItem, Uri } from 'vscode'; -import { IApplicationShell, ICommandManager } from '../../../client/common/application/types'; -import { Commands } from '../../../client/common/constants'; -import '../../../client/common/extensions'; -import { IConfigurationService, IPythonSettings } from '../../../client/common/types'; -import { createDeferred } from '../../../client/common/utils/async'; -import { Testing } from '../../../client/common/utils/localize'; -import { noop } from '../../../client/common/utils/misc'; -import { IServiceContainer } from '../../../client/ioc/types'; -import { CANCELLATION_REASON } from '../../../client/testing/common/constants'; -import { ITestsHelper, Tests } from '../../../client/testing/common/types'; -import { TestResultDisplay } from '../../../client/testing/display/main'; -import { ITestingSettings } from '../../../client/testing/configuration/types'; -import { sleep } from '../../core'; - -suite('Unit Tests - TestResultDisplay', () => { - const workspaceUri = Uri.file(__filename); - let appShell: typeMoq.IMock; - let unitTestSettings: typeMoq.IMock; - let serviceContainer: typeMoq.IMock; - let display: TestResultDisplay; - let testsHelper: typeMoq.IMock; - let configurationService: typeMoq.IMock; - let cmdManager: typeMoq.IMock; - setup(() => { - serviceContainer = typeMoq.Mock.ofType(); - configurationService = typeMoq.Mock.ofType(); - appShell = typeMoq.Mock.ofType(); - unitTestSettings = typeMoq.Mock.ofType(); - const pythonSettings = typeMoq.Mock.ofType(); - testsHelper = typeMoq.Mock.ofType(); - cmdManager = typeMoq.Mock.ofType(); - - pythonSettings.setup((p) => p.testing).returns(() => unitTestSettings.object); - configurationService.setup((c) => c.getSettings(workspaceUri)).returns(() => pythonSettings.object); - - serviceContainer - .setup((c) => c.get(typeMoq.It.isValue(IConfigurationService))) - .returns(() => configurationService.object); - serviceContainer.setup((c) => c.get(typeMoq.It.isValue(IApplicationShell))).returns(() => appShell.object); - serviceContainer.setup((c) => c.get(typeMoq.It.isValue(ITestsHelper))).returns(() => testsHelper.object); - serviceContainer.setup((c) => c.get(typeMoq.It.isValue(ICommandManager))).returns(() => cmdManager.object); - }); - teardown(() => { - try { - display.dispose(); - } catch { - noop(); - } - }); - function createTestResultDisplay() { - display = new TestResultDisplay(serviceContainer.object); - } - test('Should create a status bar item upon instantiation', async () => { - const statusBar = typeMoq.Mock.ofType(); - appShell - .setup((a) => a.createStatusBarItem(typeMoq.It.isAny())) - .returns(() => statusBar.object) - .verifiable(typeMoq.Times.once()); - - createTestResultDisplay(); - appShell.verifyAll(); - }); - test('Should be disabled upon instantiation', async () => { - const statusBar = typeMoq.Mock.ofType(); - appShell - .setup((a) => a.createStatusBarItem(typeMoq.It.isAny())) - .returns(() => statusBar.object) - .verifiable(typeMoq.Times.once()); - - createTestResultDisplay(); - appShell.verifyAll(); - expect(display.enabled).to.be.equal(false, 'not disabled'); - }); - test('Enable display should show the statusbar', async () => { - const statusBar = typeMoq.Mock.ofType(); - appShell - .setup((a) => a.createStatusBarItem(typeMoq.It.isAny())) - .returns(() => statusBar.object) - .verifiable(typeMoq.Times.once()); - - statusBar.setup((s) => s.show()).verifiable(typeMoq.Times.once()); - - createTestResultDisplay(); - display.enabled = true; - statusBar.verifyAll(); - }); - test('Disable display should hide the statusbar', async () => { - const statusBar = typeMoq.Mock.ofType(); - appShell - .setup((a) => a.createStatusBarItem(typeMoq.It.isAny())) - .returns(() => statusBar.object) - .verifiable(typeMoq.Times.once()); - - statusBar.setup((s) => s.hide()).verifiable(typeMoq.Times.once()); - - createTestResultDisplay(); - display.enabled = false; - statusBar.verifyAll(); - }); - test('Ensure status bar is displayed and updated with progress with ability to stop tests', async () => { - const statusBar = typeMoq.Mock.ofType(); - appShell - .setup((a) => a.createStatusBarItem(typeMoq.It.isAny())) - .returns(() => statusBar.object) - .verifiable(typeMoq.Times.once()); - - statusBar.setup((s) => s.show()).verifiable(typeMoq.Times.once()); - - createTestResultDisplay(); - display.displayProgressStatus(createDeferred().promise, false); - - statusBar.verifyAll(); - statusBar.verify( - (s) => (s.command = typeMoq.It.isValue(Commands.Tests_Ask_To_Stop_Test)), - typeMoq.Times.atLeastOnce(), - ); - statusBar.verify((s) => (s.text = typeMoq.It.isValue('$(stop) Running Tests')), typeMoq.Times.atLeastOnce()); - }); - test('Ensure status bar is updated with success with ability to view ui without any results', async () => { - const statusBar = typeMoq.Mock.ofType(); - appShell - .setup((a) => a.createStatusBarItem(typeMoq.It.isAny())) - .returns(() => statusBar.object) - .verifiable(typeMoq.Times.once()); - - statusBar.setup((s) => s.show()).verifiable(typeMoq.Times.once()); - - createTestResultDisplay(); - const def = createDeferred(); - - display.displayProgressStatus(def.promise, false); - - statusBar.verifyAll(); - statusBar.verify( - (s) => (s.command = typeMoq.It.isValue(Commands.Tests_Ask_To_Stop_Test)), - typeMoq.Times.atLeastOnce(), - ); - statusBar.verify((s) => (s.text = typeMoq.It.isValue('$(stop) Running Tests')), typeMoq.Times.atLeastOnce()); - - const tests = typeMoq.Mock.ofType(); - tests.setup((t: any) => t.then).returns(() => undefined); - tests - .setup((t) => t.summary) - .returns(() => { - return { errors: 0, failures: 0, passed: 0, skipped: 0 }; - }) - .verifiable(typeMoq.Times.atLeastOnce()); - - appShell - .setup((a) => - a.showWarningMessage(typeMoq.It.isAny(), typeMoq.It.isAny(), typeMoq.It.isAny(), typeMoq.It.isAny()), - ) - .returns(() => Promise.resolve(undefined)) - .verifiable(typeMoq.Times.once()); - - def.resolve(tests.object); - await sleep(1); - - tests.verifyAll(); - appShell.verifyAll(); - }); - test('Ensure status bar is updated with success with ability to view ui with results', async () => { - const statusBar = typeMoq.Mock.ofType(); - appShell - .setup((a) => a.createStatusBarItem(typeMoq.It.isAny())) - .returns(() => statusBar.object) - .verifiable(typeMoq.Times.once()); - - statusBar.setup((s) => s.show()).verifiable(typeMoq.Times.once()); - - createTestResultDisplay(); - const def = createDeferred(); - - display.displayProgressStatus(def.promise, false); - - statusBar.verifyAll(); - statusBar.verify( - (s) => (s.command = typeMoq.It.isValue(Commands.Tests_Ask_To_Stop_Test)), - typeMoq.Times.atLeastOnce(), - ); - statusBar.verify((s) => (s.text = typeMoq.It.isValue('$(stop) Running Tests')), typeMoq.Times.atLeastOnce()); - - const tests = typeMoq.Mock.ofType(); - tests.setup((t: any) => t.then).returns(() => undefined); - tests - .setup((t) => t.summary) - .returns(() => { - return { errors: 0, failures: 0, passed: 1, skipped: 0 }; - }) - .verifiable(typeMoq.Times.atLeastOnce()); - - appShell - .setup((a) => - a.showWarningMessage(typeMoq.It.isAny(), typeMoq.It.isAny(), typeMoq.It.isAny(), typeMoq.It.isAny()), - ) - .returns(() => Promise.resolve(undefined)) - .verifiable(typeMoq.Times.never()); - - def.resolve(tests.object); - await sleep(1); - - tests.verifyAll(); - appShell.verifyAll(); - }); - test('Ensure status bar is updated with error when cancelled by user with ability to view ui with results', async () => { - const statusBar = typeMoq.Mock.ofType(); - appShell - .setup((a) => a.createStatusBarItem(typeMoq.It.isAny())) - .returns(() => statusBar.object) - .verifiable(typeMoq.Times.once()); - - statusBar.setup((s) => s.show()).verifiable(typeMoq.Times.once()); - - createTestResultDisplay(); - const def = createDeferred(); - - display.displayProgressStatus(def.promise, false); - - statusBar.verifyAll(); - statusBar.verify( - (s) => (s.command = typeMoq.It.isValue(Commands.Tests_Ask_To_Stop_Test)), - typeMoq.Times.atLeastOnce(), - ); - statusBar.verify((s) => (s.text = typeMoq.It.isValue('$(stop) Running Tests')), typeMoq.Times.atLeastOnce()); - - def.reject(CANCELLATION_REASON); - await sleep(1); - - appShell.verifyAll(); - }); - test('Ensure status bar is updated, and error message display with error in running tests, with ability to view ui with results', async () => { - const statusBar = typeMoq.Mock.ofType(); - appShell - .setup((a) => a.createStatusBarItem(typeMoq.It.isAny())) - .returns(() => statusBar.object) - .verifiable(typeMoq.Times.once()); - - statusBar.setup((s) => s.show()).verifiable(typeMoq.Times.once()); - - createTestResultDisplay(); - const def = createDeferred(); - - display.displayProgressStatus(def.promise, false); - - statusBar.verifyAll(); - statusBar.verify( - (s) => (s.command = typeMoq.It.isValue(Commands.Tests_Ask_To_Stop_Test)), - typeMoq.Times.atLeastOnce(), - ); - statusBar.verify((s) => (s.text = typeMoq.It.isValue('$(stop) Running Tests')), typeMoq.Times.atLeastOnce()); - - def.reject('Some other reason'); - await sleep(1); - - appShell.verifyAll(); - }); - - test('Ensure status bar is displayed and updated with progress with ability to stop test discovery', async () => { - const statusBar = typeMoq.Mock.ofType(); - appShell - .setup((a) => a.createStatusBarItem(typeMoq.It.isAny())) - .returns(() => statusBar.object) - .verifiable(typeMoq.Times.once()); - - statusBar.setup((s) => s.show()).verifiable(typeMoq.Times.once()); - - createTestResultDisplay(); - display.displayDiscoverStatus(createDeferred().promise, false).ignoreErrors(); - - statusBar.verifyAll(); - statusBar.verify( - (s) => (s.command = typeMoq.It.isValue(Commands.Tests_Ask_To_Stop_Discovery)), - typeMoq.Times.atLeastOnce(), - ); - statusBar.verify( - (s) => (s.text = typeMoq.It.isValue('$(stop) Discovering Tests')), - typeMoq.Times.atLeastOnce(), - ); - }); - test('Ensure status bar is displayed and updated with success and no tests, with ability to view ui to view results of test discovery', async () => { - const statusBar = typeMoq.Mock.ofType(); - appShell - .setup((a) => a.createStatusBarItem(typeMoq.It.isAny())) - .returns(() => statusBar.object) - .verifiable(typeMoq.Times.once()); - - statusBar.setup((s) => s.show()).verifiable(typeMoq.Times.once()); - - createTestResultDisplay(); - const def = createDeferred(); - - display.displayDiscoverStatus(def.promise, false).ignoreErrors(); - - statusBar.verifyAll(); - statusBar.verify( - (s) => (s.command = typeMoq.It.isValue(Commands.Tests_Ask_To_Stop_Discovery)), - typeMoq.Times.atLeastOnce(), - ); - statusBar.verify( - (s) => (s.text = typeMoq.It.isValue('$(stop) Discovering Tests')), - typeMoq.Times.atLeastOnce(), - ); - - const tests = typeMoq.Mock.ofType(); - appShell - .setup((a) => - a.showInformationMessage( - typeMoq.It.isAny(), - typeMoq.It.isAny(), - typeMoq.It.isAny(), - typeMoq.It.isAny(), - ), - ) - .returns(() => Promise.resolve(undefined)) - .verifiable(typeMoq.Times.once()); - - def.resolve(undefined as any); - await sleep(1); - - tests.verifyAll(); - appShell.verifyAll(); - }); - test('Ensure tests are disabled when there are errors and user choses to disable tests', async () => { - const statusBar = typeMoq.Mock.ofType(); - appShell - .setup((a) => a.createStatusBarItem(typeMoq.It.isAny())) - .returns(() => statusBar.object) - .verifiable(typeMoq.Times.once()); - - statusBar.setup((s) => s.show()).verifiable(typeMoq.Times.once()); - cmdManager - .setup((c) => - c.executeCommand( - typeMoq.It.isValue('setContext'), - typeMoq.It.isValue('testsDiscovered'), - typeMoq.It.isValue(false), - ), - ) - .verifiable(typeMoq.Times.once()); - createTestResultDisplay(); - const def = createDeferred(); - - display.displayDiscoverStatus(def.promise, false).ignoreErrors(); - - statusBar.verifyAll(); - statusBar.verify( - (s) => (s.command = typeMoq.It.isValue(Commands.Tests_Ask_To_Stop_Discovery)), - typeMoq.Times.atLeastOnce(), - ); - statusBar.verify( - (s) => (s.text = typeMoq.It.isValue('$(stop) Discovering Tests')), - typeMoq.Times.atLeastOnce(), - ); - - const tests = typeMoq.Mock.ofType(); - appShell - .setup((a) => - a.showInformationMessage( - typeMoq.It.isAny(), - typeMoq.It.isAny(), - typeMoq.It.isAny(), - typeMoq.It.isAny(), - ), - ) - .returns(() => Promise.resolve(Testing.disableTests())) - .verifiable(typeMoq.Times.once()); - - for (const setting of ['testing.promptToConfigure', 'testing.pytestEnabled', 'testing.unittestEnabled']) { - configurationService - .setup((c) => c.updateSetting(typeMoq.It.isValue(setting), typeMoq.It.isValue(false))) - .returns(() => Promise.resolve()) - .verifiable(typeMoq.Times.once()); - } - def.resolve(undefined as any); - await sleep(1); - - tests.verifyAll(); - appShell.verifyAll(); - configurationService.verifyAll(); - cmdManager.verifyAll(); - }); - test('Ensure corresponding command is executed when there are errors and user choses to configure test framework', async () => { - const statusBar = typeMoq.Mock.ofType(); - appShell - .setup((a) => a.createStatusBarItem(typeMoq.It.isAny())) - .returns(() => statusBar.object) - .verifiable(typeMoq.Times.once()); - - statusBar.setup((s) => s.show()).verifiable(typeMoq.Times.once()); - - createTestResultDisplay(); - const def = createDeferred(); - - display.displayDiscoverStatus(def.promise, false).ignoreErrors(); - - statusBar.verifyAll(); - statusBar.verify( - (s) => (s.command = typeMoq.It.isValue(Commands.Tests_Ask_To_Stop_Discovery)), - typeMoq.Times.atLeastOnce(), - ); - statusBar.verify( - (s) => (s.text = typeMoq.It.isValue('$(stop) Discovering Tests')), - typeMoq.Times.atLeastOnce(), - ); - - const tests = typeMoq.Mock.ofType(); - appShell - .setup((a) => - a.showInformationMessage( - typeMoq.It.isAny(), - typeMoq.It.isAny(), - typeMoq.It.isAny(), - typeMoq.It.isAny(), - ), - ) - .returns(() => Promise.resolve(Testing.configureTests())) - .verifiable(typeMoq.Times.once()); - - const undefinedArg = typeMoq.It.isValue(undefined); - cmdManager - .setup((c) => - c.executeCommand( - typeMoq.It.isValue(Commands.Tests_Configure as any), - undefinedArg, - undefinedArg, - undefinedArg, - ), - ) - .returns(() => Promise.resolve() as any) - .verifiable(typeMoq.Times.once()); - def.resolve(undefined as any); - await sleep(1); - - tests.verifyAll(); - appShell.verifyAll(); - cmdManager.verifyAll(); - }); - test('Ensure status bar is displayed and updated with error info when test discovery is cancelled by the user', async () => { - const statusBar = typeMoq.Mock.ofType(); - appShell - .setup((a) => a.createStatusBarItem(typeMoq.It.isAny())) - .returns(() => statusBar.object) - .verifiable(typeMoq.Times.once()); - - statusBar.setup((s) => s.show()).verifiable(typeMoq.Times.once()); - - createTestResultDisplay(); - const def = createDeferred(); - - display.displayDiscoverStatus(def.promise, false).ignoreErrors(); - - statusBar.verifyAll(); - statusBar.verify( - (s) => (s.command = typeMoq.It.isValue(Commands.Tests_Ask_To_Stop_Discovery)), - typeMoq.Times.atLeastOnce(), - ); - statusBar.verify( - (s) => (s.text = typeMoq.It.isValue('$(stop) Discovering Tests')), - typeMoq.Times.atLeastOnce(), - ); - - appShell.setup((a) => a.showErrorMessage(typeMoq.It.isAny())).verifiable(typeMoq.Times.never()); - - def.reject(CANCELLATION_REASON); - await sleep(1); - - appShell.verifyAll(); - statusBar.verify((s) => (s.command = typeMoq.It.isValue(Commands.Tests_Discover)), typeMoq.Times.atLeastOnce()); - configurationService.verifyAll(); - }); - test('Ensure status bar is displayed and updated with error info, and message is displayed when test discovery is fails due to errors', async () => { - const statusBar = typeMoq.Mock.ofType(); - appShell - .setup((a) => a.createStatusBarItem(typeMoq.It.isAny())) - .returns(() => statusBar.object) - .verifiable(typeMoq.Times.once()); - - statusBar.setup((s) => s.show()).verifiable(typeMoq.Times.once()); - - createTestResultDisplay(); - const def = createDeferred(); - - display.displayDiscoverStatus(def.promise, false).ignoreErrors(); - - statusBar.verifyAll(); - statusBar.verify( - (s) => (s.command = typeMoq.It.isValue(Commands.Tests_Ask_To_Stop_Discovery)), - typeMoq.Times.atLeastOnce(), - ); - statusBar.verify( - (s) => (s.text = typeMoq.It.isValue('$(stop) Discovering Tests')), - typeMoq.Times.atLeastOnce(), - ); - - appShell.setup((a) => a.showErrorMessage(typeMoq.It.isAny())).verifiable(typeMoq.Times.once()); - - def.reject('some weird error'); - await sleep(1); - - appShell.verifyAll(); - statusBar.verify((s) => (s.command = typeMoq.It.isValue(Commands.Tests_Discover)), typeMoq.Times.atLeastOnce()); - configurationService.verifyAll(); - }); -}); diff --git a/src/test/testing/display/picker.functional.test.ts b/src/test/testing/display/picker.functional.test.ts deleted file mode 100644 index a41b46f372e7..000000000000 --- a/src/test/testing/display/picker.functional.test.ts +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { anything, instance, mock, verify, when } from 'ts-mockito'; -import { Uri } from 'vscode'; -import { ApplicationShell } from '../../../client/common/application/applicationShell'; -import { CommandManager } from '../../../client/common/application/commandManager'; -import { IApplicationShell, ICommandManager } from '../../../client/common/application/types'; -import { CommandSource } from '../../../client/common/constants'; -import { FileSystem } from '../../../client/common/platform/fileSystem'; -import { IFileSystem } from '../../../client/common/platform/types'; -import { ServiceContainer } from '../../../client/ioc/container'; -import { IServiceContainer } from '../../../client/ioc/types'; -import { TestCollectionStorageService } from '../../../client/testing/common/services/storageService'; -import { ITestCollectionStorageService, TestFunction, Tests } from '../../../client/testing/common/types'; -import { TestDisplay } from '../../../client/testing/display/picker'; -import { createEmptyResults } from '../results'; - -suite('Testing - TestDisplay', () => { - const wkspace = Uri.file(__dirname); - let mockedCommandManager: ICommandManager; - let mockedServiceContainer: IServiceContainer; - let mockedTestCollectionStorage: ITestCollectionStorageService; - let mockedAppShell: IApplicationShell; - let testDisplay: TestDisplay; - - function fullPathInTests(collectedTests: Tests, fullpath?: string): Tests { - collectedTests.testFiles = [ - { - fullPath: fullpath ? fullpath : 'path/to/testfile', - ...anything(), - }, - ]; - return collectedTests; - } - - setup(() => { - mockedCommandManager = mock(CommandManager); - mockedServiceContainer = mock(ServiceContainer); - mockedTestCollectionStorage = mock(TestCollectionStorageService); - mockedAppShell = mock(ApplicationShell); - when(mockedServiceContainer.get(ITestCollectionStorageService)).thenReturn( - instance(mockedTestCollectionStorage), - ); - when(mockedServiceContainer.get(IApplicationShell)).thenReturn(instance(mockedAppShell)); - - testDisplay = new TestDisplay(instance(mockedServiceContainer), instance(mockedCommandManager)); - }); - - suite('displayFunctionTestPickerUI', () => { - const paths: { [key: string]: any } = { - match: { - fullPath: '/path/to/testfile', - fileName: '/path/to/testfile', - }, - mismatch: { - fullPath: '/path/to/testfile', - fileName: '/testfile/to/path', - }, - }; - let tests: Tests; - - function codeLensTestFunctions(testfunctions?: TestFunction[]): TestFunction[] { - if (!testfunctions) { - return [{ ...anything() }]; - } - const functions: TestFunction[] = []; - testfunctions.forEach((fn) => functions.push(fn)); - return functions; - } - - setup(() => { - tests = createEmptyResults(); - when(mockedServiceContainer.get(IFileSystem)).thenReturn(new FileSystem()); - when(mockedTestCollectionStorage.getTests(wkspace)).thenReturn(tests); - when(mockedAppShell.showQuickPick(anything(), anything())).thenResolve(); - }); - - test(`Test that a dropdown picker for parametrized tests is shown if compared paths are equal (OS independent) (#8627)`, () => { - const { fullPath, fileName } = paths.match; - fullPathInTests(tests, fullPath); - - testDisplay.displayFunctionTestPickerUI( - CommandSource.commandPalette, - wkspace, - 'rootDirectory', - Uri.file(fileName), - codeLensTestFunctions(), - ); - - verify(mockedAppShell.showQuickPick(anything(), anything())).once(); - }); - - test(`Test that a dropdown picker for parametrized tests is NOT shown if compared paths are NOT equal (OS independent) (#8627)`, () => { - const { fullPath, fileName } = paths.mismatch; - fullPathInTests(tests, fullPath); - - testDisplay.displayFunctionTestPickerUI( - CommandSource.commandPalette, - wkspace, - 'rootDirectory', - Uri.file(fileName), - codeLensTestFunctions(), - ); - - verify(mockedAppShell.showQuickPick(anything(), anything())).never(); - }); - - test(`Test that clicking a codelens on parametrized tests opens a dropdown picker on windows (#8627)`, function () { - if (process.platform !== 'win32') { - this.skip(); - } - // The error described in #8627 originated from the problem that the casing of the drive letter was different - // in a test items fullPath property to the one of a file that contained the clicked parametrized test. - const fileName = 'c:\\path\\to\\testfile'; - fullPathInTests(tests, 'C:\\path\\to\\testfile'); - - testDisplay.displayFunctionTestPickerUI( - CommandSource.commandPalette, - wkspace, - 'rootDirectory', - Uri.file(fileName), - codeLensTestFunctions(), - ); - - verify(mockedAppShell.showQuickPick(anything(), anything())).once(); - }); - }); -}); diff --git a/src/test/testing/display/picker.unit.test.ts b/src/test/testing/display/picker.unit.test.ts deleted file mode 100644 index 1d1c656eb27e..000000000000 --- a/src/test/testing/display/picker.unit.test.ts +++ /dev/null @@ -1,255 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { anything, instance, mock, verify, when } from 'ts-mockito'; -import { Uri } from 'vscode'; -import { ApplicationShell } from '../../../client/common/application/applicationShell'; -import { CommandManager } from '../../../client/common/application/commandManager'; -import { IApplicationShell, ICommandManager } from '../../../client/common/application/types'; -import { Commands, CommandSource } from '../../../client/common/constants'; -import { FileSystem } from '../../../client/common/platform/fileSystem'; -import { IFileSystem } from '../../../client/common/platform/types'; -import { getNamesAndValues } from '../../../client/common/utils/enum'; -import { ServiceContainer } from '../../../client/ioc/container'; -import { IServiceContainer } from '../../../client/ioc/types'; -import { TestCollectionStorageService } from '../../../client/testing/common/services/storageService'; -import { ITestCollectionStorageService, TestFunction, Tests, TestsToRun } from '../../../client/testing/common/types'; -import { onItemSelected, TestDisplay, Type } from '../../../client/testing/display/picker'; -import { createEmptyResults } from '../results'; - -suite('Unit Tests - Picker (execution of commands)', () => { - getNamesAndValues(Type).forEach((item) => { - getNamesAndValues(CommandSource).forEach((commandSource) => { - [true, false].forEach((debug) => { - test(`Invoking command for selection ${item.name} from ${commandSource.name} (${ - debug ? 'Debug' : 'No debug' - })`, async () => { - const commandManager = mock(CommandManager); - const workspaceUri = Uri.file(__filename); - - const testFunction = 'some test Function'; - const testFunctions = [ - { - name: 'some_name', - nameToRun: 'some_name_to_run', - time: 0, - resource: workspaceUri, - }, - ]; - const selection = { type: item.value, fn: { testFunction }, fns: testFunctions }; - - // Getting the value of CommandSource.commandPalette in getNamesAndValues(CommandSource) - // fails because the names and values object is build by accessing the CommandSource enum - // properties by value. In case of commandpalette the property is commandPalette and the - // respective value is commandpalette which do not match and thus return undefined for value. - if (commandSource.name === 'commandpalette') { - commandSource.value = CommandSource.commandPalette; - } - - onItemSelected( - instance(commandManager), - commandSource.value, - workspaceUri, - selection as any, - debug, - ); - - switch (selection.type) { - case Type.Null: { - verify(commandManager.executeCommand(anything())).never(); - const args: any[] = []; - for (let i = 0; i <= 7; i += 1) { - args.push(anything()); - } - verify(commandManager.executeCommand(anything(), ...args)).never(); - return; - } - case Type.RunAll: { - verify( - commandManager.executeCommand( - Commands.Tests_Run, - undefined, - commandSource.value, - workspaceUri, - undefined, - ), - ).once(); - return; - } - case Type.RunParametrized: { - verify( - commandManager.executeCommand( - Commands.Tests_Run_Parametrized, - undefined, - commandSource.value, - workspaceUri, - selection.fns, - debug, - ), - ).once(); - return; - } - case Type.ReDiscover: { - verify( - commandManager.executeCommand( - Commands.Tests_Discover, - undefined, - commandSource.value, - workspaceUri, - ), - ).once(); - return; - } - case Type.RunFailed: { - verify( - commandManager.executeCommand( - Commands.Tests_Run_Failed, - undefined, - commandSource.value, - workspaceUri, - ), - ).once(); - return; - } - case Type.SelectAndRunMethod: { - const cmd = debug - ? Commands.Tests_Select_And_Debug_Method - : Commands.Tests_Select_And_Run_Method; - verify( - commandManager.executeCommand(cmd, undefined, commandSource.value, workspaceUri), - ).once(); - return; - } - case Type.RunMethod: { - const testsToRun: TestsToRun = { testFunction: ['something' as any] }; - verify( - commandManager.executeCommand( - Commands.Tests_Run, - undefined, - commandSource.value, - workspaceUri, - testsToRun, - ), - ).never(); - return; - } - case Type.DebugMethod: { - const testsToRun: TestsToRun = { testFunction: ['something' as any] }; - verify( - commandManager.executeCommand( - Commands.Tests_Debug, - undefined, - commandSource.value, - workspaceUri, - testsToRun, - ), - ).never(); - return; - } - case Type.Configure: { - verify( - commandManager.executeCommand( - Commands.Tests_Configure, - undefined, - commandSource.value, - workspaceUri, - ), - ).once(); - return; - } - default: { - return; - } - } - }); - }); - }); - }); -}); - -suite('Testing - TestDisplay', () => { - const wkspace = Uri.file(__dirname); - let mockedCommandManager: ICommandManager; - let mockedServiceContainer: IServiceContainer; - let mockedTestCollectionStorage: ITestCollectionStorageService; - let mockedAppShell: IApplicationShell; - let mockedFileSytem: IFileSystem; - let testDisplay: TestDisplay; - - function fullPathInTests(collectedTests: Tests, fullpath?: string): Tests { - collectedTests.testFiles = [ - { - fullPath: fullpath ? fullpath : 'path/to/testfile', - ...anything(), - }, - ]; - return collectedTests; - } - - setup(() => { - mockedCommandManager = mock(CommandManager); - mockedServiceContainer = mock(ServiceContainer); - mockedTestCollectionStorage = mock(TestCollectionStorageService); - mockedAppShell = mock(ApplicationShell); - when(mockedServiceContainer.get(ITestCollectionStorageService)).thenReturn( - instance(mockedTestCollectionStorage), - ); - when(mockedServiceContainer.get(IApplicationShell)).thenReturn(instance(mockedAppShell)); - - testDisplay = new TestDisplay(instance(mockedServiceContainer), instance(mockedCommandManager)); - }); - - suite('displayFunctionTestPickerUI', () => { - const fileName = Uri.file('path/to/testfile'); - let tests: Tests; - - function codeLensTestFunctions(testfunctions?: TestFunction[]): TestFunction[] { - if (!testfunctions) { - return [{ ...anything() }]; - } - const functions: TestFunction[] = []; - testfunctions.forEach((fn) => functions.push(fn)); - return functions; - } - - setup(() => { - tests = createEmptyResults(); - mockedFileSytem = mock(FileSystem); - when(mockedServiceContainer.get(IFileSystem)).thenReturn(instance(mockedFileSytem)); - when(mockedTestCollectionStorage.getTests(wkspace)).thenReturn(tests); - when(mockedAppShell.showQuickPick(anything(), anything())).thenResolve(); - }); - - test(`Test that a dropdown picker for parametrized tests is shown if compared paths are equal (#8627)`, () => { - fullPathInTests(tests); - when(mockedFileSytem.arePathsSame(anything(), anything())).thenReturn(true); - - testDisplay.displayFunctionTestPickerUI( - CommandSource.commandPalette, - wkspace, - 'rootDirectory', - fileName, - codeLensTestFunctions(), - ); - - verify(mockedAppShell.showQuickPick(anything(), anything())).once(); - }); - - test(`Test that a dropdown picker for parametrized tests is NOT shown if compared paths are NOT equal (#8627)`, () => { - fullPathInTests(tests); - when(mockedFileSytem.arePathsSame(anything(), anything())).thenReturn(false); - - testDisplay.displayFunctionTestPickerUI( - CommandSource.commandPalette, - wkspace, - 'rootDirectory', - fileName, - codeLensTestFunctions(), - ); - - verify(mockedAppShell.showQuickPick(anything(), anything())).never(); - }); - }); -}); From 8e3d0c8700b963f5b7bdc95c6107444cf2331f77 Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Mon, 24 May 2021 18:00:41 -0700 Subject: [PATCH 08/39] Remove more test commands (#16314) * Remove select and run commands * Remove commands from package json --- package.json | 28 ------ package.nls.de.json | 3 - package.nls.es.json | 3 - package.nls.fr.json | 3 - package.nls.it.json | 3 - package.nls.ja.json | 3 - package.nls.json | 3 - package.nls.ko-kr.json | 3 - package.nls.nl.json | 3 - package.nls.pl.json | 3 - package.nls.pt-br.json | 3 - package.nls.ru.json | 3 - package.nls.tr.json | 3 - package.nls.zh-cn.json | 3 - package.nls.zh-tw.json | 3 - src/client/common/application/commands.ts | 5 -- src/client/common/constants.ts | 6 -- src/client/testing/common/types.ts | 5 -- src/client/testing/main.ts | 102 +--------------------- 19 files changed, 1 insertion(+), 187 deletions(-) diff --git a/package.json b/package.json index 8db9a37ee96e..b9fc1039caff 100644 --- a/package.json +++ b/package.json @@ -64,13 +64,9 @@ "onCommand:python.debugtests", "onCommand:python.setInterpreter", "onCommand:python.setShebangInterpreter", - "onCommand:python.viewTestUI", "onCommand:python.viewLanguageServerOutput", - "onCommand:python.viewTestOutput", "onCommand:python.viewOutput", - "onCommand:python.selectAndRunTestMethod", "onCommand:python.selectAndDebugTestMethod", - "onCommand:python.selectAndRunTestFile", "onCommand:python.runCurrentTestFile", "onCommand:python.runFailedTests", "onCommand:python.execSelectionInTerminal", @@ -457,16 +453,6 @@ "command": "python.selectAndDebugTestMethod", "title": "%python.command.python.selectAndDebugTestMethod.title%" }, - { - "category": "Python", - "command": "python.selectAndRunTestFile", - "title": "%python.command.python.selectAndRunTestFile.title%" - }, - { - "category": "Python", - "command": "python.selectAndRunTestMethod", - "title": "%python.command.python.selectAndRunTestMethod.title%" - }, { "category": "Python", "command": "python.setInterpreter", @@ -525,15 +511,6 @@ "light": "resources/light/repl.svg" }, "title": "%python.command.python.viewOutput.title%" - }, - { - "category": "Python", - "command": "python.viewTestOutput", - "icon": { - "dark": "resources/dark/repl.svg", - "light": "resources/light/repl.svg" - }, - "title": "%python.command.python.viewTestOutput.title%" } ], "configuration": { @@ -2103,11 +2080,6 @@ "command": "python.stopTests", "group": "navigation@1", "when": "view == python_tests && busyTests" - }, - { - "command": "python.viewTestOutput", - "group": "navigation@5", - "when": "view == python_tests" } ] }, diff --git a/package.nls.de.json b/package.nls.de.json index 77ec14b3ee9c..95f24755d131 100644 --- a/package.nls.de.json +++ b/package.nls.de.json @@ -9,10 +9,7 @@ "python.command.python.setInterpreter.title": "Interpreter auswählen", "python.command.python.refactorExtractVariable.title": "Variable extrahieren", "python.command.python.refactorExtractMethod.title": "Methode extrahieren", - "python.command.python.viewTestOutput.title": "Unittest-Ausgabe anzeigen", - "python.command.python.selectAndRunTestMethod.title": "Unittest-Methode ausführen ...", "python.command.python.selectAndDebugTestMethod.title": "Unittest-Debug-Methode ausführen ...", - "python.command.python.selectAndRunTestFile.title": "Unittest-Datei ausführen ...", "python.command.python.runCurrentTestFile.title": "Ausgewählte Unittest-Datei ausführen", "python.command.python.runFailedTests.title": "Fehlerhafte Unittests ausführen", "python.command.python.discoverTests.title": "Unittests durchsuchen", diff --git a/package.nls.es.json b/package.nls.es.json index 227e268dbc8d..97e0666a52ec 100644 --- a/package.nls.es.json +++ b/package.nls.es.json @@ -9,10 +9,7 @@ "python.command.python.setInterpreter.title": "Seleccionar intérprete", "python.command.python.refactorExtractVariable.title": "Extraer variable", "python.command.python.refactorExtractMethod.title": "Extraer método", - "python.command.python.viewTestOutput.title": "Mostrar resultados de la prueba unitaria", - "python.command.python.selectAndRunTestMethod.title": "Método de ejecución de pruebas unitarias ...", "python.command.python.selectAndDebugTestMethod.title": "Método de depuración de pruebas unitarias ...", - "python.command.python.selectAndRunTestFile.title": "Ejecutar archivo de prueba unitaria ...", "python.command.python.runCurrentTestFile.title": "Ejecutar archivo de prueba unitaria actual", "python.command.python.runFailedTests.title": "Ejecutar pruebas unitarias fallidas", "python.command.python.discoverTests.title": "Encontrar pruebas unitarias", diff --git a/package.nls.fr.json b/package.nls.fr.json index ad28a94d6e09..2e6b60234b72 100644 --- a/package.nls.fr.json +++ b/package.nls.fr.json @@ -9,10 +9,7 @@ "python.command.python.setInterpreter.title": "Sélectionner l'interpreteur", "python.command.python.refactorExtractVariable.title": "Extraire la variable", "python.command.python.refactorExtractMethod.title": "Extraire la méthode", - "python.command.python.viewTestOutput.title": "Afficher la sortie des tests unitaires", - "python.command.python.selectAndRunTestMethod.title": "Exécuter la méthode de test unitaire ...", "python.command.python.selectAndDebugTestMethod.title": "Déboguer la méthode de test unitaire ...", - "python.command.python.selectAndRunTestFile.title": "Exécuter le fichier de test unitaire ...", "python.command.python.runCurrentTestFile.title": "Exécuter le fichier de test unitaire courant", "python.command.python.runFailedTests.title": "Exécuter les derniers test unitaires échoués", "python.command.python.execSelectionInTerminal.title": "Exécuter la ligne/sélection dans un terminal Python", diff --git a/package.nls.it.json b/package.nls.it.json index c16d6ce74241..bebe0580da7c 100644 --- a/package.nls.it.json +++ b/package.nls.it.json @@ -9,10 +9,7 @@ "python.command.python.setInterpreter.title": "Seleziona interprete", "python.command.python.refactorExtractVariable.title": "Estrai variable", "python.command.python.refactorExtractMethod.title": "Estrai metodo", - "python.command.python.viewTestOutput.title": "Mostra output dei test", - "python.command.python.selectAndRunTestMethod.title": "Esegui metodo di test ...", "python.command.python.selectAndDebugTestMethod.title": "Esegui debug del metodo di test ...", - "python.command.python.selectAndRunTestFile.title": "Esegui file di test ...", "python.command.python.runCurrentTestFile.title": "Esegui file di test attuale", "python.command.python.runFailedTests.title": "Esegui test falliti", "python.command.python.execSelectionInTerminal.title": "Esegui selezione/linea nel terminale di Python", diff --git a/package.nls.ja.json b/package.nls.ja.json index a2db0a823636..717a4ecc54f8 100644 --- a/package.nls.ja.json +++ b/package.nls.ja.json @@ -8,10 +8,7 @@ "python.command.python.setInterpreter.title": "インタープリターを選択", "python.command.python.refactorExtractVariable.title": "変数を抽出", "python.command.python.refactorExtractMethod.title": "メソッドを抽出", - "python.command.python.viewTestOutput.title": "単体テストの出力を表示", - "python.command.python.selectAndRunTestMethod.title": "単体テストメソッドを実行...", "python.command.python.selectAndDebugTestMethod.title": "単体テストメソッドをデバッグ...", - "python.command.python.selectAndRunTestFile.title": "単体テストファイルを実行...", "python.command.python.runCurrentTestFile.title": "現在の単体テストファイルを実行", "python.command.python.runFailedTests.title": "失敗した単体テストを実行", "python.command.python.execSelectionInTerminal.title": "Python ターミナルで選択範囲/行を実行", diff --git a/package.nls.json b/package.nls.json index 0940a7309557..8e32a0203ff6 100644 --- a/package.nls.json +++ b/package.nls.json @@ -14,11 +14,8 @@ "python.command.python.refactorExtractVariable.title": "Extract Variable", "python.command.python.refactorExtractMethod.title": "Extract Method", "python.command.python.viewOutput.title": "Show Output", - "python.command.python.viewTestOutput.title": "Show Test Output", "python.command.python.viewLanguageServerOutput.title": "Show Language Server Output", - "python.command.python.selectAndRunTestMethod.title": "Run Test Method ...", "python.command.python.selectAndDebugTestMethod.title": "Debug Test Method ...", - "python.command.python.selectAndRunTestFile.title": "Run Test File ...", "python.command.python.runCurrentTestFile.title": "Run Current Test File", "python.command.python.runFailedTests.title": "Run Failed Tests", "python.command.python.discoverTests.title": "Discover Tests", diff --git a/package.nls.ko-kr.json b/package.nls.ko-kr.json index 5309a9b07b81..c9562d08fe9f 100644 --- a/package.nls.ko-kr.json +++ b/package.nls.ko-kr.json @@ -8,10 +8,7 @@ "python.command.python.setInterpreter.title": "인터프리터 선택", "python.command.python.refactorExtractVariable.title": "변수 추출", "python.command.python.refactorExtractMethod.title": "메서드 추출", - "python.command.python.viewTestOutput.title": "단위 테스트 결과 보기", - "python.command.python.selectAndRunTestMethod.title": "단위 테스트 메서드 실행 ...", "python.command.python.selectAndDebugTestMethod.title": "단위 테스트 메서드 디버그 ...", - "python.command.python.selectAndRunTestFile.title": "단위 테스트 파일 실행 ...", "python.command.python.runCurrentTestFile.title": "현재 단위 테스트 파일 실행", "python.command.python.runFailedTests.title": "실패한 단위 테스트 실행", "python.command.python.execSelectionInTerminal.title": "Python 터미널에서 선택 영역/줄 실행", diff --git a/package.nls.nl.json b/package.nls.nl.json index 08c9534dc962..9a86994b9594 100644 --- a/package.nls.nl.json +++ b/package.nls.nl.json @@ -9,10 +9,7 @@ "python.command.python.setInterpreter.title": "Interpreter selecteren", "python.command.python.refactorExtractVariable.title": "Variabelen selecteren", "python.command.python.refactorExtractMethod.title": "Methode selecteren", - "python.command.python.viewTestOutput.title": "Unittest-resultaat laten zien", - "python.command.python.selectAndRunTestMethod.title": "Unittest-methode uitvoeren ...", "python.command.python.selectAndDebugTestMethod.title": "Unittest-methode debuggen ...", - "python.command.python.selectAndRunTestFile.title": "Unittest-bestand uitvoeren ...", "python.command.python.runCurrentTestFile.title": "Huidige unittest-bestand uitvoeren", "python.command.python.runFailedTests.title": "Gefaalde unittests uitvoeren", "python.command.python.discoverTests.title": "Unittests doorzoeken", diff --git a/package.nls.pl.json b/package.nls.pl.json index 00f186f2ebab..d31fc094ce10 100644 --- a/package.nls.pl.json +++ b/package.nls.pl.json @@ -10,10 +10,7 @@ "python.command.python.refactorExtractVariable.title": "Wyodrębnij zmienną", "python.command.python.refactorExtractMethod.title": "Wyodrębnij metodę", "python.command.python.viewOutput.title": "Pokaż wyniki", - "python.command.python.viewTestOutput.title": "Pokaż wyniki testów jednostkowych", - "python.command.python.selectAndRunTestMethod.title": "Uruchom metodę testów jednostkowych ...", "python.command.python.selectAndDebugTestMethod.title": "Debuguj metodę testów jednostkowych ...", - "python.command.python.selectAndRunTestFile.title": "Uruchom plik z testami jednostkowymi ...", "python.command.python.runCurrentTestFile.title": "Uruchom bieżący plik z testami jednostkowymi", "python.command.python.runFailedTests.title": "Uruchom testy jednostkowe, które się nie powiodły", "python.command.python.discoverTests.title": "Wyszukaj testy jednostkowe", diff --git a/package.nls.pt-br.json b/package.nls.pt-br.json index 1acc94053ca0..e27ad034b781 100644 --- a/package.nls.pt-br.json +++ b/package.nls.pt-br.json @@ -9,10 +9,7 @@ "python.command.python.setInterpreter.title": "Selecionar Interpretador", "python.command.python.refactorExtractVariable.title": "Extrair Variável", "python.command.python.refactorExtractMethod.title": "Extrair Método", - "python.command.python.viewTestOutput.title": "Exibir Resultados dos Testes Unitários", - "python.command.python.selectAndRunTestMethod.title": "Executar Testes Unitários do Método ...", "python.command.python.selectAndDebugTestMethod.title": "Depurar Testes Unitários do Método ...", - "python.command.python.selectAndRunTestFile.title": "Executar Arquivo de Testes Unitários ...", "python.command.python.runCurrentTestFile.title": "Executar o Arquivo de Testes Unitários Atual", "python.command.python.runFailedTests.title": "Executar Testes Unitários com Falhas", "python.command.python.discoverTests.title": "Descobrir Testes Unitários", diff --git a/package.nls.ru.json b/package.nls.ru.json index 4be739ab2bb7..7463070237b2 100644 --- a/package.nls.ru.json +++ b/package.nls.ru.json @@ -8,10 +8,7 @@ "python.command.python.setInterpreter.title": "Выбрать интерпретатор", "python.command.python.refactorExtractVariable.title": "Извлечь в переменную", "python.command.python.refactorExtractMethod.title": "Извлечь в метод", - "python.command.python.viewTestOutput.title": "Показать вывод теста", - "python.command.python.selectAndRunTestMethod.title": "Запусть тестовый метод...", "python.command.python.selectAndDebugTestMethod.title": "Отладить тестовый метод...", - "python.command.python.selectAndRunTestFile.title": "Запустить тестовый файл...", "python.command.python.runCurrentTestFile.title": "Запустить текущий тестовый файл", "python.command.python.runFailedTests.title": "Запустить непрошедшие тесты", "python.command.python.discoverTests.title": "Обнаружить тесты", diff --git a/package.nls.tr.json b/package.nls.tr.json index 0e648bb38fdf..4dd32315b3e5 100644 --- a/package.nls.tr.json +++ b/package.nls.tr.json @@ -9,10 +9,7 @@ "python.command.python.setInterpreter.title": "Bir Interpreter Seçin", "python.command.python.refactorExtractVariable.title": "Değişken Çıkar", "python.command.python.refactorExtractMethod.title": "Metot Çıkar", - "python.command.python.viewTestOutput.title": "Test Çıktısını Görüntüle", - "python.command.python.selectAndRunTestMethod.title": "Test Metodu Çalıştır", "python.command.python.selectAndDebugTestMethod.title": "Test Metodu Debug Et", - "python.command.python.selectAndRunTestFile.title": "Bir Test Dosyası Seç ve Çalıştır", "python.command.python.runCurrentTestFile.title": "Aktif Test Dosyasını Çalıştır", "python.command.python.runFailedTests.title": "Başarısız Testleri Çalıştır", "python.command.python.discoverTests.title": "Testleri Keşfet", diff --git a/package.nls.zh-cn.json b/package.nls.zh-cn.json index df3c5ccdf158..bd3346e4686d 100644 --- a/package.nls.zh-cn.json +++ b/package.nls.zh-cn.json @@ -14,11 +14,8 @@ "python.command.python.refactorExtractVariable.title": "提取变量", "python.command.python.refactorExtractMethod.title": "提取方法", "python.command.python.viewOutput.title": "显示输出", - "python.command.python.viewTestOutput.title": "显示单元测试输出", "python.command.python.viewLanguageServerOutput.title": "显示语言服务器输出", - "python.command.python.selectAndRunTestMethod.title": "运行单元测试方法...", "python.command.python.selectAndDebugTestMethod.title": "调试单元测试方法...", - "python.command.python.selectAndRunTestFile.title": "运行单元测试文件...", "python.command.python.runCurrentTestFile.title": "运行当前单元测试文件", "python.command.python.runFailedTests.title": "运行失败的单元测试", "python.command.python.discoverTests.title": "检测单元测试", diff --git a/package.nls.zh-tw.json b/package.nls.zh-tw.json index 373a44299d87..6cf249c38190 100644 --- a/package.nls.zh-tw.json +++ b/package.nls.zh-tw.json @@ -9,10 +9,7 @@ "python.command.python.setInterpreter.title": "選擇直譯器", "python.command.python.refactorExtractVariable.title": "提取變數", "python.command.python.refactorExtractMethod.title": "提取方法", - "python.command.python.viewTestOutput.title": "顯示單元測試輸出", - "python.command.python.selectAndRunTestMethod.title": "執行單元測試方法…", "python.command.python.selectAndDebugTestMethod.title": "偵錯單元測試方法…", - "python.command.python.selectAndRunTestFile.title": "執行單元測試檔案…", "python.command.python.runCurrentTestFile.title": "執行目前單元測試檔案", "python.command.python.runFailedTests.title": "執行失敗的單元測試", "python.command.python.execSelectionInTerminal.title": "在 Python 終端機中執行選定內容/行", diff --git a/src/client/common/application/commands.ts b/src/client/common/application/commands.ts index c7bd705757a3..8e3bf0aa9f6f 100644 --- a/src/client/common/application/commands.ts +++ b/src/client/common/application/commands.ts @@ -94,7 +94,6 @@ export interface ICommandNameArgumentTypeMapping extends ICommandNameWithoutArgu [Commands.Sort_Imports]: [undefined, Uri]; [Commands.Exec_In_Terminal]: [undefined, Uri]; [Commands.Exec_In_Terminal_Icon]: [undefined, Uri]; - [Commands.Tests_Select_And_Run_File]: [undefined, CommandSource]; [Commands.Tests_Run_Current_File]: [undefined, CommandSource]; [Commands.Tests_Stop]: [undefined, Uri]; [Commands.Test_Reveal_Test_Item]: [TestDataItem]; @@ -116,11 +115,7 @@ export interface ICommandNameArgumentTypeMapping extends ICommandNameWithoutArgu // When command is invoked from a tree node, first argument is the node data. [Commands.Tests_Discover]: [undefined | TestWorkspaceFolder, undefined | CommandSource, undefined | Uri]; [Commands.Tests_Run_Failed]: [undefined, CommandSource, Uri]; - [Commands.Tests_Select_And_Debug_Method]: [undefined, CommandSource, Uri]; - [Commands.Tests_Select_And_Run_Method]: [undefined, CommandSource, Uri]; [Commands.Tests_Configure]: [undefined, undefined | CommandSource, undefined | Uri]; - [Commands.Tests_Picker_UI]: [undefined, undefined | CommandSource, Uri, TestFunction[]]; - [Commands.Tests_Picker_UI_Debug]: [undefined, undefined | CommandSource, Uri, TestFunction[]]; // When command is invoked from a tree node, first argument is the node data. [Commands.runTestNode]: [TestDataItem]; // When command is invoked from a tree node, first argument is the node data. diff --git a/src/client/common/constants.ts b/src/client/common/constants.ts index cb07c28ba905..a66696f767b2 100644 --- a/src/client/common/constants.ts +++ b/src/client/common/constants.ts @@ -37,8 +37,6 @@ export namespace Commands { export const Exec_In_Terminal_Icon = 'python.execInTerminal-icon'; export const Exec_Selection_In_Terminal = 'python.execSelectionInTerminal'; export const Exec_Selection_In_Django_Shell = 'python.execSelectionInDjangoShell'; - export const Tests_Picker_UI = 'python.selectTestToRun'; - export const Tests_Picker_UI_Debug = 'python.selectTestToDebug'; export const Tests_Configure = 'python.configureTests'; export const Tests_Discover = 'python.discoverTests'; export const Tests_Discovering = 'python.discoveringTests'; @@ -52,10 +50,6 @@ export namespace Commands { export const Tests_Stop = 'python.stopTests'; export const Test_Reveal_Test_Item = 'python.revealTestItem'; export const ViewOutput = 'python.viewOutput'; - export const Tests_ViewOutput = 'python.viewTestOutput'; - export const Tests_Select_And_Run_Method = 'python.selectAndRunTestMethod'; - export const Tests_Select_And_Debug_Method = 'python.selectAndDebugTestMethod'; - export const Tests_Select_And_Run_File = 'python.selectAndRunTestFile'; export const Tests_Run_Current_File = 'python.runCurrentTestFile'; export const Refactor_Extract_Variable = 'python.refactorExtractVariable'; export const Refactor_Extract_Method = 'python.refactorExtractMethod'; diff --git a/src/client/testing/common/types.ts b/src/client/testing/common/types.ts index 934d79c563b7..5ac16619d072 100644 --- a/src/client/testing/common/types.ts +++ b/src/client/testing/common/types.ts @@ -300,7 +300,6 @@ export interface ITestManagementService { ): Promise; stopTests(resource: Uri): Promise; displayStopUI(message: string): Promise; - displayPickerUI(cmdSource: CommandSource, file: Uri, testFunctions: TestFunction[], debug?: boolean): Promise; runTestsImpl( cmdSource: CommandSource, resource?: Uri, @@ -309,10 +308,6 @@ export interface ITestManagementService { debug?: boolean, ): Promise; runCurrentTestFile(cmdSource: CommandSource): Promise; - - selectAndRunTestFile(cmdSource: CommandSource): Promise; - - selectAndRunTestMethod(cmdSource: CommandSource, resource: Uri, debug?: boolean): Promise; } export interface ITestManagerService extends Disposable { diff --git a/src/client/testing/main.ts b/src/client/testing/main.ts index 8289fb1f963e..568d0e7637d7 100644 --- a/src/client/testing/main.ts +++ b/src/client/testing/main.ts @@ -277,22 +277,6 @@ export class UnitTestManagementService implements ITestManagementService, Dispos const testDisplay = this.serviceContainer.get(ITestDisplay); testDisplay.displayStopTestUI(testManager.workspaceFolder, message); } - public async displayPickerUI(cmdSource: CommandSource, file: Uri, testFunctions: TestFunction[], debug?: boolean) { - const testManager = await this.getTestManager(true, file); - if (!testManager) { - return; - } - - const testDisplay = this.serviceContainer.get(ITestDisplay); - testDisplay.displayFunctionTestPickerUI( - cmdSource, - testManager.workspaceFolder, - testManager.workingDirectory, - file, - testFunctions, - debug, - ); - } public async runParametrizedTests( cmdSource: constants.CommandSource, resource: Uri, @@ -305,59 +289,8 @@ export class UnitTestManagementService implements ITestManagementService, Dispos } await this.runTestsImpl(cmdSource, resource, { testFunction: testFunctions }, undefined, debug); } - public async selectAndRunTestMethod(cmdSource: CommandSource, resource: Uri, debug?: boolean) { - const testManager = await this.getTestManager(true, resource); - if (!testManager) { - return; - } - try { - await testManager.discoverTests(cmdSource, true, true, true); - } catch (ex) { - return; - } - - const testCollectionStorage = this.serviceContainer.get( - ITestCollectionStorageService, - ); - const tests = testCollectionStorage.getTests(testManager.workspaceFolder)!; - const testDisplay = this.serviceContainer.get(ITestDisplay); - const selectedTestFn = await testDisplay.selectTestFunction(testManager.workspaceFolder.fsPath, tests); - if (!selectedTestFn) { - return; - } - - await this.runTestsImpl( - cmdSource, - testManager.workspaceFolder, - - { testFunction: [selectedTestFn.testFunction] } as TestsToRun, - false, - debug, - ); - } - public async selectAndRunTestFile(cmdSource: constants.CommandSource) { - const testManager = await this.getTestManager(true); - if (!testManager) { - return; - } - try { - await testManager.discoverTests(cmdSource, true, true, true); - } catch (ex) { - return; - } - const testCollectionStorage = this.serviceContainer.get( - ITestCollectionStorageService, - ); - const tests = testCollectionStorage.getTests(testManager.workspaceFolder)!; - const testDisplay = this.serviceContainer.get(ITestDisplay); - const selectedFile = await testDisplay.selectTestFile(testManager.workspaceFolder.fsPath, tests); - if (!selectedFile) { - return; - } - await this.runTestsImpl(cmdSource, testManager.workspaceFolder, { testFile: [selectedFile] }); - } - public async runCurrentTestFile(cmdSource: constants.CommandSource) { + public async runCurrentTestFile(cmdSource: CommandSource) { if (!this.documentManager.activeTextEditor) { return; } @@ -491,24 +424,6 @@ export class UnitTestManagementService implements ITestManagementService, Dispos return this.runTestsImpl(cmdSource, resource, testToRun, false, true); }, ), - commandManager.registerCommand( - constants.Commands.Tests_Picker_UI, - ( - _, - cmdSource: constants.CommandSource = constants.CommandSource.commandPalette, - file: Uri, - testFunctions: TestFunction[], - ) => this.displayPickerUI(cmdSource, file, testFunctions), - ), - commandManager.registerCommand( - constants.Commands.Tests_Picker_UI_Debug, - ( - _, - cmdSource: constants.CommandSource = constants.CommandSource.commandPalette, - file: Uri, - testFunctions: TestFunction[], - ) => this.displayPickerUI(cmdSource, file, testFunctions, true), - ), commandManager.registerCommand( constants.Commands.Tests_Run_Parametrized, ( @@ -528,21 +443,6 @@ export class UnitTestManagementService implements ITestManagementService, Dispos commandManager.registerCommand(constants.Commands.Tests_Ask_To_Stop_Test, () => this.displayStopUI('Stop running tests'), ), - commandManager.registerCommand( - constants.Commands.Tests_Select_And_Run_Method, - (_, cmdSource: constants.CommandSource = constants.CommandSource.commandPalette, resource: Uri) => - this.selectAndRunTestMethod(cmdSource, resource), - ), - commandManager.registerCommand( - constants.Commands.Tests_Select_And_Debug_Method, - (_, cmdSource: constants.CommandSource = constants.CommandSource.commandPalette, resource: Uri) => - this.selectAndRunTestMethod(cmdSource, resource, true), - ), - commandManager.registerCommand( - constants.Commands.Tests_Select_And_Run_File, - (_, cmdSource: constants.CommandSource = constants.CommandSource.commandPalette) => - this.selectAndRunTestFile(cmdSource), - ), commandManager.registerCommand( constants.Commands.Tests_Run_Current_File, (_, cmdSource: constants.CommandSource = constants.CommandSource.commandPalette) => From a9c7c1b9beebb2157e6e8a9599703efde2615c56 Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Mon, 24 May 2021 23:00:43 -0700 Subject: [PATCH 09/39] Remove more test commands (#16315) --- package.json | 213 +--------------------- package.nls.de.json | 6 - package.nls.es.json | 6 - package.nls.fr.json | 5 - package.nls.it.json | 5 - package.nls.ja.json | 5 - package.nls.json | 8 - package.nls.ko-kr.json | 5 - package.nls.nl.json | 6 - package.nls.pl.json | 6 - package.nls.pt-br.json | 6 - package.nls.ru.json | 6 - package.nls.tr.json | 7 - package.nls.zh-cn.json | 8 - package.nls.zh-tw.json | 8 - src/client/common/application/commands.ts | 32 +--- src/client/common/constants.ts | 22 --- src/client/testing/main.ts | 78 -------- 18 files changed, 5 insertions(+), 427 deletions(-) diff --git a/package.json b/package.json index b9fc1039caff..159fd3776eb4 100644 --- a/package.json +++ b/package.json @@ -60,15 +60,10 @@ "onDebugResolve:python", "onCommand:python.execInTerminal", "onCommand:python.sortImports", - "onCommand:python.runtests", - "onCommand:python.debugtests", "onCommand:python.setInterpreter", "onCommand:python.setShebangInterpreter", "onCommand:python.viewLanguageServerOutput", "onCommand:python.viewOutput", - "onCommand:python.selectAndDebugTestMethod", - "onCommand:python.runCurrentTestFile", - "onCommand:python.runFailedTests", "onCommand:python.execSelectionInTerminal", "onCommand:python.execSelectionInDjangoShell", "onCommand:python.buildWorkspaceSymbols", @@ -78,7 +73,6 @@ "onCommand:python.setLinter", "onCommand:python.enableLinting", "onCommand:python.createTerminal", - "onCommand:python.discoverTests", "onCommand:python.configureTests", "onCommand:python.switchOffInsidersChannel", "onCommand:python.switchToDailyChannel", @@ -170,7 +164,7 @@ { "id": "python.learnMore", "title": "Learn more", - "description": "• Explore all the features the Python extension has to offer by looking for \"Python\" in the [Command Palette](command:workbench.action.showCommands).\n• [Sign up](https://aka.ms/python-vscode-mailinglist) for tips and tutorials through our mailing list.\n• Explore more features in our [Tutorials](https://aka.ms/AA8dqti) or check [Documentation](https://aka.ms/AA8dxwy) for tips and troubleshooting.\n• Take a look at our [Release Notes](https://aka.ms/AA8dxtb) to learn more about the latest features.", + "description": "� Explore all the features the Python extension has to offer by looking for \"Python\" in the [Command Palette](command:workbench.action.showCommands).\n� [Sign up](https://aka.ms/python-vscode-mailinglist) for tips and tutorials through our mailing list.\n� Explore more features in our [Tutorials](https://aka.ms/AA8dqti) or check [Documentation](https://aka.ms/AA8dxwy) for tips and troubleshooting.\n� Take a look at our [Release Notes](https://aka.ms/AA8dxtb) to learn more about the latest features.", "media": { "image": "resources/walkthrough/python-docs-learn-more.png", "altText": "Documentation page for Python in VS Code" @@ -311,41 +305,6 @@ "command": "python.createTerminal", "title": "%python.command.python.createTerminal.title%" }, - { - "command": "python.debugTestNode", - "icon": { - "dark": "resources/dark/debug.svg", - "light": "resources/light/debug.svg" - }, - "title": "Debug" - }, - { - "category": "Python", - "command": "python.debugtests", - "icon": { - "dark": "resources/dark/debug.svg", - "light": "resources/light/debug.svg" - }, - "title": "%python.command.python.debugtests.title%" - }, - { - "category": "Python", - "command": "python.discoverTests", - "icon": { - "dark": "resources/dark/refresh.svg", - "light": "resources/light/refresh.svg" - }, - "title": "%python.command.python.discoverTests.title%" - }, - { - "category": "Python", - "command": "python.discoveringTests", - "icon": { - "dark": "resources/dark/discovering-tests.svg", - "light": "resources/light/discovering-tests.svg" - }, - "title": "%python.command.python.discoveringTests.title%" - }, { "category": "Python", "command": "python.enableLinting", @@ -412,47 +371,11 @@ "command": "python.reportIssue", "title": "%python.command.python.reportIssue.title%" }, - { - "category": "Python", - "command": "python.runCurrentTestFile", - "title": "%python.command.python.runCurrentTestFile.title%" - }, - { - "category": "Python", - "command": "python.runFailedTests", - "icon": { - "dark": "resources/dark/run-failed-tests.svg", - "light": "resources/light/run-failed-tests.svg" - }, - "title": "%python.command.python.runFailedTests.title%" - }, { "category": "Python", "command": "python.runLinting", "title": "%python.command.python.runLinting.title%" }, - { - "command": "python.runTestNode", - "icon": { - "dark": "resources/dark/start.svg", - "light": "resources/light/start.svg" - }, - "title": "Run" - }, - { - "category": "Python", - "command": "python.runtests", - "icon": { - "dark": "resources/dark/run-tests.svg", - "light": "resources/light/run-tests.svg" - }, - "title": "%python.command.python.runtests.title%" - }, - { - "category": "Python", - "command": "python.selectAndDebugTestMethod", - "title": "%python.command.python.selectAndDebugTestMethod.title%" - }, { "category": "Python", "command": "python.setInterpreter", @@ -473,15 +396,6 @@ "command": "python.startREPL", "title": "%python.command.python.startREPL.title%" }, - { - "category": "Python", - "command": "python.stopTests", - "icon": { - "dark": "resources/dark/stop.svg", - "light": "resources/light/stop.svg" - }, - "title": "%python.command.python.stopTests.title%" - }, { "category": "Python", "command": "python.switchOffInsidersChannel", @@ -1871,31 +1785,14 @@ "command": "python.clearWorkspaceInterpreter", "title": "%python.command.python.clearWorkspaceInterpreter.title%" }, - { - "category": "Python", - "command": "python.debugTestNode", - "title": "Debug", - "when": "config.noExists" - }, - { - "category": "Python", - "command": "python.discoveringTests", - "when": "config.noExists" - }, { "category": "Python", "command": "python.launchTensorBoard" }, { "category": "Python", - "command": "python.runTestNode", - "title": "Run", - "when": "config.noExists" - }, - { - "category": "Python", - "command": "python.stopTests", - "when": "config.noExists" + "command": "python.startPage.open", + "title": "%python.command.python.startPage.open.title%" }, { "category": "Python", @@ -1949,11 +1846,6 @@ "title": "Refactor: Extract Variable", "when": "editorHasSelection && editorLangId == python && !notebookEditorFocused" }, - { - "command": "python.runCurrentTestFile", - "group": "Python", - "when": "resourceLangId == python" - }, { "command": "python.sortImports", "group": "Refactor", @@ -1977,109 +1869,10 @@ } ], "explorer/context": [ - { - "command": "python.debugtests", - "group": "Python", - "when": "resourceLangId == python && !busyTests && !notebookEditorFocused" - }, { "command": "python.execInTerminal", "group": "Python", "when": "resourceLangId == python" - }, - { - "command": "python.runtests", - "group": "Python", - "when": "resourceLangId == python && !busyTests && !notebookEditorFocused" - } - ], - "view/item/context": [ - { - "command": "python.debugTestNode", - "group": "inline@1", - "when": "view == python_tests && viewItem == file && !busyTests" - }, - { - "command": "python.debugTestNode", - "group": "inline@1", - "when": "view == python_tests && viewItem == folder && !busyTests" - }, - { - "command": "python.debugTestNode", - "group": "inline@1", - "when": "view == python_tests && viewItem == function && !busyTests" - }, - { - "command": "python.debugTestNode", - "group": "inline@1", - "when": "view == python_tests && viewItem == suite && !busyTests" - }, - { - "command": "python.debugtests", - "group": "inline@1", - "when": "view == python_tests && viewItem == testWorkspaceFolder && !busyTests" - }, - { - "command": "python.discoverTests", - "group": "inline@2", - "when": "view == python_tests && viewItem == testWorkspaceFolder && !busyTests" - }, - { - "command": "python.runTestNode", - "group": "inline@0", - "when": "view == python_tests && viewItem == file && !busyTests" - }, - { - "command": "python.runTestNode", - "group": "inline@0", - "when": "view == python_tests && viewItem == folder && !busyTests" - }, - { - "command": "python.runTestNode", - "group": "inline@0", - "when": "view == python_tests && viewItem == function && !busyTests" - }, - { - "command": "python.runTestNode", - "group": "inline@0", - "when": "view == python_tests && viewItem == suite && !busyTests" - }, - { - "command": "python.runtests", - "group": "inline@0", - "when": "view == python_tests && viewItem == testWorkspaceFolder && !busyTests" - } - ], - "view/title": [ - { - "command": "python.debugtests", - "group": "navigation@3", - "when": "view == python_tests && !busyTests" - }, - { - "command": "python.discoverTests", - "group": "navigation@4", - "when": "view == python_tests && !busyTests" - }, - { - "command": "python.discoveringTests", - "group": "navigation@4", - "when": "view == python_tests && discoveringTests" - }, - { - "command": "python.runFailedTests", - "group": "navigation@2", - "when": "view == python_tests && hasFailedTests && !busyTests" - }, - { - "command": "python.runtests", - "group": "navigation@1", - "when": "view == python_tests && !busyTests" - }, - { - "command": "python.stopTests", - "group": "navigation@1", - "when": "view == python_tests && busyTests" } ] }, diff --git a/package.nls.de.json b/package.nls.de.json index 95f24755d131..dd638e16398b 100644 --- a/package.nls.de.json +++ b/package.nls.de.json @@ -3,16 +3,10 @@ "python.command.python.startREPL.title": "Starten des REPL", "python.command.python.createTerminal.title": "Terminal erstellen", "python.command.python.buildWorkspaceSymbols.title": "Arbeitsplatz-Symbole erstellen", - "python.command.python.runtests.title": "Alle Unittests ausführen", - "python.command.python.debugtests.title": "Alle Unittests debuggen", "python.command.python.execInTerminal.title": "Python-Datei im Terminal ausführen", "python.command.python.setInterpreter.title": "Interpreter auswählen", "python.command.python.refactorExtractVariable.title": "Variable extrahieren", "python.command.python.refactorExtractMethod.title": "Methode extrahieren", - "python.command.python.selectAndDebugTestMethod.title": "Unittest-Debug-Methode ausführen ...", - "python.command.python.runCurrentTestFile.title": "Ausgewählte Unittest-Datei ausführen", - "python.command.python.runFailedTests.title": "Fehlerhafte Unittests ausführen", - "python.command.python.discoverTests.title": "Unittests durchsuchen", "python.command.python.execSelectionInTerminal.title": "Selektion/Reihe in Python-Terminal ausführen", "python.command.python.execSelectionInDjangoShell.title": "Selektion/Reihe in Django-Shell ausführen", "python.command.python.goToPythonObject.title": "Gehe zu Python-Objekt", diff --git a/package.nls.es.json b/package.nls.es.json index 97e0666a52ec..c75644b838a0 100644 --- a/package.nls.es.json +++ b/package.nls.es.json @@ -3,16 +3,10 @@ "python.command.python.startREPL.title": "Nuevo REPL", "python.command.python.createTerminal.title": "Nueva terminal", "python.command.python.buildWorkspaceSymbols.title": "Compilar símbolos del área de trabajo", - "python.command.python.runtests.title": "Ejecutar todas las pruebas unitarias", - "python.command.python.debugtests.title": "Depurar todas las pruebas unitarias", "python.command.python.execInTerminal.title": "Ejecutar archivo Python en la terminal", "python.command.python.setInterpreter.title": "Seleccionar intérprete", "python.command.python.refactorExtractVariable.title": "Extraer variable", "python.command.python.refactorExtractMethod.title": "Extraer método", - "python.command.python.selectAndDebugTestMethod.title": "Método de depuración de pruebas unitarias ...", - "python.command.python.runCurrentTestFile.title": "Ejecutar archivo de prueba unitaria actual", - "python.command.python.runFailedTests.title": "Ejecutar pruebas unitarias fallidas", - "python.command.python.discoverTests.title": "Encontrar pruebas unitarias", "python.command.python.execSelectionInTerminal.title": "Ejecutar línea/selección en la terminal", "python.command.python.execSelectionInDjangoShell.title": "Ejecutar línea/selección en el intérprete de Django", "python.command.python.goToPythonObject.title": "Ir al objeto de Python", diff --git a/package.nls.fr.json b/package.nls.fr.json index 2e6b60234b72..f79d28bd4911 100644 --- a/package.nls.fr.json +++ b/package.nls.fr.json @@ -3,15 +3,10 @@ "python.command.python.startREPL.title": "Démarrer la console interactive", "python.command.python.createTerminal.title": "Créer un terminal", "python.command.python.buildWorkspaceSymbols.title": "Construire les symboles de l'espace de travail", - "python.command.python.runtests.title": "Exécuter tous les tests unitaires", - "python.command.python.debugtests.title": "Déboguer tous les tests unitaires", "python.command.python.execInTerminal.title": "Exécuter le script Python dans un terminal", "python.command.python.setInterpreter.title": "Sélectionner l'interpreteur", "python.command.python.refactorExtractVariable.title": "Extraire la variable", "python.command.python.refactorExtractMethod.title": "Extraire la méthode", - "python.command.python.selectAndDebugTestMethod.title": "Déboguer la méthode de test unitaire ...", - "python.command.python.runCurrentTestFile.title": "Exécuter le fichier de test unitaire courant", - "python.command.python.runFailedTests.title": "Exécuter les derniers test unitaires échoués", "python.command.python.execSelectionInTerminal.title": "Exécuter la ligne/sélection dans un terminal Python", "python.command.python.execSelectionInDjangoShell.title": "Exécuter la ligne/sélection dans un shell Django", "python.command.python.goToPythonObject.title": "Se rendre à l'objet Python", diff --git a/package.nls.it.json b/package.nls.it.json index bebe0580da7c..a88f39eb11a4 100644 --- a/package.nls.it.json +++ b/package.nls.it.json @@ -3,15 +3,10 @@ "python.command.python.startREPL.title": "Apri nuova REPL", "python.command.python.createTerminal.title": "Apri nuovo terminale", "python.command.python.buildWorkspaceSymbols.title": "Compila simboli dello spazio di lavoro", - "python.command.python.runtests.title": "Esegui tutti i test", - "python.command.python.debugtests.title": "Esegui debug di tutti i test", "python.command.python.execInTerminal.title": "Esegui file Python nel terminale", "python.command.python.setInterpreter.title": "Seleziona interprete", "python.command.python.refactorExtractVariable.title": "Estrai variable", "python.command.python.refactorExtractMethod.title": "Estrai metodo", - "python.command.python.selectAndDebugTestMethod.title": "Esegui debug del metodo di test ...", - "python.command.python.runCurrentTestFile.title": "Esegui file di test attuale", - "python.command.python.runFailedTests.title": "Esegui test falliti", "python.command.python.execSelectionInTerminal.title": "Esegui selezione/linea nel terminale di Python", "python.command.python.execSelectionInDjangoShell.title": "Esegui selezione/linea nella shell Django", "python.command.python.goToPythonObject.title": "Vai a oggetto Python", diff --git a/package.nls.ja.json b/package.nls.ja.json index 717a4ecc54f8..e10a8e6ea872 100644 --- a/package.nls.ja.json +++ b/package.nls.ja.json @@ -2,15 +2,10 @@ "python.command.python.sortImports.title": "import 文を並び替える", "python.command.python.startREPL.title": "REPL を開始", "python.command.python.buildWorkspaceSymbols.title": "ワークスペースのシンボルをビルド", - "python.command.python.runtests.title": "すべての単体テストを実行", - "python.command.python.debugtests.title": "すべての単体テストをデバッグ", "python.command.python.execInTerminal.title": "ターミナルで Python ファイルを実行", "python.command.python.setInterpreter.title": "インタープリターを選択", "python.command.python.refactorExtractVariable.title": "変数を抽出", "python.command.python.refactorExtractMethod.title": "メソッドを抽出", - "python.command.python.selectAndDebugTestMethod.title": "単体テストメソッドをデバッグ...", - "python.command.python.runCurrentTestFile.title": "現在の単体テストファイルを実行", - "python.command.python.runFailedTests.title": "失敗した単体テストを実行", "python.command.python.execSelectionInTerminal.title": "Python ターミナルで選択範囲/行を実行", "python.command.python.execSelectionInDjangoShell.title": "Django シェルで選択範囲/行を実行", "python.command.python.goToPythonObject.title": "Python オブジェクトに移動", diff --git a/package.nls.json b/package.nls.json index 8e32a0203ff6..ce1a7f3242c0 100644 --- a/package.nls.json +++ b/package.nls.json @@ -3,8 +3,6 @@ "python.command.python.startREPL.title": "Start REPL", "python.command.python.createTerminal.title": "Create Terminal", "python.command.python.buildWorkspaceSymbols.title": "Build Workspace Symbols", - "python.command.python.runtests.title": "Run All Tests", - "python.command.python.debugtests.title": "Debug All Tests", "python.command.python.execInTerminal.title": "Run Python File in Terminal", "python.command.python.setInterpreter.title": "Select Interpreter", "python.command.python.switchOffInsidersChannel.title": "Switch to Default Channel", @@ -15,12 +13,6 @@ "python.command.python.refactorExtractMethod.title": "Extract Method", "python.command.python.viewOutput.title": "Show Output", "python.command.python.viewLanguageServerOutput.title": "Show Language Server Output", - "python.command.python.selectAndDebugTestMethod.title": "Debug Test Method ...", - "python.command.python.runCurrentTestFile.title": "Run Current Test File", - "python.command.python.runFailedTests.title": "Run Failed Tests", - "python.command.python.discoverTests.title": "Discover Tests", - "python.command.python.discoveringTests.title": "Discovering...", - "python.command.python.stopTests.title": "Stop", "python.command.python.configureTests.title": "Configure Tests", "python.command.python.execSelectionInTerminal.title": "Run Selection/Line in Python Terminal", "python.command.python.execSelectionInDjangoShell.title": "Run Selection/Line in Django Shell", diff --git a/package.nls.ko-kr.json b/package.nls.ko-kr.json index c9562d08fe9f..910d256f31a5 100644 --- a/package.nls.ko-kr.json +++ b/package.nls.ko-kr.json @@ -2,15 +2,10 @@ "python.command.python.sortImports.title": "Import문 정렬", "python.command.python.startREPL.title": "REPL 시작", "python.command.python.buildWorkspaceSymbols.title": "작업 영역 기호 빌드", - "python.command.python.runtests.title": "모든 단위 테스트 실행", - "python.command.python.debugtests.title": "모든 단위 테스트 디버그", "python.command.python.execInTerminal.title": "터미널에서 Python 파일 실행", "python.command.python.setInterpreter.title": "인터프리터 선택", "python.command.python.refactorExtractVariable.title": "변수 추출", "python.command.python.refactorExtractMethod.title": "메서드 추출", - "python.command.python.selectAndDebugTestMethod.title": "단위 테스트 메서드 디버그 ...", - "python.command.python.runCurrentTestFile.title": "현재 단위 테스트 파일 실행", - "python.command.python.runFailedTests.title": "실패한 단위 테스트 실행", "python.command.python.execSelectionInTerminal.title": "Python 터미널에서 선택 영역/줄 실행", "python.command.python.execSelectionInDjangoShell.title": "Django 셸에서 선택 영역/줄 실행", "python.command.python.goToPythonObject.title": " Python 객체로 이동", diff --git a/package.nls.nl.json b/package.nls.nl.json index 9a86994b9594..a98570ec8035 100644 --- a/package.nls.nl.json +++ b/package.nls.nl.json @@ -3,16 +3,10 @@ "python.command.python.startREPL.title": "REPL starten", "python.command.python.createTerminal.title": "Terminal aanmaken", "python.command.python.buildWorkspaceSymbols.title": "Werkruimte-symbolen aanmaken", - "python.command.python.runtests.title": "Alle unittests uitvoeren", - "python.command.python.debugtests.title": "Alle unittests debuggen", "python.command.python.execInTerminal.title": "Python-bestand in terminal uitvoeren", "python.command.python.setInterpreter.title": "Interpreter selecteren", "python.command.python.refactorExtractVariable.title": "Variabelen selecteren", "python.command.python.refactorExtractMethod.title": "Methode selecteren", - "python.command.python.selectAndDebugTestMethod.title": "Unittest-methode debuggen ...", - "python.command.python.runCurrentTestFile.title": "Huidige unittest-bestand uitvoeren", - "python.command.python.runFailedTests.title": "Gefaalde unittests uitvoeren", - "python.command.python.discoverTests.title": "Unittests doorzoeken", "python.command.python.execSelectionInTerminal.title": "Selectie/rij in Python-terminal uitvoeren", "python.command.python.execSelectionInDjangoShell.title": "Selectie/rij in Django-shell uitvoeren", "python.command.python.goToPythonObject.title": "Naar Python-object gaan", diff --git a/package.nls.pl.json b/package.nls.pl.json index d31fc094ce10..fefb0d9f8904 100644 --- a/package.nls.pl.json +++ b/package.nls.pl.json @@ -3,17 +3,11 @@ "python.command.python.startREPL.title": "Uruchom REPL", "python.command.python.createTerminal.title": "Otwórz Terminal", "python.command.python.buildWorkspaceSymbols.title": "Zbuduj symbole dla przestrzeni roboczej", - "python.command.python.runtests.title": "Uruchom wszystkie testy jednostkowe", - "python.command.python.debugtests.title": "Debuguj wszystkie testy jednostkowe", "python.command.python.execInTerminal.title": "Uruchom plik pythonowy w terminalu", "python.command.python.setInterpreter.title": "Wybierz wersję interpretera", "python.command.python.refactorExtractVariable.title": "Wyodrębnij zmienną", "python.command.python.refactorExtractMethod.title": "Wyodrębnij metodę", "python.command.python.viewOutput.title": "Pokaż wyniki", - "python.command.python.selectAndDebugTestMethod.title": "Debuguj metodę testów jednostkowych ...", - "python.command.python.runCurrentTestFile.title": "Uruchom bieżący plik z testami jednostkowymi", - "python.command.python.runFailedTests.title": "Uruchom testy jednostkowe, które się nie powiodły", - "python.command.python.discoverTests.title": "Wyszukaj testy jednostkowe", "python.command.python.configureTests.title": "Konfiguruj testy jednostkowe", "python.command.python.execSelectionInTerminal.title": "Uruchom zaznaczony obszar w interpreterze Pythona", "python.command.python.execSelectionInDjangoShell.title": "Uruchom zaznaczony obszar w powłoce Django", diff --git a/package.nls.pt-br.json b/package.nls.pt-br.json index e27ad034b781..01e8cebfb9ce 100644 --- a/package.nls.pt-br.json +++ b/package.nls.pt-br.json @@ -3,16 +3,10 @@ "python.command.python.startREPL.title": "Iniciar REPL", "python.command.python.createTerminal.title": "Criar Terminal", "python.command.python.buildWorkspaceSymbols.title": "Construir Símbolos da Área de Trabalho", - "python.command.python.runtests.title": "Executar Todos os Testes Unitários", - "python.command.python.debugtests.title": "Depurar Todos os Testes Unitários", "python.command.python.execInTerminal.title": "Executar Arquivo no Terminal", "python.command.python.setInterpreter.title": "Selecionar Interpretador", "python.command.python.refactorExtractVariable.title": "Extrair Variável", "python.command.python.refactorExtractMethod.title": "Extrair Método", - "python.command.python.selectAndDebugTestMethod.title": "Depurar Testes Unitários do Método ...", - "python.command.python.runCurrentTestFile.title": "Executar o Arquivo de Testes Unitários Atual", - "python.command.python.runFailedTests.title": "Executar Testes Unitários com Falhas", - "python.command.python.discoverTests.title": "Descobrir Testes Unitários", "python.command.python.execSelectionInTerminal.title": "Executar Seleção/Linha no Terminal", "python.command.python.execSelectionInDjangoShell.title": "Executar Seleção/Linha no Django Shell", "python.command.python.goToPythonObject.title": "Ir para Objeto Python", diff --git a/package.nls.ru.json b/package.nls.ru.json index 7463070237b2..abb8a67f1d86 100644 --- a/package.nls.ru.json +++ b/package.nls.ru.json @@ -2,16 +2,10 @@ "python.command.python.sortImports.title": "Отсортировать Imports", "python.command.python.startREPL.title": "Открыть REPL", "python.command.python.buildWorkspaceSymbols.title": "Собрать символы рабочего пространства", - "python.command.python.runtests.title": "Запустить все тесты", - "python.command.python.debugtests.title": "Запустить все тесты под отладчиком", "python.command.python.execInTerminal.title": "Выполнить файл в консоли", "python.command.python.setInterpreter.title": "Выбрать интерпретатор", "python.command.python.refactorExtractVariable.title": "Извлечь в переменную", "python.command.python.refactorExtractMethod.title": "Извлечь в метод", - "python.command.python.selectAndDebugTestMethod.title": "Отладить тестовый метод...", - "python.command.python.runCurrentTestFile.title": "Запустить текущий тестовый файл", - "python.command.python.runFailedTests.title": "Запустить непрошедшие тесты", - "python.command.python.discoverTests.title": "Обнаружить тесты", "python.command.python.execSelectionInTerminal.title": "Выполнить выбранный текст или текущую строку в консоли", "python.command.python.execSelectionInDjangoShell.title": "Выполнить выбранный текст или текущую строку в оболочке Django", "python.command.python.goToPythonObject.title": "Перейти к объекту Python", diff --git a/package.nls.tr.json b/package.nls.tr.json index 4dd32315b3e5..e578fd7c9416 100644 --- a/package.nls.tr.json +++ b/package.nls.tr.json @@ -3,17 +3,10 @@ "python.command.python.startREPL.title": "REPL Başlat", "python.command.python.createTerminal.title": "Terminal Oluştur", "python.command.python.buildWorkspaceSymbols.title": "Çalışma Alanındaki Sembolleri Derle", - "python.command.python.runtests.title": "Testleri Çalıştır", - "python.command.python.debugtests.title": "Testleri Debug Et", "python.command.python.execInTerminal.title": "Terminalde Çalıştır", "python.command.python.setInterpreter.title": "Bir Interpreter Seçin", "python.command.python.refactorExtractVariable.title": "Değişken Çıkar", "python.command.python.refactorExtractMethod.title": "Metot Çıkar", - "python.command.python.selectAndDebugTestMethod.title": "Test Metodu Debug Et", - "python.command.python.runCurrentTestFile.title": "Aktif Test Dosyasını Çalıştır", - "python.command.python.runFailedTests.title": "Başarısız Testleri Çalıştır", - "python.command.python.discoverTests.title": "Testleri Keşfet", - "python.command.python.discoveringTests.title": "Testler Keşfediliyor...", "python.command.python.execSelectionInTerminal.title": "Seçimi/Satırı Terminalde Çalıştır", "python.command.python.execSelectionInDjangoShell.title": "Seçimi/Satırı Django Shell'inde Çalıştır", "python.command.python.goToPythonObject.title": "Python Nesnesine Git", diff --git a/package.nls.zh-cn.json b/package.nls.zh-cn.json index bd3346e4686d..bb6e9b4c1704 100644 --- a/package.nls.zh-cn.json +++ b/package.nls.zh-cn.json @@ -3,8 +3,6 @@ "python.command.python.startREPL.title": "启动 REPL", "python.command.python.createTerminal.title": "创建终端", "python.command.python.buildWorkspaceSymbols.title": "构建工作区符号", - "python.command.python.runtests.title": "运行所有单元测试", - "python.command.python.debugtests.title": "调试所有单元测试", "python.command.python.execInTerminal.title": "在终端中运行 Python 文件", "python.command.python.setInterpreter.title": "选择解释器", "python.command.python.switchOffInsidersChannel.title": "切换到默认版本", @@ -15,12 +13,6 @@ "python.command.python.refactorExtractMethod.title": "提取方法", "python.command.python.viewOutput.title": "显示输出", "python.command.python.viewLanguageServerOutput.title": "显示语言服务器输出", - "python.command.python.selectAndDebugTestMethod.title": "调试单元测试方法...", - "python.command.python.runCurrentTestFile.title": "运行当前单元测试文件", - "python.command.python.runFailedTests.title": "运行失败的单元测试", - "python.command.python.discoverTests.title": "检测单元测试", - "python.command.python.discoveringTests.title": "检测中...", - "python.command.python.stopTests.title": "停止", "python.command.python.configureTests.title": "配置单元测试", "python.command.python.execSelectionInTerminal.title": "在 Python 终端中运行选定内容/行", "python.command.python.execSelectionInDjangoShell.title": "在 Django Shell 中运行选定内容/行", diff --git a/package.nls.zh-tw.json b/package.nls.zh-tw.json index 6cf249c38190..2664d32226bf 100644 --- a/package.nls.zh-tw.json +++ b/package.nls.zh-tw.json @@ -3,15 +3,10 @@ "python.command.python.startREPL.title": "啟動 REPL", "python.command.python.createTerminal.title": "建立終端機", "python.command.python.buildWorkspaceSymbols.title": "建構工作區符號", - "python.command.python.runtests.title": "執行所有單元測試", - "python.command.python.debugtests.title": "偵錯所有單元測試", "python.command.python.execInTerminal.title": "在終端機中執行 Python 檔案", "python.command.python.setInterpreter.title": "選擇直譯器", "python.command.python.refactorExtractVariable.title": "提取變數", "python.command.python.refactorExtractMethod.title": "提取方法", - "python.command.python.selectAndDebugTestMethod.title": "偵錯單元測試方法…", - "python.command.python.runCurrentTestFile.title": "執行目前單元測試檔案", - "python.command.python.runFailedTests.title": "執行失敗的單元測試", "python.command.python.execSelectionInTerminal.title": "在 Python 終端機中執行選定內容/行", "python.command.python.execSelectionInDjangoShell.title": "在 Django Shell 中執行選定內容/行", "python.command.python.goToPythonObject.title": "跳至 Python 物件", @@ -24,14 +19,11 @@ "python.snippet.launch.flask.label": "Python: Flask", "python.snippet.launch.pyramid.label": "Python: Pyramid 程式", "python.snippet.launch.attach.label": "Python: 附加", - "python.command.python.discoverTests.title": "探索 Unit 測試項目", "python.command.python.switchOffInsidersChannel.title": "切換至預設頻道", "python.command.python.switchToDailyChannel.title": "切換至 Insiders 每日頻道", "python.command.python.switchToWeeklyChannel.title": "切換至 Insiders 每週頻道", "python.command.python.viewOutput.title": "顯示輸出", "python.command.python.viewLanguageServerOutput.title": "顯示語言伺服器輸出", - "python.command.python.discoveringTests.title": "正在探索...", - "python.command.python.stopTests.title": "停止", "python.command.python.configureTests.title": "設定測試", "python.command.python.enableSourceMapSupport.title": "啟用供偵錯延伸模組的原始碼映射 (Source Map) 支援", "python.command.python.analysis.clearCache.title": "清除模組分析快取", diff --git a/src/client/common/application/commands.ts b/src/client/common/application/commands.ts index 8e3bf0aa9f6f..2181516df229 100644 --- a/src/client/common/application/commands.ts +++ b/src/client/common/application/commands.ts @@ -6,8 +6,8 @@ import { CancellationToken, Position, TextDocument, Uri } from 'vscode'; import { Commands as LSCommands } from '../../activation/commands'; import { TensorBoardEntrypoint, TensorBoardEntrypointTrigger } from '../../tensorBoard/constants'; -import { TestDataItem, TestFunction, TestsToRun, TestWorkspaceFolder } from '../../testing/common/types'; -import { Channel, Commands, CommandSource } from '../constants'; +import { Commands } from '../constants'; +import { Channel, CommandSource, ICommandManager } from './types'; export type CommandsWithoutArgs = keyof ICommandNameWithoutArgumentTypeMapping; @@ -40,9 +40,6 @@ interface ICommandNameWithoutArgumentTypeMapping { [Commands.Exec_Selection_In_Terminal]: []; [Commands.Exec_Selection_In_Django_Shell]: []; [Commands.Create_Terminal]: []; - [Commands.Tests_Ask_To_Stop_Discovery]: []; - [Commands.Tests_Ask_To_Stop_Test]: []; - [Commands.Tests_Discovering]: []; [Commands.PickLocalProcess]: []; [Commands.OpenStartPage]: []; [Commands.ClearStorage]: []; @@ -94,31 +91,6 @@ export interface ICommandNameArgumentTypeMapping extends ICommandNameWithoutArgu [Commands.Sort_Imports]: [undefined, Uri]; [Commands.Exec_In_Terminal]: [undefined, Uri]; [Commands.Exec_In_Terminal_Icon]: [undefined, Uri]; - [Commands.Tests_Run_Current_File]: [undefined, CommandSource]; - [Commands.Tests_Stop]: [undefined, Uri]; - [Commands.Test_Reveal_Test_Item]: [TestDataItem]; - // When command is invoked from a tree node, first argument is the node data. - [Commands.Tests_Run]: [ - undefined | TestWorkspaceFolder, - undefined | CommandSource, - undefined | Uri, - undefined | TestsToRun, - ]; - // When command is invoked from a tree node, first argument is the node data. - [Commands.Tests_Debug]: [ - undefined | TestWorkspaceFolder, - undefined | CommandSource, - undefined | Uri, - undefined | TestsToRun, - ]; - [Commands.Tests_Run_Parametrized]: [undefined, undefined | CommandSource, Uri, TestFunction[], boolean]; - // When command is invoked from a tree node, first argument is the node data. - [Commands.Tests_Discover]: [undefined | TestWorkspaceFolder, undefined | CommandSource, undefined | Uri]; - [Commands.Tests_Run_Failed]: [undefined, CommandSource, Uri]; [Commands.Tests_Configure]: [undefined, undefined | CommandSource, undefined | Uri]; - // When command is invoked from a tree node, first argument is the node data. - [Commands.runTestNode]: [TestDataItem]; - // When command is invoked from a tree node, first argument is the node data. - [Commands.debugTestNode]: [TestDataItem]; [Commands.LaunchTensorBoard]: [TensorBoardEntrypoint, TensorBoardEntrypointTrigger]; } diff --git a/src/client/common/constants.ts b/src/client/common/constants.ts index a66696f767b2..5b00d4de5918 100644 --- a/src/client/common/constants.ts +++ b/src/client/common/constants.ts @@ -38,19 +38,8 @@ export namespace Commands { export const Exec_Selection_In_Terminal = 'python.execSelectionInTerminal'; export const Exec_Selection_In_Django_Shell = 'python.execSelectionInDjangoShell'; export const Tests_Configure = 'python.configureTests'; - export const Tests_Discover = 'python.discoverTests'; - export const Tests_Discovering = 'python.discoveringTests'; - export const Tests_Run_Failed = 'python.runFailedTests'; export const Sort_Imports = 'python.sortImports'; - export const Tests_Run = 'python.runtests'; - export const Tests_Run_Parametrized = 'python.runParametrizedTests'; - export const Tests_Debug = 'python.debugtests'; - export const Tests_Ask_To_Stop_Test = 'python.askToStopTests'; - export const Tests_Ask_To_Stop_Discovery = 'python.askToStopTestDiscovery'; - export const Tests_Stop = 'python.stopTests'; - export const Test_Reveal_Test_Item = 'python.revealTestItem'; export const ViewOutput = 'python.viewOutput'; - export const Tests_Run_Current_File = 'python.runCurrentTestFile'; export const Refactor_Extract_Variable = 'python.refactorExtractVariable'; export const Refactor_Extract_Method = 'python.refactorExtractMethod'; export const Build_Workspace_Symbols = 'python.buildWorkspaceSymbols'; @@ -60,8 +49,6 @@ export namespace Commands { export const Enable_Linter = 'python.enableLinting'; export const Run_Linter = 'python.runLinting'; export const Enable_SourceMap_Support = 'python.enableSourceMapSupport'; - export const runTestNode = 'python.runTestNode'; - export const debugTestNode = 'python.debugTestNode'; export const SwitchOffInsidersChannel = 'python.switchOffInsidersChannel'; export const SwitchToInsidersDaily = 'python.switchToDailyChannel'; export const SwitchToInsidersWeekly = 'python.switchToWeeklyChannel'; @@ -87,15 +74,6 @@ export namespace Octicons { export const Star = '$(star)'; } -export namespace Text { - export const CodeLensRunUnitTest = 'Run Test'; - export const CodeLensDebugUnitTest = 'Debug Test'; -} -export namespace Delays { - // Max time to wait before aborting the generation of code lenses for unit tests - export const MaxUnitTestCodeLensDelay = 5000; -} - export const DEFAULT_INTERPRETER_SETTING = 'python'; export const STANDARD_OUTPUT_CHANNEL = 'STANDARD_OUTPUT_CHANNEL'; diff --git a/src/client/testing/main.ts b/src/client/testing/main.ts index 568d0e7637d7..475cbbe629d3 100644 --- a/src/client/testing/main.ts +++ b/src/client/testing/main.ts @@ -17,7 +17,6 @@ import * as constants from '../common/constants'; import '../common/extensions'; import { traceError } from '../common/logger'; import { IConfigurationService, IDisposableRegistry, IOutputChannel, Product, Resource } from '../common/types'; -import { noop } from '../common/utils/misc'; import { IInterpreterService } from '../interpreter/contracts'; import { IServiceContainer } from '../ioc/types'; import { EventName } from '../telemetry/constants'; @@ -39,7 +38,6 @@ import { ITestsHelper, TestStatus, TestsToRun, - TestWorkspaceFolder, WorkspaceTestStatus, } from './common/types'; import { TEST_OUTPUT_CHANNEL } from './constants'; @@ -365,22 +363,6 @@ export class UnitTestManagementService implements ITestManagementService, Dispos const commandManager = this.serviceContainer.get(ICommandManager); const disposables = [ - commandManager.registerCommand( - constants.Commands.Tests_Discover, - ( - treeNode?: TestWorkspaceFolder, - cmdSource: constants.CommandSource = constants.CommandSource.commandPalette, - resource?: Uri, - ) => { - if (treeNode && treeNode instanceof TestWorkspaceFolder) { - resource = treeNode.resource; - cmdSource = constants.CommandSource.testExplorer; - } - // Ignore the exceptions returned. - // This command will be invoked from other places of the extension. - return this.discoverTests(cmdSource, resource, true, true, false, true).ignoreErrors(); - }, - ), commandManager.registerCommand( constants.Commands.Tests_Configure, (_, _cmdSource: constants.CommandSource = constants.CommandSource.commandPalette, resource?: Uri) => { @@ -389,66 +371,6 @@ export class UnitTestManagementService implements ITestManagementService, Dispos this.configureTests(resource).ignoreErrors(); }, ), - commandManager.registerCommand( - constants.Commands.Tests_Run_Failed, - (_, cmdSource: constants.CommandSource = constants.CommandSource.commandPalette, resource: Uri) => - this.runTestsImpl(cmdSource, resource, undefined, true), - ), - commandManager.registerCommand( - constants.Commands.Tests_Run, - ( - treeNode?: TestWorkspaceFolder, - cmdSource: constants.CommandSource = constants.CommandSource.commandPalette, - resource?: Uri, - testToRun?: TestsToRun, - ) => { - if (treeNode && treeNode instanceof TestWorkspaceFolder) { - resource = treeNode.resource; - cmdSource = constants.CommandSource.testExplorer; - } - return this.runTestsImpl(cmdSource, resource, testToRun); - }, - ), - commandManager.registerCommand( - constants.Commands.Tests_Debug, - ( - treeNode?: TestWorkspaceFolder, - cmdSource: constants.CommandSource = constants.CommandSource.commandPalette, - resource?: Uri, - testToRun?: TestsToRun, - ) => { - if (treeNode && treeNode instanceof TestWorkspaceFolder) { - resource = treeNode.resource; - cmdSource = constants.CommandSource.testExplorer; - } - return this.runTestsImpl(cmdSource, resource, testToRun, false, true); - }, - ), - commandManager.registerCommand( - constants.Commands.Tests_Run_Parametrized, - ( - _, - cmdSource: constants.CommandSource = constants.CommandSource.commandPalette, - resource: Uri, - testFunctions: TestFunction[], - debug: boolean, - ) => this.runParametrizedTests(cmdSource, resource, testFunctions, debug), - ), - commandManager.registerCommand(constants.Commands.Tests_Stop, (_, resource: Uri) => - this.stopTests(resource), - ), - commandManager.registerCommand(constants.Commands.Tests_Ask_To_Stop_Discovery, () => - this.displayStopUI('Stop discovering tests'), - ), - commandManager.registerCommand(constants.Commands.Tests_Ask_To_Stop_Test, () => - this.displayStopUI('Stop running tests'), - ), - commandManager.registerCommand( - constants.Commands.Tests_Run_Current_File, - (_, cmdSource: constants.CommandSource = constants.CommandSource.commandPalette) => - this.runCurrentTestFile(cmdSource), - ), - commandManager.registerCommand(constants.Commands.Tests_Discovering, noop), ]; disposablesRegistry.push(...disposables); From 8da632d2fb44eb410658c7d7bb120aa1512b671b Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Wed, 26 May 2021 11:37:43 -0700 Subject: [PATCH 10/39] Remove testing dependency on language server (#16319) --- src/client/activation/jedi.ts | 7 - .../activation/jedi/languageServerProxy.ts | 18 --- .../languageServer/languageServerProxy.ts | 13 -- .../activation/node/languageServerProxy.ts | 14 -- src/client/extensionActivation.ts | 2 - .../testing/common/services/contextService.ts | 59 -------- src/client/testing/common/types.ts | 5 - src/client/testing/main.ts | 15 +- src/client/testing/serviceRegistry.ts | 4 +- src/client/testing/types.ts | 3 - .../languageServer.unit.test.ts | 25 +--- .../services/contextService.unit.test.ts | 137 ------------------ src/test/testing/serviceRegistry.ts | 3 - 13 files changed, 6 insertions(+), 299 deletions(-) delete mode 100644 src/client/testing/common/services/contextService.ts delete mode 100644 src/test/testing/common/services/contextService.unit.test.ts diff --git a/src/client/activation/jedi.ts b/src/client/activation/jedi.ts index b82aee4edca6..f65763ac8d72 100644 --- a/src/client/activation/jedi.ts +++ b/src/client/activation/jedi.ts @@ -26,7 +26,6 @@ import { } from 'vscode'; import { PYTHON } from '../common/constants'; -import { traceError } from '../common/logger'; import { IConfigurationService, IDisposable, IExtensionContext, Resource } from '../common/types'; import { IShebangCodeLensProvider } from '../interpreter/contracts'; import { IServiceContainer, IServiceManager } from '../ioc/types'; @@ -40,7 +39,6 @@ import { PythonRenameProvider } from '../providers/renameProvider'; import { PythonSignatureProvider } from '../providers/signatureProvider'; import { JediSymbolProvider } from '../providers/symbolProvider'; import { PythonEnvironment } from '../pythonEnvironments/info'; -import { ITestingService } from '../testing/types'; import { WorkspaceSymbols } from '../workspaceSymbols/main'; import { ILanguageServerActivator } from './types'; @@ -90,11 +88,6 @@ export class JediExtensionActivator implements ILanguageServerActivator { JediExtensionActivator.workspaceSymbols = new WorkspaceSymbols(serviceContainer); context.subscriptions.push(JediExtensionActivator.workspaceSymbols); } - - const testManagementService = this.serviceManager.get(ITestingService); - testManagementService - .activate(this.symbolProvider) - .catch((ex) => traceError('Failed to activate Unit Tests', ex)); } public deactivate() { diff --git a/src/client/activation/jedi/languageServerProxy.ts b/src/client/activation/jedi/languageServerProxy.ts index 2be54d3a0a49..977a4efb9710 100644 --- a/src/client/activation/jedi/languageServerProxy.ts +++ b/src/client/activation/jedi/languageServerProxy.ts @@ -14,12 +14,9 @@ import { ChildProcess } from 'child_process'; import { DeprecatePythonPath } from '../../common/experiments/groups'; import { traceDecorators, traceError } from '../../common/logger'; import { IExperimentService, IInterpreterPathService, Resource } from '../../common/types'; -import { swallowExceptions } from '../../common/utils/decorators'; -import { LanguageServerSymbolProvider } from '../../providers/symbolProvider'; import { PythonEnvironment } from '../../pythonEnvironments/info'; import { captureTelemetry } from '../../telemetry'; import { EventName } from '../../telemetry/constants'; -import { ITestingService } from '../../testing/types'; import { FileBasedCancellationStrategy } from '../common/cancellationUtils'; import { LanguageClientMiddleware } from '../languageClientMiddleware'; import { ProgressReporting } from '../progress'; @@ -40,7 +37,6 @@ export class JediLanguageServerProxy implements ILanguageServerProxy { constructor( @inject(ILanguageClientFactory) private readonly factory: ILanguageClientFactory, - @inject(ITestingService) private readonly testManager: ITestingService, @inject(IExperimentService) private readonly experiments: IExperimentService, @inject(IInterpreterPathService) private readonly interpreterPathService: IInterpreterPathService, ) {} @@ -122,12 +118,6 @@ export class JediLanguageServerProxy implements ILanguageServerProxy { this.disposables.push(this.languageClient.start()); await this.serverReady(); - if (this.disposed) { - // Check if it got disposed in the interim. - return Promise.resolve(); - } - - await this.registerTestServices(); return Promise.resolve(); } @@ -149,14 +139,6 @@ export class JediLanguageServerProxy implements ILanguageServerProxy { } } - @swallowExceptions('Activating Unit Tests Manager for Jedi language server') - protected async registerTestServices(): Promise { - if (!this.languageClient) { - throw new Error('languageClient not initialized'); - } - await this.testManager.activate(new LanguageServerSymbolProvider(this.languageClient)); - } - private registerHandlers() { if (this.disposed) { // Check if it got disposed in the interim. diff --git a/src/client/activation/languageServer/languageServerProxy.ts b/src/client/activation/languageServer/languageServerProxy.ts index e3a471f54a06..7432723807d6 100644 --- a/src/client/activation/languageServer/languageServerProxy.ts +++ b/src/client/activation/languageServer/languageServerProxy.ts @@ -8,13 +8,10 @@ import { Disposable, LanguageClient, LanguageClientOptions, State } from 'vscode import { traceDecorators, traceError } from '../../common/logger'; import { IConfigurationService, Resource } from '../../common/types'; import { createDeferred, Deferred, sleep } from '../../common/utils/async'; -import { swallowExceptions } from '../../common/utils/decorators'; import { noop } from '../../common/utils/misc'; -import { LanguageServerSymbolProvider } from '../../providers/symbolProvider'; import { PythonEnvironment } from '../../pythonEnvironments/info'; import { captureTelemetry, sendTelemetryEvent } from '../../telemetry'; import { EventName } from '../../telemetry/constants'; -import { ITestingService } from '../../testing/types'; import { ProgressReporting } from '../progress'; import { ILanguageClientFactory, ILanguageServerProxy } from '../types'; @@ -28,7 +25,6 @@ export class DotNetLanguageServerProxy implements ILanguageServerProxy { constructor( @inject(ILanguageClientFactory) private readonly factory: ILanguageClientFactory, - @inject(ITestingService) private readonly testManager: ITestingService, @inject(IConfigurationService) private readonly configurationService: IConfigurationService, ) { this.startupCompleted = createDeferred(); @@ -77,8 +73,6 @@ export class DotNetLanguageServerProxy implements ILanguageServerProxy { // Check if it got disposed in the interim. return; } - - await this.registerTestServices(); } else { await this.startupCompleted.promise; } @@ -108,13 +102,6 @@ export class DotNetLanguageServerProxy implements ILanguageServerProxy { } this.startupCompleted.resolve(); } - @swallowExceptions('Activating Unit Tests Manager for Microsoft Python Language Server') - protected async registerTestServices() { - if (!this.languageClient) { - throw new Error('languageClient not initialized'); - } - await this.testManager.activate(new LanguageServerSymbolProvider(this.languageClient!)); - } private registerHandlers(resource: Resource) { if (this.disposed) { diff --git a/src/client/activation/node/languageServerProxy.ts b/src/client/activation/node/languageServerProxy.ts index a309b6ec1d85..ba0ede400b55 100644 --- a/src/client/activation/node/languageServerProxy.ts +++ b/src/client/activation/node/languageServerProxy.ts @@ -15,14 +15,11 @@ import { DeprecatePythonPath } from '../../common/experiments/groups'; import { traceDecorators, traceError } from '../../common/logger'; import { IConfigurationService, IExperimentService, IInterpreterPathService, Resource } from '../../common/types'; import { createDeferred, Deferred, sleep } from '../../common/utils/async'; -import { swallowExceptions } from '../../common/utils/decorators'; import { noop } from '../../common/utils/misc'; import { IEnvironmentVariablesProvider } from '../../common/variables/types'; -import { LanguageServerSymbolProvider } from '../../providers/symbolProvider'; import { PythonEnvironment } from '../../pythonEnvironments/info'; import { captureTelemetry, sendTelemetryEvent } from '../../telemetry'; import { EventName } from '../../telemetry/constants'; -import { ITestingService } from '../../testing/types'; import { FileBasedCancellationStrategy } from '../common/cancellationUtils'; import { ProgressReporting } from '../progress'; import { ILanguageClientFactory, ILanguageServerFolderService, ILanguageServerProxy } from '../types'; @@ -62,7 +59,6 @@ export class NodeLanguageServerProxy implements ILanguageServerProxy { constructor( @inject(ILanguageClientFactory) private readonly factory: ILanguageClientFactory, - @inject(ITestingService) private readonly testManager: ITestingService, @inject(IConfigurationService) private readonly configurationService: IConfigurationService, @inject(ILanguageServerFolderService) private readonly folderService: ILanguageServerFolderService, @inject(IExperimentService) private readonly experimentService: IExperimentService, @@ -138,8 +134,6 @@ export class NodeLanguageServerProxy implements ILanguageServerProxy { // Check if it got disposed in the interim. return; } - - await this.registerTestServices(); } else { await this.startupCompleted.promise; } @@ -164,14 +158,6 @@ export class NodeLanguageServerProxy implements ILanguageServerProxy { this.startupCompleted.resolve(); } - @swallowExceptions('Activating Unit Tests Manager for Pylance language server') - protected async registerTestServices() { - if (!this.languageClient) { - throw new Error('languageClient not initialized'); - } - await this.testManager.activate(new LanguageServerSymbolProvider(this.languageClient!)); - } - private registerHandlers(resource: Resource) { if (this.disposed) { // Check if it got disposed in the interim. diff --git a/src/client/extensionActivation.ts b/src/client/extensionActivation.ts index 034cde341f49..79ec2ec9c1d0 100644 --- a/src/client/extensionActivation.ts +++ b/src/client/extensionActivation.ts @@ -48,7 +48,6 @@ import { registerTypes as tensorBoardRegisterTypes } from './tensorBoard/service import { registerTypes as commonRegisterTerminalTypes } from './terminals/serviceRegistry'; import { ICodeExecutionManager, ITerminalAutoActivation } from './terminals/types'; import { registerTypes as unitTestsRegisterTypes } from './testing/serviceRegistry'; -import { ITestingService } from './testing/types'; import { registerTypes as interpretersRegisterTypes } from './interpreter/serviceRegistry'; // components @@ -161,7 +160,6 @@ async function activateLegacy(ext: ExtensionState): Promise { serviceContainer.get(IApplicationDiagnostics).register(); serviceContainer.get(ILanguageServerExtension).register(); - serviceContainer.get(ITestingService).register(); // "activate" everything else diff --git a/src/client/testing/common/services/contextService.ts b/src/client/testing/common/services/contextService.ts deleted file mode 100644 index f4933c0f850e..000000000000 --- a/src/client/testing/common/services/contextService.ts +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { inject, injectable } from 'inversify'; -import { ICommandManager } from '../../../common/application/types'; -import { ContextKey } from '../../../common/contextKey'; -import { IDisposable } from '../../../common/types'; -import { swallowExceptions } from '../../../common/utils/decorators'; -import { - ITestCollectionStorageService, - ITestContextService, - ITestManagementService, - TestStatus, - WorkspaceTestStatus, -} from '../types'; - -@injectable() -export class TestContextService implements ITestContextService { - private readonly hasFailedTests: ContextKey; - private readonly runningTests: ContextKey; - private readonly discoveringTests: ContextKey; - private readonly busyTests: ContextKey; - private readonly disposables: IDisposable[] = []; - constructor( - @inject(ITestCollectionStorageService) private readonly storage: ITestCollectionStorageService, - @inject(ITestManagementService) private readonly testManager: ITestManagementService, - @inject(ICommandManager) cmdManager: ICommandManager, - ) { - this.hasFailedTests = new ContextKey('hasFailedTests', cmdManager); - this.runningTests = new ContextKey('runningTests', cmdManager); - this.discoveringTests = new ContextKey('discoveringTests', cmdManager); - this.busyTests = new ContextKey('busyTests', cmdManager); - } - public dispose(): void { - this.disposables.forEach((d) => d.dispose()); - } - public register(): void { - this.testManager.onDidStatusChange(this.onStatusChange, this, this.disposables); - } - @swallowExceptions('Handle status change of tests') - protected async onStatusChange(status: WorkspaceTestStatus): Promise { - const tests = this.storage.getTests(status.workspace); - const promises: Promise[] = []; - if (tests && tests.summary) { - promises.push(this.hasFailedTests.set(tests.summary.failures > 0)); - } - promises.push( - ...[ - this.runningTests.set(status.status === TestStatus.Running), - this.discoveringTests.set(status.status === TestStatus.Discovering), - this.busyTests.set(status.status === TestStatus.Running || status.status === TestStatus.Discovering), - ], - ); - - await Promise.all(promises); - } -} diff --git a/src/client/testing/common/types.ts b/src/client/testing/common/types.ts index 5ac16619d072..0c5ede16b9e9 100644 --- a/src/client/testing/common/types.ts +++ b/src/client/testing/common/types.ts @@ -495,11 +495,6 @@ export interface ITestDebugConfig extends DebugConfiguration { subProcess?: boolean; } -export const ITestContextService = Symbol('ITestContextService'); -export interface ITestContextService extends Disposable { - register(): void; -} - export const ITestsStatusUpdaterService = Symbol('ITestsStatusUpdaterService'); export interface ITestsStatusUpdaterService { updateStatusAsDiscovering(resource: Uri, tests?: Tests): void; diff --git a/src/client/testing/main.ts b/src/client/testing/main.ts index 475cbbe629d3..047ed68f524c 100644 --- a/src/client/testing/main.ts +++ b/src/client/testing/main.ts @@ -4,7 +4,6 @@ import { inject, injectable } from 'inversify'; import { ConfigurationChangeEvent, Disposable, - DocumentSymbolProvider, Event, EventEmitter, OutputChannel, @@ -33,7 +32,6 @@ import { ITestDisplay, TestFile, TestFunction, - ITestContextService, ITestResultDisplay, ITestsHelper, TestStatus, @@ -43,21 +41,12 @@ import { import { TEST_OUTPUT_CHANNEL } from './constants'; import { ITestingService } from './types'; import { PythonTestController } from './testController/controller'; +import { IExtensionActivationService } from '../activation/types'; @injectable() export class TestingService implements ITestingService { constructor(@inject(IServiceContainer) private serviceContainer: IServiceContainer) {} - public async activate(symbolProvider: DocumentSymbolProvider): Promise { - const mgmt = this.serviceContainer.get(ITestManagementService); - return ((mgmt as unknown) as ITestingService).activate(symbolProvider); - } - - public register(): void { - const context = this.serviceContainer.get(ITestContextService); - context.register(); - } - public getSettingsPropertyNames(product: Product): TestSettingsPropertyNames { const helper = this.serviceContainer.get(ITestsHelper); return helper.getSettingsPropertyNames(product); @@ -65,7 +54,7 @@ export class TestingService implements ITestingService { } @injectable() -export class UnitTestManagementService implements ITestManagementService, Disposable { +export class UnitTestManagementService implements ITestManagementService, IExtensionActivationService, Disposable { private readonly outputChannel: OutputChannel; private activatedOnce: boolean = false; private readonly disposableRegistry: Disposable[]; diff --git a/src/client/testing/serviceRegistry.ts b/src/client/testing/serviceRegistry.ts index 7053d365a17e..3dc2c5f33866 100644 --- a/src/client/testing/serviceRegistry.ts +++ b/src/client/testing/serviceRegistry.ts @@ -10,7 +10,6 @@ import { DebugLauncher } from './common/debugLauncher'; import { EnablementTracker } from './common/enablementTracker'; import { TestRunner } from './common/runner'; import { TestConfigSettingsService } from './common/services/configSettingService'; -import { TestContextService } from './common/services/contextService'; import { TestDiscoveredTestParser } from './common/services/discoveredTestParser'; import { TestsDiscoveryService } from './common/services/discovery'; import { TestCollectionStorageService } from './common/services/storageService'; @@ -30,7 +29,6 @@ import { ITestConfigSettingsService, ITestConfigurationManagerFactory, ITestConfigurationService, - ITestContextService, ITestDebugLauncher, ITestDiagnosticService, ITestDiscoveryService, @@ -86,7 +84,6 @@ export function registerTypes(serviceManager: IServiceManager) { serviceManager.add(ITestDiscoveredTestParser, TestDiscoveredTestParser); serviceManager.add(ITestDiscoveryService, TestsDiscoveryService, 'common'); serviceManager.add(IUnitTestSocketServer, UnitTestSocketServer); - serviceManager.addSingleton(ITestContextService, TestContextService); serviceManager.addSingleton(ITestsStatusUpdaterService, TestsStatusUpdaterService); serviceManager.add(ITestResultsService, TestResultsService); @@ -111,6 +108,7 @@ export function registerTypes(serviceManager: IServiceManager) { serviceManager.addSingleton(ITestConfigurationService, UnitTestConfigurationService); serviceManager.addSingleton(ITestManagementService, UnitTestManagementService); + serviceManager.addBinding(ITestManagementService, IExtensionActivationService); serviceManager.addSingleton(ITestingService, TestingService); serviceManager.addSingleton(ITestConfigSettingsService, TestConfigSettingsService); diff --git a/src/client/testing/types.ts b/src/client/testing/types.ts index a362f898d22d..da308ee6998b 100644 --- a/src/client/testing/types.ts +++ b/src/client/testing/types.ts @@ -3,7 +3,6 @@ 'use strict'; -import { DocumentSymbolProvider } from 'vscode'; import { Product } from '../common/types'; import { TestSettingsPropertyNames } from './configuration/types'; @@ -14,7 +13,5 @@ export type TestProvider = 'pytest' | 'unittest'; export const ITestingService = Symbol('ITestingService'); export interface ITestingService { - activate(symbolProvider: DocumentSymbolProvider): Promise; - register(): void; getSettingsPropertyNames(product: Product): TestSettingsPropertyNames; } diff --git a/src/test/activation/languageServer/languageServer.unit.test.ts b/src/test/activation/languageServer/languageServer.unit.test.ts index 2a26d3171b66..e74d44d6b262 100644 --- a/src/test/activation/languageServer/languageServer.unit.test.ts +++ b/src/test/activation/languageServer/languageServer.unit.test.ts @@ -4,7 +4,7 @@ 'use strict'; import { expect } from 'chai'; -import { anything, instance, mock, verify, when } from 'ts-mockito'; +import { instance, mock, when } from 'ts-mockito'; import * as typemoq from 'typemoq'; import { Uri } from 'vscode'; import { Disposable, LanguageClient, LanguageClientOptions, State, StateChangeEvent } from 'vscode-languageclient/node'; @@ -15,28 +15,19 @@ import { ICommandManager } from '../../../client/common/application/types'; import '../../../client/common/extensions'; import { IConfigurationService, IDisposable, IPythonSettings } from '../../../client/common/types'; import { sleep } from '../../../client/common/utils/async'; -import { TestingService } from '../../../client/testing/main'; -import { ITestingService } from '../../../client/testing/types'; //tslint:disable:no-require-imports no-require-imports no-var-requires no-any no-unnecessary-class max-func-body-length suite('Language Server - LanguageServer', () => { - class LanguageServerTest extends DotNetLanguageServerProxy { - public async registerTestServices() { - return super.registerTestServices(); - } - } let clientFactory: ILanguageClientFactory; - let server: LanguageServerTest; + let server: DotNetLanguageServerProxy; let client: typemoq.IMock; - let testManager: ITestingService; let configService: typemoq.IMock; let commandManager: typemoq.IMock; let stateChangeListener: ((e: StateChangeEvent) => void) | undefined; setup(() => { client = typemoq.Mock.ofType(); clientFactory = mock(DotNetLanguageClientFactory); - testManager = mock(TestingService); configService = typemoq.Mock.ofType(); commandManager = typemoq.Mock.ofType(); @@ -45,7 +36,7 @@ suite('Language Server - LanguageServer', () => { .returns(() => { return typemoq.Mock.ofType().object; }); - server = new LanguageServerTest(instance(clientFactory), instance(testManager), configService.object); + server = new DotNetLanguageServerProxy(instance(clientFactory), configService.object); const stateChangeDisposable = typemoq.Mock.ofType(); client @@ -125,7 +116,6 @@ suite('Language Server - LanguageServer', () => { .verifiable(typemoq.Times.once()); await sleep(120); - verify(testManager.activate(anything())).once(); client.verify((c) => c.sendRequest(typemoq.It.isAny(), typemoq.It.isAny()), typemoq.Times.atLeast(2)); }); test('Send telemetry when LS has started and disposes appropriately', async () => { @@ -175,7 +165,6 @@ suite('Language Server - LanguageServer', () => { .verifiable(typemoq.Times.once()); await sleep(120); - verify(testManager.activate(anything())).once(); expect(() => server.loadExtension(loadExtensionArgs)).to.not.throw(); client.verify((c) => c.sendRequest(typemoq.It.isAny(), typemoq.It.isAny()), typemoq.Times.once()); client.verify((c) => c.stop(), typemoq.Times.never()); @@ -186,9 +175,6 @@ suite('Language Server - LanguageServer', () => { client.verify((c) => c.stop(), typemoq.Times.once()); startDisposable.verify((d) => d.dispose(), typemoq.Times.once()); }); - test('Ensure Errors raised when starting test manager are not bubbled up', async () => { - await server.registerTestServices(); - }); test('Register telemetry handler if LS was downloadeded', async () => { client.verify((c) => c.sendRequest(typemoq.It.isAny(), typemoq.It.isAny()), typemoq.Times.never()); @@ -232,8 +218,6 @@ suite('Language Server - LanguageServer', () => { .verifiable(typemoq.Times.once()); await sleep(120); - verify(testManager.activate(anything())).once(); - client.verify((c) => c.onTelemetry(typemoq.It.isAny()), typemoq.Times.once()); pythonSettings.verifyAll(); configService.verifyAll(); @@ -281,8 +265,6 @@ suite('Language Server - LanguageServer', () => { .verifiable(typemoq.Times.once()); await sleep(120); - verify(testManager.activate(anything())).once(); - client.verify((c) => c.onTelemetry(typemoq.It.isAny()), typemoq.Times.never()); pythonSettings.verifyAll(); configService.verifyAll(); @@ -327,7 +309,6 @@ suite('Language Server - LanguageServer', () => { // Promise should resolve without any errors. await promise; - verify(testManager.activate(anything())).never(); client.verify((c) => c.onTelemetry(typemoq.It.isAny()), typemoq.Times.never()); pythonSettings.verifyAll(); configService.verifyAll(); diff --git a/src/test/testing/common/services/contextService.unit.test.ts b/src/test/testing/common/services/contextService.unit.test.ts deleted file mode 100644 index b2d10778ed42..000000000000 --- a/src/test/testing/common/services/contextService.unit.test.ts +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import * as assert from 'assert'; -import { anything, instance, mock, verify, when } from 'ts-mockito'; -import { Uri } from 'vscode'; -import { CommandManager } from '../../../../client/common/application/commandManager'; -import { ICommandManager } from '../../../../client/common/application/types'; -import { TestContextService } from '../../../../client/testing/common/services/contextService'; -import { TestCollectionStorageService } from '../../../../client/testing/common/services/storageService'; -import { - ITestCollectionStorageService, - ITestContextService, - ITestManagementService, - TestStatus, - WorkspaceTestStatus, -} from '../../../../client/testing/common/types'; -import { UnitTestManagementService } from '../../../../client/testing/main'; - -suite('Unit Tests - Context Service', () => { - let cmdManager: ICommandManager; - let contextService: ITestContextService; - let storage: ITestCollectionStorageService; - let mgr: ITestManagementService; - const workspaceUri = Uri.file(__filename); - type StatusChangeHandler = (status: WorkspaceTestStatus) => Promise; - setup(() => { - cmdManager = mock(CommandManager); - storage = mock(TestCollectionStorageService); - mgr = mock(UnitTestManagementService); - contextService = new TestContextService(instance(storage), instance(mgr), instance(cmdManager)); - }); - - test('register will add event handler', () => { - let invoked = false; - const fn = () => (invoked = true); - when(mgr.onDidStatusChange).thenReturn(fn as any); - - contextService.register(); - - assert.equal(invoked, true); - }); - test('Status change without tests does not update hasFailedTests', async () => { - let handler!: StatusChangeHandler; - const fn = (cb: StatusChangeHandler) => (handler = cb); - when(mgr.onDidStatusChange).thenReturn(fn as any); - when(storage.getTests(workspaceUri)).thenReturn(); - contextService.register(); - - await handler.bind(contextService)({ status: TestStatus.Discovering, workspace: workspaceUri }); - - verify(cmdManager.executeCommand('setContext', 'hasFailedTests', anything())).never(); - }); - test('Status change without a summary does not update hasFailedTests', async () => { - let handler!: StatusChangeHandler; - const fn = (cb: StatusChangeHandler) => (handler = cb); - when(mgr.onDidStatusChange).thenReturn(fn as any); - when(storage.getTests(workspaceUri)).thenReturn({} as any); - contextService.register(); - - await handler.bind(contextService)({ status: TestStatus.Discovering, workspace: workspaceUri }); - - verify(cmdManager.executeCommand('setContext', 'hasFailedTests', anything())).never(); - }); - test('Status change with a summary updates hasFailedTests to false ', async () => { - let handler!: StatusChangeHandler; - const fn = (cb: StatusChangeHandler) => (handler = cb); - when(mgr.onDidStatusChange).thenReturn(fn as any); - when(storage.getTests(anything())).thenReturn({ summary: { failures: 0 } } as any); - contextService.register(); - - await handler.bind(contextService)({ status: TestStatus.Discovering, workspace: workspaceUri }); - - verify(cmdManager.executeCommand('setContext', 'hasFailedTests', false)).once(); - }); - test('Status change with a summary and failures updates hasFailedTests to false', async () => { - let handler!: StatusChangeHandler; - const fn = (cb: StatusChangeHandler) => (handler = cb); - when(mgr.onDidStatusChange).thenReturn(fn as any); - when(storage.getTests(anything())).thenReturn({ summary: { failures: 1 } } as any); - contextService.register(); - - await handler.bind(contextService)({ status: TestStatus.Discovering, workspace: workspaceUri }); - - verify(cmdManager.executeCommand('setContext', 'hasFailedTests', true)).once(); - }); - test('Status change with status of running', async () => { - let handler!: StatusChangeHandler; - const fn = (cb: StatusChangeHandler) => (handler = cb); - when(mgr.onDidStatusChange).thenReturn(fn as any); - when(storage.getTests(anything())).thenReturn({} as any); - contextService.register(); - - await handler.bind(contextService)({ status: TestStatus.Running, workspace: workspaceUri }); - - verify(cmdManager.executeCommand('setContext', 'runningTests', true)).once(); - verify(cmdManager.executeCommand('setContext', 'discoveringTests', false)).once(); - verify(cmdManager.executeCommand('setContext', 'busyTests', true)).once(); - }); - test('Status change with status of discovering', async () => { - let handler!: StatusChangeHandler; - const fn = (cb: StatusChangeHandler) => (handler = cb); - when(mgr.onDidStatusChange).thenReturn(fn as any); - when(storage.getTests(anything())).thenReturn({} as any); - contextService.register(); - - await handler.bind(contextService)({ status: TestStatus.Discovering, workspace: workspaceUri }); - - verify(cmdManager.executeCommand('setContext', 'runningTests', false)).once(); - verify(cmdManager.executeCommand('setContext', 'discoveringTests', true)).once(); - verify(cmdManager.executeCommand('setContext', 'busyTests', true)).once(); - }); - test('Status change with status of others', async () => { - let handler!: StatusChangeHandler; - const fn = (cb: StatusChangeHandler) => (handler = cb); - when(mgr.onDidStatusChange).thenReturn(fn as any); - when(storage.getTests(anything())).thenReturn({} as any); - contextService.register(); - - await handler.bind(contextService)({ status: TestStatus.Error, workspace: workspaceUri }); - await handler.bind(contextService)({ status: TestStatus.Fail, workspace: workspaceUri }); - await handler.bind(contextService)({ status: TestStatus.Idle, workspace: workspaceUri }); - await handler.bind(contextService)({ status: TestStatus.Pass, workspace: workspaceUri }); - await handler.bind(contextService)({ status: TestStatus.Skipped, workspace: workspaceUri }); - await handler.bind(contextService)({ status: TestStatus.Unknown, workspace: workspaceUri }); - - verify(cmdManager.executeCommand('setContext', 'runningTests', false)).once(); - verify(cmdManager.executeCommand('setContext', 'discoveringTests', false)).once(); - verify(cmdManager.executeCommand('setContext', 'busyTests', false)).once(); - - verify(cmdManager.executeCommand('setContext', 'runningTests', true)).never(); - verify(cmdManager.executeCommand('setContext', 'discoveringTests', true)).never(); - verify(cmdManager.executeCommand('setContext', 'busyTests', true)).never(); - }); -}); diff --git a/src/test/testing/serviceRegistry.ts b/src/test/testing/serviceRegistry.ts index 8b1f32956b48..11147bb27064 100644 --- a/src/test/testing/serviceRegistry.ts +++ b/src/test/testing/serviceRegistry.ts @@ -10,7 +10,6 @@ import { IInterpreterHelper } from '../../client/interpreter/contracts'; import { InterpreterHelper } from '../../client/interpreter/helpers'; import { IServiceContainer } from '../../client/ioc/types'; import { PYTEST_PROVIDER, UNITTEST_PROVIDER } from '../../client/testing/common/constants'; -import { TestContextService } from '../../client/testing/common/services/contextService'; import { TestDiscoveredTestParser } from '../../client/testing/common/services/discoveredTestParser'; import { TestsDiscoveryService } from '../../client/testing/common/services/discovery'; import { TestCollectionStorageService } from '../../client/testing/common/services/storageService'; @@ -24,7 +23,6 @@ import { TestFlatteningVisitor } from '../../client/testing/common/testVisitors/ import { TestResultResetVisitor } from '../../client/testing/common/testVisitors/resultResetVisitor'; import { ITestCollectionStorageService, - ITestContextService, ITestDiagnosticService, ITestDiscoveryService, ITestManager, @@ -66,7 +64,6 @@ export class UnitTestIocContainer extends IocContainer { ITestsStatusUpdaterService, TestsStatusUpdaterService, ); - this.serviceManager.addSingleton(ITestContextService, TestContextService); } public registerTestStorage(): void { From 595247e63c23bb557055cd0a77617ac7ae563d0d Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Thu, 22 Jul 2021 15:19:43 -0700 Subject: [PATCH 11/39] Remove old test code (only configuration remains) --- src/client/common/application/commands.ts | 3 +- src/client/testing/common/argumentsHelper.ts | 124 - .../bufferedTestConfigSettingService.ts | 56 + .../{services => }/configSettingService.ts | 65 +- .../testing/common/enablementTracker.ts | 57 - .../common/managers/baseTestManager.ts | 554 ----- .../common/services/discoveredTestParser.ts | 383 --- .../testing/common/services/discovery.ts | 63 - .../testing/common/services/storageService.ts | 61 - .../common/services/testManagerService.ts | 47 - .../common/services/testResultsService.ts | 77 - .../common/services/testsStatusService.ts | 103 - src/client/testing/common/services/types.ts | 22 - .../services/unitTestDiagnosticService.ts | 62 - .../services/workspaceTestManagerService.ts | 63 - .../testConfigurationManager.ts | 18 +- src/client/testing/common/testUtils.ts | 162 +- .../common/testVisitors/flatteningVisitor.ts | 75 - .../common/testVisitors/resultResetVisitor.ts | 40 - .../testing/common/testVisitors/visitor.ts | 40 - src/client/testing/common/types.ts | 215 +- src/client/testing/common/xUnitParser.ts | 181 -- src/client/testing/configuration/index.ts | 2 +- src/client/testing/main.ts | 276 +-- .../testing/navigation/symbolProvider.ts | 77 - src/client/testing/pytest/main.ts | 99 - src/client/testing/pytest/runner.ts | 127 - .../testing/pytest/services/argsService.ts | 296 --- .../pytest/services/discoveryService.ts | 80 - .../pytest/services/testMessageService.ts | 292 --- .../pytest/testConfigurationManager.ts | 2 +- src/client/testing/serviceRegistry.ts | 119 +- src/client/testing/unittest/helper.ts | 50 - src/client/testing/unittest/main.ts | 96 - src/client/testing/unittest/runner.ts | 229 -- .../testing/unittest/services/argsService.ts | 84 - .../unittest/services/discoveryService.ts | 99 - .../unittest/services/parserService.ts | 125 - .../unittest/testConfigurationManager.ts | 2 +- src/test/testing/argsService.test.ts | 177 -- .../testing/common/argsHelper.unit.test.ts | 115 - .../managers/baseTestManager.unit.test.ts | 201 -- .../testConfigurationManager.unit.test.ts | 2 +- .../configSettingService.unit.test.ts | 4 +- .../discoveredTestParser.unit.test.ts | 119 - .../common/services/discovery.unit.test.ts | 100 - .../services/testResultsService.unit.test.ts | 234 -- .../services/testStatusService.unit.test.ts | 253 -- .../resultResetVisitor.unit.test.ts | 111 - .../common/trackEnablement.unit.test.ts | 148 -- .../testing/common/xUnitParser.unit.test.ts | 148 -- src/test/testing/configuration.unit.test.ts | 4 +- src/test/testing/debugger.test.ts | 234 -- src/test/testing/main.unit.test.ts | 48 - src/test/testing/mocks.ts | 44 - .../navigation/symbolNavigator.unit.test.ts | 178 -- .../pytest/pytest.argsService.unit.test.ts | 106 - .../testing/pytest/pytest.discovery.test.ts | 1019 -------- src/test/testing/pytest/pytest.run.test.ts | 635 ----- src/test/testing/pytest/pytest.test.ts | 65 - .../pytest/pytest.testMessageService.test.ts | 249 -- .../testing/pytest/pytest_run_tests_data.ts | 464 ---- .../pytest/pytest_unittest_parser_data.ts | 2087 ----------------- .../services/discoveryService.unit.test.ts | 188 -- src/test/testing/rediscover.test.ts | 88 - src/test/testing/serviceRegistry.ts | 104 - .../testing/stoppingDiscoverAndTest.test.ts | 120 - .../unittest.argsService.unit.test.ts | 57 - .../unittest.diagnosticService.unit.test.ts | 72 - .../unittest/unittest.discovery.test.ts | 212 -- .../unittest/unittest.discovery.unit.test.ts | 636 ----- .../testing/unittest/unittest.run.test.ts | 511 ---- src/test/testing/unittest/unittest.test.ts | 260 -- .../testing/unittest/unittest.unit.test.ts | 220 -- 74 files changed, 113 insertions(+), 13626 deletions(-) delete mode 100644 src/client/testing/common/argumentsHelper.ts create mode 100644 src/client/testing/common/bufferedTestConfigSettingService.ts rename src/client/testing/common/{services => }/configSettingService.ts (57%) delete mode 100644 src/client/testing/common/enablementTracker.ts delete mode 100644 src/client/testing/common/managers/baseTestManager.ts delete mode 100644 src/client/testing/common/services/discoveredTestParser.ts delete mode 100644 src/client/testing/common/services/discovery.ts delete mode 100644 src/client/testing/common/services/storageService.ts delete mode 100644 src/client/testing/common/services/testManagerService.ts delete mode 100644 src/client/testing/common/services/testResultsService.ts delete mode 100644 src/client/testing/common/services/testsStatusService.ts delete mode 100644 src/client/testing/common/services/types.ts delete mode 100644 src/client/testing/common/services/unitTestDiagnosticService.ts delete mode 100644 src/client/testing/common/services/workspaceTestManagerService.ts rename src/client/testing/common/{managers => }/testConfigurationManager.ts (90%) delete mode 100644 src/client/testing/common/testVisitors/flatteningVisitor.ts delete mode 100644 src/client/testing/common/testVisitors/resultResetVisitor.ts delete mode 100644 src/client/testing/common/testVisitors/visitor.ts delete mode 100644 src/client/testing/common/xUnitParser.ts delete mode 100644 src/client/testing/navigation/symbolProvider.ts delete mode 100644 src/client/testing/pytest/main.ts delete mode 100644 src/client/testing/pytest/runner.ts delete mode 100644 src/client/testing/pytest/services/argsService.ts delete mode 100644 src/client/testing/pytest/services/discoveryService.ts delete mode 100644 src/client/testing/pytest/services/testMessageService.ts delete mode 100644 src/client/testing/unittest/helper.ts delete mode 100644 src/client/testing/unittest/main.ts delete mode 100644 src/client/testing/unittest/runner.ts delete mode 100644 src/client/testing/unittest/services/argsService.ts delete mode 100644 src/client/testing/unittest/services/discoveryService.ts delete mode 100644 src/client/testing/unittest/services/parserService.ts delete mode 100644 src/test/testing/argsService.test.ts delete mode 100644 src/test/testing/common/argsHelper.unit.test.ts delete mode 100644 src/test/testing/common/managers/baseTestManager.unit.test.ts delete mode 100644 src/test/testing/common/services/discoveredTestParser.unit.test.ts delete mode 100644 src/test/testing/common/services/discovery.unit.test.ts delete mode 100644 src/test/testing/common/services/testResultsService.unit.test.ts delete mode 100644 src/test/testing/common/services/testStatusService.unit.test.ts delete mode 100644 src/test/testing/common/testVisitors/resultResetVisitor.unit.test.ts delete mode 100644 src/test/testing/common/trackEnablement.unit.test.ts delete mode 100644 src/test/testing/common/xUnitParser.unit.test.ts delete mode 100644 src/test/testing/debugger.test.ts delete mode 100644 src/test/testing/main.unit.test.ts delete mode 100644 src/test/testing/navigation/symbolNavigator.unit.test.ts delete mode 100644 src/test/testing/pytest/pytest.argsService.unit.test.ts delete mode 100644 src/test/testing/pytest/pytest.discovery.test.ts delete mode 100644 src/test/testing/pytest/pytest.run.test.ts delete mode 100644 src/test/testing/pytest/pytest.test.ts delete mode 100644 src/test/testing/pytest/pytest.testMessageService.test.ts delete mode 100644 src/test/testing/pytest/pytest_run_tests_data.ts delete mode 100644 src/test/testing/pytest/pytest_unittest_parser_data.ts delete mode 100644 src/test/testing/pytest/services/discoveryService.unit.test.ts delete mode 100644 src/test/testing/rediscover.test.ts delete mode 100644 src/test/testing/stoppingDiscoverAndTest.test.ts delete mode 100644 src/test/testing/unittest/unittest.argsService.unit.test.ts delete mode 100644 src/test/testing/unittest/unittest.diagnosticService.unit.test.ts delete mode 100644 src/test/testing/unittest/unittest.discovery.test.ts delete mode 100644 src/test/testing/unittest/unittest.discovery.unit.test.ts delete mode 100644 src/test/testing/unittest/unittest.run.test.ts delete mode 100644 src/test/testing/unittest/unittest.test.ts delete mode 100644 src/test/testing/unittest/unittest.unit.test.ts diff --git a/src/client/common/application/commands.ts b/src/client/common/application/commands.ts index 2181516df229..cae54bef51d9 100644 --- a/src/client/common/application/commands.ts +++ b/src/client/common/application/commands.ts @@ -6,8 +6,7 @@ import { CancellationToken, Position, TextDocument, Uri } from 'vscode'; import { Commands as LSCommands } from '../../activation/commands'; import { TensorBoardEntrypoint, TensorBoardEntrypointTrigger } from '../../tensorBoard/constants'; -import { Commands } from '../constants'; -import { Channel, CommandSource, ICommandManager } from './types'; +import { Channel, Commands, CommandSource } from '../constants'; export type CommandsWithoutArgs = keyof ICommandNameWithoutArgumentTypeMapping; diff --git a/src/client/testing/common/argumentsHelper.ts b/src/client/testing/common/argumentsHelper.ts deleted file mode 100644 index 04215e745e57..000000000000 --- a/src/client/testing/common/argumentsHelper.ts +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { injectable } from 'inversify'; -import { traceWarning } from '../../common/logger'; -import { IArgumentsHelper } from '../common/types'; - -@injectable() -export class ArgumentsHelper implements IArgumentsHelper { - public getOptionValues(args: string[], option: string): string | string[] | undefined { - const values: string[] = []; - let returnNextValue = false; - for (const arg of args) { - if (returnNextValue) { - values.push(arg); - returnNextValue = false; - continue; - } - if (arg.startsWith(`${option}=`)) { - values.push(arg.substring(`${option}=`.length)); - continue; - } - if (arg === option) { - returnNextValue = true; - } - } - switch (values.length) { - case 0: { - return; - } - case 1: { - return values[0]; - } - default: { - return values; - } - } - } - public getPositionalArguments( - args: string[], - optionsWithArguments: string[] = [], - optionsWithoutArguments: string[] = [], - ): string[] { - const nonPositionalIndexes: number[] = []; - args.forEach((arg, index) => { - if (optionsWithoutArguments.indexOf(arg) !== -1) { - nonPositionalIndexes.push(index); - return; - } else if (optionsWithArguments.indexOf(arg) !== -1) { - nonPositionalIndexes.push(index); - // Cuz the next item is the value. - nonPositionalIndexes.push(index + 1); - } else if (optionsWithArguments.findIndex((item) => arg.startsWith(`${item}=`)) !== -1) { - nonPositionalIndexes.push(index); - return; - } else if (arg.startsWith('-')) { - // Ok this is an unknown option, lets treat this as one without values. - traceWarning( - `Unknown command line option passed into args parser for tests '${arg}'. Please report on https://github.com/Microsoft/vscode-python/issues/new`, - ); - nonPositionalIndexes.push(index); - return; - } else if (arg.indexOf('=') > 0) { - // Ok this is an unknown option with a value - traceWarning( - `Unknown command line option passed into args parser for tests '${arg}'. Please report on https://github.com/Microsoft/vscode-python/issues/new`, - ); - nonPositionalIndexes.push(index); - } - }); - return args.filter((_, index) => nonPositionalIndexes.indexOf(index) === -1); - } - public filterArguments( - args: string[], - optionsWithArguments: string[] = [], - optionsWithoutArguments: string[] = [], - ): string[] { - let ignoreIndex = -1; - return args.filter((arg, index) => { - if (ignoreIndex === index) { - return false; - } - // Options can use willd cards (with trailing '*') - if ( - optionsWithoutArguments.indexOf(arg) >= 0 || - optionsWithoutArguments.filter((option) => option.endsWith('*') && arg.startsWith(option.slice(0, -1))) - .length > 0 - ) { - return false; - } - // Ignore args that match exactly. - if (optionsWithArguments.indexOf(arg) >= 0) { - ignoreIndex = index + 1; - return false; - } - // Ignore args that match exactly with wild cards & do not have inline values. - if (optionsWithArguments.filter((option) => arg.startsWith(`${option}=`)).length > 0) { - return false; - } - // Ignore args that match a wild card (ending with *) and no ineline values. - // Eg. arg='--log-cli-level' and optionsArguments=['--log-*'] - if ( - arg.indexOf('=') === -1 && - optionsWithoutArguments.filter((option) => option.endsWith('*') && arg.startsWith(option.slice(0, -1))) - .length > 0 - ) { - ignoreIndex = index + 1; - return false; - } - // Ignore args that match a wild card (ending with *) and have ineline values. - // Eg. arg='--log-cli-level=XYZ' and optionsArguments=['--log-*'] - if ( - arg.indexOf('=') >= 0 && - optionsWithoutArguments.filter((option) => option.endsWith('*') && arg.startsWith(option.slice(0, -1))) - .length > 0 - ) { - return false; - } - return true; - }); - } -} diff --git a/src/client/testing/common/bufferedTestConfigSettingService.ts b/src/client/testing/common/bufferedTestConfigSettingService.ts new file mode 100644 index 000000000000..41cdd1664e4f --- /dev/null +++ b/src/client/testing/common/bufferedTestConfigSettingService.ts @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { Uri } from 'vscode'; +import { ITestConfigSettingsService, UnitTestProduct } from './types'; + +export class BufferedTestConfigSettingsService implements ITestConfigSettingsService { + private ops: [string, string | Uri, UnitTestProduct, string[]][]; + + constructor() { + this.ops = []; + } + + public async updateTestArgs(testDirectory: string | Uri, product: UnitTestProduct, args: string[]):Promise { + this.ops.push(['updateTestArgs', testDirectory, product, args]); + return Promise.resolve(); + } + + public async enable(testDirectory: string | Uri, product: UnitTestProduct): Promise { + this.ops.push(['enable', testDirectory, product, []]); + return Promise.resolve(); + } + + public async disable(testDirectory: string | Uri, product: UnitTestProduct): Promise { + this.ops.push(['disable', testDirectory, product, []]); + return Promise.resolve(); + } + + public async apply(cfg: ITestConfigSettingsService): Promise { + const {ops} = this; + this.ops = []; + // Note that earlier ops do not get rolled back if a later + // one fails. + for (const [op, testDir, prod, args] of ops) { + switch (op) { + case 'updateTestArgs': + await cfg.updateTestArgs(testDir, prod, args); + break; + case 'enable': + await cfg.enable(testDir, prod); + break; + case 'disable': + await cfg.disable(testDir, prod); + break; + default: + break; + } + } + return Promise.resolve(); + } + + // eslint-disable-next-line class-methods-use-this + public getTestEnablingSetting(_: UnitTestProduct): string { + throw new Error('Method not implemented.'); + } +} diff --git a/src/client/testing/common/services/configSettingService.ts b/src/client/testing/common/configSettingService.ts similarity index 57% rename from src/client/testing/common/services/configSettingService.ts rename to src/client/testing/common/configSettingService.ts index 1c4a3d87ef1c..7fd26273019a 100644 --- a/src/client/testing/common/services/configSettingService.ts +++ b/src/client/testing/common/configSettingService.ts @@ -1,17 +1,19 @@ import { inject, injectable } from 'inversify'; import { Uri, WorkspaceConfiguration } from 'vscode'; -import { IWorkspaceService } from '../../../common/application/types'; -import { Product } from '../../../common/types'; -import { IServiceContainer } from '../../../ioc/types'; -import { ITestConfigSettingsService, UnitTestProduct } from '../types'; +import { IWorkspaceService } from '../../common/application/types'; +import { Product } from '../../common/types'; +import { IServiceContainer } from '../../ioc/types'; +import { ITestConfigSettingsService, UnitTestProduct } from './types'; @injectable() export class TestConfigSettingsService implements ITestConfigSettingsService { private readonly workspaceService: IWorkspaceService; + constructor(@inject(IServiceContainer) serviceContainer: IServiceContainer) { this.workspaceService = serviceContainer.get(IWorkspaceService); } - public async updateTestArgs(testDirectory: string | Uri, product: UnitTestProduct, args: string[]) { + + public async updateTestArgs(testDirectory: string | Uri, product: UnitTestProduct, args: string[]): Promise { const setting = this.getTestArgSetting(product); return this.updateSetting(testDirectory, setting, args); } @@ -25,7 +27,9 @@ export class TestConfigSettingsService implements ITestConfigSettingsService { const setting = this.getTestEnablingSetting(product); return this.updateSetting(testDirectory, setting, false); } - public getTestEnablingSetting(product: UnitTestProduct) { + + // eslint-disable-next-line class-methods-use-this + public getTestEnablingSetting(product: UnitTestProduct):string { switch (product) { case Product.unittest: return 'testing.unittestEnabled'; @@ -35,7 +39,9 @@ export class TestConfigSettingsService implements ITestConfigSettingsService { throw new Error('Invalid Test Product'); } } - private getTestArgSetting(product: UnitTestProduct) { + + // eslint-disable-next-line class-methods-use-this + private getTestArgSetting(product: UnitTestProduct):string { switch (product) { case Product.unittest: return 'testing.unittestArgs'; @@ -46,7 +52,7 @@ export class TestConfigSettingsService implements ITestConfigSettingsService { } } - private async updateSetting(testDirectory: string | Uri, setting: string, value: any) { + private async updateSetting(testDirectory: string | Uri, setting: string, value: unknown) { let pythonConfig: WorkspaceConfiguration; const resource = typeof testDirectory === 'string' ? Uri.file(testDirectory) : testDirectory; if (!this.workspaceService.hasWorkspaceFolders) { @@ -69,46 +75,3 @@ export class TestConfigSettingsService implements ITestConfigSettingsService { } } -export class BufferedTestConfigSettingsService implements ITestConfigSettingsService { - private ops: [string, string | Uri, UnitTestProduct, string[]][]; - constructor() { - this.ops = []; - } - - public async updateTestArgs(testDirectory: string | Uri, product: UnitTestProduct, args: string[]) { - this.ops.push(['updateTestArgs', testDirectory, product, args]); - } - - public async enable(testDirectory: string | Uri, product: UnitTestProduct): Promise { - this.ops.push(['enable', testDirectory, product, []]); - } - - public async disable(testDirectory: string | Uri, product: UnitTestProduct): Promise { - this.ops.push(['disable', testDirectory, product, []]); - } - - public async apply(cfg: ITestConfigSettingsService) { - const ops = this.ops; - this.ops = []; - // Note that earlier ops do not get rolled back if a later - // one fails. - for (const [op, testDir, prod, args] of ops) { - switch (op) { - case 'updateTestArgs': - await cfg.updateTestArgs(testDir, prod, args); - break; - case 'enable': - await cfg.enable(testDir, prod); - break; - case 'disable': - await cfg.disable(testDir, prod); - break; - default: - break; - } - } - } - public getTestEnablingSetting(_: UnitTestProduct): string { - throw new Error('Method not implemented.'); - } -} diff --git a/src/client/testing/common/enablementTracker.ts b/src/client/testing/common/enablementTracker.ts deleted file mode 100644 index 0f99939450ec..000000000000 --- a/src/client/testing/common/enablementTracker.ts +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { inject, injectable } from 'inversify'; -import { ConfigurationChangeEvent } from 'vscode'; -import { IExtensionSingleActivationService } from '../../activation/types'; -import { IWorkspaceService } from '../../common/application/types'; -import { IDisposableRegistry, Resource } from '../../common/types'; -import { sendTelemetryEvent } from '../../telemetry'; -import { EventName } from '../../telemetry/constants'; -import { TestProvider } from '../types'; -import { ITestConfigSettingsService, ITestsHelper } from './types'; - -@injectable() -export class EnablementTracker implements IExtensionSingleActivationService { - constructor( - @inject(IWorkspaceService) private readonly workspaceService: IWorkspaceService, - @inject(IDisposableRegistry) private readonly disposables: IDisposableRegistry, - @inject(ITestConfigSettingsService) private readonly testConfig: ITestConfigSettingsService, - @inject(ITestsHelper) private readonly testsHelper: ITestsHelper, - ) {} - public async activate(): Promise { - this.disposables.push(this.workspaceService.onDidChangeConfiguration(this.onDidChangeConfiguration, this)); - } - public onDidChangeConfiguration(args: ConfigurationChangeEvent) { - const resourcesToCheck: Resource[] = [undefined]; - if (Array.isArray(this.workspaceService.workspaceFolders)) { - this.workspaceService.workspaceFolders.forEach((item) => resourcesToCheck.push(item.uri)); - } - - const testProviders: TestProvider[] = ['pytest', 'unittest']; - resourcesToCheck.forEach((resource) => { - const telemetry: Partial> = {}; - testProviders.forEach((item) => { - const product = this.testsHelper.parseProduct(item); - const testingSetting = this.testConfig.getTestEnablingSetting(product); - const settingToCheck = `python.${testingSetting}`; - // If the setting was modified and if its value is true, then track this. - if ( - args.affectsConfiguration(settingToCheck) && - this.workspaceService.getConfiguration('python', resource).get(testingSetting, false) - ) { - telemetry[item] = true; - } - }); - // If anyone of the items have been enabled, then send telemetry. - if (telemetry.pytest || telemetry.unittest) { - this.sendTelemetry(telemetry); - } - }); - } - public sendTelemetry(telemetry: Partial>) { - sendTelemetryEvent(EventName.UNITTEST_ENABLED, undefined, telemetry); - } -} diff --git a/src/client/testing/common/managers/baseTestManager.ts b/src/client/testing/common/managers/baseTestManager.ts deleted file mode 100644 index 34f626bfd802..000000000000 --- a/src/client/testing/common/managers/baseTestManager.ts +++ /dev/null @@ -1,554 +0,0 @@ -import { - CancellationToken, - CancellationTokenSource, - Diagnostic, - DiagnosticCollection, - DiagnosticRelatedInformation, - Disposable, - Event, - EventEmitter, - languages, - OutputChannel, - Uri, -} from 'vscode'; -import { ICommandManager, IWorkspaceService } from '../../../common/application/types'; -import '../../../common/extensions'; -import { isNotInstalledError } from '../../../common/helpers'; -import { traceError } from '../../../common/logger'; -import { IFileSystem } from '../../../common/platform/types'; -import { - IConfigurationService, - IDisposableRegistry, - IInstaller, - IOutputChannel, - IPythonSettings, - Product, -} from '../../../common/types'; -import { getNamesAndValues } from '../../../common/utils/enum'; -import { noop } from '../../../common/utils/misc'; -import { IServiceContainer } from '../../../ioc/types'; -import { EventName } from '../../../telemetry/constants'; -import { sendTelemetryEvent } from '../../../telemetry/index'; -import { TestDiscoveryTelemetry, TestRunTelemetry } from '../../../telemetry/types'; -import { TEST_OUTPUT_CHANNEL } from '../../constants'; -import { TestProvider } from '../../types'; -import { copyDesiredTestResults } from '../testUtils'; -import { CANCELLATION_REASON } from '../constants'; -import { - IPythonTestMessage, - ITestCollectionStorageService, - ITestDiagnosticService, - ITestDiscoveryService, - ITestManager, - ITestNonPassingMessage, - ITestResultsService, - ITestsStatusUpdaterService, - TestDiscoveryOptions, - Tests, - TestStatus, - TestsToRun, - WorkspaceTestStatus, -} from '../types'; -import { CommandSource } from '../../../common/constants'; - -enum CancellationTokenType { - testDiscovery, - testRunner, -} - -export abstract class BaseTestManager implements ITestManager { - public diagnosticCollection: DiagnosticCollection; - - protected readonly settings: IPythonSettings; - - private readonly unitTestDiagnosticService: ITestDiagnosticService; - - public abstract get enabled(): boolean; - - protected get outputChannel(): OutputChannel { - return this._outputChannel; - } - - protected get testResultsService(): ITestResultsService { - return this._testResultsService; - } - - private readonly testCollectionStorage: ITestCollectionStorageService; - - private readonly _testResultsService: ITestResultsService; - - private readonly commandManager: ICommandManager; - - private readonly workspaceService: IWorkspaceService; - - private readonly _outputChannel: OutputChannel; - - protected tests?: Tests; - - private _status: TestStatus = TestStatus.Unknown; - - private testDiscoveryCancellationTokenSource?: CancellationTokenSource; - - private testRunnerCancellationTokenSource?: CancellationTokenSource; - - private _installer!: IInstaller; - - private readonly testsStatusUpdaterService: ITestsStatusUpdaterService; - - private discoverTestsPromise?: Promise; - - private readonly _onDidStatusChange = new EventEmitter(); - - private get installer(): IInstaller { - if (!this._installer) { - this._installer = this.serviceContainer.get(IInstaller); - } - return this._installer; - } - - constructor( - public readonly testProvider: TestProvider, - private readonly product: Product, - public readonly workspaceFolder: Uri, - protected rootDirectory: string, - protected serviceContainer: IServiceContainer, - ) { - this.updateStatus(TestStatus.Unknown); - const configService = serviceContainer.get(IConfigurationService); - this.settings = configService.getSettings(this.rootDirectory ? Uri.file(this.rootDirectory) : undefined); - const disposables = serviceContainer.get(IDisposableRegistry); - this._outputChannel = this.serviceContainer.get(IOutputChannel, TEST_OUTPUT_CHANNEL); - this.testCollectionStorage = this.serviceContainer.get( - ITestCollectionStorageService, - ); - this._testResultsService = this.serviceContainer.get(ITestResultsService); - this.workspaceService = this.serviceContainer.get(IWorkspaceService); - this.diagnosticCollection = languages.createDiagnosticCollection(this.testProvider); - this.unitTestDiagnosticService = serviceContainer.get(ITestDiagnosticService); - this.testsStatusUpdaterService = serviceContainer.get(ITestsStatusUpdaterService); - this.commandManager = serviceContainer.get(ICommandManager); - disposables.push(this); - } - - protected get testDiscoveryCancellationToken(): CancellationToken | undefined { - return this.testDiscoveryCancellationTokenSource ? this.testDiscoveryCancellationTokenSource.token : undefined; - } - - protected get testRunnerCancellationToken(): CancellationToken | undefined { - return this.testRunnerCancellationTokenSource ? this.testRunnerCancellationTokenSource.token : undefined; - } - - public dispose(): void { - this.stop(); - } - - public get status(): TestStatus { - return this._status; - } - - public get onDidStatusChange(): Event { - return this._onDidStatusChange.event; - } - - public get workingDirectory(): string { - return this.settings.testing.cwd && this.settings.testing.cwd.length > 0 - ? this.settings.testing.cwd - : this.rootDirectory; - } - - public stop(): void { - if (this.testDiscoveryCancellationTokenSource) { - this.testDiscoveryCancellationTokenSource.cancel(); - } - if (this.testRunnerCancellationTokenSource) { - this.testRunnerCancellationTokenSource.cancel(); - } - } - - public reset(): void { - this.tests = undefined; - this.updateStatus(TestStatus.Unknown); - } - - public resetTestResults(): void { - if (!this.tests) { - return; - } - - this.testResultsService.resetResults(this.tests); - } - - public async discoverTests( - cmdSource: CommandSource, - ignoreCache = false, - quietMode = false, - userInitiated = false, - clearTestStatus = false, - ): Promise { - if (this.discoverTestsPromise) { - return this.discoverTestsPromise; - } - this.discoverTestsPromise = this._discoverTests( - cmdSource, - ignoreCache, - quietMode, - userInitiated, - clearTestStatus, - ); - this.discoverTestsPromise - .catch(noop) - .then(() => { - this.discoverTestsPromise = undefined; - }) - .ignoreErrors(); - return this.discoverTestsPromise; - } - - private async _discoverTests( - cmdSource: CommandSource, - ignoreCache = false, - quietMode = false, - userInitiated = false, - clearTestStatus = false, - ): Promise { - if (!ignoreCache && this.tests! && this.tests!.testFunctions.length > 0) { - this.updateStatus(TestStatus.Idle); - return Promise.resolve(this.tests!); - } - if (userInitiated) { - this.testsStatusUpdaterService.updateStatusAsDiscovering(this.workspaceFolder, this.tests); - } - this.updateStatus(TestStatus.Discovering); - // If ignoreCache is true, its an indication of the fact that its a user invoked operation. - // Hence we can stop the debugger. - if (userInitiated) { - this.stop(); - } - const telementryProperties: TestDiscoveryTelemetry = { - tool: this.testProvider, - - trigger: cmdSource as 'ui' | 'commandpalette', - failed: false, - }; - this.commandManager.executeCommand('setContext', 'testsDiscovered', true).then(noop, noop); - this.createCancellationToken(CancellationTokenType.testDiscovery); - const discoveryOptions = this.getDiscoveryOptions(ignoreCache); - const discoveryService = this.serviceContainer.get( - ITestDiscoveryService, - this.testProvider, - ); - return discoveryService - .discoverTests(discoveryOptions) - .then((tests) => { - const wkspace = this.workspaceService.getWorkspaceFolder(Uri.file(this.rootDirectory))!.uri; - const existingTests = this.testCollectionStorage.getTests(wkspace)!; - if (clearTestStatus) { - this.resetTestResults(); - } else if (existingTests) { - copyDesiredTestResults(existingTests, tests); - this._testResultsService.updateResults(tests); - } - this.testCollectionStorage.storeTests(wkspace, tests); - this.tests = tests; - this.updateStatus(TestStatus.Idle); - this.discoverTestsPromise = undefined; - - tests.testFiles.forEach((file) => { - if (file.errorsWhenDiscovering && file.errorsWhenDiscovering.length > 0) { - this.outputChannel.append('_'.repeat(10)); - this.outputChannel.append(`There was an error in identifying unit tests in ${file.nameToRun}`); - this.outputChannel.appendLine('_'.repeat(10)); - this.outputChannel.appendLine(file.errorsWhenDiscovering); - } - }); - - this.disposeCancellationToken(CancellationTokenType.testDiscovery); - sendTelemetryEvent(EventName.UNITTEST_DISCOVER, undefined, telementryProperties); - return tests; - }) - .catch(async (reason: Error | string) => { - if (userInitiated) { - this.testsStatusUpdaterService.updateStatusAsUnknown(this.workspaceFolder, this.tests); - } - if ( - isNotInstalledError(reason as Error) && - !quietMode && - !(await this.installer.isInstalled(this.product, this.workspaceFolder)) - ) { - this.installer - .promptToInstall(this.product, this.workspaceFolder) - .catch((ex) => traceError('isNotInstalledError', ex)); - } - - this.tests = undefined; - this.discoverTestsPromise = undefined; - if ( - this.testDiscoveryCancellationToken && - this.testDiscoveryCancellationToken.isCancellationRequested - ) { - reason = CANCELLATION_REASON; - this.updateStatus(TestStatus.Idle); - } else { - telementryProperties.failed = true; - sendTelemetryEvent(EventName.UNITTEST_DISCOVER, undefined, telementryProperties); - this.updateStatus(TestStatus.Error); - this.outputChannel.appendLine('Test Discovery failed: '); - this.outputChannel.appendLine(reason.toString()); - } - const wkspace = this.workspaceService.getWorkspaceFolder(Uri.file(this.rootDirectory))!.uri; - this.testCollectionStorage.storeTests(wkspace, undefined); - this.disposeCancellationToken(CancellationTokenType.testDiscovery); - return Promise.reject(reason); - }); - } - - public async runTest( - cmdSource: CommandSource, - testsToRun?: TestsToRun, - runFailedTests?: boolean, - debug?: boolean, - ): Promise { - const moreInfo = { - Test_Provider: this.testProvider, - Run_Failed_Tests: 'false', - Run_Specific_File: 'false', - Run_Specific_Class: 'false', - Run_Specific_Function: 'false', - }; - // Ensure valid values are sent. - const validCmdSourceValues = getNamesAndValues(CommandSource).map((item) => item.value); - const telementryProperties: TestRunTelemetry = { - tool: this.testProvider, - scope: 'all', - debugging: debug === true, - triggerSource: validCmdSourceValues.indexOf(cmdSource) === -1 ? 'commandpalette' : cmdSource, - failed: false, - }; - - if (!runFailedTests && !testsToRun) { - this.testsStatusUpdaterService.updateStatusAsRunning(this.workspaceFolder, this.tests); - } - - this.updateStatus(TestStatus.Running); - if (this.testRunnerCancellationTokenSource) { - this.testRunnerCancellationTokenSource.cancel(); - } - - if (runFailedTests === true) { - moreInfo.Run_Failed_Tests = runFailedTests.toString(); - telementryProperties.scope = 'failed'; - this.testsStatusUpdaterService.updateStatusAsRunningFailedTests(this.workspaceFolder, this.tests); - } - if (testsToRun && typeof testsToRun === 'object') { - if (Array.isArray(testsToRun.testFile) && testsToRun.testFile.length > 0) { - telementryProperties.scope = 'file'; - moreInfo.Run_Specific_File = 'true'; - } - if (Array.isArray(testsToRun.testSuite) && testsToRun.testSuite.length > 0) { - telementryProperties.scope = 'class'; - moreInfo.Run_Specific_Class = 'true'; - } - if (Array.isArray(testsToRun.testFunction) && testsToRun.testFunction.length > 0) { - telementryProperties.scope = 'function'; - moreInfo.Run_Specific_Function = 'true'; - } - this.testsStatusUpdaterService.updateStatusAsRunningSpecificTests( - this.workspaceFolder, - testsToRun, - this.tests, - ); - } - - this.testsStatusUpdaterService.triggerUpdatesToTests(this.workspaceFolder, this.tests); - // If running failed tests, then don't clear the previously build UnitTests - // If we do so, then we end up re-discovering the unit tests and clearing previously cached list of failed tests - // Similarly, if running a specific test or test file, don't clear the cache (possible tests have some state information retained) - const clearDiscoveredTestCache = !( - runFailedTests || - moreInfo.Run_Specific_File || - moreInfo.Run_Specific_Class || - moreInfo.Run_Specific_Function - ); - return this.discoverTests(cmdSource, clearDiscoveredTestCache, true, true) - .catch((reason) => { - if ( - this.testDiscoveryCancellationToken && - this.testDiscoveryCancellationToken.isCancellationRequested - ) { - return Promise.reject(reason); - } - return { - rootTestFolders: [], - testFiles: [], - testFolders: [], - testFunctions: [], - testSuites: [], - summary: { errors: 0, failures: 0, passed: 0, skipped: 0 }, - }; - }) - .then((tests) => { - this.updateStatus(TestStatus.Running); - this.createCancellationToken(CancellationTokenType.testRunner); - return this.runTestImpl(tests, testsToRun, runFailedTests, debug); - }) - .then(() => { - this.updateStatus(TestStatus.Idle); - this.disposeCancellationToken(CancellationTokenType.testRunner); - sendTelemetryEvent(EventName.UNITTEST_RUN, undefined, telementryProperties); - this.testsStatusUpdaterService.updateStatusOfRunningTestsAsIdle(this.workspaceFolder, this.tests); - this.testsStatusUpdaterService.triggerUpdatesToTests(this.workspaceFolder, this.tests); - return this.tests!; - }) - .catch((reason) => { - this.testsStatusUpdaterService.updateStatusOfRunningTestsAsIdle(this.workspaceFolder, this.tests); - this.testsStatusUpdaterService.triggerUpdatesToTests(this.workspaceFolder, this.tests); - if (this.testRunnerCancellationToken && this.testRunnerCancellationToken.isCancellationRequested) { - reason = CANCELLATION_REASON; - this.updateStatus(TestStatus.Idle); - } else { - this.updateStatus(TestStatus.Error); - telementryProperties.failed = true; - sendTelemetryEvent(EventName.UNITTEST_RUN, undefined, telementryProperties); - } - this.disposeCancellationToken(CancellationTokenType.testRunner); - return Promise.reject(reason); - }); - } - - public async updateDiagnostics(tests: Tests, messages: IPythonTestMessage[]): Promise { - await this.stripStaleDiagnostics(tests, messages); - - // Update relevant file diagnostics for tests that have problems. - const uniqueMsgFiles = messages.reduce((filtered, msg) => { - if (filtered.indexOf(msg.testFilePath) === -1 && msg.testFilePath !== undefined) { - filtered.push(msg.testFilePath); - } - return filtered; - }, []); - const fs = this.serviceContainer.get(IFileSystem); - for (const msgFile of uniqueMsgFiles) { - // Check all messages against each test file. - const fileUri = Uri.file(msgFile); - if (!this.diagnosticCollection.has(fileUri)) { - // Create empty diagnostic for file URI so the rest of the logic can assume one already exists. - const diagnostics: Diagnostic[] = []; - this.diagnosticCollection.set(fileUri, diagnostics); - } - // Get the diagnostics for this file's URI before updating it so old tests that weren't run can still show problems. - const oldDiagnostics = this.diagnosticCollection.get(fileUri)!; - const newDiagnostics: Diagnostic[] = []; - for (const diagnostic of oldDiagnostics) { - newDiagnostics.push(diagnostic); - } - for (const msg of messages) { - if ( - fs.arePathsSame(fileUri.fsPath, Uri.file(msg.testFilePath).fsPath) && - msg.status !== TestStatus.Pass - ) { - const diagnostic = this.createDiagnostics(msg as ITestNonPassingMessage); - newDiagnostics.push(diagnostic); - } - } - - // Set the diagnostics for the file. - this.diagnosticCollection.set(fileUri, newDiagnostics); - } - } - - protected abstract runTestImpl( - tests: Tests, - testsToRun?: TestsToRun, - runFailedTests?: boolean, - debug?: boolean, - ): Promise; - - protected abstract getDiscoveryOptions(ignoreCache: boolean): TestDiscoveryOptions; - - private updateStatus(status: TestStatus): void { - this._status = status; - // Fire after 1ms, let existing code run to completion, - // We need to allow for code to get into a consistent state. - setTimeout(() => this._onDidStatusChange.fire({ workspace: this.workspaceFolder, status }), 1); - } - - private createCancellationToken(tokenType: CancellationTokenType) { - this.disposeCancellationToken(tokenType); - if (tokenType === CancellationTokenType.testDiscovery) { - this.testDiscoveryCancellationTokenSource = new CancellationTokenSource(); - } else { - this.testRunnerCancellationTokenSource = new CancellationTokenSource(); - } - } - - private disposeCancellationToken(tokenType: CancellationTokenType) { - if (tokenType === CancellationTokenType.testDiscovery) { - if (this.testDiscoveryCancellationTokenSource) { - this.testDiscoveryCancellationTokenSource.dispose(); - } - this.testDiscoveryCancellationTokenSource = undefined; - } else { - if (this.testRunnerCancellationTokenSource) { - this.testRunnerCancellationTokenSource.dispose(); - } - this.testRunnerCancellationTokenSource = undefined; - } - } - - /** - * Whenever a test is run, any previous problems it had should be removed. This runs through - * every already existing set of diagnostics for any that match the tests that were just run - * so they can be stripped out (as they are now no longer relevant). If the tests pass, then - * there is no need to have a diagnostic for it. If they fail, the stale diagnostic will be - * replaced by an up-to-date diagnostic showing the most recent problem with that test. - * - * In order to identify diagnostics associated with the tests that were run, the `nameToRun` - * property of each messages is compared to the `code` property of each diagnostic. - * - * @param messages Details about the tests that were just run. - */ - private async stripStaleDiagnostics(tests: Tests, messages: IPythonTestMessage[]): Promise { - this.diagnosticCollection.forEach((diagnosticUri, oldDiagnostics, collection) => { - const newDiagnostics: Diagnostic[] = []; - for (const diagnostic of oldDiagnostics) { - const matchingMsg = messages.find((msg) => msg.code === diagnostic.code); - if (matchingMsg === undefined) { - // No matching message was found, so this test was not included in the test run. - const matchingTest = tests.testFunctions.find( - (tf) => tf.testFunction.nameToRun === diagnostic.code, - ); - if (matchingTest !== undefined) { - // Matching test was found, so the diagnostic is still relevant. - newDiagnostics.push(diagnostic); - } - } - } - // Set the diagnostics for the file. - collection.set(diagnosticUri, newDiagnostics); - }); - } - - private createDiagnostics(message: ITestNonPassingMessage): Diagnostic { - const stackStart = message.locationStack[0]; - const diagMsg = this.getDiagnosticMessage(message); - const severity = this.unitTestDiagnosticService.getSeverity(message.severity); - const diagnostic = new Diagnostic(stackStart.location.range, diagMsg, severity); - diagnostic.code = message.code; - diagnostic.source = message.provider; - const relatedInfoArr: DiagnosticRelatedInformation[] = []; - for (const frameDetails of message.locationStack) { - const relatedInfo = new DiagnosticRelatedInformation(frameDetails.location, frameDetails.lineText); - relatedInfoArr.push(relatedInfo); - } - diagnostic.relatedInformation = relatedInfoArr; - return diagnostic; - } - - private getDiagnosticMessage(message: ITestNonPassingMessage): string { - const diagMsg = message.message ? message.message.split('\n')[0] : ''; - const diagPrefix = this.unitTestDiagnosticService.getMessagePrefix(message.status); - if (diagMsg === '') { - return diagPrefix; - } - return `${diagPrefix}: ${diagMsg}`; - } -} diff --git a/src/client/testing/common/services/discoveredTestParser.ts b/src/client/testing/common/services/discoveredTestParser.ts deleted file mode 100644 index 182281db6508..000000000000 --- a/src/client/testing/common/services/discoveredTestParser.ts +++ /dev/null @@ -1,383 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { inject, injectable } from 'inversify'; -import * as path from 'path'; -import { Uri } from 'vscode'; -import { IWorkspaceService } from '../../../common/application/types'; -import { traceError } from '../../../common/logger'; -import { getParentFile, getParentSuite, getTestDataItemType } from '../testUtils'; -import { TestDataItem, TestDataItemType } from '../types'; -import * as testing from '../types'; -import * as discovery from './types'; - -@injectable() -export class TestDiscoveredTestParser implements discovery.ITestDiscoveredTestParser { - constructor(@inject(IWorkspaceService) private readonly workspaceService: IWorkspaceService) {} - - public parse(resource: Uri, discoveredTests: discovery.DiscoveredTests[]): testing.Tests { - const tests: testing.Tests = { - rootTestFolders: [], - summary: { errors: 0, failures: 0, passed: 0, skipped: 0 }, - testFiles: [], - testFolders: [], - testFunctions: [], - testSuites: [], - }; - - const workspace = this.workspaceService.getWorkspaceFolder(resource); - if (!workspace) { - traceError('Resource does not belong to any workspace folder'); - return tests; - } - - for (const data of discoveredTests) { - const rootFolder = { - name: data.root, - folders: [], - time: 0, - testFiles: [], - resource: resource, - nameToRun: data.rootid, - }; - tests.rootTestFolders.push(rootFolder); - tests.testFolders.push(rootFolder); - this.buildChildren(rootFolder, rootFolder, data, tests); - } - - return tests; - } - - /** - * Not the best solution to use `case statements`, but it keeps the code simple and easy to read in one place. - * Could go with separate classes for each type and use stratergies, but that just ends up a class for - * 10 lines of code. Hopefully this is more readable and maintainable than having multiple classes for - * the simple processing of the children. - * - * @protected - * @param {TestFolder} rootFolder - * @param {TestDataItem} parent - * @param {DiscoveredTests} discoveredTests - * @param {Tests} tests - * @memberof TestsDiscovery - */ - public buildChildren( - rootFolder: testing.TestFolder, - parent: TestDataItem, - discoveredTests: discovery.DiscoveredTests, - tests: testing.Tests, - ) { - const parentType = getTestDataItemType(parent); - switch (parentType) { - case TestDataItemType.folder: { - this.processFolder(rootFolder, parent as testing.TestFolder, discoveredTests, tests); - break; - } - case TestDataItemType.file: { - this.processFile(rootFolder, parent as testing.TestFile, discoveredTests, tests); - break; - } - case TestDataItemType.suite: { - this.processSuite(rootFolder, parent as testing.TestSuite, discoveredTests, tests); - break; - } - default: - break; - } - } - - /** - * Process the children of a folder. - * A folder can only contain other folders and files. - * Hence limit processing to those items. - * - * @protected - * @param {TestFolder} rootFolder - * @param {TestFolder} parentFolder - * @param {DiscoveredTests} discoveredTests - * @param {Tests} tests - * @memberof TestDiscoveredTestParser - */ - protected processFolder( - rootFolder: testing.TestFolder, - parentFolder: testing.TestFolder, - discoveredTests: discovery.DiscoveredTests, - tests: testing.Tests, - ) { - const folders = discoveredTests.parents - .filter((child) => child.kind === 'folder' && child.parentid === parentFolder.nameToRun) - .map((folder) => createTestFolder(rootFolder, folder as discovery.TestFolder)); - folders.forEach((folder) => { - parentFolder.folders.push(folder); - tests.testFolders.push(folder); - this.buildChildren(rootFolder, folder, discoveredTests, tests); - }); - - const files = discoveredTests.parents - .filter((child) => child.kind === 'file' && child.parentid === parentFolder.nameToRun) - .map((file) => createTestFile(rootFolder, file as discovery.TestFile)); - files.forEach((file) => { - parentFolder.testFiles.push(file); - tests.testFiles.push(file); - this.buildChildren(rootFolder, file, discoveredTests, tests); - }); - } - - /** - * Process the children of a file. - * A file can only contain suites, functions and paramerterized functions. - * Hence limit processing just to those items. - * - * @protected - * @param {TestFolder} rootFolder - * @param {TestFile} parentFile - * @param {DiscoveredTests} discoveredTests - * @param {Tests} tests - * @memberof TestDiscoveredTestParser - */ - protected processFile( - rootFolder: testing.TestFolder, - parentFile: testing.TestFile, - discoveredTests: discovery.DiscoveredTests, - tests: testing.Tests, - ) { - const suites = discoveredTests.parents - .filter((child) => child.kind === 'suite' && child.parentid === parentFile.nameToRun) - .map((suite) => createTestSuite(parentFile, rootFolder.resource, suite as discovery.TestSuite)); - suites.forEach((suite) => { - parentFile.suites.push(suite); - tests.testSuites.push(createFlattenedSuite(tests, suite)); - this.buildChildren(rootFolder, suite, discoveredTests, tests); - }); - - const functions = discoveredTests.tests - .filter((test) => test.parentid === parentFile.nameToRun) - .map((test) => createTestFunction(rootFolder, test)); - functions.forEach((func) => { - parentFile.functions.push(func); - tests.testFunctions.push(createFlattenedFunction(tests, func)); - }); - - const parameterizedFunctions = discoveredTests.parents - .filter((child) => child.kind === 'function' && child.parentid === parentFile.nameToRun) - .map((func) => createParameterizedTestFunction(rootFolder, func as discovery.TestFunction)); - parameterizedFunctions.forEach((func) => - this.processParameterizedFunction(rootFolder, parentFile, func, discoveredTests, tests), - ); - } - - /** - * Process the children of a suite. - * A suite can only contain suites, functions and paramerterized functions. - * Hence limit processing just to those items. - * - * @protected - * @param {TestFolder} rootFolder - * @param {TestSuite} parentSuite - * @param {DiscoveredTests} discoveredTests - * @param {Tests} tests - * @memberof TestDiscoveredTestParser - */ - protected processSuite( - rootFolder: testing.TestFolder, - parentSuite: testing.TestSuite, - discoveredTests: discovery.DiscoveredTests, - tests: testing.Tests, - ) { - const suites = discoveredTests.parents - .filter((child) => child.kind === 'suite' && child.parentid === parentSuite.nameToRun) - .map((suite) => createTestSuite(parentSuite, rootFolder.resource, suite as discovery.TestSuite)); - suites.forEach((suite) => { - parentSuite.suites.push(suite); - tests.testSuites.push(createFlattenedSuite(tests, suite)); - this.buildChildren(rootFolder, suite, discoveredTests, tests); - }); - - const functions = discoveredTests.tests - .filter((test) => test.parentid === parentSuite.nameToRun) - .map((test) => createTestFunction(rootFolder, test)); - functions.forEach((func) => { - parentSuite.functions.push(func); - tests.testFunctions.push(createFlattenedFunction(tests, func)); - }); - - const parameterizedFunctions = discoveredTests.parents - .filter((child) => child.kind === 'function' && child.parentid === parentSuite.nameToRun) - .map((func) => createParameterizedTestFunction(rootFolder, func as discovery.TestFunction)); - parameterizedFunctions.forEach((func) => - this.processParameterizedFunction(rootFolder, parentSuite, func, discoveredTests, tests), - ); - } - - /** - * Process the children of a parameterized function. - * A parameterized function can only contain functions (in tests). - * Hence limit processing just to those items. - * - * @protected - * @param {TestFolder} rootFolder - * @param {TestFile | TestSuite} parent - * @param {TestFunction} parentFunction - * @param {DiscoveredTests} discoveredTests - * @param {Tests} tests - * @returns - * @memberof TestDiscoveredTestParser - */ - protected processParameterizedFunction( - rootFolder: testing.TestFolder, - parent: testing.TestFile | testing.TestSuite, - parentFunction: testing.SubtestParent, - discoveredTests: discovery.DiscoveredTests, - tests: testing.Tests, - ) { - if (!parentFunction.asSuite) { - return; - } - const functions = discoveredTests.tests - .filter((test) => test.parentid === parentFunction.nameToRun) - .map((test) => createTestFunction(rootFolder, test)); - functions.forEach((func) => { - func.subtestParent = parentFunction; - parentFunction.asSuite.functions.push(func); - parent.functions.push(func); - tests.testFunctions.push(createFlattenedParameterizedFunction(tests, func, parent)); - }); - } -} - -function createTestFolder(root: testing.TestFolder, item: discovery.TestFolder): testing.TestFolder { - return { - name: item.name, - nameToRun: item.id, - resource: root.resource, - time: 0, - folders: [], - testFiles: [], - }; -} - -function createTestFile(root: testing.TestFolder, item: discovery.TestFile): testing.TestFile { - const fullpath = path.isAbsolute(item.relpath) ? item.relpath : path.resolve(root.name, item.relpath); - return { - fullPath: fullpath, - functions: [], - name: item.name, - nameToRun: item.id, - resource: root.resource, - suites: [], - time: 0, - xmlName: createXmlName(item.id), - }; -} - -function createTestSuite( - parentSuiteFile: testing.TestFile | testing.TestSuite, - resource: Uri, - item: discovery.TestSuite, -): testing.TestSuite { - const suite = { - functions: [], - name: item.name, - nameToRun: item.id, - resource: resource, - suites: [], - time: 0, - xmlName: '', - isInstance: false, - isUnitTest: false, - }; - suite.xmlName = `${parentSuiteFile.xmlName}.${item.name}`; - return suite; -} - -function createFlattenedSuite(tests: testing.Tests, suite: testing.TestSuite): testing.FlattenedTestSuite { - const parentFile = getParentFile(tests, suite); - return { - parentTestFile: parentFile, - testSuite: suite, - xmlClassName: parentFile.xmlName, - }; -} - -function createFlattenedParameterizedFunction( - tests: testing.Tests, - func: testing.TestFunction, - parent: testing.TestFile | testing.TestSuite, -): testing.FlattenedTestFunction { - const type = getTestDataItemType(parent); - const parentFile = - type && type === TestDataItemType.suite ? getParentFile(tests, func) : (parent as testing.TestFile); - const parentSuite = type && type === TestDataItemType.suite ? (parent as testing.TestSuite) : undefined; - return { - parentTestFile: parentFile, - parentTestSuite: parentSuite, - xmlClassName: parentSuite ? parentSuite.xmlName : parentFile.xmlName, - testFunction: func, - }; -} - -function createFlattenedFunction(tests: testing.Tests, func: testing.TestFunction): testing.FlattenedTestFunction { - const parent = getParentFile(tests, func); - const type = parent ? getTestDataItemType(parent) : undefined; - const parentFile = type && type === TestDataItemType.suite ? getParentFile(tests, func) : parent; - const parentSuite = getParentSuite(tests, func); - return { - parentTestFile: parentFile, - parentTestSuite: parentSuite, - xmlClassName: parentSuite ? parentSuite.xmlName : parentFile.xmlName, - testFunction: func, - }; -} - -function createParameterizedTestFunction( - root: testing.TestFolder, - item: discovery.TestFunction, -): testing.SubtestParent { - const suite: testing.TestSuite = { - functions: [], - isInstance: false, - isUnitTest: false, - name: item.name, - nameToRun: item.id, - resource: root.resource, - time: 0, - suites: [], - xmlName: '', - }; - return { - asSuite: suite, - name: item.name, - nameToRun: item.id, - time: 0, - }; -} - -function createTestFunction(root: testing.TestFolder, item: discovery.Test): testing.TestFunction { - return { - name: item.name, - nameToRun: item.id, - resource: root.resource, - time: 0, - file: item.source.substr(0, item.source.lastIndexOf(':')), - }; -} - -/** - * Creates something known as an Xml Name, used to identify items - * from an xunit test result. - * Once we have the test runner done in Python, this can be discarded. - * @param {string} fileId - * @returns - */ -function createXmlName(fileId: string) { - let name = path.join(path.dirname(fileId), path.basename(fileId, path.extname(fileId))); - // Replace all path separators with ".". - name = name.replace(/\\/g, '.').replace(/\//g, '.'); - // Remove leading "." and path separators. - while (name.startsWith('.') || name.startsWith('/') || name.startsWith('\\')) { - name = name.substring(1); - } - return name; -} diff --git a/src/client/testing/common/services/discovery.ts b/src/client/testing/common/services/discovery.ts deleted file mode 100644 index d717043b36e9..000000000000 --- a/src/client/testing/common/services/discovery.ts +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { inject, injectable, named } from 'inversify'; -import { OutputChannel } from 'vscode'; -import { traceError } from '../../../common/logger'; -import * as internalScripts from '../../../common/process/internal/scripts'; -import { - ExecutionFactoryCreateWithEnvironmentOptions, - IPythonExecutionFactory, - SpawnOptions, -} from '../../../common/process/types'; -import { IOutputChannel } from '../../../common/types'; -import { captureTelemetry } from '../../../telemetry'; -import { EventName } from '../../../telemetry/constants'; -import { TEST_OUTPUT_CHANNEL } from '../../constants'; -import { ITestDiscoveryService, TestDiscoveryOptions, Tests } from '../types'; -import { DiscoveredTests, ITestDiscoveredTestParser } from './types'; - -@injectable() -export class TestsDiscoveryService implements ITestDiscoveryService { - constructor( - @inject(IPythonExecutionFactory) private readonly execFactory: IPythonExecutionFactory, - @inject(ITestDiscoveredTestParser) private readonly parser: ITestDiscoveredTestParser, - @inject(IOutputChannel) @named(TEST_OUTPUT_CHANNEL) private readonly outChannel: OutputChannel, - ) {} - @captureTelemetry(EventName.UNITTEST_DISCOVER_WITH_PYCODE, undefined, true) - public async discoverTests(options: TestDiscoveryOptions): Promise { - try { - const discoveredTests = await this.exec(options); - return this.parser.parse(options.workspaceFolder, discoveredTests); - } catch (ex) { - if (ex.stdout) { - traceError('Failed to parse discovered Test', new Error(ex.stdout)); - } - traceError('Failed to parse discovered Test', ex); - throw ex; - } - } - public async exec(options: TestDiscoveryOptions): Promise { - const [args, parse] = internalScripts.testingTools.run_adapter(options.args); - const creationOptions: ExecutionFactoryCreateWithEnvironmentOptions = { - allowEnvironmentFetchExceptions: false, - resource: options.workspaceFolder, - }; - const execService = await this.execFactory.createActivatedEnvironment(creationOptions); - const spawnOptions: SpawnOptions = { - token: options.token, - cwd: options.cwd, - throwOnStdErr: true, - }; - this.outChannel.appendLine(`python ${args.join(' ')}`); - const proc = await execService.exec(args, spawnOptions); - try { - return parse(proc.stdout); - } catch (ex) { - ex.stdout = proc.stdout; - throw ex; // re-throw - } - } -} diff --git a/src/client/testing/common/services/storageService.ts b/src/client/testing/common/services/storageService.ts deleted file mode 100644 index 3540174404a0..000000000000 --- a/src/client/testing/common/services/storageService.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { inject, injectable } from 'inversify'; -import { Disposable, Event, EventEmitter, Uri } from 'vscode'; -import { IWorkspaceService } from '../../../common/application/types'; -import { IDisposableRegistry } from '../../../common/types'; -import {} from '../../types'; -import { - FlattenedTestFunction, - FlattenedTestSuite, - ITestCollectionStorageService, - TestDataItem, - TestFunction, - Tests, - TestSuite, -} from './../types'; - -@injectable() -export class TestCollectionStorageService implements ITestCollectionStorageService { - private readonly _onDidChange = new EventEmitter<{ uri: Uri; data?: TestDataItem }>(); - private readonly testsIndexedByWorkspaceUri = new Map(); - - constructor( - @inject(IDisposableRegistry) disposables: Disposable[], - @inject(IWorkspaceService) private readonly workspaceService: IWorkspaceService, - ) { - disposables.push(this); - } - public get onDidChange(): Event<{ uri: Uri; data?: TestDataItem }> { - return this._onDidChange.event; - } - public getTests(resource: Uri): Tests | undefined { - const workspaceFolder = this.workspaceService.getWorkspaceFolderIdentifier(resource); - return this.testsIndexedByWorkspaceUri.has(workspaceFolder) - ? this.testsIndexedByWorkspaceUri.get(workspaceFolder) - : undefined; - } - public storeTests(resource: Uri, tests: Tests | undefined): void { - const workspaceFolder = this.workspaceService.getWorkspaceFolderIdentifier(resource); - this.testsIndexedByWorkspaceUri.set(workspaceFolder, tests); - this._onDidChange.fire({ uri: resource }); - } - public findFlattendTestFunction(resource: Uri, func: TestFunction): FlattenedTestFunction | undefined { - const tests = this.getTests(resource); - if (!tests) { - return; - } - return tests.testFunctions.find((f) => f.testFunction === func); - } - public findFlattendTestSuite(resource: Uri, suite: TestSuite): FlattenedTestSuite | undefined { - const tests = this.getTests(resource); - if (!tests) { - return; - } - return tests.testSuites.find((f) => f.testSuite === suite); - } - public dispose() { - this.testsIndexedByWorkspaceUri.clear(); - } - public update(resource: Uri, item: TestDataItem): void { - this._onDidChange.fire({ uri: resource, data: item }); - } -} diff --git a/src/client/testing/common/services/testManagerService.ts b/src/client/testing/common/services/testManagerService.ts deleted file mode 100644 index 53c3d60a75d0..000000000000 --- a/src/client/testing/common/services/testManagerService.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { Disposable, Uri } from 'vscode'; -import { IConfigurationService, IDisposableRegistry, Product } from '../../../common/types'; -import { IServiceContainer } from '../../../ioc/types'; -import { ITestManager, ITestManagerFactory, ITestManagerService, ITestsHelper, UnitTestProduct } from './../types'; - -export class TestManagerService implements ITestManagerService { - private cachedTestManagers = new Map(); - private readonly configurationService: IConfigurationService; - constructor(private wkspace: Uri, private testsHelper: ITestsHelper, private serviceContainer: IServiceContainer) { - const disposables = serviceContainer.get(IDisposableRegistry); - this.configurationService = serviceContainer.get(IConfigurationService); - disposables.push(this); - } - public dispose() { - this.cachedTestManagers.forEach((info) => { - info.dispose(); - }); - } - public getTestManager(): ITestManager | undefined { - const preferredTestManager = this.getPreferredTestManager(); - if (typeof preferredTestManager !== 'number') { - return; - } - - if (!this.cachedTestManagers.has(preferredTestManager)) { - const testDirectory = this.getTestWorkingDirectory(); - const testProvider = this.testsHelper.parseProviderName(preferredTestManager); - const factory = this.serviceContainer.get(ITestManagerFactory); - this.cachedTestManagers.set(preferredTestManager, factory(testProvider, this.wkspace, testDirectory)); - } - const testManager = this.cachedTestManagers.get(preferredTestManager)!; - return testManager.enabled ? testManager : undefined; - } - public getTestWorkingDirectory() { - const settings = this.configurationService.getSettings(this.wkspace); - return settings.testing.cwd && settings.testing.cwd.length > 0 ? settings.testing.cwd : this.wkspace.fsPath; - } - public getPreferredTestManager(): UnitTestProduct | undefined { - const settings = this.configurationService.getSettings(this.wkspace); - if (settings.testing.pytestEnabled) { - return Product.pytest; - } else if (settings.testing.unittestEnabled) { - return Product.unittest; - } - return undefined; - } -} diff --git a/src/client/testing/common/services/testResultsService.ts b/src/client/testing/common/services/testResultsService.ts deleted file mode 100644 index 8c526ef16cc1..000000000000 --- a/src/client/testing/common/services/testResultsService.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { inject, injectable, named } from 'inversify'; -import { getChildren, getTestDataItemType } from '../testUtils'; -import { ITestResultsService, ITestVisitor, Tests, TestStatus } from '../types'; -import { TestDataItem, TestDataItemType } from '../types'; - -@injectable() -export class TestResultsService implements ITestResultsService { - constructor(@inject(ITestVisitor) @named('TestResultResetVisitor') private resultResetVisitor: ITestVisitor) {} - public resetResults(tests: Tests): void { - tests.testFolders.forEach((f) => this.resultResetVisitor.visitTestFolder(f)); - tests.testFunctions.forEach((fn) => this.resultResetVisitor.visitTestFunction(fn.testFunction)); - tests.testSuites.forEach((suite) => this.resultResetVisitor.visitTestSuite(suite.testSuite)); - tests.testFiles.forEach((testFile) => this.resultResetVisitor.visitTestFile(testFile)); - } - public updateResults(tests: Tests): void { - // Update Test tree bottom to top - const testQueue: TestDataItem[] = []; - const testStack: TestDataItem[] = []; - tests.rootTestFolders.forEach((folder) => testQueue.push(folder)); - - while (testQueue.length > 0) { - const item = testQueue.shift(); - if (!item) { - continue; - } - testStack.push(item); - const children = getChildren(item); - children.forEach((child) => testQueue.push(child)); - } - while (testStack.length > 0) { - const item = testStack.pop(); - this.updateTestItem(item!); - } - } - private updateTestItem(test: TestDataItem): void { - if (getTestDataItemType(test) === TestDataItemType.function) { - return; - } - let allChildrenPassed = true; - let noChildrenRan = true; - test.functionsPassed = test.functionsFailed = test.functionsDidNotRun = 0; - - const children = getChildren(test); - children.forEach((child) => { - if (getTestDataItemType(child) === TestDataItemType.function) { - if (typeof child.passed === 'boolean') { - noChildrenRan = false; - if (child.passed) { - test.functionsPassed! += 1; - } else { - test.functionsFailed! += 1; - allChildrenPassed = false; - } - } else { - test.functionsDidNotRun! += 1; - } - } else { - if (typeof child.passed === 'boolean') { - noChildrenRan = false; - if (!child.passed) { - allChildrenPassed = false; - } - } - test.functionsFailed! += child.functionsFailed!; - test.functionsPassed! += child.functionsPassed!; - test.functionsDidNotRun! += child.functionsDidNotRun!; - } - }); - if (noChildrenRan) { - test.passed = undefined; - test.status = TestStatus.Unknown; - } else { - test.passed = allChildrenPassed; - test.status = test.passed ? TestStatus.Pass : TestStatus.Fail; - } - } -} diff --git a/src/client/testing/common/services/testsStatusService.ts b/src/client/testing/common/services/testsStatusService.ts deleted file mode 100644 index 37ad2ca3cee2..000000000000 --- a/src/client/testing/common/services/testsStatusService.ts +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { inject, injectable } from 'inversify'; -import { Uri } from 'vscode'; -import { visitRecursive } from '../testVisitors/visitor'; -import { - ITestCollectionStorageService, - ITestsStatusUpdaterService, - TestDataItem, - Tests, - TestStatus, - TestsToRun, -} from '../types'; - -@injectable() -export class TestsStatusUpdaterService implements ITestsStatusUpdaterService { - constructor(@inject(ITestCollectionStorageService) private readonly storage: ITestCollectionStorageService) {} - public updateStatusAsDiscovering(resource: Uri, tests?: Tests): void { - if (!tests) { - return; - } - const visitor = (item: TestDataItem) => { - item.status = TestStatus.Discovering; - this.storage.update(resource, item); - }; - tests.rootTestFolders.forEach((item) => visitRecursive(tests, item, visitor)); - } - public updateStatusAsUnknown(resource: Uri, tests?: Tests): void { - if (!tests) { - return; - } - const visitor = (item: TestDataItem) => { - item.status = TestStatus.Unknown; - this.storage.update(resource, item); - }; - tests.rootTestFolders.forEach((item) => visitRecursive(tests, item, visitor)); - } - public updateStatusAsRunning(resource: Uri, tests?: Tests): void { - if (!tests) { - return; - } - const visitor = (item: TestDataItem) => { - item.status = TestStatus.Running; - this.storage.update(resource, item); - }; - tests.rootTestFolders.forEach((item) => visitRecursive(tests, item, visitor)); - } - public updateStatusAsRunningFailedTests(resource: Uri, tests?: Tests): void { - if (!tests) { - return; - } - const predicate = (item: TestDataItem) => item.status === TestStatus.Fail || item.status === TestStatus.Error; - const visitor = (item: TestDataItem) => { - if (item.status && predicate(item)) { - item.status = TestStatus.Running; - this.storage.update(resource, item); - } - }; - const failedItems = [ - ...tests.testFunctions.map((f) => f.testFunction).filter(predicate), - ...tests.testSuites.map((f) => f.testSuite).filter(predicate), - ]; - failedItems.forEach((failedItem) => visitRecursive(tests, failedItem, visitor)); - } - public updateStatusAsRunningSpecificTests(resource: Uri, testsToRun: TestsToRun, tests?: Tests): void { - if (!tests) { - return; - } - const itemsRunning = [ - ...(testsToRun.testFolder || []), - ...(testsToRun.testFile || []), - ...(testsToRun.testSuite || []), - ...(testsToRun.testFunction || []), - ]; - const visitor = (item: TestDataItem) => { - item.status = TestStatus.Running; - this.storage.update(resource, item); - }; - itemsRunning.forEach((item) => visitRecursive(tests, item, visitor)); - } - public updateStatusOfRunningTestsAsIdle(resource: Uri, tests?: Tests): void { - if (!tests) { - return; - } - const visitor = (item: TestDataItem) => { - if (item.status === TestStatus.Running) { - item.status = TestStatus.Idle; - this.storage.update(resource, item); - } - }; - tests.rootTestFolders.forEach((item) => visitRecursive(tests, item, visitor)); - } - public triggerUpdatesToTests(resource: Uri, tests?: Tests): void { - if (!tests) { - return; - } - const visitor = (item: TestDataItem) => this.storage.update(resource, item); - tests.rootTestFolders.forEach((item) => visitRecursive(tests, item, visitor)); - } -} diff --git a/src/client/testing/common/services/types.ts b/src/client/testing/common/services/types.ts deleted file mode 100644 index 025a41d2f61d..000000000000 --- a/src/client/testing/common/services/types.ts +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { Uri } from 'vscode'; -import * as internalScripts from '../../../common/process/internal/scripts'; -import { Tests } from '../types'; - -// We expose these here as a convenience and to cut down on churn -// elsewhere in the code. -export type DiscoveredTests = internalScripts.testingTools.DiscoveredTests; -export type Test = internalScripts.testingTools.Test; -export type TestFolder = internalScripts.testingTools.TestFolder; -export type TestFile = internalScripts.testingTools.TestFile; -export type TestSuite = internalScripts.testingTools.TestSuite; -export type TestFunction = internalScripts.testingTools.TestFunction; - -export const ITestDiscoveredTestParser = Symbol('ITestDiscoveredTestParser'); -export interface ITestDiscoveredTestParser { - parse(resource: Uri, discoveredTests: DiscoveredTests[]): Tests; -} diff --git a/src/client/testing/common/services/unitTestDiagnosticService.ts b/src/client/testing/common/services/unitTestDiagnosticService.ts deleted file mode 100644 index be8ef0f4a415..000000000000 --- a/src/client/testing/common/services/unitTestDiagnosticService.ts +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { injectable } from 'inversify'; -import { DiagnosticSeverity } from 'vscode'; -import * as localize from '../../../common/utils/localize'; -import { - DiagnosticMessageType, - ITestDiagnosticService, - NonPassingTestMessageType, - NonPassingTestSeverity, - NonPassingTestStatus, - PythonTestMessageSeverity, - TestStatus, -} from '../types'; - -@injectable() -export class UnitTestDiagnosticService implements ITestDiagnosticService { - private MessageTypes = new Map(); - - private MessageSeverities = new Map(); - - private MessagePrefixes = new Map(); - - constructor() { - this.MessageTypes.set(TestStatus.Error, DiagnosticMessageType.Error); - this.MessageTypes.set(TestStatus.Fail, DiagnosticMessageType.Fail); - this.MessageTypes.set(TestStatus.Skipped, DiagnosticMessageType.Skipped); - this.MessageSeverities.set(PythonTestMessageSeverity.Error, DiagnosticSeverity.Error); - this.MessageSeverities.set(PythonTestMessageSeverity.Failure, DiagnosticSeverity.Error); - this.MessageSeverities.set(PythonTestMessageSeverity.Skip, DiagnosticSeverity.Information); - this.MessagePrefixes.set(DiagnosticMessageType.Error, localize.Testing.testErrorDiagnosticMessage()); - this.MessagePrefixes.set(DiagnosticMessageType.Fail, localize.Testing.testFailDiagnosticMessage()); - this.MessagePrefixes.set(DiagnosticMessageType.Skipped, localize.Testing.testSkippedDiagnosticMessage()); - } - - public getMessagePrefix(status: NonPassingTestStatus): string { - // If `msgType` ends up `undefined` then it means we've added - // a new failing test status but forgot to support it here - // (or it means elsewhere we asserted a bogus value, like - // `undefined`). The same goes for `msgPrefix`. - const msgType = this.MessageTypes.get(status); - if (msgType === undefined) { - throw Error(`unsupported status (${status})`); - } - const msgPrefix = this.MessagePrefixes.get(msgType); - if (msgType === undefined || msgPrefix === undefined) { - throw Error(`unsupported message type (${msgType})`); - } - return msgPrefix; - } - - public getSeverity(unitTestSeverity: NonPassingTestSeverity): DiagnosticSeverity { - const severity = this.MessageSeverities.get(unitTestSeverity); - if (severity === undefined) { - throw Error(`unsupported severity (${unitTestSeverity})`); - } - return severity; - } -} diff --git a/src/client/testing/common/services/workspaceTestManagerService.ts b/src/client/testing/common/services/workspaceTestManagerService.ts deleted file mode 100644 index bd09856d2e40..000000000000 --- a/src/client/testing/common/services/workspaceTestManagerService.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { inject, injectable, named } from 'inversify'; -import { Disposable, OutputChannel, Uri, workspace } from 'vscode'; -import { IDisposableRegistry, IOutputChannel } from '../../../common/types'; -import { TEST_OUTPUT_CHANNEL } from '../../constants'; -import { - ITestManager, - ITestManagerService, - ITestManagerServiceFactory, - IWorkspaceTestManagerService, - UnitTestProduct, -} from '../types'; - -@injectable() -export class WorkspaceTestManagerService implements IWorkspaceTestManagerService, Disposable { - private workspaceTestManagers = new Map(); - constructor( - @inject(IOutputChannel) @named(TEST_OUTPUT_CHANNEL) private outChannel: OutputChannel, - @inject(ITestManagerServiceFactory) private testManagerServiceFactory: ITestManagerServiceFactory, - @inject(IDisposableRegistry) disposables: Disposable[], - ) { - disposables.push(this); - } - public dispose() { - this.workspaceTestManagers.forEach((info) => info.dispose()); - } - public getTestManager(resource: Uri): ITestManager | undefined { - const wkspace = this.getWorkspace(resource); - this.ensureTestManagerService(wkspace); - return this.workspaceTestManagers.get(wkspace.fsPath)!.getTestManager(); - } - public getTestWorkingDirectory(resource: Uri) { - const wkspace = this.getWorkspace(resource); - this.ensureTestManagerService(wkspace); - return this.workspaceTestManagers.get(wkspace.fsPath)!.getTestWorkingDirectory(); - } - public getPreferredTestManager(resource: Uri): UnitTestProduct | undefined { - const wkspace = this.getWorkspace(resource); - this.ensureTestManagerService(wkspace); - return this.workspaceTestManagers.get(wkspace.fsPath)!.getPreferredTestManager(); - } - private getWorkspace(resource: Uri): Uri { - if (!Array.isArray(workspace.workspaceFolders) || workspace.workspaceFolders.length === 0) { - const noWkspaceMessage = 'Please open a workspace'; - this.outChannel.appendLine(noWkspaceMessage); - throw new Error(noWkspaceMessage); - } - if (!resource || workspace.workspaceFolders.length === 1) { - return workspace.workspaceFolders[0].uri; - } - const workspaceFolder = workspace.getWorkspaceFolder(resource); - if (workspaceFolder) { - return workspaceFolder.uri; - } - const message = `Resource '${resource.fsPath}' does not belong to any workspace`; - this.outChannel.appendLine(message); - throw new Error(message); - } - private ensureTestManagerService(wkspace: Uri) { - if (!this.workspaceTestManagers.has(wkspace.fsPath)) { - this.workspaceTestManagers.set(wkspace.fsPath, this.testManagerServiceFactory(wkspace)); - } - } -} diff --git a/src/client/testing/common/managers/testConfigurationManager.ts b/src/client/testing/common/testConfigurationManager.ts similarity index 90% rename from src/client/testing/common/managers/testConfigurationManager.ts rename to src/client/testing/common/testConfigurationManager.ts index ea9098f8dd56..237ab67c29d4 100644 --- a/src/client/testing/common/managers/testConfigurationManager.ts +++ b/src/client/testing/common/testConfigurationManager.ts @@ -1,14 +1,14 @@ import * as path from 'path'; import { OutputChannel, QuickPickItem, Uri } from 'vscode'; -import { IApplicationShell } from '../../../common/application/types'; -import { traceInfo } from '../../../common/logger'; -import { IFileSystem } from '../../../common/platform/types'; -import { IInstaller, IOutputChannel } from '../../../common/types'; -import { createDeferred } from '../../../common/utils/async'; -import { IServiceContainer } from '../../../ioc/types'; -import { TEST_OUTPUT_CHANNEL } from '../../constants'; -import { UNIT_TEST_PRODUCTS } from '../constants'; -import { ITestConfigSettingsService, ITestConfigurationManager, UnitTestProduct } from '../types'; +import { IApplicationShell } from '../../common/application/types'; +import { traceInfo } from '../../common/logger'; +import { IFileSystem } from '../../common/platform/types'; +import { IInstaller, IOutputChannel } from '../../common/types'; +import { createDeferred } from '../../common/utils/async'; +import { IServiceContainer } from '../../ioc/types'; +import { TEST_OUTPUT_CHANNEL } from '../constants'; +import { UNIT_TEST_PRODUCTS } from './constants'; +import { ITestConfigSettingsService, ITestConfigurationManager, UnitTestProduct } from './types'; function handleCancelled(): void { traceInfo('testing configuration (in UI) cancelled'); diff --git a/src/client/testing/common/testUtils.ts b/src/client/testing/common/testUtils.ts index 99a7d38172e7..81902482342f 100644 --- a/src/client/testing/common/testUtils.ts +++ b/src/client/testing/common/testUtils.ts @@ -1,21 +1,17 @@ -import { inject, injectable, named } from 'inversify'; -import * as path from 'path'; +import { injectable } from 'inversify'; import { Uri, workspace } from 'vscode'; import { IApplicationShell } from '../../common/application/types'; import { Product } from '../../common/types'; import { ITestingSettings, TestSettingsPropertyNames } from '../configuration/types'; import { TestProvider } from '../types'; -import { TestFlatteningVisitor } from './testVisitors/flatteningVisitor'; import { ITestsHelper, - ITestVisitor, TestDataItem, TestDataItemType, TestFile, TestFolder, TestFunction, Tests, - TestsToRun, TestSuite, TestWorkspaceFolder, UnitTestProduct, @@ -44,9 +40,7 @@ export function convertFileToPackage(filePath: string): string { @injectable() export class TestsHelper implements ITestsHelper { - constructor( - @inject(ITestVisitor) @named('TestFlatteningVisitor') private readonly flatteningVisitor: TestFlatteningVisitor, - ) {} + constructor() {} public parseProviderName(product: UnitTestProduct): TestProvider { switch (product) { case Product.pytest: @@ -90,158 +84,6 @@ export class TestsHelper implements ITestsHelper { } } } - public flattenTestFiles(testFiles: TestFile[], workspaceFolder: string): Tests { - testFiles.forEach((testFile) => this.flatteningVisitor.visitTestFile(testFile)); - - const tests = { - testFiles: testFiles, - testFunctions: this.flatteningVisitor.flattenedTestFunctions, - testSuites: this.flatteningVisitor.flattenedTestSuites, - testFolders: [], - rootTestFolders: [], - summary: { passed: 0, failures: 0, errors: 0, skipped: 0 }, - }; - - this.placeTestFilesIntoFolders(tests, workspaceFolder); - - return tests; - } - public placeTestFilesIntoFolders(tests: Tests, workspaceFolder: string): void { - // First get all the unique folders - const folders: string[] = []; - tests.testFiles.forEach((file) => { - const relativePath = path.relative(workspaceFolder, file.fullPath); - const dir = path.dirname(relativePath); - if (folders.indexOf(dir) === -1) { - folders.push(dir); - } - }); - - tests.testFolders = []; - const folderMap = new Map(); - folders.sort(); - const resource = Uri.file(workspaceFolder); - folders.forEach((dir) => { - let parentPath = ''; // Accumulator - dir.split(path.sep).forEach((currentName) => { - let newPath = currentName; - let parentFolder: TestFolder | undefined; - if (parentPath.length > 0) { - parentFolder = folderMap.get(parentPath); - newPath = path.join(parentPath, currentName); - } - if (!folderMap.has(newPath)) { - const testFolder: TestFolder = { - resource, - name: currentName, - testFiles: [], - folders: [], - nameToRun: newPath, - time: 0, - functionsPassed: 0, - functionsFailed: 0, - functionsDidNotRun: 0, - }; - folderMap.set(newPath, testFolder); - if (parentFolder) { - parentFolder.folders.push(testFolder); - } else { - tests.rootTestFolders.push(testFolder); - } - tests.testFiles - .filter((fl) => path.dirname(path.relative(workspaceFolder, fl.fullPath)) === newPath) - .forEach((testFile) => { - testFolder.testFiles.push(testFile); - }); - tests.testFolders.push(testFolder); - } - parentPath = newPath; - }); - }); - } - public parseTestName(name: string, rootDirectory: string, tests: Tests): TestsToRun | undefined { - // TODO: We need a better way to match (currently we have raw name, name, xmlname, etc = which one do we. - // Use to identify a file given the full file name, similarly for a folder and function. - // Perhaps something like a parser or methods like TestFunction.fromString()... something). - if (!tests) { - return undefined; - } - const absolutePath = path.isAbsolute(name) ? name : path.resolve(rootDirectory, name); - const testFolders = tests.testFolders.filter( - (folder) => folder.nameToRun === name || folder.name === name || folder.name === absolutePath, - ); - if (testFolders.length > 0) { - return { testFolder: testFolders }; - } - - const testFiles = tests.testFiles.filter( - (file) => file.nameToRun === name || file.name === name || file.fullPath === absolutePath, - ); - if (testFiles.length > 0) { - return { testFile: testFiles }; - } - - const testFns = tests.testFunctions - .filter((fn) => fn.testFunction.nameToRun === name || fn.testFunction.name === name) - .map((fn) => fn.testFunction); - if (testFns.length > 0) { - return { testFunction: testFns }; - } - - // Just return this as a test file. - return { - testFile: [ - { - resource: Uri.file(rootDirectory), - name: name, - nameToRun: name, - functions: [], - suites: [], - xmlName: name, - fullPath: '', - time: 0, - functionsPassed: 0, - functionsFailed: 0, - functionsDidNotRun: 0, - }, - ], - }; - } - public mergeTests(items: Tests[]): Tests { - return items.reduce((tests, otherTests, index) => { - if (index === 0) { - return tests; - } - - tests.summary.errors += otherTests.summary.errors; - tests.summary.failures += otherTests.summary.failures; - tests.summary.passed += otherTests.summary.passed; - tests.summary.skipped += otherTests.summary.skipped; - tests.rootTestFolders.push(...otherTests.rootTestFolders); - tests.testFiles.push(...otherTests.testFiles); - tests.testFolders.push(...otherTests.testFolders); - tests.testFunctions.push(...otherTests.testFunctions); - tests.testSuites.push(...otherTests.testSuites); - - return tests; - }, items[0]); - } - - public shouldRunAllTests(testsToRun?: TestsToRun) { - if (!testsToRun) { - return true; - } - if ( - (Array.isArray(testsToRun.testFile) && testsToRun.testFile.length > 0) || - (Array.isArray(testsToRun.testFolder) && testsToRun.testFolder.length > 0) || - (Array.isArray(testsToRun.testFunction) && testsToRun.testFunction.length > 0) || - (Array.isArray(testsToRun.testSuite) && testsToRun.testSuite.length > 0) - ) { - return false; - } - - return true; - } } export function getTestDataItemType(test: TestDataItem): TestDataItemType { diff --git a/src/client/testing/common/testVisitors/flatteningVisitor.ts b/src/client/testing/common/testVisitors/flatteningVisitor.ts deleted file mode 100644 index aa032b9a2a1c..000000000000 --- a/src/client/testing/common/testVisitors/flatteningVisitor.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { injectable } from 'inversify'; -import { convertFileToPackage } from '../testUtils'; -import { - FlattenedTestFunction, - FlattenedTestSuite, - ITestVisitor, - TestFile, - TestFolder, - TestFunction, - TestSuite, -} from '../types'; - -@injectable() -export class TestFlatteningVisitor implements ITestVisitor { - private _flattedTestFunctions = new Map(); - - private _flattenedTestSuites = new Map(); - public get flattenedTestFunctions(): FlattenedTestFunction[] { - return [...this._flattedTestFunctions.values()]; - } - public get flattenedTestSuites(): FlattenedTestSuite[] { - return [...this._flattenedTestSuites.values()]; - } - - public visitTestFunction(_testFunction: TestFunction): void {} - - public visitTestSuite(_testSuite: TestSuite): void {} - public visitTestFile(testFile: TestFile): void { - // sample test_three (file name without extension and all / replaced with ., meaning this is the package) - const packageName = convertFileToPackage(testFile.name); - - testFile.functions.forEach((fn) => this.addTestFunction(fn, testFile, packageName)); - testFile.suites.forEach((suite) => this.visitTestSuiteOfAFile(suite, testFile)); - } - - public visitTestFolder(_testFile: TestFolder) {} - private visitTestSuiteOfAFile(testSuite: TestSuite, parentTestFile: TestFile): void { - testSuite.functions.forEach((fn) => this.visitTestFunctionOfASuite(fn, testSuite, parentTestFile)); - testSuite.suites.forEach((suite) => this.visitTestSuiteOfAFile(suite, parentTestFile)); - this.addTestSuite(testSuite, parentTestFile); - } - private visitTestFunctionOfASuite( - testFunction: TestFunction, - parentTestSuite: TestSuite, - parentTestFile: TestFile, - ) { - const key = `Function:${testFunction.name},Suite:${parentTestSuite.name},SuiteXmlName:${parentTestSuite.xmlName},ParentFile:${parentTestFile.fullPath}`; - if (this._flattenedTestSuites.has(key)) { - return; - } - const flattenedFunction = { - testFunction, - xmlClassName: parentTestSuite.xmlName, - parentTestFile, - parentTestSuite, - }; - this._flattedTestFunctions.set(key, flattenedFunction); - } - private addTestSuite(testSuite: TestSuite, parentTestFile: TestFile) { - const key = `Suite:${testSuite.name},SuiteXmlName:${testSuite.xmlName},ParentFile:${parentTestFile.fullPath}`; - if (this._flattenedTestSuites.has(key)) { - return; - } - const flattenedSuite = { parentTestFile, testSuite, xmlClassName: testSuite.xmlName }; - this._flattenedTestSuites.set(key, flattenedSuite); - } - private addTestFunction(testFunction: TestFunction, parentTestFile: TestFile, parentTestPackage: string) { - const key = `Function:${testFunction.name},ParentFile:${parentTestFile.fullPath}`; - if (this._flattedTestFunctions.has(key)) { - return; - } - const flattendFunction = { testFunction, xmlClassName: parentTestPackage, parentTestFile }; - this._flattedTestFunctions.set(key, flattendFunction); - } -} diff --git a/src/client/testing/common/testVisitors/resultResetVisitor.ts b/src/client/testing/common/testVisitors/resultResetVisitor.ts deleted file mode 100644 index 5b4113bd43e5..000000000000 --- a/src/client/testing/common/testVisitors/resultResetVisitor.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { injectable } from 'inversify'; -import { ITestVisitor, TestFile, TestFolder, TestFunction, TestStatus, TestSuite } from '../types'; - -@injectable() -export class TestResultResetVisitor implements ITestVisitor { - public visitTestFunction(testFunction: TestFunction): void { - testFunction.passed = undefined; - testFunction.time = 0; - testFunction.message = ''; - testFunction.traceback = ''; - testFunction.status = TestStatus.Unknown; - testFunction.functionsFailed = 0; - testFunction.functionsPassed = 0; - testFunction.functionsDidNotRun = 0; - } - public visitTestSuite(testSuite: TestSuite): void { - testSuite.passed = undefined; - testSuite.time = 0; - testSuite.status = TestStatus.Unknown; - testSuite.functionsFailed = 0; - testSuite.functionsPassed = 0; - testSuite.functionsDidNotRun = 0; - } - public visitTestFile(testFile: TestFile): void { - testFile.passed = undefined; - testFile.time = 0; - testFile.status = TestStatus.Unknown; - testFile.functionsFailed = 0; - testFile.functionsPassed = 0; - testFile.functionsDidNotRun = 0; - } - public visitTestFolder(testFolder: TestFolder) { - testFolder.functionsDidNotRun = 0; - testFolder.functionsFailed = 0; - testFolder.functionsPassed = 0; - testFolder.passed = undefined; - testFolder.time = 0; - testFolder.status = TestStatus.Unknown; - } -} diff --git a/src/client/testing/common/testVisitors/visitor.ts b/src/client/testing/common/testVisitors/visitor.ts deleted file mode 100644 index 34ff2a3a0486..000000000000 --- a/src/client/testing/common/testVisitors/visitor.ts +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { getChildren } from '../testUtils'; -import { TestDataItem, Tests } from '../types'; - -type Visitor = (item: TestDataItem) => void; - -/** - * Visits tests recursively. - * - * @export - * @param {Tests} tests - * @param {Visitor} visitor - */ -export function visitRecursive(tests: Tests, visitor: Visitor): void; - -/** - * Vists tests recursively. - * - * @export - * @param {Tests} tests - * @param {TestDataItem} start - * @param {Visitor} visitor - */ -export function visitRecursive(tests: Tests, start: TestDataItem, visitor: Visitor): void; -export function visitRecursive(tests: Tests, arg1: TestDataItem | Visitor, arg2?: Visitor): void { - const startItem = typeof arg1 === 'function' ? undefined : arg1; - const visitor = startItem ? arg2! : (arg1 as Visitor); - let children: TestDataItem[] = []; - if (startItem) { - visitor(startItem); - children = getChildren(startItem); - } else { - children = tests.rootTestFolders; - } - children.forEach((folder) => visitRecursive(tests, folder, visitor)); -} diff --git a/src/client/testing/common/types.ts b/src/client/testing/common/types.ts index 0c5ede16b9e9..8bd58a1727fc 100644 --- a/src/client/testing/common/types.ts +++ b/src/client/testing/common/types.ts @@ -1,25 +1,18 @@ import { CancellationToken, DebugConfiguration, - DiagnosticCollection, DiagnosticSeverity, Disposable, - Event, Location, OutputChannel, - ProviderResult, - TextDocument, - TreeDataProvider, - TreeItem, Uri, WorkspaceFolder, } from 'vscode'; import { Product } from '../../common/types'; import { DebuggerTypeName } from '../../debugger/constants'; import { ConsoleType } from '../../debugger/types'; -import { TestProvider } from '../types'; import { TestSettingsPropertyNames } from '../configuration/types'; -import { CommandSource } from '../../common/constants'; +import { TestProvider } from '../types'; export type UnitTestProduct = Product.pytest | Product.unittest; @@ -285,42 +278,11 @@ export class TestWorkspaceFolder { // **************** // interfaces -export const ITestManagementService = Symbol('ITestManagementService'); -export interface ITestManagementService { - readonly onDidStatusChange: Event; - getTestManager(displayTestNotConfiguredMessage: boolean, resource?: Uri): Promise; - discoverTestsForDocument(doc: TextDocument): Promise; - autoDiscoverTests(resource: Uri | undefined): Promise; - discoverTests( - cmdSource: CommandSource, - resource?: Uri, - ignoreCache?: boolean, - userInitiated?: boolean, - quietMode?: boolean, - ): Promise; - stopTests(resource: Uri): Promise; - displayStopUI(message: string): Promise; - runTestsImpl( - cmdSource: CommandSource, - resource?: Uri, - testsToRun?: TestsToRun, - runFailedTests?: boolean, - debug?: boolean, - ): Promise; - runCurrentTestFile(cmdSource: CommandSource): Promise; -} - -export interface ITestManagerService extends Disposable { - getTestManager(): ITestManager | undefined; - getTestWorkingDirectory(): string; - getPreferredTestManager(): UnitTestProduct | undefined; -} - -export const IWorkspaceTestManagerService = Symbol('IWorkspaceTestManagerService'); -export interface IWorkspaceTestManagerService extends Disposable { - getTestManager(resource: Uri): ITestManager | undefined; - getTestWorkingDirectory(resource: Uri): string; - getPreferredTestManager(resource: Uri): UnitTestProduct | undefined; +export const ITestsHelper = Symbol('ITestsHelper'); +export interface ITestsHelper { + parseProviderName(product: UnitTestProduct): TestProvider; + parseProduct(provider: TestProvider): UnitTestProduct; + getSettingsPropertyNames(product: Product): TestSettingsPropertyNames; } export const ITestConfigurationService = Symbol('ITestConfigurationService'); @@ -350,107 +312,17 @@ export const ITestConfigurationManagerFactory = Symbol('ITestConfigurationManage export interface ITestConfigurationManagerFactory { create(wkspace: Uri, product: Product, cfg?: ITestConfigSettingsService): ITestConfigurationManager; } - -export const ITestManagerRunner = Symbol('ITestManagerRunner'); -export interface ITestManagerRunner { - runTest( - testResultsService: ITestResultsService, - options: TestRunOptions, - testManager: ITestManager, - ): Promise; -} - -export const IUnitTestHelper = Symbol('IUnitTestHelper'); -export interface IUnitTestHelper { - getStartDirectory(args: string[]): string; - getIdsOfTestsToRun(tests: Tests, testsToRun: TestsToRun): string[]; -} - -export const ITestsHelper = Symbol('ITestsHelper'); -export interface ITestsHelper { - parseProviderName(product: UnitTestProduct): TestProvider; - parseProduct(provider: TestProvider): UnitTestProduct; - getSettingsPropertyNames(product: Product): TestSettingsPropertyNames; - flattenTestFiles(testFiles: TestFile[], workspaceFolder: string): Tests; - placeTestFilesIntoFolders(tests: Tests, workspaceFolder: string): void; - shouldRunAllTests(testsToRun?: TestsToRun): boolean; - mergeTests(items: Tests[]): Tests; -} - -export const ITestVisitor = Symbol('ITestVisitor'); -export interface ITestVisitor { - visitTestFunction(testFunction: TestFunction): void; - visitTestSuite(testSuite: TestSuite): void; - visitTestFile(testFile: TestFile): void; - visitTestFolder(testFile: TestFolder): void; -} - -export const ITestCollectionStorageService = Symbol('ITestCollectionStorageService'); -export interface ITestCollectionStorageService extends Disposable { - onDidChange: Event<{ uri: Uri; data?: TestDataItem }>; - getTests(wkspace: Uri): Tests | undefined; - storeTests(wkspace: Uri, tests: Tests | null | undefined): void; - findFlattendTestFunction(resource: Uri, func: TestFunction): FlattenedTestFunction | undefined; - findFlattendTestSuite(resource: Uri, suite: TestSuite): FlattenedTestSuite | undefined; - update(resource: Uri, item: TestDataItem): void; -} - -export const ITestResultsService = Symbol('ITestResultsService'); -export interface ITestResultsService { - resetResults(tests: Tests): void; - updateResults(tests: Tests): void; -} - export const ITestDebugLauncher = Symbol('ITestDebugLauncher'); export interface ITestDebugLauncher { launchDebugger(options: LaunchOptions): Promise; } -export const ITestManagerFactory = Symbol('ITestManagerFactory'); -export interface ITestManagerFactory extends Function { - (testProvider: TestProvider, workspaceFolder: Uri, rootDirectory: string): ITestManager; -} - -export const ITestManagerServiceFactory = Symbol('TestManagerServiceFactory'); -export interface ITestManagerServiceFactory extends Function { - (workspaceFolder: Uri): ITestManagerService; -} - -export const ITestManager = Symbol('ITestManager'); -export interface ITestManager extends Disposable { - readonly status: TestStatus; - readonly enabled: boolean; - readonly workingDirectory: string; - readonly workspaceFolder: Uri; - diagnosticCollection: DiagnosticCollection; - readonly onDidStatusChange: Event; - stop(): void; - resetTestResults(): void; - discoverTests( - cmdSource: CommandSource, - ignoreCache?: boolean, - quietMode?: boolean, - userInitiated?: boolean, - clearTestStatus?: boolean, - ): Promise; - runTest( - cmdSource: CommandSource, - testsToRun?: TestsToRun, - runFailedTests?: boolean, - debug?: boolean, - ): Promise; -} export const ITestDiscoveryService = Symbol('ITestDiscoveryService'); export interface ITestDiscoveryService { discoverTests(options: TestDiscoveryOptions): Promise; } -export const ITestsParser = Symbol('ITestsParser'); -export interface ITestsParser { - parse(content: string, options: ParserOptions): Tests; -} - export const IUnitTestSocketServer = Symbol('IUnitTestSocketServer'); export interface IUnitTestSocketServer extends Disposable { // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -465,12 +337,6 @@ export interface ITestRunner { run(testProvider: TestProvider, options: Options): Promise; } -export const IXUnitParser = Symbol('IXUnitParser'); -export interface IXUnitParser { - // Update "tests" with the results parsed from the given file. - updateResultsFromXmlLogFile(tests: Tests, outputXmlFile: string): Promise; -} - export const ITestMessageService = Symbol('ITestMessageService'); export interface ITestMessageService { getFilteredTestMessages(rootDirectory: string, testResults: Tests): Promise; @@ -495,77 +361,8 @@ export interface ITestDebugConfig extends DebugConfiguration { subProcess?: boolean; } -export const ITestsStatusUpdaterService = Symbol('ITestsStatusUpdaterService'); -export interface ITestsStatusUpdaterService { - updateStatusAsDiscovering(resource: Uri, tests?: Tests): void; - updateStatusAsUnknown(resource: Uri, tests?: Tests): void; - updateStatusAsRunning(resource: Uri, tests?: Tests): void; - updateStatusAsRunningFailedTests(resource: Uri, tests?: Tests): void; - updateStatusAsRunningSpecificTests(resource: Uri, testsToRun: TestsToRun, tests?: Tests): void; - updateStatusOfRunningTestsAsIdle(resource: Uri, tests?: Tests): void; - triggerUpdatesToTests(resource: Uri, tests?: Tests): void; -} - export const ITestDiagnosticService = Symbol('ITestDiagnosticService'); export interface ITestDiagnosticService { getMessagePrefix(status: TestStatus): string; getSeverity(unitTestSeverity: PythonTestMessageSeverity): DiagnosticSeverity; } - -export const IArgumentsService = Symbol('IArgumentsService'); -export interface IArgumentsService { - getKnownOptions(): { withArgs: string[]; withoutArgs: string[] }; - getOptionValue(args: string[], option: string): string | string[] | undefined; - filterArguments(args: string[], argumentToRemove: string[]): string[]; - - filterArguments(args: string[], filter: TestFilter): string[]; - getTestFolders(args: string[]): string[]; -} - -export const IArgumentsHelper = Symbol('IArgumentsHelper'); -export interface IArgumentsHelper { - getOptionValues(args: string[], option: string): string | string[] | undefined; - filterArguments(args: string[], optionsWithArguments?: string[], optionsWithoutArguments?: string[]): string[]; - getPositionalArguments( - args: string[], - optionsWithArguments?: string[], - optionsWithoutArguments?: string[], - ): string[]; -} - -export const ITestResultDisplay = Symbol('ITestResultDisplay'); -export interface ITestResultDisplay extends Disposable { - enabled: boolean; - readonly onDidChange: Event; - displayProgressStatus(testRunResult: Promise, debug?: boolean): void; - displayDiscoverStatus(testDiscovery: Promise, quietMode?: boolean): Promise; -} - -export const ITestDisplay = Symbol('ITestDisplay'); -export interface ITestDisplay { - displayStopTestUI(workspace: Uri, message: string): void; - displayTestUI(cmdSource: CommandSource, wkspace: Uri): void; - selectTestFunction(rootDirectory: string, tests: Tests): Promise; - selectTestFile(rootDirectory: string, tests: Tests): Promise; - displayFunctionTestPickerUI( - cmdSource: CommandSource, - wkspace: Uri, - rootDirectory: string, - file: Uri, - testFunctions: TestFunction[], - debug?: boolean, - ): void; -} - -export const ITestTreeViewProvider = Symbol('ITestTreeViewProvider'); -export interface ITestTreeViewProvider extends TreeDataProvider { - onDidChangeTreeData: Event; - getTreeItem(element: TestDataItem): Promise; - getChildren(element?: TestDataItem): ProviderResult; - refresh(resource: Uri): void; -} - -export const ITestDataItemResource = Symbol('ITestDataItemResource'); -export interface ITestDataItemResource { - getResource(testData: Readonly): Uri; -} diff --git a/src/client/testing/common/xUnitParser.ts b/src/client/testing/common/xUnitParser.ts deleted file mode 100644 index 5f69b68dfe5c..000000000000 --- a/src/client/testing/common/xUnitParser.ts +++ /dev/null @@ -1,181 +0,0 @@ -import { inject, injectable } from 'inversify'; -import { IFileSystem } from '../../common/platform/types'; -import { FlattenedTestFunction, IXUnitParser, TestFunction, TestResult, Tests, TestStatus, TestSummary } from './types'; - -type TestSuiteResult = { - $: { - errors: string; - failures: string; - name: string; - skips: string; - skip: string; - tests: string; - time: string; - }; - testcase: TestCaseResult[]; -}; -type TestCaseResult = { - $: { - classname: string; - file: string; - line: string; - name: string; - time: string; - }; - failure: { - _: string; - $: { message: string; type: string }; - }[]; - error: { - _: string; - $: { message: string; type: string }; - }[]; - skipped: { - _: string; - $: { message: string; type: string }; - }[]; -}; - -function getSafeInt(value: string, defaultValue: any = 0): number { - const num = parseInt(value, 10); - if (isNaN(num)) { - return defaultValue; - } - return num; -} - -@injectable() -export class XUnitParser implements IXUnitParser { - constructor(@inject(IFileSystem) private readonly fs: IFileSystem) {} - - // Update "tests" with the results parsed from the given file. - public async updateResultsFromXmlLogFile(tests: Tests, outputXmlFile: string) { - const data = await this.fs.readFile(outputXmlFile); - - const parserResult = await parseXML(data); - const junitResults = getJunitResults(parserResult); - if (junitResults) { - updateTests(tests, junitResults); - } - } -} - -// An async wrapper around xml2js.parseString(). - -async function parseXML(data: string): Promise { - const xml2js = await import('xml2js'); - - return new Promise((resolve, reject) => { - xml2js.parseString(data, (error: Error, result: any) => { - if (error) { - return reject(error); - } - return resolve(result); - }); - }); -} - -// Return the actual test results from the given data. - -function getJunitResults(parserResult: any): TestSuiteResult | undefined { - // This is the newer JUnit XML format (e.g. pytest 5.1 and later). - const fullResults = parserResult as { testsuites: { testsuite: TestSuiteResult[] } }; - if (!fullResults.testsuites) { - return (parserResult as { testsuite: TestSuiteResult }).testsuite; - } - - const junitSuites = fullResults.testsuites.testsuite; - if (!Array.isArray(junitSuites)) { - throw Error('bad JUnit XML data'); - } - if (junitSuites.length === 0) { - return; - } - if (junitSuites.length > 1) { - throw Error('got multiple XML results'); - } - return junitSuites[0]; -} - -// Update "tests" with the given results. -function updateTests(tests: Tests, testSuiteResult: TestSuiteResult) { - updateSummary(tests.summary, testSuiteResult); - - if (!Array.isArray(testSuiteResult.testcase)) { - return; - } - - // Update the results for each test. - // Previously unknown tests are ignored. - testSuiteResult.testcase.forEach((testcase: TestCaseResult) => { - const testFunc = findTestFunction(tests.testFunctions, testcase.$.classname, testcase.$.name); - if (testFunc) { - updateResultInfo(testFunc, testcase); - updateResultStatus(testFunc, testcase); - } else { - // Possible we're dealing with nosetests, where the file name isn't returned to us - // When dealing with nose tests - // It is possible to have a test file named x in two separate test sub directories and have same functions/classes - // And unfortunately xunit log doesn't output the filename - - // result = tests.testFunctions.find(fn => fn.testFunction.name === testcase.$.name && - // fn.parentTestSuite && fn.parentTestSuite.name === testcase.$.classname); - - // Look for failed file test - const fileTest = testcase.$.file && tests.testFiles.find((file) => file.nameToRun === testcase.$.file); - if (fileTest && testcase.error) { - updateResultStatus(fileTest, testcase); - } - } - }); -} - -// Update the summary with the information in the given results. -function updateSummary(summary: TestSummary, testSuiteResult: TestSuiteResult) { - summary.errors = getSafeInt(testSuiteResult.$.errors); - summary.failures = getSafeInt(testSuiteResult.$.failures); - summary.skipped = getSafeInt(testSuiteResult.$.skips ? testSuiteResult.$.skips : testSuiteResult.$.skip); - const testCount = getSafeInt(testSuiteResult.$.tests); - summary.passed = testCount - summary.failures - summary.skipped - summary.errors; -} - -function findTestFunction( - candidates: FlattenedTestFunction[], - className: string, - funcName: string, -): TestFunction | undefined { - const xmlClassName = className.replace(/\(\)/g, '').replace(/\.\./g, '.').replace(/\.\./g, '.').replace(/\.+$/, ''); - const flattened = candidates.find((fn) => fn.xmlClassName === xmlClassName && fn.testFunction.name === funcName); - if (!flattened) { - return; - } - return flattened.testFunction; -} - -function updateResultInfo(result: TestResult, testCase: TestCaseResult) { - result.file = testCase.$.file; - result.line = getSafeInt(testCase.$.line, null); - result.time = parseFloat(testCase.$.time); -} - -function updateResultStatus(result: TestResult, testCase: TestCaseResult) { - if (testCase.error) { - result.status = TestStatus.Error; - result.passed = false; - result.message = testCase.error[0].$.message; - result.traceback = testCase.error[0]._; - } else if (testCase.failure) { - result.status = TestStatus.Fail; - result.passed = false; - result.message = testCase.failure[0].$.message; - result.traceback = testCase.failure[0]._; - } else if (testCase.skipped) { - result.status = TestStatus.Skipped; - result.passed = undefined; - result.message = testCase.skipped[0].$.message; - result.traceback = ''; - } else { - result.status = TestStatus.Pass; - result.passed = true; - } -} diff --git a/src/client/testing/configuration/index.ts b/src/client/testing/configuration/index.ts index ba9233549f70..b803bb106230 100644 --- a/src/client/testing/configuration/index.ts +++ b/src/client/testing/configuration/index.ts @@ -9,7 +9,7 @@ import { IServiceContainer } from '../../ioc/types'; import { sendTelemetryEvent } from '../../telemetry'; import { EventName } from '../../telemetry/constants'; import { TestConfiguringTelemetry } from '../../telemetry/types'; -import { BufferedTestConfigSettingsService } from '../common/services/configSettingService'; +import { BufferedTestConfigSettingsService } from '../common/bufferedTestConfigSettingService'; import { ITestConfigSettingsService, ITestConfigurationManager, diff --git a/src/client/testing/main.ts b/src/client/testing/main.ts index 047ed68f524c..8f0e4c7f20c6 100644 --- a/src/client/testing/main.ts +++ b/src/client/testing/main.ts @@ -4,41 +4,23 @@ import { inject, injectable } from 'inversify'; import { ConfigurationChangeEvent, Disposable, - Event, - EventEmitter, - OutputChannel, test, - TextDocument, Uri, } from 'vscode'; -import { IApplicationShell, ICommandManager, IDocumentManager, IWorkspaceService } from '../common/application/types'; +import { IApplicationShell, ICommandManager, IWorkspaceService } from '../common/application/types'; import * as constants from '../common/constants'; import '../common/extensions'; -import { traceError } from '../common/logger'; -import { IConfigurationService, IDisposableRegistry, IOutputChannel, Product, Resource } from '../common/types'; +import { IDisposableRegistry, Product } from '../common/types'; import { IInterpreterService } from '../interpreter/contracts'; import { IServiceContainer } from '../ioc/types'; import { EventName } from '../telemetry/constants'; -import { captureTelemetry, sendTelemetryEvent } from '../telemetry/index'; -import { CANCELLATION_REASON } from './common/constants'; +import { captureTelemetry } from '../telemetry/index'; import { selectTestWorkspace } from './common/testUtils'; import { TestSettingsPropertyNames } from './configuration/types'; import { - ITestCollectionStorageService, ITestConfigurationService, - ITestManagementService, - ITestManager, - IWorkspaceTestManagerService, - ITestDisplay, - TestFile, - TestFunction, - ITestResultDisplay, ITestsHelper, - TestStatus, - TestsToRun, - WorkspaceTestStatus, } from './common/types'; -import { TEST_OUTPUT_CHANNEL } from './constants'; import { ITestingService } from './types'; import { PythonTestController } from './testController/controller'; import { IExtensionActivationService } from '../activation/types'; @@ -54,93 +36,38 @@ export class TestingService implements ITestingService { } @injectable() -export class UnitTestManagementService implements ITestManagementService, IExtensionActivationService, Disposable { - private readonly outputChannel: OutputChannel; +export class UnitTestManagementService implements IExtensionActivationService, Disposable { private activatedOnce: boolean = false; private readonly disposableRegistry: Disposable[]; - private workspaceTestManagerService?: IWorkspaceTestManagerService; - private documentManager: IDocumentManager; private workspaceService: IWorkspaceService; - private testResultDisplay?: ITestResultDisplay; - private autoDiscoverTimer?: NodeJS.Timer | number; private configChangedTimer?: NodeJS.Timer | number; - private testManagers = new Set(); - private readonly _onDidStatusChange: EventEmitter = new EventEmitter(); constructor(@inject(IServiceContainer) private serviceContainer: IServiceContainer) { this.disposableRegistry = serviceContainer.get(IDisposableRegistry); - this.outputChannel = serviceContainer.get(IOutputChannel, TEST_OUTPUT_CHANNEL); this.workspaceService = serviceContainer.get(IWorkspaceService); - this.documentManager = serviceContainer.get(IDocumentManager); - this.disposableRegistry.push(this); } public dispose() { - if (this.workspaceTestManagerService) { - this.workspaceTestManagerService.dispose(); - } if (this.configChangedTimer) { clearTimeout(this.configChangedTimer as any); this.configChangedTimer = undefined; } - if (this.autoDiscoverTimer) { - clearTimeout(this.autoDiscoverTimer as any); - this.autoDiscoverTimer = undefined; - } - } - public get onDidStatusChange(): Event { - return this._onDidStatusChange.event; } + public async activate(): Promise { if (this.activatedOnce) { return; } this.activatedOnce = true; - this.workspaceTestManagerService = this.serviceContainer.get( - IWorkspaceTestManagerService, - ); this.registerHandlers(); this.registerCommands(); - this.autoDiscoverTests(undefined).catch((ex) => - traceError('Failed to auto discover tests upon activation', ex), - ); if (test && test.registerTestController) { this.disposableRegistry.push(test.registerTestController(new PythonTestController())); } } - public async getTestManager( - displayTestNotConfiguredMessage: boolean, - resource?: Uri, - ): Promise { - let wkspace: Uri | undefined; - if (resource) { - const wkspaceFolder = this.workspaceService.getWorkspaceFolder(resource); - wkspace = wkspaceFolder ? wkspaceFolder.uri : undefined; - } else { - const appShell = this.serviceContainer.get(IApplicationShell); - wkspace = await selectTestWorkspace(appShell); - } - if (!wkspace) { - return; - } - const testManager = this.workspaceTestManagerService!.getTestManager(wkspace); - if (testManager) { - if (!this.testManagers.has(testManager)) { - this.testManagers.add(testManager); - const handler = testManager.onDidStatusChange((e) => this._onDidStatusChange.fire(e)); - this.disposableRegistry.push(handler); - } - return testManager; - } - if (displayTestNotConfiguredMessage) { - const configurationService = this.serviceContainer.get( - ITestConfigurationService, - ); - await configurationService.displayTestFrameworkError(wkspace); - } - } + public async configurationChangeHandler(eventArgs: ConfigurationChangeEvent) { // If there's one workspace, then stop the tests and restart, // else let the user do this manually. @@ -156,178 +83,8 @@ export class UnitTestManagementService implements ITestManagementService, IExten if (!workspaceFolderUri) { return; } - const workspaceUri = workspaceFolderUri.uri; - const settings = this.serviceContainer - .get(IConfigurationService) - .getSettings(workspaceUri); - if (!settings.testing.pytestEnabled && !settings.testing.unittestEnabled) { - if (this.testResultDisplay) { - this.testResultDisplay.enabled = false; - } - // TODO: Why are we disposing, what happens when tests are enabled. - if (this.workspaceTestManagerService) { - this.workspaceTestManagerService.dispose(); - } - return; - } - if (this.testResultDisplay) { - this.testResultDisplay.enabled = true; - } - this.autoDiscoverTests(workspaceUri).catch((ex) => - traceError('Failed to auto discover tests upon activation', ex), - ); - } - - public async discoverTestsForDocument(doc: TextDocument): Promise { - const testManager = await this.getTestManager(false, doc.uri); - if (!testManager) { - return; - } - const tests = await testManager.discoverTests(constants.CommandSource.auto, false, true); - if (!tests || !Array.isArray(tests.testFiles) || tests.testFiles.length === 0) { - return; - } - if (tests.testFiles.findIndex((f: TestFile) => f.fullPath === doc.uri.fsPath) === -1) { - return; - } - - if (this.autoDiscoverTimer) { - clearTimeout(this.autoDiscoverTimer as any); - } - this.autoDiscoverTimer = setTimeout( - () => this.discoverTests(constants.CommandSource.auto, doc.uri, true, false, true), - 1000, - ); - } - public async autoDiscoverTests(resource: Resource) { - if (!this.workspaceService.hasWorkspaceFolders) { - return; - } - // Default to discovering tests in first folder if none specified. - if (!resource) { - resource = this.workspaceService.workspaceFolders![0].uri; - } - const configurationService = this.serviceContainer.get(IConfigurationService); - const settings = configurationService.getSettings(resource); - if (!settings.testing.pytestEnabled && !settings.testing.unittestEnabled) { - return; - } - - this.discoverTests(constants.CommandSource.auto, resource, true).ignoreErrors(); - } - public async discoverTests( - cmdSource: constants.CommandSource, - resource?: Uri, - ignoreCache?: boolean, - userInitiated?: boolean, - quietMode?: boolean, - clearTestStatus?: boolean, - ) { - const testManager = await this.getTestManager(true, resource); - if (!testManager) { - return; - } - - if (testManager.status === TestStatus.Discovering || testManager.status === TestStatus.Running) { - return; - } - - if (!this.testResultDisplay) { - this.testResultDisplay = this.serviceContainer.get(ITestResultDisplay); - } - const discoveryPromise = testManager.discoverTests( - cmdSource, - ignoreCache, - quietMode, - userInitiated, - clearTestStatus, - ); - this.testResultDisplay - .displayDiscoverStatus(discoveryPromise, quietMode) - .catch((ex) => traceError('Python Extension: displayDiscoverStatus', ex)); - await discoveryPromise; - } - public async stopTests(resource: Uri) { - sendTelemetryEvent(EventName.UNITTEST_STOP); - const testManager = await this.getTestManager(true, resource); - if (testManager) { - testManager.stop(); - } - } - public async displayStopUI(message: string): Promise { - const testManager = await this.getTestManager(true); - if (!testManager) { - return; - } - - const testDisplay = this.serviceContainer.get(ITestDisplay); - testDisplay.displayStopTestUI(testManager.workspaceFolder, message); - } - public async runParametrizedTests( - cmdSource: constants.CommandSource, - resource: Uri, - testFunctions: TestFunction[], - debug?: boolean, - ) { - const testManager = await this.getTestManager(true, resource); - if (!testManager) { - return; - } - await this.runTestsImpl(cmdSource, resource, { testFunction: testFunctions }, undefined, debug); - } - - public async runCurrentTestFile(cmdSource: CommandSource) { - if (!this.documentManager.activeTextEditor) { - return; - } - const testManager = await this.getTestManager(true, this.documentManager.activeTextEditor.document.uri); - if (!testManager) { - return; - } - try { - await testManager.discoverTests(cmdSource, true, true, true); - } catch (ex) { - return; - } - const testCollectionStorage = this.serviceContainer.get( - ITestCollectionStorageService, - ); - const tests = testCollectionStorage.getTests(testManager.workspaceFolder)!; - const testFiles = tests.testFiles.filter((testFile) => { - return testFile.fullPath === this.documentManager.activeTextEditor!.document.uri.fsPath; - }); - if (testFiles.length < 1) { - return; - } - await this.runTestsImpl(cmdSource, testManager.workspaceFolder, { testFile: [testFiles[0]] }); - } - - public async runTestsImpl( - cmdSource: constants.CommandSource, - resource?: Uri, - testsToRun?: TestsToRun, - runFailedTests?: boolean, - debug: boolean = false, - ) { - const testManager = await this.getTestManager(true, resource); - if (!testManager) { - return; - } - - if (!this.testResultDisplay) { - this.testResultDisplay = this.serviceContainer.get(ITestResultDisplay); - } - - const promise = testManager.runTest(cmdSource, testsToRun, runFailedTests, debug).catch((reason) => { - if (reason !== CANCELLATION_REASON) { - this.outputChannel.appendLine(`Error: ${reason}`); - } - return Promise.reject(reason); - }); - - this.testResultDisplay.displayProgressStatus(promise, debug); - await promise; + // TODO: refresh test data } @captureTelemetry(EventName.UNITTEST_CONFIGURE, undefined, false) @@ -352,30 +109,23 @@ export class UnitTestManagementService implements ITestManagementService, IExten const commandManager = this.serviceContainer.get(ICommandManager); const disposables = [ + // TODO: register command to refresh test data commandManager.registerCommand( constants.Commands.Tests_Configure, (_, _cmdSource: constants.CommandSource = constants.CommandSource.commandPalette, resource?: Uri) => { // Ignore the exceptions returned. // This command will be invoked from other places of the extension. this.configureTests(resource).ignoreErrors(); + // TODO: refresh test data }, ), ]; disposablesRegistry.push(...disposables); } - public onDocumentSaved(doc: TextDocument) { - const settings = this.serviceContainer.get(IConfigurationService).getSettings(doc.uri); - if (!settings.testing.autoTestDiscoverOnSaveEnabled) { - return; - } - this.discoverTestsForDocument(doc).ignoreErrors(); - } + public registerHandlers() { - const documentManager = this.serviceContainer.get(IDocumentManager); const interpreterService = this.serviceContainer.get(IInterpreterService); - - this.disposableRegistry.push(documentManager.onDidSaveTextDocument(this.onDocumentSaved.bind(this))); this.disposableRegistry.push( this.workspaceService.onDidChangeConfiguration((e) => { if (this.configChangedTimer) { @@ -386,9 +136,9 @@ export class UnitTestManagementService implements ITestManagementService, IExten ); this.disposableRegistry.push( interpreterService.onDidChangeInterpreter(() => - this.autoDiscoverTests(undefined).catch((ex) => - traceError('Failed to auto discover tests upon changing interpreter', ex), - ), + { + // TODO: Refresh test data + } ), ); } diff --git a/src/client/testing/navigation/symbolProvider.ts b/src/client/testing/navigation/symbolProvider.ts deleted file mode 100644 index d73570533c62..000000000000 --- a/src/client/testing/navigation/symbolProvider.ts +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { inject, injectable } from 'inversify'; -import { - CancellationToken, - DocumentSymbolProvider, - Location, - Range, - SymbolInformation, - SymbolKind, - TextDocument, - Uri, -} from 'vscode'; -import { traceError } from '../../common/logger'; -import * as internalScripts from '../../common/process/internal/scripts'; -import { IPythonExecutionFactory } from '../../common/process/types'; - -type RawSymbol = { namespace: string; name: string; range: Range }; -type Symbols = { - classes: RawSymbol[]; - methods: RawSymbol[]; - functions: RawSymbol[]; -}; - -@injectable() -export class TestFileSymbolProvider implements DocumentSymbolProvider { - constructor(@inject(IPythonExecutionFactory) private readonly pythonServiceFactory: IPythonExecutionFactory) {} - public async provideDocumentSymbols( - document: TextDocument, - token: CancellationToken, - ): Promise { - const rawSymbols = await this.getSymbols(document, token); - if (!rawSymbols) { - return []; - } - return [ - ...rawSymbols.classes.map((item) => this.parseRawSymbol(document.uri, item, SymbolKind.Class)), - ...rawSymbols.methods.map((item) => this.parseRawSymbol(document.uri, item, SymbolKind.Method)), - ...rawSymbols.functions.map((item) => this.parseRawSymbol(document.uri, item, SymbolKind.Function)), - ]; - } - private parseRawSymbol(uri: Uri, symbol: RawSymbol, kind: SymbolKind): SymbolInformation { - const range = new Range( - symbol.range.start.line, - symbol.range.start.character, - symbol.range.end.line, - symbol.range.end.character, - ); - return { - containerName: symbol.namespace, - kind, - name: symbol.name, - location: new Location(uri, range), - }; - } - private async getSymbols(document: TextDocument, token: CancellationToken): Promise { - try { - if (document.isUntitled) { - return; - } - const [args, parse] = internalScripts.symbolProvider( - document.uri.fsPath, - document.isDirty ? document.getText() : undefined, - ); - const pythonService = await this.pythonServiceFactory.create({ resource: document.uri }); - const proc = await pythonService.exec(args, { throwOnStdErr: true, token }); - - return (parse(proc.stdout) as unknown) as Symbols; - } catch (ex) { - traceError('Python: Failed to get symbols', ex); - return; - } - } -} diff --git a/src/client/testing/pytest/main.ts b/src/client/testing/pytest/main.ts deleted file mode 100644 index 438c38ee4551..000000000000 --- a/src/client/testing/pytest/main.ts +++ /dev/null @@ -1,99 +0,0 @@ -'use strict'; - -import { Uri } from 'vscode'; -import { Product } from '../../common/types'; -import { IServiceContainer } from '../../ioc/types'; -import { PYTEST_PROVIDER } from '../common/constants'; -import { BaseTestManager } from '../common/managers/baseTestManager'; -import { - IArgumentsService, - IPythonTestMessage, - ITestManagerRunner, - ITestMessageService, - ITestsHelper, - TestDiscoveryOptions, - TestFilter, - TestRunOptions, - Tests, - TestsToRun, -} from '../common/types'; - -export class TestManager extends BaseTestManager { - private readonly argsService: IArgumentsService; - - private readonly helper: ITestsHelper; - - private readonly runner: ITestManagerRunner; - - private readonly testMessageService: ITestMessageService; - - public get enabled(): boolean { - return this.settings.testing.pytestEnabled; - } - - constructor(workspaceFolder: Uri, rootDirectory: string, serviceContainer: IServiceContainer) { - super(PYTEST_PROVIDER, Product.pytest, workspaceFolder, rootDirectory, serviceContainer); - this.argsService = this.serviceContainer.get(IArgumentsService, this.testProvider); - this.helper = this.serviceContainer.get(ITestsHelper); - this.runner = this.serviceContainer.get(ITestManagerRunner, this.testProvider); - this.testMessageService = this.serviceContainer.get( - ITestMessageService, - this.testProvider, - ); - } - - public getDiscoveryOptions(ignoreCache: boolean): TestDiscoveryOptions { - const args = this.settings.testing.pytestArgs.slice(0); - return { - workspaceFolder: this.workspaceFolder, - cwd: this.rootDirectory, - args, - token: this.testDiscoveryCancellationToken!, - ignoreCache, - outChannel: this.outputChannel, - }; - } - - public async runTestImpl( - tests: Tests, - testsToRun?: TestsToRun, - runFailedTests?: boolean, - debug?: boolean, - ): Promise { - let args: string[]; - - const runAllTests = this.helper.shouldRunAllTests(testsToRun); - if (debug) { - args = this.argsService.filterArguments( - this.settings.testing.pytestArgs, - runAllTests ? TestFilter.debugAll : TestFilter.debugSpecific, - ); - } else { - args = this.argsService.filterArguments( - this.settings.testing.pytestArgs, - runAllTests ? TestFilter.runAll : TestFilter.runSpecific, - ); - } - - if (runFailedTests === true && args.indexOf('--lf') === -1 && args.indexOf('--last-failed') === -1) { - args.splice(0, 0, '--last-failed'); - } - const options: TestRunOptions = { - workspaceFolder: this.workspaceFolder, - cwd: this.rootDirectory, - tests, - args, - testsToRun, - debug, - token: this.testRunnerCancellationToken!, - outChannel: this.outputChannel, - }; - const testResults = await this.runner.runTest(this.testResultsService, options, this); - const messages: IPythonTestMessage[] = await this.testMessageService.getFilteredTestMessages( - this.rootDirectory, - testResults, - ); - await this.updateDiagnostics(tests, messages); - return testResults; - } -} diff --git a/src/client/testing/pytest/runner.ts b/src/client/testing/pytest/runner.ts deleted file mode 100644 index e200de426bf6..000000000000 --- a/src/client/testing/pytest/runner.ts +++ /dev/null @@ -1,127 +0,0 @@ -'use strict'; - -import { inject, injectable } from 'inversify'; -import { IFileSystem, TemporaryFile } from '../../common/platform/types'; -import { noop } from '../../common/utils/misc'; -import { IServiceContainer } from '../../ioc/types'; -import { PYTEST_PROVIDER } from '../common/constants'; -import { Options } from '../common/runner'; -import { - IArgumentsHelper, - IArgumentsService, - ITestDebugLauncher, - ITestManagerRunner, - ITestResultsService, - ITestRunner, - IXUnitParser, - LaunchOptions, - TestRunOptions, - Tests, -} from '../common/types'; - -const JunitXmlArgOld = '--junitxml'; -const JunitXmlArg = '--junit-xml'; -@injectable() -export class TestManagerRunner implements ITestManagerRunner { - private readonly argsService: IArgumentsService; - - private readonly argsHelper: IArgumentsHelper; - - private readonly testRunner: ITestRunner; - - private readonly xUnitParser: IXUnitParser; - - private readonly fs: IFileSystem; - - constructor(@inject(IServiceContainer) private serviceContainer: IServiceContainer) { - this.argsService = serviceContainer.get(IArgumentsService, PYTEST_PROVIDER); - this.argsHelper = serviceContainer.get(IArgumentsHelper); - this.testRunner = serviceContainer.get(ITestRunner); - this.xUnitParser = this.serviceContainer.get(IXUnitParser); - this.fs = this.serviceContainer.get(IFileSystem); - } - - public async runTest( - testResultsService: ITestResultsService, - options: TestRunOptions, - // We ignore the ITestManager arg, - ): Promise { - let testPaths: string[] = []; - if (options.testsToRun && options.testsToRun.testFolder) { - testPaths = testPaths.concat(options.testsToRun.testFolder.map((f) => f.nameToRun)); - } - if (options.testsToRun && options.testsToRun.testFile) { - testPaths = testPaths.concat(options.testsToRun.testFile.map((f) => f.nameToRun)); - } - if (options.testsToRun && options.testsToRun.testSuite) { - testPaths = testPaths.concat(options.testsToRun.testSuite.map((f) => f.nameToRun)); - } - if (options.testsToRun && options.testsToRun.testFunction) { - testPaths = testPaths.concat(options.testsToRun.testFunction.map((f) => f.nameToRun)); - } - - let deleteJUnitXmlFile: () => void = noop; - const { args } = options; - try { - const xmlLogResult = await this.getJUnitXmlFile(args); - const xmlLogFile = xmlLogResult.filePath; - deleteJUnitXmlFile = xmlLogResult.dispose; - // Remove the '--junitxml' or '--junit-xml' if it exists, and add it with our path. - const testArgs = this.argsService.filterArguments(args, [JunitXmlArg, JunitXmlArgOld]); - testArgs.splice(0, 0, `${JunitXmlArg}=${xmlLogFile}`); - - testArgs.splice(0, 0, '--rootdir', options.workspaceFolder.fsPath); - testArgs.splice(0, 0, '--override-ini', 'junit_family=xunit1'); - - // Positional arguments control the tests to be run. - testArgs.push(...testPaths); - - if (options.debug) { - const debugLauncher = this.serviceContainer.get(ITestDebugLauncher); - const debuggerArgs = [options.cwd, 'pytest'].concat(testArgs); - const launchOptions: LaunchOptions = { - cwd: options.cwd, - args: debuggerArgs, - token: options.token, - outChannel: options.outChannel, - testProvider: PYTEST_PROVIDER, - }; - await debugLauncher.launchDebugger(launchOptions); - } else { - const runOptions: Options = { - args: testArgs, - cwd: options.cwd, - outChannel: options.outChannel, - token: options.token, - workspaceFolder: options.workspaceFolder, - }; - await this.testRunner.run(PYTEST_PROVIDER, runOptions); - } - - // Promise must resolve before return as result file will be deleted in finally block. - return await this.updateResultsFromLogFiles(options.tests, xmlLogFile, testResultsService); - } catch (ex) { - return Promise.reject(ex); - } finally { - deleteJUnitXmlFile(); - } - } - - private async updateResultsFromLogFiles( - tests: Tests, - outputXmlFile: string, - testResultsService: ITestResultsService, - ): Promise { - await this.xUnitParser.updateResultsFromXmlLogFile(tests, outputXmlFile); - testResultsService.updateResults(tests); - return tests; - } - - private async getJUnitXmlFile(args: string[]): Promise { - const xmlFile = this.argsHelper.getOptionValues(args, JunitXmlArg); - if (typeof xmlFile === 'string') { - return { filePath: xmlFile, dispose: noop }; - } - return this.fs.createTemporaryFile('.xml'); - } -} diff --git a/src/client/testing/pytest/services/argsService.ts b/src/client/testing/pytest/services/argsService.ts deleted file mode 100644 index aae49625f3f9..000000000000 --- a/src/client/testing/pytest/services/argsService.ts +++ /dev/null @@ -1,296 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { inject, injectable } from 'inversify'; -import { IServiceContainer } from '../../../ioc/types'; -import { IArgumentsHelper, IArgumentsService, TestFilter } from '../../common/types'; - -const OptionsWithArguments = [ - '-c', - '-k', - '-m', - '-o', - '-p', - '-r', - '-W', - '-n', // -n is a pytest-xdist option - '--assert', - '--basetemp', - '--cache-show', - '--capture', - '--code-highlight', - '--color', - '--confcutdir', - '--cov', - '--cov-config', - '--cov-fail-under', - '--cov-report', - '--deselect', - '--dist', - '--doctest-glob', - '--doctest-report', - '--durations', - '--durations-min', - '--ignore', - '--ignore-glob', - '--import-mode', - '--junit-prefix', - '--junit-xml', - '--last-failed-no-failures', - '--lfnf', - '--log-auto-indent', - '--log-cli-date-format', - '--log-cli-format', - '--log-cli-level', - '--log-date-format', - '--log-file', - '--log-file-date-format', - '--log-file-format', - '--log-file-level', - '--log-format', - '--log-level', - '--maxfail', - '--override-ini', - '--pastebin', - '--pdbcls', - '--pythonwarnings', - '--result-log', - '--rootdir', - '--show-capture', - '--tb', - '--verbosity', - '--max-slave-restart', - '--numprocesses', - '--rsyncdir', - '--rsyncignore', - '--tx', -]; - -const OptionsWithoutArguments = [ - '--cache-clear', - '--collect-in-virtualenv', - '--collect-only', - '--co', - '--continue-on-collection-errors', - '--cov-append', - '--cov-branch', - '--debug', - '--disable-pytest-warnings', - '--disable-warnings', - '--doctest-continue-on-failure', - '--doctest-ignore-import-errors', - '--doctest-modules', - '--exitfirst', - '--failed-first', - '--ff', - '--fixtures', - '--fixtures-per-test', - '--force-sugar', - '--full-trace', - '--funcargs', - '--help', - '--keep-duplicates', - '--last-failed', - '--lf', - '--markers', - '--new-first', - '--nf', - '--no-cov', - '--no-cov-on-fail', - '--no-header', - '--no-print-logs', - '--no-summary', - '--noconftest', - '--old-summary', - '--pdb', - '--pyargs', - '-PyTest, Unittest-pyargs', - '--quiet', - '--runxfail', - '--setup-only', - '--setup-plan', - '--setup-show', - '--showlocals', - '--stepwise', - '--sw', - '--stepwise-skip', - '--strict', - '--strict-config', - '--strict-markers', - '--trace-config', - '--verbose', - '--version', - '-V', - '-h', - '-l', - '-q', - '-s', - '-v', - '-x', - '--boxed', - '--forked', - '--looponfail', - '--trace', - '--tx', - '-d', -]; - -function getKnownOptions(): { withArgs: string[]; withoutArgs: string[] } { - return { - withArgs: OptionsWithArguments, - withoutArgs: OptionsWithoutArguments, - }; -} - -@injectable() -export class ArgumentsService implements IArgumentsService { - public readonly getKnownOptions = getKnownOptions; - - private readonly helper: IArgumentsHelper; - - constructor(@inject(IServiceContainer) serviceContainer: IServiceContainer) { - this.helper = serviceContainer.get(IArgumentsHelper); - } - - public getOptionValue(args: string[], option: string): string | string[] | undefined { - return this.helper.getOptionValues(args, option); - } - - public filterArguments(args: string[], argumentToRemoveOrFilter: string[] | TestFilter): string[] { - const optionsWithoutArgsToRemove: string[] = []; - const optionsWithArgsToRemove: string[] = []; - // Positional arguments in pytest are test directories and files. - // So if we want to run a specific test, then remove positional args. - let removePositionalArgs = false; - if (Array.isArray(argumentToRemoveOrFilter)) { - argumentToRemoveOrFilter.forEach((item) => { - if (OptionsWithArguments.indexOf(item) >= 0) { - optionsWithArgsToRemove.push(item); - } - if (OptionsWithoutArguments.indexOf(item) >= 0) { - optionsWithoutArgsToRemove.push(item); - } - }); - } else { - switch (argumentToRemoveOrFilter) { - case TestFilter.removeTests: { - optionsWithoutArgsToRemove.push( - ...['--lf', '--last-failed', '--ff', '--failed-first', '--nf', '--new-first'], - ); - optionsWithArgsToRemove.push(...['-k', '-m', '--lfnf', '--last-failed-no-failures']); - removePositionalArgs = true; - break; - } - case TestFilter.discovery: { - optionsWithoutArgsToRemove.push( - ...[ - '-x', - '--exitfirst', - '--fixtures', - '--funcargs', - '--fixtures-per-test', - '--pdb', - '--lf', - '--last-failed', - '--ff', - '--failed-first', - '--nf', - '--new-first', - '--cache-show', - '-v', - '--verbose', - '-q', - '-quiet', - '-l', - '--showlocals', - '--no-print-logs', - '--debug', - '--setup-only', - '--setup-show', - '--setup-plan', - '--trace', - ], - ); - optionsWithArgsToRemove.push( - ...[ - '-m', - '--maxfail', - '--pdbcls', - '--capture', - '--lfnf', - '--last-failed-no-failures', - '--verbosity', - '-r', - '--tb', - '--rootdir', - '--show-capture', - '--durations', - '--junit-xml', - '--junit-prefix', - '--result-log', - '-W', - '--pythonwarnings', - '--log-*', - ], - ); - removePositionalArgs = true; - break; - } - case TestFilter.debugAll: - case TestFilter.runAll: { - optionsWithoutArgsToRemove.push(...['--collect-only', '--trace']); - break; - } - case TestFilter.debugSpecific: - case TestFilter.runSpecific: { - optionsWithoutArgsToRemove.push( - ...[ - '--collect-only', - '--lf', - '--last-failed', - '--ff', - '--failed-first', - '--nf', - '--new-first', - '--trace', - ], - ); - optionsWithArgsToRemove.push(...['-k', '-m', '--lfnf', '--last-failed-no-failures']); - removePositionalArgs = true; - break; - } - default: { - throw new Error(`Unsupported Filter '${argumentToRemoveOrFilter}'`); - } - } - } - - let filteredArgs = args.slice(); - if (removePositionalArgs) { - const positionalArgs = this.helper.getPositionalArguments( - filteredArgs, - OptionsWithArguments, - OptionsWithoutArguments, - ); - filteredArgs = filteredArgs.filter((item) => positionalArgs.indexOf(item) === -1); - } - return this.helper.filterArguments(filteredArgs, optionsWithArgsToRemove, optionsWithoutArgsToRemove); - } - - public getTestFolders(args: string[]): string[] { - const testDirs = this.helper.getOptionValues(args, '--rootdir'); - if (typeof testDirs === 'string') { - return [testDirs]; - } - if (Array.isArray(testDirs) && testDirs.length > 0) { - return testDirs; - } - const positionalArgs = this.helper.getPositionalArguments(args, OptionsWithArguments, OptionsWithoutArguments); - // Positional args in pytest are files or directories. - // Remove files from the args, and what's left are test directories. - // If users enter test modules/methods, then its not supported. - return positionalArgs.filter((arg) => !arg.toUpperCase().endsWith('.PY')); - } -} diff --git a/src/client/testing/pytest/services/discoveryService.ts b/src/client/testing/pytest/services/discoveryService.ts deleted file mode 100644 index 0335a773023d..000000000000 --- a/src/client/testing/pytest/services/discoveryService.ts +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -import { inject, injectable } from 'inversify'; -import { CancellationTokenSource } from 'vscode'; -import { IServiceContainer } from '../../../ioc/types'; -import { PYTEST_PROVIDER } from '../../common/constants'; -import { - IArgumentsService, - ITestDiscoveryService, - ITestsHelper, - TestDiscoveryOptions, - TestFilter, - Tests, -} from '../../common/types'; - -@injectable() -export class TestDiscoveryService implements ITestDiscoveryService { - private argsService: IArgumentsService; - - private helper: ITestsHelper; - - constructor(@inject(IServiceContainer) private serviceContainer: IServiceContainer) { - this.argsService = this.serviceContainer.get(IArgumentsService, PYTEST_PROVIDER); - this.helper = this.serviceContainer.get(ITestsHelper); - } - - public async discoverTests(options: TestDiscoveryOptions): Promise { - const args = this.buildTestCollectionArgs(options); - - // Collect tests for each test directory separately and merge. - const testDirectories = this.argsService.getTestFolders(options.args); - if (testDirectories.length === 0) { - const opts = { - ...options, - args, - }; - return this.discoverTestsInTestDirectory(opts); - } - const results = await Promise.all( - testDirectories.map((testDir) => { - // Add test directory as a positional argument. - const opts = { - ...options, - args: [...args, testDir], - }; - return this.discoverTestsInTestDirectory(opts); - }), - ); - - return this.helper.mergeTests(results); - } - - protected buildTestCollectionArgs(options: TestDiscoveryOptions): string[] { - // Remove unwnted arguments (which happen to be test directories & test specific args). - const args = this.argsService.filterArguments(options.args, TestFilter.discovery); - if (options.ignoreCache && args.indexOf('--cache-clear') === -1) { - args.splice(0, 0, '--cache-clear'); - } - if (args.indexOf('-s') === -1) { - args.splice(0, 0, '-s'); - } - args.splice(0, 0, '--rootdir', options.workspaceFolder.fsPath); - return args; - } - - protected async discoverTestsInTestDirectory(options: TestDiscoveryOptions): Promise { - const token = options.token ? options.token : new CancellationTokenSource().token; - const discoveryOptions = { ...options }; - discoveryOptions.args = ['discover', 'pytest', '--', ...options.args]; - discoveryOptions.token = token; - - const discoveryService = this.serviceContainer.get(ITestDiscoveryService, 'common'); - if (discoveryOptions.token && discoveryOptions.token.isCancellationRequested) { - return Promise.reject(new Error('cancelled')); - } - - return discoveryService.discoverTests(discoveryOptions); - } -} diff --git a/src/client/testing/pytest/services/testMessageService.ts b/src/client/testing/pytest/services/testMessageService.ts deleted file mode 100644 index fe824d80ec91..000000000000 --- a/src/client/testing/pytest/services/testMessageService.ts +++ /dev/null @@ -1,292 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { inject, injectable } from 'inversify'; -import * as path from 'path'; -import { Location, Position, Range, TextLine, Uri, workspace } from 'vscode'; -import '../../../common/extensions'; -import { ProductNames } from '../../../common/installer/productNames'; -import { IFileSystem } from '../../../common/platform/types'; -import { Product } from '../../../common/types'; -import { IServiceContainer } from '../../../ioc/types'; -import { - FlattenedTestFunction, - isNonPassingTestStatus, - ILocationStackFrameDetails, - IPythonTestMessage, - ITestMessageService, - ITestNonPassingMessage, - ITestPassingMessage, - NonPassingTestStatus, - PythonTestMessageSeverity, - Tests, - TestStatus, -} from '../../common/types'; - -@injectable() -export class TestMessageService implements ITestMessageService { - constructor(@inject(IServiceContainer) private serviceContainer: IServiceContainer) {} - - /** - * Condense the test details down to just the potentially relevant information. Messages - * should only be created for tests that were actually run. - * - * @param rootDirectory - * @param testResults Details about all known tests. - */ - public async getFilteredTestMessages(rootDirectory: string, testResults: Tests): Promise { - const testFuncs = testResults.testFunctions.reduce((filtered, test) => { - if (test.testFunction.passed !== undefined || test.testFunction.status === TestStatus.Skipped) { - filtered.push(test); - } - return filtered; - }, []); - const messages: IPythonTestMessage[] = []; - for (const tf of testFuncs) { - const { nameToRun } = tf.testFunction; - const provider = ProductNames.get(Product.pytest)!; - const status = tf.testFunction.status!; - if (status === TestStatus.Pass) { - // If the test passed, there's not much to do with it. - const msg: ITestPassingMessage = { - code: nameToRun, - severity: PythonTestMessageSeverity.Pass, - provider, - testTime: tf.testFunction.time, - status, - testFilePath: tf.parentTestFile.fullPath, - }; - messages.push(msg); - } else if (isNonPassingTestStatus(status)) { - // If the test did not pass, we need to parse the traceback to find each line in - // their respective files so they can be included as related information for the - // diagnostic. - const locationStack = await this.getLocationStack(rootDirectory, tf); - const { message } = tf.testFunction; - const testFilePath = tf.parentTestFile.fullPath; - let severity = PythonTestMessageSeverity.Error; - if (tf.testFunction.status === TestStatus.Skipped) { - severity = PythonTestMessageSeverity.Skip; - } - - const msg: ITestNonPassingMessage = { - code: nameToRun, - message, - severity, - provider, - traceback: tf.testFunction.traceback, - testTime: tf.testFunction.time, - testFilePath, - status: status as NonPassingTestStatus, - locationStack, - }; - messages.push(msg); - } - // All test results with a non-final status are ignored. - } - return messages; - } - - /** - * Given a FlattenedTestFunction, parse its traceback to piece together where each line in the - * traceback was in its respective file and grab the entire text of each line so they can be - * included in the Diagnostic as related information. - * - * @param testFunction The FlattenedTestFunction with the traceback that we need to parse. - */ - private async getLocationStack( - rootDirectory: string, - testFunction: FlattenedTestFunction, - ): Promise { - const locationStack: ILocationStackFrameDetails[] = []; - if (testFunction.testFunction.traceback) { - const fileMatches = - testFunction.testFunction.traceback.match(/^((\.\.[\\\/])*.+\.py)\:(\d+)\:.*$/gim) || []; - for (const fileDetailsMatch of fileMatches) { - const fileDetails = fileDetailsMatch.split(':'); - let filePath = fileDetails[0]; - filePath = path.isAbsolute(filePath) ? filePath : path.resolve(rootDirectory, filePath); - const fileUri = Uri.file(filePath); - const file = await workspace.openTextDocument(fileUri); - const fileLineNum = parseInt(fileDetails[1], 10); - const line = file.lineAt(fileLineNum - 1); - const location = new Location( - fileUri, - new Range( - new Position(fileLineNum - 1, line.firstNonWhitespaceCharacterIndex), - new Position(fileLineNum - 1, line.text.length), - ), - ); - const stackFrame: ILocationStackFrameDetails = { - location, - lineText: file.getText(location.range), - }; - locationStack.push(stackFrame); - } - } - // Find where the file the test was defined. - let testSourceFilePath = testFunction.testFunction.file!; - testSourceFilePath = path.isAbsolute(testSourceFilePath) - ? testSourceFilePath - : path.resolve(rootDirectory, testSourceFilePath); - const testSourceFileUri = Uri.file(testSourceFilePath); - const testSourceFile = await workspace.openTextDocument(testSourceFileUri); - let testDefLine: TextLine | null = null; - let lineNum = testFunction.testFunction.line!; - let lineText = ''; - let trimmedLineText = ''; - const testDefPrefix = 'def '; - const testAsyncDefPrefix = 'async def '; - let prefix = ''; - - while (testDefLine === null) { - const possibleTestDefLine = testSourceFile.lineAt(lineNum); - lineText = possibleTestDefLine.text; - trimmedLineText = lineText.trimLeft()!; - if (trimmedLineText.toLowerCase().startsWith(testDefPrefix)) { - testDefLine = possibleTestDefLine; - prefix = testDefPrefix; - } else if (trimmedLineText.toLowerCase().startsWith(testAsyncDefPrefix)) { - testDefLine = possibleTestDefLine; - prefix = testAsyncDefPrefix; - } else { - // The test definition may have been decorated, and there may be multiple - // decorations, so move to the next line and check it. - lineNum += 1; - } - } - const matches = trimmedLineText!.slice(prefix.length).match(/[^ \(:]+/); - const testSimpleName = matches ? matches[0] : ''; - const testDefStartCharNum = lineText.length - trimmedLineText.length + prefix.length; - const testDefEndCharNum = testDefStartCharNum + testSimpleName.length; - const lineStart = new Position(testDefLine!.lineNumber, testDefStartCharNum); - const lineEnd = new Position(testDefLine!.lineNumber, testDefEndCharNum); - const lineRange = new Range(lineStart, lineEnd); - const testDefLocation = new Location(testSourceFileUri, lineRange); - const testSourceLocationDetails = { location: testDefLocation, lineText: testSourceFile.getText(lineRange) }; - locationStack.unshift(testSourceLocationDetails); - - // Put the class declaration at the top of the stack if the test was imported. - if (testFunction.parentTestSuite !== undefined) { - // This could be an imported test method - const fs = this.serviceContainer.get(IFileSystem); - if ( - !fs.arePathsSame( - Uri.file(testFunction.parentTestFile.fullPath).fsPath, - locationStack[0].location.uri.fsPath, - ) - ) { - // test method was imported, so reference class declaration line. - // this should be the first thing in the stack to show where the failure/error originated. - locationStack.unshift(await getParentSuiteLocation(testFunction)); - } - } - return locationStack; - } -} - -/** - * The test that's associated with the FlattenedtestFunction was imported from another file, as the file - * location found in the traceback that shows what file the test was actually defined in is different than - * the file that the test was executed in. This must also mean that the test was part of a class that was - * imported and then inherited by the class that was actually run in the file. - * - * Test classes can be defined inside of other test classes, and even nested test classes of those that were - * imported will be discovered and ran. Luckily, for pytest, the entire chain of classes is preserved in the - * test's ID. However, in order to keep the Diagnostic as relevant as possible, it should point only at the - * most-nested test class that exists in the file that the test was actually run in, in order to provide the - * most context. This method attempts to go as far down the chain as it can, and resolves to the - * LocationStackFrameDetails for that test class. - * - * @param testFunction The FlattenedTestFunction that was executed. - */ -async function getParentSuiteLocation(testFunction: FlattenedTestFunction): Promise { - const suiteStackWithFileAndTest = testFunction.testFunction.nameToRun.replace('::()', '').split('::'); - // Don't need the file location or the test's name. - const suiteStack = suiteStackWithFileAndTest.slice(1, suiteStackWithFileAndTest.length - 1); - const testFileUri = Uri.file(testFunction.parentTestFile.fullPath); - const testFile = await workspace.openTextDocument(testFileUri); - const testFileLines = testFile.getText().splitLines({ trim: false, removeEmptyEntries: false }); - const reversedTestFileLines = testFileLines.slice().reverse(); - // Track the end of the parent scope. - let parentScopeEndIndex = 0; - let parentScopeStartIndex = testFileLines.length; - let parentIndentation: number | undefined; - const suiteLocationStackFrameDetails: ILocationStackFrameDetails[] = []; - - const classPrefix = 'class '; - while (suiteStack.length > 0) { - let indentation = 0; - let prevLowestIndentation: number | undefined; - // Get the name of the suite on top of the stack so it can be located. - const suiteName = suiteStack.shift()!; - let suiteDefLineIndex: number | undefined; - for (let index = parentScopeEndIndex; index < parentScopeStartIndex; index += 1) { - const lineText = reversedTestFileLines[index]; - if (lineText.trim().length === 0) { - // This line is just whitespace. - } else { - const trimmedLineText = lineText.trimLeft()!; - if (!trimmedLineText.toLowerCase().startsWith(classPrefix)) { - // line is not a class declaration - } else { - const matches = trimmedLineText.slice(classPrefix.length).match(/[^ \(:]+/); - const lineClassName = matches ? matches[0] : undefined; - - // Check if the indentation is proper. - if (parentIndentation === undefined) { - // The parentIndentation hasn't been set yet, so we are looking for a class that was - // defined in the global scope of the module. - if (trimmedLineText.length === lineText.length) { - // This line doesn't start with whitespace. - if (lineClassName === suiteName) { - // This is the line that we want. - suiteDefLineIndex = index; - indentation = 0; - // We have our line for the root suite declaration, so move on to processing the Location. - break; - } else { - // This is not the line we want, but may be the line that ends the scope of the class we want. - parentScopeEndIndex = index + 1; - } - } - } else { - indentation = lineText.length - trimmedLineText.length; - if (indentation <= parentIndentation) { - // This is not the line we want, but may be the line that ends the scope of the parent class. - parentScopeEndIndex = index + 1; - } else if (prevLowestIndentation === undefined || indentation < prevLowestIndentation) { - if (lineClassName === suiteName) { - // This might be the line that we want. - suiteDefLineIndex = index; - prevLowestIndentation = indentation; - } else { - // This is not the line we want, but may be the line that ends the scope of the class we want. - parentScopeEndIndex = index + 1; - } - } - } - } - } - } - if (suiteDefLineIndex === undefined) { - // Could not find the suite declaration line, so give up and move on with the latest one that we found. - break; - } - // Found the line to process. - parentScopeStartIndex = suiteDefLineIndex; - parentIndentation = indentation!; - - // Invert the index to get the unreversed equivalent. - const realIndex = reversedTestFileLines.length - 1 - suiteDefLineIndex; - const startChar = indentation! + classPrefix.length; - const suiteStartPos = new Position(realIndex, startChar); - const suiteEndPos = new Position(realIndex, startChar + suiteName!.length); - const suiteRange = new Range(suiteStartPos, suiteEndPos); - const suiteLocation = new Location(testFileUri, suiteRange); - suiteLocationStackFrameDetails.push({ location: suiteLocation, lineText: testFile.getText(suiteRange) }); - } - return suiteLocationStackFrameDetails[suiteLocationStackFrameDetails.length - 1]; -} diff --git a/src/client/testing/pytest/testConfigurationManager.ts b/src/client/testing/pytest/testConfigurationManager.ts index 8b65321d05cf..4499a0aef84a 100644 --- a/src/client/testing/pytest/testConfigurationManager.ts +++ b/src/client/testing/pytest/testConfigurationManager.ts @@ -3,7 +3,7 @@ import { QuickPickItem, Uri } from 'vscode'; import { IFileSystem } from '../../common/platform/types'; import { Product } from '../../common/types'; import { IServiceContainer } from '../../ioc/types'; -import { TestConfigurationManager } from '../common/managers/testConfigurationManager'; +import { TestConfigurationManager } from '../common/testConfigurationManager'; import { ITestConfigSettingsService } from '../common/types'; export class ConfigurationManager extends TestConfigurationManager { diff --git a/src/client/testing/serviceRegistry.ts b/src/client/testing/serviceRegistry.ts index 3dc2c5f33866..9c7449055b90 100644 --- a/src/client/testing/serviceRegistry.ts +++ b/src/client/testing/serviceRegistry.ts @@ -1,114 +1,37 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import { Uri } from 'vscode'; -import { IExtensionActivationService, IExtensionSingleActivationService } from '../activation/types'; -import { IServiceContainer, IServiceManager } from '../ioc/types'; -import { ArgumentsHelper } from './common/argumentsHelper'; -import { PYTEST_PROVIDER, UNITTEST_PROVIDER } from './common/constants'; +import { IExtensionActivationService } from '../activation/types'; +import { IServiceManager } from '../ioc/types'; import { DebugLauncher } from './common/debugLauncher'; -import { EnablementTracker } from './common/enablementTracker'; import { TestRunner } from './common/runner'; -import { TestConfigSettingsService } from './common/services/configSettingService'; -import { TestDiscoveredTestParser } from './common/services/discoveredTestParser'; -import { TestsDiscoveryService } from './common/services/discovery'; -import { TestCollectionStorageService } from './common/services/storageService'; -import { TestManagerService } from './common/services/testManagerService'; -import { TestResultsService } from './common/services/testResultsService'; -import { TestsStatusUpdaterService } from './common/services/testsStatusService'; -import { ITestDiscoveredTestParser } from './common/services/types'; -import { UnitTestDiagnosticService } from './common/services/unitTestDiagnosticService'; -import { WorkspaceTestManagerService } from './common/services/workspaceTestManagerService'; +import { TestConfigSettingsService } from './common/configSettingService'; import { TestsHelper } from './common/testUtils'; -import { TestFlatteningVisitor } from './common/testVisitors/flatteningVisitor'; -import { TestResultResetVisitor } from './common/testVisitors/resultResetVisitor'; import { - IArgumentsHelper, - IArgumentsService, - ITestCollectionStorageService, ITestConfigSettingsService, ITestConfigurationManagerFactory, ITestConfigurationService, ITestDebugLauncher, - ITestDiagnosticService, - ITestDiscoveryService, - ITestManagementService, - ITestManager, - ITestManagerFactory, - ITestManagerRunner, - ITestManagerService, - ITestManagerServiceFactory, - ITestMessageService, - ITestResultsService, ITestRunner, ITestsHelper, - ITestsParser, - ITestsStatusUpdaterService, - ITestVisitor, - IUnitTestHelper, IUnitTestSocketServer, - IWorkspaceTestManagerService, - IXUnitParser, } from './common/types'; import { UpdateTestSettingService } from './common/updateTestSettings'; -import { XUnitParser } from './common/xUnitParser'; import { UnitTestConfigurationService } from './configuration'; import { TestConfigurationManagerFactory } from './configurationFactory'; import { TestingService, UnitTestManagementService } from './main'; -import { TestManager as PyTestTestManager } from './pytest/main'; -import { TestManagerRunner as PytestManagerRunner } from './pytest/runner'; -import { ArgumentsService as PyTestArgumentsService } from './pytest/services/argsService'; -import { TestDiscoveryService as PytestTestDiscoveryService } from './pytest/services/discoveryService'; -import { TestMessageService } from './pytest/services/testMessageService'; -import { ITestingService, TestProvider } from './types'; -import { UnitTestHelper } from './unittest/helper'; -import { TestManager as UnitTestTestManager } from './unittest/main'; -import { TestManagerRunner as UnitTestTestManagerRunner } from './unittest/runner'; -import { ArgumentsService as UnitTestArgumentsService } from './unittest/services/argsService'; -import { TestDiscoveryService as UnitTestTestDiscoveryService } from './unittest/services/discoveryService'; -import { TestsParser as UnitTestTestsParser } from './unittest/services/parserService'; +import { ITestingService } from './types'; import { UnitTestSocketServer } from './unittest/socketServer'; export function registerTypes(serviceManager: IServiceManager) { serviceManager.addSingleton(ITestDebugLauncher, DebugLauncher); - serviceManager.addSingleton( - ITestCollectionStorageService, - TestCollectionStorageService, - ); - serviceManager.addSingleton( - IWorkspaceTestManagerService, - WorkspaceTestManagerService, - ); serviceManager.add(ITestsHelper, TestsHelper); - serviceManager.add(ITestDiscoveredTestParser, TestDiscoveredTestParser); - serviceManager.add(ITestDiscoveryService, TestsDiscoveryService, 'common'); serviceManager.add(IUnitTestSocketServer, UnitTestSocketServer); - serviceManager.addSingleton(ITestsStatusUpdaterService, TestsStatusUpdaterService); - - serviceManager.add(ITestResultsService, TestResultsService); - - serviceManager.add(ITestVisitor, TestFlatteningVisitor, 'TestFlatteningVisitor'); - serviceManager.add(ITestVisitor, TestResultResetVisitor, 'TestResultResetVisitor'); - - serviceManager.add(ITestsParser, UnitTestTestsParser, UNITTEST_PROVIDER); - - serviceManager.add(ITestDiscoveryService, UnitTestTestDiscoveryService, UNITTEST_PROVIDER); - serviceManager.add(ITestDiscoveryService, PytestTestDiscoveryService, PYTEST_PROVIDER); - serviceManager.add(IArgumentsHelper, ArgumentsHelper); serviceManager.add(ITestRunner, TestRunner); - serviceManager.add(IXUnitParser, XUnitParser); - serviceManager.add(IUnitTestHelper, UnitTestHelper); - - serviceManager.add(IArgumentsService, PyTestArgumentsService, PYTEST_PROVIDER); - serviceManager.add(IArgumentsService, UnitTestArgumentsService, UNITTEST_PROVIDER); - serviceManager.add(ITestManagerRunner, PytestManagerRunner, PYTEST_PROVIDER); - serviceManager.add(ITestManagerRunner, UnitTestTestManagerRunner, UNITTEST_PROVIDER); serviceManager.addSingleton(ITestConfigurationService, UnitTestConfigurationService); - serviceManager.addSingleton(ITestManagementService, UnitTestManagementService); - serviceManager.addBinding(ITestManagementService, IExtensionActivationService); serviceManager.addSingleton(ITestingService, TestingService); serviceManager.addSingleton(ITestConfigSettingsService, TestConfigSettingsService); @@ -116,38 +39,6 @@ export function registerTypes(serviceManager: IServiceManager) { ITestConfigurationManagerFactory, TestConfigurationManagerFactory, ); - - serviceManager.addSingleton(ITestDiagnosticService, UnitTestDiagnosticService); - serviceManager.addSingleton(ITestMessageService, TestMessageService, PYTEST_PROVIDER); - serviceManager.addSingleton( - IExtensionSingleActivationService, - EnablementTracker, - ); serviceManager.addSingleton(IExtensionActivationService, UpdateTestSettingService); - - serviceManager.addFactory(ITestManagerFactory, (context) => { - return (testProvider: TestProvider, workspaceFolder: Uri, rootDirectory: string) => { - const serviceContainer = context.container.get(IServiceContainer); - - switch (testProvider) { - case PYTEST_PROVIDER: { - return new PyTestTestManager(workspaceFolder, rootDirectory, serviceContainer); - } - case UNITTEST_PROVIDER: { - return new UnitTestTestManager(workspaceFolder, rootDirectory, serviceContainer); - } - default: { - throw new Error(`Unrecognized test provider '${testProvider}'`); - } - } - }; - }); - - serviceManager.addFactory(ITestManagerServiceFactory, (context) => { - return (workspaceFolder: Uri) => { - const serviceContainer = context.container.get(IServiceContainer); - const testsHelper = context.container.get(ITestsHelper); - return new TestManagerService(workspaceFolder, testsHelper, serviceContainer); - }; - }); + serviceManager.addSingleton(IExtensionActivationService, UnitTestManagementService); } diff --git a/src/client/testing/unittest/helper.ts b/src/client/testing/unittest/helper.ts deleted file mode 100644 index 993efa2a77fa..000000000000 --- a/src/client/testing/unittest/helper.ts +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { inject, injectable } from 'inversify'; -import { IServiceContainer } from '../../ioc/types'; -import { IArgumentsHelper, IUnitTestHelper, Tests, TestsToRun } from '../common/types'; - -@injectable() -export class UnitTestHelper implements IUnitTestHelper { - private readonly argsHelper: IArgumentsHelper; - constructor(@inject(IServiceContainer) serviceContainer: IServiceContainer) { - this.argsHelper = serviceContainer.get(IArgumentsHelper); - } - public getStartDirectory(args: string[]): string { - const shortValue = this.argsHelper.getOptionValues(args, '-s'); - if (typeof shortValue === 'string') { - return shortValue; - } - const longValue = this.argsHelper.getOptionValues(args, '--start-directory'); - if (typeof longValue === 'string') { - return longValue; - } - return '.'; - } - public getIdsOfTestsToRun(tests: Tests, testsToRun: TestsToRun): string[] { - const testIds: string[] = []; - if (testsToRun && testsToRun.testFolder) { - // Get test ids of files in these folders. - testsToRun.testFolder.forEach((folder) => { - tests.testFiles.forEach((f) => { - if (f.fullPath.startsWith(folder.name)) { - testIds.push(f.nameToRun); - } - }); - }); - } - if (testsToRun && testsToRun.testFile) { - testIds.push(...testsToRun.testFile.map((f) => f.nameToRun)); - } - if (testsToRun && testsToRun.testSuite) { - testIds.push(...testsToRun.testSuite.map((f) => f.nameToRun)); - } - if (testsToRun && testsToRun.testFunction) { - testIds.push(...testsToRun.testFunction.map((f) => f.nameToRun)); - } - return testIds; - } -} diff --git a/src/client/testing/unittest/main.ts b/src/client/testing/unittest/main.ts deleted file mode 100644 index 1bb99d12d026..000000000000 --- a/src/client/testing/unittest/main.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { Uri } from 'vscode'; -import { CommandSource } from '../../common/constants'; -import { Product } from '../../common/types'; -import { noop } from '../../common/utils/misc'; -import { IServiceContainer } from '../../ioc/types'; -import { UNITTEST_PROVIDER } from '../common/constants'; -import { BaseTestManager } from '../common/managers/baseTestManager'; -import { - IArgumentsService, - ITestManagerRunner, - ITestsHelper, - TestDiscoveryOptions, - TestFilter, - TestRunOptions, - Tests, - TestStatus, - TestsToRun, -} from '../common/types'; - -export class TestManager extends BaseTestManager { - private readonly argsService: IArgumentsService; - private readonly helper: ITestsHelper; - private readonly runner: ITestManagerRunner; - public get enabled() { - return this.settings.testing.unittestEnabled; - } - constructor(workspaceFolder: Uri, rootDirectory: string, serviceContainer: IServiceContainer) { - super(UNITTEST_PROVIDER, Product.unittest, workspaceFolder, rootDirectory, serviceContainer); - this.argsService = this.serviceContainer.get(IArgumentsService, this.testProvider); - this.helper = this.serviceContainer.get(ITestsHelper); - this.runner = this.serviceContainer.get(ITestManagerRunner, this.testProvider); - } - public configure() { - noop(); - } - public getDiscoveryOptions(ignoreCache: boolean): TestDiscoveryOptions { - const args = this.settings.testing.unittestArgs.slice(0); - return { - workspaceFolder: this.workspaceFolder, - cwd: this.rootDirectory, - args, - token: this.testDiscoveryCancellationToken!, - ignoreCache, - outChannel: this.outputChannel, - }; - } - public async runTest( - cmdSource: CommandSource, - testsToRun?: TestsToRun, - runFailedTests?: boolean, - debug?: boolean, - ): Promise { - if (runFailedTests === true && this.tests) { - testsToRun = { testFile: [], testFolder: [], testSuite: [], testFunction: [] }; - testsToRun.testFunction = this.tests.testFunctions - .filter((fn) => { - return fn.testFunction.status === TestStatus.Error || fn.testFunction.status === TestStatus.Fail; - }) - .map((fn) => fn.testFunction); - } - return super.runTest(cmdSource, testsToRun, runFailedTests, debug); - } - public async runTestImpl( - tests: Tests, - testsToRun?: TestsToRun, - _runFailedTests?: boolean, - debug?: boolean, - ): Promise { - let args: string[]; - - const runAllTests = this.helper.shouldRunAllTests(testsToRun); - if (debug) { - args = this.argsService.filterArguments( - this.settings.testing.unittestArgs, - runAllTests ? TestFilter.debugAll : TestFilter.debugSpecific, - ); - } else { - args = this.argsService.filterArguments( - this.settings.testing.unittestArgs, - runAllTests ? TestFilter.runAll : TestFilter.runSpecific, - ); - } - - const options: TestRunOptions = { - workspaceFolder: this.workspaceFolder, - cwd: this.rootDirectory, - tests, - args, - testsToRun, - debug, - token: this.testRunnerCancellationToken!, - outChannel: this.outputChannel, - }; - return this.runner.runTest(this.testResultsService, options, this); - } -} diff --git a/src/client/testing/unittest/runner.ts b/src/client/testing/unittest/runner.ts deleted file mode 100644 index 10ac21b2c990..000000000000 --- a/src/client/testing/unittest/runner.ts +++ /dev/null @@ -1,229 +0,0 @@ -'use strict'; - -import { inject, injectable } from 'inversify'; -import { traceError } from '../../common/logger'; -import * as internalScripts from '../../common/process/internal/scripts'; -import { IDisposableRegistry } from '../../common/types'; -import { createDeferred, Deferred } from '../../common/utils/async'; -import { noop } from '../../common/utils/misc'; -import { IServiceContainer } from '../../ioc/types'; -import { UNITTEST_PROVIDER } from '../common/constants'; -import { Options } from '../common/runner'; -import { - IArgumentsHelper, - ITestDebugLauncher, - ITestManager, - ITestManagerRunner, - ITestResultsService, - ITestRunner, - IUnitTestHelper, - IUnitTestSocketServer, - LaunchOptions, - TestRunOptions, - Tests, - TestStatus, -} from '../common/types'; - -type TestStatusMap = { - status: TestStatus; - summaryProperty: 'passed' | 'failures' | 'errors' | 'skipped'; -}; - -const outcomeMapping = new Map(); -outcomeMapping.set('passed', { status: TestStatus.Pass, summaryProperty: 'passed' }); -outcomeMapping.set('failed', { status: TestStatus.Fail, summaryProperty: 'failures' }); -outcomeMapping.set('error', { status: TestStatus.Error, summaryProperty: 'errors' }); -outcomeMapping.set('skipped', { status: TestStatus.Skipped, summaryProperty: 'skipped' }); - -interface ITestData { - test: string; - message: string; - outcome: string; - traceback: string; -} - -@injectable() -export class TestManagerRunner implements ITestManagerRunner { - private readonly argsHelper: IArgumentsHelper; - private readonly helper: IUnitTestHelper; - private readonly testRunner: ITestRunner; - private readonly server: IUnitTestSocketServer; - private busy!: Deferred; - - constructor(@inject(IServiceContainer) private serviceContainer: IServiceContainer) { - this.argsHelper = serviceContainer.get(IArgumentsHelper); - this.testRunner = serviceContainer.get(ITestRunner); - this.server = this.serviceContainer.get(IUnitTestSocketServer); - this.helper = this.serviceContainer.get(IUnitTestHelper); - this.serviceContainer.get(IDisposableRegistry).push(this.server); - } - - public async runTest( - testResultsService: ITestResultsService, - options: TestRunOptions, - testManager: ITestManager, - ): Promise { - if (this.busy && !this.busy.completed) { - return this.busy.promise; - } - this.busy = createDeferred(); - - options.tests.summary.errors = 0; - options.tests.summary.failures = 0; - options.tests.summary.passed = 0; - options.tests.summary.skipped = 0; - let failFast = false; - this.server.on('error', (message: string, ...data: string[]) => traceError(`${message} ${data.join(' ')}`)); - this.server.on('log', noop); - this.server.on('connect', noop); - this.server.on('start', noop); - this.server.on('result', (data: ITestData) => { - const test = options.tests.testFunctions.find((t) => t.testFunction.nameToRun === data.test); - const statusDetails = outcomeMapping.get(data.outcome)!; - if (test) { - test.testFunction.status = statusDetails.status; - switch (test.testFunction.status) { - case TestStatus.Error: - case TestStatus.Fail: { - test.testFunction.passed = false; - break; - } - case TestStatus.Pass: { - test.testFunction.passed = true; - break; - } - default: { - test.testFunction.passed = undefined; - } - } - test.testFunction.message = data.message; - test.testFunction.traceback = data.traceback; - options.tests.summary[statusDetails.summaryProperty] += 1; - - if ( - failFast && - (statusDetails.summaryProperty === 'failures' || statusDetails.summaryProperty === 'errors') - ) { - testManager.stop(); - } - } else { - if (statusDetails) { - options.tests.summary[statusDetails.summaryProperty] += 1; - } - } - }); - - const port = await this.server.start(); - const testPaths: string[] = this.helper.getIdsOfTestsToRun(options.tests, options.testsToRun!); - for (let counter = 0; counter < testPaths.length; counter += 1) { - testPaths[counter] = `-t${testPaths[counter].trim()}`; - } - - const runTestInternal = async (testFile: string = '', testId: string = '') => { - let testArgs = this.buildTestArgs(options.args); - failFast = testArgs.indexOf('--uf') >= 0; - testArgs = testArgs.filter((arg) => arg !== '--uf'); - - testArgs.push(`--result-port=${port}`); - if (testId.length > 0) { - testArgs.push(`-t${testId}`); - } - if (testFile.length > 0) { - testArgs.push(`--testFile=${testFile}`); - } - if (options.debug === true) { - const debugLauncher = this.serviceContainer.get(ITestDebugLauncher); - testArgs.push('--debug'); - const launchOptions: LaunchOptions = { - cwd: options.cwd, - args: testArgs, - token: options.token, - outChannel: options.outChannel, - testProvider: UNITTEST_PROVIDER, - }; - return debugLauncher.launchDebugger(launchOptions); - } else { - const args = internalScripts.visualstudio_py_testlauncher(testArgs); - - const runOptions: Options = { - args: args, - cwd: options.cwd, - outChannel: options.outChannel, - token: options.token, - workspaceFolder: options.workspaceFolder, - }; - await this.testRunner.run(UNITTEST_PROVIDER, runOptions); - } - }; - - // Test everything. - if (testPaths.length === 0) { - await this.removeListenersAfter(runTestInternal()); - } else { - // Ok, the test runner can only work with one test at a time. - if (options.testsToRun) { - if (Array.isArray(options.testsToRun.testFile)) { - for (const testFile of options.testsToRun.testFile) { - await runTestInternal(testFile.fullPath, testFile.nameToRun); - } - } - if (Array.isArray(options.testsToRun.testSuite)) { - for (const testSuite of options.testsToRun.testSuite) { - const item = options.tests.testSuites.find((t) => t.testSuite === testSuite); - if (item) { - const testFileName = item.parentTestFile.fullPath; - await runTestInternal(testFileName, testSuite.nameToRun); - } - } - } - if (Array.isArray(options.testsToRun.testFunction)) { - for (const testFn of options.testsToRun.testFunction) { - const item = options.tests.testFunctions.find((t) => t.testFunction === testFn); - if (item) { - const testFileName = item.parentTestFile.fullPath; - await runTestInternal(testFileName, testFn.nameToRun); - } - } - } - - await this.removeListenersAfter(Promise.resolve()); - } - } - - testResultsService.updateResults(options.tests); - this.busy.resolve(options.tests); - return options.tests; - } - - // remove all the listeners from the server after all tests are complete, - // and just pass the promise `after` through as we do not want to get in - // the way here. - - private async removeListenersAfter(after: Promise): Promise { - return after - .then(() => this.server.removeAllListeners()) - .catch((err) => { - this.server.removeAllListeners(); - throw err; // keep propagating this downward - }); - } - - private buildTestArgs(args: string[]): string[] { - const startTestDiscoveryDirectory = this.helper.getStartDirectory(args); - let pattern = 'test*.py'; - const shortValue = this.argsHelper.getOptionValues(args, '-p'); - const longValueValue = this.argsHelper.getOptionValues(args, '--pattern'); - if (typeof shortValue === 'string') { - pattern = shortValue; - } else if (typeof longValueValue === 'string') { - pattern = longValueValue; - } - const failFast = args.some((arg) => arg.trim() === '-f' || arg.trim() === '--failfast'); - const verbosity = args.some((arg) => arg.trim().indexOf('-v') === 0) ? 2 : 1; - const testArgs = [`--us=${startTestDiscoveryDirectory}`, `--up=${pattern}`, `--uvInt=${verbosity}`]; - if (failFast) { - testArgs.push('--uf'); - } - return testArgs; - } -} diff --git a/src/client/testing/unittest/services/argsService.ts b/src/client/testing/unittest/services/argsService.ts deleted file mode 100644 index 81341e3aeae6..000000000000 --- a/src/client/testing/unittest/services/argsService.ts +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { inject, injectable } from 'inversify'; -import { IServiceContainer } from '../../../ioc/types'; -import { IArgumentsHelper, IArgumentsService, TestFilter } from '../../common/types'; - -const OptionsWithArguments = ['-k', '-p', '-s', '-t', '--pattern', '--start-directory', '--top-level-directory']; - -const OptionsWithoutArguments = [ - '-b', - '-c', - '-f', - '-h', - '-q', - '-v', - '--buffer', - '--catch', - '--failfast', - '--help', - '--locals', - '--quiet', - '--verbose', -]; - -@injectable() -export class ArgumentsService implements IArgumentsService { - private readonly helper: IArgumentsHelper; - constructor(@inject(IServiceContainer) serviceContainer: IServiceContainer) { - this.helper = serviceContainer.get(IArgumentsHelper); - } - public getKnownOptions(): { withArgs: string[]; withoutArgs: string[] } { - return { - withArgs: OptionsWithArguments, - withoutArgs: OptionsWithoutArguments, - }; - } - public getOptionValue(args: string[], option: string): string | string[] | undefined { - return this.helper.getOptionValues(args, option); - } - public filterArguments(args: string[], argumentToRemoveOrFilter: string[] | TestFilter): string[] { - const optionsWithoutArgsToRemove: string[] = []; - const optionsWithArgsToRemove: string[] = []; - // Positional arguments in pytest positional args are test directories and files. - // So if we want to run a specific test, then remove positional args. - let removePositionalArgs = false; - if (Array.isArray(argumentToRemoveOrFilter)) { - argumentToRemoveOrFilter.forEach((item) => { - if (OptionsWithArguments.indexOf(item) >= 0) { - optionsWithArgsToRemove.push(item); - } - if (OptionsWithoutArguments.indexOf(item) >= 0) { - optionsWithoutArgsToRemove.push(item); - } - }); - } else { - removePositionalArgs = true; - } - - let filteredArgs = args.slice(); - if (removePositionalArgs) { - const positionalArgs = this.helper.getPositionalArguments( - filteredArgs, - OptionsWithArguments, - OptionsWithoutArguments, - ); - filteredArgs = filteredArgs.filter((item) => positionalArgs.indexOf(item) === -1); - } - return this.helper.filterArguments(filteredArgs, optionsWithArgsToRemove, optionsWithoutArgsToRemove); - } - public getTestFolders(args: string[]): string[] { - const shortValue = this.helper.getOptionValues(args, '-s'); - if (typeof shortValue === 'string') { - return [shortValue]; - } - const longValue = this.helper.getOptionValues(args, '--start-directory'); - if (typeof longValue === 'string') { - return [longValue]; - } - return ['.']; - } -} diff --git a/src/client/testing/unittest/services/discoveryService.ts b/src/client/testing/unittest/services/discoveryService.ts deleted file mode 100644 index 351341eb6665..000000000000 --- a/src/client/testing/unittest/services/discoveryService.ts +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -import { inject, injectable, named } from 'inversify'; -import * as internalPython from '../../../common/process/internal/python'; -import { IServiceContainer } from '../../../ioc/types'; -import { UNITTEST_PROVIDER } from '../../common/constants'; -import { Options } from '../../common/runner'; -import { - IArgumentsHelper, - ITestDiscoveryService, - ITestRunner, - ITestsParser, - TestDiscoveryOptions, - Tests, -} from '../../common/types'; - -type UnitTestDiscoveryOptions = TestDiscoveryOptions & { - startDirectory: string; - pattern: string; -}; - -@injectable() -export class TestDiscoveryService implements ITestDiscoveryService { - private readonly argsHelper: IArgumentsHelper; - private readonly runner: ITestRunner; - constructor( - @inject(IServiceContainer) serviceContainer: IServiceContainer, - @inject(ITestsParser) @named(UNITTEST_PROVIDER) private testParser: ITestsParser, - ) { - this.argsHelper = serviceContainer.get(IArgumentsHelper); - this.runner = serviceContainer.get(ITestRunner); - } - public async discoverTests(options: TestDiscoveryOptions): Promise { - const pythonScript = this.getDiscoveryScript(options); - const unitTestOptions = this.translateOptions(options); - const runOptions: Options = { - // unittest needs to load modules in the workspace - // isolating it breaks unittest discovery - args: internalPython.execCode(pythonScript), - cwd: options.cwd, - workspaceFolder: options.workspaceFolder, - token: options.token, - outChannel: options.outChannel, - }; - - const data = await this.runner.run(UNITTEST_PROVIDER, runOptions); - - if (options.token && options.token.isCancellationRequested) { - return Promise.reject('cancelled'); - } - - return this.testParser.parse(data, unitTestOptions); - } - public getDiscoveryScript(options: TestDiscoveryOptions): string { - const unitTestOptions = this.translateOptions(options); - return ` -import unittest -def generate_test_cases(suite): - for test in suite: - if isinstance(test, unittest.TestCase): - yield test - else: - yield from generate_test_cases(test) -loader = unittest.TestLoader() -suite = loader.discover("${unitTestOptions.startDirectory}", pattern="${unitTestOptions.pattern}") -print("start") #Don't remove this line -print("\n".join(s.id() for s in generate_test_cases(suite)))`; - } - public translateOptions(options: TestDiscoveryOptions): UnitTestDiscoveryOptions { - return { - ...options, - startDirectory: this.getStartDirectory(options), - pattern: this.getTestPattern(options), - }; - } - private getStartDirectory(options: TestDiscoveryOptions) { - const shortValue = this.argsHelper.getOptionValues(options.args, '-s'); - if (typeof shortValue === 'string') { - return shortValue; - } - const longValue = this.argsHelper.getOptionValues(options.args, '--start-directory'); - if (typeof longValue === 'string') { - return longValue; - } - return '.'; - } - private getTestPattern(options: TestDiscoveryOptions) { - const shortValue = this.argsHelper.getOptionValues(options.args, '-p'); - if (typeof shortValue === 'string') { - return shortValue; - } - const longValue = this.argsHelper.getOptionValues(options.args, '--pattern'); - if (typeof longValue === 'string') { - return longValue; - } - return 'test*.py'; - } -} diff --git a/src/client/testing/unittest/services/parserService.ts b/src/client/testing/unittest/services/parserService.ts deleted file mode 100644 index 353e710e1fb6..000000000000 --- a/src/client/testing/unittest/services/parserService.ts +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -import { inject, injectable } from 'inversify'; -import * as path from 'path'; -import { Uri } from 'vscode'; -import { - ITestsHelper, - ITestsParser, - TestFile, - TestFunction, - Tests, - TestStatus, - UnitTestParserOptions, -} from '../../common/types'; - -@injectable() -export class TestsParser implements ITestsParser { - constructor(@inject(ITestsHelper) private testsHelper: ITestsHelper) {} - public parse(content: string, options: UnitTestParserOptions): Tests { - const testIds = this.getTestIds(content); - let testsDirectory = options.cwd; - if (options.startDirectory.length > 1) { - testsDirectory = path.isAbsolute(options.startDirectory) - ? options.startDirectory - : path.resolve(options.cwd, options.startDirectory); - } - return this.parseTestIds(options.cwd, testsDirectory, testIds); - } - private getTestIds(content: string): string[] { - let startedCollecting = false; - return content - .split(/\r?\n/g) - .map((line) => { - if (!startedCollecting) { - if (line === 'start') { - startedCollecting = true; - } - return ''; - } - return line.trim(); - }) - .filter((line) => line.length > 0); - } - private parseTestIds(workspaceDirectory: string, testsDirectory: string, testIds: string[]): Tests { - const testFiles: TestFile[] = []; - testIds.forEach((testId) => this.addTestId(testsDirectory, testId, testFiles)); - - return this.testsHelper.flattenTestFiles(testFiles, workspaceDirectory); - } - - /** - * Add the test Ids into the array provided. - * TestIds are fully qualified including the method names. - * E.g. tone_test.Failing2Tests.test_failure - * Where tone_test = folder, Failing2Tests = class/suite, test_failure = method. - * @private - * @param {string} rootDirectory - * @param {string} testId - * @param {TestFile[]} testFiles - * @returns {Tests} - * @memberof TestsParser - */ - private addTestId(rootDirectory: string, testId: string, testFiles: TestFile[]) { - const testIdParts = testId.split('.'); - // We must have a file, class and function name - if (testIdParts.length <= 2) { - return null; - } - - const paths = testIdParts.slice(0, testIdParts.length - 2); - const filePath = `${path.join(rootDirectory, ...paths)}.py`; - const functionName = testIdParts.pop()!; - const suiteToRun = testIdParts.join('.'); - const className = testIdParts.pop()!; - const moduleName = testIdParts.join('.'); - const resource = Uri.file(rootDirectory); - - // Check if we already have this test file - let testFile = testFiles.find((test) => test.fullPath === filePath); - if (!testFile) { - testFile = { - resource, - name: path.basename(filePath), - fullPath: filePath, - functions: [], - suites: [], - nameToRun: moduleName, - xmlName: '', - status: TestStatus.Idle, - time: 0, - }; - testFiles.push(testFile); - } - - // Check if we already have this suite - // nameToRun = testId - method name - let testSuite = testFile.suites.find((cls) => cls.nameToRun === suiteToRun); - if (!testSuite) { - testSuite = { - resource, - name: className, - functions: [], - suites: [], - isUnitTest: true, - isInstance: false, - nameToRun: suiteToRun, - xmlName: '', - status: TestStatus.Idle, - time: 0, - }; - testFile.suites.push(testSuite!); - } - - const testFunction: TestFunction = { - resource, - name: functionName, - nameToRun: testId, - status: TestStatus.Idle, - time: 0, - }; - - testSuite!.functions.push(testFunction); - } -} diff --git a/src/client/testing/unittest/testConfigurationManager.ts b/src/client/testing/unittest/testConfigurationManager.ts index f4b2f0af0a18..388656043696 100644 --- a/src/client/testing/unittest/testConfigurationManager.ts +++ b/src/client/testing/unittest/testConfigurationManager.ts @@ -1,7 +1,7 @@ import { Uri } from 'vscode'; import { Product } from '../../common/types'; import { IServiceContainer } from '../../ioc/types'; -import { TestConfigurationManager } from '../common/managers/testConfigurationManager'; +import { TestConfigurationManager } from '../common/testConfigurationManager'; import { ITestConfigSettingsService } from '../common/types'; export class ConfigurationManager extends TestConfigurationManager { diff --git a/src/test/testing/argsService.test.ts b/src/test/testing/argsService.test.ts deleted file mode 100644 index 4bcfa3b24538..000000000000 --- a/src/test/testing/argsService.test.ts +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { strictEqual } from 'assert'; -import { expect } from 'chai'; -import { spawnSync } from 'child_process'; -import * as typeMoq from 'typemoq'; -import { Product } from '../../client/common/types'; -import { getNamesAndValues } from '../../client/common/utils/enum'; -import { IServiceContainer } from '../../client/ioc/types'; -import { ArgumentsHelper } from '../../client/testing/common/argumentsHelper'; -import { UNIT_TEST_PRODUCTS } from '../../client/testing/common/constants'; -import { IArgumentsHelper, IArgumentsService } from '../../client/testing/common/types'; -import { ArgumentsService as PyTestArgumentsService } from '../../client/testing/pytest/services/argsService'; -import { ArgumentsService as UnitTestArgumentsService } from '../../client/testing/unittest/services/argsService'; -import { PYTHON_PATH } from '../common'; -import { TEST_TIMEOUT } from '../constants'; - -suite('ArgsService: Common', () => { - UNIT_TEST_PRODUCTS.forEach((product) => { - const productNames = getNamesAndValues(Product); - const productName = productNames.find((item) => item.value === product)!.name; - suite(productName, () => { - let argumentsService: IArgumentsService; - let moduleName = ''; - let expectedWithArgs: string[] = []; - let expectedWithoutArgs: string[] = []; - - setup(function () { - // Take the spawning of process into account. - - this.timeout(TEST_TIMEOUT * 2); - const serviceContainer = typeMoq.Mock.ofType(); - - const argsHelper = new ArgumentsHelper(); - - serviceContainer - .setup((s) => s.get(typeMoq.It.isValue(IArgumentsHelper), typeMoq.It.isAny())) - .returns(() => argsHelper); - - switch (product) { - case Product.unittest: { - argumentsService = new UnitTestArgumentsService(serviceContainer.object); - moduleName = 'unittest'; - break; - } - case Product.pytest: { - moduleName = 'pytest'; - argumentsService = new PyTestArgumentsService(serviceContainer.object); - break; - } - default: { - throw new Error('Unrecognized Test Framework'); - } - } - - expectedWithArgs = getOptions(product, moduleName, true); - expectedWithoutArgs = getOptions(product, moduleName, false); - }); - - test('Check for new/unrecognized options with values', () => { - const options = argumentsService.getKnownOptions(); - const optionsNotFound = expectedWithArgs.filter((item) => options.withArgs.indexOf(item) === -1); - - strictEqual(optionsNotFound.length, 0, `unhandled flags: ${optionsNotFound.join(',')}`); - }); - test('Check for new/unrecognized options without values', () => { - const options = argumentsService.getKnownOptions(); - const optionsNotFound = expectedWithoutArgs.filter((item) => options.withoutArgs.indexOf(item) === -1); - - strictEqual(optionsNotFound.length, 0, `unhandled flags: ${optionsNotFound.join(',')}`); - }); - test('Test getting value for an option with a single value', () => { - for (const option of expectedWithArgs) { - const args = [ - '--some-option-with-a-value', - '1234', - '--another-value-with-inline=1234', - option, - 'abcd', - ]; - const value = argumentsService.getOptionValue(args, option); - expect(value).to.equal('abcd'); - } - }); - test('Test getting value for an option with a multiple value', () => { - for (const option of expectedWithArgs) { - const args = [ - '--some-option-with-a-value', - '1234', - '--another-value-with-inline=1234', - option, - 'abcd', - option, - 'xyz', - ]; - const value = argumentsService.getOptionValue(args, option); - expect(value).to.deep.equal(['abcd', 'xyz']); - } - }); - test('Test filtering of arguments', () => { - const args: string[] = []; - const knownOptions = argumentsService.getKnownOptions(); - const argumentsToRemove: string[] = []; - const expectedFilteredArgs: string[] = []; - // Generate some random arguments. - for (let i = 0; i < 5; i += 1) { - args.push(knownOptions.withArgs[i], `Random Value ${i}`); - args.push(knownOptions.withoutArgs[i]); - - if (i % 2 === 0) { - argumentsToRemove.push(knownOptions.withArgs[i], knownOptions.withoutArgs[i]); - } else { - expectedFilteredArgs.push(knownOptions.withArgs[i], `Random Value ${i}`); - expectedFilteredArgs.push(knownOptions.withoutArgs[i]); - } - } - - const filteredArgs = argumentsService.filterArguments(args, argumentsToRemove); - expect(filteredArgs).to.be.deep.equal(expectedFilteredArgs); - }); - }); - }); -}); - -function getOptions(product: Product, moduleName: string, withValues: boolean) { - const result = spawnSync(PYTHON_PATH, ['-m', moduleName, '-h']); - const output = result.stdout.toString(); - - // Our regex isn't the best, so lets exclude stuff that shouldn't be captured. - const knownOptionsWithoutArgs: string[] = []; - const knownOptionsWithArgs: string[] = []; - if (product === Product.pytest) { - knownOptionsWithArgs.push(...['-c', '-k', '-p', '-r']); - } - - if (withValues) { - return getOptionsWithArguments(output) - .concat(...knownOptionsWithArgs) - .filter((item) => knownOptionsWithoutArgs.indexOf(item) === -1) - .sort(); - } else { - return ( - getOptionsWithoutArguments(output) - .concat(...knownOptionsWithoutArgs) - .filter((item) => knownOptionsWithArgs.indexOf(item) === -1) - // In pytest, any option beginning with --log- is known to have args. - .filter((item) => (product === Product.pytest ? !item.startsWith('--log-') : true)) - .sort() - ); - } -} - -function getOptionsWithoutArguments(output: string) { - return getMatches('\\s{1,}(-{1,2}[A-Za-z0-9-]+)(?:,|\\s{2,})', output); -} -function getOptionsWithArguments(output: string) { - return getMatches('\\s{1,}(-{1,2}[A-Za-z0-9-]+)(?:=|\\s{0,1}[A-Z])', output); -} - -function getMatches(pattern: any, str: string) { - const matches: string[] = []; - const regex = new RegExp(pattern, 'gm'); - let result: RegExpExecArray | null = regex.exec(str); - while (result !== null) { - if (result.index === regex.lastIndex) { - regex.lastIndex += 1; - } - matches.push(result[1].trim()); - result = regex.exec(str); - } - return matches - .sort() - .reduce((items, item) => (items.indexOf(item) === -1 ? items.concat([item]) : items), []); -} diff --git a/src/test/testing/common/argsHelper.unit.test.ts b/src/test/testing/common/argsHelper.unit.test.ts deleted file mode 100644 index 9fb42221ea93..000000000000 --- a/src/test/testing/common/argsHelper.unit.test.ts +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { expect, use } from 'chai'; -import { ArgumentsHelper } from '../../../client/testing/common/argumentsHelper'; -import { IArgumentsHelper } from '../../../client/testing/common/types'; -const assertArrays = require('chai-arrays'); -use(assertArrays); - -suite('Unit Tests - Arguments Helper', () => { - let argsHelper: IArgumentsHelper; - setup(() => { - argsHelper = new ArgumentsHelper(); - }); - - test('Get Option Value', () => { - const args = ['-abc', '1234', 'zys', '--root', 'value']; - const value = argsHelper.getOptionValues(args, '--root'); - expect(value).to.not.be.array(); - expect(value).to.be.deep.equal('value'); - }); - test('Get Option Value when using =', () => { - const args = ['-abc', '1234', 'zys', '--root=value']; - const value = argsHelper.getOptionValues(args, '--root'); - expect(value).to.not.be.array(); - expect(value).to.be.deep.equal('value'); - }); - test('Get Option Values', () => { - const args = ['-abc', '1234', 'zys', '--root', 'value1', '--root', 'value2']; - const values = argsHelper.getOptionValues(args, '--root'); - expect(values).to.be.array(); - expect(values).to.be.lengthOf(2); - expect(values).to.be.deep.equal(['value1', 'value2']); - }); - test('Get Option Values when using =', () => { - const args = ['-abc', '1234', 'zys', '--root=value1', '--root=value2']; - const values = argsHelper.getOptionValues(args, '--root'); - expect(values).to.be.array(); - expect(values).to.be.lengthOf(2); - expect(values).to.be.deep.equal(['value1', 'value2']); - }); - test('Get Positional options', () => { - const args = ['-abc', '1234', '--value-option', 'value1', '--no-value-option', 'value2']; - const values = argsHelper.getPositionalArguments(args, ['--value-option', '-abc'], ['--no-value-option']); - expect(values).to.be.array(); - expect(values).to.be.lengthOf(1); - expect(values).to.be.deep.equal(['value2']); - }); - test('Get multiple Positional options', () => { - const args = ['-abc', '1234', '--value-option', 'value1', '--no-value-option', 'value2', 'value3']; - const values = argsHelper.getPositionalArguments(args, ['--value-option', '-abc'], ['--no-value-option']); - expect(values).to.be.array(); - expect(values).to.be.lengthOf(2); - expect(values).to.be.deep.equal(['value2', 'value3']); - }); - test('Get multiple Positional options and inline values', () => { - const args = ['-abc=1234', '--value-option=value1', '--no-value-option', 'value2', 'value3']; - const values = argsHelper.getPositionalArguments(args, ['--value-option', '-abc'], ['--no-value-option']); - expect(values).to.be.array(); - expect(values).to.be.lengthOf(2); - expect(values).to.be.deep.equal(['value2', 'value3']); - }); - test('Get Positional options with trailing value option', () => { - const args = ['-abc', '1234', '--value-option', 'value1', '--value-option', 'value2', 'value3']; - const values = argsHelper.getPositionalArguments(args, ['--value-option', '-abc'], ['--no-value-option']); - expect(values).to.be.array(); - expect(values).to.be.lengthOf(1); - expect(values).to.be.deep.equal(['value3']); - }); - test('Get multiple Positional options with trailing value option', () => { - const args = ['-abc', '1234', '--value-option', 'value1', '--value-option', 'value2', 'value3', '4']; - const values = argsHelper.getPositionalArguments(args, ['--value-option', '-abc'], ['--no-value-option']); - expect(values).to.be.array(); - expect(values).to.be.lengthOf(2); - expect(values).to.be.deep.equal(['value3', '4']); - }); - test('Get Positional options with unknown args', () => { - const args = ['-abc', '1234', '--value-option', 'value1', '--value-option', 'value2', 'value3', '4']; - const values = argsHelper.getPositionalArguments(args, ['-abc'], ['--no-value-option']); - expect(values).to.be.array(); - expect(values).to.be.lengthOf(4); - expect(values).to.be.deep.equal(['value1', 'value2', 'value3', '4']); - }); - test('Get Positional options with no options parameters', () => { - const args = ['-abc', '1234', '--value-option', 'value1', '--value-option', 'value2', 'value3', '4']; - const values = argsHelper.getPositionalArguments(args); - expect(values).to.be.array(); - expect(values).to.be.lengthOf(5); - expect(values).to.be.deep.equal(['1234', 'value1', 'value2', 'value3', '4']); - expect(values).to.be.deep.equal(argsHelper.getPositionalArguments(args, [], [])); - }); - test('Filter to remove those with values', () => { - const args = ['-abc', '1234', '--value-option', 'value1', '--value-option', 'value2', 'value3', '4']; - const values = argsHelper.filterArguments(args, ['--value-option']); - expect(values).to.be.array(); - expect(values).to.be.lengthOf(4); - expect(values).to.be.deep.equal(['-abc', '1234', 'value3', '4']); - }); - test('Filter to remove those without values', () => { - const args = ['-abc', '1234', '--value-option', 'value1', '--no-value-option', 'value2', 'value3', '4']; - const values = argsHelper.filterArguments(args, [], ['--no-value-option']); - expect(values).to.be.array(); - expect(values).to.be.lengthOf(7); - expect(values).to.be.deep.equal(['-abc', '1234', '--value-option', 'value1', 'value2', 'value3', '4']); - }); - test('Filter to remove those with and without values', () => { - const args = ['-abc', '1234', '--value-option', 'value1', '--value-option', 'value2', 'value3', '4']; - const values = argsHelper.filterArguments(args, ['--value-option'], ['-abc']); - expect(values).to.be.array(); - expect(values).to.be.lengthOf(3); - expect(values).to.be.deep.equal(['1234', 'value3', '4']); - }); -}); diff --git a/src/test/testing/common/managers/baseTestManager.unit.test.ts b/src/test/testing/common/managers/baseTestManager.unit.test.ts deleted file mode 100644 index 91e2897649a5..000000000000 --- a/src/test/testing/common/managers/baseTestManager.unit.test.ts +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import * as sinon from 'sinon'; -import { anything, instance, mock, verify, when } from 'ts-mockito'; -import { Disposable, OutputChannel, Uri } from 'vscode'; -import { CommandManager } from '../../../../client/common/application/commandManager'; -import { ICommandManager, IWorkspaceService } from '../../../../client/common/application/types'; -import { WorkspaceService } from '../../../../client/common/application/workspace'; -import { PythonSettings } from '../../../../client/common/configSettings'; -import { ConfigurationService } from '../../../../client/common/configuration/service'; -import { CommandSource } from '../../../../client/common/constants'; -import { ModuleNotInstalledError } from '../../../../client/common/errors/moduleNotInstalledError'; -import { ProductInstaller } from '../../../../client/common/installer/productInstaller'; -import { - IConfigurationService, - IDisposableRegistry, - IInstaller, - IOutputChannel, - IPythonSettings, -} from '../../../../client/common/types'; -import { ServiceContainer } from '../../../../client/ioc/container'; -import { IServiceContainer } from '../../../../client/ioc/types'; -import { TestCollectionStorageService } from '../../../../client/testing/common/services/storageService'; -import { TestResultsService } from '../../../../client/testing/common/services/testResultsService'; -import { TestsStatusUpdaterService } from '../../../../client/testing/common/services/testsStatusService'; -import { UnitTestDiagnosticService } from '../../../../client/testing/common/services/unitTestDiagnosticService'; -import { TestsHelper } from '../../../../client/testing/common/testUtils'; -import { - IArgumentsService, - ITestCollectionStorageService, - ITestDiagnosticService, - ITestDiscoveryService, - ITestManager, - ITestManagerRunner, - ITestMessageService, - ITestResultsService, - ITestsHelper, - ITestsStatusUpdaterService, - TestDiscoveryOptions, -} from '../../../../client/testing/common/types'; -import { TEST_OUTPUT_CHANNEL } from '../../../../client/testing/constants'; -import { TestManager as PyTestTestManager } from '../../../../client/testing/pytest/main'; -import { ArgumentsService } from '../../../../client/testing/pytest/services/argsService'; -import { TestDiscoveryService } from '../../../../client/testing/pytest/services/discoveryService'; -import { TestMessageService } from '../../../../client/testing/pytest/services/testMessageService'; -import { TestManager as UnitTestTestManager } from '../../../../client/testing/unittest/main'; -import { TestManagerRunner } from '../../../../client/testing/unittest/runner'; -import { noop } from '../../../core'; -import { MockOutputChannel } from '../../../mockClasses'; - -const IGNORED_OPTIONS = ({} as unknown) as TestDiscoveryOptions; - -suite('Unit Tests - Base Test Manager', () => { - [ - { name: 'pytest', class: PyTestTestManager }, - { name: 'unittest', class: UnitTestTestManager }, - ].forEach((item) => { - suite(item.name, () => { - let testManager: ITestManager; - const workspaceFolder = Uri.file(__dirname); - let serviceContainer: IServiceContainer; - let configService: IConfigurationService; - let settings: IPythonSettings; - let outputChannel: IOutputChannel; - let storageService: ITestCollectionStorageService; - let resultsService: ITestResultsService; - let workspaceService: IWorkspaceService; - let diagnosticService: ITestDiagnosticService; - let statusUpdater: ITestsStatusUpdaterService; - let commandManager: ICommandManager; - let testDiscoveryService: ITestDiscoveryService; - let installer: IInstaller; - const sandbox = sinon.createSandbox(); - - suiteTeardown(() => sandbox.restore()); - - setup(() => { - serviceContainer = mock(ServiceContainer); - settings = mock(PythonSettings); - configService = mock(ConfigurationService); - outputChannel = mock(MockOutputChannel); - storageService = mock(TestCollectionStorageService); - resultsService = mock(TestResultsService); - workspaceService = mock(WorkspaceService); - diagnosticService = mock(UnitTestDiagnosticService); - statusUpdater = mock(TestsStatusUpdaterService); - commandManager = mock(CommandManager); - testDiscoveryService = mock(TestDiscoveryService); - installer = mock(ProductInstaller); - - const argsService = mock(ArgumentsService); - const testsHelper = mock(TestsHelper); - const runner = mock(TestManagerRunner); - const messageService = mock(TestMessageService); - - when(serviceContainer.get(IConfigurationService)).thenReturn( - instance(configService), - ); - when(serviceContainer.get(IDisposableRegistry)).thenReturn([]); - when(serviceContainer.get(IOutputChannel, TEST_OUTPUT_CHANNEL)).thenReturn( - instance(outputChannel), - ); - when(serviceContainer.get(ITestCollectionStorageService)).thenReturn( - instance(storageService), - ); - when(serviceContainer.get(ITestResultsService)).thenReturn( - instance(resultsService), - ); - when(serviceContainer.get(IWorkspaceService)).thenReturn(instance(workspaceService)); - when(serviceContainer.get(ITestDiagnosticService)).thenReturn( - instance(diagnosticService), - ); - when(serviceContainer.get(ITestsStatusUpdaterService)).thenReturn( - instance(statusUpdater), - ); - when(serviceContainer.get(ICommandManager)).thenReturn(instance(commandManager)); - - when(serviceContainer.get(IArgumentsService, anything())).thenReturn( - instance(argsService), - ); - when(serviceContainer.get(ITestsHelper)).thenReturn(instance(testsHelper)); - when(serviceContainer.get(ITestManagerRunner, anything())).thenReturn( - instance(runner), - ); - when(serviceContainer.get(ITestMessageService, anything())).thenReturn( - instance(messageService), - ); - - when(serviceContainer.get(ITestDiscoveryService, anything())).thenReturn( - instance(testDiscoveryService), - ); - when(serviceContainer.get(IInstaller)).thenReturn(instance(installer)); - - when(configService.getSettings(anything())).thenReturn(instance(settings)); - when(commandManager.executeCommand(anything(), anything(), anything())).thenResolve(); - - sandbox.restore(); - sandbox.stub(item.class.prototype, 'getDiscoveryOptions').callsFake(() => IGNORED_OPTIONS); - - // eslint-disable-next-line new-cap - testManager = new item.class(workspaceFolder, workspaceFolder.fsPath, instance(serviceContainer)); - }); - - test('Discovering tests should display test manager', async () => { - // We don't care about failures in running code - // Just test our expectations, ignore everything else. - await testManager.discoverTests(CommandSource.auto, true, true, true).catch(noop); - - verify(commandManager.executeCommand('setContext', 'testsDiscovered', true)).once(); - }); - - if (item.name !== 'unittest') { - test('When failing to discover tests prompt to install test framework', async () => { - when(testDiscoveryService.discoverTests(anything())).thenReject( - new ModuleNotInstalledError('Kaboom'), - ); - when(installer.isInstalled(anything(), anything())).thenResolve(false); - when(installer.promptToInstall(anything(), anything())).thenResolve(); - - // We don't care about failures in running code - // Just test our expectations, ignore everything else. - await testManager.discoverTests(CommandSource.ui, true, false, true).catch(noop); - - verify(installer.isInstalled(anything(), anything())).once(); - verify(installer.promptToInstall(anything(), anything())).once(); - }); - - test('When failing to discover tests do not prompt to install test framework', async () => { - when(testDiscoveryService.discoverTests(anything())).thenReject(new Error('Kaboom')); - when(installer.isInstalled(anything(), anything())).thenResolve(false); - when(installer.promptToInstall(anything(), anything())).thenResolve(); - - // We don't care about failures in running code - // Just test our expectations, ignore everything else. - await testManager.discoverTests(CommandSource.ui, true, false, true).catch(noop); - - verify(installer.isInstalled(anything(), anything())).never(); - verify(installer.promptToInstall(anything(), anything())).never(); - }); - - test('When failing to discover tests do not prompt to install test framework if installed', async () => { - when(testDiscoveryService.discoverTests(anything())).thenReject( - new ModuleNotInstalledError('Kaboom'), - ); - when(installer.isInstalled(anything(), anything())).thenResolve(true); - when(installer.promptToInstall(anything(), anything())).thenResolve(); - - // We don't care about failures in running code - // Just test our expectations, ignore everything else. - await testManager.discoverTests(CommandSource.ui, true, false, true).catch(noop); - - verify(installer.isInstalled(anything(), anything())).once(); - verify(installer.promptToInstall(anything(), anything())).never(); - }); - } - }); - }); -}); diff --git a/src/test/testing/common/managers/testConfigurationManager.unit.test.ts b/src/test/testing/common/managers/testConfigurationManager.unit.test.ts index 1d589def344b..02a7193172af 100644 --- a/src/test/testing/common/managers/testConfigurationManager.unit.test.ts +++ b/src/test/testing/common/managers/testConfigurationManager.unit.test.ts @@ -9,7 +9,7 @@ import { IInstaller, IOutputChannel, Product } from '../../../../client/common/t import { getNamesAndValues } from '../../../../client/common/utils/enum'; import { IServiceContainer } from '../../../../client/ioc/types'; import { UNIT_TEST_PRODUCTS } from '../../../../client/testing/common/constants'; -import { TestConfigurationManager } from '../../../../client/testing/common/managers/testConfigurationManager'; +import { TestConfigurationManager } from '../../../../client/testing/common/testConfigurationManager'; import { ITestConfigSettingsService, UnitTestProduct } from '../../../../client/testing/common/types'; import { TEST_OUTPUT_CHANNEL } from '../../../../client/testing/constants'; diff --git a/src/test/testing/common/services/configSettingService.unit.test.ts b/src/test/testing/common/services/configSettingService.unit.test.ts index bc5dce03235d..2de76c874fea 100644 --- a/src/test/testing/common/services/configSettingService.unit.test.ts +++ b/src/test/testing/common/services/configSettingService.unit.test.ts @@ -13,10 +13,10 @@ import { getNamesAndValues } from '../../../../client/common/utils/enum'; import { IServiceContainer } from '../../../../client/ioc/types'; import { UNIT_TEST_PRODUCTS } from '../../../../client/testing/common/constants'; import { - BufferedTestConfigSettingsService, TestConfigSettingsService, -} from '../../../../client/testing/common/services/configSettingService'; +} from '../../../../client/testing/common/configSettingService'; import { ITestConfigSettingsService, UnitTestProduct } from '../../../../client/testing/common/types'; +import { BufferedTestConfigSettingsService } from '../../../../client/testing/common/bufferedTestConfigSettingService'; use(chaiPromise); diff --git a/src/test/testing/common/services/discoveredTestParser.unit.test.ts b/src/test/testing/common/services/discoveredTestParser.unit.test.ts deleted file mode 100644 index 354c03622d9f..000000000000 --- a/src/test/testing/common/services/discoveredTestParser.unit.test.ts +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import * as assert from 'assert'; -import * as sinon from 'sinon'; -import * as typemoq from 'typemoq'; -import { Uri } from 'vscode'; -import { IWorkspaceService } from '../../../../client/common/application/types'; -import { TestDiscoveredTestParser } from '../../../../client/testing/common/services/discoveredTestParser'; -import { Tests } from '../../../../client/testing/common/types'; - -suite('Services - Discovered test parser', () => { - let workspaceService: typemoq.IMock; - let parser: TestDiscoveredTestParser; - setup(() => { - workspaceService = typemoq.Mock.ofType(); - }); - - teardown(() => { - sinon.restore(); - }); - - test('Parse returns empty tests if resource does not belong to workspace', () => { - // That is, getWorkspaceFolder() returns undefined. - const expectedTests: Tests = { - rootTestFolders: [], - summary: { errors: 0, failures: 0, passed: 0, skipped: 0 }, - testFiles: [], - testFolders: [], - testFunctions: [], - testSuites: [], - }; - const discoveredTests = [ - { - root: 'path/to/testDataRoot', - }, - ]; - const buildChildren = sinon.stub(TestDiscoveredTestParser.prototype, 'buildChildren'); - buildChildren.callsFake(() => undefined); - workspaceService - .setup((w) => w.getWorkspaceFolder(typemoq.It.isAny())) - .returns(() => undefined) - .verifiable(typemoq.Times.once()); - parser = new TestDiscoveredTestParser(workspaceService.object); - const result = parser.parse(Uri.file('path/to/resource'), discoveredTests as any); - assert.ok(buildChildren.notCalled); - assert.deepEqual(expectedTests, result); - workspaceService.verifyAll(); - }); - - test('Parse returns expected tests otherwise', () => { - const discoveredTests = [ - { - root: 'path/to/testDataRoot1', - rootid: 'rootId1', - }, - { - root: 'path/to/testDataRoot2', - rootid: 'rootId2', - }, - ]; - const workspaceUri = Uri.file('path/to/workspace'); - const workspace = { uri: workspaceUri }; - const expectedTests: Tests = { - rootTestFolders: [ - { - name: 'path/to/testDataRoot1', - folders: [], - time: 0, - testFiles: [], - resource: workspaceUri, - nameToRun: 'rootId1', - }, - { - name: 'path/to/testDataRoot2', - folders: [], - time: 0, - testFiles: [], - resource: workspaceUri, - nameToRun: 'rootId2', - }, - ], - summary: { errors: 0, failures: 0, passed: 0, skipped: 0 }, - testFiles: [], - testFolders: [ - { - name: 'path/to/testDataRoot1', - folders: [], - time: 0, - testFiles: [], - resource: workspaceUri, - nameToRun: 'rootId1', - }, - { - name: 'path/to/testDataRoot2', - folders: [], - time: 0, - testFiles: [], - resource: workspaceUri, - nameToRun: 'rootId2', - }, - ], - testFunctions: [], - testSuites: [], - }; - const buildChildren = sinon.stub(TestDiscoveredTestParser.prototype, 'buildChildren'); - buildChildren.callsFake(() => undefined); - workspaceService - .setup((w) => w.getWorkspaceFolder(typemoq.It.isAny())) - .returns(() => workspace as any) - .verifiable(typemoq.Times.once()); - parser = new TestDiscoveredTestParser(workspaceService.object); - const result = parser.parse(workspaceUri, discoveredTests as any); - assert.ok(buildChildren.calledTwice); - assert.deepEqual(expectedTests, result); - }); -}); diff --git a/src/test/testing/common/services/discovery.unit.test.ts b/src/test/testing/common/services/discovery.unit.test.ts deleted file mode 100644 index 6d16c9ada01c..000000000000 --- a/src/test/testing/common/services/discovery.unit.test.ts +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import * as assert from 'assert'; -import * as path from 'path'; -import { deepEqual, instance, mock, when } from 'ts-mockito'; -import * as typemoq from 'typemoq'; -import { CancellationTokenSource, OutputChannel, Uri, ViewColumn } from 'vscode'; -import { PythonExecutionFactory } from '../../../../client/common/process/pythonExecutionFactory'; -import { - ExecutionFactoryCreateWithEnvironmentOptions, - IPythonExecutionFactory, - IPythonExecutionService, - SpawnOptions, -} from '../../../../client/common/process/types'; -import { EXTENSION_ROOT_DIR } from '../../../../client/constants'; -import { TestDiscoveredTestParser } from '../../../../client/testing/common/services/discoveredTestParser'; -import { TestsDiscoveryService } from '../../../../client/testing/common/services/discovery'; -import { DiscoveredTests, ITestDiscoveredTestParser } from '../../../../client/testing/common/services/types'; -import { TestDiscoveryOptions, Tests } from '../../../../client/testing/common/types'; -import { MockOutputChannel } from '../../../mockClasses'; - -suite('Unit Tests - Common Discovery', () => { - let output: OutputChannel; - let discovery: TestsDiscoveryService; - let executionFactory: IPythonExecutionFactory; - let parser: ITestDiscoveredTestParser; - setup(() => { - output = mock(StubOutput); - executionFactory = mock(PythonExecutionFactory); - parser = mock(TestDiscoveredTestParser); - discovery = new TestsDiscoveryService(instance(executionFactory), instance(parser), instance(output)); - }); - test('Use parser to parse results', async () => { - const options: TestDiscoveryOptions = { - args: [], - cwd: __dirname, - workspaceFolder: Uri.file(__dirname), - ignoreCache: false, - token: new CancellationTokenSource().token, - outChannel: new MockOutputChannel('Test'), - }; - const discoveredTests: DiscoveredTests[] = [{ hello: 1 } as any]; - const parsedResult = ({ done: true } as any) as Tests; - discovery.exec = () => Promise.resolve(discoveredTests); - when(parser.parse(options.workspaceFolder, deepEqual(discoveredTests))).thenResolve(parsedResult as any); - - const tests = await discovery.discoverTests(options); - - assert.deepEqual(tests, parsedResult); - }); - test('Invoke Python Code to discover tests', async () => { - const options: TestDiscoveryOptions = { - args: ['1', '2', '3'], - cwd: __dirname, - workspaceFolder: Uri.file(__dirname), - ignoreCache: false, - token: new CancellationTokenSource().token, - outChannel: new MockOutputChannel('Test'), - }; - const discoveredTests = '[1]'; - const execService = typemoq.Mock.ofType(); - execService.setup((e: any) => e.then).returns(() => undefined); - const creationOptions: ExecutionFactoryCreateWithEnvironmentOptions = { - allowEnvironmentFetchExceptions: false, - resource: options.workspaceFolder, - }; - const pythonFile = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'testing_tools', 'run_adapter.py'); - const spawnOptions: SpawnOptions = { - token: options.token, - cwd: options.cwd, - throwOnStdErr: true, - }; - - when(executionFactory.createActivatedEnvironment(deepEqual(creationOptions))).thenResolve(execService.object); - const executionResult = { stdout: JSON.stringify(discoveredTests) }; - execService - .setup((e) => e.exec(typemoq.It.isValue([pythonFile, ...options.args]), typemoq.It.isValue(spawnOptions))) - .returns(() => Promise.resolve(executionResult)); - - const result = await discovery.exec(options); - - execService.verifyAll(); - assert.deepEqual(result, discoveredTests); - }); -}); - -//class StubOutput implements OutputChannel { -class StubOutput { - constructor(public name: string) {} - public append(_value: string) {} - public appendLine(_value: string) {} - public clear() {} - //public show(_preserveFocus?: boolean) {} - public show(_column?: ViewColumn | boolean, _preserveFocus?: boolean) {} - public hide() {} - public dispose() {} -} diff --git a/src/test/testing/common/services/testResultsService.unit.test.ts b/src/test/testing/common/services/testResultsService.unit.test.ts deleted file mode 100644 index 9778e93ce2d7..000000000000 --- a/src/test/testing/common/services/testResultsService.unit.test.ts +++ /dev/null @@ -1,234 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { expect } from 'chai'; -import * as typemoq from 'typemoq'; -import { TestResultsService } from '../../../../client/testing/common/services/testResultsService'; -import { - FlattenedTestFunction, - FlattenedTestSuite, - ITestVisitor, - TestDataItemType, - TestFile, - TestFolder, - TestFunction, - Tests, - TestStatus, - TestSuite, -} from '../../../../client/testing/common/types'; -import { createMockTestDataItem } from '../testUtils.unit.test'; - -suite('Unit Tests - Tests Results Service', () => { - let testResultsService: TestResultsService; - let resultResetVisitor: typemoq.IMock; - let tests!: Tests; - - let folder1: TestFolder, - folder2: TestFolder, - folder3: TestFolder, - folder4: TestFolder, - folder5: TestFolder, - suite1: TestSuite, - suite2: TestSuite, - suite3: TestSuite, - suite4: TestSuite, - suite5: TestSuite; - let file1: TestFile, file2: TestFile, file3: TestFile, file4: TestFile, file5: TestFile; - setup(() => { - resultResetVisitor = typemoq.Mock.ofType(); - folder1 = createMockTestDataItem(TestDataItemType.folder); - folder2 = createMockTestDataItem(TestDataItemType.folder); - folder3 = createMockTestDataItem(TestDataItemType.folder); - folder4 = createMockTestDataItem(TestDataItemType.folder); - folder5 = createMockTestDataItem(TestDataItemType.folder); - folder1.folders.push(folder2); - folder1.folders.push(folder3); - folder2.folders.push(folder4); - folder3.folders.push(folder5); - - file1 = createMockTestDataItem(TestDataItemType.file); - file2 = createMockTestDataItem(TestDataItemType.file); - file3 = createMockTestDataItem(TestDataItemType.file); - file4 = createMockTestDataItem(TestDataItemType.file); - file5 = createMockTestDataItem(TestDataItemType.file); - folder1.testFiles.push(file1); - folder3.testFiles.push(file2); - folder3.testFiles.push(file3); - folder4.testFiles.push(file5); - folder5.testFiles.push(file4); - - suite1 = createMockTestDataItem(TestDataItemType.suite); - suite2 = createMockTestDataItem(TestDataItemType.suite); - suite3 = createMockTestDataItem(TestDataItemType.suite); - suite4 = createMockTestDataItem(TestDataItemType.suite); - suite5 = createMockTestDataItem(TestDataItemType.suite); - const fn1 = createMockTestDataItem(TestDataItemType.function); - fn1.passed = true; - const fn2 = createMockTestDataItem(TestDataItemType.function); - fn2.passed = undefined; - const fn3 = createMockTestDataItem(TestDataItemType.function); - fn3.passed = true; - const fn4 = createMockTestDataItem(TestDataItemType.function); - fn4.passed = false; - const fn5 = createMockTestDataItem(TestDataItemType.function); - fn5.passed = undefined; - const fn6 = createMockTestDataItem(TestDataItemType.function); - fn6.passed = true; - const fn7 = createMockTestDataItem(TestDataItemType.function); - fn7.passed = undefined; - const fn8 = createMockTestDataItem(TestDataItemType.function); - fn8.passed = false; - const fn9 = createMockTestDataItem(TestDataItemType.function); - fn9.passed = true; - const fn10 = createMockTestDataItem(TestDataItemType.function); - fn10.passed = true; - const fn11 = createMockTestDataItem(TestDataItemType.function); - fn11.passed = true; - file1.suites.push(suite1); - file1.suites.push(suite2); - file3.suites.push(suite3); - suite3.suites.push(suite4); - suite4.suites.push(suite5); - file1.functions.push(fn1); - file1.functions.push(fn2); - file2.functions.push(fn8); - file4.functions.push(fn9); - file4.functions.push(fn11); - file5.functions.push(fn10); - suite1.functions.push(fn3); - suite1.functions.push(fn4); - suite2.functions.push(fn6); - suite3.functions.push(fn5); - suite5.functions.push(fn7); - const flattendSuite1: FlattenedTestSuite = { - testSuite: suite1, - xmlClassName: suite1.xmlName, - } as any; - const flattendSuite2: FlattenedTestSuite = { - testSuite: suite2, - xmlClassName: suite2.xmlName, - } as any; - const flattendSuite3: FlattenedTestSuite = { - testSuite: suite3, - xmlClassName: suite3.xmlName, - } as any; - const flattendSuite4: FlattenedTestSuite = { - testSuite: suite4, - xmlClassName: suite4.xmlName, - } as any; - const flattendSuite5: FlattenedTestSuite = { - testSuite: suite5, - xmlClassName: suite5.xmlName, - } as any; - const flattendFn1: FlattenedTestFunction = { - testFunction: fn1, - xmlClassName: fn1.name, - } as any; - const flattendFn2: FlattenedTestFunction = { - testFunction: fn2, - xmlClassName: fn2.name, - } as any; - const flattendFn3: FlattenedTestFunction = { - testFunction: fn3, - xmlClassName: fn3.name, - } as any; - const flattendFn4: FlattenedTestFunction = { - testFunction: fn4, - xmlClassName: fn4.name, - } as any; - const flattendFn5: FlattenedTestFunction = { - testFunction: fn5, - xmlClassName: fn5.name, - } as any; - const flattendFn6: FlattenedTestFunction = { - testFunction: fn6, - xmlClassName: fn6.name, - } as any; - const flattendFn7: FlattenedTestFunction = { - testFunction: fn7, - xmlClassName: fn7.name, - } as any; - const flattendFn8: FlattenedTestFunction = { - testFunction: fn8, - xmlClassName: fn8.name, - } as any; - const flattendFn9: FlattenedTestFunction = { - testFunction: fn9, - xmlClassName: fn9.name, - } as any; - const flattendFn10: FlattenedTestFunction = { - testFunction: fn10, - xmlClassName: fn10.name, - } as any; - const flattendFn11: FlattenedTestFunction = { - testFunction: fn11, - xmlClassName: fn11.name, - } as any; - tests = { - rootTestFolders: [folder1], - summary: { errors: 0, skipped: 0, passed: 0, failures: 0 }, - testFiles: [file1, file2, file3, file4, file5], - testFolders: [folder1, folder2, folder3, folder4, folder5], - testFunctions: [ - flattendFn1, - flattendFn2, - flattendFn3, - flattendFn4, - flattendFn5, - flattendFn6, - flattendFn7, - flattendFn8, - flattendFn9, - flattendFn10, - flattendFn11, - ], - testSuites: [flattendSuite1, flattendSuite2, flattendSuite3, flattendSuite4, flattendSuite5], - }; - testResultsService = new TestResultsService(resultResetVisitor.object); - }); - - test('If any test fails, parent fails', () => { - testResultsService.updateResults(tests); - expect(suite1.status).to.equal(TestStatus.Fail); - expect(file1.status).to.equal(TestStatus.Fail); - expect(folder1.status).to.equal(TestStatus.Fail); - expect(file2.status).to.equal(TestStatus.Fail); - expect(folder3.status).to.equal(TestStatus.Fail); - }); - - test('If all tests pass, parent passes', () => { - testResultsService.updateResults(tests); - expect(file4.status).to.equal(TestStatus.Pass); - expect(folder5.status).to.equal(TestStatus.Pass); - expect(folder2.status).to.equal(TestStatus.Pass); - }); - - test('If no tests run, parent status is not run', () => { - testResultsService.updateResults(tests); - expect(suite3.status).to.equal(TestStatus.Unknown); - expect(suite4.status).to.equal(TestStatus.Unknown); - expect(suite5.status).to.equal(TestStatus.Unknown); - expect(file3.status).to.equal(TestStatus.Unknown); - }); - - test('Number of functions passed, not run and failed are correctly calculated', () => { - testResultsService.updateResults(tests); - - expect(file1.functionsPassed).to.equal(3); - expect(folder2.functionsPassed).to.equal(1); - expect(folder3.functionsPassed).to.equal(2); - expect(folder1.functionsPassed).to.equal(6); - - expect(file1.functionsFailed).to.equal(1); - expect(folder2.functionsFailed).to.equal(0); - expect(folder3.functionsFailed).to.equal(1); - expect(folder1.functionsFailed).to.equal(2); - - expect(file1.functionsDidNotRun).to.equal(1); - expect(suite4.functionsDidNotRun).to.equal(1); - expect(suite3.functionsDidNotRun).to.equal(2); - expect(folder1.functionsDidNotRun).to.equal(3); - }); -}); diff --git a/src/test/testing/common/services/testStatusService.unit.test.ts b/src/test/testing/common/services/testStatusService.unit.test.ts deleted file mode 100644 index 63c018d09477..000000000000 --- a/src/test/testing/common/services/testStatusService.unit.test.ts +++ /dev/null @@ -1,253 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import * as assert from 'assert'; -import { anything, instance, mock, verify, when } from 'ts-mockito'; -import { Uri } from 'vscode'; -import { TestCollectionStorageService } from '../../../../client/testing/common/services/storageService'; -import { TestsStatusUpdaterService } from '../../../../client/testing/common/services/testsStatusService'; -import { visitRecursive } from '../../../../client/testing/common/testVisitors/visitor'; -import { - FlattenedTestFunction, - FlattenedTestSuite, - ITestCollectionStorageService, - ITestsStatusUpdaterService, - TestDataItem, - TestDataItemType, - TestFile, - TestFolder, - TestFunction, - Tests, - TestStatus, - TestSuite, -} from '../../../../client/testing/common/types'; -import { createMockTestDataItem } from '../testUtils.unit.test'; - -suite('Unit Tests - Tests Status Updater', () => { - let storage: ITestCollectionStorageService; - let updater: ITestsStatusUpdaterService; - const workspaceUri = Uri.file(__filename); - let tests!: Tests; - setup(() => { - storage = mock(TestCollectionStorageService); - updater = new TestsStatusUpdaterService(instance(storage)); - const folder1 = createMockTestDataItem(TestDataItemType.folder); - const folder2 = createMockTestDataItem(TestDataItemType.folder); - const folder3 = createMockTestDataItem(TestDataItemType.folder); - const folder4 = createMockTestDataItem(TestDataItemType.folder); - const folder5 = createMockTestDataItem(TestDataItemType.folder); - folder1.folders.push(folder2); - folder1.folders.push(folder3); - folder2.folders.push(folder4); - folder3.folders.push(folder5); - - const file1 = createMockTestDataItem(TestDataItemType.file); - const file2 = createMockTestDataItem(TestDataItemType.file); - const file3 = createMockTestDataItem(TestDataItemType.file); - const file4 = createMockTestDataItem(TestDataItemType.file); - folder1.testFiles.push(file1); - folder3.testFiles.push(file2); - folder3.testFiles.push(file3); - folder5.testFiles.push(file4); - - const suite1 = createMockTestDataItem(TestDataItemType.suite); - const suite2 = createMockTestDataItem(TestDataItemType.suite); - const suite3 = createMockTestDataItem(TestDataItemType.suite); - const suite4 = createMockTestDataItem(TestDataItemType.suite); - const suite5 = createMockTestDataItem(TestDataItemType.suite); - const fn1 = createMockTestDataItem(TestDataItemType.function); - const fn2 = createMockTestDataItem(TestDataItemType.function); - const fn3 = createMockTestDataItem(TestDataItemType.function); - const fn4 = createMockTestDataItem(TestDataItemType.function); - const fn5 = createMockTestDataItem(TestDataItemType.function); - file1.suites.push(suite1); - file1.suites.push(suite2); - file3.suites.push(suite3); - suite3.suites.push(suite4); - suite4.suites.push(suite5); - file1.functions.push(fn1); - file1.functions.push(fn2); - suite1.functions.push(fn3); - suite1.functions.push(fn4); - suite3.functions.push(fn5); - const flattendSuite1: FlattenedTestSuite = { - testSuite: suite1, - xmlClassName: suite1.xmlName, - } as any; - const flattendSuite2: FlattenedTestSuite = { - testSuite: suite2, - xmlClassName: suite2.xmlName, - } as any; - const flattendSuite3: FlattenedTestSuite = { - testSuite: suite3, - xmlClassName: suite3.xmlName, - } as any; - const flattendSuite4: FlattenedTestSuite = { - testSuite: suite4, - xmlClassName: suite4.xmlName, - } as any; - const flattendSuite5: FlattenedTestSuite = { - testSuite: suite5, - xmlClassName: suite5.xmlName, - } as any; - const flattendFn1: FlattenedTestFunction = { - testFunction: fn1, - xmlClassName: fn1.name, - } as any; - const flattendFn2: FlattenedTestFunction = { - testFunction: fn2, - xmlClassName: fn2.name, - } as any; - const flattendFn3: FlattenedTestFunction = { - testFunction: fn3, - xmlClassName: fn3.name, - } as any; - const flattendFn4: FlattenedTestFunction = { - testFunction: fn4, - xmlClassName: fn4.name, - } as any; - const flattendFn5: FlattenedTestFunction = { - testFunction: fn5, - xmlClassName: fn5.name, - } as any; - tests = { - rootTestFolders: [folder1], - summary: { errors: 0, skipped: 0, passed: 0, failures: 0 }, - testFiles: [file1, file2, file3, file4], - testFolders: [folder1, folder2, folder3, folder4, folder5], - testFunctions: [flattendFn1, flattendFn2, flattendFn3, flattendFn4, flattendFn5], - testSuites: [flattendSuite1, flattendSuite2, flattendSuite3, flattendSuite4, flattendSuite5], - }; - when(storage.getTests(workspaceUri)).thenReturn(tests); - }); - - test('Updating discovery status will recursively update all items and triggers an update for each', () => { - updater.updateStatusAsDiscovering(workspaceUri, tests); - - function validate(item: TestDataItem) { - assert.equal(item.status, TestStatus.Discovering); - verify(storage.update(workspaceUri, item)).once(); - } - tests.testFolders.forEach(validate); - tests.testFiles.forEach(validate); - tests.testFunctions.forEach((func) => validate(func.testFunction)); - tests.testSuites.forEach((suite) => validate(suite.testSuite)); - }); - test('Updating unknown status will recursively update all items and triggers an update for each', () => { - updater.updateStatusAsUnknown(workspaceUri, tests); - - function validate(item: TestDataItem) { - assert.equal(item.status, TestStatus.Unknown); - verify(storage.update(workspaceUri, item)).once(); - } - tests.testFolders.forEach(validate); - tests.testFiles.forEach(validate); - tests.testFunctions.forEach((func) => validate(func.testFunction)); - tests.testSuites.forEach((suite) => validate(suite.testSuite)); - }); - test('Updating running status will recursively update all items and triggers an update for each', () => { - updater.updateStatusAsRunning(workspaceUri, tests); - - function validate(item: TestDataItem) { - assert.equal(item.status, TestStatus.Running); - verify(storage.update(workspaceUri, item)).once(); - } - tests.testFolders.forEach(validate); - tests.testFiles.forEach(validate); - tests.testFunctions.forEach((func) => validate(func.testFunction)); - tests.testSuites.forEach((suite) => validate(suite.testSuite)); - }); - test('Updating running status for failed tests will recursively update all items and triggers an update for each', () => { - tests.testFolders[1].status = TestStatus.Fail; - tests.testFolders[2].status = TestStatus.Error; - tests.testFiles[2].status = TestStatus.Fail; - tests.testFiles[3].status = TestStatus.Error; - tests.testFunctions[2].testFunction.status = TestStatus.Fail; - tests.testFunctions[3].testFunction.status = TestStatus.Error; - tests.testFunctions[4].testFunction.status = TestStatus.Pass; - tests.testSuites[1].testSuite.status = TestStatus.Fail; - tests.testSuites[2].testSuite.status = TestStatus.Error; - - updater.updateStatusAsRunningFailedTests(workspaceUri, tests); - - // Do not update status of folders and files. - assert.equal(tests.testFolders[1].status, TestStatus.Fail); - assert.equal(tests.testFolders[2].status, TestStatus.Error); - assert.equal(tests.testFiles[2].status, TestStatus.Fail); - assert.equal(tests.testFiles[3].status, TestStatus.Error); - - // Update status of test functions and suites. - const updatedItems: TestDataItem[] = []; - const visitor = (item: TestDataItem) => { - if (item.status && item.status !== TestStatus.Pass) { - updatedItems.push(item); - } - }; - const failedItems = [ - tests.testFunctions[2].testFunction, - tests.testFunctions[3].testFunction, - tests.testSuites[1].testSuite, - tests.testSuites[2].testSuite, - ]; - failedItems.forEach((failedItem) => visitRecursive(tests, failedItem, visitor)); - - for (const item of updatedItems) { - assert.equal(item.status, TestStatus.Running); - verify(storage.update(workspaceUri, item)).once(); - } - - // Only items with status Fail & Error should be modified - assert.equal(tests.testFunctions[4].testFunction.status, TestStatus.Pass); - - // Should only be called for failed items. - verify(storage.update(workspaceUri, anything())).times(updatedItems.length); - }); - test('Updating idle status for runnings tests will recursively update all items and triggers an update for each', () => { - tests.testFolders[1].status = TestStatus.Running; - tests.testFolders[2].status = TestStatus.Running; - tests.testFiles[2].status = TestStatus.Running; - tests.testFiles[3].status = TestStatus.Running; - tests.testFunctions[2].testFunction.status = TestStatus.Running; - tests.testFunctions[3].testFunction.status = TestStatus.Running; - tests.testSuites[1].testSuite.status = TestStatus.Running; - tests.testSuites[2].testSuite.status = TestStatus.Running; - - updater.updateStatusOfRunningTestsAsIdle(workspaceUri, tests); - - const updatedItems: TestDataItem[] = []; - updatedItems.push(tests.testFolders[1]); - updatedItems.push(tests.testFolders[2]); - updatedItems.push(tests.testFiles[2]); - updatedItems.push(tests.testFiles[3]); - updatedItems.push(tests.testFunctions[2].testFunction); - updatedItems.push(tests.testFunctions[3].testFunction); - updatedItems.push(tests.testSuites[1].testSuite); - updatedItems.push(tests.testSuites[2].testSuite); - - for (const item of updatedItems) { - assert.equal(item.status, TestStatus.Idle); - verify(storage.update(workspaceUri, item)).once(); - } - - // Should only be called for failed items. - verify(storage.update(workspaceUri, anything())).times(updatedItems.length); - }); - test('Triggers an update for each', () => { - updater.triggerUpdatesToTests(workspaceUri, tests); - - const updatedItems: TestDataItem[] = [ - ...tests.testFolders, - ...tests.testFiles, - ...tests.testFunctions.map((item) => item.testFunction), - ...tests.testSuites.map((item) => item.testSuite), - ]; - - for (const item of updatedItems) { - verify(storage.update(workspaceUri, item)).once(); - } - - verify(storage.update(workspaceUri, anything())).times(updatedItems.length); - }); -}); diff --git a/src/test/testing/common/testVisitors/resultResetVisitor.unit.test.ts b/src/test/testing/common/testVisitors/resultResetVisitor.unit.test.ts deleted file mode 100644 index e262eda5139b..000000000000 --- a/src/test/testing/common/testVisitors/resultResetVisitor.unit.test.ts +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { assert } from 'chai'; -import { TestResultResetVisitor } from '../../../../client/testing/common/testVisitors/resultResetVisitor'; -import { TestStatus } from '../../../../client/testing/common/types'; - -suite('Result reset visitor', async () => { - let resultResetVisitor: TestResultResetVisitor; - setup(() => { - resultResetVisitor = new TestResultResetVisitor(); - }); - - test('Method visitTestFunction() resets visited function nodes', async () => { - const testFunction = { - passed: true, - time: 102, - message: 'yo', - traceback: 'sd', - status: TestStatus.Fail, - functionsDidNotRun: 12, - functionsPassed: 1, - functionsFailed: 5, - }; - const expectedTestFunction = { - passed: undefined, - time: 0, - message: '', - traceback: '', - status: TestStatus.Unknown, - functionsDidNotRun: 0, - functionsPassed: 0, - functionsFailed: 0, - }; - - resultResetVisitor.visitTestFunction(testFunction as any); - - assert.deepEqual(testFunction, expectedTestFunction as any); - }); - - test('Method visitTestSuite() resets visited suite nodes', async () => { - const testSuite = { - passed: true, - time: 102, - status: TestStatus.Fail, - functionsDidNotRun: 12, - functionsPassed: 1, - functionsFailed: 5, - }; - const expectedTestSuite = { - passed: undefined, - time: 0, - status: TestStatus.Unknown, - functionsDidNotRun: 0, - functionsPassed: 0, - functionsFailed: 0, - }; - - resultResetVisitor.visitTestSuite(testSuite as any); - - assert.deepEqual(testSuite, expectedTestSuite as any); - }); - - test('Method visitTestFile() resets visited file nodes', async () => { - const testFile = { - passed: true, - time: 102, - status: TestStatus.Fail, - functionsDidNotRun: 12, - functionsPassed: 1, - functionsFailed: 5, - }; - const expectedTestFile = { - passed: undefined, - time: 0, - status: TestStatus.Unknown, - functionsDidNotRun: 0, - functionsPassed: 0, - functionsFailed: 0, - }; - - resultResetVisitor.visitTestFile(testFile as any); - - assert.deepEqual(testFile, expectedTestFile as any); - }); - - test('Method visitTestFolder() resets visited folder nodes', async () => { - const testFolder = { - passed: true, - time: 102, - status: TestStatus.Fail, - functionsDidNotRun: 12, - functionsPassed: 1, - functionsFailed: 5, - }; - const expectedTestFolder = { - passed: undefined, - time: 0, - status: TestStatus.Unknown, - functionsDidNotRun: 0, - functionsPassed: 0, - functionsFailed: 0, - }; - - resultResetVisitor.visitTestFolder(testFolder as any); - - assert.deepEqual(testFolder, expectedTestFolder as any); - }); -}); diff --git a/src/test/testing/common/trackEnablement.unit.test.ts b/src/test/testing/common/trackEnablement.unit.test.ts deleted file mode 100644 index d45f3280a412..000000000000 --- a/src/test/testing/common/trackEnablement.unit.test.ts +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import * as assert from 'assert'; -import * as sinon from 'sinon'; -import { anything, instance, mock, verify, when } from 'ts-mockito'; -import { IWorkspaceService } from '../../../client/common/application/types'; -import { WorkspaceService } from '../../../client/common/application/workspace'; -import { Product } from '../../../client/common/types'; -import { EnablementTracker } from '../../../client/testing/common/enablementTracker'; -import { TestConfigSettingsService } from '../../../client/testing/common/services/configSettingService'; -import { TestsHelper } from '../../../client/testing/common/testUtils'; -import { TestFlatteningVisitor } from '../../../client/testing/common/testVisitors/flatteningVisitor'; -import { ITestConfigSettingsService, ITestsHelper } from '../../../client/testing/common/types'; -import { TestProvider } from '../../../client/testing/types'; -import { noop } from '../../core'; - -suite('Unit Tests - Track Enablement', () => { - const sandbox = sinon.createSandbox(); - let workspaceService: IWorkspaceService; - let configService: ITestConfigSettingsService; - let testsHelper: ITestsHelper; - let enablementTracker: EnablementTracker; - setup(() => { - sandbox.restore(); - workspaceService = mock(WorkspaceService); - configService = mock(TestConfigSettingsService); - testsHelper = new TestsHelper(instance(mock(TestFlatteningVisitor))); - }); - teardown(() => { - sandbox.restore(); - }); - function createEnablementTracker() { - return new EnablementTracker(instance(workspaceService), [], instance(configService), testsHelper); - } - test('Add handler for onDidChangeConfiguration', async () => { - const stub = sinon.stub(); - when(workspaceService.onDidChangeConfiguration).thenReturn(stub); - - enablementTracker = createEnablementTracker(); - - await enablementTracker.activate(); - - assert.ok(stub.calledOnce); - }); - test('handler for onDidChangeConfiguration is onDidChangeConfiguration', async () => { - const stub = sinon.stub(); - when(workspaceService.onDidChangeConfiguration).thenReturn(stub); - - enablementTracker = createEnablementTracker(); - await enablementTracker.activate(); - - assert.equal(stub.args[0][0], enablementTracker.onDidChangeConfiguration); - assert.equal(stub.args[0][1], enablementTracker); - }); - test('If there are no workspaces and nothing changed, then do not send telemetry', async () => { - const telemetryReporter = sandbox.stub(EnablementTracker.prototype, 'sendTelemetry'); - telemetryReporter.callsFake(noop); - const affectsConfiguration = sinon.stub().returns(false); - when(workspaceService.workspaceFolders).thenReturn([]); - - enablementTracker = createEnablementTracker(); - enablementTracker.onDidChangeConfiguration({ affectsConfiguration }); - - assert.ok(telemetryReporter.notCalled); - assert.ok(affectsConfiguration.callCount > 0); - }); - test('Check whether unittest, pytest settings have been enabled', async () => { - const expectedSettingsChecked = ['python.testing.unittestEnabled', 'python.testing.pytestEnabled']; - - const telemetryReporter = sandbox.stub(EnablementTracker.prototype, 'sendTelemetry'); - telemetryReporter.callsFake(noop); - const affectsConfiguration = sinon.stub().returns(false); - when(workspaceService.workspaceFolders).thenReturn([]); - when(configService.getTestEnablingSetting(Product.unittest)).thenReturn('testing.unittestEnabled'); - when(configService.getTestEnablingSetting(Product.pytest)).thenReturn('testing.pytestEnabled'); - - enablementTracker = createEnablementTracker(); - enablementTracker.onDidChangeConfiguration({ affectsConfiguration }); - - verify(workspaceService.getConfiguration(anything(), anything())).never(); - assert.ok(telemetryReporter.notCalled); - assert.ok(affectsConfiguration.callCount > 0); - const settingsChecked = [affectsConfiguration.args[0][0], affectsConfiguration.args[1][0]]; - assert.deepEqual(settingsChecked.sort(), expectedSettingsChecked.sort()); - }); - test('Check settings related to unittest, pytest and nose', async () => { - const expectedSettingsChecked = ['python.testing.unittestEnabled', 'python.testing.pytestEnabled']; - const expectedSettingsRetrieved = ['testing.unittestEnabled', 'testing.pytestEnabled']; - - const telemetryReporter = sandbox.stub(EnablementTracker.prototype, 'sendTelemetry'); - telemetryReporter.callsFake(noop); - const affectsConfiguration = sinon.stub().returns(true); - const getConfigSettings = sinon.stub<[string], boolean>().returns(false); - - when(workspaceService.workspaceFolders).thenReturn([]); - - when(workspaceService.getConfiguration('python', anything())).thenReturn({ get: getConfigSettings } as any); - when(configService.getTestEnablingSetting(Product.unittest)).thenReturn('testing.unittestEnabled'); - when(configService.getTestEnablingSetting(Product.pytest)).thenReturn('testing.pytestEnabled'); - - enablementTracker = createEnablementTracker(); - enablementTracker.onDidChangeConfiguration({ affectsConfiguration }); - - verify(workspaceService.getConfiguration(anything(), anything())).atLeast(2); - assert.ok(telemetryReporter.notCalled); - assert.ok(affectsConfiguration.callCount > 0); - const settingsChecked = [affectsConfiguration.args[0][0], affectsConfiguration.args[1][0]]; - assert.deepEqual(settingsChecked.sort(), expectedSettingsChecked.sort()); - - const settingsRetrieved = [getConfigSettings.args[0][0], getConfigSettings.args[1][0]]; - assert.deepEqual(settingsRetrieved.sort(), expectedSettingsRetrieved.sort()); - }); - function testSendingTelemetry(sendForProvider: TestProvider) { - const expectedSettingsChecked = ['python.testing.unittestEnabled', 'python.testing.pytestEnabled']; - const expectedSettingsRetrieved = ['testing.unittestEnabled', 'testing.pytestEnabled']; - - const telemetryReporter = sandbox.stub(EnablementTracker.prototype, 'sendTelemetry'); - telemetryReporter.callsFake(noop); - const affectsConfiguration = sinon.stub().returns(true); - const getConfigSettings = sinon - .stub<[string], boolean>() - .callsFake((setting) => setting.includes(sendForProvider)); - - when(workspaceService.workspaceFolders).thenReturn([]); - - when(workspaceService.getConfiguration('python', anything())).thenReturn({ get: getConfigSettings } as any); - when(configService.getTestEnablingSetting(Product.unittest)).thenReturn('testing.unittestEnabled'); - when(configService.getTestEnablingSetting(Product.pytest)).thenReturn('testing.pytestEnabled'); - - enablementTracker = createEnablementTracker(); - enablementTracker.onDidChangeConfiguration({ affectsConfiguration }); - - verify(workspaceService.getConfiguration(anything(), anything())).atLeast(2); - assert.equal(telemetryReporter.callCount, 1); - assert.deepEqual(telemetryReporter.args[0][0], { [sendForProvider]: true }); - assert.ok(affectsConfiguration.callCount > 0); - const settingsChecked = [affectsConfiguration.args[0][0], affectsConfiguration.args[1][0]]; - assert.deepEqual(settingsChecked.sort(), expectedSettingsChecked.sort()); - - const settingsRetrieved = [getConfigSettings.args[0][0], getConfigSettings.args[1][0]]; - assert.deepEqual(settingsRetrieved.sort(), expectedSettingsRetrieved.sort()); - } - test('Send telemetry for unittest', () => testSendingTelemetry('unittest')); - test('Send telemetry for pytest', () => testSendingTelemetry('pytest')); -}); diff --git a/src/test/testing/common/xUnitParser.unit.test.ts b/src/test/testing/common/xUnitParser.unit.test.ts deleted file mode 100644 index de93424fb55b..000000000000 --- a/src/test/testing/common/xUnitParser.unit.test.ts +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { expect } from 'chai'; -import * as typeMoq from 'typemoq'; -import { IFileSystem } from '../../../client/common/platform/types'; -import { IXUnitParser, Tests, TestStatus } from '../../../client/testing/common/types'; -import { XUnitParser } from '../../../client/testing/common/xUnitParser'; -import { createDeclaratively, createEmptyResults, TestItem } from '../results'; - -suite('Testing - parse JUnit XML file', () => { - let parser: IXUnitParser; - let fs: typeMoq.IMock; - setup(() => { - fs = typeMoq.Mock.ofType(undefined, typeMoq.MockBehavior.Strict); - parser = new XUnitParser(fs.object); - }); - - function fixResult(node: TestItem, file: string, line: number) { - switch (node.status) { - case TestStatus.Pass: - node.passed = true; - break; - case TestStatus.Fail: - case TestStatus.Error: - node.passed = false; - break; - default: - node.passed = undefined; - } - node.file = file; - node.line = line; - } - - test('legacy - success with single passing test', async () => { - const tests = createDeclaratively(` - ./ - test_spam.py - - test_spam - `); - const expected = createDeclaratively(` - ./ - test_spam.py - - test_spam P 1.001 - `); - fixResult(expected.testFunctions[0].testFunction, 'test_spam.py', 3); - const filename = 'x/y/z/results.xml'; - fs.setup((f) => f.readFile(filename)).returns(() => - Promise.resolve(` - - - - - - `), - ); - - await parser.updateResultsFromXmlLogFile(tests, filename); - - expect(tests).to.deep.equal(expected); - fs.verifyAll(); - }); - - test('success with single passing test', async () => { - const tests = createDeclaratively(` - ./ - test_spam.py - - test_spam - `); - const expected = createDeclaratively(` - ./ - test_spam.py - - test_spam P 0.001 - `); - fixResult(expected.testFunctions[0].testFunction, 'test_spam.py', 3); - const filename = 'x/y/z/results.xml'; - fs.setup((f) => f.readFile(filename)).returns(() => - Promise.resolve(` - - - - - - - - `), - ); - - await parser.updateResultsFromXmlLogFile(tests, filename); - - expect(tests).to.deep.equal(expected); - fs.verifyAll(); - }); - - test('no discovered tests', async () => { - const tests: Tests = createEmptyResults(); - const expected: Tests = createEmptyResults(); - expected.summary.passed = 1; // That's a little strange... - const filename = 'x/y/z/results.xml'; - fs.setup((f) => f.readFile(filename)).returns(() => - Promise.resolve(` - - - - - - `), - ); - - await parser.updateResultsFromXmlLogFile(tests, filename); - - expect(tests).to.deep.equal(expected); - fs.verifyAll(); - }); - - test('no tests run', async () => { - const tests: Tests = createEmptyResults(); - const expected: Tests = createEmptyResults(); - const filename = 'x/y/z/results.xml'; - fs.setup((f) => f.readFile(filename)).returns(() => - Promise.resolve(` - - - - `), - ); - - await parser.updateResultsFromXmlLogFile(tests, filename); - - expect(tests).to.deep.equal(expected); - fs.verifyAll(); - }); - - // Missing tests (see https://github.com/microsoft/vscode-python/issues/7447): - // * simple pytest - // * complex - // * error - // * failure - // * skipped - // * no clobber old if not matching - // * ... -}); diff --git a/src/test/testing/configuration.unit.test.ts b/src/test/testing/configuration.unit.test.ts index 96c627d13fce..51b2d5641df1 100644 --- a/src/test/testing/configuration.unit.test.ts +++ b/src/test/testing/configuration.unit.test.ts @@ -12,7 +12,6 @@ import { getNamesAndValues } from '../../client/common/utils/enum'; import { IServiceContainer } from '../../client/ioc/types'; import { UNIT_TEST_PRODUCTS } from '../../client/testing/common/constants'; import { TestsHelper } from '../../client/testing/common/testUtils'; -import { TestFlatteningVisitor } from '../../client/testing/common/testVisitors/flatteningVisitor'; import { ITestConfigSettingsService, ITestConfigurationManager, @@ -79,10 +78,9 @@ suite('Unit Tests - ConfigurationService', () => { serviceContainer .setup((c) => c.get(typeMoq.It.isValue(ICommandManager))) .returns(() => commands.object); - const flattener = typeMoq.Mock.ofType(undefined, typeMoq.MockBehavior.Strict); serviceContainer .setup((c) => c.get(typeMoq.It.isValue(ITestsHelper))) - .returns(() => new TestsHelper(flattener.object)); + .returns(() => new TestsHelper()); testConfigService = typeMoq.Mock.ofType( UnitTestConfigurationService, typeMoq.MockBehavior.Loose, diff --git a/src/test/testing/debugger.test.ts b/src/test/testing/debugger.test.ts deleted file mode 100644 index 52be16c6060c..000000000000 --- a/src/test/testing/debugger.test.ts +++ /dev/null @@ -1,234 +0,0 @@ -import { assert, expect, use } from 'chai'; -import * as chaiAsPromised from 'chai-as-promised'; -import * as path from 'path'; -import { instance, mock } from 'ts-mockito'; -import { ConfigurationTarget } from 'vscode'; -import { CommandSource } from '../../client/common/constants'; -import { createDeferred } from '../../client/common/utils/async'; -import { ICondaService, IInterpreterService } from '../../client/interpreter/contracts'; -import { InterpreterService } from '../../client/interpreter/interpreterService'; -import { CondaService } from '../../client/pythonEnvironments/discovery/locators/services/condaService'; -import { TestManagerRunner as PytestManagerRunner } from '../../client/testing//pytest/runner'; -import { TestManagerRunner as UnitTestTestManagerRunner } from '../../client/testing//unittest/runner'; -import { ArgumentsHelper } from '../../client/testing/common/argumentsHelper'; -import { CANCELLATION_REASON, PYTEST_PROVIDER, UNITTEST_PROVIDER } from '../../client/testing/common/constants'; -import { TestRunner } from '../../client/testing/common/runner'; -import { - IArgumentsHelper, - IArgumentsService, - ITestDebugLauncher, - ITestManagerFactory, - ITestManagerRunner, - ITestMessageService, - ITestRunner, - IUnitTestHelper, - IXUnitParser, -} from '../../client/testing/common/types'; -import { XUnitParser } from '../../client/testing/common/xUnitParser'; -import { ArgumentsService as PyTestArgumentsService } from '../../client/testing/pytest/services/argsService'; -import { TestMessageService } from '../../client/testing/pytest/services/testMessageService'; -import { TestProvider } from '../../client/testing/types'; -import { UnitTestHelper } from '../../client/testing/unittest/helper'; -import { ArgumentsService as UnitTestArgumentsService } from '../../client/testing/unittest/services/argsService'; -import { deleteDirectory, rootWorkspaceUri, updateSetting } from '../common'; -import { initialize, initializeTest, IS_MULTI_ROOT_TEST, TEST_TIMEOUT } from './../initialize'; -import { MockDebugLauncher } from './mocks'; -import { UnitTestIocContainer } from './serviceRegistry'; - -use(chaiAsPromised); - -const testFilesPath = path.join(__dirname, '..', '..', '..', 'src', 'test', 'pythonFiles', 'testFiles', 'debuggerTest'); -const defaultUnitTestArgs = ['-v', '-s', '.', '-p', '*test*.py']; - -suite('Unit Tests - debugging', () => { - let ioc: UnitTestIocContainer; - const configTarget = IS_MULTI_ROOT_TEST ? ConfigurationTarget.WorkspaceFolder : ConfigurationTarget.Workspace; - suiteSetup(async function () { - this.timeout(TEST_TIMEOUT * 2); - // Test discovery is where the delay is, hence give 10 seconds (as we discover tests at least twice in each test). - await initialize(); - await Promise.all([ - updateSetting('testing.unittestArgs', defaultUnitTestArgs, rootWorkspaceUri, configTarget), - updateSetting('testing.pytestArgs', [], rootWorkspaceUri, configTarget), - ]); - }); - setup(async function () { - this.timeout(TEST_TIMEOUT * 2); // This hook requires more timeout as we're deleting files as well - await deleteDirectory(path.join(testFilesPath, '.cache')); - await initializeTest(); - await initializeDI(); - }); - teardown(async function () { - // It's been observed that each call to `updateSetting` can take upto 20 seconds on Windows, hence increasing timeout. - - this.timeout(TEST_TIMEOUT * 3); - await ioc.dispose(); - await Promise.all([ - updateSetting('testing.unittestArgs', defaultUnitTestArgs, rootWorkspaceUri, configTarget), - updateSetting('testing.pytestArgs', [], rootWorkspaceUri, configTarget), - ]); - }); - - async function initializeDI() { - ioc = new UnitTestIocContainer(); - ioc.registerCommonTypes(); - ioc.registerProcessTypes(); - ioc.registerVariableTypes(); - - ioc.registerTestParsers(); - ioc.registerTestVisitors(); - ioc.registerTestDiscoveryServices(); - ioc.registerTestDiagnosticServices(); - ioc.registerTestResultsHelper(); - ioc.registerTestStorage(); - ioc.registerTestsHelper(); - ioc.registerTestManagers(); - ioc.registerMockUnitTestSocketServer(); - ioc.registerInterpreterStorageTypes(); - await ioc.registerMockInterpreterTypes(); - ioc.serviceManager.add(IArgumentsHelper, ArgumentsHelper); - ioc.serviceManager.add(ITestRunner, TestRunner); - ioc.serviceManager.add(IXUnitParser, XUnitParser); - ioc.serviceManager.add(IUnitTestHelper, UnitTestHelper); - ioc.serviceManager.add(IArgumentsService, PyTestArgumentsService, PYTEST_PROVIDER); - ioc.serviceManager.add(IArgumentsService, UnitTestArgumentsService, UNITTEST_PROVIDER); - ioc.serviceManager.add(ITestManagerRunner, PytestManagerRunner, PYTEST_PROVIDER); - ioc.serviceManager.add(ITestManagerRunner, UnitTestTestManagerRunner, UNITTEST_PROVIDER); - ioc.serviceManager.addSingleton(ITestDebugLauncher, MockDebugLauncher); - ioc.serviceManager.addSingleton(ITestMessageService, TestMessageService, PYTEST_PROVIDER); - ioc.serviceManager.rebindInstance(ICondaService, instance(mock(CondaService))); - ioc.serviceManager.rebindInstance(IInterpreterService, instance(mock(InterpreterService))); - } - - async function testStartingDebugger(testProvider: TestProvider) { - const testManager = ioc.serviceContainer.get(ITestManagerFactory)( - testProvider, - rootWorkspaceUri!, - testFilesPath, - ); - const mockDebugLauncher = ioc.serviceContainer.get(ITestDebugLauncher); - const tests = await testManager.discoverTests(CommandSource.commandPalette, true, true); - assert.equal(tests.testFiles.length, 2, 'Incorrect number of test files'); - assert.equal(tests.testFunctions.length, 2, 'Incorrect number of test functions'); - assert.equal(tests.testSuites.length, 2, 'Incorrect number of test suites'); - - const deferred = createDeferred(); - const testFunction = [tests.testFunctions[0].testFunction]; - const runningPromise = testManager.runTest(CommandSource.commandPalette, { testFunction }, false, true); - - // This promise should never resolve nor reject. - runningPromise - .then(() => deferred.reject("Debugger stopped when it shouldn't have")) - .catch((error) => deferred.reject(error)); - - mockDebugLauncher.launched - .then((launched) => { - if (launched) { - deferred.resolve(''); - } else { - deferred.reject('Debugger not launched'); - } - }) - .catch((error) => deferred.reject(error)); - - await deferred.promise; - } - - test('Debugger should start (unittest)', async () => { - await updateSetting('testing.unittestArgs', ['-s=./tests', '-p=test_*.py'], rootWorkspaceUri, configTarget); - await testStartingDebugger('unittest'); - }); - - test('Debugger should start (pytest)', async () => { - await updateSetting('testing.pytestArgs', ['-k=test_'], rootWorkspaceUri, configTarget); - await testStartingDebugger('pytest'); - }); - - async function testStoppingDebugger(testProvider: TestProvider) { - const testManager = ioc.serviceContainer.get(ITestManagerFactory)( - testProvider, - rootWorkspaceUri!, - testFilesPath, - ); - const mockDebugLauncher = ioc.serviceContainer.get(ITestDebugLauncher); - const tests = await testManager.discoverTests(CommandSource.commandPalette, true, true); - assert.equal(tests.testFiles.length, 2, 'Incorrect number of test files'); - assert.equal(tests.testFunctions.length, 2, 'Incorrect number of test functions'); - assert.equal(tests.testSuites.length, 2, 'Incorrect number of test suites'); - - const testFunction = [tests.testFunctions[0].testFunction]; - const runningPromise = testManager.runTest(CommandSource.commandPalette, { testFunction }, false, true); - const launched = await mockDebugLauncher.launched; - assert.isTrue(launched, 'Debugger not launched'); - - const discoveryPromise = testManager.discoverTests(CommandSource.commandPalette, true, true, true); - await expect(runningPromise).to.be.rejectedWith( - CANCELLATION_REASON, - 'Incorrect reason for ending the debugger', - ); - await ioc.dispose(); // will cancel test discovery - await expect(discoveryPromise).to.be.rejectedWith( - CANCELLATION_REASON, - 'Incorrect reason for ending the debugger', - ); - } - - test('Debugger should stop when user invokes a test discovery (unittest)', async () => { - await updateSetting('testing.unittestArgs', ['-s=./tests', '-p=test_*.py'], rootWorkspaceUri, configTarget); - await testStoppingDebugger('unittest'); - }); - - test('Debugger should stop when user invokes a test discovery (pytest)', async () => { - await updateSetting('testing.pytestArgs', ['-k=test_'], rootWorkspaceUri, configTarget); - await testStoppingDebugger('pytest'); - }); - - async function testDebuggerWhenRediscoveringTests(testProvider: TestProvider) { - const testManager = ioc.serviceContainer.get(ITestManagerFactory)( - testProvider, - rootWorkspaceUri!, - testFilesPath, - ); - const mockDebugLauncher = ioc.serviceContainer.get(ITestDebugLauncher); - const tests = await testManager.discoverTests(CommandSource.commandPalette, true, true); - assert.equal(tests.testFiles.length, 2, 'Incorrect number of test files'); - assert.equal(tests.testFunctions.length, 2, 'Incorrect number of test functions'); - assert.equal(tests.testSuites.length, 2, 'Incorrect number of test suites'); - - const testFunction = [tests.testFunctions[0].testFunction]; - const runningPromise = testManager.runTest(CommandSource.commandPalette, { testFunction }, false, true); - const launched = await mockDebugLauncher.launched; - assert.isTrue(launched, 'Debugger not launched'); - - const discoveryPromise = testManager.discoverTests(CommandSource.commandPalette, false, true); - const deferred = createDeferred(); - - discoveryPromise - - .then(() => deferred.resolve('')) - - .catch((ex) => deferred.reject(ex)); - - // This promise should never resolve nor reject. - runningPromise - .then(() => "Debugger stopped when it shouldn't have") - .catch(() => "Debugger crashed when it shouldn't have") - - .then((error) => { - deferred.reject(error); - }); - - // Should complete without any errors - await deferred.promise; - } - - test('Debugger should not stop when test discovery is invoked automatically by extension (unittest)', async () => { - await updateSetting('testing.unittestArgs', ['-s=./tests', '-p=test_*.py'], rootWorkspaceUri, configTarget); - await testDebuggerWhenRediscoveringTests('unittest'); - }); - - test('Debugger should not stop when test discovery is invoked automatically by extension (pytest)', async () => { - await updateSetting('testing.pytestArgs', ['-k=test_'], rootWorkspaceUri, configTarget); - await testDebuggerWhenRediscoveringTests('pytest'); - }); -}); diff --git a/src/test/testing/main.unit.test.ts b/src/test/testing/main.unit.test.ts deleted file mode 100644 index 821eb1a408b3..000000000000 --- a/src/test/testing/main.unit.test.ts +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import * as sinon from 'sinon'; -import { anything, instance, mock, verify, when } from 'ts-mockito'; -import { Disposable } from 'vscode'; -import { CommandManager } from '../../client/common/application/commandManager'; -import { ICommandManager } from '../../client/common/application/types'; -import { IDisposableRegistry } from '../../client/common/types'; -import { ServiceContainer } from '../../client/ioc/container'; -import { IServiceContainer } from '../../client/ioc/types'; -import { UnitTestManagementService } from '../../client/testing/main'; - -suite('Unit Tests - ManagementService', () => { - suite('Experiments', () => { - let serviceContainer: IServiceContainer; - let sandbox: sinon.SinonSandbox; - let commandManager: ICommandManager; - let testManagementService: UnitTestManagementService; - setup(() => { - serviceContainer = mock(ServiceContainer); - sandbox = sinon.createSandbox(); - - sandbox.stub(UnitTestManagementService.prototype, 'registerCommands'); - sandbox.stub(UnitTestManagementService.prototype, 'registerHandlers'); - sandbox.stub(UnitTestManagementService.prototype, 'autoDiscoverTests').callsFake(() => Promise.resolve()); - - commandManager = mock(CommandManager); - - when(serviceContainer.get(IDisposableRegistry)).thenReturn([]); - when(serviceContainer.get(ICommandManager)).thenReturn(instance(commandManager)); - when(commandManager.executeCommand(anything(), anything(), anything())).thenResolve(); - - testManagementService = new UnitTestManagementService(instance(serviceContainer)); - }); - teardown(() => { - sandbox.restore(); - }); - - test('Do not execute command', async () => { - await testManagementService.activate(); - - verify(commandManager.executeCommand('setContext', 'testsDiscovered', anything())).never(); - }); - }); -}); diff --git a/src/test/testing/mocks.ts b/src/test/testing/mocks.ts index 06e7004478ff..fc2bf67bafbf 100644 --- a/src/test/testing/mocks.ts +++ b/src/test/testing/mocks.ts @@ -1,11 +1,7 @@ import { EventEmitter } from 'events'; import { injectable } from 'inversify'; import { CancellationToken, Disposable, Uri } from 'vscode'; -import { Product } from '../../client/common/types'; import { createDeferred, Deferred } from '../../client/common/utils/async'; -import { IServiceContainer } from '../../client/ioc/types'; -import { CANCELLATION_REASON } from '../../client/testing/common/constants'; -import { BaseTestManager } from '../../client/testing/common/managers/baseTestManager'; import { ITestDebugLauncher, ITestDiscoveryService, @@ -13,9 +9,7 @@ import { LaunchOptions, TestDiscoveryOptions, Tests, - TestsToRun, } from '../../client/testing/common/types'; -import { TestProvider } from '../../client/testing/types'; @injectable() export class MockDebugLauncher implements ITestDebugLauncher, Disposable { @@ -61,44 +55,6 @@ export class MockDebugLauncher implements ITestDebugLauncher, Disposable { } } -@injectable() -export class MockTestManagerWithRunningTests extends BaseTestManager { - public readonly runnerDeferred = createDeferred(); - public readonly enabled = true; - - public readonly discoveryDeferred = createDeferred(); - constructor( - testProvider: TestProvider, - product: Product, - workspaceFolder: Uri, - rootDirectory: string, - serviceContainer: IServiceContainer, - ) { - super(testProvider, product, workspaceFolder, rootDirectory, serviceContainer); - } - protected getDiscoveryOptions(_ignoreCache: boolean) { - return {} as TestDiscoveryOptions; - } - - protected async runTestImpl( - _tests: Tests, - _testsToRun?: TestsToRun, - _runFailedTests?: boolean, - _debug?: boolean, - ): Promise { - this.testRunnerCancellationToken!.onCancellationRequested(() => { - this.runnerDeferred.reject(CANCELLATION_REASON); - }); - return this.runnerDeferred.promise; - } - protected async discoverTestsImpl(_ignoreCache: boolean, _debug?: boolean): Promise { - this.testDiscoveryCancellationToken!.onCancellationRequested(() => { - this.discoveryDeferred.reject(CANCELLATION_REASON); - }); - return this.discoveryDeferred.promise; - } -} - @injectable() export class MockDiscoveryService implements ITestDiscoveryService { constructor(private discoverPromise: Promise) {} diff --git a/src/test/testing/navigation/symbolNavigator.unit.test.ts b/src/test/testing/navigation/symbolNavigator.unit.test.ts deleted file mode 100644 index 6658848bbeb9..000000000000 --- a/src/test/testing/navigation/symbolNavigator.unit.test.ts +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { expect } from 'chai'; -import * as path from 'path'; -import * as typemoq from 'typemoq'; -import { - CancellationToken, - CancellationTokenSource, - Range, - SymbolInformation, - SymbolKind, - TextDocument, - Uri, -} from 'vscode'; -import { - ExecutionResult, - IPythonExecutionFactory, - IPythonExecutionService, -} from '../../../client/common/process/types'; -import { IDocumentSymbolProvider } from '../../../client/common/types'; -import { EXTENSION_ROOT_DIR } from '../../../client/constants'; -import { TestFileSymbolProvider } from '../../../client/testing/navigation/symbolProvider'; - -suite('Unit Tests - Navigation Command Handler', () => { - let symbolProvider: IDocumentSymbolProvider; - let pythonExecFactory: typemoq.IMock; - let pythonService: typemoq.IMock; - let doc: typemoq.IMock; - let token: CancellationToken; - setup(() => { - pythonService = typemoq.Mock.ofType(); - pythonExecFactory = typemoq.Mock.ofType(); - - // Both typemoq and ts-mockito fail to resolve promises on dynamically created mocks - // A solution is to mock the `then` on the mock that the `Promise` resolves to. - // typemoq: https://github.com/florinn/typemoq/issues/66#issuecomment-315681245 - // ts-mockito: https://github.com/NagRock/ts-mockito/issues/163#issuecomment-536210863 - // In this case, the factory below returns a promise that is a mock of python service - // so we need to mock the `then` on the service. - pythonService.setup((x: any) => x.then).returns(() => undefined); - - pythonExecFactory - .setup((factory) => factory.create(typemoq.It.isAny())) - .returns(async () => pythonService.object); - - doc = typemoq.Mock.ofType(); - token = new CancellationTokenSource().token; - }); - test('Ensure no symbols are returned when file has not been saved', async () => { - doc.setup((d) => d.isUntitled) - .returns(() => true) - .verifiable(typemoq.Times.once()); - - symbolProvider = new TestFileSymbolProvider(pythonExecFactory.object); - const symbols = await symbolProvider.provideDocumentSymbols(doc.object, token); - - expect(symbols).to.be.lengthOf(0); - doc.verifyAll(); - }); - test('Ensure no symbols are returned when there are errors in running the code', async () => { - doc.setup((d) => d.isUntitled) - .returns(() => false) - .verifiable(typemoq.Times.once()); - doc.setup((d) => d.isDirty) - .returns(() => false) - .verifiable(typemoq.Times.once()); - doc.setup((d) => d.uri) - .returns(() => Uri.file(__filename)) - .verifiable(typemoq.Times.atLeastOnce()); - - pythonService - .setup((service) => service.exec(typemoq.It.isAny(), typemoq.It.isAny())) - .returns(async () => { - return { stdout: '' }; - }); - - symbolProvider = new TestFileSymbolProvider(pythonExecFactory.object); - const symbols = await symbolProvider.provideDocumentSymbols(doc.object, token); - - expect(symbols).to.be.lengthOf(0); - doc.verifyAll(); - }); - test('Ensure no symbols are returned when there are no symbols to be returned', async () => { - const docUri = Uri.file(__filename); - const args = [path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'symbolProvider.py'), docUri.fsPath]; - const proc: ExecutionResult = { - stdout: JSON.stringify({ classes: [], methods: [], functions: [] }), - }; - doc.setup((d) => d.isUntitled) - .returns(() => false) - .verifiable(typemoq.Times.once()); - doc.setup((d) => d.isDirty) - .returns(() => false) - .verifiable(typemoq.Times.once()); - doc.setup((d) => d.uri) - .returns(() => docUri) - .verifiable(typemoq.Times.atLeastOnce()); - - pythonService - .setup((service) => service.exec(typemoq.It.isValue(args), typemoq.It.isAny())) - .returns(async () => proc) - .verifiable(typemoq.Times.once()); - - symbolProvider = new TestFileSymbolProvider(pythonExecFactory.object); - const symbols = await symbolProvider.provideDocumentSymbols(doc.object, token); - - expect(symbols).to.be.lengthOf(0); - doc.verifyAll(); - pythonService.verifyAll(); - }); - test('Ensure symbols are returned', async () => { - const docUri = Uri.file(__filename); - const args = [path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'symbolProvider.py'), docUri.fsPath]; - const proc: ExecutionResult = { - stdout: JSON.stringify({ - classes: [ - { - namespace: '1', - name: 'one', - kind: SymbolKind.Class, - range: { start: { line: 1, character: 2 }, end: { line: 3, character: 4 } }, - }, - ], - methods: [ - { - namespace: '2', - name: 'two', - kind: SymbolKind.Class, - range: { start: { line: 5, character: 6 }, end: { line: 7, character: 8 } }, - }, - ], - functions: [ - { - namespace: '3', - name: 'three', - kind: SymbolKind.Class, - range: { start: { line: 9, character: 10 }, end: { line: 11, character: 12 } }, - }, - ], - }), - }; - doc.setup((d) => d.isUntitled) - .returns(() => false) - .verifiable(typemoq.Times.once()); - doc.setup((d) => d.isDirty) - .returns(() => false) - .verifiable(typemoq.Times.once()); - doc.setup((d) => d.uri) - .returns(() => docUri) - .verifiable(typemoq.Times.atLeastOnce()); - - pythonService - .setup((service) => service.exec(typemoq.It.isValue(args), typemoq.It.isAny())) - .returns(async () => proc) - .verifiable(typemoq.Times.once()); - - symbolProvider = new TestFileSymbolProvider(pythonExecFactory.object); - const symbols = (await symbolProvider.provideDocumentSymbols(doc.object, token)) as SymbolInformation[]; - - expect(symbols).to.be.lengthOf(3); - doc.verifyAll(); - pythonService.verifyAll(); - expect(symbols[0].kind).to.be.equal(SymbolKind.Class); - expect(symbols[0].name).to.be.equal('one'); - expect(symbols[0].location.range).to.be.deep.equal(new Range(1, 2, 3, 4)); - - expect(symbols[1].kind).to.be.equal(SymbolKind.Method); - expect(symbols[1].name).to.be.equal('two'); - expect(symbols[1].location.range).to.be.deep.equal(new Range(5, 6, 7, 8)); - - expect(symbols[2].kind).to.be.equal(SymbolKind.Function); - expect(symbols[2].name).to.be.equal('three'); - expect(symbols[2].location.range).to.be.deep.equal(new Range(9, 10, 11, 12)); - }); -}); diff --git a/src/test/testing/pytest/pytest.argsService.unit.test.ts b/src/test/testing/pytest/pytest.argsService.unit.test.ts deleted file mode 100644 index fb9f8a19beae..000000000000 --- a/src/test/testing/pytest/pytest.argsService.unit.test.ts +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { expect } from 'chai'; -import * as path from 'path'; -import * as typeMoq from 'typemoq'; -import { IServiceContainer } from '../../../client/ioc/types'; -import { ArgumentsHelper } from '../../../client/testing/common/argumentsHelper'; -import { IArgumentsHelper } from '../../../client/testing/common/types'; -import { ArgumentsService as PyTestArgumentsService } from '../../../client/testing/pytest/services/argsService'; - -suite('ArgsService: pytest', () => { - let argumentsService: PyTestArgumentsService; - - suiteSetup(() => { - const serviceContainer = typeMoq.Mock.ofType(); - - const argsHelper = new ArgumentsHelper(); - - serviceContainer - .setup((s) => s.get(typeMoq.It.isValue(IArgumentsHelper), typeMoq.It.isAny())) - .returns(() => argsHelper); - - argumentsService = new PyTestArgumentsService(serviceContainer.object); - }); - - test('Test getting the test folder in pytest', () => { - const dir = path.join('a', 'b', 'c'); - const args = ['--one', '--rootdir', dir]; - const testDirs = argumentsService.getTestFolders(args); - expect(testDirs).to.be.lengthOf(1); - expect(testDirs[0]).to.equal(dir); - }); - test('Test getting the test folder in pytest (with folder before the arguments)', () => { - const dir = path.join('a', 'b', 'c'); - const args = [dir, '--one', '--rootdir']; - const testDirs = argumentsService.getTestFolders(args); - expect(testDirs).to.be.lengthOf(1); - expect(testDirs[0]).to.equal(dir); - }); - test('Test getting the test folder in pytest (with multiple dirs)', () => { - const dir = path.join('a', 'b', 'c'); - const dir2 = path.join('a', 'b', '2'); - const args = ['anzy', '--one', '--rootdir', dir, '--rootdir', dir2]; - const testDirs = argumentsService.getTestFolders(args); - expect(testDirs).to.be.lengthOf(2); - expect(testDirs[0]).to.equal(dir); - expect(testDirs[1]).to.equal(dir2); - }); - test('Test getting the test folder in pytest (with multiple dirs in the middle)', () => { - const dir = path.join('a', 'b', 'c'); - const dir2 = path.join('a', 'b', '2'); - const args = ['anzy', '--one', '--rootdir', dir, '--rootdir', dir2, '-xyz']; - const testDirs = argumentsService.getTestFolders(args); - expect(testDirs).to.be.lengthOf(2); - expect(testDirs[0]).to.equal(dir); - expect(testDirs[1]).to.equal(dir2); - }); - test('Test getting the test folder in pytest (with single positional dir)', () => { - const dir = path.join('a', 'b', 'c'); - const args = ['--one', dir]; - const testDirs = argumentsService.getTestFolders(args); - expect(testDirs).to.be.lengthOf(1); - expect(testDirs[0]).to.equal(dir); - }); - test('Test getting the test folder in pytest (with multiple positional dirs)', () => { - const dir = path.join('a', 'b', 'c'); - const dir2 = path.join('a', 'b', '2'); - const args = ['--one', dir, dir2]; - const testDirs = argumentsService.getTestFolders(args); - expect(testDirs).to.be.lengthOf(2); - expect(testDirs[0]).to.equal(dir); - expect(testDirs[1]).to.equal(dir2); - }); - test('Test getting the test folder in pytest (with multiple dirs excluding python files)', () => { - const dir = path.join('a', 'b', 'c'); - const dir2 = path.join('a', 'b', '2'); - const args = ['anzy', '--one', dir, dir2, path.join(dir, 'one.py')]; - const testDirs = argumentsService.getTestFolders(args); - expect(testDirs).to.be.lengthOf(3); - expect(testDirs[0]).to.equal('anzy'); - expect(testDirs[1]).to.equal(dir); - expect(testDirs[2]).to.equal(dir2); - }); - test('Test getting the list of known options for pytest', () => { - const knownOptions = argumentsService.getKnownOptions(); - expect(knownOptions.withArgs.length).to.not.equal(0); - expect(knownOptions.withoutArgs.length).to.not.equal(0); - }); - test('Test calling ArgumentsService.getOptionValue with the option followed by the value', () => { - const knownOptionsWithValues = argumentsService.getKnownOptions().withArgs; - knownOptionsWithValues.forEach((option) => { - const args = ['--foo', '--bar', 'arg1', option, 'value1']; - expect(argumentsService.getOptionValue(args, option)).to.deep.equal('value1'); - }); - }); - test('Test calling ArgumentsService.getOptionValue with the inline option syntax', () => { - const knownOptionsWithValues = argumentsService.getKnownOptions().withArgs; - knownOptionsWithValues.forEach((option) => { - const args = ['--foo', '--bar', 'arg1', `${option}=value1`]; - expect(argumentsService.getOptionValue(args, option)).to.deep.equal('value1'); - }); - }); -}); diff --git a/src/test/testing/pytest/pytest.discovery.test.ts b/src/test/testing/pytest/pytest.discovery.test.ts deleted file mode 100644 index 46216dc7df49..000000000000 --- a/src/test/testing/pytest/pytest.discovery.test.ts +++ /dev/null @@ -1,1019 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -import * as assert from 'assert'; -import { inject, injectable } from 'inversify'; -import * as path from 'path'; -import { instance, mock } from 'ts-mockito'; -import * as vscode from 'vscode'; -import { CommandSource, EXTENSION_ROOT_DIR } from '../../../client/common/constants'; -import { IFileSystem } from '../../../client/common/platform/types'; -import { createPythonEnv } from '../../../client/common/process/pythonEnvironment'; -import { PythonExecutionFactory } from '../../../client/common/process/pythonExecutionFactory'; -import { createPythonProcessService } from '../../../client/common/process/pythonProcess'; -import { - ExecutionFactoryCreateWithEnvironmentOptions, - IBufferDecoder, - IProcessServiceFactory, - IPythonExecutionFactory, - IPythonExecutionService, -} from '../../../client/common/process/types'; -import { IConfigurationService, IExperimentService } from '../../../client/common/types'; -import { IEnvironmentActivationService } from '../../../client/interpreter/activation/types'; -import { IComponentAdapter, ICondaService, IInterpreterService } from '../../../client/interpreter/contracts'; -import { InterpreterService } from '../../../client/interpreter/interpreterService'; -import { IServiceContainer } from '../../../client/ioc/types'; -import { CondaService } from '../../../client/pythonEnvironments/discovery/locators/services/condaService'; -import { ITestManagerFactory } from '../../../client/testing/common/types'; -import { rootWorkspaceUri, updateSetting } from '../../common'; -import { initialize, initializeTest, IS_MULTI_ROOT_TEST } from '../../initialize'; -import { MockProcessService } from '../../mocks/proc'; -import { registerForIOC } from '../../pythonEnvironments/legacyIOC'; -import { UnitTestIocContainer } from '../serviceRegistry'; - -const UNITTEST_TEST_FILES_PATH = path.join(EXTENSION_ROOT_DIR, 'src', 'test', 'pythonFiles', 'testFiles', 'standard'); -const UNITTEST_SINGLE_TEST_FILE_PATH = path.join( - EXTENSION_ROOT_DIR, - 'src', - 'test', - 'pythonFiles', - 'testFiles', - 'single', -); -const UNITTEST_TEST_FILES_PATH_WITH_CONFIGS = path.join( - EXTENSION_ROOT_DIR, - 'src', - 'test', - 'pythonFiles', - 'testFiles', - 'unittestsWithConfigs', -); -const unitTestTestFilesCwdPath = path.join(EXTENSION_ROOT_DIR, 'src', 'test', 'pythonFiles', 'testFiles', 'cwd', 'src'); - -/* -These test results are from `/src/test/pythonFiles/testFiles/...` directories. -Run the command `python /pythonFiles/testing_tools/run_adapter.py discover pytest -- -s --cache-clear` to get the JSON output. -*/ - -suite('Unit Tests - pytest - discovery with mocked process output', () => { - let ioc: UnitTestIocContainer; - const configTarget = IS_MULTI_ROOT_TEST - ? vscode.ConfigurationTarget.WorkspaceFolder - : vscode.ConfigurationTarget.Workspace; - @injectable() - class ExecutionFactory extends PythonExecutionFactory { - constructor( - @inject(IServiceContainer) private readonly _serviceContainer: IServiceContainer, - @inject(IEnvironmentActivationService) activationHelper: IEnvironmentActivationService, - @inject(IProcessServiceFactory) processServiceFactory: IProcessServiceFactory, - @inject(IConfigurationService) private readonly _configService: IConfigurationService, - @inject(ICondaService) condaService: ICondaService, - @inject(IBufferDecoder) decoder: IBufferDecoder, - @inject(IComponentAdapter) pyenvs: IComponentAdapter, - @inject(IExperimentService) experimentService: IExperimentService, - ) { - super( - _serviceContainer, - activationHelper, - processServiceFactory, - _configService, - condaService, - decoder, - pyenvs, - experimentService, - ); - } - - public async createActivatedEnvironment( - options: ExecutionFactoryCreateWithEnvironmentOptions, - ): Promise { - const pythonPath = options.interpreter - ? options.interpreter.path - : this._configService.getSettings(options.resource).pythonPath; - const procService = (await ioc.serviceContainer - .get(IProcessServiceFactory) - .create()) as MockProcessService; - const fileSystem = this._serviceContainer.get(IFileSystem); - const env = createPythonEnv(pythonPath, procService, fileSystem); - const procs = createPythonProcessService(procService, env); - - return { - getInterpreterInformation: () => env.getInterpreterInformation(), - getExecutablePath: () => env.getExecutablePath(), - isModuleInstalled: (m) => env.isModuleInstalled(m), - getModuleVersion: (m) => env.getModuleVersion(m), - getExecutionInfo: (a) => env.getExecutionInfo(a), - execObservable: (a, o) => procs.execObservable(a, o), - execModuleObservable: (m, a, o) => procs.execModuleObservable(m, a, o), - exec: (a, o) => procs.exec(a, o), - execModule: (m, a, o) => procs.execModule(m, a, o), - }; - } - } - suiteSetup(async () => { - await initialize(); - await updateSetting('testing.pytestArgs', [], rootWorkspaceUri, configTarget); - }); - setup(async () => { - await initializeTest(); - await initializeDI(); - }); - teardown(async () => { - await ioc.dispose(); - await updateSetting('testing.pytestArgs', [], rootWorkspaceUri, configTarget); - }); - - async function initializeDI() { - ioc = new UnitTestIocContainer(); - ioc.registerCommonTypes(); - ioc.registerUnitTestTypes(); - ioc.registerVariableTypes(); - - // Mocks. - ioc.registerMockProcessTypes(); - ioc.registerInterpreterStorageTypes(); - ioc.serviceManager.addSingletonInstance( - IInterpreterService, - instance(mock(InterpreterService)), - ); - ioc.serviceManager.rebind(IPythonExecutionFactory, ExecutionFactory); - await registerForIOC(ioc.serviceManager, ioc.serviceContainer); - ioc.serviceManager.rebindInstance(ICondaService, instance(mock(CondaService))); - } - - async function injectTestDiscoveryOutput(output: string) { - const procService = (await ioc.serviceContainer - .get(IProcessServiceFactory) - .create()) as MockProcessService; - procService.onExec((_file, args, _options, callback) => { - if (args.indexOf('discover') >= 0 && args.indexOf('pytest') >= 0) { - callback({ - stdout: output, - }); - } - }); - } - - test('Discover Tests (single test file)', async () => { - await injectTestDiscoveryOutput( - JSON.stringify([ - { - rootid: '.', - root: - '/Users/donjayamanne/.vscode-insiders/extensions/pythonVSCode/src/test/pythonFiles/testFiles/single', - parents: [ - { - id: './test_root.py', - kind: 'file', - name: 'test_root.py', - relpath: './test_root.py', - parentid: '.', - }, - { - id: './test_root.py::Test_Root_test1', - kind: 'suite', - name: 'Test_Root_test1', - parentid: './test_root.py', - }, - { - id: './tests', - kind: 'folder', - name: 'tests', - relpath: './tests', - parentid: '.', - }, - { - id: './tests/test_one.py', - kind: 'file', - name: 'test_one.py', - relpath: './tests/test_one.py', - parentid: './tests', - }, - { - id: './tests/test_one.py::Test_test1', - kind: 'suite', - name: 'Test_test1', - parentid: './tests/test_one.py', - }, - ], - tests: [ - { - id: './test_root.py::Test_Root_test1::test_Root_A', - name: 'test_Root_A', - source: './test_root.py:6', - markers: [], - parentid: './test_root.py::Test_Root_test1', - }, - { - id: './test_root.py::Test_Root_test1::test_Root_B', - name: 'test_Root_B', - source: './test_root.py:9', - markers: [], - parentid: './test_root.py::Test_Root_test1', - }, - { - id: './test_root.py::Test_Root_test1::test_Root_c', - name: 'test_Root_c', - source: './test_root.py:12', - markers: [], - parentid: './test_root.py::Test_Root_test1', - }, - { - id: './tests/test_one.py::Test_test1::test_A', - name: 'test_A', - source: 'tests/test_one.py:6', - markers: [], - parentid: './tests/test_one.py::Test_test1', - }, - { - id: './tests/test_one.py::Test_test1::test_B', - name: 'test_B', - source: 'tests/test_one.py:9', - markers: [], - parentid: './tests/test_one.py::Test_test1', - }, - { - id: './tests/test_one.py::Test_test1::test_c', - name: 'test_c', - source: 'tests/test_one.py:12', - markers: [], - parentid: './tests/test_one.py::Test_test1', - }, - ], - }, - ]), - ); - const factory = ioc.serviceContainer.get(ITestManagerFactory); - const testManager = factory('pytest', rootWorkspaceUri!, UNITTEST_SINGLE_TEST_FILE_PATH); - const tests = await testManager.discoverTests(CommandSource.ui, true, true); - const diagnosticCollectionUris: vscode.Uri[] = []; - testManager.diagnosticCollection.forEach((uri) => { - diagnosticCollectionUris.push(uri); - }); - assert.equal(diagnosticCollectionUris.length, 0, 'Should not have diagnostics yet'); - assert.equal(tests.testFiles.length, 2, 'Incorrect number of test files'); - assert.equal(tests.testFunctions.length, 6, 'Incorrect number of test functions'); - assert.equal(tests.testSuites.length, 2, 'Incorrect number of test suites'); - assert.equal( - tests.testFiles.some((t) => t.name === 'test_one.py'), - true, - 'Test File not found', - ); - assert.equal( - tests.testFiles.some((t) => t.name === 'test_root.py'), - true, - 'Test File not found', - ); - }); - - test('Discover Tests (pattern = test_)', async () => { - await injectTestDiscoveryOutput( - JSON.stringify([ - { - rootid: '.', - root: - '/Users/donjayamanne/.vscode-insiders/extensions/pythonVSCode/src/test/pythonFiles/testFiles/standard', - parents: [ - { - id: './test_root.py', - relpath: './test_root.py', - kind: 'file', - name: 'test_root.py', - parentid: '.', - }, - { - id: './test_root.py::Test_Root_test1', - kind: 'suite', - name: 'Test_Root_test1', - parentid: './test_root.py', - }, - { - id: './tests', - relpath: './tests', - kind: 'folder', - name: 'tests', - parentid: '.', - }, - { - id: './tests/test_another_pytest.py', - relpath: './tests/test_another_pytest.py', - kind: 'file', - name: 'test_another_pytest.py', - parentid: './tests', - }, - { - id: './tests/test_another_pytest.py::test_parametrized_username', - kind: 'function', - name: 'test_parametrized_username', - parentid: './tests/test_another_pytest.py', - }, - { - id: './tests/test_foreign_nested_tests.py', - relpath: './tests/test_foreign_nested_tests.py', - kind: 'file', - name: 'test_foreign_nested_tests.py', - parentid: './tests', - }, - { - id: './tests/test_foreign_nested_tests.py::TestNestedForeignTests', - kind: 'suite', - name: 'TestNestedForeignTests', - parentid: './tests/test_foreign_nested_tests.py', - }, - { - id: './tests/test_foreign_nested_tests.py::TestNestedForeignTests::TestInheritingHere', - kind: 'suite', - name: 'TestInheritingHere', - parentid: './tests/test_foreign_nested_tests.py::TestNestedForeignTests', - }, - { - id: - './tests/test_foreign_nested_tests.py::TestNestedForeignTests::TestInheritingHere::TestExtraNestedForeignTests', - kind: 'suite', - name: 'TestExtraNestedForeignTests', - parentid: - './tests/test_foreign_nested_tests.py::TestNestedForeignTests::TestInheritingHere', - }, - { - id: './tests/test_pytest.py', - relpath: './tests/test_pytest.py', - kind: 'file', - name: 'test_pytest.py', - parentid: './tests', - }, - { - id: './tests/test_pytest.py::Test_CheckMyApp', - kind: 'suite', - name: 'Test_CheckMyApp', - parentid: './tests/test_pytest.py', - }, - { - id: './tests/test_pytest.py::Test_CheckMyApp::Test_NestedClassA', - kind: 'suite', - name: 'Test_NestedClassA', - parentid: './tests/test_pytest.py::Test_CheckMyApp', - }, - { - id: './tests/test_pytest.py::Test_CheckMyApp::Test_NestedClassA::Test_nested_classB_Of_A', - kind: 'suite', - name: 'Test_nested_classB_Of_A', - parentid: './tests/test_pytest.py::Test_CheckMyApp::Test_NestedClassA', - }, - { - id: './tests/test_pytest.py::test_parametrized_username', - kind: 'function', - name: 'test_parametrized_username', - parentid: './tests/test_pytest.py', - }, - { - id: './tests/test_unittest_one.py', - relpath: './tests/test_unittest_one.py', - kind: 'file', - name: 'test_unittest_one.py', - parentid: './tests', - }, - { - id: './tests/test_unittest_one.py::Test_test1', - kind: 'suite', - name: 'Test_test1', - parentid: './tests/test_unittest_one.py', - }, - { - id: './tests/test_unittest_two.py', - relpath: './tests/test_unittest_two.py', - kind: 'file', - name: 'test_unittest_two.py', - parentid: './tests', - }, - { - id: './tests/test_unittest_two.py::Test_test2', - kind: 'suite', - name: 'Test_test2', - parentid: './tests/test_unittest_two.py', - }, - { - id: './tests/test_unittest_two.py::Test_test2a', - kind: 'suite', - name: 'Test_test2a', - parentid: './tests/test_unittest_two.py', - }, - { - id: './tests/unittest_three_test.py', - relpath: './tests/unittest_three_test.py', - kind: 'file', - name: 'unittest_three_test.py', - parentid: './tests', - }, - { - id: './tests/unittest_three_test.py::Test_test3', - kind: 'suite', - name: 'Test_test3', - parentid: './tests/unittest_three_test.py', - }, - ], - tests: [ - { - id: './test_root.py::Test_Root_test1::test_Root_A', - name: 'test_Root_A', - source: './test_root.py:6', - markers: [], - parentid: './test_root.py::Test_Root_test1', - }, - { - id: './test_root.py::Test_Root_test1::test_Root_B', - name: 'test_Root_B', - source: './test_root.py:9', - markers: [], - parentid: './test_root.py::Test_Root_test1', - }, - { - id: './test_root.py::Test_Root_test1::test_Root_c', - name: 'test_Root_c', - source: './test_root.py:12', - markers: [], - parentid: './test_root.py::Test_Root_test1', - }, - { - id: './tests/test_another_pytest.py::test_username', - name: 'test_username', - source: 'tests/test_another_pytest.py:12', - markers: [], - parentid: './tests/test_another_pytest.py', - }, - { - id: './tests/test_another_pytest.py::test_parametrized_username[one]', - name: 'test_parametrized_username[one]', - source: 'tests/test_another_pytest.py:15', - markers: [], - parentid: './tests/test_another_pytest.py::test_parametrized_username', - }, - { - id: './tests/test_another_pytest.py::test_parametrized_username[two]', - name: 'test_parametrized_username[two]', - source: 'tests/test_another_pytest.py:15', - markers: [], - parentid: './tests/test_another_pytest.py::test_parametrized_username', - }, - { - id: './tests/test_another_pytest.py::test_parametrized_username[three]', - name: 'test_parametrized_username[three]', - source: 'tests/test_another_pytest.py:15', - markers: [], - parentid: './tests/test_another_pytest.py::test_parametrized_username', - }, - { - id: - './tests/test_foreign_nested_tests.py::TestNestedForeignTests::TestInheritingHere::TestExtraNestedForeignTests::test_super_deep_foreign', - name: 'test_super_deep_foreign', - source: 'tests/external.py:2', - markers: [], - parentid: - './tests/test_foreign_nested_tests.py::TestNestedForeignTests::TestInheritingHere::TestExtraNestedForeignTests', - }, - { - id: - './tests/test_foreign_nested_tests.py::TestNestedForeignTests::TestInheritingHere::test_foreign_test', - name: 'test_foreign_test', - source: 'tests/external.py:4', - markers: [], - parentid: - './tests/test_foreign_nested_tests.py::TestNestedForeignTests::TestInheritingHere', - }, - { - id: - './tests/test_foreign_nested_tests.py::TestNestedForeignTests::TestInheritingHere::test_nested_normal', - name: 'test_nested_normal', - source: 'tests/test_foreign_nested_tests.py:5', - markers: [], - parentid: - './tests/test_foreign_nested_tests.py::TestNestedForeignTests::TestInheritingHere', - }, - { - id: './tests/test_foreign_nested_tests.py::TestNestedForeignTests::test_normal', - name: 'test_normal', - source: 'tests/test_foreign_nested_tests.py:7', - markers: [], - parentid: './tests/test_foreign_nested_tests.py::TestNestedForeignTests', - }, - { - id: './tests/test_pytest.py::Test_CheckMyApp::test_simple_check', - name: 'test_simple_check', - source: 'tests/test_pytest.py:6', - markers: [], - parentid: './tests/test_pytest.py::Test_CheckMyApp', - }, - { - id: './tests/test_pytest.py::Test_CheckMyApp::test_complex_check', - name: 'test_complex_check', - source: 'tests/test_pytest.py:9', - markers: [], - parentid: './tests/test_pytest.py::Test_CheckMyApp', - }, - { - id: './tests/test_pytest.py::Test_CheckMyApp::Test_NestedClassA::test_nested_class_methodB', - name: 'test_nested_class_methodB', - source: 'tests/test_pytest.py:13', - markers: [], - parentid: './tests/test_pytest.py::Test_CheckMyApp::Test_NestedClassA', - }, - { - id: - './tests/test_pytest.py::Test_CheckMyApp::Test_NestedClassA::Test_nested_classB_Of_A::test_d', - name: 'test_d', - source: 'tests/test_pytest.py:16', - markers: [], - parentid: - './tests/test_pytest.py::Test_CheckMyApp::Test_NestedClassA::Test_nested_classB_Of_A', - }, - { - id: './tests/test_pytest.py::Test_CheckMyApp::Test_NestedClassA::test_nested_class_methodC', - name: 'test_nested_class_methodC', - source: 'tests/test_pytest.py:18', - markers: [], - parentid: './tests/test_pytest.py::Test_CheckMyApp::Test_NestedClassA', - }, - { - id: './tests/test_pytest.py::Test_CheckMyApp::test_simple_check2', - name: 'test_simple_check2', - source: 'tests/test_pytest.py:21', - markers: [], - parentid: './tests/test_pytest.py::Test_CheckMyApp', - }, - { - id: './tests/test_pytest.py::Test_CheckMyApp::test_complex_check2', - name: 'test_complex_check2', - source: 'tests/test_pytest.py:23', - markers: [], - parentid: './tests/test_pytest.py::Test_CheckMyApp', - }, - { - id: './tests/test_pytest.py::test_username', - name: 'test_username', - source: 'tests/test_pytest.py:35', - markers: [], - parentid: './tests/test_pytest.py', - }, - { - id: './tests/test_pytest.py::test_parametrized_username[one]', - name: 'test_parametrized_username[one]', - source: 'tests/test_pytest.py:38', - markers: [], - parentid: './tests/test_pytest.py::test_parametrized_username', - }, - { - id: './tests/test_pytest.py::test_parametrized_username[two]', - name: 'test_parametrized_username[two]', - source: 'tests/test_pytest.py:38', - markers: [], - parentid: './tests/test_pytest.py::test_parametrized_username', - }, - { - id: './tests/test_pytest.py::test_parametrized_username[three]', - name: 'test_parametrized_username[three]', - source: 'tests/test_pytest.py:38', - markers: [], - parentid: './tests/test_pytest.py::test_parametrized_username', - }, - { - id: './tests/test_unittest_one.py::Test_test1::test_A', - name: 'test_A', - source: 'tests/test_unittest_one.py:6', - markers: [], - parentid: './tests/test_unittest_one.py::Test_test1', - }, - { - id: './tests/test_unittest_one.py::Test_test1::test_B', - name: 'test_B', - source: 'tests/test_unittest_one.py:9', - markers: [], - parentid: './tests/test_unittest_one.py::Test_test1', - }, - { - id: './tests/test_unittest_one.py::Test_test1::test_c', - name: 'test_c', - source: 'tests/test_unittest_one.py:12', - markers: [], - parentid: './tests/test_unittest_one.py::Test_test1', - }, - { - id: './tests/test_unittest_two.py::Test_test2::test_A2', - name: 'test_A2', - source: 'tests/test_unittest_two.py:3', - markers: [], - parentid: './tests/test_unittest_two.py::Test_test2', - }, - { - id: './tests/test_unittest_two.py::Test_test2::test_B2', - name: 'test_B2', - source: 'tests/test_unittest_two.py:6', - markers: [], - parentid: './tests/test_unittest_two.py::Test_test2', - }, - { - id: './tests/test_unittest_two.py::Test_test2::test_C2', - name: 'test_C2', - source: 'tests/test_unittest_two.py:9', - markers: [], - parentid: './tests/test_unittest_two.py::Test_test2', - }, - { - id: './tests/test_unittest_two.py::Test_test2::test_D2', - name: 'test_D2', - source: 'tests/test_unittest_two.py:12', - markers: [], - parentid: './tests/test_unittest_two.py::Test_test2', - }, - { - id: './tests/test_unittest_two.py::Test_test2a::test_222A2', - name: 'test_222A2', - source: 'tests/test_unittest_two.py:17', - markers: [], - parentid: './tests/test_unittest_two.py::Test_test2a', - }, - { - id: './tests/test_unittest_two.py::Test_test2a::test_222B2', - name: 'test_222B2', - source: 'tests/test_unittest_two.py:20', - markers: [], - parentid: './tests/test_unittest_two.py::Test_test2a', - }, - { - id: './tests/unittest_three_test.py::Test_test3::test_A', - name: 'test_A', - source: 'tests/unittest_three_test.py:4', - markers: [], - parentid: './tests/unittest_three_test.py::Test_test3', - }, - { - id: './tests/unittest_three_test.py::Test_test3::test_B', - name: 'test_B', - source: 'tests/unittest_three_test.py:7', - markers: [], - parentid: './tests/unittest_three_test.py::Test_test3', - }, - ], - }, - ]), - ); - await updateSetting('testing.pytestArgs', ['-k=test_'], rootWorkspaceUri, configTarget); - const factory = ioc.serviceContainer.get(ITestManagerFactory); - const testManager = factory('pytest', rootWorkspaceUri!, UNITTEST_TEST_FILES_PATH); - const tests = await testManager.discoverTests(CommandSource.ui, true, true); - const diagnosticCollectionUris: vscode.Uri[] = []; - testManager.diagnosticCollection.forEach((uri) => { - diagnosticCollectionUris.push(uri); - }); - assert.equal(diagnosticCollectionUris.length, 0, 'Should not have diagnostics yet'); - assert.equal(tests.testFiles.length, 7, 'Incorrect number of test files'); - assert.equal(tests.testFunctions.length, 33, 'Incorrect number of test functions'); - assert.equal(tests.testSuites.length, 11, 'Incorrect number of test suites'); - assert.equal( - tests.testFiles.some((t) => t.name === 'test_foreign_nested_tests.py'), - true, - 'Test File not found', - ); - assert.equal( - tests.testFiles.some((t) => t.name === 'test_unittest_one.py'), - true, - 'Test File not found', - ); - assert.equal( - tests.testFiles.some((t) => t.name === 'test_unittest_two.py'), - true, - 'Test File not found', - ); - assert.equal( - tests.testFiles.some((t) => t.name === 'unittest_three_test.py'), - true, - 'Test File not found', - ); - assert.equal( - tests.testFiles.some((t) => t.name === 'test_pytest.py'), - true, - 'Test File not found', - ); - assert.equal( - tests.testFiles.some((t) => t.name === 'test_another_pytest.py'), - true, - 'Test File not found', - ); - assert.equal( - tests.testFiles.some((t) => t.name === 'test_root.py'), - true, - 'Test File not found', - ); - }); - - test('Discover Tests (pattern = _test)', async () => { - await injectTestDiscoveryOutput( - JSON.stringify([ - { - rootid: '.', - root: - '/Users/donjayamanne/.vscode-insiders/extensions/pythonVSCode/src/test/pythonFiles/testFiles/standard', - parents: [ - { - id: './tests', - kind: 'folder', - name: 'tests', - relpath: './tests', - parentid: '.', - }, - { - id: './tests/unittest_three_test.py', - kind: 'file', - name: 'unittest_three_test.py', - relpath: './tests/unittest_three_test.py', - parentid: './tests', - }, - { - id: './tests/unittest_three_test.py::Test_test3', - kind: 'suite', - name: 'Test_test3', - parentid: './tests/unittest_three_test.py', - }, - ], - tests: [ - { - id: './tests/unittest_three_test.py::Test_test3::test_A', - name: 'test_A', - source: 'tests/unittest_three_test.py:4', - markers: [], - parentid: './tests/unittest_three_test.py::Test_test3', - }, - { - id: './tests/unittest_three_test.py::Test_test3::test_B', - name: 'test_B', - source: 'tests/unittest_three_test.py:7', - markers: [], - parentid: './tests/unittest_three_test.py::Test_test3', - }, - ], - }, - ]), - ); - await updateSetting('testing.pytestArgs', ['-k=_test.py'], rootWorkspaceUri, configTarget); - const factory = ioc.serviceContainer.get(ITestManagerFactory); - const testManager = factory('pytest', rootWorkspaceUri!, UNITTEST_TEST_FILES_PATH); - const tests = await testManager.discoverTests(CommandSource.ui, true, true); - const diagnosticCollectionUris: vscode.Uri[] = []; - testManager.diagnosticCollection.forEach((uri) => { - diagnosticCollectionUris.push(uri); - }); - assert.equal(diagnosticCollectionUris.length, 0, 'Should not have diagnostics yet'); - assert.equal(tests.testFiles.length, 1, 'Incorrect number of test files'); - assert.equal(tests.testFunctions.length, 2, 'Incorrect number of test functions'); - assert.equal(tests.testSuites.length, 1, 'Incorrect number of test suites'); - assert.equal( - tests.testFiles.some((t) => t.name === 'unittest_three_test.py'), - true, - 'Test File not found', - ); - }); - - test('Discover Tests (with config)', async () => { - await injectTestDiscoveryOutput( - JSON.stringify([ - { - rootid: '.', - root: - '/Users/donjayamanne/.vscode-insiders/extensions/pythonVSCode/src/test/pythonFiles/testFiles/unittestsWithConfigs', - parents: [ - { - id: './other', - relpath: './other', - kind: 'folder', - name: 'other', - parentid: '.', - }, - { - id: './other/test_pytest.py', - relpath: './other/test_pytest.py', - kind: 'file', - name: 'test_pytest.py', - parentid: './other', - }, - { - id: './other/test_pytest.py::Test_CheckMyApp', - kind: 'suite', - name: 'Test_CheckMyApp', - parentid: './other/test_pytest.py', - }, - { - id: './other/test_pytest.py::Test_CheckMyApp::Test_NestedClassA', - kind: 'suite', - name: 'Test_NestedClassA', - parentid: './other/test_pytest.py::Test_CheckMyApp', - }, - { - id: './other/test_pytest.py::Test_CheckMyApp::Test_NestedClassA::Test_nested_classB_Of_A', - kind: 'suite', - name: 'Test_nested_classB_Of_A', - parentid: './other/test_pytest.py::Test_CheckMyApp::Test_NestedClassA', - }, - { - id: './other/test_pytest.py::test_parametrized_username', - kind: 'function', - name: 'test_parametrized_username', - parentid: './other/test_pytest.py', - }, - { - id: './other/test_unittest_one.py', - relpath: './other/test_unittest_one.py', - kind: 'file', - name: 'test_unittest_one.py', - parentid: './other', - }, - { - id: './other/test_unittest_one.py::Test_test1', - kind: 'suite', - name: 'Test_test1', - parentid: './other/test_unittest_one.py', - }, - ], - tests: [ - { - id: './other/test_pytest.py::Test_CheckMyApp::test_simple_check', - name: 'test_simple_check', - source: 'other/test_pytest.py:6', - markers: [], - parentid: './other/test_pytest.py::Test_CheckMyApp', - }, - { - id: './other/test_pytest.py::Test_CheckMyApp::test_complex_check', - name: 'test_complex_check', - source: 'other/test_pytest.py:9', - markers: [], - parentid: './other/test_pytest.py::Test_CheckMyApp', - }, - { - id: './other/test_pytest.py::Test_CheckMyApp::Test_NestedClassA::test_nested_class_methodB', - name: 'test_nested_class_methodB', - source: 'other/test_pytest.py:13', - markers: [], - parentid: './other/test_pytest.py::Test_CheckMyApp::Test_NestedClassA', - }, - { - id: - './other/test_pytest.py::Test_CheckMyApp::Test_NestedClassA::Test_nested_classB_Of_A::test_d', - name: 'test_d', - source: 'other/test_pytest.py:16', - markers: [], - parentid: - './other/test_pytest.py::Test_CheckMyApp::Test_NestedClassA::Test_nested_classB_Of_A', - }, - { - id: './other/test_pytest.py::Test_CheckMyApp::Test_NestedClassA::test_nested_class_methodC', - name: 'test_nested_class_methodC', - source: 'other/test_pytest.py:18', - markers: [], - parentid: './other/test_pytest.py::Test_CheckMyApp::Test_NestedClassA', - }, - { - id: './other/test_pytest.py::Test_CheckMyApp::test_simple_check2', - name: 'test_simple_check2', - source: 'other/test_pytest.py:21', - markers: [], - parentid: './other/test_pytest.py::Test_CheckMyApp', - }, - { - id: './other/test_pytest.py::Test_CheckMyApp::test_complex_check2', - name: 'test_complex_check2', - source: 'other/test_pytest.py:23', - markers: [], - parentid: './other/test_pytest.py::Test_CheckMyApp', - }, - { - id: './other/test_pytest.py::test_username', - name: 'test_username', - source: 'other/test_pytest.py:35', - markers: [], - parentid: './other/test_pytest.py', - }, - { - id: './other/test_pytest.py::test_parametrized_username[one]', - name: 'test_parametrized_username[one]', - source: 'other/test_pytest.py:38', - markers: [], - parentid: './other/test_pytest.py::test_parametrized_username', - }, - { - id: './other/test_pytest.py::test_parametrized_username[two]', - name: 'test_parametrized_username[two]', - source: 'other/test_pytest.py:38', - markers: [], - parentid: './other/test_pytest.py::test_parametrized_username', - }, - { - id: './other/test_pytest.py::test_parametrized_username[three]', - name: 'test_parametrized_username[three]', - source: 'other/test_pytest.py:38', - markers: [], - parentid: './other/test_pytest.py::test_parametrized_username', - }, - { - id: './other/test_unittest_one.py::Test_test1::test_A', - name: 'test_A', - source: 'other/test_unittest_one.py:6', - markers: [], - parentid: './other/test_unittest_one.py::Test_test1', - }, - { - id: './other/test_unittest_one.py::Test_test1::test_B', - name: 'test_B', - source: 'other/test_unittest_one.py:9', - markers: [], - parentid: './other/test_unittest_one.py::Test_test1', - }, - { - id: './other/test_unittest_one.py::Test_test1::test_c', - name: 'test_c', - source: 'other/test_unittest_one.py:12', - markers: [], - parentid: './other/test_unittest_one.py::Test_test1', - }, - ], - }, - ]), - ); - await updateSetting('testing.pytestArgs', [], rootWorkspaceUri, configTarget); - const factory = ioc.serviceContainer.get(ITestManagerFactory); - const testManager = factory('pytest', rootWorkspaceUri!, UNITTEST_TEST_FILES_PATH_WITH_CONFIGS); - const tests = await testManager.discoverTests(CommandSource.ui, true, true); - const diagnosticCollectionUris: vscode.Uri[] = []; - testManager.diagnosticCollection.forEach((uri) => { - diagnosticCollectionUris.push(uri); - }); - assert.equal(diagnosticCollectionUris.length, 0, 'Should not have diagnostics yet'); - assert.equal(tests.testFiles.length, 2, 'Incorrect number of test files'); - assert.equal(tests.testFunctions.length, 14, 'Incorrect number of test functions'); - assert.equal(tests.testSuites.length, 4, 'Incorrect number of test suites'); - assert.equal( - tests.testFiles.some((t) => t.name === 'test_unittest_one.py'), - true, - 'Test File not found', - ); - assert.equal( - tests.testFiles.some((t) => t.name === 'test_pytest.py'), - true, - 'Test File not found', - ); - }); - - test('Setting cwd should return tests', async () => { - await injectTestDiscoveryOutput( - JSON.stringify([ - { - rootid: '.', - root: - '/Users/donjayamanne/.vscode-insiders/extensions/pythonVSCode/src/test/pythonFiles/testFiles/cwd/src', - parents: [ - { - id: './tests', - kind: 'folder', - name: 'tests', - relpath: './tests', - parentid: '.', - }, - { - id: './tests/test_cwd.py', - kind: 'file', - name: 'test_cwd.py', - relpath: './tests/test_cwd.py', - parentid: './tests', - }, - { - id: './tests/test_cwd.py::Test_Current_Working_Directory', - kind: 'suite', - name: 'Test_Current_Working_Directory', - parentid: './tests/test_cwd.py', - }, - ], - tests: [ - { - id: './tests/test_cwd.py::Test_Current_Working_Directory::test_cwd', - name: 'test_cwd', - source: 'tests/test_cwd.py:6', - markers: [], - parentid: './tests/test_cwd.py::Test_Current_Working_Directory', - }, - ], - }, - ]), - ); - await updateSetting('testing.pytestArgs', ['-k=test_'], rootWorkspaceUri, configTarget); - const factory = ioc.serviceContainer.get(ITestManagerFactory); - const testManager = factory('pytest', rootWorkspaceUri!, unitTestTestFilesCwdPath); - - const tests = await testManager.discoverTests(CommandSource.ui, true, true); - const diagnosticCollectionUris: vscode.Uri[] = []; - testManager.diagnosticCollection.forEach((uri) => { - diagnosticCollectionUris.push(uri); - }); - assert.equal(diagnosticCollectionUris.length, 0, 'Should not have diagnostics yet'); - assert.equal(tests.testFiles.length, 1, 'Incorrect number of test files'); - assert.equal(tests.testFolders.length, 2, 'Incorrect number of test folders'); - assert.equal(tests.testFunctions.length, 1, 'Incorrect number of test functions'); - assert.equal(tests.testSuites.length, 1, 'Incorrect number of test suites'); - }); -}); diff --git a/src/test/testing/pytest/pytest.run.test.ts b/src/test/testing/pytest/pytest.run.test.ts deleted file mode 100644 index cf886bd993e8..000000000000 --- a/src/test/testing/pytest/pytest.run.test.ts +++ /dev/null @@ -1,635 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -import * as assert from 'assert'; -import * as fs from 'fs'; -import { inject, injectable } from 'inversify'; -import * as path from 'path'; -import { instance, mock } from 'ts-mockito'; -import * as vscode from 'vscode'; -import { CommandSource, EXTENSION_ROOT_DIR } from '../../../client/common/constants'; -import { IFileSystem } from '../../../client/common/platform/types'; -import { createPythonEnv } from '../../../client/common/process/pythonEnvironment'; -import { PythonExecutionFactory } from '../../../client/common/process/pythonExecutionFactory'; -import { createPythonProcessService } from '../../../client/common/process/pythonProcess'; -import { - ExecutionFactoryCreateWithEnvironmentOptions, - IBufferDecoder, - IProcessServiceFactory, - IPythonExecutionFactory, - IPythonExecutionService, -} from '../../../client/common/process/types'; -import { IConfigurationService, IExperimentService } from '../../../client/common/types'; -import { IEnvironmentActivationService } from '../../../client/interpreter/activation/types'; -import { IComponentAdapter, ICondaService, IInterpreterService } from '../../../client/interpreter/contracts'; -import { InterpreterService } from '../../../client/interpreter/interpreterService'; -import { IServiceContainer } from '../../../client/ioc/types'; -import { CondaService } from '../../../client/pythonEnvironments/discovery/locators/services/condaService'; -import { UnitTestDiagnosticService } from '../../../client/testing/common/services/unitTestDiagnosticService'; -import { - FlattenedTestFunction, - isNonPassingTestStatus, - NonPassingTestStatus, - ITestManager, - ITestManagerFactory, - Tests, - TestStatus, - TestsToRun, -} from '../../../client/testing/common/types'; -import { rootWorkspaceUri, updateSetting } from '../../common'; -import { TEST_TIMEOUT } from '../../constants'; -import { MockProcessService } from '../../mocks/proc'; -import { registerForIOC } from '../../pythonEnvironments/legacyIOC'; -import { UnitTestIocContainer } from '../serviceRegistry'; -import { initialize, initializeTest, IS_MULTI_ROOT_TEST } from '../../initialize'; -import { ITestDetails, ITestScenarioDetails, testScenarios } from './pytest_run_tests_data'; - -const UNITTEST_TEST_FILES_PATH = path.join(EXTENSION_ROOT_DIR, 'src', 'test', 'pythonFiles', 'testFiles', 'standard'); -const PYTEST_RESULTS_PATH = path.join( - EXTENSION_ROOT_DIR, - 'src', - 'test', - 'pythonFiles', - 'testFiles', - 'pytestFiles', - 'results', -); - -interface IResultsSummaryCount { - passes: number; - skips: number; - failures: number; - errors: number; -} - -/** - * Establishing what tests should be run (so that they can be passed to the test manager) can be - * dependant on the test discovery process having occurred. If the scenario has any properties that - * indicate its testsToRun property needs to be generated, then this process is done by using - * properties of the scenario to determine which test folders/files/suites/functions should be - * used from the tests object created by the test discovery process. - * - * @param scenario The testing scenario to emulate. - * @param tests The tests that were discovered. - */ -async function getScenarioTestsToRun(scenario: ITestScenarioDetails, tests: Tests): Promise { - const generateTestsToRun = scenario.testSuiteIndex || scenario.testFunctionIndex; - if (scenario.testsToRun === undefined && generateTestsToRun) { - scenario.testsToRun = { - testFolder: [], - testFile: [], - testSuite: [], - testFunction: [], - }; - if (scenario.testSuiteIndex) { - scenario.testsToRun.testSuite!.push(tests.testSuites[scenario.testSuiteIndex].testSuite); - } - if (scenario.testFunctionIndex) { - scenario.testsToRun.testFunction!.push(tests.testSuites[scenario.testFunctionIndex].testSuite); - } - } - return scenario.testsToRun!; -} - -/** - * Run the tests and return the results. - * - * In the case of a failed test run, some test details can be marked through the passOnFailedRun property to pass on a - * failed run. This is meant to simulate a test or the thing it's meant to test being fixed. - * - * @param testManager The test manager used to run the tests. - * @param testsToRun The tests that the test manager should run. - * @param failedRun Whether or not the current test run is for failed tests from a previous run. - */ -async function getResultsFromTestManagerRunTest( - testManager: ITestManager, - testsToRun: TestsToRun, - failedRun = false, -): Promise { - if (failedRun) { - return testManager.runTest(CommandSource.ui, undefined, true); - } - return testManager.runTest(CommandSource.ui, testsToRun); -} - -/** - * Get the number of passes/skips/failures/errors for a test run based on the test details for a scenario. - * - * In the case of a failed test run, some test details can be marked through the passOnFailedRun property to pass on a - * failed run. This is meant to simulate a test or the thing it's meant to test being fixed. - * - * @param testDetails All the test details for a scenario. - * @param failedRun Whether or not the current test run is for failed tests from a previous run. - */ -function getExpectedSummaryCount(testDetails: ITestDetails[], failedRun: boolean): IResultsSummaryCount { - const summaryCount: IResultsSummaryCount = { - passes: 0, - skips: 0, - failures: 0, - errors: 0, - }; - testDetails.forEach((td) => { - let tStatus = td.status; - if (failedRun && td.passOnFailedRun) { - tStatus = TestStatus.Pass; - } - switch (tStatus) { - case TestStatus.Pass: { - summaryCount.passes += 1; - break; - } - case TestStatus.Skipped: { - summaryCount.skips += 1; - break; - } - case TestStatus.Fail: { - summaryCount.failures += 1; - break; - } - case TestStatus.Error: { - summaryCount.errors += 1; - break; - } - default: { - throw Error('Unsupported TestStatus'); - } - } - }); - return summaryCount; -} - -/** - * Get all the test details associated with a file. - * - * @param testDetails All the test details for a scenario. - * @param fileName The name of the file to find test details for. - */ -function getRelevantTestDetailsForFile(testDetails: ITestDetails[], fileName: string): ITestDetails[] { - return testDetails.filter((td) => td.fileName === fileName); -} - -/** - * Every failed/skipped test in a file should should have an associated Diagnostic for it. This calculates and returns the - * expected number of Diagnostics based on the expected test details for that file. In the event of a normal test run, - * skipped tests will be included in the results, and thus will be included in the testDetails argument. But if it's a - * failed test run, skipped tests will not be attempted again, so they will not be included in the testDetails argument. - * - * In the case of a failed test run, some test details can be marked through the passOnFailedRun property to pass on a - * failed run. This is meant to simulate a test or the thing it's meant to test being fixed. - * - * @param testDetails All the test details for a file for the tests that were run. - * @param skippedTestDetails All the test details for skipped tests for a file. - * @param failedRun Whether or not the current test run is for failed tests from a previous run. - */ -function getIssueCountFromRelevantTestDetails( - testDetails: ITestDetails[], - skippedTestDetails: ITestDetails[], - failedRun = false, -): number { - const relevantIssueDetails = testDetails.filter( - (td) => td.status !== TestStatus.Pass && !(failedRun && td.passOnFailedRun), - ); - // If it's a failed run, the skipped tests won't be included in testDetails, but should still be included as they still aren't passing. - return relevantIssueDetails.length + (failedRun ? skippedTestDetails.length : 0); -} - -/** - * Get the Diagnostic associated with the FlattenedTestFunction. - * - * @param diagnostics The array of Diagnostics for a file. - * @param testFunc The FlattenedTestFunction to find the Diagnostic for. - */ -function getDiagnosticForTestFunc( - diagnostics: readonly vscode.Diagnostic[], - testFunc: FlattenedTestFunction, -): vscode.Diagnostic { - return diagnostics.find((diag) => testFunc.testFunction.nameToRun === diag.code)!; -} - -/** - * Get a list of all the unique files found in a given testDetails array. - * - * @param testDetails All the test details for a scenario. - */ -function getUniqueIssueFilesFromTestDetails(testDetails: ITestDetails[]): string[] { - return testDetails.reduce((filtered, issue) => { - if (filtered.indexOf(issue.fileName) === -1 && issue.fileName !== undefined) { - filtered.push(issue.fileName); - } - return filtered; - }, []); -} - -/** - * Of all the test details that were run for a scenario, given a file location, get all those that were skipped. - * - * @param testDetails All test details that should have been run for the scenario. - * @param fileName The location of a file that had tests run. - */ -function getRelevantSkippedIssuesFromTestDetailsForFile(testDetails: ITestDetails[], fileName: string): ITestDetails[] { - return testDetails.filter((td) => td.fileName === fileName && td.status === TestStatus.Skipped); -} - -/** - * Get the FlattenedTestFunction from the test results that's associated with the given testDetails object. - * - * @param ioc IOC Test Container - * @param results Results of the test run. - * @param testFileUri The Uri of the test file that was run. - * @param testDetails The details of a particular test. - */ -function getTestFuncFromResultsByTestFileAndName( - ioc: UnitTestIocContainer, - results: Tests, - testFileUri: vscode.Uri, - testDetails: ITestDetails, -): FlattenedTestFunction { - const fileSystem = ioc.serviceContainer.get(IFileSystem); - return results.testFunctions.find( - (test) => - fileSystem.arePathsSame(vscode.Uri.file(test.parentTestFile.fullPath).fsPath, testFileUri.fsPath) && - test.testFunction.name === testDetails.testName, - )!; -} - -/** - * Generate a Diagnostic object (including DiagnosticRelatedInformation) using the provided test details that reflects - * what the Diagnostic for the associated test should be in order for it to be compared to by the actual Diagnostic - * for the test. - * - * @param testDetails Test details for a specific test. - */ -async function getExpectedDiagnosticFromTestDetails(testDetails: ITestDetails): Promise { - const relatedInfo: vscode.DiagnosticRelatedInformation[] = []; - const testFilePath = path.join(UNITTEST_TEST_FILES_PATH, testDetails.fileName); - const testFileUri = vscode.Uri.file(testFilePath); - let expectedSourceTestFilePath = testFilePath; - if (testDetails.imported) { - expectedSourceTestFilePath = path.join(UNITTEST_TEST_FILES_PATH, testDetails.sourceFileName!); - } - const expectedSourceTestFileUri = vscode.Uri.file(expectedSourceTestFilePath); - assert.ok(isNonPassingTestStatus(testDetails.status)); - const diagMsgPrefix = new UnitTestDiagnosticService().getMessagePrefix(testDetails.status as NonPassingTestStatus); - const expectedDiagMsg = `${diagMsgPrefix ? `${diagMsgPrefix}: ` : ''}${testDetails.message}`; - let expectedDiagRange = testDetails.testDefRange; - let expectedSeverity = vscode.DiagnosticSeverity.Error; - if (testDetails.status === TestStatus.Skipped) { - // Stack should stop at the test definition line. - expectedSeverity = vscode.DiagnosticSeverity.Information; - } - if (testDetails.imported) { - // Stack should include the class furthest down the chain from the file that was executed. - relatedInfo.push( - new vscode.DiagnosticRelatedInformation( - new vscode.Location(testFileUri, testDetails.classDefRange!), - testDetails.simpleClassName!, - ), - ); - expectedDiagRange = testDetails.classDefRange; - } - relatedInfo.push( - new vscode.DiagnosticRelatedInformation( - new vscode.Location(expectedSourceTestFileUri, testDetails.testDefRange!), - testDetails.sourceTestName, - ), - ); - if (testDetails.status !== TestStatus.Skipped) { - relatedInfo.push( - new vscode.DiagnosticRelatedInformation( - new vscode.Location(expectedSourceTestFileUri, testDetails.issueRange!), - testDetails.issueLineText!, - ), - ); - } else { - expectedSeverity = vscode.DiagnosticSeverity.Information; - } - - const expectedDiagnostic = new vscode.Diagnostic(expectedDiagRange!, expectedDiagMsg, expectedSeverity); - expectedDiagnostic.source = 'pytest'; - expectedDiagnostic.code = testDetails.nameToRun; - expectedDiagnostic.relatedInformation = relatedInfo; - return expectedDiagnostic; -} - -async function testResultsSummary(results: Tests, expectedSummaryCount: IResultsSummaryCount) { - const totalTests = - results.summary.passed + results.summary.skipped + results.summary.failures + results.summary.errors; - assert.notEqual(totalTests, 0); - assert.equal(results.summary.passed, expectedSummaryCount.passes, 'Passed'); - assert.equal(results.summary.skipped, expectedSummaryCount.skips, 'Skipped'); - assert.equal(results.summary.failures, expectedSummaryCount.failures, 'Failures'); - assert.equal(results.summary.errors, expectedSummaryCount.errors, 'Errors'); -} - -async function testDiagnostic(diagnostic: vscode.Diagnostic, expectedDiagnostic: vscode.Diagnostic) { - assert.equal(diagnostic.code, expectedDiagnostic.code, 'Diagnostic code'); - assert.equal(diagnostic.message, expectedDiagnostic.message, 'Diagnostic message'); - assert.equal(diagnostic.severity, expectedDiagnostic.severity, 'Diagnostic severity'); - assert.equal(diagnostic.range.start.line, expectedDiagnostic.range.start.line, 'Diagnostic range start line'); - assert.equal( - diagnostic.range.start.character, - expectedDiagnostic.range.start.character, - 'Diagnostic range start character', - ); - assert.equal(diagnostic.range.end.line, expectedDiagnostic.range.end.line, 'Diagnostic range end line'); - assert.equal( - diagnostic.range.end.character, - expectedDiagnostic.range.end.character, - 'Diagnostic range end character', - ); - assert.equal(diagnostic.source, expectedDiagnostic.source, 'Diagnostic source'); - assert.equal( - diagnostic.relatedInformation!.length, - expectedDiagnostic.relatedInformation!.length, - 'DiagnosticRelatedInformation count', - ); -} - -async function testDiagnosticRelatedInformation( - relatedInfo: vscode.DiagnosticRelatedInformation, - expectedRelatedInfo: vscode.DiagnosticRelatedInformation, -) { - assert.equal(relatedInfo.message, expectedRelatedInfo.message, 'DiagnosticRelatedInfo definition'); - assert.equal( - relatedInfo.location.range.start.line, - expectedRelatedInfo.location.range.start.line, - 'DiagnosticRelatedInfo definition range start line', - ); - assert.equal( - relatedInfo.location.range.start.character, - expectedRelatedInfo.location.range.start.character, - 'DiagnosticRelatedInfo definition range start character', - ); - assert.equal( - relatedInfo.location.range.end.line, - expectedRelatedInfo.location.range.end.line, - 'DiagnosticRelatedInfo definition range end line', - ); - assert.equal( - relatedInfo.location.range.end.character, - expectedRelatedInfo.location.range.end.character, - 'DiagnosticRelatedInfo definition range end character', - ); -} - -suite('Unit Tests - pytest - run with mocked process output', () => { - let ioc: UnitTestIocContainer; - const configTarget = IS_MULTI_ROOT_TEST - ? vscode.ConfigurationTarget.WorkspaceFolder - : vscode.ConfigurationTarget.Workspace; - @injectable() - class ExecutionFactory extends PythonExecutionFactory { - constructor( - @inject(IServiceContainer) private readonly _serviceContainer: IServiceContainer, - @inject(IEnvironmentActivationService) activationHelper: IEnvironmentActivationService, - @inject(IProcessServiceFactory) processServiceFactory: IProcessServiceFactory, - @inject(IConfigurationService) private readonly _configService: IConfigurationService, - @inject(ICondaService) condaService: ICondaService, - @inject(IBufferDecoder) decoder: IBufferDecoder, - @inject(IComponentAdapter) pyenvs: IComponentAdapter, - @inject(IExperimentService) experimentService: IExperimentService, - ) { - super( - _serviceContainer, - activationHelper, - processServiceFactory, - _configService, - condaService, - decoder, - pyenvs, - experimentService, - ); - } - - public async createActivatedEnvironment( - options: ExecutionFactoryCreateWithEnvironmentOptions, - ): Promise { - const pythonPath = options.interpreter - ? options.interpreter.path - : this._configService.getSettings(options.resource).pythonPath; - const procService = (await ioc.serviceContainer - .get(IProcessServiceFactory) - .create()) as MockProcessService; - const fileSystem = this._serviceContainer.get(IFileSystem); - const env = createPythonEnv(pythonPath, procService, fileSystem); - const procs = createPythonProcessService(procService, env); - return { - getInterpreterInformation: () => env.getInterpreterInformation(), - getExecutablePath: () => env.getExecutablePath(), - isModuleInstalled: (m) => env.isModuleInstalled(m), - getExecutionInfo: (a) => env.getExecutionInfo(a), - getModuleVersion: (m) => env.getModuleVersion(m), - execObservable: (a, o) => procs.execObservable(a, o), - execModuleObservable: (m, a, o) => procs.execModuleObservable(m, a, o), - exec: (a, o) => procs.exec(a, o), - execModule: (m, a, o) => procs.execModule(m, a, o), - }; - } - } - - suiteSetup(async function () { - this.timeout(TEST_TIMEOUT * 2); - - console.time('Pytest before all hook'); - await initialize(); - console.timeLog('Pytest before all hook'); - await updateSetting('testing.pytestArgs', [], rootWorkspaceUri, configTarget); - console.timeEnd('Pytest before all hook'); - }); - async function initializeDI() { - ioc = new UnitTestIocContainer(); - ioc.registerCommonTypes(); - ioc.registerUnitTestTypes(); - ioc.registerVariableTypes(); - // Mocks. - ioc.registerMockProcessTypes(); - ioc.registerInterpreterStorageTypes(); - - ioc.serviceManager.addSingletonInstance( - IInterpreterService, - instance(mock(InterpreterService)), - ); - ioc.serviceManager.rebind(IPythonExecutionFactory, ExecutionFactory); - - await registerForIOC(ioc.serviceManager, ioc.serviceContainer); - ioc.serviceManager.rebindInstance(ICondaService, instance(mock(CondaService))); - } - - async function injectTestDiscoveryOutput(outputFileName: string) { - const procService = (await ioc.serviceContainer - .get(IProcessServiceFactory) - .create()) as MockProcessService; - procService.onExec((_file, args, _options, callback) => { - if (args.indexOf('discover') >= 0 && args.indexOf('pytest') >= 0) { - let stdout = fs.readFileSync(path.join(PYTEST_RESULTS_PATH, outputFileName), 'utf8'); - stdout = stdout.replace( - /\/Users\/donjayamanne\/.vscode-insiders\/extensions\/pythonVSCode\/src\/test\/pythonFiles\/testFiles/g, - path.dirname(UNITTEST_TEST_FILES_PATH), - ); - stdout = stdout.replace(/\\/g, '/'); - callback({ stdout }); - } - }); - } - async function injectTestRunOutput(outputFileName: string, failedOutput = false) { - const junitXmlArgs = '--junit-xml='; - const procService = (await ioc.serviceContainer - .get(IProcessServiceFactory) - .create()) as MockProcessService; - procService.onExecObservable((_file, args, _options, callback) => { - if (failedOutput && args.indexOf('--last-failed') === -1) { - return; - } - const index = args.findIndex((arg) => arg.startsWith(junitXmlArgs)); - if (index >= 0) { - const fileName = args[index].substr(junitXmlArgs.length); - const contents = fs.readFileSync(path.join(PYTEST_RESULTS_PATH, outputFileName), 'utf8'); - fs.writeFileSync(fileName, contents, 'utf8'); - callback({ out: '', source: 'stdout' }); - } - }); - } - function getScenarioTestDetails(scenario: ITestScenarioDetails, failedRun: boolean): ITestDetails[] { - if (scenario.shouldRunFailed && failedRun) { - return scenario.testDetails!.filter((td) => td.status === TestStatus.Fail)!; - } - return scenario.testDetails!; - } - testScenarios.forEach((scenario) => { - suite(scenario.scenarioName, () => { - let testDetails: ITestDetails[]; - let factory: ITestManagerFactory; - let testManager: ITestManager; - let results: Tests; - let diagnostics: readonly vscode.Diagnostic[]; - suiteSetup(async function () { - // This "before all" hook is doing way more than normal - - this.timeout(TEST_TIMEOUT * 2); - await initializeTest(); - await initializeDI(); - await injectTestDiscoveryOutput(scenario.discoveryOutput); - await injectTestRunOutput(scenario.runOutput); - if (scenario.shouldRunFailed === true) { - await injectTestRunOutput(scenario.failedRunOutput!, true); - } - await updateSetting('testing.pytestArgs', ['-k=test_'], rootWorkspaceUri, configTarget); - factory = ioc.serviceContainer.get(ITestManagerFactory); - testManager = factory('pytest', rootWorkspaceUri!, UNITTEST_TEST_FILES_PATH); - const tests = await testManager.discoverTests(CommandSource.ui, true, true); - scenario.testsToRun = await getScenarioTestsToRun(scenario, tests); - }); - suiteTeardown(async () => { - await ioc.dispose(); - await updateSetting('testing.pytestArgs', [], rootWorkspaceUri, configTarget); - }); - - const shouldRunProperly = (suiteName: string, failedRun = false) => { - suite(suiteName, () => { - testDetails = getScenarioTestDetails(scenario, failedRun); - const uniqueIssueFiles = getUniqueIssueFilesFromTestDetails(testDetails); - let expectedSummaryCount: IResultsSummaryCount; - suiteSetup(async () => { - testDetails = getScenarioTestDetails(scenario, failedRun); - results = await getResultsFromTestManagerRunTest(testManager, scenario.testsToRun!, failedRun); - expectedSummaryCount = getExpectedSummaryCount(testDetails, failedRun); - }); - test('Test results summary', async () => { - await testResultsSummary(results, expectedSummaryCount); - }); - uniqueIssueFiles.forEach((fileName) => { - suite(fileName, () => { - let testFileUri: vscode.Uri; - const relevantTestDetails = getRelevantTestDetailsForFile(testDetails, fileName); - const relevantSkippedIssues = getRelevantSkippedIssuesFromTestDetailsForFile( - scenario.testDetails!, - fileName, - ); - suiteSetup(async () => { - testFileUri = vscode.Uri.file(path.join(UNITTEST_TEST_FILES_PATH, fileName)); - diagnostics = testManager.diagnosticCollection.get(testFileUri)!; - getIssueCountFromRelevantTestDetails( - relevantTestDetails, - relevantSkippedIssues, - failedRun, - ); - }); - // test('Test DiagnosticCollection', async () => { assert.equal(diagnostics.length, expectedDiagnosticCount, 'Diagnostics count'); }); - const validateTestFunctionAndDiagnostics = (td: ITestDetails) => { - suite(td.testName, () => { - let testFunc: FlattenedTestFunction; - let expectedStatus: TestStatus; - let diagnostic: vscode.Diagnostic; - let expectedDiagnostic: vscode.Diagnostic; - suiteSetup(async () => { - testFunc = getTestFuncFromResultsByTestFileAndName( - ioc, - results, - testFileUri, - td, - )!; - expectedStatus = failedRun && td.passOnFailedRun ? TestStatus.Pass : td.status; - }); - suite('TestFunction', async () => { - test('Status', async () => { - assert.equal(testFunc.testFunction.status, expectedStatus, 'Test status'); - }); - }); - if (td.status !== TestStatus.Pass && !(failedRun && td.passOnFailedRun)) { - suite('Diagnostic', async () => { - suiteSetup(async () => { - diagnostic = getDiagnosticForTestFunc(diagnostics, testFunc)!; - expectedDiagnostic = await getExpectedDiagnosticFromTestDetails(td); - }); - test('Test Diagnostic', async () => { - await testDiagnostic(diagnostic, expectedDiagnostic); - }); - suite('Test DiagnosticRelatedInformation', async () => { - if (td.imported) { - test('Class Definition', async () => { - await testDiagnosticRelatedInformation( - diagnostic.relatedInformation![0], - expectedDiagnostic.relatedInformation![0], - ); - }); - } - test('Test Function Definition', async () => { - await testDiagnosticRelatedInformation( - diagnostic.relatedInformation![td.imported ? 1 : 0], - expectedDiagnostic.relatedInformation![td.imported ? 1 : 0], - ); - }); - if (td.status !== TestStatus.Skipped) { - test('Failure Line', async () => { - await testDiagnosticRelatedInformation( - diagnostic.relatedInformation![(td.imported ? 1 : 0) + 1], - expectedDiagnostic.relatedInformation![ - (td.imported ? 1 : 0) + 1 - ], - ); - }); - } - }); - }); - } - }); - }; - relevantTestDetails.forEach((td: ITestDetails) => { - validateTestFunctionAndDiagnostics(td); - }); - if (failedRun) { - relevantSkippedIssues.forEach((td: ITestDetails) => { - validateTestFunctionAndDiagnostics(td); - }); - } - }); - }); - }); - }; - shouldRunProperly('Run'); - if (scenario.shouldRunFailed) { - shouldRunProperly('Run Failed', true); - } - }); - }); -}); diff --git a/src/test/testing/pytest/pytest.test.ts b/src/test/testing/pytest/pytest.test.ts deleted file mode 100644 index c6f868e51e22..000000000000 --- a/src/test/testing/pytest/pytest.test.ts +++ /dev/null @@ -1,65 +0,0 @@ -import * as assert from 'assert'; -import * as path from 'path'; -import * as vscode from 'vscode'; -import { CommandSource, EXTENSION_ROOT_DIR } from '../../../client/common/constants'; -import { ITestManagerFactory } from '../../../client/testing/common/types'; -import { rootWorkspaceUri, updateSetting } from '../../common'; -import { UnitTestIocContainer } from '../serviceRegistry'; -import { initialize, initializeTest, IS_MULTI_ROOT_TEST } from '../../initialize'; - -const UNITTEST_SINGLE_TEST_FILE_PATH = path.join( - EXTENSION_ROOT_DIR, - 'src', - 'test', - 'pythonFiles', - 'testFiles', - 'single', -); - -suite('Unit Tests - pytest - discovery against actual python process', () => { - let ioc: UnitTestIocContainer; - const configTarget = IS_MULTI_ROOT_TEST - ? vscode.ConfigurationTarget.WorkspaceFolder - : vscode.ConfigurationTarget.Workspace; - suiteSetup(async () => { - await initialize(); - await updateSetting('testing.pytestArgs', [], rootWorkspaceUri, configTarget); - }); - setup(async () => { - await initializeTest(); - await initializeDI(); - }); - teardown(async () => { - await ioc.dispose(); - await updateSetting('testing.pytestArgs', [], rootWorkspaceUri, configTarget); - }); - - async function initializeDI() { - ioc = new UnitTestIocContainer(); - ioc.registerCommonTypes(); - ioc.registerProcessTypes(); - ioc.registerUnitTestTypes(); - ioc.registerVariableTypes(); - await ioc.registerMockInterpreterTypes(); - ioc.registerInterpreterStorageTypes(); - } - - test('Discover Tests (single test file)', async () => { - const factory = ioc.serviceContainer.get(ITestManagerFactory); - const testManager = factory('pytest', rootWorkspaceUri!, UNITTEST_SINGLE_TEST_FILE_PATH); - const tests = await testManager.discoverTests(CommandSource.ui, true, true); - assert.equal(tests.testFiles.length, 2, 'Incorrect number of test files'); - assert.equal(tests.testFunctions.length, 6, 'Incorrect number of test functions'); - assert.equal(tests.testSuites.length, 2, 'Incorrect number of test suites'); - assert.equal( - tests.testFiles.some((t) => t.name === 'test_one.py'), - true, - 'Test File not found', - ); - assert.equal( - tests.testFiles.some((t) => t.name === 'test_root.py'), - true, - 'Test File not found', - ); - }); -}); diff --git a/src/test/testing/pytest/pytest.testMessageService.test.ts b/src/test/testing/pytest/pytest.testMessageService.test.ts deleted file mode 100644 index 8fdc89db7871..000000000000 --- a/src/test/testing/pytest/pytest.testMessageService.test.ts +++ /dev/null @@ -1,249 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { assert } from 'chai'; -import * as fs from 'fs'; -import * as path from 'path'; -import { instance, mock } from 'ts-mockito'; -import * as typeMoq from 'typemoq'; -import * as vscode from 'vscode'; -import { IWorkspaceService } from '../../../client/common/application/types'; -import { EXTENSION_ROOT_DIR } from '../../../client/common/constants'; -import { ProductNames } from '../../../client/common/installer/productNames'; -import { FileSystem } from '../../../client/common/platform/fileSystem'; -import { Product } from '../../../client/common/types'; -import { ICondaService, IInterpreterService } from '../../../client/interpreter/contracts'; -import { InterpreterService } from '../../../client/interpreter/interpreterService'; -import { CondaService } from '../../../client/pythonEnvironments/discovery/locators/services/condaService'; -import { TestDiscoveredTestParser } from '../../../client/testing/common/services/discoveredTestParser'; -import { TestResultsService } from '../../../client/testing/common/services/testResultsService'; -import { DiscoveredTests } from '../../../client/testing/common/services/types'; -import { - FinalTestStatus, - ILocationStackFrameDetails, - IPythonTestMessage, - ITestNonPassingMessage, - ITestVisitor, - PythonTestMessageSeverity, - TestDiscoveryOptions, - Tests, - TestStatus, -} from '../../../client/testing/common/types'; -import { XUnitParser } from '../../../client/testing/common/xUnitParser'; -import { TestMessageService } from '../../../client/testing/pytest/services/testMessageService'; -import { rootWorkspaceUri, updateSetting } from '../../common'; -import { initialize, initializeTest, IS_MULTI_ROOT_TEST } from '../../initialize'; -import { UnitTestIocContainer } from '../serviceRegistry'; -import { ITestDetails, testScenarios } from './pytest_run_tests_data'; - -const UNITTEST_TEST_FILES_PATH = path.join(EXTENSION_ROOT_DIR, 'src', 'test', 'pythonFiles', 'testFiles', 'standard'); -const PYTEST_RESULTS_PATH = path.join( - EXTENSION_ROOT_DIR, - 'src', - 'test', - 'pythonFiles', - 'testFiles', - 'pytestFiles', - 'results', -); - -const filterdTestScenarios = testScenarios.filter((ts) => !ts.shouldRunFailed); - -async function testMessageProperties( - message: IPythonTestMessage, - expectedMessage: IPythonTestMessage, - imported = false, - status: TestStatus, -) { - const nonPassing = message as ITestNonPassingMessage; - const expectedNonPassing = expectedMessage as ITestNonPassingMessage; - assert.equal(message.code, expectedMessage.code, 'IPythonTestMessage code'); - assert.equal(nonPassing.message, expectedNonPassing.message, 'IPythonTestMessage message'); - assert.equal(message.severity, expectedMessage.severity, 'IPythonTestMessage severity'); - assert.equal(message.provider, expectedMessage.provider, 'IPythonTestMessage provider'); - assert.isNumber(message.testTime, 'IPythonTestMessage testTime'); - assert.equal(message.status, expectedMessage.status, 'IPythonTestMessage status'); - assert.equal(message.testFilePath, expectedMessage.testFilePath, 'IPythonTestMessage testFilePath'); - if (status !== TestStatus.Pass) { - assert.equal( - nonPassing.locationStack[0].lineText, - expectedNonPassing.locationStack[0].lineText, - 'IPythonTestMessage line text', - ); - assert.equal( - nonPassing.locationStack[0].location.uri.fsPath, - expectedNonPassing.locationStack[0].location.uri.fsPath, - 'IPythonTestMessage locationStack fsPath', - ); - if (status !== TestStatus.Skipped) { - assert.equal( - nonPassing.locationStack[1].lineText, - expectedNonPassing.locationStack[1].lineText, - 'IPythonTestMessage line text', - ); - assert.equal( - nonPassing.locationStack[1].location.uri.fsPath, - expectedNonPassing.locationStack[1].location.uri.fsPath, - 'IPythonTestMessage locationStack fsPath', - ); - } - if (imported) { - assert.equal( - nonPassing.locationStack[2].lineText, - expectedNonPassing.locationStack[2].lineText, - 'IPythonTestMessage imported line text', - ); - assert.equal( - nonPassing.locationStack[2].location.uri.fsPath, - expectedNonPassing.locationStack[2].location.uri.fsPath, - 'IPythonTestMessage imported location fsPath', - ); - } - } -} - -/** - * Generate a Diagnostic object (including DiagnosticRelatedInformation) using the provided test details that reflects - * what the Diagnostic for the associated test should be in order for it to be compared to by the actual Diagnostic - * for the test. - * - * @param testDetails Test details for a specific test. - */ -async function getExpectedLocationStackFromTestDetails( - testDetails: ITestDetails, -): Promise { - const locationStack: ILocationStackFrameDetails[] = []; - const testFilePath = path.join(UNITTEST_TEST_FILES_PATH, testDetails.fileName); - const testFileUri = vscode.Uri.file(testFilePath); - let expectedSourceTestFilePath = testFilePath; - if (testDetails.imported) { - expectedSourceTestFilePath = path.join(UNITTEST_TEST_FILES_PATH, testDetails.sourceFileName!); - } - const expectedSourceTestFileUri = vscode.Uri.file(expectedSourceTestFilePath); - if (testDetails.imported) { - // Stack should include the class furthest down the chain from the file that was executed. - locationStack.push({ - location: new vscode.Location(testFileUri, testDetails.classDefRange!), - lineText: testDetails.simpleClassName!, - }); - } - locationStack.push({ - location: new vscode.Location(expectedSourceTestFileUri, testDetails.testDefRange!), - lineText: testDetails.sourceTestName, - }); - if (testDetails.status !== TestStatus.Skipped) { - locationStack.push({ - location: new vscode.Location(expectedSourceTestFileUri, testDetails.issueRange!), - lineText: testDetails.issueLineText!, - }); - } - return locationStack; -} - -suite('Unit Tests - PyTest - TestMessageService', () => { - let ioc: UnitTestIocContainer; - const filesystem = new FileSystem(); - const configTarget = IS_MULTI_ROOT_TEST - ? vscode.ConfigurationTarget.WorkspaceFolder - : vscode.ConfigurationTarget.Workspace; - suiteSetup(async () => { - await initialize(); - await updateSetting('testing.pytestArgs', [], rootWorkspaceUri, configTarget); - }); - async function initializeDI() { - ioc = new UnitTestIocContainer(); - ioc.registerCommonTypes(); - ioc.registerUnitTestTypes(); - ioc.registerVariableTypes(); - // Mocks. - ioc.registerMockProcessTypes(); - ioc.serviceManager.addSingletonInstance(ICondaService, instance(mock(CondaService))); - ioc.serviceManager.addSingletonInstance( - IInterpreterService, - instance(mock(InterpreterService)), - ); - } - // Build tests for the test data that is relevant for this platform. - filterdTestScenarios.forEach((scenario) => { - suite(scenario.scenarioName, async () => { - let testMessages: IPythonTestMessage[]; - suiteSetup(async () => { - await initializeTest(); - await initializeDI(); - // Setup the service container for use by the parser. - const testVisitor = typeMoq.Mock.ofType(); - const outChannel = typeMoq.Mock.ofType(); - const cancelToken = typeMoq.Mock.ofType(); - cancelToken.setup((c) => c.isCancellationRequested).returns(() => false); - const options: TestDiscoveryOptions = { - args: [], - cwd: UNITTEST_TEST_FILES_PATH, - ignoreCache: true, - outChannel: outChannel.object, - token: cancelToken.object, - workspaceFolder: vscode.Uri.file(__dirname), - }; - // Setup the parser. - const workspaceService = ioc.serviceContainer.get(IWorkspaceService); - const parser = new TestDiscoveredTestParser(workspaceService); - const discoveryOutput = fs - .readFileSync(path.join(PYTEST_RESULTS_PATH, scenario.discoveryOutput), 'utf8') - .replace( - /\/Users\/donjayamanne\/.vscode-insiders\/extensions\/pythonVSCode\/src\/test\/pythonFiles\/testFiles/g, - path.dirname(UNITTEST_TEST_FILES_PATH), - ) - .replace(/\\/g, '/'); - const discoveredTest: DiscoveredTests[] = JSON.parse(discoveryOutput); - options.workspaceFolder = vscode.Uri.file(discoveredTest[0].root); - const parsedTests: Tests = parser.parse(options.workspaceFolder, discoveredTest); - const xUnitParser = new XUnitParser(filesystem); - await xUnitParser.updateResultsFromXmlLogFile( - parsedTests, - path.join(PYTEST_RESULTS_PATH, scenario.runOutput), - ); - const testResultsService = new TestResultsService(testVisitor.object); - testResultsService.updateResults(parsedTests); - const testMessageService = new TestMessageService(ioc.serviceContainer); - testMessages = await testMessageService.getFilteredTestMessages(UNITTEST_TEST_FILES_PATH, parsedTests); - }); - suiteTeardown(async () => { - await ioc.dispose(); - await updateSetting('testing.pytestArgs', [], rootWorkspaceUri, configTarget); - }); - scenario.testDetails!.forEach((td) => { - suite(td.nameToRun, () => { - let testMessage: IPythonTestMessage; - let expectedMessage: IPythonTestMessage; - suiteSetup(async () => { - let expectedSeverity: PythonTestMessageSeverity; - if (td.status === TestStatus.Error || td.status === TestStatus.Fail) { - expectedSeverity = PythonTestMessageSeverity.Error; - } else if (td.status === TestStatus.Skipped) { - expectedSeverity = PythonTestMessageSeverity.Skip; - } else { - expectedSeverity = PythonTestMessageSeverity.Pass; - } - const expectedLocationStack = await getExpectedLocationStackFromTestDetails(td); - expectedMessage = { - code: td.nameToRun, - severity: expectedSeverity, - provider: ProductNames.get(Product.pytest)!, - testTime: 0, - status: td.status as FinalTestStatus, - testFilePath: path.join(UNITTEST_TEST_FILES_PATH, td.fileName), - // These are non-passing properties only: - message: td.message, - locationStack: expectedLocationStack, - } as IPythonTestMessage; - testMessage = testMessages.find((tm) => tm.code === td.nameToRun)!; - }); - test('Message', async () => { - await testMessageProperties(testMessage, expectedMessage, td.imported, td.status); - }); - }); - }); - }); - }); -}); diff --git a/src/test/testing/pytest/pytest_run_tests_data.ts b/src/test/testing/pytest/pytest_run_tests_data.ts deleted file mode 100644 index 1b06ae59d668..000000000000 --- a/src/test/testing/pytest/pytest_run_tests_data.ts +++ /dev/null @@ -1,464 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import * as path from 'path'; -import * as vscode from 'vscode'; -import { EXTENSION_ROOT_DIR } from '../../../client/common/constants'; -import { TestStatus, TestsToRun } from '../../../client/testing/common/types'; - -const UNITTEST_TEST_FILES_PATH = path.join(EXTENSION_ROOT_DIR, 'src', 'test', 'pythonFiles', 'testFiles', 'standard'); - -export interface ITestDetails { - className: string; - nameToRun: string; - fileName: string; - sourceFileName?: string; - testName: string; - simpleClassName?: string; - sourceTestName: string; - imported: boolean; - passOnFailedRun?: boolean; - status: TestStatus; - classDefRange?: vscode.Range; - testDefRange?: vscode.Range; - issueRange?: vscode.Range; - issueLineText?: string; - message?: string; - expectedDiagnostic?: vscode.Diagnostic; -} - -export const allTestDetails: ITestDetails[] = [ - { - className: 'test_root.Test_Root_test1', - nameToRun: './test_root.py::Test_Root_test1::test_Root_A', - fileName: 'test_root.py', - testName: 'test_Root_A', - sourceTestName: 'test_Root_A', - testDefRange: new vscode.Range(6, 8, 6, 19), - issueRange: new vscode.Range(7, 8, 7, 36), - issueLineText: 'self.fail("Not implemented")', - message: 'AssertionError: Not implemented', - imported: false, - status: TestStatus.Fail, - }, - { - className: 'test_root.Test_Root_test1', - nameToRun: './test_root.py::Test_Root_test1::test_Root_B', - fileName: 'test_root.py', - testName: 'test_Root_B', - sourceTestName: 'test_Root_B', - imported: false, - status: TestStatus.Pass, - }, - { - className: 'test_root.Test_Root_test1', - nameToRun: './test_root.py::Test_Root_test1::test_Root_c', - fileName: 'test_root.py', - testName: 'test_Root_c', - sourceTestName: 'test_Root_c', - testDefRange: new vscode.Range(13, 8, 13, 19), - message: 'demonstrating skipping', - imported: false, - status: TestStatus.Skipped, - }, - { - className: 'tests.test_another_pytest', - nameToRun: './tests/test_another_pytest.py::test_username', - fileName: path.join(...'tests/test_another_pytest.py'.split('/')), - testName: 'test_username', - sourceTestName: 'test_username', - imported: false, - status: TestStatus.Pass, - }, - { - className: 'tests.test_another_pytest', - nameToRun: './tests/test_another_pytest.py::test_parametrized_username[one]', - fileName: path.join(...'tests/test_another_pytest.py'.split('/')), - testName: 'test_parametrized_username[one]', - sourceTestName: 'test_parametrized_username', - imported: false, - status: TestStatus.Pass, - }, - { - className: 'tests.test_another_pytest', - nameToRun: './tests/test_another_pytest.py::test_parametrized_username[two]', - fileName: path.join(...'tests/test_another_pytest.py'.split('/')), - testName: 'test_parametrized_username[two]', - sourceTestName: 'test_parametrized_username', - imported: false, - status: TestStatus.Pass, - }, - { - className: 'tests.test_another_pytest', - nameToRun: './tests/test_another_pytest.py::test_parametrized_username[three]', - fileName: path.join(...'tests/test_another_pytest.py'.split('/')), - testName: 'test_parametrized_username[three]', - sourceTestName: 'test_parametrized_username', - testDefRange: new vscode.Range(15, 4, 15, 30), - issueRange: new vscode.Range(16, 4, 16, 64), - issueLineText: "assert non_parametrized_username in ['one', 'two', 'threes']", - message: "AssertionError: assert 'three' in ['one', 'two', 'threes']", - imported: false, - status: TestStatus.Fail, - }, - { - className: - 'tests.test_foreign_nested_tests.TestNestedForeignTests.TestInheritingHere.().TestExtraNestedForeignTests.()', - nameToRun: - './tests/test_foreign_nested_tests.py::TestNestedForeignTests::TestInheritingHere::TestExtraNestedForeignTests::test_super_deep_foreign', - simpleClassName: 'TestInheritingHere', - fileName: path.join(...'tests/test_foreign_nested_tests.py'.split('/')), - testName: 'test_super_deep_foreign', - sourceTestName: 'test_super_deep_foreign', - sourceFileName: path.join(...'tests/external.py'.split('/')), - classDefRange: new vscode.Range(4, 10, 4, 28), - testDefRange: new vscode.Range(2, 12, 2, 35), - issueRange: new vscode.Range(3, 12, 3, 24), - issueLineText: 'assert False', - message: 'AssertionError', - imported: true, - status: TestStatus.Fail, - }, - { - className: 'tests.test_foreign_nested_tests.TestNestedForeignTests.TestInheritingHere.()', - nameToRun: - './tests/test_foreign_nested_tests.py::TestNestedForeignTests::TestInheritingHere::test_foreign_test', - simpleClassName: 'TestInheritingHere', - fileName: path.join(...'tests/test_foreign_nested_tests.py'.split('/')), - testName: 'test_foreign_test', - sourceTestName: 'test_foreign_test', - sourceFileName: path.join(...'tests/external.py'.split('/')), - classDefRange: new vscode.Range(4, 10, 4, 28), - testDefRange: new vscode.Range(4, 8, 4, 25), - issueRange: new vscode.Range(5, 8, 5, 20), - issueLineText: 'assert False', - message: 'AssertionError', - imported: true, - status: TestStatus.Fail, - }, - { - className: 'tests.test_foreign_nested_tests.TestNestedForeignTests.TestInheritingHere.()', - nameToRun: - './tests/test_foreign_nested_tests.py::TestNestedForeignTests::TestInheritingHere::test_nested_normal', - fileName: path.join(...'tests/test_foreign_nested_tests.py'.split('/')), - testName: 'test_nested_normal', - sourceTestName: 'test_nested_normal', - imported: false, - status: TestStatus.Pass, - }, - { - className: 'tests.test_foreign_nested_tests.TestNestedForeignTests', - nameToRun: './tests/test_foreign_nested_tests.py::TestNestedForeignTests::test_normal', - fileName: path.join(...'tests/test_foreign_nested_tests.py'.split('/')), - testName: 'test_normal', - sourceTestName: 'test_normal', - imported: false, - status: TestStatus.Pass, - }, - { - className: 'tests.test_pytest.Test_CheckMyApp', - nameToRun: './tests/test_pytest.py::Test_CheckMyApp::test_simple_check', - fileName: path.join(...'tests/test_pytest.py'.split('/')), - testName: 'test_simple_check', - sourceTestName: 'test_simple_check', - testDefRange: new vscode.Range(7, 8, 7, 25), - message: 'demonstrating skipping', - imported: false, - status: TestStatus.Skipped, - }, - { - className: 'tests.test_pytest.Test_CheckMyApp', - nameToRun: './tests/test_pytest.py::Test_CheckMyApp::test_complex_check', - fileName: path.join(...'tests/test_pytest.py'.split('/')), - testName: 'test_complex_check', - sourceTestName: 'test_complex_check', - imported: false, - status: TestStatus.Pass, - }, - { - className: 'tests.test_pytest.Test_CheckMyApp.Test_NestedClassA.()', - nameToRun: './tests/test_pytest.py::Test_CheckMyApp::Test_NestedClassA::test_nested_class_methodB', - fileName: path.join(...'tests/test_pytest.py'.split('/')), - testName: 'test_nested_class_methodB', - sourceTestName: 'test_nested_class_methodB', - imported: false, - status: TestStatus.Pass, - }, - { - className: 'tests.test_pytest.Test_CheckMyApp.Test_NestedClassA.().Test_nested_classB_Of_A.()', - nameToRun: './tests/test_pytest.py::Test_CheckMyApp::Test_NestedClassA::Test_nested_classB_Of_A::test_d', - fileName: path.join(...'tests/test_pytest.py'.split('/')), - testName: 'test_d', - sourceTestName: 'test_d', - imported: false, - status: TestStatus.Pass, - }, - { - className: 'tests.test_pytest.Test_CheckMyApp.Test_NestedClassA.()', - nameToRun: './tests/test_pytest.py::Test_CheckMyApp::Test_NestedClassA::test_nested_class_methodC', - fileName: path.join(...'tests/test_pytest.py'.split('/')), - testName: 'test_nested_class_methodC', - sourceTestName: 'test_nested_class_methodC', - imported: false, - status: TestStatus.Pass, - }, - { - className: 'tests.test_pytest.Test_CheckMyApp', - nameToRun: './tests/test_pytest.py::Test_CheckMyApp::test_simple_check2', - fileName: path.join(...'tests/test_pytest.py'.split('/')), - testName: 'test_simple_check2', - sourceTestName: 'test_simple_check2', - imported: false, - status: TestStatus.Pass, - }, - { - className: 'tests.test_pytest.Test_CheckMyApp', - nameToRun: './tests/test_pytest.py::Test_CheckMyApp::test_complex_check2', - fileName: path.join(...'tests/test_pytest.py'.split('/')), - testName: 'test_complex_check2', - sourceTestName: 'test_complex_check2', - imported: false, - status: TestStatus.Pass, - }, - { - className: 'tests.test_pytest', - nameToRun: './tests/test_pytest.py::test_username', - fileName: path.join(...'tests/test_pytest.py'.split('/')), - testName: 'test_username', - sourceTestName: 'test_username', - imported: false, - status: TestStatus.Pass, - }, - { - className: 'tests.test_pytest', - nameToRun: './tests/test_pytest.py::test_parametrized_username[one]', - fileName: path.join(...'tests/test_pytest.py'.split('/')), - testName: 'test_parametrized_username[one]', - sourceTestName: 'test_parametrized_username', - imported: false, - status: TestStatus.Pass, - }, - { - className: 'tests.test_pytest', - nameToRun: './tests/test_pytest.py::test_parametrized_username[two]', - fileName: path.join(...'tests/test_pytest.py'.split('/')), - testName: 'test_parametrized_username[two]', - sourceTestName: 'test_parametrized_username', - imported: false, - status: TestStatus.Pass, - }, - { - className: 'tests.test_pytest', - nameToRun: './tests/test_pytest.py::test_parametrized_username[three]', - fileName: path.join(...'tests/test_pytest.py'.split('/')), - testName: 'test_parametrized_username[three]', - sourceTestName: 'test_parametrized_username', - testDefRange: new vscode.Range(38, 4, 38, 30), - issueRange: new vscode.Range(39, 4, 39, 64), - issueLineText: "assert non_parametrized_username in ['one', 'two', 'threes']", - message: "AssertionError: assert 'three' in ['one', 'two', 'threes']", - imported: false, - status: TestStatus.Fail, - }, - { - className: 'tests.test_unittest_one.Test_test1', - nameToRun: './tests/test_unittest_one.py::Test_test1::test_A', - fileName: path.join(...'tests/test_unittest_one.py'.split('/')), - testName: 'test_A', - sourceTestName: 'test_A', - testDefRange: new vscode.Range(6, 8, 6, 14), - issueRange: new vscode.Range(7, 8, 7, 36), - issueLineText: 'self.fail("Not implemented")', - message: 'AssertionError: Not implemented', - imported: false, - status: TestStatus.Fail, - }, - { - className: 'tests.test_unittest_one.Test_test1', - nameToRun: './tests/test_unittest_one.py::Test_test1::test_B', - fileName: path.join(...'tests/test_unittest_one.py'.split('/')), - testName: 'test_B', - sourceTestName: 'test_B', - imported: false, - status: TestStatus.Pass, - }, - { - className: 'tests.test_unittest_one.Test_test1', - nameToRun: './tests/test_unittest_one.py::Test_test1::test_c', - fileName: path.join(...'tests/test_unittest_one.py'.split('/')), - testName: 'test_c', - sourceTestName: 'test_c', - testDefRange: new vscode.Range(13, 8, 13, 14), - message: 'demonstrating skipping', - imported: false, - status: TestStatus.Skipped, - }, - { - className: 'tests.test_unittest_two.Test_test2', - nameToRun: './tests/test_unittest_two.py::Test_test2::test_A2', - fileName: path.join(...'tests/test_unittest_two.py'.split('/')), - testName: 'test_A2', - sourceTestName: 'test_A2', - testDefRange: new vscode.Range(3, 8, 3, 15), - issueRange: new vscode.Range(4, 8, 4, 36), - issueLineText: 'self.fail("Not implemented")', - message: 'AssertionError: Not implemented', - imported: false, - status: TestStatus.Fail, - }, - { - className: 'tests.test_unittest_two.Test_test2', - nameToRun: './tests/test_unittest_two.py::Test_test2::test_B2', - fileName: path.join(...'tests/test_unittest_two.py'.split('/')), - testName: 'test_B2', - sourceTestName: 'test_B2', - imported: false, - status: TestStatus.Pass, - }, - { - className: 'tests.test_unittest_two.Test_test2', - nameToRun: './tests/test_unittest_two.py::Test_test2::test_C2', - fileName: path.join(...'tests/test_unittest_two.py'.split('/')), - testName: 'test_C2', - sourceTestName: 'test_C2', - testDefRange: new vscode.Range(9, 8, 9, 15), - issueRange: new vscode.Range(10, 8, 10, 41), - issueLineText: "self.assertEqual(1,2,'Not equal')", - message: 'AssertionError: 1 != 2 : Not equal', - imported: false, - status: TestStatus.Fail, - }, - { - className: 'tests.test_unittest_two.Test_test2', - nameToRun: './tests/test_unittest_two.py::Test_test2::test_D2', - fileName: path.join(...'tests/test_unittest_two.py'.split('/')), - testName: 'test_D2', - sourceTestName: 'test_D2', - testDefRange: new vscode.Range(12, 8, 12, 15), - issueRange: new vscode.Range(13, 8, 13, 31), - issueLineText: 'raise ArithmeticError()', - message: 'ArithmeticError', - imported: false, - status: TestStatus.Fail, - }, - { - className: 'tests.test_unittest_two.Test_test2a', - nameToRun: './tests/test_unittest_two.py::Test_test2a::test_222A2', - fileName: path.join(...'tests/test_unittest_two.py'.split('/')), - testName: 'test_222A2', - sourceTestName: 'test_222A2', - testDefRange: new vscode.Range(17, 8, 17, 18), - issueRange: new vscode.Range(18, 8, 18, 36), - issueLineText: 'self.fail("Not implemented")', - message: 'AssertionError: Not implemented', - imported: false, - passOnFailedRun: true, - status: TestStatus.Fail, - }, - { - className: 'tests.test_unittest_two.Test_test2a', - nameToRun: './tests/test_unittest_two.py::Test_test2a::test_222B2', - fileName: path.join(...'tests/test_unittest_two.py'.split('/')), - testName: 'test_222B2', - sourceTestName: 'test_222B2', - imported: false, - status: TestStatus.Pass, - }, - { - className: 'tests.unittest_three_test.Test_test3', - nameToRun: './tests/unittest_three_test.py::Test_test3::test_A', - fileName: path.join(...'tests/unittest_three_test.py'.split('/')), - testName: 'test_A', - sourceTestName: 'test_A', - testDefRange: new vscode.Range(4, 8, 4, 14), - issueRange: new vscode.Range(5, 8, 5, 36), - issueLineText: 'self.fail("Not implemented")', - message: 'AssertionError: Not implemented', - imported: false, - status: TestStatus.Fail, - }, - { - className: 'tests.unittest_three_test.Test_test3', - nameToRun: './tests/unittest_three_test.py::Test_test3::test_B', - fileName: path.join(...'tests/unittest_three_test.py'.split('/')), - testName: 'test_B', - sourceTestName: 'test_B', - imported: false, - status: TestStatus.Pass, - }, -]; - -export interface ITestScenarioDetails { - scenarioName: string; - discoveryOutput: string; - runOutput: string; - testsToRun?: TestsToRun; - testDetails?: ITestDetails[]; - testSuiteIndex?: number; - testFunctionIndex?: number; - shouldRunFailed?: boolean; - failedRunOutput?: string; -} - -const IGNORED_RESOURCE = (undefined as unknown) as vscode.Uri; -const IGNORED_TESTS_TO_RUN = (undefined as unknown) as TestsToRun; -export const testScenarios: ITestScenarioDetails[] = [ - { - scenarioName: 'Run Tests', - discoveryOutput: 'one.output', - runOutput: 'one.xml', - testsToRun: IGNORED_TESTS_TO_RUN, - testDetails: allTestDetails.filter(() => true), - }, - { - scenarioName: 'Run Specific Test File', - discoveryOutput: 'three.output', - runOutput: 'three.xml', - testsToRun: { - testFile: [ - { - fullPath: path.join(UNITTEST_TEST_FILES_PATH, 'tests', 'test_another_pytest.py'), - name: 'tests/test_another_pytest.py', - nameToRun: 'tests/test_another_pytest.py', - xmlName: 'tests/test_another_pytest.py', - functions: [], - suites: [], - time: 0, - resource: IGNORED_RESOURCE, - }, - ], - testFolder: [], - testFunction: [], - testSuite: [], - }, - testDetails: allTestDetails.filter((td) => td.fileName === path.join('tests', 'test_another_pytest.py')), - }, - { - scenarioName: 'Run Specific Test Suite', - discoveryOutput: 'four.output', - runOutput: 'four.xml', - testsToRun: IGNORED_TESTS_TO_RUN, - testSuiteIndex: 0, - testDetails: allTestDetails.filter((td) => td.className === 'test_root.Test_Root_test1'), - }, - { - scenarioName: 'Run Specific Test Function', - discoveryOutput: 'five.output', - runOutput: 'five.xml', - testsToRun: IGNORED_TESTS_TO_RUN, - testFunctionIndex: 0, - testDetails: allTestDetails.filter((td) => td.testName === 'test_Root_A'), - }, - { - scenarioName: 'Run Failed Tests', - discoveryOutput: 'two.output', - runOutput: 'two.xml', - testsToRun: IGNORED_TESTS_TO_RUN, - // We ignore the "td" arg to the filter callback. - testDetails: allTestDetails.filter(() => true), - shouldRunFailed: true, - failedRunOutput: 'two.again.xml', - }, -]; diff --git a/src/test/testing/pytest/pytest_unittest_parser_data.ts b/src/test/testing/pytest/pytest_unittest_parser_data.ts deleted file mode 100644 index f0197ee87c7f..000000000000 --- a/src/test/testing/pytest/pytest_unittest_parser_data.ts +++ /dev/null @@ -1,2087 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -// disable the ' quotemark, as we need to consume many strings from stdout that use that -// test delimiter exclusively. - -export enum PytestDataPlatformType { - NonWindows = 'non-windows', - Windows = 'windows', -} - -export type PytestDiscoveryScenario = { - // eslint-disable-next-line camelcase - pytest_version_spec: string; - platform: string; - description: string; - rootdir: string; - // eslint-disable-next-line camelcase - test_functions: string[]; - functionCount: number; - stdout: string[]; -}; - -// Data to test the pytest unit test parser with. See pytest.discovery.unit.test.ts. -export const pytestScenarioData: PytestDiscoveryScenario[] = [ - { - pytest_version_spec: '< 3.7', - platform: PytestDataPlatformType.NonWindows, - description: - 'Non-package source, tests throughout a deeper tree, including 2 distinct folder paths at different levels.', - rootdir: '/home/user/test/pytest_scenario', - test_functions: [ - 'src/test_things.py::test_things_major', - 'test/this/is/deep/testing/test_very_deeply.py::test_math_works', - ], - functionCount: 9, - stdout: [ - '============================= test session starts ==============================', - 'platform linux -- Python 3.7.0+, pytest-3.6.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: /home/user/test/pytest_scenario, inifile:', - 'collected 9 items', - "", - " ", - " ", - "", - " ", - "", - " ", - "", - " ", - "", - " ", - "", - " ", - " ", - "", - " ", - '', - '========================= no tests ran in 0.02 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 3.7 < 4.1', - platform: PytestDataPlatformType.NonWindows, - description: - 'Non-package source, tests throughout a deeper tree, including 2 distinct folder paths at different levels.', - rootdir: '/home/user/test/pytest_scenario', - test_functions: [ - 'src/test_things.py::test_things_major', - 'test/this/is/deep/testing/test_very_deeply.py::test_math_works', - ], - functionCount: 9, - stdout: [ - '============================= test session starts ==============================', - 'platform linux -- Python 3.7.0+, pytest-3.7.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: /home/user/test/pytest_scenario, inifile:', - 'collected 9 items', - "", - " ", - " ", - "", - " ", - "", - " ", - "", - " ", - "", - " ", - "", - " ", - " ", - "", - " ", - '', - '========================= no tests ran in 0.18 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 4.1', - platform: PytestDataPlatformType.NonWindows, - description: - 'Non-package source, tests throughout a deeper tree, including 2 distinct folder paths at different levels.', - rootdir: '/home/user/test/pytest_scenario', - test_functions: [ - 'src/test_things.py::test_things_major', - 'test/this/is/deep/testing/test_very_deeply.py::test_math_works', - ], - functionCount: 9, - stdout: [ - '============================= test session starts ==============================', - 'platform linux -- Python 3.7.0+, pytest-4.1.0, py-1.6.0, pluggy-0.7.1', - 'rootdir: /home/user/test/pytest_scenario, inifile:', - 'collected 9 items', - '', - ' ', - ' ', - '', - ' ', - '', - ' ', - '', - ' ', - '', - ' ', - '', - ' ', - ' ', - '', - ' ', - '', - '========================= no tests ran in 0.18 seconds =========================', - ], - }, - { - pytest_version_spec: '< 3.7', - platform: PytestDataPlatformType.NonWindows, - description: 'Non-package source, 2 test modules in subfolders of root, and 2 more in one (direct) subfolder.', - rootdir: '/home/user/test/pytest_scenario', - test_functions: ['src/test_things.py::test_things_major', 'src/under/test_stuff.py::test_platform'], - functionCount: 5, - stdout: [ - '============================= test session starts ==============================', - 'platform linux -- Python 3.7.0+, pytest-3.6.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: /home/user/test/pytest_scenario, inifile:', - 'collected 5 items', - "", - " ", - " ", - "", - " ", - "", - " ", - "", - " ", - '', - '========================= no tests ran in 0.05 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 3.7 < 4.1', - platform: PytestDataPlatformType.NonWindows, - description: 'Non-package source, 2 test modules in subfolders of root, and 2 more in one (direct) subfolder.', - rootdir: '/home/user/test/pytest_scenario', - test_functions: ['src/test_things.py::test_things_major', 'src/under/test_stuff.py::test_platform'], - functionCount: 5, - stdout: [ - '============================= test session starts ==============================', - 'platform linux -- Python 3.7.0+, pytest-3.7.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: /home/user/test/pytest_scenario, inifile:', - 'collected 5 items', - "", - " ", - " ", - "", - " ", - "", - " ", - "", - " ", - '', - '========================= no tests ran in 0.03 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 4.1', - platform: PytestDataPlatformType.NonWindows, - description: 'Non-package source, 2 test modules in subfolders of root, and 2 more in one (direct) subfolder.', - rootdir: '/home/user/test/pytest_scenario', - test_functions: ['src/test_things.py::test_things_major', 'src/under/test_stuff.py::test_platform'], - functionCount: 5, - stdout: [ - '============================= test session starts ==============================', - 'platform linux -- Python 3.7.0+, pytest-4.1.0, py-1.6.0, pluggy-0.7.1', - 'rootdir: /home/user/test/pytest_scenario, inifile:', - 'collected 5 items', - '', - ' ', - ' ', - '', - ' ', - '', - ' ', - '', - ' ', - '', - '========================= no tests ran in 0.03 seconds =========================', - ], - }, - { - pytest_version_spec: '< 3.7', - platform: PytestDataPlatformType.NonWindows, - description: 'Non-package source, 2 test modules in root folder and two more in one (direct) subfolder.', - rootdir: '/home/user/test/pytest_scenario', - test_functions: ['test_things.py::test_things_major', 'under/test_stuff.py::test_platform'], - functionCount: 5, - stdout: [ - '============================= test session starts ==============================', - 'platform linux -- Python 3.7.0+, pytest-3.6.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: /home/user/test/pytest_scenario, inifile:', - 'collected 5 items', - "", - " ", - " ", - "", - " ", - "", - " ", - "", - " ", - '', - '========================= no tests ran in 0.12 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 3.7 < 4.1', - platform: PytestDataPlatformType.NonWindows, - description: 'Non-package source, 2 test modules in root folder and two more in one (direct) subfolder.', - rootdir: '/home/user/test/pytest_scenario', - test_functions: ['test_things.py::test_things_major', 'under/test_stuff.py::test_platform'], - functionCount: 5, - stdout: [ - '============================= test session starts ==============================', - 'platform linux -- Python 3.7.0+, pytest-3.7.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: /home/user/test/pytest_scenario, inifile:', - 'collected 5 items', - "", - " ", - " ", - "", - " ", - "", - " ", - "", - " ", - '', - '========================= no tests ran in 0.12 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 4.1', - platform: PytestDataPlatformType.NonWindows, - description: 'Non-package source, 2 test modules in root folder and two more in one (direct) subfolder.', - rootdir: '/home/user/test/pytest_scenario', - test_functions: ['test_things.py::test_things_major', 'under/test_stuff.py::test_platform'], - functionCount: 5, - stdout: [ - '============================= test session starts ==============================', - 'platform linux -- Python 3.7.0+, pytest-4.1.0, py-1.6.0, pluggy-0.7.1', - 'rootdir: /home/user/test/pytest_scenario, inifile:', - 'collected 5 items', - '', - ' ', - ' ', - '', - ' ', - '', - ' ', - '', - ' ', - '', - '========================= no tests ran in 0.12 seconds =========================', - ], - }, - { - pytest_version_spec: '< 3.7', - platform: PytestDataPlatformType.NonWindows, - description: 'Non-package source, 2 test modules in a subfolder off the root.', - rootdir: '/home/user/test/pytest_scenario', - test_functions: ['under/test_other_stuff.py::test_machine_values', 'under/test_stuff.py::test_platform'], - functionCount: 2, - stdout: [ - '============================= test session starts ==============================', - 'platform linux -- Python 3.7.0+, pytest-3.6.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: /home/user/test/pytest_scenario, inifile:', - 'collected 2 items', - "", - " ", - "", - " ", - '', - '========================= no tests ran in 0.06 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 3.7 < 4.1', - platform: PytestDataPlatformType.NonWindows, - description: 'Non-package source, 2 test modules in a subfolder off the root.', - rootdir: '/home/user/test/pytest_scenario', - test_functions: ['under/test_other_stuff.py::test_machine_values', 'under/test_stuff.py::test_platform'], - functionCount: 2, - stdout: [ - '============================= test session starts ==============================', - 'platform linux -- Python 3.7.0+, pytest-3.7.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: /home/user/test/pytest_scenario, inifile:', - 'collected 2 items', - "", - " ", - "", - " ", - '', - '========================= no tests ran in 0.05 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 4.1', - platform: PytestDataPlatformType.NonWindows, - description: 'Non-package source, 2 test modules in a subfolder off the root.', - rootdir: '/home/user/test/pytest_scenario', - test_functions: ['under/test_other_stuff.py::test_machine_values', 'under/test_stuff.py::test_platform'], - functionCount: 2, - stdout: [ - '============================= test session starts ==============================', - 'platform linux -- Python 3.7.0+, pytest4.1.0, py-1.6.0, pluggy-0.7.1', - 'rootdir: /home/user/test/pytest_scenario, inifile:', - 'collected 2 items', - '', - ' ', - '', - ' ', - '', - '========================= no tests ran in 0.05 seconds =========================', - ], - }, - { - pytest_version_spec: '< 3.7', - platform: PytestDataPlatformType.NonWindows, - description: 'Non-package source, 2 modules at the topmost level.', - rootdir: '/home/user/test/pytest_scenario', - test_functions: ['test_other_stuff.py::test_machine_values', 'test_stuff.py::test_platform'], - functionCount: 2, - stdout: [ - '============================= test session starts ==============================', - 'platform linux -- Python 3.7.0+, pytest-3.6.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: /home/user/test/pytest_scenario, inifile:', - 'collected 2 items', - "", - " ", - "", - " ", - '', - '========================= no tests ran in 0.05 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 3.7 < 4.1', - platform: PytestDataPlatformType.NonWindows, - description: 'Non-package source, 2 modules at the topmost level.', - rootdir: '/home/user/test/pytest_scenario', - test_functions: ['test_other_stuff.py::test_machine_values', 'test_stuff.py::test_platform'], - functionCount: 2, - stdout: [ - '============================= test session starts ==============================', - 'platform linux -- Python 3.7.0+, pytest-3.7.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: /home/user/test/pytest_scenario, inifile:', - 'collected 2 items', - "", - " ", - "", - " ", - '', - '========================= no tests ran in 0.05 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 4.1', - platform: PytestDataPlatformType.NonWindows, - description: 'Non-package source, 2 modules at the topmost level.', - rootdir: '/home/user/test/pytest_scenario', - test_functions: ['test_other_stuff.py::test_machine_values', 'test_stuff.py::test_platform'], - functionCount: 2, - stdout: [ - '============================= test session starts ==============================', - 'platform linux -- Python 3.7.0+, pytest-4.1.0, py-1.6.0, pluggy-0.7.1', - 'rootdir: /home/user/test/pytest_scenario, inifile:', - 'collected 2 items', - '', - ' ', - '', - ' ', - '', - '========================= no tests ran in 0.05 seconds =========================', - ], - }, - { - pytest_version_spec: '< 3.7', - platform: PytestDataPlatformType.NonWindows, - description: - 'Package-based source, tests throughout a deeper tree, including 2 distinct folder paths at different levels.', - rootdir: '/home/user/test/pytest_scenario', - test_functions: [ - 'test_basic_root.py::test_basic_major', - 'test/test_other_basic.py::test_basic_major_minor_internal', - 'test/subdir/under/another/subdir/test_other_basic_sub.py::test_basic_major_minor', - ], - functionCount: 16, - stdout: [ - '============================= test session starts ==============================', - 'platform linux -- Python 3.7.0+, pytest-3.6.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: /home/user/test/pytest_scenario, inifile:', - 'collected 16 items', - "", - " ", - " ", - "", - " ", - " ", - "", - " ", - " ", - "", - " ", - " ", - "", - " ", - " ", - "", - " ", - " ", - "", - " ", - " ", - "", - " ", - " ", - '', - '========================= no tests ran in 0.07 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 3.7 < 4.1', - platform: PytestDataPlatformType.NonWindows, - description: - 'Package-based source, tests throughout a deeper tree, including 2 distinct folder paths at different levels.', - rootdir: '/home/user/test/pytest_scenario', - test_functions: [ - 'test_basic_root.py::test_basic_major', - 'test/test_other_basic.py::test_basic_major_minor_internal', - 'test/subdir/under/another/subdir/test_other_basic_sub.py::test_basic_major_minor', - 'test/uneven/folders/test_other_basic_uneven.py::test_basic_major_minor_internal_uneven', - ], - functionCount: 16, - stdout: [ - '============================= test session starts ==============================', - 'platform linux -- Python 3.7.0+, pytest-3.7.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: /home/user/test/pytest_scenario, inifile:', - 'collected 16 items', - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - '', - '========================= no tests ran in 0.13 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 4.1', - platform: PytestDataPlatformType.NonWindows, - description: - 'Package-based source, tests throughout a deeper tree, including 2 distinct folder paths at different levels.', - rootdir: '/home/user/test/pytest_scenario', - test_functions: [ - 'test_basic_root.py::test_basic_major', - 'test/test_other_basic.py::test_basic_major_minor_internal', - 'test/subdir/under/another/subdir/test_other_basic_sub.py::test_basic_major_minor', - 'test/uneven/folders/test_other_basic_uneven.py::test_basic_major_minor_internal_uneven', - ], - functionCount: 16, - stdout: [ - '============================= test session starts ==============================', - 'platform linux -- Python 3.7.0+, pytest-4.1.0, py-1.6.0, pluggy-0.7.1', - 'rootdir: /home/user/test/pytest_scenario, inifile:', - 'collected 16 items', - '', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - '', - '========================= no tests ran in 0.13 seconds =========================', - ], - }, - { - pytest_version_spec: '< 3.7', - platform: PytestDataPlatformType.NonWindows, - description: - 'Package-based source, 2 test modules in subfolders of root, and 2 more in one (direct) subfolder.', - rootdir: '/home/user/test/pytest_scenario', - test_functions: [ - 'test/test_other_basic.py::test_basic_major_minor_internal', - 'test/subdir/test_other_basic_sub.py::test_basic_major_minor', - ], - functionCount: 12, - stdout: [ - '============================= test session starts ==============================', - 'platform linux -- Python 3.7.0+, pytest-3.6.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: /home/user/test/pytest_scenario, inifile:', - 'collected 12 items', - "", - " ", - " ", - "", - " ", - " ", - "", - " ", - " ", - "", - " ", - " ", - "", - " ", - " ", - "", - " ", - " ", - '', - '========================= no tests ran in 0.18 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 3.7 < 4.1', - platform: PytestDataPlatformType.NonWindows, - description: - 'Package-based source, 2 test modules in subfolders of root, and 2 more in one (direct) subfolder.', - rootdir: '/home/user/test/pytest_scenario', - test_functions: [ - 'test/test_other_basic.py::test_basic_major_minor_internal', - 'test/subdir/test_other_basic_sub.py::test_basic_major_minor', - ], - functionCount: 12, - stdout: [ - '============================= test session starts ==============================', - 'platform linux -- Python 3.7.0+, pytest-3.7.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: /home/user/test/pytest_scenario, inifile:', - 'collected 12 items', - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - '', - '========================= no tests ran in 0.07 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 4.1', - platform: PytestDataPlatformType.NonWindows, - description: - 'Package-based source, 2 test modules in subfolders of root, and 2 more in one (direct) subfolder.', - rootdir: '/home/user/test/pytest_scenario', - test_functions: [ - 'test/test_other_basic.py::test_basic_major_minor_internal', - 'test/subdir/test_other_basic_sub.py::test_basic_major_minor', - ], - functionCount: 12, - stdout: [ - '============================= test session starts ==============================', - 'platform linux -- Python 3.7.0+, pytest-4.1.0, py-1.6.0, pluggy-0.7.1', - 'rootdir: /home/user/test/pytest_scenario, inifile:', - 'collected 12 items', - '', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - '', - '========================= no tests ran in 0.07 seconds =========================', - ], - }, - { - pytest_version_spec: '< 3.7', - platform: PytestDataPlatformType.NonWindows, - description: 'Package-based source, 2+ test modules in root folder and two more in one (direct) subfolder.', - rootdir: '/home/user/test/pytest_scenario', - test_functions: [ - 'test_other_basic_root.py::test_basic_major_minor_internal', - 'test/test_other_basic_sub.py::test_basic_major_minor', - ], - functionCount: 12, - stdout: [ - '============================= test session starts ==============================', - 'platform linux -- Python 3.7.0+, pytest-3.6.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: /home/user/test/pytest_scenario, inifile:', - 'collected 12 items', - "", - " ", - " ", - "", - " ", - " ", - "", - " ", - " ", - "", - " ", - " ", - "", - " ", - " ", - "", - " ", - " ", - '', - '========================= no tests ran in 0.18 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 3.7 < 4.1', - platform: PytestDataPlatformType.NonWindows, - description: 'Package-based source, 2+ test modules in root folder and two more in one (direct) subfolder.', - rootdir: '/home/user/test/pytest_scenario', - test_functions: [ - 'test_other_basic_root.py::test_basic_major_minor_internal', - 'test/test_basic_sub.py::test_basic_major', - 'test/test_basic_sub.py::test_basic_minor', - ], - functionCount: 12, - stdout: [ - '============================= test session starts ==============================', - 'platform linux -- Python 3.7.0+, pytest-3.7.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: /home/user/test/pytest_scenario, inifile:', - 'collected 12 items', - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - '', - '========================= no tests ran in 0.22 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 4.1', - platform: PytestDataPlatformType.NonWindows, - description: 'Package-based source, 2+ test modules in root folder and two more in one (direct) subfolder.', - rootdir: '/home/user/test/pytest_scenario', - test_functions: [ - 'test_other_basic_root.py::test_basic_major_minor_internal', - 'test/test_basic_sub.py::test_basic_major', - 'test/test_basic_sub.py::test_basic_minor', - ], - functionCount: 12, - stdout: [ - '============================= test session starts ==============================', - 'platform linux -- Python 3.7.0+, pytest-4.1.0, py-1.6.0, pluggy-0.7.1', - 'rootdir: /home/user/test/pytest_scenario, inifile:', - 'collected 12 items', - '', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - '', - '========================= no tests ran in 0.22 seconds =========================', - ], - }, - { - pytest_version_spec: '< 3.7', - platform: PytestDataPlatformType.NonWindows, - description: 'Package-based source, 2+ test modules in a subfolder off the root.', - rootdir: '/home/user/test/pytest_scenario', - test_functions: [ - 'test/test_basic.py::test_basic_minor', - 'test/test_other_basic.py::test_basic_major_minor', - 'test/test_other_basic_root.py::test_basic_major_minor', - 'test/test_other_basic_sub.py::test_basic_major_minor_internal', - ], - functionCount: 12, - stdout: [ - '============================= test session starts ==============================', - 'platform linux -- Python 3.7.0+, pytest-3.6.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: /home/user/test/pytest_scenario, inifile:', - 'collected 12 items', - "", - " ", - " ", - "", - " ", - " ", - "", - " ", - " ", - "", - " ", - " ", - "", - " ", - " ", - "", - " ", - " ", - '', - '========================= no tests ran in 0.15 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 3.7 < 4.1', - platform: PytestDataPlatformType.NonWindows, - description: 'Package-based source, 2+ test modules in a subfolder off the root.', - rootdir: '/home/user/test/pytest_scenario', - test_functions: [ - 'test/test_basic.py::test_basic_minor', - 'test/test_other_basic.py::test_basic_major_minor', - 'test/test_other_basic_root.py::test_basic_major_minor', - 'test/test_other_basic_sub.py::test_basic_major_minor_internal', - ], - functionCount: 12, - stdout: [ - '============================= test session starts ==============================', - 'platform linux -- Python 3.7.0+, pytest-3.7.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: /home/user/test/pytest_scenario, inifile:', - 'collected 12 items', - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - '', - '========================= no tests ran in 0.15 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 4.1', - platform: PytestDataPlatformType.NonWindows, - description: 'Package-based source, 2+ test modules in a subfolder off the root.', - rootdir: '/home/user/test/pytest_scenario', - test_functions: [ - 'test/test_basic.py::test_basic_minor', - 'test/test_other_basic.py::test_basic_major_minor', - 'test/test_other_basic_root.py::test_basic_major_minor', - 'test/test_other_basic_sub.py::test_basic_major_minor_internal', - ], - functionCount: 12, - stdout: [ - '============================= test session starts ==============================', - 'platform linux -- Python 3.7.0+, pytest-4.1.0, py-1.6.0, pluggy-0.7.1', - 'rootdir: /home/user/test/pytest_scenario, inifile:', - 'collected 12 items', - '', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - '', - '========================= no tests ran in 0.15 seconds =========================', - ], - }, - { - pytest_version_spec: '< 3.7', - platform: PytestDataPlatformType.NonWindows, - description: 'Package-based source, 2+ modules at the topmost level.', - rootdir: '/home/user/test/pytest_scenario', - test_functions: [ - 'test_basic.py::test_basic_major', - 'test_basic_root.py::test_basic_major', - 'test_other_basic_root.py::test_basic_major_minor', - 'test_other_basic_sub.py::test_basic_major_minor_internal', - ], - functionCount: 12, - stdout: [ - '============================= test session starts ==============================', - 'platform linux -- Python 3.7.0+, pytest-3.6.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: /home/user/test/pytest_scenario, inifile:', - 'collected 12 items', - "", - " ", - " ", - "", - " ", - " ", - "", - " ", - " ", - "", - " ", - " ", - "", - " ", - " ", - "", - " ", - " ", - '', - '========================= no tests ran in 0.23 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 3.7 < 4.1', - platform: PytestDataPlatformType.NonWindows, - description: 'Package-based source, 2+ modules at the topmost level.', - rootdir: '/home/user/test/pytest_scenario', - test_functions: [ - 'test_basic.py::test_basic_major', - 'test_basic_root.py::test_basic_major', - 'test_other_basic_root.py::test_basic_major_minor', - 'test_other_basic_sub.py::test_basic_major_minor_internal', - ], - functionCount: 12, - stdout: [ - '============================= test session starts ==============================', - 'platform linux -- Python 3.7.0+, pytest-3.7.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: /home/user/test/pytest_scenario, inifile:', - 'collected 12 items', - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - '', - '========================= no tests ran in 0.16 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 4.1', - platform: PytestDataPlatformType.NonWindows, - description: 'Package-based source, 2+ modules at the topmost level.', - rootdir: '/home/user/test/pytest_scenario', - test_functions: [ - 'test_basic.py::test_basic_major', - 'test_basic_root.py::test_basic_major', - 'test_other_basic_root.py::test_basic_major_minor', - 'test_other_basic_sub.py::test_basic_major_minor_internal', - ], - functionCount: 12, - stdout: [ - '============================= test session starts ==============================', - 'platform linux -- Python 3.7.0+, pytest-4.1.0, py-1.6.0, pluggy-0.7.1', - 'rootdir: /home/user/test/pytest_scenario, inifile:', - 'collected 12 items', - '', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - '', - '========================= no tests ran in 0.16 seconds =========================', - ], - }, - { - pytest_version_spec: '< 3.7', - platform: PytestDataPlatformType.Windows, - description: - 'Package-based source, tests throughout a deeper tree, including 2 distinct folder paths at different levels.', - rootdir: 'e:\\user\\test\\pytest_scenario', - test_functions: [ - 'other_tests/test_base_stuff.py::test_do_other_test', - 'other_tests/test_base_stuff.py::test_do_test', - 'tests/further_tests/test_gimme_5.py::test_gimme_5', - 'tests/further_tests/test_multiply.py::test_times_10', - 'tests/further_tests/test_multiply.py::test_times_2', - 'tests/further_tests/deeper/test_more_multiply.py::test_times_100', - 'tests/further_tests/deeper/test_more_multiply.py::test_times_negative_1', - ], - functionCount: 7, - stdout: [ - '============================= test session starts =============================', - 'platform win32 -- Python 3.7.0, pytest-3.6.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: e:\\user\\test\\pytest_scenario, inifile:', - 'collected 8 items', - "", - " ", - " ", - "", - " ", - "", - " ", - " ", - "", - " ", - " ", - '', - '======================== no tests ran in 0.30 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 3.7 < 4.1', - platform: PytestDataPlatformType.Windows, - description: - 'Package-based source, tests throughout a deeper tree, including 2 distinct folder paths at different levels.', - rootdir: 'e:\\user\\test\\pytest_scenario', - test_functions: [ - 'other_tests/test_base_stuff.py::test_do_other_test', - 'other_tests/test_base_stuff.py::test_do_test', - 'tests/further_tests/test_gimme_5.py::test_gimme_5', - 'tests/further_tests/test_multiply.py::test_times_10', - 'tests/further_tests/test_multiply.py::test_times_2', - 'tests/further_tests/deeper/test_more_multiply.py::test_times_100', - 'tests/further_tests/deeper/test_more_multiply.py::test_times_negative_1', - ], - functionCount: 7, - stdout: [ - '============================= test session starts =============================', - 'platform win32 -- Python 3.7.0, pytest-3.7.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: e:\\user\\test\\pytest_scenario, inifile:', - 'collected 7 items', - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - '', - '======================== no tests ran in 0.42 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 4.1', - platform: PytestDataPlatformType.Windows, - description: - 'Package-based source, tests throughout a deeper tree, including 2 distinct folder paths at different levels.', - rootdir: 'e:\\user\\test\\pytest_scenario', - test_functions: [ - 'other_tests/test_base_stuff.py::test_do_other_test', - 'other_tests/test_base_stuff.py::test_do_test', - 'tests/further_tests/test_gimme_5.py::test_gimme_5', - 'tests/further_tests/test_multiply.py::test_times_10', - 'tests/further_tests/test_multiply.py::test_times_2', - 'tests/further_tests/deeper/test_more_multiply.py::test_times_100', - 'tests/further_tests/deeper/test_more_multiply.py::test_times_negative_1', - ], - functionCount: 7, - stdout: [ - '============================= test session starts =============================', - 'platform win32 -- Python 3.7.0, pytest-4.1.0, py-1.6.0, pluggy-0.7.1', - 'rootdir: e:\\user\\test\\pytest_scenario, inifile:', - 'collected 7 items', - '', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - '', - '======================== no tests ran in 0.42 seconds =========================', - ], - }, - { - pytest_version_spec: '< 3.7', - platform: PytestDataPlatformType.Windows, - description: - 'Non-package source, tests throughout a deeper tree, including 2 distinct folder paths at different levels.', - rootdir: 'e:\\user\\test\\pytest_scenario', - test_functions: [ - 'other_tests/test_base_stuff.py::test_do_other_test', - 'other_tests/test_base_stuff.py::test_do_test', - 'tests/further_tests/test_gimme_5.py::test_gimme_5', - 'tests/further_tests/test_multiply.py::test_times_10', - 'tests/further_tests/test_multiply.py::test_times_2', - 'tests/further_tests/deeper/test_more_multiply.py::test_times_100', - 'tests/further_tests/deeper/test_more_multiply.py::test_times_negative_1', - ], - functionCount: 7, - stdout: [ - '============================= test session starts =============================', - 'platform win32 -- Python 3.7.0, pytest-3.6.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: e:\\user\\test\\pytest_scenario, inifile:', - 'collected 7 items', - "", - " ", - " ", - "", - " ", - "", - " ", - " ", - "", - " ", - " ", - '', - '======================== no tests ran in 0.11 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 3.7 < 4.1', - platform: PytestDataPlatformType.Windows, - description: - 'Non-package source, tests throughout a deeper tree, including 2 distinct folder paths at different levels.', - rootdir: 'e:\\user\\test\\pytest_scenario', - test_functions: [ - 'other_tests/test_base_stuff.py::test_do_other_test', - 'other_tests/test_base_stuff.py::test_do_test', - 'tests/further_tests/test_gimme_5.py::test_gimme_5', - 'tests/further_tests/test_multiply.py::test_times_10', - 'tests/further_tests/test_multiply.py::test_times_2', - 'tests/further_tests/deeper/test_more_multiply.py::test_times_100', - 'tests/further_tests/deeper/test_more_multiply.py::test_times_negative_1', - ], - functionCount: 7, - stdout: [ - '============================= test session starts =============================', - 'platform win32 -- Python 3.7.0, pytest-3.7.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: e:\\user\\test\\pytest_scenario, inifile:', - 'collected 7 items', - "", - " ", - " ", - "", - " ", - "", - " ", - " ", - "", - " ", - " ", - '', - '======================== no tests ran in 0.17 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 4.1', - platform: PytestDataPlatformType.Windows, - description: - 'Non-package source, tests throughout a deeper tree, including 2 distinct folder paths at different levels.', - rootdir: 'e:\\user\\test\\pytest_scenario', - test_functions: [ - 'other_tests/test_base_stuff.py::test_do_other_test', - 'other_tests/test_base_stuff.py::test_do_test', - 'tests/further_tests/test_gimme_5.py::test_gimme_5', - 'tests/further_tests/test_multiply.py::test_times_10', - 'tests/further_tests/test_multiply.py::test_times_2', - 'tests/further_tests/deeper/test_more_multiply.py::test_times_100', - 'tests/further_tests/deeper/test_more_multiply.py::test_times_negative_1', - ], - functionCount: 7, - stdout: [ - '============================= test session starts =============================', - 'platform win32 -- Python 3.7.0, pytest-4.1.0, py-1.6.0, pluggy-0.7.1', - 'rootdir: e:\\user\\test\\pytest_scenario, inifile:', - 'collected 7 items', - '', - ' ', - ' ', - '', - ' ', - '', - ' ', - ' ', - '', - ' ', - ' ', - '', - '======================== no tests ran in 0.17 seconds =========================', - ], - }, - { - pytest_version_spec: '< 3.7', - platform: PytestDataPlatformType.Windows, - description: - 'Package-based source, 2 test modules in subfolders of root, and 2 more in one (direct) subfolder.', - rootdir: 'e:\\user\\test\\pytest_scenario', - test_functions: [ - 'tests/test_base_stuff.py::test_do_test', - 'tests/test_base_stuff.py::test_do_other_test', - 'tests/test_gimme_5.py::test_gimme_5', - 'tests/further_tests/test_more_multiply.py::test_times_100', - 'tests/further_tests/test_more_multiply.py::test_times_negative_1', - 'tests/further_tests/test_multiply.py::test_times_10', - 'tests/further_tests/test_multiply.py::test_times_2', - ], - functionCount: 7, - stdout: [ - '============================= test session starts =============================', - 'platform win32 -- Python 3.7.0, pytest-3.6.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: e:\\user\\test\\pytest_scenario, inifile:', - 'collected 7 items', - "", - " ", - " ", - "", - " ", - "", - " ", - " ", - "", - " ", - " ", - '', - '======================== no tests ran in 0.26 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 3.7 < 4.1', - platform: PytestDataPlatformType.Windows, - description: - 'Package-based source, 2 test modules in subfolders of root, and 2 more in one (direct) subfolder.', - rootdir: 'e:\\user\\test\\pytest_scenario', - test_functions: [ - 'tests/test_base_stuff.py::test_do_test', - 'tests/test_base_stuff.py::test_do_other_test', - 'tests/test_gimme_5.py::test_gimme_5', - 'tests/further_tests/test_more_multiply.py::test_times_100', - 'tests/further_tests/test_more_multiply.py::test_times_negative_1', - 'tests/further_tests/test_multiply.py::test_times_10', - 'tests/further_tests/test_multiply.py::test_times_2', - ], - functionCount: 7, - stdout: [ - '============================= test session starts =============================', - 'platform win32 -- Python 3.7.0, pytest-3.7.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: e:\\user\\test\\pytest_scenario, inifile:', - 'collected 7 items', - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - '', - '======================== no tests ran in 0.38 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 4.1', - platform: PytestDataPlatformType.Windows, - description: - 'Package-based source, 2 test modules in subfolders of root, and 2 more in one (direct) subfolder.', - rootdir: 'e:\\user\\test\\pytest_scenario', - test_functions: [ - 'tests/test_base_stuff.py::test_do_test', - 'tests/test_base_stuff.py::test_do_other_test', - 'tests/test_gimme_5.py::test_gimme_5', - 'tests/further_tests/test_more_multiply.py::test_times_100', - 'tests/further_tests/test_more_multiply.py::test_times_negative_1', - 'tests/further_tests/test_multiply.py::test_times_10', - 'tests/further_tests/test_multiply.py::test_times_2', - ], - functionCount: 7, - stdout: [ - '============================= test session starts =============================', - 'platform win32 -- Python 3.7.0, pytest-4.1.0, py-1.6.0, pluggy-0.7.1', - 'rootdir: e:\\user\\test\\pytest_scenario, inifile:', - 'collected 7 items', - '', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - '', - '======================== no tests ran in 0.38 seconds =========================', - ], - }, - { - pytest_version_spec: '< 3.7', - platform: PytestDataPlatformType.Windows, - description: 'Non-package source, 2 test modules in subfolders of root, and 2 more in one (direct) subfolder.', - rootdir: 'e:\\user\\test\\pytest_scenario', - test_functions: [ - 'tests/test_base_stuff.py::test_do_test', - 'tests/test_base_stuff.py::test_do_other_test', - 'tests/test_gimme_5.py::test_gimme_5', - 'tests/further_tests/test_more_multiply.py::test_times_100', - 'tests/further_tests/test_more_multiply.py::test_times_negative_1', - 'tests/further_tests/test_multiply.py::test_times_10', - 'tests/further_tests/test_multiply.py::test_times_2', - ], - functionCount: 7, - stdout: [ - '============================= test session starts =============================', - 'platform win32 -- Python 3.7.0, pytest-3.6.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: e:\\user\\test\\pytest_scenario, inifile:', - 'collected 7 items', - "", - " ", - " ", - "", - " ", - "", - " ", - " ", - "", - " ", - " ", - '', - '======================== no tests ran in 0.17 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 3.7 < 4.1', - platform: PytestDataPlatformType.Windows, - description: 'Non-package source, 2 test modules in subfolders of root, and 2 more in one (direct) subfolder.', - rootdir: 'e:\\user\\test\\pytest_scenario', - test_functions: [ - 'tests/test_base_stuff.py::test_do_test', - 'tests/test_base_stuff.py::test_do_other_test', - 'tests/test_gimme_5.py::test_gimme_5', - 'tests/further_tests/test_more_multiply.py::test_times_100', - 'tests/further_tests/test_more_multiply.py::test_times_negative_1', - 'tests/further_tests/test_multiply.py::test_times_10', - 'tests/further_tests/test_multiply.py::test_times_2', - ], - functionCount: 7, - stdout: [ - '============================= test session starts =============================', - 'platform win32 -- Python 3.7.0, pytest-3.7.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: e:\\user\\test\\pytest_scenario, inifile:', - 'collected 7 items', - "", - " ", - " ", - "", - " ", - "", - " ", - " ", - "", - " ", - " ", - '', - '======================== no tests ran in 0.20 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 4.1', - platform: PytestDataPlatformType.Windows, - description: 'Non-package source, 2 test modules in subfolders of root, and 2 more in one (direct) subfolder.', - rootdir: 'e:\\user\\test\\pytest_scenario', - test_functions: [ - 'tests/test_base_stuff.py::test_do_test', - 'tests/test_base_stuff.py::test_do_other_test', - 'tests/test_gimme_5.py::test_gimme_5', - 'tests/further_tests/test_more_multiply.py::test_times_100', - 'tests/further_tests/test_more_multiply.py::test_times_negative_1', - 'tests/further_tests/test_multiply.py::test_times_10', - 'tests/further_tests/test_multiply.py::test_times_2', - ], - functionCount: 7, - stdout: [ - '============================= test session starts =============================', - 'platform win32 -- Python 3.7.0, pytest-4.1.0, py-1.6.0, pluggy-0.7.1', - 'rootdir: e:\\user\\test\\pytest_scenario, inifile:', - 'collected 7 items', - '', - ' ', - ' ', - '', - ' ', - '', - ' ', - ' ', - '', - ' ', - ' ', - '', - '======================== no tests ran in 0.20 seconds =========================', - ], - }, - { - pytest_version_spec: '< 3.7', - platform: PytestDataPlatformType.Windows, - description: 'Package-based source, 2+ test modules in root folder and two more in one (direct) subfolder.', - rootdir: 'e:\\user\\test\\pytest_scenario', - test_functions: [ - 'test_base_stuff.py::test_do_test', - 'test_base_stuff.py::test_do_other_test', - 'tests/test_multiply.py::test_times_10', - 'tests/test_multiply.py::test_times_2', - 'tests/test_more_multiply.py::test_times_100', - 'tests/test_more_multiply.py::test_times_negative_1', - ], - functionCount: 7, - stdout: [ - '============================= test session starts =============================', - 'platform win32 -- Python 3.7.0, pytest-3.6.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: e:\\user\\test\\pytest_scenario, inifile:', - 'collected 7 items', - "", - " ", - " ", - "", - " ", - "", - " ", - " ", - "", - " ", - " ", - '', - '======================== no tests ran in 0.26 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 3.7 < 4.1', - platform: PytestDataPlatformType.Windows, - description: 'Package-based source, 2+ test modules in root folder and two more in one (direct) subfolder.', - rootdir: 'e:\\user\\test\\pytest_scenario', - test_functions: [ - 'test_base_stuff.py::test_do_test', - 'test_base_stuff.py::test_do_other_test', - 'tests/test_multiply.py::test_times_10', - 'tests/test_multiply.py::test_times_2', - 'tests/test_more_multiply.py::test_times_100', - 'tests/test_more_multiply.py::test_times_negative_1', - ], - functionCount: 7, - stdout: [ - '============================= test session starts =============================', - 'platform win32 -- Python 3.7.0, pytest-3.7.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: e:\\user\\test\\pytest_scenario, inifile:', - 'collected 7 items', - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - '', - '======================== no tests ran in 0.66 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 4.1', - platform: PytestDataPlatformType.Windows, - description: 'Package-based source, 2+ test modules in root folder and two more in one (direct) subfolder.', - rootdir: 'e:\\user\\test\\pytest_scenario', - test_functions: [ - 'test_base_stuff.py::test_do_test', - 'test_base_stuff.py::test_do_other_test', - 'tests/test_multiply.py::test_times_10', - 'tests/test_multiply.py::test_times_2', - 'tests/test_more_multiply.py::test_times_100', - 'tests/test_more_multiply.py::test_times_negative_1', - ], - functionCount: 7, - stdout: [ - '============================= test session starts =============================', - 'platform win32 -- Python 3.7.0, pytest-4.1.0, py-1.6.0, pluggy-0.7.1', - 'rootdir: e:\\user\\test\\pytest_scenario, inifile:', - 'collected 7 items', - '', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - '', - '======================== no tests ran in 0.66 seconds =========================', - ], - }, - { - pytest_version_spec: '< 3.7', - platform: PytestDataPlatformType.Windows, - description: 'Non-package source, 2+ test modules in root folder and two more in one (direct) subfolder.', - rootdir: 'e:\\user\\test\\pytest_scenario', - test_functions: [ - 'test_base_stuff.py::test_do_test', - 'test_base_stuff.py::test_do_other_test', - 'tests/test_multiply.py::test_times_10', - 'tests/test_multiply.py::test_times_2', - 'tests/test_more_multiply.py::test_times_100', - 'tests/test_more_multiply.py::test_times_negative_1', - ], - functionCount: 7, - stdout: [ - '============================= test session starts =============================', - 'platform win32 -- Python 3.7.0, pytest-3.6.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: e:\\user\\test\\pytest_scenario, inifile:', - 'collected 7 items', - "", - " ", - " ", - "", - " ", - "", - " ", - " ", - "", - " ", - " ", - '', - '======================== no tests ran in 0.11 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 3.7 < 4.1', - platform: PytestDataPlatformType.Windows, - description: 'Non-package source, 2+ test modules in root folder and two more in one (direct) subfolder.', - rootdir: 'e:\\user\\test\\pytest_scenario', - test_functions: [ - 'test_base_stuff.py::test_do_test', - 'test_base_stuff.py::test_do_other_test', - 'tests/test_multiply.py::test_times_10', - 'tests/test_multiply.py::test_times_2', - 'tests/test_more_multiply.py::test_times_100', - 'tests/test_more_multiply.py::test_times_negative_1', - ], - functionCount: 7, - stdout: [ - '============================= test session starts =============================', - 'platform win32 -- Python 3.7.0, pytest-3.7.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: e:\\user\\test\\pytest_scenario, inifile:', - 'collected 7 items', - "", - " ", - " ", - "", - " ", - "", - " ", - " ", - "", - " ", - " ", - '', - '======================== no tests ran in 0.41 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 4.1', - platform: PytestDataPlatformType.Windows, - description: 'Non-package source, 2+ test modules in root folder and two more in one (direct) subfolder.', - rootdir: 'e:\\user\\test\\pytest_scenario', - test_functions: [ - 'test_base_stuff.py::test_do_test', - 'test_base_stuff.py::test_do_other_test', - 'tests/test_multiply.py::test_times_10', - 'tests/test_multiply.py::test_times_2', - 'tests/test_more_multiply.py::test_times_100', - 'tests/test_more_multiply.py::test_times_negative_1', - ], - functionCount: 7, - stdout: [ - '============================= test session starts =============================', - 'platform win32 -- Python 3.7.0, pytest-4.1.0, py-1.6.0, pluggy-0.7.1', - 'rootdir: e:\\user\\test\\pytest_scenario, inifile:', - 'collected 7 items', - '', - ' ', - ' ', - '', - ' ', - '', - ' ', - ' ', - '', - ' ', - ' ', - '', - '======================== no tests ran in 0.41 seconds =========================', - ], - }, - { - pytest_version_spec: '< 3.7', - platform: PytestDataPlatformType.Windows, - description: 'Package-based source, 2+ test modules in a subfolder off the root.', - rootdir: 'e:\\user\\test\\pytest_scenario', - test_functions: [ - 'tests/test_base_stuff.py::test_do_test', - 'tests/test_base_stuff.py::test_do_other_test', - 'tests/test_gimme_5.py::test_gimme_5', - 'tests/test_more_multiply.py::test_times_100', - 'tests/test_more_multiply.py::test_times_negative_1', - 'tests/test_multiply.py::test_times_10', - 'tests/test_multiply.py::test_times_2', - ], - functionCount: 7, - stdout: [ - '============================= test session starts =============================', - 'platform win32 -- Python 3.7.0, pytest-3.6.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: e:\\user\\test\\pytest_scenario, inifile:', - 'collected 7 items', - "", - " ", - " ", - "", - " ", - "", - " ", - " ", - "", - " ", - " ", - '', - '======================== no tests ran in 0.20 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 3.7 < 4.1', - platform: PytestDataPlatformType.Windows, - description: 'Package-based source, 2+ test modules in a subfolder off the root.', - rootdir: 'e:\\user\\test\\pytest_scenario', - test_functions: [ - 'tests/test_base_stuff.py::test_do_test', - 'tests/test_base_stuff.py::test_do_other_test', - 'tests/test_gimme_5.py::test_gimme_5', - 'tests/test_more_multiply.py::test_times_100', - 'tests/test_more_multiply.py::test_times_negative_1', - 'tests/test_multiply.py::test_times_10', - 'tests/test_multiply.py::test_times_2', - ], - functionCount: 7, - stdout: [ - '============================= test session starts =============================', - 'platform win32 -- Python 3.7.0, pytest-3.7.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: e:\\user\\test\\pytest_scenario, inifile:', - 'collected 7 items', - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - '', - '======================== no tests ran in 0.26 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 4.1', - platform: PytestDataPlatformType.Windows, - description: 'Package-based source, 2+ test modules in a subfolder off the root.', - rootdir: 'e:\\user\\test\\pytest_scenario', - test_functions: [ - 'tests/test_base_stuff.py::test_do_test', - 'tests/test_base_stuff.py::test_do_other_test', - 'tests/test_gimme_5.py::test_gimme_5', - 'tests/test_more_multiply.py::test_times_100', - 'tests/test_more_multiply.py::test_times_negative_1', - 'tests/test_multiply.py::test_times_10', - 'tests/test_multiply.py::test_times_2', - ], - functionCount: 7, - stdout: [ - '============================= test session starts =============================', - 'platform win32 -- Python 3.7.0, pytest-4.1.0, py-1.6.0, pluggy-0.7.1', - 'rootdir: e:\\user\\test\\pytest_scenario, inifile:', - 'collected 7 items', - '', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - '', - '======================== no tests ran in 0.26 seconds =========================', - ], - }, - { - pytest_version_spec: '< 3.7', - platform: PytestDataPlatformType.Windows, - description: 'Non-package source, 2+ test modules in a subfolder off the root.', - rootdir: 'e:\\user\\test\\pytest_scenario', - test_functions: [ - 'tests/test_base_stuff.py::test_do_test', - 'tests/test_base_stuff.py::test_do_other_test', - 'tests/test_gimme_5.py::test_gimme_5', - 'tests/test_more_multiply.py::test_times_100', - 'tests/test_more_multiply.py::test_times_negative_1', - 'tests/test_multiply.py::test_times_10', - 'tests/test_multiply.py::test_times_2', - ], - functionCount: 7, - stdout: [ - '============================= test session starts =============================', - 'platform win32 -- Python 3.7.0, pytest-3.6.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: e:\\user\\test\\pytest_scenario, inifile:', - 'collected 7 items', - "", - " ", - " ", - "", - " ", - "", - " ", - " ", - "", - " ", - " ", - '', - '======================== no tests ran in 0.26 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 3.7 < 4.1', - platform: PytestDataPlatformType.Windows, - description: 'Non-package source, 2+ test modules in a subfolder off the root.', - rootdir: 'e:\\user\\test\\pytest_scenario', - test_functions: [ - 'tests/test_base_stuff.py::test_do_test', - 'tests/test_base_stuff.py::test_do_other_test', - 'tests/test_gimme_5.py::test_gimme_5', - 'tests/test_more_multiply.py::test_times_100', - 'tests/test_more_multiply.py::test_times_negative_1', - 'tests/test_multiply.py::test_times_10', - 'tests/test_multiply.py::test_times_2', - ], - functionCount: 7, - stdout: [ - '============================= test session starts =============================', - 'platform win32 -- Python 3.7.0, pytest-3.7.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: e:\\user\\test\\pytest_scenario, inifile:', - 'collected 7 items', - "", - " ", - " ", - "", - " ", - "", - " ", - " ", - "", - " ", - " ", - '', - '======================== no tests ran in 0.26 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 4.1', - platform: PytestDataPlatformType.Windows, - description: 'Non-package source, 2+ test modules in a subfolder off the root.', - rootdir: 'e:\\user\\test\\pytest_scenario', - test_functions: [ - 'tests/test_base_stuff.py::test_do_test', - 'tests/test_base_stuff.py::test_do_other_test', - 'tests/test_gimme_5.py::test_gimme_5', - 'tests/test_more_multiply.py::test_times_100', - 'tests/test_more_multiply.py::test_times_negative_1', - 'tests/test_multiply.py::test_times_10', - 'tests/test_multiply.py::test_times_2', - ], - functionCount: 7, - stdout: [ - '============================= test session starts =============================', - 'platform win32 -- Python 3.7.0, pytest-4.1.0, py-1.6.0, pluggy-0.7.1', - 'rootdir: e:\\user\\test\\pytest_scenario, inifile:', - 'collected 7 items', - '', - ' ', - ' ', - '', - ' ', - '', - ' ', - ' ', - '', - ' ', - ' ', - '', - '======================== no tests ran in 0.26 seconds =========================', - ], - }, - { - pytest_version_spec: '< 3.7', - platform: PytestDataPlatformType.Windows, - description: 'Package-based source, 2+ modules at the topmost level.', - rootdir: 'e:\\user\\test\\pytest_scenario', - test_functions: [ - 'test_base_stuff.py::test_do_test', - 'test_base_stuff.py::test_do_other_test', - 'test_multiply.py::test_times_10', - 'test_multiply.py::test_times_2', - ], - functionCount: 4, - stdout: [ - '============================= test session starts =============================', - 'platform win32 -- Python 3.7.0, pytest-3.6.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: e:\\user\\test\\pytest_scenario, inifile:', - 'collected 4 items', - "", - " ", - " ", - "", - " ", - " ", - '', - '======================== no tests ran in 0.17 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 3.7 < 4.1', - platform: PytestDataPlatformType.Windows, - description: 'Package-based source, 2+ modules at the topmost level.', - rootdir: 'e:\\user\\test\\pytest_scenario', - test_functions: [ - 'test_base_stuff.py::test_do_test', - 'test_base_stuff.py::test_do_other_test', - 'test_multiply.py::test_times_10', - 'test_multiply.py::test_times_2', - ], - functionCount: 4, - stdout: [ - '============================= test session starts =============================', - 'platform win32 -- Python 3.7.0, pytest-3.7.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: e:\\user\\test\\pytest_scenario, inifile:', - 'collected 4 items', - "", - " ", - " ", - " ", - " ", - " ", - " ", - '', - '======================== no tests ran in 0.37 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 4.1', - platform: PytestDataPlatformType.Windows, - description: 'Package-based source, 2+ modules at the topmost level.', - rootdir: 'e:\\user\\test\\pytest_scenario', - test_functions: [ - 'test_base_stuff.py::test_do_test', - 'test_base_stuff.py::test_do_other_test', - 'test_multiply.py::test_times_10', - 'test_multiply.py::test_times_2', - ], - functionCount: 4, - stdout: [ - '============================= test session starts =============================', - 'platform win32 -- Python 3.7.0, pytest-4.1.0, py-1.6.0, pluggy-0.7.1', - 'rootdir: e:\\user\\test\\pytest_scenario, inifile:', - 'collected 4 items', - '', - ' ', - ' ', - ' ', - ' ', - ' ', - ' ', - '', - '======================== no tests ran in 0.37 seconds =========================', - ], - }, - { - pytest_version_spec: '< 3.7', - platform: PytestDataPlatformType.Windows, - description: 'Non-package source, 2 modules at the topmost level.', - rootdir: 'e:\\user\\test\\pytest_scenario', - test_functions: [ - 'test_base_stuff.py::test_do_test', - 'test_base_stuff.py::test_do_other_test', - 'test_multiply.py::test_times_10', - 'test_multiply.py::test_times_2', - ], - functionCount: 4, - stdout: [ - '============================= test session starts =============================', - 'platform win32 -- Python 3.7.0, pytest-3.6.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: e:\\user\\test\\pytest_scenario, inifile:', - 'collected 4 items', - "", - " ", - " ", - "", - " ", - " ", - '', - '======================== no tests ran in 0.18 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 3.7 < 4.1', - platform: PytestDataPlatformType.Windows, - description: 'Non-package source, 2 modules at the topmost level.', - rootdir: 'e:\\user\\test\\pytest_scenario', - test_functions: [ - 'test_base_stuff.py::test_do_test', - 'test_base_stuff.py::test_do_other_test', - 'test_multiply.py::test_times_10', - 'test_multiply.py::test_times_2', - ], - functionCount: 4, - stdout: [ - '============================= test session starts =============================', - 'platform win32 -- Python 3.7.0, pytest-3.7.4, py-1.6.0, pluggy-0.7.1', - 'rootdir: e:\\user\\test\\pytest_scenario, inifile:', - 'collected 4 items', - "", - " ", - " ", - "", - " ", - " ", - '', - '======================== no tests ran in 0.36 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 4.1', - platform: PytestDataPlatformType.Windows, - description: 'Non-package source, 2 modules at the topmost level.', - rootdir: 'e:\\user\\test\\pytest_scenario', - test_functions: [ - 'test_base_stuff.py::test_do_test', - 'test_base_stuff.py::test_do_other_test', - 'test_multiply.py::test_times_10', - 'test_multiply.py::test_times_2', - ], - functionCount: 4, - stdout: [ - '============================= test session starts =============================', - 'platform win32 -- Python 3.7.0, pytest-4.1.0, py-1.6.0, pluggy-0.7.1', - 'rootdir: e:\\user\\test\\pytest_scenario, inifile:', - 'collected 4 items', - '', - ' ', - ' ', - '', - ' ', - ' ', - '', - '======================== no tests ran in 0.36 seconds =========================', - ], - }, - { - pytest_version_spec: '>= 4.1', - platform: PytestDataPlatformType.NonWindows, - description: 'Parameterized tests', - rootdir: '/home/user/test/pytest_scenario', - test_functions: ['tests/test_spam.py::test_with_subtests[1-2]', 'tests/test_spam.py::test_with_subtests[3-4]'], - functionCount: 2, - stdout: [ - '============================= test session starts ==============================', - 'platform linux -- Python 3.7.1, pytest-4.2.1, py-1.7.0, pluggy-0.8.1', - 'rootdir: /home/user/test/pytest_scenario, inifile:', - 'collected 2 items', - '', - ' ', - ' ', - ' ', - '', - '========================= no tests ran in 0.02 seconds =========================', - ], - }, -]; diff --git a/src/test/testing/pytest/services/discoveryService.unit.test.ts b/src/test/testing/pytest/services/discoveryService.unit.test.ts deleted file mode 100644 index a445295c052f..000000000000 --- a/src/test/testing/pytest/services/discoveryService.unit.test.ts +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { expect } from 'chai'; -import { deepEqual, instance, mock, verify, when } from 'ts-mockito'; -import { CancellationTokenSource, Uri } from 'vscode'; -import { ServiceContainer } from '../../../../client/ioc/container'; -import { IServiceContainer } from '../../../../client/ioc/types'; -import { PYTEST_PROVIDER } from '../../../../client/testing/common/constants'; -import { TestsDiscoveryService } from '../../../../client/testing/common/services/discovery'; -import { TestsHelper } from '../../../../client/testing/common/testUtils'; -import { - IArgumentsService, - ITestDiscoveryService, - ITestsHelper, - TestDiscoveryOptions, - TestFilter, - Tests, -} from '../../../../client/testing/common/types'; -import { ArgumentsService } from '../../../../client/testing/pytest/services/argsService'; -import { TestDiscoveryService } from '../../../../client/testing/pytest/services/discoveryService'; -import { MockOutputChannel } from '../../../mockClasses'; - -function fakeTests(fake: string): Tests { - return (fake as unknown) as Tests; -} - -suite('Unit Tests - PyTest - Discovery', () => { - class DiscoveryService extends TestDiscoveryService { - public buildTestCollectionArgs(options: TestDiscoveryOptions): string[] { - return super.buildTestCollectionArgs(options); - } - - public discoverTestsInTestDirectory(options: TestDiscoveryOptions): Promise { - return super.discoverTestsInTestDirectory(options); - } - } - let discoveryService: DiscoveryService; - let serviceContainer: IServiceContainer; - let argsService: IArgumentsService; - let helper: ITestsHelper; - setup(() => { - serviceContainer = mock(ServiceContainer); - helper = mock(TestsHelper); - argsService = mock(ArgumentsService); - - when(serviceContainer.get(IArgumentsService, PYTEST_PROVIDER)).thenReturn( - instance(argsService), - ); - when(serviceContainer.get(ITestsHelper)).thenReturn(instance(helper)); - discoveryService = new DiscoveryService(instance(serviceContainer)); - }); - test('Ensure discovery is invoked when there are no test directories', async () => { - const options: TestDiscoveryOptions = { - args: ['some args'], - cwd: Uri.file(__dirname).fsPath, - ignoreCache: true, - outChannel: new MockOutputChannel('Tests'), - token: new CancellationTokenSource().token, - workspaceFolder: Uri.file(__dirname), - }; - const args = ['1', '2', '3']; - const discoveredTests = fakeTests('Hello World'); - discoveryService.buildTestCollectionArgs = () => args; - discoveryService.discoverTestsInTestDirectory = () => Promise.resolve(discoveredTests); - when(argsService.getTestFolders(deepEqual(options.args))).thenReturn([]); - - const tests = await discoveryService.discoverTests(options); - - expect(tests).equal(discoveredTests); - }); - test('Ensure discovery is invoked when there are multiple test directories', async () => { - const options: TestDiscoveryOptions = { - args: ['some args'], - cwd: Uri.file(__dirname).fsPath, - ignoreCache: true, - outChannel: new MockOutputChannel('Tests'), - token: new CancellationTokenSource().token, - workspaceFolder: Uri.file(__dirname), - }; - const args = ['1', '2', '3']; - discoveryService.buildTestCollectionArgs = () => args; - const directories = ['a', 'b']; - discoveryService.discoverTestsInTestDirectory = async (opts) => { - const dir = opts.args[opts.args.length - 1]; - if (dir === 'a') { - return fakeTests('Result A'); - } - if (dir === 'b') { - return fakeTests('Result B'); - } - throw new Error('Unrecognized directory'); - }; - when(argsService.getTestFolders(deepEqual(options.args))).thenReturn(directories); - when(helper.mergeTests(deepEqual([fakeTests('Result A'), fakeTests('Result B')]))).thenReturn( - fakeTests('mergedTests'), - ); - - const tests = await discoveryService.discoverTests(options); - - verify(helper.mergeTests(deepEqual([fakeTests('Result A'), fakeTests('Result B')]))).once(); - expect(tests).equal('mergedTests'); - }); - test('Build collection arguments', async () => { - const options: TestDiscoveryOptions = { - args: ['some args', 'and some more'], - cwd: Uri.file(__dirname).fsPath, - ignoreCache: false, - outChannel: new MockOutputChannel('Tests'), - token: new CancellationTokenSource().token, - workspaceFolder: Uri.file(__dirname), - }; - - const filteredArgs = options.args; - const expectedArgs = ['--rootdir', Uri.file(__dirname).fsPath, '-s', ...filteredArgs]; - when(argsService.filterArguments(deepEqual(options.args), TestFilter.discovery)).thenReturn(filteredArgs); - - const args = discoveryService.buildTestCollectionArgs(options); - - expect(args).deep.equal(expectedArgs); - verify(argsService.filterArguments(deepEqual(options.args), TestFilter.discovery)).once(); - }); - test('Build collection arguments with ignore in args', async () => { - const options: TestDiscoveryOptions = { - args: ['some args', 'and some more', '--cache-clear'], - cwd: Uri.file(__dirname).fsPath, - ignoreCache: true, - outChannel: new MockOutputChannel('Tests'), - token: new CancellationTokenSource().token, - workspaceFolder: Uri.file(__dirname), - }; - - const filteredArgs = options.args; - const expectedArgs = ['--rootdir', Uri.file(__dirname).fsPath, '-s', ...filteredArgs]; - when(argsService.filterArguments(deepEqual(options.args), TestFilter.discovery)).thenReturn(filteredArgs); - - const args = discoveryService.buildTestCollectionArgs(options); - - expect(args).deep.equal(expectedArgs); - verify(argsService.filterArguments(deepEqual(options.args), TestFilter.discovery)).once(); - }); - test('Build collection arguments (& ignore)', async () => { - const options: TestDiscoveryOptions = { - args: ['some args', 'and some more'], - cwd: Uri.file(__dirname).fsPath, - ignoreCache: true, - outChannel: new MockOutputChannel('Tests'), - token: new CancellationTokenSource().token, - workspaceFolder: Uri.file(__dirname), - }; - - const filteredArgs = options.args; - const expectedArgs = ['--rootdir', Uri.file(__dirname).fsPath, '-s', '--cache-clear', ...filteredArgs]; - when(argsService.filterArguments(deepEqual(options.args), TestFilter.discovery)).thenReturn(filteredArgs); - - const args = discoveryService.buildTestCollectionArgs(options); - - expect(args).deep.equal(expectedArgs); - verify(argsService.filterArguments(deepEqual(options.args), TestFilter.discovery)).once(); - }); - test('Discover using common discovery', async () => { - const options: TestDiscoveryOptions = { - args: ['some args', 'and some more'], - cwd: Uri.file(__dirname).fsPath, - ignoreCache: true, - outChannel: new MockOutputChannel('Tests'), - token: new CancellationTokenSource().token, - workspaceFolder: Uri.file(__dirname), - }; - const expectedDiscoveryArgs = ['discover', 'pytest', '--', ...options.args]; - const discoveryOptions = { ...options }; - discoveryOptions.args = expectedDiscoveryArgs; - - const commonDiscoveryService = mock(TestsDiscoveryService); - const discoveredTests = fakeTests('Hello'); - when(serviceContainer.get(ITestDiscoveryService, 'common')).thenReturn( - instance(commonDiscoveryService), - ); - when(commonDiscoveryService.discoverTests(deepEqual(discoveryOptions))).thenResolve(discoveredTests); - - const tests = await discoveryService.discoverTestsInTestDirectory(options); - - verify(commonDiscoveryService.discoverTests(deepEqual(discoveryOptions))).once(); - expect(tests).equal(discoveredTests); - }); -}); diff --git a/src/test/testing/rediscover.test.ts b/src/test/testing/rediscover.test.ts deleted file mode 100644 index 3ac1ec17c148..000000000000 --- a/src/test/testing/rediscover.test.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { assert } from 'chai'; -import * as fs from 'fs-extra'; -import * as path from 'path'; -import { instance, mock } from 'ts-mockito'; -import { ConfigurationTarget } from 'vscode'; -import { CommandSource } from '../../client/common/constants'; -import { ICondaService, IInterpreterService } from '../../client/interpreter/contracts'; -import { InterpreterService } from '../../client/interpreter/interpreterService'; -import { CondaService } from '../../client/pythonEnvironments/discovery/locators/services/condaService'; -import { ITestManagerFactory } from '../../client/testing/common/types'; -import { TestProvider } from '../../client/testing/types'; -import { deleteDirectory, deleteFile, rootWorkspaceUri, updateSetting } from '../common'; -import { initialize, initializeTest, IS_MULTI_ROOT_TEST, TEST_TIMEOUT } from './../initialize'; -import { UnitTestIocContainer } from './serviceRegistry'; - -const testFilesPath = path.join(__dirname, '..', '..', '..', 'src', 'test', 'pythonFiles', 'testFiles', 'debuggerTest'); -const testFile = path.join(testFilesPath, 'tests', 'test_debugger_two.py'); -const testFileWithFewTests = path.join(testFilesPath, 'tests', 'test_debugger_two.txt'); -const testFileWithMoreTests = path.join(testFilesPath, 'tests', 'test_debugger_two.updated.txt'); -const defaultUnitTestArgs = ['-v', '-s', '.', '-p', '*test*.py']; - -suite('Unit Tests re-discovery', () => { - let ioc: UnitTestIocContainer; - const configTarget = IS_MULTI_ROOT_TEST ? ConfigurationTarget.WorkspaceFolder : ConfigurationTarget.Workspace; - suiteSetup(async () => { - await initialize(); - }); - setup(async function () { - this.timeout(TEST_TIMEOUT * 2); // This hook requires more timeout as we're dealing with files as well - await fs.copy(testFileWithFewTests, testFile, { overwrite: true }); - await deleteDirectory(path.join(testFilesPath, '.cache')); - await resetSettings(); - await initializeTest(); - await initializeDI(); - }); - teardown(async function () { - // This is doing a lot more than what a teardown does normally, so increasing the timeout. - - this.timeout(TEST_TIMEOUT * 2); - await ioc.dispose(); - await resetSettings(); - await fs.copy(testFileWithFewTests, testFile, { overwrite: true }); - await deleteFile(path.join(path.dirname(testFile), `${path.basename(testFile, '.py')}.pyc`)); - }); - - async function resetSettings() { - await updateSetting('testing.unittestArgs', defaultUnitTestArgs, rootWorkspaceUri, configTarget); - await updateSetting('testing.pytestArgs', [], rootWorkspaceUri, configTarget); - } - - async function initializeDI() { - ioc = new UnitTestIocContainer(); - ioc.registerCommonTypes(); - ioc.registerProcessTypes(); - ioc.registerVariableTypes(); - ioc.registerUnitTestTypes(); - ioc.registerInterpreterStorageTypes(); - await ioc.registerMockInterpreterTypes(); - ioc.serviceManager.rebindInstance(ICondaService, instance(mock(CondaService))); - ioc.serviceManager.rebindInstance(IInterpreterService, instance(mock(InterpreterService))); - } - - async function discoverUnitTests(testProvider: TestProvider) { - const testManager = ioc.serviceContainer.get(ITestManagerFactory)( - testProvider, - rootWorkspaceUri!, - testFilesPath, - ); - let tests = await testManager.discoverTests(CommandSource.ui, true, true); - assert.equal(tests.testFiles.length, 2, 'Incorrect number of test files'); - assert.equal(tests.testSuites.length, 2, 'Incorrect number of test suites'); - assert.equal(tests.testFunctions.length, 2, 'Incorrect number of test functions'); - await deleteFile(path.join(path.dirname(testFile), `${path.basename(testFile, '.py')}.pyc`)); - await fs.copy(testFileWithMoreTests, testFile, { overwrite: true }); - tests = await testManager.discoverTests(CommandSource.ui, true, true); - assert.equal(tests.testFunctions.length, 4, 'Incorrect number of updated test functions'); - } - - test('Re-discover tests (unittest)', async () => { - await updateSetting('testing.unittestArgs', ['-s=./tests', '-p=test_*.py'], rootWorkspaceUri, configTarget); - await discoverUnitTests('unittest'); - }); - - test('Re-discover tests (pytest)', async () => { - await updateSetting('testing.pytestArgs', ['-k=test_'], rootWorkspaceUri, configTarget); - await discoverUnitTests('pytest'); - }); -}); diff --git a/src/test/testing/serviceRegistry.ts b/src/test/testing/serviceRegistry.ts index 11147bb27064..89c2bf8271ef 100644 --- a/src/test/testing/serviceRegistry.ts +++ b/src/test/testing/serviceRegistry.ts @@ -8,40 +8,11 @@ import { Uri } from 'vscode'; import { IProcessServiceFactory } from '../../client/common/process/types'; import { IInterpreterHelper } from '../../client/interpreter/contracts'; import { InterpreterHelper } from '../../client/interpreter/helpers'; -import { IServiceContainer } from '../../client/ioc/types'; -import { PYTEST_PROVIDER, UNITTEST_PROVIDER } from '../../client/testing/common/constants'; -import { TestDiscoveredTestParser } from '../../client/testing/common/services/discoveredTestParser'; -import { TestsDiscoveryService } from '../../client/testing/common/services/discovery'; -import { TestCollectionStorageService } from '../../client/testing/common/services/storageService'; -import { TestManagerService } from '../../client/testing/common/services/testManagerService'; -import { TestResultsService } from '../../client/testing/common/services/testResultsService'; -import { TestsStatusUpdaterService } from '../../client/testing/common/services/testsStatusService'; -import { ITestDiscoveredTestParser } from '../../client/testing/common/services/types'; -import { UnitTestDiagnosticService } from '../../client/testing/common/services/unitTestDiagnosticService'; import { TestsHelper } from '../../client/testing/common/testUtils'; -import { TestFlatteningVisitor } from '../../client/testing/common/testVisitors/flatteningVisitor'; -import { TestResultResetVisitor } from '../../client/testing/common/testVisitors/resultResetVisitor'; import { - ITestCollectionStorageService, - ITestDiagnosticService, - ITestDiscoveryService, - ITestManager, - ITestManagerFactory, - ITestManagerService, - ITestManagerServiceFactory, - ITestResultsService, ITestsHelper, - ITestsParser, - ITestsStatusUpdaterService, - ITestVisitor, IUnitTestSocketServer, } from '../../client/testing/common/types'; -import { TestManager as PyTestTestManager } from '../../client/testing/pytest/main'; -import { TestDiscoveryService as PytestTestDiscoveryService } from '../../client/testing/pytest/services/discoveryService'; -import { TestProvider } from '../../client/testing/types'; -import { TestManager as UnitTestTestManager } from '../../client/testing/unittest/main'; -import { TestDiscoveryService as UnitTestTestDiscoveryService } from '../../client/testing/unittest/services/discoveryService'; -import { TestsParser as UnitTestTestsParser } from '../../client/testing/unittest/services/parserService'; import { getPythonSemVer } from '../common'; import { IocContainer } from '../serviceRegistry'; import { MockUnitTestSocketServer } from './mocks'; @@ -57,89 +28,14 @@ export class UnitTestIocContainer extends IocContainer { return -1; // log warning already issued by underlying functions... } - public registerTestVisitors(): void { - this.serviceManager.add(ITestVisitor, TestFlatteningVisitor, 'TestFlatteningVisitor'); - this.serviceManager.add(ITestVisitor, TestResultResetVisitor, 'TestResultResetVisitor'); - this.serviceManager.addSingleton( - ITestsStatusUpdaterService, - TestsStatusUpdaterService, - ); - } - - public registerTestStorage(): void { - this.serviceManager.addSingleton( - ITestCollectionStorageService, - TestCollectionStorageService, - ); - } - public registerTestsHelper(): void { this.serviceManager.addSingleton(ITestsHelper, TestsHelper); } - public registerTestResultsHelper(): void { - this.serviceManager.add(ITestResultsService, TestResultsService); - } - - public registerTestParsers(): void { - this.serviceManager.add(ITestsParser, UnitTestTestsParser, UNITTEST_PROVIDER); - } - - public registerTestDiscoveryServices(): void { - this.serviceManager.add( - ITestDiscoveryService, - UnitTestTestDiscoveryService, - UNITTEST_PROVIDER, - ); - this.serviceManager.add( - ITestDiscoveryService, - PytestTestDiscoveryService, - PYTEST_PROVIDER, - ); - this.serviceManager.add(ITestDiscoveryService, TestsDiscoveryService, 'common'); - this.serviceManager.add(ITestDiscoveredTestParser, TestDiscoveredTestParser); - } - - public registerTestDiagnosticServices(): void { - this.serviceManager.addSingleton(ITestDiagnosticService, UnitTestDiagnosticService); - } - - public registerTestManagers(): void { - this.serviceManager.addFactory( - ITestManagerFactory, - (context) => (testProvider: TestProvider, workspaceFolder: Uri, rootDirectory: string) => { - const serviceContainer = context.container.get(IServiceContainer); - - switch (testProvider) { - case PYTEST_PROVIDER: { - return new PyTestTestManager(workspaceFolder, rootDirectory, serviceContainer); - } - case UNITTEST_PROVIDER: { - return new UnitTestTestManager(workspaceFolder, rootDirectory, serviceContainer); - } - default: { - throw new Error(`Unrecognized test provider '${testProvider}'`); - } - } - }, - ); - } - public registerInterpreterStorageTypes(): void { this.serviceManager.add(IInterpreterHelper, InterpreterHelper); } - public registerTestManagerService(): void { - this.serviceManager.addFactory( - ITestManagerServiceFactory, - (context) => (workspaceFolder: Uri) => { - const serviceContainer = context.container.get(IServiceContainer); - const testsHelper = context.container.get(ITestsHelper); - return new TestManagerService(workspaceFolder, testsHelper, serviceContainer); - }, - ); - } - public registerMockUnitTestSocketServer(): void { this.serviceManager.addSingleton(IUnitTestSocketServer, MockUnitTestSocketServer); } diff --git a/src/test/testing/stoppingDiscoverAndTest.test.ts b/src/test/testing/stoppingDiscoverAndTest.test.ts deleted file mode 100644 index 8de3ff5b75e8..000000000000 --- a/src/test/testing/stoppingDiscoverAndTest.test.ts +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -import { expect, use } from 'chai'; -import * as chaiAsPromised from 'chai-as-promised'; -import * as path from 'path'; -import { Uri } from 'vscode'; -import { CommandSource } from '../../client/common/constants'; -import { Product } from '../../client/common/types'; -import { createDeferred } from '../../client/common/utils/async'; -import { CANCELLATION_REASON, UNITTEST_PROVIDER } from '../../client/testing/common/constants'; -import { ITestDiscoveryService } from '../../client/testing/common/types'; -import { initialize, initializeTest } from '../initialize'; -import { MockDiscoveryService, MockTestManagerWithRunningTests } from './mocks'; -import { UnitTestIocContainer } from './serviceRegistry'; - -use(chaiAsPromised); - -const testFilesPath = path.join(__dirname, '..', '..', '..', 'src', 'test', 'pythonFiles', 'testFiles', 'debuggerTest'); - -const EmptyTests = { - summary: { - passed: 0, - failures: 0, - errors: 0, - skipped: 0, - }, - testFiles: [], - testFunctions: [], - testSuites: [], - testFolders: [], - rootTestFolders: [], -}; - -suite('Unit Tests Stopping Discovery and Runner', () => { - let ioc: UnitTestIocContainer; - suiteSetup(initialize); - setup(async () => { - await initializeTest(); - await initializeDI(); - }); - teardown(() => ioc.dispose()); - - async function initializeDI() { - ioc = new UnitTestIocContainer(); - ioc.registerCommonTypes(); - ioc.registerProcessTypes(); - ioc.registerVariableTypes(); - - ioc.registerTestParsers(); - ioc.registerTestVisitors(); - ioc.registerTestResultsHelper(); - ioc.registerTestStorage(); - ioc.registerTestsHelper(); - ioc.registerTestDiagnosticServices(); - ioc.registerInterpreterStorageTypes(); - await ioc.registerMockInterpreterTypes(); - } - - test('Running tests should not stop existing discovery', async () => { - const mockTestManager = new MockTestManagerWithRunningTests( - UNITTEST_PROVIDER, - Product.unittest, - Uri.file(testFilesPath), - testFilesPath, - ioc.serviceContainer, - ); - ioc.serviceManager.addSingletonInstance( - ITestDiscoveryService, - new MockDiscoveryService(mockTestManager.discoveryDeferred.promise), - UNITTEST_PROVIDER, - ); - - const discoveryPromise = mockTestManager.discoverTests(CommandSource.auto); - mockTestManager.discoveryDeferred.resolve(EmptyTests); - const runningPromise = mockTestManager.runTest(CommandSource.ui); - const deferred = createDeferred(); - - // This promise should never resolve nor reject. - runningPromise - .then(() => Promise.reject("Debugger stopped when it shouldn't have")) - .catch((error) => deferred.reject(error)); - - discoveryPromise - .then((result) => { - if (result === EmptyTests) { - deferred.resolve(''); - } else { - deferred.reject('tests not empty'); - } - }) - .catch((error) => deferred.reject(error)); - - await deferred.promise; - }); - - test('Discovering tests should stop running tests', async () => { - const mockTestManager = new MockTestManagerWithRunningTests( - UNITTEST_PROVIDER, - Product.unittest, - Uri.file(testFilesPath), - testFilesPath, - ioc.serviceContainer, - ); - ioc.serviceManager.addSingletonInstance( - ITestDiscoveryService, - new MockDiscoveryService(mockTestManager.discoveryDeferred.promise), - UNITTEST_PROVIDER, - ); - mockTestManager.discoveryDeferred.resolve(EmptyTests); - await mockTestManager.discoverTests(CommandSource.auto); - const runPromise = mockTestManager.runTest(CommandSource.ui); - - await new Promise((resolve) => setTimeout(resolve, 1000)); - - // User manually discovering tests will kill the existing test runner. - await mockTestManager.discoverTests(CommandSource.ui, true, false, true); - await expect(runPromise).to.eventually.be.rejectedWith(CANCELLATION_REASON); - }); -}); diff --git a/src/test/testing/unittest/unittest.argsService.unit.test.ts b/src/test/testing/unittest/unittest.argsService.unit.test.ts deleted file mode 100644 index 561c3c5fa264..000000000000 --- a/src/test/testing/unittest/unittest.argsService.unit.test.ts +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { expect } from 'chai'; -import * as path from 'path'; -import * as typeMoq from 'typemoq'; -import { IServiceContainer } from '../../../client/ioc/types'; -import { ArgumentsHelper } from '../../../client/testing/common/argumentsHelper'; -import { IArgumentsHelper } from '../../../client/testing/common/types'; -import { ArgumentsService as UnittestArgumentsService } from '../../../client/testing/unittest/services/argsService'; - -suite('ArgsService: unittest', () => { - let argumentsService: UnittestArgumentsService; - - suiteSetup(() => { - const serviceContainer = typeMoq.Mock.ofType(); - - const argsHelper = new ArgumentsHelper(); - - serviceContainer - .setup((s) => s.get(typeMoq.It.isValue(IArgumentsHelper), typeMoq.It.isAny())) - .returns(() => argsHelper); - - argumentsService = new UnittestArgumentsService(serviceContainer.object); - }); - - test('Test getting the test folder in unittest with -s', () => { - const dir = path.join('a', 'b', 'c'); - const args = ['anzy', '--one', '--three', '-s', dir]; - const testDirs = argumentsService.getTestFolders(args); - expect(testDirs).to.be.lengthOf(1); - expect(testDirs[0]).to.equal(dir); - }); - test('Test getting the test folder in unittest with -s in the middle', () => { - const dir = path.join('a', 'b', 'c'); - const args = ['anzy', '--one', '--three', '-s', dir, 'some other', '--value', '1234']; - const testDirs = argumentsService.getTestFolders(args); - expect(testDirs).to.be.lengthOf(1); - expect(testDirs[0]).to.equal(dir); - }); - test('Test getting the test folder in unittest with --start-directory', () => { - const dir = path.join('a', 'b', 'c'); - const args = ['anzy', '--one', '--three', '--start-directory', dir]; - const testDirs = argumentsService.getTestFolders(args); - expect(testDirs).to.be.lengthOf(1); - expect(testDirs[0]).to.equal(dir); - }); - test('Test getting the test folder in unittest with --start-directory in the middle', () => { - const dir = path.join('a', 'b', 'c'); - const args = ['anzy', '--one', '--three', '--start-directory', dir, 'some other', '--value', '1234']; - const testDirs = argumentsService.getTestFolders(args); - expect(testDirs).to.be.lengthOf(1); - expect(testDirs[0]).to.equal(dir); - }); -}); diff --git a/src/test/testing/unittest/unittest.diagnosticService.unit.test.ts b/src/test/testing/unittest/unittest.diagnosticService.unit.test.ts deleted file mode 100644 index 56990aa2f18f..000000000000 --- a/src/test/testing/unittest/unittest.diagnosticService.unit.test.ts +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import * as assert from 'assert'; -import { DiagnosticSeverity } from 'vscode'; -import * as localize from '../../../client/common/utils/localize'; -import { UnitTestDiagnosticService } from '../../../client/testing/common/services/unitTestDiagnosticService'; -import { PythonTestMessageSeverity, TestStatus } from '../../../client/testing/common/types'; - -suite('UnitTestDiagnosticService: unittest', () => { - let diagnosticService: UnitTestDiagnosticService; - - suiteSetup(() => { - diagnosticService = new UnitTestDiagnosticService(); - }); - suite('TestStatus: Error', () => { - let actualPrefix: string; - let actualSeverity: DiagnosticSeverity; - let expectedPrefix: string; - let expectedSeverity: DiagnosticSeverity; - suiteSetup(() => { - actualPrefix = diagnosticService.getMessagePrefix(TestStatus.Error); - actualSeverity = diagnosticService.getSeverity(PythonTestMessageSeverity.Error); - expectedPrefix = localize.Testing.testErrorDiagnosticMessage(); - expectedSeverity = DiagnosticSeverity.Error; - }); - test('Message Prefix', () => { - assert.equal(actualPrefix, expectedPrefix); - }); - test('Severity', () => { - assert.equal(actualSeverity, expectedSeverity); - }); - }); - suite('TestStatus: Fail', () => { - let actualPrefix: string; - let actualSeverity: DiagnosticSeverity; - let expectedPrefix: string; - let expectedSeverity: DiagnosticSeverity; - suiteSetup(() => { - actualPrefix = diagnosticService.getMessagePrefix(TestStatus.Fail); - actualSeverity = diagnosticService.getSeverity(PythonTestMessageSeverity.Failure); - expectedPrefix = localize.Testing.testFailDiagnosticMessage(); - expectedSeverity = DiagnosticSeverity.Error; - }); - test('Message Prefix', () => { - assert.equal(actualPrefix, expectedPrefix); - }); - test('Severity', () => { - assert.equal(actualSeverity, expectedSeverity); - }); - }); - suite('TestStatus: Skipped', () => { - let actualPrefix: string; - let actualSeverity: DiagnosticSeverity; - let expectedPrefix: string; - let expectedSeverity: DiagnosticSeverity; - suiteSetup(() => { - actualPrefix = diagnosticService.getMessagePrefix(TestStatus.Skipped); - actualSeverity = diagnosticService.getSeverity(PythonTestMessageSeverity.Skip); - expectedPrefix = localize.Testing.testSkippedDiagnosticMessage(); - expectedSeverity = DiagnosticSeverity.Information; - }); - test('Message Prefix', () => { - assert.equal(actualPrefix, expectedPrefix); - }); - test('Severity', () => { - assert.equal(actualSeverity, expectedSeverity); - }); - }); -}); diff --git a/src/test/testing/unittest/unittest.discovery.test.ts b/src/test/testing/unittest/unittest.discovery.test.ts deleted file mode 100644 index f3e7608779c0..000000000000 --- a/src/test/testing/unittest/unittest.discovery.test.ts +++ /dev/null @@ -1,212 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -import * as assert from 'assert'; -import * as fs from 'fs-extra'; -import { EOL } from 'os'; -import * as path from 'path'; -import { instance, mock } from 'ts-mockito'; -import { ConfigurationTarget } from 'vscode'; -import { CommandSource, EXTENSION_ROOT_DIR } from '../../../client/common/constants'; -import { IProcessServiceFactory } from '../../../client/common/process/types'; -import { ICondaService, IInterpreterService } from '../../../client/interpreter/contracts'; -import { InterpreterService } from '../../../client/interpreter/interpreterService'; -import { CondaService } from '../../../client/pythonEnvironments/discovery/locators/services/condaService'; -import { ITestManagerFactory } from '../../../client/testing/common/types'; -import { rootWorkspaceUri, updateSetting } from '../../common'; -import { MockProcessService } from '../../mocks/proc'; -import { registerForIOC } from '../../pythonEnvironments/legacyIOC'; -import { UnitTestIocContainer } from '../serviceRegistry'; -import { initialize, initializeTest, IS_MULTI_ROOT_TEST } from './../../initialize'; - -const testFilesPath = path.join(EXTENSION_ROOT_DIR, '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 defaultUnitTestArgs = ['-v', '-s', '.', '-p', '*test*.py']; - -suite('Unit Tests - unittest - discovery with mocked process output', () => { - let ioc: UnitTestIocContainer; - const rootDirectory = UNITTEST_TEST_FILES_PATH; - const configTarget = IS_MULTI_ROOT_TEST ? ConfigurationTarget.WorkspaceFolder : ConfigurationTarget.Workspace; - - suiteSetup(async () => { - await initialize(); - await updateSetting('testing.unittestArgs', defaultUnitTestArgs, rootWorkspaceUri, configTarget); - }); - setup(async () => { - const cachePath = path.join(UNITTEST_TEST_FILES_PATH, '.cache'); - if (await fs.pathExists(cachePath)) { - await fs.remove(cachePath); - } - await initializeTest(); - await initializeDI(); - }); - teardown(async () => { - await ioc.dispose(); - await updateSetting('testing.unittestArgs', defaultUnitTestArgs, rootWorkspaceUri, configTarget); - }); - - async function initializeDI() { - ioc = new UnitTestIocContainer(); - ioc.registerCommonTypes(); - ioc.registerVariableTypes(); - ioc.registerUnitTestTypes(); - - // Mocks. - ioc.registerMockProcessTypes(); - ioc.registerInterpreterStorageTypes(); - ioc.serviceManager.addSingletonInstance( - IInterpreterService, - instance(mock(InterpreterService)), - ); - await registerForIOC(ioc.serviceManager, ioc.serviceContainer); - ioc.serviceManager.rebindInstance(ICondaService, instance(mock(CondaService))); - } - - async function injectTestDiscoveryOutput(output: string) { - const procService = (await ioc.serviceContainer - .get(IProcessServiceFactory) - .create()) as MockProcessService; - procService.onExecObservable((_file, args, _options, callback) => { - if ( - args.length > 1 && - args[0] === '-c' && - args[1].includes('import unittest') && - args[1].includes('loader = unittest.TestLoader()') - ) { - callback({ - // Ensure any spaces added during code formatting or the like are removed. - out: output - .split(/\r?\n/g) - .map((item) => item.trim()) - .join(EOL), - source: 'stdout', - }); - } - }); - } - - test('Discover Tests (single test file)', async () => { - await updateSetting('testing.unittestArgs', ['-s=./tests', '-p=test_*.py'], rootWorkspaceUri, configTarget); - - await injectTestDiscoveryOutput(`start - test_one.Test_test1.test_A - test_one.Test_test1.test_B - test_one.Test_test1.test_c - `); - const factory = ioc.serviceContainer.get(ITestManagerFactory); - const testManager = factory('unittest', rootWorkspaceUri!, UNITTEST_SINGLE_TEST_FILE_PATH); - const tests = await testManager.discoverTests(CommandSource.ui, true, true); - assert.equal(tests.testFiles.length, 1, 'Incorrect number of test files'); - assert.equal(tests.testFunctions.length, 3, 'Incorrect number of test functions'); - assert.equal(tests.testSuites.length, 1, 'Incorrect number of test suites'); - assert.equal( - tests.testFiles.some((t) => t.name === 'test_one.py' && t.nameToRun === 'test_one'), - true, - 'Test File not found', - ); - assert.equal( - tests.testFunctions.some( - (t) => t.testFunction.name === 'test_A' && t.testFunction.nameToRun === 'test_one.Test_test1.test_A', - ), - true, - 'Test File not found', - ); - }); - - test('Discover Tests', async () => { - await updateSetting('testing.unittestArgs', ['-s=./tests', '-p=test_*.py'], rootWorkspaceUri, configTarget); - - await injectTestDiscoveryOutput(`start - test_unittest_one.Test_test1.test_A - test_unittest_one.Test_test1.test_B - test_unittest_one.Test_test1.test_c - test_unittest_two.Test_test2.test_A2 - test_unittest_two.Test_test2.test_B2 - test_unittest_two.Test_test2.test_C2 - test_unittest_two.Test_test2.test_D2 - test_unittest_two.Test_test2a.test_222A2 - test_unittest_two.Test_test2a.test_222B2 - `); - const factory = ioc.serviceContainer.get(ITestManagerFactory); - const testManager = factory('unittest', rootWorkspaceUri!, rootDirectory); - const tests = await testManager.discoverTests(CommandSource.ui, true, true); - assert.equal(tests.testFiles.length, 2, 'Incorrect number of test files'); - assert.equal(tests.testFunctions.length, 9, 'Incorrect number of test functions'); - assert.equal(tests.testSuites.length, 3, 'Incorrect number of test suites'); - assert.equal( - tests.testFiles.some((t) => t.name === 'test_unittest_one.py' && t.nameToRun === 'test_unittest_one'), - true, - 'Test File not found', - ); - assert.equal( - tests.testFiles.some((t) => t.name === 'test_unittest_two.py' && t.nameToRun === 'test_unittest_two'), - true, - 'Test File not found', - ); - assert.equal( - tests.testFunctions.some( - (t) => - t.testFunction.name === 'test_A' && - t.testFunction.nameToRun === 'test_unittest_one.Test_test1.test_A', - ), - true, - 'Test File not found', - ); - assert.equal( - tests.testFunctions.some( - (t) => - t.testFunction.name === 'test_A2' && - t.testFunction.nameToRun === 'test_unittest_two.Test_test2.test_A2', - ), - true, - 'Test File not found', - ); - }); - - test('Discover Tests (pattern = *_test_*.py)', async () => { - await updateSetting('testing.unittestArgs', ['-s=./tests', '-p=*_test*.py'], rootWorkspaceUri, configTarget); - - await injectTestDiscoveryOutput(`start - unittest_three_test.Test_test3.test_A - unittest_three_test.Test_test3.test_B - `); - const factory = ioc.serviceContainer.get(ITestManagerFactory); - const testManager = factory('unittest', rootWorkspaceUri!, rootDirectory); - const tests = await testManager.discoverTests(CommandSource.ui, true, true); - assert.equal(tests.testFiles.length, 1, 'Incorrect number of test files'); - assert.equal(tests.testFunctions.length, 2, 'Incorrect number of test functions'); - assert.equal(tests.testSuites.length, 1, 'Incorrect number of test suites'); - assert.equal( - tests.testFiles.some((t) => t.name === 'unittest_three_test.py' && t.nameToRun === 'unittest_three_test'), - true, - 'Test File not found', - ); - assert.equal( - tests.testFunctions.some( - (t) => - t.testFunction.name === 'test_A' && - t.testFunction.nameToRun === 'unittest_three_test.Test_test3.test_A', - ), - true, - 'Test File not found', - ); - }); - - test('Setting cwd should return tests', async () => { - await updateSetting('testing.unittestArgs', ['-s=./tests', '-p=test_*.py'], rootWorkspaceUri, configTarget); - - await injectTestDiscoveryOutput(`start - test_cwd.Test_Current_Working_Directory.test_cwd - `); - const factory = ioc.serviceContainer.get(ITestManagerFactory); - const testManager = factory('unittest', rootWorkspaceUri!, unitTestTestFilesCwdPath); - - const tests = await testManager.discoverTests(CommandSource.ui, true, true); - assert.equal(tests.testFiles.length, 1, 'Incorrect number of test files'); - assert.equal(tests.testFolders.length, 1, 'Incorrect number of test folders'); - assert.equal(tests.testFunctions.length, 1, 'Incorrect number of test functions'); - assert.equal(tests.testSuites.length, 1, 'Incorrect number of test suites'); - }); -}); diff --git a/src/test/testing/unittest/unittest.discovery.unit.test.ts b/src/test/testing/unittest/unittest.discovery.unit.test.ts deleted file mode 100644 index 9d5b00fac89b..000000000000 --- a/src/test/testing/unittest/unittest.discovery.unit.test.ts +++ /dev/null @@ -1,636 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { expect, use } from 'chai'; -import * as chaipromise from 'chai-as-promised'; -import * as path from 'path'; -import * as typeMoq from 'typemoq'; -import { CancellationToken, Uri } from 'vscode'; -import { IServiceContainer } from '../../../client/ioc/types'; -import { UNITTEST_PROVIDER } from '../../../client/testing/common/constants'; -import { TestsHelper } from '../../../client/testing/common/testUtils'; -import { TestFlatteningVisitor } from '../../../client/testing/common/testVisitors/flatteningVisitor'; -import { - IArgumentsHelper, - ITestDiscoveryService, - ITestRunner, - ITestsParser, - Options, - TestDiscoveryOptions, - Tests, - UnitTestParserOptions, -} from '../../../client/testing/common/types'; -import { TestDiscoveryService } from '../../../client/testing/unittest/services/discoveryService'; -import { TestsParser } from '../../../client/testing/unittest/services/parserService'; - -use(chaipromise); - -suite('Unit Tests - Unittest - Discovery', () => { - let discoveryService: ITestDiscoveryService; - let argsHelper: typeMoq.IMock; - let testParser: typeMoq.IMock; - let runner: typeMoq.IMock; - let serviceContainer: typeMoq.IMock; - const dir = path.join('a', 'b', 'c'); - const pattern = 'Pattern_To_Search_For'; - setup(() => { - serviceContainer = typeMoq.Mock.ofType(); - argsHelper = typeMoq.Mock.ofType(); - testParser = typeMoq.Mock.ofType(); - runner = typeMoq.Mock.ofType(); - - serviceContainer - .setup((s) => s.get(typeMoq.It.isValue(IArgumentsHelper), typeMoq.It.isAny())) - .returns(() => argsHelper.object); - serviceContainer - .setup((s) => s.get(typeMoq.It.isValue(ITestRunner), typeMoq.It.isAny())) - .returns(() => runner.object); - - discoveryService = new TestDiscoveryService(serviceContainer.object, testParser.object); - }); - test('Ensure discovery is invoked with the right args with start directory defined with -s', async () => { - const args: string[] = []; - const runOutput = 'xyz'; - const tests: Tests = { - summary: { errors: 1, failures: 0, passed: 0, skipped: 0 }, - testFiles: [], - testFunctions: [], - testSuites: [], - rootTestFolders: [], - testFolders: [], - }; - argsHelper - .setup((a) => a.getOptionValues(typeMoq.It.isValue(args), typeMoq.It.isValue('-s'))) - .returns(() => dir) - .verifiable(typeMoq.Times.atLeastOnce()); - runner - .setup((r) => r.run(typeMoq.It.isValue(UNITTEST_PROVIDER), typeMoq.It.isAny())) - .callback((_, opts: Options) => { - expect(opts.args).to.include('-c'); - expect(opts.args[1]).to.contain(dir); - expect(opts.args[1]).to.not.contain('loader.discover("."'); - }) - .returns(() => Promise.resolve(runOutput)) - .verifiable(typeMoq.Times.once()); - testParser - .setup((t) => t.parse(typeMoq.It.isValue(runOutput), typeMoq.It.isAny())) - .returns(() => tests) - .verifiable(typeMoq.Times.once()); - - const options = typeMoq.Mock.ofType(); - const token = typeMoq.Mock.ofType(); - options.setup((o) => o.args).returns(() => args); - options.setup((o) => o.token).returns(() => token.object); - token.setup((t) => t.isCancellationRequested).returns(() => false); - - const result = await discoveryService.discoverTests(options.object); - - expect(result).to.be.equal(tests); - argsHelper.verifyAll(); - runner.verifyAll(); - testParser.verifyAll(); - }); - test('Ensure discovery is invoked with the right args with start directory defined with --start-directory', async () => { - const args: string[] = []; - const runOutput = 'xyz'; - const tests: Tests = { - summary: { errors: 1, failures: 0, passed: 0, skipped: 0 }, - testFiles: [], - testFunctions: [], - testSuites: [], - rootTestFolders: [], - testFolders: [], - }; - argsHelper - .setup((a) => a.getOptionValues(typeMoq.It.isValue(args), typeMoq.It.isValue('-s'))) - .returns(() => undefined) - .verifiable(typeMoq.Times.atLeastOnce()); - argsHelper - .setup((a) => a.getOptionValues(typeMoq.It.isValue(args), typeMoq.It.isValue('--start-directory'))) - .returns(() => dir) - .verifiable(typeMoq.Times.atLeastOnce()); - runner - .setup((r) => r.run(typeMoq.It.isValue(UNITTEST_PROVIDER), typeMoq.It.isAny())) - .callback((_, opts: Options) => { - expect(opts.args).to.include('-c'); - expect(opts.args[1]).to.contain(dir); - expect(opts.args[1]).to.not.contain('loader.discover("."'); - }) - .returns(() => Promise.resolve(runOutput)) - .verifiable(typeMoq.Times.once()); - testParser - .setup((t) => t.parse(typeMoq.It.isValue(runOutput), typeMoq.It.isAny())) - .returns(() => tests) - .verifiable(typeMoq.Times.once()); - - const options = typeMoq.Mock.ofType(); - const token = typeMoq.Mock.ofType(); - options.setup((o) => o.args).returns(() => args); - options.setup((o) => o.token).returns(() => token.object); - token.setup((t) => t.isCancellationRequested).returns(() => false); - - const result = await discoveryService.discoverTests(options.object); - - expect(result).to.be.equal(tests); - argsHelper.verifyAll(); - runner.verifyAll(); - testParser.verifyAll(); - }); - test('Ensure discovery is invoked with the right args without a start directory', async () => { - const args: string[] = []; - const runOutput = 'xyz'; - const tests: Tests = { - summary: { errors: 1, failures: 0, passed: 0, skipped: 0 }, - testFiles: [], - testFunctions: [], - testSuites: [], - rootTestFolders: [], - testFolders: [], - }; - argsHelper - .setup((a) => a.getOptionValues(typeMoq.It.isValue(args), typeMoq.It.isValue('-s'))) - .returns(() => undefined) - .verifiable(typeMoq.Times.atLeastOnce()); - argsHelper - .setup((a) => a.getOptionValues(typeMoq.It.isValue(args), typeMoq.It.isValue('--start-directory'))) - .returns(() => undefined) - .verifiable(typeMoq.Times.atLeastOnce()); - runner - .setup((r) => r.run(typeMoq.It.isValue(UNITTEST_PROVIDER), typeMoq.It.isAny())) - .callback((_, opts: Options) => { - expect(opts.args).to.include('-c'); - expect(opts.args[1]).to.not.contain(dir); - expect(opts.args[1]).to.contain('loader.discover("."'); - }) - .returns(() => Promise.resolve(runOutput)) - .verifiable(typeMoq.Times.once()); - testParser - .setup((t) => t.parse(typeMoq.It.isValue(runOutput), typeMoq.It.isAny())) - .returns(() => tests) - .verifiable(typeMoq.Times.once()); - - const options = typeMoq.Mock.ofType(); - const token = typeMoq.Mock.ofType(); - options.setup((o) => o.args).returns(() => args); - options.setup((o) => o.token).returns(() => token.object); - token.setup((t) => t.isCancellationRequested).returns(() => false); - - const result = await discoveryService.discoverTests(options.object); - - expect(result).to.be.equal(tests); - argsHelper.verifyAll(); - runner.verifyAll(); - testParser.verifyAll(); - }); - test('Ensure discovery is invoked with the right args without a pattern defined with -p', async () => { - const args: string[] = []; - const runOutput = 'xyz'; - const tests: Tests = { - summary: { errors: 1, failures: 0, passed: 0, skipped: 0 }, - testFiles: [], - testFunctions: [], - testSuites: [], - rootTestFolders: [], - testFolders: [], - }; - argsHelper - .setup((a) => a.getOptionValues(typeMoq.It.isValue(args), typeMoq.It.isValue('-p'))) - .returns(() => pattern) - .verifiable(typeMoq.Times.atLeastOnce()); - runner - .setup((r) => r.run(typeMoq.It.isValue(UNITTEST_PROVIDER), typeMoq.It.isAny())) - .callback((_, opts: Options) => { - expect(opts.args).to.include('-c'); - expect(opts.args[1]).to.contain(pattern); - expect(opts.args[1]).to.not.contain('test*.py'); - }) - .returns(() => Promise.resolve(runOutput)) - .verifiable(typeMoq.Times.once()); - testParser - .setup((t) => t.parse(typeMoq.It.isValue(runOutput), typeMoq.It.isAny())) - .returns(() => tests) - .verifiable(typeMoq.Times.once()); - - const options = typeMoq.Mock.ofType(); - const token = typeMoq.Mock.ofType(); - options.setup((o) => o.args).returns(() => args); - options.setup((o) => o.token).returns(() => token.object); - token.setup((t) => t.isCancellationRequested).returns(() => false); - - const result = await discoveryService.discoverTests(options.object); - - expect(result).to.be.equal(tests); - argsHelper.verifyAll(); - runner.verifyAll(); - testParser.verifyAll(); - }); - test('Ensure discovery is invoked with the right args without a pattern defined with --pattern', async () => { - const args: string[] = []; - const runOutput = 'xyz'; - const tests: Tests = { - summary: { errors: 1, failures: 0, passed: 0, skipped: 0 }, - testFiles: [], - testFunctions: [], - testSuites: [], - rootTestFolders: [], - testFolders: [], - }; - argsHelper - .setup((a) => a.getOptionValues(typeMoq.It.isValue(args), typeMoq.It.isValue('-p'))) - .returns(() => undefined) - .verifiable(typeMoq.Times.atLeastOnce()); - argsHelper - .setup((a) => a.getOptionValues(typeMoq.It.isValue(args), typeMoq.It.isValue('--pattern'))) - .returns(() => pattern) - .verifiable(typeMoq.Times.atLeastOnce()); - runner - .setup((r) => r.run(typeMoq.It.isValue(UNITTEST_PROVIDER), typeMoq.It.isAny())) - .callback((_, opts: Options) => { - expect(opts.args).to.include('-c'); - expect(opts.args[1]).to.contain(pattern); - expect(opts.args[1]).to.not.contain('test*.py'); - }) - .returns(() => Promise.resolve(runOutput)) - .verifiable(typeMoq.Times.once()); - testParser - .setup((t) => t.parse(typeMoq.It.isValue(runOutput), typeMoq.It.isAny())) - .returns(() => tests) - .verifiable(typeMoq.Times.once()); - - const options = typeMoq.Mock.ofType(); - const token = typeMoq.Mock.ofType(); - options.setup((o) => o.args).returns(() => args); - options.setup((o) => o.token).returns(() => token.object); - token.setup((t) => t.isCancellationRequested).returns(() => false); - - const result = await discoveryService.discoverTests(options.object); - - expect(result).to.be.equal(tests); - argsHelper.verifyAll(); - runner.verifyAll(); - testParser.verifyAll(); - }); - test('Ensure discovery is invoked with the right args without a pattern not defined', async () => { - const args: string[] = []; - const runOutput = 'xyz'; - const tests: Tests = { - summary: { errors: 1, failures: 0, passed: 0, skipped: 0 }, - testFiles: [], - testFunctions: [], - testSuites: [], - rootTestFolders: [], - testFolders: [], - }; - argsHelper - .setup((a) => a.getOptionValues(typeMoq.It.isValue(args), typeMoq.It.isValue('-p'))) - .returns(() => undefined) - .verifiable(typeMoq.Times.atLeastOnce()); - argsHelper - .setup((a) => a.getOptionValues(typeMoq.It.isValue(args), typeMoq.It.isValue('--pattern'))) - .returns(() => undefined) - .verifiable(typeMoq.Times.atLeastOnce()); - runner - .setup((r) => r.run(typeMoq.It.isValue(UNITTEST_PROVIDER), typeMoq.It.isAny())) - .callback((_, opts: Options) => { - expect(opts.args).to.include('-c'); - expect(opts.args[1]).to.not.contain(pattern); - expect(opts.args[1]).to.contain('test*.py'); - }) - .returns(() => Promise.resolve(runOutput)) - .verifiable(typeMoq.Times.once()); - testParser - .setup((t) => t.parse(typeMoq.It.isValue(runOutput), typeMoq.It.isAny())) - .returns(() => tests) - .verifiable(typeMoq.Times.once()); - - const options = typeMoq.Mock.ofType(); - const token = typeMoq.Mock.ofType(); - options.setup((o) => o.args).returns(() => args); - options.setup((o) => o.token).returns(() => token.object); - token.setup((t) => t.isCancellationRequested).returns(() => false); - - const result = await discoveryService.discoverTests(options.object); - - expect(result).to.be.equal(tests); - argsHelper.verifyAll(); - runner.verifyAll(); - testParser.verifyAll(); - }); - test('Ensure discovery is cancelled', async () => { - const args: string[] = []; - const runOutput = 'xyz'; - const tests: Tests = { - summary: { errors: 1, failures: 0, passed: 0, skipped: 0 }, - testFiles: [], - testFunctions: [], - testSuites: [], - rootTestFolders: [], - testFolders: [], - }; - argsHelper - .setup((a) => a.getOptionValues(typeMoq.It.isValue(args), typeMoq.It.isValue('-p'))) - .returns(() => undefined) - .verifiable(typeMoq.Times.atLeastOnce()); - argsHelper - .setup((a) => a.getOptionValues(typeMoq.It.isValue(args), typeMoq.It.isValue('--pattern'))) - .returns(() => undefined) - .verifiable(typeMoq.Times.atLeastOnce()); - runner - .setup((r) => r.run(typeMoq.It.isValue(UNITTEST_PROVIDER), typeMoq.It.isAny())) - .returns(() => Promise.resolve(runOutput)) - .verifiable(typeMoq.Times.once()); - testParser - .setup((t) => t.parse(typeMoq.It.isValue(runOutput), typeMoq.It.isAny())) - .returns(() => tests) - .verifiable(typeMoq.Times.never()); - - const options = typeMoq.Mock.ofType(); - const token = typeMoq.Mock.ofType(); - options.setup((o) => o.args).returns(() => args); - options.setup((o) => o.token).returns(() => token.object); - token.setup((t) => t.isCancellationRequested).returns(() => true); - - const promise = discoveryService.discoverTests(options.object); - - await expect(promise).to.eventually.be.rejectedWith('cancelled'); - argsHelper.verifyAll(); - runner.verifyAll(); - testParser.verifyAll(); - }); - test('Ensure discovery resolves test suites in n-depth directories', async () => { - const testHelper: TestsHelper = new TestsHelper(new TestFlatteningVisitor()); - - const testsParser: TestsParser = new TestsParser(testHelper); - - const opts = typeMoq.Mock.ofType(); - const token = typeMoq.Mock.ofType(); - const wspace = typeMoq.Mock.ofType(); - opts.setup((o) => o.token).returns(() => token.object); - opts.setup((o) => o.workspaceFolder).returns(() => wspace.object); - token.setup((t) => t.isCancellationRequested).returns(() => true); - opts.setup((o) => o.cwd).returns(() => '/home/user/dev'); - opts.setup((o) => o.startDirectory).returns(() => '/home/user/dev/tests'); - - const discoveryOutput: string = [ - 'start', - 'apptests.debug.class_name.RootClassName.test_root', - 'apptests.debug.class_name.RootClassName.test_root_other', - 'apptests.debug.first.class_name.FirstLevelClassName.test_first', - 'apptests.debug.first.class_name.FirstLevelClassName.test_first_other', - 'apptests.debug.first.second.class_name.SecondLevelClassName.test_second', - 'apptests.debug.first.second.class_name.SecondLevelClassName.test_second_other', - '', - ].join('\n'); - - const tests: Tests = testsParser.parse(discoveryOutput, opts.object); - - expect(tests.testFiles.length).to.be.equal(3); - expect(tests.testFunctions.length).to.be.equal(6); - expect(tests.testSuites.length).to.be.equal(3); - expect(tests.testFolders.length).to.be.equal(5); - - // now ensure that each test function belongs within a single test suite... - tests.testFunctions.forEach((fn) => { - if (fn.parentTestSuite) { - const testPrefix: boolean = fn.testFunction.nameToRun.startsWith(fn.parentTestSuite.nameToRun); - expect(testPrefix).to.equal( - true, - [ - `function ${fn.testFunction.name} has a parent suite ${fn.parentTestSuite.name}, `, - `but the parent suite 'nameToRun' (${fn.parentTestSuite.nameToRun}) isn't the `, - `prefix to the functions 'nameToRun' (${fn.testFunction.nameToRun})`, - ].join(''), - ); - } - }); - }); - test('Ensure discovery resolves test files in n-depth directories', async () => { - const testHelper: TestsHelper = new TestsHelper(new TestFlatteningVisitor()); - - const testsParser: TestsParser = new TestsParser(testHelper); - - const opts = typeMoq.Mock.ofType(); - const token = typeMoq.Mock.ofType(); - const wspace = typeMoq.Mock.ofType(); - opts.setup((o) => o.token).returns(() => token.object); - opts.setup((o) => o.workspaceFolder).returns(() => wspace.object); - token.setup((t) => t.isCancellationRequested).returns(() => true); - opts.setup((o) => o.cwd).returns(() => '/home/user/dev'); - opts.setup((o) => o.startDirectory).returns(() => '/home/user/dev/tests'); - - const discoveryOutput: string = [ - 'start', - 'apptests.debug.class_name.RootClassName.test_root', - 'apptests.debug.class_name.RootClassName.test_root_other', - 'apptests.debug.first.class_name.FirstLevelClassName.test_first', - 'apptests.debug.first.class_name.FirstLevelClassName.test_first_other', - 'apptests.debug.first.second.class_name.SecondLevelClassName.test_second', - 'apptests.debug.first.second.class_name.SecondLevelClassName.test_second_other', - '', - ].join('\n'); - - const tests: Tests = testsParser.parse(discoveryOutput, opts.object); - - expect(tests.testFiles.length).to.be.equal(3); - expect(tests.testFunctions.length).to.be.equal(6); - expect(tests.testSuites.length).to.be.equal(3); - expect(tests.testFolders.length).to.be.equal(5); - - // now ensure that the 'nameToRun' for each test function begins with its file's a single test suite... - tests.testFunctions.forEach((fn) => { - if (fn.parentTestSuite) { - const testPrefix: boolean = fn.testFunction.nameToRun.startsWith(fn.parentTestFile.nameToRun); - expect(testPrefix).to.equal( - true, - [ - `function ${fn.testFunction.name} was found in file ${fn.parentTestFile.name}, `, - `but the parent file 'nameToRun' (${fn.parentTestFile.nameToRun}) isn't the `, - `prefix to the functions 'nameToRun' (${fn.testFunction.nameToRun})`, - ].join(''), - ); - } - }); - - // Check that the visible folder name is just the last item in the path, not the whole path - tests.testFolders.forEach((folder) => { - const pathItems = folder.nameToRun.split(path.sep); - expect(pathItems[pathItems.length - 1]).to.equal(folder.name); - }); - - // Check that the visible file name is just the last item in the path, not the whole path - tests.testFiles.forEach((file) => { - const pathItems = file.nameToRun.split('.'); - expect(pathItems[pathItems.length - 1] + '.py').to.equal(file.name); - }); - }); - - test('Ensure discovery resolves test suites in n-depth directories when no start directory is given', async () => { - const testHelper: TestsHelper = new TestsHelper(new TestFlatteningVisitor()); - - const testsParser: TestsParser = new TestsParser(testHelper); - - const opts = typeMoq.Mock.ofType(); - const token = typeMoq.Mock.ofType(); - const wspace = typeMoq.Mock.ofType(); - opts.setup((o) => o.token).returns(() => token.object); - opts.setup((o) => o.workspaceFolder).returns(() => wspace.object); - token.setup((t) => t.isCancellationRequested).returns(() => true); - opts.setup((o) => o.cwd).returns(() => '/home/user/dev'); - opts.setup((o) => o.startDirectory).returns(() => ''); - - const discoveryOutput: string = [ - 'start', - 'apptests.debug.class_name.RootClassName.test_root', - 'apptests.debug.class_name.RootClassName.test_root_other', - 'apptests.debug.first.class_name.FirstLevelClassName.test_first', - 'apptests.debug.first.class_name.FirstLevelClassName.test_first_other', - 'apptests.debug.first.second.class_name.SecondLevelClassName.test_second', - 'apptests.debug.first.second.class_name.SecondLevelClassName.test_second_other', - '', - ].join('\n'); - - const tests: Tests = testsParser.parse(discoveryOutput, opts.object); - - expect(tests.testFiles.length).to.be.equal(3); - expect(tests.testFunctions.length).to.be.equal(6); - expect(tests.testSuites.length).to.be.equal(3); - expect(tests.testFolders.length).to.be.equal(4); - - // now ensure that each test function belongs within a single test suite... - tests.testFunctions.forEach((fn) => { - if (fn.parentTestSuite) { - const testPrefix: boolean = fn.testFunction.nameToRun.startsWith(fn.parentTestSuite.nameToRun); - expect(testPrefix).to.equal( - true, - [ - `function ${fn.testFunction.name} has a parent suite ${fn.parentTestSuite.name}, `, - `but the parent suite 'nameToRun' (${fn.parentTestSuite.nameToRun}) isn't the `, - `prefix to the functions 'nameToRun' (${fn.testFunction.nameToRun})`, - ].join(''), - ); - } - }); - }); - test('Ensure discovery resolves test suites in n-depth directories when a relative start directory is given', async () => { - const testHelper: TestsHelper = new TestsHelper(new TestFlatteningVisitor()); - - const testsParser: TestsParser = new TestsParser(testHelper); - - const opts = typeMoq.Mock.ofType(); - const token = typeMoq.Mock.ofType(); - const wspace = typeMoq.Mock.ofType(); - opts.setup((o) => o.token).returns(() => token.object); - opts.setup((o) => o.workspaceFolder).returns(() => wspace.object); - token.setup((t) => t.isCancellationRequested).returns(() => true); - opts.setup((o) => o.cwd).returns(() => '/home/user/dev'); - opts.setup((o) => o.startDirectory).returns(() => './tests'); - - const discoveryOutput: string = [ - 'start', - 'apptests.debug.class_name.RootClassName.test_root', - 'apptests.debug.class_name.RootClassName.test_root_other', - 'apptests.debug.first.class_name.FirstLevelClassName.test_first', - 'apptests.debug.first.class_name.FirstLevelClassName.test_first_other', - 'apptests.debug.first.second.class_name.SecondLevelClassName.test_second', - 'apptests.debug.first.second.class_name.SecondLevelClassName.test_second_other', - '', - ].join('\n'); - - const tests: Tests = testsParser.parse(discoveryOutput, opts.object); - - expect(tests.testFiles.length).to.be.equal(3); - expect(tests.testFunctions.length).to.be.equal(6); - expect(tests.testSuites.length).to.be.equal(3); - expect(tests.testFolders.length).to.be.equal(5); - - // now ensure that each test function belongs within a single test suite... - tests.testFunctions.forEach((fn) => { - if (fn.parentTestSuite) { - const testPrefix: boolean = fn.testFunction.nameToRun.startsWith(fn.parentTestSuite.nameToRun); - expect(testPrefix).to.equal( - true, - [ - `function ${fn.testFunction.name} has a parent suite ${fn.parentTestSuite.name}, `, - `but the parent suite 'nameToRun' (${fn.parentTestSuite.nameToRun}) isn't the `, - `prefix to the functions 'nameToRun' (${fn.testFunction.nameToRun})`, - ].join(''), - ); - } - }); - }); - test('Ensure discovery will not fail with blank content', async () => { - const testHelper: TestsHelper = new TestsHelper(new TestFlatteningVisitor()); - - const testsParser: TestsParser = new TestsParser(testHelper); - - const opts = typeMoq.Mock.ofType(); - const token = typeMoq.Mock.ofType(); - const wspace = typeMoq.Mock.ofType(); - opts.setup((o) => o.token).returns(() => token.object); - opts.setup((o) => o.workspaceFolder).returns(() => wspace.object); - token.setup((t) => t.isCancellationRequested).returns(() => true); - opts.setup((o) => o.cwd).returns(() => '/home/user/dev'); - opts.setup((o) => o.startDirectory).returns(() => './tests'); - - const tests: Tests = testsParser.parse('', opts.object); - - expect(tests.testFiles.length).to.be.equal(0); - expect(tests.testFunctions.length).to.be.equal(0); - expect(tests.testSuites.length).to.be.equal(0); - expect(tests.testFolders.length).to.be.equal(0); - }); - test('Ensure discovery will not fail with corrupt content', async () => { - const testHelper: TestsHelper = new TestsHelper(new TestFlatteningVisitor()); - - const testsParser: TestsParser = new TestsParser(testHelper); - - const opts = typeMoq.Mock.ofType(); - const token = typeMoq.Mock.ofType(); - const wspace = typeMoq.Mock.ofType(); - opts.setup((o) => o.token).returns(() => token.object); - opts.setup((o) => o.workspaceFolder).returns(() => wspace.object); - token.setup((t) => t.isCancellationRequested).returns(() => true); - opts.setup((o) => o.cwd).returns(() => '/home/user/dev'); - opts.setup((o) => o.startDirectory).returns(() => './tests'); - - const discoveryOutput: string = [ - 'a;lskdjfa', - 'allikbrilkpdbfkdfbalk;nfm', - '', - ';;h,spmn,nlikmslkjls.bmnl;klkjna;jdfngad,lmvnjkldfhb', - '', - ].join('\n'); - - const tests: Tests = testsParser.parse(discoveryOutput, opts.object); - - expect(tests.testFiles.length).to.be.equal(0); - expect(tests.testFunctions.length).to.be.equal(0); - expect(tests.testSuites.length).to.be.equal(0); - expect(tests.testFolders.length).to.be.equal(0); - }); - test('Ensure discovery resolves when no tests are found in the given path', async () => { - const testHelper: TestsHelper = new TestsHelper(new TestFlatteningVisitor()); - - const testsParser: TestsParser = new TestsParser(testHelper); - - const opts = typeMoq.Mock.ofType(); - const token = typeMoq.Mock.ofType(); - const wspace = typeMoq.Mock.ofType(); - opts.setup((o) => o.token).returns(() => token.object); - opts.setup((o) => o.workspaceFolder).returns(() => wspace.object); - token.setup((t) => t.isCancellationRequested).returns(() => true); - opts.setup((o) => o.cwd).returns(() => '/home/user/dev'); - opts.setup((o) => o.startDirectory).returns(() => './tests'); - - const discoveryOutput: string = 'start'; - - const tests: Tests = testsParser.parse(discoveryOutput, opts.object); - - expect(tests.testFiles.length).to.be.equal(0); - expect(tests.testFunctions.length).to.be.equal(0); - expect(tests.testSuites.length).to.be.equal(0); - expect(tests.testFolders.length).to.be.equal(0); - }); -}); diff --git a/src/test/testing/unittest/unittest.run.test.ts b/src/test/testing/unittest/unittest.run.test.ts deleted file mode 100644 index 292541ee570b..000000000000 --- a/src/test/testing/unittest/unittest.run.test.ts +++ /dev/null @@ -1,511 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -import * as assert from 'assert'; -import * as fs from 'fs-extra'; -import { EOL } from 'os'; -import * as path from 'path'; -import { instance, mock } from 'ts-mockito'; -import { ConfigurationTarget } from 'vscode'; -import { CommandSource, EXTENSION_ROOT_DIR } from '../../../client/common/constants'; -import { IProcessServiceFactory } from '../../../client/common/process/types'; -import { ICondaService, IInterpreterService } from '../../../client/interpreter/contracts'; -import { InterpreterService } from '../../../client/interpreter/interpreterService'; -import { CondaService } from '../../../client/pythonEnvironments/discovery/locators/services/condaService'; -import { ArgumentsHelper } from '../../../client/testing/common/argumentsHelper'; -import { UNITTEST_PROVIDER } from '../../../client/testing/common/constants'; -import { TestRunner } from '../../../client/testing/common/runner'; -import { - IArgumentsHelper, - IArgumentsService, - ITestManagerFactory, - ITestManagerRunner, - ITestRunner, - IUnitTestHelper, - IUnitTestSocketServer, - TestsToRun, -} from '../../../client/testing/common/types'; -import { UnitTestHelper } from '../../../client/testing/unittest/helper'; -import { TestManagerRunner } from '../../../client/testing/unittest/runner'; -import { ArgumentsService } from '../../../client/testing/unittest/services/argsService'; -import { rootWorkspaceUri, updateSetting } from '../../common'; -import { MockProcessService } from '../../mocks/proc'; -import { registerForIOC } from '../../pythonEnvironments/legacyIOC'; -import { MockUnitTestSocketServer } from '../mocks'; -import { UnitTestIocContainer } from '../serviceRegistry'; -import { initialize, initializeTest, IS_MULTI_ROOT_TEST } from './../../initialize'; - -const testFilesPath = path.join(EXTENSION_ROOT_DIR, 'src', 'test', 'pythonFiles', 'testFiles'); -const UNITTEST_TEST_FILES_PATH = path.join(testFilesPath, 'standard'); -const unitTestSpecificTestFilesPath = path.join(testFilesPath, 'specificTest'); -const defaultUnitTestArgs = ['-v', '-s', '.', '-p', '*test*.py']; - -suite('Unit Tests - unittest - run with mocked process output', () => { - let ioc: UnitTestIocContainer; - const rootDirectory = UNITTEST_TEST_FILES_PATH; - const configTarget = IS_MULTI_ROOT_TEST ? ConfigurationTarget.WorkspaceFolder : ConfigurationTarget.Workspace; - - suiteSetup(async () => { - await initialize(); - await updateSetting('testing.unittestArgs', defaultUnitTestArgs, rootWorkspaceUri, configTarget); - }); - setup(async () => { - const cachePath = path.join(UNITTEST_TEST_FILES_PATH, '.cache'); - if (await fs.pathExists(cachePath)) { - await fs.remove(cachePath); - } - await initializeTest(); - await initializeDI(); - await ignoreTestLauncher(); - }); - teardown(async () => { - await ioc.dispose(); - await updateSetting('testing.unittestArgs', defaultUnitTestArgs, rootWorkspaceUri, configTarget); - }); - - interface ITestConfiguration { - patternSwitch: string; - startDirSwitch: string; - } - - function buildTestCliSwitches(): ITestConfiguration[] { - const switches: ITestConfiguration[] = []; - ['-p', '--pattern'].forEach((p) => { - ['-s', '--start - directory'].forEach((s) => { - switches.push({ - patternSwitch: p, - startDirSwitch: s, - }); - }); - }); - return switches; - } - const cliSwitches = buildTestCliSwitches(); - - async function initializeDI() { - ioc = new UnitTestIocContainer(); - ioc.registerCommonTypes(); - ioc.registerVariableTypes(); - - // Mocks. - ioc.registerMockProcessTypes(); - ioc.registerMockUnitTestSocketServer(); - - // Standard unit test stypes. - ioc.registerTestDiscoveryServices(); - ioc.registerTestDiagnosticServices(); - ioc.registerTestManagers(); - ioc.registerTestManagerService(); - ioc.registerTestParsers(); - ioc.registerTestResultsHelper(); - ioc.registerTestsHelper(); - ioc.registerTestStorage(); - ioc.registerTestVisitors(); - ioc.registerInterpreterStorageTypes(); - ioc.serviceManager.add(IArgumentsService, ArgumentsService, UNITTEST_PROVIDER); - ioc.serviceManager.add(IArgumentsHelper, ArgumentsHelper); - ioc.serviceManager.add(ITestManagerRunner, TestManagerRunner, UNITTEST_PROVIDER); - ioc.serviceManager.add(ITestRunner, TestRunner); - ioc.serviceManager.add(IUnitTestHelper, UnitTestHelper); - ioc.serviceManager.addSingletonInstance( - IInterpreterService, - instance(mock(InterpreterService)), - ); - await registerForIOC(ioc.serviceManager, ioc.serviceContainer); - ioc.serviceManager.rebindInstance(ICondaService, instance(mock(CondaService))); - } - - async function ignoreTestLauncher() { - const procService = (await ioc.serviceContainer - .get(IProcessServiceFactory) - .create()) as MockProcessService; - // When running the python test launcher, just return. - procService.onExecObservable((_file, args, _options, callback) => { - if (args.length > 1 && args[0].endsWith('visualstudio_py_testlauncher.py')) { - callback({ out: '', source: 'stdout' }); - } - }); - } - async function injectTestDiscoveryOutput(output: string) { - const procService = (await ioc.serviceContainer - .get(IProcessServiceFactory) - .create()) as MockProcessService; - procService.onExecObservable((_file, args, _options, callback) => { - if ( - args.length > 1 && - args[0] === '-c' && - args[1].includes('import unittest') && - args[1].includes('loader = unittest.TestLoader()') - ) { - callback({ - // Ensure any spaces added during code formatting or the like are removed - out: output - .split(/\r?\n/g) - .map((item) => item.trim()) - .join(EOL), - source: 'stdout', - }); - } - }); - } - function injectTestSocketServerResults(results: {}[]) { - // Add results to be sent by unit test socket server. - const socketServer = ioc.serviceContainer.get(IUnitTestSocketServer); - socketServer.reset(); - socketServer.addResults(results); - } - - cliSwitches.forEach((cfg) => { - test(`Run Tests [${cfg.startDirSwitch}, ${cfg.patternSwitch}]`, async () => { - await updateSetting( - 'testing.unittestArgs', - ['-v', cfg.startDirSwitch, './tests', cfg.patternSwitch, 'test_unittest*.py'], - rootWorkspaceUri, - configTarget, - ); - - await injectTestDiscoveryOutput(`start - test_unittest_one.Test_test1.test_A - test_unittest_one.Test_test1.test_B - test_unittest_one.Test_test1.test_c - test_unittest_two.Test_test2.test_A2 - test_unittest_two.Test_test2.test_B2 - test_unittest_two.Test_test2.test_C2 - test_unittest_two.Test_test2.test_D2 - test_unittest_two.Test_test2a.test_222A2 - test_unittest_two.Test_test2a.test_222B2 - `); - const resultsToSend = [ - { - outcome: 'failed', - traceback: 'AssertionError: Not implemented\n', - message: 'Not implemented', - test: 'test_unittest_one.Test_test1.test_A', - }, - { outcome: 'passed', traceback: null, message: null, test: 'test_unittest_one.Test_test1.test_B' }, - { outcome: 'skipped', traceback: null, message: null, test: 'test_unittest_one.Test_test1.test_c' }, - { - outcome: 'failed', - traceback: 'raise self.failureException(msg)\nAssertionError: Not implemented\n', - message: 'Not implemented', - test: 'test_unittest_two.Test_test2.test_A2', - }, - { outcome: 'passed', traceback: null, message: null, test: 'test_unittest_two.Test_test2.test_B2' }, - { - outcome: 'failed', - traceback: 'raise self.failureException(msg)\nAssertionError: 1 != 2 : Not equal\n', - message: '1 != 2 : Not equal', - test: 'test_unittest_two.Test_test2.test_C2', - }, - { - outcome: 'error', - traceback: 'raise ArithmeticError()\nArithmeticError\n', - message: '', - test: 'test_unittest_two.Test_test2.test_D2', - }, - { - outcome: 'failed', - traceback: 'raise self.failureException(msg)\nAssertionError: Not implemented\n', - message: 'Not implemented', - test: 'test_unittest_two.Test_test2a.test_222A2', - }, - { outcome: 'passed', traceback: null, message: null, test: 'test_unittest_two.Test_test2a.test_222B2' }, - ]; - injectTestSocketServerResults(resultsToSend); - - const factory = ioc.serviceContainer.get(ITestManagerFactory); - const testManager = factory('unittest', rootWorkspaceUri!, rootDirectory); - const results = await testManager.runTest(CommandSource.ui); - - assert.equal(results.summary.errors, 1, 'Errors'); - assert.equal(results.summary.failures, 4, 'Failures'); - assert.equal(results.summary.passed, 3, 'Passed'); - assert.equal(results.summary.skipped, 1, 'skipped'); - }); - - test(`Run Failed Tests [${cfg.startDirSwitch}, ${cfg.patternSwitch}]`, async () => { - await updateSetting( - 'testing.unittestArgs', - [`${cfg.startDirSwitch}=./tests`, `${cfg.patternSwitch}=test_unittest*.py`], - rootWorkspaceUri, - configTarget, - ); - - await injectTestDiscoveryOutput(`start - test_unittest_one.Test_test1.test_A - test_unittest_one.Test_test1.test_B - test_unittest_one.Test_test1.test_c - test_unittest_two.Test_test2.test_A2 - test_unittest_two.Test_test2.test_B2 - test_unittest_two.Test_test2.test_C2 - test_unittest_two.Test_test2.test_D2 - test_unittest_two.Test_test2a.test_222A2 - test_unittest_two.Test_test2a.test_222B2 - `); - - const resultsToSend = [ - { - outcome: 'failed', - traceback: 'raise self.failureException(msg)\nAssertionError: Not implemented\n', - message: 'Not implemented', - test: 'test_unittest_one.Test_test1.test_A', - }, - { outcome: 'passed', traceback: null, message: null, test: 'test_unittest_one.Test_test1.test_B' }, - { outcome: 'skipped', traceback: null, message: null, test: 'test_unittest_one.Test_test1.test_c' }, - { - outcome: 'failed', - traceback: 'raise self.failureException(msg)\nAssertionError: Not implemented\n', - message: 'Not implemented', - test: 'test_unittest_two.Test_test2.test_A2', - }, - { outcome: 'passed', traceback: null, message: null, test: 'test_unittest_two.Test_test2.test_B2' }, - { - outcome: 'failed', - traceback: 'raise self.failureException(msg)\nAssertionError: 1 != 2 : Not equal\n', - message: '1 != 2 : Not equal', - test: 'test_unittest_two.Test_test2.test_C2', - }, - { - outcome: 'error', - traceback: 'raise ArithmeticError()\nArithmeticError\n', - message: '', - test: 'test_unittest_two.Test_test2.test_D2', - }, - { - outcome: 'failed', - traceback: 'raise self.failureException(msg)\nAssertionError: Not implemented\n', - message: 'Not implemented', - test: 'test_unittest_two.Test_test2a.test_222A2', - }, - { outcome: 'passed', traceback: null, message: null, test: 'test_unittest_two.Test_test2a.test_222B2' }, - ]; - injectTestSocketServerResults(resultsToSend); - - const factory = ioc.serviceContainer.get(ITestManagerFactory); - const testManager = factory('unittest', rootWorkspaceUri!, rootDirectory); - let results = await testManager.runTest(CommandSource.ui); - assert.equal(results.summary.errors, 1, 'Errors'); - assert.equal(results.summary.failures, 4, 'Failures'); - assert.equal(results.summary.passed, 3, 'Passed'); - assert.equal(results.summary.skipped, 1, 'skipped'); - - const failedResultsToSend = [ - { - outcome: 'failed', - traceback: 'raise self.failureException(msg)\nAssertionError: Not implemented\n', - message: 'Not implemented', - test: 'test_unittest_one.Test_test1.test_A', - }, - { - outcome: 'failed', - traceback: 'raise self.failureException(msg)\nAssertionError: Not implemented\n', - message: 'Not implemented', - test: 'test_unittest_two.Test_test2.test_A2', - }, - { - outcome: 'failed', - traceback: 'raise self.failureException(msg)\nAssertionError: 1 != 2 : Not equal\n', - message: '1 != 2 : Not equal', - test: 'test_unittest_two.Test_test2.test_C2', - }, - { - outcome: 'error', - traceback: 'raise ArithmeticError()\nArithmeticError\n', - message: '', - test: 'test_unittest_two.Test_test2.test_D2', - }, - { - outcome: 'failed', - traceback: 'raise self.failureException(msg)\nAssertionError: Not implemented\n', - message: 'Not implemented', - test: 'test_unittest_two.Test_test2a.test_222A2', - }, - ]; - injectTestSocketServerResults(failedResultsToSend); - - results = await testManager.runTest(CommandSource.ui, undefined, true); - assert.equal(results.summary.errors, 1, 'Failed Errors'); - assert.equal(results.summary.failures, 4, 'Failed Failures'); - assert.equal(results.summary.passed, 0, 'Failed Passed'); - assert.equal(results.summary.skipped, 0, 'Failed skipped'); - }); - - test(`Run Specific Test File [${cfg.startDirSwitch}, ${cfg.patternSwitch}]`, async () => { - await updateSetting( - 'testing.unittestArgs', - [`${cfg.startDirSwitch}=./tests`, `${cfg.patternSwitch}=test_unittest*.py`], - rootWorkspaceUri, - configTarget, - ); - - await injectTestDiscoveryOutput(`start - test_unittest_one.Test_test_one_1.test_1_1_1 - test_unittest_one.Test_test_one_1.test_1_1_2 - test_unittest_one.Test_test_one_1.test_1_1_3 - test_unittest_one.Test_test_one_2.test_1_2_1 - test_unittest_two.Test_test_two_1.test_1_1_1 - test_unittest_two.Test_test_two_1.test_1_1_2 - test_unittest_two.Test_test_two_1.test_1_1_3 - test_unittest_two.Test_test_two_2.test_2_1_1 - `); - - const resultsToSend = [ - { - outcome: 'passed', - traceback: null, - message: null, - test: 'test_unittest_one.Test_test_one_1.test_1_1_1', - }, - { - outcome: 'failed', - traceback: 'AssertionError: 1 != 2 : Not equal\n', - message: '1 != 2 : Not equal', - test: 'test_unittest_one.Test_test_one_1.test_1_1_2', - }, - { - outcome: 'skipped', - traceback: null, - message: null, - test: 'test_unittest_one.Test_test_one_1.test_1_1_3', - }, - { - outcome: 'passed', - traceback: null, - message: null, - test: 'test_unittest_one.Test_test_one_2.test_1_2_1', - }, - ]; - injectTestSocketServerResults(resultsToSend); - - const factory = ioc.serviceContainer.get(ITestManagerFactory); - const testManager = factory('unittest', rootWorkspaceUri!, unitTestSpecificTestFilesPath); - const tests = await testManager.discoverTests(CommandSource.ui, true, true); - - const testFileToTest = tests.testFiles.find((f) => f.name === 'test_unittest_one.py')!; - const testFile: TestsToRun = { - testFile: [testFileToTest], - testFolder: [], - testFunction: [], - testSuite: [], - }; - const results = await testManager.runTest(CommandSource.ui, testFile); - - assert.equal(results.summary.errors, 0, 'Errors'); - assert.equal(results.summary.failures, 1, 'Failures'); - assert.equal(results.summary.passed, 2, 'Passed'); - assert.equal(results.summary.skipped, 1, 'skipped'); - }); - - test(`Run Specific Test Suite [${cfg.startDirSwitch}, ${cfg.patternSwitch}]`, async () => { - await updateSetting( - 'testing.unittestArgs', - [`${cfg.startDirSwitch}=./tests`, `${cfg.patternSwitch}=test_unittest*.py`], - rootWorkspaceUri, - configTarget, - ); - - await injectTestDiscoveryOutput(`start - test_unittest_one.Test_test_one_1.test_1_1_1 - test_unittest_one.Test_test_one_1.test_1_1_2 - test_unittest_one.Test_test_one_1.test_1_1_3 - test_unittest_one.Test_test_one_2.test_1_2_1 - test_unittest_two.Test_test_two_1.test_1_1_1 - test_unittest_two.Test_test_two_1.test_1_1_2 - test_unittest_two.Test_test_two_1.test_1_1_3 - test_unittest_two.Test_test_two_2.test_2_1_1 - `); - - const resultsToSend = [ - { - outcome: 'passed', - traceback: null, - message: null, - test: 'test_unittest_one.Test_test_one_1.test_1_1_1', - }, - { - outcome: 'failed', - traceback: 'AssertionError: 1 != 2 : Not equal\n', - message: '1 != 2 : Not equal', - test: 'test_unittest_one.Test_test_one_1.test_1_1_2', - }, - { - outcome: 'skipped', - traceback: null, - message: null, - test: 'test_unittest_one.Test_test_one_1.test_1_1_3', - }, - { - outcome: 'passed', - traceback: null, - message: null, - test: 'test_unittest_one.Test_test_one_2.test_1_2_1', - }, - ]; - injectTestSocketServerResults(resultsToSend); - - const factory = ioc.serviceContainer.get(ITestManagerFactory); - const testManager = factory('unittest', rootWorkspaceUri!, unitTestSpecificTestFilesPath); - const tests = await testManager.discoverTests(CommandSource.ui, true, true); - - const testSuiteToTest = tests.testSuites.find((s) => s.testSuite.name === 'Test_test_one_1')!.testSuite; - const testSuite: TestsToRun = { - testFile: [], - testFolder: [], - testFunction: [], - testSuite: [testSuiteToTest], - }; - const results = await testManager.runTest(CommandSource.ui, testSuite); - - assert.equal(results.summary.errors, 0, 'Errors'); - assert.equal(results.summary.failures, 1, 'Failures'); - assert.equal(results.summary.passed, 2, 'Passed'); - assert.equal(results.summary.skipped, 1, 'skipped'); - }); - - test(`Run Specific Test Function [${cfg.startDirSwitch}, ${cfg.patternSwitch}]`, async () => { - await updateSetting( - 'testing.unittestArgs', - [`${cfg.startDirSwitch}=./tests`, `${cfg.patternSwitch}=test_unittest*.py`], - rootWorkspaceUri, - configTarget, - ); - - await injectTestDiscoveryOutput(`start - test_unittest_one.Test_test1.test_A - test_unittest_one.Test_test1.test_B - test_unittest_one.Test_test1.test_c - test_unittest_two.Test_test2.test_A2 - test_unittest_two.Test_test2.test_B2 - test_unittest_two.Test_test2.test_C2 - test_unittest_two.Test_test2.test_D2 - test_unittest_two.Test_test2a.test_222A2 - test_unittest_two.Test_test2a.test_222B2 - `); - - const resultsToSend = [ - { - outcome: 'failed', - traceback: 'AssertionError: Not implemented\n', - message: 'Not implemented', - test: 'test_unittest_one.Test_test1.test_A', - }, - ]; - injectTestSocketServerResults(resultsToSend); - - const factory = ioc.serviceContainer.get(ITestManagerFactory); - const testManager = factory('unittest', rootWorkspaceUri!, rootDirectory); - const tests = await testManager.discoverTests(CommandSource.ui, true, true); - const testFn: TestsToRun = { - testFile: [], - testFolder: [], - testFunction: [tests.testFunctions[0].testFunction], - testSuite: [], - }; - const results = await testManager.runTest(CommandSource.ui, testFn); - assert.equal(results.summary.errors, 0, 'Errors'); - assert.equal(results.summary.failures, 1, 'Failures'); - assert.equal(results.summary.passed, 0, 'Passed'); - assert.equal(results.summary.skipped, 0, 'skipped'); - }); - }); -}); diff --git a/src/test/testing/unittest/unittest.test.ts b/src/test/testing/unittest/unittest.test.ts deleted file mode 100644 index a740db548b34..000000000000 --- a/src/test/testing/unittest/unittest.test.ts +++ /dev/null @@ -1,260 +0,0 @@ -'use strict'; - -import * as assert from 'assert'; -import * as fs from 'fs-extra'; -import * as path from 'path'; -import { anything, instance, mock, when } from 'ts-mockito'; -import { ConfigurationTarget } from 'vscode'; -import { CommandSource, EXTENSION_ROOT_DIR } from '../../../client/common/constants'; -import { EnvironmentActivationService } from '../../../client/interpreter/activation/service'; -import { IEnvironmentActivationService } from '../../../client/interpreter/activation/types'; -import { ICondaService, IInterpreterService } from '../../../client/interpreter/contracts'; -import { InterpreterService } from '../../../client/interpreter/interpreterService'; -import { CondaService } from '../../../client/pythonEnvironments/discovery/locators/services/condaService'; -import { ITestManagerFactory, TestFile, TestFunction, Tests, TestsToRun } from '../../../client/testing/common/types'; -import { rootWorkspaceUri, updateSetting } from '../../common'; -import { UnitTestIocContainer } from '../serviceRegistry'; -import { initialize, initializeTest, IS_MULTI_ROOT_TEST } from './../../initialize'; - -const testFilesPath = path.join(EXTENSION_ROOT_DIR, 'src', 'test', 'pythonFiles', 'testFiles'); -const UNITTEST_TEST_FILES_PATH = path.join(testFilesPath, 'standard'); -const UNITTEST_SINGLE_TEST_FILE_PATH = path.join(testFilesPath, 'single'); -const UNITTEST_MULTI_TEST_FILE_PATH = path.join(testFilesPath, 'multi'); -const UNITTEST_COUNTS_TEST_FILE_PATH = path.join(testFilesPath, 'counter'); -const defaultUnitTestArgs = ['-v', '-s', '.', '-p', '*test*.py']; - -suite('Unit Tests - unittest - discovery against actual python process', () => { - let ioc: UnitTestIocContainer; - const configTarget = IS_MULTI_ROOT_TEST ? ConfigurationTarget.WorkspaceFolder : ConfigurationTarget.Workspace; - - suiteSetup(async () => { - await initialize(); - await updateSetting('testing.unittestArgs', defaultUnitTestArgs, rootWorkspaceUri!, configTarget); - }); - setup(async () => { - const cachePath = path.join(UNITTEST_TEST_FILES_PATH, '.cache'); - if (await fs.pathExists(cachePath)) { - await fs.remove(cachePath); - } - await initializeTest(); - await initializeDI(); - }); - teardown(async () => { - await ioc.dispose(); - await updateSetting('testing.unittestArgs', defaultUnitTestArgs, rootWorkspaceUri!, configTarget); - }); - - async function initializeDI() { - ioc = new UnitTestIocContainer(); - ioc.registerCommonTypes(); - ioc.registerVariableTypes(); - ioc.registerUnitTestTypes(); - ioc.registerProcessTypes(); - ioc.registerInterpreterStorageTypes(); - await ioc.registerMockInterpreterTypes(); - ioc.serviceManager.rebindInstance(ICondaService, instance(mock(CondaService))); - ioc.serviceManager.rebindInstance(IInterpreterService, instance(mock(InterpreterService))); - const mockEnvironmentActivationService = mock(EnvironmentActivationService); - when(mockEnvironmentActivationService.getActivatedEnvironmentVariables(anything())).thenResolve(); - ioc.serviceManager.rebindInstance( - IEnvironmentActivationService, - instance(mockEnvironmentActivationService), - ); - } - - test('Discover Tests (single test file)', async () => { - await updateSetting('testing.unittestArgs', ['-s=./tests', '-p=test_*.py'], rootWorkspaceUri!, configTarget); - const factory = ioc.serviceContainer.get(ITestManagerFactory); - const testManager = factory('unittest', rootWorkspaceUri!, UNITTEST_SINGLE_TEST_FILE_PATH); - const tests = await testManager.discoverTests(CommandSource.ui, true, true); - assert.equal(tests.testFiles.length, 1, 'Incorrect number of test files'); - assert.equal(tests.testFunctions.length, 3, 'Incorrect number of test functions'); - assert.equal(tests.testSuites.length, 1, 'Incorrect number of test suites'); - assert.equal( - tests.testFiles.some((t) => t.name === 'test_one.py' && t.nameToRun === 'test_one'), - true, - 'Test File not found', - ); - assert.equal( - tests.testFunctions.some( - (t) => t.testFunction.name === 'test_A' && t.testFunction.nameToRun === 'test_one.Test_test1.test_A', - ), - true, - 'Test File not found', - ); - }); - - test('Discover Tests (many test files, subdir included)', async () => { - await updateSetting('testing.unittestArgs', ['-s=./tests', '-p=test_*.py'], rootWorkspaceUri!, configTarget); - const factory = ioc.serviceContainer.get(ITestManagerFactory); - const testManager = factory('unittest', rootWorkspaceUri!, UNITTEST_MULTI_TEST_FILE_PATH); - const tests = await testManager.discoverTests(CommandSource.ui, true, true); - assert.equal(tests.testFiles.length, 3, 'Incorrect number of test files'); - assert.equal(tests.testFunctions.length, 9, 'Incorrect number of test functions'); - assert.equal(tests.testSuites.length, 3, 'Incorrect number of test suites'); - assert.equal( - tests.testFiles.some((t) => t.name === 'test_one.py' && t.nameToRun === 'test_one'), - true, - 'Test File one not found', - ); - assert.equal( - tests.testFiles.some((t) => t.name === 'test_two.py' && t.nameToRun === 'test_two'), - true, - 'Test File two not found', - ); - assert.equal( - tests.testFiles.some((t) => t.name === 'test_three.py' && t.nameToRun === 'more_tests.test_three'), - true, - 'Test File three not found', - ); - assert.equal( - tests.testFunctions.some( - (t) => t.testFunction.name === 'test_A' && t.testFunction.nameToRun === 'test_one.Test_test1.test_A', - ), - true, - 'Test File one not found', - ); - assert.equal( - tests.testFunctions.some( - (t) => t.testFunction.name === 'test_2A' && t.testFunction.nameToRun === 'test_two.Test_test2.test_2A', - ), - true, - 'Test File two not found', - ); - assert.equal( - tests.testFunctions.some( - (t) => - t.testFunction.name === 'test_3A' && - t.testFunction.nameToRun === 'more_tests.test_three.Test_test3.test_3A', - ), - true, - 'Test File three not found', - ); - }); - - test('Run single test', async () => { - await updateSetting('testing.unittestArgs', ['-s=./tests', '-p=test_*.py'], rootWorkspaceUri!, configTarget); - const factory = ioc.serviceContainer.get(ITestManagerFactory); - const testManager = factory('unittest', rootWorkspaceUri!, UNITTEST_MULTI_TEST_FILE_PATH); - const testsDiscovered: Tests = await testManager.discoverTests(CommandSource.ui, true, true); - const testFile: TestFile | undefined = testsDiscovered.testFiles.find((value: TestFile) => - value.nameToRun.endsWith('_three'), - ); - assert.notEqual(testFile, undefined, 'No test file suffixed with _3A in test files.'); - assert.equal(testFile!.suites.length, 1, 'Expected only 1 test suite in test file three.'); - const testFunc: TestFunction | undefined = testFile!.suites[0].functions.find( - (value: TestFunction) => value.name === 'test_3A', - ); - assert.notEqual(testFunc, undefined, 'No test in file test_three.py named test_3A'); - const testsToRun: TestsToRun = { - testFunction: [testFunc!], - }; - const testRunResult: Tests = await testManager.runTest(CommandSource.ui, testsToRun); - assert.equal( - testRunResult.summary.failures + testRunResult.summary.passed + testRunResult.summary.skipped, - 1, - 'Expected to see only 1 test run in the summary for tests run.', - ); - assert.equal(testRunResult.summary.errors, 0, 'Unexpected: Test file ran with errors.'); - assert.equal(testRunResult.summary.failures, 0, 'Unexpected: Test has failed during test run.'); - assert.equal( - testRunResult.summary.passed, - 1, - `Only one test should have passed during our test run. Instead, ${testRunResult.summary.passed} passed.`, - ); - assert.equal( - testRunResult.summary.skipped, - 0, - `Expected to have skipped 0 tests during this test-run. Instead, ${testRunResult.summary.skipped} where skipped.`, - ); - }); - - test('Ensure correct test count for running a set of tests multiple times', async function () { - // https://github.com/microsoft/vscode-python/issues/11634 - - return this.skip(); - await updateSetting('testing.unittestArgs', ['-s=./tests', '-p=test_*.py'], rootWorkspaceUri!, configTarget); - const factory = ioc.serviceContainer.get(ITestManagerFactory); - const testManager = factory('unittest', rootWorkspaceUri!, UNITTEST_COUNTS_TEST_FILE_PATH); - const testsDiscovered: Tests = await testManager.discoverTests(CommandSource.ui, true, true); - const testsFile: TestFile | undefined = testsDiscovered.testFiles.find((value: TestFile) => - value.name.startsWith('test_unit_test_counter'), - ); - assert.notEqual( - testsFile, - undefined, - `No test file suffixed with _counter in test files. Looked in ${UNITTEST_COUNTS_TEST_FILE_PATH}.`, - ); - assert.equal(testsFile!.suites.length, 1, 'Expected only 1 test suite in counter test file.'); - const testsToRun: TestsToRun = { - testFolder: [testsDiscovered.testFolders[0]], - }; - - // ensure that each re-run of the unit tests in question result in the same summary count information. - let testRunResult: Tests = await testManager.runTest(CommandSource.ui, testsToRun); - assert.equal( - testRunResult.summary.failures, - 2, - 'This test was written assuming there was 2 tests run that would fail. (iteration 1)', - ); - assert.equal( - testRunResult.summary.passed, - 2, - 'This test was written assuming there was 2 tests run that would succeed. (iteration 1)', - ); - - testRunResult = await testManager.runTest(CommandSource.ui, testsToRun); - assert.equal( - testRunResult.summary.failures, - 2, - 'This test was written assuming there was 2 tests run that would fail. (iteration 2)', - ); - assert.equal( - testRunResult.summary.passed, - 2, - 'This test was written assuming there was 2 tests run that would succeed. (iteration 2)', - ); - }); - - test('Re-run failed tests results in the correct number of tests counted', async function () { - // https://github.com/microsoft/vscode-python/issues/11634 - - return this.skip(); - await updateSetting('testing.unittestArgs', ['-s=./tests', '-p=test_*.py'], rootWorkspaceUri!, configTarget); - const factory = ioc.serviceContainer.get(ITestManagerFactory); - const testManager = factory('unittest', rootWorkspaceUri!, UNITTEST_COUNTS_TEST_FILE_PATH); - const testsDiscovered: Tests = await testManager.discoverTests(CommandSource.ui, true, true); - const testsFile: TestFile | undefined = testsDiscovered.testFiles.find((value: TestFile) => - value.name.startsWith('test_unit_test_counter'), - ); - assert.notEqual( - testsFile, - undefined, - `No test file suffixed with _counter in test files. Looked in ${UNITTEST_COUNTS_TEST_FILE_PATH}.`, - ); - assert.equal(testsFile!.suites.length, 1, 'Expected only 1 test suite in counter test file.'); - const testsToRun: TestsToRun = { - testFolder: [testsDiscovered.testFolders[0]], - }; - - // ensure that each re-run of the unit tests in question result in the same summary count information. - let testRunResult: Tests = await testManager.runTest(CommandSource.ui, testsToRun); - assert.equal( - testRunResult.summary.failures, - 2, - 'This test was written assuming there was 2 tests run that would fail. (iteration 1)', - ); - assert.equal( - testRunResult.summary.passed, - 2, - 'This test was written assuming there was 2 tests run that would succeed. (iteration 1)', - ); - - testRunResult = await testManager.runTest(CommandSource.ui, testsToRun, true); - assert.equal( - testRunResult.summary.failures, - 2, - 'This test was written assuming there was 2 tests run that would fail. (iteration 2)', - ); - }); -}); diff --git a/src/test/testing/unittest/unittest.unit.test.ts b/src/test/testing/unittest/unittest.unit.test.ts deleted file mode 100644 index c35011bb3ce8..000000000000 --- a/src/test/testing/unittest/unittest.unit.test.ts +++ /dev/null @@ -1,220 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import * as assert from 'assert'; -import { anything, capture, instance, mock, when } from 'ts-mockito'; -import { Uri } from 'vscode'; -import { IWorkspaceService } from '../../../client/common/application/types'; -import { WorkspaceService } from '../../../client/common/application/workspace'; -import { ConfigurationService } from '../../../client/common/configuration/service'; -import { CommandSource } from '../../../client/common/constants'; -import { - IConfigurationService, - IDisposableRegistry, - IOutputChannel, - IPythonSettings, -} from '../../../client/common/types'; -import { ServiceContainer } from '../../../client/ioc/container'; -import { IServiceContainer } from '../../../client/ioc/types'; -import { ArgumentsHelper } from '../../../client/testing/common/argumentsHelper'; -import { TestCollectionStorageService } from '../../../client/testing/common/services/storageService'; -import { TestResultsService } from '../../../client/testing/common/services/testResultsService'; -import { TestsStatusUpdaterService } from '../../../client/testing/common/services/testsStatusService'; -import { TestsHelper } from '../../../client/testing/common/testUtils'; -import { TestResultResetVisitor } from '../../../client/testing/common/testVisitors/resultResetVisitor'; -import { - IArgumentsHelper, - IArgumentsService, - FlattenedTestFunction, - FlattenedTestSuite, - ITestManagerRunner, - ITestResultsService, - ITestsHelper, - ITestsStatusUpdaterService, - TestDataItemType, - TestFile, - TestFolder, - TestFunction, - Tests, - TestStatus, - TestSuite, -} from '../../../client/testing/common/types'; -import { TestManager } from '../../../client/testing/unittest/main'; -import { TestManagerRunner } from '../../../client/testing/unittest/runner'; -import { ArgumentsService } from '../../../client/testing/unittest/services/argsService'; -import { MockOutputChannel } from '../../mockClasses'; -import { createMockTestDataItem } from '../common/testUtils.unit.test'; - -suite('Unit Tests - unittest - run failed tests', () => { - let testManager: TestManager; - const workspaceFolder = Uri.file(__dirname); - let serviceContainer: IServiceContainer; - let testsHelper: ITestsHelper; - let testManagerRunner: ITestManagerRunner; - let tests: Tests; - function createTestData() { - const folder1 = createMockTestDataItem(TestDataItemType.folder); - const folder2 = createMockTestDataItem(TestDataItemType.folder); - const folder3 = createMockTestDataItem(TestDataItemType.folder); - const folder4 = createMockTestDataItem(TestDataItemType.folder); - const folder5 = createMockTestDataItem(TestDataItemType.folder); - folder1.folders.push(folder2); - folder1.folders.push(folder3); - folder2.folders.push(folder4); - folder3.folders.push(folder5); - - const file1 = createMockTestDataItem(TestDataItemType.file); - const file2 = createMockTestDataItem(TestDataItemType.file); - const file3 = createMockTestDataItem(TestDataItemType.file); - const file4 = createMockTestDataItem(TestDataItemType.file); - folder1.testFiles.push(file1); - folder3.testFiles.push(file2); - folder3.testFiles.push(file3); - folder5.testFiles.push(file4); - - const suite1 = createMockTestDataItem(TestDataItemType.suite); - const suite2 = createMockTestDataItem(TestDataItemType.suite); - const suite3 = createMockTestDataItem(TestDataItemType.suite); - const suite4 = createMockTestDataItem(TestDataItemType.suite); - const suite5 = createMockTestDataItem(TestDataItemType.suite); - const fn1 = createMockTestDataItem(TestDataItemType.function); - const fn2 = createMockTestDataItem(TestDataItemType.function); - const fn3 = createMockTestDataItem(TestDataItemType.function); - const fn4 = createMockTestDataItem(TestDataItemType.function); - const fn5 = createMockTestDataItem(TestDataItemType.function); - file1.suites.push(suite1); - file1.suites.push(suite2); - file3.suites.push(suite3); - suite3.suites.push(suite4); - suite4.suites.push(suite5); - file1.functions.push(fn1); - file1.functions.push(fn2); - suite1.functions.push(fn3); - suite1.functions.push(fn4); - suite3.functions.push(fn5); - const flattendSuite1: FlattenedTestSuite = { - testSuite: suite1, - xmlClassName: suite1.xmlName, - } as any; - const flattendSuite2: FlattenedTestSuite = { - testSuite: suite2, - xmlClassName: suite2.xmlName, - } as any; - const flattendSuite3: FlattenedTestSuite = { - testSuite: suite3, - xmlClassName: suite3.xmlName, - } as any; - const flattendSuite4: FlattenedTestSuite = { - testSuite: suite4, - xmlClassName: suite4.xmlName, - } as any; - const flattendSuite5: FlattenedTestSuite = { - testSuite: suite5, - xmlClassName: suite5.xmlName, - } as any; - const flattendFn1: FlattenedTestFunction = { - testFunction: fn1, - xmlClassName: fn1.name, - } as any; - const flattendFn2: FlattenedTestFunction = { - testFunction: fn2, - xmlClassName: fn2.name, - } as any; - const flattendFn3: FlattenedTestFunction = { - testFunction: fn3, - xmlClassName: fn3.name, - } as any; - const flattendFn4: FlattenedTestFunction = { - testFunction: fn4, - xmlClassName: fn4.name, - } as any; - const flattendFn5: FlattenedTestFunction = { - testFunction: fn5, - xmlClassName: fn5.name, - } as any; - tests = { - rootTestFolders: [folder1], - summary: { errors: 0, skipped: 0, passed: 0, failures: 0 }, - testFiles: [file1, file2, file3, file4], - testFolders: [folder1, folder2, folder3, folder4, folder5], - testFunctions: [flattendFn1, flattendFn2, flattendFn3, flattendFn4, flattendFn5], - testSuites: [flattendSuite1, flattendSuite2, flattendSuite3, flattendSuite4, flattendSuite5], - }; - } - setup(() => { - createTestData(); - serviceContainer = mock(ServiceContainer); - testsHelper = mock(TestsHelper); - testManagerRunner = mock(TestManagerRunner); - const testStorage = mock(TestCollectionStorageService); - const workspaceService = mock(WorkspaceService); - const svcInstance = instance(serviceContainer); - when(testStorage.getTests(anything())).thenReturn(tests); - when(workspaceService.getWorkspaceFolder(anything())).thenReturn({ name: '', index: 0, uri: workspaceFolder }); - when(serviceContainer.get(IWorkspaceService)).thenReturn(instance(workspaceService)); - when(serviceContainer.get(IArgumentsHelper)).thenReturn(new ArgumentsHelper()); - when(serviceContainer.get(IArgumentsService, anything())).thenReturn( - new ArgumentsService(svcInstance), - ); - when(serviceContainer.get(ITestsHelper)).thenReturn(instance(testsHelper)); - when(serviceContainer.get(ITestManagerRunner, anything())).thenReturn( - instance(testManagerRunner), - ); - when(serviceContainer.get(ITestsStatusUpdaterService)).thenReturn( - new TestsStatusUpdaterService(instance(testStorage)), - ); - when(serviceContainer.get(ITestResultsService)).thenReturn( - new TestResultsService(new TestResultResetVisitor()), - ); - when(serviceContainer.get(IOutputChannel)).thenReturn(instance(mock(MockOutputChannel))); - when(serviceContainer.get(IOutputChannel)).thenReturn(instance(mock(MockOutputChannel))); - when(serviceContainer.get(IDisposableRegistry)).thenReturn([]); - const settingsService = mock(ConfigurationService); - const settings: IPythonSettings = { - testing: { - unittestArgs: [], - }, - } as any; - when(settingsService.getSettings(anything())).thenReturn(settings); - when(serviceContainer.get(IConfigurationService)).thenReturn(instance(settingsService)); - - testManager = new TestManager(workspaceFolder, workspaceFolder.fsPath, svcInstance); - }); - - test('Run Failed tests', async () => { - testManager.discoverTests = () => Promise.resolve(tests); - when(testsHelper.shouldRunAllTests(anything())).thenReturn(false); - when(testManagerRunner.runTest(anything(), anything(), anything())).thenResolve(undefined as any); - (testManager as any).tests = tests; - tests.testFunctions[0].testFunction.status = TestStatus.Fail; - tests.testFunctions[2].testFunction.status = TestStatus.Fail; - - await testManager.runTest(CommandSource.testExplorer, undefined, true); - - const options = capture(testManagerRunner.runTest).last()[1]; - assert.deepEqual(options.tests, tests); - assert.equal(options.testsToRun!.testFile!.length, 0); - assert.equal(options.testsToRun!.testFolder!.length, 0); - assert.equal(options.testsToRun!.testSuite!.length, 0); - assert.equal(options.testsToRun!.testFunction!.length, 2); - assert.deepEqual(options.testsToRun!.testFunction![0], tests.testFunctions[0].testFunction); - assert.deepEqual(options.testsToRun!.testFunction![1], tests.testFunctions[2].testFunction); - }); - test('Run All tests', async () => { - testManager.discoverTests = () => Promise.resolve(tests); - when(testsHelper.shouldRunAllTests(anything())).thenReturn(false); - when(testManagerRunner.runTest(anything(), anything(), anything())).thenResolve(undefined as any); - (testManager as any).tests = tests; - - await testManager.runTest(CommandSource.testExplorer, undefined, true); - - const options = capture(testManagerRunner.runTest).last()[1]; - assert.deepEqual(options.tests, tests); - assert.equal(options.testsToRun!.testFile!.length, 0); - assert.equal(options.testsToRun!.testFolder!.length, 0); - assert.equal(options.testsToRun!.testSuite!.length, 0); - assert.equal(options.testsToRun!.testFunction!.length, 0); - }); -}); From a43f469c299b53a833c8fd50bf72147b45180923 Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Thu, 22 Jul 2021 22:05:34 -0700 Subject: [PATCH 12/39] Use new Test UI API from VS Code --- .eslintignore | 101 +-- src/client/common/application/commands.ts | 1 + src/client/common/constants.ts | 1 + .../process/internal/scripts/testing_tools.ts | 46 +- .../{unittest => common}/socketServer.ts | 15 +- src/client/testing/common/types.ts | 7 +- src/client/testing/main.ts | 56 +- src/client/testing/serviceRegistry.ts | 5 +- .../testController/common/argumentsHelper.ts | 102 +++ .../testController/common/discoveryHelper.ts | 42 ++ .../common/externalDependencies.ts | 20 + .../testController/common/resultsHelper.ts | 164 ++++ .../common/testItemUtilities.ts | 510 +++++++++++++ .../testController/common/testWorkspace.ts | 0 .../testing/testController/common/types.ts | 104 +++ .../testing/testController/controller.ts | 137 +++- .../testController/pytest/arguments.ts | 282 +++++++ .../testController/pytest/pytestController.ts | 258 +++++++ .../testing/testController/pytest/runner.ts | 142 ++++ .../testing/testController/serviceRegistry.ts | 27 + .../testController/unittest/arguments.ts | 87 +++ .../testing/testController/unittest/runner.ts | 223 ++++++ .../unittest/unittestController.ts | 329 +++++++++ types/vscode.proposed.d.ts | 699 +++++++++--------- 24 files changed, 2795 insertions(+), 563 deletions(-) rename src/client/testing/{unittest => common}/socketServer.ts (97%) create mode 100644 src/client/testing/testController/common/argumentsHelper.ts create mode 100644 src/client/testing/testController/common/discoveryHelper.ts create mode 100644 src/client/testing/testController/common/externalDependencies.ts create mode 100644 src/client/testing/testController/common/resultsHelper.ts create mode 100644 src/client/testing/testController/common/testItemUtilities.ts create mode 100644 src/client/testing/testController/common/testWorkspace.ts create mode 100644 src/client/testing/testController/common/types.ts create mode 100644 src/client/testing/testController/pytest/arguments.ts create mode 100644 src/client/testing/testController/pytest/pytestController.ts create mode 100644 src/client/testing/testController/pytest/runner.ts create mode 100644 src/client/testing/testController/serviceRegistry.ts create mode 100644 src/client/testing/testController/unittest/arguments.ts create mode 100644 src/client/testing/testController/unittest/runner.ts create mode 100644 src/client/testing/testController/unittest/unittestController.ts diff --git a/.eslintignore b/.eslintignore index fdad96bd2456..b0418a03f670 100644 --- a/.eslintignore +++ b/.eslintignore @@ -86,57 +86,22 @@ src/test/activation/extensionSurvey.unit.test.ts src/test/utils/fs.ts -src/test/language/braceCounter.unit.test.ts src/test/language/textRangeCollection.unit.test.ts src/test/language/characterStream.unit.test.ts src/test/language/languageConfiguration.unit.test.ts src/test/language/textIterator.unit.test.ts -src/test/language/textBuilder.unit.test.ts src/test/language/textRange.unit.test.ts src/test/language/tokenizer.unit.test.ts src/test/api.functional.test.ts -src/test/testing/argsService.test.ts src/test/testing/mocks.ts -src/test/testing/debugger.test.ts -src/test/testing/unittest/unittest.test.ts -src/test/testing/unittest/unittest.discovery.unit.test.ts -src/test/testing/unittest/unittest.discovery.test.ts -src/test/testing/unittest/unittest.run.test.ts -src/test/testing/unittest/unittest.unit.test.ts -src/test/testing/codeLenses/testFiles.unit.test.ts -src/test/testing/rediscover.test.ts src/test/testing/helper.ts -src/test/testing/navigation/fileNavigator.unit.test.ts -src/test/testing/navigation/functionNavigator.unit.test.ts -src/test/testing/navigation/suiteNavigator.unit.test.ts -src/test/testing/navigation/commandHandlers.unit.test.ts -src/test/testing/navigation/helper.unit.test.ts -src/test/testing/navigation/symbolNavigator.unit.test.ts -src/test/testing/explorer/treeView.unit.test.ts -src/test/testing/explorer/testExplorerCommandHandler.unit.test.ts -src/test/testing/explorer/failedTestHandler.unit.test.ts -src/test/testing/explorer/testTreeViewProvider.unit.test.ts -src/test/testing/explorer/explorerTestData.ts -src/test/testing/stoppingDiscoverAndTest.test.ts -src/test/testing/banners/proposeNewLanguageServerBanner.unit.test.ts -src/test/testing/common/argsHelper.unit.test.ts -src/test/testing/common/trackEnablement.unit.test.ts src/test/testing/common/debugLauncher.unit.test.ts src/test/testing/common/testUtils.unit.test.ts -src/test/testing/common/testVisitors/resultResetVisitor.unit.test.ts -src/test/testing/common/services/discoveredTestParser.unit.test.ts src/test/testing/common/services/storageService.unit.test.ts -src/test/testing/common/services/testStatusService.unit.test.ts -src/test/testing/common/services/testResultsService.unit.test.ts -src/test/testing/common/services/discovery.unit.test.ts src/test/testing/common/services/configSettingService.unit.test.ts -src/test/testing/common/services/contextService.unit.test.ts src/test/testing/results.ts -src/test/testing/display/picker.functional.test.ts -src/test/testing/display/main.unit.test.ts -src/test/testing/display/picker.unit.test.ts src/test/common/exitCIAfterTestReporter.ts src/test/common/crypto.unit.test.ts @@ -152,7 +117,6 @@ src/test/common/terminals/shellDetectors/shellDetectors.unit.test.ts src/test/common/terminals/environmentActivationProviders/terminalActivation.testvirtualenvs.ts src/test/common/socketStream.test.ts src/test/common/configSettings.test.ts -src/test/common/experiments/manager.unit.test.ts src/test/common/experiments/telemetry.unit.test.ts src/test/common/platform/filesystem.unit.test.ts src/test/common/platform/errors.unit.test.ts @@ -166,7 +130,6 @@ src/test/common/utils/decorators.unit.test.ts src/test/common/utils/localize.functional.test.ts src/test/common/utils/version.unit.test.ts src/test/common/configSettings/configSettings.unit.test.ts -src/test/common/featureDeprecationManager.unit.test.ts src/test/common/serviceRegistry.unit.test.ts src/test/common/extensions.unit.test.ts src/test/common/variables/envVarsService.unit.test.ts @@ -181,16 +144,13 @@ src/test/common/installer/productPath.unit.test.ts src/test/common/installer/extensionBuildInstaller.unit.test.ts src/test/common/socketCallbackHandler.test.ts src/test/common/process/decoder.test.ts -src/test/common/process/pythonDaemonPool.unit.test.ts src/test/common/process/processFactory.unit.test.ts src/test/common/process/pythonToolService.unit.test.ts src/test/common/process/proc.observable.test.ts src/test/common/process/pythonProc.simple.multiroot.test.ts src/test/common/process/execFactory.test.ts src/test/common/process/logger.unit.test.ts -src/test/common/process/pythonDaemonPool.functional.test.ts src/test/common/process/proc.exec.test.ts -src/test/common/process/pythonDaemon.functional.test.ts src/test/common/process/pythonProcess.unit.test.ts src/test/common/process/proc.unit.test.ts src/test/common/asyncDump.ts @@ -226,7 +186,6 @@ src/test/debugger/common/protocolparser.test.ts src/test/debugger/envVars.test.ts src/test/telemetry/index.unit.test.ts -src/test/telemetry/importTracker.unit.test.ts src/test/telemetry/envFileTelemetry.unit.test.ts src/test/linters/pylint.unit.test.ts @@ -339,12 +298,9 @@ src/client/activation/refCountedLanguageServer.ts src/client/activation/jedi.ts src/client/activation/languageClientMiddleware.ts src/client/activation/node/manager.ts -src/client/activation/node/cancellationUtils.ts src/client/activation/node/languageServerProxy.ts src/client/activation/node/languageClientFactory.ts -src/client/activation/node/languageServerPackageRepository.ts src/client/activation/node/languageServerFolderService.ts -src/client/activation/node/languageServerPackageService.ts src/client/activation/node/analysisOptions.ts src/client/activation/node/activator.ts src/client/activation/none/activator.ts @@ -361,58 +317,18 @@ src/client/language/characterStream.ts src/client/language/textIterator.ts src/client/language/types.ts src/client/language/iterableTextRange.ts -src/client/language/braceCounter.ts src/client/language/unicode.ts -src/client/language/textBuilder.ts src/client/testing/serviceRegistry.ts -src/client/testing/unittest/main.ts -src/client/testing/unittest/helper.ts src/client/testing/unittest/testConfigurationManager.ts -src/client/testing/unittest/socketServer.ts -src/client/testing/unittest/runner.ts -src/client/testing/unittest/services/parserService.ts -src/client/testing/unittest/services/argsService.ts -src/client/testing/unittest/services/discoveryService.ts -src/client/testing/codeLenses/main.ts -src/client/testing/codeLenses/testFiles.ts src/client/testing/main.ts src/client/testing/configurationFactory.ts -src/client/testing/navigation/serviceRegistry.ts -src/client/testing/navigation/symbolProvider.ts -src/client/testing/navigation/helper.ts -src/client/testing/navigation/commandHandler.ts -src/client/testing/navigation/suiteNavigator.ts -src/client/testing/navigation/functionNavigator.ts -src/client/testing/navigation/fileNavigator.ts -src/client/testing/explorer/testTreeViewItem.ts -src/client/testing/explorer/testTreeViewProvider.ts -src/client/testing/explorer/commandHandlers.ts -src/client/testing/explorer/failedTestHandler.ts -src/client/testing/explorer/treeView.ts -src/client/testing/common/argumentsHelper.ts -src/client/testing/common/enablementTracker.ts src/client/testing/common/debugLauncher.ts src/client/testing/common/constants.ts src/client/testing/common/testUtils.ts -src/client/testing/common/xUnitParser.ts src/client/testing/common/updateTestSettings.ts -src/client/testing/common/testVisitors/flatteningVisitor.ts -src/client/testing/common/testVisitors/resultResetVisitor.ts +src/client/testing/common/socketServer.ts src/client/testing/common/runner.ts -src/client/testing/common/services/discoveredTestParser.ts -src/client/testing/common/services/contextService.ts -src/client/testing/common/services/testResultsService.ts -src/client/testing/common/services/storageService.ts -src/client/testing/common/services/types.ts -src/client/testing/common/services/testsStatusService.ts -src/client/testing/common/services/discovery.ts -src/client/testing/common/services/configSettingService.ts -src/client/testing/common/services/testManagerService.ts -src/client/testing/common/services/workspaceTestManagerService.ts -src/client/testing/display/main.ts -src/client/testing/display/picker.ts -src/client/testing/configuration.ts src/client/common/helpers.ts src/client/common/net/browser.ts @@ -425,11 +341,7 @@ src/client/common/asyncDisposableRegistry.ts src/client/common/editor.ts src/client/common/contextKey.ts src/client/common/markdown/restTextConverter.ts -src/client/common/featureDeprecationManager.ts -src/client/common/experiments/manager.ts src/client/common/experiments/telemetry.ts -src/client/common/refBool.ts -src/client/common/open.ts src/client/common/platform/serviceRegistry.ts src/client/common/platform/errors.ts src/client/common/platform/fs-temp.ts @@ -460,10 +372,8 @@ src/client/common/utils/enum.ts src/client/common/utils/platform.ts src/client/common/utils/stopWatch.ts src/client/common/utils/random.ts -src/client/common/utils/serializers.ts src/client/common/utils/sysTypes.ts src/client/common/utils/misc.ts -src/client/common/utils/logging.ts src/client/common/utils/cacheUtils.ts src/client/common/utils/workerPool.ts src/client/common/extensions.ts @@ -477,7 +387,6 @@ src/client/common/logger.ts src/client/common/variables/serviceRegistry.ts src/client/common/variables/environment.ts src/client/common/variables/types.ts -src/client/common/variables/sysTypes.ts src/client/common/variables/systemVariables.ts src/client/common/nuget/azureBlobStoreNugetRepository.ts src/client/common/nuget/nugetRepository.ts @@ -486,7 +395,6 @@ src/client/common/nuget/nugetService.ts src/client/common/cancellation.ts src/client/common/interpreterPathService.ts src/client/common/startPage/startPageMessageListener.ts -src/client/common/application/customEditorService.ts src/client/common/application/applicationShell.ts src/client/common/application/languageService.ts src/client/common/application/notebook.ts @@ -495,8 +403,6 @@ src/client/common/application/workspace.ts src/client/common/application/debugSessionTelemetry.ts src/client/common/application/extensions.ts src/client/common/application/documentManager.ts -src/client/common/application/webPanels/webPanelProvider.ts -src/client/common/application/webPanels/webPanel.ts src/client/common/application/debugService.ts src/client/common/application/commands/reloadCommand.ts src/client/common/application/terminalManager.ts @@ -514,15 +420,11 @@ src/client/common/installer/productPath.ts src/client/common/process/currentProcess.ts src/client/common/process/processFactory.ts src/client/common/process/serviceRegistry.ts -src/client/common/process/pythonDaemon.ts src/client/common/process/pythonToolService.ts src/client/common/process/internal/python.ts src/client/common/process/internal/scripts/testing_tools.ts -src/client/common/process/pythonDaemonPool.ts -src/client/common/process/pythonDaemonFactory.ts src/client/common/process/types.ts src/client/common/process/logger.ts -src/client/common/process/baseDaemon.ts src/client/common/process/pythonProcess.ts src/client/common/process/pythonEnvironment.ts src/client/common/process/decoder.ts @@ -566,7 +468,6 @@ src/client/debugger/extension/attachQuickPick/picker.ts src/client/debugger/extension/helpers/protocolParser.ts src/client/languageServices/jediProxyFactory.ts -src/client/languageServices/proposeLanguageServerBanner.ts src/client/linters/pydocstyle.ts src/client/linters/serviceRegistry.ts diff --git a/src/client/common/application/commands.ts b/src/client/common/application/commands.ts index cae54bef51d9..a19cbad0bfb7 100644 --- a/src/client/common/application/commands.ts +++ b/src/client/common/application/commands.ts @@ -91,5 +91,6 @@ export interface ICommandNameArgumentTypeMapping extends ICommandNameWithoutArgu [Commands.Exec_In_Terminal]: [undefined, Uri]; [Commands.Exec_In_Terminal_Icon]: [undefined, Uri]; [Commands.Tests_Configure]: [undefined, undefined | CommandSource, undefined | Uri]; + [Commands.Test_Refresh]: [undefined, undefined | CommandSource, undefined | Uri]; [Commands.LaunchTensorBoard]: [TensorBoardEntrypoint, TensorBoardEntrypointTrigger]; } diff --git a/src/client/common/constants.ts b/src/client/common/constants.ts index 5b00d4de5918..1b44b27bd406 100644 --- a/src/client/common/constants.ts +++ b/src/client/common/constants.ts @@ -38,6 +38,7 @@ export namespace Commands { export const Exec_Selection_In_Terminal = 'python.execSelectionInTerminal'; export const Exec_Selection_In_Django_Shell = 'python.execSelectionInDjangoShell'; export const Tests_Configure = 'python.configureTests'; + export const Test_Refresh = 'python.refreshTests'; export const Sort_Imports = 'python.sortImports'; export const ViewOutput = 'python.viewOutput'; export const Refactor_Extract_Variable = 'python.refactorExtractVariable'; diff --git a/src/client/common/process/internal/scripts/testing_tools.ts b/src/client/common/process/internal/scripts/testing_tools.ts index ef22517fed60..f496147a120b 100644 --- a/src/client/common/process/internal/scripts/testing_tools.ts +++ b/src/client/common/process/internal/scripts/testing_tools.ts @@ -9,52 +9,10 @@ const SCRIPTS_DIR = path.join(_SCRIPTS_DIR, 'testing_tools'); //============================ // run_adapter.py -type TestNode = { - id: string; - name: string; - parentid: string; -}; -type TestParent = TestNode & { - kind: 'folder' | 'file' | 'suite' | 'function'; -}; -type TestFSNode = TestParent & { - kind: 'folder' | 'file'; - relpath: string; -}; - -export type TestFolder = TestFSNode & { - kind: 'folder'; -}; -export type TestFile = TestFSNode & { - kind: 'file'; -}; -export type TestSuite = TestParent & { - kind: 'suite'; -}; -// function-as-a-container is for parameterized ("sub") tests. -export type TestFunction = TestParent & { - kind: 'function'; -}; -export type Test = TestNode & { - source: string; -}; -export type DiscoveredTests = { - rootid: string; - root: string; - parents: TestParent[]; - tests: Test[]; -}; - -export function run_adapter(adapterArgs: string[]): [string[], (out: string) => DiscoveredTests[]] { +export function runAdapter(adapterArgs: string[]): string[] { const script = path.join(SCRIPTS_DIR, 'run_adapter.py'); // Note that we for now we do not run this "isolated". The // script relies on some magic that conflicts with the // isolated script. - const args = [script, ...adapterArgs]; - - function parse(out: string): DiscoveredTests[] { - return JSON.parse(out); - } - - return [args, parse]; + return [script, ...adapterArgs]; } diff --git a/src/client/testing/unittest/socketServer.ts b/src/client/testing/common/socketServer.ts similarity index 97% rename from src/client/testing/unittest/socketServer.ts rename to src/client/testing/common/socketServer.ts index 372dd0e188e7..f1cdc9f1f763 100644 --- a/src/client/testing/unittest/socketServer.ts +++ b/src/client/testing/common/socketServer.ts @@ -1,33 +1,42 @@ 'use strict'; + import { EventEmitter } from 'events'; import { injectable } from 'inversify'; import * as net from 'net'; import { createDeferred, Deferred } from '../../common/utils/async'; -import { IUnitTestSocketServer } from '../common/types'; +import { IUnitTestSocketServer } from './types'; const MaxConnections = 100; @injectable() export class UnitTestSocketServer extends EventEmitter implements IUnitTestSocketServer { private server?: net.Server; + private startedDef?: Deferred; + private sockets: net.Socket[] = []; - private ipcBuffer: string = ''; + + private ipcBuffer = ''; + constructor() { super(); } + public get clientsConnected(): boolean { return this.sockets.length > 0; } + public dispose() { this.stop(); } + public stop() { if (this.server) { this.server!.close(); this.server = undefined; } } + public start({ port, host }: { port: number; host: string } = { port: 0, host: 'localhost' }): Promise { this.ipcBuffer = ''; this.startedDef = createDeferred(); @@ -97,9 +106,11 @@ export class UnitTestSocketServer extends EventEmitter implements IUnitTestSocke }); this.emit('connect', socket); } + private log(message: string, ...data: any[]) { this.emit('log', message, ...data); } + private onCloseSocket() { for (let i = 0, count = this.sockets.length; i < count; i += 1) { const socket = this.sockets[i]; diff --git a/src/client/testing/common/types.ts b/src/client/testing/common/types.ts index 8bd58a1727fc..98eed7e0e8ab 100644 --- a/src/client/testing/common/types.ts +++ b/src/client/testing/common/types.ts @@ -23,9 +23,9 @@ export type TestDiscoveryOptions = { workspaceFolder: Uri; cwd: string; args: string[]; - token: CancellationToken; + token?: CancellationToken; ignoreCache: boolean; - outChannel: OutputChannel; + outChannel?: OutputChannel; }; export type TestRunOptions = { @@ -56,7 +56,7 @@ export type Options = { cwd: string; args: string[]; outChannel?: OutputChannel; - token: CancellationToken; + token?: CancellationToken; }; export type TestsToRun = { @@ -317,7 +317,6 @@ export interface ITestDebugLauncher { launchDebugger(options: LaunchOptions): Promise; } - export const ITestDiscoveryService = Symbol('ITestDiscoveryService'); export interface ITestDiscoveryService { discoverTests(options: TestDiscoveryOptions): Promise; diff --git a/src/client/testing/main.ts b/src/client/testing/main.ts index 8f0e4c7f20c6..5f970cde5dcd 100644 --- a/src/client/testing/main.ts +++ b/src/client/testing/main.ts @@ -1,12 +1,7 @@ 'use strict'; import { inject, injectable } from 'inversify'; -import { - ConfigurationChangeEvent, - Disposable, - test, - Uri, -} from 'vscode'; +import { ConfigurationChangeEvent, Disposable, Uri } from 'vscode'; import { IApplicationShell, ICommandManager, IWorkspaceService } from '../common/application/types'; import * as constants from '../common/constants'; import '../common/extensions'; @@ -17,13 +12,10 @@ import { EventName } from '../telemetry/constants'; import { captureTelemetry } from '../telemetry/index'; import { selectTestWorkspace } from './common/testUtils'; import { TestSettingsPropertyNames } from './configuration/types'; -import { - ITestConfigurationService, - ITestsHelper, -} from './common/types'; +import { ITestConfigurationService, ITestsHelper } from './common/types'; import { ITestingService } from './types'; -import { PythonTestController } from './testController/controller'; import { IExtensionActivationService } from '../activation/types'; +import { ITestController } from './testController/common/types'; @injectable() export class TestingService implements ITestingService { @@ -40,11 +32,13 @@ export class UnitTestManagementService implements IExtensionActivationService, D private activatedOnce: boolean = false; private readonly disposableRegistry: Disposable[]; private workspaceService: IWorkspaceService; + private testController: ITestController; private configChangedTimer?: NodeJS.Timer | number; constructor(@inject(IServiceContainer) private serviceContainer: IServiceContainer) { this.disposableRegistry = serviceContainer.get(IDisposableRegistry); this.workspaceService = serviceContainer.get(IWorkspaceService); + this.testController = serviceContainer.get(ITestController); this.disposableRegistry.push(this); } public dispose() { @@ -62,29 +56,15 @@ export class UnitTestManagementService implements IExtensionActivationService, D this.registerHandlers(); this.registerCommands(); - - if (test && test.registerTestController) { - this.disposableRegistry.push(test.registerTestController(new PythonTestController())); - } } public async configurationChangeHandler(eventArgs: ConfigurationChangeEvent) { - // If there's one workspace, then stop the tests and restart, - // else let the user do this manually. - if (!this.workspaceService.hasWorkspaceFolders || this.workspaceService.workspaceFolders!.length > 1) { - return; - } - if (!Array.isArray(this.workspaceService.workspaceFolders)) { - return; - } - const workspaceFolderUri = this.workspaceService.workspaceFolders.find((w) => - eventArgs.affectsConfiguration('python.testing', w.uri), - ); - if (!workspaceFolderUri) { - return; - } + const workspaces = this.workspaceService.workspaceFolders ?? []; + const changedWorkspaces: Uri[] = workspaces + .filter((w) => eventArgs.affectsConfiguration('python.testing', w.uri)) + .map((w) => w.uri); - // TODO: refresh test data + await Promise.all(changedWorkspaces.map((u) => this.testController.refreshTestData(u))); } @captureTelemetry(EventName.UNITTEST_CONFIGURE, undefined, false) @@ -116,7 +96,13 @@ export class UnitTestManagementService implements IExtensionActivationService, D // Ignore the exceptions returned. // This command will be invoked from other places of the extension. this.configureTests(resource).ignoreErrors(); - // TODO: refresh test data + this.testController.refreshTestData(resource); + }, + ), + commandManager.registerCommand( + constants.Commands.Test_Refresh, + (_, _cmdSource: constants.CommandSource = constants.CommandSource.commandPalette, resource?: Uri) => { + this.testController.refreshTestData(resource); }, ), ]; @@ -135,11 +121,9 @@ export class UnitTestManagementService implements IExtensionActivationService, D }), ); this.disposableRegistry.push( - interpreterService.onDidChangeInterpreter(() => - { - // TODO: Refresh test data - } - ), + interpreterService.onDidChangeInterpreter(() => { + this.testController.refreshTestData(); + }), ); } } diff --git a/src/client/testing/serviceRegistry.ts b/src/client/testing/serviceRegistry.ts index 9c7449055b90..c525d4c58abf 100644 --- a/src/client/testing/serviceRegistry.ts +++ b/src/client/testing/serviceRegistry.ts @@ -21,7 +21,8 @@ import { UnitTestConfigurationService } from './configuration'; import { TestConfigurationManagerFactory } from './configurationFactory'; import { TestingService, UnitTestManagementService } from './main'; import { ITestingService } from './types'; -import { UnitTestSocketServer } from './unittest/socketServer'; +import { UnitTestSocketServer } from './common/socketServer'; +import { registerTestControllerTypes } from './testController/serviceRegistry'; export function registerTypes(serviceManager: IServiceManager) { serviceManager.addSingleton(ITestDebugLauncher, DebugLauncher); @@ -41,4 +42,6 @@ export function registerTypes(serviceManager: IServiceManager) { ); serviceManager.addSingleton(IExtensionActivationService, UpdateTestSettingService); serviceManager.addSingleton(IExtensionActivationService, UnitTestManagementService); + + registerTestControllerTypes(serviceManager); } diff --git a/src/client/testing/testController/common/argumentsHelper.ts b/src/client/testing/testController/common/argumentsHelper.ts new file mode 100644 index 000000000000..69e27b915896 --- /dev/null +++ b/src/client/testing/testController/common/argumentsHelper.ts @@ -0,0 +1,102 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { traceWarning } from '../../../common/logger'; + +export function getOptionValues(args: string[], option: string): string[] { + const values: string[] = []; + let returnNextValue = false; + for (const arg of args) { + if (returnNextValue) { + values.push(arg); + returnNextValue = false; + } else if (arg.startsWith(`${option}=`)) { + values.push(arg.substring(`${option}=`.length)); + } else if (arg === option) { + returnNextValue = true; + } + } + return values; +} + +export function getPositionalArguments( + args: string[], + optionsWithArguments: string[] = [], + optionsWithoutArguments: string[] = [], +): string[] { + const nonPositionalIndexes: number[] = []; + args.forEach((arg, index) => { + if (optionsWithoutArguments.indexOf(arg) !== -1) { + nonPositionalIndexes.push(index); + } else if (optionsWithArguments.indexOf(arg) !== -1) { + nonPositionalIndexes.push(index); + // Cuz the next item is the value. + nonPositionalIndexes.push(index + 1); + } else if (optionsWithArguments.findIndex((item) => arg.startsWith(`${item}=`)) !== -1) { + nonPositionalIndexes.push(index); + } else if (arg.startsWith('-')) { + // Ok this is an unknown option, lets treat this as one without values. + traceWarning( + `Unknown command line option passed into args parser for tests '${arg}'. Please report on https://github.com/Microsoft/vscode-python/issues/new`, + ); + nonPositionalIndexes.push(index); + } else if (arg.indexOf('=') > 0) { + // Ok this is an unknown option with a value + traceWarning( + `Unknown command line option passed into args parser for tests '${arg}'. Please report on https://github.com/Microsoft/vscode-python/issues/new`, + ); + nonPositionalIndexes.push(index); + } + }); + return args.filter((_, index) => nonPositionalIndexes.indexOf(index) === -1); +} + +export function filterArguments( + args: string[], + optionsWithArguments: string[] = [], + optionsWithoutArguments: string[] = [], +): string[] { + let ignoreIndex = -1; + return args.filter((arg, index) => { + if (ignoreIndex === index) { + return false; + } + // Options can use wild cards (with trailing '*') + if ( + optionsWithoutArguments.indexOf(arg) >= 0 || + optionsWithoutArguments.filter((option) => option.endsWith('*') && arg.startsWith(option.slice(0, -1))) + .length > 0 + ) { + return false; + } + // Ignore args that match exactly. + if (optionsWithArguments.indexOf(arg) >= 0) { + ignoreIndex = index + 1; + return false; + } + // Ignore args that match exactly with wild cards & do not have inline values. + if (optionsWithArguments.filter((option) => arg.startsWith(`${option}=`)).length > 0) { + return false; + } + // Ignore args that match a wild card (ending with *) and no inline values. + // Eg. arg='--log-cli-level' and optionsArguments=['--log-*'] + if ( + arg.indexOf('=') === -1 && + optionsWithoutArguments.filter((option) => option.endsWith('*') && arg.startsWith(option.slice(0, -1))) + .length > 0 + ) { + ignoreIndex = index + 1; + return false; + } + // Ignore args that match a wild card (ending with *) and have inline values. + // Eg. arg='--log-cli-level=XYZ' and optionsArguments=['--log-*'] + if ( + arg.indexOf('=') >= 0 && + optionsWithoutArguments.filter((option) => option.endsWith('*') && arg.startsWith(option.slice(0, -1))) + .length > 0 + ) { + return false; + } + return true; + }); +} diff --git a/src/client/testing/testController/common/discoveryHelper.ts b/src/client/testing/testController/common/discoveryHelper.ts new file mode 100644 index 000000000000..310b3e95c7ec --- /dev/null +++ b/src/client/testing/testController/common/discoveryHelper.ts @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { inject, injectable } from 'inversify'; +import { + ExecutionFactoryCreateWithEnvironmentOptions, + IPythonExecutionFactory, + SpawnOptions, +} from '../../../common/process/types'; +import { TestDiscoveryOptions } from '../../common/types'; +import { ITestDiscoveryHelper, RawDiscoveredTests } from './types'; + +@injectable() +export class TestDiscoveryHelper implements ITestDiscoveryHelper { + constructor(@inject(IPythonExecutionFactory) private readonly pythonExecFactory: IPythonExecutionFactory) {} + + public async runTestDiscovery(options: TestDiscoveryOptions): Promise { + const creationOptions: ExecutionFactoryCreateWithEnvironmentOptions = { + allowEnvironmentFetchExceptions: false, + resource: options.workspaceFolder, + }; + const execService = await this.pythonExecFactory.createActivatedEnvironment(creationOptions); + + const spawnOptions: SpawnOptions = { + token: options.token, + cwd: options.cwd, + throwOnStdErr: true, + }; + + if (options.outChannel) { + options.outChannel.appendLine(`python ${options.args.join(' ')}`); + } + + const proc = await execService.exec(options.args, spawnOptions); + try { + return JSON.parse(proc.stdout); + } catch (ex) { + ex.stdout = proc.stdout; + throw ex; // re-throw + } + } +} diff --git a/src/client/testing/testController/common/externalDependencies.ts b/src/client/testing/testController/common/externalDependencies.ts new file mode 100644 index 000000000000..db7bc9448d27 --- /dev/null +++ b/src/client/testing/testController/common/externalDependencies.ts @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import * as tmp from 'tmp'; +import { TemporaryFile } from '../../../common/platform/types'; + +export function createTemporaryFile(ext = '.tmp'): Promise { + return new Promise((resolve, reject) => { + tmp.file({ postfix: ext }, (err, filename, _fd, cleanUp): void => { + if (err) { + reject(err); + } else { + resolve({ + filePath: filename, + dispose: cleanUp, + }); + } + }); + }); +} diff --git a/src/client/testing/testController/common/resultsHelper.ts b/src/client/testing/testController/common/resultsHelper.ts new file mode 100644 index 000000000000..957840c5962e --- /dev/null +++ b/src/client/testing/testController/common/resultsHelper.ts @@ -0,0 +1,164 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import * as fsapi from 'fs-extra'; +import { Location, TestItem, TestMessage, TestRun } from 'vscode'; +import { getTestCaseNodes } from './testItemUtilities'; +import { TestData } from './types'; + +type TestSuiteResult = { + $: { + errors: string; + failures: string; + name: string; + skips: string; + skip: string; + tests: string; + time: string; + }; + testcase: TestCaseResult[]; +}; +type TestCaseResult = { + $: { + classname: string; + file: string; + line: string; + name: string; + time: string; + }; + failure: { + _: string; + $: { message: string; type: string }; + }[]; + error: { + _: string; + $: { message: string; type: string }; + }[]; + skipped: { + _: string; + $: { message: string; type: string }; + }[]; +}; + +async function parseXML(data: string): Promise { + const xml2js = await import('xml2js'); + + return new Promise((resolve, reject) => { + xml2js.parseString(data, (error: Error, result: unknown) => { + if (error) { + return reject(error); + } + return resolve(result); + }); + }); +} + +function getJunitResults(parserResult: unknown): TestSuiteResult | undefined { + // This is the newer JUnit XML format (e.g. pytest 5.1 and later). + const fullResults = parserResult as { testsuites: { testsuite: TestSuiteResult[] } }; + if (!fullResults.testsuites) { + return (parserResult as { testsuite: TestSuiteResult }).testsuite; + } + + const junitSuites = fullResults.testsuites.testsuite; + if (!Array.isArray(junitSuites)) { + throw Error('bad JUnit XML data'); + } + if (junitSuites.length === 0) { + return undefined; + } + if (junitSuites.length > 1) { + throw Error('got multiple XML results'); + } + return junitSuites[0]; +} + +export async function updateResultFromJunitXml( + outputXmlFile: string, + testNode: TestItem, + runInstance: TestRun, + idToRawData: Map, +): Promise { + const data = await fsapi.readFile(outputXmlFile); + const parserResult = await parseXML(data.toString('utf8')); + const junitSuite = getJunitResults(parserResult); + const testCaseNodes = getTestCaseNodes(testNode); + + if (junitSuite && junitSuite.testcase.length > 0 && testCaseNodes.length > 0) { + let failures = 0; + let skipped = 0; + let errors = 0; + let passed = 0; + + testCaseNodes.forEach((node) => { + const rawTestCaseNode = idToRawData.get(node.id); + if (!rawTestCaseNode) { + return; + } + + const result = junitSuite.testcase.find((t) => { + const idResult = `${t.$.classname}.${t.$.name}`; + const idNode = rawTestCaseNode.runId; + return idResult === idNode || idNode.endsWith(idResult); + }); + if (result) { + if (result.error) { + errors += 1; + const error = result.error[0]; + const text = `${rawTestCaseNode.rawId} Failed with Error: [${error.$.type}]${error.$.message}\r\n${error._}\r\n\r\n`; + const message = new TestMessage(text); + + if (node.uri && node.range) { + message.location = new Location(node.uri, node.range); + } + + runInstance.failed(node, message); + runInstance.appendOutput(text); + } else if (result.failure) { + failures += 1; + const failure = result.failure[0]; + const text = `${rawTestCaseNode.rawId} Failed: [${failure.$.type}]${failure.$.message}\r\n${failure._}\r\n`; + const message = new TestMessage(text); + + if (node.uri && node.range) { + message.location = new Location(node.uri, node.range); + } + + runInstance.failed(node, message); + runInstance.appendOutput(text); + } else if (result.skipped) { + skipped += 1; + const skip = result.skipped[0]; + const text = `${rawTestCaseNode.rawId} Skipped: [${skip.$.type}]${skip.$.message}\r\n`; + + runInstance.skipped(node); + runInstance.appendOutput(text); + } else { + passed += 1; + const text = `${rawTestCaseNode.rawId} Passed\r\n`; + runInstance.passed(node); + runInstance.appendOutput(text); + } + } else { + const text = `Test result not found for: ${rawTestCaseNode.rawId}\r\n`; + runInstance.appendOutput(text); + const message = new TestMessage(text); + + if (node.uri && node.range) { + message.location = new Location(node.uri, node.range); + } + runInstance.failed(node, message); + } + }); + + runInstance.appendOutput(`Total number of tests passed: ${passed}\r\n`); + runInstance.appendOutput(`Total number of tests failed: ${failures}\r\n`); + runInstance.appendOutput(`Total number of tests failed with errors: ${errors}\r\n`); + runInstance.appendOutput(`Total number of tests skipped: ${skipped}\r\n`); + runInstance.appendOutput( + `Total number of tests with no result data: ${ + testCaseNodes.length - passed - failures - errors - skipped + }\r\n`, + ); + } +} diff --git a/src/client/testing/testController/common/testItemUtilities.ts b/src/client/testing/testController/common/testItemUtilities.ts new file mode 100644 index 000000000000..24c20937238d --- /dev/null +++ b/src/client/testing/testController/common/testItemUtilities.ts @@ -0,0 +1,510 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import * as path from 'path'; +import { TestItem, Uri, Range, Position, TestController } from 'vscode'; +import { traceError, traceVerbose } from '../../../common/logger'; +import { + RawDiscoveredTests, + RawTest, + RawTestFile, + RawTestFolder, + RawTestFunction, + RawTestSuite, + TestData, + TestDataKinds, +} from './types'; + +export function removeItemByIdFromChildren( + idToRawData: Map, + item: TestItem, + childNodeIdsToRemove: string[], +): void { + childNodeIdsToRemove.forEach((id) => { + item.children.delete(id); + idToRawData.delete(id); + }); +} + +export function createWorkspaceRootTestItem( + testController: TestController, + idToRawData: Map, + options: { id: string; label: string; uri: Uri; runId: string; parentId?: string; rawId?: string }, +): TestItem { + const testItem = testController.createTestItem(options.id, options.label, options.uri); + testItem.description = options.uri.fsPath; + testItem.canResolveChildren = true; + idToRawData.set(options.id, { + ...options, + rawId: options.rawId ?? options.id, + kind: TestDataKinds.Workspace, + }); + return testItem; +} + +function getParentIdFromRawParentId( + idToRawData: Map, + testRoot: string, + raw: { parentid: string }, +): string | undefined { + const parent = idToRawData.get(path.join(testRoot, raw.parentid)); + let parentId; + if (parent) { + parentId = parent.id === '.' ? testRoot : parent.id; + } + return parentId; +} + +function getRangeFromRawSource(raw: { source: string }): Range | undefined { + // We have to extract the line number from the source data. If it is available it + // saves us from running symbol script or querying language server for this info. + try { + const sourceLine = raw.source.substr(raw.source.indexOf(':') + 1); + const line = Number.parseInt(sourceLine, 10); + // Lines in raw data start at 1, vscode lines start at 0 + return new Range(new Position(line - 1, 0), new Position(line, 0)); + } catch (ex) { + // ignore + } + return undefined; +} + +function getRunIdFromRawData(raw: { id: string }): string { + // This is the id that will be used to compare with the results. + const runId = raw.id + .replace(/[\\\:\/]/g, '.') + .replace(/\:\:/g, '.') + .replace(/\.\./g, '.') + .replace(/\.py/g, ''); + return runId.startsWith('.') ? runId.substr(1) : runId; +} + +function createFolderOrFileTestItem( + testController: TestController, + idToRawData: Map, + testRoot: string, + rawData: RawTestFolder | RawTestFile, +): TestItem { + const fullPath = path.join(testRoot, rawData.relpath); + const uri = Uri.file(fullPath); + + const parentId = getParentIdFromRawParentId(idToRawData, testRoot, rawData); + + const label = path.basename(fullPath); + const testItem = testController.createTestItem(fullPath, label, uri); + + testItem.description = fullPath; + testItem.canResolveChildren = true; + + idToRawData.set(testItem.id, { + id: testItem.id, + rawId: rawData.id, + runId: rawData.relpath, + uri, + kind: TestDataKinds.FolderOrFile, + parentId, + }); + return testItem; +} + +function updateFolderOrFileTestItem( + item: TestItem, + idToRawData: Map, + testRoot: string, + rawData: RawTestFolder | RawTestFile, +): void { + const fullPath = path.join(testRoot, rawData.relpath); + const uri = Uri.file(fullPath); + + const parentId = getParentIdFromRawParentId(idToRawData, testRoot, rawData); + + item.label = path.basename(fullPath); + + item.description = fullPath; + item.canResolveChildren = true; + + idToRawData.set(item.id, { + id: item.id, + rawId: rawData.id, + runId: rawData.relpath, + uri, + kind: TestDataKinds.FolderOrFile, + parentId, + }); +} + +function createCollectionTestItem( + testController: TestController, + idToRawData: Map, + testRoot: string, + rawData: RawTestSuite | RawTestFunction, +): TestItem { + // id can look like test_something.py::SomeClass + const id = path.join(testRoot, rawData.id); + + // We need the actual document path so we can set the location for the tests. This will be + // used to provide test result status next to the tests. + const documentPath = path.join(testRoot, rawData.id.substr(0, rawData.id.indexOf(':'))); + const uri = Uri.file(documentPath); + + const label = rawData.name; + + const parentId = getParentIdFromRawParentId(idToRawData, testRoot, rawData); + const runId = getRunIdFromRawData(rawData); + + const testItem = testController.createTestItem(id, label, uri); + + testItem.description = id; + testItem.canResolveChildren = true; + + idToRawData.set(testItem.id, { + id: testItem.id, + rawId: rawData.id, + runId, + uri, + kind: TestDataKinds.Collection, + parentId, + }); + return testItem; +} + +function updateCollectionTestItem( + item: TestItem, + idToRawData: Map, + testRoot: string, + rawData: RawTestSuite | RawTestFunction, +): void { + // id can look like test_something.py::SomeClass + const id = path.join(testRoot, rawData.id); + + // We need the actual document path so we can set the location for the tests. This will be + // used to provide test result status next to the tests. + const documentPath = path.join(testRoot, rawData.id.substr(0, rawData.id.indexOf(':'))); + const uri = Uri.file(documentPath); + + item.label = rawData.name; + + const parentId = getParentIdFromRawParentId(idToRawData, testRoot, rawData); + const runId = getRunIdFromRawData(rawData); + + item.description = id; + item.canResolveChildren = true; + + idToRawData.set(item.id, { + id: item.id, + rawId: rawData.id, + runId, + uri, + kind: TestDataKinds.Collection, + parentId, + }); +} + +function createTestCaseItem( + testController: TestController, + idToRawData: Map, + testRoot: string, + rawData: RawTest, +): TestItem { + // id can look like: + // test_something.py::SomeClass::someTest + // test_something.py::SomeClass::someTest[x1] + const id = path.join(testRoot, rawData.id); + + // We need the actual document path so we can set the location for the tests. This will be + // used to provide test result status next to the tests. + const documentPath = path.join(testRoot, rawData.source.substr(0, rawData.source.indexOf(':'))); + const uri = Uri.file(documentPath); + + const label = rawData.name; + + const parentId = getParentIdFromRawParentId(idToRawData, testRoot, rawData); + const runId = getRunIdFromRawData(rawData); + + const testItem = testController.createTestItem(id, label, uri); + + testItem.description = id; + testItem.canResolveChildren = false; + testItem.range = getRangeFromRawSource(rawData); + + idToRawData.set(testItem.id, { + id: testItem.id, + rawId: rawData.id, + runId, + uri, + kind: TestDataKinds.Case, + parentId, + }); + return testItem; +} + +function updateTestCaseItem( + item: TestItem, + idToRawData: Map, + testRoot: string, + rawData: RawTest, +): void { + // id can look like: + // test_something.py::SomeClass::someTest + // test_something.py::SomeClass::someTest[x1] + const id = path.join(testRoot, rawData.id); + + // We need the actual document path so we can set the location for the tests. This will be + // used to provide test result status next to the tests. + const documentPath = path.join(testRoot, rawData.source.substr(0, rawData.source.indexOf(':'))); + const uri = Uri.file(documentPath); + + item.label = rawData.name; + + const parentId = getParentIdFromRawParentId(idToRawData, testRoot, rawData); + const runId = getRunIdFromRawData(rawData); + + item.description = id; + item.canResolveChildren = false; + item.range = getRangeFromRawSource(rawData); + + idToRawData.set(item.id, { + id: item.id, + rawId: rawData.id, + runId, + uri, + kind: TestDataKinds.Case, + parentId, + }); +} + +function updateTestItemFromRawDataInternal( + item: TestItem, + testController: TestController, + idToRawData: Map, + testRoot: string, + rawDataSet: RawDiscoveredTests[], +): void { + const rawId = idToRawData.get(item.id)?.rawId; + if (!rawId) { + traceError(`Unknown node id: ${item.id}`); + return; + } + + const nodeRawData = rawDataSet.filter( + (r) => + r.root === rawId || + r.rootid === rawId || + r.parents.find((p) => p.id === rawId) || + r.tests.find((t) => t.id === rawId), + ); + + if (nodeRawData.length === 0 && item.parent) { + removeItemByIdFromChildren(idToRawData, item.parent, [item.id]); + traceVerbose(`Following test item was removed Reason: No-Raw-Data ${item.id}`); + return; + } + + if (nodeRawData.length > 1) { + // Something is wrong, there can only be one test node with that id + traceError(`Multiple (${nodeRawData.length}) raw data nodes had the same id: ${rawId}`); + return; + } + + if (rawId === nodeRawData[0].root || rawId === nodeRawData[0].rootid) { + // This is a test root node, we need to update the entire tree + // The update children and remove any child that does not have raw data. + item.children.forEach((c) => updateTestItemFromRawData(c, testController, idToRawData, testRoot, nodeRawData)); + + // Create child nodes that are new. + // We only need to look at rawData.parents. Since at this level we either have folder or file. + const rawChildNodes = nodeRawData[0].parents.filter((p) => p.parentid === '.' || p.parentid === rawId); + const existingNodes: string[] = []; + item.children.forEach((c) => existingNodes.push(idToRawData.get(c.id)?.rawId ?? '')); + + rawChildNodes + .filter((r) => !existingNodes.includes(r.id)) + .forEach((r) => { + const childItem = + r.kind === 'file' + ? createFolderOrFileTestItem(testController, idToRawData, testRoot, r as RawTestFile) + : createFolderOrFileTestItem(testController, idToRawData, testRoot, r as RawTestFolder); + item.children.add(childItem); + updateTestItemFromRawData(childItem, testController, idToRawData, testRoot, nodeRawData); + }); + + return; + } + + // First check if this is a parent node + const rawData = nodeRawData[0].parents.filter((r) => r.id === rawId); + if (rawData.length === 1) { + // This is either a File/Folder/Collection node + + // Update the node data + switch (rawData[0].kind) { + case 'file': + updateFolderOrFileTestItem(item, idToRawData, testRoot, rawData[0] as RawTestFile); + break; + case 'folder': + updateFolderOrFileTestItem(item, idToRawData, testRoot, rawData[0] as RawTestFolder); + break; + case 'suite': + updateCollectionTestItem(item, idToRawData, testRoot, rawData[0] as RawTestSuite); + break; + case 'function': + updateCollectionTestItem(item, idToRawData, testRoot, rawData[0] as RawTestFunction); + break; + default: + break; + } + + // The update children and remove any child that does not have raw data. + item.children.forEach((c) => updateTestItemFromRawData(c, testController, idToRawData, testRoot, nodeRawData)); + + // Create child nodes that are new. + // Get the existing child node ids so we can skip them + const existingNodes: string[] = []; + item.children.forEach((c) => existingNodes.push(idToRawData.get(c.id)?.rawId ?? '')); + + // We first look at rawData.parents. Since at this level we either have folder or file. + // The current node is potentially a parent of one of these "parent" nodes or it is a parent + // of test case nodes. We will handle Test case nodes after handling parents. + const rawChildNodes = nodeRawData[0].parents.filter((p) => p.parentid === rawId); + rawChildNodes + .filter((r) => !existingNodes.includes(r.id)) + .forEach((r) => { + let childItem; + switch (r.kind) { + case 'file': + childItem = createFolderOrFileTestItem(testController, idToRawData, testRoot, r as RawTestFile); + break; + case 'folder': + childItem = createFolderOrFileTestItem( + testController, + idToRawData, + testRoot, + r as RawTestFolder, + ); + break; + case 'suite': + childItem = createCollectionTestItem(testController, idToRawData, testRoot, r as RawTestSuite); + break; + case 'function': + childItem = createCollectionTestItem( + testController, + idToRawData, + testRoot, + r as RawTestFunction, + ); + break; + default: + break; + } + if (childItem) { + item.children.add(childItem); + // This node can potentially have children. So treat it like a new node and update it. + updateTestItemFromRawData(childItem, testController, idToRawData, testRoot, nodeRawData); + } + }); + + // Now we will look at test case nodes. Create any test case node that does not already exist. + const rawTestCaseNodes = nodeRawData[0].tests.filter((p) => p.parentid === rawId); + rawTestCaseNodes + .filter((r) => !existingNodes.includes(r.id)) + .forEach((r) => { + const childItem = createTestCaseItem(testController, idToRawData, testRoot, r as RawTest); + item.children.add(childItem); + }); + + return; + } + + if (rawData.length > 1) { + // Something is wrong, there can only be one test node with that id + traceError(`Multiple (${rawData.length}) raw data nodes had the same id: ${rawId}`); + return; + } + + // We are here this means rawData.length === 0 + // The node is probably is test case node. Try and find it. + const rawCaseData = nodeRawData[0].tests.filter((r) => r.id === rawId); + + if (rawCaseData.length === 1) { + // This is a test case node + updateTestCaseItem(item, idToRawData, testRoot, rawCaseData[0] as RawTest); + return; + } + + if (rawCaseData.length > 1) { + // Something is wrong, there can only be one test node with that id + traceError(`Multiple (${rawCaseData.length}) raw data nodes had the same id: ${rawId}`); + } +} + +export function updateTestItemFromRawData( + item: TestItem, + testController: TestController, + idToRawData: Map, + testRoot: string, + rawDataSet: RawDiscoveredTests[], +): void { + item.busy = true; + updateTestItemFromRawDataInternal(item, testController, idToRawData, testRoot, rawDataSet); + item.busy = false; +} + +export function getUri(node: TestItem): Uri | undefined { + if (!node.uri && node.parent) { + return getUri(node.parent); + } + return node.uri; +} + +export function getTestCaseNodes(testNode: TestItem, collection: TestItem[] = []): TestItem[] { + if (!testNode.canResolveChildren) { + collection.push(testNode); + } + + testNode.children.forEach((c) => { + if (testNode.canResolveChildren) { + getTestCaseNodes(c, collection); + } else { + collection.push(testNode); + } + }); + return collection; +} + +export function getWorkspaceNode(testNode: TestItem, idToRawData: Map): TestItem | undefined { + const raw = idToRawData.get(testNode.id); + if (raw) { + if (raw.kind === TestDataKinds.Workspace) { + return testNode; + } + if (testNode.parent) { + return getWorkspaceNode(testNode.parent, idToRawData); + } + } + return undefined; +} + +export function getNodeByUri(root: TestItem, uri: Uri): TestItem | undefined { + if (root.uri?.fsPath === uri.fsPath) { + return root; + } + + const nodes: TestItem[] = []; + root.children.forEach((c) => nodes.push(c)); + + // Search at the current level + for (const node of nodes) { + if (node.uri?.fsPath === uri.fsPath) { + return node; + } + } + + // Search the children of the current level + for (const node of nodes) { + const found = getNodeByUri(node, uri); + if (found) { + return found; + } + } + return undefined; +} diff --git a/src/client/testing/testController/common/testWorkspace.ts b/src/client/testing/testController/common/testWorkspace.ts new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/client/testing/testController/common/types.ts b/src/client/testing/testController/common/types.ts new file mode 100644 index 000000000000..4d46a612f956 --- /dev/null +++ b/src/client/testing/testController/common/types.ts @@ -0,0 +1,104 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { CancellationToken, TestController, TestItem, TestRunRequest, Uri, WorkspaceFolder } from 'vscode'; +import { TestDiscoveryOptions } from '../../common/types'; + +export type TestRunInstanceOptions = TestRunOptions & { + exclude?: TestItem[]; + debug: boolean; +}; + +export enum TestDataKinds { + Workspace, + FolderOrFile, + Collection, + Case, +} + +export interface TestData { + rawId: string; + runId: string; + id: string; + uri: Uri; + parentId?: string; + kind: TestDataKinds; +} + +export const ITestDiscoveryHelper = Symbol('ITestDiscoveryHelper'); +export interface ITestDiscoveryHelper { + runTestDiscovery(options: TestDiscoveryOptions): Promise; +} + +export const ITestController = Symbol('ITestController'); +export interface ITestController { + refreshTestData(resource?: Uri): Promise; +} + +export const ITestFrameworkController = Symbol('ITestFrameworkController'); +export interface ITestFrameworkController { + resolveChildren(testController: TestController, item: TestItem): Promise; + refreshTestData(testController: TestController, resource?: Uri): Promise; + runTests( + testController: TestController, + request: TestRunRequest, + debug: boolean, + workspace: WorkspaceFolder, + token: CancellationToken, + ): Promise; +} + +export const ITestsRunner = Symbol('ITestsRunner'); +export interface ITestsRunner { + runTests( + testController: TestController, + request: TestRunRequest, + debug: boolean, + options: TestRunOptions, + idToRawData: Map, + ): Promise; +} + +export type TestRunOptions = { + workspaceFolder: Uri; + cwd: string; + args: string[]; + token: CancellationToken; +}; + +// We expose these here as a convenience and to cut down on churn +// elsewhere in the code. +type RawTestNode = { + id: string; + name: string; + parentid: string; +}; +export type RawTestParent = RawTestNode & { + kind: 'folder' | 'file' | 'suite' | 'function' | 'workspace'; +}; +type RawTestFSNode = RawTestParent & { + kind: 'folder' | 'file'; + relpath: string; +}; +export type RawTestFolder = RawTestFSNode & { + kind: 'folder'; +}; +export type RawTestFile = RawTestFSNode & { + kind: 'file'; +}; +export type RawTestSuite = RawTestParent & { + kind: 'suite'; +}; +// function-as-a-container is for parameterized ("sub") tests. +export type RawTestFunction = RawTestParent & { + kind: 'function'; +}; +export type RawTest = RawTestNode & { + source: string; +}; +export type RawDiscoveredTests = { + rootid: string; + root: string; + parents: RawTestParent[]; + tests: RawTest[]; +}; diff --git a/src/client/testing/testController/controller.ts b/src/client/testing/testController/controller.ts index 97f45a90a1a9..69597f4c7e64 100644 --- a/src/client/testing/testController/controller.ts +++ b/src/client/testing/testController/controller.ts @@ -1,18 +1,137 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import { TestController } from 'vscode'; -/* eslint-disable */ +import { inject, injectable, named } from 'inversify'; +import { uniq } from 'lodash'; +import { + CancellationToken, + TestController, + TestItem, + TestRunRequest, + tests, + Disposable, + WorkspaceFolder, + RelativePattern, + TestRunProfileKind, +} from 'vscode'; +import { IWorkspaceService } from '../../common/application/types'; +import { IConfigurationService, Resource } from '../../common/types'; +import { PYTEST_PROVIDER, UNITTEST_PROVIDER } from '../common/constants'; +import { ITestController, ITestFrameworkController } from './common/types'; -// This is a place holder for a controller -export class PythonTestController implements TestController { - public createWorkspaceTestRoot() { - return undefined; +@injectable() +export class PythonTestController implements ITestController, Disposable { + private readonly testController: TestController; + + private readonly disposables: Disposable[] = []; + + constructor( + @inject(IWorkspaceService) private readonly workspaceService: IWorkspaceService, + @inject(IConfigurationService) private readonly configSettings: IConfigurationService, + @inject(ITestFrameworkController) @named(PYTEST_PROVIDER) private readonly pytest: ITestFrameworkController, + @inject(ITestFrameworkController) @named(UNITTEST_PROVIDER) private readonly unittest: ITestFrameworkController, + ) { + this.testController = tests.createTestController('python-tests', 'Python Tests'); + this.disposables.push(this.testController); + + this.disposables.push( + this.testController.createRunProfile('Run Tests', TestRunProfileKind.Run, this.runTests.bind(this), true), + this.testController.createRunProfile( + 'Debug Tests', + TestRunProfileKind.Debug, + this.runTests.bind(this), + true, + ), + ); + this.testController.resolveHandler = this.resolveChildren.bind(this); + } + + public dispose(): void { + this.disposables.forEach((d) => d.dispose()); + } + + public async refreshTestData(uri?: Resource): Promise { + const settings = this.configSettings.getSettings(uri); + if (settings.testing.pytestEnabled) { + return this.pytest.refreshTestData(this.testController, uri); + } + if (settings.testing.unittestEnabled) { + return this.unittest.refreshTestData(this.testController, uri); + } + return Promise.resolve(); + } + + private async resolveChildren(item: TestItem | undefined): Promise { + if (item) { + const settings = this.configSettings.getSettings(item.uri); + if (settings.testing.pytestEnabled) { + return this.pytest.resolveChildren(this.testController, item); + } + if (settings.testing.unittestEnabled) { + return this.unittest.resolveChildren(this.testController, item); + } + } else { + this.watchForTestChanges(); + const workspaces: readonly WorkspaceFolder[] = this.workspaceService.workspaceFolders || []; + await Promise.all(workspaces.map((workspace) => this.refreshTestData(workspace.uri))); + } + return Promise.resolve(); + } + + private async runTests(request: TestRunRequest, token: CancellationToken): Promise { + const workspaces: WorkspaceFolder[] = []; + if (request.include) { + uniq(request.include.map((r) => this.workspaceService.getWorkspaceFolder(r.uri))).forEach((w) => { + if (w) { + workspaces.push(w); + } + }); + } else { + (this.workspaceService.workspaceFolders || []).forEach((w) => workspaces.push(w)); + } + const debug = request.profile?.kind === TestRunProfileKind.Debug; + await Promise.all( + workspaces.map((workspace) => { + const settings = this.configSettings.getSettings(workspace.uri); + if (settings.testing.pytestEnabled) { + return this.pytest.runTests(this.testController, request, debug, workspace, token); + } + if (settings.testing.unittestEnabled) { + return this.unittest.runTests(this.testController, request, debug, workspace, token); + } + return Promise.resolve(); + }), + ); + } + + private watchForTestChanges(): void { + const workspaces: readonly WorkspaceFolder[] = this.workspaceService.workspaceFolders || []; + for (const workspace of workspaces) { + const settings = this.configSettings.getSettings(workspace.uri); + if (settings.testing.autoTestDiscoverOnSaveEnabled) { + this.watchForSettingsChanges(workspace); + this.watchForTestContentChanges(workspace); + } + } } - public createDocumentTestRoot() { - return undefined; + private watchForSettingsChanges(workspace: WorkspaceFolder): void { + const pattern = new RelativePattern(workspace, '**/{settings.json,pytest.ini,pyproject.toml,setup.cfg}'); + const watcher = this.workspaceService.createFileSystemWatcher(pattern); + this.disposables.push(watcher); + + watcher.onDidChange((uri) => this.refreshTestData(uri)); + watcher.onDidCreate((uri) => this.refreshTestData(uri)); + watcher.onDidDelete((uri) => this.refreshTestData(uri)); } - public runTests() {} + private watchForTestContentChanges(workspace: WorkspaceFolder): void { + const pattern = new RelativePattern(workspace, '**/*test*.py'); + const watcher = this.workspaceService.createFileSystemWatcher(pattern); + this.disposables.push(watcher); + + watcher.onDidChange((uri) => this.refreshTestData(uri)); + watcher.onDidCreate((uri) => this.refreshTestData(uri)); + watcher.onDidDelete((uri) => this.refreshTestData(uri)); + } } diff --git a/src/client/testing/testController/pytest/arguments.ts b/src/client/testing/testController/pytest/arguments.ts new file mode 100644 index 000000000000..3474df8fc6c9 --- /dev/null +++ b/src/client/testing/testController/pytest/arguments.ts @@ -0,0 +1,282 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { TestDiscoveryOptions, TestFilter } from '../../common/types'; +import { getOptionValues, getPositionalArguments, filterArguments } from '../common/argumentsHelper'; + +const OptionsWithArguments = [ + '-c', + '-k', + '-m', + '-o', + '-p', + '-r', + '-W', + '-n', // -n is a pytest-xdist option + '--assert', + '--basetemp', + '--cache-show', + '--capture', + '--code-highlight', + '--color', + '--confcutdir', + '--cov', + '--cov-config', + '--cov-fail-under', + '--cov-report', + '--deselect', + '--dist', + '--doctest-glob', + '--doctest-report', + '--durations', + '--durations-min', + '--ignore', + '--ignore-glob', + '--import-mode', + '--junit-prefix', + '--junit-xml', + '--last-failed-no-failures', + '--lfnf', + '--log-auto-indent', + '--log-cli-date-format', + '--log-cli-format', + '--log-cli-level', + '--log-date-format', + '--log-file', + '--log-file-date-format', + '--log-file-format', + '--log-file-level', + '--log-format', + '--log-level', + '--maxfail', + '--override-ini', + '--pastebin', + '--pdbcls', + '--pythonwarnings', + '--result-log', + '--rootdir', + '--show-capture', + '--tb', + '--verbosity', + '--max-slave-restart', + '--numprocesses', + '--rsyncdir', + '--rsyncignore', + '--tx', +]; + +const OptionsWithoutArguments = [ + '--cache-clear', + '--collect-in-virtualenv', + '--collect-only', + '--co', + '--continue-on-collection-errors', + '--cov-append', + '--cov-branch', + '--debug', + '--disable-pytest-warnings', + '--disable-warnings', + '--doctest-continue-on-failure', + '--doctest-ignore-import-errors', + '--doctest-modules', + '--exitfirst', + '--failed-first', + '--ff', + '--fixtures', + '--fixtures-per-test', + '--force-sugar', + '--full-trace', + '--funcargs', + '--help', + '--keep-duplicates', + '--last-failed', + '--lf', + '--markers', + '--new-first', + '--nf', + '--no-cov', + '--no-cov-on-fail', + '--no-header', + '--no-print-logs', + '--no-summary', + '--noconftest', + '--old-summary', + '--pdb', + '--pyargs', + '-PyTest, Unittest-pyargs', + '--quiet', + '--runxfail', + '--setup-only', + '--setup-plan', + '--setup-show', + '--showlocals', + '--stepwise', + '--sw', + '--stepwise-skip', + '--strict', + '--strict-config', + '--strict-markers', + '--trace-config', + '--verbose', + '--version', + '-V', + '-h', + '-l', + '-q', + '-s', + '-v', + '-x', + '--boxed', + '--forked', + '--looponfail', + '--trace', + '--tx', + '-d', +]; + +export function pytestGetTestFolders(args: string[]): string[] { + const testDirs = getOptionValues(args, '--rootdir'); + if (testDirs.length > 0) { + return testDirs; + } + + const positionalArgs = getPositionalArguments(args, OptionsWithArguments, OptionsWithoutArguments); + // Positional args in pytest are files or directories. + // Remove files from the args, and what's left are test directories. + // If users enter test modules/methods, then its not supported. + return positionalArgs.filter((arg) => !arg.toUpperCase().endsWith('.PY')); +} + +export function removePositionalFoldersAndFiles(args: string[]): string[] { + return pytestFilterArguments(args, TestFilter.removeTests); +} + +function pytestFilterArguments(args: string[], argumentToRemoveOrFilter: string[] | TestFilter): string[] { + const optionsWithoutArgsToRemove: string[] = []; + const optionsWithArgsToRemove: string[] = []; + // Positional arguments in pytest are test directories and files. + // So if we want to run a specific test, then remove positional args. + let removePositionalArgs = false; + if (Array.isArray(argumentToRemoveOrFilter)) { + argumentToRemoveOrFilter.forEach((item) => { + if (OptionsWithArguments.indexOf(item) >= 0) { + optionsWithArgsToRemove.push(item); + } + if (OptionsWithoutArguments.indexOf(item) >= 0) { + optionsWithoutArgsToRemove.push(item); + } + }); + } else { + switch (argumentToRemoveOrFilter) { + case TestFilter.removeTests: { + optionsWithoutArgsToRemove.push( + ...['--lf', '--last-failed', '--ff', '--failed-first', '--nf', '--new-first'], + ); + optionsWithArgsToRemove.push(...['-k', '-m', '--lfnf', '--last-failed-no-failures']); + removePositionalArgs = true; + break; + } + case TestFilter.discovery: { + optionsWithoutArgsToRemove.push( + ...[ + '-x', + '--exitfirst', + '--fixtures', + '--funcargs', + '--fixtures-per-test', + '--pdb', + '--lf', + '--last-failed', + '--ff', + '--failed-first', + '--nf', + '--new-first', + '--cache-show', + '-v', + '--verbose', + '-q', + '-quiet', + '-l', + '--showlocals', + '--no-print-logs', + '--debug', + '--setup-only', + '--setup-show', + '--setup-plan', + '--trace', + ], + ); + optionsWithArgsToRemove.push( + ...[ + '-m', + '--maxfail', + '--pdbcls', + '--capture', + '--lfnf', + '--last-failed-no-failures', + '--verbosity', + '-r', + '--tb', + '--rootdir', + '--show-capture', + '--durations', + '--junit-xml', + '--junit-prefix', + '--result-log', + '-W', + '--pythonwarnings', + '--log-*', + ], + ); + removePositionalArgs = true; + break; + } + case TestFilter.debugAll: + case TestFilter.runAll: { + optionsWithoutArgsToRemove.push(...['--collect-only', '--trace']); + break; + } + case TestFilter.debugSpecific: + case TestFilter.runSpecific: { + optionsWithoutArgsToRemove.push( + ...[ + '--collect-only', + '--lf', + '--last-failed', + '--ff', + '--failed-first', + '--nf', + '--new-first', + '--trace', + ], + ); + optionsWithArgsToRemove.push(...['-k', '-m', '--lfnf', '--last-failed-no-failures']); + removePositionalArgs = true; + break; + } + default: { + throw new Error(`Unsupported Filter '${argumentToRemoveOrFilter}'`); + } + } + } + + let filteredArgs = args.slice(); + if (removePositionalArgs) { + const positionalArgs = getPositionalArguments(filteredArgs, OptionsWithArguments, OptionsWithoutArguments); + filteredArgs = filteredArgs.filter((item) => positionalArgs.indexOf(item) === -1); + } + return filterArguments(filteredArgs, optionsWithArgsToRemove, optionsWithoutArgsToRemove); +} + +export function preparePytestArgumentsForDiscovery(options: TestDiscoveryOptions): string[] { + // Remove unwanted arguments (which happen to be test directories & test specific args). + const args = pytestFilterArguments(options.args, TestFilter.discovery); + if (options.ignoreCache && args.indexOf('--cache-clear') === -1) { + args.splice(0, 0, '--cache-clear'); + } + if (args.indexOf('-s') === -1) { + args.splice(0, 0, '-s'); + } + args.splice(0, 0, '--rootdir', options.workspaceFolder.fsPath); + return args; +} diff --git a/src/client/testing/testController/pytest/pytestController.ts b/src/client/testing/testController/pytest/pytestController.ts new file mode 100644 index 000000000000..d42283b5f243 --- /dev/null +++ b/src/client/testing/testController/pytest/pytestController.ts @@ -0,0 +1,258 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { inject, injectable, named } from 'inversify'; +import { flatten } from 'lodash'; +import * as path from 'path'; +import { CancellationToken, TestItem, TestRunRequest, Uri, TestController, WorkspaceFolder } from 'vscode'; +import { IWorkspaceService } from '../../../common/application/types'; +import { runAdapter } from '../../../common/process/internal/scripts/testing_tools'; +import { IConfigurationService } from '../../../common/types'; +import { createDeferred, Deferred } from '../../../common/utils/async'; +import { PYTEST_PROVIDER } from '../../common/constants'; +import { TestDiscoveryOptions } from '../../common/types'; +import { + createWorkspaceRootTestItem, + getNodeByUri, + getWorkspaceNode, + removeItemByIdFromChildren, + updateTestItemFromRawData, +} from '../common/testItemUtilities'; +import { + ITestFrameworkController, + ITestDiscoveryHelper, + ITestsRunner, + TestData, + RawDiscoveredTests, +} from '../common/types'; +import { preparePytestArgumentsForDiscovery, pytestGetTestFolders } from './arguments'; + +@injectable() +export class PytestController implements ITestFrameworkController { + private readonly testData: Map = new Map(); + + private discovering: Map> = new Map(); + + private idToRawData: Map = new Map(); + + constructor( + @inject(ITestDiscoveryHelper) private readonly discoveryHelper: ITestDiscoveryHelper, + @inject(ITestsRunner) @named(PYTEST_PROVIDER) private readonly runner: ITestsRunner, + @inject(IConfigurationService) private readonly configService: IConfigurationService, + @inject(IWorkspaceService) private readonly workspaceService: IWorkspaceService, + ) {} + + public async resolveChildren(testController: TestController, item: TestItem): Promise { + const workspace = this.workspaceService.getWorkspaceFolder(item.uri); + if (workspace) { + // if we are still discovering then wait + const discovery = this.discovering.get(workspace.uri.fsPath); + if (discovery) { + await discovery.promise; + } + + // see if we have raw test data + const rawTestData = this.testData.get(workspace.uri.fsPath); + if (rawTestData) { + // Refresh each node with new data + if (rawTestData.length === 0) { + const items: TestItem[] = []; + testController.items.forEach((i) => items.push(i)); + items.forEach((i) => testController.items.delete(i.id)); + return Promise.resolve(); + } + + const root = rawTestData.length === 1 ? rawTestData[0].root : workspace.uri.fsPath; + if (root === item.id) { + // This is the workspace root node + if (rawTestData.length === 1) { + if (rawTestData[0].tests.length > 0) { + item.description = item.id; + updateTestItemFromRawData(item, testController, this.idToRawData, item.id, rawTestData); + } else { + this.idToRawData.delete(item.id); + testController.items.delete(item.id); + return Promise.resolve(); + } + } else { + item.description = workspace.uri.fsPath; + + // To figure out which top level nodes have to removed. First we get all the + // existing nodes. Then if they have data we keep thoese nodes, Nodes with + // node data will be removed after we check the raw data. + let subRootWithNoData: string[] = []; + item.children.forEach((c) => subRootWithNoData.push(c.id)); + + rawTestData.forEach((data) => { + if (data.tests.length > 0) { + let subRootItem = item.children.get(data.root); + if (!subRootItem) { + subRootItem = createWorkspaceRootTestItem(testController, this.idToRawData, { + id: data.root, + label: path.basename(data.root), + uri: Uri.file(data.root), + runId: data.root, + parentId: item.id, + }); + item.children.add(subRootItem); + } + + // We found data for a node. Remove its id for the no-data list. + subRootWithNoData = subRootWithNoData.filter((s) => s !== data.root); + updateTestItemFromRawData( + subRootItem, + testController, + this.idToRawData, + subRootItem.id, + [data], + ); + } else { + // This means there are no tests under this node + removeItemByIdFromChildren(this.idToRawData, item, [data.root]); + } + }); + + // We did not find any data for these nodes, delete them. + removeItemByIdFromChildren(this.idToRawData, item, subRootWithNoData); + } + } else { + const workspaceNode = getWorkspaceNode(item, this.idToRawData); + if (workspaceNode) { + updateTestItemFromRawData( + item, + testController, + this.idToRawData, + workspaceNode.id, + rawTestData, + ); + } + } + } else { + const workspaceNode = getWorkspaceNode(item, this.idToRawData); + if (workspaceNode) { + testController.items.delete(workspaceNode.id); + } + } + } + return Promise.resolve(); + } + + public async refreshTestData(testController: TestController, uri: Uri): Promise { + const workspace = this.workspaceService.getWorkspaceFolder(uri); + if (workspace) { + // Discovery is expensive. So if it is already running then use the promise + // from the last run + const previous = this.discovering.get(workspace.uri.fsPath); + if (previous) { + return previous.promise; + } + + const deferred = createDeferred(); + this.discovering.set(workspace.uri.fsPath, deferred); + + const settings = this.configService.getSettings(workspace.uri); + const options: TestDiscoveryOptions = { + workspaceFolder: workspace.uri, + cwd: settings.testing.cwd ?? workspace.uri.fsPath, + args: settings.testing.pytestArgs, + ignoreCache: true, + }; + + // Get individual test directories selected by the user. + const testDirectories = pytestGetTestFolders(options.args); + + // Set arguments to use with pytest discovery script. + const args = runAdapter(['discover', 'pytest', '--', ...preparePytestArgumentsForDiscovery(options)]); + + // Build options for each directory selected by the user. + let discoveryRunOptions: TestDiscoveryOptions[]; + if (testDirectories.length === 0) { + // User did not provide any directory. So we don't need to tweak arguments. + discoveryRunOptions = [ + { + ...options, + args, + }, + ]; + } else { + discoveryRunOptions = testDirectories.map((testDir) => ({ + ...options, + args: [...args, testDir], + })); + } + + // This is where we execute pytest discovery via a common helper. + const rawTestData = flatten( + await Promise.all(discoveryRunOptions.map((o) => this.discoveryHelper.runTestDiscovery(o))), + ); + this.testData.set(workspace.uri.fsPath, rawTestData); + + // Discovery has finished running we have the raw test data at this point. + deferred.resolve(); + this.discovering.delete(workspace.uri.fsPath); + + const root = rawTestData.length === 1 ? rawTestData[0].root : workspace.uri.fsPath; + const workspaceNode = testController.items.get(root); + if (workspaceNode) { + if (uri.fsPath === workspace.uri.fsPath) { + // this is a workspace level refresh + // This is an existing workspace test node. Just update the children + await this.resolveChildren(testController, workspaceNode); + } else { + // This is a child node refresh + const testNode = getNodeByUri(workspaceNode, uri); + if (testNode) { + // We found the node to update + await this.resolveChildren(testController, testNode); + } else { + // update the entire workspace tree + await this.resolveChildren(testController, workspaceNode); + } + } + } else if (rawTestData.length > 0) { + // This is a new workspace with tests. + const newItem = createWorkspaceRootTestItem(testController, this.idToRawData, { + id: root, + label: path.basename(root), + uri: Uri.file(root), + runId: root, + }); + testController.items.add(newItem); + + await this.resolveChildren(testController, newItem); + } + } + return Promise.resolve(); + } + + public runTests( + testController: TestController, + request: TestRunRequest, + debug: boolean, + workspace: WorkspaceFolder, + token: CancellationToken, + ): Promise { + let runRequest = request; + if (!runRequest.include) { + const testItem = testController.items.get(workspace.uri.fsPath); + + if (testItem) { + runRequest = new TestRunRequest([testItem], undefined, request.profile); + } + } + + const settings = this.configService.getSettings(workspace.uri); + return this.runner.runTests( + testController, + runRequest, + debug, + { + workspaceFolder: workspace.uri, + cwd: settings.testing.cwd ?? workspace.uri.fsPath, + token, + args: settings.testing.pytestArgs, + }, + this.idToRawData, + ); + } +} diff --git a/src/client/testing/testController/pytest/runner.ts b/src/client/testing/testController/pytest/runner.ts new file mode 100644 index 000000000000..19ad32c22b56 --- /dev/null +++ b/src/client/testing/testController/pytest/runner.ts @@ -0,0 +1,142 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { inject, injectable, named } from 'inversify'; +import { Disposable, TestController, TestItem, TestRun, TestRunRequest } from 'vscode'; +import { IOutputChannel } from '../../../common/types'; +import { PYTEST_PROVIDER } from '../../common/constants'; +import { ITestDebugLauncher, ITestRunner, LaunchOptions, Options } from '../../common/types'; +import { TEST_OUTPUT_CHANNEL } from '../../constants'; +import { filterArguments, getOptionValues } from '../common/argumentsHelper'; +import { createTemporaryFile } from '../common/externalDependencies'; +import { updateResultFromJunitXml } from '../common/resultsHelper'; +import { getTestCaseNodes } from '../common/testItemUtilities'; +import { ITestsRunner, TestData, TestRunInstanceOptions, TestRunOptions } from '../common/types'; +import { removePositionalFoldersAndFiles } from './arguments'; + +const JunitXmlArgOld = '--junitxml'; +const JunitXmlArg = '--junit-xml'; + +async function getPytestJunitXmlTempFile(args: string[], disposables: Disposable[]): Promise { + const argValues = getOptionValues(args, JunitXmlArg); + if (argValues.length === 1) { + return argValues[0]; + } + const tempFile = await createTemporaryFile('.xml'); + disposables.push(tempFile); + return tempFile.filePath; +} + +@injectable() +export class PytestRunner implements ITestsRunner { + constructor( + @inject(ITestRunner) private readonly runner: ITestRunner, + @inject(ITestDebugLauncher) private readonly debugLauncher: ITestDebugLauncher, + @inject(IOutputChannel) @named(TEST_OUTPUT_CHANNEL) private readonly outputChannel: IOutputChannel, + ) {} + + public async runTests( + testController: TestController, + request: TestRunRequest, + debug: boolean, + options: TestRunOptions, + idToRawData: Map, + ): Promise { + const runOptions: TestRunInstanceOptions = { + ...options, + exclude: request.exclude, + debug, + }; + const runInstance = testController.createTestRun( + request, + `Running Tests for Workspace ${runOptions.workspaceFolder.fsPath}`, + true, + ); + try { + await Promise.all( + (request.include ?? []).map((testNode) => this.runTest(testNode, runInstance, runOptions, idToRawData)), + ); + } catch (ex) { + runInstance.appendOutput(`Error while running tests:\r\n${ex}\r\n\r\n`); + } finally { + runInstance.appendOutput(`Finished running tests!\r\n`); + runInstance.end(); + } + } + + private async runTest( + testNode: TestItem, + runInstance: TestRun, + options: TestRunInstanceOptions, + idToRawData: Map, + ): Promise { + runInstance.appendOutput(`Running tests: ${testNode.label}\r\n`); + + // VS Code API requires that we set the run state on the leaf nodes. The state of the + // parent nodes are computed based on the state of child nodes. + const testCaseNodes = getTestCaseNodes(testNode); + testCaseNodes.forEach((node) => runInstance.started(node)); + + // For pytest we currently use JUnit XML to get the results. We create a temporary file here + // to ensure that the file is removed when we are done reading the result. + const disposables: Disposable[] = []; + const junitFilePath = await getPytestJunitXmlTempFile(options.args, disposables); + + try { + // Remove positional test folders and files, we will add as needed per node + let testArgs = removePositionalFoldersAndFiles(options.args); + + // Remove the '--junitxml' or '--junit-xml' if it exists, and add it with our path. + testArgs = filterArguments(testArgs, [JunitXmlArg, JunitXmlArgOld]); + testArgs.splice(0, 0, `${JunitXmlArg}=${junitFilePath}`); + + // Ensure that we use the xunit1 format. + testArgs.splice(0, 0, '--override-ini', 'junit_family=xunit1'); + + // Make sure root dir is set so pytest can find the relative paths + testArgs.splice(0, 0, '--rootdir', options.workspaceFolder.fsPath); + + // Positional arguments control the tests to be run. + const rawData = idToRawData.get(testNode.id); + if (!rawData) { + throw new Error(`Trying to run unknown node: ${testNode.id}`); + } + testArgs.push(rawData.rawId); + + runInstance.appendOutput(`Running test with arguments: ${testArgs.join(' ')}\r\n`); + runInstance.appendOutput(`Current working directory: ${options.cwd}\r\n`); + runInstance.appendOutput(`Workspace directory: ${options.workspaceFolder.fsPath}\r\n`); + + if (options.debug) { + const debuggerArgs = [options.cwd, 'pytest'].concat(testArgs); + const launchOptions: LaunchOptions = { + cwd: options.cwd, + args: debuggerArgs, + token: options.token, + outChannel: this.outputChannel, + testProvider: PYTEST_PROVIDER, + }; + await this.debugLauncher.launchDebugger(launchOptions); + } else { + const runOptions: Options = { + args: testArgs, + cwd: options.cwd, + outChannel: this.outputChannel, + token: options.token, + workspaceFolder: options.workspaceFolder, + }; + await this.runner.run(PYTEST_PROVIDER, runOptions); + } + + // At this point pytest has finished running, we now have to parse the output + runInstance.appendOutput(`Run completed, parsing output\r\n`); + await updateResultFromJunitXml(junitFilePath, testNode, runInstance, idToRawData); + } catch (ex) { + runInstance.appendOutput(`Error while running tests: ${testNode.label}\r\n${ex}\r\n\r\n`); + return Promise.reject(ex); + } finally { + disposables.forEach((d) => d.dispose()); + } + return Promise.resolve(); + } +} diff --git a/src/client/testing/testController/serviceRegistry.ts b/src/client/testing/testController/serviceRegistry.ts new file mode 100644 index 000000000000..0e8320a4f153 --- /dev/null +++ b/src/client/testing/testController/serviceRegistry.ts @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { IServiceManager } from '../../ioc/types'; +import { PYTEST_PROVIDER, UNITTEST_PROVIDER } from '../common/constants'; +import { TestDiscoveryHelper } from './common/discoveryHelper'; +import { ITestFrameworkController, ITestDiscoveryHelper, ITestsRunner, ITestController } from './common/types'; +import { PythonTestController } from './controller'; +import { PytestController } from './pytest/pytestController'; +import { PytestRunner } from './pytest/runner'; +import { UnittestRunner } from './unittest/runner'; +import { UnittestController } from './unittest/unittestController'; + +export function registerTestControllerTypes(serviceManager: IServiceManager): void { + serviceManager.addSingleton(ITestDiscoveryHelper, TestDiscoveryHelper); + + serviceManager.addSingleton(ITestFrameworkController, PytestController, PYTEST_PROVIDER); + serviceManager.addSingleton(ITestsRunner, PytestRunner, PYTEST_PROVIDER); + + serviceManager.addSingleton( + ITestFrameworkController, + UnittestController, + UNITTEST_PROVIDER, + ); + serviceManager.addSingleton(ITestsRunner, UnittestRunner, UNITTEST_PROVIDER); + serviceManager.addSingleton(ITestController, PythonTestController); +} diff --git a/src/client/testing/testController/unittest/arguments.ts b/src/client/testing/testController/unittest/arguments.ts new file mode 100644 index 000000000000..52ae484a87c2 --- /dev/null +++ b/src/client/testing/testController/unittest/arguments.ts @@ -0,0 +1,87 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { TestFilter } from '../../common/types'; +import { filterArguments, getOptionValues, getPositionalArguments } from '../common/argumentsHelper'; + +const OptionsWithArguments = ['-k', '-p', '-s', '-t', '--pattern', '--start-directory', '--top-level-directory']; + +const OptionsWithoutArguments = [ + '-b', + '-c', + '-f', + '-h', + '-q', + '-v', + '--buffer', + '--catch', + '--failfast', + '--help', + '--locals', + '--quiet', + '--verbose', +]; + +export function unittestFilterArguments(args: string[], argumentToRemoveOrFilter: string[] | TestFilter): string[] { + const optionsWithoutArgsToRemove: string[] = []; + const optionsWithArgsToRemove: string[] = []; + // Positional arguments in pytest positional args are test directories and files. + // So if we want to run a specific test, then remove positional args. + let removePositionalArgs = false; + if (Array.isArray(argumentToRemoveOrFilter)) { + argumentToRemoveOrFilter.forEach((item) => { + if (OptionsWithArguments.indexOf(item) >= 0) { + optionsWithArgsToRemove.push(item); + } + if (OptionsWithoutArguments.indexOf(item) >= 0) { + optionsWithoutArgsToRemove.push(item); + } + }); + } else { + removePositionalArgs = true; + } + + let filteredArgs = args.slice(); + if (removePositionalArgs) { + const positionalArgs = getPositionalArguments(filteredArgs, OptionsWithArguments, OptionsWithoutArguments); + filteredArgs = filteredArgs.filter((item) => positionalArgs.indexOf(item) === -1); + } + return filterArguments(filteredArgs, optionsWithArgsToRemove, optionsWithoutArgsToRemove); +} + +export function unittestGetTestFolders(args: string[]): string[] { + const shortValue = getOptionValues(args, '-s'); + if (shortValue.length === 1) { + return shortValue; + } + const longValue = getOptionValues(args, '--start-directory'); + if (longValue.length === 1) { + return longValue; + } + return ['.']; +} + +export function unittestGetTestPattern(args: string[]): string { + const shortValue = getOptionValues(args, '-p'); + if (shortValue.length === 1) { + return shortValue[0]; + } + const longValue = getOptionValues(args, '--pattern'); + if (longValue.length === 1) { + return longValue[0]; + } + return 'test*.py'; +} + +export function getTestRunArgs(args: string[]): string[] { + const startTestDiscoveryDirectory = unittestGetTestFolders(args)[0]; + const pattern = unittestGetTestPattern(args); + + const failFast = args.some((arg) => arg.trim() === '-f' || arg.trim() === '--failfast'); + const verbosity = args.some((arg) => arg.trim().indexOf('-v') === 0) ? 2 : 1; + const testArgs = [`--us=${startTestDiscoveryDirectory}`, `--up=${pattern}`, `--uvInt=${verbosity}`]; + if (failFast) { + testArgs.push('--uf'); + } + return testArgs; +} diff --git a/src/client/testing/testController/unittest/runner.ts b/src/client/testing/testController/unittest/runner.ts new file mode 100644 index 000000000000..673166e0d6ef --- /dev/null +++ b/src/client/testing/testController/unittest/runner.ts @@ -0,0 +1,223 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { injectable, inject, named } from 'inversify'; +import { Location, TestController, TestItem, TestMessage, TestRun, TestRunRequest } from 'vscode'; +import { traceError, traceInfo } from '../../../common/logger'; +import * as internalScripts from '../../../common/process/internal/scripts'; +import { IOutputChannel } from '../../../common/types'; +import { createDeferred, Deferred } from '../../../common/utils/async'; +import { noop } from '../../../common/utils/misc'; +import { UNITTEST_PROVIDER } from '../../common/constants'; +import { ITestRunner, ITestDebugLauncher, IUnitTestSocketServer, LaunchOptions, Options } from '../../common/types'; +import { TEST_OUTPUT_CHANNEL } from '../../constants'; +import { getTestCaseNodes } from '../common/testItemUtilities'; +import { ITestsRunner, TestData, TestRunInstanceOptions, TestRunOptions } from '../common/types'; +import { getTestRunArgs } from './arguments'; + +interface ITestData { + test: string; + message: string; + outcome: string; + traceback: string; +} + +@injectable() +export class UnittestRunner implements ITestsRunner { + constructor( + @inject(ITestRunner) private readonly runner: ITestRunner, + @inject(ITestDebugLauncher) private readonly debugLauncher: ITestDebugLauncher, + @inject(IOutputChannel) @named(TEST_OUTPUT_CHANNEL) private readonly outputChannel: IOutputChannel, + @inject(IUnitTestSocketServer) private readonly server: IUnitTestSocketServer, + ) {} + + public async runTests( + testController: TestController, + request: TestRunRequest, + debug: boolean, + options: TestRunOptions, + idToRawData: Map, + ): Promise { + const runOptions: TestRunInstanceOptions = { + ...options, + exclude: request.exclude, + debug, + }; + + const runInstance = testController.createTestRun(request); + const dispose = options.token.onCancellationRequested(() => { + runInstance.end(); + }); + try { + await Promise.all( + (request.include ?? []).map((testNode) => this.runTest(testNode, runInstance, runOptions, idToRawData)), + ); + } catch (ex) { + runInstance.appendOutput(`Error while running tests:\r\n${ex}\r\n\r\n`); + } finally { + runInstance.appendOutput(`Finished running tests!\r\n`); + runInstance.end(); + dispose.dispose(); + } + } + + private async runTest( + testNode: TestItem, + runInstance: TestRun, + options: TestRunInstanceOptions, + idToRawData: Map, + ): Promise { + runInstance.appendOutput(`Running tests: ${testNode.label}\r\n`); + const testCaseNodes = getTestCaseNodes(testNode); + const tested: string[] = []; + + const counts = { + total: testCaseNodes.length, + passed: 0, + skipped: 0, + errored: 0, + failed: 0, + }; + + let failFast = false; + let stopTesting = false; + let testCasePromise: Deferred; + this.server.on('error', (message: string, ...data: string[]) => { + traceError(`${message} ${data.join(' ')}`); + testCasePromise.reject(); + }); + this.server.on('log', (message: string, ...data: string[]) => { + traceInfo(`${message} ${data.join(' ')}`); + }); + this.server.on('connect', noop); + this.server.on('start', noop); + this.server.on('result', (data: ITestData) => { + testCasePromise.resolve(); + const testCase = testCaseNodes.find((node) => idToRawData.get(node.id)?.runId === data.test); + const rawTestCase = idToRawData.get(testCase?.id ?? ''); + if (testCase && rawTestCase) { + tested.push(rawTestCase.runId); + + if (data.outcome === 'passed') { + const text = `${rawTestCase.rawId} Passed\r\n`; + runInstance.passed(testCase); + runInstance.appendOutput(text); + counts.passed += 1; + } else if (data.outcome === 'failed') { + const traceback = data.traceback.splitLines({ trim: false, removeEmptyEntries: true }).join('\r\n'); + const text = `${rawTestCase.rawId} Failed: ${data.message}\r\n${traceback}\r\n`; + const message = new TestMessage(text); + + if (testCase.uri && testCase.range) { + message.location = new Location(testCase.uri, testCase.range); + } + + runInstance.failed(testCase, message); + runInstance.appendOutput(text); + counts.failed += 1; + if (failFast) { + stopTesting = true; + } + } else if (data.outcome === 'error') { + const traceback = data.traceback.splitLines({ trim: false, removeEmptyEntries: true }).join('\r\n'); + const text = `${rawTestCase.rawId} Failed with Error: ${data.message}\r\n${traceback}\r\n`; + const message = new TestMessage(text); + + if (testCase.uri && testCase.range) { + message.location = new Location(testCase.uri, testCase.range); + } + + runInstance.failed(testCase, message); + runInstance.appendOutput(text); + counts.errored += 1; + if (failFast) { + stopTesting = true; + } + } else if (data.outcome === 'skipped') { + const traceback = data.traceback.splitLines({ trim: false, removeEmptyEntries: true }).join('\r\n'); + const text = `${rawTestCase.rawId} Skipped: ${data.message}\r\n${traceback}\r\n`; + runInstance.skipped(testCase); + runInstance.appendOutput(text); + counts.skipped += 1; + } else { + const text = `Unknown outcome type for test ${rawTestCase.rawId}: ${data.outcome}`; + runInstance.appendOutput(text); + const message = new TestMessage(text); + if (testCase.uri && testCase.range) { + message.location = new Location(testCase.uri, testCase.range); + } + } + } + }); + + const port = await this.server.start(); + const runTestInternal = async (testFile = '', testId = ''): Promise => { + let testArgs = getTestRunArgs(options.args); + failFast = testArgs.indexOf('--uf') >= 0; + testArgs = testArgs.filter((arg) => arg !== '--uf'); + + testArgs.push(`--result-port=${port}`); + if (testId.length > 0) { + testArgs.push(`-t${testId}`); + } + if (testFile.length > 0) { + testArgs.push(`--testFile=${testFile}`); + } + if (options.debug === true) { + testArgs.push('--debug'); + const launchOptions: LaunchOptions = { + cwd: options.cwd, + args: testArgs, + token: options.token, + outChannel: this.outputChannel, + testProvider: UNITTEST_PROVIDER, + }; + return this.debugLauncher.launchDebugger(launchOptions); + } + const args = internalScripts.visualstudio_py_testlauncher(testArgs); + + const runOptions: Options = { + args, + cwd: options.cwd, + outChannel: this.outputChannel, + token: options.token, + workspaceFolder: options.workspaceFolder, + }; + testCasePromise = createDeferred(); + await this.runner.run(UNITTEST_PROVIDER, runOptions); + return testCasePromise.promise; + }; + + try { + for (const testCaseNode of testCaseNodes) { + if (stopTesting || options.token.isCancellationRequested) { + break; + } + + const rawTestCaseNode = idToRawData.get(testCaseNode.id); + if (rawTestCaseNode) { + // VS Code API requires that we set the run state on the leaf nodes. The state of the + // parent nodes are computed based on the state of child nodes. + runInstance.started(testCaseNode); + await runTestInternal(testCaseNode.uri?.fsPath, rawTestCaseNode.runId); + } + } + } catch (ex) { + traceError(ex); + } finally { + this.server.removeAllListeners(); + this.server.stop(); + } + + runInstance.appendOutput(`Total number of tests passed: ${counts.passed}\r\n`); + runInstance.appendOutput(`Total number of tests failed: ${counts.failed}\r\n`); + runInstance.appendOutput(`Total number of tests failed with errors: ${counts.errored}\r\n`); + runInstance.appendOutput(`Total number of tests skipped: ${counts.skipped}\r\n`); + + if (failFast) { + runInstance.appendOutput( + `Total number of tests skipped due to fail fast: ${counts.total - tested.length}\r\n`, + ); + } + } +} diff --git a/src/client/testing/testController/unittest/unittestController.ts b/src/client/testing/testController/unittest/unittestController.ts new file mode 100644 index 000000000000..2bfc6e642c88 --- /dev/null +++ b/src/client/testing/testController/unittest/unittestController.ts @@ -0,0 +1,329 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import * as path from 'path'; +import { inject, injectable, named } from 'inversify'; +import { CancellationToken, TestController, TestItem, TestRunRequest, Uri, WorkspaceFolder } from 'vscode'; +import { IWorkspaceService } from '../../../common/application/types'; +import { IConfigurationService } from '../../../common/types'; +import { createDeferred, Deferred } from '../../../common/utils/async'; +import { UNITTEST_PROVIDER } from '../../common/constants'; +import { ITestRunner, Options, TestDiscoveryOptions } from '../../common/types'; +import { + ITestFrameworkController, + ITestsRunner, + RawDiscoveredTests, + RawTest, + RawTestParent, + TestData, +} from '../common/types'; +import { unittestGetTestFolders, unittestGetTestPattern } from './arguments'; +import { execCode } from '../../../common/process/internal/python'; +import { + createWorkspaceRootTestItem, + getNodeByUri, + getWorkspaceNode, + updateTestItemFromRawData, +} from '../common/testItemUtilities'; + +@injectable() +export class UnittestController implements ITestFrameworkController { + private readonly testData: Map = new Map(); + + private discovering: Map> = new Map(); + + private idToRawData: Map = new Map(); + + constructor( + @inject(ITestRunner) private readonly discoveryRunner: ITestRunner, + @inject(ITestsRunner) @named(UNITTEST_PROVIDER) private readonly runner: ITestsRunner, + @inject(IConfigurationService) private readonly configService: IConfigurationService, + @inject(IWorkspaceService) private readonly workspaceService: IWorkspaceService, + ) {} + + public async resolveChildren(testController: TestController, item: TestItem): Promise { + const workspace = this.workspaceService.getWorkspaceFolder(item.uri); + if (workspace) { + // if we are still discovering then wait + const discovery = this.discovering.get(workspace.uri.fsPath); + if (discovery) { + await discovery.promise; + } + + // see if we have raw test data + const rawTestData = this.testData.get(workspace.uri.fsPath); + if (rawTestData) { + if (rawTestData.root === item.id) { + if (rawTestData.tests.length === 0) { + testController.items.delete(item.id); + return Promise.resolve(); + } + + if (rawTestData.tests.length > 0) { + item.description = item.id; + updateTestItemFromRawData(item, testController, this.idToRawData, item.id, [rawTestData]); + } else { + this.idToRawData.delete(item.id); + testController.items.delete(item.id); + } + } else { + const workspaceNode = getWorkspaceNode(item, this.idToRawData); + if (workspaceNode) { + updateTestItemFromRawData(item, testController, this.idToRawData, workspaceNode.id, [ + rawTestData, + ]); + } + } + } else { + const workspaceNode = getWorkspaceNode(item, this.idToRawData); + if (workspaceNode) { + testController.items.delete(workspaceNode.id); + } + } + } + return Promise.resolve(); + } + + public async refreshTestData(testController: TestController, uri: Uri): Promise { + const workspace = this.workspaceService.getWorkspaceFolder(uri); + if (workspace) { + // Discovery is expensive. So if it is already running then use the promise + // from the last run + const previous = this.discovering.get(workspace.uri.fsPath); + if (previous) { + return previous.promise; + } + + const deferred = createDeferred(); + this.discovering.set(workspace.uri.fsPath, deferred); + + const settings = this.configService.getSettings(workspace.uri); + const options: TestDiscoveryOptions = { + workspaceFolder: workspace.uri, + cwd: settings.testing.cwd ?? workspace.uri.fsPath, + args: settings.testing.unittestArgs, + ignoreCache: true, + }; + + const startDir = unittestGetTestFolders(options.args)[0]; + const pattern = unittestGetTestPattern(options.args); + const discoveryScript = ` +import unittest +import inspect + +def get_sourceline(obj): + s, n = inspect.getsourcelines(obj) + for i, v in enumerate(s): + if v.strip().startswith('def'): + return str(n+i) + return '*' + +def generate_test_cases(suite): + for test in suite: + if isinstance(test, unittest.TestCase): + yield test + else: + yield from generate_test_cases(test) + +loader = unittest.TestLoader() +suite = loader.discover("${startDir}", pattern="${pattern}") + +print("start") #Don't remove this line +for s in generate_test_cases(suite): + tm = getattr(s, s._testMethodName) + print(s.id().replace('.',':') + ":" + get_sourceline(tm)) +`; + + const runOptions: Options = { + // unittest needs to load modules in the workspace + // isolating it breaks unittest discovery + args: execCode(discoveryScript), + cwd: options.cwd, + workspaceFolder: options.workspaceFolder, + token: options.token, + outChannel: options.outChannel, + }; + + const content = await this.discoveryRunner.run(UNITTEST_PROVIDER, runOptions); + const rawTestData = await testDiscoveryParser( + options.cwd, + path.isAbsolute(startDir) ? path.relative(options.cwd, startDir) : startDir, + getTestIds(content), + options.token, + ); + this.testData.set(workspace.uri.fsPath, rawTestData); + + // Discovery has finished running we have the raw test data at this point. + deferred.resolve(); + this.discovering.delete(workspace.uri.fsPath); + + const workspaceNode = testController.items.get(rawTestData.root); + if (workspaceNode) { + if (uri.fsPath === workspace.uri.fsPath) { + // this is a workspace level refresh + // This is an existing workspace test node. Just update the children + await this.resolveChildren(testController, workspaceNode); + } else { + // This is a child node refresh + const testNode = getNodeByUri(workspaceNode, uri); + if (testNode) { + // We found the node to update + await this.resolveChildren(testController, testNode); + } else { + // update the entire workspace tree + await this.resolveChildren(testController, workspaceNode); + } + } + } else if (rawTestData.tests.length > 0) { + // This is a new workspace with tests. + const newItem = createWorkspaceRootTestItem(testController, this.idToRawData, { + id: rawTestData.root, + label: path.basename(rawTestData.root), + uri: Uri.file(rawTestData.root), + runId: rawTestData.root === '.' ? workspace.uri.fsPath : rawTestData.root, + rawId: rawTestData.rootid, + }); + testController.items.add(newItem); + + await this.resolveChildren(testController, newItem); + } + } + return Promise.resolve(); + } + + public runTests( + testController: TestController, + request: TestRunRequest, + debug: boolean, + workspace: WorkspaceFolder, + token: CancellationToken, + ): Promise { + let runRequest = request; + if (!runRequest.include) { + const testItem = testController.items.get(workspace.uri.fsPath); + + if (testItem) { + runRequest = new TestRunRequest([testItem], undefined, request.profile); + } + } + + const settings = this.configService.getSettings(workspace.uri); + + return this.runner.runTests( + testController, + request, + debug, + { + workspaceFolder: workspace.uri, + cwd: settings.testing.cwd ?? workspace.uri.fsPath, + token, + args: settings.testing.unittestArgs, + }, + this.idToRawData, + ); + } +} + +function getTestIds(content: string): string[] { + let startedCollecting = false; + return content + .split(/\r?\n/g) + .map((line) => { + if (!startedCollecting) { + if (line === 'start') { + startedCollecting = true; + } + return ''; + } + return line.trim(); + }) + .filter((line) => line.length > 0); +} + +function testDiscoveryParser( + cwd: string, + testDir: string, + testIds: string[], + token: CancellationToken | undefined, +): Promise { + const parents: RawTestParent[] = []; + const tests: RawTest[] = []; + + for (const testId of testIds) { + if (token?.isCancellationRequested) { + break; + } + + const parts = testId.split(':'); + + // At minimum a `unittest` test will have a file, class, function, and line number + // E.g: + // test_math.TestMathMethods.test_numbers:5 + // test_math.TestMathMethods.test_numbers2:9 + if (parts.length > 3) { + const lineNo = parts.pop(); + const functionName = parts.pop(); + const className = parts.pop(); + const fileName = parts.pop(); + const folders = parts; + const pyFileName = `${fileName}.py`; + const relPath = `./${[...folders, pyFileName].join('/')}`; + + if (functionName && className && fileName && lineNo) { + const collectionId = `${relPath}::${className}`; + const fileId = relPath; + tests.push({ + id: `${relPath}::${className}::${functionName}`, + name: functionName, + parentid: collectionId, + source: `${relPath}:${lineNo}`, + }); + + const rawCollection = parents.find((c) => c.id === collectionId); + if (!rawCollection) { + parents.push({ + id: collectionId, + name: className, + parentid: fileId, + kind: 'suite', + }); + } + + const rawFile = parents.find((f) => f.id === fileId); + if (!rawFile) { + parents.push({ + id: fileId, + name: pyFileName, + parentid: folders.length === 0 ? testDir : `./${folders.join('/')}`, + kind: 'file', + relpath: relPath, + } as RawTestParent); + } + + const folderParts = []; + for (const folder of folders) { + const parentId = folderParts.length === 0 ? testDir : `${folderParts.join('/')}`; + folderParts.push(folder); + const pathId = `${folderParts.join('/')}`; + const rawFolder = parents.find((f) => f.id === pathId); + if (!rawFolder) { + parents.push({ + id: pathId, + name: folder, + parentid: parentId, + kind: 'folder', + relpath: pathId, + } as RawTestParent); + } + } + } + } + } + + return Promise.resolve({ + rootid: testDir, + root: path.isAbsolute(testDir) ? testDir : path.resolve(cwd, testDir), + parents, + tests, + }); +} diff --git a/types/vscode.proposed.d.ts b/types/vscode.proposed.d.ts index ef765c720354..602b8c2d0e50 100644 --- a/types/vscode.proposed.d.ts +++ b/types/vscode.proposed.d.ts @@ -930,209 +930,331 @@ declare module 'vscode' { } //#endregion + //#region proposed test APIs https://github.com/microsoft/vscode/issues/107467 + export namespace tests { + /** + * Returns an observer that watches and can request tests. + */ + export function createTestObserver(): TestObserver; - //#region https://github.com/microsoft/vscode/issues/107467 - export namespace test { /** - * Registers a controller that can discover and - * run tests in workspaces and documents. + * Event that fires when the {@link testResults} array is updated. */ - export function registerTestController(testController: TestController): Disposable; + export const onDidChangeTestResults: Event; + } + export interface TestObserver { /** - * Requests that tests be run by their controller. - * @param run Run options to use - * @param token Cancellation token for the test run + * List of tests returned by test provider for files in the workspace. */ - export function runTests(run: TestRunRequest, token?: CancellationToken): Thenable; + readonly tests: ReadonlyArray; /** - * Returns an observer that retrieves tests in the given workspace folder. - * @stability experimental + * An event that fires when an existing test in the collection changes, or + * null if a top-level test was added or removed. When fired, the consumer + * should check the test item and all its children for changes. */ - export function createWorkspaceTestObserver(workspaceFolder: WorkspaceFolder): TestObserver; + readonly onDidChangeTest: Event; /** - * Returns an observer that retrieves tests in the given text document. - * @stability experimental + * Dispose of the observer, allowing the editor to eventually tell test + * providers that they no longer need to update tests. */ - export function createDocumentTestObserver(document: TextDocument): TestObserver; + dispose(): void; + } + export interface TestsChangeEvent { /** - * Creates a {@link TestRun}. This should be called by the - * {@link TestRunner} when a request is made to execute tests, and may also - * be called if a test run is detected externally. Once created, tests - * that are included in the results will be moved into the - * {@link TestResultState.Pending} state. - * - * @param request Test run request. Only tests inside the `include` may be - * modified, and tests in its `exclude` are ignored. - * @param name The human-readable name of the run. This can be used to - * disambiguate multiple sets of results in a test run. It is useful if - * tests are run across multiple platforms, for example. - * @param persist Whether the results created by the run should be - * persisted in VS Code. This may be false if the results are coming from - * a file already saved externally, such as a coverage information file. + * List of all tests that are newly added. */ - export function createTestRun(request: TestRunRequest, name?: string, persist?: boolean): TestRun; + readonly added: ReadonlyArray; /** - * Creates a new managed {@link TestItem} instance. - * @param options Initial/required options for the item - * @param data Custom data to be stored in {@link TestItem.data} + * List of existing tests that have updated. */ - export function createTestItem(options: TestItemOptions, data: T): TestItem; + readonly updated: ReadonlyArray; /** - * Creates a new managed {@link TestItem} instance. - * @param options Initial/required options for the item + * List of existing tests that have been removed. */ - export function createTestItem(options: TestItemOptions): TestItem; + readonly removed: ReadonlyArray; + } + /** + * A test item is an item shown in the "test explorer" view. It encompasses + * both a suite and a test, since they have almost or identical capabilities. + */ + export interface TestItem { /** - * List of test results stored by VS Code, sorted in descnding - * order by their `completedAt` time. - * @stability experimental + * Marks the test as outdated. This can happen as a result of file changes, + * for example. In "auto run" mode, tests that are outdated will be + * automatically rerun after a short delay. Invoking this on a + * test with children will mark the entire subtree as outdated. + * + * Extensions should generally not override this method. */ - export const testResults: ReadonlyArray; + // todo@api still unsure about this + invalidateResults(): void; + } + /** + * Possible states of tests in a test run. + */ + export enum TestResultState { + // Test will be run, but is not currently running. + Queued = 1, + // Test is currently running + Running = 2, + // Test run has passed + Passed = 3, + // Test run has failed (on an assertion) + Failed = 4, + // Test run has been skipped + Skipped = 5, + // Test run failed for some other reason (compilation error, timeout, etc) + Errored = 6, + } + + //#endregion + + /** + * Namespace for testing functionality. Tests are published by registering + * {@link TestController} instances, then adding {@link TestItem}s. + * Controllers may also describe how to run tests by creating one or more + * {@link TestRunProfile} instances. + */ + export namespace tests { /** - * Event that fires when the {@link testResults} array is updated. - * @stability experimental + * Creates a new test controller. + * + * @param id Identifier for the controller, must be globally unique. + * @param label A human-readable label for the controller. + * @returns An instance of the {@link TestController}. */ - export const onDidChangeTestResults: Event; + export function createTestController(id: string, label: string): TestController; } /** - * @stability experimental + * The kind of executions that {@link TestRunProfile TestRunProfiles} control. */ - export interface TestObserver { + export enum TestRunProfileKind { + Run = 1, + Debug = 2, + Coverage = 3, + } + + /** + * A TestRunProfile describes one way to execute tests in a {@link TestController}. + */ + export interface TestRunProfile { /** - * List of tests returned by test provider for files in the workspace. + * Label shown to the user in the UI. + * + * Note that the label has some significance if the user requests that + * tests be re-run in a certain way. For example, if tests were run + * normally and the user requests to re-run them in debug mode, the editor + * will attempt use a configuration with the same label of the `Debug` + * kind. If there is no such configuration, the default will be used. */ - readonly tests: ReadonlyArray>; + label: string; /** - * An event that fires when an existing test in the collection changes, or - * null if a top-level test was added or removed. When fired, the consumer - * should check the test item and all its children for changes. + * Configures what kind of execution this profile controls. If there + * are no profiles for a kind, it will not be available in the UI. */ - readonly onDidChangeTest: Event; + readonly kind: TestRunProfileKind; /** - * An event that fires when all test providers have signalled that the tests - * the observer references have been discovered. Providers may continue to - * watch for changes and cause {@link onDidChangeTest} to fire as files - * change, until the observer is disposed. + * Controls whether this profile is the default action that will + * be taken when its kind is actioned. For example, if the user clicks + * the generic "run all" button, then the default profile for + * {@link TestRunProfileKind.Run} will be executed, although the + * user can configure this. + */ + isDefault: boolean; + + /** + * If this method is present, a configuration gear will be present in the + * UI, and this method will be invoked when it's clicked. When called, + * you can take other editor actions, such as showing a quick pick or + * opening a configuration file. + */ + configureHandler?: () => void; + + /** + * Handler called to start a test run. When invoked, the function should call + * {@link TestController.createTestRun} at least once, and all test runs + * associated with the request should be created before the function returns + * or the returned promise is resolved. * - * @todo as below + * @param request Request information for the test run. + * @param cancellationToken Token that signals the used asked to abort the + * test run. If cancellation is requested on this token, all {@link TestRun} + * instances associated with the request will be + * automatically cancelled as well. */ - readonly onDidDiscoverInitialTests: Event; + runHandler: (request: TestRunRequest, token: CancellationToken) => Thenable | void; /** - * Dispose of the observer, allowing VS Code to eventually tell test - * providers that they no longer need to update tests. + * Deletes the run profile. */ dispose(): void; } /** - * @stability experimental + * Entry point to discover and execute tests. It contains {@link items} which + * are used to populate the editor UI, and is associated with + * {@link createRunProfile | run profiles} to allow + * for tests to be executed. */ - export interface TestsChangeEvent { + export interface TestController { /** - * List of all tests that are newly added. + * The id of the controller passed in {@link vscode.tests.createTestController}. + * This must be globally unique. */ - readonly added: ReadonlyArray>; + readonly id: string; /** - * List of existing tests that have updated. + * Human-readable label for the test controller. */ - readonly updated: ReadonlyArray>; + label: string; /** - * List of existing tests that have been removed. + * Available test items. Tests in the workspace should be added in this + * collection. The extension controls when to add these, although the + * editor may request children using the {@link resolveHandler}, + * and the extension should add tests for a file when + * {@link vscode.workspace.onDidOpenTextDocument} fires in order for + * decorations for tests within a file to be visible. + * + * Tests in this collection should be watched and updated by the extension + * as files change. See {@link resolveHandler} for details around + * for the lifecycle of watches. */ - readonly removed: ReadonlyArray>; - } + readonly items: TestItemCollection; + + /** + * Creates a profile used for running tests. Extensions must create + * at least one profile in order for tests to be run. + * @param label A human-readable label for this profile. + * @param kind Configures what kind of execution this profile manages. + * @param runHandler Function called to start a test run. + * @param isDefault Whether this is the default action for its kind. + * @returns An instance of a {@link TestRunProfile}, which is automatically + * associated with this controller. + */ + createRunProfile( + label: string, + kind: TestRunProfileKind, + runHandler: (request: TestRunRequest, token: CancellationToken) => Thenable | void, + isDefault?: boolean, + ): TestRunProfile; - /** - * Interface to discover and execute tests. - */ - export interface TestController { /** - * Requests that tests be provided for the given workspace. This will - * be called when tests need to be enumerated for the workspace, such as - * when the user opens the test explorer. + * A function provided by the extension that the editor may call to request + * children of a test item, if the {@link TestItem.canResolveChildren} is + * `true`. When called, the item should discover children and call + * {@link vscode.tests.createTestItem} as children are discovered. + * + * Generally the extension manages the lifecycle of test items, but under + * certain conditions the editor may request the children of a specific + * item to be loaded. For example, if the user requests to re-run tests + * after reloading the editor, the editor may need to call this method + * to resolve the previously-run tests. * - * It's guaranteed that this method will not be called again while - * there is a previous uncancelled call for the given workspace folder. + * The item in the explorer will automatically be marked as "busy" until + * the function returns or the returned thenable resolves. * - * @param workspace The workspace in which to observe tests - * @param cancellationToken Token that signals the used asked to abort the test run. - * @returns the root test item for the workspace + * @param item An unresolved test item for which children are being + * requested, or `undefined` to resolve the controller's initial {@link items}. */ - createWorkspaceTestRoot(workspace: WorkspaceFolder, token: CancellationToken): ProviderResult>; + resolveHandler?: (item: TestItem | undefined) => Thenable | void; /** - * Requests that tests be provided for the given document. This will be - * called when tests need to be enumerated for a single open file, for - * instance by code lens UI. - * - * It's suggested that the provider listen to change events for the text - * document to provide information for tests that might not yet be - * saved. + * Creates a {@link TestRun}. This should be called by the + * {@link TestRunProfile} when a request is made to execute tests, and may + * also be called if a test run is detected externally. Once created, tests + * that are included in the request will be moved into the queued state. * - * If the test system is not able to provide or estimate for tests on a - * per-file basis, this method may not be implemented. In that case, the - * editor will request and use the information from the workspace tree. + * All runs created using the same `request` instance will be grouped + * together. This is useful if, for example, a single suite of tests is + * run on multiple platforms. * - * @param document The document in which to observe tests - * @param cancellationToken Token that signals the used asked to abort the test run. - * @returns the root test item for the document + * @param request Test run request. Only tests inside the `include` may be + * modified, and tests in its `exclude` are ignored. + * @param name The human-readable name of the run. This can be used to + * disambiguate multiple sets of results in a test run. It is useful if + * tests are run across multiple platforms, for example. + * @param persist Whether the results created by the run should be + * persisted in the editor. This may be false if the results are coming from + * a file already saved externally, such as a coverage information file. + * @returns An instance of the {@link TestRun}. It will be considered "running" + * from the moment this method is invoked until {@link TestRun.end} is called. */ - createDocumentTestRoot?(document: TextDocument, token: CancellationToken): ProviderResult>; + createTestRun(request: TestRunRequest, name?: string, persist?: boolean): TestRun; /** - * Starts a test run. When called, the controller should call - * {@link vscode.test.createTestRun}. All tasks associated with the - * run should be created before the function returns or the reutrned - * promise is resolved. + * Creates a new managed {@link TestItem} instance. It can be added into + * the {@link TestItem.children} of an existing item, or into the + * {@link TestController.items}. * - * @param options Options for this test run - * @param cancellationToken Token that signals the used asked to abort the test run. + * @param id Identifier for the TestItem. The test item's ID must be unique + * in the {@link TestItemCollection} it's added to. + * @param label Human-readable label of the test item. + * @param uri URI this TestItem is associated with. May be a file or directory. */ - runTests(options: TestRunRequest, token: CancellationToken): Thenable | void; + createTestItem(id: string, label: string, uri?: Uri): TestItem; + + /** + * Unregisters the test controller, disposing of its associated tests + * and unpersisted results. + */ + dispose(): void; } /** - * Options given to {@link test.runTests}. + * Options given to {@link tests.runTests}. */ - export interface TestRunRequest { + export class TestRunRequest { + /** + * A filter for specific tests to run. If given, the extension should run + * all of the included tests and all their children, excluding any tests + * that appear in {@link TestRunRequest.exclude}. If this property is + * undefined, then the extension should simply run all tests. + * + * The process of running tests should resolve the children of any test + * items who have not yet been resolved. + */ + include?: TestItem[]; + /** - * Array of specific tests to run. The controllers should run all of the - * given tests and all children of the given tests, excluding any tests - * that appear in {@link TestRunRequest.exclude}. + * An array of tests the user has marked as excluded from the test included + * in this run; exclusions should apply after inclusions. + * + * May be omitted if no exclusions were requested. Test controllers should + * not run excluded tests or any children of excluded tests. */ - tests: TestItem[]; + exclude?: TestItem[]; /** - * An array of tests the user has marked as excluded in VS Code. May be - * omitted if no exclusions were requested. Test controllers should not run - * excluded tests or any children of excluded tests. + * The profile used for this request. This will always be defined + * for requests issued from the editor UI, though extensions may + * programmatically create requests not associated with any profile. */ - exclude?: TestItem[]; + profile?: TestRunProfile; /** - * Whether tests in this run should be debugged. + * @param tests Array of specific tests to run, or undefined to run all tests + * @param exclude An array of tests to exclude from the run. + * @param profile The run profile used for this request. */ - debug: boolean; + constructor(include?: readonly TestItem[], exclude?: readonly TestItem[], profile?: TestRunProfile); } /** * Options given to {@link TestController.runTests} */ - export interface TestRun { + export interface TestRun { /** * The human-readable name of the run. This can be used to * disambiguate multiple sets of results in a test run. It is useful if @@ -1141,91 +1263,121 @@ declare module 'vscode' { readonly name?: string; /** - * Updates the state of the test in the run. Calling with method with nodes - * outside the {@link TestRunRequest.tests} or in the - * {@link TestRunRequest.exclude} array will no-op. - * - * @param test The test to update - * @param state The state to assign to the test - * @param duration Optionally sets how long the test took to run + * A cancellation token which will be triggered when the test run is + * canceled from the UI. */ - setState(test: TestItem, state: TestResultState, duration?: number): void; + readonly token: CancellationToken; /** - * Appends a message, such as an assertion error, to the test item. - * - * Calling with method with nodes outside the {@link TestRunRequest.tests} - * or in the {@link TestRunRequest.exclude} array will no-op. - * - * @param test The test to update - * @param state The state to assign to the test - * + * Whether the test run will be persisted across reloads by the editor. + */ + readonly isPersisted: boolean; + + /** + * Indicates a test is queued for later execution. + * @param test Test item to update. + */ + enqueued(test: TestItem): void; + + /** + * Indicates a test has started running. + * @param test Test item to update. + */ + started(test: TestItem): void; + + /** + * Indicates a test has been skipped. + * @param test Test item to update. + */ + skipped(test: TestItem): void; + + /** + * Indicates a test has failed. You should pass one or more + * {@link TestMessage | TestMessages} to describe the failure. + * @param test Test item to update. + * @param messages Messages associated with the test failure. + * @param duration How long the test took to execute, in milliseconds. */ - appendMessage(test: TestItem, message: TestMessage): void; + failed(test: TestItem, message: TestMessage | readonly TestMessage[], duration?: number): void; + + /** + * Indicates a test has passed. + * @param test Test item to update. + * @param duration How long the test took to execute, in milliseconds. + */ + passed(test: TestItem, duration?: number): void; /** * Appends raw output from the test runner. On the user's request, the * output will be displayed in a terminal. ANSI escape sequences, * such as colors and text styles, are supported. * - * @param output Output text to append - * @param associateTo Optionally, associate the given segment of output + * @param output Output text to append. */ appendOutput(output: string): void; /** - * Signals that the end of the test run. Any tests whose states have not - * been updated will be moved into the {@link TestResultState.Unset} state. + * Signals that the end of the test run. Any tests included in the run whose + * states have not been updated will have their state reset. */ end(): void; } /** - * Indicates the the activity state of the {@link TestItem}. + * Collection of test items, found in {@link TestItem.children} and + * {@link TestController.items}. */ - export enum TestItemStatus { + export interface TestItemCollection { /** - * All children of the test item, if any, have been discovered. + * Gets the number of items in the collection. */ - Resolved = 1, + readonly size: number; /** - * The test item may have children who have not been discovered yet. + * Replaces the items stored by the collection. + * @param items Items to store. */ - Pending = 0, - } + replace(items: readonly TestItem[]): void; - /** - * Options initially passed into `vscode.test.createTestItem` - */ - export interface TestItemOptions { /** - * Unique identifier for the TestItem. This is used to correlate - * test results and tests in the document with those in the workspace - * (test explorer). This cannot change for the lifetime of the TestItem. + * Iterate over each entry in this collection. + * + * @param callback Function to execute for each entry. + * @param thisArg The `this` context used when invoking the handler function. */ - id: string; + forEach(callback: (item: TestItem, collection: TestItemCollection) => unknown, thisArg?: unknown): void; /** - * URI this TestItem is associated with. May be a file or directory. + * Adds the test item to the children. If an item with the same ID already + * exists, it'll be replaced. + * @param items Item to add. */ - uri?: Uri; + add(item: TestItem): void; /** - * Display name describing the test item. + * Removes the a single test item from the collection. + * @param itemId Item ID to delete. */ - label: string; + delete(itemId: string): void; + + /** + * Efficiently gets a test item by ID, if it exists, in the children. + * @param itemId Item ID to get. + * @returns The found item, or undefined if it does not exist. + */ + get(itemId: string): TestItem | undefined; } /** * A test item is an item shown in the "test explorer" view. It encompasses - * both a suite and a test, since they have almost or identical capabilities. + * both a suite and a test, since they simiular capabilities. */ - export interface TestItem { + export interface TestItem { /** - * Unique identifier for the TestItem. This is used to correlate + * Identifier for the TestItem. This is used to correlate * test results and tests in the document with those in the workspace - * (test explorer). This must not change for the lifetime of the TestItem. + * (test explorer). This cannot change for the lifetime of the TestItem, + * and must be unique among its parent's direct children. */ readonly id: string; @@ -1235,28 +1387,34 @@ declare module 'vscode' { readonly uri?: Uri; /** - * A mapping of children by ID to the associated TestItem instances. + * The children of this test item. For a test suite, this may contain the + * individual test cases, or nested suites. */ - readonly children: ReadonlyMap>; + readonly children: TestItemCollection; /** - * The parent of this item, if any. Assigned automatically when calling - * {@link TestItem.addChild}. + * The parent of this item. It's set automatically, and is undefined + * top-level items in the {@link TestController.items} and for items that + * aren't yet included in another item's {@link children}. */ - readonly parent?: TestItem; + readonly parent?: TestItem; /** - * Indicates the state of the test item's children. The editor will show - * TestItems in the `Pending` state and with a `resolveHandler` as being - * expandable, and will call the `resolveHandler` to request items. + * Indicates whether this test item may have children discovered by resolving. + * If so, it will be shown as expandable in the Test Explorer view, and + * expanding the item will cause {@link TestController.resolveHandler} + * to be invoked with the item. * - * A TestItem in the `Resolved` state is assumed to have discovered and be - * watching for changes in its children if applicable. TestItems are in the - * `Resolved` state when initially created; if the editor should call - * the `resolveHandler` to discover children, set the state to `Pending` - * after creating the item. + * Default to `false`. */ - status: TestItemStatus; + canResolveChildren: boolean; + + /** + * Controls whether the item is shown as "busy" in the Test Explorer view. + * This is useful for showing status while discovering children. Defaults + * to false. + */ + busy: boolean; /** * Display name describing the test case. @@ -1280,99 +1438,6 @@ declare module 'vscode' { * discovery, such as syntax errors. */ error?: string | MarkdownString; - - /** - * Whether this test item can be run by providing it in the - * {@link TestRunRequest.tests} array. Defaults to `true`. - */ - runnable: boolean; - - /** - * Whether this test item can be debugged by providing it in the - * {@link TestRunRequest.tests} array. Defaults to `false`. - */ - debuggable: boolean; - - /** - * Custom extension data on the item. This data will never be serialized - * or shared outside the extenion who created the item. - */ - data: T; - - /** - * Marks the test as outdated. This can happen as a result of file changes, - * for example. In "auto run" mode, tests that are outdated will be - * automatically rerun after a short delay. Invoking this on a - * test with children will mark the entire subtree as outdated. - * - * Extensions should generally not override this method. - */ - invalidate(): void; - - /** - * A function provided by the extension that the editor may call to request - * children of the item, if the {@link TestItem.status} is `Pending`. - * - * When called, the item should discover tests and call {@link TestItem.addChild}. - * The items should set its {@link TestItem.status} to `Resolved` when - * discovery is finished. - * - * The item should continue watching for changes to the children and - * firing updates until the token is cancelled. The process of watching - * the tests may involve creating a file watcher, for example. After the - * token is cancelled and watching stops, the TestItem should set its - * {@link TestItem.status} back to `Pending`. - * - * The editor will only call this method when it's interested in refreshing - * the children of the item, and will not call it again while there's an - * existing, uncancelled discovery for an item. - * - * @param token Cancellation for the request. Cancellation will be - * requested if the test changes before the previous call completes. - */ - resolveHandler?: (token: CancellationToken) => void; - - /** - * Attaches a child, created from the {@link test.createTestItem} function, - * to this item. A `TestItem` may be a child of at most one other item. - */ - addChild(child: TestItem): void; - - /** - * Removes the test and its children from the tree. Any tokens passed to - * child `resolveHandler` methods will be cancelled. - */ - dispose(): void; - } - - /** - * Possible states of tests in a test run. - */ - export enum TestResultState { - // Initial state - Unset = 0, - // Test will be run, but is not currently running. - Queued = 1, - // Test is currently running - Running = 2, - // Test run has passed - Passed = 3, - // Test run has failed (on an assertion) - Failed = 4, - // Test run has been skipped - Skipped = 5, - // Test run failed for some other reason (compilation error, timeout, etc) - Errored = 6, - } - - /** - * Represents the severity of test messages. - */ - export enum TestMessageSeverity { - Error = 0, - Warning = 1, - Information = 2, - Hint = 3, } /** @@ -1385,11 +1450,6 @@ declare module 'vscode' { */ message: string | MarkdownString; - /** - * Message severity. Defaults to "Error". - */ - severity: TestMessageSeverity; - /** * Expected test output. If given with `actualOutput`, a diff view will be shown. */ @@ -1419,100 +1479,5 @@ declare module 'vscode' { */ constructor(message: string | MarkdownString); } - - /** - * TestResults can be provided to VS Code in {@link test.publishTestResult}, - * or read from it in {@link test.testResults}. - * - * The results contain a 'snapshot' of the tests at the point when the test - * run is complete. Therefore, information such as its {@link Range} may be - * out of date. If the test still exists in the workspace, consumers can use - * its `id` to correlate the result instance with the living test. - * - * @todo coverage and other info may eventually be provided here - */ - export interface TestRunResult { - /** - * Unix milliseconds timestamp at which the test run was completed. - */ - completedAt: number; - - /** - * Optional raw output from the test run. - */ - output?: string; - - /** - * List of test results. The items in this array are the items that - * were passed in the {@link test.runTests} method. - */ - results: ReadonlyArray>; - } - - /** - * A {@link TestItem}-like interface with an associated result, which appear - * or can be provided in {@link TestResult} interfaces. - */ - export interface TestResultSnapshot { - /** - * Unique identifier that matches that of the associated TestItem. - * This is used to correlate test results and tests in the document with - * those in the workspace (test explorer). - */ - readonly id: string; - - /** - * URI this TestItem is associated with. May be a file or file. - */ - readonly uri?: Uri; - - /** - * Display name describing the test case. - */ - readonly label: string; - - /** - * Optional description that appears next to the label. - */ - readonly description?: string; - - /** - * Location of the test item in its `uri`. This is only meaningful if the - * `uri` points to a file. - */ - readonly range?: Range; - - /** - * State of the test in each task. In the common case, a test will only - * be executed in a single task and the length of this array will be 1. - */ - readonly taskStates: ReadonlyArray; - - /** - * Optional list of nested tests for this item. - */ - readonly children: Readonly[]; - } - - export interface TestSnapshoptTaskState { - /** - * Current result of the test. - */ - readonly state: TestResultState; - - /** - * The number of milliseconds the test took to run. This is set once the - * `state` is `Passed`, `Failed`, or `Errored`. - */ - readonly duration?: number; - - /** - * Associated test run message. Can, for example, contain assertion - * failure information if the test fails. - */ - readonly messages: ReadonlyArray; - } - - //#endregion } //#endregion From 77daf3dfbf25058ff408db3f2289b3d6723b98ec Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Thu, 22 Jul 2021 22:12:13 -0700 Subject: [PATCH 13/39] Move test configuration --- .eslintignore | 1 - .../pytest/testConfigurationManager.ts | 10 +++++----- .../unittest/testConfigurationManager.ts | 13 ++++++++----- src/client/testing/configurationFactory.ts | 4 ++-- src/test/testing/configurationFactory.unit.test.ts | 4 ++-- 5 files changed, 17 insertions(+), 15 deletions(-) rename src/client/testing/{ => configuration}/pytest/testConfigurationManager.ts (88%) rename src/client/testing/{ => configuration}/unittest/testConfigurationManager.ts (74%) diff --git a/.eslintignore b/.eslintignore index b0418a03f670..8a42eaabd662 100644 --- a/.eslintignore +++ b/.eslintignore @@ -320,7 +320,6 @@ src/client/language/iterableTextRange.ts src/client/language/unicode.ts src/client/testing/serviceRegistry.ts -src/client/testing/unittest/testConfigurationManager.ts src/client/testing/main.ts src/client/testing/configurationFactory.ts src/client/testing/common/debugLauncher.ts diff --git a/src/client/testing/pytest/testConfigurationManager.ts b/src/client/testing/configuration/pytest/testConfigurationManager.ts similarity index 88% rename from src/client/testing/pytest/testConfigurationManager.ts rename to src/client/testing/configuration/pytest/testConfigurationManager.ts index 4499a0aef84a..89f4246346ef 100644 --- a/src/client/testing/pytest/testConfigurationManager.ts +++ b/src/client/testing/configuration/pytest/testConfigurationManager.ts @@ -1,10 +1,10 @@ import * as path from 'path'; import { QuickPickItem, Uri } from 'vscode'; -import { IFileSystem } from '../../common/platform/types'; -import { Product } from '../../common/types'; -import { IServiceContainer } from '../../ioc/types'; -import { TestConfigurationManager } from '../common/testConfigurationManager'; -import { ITestConfigSettingsService } from '../common/types'; +import { IFileSystem } from '../../../common/platform/types'; +import { Product } from '../../../common/types'; +import { IServiceContainer } from '../../../ioc/types'; +import { TestConfigurationManager } from '../../common/testConfigurationManager'; +import { ITestConfigSettingsService } from '../../common/types'; export class ConfigurationManager extends TestConfigurationManager { constructor(workspace: Uri, serviceContainer: IServiceContainer, cfg?: ITestConfigSettingsService) { diff --git a/src/client/testing/unittest/testConfigurationManager.ts b/src/client/testing/configuration/unittest/testConfigurationManager.ts similarity index 74% rename from src/client/testing/unittest/testConfigurationManager.ts rename to src/client/testing/configuration/unittest/testConfigurationManager.ts index 388656043696..b1482c2a42bc 100644 --- a/src/client/testing/unittest/testConfigurationManager.ts +++ b/src/client/testing/configuration/unittest/testConfigurationManager.ts @@ -1,17 +1,20 @@ import { Uri } from 'vscode'; -import { Product } from '../../common/types'; -import { IServiceContainer } from '../../ioc/types'; -import { TestConfigurationManager } from '../common/testConfigurationManager'; -import { ITestConfigSettingsService } from '../common/types'; +import { Product } from '../../../common/types'; +import { IServiceContainer } from '../../../ioc/types'; +import { TestConfigurationManager } from '../../common/testConfigurationManager'; +import { ITestConfigSettingsService } from '../../common/types'; export class ConfigurationManager extends TestConfigurationManager { constructor(workspace: Uri, serviceContainer: IServiceContainer, cfg?: ITestConfigSettingsService) { super(workspace, Product.unittest, serviceContainer, cfg); } + + // eslint-disable-next-line class-methods-use-this public async requiresUserToConfigure(_wkspace: Uri): Promise { return true; } - public async configure(wkspace: Uri) { + + public async configure(wkspace: Uri): Promise { const args = ['-v']; const subDirs = await this.getTestDirs(wkspace.fsPath); const testDir = await this.selectTestDir(wkspace.fsPath, subDirs); diff --git a/src/client/testing/configurationFactory.ts b/src/client/testing/configurationFactory.ts index 61f830325545..b661a38d5779 100644 --- a/src/client/testing/configurationFactory.ts +++ b/src/client/testing/configurationFactory.ts @@ -7,13 +7,13 @@ import { inject, injectable } from 'inversify'; import { Uri } from 'vscode'; import { Product } from '../common/types'; import { IServiceContainer } from '../ioc/types'; -import * as pytest from './pytest/testConfigurationManager'; +import * as pytest from './configuration/pytest/testConfigurationManager'; import { ITestConfigSettingsService, ITestConfigurationManager, ITestConfigurationManagerFactory, } from './common/types'; -import * as unittest from './unittest/testConfigurationManager'; +import * as unittest from './configuration/unittest/testConfigurationManager'; @injectable() export class TestConfigurationManagerFactory implements ITestConfigurationManagerFactory { diff --git a/src/test/testing/configurationFactory.unit.test.ts b/src/test/testing/configurationFactory.unit.test.ts index 3d0c157d141b..1418147d615c 100644 --- a/src/test/testing/configurationFactory.unit.test.ts +++ b/src/test/testing/configurationFactory.unit.test.ts @@ -12,8 +12,8 @@ import { IServiceContainer } from '../../client/ioc/types'; import { ITestConfigSettingsService, ITestConfigurationManagerFactory } from '../../client/testing/common/types'; import { TestConfigurationManagerFactory } from '../../client/testing/configurationFactory'; import { TEST_OUTPUT_CHANNEL } from '../../client/testing/constants'; -import * as pytest from '../../client/testing/pytest/testConfigurationManager'; -import * as unittest from '../../client/testing/unittest/testConfigurationManager'; +import * as pytest from '../../client/testing/configuration/pytest/testConfigurationManager'; +import * as unittest from '../../client/testing/configuration/unittest/testConfigurationManager'; use(chaiAsPromised); From 2a5f2ef599dcadc1a27a56ce85302b26cb92958f Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Thu, 22 Jul 2021 22:54:34 -0700 Subject: [PATCH 14/39] Fix linting --- .../testing/common/bufferedTestConfigSettingService.ts | 4 ++-- src/client/testing/common/configSettingService.ts | 5 ++--- .../common/services/configSettingService.unit.test.ts | 4 +--- src/test/testing/configuration.unit.test.ts | 4 +--- src/test/testing/serviceRegistry.ts | 5 +---- 5 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/client/testing/common/bufferedTestConfigSettingService.ts b/src/client/testing/common/bufferedTestConfigSettingService.ts index 41cdd1664e4f..35266de38c72 100644 --- a/src/client/testing/common/bufferedTestConfigSettingService.ts +++ b/src/client/testing/common/bufferedTestConfigSettingService.ts @@ -11,7 +11,7 @@ export class BufferedTestConfigSettingsService implements ITestConfigSettingsSer this.ops = []; } - public async updateTestArgs(testDirectory: string | Uri, product: UnitTestProduct, args: string[]):Promise { + public async updateTestArgs(testDirectory: string | Uri, product: UnitTestProduct, args: string[]): Promise { this.ops.push(['updateTestArgs', testDirectory, product, args]); return Promise.resolve(); } @@ -27,7 +27,7 @@ export class BufferedTestConfigSettingsService implements ITestConfigSettingsSer } public async apply(cfg: ITestConfigSettingsService): Promise { - const {ops} = this; + const { ops } = this; this.ops = []; // Note that earlier ops do not get rolled back if a later // one fails. diff --git a/src/client/testing/common/configSettingService.ts b/src/client/testing/common/configSettingService.ts index 7fd26273019a..3ce64f120244 100644 --- a/src/client/testing/common/configSettingService.ts +++ b/src/client/testing/common/configSettingService.ts @@ -29,7 +29,7 @@ export class TestConfigSettingsService implements ITestConfigSettingsService { } // eslint-disable-next-line class-methods-use-this - public getTestEnablingSetting(product: UnitTestProduct):string { + public getTestEnablingSetting(product: UnitTestProduct): string { switch (product) { case Product.unittest: return 'testing.unittestEnabled'; @@ -41,7 +41,7 @@ export class TestConfigSettingsService implements ITestConfigSettingsService { } // eslint-disable-next-line class-methods-use-this - private getTestArgSetting(product: UnitTestProduct):string { + private getTestArgSetting(product: UnitTestProduct): string { switch (product) { case Product.unittest: return 'testing.unittestArgs'; @@ -74,4 +74,3 @@ export class TestConfigSettingsService implements ITestConfigSettingsService { return pythonConfig.update(setting, value); } } - diff --git a/src/test/testing/common/services/configSettingService.unit.test.ts b/src/test/testing/common/services/configSettingService.unit.test.ts index 2de76c874fea..0f5ffc431e4b 100644 --- a/src/test/testing/common/services/configSettingService.unit.test.ts +++ b/src/test/testing/common/services/configSettingService.unit.test.ts @@ -12,9 +12,7 @@ import { Product } from '../../../../client/common/types'; import { getNamesAndValues } from '../../../../client/common/utils/enum'; import { IServiceContainer } from '../../../../client/ioc/types'; import { UNIT_TEST_PRODUCTS } from '../../../../client/testing/common/constants'; -import { - TestConfigSettingsService, -} from '../../../../client/testing/common/configSettingService'; +import { TestConfigSettingsService } from '../../../../client/testing/common/configSettingService'; import { ITestConfigSettingsService, UnitTestProduct } from '../../../../client/testing/common/types'; import { BufferedTestConfigSettingsService } from '../../../../client/testing/common/bufferedTestConfigSettingService'; diff --git a/src/test/testing/configuration.unit.test.ts b/src/test/testing/configuration.unit.test.ts index 51b2d5641df1..fec936a2a21a 100644 --- a/src/test/testing/configuration.unit.test.ts +++ b/src/test/testing/configuration.unit.test.ts @@ -78,9 +78,7 @@ suite('Unit Tests - ConfigurationService', () => { serviceContainer .setup((c) => c.get(typeMoq.It.isValue(ICommandManager))) .returns(() => commands.object); - serviceContainer - .setup((c) => c.get(typeMoq.It.isValue(ITestsHelper))) - .returns(() => new TestsHelper()); + serviceContainer.setup((c) => c.get(typeMoq.It.isValue(ITestsHelper))).returns(() => new TestsHelper()); testConfigService = typeMoq.Mock.ofType( UnitTestConfigurationService, typeMoq.MockBehavior.Loose, diff --git a/src/test/testing/serviceRegistry.ts b/src/test/testing/serviceRegistry.ts index 89c2bf8271ef..ddd1cde115d1 100644 --- a/src/test/testing/serviceRegistry.ts +++ b/src/test/testing/serviceRegistry.ts @@ -9,10 +9,7 @@ import { IProcessServiceFactory } from '../../client/common/process/types'; import { IInterpreterHelper } from '../../client/interpreter/contracts'; import { InterpreterHelper } from '../../client/interpreter/helpers'; import { TestsHelper } from '../../client/testing/common/testUtils'; -import { - ITestsHelper, - IUnitTestSocketServer, -} from '../../client/testing/common/types'; +import { ITestsHelper, IUnitTestSocketServer } from '../../client/testing/common/types'; import { getPythonSemVer } from '../common'; import { IocContainer } from '../serviceRegistry'; import { MockUnitTestSocketServer } from './mocks'; From b678cca8719fdc44b4376e178c8309c17e846b33 Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Thu, 22 Jul 2021 23:03:56 -0700 Subject: [PATCH 15/39] Add news items --- news/1 Enhancements/10898.md | 1 + news/1 Enhancements/15750.md | 1 + news/3 Code Health/16371.md | 1 + 3 files changed, 3 insertions(+) create mode 100644 news/1 Enhancements/10898.md create mode 100644 news/1 Enhancements/15750.md create mode 100644 news/3 Code Health/16371.md diff --git a/news/1 Enhancements/10898.md b/news/1 Enhancements/10898.md new file mode 100644 index 000000000000..c9dd529d808f --- /dev/null +++ b/news/1 Enhancements/10898.md @@ -0,0 +1 @@ +Use VS Code's test UI instead of code lenses above tests. diff --git a/news/1 Enhancements/15750.md b/news/1 Enhancements/15750.md new file mode 100644 index 000000000000..2f0b1c90830d --- /dev/null +++ b/news/1 Enhancements/15750.md @@ -0,0 +1 @@ +Plug into VS Code's Test UI. diff --git a/news/3 Code Health/16371.md b/news/3 Code Health/16371.md new file mode 100644 index 000000000000..868130d7cb6e --- /dev/null +++ b/news/3 Code Health/16371.md @@ -0,0 +1 @@ +Remove nose test support. From 3a28eebb051a3542e6972225124e3e4bd7b33895 Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Thu, 22 Jul 2021 23:42:37 -0700 Subject: [PATCH 16/39] Ensure controller is disposed --- src/client/testing/testController/controller.ts | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/client/testing/testController/controller.ts b/src/client/testing/testController/controller.ts index 69597f4c7e64..4bbe7b782530 100644 --- a/src/client/testing/testController/controller.ts +++ b/src/client/testing/testController/controller.ts @@ -9,27 +9,25 @@ import { TestItem, TestRunRequest, tests, - Disposable, WorkspaceFolder, RelativePattern, TestRunProfileKind, } from 'vscode'; import { IWorkspaceService } from '../../common/application/types'; -import { IConfigurationService, Resource } from '../../common/types'; +import { IConfigurationService, IDisposableRegistry, Resource } from '../../common/types'; import { PYTEST_PROVIDER, UNITTEST_PROVIDER } from '../common/constants'; import { ITestController, ITestFrameworkController } from './common/types'; @injectable() -export class PythonTestController implements ITestController, Disposable { +export class PythonTestController implements ITestController { private readonly testController: TestController; - private readonly disposables: Disposable[] = []; - constructor( @inject(IWorkspaceService) private readonly workspaceService: IWorkspaceService, @inject(IConfigurationService) private readonly configSettings: IConfigurationService, @inject(ITestFrameworkController) @named(PYTEST_PROVIDER) private readonly pytest: ITestFrameworkController, @inject(ITestFrameworkController) @named(UNITTEST_PROVIDER) private readonly unittest: ITestFrameworkController, + @inject(IDisposableRegistry) private readonly disposables: IDisposableRegistry, ) { this.testController = tests.createTestController('python-tests', 'Python Tests'); this.disposables.push(this.testController); @@ -46,10 +44,6 @@ export class PythonTestController implements ITestController, Disposable { this.testController.resolveHandler = this.resolveChildren.bind(this); } - public dispose(): void { - this.disposables.forEach((d) => d.dispose()); - } - public async refreshTestData(uri?: Resource): Promise { const settings = this.configSettings.getSettings(uri); if (settings.testing.pytestEnabled) { From 6ca637a3d88b49490fdad52cbf1ed356ce2a5641 Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Thu, 22 Jul 2021 23:43:06 -0700 Subject: [PATCH 17/39] Tweaks to get testing working on stable. --- src/client/testing/main.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/client/testing/main.ts b/src/client/testing/main.ts index 5f970cde5dcd..0d79db89a134 100644 --- a/src/client/testing/main.ts +++ b/src/client/testing/main.ts @@ -1,7 +1,7 @@ 'use strict'; import { inject, injectable } from 'inversify'; -import { ConfigurationChangeEvent, Disposable, Uri } from 'vscode'; +import { ConfigurationChangeEvent, Disposable, Uri, tests } from 'vscode'; import { IApplicationShell, ICommandManager, IWorkspaceService } from '../common/application/types'; import * as constants from '../common/constants'; import '../common/extensions'; @@ -32,13 +32,15 @@ export class UnitTestManagementService implements IExtensionActivationService, D private activatedOnce: boolean = false; private readonly disposableRegistry: Disposable[]; private workspaceService: IWorkspaceService; - private testController: ITestController; + private testController: ITestController | undefined; private configChangedTimer?: NodeJS.Timer | number; constructor(@inject(IServiceContainer) private serviceContainer: IServiceContainer) { this.disposableRegistry = serviceContainer.get(IDisposableRegistry); this.workspaceService = serviceContainer.get(IWorkspaceService); - this.testController = serviceContainer.get(ITestController); + if (tests && !!tests.createTestController) { + this.testController = serviceContainer.get(ITestController); + } this.disposableRegistry.push(this); } public dispose() { @@ -64,7 +66,7 @@ export class UnitTestManagementService implements IExtensionActivationService, D .filter((w) => eventArgs.affectsConfiguration('python.testing', w.uri)) .map((w) => w.uri); - await Promise.all(changedWorkspaces.map((u) => this.testController.refreshTestData(u))); + await Promise.all(changedWorkspaces.map((u) => this.testController?.refreshTestData(u))); } @captureTelemetry(EventName.UNITTEST_CONFIGURE, undefined, false) @@ -96,13 +98,13 @@ export class UnitTestManagementService implements IExtensionActivationService, D // Ignore the exceptions returned. // This command will be invoked from other places of the extension. this.configureTests(resource).ignoreErrors(); - this.testController.refreshTestData(resource); + this.testController?.refreshTestData(resource); }, ), commandManager.registerCommand( constants.Commands.Test_Refresh, (_, _cmdSource: constants.CommandSource = constants.CommandSource.commandPalette, resource?: Uri) => { - this.testController.refreshTestData(resource); + this.testController?.refreshTestData(resource); }, ), ]; @@ -122,7 +124,7 @@ export class UnitTestManagementService implements IExtensionActivationService, D ); this.disposableRegistry.push( interpreterService.onDidChangeInterpreter(() => { - this.testController.refreshTestData(); + this.testController?.refreshTestData(); }), ); } From f5178587e386fd57e4d2fbd899b4a94babd28f7b Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Fri, 23 Jul 2021 00:41:46 -0700 Subject: [PATCH 18/39] Remove empty file. --- src/client/testing/testController/common/testWorkspace.ts | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/client/testing/testController/common/testWorkspace.ts diff --git a/src/client/testing/testController/common/testWorkspace.ts b/src/client/testing/testController/common/testWorkspace.ts deleted file mode 100644 index e69de29bb2d1..000000000000 From 4d2de7f18c275dc81b1f2157e6ebd41a5af4e05c Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Fri, 23 Jul 2021 09:16:02 -0700 Subject: [PATCH 19/39] Fix some sonar issues --- src/client/testing/common/socketServer.ts | 17 ++++---- .../common/testConfigurationManager.ts | 42 ++++++++----------- src/client/testing/common/testUtils.ts | 1 - src/client/testing/main.ts | 1 - .../common/testItemUtilities.ts | 4 +- .../testController/pytest/pytestController.ts | 1 - .../unittest/unittestController.ts | 4 +- 7 files changed, 29 insertions(+), 41 deletions(-) diff --git a/src/client/testing/common/socketServer.ts b/src/client/testing/common/socketServer.ts index f1cdc9f1f763..554d8c8a0c76 100644 --- a/src/client/testing/common/socketServer.ts +++ b/src/client/testing/common/socketServer.ts @@ -32,7 +32,7 @@ export class UnitTestSocketServer extends EventEmitter implements IUnitTestSocke public stop() { if (this.server) { - this.server!.close(); + this.server.close(); this.server = undefined; } } @@ -41,8 +41,8 @@ export class UnitTestSocketServer extends EventEmitter implements IUnitTestSocke this.ipcBuffer = ''; this.startedDef = createDeferred(); this.server = net.createServer(this.connectionListener.bind(this)); - this.server!.maxConnections = MaxConnections; - this.server!.on('error', (err) => { + this.server.maxConnections = MaxConnections; + this.server.on('error', (err) => { if (this.startedDef) { this.startedDef.reject(err); this.startedDef = undefined; @@ -53,14 +53,14 @@ export class UnitTestSocketServer extends EventEmitter implements IUnitTestSocke if (host.trim().length === 0) { host = 'localhost'; } - this.server!.on('connection', (socket: net.Socket) => { + this.server.on('connection', (socket: net.Socket) => { this.emit('start', socket); }); - this.server!.listen(port, host, () => { - this.startedDef!.resolve((this.server!.address() as net.AddressInfo).port); + this.server.listen(port, host, () => { + this.startedDef?.resolve((this.server?.address() as net.AddressInfo).port); this.startedDef = undefined; }); - return this.startedDef!.promise; + return this.startedDef?.promise; } private connectionListener(socket: net.Socket) { @@ -114,11 +114,12 @@ export class UnitTestSocketServer extends EventEmitter implements IUnitTestSocke private onCloseSocket() { for (let i = 0, count = this.sockets.length; i < count; i += 1) { const socket = this.sockets[i]; - let destroyedSocketId = false; + if (socket && socket.readable) { continue; } + let destroyedSocketId; if ((socket as any).id) { destroyedSocketId = (socket as any).id; } diff --git a/src/client/testing/common/testConfigurationManager.ts b/src/client/testing/common/testConfigurationManager.ts index 237ab67c29d4..6d0215ee5c58 100644 --- a/src/client/testing/common/testConfigurationManager.ts +++ b/src/client/testing/common/testConfigurationManager.ts @@ -1,5 +1,5 @@ import * as path from 'path'; -import { OutputChannel, QuickPickItem, Uri } from 'vscode'; +import { OutputChannel, QuickPickItem, QuickPickOptions, Uri } from 'vscode'; import { IApplicationShell } from '../../common/application/types'; import { traceInfo } from '../../common/logger'; import { IFileSystem } from '../../common/platform/types'; @@ -77,18 +77,7 @@ export abstract class TestConfigurationManager implements ITestConfigurationMana items = [{ label: '.', description: 'Root directory' }, ...items]; items = customOptions.concat(items); - const def = createDeferred(); - const appShell = this.serviceContainer.get(IApplicationShell); - appShell.showQuickPick(items, options).then((item) => { - if (!item) { - this.handleCancelled(); // This will throw an exception. - return; - } - - def.resolve(item.label); - }); - - return def.promise; + return this.showQuickPick(items, options); } protected selectTestFilePattern(): Promise { @@ -106,18 +95,7 @@ export abstract class TestConfigurationManager implements ITestConfigurationMana { label: '*test*.py', description: "Python Files containing the word 'test'" }, ]; - const def = createDeferred(); - const appShell = this.serviceContainer.get(IApplicationShell); - appShell.showQuickPick(items, options).then((item) => { - if (!item) { - this.handleCancelled(); // This will throw an exception. - return; - } - - def.resolve(item.label); - }); - - return def.promise; + return this.showQuickPick(items, options); } protected getTestDirs(rootDir: string): Promise { @@ -134,4 +112,18 @@ export abstract class TestConfigurationManager implements ITestConfigurationMana return possibleTestDirs; }); } + + private showQuickPick(items: QuickPickItem[], options: QuickPickOptions): Promise { + const def = createDeferred(); + const appShell = this.serviceContainer.get(IApplicationShell); + appShell.showQuickPick(items, options).then((item) => { + if (!item) { + this.handleCancelled(); // This will throw an exception. + return; + } + + def.resolve(item.label); + }); + return def.promise; + } } diff --git a/src/client/testing/common/testUtils.ts b/src/client/testing/common/testUtils.ts index 81902482342f..9e7238eed35f 100644 --- a/src/client/testing/common/testUtils.ts +++ b/src/client/testing/common/testUtils.ts @@ -40,7 +40,6 @@ export function convertFileToPackage(filePath: string): string { @injectable() export class TestsHelper implements ITestsHelper { - constructor() {} public parseProviderName(product: UnitTestProduct): TestProvider { switch (product) { case Product.pytest: diff --git a/src/client/testing/main.ts b/src/client/testing/main.ts index 0d79db89a134..700bdf2a2889 100644 --- a/src/client/testing/main.ts +++ b/src/client/testing/main.ts @@ -91,7 +91,6 @@ export class UnitTestManagementService implements IExtensionActivationService, D const commandManager = this.serviceContainer.get(ICommandManager); const disposables = [ - // TODO: register command to refresh test data commandManager.registerCommand( constants.Commands.Tests_Configure, (_, _cmdSource: constants.CommandSource = constants.CommandSource.commandPalette, resource?: Uri) => { diff --git a/src/client/testing/testController/common/testItemUtilities.ts b/src/client/testing/testController/common/testItemUtilities.ts index 24c20937238d..82b65ec74c10 100644 --- a/src/client/testing/testController/common/testItemUtilities.ts +++ b/src/client/testing/testController/common/testItemUtilities.ts @@ -408,7 +408,7 @@ function updateTestItemFromRawDataInternal( rawTestCaseNodes .filter((r) => !existingNodes.includes(r.id)) .forEach((r) => { - const childItem = createTestCaseItem(testController, idToRawData, testRoot, r as RawTest); + const childItem = createTestCaseItem(testController, idToRawData, testRoot, r); item.children.add(childItem); }); @@ -427,7 +427,7 @@ function updateTestItemFromRawDataInternal( if (rawCaseData.length === 1) { // This is a test case node - updateTestCaseItem(item, idToRawData, testRoot, rawCaseData[0] as RawTest); + updateTestCaseItem(item, idToRawData, testRoot, rawCaseData[0]); return; } diff --git a/src/client/testing/testController/pytest/pytestController.ts b/src/client/testing/testController/pytest/pytestController.ts index d42283b5f243..88a122d2017f 100644 --- a/src/client/testing/testController/pytest/pytestController.ts +++ b/src/client/testing/testController/pytest/pytestController.ts @@ -235,7 +235,6 @@ export class PytestController implements ITestFrameworkController { let runRequest = request; if (!runRequest.include) { const testItem = testController.items.get(workspace.uri.fsPath); - if (testItem) { runRequest = new TestRunRequest([testItem], undefined, request.profile); } diff --git a/src/client/testing/testController/unittest/unittestController.ts b/src/client/testing/testController/unittest/unittestController.ts index 2bfc6e642c88..482249a21d72 100644 --- a/src/client/testing/testController/unittest/unittestController.ts +++ b/src/client/testing/testController/unittest/unittestController.ts @@ -201,17 +201,15 @@ for s in generate_test_cases(suite): let runRequest = request; if (!runRequest.include) { const testItem = testController.items.get(workspace.uri.fsPath); - if (testItem) { runRequest = new TestRunRequest([testItem], undefined, request.profile); } } const settings = this.configService.getSettings(workspace.uri); - return this.runner.runTests( testController, - request, + runRequest, debug, { workspaceFolder: workspace.uri, From 2252a5ce6d4965d84ee3e229dfe2a026752237be Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Fri, 23 Jul 2021 12:56:47 -0700 Subject: [PATCH 20/39] Fix issue with pytest crashing on discovery --- package.json | 5 +++ package.nls.json | 1 + .../testController/pytest/pytestController.ts | 30 +++++++------ .../unittest/unittestController.ts | 42 ++++++++++++------- 4 files changed, 51 insertions(+), 27 deletions(-) diff --git a/package.json b/package.json index 159fd3776eb4..c1a72e7946ce 100644 --- a/package.json +++ b/package.json @@ -366,6 +366,11 @@ "icon": "$(refresh)", "title": "%python.command.python.refreshTensorBoard.title%" }, + { + "category": "Python", + "command": "python.refreshTests", + "title": "%python.command.python.refreshTests.title%" + }, { "category": "Python", "command": "python.reportIssue", diff --git a/package.nls.json b/package.nls.json index ce1a7f3242c0..01cab0aa620f 100644 --- a/package.nls.json +++ b/package.nls.json @@ -14,6 +14,7 @@ "python.command.python.viewOutput.title": "Show Output", "python.command.python.viewLanguageServerOutput.title": "Show Language Server Output", "python.command.python.configureTests.title": "Configure Tests", + "python.command.python.refreshTests.title": "Refresh Tests", "python.command.python.execSelectionInTerminal.title": "Run Selection/Line in Python Terminal", "python.command.python.execSelectionInDjangoShell.title": "Run Selection/Line in Django Shell", "python.command.python.goToPythonObject.title": "Go to Python Object", diff --git a/src/client/testing/testController/pytest/pytestController.ts b/src/client/testing/testController/pytest/pytestController.ts index 88a122d2017f..d94a090a24c8 100644 --- a/src/client/testing/testController/pytest/pytestController.ts +++ b/src/client/testing/testController/pytest/pytestController.ts @@ -6,6 +6,7 @@ import { flatten } from 'lodash'; import * as path from 'path'; import { CancellationToken, TestItem, TestRunRequest, Uri, TestController, WorkspaceFolder } from 'vscode'; import { IWorkspaceService } from '../../../common/application/types'; +import { traceError } from '../../../common/logger'; import { runAdapter } from '../../../common/process/internal/scripts/testing_tools'; import { IConfigurationService } from '../../../common/types'; import { createDeferred, Deferred } from '../../../common/utils/async'; @@ -147,9 +148,6 @@ export class PytestController implements ITestFrameworkController { return previous.promise; } - const deferred = createDeferred(); - this.discovering.set(workspace.uri.fsPath, deferred); - const settings = this.configService.getSettings(workspace.uri); const options: TestDiscoveryOptions = { workspaceFolder: workspace.uri, @@ -181,16 +179,24 @@ export class PytestController implements ITestFrameworkController { })); } - // This is where we execute pytest discovery via a common helper. - const rawTestData = flatten( - await Promise.all(discoveryRunOptions.map((o) => this.discoveryHelper.runTestDiscovery(o))), - ); - this.testData.set(workspace.uri.fsPath, rawTestData); - - // Discovery has finished running we have the raw test data at this point. - deferred.resolve(); - this.discovering.delete(workspace.uri.fsPath); + const deferred = createDeferred(); + this.discovering.set(workspace.uri.fsPath, deferred); + let rawTestData: RawDiscoveredTests[] = []; + try { + // This is where we execute pytest discovery via a common helper. + rawTestData = flatten( + await Promise.all(discoveryRunOptions.map((o) => this.discoveryHelper.runTestDiscovery(o))), + ); + this.testData.set(workspace.uri.fsPath, rawTestData); + deferred.resolve(); + } catch (ex) { + traceError('Error discovering pytest tests: ', ex); + deferred.reject(ex); + } finally { + // Discovery has finished running we have the raw test data at this point. + this.discovering.delete(workspace.uri.fsPath); + } const root = rawTestData.length === 1 ? rawTestData[0].root : workspace.uri.fsPath; const workspaceNode = testController.items.get(root); if (workspaceNode) { diff --git a/src/client/testing/testController/unittest/unittestController.ts b/src/client/testing/testController/unittest/unittestController.ts index 482249a21d72..15ed16b17831 100644 --- a/src/client/testing/testController/unittest/unittestController.ts +++ b/src/client/testing/testController/unittest/unittestController.ts @@ -25,6 +25,7 @@ import { getWorkspaceNode, updateTestItemFromRawData, } from '../common/testItemUtilities'; +import { traceError } from '../../../common/logger'; @injectable() export class UnittestController implements ITestFrameworkController { @@ -94,9 +95,6 @@ export class UnittestController implements ITestFrameworkController { return previous.promise; } - const deferred = createDeferred(); - this.discovering.set(workspace.uri.fsPath, deferred); - const settings = this.configService.getSettings(workspace.uri); const options: TestDiscoveryOptions = { workspaceFolder: workspace.uri, @@ -144,18 +142,32 @@ for s in generate_test_cases(suite): outChannel: options.outChannel, }; - const content = await this.discoveryRunner.run(UNITTEST_PROVIDER, runOptions); - const rawTestData = await testDiscoveryParser( - options.cwd, - path.isAbsolute(startDir) ? path.relative(options.cwd, startDir) : startDir, - getTestIds(content), - options.token, - ); - this.testData.set(workspace.uri.fsPath, rawTestData); - - // Discovery has finished running we have the raw test data at this point. - deferred.resolve(); - this.discovering.delete(workspace.uri.fsPath); + const deferred = createDeferred(); + this.discovering.set(workspace.uri.fsPath, deferred); + + let rawTestData: RawDiscoveredTests | undefined; + try { + const content = await this.discoveryRunner.run(UNITTEST_PROVIDER, runOptions); + rawTestData = await testDiscoveryParser( + options.cwd, + path.isAbsolute(startDir) ? path.relative(options.cwd, startDir) : startDir, + getTestIds(content), + options.token, + ); + this.testData.set(workspace.uri.fsPath, rawTestData); + deferred.resolve(); + } catch (ex) { + traceError('Error discovering unittest tests: ', ex); + deferred.reject(ex); + } finally { + // Discovery has finished running we have the raw test data at this point. + this.discovering.delete(workspace.uri.fsPath); + } + + if (!rawTestData) { + // No test data is available + return Promise.resolve(); + } const workspaceNode = testController.items.get(rawTestData.root); if (workspaceNode) { From 1eaff491e33ef2d311a1ba0389162c089d75619c Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Fri, 23 Jul 2021 16:18:07 -0700 Subject: [PATCH 21/39] Add force refresh on interpreter change. --- src/client/testing/main.ts | 21 ++++---- .../testing/testController/common/types.ts | 6 ++- .../testing/testController/controller.ts | 52 +++++++++++++++---- .../testController/pytest/pytestController.ts | 3 +- .../unittest/unittestController.ts | 3 +- 5 files changed, 60 insertions(+), 25 deletions(-) diff --git a/src/client/testing/main.ts b/src/client/testing/main.ts index 700bdf2a2889..96709a2c07e0 100644 --- a/src/client/testing/main.ts +++ b/src/client/testing/main.ts @@ -16,6 +16,7 @@ import { ITestConfigurationService, ITestsHelper } from './common/types'; import { ITestingService } from './types'; import { IExtensionActivationService } from '../activation/types'; import { ITestController } from './testController/common/types'; +import { traceVerbose } from '../common/logger'; @injectable() export class TestingService implements ITestingService { @@ -87,28 +88,27 @@ export class UnitTestManagementService implements IExtensionActivationService, D } public registerCommands(): void { - const disposablesRegistry = this.serviceContainer.get(IDisposableRegistry); const commandManager = this.serviceContainer.get(ICommandManager); - const disposables = [ + this.disposableRegistry.push( commandManager.registerCommand( constants.Commands.Tests_Configure, (_, _cmdSource: constants.CommandSource = constants.CommandSource.commandPalette, resource?: Uri) => { // Ignore the exceptions returned. // This command will be invoked from other places of the extension. this.configureTests(resource).ignoreErrors(); - this.testController?.refreshTestData(resource); + traceVerbose('Testing: Trigger refresh after config change'); + this.testController?.refreshTestData(resource, { forceRefresh: true }); }, ), commandManager.registerCommand( constants.Commands.Test_Refresh, (_, _cmdSource: constants.CommandSource = constants.CommandSource.commandPalette, resource?: Uri) => { - this.testController?.refreshTestData(resource); + traceVerbose('Testing: Manually triggered test refresh'); + this.testController?.refreshTestData(resource, { forceRefresh: true }); }, ), - ]; - - disposablesRegistry.push(...disposables); + ); } public registerHandlers() { @@ -120,10 +120,9 @@ export class UnitTestManagementService implements IExtensionActivationService, D } this.configChangedTimer = setTimeout(() => this.configurationChangeHandler(e), 1000); }), - ); - this.disposableRegistry.push( - interpreterService.onDidChangeInterpreter(() => { - this.testController?.refreshTestData(); + interpreterService.onDidChangeInterpreter(async () => { + traceVerbose('Testing: Trigerred refresh due to interpreter change.'); + await this.testController?.refreshTestData(undefined, { forceRefresh: true }); }), ); } diff --git a/src/client/testing/testController/common/types.ts b/src/client/testing/testController/common/types.ts index 4d46a612f956..d8f59a4dcc36 100644 --- a/src/client/testing/testController/common/types.ts +++ b/src/client/testing/testController/common/types.ts @@ -30,15 +30,17 @@ export interface ITestDiscoveryHelper { runTestDiscovery(options: TestDiscoveryOptions): Promise; } +export type TestRefreshOptions = { forceRefresh: boolean }; + export const ITestController = Symbol('ITestController'); export interface ITestController { - refreshTestData(resource?: Uri): Promise; + refreshTestData(resource?: Uri, options?: TestRefreshOptions): Promise; } export const ITestFrameworkController = Symbol('ITestFrameworkController'); export interface ITestFrameworkController { resolveChildren(testController: TestController, item: TestItem): Promise; - refreshTestData(testController: TestController, resource?: Uri): Promise; + refreshTestData(testController: TestController, resource?: Uri, token?: CancellationToken): Promise; runTests( testController: TestController, request: TestRunRequest, diff --git a/src/client/testing/testController/controller.ts b/src/client/testing/testController/controller.ts index 4bbe7b782530..ef4676c0bdb5 100644 --- a/src/client/testing/testController/controller.ts +++ b/src/client/testing/testController/controller.ts @@ -12,16 +12,20 @@ import { WorkspaceFolder, RelativePattern, TestRunProfileKind, + CancellationTokenSource, } from 'vscode'; import { IWorkspaceService } from '../../common/application/types'; +import { traceVerbose } from '../../common/logger'; import { IConfigurationService, IDisposableRegistry, Resource } from '../../common/types'; import { PYTEST_PROVIDER, UNITTEST_PROVIDER } from '../common/constants'; -import { ITestController, ITestFrameworkController } from './common/types'; +import { ITestController, ITestFrameworkController, TestRefreshOptions } from './common/types'; @injectable() export class PythonTestController implements ITestController { private readonly testController: TestController; + private refreshCancellation: CancellationTokenSource; + constructor( @inject(IWorkspaceService) private readonly workspaceService: IWorkspaceService, @inject(IConfigurationService) private readonly configSettings: IConfigurationService, @@ -29,6 +33,7 @@ export class PythonTestController implements ITestController { @inject(ITestFrameworkController) @named(UNITTEST_PROVIDER) private readonly unittest: ITestFrameworkController, @inject(IDisposableRegistry) private readonly disposables: IDisposableRegistry, ) { + this.refreshCancellation = new CancellationTokenSource(); this.testController = tests.createTestController('python-tests', 'Python Tests'); this.disposables.push(this.testController); @@ -44,19 +49,26 @@ export class PythonTestController implements ITestController { this.testController.resolveHandler = this.resolveChildren.bind(this); } - public async refreshTestData(uri?: Resource): Promise { + public async refreshTestData(uri?: Resource, options?: TestRefreshOptions): Promise { + traceVerbose(`Testing: Refreshing test data for ${uri?.fsPath}`); + if (options?.forceRefresh) { + this.refreshCancellation.cancel(); + this.refreshCancellation.dispose(); + this.refreshCancellation = new CancellationTokenSource(); + } const settings = this.configSettings.getSettings(uri); if (settings.testing.pytestEnabled) { - return this.pytest.refreshTestData(this.testController, uri); + return this.pytest.refreshTestData(this.testController, uri, this.refreshCancellation.token); } if (settings.testing.unittestEnabled) { - return this.unittest.refreshTestData(this.testController, uri); + return this.unittest.refreshTestData(this.testController, uri, this.refreshCancellation.token); } return Promise.resolve(); } private async resolveChildren(item: TestItem | undefined): Promise { if (item) { + traceVerbose(`Testing: Resolving item ${item.id}`); const settings = this.configSettings.getSettings(item.uri); if (settings.testing.pytestEnabled) { return this.pytest.resolveChildren(this.testController, item); @@ -65,6 +77,7 @@ export class PythonTestController implements ITestController { return this.unittest.resolveChildren(this.testController, item); } } else { + traceVerbose('Testing: Setting up test resolver'); this.watchForTestChanges(); const workspaces: readonly WorkspaceFolder[] = this.workspaceService.workspaceFolders || []; await Promise.all(workspaces.map((workspace) => this.refreshTestData(workspace.uri))); @@ -103,6 +116,7 @@ export class PythonTestController implements ITestController { for (const workspace of workspaces) { const settings = this.configSettings.getSettings(workspace.uri); if (settings.testing.autoTestDiscoverOnSaveEnabled) { + traceVerbose(`Testing: Setting up watcher for ${workspace.uri.fsPath}`); this.watchForSettingsChanges(workspace); this.watchForTestContentChanges(workspace); } @@ -114,9 +128,18 @@ export class PythonTestController implements ITestController { const watcher = this.workspaceService.createFileSystemWatcher(pattern); this.disposables.push(watcher); - watcher.onDidChange((uri) => this.refreshTestData(uri)); - watcher.onDidCreate((uri) => this.refreshTestData(uri)); - watcher.onDidDelete((uri) => this.refreshTestData(uri)); + watcher.onDidChange((uri) => { + traceVerbose(`Testing: Trigger refresh after change in ${uri.fsPath}`); + this.refreshTestData(uri); + }); + watcher.onDidCreate((uri) => { + traceVerbose(`Testing: Trigger refresh after creating ${uri.fsPath}`); + this.refreshTestData(uri); + }); + watcher.onDidDelete((uri) => { + traceVerbose(`Testing: Trigger refresh after deleting in ${uri.fsPath}`); + this.refreshTestData(uri); + }); } private watchForTestContentChanges(workspace: WorkspaceFolder): void { @@ -124,8 +147,17 @@ export class PythonTestController implements ITestController { const watcher = this.workspaceService.createFileSystemWatcher(pattern); this.disposables.push(watcher); - watcher.onDidChange((uri) => this.refreshTestData(uri)); - watcher.onDidCreate((uri) => this.refreshTestData(uri)); - watcher.onDidDelete((uri) => this.refreshTestData(uri)); + watcher.onDidChange((uri) => { + traceVerbose(`Testing: Trigger refresh after change in ${uri.fsPath}`); + this.refreshTestData(uri); + }); + watcher.onDidCreate((uri) => { + traceVerbose(`Testing: Trigger refresh after creating ${uri.fsPath}`); + this.refreshTestData(uri); + }); + watcher.onDidDelete((uri) => { + traceVerbose(`Testing: Trigger refresh after deleting in ${uri.fsPath}`); + this.refreshTestData(uri); + }); } } diff --git a/src/client/testing/testController/pytest/pytestController.ts b/src/client/testing/testController/pytest/pytestController.ts index d94a090a24c8..d306dd6b0f23 100644 --- a/src/client/testing/testController/pytest/pytestController.ts +++ b/src/client/testing/testController/pytest/pytestController.ts @@ -138,7 +138,7 @@ export class PytestController implements ITestFrameworkController { return Promise.resolve(); } - public async refreshTestData(testController: TestController, uri: Uri): Promise { + public async refreshTestData(testController: TestController, uri: Uri, token?: CancellationToken): Promise { const workspace = this.workspaceService.getWorkspaceFolder(uri); if (workspace) { // Discovery is expensive. So if it is already running then use the promise @@ -154,6 +154,7 @@ export class PytestController implements ITestFrameworkController { cwd: settings.testing.cwd ?? workspace.uri.fsPath, args: settings.testing.pytestArgs, ignoreCache: true, + token, }; // Get individual test directories selected by the user. diff --git a/src/client/testing/testController/unittest/unittestController.ts b/src/client/testing/testController/unittest/unittestController.ts index 15ed16b17831..5991948b6964 100644 --- a/src/client/testing/testController/unittest/unittestController.ts +++ b/src/client/testing/testController/unittest/unittestController.ts @@ -85,7 +85,7 @@ export class UnittestController implements ITestFrameworkController { return Promise.resolve(); } - public async refreshTestData(testController: TestController, uri: Uri): Promise { + public async refreshTestData(testController: TestController, uri: Uri, token?: CancellationToken): Promise { const workspace = this.workspaceService.getWorkspaceFolder(uri); if (workspace) { // Discovery is expensive. So if it is already running then use the promise @@ -101,6 +101,7 @@ export class UnittestController implements ITestFrameworkController { cwd: settings.testing.cwd ?? workspace.uri.fsPath, args: settings.testing.unittestArgs, ignoreCache: true, + token, }; const startDir = unittestGetTestFolders(options.args)[0]; From eb370dd407ca5b0341bf5b2b61941cf21b2a67e8 Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Sun, 25 Jul 2021 21:37:01 -0700 Subject: [PATCH 22/39] Handle large number of FS events --- package.json | 2 +- src/client/common/utils/delayTrigger.ts | 68 ++++++++++++++++++ .../testing/testController/controller.ts | 70 ++++++++++++------- 3 files changed, 114 insertions(+), 26 deletions(-) create mode 100644 src/client/common/utils/delayTrigger.ts diff --git a/package.json b/package.json index c1a72e7946ce..7871ddd93ac4 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "theme": "dark" }, "engines": { - "vscode": "^1.57.0" + "vscode": "^1.59.0" }, "keywords": [ "python", diff --git a/src/client/common/utils/delayTrigger.ts b/src/client/common/utils/delayTrigger.ts new file mode 100644 index 000000000000..77b2ad446885 --- /dev/null +++ b/src/client/common/utils/delayTrigger.ts @@ -0,0 +1,68 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { clearTimeout, setTimeout } from 'timers'; +import { Disposable } from 'vscode'; +import { traceVerbose } from '../logger'; + +/* eslint-disable @typescript-eslint/no-explicit-any */ + +export interface IDelayedTrigger { + trigger(...args: any[]): void; +} + +/** + * DelayedTrigger can be used to prevent some action being called too + * often within a given duration. This was added to support file watching + * for tests. Suppose we are watching for *.py files. If the user installs + * and new package or runs formatter on the entire workspace. This could + * trigger too many discover test calls which are expensive. We could + * debounce, but the limitation with debounce is that it might run before + * the package has finished installing. With delayed trigger approach + * we delay running until @param ms amount of time has passed. + */ +export class DelayedTrigger implements IDelayedTrigger, Disposable { + private timerId: NodeJS.Timeout | undefined; + + private triggeredCounter = 0; + + private calledCounter = 0; + + /** + * Delay calling the function in callback for a predefined amount of time. + * @param callback : Callback that should be called after some time has passed. + * @param ms : Amount of time after the last trigger that the call to callback + * should be delayed. + * @param name : A name for the callback action. This will be used in logs. + */ + constructor( + private readonly callback: (...args: any[]) => void, + private readonly ms: number, + private readonly name: string, + ) {} + + public trigger(...args: unknown[]): void { + this.triggeredCounter += 1; + if (this.timerId) { + clearTimeout(this.timerId); + } + + this.timerId = setTimeout( + (...args2: any[]) => { + this.calledCounter += 1; + traceVerbose( + `Delay Trigger[${this.name}]: triggered=${this.triggeredCounter}, called=${this.calledCounter}`, + ); + this.callback(...args2); + }, + this.ms, + ...args, + ); + } + + public dispose(): void { + if (this.timerId) { + clearTimeout(this.timerId); + } + } +} diff --git a/src/client/testing/testController/controller.ts b/src/client/testing/testController/controller.ts index ef4676c0bdb5..38c5e46da026 100644 --- a/src/client/testing/testController/controller.ts +++ b/src/client/testing/testController/controller.ts @@ -13,10 +13,12 @@ import { RelativePattern, TestRunProfileKind, CancellationTokenSource, + Disposable, } from 'vscode'; import { IWorkspaceService } from '../../common/application/types'; import { traceVerbose } from '../../common/logger'; import { IConfigurationService, IDisposableRegistry, Resource } from '../../common/types'; +import { DelayedTrigger, IDelayedTrigger } from '../../common/utils/delayTrigger'; import { PYTEST_PROVIDER, UNITTEST_PROVIDER } from '../common/constants'; import { ITestController, ITestFrameworkController, TestRefreshOptions } from './common/types'; @@ -24,6 +26,8 @@ import { ITestController, ITestFrameworkController, TestRefreshOptions } from '. export class PythonTestController implements ITestController { private readonly testController: TestController; + private readonly delayTrigger: IDelayedTrigger & Disposable; + private refreshCancellation: CancellationTokenSource; constructor( @@ -34,9 +38,13 @@ export class PythonTestController implements ITestController { @inject(IDisposableRegistry) private readonly disposables: IDisposableRegistry, ) { this.refreshCancellation = new CancellationTokenSource(); + this.testController = tests.createTestController('python-tests', 'Python Tests'); this.disposables.push(this.testController); + this.delayTrigger = new DelayedTrigger(this.refreshTestData.bind(this), 250, 'Refresh Test Data'); + this.disposables.push(this.delayTrigger); + this.disposables.push( this.testController.createRunProfile('Run Tests', TestRunProfileKind.Run, this.runTests.bind(this), true), this.testController.createRunProfile( @@ -128,36 +136,48 @@ export class PythonTestController implements ITestController { const watcher = this.workspaceService.createFileSystemWatcher(pattern); this.disposables.push(watcher); - watcher.onDidChange((uri) => { - traceVerbose(`Testing: Trigger refresh after change in ${uri.fsPath}`); - this.refreshTestData(uri); - }); - watcher.onDidCreate((uri) => { - traceVerbose(`Testing: Trigger refresh after creating ${uri.fsPath}`); - this.refreshTestData(uri); - }); - watcher.onDidDelete((uri) => { - traceVerbose(`Testing: Trigger refresh after deleting in ${uri.fsPath}`); - this.refreshTestData(uri); - }); + this.disposables.push( + watcher.onDidChange((uri) => { + traceVerbose(`Testing: Trigger refresh after change in ${uri.fsPath}`); + this.delayTrigger.trigger(uri); + }), + ); + this.disposables.push( + watcher.onDidCreate((uri) => { + traceVerbose(`Testing: Trigger refresh after creating ${uri.fsPath}`); + this.delayTrigger.trigger(uri); + }), + ); + this.disposables.push( + watcher.onDidDelete((uri) => { + traceVerbose(`Testing: Trigger refresh after deleting in ${uri.fsPath}`); + this.delayTrigger.trigger(uri); + }), + ); } private watchForTestContentChanges(workspace: WorkspaceFolder): void { - const pattern = new RelativePattern(workspace, '**/*test*.py'); + const pattern = new RelativePattern(workspace, '**/*.py'); const watcher = this.workspaceService.createFileSystemWatcher(pattern); this.disposables.push(watcher); - watcher.onDidChange((uri) => { - traceVerbose(`Testing: Trigger refresh after change in ${uri.fsPath}`); - this.refreshTestData(uri); - }); - watcher.onDidCreate((uri) => { - traceVerbose(`Testing: Trigger refresh after creating ${uri.fsPath}`); - this.refreshTestData(uri); - }); - watcher.onDidDelete((uri) => { - traceVerbose(`Testing: Trigger refresh after deleting in ${uri.fsPath}`); - this.refreshTestData(uri); - }); + this.disposables.push( + watcher.onDidChange((uri) => { + traceVerbose(`Testing: Trigger refresh after change in ${uri.fsPath}`); + this.delayTrigger.trigger(uri); + }), + ); + this.disposables.push( + watcher.onDidCreate((uri) => { + traceVerbose(`Testing: Trigger refresh after creating ${uri.fsPath}`); + this.delayTrigger.trigger(uri); + }), + ); + this.disposables.push( + watcher.onDidDelete((uri) => { + traceVerbose(`Testing: Trigger refresh after deleting in ${uri.fsPath}`); + this.delayTrigger.trigger(uri); + }), + ); } } From c4b4f496b29ca2e6e5f517bf18bbc91987ee5a78 Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Sun, 25 Jul 2021 23:05:50 -0700 Subject: [PATCH 23/39] Simplify triggering test refresh on config change --- package.json | 3 +- src/client/testing/main.ts | 27 ++++++------- .../testing/testController/controller.ts | 40 ++++++++++++------- 3 files changed, 39 insertions(+), 31 deletions(-) diff --git a/package.json b/package.json index 7871ddd93ac4..5703b10ce45a 100644 --- a/package.json +++ b/package.json @@ -1884,8 +1884,7 @@ "viewsWelcome": [ { "view": "testing", - "contents": "Configure a test framework to see your tests here.\n[Configure Python Tests](command:python.configureTests)", - "when": "!testsDiscovered" + "contents": "Configure a test framework to see your tests here.\n[Configure Python Tests](command:python.configureTests)" } ], "yamlValidation": [ diff --git a/src/client/testing/main.ts b/src/client/testing/main.ts index 96709a2c07e0..312348c3946a 100644 --- a/src/client/testing/main.ts +++ b/src/client/testing/main.ts @@ -17,6 +17,7 @@ import { ITestingService } from './types'; import { IExtensionActivationService } from '../activation/types'; import { ITestController } from './testController/common/types'; import { traceVerbose } from '../common/logger'; +import { DelayedTrigger, IDelayedTrigger } from '../common/utils/delayTrigger'; @injectable() export class TestingService implements ITestingService { @@ -29,12 +30,12 @@ export class TestingService implements ITestingService { } @injectable() -export class UnitTestManagementService implements IExtensionActivationService, Disposable { +export class UnitTestManagementService implements IExtensionActivationService { private activatedOnce: boolean = false; private readonly disposableRegistry: Disposable[]; private workspaceService: IWorkspaceService; private testController: ITestController | undefined; - private configChangedTimer?: NodeJS.Timer | number; + private configChangeTrigger: IDelayedTrigger; constructor(@inject(IServiceContainer) private serviceContainer: IServiceContainer) { this.disposableRegistry = serviceContainer.get(IDisposableRegistry); @@ -42,13 +43,14 @@ export class UnitTestManagementService implements IExtensionActivationService, D if (tests && !!tests.createTestController) { this.testController = serviceContainer.get(ITestController); } - this.disposableRegistry.push(this); - } - public dispose() { - if (this.configChangedTimer) { - clearTimeout(this.configChangedTimer as any); - this.configChangedTimer = undefined; - } + + const trigger = new DelayedTrigger( + this.configurationChangeHandler.bind(this), + 500, + 'Test Configuration Change', + ); + this.configChangeTrigger = trigger; + this.disposableRegistry.push(trigger); } public async activate(): Promise { @@ -115,13 +117,10 @@ export class UnitTestManagementService implements IExtensionActivationService, D const interpreterService = this.serviceContainer.get(IInterpreterService); this.disposableRegistry.push( this.workspaceService.onDidChangeConfiguration((e) => { - if (this.configChangedTimer) { - clearTimeout(this.configChangedTimer as any); - } - this.configChangedTimer = setTimeout(() => this.configurationChangeHandler(e), 1000); + this.configChangeTrigger.trigger(e); }), interpreterService.onDidChangeInterpreter(async () => { - traceVerbose('Testing: Trigerred refresh due to interpreter change.'); + traceVerbose('Testing: Triggered refresh due to interpreter change.'); await this.testController?.refreshTestData(undefined, { forceRefresh: true }); }), ); diff --git a/src/client/testing/testController/controller.ts b/src/client/testing/testController/controller.ts index 38c5e46da026..d85bbdc8d58f 100644 --- a/src/client/testing/testController/controller.ts +++ b/src/client/testing/testController/controller.ts @@ -13,7 +13,6 @@ import { RelativePattern, TestRunProfileKind, CancellationTokenSource, - Disposable, } from 'vscode'; import { IWorkspaceService } from '../../common/application/types'; import { traceVerbose } from '../../common/logger'; @@ -26,7 +25,7 @@ import { ITestController, ITestFrameworkController, TestRefreshOptions } from '. export class PythonTestController implements ITestController { private readonly testController: TestController; - private readonly delayTrigger: IDelayedTrigger & Disposable; + private readonly refreshData: IDelayedTrigger; private refreshCancellation: CancellationTokenSource; @@ -42,8 +41,9 @@ export class PythonTestController implements ITestController { this.testController = tests.createTestController('python-tests', 'Python Tests'); this.disposables.push(this.testController); - this.delayTrigger = new DelayedTrigger(this.refreshTestData.bind(this), 250, 'Refresh Test Data'); - this.disposables.push(this.delayTrigger); + const delayTrigger = new DelayedTrigger(this.refreshTestDataInternal.bind(this), 250, 'Refresh Test Data'); + this.disposables.push(delayTrigger); + this.refreshData = delayTrigger; this.disposables.push( this.testController.createRunProfile('Run Tests', TestRunProfileKind.Run, this.runTests.bind(this), true), @@ -55,15 +55,26 @@ export class PythonTestController implements ITestController { ), ); this.testController.resolveHandler = this.resolveChildren.bind(this); + + this.watchForTestChanges(); } - public async refreshTestData(uri?: Resource, options?: TestRefreshOptions): Promise { - traceVerbose(`Testing: Refreshing test data for ${uri?.fsPath}`); + public refreshTestData(uri?: Resource, options?: TestRefreshOptions): Promise { if (options?.forceRefresh) { this.refreshCancellation.cancel(); this.refreshCancellation.dispose(); this.refreshCancellation = new CancellationTokenSource(); + traceVerbose('Testing: Forcing test data refresh'); + return this.refreshTestDataInternal(uri); } + + this.refreshData.trigger(uri); + return Promise.resolve(); + } + + private async refreshTestDataInternal(uri?: Resource): Promise { + traceVerbose(`Testing: Refreshing test data for ${uri?.fsPath}`); + const settings = this.configSettings.getSettings(uri); if (settings.testing.pytestEnabled) { return this.pytest.refreshTestData(this.testController, uri, this.refreshCancellation.token); @@ -85,10 +96,9 @@ export class PythonTestController implements ITestController { return this.unittest.resolveChildren(this.testController, item); } } else { - traceVerbose('Testing: Setting up test resolver'); - this.watchForTestChanges(); + traceVerbose('Testing: Resolving all workspaces'); const workspaces: readonly WorkspaceFolder[] = this.workspaceService.workspaceFolders || []; - await Promise.all(workspaces.map((workspace) => this.refreshTestData(workspace.uri))); + await Promise.all(workspaces.map((workspace) => this.refreshTestDataInternal(workspace.uri))); } return Promise.resolve(); } @@ -139,19 +149,19 @@ export class PythonTestController implements ITestController { this.disposables.push( watcher.onDidChange((uri) => { traceVerbose(`Testing: Trigger refresh after change in ${uri.fsPath}`); - this.delayTrigger.trigger(uri); + this.refreshData.trigger(uri); }), ); this.disposables.push( watcher.onDidCreate((uri) => { traceVerbose(`Testing: Trigger refresh after creating ${uri.fsPath}`); - this.delayTrigger.trigger(uri); + this.refreshData.trigger(uri); }), ); this.disposables.push( watcher.onDidDelete((uri) => { traceVerbose(`Testing: Trigger refresh after deleting in ${uri.fsPath}`); - this.delayTrigger.trigger(uri); + this.refreshData.trigger(uri); }), ); } @@ -164,19 +174,19 @@ export class PythonTestController implements ITestController { this.disposables.push( watcher.onDidChange((uri) => { traceVerbose(`Testing: Trigger refresh after change in ${uri.fsPath}`); - this.delayTrigger.trigger(uri); + this.refreshData.trigger(uri); }), ); this.disposables.push( watcher.onDidCreate((uri) => { traceVerbose(`Testing: Trigger refresh after creating ${uri.fsPath}`); - this.delayTrigger.trigger(uri); + this.refreshData.trigger(uri); }), ); this.disposables.push( watcher.onDidDelete((uri) => { traceVerbose(`Testing: Trigger refresh after deleting in ${uri.fsPath}`); - this.delayTrigger.trigger(uri); + this.refreshData.trigger(uri); }), ); } From 2115232b3c093d37c6432a6672a4dfac87b534c6 Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Mon, 26 Jul 2021 09:53:36 -0700 Subject: [PATCH 24/39] VS Code API change to support errored state --- .../testing/testController/common/resultsHelper.ts | 6 ++++-- src/client/testing/testController/unittest/runner.ts | 5 ++++- types/vscode.proposed.d.ts | 11 +++++++++++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/client/testing/testController/common/resultsHelper.ts b/src/client/testing/testController/common/resultsHelper.ts index 957840c5962e..f0b2fb8fc7c4 100644 --- a/src/client/testing/testController/common/resultsHelper.ts +++ b/src/client/testing/testController/common/resultsHelper.ts @@ -112,7 +112,7 @@ export async function updateResultFromJunitXml( message.location = new Location(node.uri, node.range); } - runInstance.failed(node, message); + runInstance.errored(node, message); runInstance.appendOutput(text); } else if (result.failure) { failures += 1; @@ -147,10 +147,12 @@ export async function updateResultFromJunitXml( if (node.uri && node.range) { message.location = new Location(node.uri, node.range); } - runInstance.failed(node, message); + runInstance.errored(node, message); } }); + runInstance.appendOutput(`Total number of tests expected to run: ${testCaseNodes.length}\r\n`); + runInstance.appendOutput(`Total number of tests run: ${passed + failures + errors + skipped}\r\n`); runInstance.appendOutput(`Total number of tests passed: ${passed}\r\n`); runInstance.appendOutput(`Total number of tests failed: ${failures}\r\n`); runInstance.appendOutput(`Total number of tests failed with errors: ${errors}\r\n`); diff --git a/src/client/testing/testController/unittest/runner.ts b/src/client/testing/testController/unittest/runner.ts index 673166e0d6ef..c54adac34f81 100644 --- a/src/client/testing/testController/unittest/runner.ts +++ b/src/client/testing/testController/unittest/runner.ts @@ -127,7 +127,7 @@ export class UnittestRunner implements ITestsRunner { message.location = new Location(testCase.uri, testCase.range); } - runInstance.failed(testCase, message); + runInstance.errored(testCase, message); runInstance.appendOutput(text); counts.errored += 1; if (failFast) { @@ -146,6 +146,7 @@ export class UnittestRunner implements ITestsRunner { if (testCase.uri && testCase.range) { message.location = new Location(testCase.uri, testCase.range); } + runInstance.errored(testCase, message); } } }); @@ -209,6 +210,8 @@ export class UnittestRunner implements ITestsRunner { this.server.stop(); } + runInstance.appendOutput(`Total number of tests expected to run: ${testCaseNodes.length}\r\n`); + runInstance.appendOutput(`Total number of tests run: ${counts.total}\r\n`); runInstance.appendOutput(`Total number of tests passed: ${counts.passed}\r\n`); runInstance.appendOutput(`Total number of tests failed: ${counts.failed}\r\n`); runInstance.appendOutput(`Total number of tests failed with errors: ${counts.errored}\r\n`); diff --git a/types/vscode.proposed.d.ts b/types/vscode.proposed.d.ts index 602b8c2d0e50..fc6e2d3a7d71 100644 --- a/types/vscode.proposed.d.ts +++ b/types/vscode.proposed.d.ts @@ -1300,6 +1300,17 @@ declare module 'vscode' { */ failed(test: TestItem, message: TestMessage | readonly TestMessage[], duration?: number): void; + /** + * Indicates a test has errored. You should pass one or more + * {@link TestMessage | TestMessages} to describe the failure. This differs + * from the "failed" state in that it indicates a test that couldn't be + * executed at all, from a compilation error for example. + * @param test Test item to update. + * @param messages Messages associated with the test failure. + * @param duration How long the test took to execute, in milliseconds. + */ + errored(test: TestItem, message: TestMessage | readonly TestMessage[], duration?: number): void; + /** * Indicates a test has passed. * @param test Test item to update. From 644f4a1846239f2094e633d8647b0bc0b5ad6996 Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Mon, 26 Jul 2021 14:24:01 -0700 Subject: [PATCH 25/39] Ensure skipped status is set on unittest tests --- src/client/testing/testController/unittest/runner.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/client/testing/testController/unittest/runner.ts b/src/client/testing/testController/unittest/runner.ts index c54adac34f81..82cfa140178e 100644 --- a/src/client/testing/testController/unittest/runner.ts +++ b/src/client/testing/testController/unittest/runner.ts @@ -104,7 +104,9 @@ export class UnittestRunner implements ITestsRunner { runInstance.appendOutput(text); counts.passed += 1; } else if (data.outcome === 'failed') { - const traceback = data.traceback.splitLines({ trim: false, removeEmptyEntries: true }).join('\r\n'); + const traceback = data.traceback + ? data.traceback.splitLines({ trim: false, removeEmptyEntries: true }).join('\r\n') + : ''; const text = `${rawTestCase.rawId} Failed: ${data.message}\r\n${traceback}\r\n`; const message = new TestMessage(text); @@ -119,7 +121,9 @@ export class UnittestRunner implements ITestsRunner { stopTesting = true; } } else if (data.outcome === 'error') { - const traceback = data.traceback.splitLines({ trim: false, removeEmptyEntries: true }).join('\r\n'); + const traceback = data.traceback + ? data.traceback.splitLines({ trim: false, removeEmptyEntries: true }).join('\r\n') + : ''; const text = `${rawTestCase.rawId} Failed with Error: ${data.message}\r\n${traceback}\r\n`; const message = new TestMessage(text); @@ -134,7 +138,9 @@ export class UnittestRunner implements ITestsRunner { stopTesting = true; } } else if (data.outcome === 'skipped') { - const traceback = data.traceback.splitLines({ trim: false, removeEmptyEntries: true }).join('\r\n'); + const traceback = data.traceback + ? data.traceback.splitLines({ trim: false, removeEmptyEntries: true }).join('\r\n') + : ''; const text = `${rawTestCase.rawId} Skipped: ${data.message}\r\n${traceback}\r\n`; runInstance.skipped(testCase); runInstance.appendOutput(text); From 4a236858813ee65109453d3ab4a15fe71fa719ed Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Mon, 26 Jul 2021 16:25:45 -0700 Subject: [PATCH 26/39] Adding code review suggestions Co-authored-by: Kim-Adeline Miguel <51720070+kimadeline@users.noreply.github.com> --- src/client/common/utils/delayTrigger.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/client/common/utils/delayTrigger.ts b/src/client/common/utils/delayTrigger.ts index 77b2ad446885..fa7a8ab0b369 100644 --- a/src/client/common/utils/delayTrigger.ts +++ b/src/client/common/utils/delayTrigger.ts @@ -15,7 +15,7 @@ export interface IDelayedTrigger { * DelayedTrigger can be used to prevent some action being called too * often within a given duration. This was added to support file watching * for tests. Suppose we are watching for *.py files. If the user installs - * and new package or runs formatter on the entire workspace. This could + * a new package or runs a formatter on the entire workspace. This could * trigger too many discover test calls which are expensive. We could * debounce, but the limitation with debounce is that it might run before * the package has finished installing. With delayed trigger approach @@ -48,15 +48,14 @@ export class DelayedTrigger implements IDelayedTrigger, Disposable { } this.timerId = setTimeout( - (...args2: any[]) => { + () => { this.calledCounter += 1; traceVerbose( `Delay Trigger[${this.name}]: triggered=${this.triggeredCounter}, called=${this.calledCounter}`, ); - this.callback(...args2); + this.callback(...args); }, - this.ms, - ...args, + this.ms ); } From 9fd86ffb94cb2161ec5ba4765e5ab8f38663bb2c Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Mon, 26 Jul 2021 16:28:21 -0700 Subject: [PATCH 27/39] Fix package json encoding issue --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5703b10ce45a..93849041e11b 100644 --- a/package.json +++ b/package.json @@ -164,7 +164,7 @@ { "id": "python.learnMore", "title": "Learn more", - "description": "� Explore all the features the Python extension has to offer by looking for \"Python\" in the [Command Palette](command:workbench.action.showCommands).\n� [Sign up](https://aka.ms/python-vscode-mailinglist) for tips and tutorials through our mailing list.\n� Explore more features in our [Tutorials](https://aka.ms/AA8dqti) or check [Documentation](https://aka.ms/AA8dxwy) for tips and troubleshooting.\n� Take a look at our [Release Notes](https://aka.ms/AA8dxtb) to learn more about the latest features.", + "description": "- Explore all the features the Python extension has to offer by looking for \"Python\" in the [Command Palette](command:workbench.action.showCommands).\n- [Sign up](https://aka.ms/python-vscode-mailinglist) for tips and tutorials through our mailing list.\n- Explore more features in our [Tutorials](https://aka.ms/AA8dqti) or check [Documentation](https://aka.ms/AA8dxwy) for tips and troubleshooting.\n� Take a look at our [Release Notes](https://aka.ms/AA8dxtb) to learn more about the latest features.", "media": { "image": "resources/walkthrough/python-docs-learn-more.png", "altText": "Documentation page for Python in VS Code" From c07318f12de6c9eeb2114222bd241a14c3d2dd20 Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Tue, 27 Jul 2021 22:02:39 -0700 Subject: [PATCH 28/39] Fix bad package.json merge --- package.json | 5 ----- 1 file changed, 5 deletions(-) diff --git a/package.json b/package.json index 93849041e11b..eb747c6673ae 100644 --- a/package.json +++ b/package.json @@ -1794,11 +1794,6 @@ "category": "Python", "command": "python.launchTensorBoard" }, - { - "category": "Python", - "command": "python.startPage.open", - "title": "%python.command.python.startPage.open.title%" - }, { "category": "Python", "command": "python.switchOffInsidersChannel", From 1be740ee4d1fe2ce42f0db1ea86d18aeb46f5036 Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Tue, 27 Jul 2021 22:03:13 -0700 Subject: [PATCH 29/39] Fix issues with multi-root workspace runs --- .../testController/pytest/pytestController.ts | 12 +++++++++--- src/client/testing/testController/unittest/runner.ts | 6 +++++- .../testController/unittest/unittestController.ts | 12 +++++++++--- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/client/testing/testController/pytest/pytestController.ts b/src/client/testing/testController/pytest/pytestController.ts index d306dd6b0f23..1da6ae7ea2c2 100644 --- a/src/client/testing/testController/pytest/pytestController.ts +++ b/src/client/testing/testController/pytest/pytestController.ts @@ -241,9 +241,15 @@ export class PytestController implements ITestFrameworkController { ): Promise { let runRequest = request; if (!runRequest.include) { - const testItem = testController.items.get(workspace.uri.fsPath); - if (testItem) { - runRequest = new TestRunRequest([testItem], undefined, request.profile); + const testItems: TestItem[] = []; + testController.items.forEach((i) => { + const w = this.workspaceService.getWorkspaceFolder(i.uri); + if (w?.uri.fsPath === workspace.uri.fsPath) { + testItems.push(i); + } + }); + if (testItems.length > 0) { + runRequest = new TestRunRequest(testItems, undefined, request.profile); } } diff --git a/src/client/testing/testController/unittest/runner.ts b/src/client/testing/testController/unittest/runner.ts index 82cfa140178e..766af3681610 100644 --- a/src/client/testing/testController/unittest/runner.ts +++ b/src/client/testing/testController/unittest/runner.ts @@ -44,7 +44,11 @@ export class UnittestRunner implements ITestsRunner { debug, }; - const runInstance = testController.createTestRun(request); + const runInstance = testController.createTestRun( + request, + `Running Tests for Workspace ${runOptions.workspaceFolder.fsPath}`, + true, + ); const dispose = options.token.onCancellationRequested(() => { runInstance.end(); }); diff --git a/src/client/testing/testController/unittest/unittestController.ts b/src/client/testing/testController/unittest/unittestController.ts index 5991948b6964..5954dbaa4831 100644 --- a/src/client/testing/testController/unittest/unittestController.ts +++ b/src/client/testing/testController/unittest/unittestController.ts @@ -213,9 +213,15 @@ for s in generate_test_cases(suite): ): Promise { let runRequest = request; if (!runRequest.include) { - const testItem = testController.items.get(workspace.uri.fsPath); - if (testItem) { - runRequest = new TestRunRequest([testItem], undefined, request.profile); + const testItems: TestItem[] = []; + testController.items.forEach((i) => { + const w = this.workspaceService.getWorkspaceFolder(i.uri); + if (w?.uri.fsPath === workspace.uri.fsPath) { + testItems.push(i); + } + }); + if (testItems.length > 0) { + runRequest = new TestRunRequest(testItems, undefined, request.profile); } } From 31f0b5af50bd043201620a162dad4367da2d833d Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Wed, 28 Jul 2021 08:56:36 -0700 Subject: [PATCH 30/39] Tweak multi-root support and failed test reruns --- .../testing/testController/common/types.ts | 25 ++-- .../testing/testController/controller.ts | 109 ++++++++++++++---- .../testController/pytest/pytestController.ts | 33 +----- .../testing/testController/pytest/runner.ts | 29 ++--- .../testing/testController/unittest/runner.ts | 39 ++----- .../unittest/unittestController.ts | 29 +---- 6 files changed, 132 insertions(+), 132 deletions(-) diff --git a/src/client/testing/testController/common/types.ts b/src/client/testing/testController/common/types.ts index d8f59a4dcc36..ea3b15b8c22c 100644 --- a/src/client/testing/testController/common/types.ts +++ b/src/client/testing/testController/common/types.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import { CancellationToken, TestController, TestItem, TestRunRequest, Uri, WorkspaceFolder } from 'vscode'; +import { CancellationToken, TestController, TestItem, TestRun, TestRunProfileKind, Uri, WorkspaceFolder } from 'vscode'; import { TestDiscoveryOptions } from '../../common/types'; export type TestRunInstanceOptions = TestRunOptions & { @@ -37,28 +37,23 @@ export interface ITestController { refreshTestData(resource?: Uri, options?: TestRefreshOptions): Promise; } +export interface ITestRun { + includes: TestItem[]; + excludes: TestItem[]; + runKind: TestRunProfileKind; + runInstance: TestRun; +} + export const ITestFrameworkController = Symbol('ITestFrameworkController'); export interface ITestFrameworkController { resolveChildren(testController: TestController, item: TestItem): Promise; refreshTestData(testController: TestController, resource?: Uri, token?: CancellationToken): Promise; - runTests( - testController: TestController, - request: TestRunRequest, - debug: boolean, - workspace: WorkspaceFolder, - token: CancellationToken, - ): Promise; + runTests(testRun: ITestRun, workspace: WorkspaceFolder, token: CancellationToken): Promise; } export const ITestsRunner = Symbol('ITestsRunner'); export interface ITestsRunner { - runTests( - testController: TestController, - request: TestRunRequest, - debug: boolean, - options: TestRunOptions, - idToRawData: Map, - ): Promise; + runTests(testRun: ITestRun, options: TestRunOptions, idToRawData: Map): Promise; } export type TestRunOptions = { diff --git a/src/client/testing/testController/controller.ts b/src/client/testing/testController/controller.ts index d85bbdc8d58f..382860f2a80a 100644 --- a/src/client/testing/testController/controller.ts +++ b/src/client/testing/testController/controller.ts @@ -13,12 +13,14 @@ import { RelativePattern, TestRunProfileKind, CancellationTokenSource, + Uri, } from 'vscode'; import { IWorkspaceService } from '../../common/application/types'; import { traceVerbose } from '../../common/logger'; import { IConfigurationService, IDisposableRegistry, Resource } from '../../common/types'; import { DelayedTrigger, IDelayedTrigger } from '../../common/utils/delayTrigger'; import { PYTEST_PROVIDER, UNITTEST_PROVIDER } from '../common/constants'; +import { getNodeByUri } from './common/testItemUtilities'; import { ITestController, ITestFrameworkController, TestRefreshOptions } from './common/types'; @injectable() @@ -41,7 +43,16 @@ export class PythonTestController implements ITestController { this.testController = tests.createTestController('python-tests', 'Python Tests'); this.disposables.push(this.testController); - const delayTrigger = new DelayedTrigger(this.refreshTestDataInternal.bind(this), 250, 'Refresh Test Data'); + const delayTrigger = new DelayedTrigger( + (uri: Uri, invalidate: boolean) => { + this.refreshTestDataInternal(uri); + if (invalidate) { + this.invalidateTests(uri); + } + }, + 250, // Delay running the refresh by 250 ms + 'Refresh Test Data', + ); this.disposables.push(delayTrigger); this.refreshData = delayTrigger; @@ -68,7 +79,7 @@ export class PythonTestController implements ITestController { return this.refreshTestDataInternal(uri); } - this.refreshData.trigger(uri); + this.refreshData.trigger(uri, false); return Promise.resolve(); } @@ -114,19 +125,76 @@ export class PythonTestController implements ITestController { } else { (this.workspaceService.workspaceFolders || []).forEach((w) => workspaces.push(w)); } - const debug = request.profile?.kind === TestRunProfileKind.Debug; - await Promise.all( - workspaces.map((workspace) => { - const settings = this.configSettings.getSettings(workspace.uri); - if (settings.testing.pytestEnabled) { - return this.pytest.runTests(this.testController, request, debug, workspace, token); - } - if (settings.testing.unittestEnabled) { - return this.unittest.runTests(this.testController, request, debug, workspace, token); - } - return Promise.resolve(); - }), + const runInstance = this.testController.createTestRun( + request, + `Running Tests for Workspace(s): ${workspaces.map((w) => w.uri.fsPath).join(';')}`, + true, ); + const dispose = token.onCancellationRequested(() => { + runInstance.end(); + }); + + try { + await Promise.all( + workspaces.map((workspace) => { + const testItems: TestItem[] = []; + // If the run request includes test items then collect only items that belong to + // `workspace`. If there are no items in the run request then just run the `workspace` + // root test node. Include will be `undefined` in the "run all" scenario. + (request.include ?? this.testController.items).forEach((i: TestItem) => { + const w = this.workspaceService.getWorkspaceFolder(i.uri); + if (w?.uri.fsPath === workspace.uri.fsPath) { + testItems.push(i); + } + }); + + if (testItems.length > 0) { + const settings = this.configSettings.getSettings(workspace.uri); + if (settings.testing.pytestEnabled) { + return this.pytest.runTests( + { + includes: testItems, + excludes: request.exclude ?? [], + runKind: request.profile?.kind ?? TestRunProfileKind.Run, + runInstance, + }, + workspace, + token, + ); + } + if (settings.testing.unittestEnabled) { + return this.unittest.runTests( + { + includes: testItems, + excludes: request.exclude ?? [], + runKind: request.profile?.kind ?? TestRunProfileKind.Run, + runInstance, + }, + workspace, + token, + ); + } + } + + return Promise.resolve(); + }), + ); + } finally { + runInstance.appendOutput(`Finished running tests!\r\n`); + runInstance.end(); + dispose.dispose(); + } + } + + private invalidateTests(uri: Uri) { + this.testController.items.forEach((root) => { + const item = getNodeByUri(root, uri); + if (item && !!item.invalidateResults) { + // Minimize invalidating to test case nodes for the test file where + // the change occurred + item.invalidateResults(); + } + }); } private watchForTestChanges(): void { @@ -149,19 +217,19 @@ export class PythonTestController implements ITestController { this.disposables.push( watcher.onDidChange((uri) => { traceVerbose(`Testing: Trigger refresh after change in ${uri.fsPath}`); - this.refreshData.trigger(uri); + this.refreshData.trigger(uri, false); }), ); this.disposables.push( watcher.onDidCreate((uri) => { traceVerbose(`Testing: Trigger refresh after creating ${uri.fsPath}`); - this.refreshData.trigger(uri); + this.refreshData.trigger(uri, false); }), ); this.disposables.push( watcher.onDidDelete((uri) => { traceVerbose(`Testing: Trigger refresh after deleting in ${uri.fsPath}`); - this.refreshData.trigger(uri); + this.refreshData.trigger(uri, false); }), ); } @@ -174,19 +242,20 @@ export class PythonTestController implements ITestController { this.disposables.push( watcher.onDidChange((uri) => { traceVerbose(`Testing: Trigger refresh after change in ${uri.fsPath}`); - this.refreshData.trigger(uri); + // We want to invalidate tests for code change + this.refreshData.trigger(uri, true); }), ); this.disposables.push( watcher.onDidCreate((uri) => { traceVerbose(`Testing: Trigger refresh after creating ${uri.fsPath}`); - this.refreshData.trigger(uri); + this.refreshData.trigger(uri, false); }), ); this.disposables.push( watcher.onDidDelete((uri) => { traceVerbose(`Testing: Trigger refresh after deleting in ${uri.fsPath}`); - this.refreshData.trigger(uri); + this.refreshData.trigger(uri, false); }), ); } diff --git a/src/client/testing/testController/pytest/pytestController.ts b/src/client/testing/testController/pytest/pytestController.ts index 1da6ae7ea2c2..393d51162b83 100644 --- a/src/client/testing/testController/pytest/pytestController.ts +++ b/src/client/testing/testController/pytest/pytestController.ts @@ -4,7 +4,7 @@ import { inject, injectable, named } from 'inversify'; import { flatten } from 'lodash'; import * as path from 'path'; -import { CancellationToken, TestItem, TestRunRequest, Uri, TestController, WorkspaceFolder } from 'vscode'; +import { CancellationToken, TestItem, Uri, TestController, WorkspaceFolder } from 'vscode'; import { IWorkspaceService } from '../../../common/application/types'; import { traceError } from '../../../common/logger'; import { runAdapter } from '../../../common/process/internal/scripts/testing_tools'; @@ -25,6 +25,7 @@ import { ITestsRunner, TestData, RawDiscoveredTests, + ITestRun, } from '../common/types'; import { preparePytestArgumentsForDiscovery, pytestGetTestFolders } from './arguments'; @@ -79,8 +80,8 @@ export class PytestController implements ITestFrameworkController { item.description = workspace.uri.fsPath; // To figure out which top level nodes have to removed. First we get all the - // existing nodes. Then if they have data we keep thoese nodes, Nodes with - // node data will be removed after we check the raw data. + // existing nodes. Then if they have data we keep those nodes, Nodes without + // data will be removed after we check the raw data. let subRootWithNoData: string[] = []; item.children.forEach((c) => subRootWithNoData.push(c.id)); @@ -232,32 +233,10 @@ export class PytestController implements ITestFrameworkController { return Promise.resolve(); } - public runTests( - testController: TestController, - request: TestRunRequest, - debug: boolean, - workspace: WorkspaceFolder, - token: CancellationToken, - ): Promise { - let runRequest = request; - if (!runRequest.include) { - const testItems: TestItem[] = []; - testController.items.forEach((i) => { - const w = this.workspaceService.getWorkspaceFolder(i.uri); - if (w?.uri.fsPath === workspace.uri.fsPath) { - testItems.push(i); - } - }); - if (testItems.length > 0) { - runRequest = new TestRunRequest(testItems, undefined, request.profile); - } - } - + public runTests(testRun: ITestRun, workspace: WorkspaceFolder, token: CancellationToken): Promise { const settings = this.configService.getSettings(workspace.uri); return this.runner.runTests( - testController, - runRequest, - debug, + testRun, { workspaceFolder: workspace.uri, cwd: settings.testing.cwd ?? workspace.uri.fsPath, diff --git a/src/client/testing/testController/pytest/runner.ts b/src/client/testing/testController/pytest/runner.ts index 19ad32c22b56..f4790fbe74f1 100644 --- a/src/client/testing/testController/pytest/runner.ts +++ b/src/client/testing/testController/pytest/runner.ts @@ -2,7 +2,7 @@ // Licensed under the MIT License. import { inject, injectable, named } from 'inversify'; -import { Disposable, TestController, TestItem, TestRun, TestRunRequest } from 'vscode'; +import { Disposable, TestItem, TestRun, TestRunProfileKind } from 'vscode'; import { IOutputChannel } from '../../../common/types'; import { PYTEST_PROVIDER } from '../../common/constants'; import { ITestDebugLauncher, ITestRunner, LaunchOptions, Options } from '../../common/types'; @@ -11,7 +11,7 @@ import { filterArguments, getOptionValues } from '../common/argumentsHelper'; import { createTemporaryFile } from '../common/externalDependencies'; import { updateResultFromJunitXml } from '../common/resultsHelper'; import { getTestCaseNodes } from '../common/testItemUtilities'; -import { ITestsRunner, TestData, TestRunInstanceOptions, TestRunOptions } from '../common/types'; +import { ITestRun, ITestsRunner, TestData, TestRunInstanceOptions, TestRunOptions } from '../common/types'; import { removePositionalFoldersAndFiles } from './arguments'; const JunitXmlArgOld = '--junitxml'; @@ -36,31 +36,24 @@ export class PytestRunner implements ITestsRunner { ) {} public async runTests( - testController: TestController, - request: TestRunRequest, - debug: boolean, + testRun: ITestRun, options: TestRunOptions, idToRawData: Map, ): Promise { const runOptions: TestRunInstanceOptions = { ...options, - exclude: request.exclude, - debug, + exclude: testRun.excludes, + debug: testRun.runKind === TestRunProfileKind.Debug, }; - const runInstance = testController.createTestRun( - request, - `Running Tests for Workspace ${runOptions.workspaceFolder.fsPath}`, - true, - ); + try { await Promise.all( - (request.include ?? []).map((testNode) => this.runTest(testNode, runInstance, runOptions, idToRawData)), + testRun.includes.map((testNode) => + this.runTest(testNode, testRun.runInstance, runOptions, idToRawData), + ), ); } catch (ex) { - runInstance.appendOutput(`Error while running tests:\r\n${ex}\r\n\r\n`); - } finally { - runInstance.appendOutput(`Finished running tests!\r\n`); - runInstance.end(); + testRun.runInstance.appendOutput(`Error while running tests:\r\n${ex}\r\n\r\n`); } } @@ -70,7 +63,7 @@ export class PytestRunner implements ITestsRunner { options: TestRunInstanceOptions, idToRawData: Map, ): Promise { - runInstance.appendOutput(`Running tests: ${testNode.label}\r\n`); + runInstance.appendOutput(`Running tests (pytest): ${testNode.id}\r\n`); // VS Code API requires that we set the run state on the leaf nodes. The state of the // parent nodes are computed based on the state of child nodes. diff --git a/src/client/testing/testController/unittest/runner.ts b/src/client/testing/testController/unittest/runner.ts index 766af3681610..2925ba50823f 100644 --- a/src/client/testing/testController/unittest/runner.ts +++ b/src/client/testing/testController/unittest/runner.ts @@ -2,7 +2,7 @@ // Licensed under the MIT License. import { injectable, inject, named } from 'inversify'; -import { Location, TestController, TestItem, TestMessage, TestRun, TestRunRequest } from 'vscode'; +import { Location, TestItem, TestMessage, TestRun, TestRunProfileKind } from 'vscode'; import { traceError, traceInfo } from '../../../common/logger'; import * as internalScripts from '../../../common/process/internal/scripts'; import { IOutputChannel } from '../../../common/types'; @@ -12,7 +12,7 @@ import { UNITTEST_PROVIDER } from '../../common/constants'; import { ITestRunner, ITestDebugLauncher, IUnitTestSocketServer, LaunchOptions, Options } from '../../common/types'; import { TEST_OUTPUT_CHANNEL } from '../../constants'; import { getTestCaseNodes } from '../common/testItemUtilities'; -import { ITestsRunner, TestData, TestRunInstanceOptions, TestRunOptions } from '../common/types'; +import { ITestRun, ITestsRunner, TestData, TestRunInstanceOptions, TestRunOptions } from '../common/types'; import { getTestRunArgs } from './arguments'; interface ITestData { @@ -32,47 +32,32 @@ export class UnittestRunner implements ITestsRunner { ) {} public async runTests( - testController: TestController, - request: TestRunRequest, - debug: boolean, + testRun: ITestRun, options: TestRunOptions, idToRawData: Map, ): Promise { const runOptions: TestRunInstanceOptions = { ...options, - exclude: request.exclude, - debug, + exclude: testRun.excludes, + debug: testRun.runKind === TestRunProfileKind.Debug, }; - const runInstance = testController.createTestRun( - request, - `Running Tests for Workspace ${runOptions.workspaceFolder.fsPath}`, - true, - ); - const dispose = options.token.onCancellationRequested(() => { - runInstance.end(); - }); try { - await Promise.all( - (request.include ?? []).map((testNode) => this.runTest(testNode, runInstance, runOptions, idToRawData)), - ); + await this.runTest(testRun.includes, testRun.runInstance, runOptions, idToRawData); } catch (ex) { - runInstance.appendOutput(`Error while running tests:\r\n${ex}\r\n\r\n`); - } finally { - runInstance.appendOutput(`Finished running tests!\r\n`); - runInstance.end(); - dispose.dispose(); + testRun.runInstance.appendOutput(`Error while running tests:\r\n${ex}\r\n\r\n`); } } private async runTest( - testNode: TestItem, + testNodes: TestItem[], runInstance: TestRun, options: TestRunInstanceOptions, idToRawData: Map, ): Promise { - runInstance.appendOutput(`Running tests: ${testNode.label}\r\n`); - const testCaseNodes = getTestCaseNodes(testNode); + runInstance.appendOutput(`Running tests (unittest): ${testNodes.map((t) => t.id).join(' ; ')}\r\n`); + const testCaseNodes: TestItem[] = []; + testNodes.forEach((t) => testCaseNodes.push(...getTestCaseNodes(t))); const tested: string[] = []; const counts = { @@ -204,7 +189,7 @@ export class UnittestRunner implements ITestsRunner { if (stopTesting || options.token.isCancellationRequested) { break; } - + runInstance.appendOutput(`Running tests: ${testCaseNode.id}\r\n`); const rawTestCaseNode = idToRawData.get(testCaseNode.id); if (rawTestCaseNode) { // VS Code API requires that we set the run state on the leaf nodes. The state of the diff --git a/src/client/testing/testController/unittest/unittestController.ts b/src/client/testing/testController/unittest/unittestController.ts index 5954dbaa4831..cacaa8a086d7 100644 --- a/src/client/testing/testController/unittest/unittestController.ts +++ b/src/client/testing/testController/unittest/unittestController.ts @@ -3,7 +3,7 @@ import * as path from 'path'; import { inject, injectable, named } from 'inversify'; -import { CancellationToken, TestController, TestItem, TestRunRequest, Uri, WorkspaceFolder } from 'vscode'; +import { CancellationToken, TestController, TestItem, Uri, WorkspaceFolder } from 'vscode'; import { IWorkspaceService } from '../../../common/application/types'; import { IConfigurationService } from '../../../common/types'; import { createDeferred, Deferred } from '../../../common/utils/async'; @@ -11,6 +11,7 @@ import { UNITTEST_PROVIDER } from '../../common/constants'; import { ITestRunner, Options, TestDiscoveryOptions } from '../../common/types'; import { ITestFrameworkController, + ITestRun, ITestsRunner, RawDiscoveredTests, RawTest, @@ -204,32 +205,10 @@ for s in generate_test_cases(suite): return Promise.resolve(); } - public runTests( - testController: TestController, - request: TestRunRequest, - debug: boolean, - workspace: WorkspaceFolder, - token: CancellationToken, - ): Promise { - let runRequest = request; - if (!runRequest.include) { - const testItems: TestItem[] = []; - testController.items.forEach((i) => { - const w = this.workspaceService.getWorkspaceFolder(i.uri); - if (w?.uri.fsPath === workspace.uri.fsPath) { - testItems.push(i); - } - }); - if (testItems.length > 0) { - runRequest = new TestRunRequest(testItems, undefined, request.profile); - } - } - + public runTests(testRun: ITestRun, workspace: WorkspaceFolder, token: CancellationToken): Promise { const settings = this.configService.getSettings(workspace.uri); return this.runner.runTests( - testController, - runRequest, - debug, + testRun, { workspaceFolder: workspace.uri, cwd: settings.testing.cwd ?? workspace.uri.fsPath, From 1a8799e8c3eddc4f5d1cd5b053492a0349c825aa Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Wed, 28 Jul 2021 11:56:55 -0700 Subject: [PATCH 31/39] Fix package json encoding --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index eb747c6673ae..102379a9d064 100644 --- a/package.json +++ b/package.json @@ -164,7 +164,7 @@ { "id": "python.learnMore", "title": "Learn more", - "description": "- Explore all the features the Python extension has to offer by looking for \"Python\" in the [Command Palette](command:workbench.action.showCommands).\n- [Sign up](https://aka.ms/python-vscode-mailinglist) for tips and tutorials through our mailing list.\n- Explore more features in our [Tutorials](https://aka.ms/AA8dqti) or check [Documentation](https://aka.ms/AA8dxwy) for tips and troubleshooting.\n� Take a look at our [Release Notes](https://aka.ms/AA8dxtb) to learn more about the latest features.", + "description": "- Explore all the features the Python extension has to offer by looking for \"Python\" in the [Command Palette](command:workbench.action.showCommands).\n- [Sign up](https://aka.ms/python-vscode-mailinglist) for tips and tutorials through our mailing list.\n- Explore more features in our [Tutorials](https://aka.ms/AA8dqti) or check [Documentation](https://aka.ms/AA8dxwy) for tips and troubleshooting.\n- Take a look at our [Release Notes](https://aka.ms/AA8dxtb) to learn more about the latest features.", "media": { "image": "resources/walkthrough/python-docs-learn-more.png", "altText": "Documentation page for Python in VS Code" @@ -249,7 +249,7 @@ { "id": "python.dataScienceLearnMore", "title": "Learn more", - "description": "• Explore all the features the Python extension has to offer by looking for \"Python\" in the [Command Palette](command:workbench.action.showCommands).\n• [Sign up](https://aka.ms/python-vscode-mailinglist) for tips and tutorials through our mailing list.\n• Explore more features in our [Tutorials](https://aka.ms/AAdar6q) or check the [Documentation](https://aka.ms/AA8dxwy) for tips and troubleshooting.\n• Take a look at our [Release Notes](https://aka.ms/AA8dxtb) to learn more about the latest features.", + "description": " Explore all the features the Python extension has to offer by looking for \"Python\" in the [Command Palette](command:workbench.action.showCommands).\n [Sign up](https://aka.ms/python-vscode-mailinglist) for tips and tutorials through our mailing list.\n Explore more features in our [Tutorials](https://aka.ms/AAdar6q) or check the [Documentation](https://aka.ms/AA8dxwy) for tips and troubleshooting.\n Take a look at our [Release Notes](https://aka.ms/AA8dxtb) to learn more about the latest features.", "media": { "image": "resources/walkthrough/datascience-learn-more.png", "altText": "Learning more from python visual studio code documentation" From 791b4e91c549020f38d8149b6011cd0de114caa1 Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Wed, 28 Jul 2021 19:56:24 -0700 Subject: [PATCH 32/39] Fix linting --- src/client/common/utils/delayTrigger.ts | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/client/common/utils/delayTrigger.ts b/src/client/common/utils/delayTrigger.ts index fa7a8ab0b369..85ff5695714c 100644 --- a/src/client/common/utils/delayTrigger.ts +++ b/src/client/common/utils/delayTrigger.ts @@ -47,16 +47,13 @@ export class DelayedTrigger implements IDelayedTrigger, Disposable { clearTimeout(this.timerId); } - this.timerId = setTimeout( - () => { - this.calledCounter += 1; - traceVerbose( - `Delay Trigger[${this.name}]: triggered=${this.triggeredCounter}, called=${this.calledCounter}`, - ); - this.callback(...args); - }, - this.ms - ); + this.timerId = setTimeout(() => { + this.calledCounter += 1; + traceVerbose( + `Delay Trigger[${this.name}]: triggered=${this.triggeredCounter}, called=${this.calledCounter}`, + ); + this.callback(...args); + }, this.ms); } public dispose(): void { From 0d4d1f266147d991e02215f070dcf6da8064f340 Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Thu, 29 Jul 2021 20:00:09 -0700 Subject: [PATCH 33/39] Add refresh and run failed icons --- package.json | 25 ++++++++++++++++++++++++- package.nls.json | 1 + 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 102379a9d064..aae8a7d6a41a 100644 --- a/package.json +++ b/package.json @@ -367,8 +367,9 @@ "title": "%python.command.python.refreshTensorBoard.title%" }, { - "category": "Python", + "category": "Test", "command": "python.refreshTests", + "icon": "$(refresh)", "title": "%python.command.python.refreshTests.title%" }, { @@ -376,6 +377,16 @@ "command": "python.reportIssue", "title": "%python.command.python.reportIssue.title%" }, + { + "category": "Test", + "command": "testing.reRunFailTests", + + "icon": { + "dark": "resources/dark/run-failed-tests.svg", + "light": "resources/light/run-failed-tests.svg" + }, + "title": "%python.command.testing.rerunFailedTests.title%" + }, { "category": "Python", "command": "python.runLinting", @@ -1874,6 +1885,18 @@ "group": "Python", "when": "resourceLangId == python" } + ], + "view/title":[ + { + "command": "python.refreshTests", + "when": "view == workbench.view.testing", + "group": "navigation" + }, + { + "command": "testing.reRunFailTests", + "when": "view == workbench.view.testing", + "group": "navigation" + } ] }, "viewsWelcome": [ diff --git a/package.nls.json b/package.nls.json index 01cab0aa620f..072364a27542 100644 --- a/package.nls.json +++ b/package.nls.json @@ -15,6 +15,7 @@ "python.command.python.viewLanguageServerOutput.title": "Show Language Server Output", "python.command.python.configureTests.title": "Configure Tests", "python.command.python.refreshTests.title": "Refresh Tests", + "python.command.testing.rerunFailedTests.title": "Rerun Failed Tests", "python.command.python.execSelectionInTerminal.title": "Run Selection/Line in Python Terminal", "python.command.python.execSelectionInDjangoShell.title": "Run Selection/Line in Django Shell", "python.command.python.goToPythonObject.title": "Go to Python Object", From 7a2346e67cd8144a33614da48e40085df88b1994 Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Thu, 29 Jul 2021 20:04:11 -0700 Subject: [PATCH 34/39] Trigger discovery on settings change, and show discovery errors --- .../common/testItemUtilities.ts | 10 ++ .../testing/testController/controller.ts | 49 +++++++-- .../testController/pytest/pytestController.ts | 36 ++++++- .../unittest/unittestController.ts | 102 +++++++++++++++--- 4 files changed, 174 insertions(+), 23 deletions(-) diff --git a/src/client/testing/testController/common/testItemUtilities.ts b/src/client/testing/testController/common/testItemUtilities.ts index 82b65ec74c10..9d30774e829a 100644 --- a/src/client/testing/testController/common/testItemUtilities.ts +++ b/src/client/testing/testController/common/testItemUtilities.ts @@ -26,6 +26,16 @@ export function removeItemByIdFromChildren( }); } +export function createErrorTestItem( + testController: TestController, + options: { id: string; label: string; error: string }, +): TestItem { + const testItem = testController.createTestItem(options.id, options.label); + testItem.canResolveChildren = false; + testItem.error = options.error; + return testItem; +} + export function createWorkspaceRootTestItem( testController: TestController, idToRawData: Map, diff --git a/src/client/testing/testController/controller.ts b/src/client/testing/testController/controller.ts index 382860f2a80a..38b0f6aa957c 100644 --- a/src/client/testing/testController/controller.ts +++ b/src/client/testing/testController/controller.ts @@ -75,6 +75,18 @@ export class PythonTestController implements ITestController { this.refreshCancellation.cancel(); this.refreshCancellation.dispose(); this.refreshCancellation = new CancellationTokenSource(); + + if (uri === undefined) { + // This is a special case where we want everything to be re-discovered. + traceVerbose('Testing: Clearing all discovered tests'); + const ids: string[] = []; + this.testController.items.forEach((i) => ids.push(i.id)); + ids.forEach((id) => this.testController.items.delete(id)); + + traceVerbose('Testing: Forcing test data refresh'); + return this.refreshTestDataInternal(undefined); + } + traceVerbose('Testing: Forcing test data refresh'); return this.refreshTestDataInternal(uri); } @@ -84,14 +96,35 @@ export class PythonTestController implements ITestController { } private async refreshTestDataInternal(uri?: Resource): Promise { - traceVerbose(`Testing: Refreshing test data for ${uri?.fsPath}`); + if (uri) { + traceVerbose(`Testing: Refreshing test data for ${uri.fsPath}`); - const settings = this.configSettings.getSettings(uri); - if (settings.testing.pytestEnabled) { - return this.pytest.refreshTestData(this.testController, uri, this.refreshCancellation.token); - } - if (settings.testing.unittestEnabled) { - return this.unittest.refreshTestData(this.testController, uri, this.refreshCancellation.token); + const settings = this.configSettings.getSettings(uri); + if (settings.testing.pytestEnabled) { + return this.pytest.refreshTestData(this.testController, uri, this.refreshCancellation.token); + } + if (settings.testing.unittestEnabled) { + return this.unittest.refreshTestData(this.testController, uri, this.refreshCancellation.token); + } + + // If we are here we may have to remove an existing node from the tree + // This handles the case where user removes test settings. Which should remove the + // tests for that particular case from the tree view + const workspace = this.workspaceService.getWorkspaceFolder(uri); + if (workspace) { + const toDelete: string[] = []; + this.testController.items.forEach((i: TestItem) => { + const w = this.workspaceService.getWorkspaceFolder(i.uri); + if (w?.uri.fsPath === workspace.uri.fsPath) { + toDelete.push(i.id); + } + }); + toDelete.forEach((i) => this.testController.items.delete(i)); + } + } else { + traceVerbose('Testing: Refreshing all test data'); + const workspaces: readonly WorkspaceFolder[] = this.workspaceService.workspaceFolders || []; + await Promise.all(workspaces.map((workspace) => this.refreshTestDataInternal(workspace.uri))); } return Promise.resolve(); } @@ -107,7 +140,7 @@ export class PythonTestController implements ITestController { return this.unittest.resolveChildren(this.testController, item); } } else { - traceVerbose('Testing: Resolving all workspaces'); + traceVerbose('Testing: Refreshing all test data'); const workspaces: readonly WorkspaceFolder[] = this.workspaceService.workspaceFolders || []; await Promise.all(workspaces.map((workspace) => this.refreshTestDataInternal(workspace.uri))); } diff --git a/src/client/testing/testController/pytest/pytestController.ts b/src/client/testing/testController/pytest/pytestController.ts index 393d51162b83..ec96e9fc9b4b 100644 --- a/src/client/testing/testController/pytest/pytestController.ts +++ b/src/client/testing/testController/pytest/pytestController.ts @@ -4,6 +4,7 @@ import { inject, injectable, named } from 'inversify'; import { flatten } from 'lodash'; import * as path from 'path'; +import * as util from 'util'; import { CancellationToken, TestItem, Uri, TestController, WorkspaceFolder } from 'vscode'; import { IWorkspaceService } from '../../../common/application/types'; import { traceError } from '../../../common/logger'; @@ -13,6 +14,7 @@ import { createDeferred, Deferred } from '../../../common/utils/async'; import { PYTEST_PROVIDER } from '../../common/constants'; import { TestDiscoveryOptions } from '../../common/types'; import { + createErrorTestItem, createWorkspaceRootTestItem, getNodeByUri, getWorkspaceNode, @@ -191,9 +193,27 @@ export class PytestController implements ITestFrameworkController { await Promise.all(discoveryRunOptions.map((o) => this.discoveryHelper.runTestDiscovery(o))), ); this.testData.set(workspace.uri.fsPath, rawTestData); + + // Remove error node + testController.items.delete(`DiscoveryError:${workspace.uri.fsPath}`); + deferred.resolve(); } catch (ex) { - traceError('Error discovering pytest tests: ', ex); + traceError('Error discovering pytest tests:\r\n', ex); + + // Report also on the test view. Getting root node is more complicated due to fact + // that in pytest project can be organized in many ways + testController.items.add( + createErrorTestItem(testController, { + id: `DiscoveryError:${workspace.uri.fsPath}`, + label: `Pytest Discovery Error [${path.basename(workspace.uri.fsPath)}]`, + error: util.format( + 'Error discovering pytest tests (see Output > Python):\r\n', + getTestDiscoveryExceptions(ex.message), + ), + }), + ); + deferred.reject(ex); } finally { // Discovery has finished running we have the raw test data at this point. @@ -247,3 +267,17 @@ export class PytestController implements ITestFrameworkController { ); } } + +function getTestDiscoveryExceptions(content: string): string { + const lines = content.split(/\r?\n/g); + let start = false; + let exceptions = ''; + for (const line of lines) { + if (start) { + exceptions += `${line}\r\n`; + } else if (line.includes(' ERRORS ')) { + start = true; + } + } + return exceptions; +} diff --git a/src/client/testing/testController/unittest/unittestController.ts b/src/client/testing/testController/unittest/unittestController.ts index cacaa8a086d7..68a6359f0158 100644 --- a/src/client/testing/testController/unittest/unittestController.ts +++ b/src/client/testing/testController/unittest/unittestController.ts @@ -2,6 +2,7 @@ // Licensed under the MIT License. import * as path from 'path'; +import * as util from 'util'; import { inject, injectable, named } from 'inversify'; import { CancellationToken, TestController, TestItem, Uri, WorkspaceFolder } from 'vscode'; import { IWorkspaceService } from '../../../common/application/types'; @@ -21,6 +22,7 @@ import { import { unittestGetTestFolders, unittestGetTestPattern } from './arguments'; import { execCode } from '../../../common/process/internal/python'; import { + createErrorTestItem, createWorkspaceRootTestItem, getNodeByUri, getWorkspaceNode, @@ -128,10 +130,23 @@ def generate_test_cases(suite): loader = unittest.TestLoader() suite = loader.discover("${startDir}", pattern="${pattern}") -print("start") #Don't remove this line +print("start") # Don't remove this line +loader_errors = [] for s in generate_test_cases(suite): tm = getattr(s, s._testMethodName) - print(s.id().replace('.',':') + ":" + get_sourceline(tm)) + testId = s.id() + if testId.startswith("unittest.loader._FailedTest"): + loader_errors.append(s._exception) + else: + print(testId.replace(".", ":") + ":" + get_sourceline(tm)) + +for error in loader_errors: + try: + print("=== exception start ===") + print(error.msg) + print("=== exception end ===") + except: + pass `; const runOptions: Options = { @@ -157,9 +172,44 @@ for s in generate_test_cases(suite): options.token, ); this.testData.set(workspace.uri.fsPath, rawTestData); + + const exceptions = getTestDiscoveryExceptions(content); + if (exceptions.length === 0) { + // Remove error node + testController.items.delete(`DiscoveryError:${workspace.uri.fsPath}`); + } else { + traceError('Error discovering unittest tests:\r\n', exceptions.join('\r\n\r\n')); + + let errorNode = testController.items.get(`DiscoveryError:${workspace.uri.fsPath}`); + const message = util.format( + 'Error discovering unittest tests (see Output > Python):\r\n', + exceptions.join('\r\n\r\n'), + ); + if (errorNode === undefined) { + errorNode = createErrorTestItem(testController, { + id: `DiscoveryError:${workspace.uri.fsPath}`, + label: `Unittest Discovery Error [${path.basename(workspace.uri.fsPath)}]`, + error: message, + }); + errorNode.canResolveChildren = false; + testController.items.add(errorNode); + } + errorNode.error = message; + } + deferred.resolve(); } catch (ex) { - traceError('Error discovering unittest tests: ', ex); + traceError('Error discovering unittest tests:\r\n', ex); + + // Report also on the test view. + testController.items.add( + createErrorTestItem(testController, { + id: `DiscoveryError:${workspace.uri.fsPath}`, + label: `Unittest Discovery Error [${path.basename(workspace.uri.fsPath)}]`, + error: util.format('Error discovering unittest tests (see Output > Python):\r\n', ex), + }), + ); + deferred.reject(ex); } finally { // Discovery has finished running we have the raw test data at this point. @@ -220,20 +270,44 @@ for s in generate_test_cases(suite): } } +function getTestDiscoveryExceptions(content: string): string[] { + const lines = content.split(/\r?\n/g); + let start = false; + let data = ''; + const exceptions: string[] = []; + for (const line of lines) { + if (start) { + if (line.startsWith('=== exception end ===')) { + exceptions.push(data); + start = false; + } else { + data += `${line}\r\n`; + } + } else if (line.startsWith('=== exception start ===')) { + start = true; + data = ''; + } + } + return exceptions; +} + function getTestIds(content: string): string[] { let startedCollecting = false; - return content - .split(/\r?\n/g) - .map((line) => { - if (!startedCollecting) { - if (line === 'start') { - startedCollecting = true; - } - return ''; + const lines = content.split(/\r?\n/g); + + const ids: string[] = []; + for (const line of lines) { + if (!startedCollecting) { + if (line === 'start') { + startedCollecting = true; + } + if (line.startsWith('===')) { + break; } - return line.trim(); - }) - .filter((line) => line.length > 0); + } + ids.push(line.trim()); + } + return ids.filter((id) => id.length > 0); } function testDiscoveryParser( From d48f6a12d355ab828705d0b94bdcdc94d15d26dd Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Thu, 29 Jul 2021 20:14:29 -0700 Subject: [PATCH 35/39] Fix encoding from windows-1252 to utf-8 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index aae8a7d6a41a..5028bbf93893 100644 --- a/package.json +++ b/package.json @@ -164,7 +164,7 @@ { "id": "python.learnMore", "title": "Learn more", - "description": "- Explore all the features the Python extension has to offer by looking for \"Python\" in the [Command Palette](command:workbench.action.showCommands).\n- [Sign up](https://aka.ms/python-vscode-mailinglist) for tips and tutorials through our mailing list.\n- Explore more features in our [Tutorials](https://aka.ms/AA8dqti) or check [Documentation](https://aka.ms/AA8dxwy) for tips and troubleshooting.\n- Take a look at our [Release Notes](https://aka.ms/AA8dxtb) to learn more about the latest features.", + "description": "• Explore all the features the Python extension has to offer by looking for \"Python\" in the [Command Palette](command:workbench.action.showCommands).\n• [Sign up](https://aka.ms/python-vscode-mailinglist) for tips and tutorials through our mailing list.\n• Explore more features in our [Tutorials](https://aka.ms/AA8dqti) or check [Documentation](https://aka.ms/AA8dxwy) for tips and troubleshooting.\n• Take a look at our [Release Notes](https://aka.ms/AA8dxtb) to learn more about the latest features.", "media": { "image": "resources/walkthrough/python-docs-learn-more.png", "altText": "Documentation page for Python in VS Code" @@ -249,7 +249,7 @@ { "id": "python.dataScienceLearnMore", "title": "Learn more", - "description": " Explore all the features the Python extension has to offer by looking for \"Python\" in the [Command Palette](command:workbench.action.showCommands).\n [Sign up](https://aka.ms/python-vscode-mailinglist) for tips and tutorials through our mailing list.\n Explore more features in our [Tutorials](https://aka.ms/AAdar6q) or check the [Documentation](https://aka.ms/AA8dxwy) for tips and troubleshooting.\n Take a look at our [Release Notes](https://aka.ms/AA8dxtb) to learn more about the latest features.", + "description": "• Explore all the features the Python extension has to offer by looking for \"Python\" in the [Command Palette](command:workbench.action.showCommands).\n• [Sign up](https://aka.ms/python-vscode-mailinglist) for tips and tutorials through our mailing list.\n• Explore more features in our [Tutorials](https://aka.ms/AAdar6q) or check the [Documentation](https://aka.ms/AA8dxwy) for tips and troubleshooting.\n• Take a look at our [Release Notes](https://aka.ms/AA8dxtb) to learn more about the latest features.", "media": { "image": "resources/walkthrough/datascience-learn-more.png", "altText": "Learning more from python visual studio code documentation" From 328261b0509f9e5c4e17eb6a27ed47a63e5b44ed Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Thu, 29 Jul 2021 20:53:17 -0700 Subject: [PATCH 36/39] Better messaging when pytest is not installed --- src/client/testing/testController/pytest/pytestController.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/client/testing/testController/pytest/pytestController.ts b/src/client/testing/testController/pytest/pytestController.ts index ec96e9fc9b4b..fa83b5c452c5 100644 --- a/src/client/testing/testController/pytest/pytestController.ts +++ b/src/client/testing/testController/pytest/pytestController.ts @@ -200,6 +200,7 @@ export class PytestController implements ITestFrameworkController { deferred.resolve(); } catch (ex) { traceError('Error discovering pytest tests:\r\n', ex); + const message = getTestDiscoveryExceptions(ex.message); // Report also on the test view. Getting root node is more complicated due to fact // that in pytest project can be organized in many ways @@ -209,7 +210,7 @@ export class PytestController implements ITestFrameworkController { label: `Pytest Discovery Error [${path.basename(workspace.uri.fsPath)}]`, error: util.format( 'Error discovering pytest tests (see Output > Python):\r\n', - getTestDiscoveryExceptions(ex.message), + message.length > 0 ? message : ex, ), }), ); From 2c0580826d952dd92db0c447c752370c176e36af Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Fri, 30 Jul 2021 09:19:30 -0700 Subject: [PATCH 37/39] Improve handling of failure expected and pass unexpected --- pythonFiles/visualstudio_py_testlauncher.py | 4 ++-- src/client/testing/testController/unittest/runner.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pythonFiles/visualstudio_py_testlauncher.py b/pythonFiles/visualstudio_py_testlauncher.py index 3a43c1e1be34..13a34bf6f91e 100644 --- a/pythonFiles/visualstudio_py_testlauncher.py +++ b/pythonFiles/visualstudio_py_testlauncher.py @@ -162,11 +162,11 @@ def addSkip(self, test, reason): def addExpectedFailure(self, test, err): super(VsTestResult, self).addExpectedFailure(test, err) - self.sendResult(test, "failed", err) + self.sendResult(test, "failed-expected", err) def addUnexpectedSuccess(self, test): super(VsTestResult, self).addUnexpectedSuccess(test) - self.sendResult(test, "passed") + self.sendResult(test, "passed-unexpected") def sendResult(self, test, outcome, trace=None): if _channel is not None: diff --git a/src/client/testing/testController/unittest/runner.ts b/src/client/testing/testController/unittest/runner.ts index 2925ba50823f..1a7008718edc 100644 --- a/src/client/testing/testController/unittest/runner.ts +++ b/src/client/testing/testController/unittest/runner.ts @@ -87,16 +87,16 @@ export class UnittestRunner implements ITestsRunner { if (testCase && rawTestCase) { tested.push(rawTestCase.runId); - if (data.outcome === 'passed') { + if (data.outcome === 'passed' || data.outcome === 'failed-expected') { const text = `${rawTestCase.rawId} Passed\r\n`; runInstance.passed(testCase); runInstance.appendOutput(text); counts.passed += 1; - } else if (data.outcome === 'failed') { + } else if (data.outcome === 'failed' || data.outcome === 'passed-unexpected') { const traceback = data.traceback ? data.traceback.splitLines({ trim: false, removeEmptyEntries: true }).join('\r\n') : ''; - const text = `${rawTestCase.rawId} Failed: ${data.message}\r\n${traceback}\r\n`; + const text = `${rawTestCase.rawId} Failed: ${data.message ?? data.outcome}\r\n${traceback}\r\n`; const message = new TestMessage(text); if (testCase.uri && testCase.range) { From 4c475a6db2d9bd7a3ba3d29319da251131ed778c Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Fri, 30 Jul 2021 11:36:36 -0700 Subject: [PATCH 38/39] Add news items --- news/1 Enhancements/11864.md | 1 + news/1 Enhancements/12218.md | 1 + news/1 Enhancements/13147.md | 1 + news/1 Enhancements/3652.md | 1 + news/1 Enhancements/8405.md | 1 + news/1 Enhancements/8675.md | 1 + news/1 Enhancements/8836.md | 1 + news/1 Enhancements/9026.md | 1 + news/1 Enhancements/9402.md | 1 + news/2 Fixes/10972.md | 1 + news/2 Fixes/11866.md | 1 + news/2 Fixes/12403.md | 1 + news/2 Fixes/12995.md | 1 + news/2 Fixes/13285.md | 1 + news/2 Fixes/13713.md | 1 + news/2 Fixes/13916.md | 1 + news/2 Fixes/15260.md | 1 + news/2 Fixes/15736.md | 1 + news/2 Fixes/16475.md | 1 + news/2 Fixes/1654.md | 1 + news/2 Fixes/2382.md | 1 + news/2 Fixes/2644.md | 1 + news/2 Fixes/2660.md | 1 + news/2 Fixes/2790.md | 1 + news/2 Fixes/3062.md | 1 + news/2 Fixes/3591.md | 1 + news/2 Fixes/4469.md | 1 + news/2 Fixes/4848.md | 1 + news/2 Fixes/5417.md | 1 + news/2 Fixes/6787.md | 1 + news/2 Fixes/7150.md | 1 + news/2 Fixes/7443.md | 1 + news/2 Fixes/7870.md | 1 + news/2 Fixes/8448.md | 1 + news/2 Fixes/8761.md | 1 + news/2 Fixes/9640.md | 1 + 36 files changed, 36 insertions(+) create mode 100644 news/1 Enhancements/11864.md create mode 100644 news/1 Enhancements/12218.md create mode 100644 news/1 Enhancements/13147.md create mode 100644 news/1 Enhancements/3652.md create mode 100644 news/1 Enhancements/8405.md create mode 100644 news/1 Enhancements/8675.md create mode 100644 news/1 Enhancements/8836.md create mode 100644 news/1 Enhancements/9026.md create mode 100644 news/1 Enhancements/9402.md create mode 100644 news/2 Fixes/10972.md create mode 100644 news/2 Fixes/11866.md create mode 100644 news/2 Fixes/12403.md create mode 100644 news/2 Fixes/12995.md create mode 100644 news/2 Fixes/13285.md create mode 100644 news/2 Fixes/13713.md create mode 100644 news/2 Fixes/13916.md create mode 100644 news/2 Fixes/15260.md create mode 100644 news/2 Fixes/15736.md create mode 100644 news/2 Fixes/16475.md create mode 100644 news/2 Fixes/1654.md create mode 100644 news/2 Fixes/2382.md create mode 100644 news/2 Fixes/2644.md create mode 100644 news/2 Fixes/2660.md create mode 100644 news/2 Fixes/2790.md create mode 100644 news/2 Fixes/3062.md create mode 100644 news/2 Fixes/3591.md create mode 100644 news/2 Fixes/4469.md create mode 100644 news/2 Fixes/4848.md create mode 100644 news/2 Fixes/5417.md create mode 100644 news/2 Fixes/6787.md create mode 100644 news/2 Fixes/7150.md create mode 100644 news/2 Fixes/7443.md create mode 100644 news/2 Fixes/7870.md create mode 100644 news/2 Fixes/8448.md create mode 100644 news/2 Fixes/8761.md create mode 100644 news/2 Fixes/9640.md diff --git a/news/1 Enhancements/11864.md b/news/1 Enhancements/11864.md new file mode 100644 index 000000000000..0790187c7486 --- /dev/null +++ b/news/1 Enhancements/11864.md @@ -0,0 +1 @@ +Added command to run last executed test. diff --git a/news/1 Enhancements/12218.md b/news/1 Enhancements/12218.md new file mode 100644 index 000000000000..27bf31ac2ec2 --- /dev/null +++ b/news/1 Enhancements/12218.md @@ -0,0 +1 @@ +Add shortcut to run the current test (at cursor position). diff --git a/news/1 Enhancements/13147.md b/news/1 Enhancements/13147.md new file mode 100644 index 000000000000..78c8c6fdf147 --- /dev/null +++ b/news/1 Enhancements/13147.md @@ -0,0 +1 @@ +Run all tests in a multi-root workspace without prompting. diff --git a/news/1 Enhancements/3652.md b/news/1 Enhancements/3652.md new file mode 100644 index 000000000000..df73e05e453d --- /dev/null +++ b/news/1 Enhancements/3652.md @@ -0,0 +1 @@ +Added commands to select and run a set of tests. diff --git a/news/1 Enhancements/8405.md b/news/1 Enhancements/8405.md new file mode 100644 index 000000000000..09ea0d1eeced --- /dev/null +++ b/news/1 Enhancements/8405.md @@ -0,0 +1 @@ +Remove the testing functionality from the status bar. diff --git a/news/1 Enhancements/8675.md b/news/1 Enhancements/8675.md new file mode 100644 index 000000000000..4965b95e19cf --- /dev/null +++ b/news/1 Enhancements/8675.md @@ -0,0 +1 @@ +Automatically detect new test file in test explorer. diff --git a/news/1 Enhancements/8836.md b/news/1 Enhancements/8836.md new file mode 100644 index 000000000000..028c8a633124 --- /dev/null +++ b/news/1 Enhancements/8836.md @@ -0,0 +1 @@ +Search test names in test explorer. diff --git a/news/1 Enhancements/9026.md b/news/1 Enhancements/9026.md new file mode 100644 index 000000000000..36d21a7f4df9 --- /dev/null +++ b/news/1 Enhancements/9026.md @@ -0,0 +1 @@ +Added a command for displaying the test explorer. diff --git a/news/1 Enhancements/9402.md b/news/1 Enhancements/9402.md new file mode 100644 index 000000000000..789362274c96 --- /dev/null +++ b/news/1 Enhancements/9402.md @@ -0,0 +1 @@ +Make "run all tests" icon gray instead of green. diff --git a/news/2 Fixes/10972.md b/news/2 Fixes/10972.md new file mode 100644 index 000000000000..da53177f3b09 --- /dev/null +++ b/news/2 Fixes/10972.md @@ -0,0 +1 @@ +Fix for unittest module invoking wrong TestCase. diff --git a/news/2 Fixes/11866.md b/news/2 Fixes/11866.md new file mode 100644 index 000000000000..211b26ac865c --- /dev/null +++ b/news/2 Fixes/11866.md @@ -0,0 +1 @@ +Fix for unable to navigate to test function. diff --git a/news/2 Fixes/12403.md b/news/2 Fixes/12403.md new file mode 100644 index 000000000000..7603d82d9db2 --- /dev/null +++ b/news/2 Fixes/12403.md @@ -0,0 +1 @@ +Fix for running test fails trying to access non-existing file. diff --git a/news/2 Fixes/12995.md b/news/2 Fixes/12995.md new file mode 100644 index 000000000000..a983c81eed14 --- /dev/null +++ b/news/2 Fixes/12995.md @@ -0,0 +1 @@ +Fix for code lenses don't work after opening files from different projects in workspace. diff --git a/news/2 Fixes/13285.md b/news/2 Fixes/13285.md new file mode 100644 index 000000000000..7f73e64cb180 --- /dev/null +++ b/news/2 Fixes/13285.md @@ -0,0 +1 @@ +Fix for the pytest icons keep spinning when run Test Method. diff --git a/news/2 Fixes/13713.md b/news/2 Fixes/13713.md new file mode 100644 index 000000000000..1269610be451 --- /dev/null +++ b/news/2 Fixes/13713.md @@ -0,0 +1 @@ +Test for any functionality related to testing doesn't work if language server is set to none. diff --git a/news/2 Fixes/13916.md b/news/2 Fixes/13916.md new file mode 100644 index 000000000000..a8c4953e3dad --- /dev/null +++ b/news/2 Fixes/13916.md @@ -0,0 +1 @@ +Fix for cannot configure PyTest from UI. diff --git a/news/2 Fixes/15260.md b/news/2 Fixes/15260.md new file mode 100644 index 000000000000..54af2fe92536 --- /dev/null +++ b/news/2 Fixes/15260.md @@ -0,0 +1 @@ +Fix for test icons not updating when using pytest. diff --git a/news/2 Fixes/15736.md b/news/2 Fixes/15736.md new file mode 100644 index 000000000000..0752a597b670 --- /dev/null +++ b/news/2 Fixes/15736.md @@ -0,0 +1 @@ +Fix for debugging tests is returning errors due to "unsupported status". diff --git a/news/2 Fixes/16475.md b/news/2 Fixes/16475.md new file mode 100644 index 000000000000..ab43422fee61 --- /dev/null +++ b/news/2 Fixes/16475.md @@ -0,0 +1 @@ +Fix for "There was an error in running the tests" when stopping debugger. diff --git a/news/2 Fixes/1654.md b/news/2 Fixes/1654.md new file mode 100644 index 000000000000..1015fbcf6244 --- /dev/null +++ b/news/2 Fixes/1654.md @@ -0,0 +1 @@ +Fix for test code lenses do not disappear even after disabling the unit tests. diff --git a/news/2 Fixes/2382.md b/news/2 Fixes/2382.md new file mode 100644 index 000000000000..bd31cd7799f3 --- /dev/null +++ b/news/2 Fixes/2382.md @@ -0,0 +1 @@ +Fix for code lens for a test class run under unittest doesn't show overall results for methods. diff --git a/news/2 Fixes/2644.md b/news/2 Fixes/2644.md new file mode 100644 index 000000000000..e481f5c61932 --- /dev/null +++ b/news/2 Fixes/2644.md @@ -0,0 +1 @@ +Fix for test code lens do not appear on initial activation of testing support. diff --git a/news/2 Fixes/2660.md b/news/2 Fixes/2660.md new file mode 100644 index 000000000000..74bb10bfd255 --- /dev/null +++ b/news/2 Fixes/2660.md @@ -0,0 +1 @@ +Fix for "No tests ran, please check the configuration settings for the tests". diff --git a/news/2 Fixes/2790.md b/news/2 Fixes/2790.md new file mode 100644 index 000000000000..0a73cb76f516 --- /dev/null +++ b/news/2 Fixes/2790.md @@ -0,0 +1 @@ +Fix for code lenses disappear on save, then re-appear when tabbing on/off the file. diff --git a/news/2 Fixes/3062.md b/news/2 Fixes/3062.md new file mode 100644 index 000000000000..d490422dc225 --- /dev/null +++ b/news/2 Fixes/3062.md @@ -0,0 +1 @@ +Fix for code lenses for tests not showing up when test is defined on line 1. diff --git a/news/2 Fixes/3591.md b/news/2 Fixes/3591.md new file mode 100644 index 000000000000..3bad43fee35c --- /dev/null +++ b/news/2 Fixes/3591.md @@ -0,0 +1 @@ +Fix for command 'python.runtests' not found. diff --git a/news/2 Fixes/4469.md b/news/2 Fixes/4469.md new file mode 100644 index 000000000000..150c3df5eb3b --- /dev/null +++ b/news/2 Fixes/4469.md @@ -0,0 +1 @@ +Fix for navigation to code doesn't work with parameterized tests. diff --git a/news/2 Fixes/4848.md b/news/2 Fixes/4848.md new file mode 100644 index 000000000000..832a093c8f97 --- /dev/null +++ b/news/2 Fixes/4848.md @@ -0,0 +1 @@ +Fix for tests are not being discovered at first in multiroot workspace. diff --git a/news/2 Fixes/5417.md b/news/2 Fixes/5417.md new file mode 100644 index 000000000000..a80c2adf023c --- /dev/null +++ b/news/2 Fixes/5417.md @@ -0,0 +1 @@ +Fix for tests not found after upgrade. diff --git a/news/2 Fixes/6787.md b/news/2 Fixes/6787.md new file mode 100644 index 000000000000..f11fc5475504 --- /dev/null +++ b/news/2 Fixes/6787.md @@ -0,0 +1 @@ +Fix for test results not updated if test is run via codelens. diff --git a/news/2 Fixes/7150.md b/news/2 Fixes/7150.md new file mode 100644 index 000000000000..792ee09816b0 --- /dev/null +++ b/news/2 Fixes/7150.md @@ -0,0 +1 @@ +Fix for "Run Current Test File" is not running tests, just discovering them. diff --git a/news/2 Fixes/7443.md b/news/2 Fixes/7443.md new file mode 100644 index 000000000000..e570b451d426 --- /dev/null +++ b/news/2 Fixes/7443.md @@ -0,0 +1 @@ +Fix for testing code lenses don't show for remote sessions to a directory symlink. diff --git a/news/2 Fixes/7870.md b/news/2 Fixes/7870.md new file mode 100644 index 000000000000..8bb9c96d3c46 --- /dev/null +++ b/news/2 Fixes/7870.md @@ -0,0 +1 @@ +Fix for discover test per folder icon is missing in multi-root workspace after upgrade. diff --git a/news/2 Fixes/8448.md b/news/2 Fixes/8448.md new file mode 100644 index 000000000000..fca0c8d6d6c5 --- /dev/null +++ b/news/2 Fixes/8448.md @@ -0,0 +1 @@ +Fix for clicking on a test in the Test Explorer does not navigate to the correct test. diff --git a/news/2 Fixes/8761.md b/news/2 Fixes/8761.md new file mode 100644 index 000000000000..5ea6226dc999 --- /dev/null +++ b/news/2 Fixes/8761.md @@ -0,0 +1 @@ +Fix for if multiple tests have the same name, only one is run. diff --git a/news/2 Fixes/9640.md b/news/2 Fixes/9640.md new file mode 100644 index 000000000000..c8d733193c63 --- /dev/null +++ b/news/2 Fixes/9640.md @@ -0,0 +1 @@ +Fix for test failure is reported as a compile error. From ae249d0ffa9a5f40feba2b316c188c6ddca4b091 Mon Sep 17 00:00:00 2001 From: Karthik Nadig Date: Tue, 3 Aug 2021 13:49:05 -0700 Subject: [PATCH 39/39] Add more news items. --- news/1 Enhancements/12043.md | 1 + news/1 Enhancements/5347.md | 1 + news/2 Fixes/5791.md | 1 + news/2 Fixes/5889.md | 1 + news/2 Fixes/9854.md | 1 + 5 files changed, 5 insertions(+) create mode 100644 news/1 Enhancements/12043.md create mode 100644 news/1 Enhancements/5347.md create mode 100644 news/2 Fixes/5791.md create mode 100644 news/2 Fixes/5889.md create mode 100644 news/2 Fixes/9854.md diff --git a/news/1 Enhancements/12043.md b/news/1 Enhancements/12043.md new file mode 100644 index 000000000000..e4912fd40fe5 --- /dev/null +++ b/news/1 Enhancements/12043.md @@ -0,0 +1 @@ +Fix for PyTest discovery can fail but not give any clue as to what the problem is. diff --git a/news/1 Enhancements/5347.md b/news/1 Enhancements/5347.md new file mode 100644 index 000000000000..f9006965a0c1 --- /dev/null +++ b/news/1 Enhancements/5347.md @@ -0,0 +1 @@ +Fix for tests should be re-discovered after switching environment. diff --git a/news/2 Fixes/5791.md b/news/2 Fixes/5791.md new file mode 100644 index 000000000000..3ceaa903afe1 --- /dev/null +++ b/news/2 Fixes/5791.md @@ -0,0 +1 @@ +Fix for failed icon of the first failed test doesn't changed to running icon when using unittest framework. diff --git a/news/2 Fixes/5889.md b/news/2 Fixes/5889.md new file mode 100644 index 000000000000..67a09c56c6a7 --- /dev/null +++ b/news/2 Fixes/5889.md @@ -0,0 +1 @@ +Fix for failure details in unittest discovery are not always logged. diff --git a/news/2 Fixes/9854.md b/news/2 Fixes/9854.md new file mode 100644 index 000000000000..26b0e7d175df --- /dev/null +++ b/news/2 Fixes/9854.md @@ -0,0 +1 @@ +Fix for discovering tests immediately after interpreter change often fails.