diff --git a/news/2 Fixes/4966.md b/news/2 Fixes/4966.md new file mode 100644 index 000000000000..9e03fd5b0842 --- /dev/null +++ b/news/2 Fixes/4966.md @@ -0,0 +1 @@ +getRemoteLauncherCommand should wrap path to ptvsd_launcher.py in quotes diff --git a/src/client/debugger/debugAdapter/DebugClients/launcherProvider.ts b/src/client/debugger/debugAdapter/DebugClients/launcherProvider.ts index bc4b94af90e7..455db85cde63 100644 --- a/src/client/debugger/debugAdapter/DebugClients/launcherProvider.ts +++ b/src/client/debugger/debugAdapter/DebugClients/launcherProvider.ts @@ -5,28 +5,32 @@ // tslint:disable:max-classes-per-file +import { optional } from 'inversify'; import * as path from 'path'; import { EXTENSION_ROOT_DIR } from '../../../common/constants'; import { IDebugLauncherScriptProvider, IRemoteDebugLauncherScriptProvider, LocalDebugOptions, RemoteDebugOptions } from '../types'; -const script = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'ptvsd_launcher.py'); +const pathToScript = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'ptvsd_launcher.py'); export class NoDebugLauncherScriptProvider implements IDebugLauncherScriptProvider { + constructor(@optional() private script: string = pathToScript) { } public getLauncherArgs(options: LocalDebugOptions): string[] { const customDebugger = options.customDebugger ? '--custom' : '--default'; - return [script, customDebugger, '--nodebug', '--client', '--host', options.host, '--port', options.port.toString()]; + return [this.script.fileToCommandArgument(), customDebugger, '--nodebug', '--client', '--host', options.host, '--port', options.port.toString()]; } } export class DebuggerLauncherScriptProvider implements IDebugLauncherScriptProvider { + constructor(@optional() private script: string = pathToScript) { } public getLauncherArgs(options: LocalDebugOptions): string[] { const customDebugger = options.customDebugger ? '--custom' : '--default'; - return [script, customDebugger, '--client', '--host', options.host, '--port', options.port.toString()]; + return [this.script.fileToCommandArgument(), customDebugger, '--client', '--host', options.host, '--port', options.port.toString()]; } } export class RemoteDebuggerLauncherScriptProvider implements IRemoteDebugLauncherScriptProvider { + constructor(@optional() private script: string = pathToScript) { } public getLauncherArgs(options: RemoteDebugOptions): string[] { const waitArgs = options.waitUntilDebuggerAttaches ? ['--wait'] : []; - return [script, '--default', '--host', options.host, '--port', options.port.toString()].concat(waitArgs); + return [this.script.fileToCommandArgument(), '--default', '--host', options.host, '--port', options.port.toString()].concat(waitArgs); } } diff --git a/src/test/debugger/debugAdapter/debugClients/launcherProvider.unit.test.ts b/src/test/debugger/debugAdapter/debugClients/launcherProvider.unit.test.ts index 4dd9542a6b0c..a3f67e3c22dd 100644 --- a/src/test/debugger/debugAdapter/debugClients/launcherProvider.unit.test.ts +++ b/src/test/debugger/debugAdapter/debugClients/launcherProvider.unit.test.ts @@ -11,38 +11,57 @@ import { DebuggerLauncherScriptProvider, NoDebugLauncherScriptProvider, RemoteDe const expectedPath = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'ptvsd_launcher.py'); +// tslint:disable-next-line:max-func-body-length suite('Debugger - Launcher Script Provider', () => { test('Ensure launcher script exists', async () => { expect(await fs.pathExists(expectedPath)).to.be.deep.equal(true, 'Debugger launcher script does not exist'); }); - test('Test debug launcher args', async () => { - const args = new DebuggerLauncherScriptProvider().getLauncherArgs({ host: 'something', port: 1234 }); - const expectedArgs = [expectedPath, '--default', '--client', '--host', 'something', '--port', '1234']; - expect(args).to.be.deep.equal(expectedArgs); - }); - test('Test non-debug launcher args', async () => { - const args = new NoDebugLauncherScriptProvider().getLauncherArgs({ host: 'something', port: 1234 }); - const expectedArgs = [expectedPath, '--default', '--nodebug', '--client', '--host', 'something', '--port', '1234']; - expect(args).to.be.deep.equal(expectedArgs); - }); - test('Test debug launcher args and custom ptvsd', async () => { - const args = new DebuggerLauncherScriptProvider().getLauncherArgs({ host: 'something', port: 1234, customDebugger: true }); - const expectedArgs = [expectedPath, '--custom', '--client', '--host', 'something', '--port', '1234']; - expect(args).to.be.deep.equal(expectedArgs); - }); - test('Test non-debug launcher args and custom ptvsd', async () => { - const args = new NoDebugLauncherScriptProvider().getLauncherArgs({ host: 'something', port: 1234, customDebugger: true }); - const expectedArgs = [expectedPath, '--custom', '--nodebug', '--client', '--host', 'something', '--port', '1234']; - expect(args).to.be.deep.equal(expectedArgs); - }); - test('Test remote debug launcher args (and do not wait for debugger to attach)', async () => { - const args = new RemoteDebuggerLauncherScriptProvider().getLauncherArgs({ host: 'something', port: 1234, waitUntilDebuggerAttaches: false }); - const expectedArgs = [expectedPath, '--default', '--host', 'something', '--port', '1234']; - expect(args).to.be.deep.equal(expectedArgs); - }); - test('Test remote debug launcher args (and wait for debugger to attach)', async () => { - const args = new RemoteDebuggerLauncherScriptProvider().getLauncherArgs({ host: 'something', port: 1234, waitUntilDebuggerAttaches: true }); - const expectedArgs = [expectedPath, '--default', '--host', 'something', '--port', '1234', '--wait']; - expect(args).to.be.deep.equal(expectedArgs); + const testsForLaunchProvider = + [ + { + testName: 'When path to ptvsd launcher does not contains spaces', + path: path.join('path', 'to', 'ptvsd_launcher'), + expectedPath: 'path/to/ptvsd_launcher' + }, + { + testName: 'When path to ptvsd launcher contains spaces', + path: path.join('path', 'to', 'ptvsd_launcher', 'with spaces'), + expectedPath: '"path/to/ptvsd_launcher/with spaces"' + } + ]; + + testsForLaunchProvider.forEach(testParams => { + suite(testParams.testName, async () => { + test('Test debug launcher args', async () => { + const args = new DebuggerLauncherScriptProvider(testParams.path).getLauncherArgs({ host: 'something', port: 1234 }); + const expectedArgs = [testParams.expectedPath, '--default', '--client', '--host', 'something', '--port', '1234']; + expect(args).to.be.deep.equal(expectedArgs); + }); + test('Test non-debug launcher args', async () => { + const args = new NoDebugLauncherScriptProvider(testParams.path).getLauncherArgs({ host: 'something', port: 1234 }); + const expectedArgs = [testParams.expectedPath, '--default', '--nodebug', '--client', '--host', 'something', '--port', '1234']; + expect(args).to.be.deep.equal(expectedArgs); + }); + test('Test debug launcher args and custom ptvsd', async () => { + const args = new DebuggerLauncherScriptProvider(testParams.path).getLauncherArgs({ host: 'something', port: 1234, customDebugger: true }); + const expectedArgs = [testParams.expectedPath, '--custom', '--client', '--host', 'something', '--port', '1234']; + expect(args).to.be.deep.equal(expectedArgs); + }); + test('Test non-debug launcher args and custom ptvsd', async () => { + const args = new NoDebugLauncherScriptProvider(testParams.path).getLauncherArgs({ host: 'something', port: 1234, customDebugger: true }); + const expectedArgs = [testParams.expectedPath, '--custom', '--nodebug', '--client', '--host', 'something', '--port', '1234']; + expect(args).to.be.deep.equal(expectedArgs); + }); + test('Test remote debug launcher args (and do not wait for debugger to attach)', async () => { + const args = new RemoteDebuggerLauncherScriptProvider(testParams.path).getLauncherArgs({ host: 'something', port: 1234, waitUntilDebuggerAttaches: false }); + const expectedArgs = [testParams.expectedPath, '--default', '--host', 'something', '--port', '1234']; + expect(args).to.be.deep.equal(expectedArgs); + }); + test('Test remote debug launcher args (and wait for debugger to attach)', async () => { + const args = new RemoteDebuggerLauncherScriptProvider(testParams.path).getLauncherArgs({ host: 'something', port: 1234, waitUntilDebuggerAttaches: true }); + const expectedArgs = [testParams.expectedPath, '--default', '--host', 'something', '--port', '1234', '--wait']; + expect(args).to.be.deep.equal(expectedArgs); + }); + }); }); }); diff --git a/src/test/extension.unit.test.ts b/src/test/extension.unit.test.ts index c9693be71e91..553be3f7121e 100644 --- a/src/test/extension.unit.test.ts +++ b/src/test/extension.unit.test.ts @@ -6,11 +6,10 @@ // tslint:disable:no-any import { expect } from 'chai'; -import * as path from 'path'; import { buildApi } from '../client/api'; import { EXTENSION_ROOT_DIR } from '../client/common/constants'; -const expectedPath = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'ptvsd_launcher.py'); +const expectedPath = `${EXTENSION_ROOT_DIR.fileToCommandArgument()}/pythonFiles/ptvsd_launcher.py`; suite('Extension API Debugger', () => { test('Test debug launcher args (no-wait)', async () => {