Vscode merge (#4582)

* Merge from vscode 37cb23d3dd4f9433d56d4ba5ea3203580719a0bd

* fix issues with merges

* bump node version in azpipe

* replace license headers

* remove duplicate launch task

* fix build errors

* fix build errors

* fix tslint issues

* working through package and linux build issues

* more work

* wip

* fix packaged builds

* working through linux build errors

* wip

* wip

* wip

* fix mac and linux file limits

* iterate linux pipeline

* disable editor typing

* revert series to parallel

* remove optimize vscode from linux

* fix linting issues

* revert testing change

* add work round for new node

* readd packaging for extensions

* fix issue with angular not resolving decorator dependencies
This commit is contained in:
Anthony Dresser
2019-03-19 17:44:35 -07:00
committed by GitHub
parent 833d197412
commit 87765e8673
1879 changed files with 54505 additions and 38058 deletions

View File

@@ -0,0 +1,25 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { replaceWhitespace, renderExpressionValue, renderVariable } from 'vs/workbench/contrib/debug/browser/baseDebugView';
import * as dom from 'vs/base/browser/dom';
import { MockSession } from 'vs/workbench/contrib/debug/test/common/mockDebug';
import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';
const $ = dom.$;
suite('Debug - Base Debug View', () => {
test('replace whitespace', () => {
assert.equal(replaceWhitespace('hey there'), 'hey there');
assert.equal(replaceWhitespace('hey there\n'), 'hey there\\n');
assert.equal(replaceWhitespace('hey \r there\n\t'), 'hey \\r there\\n\\t');
assert.equal(replaceWhitespace('hey \r\t\n\t\t\n there'), 'hey \\r\\t\\n\\t\\t\\n there');
});
test('render variable', () => {
// {{SQL CARBON EDIT}} - Disable test
});
});

View File

@@ -0,0 +1,18 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import * as dom from 'vs/base/browser/dom';
import { generateUuid } from 'vs/base/common/uuid';
import { appendStylizedStringToContainer, handleANSIOutput } from 'vs/workbench/contrib/debug/browser/debugANSIHandling';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { workbenchInstantiationService } from 'vs/workbench/test/workbenchTestServices';
import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector';
suite('Debug - ANSI Handling', () => {
test('appendStylizedStringToContainer', () => {
assert.equal('', '');
});
});

View File

@@ -0,0 +1,153 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { workbenchInstantiationService } from 'vs/workbench/test/workbenchTestServices';
import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector';
import { isWindows } from 'vs/base/common/platform';
suite('Debug - Link Detector', () => {
let linkDetector: LinkDetector;
/**
* Instantiate a {@link LinkDetector} for use by the functions being tested.
*/
setup(() => {
const instantiationService: TestInstantiationService = <TestInstantiationService>workbenchInstantiationService();
linkDetector = instantiationService.createInstance(LinkDetector);
});
/**
* Assert that a given Element is an anchor element with an onClick event.
*
* @param element The Element to verify.
*/
function assertElementIsLink(element: Element) {
assert(element instanceof HTMLAnchorElement);
assert.notEqual(null, (element as HTMLAnchorElement).onclick);
}
test('noLinks', () => {
const input = 'I am a string';
const expectedOutput = '<span>I am a string</span>';
const output = linkDetector.handleLinks(input);
assert.equal(0, output.children.length);
assert.equal('SPAN', output.tagName);
assert.equal(expectedOutput, output.outerHTML);
});
test('trailingNewline', () => {
const input = 'I am a string\n';
const expectedOutput = '<span>I am a string\n</span>';
const output = linkDetector.handleLinks(input);
assert.equal(0, output.children.length);
assert.equal('SPAN', output.tagName);
assert.equal(expectedOutput, output.outerHTML);
});
test('singleLineLink', () => {
const input = isWindows ? 'C:/foo/bar.js:12:34' : '/Users/foo/bar.js:12:34';
const expectedOutput = /^<span><a title=".*">.*\/foo\/bar.js:12:34<\/a><\/span>$/;
const output = linkDetector.handleLinks(input);
assert.equal(1, output.children.length);
assert.equal('SPAN', output.tagName);
assert.equal('A', output.firstElementChild!.tagName);
assert(expectedOutput.test(output.outerHTML));
assertElementIsLink(output.firstElementChild!);
assert.equal(isWindows ? 'C:/foo/bar.js:12:34' : '/Users/foo/bar.js:12:34', output.firstElementChild!.textContent);
});
test('relativeLink', () => {
const input = '\./foo/bar.js';
const expectedOutput = '<span>\./foo/bar.js</span>';
const output = linkDetector.handleLinks(input);
assert.equal(0, output.children.length);
assert.equal('SPAN', output.tagName);
assert.equal(expectedOutput, output.outerHTML);
});
test('singleLineLinkAndText', function () {
const input = isWindows ? 'The link: C:/foo/bar.js:12:34' : 'The link: /Users/foo/bar.js:12:34';
const expectedOutput = /^<span><span>The link: <\/span><a title=".*">.*\/foo\/bar.js:12:34<\/a><\/span>$/;
const output = linkDetector.handleLinks(input);
assert.equal(2, output.children.length);
assert.equal('SPAN', output.tagName);
assert.equal('SPAN', output.children[0].tagName);
assert.equal('A', output.children[1].tagName);
assert(expectedOutput.test(output.outerHTML));
assertElementIsLink(output.children[1]);
assert.equal(isWindows ? 'C:/foo/bar.js:12:34' : '/Users/foo/bar.js:12:34', output.children[1].textContent);
});
test('singleLineMultipleLinks', () => {
const input = isWindows ? 'Here is a link C:/foo/bar.js:12:34 and here is another D:/boo/far.js:56:78' :
'Here is a link /Users/foo/bar.js:12:34 and here is another /Users/boo/far.js:56:78';
const expectedOutput = /^<span><span>Here is a link <\/span><a title=".*">.*\/foo\/bar.js:12:34<\/a><span> and here is another <\/span><a title=".*">.*\/boo\/far.js:56:78<\/a><\/span>$/;
const output = linkDetector.handleLinks(input);
assert.equal(4, output.children.length);
assert.equal('SPAN', output.tagName);
assert.equal('SPAN', output.children[0].tagName);
assert.equal('A', output.children[1].tagName);
assert.equal('SPAN', output.children[2].tagName);
assert.equal('A', output.children[3].tagName);
assert(expectedOutput.test(output.outerHTML));
assertElementIsLink(output.children[1]);
assertElementIsLink(output.children[3]);
assert.equal(isWindows ? 'C:/foo/bar.js:12:34' : '/Users/foo/bar.js:12:34', output.children[1].textContent);
assert.equal(isWindows ? 'D:/boo/far.js:56:78' : '/Users/boo/far.js:56:78', output.children[3].textContent);
});
test('multilineNoLinks', () => {
const input = 'Line one\nLine two\nLine three';
const expectedOutput = /^<span><span>Line one\n<\/span><span>Line two\n<\/span><span>Line three<\/span><\/span>$/;
const output = linkDetector.handleLinks(input);
assert.equal(3, output.children.length);
assert.equal('SPAN', output.tagName);
assert.equal('SPAN', output.children[0].tagName);
assert.equal('SPAN', output.children[1].tagName);
assert.equal('SPAN', output.children[2].tagName);
assert(expectedOutput.test(output.outerHTML));
});
test('multilineTrailingNewline', () => {
const input = 'I am a string\nAnd I am another\n';
const expectedOutput = '<span><span>I am a string\n<\/span><span>And I am another\n<\/span><\/span>';
const output = linkDetector.handleLinks(input);
assert.equal(2, output.children.length);
assert.equal('SPAN', output.tagName);
assert.equal('SPAN', output.children[0].tagName);
assert.equal('SPAN', output.children[1].tagName);
assert.equal(expectedOutput, output.outerHTML);
});
test('multilineWithLinks', () => {
const input = isWindows ? 'I have a link for you\nHere it is: C:/foo/bar.js:12:34\nCool, huh?' :
'I have a link for you\nHere it is: /Users/foo/bar.js:12:34\nCool, huh?';
const expectedOutput = /^<span><span>I have a link for you\n<\/span><span><span>Here it is: <\/span><a title=".*">.*\/foo\/bar.js:12:34<\/a><span>\n<\/span><\/span><span>Cool, huh\?<\/span><\/span>$/;
const output = linkDetector.handleLinks(input);
assert.equal(3, output.children.length);
assert.equal('SPAN', output.tagName);
assert.equal('SPAN', output.children[0].tagName);
assert.equal('SPAN', output.children[1].tagName);
assert.equal('SPAN', output.children[2].tagName);
assert.equal('SPAN', output.children[1].children[0].tagName);
assert.equal('A', output.children[1].children[1].tagName);
assert.equal('SPAN', output.children[1].children[2].tagName);
assert(expectedOutput.test(output.outerHTML));
assertElementIsLink(output.children[1].children[1]);
assert.equal(isWindows ? 'C:/foo/bar.js:12:34' : '/Users/foo/bar.js:12:34', output.children[1].children[1].textContent);
});
});

View File

@@ -0,0 +1,59 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { URI as uri } from 'vs/base/common/uri';
import { Source } from 'vs/workbench/contrib/debug/common/debugSource';
import { isWindows } from 'vs/base/common/platform';
suite('Debug - Source', () => {
test('from raw source', () => {
const source = new Source({
name: 'zz',
path: '/xx/yy/zz',
sourceReference: 0,
presentationHint: 'emphasize'
}, 'aDebugSessionId');
assert.equal(source.presentationHint, 'emphasize');
assert.equal(source.name, 'zz');
assert.equal(source.inMemory, false);
assert.equal(source.reference, 0);
assert.equal(source.uri.toString(), uri.file('/xx/yy/zz').toString());
});
test('from raw internal source', () => {
const source = new Source({
name: 'internalModule.js',
sourceReference: 11,
presentationHint: 'deemphasize'
}, 'aDebugSessionId');
assert.equal(source.presentationHint, 'deemphasize');
assert.equal(source.name, 'internalModule.js');
assert.equal(source.inMemory, true);
assert.equal(source.reference, 11);
assert.equal(source.uri.toString(), 'debug:internalModule.js?session%3DaDebugSessionId%26ref%3D11');
});
test('get encoded debug data', () => {
const checkData = (uri: uri, expectedName, expectedPath, expectedSourceReference, expectedSessionId) => {
let { name, path, sourceReference, sessionId } = Source.getEncodedDebugData(uri);
assert.equal(name, expectedName);
assert.equal(path, expectedPath);
assert.equal(sourceReference, expectedSourceReference);
assert.equal(sessionId, expectedSessionId);
};
checkData(uri.file('a/b/c/d'), 'd', isWindows ? '\\a\\b\\c\\d' : '/a/b/c/d', undefined, undefined);
checkData(uri.from({ scheme: 'file', path: '/my/path/test.js', query: 'ref=1&session=2' }), 'test.js', isWindows ? '\\my\\path\\test.js' : '/my/path/test.js', undefined, undefined);
checkData(uri.from({ scheme: 'http', authority: 'www.msft.com', path: '/my/path' }), 'path', 'http://www.msft.com/my/path', undefined, undefined);
checkData(uri.from({ scheme: 'debug', authority: 'www.msft.com', path: '/my/path', query: 'ref=100' }), 'path', '/my/path', 100, undefined);
checkData(uri.from({ scheme: 'debug', path: 'a/b/c/d.js', query: 'session=100' }), 'd.js', 'a/b/c/d.js', undefined, 100);
checkData(uri.from({ scheme: 'debug', path: 'a/b/c/d/foo.txt', query: 'session=100&ref=10' }), 'foo.txt', 'a/b/c/d/foo.txt', 10, 100);
});
});

View File

@@ -0,0 +1,40 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { formatPII, getExactExpressionStartAndEnd } from 'vs/workbench/contrib/debug/common/debugUtils';
suite('Debug - Utils', () => {
test('formatPII', () => {
assert.strictEqual(formatPII('Foo Bar', false, {}), 'Foo Bar');
assert.strictEqual(formatPII('Foo {key} Bar', false, {}), 'Foo {key} Bar');
assert.strictEqual(formatPII('Foo {key} Bar', false, { 'key': 'yes' }), 'Foo yes Bar');
assert.strictEqual(formatPII('Foo {_0} Bar {_0}', true, { '_0': 'yes' }), 'Foo yes Bar yes');
assert.strictEqual(formatPII('Foo {0} Bar {1}{2}', false, { '0': 'yes' }), 'Foo yes Bar {1}{2}');
assert.strictEqual(formatPII('Foo {0} Bar {1}{2}', false, { '0': 'yes', '1': 'undefined' }), 'Foo yes Bar undefined{2}');
assert.strictEqual(formatPII('Foo {_key0} Bar {key1}{key2}', true, { '_key0': 'yes', 'key1': '5', 'key2': 'false' }), 'Foo yes Bar {key1}{key2}');
assert.strictEqual(formatPII('Foo {_key0} Bar {key1}{key2}', false, { '_key0': 'yes', 'key1': '5', 'key2': 'false' }), 'Foo yes Bar 5false');
});
test('getExactExpressionStartAndEnd', () => {
assert.deepEqual(getExactExpressionStartAndEnd('foo', 1, 2), { start: 1, end: 3 });
assert.deepEqual(getExactExpressionStartAndEnd('foo', 1, 3), { start: 1, end: 3 });
assert.deepEqual(getExactExpressionStartAndEnd('foo', 1, 4), { start: 1, end: 3 });
assert.deepEqual(getExactExpressionStartAndEnd('this.name = "John"', 1, 10), { start: 1, end: 9 });
assert.deepEqual(getExactExpressionStartAndEnd('this.name = "John"', 6, 10), { start: 1, end: 9 });
// Hovers over "address" should pick up this->address
assert.deepEqual(getExactExpressionStartAndEnd('this->address = "Main street"', 6, 10), { start: 1, end: 13 });
// Hovers over "name" should pick up a.b.c.d.name
assert.deepEqual(getExactExpressionStartAndEnd('var t = a.b.c.d.name', 16, 20), { start: 9, end: 20 });
assert.deepEqual(getExactExpressionStartAndEnd('MyClass::StaticProp', 10, 20), { start: 1, end: 19 });
assert.deepEqual(getExactExpressionStartAndEnd('largeNumber = myVar?.prop', 21, 25), { start: 15, end: 25 });
// For example in expression 'a.b.c.d', hover was under 'b', 'a.b' should be the exact range
assert.deepEqual(getExactExpressionStartAndEnd('var t = a.b.c.d.name', 11, 12), { start: 9, end: 11 });
assert.deepEqual(getExactExpressionStartAndEnd('var t = a.b;c.d.name', 16, 20), { start: 13, end: 20 });
assert.deepEqual(getExactExpressionStartAndEnd('var t = a.b.c-d.name', 16, 20), { start: 15, end: 20 });
});
});

View File

@@ -0,0 +1,45 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { ViewModel } from 'vs/workbench/contrib/debug/common/debugViewModel';
import { StackFrame, Expression, Thread } from 'vs/workbench/contrib/debug/common/debugModel';
import { MockSession } from 'vs/workbench/contrib/debug/test/common/mockDebug';
import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
suite('Debug - View Model', () => {
let model: ViewModel;
setup(() => {
model = new ViewModel(new MockContextKeyService());
});
test('focused stack frame', () => {
assert.equal(model.focusedStackFrame, null);
assert.equal(model.focusedThread, null);
const session = new MockSession();
const thread = new Thread(session, 'myThread', 1);
const frame = new StackFrame(thread, 1, undefined!, 'app.js', 'normal', { startColumn: 1, startLineNumber: 1, endColumn: 1, endLineNumber: 1 }, 0);
model.setFocus(frame, thread, session, false);
assert.equal(model.focusedStackFrame!.getId(), frame.getId());
assert.equal(model.focusedThread!.threadId, 1);
assert.equal(model.focusedSession!.getId(), session.getId());
});
test('selected expression', () => {
assert.equal(model.getSelectedExpression(), null);
const expression = new Expression('my expression');
model.setSelectedExpression(expression);
assert.equal(model.getSelectedExpression(), expression);
});
test('multi session view and changed workbench state', () => {
assert.equal(model.isMultiSessionView(), false);
model.setMultiSessionView(true);
assert.equal(model.isMultiSessionView(), true);
});
});

View File

@@ -0,0 +1,414 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { URI as uri } from 'vs/base/common/uri';
import { Event } from 'vs/base/common/event';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { Position } from 'vs/editor/common/core/position';
import { ILaunch, IDebugService, State, IDebugSession, IConfigurationManager, IStackFrame, IBreakpointData, IBreakpointUpdateData, IConfig, IDebugModel, IViewModel, IBreakpoint, LoadedSourceEvent, IThread, IRawModelUpdate, IFunctionBreakpoint, IExceptionBreakpoint, IDebugger, IExceptionInfo, AdapterEndEvent, IReplElement, IExpression, IReplElementSource } from 'vs/workbench/contrib/debug/common/debug';
import { Source } from 'vs/workbench/contrib/debug/common/debugSource';
import { CompletionItem } from 'vs/editor/common/modes';
import Severity from 'vs/base/common/severity';
export class MockDebugService implements IDebugService {
public _serviceBrand: any;
public get state(): State {
throw new Error('not implemented');
}
public get onWillNewSession(): Event<IDebugSession> {
throw new Error('not implemented');
}
public get onDidNewSession(): Event<IDebugSession> {
throw new Error('not implemented');
}
public get onDidEndSession(): Event<IDebugSession> {
throw new Error('not implemented');
}
public get onDidChangeState(): Event<State> {
throw new Error('not implemented');
}
public getConfigurationManager(): IConfigurationManager {
throw new Error('not implemented');
}
public focusStackFrame(focusedStackFrame: IStackFrame): void {
}
sendAllBreakpoints(session?: IDebugSession): Promise<any> {
throw new Error('not implemented');
}
public addBreakpoints(uri: uri, rawBreakpoints: IBreakpointData[]): Promise<IBreakpoint[]> {
throw new Error('not implemented');
}
public updateBreakpoints(uri: uri, data: { [id: string]: IBreakpointUpdateData }, sendOnResourceSaved: boolean): void { }
public enableOrDisableBreakpoints(enabled: boolean): Promise<void> {
throw new Error('not implemented');
}
public setBreakpointsActivated(): Promise<void> {
throw new Error('not implemented');
}
public removeBreakpoints(): Promise<any> {
throw new Error('not implemented');
}
public addFunctionBreakpoint(): void { }
public moveWatchExpression(id: string, position: number): void { }
public renameFunctionBreakpoint(id: string, newFunctionName: string): Promise<void> {
throw new Error('not implemented');
}
public removeFunctionBreakpoints(id?: string): Promise<void> {
throw new Error('not implemented');
}
public addReplExpression(name: string): Promise<void> {
throw new Error('not implemented');
}
public removeReplExpressions(): void { }
public addWatchExpression(name?: string): Promise<void> {
throw new Error('not implemented');
}
public renameWatchExpression(id: string, newName: string): Promise<void> {
throw new Error('not implemented');
}
public removeWatchExpressions(id?: string): void { }
public startDebugging(launch: ILaunch, configOrName?: IConfig | string, noDebug?: boolean): Promise<boolean> {
return Promise.resolve(true);
}
public restartSession(): Promise<any> {
throw new Error('not implemented');
}
public stopSession(): Promise<any> {
throw new Error('not implemented');
}
public getModel(): IDebugModel {
throw new Error('not implemented');
}
public getViewModel(): IViewModel {
throw new Error('not implemented');
}
public logToRepl(session: IDebugSession, value: string): void { }
public sourceIsNotAvailable(uri: uri): void { }
public tryToAutoFocusStackFrame(thread: IThread): Promise<any> {
throw new Error('not implemented');
}
}
export class MockSession implements IDebugSession {
getReplElements(): IReplElement[] {
return [];
}
removeReplExpressions(): void { }
get onDidChangeReplElements(): Event<void> {
throw new Error('not implemented');
}
addReplExpression(stackFrame: IStackFrame, name: string): Promise<void> {
return Promise.resolve(undefined);
}
appendToRepl(data: string | IExpression, severity: Severity, source?: IReplElementSource): void { }
logToRepl(sev: Severity, args: any[], frame?: { uri: uri; line: number; column: number; }) { }
configuration: IConfig = { type: 'mock', name: 'mock', request: 'launch' };
unresolvedConfiguration: IConfig = { type: 'mock', name: 'mock', request: 'launch' };
state = State.Stopped;
root: IWorkspaceFolder;
capabilities: DebugProtocol.Capabilities = {};
getId(): string {
return 'mock';
}
getLabel(): string {
return 'mockname';
}
getSourceForUri(modelUri: uri): Source {
throw new Error('not implemented');
}
getThread(threadId: number): IThread {
throw new Error('not implemented');
}
get onDidCustomEvent(): Event<DebugProtocol.Event> {
throw new Error('not implemented');
}
get onDidLoadedSource(): Event<LoadedSourceEvent> {
throw new Error('not implemented');
}
get onDidChangeState(): Event<void> {
throw new Error('not implemented');
}
get onDidEndAdapter(): Event<AdapterEndEvent> {
throw new Error('not implemented');
}
setConfiguration(configuration: { resolved: IConfig, unresolved: IConfig }) { }
getAllThreads(): IThread[] {
return [];
}
getSource(raw: DebugProtocol.Source): Source {
throw new Error('not implemented');
}
getLoadedSources(): Promise<Source[]> {
return Promise.resolve([]);
}
completions(frameId: number, text: string, position: Position, overwriteBefore: number): Promise<CompletionItem[]> {
return Promise.resolve([]);
}
clearThreads(removeThreads: boolean, reference?: number): void { }
rawUpdate(data: IRawModelUpdate): void { }
initialize(dbgr: IDebugger): Promise<void> {
throw new Error('Method not implemented.');
}
launchOrAttach(config: IConfig): Promise<void> {
throw new Error('Method not implemented.');
}
restart(): Promise<void> {
throw new Error('Method not implemented.');
}
sendBreakpoints(modelUri: uri, bpts: IBreakpoint[], sourceModified: boolean): Promise<void> {
throw new Error('Method not implemented.');
}
sendFunctionBreakpoints(fbps: IFunctionBreakpoint[]): Promise<void> {
throw new Error('Method not implemented.');
}
sendExceptionBreakpoints(exbpts: IExceptionBreakpoint[]): Promise<void> {
throw new Error('Method not implemented.');
}
customRequest(request: string, args: any): Promise<DebugProtocol.Response> {
throw new Error('Method not implemented.');
}
stackTrace(threadId: number, startFrame: number, levels: number): Promise<DebugProtocol.StackTraceResponse> {
throw new Error('Method not implemented.');
}
exceptionInfo(threadId: number): Promise<IExceptionInfo> {
throw new Error('Method not implemented.');
}
scopes(frameId: number): Promise<DebugProtocol.ScopesResponse> {
throw new Error('Method not implemented.');
}
variables(variablesReference: number, filter: 'indexed' | 'named', start: number, count: number): Promise<DebugProtocol.VariablesResponse> {
throw new Error('Method not implemented.');
}
evaluate(expression: string, frameId: number, context?: string): Promise<DebugProtocol.EvaluateResponse> {
throw new Error('Method not implemented.');
}
restartFrame(frameId: number, threadId: number): Promise<void> {
throw new Error('Method not implemented.');
}
next(threadId: number): Promise<void> {
throw new Error('Method not implemented.');
}
stepIn(threadId: number): Promise<void> {
throw new Error('Method not implemented.');
}
stepOut(threadId: number): Promise<void> {
throw new Error('Method not implemented.');
}
stepBack(threadId: number): Promise<void> {
throw new Error('Method not implemented.');
}
continue(threadId: number): Promise<void> {
throw new Error('Method not implemented.');
}
reverseContinue(threadId: number): Promise<void> {
throw new Error('Method not implemented.');
}
pause(threadId: number): Promise<void> {
throw new Error('Method not implemented.');
}
terminateThreads(threadIds: number[]): Promise<void> {
throw new Error('Method not implemented.');
}
setVariable(variablesReference: number, name: string, value: string): Promise<DebugProtocol.SetVariableResponse> {
throw new Error('Method not implemented.');
}
loadSource(resource: uri): Promise<DebugProtocol.SourceResponse> {
throw new Error('Method not implemented.');
}
terminate(restart = false): Promise<void> {
throw new Error('Method not implemented.');
}
disconnect(restart = false): Promise<void> {
throw new Error('Method not implemented.');
}
shutdown(): void { }
}
export class MockRawSession {
capabilities: DebugProtocol.Capabilities;
disconnected: boolean;
sessionLengthInSeconds: number;
public readyForBreakpoints = true;
public emittedStopped = true;
public getLengthInSeconds(): number {
return 100;
}
public stackTrace(args: DebugProtocol.StackTraceArguments): Promise<DebugProtocol.StackTraceResponse> {
return Promise.resolve({
seq: 1,
type: 'response',
request_seq: 1,
success: true,
command: 'stackTrace',
body: {
stackFrames: [{
id: 1,
name: 'mock',
line: 5,
column: 6
}]
}
});
}
public exceptionInfo(args: DebugProtocol.ExceptionInfoArguments): Promise<DebugProtocol.ExceptionInfoResponse> {
throw new Error('not implemented');
}
public launchOrAttach(args: IConfig): Promise<DebugProtocol.Response> {
throw new Error('not implemented');
}
public scopes(args: DebugProtocol.ScopesArguments): Promise<DebugProtocol.ScopesResponse> {
throw new Error('not implemented');
}
public variables(args: DebugProtocol.VariablesArguments): Promise<DebugProtocol.VariablesResponse> {
throw new Error('not implemented');
}
evaluate(args: DebugProtocol.EvaluateArguments): Promise<DebugProtocol.EvaluateResponse> {
return Promise.resolve(null!);
}
public custom(request: string, args: any): Promise<DebugProtocol.Response> {
throw new Error('not implemented');
}
public terminate(restart = false): Promise<DebugProtocol.TerminateResponse> {
throw new Error('not implemented');
}
public disconnect(restart?: boolean): Promise<any> {
throw new Error('not implemented');
}
public threads(): Promise<DebugProtocol.ThreadsResponse> {
throw new Error('not implemented');
}
public stepIn(args: DebugProtocol.StepInArguments): Promise<DebugProtocol.StepInResponse> {
throw new Error('not implemented');
}
public stepOut(args: DebugProtocol.StepOutArguments): Promise<DebugProtocol.StepOutResponse> {
throw new Error('not implemented');
}
public stepBack(args: DebugProtocol.StepBackArguments): Promise<DebugProtocol.StepBackResponse> {
throw new Error('not implemented');
}
public continue(args: DebugProtocol.ContinueArguments): Promise<DebugProtocol.ContinueResponse> {
throw new Error('not implemented');
}
public reverseContinue(args: DebugProtocol.ReverseContinueArguments): Promise<DebugProtocol.ReverseContinueResponse> {
throw new Error('not implemented');
}
public pause(args: DebugProtocol.PauseArguments): Promise<DebugProtocol.PauseResponse> {
throw new Error('not implemented');
}
public terminateThreads(args: DebugProtocol.TerminateThreadsArguments): Promise<DebugProtocol.TerminateThreadsResponse> {
throw new Error('not implemented');
}
public setVariable(args: DebugProtocol.SetVariableArguments): Promise<DebugProtocol.SetVariableResponse> {
throw new Error('not implemented');
}
public restartFrame(args: DebugProtocol.RestartFrameArguments): Promise<DebugProtocol.RestartFrameResponse> {
throw new Error('not implemented');
}
public completions(args: DebugProtocol.CompletionsArguments): Promise<DebugProtocol.CompletionsResponse> {
throw new Error('not implemented');
}
public next(args: DebugProtocol.NextArguments): Promise<DebugProtocol.NextResponse> {
throw new Error('not implemented');
}
public source(args: DebugProtocol.SourceArguments): Promise<DebugProtocol.SourceResponse> {
throw new Error('not implemented');
}
public loadedSources(args: DebugProtocol.LoadedSourcesArguments): Promise<DebugProtocol.LoadedSourcesResponse> {
throw new Error('not implemented');
}
public setBreakpoints(args: DebugProtocol.SetBreakpointsArguments): Promise<DebugProtocol.SetBreakpointsResponse> {
throw new Error('not implemented');
}
public setFunctionBreakpoints(args: DebugProtocol.SetFunctionBreakpointsArguments): Promise<DebugProtocol.SetFunctionBreakpointsResponse> {
throw new Error('not implemented');
}
public setExceptionBreakpoints(args: DebugProtocol.SetExceptionBreakpointsArguments): Promise<DebugProtocol.SetExceptionBreakpointsResponse> {
throw new Error('not implemented');
}
public readonly onDidStop: Event<DebugProtocol.StoppedEvent> = null!;
}

View File

@@ -0,0 +1,429 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { URI as uri } from 'vs/base/common/uri';
import severity from 'vs/base/common/severity';
import { SimpleReplElement, DebugModel, Expression, RawObjectReplElement, StackFrame, Thread } from 'vs/workbench/contrib/debug/common/debugModel';
import * as sinon from 'sinon';
import { MockRawSession } from 'vs/workbench/contrib/debug/test/common/mockDebug';
import { Source } from 'vs/workbench/contrib/debug/common/debugSource';
import { DebugSession } from 'vs/workbench/contrib/debug/electron-browser/debugSession';
import { ReplModel } from 'vs/workbench/contrib/debug/common/replModel';
suite('Debug - Model', () => {
let model: DebugModel;
let rawSession: MockRawSession;
setup(() => {
model = new DebugModel([], true, [], [], [], <any>{ isDirty: (e: any) => false });
rawSession = new MockRawSession();
});
// Breakpoints
test('breakpoints simple', () => {
const modelUri = uri.file('/myfolder/myfile.js');
model.addBreakpoints(modelUri, [{ lineNumber: 5, enabled: true }, { lineNumber: 10, enabled: false }]);
assert.equal(model.areBreakpointsActivated(), true);
assert.equal(model.getBreakpoints().length, 2);
model.removeBreakpoints(model.getBreakpoints());
assert.equal(model.getBreakpoints().length, 0);
});
test('breakpoints toggling', () => {
const modelUri = uri.file('/myfolder/myfile.js');
model.addBreakpoints(modelUri, [{ lineNumber: 5, enabled: true }, { lineNumber: 10, enabled: false }]);
model.addBreakpoints(modelUri, [{ lineNumber: 12, enabled: true, condition: 'fake condition' }]);
assert.equal(model.getBreakpoints().length, 3);
const bp = model.getBreakpoints().pop();
if (bp) {
model.removeBreakpoints([bp]);
}
assert.equal(model.getBreakpoints().length, 2);
model.setBreakpointsActivated(false);
assert.equal(model.areBreakpointsActivated(), false);
model.setBreakpointsActivated(true);
assert.equal(model.areBreakpointsActivated(), true);
});
test('breakpoints two files', () => {
const modelUri1 = uri.file('/myfolder/my file first.js');
const modelUri2 = uri.file('/secondfolder/second/second file.js');
model.addBreakpoints(modelUri1, [{ lineNumber: 5, enabled: true }, { lineNumber: 10, enabled: false }]);
model.addBreakpoints(modelUri2, [{ lineNumber: 1, enabled: true }, { lineNumber: 2, enabled: true }, { lineNumber: 3, enabled: false }]);
assert.equal(model.getBreakpoints().length, 5);
const bp = model.getBreakpoints()[0];
const update: any = {};
update[bp.getId()] = { lineNumber: 100 };
model.updateBreakpoints(update);
assert.equal(bp.lineNumber, 100);
model.enableOrDisableAllBreakpoints(false);
model.getBreakpoints().forEach(bp => {
assert.equal(bp.enabled, false);
});
model.setEnablement(bp, true);
assert.equal(bp.enabled, true);
model.removeBreakpoints(model.getBreakpoints({ uri: modelUri1 }));
assert.equal(model.getBreakpoints().length, 3);
});
test('breakpoints conditions', () => {
const modelUri1 = uri.file('/myfolder/my file first.js');
model.addBreakpoints(modelUri1, [{ lineNumber: 5, condition: 'i < 5', hitCondition: '17' }, { lineNumber: 10, condition: 'j < 3' }]);
const breakpoints = model.getBreakpoints();
assert.equal(breakpoints[0].condition, 'i < 5');
assert.equal(breakpoints[0].hitCondition, '17');
assert.equal(breakpoints[1].condition, 'j < 3');
assert.equal(!!breakpoints[1].hitCondition, false);
assert.equal(model.getBreakpoints().length, 2);
model.removeBreakpoints(model.getBreakpoints());
assert.equal(model.getBreakpoints().length, 0);
});
test('function breakpoints', () => {
model.addFunctionBreakpoint('foo', '1');
model.addFunctionBreakpoint('bar', '2');
model.renameFunctionBreakpoint('1', 'fooUpdated');
model.renameFunctionBreakpoint('2', 'barUpdated');
const functionBps = model.getFunctionBreakpoints();
assert.equal(functionBps[0].name, 'fooUpdated');
assert.equal(functionBps[1].name, 'barUpdated');
model.removeFunctionBreakpoints();
assert.equal(model.getFunctionBreakpoints().length, 0);
});
// Threads
test('threads simple', () => {
const threadId = 1;
const threadName = 'firstThread';
const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!);
model.addSession(session);
assert.equal(model.getSessions(true).length, 1);
model.rawUpdate({
sessionId: session.getId(),
threads: [{
id: threadId,
name: threadName
}]
});
assert.equal(session.getThread(threadId)!.name, threadName);
model.clearThreads(session.getId(), true);
assert.equal(session.getThread(threadId), undefined);
assert.equal(model.getSessions(true).length, 1);
});
test('threads multiple wtih allThreadsStopped', () => {
const threadId1 = 1;
const threadName1 = 'firstThread';
const threadId2 = 2;
const threadName2 = 'secondThread';
const stoppedReason = 'breakpoint';
// Add the threads
const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!);
model.addSession(session);
session['raw'] = <any>rawSession;
model.rawUpdate({
sessionId: session.getId(),
threads: [{
id: threadId1,
name: threadName1
}]
});
model.rawUpdate({
sessionId: session.getId(),
threads: [{
id: threadId2,
name: threadName2
}]
});
// Stopped event with all threads stopped
model.rawUpdate({
sessionId: session.getId(),
threads: [{
id: threadId1,
name: threadName1
}],
stoppedDetails: {
reason: stoppedReason,
threadId: 1,
allThreadsStopped: true
},
});
const thread1 = session.getThread(threadId1)!;
const thread2 = session.getThread(threadId2)!;
// at the beginning, callstacks are obtainable but not available
assert.equal(session.getAllThreads().length, 2);
assert.equal(thread1.name, threadName1);
assert.equal(thread1.stopped, true);
assert.equal(thread1.getCallStack().length, 0);
assert.equal(thread1.stoppedDetails!.reason, stoppedReason);
assert.equal(thread2.name, threadName2);
assert.equal(thread2.stopped, true);
assert.equal(thread2.getCallStack().length, 0);
assert.equal(thread2.stoppedDetails!.reason, undefined);
// after calling getCallStack, the callstack becomes available
// and results in a request for the callstack in the debug adapter
thread1.fetchCallStack().then(() => {
assert.notEqual(thread1.getCallStack().length, 0);
});
thread2.fetchCallStack().then(() => {
assert.notEqual(thread2.getCallStack().length, 0);
});
// calling multiple times getCallStack doesn't result in multiple calls
// to the debug adapter
thread1.fetchCallStack().then(() => {
return thread2.fetchCallStack();
});
// clearing the callstack results in the callstack not being available
thread1.clearCallStack();
assert.equal(thread1.stopped, true);
assert.equal(thread1.getCallStack().length, 0);
thread2.clearCallStack();
assert.equal(thread2.stopped, true);
assert.equal(thread2.getCallStack().length, 0);
model.clearThreads(session.getId(), true);
assert.equal(session.getThread(threadId1), undefined);
assert.equal(session.getThread(threadId2), undefined);
assert.equal(session.getAllThreads().length, 0);
});
test('threads mutltiple without allThreadsStopped', () => {
const sessionStub = sinon.spy(rawSession, 'stackTrace');
const stoppedThreadId = 1;
const stoppedThreadName = 'stoppedThread';
const runningThreadId = 2;
const runningThreadName = 'runningThread';
const stoppedReason = 'breakpoint';
const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!);
model.addSession(session);
session['raw'] = <any>rawSession;
// Add the threads
model.rawUpdate({
sessionId: session.getId(),
threads: [{
id: stoppedThreadId,
name: stoppedThreadName
}]
});
model.rawUpdate({
sessionId: session.getId(),
threads: [{
id: runningThreadId,
name: runningThreadName
}]
});
// Stopped event with only one thread stopped
model.rawUpdate({
sessionId: session.getId(),
threads: [{
id: 1,
name: stoppedThreadName
}],
stoppedDetails: {
reason: stoppedReason,
threadId: 1,
allThreadsStopped: false
}
});
const stoppedThread = session.getThread(stoppedThreadId)!;
const runningThread = session.getThread(runningThreadId)!;
// the callstack for the stopped thread is obtainable but not available
// the callstack for the running thread is not obtainable nor available
assert.equal(stoppedThread.name, stoppedThreadName);
assert.equal(stoppedThread.stopped, true);
assert.equal(session.getAllThreads().length, 2);
assert.equal(stoppedThread.getCallStack().length, 0);
assert.equal(stoppedThread.stoppedDetails!.reason, stoppedReason);
assert.equal(runningThread.name, runningThreadName);
assert.equal(runningThread.stopped, false);
assert.equal(runningThread.getCallStack().length, 0);
assert.equal(runningThread.stoppedDetails, undefined);
// after calling getCallStack, the callstack becomes available
// and results in a request for the callstack in the debug adapter
stoppedThread.fetchCallStack().then(() => {
assert.notEqual(stoppedThread.getCallStack().length, 0);
assert.equal(runningThread.getCallStack().length, 0);
assert.equal(sessionStub.callCount, 1);
});
// calling getCallStack on the running thread returns empty array
// and does not return in a request for the callstack in the debug
// adapter
runningThread.fetchCallStack().then(() => {
assert.equal(runningThread.getCallStack().length, 0);
assert.equal(sessionStub.callCount, 1);
});
// clearing the callstack results in the callstack not being available
stoppedThread.clearCallStack();
assert.equal(stoppedThread.stopped, true);
assert.equal(stoppedThread.getCallStack().length, 0);
model.clearThreads(session.getId(), true);
assert.equal(session.getThread(stoppedThreadId), undefined);
assert.equal(session.getThread(runningThreadId), undefined);
assert.equal(session.getAllThreads().length, 0);
});
// Expressions
function assertWatchExpressions(watchExpressions: Expression[], expectedName: string) {
assert.equal(watchExpressions.length, 2);
watchExpressions.forEach(we => {
assert.equal(we.available, false);
assert.equal(we.reference, 0);
assert.equal(we.name, expectedName);
});
}
test('watch expressions', () => {
assert.equal(model.getWatchExpressions().length, 0);
model.addWatchExpression('console');
model.addWatchExpression('console');
let watchExpressions = model.getWatchExpressions();
assertWatchExpressions(watchExpressions, 'console');
model.renameWatchExpression(watchExpressions[0].getId(), 'new_name');
model.renameWatchExpression(watchExpressions[1].getId(), 'new_name');
assertWatchExpressions(model.getWatchExpressions(), 'new_name');
assertWatchExpressions(model.getWatchExpressions(), 'new_name');
model.addWatchExpression('mockExpression');
model.moveWatchExpression(model.getWatchExpressions()[2].getId(), 1);
watchExpressions = model.getWatchExpressions();
assert.equal(watchExpressions[0].name, 'new_name');
assert.equal(watchExpressions[1].name, 'mockExpression');
assert.equal(watchExpressions[2].name, 'new_name');
model.removeWatchExpressions();
assert.equal(model.getWatchExpressions().length, 0);
});
test('repl expressions', () => {
const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!);
assert.equal(session.getReplElements().length, 0);
model.addSession(session);
session['raw'] = <any>rawSession;
const thread = new Thread(session, 'mockthread', 1);
const stackFrame = new StackFrame(thread, 1, <any>undefined, 'app.js', 'normal', { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 10 }, 1);
const replModel = new ReplModel(session);
replModel.addReplExpression(stackFrame, 'myVariable').then();
replModel.addReplExpression(stackFrame, 'myVariable').then();
replModel.addReplExpression(stackFrame, 'myVariable').then();
assert.equal(replModel.getReplElements().length, 3);
replModel.getReplElements().forEach(re => {
assert.equal((<Expression>re).available, false);
assert.equal((<Expression>re).name, 'myVariable');
assert.equal((<Expression>re).reference, 0);
});
replModel.removeReplExpressions();
assert.equal(replModel.getReplElements().length, 0);
});
test('stack frame get specific source name', () => {
const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!);
model.addSession(session);
let firstStackFrame: StackFrame;
let secondStackFrame: StackFrame;
const thread = new class extends Thread {
public getCallStack(): StackFrame[] {
return [firstStackFrame, secondStackFrame];
}
}(session, 'mockthread', 1);
const firstSource = new Source({
name: 'internalModule.js',
path: 'a/b/c/d/internalModule.js',
sourceReference: 10,
}, 'aDebugSessionId');
const secondSource = new Source({
name: 'internalModule.js',
path: 'z/x/c/d/internalModule.js',
sourceReference: 11,
}, 'aDebugSessionId');
firstStackFrame = new StackFrame(thread, 1, firstSource, 'app.js', 'normal', { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 10 }, 1);
secondStackFrame = new StackFrame(thread, 1, secondSource, 'app.js', 'normal', { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 10 }, 1);
assert.equal(firstStackFrame.getSpecificSourceName(), '.../b/c/d/internalModule.js');
assert.equal(secondStackFrame.getSpecificSourceName(), '.../x/c/d/internalModule.js');
});
// Repl output
test('repl output', () => {
const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!);
const repl = new ReplModel(session);
repl.appendToRepl('first line\n', severity.Error);
repl.appendToRepl('second line', severity.Error);
repl.appendToRepl('third line', severity.Warning);
repl.appendToRepl('fourth line', severity.Error);
let elements = <SimpleReplElement[]>repl.getReplElements();
assert.equal(elements.length, 4);
assert.equal(elements[0].value, 'first line');
assert.equal(elements[0].severity, severity.Error);
assert.equal(elements[1].value, 'second line');
assert.equal(elements[1].severity, severity.Error);
assert.equal(elements[2].value, 'third line');
assert.equal(elements[2].severity, severity.Warning);
assert.equal(elements[3].value, 'fourth line');
assert.equal(elements[3].severity, severity.Error);
repl.appendToRepl('1', severity.Warning);
elements = <SimpleReplElement[]>repl.getReplElements();
assert.equal(elements.length, 5);
assert.equal(elements[4].value, '1');
assert.equal(elements[4].severity, severity.Warning);
const keyValueObject = { 'key1': 2, 'key2': 'value' };
repl.appendToRepl(new RawObjectReplElement('fakeid', 'fake', keyValueObject), severity.Info);
const element = <RawObjectReplElement>repl.getReplElements()[5];
assert.equal(element.value, 'Object');
assert.deepEqual(element.valueObj, keyValueObject);
repl.removeReplExpressions();
assert.equal(repl.getReplElements().length, 0);
});
});

View File

@@ -0,0 +1,192 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { join, normalize } from 'vs/base/common/path';
import * as platform from 'vs/base/common/platform';
import { IDebugAdapterExecutable, IConfigurationManager, IConfig, IDebugSession } from 'vs/workbench/contrib/debug/common/debug';
import { Debugger } from 'vs/workbench/contrib/debug/node/debugger';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
import { URI } from 'vs/base/common/uri';
import { ExecutableDebugAdapter } from 'vs/workbench/contrib/debug/node/debugAdapter';
import { TestTextResourcePropertiesService } from 'vs/workbench/test/workbenchTestServices';
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
suite('Debug - Debugger', () => {
let _debugger: Debugger;
const extensionFolderPath = '/a/b/c/';
const debuggerContribution = {
type: 'mock',
label: 'Mock Debug',
enableBreakpointsFor: { 'languageIds': ['markdown'] },
program: './out/mock/mockDebug.js',
args: ['arg1', 'arg2'],
configurationAttributes: {
launch: {
required: ['program'],
properties: {
program: {
'type': 'string',
'description': 'Workspace relative path to a text file.',
'default': 'readme.md'
}
}
}
},
variables: null!,
initialConfigurations: [
{
name: 'Mock-Debug',
type: 'mock',
request: 'launch',
program: 'readme.md'
}
]
};
const extensionDescriptor0 = <IExtensionDescription>{
id: 'adapter',
identifier: new ExtensionIdentifier('adapter'),
name: 'myAdapter',
version: '1.0.0',
publisher: 'vscode',
extensionLocation: URI.file(extensionFolderPath),
isBuiltin: false,
isUnderDevelopment: false,
engines: null!,
contributes: {
'debuggers': [
debuggerContribution
]
}
};
const extensionDescriptor1 = {
id: 'extension1',
identifier: new ExtensionIdentifier('extension1'),
name: 'extension1',
version: '1.0.0',
publisher: 'vscode',
extensionLocation: URI.file('/e1/b/c/'),
isBuiltin: false,
isUnderDevelopment: false,
engines: null!,
contributes: {
'debuggers': [
{
type: 'mock',
runtime: 'runtime',
runtimeArgs: ['rarg'],
program: 'mockprogram',
args: ['parg']
}
]
}
};
const extensionDescriptor2 = {
id: 'extension2',
identifier: new ExtensionIdentifier('extension2'),
name: 'extension2',
version: '1.0.0',
publisher: 'vscode',
extensionLocation: URI.file('/e2/b/c/'),
isBuiltin: false,
isUnderDevelopment: false,
engines: null!,
contributes: {
'debuggers': [
{
type: 'mock',
win: {
runtime: 'winRuntime',
program: 'winProgram'
},
linux: {
runtime: 'linuxRuntime',
program: 'linuxProgram'
},
osx: {
runtime: 'osxRuntime',
program: 'osxProgram'
}
}
]
}
};
const configurationManager = <IConfigurationManager>{
getDebugAdapterDescriptor(session: IDebugSession, config: IConfig): Promise<IDebugAdapterExecutable | undefined> {
return Promise.resolve(undefined);
}
};
const configurationService = new TestConfigurationService();
const testResourcePropertiesService = new TestTextResourcePropertiesService(configurationService);
setup(() => {
_debugger = new Debugger(configurationManager, debuggerContribution, extensionDescriptor0, configurationService, testResourcePropertiesService, undefined!, undefined!, undefined!);
});
teardown(() => {
_debugger = null!;
});
test('attributes', () => {
assert.equal(_debugger.type, debuggerContribution.type);
assert.equal(_debugger.label, debuggerContribution.label);
const ae = ExecutableDebugAdapter.platformAdapterExecutable([extensionDescriptor0], 'mock');
assert.equal(ae!.command, join(extensionFolderPath, debuggerContribution.program));
assert.deepEqual(ae!.args, debuggerContribution.args);
});
test('schema attributes', () => {
const schemaAttribute = _debugger.getSchemaAttributes()![0];
assert.notDeepEqual(schemaAttribute, debuggerContribution.configurationAttributes);
Object.keys(debuggerContribution.configurationAttributes.launch).forEach(key => {
assert.deepEqual(schemaAttribute[key], debuggerContribution.configurationAttributes.launch[key]);
});
assert.equal(schemaAttribute['additionalProperties'], false);
assert.equal(!!schemaAttribute['properties']!['request'], true);
assert.equal(!!schemaAttribute['properties']!['name'], true);
assert.equal(!!schemaAttribute['properties']!['type'], true);
assert.equal(!!schemaAttribute['properties']!['preLaunchTask'], true);
});
test('merge platform specific attributes', () => {
const ae = ExecutableDebugAdapter.platformAdapterExecutable([extensionDescriptor1, extensionDescriptor2], 'mock')!;
assert.equal(ae.command, platform.isLinux ? 'linuxRuntime' : (platform.isMacintosh ? 'osxRuntime' : 'winRuntime'));
const xprogram = platform.isLinux ? 'linuxProgram' : (platform.isMacintosh ? 'osxProgram' : 'winProgram');
assert.deepEqual(ae.args, ['rarg', normalize('/e2/b/c/') + xprogram, 'parg']);
});
test('initial config file content', () => {
const expected = ['{',
' // Use IntelliSense to learn about possible attributes.',
' // Hover to view descriptions of existing attributes.',
' // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387',
' "version": "0.2.0",',
' "configurations": [',
' {',
' "name": "Mock-Debug",',
' "type": "mock",',
' "request": "launch",',
' "program": "readme.md"',
' }',
' ]',
'}'].join(testResourcePropertiesService.getEOL(URI.file('somefile')));
return _debugger.getInitialConfigurationContent().then(content => {
assert.equal(content, expected);
}, err => assert.fail(err));
});
});