diff --git a/package.json b/package.json index 81128aa16bb6..5de98e8a3bcb 100644 --- a/package.json +++ b/package.json @@ -1768,8 +1768,8 @@ "unicode": "^10.0.0", "untildify": "^3.0.2", "unzip": "^0.1.11", - "vscode-debugadapter": "^1.0.1", - "vscode-debugprotocol": "^1.0.1", + "vscode-debugadapter": "^1.28.0", + "vscode-debugprotocol": "^1.28.0", "vscode-extension-telemetry": "^0.0.14", "vscode-languageclient": "^3.1.0", "vscode-languageserver": "^3.1.0", diff --git a/src/client/debugger/mainV2.ts b/src/client/debugger/mainV2.ts index 53f4d60d17cd..bcb9a9d26e8c 100644 --- a/src/client/debugger/mainV2.ts +++ b/src/client/debugger/mainV2.ts @@ -69,6 +69,10 @@ export class PythonDebugger extends DebugSession { body.supportsConditionalBreakpoints = true; body.supportsSetVariable = true; body.supportsExceptionOptions = true; + body.supportsEvaluateForHovers = true; + body.supportsModulesRequest = true; + body.supportsValueFormattingOptions = true; + body.supportsSetExpression = true; body.exceptionBreakpointFilters = [ { filter: 'raised', diff --git a/src/test/debugger/capabilities.test.ts b/src/test/debugger/capabilities.test.ts new file mode 100644 index 000000000000..8052b5f6f2dc --- /dev/null +++ b/src/test/debugger/capabilities.test.ts @@ -0,0 +1,103 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +'use strict'; + +// tslint:disable:no-suspicious-comment max-func-body-length no-invalid-this no-var-requires no-require-imports no-any + +import { expect } from 'chai'; +import { ChildProcess, spawn } from 'child_process'; +import * as getFreePort from 'get-port'; +import { connect, Socket } from 'net'; +import * as path from 'path'; +import { PassThrough } from 'stream'; +import { Message } from 'vscode-debugadapter/lib/messages'; +import { DebugProtocol } from 'vscode-debugprotocol'; +import { EXTENSION_ROOT_DIR } from '../../client/common/constants'; +import { createDeferred } from '../../client/common/helpers'; +import { ProtocolParser } from '../../client/debugger/Common/protocolParser'; +import { ProtocolMessageWriter } from '../../client/debugger/Common/protocolWriter'; +import { PythonDebugger } from '../../client/debugger/mainV2'; +import { sleep } from '../common'; +import { IS_MULTI_ROOT_TEST, TEST_DEBUGGER } from '../initialize'; + +class Request extends Message implements DebugProtocol.InitializeRequest { + // tslint:disable-next-line:no-banned-terms + public arguments: any; + constructor(public command: string, args: any) { + super('request'); + this.arguments = args; + } +} + +suite('Debugging - Capabilities', () => { + let disposables: { dispose?: Function; destroy?: Function }[]; + let proc: ChildProcess; + setup(async function () { + if (!IS_MULTI_ROOT_TEST || !TEST_DEBUGGER) { + this.skip(); + } + disposables = []; + }); + teardown(() => { + disposables.forEach(disposable => { + try { + disposable.dispose!(); + // tslint:disable-next-line:no-empty + } catch { } + try { + disposable.destroy!(); + // tslint:disable-next-line:no-empty + } catch { } + }); + try { + proc.kill(); + // tslint:disable-next-line:no-empty + } catch { } + }); + test('Compare capabilities', async () => { + const protocolWriter = new ProtocolMessageWriter(); + const initializeRequest: DebugProtocol.InitializeRequest = new Request('initialize', { pathFormat: 'path' }); + + const debugClient = new PythonDebugger(undefined as any); + const inStream = new PassThrough(); + const outStream = new PassThrough(); + disposables.push(inStream); + disposables.push(outStream); + debugClient.start(inStream, outStream); + const debugClientProtocolParser = new ProtocolParser(); + debugClientProtocolParser.connect(outStream); + disposables.push(debugClientProtocolParser); + const expectedResponsePromise = new Promise(resolve => debugClientProtocolParser.once('response_initialize', resolve)); + protocolWriter.write(inStream, initializeRequest); + const expectedResponse = await expectedResponsePromise; + + const host = 'localhost'; + const port = await getFreePort({ host }); + const env = { ...process.env }; + env.PYTHONPATH = path.join(EXTENSION_ROOT_DIR, 'pythonFiles', 'experimental', 'ptvsd'); + proc = spawn('python', ['-m', 'ptvsd', '--server', '--port', `${port}`, '--file', 'someFile.py'], { cwd: __dirname, env }); + // Wait for the socket server to start. + // Keep trying till we timeout. + let socket: Socket | undefined; + for (let index = 0; index < 1000; index += 1) { + try { + const connected = createDeferred(); + socket = connect({ port, host }, () => connected.resolve(socket)); + socket.on('error', connected.reject.bind(connected)); + await connected.promise; + break; + } catch { + await sleep(500); + } + } + const protocolParser = new ProtocolParser(); + protocolParser.connect(socket!); + disposables.push(protocolParser); + const actualResponsePromise = new Promise(resolve => protocolParser.once('response_initialize', resolve)); + protocolWriter.write(socket!, initializeRequest); + const actualResponse = await actualResponsePromise; + + expect(actualResponse.body).to.deep.equal(expectedResponse.body); + }); +}); diff --git a/yarn.lock b/yarn.lock index 19893afaaa94..7027a7bdcfbc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1826,7 +1826,7 @@ gulp-untar@^0.0.6: tar "^2.2.1" through2 "~2.0.3" -gulp-util@^3.0.0, gulp-util@^3.0.7, gulp-util@~3.0.0, gulp-util@~3.0.7, gulp-util@~3.0.8: +gulp-util@^3.0.0, gulp-util@^3.0.7, gulp-util@~3.0.8: version "3.0.8" resolved "https://registry.yarnpkg.com/gulp-util/-/gulp-util-3.0.8.tgz#0054e1e744502e27c04c187c3ecc505dd54bbb4f" dependencies: @@ -3904,7 +3904,7 @@ ret@~0.1.10: version "0.1.15" resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" -retyped-diff-match-patch-tsd-ambient@^1.0.0-1: +retyped-diff-match-patch-tsd-ambient@^1.0.0-0: version "1.0.0-1" resolved "https://registry.yarnpkg.com/retyped-diff-match-patch-tsd-ambient/-/retyped-diff-match-patch-tsd-ambient-1.0.0-1.tgz#26482bf4915c7ed9f8300bb5cbec48fd4ff5bc62" @@ -4835,16 +4835,21 @@ vscode-debugadapter-testsupport@^1.27.0: dependencies: vscode-debugprotocol "1.27.0" -vscode-debugadapter@^1.0.1: - version "1.27.0" - resolved "https://registry.yarnpkg.com/vscode-debugadapter/-/vscode-debugadapter-1.27.0.tgz#0688f7d03d7568efd653003ecdb402b7ba37231e" +vscode-debugadapter@^1.28.0: + version "1.28.0" + resolved "https://registry.yarnpkg.com/vscode-debugadapter/-/vscode-debugadapter-1.28.0.tgz#ebd6653e3f41db324d9547595375571a8732e966" dependencies: - vscode-debugprotocol "1.27.0" + vscode-debugprotocol "1.28.0" + vscode-uri "1.0.1" -vscode-debugprotocol@1.27.0, vscode-debugprotocol@^1.0.1: +vscode-debugprotocol@1.27.0: version "1.27.0" resolved "https://registry.yarnpkg.com/vscode-debugprotocol/-/vscode-debugprotocol-1.27.0.tgz#735a43a3cc1235fe587c0ef93fe4e328def7b17c" +vscode-debugprotocol@1.28.0, vscode-debugprotocol@^1.28.0: + version "1.28.0" + resolved "https://registry.yarnpkg.com/vscode-debugprotocol/-/vscode-debugprotocol-1.28.0.tgz#b9fb97c3fb2dadbec78e5c1619ff12bf741ce406" + vscode-extension-telemetry@^0.0.14: version "0.0.14" resolved "https://registry.yarnpkg.com/vscode-extension-telemetry/-/vscode-extension-telemetry-0.0.14.tgz#17454705b6bb8757351b955d812923f02ee895bf" @@ -4879,6 +4884,10 @@ vscode-languageserver@^3.1.0: vscode-languageserver-protocol "3.5.1" vscode-uri "^1.0.1" +vscode-uri@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-1.0.1.tgz#11a86befeac3c4aa3ec08623651a3c81a6d0bbc8" + vscode-uri@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-1.0.3.tgz#631bdbf716dccab0e65291a8dc25c23232085a52"