diff --git a/CHANGELOG.md b/CHANGELOG.md index df54be3bf263..f0f21fb9f7c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,14 @@ # Changelog +## 2019.5.1 (30 May 2019) -## 2019.5.0 (28 May 2019) +### Fixes + +1. Revert changes related to pathMappings in `launch.json` for `debugging` [#3568](https://github.com/Microsoft/vscode-python/issues/3568) + ([#5833](https://github.com/microsoft/vscode-python/issues/5833)) + + +## 2019.5.17059 (28 May 2019) ### Enhancements diff --git a/package-lock.json b/package-lock.json index 635ca15cf96f..415cc79803eb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "python", - "version": "2019.5.0", + "version": "2019.5.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index fa0940c9f068..25dad5ec6c7f 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "python", "displayName": "Python", "description": "Linting, Debugging (multi-threaded, remote), Intellisense, code formatting, refactoring, unit tests, snippets, and more.", - "version": "2019.5.0", + "version": "2019.5.1", "languageServerVersion": "0.2.82", "publisher": "ms-python", "author": { diff --git a/src/client/debugger/extension/configuration/resolvers/launch.ts b/src/client/debugger/extension/configuration/resolvers/launch.ts index bd596b9163ef..4efb111655ba 100644 --- a/src/client/debugger/extension/configuration/resolvers/launch.ts +++ b/src/client/debugger/extension/configuration/resolvers/launch.ts @@ -122,19 +122,6 @@ export class LaunchConfigurationResolver extends BaseConfigurationResolver { expect(debugConfig).to.have.property('justMyCode', testParams.expectedResult); }); }); - test('Ensure pathMappings property is correctly derived', async () => { - const pythonPath = `PythonPath_${new Date().toString()}`; - const workspaceFolder = createMoqWorkspaceFolder(__dirname); - const pythonFile = 'xyz.py'; - setupIoc(pythonPath); - setupActiveEditor(pythonFile, PYTHON_LANGUAGE); - const debugConfig = await debugProvider.resolveDebugConfiguration!(workspaceFolder, { localRoot: 'abc', remoteRoot: 'remoteabc' } as LaunchRequestArguments); - expect(debugConfig).to.have.property('pathMappings'); - expect(debugConfig!.pathMappings).to.deep.equal([{ localRoot: workspaceFolder.uri.fsPath, remoteRoot: '.' }, { localRoot: 'abc', remoteRoot: 'remoteabc' }]); - }); async function testFixFilePathCase(isWindows: boolean, isMac: boolean, isLinux: boolean) { const pythonPath = `PythonPath_${new Date().toString()}`; const workspaceFolder = createMoqWorkspaceFolder(__dirname); diff --git a/src/test/testing/common/debugLauncher.unit.test.ts b/src/test/testing/common/debugLauncher.unit.test.ts index 471abaa2dfde..90987785c0ce 100644 --- a/src/test/testing/common/debugLauncher.unit.test.ts +++ b/src/test/testing/common/debugLauncher.unit.test.ts @@ -232,19 +232,6 @@ suite('Unit Tests - Debug Launcher', () => { if (isOs(OSType.Windows)) { expected.debugOptions.push(DebugOptions.FixFilePathCase); } - if (!expected.pathMappings) { - expected.pathMappings = expected.workspaceFolder ? [{ - localRoot: expected.workspaceFolder, - remoteRoot: '.' - }] : []; - } - // This is for backwards compatibility. - if (expected.localRoot && expected.remoteRoot) { - expected.pathMappings!.push({ - localRoot: expected.localRoot, - remoteRoot: expected.remoteRoot - }); - } setupDebugManager( workspaceFolders[0], @@ -253,177 +240,177 @@ suite('Unit Tests - Debug Launcher', () => { ); } - const testProviders: TestProvider[] = ['nosetest', 'pytest', 'unittest']; - // tslint:disable-next-line:max-func-body-length - testProviders.forEach(testProvider => { - const testTitleSuffix = `(Test Framework '${testProvider}')`; + const testProviders: TestProvider[] = ['nosetest', 'pytest', 'unittest']; + // tslint:disable-next-line:max-func-body-length + testProviders.forEach(testProvider => { + const testTitleSuffix = `(Test Framework '${testProvider}')`; + + test(`Must launch debugger ${testTitleSuffix}`, async () => { + const options = { + cwd: 'one/two/three', + args: ['/one/two/three/testfile.py'], + testProvider + }; + setupSuccess(options, testProvider); + + await debugLauncher.launchDebugger(options); - test(`Must launch debugger ${testTitleSuffix}`, async () => { - const options = { + debugService.verifyAll(); + }); + test(`Must launch debugger with arguments ${testTitleSuffix}`, async () => { + const options = { + cwd: 'one/two/three', + args: ['/one/two/three/testfile.py', '--debug', '1'], + testProvider + }; + setupSuccess(options, testProvider); + + await debugLauncher.launchDebugger(options); + + debugService.verifyAll(); + }); + test(`Must not launch debugger if cancelled ${testTitleSuffix}`, async () => { + debugService.setup(d => d.startDebugging(TypeMoq.It.isAny(), TypeMoq.It.isAny())) + .returns(() => { + return Promise.resolve(undefined as any); + }) + .verifiable(TypeMoq.Times.never()); + + const cancellationToken = new CancellationTokenSource(); + cancellationToken.cancel(); + const token = cancellationToken.token; + const options: LaunchOptions = { cwd: '', args: [], token, testProvider }; + + await expect( + debugLauncher.launchDebugger(options) + ).to.be.eventually.equal(undefined, 'not undefined'); + + debugService.verifyAll(); + }); + test(`Must throw an exception if there are no workspaces ${testTitleSuffix}`, async () => { + hasWorkspaceFolders = false; + debugService.setup(d => d.startDebugging(TypeMoq.It.isAny(), TypeMoq.It.isAny())) + .returns(() => Promise.resolve(undefined as any)) + .verifiable(TypeMoq.Times.never()); + + const options: LaunchOptions = { cwd: '', args: [], testProvider }; + + await expect( + debugLauncher.launchDebugger(options) + ).to.eventually.rejectedWith('Please open a workspace'); + + debugService.verifyAll(); + }); + }); + + test('Tries launch.json first', async () => { + const options: LaunchOptions = { cwd: 'one/two/three', args: ['/one/two/three/testfile.py'], - testProvider + testProvider: 'unittest' }; - setupSuccess(options, testProvider); + const expected = getDefaultDebugConfig(); + expected.name = 'spam'; + setupSuccess(options, 'unittest', expected, [ + { name: 'spam', type: DebuggerTypeName, request: 'test' } + ]); await debugLauncher.launchDebugger(options); debugService.verifyAll(); }); - test(`Must launch debugger with arguments ${testTitleSuffix}`, async () => { - const options = { + + test('Full debug config', async () => { + const options: LaunchOptions = { cwd: 'one/two/three', - args: ['/one/two/three/testfile.py', '--debug', '1'], - testProvider + args: ['/one/two/three/testfile.py'], + testProvider: 'unittest' + }; + const expected = { + name: 'my tests', + type: DebuggerTypeName, + request: 'launch', + pythonPath: 'some/dir/bin/py3', + stopOnEntry: true, + showReturnValue: true, + console: 'integratedTerminal', + cwd: 'some/dir', + env: { + SPAM: 'EGGS' + }, + envFile: 'some/dir/.env', + redirectOutput: false, + debugStdLib: true, + justMyCode: false, + // added by LaunchConfigurationResolver: + internalConsoleOptions: 'neverOpen' }; - setupSuccess(options, testProvider); + setupSuccess(options, 'unittest', expected, [ + { + name: 'my tests', + type: DebuggerTypeName, + request: 'test', + pythonPath: expected.pythonPath, + stopOnEntry: expected.stopOnEntry, + showReturnValue: expected.showReturnValue, + console: expected.console, + cwd: expected.cwd, + env: expected.env, + envFile: expected.envFile, + redirectOutput: expected.redirectOutput, + debugStdLib: expected.debugStdLib, + justMyCode: undefined + } + ]); await debugLauncher.launchDebugger(options); debugService.verifyAll(); }); - test(`Must not launch debugger if cancelled ${testTitleSuffix}`, async () => { - debugService.setup(d => d.startDebugging(TypeMoq.It.isAny(), TypeMoq.It.isAny())) - .returns(() => { - return Promise.resolve(undefined as any); - }) - .verifiable(TypeMoq.Times.never()); - - const cancellationToken = new CancellationTokenSource(); - cancellationToken.cancel(); - const token = cancellationToken.token; - const options: LaunchOptions = { cwd: '', args: [], token, testProvider }; - - await expect( - debugLauncher.launchDebugger(options) - ).to.be.eventually.equal(undefined, 'not undefined'); - debugService.verifyAll(); - }); - test(`Must throw an exception if there are no workspaces ${testTitleSuffix}`, async () => { - hasWorkspaceFolders = false; - debugService.setup(d => d.startDebugging(TypeMoq.It.isAny(), TypeMoq.It.isAny())) - .returns(() => Promise.resolve(undefined as any)) - .verifiable(TypeMoq.Times.never()); - - const options: LaunchOptions = { cwd: '', args: [], testProvider }; + test('Uses first entry', async () => { + const options: LaunchOptions = { + cwd: 'one/two/three', + args: ['/one/two/three/testfile.py'], + testProvider: 'unittest' + }; + const expected = getDefaultDebugConfig(); + expected.name = 'spam1'; + setupSuccess(options, 'unittest', expected, [ + { name: 'spam1', type: DebuggerTypeName, request: 'test' }, + { name: 'spam2', type: DebuggerTypeName, request: 'test' }, + { name: 'spam3', type: DebuggerTypeName, request: 'test' } + ]); - await expect( - debugLauncher.launchDebugger(options) - ).to.eventually.rejectedWith('Please open a workspace'); + await debugLauncher.launchDebugger(options); debugService.verifyAll(); }); - }); - - test('Tries launch.json first', async () => { - const options: LaunchOptions = { - cwd: 'one/two/three', - args: ['/one/two/three/testfile.py'], - testProvider: 'unittest' - }; - const expected = getDefaultDebugConfig(); - expected.name = 'spam'; - setupSuccess(options, 'unittest', expected, [ - { name: 'spam', type: DebuggerTypeName, request: 'test' } - ]); - - await debugLauncher.launchDebugger(options); - - debugService.verifyAll(); - }); - - test('Full debug config', async () => { - const options: LaunchOptions = { - cwd: 'one/two/three', - args: ['/one/two/three/testfile.py'], - testProvider: 'unittest' - }; - const expected = { - name: 'my tests', - type: DebuggerTypeName, - request: 'launch', - pythonPath: 'some/dir/bin/py3', - stopOnEntry: true, - showReturnValue: true, - console: 'integratedTerminal', - cwd: 'some/dir', - env: { - SPAM: 'EGGS' - }, - envFile: 'some/dir/.env', - redirectOutput: false, - debugStdLib: true, - justMyCode: false, - // added by LaunchConfigurationResolver: - internalConsoleOptions: 'neverOpen' - }; - setupSuccess(options, 'unittest', expected, [ - { - name: 'my tests', - type: DebuggerTypeName, - request: 'test', - pythonPath: expected.pythonPath, - stopOnEntry: expected.stopOnEntry, - showReturnValue: expected.showReturnValue, - console: expected.console, - cwd: expected.cwd, - env: expected.env, - envFile: expected.envFile, - redirectOutput: expected.redirectOutput, - debugStdLib: expected.debugStdLib, - justMyCode: undefined - } - ]); - await debugLauncher.launchDebugger(options); - - debugService.verifyAll(); - }); - - test('Uses first entry', async () => { - const options: LaunchOptions = { - cwd: 'one/two/three', - args: ['/one/two/three/testfile.py'], - testProvider: 'unittest' - }; - const expected = getDefaultDebugConfig(); - expected.name = 'spam1'; - setupSuccess(options, 'unittest', expected, [ - { name: 'spam1', type: DebuggerTypeName, request: 'test' }, - { name: 'spam2', type: DebuggerTypeName, request: 'test' }, - { name: 'spam3', type: DebuggerTypeName, request: 'test' } - ]); - - await debugLauncher.launchDebugger(options); - - debugService.verifyAll(); - }); - - test('Handles bad JSON', async () => { - const options: LaunchOptions = { - cwd: 'one/two/three', - args: ['/one/two/three/testfile.py'], - testProvider: 'unittest' - }; - const expected = getDefaultDebugConfig(); - setupSuccess(options, 'unittest', expected, ']'); + test('Handles bad JSON', async () => { + const options: LaunchOptions = { + cwd: 'one/two/three', + args: ['/one/two/three/testfile.py'], + testProvider: 'unittest' + }; + const expected = getDefaultDebugConfig(); + setupSuccess(options, 'unittest', expected, ']'); - await debugLauncher.launchDebugger(options); + await debugLauncher.launchDebugger(options); - debugService.verifyAll(); - }); + debugService.verifyAll(); + }); - const malformedFiles = [ - '// test 1', - '// test 2 \n\ + const malformedFiles = [ + '// test 1', + '// test 2 \n\ { \n\ "name": "spam", \n\ "type": "python", \n\ "request": "test" \n\ } \n\ ', - '// test 3 \n\ + '// test 3 \n\ [ \n\ { \n\ "name": "spam", \n\ @@ -432,7 +419,7 @@ suite('Unit Tests - Debug Launcher', () => { } \n\ ] \n\ ', - '// test 4 \n\ + '// test 4 \n\ { \n\ "configurations": [ \n\ { \n\ @@ -443,129 +430,129 @@ suite('Unit Tests - Debug Launcher', () => { ] \n\ } \n\ ' - ]; - for (const text of malformedFiles) { - const testID = text.split('\n')[0].substring(3).trim(); - test(`Handles malformed launch.json - ${testID}`, async () => { + ]; + for (const text of malformedFiles) { + const testID = text.split('\n')[0].substring(3).trim(); + test(`Handles malformed launch.json - ${testID}`, async () => { + const options: LaunchOptions = { + cwd: 'one/two/three', + args: ['/one/two/three/testfile.py'], + testProvider: 'unittest' + }; + const expected = getDefaultDebugConfig(); + setupSuccess(options, 'unittest', expected, text); + + await debugLauncher.launchDebugger(options); + + debugService.verifyAll(); + }); + } + + test('Handles bad debug config items', async () => { const options: LaunchOptions = { cwd: 'one/two/three', args: ['/one/two/three/testfile.py'], testProvider: 'unittest' }; const expected = getDefaultDebugConfig(); - setupSuccess(options, 'unittest', expected, text); + // tslint:disable:no-object-literal-type-assertion + setupSuccess(options, 'unittest', expected, [ + {} as DebugConfiguration, + { name: 'spam1' } as DebugConfiguration, + { name: 'spam2', type: DebuggerTypeName } as DebugConfiguration, + { name: 'spam3', request: 'test' } as DebugConfiguration, + { type: DebuggerTypeName } as DebugConfiguration, + { type: DebuggerTypeName, request: 'test' } as DebugConfiguration, + { request: 'test' } as DebugConfiguration + ]); + // tslint:enable:no-object-literal-type-assertion await debugLauncher.launchDebugger(options); debugService.verifyAll(); }); - } - test('Handles bad debug config items', async () => { - const options: LaunchOptions = { - cwd: 'one/two/three', - args: ['/one/two/three/testfile.py'], - testProvider: 'unittest' - }; - const expected = getDefaultDebugConfig(); - // tslint:disable:no-object-literal-type-assertion - setupSuccess(options, 'unittest', expected, [ - {} as DebugConfiguration, - { name: 'spam1' } as DebugConfiguration, - { name: 'spam2', type: DebuggerTypeName } as DebugConfiguration, - { name: 'spam3', request: 'test' } as DebugConfiguration, - { type: DebuggerTypeName } as DebugConfiguration, - { type: DebuggerTypeName, request: 'test' } as DebugConfiguration, - { request: 'test' } as DebugConfiguration - ]); - // tslint:enable:no-object-literal-type-assertion - - await debugLauncher.launchDebugger(options); - - debugService.verifyAll(); - }); + test('Handles non-python debug configs', async () => { + const options: LaunchOptions = { + cwd: 'one/two/three', + args: ['/one/two/three/testfile.py'], + testProvider: 'unittest' + }; + const expected = getDefaultDebugConfig(); + setupSuccess(options, 'unittest', expected, [ + { name: 'foo', type: 'other', request: 'bar' } + ]); - test('Handles non-python debug configs', async () => { - const options: LaunchOptions = { - cwd: 'one/two/three', - args: ['/one/two/three/testfile.py'], - testProvider: 'unittest' - }; - const expected = getDefaultDebugConfig(); - setupSuccess(options, 'unittest', expected, [ - { name: 'foo', type: 'other', request: 'bar' } - ]); + await debugLauncher.launchDebugger(options); - await debugLauncher.launchDebugger(options); + debugService.verifyAll(); + }); - debugService.verifyAll(); - }); + test('Handles bogus python debug configs', async () => { + const options: LaunchOptions = { + cwd: 'one/two/three', + args: ['/one/two/three/testfile.py'], + testProvider: 'unittest' + }; + const expected = getDefaultDebugConfig(); + setupSuccess(options, 'unittest', expected, [ + { name: 'spam', type: DebuggerTypeName, request: 'bogus' } + ]); - test('Handles bogus python debug configs', async () => { - const options: LaunchOptions = { - cwd: 'one/two/three', - args: ['/one/two/three/testfile.py'], - testProvider: 'unittest' - }; - const expected = getDefaultDebugConfig(); - setupSuccess(options, 'unittest', expected, [ - { name: 'spam', type: DebuggerTypeName, request: 'bogus' } - ]); + await debugLauncher.launchDebugger(options); - await debugLauncher.launchDebugger(options); + debugService.verifyAll(); + }); - debugService.verifyAll(); - }); + test('Handles non-test debug config', async () => { + const options: LaunchOptions = { + cwd: 'one/two/three', + args: ['/one/two/three/testfile.py'], + testProvider: 'unittest' + }; + const expected = getDefaultDebugConfig(); + setupSuccess(options, 'unittest', expected, [ + { name: 'spam', type: DebuggerTypeName, request: 'launch' }, + { name: 'spam', type: DebuggerTypeName, request: 'attach' } + ]); - test('Handles non-test debug config', async () => { - const options: LaunchOptions = { - cwd: 'one/two/three', - args: ['/one/two/three/testfile.py'], - testProvider: 'unittest' - }; - const expected = getDefaultDebugConfig(); - setupSuccess(options, 'unittest', expected, [ - { name: 'spam', type: DebuggerTypeName, request: 'launch' }, - { name: 'spam', type: DebuggerTypeName, request: 'attach' } - ]); + await debugLauncher.launchDebugger(options); - await debugLauncher.launchDebugger(options); + debugService.verifyAll(); + }); - debugService.verifyAll(); - }); + test('Handles mixed debug config', async () => { + const options: LaunchOptions = { + cwd: 'one/two/three', + args: ['/one/two/three/testfile.py'], + testProvider: 'unittest' + }; + const expected = getDefaultDebugConfig(); + expected.name = 'spam2'; + setupSuccess(options, 'unittest', expected, [ + { name: 'foo1', type: 'other', request: 'bar' }, + { name: 'foo2', type: 'other', request: 'bar' }, + { name: 'spam1', type: DebuggerTypeName, request: 'launch' }, + { name: 'spam2', type: DebuggerTypeName, request: 'test' }, + { name: 'spam3', type: DebuggerTypeName, request: 'attach' }, + { name: 'xyz', type: 'another', request: 'abc' } + ]); - test('Handles mixed debug config', async () => { - const options: LaunchOptions = { - cwd: 'one/two/three', - args: ['/one/two/three/testfile.py'], - testProvider: 'unittest' - }; - const expected = getDefaultDebugConfig(); - expected.name = 'spam2'; - setupSuccess(options, 'unittest', expected, [ - { name: 'foo1', type: 'other', request: 'bar' }, - { name: 'foo2', type: 'other', request: 'bar' }, - { name: 'spam1', type: DebuggerTypeName, request: 'launch' }, - { name: 'spam2', type: DebuggerTypeName, request: 'test' }, - { name: 'spam3', type: DebuggerTypeName, request: 'attach' }, - { name: 'xyz', type: 'another', request: 'abc' } - ]); - - await debugLauncher.launchDebugger(options); - - debugService.verifyAll(); - }); + await debugLauncher.launchDebugger(options); - test('Handles comments', async () => { - const options: LaunchOptions = { - cwd: 'one/two/three', - args: ['/one/two/three/testfile.py'], - testProvider: 'unittest' - }; - const expected = getDefaultDebugConfig(); - expected.name = 'spam'; - expected.stopOnEntry = true; - setupSuccess(options, 'unittest', expected, ' \n\ + debugService.verifyAll(); + }); + + test('Handles comments', async () => { + const options: LaunchOptions = { + cwd: 'one/two/three', + args: ['/one/two/three/testfile.py'], + testProvider: 'unittest' + }; + const expected = getDefaultDebugConfig(); + expected.name = 'spam'; + expected.stopOnEntry = true; + setupSuccess(options, 'unittest', expected, ' \n\ { \n\ "version": "0.1.0", \n\ "configurations": [ \n\ @@ -582,10 +569,10 @@ suite('Unit Tests - Debug Launcher', () => { } \n\ '); - await debugLauncher.launchDebugger(options); + await debugLauncher.launchDebugger(options); - debugService.verifyAll(); - }); + debugService.verifyAll(); + }); test('Ensure trailing commands in JSON are handled', async () => { const workspaceFolder = { name: 'abc', index: 0, uri: Uri.file(__filename) }; const filename = path.join(workspaceFolder.uri.fsPath, '.vscode', 'launch.json');