diff --git a/src/client/application/diagnostics/checks/invalidPythonPathInDebugger.ts b/src/client/application/diagnostics/checks/invalidPythonPathInDebugger.ts deleted file mode 100644 index 60a945771b4c..000000000000 --- a/src/client/application/diagnostics/checks/invalidPythonPathInDebugger.ts +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -import { inject, injectable } from 'inversify'; -import { DiagnosticSeverity, Uri } from 'vscode'; -import '../../../common/extensions'; -import { IConfigurationService, ILogger } from '../../../common/types'; -import { IInterpreterHelper } from '../../../interpreter/contracts'; -import { IServiceContainer } from '../../../ioc/types'; -import { BaseDiagnostic, BaseDiagnosticsService } from '../base'; -import { IDiagnosticsCommandFactory } from '../commands/types'; -import { DiagnosticCodes } from '../constants'; -import { DiagnosticCommandPromptHandlerServiceId, MessageCommandPrompt } from '../promptHandler'; -import { DiagnosticScope, IDiagnostic, IDiagnosticHandlerService, IInvalidPythonPathInDebuggerService } from '../types'; - -const InvalidPythonPathInDebuggerMessage = 'You need to select a Python interpreter before you start debugging. \nTip: click on "Select Python Environment" in the status bar.'; - -export class InvalidPythonPathInDebuggerDiagnostic extends BaseDiagnostic { - constructor() { - super(DiagnosticCodes.InvalidDebuggerTypeDiagnostic, - InvalidPythonPathInDebuggerMessage, DiagnosticSeverity.Error, DiagnosticScope.WorkspaceFolder); - } -} - -export const InvalidPythonPathInDebuggerServiceId = 'InvalidPythonPathInDebuggerServiceId'; - -const CommandName = 'python.setInterpreter'; - -@injectable() -export class InvalidPythonPathInDebuggerService extends BaseDiagnosticsService implements IInvalidPythonPathInDebuggerService { - protected readonly messageService: IDiagnosticHandlerService; - constructor(@inject(IServiceContainer) serviceContainer: IServiceContainer) { - super([DiagnosticCodes.InvalidPythonPathInDebuggerDiagnostic], serviceContainer); - this.messageService = serviceContainer.get>(IDiagnosticHandlerService, DiagnosticCommandPromptHandlerServiceId); - } - public async diagnose(): Promise { - return []; - } - public async handle(diagnostics: IDiagnostic[]): Promise { - // This class can only handle one type of diagnostic, hence just use first item in list. - if (diagnostics.length === 0 || !this.canHandle(diagnostics[0])) { - return; - } - const diagnostic = diagnostics[0]; - const commandFactory = this.serviceContainer.get(IDiagnosticsCommandFactory); - const options = [ - { - prompt: 'Select Python Interpreter', - command: commandFactory.createCommand(diagnostic, { type: 'executeVSCCommand', options: CommandName }) - } - ]; - - await this.messageService.handle(diagnostic, { commandPrompts: options }); - } - public async validatePythonPath(pythonPath?: string, resource?: Uri) { - // tslint:disable-next-line:no-invalid-template-strings - if (pythonPath === '${config:python.pythonPath}' || !pythonPath) { - const configService = this.serviceContainer.get(IConfigurationService); - pythonPath = configService.getSettings(resource).pythonPath; - } - const helper = this.serviceContainer.get(IInterpreterHelper); - if (!await helper.getInterpreterInformation(pythonPath).catch(() => undefined)) { - this.handle([new InvalidPythonPathInDebuggerDiagnostic()]) - .catch(ex => { - const logger = this.serviceContainer.get(ILogger); - logger.logError('Failed to handle invalid python path in debugger', ex); - }) - .ignoreErrors(); - return false; - } - return true; - } -} diff --git a/src/client/application/diagnostics/constants.ts b/src/client/application/diagnostics/constants.ts index 1edb9c0350df..0f385a33aa75 100644 --- a/src/client/application/diagnostics/constants.ts +++ b/src/client/application/diagnostics/constants.ts @@ -6,7 +6,6 @@ export enum DiagnosticCodes { InvalidEnvironmentPathVariableDiagnostic = 'InvalidEnvironmentPathVariableDiagnostic', InvalidDebuggerTypeDiagnostic = 'InvalidDebuggerTypeDiagnostic', - InvalidPythonPathInDebuggerDiagnostic = 'InvalidPythonPathInDebuggerDiagnostic', NoPythonInterpretersDiagnostic = 'NoPythonInterpretersDiagnostic', MacInterpreterSelectedAndNoOtherInterpretersDiagnostic = 'MacInterpreterSelectedAndNoOtherInterpretersDiagnostic', MacInterpreterSelectedAndHaveOtherInterpretersDiagnostic = 'MacInterpreterSelectedAndHaveOtherInterpretersDiagnostic' diff --git a/src/client/application/diagnostics/serviceRegistry.ts b/src/client/application/diagnostics/serviceRegistry.ts index 42b2093e982e..d2e1664cf7aa 100644 --- a/src/client/application/diagnostics/serviceRegistry.ts +++ b/src/client/application/diagnostics/serviceRegistry.ts @@ -6,7 +6,6 @@ import { IServiceManager } from '../../ioc/types'; import { EnvironmentPathVariableDiagnosticsService, EnvironmentPathVariableDiagnosticsServiceId } from './checks/envPathVariable'; import { InvalidDebuggerTypeDiagnosticsService, InvalidDebuggerTypeDiagnosticsServiceId } from './checks/invalidDebuggerType'; -import { InvalidPythonPathInDebuggerService, InvalidPythonPathInDebuggerServiceId } from './checks/invalidPythonPathInDebugger'; import { InvalidPythonInterpreterService, InvalidPythonInterpreterServiceId } from './checks/pythonInterpreter'; import { DiagnosticsCommandFactory } from './commands/factory'; import { IDiagnosticsCommandFactory } from './commands/types'; @@ -19,7 +18,6 @@ export function registerTypes(serviceManager: IServiceManager) { serviceManager.addSingleton>(IDiagnosticHandlerService, DiagnosticCommandPromptHandlerService, DiagnosticCommandPromptHandlerServiceId); serviceManager.addSingleton(IDiagnosticsService, EnvironmentPathVariableDiagnosticsService, EnvironmentPathVariableDiagnosticsServiceId); serviceManager.addSingleton(IDiagnosticsService, InvalidDebuggerTypeDiagnosticsService, InvalidDebuggerTypeDiagnosticsServiceId); - serviceManager.addSingleton(IDiagnosticsService, InvalidPythonPathInDebuggerService, InvalidPythonPathInDebuggerServiceId); serviceManager.addSingleton(IDiagnosticsService, InvalidPythonInterpreterService, InvalidPythonInterpreterServiceId); serviceManager.addSingleton(IDiagnosticsCommandFactory, DiagnosticsCommandFactory); } diff --git a/src/client/debugger/Common/processServiceFactory.ts b/src/client/debugger/Common/processServiceFactory.ts new file mode 100644 index 000000000000..b6b30ef90a4c --- /dev/null +++ b/src/client/debugger/Common/processServiceFactory.ts @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +'use strict'; + +import { inject, injectable } from 'inversify'; +import { ProcessService } from '../../common/process/proc'; +import { IBufferDecoder, IProcessService, IProcessServiceFactory } from '../../common/process/types'; +import { IServiceContainer } from '../../ioc/types'; + +@injectable() +export class DebuggerProcessServiceFactory implements IProcessServiceFactory { + constructor(@inject(IServiceContainer) private serviceContainer: IServiceContainer) { } + public create(): Promise { + const processService = new ProcessService(this.serviceContainer.get(IBufferDecoder), process.env); + return Promise.resolve(processService); + } +} diff --git a/src/client/debugger/configProviders/baseProvider.ts b/src/client/debugger/configProviders/baseProvider.ts index 7082e2627716..81c86c7520a7 100644 --- a/src/client/debugger/configProviders/baseProvider.ts +++ b/src/client/debugger/configProviders/baseProvider.ts @@ -8,8 +8,6 @@ import { injectable, unmanaged } from 'inversify'; import * as path from 'path'; import { CancellationToken, DebugConfiguration, DebugConfigurationProvider, Uri, WorkspaceFolder } from 'vscode'; -import { InvalidPythonPathInDebuggerServiceId } from '../../application/diagnostics/checks/invalidPythonPathInDebugger'; -import { IDiagnosticsService, IInvalidPythonPathInDebuggerService } from '../../application/diagnostics/types'; import { IDocumentManager, IWorkspaceService } from '../../common/application/types'; import { PYTHON_LANGUAGE } from '../../common/constants'; import { IConfigurationService } from '../../common/types'; @@ -29,12 +27,6 @@ export abstract class BaseConfigurationProvider); } else { const config = debugConfiguration as PythonLaunchDebugConfiguration; - const diagnosticService = this.serviceContainer.get(IDiagnosticsService, InvalidPythonPathInDebuggerServiceId); - if (!await diagnosticService.validatePythonPath(config.pythonPath, workspaceFolder)) { - // Returning an invalid configuration will cause VSC to display `launch.json` and stop launching the debugger.. - // tslint:disable-next-line:no-any - return {} as any; - } const numberOfSettings = Object.keys(config); if ((config.noDebug === true && numberOfSettings.length === 1) || numberOfSettings.length === 0) { diff --git a/src/client/debugger/mainV2.ts b/src/client/debugger/mainV2.ts index 2d290fc4bc29..9c5df1076ec4 100644 --- a/src/client/debugger/mainV2.ts +++ b/src/client/debugger/mainV2.ts @@ -22,6 +22,7 @@ import { createDeferred, Deferred, sleep } from '../../utils/async'; import { noop } from '../../utils/misc'; import { isNotInstalledError } from '../common/helpers'; import { IFileSystem } from '../common/platform/types'; +import { IProcessServiceFactory } from '../common/process/types'; import { ICurrentProcess } from '../common/types'; import { IServiceContainer } from '../ioc/types'; import { AttachRequestArguments, LaunchRequestArguments } from './Common/Contracts'; @@ -33,6 +34,7 @@ const killProcessTree = require('tree-kill'); const DEBUGGER_CONNECT_TIMEOUT = 20000; const MIN_DEBUGGER_CONNECT_TIMEOUT = 5000; +const InvalidPythonPathInDebuggerMessage = 'You need to select a Python interpreter before you start debugging. \nTip: click on "Select Python Environment" in the status bar.'; /** * Primary purpose of this class is to perform the handshake with VS Code and launch PTVSD process. @@ -106,14 +108,33 @@ export class PythonDebugger extends DebugSession { if ((typeof args.module !== 'string' || args.module.length === 0) && args.program && !fs.fileExistsSync(args.program)) { return this.sendErrorResponse(response, { format: `File does not exist. "${args.program}"`, id: 1 }, undefined, undefined, ErrorDestination.User); } - this.launchPTVSD(args) - .then(() => this.waitForPTVSDToConnect(args)) - .then(() => this.emit('debugger_launched')) + + this.validatePythonPath(response, args) + .then(valid => { + if (!valid) { + return; + } + return this.launchPTVSD(args) + .then(() => this.waitForPTVSDToConnect(args)) + .then(() => this.emit('debugger_launched')); + }) .catch(ex => { const message = this.getUserFriendlyLaunchErrorMessage(args, ex) || 'Debug Error'; this.sendErrorResponse(response, { format: message, id: 1 }, undefined, undefined, ErrorDestination.User); }); } + private async validatePythonPath(response: DebugProtocol.LaunchResponse, args: LaunchRequestArguments): Promise { + const pythonPath = typeof args.pythonPath === 'string' && args.pythonPath.length > 0 ? args.pythonPath : 'python'; + const processFactory = this.serviceContainer.get(IProcessServiceFactory); + const processService = await processFactory.create(); + const valid = await processService.exec(pythonPath, ['--version']) + .then(output => output.stdout.trim().length > 0) + .catch(() => false); + if (!valid) { + this.sendErrorResponse(response, { format: InvalidPythonPathInDebuggerMessage, id: 2 }, undefined, undefined, ErrorDestination.User); + } + return valid; + } private async launchPTVSD(args: LaunchRequestArguments) { const launcher = CreateLaunchDebugClient(args, this, this.supportsRunInTerminalRequest); this.debugServer = launcher.CreateDebugServer(undefined, this.serviceContainer); diff --git a/src/client/debugger/serviceRegistry.ts b/src/client/debugger/serviceRegistry.ts index 3762736006f0..a35ea1f64933 100644 --- a/src/client/debugger/serviceRegistry.ts +++ b/src/client/debugger/serviceRegistry.ts @@ -9,12 +9,15 @@ import { FileSystem } from '../common/platform/fileSystem'; import { PlatformService } from '../common/platform/platformService'; import { IFileSystem, IPlatformService } from '../common/platform/types'; import { CurrentProcess } from '../common/process/currentProcess'; +import { BufferDecoder } from '../common/process/decoder'; +import { IBufferDecoder, IProcessServiceFactory } from '../common/process/types'; import { ICurrentProcess, ISocketServer } from '../common/types'; import { ServiceContainer } from '../ioc/container'; import { ServiceManager } from '../ioc/serviceManager'; import { IServiceContainer, IServiceManager } from '../ioc/types'; import { DebuggerBanner } from './banner'; import { DebugStreamProvider } from './Common/debugStreamProvider'; +import { DebuggerProcessServiceFactory } from './Common/processServiceFactory'; import { ProtocolLogger } from './Common/protocolLogger'; import { ProtocolParser } from './Common/protocolParser'; import { ProtocolMessageWriter } from './Common/protocolWriter'; @@ -38,6 +41,8 @@ function registerDebuggerTypes(serviceManager: IServiceManager) { serviceManager.addSingleton(IPlatformService, PlatformService); serviceManager.addSingleton(ISocketServer, SocketServer); serviceManager.addSingleton(IProtocolMessageWriter, ProtocolMessageWriter); + serviceManager.addSingleton(IBufferDecoder, BufferDecoder); + serviceManager.addSingleton(IProcessServiceFactory, DebuggerProcessServiceFactory); } export function registerTypes(serviceManager: IServiceManager) { diff --git a/src/client/interpreter/locators/services/currentPathService.ts b/src/client/interpreter/locators/services/currentPathService.ts index 32599fbdf4c0..f421cee2db44 100644 --- a/src/client/interpreter/locators/services/currentPathService.ts +++ b/src/client/interpreter/locators/services/currentPathService.ts @@ -6,7 +6,6 @@ import { IProcessServiceFactory } from '../../../common/process/types'; import { IConfigurationService } from '../../../common/types'; import { IServiceContainer } from '../../../ioc/types'; import { IInterpreterHelper, InterpreterType, PythonInterpreter } from '../../contracts'; -import { IVirtualEnvironmentManager } from '../../virtualEnvs/types'; import { CacheableLocatorService } from './cacheableLocatorService'; /** @@ -20,7 +19,6 @@ export class CurrentPathService extends CacheableLocatorService { private readonly fs: IFileSystem; public constructor( - @inject(IVirtualEnvironmentManager) private virtualEnvMgr: IVirtualEnvironmentManager, @inject(IInterpreterHelper) private helper: IInterpreterHelper, @inject(IProcessServiceFactory) private readonly processServiceFactory: IProcessServiceFactory, @inject(IServiceContainer) serviceContainer: IServiceContainer @@ -60,28 +58,23 @@ export class CurrentPathService extends CacheableLocatorService { .then(listOfInterpreters => _.flatten(listOfInterpreters)) .then(interpreters => interpreters.filter(item => item.length > 0)) // tslint:disable-next-line:promise-function-async - .then(interpreters => Promise.all(interpreters.map(interpreter => this.getInterpreterDetails(interpreter, resource)))) + .then(interpreters => Promise.all(interpreters.map(interpreter => this.getInterpreterDetails(interpreter)))) .then(interpreters => interpreters.filter(item => !!item).map(item => item!)); } /** * Return the information about the identified interpreter binary. */ - private async getInterpreterDetails(interpreter: string, resource?: Uri): Promise { - return Promise.all([ - this.helper.getInterpreterInformation(interpreter), - this.virtualEnvMgr.getEnvironmentName(interpreter, resource), - this.virtualEnvMgr.getEnvironmentType(interpreter, resource) - ]). - then(([details, virtualEnvName, type]) => { + private async getInterpreterDetails(interpreter: string): Promise { + return this.helper.getInterpreterInformation(interpreter) + .then(details => { if (!details) { return; } return { ...(details as PythonInterpreter), - envName: virtualEnvName, path: interpreter, - type: type ? type : InterpreterType.Unknown + type: details.type ? details.type : InterpreterType.Unknown }; }); } diff --git a/src/test/application/diagnostics/checks/invalidPythonPathInDebugger.unit.test.ts b/src/test/application/diagnostics/checks/invalidPythonPathInDebugger.unit.test.ts deleted file mode 100644 index 6ca4d2797e7c..000000000000 --- a/src/test/application/diagnostics/checks/invalidPythonPathInDebugger.unit.test.ts +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -'use strict'; - -// tslint:disable:no-invalid-template-strings max-func-body-length - -import { expect } from 'chai'; -import * as path from 'path'; -import * as typemoq from 'typemoq'; -import { InvalidPythonPathInDebuggerService } from '../../../../client/application/diagnostics/checks/invalidPythonPathInDebugger'; -import { CommandOption, IDiagnosticsCommandFactory } from '../../../../client/application/diagnostics/commands/types'; -import { DiagnosticCodes } from '../../../../client/application/diagnostics/constants'; -import { DiagnosticCommandPromptHandlerServiceId, MessageCommandPrompt } from '../../../../client/application/diagnostics/promptHandler'; -import { IDiagnostic, IDiagnosticCommand, IDiagnosticHandlerService, IInvalidPythonPathInDebuggerService } from '../../../../client/application/diagnostics/types'; -import { IConfigurationService, IPythonSettings } from '../../../../client/common/types'; -import { IInterpreterHelper } from '../../../../client/interpreter/contracts'; -import { IServiceContainer } from '../../../../client/ioc/types'; - -suite('Application Diagnostics - Checks Python Path in debugger', () => { - let diagnosticService: IInvalidPythonPathInDebuggerService; - let messageHandler: typemoq.IMock>; - let commandFactory: typemoq.IMock; - let configService: typemoq.IMock; - let helper: typemoq.IMock; - setup(() => { - const serviceContainer = typemoq.Mock.ofType(); - messageHandler = typemoq.Mock.ofType>(); - serviceContainer.setup(s => s.get(typemoq.It.isValue(IDiagnosticHandlerService), typemoq.It.isValue(DiagnosticCommandPromptHandlerServiceId))) - .returns(() => messageHandler.object); - commandFactory = typemoq.Mock.ofType(); - serviceContainer.setup(s => s.get(typemoq.It.isValue(IDiagnosticsCommandFactory))) - .returns(() => commandFactory.object); - configService = typemoq.Mock.ofType(); - serviceContainer.setup(s => s.get(typemoq.It.isValue(IConfigurationService))) - .returns(() => configService.object); - helper = typemoq.Mock.ofType(); - serviceContainer.setup(s => s.get(typemoq.It.isValue(IInterpreterHelper))) - .returns(() => helper.object); - - diagnosticService = new InvalidPythonPathInDebuggerService(serviceContainer.object); - }); - - test('Can handle InvalidPythonPathInDebugger diagnostics', async () => { - const diagnostic = typemoq.Mock.ofType(); - diagnostic.setup(d => d.code) - .returns(() => DiagnosticCodes.InvalidPythonPathInDebuggerDiagnostic) - .verifiable(typemoq.Times.atLeastOnce()); - - const canHandle = await diagnosticService.canHandle(diagnostic.object); - expect(canHandle).to.be.equal(true, 'Invalid value'); - diagnostic.verifyAll(); - }); - test('Can not handle non-InvalidPythonPathInDebugger diagnostics', async () => { - const diagnostic = typemoq.Mock.ofType(); - diagnostic.setup(d => d.code) - .returns(() => 'Something Else') - .verifiable(typemoq.Times.atLeastOnce()); - - const canHandle = await diagnosticService.canHandle(diagnostic.object); - expect(canHandle).to.be.equal(false, 'Invalid value'); - diagnostic.verifyAll(); - }); - test('Should return empty diagnostics', async () => { - const diagnostics = await diagnosticService.diagnose(); - expect(diagnostics).to.be.deep.equal([]); - }); - test('Should display one option to with a command', async () => { - const diagnostic = typemoq.Mock.ofType(); - diagnostic.setup(d => d.code) - .returns(() => DiagnosticCodes.InvalidEnvironmentPathVariableDiagnostic) - .verifiable(typemoq.Times.atLeastOnce()); - const interpreterSelectionCommand = typemoq.Mock.ofType(); - commandFactory.setup(f => f.createCommand(typemoq.It.isAny(), - typemoq.It.isObjectWith>({ type: 'executeVSCCommand' }))) - .returns(() => interpreterSelectionCommand.object) - .verifiable(typemoq.Times.once()); - messageHandler.setup(m => m.handle(typemoq.It.isAny(), typemoq.It.isAny())) - .verifiable(typemoq.Times.once()); - - await diagnosticService.handle([diagnostic.object]); - - diagnostic.verifyAll(); - commandFactory.verifyAll(); - messageHandler.verifyAll(); - }); - test('Ensure we get python path from config when path = ${config:python.pythonPath}', async () => { - const pythonPath = '${config:python.pythonPath}'; - - const settings = typemoq.Mock.ofType(); - settings - .setup(s => s.pythonPath) - .returns(() => 'p') - .verifiable(typemoq.Times.once()); - configService - .setup(c => c.getSettings(typemoq.It.isAny())) - .returns(() => settings.object) - .verifiable(typemoq.Times.once()); - helper - .setup(h => h.getInterpreterInformation(typemoq.It.isValue('p'))) - .returns(() => Promise.resolve({})) - .verifiable(typemoq.Times.once()); - - const valid = await diagnosticService.validatePythonPath(pythonPath); - - settings.verifyAll(); - configService.verifyAll(); - helper.verifyAll(); - expect(valid).to.be.equal(true, 'not valid'); - }); - test('Ensure we get python path from config when path = undefined', async () => { - const pythonPath = undefined; - - const settings = typemoq.Mock.ofType(); - settings - .setup(s => s.pythonPath) - .returns(() => 'p') - .verifiable(typemoq.Times.once()); - configService - .setup(c => c.getSettings(typemoq.It.isAny())) - .returns(() => settings.object) - .verifiable(typemoq.Times.once()); - helper - .setup(h => h.getInterpreterInformation(typemoq.It.isValue('p'))) - .returns(() => Promise.resolve({})) - .verifiable(typemoq.Times.once()); - - const valid = await diagnosticService.validatePythonPath(pythonPath); - - settings.verifyAll(); - configService.verifyAll(); - helper.verifyAll(); - expect(valid).to.be.equal(true, 'not valid'); - }); - test('Ensure we do get python path from config when path is provided', async () => { - const pythonPath = path.join('a', 'b'); - - const settings = typemoq.Mock.ofType(); - configService - .setup(c => c.getSettings(typemoq.It.isAny())) - .returns(() => settings.object) - .verifiable(typemoq.Times.never()); - helper - .setup(h => h.getInterpreterInformation(typemoq.It.isValue(pythonPath))) - .returns(() => Promise.resolve({})) - .verifiable(typemoq.Times.once()); - - const valid = await diagnosticService.validatePythonPath(pythonPath); - - configService.verifyAll(); - helper.verifyAll(); - expect(valid).to.be.equal(true, 'not valid'); - }); - test('Ensure diagnosics are handled when path is invalid', async () => { - const pythonPath = path.join('a', 'b'); - let handleInvoked = false; - diagnosticService.handle = () => { handleInvoked = true; return Promise.resolve(); }; - helper - .setup(h => h.getInterpreterInformation(typemoq.It.isValue(pythonPath))) - .returns(() => Promise.resolve(undefined)) - .verifiable(typemoq.Times.once()); - - const valid = await diagnosticService.validatePythonPath(pythonPath); - - helper.verifyAll(); - expect(valid).to.be.equal(false, 'should be invalid'); - expect(handleInvoked).to.be.equal(true, 'should be invoked'); - }); -}); diff --git a/src/test/debugger/configProvider/provider.unit.test.ts b/src/test/debugger/configProvider/provider.unit.test.ts index 57b53145a038..aa6d30920c95 100644 --- a/src/test/debugger/configProvider/provider.unit.test.ts +++ b/src/test/debugger/configProvider/provider.unit.test.ts @@ -9,8 +9,6 @@ import { expect } from 'chai'; import * as path from 'path'; import * as TypeMoq from 'typemoq'; import { DebugConfiguration, DebugConfigurationProvider, TextDocument, TextEditor, Uri, WorkspaceFolder } from 'vscode'; -import { InvalidPythonPathInDebuggerServiceId } from '../../../client/application/diagnostics/checks/invalidPythonPathInDebugger'; -import { IDiagnosticsService, IInvalidPythonPathInDebuggerService } from '../../../client/application/diagnostics/types'; import { IApplicationShell, IDocumentManager, IWorkspaceService } from '../../../client/common/application/types'; import { PYTHON_LANGUAGE } from '../../../client/common/constants'; import { IFileSystem, IPlatformService } from '../../../client/common/platform/types'; @@ -34,7 +32,6 @@ suite('Debugging - Config Provider', () => { let pythonExecutionService: TypeMoq.IMock; let logger: TypeMoq.IMock; let helper: TypeMoq.IMock; - let diagnosticsService: TypeMoq.IMock; setup(() => { serviceContainer = TypeMoq.Mock.ofType(); debugProvider = new PythonV2DebugConfigurationProvider(serviceContainer.object); @@ -50,7 +47,6 @@ suite('Debugging - Config Provider', () => { fileSystem = TypeMoq.Mock.ofType(); appShell = TypeMoq.Mock.ofType(); logger = TypeMoq.Mock.ofType(); - diagnosticsService = TypeMoq.Mock.ofType(); pythonExecutionService = TypeMoq.Mock.ofType(); helper = TypeMoq.Mock.ofType(); @@ -59,10 +55,6 @@ suite('Debugging - Config Provider', () => { factory.setup(f => f.create(TypeMoq.It.isAny())).returns(() => Promise.resolve(pythonExecutionService.object)); helper.setup(h => h.getInterpreterInformation(TypeMoq.It.isAny())).returns(() => Promise.resolve({})); - diagnosticsService - .setup(h => h.validatePythonPath(TypeMoq.It.isAny(), TypeMoq.It.isAny())) - .returns(() => Promise.resolve(true)); - serviceContainer.setup(c => c.get(TypeMoq.It.isValue(IPythonExecutionFactory))).returns(() => factory.object); serviceContainer.setup(c => c.get(TypeMoq.It.isValue(IConfigurationService))).returns(() => confgService.object); serviceContainer.setup(c => c.get(TypeMoq.It.isValue(IPlatformService))).returns(() => platformService.object); @@ -71,7 +63,6 @@ suite('Debugging - Config Provider', () => { serviceContainer.setup(c => c.get(TypeMoq.It.isValue(IConfigurationProviderUtils))).returns(() => new ConfigurationProviderUtils(serviceContainer.object)); serviceContainer.setup(c => c.get(TypeMoq.It.isValue(ILogger))).returns(() => logger.object); serviceContainer.setup(c => c.get(TypeMoq.It.isValue(IInterpreterHelper))).returns(() => helper.object); - serviceContainer.setup(c => c.get(TypeMoq.It.isValue(IDiagnosticsService), TypeMoq.It.isValue(InvalidPythonPathInDebuggerServiceId))).returns(() => diagnosticsService.object); const settings = TypeMoq.Mock.ofType(); settings.setup(s => s.pythonPath).returns(() => pythonPath); @@ -412,22 +403,4 @@ suite('Debugging - Config Provider', () => { expect((debugConfig as any).debugOptions).contains(DebugOptions.RedirectOutput); expect((debugConfig as any).debugOptions).contains(DebugOptions.Jinja); }); - test('Test validation of Python Path when launching debugger', async () => { - const pythonPath = `PythonPath_${new Date().toString()}`; - const workspaceFolder = createMoqWorkspaceFolder(__dirname); - const pythonFile = 'xyz.py'; - setupIoc(pythonPath); - setupActiveEditor(pythonFile, PYTHON_LANGUAGE); - - diagnosticsService.reset(); - diagnosticsService - .setup(h => h.validatePythonPath(TypeMoq.It.isValue(pythonPath), TypeMoq.It.isAny())) - .returns(() => Promise.resolve(false)) - .verifiable(TypeMoq.Times.once()); - - const debugConfig = await debugProvider.resolveDebugConfiguration!(workspaceFolder, { redirectOutput: false, pythonPath } as PythonLaunchDebugConfiguration); - - diagnosticsService.verifyAll(); - expect(Object.keys(debugConfig!)).to.be.lengthOf(0); - }); }); diff --git a/src/test/interpreters/currentPathService.unit.test.ts b/src/test/interpreters/currentPathService.unit.test.ts index d3060072cb39..f9131779e51b 100644 --- a/src/test/interpreters/currentPathService.unit.test.ts +++ b/src/test/interpreters/currentPathService.unit.test.ts @@ -49,16 +49,13 @@ suite('Interpreters CurrentPath Service', () => { serviceContainer.setup(c => c.get(TypeMoq.It.isValue(IPersistentStateFactory), TypeMoq.It.isAny())).returns(() => persistentStateFactory.object); serviceContainer.setup(c => c.get(TypeMoq.It.isValue(IConfigurationService), TypeMoq.It.isAny())).returns(() => configurationService.object); - currentPathService = new CurrentPathService(virtualEnvironmentManager.object, interpreterHelper.object, procServiceFactory.object, serviceContainer.object); + currentPathService = new CurrentPathService(interpreterHelper.object, procServiceFactory.object, serviceContainer.object); }); test('Interpreters that do not exist on the file system are not excluded from the list', async () => { // Specific test for 1305 const version = 'mockVersion'; - const envName = 'mockEnvName'; interpreterHelper.setup(v => v.getInterpreterInformation(TypeMoq.It.isAny())).returns(() => Promise.resolve({ version })); - virtualEnvironmentManager.setup(v => v.getEnvironmentName(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve(envName)); - virtualEnvironmentManager.setup(v => v.getEnvironmentType(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve(InterpreterType.VirtualEnv)); const execArgs = ['-c', 'import sys;print(sys.executable)']; pythonSettings.setup(p => p.pythonPath).returns(() => 'root:Python'); @@ -75,8 +72,9 @@ suite('Interpreters CurrentPath Service', () => { const interpreters = await currentPathService.getInterpreters(); processService.verifyAll(); fileSystem.verifyAll(); + expect(interpreters).to.be.of.length(2); - expect(interpreters).to.deep.include({ version, envName, path: 'c:/root:python', type: InterpreterType.VirtualEnv }); - expect(interpreters).to.deep.include({ version, envName, path: 'c:/python3', type: InterpreterType.VirtualEnv }); + expect(interpreters).to.deep.include({ version, path: 'c:/root:python', type: InterpreterType.Unknown }); + expect(interpreters).to.deep.include({ version, path: 'c:/python3', type: InterpreterType.Unknown }); }); });