mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-10 02:02:35 -05:00
Merge vscode 1.67 (#20883)
* Fix initial build breaks from 1.67 merge (#2514) * Update yarn lock files * Update build scripts * Fix tsconfig * Build breaks * WIP * Update yarn lock files * Misc breaks * Updates to package.json * Breaks * Update yarn * Fix breaks * Breaks * Build breaks * Breaks * Breaks * Breaks * Breaks * Breaks * Missing file * Breaks * Breaks * Breaks * Breaks * Breaks * Fix several runtime breaks (#2515) * Missing files * Runtime breaks * Fix proxy ordering issue * Remove commented code * Fix breaks with opening query editor * Fix post merge break * Updates related to setup build and other breaks (#2516) * Fix bundle build issues * Update distro * Fix distro merge and update build JS files * Disable pipeline steps * Remove stats call * Update license name * Make new RPM dependencies a warning * Fix extension manager version checks * Update JS file * Fix a few runtime breaks * Fixes * Fix runtime issues * Fix build breaks * Update notebook tests (part 1) * Fix broken tests * Linting errors * Fix hygiene * Disable lint rules * Bump distro * Turn off smoke tests * Disable integration tests * Remove failing "activate" test * Remove failed test assertion * Disable other broken test * Disable query history tests * Disable extension unit tests * Disable failing tasks
This commit is contained in:
@@ -1,21 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 } from 'vs/base/common/uri';
|
||||
import { originalFSPath } from 'vs/base/common/resources';
|
||||
import { isWindows } from 'vs/base/common/platform';
|
||||
|
||||
suite('ExtHost API', function () {
|
||||
test('issue #51387: originalFSPath', function () {
|
||||
if (isWindows) {
|
||||
assert.strictEqual(originalFSPath(URI.file('C:\\test')).charAt(0), 'C');
|
||||
assert.strictEqual(originalFSPath(URI.file('c:\\test')).charAt(0), 'c');
|
||||
|
||||
assert.strictEqual(originalFSPath(URI.revive(JSON.parse(JSON.stringify(URI.file('C:\\test'))))).charAt(0), 'C');
|
||||
assert.strictEqual(originalFSPath(URI.revive(JSON.parse(JSON.stringify(URI.file('c:\\test'))))).charAt(0), 'c');
|
||||
}
|
||||
});
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,358 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { TestDialogService } from 'vs/platform/dialogs/test/common/testDialogService';
|
||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
|
||||
import { IQuickInputHideEvent, IQuickInputService, IQuickPickDidAcceptEvent } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
|
||||
import { MainThreadAuthentication } from 'vs/workbench/api/browser/mainThreadAuthentication';
|
||||
import { ExtHostContext, MainContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostAuthentication } from 'vs/workbench/api/common/extHostAuthentication';
|
||||
import { IActivityService } from 'vs/workbench/services/activity/common/activity';
|
||||
import { AuthenticationService, IAuthenticationService } from 'vs/workbench/services/authentication/browser/authenticationService';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
import { TestRemoteAgentService } from 'vs/workbench/services/remote/test/common/testServices';
|
||||
import { TestRPCProtocol } from 'vs/workbench/test/browser/api/testRPCProtocol';
|
||||
import { TestQuickInputService } from 'vs/workbench/test/browser/workbenchTestServices';
|
||||
import { TestActivityService, TestExtensionService, TestStorageService } from 'vs/workbench/test/common/workbenchTestServices';
|
||||
import type { AuthenticationProvider, AuthenticationSession } from 'vscode';
|
||||
|
||||
class AuthQuickPick {
|
||||
private listener: ((e: IQuickPickDidAcceptEvent) => any) | undefined;
|
||||
public items = [];
|
||||
public get selectedItems(): string[] {
|
||||
return this.items;
|
||||
}
|
||||
|
||||
onDidAccept(listener: (e: IQuickPickDidAcceptEvent) => any) {
|
||||
this.listener = listener;
|
||||
}
|
||||
onDidHide(listener: (e: IQuickInputHideEvent) => any) {
|
||||
|
||||
}
|
||||
dispose() {
|
||||
|
||||
}
|
||||
show() {
|
||||
this.listener!({
|
||||
inBackground: false
|
||||
});
|
||||
}
|
||||
}
|
||||
class AuthTestQuickInputService extends TestQuickInputService {
|
||||
override createQuickPick() {
|
||||
return <any>new AuthQuickPick();
|
||||
}
|
||||
}
|
||||
|
||||
class TestAuthProvider implements AuthenticationProvider {
|
||||
private sessions = new Map<string, AuthenticationSession>();
|
||||
onDidChangeSessions = () => { return { dispose() { } }; };
|
||||
async getSessions(scopes?: readonly string[]): Promise<AuthenticationSession[]> {
|
||||
if (!scopes) {
|
||||
return [...this.sessions.values()];
|
||||
}
|
||||
|
||||
const sessions = this.sessions.get(scopes.join(' '));
|
||||
return sessions ? [sessions] : [];
|
||||
}
|
||||
async createSession(scopes: readonly string[]): Promise<AuthenticationSession> {
|
||||
const scopesStr = scopes.join(' ');
|
||||
const session = {
|
||||
scopes,
|
||||
id: 'test',
|
||||
account: {
|
||||
label: scopesStr,
|
||||
id: scopesStr,
|
||||
},
|
||||
accessToken: Math.random() + '',
|
||||
};
|
||||
this.sessions.set(scopesStr, session);
|
||||
return session;
|
||||
}
|
||||
async removeSession(sessionId: string): Promise<void> {
|
||||
this.sessions.delete(sessionId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
suite('ExtHostAuthentication', () => {
|
||||
let disposables: DisposableStore;
|
||||
let nullExtensionDescription: IExtensionDescription = {
|
||||
identifier: new ExtensionIdentifier('nullExtensionDescription'),
|
||||
name: 'Null Extension Description',
|
||||
publisher: 'vscode',
|
||||
enableProposedApi: true,
|
||||
engines: undefined!,
|
||||
extensionLocation: undefined!,
|
||||
isBuiltin: false,
|
||||
isUserBuiltin: false,
|
||||
isUnderDevelopment: false,
|
||||
version: undefined!
|
||||
};
|
||||
|
||||
let extHostAuthentication: ExtHostAuthentication;
|
||||
let instantiationService: TestInstantiationService;
|
||||
|
||||
suiteSetup(async () => {
|
||||
instantiationService = new TestInstantiationService();
|
||||
instantiationService.stub(IDialogService, new TestDialogService());
|
||||
instantiationService.stub(IStorageService, new TestStorageService());
|
||||
instantiationService.stub(IQuickInputService, new AuthTestQuickInputService());
|
||||
instantiationService.stub(IExtensionService, new TestExtensionService());
|
||||
|
||||
instantiationService.stub(IActivityService, new TestActivityService());
|
||||
instantiationService.stub(IRemoteAgentService, new TestRemoteAgentService());
|
||||
instantiationService.stub(INotificationService, new TestNotificationService());
|
||||
instantiationService.stub(ITelemetryService, NullTelemetryService);
|
||||
const rpcProtocol = new TestRPCProtocol();
|
||||
|
||||
instantiationService.stub(IAuthenticationService, instantiationService.createInstance(AuthenticationService));
|
||||
rpcProtocol.set(MainContext.MainThreadAuthentication, instantiationService.createInstance(MainThreadAuthentication, rpcProtocol));
|
||||
extHostAuthentication = new ExtHostAuthentication(rpcProtocol);
|
||||
rpcProtocol.set(ExtHostContext.ExtHostAuthentication, extHostAuthentication);
|
||||
});
|
||||
|
||||
setup(async () => {
|
||||
disposables = new DisposableStore();
|
||||
disposables.add(extHostAuthentication.registerAuthenticationProvider('test', 'test provider', new TestAuthProvider()));
|
||||
disposables.add(extHostAuthentication.registerAuthenticationProvider(
|
||||
'test-multiple',
|
||||
'test multiple provider',
|
||||
new TestAuthProvider(),
|
||||
{ supportsMultipleAccounts: true }));
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
disposables.dispose();
|
||||
});
|
||||
|
||||
test('createIfNone - true', async () => {
|
||||
const session = await extHostAuthentication.getSession(
|
||||
nullExtensionDescription,
|
||||
'test',
|
||||
['foo'],
|
||||
{
|
||||
createIfNone: true
|
||||
});
|
||||
assert.strictEqual(session?.id, 'test');
|
||||
assert.strictEqual(session?.scopes[0], 'foo');
|
||||
});
|
||||
|
||||
test('createIfNone - false', async () => {
|
||||
const nosession = await extHostAuthentication.getSession(
|
||||
nullExtensionDescription,
|
||||
'test',
|
||||
['foo'],
|
||||
{});
|
||||
assert.strictEqual(nosession, undefined);
|
||||
|
||||
// Now create the session
|
||||
const session = await extHostAuthentication.getSession(
|
||||
nullExtensionDescription,
|
||||
'test',
|
||||
['foo'],
|
||||
{
|
||||
createIfNone: true
|
||||
});
|
||||
|
||||
assert.strictEqual(session?.id, 'test');
|
||||
assert.strictEqual(session?.scopes[0], 'foo');
|
||||
|
||||
const session2 = await extHostAuthentication.getSession(
|
||||
nullExtensionDescription,
|
||||
'test',
|
||||
['foo'],
|
||||
{});
|
||||
|
||||
assert.strictEqual(session.id, session2?.id);
|
||||
assert.strictEqual(session.scopes[0], session2?.scopes[0]);
|
||||
assert.strictEqual(session.accessToken, session2?.accessToken);
|
||||
});
|
||||
|
||||
// should behave the same as createIfNone: false
|
||||
test('silent - true', async () => {
|
||||
const nosession = await extHostAuthentication.getSession(
|
||||
nullExtensionDescription,
|
||||
'test',
|
||||
['foo'],
|
||||
{
|
||||
silent: true
|
||||
});
|
||||
assert.strictEqual(nosession, undefined);
|
||||
|
||||
// Now create the session
|
||||
const session = await extHostAuthentication.getSession(
|
||||
nullExtensionDescription,
|
||||
'test',
|
||||
['foo'],
|
||||
{
|
||||
createIfNone: true
|
||||
});
|
||||
|
||||
assert.strictEqual(session?.id, 'test');
|
||||
assert.strictEqual(session?.scopes[0], 'foo');
|
||||
|
||||
const session2 = await extHostAuthentication.getSession(
|
||||
nullExtensionDescription,
|
||||
'test',
|
||||
['foo'],
|
||||
{
|
||||
silent: true
|
||||
});
|
||||
|
||||
assert.strictEqual(session.id, session2?.id);
|
||||
assert.strictEqual(session.scopes[0], session2?.scopes[0]);
|
||||
});
|
||||
|
||||
test('forceNewSession - true', async () => {
|
||||
const session1 = await extHostAuthentication.getSession(
|
||||
nullExtensionDescription,
|
||||
'test',
|
||||
['foo'],
|
||||
{
|
||||
createIfNone: true
|
||||
});
|
||||
|
||||
// Now create the session
|
||||
const session2 = await extHostAuthentication.getSession(
|
||||
nullExtensionDescription,
|
||||
'test',
|
||||
['foo'],
|
||||
{
|
||||
forceNewSession: true
|
||||
});
|
||||
|
||||
assert.strictEqual(session2?.id, 'test');
|
||||
assert.strictEqual(session2?.scopes[0], 'foo');
|
||||
assert.notStrictEqual(session1.accessToken, session2?.accessToken);
|
||||
});
|
||||
|
||||
test('forceNewSession - detail', async () => {
|
||||
const session1 = await extHostAuthentication.getSession(
|
||||
nullExtensionDescription,
|
||||
'test',
|
||||
['foo'],
|
||||
{
|
||||
createIfNone: true
|
||||
});
|
||||
|
||||
// Now create the session
|
||||
const session2 = await extHostAuthentication.getSession(
|
||||
nullExtensionDescription,
|
||||
'test',
|
||||
['foo'],
|
||||
{
|
||||
forceNewSession: { detail: 'bar' }
|
||||
});
|
||||
|
||||
assert.strictEqual(session2?.id, 'test');
|
||||
assert.strictEqual(session2?.scopes[0], 'foo');
|
||||
assert.notStrictEqual(session1.accessToken, session2?.accessToken);
|
||||
});
|
||||
|
||||
test('clearSessionPreference - true', async () => {
|
||||
// Now create the session
|
||||
const session = await extHostAuthentication.getSession(
|
||||
nullExtensionDescription,
|
||||
'test-multiple',
|
||||
['foo'],
|
||||
{
|
||||
createIfNone: true
|
||||
});
|
||||
|
||||
assert.strictEqual(session?.id, 'test');
|
||||
assert.strictEqual(session?.scopes[0], 'foo');
|
||||
|
||||
const session2 = await extHostAuthentication.getSession(
|
||||
nullExtensionDescription,
|
||||
'test-multiple',
|
||||
['foo'],
|
||||
{
|
||||
clearSessionPreference: true,
|
||||
createIfNone: true
|
||||
});
|
||||
|
||||
assert.strictEqual(session.id, session2?.id);
|
||||
assert.strictEqual(session.scopes[0], session2?.scopes[0]);
|
||||
assert.notStrictEqual(session.accessToken, session2?.accessToken);
|
||||
});
|
||||
|
||||
//#region error cases
|
||||
|
||||
test('forceNewSession with no sessions', async () => {
|
||||
try {
|
||||
await extHostAuthentication.getSession(
|
||||
nullExtensionDescription,
|
||||
'test',
|
||||
['foo'],
|
||||
{
|
||||
forceNewSession: true
|
||||
});
|
||||
assert.fail('should have thrown an Error.');
|
||||
} catch (e) {
|
||||
assert.strictEqual(e.message, 'No existing sessions found.');
|
||||
}
|
||||
});
|
||||
|
||||
test('createIfNone and forceNewSession', async () => {
|
||||
try {
|
||||
await extHostAuthentication.getSession(
|
||||
nullExtensionDescription,
|
||||
'test',
|
||||
['foo'],
|
||||
{
|
||||
createIfNone: true,
|
||||
forceNewSession: true
|
||||
});
|
||||
assert.fail('should have thrown an Error.');
|
||||
} catch (e) {
|
||||
assert.ok(e);
|
||||
}
|
||||
});
|
||||
|
||||
test('forceNewSession and silent', async () => {
|
||||
try {
|
||||
await extHostAuthentication.getSession(
|
||||
nullExtensionDescription,
|
||||
'test',
|
||||
['foo'],
|
||||
{
|
||||
forceNewSession: true,
|
||||
silent: true
|
||||
});
|
||||
assert.fail('should have thrown an Error.');
|
||||
} catch (e) {
|
||||
assert.ok(e);
|
||||
}
|
||||
});
|
||||
|
||||
test('createIfNone and silent', async () => {
|
||||
try {
|
||||
await extHostAuthentication.getSession(
|
||||
nullExtensionDescription,
|
||||
'test',
|
||||
['foo'],
|
||||
{
|
||||
createIfNone: true,
|
||||
silent: true
|
||||
});
|
||||
assert.fail('should have thrown an Error.');
|
||||
} catch (e) {
|
||||
assert.ok(e);
|
||||
}
|
||||
});
|
||||
|
||||
//#endregion
|
||||
});
|
||||
@@ -1,66 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 extHostTypes from 'vs/workbench/api/common/extHostTypes';
|
||||
import { MainContext, IWorkspaceEditDto, WorkspaceEditType, MainThreadBulkEditsShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { mock } from 'vs/base/test/common/mock';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import { SingleProxyRPCProtocol, TestRPCProtocol } from 'vs/workbench/test/browser/api/testRPCProtocol';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
import { assertType } from 'vs/base/common/types';
|
||||
import { ExtHostBulkEdits } from 'vs/workbench/api/common/extHostBulkEdits';
|
||||
|
||||
suite('ExtHostBulkEdits.applyWorkspaceEdit', () => {
|
||||
|
||||
const resource = URI.parse('foo:bar');
|
||||
let bulkEdits: ExtHostBulkEdits;
|
||||
let workspaceResourceEdits: IWorkspaceEditDto;
|
||||
|
||||
setup(() => {
|
||||
workspaceResourceEdits = null!;
|
||||
|
||||
let rpcProtocol = new TestRPCProtocol();
|
||||
rpcProtocol.set(MainContext.MainThreadBulkEdits, new class extends mock<MainThreadBulkEditsShape>() {
|
||||
override $tryApplyWorkspaceEdit(_workspaceResourceEdits: IWorkspaceEditDto): Promise<boolean> {
|
||||
workspaceResourceEdits = _workspaceResourceEdits;
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
});
|
||||
const documentsAndEditors = new ExtHostDocumentsAndEditors(SingleProxyRPCProtocol(null), new NullLogService());
|
||||
documentsAndEditors.$acceptDocumentsAndEditorsDelta({
|
||||
addedDocuments: [{
|
||||
isDirty: false,
|
||||
languageId: 'foo',
|
||||
uri: resource,
|
||||
versionId: 1337,
|
||||
lines: ['foo'],
|
||||
EOL: '\n',
|
||||
}]
|
||||
});
|
||||
bulkEdits = new ExtHostBulkEdits(rpcProtocol, documentsAndEditors);
|
||||
});
|
||||
|
||||
test('uses version id if document available', async () => {
|
||||
let edit = new extHostTypes.WorkspaceEdit();
|
||||
edit.replace(resource, new extHostTypes.Range(0, 0, 0, 0), 'hello');
|
||||
await bulkEdits.applyWorkspaceEdit(edit);
|
||||
assert.strictEqual(workspaceResourceEdits.edits.length, 1);
|
||||
const [first] = workspaceResourceEdits.edits;
|
||||
assertType(first._type === WorkspaceEditType.Text);
|
||||
assert.strictEqual(first.modelVersionId, 1337);
|
||||
});
|
||||
|
||||
test('does not use version id if document is not available', async () => {
|
||||
let edit = new extHostTypes.WorkspaceEdit();
|
||||
edit.replace(URI.parse('foo:bar2'), new extHostTypes.Range(0, 0, 0, 0), 'hello');
|
||||
await bulkEdits.applyWorkspaceEdit(edit);
|
||||
assert.strictEqual(workspaceResourceEdits.edits.length, 1);
|
||||
const [first] = workspaceResourceEdits.edits;
|
||||
assertType(first._type === WorkspaceEditType.Text);
|
||||
assert.ok(typeof first.modelVersionId === 'undefined');
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,93 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { MainThreadCommandsShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
|
||||
import { SingleProxyRPCProtocol } from './testRPCProtocol';
|
||||
import { mock } from 'vs/base/test/common/mock';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
|
||||
suite('ExtHostCommands', function () {
|
||||
|
||||
test('dispose calls unregister', function () {
|
||||
|
||||
let lastUnregister: string;
|
||||
|
||||
const shape = new class extends mock<MainThreadCommandsShape>() {
|
||||
override $registerCommand(id: string): void {
|
||||
//
|
||||
}
|
||||
override $unregisterCommand(id: string): void {
|
||||
lastUnregister = id;
|
||||
}
|
||||
};
|
||||
|
||||
const commands = new ExtHostCommands(
|
||||
SingleProxyRPCProtocol(shape),
|
||||
new NullLogService()
|
||||
);
|
||||
commands.registerCommand(true, 'foo', (): any => { }).dispose();
|
||||
assert.strictEqual(lastUnregister!, 'foo');
|
||||
assert.strictEqual(CommandsRegistry.getCommand('foo'), undefined);
|
||||
|
||||
});
|
||||
|
||||
test('dispose bubbles only once', function () {
|
||||
|
||||
let unregisterCounter = 0;
|
||||
|
||||
const shape = new class extends mock<MainThreadCommandsShape>() {
|
||||
override $registerCommand(id: string): void {
|
||||
//
|
||||
}
|
||||
override $unregisterCommand(id: string): void {
|
||||
unregisterCounter += 1;
|
||||
}
|
||||
};
|
||||
|
||||
const commands = new ExtHostCommands(
|
||||
SingleProxyRPCProtocol(shape),
|
||||
new NullLogService()
|
||||
);
|
||||
const reg = commands.registerCommand(true, 'foo', (): any => { });
|
||||
reg.dispose();
|
||||
reg.dispose();
|
||||
reg.dispose();
|
||||
assert.strictEqual(unregisterCounter, 1);
|
||||
});
|
||||
|
||||
test('execute with retry', async function () {
|
||||
|
||||
let count = 0;
|
||||
|
||||
const shape = new class extends mock<MainThreadCommandsShape>() {
|
||||
override $registerCommand(id: string): void {
|
||||
//
|
||||
}
|
||||
override async $executeCommand<T>(id: string, args: any[], retry: boolean): Promise<T | undefined> {
|
||||
count++;
|
||||
assert.strictEqual(retry, count === 1);
|
||||
if (count === 1) {
|
||||
assert.strictEqual(retry, true);
|
||||
throw new Error('$executeCommand:retry');
|
||||
} else {
|
||||
assert.strictEqual(retry, false);
|
||||
return <any>17;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const commands = new ExtHostCommands(
|
||||
SingleProxyRPCProtocol(shape),
|
||||
new NullLogService()
|
||||
);
|
||||
|
||||
const result = await commands.executeCommand('fooo', [this, true]);
|
||||
assert.strictEqual(result, 17);
|
||||
assert.strictEqual(count, 2);
|
||||
});
|
||||
});
|
||||
@@ -1,738 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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, UriComponents } from 'vs/base/common/uri';
|
||||
import { ExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
import { ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration';
|
||||
import { MainThreadConfigurationShape, IConfigurationInitData } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ConfigurationModel, ConfigurationModelParser } from 'vs/platform/configuration/common/configurationModels';
|
||||
import { TestRPCProtocol } from './testRPCProtocol';
|
||||
import { mock } from 'vs/base/test/common/mock';
|
||||
import { IWorkspaceFolder, WorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { ConfigurationTarget, IConfigurationModel, IConfigurationChange } from 'vs/platform/configuration/common/configuration';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
|
||||
import { IExtHostFileSystemInfo } from 'vs/workbench/api/common/extHostFileSystemInfo';
|
||||
import { FileSystemProviderCapabilities } from 'vs/platform/files/common/files';
|
||||
import { isLinux } from 'vs/base/common/platform';
|
||||
|
||||
suite('ExtHostConfiguration', function () {
|
||||
|
||||
class RecordingShape extends mock<MainThreadConfigurationShape>() {
|
||||
lastArgs!: [ConfigurationTarget, string, any];
|
||||
override $updateConfigurationOption(target: ConfigurationTarget, key: string, value: any): Promise<void> {
|
||||
this.lastArgs = [target, key, value];
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
function createExtHostWorkspace(): ExtHostWorkspace {
|
||||
return new ExtHostWorkspace(new TestRPCProtocol(), new class extends mock<IExtHostInitDataService>() { }, new class extends mock<IExtHostFileSystemInfo>() { override getCapabilities() { return isLinux ? FileSystemProviderCapabilities.PathCaseSensitive : undefined; } }, new NullLogService());
|
||||
}
|
||||
|
||||
function createExtHostConfiguration(contents: any = Object.create(null), shape?: MainThreadConfigurationShape) {
|
||||
if (!shape) {
|
||||
shape = new class extends mock<MainThreadConfigurationShape>() { };
|
||||
}
|
||||
return new ExtHostConfigProvider(shape, createExtHostWorkspace(), createConfigurationData(contents), new NullLogService());
|
||||
}
|
||||
|
||||
function createConfigurationData(contents: any): IConfigurationInitData {
|
||||
return {
|
||||
defaults: new ConfigurationModel(contents),
|
||||
user: new ConfigurationModel(contents),
|
||||
workspace: new ConfigurationModel(),
|
||||
folders: [],
|
||||
configurationScopes: []
|
||||
};
|
||||
}
|
||||
|
||||
test('getConfiguration fails regression test 1.7.1 -> 1.8 #15552', function () {
|
||||
const extHostConfig = createExtHostConfiguration({
|
||||
'search': {
|
||||
'exclude': {
|
||||
'**/node_modules': true
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
assert.strictEqual(extHostConfig.getConfiguration('search.exclude')['**/node_modules'], true);
|
||||
assert.strictEqual(extHostConfig.getConfiguration('search.exclude').get('**/node_modules'), true);
|
||||
assert.strictEqual(extHostConfig.getConfiguration('search').get<any>('exclude')['**/node_modules'], true);
|
||||
|
||||
assert.strictEqual(extHostConfig.getConfiguration('search.exclude').has('**/node_modules'), true);
|
||||
assert.strictEqual(extHostConfig.getConfiguration('search').has('exclude.**/node_modules'), true);
|
||||
});
|
||||
|
||||
test('has/get', () => {
|
||||
|
||||
const all = createExtHostConfiguration({
|
||||
'farboo': {
|
||||
'config0': true,
|
||||
'nested': {
|
||||
'config1': 42,
|
||||
'config2': 'Das Pferd frisst kein Reis.'
|
||||
},
|
||||
'config4': ''
|
||||
}
|
||||
});
|
||||
|
||||
const config = all.getConfiguration('farboo');
|
||||
|
||||
assert.ok(config.has('config0'));
|
||||
assert.strictEqual(config.get('config0'), true);
|
||||
assert.strictEqual(config.get('config4'), '');
|
||||
assert.strictEqual(config['config0'], true);
|
||||
assert.strictEqual(config['config4'], '');
|
||||
|
||||
assert.ok(config.has('nested.config1'));
|
||||
assert.strictEqual(config.get('nested.config1'), 42);
|
||||
assert.ok(config.has('nested.config2'));
|
||||
assert.strictEqual(config.get('nested.config2'), 'Das Pferd frisst kein Reis.');
|
||||
|
||||
assert.ok(config.has('nested'));
|
||||
assert.deepStrictEqual(config.get('nested'), { config1: 42, config2: 'Das Pferd frisst kein Reis.' });
|
||||
});
|
||||
|
||||
test('can modify the returned configuration', function () {
|
||||
|
||||
const all = createExtHostConfiguration({
|
||||
'farboo': {
|
||||
'config0': true,
|
||||
'nested': {
|
||||
'config1': 42,
|
||||
'config2': 'Das Pferd frisst kein Reis.'
|
||||
},
|
||||
'config4': ''
|
||||
},
|
||||
'workbench': {
|
||||
'colorCustomizations': {
|
||||
'statusBar.foreground': 'somevalue'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let testObject = all.getConfiguration();
|
||||
let actual = testObject.get<any>('farboo')!;
|
||||
actual['nested']['config1'] = 41;
|
||||
assert.strictEqual(41, actual['nested']['config1']);
|
||||
actual['farboo1'] = 'newValue';
|
||||
assert.strictEqual('newValue', actual['farboo1']);
|
||||
|
||||
testObject = all.getConfiguration();
|
||||
actual = testObject.get('farboo')!;
|
||||
assert.strictEqual(actual['nested']['config1'], 42);
|
||||
assert.strictEqual(actual['farboo1'], undefined);
|
||||
|
||||
testObject = all.getConfiguration();
|
||||
actual = testObject.get('farboo')!;
|
||||
assert.strictEqual(actual['config0'], true);
|
||||
actual['config0'] = false;
|
||||
assert.strictEqual(actual['config0'], false);
|
||||
|
||||
testObject = all.getConfiguration();
|
||||
actual = testObject.get('farboo')!;
|
||||
assert.strictEqual(actual['config0'], true);
|
||||
|
||||
testObject = all.getConfiguration();
|
||||
actual = testObject.inspect('farboo')!;
|
||||
actual['value'] = 'effectiveValue';
|
||||
assert.strictEqual('effectiveValue', actual['value']);
|
||||
|
||||
testObject = all.getConfiguration('workbench');
|
||||
actual = testObject.get('colorCustomizations')!;
|
||||
actual['statusBar.foreground'] = undefined;
|
||||
assert.strictEqual(actual['statusBar.foreground'], undefined);
|
||||
testObject = all.getConfiguration('workbench');
|
||||
actual = testObject.get('colorCustomizations')!;
|
||||
assert.strictEqual(actual['statusBar.foreground'], 'somevalue');
|
||||
});
|
||||
|
||||
test('Stringify returned configuration', function () {
|
||||
|
||||
const all = createExtHostConfiguration({
|
||||
'farboo': {
|
||||
'config0': true,
|
||||
'nested': {
|
||||
'config1': 42,
|
||||
'config2': 'Das Pferd frisst kein Reis.'
|
||||
},
|
||||
'config4': ''
|
||||
},
|
||||
'workbench': {
|
||||
'colorCustomizations': {
|
||||
'statusBar.foreground': 'somevalue'
|
||||
},
|
||||
'emptyobjectkey': {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const testObject = all.getConfiguration();
|
||||
let actual: any = testObject.get('farboo');
|
||||
assert.deepStrictEqual(JSON.stringify({
|
||||
'config0': true,
|
||||
'nested': {
|
||||
'config1': 42,
|
||||
'config2': 'Das Pferd frisst kein Reis.'
|
||||
},
|
||||
'config4': ''
|
||||
}), JSON.stringify(actual));
|
||||
|
||||
assert.deepStrictEqual(undefined, JSON.stringify(testObject.get('unknownkey')));
|
||||
|
||||
actual = testObject.get('farboo')!;
|
||||
actual['config0'] = false;
|
||||
assert.deepStrictEqual(JSON.stringify({
|
||||
'config0': false,
|
||||
'nested': {
|
||||
'config1': 42,
|
||||
'config2': 'Das Pferd frisst kein Reis.'
|
||||
},
|
||||
'config4': ''
|
||||
}), JSON.stringify(actual));
|
||||
|
||||
actual = testObject.get<any>('workbench')!['colorCustomizations']!;
|
||||
actual['statusBar.background'] = 'anothervalue';
|
||||
assert.deepStrictEqual(JSON.stringify({
|
||||
'statusBar.foreground': 'somevalue',
|
||||
'statusBar.background': 'anothervalue'
|
||||
}), JSON.stringify(actual));
|
||||
|
||||
actual = testObject.get('workbench');
|
||||
actual['unknownkey'] = 'somevalue';
|
||||
assert.deepStrictEqual(JSON.stringify({
|
||||
'colorCustomizations': {
|
||||
'statusBar.foreground': 'somevalue'
|
||||
},
|
||||
'emptyobjectkey': {},
|
||||
'unknownkey': 'somevalue'
|
||||
}), JSON.stringify(actual));
|
||||
|
||||
actual = all.getConfiguration('workbench').get('emptyobjectkey');
|
||||
actual = {
|
||||
...(actual || {}),
|
||||
'statusBar.background': `#0ff`,
|
||||
'statusBar.foreground': `#ff0`,
|
||||
};
|
||||
assert.deepStrictEqual(JSON.stringify({
|
||||
'statusBar.background': `#0ff`,
|
||||
'statusBar.foreground': `#ff0`,
|
||||
}), JSON.stringify(actual));
|
||||
|
||||
actual = all.getConfiguration('workbench').get('unknownkey');
|
||||
actual = {
|
||||
...(actual || {}),
|
||||
'statusBar.background': `#0ff`,
|
||||
'statusBar.foreground': `#ff0`,
|
||||
};
|
||||
assert.deepStrictEqual(JSON.stringify({
|
||||
'statusBar.background': `#0ff`,
|
||||
'statusBar.foreground': `#ff0`,
|
||||
}), JSON.stringify(actual));
|
||||
});
|
||||
|
||||
test('cannot modify returned configuration', function () {
|
||||
|
||||
const all = createExtHostConfiguration({
|
||||
'farboo': {
|
||||
'config0': true,
|
||||
'nested': {
|
||||
'config1': 42,
|
||||
'config2': 'Das Pferd frisst kein Reis.'
|
||||
},
|
||||
'config4': ''
|
||||
}
|
||||
});
|
||||
|
||||
let testObject: any = all.getConfiguration();
|
||||
|
||||
try {
|
||||
testObject['get'] = null;
|
||||
assert.fail('This should be readonly');
|
||||
} catch (e) {
|
||||
}
|
||||
|
||||
try {
|
||||
testObject['farboo']['config0'] = false;
|
||||
assert.fail('This should be readonly');
|
||||
} catch (e) {
|
||||
}
|
||||
|
||||
try {
|
||||
testObject['farboo']['farboo1'] = 'hello';
|
||||
assert.fail('This should be readonly');
|
||||
} catch (e) {
|
||||
}
|
||||
});
|
||||
|
||||
test('inspect in no workspace context', function () {
|
||||
const testObject = new ExtHostConfigProvider(
|
||||
new class extends mock<MainThreadConfigurationShape>() { },
|
||||
createExtHostWorkspace(),
|
||||
{
|
||||
defaults: new ConfigurationModel({
|
||||
'editor': {
|
||||
'wordWrap': 'off'
|
||||
}
|
||||
}, ['editor.wordWrap']),
|
||||
user: new ConfigurationModel({
|
||||
'editor': {
|
||||
'wordWrap': 'on'
|
||||
}
|
||||
}, ['editor.wordWrap']),
|
||||
workspace: new ConfigurationModel({}, []),
|
||||
folders: [],
|
||||
configurationScopes: []
|
||||
},
|
||||
new NullLogService()
|
||||
);
|
||||
|
||||
let actual = testObject.getConfiguration().inspect('editor.wordWrap')!;
|
||||
assert.strictEqual(actual.defaultValue, 'off');
|
||||
assert.strictEqual(actual.globalValue, 'on');
|
||||
assert.strictEqual(actual.workspaceValue, undefined);
|
||||
assert.strictEqual(actual.workspaceFolderValue, undefined);
|
||||
|
||||
actual = testObject.getConfiguration('editor').inspect('wordWrap')!;
|
||||
assert.strictEqual(actual.defaultValue, 'off');
|
||||
assert.strictEqual(actual.globalValue, 'on');
|
||||
assert.strictEqual(actual.workspaceValue, undefined);
|
||||
assert.strictEqual(actual.workspaceFolderValue, undefined);
|
||||
});
|
||||
|
||||
test('inspect in single root context', function () {
|
||||
const workspaceUri = URI.file('foo');
|
||||
const folders: [UriComponents, IConfigurationModel][] = [];
|
||||
const workspace = new ConfigurationModel({
|
||||
'editor': {
|
||||
'wordWrap': 'bounded'
|
||||
}
|
||||
}, ['editor.wordWrap']);
|
||||
folders.push([workspaceUri, workspace]);
|
||||
const extHostWorkspace = createExtHostWorkspace();
|
||||
extHostWorkspace.$initializeWorkspace({
|
||||
'id': 'foo',
|
||||
'folders': [aWorkspaceFolder(URI.file('foo'), 0)],
|
||||
'name': 'foo'
|
||||
}, true);
|
||||
const testObject = new ExtHostConfigProvider(
|
||||
new class extends mock<MainThreadConfigurationShape>() { },
|
||||
extHostWorkspace,
|
||||
{
|
||||
defaults: new ConfigurationModel({
|
||||
'editor': {
|
||||
'wordWrap': 'off'
|
||||
}
|
||||
}, ['editor.wordWrap']),
|
||||
user: new ConfigurationModel({
|
||||
'editor': {
|
||||
'wordWrap': 'on'
|
||||
}
|
||||
}, ['editor.wordWrap']),
|
||||
workspace,
|
||||
folders,
|
||||
configurationScopes: []
|
||||
},
|
||||
new NullLogService()
|
||||
);
|
||||
|
||||
let actual1 = testObject.getConfiguration().inspect('editor.wordWrap')!;
|
||||
assert.strictEqual(actual1.defaultValue, 'off');
|
||||
assert.strictEqual(actual1.globalValue, 'on');
|
||||
assert.strictEqual(actual1.workspaceValue, 'bounded');
|
||||
assert.strictEqual(actual1.workspaceFolderValue, undefined);
|
||||
|
||||
actual1 = testObject.getConfiguration('editor').inspect('wordWrap')!;
|
||||
assert.strictEqual(actual1.defaultValue, 'off');
|
||||
assert.strictEqual(actual1.globalValue, 'on');
|
||||
assert.strictEqual(actual1.workspaceValue, 'bounded');
|
||||
assert.strictEqual(actual1.workspaceFolderValue, undefined);
|
||||
|
||||
let actual2 = testObject.getConfiguration(undefined, workspaceUri).inspect('editor.wordWrap')!;
|
||||
assert.strictEqual(actual2.defaultValue, 'off');
|
||||
assert.strictEqual(actual2.globalValue, 'on');
|
||||
assert.strictEqual(actual2.workspaceValue, 'bounded');
|
||||
assert.strictEqual(actual2.workspaceFolderValue, 'bounded');
|
||||
|
||||
actual2 = testObject.getConfiguration('editor', workspaceUri).inspect('wordWrap')!;
|
||||
assert.strictEqual(actual2.defaultValue, 'off');
|
||||
assert.strictEqual(actual2.globalValue, 'on');
|
||||
assert.strictEqual(actual2.workspaceValue, 'bounded');
|
||||
assert.strictEqual(actual2.workspaceFolderValue, 'bounded');
|
||||
});
|
||||
|
||||
test('inspect in multi root context', function () {
|
||||
const workspace = new ConfigurationModel({
|
||||
'editor': {
|
||||
'wordWrap': 'bounded'
|
||||
}
|
||||
}, ['editor.wordWrap']);
|
||||
|
||||
const firstRoot = URI.file('foo1');
|
||||
const secondRoot = URI.file('foo2');
|
||||
const thirdRoot = URI.file('foo3');
|
||||
const folders: [UriComponents, IConfigurationModel][] = [];
|
||||
folders.push([firstRoot, new ConfigurationModel({
|
||||
'editor': {
|
||||
'wordWrap': 'off',
|
||||
'lineNumbers': 'relative'
|
||||
}
|
||||
}, ['editor.wordWrap'])]);
|
||||
folders.push([secondRoot, new ConfigurationModel({
|
||||
'editor': {
|
||||
'wordWrap': 'on'
|
||||
}
|
||||
}, ['editor.wordWrap'])]);
|
||||
folders.push([thirdRoot, new ConfigurationModel({}, [])]);
|
||||
|
||||
const extHostWorkspace = createExtHostWorkspace();
|
||||
extHostWorkspace.$initializeWorkspace({
|
||||
'id': 'foo',
|
||||
'folders': [aWorkspaceFolder(firstRoot, 0), aWorkspaceFolder(secondRoot, 1)],
|
||||
'name': 'foo'
|
||||
}, true);
|
||||
const testObject = new ExtHostConfigProvider(
|
||||
new class extends mock<MainThreadConfigurationShape>() { },
|
||||
extHostWorkspace,
|
||||
{
|
||||
defaults: new ConfigurationModel({
|
||||
'editor': {
|
||||
'wordWrap': 'off',
|
||||
'lineNumbers': 'on'
|
||||
}
|
||||
}, ['editor.wordWrap']),
|
||||
user: new ConfigurationModel({
|
||||
'editor': {
|
||||
'wordWrap': 'on'
|
||||
}
|
||||
}, ['editor.wordWrap']),
|
||||
workspace,
|
||||
folders,
|
||||
configurationScopes: []
|
||||
},
|
||||
new NullLogService()
|
||||
);
|
||||
|
||||
let actual1 = testObject.getConfiguration().inspect('editor.wordWrap')!;
|
||||
assert.strictEqual(actual1.defaultValue, 'off');
|
||||
assert.strictEqual(actual1.globalValue, 'on');
|
||||
assert.strictEqual(actual1.workspaceValue, 'bounded');
|
||||
assert.strictEqual(actual1.workspaceFolderValue, undefined);
|
||||
|
||||
actual1 = testObject.getConfiguration('editor').inspect('wordWrap')!;
|
||||
assert.strictEqual(actual1.defaultValue, 'off');
|
||||
assert.strictEqual(actual1.globalValue, 'on');
|
||||
assert.strictEqual(actual1.workspaceValue, 'bounded');
|
||||
assert.strictEqual(actual1.workspaceFolderValue, undefined);
|
||||
|
||||
actual1 = testObject.getConfiguration('editor').inspect('lineNumbers')!;
|
||||
assert.strictEqual(actual1.defaultValue, 'on');
|
||||
assert.strictEqual(actual1.globalValue, undefined);
|
||||
assert.strictEqual(actual1.workspaceValue, undefined);
|
||||
assert.strictEqual(actual1.workspaceFolderValue, undefined);
|
||||
|
||||
let actual2 = testObject.getConfiguration(undefined, firstRoot).inspect('editor.wordWrap')!;
|
||||
assert.strictEqual(actual2.defaultValue, 'off');
|
||||
assert.strictEqual(actual2.globalValue, 'on');
|
||||
assert.strictEqual(actual2.workspaceValue, 'bounded');
|
||||
assert.strictEqual(actual2.workspaceFolderValue, 'off');
|
||||
|
||||
actual2 = testObject.getConfiguration('editor', firstRoot).inspect('wordWrap')!;
|
||||
assert.strictEqual(actual2.defaultValue, 'off');
|
||||
assert.strictEqual(actual2.globalValue, 'on');
|
||||
assert.strictEqual(actual2.workspaceValue, 'bounded');
|
||||
assert.strictEqual(actual2.workspaceFolderValue, 'off');
|
||||
|
||||
actual2 = testObject.getConfiguration('editor', firstRoot).inspect('lineNumbers')!;
|
||||
assert.strictEqual(actual2.defaultValue, 'on');
|
||||
assert.strictEqual(actual2.globalValue, undefined);
|
||||
assert.strictEqual(actual2.workspaceValue, undefined);
|
||||
assert.strictEqual(actual2.workspaceFolderValue, 'relative');
|
||||
|
||||
actual2 = testObject.getConfiguration(undefined, secondRoot).inspect('editor.wordWrap')!;
|
||||
assert.strictEqual(actual2.defaultValue, 'off');
|
||||
assert.strictEqual(actual2.globalValue, 'on');
|
||||
assert.strictEqual(actual2.workspaceValue, 'bounded');
|
||||
assert.strictEqual(actual2.workspaceFolderValue, 'on');
|
||||
|
||||
actual2 = testObject.getConfiguration('editor', secondRoot).inspect('wordWrap')!;
|
||||
assert.strictEqual(actual2.defaultValue, 'off');
|
||||
assert.strictEqual(actual2.globalValue, 'on');
|
||||
assert.strictEqual(actual2.workspaceValue, 'bounded');
|
||||
assert.strictEqual(actual2.workspaceFolderValue, 'on');
|
||||
|
||||
actual2 = testObject.getConfiguration(undefined, thirdRoot).inspect('editor.wordWrap')!;
|
||||
assert.strictEqual(actual2.defaultValue, 'off');
|
||||
assert.strictEqual(actual2.globalValue, 'on');
|
||||
assert.strictEqual(actual2.workspaceValue, 'bounded');
|
||||
assert.ok(Object.keys(actual2).indexOf('workspaceFolderValue') !== -1);
|
||||
assert.strictEqual(actual2.workspaceFolderValue, undefined);
|
||||
|
||||
actual2 = testObject.getConfiguration('editor', thirdRoot).inspect('wordWrap')!;
|
||||
assert.strictEqual(actual2.defaultValue, 'off');
|
||||
assert.strictEqual(actual2.globalValue, 'on');
|
||||
assert.strictEqual(actual2.workspaceValue, 'bounded');
|
||||
assert.ok(Object.keys(actual2).indexOf('workspaceFolderValue') !== -1);
|
||||
assert.strictEqual(actual2.workspaceFolderValue, undefined);
|
||||
});
|
||||
|
||||
test('inspect with language overrides', function () {
|
||||
const firstRoot = URI.file('foo1');
|
||||
const secondRoot = URI.file('foo2');
|
||||
const folders: [UriComponents, IConfigurationModel][] = [];
|
||||
folders.push([firstRoot, toConfigurationModel({
|
||||
'editor.wordWrap': 'bounded',
|
||||
'[typescript]': {
|
||||
'editor.wordWrap': 'unbounded',
|
||||
}
|
||||
})]);
|
||||
folders.push([secondRoot, toConfigurationModel({})]);
|
||||
|
||||
const extHostWorkspace = createExtHostWorkspace();
|
||||
extHostWorkspace.$initializeWorkspace({
|
||||
'id': 'foo',
|
||||
'folders': [aWorkspaceFolder(firstRoot, 0), aWorkspaceFolder(secondRoot, 1)],
|
||||
'name': 'foo'
|
||||
}, true);
|
||||
const testObject = new ExtHostConfigProvider(
|
||||
new class extends mock<MainThreadConfigurationShape>() { },
|
||||
extHostWorkspace,
|
||||
{
|
||||
defaults: toConfigurationModel({
|
||||
'editor.wordWrap': 'off',
|
||||
'[markdown]': {
|
||||
'editor.wordWrap': 'bounded',
|
||||
}
|
||||
}),
|
||||
user: toConfigurationModel({
|
||||
'editor.wordWrap': 'bounded',
|
||||
'[typescript]': {
|
||||
'editor.lineNumbers': 'off',
|
||||
}
|
||||
}),
|
||||
workspace: toConfigurationModel({
|
||||
'[typescript]': {
|
||||
'editor.wordWrap': 'unbounded',
|
||||
'editor.lineNumbers': 'off',
|
||||
}
|
||||
}),
|
||||
folders,
|
||||
configurationScopes: []
|
||||
},
|
||||
new NullLogService()
|
||||
);
|
||||
|
||||
let actual = testObject.getConfiguration(undefined, { uri: firstRoot, languageId: 'typescript' }).inspect('editor.wordWrap')!;
|
||||
assert.strictEqual(actual.defaultValue, 'off');
|
||||
assert.strictEqual(actual.globalValue, 'bounded');
|
||||
assert.strictEqual(actual.workspaceValue, undefined);
|
||||
assert.strictEqual(actual.workspaceFolderValue, 'bounded');
|
||||
assert.strictEqual(actual.defaultLanguageValue, undefined);
|
||||
assert.strictEqual(actual.globalLanguageValue, undefined);
|
||||
assert.strictEqual(actual.workspaceLanguageValue, 'unbounded');
|
||||
assert.strictEqual(actual.workspaceFolderLanguageValue, 'unbounded');
|
||||
assert.deepStrictEqual(actual.languageIds, ['markdown', 'typescript']);
|
||||
|
||||
actual = testObject.getConfiguration(undefined, { uri: secondRoot, languageId: 'typescript' }).inspect('editor.wordWrap')!;
|
||||
assert.strictEqual(actual.defaultValue, 'off');
|
||||
assert.strictEqual(actual.globalValue, 'bounded');
|
||||
assert.strictEqual(actual.workspaceValue, undefined);
|
||||
assert.strictEqual(actual.workspaceFolderValue, undefined);
|
||||
assert.strictEqual(actual.defaultLanguageValue, undefined);
|
||||
assert.strictEqual(actual.globalLanguageValue, undefined);
|
||||
assert.strictEqual(actual.workspaceLanguageValue, 'unbounded');
|
||||
assert.strictEqual(actual.workspaceFolderLanguageValue, undefined);
|
||||
assert.deepStrictEqual(actual.languageIds, ['markdown', 'typescript']);
|
||||
});
|
||||
|
||||
|
||||
test('getConfiguration vs get', function () {
|
||||
|
||||
const all = createExtHostConfiguration({
|
||||
'farboo': {
|
||||
'config0': true,
|
||||
'config4': 38
|
||||
}
|
||||
});
|
||||
|
||||
let config = all.getConfiguration('farboo.config0');
|
||||
assert.strictEqual(config.get(''), undefined);
|
||||
assert.strictEqual(config.has(''), false);
|
||||
|
||||
config = all.getConfiguration('farboo');
|
||||
assert.strictEqual(config.get('config0'), true);
|
||||
assert.strictEqual(config.has('config0'), true);
|
||||
});
|
||||
|
||||
test('getConfiguration vs get', function () {
|
||||
|
||||
const all = createExtHostConfiguration({
|
||||
'farboo': {
|
||||
'config0': true,
|
||||
'config4': 38
|
||||
}
|
||||
});
|
||||
|
||||
let config = all.getConfiguration('farboo.config0');
|
||||
assert.strictEqual(config.get(''), undefined);
|
||||
assert.strictEqual(config.has(''), false);
|
||||
|
||||
config = all.getConfiguration('farboo');
|
||||
assert.strictEqual(config.get('config0'), true);
|
||||
assert.strictEqual(config.has('config0'), true);
|
||||
});
|
||||
|
||||
test('name vs property', function () {
|
||||
const all = createExtHostConfiguration({
|
||||
'farboo': {
|
||||
'get': 'get-prop'
|
||||
}
|
||||
});
|
||||
const config = all.getConfiguration('farboo');
|
||||
|
||||
assert.ok(config.has('get'));
|
||||
assert.strictEqual(config.get('get'), 'get-prop');
|
||||
assert.deepStrictEqual(config['get'], config.get);
|
||||
assert.throws(() => config['get'] = <any>'get-prop');
|
||||
});
|
||||
|
||||
test('update: no target passes null', function () {
|
||||
const shape = new RecordingShape();
|
||||
const allConfig = createExtHostConfiguration({
|
||||
'foo': {
|
||||
'bar': 1,
|
||||
'far': 1
|
||||
}
|
||||
}, shape);
|
||||
|
||||
let config = allConfig.getConfiguration('foo');
|
||||
config.update('bar', 42);
|
||||
|
||||
assert.strictEqual(shape.lastArgs[0], null);
|
||||
});
|
||||
|
||||
test('update/section to key', function () {
|
||||
|
||||
const shape = new RecordingShape();
|
||||
const allConfig = createExtHostConfiguration({
|
||||
'foo': {
|
||||
'bar': 1,
|
||||
'far': 1
|
||||
}
|
||||
}, shape);
|
||||
|
||||
let config = allConfig.getConfiguration('foo');
|
||||
config.update('bar', 42, true);
|
||||
|
||||
assert.strictEqual(shape.lastArgs[0], ConfigurationTarget.USER);
|
||||
assert.strictEqual(shape.lastArgs[1], 'foo.bar');
|
||||
assert.strictEqual(shape.lastArgs[2], 42);
|
||||
|
||||
config = allConfig.getConfiguration('');
|
||||
config.update('bar', 42, true);
|
||||
assert.strictEqual(shape.lastArgs[1], 'bar');
|
||||
|
||||
config.update('foo.bar', 42, true);
|
||||
assert.strictEqual(shape.lastArgs[1], 'foo.bar');
|
||||
});
|
||||
|
||||
test('update, what is #15834', function () {
|
||||
const shape = new RecordingShape();
|
||||
const allConfig = createExtHostConfiguration({
|
||||
'editor': {
|
||||
'formatOnSave': true
|
||||
}
|
||||
}, shape);
|
||||
|
||||
allConfig.getConfiguration('editor').update('formatOnSave', { extensions: ['ts'] });
|
||||
assert.strictEqual(shape.lastArgs[1], 'editor.formatOnSave');
|
||||
assert.deepStrictEqual(shape.lastArgs[2], { extensions: ['ts'] });
|
||||
});
|
||||
|
||||
test('update/error-state not OK', function () {
|
||||
|
||||
const shape = new class extends mock<MainThreadConfigurationShape>() {
|
||||
override $updateConfigurationOption(target: ConfigurationTarget, key: string, value: any): Promise<any> {
|
||||
return Promise.reject(new Error('Unknown Key')); // something !== OK
|
||||
}
|
||||
};
|
||||
|
||||
return createExtHostConfiguration({}, shape)
|
||||
.getConfiguration('')
|
||||
.update('', true, false)
|
||||
.then(() => assert.ok(false), err => { /* expecting rejection */ });
|
||||
});
|
||||
|
||||
test('configuration change event', (done) => {
|
||||
|
||||
const workspaceFolder = aWorkspaceFolder(URI.file('folder1'), 0);
|
||||
const extHostWorkspace = createExtHostWorkspace();
|
||||
extHostWorkspace.$initializeWorkspace({
|
||||
'id': 'foo',
|
||||
'folders': [workspaceFolder],
|
||||
'name': 'foo'
|
||||
}, true);
|
||||
const testObject = new ExtHostConfigProvider(
|
||||
new class extends mock<MainThreadConfigurationShape>() { },
|
||||
extHostWorkspace,
|
||||
createConfigurationData({
|
||||
'farboo': {
|
||||
'config': false,
|
||||
'updatedConfig': false
|
||||
}
|
||||
}),
|
||||
new NullLogService()
|
||||
);
|
||||
|
||||
const newConfigData = createConfigurationData({
|
||||
'farboo': {
|
||||
'config': false,
|
||||
'updatedConfig': true,
|
||||
'newConfig': true,
|
||||
}
|
||||
});
|
||||
const configEventData: IConfigurationChange = { keys: ['farboo.updatedConfig', 'farboo.newConfig'], overrides: [] };
|
||||
testObject.onDidChangeConfiguration(e => {
|
||||
|
||||
assert.deepStrictEqual(testObject.getConfiguration().get('farboo'), {
|
||||
'config': false,
|
||||
'updatedConfig': true,
|
||||
'newConfig': true,
|
||||
});
|
||||
|
||||
assert.ok(e.affectsConfiguration('farboo'));
|
||||
assert.ok(e.affectsConfiguration('farboo', workspaceFolder.uri));
|
||||
assert.ok(e.affectsConfiguration('farboo', URI.file('any')));
|
||||
|
||||
assert.ok(e.affectsConfiguration('farboo.updatedConfig'));
|
||||
assert.ok(e.affectsConfiguration('farboo.updatedConfig', workspaceFolder.uri));
|
||||
assert.ok(e.affectsConfiguration('farboo.updatedConfig', URI.file('any')));
|
||||
|
||||
assert.ok(e.affectsConfiguration('farboo.newConfig'));
|
||||
assert.ok(e.affectsConfiguration('farboo.newConfig', workspaceFolder.uri));
|
||||
assert.ok(e.affectsConfiguration('farboo.newConfig', URI.file('any')));
|
||||
|
||||
assert.ok(!e.affectsConfiguration('farboo.config'));
|
||||
assert.ok(!e.affectsConfiguration('farboo.config', workspaceFolder.uri));
|
||||
assert.ok(!e.affectsConfiguration('farboo.config', URI.file('any')));
|
||||
done();
|
||||
});
|
||||
|
||||
testObject.$acceptConfigurationChanged(newConfigData, configEventData);
|
||||
});
|
||||
|
||||
function aWorkspaceFolder(uri: URI, index: number, name: string = ''): IWorkspaceFolder {
|
||||
return new WorkspaceFolder({ uri, name, index });
|
||||
}
|
||||
|
||||
function toConfigurationModel(obj: any): ConfigurationModel {
|
||||
const parser = new ConfigurationModelParser('test');
|
||||
parser.parse(JSON.stringify(obj));
|
||||
return parser.configurationModel;
|
||||
}
|
||||
|
||||
});
|
||||
@@ -1,84 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { timeout } from 'vs/base/common/async';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { mock } from 'vs/base/test/common/mock';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
import { MainThreadDecorationsShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostDecorations } from 'vs/workbench/api/common/extHostDecorations';
|
||||
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
import { nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
|
||||
|
||||
suite('ExtHostDecorations', function () {
|
||||
|
||||
let mainThreadShape: MainThreadDecorationsShape;
|
||||
let extHostDecorations: ExtHostDecorations;
|
||||
let providers = new Set<number>();
|
||||
|
||||
setup(function () {
|
||||
|
||||
providers.clear();
|
||||
|
||||
mainThreadShape = new class extends mock<MainThreadDecorationsShape>() {
|
||||
override $registerDecorationProvider(handle: number) {
|
||||
providers.add(handle);
|
||||
}
|
||||
};
|
||||
|
||||
extHostDecorations = new ExtHostDecorations(
|
||||
new class extends mock<IExtHostRpcService>() {
|
||||
override getProxy(): any {
|
||||
return mainThreadShape;
|
||||
}
|
||||
},
|
||||
new NullLogService()
|
||||
);
|
||||
});
|
||||
|
||||
test('SCM Decorations missing #100524', async function () {
|
||||
|
||||
let calledA = false;
|
||||
let calledB = false;
|
||||
|
||||
// never returns
|
||||
extHostDecorations.registerFileDecorationProvider({
|
||||
|
||||
provideFileDecoration() {
|
||||
calledA = true;
|
||||
return new Promise(() => { });
|
||||
}
|
||||
}, nullExtensionDescription.identifier);
|
||||
|
||||
// always returns
|
||||
extHostDecorations.registerFileDecorationProvider({
|
||||
|
||||
provideFileDecoration() {
|
||||
calledB = true;
|
||||
return new Promise(resolve => resolve({ badge: 'H', tooltip: 'Hello' }));
|
||||
}
|
||||
}, nullExtensionDescription.identifier);
|
||||
|
||||
|
||||
const requests = [...providers.values()].map((handle, idx) => {
|
||||
return extHostDecorations.$provideDecorations(handle, [{ id: idx, uri: URI.parse('test:///file') }], CancellationToken.None);
|
||||
});
|
||||
|
||||
assert.strictEqual(calledA, true);
|
||||
assert.strictEqual(calledB, true);
|
||||
|
||||
assert.strictEqual(requests.length, 2);
|
||||
const [first, second] = requests;
|
||||
|
||||
const firstResult = await Promise.race([first, timeout(30).then(() => false)]);
|
||||
assert.strictEqual(typeof firstResult, 'boolean'); // never finishes...
|
||||
|
||||
const secondResult = await Promise.race([second, timeout(30).then(() => false)]);
|
||||
assert.strictEqual(typeof secondResult, 'object');
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,530 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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, UriComponents } from 'vs/base/common/uri';
|
||||
import { DiagnosticCollection, ExtHostDiagnostics } from 'vs/workbench/api/common/extHostDiagnostics';
|
||||
import { Diagnostic, DiagnosticSeverity, Range, DiagnosticRelatedInformation, Location } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { MainThreadDiagnosticsShape, IMainContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { IMarkerData, MarkerSeverity } from 'vs/platform/markers/common/markers';
|
||||
import { mock } from 'vs/base/test/common/mock';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
import type * as vscode from 'vscode';
|
||||
import { nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ExtUri, extUri } from 'vs/base/common/resources';
|
||||
import { IExtHostFileSystemInfo } from 'vs/workbench/api/common/extHostFileSystemInfo';
|
||||
|
||||
suite('ExtHostDiagnostics', () => {
|
||||
|
||||
class DiagnosticsShape extends mock<MainThreadDiagnosticsShape>() {
|
||||
override $changeMany(owner: string, entries: [UriComponents, IMarkerData[]][]): void {
|
||||
//
|
||||
}
|
||||
override $clear(owner: string): void {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
const fileSystemInfoService = new class extends mock<IExtHostFileSystemInfo>() {
|
||||
override readonly extUri = extUri;
|
||||
};
|
||||
|
||||
test('disposeCheck', () => {
|
||||
|
||||
const collection = new DiagnosticCollection('test', 'test', 100, extUri, new DiagnosticsShape(), new Emitter());
|
||||
|
||||
collection.dispose();
|
||||
collection.dispose(); // that's OK
|
||||
assert.throws(() => collection.name);
|
||||
assert.throws(() => collection.clear());
|
||||
assert.throws(() => collection.delete(URI.parse('aa:bb')));
|
||||
assert.throws(() => collection.forEach(() => { }));
|
||||
assert.throws(() => collection.get(URI.parse('aa:bb')));
|
||||
assert.throws(() => collection.has(URI.parse('aa:bb')));
|
||||
assert.throws(() => collection.set(URI.parse('aa:bb'), []));
|
||||
assert.throws(() => collection.set(URI.parse('aa:bb'), undefined!));
|
||||
});
|
||||
|
||||
|
||||
test('diagnostic collection, forEach, clear, has', function () {
|
||||
let collection = new DiagnosticCollection('test', 'test', 100, extUri, new DiagnosticsShape(), new Emitter());
|
||||
assert.strictEqual(collection.name, 'test');
|
||||
collection.dispose();
|
||||
assert.throws(() => collection.name);
|
||||
|
||||
let c = 0;
|
||||
collection = new DiagnosticCollection('test', 'test', 100, extUri, new DiagnosticsShape(), new Emitter());
|
||||
collection.forEach(() => c++);
|
||||
assert.strictEqual(c, 0);
|
||||
|
||||
collection.set(URI.parse('foo:bar'), [
|
||||
new Diagnostic(new Range(0, 0, 1, 1), 'message-1'),
|
||||
new Diagnostic(new Range(0, 0, 1, 1), 'message-2')
|
||||
]);
|
||||
collection.forEach(() => c++);
|
||||
assert.strictEqual(c, 1);
|
||||
|
||||
c = 0;
|
||||
collection.clear();
|
||||
collection.forEach(() => c++);
|
||||
assert.strictEqual(c, 0);
|
||||
|
||||
collection.set(URI.parse('foo:bar1'), [
|
||||
new Diagnostic(new Range(0, 0, 1, 1), 'message-1'),
|
||||
new Diagnostic(new Range(0, 0, 1, 1), 'message-2')
|
||||
]);
|
||||
collection.set(URI.parse('foo:bar2'), [
|
||||
new Diagnostic(new Range(0, 0, 1, 1), 'message-1'),
|
||||
new Diagnostic(new Range(0, 0, 1, 1), 'message-2')
|
||||
]);
|
||||
collection.forEach(() => c++);
|
||||
assert.strictEqual(c, 2);
|
||||
|
||||
assert.ok(collection.has(URI.parse('foo:bar1')));
|
||||
assert.ok(collection.has(URI.parse('foo:bar2')));
|
||||
assert.ok(!collection.has(URI.parse('foo:bar3')));
|
||||
collection.delete(URI.parse('foo:bar1'));
|
||||
assert.ok(!collection.has(URI.parse('foo:bar1')));
|
||||
|
||||
collection.dispose();
|
||||
});
|
||||
|
||||
test('diagnostic collection, immutable read', function () {
|
||||
let collection = new DiagnosticCollection('test', 'test', 100, extUri, new DiagnosticsShape(), new Emitter());
|
||||
collection.set(URI.parse('foo:bar'), [
|
||||
new Diagnostic(new Range(0, 0, 1, 1), 'message-1'),
|
||||
new Diagnostic(new Range(0, 0, 1, 1), 'message-2')
|
||||
]);
|
||||
|
||||
let array = collection.get(URI.parse('foo:bar')) as Diagnostic[];
|
||||
assert.throws(() => array.length = 0);
|
||||
assert.throws(() => array.pop());
|
||||
assert.throws(() => array[0] = new Diagnostic(new Range(0, 0, 0, 0), 'evil'));
|
||||
|
||||
collection.forEach((uri: URI, array: readonly vscode.Diagnostic[]): any => {
|
||||
assert.throws(() => (array as Diagnostic[]).length = 0);
|
||||
assert.throws(() => (array as Diagnostic[]).pop());
|
||||
assert.throws(() => (array as Diagnostic[])[0] = new Diagnostic(new Range(0, 0, 0, 0), 'evil'));
|
||||
});
|
||||
|
||||
array = collection.get(URI.parse('foo:bar')) as Diagnostic[];
|
||||
assert.strictEqual(array.length, 2);
|
||||
|
||||
collection.dispose();
|
||||
});
|
||||
|
||||
|
||||
test('diagnostics collection, set with dupliclated tuples', function () {
|
||||
let collection = new DiagnosticCollection('test', 'test', 100, extUri, new DiagnosticsShape(), new Emitter());
|
||||
let uri = URI.parse('sc:hightower');
|
||||
collection.set([
|
||||
[uri, [new Diagnostic(new Range(0, 0, 0, 1), 'message-1')]],
|
||||
[URI.parse('some:thing'), [new Diagnostic(new Range(0, 0, 1, 1), 'something')]],
|
||||
[uri, [new Diagnostic(new Range(0, 0, 0, 1), 'message-2')]],
|
||||
]);
|
||||
|
||||
let array = collection.get(uri);
|
||||
assert.strictEqual(array.length, 2);
|
||||
let [first, second] = array;
|
||||
assert.strictEqual(first.message, 'message-1');
|
||||
assert.strictEqual(second.message, 'message-2');
|
||||
|
||||
// clear
|
||||
collection.delete(uri);
|
||||
assert.ok(!collection.has(uri));
|
||||
|
||||
// bad tuple clears 1/2
|
||||
collection.set([
|
||||
[uri, [new Diagnostic(new Range(0, 0, 0, 1), 'message-1')]],
|
||||
[URI.parse('some:thing'), [new Diagnostic(new Range(0, 0, 1, 1), 'something')]],
|
||||
[uri, undefined!]
|
||||
]);
|
||||
assert.ok(!collection.has(uri));
|
||||
|
||||
// clear
|
||||
collection.delete(uri);
|
||||
assert.ok(!collection.has(uri));
|
||||
|
||||
// bad tuple clears 2/2
|
||||
collection.set([
|
||||
[uri, [new Diagnostic(new Range(0, 0, 0, 1), 'message-1')]],
|
||||
[URI.parse('some:thing'), [new Diagnostic(new Range(0, 0, 1, 1), 'something')]],
|
||||
[uri, undefined!],
|
||||
[uri, [new Diagnostic(new Range(0, 0, 0, 1), 'message-2')]],
|
||||
[uri, [new Diagnostic(new Range(0, 0, 0, 1), 'message-3')]],
|
||||
]);
|
||||
|
||||
array = collection.get(uri);
|
||||
assert.strictEqual(array.length, 2);
|
||||
[first, second] = array;
|
||||
assert.strictEqual(first.message, 'message-2');
|
||||
assert.strictEqual(second.message, 'message-3');
|
||||
|
||||
collection.dispose();
|
||||
});
|
||||
|
||||
test('diagnostics collection, set tuple overrides, #11547', function () {
|
||||
|
||||
let lastEntries!: [UriComponents, IMarkerData[]][];
|
||||
let collection = new DiagnosticCollection('test', 'test', 100, extUri, new class extends DiagnosticsShape {
|
||||
override $changeMany(owner: string, entries: [UriComponents, IMarkerData[]][]): void {
|
||||
lastEntries = entries;
|
||||
return super.$changeMany(owner, entries);
|
||||
}
|
||||
}, new Emitter());
|
||||
let uri = URI.parse('sc:hightower');
|
||||
|
||||
collection.set([[uri, [new Diagnostic(new Range(0, 0, 1, 1), 'error')]]]);
|
||||
assert.strictEqual(collection.get(uri).length, 1);
|
||||
assert.strictEqual(collection.get(uri)[0].message, 'error');
|
||||
assert.strictEqual(lastEntries.length, 1);
|
||||
let [[, data1]] = lastEntries;
|
||||
assert.strictEqual(data1.length, 1);
|
||||
assert.strictEqual(data1[0].message, 'error');
|
||||
lastEntries = undefined!;
|
||||
|
||||
collection.set([[uri, [new Diagnostic(new Range(0, 0, 1, 1), 'warning')]]]);
|
||||
assert.strictEqual(collection.get(uri).length, 1);
|
||||
assert.strictEqual(collection.get(uri)[0].message, 'warning');
|
||||
assert.strictEqual(lastEntries.length, 1);
|
||||
let [[, data2]] = lastEntries;
|
||||
assert.strictEqual(data2.length, 1);
|
||||
assert.strictEqual(data2[0].message, 'warning');
|
||||
lastEntries = undefined!;
|
||||
});
|
||||
|
||||
test('do send message when not making a change', function () {
|
||||
|
||||
let changeCount = 0;
|
||||
let eventCount = 0;
|
||||
|
||||
const emitter = new Emitter<any>();
|
||||
emitter.event(_ => eventCount += 1);
|
||||
const collection = new DiagnosticCollection('test', 'test', 100, extUri, new class extends DiagnosticsShape {
|
||||
override $changeMany() {
|
||||
changeCount += 1;
|
||||
}
|
||||
}, emitter);
|
||||
|
||||
let uri = URI.parse('sc:hightower');
|
||||
let diag = new Diagnostic(new Range(0, 0, 0, 1), 'ffff');
|
||||
|
||||
collection.set(uri, [diag]);
|
||||
assert.strictEqual(changeCount, 1);
|
||||
assert.strictEqual(eventCount, 1);
|
||||
|
||||
collection.set(uri, [diag]);
|
||||
assert.strictEqual(changeCount, 2);
|
||||
assert.strictEqual(eventCount, 2);
|
||||
});
|
||||
|
||||
test('diagnostics collection, tuples and undefined (small array), #15585', function () {
|
||||
|
||||
const collection = new DiagnosticCollection('test', 'test', 100, extUri, new DiagnosticsShape(), new Emitter());
|
||||
let uri = URI.parse('sc:hightower');
|
||||
let uri2 = URI.parse('sc:nomad');
|
||||
let diag = new Diagnostic(new Range(0, 0, 0, 1), 'ffff');
|
||||
|
||||
collection.set([
|
||||
[uri, [diag, diag, diag]],
|
||||
[uri, undefined!],
|
||||
[uri, [diag]],
|
||||
|
||||
[uri2, [diag, diag]],
|
||||
[uri2, undefined!],
|
||||
[uri2, [diag]],
|
||||
]);
|
||||
|
||||
assert.strictEqual(collection.get(uri).length, 1);
|
||||
assert.strictEqual(collection.get(uri2).length, 1);
|
||||
});
|
||||
|
||||
test('diagnostics collection, tuples and undefined (large array), #15585', function () {
|
||||
|
||||
const collection = new DiagnosticCollection('test', 'test', 100, extUri, new DiagnosticsShape(), new Emitter());
|
||||
const tuples: [URI, Diagnostic[]][] = [];
|
||||
|
||||
for (let i = 0; i < 500; i++) {
|
||||
let uri = URI.parse('sc:hightower#' + i);
|
||||
let diag = new Diagnostic(new Range(0, 0, 0, 1), i.toString());
|
||||
|
||||
tuples.push([uri, [diag, diag, diag]]);
|
||||
tuples.push([uri, undefined!]);
|
||||
tuples.push([uri, [diag]]);
|
||||
}
|
||||
|
||||
collection.set(tuples);
|
||||
|
||||
for (let i = 0; i < 500; i++) {
|
||||
let uri = URI.parse('sc:hightower#' + i);
|
||||
assert.strictEqual(collection.has(uri), true);
|
||||
assert.strictEqual(collection.get(uri).length, 1);
|
||||
}
|
||||
});
|
||||
|
||||
test('diagnostic capping', function () {
|
||||
|
||||
let lastEntries!: [UriComponents, IMarkerData[]][];
|
||||
let collection = new DiagnosticCollection('test', 'test', 250, extUri, new class extends DiagnosticsShape {
|
||||
override $changeMany(owner: string, entries: [UriComponents, IMarkerData[]][]): void {
|
||||
lastEntries = entries;
|
||||
return super.$changeMany(owner, entries);
|
||||
}
|
||||
}, new Emitter());
|
||||
let uri = URI.parse('aa:bb');
|
||||
|
||||
let diagnostics: Diagnostic[] = [];
|
||||
for (let i = 0; i < 500; i++) {
|
||||
diagnostics.push(new Diagnostic(new Range(i, 0, i + 1, 0), `error#${i}`, i < 300
|
||||
? DiagnosticSeverity.Warning
|
||||
: DiagnosticSeverity.Error));
|
||||
}
|
||||
|
||||
collection.set(uri, diagnostics);
|
||||
assert.strictEqual(collection.get(uri).length, 500);
|
||||
assert.strictEqual(lastEntries.length, 1);
|
||||
assert.strictEqual(lastEntries[0][1].length, 251);
|
||||
assert.strictEqual(lastEntries[0][1][0].severity, MarkerSeverity.Error);
|
||||
assert.strictEqual(lastEntries[0][1][200].severity, MarkerSeverity.Warning);
|
||||
assert.strictEqual(lastEntries[0][1][250].severity, MarkerSeverity.Info);
|
||||
});
|
||||
|
||||
test('diagnostic eventing', async function () {
|
||||
let emitter = new Emitter<Array<URI>>();
|
||||
let collection = new DiagnosticCollection('ddd', 'test', 100, extUri, new DiagnosticsShape(), emitter);
|
||||
|
||||
let diag1 = new Diagnostic(new Range(1, 1, 2, 3), 'diag1');
|
||||
let diag2 = new Diagnostic(new Range(1, 1, 2, 3), 'diag2');
|
||||
let diag3 = new Diagnostic(new Range(1, 1, 2, 3), 'diag3');
|
||||
|
||||
let p = Event.toPromise(emitter.event).then(a => {
|
||||
assert.strictEqual(a.length, 1);
|
||||
assert.strictEqual(a[0].toString(), 'aa:bb');
|
||||
assert.ok(URI.isUri(a[0]));
|
||||
});
|
||||
collection.set(URI.parse('aa:bb'), []);
|
||||
await p;
|
||||
|
||||
p = Event.toPromise(emitter.event).then(e => {
|
||||
assert.strictEqual(e.length, 2);
|
||||
assert.ok(URI.isUri(e[0]));
|
||||
assert.ok(URI.isUri(e[1]));
|
||||
assert.strictEqual(e[0].toString(), 'aa:bb');
|
||||
assert.strictEqual(e[1].toString(), 'aa:cc');
|
||||
});
|
||||
collection.set([
|
||||
[URI.parse('aa:bb'), [diag1]],
|
||||
[URI.parse('aa:cc'), [diag2, diag3]],
|
||||
]);
|
||||
await p;
|
||||
|
||||
p = Event.toPromise(emitter.event).then(e => {
|
||||
assert.strictEqual(e.length, 2);
|
||||
assert.ok(URI.isUri(e[0]));
|
||||
assert.ok(URI.isUri(e[1]));
|
||||
});
|
||||
collection.clear();
|
||||
await p;
|
||||
});
|
||||
|
||||
test('vscode.languages.onDidChangeDiagnostics Does Not Provide Document URI #49582', async function () {
|
||||
let emitter = new Emitter<Array<URI>>();
|
||||
let collection = new DiagnosticCollection('ddd', 'test', 100, extUri, new DiagnosticsShape(), emitter);
|
||||
|
||||
let diag1 = new Diagnostic(new Range(1, 1, 2, 3), 'diag1');
|
||||
|
||||
// delete
|
||||
collection.set(URI.parse('aa:bb'), [diag1]);
|
||||
let p = Event.toPromise(emitter.event).then(e => {
|
||||
assert.strictEqual(e[0].toString(), 'aa:bb');
|
||||
});
|
||||
collection.delete(URI.parse('aa:bb'));
|
||||
await p;
|
||||
|
||||
// set->undefined (as delete)
|
||||
collection.set(URI.parse('aa:bb'), [diag1]);
|
||||
p = Event.toPromise(emitter.event).then(e => {
|
||||
assert.strictEqual(e[0].toString(), 'aa:bb');
|
||||
});
|
||||
collection.set(URI.parse('aa:bb'), undefined!);
|
||||
await p;
|
||||
});
|
||||
|
||||
test('diagnostics with related information', function (done) {
|
||||
|
||||
let collection = new DiagnosticCollection('ddd', 'test', 100, extUri, new class extends DiagnosticsShape {
|
||||
override $changeMany(owner: string, entries: [UriComponents, IMarkerData[]][]) {
|
||||
|
||||
let [[, data]] = entries;
|
||||
assert.strictEqual(entries.length, 1);
|
||||
assert.strictEqual(data.length, 1);
|
||||
|
||||
let [diag] = data;
|
||||
assert.strictEqual(diag.relatedInformation!.length, 2);
|
||||
assert.strictEqual(diag.relatedInformation![0].message, 'more1');
|
||||
assert.strictEqual(diag.relatedInformation![1].message, 'more2');
|
||||
done();
|
||||
}
|
||||
}, new Emitter<any>());
|
||||
|
||||
let diag = new Diagnostic(new Range(0, 0, 1, 1), 'Foo');
|
||||
diag.relatedInformation = [
|
||||
new DiagnosticRelatedInformation(new Location(URI.parse('cc:dd'), new Range(0, 0, 0, 0)), 'more1'),
|
||||
new DiagnosticRelatedInformation(new Location(URI.parse('cc:ee'), new Range(0, 0, 0, 0)), 'more2')
|
||||
];
|
||||
|
||||
collection.set(URI.parse('aa:bb'), [diag]);
|
||||
});
|
||||
|
||||
test('vscode.languages.getDiagnostics appears to return old diagnostics in some circumstances #54359', function () {
|
||||
const ownerHistory: string[] = [];
|
||||
const diags = new ExtHostDiagnostics(new class implements IMainContext {
|
||||
getProxy(id: any): any {
|
||||
return new class DiagnosticsShape {
|
||||
$clear(owner: string): void {
|
||||
ownerHistory.push(owner);
|
||||
}
|
||||
};
|
||||
}
|
||||
set(): any {
|
||||
return null;
|
||||
}
|
||||
assertRegistered(): void {
|
||||
|
||||
}
|
||||
drain() {
|
||||
return undefined!;
|
||||
}
|
||||
}, new NullLogService(), fileSystemInfoService);
|
||||
|
||||
let collection1 = diags.createDiagnosticCollection(nullExtensionDescription.identifier, 'foo');
|
||||
let collection2 = diags.createDiagnosticCollection(nullExtensionDescription.identifier, 'foo'); // warns, uses a different owner
|
||||
|
||||
collection1.clear();
|
||||
collection2.clear();
|
||||
|
||||
assert.strictEqual(ownerHistory.length, 2);
|
||||
assert.strictEqual(ownerHistory[0], 'foo');
|
||||
assert.strictEqual(ownerHistory[1], 'foo0');
|
||||
});
|
||||
|
||||
test('Error updating diagnostics from extension #60394', function () {
|
||||
let callCount = 0;
|
||||
let collection = new DiagnosticCollection('ddd', 'test', 100, extUri, new class extends DiagnosticsShape {
|
||||
override $changeMany(owner: string, entries: [UriComponents, IMarkerData[]][]) {
|
||||
callCount += 1;
|
||||
}
|
||||
}, new Emitter<any>());
|
||||
|
||||
let array: Diagnostic[] = [];
|
||||
let diag1 = new Diagnostic(new Range(0, 0, 1, 1), 'Foo');
|
||||
let diag2 = new Diagnostic(new Range(0, 0, 1, 1), 'Bar');
|
||||
|
||||
array.push(diag1, diag2);
|
||||
|
||||
collection.set(URI.parse('test:me'), array);
|
||||
assert.strictEqual(callCount, 1);
|
||||
|
||||
collection.set(URI.parse('test:me'), array);
|
||||
assert.strictEqual(callCount, 2); // equal array
|
||||
|
||||
array.push(diag2);
|
||||
collection.set(URI.parse('test:me'), array);
|
||||
assert.strictEqual(callCount, 3); // same but un-equal array
|
||||
});
|
||||
|
||||
test('Diagnostics created by tasks aren\'t accessible to extensions #47292', async function () {
|
||||
const diags = new ExtHostDiagnostics(new class implements IMainContext {
|
||||
getProxy(id: any): any {
|
||||
return {};
|
||||
}
|
||||
set(): any {
|
||||
return null;
|
||||
}
|
||||
assertRegistered(): void {
|
||||
|
||||
}
|
||||
drain() {
|
||||
return undefined!;
|
||||
}
|
||||
}, new NullLogService(), fileSystemInfoService);
|
||||
|
||||
|
||||
//
|
||||
const uri = URI.parse('foo:bar');
|
||||
const data: IMarkerData[] = [{
|
||||
message: 'message',
|
||||
startLineNumber: 1,
|
||||
startColumn: 1,
|
||||
endLineNumber: 1,
|
||||
endColumn: 1,
|
||||
severity: 3
|
||||
}];
|
||||
|
||||
const p1 = Event.toPromise(diags.onDidChangeDiagnostics);
|
||||
diags.$acceptMarkersChange([[uri, data]]);
|
||||
await p1;
|
||||
assert.strictEqual(diags.getDiagnostics(uri).length, 1);
|
||||
|
||||
const p2 = Event.toPromise(diags.onDidChangeDiagnostics);
|
||||
diags.$acceptMarkersChange([[uri, []]]);
|
||||
await p2;
|
||||
assert.strictEqual(diags.getDiagnostics(uri).length, 0);
|
||||
});
|
||||
|
||||
test('languages.getDiagnostics doesn\'t handle case insensitivity correctly #128198', function () {
|
||||
|
||||
const diags = new ExtHostDiagnostics(new class implements IMainContext {
|
||||
getProxy(id: any): any {
|
||||
return new DiagnosticsShape();
|
||||
}
|
||||
set(): any {
|
||||
return null;
|
||||
}
|
||||
assertRegistered(): void {
|
||||
|
||||
}
|
||||
drain() {
|
||||
return undefined!;
|
||||
}
|
||||
}, new NullLogService(), new class extends mock<IExtHostFileSystemInfo>() {
|
||||
|
||||
override readonly extUri = new ExtUri(uri => uri.scheme === 'insensitive');
|
||||
});
|
||||
|
||||
const col = diags.createDiagnosticCollection(nullExtensionDescription.identifier);
|
||||
|
||||
const uriSensitive = URI.from({ scheme: 'foo', path: '/SOME/path' });
|
||||
const uriSensitiveCaseB = uriSensitive.with({ path: uriSensitive.path.toUpperCase() });
|
||||
|
||||
const uriInSensitive = URI.from({ scheme: 'insensitive', path: '/SOME/path' });
|
||||
const uriInSensitiveUpper = uriInSensitive.with({ path: uriInSensitive.path.toUpperCase() });
|
||||
|
||||
col.set(uriSensitive, [new Diagnostic(new Range(0, 0, 0, 0), 'sensitive')]);
|
||||
col.set(uriInSensitive, [new Diagnostic(new Range(0, 0, 0, 0), 'insensitive')]);
|
||||
|
||||
// collection itself honours casing
|
||||
assert.strictEqual(col.get(uriSensitive)?.length, 1);
|
||||
assert.strictEqual(col.get(uriSensitiveCaseB)?.length, 0);
|
||||
|
||||
assert.strictEqual(col.get(uriInSensitive)?.length, 1);
|
||||
assert.strictEqual(col.get(uriInSensitiveUpper)?.length, 1);
|
||||
|
||||
// languages.getDiagnostics honours casing
|
||||
assert.strictEqual(diags.getDiagnostics(uriSensitive)?.length, 1);
|
||||
assert.strictEqual(diags.getDiagnostics(uriSensitiveCaseB)?.length, 0);
|
||||
|
||||
assert.strictEqual(diags.getDiagnostics(uriInSensitive)?.length, 1);
|
||||
assert.strictEqual(diags.getDiagnostics(uriInSensitiveUpper)?.length, 1);
|
||||
|
||||
|
||||
const fromForEach: URI[] = [];
|
||||
col.forEach(uri => fromForEach.push(uri));
|
||||
assert.strictEqual(fromForEach.length, 2);
|
||||
assert.strictEqual(fromForEach[0].toString(), uriSensitive.toString());
|
||||
assert.strictEqual(fromForEach[1].toString(), uriInSensitive.toString());
|
||||
});
|
||||
});
|
||||
File diff suppressed because one or more lines are too long
@@ -1,530 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 } from 'vs/base/common/uri';
|
||||
import { ExtHostDocumentData } from 'vs/workbench/api/common/extHostDocumentData';
|
||||
import { Position } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { MainThreadDocumentsShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { IModelChangedEvent } from 'vs/editor/common/model/mirrorTextModel';
|
||||
import { mock } from 'vs/base/test/common/mock';
|
||||
import * as perfData from './extHostDocumentData.test.perf-data';
|
||||
|
||||
suite('ExtHostDocumentData', () => {
|
||||
|
||||
let data: ExtHostDocumentData;
|
||||
|
||||
function assertPositionAt(offset: number, line: number, character: number) {
|
||||
let position = data.document.positionAt(offset);
|
||||
assert.strictEqual(position.line, line);
|
||||
assert.strictEqual(position.character, character);
|
||||
}
|
||||
|
||||
function assertOffsetAt(line: number, character: number, offset: number) {
|
||||
let pos = new Position(line, character);
|
||||
let actual = data.document.offsetAt(pos);
|
||||
assert.strictEqual(actual, offset);
|
||||
}
|
||||
|
||||
setup(function () {
|
||||
data = new ExtHostDocumentData(undefined!, URI.file(''), [
|
||||
'This is line one', //16
|
||||
'and this is line number two', //27
|
||||
'it is followed by #3', //20
|
||||
'and finished with the fourth.', //29
|
||||
], '\n', 1, 'text', false);
|
||||
});
|
||||
|
||||
test('readonly-ness', () => {
|
||||
assert.throws(() => (data as any).document.uri = null);
|
||||
assert.throws(() => (data as any).document.fileName = 'foofile');
|
||||
assert.throws(() => (data as any).document.isDirty = false);
|
||||
assert.throws(() => (data as any).document.isUntitled = false);
|
||||
assert.throws(() => (data as any).document.languageId = 'dddd');
|
||||
assert.throws(() => (data as any).document.lineCount = 9);
|
||||
});
|
||||
|
||||
test('save, when disposed', function () {
|
||||
let saved: URI;
|
||||
let data = new ExtHostDocumentData(new class extends mock<MainThreadDocumentsShape>() {
|
||||
override $trySaveDocument(uri: URI) {
|
||||
assert.ok(!saved);
|
||||
saved = uri;
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
}, URI.parse('foo:bar'), [], '\n', 1, 'text', true);
|
||||
|
||||
return data.document.save().then(() => {
|
||||
assert.strictEqual(saved.toString(), 'foo:bar');
|
||||
|
||||
data.dispose();
|
||||
|
||||
return data.document.save().then(() => {
|
||||
assert.ok(false, 'expected failure');
|
||||
}, err => {
|
||||
assert.ok(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('read, when disposed', function () {
|
||||
data.dispose();
|
||||
|
||||
const { document } = data;
|
||||
assert.strictEqual(document.lineCount, 4);
|
||||
assert.strictEqual(document.lineAt(0).text, 'This is line one');
|
||||
});
|
||||
|
||||
test('lines', () => {
|
||||
|
||||
assert.strictEqual(data.document.lineCount, 4);
|
||||
|
||||
assert.throws(() => data.document.lineAt(-1));
|
||||
assert.throws(() => data.document.lineAt(data.document.lineCount));
|
||||
assert.throws(() => data.document.lineAt(Number.MAX_VALUE));
|
||||
assert.throws(() => data.document.lineAt(Number.MIN_VALUE));
|
||||
assert.throws(() => data.document.lineAt(0.8));
|
||||
|
||||
let line = data.document.lineAt(0);
|
||||
assert.strictEqual(line.lineNumber, 0);
|
||||
assert.strictEqual(line.text.length, 16);
|
||||
assert.strictEqual(line.text, 'This is line one');
|
||||
assert.strictEqual(line.isEmptyOrWhitespace, false);
|
||||
assert.strictEqual(line.firstNonWhitespaceCharacterIndex, 0);
|
||||
|
||||
data.onEvents({
|
||||
changes: [{
|
||||
range: { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 },
|
||||
rangeOffset: undefined!,
|
||||
rangeLength: undefined!,
|
||||
text: '\t '
|
||||
}],
|
||||
eol: undefined!,
|
||||
versionId: undefined!,
|
||||
isRedoing: false,
|
||||
isUndoing: false,
|
||||
});
|
||||
|
||||
// line didn't change
|
||||
assert.strictEqual(line.text, 'This is line one');
|
||||
assert.strictEqual(line.firstNonWhitespaceCharacterIndex, 0);
|
||||
|
||||
// fetch line again
|
||||
line = data.document.lineAt(0);
|
||||
assert.strictEqual(line.text, '\t This is line one');
|
||||
assert.strictEqual(line.firstNonWhitespaceCharacterIndex, 2);
|
||||
});
|
||||
|
||||
test('line, issue #5704', function () {
|
||||
|
||||
let line = data.document.lineAt(0);
|
||||
let { range, rangeIncludingLineBreak } = line;
|
||||
assert.strictEqual(range.end.line, 0);
|
||||
assert.strictEqual(range.end.character, 16);
|
||||
assert.strictEqual(rangeIncludingLineBreak.end.line, 1);
|
||||
assert.strictEqual(rangeIncludingLineBreak.end.character, 0);
|
||||
|
||||
line = data.document.lineAt(data.document.lineCount - 1);
|
||||
range = line.range;
|
||||
rangeIncludingLineBreak = line.rangeIncludingLineBreak;
|
||||
assert.strictEqual(range.end.line, 3);
|
||||
assert.strictEqual(range.end.character, 29);
|
||||
assert.strictEqual(rangeIncludingLineBreak.end.line, 3);
|
||||
assert.strictEqual(rangeIncludingLineBreak.end.character, 29);
|
||||
|
||||
});
|
||||
|
||||
test('offsetAt', () => {
|
||||
assertOffsetAt(0, 0, 0);
|
||||
assertOffsetAt(0, 1, 1);
|
||||
assertOffsetAt(0, 16, 16);
|
||||
assertOffsetAt(1, 0, 17);
|
||||
assertOffsetAt(1, 3, 20);
|
||||
assertOffsetAt(2, 0, 45);
|
||||
assertOffsetAt(4, 29, 95);
|
||||
assertOffsetAt(4, 30, 95);
|
||||
assertOffsetAt(4, Number.MAX_VALUE, 95);
|
||||
assertOffsetAt(5, 29, 95);
|
||||
assertOffsetAt(Number.MAX_VALUE, 29, 95);
|
||||
assertOffsetAt(Number.MAX_VALUE, Number.MAX_VALUE, 95);
|
||||
});
|
||||
|
||||
test('offsetAt, after remove', function () {
|
||||
|
||||
data.onEvents({
|
||||
changes: [{
|
||||
range: { startLineNumber: 1, startColumn: 3, endLineNumber: 1, endColumn: 6 },
|
||||
rangeOffset: undefined!,
|
||||
rangeLength: undefined!,
|
||||
text: ''
|
||||
}],
|
||||
eol: undefined!,
|
||||
versionId: undefined!,
|
||||
isRedoing: false,
|
||||
isUndoing: false,
|
||||
});
|
||||
|
||||
assertOffsetAt(0, 1, 1);
|
||||
assertOffsetAt(0, 13, 13);
|
||||
assertOffsetAt(1, 0, 14);
|
||||
});
|
||||
|
||||
test('offsetAt, after replace', function () {
|
||||
|
||||
data.onEvents({
|
||||
changes: [{
|
||||
range: { startLineNumber: 1, startColumn: 3, endLineNumber: 1, endColumn: 6 },
|
||||
rangeOffset: undefined!,
|
||||
rangeLength: undefined!,
|
||||
text: 'is could be'
|
||||
}],
|
||||
eol: undefined!,
|
||||
versionId: undefined!,
|
||||
isRedoing: false,
|
||||
isUndoing: false,
|
||||
});
|
||||
|
||||
assertOffsetAt(0, 1, 1);
|
||||
assertOffsetAt(0, 24, 24);
|
||||
assertOffsetAt(1, 0, 25);
|
||||
});
|
||||
|
||||
test('offsetAt, after insert line', function () {
|
||||
|
||||
data.onEvents({
|
||||
changes: [{
|
||||
range: { startLineNumber: 1, startColumn: 3, endLineNumber: 1, endColumn: 6 },
|
||||
rangeOffset: undefined!,
|
||||
rangeLength: undefined!,
|
||||
text: 'is could be\na line with number'
|
||||
}],
|
||||
eol: undefined!,
|
||||
versionId: undefined!,
|
||||
isRedoing: false,
|
||||
isUndoing: false,
|
||||
});
|
||||
|
||||
assertOffsetAt(0, 1, 1);
|
||||
assertOffsetAt(0, 13, 13);
|
||||
assertOffsetAt(1, 0, 14);
|
||||
assertOffsetAt(1, 18, 13 + 1 + 18);
|
||||
assertOffsetAt(1, 29, 13 + 1 + 29);
|
||||
assertOffsetAt(2, 0, 13 + 1 + 29 + 1);
|
||||
});
|
||||
|
||||
test('offsetAt, after remove line', function () {
|
||||
|
||||
data.onEvents({
|
||||
changes: [{
|
||||
range: { startLineNumber: 1, startColumn: 3, endLineNumber: 2, endColumn: 6 },
|
||||
rangeOffset: undefined!,
|
||||
rangeLength: undefined!,
|
||||
text: ''
|
||||
}],
|
||||
eol: undefined!,
|
||||
versionId: undefined!,
|
||||
isRedoing: false,
|
||||
isUndoing: false,
|
||||
});
|
||||
|
||||
assertOffsetAt(0, 1, 1);
|
||||
assertOffsetAt(0, 2, 2);
|
||||
assertOffsetAt(1, 0, 25);
|
||||
});
|
||||
|
||||
test('positionAt', () => {
|
||||
assertPositionAt(0, 0, 0);
|
||||
assertPositionAt(Number.MIN_VALUE, 0, 0);
|
||||
assertPositionAt(1, 0, 1);
|
||||
assertPositionAt(16, 0, 16);
|
||||
assertPositionAt(17, 1, 0);
|
||||
assertPositionAt(20, 1, 3);
|
||||
assertPositionAt(45, 2, 0);
|
||||
assertPositionAt(95, 3, 29);
|
||||
assertPositionAt(96, 3, 29);
|
||||
assertPositionAt(99, 3, 29);
|
||||
assertPositionAt(Number.MAX_VALUE, 3, 29);
|
||||
});
|
||||
|
||||
test('getWordRangeAtPosition', () => {
|
||||
data = new ExtHostDocumentData(undefined!, URI.file(''), [
|
||||
'aaaa bbbb+cccc abc'
|
||||
], '\n', 1, 'text', false);
|
||||
|
||||
let range = data.document.getWordRangeAtPosition(new Position(0, 2))!;
|
||||
assert.strictEqual(range.start.line, 0);
|
||||
assert.strictEqual(range.start.character, 0);
|
||||
assert.strictEqual(range.end.line, 0);
|
||||
assert.strictEqual(range.end.character, 4);
|
||||
|
||||
// ignore bad regular expresson /.*/
|
||||
assert.throws(() => data.document.getWordRangeAtPosition(new Position(0, 2), /.*/)!);
|
||||
|
||||
range = data.document.getWordRangeAtPosition(new Position(0, 5), /[a-z+]+/)!;
|
||||
assert.strictEqual(range.start.line, 0);
|
||||
assert.strictEqual(range.start.character, 5);
|
||||
assert.strictEqual(range.end.line, 0);
|
||||
assert.strictEqual(range.end.character, 14);
|
||||
|
||||
range = data.document.getWordRangeAtPosition(new Position(0, 17), /[a-z+]+/)!;
|
||||
assert.strictEqual(range.start.line, 0);
|
||||
assert.strictEqual(range.start.character, 15);
|
||||
assert.strictEqual(range.end.line, 0);
|
||||
assert.strictEqual(range.end.character, 18);
|
||||
|
||||
range = data.document.getWordRangeAtPosition(new Position(0, 11), /yy/)!;
|
||||
assert.strictEqual(range, undefined);
|
||||
});
|
||||
|
||||
test('getWordRangeAtPosition doesn\'t quite use the regex as expected, #29102', function () {
|
||||
data = new ExtHostDocumentData(undefined!, URI.file(''), [
|
||||
'some text here',
|
||||
'/** foo bar */',
|
||||
'function() {',
|
||||
' "far boo"',
|
||||
'}'
|
||||
], '\n', 1, 'text', false);
|
||||
|
||||
let range = data.document.getWordRangeAtPosition(new Position(0, 0), /\/\*.+\*\//);
|
||||
assert.strictEqual(range, undefined);
|
||||
|
||||
range = data.document.getWordRangeAtPosition(new Position(1, 0), /\/\*.+\*\//)!;
|
||||
assert.strictEqual(range.start.line, 1);
|
||||
assert.strictEqual(range.start.character, 0);
|
||||
assert.strictEqual(range.end.line, 1);
|
||||
assert.strictEqual(range.end.character, 14);
|
||||
|
||||
range = data.document.getWordRangeAtPosition(new Position(3, 0), /("|').*\1/);
|
||||
assert.strictEqual(range, undefined);
|
||||
|
||||
range = data.document.getWordRangeAtPosition(new Position(3, 1), /("|').*\1/)!;
|
||||
assert.strictEqual(range.start.line, 3);
|
||||
assert.strictEqual(range.start.character, 1);
|
||||
assert.strictEqual(range.end.line, 3);
|
||||
assert.strictEqual(range.end.character, 10);
|
||||
});
|
||||
|
||||
|
||||
test('getWordRangeAtPosition can freeze the extension host #95319', function () {
|
||||
|
||||
const regex = /(https?:\/\/github\.com\/(([^\s]+)\/([^\s]+))\/([^\s]+\/)?(issues|pull)\/([0-9]+))|(([^\s]+)\/([^\s]+))?#([1-9][0-9]*)($|[\s\:\;\-\(\=])/;
|
||||
|
||||
data = new ExtHostDocumentData(undefined!, URI.file(''), [
|
||||
perfData._$_$_expensive
|
||||
], '\n', 1, 'text', false);
|
||||
|
||||
let range = data.document.getWordRangeAtPosition(new Position(0, 1_177_170), regex)!;
|
||||
assert.strictEqual(range, undefined);
|
||||
|
||||
const pos = new Position(0, 1177170);
|
||||
range = data.document.getWordRangeAtPosition(pos)!;
|
||||
assert.ok(range);
|
||||
assert.ok(range.contains(pos));
|
||||
assert.strictEqual(data.document.getText(range), 'TaskDefinition');
|
||||
});
|
||||
|
||||
test('Rename popup sometimes populates with text on the left side omitted #96013', function () {
|
||||
|
||||
const regex = /(-?\d*\.\d\w*)|([^\`\~\!\@\#\$\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g;
|
||||
const line = 'int abcdefhijklmnopqwvrstxyz;';
|
||||
|
||||
data = new ExtHostDocumentData(undefined!, URI.file(''), [
|
||||
line
|
||||
], '\n', 1, 'text', false);
|
||||
|
||||
let range = data.document.getWordRangeAtPosition(new Position(0, 27), regex)!;
|
||||
assert.strictEqual(range.start.line, 0);
|
||||
assert.strictEqual(range.end.line, 0);
|
||||
assert.strictEqual(range.start.character, 4);
|
||||
assert.strictEqual(range.end.character, 28);
|
||||
});
|
||||
|
||||
test('Custom snippet $TM_SELECTED_TEXT not show suggestion #108892', function () {
|
||||
|
||||
data = new ExtHostDocumentData(undefined!, URI.file(''), [
|
||||
` <p><span xml:lang="en">Sheldon</span>, soprannominato "<span xml:lang="en">Shelly</span> dalla madre e dalla sorella, è nato a <span xml:lang="en">Galveston</span>, in <span xml:lang="en">Texas</span>, il 26 febbraio 1980 in un supermercato. È stato un bambino prodigio, come testimoniato dal suo quoziente d'intelligenza (187, di molto superiore alla norma) e dalla sua rapida carriera scolastica: si è diplomato all'eta di 11 anni approdando alla stessa età alla formazione universitaria e all'età di 16 anni ha ottenuto il suo primo dottorato di ricerca. All'inizio della serie e per gran parte di essa vive con il coinquilino Leonard nell'appartamento 4A al 2311 <span xml:lang="en">North Los Robles Avenue</span> di <span xml:lang="en">Pasadena</span>, per poi trasferirsi nell'appartamento di <span xml:lang="en">Penny</span> con <span xml:lang="en">Amy</span> nella decima stagione. Come più volte afferma lui stesso possiede una memoria eidetica e un orecchio assoluto. È stato educato da una madre estremamente religiosa e, in più occasioni, questo aspetto contrasta con il rigore scientifico di <span xml:lang="en">Sheldon</span>; tuttavia la donna sembra essere l'unica persona in grado di comandarlo a bacchetta.</p>`
|
||||
], '\n', 1, 'text', false);
|
||||
|
||||
const pos = new Position(0, 55);
|
||||
const range = data.document.getWordRangeAtPosition(pos)!;
|
||||
assert.strictEqual(range.start.line, 0);
|
||||
assert.strictEqual(range.end.line, 0);
|
||||
assert.strictEqual(range.start.character, 47);
|
||||
assert.strictEqual(range.end.character, 61);
|
||||
assert.strictEqual(data.document.getText(range), 'soprannominato');
|
||||
});
|
||||
});
|
||||
|
||||
enum AssertDocumentLineMappingDirection {
|
||||
OffsetToPosition,
|
||||
PositionToOffset
|
||||
}
|
||||
|
||||
suite('ExtHostDocumentData updates line mapping', () => {
|
||||
|
||||
function positionToStr(position: { line: number; character: number; }): string {
|
||||
return '(' + position.line + ',' + position.character + ')';
|
||||
}
|
||||
|
||||
function assertDocumentLineMapping(doc: ExtHostDocumentData, direction: AssertDocumentLineMappingDirection): void {
|
||||
let allText = doc.getText();
|
||||
|
||||
let line = 0, character = 0, previousIsCarriageReturn = false;
|
||||
for (let offset = 0; offset <= allText.length; offset++) {
|
||||
// The position coordinate system cannot express the position between \r and \n
|
||||
const position: Position = new Position(line, character + (previousIsCarriageReturn ? -1 : 0));
|
||||
|
||||
if (direction === AssertDocumentLineMappingDirection.OffsetToPosition) {
|
||||
let actualPosition = doc.document.positionAt(offset);
|
||||
assert.strictEqual(positionToStr(actualPosition), positionToStr(position), 'positionAt mismatch for offset ' + offset);
|
||||
} else {
|
||||
// The position coordinate system cannot express the position between \r and \n
|
||||
let expectedOffset: number = offset + (previousIsCarriageReturn ? -1 : 0);
|
||||
let actualOffset = doc.document.offsetAt(position);
|
||||
assert.strictEqual(actualOffset, expectedOffset, 'offsetAt mismatch for position ' + positionToStr(position));
|
||||
}
|
||||
|
||||
if (allText.charAt(offset) === '\n') {
|
||||
line++;
|
||||
character = 0;
|
||||
} else {
|
||||
character++;
|
||||
}
|
||||
|
||||
previousIsCarriageReturn = (allText.charAt(offset) === '\r');
|
||||
}
|
||||
}
|
||||
|
||||
function createChangeEvent(range: Range, text: string, eol?: string): IModelChangedEvent {
|
||||
return {
|
||||
changes: [{
|
||||
range: range,
|
||||
rangeOffset: undefined!,
|
||||
rangeLength: undefined!,
|
||||
text: text
|
||||
}],
|
||||
eol: eol!,
|
||||
versionId: undefined!,
|
||||
isRedoing: false,
|
||||
isUndoing: false,
|
||||
};
|
||||
}
|
||||
|
||||
function testLineMappingDirectionAfterEvents(lines: string[], eol: string, direction: AssertDocumentLineMappingDirection, e: IModelChangedEvent): void {
|
||||
let myDocument = new ExtHostDocumentData(undefined!, URI.file(''), lines.slice(0), eol, 1, 'text', false);
|
||||
assertDocumentLineMapping(myDocument, direction);
|
||||
|
||||
myDocument.onEvents(e);
|
||||
assertDocumentLineMapping(myDocument, direction);
|
||||
}
|
||||
|
||||
function testLineMappingAfterEvents(lines: string[], e: IModelChangedEvent): void {
|
||||
testLineMappingDirectionAfterEvents(lines, '\n', AssertDocumentLineMappingDirection.PositionToOffset, e);
|
||||
testLineMappingDirectionAfterEvents(lines, '\n', AssertDocumentLineMappingDirection.OffsetToPosition, e);
|
||||
|
||||
testLineMappingDirectionAfterEvents(lines, '\r\n', AssertDocumentLineMappingDirection.PositionToOffset, e);
|
||||
testLineMappingDirectionAfterEvents(lines, '\r\n', AssertDocumentLineMappingDirection.OffsetToPosition, e);
|
||||
}
|
||||
|
||||
test('line mapping', () => {
|
||||
testLineMappingAfterEvents([
|
||||
'This is line one',
|
||||
'and this is line number two',
|
||||
'it is followed by #3',
|
||||
'and finished with the fourth.',
|
||||
], { changes: [], eol: undefined!, versionId: 7, isRedoing: false, isUndoing: false });
|
||||
});
|
||||
|
||||
test('after remove', () => {
|
||||
testLineMappingAfterEvents([
|
||||
'This is line one',
|
||||
'and this is line number two',
|
||||
'it is followed by #3',
|
||||
'and finished with the fourth.',
|
||||
], createChangeEvent(new Range(1, 3, 1, 6), ''));
|
||||
});
|
||||
|
||||
test('after replace', () => {
|
||||
testLineMappingAfterEvents([
|
||||
'This is line one',
|
||||
'and this is line number two',
|
||||
'it is followed by #3',
|
||||
'and finished with the fourth.',
|
||||
], createChangeEvent(new Range(1, 3, 1, 6), 'is could be'));
|
||||
});
|
||||
|
||||
test('after insert line', () => {
|
||||
testLineMappingAfterEvents([
|
||||
'This is line one',
|
||||
'and this is line number two',
|
||||
'it is followed by #3',
|
||||
'and finished with the fourth.',
|
||||
], createChangeEvent(new Range(1, 3, 1, 6), 'is could be\na line with number'));
|
||||
});
|
||||
|
||||
test('after insert two lines', () => {
|
||||
testLineMappingAfterEvents([
|
||||
'This is line one',
|
||||
'and this is line number two',
|
||||
'it is followed by #3',
|
||||
'and finished with the fourth.',
|
||||
], createChangeEvent(new Range(1, 3, 1, 6), 'is could be\na line with number\nyet another line'));
|
||||
});
|
||||
|
||||
test('after remove line', () => {
|
||||
testLineMappingAfterEvents([
|
||||
'This is line one',
|
||||
'and this is line number two',
|
||||
'it is followed by #3',
|
||||
'and finished with the fourth.',
|
||||
], createChangeEvent(new Range(1, 3, 2, 6), ''));
|
||||
});
|
||||
|
||||
test('after remove two lines', () => {
|
||||
testLineMappingAfterEvents([
|
||||
'This is line one',
|
||||
'and this is line number two',
|
||||
'it is followed by #3',
|
||||
'and finished with the fourth.',
|
||||
], createChangeEvent(new Range(1, 3, 3, 6), ''));
|
||||
});
|
||||
|
||||
test('after deleting entire content', () => {
|
||||
testLineMappingAfterEvents([
|
||||
'This is line one',
|
||||
'and this is line number two',
|
||||
'it is followed by #3',
|
||||
'and finished with the fourth.',
|
||||
], createChangeEvent(new Range(1, 3, 4, 30), ''));
|
||||
});
|
||||
|
||||
test('after replacing entire content', () => {
|
||||
testLineMappingAfterEvents([
|
||||
'This is line one',
|
||||
'and this is line number two',
|
||||
'it is followed by #3',
|
||||
'and finished with the fourth.',
|
||||
], createChangeEvent(new Range(1, 3, 4, 30), 'some new text\nthat\nspans multiple lines'));
|
||||
});
|
||||
|
||||
test('after changing EOL to CRLF', () => {
|
||||
testLineMappingAfterEvents([
|
||||
'This is line one',
|
||||
'and this is line number two',
|
||||
'it is followed by #3',
|
||||
'and finished with the fourth.',
|
||||
], createChangeEvent(new Range(1, 1, 1, 1), '', '\r\n'));
|
||||
});
|
||||
|
||||
test('after changing EOL to LF', () => {
|
||||
testLineMappingAfterEvents([
|
||||
'This is line one',
|
||||
'and this is line number two',
|
||||
'it is followed by #3',
|
||||
'and finished with the fourth.',
|
||||
], createChangeEvent(new Range(1, 1, 1, 1), '', '\n'));
|
||||
});
|
||||
});
|
||||
@@ -1,399 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 } from 'vs/base/common/uri';
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import { TextDocumentSaveReason, TextEdit, Position, EndOfLine } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { MainThreadTextEditorsShape, IWorkspaceEditDto, IWorkspaceTextEditDto, MainThreadBulkEditsShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostDocumentSaveParticipant } from 'vs/workbench/api/common/extHostDocumentSaveParticipant';
|
||||
import { SingleProxyRPCProtocol } from './testRPCProtocol';
|
||||
import { SaveReason } from 'vs/workbench/common/editor';
|
||||
import type * as vscode from 'vscode';
|
||||
import { mock } from 'vs/base/test/common/mock';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
|
||||
suite('ExtHostDocumentSaveParticipant', () => {
|
||||
|
||||
let resource = URI.parse('foo:bar');
|
||||
let mainThreadBulkEdits = new class extends mock<MainThreadBulkEditsShape>() { };
|
||||
let documents: ExtHostDocuments;
|
||||
let nullLogService = new NullLogService();
|
||||
let nullExtensionDescription: IExtensionDescription = {
|
||||
identifier: new ExtensionIdentifier('nullExtensionDescription'),
|
||||
name: 'Null Extension Description',
|
||||
publisher: 'vscode',
|
||||
enableProposedApi: false,
|
||||
engines: undefined!,
|
||||
extensionLocation: undefined!,
|
||||
isBuiltin: false,
|
||||
isUserBuiltin: false,
|
||||
isUnderDevelopment: false,
|
||||
version: undefined!
|
||||
};
|
||||
|
||||
setup(() => {
|
||||
const documentsAndEditors = new ExtHostDocumentsAndEditors(SingleProxyRPCProtocol(null), new NullLogService());
|
||||
documentsAndEditors.$acceptDocumentsAndEditorsDelta({
|
||||
addedDocuments: [{
|
||||
isDirty: false,
|
||||
languageId: 'foo',
|
||||
uri: resource,
|
||||
versionId: 1,
|
||||
lines: ['foo'],
|
||||
EOL: '\n',
|
||||
}]
|
||||
});
|
||||
documents = new ExtHostDocuments(SingleProxyRPCProtocol(null), documentsAndEditors);
|
||||
});
|
||||
|
||||
test('no listeners, no problem', () => {
|
||||
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadBulkEdits);
|
||||
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(() => assert.ok(true));
|
||||
});
|
||||
|
||||
test('event delivery', () => {
|
||||
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadBulkEdits);
|
||||
|
||||
let event: vscode.TextDocumentWillSaveEvent;
|
||||
let sub = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
||||
event = e;
|
||||
});
|
||||
|
||||
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(() => {
|
||||
sub.dispose();
|
||||
|
||||
assert.ok(event);
|
||||
assert.strictEqual(event.reason, TextDocumentSaveReason.Manual);
|
||||
assert.strictEqual(typeof event.waitUntil, 'function');
|
||||
});
|
||||
});
|
||||
|
||||
test('event delivery, immutable', () => {
|
||||
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadBulkEdits);
|
||||
|
||||
let event: vscode.TextDocumentWillSaveEvent;
|
||||
let sub = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
||||
event = e;
|
||||
});
|
||||
|
||||
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(() => {
|
||||
sub.dispose();
|
||||
|
||||
assert.ok(event);
|
||||
assert.throws(() => { (event.document as any) = null!; });
|
||||
});
|
||||
});
|
||||
|
||||
test('event delivery, bad listener', () => {
|
||||
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadBulkEdits);
|
||||
|
||||
let sub = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
||||
throw new Error('💀');
|
||||
});
|
||||
|
||||
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(values => {
|
||||
sub.dispose();
|
||||
|
||||
const [first] = values;
|
||||
assert.strictEqual(first, false);
|
||||
});
|
||||
});
|
||||
|
||||
test('event delivery, bad listener doesn\'t prevent more events', () => {
|
||||
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadBulkEdits);
|
||||
|
||||
let sub1 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
||||
throw new Error('💀');
|
||||
});
|
||||
let event: vscode.TextDocumentWillSaveEvent;
|
||||
let sub2 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
||||
event = e;
|
||||
});
|
||||
|
||||
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(() => {
|
||||
sub1.dispose();
|
||||
sub2.dispose();
|
||||
|
||||
assert.ok(event);
|
||||
});
|
||||
});
|
||||
|
||||
test('event delivery, in subscriber order', () => {
|
||||
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadBulkEdits);
|
||||
|
||||
let counter = 0;
|
||||
let sub1 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (event) {
|
||||
assert.strictEqual(counter++, 0);
|
||||
});
|
||||
|
||||
let sub2 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (event) {
|
||||
assert.strictEqual(counter++, 1);
|
||||
});
|
||||
|
||||
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(() => {
|
||||
sub1.dispose();
|
||||
sub2.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
test('event delivery, ignore bad listeners', async () => {
|
||||
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadBulkEdits, { timeout: 5, errors: 1 });
|
||||
|
||||
let callCount = 0;
|
||||
let sub = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (event) {
|
||||
callCount += 1;
|
||||
throw new Error('boom');
|
||||
});
|
||||
|
||||
await participant.$participateInSave(resource, SaveReason.EXPLICIT);
|
||||
await participant.$participateInSave(resource, SaveReason.EXPLICIT);
|
||||
await participant.$participateInSave(resource, SaveReason.EXPLICIT);
|
||||
await participant.$participateInSave(resource, SaveReason.EXPLICIT);
|
||||
|
||||
sub.dispose();
|
||||
assert.strictEqual(callCount, 2);
|
||||
});
|
||||
|
||||
test('event delivery, overall timeout', async function () {
|
||||
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadBulkEdits, { timeout: 20, errors: 5 });
|
||||
|
||||
// let callCount = 0;
|
||||
let calls: number[] = [];
|
||||
let sub1 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (event) {
|
||||
calls.push(1);
|
||||
});
|
||||
|
||||
let sub2 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (event) {
|
||||
calls.push(2);
|
||||
event.waitUntil(timeout(100));
|
||||
});
|
||||
|
||||
let sub3 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (event) {
|
||||
calls.push(3);
|
||||
});
|
||||
|
||||
const values = await participant.$participateInSave(resource, SaveReason.EXPLICIT);
|
||||
sub1.dispose();
|
||||
sub2.dispose();
|
||||
sub3.dispose();
|
||||
assert.deepStrictEqual(calls, [1, 2]);
|
||||
assert.strictEqual(values.length, 2);
|
||||
});
|
||||
|
||||
test('event delivery, waitUntil', () => {
|
||||
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadBulkEdits);
|
||||
|
||||
let sub = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (event) {
|
||||
|
||||
event.waitUntil(timeout(10));
|
||||
event.waitUntil(timeout(10));
|
||||
event.waitUntil(timeout(10));
|
||||
});
|
||||
|
||||
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(() => {
|
||||
sub.dispose();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
test('event delivery, waitUntil must be called sync', () => {
|
||||
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadBulkEdits);
|
||||
|
||||
let sub = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (event) {
|
||||
|
||||
event.waitUntil(new Promise<undefined>((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
try {
|
||||
assert.throws(() => event.waitUntil(timeout(10)));
|
||||
resolve(undefined);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
|
||||
}, 10);
|
||||
}));
|
||||
});
|
||||
|
||||
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(() => {
|
||||
sub.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
test('event delivery, waitUntil will timeout', function () {
|
||||
|
||||
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadBulkEdits, { timeout: 5, errors: 3 });
|
||||
|
||||
let sub = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (event) {
|
||||
event.waitUntil(timeout(100));
|
||||
});
|
||||
|
||||
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(values => {
|
||||
sub.dispose();
|
||||
|
||||
const [first] = values;
|
||||
assert.strictEqual(first, false);
|
||||
});
|
||||
});
|
||||
|
||||
test('event delivery, waitUntil failure handling', () => {
|
||||
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadBulkEdits);
|
||||
|
||||
let sub1 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
||||
e.waitUntil(Promise.reject(new Error('dddd')));
|
||||
});
|
||||
|
||||
let event: vscode.TextDocumentWillSaveEvent;
|
||||
let sub2 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
||||
event = e;
|
||||
});
|
||||
|
||||
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(() => {
|
||||
assert.ok(event);
|
||||
sub1.dispose();
|
||||
sub2.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
test('event delivery, pushEdits sync', () => {
|
||||
|
||||
let dto: IWorkspaceEditDto;
|
||||
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, new class extends mock<MainThreadTextEditorsShape>() {
|
||||
$tryApplyWorkspaceEdit(_edits: IWorkspaceEditDto) {
|
||||
dto = _edits;
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
});
|
||||
|
||||
let sub = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
||||
e.waitUntil(Promise.resolve([TextEdit.insert(new Position(0, 0), 'bar')]));
|
||||
e.waitUntil(Promise.resolve([TextEdit.setEndOfLine(EndOfLine.CRLF)]));
|
||||
});
|
||||
|
||||
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(() => {
|
||||
sub.dispose();
|
||||
|
||||
assert.strictEqual(dto.edits.length, 2);
|
||||
assert.ok((<IWorkspaceTextEditDto>dto.edits[0]).edit);
|
||||
assert.ok((<IWorkspaceTextEditDto>dto.edits[1]).edit);
|
||||
});
|
||||
});
|
||||
|
||||
test('event delivery, concurrent change', () => {
|
||||
|
||||
let edits: IWorkspaceEditDto;
|
||||
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, new class extends mock<MainThreadTextEditorsShape>() {
|
||||
$tryApplyWorkspaceEdit(_edits: IWorkspaceEditDto) {
|
||||
edits = _edits;
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
});
|
||||
|
||||
let sub = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
||||
|
||||
// concurrent change from somewhere
|
||||
documents.$acceptModelChanged(resource, {
|
||||
changes: [{
|
||||
range: { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 },
|
||||
rangeOffset: undefined!,
|
||||
rangeLength: undefined!,
|
||||
text: 'bar'
|
||||
}],
|
||||
eol: undefined!,
|
||||
versionId: 2,
|
||||
isRedoing: false,
|
||||
isUndoing: false,
|
||||
}, true);
|
||||
|
||||
e.waitUntil(Promise.resolve([TextEdit.insert(new Position(0, 0), 'bar')]));
|
||||
});
|
||||
|
||||
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(values => {
|
||||
sub.dispose();
|
||||
|
||||
assert.strictEqual(edits, undefined);
|
||||
assert.strictEqual(values[0], false);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
test('event delivery, two listeners -> two document states', () => {
|
||||
|
||||
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, new class extends mock<MainThreadTextEditorsShape>() {
|
||||
$tryApplyWorkspaceEdit(dto: IWorkspaceEditDto) {
|
||||
|
||||
for (const edit of dto.edits) {
|
||||
|
||||
const uri = URI.revive((<IWorkspaceTextEditDto>edit).resource);
|
||||
const { text, range } = (<IWorkspaceTextEditDto>edit).edit;
|
||||
documents.$acceptModelChanged(uri, {
|
||||
changes: [{
|
||||
range,
|
||||
text,
|
||||
rangeOffset: undefined!,
|
||||
rangeLength: undefined!,
|
||||
}],
|
||||
eol: undefined!,
|
||||
versionId: documents.getDocumentData(uri)!.version + 1,
|
||||
isRedoing: false,
|
||||
isUndoing: false,
|
||||
}, true);
|
||||
// }
|
||||
}
|
||||
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
});
|
||||
|
||||
const document = documents.getDocument(resource);
|
||||
|
||||
let sub1 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
||||
// the document state we started with
|
||||
assert.strictEqual(document.version, 1);
|
||||
assert.strictEqual(document.getText(), 'foo');
|
||||
|
||||
e.waitUntil(Promise.resolve([TextEdit.insert(new Position(0, 0), 'bar')]));
|
||||
});
|
||||
|
||||
let sub2 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
||||
// the document state AFTER the first listener kicked in
|
||||
assert.strictEqual(document.version, 2);
|
||||
assert.strictEqual(document.getText(), 'barfoo');
|
||||
|
||||
e.waitUntil(Promise.resolve([TextEdit.insert(new Position(0, 0), 'bar')]));
|
||||
});
|
||||
|
||||
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(values => {
|
||||
sub1.dispose();
|
||||
sub2.dispose();
|
||||
|
||||
// the document state AFTER eventing is done
|
||||
assert.strictEqual(document.version, 3);
|
||||
assert.strictEqual(document.getText(), 'barbarfoo');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
test('Log failing listener', function () {
|
||||
let didLogSomething = false;
|
||||
let participant = new ExtHostDocumentSaveParticipant(new class extends NullLogService {
|
||||
override error(message: string | Error, ...args: any[]): void {
|
||||
didLogSomething = true;
|
||||
}
|
||||
}, documents, mainThreadBulkEdits);
|
||||
|
||||
|
||||
let sub = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
||||
throw new Error('boom');
|
||||
});
|
||||
|
||||
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(() => {
|
||||
sub.dispose();
|
||||
assert.strictEqual(didLogSomething, true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,57 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 } from 'vs/base/common/uri';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import { TestRPCProtocol } from 'vs/workbench/test/browser/api/testRPCProtocol';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
|
||||
suite('ExtHostDocumentsAndEditors', () => {
|
||||
|
||||
let editors: ExtHostDocumentsAndEditors;
|
||||
|
||||
setup(function () {
|
||||
editors = new ExtHostDocumentsAndEditors(new TestRPCProtocol(), new NullLogService());
|
||||
});
|
||||
|
||||
test('The value of TextDocument.isClosed is incorrect when a text document is closed, #27949', () => {
|
||||
|
||||
editors.$acceptDocumentsAndEditorsDelta({
|
||||
addedDocuments: [{
|
||||
EOL: '\n',
|
||||
isDirty: true,
|
||||
languageId: 'fooLang',
|
||||
uri: URI.parse('foo:bar'),
|
||||
versionId: 1,
|
||||
lines: [
|
||||
'first',
|
||||
'second'
|
||||
]
|
||||
}]
|
||||
});
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
editors.onDidRemoveDocuments(e => {
|
||||
try {
|
||||
|
||||
for (const data of e) {
|
||||
assert.strictEqual(data.document.isClosed, true);
|
||||
}
|
||||
resolve(undefined);
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
|
||||
editors.$acceptDocumentsAndEditorsDelta({
|
||||
removedDocuments: [URI.parse('foo:bar')]
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,33 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { ExtHostFileSystemEventService } from 'vs/workbench/api/common/extHostFileSystemEventService';
|
||||
import { IMainContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
|
||||
suite('ExtHostFileSystemEventService', () => {
|
||||
|
||||
|
||||
test('FileSystemWatcher ignore events properties are reversed #26851', function () {
|
||||
|
||||
const protocol: IMainContext = {
|
||||
getProxy: () => { return undefined!; },
|
||||
set: undefined!,
|
||||
assertRegistered: undefined!,
|
||||
drain: undefined!
|
||||
};
|
||||
|
||||
const watcher1 = new ExtHostFileSystemEventService(protocol, new NullLogService(), undefined!).createFileSystemWatcher('**/somethingInteresting', false, false, false);
|
||||
assert.strictEqual(watcher1.ignoreChangeEvents, false);
|
||||
assert.strictEqual(watcher1.ignoreCreateEvents, false);
|
||||
assert.strictEqual(watcher1.ignoreDeleteEvents, false);
|
||||
|
||||
const watcher2 = new ExtHostFileSystemEventService(protocol, new NullLogService(), undefined!).createFileSystemWatcher('**/somethingBoring', true, true, true);
|
||||
assert.strictEqual(watcher2.ignoreChangeEvents, true);
|
||||
assert.strictEqual(watcher2.ignoreCreateEvents, true);
|
||||
assert.strictEqual(watcher2.ignoreDeleteEvents, true);
|
||||
});
|
||||
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,155 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { MainThreadMessageService } from 'vs/workbench/api/browser/mainThreadMessageService';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { INotificationService, INotification, NoOpNotification, INotificationHandle, Severity, IPromptChoice, IPromptOptions, IStatusMessageOptions, NotificationsFilter } from 'vs/platform/notification/common/notification';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { mock } from 'vs/base/test/common/mock';
|
||||
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
|
||||
const emptyDialogService = new class implements IDialogService {
|
||||
declare readonly _serviceBrand: undefined;
|
||||
show(): never {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
|
||||
confirm(): never {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
|
||||
about(): never {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
|
||||
input(): never {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
};
|
||||
|
||||
const emptyCommandService: ICommandService = {
|
||||
_serviceBrand: undefined,
|
||||
onWillExecuteCommand: () => Disposable.None,
|
||||
onDidExecuteCommand: () => Disposable.None,
|
||||
executeCommand: (commandId: string, ...args: any[]): Promise<any> => {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
};
|
||||
|
||||
const emptyNotificationService = new class implements INotificationService {
|
||||
declare readonly _serviceBrand: undefined;
|
||||
onDidAddNotification: Event<INotification> = Event.None;
|
||||
onDidRemoveNotification: Event<INotification> = Event.None;
|
||||
notify(...args: any[]): never {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
info(...args: any[]): never {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
warn(...args: any[]): never {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
error(...args: any[]): never {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
prompt(severity: Severity, message: string, choices: IPromptChoice[], options?: IPromptOptions): INotificationHandle {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
status(message: string | Error, options?: IStatusMessageOptions): IDisposable {
|
||||
return Disposable.None;
|
||||
}
|
||||
setFilter(filter: NotificationsFilter): void {
|
||||
throw new Error('not implemented.');
|
||||
}
|
||||
};
|
||||
|
||||
class EmptyNotificationService implements INotificationService {
|
||||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
constructor(private withNotify: (notification: INotification) => void) {
|
||||
}
|
||||
|
||||
onDidAddNotification: Event<INotification> = Event.None;
|
||||
onDidRemoveNotification: Event<INotification> = Event.None;
|
||||
notify(notification: INotification): INotificationHandle {
|
||||
this.withNotify(notification);
|
||||
|
||||
return new NoOpNotification();
|
||||
}
|
||||
info(message: any): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
warn(message: any): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
error(message: any): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
prompt(severity: Severity, message: string, choices: IPromptChoice[], options?: IPromptOptions): INotificationHandle {
|
||||
throw new Error('Method not implemented');
|
||||
}
|
||||
status(message: string, options?: IStatusMessageOptions): IDisposable {
|
||||
return Disposable.None;
|
||||
}
|
||||
setFilter(filter: NotificationsFilter): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
}
|
||||
|
||||
suite('ExtHostMessageService', function () {
|
||||
|
||||
test('propagte handle on select', async function () {
|
||||
|
||||
let service = new MainThreadMessageService(null!, new EmptyNotificationService(notification => {
|
||||
assert.strictEqual(notification.actions!.primary!.length, 1);
|
||||
queueMicrotask(() => notification.actions!.primary![0].run());
|
||||
}), emptyCommandService, emptyDialogService);
|
||||
|
||||
const handle = await service.$showMessage(1, 'h', {}, [{ handle: 42, title: 'a thing', isCloseAffordance: true }]);
|
||||
assert.strictEqual(handle, 42);
|
||||
});
|
||||
|
||||
suite('modal', () => {
|
||||
test('calls dialog service', async () => {
|
||||
const service = new MainThreadMessageService(null!, emptyNotificationService, emptyCommandService, new class extends mock<IDialogService>() {
|
||||
override show(severity: Severity, message: string, buttons: string[]) {
|
||||
assert.strictEqual(severity, 1);
|
||||
assert.strictEqual(message, 'h');
|
||||
assert.strictEqual(buttons.length, 2);
|
||||
assert.strictEqual(buttons[1], 'Cancel');
|
||||
return Promise.resolve({ choice: 0 });
|
||||
}
|
||||
} as IDialogService);
|
||||
|
||||
const handle = await service.$showMessage(1, 'h', { modal: true }, [{ handle: 42, title: 'a thing', isCloseAffordance: false }]);
|
||||
assert.strictEqual(handle, 42);
|
||||
});
|
||||
|
||||
test('returns undefined when cancelled', async () => {
|
||||
const service = new MainThreadMessageService(null!, emptyNotificationService, emptyCommandService, new class extends mock<IDialogService>() {
|
||||
override show() {
|
||||
return Promise.resolve({ choice: 1 });
|
||||
}
|
||||
} as IDialogService);
|
||||
|
||||
const handle = await service.$showMessage(1, 'h', { modal: true }, [{ handle: 42, title: 'a thing', isCloseAffordance: false }]);
|
||||
assert.strictEqual(handle, undefined);
|
||||
});
|
||||
|
||||
test('hides Cancel button when not needed', async () => {
|
||||
const service = new MainThreadMessageService(null!, emptyNotificationService, emptyCommandService, new class extends mock<IDialogService>() {
|
||||
override show(severity: Severity, message: string, buttons: string[]) {
|
||||
assert.strictEqual(buttons.length, 1);
|
||||
return Promise.resolve({ choice: 0 });
|
||||
}
|
||||
} as IDialogService);
|
||||
|
||||
const handle = await service.$showMessage(1, 'h', { modal: true }, [{ handle: 42, title: 'a thing', isCloseAffordance: true }]);
|
||||
assert.strictEqual(handle, 42);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,421 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 vscode from 'vscode';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import { TestRPCProtocol } from 'vs/workbench/test/browser/api/testRPCProtocol';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
import { mock } from 'vs/base/test/common/mock';
|
||||
import { IModelAddedData, MainContext, MainThreadCommandsShape, MainThreadNotebookShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook';
|
||||
import { ExtHostNotebookDocument } from 'vs/workbench/api/common/extHostNotebookDocument';
|
||||
import { CellKind, CellUri, NotebookCellsChangeType } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { isEqual } from 'vs/base/common/resources';
|
||||
import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { ExtHostNotebookDocuments } from 'vs/workbench/api/common/extHostNotebookDocuments';
|
||||
import { SerializableObjectWithBuffers } from 'vs/workbench/services/extensions/common/proxyIdentifier';
|
||||
|
||||
suite('NotebookCell#Document', function () {
|
||||
|
||||
|
||||
let rpcProtocol: TestRPCProtocol;
|
||||
let notebook: ExtHostNotebookDocument;
|
||||
let extHostDocumentsAndEditors: ExtHostDocumentsAndEditors;
|
||||
let extHostDocuments: ExtHostDocuments;
|
||||
let extHostNotebooks: ExtHostNotebookController;
|
||||
let extHostNotebookDocuments: ExtHostNotebookDocuments;
|
||||
|
||||
const notebookUri = URI.parse('test:///notebook.file');
|
||||
const disposables = new DisposableStore();
|
||||
|
||||
teardown(function () {
|
||||
disposables.clear();
|
||||
});
|
||||
|
||||
setup(async function () {
|
||||
rpcProtocol = new TestRPCProtocol();
|
||||
rpcProtocol.set(MainContext.MainThreadCommands, new class extends mock<MainThreadCommandsShape>() {
|
||||
override $registerCommand() { }
|
||||
});
|
||||
rpcProtocol.set(MainContext.MainThreadNotebook, new class extends mock<MainThreadNotebookShape>() {
|
||||
override async $registerNotebookProvider() { }
|
||||
override async $unregisterNotebookProvider() { }
|
||||
});
|
||||
extHostDocumentsAndEditors = new ExtHostDocumentsAndEditors(rpcProtocol, new NullLogService());
|
||||
extHostDocuments = new ExtHostDocuments(rpcProtocol, extHostDocumentsAndEditors);
|
||||
const extHostStoragePaths = new class extends mock<IExtensionStoragePaths>() {
|
||||
override workspaceValue() {
|
||||
return URI.from({ scheme: 'test', path: generateUuid() });
|
||||
}
|
||||
};
|
||||
extHostNotebooks = new ExtHostNotebookController(rpcProtocol, new ExtHostCommands(rpcProtocol, new NullLogService()), extHostDocumentsAndEditors, extHostDocuments, extHostStoragePaths);
|
||||
extHostNotebookDocuments = new ExtHostNotebookDocuments(new NullLogService(), extHostNotebooks);
|
||||
|
||||
let reg = extHostNotebooks.registerNotebookContentProvider(nullExtensionDescription, 'test', new class extends mock<vscode.NotebookContentProvider>() {
|
||||
// async openNotebook() { }
|
||||
});
|
||||
extHostNotebooks.$acceptDocumentAndEditorsDelta(new SerializableObjectWithBuffers({
|
||||
addedDocuments: [{
|
||||
uri: notebookUri,
|
||||
viewType: 'test',
|
||||
versionId: 0,
|
||||
cells: [{
|
||||
handle: 0,
|
||||
uri: CellUri.generate(notebookUri, 0),
|
||||
source: ['### Heading'],
|
||||
eol: '\n',
|
||||
language: 'markdown',
|
||||
cellKind: CellKind.Markup,
|
||||
outputs: [],
|
||||
}, {
|
||||
handle: 1,
|
||||
uri: CellUri.generate(notebookUri, 1),
|
||||
source: ['console.log("aaa")', 'console.log("bbb")'],
|
||||
eol: '\n',
|
||||
language: 'javascript',
|
||||
cellKind: CellKind.Code,
|
||||
outputs: [],
|
||||
}],
|
||||
}],
|
||||
addedEditors: [{
|
||||
documentUri: notebookUri,
|
||||
id: '_notebook_editor_0',
|
||||
selections: [{ start: 0, end: 1 }],
|
||||
visibleRanges: []
|
||||
}]
|
||||
}));
|
||||
extHostNotebooks.$acceptDocumentAndEditorsDelta(new SerializableObjectWithBuffers({ newActiveEditor: '_notebook_editor_0' }));
|
||||
|
||||
notebook = extHostNotebooks.notebookDocuments[0]!;
|
||||
|
||||
disposables.add(reg);
|
||||
disposables.add(notebook);
|
||||
disposables.add(extHostDocuments);
|
||||
});
|
||||
|
||||
|
||||
test('cell document is vscode.TextDocument', async function () {
|
||||
|
||||
assert.strictEqual(notebook.apiNotebook.cellCount, 2);
|
||||
|
||||
const [c1, c2] = notebook.apiNotebook.getCells();
|
||||
const d1 = extHostDocuments.getDocument(c1.document.uri);
|
||||
|
||||
assert.ok(d1);
|
||||
assert.strictEqual(d1.languageId, c1.document.languageId);
|
||||
assert.strictEqual(d1.version, 1);
|
||||
assert.ok(d1.notebook === notebook.apiNotebook);
|
||||
|
||||
const d2 = extHostDocuments.getDocument(c2.document.uri);
|
||||
assert.ok(d2);
|
||||
assert.strictEqual(d2.languageId, c2.document.languageId);
|
||||
assert.strictEqual(d2.version, 1);
|
||||
assert.ok(d2.notebook === notebook.apiNotebook);
|
||||
});
|
||||
|
||||
test('cell document goes when notebook closes', async function () {
|
||||
const cellUris: string[] = [];
|
||||
for (let cell of notebook.apiNotebook.getCells()) {
|
||||
assert.ok(extHostDocuments.getDocument(cell.document.uri));
|
||||
cellUris.push(cell.document.uri.toString());
|
||||
}
|
||||
|
||||
const removedCellUris: string[] = [];
|
||||
const reg = extHostDocuments.onDidRemoveDocument(doc => {
|
||||
removedCellUris.push(doc.uri.toString());
|
||||
});
|
||||
|
||||
extHostNotebooks.$acceptDocumentAndEditorsDelta(new SerializableObjectWithBuffers({ removedDocuments: [notebook.uri] }));
|
||||
reg.dispose();
|
||||
|
||||
assert.strictEqual(removedCellUris.length, 2);
|
||||
assert.deepStrictEqual(removedCellUris.sort(), cellUris.sort());
|
||||
});
|
||||
|
||||
test('cell document is vscode.TextDocument after changing it', async function () {
|
||||
|
||||
const p = new Promise<void>((resolve, reject) => {
|
||||
extHostNotebooks.onDidChangeNotebookCells(e => {
|
||||
try {
|
||||
assert.strictEqual(e.changes.length, 1);
|
||||
assert.strictEqual(e.changes[0].items.length, 2);
|
||||
|
||||
const [first, second] = e.changes[0].items;
|
||||
|
||||
const doc1 = extHostDocuments.getAllDocumentData().find(data => isEqual(data.document.uri, first.document.uri));
|
||||
assert.ok(doc1);
|
||||
assert.strictEqual(doc1?.document === first.document, true);
|
||||
|
||||
const doc2 = extHostDocuments.getAllDocumentData().find(data => isEqual(data.document.uri, second.document.uri));
|
||||
assert.ok(doc2);
|
||||
assert.strictEqual(doc2?.document === second.document, true);
|
||||
|
||||
resolve();
|
||||
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
extHostNotebookDocuments.$acceptModelChanged(notebookUri, new SerializableObjectWithBuffers({
|
||||
versionId: notebook.apiNotebook.version + 1,
|
||||
rawEvents: [
|
||||
{
|
||||
kind: NotebookCellsChangeType.ModelChange,
|
||||
changes: [[0, 0, [{
|
||||
handle: 2,
|
||||
uri: CellUri.generate(notebookUri, 2),
|
||||
source: ['Hello', 'World', 'Hello World!'],
|
||||
eol: '\n',
|
||||
language: 'test',
|
||||
cellKind: CellKind.Code,
|
||||
outputs: [],
|
||||
}, {
|
||||
handle: 3,
|
||||
uri: CellUri.generate(notebookUri, 3),
|
||||
source: ['Hallo', 'Welt', 'Hallo Welt!'],
|
||||
eol: '\n',
|
||||
language: 'test',
|
||||
cellKind: CellKind.Code,
|
||||
outputs: [],
|
||||
}]]]
|
||||
}
|
||||
]
|
||||
}), false);
|
||||
|
||||
await p;
|
||||
|
||||
});
|
||||
|
||||
test('cell document stays open when notebook is still open', async function () {
|
||||
|
||||
const docs: vscode.TextDocument[] = [];
|
||||
const addData: IModelAddedData[] = [];
|
||||
for (let cell of notebook.apiNotebook.getCells()) {
|
||||
const doc = extHostDocuments.getDocument(cell.document.uri);
|
||||
assert.ok(doc);
|
||||
assert.strictEqual(extHostDocuments.getDocument(cell.document.uri).isClosed, false);
|
||||
docs.push(doc);
|
||||
addData.push({
|
||||
EOL: '\n',
|
||||
isDirty: doc.isDirty,
|
||||
lines: doc.getText().split('\n'),
|
||||
languageId: doc.languageId,
|
||||
uri: doc.uri,
|
||||
versionId: doc.version
|
||||
});
|
||||
}
|
||||
|
||||
// this call happens when opening a document on the main side
|
||||
extHostDocumentsAndEditors.$acceptDocumentsAndEditorsDelta({ addedDocuments: addData });
|
||||
|
||||
// this call happens when closing a document from the main side
|
||||
extHostDocumentsAndEditors.$acceptDocumentsAndEditorsDelta({ removedDocuments: docs.map(d => d.uri) });
|
||||
|
||||
// notebook is still open -> cell documents stay open
|
||||
for (let cell of notebook.apiNotebook.getCells()) {
|
||||
assert.ok(extHostDocuments.getDocument(cell.document.uri));
|
||||
assert.strictEqual(extHostDocuments.getDocument(cell.document.uri).isClosed, false);
|
||||
}
|
||||
|
||||
// close notebook -> docs are closed
|
||||
extHostNotebooks.$acceptDocumentAndEditorsDelta(new SerializableObjectWithBuffers({ removedDocuments: [notebook.uri] }));
|
||||
for (let cell of notebook.apiNotebook.getCells()) {
|
||||
assert.throws(() => extHostDocuments.getDocument(cell.document.uri));
|
||||
}
|
||||
for (let doc of docs) {
|
||||
assert.strictEqual(doc.isClosed, true);
|
||||
}
|
||||
});
|
||||
|
||||
test('cell document goes when cell is removed', async function () {
|
||||
|
||||
assert.strictEqual(notebook.apiNotebook.cellCount, 2);
|
||||
const [cell1, cell2] = notebook.apiNotebook.getCells();
|
||||
|
||||
extHostNotebookDocuments.$acceptModelChanged(notebook.uri, new SerializableObjectWithBuffers({
|
||||
versionId: 2,
|
||||
rawEvents: [
|
||||
{
|
||||
kind: NotebookCellsChangeType.ModelChange,
|
||||
changes: [[0, 1, []]]
|
||||
}
|
||||
]
|
||||
}), false);
|
||||
|
||||
assert.strictEqual(notebook.apiNotebook.cellCount, 1);
|
||||
assert.strictEqual(cell1.document.isClosed, true); // ref still alive!
|
||||
assert.strictEqual(cell2.document.isClosed, false);
|
||||
|
||||
assert.throws(() => extHostDocuments.getDocument(cell1.document.uri));
|
||||
});
|
||||
|
||||
test('cell document knows notebook', function () {
|
||||
for (let cells of notebook.apiNotebook.getCells()) {
|
||||
assert.strictEqual(cells.document.notebook === notebook.apiNotebook, true);
|
||||
}
|
||||
});
|
||||
|
||||
test('cell#index', function () {
|
||||
|
||||
assert.strictEqual(notebook.apiNotebook.cellCount, 2);
|
||||
const [first, second] = notebook.apiNotebook.getCells();
|
||||
assert.strictEqual(first.index, 0);
|
||||
assert.strictEqual(second.index, 1);
|
||||
|
||||
// remove first cell
|
||||
extHostNotebookDocuments.$acceptModelChanged(notebook.uri, new SerializableObjectWithBuffers({
|
||||
versionId: notebook.apiNotebook.version + 1,
|
||||
rawEvents: [{
|
||||
kind: NotebookCellsChangeType.ModelChange,
|
||||
changes: [[0, 1, []]]
|
||||
}]
|
||||
}), false);
|
||||
|
||||
assert.strictEqual(notebook.apiNotebook.cellCount, 1);
|
||||
assert.strictEqual(second.index, 0);
|
||||
|
||||
extHostNotebookDocuments.$acceptModelChanged(notebookUri, new SerializableObjectWithBuffers({
|
||||
versionId: notebook.apiNotebook.version + 1,
|
||||
rawEvents: [{
|
||||
kind: NotebookCellsChangeType.ModelChange,
|
||||
changes: [[0, 0, [{
|
||||
handle: 2,
|
||||
uri: CellUri.generate(notebookUri, 2),
|
||||
source: ['Hello', 'World', 'Hello World!'],
|
||||
eol: '\n',
|
||||
language: 'test',
|
||||
cellKind: CellKind.Code,
|
||||
outputs: [],
|
||||
}, {
|
||||
handle: 3,
|
||||
uri: CellUri.generate(notebookUri, 3),
|
||||
source: ['Hallo', 'Welt', 'Hallo Welt!'],
|
||||
eol: '\n',
|
||||
language: 'test',
|
||||
cellKind: CellKind.Code,
|
||||
outputs: [],
|
||||
}]]]
|
||||
}]
|
||||
}), false);
|
||||
|
||||
assert.strictEqual(notebook.apiNotebook.cellCount, 3);
|
||||
assert.strictEqual(second.index, 2);
|
||||
});
|
||||
|
||||
test('ERR MISSING extHostDocument for notebook cell: #116711', async function () {
|
||||
|
||||
const p = Event.toPromise(extHostNotebooks.onDidChangeNotebookCells);
|
||||
|
||||
// DON'T call this, make sure the cell-documents have not been created yet
|
||||
// assert.strictEqual(notebook.notebookDocument.cellCount, 2);
|
||||
|
||||
extHostNotebookDocuments.$acceptModelChanged(notebook.uri, new SerializableObjectWithBuffers({
|
||||
versionId: 100,
|
||||
rawEvents: [{
|
||||
kind: NotebookCellsChangeType.ModelChange,
|
||||
changes: [[0, 2, [{
|
||||
handle: 3,
|
||||
uri: CellUri.generate(notebookUri, 3),
|
||||
source: ['### Heading'],
|
||||
eol: '\n',
|
||||
language: 'markdown',
|
||||
cellKind: CellKind.Markup,
|
||||
outputs: [],
|
||||
}, {
|
||||
handle: 4,
|
||||
uri: CellUri.generate(notebookUri, 4),
|
||||
source: ['console.log("aaa")', 'console.log("bbb")'],
|
||||
eol: '\n',
|
||||
language: 'javascript',
|
||||
cellKind: CellKind.Code,
|
||||
outputs: [],
|
||||
}]]]
|
||||
}]
|
||||
}), false);
|
||||
|
||||
assert.strictEqual(notebook.apiNotebook.cellCount, 2);
|
||||
|
||||
const event = await p;
|
||||
|
||||
assert.strictEqual(event.document === notebook.apiNotebook, true);
|
||||
assert.strictEqual(event.changes.length, 1);
|
||||
assert.strictEqual(event.changes[0].deletedCount, 2);
|
||||
assert.strictEqual(event.changes[0].deletedItems[0].document.isClosed, true);
|
||||
assert.strictEqual(event.changes[0].deletedItems[1].document.isClosed, true);
|
||||
assert.strictEqual(event.changes[0].items.length, 2);
|
||||
assert.strictEqual(event.changes[0].items[0].document.isClosed, false);
|
||||
assert.strictEqual(event.changes[0].items[1].document.isClosed, false);
|
||||
});
|
||||
|
||||
|
||||
test('Opening a notebook results in VS Code firing the event onDidChangeActiveNotebookEditor twice #118470', function () {
|
||||
let count = 0;
|
||||
extHostNotebooks.onDidChangeActiveNotebookEditor(() => count += 1);
|
||||
|
||||
extHostNotebooks.$acceptDocumentAndEditorsDelta(new SerializableObjectWithBuffers({
|
||||
addedEditors: [{
|
||||
documentUri: notebookUri,
|
||||
id: '_notebook_editor_2',
|
||||
selections: [{ start: 0, end: 1 }],
|
||||
visibleRanges: []
|
||||
}]
|
||||
}));
|
||||
|
||||
extHostNotebooks.$acceptDocumentAndEditorsDelta(new SerializableObjectWithBuffers({
|
||||
newActiveEditor: '_notebook_editor_2'
|
||||
}));
|
||||
|
||||
assert.strictEqual(count, 1);
|
||||
});
|
||||
|
||||
test('unset active notebook editor', function () {
|
||||
|
||||
const editor = extHostNotebooks.activeNotebookEditor;
|
||||
assert.ok(editor !== undefined);
|
||||
|
||||
extHostNotebooks.$acceptDocumentAndEditorsDelta(new SerializableObjectWithBuffers({ newActiveEditor: undefined }));
|
||||
assert.ok(extHostNotebooks.activeNotebookEditor === editor);
|
||||
|
||||
extHostNotebooks.$acceptDocumentAndEditorsDelta(new SerializableObjectWithBuffers({}));
|
||||
assert.ok(extHostNotebooks.activeNotebookEditor === editor);
|
||||
|
||||
extHostNotebooks.$acceptDocumentAndEditorsDelta(new SerializableObjectWithBuffers({ newActiveEditor: null }));
|
||||
assert.ok(extHostNotebooks.activeNotebookEditor === undefined);
|
||||
});
|
||||
|
||||
test('change cell language triggers onDidChange events', async function () {
|
||||
|
||||
const first = notebook.apiNotebook.cellAt(0);
|
||||
|
||||
assert.strictEqual(first.document.languageId, 'markdown');
|
||||
|
||||
const removed = Event.toPromise(extHostDocuments.onDidRemoveDocument);
|
||||
const added = Event.toPromise(extHostDocuments.onDidAddDocument);
|
||||
|
||||
extHostNotebookDocuments.$acceptModelChanged(notebook.uri, new SerializableObjectWithBuffers({
|
||||
versionId: 12, rawEvents: [{
|
||||
kind: NotebookCellsChangeType.ChangeLanguage,
|
||||
index: 0,
|
||||
language: 'fooLang'
|
||||
}]
|
||||
}), false);
|
||||
|
||||
const removedDoc = await removed;
|
||||
const addedDoc = await added;
|
||||
|
||||
assert.strictEqual(first.document.languageId, 'fooLang');
|
||||
assert.ok(removedDoc === addedDoc);
|
||||
});
|
||||
});
|
||||
@@ -1,620 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { TestRPCProtocol } from 'vs/workbench/test/browser/api/testRPCProtocol';
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
import { ExtHostNotebookConcatDocument } from 'vs/workbench/api/common/extHostNotebookConcatDocument';
|
||||
import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook';
|
||||
import { ExtHostNotebookDocument } from 'vs/workbench/api/common/extHostNotebookDocument';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { CellKind, CellUri, NotebookCellsChangeType } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { Position, Location, Range } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import * as vscode from 'vscode';
|
||||
import { mock } from 'vs/workbench/test/common/workbenchTestServices';
|
||||
import { MainContext, MainThreadCommandsShape, MainThreadNotebookShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { ExtHostNotebookDocuments } from 'vs/workbench/api/common/extHostNotebookDocuments';
|
||||
import { SerializableObjectWithBuffers } from 'vs/workbench/services/extensions/common/proxyIdentifier';
|
||||
|
||||
suite('NotebookConcatDocument', function () {
|
||||
|
||||
let rpcProtocol: TestRPCProtocol;
|
||||
let notebook: ExtHostNotebookDocument;
|
||||
let extHostDocumentsAndEditors: ExtHostDocumentsAndEditors;
|
||||
let extHostDocuments: ExtHostDocuments;
|
||||
let extHostNotebooks: ExtHostNotebookController;
|
||||
let extHostNotebookDocuments: ExtHostNotebookDocuments;
|
||||
|
||||
const notebookUri = URI.parse('test:///notebook.file');
|
||||
const disposables = new DisposableStore();
|
||||
|
||||
setup(async function () {
|
||||
disposables.clear();
|
||||
|
||||
rpcProtocol = new TestRPCProtocol();
|
||||
rpcProtocol.set(MainContext.MainThreadCommands, new class extends mock<MainThreadCommandsShape>() {
|
||||
override $registerCommand() { }
|
||||
});
|
||||
rpcProtocol.set(MainContext.MainThreadNotebook, new class extends mock<MainThreadNotebookShape>() {
|
||||
override async $registerNotebookProvider() { }
|
||||
override async $unregisterNotebookProvider() { }
|
||||
});
|
||||
extHostDocumentsAndEditors = new ExtHostDocumentsAndEditors(rpcProtocol, new NullLogService());
|
||||
extHostDocuments = new ExtHostDocuments(rpcProtocol, extHostDocumentsAndEditors);
|
||||
const extHostStoragePaths = new class extends mock<IExtensionStoragePaths>() {
|
||||
override workspaceValue() {
|
||||
return URI.from({ scheme: 'test', path: generateUuid() });
|
||||
}
|
||||
};
|
||||
extHostNotebooks = new ExtHostNotebookController(rpcProtocol, new ExtHostCommands(rpcProtocol, new NullLogService()), extHostDocumentsAndEditors, extHostDocuments, extHostStoragePaths);
|
||||
extHostNotebookDocuments = new ExtHostNotebookDocuments(new NullLogService(), extHostNotebooks);
|
||||
|
||||
let reg = extHostNotebooks.registerNotebookContentProvider(nullExtensionDescription, 'test', new class extends mock<vscode.NotebookContentProvider>() {
|
||||
// async openNotebook() { }
|
||||
});
|
||||
extHostNotebooks.$acceptDocumentAndEditorsDelta(new SerializableObjectWithBuffers({
|
||||
addedDocuments: [{
|
||||
uri: notebookUri,
|
||||
viewType: 'test',
|
||||
cells: [{
|
||||
handle: 0,
|
||||
uri: CellUri.generate(notebookUri, 0),
|
||||
source: ['### Heading'],
|
||||
eol: '\n',
|
||||
language: 'markdown',
|
||||
cellKind: CellKind.Markup,
|
||||
outputs: [],
|
||||
}],
|
||||
versionId: 0
|
||||
}],
|
||||
addedEditors: [{
|
||||
documentUri: notebookUri,
|
||||
id: '_notebook_editor_0',
|
||||
selections: [{ start: 0, end: 1 }],
|
||||
visibleRanges: []
|
||||
}]
|
||||
}));
|
||||
extHostNotebooks.$acceptDocumentAndEditorsDelta(new SerializableObjectWithBuffers({ newActiveEditor: '_notebook_editor_0' }));
|
||||
|
||||
notebook = extHostNotebooks.notebookDocuments[0]!;
|
||||
|
||||
disposables.add(reg);
|
||||
disposables.add(notebook);
|
||||
disposables.add(extHostDocuments);
|
||||
});
|
||||
|
||||
test('empty', function () {
|
||||
let doc = new ExtHostNotebookConcatDocument(extHostNotebooks, extHostDocuments, notebook.apiNotebook, undefined);
|
||||
assert.strictEqual(doc.getText(), '');
|
||||
assert.strictEqual(doc.version, 0);
|
||||
|
||||
// assert.strictEqual(doc.locationAt(new Position(0, 0)), undefined);
|
||||
// assert.strictEqual(doc.positionAt(SOME_FAKE_LOCATION?), undefined);
|
||||
});
|
||||
|
||||
|
||||
function assertLocation(doc: vscode.NotebookConcatTextDocument, pos: Position, expected: Location, reverse = true) {
|
||||
const actual = doc.locationAt(pos);
|
||||
assert.strictEqual(actual.uri.toString(), expected.uri.toString());
|
||||
assert.strictEqual(actual.range.isEqual(expected.range), true);
|
||||
|
||||
if (reverse) {
|
||||
// reverse - offset
|
||||
const offset = doc.offsetAt(pos);
|
||||
assert.strictEqual(doc.positionAt(offset).isEqual(pos), true);
|
||||
|
||||
// reverse - pos
|
||||
const actualPosition = doc.positionAt(actual);
|
||||
assert.strictEqual(actualPosition.isEqual(pos), true);
|
||||
}
|
||||
}
|
||||
|
||||
function assertLines(doc: vscode.NotebookConcatTextDocument, ...lines: string[]) {
|
||||
let actual = doc.getText().split(/\r\n|\n|\r/);
|
||||
assert.deepStrictEqual(actual, lines);
|
||||
}
|
||||
|
||||
test('contains', function () {
|
||||
|
||||
const cellUri1 = CellUri.generate(notebook.uri, 1);
|
||||
const cellUri2 = CellUri.generate(notebook.uri, 2);
|
||||
|
||||
extHostNotebookDocuments.$acceptModelChanged(notebookUri, new SerializableObjectWithBuffers({
|
||||
versionId: notebook.apiNotebook.version + 1,
|
||||
rawEvents: [{
|
||||
kind: NotebookCellsChangeType.ModelChange,
|
||||
changes: [[0, 0, [{
|
||||
handle: 1,
|
||||
uri: cellUri1,
|
||||
source: ['Hello', 'World', 'Hello World!'],
|
||||
eol: '\n',
|
||||
language: 'test',
|
||||
cellKind: CellKind.Code,
|
||||
outputs: [],
|
||||
}, {
|
||||
handle: 2,
|
||||
uri: cellUri2,
|
||||
source: ['Hallo', 'Welt', 'Hallo Welt!'],
|
||||
eol: '\n',
|
||||
language: 'test',
|
||||
cellKind: CellKind.Code,
|
||||
outputs: [],
|
||||
}]]
|
||||
]
|
||||
}]
|
||||
}), false);
|
||||
|
||||
|
||||
assert.strictEqual(notebook.apiNotebook.cellCount, 1 + 2); // markdown and code
|
||||
|
||||
let doc = new ExtHostNotebookConcatDocument(extHostNotebooks, extHostDocuments, notebook.apiNotebook, undefined);
|
||||
|
||||
assert.strictEqual(doc.contains(cellUri1), true);
|
||||
assert.strictEqual(doc.contains(cellUri2), true);
|
||||
assert.strictEqual(doc.contains(URI.parse('some://miss/path')), false);
|
||||
});
|
||||
|
||||
test('location, position mapping', function () {
|
||||
|
||||
extHostNotebookDocuments.$acceptModelChanged(notebookUri, new SerializableObjectWithBuffers({
|
||||
versionId: notebook.apiNotebook.version + 1,
|
||||
rawEvents: [
|
||||
{
|
||||
kind: NotebookCellsChangeType.ModelChange,
|
||||
changes: [[0, 0, [{
|
||||
handle: 1,
|
||||
uri: CellUri.generate(notebook.uri, 1),
|
||||
source: ['Hello', 'World', 'Hello World!'],
|
||||
eol: '\n',
|
||||
language: 'test',
|
||||
cellKind: CellKind.Code,
|
||||
outputs: [],
|
||||
}, {
|
||||
handle: 2,
|
||||
uri: CellUri.generate(notebook.uri, 2),
|
||||
source: ['Hallo', 'Welt', 'Hallo Welt!'],
|
||||
eol: '\n',
|
||||
language: 'test',
|
||||
cellKind: CellKind.Code,
|
||||
outputs: [],
|
||||
}]]]
|
||||
}
|
||||
]
|
||||
}), false);
|
||||
|
||||
|
||||
assert.strictEqual(notebook.apiNotebook.cellCount, 1 + 2); // markdown and code
|
||||
|
||||
let doc = new ExtHostNotebookConcatDocument(extHostNotebooks, extHostDocuments, notebook.apiNotebook, undefined);
|
||||
assertLines(doc, 'Hello', 'World', 'Hello World!', 'Hallo', 'Welt', 'Hallo Welt!');
|
||||
|
||||
assertLocation(doc, new Position(0, 0), new Location(notebook.apiNotebook.cellAt(0).document.uri, new Position(0, 0)));
|
||||
assertLocation(doc, new Position(4, 0), new Location(notebook.apiNotebook.cellAt(1).document.uri, new Position(1, 0)));
|
||||
assertLocation(doc, new Position(4, 3), new Location(notebook.apiNotebook.cellAt(1).document.uri, new Position(1, 3)));
|
||||
assertLocation(doc, new Position(5, 11), new Location(notebook.apiNotebook.cellAt(1).document.uri, new Position(2, 11)));
|
||||
assertLocation(doc, new Position(5, 12), new Location(notebook.apiNotebook.cellAt(1).document.uri, new Position(2, 11)), false); // don't check identity because position will be clamped
|
||||
});
|
||||
|
||||
|
||||
test('location, position mapping, cell changes', function () {
|
||||
|
||||
let doc = new ExtHostNotebookConcatDocument(extHostNotebooks, extHostDocuments, notebook.apiNotebook, undefined);
|
||||
|
||||
// UPDATE 1
|
||||
extHostNotebookDocuments.$acceptModelChanged(notebookUri, new SerializableObjectWithBuffers({
|
||||
versionId: notebook.apiNotebook.version + 1,
|
||||
rawEvents: [
|
||||
{
|
||||
kind: NotebookCellsChangeType.ModelChange,
|
||||
changes: [[0, 0, [{
|
||||
handle: 1,
|
||||
uri: CellUri.generate(notebook.uri, 1),
|
||||
source: ['Hello', 'World', 'Hello World!'],
|
||||
eol: '\n',
|
||||
language: 'test',
|
||||
cellKind: CellKind.Code,
|
||||
outputs: [],
|
||||
}]]]
|
||||
}
|
||||
]
|
||||
}), false);
|
||||
assert.strictEqual(notebook.apiNotebook.cellCount, 1 + 1);
|
||||
assert.strictEqual(doc.version, 1);
|
||||
assertLines(doc, 'Hello', 'World', 'Hello World!');
|
||||
|
||||
assertLocation(doc, new Position(0, 0), new Location(notebook.apiNotebook.cellAt(0).document.uri, new Position(0, 0)));
|
||||
assertLocation(doc, new Position(2, 2), new Location(notebook.apiNotebook.cellAt(0).document.uri, new Position(2, 2)));
|
||||
assertLocation(doc, new Position(4, 0), new Location(notebook.apiNotebook.cellAt(0).document.uri, new Position(2, 12)), false); // clamped
|
||||
|
||||
|
||||
// UPDATE 2
|
||||
extHostNotebookDocuments.$acceptModelChanged(notebookUri, new SerializableObjectWithBuffers({
|
||||
versionId: notebook.apiNotebook.version + 1,
|
||||
rawEvents: [
|
||||
{
|
||||
kind: NotebookCellsChangeType.ModelChange,
|
||||
changes: [[1, 0, [{
|
||||
handle: 2,
|
||||
uri: CellUri.generate(notebook.uri, 2),
|
||||
source: ['Hallo', 'Welt', 'Hallo Welt!'],
|
||||
eol: '\n',
|
||||
language: 'test',
|
||||
cellKind: CellKind.Code,
|
||||
outputs: [],
|
||||
}]]]
|
||||
}
|
||||
]
|
||||
}), false);
|
||||
|
||||
assert.strictEqual(notebook.apiNotebook.cellCount, 1 + 2);
|
||||
assert.strictEqual(doc.version, 2);
|
||||
assertLines(doc, 'Hello', 'World', 'Hello World!', 'Hallo', 'Welt', 'Hallo Welt!');
|
||||
assertLocation(doc, new Position(0, 0), new Location(notebook.apiNotebook.cellAt(0).document.uri, new Position(0, 0)));
|
||||
assertLocation(doc, new Position(4, 0), new Location(notebook.apiNotebook.cellAt(1).document.uri, new Position(1, 0)));
|
||||
assertLocation(doc, new Position(4, 3), new Location(notebook.apiNotebook.cellAt(1).document.uri, new Position(1, 3)));
|
||||
assertLocation(doc, new Position(5, 11), new Location(notebook.apiNotebook.cellAt(1).document.uri, new Position(2, 11)));
|
||||
assertLocation(doc, new Position(5, 12), new Location(notebook.apiNotebook.cellAt(1).document.uri, new Position(2, 11)), false); // don't check identity because position will be clamped
|
||||
|
||||
// UPDATE 3 (remove cell #2 again)
|
||||
extHostNotebookDocuments.$acceptModelChanged(notebookUri, new SerializableObjectWithBuffers({
|
||||
versionId: notebook.apiNotebook.version + 1,
|
||||
rawEvents: [
|
||||
{
|
||||
kind: NotebookCellsChangeType.ModelChange,
|
||||
changes: [[1, 1, []]]
|
||||
}
|
||||
]
|
||||
}), false);
|
||||
assert.strictEqual(notebook.apiNotebook.cellCount, 1 + 1);
|
||||
assert.strictEqual(doc.version, 3);
|
||||
assertLines(doc, 'Hello', 'World', 'Hello World!');
|
||||
assertLocation(doc, new Position(0, 0), new Location(notebook.apiNotebook.cellAt(0).document.uri, new Position(0, 0)));
|
||||
assertLocation(doc, new Position(2, 2), new Location(notebook.apiNotebook.cellAt(0).document.uri, new Position(2, 2)));
|
||||
assertLocation(doc, new Position(4, 0), new Location(notebook.apiNotebook.cellAt(0).document.uri, new Position(2, 12)), false); // clamped
|
||||
});
|
||||
|
||||
test('location, position mapping, cell-document changes', function () {
|
||||
|
||||
let doc = new ExtHostNotebookConcatDocument(extHostNotebooks, extHostDocuments, notebook.apiNotebook, undefined);
|
||||
|
||||
// UPDATE 1
|
||||
extHostNotebookDocuments.$acceptModelChanged(notebookUri, new SerializableObjectWithBuffers({
|
||||
versionId: notebook.apiNotebook.version + 1,
|
||||
rawEvents: [
|
||||
{
|
||||
|
||||
kind: NotebookCellsChangeType.ModelChange,
|
||||
changes: [[0, 0, [{
|
||||
handle: 1,
|
||||
uri: CellUri.generate(notebook.uri, 1),
|
||||
source: ['Hello', 'World', 'Hello World!'],
|
||||
eol: '\n',
|
||||
language: 'test',
|
||||
cellKind: CellKind.Code,
|
||||
outputs: [],
|
||||
}, {
|
||||
handle: 2,
|
||||
uri: CellUri.generate(notebook.uri, 2),
|
||||
source: ['Hallo', 'Welt', 'Hallo Welt!'],
|
||||
eol: '\n',
|
||||
language: 'test',
|
||||
cellKind: CellKind.Code,
|
||||
outputs: [],
|
||||
}]]]
|
||||
}
|
||||
]
|
||||
}), false);
|
||||
assert.strictEqual(notebook.apiNotebook.cellCount, 1 + 2);
|
||||
assert.strictEqual(doc.version, 1);
|
||||
|
||||
assertLines(doc, 'Hello', 'World', 'Hello World!', 'Hallo', 'Welt', 'Hallo Welt!');
|
||||
assertLocation(doc, new Position(0, 0), new Location(notebook.apiNotebook.cellAt(0).document.uri, new Position(0, 0)));
|
||||
assertLocation(doc, new Position(2, 2), new Location(notebook.apiNotebook.cellAt(0).document.uri, new Position(2, 2)));
|
||||
assertLocation(doc, new Position(2, 12), new Location(notebook.apiNotebook.cellAt(0).document.uri, new Position(2, 12)));
|
||||
assertLocation(doc, new Position(4, 0), new Location(notebook.apiNotebook.cellAt(1).document.uri, new Position(1, 0)));
|
||||
assertLocation(doc, new Position(4, 3), new Location(notebook.apiNotebook.cellAt(1).document.uri, new Position(1, 3)));
|
||||
|
||||
// offset math
|
||||
let cell1End = doc.offsetAt(new Position(2, 12));
|
||||
assert.strictEqual(doc.positionAt(cell1End).isEqual(new Position(2, 12)), true);
|
||||
|
||||
extHostDocuments.$acceptModelChanged(notebook.apiNotebook.cellAt(0).document.uri, {
|
||||
versionId: 0,
|
||||
eol: '\n',
|
||||
changes: [{
|
||||
range: { startLineNumber: 3, startColumn: 1, endLineNumber: 3, endColumn: 6 },
|
||||
rangeLength: 6,
|
||||
rangeOffset: 12,
|
||||
text: 'Hi'
|
||||
}],
|
||||
isRedoing: false,
|
||||
isUndoing: false,
|
||||
}, false);
|
||||
assertLines(doc, 'Hello', 'World', 'Hi World!', 'Hallo', 'Welt', 'Hallo Welt!');
|
||||
assertLocation(doc, new Position(2, 12), new Location(notebook.apiNotebook.cellAt(0).document.uri, new Position(2, 9)), false);
|
||||
|
||||
assert.strictEqual(doc.positionAt(cell1End).isEqual(new Position(3, 2)), true);
|
||||
|
||||
});
|
||||
|
||||
test('selector', function () {
|
||||
|
||||
extHostNotebookDocuments.$acceptModelChanged(notebookUri, new SerializableObjectWithBuffers({
|
||||
versionId: notebook.apiNotebook.version + 1,
|
||||
rawEvents: [
|
||||
{
|
||||
kind: NotebookCellsChangeType.ModelChange,
|
||||
changes: [[0, 0, [{
|
||||
handle: 1,
|
||||
uri: CellUri.generate(notebook.uri, 1),
|
||||
source: ['fooLang-document'],
|
||||
eol: '\n',
|
||||
language: 'fooLang',
|
||||
cellKind: CellKind.Code,
|
||||
outputs: [],
|
||||
}, {
|
||||
handle: 2,
|
||||
uri: CellUri.generate(notebook.uri, 2),
|
||||
source: ['barLang-document'],
|
||||
eol: '\n',
|
||||
language: 'barLang',
|
||||
cellKind: CellKind.Code,
|
||||
outputs: [],
|
||||
}]]]
|
||||
}
|
||||
]
|
||||
}), false);
|
||||
|
||||
const mixedDoc = new ExtHostNotebookConcatDocument(extHostNotebooks, extHostDocuments, notebook.apiNotebook, undefined);
|
||||
const fooLangDoc = new ExtHostNotebookConcatDocument(extHostNotebooks, extHostDocuments, notebook.apiNotebook, 'fooLang');
|
||||
const barLangDoc = new ExtHostNotebookConcatDocument(extHostNotebooks, extHostDocuments, notebook.apiNotebook, 'barLang');
|
||||
|
||||
assertLines(mixedDoc, 'fooLang-document', 'barLang-document');
|
||||
assertLines(fooLangDoc, 'fooLang-document');
|
||||
assertLines(barLangDoc, 'barLang-document');
|
||||
|
||||
extHostNotebookDocuments.$acceptModelChanged(notebookUri, new SerializableObjectWithBuffers({
|
||||
versionId: notebook.apiNotebook.version + 1,
|
||||
rawEvents: [
|
||||
{
|
||||
kind: NotebookCellsChangeType.ModelChange,
|
||||
changes: [[2, 0, [{
|
||||
handle: 3,
|
||||
uri: CellUri.generate(notebook.uri, 3),
|
||||
source: ['barLang-document2'],
|
||||
eol: '\n',
|
||||
language: 'barLang',
|
||||
cellKind: CellKind.Code,
|
||||
outputs: [],
|
||||
}]]]
|
||||
}
|
||||
]
|
||||
}), false);
|
||||
|
||||
assertLines(mixedDoc, 'fooLang-document', 'barLang-document', 'barLang-document2');
|
||||
assertLines(fooLangDoc, 'fooLang-document');
|
||||
assertLines(barLangDoc, 'barLang-document', 'barLang-document2');
|
||||
});
|
||||
|
||||
function assertOffsetAtPosition(doc: vscode.NotebookConcatTextDocument, offset: number, expected: { line: number, character: number }, reverse = true) {
|
||||
const actual = doc.positionAt(offset);
|
||||
|
||||
assert.strictEqual(actual.line, expected.line);
|
||||
assert.strictEqual(actual.character, expected.character);
|
||||
|
||||
if (reverse) {
|
||||
const actualOffset = doc.offsetAt(actual);
|
||||
assert.strictEqual(actualOffset, offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
test('offsetAt(position) <-> positionAt(offset)', function () {
|
||||
|
||||
extHostNotebookDocuments.$acceptModelChanged(notebookUri, new SerializableObjectWithBuffers({
|
||||
versionId: notebook.apiNotebook.version + 1,
|
||||
rawEvents: [
|
||||
{
|
||||
kind: NotebookCellsChangeType.ModelChange,
|
||||
changes: [[0, 0, [{
|
||||
handle: 1,
|
||||
uri: CellUri.generate(notebook.uri, 1),
|
||||
source: ['Hello', 'World', 'Hello World!'],
|
||||
eol: '\n',
|
||||
language: 'test',
|
||||
cellKind: CellKind.Code,
|
||||
outputs: [],
|
||||
}, {
|
||||
handle: 2,
|
||||
uri: CellUri.generate(notebook.uri, 2),
|
||||
source: ['Hallo', 'Welt', 'Hallo Welt!'],
|
||||
eol: '\n',
|
||||
language: 'test',
|
||||
cellKind: CellKind.Code,
|
||||
outputs: [],
|
||||
}]]]
|
||||
}
|
||||
]
|
||||
}), false);
|
||||
|
||||
assert.strictEqual(notebook.apiNotebook.cellCount, 1 + 2); // markdown and code
|
||||
|
||||
let doc = new ExtHostNotebookConcatDocument(extHostNotebooks, extHostDocuments, notebook.apiNotebook, undefined);
|
||||
assertLines(doc, 'Hello', 'World', 'Hello World!', 'Hallo', 'Welt', 'Hallo Welt!');
|
||||
|
||||
assertOffsetAtPosition(doc, 0, { line: 0, character: 0 });
|
||||
assertOffsetAtPosition(doc, 1, { line: 0, character: 1 });
|
||||
assertOffsetAtPosition(doc, 9, { line: 1, character: 3 });
|
||||
assertOffsetAtPosition(doc, 32, { line: 4, character: 1 });
|
||||
assertOffsetAtPosition(doc, 47, { line: 5, character: 11 });
|
||||
});
|
||||
|
||||
|
||||
function assertLocationAtPosition(doc: vscode.NotebookConcatTextDocument, pos: { line: number, character: number }, expected: { uri: URI, line: number, character: number }, reverse = true) {
|
||||
|
||||
const actual = doc.locationAt(new Position(pos.line, pos.character));
|
||||
assert.strictEqual(actual.uri.toString(), expected.uri.toString());
|
||||
assert.strictEqual(actual.range.start.line, expected.line);
|
||||
assert.strictEqual(actual.range.end.line, expected.line);
|
||||
assert.strictEqual(actual.range.start.character, expected.character);
|
||||
assert.strictEqual(actual.range.end.character, expected.character);
|
||||
|
||||
if (reverse) {
|
||||
const actualPos = doc.positionAt(actual);
|
||||
assert.strictEqual(actualPos.line, pos.line);
|
||||
assert.strictEqual(actualPos.character, pos.character);
|
||||
}
|
||||
}
|
||||
|
||||
test('locationAt(position) <-> positionAt(location)', function () {
|
||||
|
||||
extHostNotebookDocuments.$acceptModelChanged(notebookUri, new SerializableObjectWithBuffers({
|
||||
versionId: notebook.apiNotebook.version + 1,
|
||||
rawEvents: [
|
||||
{
|
||||
kind: NotebookCellsChangeType.ModelChange,
|
||||
changes: [[0, 0, [{
|
||||
handle: 1,
|
||||
uri: CellUri.generate(notebook.uri, 1),
|
||||
source: ['Hello', 'World', 'Hello World!'],
|
||||
eol: '\n',
|
||||
language: 'test',
|
||||
cellKind: CellKind.Code,
|
||||
outputs: [],
|
||||
}, {
|
||||
handle: 2,
|
||||
uri: CellUri.generate(notebook.uri, 2),
|
||||
source: ['Hallo', 'Welt', 'Hallo Welt!'],
|
||||
eol: '\n',
|
||||
language: 'test',
|
||||
cellKind: CellKind.Code,
|
||||
outputs: [],
|
||||
}]]]
|
||||
}
|
||||
]
|
||||
}), false);
|
||||
|
||||
assert.strictEqual(notebook.apiNotebook.cellCount, 1 + 2); // markdown and code
|
||||
|
||||
let doc = new ExtHostNotebookConcatDocument(extHostNotebooks, extHostDocuments, notebook.apiNotebook, undefined);
|
||||
assertLines(doc, 'Hello', 'World', 'Hello World!', 'Hallo', 'Welt', 'Hallo Welt!');
|
||||
|
||||
assertLocationAtPosition(doc, { line: 0, character: 0 }, { uri: notebook.apiNotebook.cellAt(0).document.uri, line: 0, character: 0 });
|
||||
assertLocationAtPosition(doc, { line: 2, character: 0 }, { uri: notebook.apiNotebook.cellAt(0).document.uri, line: 2, character: 0 });
|
||||
assertLocationAtPosition(doc, { line: 2, character: 12 }, { uri: notebook.apiNotebook.cellAt(0).document.uri, line: 2, character: 12 });
|
||||
assertLocationAtPosition(doc, { line: 3, character: 0 }, { uri: notebook.apiNotebook.cellAt(1).document.uri, line: 0, character: 0 });
|
||||
assertLocationAtPosition(doc, { line: 5, character: 0 }, { uri: notebook.apiNotebook.cellAt(1).document.uri, line: 2, character: 0 });
|
||||
assertLocationAtPosition(doc, { line: 5, character: 11 }, { uri: notebook.apiNotebook.cellAt(1).document.uri, line: 2, character: 11 });
|
||||
});
|
||||
|
||||
test('getText(range)', function () {
|
||||
|
||||
extHostNotebookDocuments.$acceptModelChanged(notebookUri, new SerializableObjectWithBuffers({
|
||||
versionId: notebook.apiNotebook.version + 1,
|
||||
rawEvents: [
|
||||
{
|
||||
kind: NotebookCellsChangeType.ModelChange,
|
||||
changes: [[0, 0, [{
|
||||
handle: 1,
|
||||
uri: CellUri.generate(notebook.uri, 1),
|
||||
source: ['Hello', 'World', 'Hello World!'],
|
||||
eol: '\n',
|
||||
language: 'test',
|
||||
cellKind: CellKind.Code,
|
||||
outputs: [],
|
||||
}, {
|
||||
handle: 2,
|
||||
uri: CellUri.generate(notebook.uri, 2),
|
||||
source: ['Hallo', 'Welt', 'Hallo Welt!'],
|
||||
eol: '\n',
|
||||
language: 'test',
|
||||
cellKind: CellKind.Code,
|
||||
outputs: [],
|
||||
}, {
|
||||
handle: 3,
|
||||
uri: CellUri.generate(notebook.uri, 3),
|
||||
source: ['Three', 'Drei', 'Drüü'],
|
||||
eol: '\n',
|
||||
language: 'test',
|
||||
cellKind: CellKind.Code,
|
||||
outputs: [],
|
||||
}]]]
|
||||
}
|
||||
]
|
||||
}), false);
|
||||
|
||||
assert.strictEqual(notebook.apiNotebook.cellCount, 1 + 3); // markdown and code
|
||||
|
||||
let doc = new ExtHostNotebookConcatDocument(extHostNotebooks, extHostDocuments, notebook.apiNotebook, undefined);
|
||||
assertLines(doc, 'Hello', 'World', 'Hello World!', 'Hallo', 'Welt', 'Hallo Welt!', 'Three', 'Drei', 'Drüü');
|
||||
|
||||
assert.strictEqual(doc.getText(new Range(0, 0, 0, 0)), '');
|
||||
assert.strictEqual(doc.getText(new Range(0, 0, 1, 0)), 'Hello\n');
|
||||
assert.strictEqual(doc.getText(new Range(2, 0, 4, 0)), 'Hello World!\nHallo\n');
|
||||
assert.strictEqual(doc.getText(new Range(2, 0, 8, 0)), 'Hello World!\nHallo\nWelt\nHallo Welt!\nThree\nDrei\n');
|
||||
});
|
||||
|
||||
test('validateRange/Position', function () {
|
||||
|
||||
extHostNotebookDocuments.$acceptModelChanged(notebookUri, new SerializableObjectWithBuffers({
|
||||
versionId: notebook.apiNotebook.version + 1,
|
||||
rawEvents: [
|
||||
{
|
||||
kind: NotebookCellsChangeType.ModelChange,
|
||||
changes: [[0, 0, [{
|
||||
handle: 1,
|
||||
uri: CellUri.generate(notebook.uri, 1),
|
||||
source: ['Hello', 'World', 'Hello World!'],
|
||||
eol: '\n',
|
||||
language: 'test',
|
||||
cellKind: CellKind.Code,
|
||||
outputs: [],
|
||||
}, {
|
||||
handle: 2,
|
||||
uri: CellUri.generate(notebook.uri, 2),
|
||||
source: ['Hallo', 'Welt', 'Hallo Welt!'],
|
||||
eol: '\n',
|
||||
language: 'test',
|
||||
cellKind: CellKind.Code,
|
||||
outputs: [],
|
||||
}]]]
|
||||
}
|
||||
]
|
||||
}), false);
|
||||
|
||||
assert.strictEqual(notebook.apiNotebook.cellCount, 1 + 2); // markdown and code
|
||||
|
||||
let doc = new ExtHostNotebookConcatDocument(extHostNotebooks, extHostDocuments, notebook.apiNotebook, undefined);
|
||||
assertLines(doc, 'Hello', 'World', 'Hello World!', 'Hallo', 'Welt', 'Hallo Welt!');
|
||||
|
||||
|
||||
function assertPosition(actual: vscode.Position, expectedLine: number, expectedCh: number) {
|
||||
assert.strictEqual(actual.line, expectedLine);
|
||||
assert.strictEqual(actual.character, expectedCh);
|
||||
}
|
||||
|
||||
|
||||
// "fixed"
|
||||
assertPosition(doc.validatePosition(new Position(0, 1000)), 0, 5);
|
||||
assertPosition(doc.validatePosition(new Position(2, 1000)), 2, 12);
|
||||
assertPosition(doc.validatePosition(new Position(5, 1000)), 5, 11);
|
||||
assertPosition(doc.validatePosition(new Position(5000, 1000)), 5, 11);
|
||||
|
||||
// "good"
|
||||
assertPosition(doc.validatePosition(new Position(0, 1)), 0, 1);
|
||||
assertPosition(doc.validatePosition(new Position(0, 5)), 0, 5);
|
||||
assertPosition(doc.validatePosition(new Position(2, 8)), 2, 8);
|
||||
assertPosition(doc.validatePosition(new Position(2, 12)), 2, 12);
|
||||
assertPosition(doc.validatePosition(new Position(5, 11)), 5, 11);
|
||||
|
||||
});
|
||||
});
|
||||
@@ -1,321 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { Barrier } from 'vs/base/common/async';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
import { ICellExecuteUpdateDto, INotebookKernelDto2, MainContext, MainThreadCommandsShape, MainThreadNotebookDocumentsShape, MainThreadNotebookKernelsShape, MainThreadNotebookShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
|
||||
import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook';
|
||||
import { ExtHostNotebookDocument } from 'vs/workbench/api/common/extHostNotebookDocument';
|
||||
import { ExtHostNotebookDocuments } from 'vs/workbench/api/common/extHostNotebookDocuments';
|
||||
import { ExtHostNotebookKernels } from 'vs/workbench/api/common/extHostNotebookKernels';
|
||||
import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
|
||||
import { NotebookCellOutput, NotebookCellOutputItem } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { CellKind, CellUri, NotebookCellsChangeType } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { CellExecutionUpdateType } from 'vs/workbench/contrib/notebook/common/notebookExecutionService';
|
||||
import { nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { SerializableObjectWithBuffers } from 'vs/workbench/services/extensions/common/proxyIdentifier';
|
||||
import { TestRPCProtocol } from 'vs/workbench/test/browser/api/testRPCProtocol';
|
||||
import { mock } from 'vs/workbench/test/common/workbenchTestServices';
|
||||
|
||||
suite.skip('NotebookKernel', function () { // {{SQL CARBON EDIT}} Skip failing VS Notebook tests since we don't use their stuff
|
||||
|
||||
let rpcProtocol: TestRPCProtocol;
|
||||
let extHostNotebookKernels: ExtHostNotebookKernels;
|
||||
let notebook: ExtHostNotebookDocument;
|
||||
let extHostDocumentsAndEditors: ExtHostDocumentsAndEditors;
|
||||
let extHostDocuments: ExtHostDocuments;
|
||||
let extHostNotebooks: ExtHostNotebookController;
|
||||
let extHostNotebookDocuments: ExtHostNotebookDocuments;
|
||||
let extHostCommands: ExtHostCommands;
|
||||
|
||||
const notebookUri = URI.parse('test:///notebook.file');
|
||||
const kernelData = new Map<number, INotebookKernelDto2>();
|
||||
const disposables = new DisposableStore();
|
||||
|
||||
const cellExecuteUpdates: ICellExecuteUpdateDto[] = [];
|
||||
|
||||
teardown(function () {
|
||||
disposables.clear();
|
||||
});
|
||||
setup(async function () {
|
||||
cellExecuteUpdates.length = 0;
|
||||
kernelData.clear();
|
||||
|
||||
rpcProtocol = new TestRPCProtocol();
|
||||
rpcProtocol.set(MainContext.MainThreadCommands, new class extends mock<MainThreadCommandsShape>() {
|
||||
override $registerCommand() { }
|
||||
});
|
||||
rpcProtocol.set(MainContext.MainThreadNotebookKernels, new class extends mock<MainThreadNotebookKernelsShape>() {
|
||||
override async $addKernel(handle: number, data: INotebookKernelDto2): Promise<void> {
|
||||
kernelData.set(handle, data);
|
||||
}
|
||||
override $removeKernel(handle: number) {
|
||||
kernelData.delete(handle);
|
||||
}
|
||||
override $updateKernel(handle: number, data: Partial<INotebookKernelDto2>) {
|
||||
assert.strictEqual(kernelData.has(handle), true);
|
||||
kernelData.set(handle, { ...kernelData.get(handle)!, ...data, });
|
||||
}
|
||||
override $updateExecutions(data: SerializableObjectWithBuffers<ICellExecuteUpdateDto[]>): void {
|
||||
cellExecuteUpdates.push(...data.value);
|
||||
}
|
||||
});
|
||||
rpcProtocol.set(MainContext.MainThreadNotebookDocuments, new class extends mock<MainThreadNotebookDocumentsShape>() {
|
||||
|
||||
});
|
||||
rpcProtocol.set(MainContext.MainThreadNotebook, new class extends mock<MainThreadNotebookShape>() {
|
||||
override async $registerNotebookProvider() { }
|
||||
override async $unregisterNotebookProvider() { }
|
||||
});
|
||||
extHostDocumentsAndEditors = new ExtHostDocumentsAndEditors(rpcProtocol, new NullLogService());
|
||||
extHostDocuments = new ExtHostDocuments(rpcProtocol, extHostDocumentsAndEditors);
|
||||
const extHostStoragePaths = new class extends mock<IExtensionStoragePaths>() {
|
||||
override workspaceValue() {
|
||||
return URI.from({ scheme: 'test', path: generateUuid() });
|
||||
}
|
||||
};
|
||||
extHostCommands = new ExtHostCommands(rpcProtocol, new NullLogService());
|
||||
extHostNotebooks = new ExtHostNotebookController(rpcProtocol, extHostCommands, extHostDocumentsAndEditors, extHostDocuments, extHostStoragePaths);
|
||||
|
||||
extHostNotebookDocuments = new ExtHostNotebookDocuments(new NullLogService(), extHostNotebooks);
|
||||
|
||||
extHostNotebooks.$acceptDocumentAndEditorsDelta(new SerializableObjectWithBuffers({
|
||||
addedDocuments: [{
|
||||
uri: notebookUri,
|
||||
viewType: 'test',
|
||||
versionId: 0,
|
||||
cells: [{
|
||||
handle: 0,
|
||||
uri: CellUri.generate(notebookUri, 0),
|
||||
source: ['### Heading'],
|
||||
eol: '\n',
|
||||
language: 'markdown',
|
||||
cellKind: CellKind.Markup,
|
||||
outputs: [],
|
||||
}, {
|
||||
handle: 1,
|
||||
uri: CellUri.generate(notebookUri, 1),
|
||||
source: ['console.log("aaa")', 'console.log("bbb")'],
|
||||
eol: '\n',
|
||||
language: 'javascript',
|
||||
cellKind: CellKind.Code,
|
||||
outputs: [],
|
||||
}],
|
||||
}],
|
||||
addedEditors: [{
|
||||
documentUri: notebookUri,
|
||||
id: '_notebook_editor_0',
|
||||
selections: [{ start: 0, end: 1 }],
|
||||
visibleRanges: []
|
||||
}]
|
||||
}));
|
||||
extHostNotebooks.$acceptDocumentAndEditorsDelta(new SerializableObjectWithBuffers({ newActiveEditor: '_notebook_editor_0' }));
|
||||
|
||||
notebook = extHostNotebooks.notebookDocuments[0]!;
|
||||
|
||||
disposables.add(notebook);
|
||||
disposables.add(extHostDocuments);
|
||||
|
||||
|
||||
extHostNotebookKernels = new ExtHostNotebookKernels(
|
||||
rpcProtocol,
|
||||
new class extends mock<IExtHostInitDataService>() { },
|
||||
extHostNotebooks,
|
||||
extHostCommands,
|
||||
new NullLogService()
|
||||
);
|
||||
});
|
||||
|
||||
test('create/dispose kernel', async function () {
|
||||
|
||||
const kernel = extHostNotebookKernels.createNotebookController(nullExtensionDescription, 'foo', '*', 'Foo');
|
||||
|
||||
assert.throws(() => (<any>kernel).id = 'dd');
|
||||
assert.throws(() => (<any>kernel).notebookType = 'dd');
|
||||
|
||||
assert.ok(kernel);
|
||||
assert.strictEqual(kernel.id, 'foo');
|
||||
assert.strictEqual(kernel.label, 'Foo');
|
||||
assert.strictEqual(kernel.notebookType, '*');
|
||||
|
||||
await rpcProtocol.sync();
|
||||
assert.strictEqual(kernelData.size, 1);
|
||||
|
||||
let [first] = kernelData.values();
|
||||
assert.strictEqual(first.id, 'nullExtensionDescription/foo');
|
||||
assert.strictEqual(ExtensionIdentifier.equals(first.extensionId, nullExtensionDescription.identifier), true);
|
||||
assert.strictEqual(first.label, 'Foo');
|
||||
assert.strictEqual(first.notebookType, '*');
|
||||
|
||||
kernel.dispose();
|
||||
await rpcProtocol.sync();
|
||||
assert.strictEqual(kernelData.size, 0);
|
||||
});
|
||||
|
||||
test('update kernel', async function () {
|
||||
|
||||
const kernel = extHostNotebookKernels.createNotebookController(nullExtensionDescription, 'foo', '*', 'Foo');
|
||||
|
||||
await rpcProtocol.sync();
|
||||
assert.ok(kernel);
|
||||
|
||||
let [first] = kernelData.values();
|
||||
assert.strictEqual(first.id, 'nullExtensionDescription/foo');
|
||||
assert.strictEqual(first.label, 'Foo');
|
||||
|
||||
kernel.label = 'Far';
|
||||
assert.strictEqual(kernel.label, 'Far');
|
||||
|
||||
await rpcProtocol.sync();
|
||||
[first] = kernelData.values();
|
||||
assert.strictEqual(first.id, 'nullExtensionDescription/foo');
|
||||
assert.strictEqual(first.label, 'Far');
|
||||
});
|
||||
|
||||
test('execute - simple createNotebookCellExecution', function () {
|
||||
const kernel = extHostNotebookKernels.createNotebookController(nullExtensionDescription, 'foo', '*', 'Foo');
|
||||
|
||||
extHostNotebookKernels.$acceptNotebookAssociation(0, notebook.uri, true);
|
||||
|
||||
const cell1 = notebook.apiNotebook.cellAt(0);
|
||||
const task = kernel.createNotebookCellExecution(cell1);
|
||||
task.start();
|
||||
task.end(undefined);
|
||||
});
|
||||
|
||||
test('createNotebookCellExecution, must be selected/associated', function () {
|
||||
const kernel = extHostNotebookKernels.createNotebookController(nullExtensionDescription, 'foo', '*', 'Foo');
|
||||
assert.throws(() => {
|
||||
kernel.createNotebookCellExecution(notebook.apiNotebook.cellAt(0));
|
||||
});
|
||||
|
||||
extHostNotebookKernels.$acceptNotebookAssociation(0, notebook.uri, true);
|
||||
kernel.createNotebookCellExecution(notebook.apiNotebook.cellAt(0));
|
||||
});
|
||||
|
||||
test('createNotebookCellExecution, cell must be alive', function () {
|
||||
const kernel = extHostNotebookKernels.createNotebookController(nullExtensionDescription, 'foo', '*', 'Foo');
|
||||
|
||||
const cell1 = notebook.apiNotebook.cellAt(0);
|
||||
|
||||
extHostNotebookKernels.$acceptNotebookAssociation(0, notebook.uri, true);
|
||||
extHostNotebookDocuments.$acceptModelChanged(notebook.uri, new SerializableObjectWithBuffers({
|
||||
versionId: 12,
|
||||
rawEvents: [{
|
||||
kind: NotebookCellsChangeType.ModelChange,
|
||||
changes: [[0, notebook.apiNotebook.cellCount, []]]
|
||||
}]
|
||||
}), true);
|
||||
|
||||
assert.strictEqual(cell1.index, -1);
|
||||
|
||||
assert.throws(() => {
|
||||
kernel.createNotebookCellExecution(cell1);
|
||||
});
|
||||
});
|
||||
|
||||
test('interrupt handler, cancellation', async function () {
|
||||
|
||||
let interruptCallCount = 0;
|
||||
let tokenCancelCount = 0;
|
||||
|
||||
const kernel = extHostNotebookKernels.createNotebookController(nullExtensionDescription, 'foo', '*', 'Foo');
|
||||
kernel.interruptHandler = () => { interruptCallCount += 1; };
|
||||
extHostNotebookKernels.$acceptNotebookAssociation(0, notebook.uri, true);
|
||||
|
||||
const cell1 = notebook.apiNotebook.cellAt(0);
|
||||
|
||||
const task = kernel.createNotebookCellExecution(cell1);
|
||||
task.token.onCancellationRequested(() => tokenCancelCount += 1);
|
||||
|
||||
await extHostNotebookKernels.$cancelCells(0, notebook.uri, [0]);
|
||||
assert.strictEqual(interruptCallCount, 1);
|
||||
assert.strictEqual(tokenCancelCount, 0);
|
||||
|
||||
await extHostNotebookKernels.$cancelCells(0, notebook.uri, [0]);
|
||||
assert.strictEqual(interruptCallCount, 2);
|
||||
assert.strictEqual(tokenCancelCount, 0);
|
||||
});
|
||||
|
||||
test('set outputs on cancel', async function () {
|
||||
|
||||
const kernel = extHostNotebookKernels.createNotebookController(nullExtensionDescription, 'foo', '*', 'Foo');
|
||||
extHostNotebookKernels.$acceptNotebookAssociation(0, notebook.uri, true);
|
||||
|
||||
const cell1 = notebook.apiNotebook.cellAt(0);
|
||||
const task = kernel.createNotebookCellExecution(cell1);
|
||||
task.start();
|
||||
|
||||
const b = new Barrier();
|
||||
|
||||
task.token.onCancellationRequested(async () => {
|
||||
await task.replaceOutput(new NotebookCellOutput([NotebookCellOutputItem.text('canceled')]));
|
||||
task.end(true);
|
||||
b.open(); // use barrier to signal that cancellation has happened
|
||||
});
|
||||
|
||||
cellExecuteUpdates.length = 0;
|
||||
await extHostNotebookKernels.$cancelCells(0, notebook.uri, [0]);
|
||||
|
||||
await b.wait();
|
||||
|
||||
assert.strictEqual(cellExecuteUpdates.length > 0, true);
|
||||
|
||||
let found = false;
|
||||
for (let edit of cellExecuteUpdates) {
|
||||
if (edit.editType === CellExecutionUpdateType.Output) {
|
||||
assert.strictEqual(edit.append, false);
|
||||
assert.strictEqual(edit.outputs.length, 1);
|
||||
assert.strictEqual(edit.outputs[0].items.length, 1);
|
||||
assert.deepStrictEqual(Array.from(edit.outputs[0].items[0].valueBytes.buffer), Array.from(new TextEncoder().encode('canceled')));
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
assert.ok(found);
|
||||
});
|
||||
|
||||
test('set outputs on interrupt', async function () {
|
||||
|
||||
const kernel = extHostNotebookKernels.createNotebookController(nullExtensionDescription, 'foo', '*', 'Foo');
|
||||
extHostNotebookKernels.$acceptNotebookAssociation(0, notebook.uri, true);
|
||||
|
||||
|
||||
const cell1 = notebook.apiNotebook.cellAt(0);
|
||||
const task = kernel.createNotebookCellExecution(cell1);
|
||||
task.start();
|
||||
|
||||
kernel.interruptHandler = async _notebook => {
|
||||
assert.ok(notebook.apiNotebook === _notebook);
|
||||
await task.replaceOutput(new NotebookCellOutput([NotebookCellOutputItem.text('interrupted')]));
|
||||
task.end(true);
|
||||
};
|
||||
|
||||
cellExecuteUpdates.length = 0;
|
||||
await extHostNotebookKernels.$cancelCells(0, notebook.uri, [0]);
|
||||
|
||||
assert.strictEqual(cellExecuteUpdates.length > 0, true);
|
||||
|
||||
let found = false;
|
||||
for (let edit of cellExecuteUpdates) {
|
||||
if (edit.editType === CellExecutionUpdateType.Output) {
|
||||
assert.strictEqual(edit.append, false);
|
||||
assert.strictEqual(edit.outputs.length, 1);
|
||||
assert.strictEqual(edit.outputs[0].items.length, 1);
|
||||
assert.deepStrictEqual(Array.from(edit.outputs[0].items[0].valueBytes.buffer), Array.from(new TextEncoder().encode('interrupted')));
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
assert.ok(found);
|
||||
});
|
||||
});
|
||||
@@ -1,676 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { Iterable } from 'vs/base/common/iterator';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { mockObject, MockObject } from 'vs/base/test/common/mock';
|
||||
import { MainThreadTestingShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { TestRunCoordinator, TestRunDto, TestRunProfileImpl } from 'vs/workbench/api/common/extHostTesting';
|
||||
import * as convert from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import { Location, Position, Range, TestMessage, TestResultState, TestRunProfileKind, TestRunRequest as TestRunRequestImpl, TestTag } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { TestDiffOpType, TestItemExpandState, TestMessageType } from 'vs/workbench/contrib/testing/common/testCollection';
|
||||
import { TestId } from 'vs/workbench/contrib/testing/common/testId';
|
||||
import { TestItemImpl, testStubs } from 'vs/workbench/contrib/testing/common/testStubs';
|
||||
import { TestSingleUseCollection } from 'vs/workbench/contrib/testing/test/common/ownedTestCollection';
|
||||
import type { TestItem, TestRunRequest } from 'vscode';
|
||||
|
||||
const simplify = (item: TestItem) => ({
|
||||
id: item.id,
|
||||
label: item.label,
|
||||
uri: item.uri,
|
||||
range: item.range,
|
||||
});
|
||||
|
||||
const assertTreesEqual = (a: TestItemImpl | undefined, b: TestItemImpl | undefined) => {
|
||||
if (!a) {
|
||||
throw new assert.AssertionError({ message: 'Expected a to be defined', actual: a });
|
||||
}
|
||||
|
||||
if (!b) {
|
||||
throw new assert.AssertionError({ message: 'Expected b to be defined', actual: b });
|
||||
}
|
||||
|
||||
assert.deepStrictEqual(simplify(a), simplify(b));
|
||||
|
||||
const aChildren = [...a.children].map(c => c.id).sort();
|
||||
const bChildren = [...b.children].map(c => c.id).sort();
|
||||
assert.strictEqual(aChildren.length, bChildren.length, `expected ${a.label}.children.length == ${b.label}.children.length`);
|
||||
aChildren.forEach(key => assertTreesEqual(a.children.get(key) as TestItemImpl, b.children.get(key) as TestItemImpl));
|
||||
};
|
||||
|
||||
// const assertTreeListEqual = (a: ReadonlyArray<TestItem>, b: ReadonlyArray<TestItem>) => {
|
||||
// assert.strictEqual(a.length, b.length, `expected a.length == n.length`);
|
||||
// a.forEach((_, i) => assertTreesEqual(a[i], b[i]));
|
||||
// };
|
||||
|
||||
// class TestMirroredCollection extends MirroredTestCollection {
|
||||
// public changeEvent!: TestChangeEvent;
|
||||
|
||||
// constructor() {
|
||||
// super();
|
||||
// this.onDidChangeTests(evt => this.changeEvent = evt);
|
||||
// }
|
||||
|
||||
// public get length() {
|
||||
// return this.items.size;
|
||||
// }
|
||||
// }
|
||||
|
||||
suite('ExtHost Testing', () => {
|
||||
let single: TestSingleUseCollection;
|
||||
setup(() => {
|
||||
single = testStubs.nested();
|
||||
single.onDidGenerateDiff(d => single.setDiff(d /* don't clear during testing */));
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
single.dispose();
|
||||
});
|
||||
|
||||
suite('OwnedTestCollection', () => {
|
||||
test('adds a root recursively', async () => {
|
||||
await single.expand(single.root.id, Infinity);
|
||||
const a = single.root.children.get('id-a') as TestItemImpl;
|
||||
const b = single.root.children.get('id-b') as TestItemImpl;
|
||||
assert.deepStrictEqual(single.collectDiff(), [
|
||||
[
|
||||
TestDiffOpType.Add,
|
||||
{ controllerId: 'ctrlId', parent: null, expand: TestItemExpandState.BusyExpanding, item: { ...convert.TestItem.from(single.root) } }
|
||||
],
|
||||
[
|
||||
TestDiffOpType.Add,
|
||||
{ controllerId: 'ctrlId', parent: single.root.id, expand: TestItemExpandState.BusyExpanding, item: { ...convert.TestItem.from(a) } }
|
||||
],
|
||||
[
|
||||
TestDiffOpType.Add,
|
||||
{ controllerId: 'ctrlId', parent: new TestId(['ctrlId', 'id-a']).toString(), expand: TestItemExpandState.NotExpandable, item: convert.TestItem.from(a.children.get('id-aa') as TestItemImpl) }
|
||||
],
|
||||
[
|
||||
TestDiffOpType.Add,
|
||||
{ controllerId: 'ctrlId', parent: new TestId(['ctrlId', 'id-a']).toString(), expand: TestItemExpandState.NotExpandable, item: convert.TestItem.from(a.children.get('id-ab') as TestItemImpl) }
|
||||
],
|
||||
[
|
||||
TestDiffOpType.Update,
|
||||
{ extId: new TestId(['ctrlId', 'id-a']).toString(), expand: TestItemExpandState.Expanded }
|
||||
],
|
||||
[
|
||||
TestDiffOpType.Add,
|
||||
{ controllerId: 'ctrlId', parent: single.root.id, expand: TestItemExpandState.NotExpandable, item: convert.TestItem.from(b) }
|
||||
],
|
||||
[
|
||||
TestDiffOpType.Update,
|
||||
{ extId: single.root.id, expand: TestItemExpandState.Expanded }
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
test('parents are set correctly', () => {
|
||||
single.expand(single.root.id, Infinity);
|
||||
single.collectDiff();
|
||||
|
||||
const a = single.root.children.get('id-a')!;
|
||||
const ab = a.children.get('id-ab')!;
|
||||
assert.strictEqual(a.parent, undefined);
|
||||
assert.strictEqual(ab.parent, a);
|
||||
});
|
||||
|
||||
test('no-ops if items not changed', () => {
|
||||
single.collectDiff();
|
||||
assert.deepStrictEqual(single.collectDiff(), []);
|
||||
});
|
||||
|
||||
test('watches property mutations', () => {
|
||||
single.expand(single.root.id, Infinity);
|
||||
single.collectDiff();
|
||||
single.root.children.get('id-a')!.description = 'Hello world'; /* item a */
|
||||
|
||||
assert.deepStrictEqual(single.collectDiff(), [
|
||||
[
|
||||
TestDiffOpType.Update,
|
||||
{ extId: new TestId(['ctrlId', 'id-a']).toString(), item: { description: 'Hello world' } }],
|
||||
]);
|
||||
});
|
||||
|
||||
test('removes children', () => {
|
||||
single.expand(single.root.id, Infinity);
|
||||
single.collectDiff();
|
||||
single.root.children.delete('id-a');
|
||||
|
||||
assert.deepStrictEqual(single.collectDiff(), [
|
||||
[TestDiffOpType.Remove, new TestId(['ctrlId', 'id-a']).toString()],
|
||||
]);
|
||||
assert.deepStrictEqual(
|
||||
[...single.tree.keys()].sort(),
|
||||
[single.root.id, new TestId(['ctrlId', 'id-b']).toString()],
|
||||
);
|
||||
assert.strictEqual(single.tree.size, 2);
|
||||
});
|
||||
|
||||
test('adds new children', () => {
|
||||
single.expand(single.root.id, Infinity);
|
||||
single.collectDiff();
|
||||
const child = new TestItemImpl('ctrlId', 'id-ac', 'c', undefined);
|
||||
single.root.children.get('id-a')!.children.add(child);
|
||||
|
||||
assert.deepStrictEqual(single.collectDiff(), [
|
||||
[TestDiffOpType.Add, {
|
||||
controllerId: 'ctrlId',
|
||||
parent: new TestId(['ctrlId', 'id-a']).toString(),
|
||||
expand: TestItemExpandState.NotExpandable,
|
||||
item: convert.TestItem.from(child),
|
||||
}],
|
||||
]);
|
||||
assert.deepStrictEqual(
|
||||
[...single.tree.values()].map(n => n.actual.id).sort(),
|
||||
[single.root.id, 'id-a', 'id-aa', 'id-ab', 'id-ac', 'id-b'],
|
||||
);
|
||||
assert.strictEqual(single.tree.size, 6);
|
||||
});
|
||||
|
||||
test('manages tags correctly', () => {
|
||||
single.expand(single.root.id, Infinity);
|
||||
single.collectDiff();
|
||||
const tag1 = new TestTag('tag1');
|
||||
const tag2 = new TestTag('tag2');
|
||||
const tag3 = new TestTag('tag3');
|
||||
const child = new TestItemImpl('ctrlId', 'id-ac', 'c', undefined);
|
||||
child.tags = [tag1, tag2];
|
||||
single.root.children.get('id-a')!.children.add(child);
|
||||
|
||||
assert.deepStrictEqual(single.collectDiff(), [
|
||||
[TestDiffOpType.AddTag, { ctrlLabel: 'root', id: 'ctrlId\0tag1' }],
|
||||
[TestDiffOpType.AddTag, { ctrlLabel: 'root', id: 'ctrlId\0tag2' }],
|
||||
[TestDiffOpType.Add, {
|
||||
controllerId: 'ctrlId',
|
||||
parent: new TestId(['ctrlId', 'id-a']).toString(),
|
||||
expand: TestItemExpandState.NotExpandable,
|
||||
item: convert.TestItem.from(child),
|
||||
}],
|
||||
]);
|
||||
|
||||
child.tags = [tag2, tag3];
|
||||
assert.deepStrictEqual(single.collectDiff(), [
|
||||
[TestDiffOpType.AddTag, { ctrlLabel: 'root', id: 'ctrlId\0tag3' }],
|
||||
[TestDiffOpType.Update, {
|
||||
extId: new TestId(['ctrlId', 'id-a', 'id-ac']).toString(),
|
||||
item: { tags: ['ctrlId\0tag2', 'ctrlId\0tag3'] }
|
||||
}],
|
||||
[TestDiffOpType.RemoveTag, 'ctrlId\0tag1'],
|
||||
]);
|
||||
|
||||
const a = single.root.children.get('id-a')!;
|
||||
a.tags = [tag2];
|
||||
a.children.replace([]);
|
||||
assert.deepStrictEqual(single.collectDiff().filter(t => t[0] === TestDiffOpType.RemoveTag), [
|
||||
[TestDiffOpType.RemoveTag, 'ctrlId\0tag3'],
|
||||
]);
|
||||
});
|
||||
|
||||
test('treats in-place replacement as mutation', () => {
|
||||
single.expand(single.root.id, Infinity);
|
||||
single.collectDiff();
|
||||
|
||||
const oldA = single.root.children.get('id-a') as TestItemImpl;
|
||||
const newA = new TestItemImpl('ctrlId', 'id-a', 'Hello world', undefined);
|
||||
newA.children.replace([...oldA.children]);
|
||||
single.root.children.replace([
|
||||
newA,
|
||||
new TestItemImpl('ctrlId', 'id-b', single.root.children.get('id-b')!.label, undefined),
|
||||
]);
|
||||
|
||||
assert.deepStrictEqual(single.collectDiff(), [
|
||||
[
|
||||
TestDiffOpType.Update,
|
||||
{ extId: new TestId(['ctrlId', 'id-a']).toString(), expand: TestItemExpandState.Expanded, item: { label: 'Hello world' } },
|
||||
],
|
||||
]);
|
||||
|
||||
newA.label = 'still connected';
|
||||
assert.deepStrictEqual(single.collectDiff(), [
|
||||
[
|
||||
TestDiffOpType.Update,
|
||||
{ extId: new TestId(['ctrlId', 'id-a']).toString(), item: { label: 'still connected' } }
|
||||
],
|
||||
]);
|
||||
|
||||
oldA.label = 'no longer connected';
|
||||
assert.deepStrictEqual(single.collectDiff(), []);
|
||||
});
|
||||
|
||||
test('treats in-place replacement as mutation deeply', () => {
|
||||
single.expand(single.root.id, Infinity);
|
||||
single.collectDiff();
|
||||
|
||||
const oldA = single.root.children.get('id-a')!;
|
||||
const newA = new TestItemImpl('ctrlId', 'id-a', single.root.children.get('id-a')!.label, undefined);
|
||||
const oldAA = oldA.children.get('id-aa')!;
|
||||
const oldAB = oldA.children.get('id-ab')!;
|
||||
const newAB = new TestItemImpl('ctrlId', 'id-ab', 'Hello world', undefined);
|
||||
newA.children.replace([oldAA, newAB]);
|
||||
single.root.children.replace([newA, single.root.children.get('id-b')!]);
|
||||
|
||||
assert.deepStrictEqual(single.collectDiff(), [
|
||||
[
|
||||
TestDiffOpType.Update,
|
||||
{ extId: new TestId(['ctrlId', 'id-a']).toString(), expand: TestItemExpandState.Expanded },
|
||||
],
|
||||
[
|
||||
TestDiffOpType.Update,
|
||||
{ extId: TestId.fromExtHostTestItem(oldAB, 'ctrlId').toString(), item: { label: 'Hello world' } },
|
||||
],
|
||||
]);
|
||||
|
||||
oldAA.label = 'still connected1';
|
||||
newAB.label = 'still connected2';
|
||||
oldAB.label = 'not connected3';
|
||||
assert.deepStrictEqual(single.collectDiff(), [
|
||||
[
|
||||
TestDiffOpType.Update,
|
||||
{ extId: new TestId(['ctrlId', 'id-a', 'id-aa']).toString(), item: { label: 'still connected1' } }
|
||||
],
|
||||
[
|
||||
TestDiffOpType.Update,
|
||||
{ extId: new TestId(['ctrlId', 'id-a', 'id-ab']).toString(), item: { label: 'still connected2' } }
|
||||
],
|
||||
]);
|
||||
|
||||
assert.strictEqual(newAB.parent, newA);
|
||||
assert.strictEqual(oldAA.parent, newA);
|
||||
assert.deepStrictEqual(newA.parent, undefined);
|
||||
});
|
||||
|
||||
test('moves an item to be a new child', async () => {
|
||||
await single.expand(single.root.id, 0);
|
||||
single.collectDiff();
|
||||
const b = single.root.children.get('id-b') as TestItemImpl;
|
||||
const a = single.root.children.get('id-a') as TestItemImpl;
|
||||
a.children.add(b);
|
||||
assert.deepStrictEqual(single.collectDiff(), [
|
||||
[
|
||||
TestDiffOpType.Remove,
|
||||
new TestId(['ctrlId', 'id-b']).toString(),
|
||||
],
|
||||
[
|
||||
TestDiffOpType.Add,
|
||||
{ controllerId: 'ctrlId', parent: new TestId(['ctrlId', 'id-a']).toString(), expand: TestItemExpandState.NotExpandable, item: convert.TestItem.from(b) }
|
||||
],
|
||||
]);
|
||||
|
||||
b.label = 'still connected';
|
||||
assert.deepStrictEqual(single.collectDiff(), [
|
||||
[
|
||||
TestDiffOpType.Update,
|
||||
{ extId: new TestId(['ctrlId', 'id-a', 'id-b']).toString(), item: { label: 'still connected' } }
|
||||
],
|
||||
]);
|
||||
|
||||
assert.deepStrictEqual([...single.root.children], [single.root.children.get('id-a')]);
|
||||
assert.deepStrictEqual(b.parent, a);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
suite('MirroredTestCollection', () => {
|
||||
// todo@connor4312: re-renable when we figure out what observing looks like we async children
|
||||
// let m: TestMirroredCollection;
|
||||
// setup(() => m = new TestMirroredCollection());
|
||||
|
||||
// test('mirrors creation of the root', () => {
|
||||
// const tests = testStubs.nested();
|
||||
// single.addRoot(tests, 'pid');
|
||||
// single.expand(single.root.id, Infinity);
|
||||
// m.apply(single.collectDiff());
|
||||
// assertTreesEqual(m.rootTestItems[0], owned.getTestById(single.root.id)![1].actual);
|
||||
// assert.strictEqual(m.length, single.itemToInternal.size);
|
||||
// });
|
||||
|
||||
// test('mirrors node deletion', () => {
|
||||
// const tests = testStubs.nested();
|
||||
// single.addRoot(tests, 'pid');
|
||||
// m.apply(single.collectDiff());
|
||||
// single.expand(single.root.id, Infinity);
|
||||
// tests.children!.splice(0, 1);
|
||||
// single.onItemChange(tests, 'pid');
|
||||
// single.expand(single.root.id, Infinity);
|
||||
// m.apply(single.collectDiff());
|
||||
|
||||
// assertTreesEqual(m.rootTestItems[0], owned.getTestById(single.root.id)![1].actual);
|
||||
// assert.strictEqual(m.length, single.itemToInternal.size);
|
||||
// });
|
||||
|
||||
// test('mirrors node addition', () => {
|
||||
// const tests = testStubs.nested();
|
||||
// single.addRoot(tests, 'pid');
|
||||
// m.apply(single.collectDiff());
|
||||
// tests.children![0].children!.push(stubTest('ac'));
|
||||
// single.onItemChange(tests, 'pid');
|
||||
// m.apply(single.collectDiff());
|
||||
|
||||
// assertTreesEqual(m.rootTestItems[0], owned.getTestById(single.root.id)![1].actual);
|
||||
// assert.strictEqual(m.length, single.itemToInternal.size);
|
||||
// });
|
||||
|
||||
// test('mirrors node update', () => {
|
||||
// const tests = testStubs.nested();
|
||||
// single.addRoot(tests, 'pid');
|
||||
// m.apply(single.collectDiff());
|
||||
// tests.children![0].description = 'Hello world'; /* item a */
|
||||
// single.onItemChange(tests, 'pid');
|
||||
// m.apply(single.collectDiff());
|
||||
|
||||
// assertTreesEqual(m.rootTestItems[0], owned.getTestById(single.root.id)![1].actual);
|
||||
// });
|
||||
|
||||
// suite('MirroredChangeCollector', () => {
|
||||
// let tests = testStubs.nested();
|
||||
// setup(() => {
|
||||
// tests = testStubs.nested();
|
||||
// single.addRoot(tests, 'pid');
|
||||
// m.apply(single.collectDiff());
|
||||
// });
|
||||
|
||||
// test('creates change for root', () => {
|
||||
// assertTreeListEqual(m.changeEvent.added, [
|
||||
// tests,
|
||||
// tests.children[0],
|
||||
// tests.children![0].children![0],
|
||||
// tests.children![0].children![1],
|
||||
// tests.children[1],
|
||||
// ]);
|
||||
// assertTreeListEqual(m.changeEvent.removed, []);
|
||||
// assertTreeListEqual(m.changeEvent.updated, []);
|
||||
// });
|
||||
|
||||
// test('creates change for delete', () => {
|
||||
// const rm = tests.children.shift()!;
|
||||
// single.onItemChange(tests, 'pid');
|
||||
// m.apply(single.collectDiff());
|
||||
|
||||
// assertTreeListEqual(m.changeEvent.added, []);
|
||||
// assertTreeListEqual(m.changeEvent.removed, [
|
||||
// { ...rm },
|
||||
// { ...rm.children![0] },
|
||||
// { ...rm.children![1] },
|
||||
// ]);
|
||||
// assertTreeListEqual(m.changeEvent.updated, []);
|
||||
// });
|
||||
|
||||
// test('creates change for update', () => {
|
||||
// tests.children[0].label = 'updated!';
|
||||
// single.onItemChange(tests, 'pid');
|
||||
// m.apply(single.collectDiff());
|
||||
|
||||
// assertTreeListEqual(m.changeEvent.added, []);
|
||||
// assertTreeListEqual(m.changeEvent.removed, []);
|
||||
// assertTreeListEqual(m.changeEvent.updated, [tests.children[0]]);
|
||||
// });
|
||||
|
||||
// test('is a no-op if a node is added and removed', () => {
|
||||
// const nested = testStubs.nested('id2-');
|
||||
// tests.children.push(nested);
|
||||
// single.onItemChange(tests, 'pid');
|
||||
// tests.children.pop();
|
||||
// single.onItemChange(tests, 'pid');
|
||||
// const previousEvent = m.changeEvent;
|
||||
// m.apply(single.collectDiff());
|
||||
// assert.strictEqual(m.changeEvent, previousEvent);
|
||||
// });
|
||||
|
||||
// test('is a single-op if a node is added and changed', () => {
|
||||
// const child = stubTest('c');
|
||||
// tests.children.push(child);
|
||||
// single.onItemChange(tests, 'pid');
|
||||
// child.label = 'd';
|
||||
// single.onItemChange(tests, 'pid');
|
||||
// m.apply(single.collectDiff());
|
||||
|
||||
// assertTreeListEqual(m.changeEvent.added, [child]);
|
||||
// assertTreeListEqual(m.changeEvent.removed, []);
|
||||
// assertTreeListEqual(m.changeEvent.updated, []);
|
||||
// });
|
||||
|
||||
// test('gets the common ancestor (1)', () => {
|
||||
// tests.children![0].children![0].label = 'za';
|
||||
// tests.children![0].children![1].label = 'zb';
|
||||
// single.onItemChange(tests, 'pid');
|
||||
// m.apply(single.collectDiff());
|
||||
|
||||
// });
|
||||
|
||||
// test('gets the common ancestor (2)', () => {
|
||||
// tests.children![0].children![0].label = 'za';
|
||||
// tests.children![1].label = 'ab';
|
||||
// single.onItemChange(tests, 'pid');
|
||||
// m.apply(single.collectDiff());
|
||||
// });
|
||||
// });
|
||||
});
|
||||
|
||||
suite('TestRunTracker', () => {
|
||||
let proxy: MockObject<MainThreadTestingShape>;
|
||||
let c: TestRunCoordinator;
|
||||
let cts: CancellationTokenSource;
|
||||
let configuration: TestRunProfileImpl;
|
||||
|
||||
let req: TestRunRequest;
|
||||
|
||||
let dto: TestRunDto;
|
||||
|
||||
setup(async () => {
|
||||
proxy = mockObject();
|
||||
cts = new CancellationTokenSource();
|
||||
c = new TestRunCoordinator(proxy);
|
||||
|
||||
configuration = new TestRunProfileImpl(mockObject<MainThreadTestingShape, {}>(), 'ctrlId', 42, 'Do Run', TestRunProfileKind.Run, () => { }, false);
|
||||
|
||||
await single.expand(single.root.id, Infinity);
|
||||
single.collectDiff();
|
||||
|
||||
req = {
|
||||
include: undefined,
|
||||
exclude: [single.root.children.get('id-b')!],
|
||||
profile: configuration,
|
||||
};
|
||||
|
||||
dto = TestRunDto.fromInternal({
|
||||
controllerId: 'ctrl',
|
||||
profileId: configuration.profileId,
|
||||
excludeExtIds: ['id-b'],
|
||||
runId: 'run-id',
|
||||
testIds: [single.root.id],
|
||||
}, single);
|
||||
});
|
||||
|
||||
test('tracks a run started from a main thread request', () => {
|
||||
const tracker = c.prepareForMainThreadTestRun(req, dto, cts.token);
|
||||
assert.strictEqual(tracker.isRunning, false);
|
||||
|
||||
const task1 = c.createTestRun('ctrl', single, req, 'run1', true);
|
||||
const task2 = c.createTestRun('ctrl', single, req, 'run2', true);
|
||||
assert.strictEqual(proxy.$startedExtensionTestRun.called, false);
|
||||
assert.strictEqual(tracker.isRunning, true);
|
||||
|
||||
task1.appendOutput('hello');
|
||||
const taskId = proxy.$appendOutputToRun.args[0]?.[1];
|
||||
assert.deepStrictEqual([['run-id', taskId, VSBuffer.fromString('hello'), undefined, undefined]], proxy.$appendOutputToRun.args);
|
||||
task1.end();
|
||||
|
||||
assert.strictEqual(proxy.$finishedExtensionTestRun.called, false);
|
||||
assert.strictEqual(tracker.isRunning, true);
|
||||
|
||||
task2.end();
|
||||
|
||||
assert.strictEqual(proxy.$finishedExtensionTestRun.called, false);
|
||||
assert.strictEqual(tracker.isRunning, false);
|
||||
});
|
||||
|
||||
test('tracks a run started from an extension request', () => {
|
||||
const task1 = c.createTestRun('ctrl', single, req, 'hello world', false);
|
||||
|
||||
const tracker = Iterable.first(c.trackers)!;
|
||||
assert.strictEqual(tracker.isRunning, true);
|
||||
assert.deepStrictEqual(proxy.$startedExtensionTestRun.args, [
|
||||
[{
|
||||
profile: { group: 2, id: 42 },
|
||||
controllerId: 'ctrl',
|
||||
id: tracker.id,
|
||||
include: [single.root.id],
|
||||
exclude: ['id-b'],
|
||||
persist: false,
|
||||
}]
|
||||
]);
|
||||
|
||||
const task2 = c.createTestRun('ctrl', single, req, 'run2', true);
|
||||
const task3Detached = c.createTestRun('ctrl', single, { ...req }, 'task3Detached', true);
|
||||
|
||||
task1.end();
|
||||
assert.strictEqual(proxy.$finishedExtensionTestRun.called, false);
|
||||
assert.strictEqual(tracker.isRunning, true);
|
||||
|
||||
task2.end();
|
||||
assert.deepStrictEqual(proxy.$finishedExtensionTestRun.args, [[tracker.id]]);
|
||||
assert.strictEqual(tracker.isRunning, false);
|
||||
|
||||
task3Detached.end();
|
||||
});
|
||||
|
||||
test('adds tests to run smartly', () => {
|
||||
const task1 = c.createTestRun('ctrlId', single, req, 'hello world', false);
|
||||
const tracker = Iterable.first(c.trackers)!;
|
||||
const expectedArgs: unknown[][] = [];
|
||||
assert.deepStrictEqual(proxy.$addTestsToRun.args, expectedArgs);
|
||||
|
||||
task1.passed(single.root.children.get('id-a')!.children.get('id-aa')!);
|
||||
expectedArgs.push([
|
||||
'ctrlId',
|
||||
tracker.id,
|
||||
[
|
||||
convert.TestItem.from(single.root),
|
||||
convert.TestItem.from(single.root.children.get('id-a') as TestItemImpl),
|
||||
convert.TestItem.from(single.root.children.get('id-a')!.children.get('id-aa') as TestItemImpl),
|
||||
]
|
||||
]);
|
||||
assert.deepStrictEqual(proxy.$addTestsToRun.args, expectedArgs);
|
||||
|
||||
task1.enqueued(single.root.children.get('id-a')!.children.get('id-ab')!);
|
||||
expectedArgs.push([
|
||||
'ctrlId',
|
||||
tracker.id,
|
||||
[
|
||||
convert.TestItem.from(single.root.children.get('id-a') as TestItemImpl),
|
||||
convert.TestItem.from(single.root.children.get('id-a')!.children.get('id-ab') as TestItemImpl),
|
||||
],
|
||||
]);
|
||||
assert.deepStrictEqual(proxy.$addTestsToRun.args, expectedArgs);
|
||||
|
||||
task1.passed(single.root.children.get('id-a')!.children.get('id-ab')!);
|
||||
assert.deepStrictEqual(proxy.$addTestsToRun.args, expectedArgs);
|
||||
});
|
||||
|
||||
test('adds test messages to run', () => {
|
||||
const test1 = new TestItemImpl('ctrlId', 'id-c', 'test c', URI.file('/testc.txt'));
|
||||
const test2 = new TestItemImpl('ctrlId', 'id-d', 'test d', URI.file('/testd.txt'));
|
||||
test1.range = test2.range = new Range(new Position(0, 0), new Position(1, 0));
|
||||
single.root.children.replace([test1, test2]);
|
||||
const task = c.createTestRun('ctrlId', single, req, 'hello world', false);
|
||||
|
||||
const message1 = new TestMessage('some message');
|
||||
message1.location = new Location(URI.file('/a.txt'), new Position(0, 0));
|
||||
task.failed(test1, message1);
|
||||
|
||||
const args = proxy.$appendTestMessagesInRun.args[0];
|
||||
assert.deepStrictEqual(proxy.$appendTestMessagesInRun.args[0], [
|
||||
args[0],
|
||||
args[1],
|
||||
new TestId(['ctrlId', 'id-c']).toString(),
|
||||
[{
|
||||
message: 'some message',
|
||||
type: TestMessageType.Error,
|
||||
expected: undefined,
|
||||
actual: undefined,
|
||||
location: convert.location.from(message1.location)
|
||||
}]
|
||||
]);
|
||||
|
||||
// should use test location as default
|
||||
task.failed(test2, new TestMessage('some message'));
|
||||
assert.deepStrictEqual(proxy.$appendTestMessagesInRun.args[1], [
|
||||
args[0],
|
||||
args[1],
|
||||
new TestId(['ctrlId', 'id-d']).toString(),
|
||||
[{
|
||||
message: 'some message',
|
||||
type: TestMessageType.Error,
|
||||
expected: undefined,
|
||||
actual: undefined,
|
||||
location: convert.location.from({ uri: test2.uri!, range: test2.range! }),
|
||||
}]
|
||||
]);
|
||||
});
|
||||
|
||||
test('guards calls after runs are ended', () => {
|
||||
const task = c.createTestRun('ctrl', single, req, 'hello world', false);
|
||||
task.end();
|
||||
|
||||
task.failed(single.root, new TestMessage('some message'));
|
||||
task.appendOutput('output');
|
||||
|
||||
assert.strictEqual(proxy.$addTestsToRun.called, false);
|
||||
assert.strictEqual(proxy.$appendOutputToRun.called, false);
|
||||
assert.strictEqual(proxy.$appendTestMessagesInRun.called, false);
|
||||
});
|
||||
|
||||
test('excludes tests outside tree or explicitly excluded', () => {
|
||||
const task = c.createTestRun('ctrlId', single, {
|
||||
profile: configuration,
|
||||
include: [single.root.children.get('id-a')!],
|
||||
exclude: [single.root.children.get('id-a')!.children.get('id-aa')!],
|
||||
}, 'hello world', false);
|
||||
|
||||
task.passed(single.root.children.get('id-a')!.children.get('id-aa')!);
|
||||
task.passed(single.root.children.get('id-a')!.children.get('id-ab')!);
|
||||
|
||||
assert.deepStrictEqual(proxy.$updateTestStateInRun.args.length, 1);
|
||||
const args = proxy.$updateTestStateInRun.args[0];
|
||||
assert.deepStrictEqual(proxy.$updateTestStateInRun.args, [[
|
||||
args[0],
|
||||
args[1],
|
||||
new TestId(['ctrlId', 'id-a', 'id-ab']).toString(),
|
||||
TestResultState.Passed,
|
||||
undefined,
|
||||
]]);
|
||||
});
|
||||
|
||||
test('sets state of test with identical local IDs (#131827)', () => {
|
||||
const testA = single.root.children.get('id-a');
|
||||
const testB = single.root.children.get('id-b');
|
||||
const childA = new TestItemImpl('ctrlId', 'id-child', 'child', undefined);
|
||||
testA!.children.replace([childA]);
|
||||
const childB = new TestItemImpl('ctrlId', 'id-child', 'child', undefined);
|
||||
testB!.children.replace([childB]);
|
||||
|
||||
const task1 = c.createTestRun('ctrl', single, new TestRunRequestImpl(), 'hello world', false);
|
||||
const tracker = Iterable.first(c.trackers)!;
|
||||
|
||||
task1.passed(childA);
|
||||
task1.passed(childB);
|
||||
assert.deepStrictEqual(proxy.$addTestsToRun.args, [
|
||||
[
|
||||
'ctrl',
|
||||
tracker.id,
|
||||
[single.root, testA, childA].map(t => convert.TestItem.from(t as TestItemImpl)),
|
||||
],
|
||||
[
|
||||
'ctrl',
|
||||
tracker.id,
|
||||
[single.root, testB, childB].map(t => convert.TestItem.from(t as TestItemImpl)),
|
||||
],
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,370 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { TextEditorLineNumbersStyle, Range } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { TextEditorCursorStyle, RenderLineNumbersType } from 'vs/editor/common/config/editorOptions';
|
||||
import { MainThreadTextEditorsShape, IResolvedTextEditorConfiguration, ITextEditorConfigurationUpdate } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostTextEditorOptions, ExtHostTextEditor } from 'vs/workbench/api/common/extHostTextEditor';
|
||||
import { ExtHostDocumentData } from 'vs/workbench/api/common/extHostDocumentData';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { mock } from 'vs/base/test/common/mock';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
import { Lazy } from 'vs/base/common/lazy';
|
||||
|
||||
suite('ExtHostTextEditor', () => {
|
||||
|
||||
let editor: ExtHostTextEditor;
|
||||
let doc = new ExtHostDocumentData(undefined!, URI.file(''), [
|
||||
'aaaa bbbb+cccc abc'
|
||||
], '\n', 1, 'text', false);
|
||||
|
||||
setup(() => {
|
||||
editor = new ExtHostTextEditor('fake', null!, new NullLogService(), new Lazy(() => doc.document), [], { cursorStyle: 0, insertSpaces: true, lineNumbers: 1, tabSize: 4 }, [], 1);
|
||||
});
|
||||
|
||||
test('disposed editor', () => {
|
||||
|
||||
assert.ok(editor.value.document);
|
||||
editor._acceptViewColumn(3);
|
||||
assert.strictEqual(3, editor.value.viewColumn);
|
||||
|
||||
editor.dispose();
|
||||
|
||||
assert.throws(() => editor._acceptViewColumn(2));
|
||||
assert.strictEqual(3, editor.value.viewColumn);
|
||||
|
||||
assert.ok(editor.value.document);
|
||||
assert.throws(() => editor._acceptOptions(null!));
|
||||
assert.throws(() => editor._acceptSelections([]));
|
||||
});
|
||||
|
||||
test('API [bug]: registerTextEditorCommand clears redo stack even if no edits are made #55163', async function () {
|
||||
let applyCount = 0;
|
||||
let editor = new ExtHostTextEditor('edt1',
|
||||
new class extends mock<MainThreadTextEditorsShape>() {
|
||||
override $tryApplyEdits(): Promise<boolean> {
|
||||
applyCount += 1;
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
}, new NullLogService(), new Lazy(() => doc.document), [], { cursorStyle: 0, insertSpaces: true, lineNumbers: 1, tabSize: 4 }, [], 1);
|
||||
|
||||
await editor.value.edit(edit => { });
|
||||
assert.strictEqual(applyCount, 0);
|
||||
|
||||
await editor.value.edit(edit => { edit.setEndOfLine(1); });
|
||||
assert.strictEqual(applyCount, 1);
|
||||
|
||||
await editor.value.edit(edit => { edit.delete(new Range(0, 0, 1, 1)); });
|
||||
assert.strictEqual(applyCount, 2);
|
||||
});
|
||||
});
|
||||
|
||||
suite('ExtHostTextEditorOptions', () => {
|
||||
|
||||
let opts: ExtHostTextEditorOptions;
|
||||
let calls: ITextEditorConfigurationUpdate[] = [];
|
||||
|
||||
setup(() => {
|
||||
calls = [];
|
||||
let mockProxy: MainThreadTextEditorsShape = {
|
||||
dispose: undefined!,
|
||||
$trySetOptions: (id: string, options: ITextEditorConfigurationUpdate) => {
|
||||
assert.strictEqual(id, '1');
|
||||
calls.push(options);
|
||||
return Promise.resolve(undefined);
|
||||
},
|
||||
$tryShowTextDocument: undefined!,
|
||||
$registerTextEditorDecorationType: undefined!,
|
||||
$removeTextEditorDecorationType: undefined!,
|
||||
$tryShowEditor: undefined!,
|
||||
$tryHideEditor: undefined!,
|
||||
$trySetDecorations: undefined!,
|
||||
$trySetDecorationsFast: undefined!,
|
||||
$tryRevealRange: undefined!,
|
||||
$trySetSelections: undefined!,
|
||||
$tryApplyEdits: undefined!,
|
||||
$tryInsertSnippet: undefined!,
|
||||
$getDiffInformation: undefined!
|
||||
};
|
||||
opts = new ExtHostTextEditorOptions(mockProxy, '1', {
|
||||
tabSize: 4,
|
||||
insertSpaces: false,
|
||||
cursorStyle: TextEditorCursorStyle.Line,
|
||||
lineNumbers: RenderLineNumbersType.On
|
||||
}, new NullLogService());
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
opts = null!;
|
||||
calls = null!;
|
||||
});
|
||||
|
||||
function assertState(opts: ExtHostTextEditorOptions, expected: IResolvedTextEditorConfiguration): void {
|
||||
let actual = {
|
||||
tabSize: opts.value.tabSize,
|
||||
insertSpaces: opts.value.insertSpaces,
|
||||
cursorStyle: opts.value.cursorStyle,
|
||||
lineNumbers: opts.value.lineNumbers
|
||||
};
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
}
|
||||
|
||||
test('can set tabSize to the same value', () => {
|
||||
opts.value.tabSize = 4;
|
||||
assertState(opts, {
|
||||
tabSize: 4,
|
||||
insertSpaces: false,
|
||||
cursorStyle: TextEditorCursorStyle.Line,
|
||||
lineNumbers: RenderLineNumbersType.On
|
||||
});
|
||||
assert.deepStrictEqual(calls, []);
|
||||
});
|
||||
|
||||
test('can change tabSize to positive integer', () => {
|
||||
opts.value.tabSize = 1;
|
||||
assertState(opts, {
|
||||
tabSize: 1,
|
||||
insertSpaces: false,
|
||||
cursorStyle: TextEditorCursorStyle.Line,
|
||||
lineNumbers: RenderLineNumbersType.On
|
||||
});
|
||||
assert.deepStrictEqual(calls, [{ tabSize: 1 }]);
|
||||
});
|
||||
|
||||
test('can change tabSize to positive float', () => {
|
||||
opts.value.tabSize = 2.3;
|
||||
assertState(opts, {
|
||||
tabSize: 2,
|
||||
insertSpaces: false,
|
||||
cursorStyle: TextEditorCursorStyle.Line,
|
||||
lineNumbers: RenderLineNumbersType.On
|
||||
});
|
||||
assert.deepStrictEqual(calls, [{ tabSize: 2 }]);
|
||||
});
|
||||
|
||||
test('can change tabSize to a string number', () => {
|
||||
opts.value.tabSize = '2';
|
||||
assertState(opts, {
|
||||
tabSize: 2,
|
||||
insertSpaces: false,
|
||||
cursorStyle: TextEditorCursorStyle.Line,
|
||||
lineNumbers: RenderLineNumbersType.On
|
||||
});
|
||||
assert.deepStrictEqual(calls, [{ tabSize: 2 }]);
|
||||
});
|
||||
|
||||
test('tabSize can request indentation detection', () => {
|
||||
opts.value.tabSize = 'auto';
|
||||
assertState(opts, {
|
||||
tabSize: 4,
|
||||
insertSpaces: false,
|
||||
cursorStyle: TextEditorCursorStyle.Line,
|
||||
lineNumbers: RenderLineNumbersType.On
|
||||
});
|
||||
assert.deepStrictEqual(calls, [{ tabSize: 'auto' }]);
|
||||
});
|
||||
|
||||
test('ignores invalid tabSize 1', () => {
|
||||
opts.value.tabSize = null!;
|
||||
assertState(opts, {
|
||||
tabSize: 4,
|
||||
insertSpaces: false,
|
||||
cursorStyle: TextEditorCursorStyle.Line,
|
||||
lineNumbers: RenderLineNumbersType.On
|
||||
});
|
||||
assert.deepStrictEqual(calls, []);
|
||||
});
|
||||
|
||||
test('ignores invalid tabSize 2', () => {
|
||||
opts.value.tabSize = -5;
|
||||
assertState(opts, {
|
||||
tabSize: 4,
|
||||
insertSpaces: false,
|
||||
cursorStyle: TextEditorCursorStyle.Line,
|
||||
lineNumbers: RenderLineNumbersType.On
|
||||
});
|
||||
assert.deepStrictEqual(calls, []);
|
||||
});
|
||||
|
||||
test('ignores invalid tabSize 3', () => {
|
||||
opts.value.tabSize = 'hello';
|
||||
assertState(opts, {
|
||||
tabSize: 4,
|
||||
insertSpaces: false,
|
||||
cursorStyle: TextEditorCursorStyle.Line,
|
||||
lineNumbers: RenderLineNumbersType.On
|
||||
});
|
||||
assert.deepStrictEqual(calls, []);
|
||||
});
|
||||
|
||||
test('ignores invalid tabSize 4', () => {
|
||||
opts.value.tabSize = '-17';
|
||||
assertState(opts, {
|
||||
tabSize: 4,
|
||||
insertSpaces: false,
|
||||
cursorStyle: TextEditorCursorStyle.Line,
|
||||
lineNumbers: RenderLineNumbersType.On
|
||||
});
|
||||
assert.deepStrictEqual(calls, []);
|
||||
});
|
||||
|
||||
test('can set insertSpaces to the same value', () => {
|
||||
opts.value.insertSpaces = false;
|
||||
assertState(opts, {
|
||||
tabSize: 4,
|
||||
insertSpaces: false,
|
||||
cursorStyle: TextEditorCursorStyle.Line,
|
||||
lineNumbers: RenderLineNumbersType.On
|
||||
});
|
||||
assert.deepStrictEqual(calls, []);
|
||||
});
|
||||
|
||||
test('can set insertSpaces to boolean', () => {
|
||||
opts.value.insertSpaces = true;
|
||||
assertState(opts, {
|
||||
tabSize: 4,
|
||||
insertSpaces: true,
|
||||
cursorStyle: TextEditorCursorStyle.Line,
|
||||
lineNumbers: RenderLineNumbersType.On
|
||||
});
|
||||
assert.deepStrictEqual(calls, [{ insertSpaces: true }]);
|
||||
});
|
||||
|
||||
test('can set insertSpaces to false string', () => {
|
||||
opts.value.insertSpaces = 'false';
|
||||
assertState(opts, {
|
||||
tabSize: 4,
|
||||
insertSpaces: false,
|
||||
cursorStyle: TextEditorCursorStyle.Line,
|
||||
lineNumbers: RenderLineNumbersType.On
|
||||
});
|
||||
assert.deepStrictEqual(calls, []);
|
||||
});
|
||||
|
||||
test('can set insertSpaces to truey', () => {
|
||||
opts.value.insertSpaces = 'hello';
|
||||
assertState(opts, {
|
||||
tabSize: 4,
|
||||
insertSpaces: true,
|
||||
cursorStyle: TextEditorCursorStyle.Line,
|
||||
lineNumbers: RenderLineNumbersType.On
|
||||
});
|
||||
assert.deepStrictEqual(calls, [{ insertSpaces: true }]);
|
||||
});
|
||||
|
||||
test('insertSpaces can request indentation detection', () => {
|
||||
opts.value.insertSpaces = 'auto';
|
||||
assertState(opts, {
|
||||
tabSize: 4,
|
||||
insertSpaces: false,
|
||||
cursorStyle: TextEditorCursorStyle.Line,
|
||||
lineNumbers: RenderLineNumbersType.On
|
||||
});
|
||||
assert.deepStrictEqual(calls, [{ insertSpaces: 'auto' }]);
|
||||
});
|
||||
|
||||
test('can set cursorStyle to same value', () => {
|
||||
opts.value.cursorStyle = TextEditorCursorStyle.Line;
|
||||
assertState(opts, {
|
||||
tabSize: 4,
|
||||
insertSpaces: false,
|
||||
cursorStyle: TextEditorCursorStyle.Line,
|
||||
lineNumbers: RenderLineNumbersType.On
|
||||
});
|
||||
assert.deepStrictEqual(calls, []);
|
||||
});
|
||||
|
||||
test('can change cursorStyle', () => {
|
||||
opts.value.cursorStyle = TextEditorCursorStyle.Block;
|
||||
assertState(opts, {
|
||||
tabSize: 4,
|
||||
insertSpaces: false,
|
||||
cursorStyle: TextEditorCursorStyle.Block,
|
||||
lineNumbers: RenderLineNumbersType.On
|
||||
});
|
||||
assert.deepStrictEqual(calls, [{ cursorStyle: TextEditorCursorStyle.Block }]);
|
||||
});
|
||||
|
||||
test('can set lineNumbers to same value', () => {
|
||||
opts.value.lineNumbers = TextEditorLineNumbersStyle.On;
|
||||
assertState(opts, {
|
||||
tabSize: 4,
|
||||
insertSpaces: false,
|
||||
cursorStyle: TextEditorCursorStyle.Line,
|
||||
lineNumbers: RenderLineNumbersType.On
|
||||
});
|
||||
assert.deepStrictEqual(calls, []);
|
||||
});
|
||||
|
||||
test('can change lineNumbers', () => {
|
||||
opts.value.lineNumbers = TextEditorLineNumbersStyle.Off;
|
||||
assertState(opts, {
|
||||
tabSize: 4,
|
||||
insertSpaces: false,
|
||||
cursorStyle: TextEditorCursorStyle.Line,
|
||||
lineNumbers: RenderLineNumbersType.Off
|
||||
});
|
||||
assert.deepStrictEqual(calls, [{ lineNumbers: RenderLineNumbersType.Off }]);
|
||||
});
|
||||
|
||||
test('can do bulk updates 0', () => {
|
||||
opts.assign({
|
||||
tabSize: 4,
|
||||
insertSpaces: false,
|
||||
cursorStyle: TextEditorCursorStyle.Line,
|
||||
lineNumbers: TextEditorLineNumbersStyle.On
|
||||
});
|
||||
assertState(opts, {
|
||||
tabSize: 4,
|
||||
insertSpaces: false,
|
||||
cursorStyle: TextEditorCursorStyle.Line,
|
||||
lineNumbers: RenderLineNumbersType.On
|
||||
});
|
||||
assert.deepStrictEqual(calls, []);
|
||||
});
|
||||
|
||||
test('can do bulk updates 1', () => {
|
||||
opts.assign({
|
||||
tabSize: 'auto',
|
||||
insertSpaces: true
|
||||
});
|
||||
assertState(opts, {
|
||||
tabSize: 4,
|
||||
insertSpaces: true,
|
||||
cursorStyle: TextEditorCursorStyle.Line,
|
||||
lineNumbers: RenderLineNumbersType.On
|
||||
});
|
||||
assert.deepStrictEqual(calls, [{ tabSize: 'auto', insertSpaces: true }]);
|
||||
});
|
||||
|
||||
test('can do bulk updates 2', () => {
|
||||
opts.assign({
|
||||
tabSize: 3,
|
||||
insertSpaces: 'auto'
|
||||
});
|
||||
assertState(opts, {
|
||||
tabSize: 3,
|
||||
insertSpaces: false,
|
||||
cursorStyle: TextEditorCursorStyle.Line,
|
||||
lineNumbers: RenderLineNumbersType.On
|
||||
});
|
||||
assert.deepStrictEqual(calls, [{ tabSize: 3, insertSpaces: 'auto' }]);
|
||||
});
|
||||
|
||||
test('can do bulk updates 3', () => {
|
||||
opts.assign({
|
||||
cursorStyle: TextEditorCursorStyle.Block,
|
||||
lineNumbers: TextEditorLineNumbersStyle.Relative
|
||||
});
|
||||
assertState(opts, {
|
||||
tabSize: 4,
|
||||
insertSpaces: false,
|
||||
cursorStyle: TextEditorCursorStyle.Block,
|
||||
lineNumbers: RenderLineNumbersType.Relative
|
||||
});
|
||||
assert.deepStrictEqual(calls, [{ cursorStyle: TextEditorCursorStyle.Block, lineNumbers: RenderLineNumbersType.Relative }]);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,764 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 sinon from 'sinon';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { ExtHostTreeViews } from 'vs/workbench/api/common/extHostTreeViews';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { MainThreadTreeViewsShape, MainContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { TreeDataProvider, TreeItem } from 'vscode';
|
||||
import { TestRPCProtocol } from './testRPCProtocol';
|
||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||
import { MainThreadCommands } from 'vs/workbench/api/browser/mainThreadCommands';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { mock } from 'vs/base/test/common/mock';
|
||||
import { TreeItemCollapsibleState, ITreeItem, IRevealOptions } from 'vs/workbench/common/views';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import type { IDisposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
suite.skip('ExtHostTreeView', function () { // {{SQL CARBON EDIT}} Skip suite
|
||||
|
||||
class RecordingShape extends mock<MainThreadTreeViewsShape>() {
|
||||
|
||||
onRefresh = new Emitter<{ [treeItemHandle: string]: ITreeItem }>();
|
||||
|
||||
override async $registerTreeViewDataProvider(treeViewId: string): Promise<void> {
|
||||
}
|
||||
|
||||
override $refresh(viewId: string, itemsToRefresh: { [treeItemHandle: string]: ITreeItem }): Promise<void> {
|
||||
return Promise.resolve(null).then(() => {
|
||||
this.onRefresh.fire(itemsToRefresh);
|
||||
});
|
||||
}
|
||||
|
||||
override $reveal(treeViewId: string, itemInfo: { item: ITreeItem, parentChain: ITreeItem[] } | undefined, options: IRevealOptions): Promise<void> {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
let testObject: ExtHostTreeViews;
|
||||
let target: RecordingShape;
|
||||
let onDidChangeTreeNode: Emitter<{ key: string } | undefined>;
|
||||
let onDidChangeTreeNodeWithId: Emitter<{ key: string }>;
|
||||
let tree: { [key: string]: any };
|
||||
let labels: { [key: string]: string };
|
||||
let nodes: { [key: string]: { key: string } };
|
||||
|
||||
setup(() => {
|
||||
tree = {
|
||||
'a': {
|
||||
'aa': {},
|
||||
'ab': {}
|
||||
},
|
||||
'b': {
|
||||
'ba': {},
|
||||
'bb': {}
|
||||
}
|
||||
};
|
||||
|
||||
labels = {};
|
||||
nodes = {};
|
||||
|
||||
let rpcProtocol = new TestRPCProtocol();
|
||||
// Use IInstantiationService to get typechecking when instantiating
|
||||
let inst: IInstantiationService;
|
||||
{
|
||||
let instantiationService = new TestInstantiationService();
|
||||
inst = instantiationService;
|
||||
}
|
||||
|
||||
rpcProtocol.set(MainContext.MainThreadCommands, inst.createInstance(MainThreadCommands, rpcProtocol));
|
||||
target = new RecordingShape();
|
||||
testObject = new ExtHostTreeViews(target, new ExtHostCommands(
|
||||
rpcProtocol,
|
||||
new NullLogService()
|
||||
), new NullLogService());
|
||||
onDidChangeTreeNode = new Emitter<{ key: string } | undefined>();
|
||||
onDidChangeTreeNodeWithId = new Emitter<{ key: string }>();
|
||||
testObject.createTreeView('testNodeTreeProvider', { treeDataProvider: aNodeTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription);
|
||||
testObject.createTreeView('testNodeWithIdTreeProvider', { treeDataProvider: aNodeWithIdTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription);
|
||||
testObject.createTreeView('testNodeWithHighlightsTreeProvider', { treeDataProvider: aNodeWithHighlightedLabelTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription);
|
||||
|
||||
return loadCompleteTree('testNodeTreeProvider');
|
||||
});
|
||||
|
||||
test('construct node tree', () => {
|
||||
return testObject.$getChildren('testNodeTreeProvider')
|
||||
.then(elements => {
|
||||
const actuals = elements?.map(e => e.handle);
|
||||
assert.deepStrictEqual(actuals, ['0/0:a', '0/0:b']);
|
||||
return Promise.all([
|
||||
testObject.$getChildren('testNodeTreeProvider', '0/0:a')
|
||||
.then(children => {
|
||||
const actuals = children?.map(e => e.handle);
|
||||
assert.deepStrictEqual(actuals, ['0/0:a/0:aa', '0/0:a/0:ab']);
|
||||
return Promise.all([
|
||||
testObject.$getChildren('testNodeTreeProvider', '0/0:a/0:aa').then(children => assert.strictEqual(children?.length, 0)),
|
||||
testObject.$getChildren('testNodeTreeProvider', '0/0:a/0:ab').then(children => assert.strictEqual(children?.length, 0))
|
||||
]);
|
||||
}),
|
||||
testObject.$getChildren('testNodeTreeProvider', '0/0:b')
|
||||
.then(children => {
|
||||
const actuals = children?.map(e => e.handle);
|
||||
assert.deepStrictEqual(actuals, ['0/0:b/0:ba', '0/0:b/0:bb']);
|
||||
return Promise.all([
|
||||
testObject.$getChildren('testNodeTreeProvider', '0/0:b/0:ba').then(children => assert.strictEqual(children?.length, 0)),
|
||||
testObject.$getChildren('testNodeTreeProvider', '0/0:b/0:bb').then(children => assert.strictEqual(children?.length, 0))
|
||||
]);
|
||||
})
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
test('construct id tree', () => {
|
||||
return testObject.$getChildren('testNodeWithIdTreeProvider')
|
||||
.then(elements => {
|
||||
const actuals = elements?.map(e => e.handle);
|
||||
assert.deepStrictEqual(actuals, ['1/a', '1/b']);
|
||||
return Promise.all([
|
||||
testObject.$getChildren('testNodeWithIdTreeProvider', '1/a')
|
||||
.then(children => {
|
||||
const actuals = children?.map(e => e.handle);
|
||||
assert.deepStrictEqual(actuals, ['1/aa', '1/ab']);
|
||||
return Promise.all([
|
||||
testObject.$getChildren('testNodeWithIdTreeProvider', '1/aa').then(children => assert.strictEqual(children?.length, 0)),
|
||||
testObject.$getChildren('testNodeWithIdTreeProvider', '1/ab').then(children => assert.strictEqual(children?.length, 0))
|
||||
]);
|
||||
}),
|
||||
testObject.$getChildren('testNodeWithIdTreeProvider', '1/b')
|
||||
.then(children => {
|
||||
const actuals = children?.map(e => e.handle);
|
||||
assert.deepStrictEqual(actuals, ['1/ba', '1/bb']);
|
||||
return Promise.all([
|
||||
testObject.$getChildren('testNodeWithIdTreeProvider', '1/ba').then(children => assert.strictEqual(children?.length, 0)),
|
||||
testObject.$getChildren('testNodeWithIdTreeProvider', '1/bb').then(children => assert.strictEqual(children?.length, 0))
|
||||
]);
|
||||
})
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
test('construct highlights tree', () => {
|
||||
return testObject.$getChildren('testNodeWithHighlightsTreeProvider')
|
||||
.then(elements => {
|
||||
assert.deepStrictEqual(removeUnsetKeys(elements), [{
|
||||
handle: '1/a',
|
||||
label: { label: 'a', highlights: [[0, 2], [3, 5]] },
|
||||
collapsibleState: TreeItemCollapsibleState.Collapsed
|
||||
}, {
|
||||
handle: '1/b',
|
||||
label: { label: 'b', highlights: [[0, 2], [3, 5]] },
|
||||
collapsibleState: TreeItemCollapsibleState.Collapsed
|
||||
}]);
|
||||
return Promise.all([
|
||||
testObject.$getChildren('testNodeWithHighlightsTreeProvider', '1/a')
|
||||
.then(children => {
|
||||
assert.deepStrictEqual(removeUnsetKeys(children), [{
|
||||
handle: '1/aa',
|
||||
parentHandle: '1/a',
|
||||
label: { label: 'aa', highlights: [[0, 2], [3, 5]] },
|
||||
collapsibleState: TreeItemCollapsibleState.None
|
||||
}, {
|
||||
handle: '1/ab',
|
||||
parentHandle: '1/a',
|
||||
label: { label: 'ab', highlights: [[0, 2], [3, 5]] },
|
||||
collapsibleState: TreeItemCollapsibleState.None
|
||||
}]);
|
||||
}),
|
||||
testObject.$getChildren('testNodeWithHighlightsTreeProvider', '1/b')
|
||||
.then(children => {
|
||||
assert.deepStrictEqual(removeUnsetKeys(children), [{
|
||||
handle: '1/ba',
|
||||
parentHandle: '1/b',
|
||||
label: { label: 'ba', highlights: [[0, 2], [3, 5]] },
|
||||
collapsibleState: TreeItemCollapsibleState.None
|
||||
}, {
|
||||
handle: '1/bb',
|
||||
parentHandle: '1/b',
|
||||
label: { label: 'bb', highlights: [[0, 2], [3, 5]] },
|
||||
collapsibleState: TreeItemCollapsibleState.None
|
||||
}]);
|
||||
})
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
test('error is thrown if id is not unique', (done) => {
|
||||
tree['a'] = {
|
||||
'aa': {},
|
||||
};
|
||||
tree['b'] = {
|
||||
'aa': {},
|
||||
'ba': {}
|
||||
};
|
||||
let caughtExpectedError = false;
|
||||
target.onRefresh.event(() => {
|
||||
testObject.$getChildren('testNodeWithIdTreeProvider')
|
||||
.then(elements => {
|
||||
const actuals = elements?.map(e => e.handle);
|
||||
assert.deepStrictEqual(actuals, ['1/a', '1/b']);
|
||||
return testObject.$getChildren('testNodeWithIdTreeProvider', '1/a')
|
||||
.then(() => testObject.$getChildren('testNodeWithIdTreeProvider', '1/b'))
|
||||
.then(() => assert.fail('Should fail with duplicate id'))
|
||||
.catch(() => caughtExpectedError = true)
|
||||
.finally(() => caughtExpectedError ? done() : assert.fail('Expected duplicate id error not thrown.'));
|
||||
});
|
||||
});
|
||||
onDidChangeTreeNode.fire(undefined);
|
||||
});
|
||||
|
||||
test('refresh root', function (done) {
|
||||
target.onRefresh.event(actuals => {
|
||||
assert.strictEqual(undefined, actuals);
|
||||
done();
|
||||
});
|
||||
onDidChangeTreeNode.fire(undefined);
|
||||
});
|
||||
|
||||
test('refresh a parent node', () => {
|
||||
return new Promise((c, e) => {
|
||||
target.onRefresh.event(actuals => {
|
||||
assert.deepStrictEqual(['0/0:b'], Object.keys(actuals));
|
||||
assert.deepStrictEqual(removeUnsetKeys(actuals['0/0:b']), {
|
||||
handle: '0/0:b',
|
||||
label: { label: 'b' },
|
||||
collapsibleState: TreeItemCollapsibleState.Collapsed
|
||||
});
|
||||
c(undefined);
|
||||
});
|
||||
onDidChangeTreeNode.fire(getNode('b'));
|
||||
});
|
||||
});
|
||||
|
||||
test('refresh a leaf node', function (done) {
|
||||
target.onRefresh.event(actuals => {
|
||||
assert.deepStrictEqual(['0/0:b/0:bb'], Object.keys(actuals));
|
||||
assert.deepStrictEqual(removeUnsetKeys(actuals['0/0:b/0:bb']), {
|
||||
handle: '0/0:b/0:bb',
|
||||
parentHandle: '0/0:b',
|
||||
label: { label: 'bb' },
|
||||
collapsibleState: TreeItemCollapsibleState.None
|
||||
});
|
||||
done();
|
||||
});
|
||||
onDidChangeTreeNode.fire(getNode('bb'));
|
||||
});
|
||||
|
||||
async function runWithEventMerging(action: (resolve: () => void) => void) {
|
||||
await new Promise<void>((resolve) => {
|
||||
let subscription: IDisposable | undefined = undefined;
|
||||
subscription = target.onRefresh.event(() => {
|
||||
subscription!.dispose();
|
||||
resolve();
|
||||
});
|
||||
onDidChangeTreeNode.fire(getNode('b'));
|
||||
});
|
||||
await new Promise<void>(action);
|
||||
}
|
||||
|
||||
test('refresh parent and child node trigger refresh only on parent - scenario 1', async () => {
|
||||
return runWithEventMerging((resolve) => {
|
||||
target.onRefresh.event(actuals => {
|
||||
assert.deepStrictEqual(['0/0:b', '0/0:a/0:aa'], Object.keys(actuals));
|
||||
assert.deepStrictEqual(removeUnsetKeys(actuals['0/0:b']), {
|
||||
handle: '0/0:b',
|
||||
label: { label: 'b' },
|
||||
collapsibleState: TreeItemCollapsibleState.Collapsed
|
||||
});
|
||||
assert.deepStrictEqual(removeUnsetKeys(actuals['0/0:a/0:aa']), {
|
||||
handle: '0/0:a/0:aa',
|
||||
parentHandle: '0/0:a',
|
||||
label: { label: 'aa' },
|
||||
collapsibleState: TreeItemCollapsibleState.None
|
||||
});
|
||||
resolve();
|
||||
});
|
||||
onDidChangeTreeNode.fire(getNode('b'));
|
||||
onDidChangeTreeNode.fire(getNode('aa'));
|
||||
onDidChangeTreeNode.fire(getNode('bb'));
|
||||
});
|
||||
});
|
||||
|
||||
test('refresh parent and child node trigger refresh only on parent - scenario 2', async () => {
|
||||
return runWithEventMerging((resolve) => {
|
||||
target.onRefresh.event(actuals => {
|
||||
assert.deepStrictEqual(['0/0:a/0:aa', '0/0:b'], Object.keys(actuals));
|
||||
assert.deepStrictEqual(removeUnsetKeys(actuals['0/0:b']), {
|
||||
handle: '0/0:b',
|
||||
label: { label: 'b' },
|
||||
collapsibleState: TreeItemCollapsibleState.Collapsed
|
||||
});
|
||||
assert.deepStrictEqual(removeUnsetKeys(actuals['0/0:a/0:aa']), {
|
||||
handle: '0/0:a/0:aa',
|
||||
parentHandle: '0/0:a',
|
||||
label: { label: 'aa' },
|
||||
collapsibleState: TreeItemCollapsibleState.None
|
||||
});
|
||||
resolve();
|
||||
});
|
||||
onDidChangeTreeNode.fire(getNode('bb'));
|
||||
onDidChangeTreeNode.fire(getNode('aa'));
|
||||
onDidChangeTreeNode.fire(getNode('b'));
|
||||
});
|
||||
});
|
||||
|
||||
test('refresh an element for label change', function (done) {
|
||||
labels['a'] = 'aa';
|
||||
target.onRefresh.event(actuals => {
|
||||
assert.deepStrictEqual(['0/0:a'], Object.keys(actuals));
|
||||
assert.deepStrictEqual(removeUnsetKeys(actuals['0/0:a']), {
|
||||
handle: '0/0:aa',
|
||||
label: { label: 'aa' },
|
||||
collapsibleState: TreeItemCollapsibleState.Collapsed
|
||||
});
|
||||
done();
|
||||
});
|
||||
onDidChangeTreeNode.fire(getNode('a'));
|
||||
});
|
||||
|
||||
test('refresh calls are throttled on roots', () => {
|
||||
return runWithEventMerging((resolve) => {
|
||||
target.onRefresh.event(actuals => {
|
||||
assert.strictEqual(undefined, actuals);
|
||||
resolve();
|
||||
});
|
||||
onDidChangeTreeNode.fire(undefined);
|
||||
onDidChangeTreeNode.fire(undefined);
|
||||
onDidChangeTreeNode.fire(undefined);
|
||||
onDidChangeTreeNode.fire(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
test('refresh calls are throttled on elements', () => {
|
||||
return runWithEventMerging((resolve) => {
|
||||
target.onRefresh.event(actuals => {
|
||||
assert.deepStrictEqual(['0/0:a', '0/0:b'], Object.keys(actuals));
|
||||
resolve();
|
||||
});
|
||||
|
||||
onDidChangeTreeNode.fire(getNode('a'));
|
||||
onDidChangeTreeNode.fire(getNode('b'));
|
||||
onDidChangeTreeNode.fire(getNode('b'));
|
||||
onDidChangeTreeNode.fire(getNode('a'));
|
||||
});
|
||||
});
|
||||
|
||||
test('refresh calls are throttled on unknown elements', () => {
|
||||
return runWithEventMerging((resolve) => {
|
||||
target.onRefresh.event(actuals => {
|
||||
assert.deepStrictEqual(['0/0:a', '0/0:b'], Object.keys(actuals));
|
||||
resolve();
|
||||
});
|
||||
|
||||
onDidChangeTreeNode.fire(getNode('a'));
|
||||
onDidChangeTreeNode.fire(getNode('b'));
|
||||
onDidChangeTreeNode.fire(getNode('g'));
|
||||
onDidChangeTreeNode.fire(getNode('a'));
|
||||
});
|
||||
});
|
||||
|
||||
test('refresh calls are throttled on unknown elements and root', () => {
|
||||
return runWithEventMerging((resolve) => {
|
||||
target.onRefresh.event(actuals => {
|
||||
assert.strictEqual(undefined, actuals);
|
||||
resolve();
|
||||
});
|
||||
|
||||
onDidChangeTreeNode.fire(getNode('a'));
|
||||
onDidChangeTreeNode.fire(getNode('b'));
|
||||
onDidChangeTreeNode.fire(getNode('g'));
|
||||
onDidChangeTreeNode.fire(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
test('refresh calls are throttled on elements and root', () => {
|
||||
return runWithEventMerging((resolve) => {
|
||||
target.onRefresh.event(actuals => {
|
||||
assert.strictEqual(undefined, actuals);
|
||||
resolve();
|
||||
});
|
||||
|
||||
onDidChangeTreeNode.fire(getNode('a'));
|
||||
onDidChangeTreeNode.fire(getNode('b'));
|
||||
onDidChangeTreeNode.fire(undefined);
|
||||
onDidChangeTreeNode.fire(getNode('a'));
|
||||
});
|
||||
});
|
||||
|
||||
test('generate unique handles from labels by escaping them', (done) => {
|
||||
tree = {
|
||||
'a/0:b': {}
|
||||
};
|
||||
|
||||
target.onRefresh.event(() => {
|
||||
testObject.$getChildren('testNodeTreeProvider')
|
||||
.then(elements => {
|
||||
assert.deepStrictEqual(elements?.map(e => e.handle), ['0/0:a//0:b']);
|
||||
done();
|
||||
});
|
||||
});
|
||||
onDidChangeTreeNode.fire(undefined);
|
||||
});
|
||||
|
||||
test('tree with duplicate labels', (done) => {
|
||||
|
||||
const dupItems = {
|
||||
'adup1': 'c',
|
||||
'adup2': 'g',
|
||||
'bdup1': 'e',
|
||||
'hdup1': 'i',
|
||||
'hdup2': 'l',
|
||||
'jdup1': 'k'
|
||||
};
|
||||
|
||||
labels['c'] = 'a';
|
||||
labels['e'] = 'b';
|
||||
labels['g'] = 'a';
|
||||
labels['i'] = 'h';
|
||||
labels['l'] = 'h';
|
||||
labels['k'] = 'j';
|
||||
|
||||
tree[dupItems['adup1']] = {};
|
||||
tree['d'] = {};
|
||||
|
||||
const bdup1Tree: { [key: string]: any } = {};
|
||||
bdup1Tree['h'] = {};
|
||||
bdup1Tree[dupItems['hdup1']] = {};
|
||||
bdup1Tree['j'] = {};
|
||||
bdup1Tree[dupItems['jdup1']] = {};
|
||||
bdup1Tree[dupItems['hdup2']] = {};
|
||||
|
||||
tree[dupItems['bdup1']] = bdup1Tree;
|
||||
tree['f'] = {};
|
||||
tree[dupItems['adup2']] = {};
|
||||
|
||||
target.onRefresh.event(() => {
|
||||
testObject.$getChildren('testNodeTreeProvider')
|
||||
.then(elements => {
|
||||
const actuals = elements?.map(e => e.handle);
|
||||
assert.deepStrictEqual(actuals, ['0/0:a', '0/0:b', '0/1:a', '0/0:d', '0/1:b', '0/0:f', '0/2:a']);
|
||||
return testObject.$getChildren('testNodeTreeProvider', '0/1:b')
|
||||
.then(elements => {
|
||||
const actuals = elements?.map(e => e.handle);
|
||||
assert.deepStrictEqual(actuals, ['0/1:b/0:h', '0/1:b/1:h', '0/1:b/0:j', '0/1:b/1:j', '0/1:b/2:h']);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
onDidChangeTreeNode.fire(undefined);
|
||||
});
|
||||
|
||||
test('getChildren is not returned from cache if refreshed', (done) => {
|
||||
tree = {
|
||||
'c': {}
|
||||
};
|
||||
|
||||
target.onRefresh.event(() => {
|
||||
testObject.$getChildren('testNodeTreeProvider')
|
||||
.then(elements => {
|
||||
assert.deepStrictEqual(elements?.map(e => e.handle), ['0/0:c']);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
onDidChangeTreeNode.fire(undefined);
|
||||
});
|
||||
|
||||
test('getChildren is returned from cache if not refreshed', () => {
|
||||
tree = {
|
||||
'c': {}
|
||||
};
|
||||
|
||||
return testObject.$getChildren('testNodeTreeProvider')
|
||||
.then(elements => {
|
||||
assert.deepStrictEqual(elements?.map(e => e.handle), ['0/0:a', '0/0:b']);
|
||||
});
|
||||
});
|
||||
|
||||
test('reveal will throw an error if getParent is not implemented', () => {
|
||||
const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aNodeTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription);
|
||||
return treeView.reveal({ key: 'a' })
|
||||
.then(() => assert.fail('Reveal should throw an error as getParent is not implemented'), () => null);
|
||||
});
|
||||
|
||||
test('reveal will return empty array for root element', () => {
|
||||
const revealTarget = sinon.spy(target, '$reveal');
|
||||
const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription);
|
||||
const expected = {
|
||||
item:
|
||||
{ handle: '0/0:a', label: { label: 'a' }, collapsibleState: TreeItemCollapsibleState.Collapsed },
|
||||
parentChain: []
|
||||
};
|
||||
return treeView.reveal({ key: 'a' })
|
||||
.then(() => {
|
||||
assert.ok(revealTarget.calledOnce);
|
||||
assert.deepStrictEqual('treeDataProvider', revealTarget.args[0][0]);
|
||||
assert.deepStrictEqual(expected, removeUnsetKeys(revealTarget.args[0][1]));
|
||||
assert.deepStrictEqual({ select: true, focus: false, expand: false }, revealTarget.args[0][2]);
|
||||
});
|
||||
});
|
||||
|
||||
test('reveal will return parents array for an element when hierarchy is not loaded', () => {
|
||||
const revealTarget = sinon.spy(target, '$reveal');
|
||||
const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription);
|
||||
const expected = {
|
||||
item: { handle: '0/0:a/0:aa', label: { label: 'aa' }, collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:a' },
|
||||
parentChain: [{ handle: '0/0:a', label: { label: 'a' }, collapsibleState: TreeItemCollapsibleState.Collapsed }]
|
||||
};
|
||||
return treeView.reveal({ key: 'aa' })
|
||||
.then(() => {
|
||||
assert.ok(revealTarget.calledOnce);
|
||||
assert.deepStrictEqual('treeDataProvider', revealTarget.args[0][0]);
|
||||
assert.deepStrictEqual(expected.item, removeUnsetKeys(revealTarget.args[0][1]!.item));
|
||||
assert.deepStrictEqual(expected.parentChain, (<Array<any>>(revealTarget.args[0][1]!.parentChain)).map(arg => removeUnsetKeys(arg)));
|
||||
assert.deepStrictEqual({ select: true, focus: false, expand: false }, revealTarget.args[0][2]);
|
||||
});
|
||||
});
|
||||
|
||||
test('reveal will return parents array for an element when hierarchy is loaded', () => {
|
||||
const revealTarget = sinon.spy(target, '$reveal');
|
||||
const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription);
|
||||
const expected = {
|
||||
item: { handle: '0/0:a/0:aa', label: { label: 'aa' }, collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:a' },
|
||||
parentChain: [{ handle: '0/0:a', label: { label: 'a' }, collapsibleState: TreeItemCollapsibleState.Collapsed }]
|
||||
};
|
||||
return testObject.$getChildren('treeDataProvider')
|
||||
.then(() => testObject.$getChildren('treeDataProvider', '0/0:a'))
|
||||
.then(() => treeView.reveal({ key: 'aa' })
|
||||
.then(() => {
|
||||
assert.ok(revealTarget.calledOnce);
|
||||
assert.deepStrictEqual('treeDataProvider', revealTarget.args[0][0]);
|
||||
assert.deepStrictEqual(expected.item, removeUnsetKeys(revealTarget.args[0][1]!.item));
|
||||
assert.deepStrictEqual(expected.parentChain, (<Array<any>>(revealTarget.args[0][1]!.parentChain)).map(arg => removeUnsetKeys(arg)));
|
||||
assert.deepStrictEqual({ select: true, focus: false, expand: false }, revealTarget.args[0][2]);
|
||||
}));
|
||||
});
|
||||
|
||||
test('reveal will return parents array for deeper element with no selection', () => {
|
||||
tree = {
|
||||
'b': {
|
||||
'ba': {
|
||||
'bac': {}
|
||||
}
|
||||
}
|
||||
};
|
||||
const revealTarget = sinon.spy(target, '$reveal');
|
||||
const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription);
|
||||
const expected = {
|
||||
item: { handle: '0/0:b/0:ba/0:bac', label: { label: 'bac' }, collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:b/0:ba' },
|
||||
parentChain: [
|
||||
{ handle: '0/0:b', label: { label: 'b' }, collapsibleState: TreeItemCollapsibleState.Collapsed },
|
||||
{ handle: '0/0:b/0:ba', label: { label: 'ba' }, collapsibleState: TreeItemCollapsibleState.Collapsed, parentHandle: '0/0:b' }
|
||||
]
|
||||
};
|
||||
return treeView.reveal({ key: 'bac' }, { select: false, focus: false, expand: false })
|
||||
.then(() => {
|
||||
assert.ok(revealTarget.calledOnce);
|
||||
assert.deepStrictEqual('treeDataProvider', revealTarget.args[0][0]);
|
||||
assert.deepStrictEqual(expected.item, removeUnsetKeys(revealTarget.args[0][1]!.item));
|
||||
assert.deepStrictEqual(expected.parentChain, (<Array<any>>(revealTarget.args[0][1]!.parentChain)).map(arg => removeUnsetKeys(arg)));
|
||||
assert.deepStrictEqual({ select: false, focus: false, expand: false }, revealTarget.args[0][2]);
|
||||
});
|
||||
});
|
||||
|
||||
test('reveal after first udpate', () => {
|
||||
const revealTarget = sinon.spy(target, '$reveal');
|
||||
const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription);
|
||||
const expected = {
|
||||
item: { handle: '0/0:a/0:ac', label: { label: 'ac' }, collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:a' },
|
||||
parentChain: [{ handle: '0/0:a', label: { label: 'a' }, collapsibleState: TreeItemCollapsibleState.Collapsed }]
|
||||
};
|
||||
return loadCompleteTree('treeDataProvider')
|
||||
.then(() => {
|
||||
tree = {
|
||||
'a': {
|
||||
'aa': {},
|
||||
'ac': {}
|
||||
},
|
||||
'b': {
|
||||
'ba': {},
|
||||
'bb': {}
|
||||
}
|
||||
};
|
||||
onDidChangeTreeNode.fire(getNode('a'));
|
||||
|
||||
return treeView.reveal({ key: 'ac' })
|
||||
.then(() => {
|
||||
assert.ok(revealTarget.calledOnce);
|
||||
assert.deepStrictEqual('treeDataProvider', revealTarget.args[0][0]);
|
||||
assert.deepStrictEqual(expected.item, removeUnsetKeys(revealTarget.args[0][1]!.item));
|
||||
assert.deepStrictEqual(expected.parentChain, (<Array<any>>(revealTarget.args[0][1]!.parentChain)).map(arg => removeUnsetKeys(arg)));
|
||||
assert.deepStrictEqual({ select: true, focus: false, expand: false }, revealTarget.args[0][2]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('reveal after second udpate', () => {
|
||||
const revealTarget = sinon.spy(target, '$reveal');
|
||||
const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription);
|
||||
return loadCompleteTree('treeDataProvider')
|
||||
.then(() => {
|
||||
return runWithEventMerging((resolve) => {
|
||||
tree = {
|
||||
'a': {
|
||||
'aa': {},
|
||||
'ac': {}
|
||||
},
|
||||
'b': {
|
||||
'ba': {},
|
||||
'bb': {}
|
||||
}
|
||||
};
|
||||
onDidChangeTreeNode.fire(getNode('a'));
|
||||
tree = {
|
||||
'a': {
|
||||
'aa': {},
|
||||
'ac': {}
|
||||
},
|
||||
'b': {
|
||||
'ba': {},
|
||||
'bc': {}
|
||||
}
|
||||
};
|
||||
onDidChangeTreeNode.fire(getNode('b'));
|
||||
resolve();
|
||||
}).then(() => {
|
||||
return treeView.reveal({ key: 'bc' })
|
||||
.then(() => {
|
||||
assert.ok(revealTarget.calledOnce);
|
||||
assert.deepStrictEqual('treeDataProvider', revealTarget.args[0][0]);
|
||||
assert.deepStrictEqual({ handle: '0/0:b/0:bc', label: { label: 'bc' }, collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:b' }, removeUnsetKeys(revealTarget.args[0][1]!.item));
|
||||
assert.deepStrictEqual([{ handle: '0/0:b', label: { label: 'b' }, collapsibleState: TreeItemCollapsibleState.Collapsed }], (<Array<any>>revealTarget.args[0][1]!.parentChain).map(arg => removeUnsetKeys(arg)));
|
||||
assert.deepStrictEqual({ select: true, focus: false, expand: false }, revealTarget.args[0][2]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function loadCompleteTree(treeId: string, element?: string): Promise<null> {
|
||||
return testObject.$getChildren(treeId, element)
|
||||
.then(elements => elements?.map(e => loadCompleteTree(treeId, e.handle)))
|
||||
.then(() => null);
|
||||
}
|
||||
|
||||
function removeUnsetKeys(obj: any): any {
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map(o => removeUnsetKeys(o));
|
||||
}
|
||||
|
||||
if (typeof obj === 'object') {
|
||||
const result: { [key: string]: any } = {};
|
||||
for (const key of Object.keys(obj)) {
|
||||
if (obj[key] !== undefined) {
|
||||
result[key] = removeUnsetKeys(obj[key]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
function aNodeTreeDataProvider(): TreeDataProvider<{ key: string }> {
|
||||
return {
|
||||
getChildren: (element: { key: string }): { key: string }[] => {
|
||||
return getChildren(element ? element.key : undefined).map(key => getNode(key));
|
||||
},
|
||||
getTreeItem: (element: { key: string }): TreeItem => {
|
||||
return getTreeItem(element.key);
|
||||
},
|
||||
onDidChangeTreeData: onDidChangeTreeNode.event
|
||||
};
|
||||
}
|
||||
|
||||
function aCompleteNodeTreeDataProvider(): TreeDataProvider<{ key: string }> {
|
||||
return {
|
||||
getChildren: (element: { key: string }): { key: string }[] => {
|
||||
return getChildren(element ? element.key : undefined).map(key => getNode(key));
|
||||
},
|
||||
getTreeItem: (element: { key: string }): TreeItem => {
|
||||
return getTreeItem(element.key);
|
||||
},
|
||||
getParent: ({ key }: { key: string }): { key: string } | undefined => {
|
||||
const parentKey = key.substring(0, key.length - 1);
|
||||
return parentKey ? new Key(parentKey) : undefined;
|
||||
},
|
||||
onDidChangeTreeData: onDidChangeTreeNode.event
|
||||
};
|
||||
}
|
||||
|
||||
function aNodeWithIdTreeDataProvider(): TreeDataProvider<{ key: string }> {
|
||||
return {
|
||||
getChildren: (element: { key: string }): { key: string }[] => {
|
||||
return getChildren(element ? element.key : undefined).map(key => getNode(key));
|
||||
},
|
||||
getTreeItem: (element: { key: string }): TreeItem => {
|
||||
const treeItem = getTreeItem(element.key);
|
||||
treeItem.id = element.key;
|
||||
return treeItem;
|
||||
},
|
||||
onDidChangeTreeData: onDidChangeTreeNodeWithId.event
|
||||
};
|
||||
}
|
||||
|
||||
function aNodeWithHighlightedLabelTreeDataProvider(): TreeDataProvider<{ key: string }> {
|
||||
return {
|
||||
getChildren: (element: { key: string }): { key: string }[] => {
|
||||
return getChildren(element ? element.key : undefined).map(key => getNode(key));
|
||||
},
|
||||
getTreeItem: (element: { key: string }): TreeItem => {
|
||||
const treeItem = getTreeItem(element.key, [[0, 2], [3, 5]]);
|
||||
treeItem.id = element.key;
|
||||
return treeItem;
|
||||
},
|
||||
onDidChangeTreeData: onDidChangeTreeNodeWithId.event
|
||||
};
|
||||
}
|
||||
|
||||
function getTreeElement(element: string): any {
|
||||
let parent = tree;
|
||||
for (let i = 0; i < element.length; i++) {
|
||||
parent = parent[element.substring(0, i + 1)];
|
||||
if (!parent) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return parent;
|
||||
}
|
||||
|
||||
function getChildren(key: string | undefined): string[] {
|
||||
if (!key) {
|
||||
return Object.keys(tree);
|
||||
}
|
||||
let treeElement = getTreeElement(key);
|
||||
if (treeElement) {
|
||||
return Object.keys(treeElement);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
function getTreeItem(key: string, highlights?: [number, number][]): TreeItem {
|
||||
const treeElement = getTreeElement(key);
|
||||
return {
|
||||
label: <any>{ label: labels[key] || key, highlights },
|
||||
collapsibleState: treeElement && Object.keys(treeElement).length ? TreeItemCollapsibleState.Collapsed : TreeItemCollapsibleState.None
|
||||
};
|
||||
}
|
||||
|
||||
function getNode(key: string): { key: string } {
|
||||
if (!nodes[key]) {
|
||||
nodes[key] = new Key(key);
|
||||
}
|
||||
return nodes[key];
|
||||
}
|
||||
|
||||
class Key {
|
||||
constructor(readonly key: string) { }
|
||||
}
|
||||
|
||||
});
|
||||
@@ -1,114 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 extHostTypes from 'vs/workbench/api/common/extHostTypes';
|
||||
import { MarkdownString, NotebookCellOutputItem, NotebookData } from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import { isEmptyObject } from 'vs/base/common/types';
|
||||
import { forEach } from 'vs/base/common/collections';
|
||||
import { LogLevel as _MainLogLevel } from 'vs/platform/log/common/log';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
suite('ExtHostTypeConverter', function () {
|
||||
function size<T>(from: Record<any, any>): number {
|
||||
let count = 0;
|
||||
for (let key in from) {
|
||||
if (Object.prototype.hasOwnProperty.call(from, key)) {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
test('MarkdownConvert - uris', function () {
|
||||
|
||||
let data = MarkdownString.from('Hello');
|
||||
assert.strictEqual(isEmptyObject(data.uris), true);
|
||||
assert.strictEqual(data.value, 'Hello');
|
||||
|
||||
data = MarkdownString.from('Hello [link](foo)');
|
||||
assert.strictEqual(data.value, 'Hello [link](foo)');
|
||||
assert.strictEqual(isEmptyObject(data.uris), true); // no scheme, no uri
|
||||
|
||||
data = MarkdownString.from('Hello [link](www.noscheme.bad)');
|
||||
assert.strictEqual(data.value, 'Hello [link](www.noscheme.bad)');
|
||||
assert.strictEqual(isEmptyObject(data.uris), true); // no scheme, no uri
|
||||
|
||||
data = MarkdownString.from('Hello [link](foo:path)');
|
||||
assert.strictEqual(data.value, 'Hello [link](foo:path)');
|
||||
assert.strictEqual(size(data.uris!), 1);
|
||||
assert.ok(!!data.uris!['foo:path']);
|
||||
|
||||
data = MarkdownString.from('hello@foo.bar');
|
||||
assert.strictEqual(data.value, 'hello@foo.bar');
|
||||
assert.strictEqual(size(data.uris!), 1);
|
||||
// assert.ok(!!data.uris!['mailto:hello@foo.bar']);
|
||||
|
||||
data = MarkdownString.from('*hello* [click](command:me)');
|
||||
assert.strictEqual(data.value, '*hello* [click](command:me)');
|
||||
assert.strictEqual(size(data.uris!), 1);
|
||||
assert.ok(!!data.uris!['command:me']);
|
||||
|
||||
data = MarkdownString.from('*hello* [click](file:///somepath/here). [click](file:///somepath/here)');
|
||||
assert.strictEqual(data.value, '*hello* [click](file:///somepath/here). [click](file:///somepath/here)');
|
||||
assert.strictEqual(size(data.uris!), 1);
|
||||
assert.ok(!!data.uris!['file:///somepath/here']);
|
||||
|
||||
data = MarkdownString.from('*hello* [click](file:///somepath/here). [click](file:///somepath/here)');
|
||||
assert.strictEqual(data.value, '*hello* [click](file:///somepath/here). [click](file:///somepath/here)');
|
||||
assert.strictEqual(size(data.uris!), 1);
|
||||
assert.ok(!!data.uris!['file:///somepath/here']);
|
||||
|
||||
data = MarkdownString.from('*hello* [click](file:///somepath/here). [click](file:///somepath/here2)');
|
||||
assert.strictEqual(data.value, '*hello* [click](file:///somepath/here). [click](file:///somepath/here2)');
|
||||
assert.strictEqual(size(data.uris!), 2);
|
||||
assert.ok(!!data.uris!['file:///somepath/here']);
|
||||
assert.ok(!!data.uris!['file:///somepath/here2']);
|
||||
});
|
||||
|
||||
test('NPM script explorer running a script from the hover does not work #65561', function () {
|
||||
|
||||
let data = MarkdownString.from('*hello* [click](command:npm.runScriptFromHover?%7B%22documentUri%22%3A%7B%22%24mid%22%3A1%2C%22external%22%3A%22file%3A%2F%2F%2Fc%253A%2Ffoo%2Fbaz.ex%22%2C%22path%22%3A%22%2Fc%3A%2Ffoo%2Fbaz.ex%22%2C%22scheme%22%3A%22file%22%7D%2C%22script%22%3A%22dev%22%7D)');
|
||||
// assert that both uri get extracted but that the latter is only decoded once...
|
||||
assert.strictEqual(size(data.uris!), 2);
|
||||
forEach(data.uris!, entry => {
|
||||
if (entry.value.scheme === 'file') {
|
||||
assert.ok(URI.revive(entry.value).toString().indexOf('file:///c%3A') === 0);
|
||||
} else {
|
||||
assert.strictEqual(entry.value.scheme, 'command');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('Notebook metadata is ignored when using Notebook Serializer #125716', function () {
|
||||
|
||||
const d = new extHostTypes.NotebookData([]);
|
||||
d.cells.push(new extHostTypes.NotebookCellData(extHostTypes.NotebookCellKind.Code, 'hello', 'fooLang'));
|
||||
d.metadata = { custom: { foo: 'bar', bar: 123 } };
|
||||
|
||||
const dto = NotebookData.from(d);
|
||||
|
||||
assert.strictEqual(dto.cells.length, 1);
|
||||
assert.strictEqual(dto.cells[0].language, 'fooLang');
|
||||
assert.strictEqual(dto.cells[0].source, 'hello');
|
||||
assert.deepStrictEqual(dto.metadata, d.metadata);
|
||||
});
|
||||
|
||||
test('NotebookCellOutputItem', function () {
|
||||
|
||||
const item = extHostTypes.NotebookCellOutputItem.text('Hello', 'foo/bar');
|
||||
|
||||
const dto = NotebookCellOutputItem.from(item);
|
||||
|
||||
assert.strictEqual(dto.mime, 'foo/bar');
|
||||
assert.deepStrictEqual(Array.from(dto.valueBytes.buffer), Array.from(new TextEncoder().encode('Hello')));
|
||||
|
||||
const item2 = NotebookCellOutputItem.to(dto);
|
||||
|
||||
assert.strictEqual(item2.mime, item.mime);
|
||||
assert.deepStrictEqual(Array.from(item2.data), Array.from(item.data));
|
||||
});
|
||||
});
|
||||
@@ -1,711 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 } from 'vs/base/common/uri';
|
||||
import * as types from 'vs/workbench/api/common/extHostTypes';
|
||||
import { isWindows } from 'vs/base/common/platform';
|
||||
import { assertType } from 'vs/base/common/types';
|
||||
import { Mimes } from 'vs/base/common/mime';
|
||||
import { MarshalledId } from 'vs/base/common/marshalling';
|
||||
|
||||
function assertToJSON(a: any, expected: any) {
|
||||
const raw = JSON.stringify(a);
|
||||
const actual = JSON.parse(raw);
|
||||
assert.deepStrictEqual(actual, expected);
|
||||
}
|
||||
|
||||
suite('ExtHostTypes', function () {
|
||||
|
||||
test('URI, toJSON', function () {
|
||||
|
||||
let uri = URI.parse('file:///path/test.file');
|
||||
assert.deepStrictEqual(uri.toJSON(), {
|
||||
$mid: MarshalledId.Uri,
|
||||
scheme: 'file',
|
||||
path: '/path/test.file'
|
||||
});
|
||||
|
||||
assert.ok(uri.fsPath);
|
||||
assert.deepStrictEqual(uri.toJSON(), {
|
||||
$mid: MarshalledId.Uri,
|
||||
scheme: 'file',
|
||||
path: '/path/test.file',
|
||||
fsPath: '/path/test.file'.replace(/\//g, isWindows ? '\\' : '/'),
|
||||
_sep: isWindows ? 1 : undefined,
|
||||
});
|
||||
|
||||
assert.ok(uri.toString());
|
||||
assert.deepStrictEqual(uri.toJSON(), {
|
||||
$mid: MarshalledId.Uri,
|
||||
scheme: 'file',
|
||||
path: '/path/test.file',
|
||||
fsPath: '/path/test.file'.replace(/\//g, isWindows ? '\\' : '/'),
|
||||
_sep: isWindows ? 1 : undefined,
|
||||
external: 'file:///path/test.file'
|
||||
});
|
||||
});
|
||||
|
||||
test('Disposable', () => {
|
||||
|
||||
let count = 0;
|
||||
let d = new types.Disposable(() => {
|
||||
count += 1;
|
||||
return 12;
|
||||
});
|
||||
d.dispose();
|
||||
assert.strictEqual(count, 1);
|
||||
|
||||
d.dispose();
|
||||
assert.strictEqual(count, 1);
|
||||
|
||||
types.Disposable.from(undefined!, { dispose() { count += 1; } }).dispose();
|
||||
assert.strictEqual(count, 2);
|
||||
|
||||
|
||||
assert.throws(() => {
|
||||
new types.Disposable(() => {
|
||||
throw new Error();
|
||||
}).dispose();
|
||||
});
|
||||
|
||||
new types.Disposable(undefined!).dispose();
|
||||
|
||||
});
|
||||
|
||||
test('Position', () => {
|
||||
assert.throws(() => new types.Position(-1, 0));
|
||||
assert.throws(() => new types.Position(0, -1));
|
||||
|
||||
let pos = new types.Position(0, 0);
|
||||
assert.throws(() => (pos as any).line = -1);
|
||||
assert.throws(() => (pos as any).character = -1);
|
||||
assert.throws(() => (pos as any).line = 12);
|
||||
|
||||
let { line, character } = pos.toJSON();
|
||||
assert.strictEqual(line, 0);
|
||||
assert.strictEqual(character, 0);
|
||||
});
|
||||
|
||||
test('Position, toJSON', function () {
|
||||
let pos = new types.Position(4, 2);
|
||||
assertToJSON(pos, { line: 4, character: 2 });
|
||||
});
|
||||
|
||||
test('Position, isBefore(OrEqual)?', function () {
|
||||
let p1 = new types.Position(1, 3);
|
||||
let p2 = new types.Position(1, 2);
|
||||
let p3 = new types.Position(0, 4);
|
||||
|
||||
assert.ok(p1.isBeforeOrEqual(p1));
|
||||
assert.ok(!p1.isBefore(p1));
|
||||
assert.ok(p2.isBefore(p1));
|
||||
assert.ok(p3.isBefore(p2));
|
||||
});
|
||||
|
||||
test('Position, isAfter(OrEqual)?', function () {
|
||||
let p1 = new types.Position(1, 3);
|
||||
let p2 = new types.Position(1, 2);
|
||||
let p3 = new types.Position(0, 4);
|
||||
|
||||
assert.ok(p1.isAfterOrEqual(p1));
|
||||
assert.ok(!p1.isAfter(p1));
|
||||
assert.ok(p1.isAfter(p2));
|
||||
assert.ok(p2.isAfter(p3));
|
||||
assert.ok(p1.isAfter(p3));
|
||||
});
|
||||
|
||||
test('Position, compareTo', function () {
|
||||
let p1 = new types.Position(1, 3);
|
||||
let p2 = new types.Position(1, 2);
|
||||
let p3 = new types.Position(0, 4);
|
||||
|
||||
assert.strictEqual(p1.compareTo(p1), 0);
|
||||
assert.strictEqual(p2.compareTo(p1), -1);
|
||||
assert.strictEqual(p1.compareTo(p2), 1);
|
||||
assert.strictEqual(p2.compareTo(p3), 1);
|
||||
assert.strictEqual(p1.compareTo(p3), 1);
|
||||
});
|
||||
|
||||
test('Position, translate', function () {
|
||||
let p1 = new types.Position(1, 3);
|
||||
|
||||
assert.ok(p1.translate() === p1);
|
||||
assert.ok(p1.translate({}) === p1);
|
||||
assert.ok(p1.translate(0, 0) === p1);
|
||||
assert.ok(p1.translate(0) === p1);
|
||||
assert.ok(p1.translate(undefined, 0) === p1);
|
||||
assert.ok(p1.translate(undefined) === p1);
|
||||
|
||||
let res = p1.translate(-1);
|
||||
assert.strictEqual(res.line, 0);
|
||||
assert.strictEqual(res.character, 3);
|
||||
|
||||
res = p1.translate({ lineDelta: -1 });
|
||||
assert.strictEqual(res.line, 0);
|
||||
assert.strictEqual(res.character, 3);
|
||||
|
||||
res = p1.translate(undefined, -1);
|
||||
assert.strictEqual(res.line, 1);
|
||||
assert.strictEqual(res.character, 2);
|
||||
|
||||
res = p1.translate({ characterDelta: -1 });
|
||||
assert.strictEqual(res.line, 1);
|
||||
assert.strictEqual(res.character, 2);
|
||||
|
||||
res = p1.translate(11);
|
||||
assert.strictEqual(res.line, 12);
|
||||
assert.strictEqual(res.character, 3);
|
||||
|
||||
assert.throws(() => p1.translate(null!));
|
||||
assert.throws(() => p1.translate(null!, null!));
|
||||
assert.throws(() => p1.translate(-2));
|
||||
assert.throws(() => p1.translate({ lineDelta: -2 }));
|
||||
assert.throws(() => p1.translate(-2, null!));
|
||||
assert.throws(() => p1.translate(0, -4));
|
||||
});
|
||||
|
||||
test('Position, with', function () {
|
||||
let p1 = new types.Position(1, 3);
|
||||
|
||||
assert.ok(p1.with() === p1);
|
||||
assert.ok(p1.with(1) === p1);
|
||||
assert.ok(p1.with(undefined, 3) === p1);
|
||||
assert.ok(p1.with(1, 3) === p1);
|
||||
assert.ok(p1.with(undefined) === p1);
|
||||
assert.ok(p1.with({ line: 1 }) === p1);
|
||||
assert.ok(p1.with({ character: 3 }) === p1);
|
||||
assert.ok(p1.with({ line: 1, character: 3 }) === p1);
|
||||
|
||||
let p2 = p1.with({ line: 0, character: 11 });
|
||||
assert.strictEqual(p2.line, 0);
|
||||
assert.strictEqual(p2.character, 11);
|
||||
|
||||
assert.throws(() => p1.with(null!));
|
||||
assert.throws(() => p1.with(-9));
|
||||
assert.throws(() => p1.with(0, -9));
|
||||
assert.throws(() => p1.with({ line: -1 }));
|
||||
assert.throws(() => p1.with({ character: -1 }));
|
||||
});
|
||||
|
||||
test('Range', () => {
|
||||
assert.throws(() => new types.Range(-1, 0, 0, 0));
|
||||
assert.throws(() => new types.Range(0, -1, 0, 0));
|
||||
assert.throws(() => new types.Range(new types.Position(0, 0), undefined!));
|
||||
assert.throws(() => new types.Range(new types.Position(0, 0), null!));
|
||||
assert.throws(() => new types.Range(undefined!, new types.Position(0, 0)));
|
||||
assert.throws(() => new types.Range(null!, new types.Position(0, 0)));
|
||||
|
||||
let range = new types.Range(1, 0, 0, 0);
|
||||
assert.throws(() => { (range as any).start = null; });
|
||||
assert.throws(() => { (range as any).start = new types.Position(0, 3); });
|
||||
});
|
||||
|
||||
test('Range, toJSON', function () {
|
||||
|
||||
let range = new types.Range(1, 2, 3, 4);
|
||||
assertToJSON(range, [{ line: 1, character: 2 }, { line: 3, character: 4 }]);
|
||||
});
|
||||
|
||||
test('Range, sorting', function () {
|
||||
// sorts start/end
|
||||
let range = new types.Range(1, 0, 0, 0);
|
||||
assert.strictEqual(range.start.line, 0);
|
||||
assert.strictEqual(range.end.line, 1);
|
||||
|
||||
range = new types.Range(0, 0, 1, 0);
|
||||
assert.strictEqual(range.start.line, 0);
|
||||
assert.strictEqual(range.end.line, 1);
|
||||
});
|
||||
|
||||
test('Range, isEmpty|isSingleLine', function () {
|
||||
let range = new types.Range(1, 0, 0, 0);
|
||||
assert.ok(!range.isEmpty);
|
||||
assert.ok(!range.isSingleLine);
|
||||
|
||||
range = new types.Range(1, 1, 1, 1);
|
||||
assert.ok(range.isEmpty);
|
||||
assert.ok(range.isSingleLine);
|
||||
|
||||
range = new types.Range(0, 1, 0, 11);
|
||||
assert.ok(!range.isEmpty);
|
||||
assert.ok(range.isSingleLine);
|
||||
|
||||
range = new types.Range(0, 0, 1, 1);
|
||||
assert.ok(!range.isEmpty);
|
||||
assert.ok(!range.isSingleLine);
|
||||
});
|
||||
|
||||
test('Range, contains', function () {
|
||||
let range = new types.Range(1, 1, 2, 11);
|
||||
|
||||
assert.ok(range.contains(range.start));
|
||||
assert.ok(range.contains(range.end));
|
||||
assert.ok(range.contains(range));
|
||||
|
||||
assert.ok(!range.contains(new types.Range(1, 0, 2, 11)));
|
||||
assert.ok(!range.contains(new types.Range(0, 1, 2, 11)));
|
||||
assert.ok(!range.contains(new types.Range(1, 1, 2, 12)));
|
||||
assert.ok(!range.contains(new types.Range(1, 1, 3, 11)));
|
||||
});
|
||||
|
||||
test('Range, intersection', function () {
|
||||
let range = new types.Range(1, 1, 2, 11);
|
||||
let res: types.Range;
|
||||
|
||||
res = range.intersection(range)!;
|
||||
assert.strictEqual(res.start.line, 1);
|
||||
assert.strictEqual(res.start.character, 1);
|
||||
assert.strictEqual(res.end.line, 2);
|
||||
assert.strictEqual(res.end.character, 11);
|
||||
|
||||
res = range.intersection(new types.Range(2, 12, 4, 0))!;
|
||||
assert.strictEqual(res, undefined);
|
||||
|
||||
res = range.intersection(new types.Range(0, 0, 1, 0))!;
|
||||
assert.strictEqual(res, undefined);
|
||||
|
||||
res = range.intersection(new types.Range(0, 0, 1, 1))!;
|
||||
assert.ok(res.isEmpty);
|
||||
assert.strictEqual(res.start.line, 1);
|
||||
assert.strictEqual(res.start.character, 1);
|
||||
|
||||
res = range.intersection(new types.Range(2, 11, 61, 1))!;
|
||||
assert.ok(res.isEmpty);
|
||||
assert.strictEqual(res.start.line, 2);
|
||||
assert.strictEqual(res.start.character, 11);
|
||||
|
||||
assert.throws(() => range.intersection(null!));
|
||||
assert.throws(() => range.intersection(undefined!));
|
||||
});
|
||||
|
||||
test('Range, union', function () {
|
||||
let ran1 = new types.Range(0, 0, 5, 5);
|
||||
assert.ok(ran1.union(new types.Range(0, 0, 1, 1)) === ran1);
|
||||
|
||||
let res: types.Range;
|
||||
res = ran1.union(new types.Range(2, 2, 9, 9));
|
||||
assert.ok(res.start === ran1.start);
|
||||
assert.strictEqual(res.end.line, 9);
|
||||
assert.strictEqual(res.end.character, 9);
|
||||
|
||||
ran1 = new types.Range(2, 1, 5, 3);
|
||||
res = ran1.union(new types.Range(1, 0, 4, 2));
|
||||
assert.ok(res.end === ran1.end);
|
||||
assert.strictEqual(res.start.line, 1);
|
||||
assert.strictEqual(res.start.character, 0);
|
||||
});
|
||||
|
||||
test('Range, with', function () {
|
||||
let range = new types.Range(1, 1, 2, 11);
|
||||
|
||||
assert.ok(range.with(range.start) === range);
|
||||
assert.ok(range.with(undefined, range.end) === range);
|
||||
assert.ok(range.with(range.start, range.end) === range);
|
||||
assert.ok(range.with(new types.Position(1, 1)) === range);
|
||||
assert.ok(range.with(undefined, new types.Position(2, 11)) === range);
|
||||
assert.ok(range.with() === range);
|
||||
assert.ok(range.with({ start: range.start }) === range);
|
||||
assert.ok(range.with({ start: new types.Position(1, 1) }) === range);
|
||||
assert.ok(range.with({ end: range.end }) === range);
|
||||
assert.ok(range.with({ end: new types.Position(2, 11) }) === range);
|
||||
|
||||
let res = range.with(undefined, new types.Position(9, 8));
|
||||
assert.strictEqual(res.end.line, 9);
|
||||
assert.strictEqual(res.end.character, 8);
|
||||
assert.strictEqual(res.start.line, 1);
|
||||
assert.strictEqual(res.start.character, 1);
|
||||
|
||||
res = range.with({ end: new types.Position(9, 8) });
|
||||
assert.strictEqual(res.end.line, 9);
|
||||
assert.strictEqual(res.end.character, 8);
|
||||
assert.strictEqual(res.start.line, 1);
|
||||
assert.strictEqual(res.start.character, 1);
|
||||
|
||||
res = range.with({ end: new types.Position(9, 8), start: new types.Position(2, 3) });
|
||||
assert.strictEqual(res.end.line, 9);
|
||||
assert.strictEqual(res.end.character, 8);
|
||||
assert.strictEqual(res.start.line, 2);
|
||||
assert.strictEqual(res.start.character, 3);
|
||||
|
||||
assert.throws(() => range.with(null!));
|
||||
assert.throws(() => range.with(undefined, null!));
|
||||
});
|
||||
|
||||
test('TextEdit', () => {
|
||||
|
||||
let range = new types.Range(1, 1, 2, 11);
|
||||
let edit = new types.TextEdit(range, undefined!);
|
||||
assert.strictEqual(edit.newText, '');
|
||||
assertToJSON(edit, { range: [{ line: 1, character: 1 }, { line: 2, character: 11 }], newText: '' });
|
||||
|
||||
edit = new types.TextEdit(range, null!);
|
||||
assert.strictEqual(edit.newText, '');
|
||||
|
||||
edit = new types.TextEdit(range, '');
|
||||
assert.strictEqual(edit.newText, '');
|
||||
});
|
||||
|
||||
test('WorkspaceEdit', () => {
|
||||
|
||||
let a = URI.file('a.ts');
|
||||
let b = URI.file('b.ts');
|
||||
|
||||
let edit = new types.WorkspaceEdit();
|
||||
assert.ok(!edit.has(a));
|
||||
|
||||
edit.set(a, [types.TextEdit.insert(new types.Position(0, 0), 'fff')]);
|
||||
assert.ok(edit.has(a));
|
||||
assert.strictEqual(edit.size, 1);
|
||||
assertToJSON(edit, [[a.toJSON(), [{ range: [{ line: 0, character: 0 }, { line: 0, character: 0 }], newText: 'fff' }]]]);
|
||||
|
||||
edit.insert(b, new types.Position(1, 1), 'fff');
|
||||
edit.delete(b, new types.Range(0, 0, 0, 0));
|
||||
assert.ok(edit.has(b));
|
||||
assert.strictEqual(edit.size, 2);
|
||||
assertToJSON(edit, [
|
||||
[a.toJSON(), [{ range: [{ line: 0, character: 0 }, { line: 0, character: 0 }], newText: 'fff' }]],
|
||||
[b.toJSON(), [{ range: [{ line: 1, character: 1 }, { line: 1, character: 1 }], newText: 'fff' }, { range: [{ line: 0, character: 0 }, { line: 0, character: 0 }], newText: '' }]]
|
||||
]);
|
||||
|
||||
edit.set(b, undefined!);
|
||||
assert.ok(!edit.has(b));
|
||||
assert.strictEqual(edit.size, 1);
|
||||
|
||||
edit.set(b, [types.TextEdit.insert(new types.Position(0, 0), 'ffff')]);
|
||||
assert.strictEqual(edit.get(b).length, 1);
|
||||
});
|
||||
|
||||
test('WorkspaceEdit - keep order of text and file changes', function () {
|
||||
|
||||
const edit = new types.WorkspaceEdit();
|
||||
edit.replace(URI.parse('foo:a'), new types.Range(1, 1, 1, 1), 'foo');
|
||||
edit.renameFile(URI.parse('foo:a'), URI.parse('foo:b'));
|
||||
edit.replace(URI.parse('foo:a'), new types.Range(2, 1, 2, 1), 'bar');
|
||||
edit.replace(URI.parse('foo:b'), new types.Range(3, 1, 3, 1), 'bazz');
|
||||
|
||||
const all = edit._allEntries();
|
||||
assert.strictEqual(all.length, 4);
|
||||
|
||||
const [first, second, third, fourth] = all;
|
||||
assertType(first._type === types.FileEditType.Text);
|
||||
assert.strictEqual(first.uri.toString(), 'foo:a');
|
||||
|
||||
assertType(second._type === types.FileEditType.File);
|
||||
assert.strictEqual(second.from!.toString(), 'foo:a');
|
||||
assert.strictEqual(second.to!.toString(), 'foo:b');
|
||||
|
||||
assertType(third._type === types.FileEditType.Text);
|
||||
assert.strictEqual(third.uri.toString(), 'foo:a');
|
||||
|
||||
assertType(fourth._type === types.FileEditType.Text);
|
||||
assert.strictEqual(fourth.uri.toString(), 'foo:b');
|
||||
});
|
||||
|
||||
test('WorkspaceEdit - two edits for one resource', function () {
|
||||
let edit = new types.WorkspaceEdit();
|
||||
let uri = URI.parse('foo:bar');
|
||||
edit.insert(uri, new types.Position(0, 0), 'Hello');
|
||||
edit.insert(uri, new types.Position(0, 0), 'Foo');
|
||||
|
||||
assert.strictEqual(edit._allEntries().length, 2);
|
||||
let [first, second] = edit._allEntries();
|
||||
|
||||
assertType(first._type === types.FileEditType.Text);
|
||||
assertType(second._type === types.FileEditType.Text);
|
||||
assert.strictEqual(first.edit.newText, 'Hello');
|
||||
assert.strictEqual(second.edit.newText, 'Foo');
|
||||
});
|
||||
|
||||
test('DocumentLink', () => {
|
||||
assert.throws(() => new types.DocumentLink(null!, null!));
|
||||
assert.throws(() => new types.DocumentLink(new types.Range(1, 1, 1, 1), null!));
|
||||
});
|
||||
|
||||
test('toJSON & stringify', function () {
|
||||
|
||||
assertToJSON(new types.Selection(3, 4, 2, 1), { start: { line: 2, character: 1 }, end: { line: 3, character: 4 }, anchor: { line: 3, character: 4 }, active: { line: 2, character: 1 } });
|
||||
|
||||
assertToJSON(new types.Location(URI.file('u.ts'), new types.Position(3, 4)), { uri: URI.parse('file:///u.ts').toJSON(), range: [{ line: 3, character: 4 }, { line: 3, character: 4 }] });
|
||||
assertToJSON(new types.Location(URI.file('u.ts'), new types.Range(1, 2, 3, 4)), { uri: URI.parse('file:///u.ts').toJSON(), range: [{ line: 1, character: 2 }, { line: 3, character: 4 }] });
|
||||
|
||||
let diag = new types.Diagnostic(new types.Range(0, 1, 2, 3), 'hello');
|
||||
assertToJSON(diag, { severity: 'Error', message: 'hello', range: [{ line: 0, character: 1 }, { line: 2, character: 3 }] });
|
||||
diag.source = 'me';
|
||||
assertToJSON(diag, { severity: 'Error', message: 'hello', range: [{ line: 0, character: 1 }, { line: 2, character: 3 }], source: 'me' });
|
||||
|
||||
assertToJSON(new types.DocumentHighlight(new types.Range(2, 3, 4, 5)), { range: [{ line: 2, character: 3 }, { line: 4, character: 5 }], kind: 'Text' });
|
||||
assertToJSON(new types.DocumentHighlight(new types.Range(2, 3, 4, 5), types.DocumentHighlightKind.Read), { range: [{ line: 2, character: 3 }, { line: 4, character: 5 }], kind: 'Read' });
|
||||
|
||||
assertToJSON(new types.SymbolInformation('test', types.SymbolKind.Boolean, new types.Range(0, 1, 2, 3)), {
|
||||
name: 'test',
|
||||
kind: 'Boolean',
|
||||
location: {
|
||||
range: [{ line: 0, character: 1 }, { line: 2, character: 3 }]
|
||||
}
|
||||
});
|
||||
|
||||
assertToJSON(new types.CodeLens(new types.Range(7, 8, 9, 10)), { range: [{ line: 7, character: 8 }, { line: 9, character: 10 }] });
|
||||
assertToJSON(new types.CodeLens(new types.Range(7, 8, 9, 10), { command: 'id', title: 'title' }), {
|
||||
range: [{ line: 7, character: 8 }, { line: 9, character: 10 }],
|
||||
command: { command: 'id', title: 'title' }
|
||||
});
|
||||
|
||||
assertToJSON(new types.CompletionItem('complete'), { label: 'complete' });
|
||||
|
||||
let item = new types.CompletionItem('complete');
|
||||
item.kind = types.CompletionItemKind.Interface;
|
||||
assertToJSON(item, { label: 'complete', kind: 'Interface' });
|
||||
|
||||
});
|
||||
|
||||
test('SymbolInformation, old ctor', function () {
|
||||
|
||||
let info = new types.SymbolInformation('foo', types.SymbolKind.Array, new types.Range(1, 1, 2, 3));
|
||||
assert.ok(info.location instanceof types.Location);
|
||||
assert.strictEqual(info.location.uri, undefined);
|
||||
});
|
||||
|
||||
test('SnippetString, builder-methods', function () {
|
||||
|
||||
let string: types.SnippetString;
|
||||
|
||||
string = new types.SnippetString();
|
||||
assert.strictEqual(string.appendText('I need $ and $').value, 'I need \\$ and \\$');
|
||||
|
||||
string = new types.SnippetString();
|
||||
assert.strictEqual(string.appendText('I need \\$').value, 'I need \\\\\\$');
|
||||
|
||||
string = new types.SnippetString();
|
||||
string.appendPlaceholder('fo$o}');
|
||||
assert.strictEqual(string.value, '${1:fo\\$o\\}}');
|
||||
|
||||
string = new types.SnippetString();
|
||||
string.appendText('foo').appendTabstop(0).appendText('bar');
|
||||
assert.strictEqual(string.value, 'foo$0bar');
|
||||
|
||||
string = new types.SnippetString();
|
||||
string.appendText('foo').appendTabstop().appendText('bar');
|
||||
assert.strictEqual(string.value, 'foo$1bar');
|
||||
|
||||
string = new types.SnippetString();
|
||||
string.appendText('foo').appendTabstop(42).appendText('bar');
|
||||
assert.strictEqual(string.value, 'foo$42bar');
|
||||
|
||||
string = new types.SnippetString();
|
||||
string.appendText('foo').appendPlaceholder('farboo').appendText('bar');
|
||||
assert.strictEqual(string.value, 'foo${1:farboo}bar');
|
||||
|
||||
string = new types.SnippetString();
|
||||
string.appendText('foo').appendPlaceholder('far$boo').appendText('bar');
|
||||
assert.strictEqual(string.value, 'foo${1:far\\$boo}bar');
|
||||
|
||||
string = new types.SnippetString();
|
||||
string.appendText('foo').appendPlaceholder(b => b.appendText('abc').appendPlaceholder('nested')).appendText('bar');
|
||||
assert.strictEqual(string.value, 'foo${1:abc${2:nested}}bar');
|
||||
|
||||
string = new types.SnippetString();
|
||||
string.appendVariable('foo');
|
||||
assert.strictEqual(string.value, '${foo}');
|
||||
|
||||
string = new types.SnippetString();
|
||||
string.appendText('foo').appendVariable('TM_SELECTED_TEXT').appendText('bar');
|
||||
assert.strictEqual(string.value, 'foo${TM_SELECTED_TEXT}bar');
|
||||
|
||||
string = new types.SnippetString();
|
||||
string.appendVariable('BAR', b => b.appendPlaceholder('ops'));
|
||||
assert.strictEqual(string.value, '${BAR:${1:ops}}');
|
||||
|
||||
string = new types.SnippetString();
|
||||
string.appendVariable('BAR', b => { });
|
||||
assert.strictEqual(string.value, '${BAR}');
|
||||
|
||||
string = new types.SnippetString();
|
||||
string.appendChoice(['b', 'a', 'r']);
|
||||
assert.strictEqual(string.value, '${1|b,a,r|}');
|
||||
|
||||
string = new types.SnippetString();
|
||||
string.appendChoice(['b,1', 'a,2', 'r,3']);
|
||||
assert.strictEqual(string.value, '${1|b\\,1,a\\,2,r\\,3|}');
|
||||
|
||||
string = new types.SnippetString();
|
||||
string.appendChoice(['b', 'a', 'r'], 0);
|
||||
assert.strictEqual(string.value, '${0|b,a,r|}');
|
||||
|
||||
string = new types.SnippetString();
|
||||
string.appendText('foo').appendChoice(['far', 'boo']).appendText('bar');
|
||||
assert.strictEqual(string.value, 'foo${1|far,boo|}bar');
|
||||
|
||||
string = new types.SnippetString();
|
||||
string.appendText('foo').appendChoice(['far', '$boo']).appendText('bar');
|
||||
assert.strictEqual(string.value, 'foo${1|far,\\$boo|}bar');
|
||||
|
||||
string = new types.SnippetString();
|
||||
string.appendText('foo').appendPlaceholder('farboo').appendChoice(['far', 'boo']).appendText('bar');
|
||||
assert.strictEqual(string.value, 'foo${1:farboo}${2|far,boo|}bar');
|
||||
});
|
||||
|
||||
test('instanceof doesn\'t work for FileSystemError #49386', function () {
|
||||
const error = types.FileSystemError.Unavailable('foo');
|
||||
assert.ok(error instanceof Error);
|
||||
assert.ok(error instanceof types.FileSystemError);
|
||||
});
|
||||
|
||||
test('CodeActionKind contains', () => {
|
||||
assert.ok(types.CodeActionKind.RefactorExtract.contains(types.CodeActionKind.RefactorExtract));
|
||||
assert.ok(types.CodeActionKind.RefactorExtract.contains(types.CodeActionKind.RefactorExtract.append('other')));
|
||||
|
||||
assert.ok(!types.CodeActionKind.RefactorExtract.contains(types.CodeActionKind.Refactor));
|
||||
assert.ok(!types.CodeActionKind.RefactorExtract.contains(types.CodeActionKind.Refactor.append('other')));
|
||||
assert.ok(!types.CodeActionKind.RefactorExtract.contains(types.CodeActionKind.Empty.append('other').append('refactor')));
|
||||
assert.ok(!types.CodeActionKind.RefactorExtract.contains(types.CodeActionKind.Empty.append('refactory')));
|
||||
});
|
||||
|
||||
test('CodeActionKind intersects', () => {
|
||||
assert.ok(types.CodeActionKind.RefactorExtract.intersects(types.CodeActionKind.RefactorExtract));
|
||||
assert.ok(types.CodeActionKind.RefactorExtract.intersects(types.CodeActionKind.Refactor));
|
||||
assert.ok(types.CodeActionKind.RefactorExtract.intersects(types.CodeActionKind.RefactorExtract.append('other')));
|
||||
|
||||
assert.ok(!types.CodeActionKind.RefactorExtract.intersects(types.CodeActionKind.Refactor.append('other')));
|
||||
assert.ok(!types.CodeActionKind.RefactorExtract.intersects(types.CodeActionKind.Empty.append('other').append('refactor')));
|
||||
assert.ok(!types.CodeActionKind.RefactorExtract.intersects(types.CodeActionKind.Empty.append('refactory')));
|
||||
});
|
||||
|
||||
function toArr(uint32Arr: Uint32Array): number[] {
|
||||
const r = [];
|
||||
for (let i = 0, len = uint32Arr.length; i < len; i++) {
|
||||
r[i] = uint32Arr[i];
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
test('SemanticTokensBuilder simple', () => {
|
||||
const builder = new types.SemanticTokensBuilder();
|
||||
builder.push(1, 0, 5, 1, 1);
|
||||
builder.push(1, 10, 4, 2, 2);
|
||||
builder.push(2, 2, 3, 2, 2);
|
||||
assert.deepStrictEqual(toArr(builder.build().data), [
|
||||
1, 0, 5, 1, 1,
|
||||
0, 10, 4, 2, 2,
|
||||
1, 2, 3, 2, 2
|
||||
]);
|
||||
});
|
||||
|
||||
test('SemanticTokensBuilder no modifier', () => {
|
||||
const builder = new types.SemanticTokensBuilder();
|
||||
builder.push(1, 0, 5, 1);
|
||||
builder.push(1, 10, 4, 2);
|
||||
builder.push(2, 2, 3, 2);
|
||||
assert.deepStrictEqual(toArr(builder.build().data), [
|
||||
1, 0, 5, 1, 0,
|
||||
0, 10, 4, 2, 0,
|
||||
1, 2, 3, 2, 0
|
||||
]);
|
||||
});
|
||||
|
||||
test('SemanticTokensBuilder out of order 1', () => {
|
||||
const builder = new types.SemanticTokensBuilder();
|
||||
builder.push(2, 0, 5, 1, 1);
|
||||
builder.push(2, 10, 1, 2, 2);
|
||||
builder.push(2, 15, 2, 3, 3);
|
||||
builder.push(1, 0, 4, 4, 4);
|
||||
assert.deepStrictEqual(toArr(builder.build().data), [
|
||||
1, 0, 4, 4, 4,
|
||||
1, 0, 5, 1, 1,
|
||||
0, 10, 1, 2, 2,
|
||||
0, 5, 2, 3, 3
|
||||
]);
|
||||
});
|
||||
|
||||
test('SemanticTokensBuilder out of order 2', () => {
|
||||
const builder = new types.SemanticTokensBuilder();
|
||||
builder.push(2, 10, 5, 1, 1);
|
||||
builder.push(2, 2, 4, 2, 2);
|
||||
assert.deepStrictEqual(toArr(builder.build().data), [
|
||||
2, 2, 4, 2, 2,
|
||||
0, 8, 5, 1, 1
|
||||
]);
|
||||
});
|
||||
|
||||
test('SemanticTokensBuilder with legend', () => {
|
||||
const legend = new types.SemanticTokensLegend(
|
||||
['aType', 'bType', 'cType', 'dType'],
|
||||
['mod0', 'mod1', 'mod2', 'mod3', 'mod4', 'mod5']
|
||||
);
|
||||
const builder = new types.SemanticTokensBuilder(legend);
|
||||
builder.push(new types.Range(1, 0, 1, 5), 'bType');
|
||||
builder.push(new types.Range(2, 0, 2, 4), 'cType', ['mod0', 'mod5']);
|
||||
builder.push(new types.Range(3, 0, 3, 3), 'dType', ['mod2', 'mod4']);
|
||||
assert.deepStrictEqual(toArr(builder.build().data), [
|
||||
1, 0, 5, 1, 0,
|
||||
1, 0, 4, 2, 1 | (1 << 5),
|
||||
1, 0, 3, 3, (1 << 2) | (1 << 4)
|
||||
]);
|
||||
});
|
||||
|
||||
test('Markdown codeblock rendering is swapped #111604', function () {
|
||||
const md = new types.MarkdownString().appendCodeblock('<img src=0 onerror="alert(1)">', 'html');
|
||||
assert.deepStrictEqual(md.value, '\n```html\n<img src=0 onerror="alert(1)">\n```\n');
|
||||
});
|
||||
|
||||
test('NotebookCellOutputItem - factories', function () {
|
||||
|
||||
assert.throws(() => {
|
||||
// invalid mime type
|
||||
new types.NotebookCellOutputItem(new Uint8Array(), 'invalid');
|
||||
});
|
||||
|
||||
// --- err
|
||||
|
||||
let item = types.NotebookCellOutputItem.error(new Error());
|
||||
assert.strictEqual(item.mime, 'application/vnd.code.notebook.error');
|
||||
item = types.NotebookCellOutputItem.error({ name: 'Hello' });
|
||||
assert.strictEqual(item.mime, 'application/vnd.code.notebook.error');
|
||||
|
||||
// --- JSON
|
||||
|
||||
item = types.NotebookCellOutputItem.json(1);
|
||||
assert.strictEqual(item.mime, 'application/json');
|
||||
assert.deepStrictEqual(item.data, new TextEncoder().encode(JSON.stringify(1)));
|
||||
|
||||
item = types.NotebookCellOutputItem.json(1, 'foo/bar');
|
||||
assert.strictEqual(item.mime, 'foo/bar');
|
||||
assert.deepStrictEqual(item.data, new TextEncoder().encode(JSON.stringify(1)));
|
||||
|
||||
item = types.NotebookCellOutputItem.json(true);
|
||||
assert.strictEqual(item.mime, 'application/json');
|
||||
assert.deepStrictEqual(item.data, new TextEncoder().encode(JSON.stringify(true)));
|
||||
|
||||
item = types.NotebookCellOutputItem.json([true, 1, 'ddd']);
|
||||
assert.strictEqual(item.mime, 'application/json');
|
||||
assert.deepStrictEqual(item.data, new TextEncoder().encode(JSON.stringify([true, 1, 'ddd'], undefined, '\t')));
|
||||
|
||||
// --- text
|
||||
|
||||
item = types.NotebookCellOutputItem.text('Hęłlö');
|
||||
assert.strictEqual(item.mime, Mimes.text);
|
||||
assert.deepStrictEqual(item.data, new TextEncoder().encode('Hęłlö'));
|
||||
|
||||
item = types.NotebookCellOutputItem.text('Hęłlö', 'foo/bar');
|
||||
assert.strictEqual(item.mime, 'foo/bar');
|
||||
assert.deepStrictEqual(item.data, new TextEncoder().encode('Hęłlö'));
|
||||
});
|
||||
|
||||
test('FileDecoration#validate', function () {
|
||||
|
||||
assert.ok(types.FileDecoration.validate({ badge: 'u' }));
|
||||
assert.ok(types.FileDecoration.validate({ badge: 'ü' }));
|
||||
assert.ok(types.FileDecoration.validate({ badge: '1' }));
|
||||
assert.ok(types.FileDecoration.validate({ badge: 'ãã' }));
|
||||
assert.ok(types.FileDecoration.validate({ badge: '👋' }));
|
||||
assert.ok(types.FileDecoration.validate({ badge: '👋👋' }));
|
||||
assert.ok(types.FileDecoration.validate({ badge: '👩👩👧👧' }));
|
||||
assert.ok(types.FileDecoration.validate({ badge: 'போ' }));
|
||||
assert.throws(() => types.FileDecoration.validate({ badge: 'hel' }));
|
||||
assert.throws(() => types.FileDecoration.validate({ badge: '👋👋👋' }));
|
||||
assert.throws(() => types.FileDecoration.validate({ badge: 'புன்சிரிப்போடு' }));
|
||||
assert.throws(() => types.FileDecoration.validate({ badge: 'ããã' }));
|
||||
});
|
||||
});
|
||||
@@ -1,198 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { Schemas } from 'vs/base/common/network';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { mock } from 'vs/base/test/common/mock';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
import { MainThreadWebviewManager } from 'vs/workbench/api/browser/mainThreadWebviewManager';
|
||||
import { IExtHostContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { NullApiDeprecationService } from 'vs/workbench/api/common/extHostApiDeprecationService';
|
||||
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
import { ExtHostWebviews } from 'vs/workbench/api/common/extHostWebview';
|
||||
import { ExtHostWebviewPanels } from 'vs/workbench/api/common/extHostWebviewPanels';
|
||||
import { decodeAuthority, webviewResourceBaseHost } from 'vs/workbench/api/common/shared/webview';
|
||||
import { EditorGroupColumn } from 'vs/workbench/services/editor/common/editorGroupColumn';
|
||||
import type * as vscode from 'vscode';
|
||||
import { SingleProxyRPCProtocol } from './testRPCProtocol';
|
||||
|
||||
suite('ExtHostWebview', () => {
|
||||
|
||||
let rpcProtocol: (IExtHostRpcService & IExtHostContext) | undefined;
|
||||
|
||||
setup(() => {
|
||||
const shape = createNoopMainThreadWebviews();
|
||||
rpcProtocol = SingleProxyRPCProtocol(shape);
|
||||
});
|
||||
|
||||
test('Cannot register multiple serializers for the same view type', async () => {
|
||||
const viewType = 'view.type';
|
||||
|
||||
const extHostWebviews = new ExtHostWebviews(rpcProtocol!, { remote: { authority: undefined, isRemote: false } }, undefined, new NullLogService(), NullApiDeprecationService);
|
||||
|
||||
const extHostWebviewPanels = new ExtHostWebviewPanels(rpcProtocol!, extHostWebviews, undefined);
|
||||
|
||||
let lastInvokedDeserializer: vscode.WebviewPanelSerializer | undefined = undefined;
|
||||
|
||||
class NoopSerializer implements vscode.WebviewPanelSerializer {
|
||||
async deserializeWebviewPanel(_webview: vscode.WebviewPanel, _state: any): Promise<void> {
|
||||
lastInvokedDeserializer = this;
|
||||
}
|
||||
}
|
||||
|
||||
const extension = {} as IExtensionDescription;
|
||||
|
||||
const serializerA = new NoopSerializer();
|
||||
const serializerB = new NoopSerializer();
|
||||
|
||||
const serializerARegistration = extHostWebviewPanels.registerWebviewPanelSerializer(extension, viewType, serializerA);
|
||||
|
||||
await extHostWebviewPanels.$deserializeWebviewPanel('x', viewType, {
|
||||
title: 'title',
|
||||
state: {},
|
||||
panelOptions: {},
|
||||
webviewOptions: {}
|
||||
}, 0 as EditorGroupColumn);
|
||||
assert.strictEqual(lastInvokedDeserializer, serializerA);
|
||||
|
||||
assert.throws(
|
||||
() => extHostWebviewPanels.registerWebviewPanelSerializer(extension, viewType, serializerB),
|
||||
'Should throw when registering two serializers for the same view');
|
||||
|
||||
serializerARegistration.dispose();
|
||||
|
||||
extHostWebviewPanels.registerWebviewPanelSerializer(extension, viewType, serializerB);
|
||||
|
||||
await extHostWebviewPanels.$deserializeWebviewPanel('x', viewType, {
|
||||
title: 'title',
|
||||
state: {},
|
||||
panelOptions: {},
|
||||
webviewOptions: {}
|
||||
}, 0 as EditorGroupColumn);
|
||||
assert.strictEqual(lastInvokedDeserializer, serializerB);
|
||||
});
|
||||
|
||||
test('asWebviewUri for local file paths', () => {
|
||||
const webview = createWebview(rpcProtocol, /* remoteAuthority */undefined);
|
||||
|
||||
assert.strictEqual(
|
||||
(webview.webview.asWebviewUri(URI.parse('file:///Users/codey/file.html')).toString()),
|
||||
`https://file%2B.vscode-resource.${webviewResourceBaseHost}/Users/codey/file.html`,
|
||||
'Unix basic'
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
(webview.webview.asWebviewUri(URI.parse('file:///Users/codey/file.html#frag')).toString()),
|
||||
`https://file%2B.vscode-resource.${webviewResourceBaseHost}/Users/codey/file.html#frag`,
|
||||
'Unix should preserve fragment'
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
(webview.webview.asWebviewUri(URI.parse('file:///Users/codey/f%20ile.html')).toString()),
|
||||
`https://file%2B.vscode-resource.${webviewResourceBaseHost}/Users/codey/f%20ile.html`,
|
||||
'Unix with encoding'
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
(webview.webview.asWebviewUri(URI.parse('file://localhost/Users/codey/file.html')).toString()),
|
||||
`https://file%2Blocalhost.vscode-resource.${webviewResourceBaseHost}/Users/codey/file.html`,
|
||||
'Unix should preserve authority'
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
(webview.webview.asWebviewUri(URI.parse('file:///c:/codey/file.txt')).toString()),
|
||||
`https://file%2B.vscode-resource.${webviewResourceBaseHost}/c%3A/codey/file.txt`,
|
||||
'Windows C drive'
|
||||
);
|
||||
});
|
||||
|
||||
test('asWebviewUri for remote file paths', () => {
|
||||
const webview = createWebview(rpcProtocol, /* remoteAuthority */ 'remote');
|
||||
|
||||
assert.strictEqual(
|
||||
(webview.webview.asWebviewUri(URI.parse('file:///Users/codey/file.html')).toString()),
|
||||
`https://vscode-remote%2Bremote.vscode-resource.${webviewResourceBaseHost}/Users/codey/file.html`,
|
||||
'Unix basic'
|
||||
);
|
||||
});
|
||||
|
||||
test('asWebviewUri for remote with / and + in name', () => {
|
||||
const webview = createWebview(rpcProtocol, /* remoteAuthority */ 'remote');
|
||||
const authority = 'ssh-remote+localhost=foo/bar';
|
||||
|
||||
const sourceUri = URI.from({
|
||||
scheme: 'vscode-remote',
|
||||
authority: authority,
|
||||
path: '/Users/cody/x.png'
|
||||
});
|
||||
|
||||
const webviewUri = webview.webview.asWebviewUri(sourceUri);
|
||||
assert.strictEqual(
|
||||
webviewUri.toString(),
|
||||
`https://vscode-remote%2Bssh-002dremote-002blocalhost-003dfoo-002fbar.vscode-resource.vscode-webview.net/Users/cody/x.png`,
|
||||
'Check transform');
|
||||
|
||||
assert.strictEqual(
|
||||
decodeAuthority(webviewUri.authority),
|
||||
`vscode-remote+${authority}.vscode-resource.vscode-webview.net`,
|
||||
'Check decoded authority'
|
||||
);
|
||||
});
|
||||
|
||||
test('asWebviewUri for remote with port in name', () => {
|
||||
const webview = createWebview(rpcProtocol, /* remoteAuthority */ 'remote');
|
||||
const authority = 'localhost:8080';
|
||||
|
||||
const sourceUri = URI.from({
|
||||
scheme: 'vscode-remote',
|
||||
authority: authority,
|
||||
path: '/Users/cody/x.png'
|
||||
});
|
||||
|
||||
const webviewUri = webview.webview.asWebviewUri(sourceUri);
|
||||
assert.strictEqual(
|
||||
webviewUri.toString(),
|
||||
`https://vscode-remote%2Blocalhost-003a8080.vscode-resource.vscode-webview.net/Users/cody/x.png`,
|
||||
'Check transform');
|
||||
|
||||
assert.strictEqual(
|
||||
decodeAuthority(webviewUri.authority),
|
||||
`vscode-remote+${authority}.vscode-resource.vscode-webview.net`,
|
||||
'Check decoded authority'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
function createWebview(rpcProtocol: (IExtHostRpcService & IExtHostContext) | undefined, remoteAuthority: string | undefined) {
|
||||
const extHostWebviews = new ExtHostWebviews(rpcProtocol!, {
|
||||
remote: {
|
||||
authority: remoteAuthority,
|
||||
isRemote: !!remoteAuthority,
|
||||
},
|
||||
}, undefined, new NullLogService(), NullApiDeprecationService);
|
||||
|
||||
const extHostWebviewPanels = new ExtHostWebviewPanels(rpcProtocol!, extHostWebviews, undefined);
|
||||
|
||||
const webview = extHostWebviewPanels.createWebviewPanel({
|
||||
extensionLocation: URI.from({
|
||||
scheme: remoteAuthority ? Schemas.vscodeRemote : Schemas.file,
|
||||
authority: remoteAuthority,
|
||||
path: '/ext/path',
|
||||
})
|
||||
} as IExtensionDescription, 'type', 'title', 1, {});
|
||||
return webview;
|
||||
}
|
||||
|
||||
|
||||
function createNoopMainThreadWebviews() {
|
||||
return new class extends mock<MainThreadWebviewManager>() {
|
||||
$createWebviewPanel() { /* noop */ }
|
||||
$registerSerializer() { /* noop */ }
|
||||
$unregisterSerializer() { /* noop */ }
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,798 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { basename } from 'vs/base/common/path';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ILogService, NullLogService } from 'vs/platform/log/common/log';
|
||||
import { IWorkspaceFolderData } from 'vs/platform/workspace/common/workspace';
|
||||
import { MainThreadWorkspace } from 'vs/workbench/api/browser/mainThreadWorkspace';
|
||||
import { IMainContext, IWorkspaceData, MainContext, ITextSearchComplete } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { RelativePattern } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { ExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
import { mock } from 'vs/base/test/common/mock';
|
||||
import { TestRPCProtocol } from './testRPCProtocol';
|
||||
import { ExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
|
||||
import { ITextQueryBuilderOptions } from 'vs/workbench/contrib/search/common/queryBuilder';
|
||||
import { IPatternInfo } from 'vs/workbench/services/search/common/search';
|
||||
import { isLinux, isWindows } from 'vs/base/common/platform';
|
||||
import { IExtHostFileSystemInfo } from 'vs/workbench/api/common/extHostFileSystemInfo';
|
||||
import { FileSystemProviderCapabilities } from 'vs/platform/files/common/files';
|
||||
|
||||
function createExtHostWorkspace(mainContext: IMainContext, data: IWorkspaceData, logService: ILogService): ExtHostWorkspace {
|
||||
const result = new ExtHostWorkspace(
|
||||
new ExtHostRpcService(mainContext),
|
||||
new class extends mock<IExtHostInitDataService>() { override workspace = data; },
|
||||
new class extends mock<IExtHostFileSystemInfo>() { override getCapabilities() { return isLinux ? FileSystemProviderCapabilities.PathCaseSensitive : undefined; } },
|
||||
logService,
|
||||
);
|
||||
result.$initializeWorkspace(data, true);
|
||||
return result;
|
||||
}
|
||||
|
||||
suite('ExtHostWorkspace', function () {
|
||||
|
||||
const extensionDescriptor: IExtensionDescription = {
|
||||
identifier: new ExtensionIdentifier('nullExtensionDescription'),
|
||||
name: 'ext',
|
||||
publisher: 'vscode',
|
||||
enableProposedApi: false,
|
||||
engines: undefined!,
|
||||
extensionLocation: undefined!,
|
||||
isBuiltin: false,
|
||||
isUserBuiltin: false,
|
||||
isUnderDevelopment: false,
|
||||
version: undefined!
|
||||
};
|
||||
|
||||
function assertAsRelativePath(workspace: ExtHostWorkspace, input: string, expected: string, includeWorkspace?: boolean) {
|
||||
const actual = workspace.getRelativePath(input, includeWorkspace);
|
||||
assert.strictEqual(actual, expected);
|
||||
}
|
||||
|
||||
test('asRelativePath', () => {
|
||||
|
||||
const ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/Applications/NewsWoWBot'), 0)], name: 'Test' }, new NullLogService());
|
||||
|
||||
assertAsRelativePath(ws, '/Coding/Applications/NewsWoWBot/bernd/das/brot', 'bernd/das/brot');
|
||||
assertAsRelativePath(ws, '/Apps/DartPubCache/hosted/pub.dartlang.org/convert-2.0.1/lib/src/hex.dart',
|
||||
'/Apps/DartPubCache/hosted/pub.dartlang.org/convert-2.0.1/lib/src/hex.dart');
|
||||
|
||||
assertAsRelativePath(ws, '', '');
|
||||
assertAsRelativePath(ws, '/foo/bar', '/foo/bar');
|
||||
assertAsRelativePath(ws, 'in/out', 'in/out');
|
||||
});
|
||||
|
||||
test('asRelativePath, same paths, #11402', function () {
|
||||
const root = '/home/aeschli/workspaces/samples/docker';
|
||||
const input = '/home/aeschli/workspaces/samples/docker';
|
||||
const ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());
|
||||
|
||||
assertAsRelativePath(ws, input, input);
|
||||
|
||||
const input2 = '/home/aeschli/workspaces/samples/docker/a.file';
|
||||
assertAsRelativePath(ws, input2, 'a.file');
|
||||
});
|
||||
|
||||
test('asRelativePath, no workspace', function () {
|
||||
const ws = createExtHostWorkspace(new TestRPCProtocol(), null!, new NullLogService());
|
||||
assertAsRelativePath(ws, '', '');
|
||||
assertAsRelativePath(ws, '/foo/bar', '/foo/bar');
|
||||
});
|
||||
|
||||
test('asRelativePath, multiple folders', function () {
|
||||
const ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }, new NullLogService());
|
||||
assertAsRelativePath(ws, '/Coding/One/file.txt', 'One/file.txt');
|
||||
assertAsRelativePath(ws, '/Coding/Two/files/out.txt', 'Two/files/out.txt');
|
||||
assertAsRelativePath(ws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt');
|
||||
});
|
||||
|
||||
test('slightly inconsistent behaviour of asRelativePath and getWorkspaceFolder, #31553', function () {
|
||||
const mrws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }, new NullLogService());
|
||||
|
||||
assertAsRelativePath(mrws, '/Coding/One/file.txt', 'One/file.txt');
|
||||
assertAsRelativePath(mrws, '/Coding/One/file.txt', 'One/file.txt', true);
|
||||
assertAsRelativePath(mrws, '/Coding/One/file.txt', 'file.txt', false);
|
||||
assertAsRelativePath(mrws, '/Coding/Two/files/out.txt', 'Two/files/out.txt');
|
||||
assertAsRelativePath(mrws, '/Coding/Two/files/out.txt', 'Two/files/out.txt', true);
|
||||
assertAsRelativePath(mrws, '/Coding/Two/files/out.txt', 'files/out.txt', false);
|
||||
assertAsRelativePath(mrws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt');
|
||||
assertAsRelativePath(mrws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt', true);
|
||||
assertAsRelativePath(mrws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt', false);
|
||||
|
||||
const srws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0)], name: 'Test' }, new NullLogService());
|
||||
assertAsRelativePath(srws, '/Coding/One/file.txt', 'file.txt');
|
||||
assertAsRelativePath(srws, '/Coding/One/file.txt', 'file.txt', false);
|
||||
assertAsRelativePath(srws, '/Coding/One/file.txt', 'One/file.txt', true);
|
||||
assertAsRelativePath(srws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt');
|
||||
assertAsRelativePath(srws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt', true);
|
||||
assertAsRelativePath(srws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt', false);
|
||||
});
|
||||
|
||||
test('getPath, legacy', function () {
|
||||
let ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService());
|
||||
assert.strictEqual(ws.getPath(), undefined);
|
||||
|
||||
ws = createExtHostWorkspace(new TestRPCProtocol(), null!, new NullLogService());
|
||||
assert.strictEqual(ws.getPath(), undefined);
|
||||
|
||||
ws = createExtHostWorkspace(new TestRPCProtocol(), undefined!, new NullLogService());
|
||||
assert.strictEqual(ws.getPath(), undefined);
|
||||
|
||||
ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.file('Folder'), 0), aWorkspaceFolderData(URI.file('Another/Folder'), 1)] }, new NullLogService());
|
||||
assert.strictEqual(ws.getPath()!.replace(/\\/g, '/'), '/Folder');
|
||||
|
||||
ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.file('/Folder'), 0)] }, new NullLogService());
|
||||
assert.strictEqual(ws.getPath()!.replace(/\\/g, '/'), '/Folder');
|
||||
});
|
||||
|
||||
test('WorkspaceFolder has name and index', function () {
|
||||
const ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }, new NullLogService());
|
||||
|
||||
const [one, two] = ws.getWorkspaceFolders()!;
|
||||
|
||||
assert.strictEqual(one.name, 'One');
|
||||
assert.strictEqual(one.index, 0);
|
||||
assert.strictEqual(two.name, 'Two');
|
||||
assert.strictEqual(two.index, 1);
|
||||
});
|
||||
|
||||
test('getContainingWorkspaceFolder', () => {
|
||||
const ws = createExtHostWorkspace(new TestRPCProtocol(), {
|
||||
id: 'foo',
|
||||
name: 'Test',
|
||||
folders: [
|
||||
aWorkspaceFolderData(URI.file('/Coding/One'), 0),
|
||||
aWorkspaceFolderData(URI.file('/Coding/Two'), 1),
|
||||
aWorkspaceFolderData(URI.file('/Coding/Two/Nested'), 2)
|
||||
]
|
||||
}, new NullLogService());
|
||||
|
||||
let folder = ws.getWorkspaceFolder(URI.file('/foo/bar'));
|
||||
assert.strictEqual(folder, undefined);
|
||||
|
||||
folder = ws.getWorkspaceFolder(URI.file('/Coding/One/file/path.txt'))!;
|
||||
assert.strictEqual(folder.name, 'One');
|
||||
|
||||
folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/file/path.txt'))!;
|
||||
assert.strictEqual(folder.name, 'Two');
|
||||
|
||||
folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nest'))!;
|
||||
assert.strictEqual(folder.name, 'Two');
|
||||
|
||||
folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested/file'))!;
|
||||
assert.strictEqual(folder.name, 'Nested');
|
||||
|
||||
folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested/f'))!;
|
||||
assert.strictEqual(folder.name, 'Nested');
|
||||
|
||||
folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested'), true)!;
|
||||
assert.strictEqual(folder.name, 'Two');
|
||||
|
||||
folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested/'), true)!;
|
||||
assert.strictEqual(folder.name, 'Two');
|
||||
|
||||
folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested'))!;
|
||||
assert.strictEqual(folder.name, 'Nested');
|
||||
|
||||
folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested/'))!;
|
||||
assert.strictEqual(folder.name, 'Nested');
|
||||
|
||||
folder = ws.getWorkspaceFolder(URI.file('/Coding/Two'), true)!;
|
||||
assert.strictEqual(folder, undefined);
|
||||
|
||||
folder = ws.getWorkspaceFolder(URI.file('/Coding/Two'), false)!;
|
||||
assert.strictEqual(folder.name, 'Two');
|
||||
});
|
||||
|
||||
test('Multiroot change event should have a delta, #29641', function (done) {
|
||||
let ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService());
|
||||
|
||||
let finished = false;
|
||||
const finish = (error?: any) => {
|
||||
if (!finished) {
|
||||
finished = true;
|
||||
done(error);
|
||||
}
|
||||
};
|
||||
|
||||
let sub = ws.onDidChangeWorkspace(e => {
|
||||
try {
|
||||
assert.deepStrictEqual(e.added, []);
|
||||
assert.deepStrictEqual(e.removed, []);
|
||||
} catch (error) {
|
||||
finish(error);
|
||||
}
|
||||
});
|
||||
ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [] });
|
||||
sub.dispose();
|
||||
|
||||
sub = ws.onDidChangeWorkspace(e => {
|
||||
try {
|
||||
assert.deepStrictEqual(e.removed, []);
|
||||
assert.strictEqual(e.added.length, 1);
|
||||
assert.strictEqual(e.added[0].uri.toString(), 'foo:bar');
|
||||
} catch (error) {
|
||||
finish(error);
|
||||
}
|
||||
});
|
||||
ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] });
|
||||
sub.dispose();
|
||||
|
||||
sub = ws.onDidChangeWorkspace(e => {
|
||||
try {
|
||||
assert.deepStrictEqual(e.removed, []);
|
||||
assert.strictEqual(e.added.length, 1);
|
||||
assert.strictEqual(e.added[0].uri.toString(), 'foo:bar2');
|
||||
} catch (error) {
|
||||
finish(error);
|
||||
}
|
||||
});
|
||||
ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0), aWorkspaceFolderData(URI.parse('foo:bar2'), 1)] });
|
||||
sub.dispose();
|
||||
|
||||
sub = ws.onDidChangeWorkspace(e => {
|
||||
try {
|
||||
assert.strictEqual(e.removed.length, 2);
|
||||
assert.strictEqual(e.removed[0].uri.toString(), 'foo:bar');
|
||||
assert.strictEqual(e.removed[1].uri.toString(), 'foo:bar2');
|
||||
|
||||
assert.strictEqual(e.added.length, 1);
|
||||
assert.strictEqual(e.added[0].uri.toString(), 'foo:bar3');
|
||||
} catch (error) {
|
||||
finish(error);
|
||||
}
|
||||
});
|
||||
ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar3'), 0)] });
|
||||
sub.dispose();
|
||||
finish();
|
||||
});
|
||||
|
||||
test('Multiroot change keeps existing workspaces live', function () {
|
||||
let ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] }, new NullLogService());
|
||||
|
||||
let firstFolder = ws.getWorkspaceFolders()![0];
|
||||
ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar2'), 0), aWorkspaceFolderData(URI.parse('foo:bar'), 1, 'renamed')] });
|
||||
|
||||
assert.strictEqual(ws.getWorkspaceFolders()![1], firstFolder);
|
||||
assert.strictEqual(firstFolder.index, 1);
|
||||
assert.strictEqual(firstFolder.name, 'renamed');
|
||||
|
||||
ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar3'), 0), aWorkspaceFolderData(URI.parse('foo:bar2'), 1), aWorkspaceFolderData(URI.parse('foo:bar'), 2)] });
|
||||
assert.strictEqual(ws.getWorkspaceFolders()![2], firstFolder);
|
||||
assert.strictEqual(firstFolder.index, 2);
|
||||
|
||||
ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar3'), 0)] });
|
||||
ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar3'), 0), aWorkspaceFolderData(URI.parse('foo:bar'), 1)] });
|
||||
|
||||
assert.notStrictEqual(firstFolder, ws.workspace!.folders[0]);
|
||||
});
|
||||
|
||||
test('updateWorkspaceFolders - invalid arguments', function () {
|
||||
let ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService());
|
||||
|
||||
assert.strictEqual(false, ws.updateWorkspaceFolders(extensionDescriptor, null!, null!));
|
||||
assert.strictEqual(false, ws.updateWorkspaceFolders(extensionDescriptor, 0, 0));
|
||||
assert.strictEqual(false, ws.updateWorkspaceFolders(extensionDescriptor, 0, 1));
|
||||
assert.strictEqual(false, ws.updateWorkspaceFolders(extensionDescriptor, 1, 0));
|
||||
assert.strictEqual(false, ws.updateWorkspaceFolders(extensionDescriptor, -1, 0));
|
||||
assert.strictEqual(false, ws.updateWorkspaceFolders(extensionDescriptor, -1, -1));
|
||||
|
||||
ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] }, new NullLogService());
|
||||
|
||||
assert.strictEqual(false, ws.updateWorkspaceFolders(extensionDescriptor, 1, 1));
|
||||
assert.strictEqual(false, ws.updateWorkspaceFolders(extensionDescriptor, 0, 2));
|
||||
assert.strictEqual(false, ws.updateWorkspaceFolders(extensionDescriptor, 0, 1, asUpdateWorkspaceFolderData(URI.parse('foo:bar'))));
|
||||
});
|
||||
|
||||
test('updateWorkspaceFolders - valid arguments', function (done) {
|
||||
let finished = false;
|
||||
const finish = (error?: any) => {
|
||||
if (!finished) {
|
||||
finished = true;
|
||||
done(error);
|
||||
}
|
||||
};
|
||||
|
||||
const protocol: IMainContext = {
|
||||
getProxy: () => { return undefined!; },
|
||||
set: () => { return undefined!; },
|
||||
assertRegistered: () => { },
|
||||
drain: () => { return undefined!; },
|
||||
};
|
||||
|
||||
const ws = createExtHostWorkspace(protocol, { id: 'foo', name: 'Test', folders: [] }, new NullLogService());
|
||||
|
||||
//
|
||||
// Add one folder
|
||||
//
|
||||
|
||||
assert.strictEqual(true, ws.updateWorkspaceFolders(extensionDescriptor, 0, 0, asUpdateWorkspaceFolderData(URI.parse('foo:bar'))));
|
||||
assert.strictEqual(1, ws.workspace!.folders.length);
|
||||
assert.strictEqual(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar').toString());
|
||||
|
||||
const firstAddedFolder = ws.getWorkspaceFolders()![0];
|
||||
|
||||
let gotEvent = false;
|
||||
let sub = ws.onDidChangeWorkspace(e => {
|
||||
try {
|
||||
assert.deepStrictEqual(e.removed, []);
|
||||
assert.strictEqual(e.added.length, 1);
|
||||
assert.strictEqual(e.added[0].uri.toString(), 'foo:bar');
|
||||
assert.strictEqual(e.added[0], firstAddedFolder); // verify object is still live
|
||||
gotEvent = true;
|
||||
} catch (error) {
|
||||
finish(error);
|
||||
}
|
||||
});
|
||||
ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] }); // simulate acknowledgement from main side
|
||||
assert.strictEqual(gotEvent, true);
|
||||
sub.dispose();
|
||||
assert.strictEqual(ws.getWorkspaceFolders()![0], firstAddedFolder); // verify object is still live
|
||||
|
||||
//
|
||||
// Add two more folders
|
||||
//
|
||||
|
||||
assert.strictEqual(true, ws.updateWorkspaceFolders(extensionDescriptor, 1, 0, asUpdateWorkspaceFolderData(URI.parse('foo:bar1')), asUpdateWorkspaceFolderData(URI.parse('foo:bar2'))));
|
||||
assert.strictEqual(3, ws.workspace!.folders.length);
|
||||
assert.strictEqual(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar').toString());
|
||||
assert.strictEqual(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar1').toString());
|
||||
assert.strictEqual(ws.workspace!.folders[2].uri.toString(), URI.parse('foo:bar2').toString());
|
||||
|
||||
const secondAddedFolder = ws.getWorkspaceFolders()![1];
|
||||
const thirdAddedFolder = ws.getWorkspaceFolders()![2];
|
||||
|
||||
gotEvent = false;
|
||||
sub = ws.onDidChangeWorkspace(e => {
|
||||
try {
|
||||
assert.deepStrictEqual(e.removed, []);
|
||||
assert.strictEqual(e.added.length, 2);
|
||||
assert.strictEqual(e.added[0].uri.toString(), 'foo:bar1');
|
||||
assert.strictEqual(e.added[1].uri.toString(), 'foo:bar2');
|
||||
assert.strictEqual(e.added[0], secondAddedFolder);
|
||||
assert.strictEqual(e.added[1], thirdAddedFolder);
|
||||
gotEvent = true;
|
||||
} catch (error) {
|
||||
finish(error);
|
||||
}
|
||||
});
|
||||
ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0), aWorkspaceFolderData(URI.parse('foo:bar1'), 1), aWorkspaceFolderData(URI.parse('foo:bar2'), 2)] }); // simulate acknowledgement from main side
|
||||
assert.strictEqual(gotEvent, true);
|
||||
sub.dispose();
|
||||
assert.strictEqual(ws.getWorkspaceFolders()![0], firstAddedFolder); // verify object is still live
|
||||
assert.strictEqual(ws.getWorkspaceFolders()![1], secondAddedFolder); // verify object is still live
|
||||
assert.strictEqual(ws.getWorkspaceFolders()![2], thirdAddedFolder); // verify object is still live
|
||||
|
||||
//
|
||||
// Remove one folder
|
||||
//
|
||||
|
||||
assert.strictEqual(true, ws.updateWorkspaceFolders(extensionDescriptor, 2, 1));
|
||||
assert.strictEqual(2, ws.workspace!.folders.length);
|
||||
assert.strictEqual(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar').toString());
|
||||
assert.strictEqual(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar1').toString());
|
||||
|
||||
gotEvent = false;
|
||||
sub = ws.onDidChangeWorkspace(e => {
|
||||
try {
|
||||
assert.deepStrictEqual(e.added, []);
|
||||
assert.strictEqual(e.removed.length, 1);
|
||||
assert.strictEqual(e.removed[0], thirdAddedFolder);
|
||||
gotEvent = true;
|
||||
} catch (error) {
|
||||
finish(error);
|
||||
}
|
||||
});
|
||||
ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0), aWorkspaceFolderData(URI.parse('foo:bar1'), 1)] }); // simulate acknowledgement from main side
|
||||
assert.strictEqual(gotEvent, true);
|
||||
sub.dispose();
|
||||
assert.strictEqual(ws.getWorkspaceFolders()![0], firstAddedFolder); // verify object is still live
|
||||
assert.strictEqual(ws.getWorkspaceFolders()![1], secondAddedFolder); // verify object is still live
|
||||
|
||||
//
|
||||
// Rename folder
|
||||
//
|
||||
|
||||
assert.strictEqual(true, ws.updateWorkspaceFolders(extensionDescriptor, 0, 2, asUpdateWorkspaceFolderData(URI.parse('foo:bar'), 'renamed 1'), asUpdateWorkspaceFolderData(URI.parse('foo:bar1'), 'renamed 2')));
|
||||
assert.strictEqual(2, ws.workspace!.folders.length);
|
||||
assert.strictEqual(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar').toString());
|
||||
assert.strictEqual(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar1').toString());
|
||||
assert.strictEqual(ws.workspace!.folders[0].name, 'renamed 1');
|
||||
assert.strictEqual(ws.workspace!.folders[1].name, 'renamed 2');
|
||||
assert.strictEqual(ws.getWorkspaceFolders()![0].name, 'renamed 1');
|
||||
assert.strictEqual(ws.getWorkspaceFolders()![1].name, 'renamed 2');
|
||||
|
||||
gotEvent = false;
|
||||
sub = ws.onDidChangeWorkspace(e => {
|
||||
try {
|
||||
assert.deepStrictEqual(e.added, []);
|
||||
assert.strictEqual(e.removed.length, 0);
|
||||
gotEvent = true;
|
||||
} catch (error) {
|
||||
finish(error);
|
||||
}
|
||||
});
|
||||
ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0, 'renamed 1'), aWorkspaceFolderData(URI.parse('foo:bar1'), 1, 'renamed 2')] }); // simulate acknowledgement from main side
|
||||
assert.strictEqual(gotEvent, true);
|
||||
sub.dispose();
|
||||
assert.strictEqual(ws.getWorkspaceFolders()![0], firstAddedFolder); // verify object is still live
|
||||
assert.strictEqual(ws.getWorkspaceFolders()![1], secondAddedFolder); // verify object is still live
|
||||
assert.strictEqual(ws.workspace!.folders[0].name, 'renamed 1');
|
||||
assert.strictEqual(ws.workspace!.folders[1].name, 'renamed 2');
|
||||
assert.strictEqual(ws.getWorkspaceFolders()![0].name, 'renamed 1');
|
||||
assert.strictEqual(ws.getWorkspaceFolders()![1].name, 'renamed 2');
|
||||
|
||||
//
|
||||
// Add and remove folders
|
||||
//
|
||||
|
||||
assert.strictEqual(true, ws.updateWorkspaceFolders(extensionDescriptor, 0, 2, asUpdateWorkspaceFolderData(URI.parse('foo:bar3')), asUpdateWorkspaceFolderData(URI.parse('foo:bar4'))));
|
||||
assert.strictEqual(2, ws.workspace!.folders.length);
|
||||
assert.strictEqual(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar3').toString());
|
||||
assert.strictEqual(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar4').toString());
|
||||
|
||||
const fourthAddedFolder = ws.getWorkspaceFolders()![0];
|
||||
const fifthAddedFolder = ws.getWorkspaceFolders()![1];
|
||||
|
||||
gotEvent = false;
|
||||
sub = ws.onDidChangeWorkspace(e => {
|
||||
try {
|
||||
assert.strictEqual(e.added.length, 2);
|
||||
assert.strictEqual(e.added[0], fourthAddedFolder);
|
||||
assert.strictEqual(e.added[1], fifthAddedFolder);
|
||||
assert.strictEqual(e.removed.length, 2);
|
||||
assert.strictEqual(e.removed[0], firstAddedFolder);
|
||||
assert.strictEqual(e.removed[1], secondAddedFolder);
|
||||
gotEvent = true;
|
||||
} catch (error) {
|
||||
finish(error);
|
||||
}
|
||||
});
|
||||
ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar3'), 0), aWorkspaceFolderData(URI.parse('foo:bar4'), 1)] }); // simulate acknowledgement from main side
|
||||
assert.strictEqual(gotEvent, true);
|
||||
sub.dispose();
|
||||
assert.strictEqual(ws.getWorkspaceFolders()![0], fourthAddedFolder); // verify object is still live
|
||||
assert.strictEqual(ws.getWorkspaceFolders()![1], fifthAddedFolder); // verify object is still live
|
||||
|
||||
//
|
||||
// Swap folders
|
||||
//
|
||||
|
||||
assert.strictEqual(true, ws.updateWorkspaceFolders(extensionDescriptor, 0, 2, asUpdateWorkspaceFolderData(URI.parse('foo:bar4')), asUpdateWorkspaceFolderData(URI.parse('foo:bar3'))));
|
||||
assert.strictEqual(2, ws.workspace!.folders.length);
|
||||
assert.strictEqual(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar4').toString());
|
||||
assert.strictEqual(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar3').toString());
|
||||
|
||||
assert.strictEqual(ws.getWorkspaceFolders()![0], fifthAddedFolder); // verify object is still live
|
||||
assert.strictEqual(ws.getWorkspaceFolders()![1], fourthAddedFolder); // verify object is still live
|
||||
|
||||
gotEvent = false;
|
||||
sub = ws.onDidChangeWorkspace(e => {
|
||||
try {
|
||||
assert.strictEqual(e.added.length, 0);
|
||||
assert.strictEqual(e.removed.length, 0);
|
||||
gotEvent = true;
|
||||
} catch (error) {
|
||||
finish(error);
|
||||
}
|
||||
});
|
||||
ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar4'), 0), aWorkspaceFolderData(URI.parse('foo:bar3'), 1)] }); // simulate acknowledgement from main side
|
||||
assert.strictEqual(gotEvent, true);
|
||||
sub.dispose();
|
||||
assert.strictEqual(ws.getWorkspaceFolders()![0], fifthAddedFolder); // verify object is still live
|
||||
assert.strictEqual(ws.getWorkspaceFolders()![1], fourthAddedFolder); // verify object is still live
|
||||
assert.strictEqual(fifthAddedFolder.index, 0);
|
||||
assert.strictEqual(fourthAddedFolder.index, 1);
|
||||
|
||||
//
|
||||
// Add one folder after the other without waiting for confirmation (not supported currently)
|
||||
//
|
||||
|
||||
assert.strictEqual(true, ws.updateWorkspaceFolders(extensionDescriptor, 2, 0, asUpdateWorkspaceFolderData(URI.parse('foo:bar5'))));
|
||||
|
||||
assert.strictEqual(3, ws.workspace!.folders.length);
|
||||
assert.strictEqual(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar4').toString());
|
||||
assert.strictEqual(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar3').toString());
|
||||
assert.strictEqual(ws.workspace!.folders[2].uri.toString(), URI.parse('foo:bar5').toString());
|
||||
|
||||
const sixthAddedFolder = ws.getWorkspaceFolders()![2];
|
||||
|
||||
gotEvent = false;
|
||||
sub = ws.onDidChangeWorkspace(e => {
|
||||
try {
|
||||
assert.strictEqual(e.added.length, 1);
|
||||
assert.strictEqual(e.added[0], sixthAddedFolder);
|
||||
gotEvent = true;
|
||||
} catch (error) {
|
||||
finish(error);
|
||||
}
|
||||
});
|
||||
ws.$acceptWorkspaceData({
|
||||
id: 'foo', name: 'Test', folders: [
|
||||
aWorkspaceFolderData(URI.parse('foo:bar4'), 0),
|
||||
aWorkspaceFolderData(URI.parse('foo:bar3'), 1),
|
||||
aWorkspaceFolderData(URI.parse('foo:bar5'), 2)
|
||||
]
|
||||
}); // simulate acknowledgement from main side
|
||||
assert.strictEqual(gotEvent, true);
|
||||
sub.dispose();
|
||||
|
||||
assert.strictEqual(ws.getWorkspaceFolders()![0], fifthAddedFolder); // verify object is still live
|
||||
assert.strictEqual(ws.getWorkspaceFolders()![1], fourthAddedFolder); // verify object is still live
|
||||
assert.strictEqual(ws.getWorkspaceFolders()![2], sixthAddedFolder); // verify object is still live
|
||||
|
||||
finish();
|
||||
});
|
||||
|
||||
test('Multiroot change event is immutable', function (done) {
|
||||
let finished = false;
|
||||
const finish = (error?: any) => {
|
||||
if (!finished) {
|
||||
finished = true;
|
||||
done(error);
|
||||
}
|
||||
};
|
||||
|
||||
let ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService());
|
||||
let sub = ws.onDidChangeWorkspace(e => {
|
||||
try {
|
||||
assert.throws(() => {
|
||||
(<any>e).added = [];
|
||||
});
|
||||
// assert.throws(() => {
|
||||
// (<any>e.added)[0] = null;
|
||||
// });
|
||||
} catch (error) {
|
||||
finish(error);
|
||||
}
|
||||
});
|
||||
ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [] });
|
||||
sub.dispose();
|
||||
finish();
|
||||
});
|
||||
|
||||
test('`vscode.workspace.getWorkspaceFolder(file)` don\'t return workspace folder when file open from command line. #36221', function () {
|
||||
if (isWindows) {
|
||||
|
||||
let ws = createExtHostWorkspace(new TestRPCProtocol(), {
|
||||
id: 'foo', name: 'Test', folders: [
|
||||
aWorkspaceFolderData(URI.file('c:/Users/marek/Desktop/vsc_test/'), 0)
|
||||
]
|
||||
}, new NullLogService());
|
||||
|
||||
assert.ok(ws.getWorkspaceFolder(URI.file('c:/Users/marek/Desktop/vsc_test/a.txt')));
|
||||
assert.ok(ws.getWorkspaceFolder(URI.file('C:/Users/marek/Desktop/vsc_test/b.txt')));
|
||||
}
|
||||
});
|
||||
|
||||
function aWorkspaceFolderData(uri: URI, index: number, name: string = ''): IWorkspaceFolderData {
|
||||
return {
|
||||
uri,
|
||||
index,
|
||||
name: name || basename(uri.path)
|
||||
};
|
||||
}
|
||||
|
||||
function asUpdateWorkspaceFolderData(uri: URI, name?: string): { uri: URI, name?: string } {
|
||||
return { uri, name };
|
||||
}
|
||||
|
||||
test('findFiles - string include', () => {
|
||||
const root = '/project/foo';
|
||||
const rpcProtocol = new TestRPCProtocol();
|
||||
|
||||
let mainThreadCalled = false;
|
||||
rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {
|
||||
override $startFileSearch(includePattern: string, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise<URI[] | null> {
|
||||
mainThreadCalled = true;
|
||||
assert.strictEqual(includePattern, 'foo');
|
||||
assert.strictEqual(_includeFolder, null);
|
||||
assert.strictEqual(excludePatternOrDisregardExcludes, null);
|
||||
assert.strictEqual(maxResults, 10);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
});
|
||||
|
||||
const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());
|
||||
return ws.findFiles('foo', undefined, 10, new ExtensionIdentifier('test')).then(() => {
|
||||
assert(mainThreadCalled, 'mainThreadCalled');
|
||||
});
|
||||
});
|
||||
|
||||
function testFindFilesInclude(pattern: RelativePattern) {
|
||||
const root = '/project/foo';
|
||||
const rpcProtocol = new TestRPCProtocol();
|
||||
|
||||
let mainThreadCalled = false;
|
||||
rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {
|
||||
override $startFileSearch(includePattern: string, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise<URI[] | null> {
|
||||
mainThreadCalled = true;
|
||||
assert.strictEqual(includePattern, 'glob/**');
|
||||
assert.deepStrictEqual(_includeFolder ? URI.from(_includeFolder).toJSON() : null, URI.file('/other/folder').toJSON());
|
||||
assert.strictEqual(excludePatternOrDisregardExcludes, null);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
});
|
||||
|
||||
const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());
|
||||
return ws.findFiles(pattern, undefined, 10, new ExtensionIdentifier('test')).then(() => {
|
||||
assert(mainThreadCalled, 'mainThreadCalled');
|
||||
});
|
||||
}
|
||||
|
||||
test('findFiles - RelativePattern include (string)', () => {
|
||||
return testFindFilesInclude(new RelativePattern('/other/folder', 'glob/**'));
|
||||
});
|
||||
|
||||
test('findFiles - RelativePattern include (URI)', () => {
|
||||
return testFindFilesInclude(new RelativePattern(URI.file('/other/folder'), 'glob/**'));
|
||||
});
|
||||
|
||||
test('findFiles - no excludes', () => {
|
||||
const root = '/project/foo';
|
||||
const rpcProtocol = new TestRPCProtocol();
|
||||
|
||||
let mainThreadCalled = false;
|
||||
rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {
|
||||
override $startFileSearch(includePattern: string, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise<URI[] | null> {
|
||||
mainThreadCalled = true;
|
||||
assert.strictEqual(includePattern, 'glob/**');
|
||||
assert.deepStrictEqual(_includeFolder, URI.file('/other/folder').toJSON());
|
||||
assert.strictEqual(excludePatternOrDisregardExcludes, false);
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
});
|
||||
|
||||
const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());
|
||||
return ws.findFiles(new RelativePattern('/other/folder', 'glob/**'), null!, 10, new ExtensionIdentifier('test')).then(() => {
|
||||
assert(mainThreadCalled, 'mainThreadCalled');
|
||||
});
|
||||
});
|
||||
|
||||
test('findFiles - with cancelled token', () => {
|
||||
const root = '/project/foo';
|
||||
const rpcProtocol = new TestRPCProtocol();
|
||||
|
||||
let mainThreadCalled = false;
|
||||
rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {
|
||||
override $startFileSearch(includePattern: string, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise<URI[] | null> {
|
||||
mainThreadCalled = true;
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
});
|
||||
|
||||
const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());
|
||||
|
||||
const token = CancellationToken.Cancelled;
|
||||
return ws.findFiles(new RelativePattern('/other/folder', 'glob/**'), null!, 10, new ExtensionIdentifier('test'), token).then(() => {
|
||||
assert(!mainThreadCalled, '!mainThreadCalled');
|
||||
});
|
||||
});
|
||||
|
||||
test('findFiles - RelativePattern exclude', () => {
|
||||
const root = '/project/foo';
|
||||
const rpcProtocol = new TestRPCProtocol();
|
||||
|
||||
let mainThreadCalled = false;
|
||||
rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {
|
||||
override $startFileSearch(includePattern: string, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise<URI[] | null> {
|
||||
mainThreadCalled = true;
|
||||
assert(excludePatternOrDisregardExcludes, 'glob/**'); // Note that the base portion is ignored, see #52651
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
});
|
||||
|
||||
const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());
|
||||
return ws.findFiles('', new RelativePattern(root, 'glob/**'), 10, new ExtensionIdentifier('test')).then(() => {
|
||||
assert(mainThreadCalled, 'mainThreadCalled');
|
||||
});
|
||||
});
|
||||
|
||||
test('findTextInFiles - no include', async () => {
|
||||
const root = '/project/foo';
|
||||
const rpcProtocol = new TestRPCProtocol();
|
||||
|
||||
let mainThreadCalled = false;
|
||||
rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {
|
||||
override async $startTextSearch(query: IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null> {
|
||||
mainThreadCalled = true;
|
||||
assert.strictEqual(query.pattern, 'foo');
|
||||
assert.strictEqual(folder, null);
|
||||
assert.strictEqual(options.includePattern, undefined);
|
||||
assert.strictEqual(options.excludePattern, undefined);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());
|
||||
await ws.findTextInFiles({ pattern: 'foo' }, {}, () => { }, new ExtensionIdentifier('test'));
|
||||
assert(mainThreadCalled, 'mainThreadCalled');
|
||||
});
|
||||
|
||||
test('findTextInFiles - string include', async () => {
|
||||
const root = '/project/foo';
|
||||
const rpcProtocol = new TestRPCProtocol();
|
||||
|
||||
let mainThreadCalled = false;
|
||||
rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {
|
||||
override async $startTextSearch(query: IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null> {
|
||||
mainThreadCalled = true;
|
||||
assert.strictEqual(query.pattern, 'foo');
|
||||
assert.strictEqual(folder, null);
|
||||
assert.strictEqual(options.includePattern, '**/files');
|
||||
assert.strictEqual(options.excludePattern, undefined);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());
|
||||
await ws.findTextInFiles({ pattern: 'foo' }, { include: '**/files' }, () => { }, new ExtensionIdentifier('test'));
|
||||
assert(mainThreadCalled, 'mainThreadCalled');
|
||||
});
|
||||
|
||||
test('findTextInFiles - RelativePattern include', async () => {
|
||||
const root = '/project/foo';
|
||||
const rpcProtocol = new TestRPCProtocol();
|
||||
|
||||
let mainThreadCalled = false;
|
||||
rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {
|
||||
override async $startTextSearch(query: IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null> {
|
||||
mainThreadCalled = true;
|
||||
assert.strictEqual(query.pattern, 'foo');
|
||||
assert.deepStrictEqual(folder, URI.file('/other/folder').toJSON());
|
||||
assert.strictEqual(options.includePattern, 'glob/**');
|
||||
assert.strictEqual(options.excludePattern, undefined);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());
|
||||
await ws.findTextInFiles({ pattern: 'foo' }, { include: new RelativePattern('/other/folder', 'glob/**') }, () => { }, new ExtensionIdentifier('test'));
|
||||
assert(mainThreadCalled, 'mainThreadCalled');
|
||||
});
|
||||
|
||||
test('findTextInFiles - with cancelled token', async () => {
|
||||
const root = '/project/foo';
|
||||
const rpcProtocol = new TestRPCProtocol();
|
||||
|
||||
let mainThreadCalled = false;
|
||||
rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {
|
||||
override async $startTextSearch(query: IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null> {
|
||||
mainThreadCalled = true;
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());
|
||||
const token = CancellationToken.Cancelled;
|
||||
await ws.findTextInFiles({ pattern: 'foo' }, {}, () => { }, new ExtensionIdentifier('test'), token);
|
||||
assert(!mainThreadCalled, '!mainThreadCalled');
|
||||
});
|
||||
|
||||
test('findTextInFiles - RelativePattern exclude', async () => {
|
||||
const root = '/project/foo';
|
||||
const rpcProtocol = new TestRPCProtocol();
|
||||
|
||||
let mainThreadCalled = false;
|
||||
rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {
|
||||
override async $startTextSearch(query: IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null> {
|
||||
mainThreadCalled = true;
|
||||
assert.strictEqual(query.pattern, 'foo');
|
||||
assert.deepStrictEqual(folder, null);
|
||||
assert.strictEqual(options.includePattern, undefined);
|
||||
assert.strictEqual(options.excludePattern, 'glob/**'); // exclude folder is ignored...
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());
|
||||
await ws.findTextInFiles({ pattern: 'foo' }, { exclude: new RelativePattern('/other/folder', 'glob/**') }, () => { }, new ExtensionIdentifier('test'));
|
||||
assert(mainThreadCalled, 'mainThreadCalled');
|
||||
});
|
||||
});
|
||||
@@ -1,87 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { MainThreadCommands } from 'vs/workbench/api/browser/mainThreadCommands';
|
||||
import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { SingleProxyRPCProtocol } from './testRPCProtocol';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { mock } from 'vs/base/test/common/mock';
|
||||
|
||||
suite('MainThreadCommands', function () {
|
||||
|
||||
test('dispose on unregister', function () {
|
||||
|
||||
const commands = new MainThreadCommands(SingleProxyRPCProtocol(null), undefined!, new class extends mock<IExtensionService>() { });
|
||||
assert.strictEqual(CommandsRegistry.getCommand('foo'), undefined);
|
||||
|
||||
// register
|
||||
commands.$registerCommand('foo');
|
||||
assert.ok(CommandsRegistry.getCommand('foo'));
|
||||
|
||||
// unregister
|
||||
commands.$unregisterCommand('foo');
|
||||
assert.strictEqual(CommandsRegistry.getCommand('foo'), undefined);
|
||||
});
|
||||
|
||||
test('unregister all on dispose', function () {
|
||||
|
||||
const commands = new MainThreadCommands(SingleProxyRPCProtocol(null), undefined!, new class extends mock<IExtensionService>() { });
|
||||
assert.strictEqual(CommandsRegistry.getCommand('foo'), undefined);
|
||||
|
||||
commands.$registerCommand('foo');
|
||||
commands.$registerCommand('bar');
|
||||
|
||||
assert.ok(CommandsRegistry.getCommand('foo'));
|
||||
assert.ok(CommandsRegistry.getCommand('bar'));
|
||||
|
||||
commands.dispose();
|
||||
|
||||
assert.strictEqual(CommandsRegistry.getCommand('foo'), undefined);
|
||||
assert.strictEqual(CommandsRegistry.getCommand('bar'), undefined);
|
||||
});
|
||||
|
||||
test('activate and throw when needed', async function () {
|
||||
|
||||
const activations: string[] = [];
|
||||
const runs: string[] = [];
|
||||
|
||||
const commands = new MainThreadCommands(
|
||||
SingleProxyRPCProtocol(null),
|
||||
new class extends mock<ICommandService>() {
|
||||
override executeCommand<T>(id: string): Promise<T | undefined> {
|
||||
runs.push(id);
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
},
|
||||
new class extends mock<IExtensionService>() {
|
||||
override activateByEvent(id: string) {
|
||||
activations.push(id);
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// case 1: arguments and retry
|
||||
try {
|
||||
activations.length = 0;
|
||||
await commands.$executeCommand('bazz', [1, 2, { n: 3 }], true);
|
||||
assert.ok(false);
|
||||
} catch (e) {
|
||||
assert.deepStrictEqual(activations, ['onCommand:bazz']);
|
||||
assert.strictEqual((<Error>e).message, '$executeCommand:retry');
|
||||
}
|
||||
|
||||
// case 2: no arguments and retry
|
||||
runs.length = 0;
|
||||
await commands.$executeCommand('bazz', [], true);
|
||||
assert.deepStrictEqual(runs, ['bazz']);
|
||||
|
||||
// case 3: arguments and no retry
|
||||
runs.length = 0;
|
||||
await commands.$executeCommand('bazz', [1, 2, true], false);
|
||||
assert.deepStrictEqual(runs, ['bazz']);
|
||||
});
|
||||
});
|
||||
@@ -1,232 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 sinon from 'sinon';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { Extensions, IConfigurationRegistry, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||
import { MainThreadConfiguration } from 'vs/workbench/api/browser/mainThreadConfiguration';
|
||||
import { SingleProxyRPCProtocol } from './testRPCProtocol';
|
||||
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
|
||||
import { WorkspaceService } from 'vs/workbench/services/configuration/browser/configurationService';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
|
||||
suite('MainThreadConfiguration', function () {
|
||||
|
||||
let proxy = {
|
||||
$initializeConfiguration: () => { }
|
||||
};
|
||||
let instantiationService: TestInstantiationService;
|
||||
let target: sinon.SinonSpy;
|
||||
|
||||
suiteSetup(() => {
|
||||
Registry.as<IConfigurationRegistry>(Extensions.Configuration).registerConfiguration({
|
||||
'id': 'extHostConfiguration',
|
||||
'title': 'a',
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'extHostConfiguration.resource': {
|
||||
'description': 'extHostConfiguration.resource',
|
||||
'type': 'boolean',
|
||||
'default': true,
|
||||
'scope': ConfigurationScope.RESOURCE
|
||||
},
|
||||
'extHostConfiguration.window': {
|
||||
'description': 'extHostConfiguration.resource',
|
||||
'type': 'boolean',
|
||||
'default': true,
|
||||
'scope': ConfigurationScope.WINDOW
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
setup(() => {
|
||||
target = sinon.spy();
|
||||
|
||||
instantiationService = new TestInstantiationService();
|
||||
instantiationService.stub(IConfigurationService, WorkspaceService);
|
||||
instantiationService.stub(IConfigurationService, 'onDidUpdateConfiguration', sinon.mock());
|
||||
instantiationService.stub(IConfigurationService, 'onDidChangeConfiguration', sinon.mock());
|
||||
instantiationService.stub(IConfigurationService, 'updateValue', target);
|
||||
instantiationService.stub(IEnvironmentService, {
|
||||
isBuilt: false
|
||||
});
|
||||
});
|
||||
|
||||
test('update resource configuration without configuration target defaults to workspace in multi root workspace when no resource is provided', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.WORKSPACE });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(proxy));
|
||||
|
||||
testObject.$updateConfigurationOption(null, 'extHostConfiguration.resource', 'value', undefined, undefined);
|
||||
|
||||
assert.strictEqual(ConfigurationTarget.WORKSPACE, target.args[0][3]);
|
||||
});
|
||||
|
||||
test('update resource configuration without configuration target defaults to workspace in folder workspace when resource is provider', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.FOLDER });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(proxy));
|
||||
|
||||
testObject.$updateConfigurationOption(null, 'extHostConfiguration.resource', 'value', { resource: URI.file('abc') }, undefined);
|
||||
|
||||
assert.strictEqual(ConfigurationTarget.WORKSPACE, target.args[0][3]);
|
||||
});
|
||||
|
||||
test('update resource configuration without configuration target defaults to workspace in folder workspace when no resource is provider', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.FOLDER });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(proxy));
|
||||
|
||||
testObject.$updateConfigurationOption(null, 'extHostConfiguration.resource', 'value', undefined, undefined);
|
||||
|
||||
assert.strictEqual(ConfigurationTarget.WORKSPACE, target.args[0][3]);
|
||||
});
|
||||
|
||||
test('update window configuration without configuration target defaults to workspace in multi root workspace when no resource is provided', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.WORKSPACE });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(proxy));
|
||||
|
||||
testObject.$updateConfigurationOption(null, 'extHostConfiguration.window', 'value', undefined, undefined);
|
||||
|
||||
assert.strictEqual(ConfigurationTarget.WORKSPACE, target.args[0][3]);
|
||||
});
|
||||
|
||||
test('update window configuration without configuration target defaults to workspace in multi root workspace when resource is provided', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.WORKSPACE });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(proxy));
|
||||
|
||||
testObject.$updateConfigurationOption(null, 'extHostConfiguration.window', 'value', { resource: URI.file('abc') }, undefined);
|
||||
|
||||
assert.strictEqual(ConfigurationTarget.WORKSPACE, target.args[0][3]);
|
||||
});
|
||||
|
||||
test('update window configuration without configuration target defaults to workspace in folder workspace when resource is provider', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.FOLDER });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(proxy));
|
||||
|
||||
testObject.$updateConfigurationOption(null, 'extHostConfiguration.window', 'value', { resource: URI.file('abc') }, undefined);
|
||||
|
||||
assert.strictEqual(ConfigurationTarget.WORKSPACE, target.args[0][3]);
|
||||
});
|
||||
|
||||
test('update window configuration without configuration target defaults to workspace in folder workspace when no resource is provider', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.FOLDER });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(proxy));
|
||||
|
||||
testObject.$updateConfigurationOption(null, 'extHostConfiguration.window', 'value', undefined, undefined);
|
||||
|
||||
assert.strictEqual(ConfigurationTarget.WORKSPACE, target.args[0][3]);
|
||||
});
|
||||
|
||||
test('update resource configuration without configuration target defaults to folder', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.WORKSPACE });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(proxy));
|
||||
|
||||
testObject.$updateConfigurationOption(null, 'extHostConfiguration.resource', 'value', { resource: URI.file('abc') }, undefined);
|
||||
|
||||
assert.strictEqual(ConfigurationTarget.WORKSPACE_FOLDER, target.args[0][3]);
|
||||
});
|
||||
|
||||
test('update configuration with user configuration target', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.FOLDER });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(proxy));
|
||||
|
||||
testObject.$updateConfigurationOption(ConfigurationTarget.USER, 'extHostConfiguration.window', 'value', { resource: URI.file('abc') }, undefined);
|
||||
|
||||
assert.strictEqual(ConfigurationTarget.USER, target.args[0][3]);
|
||||
});
|
||||
|
||||
test('update configuration with workspace configuration target', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.FOLDER });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(proxy));
|
||||
|
||||
testObject.$updateConfigurationOption(ConfigurationTarget.WORKSPACE, 'extHostConfiguration.window', 'value', { resource: URI.file('abc') }, undefined);
|
||||
|
||||
assert.strictEqual(ConfigurationTarget.WORKSPACE, target.args[0][3]);
|
||||
});
|
||||
|
||||
test('update configuration with folder configuration target', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.FOLDER });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(proxy));
|
||||
|
||||
testObject.$updateConfigurationOption(ConfigurationTarget.WORKSPACE_FOLDER, 'extHostConfiguration.window', 'value', { resource: URI.file('abc') }, undefined);
|
||||
|
||||
assert.strictEqual(ConfigurationTarget.WORKSPACE_FOLDER, target.args[0][3]);
|
||||
});
|
||||
|
||||
test('remove resource configuration without configuration target defaults to workspace in multi root workspace when no resource is provided', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.WORKSPACE });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(proxy));
|
||||
|
||||
testObject.$removeConfigurationOption(null, 'extHostConfiguration.resource', undefined, undefined);
|
||||
|
||||
assert.strictEqual(ConfigurationTarget.WORKSPACE, target.args[0][3]);
|
||||
});
|
||||
|
||||
test('remove resource configuration without configuration target defaults to workspace in folder workspace when resource is provider', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.FOLDER });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(proxy));
|
||||
|
||||
testObject.$removeConfigurationOption(null, 'extHostConfiguration.resource', { resource: URI.file('abc') }, undefined);
|
||||
|
||||
assert.strictEqual(ConfigurationTarget.WORKSPACE, target.args[0][3]);
|
||||
});
|
||||
|
||||
test('remove resource configuration without configuration target defaults to workspace in folder workspace when no resource is provider', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.FOLDER });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(proxy));
|
||||
|
||||
testObject.$removeConfigurationOption(null, 'extHostConfiguration.resource', undefined, undefined);
|
||||
|
||||
assert.strictEqual(ConfigurationTarget.WORKSPACE, target.args[0][3]);
|
||||
});
|
||||
|
||||
test('remove window configuration without configuration target defaults to workspace in multi root workspace when no resource is provided', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.WORKSPACE });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(proxy));
|
||||
|
||||
testObject.$removeConfigurationOption(null, 'extHostConfiguration.window', undefined, undefined);
|
||||
|
||||
assert.strictEqual(ConfigurationTarget.WORKSPACE, target.args[0][3]);
|
||||
});
|
||||
|
||||
test('remove window configuration without configuration target defaults to workspace in multi root workspace when resource is provided', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.WORKSPACE });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(proxy));
|
||||
|
||||
testObject.$removeConfigurationOption(null, 'extHostConfiguration.window', { resource: URI.file('abc') }, undefined);
|
||||
|
||||
assert.strictEqual(ConfigurationTarget.WORKSPACE, target.args[0][3]);
|
||||
});
|
||||
|
||||
test('remove window configuration without configuration target defaults to workspace in folder workspace when resource is provider', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.FOLDER });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(proxy));
|
||||
|
||||
testObject.$removeConfigurationOption(null, 'extHostConfiguration.window', { resource: URI.file('abc') }, undefined);
|
||||
|
||||
assert.strictEqual(ConfigurationTarget.WORKSPACE, target.args[0][3]);
|
||||
});
|
||||
|
||||
test('remove window configuration without configuration target defaults to workspace in folder workspace when no resource is provider', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.FOLDER });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(proxy));
|
||||
|
||||
testObject.$removeConfigurationOption(null, 'extHostConfiguration.window', undefined, undefined);
|
||||
|
||||
assert.strictEqual(ConfigurationTarget.WORKSPACE, target.args[0][3]);
|
||||
});
|
||||
|
||||
test('remove configuration without configuration target defaults to folder', function () {
|
||||
instantiationService.stub(IWorkspaceContextService, <IWorkspaceContextService>{ getWorkbenchState: () => WorkbenchState.WORKSPACE });
|
||||
const testObject: MainThreadConfiguration = instantiationService.createInstance(MainThreadConfiguration, SingleProxyRPCProtocol(proxy));
|
||||
|
||||
testObject.$removeConfigurationOption(null, 'extHostConfiguration.resource', { resource: URI.file('abc') }, undefined);
|
||||
|
||||
assert.strictEqual(ConfigurationTarget.WORKSPACE_FOLDER, target.args[0][3]);
|
||||
});
|
||||
});
|
||||
@@ -1,60 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { MarkerService } from 'vs/platform/markers/common/markerService';
|
||||
import { MainThreadDiagnostics } from 'vs/workbench/api/browser/mainThreadDiagnostics';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IExtHostContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { mock } from 'vs/workbench/test/common/workbenchTestServices';
|
||||
import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity';
|
||||
import { ExtensionHostKind } from 'vs/workbench/services/extensions/common/extensions';
|
||||
|
||||
|
||||
suite('MainThreadDiagnostics', function () {
|
||||
|
||||
let markerService: MarkerService;
|
||||
|
||||
setup(function () {
|
||||
markerService = new MarkerService();
|
||||
});
|
||||
|
||||
test('clear markers on dispose', function () {
|
||||
|
||||
let diag = new MainThreadDiagnostics(
|
||||
new class implements IExtHostContext {
|
||||
remoteAuthority = '';
|
||||
extensionHostKind = ExtensionHostKind.LocalProcess;
|
||||
assertRegistered() { }
|
||||
set(v: any): any { return null; }
|
||||
getProxy(): any {
|
||||
return {
|
||||
$acceptMarkersChange() { }
|
||||
};
|
||||
}
|
||||
drain(): any { return null; }
|
||||
},
|
||||
markerService,
|
||||
new class extends mock<IUriIdentityService>() {
|
||||
override asCanonicalUri(uri: URI) { return uri; }
|
||||
}
|
||||
);
|
||||
|
||||
diag.$changeMany('foo', [[URI.file('a'), [{
|
||||
code: '666',
|
||||
startLineNumber: 1,
|
||||
startColumn: 1,
|
||||
endLineNumber: 1,
|
||||
endColumn: 1,
|
||||
message: 'fffff',
|
||||
severity: 1,
|
||||
source: 'me'
|
||||
}]]]);
|
||||
|
||||
assert.strictEqual(markerService.read().length, 1);
|
||||
diag.dispose();
|
||||
assert.strictEqual(markerService.read().length, 0);
|
||||
});
|
||||
});
|
||||
@@ -1,56 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 } from 'vs/base/common/uri';
|
||||
import { MainThreadDocumentContentProviders } from 'vs/workbench/api/browser/mainThreadDocumentContentProviders';
|
||||
import { createTextModel } from 'vs/editor/test/common/editorTestUtils';
|
||||
import { mock } from 'vs/base/test/common/mock';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';
|
||||
import { TestRPCProtocol } from 'vs/workbench/test/browser/api/testRPCProtocol';
|
||||
import { TextEdit } from 'vs/editor/common/modes';
|
||||
|
||||
suite('MainThreadDocumentContentProviders', function () {
|
||||
|
||||
test('events are processed properly', function () {
|
||||
|
||||
let uri = URI.parse('test:uri');
|
||||
let model = createTextModel('1', undefined, undefined, uri);
|
||||
|
||||
let providers = new MainThreadDocumentContentProviders(new TestRPCProtocol(), null!, null!,
|
||||
new class extends mock<IModelService>() {
|
||||
override getModel(_uri: URI) {
|
||||
assert.strictEqual(uri.toString(), _uri.toString());
|
||||
return model;
|
||||
}
|
||||
},
|
||||
new class extends mock<IEditorWorkerService>() {
|
||||
override computeMoreMinimalEdits(_uri: URI, data: TextEdit[] | undefined) {
|
||||
assert.strictEqual(model.getValue(), '1');
|
||||
return Promise.resolve(data);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
let expectedEvents = 1;
|
||||
model.onDidChangeContent(e => {
|
||||
expectedEvents -= 1;
|
||||
try {
|
||||
assert.ok(expectedEvents >= 0);
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
if (model.getValue() === '1\n2\n3') {
|
||||
model.dispose();
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
providers.$onVirtualDocumentChange(uri, '1\n2');
|
||||
providers.$onVirtualDocumentChange(uri, '1\n2\n3');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,173 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { BoundModelReferenceCollection } from 'vs/workbench/api/browser/mainThreadDocuments';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { extUri } from 'vs/base/common/resources';
|
||||
|
||||
suite('BoundModelReferenceCollection', function () {
|
||||
|
||||
let col: BoundModelReferenceCollection;
|
||||
|
||||
setup(function () {
|
||||
col = new BoundModelReferenceCollection(extUri, 15, 75);
|
||||
});
|
||||
|
||||
teardown(function () {
|
||||
col.dispose();
|
||||
});
|
||||
|
||||
test('max age', async function () {
|
||||
|
||||
let didDispose = false;
|
||||
|
||||
col.add(
|
||||
URI.parse('test://farboo'),
|
||||
{
|
||||
object: {},
|
||||
dispose() {
|
||||
didDispose = true;
|
||||
}
|
||||
});
|
||||
|
||||
await timeout(30);
|
||||
assert.strictEqual(didDispose, true);
|
||||
});
|
||||
|
||||
test('max size', function () {
|
||||
|
||||
let disposed: number[] = [];
|
||||
|
||||
col.add(
|
||||
URI.parse('test://farboo'),
|
||||
{
|
||||
object: {},
|
||||
dispose() {
|
||||
disposed.push(0);
|
||||
}
|
||||
}, 6);
|
||||
|
||||
col.add(
|
||||
URI.parse('test://boofar'),
|
||||
{
|
||||
object: {},
|
||||
dispose() {
|
||||
disposed.push(1);
|
||||
}
|
||||
}, 6);
|
||||
|
||||
col.add(
|
||||
URI.parse('test://xxxxxxx'),
|
||||
{
|
||||
object: {},
|
||||
dispose() {
|
||||
disposed.push(2);
|
||||
}
|
||||
}, 70);
|
||||
|
||||
assert.deepStrictEqual(disposed, [0, 1]);
|
||||
});
|
||||
|
||||
test('max count', function () {
|
||||
col.dispose();
|
||||
col = new BoundModelReferenceCollection(extUri, 10000, 10000, 2);
|
||||
|
||||
let disposed: number[] = [];
|
||||
|
||||
col.add(
|
||||
URI.parse('test://xxxxxxx'),
|
||||
{
|
||||
object: {},
|
||||
dispose() {
|
||||
disposed.push(0);
|
||||
}
|
||||
}
|
||||
);
|
||||
col.add(
|
||||
URI.parse('test://xxxxxxx'),
|
||||
{
|
||||
object: {},
|
||||
dispose() {
|
||||
disposed.push(1);
|
||||
}
|
||||
}
|
||||
);
|
||||
col.add(
|
||||
URI.parse('test://xxxxxxx'),
|
||||
{
|
||||
object: {},
|
||||
dispose() {
|
||||
disposed.push(2);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
assert.deepStrictEqual(disposed, [0]);
|
||||
});
|
||||
|
||||
test('dispose uri', function () {
|
||||
|
||||
let disposed: number[] = [];
|
||||
|
||||
col.add(
|
||||
URI.parse('test:///farboo'),
|
||||
{
|
||||
object: {},
|
||||
dispose() {
|
||||
disposed.push(0);
|
||||
}
|
||||
});
|
||||
|
||||
col.add(
|
||||
URI.parse('test:///boofar'),
|
||||
{
|
||||
object: {},
|
||||
dispose() {
|
||||
disposed.push(1);
|
||||
}
|
||||
});
|
||||
|
||||
col.add(
|
||||
URI.parse('test:///boo/far1'),
|
||||
{
|
||||
object: {},
|
||||
dispose() {
|
||||
disposed.push(2);
|
||||
}
|
||||
});
|
||||
|
||||
col.add(
|
||||
URI.parse('test:///boo/far2'),
|
||||
{
|
||||
object: {},
|
||||
dispose() {
|
||||
disposed.push(3);
|
||||
}
|
||||
});
|
||||
|
||||
col.add(
|
||||
URI.parse('test:///boo1/far'),
|
||||
{
|
||||
object: {},
|
||||
dispose() {
|
||||
disposed.push(4);
|
||||
}
|
||||
});
|
||||
|
||||
col.remove(URI.parse('test:///unknown'));
|
||||
assert.strictEqual(disposed.length, 0);
|
||||
|
||||
col.remove(URI.parse('test:///farboo'));
|
||||
assert.deepStrictEqual(disposed, [0]);
|
||||
|
||||
disposed = [];
|
||||
|
||||
col.remove(URI.parse('test:///boo'));
|
||||
assert.deepStrictEqual(disposed, [2, 3]);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,259 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { MainThreadDocumentsAndEditors } from 'vs/workbench/api/browser/mainThreadDocumentsAndEditors';
|
||||
import { SingleProxyRPCProtocol } from './testRPCProtocol';
|
||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||
import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl';
|
||||
import { TestCodeEditorService } from 'vs/editor/test/browser/editorTestServices';
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { ExtHostDocumentsAndEditorsShape, IDocumentsAndEditorsDelta } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { createTestCodeEditor, ITestCodeEditor } from 'vs/editor/test/browser/testCodeEditor';
|
||||
import { mock } from 'vs/base/test/common/mock';
|
||||
import { TestEditorService, TestEditorGroupsService, TestEnvironmentService, TestPathService } from 'vs/workbench/test/browser/workbenchTestServices';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
import { UndoRedoService } from 'vs/platform/undoRedo/common/undoRedoService';
|
||||
import { TestDialogService } from 'vs/platform/dialogs/test/common/testDialogService';
|
||||
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
|
||||
import { TestTextResourcePropertiesService, TestWorkingCopyFileService } from 'vs/workbench/test/common/workbenchTestServices';
|
||||
import { UriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentityService';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite';
|
||||
import { TestLanguageConfigurationService } from 'vs/editor/test/common/modes/testLanguageConfigurationService';
|
||||
import { TextModel } from 'vs/editor/common/model/textModel';
|
||||
import { ModeServiceImpl } from 'vs/editor/common/services/modeServiceImpl';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { INotebookService } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||
|
||||
suite('MainThreadDocumentsAndEditors', () => {
|
||||
|
||||
let disposables: DisposableStore;
|
||||
|
||||
let modelService: ModelServiceImpl;
|
||||
let codeEditorService: TestCodeEditorService;
|
||||
let textFileService: ITextFileService;
|
||||
let deltas: IDocumentsAndEditorsDelta[] = [];
|
||||
|
||||
function myCreateTestCodeEditor(model: ITextModel | undefined): ITestCodeEditor {
|
||||
return createTestCodeEditor({
|
||||
model: model,
|
||||
hasTextFocus: false,
|
||||
serviceCollection: new ServiceCollection(
|
||||
[ICodeEditorService, codeEditorService]
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
setup(() => {
|
||||
disposables = new DisposableStore();
|
||||
|
||||
deltas.length = 0;
|
||||
const configService = new TestConfigurationService();
|
||||
configService.setUserConfiguration('editor', { 'detectIndentation': false });
|
||||
const dialogService = new TestDialogService();
|
||||
const notificationService = new TestNotificationService();
|
||||
const undoRedoService = new UndoRedoService(dialogService, notificationService);
|
||||
modelService = new ModelServiceImpl(
|
||||
configService,
|
||||
new TestTextResourcePropertiesService(configService),
|
||||
new TestThemeService(),
|
||||
new NullLogService(),
|
||||
undoRedoService,
|
||||
disposables.add(new ModeServiceImpl()),
|
||||
new TestLanguageConfigurationService()
|
||||
);
|
||||
codeEditorService = new TestCodeEditorService();
|
||||
textFileService = new class extends mock<ITextFileService>() {
|
||||
override isDirty() { return false; }
|
||||
override files = <any>{
|
||||
onDidSave: Event.None,
|
||||
onDidRevert: Event.None,
|
||||
onDidChangeDirty: Event.None
|
||||
};
|
||||
};
|
||||
const workbenchEditorService = new TestEditorService();
|
||||
const editorGroupService = new TestEditorGroupsService();
|
||||
|
||||
const fileService = new class extends mock<IFileService>() {
|
||||
override onDidRunOperation = Event.None;
|
||||
override onDidChangeFileSystemProviderCapabilities = Event.None;
|
||||
override onDidChangeFileSystemProviderRegistrations = Event.None;
|
||||
};
|
||||
|
||||
new MainThreadDocumentsAndEditors(
|
||||
SingleProxyRPCProtocol(new class extends mock<ExtHostDocumentsAndEditorsShape>() {
|
||||
override $acceptDocumentsAndEditorsDelta(delta: IDocumentsAndEditorsDelta) { deltas.push(delta); }
|
||||
}),
|
||||
modelService,
|
||||
textFileService,
|
||||
workbenchEditorService,
|
||||
codeEditorService,
|
||||
fileService,
|
||||
null!,
|
||||
editorGroupService,
|
||||
null!,
|
||||
new class extends mock<IPaneCompositePartService>() implements IPaneCompositePartService {
|
||||
override onDidPaneCompositeOpen = Event.None;
|
||||
override onDidPaneCompositeClose = Event.None;
|
||||
override getActivePaneComposite() {
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
TestEnvironmentService,
|
||||
new TestWorkingCopyFileService(),
|
||||
new UriIdentityService(fileService),
|
||||
new class extends mock<IClipboardService>() {
|
||||
override readText() {
|
||||
return Promise.resolve('clipboard_contents');
|
||||
}
|
||||
},
|
||||
new TestPathService(),
|
||||
<INotebookService>{ // {{SQL CARBON EDIT}}
|
||||
getSupportedFileExtensions: () => ['.ipynb']
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
disposables.dispose();
|
||||
});
|
||||
|
||||
test('Model#add', () => {
|
||||
deltas.length = 0;
|
||||
|
||||
modelService.createModel('farboo', null);
|
||||
|
||||
assert.strictEqual(deltas.length, 1);
|
||||
const [delta] = deltas;
|
||||
|
||||
assert.strictEqual(delta.addedDocuments!.length, 1);
|
||||
assert.strictEqual(delta.removedDocuments, undefined);
|
||||
assert.strictEqual(delta.addedEditors, undefined);
|
||||
assert.strictEqual(delta.removedEditors, undefined);
|
||||
assert.strictEqual(delta.newActiveEditor, undefined);
|
||||
});
|
||||
|
||||
test('ignore huge model', function () {
|
||||
|
||||
const oldLimit = (<any>TextModel).MODEL_SYNC_LIMIT;
|
||||
try {
|
||||
const largeModelString = 'abc'.repeat(1024);
|
||||
(<any>TextModel).MODEL_SYNC_LIMIT = largeModelString.length / 2;
|
||||
|
||||
const model = modelService.createModel(largeModelString, null);
|
||||
assert.ok(model.isTooLargeForSyncing());
|
||||
|
||||
assert.strictEqual(deltas.length, 1);
|
||||
const [delta] = deltas;
|
||||
assert.strictEqual(delta.newActiveEditor, null);
|
||||
assert.strictEqual(delta.addedDocuments, undefined);
|
||||
assert.strictEqual(delta.removedDocuments, undefined);
|
||||
assert.strictEqual(delta.addedEditors, undefined);
|
||||
assert.strictEqual(delta.removedEditors, undefined);
|
||||
|
||||
} finally {
|
||||
(<any>TextModel).MODEL_SYNC_LIMIT = oldLimit;
|
||||
}
|
||||
});
|
||||
|
||||
test('ignore huge model from editor', function () {
|
||||
|
||||
const oldLimit = (<any>TextModel).MODEL_SYNC_LIMIT;
|
||||
try {
|
||||
const largeModelString = 'abc'.repeat(1024);
|
||||
(<any>TextModel).MODEL_SYNC_LIMIT = largeModelString.length / 2;
|
||||
|
||||
const model = modelService.createModel(largeModelString, null);
|
||||
const editor = myCreateTestCodeEditor(model);
|
||||
|
||||
assert.strictEqual(deltas.length, 1);
|
||||
deltas.length = 0;
|
||||
assert.strictEqual(deltas.length, 0);
|
||||
editor.dispose();
|
||||
|
||||
} finally {
|
||||
(<any>TextModel).MODEL_SYNC_LIMIT = oldLimit;
|
||||
}
|
||||
});
|
||||
|
||||
test('ignore simple widget model', function () {
|
||||
this.timeout(1000 * 60); // increase timeout for this one test
|
||||
|
||||
const model = modelService.createModel('test', null, undefined, true);
|
||||
assert.ok(model.isForSimpleWidget);
|
||||
|
||||
assert.strictEqual(deltas.length, 1);
|
||||
const [delta] = deltas;
|
||||
assert.strictEqual(delta.newActiveEditor, null);
|
||||
assert.strictEqual(delta.addedDocuments, undefined);
|
||||
assert.strictEqual(delta.removedDocuments, undefined);
|
||||
assert.strictEqual(delta.addedEditors, undefined);
|
||||
assert.strictEqual(delta.removedEditors, undefined);
|
||||
});
|
||||
|
||||
test('ignore editor w/o model', () => {
|
||||
const editor = myCreateTestCodeEditor(undefined);
|
||||
assert.strictEqual(deltas.length, 1);
|
||||
const [delta] = deltas;
|
||||
assert.strictEqual(delta.newActiveEditor, null);
|
||||
assert.strictEqual(delta.addedDocuments, undefined);
|
||||
assert.strictEqual(delta.removedDocuments, undefined);
|
||||
assert.strictEqual(delta.addedEditors, undefined);
|
||||
assert.strictEqual(delta.removedEditors, undefined);
|
||||
|
||||
editor.dispose();
|
||||
});
|
||||
|
||||
test('editor with model', () => {
|
||||
deltas.length = 0;
|
||||
|
||||
const model = modelService.createModel('farboo', null);
|
||||
const editor = myCreateTestCodeEditor(model);
|
||||
|
||||
assert.strictEqual(deltas.length, 2);
|
||||
const [first, second] = deltas;
|
||||
assert.strictEqual(first.addedDocuments!.length, 1);
|
||||
assert.strictEqual(first.newActiveEditor, undefined);
|
||||
assert.strictEqual(first.removedDocuments, undefined);
|
||||
assert.strictEqual(first.addedEditors, undefined);
|
||||
assert.strictEqual(first.removedEditors, undefined);
|
||||
|
||||
assert.strictEqual(second.addedEditors!.length, 1);
|
||||
assert.strictEqual(second.addedDocuments, undefined);
|
||||
assert.strictEqual(second.removedDocuments, undefined);
|
||||
assert.strictEqual(second.removedEditors, undefined);
|
||||
assert.strictEqual(second.newActiveEditor, undefined);
|
||||
|
||||
editor.dispose();
|
||||
});
|
||||
|
||||
test('editor with dispos-ed/-ing model', () => {
|
||||
modelService.createModel('foobar', null);
|
||||
const model = modelService.createModel('farboo', null);
|
||||
const editor = myCreateTestCodeEditor(model);
|
||||
|
||||
// ignore things until now
|
||||
deltas.length = 0;
|
||||
|
||||
modelService.destroyModel(model.uri);
|
||||
assert.strictEqual(deltas.length, 1);
|
||||
const [first] = deltas;
|
||||
|
||||
assert.strictEqual(first.newActiveEditor, undefined);
|
||||
assert.strictEqual(first.removedEditors!.length, 1);
|
||||
assert.strictEqual(first.removedDocuments!.length, 1);
|
||||
assert.strictEqual(first.addedDocuments, undefined);
|
||||
assert.strictEqual(first.addedEditors, undefined);
|
||||
|
||||
editor.dispose();
|
||||
});
|
||||
});
|
||||
@@ -1,272 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { MainThreadDocumentsAndEditors } from 'vs/workbench/api/browser/mainThreadDocumentsAndEditors';
|
||||
import { SingleProxyRPCProtocol, TestRPCProtocol } from './testRPCProtocol';
|
||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||
import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl';
|
||||
import { TestCodeEditorService } from 'vs/editor/test/browser/editorTestServices';
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { ExtHostDocumentsAndEditorsShape, ExtHostContext, ExtHostDocumentsShape, IWorkspaceTextEditDto, WorkspaceEditType } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { mock } from 'vs/base/test/common/mock';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { MainThreadTextEditors } from 'vs/workbench/api/browser/mainThreadEditors';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { EditOperation } from 'vs/editor/common/core/editOperation';
|
||||
import { TestFileService, TestEditorService, TestEditorGroupsService, TestEnvironmentService, TestLifecycleService } from 'vs/workbench/test/browser/workbenchTestServices';
|
||||
import { BulkEditService } from 'vs/workbench/contrib/bulkEdit/browser/bulkEditService';
|
||||
import { NullLogService, ILogService } from 'vs/platform/log/common/log';
|
||||
import { ITextModelService, IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService';
|
||||
import { IReference, ImmortalReference, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { LabelService } from 'vs/workbench/services/label/common/labelService';
|
||||
import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService';
|
||||
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
|
||||
import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { IWorkingCopyFileService, IMoveOperation, IDeleteOperation, ICopyOperation, ICreateFileOperation, ICreateOperation } from 'vs/workbench/services/workingCopy/common/workingCopyFileService';
|
||||
import { UndoRedoService } from 'vs/platform/undoRedo/common/undoRedoService';
|
||||
import { TestDialogService } from 'vs/platform/dialogs/test/common/testDialogService';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
|
||||
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { TestTextResourcePropertiesService, TestContextService } from 'vs/workbench/test/common/workbenchTestServices';
|
||||
import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity';
|
||||
import { extUri } from 'vs/base/common/resources';
|
||||
import { ITextSnapshot } from 'vs/editor/common/model';
|
||||
import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite';
|
||||
import { TestLanguageConfigurationService } from 'vs/editor/test/common/modes/testLanguageConfigurationService';
|
||||
import { ModeServiceImpl } from 'vs/editor/common/services/modeServiceImpl';
|
||||
|
||||
suite('MainThreadEditors', () => {
|
||||
|
||||
let disposables: DisposableStore;
|
||||
const resource = URI.parse('foo:bar');
|
||||
|
||||
let modelService: IModelService;
|
||||
let editors: MainThreadTextEditors;
|
||||
|
||||
const movedResources = new Map<URI, URI>();
|
||||
const copiedResources = new Map<URI, URI>();
|
||||
const createdResources = new Set<URI>();
|
||||
const deletedResources = new Set<URI>();
|
||||
|
||||
setup(() => {
|
||||
disposables = new DisposableStore();
|
||||
|
||||
movedResources.clear();
|
||||
copiedResources.clear();
|
||||
createdResources.clear();
|
||||
deletedResources.clear();
|
||||
|
||||
|
||||
const configService = new TestConfigurationService();
|
||||
const dialogService = new TestDialogService();
|
||||
const notificationService = new TestNotificationService();
|
||||
const undoRedoService = new UndoRedoService(dialogService, notificationService);
|
||||
modelService = new ModelServiceImpl(
|
||||
configService,
|
||||
new TestTextResourcePropertiesService(configService),
|
||||
new TestThemeService(),
|
||||
new NullLogService(),
|
||||
undoRedoService,
|
||||
disposables.add(new ModeServiceImpl()),
|
||||
new TestLanguageConfigurationService()
|
||||
);
|
||||
|
||||
|
||||
const services = new ServiceCollection();
|
||||
services.set(IBulkEditService, new SyncDescriptor(BulkEditService));
|
||||
services.set(ILabelService, new SyncDescriptor(LabelService));
|
||||
services.set(ILogService, new NullLogService());
|
||||
services.set(IWorkspaceContextService, new TestContextService());
|
||||
services.set(IEnvironmentService, TestEnvironmentService);
|
||||
services.set(IWorkbenchEnvironmentService, TestEnvironmentService);
|
||||
services.set(IConfigurationService, configService);
|
||||
services.set(IDialogService, dialogService);
|
||||
services.set(INotificationService, notificationService);
|
||||
services.set(IUndoRedoService, undoRedoService);
|
||||
services.set(IModelService, modelService);
|
||||
services.set(ICodeEditorService, new TestCodeEditorService());
|
||||
services.set(IFileService, new TestFileService());
|
||||
services.set(IEditorService, new TestEditorService());
|
||||
services.set(ILifecycleService, new TestLifecycleService());
|
||||
services.set(IEditorGroupsService, new TestEditorGroupsService());
|
||||
services.set(ITextFileService, new class extends mock<ITextFileService>() {
|
||||
override isDirty() { return false; }
|
||||
override files = <any>{
|
||||
onDidSave: Event.None,
|
||||
onDidRevert: Event.None,
|
||||
onDidChangeDirty: Event.None
|
||||
};
|
||||
override create(operations: { resource: URI }[]) {
|
||||
for (const o of operations) {
|
||||
createdResources.add(o.resource);
|
||||
}
|
||||
return Promise.resolve(Object.create(null));
|
||||
}
|
||||
override async getEncodedReadable(resource: URI, value?: string | ITextSnapshot): Promise<any> {
|
||||
return undefined;
|
||||
}
|
||||
});
|
||||
services.set(IWorkingCopyFileService, new class extends mock<IWorkingCopyFileService>() {
|
||||
override onDidRunWorkingCopyFileOperation = Event.None;
|
||||
override createFolder(operations: ICreateOperation[]): any {
|
||||
this.create(operations);
|
||||
}
|
||||
override create(operations: ICreateFileOperation[]) {
|
||||
for (const operation of operations) {
|
||||
createdResources.add(operation.resource);
|
||||
}
|
||||
return Promise.resolve(Object.create(null));
|
||||
}
|
||||
override move(operations: IMoveOperation[]) {
|
||||
const { source, target } = operations[0].file;
|
||||
movedResources.set(source, target);
|
||||
return Promise.resolve(Object.create(null));
|
||||
}
|
||||
override copy(operations: ICopyOperation[]) {
|
||||
const { source, target } = operations[0].file;
|
||||
copiedResources.set(source, target);
|
||||
return Promise.resolve(Object.create(null));
|
||||
}
|
||||
override delete(operations: IDeleteOperation[]) {
|
||||
for (const operation of operations) {
|
||||
deletedResources.add(operation.resource);
|
||||
}
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
});
|
||||
services.set(ITextModelService, new class extends mock<ITextModelService>() {
|
||||
override createModelReference(resource: URI): Promise<IReference<IResolvedTextEditorModel>> {
|
||||
const textEditorModel = new class extends mock<IResolvedTextEditorModel>() {
|
||||
override textEditorModel = modelService.getModel(resource)!;
|
||||
};
|
||||
textEditorModel.isReadonly = () => false;
|
||||
return Promise.resolve(new ImmortalReference(textEditorModel));
|
||||
}
|
||||
});
|
||||
services.set(IEditorWorkerService, new class extends mock<IEditorWorkerService>() {
|
||||
|
||||
});
|
||||
services.set(IPaneCompositePartService, new class extends mock<IPaneCompositePartService>() implements IPaneCompositePartService {
|
||||
override onDidPaneCompositeOpen = Event.None;
|
||||
override onDidPaneCompositeClose = Event.None;
|
||||
override getActivePaneComposite() {
|
||||
return undefined;
|
||||
}
|
||||
});
|
||||
services.set(IUriIdentityService, new class extends mock<IUriIdentityService>() {
|
||||
override get extUri() { return extUri; }
|
||||
});
|
||||
|
||||
const instaService = new InstantiationService(services);
|
||||
|
||||
const rpcProtocol = new TestRPCProtocol();
|
||||
rpcProtocol.set(ExtHostContext.ExtHostDocuments, new class extends mock<ExtHostDocumentsShape>() {
|
||||
override $acceptModelChanged(): void {
|
||||
}
|
||||
});
|
||||
rpcProtocol.set(ExtHostContext.ExtHostDocumentsAndEditors, new class extends mock<ExtHostDocumentsAndEditorsShape>() {
|
||||
override $acceptDocumentsAndEditorsDelta(): void {
|
||||
}
|
||||
});
|
||||
|
||||
const documentAndEditor = instaService.createInstance(MainThreadDocumentsAndEditors, rpcProtocol);
|
||||
|
||||
editors = instaService.createInstance(MainThreadTextEditors, documentAndEditor, SingleProxyRPCProtocol(null));
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
disposables.dispose();
|
||||
});
|
||||
|
||||
test(`applyWorkspaceEdit returns false if model is changed by user`, () => {
|
||||
|
||||
let model = modelService.createModel('something', null, resource);
|
||||
|
||||
let workspaceResourceEdit: IWorkspaceTextEditDto = {
|
||||
_type: WorkspaceEditType.Text,
|
||||
resource: resource,
|
||||
modelVersionId: model.getVersionId(),
|
||||
edit: {
|
||||
text: 'asdfg',
|
||||
range: new Range(1, 1, 1, 1)
|
||||
}
|
||||
};
|
||||
|
||||
// Act as if the user edited the model
|
||||
model.applyEdits([EditOperation.insert(new Position(0, 0), 'something')]);
|
||||
|
||||
return editors.$tryApplyWorkspaceEdit({ edits: [workspaceResourceEdit] }).then((result) => {
|
||||
assert.strictEqual(result, false);
|
||||
});
|
||||
});
|
||||
|
||||
test(`issue #54773: applyWorkspaceEdit checks model version in race situation`, () => {
|
||||
|
||||
let model = modelService.createModel('something', null, resource);
|
||||
|
||||
let workspaceResourceEdit1: IWorkspaceTextEditDto = {
|
||||
_type: WorkspaceEditType.Text,
|
||||
resource: resource,
|
||||
modelVersionId: model.getVersionId(),
|
||||
edit: {
|
||||
text: 'asdfg',
|
||||
range: new Range(1, 1, 1, 1)
|
||||
}
|
||||
};
|
||||
let workspaceResourceEdit2: IWorkspaceTextEditDto = {
|
||||
_type: WorkspaceEditType.Text,
|
||||
resource: resource,
|
||||
modelVersionId: model.getVersionId(),
|
||||
edit: {
|
||||
text: 'asdfg',
|
||||
range: new Range(1, 1, 1, 1)
|
||||
}
|
||||
};
|
||||
|
||||
let p1 = editors.$tryApplyWorkspaceEdit({ edits: [workspaceResourceEdit1] }).then((result) => {
|
||||
// first edit request succeeds
|
||||
assert.strictEqual(result, true);
|
||||
});
|
||||
let p2 = editors.$tryApplyWorkspaceEdit({ edits: [workspaceResourceEdit2] }).then((result) => {
|
||||
// second edit request fails
|
||||
assert.strictEqual(result, false);
|
||||
});
|
||||
return Promise.all([p1, p2]);
|
||||
});
|
||||
|
||||
test(`applyWorkspaceEdit with only resource edit`, () => {
|
||||
return editors.$tryApplyWorkspaceEdit({
|
||||
edits: [
|
||||
{ _type: WorkspaceEditType.File, oldUri: resource, newUri: resource, options: undefined },
|
||||
{ _type: WorkspaceEditType.File, oldUri: undefined, newUri: resource, options: undefined },
|
||||
{ _type: WorkspaceEditType.File, oldUri: resource, newUri: undefined, options: undefined }
|
||||
]
|
||||
}).then((result) => {
|
||||
assert.strictEqual(result, true);
|
||||
assert.strictEqual(movedResources.get(resource), resource);
|
||||
assert.strictEqual(createdResources.has(resource), true);
|
||||
assert.strictEqual(deletedResources.has(resource), true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,93 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { ExtHostTreeViewsShape, IExtHostContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { mock } from 'vs/base/test/common/mock';
|
||||
import { ITreeItem, IViewsRegistry, Extensions, ViewContainerLocation, IViewContainersRegistry, ITreeViewDescriptor, ITreeView, ViewContainer, IViewDescriptorService, TreeItemCollapsibleState } from 'vs/workbench/common/views';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
import { MainThreadTreeViews } from 'vs/workbench/api/browser/mainThreadTreeViews';
|
||||
import { TestViewsService, workbenchInstantiationService } from 'vs/workbench/test/browser/workbenchTestServices';
|
||||
import { TestExtensionService } from 'vs/workbench/test/common/workbenchTestServices';
|
||||
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||
import { ViewDescriptorService } from 'vs/workbench/services/views/browser/viewDescriptorService';
|
||||
import { CustomTreeView } from 'vs/workbench/browser/parts/views/treeView';
|
||||
import { ExtensionHostKind } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
|
||||
suite('MainThreadHostTreeView', function () {
|
||||
const testTreeViewId = 'testTreeView';
|
||||
const customValue = 'customValue';
|
||||
const ViewsRegistry = Registry.as<IViewsRegistry>(Extensions.ViewsRegistry);
|
||||
|
||||
interface CustomTreeItem extends ITreeItem {
|
||||
customProp: string;
|
||||
}
|
||||
|
||||
class MockExtHostTreeViewsShape extends mock<ExtHostTreeViewsShape>() {
|
||||
override async $getChildren(treeViewId: string, treeItemHandle?: string): Promise<ITreeItem[]> {
|
||||
return [<CustomTreeItem>{ handle: 'testItem1', collapsibleState: TreeItemCollapsibleState.Expanded, customProp: customValue }];
|
||||
}
|
||||
|
||||
override async $hasResolve(): Promise<boolean> {
|
||||
return false;
|
||||
}
|
||||
|
||||
override $setVisible(): void { }
|
||||
}
|
||||
|
||||
let container: ViewContainer;
|
||||
let mainThreadTreeViews: MainThreadTreeViews;
|
||||
let extHostTreeViewsShape: MockExtHostTreeViewsShape;
|
||||
let disposables: DisposableStore;
|
||||
|
||||
setup(async () => {
|
||||
disposables = new DisposableStore();
|
||||
const instantiationService: TestInstantiationService = <TestInstantiationService>workbenchInstantiationService(undefined, disposables);
|
||||
const viewDescriptorService = instantiationService.createInstance(ViewDescriptorService);
|
||||
instantiationService.stub(IViewDescriptorService, viewDescriptorService);
|
||||
container = Registry.as<IViewContainersRegistry>(Extensions.ViewContainersRegistry).registerViewContainer({ id: 'testContainer', title: 'test', ctorDescriptor: new SyncDescriptor(<any>{}) }, ViewContainerLocation.Sidebar);
|
||||
const viewDescriptor: ITreeViewDescriptor = {
|
||||
id: testTreeViewId,
|
||||
ctorDescriptor: null!,
|
||||
name: 'Test View 1',
|
||||
treeView: instantiationService.createInstance(CustomTreeView, 'testTree', 'Test Title'),
|
||||
};
|
||||
ViewsRegistry.registerViews([viewDescriptor], container);
|
||||
|
||||
const testExtensionService = new TestExtensionService();
|
||||
extHostTreeViewsShape = new MockExtHostTreeViewsShape();
|
||||
mainThreadTreeViews = new MainThreadTreeViews(
|
||||
new class implements IExtHostContext {
|
||||
remoteAuthority = '';
|
||||
extensionHostKind = ExtensionHostKind.LocalProcess;
|
||||
assertRegistered() { }
|
||||
set(v: any): any { return null; }
|
||||
getProxy(): any {
|
||||
return extHostTreeViewsShape;
|
||||
}
|
||||
drain(): any { return null; }
|
||||
}, new TestViewsService(), new TestNotificationService(), testExtensionService, new NullLogService(), undefined!);
|
||||
mainThreadTreeViews.$registerTreeViewDataProvider(testTreeViewId, { showCollapseAll: false, canSelectMany: false, canDragAndDrop: false });
|
||||
await testExtensionService.whenInstalledExtensionsRegistered();
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
ViewsRegistry.deregisterViews(ViewsRegistry.getViews(container), container);
|
||||
disposables.dispose();
|
||||
});
|
||||
|
||||
test('getChildren keeps custom properties', async () => {
|
||||
const treeView: ITreeView = (<ITreeViewDescriptor>ViewsRegistry.getView(testTreeViewId)).treeView;
|
||||
const children = await treeView.dataProvider?.getChildren({ handle: 'root', collapsibleState: TreeItemCollapsibleState.Expanded });
|
||||
assert(children!.length === 1, 'Exactly one child should be returned');
|
||||
assert((<CustomTreeItem>children![0]).customProp === customValue, 'Tree Items should keep custom properties');
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
@@ -1,158 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ProxyIdentifier, SerializableObjectWithBuffers } from 'vs/workbench/services/extensions/common/proxyIdentifier';
|
||||
import { CharCode } from 'vs/base/common/charCode';
|
||||
import { IExtHostContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { isThenable } from 'vs/base/common/async';
|
||||
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
import { ExtensionHostKind } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { parseJsonAndRestoreBufferRefs, stringifyJsonWithBufferRefs } from 'vs/workbench/services/extensions/common/rpcProtocol';
|
||||
|
||||
export function SingleProxyRPCProtocol(thing: any): IExtHostContext & IExtHostRpcService {
|
||||
return {
|
||||
_serviceBrand: undefined,
|
||||
remoteAuthority: null!,
|
||||
getProxy<T>(): T {
|
||||
return thing;
|
||||
},
|
||||
set<T, R extends T>(identifier: ProxyIdentifier<T>, value: R): R {
|
||||
return value;
|
||||
},
|
||||
assertRegistered: undefined!,
|
||||
drain: undefined!,
|
||||
extensionHostKind: ExtensionHostKind.LocalProcess
|
||||
};
|
||||
}
|
||||
|
||||
export class TestRPCProtocol implements IExtHostContext, IExtHostRpcService {
|
||||
|
||||
public _serviceBrand: undefined;
|
||||
public remoteAuthority = null!;
|
||||
public extensionHostKind = ExtensionHostKind.LocalProcess;
|
||||
|
||||
private _callCountValue: number = 0;
|
||||
private _idle?: Promise<any>;
|
||||
private _completeIdle?: Function;
|
||||
|
||||
private readonly _locals: { [id: string]: any; };
|
||||
private readonly _proxies: { [id: string]: any; };
|
||||
|
||||
constructor() {
|
||||
this._locals = Object.create(null);
|
||||
this._proxies = Object.create(null);
|
||||
}
|
||||
|
||||
drain(): Promise<void> {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
private get _callCount(): number {
|
||||
return this._callCountValue;
|
||||
}
|
||||
|
||||
private set _callCount(value: number) {
|
||||
this._callCountValue = value;
|
||||
if (this._callCountValue === 0) {
|
||||
if (this._completeIdle) {
|
||||
this._completeIdle();
|
||||
}
|
||||
this._idle = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
sync(): Promise<any> {
|
||||
return new Promise<any>((c) => {
|
||||
setTimeout(c, 0);
|
||||
}).then(() => {
|
||||
if (this._callCount === 0) {
|
||||
return undefined;
|
||||
}
|
||||
if (!this._idle) {
|
||||
this._idle = new Promise<any>((c, e) => {
|
||||
this._completeIdle = c;
|
||||
});
|
||||
}
|
||||
return this._idle;
|
||||
});
|
||||
}
|
||||
|
||||
public getProxy<T>(identifier: ProxyIdentifier<T>): T {
|
||||
if (!this._proxies[identifier.sid]) {
|
||||
this._proxies[identifier.sid] = this._createProxy(identifier.sid);
|
||||
}
|
||||
return this._proxies[identifier.sid];
|
||||
}
|
||||
|
||||
private _createProxy<T>(proxyId: string): T {
|
||||
let handler = {
|
||||
get: (target: any, name: PropertyKey) => {
|
||||
if (typeof name === 'string' && !target[name] && name.charCodeAt(0) === CharCode.DollarSign) {
|
||||
target[name] = (...myArgs: any[]) => {
|
||||
return this._remoteCall(proxyId, name, myArgs);
|
||||
};
|
||||
}
|
||||
|
||||
return target[name];
|
||||
}
|
||||
};
|
||||
return new Proxy(Object.create(null), handler);
|
||||
}
|
||||
|
||||
public set<T, R extends T>(identifier: ProxyIdentifier<T>, value: R): R {
|
||||
this._locals[identifier.sid] = value;
|
||||
return value;
|
||||
}
|
||||
|
||||
protected _remoteCall(proxyId: string, path: string, args: any[]): Promise<any> {
|
||||
this._callCount++;
|
||||
|
||||
return new Promise<any>((c) => {
|
||||
setTimeout(c, 0);
|
||||
}).then(() => {
|
||||
const instance = this._locals[proxyId];
|
||||
// pretend the args went over the wire... (invoke .toJSON on objects...)
|
||||
const wireArgs = simulateWireTransfer(args);
|
||||
let p: Promise<any>;
|
||||
try {
|
||||
let result = (<Function>instance[path]).apply(instance, wireArgs);
|
||||
p = isThenable(result) ? result : Promise.resolve(result);
|
||||
} catch (err) {
|
||||
p = Promise.reject(err);
|
||||
}
|
||||
|
||||
return p.then(result => {
|
||||
this._callCount--;
|
||||
// pretend the result went over the wire... (invoke .toJSON on objects...)
|
||||
const wireResult = simulateWireTransfer(result);
|
||||
return wireResult;
|
||||
}, err => {
|
||||
this._callCount--;
|
||||
return Promise.reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public assertRegistered(identifiers: ProxyIdentifier<any>[]): void {
|
||||
throw new Error('Not implemented!');
|
||||
}
|
||||
}
|
||||
|
||||
function simulateWireTransfer<T>(obj: T): T {
|
||||
if (!obj) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map(simulateWireTransfer) as any;
|
||||
}
|
||||
|
||||
if (obj instanceof SerializableObjectWithBuffers) {
|
||||
const { jsonString, referencedBuffers } = stringifyJsonWithBufferRefs(obj);
|
||||
return parseJsonAndRestoreBufferRefs(jsonString, referencedBuffers, null);
|
||||
} else {
|
||||
return JSON.parse(JSON.stringify(obj));
|
||||
}
|
||||
}
|
||||
@@ -7,9 +7,9 @@ import * as assert from 'assert';
|
||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { workbenchInstantiationService, TestEditorService } from 'vs/workbench/test/browser/workbenchTestServices';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { ModeServiceImpl } from 'vs/editor/common/services/modeServiceImpl';
|
||||
import { IModelService } from 'vs/editor/common/services/model';
|
||||
import { ILanguageService } from 'vs/editor/common/languages/language';
|
||||
import { LanguageService } from 'vs/editor/common/services/languageService';
|
||||
import { RangeHighlightDecorations } from 'vs/workbench/browser/codeeditor';
|
||||
import { TextModel } from 'vs/editor/common/model/textModel';
|
||||
import { createTestCodeEditor } from 'vs/editor/test/browser/testCodeEditor';
|
||||
@@ -17,11 +17,11 @@ import { Range, IRange } from 'vs/editor/common/core/range';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||
import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl';
|
||||
import { CoreNavigationCommands } from 'vs/editor/browser/controller/coreCommands';
|
||||
import { ModelService } from 'vs/editor/common/services/modelService';
|
||||
import { CoreNavigationCommands } from 'vs/editor/browser/coreCommands';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { createTextModel } from 'vs/editor/test/common/editorTestUtils';
|
||||
import { createTextModel } from 'vs/editor/test/common/testTextModel';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
@@ -40,11 +40,11 @@ suite('Editor - Range decorations', () => {
|
||||
disposables = new DisposableStore();
|
||||
instantiationService = <TestInstantiationService>workbenchInstantiationService(undefined, disposables);
|
||||
instantiationService.stub(IEditorService, new TestEditorService());
|
||||
instantiationService.stub(IModeService, ModeServiceImpl);
|
||||
instantiationService.stub(ILanguageService, LanguageService);
|
||||
instantiationService.stub(IModelService, stubModelService(instantiationService));
|
||||
text = 'LINE1' + '\n' + 'LINE2' + '\n' + 'LINE3' + '\n' + 'LINE4' + '\r\n' + 'LINE5';
|
||||
model = aModel(URI.file('some_file'));
|
||||
codeEditor = createTestCodeEditor({ model: model });
|
||||
codeEditor = createTestCodeEditor(model);
|
||||
|
||||
instantiationService.stub(IEditorService, 'activeEditor', { get resource() { return codeEditor.getModel()!.uri; } });
|
||||
instantiationService.stub(IEditorService, 'activeTextEditorControl', codeEditor);
|
||||
@@ -143,7 +143,7 @@ suite('Editor - Range decorations', () => {
|
||||
}
|
||||
|
||||
function aModel(resource: URI, content: string = text): TextModel {
|
||||
let model = createTextModel(content, TextModel.DEFAULT_CREATION_OPTIONS, null, resource);
|
||||
let model = createTextModel(content, undefined, undefined, resource);
|
||||
modelsToDispose.push(model);
|
||||
return model;
|
||||
}
|
||||
@@ -164,6 +164,6 @@ suite('Editor - Range decorations', () => {
|
||||
function stubModelService(instantiationService: TestInstantiationService): IModelService {
|
||||
instantiationService.stub(IConfigurationService, new TestConfigurationService());
|
||||
instantiationService.stub(IThemeService, new TestThemeService());
|
||||
return instantiationService.createInstance(ModelServiceImpl);
|
||||
return instantiationService.createInstance(ModelService);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { EditorResourceAccessor, SideBySideEditor, EditorInputWithPreferredResource, EditorInputCapabilities, isEditorIdentifier, IResourceDiffEditorInput, IUntitledTextResourceEditorInput, isResourceEditorInput, isUntitledResourceEditorInput, isResourceDiffEditorInput, isEditorInputWithOptionsAndGroup, EditorInputWithOptions, isEditorInputWithOptions, isEditorInput, EditorInputWithOptionsAndGroup, isResourceSideBySideEditorInput, IResourceSideBySideEditorInput } from 'vs/workbench/common/editor';
|
||||
import { EditorResourceAccessor, SideBySideEditor, EditorInputWithPreferredResource, EditorInputCapabilities, isEditorIdentifier, IResourceDiffEditorInput, IUntitledTextResourceEditorInput, isResourceEditorInput, isUntitledResourceEditorInput, isResourceDiffEditorInput, isEditorInputWithOptionsAndGroup, EditorInputWithOptions, isEditorInputWithOptions, isEditorInput, EditorInputWithOptionsAndGroup, isResourceSideBySideEditorInput, IResourceSideBySideEditorInput, isTextEditorViewState } from 'vs/workbench/common/editor';
|
||||
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
@@ -20,6 +20,8 @@ import { EditorService } from 'vs/workbench/services/editor/browser/editorServic
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { SideBySideEditorInput } from 'vs/workbench/common/editor/sideBySideEditorInput';
|
||||
import { EditorResolution, IResourceEditorInput } from 'vs/platform/editor/common/editor';
|
||||
import { ICodeEditorViewState, IDiffEditorViewState } from 'vs/editor/common/editorCommon';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
|
||||
suite('Workbench editor utils', () => {
|
||||
|
||||
@@ -204,13 +206,13 @@ suite('Workbench editor utils', () => {
|
||||
assert.strictEqual(EditorResourceAccessor.getCanonicalUri(input, { supportSideBySide: SideBySideEditor.SECONDARY, filterByScheme: Schemas.untitled })!.toString(), untitled.resource.toString());
|
||||
assert.strictEqual(EditorResourceAccessor.getCanonicalUri(input, { supportSideBySide: SideBySideEditor.SECONDARY, filterByScheme: [Schemas.file, Schemas.untitled] })!.toString(), untitled.resource.toString());
|
||||
|
||||
assert.strictEqual((EditorResourceAccessor.getCanonicalUri(input, { supportSideBySide: SideBySideEditor.BOTH }) as { primary: URI, secondary: URI }).primary.toString(), file.resource.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getCanonicalUri(input, { supportSideBySide: SideBySideEditor.BOTH, filterByScheme: Schemas.file }) as { primary: URI, secondary: URI }).primary.toString(), file.resource.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getCanonicalUri(input, { supportSideBySide: SideBySideEditor.BOTH, filterByScheme: [Schemas.file, Schemas.untitled] }) as { primary: URI, secondary: URI }).primary.toString(), file.resource.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getCanonicalUri(input, { supportSideBySide: SideBySideEditor.BOTH }) as { primary: URI; secondary: URI }).primary.toString(), file.resource.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getCanonicalUri(input, { supportSideBySide: SideBySideEditor.BOTH, filterByScheme: Schemas.file }) as { primary: URI; secondary: URI }).primary.toString(), file.resource.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getCanonicalUri(input, { supportSideBySide: SideBySideEditor.BOTH, filterByScheme: [Schemas.file, Schemas.untitled] }) as { primary: URI; secondary: URI }).primary.toString(), file.resource.toString());
|
||||
|
||||
assert.strictEqual((EditorResourceAccessor.getCanonicalUri(input, { supportSideBySide: SideBySideEditor.BOTH }) as { primary: URI, secondary: URI }).secondary.toString(), untitled.resource.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getCanonicalUri(input, { supportSideBySide: SideBySideEditor.BOTH, filterByScheme: Schemas.untitled }) as { primary: URI, secondary: URI }).secondary.toString(), untitled.resource.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getCanonicalUri(input, { supportSideBySide: SideBySideEditor.BOTH, filterByScheme: [Schemas.file, Schemas.untitled] }) as { primary: URI, secondary: URI }).secondary.toString(), untitled.resource.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getCanonicalUri(input, { supportSideBySide: SideBySideEditor.BOTH }) as { primary: URI; secondary: URI }).secondary.toString(), untitled.resource.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getCanonicalUri(input, { supportSideBySide: SideBySideEditor.BOTH, filterByScheme: Schemas.untitled }) as { primary: URI; secondary: URI }).secondary.toString(), untitled.resource.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getCanonicalUri(input, { supportSideBySide: SideBySideEditor.BOTH, filterByScheme: [Schemas.file, Schemas.untitled] }) as { primary: URI; secondary: URI }).secondary.toString(), untitled.resource.toString());
|
||||
|
||||
assert.ok(!EditorResourceAccessor.getOriginalUri(input));
|
||||
assert.ok(!EditorResourceAccessor.getOriginalUri(input, { filterByScheme: Schemas.file }));
|
||||
@@ -223,13 +225,13 @@ suite('Workbench editor utils', () => {
|
||||
assert.strictEqual(EditorResourceAccessor.getOriginalUri(input, { supportSideBySide: SideBySideEditor.SECONDARY, filterByScheme: Schemas.untitled })!.toString(), untitled.resource.toString());
|
||||
assert.strictEqual(EditorResourceAccessor.getOriginalUri(input, { supportSideBySide: SideBySideEditor.SECONDARY, filterByScheme: [Schemas.file, Schemas.untitled] })!.toString(), untitled.resource.toString());
|
||||
|
||||
assert.strictEqual((EditorResourceAccessor.getOriginalUri(input, { supportSideBySide: SideBySideEditor.BOTH }) as { primary: URI, secondary: URI }).primary.toString(), file.resource.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getOriginalUri(input, { supportSideBySide: SideBySideEditor.BOTH, filterByScheme: Schemas.file }) as { primary: URI, secondary: URI }).primary.toString(), file.resource.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getOriginalUri(input, { supportSideBySide: SideBySideEditor.BOTH, filterByScheme: [Schemas.file, Schemas.untitled] }) as { primary: URI, secondary: URI }).primary.toString(), file.resource.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getOriginalUri(input, { supportSideBySide: SideBySideEditor.BOTH }) as { primary: URI; secondary: URI }).primary.toString(), file.resource.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getOriginalUri(input, { supportSideBySide: SideBySideEditor.BOTH, filterByScheme: Schemas.file }) as { primary: URI; secondary: URI }).primary.toString(), file.resource.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getOriginalUri(input, { supportSideBySide: SideBySideEditor.BOTH, filterByScheme: [Schemas.file, Schemas.untitled] }) as { primary: URI; secondary: URI }).primary.toString(), file.resource.toString());
|
||||
|
||||
assert.strictEqual((EditorResourceAccessor.getOriginalUri(input, { supportSideBySide: SideBySideEditor.BOTH }) as { primary: URI, secondary: URI }).secondary.toString(), untitled.resource.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getOriginalUri(input, { supportSideBySide: SideBySideEditor.BOTH, filterByScheme: Schemas.untitled }) as { primary: URI, secondary: URI }).secondary.toString(), untitled.resource.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getOriginalUri(input, { supportSideBySide: SideBySideEditor.BOTH, filterByScheme: [Schemas.file, Schemas.untitled] }) as { primary: URI, secondary: URI }).secondary.toString(), untitled.resource.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getOriginalUri(input, { supportSideBySide: SideBySideEditor.BOTH }) as { primary: URI; secondary: URI }).secondary.toString(), untitled.resource.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getOriginalUri(input, { supportSideBySide: SideBySideEditor.BOTH, filterByScheme: Schemas.untitled }) as { primary: URI; secondary: URI }).secondary.toString(), untitled.resource.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getOriginalUri(input, { supportSideBySide: SideBySideEditor.BOTH, filterByScheme: [Schemas.file, Schemas.untitled] }) as { primary: URI; secondary: URI }).secondary.toString(), untitled.resource.toString());
|
||||
}
|
||||
|
||||
const resource = URI.file('/some/path.txt');
|
||||
@@ -308,13 +310,13 @@ suite('Workbench editor utils', () => {
|
||||
assert.strictEqual(EditorResourceAccessor.getCanonicalUri(untypedInput, { supportSideBySide: SideBySideEditor.SECONDARY, filterByScheme: Schemas.untitled })!.toString(), untitled.resource?.toString());
|
||||
assert.strictEqual(EditorResourceAccessor.getCanonicalUri(untypedInput, { supportSideBySide: SideBySideEditor.SECONDARY, filterByScheme: [Schemas.file, Schemas.untitled] })!.toString(), untitled.resource?.toString());
|
||||
|
||||
assert.strictEqual((EditorResourceAccessor.getCanonicalUri(untypedInput, { supportSideBySide: SideBySideEditor.BOTH }) as { primary: URI, secondary: URI }).primary.toString(), file.resource.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getCanonicalUri(untypedInput, { supportSideBySide: SideBySideEditor.BOTH, filterByScheme: Schemas.file }) as { primary: URI, secondary: URI }).primary.toString(), file.resource.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getCanonicalUri(untypedInput, { supportSideBySide: SideBySideEditor.BOTH, filterByScheme: [Schemas.file, Schemas.untitled] }) as { primary: URI, secondary: URI }).primary.toString(), file.resource.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getCanonicalUri(untypedInput, { supportSideBySide: SideBySideEditor.BOTH }) as { primary: URI; secondary: URI }).primary.toString(), file.resource.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getCanonicalUri(untypedInput, { supportSideBySide: SideBySideEditor.BOTH, filterByScheme: Schemas.file }) as { primary: URI; secondary: URI }).primary.toString(), file.resource.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getCanonicalUri(untypedInput, { supportSideBySide: SideBySideEditor.BOTH, filterByScheme: [Schemas.file, Schemas.untitled] }) as { primary: URI; secondary: URI }).primary.toString(), file.resource.toString());
|
||||
|
||||
assert.strictEqual((EditorResourceAccessor.getCanonicalUri(untypedInput, { supportSideBySide: SideBySideEditor.BOTH }) as { primary: URI, secondary: URI }).secondary.toString(), untitled.resource?.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getCanonicalUri(untypedInput, { supportSideBySide: SideBySideEditor.BOTH, filterByScheme: Schemas.untitled }) as { primary: URI, secondary: URI }).secondary.toString(), untitled.resource?.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getCanonicalUri(untypedInput, { supportSideBySide: SideBySideEditor.BOTH, filterByScheme: [Schemas.file, Schemas.untitled] }) as { primary: URI, secondary: URI }).secondary.toString(), untitled.resource?.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getCanonicalUri(untypedInput, { supportSideBySide: SideBySideEditor.BOTH }) as { primary: URI; secondary: URI }).secondary.toString(), untitled.resource?.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getCanonicalUri(untypedInput, { supportSideBySide: SideBySideEditor.BOTH, filterByScheme: Schemas.untitled }) as { primary: URI; secondary: URI }).secondary.toString(), untitled.resource?.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getCanonicalUri(untypedInput, { supportSideBySide: SideBySideEditor.BOTH, filterByScheme: [Schemas.file, Schemas.untitled] }) as { primary: URI; secondary: URI }).secondary.toString(), untitled.resource?.toString());
|
||||
|
||||
assert.ok(!EditorResourceAccessor.getOriginalUri(untypedInput));
|
||||
assert.ok(!EditorResourceAccessor.getOriginalUri(untypedInput, { filterByScheme: Schemas.file }));
|
||||
@@ -327,13 +329,13 @@ suite('Workbench editor utils', () => {
|
||||
assert.strictEqual(EditorResourceAccessor.getOriginalUri(untypedInput, { supportSideBySide: SideBySideEditor.SECONDARY, filterByScheme: Schemas.untitled })!.toString(), untitled.resource?.toString());
|
||||
assert.strictEqual(EditorResourceAccessor.getOriginalUri(untypedInput, { supportSideBySide: SideBySideEditor.SECONDARY, filterByScheme: [Schemas.file, Schemas.untitled] })!.toString(), untitled.resource?.toString());
|
||||
|
||||
assert.strictEqual((EditorResourceAccessor.getOriginalUri(untypedInput, { supportSideBySide: SideBySideEditor.BOTH }) as { primary: URI, secondary: URI }).primary.toString(), file.resource.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getOriginalUri(untypedInput, { supportSideBySide: SideBySideEditor.BOTH, filterByScheme: Schemas.file }) as { primary: URI, secondary: URI }).primary.toString(), file.resource.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getOriginalUri(untypedInput, { supportSideBySide: SideBySideEditor.BOTH, filterByScheme: [Schemas.file, Schemas.untitled] }) as { primary: URI, secondary: URI }).primary.toString(), file.resource.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getOriginalUri(untypedInput, { supportSideBySide: SideBySideEditor.BOTH }) as { primary: URI; secondary: URI }).primary.toString(), file.resource.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getOriginalUri(untypedInput, { supportSideBySide: SideBySideEditor.BOTH, filterByScheme: Schemas.file }) as { primary: URI; secondary: URI }).primary.toString(), file.resource.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getOriginalUri(untypedInput, { supportSideBySide: SideBySideEditor.BOTH, filterByScheme: [Schemas.file, Schemas.untitled] }) as { primary: URI; secondary: URI }).primary.toString(), file.resource.toString());
|
||||
|
||||
assert.strictEqual((EditorResourceAccessor.getOriginalUri(untypedInput, { supportSideBySide: SideBySideEditor.BOTH }) as { primary: URI, secondary: URI }).secondary.toString(), untitled.resource?.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getOriginalUri(untypedInput, { supportSideBySide: SideBySideEditor.BOTH, filterByScheme: Schemas.untitled }) as { primary: URI, secondary: URI }).secondary.toString(), untitled.resource?.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getOriginalUri(untypedInput, { supportSideBySide: SideBySideEditor.BOTH, filterByScheme: [Schemas.file, Schemas.untitled] }) as { primary: URI, secondary: URI }).secondary.toString(), untitled.resource?.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getOriginalUri(untypedInput, { supportSideBySide: SideBySideEditor.BOTH }) as { primary: URI; secondary: URI }).secondary.toString(), untitled.resource?.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getOriginalUri(untypedInput, { supportSideBySide: SideBySideEditor.BOTH, filterByScheme: Schemas.untitled }) as { primary: URI; secondary: URI }).secondary.toString(), untitled.resource?.toString());
|
||||
assert.strictEqual((EditorResourceAccessor.getOriginalUri(untypedInput, { supportSideBySide: SideBySideEditor.BOTH, filterByScheme: [Schemas.file, Schemas.untitled] }) as { primary: URI; secondary: URI }).secondary.toString(), untitled.resource?.toString());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -364,6 +366,30 @@ suite('Workbench editor utils', () => {
|
||||
assert.strictEqual(isEditorInputWithOptionsAndGroup(editorInputWithOptionsAndGroup), true);
|
||||
});
|
||||
|
||||
test('isTextEditorViewState', () => {
|
||||
assert.strictEqual(isTextEditorViewState(undefined), false);
|
||||
assert.strictEqual(isTextEditorViewState({}), false);
|
||||
|
||||
const codeEditorViewState: ICodeEditorViewState = {
|
||||
contributionsState: {},
|
||||
cursorState: [],
|
||||
viewState: {
|
||||
scrollLeft: 0,
|
||||
firstPosition: new Position(1, 1),
|
||||
firstPositionDeltaTop: 1
|
||||
}
|
||||
};
|
||||
|
||||
assert.strictEqual(isTextEditorViewState(codeEditorViewState), true);
|
||||
|
||||
const diffEditorViewState: IDiffEditorViewState = {
|
||||
original: codeEditorViewState,
|
||||
modified: codeEditorViewState
|
||||
};
|
||||
|
||||
assert.strictEqual(isTextEditorViewState(diffEditorViewState), true);
|
||||
});
|
||||
|
||||
test('whenEditorClosed (single editor)', async function () {
|
||||
return testWhenEditorClosed(false, false, toResource.call(this, '/path/index.txt'));
|
||||
});
|
||||
|
||||
@@ -34,7 +34,7 @@ suite('TextDiffEditorModel', () => {
|
||||
provideTextContent: async function (resource: URI): Promise<ITextModel | null> {
|
||||
if (resource.scheme === 'test') {
|
||||
let modelContent = 'Hello Test';
|
||||
let languageSelection = accessor.modeService.create('json');
|
||||
let languageSelection = accessor.languageService.createById('json');
|
||||
|
||||
return accessor.modelService.createModel(modelContent, languageSelection, resource);
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { EditorGroupModel, ISerializedEditorGroupModel } from 'vs/workbench/common/editor/editorGroupModel';
|
||||
import { EditorExtensions, IEditorFactoryRegistry, IFileEditorInput, IEditorSerializer, CloseDirection, EditorsOrder, IResourceDiffEditorInput, IResourceSideBySideEditorInput, SideBySideEditor, EditorCloseContext, IEditorCloseEvent, IEditorOpenEvent, IEditorMoveEvent } from 'vs/workbench/common/editor';
|
||||
import { EditorGroupModel, IGroupEditorChangeEvent, IGroupEditorCloseEvent, IGroupEditorMoveEvent, IGroupEditorOpenEvent, ISerializedEditorGroupModel, isGroupEditorChangeEvent, isGroupEditorCloseEvent, isGroupEditorMoveEvent, isGroupEditorOpenEvent } from 'vs/workbench/common/editor/editorGroupModel';
|
||||
import { EditorExtensions, IEditorFactoryRegistry, IFileEditorInput, IEditorSerializer, CloseDirection, EditorsOrder, IResourceDiffEditorInput, IResourceSideBySideEditorInput, SideBySideEditor, EditorCloseContext, GroupModelChangeKind } from 'vs/workbench/common/editor';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { TestLifecycleService, workbenchInstantiationService } from 'vs/workbench/test/browser/workbenchTestServices';
|
||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||
@@ -79,20 +79,24 @@ suite('EditorGroupModel', () => {
|
||||
}
|
||||
|
||||
interface GroupEvents {
|
||||
locked: number[],
|
||||
opened: IEditorOpenEvent[];
|
||||
activated: EditorInput[];
|
||||
closed: IEditorCloseEvent[];
|
||||
pinned: EditorInput[];
|
||||
unpinned: EditorInput[];
|
||||
sticky: EditorInput[];
|
||||
unsticky: EditorInput[];
|
||||
moved: IEditorMoveEvent[];
|
||||
disposed: EditorInput[];
|
||||
locked: number[];
|
||||
active: number[];
|
||||
index: number[];
|
||||
opened: IGroupEditorOpenEvent[];
|
||||
activated: IGroupEditorChangeEvent[];
|
||||
closed: IGroupEditorCloseEvent[];
|
||||
pinned: IGroupEditorChangeEvent[];
|
||||
unpinned: IGroupEditorChangeEvent[];
|
||||
sticky: IGroupEditorChangeEvent[];
|
||||
unsticky: IGroupEditorChangeEvent[];
|
||||
moved: IGroupEditorMoveEvent[];
|
||||
disposed: IGroupEditorChangeEvent[];
|
||||
}
|
||||
|
||||
function groupListener(group: EditorGroupModel): GroupEvents {
|
||||
const groupEvents: GroupEvents = {
|
||||
active: [],
|
||||
index: [],
|
||||
locked: [],
|
||||
opened: [],
|
||||
closed: [],
|
||||
@@ -105,14 +109,58 @@ suite('EditorGroupModel', () => {
|
||||
disposed: []
|
||||
};
|
||||
|
||||
group.onDidChangeLocked(() => groupEvents.locked.push(group.id));
|
||||
group.onDidOpenEditor(e => groupEvents.opened.push(e));
|
||||
group.onDidCloseEditor(e => groupEvents.closed.push(e));
|
||||
group.onDidActivateEditor(e => groupEvents.activated.push(e));
|
||||
group.onDidChangeEditorPinned(e => group.isPinned(e) ? groupEvents.pinned.push(e) : groupEvents.unpinned.push(e));
|
||||
group.onDidChangeEditorSticky(e => group.isSticky(e) ? groupEvents.sticky.push(e) : groupEvents.unsticky.push(e));
|
||||
group.onDidMoveEditor(e => groupEvents.moved.push(e));
|
||||
group.onWillDisposeEditor(e => groupEvents.disposed.push(e));
|
||||
group.onDidModelChange(e => {
|
||||
if (e.kind === GroupModelChangeKind.GROUP_LOCKED) {
|
||||
groupEvents.locked.push(group.id);
|
||||
return;
|
||||
} else if (e.kind === GroupModelChangeKind.GROUP_ACTIVE) {
|
||||
groupEvents.active.push(group.id);
|
||||
return;
|
||||
} else if (e.kind === GroupModelChangeKind.GROUP_INDEX) {
|
||||
groupEvents.index.push(group.id);
|
||||
return;
|
||||
}
|
||||
if (!e.editor) {
|
||||
return;
|
||||
}
|
||||
switch (e.kind) {
|
||||
case GroupModelChangeKind.EDITOR_OPEN:
|
||||
if (isGroupEditorOpenEvent(e)) {
|
||||
groupEvents.opened.push(e);
|
||||
}
|
||||
break;
|
||||
case GroupModelChangeKind.EDITOR_CLOSE:
|
||||
if (isGroupEditorCloseEvent(e)) {
|
||||
groupEvents.closed.push(e);
|
||||
}
|
||||
break;
|
||||
case GroupModelChangeKind.EDITOR_ACTIVE:
|
||||
if (isGroupEditorChangeEvent(e)) {
|
||||
groupEvents.activated.push(e);
|
||||
}
|
||||
break;
|
||||
case GroupModelChangeKind.EDITOR_PIN:
|
||||
if (isGroupEditorChangeEvent(e)) {
|
||||
group.isPinned(e.editor) ? groupEvents.pinned.push(e) : groupEvents.unpinned.push(e);
|
||||
}
|
||||
break;
|
||||
case GroupModelChangeKind.EDITOR_STICKY:
|
||||
if (isGroupEditorChangeEvent(e)) {
|
||||
group.isSticky(e.editor) ? groupEvents.sticky.push(e) : groupEvents.unsticky.push(e);
|
||||
}
|
||||
break;
|
||||
case GroupModelChangeKind.EDITOR_MOVE:
|
||||
if (isGroupEditorMoveEvent(e)) {
|
||||
groupEvents.moved.push(e);
|
||||
}
|
||||
break;
|
||||
case GroupModelChangeKind.EDITOR_WILL_DISPOSE:
|
||||
if (isGroupEditorChangeEvent(e)) {
|
||||
groupEvents.disposed.push(e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
return groupEvents;
|
||||
}
|
||||
@@ -174,8 +222,8 @@ suite('EditorGroupModel', () => {
|
||||
setPreferredEncoding(encoding: string) { }
|
||||
setForceOpenAsBinary(): void { }
|
||||
setPreferredContents(contents: string): void { }
|
||||
setMode(mode: string) { }
|
||||
setPreferredMode(mode: string) { }
|
||||
setLanguageId(languageId: string) { }
|
||||
setPreferredLanguageId(languageId: string) { }
|
||||
isResolved(): boolean { return false; }
|
||||
|
||||
override matches(other: TestFileEditorInput): boolean {
|
||||
@@ -278,7 +326,11 @@ suite('EditorGroupModel', () => {
|
||||
assert.strictEqual(clone.isLocked, false); // locking does not clone over
|
||||
|
||||
let didEditorLabelChange = false;
|
||||
const toDispose = clone.onDidChangeEditorLabel(() => didEditorLabelChange = true);
|
||||
const toDispose = clone.onDidModelChange((e) => {
|
||||
if (e.kind === GroupModelChangeKind.EDITOR_LABEL) {
|
||||
didEditorLabelChange = true;
|
||||
}
|
||||
});
|
||||
input1.setLabel();
|
||||
assert.ok(didEditorLabelChange);
|
||||
|
||||
@@ -694,7 +746,6 @@ suite('EditorGroupModel', () => {
|
||||
|
||||
test('group serialization (locked group)', function () {
|
||||
const group = createEditorGroupModel();
|
||||
|
||||
const events = groupListener(group);
|
||||
|
||||
assert.strictEqual(events.locked.length, 0);
|
||||
@@ -726,6 +777,28 @@ suite('EditorGroupModel', () => {
|
||||
assert.strictEqual(deserialized.isLocked, false);
|
||||
});
|
||||
|
||||
test('index', function () {
|
||||
const group = createEditorGroupModel();
|
||||
const events = groupListener(group);
|
||||
|
||||
assert.strictEqual(events.index.length, 0);
|
||||
|
||||
group.setIndex(4);
|
||||
|
||||
assert.strictEqual(events.index.length, 1);
|
||||
});
|
||||
|
||||
test('active', function () {
|
||||
const group = createEditorGroupModel();
|
||||
const events = groupListener(group);
|
||||
|
||||
assert.strictEqual(events.active.length, 0);
|
||||
|
||||
group.setActive(undefined);
|
||||
|
||||
assert.strictEqual(events.active.length, 1);
|
||||
});
|
||||
|
||||
test('One Editor', function () {
|
||||
const group = createEditorGroupModel();
|
||||
const events = groupListener(group);
|
||||
@@ -745,21 +818,25 @@ suite('EditorGroupModel', () => {
|
||||
assert.strictEqual(group.isActive(input1), true);
|
||||
assert.strictEqual(group.isPinned(input1), true);
|
||||
assert.strictEqual(group.isPinned(0), true);
|
||||
assert.strictEqual(group.isFirst(input1), true);
|
||||
assert.strictEqual(group.isLast(input1), true);
|
||||
|
||||
assert.strictEqual(events.opened[0].editor, input1);
|
||||
assert.strictEqual(events.opened[0].index, 0);
|
||||
assert.strictEqual(events.opened[0].groupId, group.id);
|
||||
assert.strictEqual(events.activated[0], input1);
|
||||
assert.strictEqual(events.opened[0].editorIndex, 0);
|
||||
assert.strictEqual(events.activated[0].editor, input1);
|
||||
assert.strictEqual(events.activated[0].editorIndex, 0);
|
||||
|
||||
let index = group.indexOf(input1);
|
||||
let event = group.closeEditor(input1, EditorCloseContext.UNPIN);
|
||||
assert.strictEqual(event?.editor, input1);
|
||||
assert.strictEqual(event?.index, index);
|
||||
assert.strictEqual(event?.editorIndex, index);
|
||||
assert.strictEqual(group.count, 0);
|
||||
assert.strictEqual(group.getEditors(EditorsOrder.MOST_RECENTLY_ACTIVE).length, 0);
|
||||
assert.strictEqual(group.activeEditor, null);
|
||||
assert.strictEqual(group.isFirst(input1), false);
|
||||
assert.strictEqual(group.isLast(input1), false);
|
||||
assert.strictEqual(events.closed[0].editor, input1);
|
||||
assert.strictEqual(events.closed[0].index, 0);
|
||||
assert.strictEqual(events.closed[0].editorIndex, 0);
|
||||
assert.strictEqual(events.closed[0].context === EditorCloseContext.UNPIN, true);
|
||||
|
||||
// Active && Preview
|
||||
@@ -774,16 +851,16 @@ suite('EditorGroupModel', () => {
|
||||
assert.strictEqual(group.isPinned(0), false);
|
||||
|
||||
assert.strictEqual(events.opened[1].editor, input2);
|
||||
assert.strictEqual(events.opened[1].index, 0);
|
||||
assert.strictEqual(events.opened[1].groupId, group.id);
|
||||
assert.strictEqual(events.activated[1], input2);
|
||||
assert.strictEqual(events.opened[1].editorIndex, 0);
|
||||
assert.strictEqual(events.activated[1].editor, input2);
|
||||
assert.strictEqual(events.activated[1].editorIndex, 0);
|
||||
|
||||
group.closeEditor(input2);
|
||||
assert.strictEqual(group.count, 0);
|
||||
assert.strictEqual(group.getEditors(EditorsOrder.MOST_RECENTLY_ACTIVE).length, 0);
|
||||
assert.strictEqual(group.activeEditor, null);
|
||||
assert.strictEqual(events.closed[1].editor, input2);
|
||||
assert.strictEqual(events.closed[1].index, 0);
|
||||
assert.strictEqual(events.closed[1].editorIndex, 0);
|
||||
assert.strictEqual(events.closed[1].context === EditorCloseContext.REPLACE, false);
|
||||
|
||||
event = group.closeEditor(input2);
|
||||
@@ -805,7 +882,7 @@ suite('EditorGroupModel', () => {
|
||||
assert.strictEqual(group.isPinned(0), true);
|
||||
|
||||
assert.strictEqual(events.opened[2].editor, input3);
|
||||
assert.strictEqual(events.activated[2], input3);
|
||||
assert.strictEqual(events.activated[2].editor, input3);
|
||||
|
||||
group.closeEditor(input3);
|
||||
assert.strictEqual(group.count, 0);
|
||||
@@ -814,7 +891,7 @@ suite('EditorGroupModel', () => {
|
||||
assert.strictEqual(events.closed[2].editor, input3);
|
||||
|
||||
assert.strictEqual(events.opened[2].editor, input3);
|
||||
assert.strictEqual(events.activated[2], input3);
|
||||
assert.strictEqual(events.activated[2].editor, input3);
|
||||
|
||||
group.closeEditor(input3);
|
||||
assert.strictEqual(group.count, 0);
|
||||
@@ -834,7 +911,7 @@ suite('EditorGroupModel', () => {
|
||||
assert.strictEqual(group.isPinned(0), false);
|
||||
|
||||
assert.strictEqual(events.opened[3].editor, input4);
|
||||
assert.strictEqual(events.activated[3], input4);
|
||||
assert.strictEqual(events.activated[3].editor, input4);
|
||||
|
||||
group.closeEditor(input4);
|
||||
assert.strictEqual(group.count, 0);
|
||||
@@ -873,14 +950,23 @@ suite('EditorGroupModel', () => {
|
||||
assert.strictEqual(group.isPinned(input2), true);
|
||||
assert.strictEqual(group.isActive(input3), true);
|
||||
assert.strictEqual(group.isPinned(input3), true);
|
||||
assert.strictEqual(group.isFirst(input1), true);
|
||||
assert.strictEqual(group.isFirst(input2), false);
|
||||
assert.strictEqual(group.isFirst(input3), false);
|
||||
assert.strictEqual(group.isLast(input1), false);
|
||||
assert.strictEqual(group.isLast(input2), false);
|
||||
assert.strictEqual(group.isLast(input3), true);
|
||||
|
||||
assert.strictEqual(events.opened[0].editor, input1);
|
||||
assert.strictEqual(events.opened[1].editor, input2);
|
||||
assert.strictEqual(events.opened[2].editor, input3);
|
||||
|
||||
assert.strictEqual(events.activated[0], input1);
|
||||
assert.strictEqual(events.activated[1], input2);
|
||||
assert.strictEqual(events.activated[2], input3);
|
||||
assert.strictEqual(events.activated[0].editor, input1);
|
||||
assert.strictEqual(events.activated[0].editorIndex, 0);
|
||||
assert.strictEqual(events.activated[1].editor, input2);
|
||||
assert.strictEqual(events.activated[1].editorIndex, 1);
|
||||
assert.strictEqual(events.activated[2].editor, input3);
|
||||
assert.strictEqual(events.activated[2].editorIndex, 2);
|
||||
|
||||
const mru = group.getEditors(EditorsOrder.MOST_RECENTLY_ACTIVE);
|
||||
assert.strictEqual(mru[0], input3);
|
||||
@@ -891,25 +977,33 @@ suite('EditorGroupModel', () => {
|
||||
// and verify that events carry the original input
|
||||
const sameInput1 = input('1');
|
||||
group.openEditor(sameInput1, { pinned: true, active: true });
|
||||
assert.strictEqual(events.activated[3], input1);
|
||||
assert.strictEqual(events.activated[3].editor, input1);
|
||||
assert.strictEqual(events.activated[3].editorIndex, 0);
|
||||
|
||||
group.unpin(sameInput1);
|
||||
assert.strictEqual(events.unpinned[0], input1);
|
||||
assert.strictEqual(events.unpinned[0].editor, input1);
|
||||
assert.strictEqual(events.unpinned[0].editorIndex, 0);
|
||||
|
||||
group.pin(sameInput1);
|
||||
assert.strictEqual(events.pinned[0], input1);
|
||||
assert.strictEqual(events.pinned[0].editor, input1);
|
||||
assert.strictEqual(events.pinned[0].editorIndex, 0);
|
||||
|
||||
group.stick(sameInput1);
|
||||
assert.strictEqual(events.sticky[0], input1);
|
||||
assert.strictEqual(events.sticky[0].editor, input1);
|
||||
assert.strictEqual(events.sticky[0].editorIndex, 0);
|
||||
|
||||
group.unstick(sameInput1);
|
||||
assert.strictEqual(events.unsticky[0], input1);
|
||||
assert.strictEqual(events.unsticky[0].editor, input1);
|
||||
assert.strictEqual(events.unsticky[0].editorIndex, 0);
|
||||
|
||||
group.moveEditor(sameInput1, 1);
|
||||
assert.strictEqual(events.moved[0].editor, input1);
|
||||
assert.strictEqual(events.moved[0].oldEditorIndex, 0);
|
||||
assert.strictEqual(events.moved[0].editorIndex, 1);
|
||||
|
||||
group.closeEditor(sameInput1);
|
||||
assert.strictEqual(events.closed[0].editor, input1);
|
||||
assert.strictEqual(events.closed[0].editorIndex, 1);
|
||||
|
||||
closeAllEditors(group);
|
||||
|
||||
@@ -1058,7 +1152,7 @@ suite('EditorGroupModel', () => {
|
||||
assert.strictEqual(events.activated.length, 3);
|
||||
|
||||
group.setActive(input1);
|
||||
assert.strictEqual(events.activated[3], input1);
|
||||
assert.strictEqual(events.activated[3].editor, input1);
|
||||
assert.strictEqual(group.activeEditor, input1);
|
||||
assert.strictEqual(group.isActive(input1), true);
|
||||
assert.strictEqual(group.isActive(input2), false);
|
||||
@@ -1090,7 +1184,7 @@ suite('EditorGroupModel', () => {
|
||||
assert.strictEqual(group.activeEditor, input3);
|
||||
assert.strictEqual(group.isPinned(input3), true);
|
||||
assert.strictEqual(group.isActive(input3), true);
|
||||
assert.strictEqual(events.pinned[0], input3);
|
||||
assert.strictEqual(events.pinned[0].editor, input3);
|
||||
assert.strictEqual(group.count, 3);
|
||||
|
||||
group.unpin(input1);
|
||||
@@ -1098,7 +1192,7 @@ suite('EditorGroupModel', () => {
|
||||
assert.strictEqual(group.activeEditor, input3);
|
||||
assert.strictEqual(group.isPinned(input1), false);
|
||||
assert.strictEqual(group.isActive(input1), false);
|
||||
assert.strictEqual(events.unpinned[0], input1);
|
||||
assert.strictEqual(events.unpinned[0].editor, input1);
|
||||
assert.strictEqual(group.count, 3);
|
||||
|
||||
group.unpin(input2);
|
||||
@@ -1141,7 +1235,7 @@ suite('EditorGroupModel', () => {
|
||||
|
||||
group.closeEditor(input5);
|
||||
assert.strictEqual(group.activeEditor, input4);
|
||||
assert.strictEqual(events.activated[5], input4);
|
||||
assert.strictEqual(events.activated[5].editor, input4);
|
||||
assert.strictEqual(group.count, 4);
|
||||
|
||||
group.setActive(input1);
|
||||
@@ -1200,7 +1294,7 @@ suite('EditorGroupModel', () => {
|
||||
|
||||
group.closeEditor(input5);
|
||||
assert.strictEqual(group.activeEditor, input4);
|
||||
assert.strictEqual(events.activated[5], input4);
|
||||
assert.strictEqual(events.activated[5].editor, input4);
|
||||
assert.strictEqual(group.count, 4);
|
||||
|
||||
group.setActive(input1);
|
||||
@@ -1242,10 +1336,8 @@ suite('EditorGroupModel', () => {
|
||||
group.moveEditor(input1, 1);
|
||||
|
||||
assert.strictEqual(events.moved[0].editor, input1);
|
||||
assert.strictEqual(events.moved[0].groupId, group.id);
|
||||
assert.strictEqual(events.moved[0].target, group.id);
|
||||
assert.strictEqual(events.moved[0].index, 0);
|
||||
assert.strictEqual(events.moved[0].newIndex, 1);
|
||||
assert.strictEqual(events.moved[0].oldEditorIndex, 0);
|
||||
assert.strictEqual(events.moved[0].editorIndex, 1);
|
||||
assert.strictEqual(group.getEditors(EditorsOrder.SEQUENTIAL)[0], input2);
|
||||
assert.strictEqual(group.getEditors(EditorsOrder.SEQUENTIAL)[1], input1);
|
||||
|
||||
@@ -1257,10 +1349,8 @@ suite('EditorGroupModel', () => {
|
||||
group.moveEditor(input4, 0);
|
||||
|
||||
assert.strictEqual(events.moved[1].editor, input4);
|
||||
assert.strictEqual(events.moved[1].groupId, group.id);
|
||||
assert.strictEqual(events.moved[1].target, group.id);
|
||||
assert.strictEqual(events.moved[1].index, 3);
|
||||
assert.strictEqual(events.moved[1].newIndex, 0);
|
||||
assert.strictEqual(events.moved[1].oldEditorIndex, 3);
|
||||
assert.strictEqual(events.moved[1].editorIndex, 0);
|
||||
assert.strictEqual(events.moved[1].editor, input4);
|
||||
assert.strictEqual(group.getEditors(EditorsOrder.SEQUENTIAL)[0], input4);
|
||||
assert.strictEqual(group.getEditors(EditorsOrder.SEQUENTIAL)[1], input2);
|
||||
@@ -1789,14 +1879,17 @@ suite('EditorGroupModel', () => {
|
||||
input1.dispose();
|
||||
|
||||
assert.strictEqual(group1Listener.disposed.length, 1);
|
||||
assert.strictEqual(group1Listener.disposed[0].editorIndex, 0);
|
||||
assert.strictEqual(group2Listener.disposed.length, 1);
|
||||
assert.ok(group1Listener.disposed[0].matches(input1));
|
||||
assert.ok(group2Listener.disposed[0].matches(input1));
|
||||
assert.strictEqual(group2Listener.disposed[0].editorIndex, 0);
|
||||
assert.ok(group1Listener.disposed[0].editor.matches(input1));
|
||||
assert.ok(group2Listener.disposed[0].editor.matches(input1));
|
||||
|
||||
input3.dispose();
|
||||
assert.strictEqual(group1Listener.disposed.length, 2);
|
||||
assert.strictEqual(group1Listener.disposed[1].editorIndex, 2);
|
||||
assert.strictEqual(group2Listener.disposed.length, 1);
|
||||
assert.ok(group1Listener.disposed[1].matches(input3));
|
||||
assert.ok(group1Listener.disposed[1].editor.matches(input3));
|
||||
});
|
||||
|
||||
test('Preview tab does not have a stable position (https://github.com/microsoft/vscode/issues/8245)', function () {
|
||||
@@ -1825,23 +1918,31 @@ suite('EditorGroupModel', () => {
|
||||
group2.openEditor(input2, { pinned: true, active: true });
|
||||
|
||||
let dirty1Counter = 0;
|
||||
group1.onDidChangeEditorDirty(() => {
|
||||
dirty1Counter++;
|
||||
group1.onDidModelChange((e) => {
|
||||
if (e.kind === GroupModelChangeKind.EDITOR_DIRTY) {
|
||||
dirty1Counter++;
|
||||
}
|
||||
});
|
||||
|
||||
let dirty2Counter = 0;
|
||||
group2.onDidChangeEditorDirty(() => {
|
||||
dirty2Counter++;
|
||||
group2.onDidModelChange((e) => {
|
||||
if (e.kind === GroupModelChangeKind.EDITOR_DIRTY) {
|
||||
dirty2Counter++;
|
||||
}
|
||||
});
|
||||
|
||||
let label1ChangeCounter = 0;
|
||||
group1.onDidChangeEditorLabel(() => {
|
||||
label1ChangeCounter++;
|
||||
group1.onDidModelChange((e) => {
|
||||
if (e.kind === GroupModelChangeKind.EDITOR_LABEL) {
|
||||
label1ChangeCounter++;
|
||||
}
|
||||
});
|
||||
|
||||
let label2ChangeCounter = 0;
|
||||
group2.onDidChangeEditorLabel(() => {
|
||||
label2ChangeCounter++;
|
||||
group2.onDidModelChange((e) => {
|
||||
if (e.kind === GroupModelChangeKind.EDITOR_LABEL) {
|
||||
label2ChangeCounter++;
|
||||
}
|
||||
});
|
||||
|
||||
(<TestEditorInput>input1).setDirty();
|
||||
@@ -2131,6 +2232,40 @@ suite('EditorGroupModel', () => {
|
||||
assert.strictEqual(group.indexOf(input4), 2);
|
||||
});
|
||||
|
||||
test('Sticky/Unsticky Editors sends correct editor index', function () {
|
||||
const group = createEditorGroupModel();
|
||||
|
||||
const input1 = input();
|
||||
const input2 = input();
|
||||
const input3 = input();
|
||||
|
||||
group.openEditor(input1, { pinned: true, active: true });
|
||||
group.openEditor(input2, { pinned: true, active: true });
|
||||
group.openEditor(input3, { pinned: false, active: true });
|
||||
|
||||
assert.strictEqual(group.stickyCount, 0);
|
||||
|
||||
const events = groupListener(group);
|
||||
|
||||
group.stick(input3);
|
||||
|
||||
assert.strictEqual(events.sticky[0].editorIndex, 0);
|
||||
assert.strictEqual(group.isSticky(input3), true);
|
||||
assert.strictEqual(group.stickyCount, 1);
|
||||
|
||||
group.stick(input2);
|
||||
|
||||
assert.strictEqual(events.sticky[1].editorIndex, 1);
|
||||
assert.strictEqual(group.isSticky(input2), true);
|
||||
assert.strictEqual(group.stickyCount, 2);
|
||||
|
||||
group.unstick(input3);
|
||||
assert.strictEqual(events.unsticky[0].editorIndex, 1);
|
||||
assert.strictEqual(group.isSticky(input3), false);
|
||||
assert.strictEqual(group.isSticky(input2), true);
|
||||
assert.strictEqual(group.stickyCount, 1);
|
||||
});
|
||||
|
||||
test('onDidMoveEditor Event', () => {
|
||||
const group1 = createEditorGroupModel();
|
||||
const group2 = createEditorGroupModel();
|
||||
@@ -2151,13 +2286,13 @@ suite('EditorGroupModel', () => {
|
||||
|
||||
group1.moveEditor(input1group1, 1);
|
||||
assert.strictEqual(group1Events.moved[0].editor, input1group1);
|
||||
assert.strictEqual(group1Events.moved[0].index, 0);
|
||||
assert.strictEqual(group1Events.moved[0].newIndex, 1);
|
||||
assert.strictEqual(group1Events.moved[0].oldEditorIndex, 0);
|
||||
assert.strictEqual(group1Events.moved[0].editorIndex, 1);
|
||||
|
||||
group2.moveEditor(input1group2, 1);
|
||||
assert.strictEqual(group2Events.moved[0].editor, input1group2);
|
||||
assert.strictEqual(group2Events.moved[0].index, 0);
|
||||
assert.strictEqual(group2Events.moved[0].newIndex, 1);
|
||||
assert.strictEqual(group2Events.moved[0].oldEditorIndex, 0);
|
||||
assert.strictEqual(group2Events.moved[0].editorIndex, 1);
|
||||
});
|
||||
|
||||
test('onDidOpeneditor Event', () => {
|
||||
@@ -2180,14 +2315,14 @@ suite('EditorGroupModel', () => {
|
||||
|
||||
assert.strictEqual(group1Events.opened.length, 2);
|
||||
assert.strictEqual(group1Events.opened[0].editor, input1group1);
|
||||
assert.strictEqual(group1Events.opened[0].index, 0);
|
||||
assert.strictEqual(group1Events.opened[0].editorIndex, 0);
|
||||
assert.strictEqual(group1Events.opened[1].editor, input2group1);
|
||||
assert.strictEqual(group1Events.opened[1].index, 1);
|
||||
assert.strictEqual(group1Events.opened[1].editorIndex, 1);
|
||||
|
||||
assert.strictEqual(group2Events.opened.length, 2);
|
||||
assert.strictEqual(group2Events.opened[0].editor, input1group2);
|
||||
assert.strictEqual(group2Events.opened[0].index, 0);
|
||||
assert.strictEqual(group2Events.opened[0].editorIndex, 0);
|
||||
assert.strictEqual(group2Events.opened[1].editor, input2group2);
|
||||
assert.strictEqual(group2Events.opened[1].index, 1);
|
||||
assert.strictEqual(group2Events.opened[1].editorIndex, 1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,39 +6,42 @@
|
||||
import * as assert from 'assert';
|
||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||
import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { ModeServiceImpl } from 'vs/editor/common/services/modeServiceImpl';
|
||||
import { IModelService } from 'vs/editor/common/services/model';
|
||||
import { ILanguageService } from 'vs/editor/common/languages/language';
|
||||
import { LanguageService } from 'vs/editor/common/services/languageService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||
import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl';
|
||||
import { ModelService } from 'vs/editor/common/services/modelService';
|
||||
import { ITextBufferFactory } from 'vs/editor/common/model';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { createTextBufferFactory } from 'vs/editor/common/model/textModel';
|
||||
import { ITextResourcePropertiesService } from 'vs/editor/common/services/textResourceConfigurationService';
|
||||
import { ITextResourcePropertiesService } from 'vs/editor/common/services/textResourceConfiguration';
|
||||
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
|
||||
import { UndoRedoService } from 'vs/platform/undoRedo/common/undoRedoService';
|
||||
import { TestDialogService } from 'vs/platform/dialogs/test/common/testDialogService';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { TestTextResourcePropertiesService } from 'vs/workbench/test/common/workbenchTestServices';
|
||||
import { TestStorageService, TestTextResourcePropertiesService } from 'vs/workbench/test/common/workbenchTestServices';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService';
|
||||
import { EditorModel } from 'vs/workbench/common/editor/editorModel';
|
||||
import { Mimes } from 'vs/base/common/mime';
|
||||
import { LanguageDetectionService } from 'vs/workbench/services/languageDetection/browser/languageDetectionWorkerServiceImpl';
|
||||
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
|
||||
import { TestAccessibilityService, TestEnvironmentService } from 'vs/workbench/test/browser/workbenchTestServices';
|
||||
import { TestEditorService, TestEnvironmentService } from 'vs/workbench/test/browser/workbenchTestServices';
|
||||
import { TestLanguageConfigurationService } from 'vs/editor/test/common/modes/testLanguageConfigurationService';
|
||||
import { ILanguageConfigurationService } from 'vs/editor/common/modes/languageConfigurationRegistry';
|
||||
import { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry';
|
||||
import { TestAccessibilityService } from 'vs/platform/accessibility/test/common/testAccessibilityService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
|
||||
suite('EditorModel', () => {
|
||||
|
||||
class MyEditorModel extends EditorModel { }
|
||||
class MyTextEditorModel extends BaseTextEditorModel {
|
||||
override createTextEditorModel(value: ITextBufferFactory, resource?: URI, preferredMode?: string) {
|
||||
return super.createTextEditorModel(value, resource, preferredMode);
|
||||
override createTextEditorModel(value: ITextBufferFactory, resource?: URI, preferredLanguageId?: string) {
|
||||
return super.createTextEditorModel(value, resource, preferredLanguageId);
|
||||
}
|
||||
|
||||
override isReadonly(): boolean {
|
||||
@@ -56,18 +59,20 @@ suite('EditorModel', () => {
|
||||
instantiationService.stub(IDialogService, dialogService);
|
||||
instantiationService.stub(INotificationService, notificationService);
|
||||
instantiationService.stub(IUndoRedoService, undoRedoService);
|
||||
instantiationService.stub(IEditorService, new TestEditorService());
|
||||
instantiationService.stub(IThemeService, new TestThemeService());
|
||||
instantiationService.stub(ILanguageConfigurationService, new TestLanguageConfigurationService());
|
||||
instantiationService.stub(IStorageService, new TestStorageService());
|
||||
|
||||
return instantiationService.createInstance(ModelServiceImpl);
|
||||
return instantiationService.createInstance(ModelService);
|
||||
}
|
||||
|
||||
let instantiationService: TestInstantiationService;
|
||||
let modeService: IModeService;
|
||||
let languageService: ILanguageService;
|
||||
|
||||
setup(() => {
|
||||
instantiationService = new TestInstantiationService();
|
||||
modeService = instantiationService.stub(IModeService, ModeServiceImpl);
|
||||
languageService = instantiationService.stub(ILanguageService, LanguageService);
|
||||
});
|
||||
|
||||
test('basics', async () => {
|
||||
@@ -91,7 +96,7 @@ suite('EditorModel', () => {
|
||||
test('BaseTextEditorModel', async () => {
|
||||
let modelService = stubModelService(instantiationService);
|
||||
|
||||
const model = new MyTextEditorModel(modelService, modeService, instantiationService.createInstance(LanguageDetectionService), instantiationService.createInstance(TestAccessibilityService));
|
||||
const model = new MyTextEditorModel(modelService, languageService, instantiationService.createInstance(LanguageDetectionService), instantiationService.createInstance(TestAccessibilityService));
|
||||
await model.resolve();
|
||||
|
||||
model.createTextEditorModel(createTextBufferFactory('foo'), null!, Mimes.text);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { EditorPane, EditorMemento } from 'vs/workbench/browser/parts/editor/editorPane';
|
||||
import { WorkspaceTrustRequiredEditor } from 'vs/workbench/browser/parts/editor/editorPlaceholder';
|
||||
import { WorkspaceTrustRequiredPlaceholderEditor } from 'vs/workbench/browser/parts/editor/editorPlaceholder';
|
||||
import { IEditorSerializer, IEditorFactoryRegistry, EditorExtensions, EditorInputCapabilities, IEditorDescriptor, IEditorPane } from 'vs/workbench/common/editor';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
@@ -286,7 +286,7 @@ suite('EditorPane', () => {
|
||||
const configurationService = new TestTextResourceConfigurationService();
|
||||
const editorGroupService = new TestEditorGroupsService([testGroup0]);
|
||||
|
||||
interface TestViewState { line: number; }
|
||||
interface TestViewState { line: number }
|
||||
|
||||
const rawMemento = Object.create(null);
|
||||
const memento = new EditorMemento<TestViewState>('id', 'key', rawMemento, 3, editorGroupService, configurationService);
|
||||
@@ -419,7 +419,7 @@ suite('EditorPane', () => {
|
||||
}));
|
||||
const editorGroupService = new TestEditorGroupsService([testGroup0]);
|
||||
|
||||
interface TestViewState { line: number; }
|
||||
interface TestViewState { line: number }
|
||||
|
||||
const rawMemento = Object.create(null);
|
||||
const memento = new EditorMemento<TestViewState>('id', 'key', rawMemento, 3, editorGroupService, configurationService);
|
||||
@@ -505,10 +505,10 @@ suite('EditorPane', () => {
|
||||
const testInput = new TrustRequiredTestInput();
|
||||
|
||||
await group.openEditor(testInput);
|
||||
assert.strictEqual(group.activeEditorPane?.getId(), WorkspaceTrustRequiredEditor.ID);
|
||||
assert.strictEqual(group.activeEditorPane?.getId(), WorkspaceTrustRequiredPlaceholderEditor.ID);
|
||||
|
||||
const getEditorPaneIdAsync = () => new Promise(resolve => {
|
||||
disposables.add(editorService.onDidActiveEditorChange(event => {
|
||||
disposables.add(editorService.onDidActiveEditorChange(() => {
|
||||
resolve(group.activeEditorPane?.getId());
|
||||
}));
|
||||
});
|
||||
@@ -518,7 +518,7 @@ suite('EditorPane', () => {
|
||||
assert.strictEqual(await getEditorPaneIdAsync(), 'trustRequiredTestEditor');
|
||||
|
||||
workspaceTrustService.setWorkspaceTrust(false);
|
||||
assert.strictEqual(await getEditorPaneIdAsync(), WorkspaceTrustRequiredEditor.ID);
|
||||
assert.strictEqual(await getEditorPaneIdAsync(), WorkspaceTrustRequiredPlaceholderEditor.ID);
|
||||
|
||||
dispose(disposables);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { toResource } from 'vs/base/test/common/utils';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { workbenchInstantiationService, TestServiceAccessor, registerTestFileEditor, createEditorPart, TestTextFileEditor } from 'vs/workbench/test/browser/workbenchTestServices';
|
||||
import { IResolvedTextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { EditorService } from 'vs/workbench/services/editor/browser/editorService';
|
||||
import { EditorPaneSelectionChangeReason, EditorPaneSelectionCompareResult, IEditorPaneSelectionChangeEvent, isEditorPaneWithSelection } from 'vs/workbench/common/editor';
|
||||
import { DeferredPromise } from 'vs/base/common/async';
|
||||
import { TextEditorPaneSelection } from 'vs/workbench/browser/parts/editor/textEditor';
|
||||
import { Selection } from 'vs/editor/common/core/selection';
|
||||
import { IEditorOptions } from 'vs/platform/editor/common/editor';
|
||||
|
||||
suite('TextEditorPane', () => {
|
||||
|
||||
const disposables = new DisposableStore();
|
||||
|
||||
setup(() => {
|
||||
disposables.add(registerTestFileEditor());
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
disposables.clear();
|
||||
});
|
||||
|
||||
async function createServices(): Promise<TestServiceAccessor> {
|
||||
const instantiationService = workbenchInstantiationService(undefined, disposables);
|
||||
|
||||
const part = await createEditorPart(instantiationService, disposables);
|
||||
instantiationService.stub(IEditorGroupsService, part);
|
||||
|
||||
const editorService = instantiationService.createInstance(EditorService);
|
||||
instantiationService.stub(IEditorService, editorService);
|
||||
|
||||
return instantiationService.createInstance(TestServiceAccessor);
|
||||
}
|
||||
|
||||
test('editor pane selection', async function () {
|
||||
const accessor = await createServices();
|
||||
|
||||
const resource = toResource.call(this, '/path/index.txt');
|
||||
let pane = (await accessor.editorService.openEditor({ resource }) as TestTextFileEditor);
|
||||
|
||||
assert.ok(pane && isEditorPaneWithSelection(pane));
|
||||
|
||||
const onDidFireSelectionEventOfEditType = new DeferredPromise<IEditorPaneSelectionChangeEvent>();
|
||||
pane.onDidChangeSelection(e => {
|
||||
if (e.reason === EditorPaneSelectionChangeReason.EDIT) {
|
||||
onDidFireSelectionEventOfEditType.complete(e);
|
||||
}
|
||||
});
|
||||
|
||||
// Changing model reports selection change
|
||||
// of EDIT kind
|
||||
|
||||
const model = await accessor.textFileService.files.resolve(resource) as IResolvedTextFileEditorModel;
|
||||
model.textEditorModel.setValue('Hello World');
|
||||
|
||||
const event = await onDidFireSelectionEventOfEditType.p;
|
||||
assert.strictEqual(event.reason, EditorPaneSelectionChangeReason.EDIT);
|
||||
|
||||
// getSelection() works and can be restored
|
||||
//
|
||||
// Note: this is a bit bogus because in tests our code editors have
|
||||
// no view and no cursor can be set as such. So the selection
|
||||
// will always report for the first line and column.
|
||||
|
||||
pane.setSelection(new Selection(1, 1, 1, 1), EditorPaneSelectionChangeReason.USER);
|
||||
const selection = pane.getSelection();
|
||||
assert.ok(selection);
|
||||
await pane.group?.closeAllEditors();
|
||||
const options = selection.restore({});
|
||||
pane = (await accessor.editorService.openEditor({ resource, options }) as TestTextFileEditor);
|
||||
|
||||
assert.ok(pane && isEditorPaneWithSelection(pane));
|
||||
|
||||
const newSelection = pane.getSelection();
|
||||
assert.ok(newSelection);
|
||||
assert.strictEqual(newSelection.compare(selection), EditorPaneSelectionCompareResult.IDENTICAL);
|
||||
});
|
||||
|
||||
test('TextEditorPaneSelection', function () {
|
||||
const sel1 = new TextEditorPaneSelection(new Selection(1, 1, 2, 2));
|
||||
const sel2 = new TextEditorPaneSelection(new Selection(5, 5, 6, 6));
|
||||
const sel3 = new TextEditorPaneSelection(new Selection(50, 50, 60, 60));
|
||||
const sel4 = { compare: () => { throw new Error(); }, restore: (options: IEditorOptions) => options };
|
||||
|
||||
assert.strictEqual(sel1.compare(sel1), EditorPaneSelectionCompareResult.IDENTICAL);
|
||||
assert.strictEqual(sel1.compare(sel2), EditorPaneSelectionCompareResult.SIMILAR);
|
||||
assert.strictEqual(sel1.compare(sel3), EditorPaneSelectionCompareResult.DIFFERENT);
|
||||
assert.strictEqual(sel1.compare(sel4), EditorPaneSelectionCompareResult.DIFFERENT);
|
||||
});
|
||||
});
|
||||
@@ -10,7 +10,7 @@ import { TextResourceEditorModel } from 'vs/workbench/common/editor/textResource
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { workbenchInstantiationService, TestServiceAccessor } from 'vs/workbench/test/browser/workbenchTestServices';
|
||||
import { snapshotToString } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { ModesRegistry, PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry';
|
||||
import { PLAINTEXT_LANGUAGE_ID } from 'vs/editor/common/languages/modesRegistry';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
|
||||
suite('TextResourceEditorInput', () => {
|
||||
@@ -31,7 +31,7 @@ suite('TextResourceEditorInput', () => {
|
||||
|
||||
test('basics', async () => {
|
||||
const resource = URI.from({ scheme: 'inmemory', authority: null!, path: 'thePath' });
|
||||
accessor.modelService.createModel('function test() {}', accessor.modeService.create('text'), resource);
|
||||
accessor.modelService.createModel('function test() {}', accessor.languageService.createById(PLAINTEXT_LANGUAGE_ID), resource);
|
||||
|
||||
const input = instantiationService.createInstance(TextResourceEditorInput, resource, 'The Name', 'The Description', undefined, undefined);
|
||||
|
||||
@@ -41,13 +41,13 @@ suite('TextResourceEditorInput', () => {
|
||||
assert.strictEqual(snapshotToString(((model as TextResourceEditorModel).createSnapshot()!)), 'function test() {}');
|
||||
});
|
||||
|
||||
test('preferred mode (via ctor)', async () => {
|
||||
ModesRegistry.registerLanguage({
|
||||
test('preferred language (via ctor)', async () => {
|
||||
const registration = accessor.languageService.registerLanguage({
|
||||
id: 'resource-input-test',
|
||||
});
|
||||
|
||||
const resource = URI.from({ scheme: 'inmemory', authority: null!, path: 'thePath' });
|
||||
accessor.modelService.createModel('function test() {}', accessor.modeService.create('text'), resource);
|
||||
accessor.modelService.createModel('function test() {}', accessor.languageService.createById(PLAINTEXT_LANGUAGE_ID), resource);
|
||||
|
||||
const input = instantiationService.createInstance(TextResourceEditorInput, resource, 'The Name', 'The Description', 'resource-input-test', undefined);
|
||||
|
||||
@@ -55,32 +55,34 @@ suite('TextResourceEditorInput', () => {
|
||||
assert.ok(model);
|
||||
assert.strictEqual(model.textEditorModel?.getLanguageId(), 'resource-input-test');
|
||||
|
||||
input.setMode('text');
|
||||
assert.strictEqual(model.textEditorModel?.getLanguageId(), PLAINTEXT_MODE_ID);
|
||||
input.setLanguageId('text');
|
||||
assert.strictEqual(model.textEditorModel?.getLanguageId(), PLAINTEXT_LANGUAGE_ID);
|
||||
|
||||
await input.resolve();
|
||||
assert.strictEqual(model.textEditorModel?.getLanguageId(), PLAINTEXT_MODE_ID);
|
||||
assert.strictEqual(model.textEditorModel?.getLanguageId(), PLAINTEXT_LANGUAGE_ID);
|
||||
registration.dispose();
|
||||
});
|
||||
|
||||
test('preferred mode (via setPreferredMode)', async () => {
|
||||
ModesRegistry.registerLanguage({
|
||||
test('preferred language (via setPreferredLanguageId)', async () => {
|
||||
const registration = accessor.languageService.registerLanguage({
|
||||
id: 'resource-input-test',
|
||||
});
|
||||
|
||||
const resource = URI.from({ scheme: 'inmemory', authority: null!, path: 'thePath' });
|
||||
accessor.modelService.createModel('function test() {}', accessor.modeService.create('text'), resource);
|
||||
accessor.modelService.createModel('function test() {}', accessor.languageService.createById(PLAINTEXT_LANGUAGE_ID), resource);
|
||||
|
||||
const input = instantiationService.createInstance(TextResourceEditorInput, resource, 'The Name', 'The Description', undefined, undefined);
|
||||
input.setPreferredMode('resource-input-test');
|
||||
input.setPreferredLanguageId('resource-input-test');
|
||||
|
||||
const model = await input.resolve();
|
||||
assert.ok(model);
|
||||
assert.strictEqual(model.textEditorModel?.getLanguageId(), 'resource-input-test');
|
||||
registration.dispose();
|
||||
});
|
||||
|
||||
test('preferred contents (via ctor)', async () => {
|
||||
const resource = URI.from({ scheme: 'inmemory', authority: null!, path: 'thePath' });
|
||||
accessor.modelService.createModel('function test() {}', accessor.modeService.create('text'), resource);
|
||||
accessor.modelService.createModel('function test() {}', accessor.languageService.createById(PLAINTEXT_LANGUAGE_ID), resource);
|
||||
|
||||
const input = instantiationService.createInstance(TextResourceEditorInput, resource, 'The Name', 'The Description', undefined, 'My Resource Input Contents');
|
||||
|
||||
@@ -97,7 +99,7 @@ suite('TextResourceEditorInput', () => {
|
||||
|
||||
test('preferred contents (via setPreferredContents)', async () => {
|
||||
const resource = URI.from({ scheme: 'inmemory', authority: null!, path: 'thePath' });
|
||||
accessor.modelService.createModel('function test() {}', accessor.modeService.create('text'), resource);
|
||||
accessor.modelService.createModel('function test() {}', accessor.languageService.createById(PLAINTEXT_LANGUAGE_ID), resource);
|
||||
|
||||
const input = instantiationService.createInstance(TextResourceEditorInput, resource, 'The Name', 'The Description', undefined, undefined);
|
||||
input.setPreferredContents('My Resource Input Contents');
|
||||
|
||||
@@ -43,7 +43,7 @@ suite('Workbench status bar model', () => {
|
||||
|
||||
assert.ok(model.findEntry(container));
|
||||
|
||||
let didChangeEntryVisibility: { id: string, visible: boolean } = { id: '', visible: false };
|
||||
let didChangeEntryVisibility: { id: string; visible: boolean } = { id: '', visible: false };
|
||||
model.onDidChangeEntryVisibility(e => {
|
||||
didChangeEntryVisibility = e;
|
||||
});
|
||||
|
||||
25
src/vs/workbench/test/browser/webview.test.ts
Normal file
25
src/vs/workbench/test/browser/webview.test.ts
Normal 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 { parentOriginHash } from 'vs/workbench/browser/webview';
|
||||
|
||||
suite('parentOriginHash', () => {
|
||||
|
||||
test('localhost 1', async () => {
|
||||
const hash = await parentOriginHash('http://localhost:9888', '123456');
|
||||
assert.strictEqual(hash, '0fnsiac2jaup1t266qekgr7iuj4pnm31gf8r0h1o6k2lvvmfh6hk');
|
||||
});
|
||||
|
||||
test('localhost 2', async () => {
|
||||
const hash = await parentOriginHash('http://localhost:9888', '123457');
|
||||
assert.strictEqual(hash, '07shf01bmdfrghk96voldpletbh36vj7blnl4td8kdq1sej5kjqs');
|
||||
});
|
||||
|
||||
test('localhost 3', async () => {
|
||||
const hash = await parentOriginHash('http://localhost:9887', '123456');
|
||||
assert.strictEqual(hash, '1v1128i162q0nee9l89360sqan26u3pdnjrkke5ijd0sel8sbtqf');
|
||||
});
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ import * as assert from 'assert';
|
||||
import { NotificationsModel, NotificationViewItem, INotificationChangeEvent, NotificationChangeType, NotificationViewItemContentChangeKind, IStatusMessageChangeEvent, StatusMessageChangeType } from 'vs/workbench/common/notifications';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { INotification, Severity, NotificationsFilter } from 'vs/platform/notification/common/notification';
|
||||
import { createErrorWithActions } from 'vs/base/common/errors';
|
||||
import { createErrorWithActions } from 'vs/base/common/errorMessage';
|
||||
import { NotificationService } from 'vs/workbench/services/notification/common/notificationService';
|
||||
import { TestStorageService } from 'vs/workbench/test/common/workbenchTestServices';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
@@ -127,7 +127,7 @@ suite('Notifications', () => {
|
||||
assert.strictEqual(called, 1);
|
||||
|
||||
// Error with Action
|
||||
let item7 = NotificationViewItem.create({ severity: Severity.Error, message: createErrorWithActions('Hello Error', { actions: [new Action('id', 'label')] }) })!;
|
||||
let item7 = NotificationViewItem.create({ severity: Severity.Error, message: createErrorWithActions('Hello Error', [new Action('id', 'label')]) })!;
|
||||
assert.strictEqual(item7.actions!.primary!.length, 1);
|
||||
|
||||
// Filter
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { LanguagesRegistry } from 'vs/editor/common/services/languagesRegistry';
|
||||
// import { ModeServiceImpl } from 'vs/editor/common/services/modeServiceImpl';
|
||||
// import { LanguageService } from 'vs/editor/common/services/languageServiceImpl';
|
||||
|
||||
/**
|
||||
* This function is called before test running and also again at the end of test running
|
||||
@@ -14,6 +14,6 @@ import { LanguagesRegistry } from 'vs/editor/common/services/languagesRegistry';
|
||||
export function assertCleanState(): void {
|
||||
// If this test fails, it is a clear indication that
|
||||
// your test or suite is leaking services (e.g. via leaking text models)
|
||||
// assert.strictEqual(ModeServiceImpl.instanceCount, 0, 'No leaking IModeService');
|
||||
// assert.strictEqual(LanguageService.instanceCount, 0, 'No leaking ILanguageService');
|
||||
assert.strictEqual(LanguagesRegistry.instanceCount, 0, 'No leaking LanguagesRegistry');
|
||||
}
|
||||
@@ -8,10 +8,9 @@ import { basename, isEqual, isEqualOrParent } from 'vs/base/common/resources';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IWorkspaceContextService, IWorkspace, WorkbenchState, IWorkspaceFolder, IWorkspaceFoldersChangeEvent, Workspace, IWorkspaceFoldersWillChangeEvent } from 'vs/platform/workspace/common/workspace';
|
||||
import { IWorkspaceContextService, IWorkspace, WorkbenchState, IWorkspaceFolder, IWorkspaceFoldersChangeEvent, Workspace, IWorkspaceFoldersWillChangeEvent, ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace';
|
||||
import { TestWorkspace } from 'vs/platform/workspace/test/common/testWorkspace';
|
||||
import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { ITextResourcePropertiesService } from 'vs/editor/common/services/textResourceConfigurationService';
|
||||
import { ITextResourcePropertiesService } from 'vs/editor/common/services/textResourceConfiguration';
|
||||
import { isLinux, isMacintosh } from 'vs/base/common/platform';
|
||||
import { InMemoryStorageService, WillSaveStateReason } from 'vs/platform/storage/common/storage';
|
||||
import { IWorkingCopy, IWorkingCopyBackup, WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopy';
|
||||
@@ -23,6 +22,7 @@ import { ISaveOptions, IRevertOptions, SaveReason } from 'vs/workbench/common/ed
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import product from 'vs/platform/product/common/product';
|
||||
import { IActivity, IActivityService } from 'vs/workbench/services/activity/common/activity';
|
||||
import { IStoredFileWorkingCopySaveEvent } from 'vs/workbench/services/workingCopy/common/storedFileWorkingCopy';
|
||||
|
||||
export class TestTextResourcePropertiesService implements ITextResourcePropertiesService {
|
||||
|
||||
@@ -140,6 +140,9 @@ export class TestWorkingCopy extends Disposable implements IWorkingCopy {
|
||||
private readonly _onDidChangeContent = this._register(new Emitter<void>());
|
||||
readonly onDidChangeContent = this._onDidChangeContent.event;
|
||||
|
||||
private readonly _onDidSave = this._register(new Emitter<IStoredFileWorkingCopySaveEvent>());
|
||||
readonly onDidSave = this._onDidSave.event;
|
||||
|
||||
readonly capabilities = WorkingCopyCapabilities.None;
|
||||
|
||||
readonly name = basename(this.resource);
|
||||
@@ -167,7 +170,9 @@ export class TestWorkingCopy extends Disposable implements IWorkingCopy {
|
||||
return this.dirty;
|
||||
}
|
||||
|
||||
async save(options?: ISaveOptions): Promise<boolean> {
|
||||
async save(options?: ISaveOptions, stat?: IFileStatWithMetadata): Promise<boolean> {
|
||||
this._onDidSave.fire({ reason: options?.reason ?? SaveReason.EXPLICIT, stat: stat ?? createFileStat(this.resource), source: options?.source });
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -180,6 +185,22 @@ export class TestWorkingCopy extends Disposable implements IWorkingCopy {
|
||||
}
|
||||
}
|
||||
|
||||
export function createFileStat(resource: URI, readonly = false): IFileStatWithMetadata {
|
||||
return {
|
||||
resource,
|
||||
etag: Date.now().toString(),
|
||||
mtime: Date.now(),
|
||||
ctime: Date.now(),
|
||||
size: 42,
|
||||
isFile: true,
|
||||
isDirectory: false,
|
||||
isSymbolicLink: false,
|
||||
readonly,
|
||||
name: basename(resource),
|
||||
children: undefined
|
||||
};
|
||||
}
|
||||
|
||||
export class TestWorkingCopyFileService implements IWorkingCopyFileService {
|
||||
|
||||
declare readonly _serviceBrand: undefined;
|
||||
@@ -192,7 +213,7 @@ export class TestWorkingCopyFileService implements IWorkingCopyFileService {
|
||||
|
||||
readonly hasSaveParticipants = false;
|
||||
addSaveParticipant(participant: IStoredFileWorkingCopySaveParticipant): IDisposable { return Disposable.None; }
|
||||
async runSaveParticipants(workingCopy: IWorkingCopy, context: { reason: SaveReason; }, token: CancellationToken): Promise<void> { }
|
||||
async runSaveParticipants(workingCopy: IWorkingCopy, context: { reason: SaveReason }, token: CancellationToken): Promise<void> { }
|
||||
|
||||
async delete(operations: IDeleteOperation[], token: CancellationToken, undoInfo?: IFileOperationUndoRedoInfo): Promise<void> { }
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,108 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { workbenchInstantiationService } from 'vs/workbench/test/electron-browser/workbenchTestServices';
|
||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||
import { ISearchService, IFileQuery } from 'vs/workbench/services/search/common/search';
|
||||
import { MainThreadWorkspace } from 'vs/workbench/api/browser/mainThreadWorkspace';
|
||||
import * as assert from 'assert';
|
||||
import { SingleProxyRPCProtocol } from 'vs/workbench/test/browser/api/testRPCProtocol';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
|
||||
suite('MainThreadWorkspace', () => {
|
||||
|
||||
let disposables: DisposableStore;
|
||||
let configService: TestConfigurationService;
|
||||
let instantiationService: TestInstantiationService;
|
||||
|
||||
setup(() => {
|
||||
disposables = new DisposableStore();
|
||||
instantiationService = workbenchInstantiationService(disposables) as TestInstantiationService;
|
||||
|
||||
configService = instantiationService.get(IConfigurationService) as TestConfigurationService;
|
||||
configService.setUserConfiguration('search', {});
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
disposables.dispose();
|
||||
});
|
||||
|
||||
test('simple', () => {
|
||||
instantiationService.stub(ISearchService, {
|
||||
fileSearch(query: IFileQuery) {
|
||||
assert.strictEqual(query.folderQueries.length, 1);
|
||||
assert.strictEqual(query.folderQueries[0].disregardIgnoreFiles, true);
|
||||
|
||||
assert.deepStrictEqual({ ...query.includePattern }, { 'foo': true });
|
||||
assert.strictEqual(query.maxResults, 10);
|
||||
|
||||
return Promise.resolve({ results: [], messages: [] });
|
||||
}
|
||||
});
|
||||
|
||||
const mtw: MainThreadWorkspace = instantiationService.createInstance(<any>MainThreadWorkspace, SingleProxyRPCProtocol({ $initializeWorkspace: () => { } }));
|
||||
return mtw.$startFileSearch('foo', null, null, 10, new CancellationTokenSource().token);
|
||||
});
|
||||
|
||||
test('exclude defaults', () => {
|
||||
configService.setUserConfiguration('search', {
|
||||
'exclude': { 'searchExclude': true }
|
||||
});
|
||||
configService.setUserConfiguration('files', {
|
||||
'exclude': { 'filesExclude': true }
|
||||
});
|
||||
|
||||
instantiationService.stub(ISearchService, {
|
||||
fileSearch(query: IFileQuery) {
|
||||
assert.strictEqual(query.folderQueries.length, 1);
|
||||
assert.strictEqual(query.folderQueries[0].disregardIgnoreFiles, true);
|
||||
assert.deepStrictEqual(query.folderQueries[0].excludePattern, { 'filesExclude': true });
|
||||
|
||||
return Promise.resolve({ results: [], messages: [] });
|
||||
}
|
||||
});
|
||||
|
||||
const mtw: MainThreadWorkspace = instantiationService.createInstance(<any>MainThreadWorkspace, SingleProxyRPCProtocol({ $initializeWorkspace: () => { } }));
|
||||
return mtw.$startFileSearch('', null, null, 10, new CancellationTokenSource().token);
|
||||
});
|
||||
|
||||
test('disregard excludes', () => {
|
||||
configService.setUserConfiguration('search', {
|
||||
'exclude': { 'searchExclude': true }
|
||||
});
|
||||
configService.setUserConfiguration('files', {
|
||||
'exclude': { 'filesExclude': true }
|
||||
});
|
||||
|
||||
instantiationService.stub(ISearchService, {
|
||||
fileSearch(query: IFileQuery) {
|
||||
assert.strictEqual(query.folderQueries[0].excludePattern, undefined);
|
||||
assert.deepStrictEqual(query.excludePattern, undefined);
|
||||
|
||||
return Promise.resolve({ results: [], messages: [] });
|
||||
}
|
||||
});
|
||||
|
||||
const mtw: MainThreadWorkspace = instantiationService.createInstance(<any>MainThreadWorkspace, SingleProxyRPCProtocol({ $initializeWorkspace: () => { } }));
|
||||
return mtw.$startFileSearch('', null, false, 10, new CancellationTokenSource().token);
|
||||
});
|
||||
|
||||
test('exclude string', () => {
|
||||
instantiationService.stub(ISearchService, {
|
||||
fileSearch(query: IFileQuery) {
|
||||
assert.strictEqual(query.folderQueries[0].excludePattern, undefined);
|
||||
assert.deepStrictEqual({ ...query.excludePattern }, { 'exclude/**': true });
|
||||
|
||||
return Promise.resolve({ results: [], messages: [] });
|
||||
}
|
||||
});
|
||||
|
||||
const mtw: MainThreadWorkspace = instantiationService.createInstance(<any>MainThreadWorkspace, SingleProxyRPCProtocol({ $initializeWorkspace: () => { } }));
|
||||
return mtw.$startFileSearch('', null, 'exclude/**', 10, new CancellationTokenSource().token);
|
||||
});
|
||||
});
|
||||
@@ -1,131 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IColorRegistry, Extensions, ColorContribution } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { asText } from 'vs/platform/request/common/request';
|
||||
import * as pfs from 'vs/base/node/pfs';
|
||||
import * as path from 'vs/base/common/path';
|
||||
import * as assert from 'assert';
|
||||
import { getPathFromAmdModule } from 'vs/base/test/node/testUtils';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { RequestService } from 'vs/platform/request/node/requestService';
|
||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||
import 'vs/workbench/workbench.desktop.main';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
import { mock } from 'vs/base/test/common/mock';
|
||||
import { INativeEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
|
||||
interface ColorInfo {
|
||||
description: string;
|
||||
offset: number;
|
||||
length: number;
|
||||
}
|
||||
|
||||
interface DescriptionDiff {
|
||||
docDescription: string;
|
||||
specDescription: string;
|
||||
}
|
||||
|
||||
export const experimental: string[] = []; // 'settings.modifiedItemForeground', 'editorUnnecessary.foreground' ];
|
||||
|
||||
suite('Color Registry', function () {
|
||||
|
||||
test('all colors documented in theme-color.md', async function () {
|
||||
// avoid importing the TestEnvironmentService as it brings in a duplicate registration of the file editor input factory.
|
||||
const environmentService = new class extends mock<INativeEnvironmentService>() { override args = { _: [] }; };
|
||||
|
||||
const reqContext = await new RequestService(new TestConfigurationService(), environmentService, new NullLogService()).request({ url: 'https://raw.githubusercontent.com/microsoft/vscode-docs/vnext/api/references/theme-color.md' }, CancellationToken.None);
|
||||
const content = (await asText(reqContext))!;
|
||||
|
||||
const expression = /\-\s*\`([\w\.]+)\`: (.*)/g;
|
||||
|
||||
let m: RegExpExecArray | null;
|
||||
let colorsInDoc: { [id: string]: ColorInfo } = Object.create(null);
|
||||
let nColorsInDoc = 0;
|
||||
while (m = expression.exec(content)) {
|
||||
colorsInDoc[m[1]] = { description: m[2], offset: m.index, length: m.length };
|
||||
nColorsInDoc++;
|
||||
}
|
||||
assert.ok(nColorsInDoc > 0, 'theme-color.md contains to color descriptions');
|
||||
|
||||
let missing = Object.create(null);
|
||||
let descriptionDiffs: { [id: string]: DescriptionDiff } = Object.create(null);
|
||||
|
||||
let themingRegistry = Registry.as<IColorRegistry>(Extensions.ColorContribution);
|
||||
for (let color of themingRegistry.getColors()) {
|
||||
if (!colorsInDoc[color.id]) {
|
||||
if (!color.deprecationMessage) {
|
||||
missing[color.id] = getDescription(color);
|
||||
}
|
||||
} else {
|
||||
let docDescription = colorsInDoc[color.id].description;
|
||||
let specDescription = getDescription(color);
|
||||
if (docDescription !== specDescription) {
|
||||
descriptionDiffs[color.id] = { docDescription, specDescription };
|
||||
}
|
||||
delete colorsInDoc[color.id];
|
||||
}
|
||||
}
|
||||
let colorsInExtensions = await getColorsFromExtension();
|
||||
for (let colorId in colorsInExtensions) {
|
||||
if (!colorsInDoc[colorId]) {
|
||||
missing[colorId] = colorsInExtensions[colorId];
|
||||
} else {
|
||||
delete colorsInDoc[colorId];
|
||||
}
|
||||
}
|
||||
for (let colorId of experimental) {
|
||||
if (missing[colorId]) {
|
||||
delete missing[colorId];
|
||||
}
|
||||
if (colorsInDoc[colorId]) {
|
||||
assert.fail(`Color ${colorId} found in doc but marked experimental. Please remove from experimental list.`);
|
||||
}
|
||||
}
|
||||
|
||||
let undocumentedKeys = Object.keys(missing).map(k => `\`${k}\`: ${missing[k]}`);
|
||||
assert.deepStrictEqual(undocumentedKeys, [], 'Undocumented colors ids');
|
||||
|
||||
let superfluousKeys = Object.keys(colorsInDoc);
|
||||
assert.deepStrictEqual(superfluousKeys, [], 'Colors ids in doc that do not exist');
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
function getDescription(color: ColorContribution) {
|
||||
let specDescription = color.description;
|
||||
if (color.deprecationMessage) {
|
||||
specDescription = specDescription + ' ' + color.deprecationMessage;
|
||||
}
|
||||
return specDescription;
|
||||
}
|
||||
|
||||
async function getColorsFromExtension(): Promise<{ [id: string]: string }> {
|
||||
let extPath = getPathFromAmdModule(require, '../../../../../extensions');
|
||||
let extFolders = await pfs.Promises.readDirsInDir(extPath);
|
||||
let result: { [id: string]: string } = Object.create(null);
|
||||
for (let folder of extFolders) {
|
||||
try {
|
||||
let packageJSON = JSON.parse((await pfs.Promises.readFile(path.join(extPath, folder, 'package.json'))).toString());
|
||||
let contributes = packageJSON['contributes'];
|
||||
if (contributes) {
|
||||
let colors = contributes['colors'];
|
||||
if (colors) {
|
||||
for (let color of colors) {
|
||||
let colorId = color['id'];
|
||||
if (colorId) {
|
||||
result[colorId] = colorId['description'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { Extensions, IColorRegistry } from 'vs/platform/theme/common/colorRegistry';
|
||||
|
||||
suite('ColorRegistry', () => {
|
||||
if (process.env.VSCODE_COLOR_REGISTRY_EXPORT) {
|
||||
test('exports', () => {
|
||||
const themingRegistry = Registry.as<IColorRegistry>(Extensions.ColorContribution);
|
||||
const colors = themingRegistry.getColors();
|
||||
const replacer = (_key: string, value: unknown) =>
|
||||
value instanceof Color ? Color.Format.CSS.formatHexA(value) : value;
|
||||
console.log(`#colors:${JSON.stringify(colors, replacer)}\n`);
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -1,230 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 fs from 'fs';
|
||||
import * as minimist from 'minimist';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import * as path from 'vs/base/common/path';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl';
|
||||
import { ModeServiceImpl } from 'vs/editor/common/services/modeServiceImpl';
|
||||
import { ITextResourcePropertiesService } from 'vs/editor/common/services/textResourceConfigurationService';
|
||||
import { TestLanguageConfigurationService } from 'vs/editor/test/common/modes/testLanguageConfigurationService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { TestDialogService } from 'vs/platform/dialogs/test/common/testDialogService';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { ILogService, NullLogService } from 'vs/platform/log/common/log';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
|
||||
import { ClassifiedEvent, GDPRClassification, StrictPropertyCheck } from 'vs/platform/telemetry/common/gdprTypings';
|
||||
import { ITelemetryInfo, ITelemetryService, TelemetryLevel } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService';
|
||||
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
|
||||
import { UndoRedoService } from 'vs/platform/undoRedo/common/undoRedoService';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { testWorkspace } from 'vs/platform/workspace/test/common/testWorkspace';
|
||||
import 'vs/workbench/contrib/search/browser/search.contribution'; // load contributions
|
||||
import { ITextQueryBuilderOptions, QueryBuilder } from 'vs/workbench/contrib/search/common/queryBuilder';
|
||||
import { SearchModel } from 'vs/workbench/contrib/search/common/searchModel';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { ISearchService } from 'vs/workbench/services/search/common/search';
|
||||
import { LocalSearchService } from 'vs/workbench/services/search/electron-browser/searchService';
|
||||
import { IUntitledTextEditorService, UntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService';
|
||||
import { TestEditorGroupsService, TestEditorService } from 'vs/workbench/test/browser/workbenchTestServices';
|
||||
import { TestContextService, TestTextResourcePropertiesService } from 'vs/workbench/test/common/workbenchTestServices';
|
||||
import { TestEnvironmentService } from 'vs/workbench/test/electron-browser/workbenchTestServices';
|
||||
|
||||
|
||||
|
||||
// declare var __dirname: string;
|
||||
|
||||
// Checkout sources to run against:
|
||||
// git clone --separate-git-dir=testGit --no-checkout --single-branch https://chromium.googlesource.com/chromium/src testWorkspace
|
||||
// cd testWorkspace; git checkout 39a7f93d67f7
|
||||
// Run from repository root folder with (test.bat on Windows): ./scripts/test-int-mocha.sh --grep TextSearch.performance --timeout 500000 --testWorkspace <path>
|
||||
suite.skip('TextSearch performance (integration)', () => {
|
||||
|
||||
test('Measure', () => {
|
||||
if (process.env['VSCODE_PID']) {
|
||||
return undefined; // TODO@Rob find out why test fails when run from within VS Code
|
||||
}
|
||||
|
||||
const n = 3;
|
||||
const argv = minimist(process.argv);
|
||||
const testWorkspaceArg = argv['testWorkspace'];
|
||||
const testWorkspacePath = testWorkspaceArg ? path.resolve(testWorkspaceArg) : __dirname;
|
||||
if (!fs.existsSync(testWorkspacePath)) {
|
||||
throw new Error(`--testWorkspace doesn't exist`);
|
||||
}
|
||||
|
||||
const telemetryService = new TestTelemetryService();
|
||||
const configurationService = new TestConfigurationService();
|
||||
const textResourcePropertiesService = new TestTextResourcePropertiesService(configurationService);
|
||||
const logService = new NullLogService();
|
||||
const dialogService = new TestDialogService();
|
||||
const notificationService = new TestNotificationService();
|
||||
const undoRedoService = new UndoRedoService(dialogService, notificationService);
|
||||
const instantiationService = new InstantiationService(
|
||||
new ServiceCollection(
|
||||
[ITelemetryService, telemetryService],
|
||||
[IConfigurationService, configurationService],
|
||||
[ITextResourcePropertiesService, textResourcePropertiesService],
|
||||
[IDialogService, dialogService],
|
||||
[INotificationService, notificationService],
|
||||
[IUndoRedoService, undoRedoService],
|
||||
[
|
||||
IModelService,
|
||||
new ModelServiceImpl(
|
||||
configurationService,
|
||||
textResourcePropertiesService,
|
||||
new TestThemeService(),
|
||||
logService,
|
||||
undoRedoService,
|
||||
new ModeServiceImpl(),
|
||||
new TestLanguageConfigurationService()
|
||||
),
|
||||
],
|
||||
[
|
||||
IWorkspaceContextService,
|
||||
new TestContextService(testWorkspace(URI.file(testWorkspacePath))),
|
||||
],
|
||||
[IEditorService, new TestEditorService()],
|
||||
[IEditorGroupsService, new TestEditorGroupsService()],
|
||||
[IEnvironmentService, TestEnvironmentService],
|
||||
[
|
||||
IUntitledTextEditorService,
|
||||
new SyncDescriptor(UntitledTextEditorService),
|
||||
],
|
||||
[ISearchService, new SyncDescriptor(LocalSearchService)],
|
||||
[ILogService, logService]
|
||||
)
|
||||
);
|
||||
|
||||
const queryOptions: ITextQueryBuilderOptions = {
|
||||
maxResults: 2048
|
||||
};
|
||||
|
||||
const searchModel: SearchModel = instantiationService.createInstance(SearchModel);
|
||||
function runSearch(): Promise<any> {
|
||||
const queryBuilder: QueryBuilder = instantiationService.createInstance(QueryBuilder);
|
||||
const query = queryBuilder.text({ pattern: 'static_library(' }, [URI.file(testWorkspacePath)], queryOptions);
|
||||
|
||||
// Wait for the 'searchResultsFinished' event, which is fired after the search() promise is resolved
|
||||
const onSearchResultsFinished = Event.filter(telemetryService.eventLogged, e => e.name === 'searchResultsFinished');
|
||||
Event.once(onSearchResultsFinished)(onComplete);
|
||||
|
||||
function onComplete(): void {
|
||||
try {
|
||||
const allEvents = telemetryService.events.map(e => JSON.stringify(e)).join('\n');
|
||||
assert.strictEqual(telemetryService.events.length, 3, 'Expected 3 telemetry events, got:\n' + allEvents);
|
||||
|
||||
const [firstRenderEvent, resultsShownEvent, resultsFinishedEvent] = telemetryService.events;
|
||||
assert.strictEqual(firstRenderEvent.name, 'searchResultsFirstRender');
|
||||
assert.strictEqual(resultsShownEvent.name, 'searchResultsShown');
|
||||
assert.strictEqual(resultsFinishedEvent.name, 'searchResultsFinished');
|
||||
|
||||
telemetryService.events = [];
|
||||
|
||||
resolve!(resultsFinishedEvent);
|
||||
} catch (e) {
|
||||
// Fail the runSearch() promise
|
||||
error!(e);
|
||||
}
|
||||
}
|
||||
|
||||
let resolve: (result: any) => void;
|
||||
let error: (error: Error) => void;
|
||||
return new Promise((_resolve, _error) => {
|
||||
resolve = _resolve;
|
||||
error = _error;
|
||||
|
||||
// Don't wait on this promise, we're waiting on the event fired above
|
||||
searchModel.search(query).then(
|
||||
null,
|
||||
_error);
|
||||
});
|
||||
}
|
||||
|
||||
const finishedEvents: any[] = [];
|
||||
return runSearch() // Warm-up first
|
||||
.then(() => {
|
||||
if (testWorkspaceArg) { // Don't measure by default
|
||||
let i = n;
|
||||
return (function iterate(): Promise<undefined> | undefined {
|
||||
if (!i--) {
|
||||
return undefined; // {{SQL CARBON EDIT}} strict-null-checks
|
||||
}
|
||||
|
||||
return runSearch()
|
||||
.then((resultsFinishedEvent: any) => {
|
||||
console.log(`Iteration ${n - i}: ${resultsFinishedEvent.data.duration / 1000}s`);
|
||||
finishedEvents.push(resultsFinishedEvent);
|
||||
return iterate();
|
||||
});
|
||||
})()!.then(() => {
|
||||
const totalTime = finishedEvents.reduce((sum, e) => sum + e.data.duration, 0);
|
||||
console.log(`Avg duration: ${totalTime / n / 1000}s`);
|
||||
});
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
class TestTelemetryService implements ITelemetryService {
|
||||
public _serviceBrand: undefined;
|
||||
public telemetryLevel = TelemetryLevel.USAGE;
|
||||
public sendErrorTelemetry = true;
|
||||
|
||||
public events: any[] = [];
|
||||
|
||||
private readonly emitter = new Emitter<any>();
|
||||
|
||||
public get eventLogged(): Event<any> {
|
||||
return this.emitter.event;
|
||||
}
|
||||
|
||||
public setEnabled(value: boolean): void {
|
||||
}
|
||||
|
||||
public setExperimentProperty(name: string, value: string): void {
|
||||
}
|
||||
|
||||
public publicLog(eventName: string, data?: any): Promise<void> {
|
||||
const event = { name: eventName, data: data };
|
||||
this.events.push(event);
|
||||
this.emitter.fire(event);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
public publicLog2<E extends ClassifiedEvent<T> = never, T extends GDPRClassification<T> = never>(eventName: string, data?: StrictPropertyCheck<T, E>) {
|
||||
return this.publicLog(eventName, data as any);
|
||||
}
|
||||
|
||||
public publicLogError(eventName: string, data?: any): Promise<void> {
|
||||
return this.publicLog(eventName, data);
|
||||
}
|
||||
|
||||
public publicLogError2<E extends ClassifiedEvent<T> = never, T extends GDPRClassification<T> = never>(eventName: string, data?: StrictPropertyCheck<T, E>) {
|
||||
return this.publicLogError(eventName, data as any);
|
||||
}
|
||||
|
||||
public getTelemetryInfo(): Promise<ITelemetryInfo> {
|
||||
return Promise.resolve({
|
||||
instanceId: 'someValue.instanceId',
|
||||
sessionId: 'someValue.sessionId',
|
||||
machineId: 'someValue.machineId',
|
||||
firstSessionDate: 'someValue.firstSessionDate'
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { workbenchInstantiationService as browserWorkbenchInstantiationService, ITestInstantiationService, TestLifecycleService, TestFilesConfigurationService, TestFileService, TestFileDialogService, TestPathService, TestEncodingOracle, TestProductService } from 'vs/workbench/test/browser/workbenchTestServices';
|
||||
import { workbenchInstantiationService as browserWorkbenchInstantiationService, ITestInstantiationService, TestLifecycleService, TestFilesConfigurationService, TestFileService, TestFileDialogService, TestPathService, TestEncodingOracle } from 'vs/workbench/test/browser/workbenchTestServices';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { ISharedProcessService } from 'vs/platform/ipc/electron-sandbox/services';
|
||||
import { NativeTextFileService, } from 'vs/workbench/services/textfile/electron-sandbox/nativeTextFileService';
|
||||
@@ -12,10 +12,10 @@ import { FileOperationError, IFileService } from 'vs/platform/files/common/files
|
||||
import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService';
|
||||
import { ILifecycleService } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { INativeWorkbenchConfiguration, INativeWorkbenchEnvironmentService, NativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService';
|
||||
import { IModelService } from 'vs/editor/common/services/model';
|
||||
import { INativeWorkbenchEnvironmentService, NativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService';
|
||||
import { IDialogService, IFileDialogService, INativeOpenDialogOptions } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfigurationService';
|
||||
import { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfiguration';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService';
|
||||
import { ITextModelService } from 'vs/editor/common/services/resolverService';
|
||||
@@ -23,21 +23,21 @@ import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IReadTextFileOptions, ITextFileStreamContent, ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { createTextBufferFactoryFromStream } from 'vs/editor/common/model/textModel';
|
||||
import { IOpenEmptyWindowOptions, IWindowOpenable, IOpenWindowOptions, IOpenedWindow, IPartsSplash, IColorScheme } from 'vs/platform/windows/common/windows';
|
||||
import { IOpenEmptyWindowOptions, IWindowOpenable, IOpenWindowOptions, IOpenedWindow, IColorScheme, INativeWindowConfiguration } from 'vs/platform/window/common/window';
|
||||
import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv';
|
||||
import { LogLevel, ILogService } from 'vs/platform/log/common/log';
|
||||
import { IPathService } from 'vs/workbench/services/path/common/pathService';
|
||||
import { IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/common/workingCopyFileService';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl';
|
||||
import { ModelService } from 'vs/editor/common/services/modelService';
|
||||
import { IWorkingCopyBackupService } from 'vs/workbench/services/workingCopy/common/workingCopyBackup';
|
||||
import { NodeTestWorkingCopyBackupService } from 'vs/workbench/services/workingCopy/test/electron-browser/workingCopyBackupService.test';
|
||||
import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { TestContextService } from 'vs/workbench/test/common/workbenchTestServices';
|
||||
import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity';
|
||||
import { TestContextService, TestProductService } from 'vs/workbench/test/common/workbenchTestServices';
|
||||
import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity';
|
||||
import { MouseInputEvent } from 'vs/base/parts/sandbox/common/electronTypes';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { ILanguageService } from 'vs/editor/common/languages/language';
|
||||
import { IOSProperties, IOSStatistics } from 'vs/platform/native/common/native';
|
||||
import { homedir, release, tmpdir, hostname } from 'os';
|
||||
import { IEnvironmentService, INativeEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
@@ -47,10 +47,11 @@ import product from 'vs/platform/product/common/product';
|
||||
import { IElevatedFileService } from 'vs/workbench/services/files/common/elevatedFileService';
|
||||
import { IDecorationsService } from 'vs/workbench/services/decorations/common/decorations';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { IPartsSplash } from 'vs/platform/theme/common/themeService';
|
||||
|
||||
const args = parseArgs(process.argv, OPTIONS);
|
||||
|
||||
export const TestWorkbenchConfiguration: INativeWorkbenchConfiguration = {
|
||||
export const TestNativeWindowConfiguration: INativeWindowConfiguration = {
|
||||
windowId: 0,
|
||||
machineId: 'testMachineId',
|
||||
logLevel: LogLevel.Error,
|
||||
@@ -68,7 +69,7 @@ export const TestWorkbenchConfiguration: INativeWorkbenchConfiguration = {
|
||||
...args
|
||||
};
|
||||
|
||||
export const TestEnvironmentService = new NativeWorkbenchEnvironmentService(TestWorkbenchConfiguration, TestProductService);
|
||||
export const TestEnvironmentService = new NativeWorkbenchEnvironmentService(TestNativeWindowConfiguration, TestProductService);
|
||||
|
||||
export class TestTextFileService extends NativeTextFileService {
|
||||
private resolveTextContentError!: FileOperationError | null;
|
||||
@@ -91,7 +92,7 @@ export class TestTextFileService extends NativeTextFileService {
|
||||
@IWorkingCopyFileService workingCopyFileService: IWorkingCopyFileService,
|
||||
@ILogService logService: ILogService,
|
||||
@IUriIdentityService uriIdentityService: IUriIdentityService,
|
||||
@IModeService modeService: IModeService,
|
||||
@ILanguageService languageService: ILanguageService,
|
||||
@IElevatedFileService elevatedFileService: IElevatedFileService,
|
||||
@IDecorationsService decorationsService: IDecorationsService
|
||||
) {
|
||||
@@ -111,7 +112,7 @@ export class TestTextFileService extends NativeTextFileService {
|
||||
pathService,
|
||||
workingCopyFileService,
|
||||
uriIdentityService,
|
||||
modeService,
|
||||
languageService,
|
||||
elevatedFileService,
|
||||
logService,
|
||||
decorationsService
|
||||
@@ -202,9 +203,10 @@ export class TestNativeHostService implements INativeHostService {
|
||||
async maximizeWindow(): Promise<void> { }
|
||||
async unmaximizeWindow(): Promise<void> { }
|
||||
async minimizeWindow(): Promise<void> { }
|
||||
async updateTitleBarOverlay(backgroundColor: string, foregroundColor: string): Promise<void> { }
|
||||
async setMinimumSize(width: number | undefined, height: number | undefined): Promise<void> { }
|
||||
async saveWindowSplash(value: IPartsSplash): Promise<void> { }
|
||||
async focusWindow(options?: { windowId?: number | undefined; } | undefined): Promise<void> { }
|
||||
async focusWindow(options?: { windowId?: number | undefined } | undefined): Promise<void> { }
|
||||
async showMessageBox(options: Electron.MessageBoxOptions): Promise<Electron.MessageBoxReturnValue> { throw new Error('Method not implemented.'); }
|
||||
async showSaveDialog(options: Electron.SaveDialogOptions): Promise<Electron.SaveDialogReturnValue> { throw new Error('Method not implemented.'); }
|
||||
async showOpenDialog(options: Electron.OpenDialogOptions): Promise<Electron.OpenDialogReturnValue> { throw new Error('Method not implemented.'); }
|
||||
@@ -234,7 +236,7 @@ export class TestNativeHostService implements INativeHostService {
|
||||
async installShellCommand(): Promise<void> { }
|
||||
async uninstallShellCommand(): Promise<void> { }
|
||||
async notifyReady(): Promise<void> { }
|
||||
async relaunch(options?: { addArgs?: string[] | undefined; removeArgs?: string[] | undefined; } | undefined): Promise<void> { }
|
||||
async relaunch(options?: { addArgs?: string[] | undefined; removeArgs?: string[] | undefined } | undefined): Promise<void> { }
|
||||
async reload(): Promise<void> { }
|
||||
async closeWindow(): Promise<void> { }
|
||||
async closeWindowById(): Promise<void> { }
|
||||
@@ -244,6 +246,7 @@ export class TestNativeHostService implements INativeHostService {
|
||||
async toggleDevTools(): Promise<void> { }
|
||||
async toggleSharedProcessWindow(): Promise<void> { }
|
||||
async resolveProxy(url: string): Promise<string | undefined> { return undefined; }
|
||||
async findFreePort(startPort: number, giveUpAfter: number, timeout: number, stride?: number): Promise<number> { return -1; }
|
||||
async readClipboardText(type?: 'selection' | 'clipboard' | undefined): Promise<string> { return ''; }
|
||||
async writeClipboardData(data: any, type?: 'selection' | 'clipboard' | undefined): Promise<void> { } // {{SQL CARBON EDIT}}
|
||||
async writeClipboardText(text: string, type?: 'selection' | 'clipboard' | undefined): Promise<void> { }
|
||||
@@ -254,11 +257,6 @@ export class TestNativeHostService implements INativeHostService {
|
||||
async hasClipboard(format: string, type?: 'selection' | 'clipboard' | undefined): Promise<boolean> { return false; }
|
||||
async sendInputEvent(event: MouseInputEvent): Promise<void> { }
|
||||
async windowsGetStringRegKey(hive: 'HKEY_CURRENT_USER' | 'HKEY_LOCAL_MACHINE' | 'HKEY_CLASSES_ROOT' | 'HKEY_USERS' | 'HKEY_CURRENT_CONFIG', path: string, name: string): Promise<string | undefined> { return undefined; }
|
||||
async getPassword(service: string, account: string): Promise<string | null> { return null; }
|
||||
async setPassword(service: string, account: string, password: string): Promise<void> { }
|
||||
async deletePassword(service: string, account: string): Promise<boolean> { return false; }
|
||||
async findPassword(service: string): Promise<string | null> { return null; }
|
||||
async findCredentials(service: string): Promise<{ account: string; password: string; }[]> { return []; }
|
||||
}
|
||||
|
||||
export function workbenchInstantiationService(disposables = new DisposableStore()): ITestInstantiationService {
|
||||
@@ -282,7 +280,7 @@ export class TestServiceAccessor {
|
||||
@ITextFileService public textFileService: TestTextFileService,
|
||||
@IFilesConfigurationService public filesConfigurationService: TestFilesConfigurationService,
|
||||
@IWorkspaceContextService public contextService: TestContextService,
|
||||
@IModelService public modelService: ModelServiceImpl,
|
||||
@IModelService public modelService: ModelService,
|
||||
@IFileService public fileService: TestFileService,
|
||||
@INativeHostService public nativeHostService: TestNativeHostService,
|
||||
@IFileDialogService public fileDialogService: TestFileDialogService,
|
||||
|
||||
@@ -1,281 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { findPorts, getRootProcesses, getSockets, loadConnectionTable, loadListeningPorts, tryFindRootPorts } from 'vs/workbench/api/node/extHostTunnelService';
|
||||
|
||||
const tcp =
|
||||
` sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
|
||||
0: 00000000:0BBA 00000000:0000 0A 00000000:00000000 00:00000000 00000000 1000 0 2335214 1 0000000010173312 100 0 0 10 0
|
||||
1: 00000000:1AF3 00000000:0000 0A 00000000:00000000 00:00000000 00000000 1000 0 2334514 1 000000008815920b 100 0 0 10 0
|
||||
2: 0100007F:A9EA 0100007F:1AF3 01 00000000:00000000 00:00000000 00000000 1000 0 2334521 1 00000000a37d44c6 21 4 0 10 -1
|
||||
3: 0100007F:E8B4 0100007F:98EF 01 00000000:00000000 00:00000000 00000000 1000 0 2334532 1 0000000031b88f06 21 4 0 10 -1
|
||||
4: 0100007F:866C 0100007F:8783 01 00000000:00000000 00:00000000 00000000 1000 0 2334510 1 00000000cbf670bb 21 4 30 10 -1
|
||||
5: 0100007F:1AF3 0100007F:A9EA 01 00000000:00000000 00:00000000 00000000 1000 0 2338989 1 0000000000bace62 21 4 1 10 -1
|
||||
`;
|
||||
const tcp6 =
|
||||
` sl local_address remote_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
|
||||
0: 00000000000000000000000000000000:815B 00000000000000000000000000000000:0000 0A 00000000:00000000 00:00000000 00000000 1000 0 2321070 1 00000000c44f3f02 100 0 0 10 0
|
||||
1: 00000000000000000000000000000000:8783 00000000000000000000000000000000:0000 0A 00000000:00000000 00:00000000 00000000 1000 0 2334509 1 000000003915e812 100 0 0 10 0
|
||||
2: 00000000000000000000000000000000:9907 00000000000000000000000000000000:0000 0A 00000000:00000000 00:00000000 00000000 1000 0 2284465 1 00000000f13b9374 100 0 0 10 0
|
||||
3: 00000000000000000000000000000000:98EF 00000000000000000000000000000000:0000 0A 00000000:00000000 00:00000000 00000000 1000 0 2334531 1 00000000184cae9c 100 0 0 10 0
|
||||
4: 00000000000000000000000000000000:8BCF 00000000000000000000000000000000:0000 0A 00000000:00000000 00:00000000 00000000 1000 0 2329890 1 00000000c05a3466 100 0 0 10 0
|
||||
5: 0000000000000000FFFF00000100007F:8783 0000000000000000FFFF00000100007F:866C 01 00000000:00000000 00:00000000 00000000 1000 0 2334511 1 00000000bf547132 21 4 1 10 -1
|
||||
6: 0000000000000000FFFF00000100007F:98EF 0000000000000000FFFF00000100007F:E8B4 01 00000000:00000000 00:00000000 00000000 1000 0 2334533 1 0000000039d0bcd2 21 4 1 10 -1
|
||||
7: 0000000000000000FFFF0000DFD317AC:9907 0000000000000000FFFF000001D017AC:C123 01 0000005A:00000000 01:00000017 00000000 1000 0 2311039 3 0000000067b6c8db 23 5 25 10 52
|
||||
8: 0000000000000000FFFF0000DFD317AC:9907 0000000000000000FFFF000001D017AC:C124 01 00000000:00000000 00:00000000 00000000 1000 0 2311040 1 00000000230bb017 25 4 30 10 28
|
||||
9: 0000000000000000FFFF0000DFD317AC:9907 0000000000000000FFFF000001D017AC:C213 01 00000000:00000000 00:00000000 00000000 1000 0 2331501 1 00000000957fcb4a 26 4 30 10 57
|
||||
10: 0000000000000000FFFF0000DFD317AC:9907 0000000000000000FFFF000001D017AC:C214 01 00000000:00000000 00:00000000 00000000 1000 0 2331500 1 00000000d7f87ceb 25 4 28 10 -1
|
||||
`;
|
||||
|
||||
const procSockets =
|
||||
`ls: cannot access '/proc/8289/fd/255': No such file or directory
|
||||
ls: cannot access '/proc/8289/fd/3': No such file or directory
|
||||
lrwx------ 1 alex alex 64 Dec 8 14:59 /proc/230/fd/3 -> socket:[21862]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2504/fd/0 -> socket:[2311043]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2504/fd/1 -> socket:[2311045]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2504/fd/19 -> socket:[2311040]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2504/fd/2 -> socket:[2311047]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2504/fd/20 -> socket:[2314928]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2504/fd/22 -> socket:[2307042]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2504/fd/24 -> socket:[2307051]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2504/fd/25 -> socket:[2307044]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2504/fd/27 -> socket:[2307046]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2504/fd/29 -> socket:[2307053]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2504/fd/3 -> socket:[2311049]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2504/fd/30 -> socket:[2307048]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2504/fd/32 -> socket:[2307055]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2504/fd/33 -> socket:[2307067]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2504/fd/34 -> socket:[2307057]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2504/fd/35 -> socket:[2321483]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2504/fd/37 -> socket:[2321070]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2504/fd/41 -> socket:[2321485]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2504/fd/42 -> socket:[2321074]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2504/fd/43 -> socket:[2321487]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2504/fd/44 -> socket:[2329890]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2504/fd/45 -> socket:[2321489]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2504/fd/46 -> socket:[2334509]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:17 /proc/2504/fd/47 -> socket:[2334510]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:17 /proc/2504/fd/48 -> socket:[2329894]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:17 /proc/2504/fd/49 -> socket:[2334511]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:17 /proc/2504/fd/50 -> socket:[2334515]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:17 /proc/2504/fd/51 -> socket:[2334519]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:17 /proc/2504/fd/52 -> socket:[2334518]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:17 /proc/2504/fd/53 -> socket:[2334521]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:17 /proc/2504/fd/54 -> socket:[2334531]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:17 /proc/2504/fd/55 -> socket:[2334532]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:17 /proc/2504/fd/56 -> socket:[2334533]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2515/fd/3 -> socket:[2311053]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2719/fd/0 -> socket:[2307043]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2719/fd/1 -> socket:[2307045]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2719/fd/2 -> socket:[2307047]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2719/fd/3 -> socket:[2307049]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2725/fd/0 -> socket:[2307052]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2725/fd/1 -> socket:[2307054]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2725/fd/2 -> socket:[2307056]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2725/fd/20 -> socket:[2290617]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2725/fd/3 -> socket:[2307058]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2739/fd/0 -> socket:[2307052]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2739/fd/1 -> socket:[2307054]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2739/fd/2 -> socket:[2307056]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2739/fd/3 -> socket:[2290618]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2795/fd/0 -> socket:[2321484]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2795/fd/1 -> socket:[2321486]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2795/fd/2 -> socket:[2321488]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/2795/fd/3 -> socket:[2321490]
|
||||
lrwx------ 1 alex alex 64 Dec 8 14:59 /proc/314/fd/18 -> socket:[2284465]
|
||||
lrwx------ 1 alex alex 64 Dec 8 14:59 /proc/314/fd/19 -> socket:[2311039]
|
||||
lrwx------ 1 alex alex 64 Dec 8 14:59 /proc/314/fd/23 -> socket:[2331501]
|
||||
lrwx------ 1 alex alex 64 Dec 8 14:59 /proc/314/fd/24 -> socket:[2311052]
|
||||
lrwx------ 1 alex alex 64 Dec 8 14:59 /proc/314/fd/25 -> socket:[2311042]
|
||||
lrwx------ 1 alex alex 64 Dec 8 14:59 /proc/314/fd/26 -> socket:[2331504]
|
||||
lrwx------ 1 alex alex 64 Dec 8 14:59 /proc/314/fd/27 -> socket:[2311051]
|
||||
lrwx------ 1 alex alex 64 Dec 8 14:59 /proc/314/fd/29 -> socket:[2311044]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/314/fd/30 -> socket:[2321909]
|
||||
lrwx------ 1 alex alex 64 Dec 8 14:59 /proc/314/fd/31 -> socket:[2311046]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:14 /proc/314/fd/33 -> socket:[2311048]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:17 /proc/314/fd/35 -> socket:[2329692]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:17 /proc/314/fd/37 -> socket:[2331506]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:20 /proc/314/fd/40 -> socket:[2331508]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:20 /proc/314/fd/42 -> socket:[2331510]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:17 /proc/314/fd/68 -> socket:[2322083]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:22 /proc/4412/fd/20 -> socket:[2335214]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:22 /proc/4496/fd/0 -> socket:[2331505]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:22 /proc/4496/fd/1 -> socket:[2331507]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:22 /proc/4496/fd/2 -> socket:[2331509]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:22 /proc/4496/fd/23 -> socket:[2334514]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:22 /proc/4496/fd/24 -> socket:[2338989]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:22 /proc/4496/fd/26 -> socket:[2338276]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:22 /proc/4496/fd/27 -> socket:[2331500]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:22 /proc/4496/fd/3 -> socket:[2331511]
|
||||
lrwx------ 1 alex alex 64 Dec 8 15:22 /proc/4496/fd/31 -> socket:[2338285]`;
|
||||
|
||||
const processes: { pid: number, cwd: string, cmd: string }[] = [
|
||||
{
|
||||
pid: 230,
|
||||
cwd: '/mnt/c/WINDOWS/system32',
|
||||
cmd: 'dockerserve--addressunix:///home/alex/.docker/run/docker-cli-api.sock',
|
||||
},
|
||||
{
|
||||
pid: 2504,
|
||||
cwd: '/mnt/c/Users/alros/AppData/Local/Programs/Microsoft VS Code Insiders',
|
||||
cmd: '/home/alex/.vscode-server-insiders/bin/bc13785d3dd99b4b0e9da9aed17bb79809a50804/node/home/alex/.vscode-server-insiders/bin/bc13785d3dd99b4b0e9da9aed17bb79809a50804/out/bootstrap-fork--type=extensionHost--uriTransformerPath=/home/alex/.vscode-server-insiders/bin/bc13785d3dd99b4b0e9da9aed17bb79809a50804/out/vs/server/uriTransformer.js--useHostProxy=',
|
||||
},
|
||||
{
|
||||
pid: 2515,
|
||||
cwd: '/mnt/c/Users/alros/AppData/Local/Programs/Microsoft VS Code Insiders',
|
||||
cmd: '/home/alex/.vscode-server-insiders/bin/bc13785d3dd99b4b0e9da9aed17bb79809a50804/node/home/alex/.vscode-server-insiders/bin/bc13785d3dd99b4b0e9da9aed17bb79809a50804/out/bootstrap-fork--type=watcherService'
|
||||
},
|
||||
{
|
||||
pid: 2526,
|
||||
cwd: '/home/alex/repos/Microsoft/vscode-extension-samples/helloworld-sample',
|
||||
cmd: '/bin/bash'
|
||||
}, {
|
||||
pid: 2719,
|
||||
cwd: '/mnt/c/Users/alros/AppData/Local/Programs/Microsoft VS Code Insiders',
|
||||
cmd: '/home/alex/.vscode-server-insiders/bin/bc13785d3dd99b4b0e9da9aed17bb79809a50804/node--max-old-space-size=3072/home/alex/.vscode-server-insiders/bin/bc13785d3dd99b4b0e9da9aed17bb79809a50804/extensions/node_modules/typescript/lib/tsserver.js--serverModepartialSemantic--useInferredProjectPerProjectRoot--disableAutomaticTypingAcquisition--cancellationPipeName/tmp/vscode-typescript1000/7cfa7171c0c00aacf1ee/tscancellation-602cd80b954818b6a2f7.tmp*--logVerbosityverbose--logFile/home/alex/.vscode-server-insiders/data/logs/20201208T145954/exthost2/vscode.typescript-language-features/tsserver-log-nxBt2m/tsserver.log--globalPluginstypescript-vscode-sh-plugin--pluginProbeLocations/home/alex/.vscode-server-insiders/bin/bc13785d3dd99b4b0e9da9aed17bb79809a50804/extensions/typescript-language-features--localeen--noGetErrOnBackgroundUpdate--validateDefaultNpmLocation'
|
||||
},
|
||||
{
|
||||
pid: 2725,
|
||||
cwd: '/mnt/c/Users/alros/AppData/Local/Programs/Microsoft VS Code Insiders',
|
||||
cmd: '/home/alex/.vscode-server-insiders/bin/bc13785d3dd99b4b0e9da9aed17bb79809a50804/node--max-old-space-size=3072/home/alex/.vscode-server-insiders/bin/bc13785d3dd99b4b0e9da9aed17bb79809a50804/extensions/node_modules/typescript/lib/tsserver.js--useInferredProjectPerProjectRoot--enableTelemetry--cancellationPipeName/tmp/vscode-typescript1000/7cfa7171c0c00aacf1ee/tscancellation-04a0b92f880c2fd535ae.tmp*--logVerbosityverbose--logFile/home/alex/.vscode-server-insiders/data/logs/20201208T145954/exthost2/vscode.typescript-language-features/tsserver-log-fqyBrs/tsserver.log--globalPluginstypescript-vscode-sh-plugin--pluginProbeLocations/home/alex/.vscode-server-insiders/bin/bc13785d3dd99b4b0e9da9aed17bb79809a50804/extensions/typescript-language-features--localeen--noGetErrOnBackgroundUpdate--validateDefaultNpmLocation'
|
||||
},
|
||||
{
|
||||
pid: 2739,
|
||||
cwd: '/mnt/c/Users/alros/AppData/Local/Programs/Microsoft VS Code Insiders',
|
||||
cmd: '/home/alex/.vscode-server-insiders/bin/bc13785d3dd99b4b0e9da9aed17bb79809a50804/node/home/alex/.vscode-server-insiders/bin/bc13785d3dd99b4b0e9da9aed17bb79809a50804/extensions/node_modules/typescript/lib/typingsInstaller.js--globalTypingsCacheLocation/home/alex/.cache/typescript/4.1--enableTelemetry--logFile/home/alex/.vscode-server-insiders/data/logs/20201208T145954/exthost2/vscode.typescript-language-features/tsserver-log-fqyBrs/ti-2725.log--typesMapLocation/home/alex/.vscode-server-insiders/bin/bc13785d3dd99b4b0e9da9aed17bb79809a50804/extensions/node_modules/typescript/lib/typesMap.json--validateDefaultNpmLocation'
|
||||
},
|
||||
{
|
||||
pid: 2795,
|
||||
cwd: '/home/alex/repos/Microsoft/vscode-extension-samples/helloworld-sample',
|
||||
cmd: '/home/alex/.vscode-server-insiders/bin/bc13785d3dd99b4b0e9da9aed17bb79809a50804/node/home/alex/.vscode-server-insiders/bin/bc13785d3dd99b4b0e9da9aed17bb79809a50804/extensions/json-language-features/server/dist/node/jsonServerMain--node-ipc--clientProcessId=2504'
|
||||
},
|
||||
{
|
||||
pid: 286,
|
||||
cwd: '/mnt/c/Users/alros/AppData/Local/Programs/Microsoft VS Code Insiders',
|
||||
cmd: 'sh-c\"$VSCODE_WSL_EXT_LOCATION/ scripts / wslServer.sh\" bc13785d3dd99b4b0e9da9aed17bb79809a50804 insider .vscode-server-insiders 0 '
|
||||
},
|
||||
{
|
||||
pid: 287,
|
||||
cwd: '/mnt/c/Users/alros/AppData/Local/Programs/Microsoft VS Code Insiders',
|
||||
cmd: 'sh/mnt/c/Users/alros/.vscode-insiders/extensions/ms-vscode-remote.remote-wsl-0.52.0/scripts/wslServer.shbc13785d3dd99b4b0e9da9aed17bb79809a50804insider.vscode-server-insiders0'
|
||||
},
|
||||
{
|
||||
pid: 3058,
|
||||
cwd: '/home/alex/repos/Microsoft/vscode-extension-samples/helloworld-sample',
|
||||
cmd: 'npm'
|
||||
},
|
||||
{
|
||||
pid: 3070,
|
||||
cwd: '/home/alex/repos/Microsoft/vscode-extension-samples/helloworld-sample',
|
||||
cmd: 'sh-ctsc -watch -p ./'
|
||||
},
|
||||
{
|
||||
pid: 3071,
|
||||
cwd: '/home/alex/repos/Microsoft/vscode-extension-samples/helloworld-sample',
|
||||
cmd: 'node/home/alex/repos/Microsoft/vscode-extension-samples/helloworld-sample/node_modules/.bin/tsc-watch-p./'
|
||||
},
|
||||
{
|
||||
pid: 312,
|
||||
cwd: '/mnt/c/Users/alros/AppData/Local/Programs/Microsoft VS Code Insiders',
|
||||
cmd: 'sh/home/alex/.vscode-server-insiders/bin/bc13785d3dd99b4b0e9da9aed17bb79809a50804/server.sh--port=0--use-host-proxy--enable-remote-auto-shutdown--print-ip-address'
|
||||
},
|
||||
{
|
||||
pid: 314,
|
||||
cwd: '/mnt/c/Users/alros/AppData/Local/Programs/Microsoft VS Code Insiders',
|
||||
cmd: '/home/alex/.vscode-server-insiders/bin/bc13785d3dd99b4b0e9da9aed17bb79809a50804/node/home/alex/.vscode-server-insiders/bin/bc13785d3dd99b4b0e9da9aed17bb79809a50804/out/vs/server/main.js--port=0--use-host-proxy--enable-remote-auto-shutdown--print-ip-address'
|
||||
},
|
||||
{
|
||||
pid: 3172,
|
||||
cwd: '/home/alex',
|
||||
cmd: '/bin/bash'
|
||||
},
|
||||
{
|
||||
pid: 3610,
|
||||
cwd: '/home/alex/repos/Microsoft/vscode-extension-samples/helloworld-sample',
|
||||
cmd: '/bin/bash'
|
||||
},
|
||||
{
|
||||
pid: 4412,
|
||||
cwd: '/home/alex/repos/Microsoft/vscode-extension-samples/helloworld-sample',
|
||||
cmd: 'http-server'
|
||||
},
|
||||
{
|
||||
pid: 4496,
|
||||
cwd: '/mnt/c/Users/alros/AppData/Local/Programs/Microsoft VS Code Insiders',
|
||||
cmd: '/home/alex/.vscode-server-insiders/bin/bc13785d3dd99b4b0e9da9aed17bb79809a50804/node--inspect-brk=0.0.0.0:6899/home/alex/.vscode-server-insiders/bin/bc13785d3dd99b4b0e9da9aed17bb79809a50804/out/bootstrap-fork--type=extensionHost--uriTransformerPath=/home/alex/.vscode-server-insiders/bin/bc13785d3dd99b4b0e9da9aed17bb79809a50804/out/vs/server/uriTransformer.js--useHostProxy='
|
||||
},
|
||||
{
|
||||
pid: 4507,
|
||||
cwd: '/mnt/c/Users/alros/AppData/Local/Programs/Microsoft VS Code Insiders',
|
||||
cmd: '/home/alex/.vscode-server-insiders/bin/bc13785d3dd99b4b0e9da9aed17bb79809a50804/node/home/alex/.vscode-server-insiders/bin/bc13785d3dd99b4b0e9da9aed17bb79809a50804/extensions/ms-vscode.js-debug/src/hash.bundle.js'
|
||||
}
|
||||
];
|
||||
|
||||
const psStdOut =
|
||||
`4 S root 1 0 0 80 0 - 596 - 1440 2 14:41 ? 00:00:00 /bin/sh -c echo Container started ; trap "exit 0" 15; while sleep 1 & wait $!; do :; done
|
||||
4 S root 14 0 0 80 0 - 596 - 764 4 14:41 ? 00:00:00 /bin/sh
|
||||
4 S root 40 0 0 80 0 - 596 - 700 4 14:41 ? 00:00:00 /bin/sh
|
||||
4 S root 513 380 0 80 0 - 2476 - 3404 1 14:41 pts/1 00:00:00 sudo npx http-server -p 5000
|
||||
4 S root 514 513 0 80 0 - 165439 - 41380 5 14:41 pts/1 00:00:00 http-server
|
||||
0 S root 1052 1 0 80 0 - 573 - 752 5 14:43 ? 00:00:00 sleep 1
|
||||
0 S node 1056 329 0 80 0 - 596 do_wai 764 10 14:43 ? 00:00:00 /bin/sh -c ps -F -A -l | grep root
|
||||
0 S node 1058 1056 0 80 0 - 770 pipe_w 888 9 14:43 ? 00:00:00 grep root`;
|
||||
|
||||
suite('ExtHostTunnelService', () => {
|
||||
test('getSockets', function () {
|
||||
const result = getSockets(procSockets);
|
||||
assert.strictEqual(Object.keys(result).length, 75);
|
||||
// 4412 is the pid of the http-server in the test data
|
||||
assert.notStrictEqual(Object.keys(result).find(key => result[key].pid === 4412), undefined);
|
||||
});
|
||||
|
||||
test('loadConnectionTable', function () {
|
||||
const result = loadConnectionTable(tcp);
|
||||
assert.strictEqual(result.length, 6);
|
||||
assert.deepStrictEqual(result[0], {
|
||||
10: '1',
|
||||
11: '0000000010173312',
|
||||
12: '100',
|
||||
13: '0',
|
||||
14: '0',
|
||||
15: '10',
|
||||
16: '0',
|
||||
inode: '2335214',
|
||||
local_address: '00000000:0BBA',
|
||||
rem_address: '00000000:0000',
|
||||
retrnsmt: '00000000',
|
||||
sl: '0:',
|
||||
st: '0A',
|
||||
timeout: '0',
|
||||
tr: '00:00000000',
|
||||
tx_queue: '00000000:00000000',
|
||||
uid: '1000'
|
||||
});
|
||||
});
|
||||
|
||||
test('loadListeningPorts', function () {
|
||||
const result = loadListeningPorts(tcp, tcp6);
|
||||
// There should be 7 based on the input data. One of them should be 3002.
|
||||
assert.strictEqual(result.length, 7);
|
||||
assert.notStrictEqual(result.find(value => value.port === 3002), undefined);
|
||||
});
|
||||
|
||||
test('tryFindRootPorts', function () {
|
||||
const rootProcesses = getRootProcesses(psStdOut);
|
||||
assert.strictEqual(rootProcesses.length, 6);
|
||||
const result = tryFindRootPorts([{ socket: 1000, ip: '127.0.0.1', port: 5000 }], psStdOut, new Map());
|
||||
assert.strictEqual(result.size, 1);
|
||||
assert.strictEqual(result.get(5000)?.pid, 514);
|
||||
});
|
||||
|
||||
test('findPorts', async function () {
|
||||
const result = await findPorts(loadListeningPorts(tcp, tcp6), getSockets(procSockets), processes);
|
||||
assert.strictEqual(result.length, 1);
|
||||
assert.strictEqual(result[0].host, '0.0.0.0');
|
||||
assert.strictEqual(result[0].port, 3002);
|
||||
assert.strictEqual(result[0].detail, 'http-server');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user