mirror of
https://github.com/coder/code-server.git
synced 2026-05-09 05:47:26 +02:00
Merge commit 'be3e8236086165e5e45a5a10783823874b3f3ebd' as 'lib/vscode'
This commit is contained in:
60
lib/vscode/src/vs/base/test/browser/actionbar.test.ts
Normal file
60
lib/vscode/src/vs/base/test/browser/actionbar.test.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { ActionBar, prepareActions } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { Action, Separator } from 'vs/base/common/actions';
|
||||
|
||||
suite('Actionbar', () => {
|
||||
|
||||
test('prepareActions()', function () {
|
||||
let a1 = new Separator();
|
||||
let a2 = new Separator();
|
||||
let a3 = new Action('a3');
|
||||
let a4 = new Separator();
|
||||
let a5 = new Separator();
|
||||
let a6 = new Action('a6');
|
||||
let a7 = new Separator();
|
||||
|
||||
let actions = prepareActions([a1, a2, a3, a4, a5, a6, a7]);
|
||||
assert.strictEqual(actions.length, 3); // duplicate separators get removed
|
||||
assert(actions[0] === a3);
|
||||
assert(actions[1] === a5);
|
||||
assert(actions[2] === a6);
|
||||
});
|
||||
|
||||
test('hasAction()', function () {
|
||||
const container = document.createElement('div');
|
||||
const actionbar = new ActionBar(container);
|
||||
|
||||
let a1 = new Action('a1');
|
||||
let a2 = new Action('a2');
|
||||
|
||||
actionbar.push(a1);
|
||||
assert.equal(actionbar.hasAction(a1), true);
|
||||
assert.equal(actionbar.hasAction(a2), false);
|
||||
|
||||
actionbar.pull(0);
|
||||
assert.equal(actionbar.hasAction(a1), false);
|
||||
|
||||
actionbar.push(a1, { index: 1 });
|
||||
actionbar.push(a2, { index: 0 });
|
||||
assert.equal(actionbar.hasAction(a1), true);
|
||||
assert.equal(actionbar.hasAction(a2), true);
|
||||
|
||||
actionbar.pull(0);
|
||||
assert.equal(actionbar.hasAction(a1), true);
|
||||
assert.equal(actionbar.hasAction(a2), false);
|
||||
|
||||
actionbar.pull(0);
|
||||
assert.equal(actionbar.hasAction(a1), false);
|
||||
assert.equal(actionbar.hasAction(a2), false);
|
||||
|
||||
actionbar.push(a1);
|
||||
assert.equal(actionbar.hasAction(a1), true);
|
||||
actionbar.clear();
|
||||
assert.equal(actionbar.hasAction(a1), false);
|
||||
});
|
||||
});
|
||||
12
lib/vscode/src/vs/base/test/browser/browser.test.ts
Normal file
12
lib/vscode/src/vs/base/test/browser/browser.test.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as assert from 'assert';
|
||||
import { isMacintosh, isWindows } from 'vs/base/common/platform';
|
||||
|
||||
suite('Browsers', () => {
|
||||
test('all', () => {
|
||||
assert(!(isWindows && isMacintosh));
|
||||
});
|
||||
});
|
||||
52
lib/vscode/src/vs/base/test/browser/codicons.test.ts
Normal file
52
lib/vscode/src/vs/base/test/browser/codicons.test.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { renderCodicons } from 'vs/base/browser/codicons';
|
||||
import * as assert from 'assert';
|
||||
|
||||
suite('renderCodicons', () => {
|
||||
|
||||
test('no codicons', () => {
|
||||
const result = renderCodicons(' hello World .');
|
||||
|
||||
assert.equal(elementsToString(result), ' hello World .');
|
||||
});
|
||||
|
||||
test('codicon only', () => {
|
||||
const result = renderCodicons('$(alert)');
|
||||
|
||||
assert.equal(elementsToString(result), '<span class="codicon codicon-alert"></span>');
|
||||
});
|
||||
|
||||
test('codicon and non-codicon strings', () => {
|
||||
const result = renderCodicons(` $(alert) Unresponsive`);
|
||||
|
||||
assert.equal(elementsToString(result), ' <span class="codicon codicon-alert"></span> Unresponsive');
|
||||
});
|
||||
|
||||
test('multiple codicons', () => {
|
||||
const result = renderCodicons('$(check)$(error)');
|
||||
|
||||
assert.equal(elementsToString(result), '<span class="codicon codicon-check"></span><span class="codicon codicon-error"></span>');
|
||||
});
|
||||
|
||||
test('escaped codicon', () => {
|
||||
const result = renderCodicons('\\$(escaped)');
|
||||
|
||||
assert.equal(elementsToString(result), '$(escaped)');
|
||||
});
|
||||
|
||||
test('codicon with animation', () => {
|
||||
const result = renderCodicons('$(zip~anim)');
|
||||
|
||||
assert.equal(elementsToString(result), '<span class="codicon codicon-zip codicon-animation-anim"></span>');
|
||||
});
|
||||
|
||||
const elementsToString = (elements: Array<HTMLElement | string>): string => {
|
||||
return elements
|
||||
.map(elem => elem instanceof HTMLElement ? elem.outerHTML : elem)
|
||||
.reduce((a, b) => a + b, '');
|
||||
};
|
||||
});
|
||||
285
lib/vscode/src/vs/base/test/browser/comparers.test.ts
Normal file
285
lib/vscode/src/vs/base/test/browser/comparers.test.ts
Normal file
@@ -0,0 +1,285 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { compareFileNames, compareFileExtensions, compareFileNamesDefault, compareFileExtensionsDefault } from 'vs/base/common/comparers';
|
||||
import * as assert from 'assert';
|
||||
|
||||
const compareLocale = (a: string, b: string) => a.localeCompare(b);
|
||||
const compareLocaleNumeric = (a: string, b: string) => a.localeCompare(b, undefined, { numeric: true });
|
||||
|
||||
|
||||
suite('Comparers', () => {
|
||||
|
||||
test('compareFileNames', () => {
|
||||
|
||||
//
|
||||
// Comparisons with the same results as compareFileNamesDefault
|
||||
//
|
||||
|
||||
// name-only comparisons
|
||||
assert(compareFileNames(null, null) === 0, 'null should be equal');
|
||||
assert(compareFileNames(null, 'abc') < 0, 'null should be come before real values');
|
||||
assert(compareFileNames('', '') === 0, 'empty should be equal');
|
||||
assert(compareFileNames('abc', 'abc') === 0, 'equal names should be equal');
|
||||
assert(compareFileNames('z', 'A') > 0, 'z comes is after A regardless of case');
|
||||
assert(compareFileNames('Z', 'a') > 0, 'Z comes after a regardless of case');
|
||||
|
||||
// name plus extension comparisons
|
||||
assert(compareFileNames('bbb.aaa', 'aaa.bbb') > 0, 'files with extensions are compared first by filename');
|
||||
assert(compareFileNames('aggregate.go', 'aggregate_repo.go') > 0, 'compares the whole name all at once by locale');
|
||||
|
||||
// dotfile comparisons
|
||||
assert(compareFileNames('.abc', '.abc') === 0, 'equal dotfile names should be equal');
|
||||
assert(compareFileNames('.env.', '.gitattributes') < 0, 'filenames starting with dots and with extensions should still sort properly');
|
||||
assert(compareFileNames('.env', '.aaa.env') > 0, 'dotfiles sort alphabetically when they contain multiple dots');
|
||||
assert(compareFileNames('.env', '.env.aaa') < 0, 'dotfiles with the same root sort shortest first');
|
||||
assert(compareFileNames('.aaa_env', '.aaa.env') < 0, 'and underscore in a dotfile name will sort before a dot');
|
||||
|
||||
// dotfile vs non-dotfile comparisons
|
||||
assert(compareFileNames(null, '.abc') < 0, 'null should come before dotfiles');
|
||||
assert(compareFileNames('.env', 'aaa') < 0, 'dotfiles come before filenames without extensions');
|
||||
assert(compareFileNames('.env', 'aaa.env') < 0, 'dotfiles come before filenames with extensions');
|
||||
assert(compareFileNames('.md', 'A.MD') < 0, 'dotfiles sort before uppercase files');
|
||||
assert(compareFileNames('.MD', 'a.md') < 0, 'dotfiles sort before lowercase files');
|
||||
|
||||
// numeric comparisons
|
||||
assert(compareFileNames('1', '1') === 0, 'numerically equal full names should be equal');
|
||||
assert(compareFileNames('abc1.txt', 'abc1.txt') === 0, 'equal filenames with numbers should be equal');
|
||||
assert(compareFileNames('abc1.txt', 'abc2.txt') < 0, 'filenames with numbers should be in numerical order, not alphabetical order');
|
||||
assert(compareFileNames('abc2.txt', 'abc10.txt') < 0, 'filenames with numbers should be in numerical order even when they are multiple digits long');
|
||||
assert(compareFileNames('abc02.txt', 'abc010.txt') < 0, 'filenames with numbers that have leading zeros sort numerically');
|
||||
assert(compareFileNames('abc1.10.txt', 'abc1.2.txt') > 0, 'numbers with dots between them are treated as two separate numbers, not one decimal number');
|
||||
|
||||
//
|
||||
// Comparisons with different results than compareFileNamesDefault
|
||||
//
|
||||
|
||||
// name-only comparisons
|
||||
assert(compareFileNames('a', 'A') !== compareLocale('a', 'A'), 'the same letter does not sort by locale');
|
||||
assert(compareFileNames('â', 'Â') !== compareLocale('â', 'Â'), 'the same accented letter does not sort by locale');
|
||||
assert.notDeepEqual(['artichoke', 'Artichoke', 'art', 'Art'].sort(compareFileNames), ['artichoke', 'Artichoke', 'art', 'Art'].sort(compareLocale), 'words with the same root and different cases do not sort in locale order');
|
||||
assert.notDeepEqual(['email', 'Email', 'émail', 'Émail'].sort(compareFileNames), ['email', 'Email', 'émail', 'Émail'].sort(compareLocale), 'the same base characters with different case or accents do not sort in locale order');
|
||||
|
||||
// numeric comparisons
|
||||
assert(compareFileNames('abc02.txt', 'abc002.txt') > 0, 'filenames with equivalent numbers and leading zeros sort in unicode order');
|
||||
assert(compareFileNames('abc.txt1', 'abc.txt01') > 0, 'same name plus extensions with equal numbers sort in unicode order');
|
||||
assert(compareFileNames('art01', 'Art01') !== 'art01'.localeCompare('Art01', undefined, { numeric: true }),
|
||||
'a numerically equivalent word of a different case does not compare numerically based on locale');
|
||||
|
||||
});
|
||||
|
||||
test('compareFileExtensions', () => {
|
||||
|
||||
//
|
||||
// Comparisons with the same results as compareFileExtensionsDefault
|
||||
//
|
||||
|
||||
// name-only comparisons
|
||||
assert(compareFileExtensions(null, null) === 0, 'null should be equal');
|
||||
assert(compareFileExtensions(null, 'abc') < 0, 'null should come before real files without extension');
|
||||
assert(compareFileExtensions('', '') === 0, 'empty should be equal');
|
||||
assert(compareFileExtensions('abc', 'abc') === 0, 'equal names should be equal');
|
||||
assert(compareFileExtensions('z', 'A') > 0, 'z comes after A');
|
||||
assert(compareFileExtensions('Z', 'a') > 0, 'Z comes after a');
|
||||
|
||||
// name plus extension comparisons
|
||||
assert(compareFileExtensions('file.ext', 'file.ext') === 0, 'equal full names should be equal');
|
||||
assert(compareFileExtensions('a.ext', 'b.ext') < 0, 'if equal extensions, filenames should be compared');
|
||||
assert(compareFileExtensions('file.aaa', 'file.bbb') < 0, 'files with equal names should be compared by extensions');
|
||||
assert(compareFileExtensions('bbb.aaa', 'aaa.bbb') < 0, 'files should be compared by extensions even if filenames compare differently');
|
||||
assert(compareFileExtensions('agg.go', 'aggrepo.go') < 0, 'shorter names sort before longer names');
|
||||
assert(compareFileExtensions('agg.go', 'agg_repo.go') < 0, 'shorter names short before longer names even when the longer name contains an underscore');
|
||||
assert(compareFileExtensions('a.MD', 'b.md') < 0, 'when extensions are the same except for case, the files sort by name');
|
||||
|
||||
// dotfile comparisons
|
||||
assert(compareFileExtensions('.abc', '.abc') === 0, 'equal dotfiles should be equal');
|
||||
assert(compareFileExtensions('.md', '.Gitattributes') > 0, 'dotfiles sort alphabetically regardless of case');
|
||||
|
||||
// dotfile vs non-dotfile comparisons
|
||||
assert(compareFileExtensions(null, '.abc') < 0, 'null should come before dotfiles');
|
||||
assert(compareFileExtensions('.env', 'aaa.env') < 0, 'if equal extensions, filenames should be compared, empty filename should come before others');
|
||||
assert(compareFileExtensions('.MD', 'a.md') < 0, 'if extensions differ in case, files sort by extension in unicode order');
|
||||
|
||||
// numeric comparisons
|
||||
assert(compareFileExtensions('1', '1') === 0, 'numerically equal full names should be equal');
|
||||
assert(compareFileExtensions('abc1.txt', 'abc1.txt') === 0, 'equal filenames with numbers should be equal');
|
||||
assert(compareFileExtensions('abc1.txt', 'abc2.txt') < 0, 'filenames with numbers should be in numerical order, not alphabetical order');
|
||||
assert(compareFileExtensions('abc2.txt', 'abc10.txt') < 0, 'filenames with numbers should be in numerical order even when they are multiple digits long');
|
||||
assert(compareFileExtensions('abc02.txt', 'abc010.txt') < 0, 'filenames with numbers that have leading zeros sort numerically');
|
||||
assert(compareFileExtensions('abc1.10.txt', 'abc1.2.txt') > 0, 'numbers with dots between them are treated as two separate numbers, not one decimal number');
|
||||
assert(compareFileExtensions('abc2.txt2', 'abc1.txt10') < 0, 'extensions with numbers should be in numerical order, not alphabetical order');
|
||||
assert(compareFileExtensions('txt.abc1', 'txt.abc1') === 0, 'equal extensions with numbers should be equal');
|
||||
assert(compareFileExtensions('txt.abc1', 'txt.abc2') < 0, 'extensions with numbers should be in numerical order, not alphabetical order');
|
||||
assert(compareFileExtensions('txt.abc2', 'txt.abc10') < 0, 'extensions with numbers should be in numerical order even when they are multiple digits long');
|
||||
assert(compareFileExtensions('a.ext1', 'b.ext1') < 0, 'if equal extensions with numbers, filenames should be compared');
|
||||
assert(compareFileExtensions('a10.txt', 'A2.txt') > 0, 'filenames with number and case differences compare numerically');
|
||||
|
||||
//
|
||||
// Comparisons with different results from compareFileExtensionsDefault
|
||||
//
|
||||
|
||||
// name-only comparisions
|
||||
assert(compareFileExtensions('a', 'A') !== compareLocale('a', 'A'), 'the same letter of different case does not sort by locale');
|
||||
assert(compareFileExtensions('â', 'Â') !== compareLocale('â', 'Â'), 'the same accented letter of different case does not sort by locale');
|
||||
assert.notDeepEqual(['artichoke', 'Artichoke', 'art', 'Art'].sort(compareFileExtensions), ['artichoke', 'Artichoke', 'art', 'Art'].sort(compareLocale), 'words with the same root and different cases do not sort in locale order');
|
||||
assert.notDeepEqual(['email', 'Email', 'émail', 'Émail'].sort(compareFileExtensions), ['email', 'Email', 'émail', 'Émail'].sort((a, b) => a.localeCompare(b)), 'the same base characters with different case or accents do not sort in locale order');
|
||||
|
||||
// name plus extension comparisons
|
||||
assert(compareFileExtensions('a.MD', 'a.md') !== compareLocale('MD', 'md'), 'case differences in extensions do not sort by locale');
|
||||
assert(compareFileExtensions('a.md', 'A.md') !== compareLocale('a', 'A'), 'case differences in names do not sort by locale');
|
||||
assert(compareFileExtensions('aggregate.go', 'aggregate_repo.go') < 0, 'when extensions are equal, names sort in dictionary order');
|
||||
|
||||
// dotfile comparisons
|
||||
assert(compareFileExtensions('.env', '.aaa.env') < 0, 'a dotfile with an extension is treated as a name plus an extension - equal extensions');
|
||||
assert(compareFileExtensions('.env', '.env.aaa') > 0, 'a dotfile with an extension is treated as a name plus an extension - unequal extensions');
|
||||
|
||||
// dotfile vs non-dotfile comparisons
|
||||
assert(compareFileExtensions('.env', 'aaa') > 0, 'filenames without extensions come before dotfiles');
|
||||
assert(compareFileExtensions('.md', 'A.MD') > 0, 'a file with an uppercase extension sorts before a dotfile of the same lowercase extension');
|
||||
|
||||
// numeric comparisons
|
||||
assert(compareFileExtensions('abc.txt01', 'abc.txt1') < 0, 'extensions with equal numbers sort in unicode order');
|
||||
assert(compareFileExtensions('art01', 'Art01') !== compareLocaleNumeric('art01', 'Art01'), 'a numerically equivalent word of a different case does not compare by locale');
|
||||
assert(compareFileExtensions('abc02.txt', 'abc002.txt') > 0, 'filenames with equivalent numbers and leading zeros sort in unicode order');
|
||||
assert(compareFileExtensions('txt.abc01', 'txt.abc1') < 0, 'extensions with equivalent numbers sort in unicode order');
|
||||
|
||||
});
|
||||
|
||||
test('compareFileNamesDefault', () => {
|
||||
|
||||
//
|
||||
// Comparisons with the same results as compareFileNames
|
||||
//
|
||||
|
||||
// name-only comparisons
|
||||
assert(compareFileNamesDefault(null, null) === 0, 'null should be equal');
|
||||
assert(compareFileNamesDefault(null, 'abc') < 0, 'null should be come before real values');
|
||||
assert(compareFileNamesDefault('', '') === 0, 'empty should be equal');
|
||||
assert(compareFileNamesDefault('abc', 'abc') === 0, 'equal names should be equal');
|
||||
assert(compareFileNamesDefault('z', 'A') > 0, 'z comes is after A regardless of case');
|
||||
assert(compareFileNamesDefault('Z', 'a') > 0, 'Z comes after a regardless of case');
|
||||
|
||||
// name plus extension comparisons
|
||||
assert(compareFileNamesDefault('file.ext', 'file.ext') === 0, 'equal full names should be equal');
|
||||
assert(compareFileNamesDefault('a.ext', 'b.ext') < 0, 'if equal extensions, filenames should be compared');
|
||||
assert(compareFileNamesDefault('file.aaa', 'file.bbb') < 0, 'files with equal names should be compared by extensions');
|
||||
assert(compareFileNamesDefault('bbb.aaa', 'aaa.bbb') > 0, 'files should be compared by names even if extensions compare differently');
|
||||
assert(compareFileNamesDefault('aggregate.go', 'aggregate_repo.go') > 0, 'compares the whole filename in locale order');
|
||||
|
||||
// dotfile comparisons
|
||||
assert(compareFileNamesDefault('.abc', '.abc') === 0, 'equal dotfile names should be equal');
|
||||
assert(compareFileNamesDefault('.env.', '.gitattributes') < 0, 'filenames starting with dots and with extensions should still sort properly');
|
||||
assert(compareFileNamesDefault('.env', '.aaa.env') > 0, 'dotfiles sort alphabetically when they contain multiple dots');
|
||||
assert(compareFileNamesDefault('.env', '.env.aaa') < 0, 'dotfiles with the same root sort shortest first');
|
||||
assert(compareFileNamesDefault('.aaa_env', '.aaa.env') < 0, 'and underscore in a dotfile name will sort before a dot');
|
||||
|
||||
// dotfile vs non-dotfile comparisons
|
||||
assert(compareFileNamesDefault(null, '.abc') < 0, 'null should come before dotfiles');
|
||||
assert(compareFileNamesDefault('.env', 'aaa') < 0, 'dotfiles come before filenames without extensions');
|
||||
assert(compareFileNamesDefault('.env', 'aaa.env') < 0, 'dotfiles come before filenames with extensions');
|
||||
assert(compareFileNamesDefault('.md', 'A.MD') < 0, 'dotfiles sort before uppercase files');
|
||||
assert(compareFileNamesDefault('.MD', 'a.md') < 0, 'dotfiles sort before lowercase files');
|
||||
|
||||
// numeric comparisons
|
||||
assert(compareFileNamesDefault('1', '1') === 0, 'numerically equal full names should be equal');
|
||||
assert(compareFileNamesDefault('abc1.txt', 'abc1.txt') === 0, 'equal filenames with numbers should be equal');
|
||||
assert(compareFileNamesDefault('abc1.txt', 'abc2.txt') < 0, 'filenames with numbers should be in numerical order, not alphabetical order');
|
||||
assert(compareFileNamesDefault('abc2.txt', 'abc10.txt') < 0, 'filenames with numbers should be in numerical order even when they are multiple digits long');
|
||||
assert(compareFileNamesDefault('abc02.txt', 'abc010.txt') < 0, 'filenames with numbers that have leading zeros sort numerically');
|
||||
assert(compareFileNamesDefault('abc1.10.txt', 'abc1.2.txt') > 0, 'numbers with dots between them are treated as two separate numbers, not one decimal number');
|
||||
|
||||
//
|
||||
// Comparisons with different results than compareFileNames
|
||||
//
|
||||
|
||||
// name-only comparisons
|
||||
assert(compareFileNamesDefault('a', 'A') === compareLocale('a', 'A'), 'the same letter sorts by locale');
|
||||
assert(compareFileNamesDefault('â', 'Â') === compareLocale('â', 'Â'), 'the same accented letter sorts by locale');
|
||||
assert.deepEqual(['artichoke', 'Artichoke', 'art', 'Art'].sort(compareFileNamesDefault), ['artichoke', 'Artichoke', 'art', 'Art'].sort(compareLocale), 'words with the same root and different cases sort in locale order');
|
||||
assert.deepEqual(['email', 'Email', 'émail', 'Émail'].sort(compareFileNamesDefault), ['email', 'Email', 'émail', 'Émail'].sort(compareLocale), 'the same base characters with different case or accents sort in locale order');
|
||||
|
||||
// numeric comparisons
|
||||
assert(compareFileNamesDefault('abc02.txt', 'abc002.txt') < 0, 'filenames with equivalent numbers and leading zeros sort shortest number first');
|
||||
assert(compareFileNamesDefault('abc.txt1', 'abc.txt01') < 0, 'same name plus extensions with equal numbers sort shortest number first');
|
||||
assert(compareFileNamesDefault('art01', 'Art01') === compareLocaleNumeric('art01', 'Art01'), 'a numerically equivalent word of a different case compares numerically based on locale');
|
||||
|
||||
});
|
||||
|
||||
test('compareFileExtensionsDefault', () => {
|
||||
|
||||
//
|
||||
// Comparisons with the same result as compareFileExtensions
|
||||
//
|
||||
|
||||
// name-only comparisons
|
||||
assert(compareFileExtensionsDefault(null, null) === 0, 'null should be equal');
|
||||
assert(compareFileExtensionsDefault(null, 'abc') < 0, 'null should come before real files without extensions');
|
||||
assert(compareFileExtensionsDefault('', '') === 0, 'empty should be equal');
|
||||
assert(compareFileExtensionsDefault('abc', 'abc') === 0, 'equal names should be equal');
|
||||
assert(compareFileExtensionsDefault('z', 'A') > 0, 'z comes after A');
|
||||
assert(compareFileExtensionsDefault('Z', 'a') > 0, 'Z comes after a');
|
||||
|
||||
// name plus extension comparisons
|
||||
assert(compareFileExtensionsDefault('file.ext', 'file.ext') === 0, 'equal full filenames should be equal');
|
||||
assert(compareFileExtensionsDefault('a.ext', 'b.ext') < 0, 'if equal extensions, filenames should be compared');
|
||||
assert(compareFileExtensionsDefault('file.aaa', 'file.bbb') < 0, 'files with equal names should be compared by extensions');
|
||||
assert(compareFileExtensionsDefault('bbb.aaa', 'aaa.bbb') < 0, 'files should be compared by extension first');
|
||||
assert(compareFileExtensionsDefault('agg.go', 'aggrepo.go') < 0, 'shorter names sort before longer names');
|
||||
assert(compareFileExtensionsDefault('a.MD', 'b.md') < 0, 'when extensions are the same except for case, the files sort by name');
|
||||
|
||||
// dotfile comparisons
|
||||
assert(compareFileExtensionsDefault('.abc', '.abc') === 0, 'equal dotfiles should be equal');
|
||||
assert(compareFileExtensionsDefault('.md', '.Gitattributes') > 0, 'dotfiles sort alphabetically regardless of case');
|
||||
|
||||
// dotfile vs non-dotfile comparisons
|
||||
assert(compareFileExtensionsDefault(null, '.abc') < 0, 'null should come before dotfiles');
|
||||
assert(compareFileExtensionsDefault('.env', 'aaa.env') < 0, 'dotfiles come before filenames with extensions');
|
||||
assert(compareFileExtensionsDefault('.MD', 'a.md') < 0, 'dotfiles sort before lowercase files');
|
||||
|
||||
// numeric comparisons
|
||||
assert(compareFileExtensionsDefault('1', '1') === 0, 'numerically equal full names should be equal');
|
||||
assert(compareFileExtensionsDefault('abc1.txt', 'abc1.txt') === 0, 'equal filenames with numbers should be equal');
|
||||
assert(compareFileExtensionsDefault('abc1.txt', 'abc2.txt') < 0, 'filenames with numbers should be in numerical order, not alphabetical order');
|
||||
assert(compareFileExtensionsDefault('abc2.txt', 'abc10.txt') < 0, 'filenames with numbers should be in numerical order');
|
||||
assert(compareFileExtensionsDefault('abc02.txt', 'abc010.txt') < 0, 'filenames with numbers that have leading zeros sort numerically');
|
||||
assert(compareFileExtensionsDefault('abc1.10.txt', 'abc1.2.txt') > 0, 'numbers with dots between them are treated as two separate numbers, not one decimal number');
|
||||
assert(compareFileExtensionsDefault('abc2.txt2', 'abc1.txt10') < 0, 'extensions with numbers should be in numerical order, not alphabetical order');
|
||||
assert(compareFileExtensionsDefault('txt.abc1', 'txt.abc1') === 0, 'equal extensions with numbers should be equal');
|
||||
assert(compareFileExtensionsDefault('txt.abc1', 'txt.abc2') < 0, 'extensions with numbers should be in numerical order, not alphabetical order');
|
||||
assert(compareFileExtensionsDefault('txt.abc2', 'txt.abc10') < 0, 'extensions with numbers should be in numerical order even when they are multiple digits long');
|
||||
assert(compareFileExtensionsDefault('a.ext1', 'b.ext1') < 0, 'if equal extensions with numbers, filenames should be compared');
|
||||
assert(compareFileExtensionsDefault('a10.txt', 'A2.txt') > 0, 'filenames with number and case differences compare numerically');
|
||||
|
||||
//
|
||||
// Comparisons with different results than compareFileExtensions
|
||||
//
|
||||
|
||||
// name-only comparisons
|
||||
assert(compareFileExtensionsDefault('a', 'A') === compareLocale('a', 'A'), 'the same letter of different case sorts by locale');
|
||||
assert(compareFileExtensionsDefault('â', 'Â') === compareLocale('â', 'Â'), 'the same accented letter of different case sorts by locale');
|
||||
assert.deepEqual(['artichoke', 'Artichoke', 'art', 'Art'].sort(compareFileExtensionsDefault), ['artichoke', 'Artichoke', 'art', 'Art'].sort(compareLocale), 'words with the same root and different cases sort in locale order');
|
||||
assert.deepEqual(['email', 'Email', 'émail', 'Émail'].sort(compareFileExtensionsDefault), ['email', 'Email', 'émail', 'Émail'].sort((a, b) => a.localeCompare(b)), 'the same base characters with different case or accents sort in locale order');
|
||||
|
||||
// name plus extension comparisons
|
||||
assert(compareFileExtensionsDefault('a.MD', 'a.md') === compareLocale('MD', 'md'), 'case differences in extensions sort by locale');
|
||||
assert(compareFileExtensionsDefault('a.md', 'A.md') === compareLocale('a', 'A'), 'case differences in names sort by locale');
|
||||
assert(compareFileExtensionsDefault('aggregate.go', 'aggregate_repo.go') > 0, 'names with the same extension sort in full filename locale order');
|
||||
|
||||
// dotfile comparisons
|
||||
assert(compareFileExtensionsDefault('.env', '.aaa.env') > 0, 'dotfiles sort alphabetically when they contain multiple dots');
|
||||
assert(compareFileExtensionsDefault('.env', '.env.aaa') < 0, 'dotfiles with the same root sort shortest first');
|
||||
|
||||
// dotfile vs non-dotfile comparisons
|
||||
assert(compareFileExtensionsDefault('.env', 'aaa') < 0, 'dotfiles come before filenames without extensions');
|
||||
assert(compareFileExtensionsDefault('.md', 'A.MD') < 0, 'dotfiles sort before uppercase files');
|
||||
|
||||
// numeric comparisons
|
||||
assert(compareFileExtensionsDefault('abc.txt01', 'abc.txt1') > 0, 'extensions with equal numbers should be in shortest-first order');
|
||||
assert(compareFileExtensionsDefault('art01', 'Art01') === compareLocaleNumeric('art01', 'Art01'), 'a numerically equivalent word of a different case compares numerically based on locale');
|
||||
assert(compareFileExtensionsDefault('abc02.txt', 'abc002.txt') < 0, 'filenames with equivalent numbers and leading zeros sort shortest string first');
|
||||
assert(compareFileExtensionsDefault('txt.abc01', 'txt.abc1') > 0, 'extensions with equivalent numbers sort shortest extension first');
|
||||
|
||||
});
|
||||
});
|
||||
131
lib/vscode/src/vs/base/test/browser/dom.test.ts
Normal file
131
lib/vscode/src/vs/base/test/browser/dom.test.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
const $ = dom.$;
|
||||
|
||||
suite('dom', () => {
|
||||
test('hasClass', () => {
|
||||
|
||||
let element = document.createElement('div');
|
||||
element.className = 'foobar boo far';
|
||||
|
||||
assert(element.classList.contains('foobar'));
|
||||
assert(element.classList.contains('boo'));
|
||||
assert(element.classList.contains('far'));
|
||||
assert(!element.classList.contains('bar'));
|
||||
assert(!element.classList.contains('foo'));
|
||||
assert(!element.classList.contains(''));
|
||||
});
|
||||
|
||||
test('removeClass', () => {
|
||||
|
||||
let element = document.createElement('div');
|
||||
element.className = 'foobar boo far';
|
||||
|
||||
element.classList.remove('boo');
|
||||
assert(element.classList.contains('far'));
|
||||
assert(!element.classList.contains('boo'));
|
||||
assert(element.classList.contains('foobar'));
|
||||
assert.equal(element.className, 'foobar far');
|
||||
|
||||
element = document.createElement('div');
|
||||
element.className = 'foobar boo far';
|
||||
|
||||
element.classList.remove('far');
|
||||
assert(!element.classList.contains('far'));
|
||||
assert(element.classList.contains('boo'));
|
||||
assert(element.classList.contains('foobar'));
|
||||
assert.equal(element.className, 'foobar boo');
|
||||
|
||||
element.classList.remove('boo');
|
||||
assert(!element.classList.contains('far'));
|
||||
assert(!element.classList.contains('boo'));
|
||||
assert(element.classList.contains('foobar'));
|
||||
assert.equal(element.className, 'foobar');
|
||||
|
||||
element.classList.remove('foobar');
|
||||
assert(!element.classList.contains('far'));
|
||||
assert(!element.classList.contains('boo'));
|
||||
assert(!element.classList.contains('foobar'));
|
||||
assert.equal(element.className, '');
|
||||
});
|
||||
|
||||
test('removeClass should consider hyphens', function () {
|
||||
let element = document.createElement('div');
|
||||
|
||||
element.classList.add('foo-bar');
|
||||
element.classList.add('bar');
|
||||
|
||||
assert(element.classList.contains('foo-bar'));
|
||||
assert(element.classList.contains('bar'));
|
||||
|
||||
element.classList.remove('bar');
|
||||
assert(element.classList.contains('foo-bar'));
|
||||
assert(!element.classList.contains('bar'));
|
||||
|
||||
element.classList.remove('foo-bar');
|
||||
assert(!element.classList.contains('foo-bar'));
|
||||
assert(!element.classList.contains('bar'));
|
||||
});
|
||||
|
||||
test('multibyteAwareBtoa', () => {
|
||||
assert.equal(dom.multibyteAwareBtoa('hello world'), dom.multibyteAwareBtoa('hello world'));
|
||||
assert.ok(dom.multibyteAwareBtoa('平仮名'));
|
||||
});
|
||||
|
||||
suite('$', () => {
|
||||
test('should build simple nodes', () => {
|
||||
const div = $('div');
|
||||
assert(div);
|
||||
assert(div instanceof HTMLElement);
|
||||
assert.equal(div.tagName, 'DIV');
|
||||
assert(!div.firstChild);
|
||||
});
|
||||
|
||||
test('should buld nodes with id', () => {
|
||||
const div = $('div#foo');
|
||||
assert(div);
|
||||
assert(div instanceof HTMLElement);
|
||||
assert.equal(div.tagName, 'DIV');
|
||||
assert.equal(div.id, 'foo');
|
||||
});
|
||||
|
||||
test('should buld nodes with class-name', () => {
|
||||
const div = $('div.foo');
|
||||
assert(div);
|
||||
assert(div instanceof HTMLElement);
|
||||
assert.equal(div.tagName, 'DIV');
|
||||
assert.equal(div.className, 'foo');
|
||||
});
|
||||
|
||||
test('should build nodes with attributes', () => {
|
||||
let div = $('div', { class: 'test' });
|
||||
assert.equal(div.className, 'test');
|
||||
|
||||
div = $('div', undefined);
|
||||
assert.equal(div.className, '');
|
||||
});
|
||||
|
||||
test('should build nodes with children', () => {
|
||||
let div = $('div', undefined, $('span', { id: 'demospan' }));
|
||||
let firstChild = div.firstChild as HTMLElement;
|
||||
assert.equal(firstChild.tagName, 'SPAN');
|
||||
assert.equal(firstChild.id, 'demospan');
|
||||
|
||||
div = $('div', undefined, 'hello');
|
||||
|
||||
assert.equal(div.firstChild && div.firstChild.textContent, 'hello');
|
||||
});
|
||||
|
||||
test('should build nodes with text children', () => {
|
||||
let div = $('div', undefined, 'foobar');
|
||||
let firstChild = div.firstChild as HTMLElement;
|
||||
assert.equal(firstChild.tagName, undefined);
|
||||
assert.equal(firstChild.textContent, 'foobar');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,104 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { renderText, renderFormattedText } from 'vs/base/browser/formattedTextRenderer';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
|
||||
suite('FormattedTextRenderer', () => {
|
||||
const store = new DisposableStore();
|
||||
|
||||
setup(() => {
|
||||
store.clear();
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
store.clear();
|
||||
});
|
||||
|
||||
test('render simple element', () => {
|
||||
let result: HTMLElement = renderText('testing');
|
||||
|
||||
assert.strictEqual(result.nodeType, document.ELEMENT_NODE);
|
||||
assert.strictEqual(result.textContent, 'testing');
|
||||
assert.strictEqual(result.tagName, 'DIV');
|
||||
});
|
||||
|
||||
test('render element with class', () => {
|
||||
let result: HTMLElement = renderText('testing', {
|
||||
className: 'testClass'
|
||||
});
|
||||
assert.strictEqual(result.nodeType, document.ELEMENT_NODE);
|
||||
assert.strictEqual(result.className, 'testClass');
|
||||
});
|
||||
|
||||
test('simple formatting', () => {
|
||||
let result: HTMLElement = renderFormattedText('**bold**');
|
||||
assert.strictEqual(result.children.length, 1);
|
||||
assert.strictEqual(result.firstChild!.textContent, 'bold');
|
||||
assert.strictEqual((<HTMLElement>result.firstChild).tagName, 'B');
|
||||
assert.strictEqual(result.innerHTML, '<b>bold</b>');
|
||||
|
||||
result = renderFormattedText('__italics__');
|
||||
assert.strictEqual(result.innerHTML, '<i>italics</i>');
|
||||
|
||||
result = renderFormattedText('this string has **bold** and __italics__');
|
||||
assert.strictEqual(result.innerHTML, 'this string has <b>bold</b> and <i>italics</i>');
|
||||
});
|
||||
|
||||
test('no formatting', () => {
|
||||
let result: HTMLElement = renderFormattedText('this is just a string');
|
||||
assert.strictEqual(result.innerHTML, 'this is just a string');
|
||||
});
|
||||
|
||||
test('preserve newlines', () => {
|
||||
let result: HTMLElement = renderFormattedText('line one\nline two');
|
||||
assert.strictEqual(result.innerHTML, 'line one<br>line two');
|
||||
});
|
||||
|
||||
test('action', () => {
|
||||
let callbackCalled = false;
|
||||
let result: HTMLElement = renderFormattedText('[[action]]', {
|
||||
actionHandler: {
|
||||
callback(content) {
|
||||
assert.strictEqual(content, '0');
|
||||
callbackCalled = true;
|
||||
},
|
||||
disposeables: store
|
||||
}
|
||||
});
|
||||
assert.strictEqual(result.innerHTML, '<a href="#">action</a>');
|
||||
|
||||
let event: MouseEvent = <any>document.createEvent('MouseEvent');
|
||||
event.initEvent('click', true, true);
|
||||
result.firstChild!.dispatchEvent(event);
|
||||
assert.strictEqual(callbackCalled, true);
|
||||
});
|
||||
|
||||
test('fancy action', () => {
|
||||
let callbackCalled = false;
|
||||
let result: HTMLElement = renderFormattedText('__**[[action]]**__', {
|
||||
actionHandler: {
|
||||
callback(content) {
|
||||
assert.strictEqual(content, '0');
|
||||
callbackCalled = true;
|
||||
},
|
||||
disposeables: store
|
||||
}
|
||||
});
|
||||
assert.strictEqual(result.innerHTML, '<i><b><a href="#">action</a></b></i>');
|
||||
|
||||
let event: MouseEvent = <any>document.createEvent('MouseEvent');
|
||||
event.initEvent('click', true, true);
|
||||
result.firstChild!.firstChild!.firstChild!.dispatchEvent(event);
|
||||
assert.strictEqual(callbackCalled, true);
|
||||
});
|
||||
|
||||
test('escaped formatting', () => {
|
||||
let result: HTMLElement = renderFormattedText('\\*\\*bold\\*\\*');
|
||||
assert.strictEqual(result.children.length, 0);
|
||||
assert.strictEqual(result.innerHTML, '**bold**');
|
||||
});
|
||||
});
|
||||
62
lib/vscode/src/vs/base/test/browser/highlightedLabel.test.ts
Normal file
62
lib/vscode/src/vs/base/test/browser/highlightedLabel.test.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as assert from 'assert';
|
||||
import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';
|
||||
|
||||
suite('HighlightedLabel', () => {
|
||||
let label: HighlightedLabel;
|
||||
|
||||
setup(() => {
|
||||
label = new HighlightedLabel(document.createElement('div'), true);
|
||||
});
|
||||
|
||||
test('empty label', function () {
|
||||
assert.equal(label.element.innerHTML, '');
|
||||
});
|
||||
|
||||
test('no decorations', function () {
|
||||
label.set('hello');
|
||||
assert.equal(label.element.innerHTML, '<span>hello</span>');
|
||||
});
|
||||
|
||||
test('escape html', function () {
|
||||
label.set('hel<lo');
|
||||
assert.equal(label.element.innerHTML, '<span>hel<lo</span>');
|
||||
});
|
||||
|
||||
test('everything highlighted', function () {
|
||||
label.set('hello', [{ start: 0, end: 5 }]);
|
||||
assert.equal(label.element.innerHTML, '<span class="highlight">hello</span>');
|
||||
});
|
||||
|
||||
test('beginning highlighted', function () {
|
||||
label.set('hellothere', [{ start: 0, end: 5 }]);
|
||||
assert.equal(label.element.innerHTML, '<span class="highlight">hello</span><span>there</span>');
|
||||
});
|
||||
|
||||
test('ending highlighted', function () {
|
||||
label.set('goodbye', [{ start: 4, end: 7 }]);
|
||||
assert.equal(label.element.innerHTML, '<span>good</span><span class="highlight">bye</span>');
|
||||
});
|
||||
|
||||
test('middle highlighted', function () {
|
||||
label.set('foobarfoo', [{ start: 3, end: 6 }]);
|
||||
assert.equal(label.element.innerHTML, '<span>foo</span><span class="highlight">bar</span><span>foo</span>');
|
||||
});
|
||||
|
||||
test('escapeNewLines', () => {
|
||||
|
||||
let highlights = [{ start: 0, end: 5 }, { start: 7, end: 9 }, { start: 11, end: 12 }];// before,after,after
|
||||
let escaped = HighlightedLabel.escapeNewLines('ACTION\r\n_TYPE2', highlights);
|
||||
assert.equal(escaped, 'ACTION\u23CE_TYPE2');
|
||||
assert.deepEqual(highlights, [{ start: 0, end: 5 }, { start: 6, end: 8 }, { start: 10, end: 11 }]);
|
||||
|
||||
highlights = [{ start: 5, end: 9 }, { start: 11, end: 12 }];//overlap,after
|
||||
escaped = HighlightedLabel.escapeNewLines('ACTION\r\n_TYPE2', highlights);
|
||||
assert.equal(escaped, 'ACTION\u23CE_TYPE2');
|
||||
assert.deepEqual(highlights, [{ start: 5, end: 8 }, { start: 10, end: 11 }]);
|
||||
|
||||
});
|
||||
});
|
||||
118
lib/vscode/src/vs/base/test/browser/markdownRenderer.test.ts
Normal file
118
lib/vscode/src/vs/base/test/browser/markdownRenderer.test.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import * as marked from 'vs/base/common/marked/marked';
|
||||
import { renderMarkdown } from 'vs/base/browser/markdownRenderer';
|
||||
import { MarkdownString, IMarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { parse } from 'vs/base/common/marshalling';
|
||||
|
||||
suite('MarkdownRenderer', () => {
|
||||
suite('Images', () => {
|
||||
|
||||
test('image rendering conforms to default', () => {
|
||||
const markdown = { value: `` };
|
||||
const result: HTMLElement = renderMarkdown(markdown);
|
||||
const renderer = new marked.Renderer();
|
||||
const imageFromMarked = marked(markdown.value, {
|
||||
renderer
|
||||
}).trim();
|
||||
assert.strictEqual(result.innerHTML, imageFromMarked);
|
||||
});
|
||||
|
||||
test('image rendering conforms to default without title', () => {
|
||||
const markdown = { value: `` };
|
||||
const result: HTMLElement = renderMarkdown(markdown);
|
||||
const renderer = new marked.Renderer();
|
||||
const imageFromMarked = marked(markdown.value, {
|
||||
renderer
|
||||
}).trim();
|
||||
assert.strictEqual(result.innerHTML, imageFromMarked);
|
||||
});
|
||||
|
||||
test('image width from title params', () => {
|
||||
let result: HTMLElement = renderMarkdown({ value: `` });
|
||||
assert.strictEqual(result.innerHTML, `<p><img src="someimageurl" alt="image" title="caption" width="100"></p>`);
|
||||
});
|
||||
|
||||
test('image height from title params', () => {
|
||||
let result: HTMLElement = renderMarkdown({ value: `` });
|
||||
assert.strictEqual(result.innerHTML, `<p><img src="someimageurl" alt="image" title="caption" height="100"></p>`);
|
||||
});
|
||||
|
||||
test('image width and height from title params', () => {
|
||||
let result: HTMLElement = renderMarkdown({ value: `` });
|
||||
assert.strictEqual(result.innerHTML, `<p><img src="someimageurl" alt="image" title="caption" width="100" height="200"></p>`);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
suite('ThemeIcons Support On', () => {
|
||||
|
||||
test('render appendText', () => {
|
||||
const mds = new MarkdownString(undefined, { supportThemeIcons: true });
|
||||
mds.appendText('$(zap) $(not a theme icon) $(add)');
|
||||
|
||||
let result: HTMLElement = renderMarkdown(mds);
|
||||
assert.strictEqual(result.innerHTML, `<p>$(zap) $(not a theme icon) $(add)</p>`);
|
||||
});
|
||||
|
||||
test('render appendMarkdown', () => {
|
||||
const mds = new MarkdownString(undefined, { supportThemeIcons: true });
|
||||
mds.appendMarkdown('$(zap) $(not a theme icon) $(add)');
|
||||
|
||||
let result: HTMLElement = renderMarkdown(mds);
|
||||
assert.strictEqual(result.innerHTML, `<p><span class="codicon codicon-zap"></span> $(not a theme icon) <span class="codicon codicon-add"></span></p>`);
|
||||
});
|
||||
|
||||
test('render appendMarkdown with escaped icon', () => {
|
||||
const mds = new MarkdownString(undefined, { supportThemeIcons: true });
|
||||
mds.appendMarkdown('\\$(zap) $(not a theme icon) $(add)');
|
||||
|
||||
let result: HTMLElement = renderMarkdown(mds);
|
||||
assert.strictEqual(result.innerHTML, `<p>$(zap) $(not a theme icon) <span class="codicon codicon-add"></span></p>`);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
suite('ThemeIcons Support Off', () => {
|
||||
|
||||
test('render appendText', () => {
|
||||
const mds = new MarkdownString(undefined, { supportThemeIcons: false });
|
||||
mds.appendText('$(zap) $(not a theme icon) $(add)');
|
||||
|
||||
let result: HTMLElement = renderMarkdown(mds);
|
||||
assert.strictEqual(result.innerHTML, `<p>$(zap) $(not a theme icon) $(add)</p>`);
|
||||
});
|
||||
|
||||
test('render appendMarkdown with escaped icon', () => {
|
||||
const mds = new MarkdownString(undefined, { supportThemeIcons: false });
|
||||
mds.appendMarkdown('\\$(zap) $(not a theme icon) $(add)');
|
||||
|
||||
let result: HTMLElement = renderMarkdown(mds);
|
||||
assert.strictEqual(result.innerHTML, `<p>$(zap) $(not a theme icon) $(add)</p>`);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
test('npm Hover Run Script not working #90855', function () {
|
||||
|
||||
const md: IMarkdownString = JSON.parse('{"value":"[Run Script](command:npm.runScriptFromHover?%7B%22documentUri%22%3A%7B%22%24mid%22%3A1%2C%22fsPath%22%3A%22c%3A%5C%5CUsers%5C%5Cjrieken%5C%5CCode%5C%5C_sample%5C%5Cfoo%5C%5Cpackage.json%22%2C%22_sep%22%3A1%2C%22external%22%3A%22file%3A%2F%2F%2Fc%253A%2FUsers%2Fjrieken%2FCode%2F_sample%2Ffoo%2Fpackage.json%22%2C%22path%22%3A%22%2Fc%3A%2FUsers%2Fjrieken%2FCode%2F_sample%2Ffoo%2Fpackage.json%22%2C%22scheme%22%3A%22file%22%7D%2C%22script%22%3A%22echo%22%7D \\"Run the script as a task\\")","supportThemeIcons":false,"isTrusted":true,"uris":{"__uri_e49443":{"$mid":1,"fsPath":"c:\\\\Users\\\\jrieken\\\\Code\\\\_sample\\\\foo\\\\package.json","_sep":1,"external":"file:///c%3A/Users/jrieken/Code/_sample/foo/package.json","path":"/c:/Users/jrieken/Code/_sample/foo/package.json","scheme":"file"},"command:npm.runScriptFromHover?%7B%22documentUri%22%3A%7B%22%24mid%22%3A1%2C%22fsPath%22%3A%22c%3A%5C%5CUsers%5C%5Cjrieken%5C%5CCode%5C%5C_sample%5C%5Cfoo%5C%5Cpackage.json%22%2C%22_sep%22%3A1%2C%22external%22%3A%22file%3A%2F%2F%2Fc%253A%2FUsers%2Fjrieken%2FCode%2F_sample%2Ffoo%2Fpackage.json%22%2C%22path%22%3A%22%2Fc%3A%2FUsers%2Fjrieken%2FCode%2F_sample%2Ffoo%2Fpackage.json%22%2C%22scheme%22%3A%22file%22%7D%2C%22script%22%3A%22echo%22%7D":{"$mid":1,"path":"npm.runScriptFromHover","scheme":"command","query":"{\\"documentUri\\":\\"__uri_e49443\\",\\"script\\":\\"echo\\"}"}}}');
|
||||
const element = renderMarkdown(md);
|
||||
|
||||
const anchor = element.querySelector('a')!;
|
||||
assert.ok(anchor);
|
||||
assert.ok(anchor.dataset['href']);
|
||||
|
||||
const uri = URI.parse(anchor.dataset['href']!);
|
||||
|
||||
const data = <{ script: string, documentUri: URI }>parse(decodeURIComponent(uri.query));
|
||||
assert.ok(data);
|
||||
assert.equal(data.script, 'echo');
|
||||
assert.ok(data.documentUri.toString().startsWith('file:///c%3A/'));
|
||||
});
|
||||
|
||||
});
|
||||
32
lib/vscode/src/vs/base/test/browser/progressBar.test.ts
Normal file
32
lib/vscode/src/vs/base/test/browser/progressBar.test.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar';
|
||||
|
||||
suite('ProgressBar', () => {
|
||||
let fixture: HTMLElement;
|
||||
|
||||
setup(() => {
|
||||
fixture = document.createElement('div');
|
||||
document.body.appendChild(fixture);
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
document.body.removeChild(fixture);
|
||||
});
|
||||
|
||||
test('Progress Bar', function () {
|
||||
const bar = new ProgressBar(fixture);
|
||||
assert(bar.infinite());
|
||||
assert(bar.total(100));
|
||||
assert(bar.worked(50));
|
||||
assert(bar.setWorked(70));
|
||||
assert(bar.worked(30));
|
||||
assert(bar.done());
|
||||
|
||||
bar.dispose();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,28 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { layout, LayoutAnchorPosition } from 'vs/base/browser/ui/contextview/contextview';
|
||||
|
||||
suite('Contextview', function () {
|
||||
|
||||
test('layout', () => {
|
||||
assert.equal(layout(200, 20, { offset: 0, size: 0, position: LayoutAnchorPosition.Before }), 0);
|
||||
assert.equal(layout(200, 20, { offset: 50, size: 0, position: LayoutAnchorPosition.Before }), 50);
|
||||
assert.equal(layout(200, 20, { offset: 200, size: 0, position: LayoutAnchorPosition.Before }), 180);
|
||||
|
||||
assert.equal(layout(200, 20, { offset: 0, size: 0, position: LayoutAnchorPosition.After }), 0);
|
||||
assert.equal(layout(200, 20, { offset: 50, size: 0, position: LayoutAnchorPosition.After }), 30);
|
||||
assert.equal(layout(200, 20, { offset: 200, size: 0, position: LayoutAnchorPosition.After }), 180);
|
||||
|
||||
assert.equal(layout(200, 20, { offset: 0, size: 50, position: LayoutAnchorPosition.Before }), 50);
|
||||
assert.equal(layout(200, 20, { offset: 50, size: 50, position: LayoutAnchorPosition.Before }), 100);
|
||||
assert.equal(layout(200, 20, { offset: 150, size: 50, position: LayoutAnchorPosition.Before }), 130);
|
||||
|
||||
assert.equal(layout(200, 20, { offset: 0, size: 50, position: LayoutAnchorPosition.After }), 50);
|
||||
assert.equal(layout(200, 20, { offset: 50, size: 50, position: LayoutAnchorPosition.After }), 30);
|
||||
assert.equal(layout(200, 20, { offset: 150, size: 50, position: LayoutAnchorPosition.After }), 130);
|
||||
});
|
||||
});
|
||||
1080
lib/vscode/src/vs/base/test/browser/ui/grid/grid.test.ts
Normal file
1080
lib/vscode/src/vs/base/test/browser/ui/grid/grid.test.ts
Normal file
File diff suppressed because it is too large
Load Diff
225
lib/vscode/src/vs/base/test/browser/ui/grid/gridview.test.ts
Normal file
225
lib/vscode/src/vs/base/test/browser/ui/grid/gridview.test.ts
Normal file
@@ -0,0 +1,225 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { $ } from 'vs/base/browser/dom';
|
||||
import { GridView, IView, Sizing } from 'vs/base/browser/ui/grid/gridview';
|
||||
import { nodesToArrays, TestView } from './util';
|
||||
|
||||
suite('Gridview', function () {
|
||||
let gridview: GridView;
|
||||
|
||||
setup(function () {
|
||||
gridview = new GridView();
|
||||
const container = $('.container');
|
||||
|
||||
container.style.position = 'absolute';
|
||||
container.style.width = `${200}px`;
|
||||
container.style.height = `${200}px`;
|
||||
container.appendChild(gridview.element);
|
||||
});
|
||||
|
||||
test('empty gridview is empty', function () {
|
||||
assert.deepEqual(nodesToArrays(gridview.getView()), []);
|
||||
gridview.dispose();
|
||||
});
|
||||
|
||||
test('gridview addView', function () {
|
||||
|
||||
const view = new TestView(20, 20, 20, 20);
|
||||
assert.throws(() => gridview.addView(view, 200, []), 'empty location');
|
||||
assert.throws(() => gridview.addView(view, 200, [1]), 'index overflow');
|
||||
assert.throws(() => gridview.addView(view, 200, [0, 0]), 'hierarchy overflow');
|
||||
|
||||
const views = [
|
||||
new TestView(20, 20, 20, 20),
|
||||
new TestView(20, 20, 20, 20),
|
||||
new TestView(20, 20, 20, 20)
|
||||
];
|
||||
|
||||
gridview.addView(views[0], 200, [0]);
|
||||
gridview.addView(views[1], 200, [1]);
|
||||
gridview.addView(views[2], 200, [2]);
|
||||
|
||||
assert.deepEqual(nodesToArrays(gridview.getView()), views);
|
||||
|
||||
gridview.dispose();
|
||||
});
|
||||
|
||||
test('gridview addView nested', function () {
|
||||
|
||||
const views = [
|
||||
new TestView(20, 20, 20, 20),
|
||||
[
|
||||
new TestView(20, 20, 20, 20),
|
||||
new TestView(20, 20, 20, 20)
|
||||
]
|
||||
];
|
||||
|
||||
gridview.addView(views[0] as IView, 200, [0]);
|
||||
gridview.addView((views[1] as TestView[])[0] as IView, 200, [1]);
|
||||
gridview.addView((views[1] as TestView[])[1] as IView, 200, [1, 1]);
|
||||
|
||||
assert.deepEqual(nodesToArrays(gridview.getView()), views);
|
||||
|
||||
gridview.dispose();
|
||||
});
|
||||
|
||||
test('gridview addView deep nested', function () {
|
||||
|
||||
const view1 = new TestView(20, 20, 20, 20);
|
||||
gridview.addView(view1 as IView, 200, [0]);
|
||||
assert.deepEqual(nodesToArrays(gridview.getView()), [view1]);
|
||||
|
||||
const view2 = new TestView(20, 20, 20, 20);
|
||||
gridview.addView(view2 as IView, 200, [1]);
|
||||
assert.deepEqual(nodesToArrays(gridview.getView()), [view1, view2]);
|
||||
|
||||
const view3 = new TestView(20, 20, 20, 20);
|
||||
gridview.addView(view3 as IView, 200, [1, 0]);
|
||||
assert.deepEqual(nodesToArrays(gridview.getView()), [view1, [view3, view2]]);
|
||||
|
||||
const view4 = new TestView(20, 20, 20, 20);
|
||||
gridview.addView(view4 as IView, 200, [1, 0, 0]);
|
||||
assert.deepEqual(nodesToArrays(gridview.getView()), [view1, [[view4, view3], view2]]);
|
||||
|
||||
const view5 = new TestView(20, 20, 20, 20);
|
||||
gridview.addView(view5 as IView, 200, [1, 0]);
|
||||
assert.deepEqual(nodesToArrays(gridview.getView()), [view1, [view5, [view4, view3], view2]]);
|
||||
|
||||
const view6 = new TestView(20, 20, 20, 20);
|
||||
gridview.addView(view6 as IView, 200, [2]);
|
||||
assert.deepEqual(nodesToArrays(gridview.getView()), [view1, [view5, [view4, view3], view2], view6]);
|
||||
|
||||
const view7 = new TestView(20, 20, 20, 20);
|
||||
gridview.addView(view7 as IView, 200, [1, 1]);
|
||||
assert.deepEqual(nodesToArrays(gridview.getView()), [view1, [view5, view7, [view4, view3], view2], view6]);
|
||||
|
||||
const view8 = new TestView(20, 20, 20, 20);
|
||||
gridview.addView(view8 as IView, 200, [1, 1, 0]);
|
||||
assert.deepEqual(nodesToArrays(gridview.getView()), [view1, [view5, [view8, view7], [view4, view3], view2], view6]);
|
||||
|
||||
gridview.dispose();
|
||||
});
|
||||
|
||||
test('simple layout', function () {
|
||||
gridview.layout(800, 600);
|
||||
|
||||
const view1 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
|
||||
gridview.addView(view1, 200, [0]);
|
||||
assert.deepEqual(view1.size, [800, 600]);
|
||||
assert.deepEqual(gridview.getViewSize([0]), { width: 800, height: 600 });
|
||||
|
||||
const view2 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
|
||||
gridview.addView(view2, 200, [0]);
|
||||
assert.deepEqual(view1.size, [800, 400]);
|
||||
assert.deepEqual(gridview.getViewSize([1]), { width: 800, height: 400 });
|
||||
assert.deepEqual(view2.size, [800, 200]);
|
||||
assert.deepEqual(gridview.getViewSize([0]), { width: 800, height: 200 });
|
||||
|
||||
const view3 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
|
||||
gridview.addView(view3, 200, [1, 1]);
|
||||
assert.deepEqual(view1.size, [600, 400]);
|
||||
assert.deepEqual(gridview.getViewSize([1, 0]), { width: 600, height: 400 });
|
||||
assert.deepEqual(view2.size, [800, 200]);
|
||||
assert.deepEqual(gridview.getViewSize([0]), { width: 800, height: 200 });
|
||||
assert.deepEqual(view3.size, [200, 400]);
|
||||
assert.deepEqual(gridview.getViewSize([1, 1]), { width: 200, height: 400 });
|
||||
|
||||
const view4 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
|
||||
gridview.addView(view4, 200, [0, 0]);
|
||||
assert.deepEqual(view1.size, [600, 400]);
|
||||
assert.deepEqual(gridview.getViewSize([1, 0]), { width: 600, height: 400 });
|
||||
assert.deepEqual(view2.size, [600, 200]);
|
||||
assert.deepEqual(gridview.getViewSize([0, 1]), { width: 600, height: 200 });
|
||||
assert.deepEqual(view3.size, [200, 400]);
|
||||
assert.deepEqual(gridview.getViewSize([1, 1]), { width: 200, height: 400 });
|
||||
assert.deepEqual(view4.size, [200, 200]);
|
||||
assert.deepEqual(gridview.getViewSize([0, 0]), { width: 200, height: 200 });
|
||||
|
||||
const view5 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
|
||||
gridview.addView(view5, 100, [1, 0, 1]);
|
||||
assert.deepEqual(view1.size, [600, 300]);
|
||||
assert.deepEqual(gridview.getViewSize([1, 0, 0]), { width: 600, height: 300 });
|
||||
assert.deepEqual(view2.size, [600, 200]);
|
||||
assert.deepEqual(gridview.getViewSize([0, 1]), { width: 600, height: 200 });
|
||||
assert.deepEqual(view3.size, [200, 400]);
|
||||
assert.deepEqual(gridview.getViewSize([1, 1]), { width: 200, height: 400 });
|
||||
assert.deepEqual(view4.size, [200, 200]);
|
||||
assert.deepEqual(gridview.getViewSize([0, 0]), { width: 200, height: 200 });
|
||||
assert.deepEqual(view5.size, [600, 100]);
|
||||
assert.deepEqual(gridview.getViewSize([1, 0, 1]), { width: 600, height: 100 });
|
||||
});
|
||||
|
||||
test('simple layout with automatic size distribution', function () {
|
||||
gridview.layout(800, 600);
|
||||
|
||||
const view1 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
|
||||
gridview.addView(view1, Sizing.Distribute, [0]);
|
||||
assert.deepEqual(view1.size, [800, 600]);
|
||||
assert.deepEqual(gridview.getViewSize([0]), { width: 800, height: 600 });
|
||||
|
||||
const view2 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
|
||||
gridview.addView(view2, Sizing.Distribute, [0]);
|
||||
assert.deepEqual(view1.size, [800, 300]);
|
||||
assert.deepEqual(view2.size, [800, 300]);
|
||||
|
||||
const view3 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
|
||||
gridview.addView(view3, Sizing.Distribute, [1, 1]);
|
||||
assert.deepEqual(view1.size, [400, 300]);
|
||||
assert.deepEqual(view2.size, [800, 300]);
|
||||
assert.deepEqual(view3.size, [400, 300]);
|
||||
|
||||
const view4 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
|
||||
gridview.addView(view4, Sizing.Distribute, [0, 0]);
|
||||
assert.deepEqual(view1.size, [400, 300]);
|
||||
assert.deepEqual(view2.size, [400, 300]);
|
||||
assert.deepEqual(view3.size, [400, 300]);
|
||||
assert.deepEqual(view4.size, [400, 300]);
|
||||
|
||||
const view5 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
|
||||
gridview.addView(view5, Sizing.Distribute, [1, 0, 1]);
|
||||
assert.deepEqual(view1.size, [400, 150]);
|
||||
assert.deepEqual(view2.size, [400, 300]);
|
||||
assert.deepEqual(view3.size, [400, 300]);
|
||||
assert.deepEqual(view4.size, [400, 300]);
|
||||
assert.deepEqual(view5.size, [400, 150]);
|
||||
});
|
||||
|
||||
test('addviews before layout call 1', function () {
|
||||
|
||||
const view1 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
|
||||
gridview.addView(view1, 200, [0]);
|
||||
|
||||
const view2 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
|
||||
gridview.addView(view2, 200, [0]);
|
||||
|
||||
const view3 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
|
||||
gridview.addView(view3, 200, [1, 1]);
|
||||
|
||||
gridview.layout(800, 600);
|
||||
|
||||
assert.deepEqual(view1.size, [400, 300]);
|
||||
assert.deepEqual(view2.size, [800, 300]);
|
||||
assert.deepEqual(view3.size, [400, 300]);
|
||||
});
|
||||
|
||||
test('addviews before layout call 2', function () {
|
||||
const view1 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
|
||||
gridview.addView(view1, 200, [0]);
|
||||
|
||||
const view2 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
|
||||
gridview.addView(view2, 200, [0]);
|
||||
|
||||
const view3 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY);
|
||||
gridview.addView(view3, 200, [0, 0]);
|
||||
|
||||
gridview.layout(800, 600);
|
||||
|
||||
assert.deepEqual(view1.size, [800, 300]);
|
||||
assert.deepEqual(view2.size, [400, 300]);
|
||||
assert.deepEqual(view3.size, [400, 300]);
|
||||
});
|
||||
});
|
||||
82
lib/vscode/src/vs/base/test/browser/ui/grid/util.ts
Normal file
82
lib/vscode/src/vs/base/test/browser/ui/grid/util.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { GridNode, isGridBranchNode } from 'vs/base/browser/ui/grid/gridview';
|
||||
import { IView } from 'vs/base/browser/ui/grid/grid';
|
||||
|
||||
export class TestView implements IView {
|
||||
|
||||
private readonly _onDidChange = new Emitter<{ width: number; height: number; } | undefined>();
|
||||
readonly onDidChange = this._onDidChange.event;
|
||||
|
||||
get minimumWidth(): number { return this._minimumWidth; }
|
||||
set minimumWidth(size: number) { this._minimumWidth = size; this._onDidChange.fire(undefined); }
|
||||
|
||||
get maximumWidth(): number { return this._maximumWidth; }
|
||||
set maximumWidth(size: number) { this._maximumWidth = size; this._onDidChange.fire(undefined); }
|
||||
|
||||
get minimumHeight(): number { return this._minimumHeight; }
|
||||
set minimumHeight(size: number) { this._minimumHeight = size; this._onDidChange.fire(undefined); }
|
||||
|
||||
get maximumHeight(): number { return this._maximumHeight; }
|
||||
set maximumHeight(size: number) { this._maximumHeight = size; this._onDidChange.fire(undefined); }
|
||||
|
||||
private _element: HTMLElement = document.createElement('div');
|
||||
get element(): HTMLElement { this._onDidGetElement.fire(); return this._element; }
|
||||
|
||||
private readonly _onDidGetElement = new Emitter<void>();
|
||||
readonly onDidGetElement = this._onDidGetElement.event;
|
||||
|
||||
private _width = 0;
|
||||
get width(): number { return this._width; }
|
||||
|
||||
private _height = 0;
|
||||
get height(): number { return this._height; }
|
||||
|
||||
get size(): [number, number] { return [this.width, this.height]; }
|
||||
|
||||
private readonly _onDidLayout = new Emitter<{ width: number; height: number; }>();
|
||||
readonly onDidLayout: Event<{ width: number; height: number; }> = this._onDidLayout.event;
|
||||
|
||||
private readonly _onDidFocus = new Emitter<void>();
|
||||
readonly onDidFocus: Event<void> = this._onDidFocus.event;
|
||||
|
||||
constructor(
|
||||
private _minimumWidth: number,
|
||||
private _maximumWidth: number,
|
||||
private _minimumHeight: number,
|
||||
private _maximumHeight: number
|
||||
) {
|
||||
assert(_minimumWidth <= _maximumWidth, 'gridview view minimum width must be <= maximum width');
|
||||
assert(_minimumHeight <= _maximumHeight, 'gridview view minimum height must be <= maximum height');
|
||||
}
|
||||
|
||||
layout(width: number, height: number): void {
|
||||
this._width = width;
|
||||
this._height = height;
|
||||
this._onDidLayout.fire({ width, height });
|
||||
}
|
||||
|
||||
focus(): void {
|
||||
this._onDidFocus.fire();
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._onDidChange.dispose();
|
||||
this._onDidGetElement.dispose();
|
||||
this._onDidLayout.dispose();
|
||||
this._onDidFocus.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
export function nodesToArrays(node: GridNode): any {
|
||||
if (isGridBranchNode(node)) {
|
||||
return node.children.map(nodesToArrays);
|
||||
} else {
|
||||
return node.view;
|
||||
}
|
||||
}
|
||||
40
lib/vscode/src/vs/base/test/browser/ui/list/listView.test.ts
Normal file
40
lib/vscode/src/vs/base/test/browser/ui/list/listView.test.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { ListView } from 'vs/base/browser/ui/list/listView';
|
||||
import { IListVirtualDelegate, IListRenderer } from 'vs/base/browser/ui/list/list';
|
||||
import { range } from 'vs/base/common/arrays';
|
||||
|
||||
suite('ListView', function () {
|
||||
test('all rows get disposed', function () {
|
||||
const element = document.createElement('div');
|
||||
element.style.height = '200px';
|
||||
element.style.width = '200px';
|
||||
|
||||
const delegate: IListVirtualDelegate<number> = {
|
||||
getHeight() { return 20; },
|
||||
getTemplateId() { return 'template'; }
|
||||
};
|
||||
|
||||
let templatesCount = 0;
|
||||
|
||||
const renderer: IListRenderer<number, void> = {
|
||||
templateId: 'template',
|
||||
renderTemplate() { templatesCount++; },
|
||||
renderElement() { },
|
||||
disposeTemplate() { templatesCount--; }
|
||||
};
|
||||
|
||||
const listView = new ListView<number>(element, delegate, [renderer]);
|
||||
listView.layout(200);
|
||||
|
||||
assert.equal(templatesCount, 0, 'no templates have been allocated');
|
||||
listView.splice(0, 0, range(100));
|
||||
assert.equal(templatesCount, 10, 'some templates have been allocated');
|
||||
listView.dispose();
|
||||
assert.equal(templatesCount, 0, 'all templates have been disposed');
|
||||
});
|
||||
});
|
||||
345
lib/vscode/src/vs/base/test/browser/ui/list/rangeMap.test.ts
Normal file
345
lib/vscode/src/vs/base/test/browser/ui/list/rangeMap.test.ts
Normal file
@@ -0,0 +1,345 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { RangeMap, groupIntersect, consolidate } from 'vs/base/browser/ui/list/rangeMap';
|
||||
import { Range } from 'vs/base/common/range';
|
||||
|
||||
suite('RangeMap', () => {
|
||||
let rangeMap: RangeMap;
|
||||
|
||||
setup(() => {
|
||||
rangeMap = new RangeMap();
|
||||
});
|
||||
|
||||
test('intersection', () => {
|
||||
assert.deepEqual(Range.intersect({ start: 0, end: 0 }, { start: 0, end: 0 }), { start: 0, end: 0 });
|
||||
assert.deepEqual(Range.intersect({ start: 0, end: 0 }, { start: 5, end: 5 }), { start: 0, end: 0 });
|
||||
assert.deepEqual(Range.intersect({ start: 0, end: 1 }, { start: 5, end: 6 }), { start: 0, end: 0 });
|
||||
assert.deepEqual(Range.intersect({ start: 5, end: 6 }, { start: 0, end: 1 }), { start: 0, end: 0 });
|
||||
assert.deepEqual(Range.intersect({ start: 0, end: 5 }, { start: 2, end: 2 }), { start: 0, end: 0 });
|
||||
assert.deepEqual(Range.intersect({ start: 0, end: 1 }, { start: 0, end: 1 }), { start: 0, end: 1 });
|
||||
assert.deepEqual(Range.intersect({ start: 0, end: 10 }, { start: 0, end: 5 }), { start: 0, end: 5 });
|
||||
assert.deepEqual(Range.intersect({ start: 0, end: 5 }, { start: 0, end: 10 }), { start: 0, end: 5 });
|
||||
assert.deepEqual(Range.intersect({ start: 0, end: 10 }, { start: 5, end: 10 }), { start: 5, end: 10 });
|
||||
assert.deepEqual(Range.intersect({ start: 5, end: 10 }, { start: 0, end: 10 }), { start: 5, end: 10 });
|
||||
assert.deepEqual(Range.intersect({ start: 0, end: 10 }, { start: 2, end: 8 }), { start: 2, end: 8 });
|
||||
assert.deepEqual(Range.intersect({ start: 2, end: 8 }, { start: 0, end: 10 }), { start: 2, end: 8 });
|
||||
assert.deepEqual(Range.intersect({ start: 0, end: 10 }, { start: 5, end: 15 }), { start: 5, end: 10 });
|
||||
assert.deepEqual(Range.intersect({ start: 5, end: 15 }, { start: 0, end: 10 }), { start: 5, end: 10 });
|
||||
});
|
||||
|
||||
test('multiIntersect', () => {
|
||||
assert.deepEqual(
|
||||
groupIntersect(
|
||||
{ start: 0, end: 0 },
|
||||
[{ range: { start: 0, end: 10 }, size: 1 }]
|
||||
),
|
||||
[]
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
groupIntersect(
|
||||
{ start: 10, end: 20 },
|
||||
[{ range: { start: 0, end: 10 }, size: 1 }]
|
||||
),
|
||||
[]
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
groupIntersect(
|
||||
{ start: 2, end: 8 },
|
||||
[{ range: { start: 0, end: 10 }, size: 1 }]
|
||||
),
|
||||
[{ range: { start: 2, end: 8 }, size: 1 }]
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
groupIntersect(
|
||||
{ start: 2, end: 8 },
|
||||
[{ range: { start: 0, end: 10 }, size: 1 }, { range: { start: 10, end: 20 }, size: 5 }]
|
||||
),
|
||||
[{ range: { start: 2, end: 8 }, size: 1 }]
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
groupIntersect(
|
||||
{ start: 12, end: 18 },
|
||||
[{ range: { start: 0, end: 10 }, size: 1 }, { range: { start: 10, end: 20 }, size: 5 }]
|
||||
),
|
||||
[{ range: { start: 12, end: 18 }, size: 5 }]
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
groupIntersect(
|
||||
{ start: 2, end: 18 },
|
||||
[{ range: { start: 0, end: 10 }, size: 1 }, { range: { start: 10, end: 20 }, size: 5 }]
|
||||
),
|
||||
[{ range: { start: 2, end: 10 }, size: 1 }, { range: { start: 10, end: 18 }, size: 5 }]
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
groupIntersect(
|
||||
{ start: 2, end: 28 },
|
||||
[{ range: { start: 0, end: 10 }, size: 1 }, { range: { start: 10, end: 20 }, size: 5 }, { range: { start: 20, end: 30 }, size: 10 }]
|
||||
),
|
||||
[{ range: { start: 2, end: 10 }, size: 1 }, { range: { start: 10, end: 20 }, size: 5 }, { range: { start: 20, end: 28 }, size: 10 }]
|
||||
);
|
||||
});
|
||||
|
||||
test('consolidate', () => {
|
||||
assert.deepEqual(consolidate([]), []);
|
||||
|
||||
assert.deepEqual(
|
||||
consolidate([{ range: { start: 0, end: 10 }, size: 1 }]),
|
||||
[{ range: { start: 0, end: 10 }, size: 1 }]
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
consolidate([
|
||||
{ range: { start: 0, end: 10 }, size: 1 },
|
||||
{ range: { start: 10, end: 20 }, size: 1 }
|
||||
]),
|
||||
[{ range: { start: 0, end: 20 }, size: 1 }]
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
consolidate([
|
||||
{ range: { start: 0, end: 10 }, size: 1 },
|
||||
{ range: { start: 10, end: 20 }, size: 1 },
|
||||
{ range: { start: 20, end: 100 }, size: 1 }
|
||||
]),
|
||||
[{ range: { start: 0, end: 100 }, size: 1 }]
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
consolidate([
|
||||
{ range: { start: 0, end: 10 }, size: 1 },
|
||||
{ range: { start: 10, end: 20 }, size: 5 },
|
||||
{ range: { start: 20, end: 30 }, size: 10 }
|
||||
]),
|
||||
[
|
||||
{ range: { start: 0, end: 10 }, size: 1 },
|
||||
{ range: { start: 10, end: 20 }, size: 5 },
|
||||
{ range: { start: 20, end: 30 }, size: 10 }
|
||||
]
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
consolidate([
|
||||
{ range: { start: 0, end: 10 }, size: 1 },
|
||||
{ range: { start: 10, end: 20 }, size: 2 },
|
||||
{ range: { start: 20, end: 100 }, size: 2 }
|
||||
]),
|
||||
[
|
||||
{ range: { start: 0, end: 10 }, size: 1 },
|
||||
{ range: { start: 10, end: 100 }, size: 2 }
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
test('empty', () => {
|
||||
assert.equal(rangeMap.size, 0);
|
||||
assert.equal(rangeMap.count, 0);
|
||||
});
|
||||
|
||||
const one = { size: 1 };
|
||||
const two = { size: 2 };
|
||||
const three = { size: 3 };
|
||||
const five = { size: 5 };
|
||||
const ten = { size: 10 };
|
||||
|
||||
test('length & count', () => {
|
||||
rangeMap.splice(0, 0, [one]);
|
||||
assert.equal(rangeMap.size, 1);
|
||||
assert.equal(rangeMap.count, 1);
|
||||
});
|
||||
|
||||
test('length & count #2', () => {
|
||||
rangeMap.splice(0, 0, [one, one, one, one, one]);
|
||||
assert.equal(rangeMap.size, 5);
|
||||
assert.equal(rangeMap.count, 5);
|
||||
});
|
||||
|
||||
test('length & count #3', () => {
|
||||
rangeMap.splice(0, 0, [five]);
|
||||
assert.equal(rangeMap.size, 5);
|
||||
assert.equal(rangeMap.count, 1);
|
||||
});
|
||||
|
||||
test('length & count #4', () => {
|
||||
rangeMap.splice(0, 0, [five, five, five, five, five]);
|
||||
assert.equal(rangeMap.size, 25);
|
||||
assert.equal(rangeMap.count, 5);
|
||||
});
|
||||
|
||||
test('insert', () => {
|
||||
rangeMap.splice(0, 0, [five, five, five, five, five]);
|
||||
assert.equal(rangeMap.size, 25);
|
||||
assert.equal(rangeMap.count, 5);
|
||||
|
||||
rangeMap.splice(0, 0, [five, five, five, five, five]);
|
||||
assert.equal(rangeMap.size, 50);
|
||||
assert.equal(rangeMap.count, 10);
|
||||
|
||||
rangeMap.splice(5, 0, [ten, ten]);
|
||||
assert.equal(rangeMap.size, 70);
|
||||
assert.equal(rangeMap.count, 12);
|
||||
|
||||
rangeMap.splice(12, 0, [{ size: 200 }]);
|
||||
assert.equal(rangeMap.size, 270);
|
||||
assert.equal(rangeMap.count, 13);
|
||||
});
|
||||
|
||||
test('delete', () => {
|
||||
rangeMap.splice(0, 0, [five, five, five, five, five,
|
||||
five, five, five, five, five,
|
||||
five, five, five, five, five,
|
||||
five, five, five, five, five]);
|
||||
assert.equal(rangeMap.size, 100);
|
||||
assert.equal(rangeMap.count, 20);
|
||||
|
||||
rangeMap.splice(10, 5);
|
||||
assert.equal(rangeMap.size, 75);
|
||||
assert.equal(rangeMap.count, 15);
|
||||
|
||||
rangeMap.splice(0, 1);
|
||||
assert.equal(rangeMap.size, 70);
|
||||
assert.equal(rangeMap.count, 14);
|
||||
|
||||
rangeMap.splice(1, 13);
|
||||
assert.equal(rangeMap.size, 5);
|
||||
assert.equal(rangeMap.count, 1);
|
||||
|
||||
rangeMap.splice(1, 1);
|
||||
assert.equal(rangeMap.size, 5);
|
||||
assert.equal(rangeMap.count, 1);
|
||||
});
|
||||
|
||||
test('insert & delete', () => {
|
||||
assert.equal(rangeMap.size, 0);
|
||||
assert.equal(rangeMap.count, 0);
|
||||
|
||||
rangeMap.splice(0, 0, [one]);
|
||||
assert.equal(rangeMap.size, 1);
|
||||
assert.equal(rangeMap.count, 1);
|
||||
|
||||
rangeMap.splice(0, 1);
|
||||
assert.equal(rangeMap.size, 0);
|
||||
assert.equal(rangeMap.count, 0);
|
||||
});
|
||||
|
||||
test('insert & delete #2', () => {
|
||||
rangeMap.splice(0, 0, [one, one, one, one, one,
|
||||
one, one, one, one, one]);
|
||||
rangeMap.splice(2, 6);
|
||||
assert.equal(rangeMap.count, 4);
|
||||
assert.equal(rangeMap.size, 4);
|
||||
});
|
||||
|
||||
test('insert & delete #3', () => {
|
||||
rangeMap.splice(0, 0, [one, one, one, one, one,
|
||||
one, one, one, one, one,
|
||||
two, two, two, two, two,
|
||||
two, two, two, two, two]);
|
||||
rangeMap.splice(8, 4);
|
||||
assert.equal(rangeMap.count, 16);
|
||||
assert.equal(rangeMap.size, 24);
|
||||
});
|
||||
|
||||
test('insert & delete #3', () => {
|
||||
rangeMap.splice(0, 0, [one, one, one, one, one,
|
||||
one, one, one, one, one,
|
||||
two, two, two, two, two,
|
||||
two, two, two, two, two]);
|
||||
rangeMap.splice(5, 0, [three, three, three, three, three]);
|
||||
assert.equal(rangeMap.count, 25);
|
||||
assert.equal(rangeMap.size, 45);
|
||||
|
||||
rangeMap.splice(4, 7);
|
||||
assert.equal(rangeMap.count, 18);
|
||||
assert.equal(rangeMap.size, 28);
|
||||
});
|
||||
|
||||
suite('indexAt, positionAt', () => {
|
||||
test('empty', () => {
|
||||
assert.equal(rangeMap.indexAt(0), 0);
|
||||
assert.equal(rangeMap.indexAt(10), 0);
|
||||
assert.equal(rangeMap.indexAt(-1), -1);
|
||||
assert.equal(rangeMap.positionAt(0), -1);
|
||||
assert.equal(rangeMap.positionAt(10), -1);
|
||||
assert.equal(rangeMap.positionAt(-1), -1);
|
||||
});
|
||||
|
||||
test('simple', () => {
|
||||
rangeMap.splice(0, 0, [one]);
|
||||
assert.equal(rangeMap.indexAt(0), 0);
|
||||
assert.equal(rangeMap.indexAt(1), 1);
|
||||
assert.equal(rangeMap.positionAt(0), 0);
|
||||
assert.equal(rangeMap.positionAt(1), -1);
|
||||
});
|
||||
|
||||
test('simple #2', () => {
|
||||
rangeMap.splice(0, 0, [ten]);
|
||||
assert.equal(rangeMap.indexAt(0), 0);
|
||||
assert.equal(rangeMap.indexAt(5), 0);
|
||||
assert.equal(rangeMap.indexAt(9), 0);
|
||||
assert.equal(rangeMap.indexAt(10), 1);
|
||||
assert.equal(rangeMap.positionAt(0), 0);
|
||||
assert.equal(rangeMap.positionAt(1), -1);
|
||||
});
|
||||
|
||||
test('insert', () => {
|
||||
rangeMap.splice(0, 0, [one, one, one, one, one, one, one, one, one, one]);
|
||||
assert.equal(rangeMap.indexAt(0), 0);
|
||||
assert.equal(rangeMap.indexAt(1), 1);
|
||||
assert.equal(rangeMap.indexAt(5), 5);
|
||||
assert.equal(rangeMap.indexAt(9), 9);
|
||||
assert.equal(rangeMap.indexAt(10), 10);
|
||||
assert.equal(rangeMap.indexAt(11), 10);
|
||||
|
||||
rangeMap.splice(10, 0, [one, one, one, one, one, one, one, one, one, one]);
|
||||
assert.equal(rangeMap.indexAt(10), 10);
|
||||
assert.equal(rangeMap.indexAt(19), 19);
|
||||
assert.equal(rangeMap.indexAt(20), 20);
|
||||
assert.equal(rangeMap.indexAt(21), 20);
|
||||
assert.equal(rangeMap.positionAt(0), 0);
|
||||
assert.equal(rangeMap.positionAt(1), 1);
|
||||
assert.equal(rangeMap.positionAt(19), 19);
|
||||
assert.equal(rangeMap.positionAt(20), -1);
|
||||
});
|
||||
|
||||
test('delete', () => {
|
||||
rangeMap.splice(0, 0, [one, one, one, one, one, one, one, one, one, one]);
|
||||
rangeMap.splice(2, 6);
|
||||
|
||||
assert.equal(rangeMap.indexAt(0), 0);
|
||||
assert.equal(rangeMap.indexAt(1), 1);
|
||||
assert.equal(rangeMap.indexAt(3), 3);
|
||||
assert.equal(rangeMap.indexAt(4), 4);
|
||||
assert.equal(rangeMap.indexAt(5), 4);
|
||||
assert.equal(rangeMap.positionAt(0), 0);
|
||||
assert.equal(rangeMap.positionAt(1), 1);
|
||||
assert.equal(rangeMap.positionAt(3), 3);
|
||||
assert.equal(rangeMap.positionAt(4), -1);
|
||||
});
|
||||
|
||||
test('delete #2', () => {
|
||||
rangeMap.splice(0, 0, [ten, ten, ten, ten, ten, ten, ten, ten, ten, ten]);
|
||||
rangeMap.splice(2, 6);
|
||||
|
||||
assert.equal(rangeMap.indexAt(0), 0);
|
||||
assert.equal(rangeMap.indexAt(1), 0);
|
||||
assert.equal(rangeMap.indexAt(30), 3);
|
||||
assert.equal(rangeMap.indexAt(40), 4);
|
||||
assert.equal(rangeMap.indexAt(50), 4);
|
||||
assert.equal(rangeMap.positionAt(0), 0);
|
||||
assert.equal(rangeMap.positionAt(1), 10);
|
||||
assert.equal(rangeMap.positionAt(2), 20);
|
||||
assert.equal(rangeMap.positionAt(3), 30);
|
||||
assert.equal(rangeMap.positionAt(4), -1);
|
||||
});
|
||||
});
|
||||
});
|
||||
81
lib/vscode/src/vs/base/test/browser/ui/menu/menubar.test.ts
Normal file
81
lib/vscode/src/vs/base/test/browser/ui/menu/menubar.test.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { $ } from 'vs/base/browser/dom';
|
||||
import { MenuBar } from 'vs/base/browser/ui/menu/menubar';
|
||||
|
||||
function getButtonElementByAriaLabel(menubarElement: HTMLElement, ariaLabel: string): HTMLElement | null {
|
||||
let i;
|
||||
for (i = 0; i < menubarElement.childElementCount; i++) {
|
||||
|
||||
if (menubarElement.children[i].getAttribute('aria-label') === ariaLabel) {
|
||||
return menubarElement.children[i] as HTMLElement;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function getTitleDivFromButtonDiv(menuButtonElement: HTMLElement): HTMLElement | null {
|
||||
let i;
|
||||
for (i = 0; i < menuButtonElement.childElementCount; i++) {
|
||||
if (menuButtonElement.children[i].classList.contains('menubar-menu-title')) {
|
||||
return menuButtonElement.children[i] as HTMLElement;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function getMnemonicFromTitleDiv(menuTitleDiv: HTMLElement): string | null {
|
||||
let i;
|
||||
for (i = 0; i < menuTitleDiv.childElementCount; i++) {
|
||||
if (menuTitleDiv.children[i].tagName.toLocaleLowerCase() === 'mnemonic') {
|
||||
return menuTitleDiv.children[i].textContent;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function validateMenuBarItem(menubar: MenuBar, menubarContainer: HTMLElement, label: string, readableLabel: string, mnemonic: string) {
|
||||
menubar.push([
|
||||
{
|
||||
actions: [],
|
||||
label: label
|
||||
}
|
||||
]);
|
||||
|
||||
const buttonElement = getButtonElementByAriaLabel(menubarContainer, readableLabel);
|
||||
assert(buttonElement !== null, `Button element not found for ${readableLabel} button.`);
|
||||
|
||||
const titleDiv = getTitleDivFromButtonDiv(buttonElement!);
|
||||
assert(titleDiv !== null, `Title div not found for ${readableLabel} button.`);
|
||||
|
||||
const mnem = getMnemonicFromTitleDiv(titleDiv!);
|
||||
assert.equal(mnem, mnemonic, 'Mnemonic not correct');
|
||||
}
|
||||
|
||||
suite('Menubar', () => {
|
||||
const container = $('.container');
|
||||
|
||||
const menubar = new MenuBar(container, {
|
||||
enableMnemonics: true,
|
||||
visibility: 'visible'
|
||||
});
|
||||
|
||||
test('English File menu renders mnemonics', function () {
|
||||
validateMenuBarItem(menubar, container, '&File', 'File', 'F');
|
||||
});
|
||||
|
||||
test('Russian File menu renders mnemonics', function () {
|
||||
validateMenuBarItem(menubar, container, '&Файл', 'Файл', 'Ф');
|
||||
});
|
||||
|
||||
test('Chinese File menu renders mnemonics', function () {
|
||||
validateMenuBarItem(menubar, container, '文件(&F)', '文件', 'F');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,524 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { MouseWheelClassifier } from 'vs/base/browser/ui/scrollbar/scrollableElement';
|
||||
|
||||
export type IMouseWheelEvent = [number, number, number];
|
||||
|
||||
suite('MouseWheelClassifier', () => {
|
||||
|
||||
test('OSX - Apple Magic Mouse', () => {
|
||||
const testData: IMouseWheelEvent[] = [
|
||||
[1503409622410, -0.025, 0],
|
||||
[1503409622435, -0.175, 0],
|
||||
[1503409622446, -0.225, 0],
|
||||
[1503409622489, -0.65, 0],
|
||||
[1503409622514, -1.225, 0],
|
||||
[1503409622537, -1.025, 0],
|
||||
[1503409622543, -0.55, 0],
|
||||
[1503409622587, -0.75, 0],
|
||||
[1503409622623, -1.45, 0],
|
||||
[1503409622641, -1.325, 0],
|
||||
[1503409622663, -0.6, 0],
|
||||
[1503409622681, -1.125, 0],
|
||||
[1503409622703, -0.5166666666666667, 0],
|
||||
[1503409622721, -0.475, 0],
|
||||
[1503409622822, -0.425, 0],
|
||||
[1503409622871, -1.9916666666666667, 0],
|
||||
[1503409622933, -0.7, 0],
|
||||
[1503409622991, -0.725, 0],
|
||||
[1503409623032, -0.45, 0],
|
||||
[1503409623083, -0.25, 0],
|
||||
[1503409623122, -0.4, 0],
|
||||
[1503409623176, -0.2, 0],
|
||||
[1503409623197, -0.225, 0],
|
||||
[1503409623219, -0.05, 0],
|
||||
[1503409623249, -0.1, 0],
|
||||
[1503409623278, -0.1, 0],
|
||||
[1503409623292, -0.025, 0],
|
||||
[1503409623315, -0.025, 0],
|
||||
[1503409623324, -0.05, 0],
|
||||
[1503409623356, -0.025, 0],
|
||||
[1503409623415, -0.025, 0],
|
||||
[1503409623443, -0.05, 0],
|
||||
[1503409623452, -0.025, 0],
|
||||
];
|
||||
|
||||
const classifier = new MouseWheelClassifier();
|
||||
for (let i = 0, len = testData.length; i < len; i++) {
|
||||
const [timestamp, deltaY, deltaX] = testData[i];
|
||||
classifier.accept(timestamp, deltaX, deltaY);
|
||||
|
||||
const actual = classifier.isPhysicalMouseWheel();
|
||||
assert.equal(actual, false);
|
||||
}
|
||||
});
|
||||
|
||||
test('OSX - Apple Touch Pad', () => {
|
||||
const testData: IMouseWheelEvent[] = [
|
||||
[1503409780792, 0.025, 0],
|
||||
[1503409780808, 0.175, -0.025],
|
||||
[1503409780811, 0.35, -0.05],
|
||||
[1503409780816, 0.55, -0.075],
|
||||
[1503409780836, 0.825, -0.1],
|
||||
[1503409780840, 0.725, -0.075],
|
||||
[1503409780842, 1.5, -0.125],
|
||||
[1503409780848, 1.1, -0.1],
|
||||
[1503409780877, 2.05, -0.1],
|
||||
[1503409780882, 3.9, 0],
|
||||
[1503409780908, 3.825, 0],
|
||||
[1503409780915, 3.65, 0],
|
||||
[1503409780940, 3.45, 0],
|
||||
[1503409780949, 3.25, 0],
|
||||
[1503409780979, 3.075, 0],
|
||||
[1503409780982, 2.9, 0],
|
||||
[1503409781016, 2.75, 0],
|
||||
[1503409781018, 2.625, 0],
|
||||
[1503409781051, 2.5, 0],
|
||||
[1503409781071, 2.4, 0],
|
||||
[1503409781089, 2.3, 0],
|
||||
[1503409781111, 2.175, 0],
|
||||
[1503409781140, 3.975, 0],
|
||||
[1503409781165, 1.8, 0],
|
||||
[1503409781183, 3.3, 0],
|
||||
[1503409781202, 1.475, 0],
|
||||
[1503409781223, 1.375, 0],
|
||||
[1503409781244, 1.275, 0],
|
||||
[1503409781269, 2.25, 0],
|
||||
[1503409781285, 1.025, 0],
|
||||
[1503409781300, 0.925, 0],
|
||||
[1503409781303, 0.875, 0],
|
||||
[1503409781321, 0.8, 0],
|
||||
[1503409781333, 0.725, 0],
|
||||
[1503409781355, 0.65, 0],
|
||||
[1503409781370, 0.6, 0],
|
||||
[1503409781384, 0.55, 0],
|
||||
[1503409781410, 0.5, 0],
|
||||
[1503409781422, 0.475, 0],
|
||||
[1503409781435, 0.425, 0],
|
||||
[1503409781454, 0.4, 0],
|
||||
[1503409781470, 0.35, 0],
|
||||
[1503409781486, 0.325, 0],
|
||||
[1503409781501, 0.3, 0],
|
||||
[1503409781519, 0.275, 0],
|
||||
[1503409781534, 0.25, 0],
|
||||
[1503409781553, 0.225, 0],
|
||||
[1503409781569, 0.2, 0],
|
||||
[1503409781589, 0.2, 0],
|
||||
[1503409781601, 0.175, 0],
|
||||
[1503409781621, 0.15, 0],
|
||||
[1503409781631, 0.15, 0],
|
||||
[1503409781652, 0.125, 0],
|
||||
[1503409781667, 0.125, 0],
|
||||
[1503409781685, 0.125, 0],
|
||||
[1503409781703, 0.1, 0],
|
||||
[1503409781715, 0.1, 0],
|
||||
[1503409781734, 0.1, 0],
|
||||
[1503409781753, 0.075, 0],
|
||||
[1503409781768, 0.075, 0],
|
||||
[1503409781783, 0.075, 0],
|
||||
[1503409781801, 0.075, 0],
|
||||
[1503409781815, 0.05, 0],
|
||||
[1503409781836, 0.05, 0],
|
||||
[1503409781850, 0.05, 0],
|
||||
[1503409781865, 0.05, 0],
|
||||
[1503409781880, 0.05, 0],
|
||||
[1503409781899, 0.025, 0],
|
||||
[1503409781916, 0.025, 0],
|
||||
[1503409781933, 0.025, 0],
|
||||
[1503409781952, 0.025, 0],
|
||||
[1503409781965, 0.025, 0],
|
||||
[1503409781996, 0.025, 0],
|
||||
[1503409782015, 0.025, 0],
|
||||
[1503409782045, 0.025, 0],
|
||||
];
|
||||
|
||||
const classifier = new MouseWheelClassifier();
|
||||
for (let i = 0, len = testData.length; i < len; i++) {
|
||||
const [timestamp, deltaY, deltaX] = testData[i];
|
||||
classifier.accept(timestamp, deltaX, deltaY);
|
||||
|
||||
const actual = classifier.isPhysicalMouseWheel();
|
||||
assert.equal(actual, false);
|
||||
}
|
||||
});
|
||||
|
||||
test('OSX - Razer Physical Mouse Wheel', () => {
|
||||
const testData: IMouseWheelEvent[] = [
|
||||
[1503409880776, -1, 0],
|
||||
[1503409880791, -1, 0],
|
||||
[1503409880810, -4, 0],
|
||||
[1503409880820, -5, 0],
|
||||
[1503409880848, -6, 0],
|
||||
[1503409880876, -7, 0],
|
||||
[1503409881319, -1, 0],
|
||||
[1503409881387, -1, 0],
|
||||
[1503409881407, -2, 0],
|
||||
[1503409881443, -4, 0],
|
||||
[1503409881444, -5, 0],
|
||||
[1503409881470, -6, 0],
|
||||
[1503409881496, -7, 0],
|
||||
[1503409881812, -1, 0],
|
||||
[1503409881829, -1, 0],
|
||||
[1503409881850, -4, 0],
|
||||
[1503409881871, -5, 0],
|
||||
[1503409881896, -13, 0],
|
||||
[1503409881914, -16, 0],
|
||||
[1503409882551, -1, 0],
|
||||
[1503409882589, -1, 0],
|
||||
[1503409882625, -2, 0],
|
||||
[1503409883035, -1, 0],
|
||||
[1503409883098, -1, 0],
|
||||
[1503409883143, -2, 0],
|
||||
[1503409883217, -2, 0],
|
||||
[1503409883270, -3, 0],
|
||||
[1503409883388, -3, 0],
|
||||
[1503409883531, -3, 0],
|
||||
[1503409884095, -1, 0],
|
||||
[1503409884122, -1, 0],
|
||||
[1503409884160, -3, 0],
|
||||
[1503409884208, -4, 0],
|
||||
[1503409884292, -4, 0],
|
||||
[1503409884447, -1, 0],
|
||||
[1503409884788, -1, 0],
|
||||
[1503409884835, -1, 0],
|
||||
[1503409884898, -2, 0],
|
||||
[1503409884965, -3, 0],
|
||||
[1503409885085, -2, 0],
|
||||
[1503409885552, -1, 0],
|
||||
[1503409885619, -1, 0],
|
||||
[1503409885670, -1, 0],
|
||||
[1503409885733, -2, 0],
|
||||
[1503409885784, -4, 0],
|
||||
[1503409885916, -3, 0],
|
||||
];
|
||||
|
||||
const classifier = new MouseWheelClassifier();
|
||||
for (let i = 0, len = testData.length; i < len; i++) {
|
||||
const [timestamp, deltaY, deltaX] = testData[i];
|
||||
classifier.accept(timestamp, deltaX, deltaY);
|
||||
|
||||
const actual = classifier.isPhysicalMouseWheel();
|
||||
assert.equal(actual, true);
|
||||
}
|
||||
});
|
||||
|
||||
test('Windows - Microsoft Arc Touch', () => {
|
||||
const testData: IMouseWheelEvent[] = [
|
||||
[1503418316909, -2, 0],
|
||||
[1503418316985, -2, 0],
|
||||
[1503418316988, -4, 0],
|
||||
[1503418317034, -2, 0],
|
||||
[1503418317071, -2, 0],
|
||||
[1503418317094, -2, 0],
|
||||
[1503418317133, -2, 0],
|
||||
[1503418317170, -2, 0],
|
||||
[1503418317192, -2, 0],
|
||||
[1503418317265, -2, 0],
|
||||
[1503418317289, -2, 0],
|
||||
[1503418317365, -2, 0],
|
||||
[1503418317414, -2, 0],
|
||||
[1503418317458, -2, 0],
|
||||
[1503418317513, -2, 0],
|
||||
[1503418317583, -2, 0],
|
||||
[1503418317637, -2, 0],
|
||||
[1503418317720, -2, 0],
|
||||
[1503418317786, -2, 0],
|
||||
[1503418317832, -2, 0],
|
||||
[1503418317933, -2, 0],
|
||||
[1503418318037, -2, 0],
|
||||
[1503418318134, -2, 0],
|
||||
[1503418318267, -2, 0],
|
||||
[1503418318411, -2, 0],
|
||||
];
|
||||
|
||||
const classifier = new MouseWheelClassifier();
|
||||
for (let i = 0, len = testData.length; i < len; i++) {
|
||||
const [timestamp, deltaY, deltaX] = testData[i];
|
||||
classifier.accept(timestamp, deltaX, deltaY);
|
||||
|
||||
const actual = classifier.isPhysicalMouseWheel();
|
||||
assert.equal(actual, true);
|
||||
}
|
||||
});
|
||||
|
||||
test('Windows - SurfaceBook TouchPad', () => {
|
||||
const testData: IMouseWheelEvent[] = [
|
||||
[1503418499174, -3.35, 0],
|
||||
[1503418499177, -0.9333333333333333, 0],
|
||||
[1503418499222, -2.091666666666667, 0],
|
||||
[1503418499238, -1.5666666666666667, 0],
|
||||
[1503418499242, -1.8, 0],
|
||||
[1503418499271, -2.5166666666666666, 0],
|
||||
[1503418499283, -0.7666666666666667, 0],
|
||||
[1503418499308, -2.033333333333333, 0],
|
||||
[1503418499320, -2.85, 0],
|
||||
[1503418499372, -1.5333333333333334, 0],
|
||||
[1503418499373, -2.8, 0],
|
||||
[1503418499411, -1.6166666666666667, 0],
|
||||
[1503418499413, -1.9166666666666667, 0],
|
||||
[1503418499443, -0.9333333333333333, 0],
|
||||
[1503418499446, -0.9833333333333333, 0],
|
||||
[1503418499458, -0.7666666666666667, 0],
|
||||
[1503418499482, -0.9666666666666667, 0],
|
||||
[1503418499485, -0.36666666666666664, 0],
|
||||
[1503418499508, -0.5833333333333334, 0],
|
||||
[1503418499532, -0.48333333333333334, 0],
|
||||
[1503418499541, -0.6333333333333333, 0],
|
||||
[1503418499571, -0.18333333333333332, 0],
|
||||
[1503418499573, -0.4, 0],
|
||||
[1503418499595, -0.15, 0],
|
||||
[1503418499608, -0.23333333333333334, 0],
|
||||
[1503418499625, -0.18333333333333332, 0],
|
||||
[1503418499657, -0.13333333333333333, 0],
|
||||
[1503418499674, -0.15, 0],
|
||||
[1503418499676, -0.03333333333333333, 0],
|
||||
[1503418499691, -0.016666666666666666, 0],
|
||||
];
|
||||
|
||||
const classifier = new MouseWheelClassifier();
|
||||
for (let i = 0, len = testData.length; i < len; i++) {
|
||||
const [timestamp, deltaY, deltaX] = testData[i];
|
||||
classifier.accept(timestamp, deltaX, deltaY);
|
||||
|
||||
const actual = classifier.isPhysicalMouseWheel();
|
||||
assert.equal(actual, false);
|
||||
}
|
||||
});
|
||||
|
||||
test('Windows - Razer physical wheel', () => {
|
||||
const testData: IMouseWheelEvent[] = [
|
||||
[1503418638271, -2, 0],
|
||||
[1503418638317, -2, 0],
|
||||
[1503418638336, -2, 0],
|
||||
[1503418638350, -2, 0],
|
||||
[1503418638360, -2, 0],
|
||||
[1503418638366, -2, 0],
|
||||
[1503418638407, -2, 0],
|
||||
[1503418638694, -2, 0],
|
||||
[1503418638742, -2, 0],
|
||||
[1503418638744, -2, 0],
|
||||
[1503418638746, -2, 0],
|
||||
[1503418638780, -2, 0],
|
||||
[1503418638782, -2, 0],
|
||||
[1503418638810, -2, 0],
|
||||
[1503418639127, -2, 0],
|
||||
[1503418639168, -2, 0],
|
||||
[1503418639194, -2, 0],
|
||||
[1503418639197, -4, 0],
|
||||
[1503418639244, -2, 0],
|
||||
[1503418639248, -2, 0],
|
||||
[1503418639586, -2, 0],
|
||||
[1503418639653, -2, 0],
|
||||
[1503418639667, -4, 0],
|
||||
[1503418639677, -2, 0],
|
||||
[1503418639681, -2, 0],
|
||||
[1503418639728, -2, 0],
|
||||
[1503418639997, -2, 0],
|
||||
[1503418640034, -2, 0],
|
||||
[1503418640039, -2, 0],
|
||||
[1503418640065, -2, 0],
|
||||
[1503418640080, -2, 0],
|
||||
[1503418640097, -2, 0],
|
||||
[1503418640141, -2, 0],
|
||||
[1503418640413, -2, 0],
|
||||
[1503418640456, -2, 0],
|
||||
[1503418640490, -2, 0],
|
||||
[1503418640492, -4, 0],
|
||||
[1503418640494, -2, 0],
|
||||
[1503418640546, -2, 0],
|
||||
[1503418640781, -2, 0],
|
||||
[1503418640823, -2, 0],
|
||||
[1503418640824, -2, 0],
|
||||
[1503418640829, -2, 0],
|
||||
[1503418640864, -2, 0],
|
||||
[1503418640874, -2, 0],
|
||||
[1503418640876, -2, 0],
|
||||
[1503418641168, -2, 0],
|
||||
[1503418641203, -2, 0],
|
||||
[1503418641224, -2, 0],
|
||||
[1503418641240, -2, 0],
|
||||
[1503418641254, -4, 0],
|
||||
[1503418641270, -2, 0],
|
||||
[1503418641546, -2, 0],
|
||||
[1503418641612, -2, 0],
|
||||
[1503418641625, -6, 0],
|
||||
[1503418641634, -2, 0],
|
||||
[1503418641680, -2, 0],
|
||||
[1503418641961, -2, 0],
|
||||
[1503418642004, -2, 0],
|
||||
[1503418642016, -4, 0],
|
||||
[1503418642044, -2, 0],
|
||||
[1503418642065, -2, 0],
|
||||
[1503418642083, -2, 0],
|
||||
[1503418642349, -2, 0],
|
||||
[1503418642378, -2, 0],
|
||||
[1503418642390, -2, 0],
|
||||
[1503418642408, -2, 0],
|
||||
[1503418642413, -2, 0],
|
||||
[1503418642448, -2, 0],
|
||||
[1503418642468, -2, 0],
|
||||
[1503418642746, -2, 0],
|
||||
[1503418642800, -2, 0],
|
||||
[1503418642814, -4, 0],
|
||||
[1503418642816, -2, 0],
|
||||
[1503418642857, -2, 0],
|
||||
];
|
||||
|
||||
const classifier = new MouseWheelClassifier();
|
||||
for (let i = 0, len = testData.length; i < len; i++) {
|
||||
const [timestamp, deltaY, deltaX] = testData[i];
|
||||
classifier.accept(timestamp, deltaX, deltaY);
|
||||
|
||||
const actual = classifier.isPhysicalMouseWheel();
|
||||
assert.equal(actual, true);
|
||||
}
|
||||
});
|
||||
|
||||
test('Windows - Logitech physical wheel', () => {
|
||||
const testData: IMouseWheelEvent[] = [
|
||||
[1503418872930, -2, 0],
|
||||
[1503418872952, -2, 0],
|
||||
[1503418872969, -2, 0],
|
||||
[1503418873022, -2, 0],
|
||||
[1503418873042, -2, 0],
|
||||
[1503418873076, -2, 0],
|
||||
[1503418873368, -2, 0],
|
||||
[1503418873393, -2, 0],
|
||||
[1503418873404, -2, 0],
|
||||
[1503418873425, -2, 0],
|
||||
[1503418873479, -2, 0],
|
||||
[1503418873520, -2, 0],
|
||||
[1503418873758, -2, 0],
|
||||
[1503418873759, -2, 0],
|
||||
[1503418873762, -2, 0],
|
||||
[1503418873807, -2, 0],
|
||||
[1503418873830, -4, 0],
|
||||
[1503418873850, -2, 0],
|
||||
[1503418874076, -2, 0],
|
||||
[1503418874116, -2, 0],
|
||||
[1503418874136, -4, 0],
|
||||
[1503418874148, -2, 0],
|
||||
[1503418874150, -2, 0],
|
||||
[1503418874409, -2, 0],
|
||||
[1503418874452, -2, 0],
|
||||
[1503418874472, -2, 0],
|
||||
[1503418874474, -4, 0],
|
||||
[1503418874543, -2, 0],
|
||||
[1503418874566, -2, 0],
|
||||
[1503418874778, -2, 0],
|
||||
[1503418874780, -2, 0],
|
||||
[1503418874801, -2, 0],
|
||||
[1503418874822, -2, 0],
|
||||
[1503418874832, -2, 0],
|
||||
[1503418874845, -2, 0],
|
||||
[1503418875122, -2, 0],
|
||||
[1503418875158, -2, 0],
|
||||
[1503418875180, -2, 0],
|
||||
[1503418875195, -4, 0],
|
||||
[1503418875239, -2, 0],
|
||||
[1503418875260, -2, 0],
|
||||
[1503418875490, -2, 0],
|
||||
[1503418875525, -2, 0],
|
||||
[1503418875547, -4, 0],
|
||||
[1503418875556, -4, 0],
|
||||
[1503418875630, -2, 0],
|
||||
[1503418875852, -2, 0],
|
||||
[1503418875895, -2, 0],
|
||||
[1503418875935, -2, 0],
|
||||
[1503418875941, -4, 0],
|
||||
[1503418876198, -2, 0],
|
||||
[1503418876242, -2, 0],
|
||||
[1503418876270, -4, 0],
|
||||
[1503418876279, -2, 0],
|
||||
[1503418876333, -2, 0],
|
||||
[1503418876342, -2, 0],
|
||||
[1503418876585, -2, 0],
|
||||
[1503418876609, -2, 0],
|
||||
[1503418876623, -2, 0],
|
||||
[1503418876644, -2, 0],
|
||||
[1503418876646, -2, 0],
|
||||
[1503418876678, -2, 0],
|
||||
[1503418877330, -2, 0],
|
||||
[1503418877354, -2, 0],
|
||||
[1503418877368, -2, 0],
|
||||
[1503418877397, -2, 0],
|
||||
[1503418877411, -2, 0],
|
||||
[1503418877748, -2, 0],
|
||||
[1503418877756, -2, 0],
|
||||
[1503418877778, -2, 0],
|
||||
[1503418877793, -2, 0],
|
||||
[1503418877807, -2, 0],
|
||||
[1503418878091, -2, 0],
|
||||
[1503418878133, -2, 0],
|
||||
[1503418878137, -4, 0],
|
||||
[1503418878181, -2, 0],
|
||||
];
|
||||
|
||||
const classifier = new MouseWheelClassifier();
|
||||
for (let i = 0, len = testData.length; i < len; i++) {
|
||||
const [timestamp, deltaY, deltaX] = testData[i];
|
||||
classifier.accept(timestamp, deltaX, deltaY);
|
||||
|
||||
const actual = classifier.isPhysicalMouseWheel();
|
||||
assert.equal(actual, true);
|
||||
}
|
||||
});
|
||||
|
||||
test('Windows - Microsoft basic v2 physical wheel', () => {
|
||||
const testData: IMouseWheelEvent[] = [
|
||||
[1503418994564, -2, 0],
|
||||
[1503418994643, -2, 0],
|
||||
[1503418994676, -2, 0],
|
||||
[1503418994691, -2, 0],
|
||||
[1503418994727, -2, 0],
|
||||
[1503418994799, -2, 0],
|
||||
[1503418994850, -2, 0],
|
||||
[1503418995259, -2, 0],
|
||||
[1503418995321, -2, 0],
|
||||
[1503418995328, -2, 0],
|
||||
[1503418995343, -2, 0],
|
||||
[1503418995402, -2, 0],
|
||||
[1503418995454, -2, 0],
|
||||
[1503418996052, -2, 0],
|
||||
[1503418996095, -2, 0],
|
||||
[1503418996107, -2, 0],
|
||||
[1503418996120, -2, 0],
|
||||
[1503418996146, -2, 0],
|
||||
[1503418996471, -2, 0],
|
||||
[1503418996530, -2, 0],
|
||||
[1503418996549, -2, 0],
|
||||
[1503418996561, -2, 0],
|
||||
[1503418996571, -2, 0],
|
||||
[1503418996636, -2, 0],
|
||||
[1503418996936, -2, 0],
|
||||
[1503418997002, -2, 0],
|
||||
[1503418997006, -2, 0],
|
||||
[1503418997043, -2, 0],
|
||||
[1503418997045, -2, 0],
|
||||
[1503418997092, -2, 0],
|
||||
[1503418997357, -2, 0],
|
||||
[1503418997394, -2, 0],
|
||||
[1503418997410, -2, 0],
|
||||
[1503418997426, -2, 0],
|
||||
[1503418997442, -2, 0],
|
||||
[1503418997486, -2, 0],
|
||||
[1503418997757, -2, 0],
|
||||
[1503418997807, -2, 0],
|
||||
[1503418997813, -2, 0],
|
||||
[1503418997850, -2, 0],
|
||||
];
|
||||
|
||||
const classifier = new MouseWheelClassifier();
|
||||
for (let i = 0, len = testData.length; i < len; i++) {
|
||||
const [timestamp, deltaY, deltaX] = testData[i];
|
||||
classifier.accept(timestamp, deltaX, deltaY);
|
||||
|
||||
const actual = classifier.isPhysicalMouseWheel();
|
||||
assert.equal(actual, true);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,55 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { ScrollbarState } from 'vs/base/browser/ui/scrollbar/scrollbarState';
|
||||
|
||||
suite('ScrollbarState', () => {
|
||||
test('inflates slider size', () => {
|
||||
let actual = new ScrollbarState(0, 14, 0, 339, 42423, 32787);
|
||||
|
||||
assert.equal(actual.getArrowSize(), 0);
|
||||
assert.equal(actual.getScrollPosition(), 32787);
|
||||
assert.equal(actual.getRectangleLargeSize(), 339);
|
||||
assert.equal(actual.getRectangleSmallSize(), 14);
|
||||
assert.equal(actual.isNeeded(), true);
|
||||
assert.equal(actual.getSliderSize(), 20);
|
||||
assert.equal(actual.getSliderPosition(), 249);
|
||||
|
||||
|
||||
assert.equal(actual.getDesiredScrollPositionFromOffset(259), 32849);
|
||||
actual.setScrollPosition(32849);
|
||||
assert.equal(actual.getArrowSize(), 0);
|
||||
assert.equal(actual.getScrollPosition(), 32849);
|
||||
assert.equal(actual.getRectangleLargeSize(), 339);
|
||||
assert.equal(actual.getRectangleSmallSize(), 14);
|
||||
assert.equal(actual.isNeeded(), true);
|
||||
assert.equal(actual.getSliderSize(), 20);
|
||||
assert.equal(actual.getSliderPosition(), 249);
|
||||
});
|
||||
|
||||
test('inflates slider size with arrows', () => {
|
||||
let actual = new ScrollbarState(12, 14, 0, 339, 42423, 32787);
|
||||
|
||||
assert.equal(actual.getArrowSize(), 12);
|
||||
assert.equal(actual.getScrollPosition(), 32787);
|
||||
assert.equal(actual.getRectangleLargeSize(), 339);
|
||||
assert.equal(actual.getRectangleSmallSize(), 14);
|
||||
assert.equal(actual.isNeeded(), true);
|
||||
assert.equal(actual.getSliderSize(), 20);
|
||||
assert.equal(actual.getSliderPosition(), 230);
|
||||
|
||||
|
||||
assert.equal(actual.getDesiredScrollPositionFromOffset(240 + 12), 32811);
|
||||
actual.setScrollPosition(32811);
|
||||
assert.equal(actual.getArrowSize(), 12);
|
||||
assert.equal(actual.getScrollPosition(), 32811);
|
||||
assert.equal(actual.getRectangleLargeSize(), 339);
|
||||
assert.equal(actual.getRectangleSmallSize(), 14);
|
||||
assert.equal(actual.isNeeded(), true);
|
||||
assert.equal(actual.getSliderSize(), 20);
|
||||
assert.equal(actual.getSliderPosition(), 230);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,549 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { SplitView, IView, Sizing, LayoutPriority } from 'vs/base/browser/ui/splitview/splitview';
|
||||
import { Sash, SashState } from 'vs/base/browser/ui/sash/sash';
|
||||
|
||||
class TestView implements IView<number> {
|
||||
|
||||
private readonly _onDidChange = new Emitter<number | undefined>();
|
||||
readonly onDidChange = this._onDidChange.event;
|
||||
|
||||
get minimumSize(): number { return this._minimumSize; }
|
||||
set minimumSize(size: number) { this._minimumSize = size; this._onDidChange.fire(undefined); }
|
||||
|
||||
get maximumSize(): number { return this._maximumSize; }
|
||||
set maximumSize(size: number) { this._maximumSize = size; this._onDidChange.fire(undefined); }
|
||||
|
||||
private _element: HTMLElement = document.createElement('div');
|
||||
get element(): HTMLElement { this._onDidGetElement.fire(); return this._element; }
|
||||
|
||||
private readonly _onDidGetElement = new Emitter<void>();
|
||||
readonly onDidGetElement = this._onDidGetElement.event;
|
||||
|
||||
private _size = 0;
|
||||
get size(): number { return this._size; }
|
||||
private _orthogonalSize: number | undefined = 0;
|
||||
get orthogonalSize(): number | undefined { return this._orthogonalSize; }
|
||||
private readonly _onDidLayout = new Emitter<{ size: number; orthogonalSize: number | undefined }>();
|
||||
readonly onDidLayout = this._onDidLayout.event;
|
||||
|
||||
private readonly _onDidFocus = new Emitter<void>();
|
||||
readonly onDidFocus = this._onDidFocus.event;
|
||||
|
||||
constructor(
|
||||
private _minimumSize: number,
|
||||
private _maximumSize: number,
|
||||
readonly priority: LayoutPriority = LayoutPriority.Normal
|
||||
) {
|
||||
assert(_minimumSize <= _maximumSize, 'splitview view minimum size must be <= maximum size');
|
||||
}
|
||||
|
||||
layout(size: number, _offset: number, orthogonalSize: number | undefined): void {
|
||||
this._size = size;
|
||||
this._orthogonalSize = orthogonalSize;
|
||||
this._onDidLayout.fire({ size, orthogonalSize });
|
||||
}
|
||||
|
||||
focus(): void {
|
||||
this._onDidFocus.fire();
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._onDidChange.dispose();
|
||||
this._onDidGetElement.dispose();
|
||||
this._onDidLayout.dispose();
|
||||
this._onDidFocus.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
function getSashes(splitview: SplitView): Sash[] {
|
||||
return (splitview as any).sashItems.map((i: any) => i.sash) as Sash[];
|
||||
}
|
||||
|
||||
suite('Splitview', () => {
|
||||
let container: HTMLElement;
|
||||
|
||||
setup(() => {
|
||||
container = document.createElement('div');
|
||||
container.style.position = 'absolute';
|
||||
container.style.width = `${200}px`;
|
||||
container.style.height = `${200}px`;
|
||||
});
|
||||
|
||||
test('empty splitview has empty DOM', () => {
|
||||
const splitview = new SplitView(container);
|
||||
assert.equal(container.firstElementChild!.firstElementChild!.childElementCount, 0, 'split view should be empty');
|
||||
splitview.dispose();
|
||||
});
|
||||
|
||||
test('has views and sashes as children', () => {
|
||||
const view1 = new TestView(20, 20);
|
||||
const view2 = new TestView(20, 20);
|
||||
const view3 = new TestView(20, 20);
|
||||
const splitview = new SplitView(container);
|
||||
|
||||
splitview.addView(view1, 20);
|
||||
splitview.addView(view2, 20);
|
||||
splitview.addView(view3, 20);
|
||||
|
||||
let viewQuery = container.querySelectorAll('.monaco-split-view2 > .split-view-container > .split-view-view');
|
||||
assert.equal(viewQuery.length, 3, 'split view should have 3 views');
|
||||
|
||||
let sashQuery = container.querySelectorAll('.monaco-split-view2 > .sash-container > .monaco-sash');
|
||||
assert.equal(sashQuery.length, 2, 'split view should have 2 sashes');
|
||||
|
||||
splitview.removeView(2);
|
||||
|
||||
viewQuery = container.querySelectorAll('.monaco-split-view2 > .split-view-container > .split-view-view');
|
||||
assert.equal(viewQuery.length, 2, 'split view should have 2 views');
|
||||
|
||||
sashQuery = container.querySelectorAll('.monaco-split-view2 > .sash-container > .monaco-sash');
|
||||
assert.equal(sashQuery.length, 1, 'split view should have 1 sash');
|
||||
|
||||
splitview.removeView(0);
|
||||
|
||||
viewQuery = container.querySelectorAll('.monaco-split-view2 > .split-view-container > .split-view-view');
|
||||
assert.equal(viewQuery.length, 1, 'split view should have 1 view');
|
||||
|
||||
sashQuery = container.querySelectorAll('.monaco-split-view2 > .sash-container > .monaco-sash');
|
||||
assert.equal(sashQuery.length, 0, 'split view should have no sashes');
|
||||
|
||||
splitview.removeView(0);
|
||||
|
||||
viewQuery = container.querySelectorAll('.monaco-split-view2 > .split-view-container > .split-view-view');
|
||||
assert.equal(viewQuery.length, 0, 'split view should have no views');
|
||||
|
||||
sashQuery = container.querySelectorAll('.monaco-split-view2 > .sash-container > .monaco-sash');
|
||||
assert.equal(sashQuery.length, 0, 'split view should have no sashes');
|
||||
|
||||
splitview.dispose();
|
||||
view1.dispose();
|
||||
view2.dispose();
|
||||
view3.dispose();
|
||||
});
|
||||
|
||||
test('calls view methods on addView and removeView', () => {
|
||||
const view = new TestView(20, 20);
|
||||
const splitview = new SplitView(container);
|
||||
|
||||
let didLayout = false;
|
||||
const layoutDisposable = view.onDidLayout(() => didLayout = true);
|
||||
|
||||
const renderDisposable = view.onDidGetElement(() => undefined);
|
||||
|
||||
splitview.addView(view, 20);
|
||||
|
||||
assert.equal(view.size, 20, 'view has right size');
|
||||
assert(didLayout, 'layout is called');
|
||||
assert(didLayout, 'render is called');
|
||||
|
||||
splitview.dispose();
|
||||
layoutDisposable.dispose();
|
||||
renderDisposable.dispose();
|
||||
view.dispose();
|
||||
});
|
||||
|
||||
test('stretches view to viewport', () => {
|
||||
const view = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const splitview = new SplitView(container);
|
||||
splitview.layout(200);
|
||||
|
||||
splitview.addView(view, 20);
|
||||
assert.equal(view.size, 200, 'view is stretched');
|
||||
|
||||
splitview.layout(200);
|
||||
assert.equal(view.size, 200, 'view stayed the same');
|
||||
|
||||
splitview.layout(100);
|
||||
assert.equal(view.size, 100, 'view is collapsed');
|
||||
|
||||
splitview.layout(20);
|
||||
assert.equal(view.size, 20, 'view is collapsed');
|
||||
|
||||
splitview.layout(10);
|
||||
assert.equal(view.size, 20, 'view is clamped');
|
||||
|
||||
splitview.layout(200);
|
||||
assert.equal(view.size, 200, 'view is stretched');
|
||||
|
||||
splitview.dispose();
|
||||
view.dispose();
|
||||
});
|
||||
|
||||
test('can resize views', () => {
|
||||
const view1 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const view2 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const view3 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const splitview = new SplitView(container);
|
||||
splitview.layout(200);
|
||||
|
||||
splitview.addView(view1, 20);
|
||||
splitview.addView(view2, 20);
|
||||
splitview.addView(view3, 20);
|
||||
|
||||
assert.equal(view1.size, 160, 'view1 is stretched');
|
||||
assert.equal(view2.size, 20, 'view2 size is 20');
|
||||
assert.equal(view3.size, 20, 'view3 size is 20');
|
||||
|
||||
splitview.resizeView(1, 40);
|
||||
|
||||
assert.equal(view1.size, 140, 'view1 is collapsed');
|
||||
assert.equal(view2.size, 40, 'view2 is stretched');
|
||||
assert.equal(view3.size, 20, 'view3 stays the same');
|
||||
|
||||
splitview.resizeView(0, 70);
|
||||
|
||||
assert.equal(view1.size, 70, 'view1 is collapsed');
|
||||
assert.equal(view2.size, 40, 'view2 stays the same');
|
||||
assert.equal(view3.size, 90, 'view3 is stretched');
|
||||
|
||||
splitview.resizeView(2, 40);
|
||||
|
||||
assert.equal(view1.size, 70, 'view1 stays the same');
|
||||
assert.equal(view2.size, 90, 'view2 is collapsed');
|
||||
assert.equal(view3.size, 40, 'view3 is stretched');
|
||||
|
||||
splitview.dispose();
|
||||
view3.dispose();
|
||||
view2.dispose();
|
||||
view1.dispose();
|
||||
});
|
||||
|
||||
test('reacts to view changes', () => {
|
||||
const view1 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const view2 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const view3 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const splitview = new SplitView(container);
|
||||
splitview.layout(200);
|
||||
|
||||
splitview.addView(view1, 20);
|
||||
splitview.addView(view2, 20);
|
||||
splitview.addView(view3, 20);
|
||||
|
||||
assert.equal(view1.size, 160, 'view1 is stretched');
|
||||
assert.equal(view2.size, 20, 'view2 size is 20');
|
||||
assert.equal(view3.size, 20, 'view3 size is 20');
|
||||
|
||||
view1.maximumSize = 20;
|
||||
|
||||
assert.equal(view1.size, 20, 'view1 is collapsed');
|
||||
assert.equal(view2.size, 20, 'view2 stays the same');
|
||||
assert.equal(view3.size, 160, 'view3 is stretched');
|
||||
|
||||
view3.maximumSize = 40;
|
||||
|
||||
assert.equal(view1.size, 20, 'view1 stays the same');
|
||||
assert.equal(view2.size, 140, 'view2 is stretched');
|
||||
assert.equal(view3.size, 40, 'view3 is collapsed');
|
||||
|
||||
view2.maximumSize = 200;
|
||||
|
||||
assert.equal(view1.size, 20, 'view1 stays the same');
|
||||
assert.equal(view2.size, 140, 'view2 stays the same');
|
||||
assert.equal(view3.size, 40, 'view3 stays the same');
|
||||
|
||||
view3.maximumSize = Number.POSITIVE_INFINITY;
|
||||
view3.minimumSize = 100;
|
||||
|
||||
assert.equal(view1.size, 20, 'view1 is collapsed');
|
||||
assert.equal(view2.size, 80, 'view2 is collapsed');
|
||||
assert.equal(view3.size, 100, 'view3 is stretched');
|
||||
|
||||
splitview.dispose();
|
||||
view3.dispose();
|
||||
view2.dispose();
|
||||
view1.dispose();
|
||||
});
|
||||
|
||||
test('sashes are properly enabled/disabled', () => {
|
||||
const view1 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const view2 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const view3 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const splitview = new SplitView(container);
|
||||
splitview.layout(200);
|
||||
|
||||
splitview.addView(view1, Sizing.Distribute);
|
||||
splitview.addView(view2, Sizing.Distribute);
|
||||
splitview.addView(view3, Sizing.Distribute);
|
||||
|
||||
let sashes = getSashes(splitview);
|
||||
assert.equal(sashes.length, 2, 'there are two sashes');
|
||||
assert.equal(sashes[0].state, SashState.Enabled, 'first sash is enabled');
|
||||
assert.equal(sashes[1].state, SashState.Enabled, 'second sash is enabled');
|
||||
|
||||
splitview.layout(60);
|
||||
assert.equal(sashes[0].state, SashState.Disabled, 'first sash is disabled');
|
||||
assert.equal(sashes[1].state, SashState.Disabled, 'second sash is disabled');
|
||||
|
||||
splitview.layout(20);
|
||||
assert.equal(sashes[0].state, SashState.Disabled, 'first sash is disabled');
|
||||
assert.equal(sashes[1].state, SashState.Disabled, 'second sash is disabled');
|
||||
|
||||
splitview.layout(200);
|
||||
assert.equal(sashes[0].state, SashState.Enabled, 'first sash is enabled');
|
||||
assert.equal(sashes[1].state, SashState.Enabled, 'second sash is enabled');
|
||||
|
||||
view1.maximumSize = 20;
|
||||
assert.equal(sashes[0].state, SashState.Disabled, 'first sash is disabled');
|
||||
assert.equal(sashes[1].state, SashState.Enabled, 'second sash is enabled');
|
||||
|
||||
view2.maximumSize = 20;
|
||||
assert.equal(sashes[0].state, SashState.Disabled, 'first sash is disabled');
|
||||
assert.equal(sashes[1].state, SashState.Disabled, 'second sash is disabled');
|
||||
|
||||
view1.maximumSize = 300;
|
||||
assert.equal(sashes[0].state, SashState.Minimum, 'first sash is enabled');
|
||||
assert.equal(sashes[1].state, SashState.Minimum, 'second sash is enabled');
|
||||
|
||||
view2.maximumSize = 200;
|
||||
assert.equal(sashes[0].state, SashState.Minimum, 'first sash is enabled');
|
||||
assert.equal(sashes[1].state, SashState.Minimum, 'second sash is enabled');
|
||||
|
||||
splitview.resizeView(0, 40);
|
||||
assert.equal(sashes[0].state, SashState.Enabled, 'first sash is enabled');
|
||||
assert.equal(sashes[1].state, SashState.Enabled, 'second sash is enabled');
|
||||
|
||||
splitview.dispose();
|
||||
view3.dispose();
|
||||
view2.dispose();
|
||||
view1.dispose();
|
||||
});
|
||||
|
||||
test('issue #35497', () => {
|
||||
const view1 = new TestView(160, Number.POSITIVE_INFINITY);
|
||||
const view2 = new TestView(66, 66);
|
||||
|
||||
const splitview = new SplitView(container);
|
||||
splitview.layout(986);
|
||||
|
||||
splitview.addView(view1, 142, 0);
|
||||
assert.equal(view1.size, 986, 'first view is stretched');
|
||||
|
||||
view2.onDidGetElement(() => {
|
||||
assert.throws(() => splitview.resizeView(1, 922));
|
||||
assert.throws(() => splitview.resizeView(1, 922));
|
||||
});
|
||||
|
||||
splitview.addView(view2, 66, 0);
|
||||
assert.equal(view2.size, 66, 'second view is fixed');
|
||||
assert.equal(view1.size, 986 - 66, 'first view is collapsed');
|
||||
|
||||
const viewContainers = container.querySelectorAll('.split-view-view');
|
||||
assert.equal(viewContainers.length, 2, 'there are two view containers');
|
||||
assert.equal((viewContainers.item(0) as HTMLElement).style.height, '66px', 'second view container is 66px');
|
||||
assert.equal((viewContainers.item(1) as HTMLElement).style.height, `${986 - 66}px`, 'first view container is 66px');
|
||||
|
||||
splitview.dispose();
|
||||
view2.dispose();
|
||||
view1.dispose();
|
||||
});
|
||||
|
||||
test('automatic size distribution', () => {
|
||||
const view1 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const view2 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const view3 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const splitview = new SplitView(container);
|
||||
splitview.layout(200);
|
||||
|
||||
splitview.addView(view1, Sizing.Distribute);
|
||||
assert.equal(view1.size, 200);
|
||||
|
||||
splitview.addView(view2, 50);
|
||||
assert.deepEqual([view1.size, view2.size], [150, 50]);
|
||||
|
||||
splitview.addView(view3, Sizing.Distribute);
|
||||
assert.deepEqual([view1.size, view2.size, view3.size], [66, 66, 68]);
|
||||
|
||||
splitview.removeView(1, Sizing.Distribute);
|
||||
assert.deepEqual([view1.size, view3.size], [100, 100]);
|
||||
|
||||
splitview.dispose();
|
||||
view3.dispose();
|
||||
view2.dispose();
|
||||
view1.dispose();
|
||||
});
|
||||
|
||||
test('add views before layout', () => {
|
||||
const view1 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const view2 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const view3 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const splitview = new SplitView(container);
|
||||
|
||||
splitview.addView(view1, 100);
|
||||
splitview.addView(view2, 75);
|
||||
splitview.addView(view3, 25);
|
||||
|
||||
splitview.layout(200);
|
||||
assert.deepEqual([view1.size, view2.size, view3.size], [67, 67, 66]);
|
||||
|
||||
splitview.dispose();
|
||||
view3.dispose();
|
||||
view2.dispose();
|
||||
view1.dispose();
|
||||
});
|
||||
|
||||
test('split sizing', () => {
|
||||
const view1 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const view2 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const view3 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const splitview = new SplitView(container);
|
||||
splitview.layout(200);
|
||||
|
||||
splitview.addView(view1, Sizing.Distribute);
|
||||
assert.equal(view1.size, 200);
|
||||
|
||||
splitview.addView(view2, Sizing.Split(0));
|
||||
assert.deepEqual([view1.size, view2.size], [100, 100]);
|
||||
|
||||
splitview.addView(view3, Sizing.Split(1));
|
||||
assert.deepEqual([view1.size, view2.size, view3.size], [100, 50, 50]);
|
||||
|
||||
splitview.dispose();
|
||||
view3.dispose();
|
||||
view2.dispose();
|
||||
view1.dispose();
|
||||
});
|
||||
|
||||
test('split sizing 2', () => {
|
||||
const view1 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const view2 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const view3 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const splitview = new SplitView(container);
|
||||
splitview.layout(200);
|
||||
|
||||
splitview.addView(view1, Sizing.Distribute);
|
||||
assert.equal(view1.size, 200);
|
||||
|
||||
splitview.addView(view2, Sizing.Split(0));
|
||||
assert.deepEqual([view1.size, view2.size], [100, 100]);
|
||||
|
||||
splitview.addView(view3, Sizing.Split(0));
|
||||
assert.deepEqual([view1.size, view2.size, view3.size], [50, 100, 50]);
|
||||
|
||||
splitview.dispose();
|
||||
view3.dispose();
|
||||
view2.dispose();
|
||||
view1.dispose();
|
||||
});
|
||||
|
||||
test('proportional layout', () => {
|
||||
const view1 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const view2 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const splitview = new SplitView(container);
|
||||
splitview.layout(200);
|
||||
|
||||
splitview.addView(view1, Sizing.Distribute);
|
||||
splitview.addView(view2, Sizing.Distribute);
|
||||
assert.deepEqual([view1.size, view2.size], [100, 100]);
|
||||
|
||||
splitview.layout(100);
|
||||
assert.deepEqual([view1.size, view2.size], [50, 50]);
|
||||
|
||||
splitview.dispose();
|
||||
view2.dispose();
|
||||
view1.dispose();
|
||||
});
|
||||
|
||||
test('disable proportional layout', () => {
|
||||
const view1 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const view2 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const splitview = new SplitView(container, { proportionalLayout: false });
|
||||
splitview.layout(200);
|
||||
|
||||
splitview.addView(view1, Sizing.Distribute);
|
||||
splitview.addView(view2, Sizing.Distribute);
|
||||
assert.deepEqual([view1.size, view2.size], [100, 100]);
|
||||
|
||||
splitview.layout(100);
|
||||
assert.deepEqual([view1.size, view2.size], [80, 20]);
|
||||
|
||||
splitview.dispose();
|
||||
view2.dispose();
|
||||
view1.dispose();
|
||||
});
|
||||
|
||||
test('high layout priority', () => {
|
||||
const view1 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const view2 = new TestView(20, Number.POSITIVE_INFINITY, LayoutPriority.High);
|
||||
const view3 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const splitview = new SplitView(container, { proportionalLayout: false });
|
||||
splitview.layout(200);
|
||||
|
||||
splitview.addView(view1, Sizing.Distribute);
|
||||
splitview.addView(view2, Sizing.Distribute);
|
||||
splitview.addView(view3, Sizing.Distribute);
|
||||
assert.deepEqual([view1.size, view2.size, view3.size], [66, 68, 66]);
|
||||
|
||||
splitview.layout(180);
|
||||
assert.deepEqual([view1.size, view2.size, view3.size], [66, 48, 66]);
|
||||
|
||||
splitview.layout(124);
|
||||
assert.deepEqual([view1.size, view2.size, view3.size], [66, 20, 38]);
|
||||
|
||||
splitview.layout(60);
|
||||
assert.deepEqual([view1.size, view2.size, view3.size], [20, 20, 20]);
|
||||
|
||||
splitview.layout(200);
|
||||
assert.deepEqual([view1.size, view2.size, view3.size], [20, 160, 20]);
|
||||
|
||||
splitview.dispose();
|
||||
view3.dispose();
|
||||
view2.dispose();
|
||||
view1.dispose();
|
||||
});
|
||||
|
||||
test('low layout priority', () => {
|
||||
const view1 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const view2 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const view3 = new TestView(20, Number.POSITIVE_INFINITY, LayoutPriority.Low);
|
||||
const splitview = new SplitView(container, { proportionalLayout: false });
|
||||
splitview.layout(200);
|
||||
|
||||
splitview.addView(view1, Sizing.Distribute);
|
||||
splitview.addView(view2, Sizing.Distribute);
|
||||
splitview.addView(view3, Sizing.Distribute);
|
||||
assert.deepEqual([view1.size, view2.size, view3.size], [66, 68, 66]);
|
||||
|
||||
splitview.layout(180);
|
||||
assert.deepEqual([view1.size, view2.size, view3.size], [66, 48, 66]);
|
||||
|
||||
splitview.layout(132);
|
||||
assert.deepEqual([view1.size, view2.size, view3.size], [46, 20, 66]);
|
||||
|
||||
splitview.layout(60);
|
||||
assert.deepEqual([view1.size, view2.size, view3.size], [20, 20, 20]);
|
||||
|
||||
splitview.layout(200);
|
||||
assert.deepEqual([view1.size, view2.size, view3.size], [20, 160, 20]);
|
||||
|
||||
splitview.dispose();
|
||||
view3.dispose();
|
||||
view2.dispose();
|
||||
view1.dispose();
|
||||
});
|
||||
|
||||
test('context propagates to views', () => {
|
||||
const view1 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const view2 = new TestView(20, Number.POSITIVE_INFINITY);
|
||||
const view3 = new TestView(20, Number.POSITIVE_INFINITY, LayoutPriority.Low);
|
||||
const splitview = new SplitView<number>(container, { proportionalLayout: false });
|
||||
splitview.layout(200);
|
||||
|
||||
splitview.addView(view1, Sizing.Distribute);
|
||||
splitview.addView(view2, Sizing.Distribute);
|
||||
splitview.addView(view3, Sizing.Distribute);
|
||||
|
||||
splitview.layout(200, 100);
|
||||
assert.deepEqual([view1.orthogonalSize, view2.orthogonalSize, view3.orthogonalSize], [100, 100, 100]);
|
||||
|
||||
splitview.dispose();
|
||||
view3.dispose();
|
||||
view2.dispose();
|
||||
view1.dispose();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,438 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { ITreeNode, ITreeRenderer, IAsyncDataSource } from 'vs/base/browser/ui/tree/tree';
|
||||
import { AsyncDataTree } from 'vs/base/browser/ui/tree/asyncDataTree';
|
||||
import { IListVirtualDelegate, IIdentityProvider } from 'vs/base/browser/ui/list/list';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
|
||||
interface Element {
|
||||
id: string;
|
||||
suffix?: string;
|
||||
children?: Element[];
|
||||
}
|
||||
|
||||
function find(element: Element, id: string): Element | undefined {
|
||||
if (element.id === id) {
|
||||
return element;
|
||||
}
|
||||
|
||||
if (!element.children) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
for (const child of element.children) {
|
||||
const result = find(child, id);
|
||||
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
class Renderer implements ITreeRenderer<Element, void, HTMLElement> {
|
||||
readonly templateId = 'default';
|
||||
renderTemplate(container: HTMLElement): HTMLElement {
|
||||
return container;
|
||||
}
|
||||
renderElement(element: ITreeNode<Element, void>, index: number, templateData: HTMLElement): void {
|
||||
templateData.textContent = element.element.id + (element.element.suffix || '');
|
||||
}
|
||||
disposeTemplate(templateData: HTMLElement): void {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
class IdentityProvider implements IIdentityProvider<Element> {
|
||||
getId(element: Element) {
|
||||
return element.id;
|
||||
}
|
||||
}
|
||||
|
||||
class VirtualDelegate implements IListVirtualDelegate<Element> {
|
||||
getHeight() { return 20; }
|
||||
getTemplateId(element: Element): string { return 'default'; }
|
||||
}
|
||||
|
||||
class DataSource implements IAsyncDataSource<Element, Element> {
|
||||
hasChildren(element: Element): boolean {
|
||||
return !!element.children && element.children.length > 0;
|
||||
}
|
||||
getChildren(element: Element): Promise<Element[]> {
|
||||
return Promise.resolve(element.children || []);
|
||||
}
|
||||
}
|
||||
|
||||
class Model {
|
||||
|
||||
constructor(readonly root: Element) { }
|
||||
|
||||
get(id: string): Element {
|
||||
const result = find(this.root, id);
|
||||
|
||||
if (!result) {
|
||||
throw new Error('element not found');
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
suite('AsyncDataTree', function () {
|
||||
|
||||
test('Collapse state should be preserved across refresh calls', async () => {
|
||||
const container = document.createElement('div');
|
||||
|
||||
const model = new Model({
|
||||
id: 'root',
|
||||
children: [{
|
||||
id: 'a'
|
||||
}]
|
||||
});
|
||||
|
||||
const tree = new AsyncDataTree<Element, Element>('test', container, new VirtualDelegate(), [new Renderer()], new DataSource(), { identityProvider: new IdentityProvider() });
|
||||
tree.layout(200);
|
||||
assert.equal(container.querySelectorAll('.monaco-list-row').length, 0);
|
||||
|
||||
await tree.setInput(model.root);
|
||||
assert.equal(container.querySelectorAll('.monaco-list-row').length, 1);
|
||||
let twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement;
|
||||
assert(!twistie.classList.contains('collapsible'));
|
||||
assert(!twistie.classList.contains('collapsed'));
|
||||
|
||||
model.get('a').children = [
|
||||
{ id: 'aa' },
|
||||
{ id: 'ab' },
|
||||
{ id: 'ac' }
|
||||
];
|
||||
|
||||
await tree.updateChildren(model.root);
|
||||
assert.equal(container.querySelectorAll('.monaco-list-row').length, 1);
|
||||
|
||||
await tree.expand(model.get('a'));
|
||||
assert.equal(container.querySelectorAll('.monaco-list-row').length, 4);
|
||||
|
||||
model.get('a').children = [];
|
||||
await tree.updateChildren(model.root);
|
||||
assert.equal(container.querySelectorAll('.monaco-list-row').length, 1);
|
||||
});
|
||||
|
||||
test('issue #68648', async () => {
|
||||
const container = document.createElement('div');
|
||||
|
||||
const getChildrenCalls: string[] = [];
|
||||
const dataSource = new class implements IAsyncDataSource<Element, Element> {
|
||||
hasChildren(element: Element): boolean {
|
||||
return !!element.children && element.children.length > 0;
|
||||
}
|
||||
getChildren(element: Element): Promise<Element[]> {
|
||||
getChildrenCalls.push(element.id);
|
||||
return Promise.resolve(element.children || []);
|
||||
}
|
||||
};
|
||||
|
||||
const model = new Model({
|
||||
id: 'root',
|
||||
children: [{
|
||||
id: 'a'
|
||||
}]
|
||||
});
|
||||
|
||||
const tree = new AsyncDataTree<Element, Element>('test', container, new VirtualDelegate(), [new Renderer()], dataSource, { identityProvider: new IdentityProvider() });
|
||||
tree.layout(200);
|
||||
|
||||
await tree.setInput(model.root);
|
||||
assert.deepStrictEqual(getChildrenCalls, ['root']);
|
||||
|
||||
let twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement;
|
||||
assert(!twistie.classList.contains('collapsible'));
|
||||
assert(!twistie.classList.contains('collapsed'));
|
||||
assert(tree.getNode().children[0].collapsed);
|
||||
|
||||
model.get('a').children = [{ id: 'aa' }, { id: 'ab' }, { id: 'ac' }];
|
||||
await tree.updateChildren(model.root);
|
||||
|
||||
assert.deepStrictEqual(getChildrenCalls, ['root', 'root']);
|
||||
twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement;
|
||||
assert(twistie.classList.contains('collapsible'));
|
||||
assert(twistie.classList.contains('collapsed'));
|
||||
assert(tree.getNode().children[0].collapsed);
|
||||
|
||||
model.get('a').children = [];
|
||||
await tree.updateChildren(model.root);
|
||||
|
||||
assert.deepStrictEqual(getChildrenCalls, ['root', 'root', 'root']);
|
||||
twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement;
|
||||
assert(!twistie.classList.contains('collapsible'));
|
||||
assert(!twistie.classList.contains('collapsed'));
|
||||
assert(tree.getNode().children[0].collapsed);
|
||||
|
||||
model.get('a').children = [{ id: 'aa' }, { id: 'ab' }, { id: 'ac' }];
|
||||
await tree.updateChildren(model.root);
|
||||
|
||||
assert.deepStrictEqual(getChildrenCalls, ['root', 'root', 'root', 'root']);
|
||||
twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement;
|
||||
assert(twistie.classList.contains('collapsible'));
|
||||
assert(twistie.classList.contains('collapsed'));
|
||||
assert(tree.getNode().children[0].collapsed);
|
||||
});
|
||||
|
||||
test('issue #67722 - once resolved, refreshed collapsed nodes should only get children when expanded', async () => {
|
||||
const container = document.createElement('div');
|
||||
|
||||
const getChildrenCalls: string[] = [];
|
||||
const dataSource = new class implements IAsyncDataSource<Element, Element> {
|
||||
hasChildren(element: Element): boolean {
|
||||
return !!element.children && element.children.length > 0;
|
||||
}
|
||||
getChildren(element: Element): Promise<Element[]> {
|
||||
getChildrenCalls.push(element.id);
|
||||
return Promise.resolve(element.children || []);
|
||||
}
|
||||
};
|
||||
|
||||
const model = new Model({
|
||||
id: 'root',
|
||||
children: [{
|
||||
id: 'a', children: [{ id: 'aa' }, { id: 'ab' }, { id: 'ac' }]
|
||||
}]
|
||||
});
|
||||
|
||||
const tree = new AsyncDataTree<Element, Element>('test', container, new VirtualDelegate(), [new Renderer()], dataSource, { identityProvider: new IdentityProvider() });
|
||||
tree.layout(200);
|
||||
|
||||
await tree.setInput(model.root);
|
||||
assert(tree.getNode(model.get('a')).collapsed);
|
||||
assert.deepStrictEqual(getChildrenCalls, ['root']);
|
||||
|
||||
await tree.expand(model.get('a'));
|
||||
assert(!tree.getNode(model.get('a')).collapsed);
|
||||
assert.deepStrictEqual(getChildrenCalls, ['root', 'a']);
|
||||
|
||||
tree.collapse(model.get('a'));
|
||||
assert(tree.getNode(model.get('a')).collapsed);
|
||||
assert.deepStrictEqual(getChildrenCalls, ['root', 'a']);
|
||||
|
||||
await tree.updateChildren();
|
||||
assert(tree.getNode(model.get('a')).collapsed);
|
||||
assert.deepStrictEqual(getChildrenCalls, ['root', 'a', 'root'], 'a should not be refreshed, since it\' collapsed');
|
||||
});
|
||||
|
||||
test('resolved collapsed nodes which lose children should lose twistie as well', async () => {
|
||||
const container = document.createElement('div');
|
||||
|
||||
const model = new Model({
|
||||
id: 'root',
|
||||
children: [{
|
||||
id: 'a', children: [{ id: 'aa' }, { id: 'ab' }, { id: 'ac' }]
|
||||
}]
|
||||
});
|
||||
|
||||
const tree = new AsyncDataTree<Element, Element>('test', container, new VirtualDelegate(), [new Renderer()], new DataSource(), { identityProvider: new IdentityProvider() });
|
||||
tree.layout(200);
|
||||
|
||||
await tree.setInput(model.root);
|
||||
await tree.expand(model.get('a'));
|
||||
|
||||
let twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement;
|
||||
assert(twistie.classList.contains('collapsible'));
|
||||
assert(!twistie.classList.contains('collapsed'));
|
||||
assert(!tree.getNode(model.get('a')).collapsed);
|
||||
|
||||
tree.collapse(model.get('a'));
|
||||
model.get('a').children = [];
|
||||
await tree.updateChildren(model.root);
|
||||
|
||||
twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement;
|
||||
assert(!twistie.classList.contains('collapsible'));
|
||||
assert(!twistie.classList.contains('collapsed'));
|
||||
assert(tree.getNode(model.get('a')).collapsed);
|
||||
});
|
||||
|
||||
test('support default collapse state per element', async () => {
|
||||
const container = document.createElement('div');
|
||||
|
||||
const getChildrenCalls: string[] = [];
|
||||
const dataSource = new class implements IAsyncDataSource<Element, Element> {
|
||||
hasChildren(element: Element): boolean {
|
||||
return !!element.children && element.children.length > 0;
|
||||
}
|
||||
getChildren(element: Element): Promise<Element[]> {
|
||||
getChildrenCalls.push(element.id);
|
||||
return Promise.resolve(element.children || []);
|
||||
}
|
||||
};
|
||||
|
||||
const model = new Model({
|
||||
id: 'root',
|
||||
children: [{
|
||||
id: 'a', children: [{ id: 'aa' }, { id: 'ab' }, { id: 'ac' }]
|
||||
}]
|
||||
});
|
||||
|
||||
const tree = new AsyncDataTree<Element, Element>('test', container, new VirtualDelegate(), [new Renderer()], dataSource, {
|
||||
collapseByDefault: el => el.id !== 'a'
|
||||
});
|
||||
tree.layout(200);
|
||||
|
||||
await tree.setInput(model.root);
|
||||
assert(!tree.getNode(model.get('a')).collapsed);
|
||||
assert.deepStrictEqual(getChildrenCalls, ['root', 'a']);
|
||||
});
|
||||
|
||||
test('issue #80098 - concurrent refresh and expand', async () => {
|
||||
const container = document.createElement('div');
|
||||
|
||||
const calls: Function[] = [];
|
||||
const dataSource = new class implements IAsyncDataSource<Element, Element> {
|
||||
hasChildren(element: Element): boolean {
|
||||
return !!element.children && element.children.length > 0;
|
||||
}
|
||||
getChildren(element: Element): Promise<Element[]> {
|
||||
return new Promise(c => calls.push(() => c(element.children || [])));
|
||||
}
|
||||
};
|
||||
|
||||
const model = new Model({
|
||||
id: 'root',
|
||||
children: [{
|
||||
id: 'a', children: [{
|
||||
id: 'aa'
|
||||
}]
|
||||
}]
|
||||
});
|
||||
|
||||
const tree = new AsyncDataTree<Element, Element>('test', container, new VirtualDelegate(), [new Renderer()], dataSource, { identityProvider: new IdentityProvider() });
|
||||
tree.layout(200);
|
||||
|
||||
const pSetInput = tree.setInput(model.root);
|
||||
calls.pop()!(); // resolve getChildren(root)
|
||||
await pSetInput;
|
||||
|
||||
const pUpdateChildrenA = tree.updateChildren(model.get('a'));
|
||||
const pExpandA = tree.expand(model.get('a'));
|
||||
assert.equal(calls.length, 1, 'expand(a) still hasn\'t called getChildren(a)');
|
||||
|
||||
calls.pop()!();
|
||||
assert.equal(calls.length, 0, 'no pending getChildren calls');
|
||||
|
||||
await pUpdateChildrenA;
|
||||
assert.equal(calls.length, 0, 'expand(a) should not have forced a second refresh');
|
||||
|
||||
const result = await pExpandA;
|
||||
assert.equal(result, true, 'expand(a) should be done');
|
||||
});
|
||||
|
||||
test('issue #80098 - first expand should call getChildren', async () => {
|
||||
const container = document.createElement('div');
|
||||
|
||||
const calls: Function[] = [];
|
||||
const dataSource = new class implements IAsyncDataSource<Element, Element> {
|
||||
hasChildren(element: Element): boolean {
|
||||
return !!element.children && element.children.length > 0;
|
||||
}
|
||||
getChildren(element: Element): Promise<Element[]> {
|
||||
return new Promise(c => calls.push(() => c(element.children || [])));
|
||||
}
|
||||
};
|
||||
|
||||
const model = new Model({
|
||||
id: 'root',
|
||||
children: [{
|
||||
id: 'a', children: [{
|
||||
id: 'aa'
|
||||
}]
|
||||
}]
|
||||
});
|
||||
|
||||
const tree = new AsyncDataTree<Element, Element>('test', container, new VirtualDelegate(), [new Renderer()], dataSource, { identityProvider: new IdentityProvider() });
|
||||
tree.layout(200);
|
||||
|
||||
const pSetInput = tree.setInput(model.root);
|
||||
calls.pop()!(); // resolve getChildren(root)
|
||||
await pSetInput;
|
||||
|
||||
const pExpandA = tree.expand(model.get('a'));
|
||||
assert.equal(calls.length, 1, 'expand(a) should\'ve called getChildren(a)');
|
||||
|
||||
let race = await Promise.race([pExpandA.then(() => 'expand'), timeout(1).then(() => 'timeout')]);
|
||||
assert.equal(race, 'timeout', 'expand(a) should not be yet done');
|
||||
|
||||
calls.pop()!();
|
||||
assert.equal(calls.length, 0, 'no pending getChildren calls');
|
||||
|
||||
race = await Promise.race([pExpandA.then(() => 'expand'), timeout(1).then(() => 'timeout')]);
|
||||
assert.equal(race, 'expand', 'expand(a) should now be done');
|
||||
});
|
||||
|
||||
test('issue #78388 - tree should react to hasChildren toggles', async () => {
|
||||
const container = document.createElement('div');
|
||||
const model = new Model({
|
||||
id: 'root',
|
||||
children: [{
|
||||
id: 'a'
|
||||
}]
|
||||
});
|
||||
|
||||
const tree = new AsyncDataTree<Element, Element>('test', container, new VirtualDelegate(), [new Renderer()], new DataSource(), { identityProvider: new IdentityProvider() });
|
||||
tree.layout(200);
|
||||
|
||||
await tree.setInput(model.root);
|
||||
assert.equal(container.querySelectorAll('.monaco-list-row').length, 1);
|
||||
|
||||
let twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement;
|
||||
assert(!twistie.classList.contains('collapsible'));
|
||||
assert(!twistie.classList.contains('collapsed'));
|
||||
|
||||
model.get('a').children = [{ id: 'aa' }];
|
||||
await tree.updateChildren(model.get('a'), false);
|
||||
assert.equal(container.querySelectorAll('.monaco-list-row').length, 1);
|
||||
twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement;
|
||||
assert(twistie.classList.contains('collapsible'));
|
||||
assert(twistie.classList.contains('collapsed'));
|
||||
|
||||
model.get('a').children = [];
|
||||
await tree.updateChildren(model.get('a'), false);
|
||||
assert.equal(container.querySelectorAll('.monaco-list-row').length, 1);
|
||||
twistie = container.querySelector('.monaco-list-row:first-child .monaco-tl-twistie') as HTMLElement;
|
||||
assert(!twistie.classList.contains('collapsible'));
|
||||
assert(!twistie.classList.contains('collapsed'));
|
||||
});
|
||||
|
||||
test('issues #84569, #82629 - rerender', async () => {
|
||||
const container = document.createElement('div');
|
||||
const model = new Model({
|
||||
id: 'root',
|
||||
children: [{
|
||||
id: 'a',
|
||||
children: [{
|
||||
id: 'b',
|
||||
suffix: '1'
|
||||
}]
|
||||
}]
|
||||
});
|
||||
|
||||
const tree = new AsyncDataTree<Element, Element>('test', container, new VirtualDelegate(), [new Renderer()], new DataSource(), { identityProvider: new IdentityProvider() });
|
||||
tree.layout(200);
|
||||
|
||||
await tree.setInput(model.root);
|
||||
await tree.expand(model.get('a'));
|
||||
assert.deepEqual(Array.from(container.querySelectorAll('.monaco-list-row')).map(e => e.textContent), ['a', 'b1']);
|
||||
|
||||
const a = model.get('a');
|
||||
const b = model.get('b');
|
||||
a.children?.splice(0, 1, { id: 'b', suffix: '2' });
|
||||
|
||||
await Promise.all([
|
||||
tree.updateChildren(a, true, true),
|
||||
tree.updateChildren(b, true, true)
|
||||
]);
|
||||
|
||||
assert.deepEqual(Array.from(container.querySelectorAll('.monaco-list-row')).map(e => e.textContent), ['a', 'b2']);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,431 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { compress, ICompressedTreeElement, ICompressedTreeNode, decompress, CompressedObjectTreeModel } from 'vs/base/browser/ui/tree/compressedObjectTreeModel';
|
||||
import { Iterable } from 'vs/base/common/iterator';
|
||||
import { ITreeNode } from 'vs/base/browser/ui/tree/tree';
|
||||
import { IList } from 'vs/base/browser/ui/tree/indexTreeModel';
|
||||
|
||||
interface IResolvedCompressedTreeElement<T> extends ICompressedTreeElement<T> {
|
||||
readonly element: T;
|
||||
readonly children?: ICompressedTreeElement<T>[];
|
||||
}
|
||||
|
||||
function resolve<T>(treeElement: ICompressedTreeElement<T>): IResolvedCompressedTreeElement<T> {
|
||||
const result: any = { element: treeElement.element };
|
||||
const children = [...Iterable.map(Iterable.from(treeElement.children), resolve)];
|
||||
|
||||
if (treeElement.incompressible) {
|
||||
result.incompressible = true;
|
||||
}
|
||||
|
||||
if (children.length > 0) {
|
||||
result.children = children;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
suite('CompressedObjectTree', function () {
|
||||
|
||||
suite('compress & decompress', function () {
|
||||
|
||||
test('small', function () {
|
||||
const decompressed: ICompressedTreeElement<number> = { element: 1 };
|
||||
const compressed: IResolvedCompressedTreeElement<ICompressedTreeNode<number>> =
|
||||
{ element: { elements: [1], incompressible: false } };
|
||||
|
||||
assert.deepEqual(resolve(compress(decompressed)), compressed);
|
||||
assert.deepEqual(resolve(decompress(compressed)), decompressed);
|
||||
});
|
||||
|
||||
test('no compression', function () {
|
||||
const decompressed: ICompressedTreeElement<number> = {
|
||||
element: 1, children: [
|
||||
{ element: 11 },
|
||||
{ element: 12 },
|
||||
{ element: 13 }
|
||||
]
|
||||
};
|
||||
|
||||
const compressed: IResolvedCompressedTreeElement<ICompressedTreeNode<number>> = {
|
||||
element: { elements: [1], incompressible: false },
|
||||
children: [
|
||||
{ element: { elements: [11], incompressible: false } },
|
||||
{ element: { elements: [12], incompressible: false } },
|
||||
{ element: { elements: [13], incompressible: false } }
|
||||
]
|
||||
};
|
||||
|
||||
assert.deepEqual(resolve(compress(decompressed)), compressed);
|
||||
assert.deepEqual(resolve(decompress(compressed)), decompressed);
|
||||
});
|
||||
|
||||
test('single hierarchy', function () {
|
||||
const decompressed: ICompressedTreeElement<number> = {
|
||||
element: 1, children: [
|
||||
{
|
||||
element: 11, children: [
|
||||
{
|
||||
element: 111, children: [
|
||||
{ element: 1111 }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const compressed: IResolvedCompressedTreeElement<ICompressedTreeNode<number>> = {
|
||||
element: { elements: [1, 11, 111, 1111], incompressible: false }
|
||||
};
|
||||
|
||||
assert.deepEqual(resolve(compress(decompressed)), compressed);
|
||||
assert.deepEqual(resolve(decompress(compressed)), decompressed);
|
||||
});
|
||||
|
||||
test('deep compression', function () {
|
||||
const decompressed: ICompressedTreeElement<number> = {
|
||||
element: 1, children: [
|
||||
{
|
||||
element: 11, children: [
|
||||
{
|
||||
element: 111, children: [
|
||||
{ element: 1111 },
|
||||
{ element: 1112 },
|
||||
{ element: 1113 },
|
||||
{ element: 1114 },
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const compressed: IResolvedCompressedTreeElement<ICompressedTreeNode<number>> = {
|
||||
element: { elements: [1, 11, 111], incompressible: false },
|
||||
children: [
|
||||
{ element: { elements: [1111], incompressible: false } },
|
||||
{ element: { elements: [1112], incompressible: false } },
|
||||
{ element: { elements: [1113], incompressible: false } },
|
||||
{ element: { elements: [1114], incompressible: false } },
|
||||
]
|
||||
};
|
||||
|
||||
assert.deepEqual(resolve(compress(decompressed)), compressed);
|
||||
assert.deepEqual(resolve(decompress(compressed)), decompressed);
|
||||
});
|
||||
|
||||
test('double deep compression', function () {
|
||||
const decompressed: ICompressedTreeElement<number> = {
|
||||
element: 1, children: [
|
||||
{
|
||||
element: 11, children: [
|
||||
{
|
||||
element: 111, children: [
|
||||
{ element: 1112 },
|
||||
{ element: 1113 },
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
element: 12, children: [
|
||||
{
|
||||
element: 121, children: [
|
||||
{ element: 1212 },
|
||||
{ element: 1213 },
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const compressed: IResolvedCompressedTreeElement<ICompressedTreeNode<number>> = {
|
||||
element: { elements: [1], incompressible: false },
|
||||
children: [
|
||||
{
|
||||
element: { elements: [11, 111], incompressible: false },
|
||||
children: [
|
||||
{ element: { elements: [1112], incompressible: false } },
|
||||
{ element: { elements: [1113], incompressible: false } },
|
||||
]
|
||||
},
|
||||
{
|
||||
element: { elements: [12, 121], incompressible: false },
|
||||
children: [
|
||||
{ element: { elements: [1212], incompressible: false } },
|
||||
{ element: { elements: [1213], incompressible: false } },
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
assert.deepEqual(resolve(compress(decompressed)), compressed);
|
||||
assert.deepEqual(resolve(decompress(compressed)), decompressed);
|
||||
});
|
||||
|
||||
test('incompressible leaf', function () {
|
||||
const decompressed: ICompressedTreeElement<number> = {
|
||||
element: 1, children: [
|
||||
{
|
||||
element: 11, children: [
|
||||
{
|
||||
element: 111, children: [
|
||||
{ element: 1111, incompressible: true }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const compressed: IResolvedCompressedTreeElement<ICompressedTreeNode<number>> = {
|
||||
element: { elements: [1, 11, 111], incompressible: false },
|
||||
children: [
|
||||
{ element: { elements: [1111], incompressible: true } }
|
||||
]
|
||||
};
|
||||
|
||||
assert.deepEqual(resolve(compress(decompressed)), compressed);
|
||||
assert.deepEqual(resolve(decompress(compressed)), decompressed);
|
||||
});
|
||||
|
||||
test('incompressible branch', function () {
|
||||
const decompressed: ICompressedTreeElement<number> = {
|
||||
element: 1, children: [
|
||||
{
|
||||
element: 11, children: [
|
||||
{
|
||||
element: 111, incompressible: true, children: [
|
||||
{ element: 1111 }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const compressed: IResolvedCompressedTreeElement<ICompressedTreeNode<number>> = {
|
||||
element: { elements: [1, 11], incompressible: false },
|
||||
children: [
|
||||
{ element: { elements: [111, 1111], incompressible: true } }
|
||||
]
|
||||
};
|
||||
|
||||
assert.deepEqual(resolve(compress(decompressed)), compressed);
|
||||
assert.deepEqual(resolve(decompress(compressed)), decompressed);
|
||||
});
|
||||
|
||||
test('incompressible chain', function () {
|
||||
const decompressed: ICompressedTreeElement<number> = {
|
||||
element: 1, children: [
|
||||
{
|
||||
element: 11, children: [
|
||||
{
|
||||
element: 111, incompressible: true, children: [
|
||||
{ element: 1111, incompressible: true }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const compressed: IResolvedCompressedTreeElement<ICompressedTreeNode<number>> = {
|
||||
element: { elements: [1, 11], incompressible: false },
|
||||
children: [
|
||||
{
|
||||
element: { elements: [111], incompressible: true },
|
||||
children: [
|
||||
{ element: { elements: [1111], incompressible: true } }
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
assert.deepEqual(resolve(compress(decompressed)), compressed);
|
||||
assert.deepEqual(resolve(decompress(compressed)), decompressed);
|
||||
});
|
||||
|
||||
test('incompressible tree', function () {
|
||||
const decompressed: ICompressedTreeElement<number> = {
|
||||
element: 1, children: [
|
||||
{
|
||||
element: 11, incompressible: true, children: [
|
||||
{
|
||||
element: 111, incompressible: true, children: [
|
||||
{ element: 1111, incompressible: true }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const compressed: IResolvedCompressedTreeElement<ICompressedTreeNode<number>> = {
|
||||
element: { elements: [1], incompressible: false },
|
||||
children: [
|
||||
{
|
||||
element: { elements: [11], incompressible: true },
|
||||
children: [
|
||||
{
|
||||
element: { elements: [111], incompressible: true },
|
||||
children: [
|
||||
{ element: { elements: [1111], incompressible: true } }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
assert.deepEqual(resolve(compress(decompressed)), compressed);
|
||||
assert.deepEqual(resolve(decompress(compressed)), decompressed);
|
||||
});
|
||||
});
|
||||
|
||||
function toList<T>(arr: T[]): IList<T> {
|
||||
return {
|
||||
splice(start: number, deleteCount: number, elements: T[]): void {
|
||||
arr.splice(start, deleteCount, ...elements);
|
||||
},
|
||||
updateElementHeight() { }
|
||||
};
|
||||
}
|
||||
|
||||
function toArray<T>(list: ITreeNode<ICompressedTreeNode<T>>[]): T[][] {
|
||||
return list.map(i => i.element.elements);
|
||||
}
|
||||
|
||||
suite('CompressedObjectTreeModel', function () {
|
||||
|
||||
test('ctor', () => {
|
||||
const list: ITreeNode<ICompressedTreeNode<number>>[] = [];
|
||||
const model = new CompressedObjectTreeModel<number>('test', toList(list));
|
||||
assert(model);
|
||||
assert.equal(list.length, 0);
|
||||
assert.equal(model.size, 0);
|
||||
});
|
||||
|
||||
test('flat', () => {
|
||||
const list: ITreeNode<ICompressedTreeNode<number>>[] = [];
|
||||
const model = new CompressedObjectTreeModel<number>('test', toList(list));
|
||||
|
||||
model.setChildren(null, [
|
||||
{ element: 0 },
|
||||
{ element: 1 },
|
||||
{ element: 2 }
|
||||
]);
|
||||
|
||||
assert.deepEqual(toArray(list), [[0], [1], [2]]);
|
||||
assert.equal(model.size, 3);
|
||||
|
||||
model.setChildren(null, [
|
||||
{ element: 3 },
|
||||
{ element: 4 },
|
||||
{ element: 5 },
|
||||
]);
|
||||
|
||||
assert.deepEqual(toArray(list), [[3], [4], [5]]);
|
||||
assert.equal(model.size, 3);
|
||||
|
||||
model.setChildren(null);
|
||||
assert.deepEqual(toArray(list), []);
|
||||
assert.equal(model.size, 0);
|
||||
});
|
||||
|
||||
test('nested', () => {
|
||||
const list: ITreeNode<ICompressedTreeNode<number>>[] = [];
|
||||
const model = new CompressedObjectTreeModel<number>('test', toList(list));
|
||||
|
||||
model.setChildren(null, [
|
||||
{
|
||||
element: 0, children: [
|
||||
{ element: 10 },
|
||||
{ element: 11 },
|
||||
{ element: 12 },
|
||||
]
|
||||
},
|
||||
{ element: 1 },
|
||||
{ element: 2 }
|
||||
]);
|
||||
|
||||
assert.deepEqual(toArray(list), [[0], [10], [11], [12], [1], [2]]);
|
||||
assert.equal(model.size, 6);
|
||||
|
||||
model.setChildren(12, [
|
||||
{ element: 120 },
|
||||
{ element: 121 }
|
||||
]);
|
||||
|
||||
assert.deepEqual(toArray(list), [[0], [10], [11], [12], [120], [121], [1], [2]]);
|
||||
assert.equal(model.size, 8);
|
||||
|
||||
model.setChildren(0);
|
||||
assert.deepEqual(toArray(list), [[0], [1], [2]]);
|
||||
assert.equal(model.size, 3);
|
||||
|
||||
model.setChildren(null);
|
||||
assert.deepEqual(toArray(list), []);
|
||||
assert.equal(model.size, 0);
|
||||
});
|
||||
|
||||
test('compressed', () => {
|
||||
const list: ITreeNode<ICompressedTreeNode<number>>[] = [];
|
||||
const model = new CompressedObjectTreeModel<number>('test', toList(list));
|
||||
|
||||
model.setChildren(null, [
|
||||
{
|
||||
element: 1, children: [{
|
||||
element: 11, children: [{
|
||||
element: 111, children: [
|
||||
{ element: 1111 },
|
||||
{ element: 1112 },
|
||||
{ element: 1113 },
|
||||
]
|
||||
}]
|
||||
}]
|
||||
}
|
||||
]);
|
||||
|
||||
assert.deepEqual(toArray(list), [[1, 11, 111], [1111], [1112], [1113]]);
|
||||
assert.equal(model.size, 6);
|
||||
|
||||
model.setChildren(11, [
|
||||
{ element: 111 },
|
||||
{ element: 112 },
|
||||
{ element: 113 },
|
||||
]);
|
||||
|
||||
assert.deepEqual(toArray(list), [[1, 11], [111], [112], [113]]);
|
||||
assert.equal(model.size, 5);
|
||||
|
||||
model.setChildren(113, [
|
||||
{ element: 1131 }
|
||||
]);
|
||||
|
||||
assert.deepEqual(toArray(list), [[1, 11], [111], [112], [113, 1131]]);
|
||||
assert.equal(model.size, 6);
|
||||
|
||||
model.setChildren(1131, [
|
||||
{ element: 1132 }
|
||||
]);
|
||||
|
||||
assert.deepEqual(toArray(list), [[1, 11], [111], [112], [113, 1131, 1132]]);
|
||||
assert.equal(model.size, 7);
|
||||
|
||||
model.setChildren(1131, [
|
||||
{ element: 1132 },
|
||||
{ element: 1133 },
|
||||
]);
|
||||
|
||||
assert.deepEqual(toArray(list), [[1, 11], [111], [112], [113, 1131], [1132], [1133]]);
|
||||
assert.equal(model.size, 8);
|
||||
});
|
||||
});
|
||||
});
|
||||
148
lib/vscode/src/vs/base/test/browser/ui/tree/dataTree.test.ts
Normal file
148
lib/vscode/src/vs/base/test/browser/ui/tree/dataTree.test.ts
Normal file
@@ -0,0 +1,148 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { ITreeNode, ITreeRenderer, IDataSource } from 'vs/base/browser/ui/tree/tree';
|
||||
import { IListVirtualDelegate, IIdentityProvider } from 'vs/base/browser/ui/list/list';
|
||||
import { DataTree } from 'vs/base/browser/ui/tree/dataTree';
|
||||
|
||||
interface E {
|
||||
value: number;
|
||||
children?: E[];
|
||||
}
|
||||
|
||||
suite('DataTree', function () {
|
||||
let tree: DataTree<E, E>;
|
||||
|
||||
const root: E = {
|
||||
value: -1,
|
||||
children: [
|
||||
{ value: 0, children: [{ value: 10 }, { value: 11 }, { value: 12 }] },
|
||||
{ value: 1 },
|
||||
{ value: 2 },
|
||||
]
|
||||
};
|
||||
|
||||
const empty: E = {
|
||||
value: -1,
|
||||
children: []
|
||||
};
|
||||
|
||||
setup(() => {
|
||||
const container = document.createElement('div');
|
||||
container.style.width = '200px';
|
||||
container.style.height = '200px';
|
||||
|
||||
const delegate = new class implements IListVirtualDelegate<E> {
|
||||
getHeight() { return 20; }
|
||||
getTemplateId(): string { return 'default'; }
|
||||
};
|
||||
|
||||
const renderer = new class implements ITreeRenderer<E, void, HTMLElement> {
|
||||
readonly templateId = 'default';
|
||||
renderTemplate(container: HTMLElement): HTMLElement {
|
||||
return container;
|
||||
}
|
||||
renderElement(element: ITreeNode<E, void>, index: number, templateData: HTMLElement): void {
|
||||
templateData.textContent = `${element.element.value}`;
|
||||
}
|
||||
disposeTemplate(): void { }
|
||||
};
|
||||
|
||||
const dataSource = new class implements IDataSource<E, E> {
|
||||
getChildren(element: E): E[] {
|
||||
return element.children || [];
|
||||
}
|
||||
};
|
||||
|
||||
const identityProvider = new class implements IIdentityProvider<E> {
|
||||
getId(element: E): { toString(): string; } {
|
||||
return `${element.value}`;
|
||||
}
|
||||
};
|
||||
|
||||
tree = new DataTree<E, E>('test', container, delegate, [renderer], dataSource, {
|
||||
identityProvider
|
||||
});
|
||||
tree.layout(200);
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
tree.dispose();
|
||||
});
|
||||
|
||||
test('view state is lost implicitly', () => {
|
||||
tree.setInput(root);
|
||||
|
||||
let navigator = tree.navigate();
|
||||
assert.equal(navigator.next()!.value, 0);
|
||||
assert.equal(navigator.next()!.value, 10);
|
||||
assert.equal(navigator.next()!.value, 11);
|
||||
assert.equal(navigator.next()!.value, 12);
|
||||
assert.equal(navigator.next()!.value, 1);
|
||||
assert.equal(navigator.next()!.value, 2);
|
||||
assert.equal(navigator.next()!, null);
|
||||
|
||||
tree.collapse(root.children![0]);
|
||||
navigator = tree.navigate();
|
||||
assert.equal(navigator.next()!.value, 0);
|
||||
assert.equal(navigator.next()!.value, 1);
|
||||
assert.equal(navigator.next()!.value, 2);
|
||||
assert.equal(navigator.next()!, null);
|
||||
|
||||
tree.setSelection([root.children![1]]);
|
||||
tree.setFocus([root.children![2]]);
|
||||
|
||||
tree.setInput(empty);
|
||||
tree.setInput(root);
|
||||
navigator = tree.navigate();
|
||||
assert.equal(navigator.next()!.value, 0);
|
||||
assert.equal(navigator.next()!.value, 10);
|
||||
assert.equal(navigator.next()!.value, 11);
|
||||
assert.equal(navigator.next()!.value, 12);
|
||||
assert.equal(navigator.next()!.value, 1);
|
||||
assert.equal(navigator.next()!.value, 2);
|
||||
assert.equal(navigator.next()!, null);
|
||||
|
||||
assert.deepEqual(tree.getSelection(), []);
|
||||
assert.deepEqual(tree.getFocus(), []);
|
||||
});
|
||||
|
||||
test('view state can be preserved', () => {
|
||||
tree.setInput(root);
|
||||
|
||||
let navigator = tree.navigate();
|
||||
assert.equal(navigator.next()!.value, 0);
|
||||
assert.equal(navigator.next()!.value, 10);
|
||||
assert.equal(navigator.next()!.value, 11);
|
||||
assert.equal(navigator.next()!.value, 12);
|
||||
assert.equal(navigator.next()!.value, 1);
|
||||
assert.equal(navigator.next()!.value, 2);
|
||||
assert.equal(navigator.next()!, null);
|
||||
|
||||
tree.collapse(root.children![0]);
|
||||
navigator = tree.navigate();
|
||||
assert.equal(navigator.next()!.value, 0);
|
||||
assert.equal(navigator.next()!.value, 1);
|
||||
assert.equal(navigator.next()!.value, 2);
|
||||
assert.equal(navigator.next()!, null);
|
||||
|
||||
tree.setSelection([root.children![1]]);
|
||||
tree.setFocus([root.children![2]]);
|
||||
|
||||
const viewState = tree.getViewState();
|
||||
|
||||
tree.setInput(empty);
|
||||
tree.setInput(root, viewState);
|
||||
navigator = tree.navigate();
|
||||
assert.equal(navigator.next()!.value, 0);
|
||||
assert.equal(navigator.next()!.value, 1);
|
||||
assert.equal(navigator.next()!.value, 2);
|
||||
assert.equal(navigator.next()!, null);
|
||||
|
||||
assert.deepEqual(tree.getSelection(), [root.children![1]]);
|
||||
assert.deepEqual(tree.getFocus(), [root.children![2]]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,759 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { ITreeNode, ITreeFilter, TreeVisibility } from 'vs/base/browser/ui/tree/tree';
|
||||
import { IndexTreeModel, IIndexTreeNode, IList } from 'vs/base/browser/ui/tree/indexTreeModel';
|
||||
|
||||
function toList<T>(arr: T[]): IList<T> {
|
||||
return {
|
||||
splice(start: number, deleteCount: number, elements: T[]): void {
|
||||
arr.splice(start, deleteCount, ...elements);
|
||||
},
|
||||
updateElementHeight() { }
|
||||
};
|
||||
}
|
||||
|
||||
function toArray<T>(list: ITreeNode<T>[]): T[] {
|
||||
return list.map(i => i.element);
|
||||
}
|
||||
|
||||
suite('IndexTreeModel', function () {
|
||||
|
||||
test('ctor', () => {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new IndexTreeModel<number>('test', toList(list), -1);
|
||||
assert(model);
|
||||
assert.equal(list.length, 0);
|
||||
});
|
||||
|
||||
test('insert', () => {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new IndexTreeModel<number>('test', toList(list), -1);
|
||||
|
||||
model.splice([0], 0, [
|
||||
{ element: 0 },
|
||||
{ element: 1 },
|
||||
{ element: 2 }
|
||||
]);
|
||||
|
||||
assert.deepEqual(list.length, 3);
|
||||
assert.deepEqual(list[0].element, 0);
|
||||
assert.deepEqual(list[0].collapsed, false);
|
||||
assert.deepEqual(list[0].depth, 1);
|
||||
assert.deepEqual(list[1].element, 1);
|
||||
assert.deepEqual(list[1].collapsed, false);
|
||||
assert.deepEqual(list[1].depth, 1);
|
||||
assert.deepEqual(list[2].element, 2);
|
||||
assert.deepEqual(list[2].collapsed, false);
|
||||
assert.deepEqual(list[2].depth, 1);
|
||||
});
|
||||
|
||||
test('deep insert', function () {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new IndexTreeModel<number>('test', toList(list), -1);
|
||||
|
||||
model.splice([0], 0, [
|
||||
{
|
||||
element: 0, children: [
|
||||
{ element: 10 },
|
||||
{ element: 11 },
|
||||
{ element: 12 },
|
||||
]
|
||||
},
|
||||
{ element: 1 },
|
||||
{ element: 2 }
|
||||
]);
|
||||
|
||||
assert.deepEqual(list.length, 6);
|
||||
assert.deepEqual(list[0].element, 0);
|
||||
assert.deepEqual(list[0].collapsed, false);
|
||||
assert.deepEqual(list[0].depth, 1);
|
||||
assert.deepEqual(list[1].element, 10);
|
||||
assert.deepEqual(list[1].collapsed, false);
|
||||
assert.deepEqual(list[1].depth, 2);
|
||||
assert.deepEqual(list[2].element, 11);
|
||||
assert.deepEqual(list[2].collapsed, false);
|
||||
assert.deepEqual(list[2].depth, 2);
|
||||
assert.deepEqual(list[3].element, 12);
|
||||
assert.deepEqual(list[3].collapsed, false);
|
||||
assert.deepEqual(list[3].depth, 2);
|
||||
assert.deepEqual(list[4].element, 1);
|
||||
assert.deepEqual(list[4].collapsed, false);
|
||||
assert.deepEqual(list[4].depth, 1);
|
||||
assert.deepEqual(list[5].element, 2);
|
||||
assert.deepEqual(list[5].collapsed, false);
|
||||
assert.deepEqual(list[5].depth, 1);
|
||||
});
|
||||
|
||||
test('deep insert collapsed', function () {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new IndexTreeModel<number>('test', toList(list), -1);
|
||||
|
||||
model.splice([0], 0, [
|
||||
{
|
||||
element: 0, collapsed: true, children: [
|
||||
{ element: 10 },
|
||||
{ element: 11 },
|
||||
{ element: 12 },
|
||||
]
|
||||
},
|
||||
{ element: 1 },
|
||||
{ element: 2 }
|
||||
]);
|
||||
|
||||
assert.deepEqual(list.length, 3);
|
||||
assert.deepEqual(list[0].element, 0);
|
||||
assert.deepEqual(list[0].collapsed, true);
|
||||
assert.deepEqual(list[0].depth, 1);
|
||||
assert.deepEqual(list[1].element, 1);
|
||||
assert.deepEqual(list[1].collapsed, false);
|
||||
assert.deepEqual(list[1].depth, 1);
|
||||
assert.deepEqual(list[2].element, 2);
|
||||
assert.deepEqual(list[2].collapsed, false);
|
||||
assert.deepEqual(list[2].depth, 1);
|
||||
});
|
||||
|
||||
test('delete', () => {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new IndexTreeModel<number>('test', toList(list), -1);
|
||||
|
||||
model.splice([0], 0, [
|
||||
{ element: 0 },
|
||||
{ element: 1 },
|
||||
{ element: 2 }
|
||||
]);
|
||||
|
||||
assert.deepEqual(list.length, 3);
|
||||
|
||||
model.splice([1], 1);
|
||||
assert.deepEqual(list.length, 2);
|
||||
assert.deepEqual(list[0].element, 0);
|
||||
assert.deepEqual(list[0].collapsed, false);
|
||||
assert.deepEqual(list[0].depth, 1);
|
||||
assert.deepEqual(list[1].element, 2);
|
||||
assert.deepEqual(list[1].collapsed, false);
|
||||
assert.deepEqual(list[1].depth, 1);
|
||||
|
||||
model.splice([0], 2);
|
||||
assert.deepEqual(list.length, 0);
|
||||
});
|
||||
|
||||
test('nested delete', function () {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new IndexTreeModel<number>('test', toList(list), -1);
|
||||
|
||||
model.splice([0], 0, [
|
||||
{
|
||||
element: 0, children: [
|
||||
{ element: 10 },
|
||||
{ element: 11 },
|
||||
{ element: 12 },
|
||||
]
|
||||
},
|
||||
{ element: 1 },
|
||||
{ element: 2 }
|
||||
]);
|
||||
|
||||
assert.deepEqual(list.length, 6);
|
||||
|
||||
model.splice([1], 2);
|
||||
assert.deepEqual(list.length, 4);
|
||||
assert.deepEqual(list[0].element, 0);
|
||||
assert.deepEqual(list[0].collapsed, false);
|
||||
assert.deepEqual(list[0].depth, 1);
|
||||
assert.deepEqual(list[1].element, 10);
|
||||
assert.deepEqual(list[1].collapsed, false);
|
||||
assert.deepEqual(list[1].depth, 2);
|
||||
assert.deepEqual(list[2].element, 11);
|
||||
assert.deepEqual(list[2].collapsed, false);
|
||||
assert.deepEqual(list[2].depth, 2);
|
||||
assert.deepEqual(list[3].element, 12);
|
||||
assert.deepEqual(list[3].collapsed, false);
|
||||
assert.deepEqual(list[3].depth, 2);
|
||||
});
|
||||
|
||||
test('deep delete', function () {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new IndexTreeModel<number>('test', toList(list), -1);
|
||||
|
||||
model.splice([0], 0, [
|
||||
{
|
||||
element: 0, children: [
|
||||
{ element: 10 },
|
||||
{ element: 11 },
|
||||
{ element: 12 },
|
||||
]
|
||||
},
|
||||
{ element: 1 },
|
||||
{ element: 2 }
|
||||
]);
|
||||
|
||||
assert.deepEqual(list.length, 6);
|
||||
|
||||
model.splice([0], 1);
|
||||
assert.deepEqual(list.length, 2);
|
||||
assert.deepEqual(list[0].element, 1);
|
||||
assert.deepEqual(list[0].collapsed, false);
|
||||
assert.deepEqual(list[0].depth, 1);
|
||||
assert.deepEqual(list[1].element, 2);
|
||||
assert.deepEqual(list[1].collapsed, false);
|
||||
assert.deepEqual(list[1].depth, 1);
|
||||
});
|
||||
|
||||
test('hidden delete', function () {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new IndexTreeModel<number>('test', toList(list), -1);
|
||||
|
||||
model.splice([0], 0, [
|
||||
{
|
||||
element: 0, collapsed: true, children: [
|
||||
{ element: 10 },
|
||||
{ element: 11 },
|
||||
{ element: 12 },
|
||||
]
|
||||
},
|
||||
{ element: 1 },
|
||||
{ element: 2 }
|
||||
]);
|
||||
|
||||
assert.deepEqual(list.length, 3);
|
||||
|
||||
model.splice([0, 1], 1);
|
||||
assert.deepEqual(list.length, 3);
|
||||
|
||||
model.splice([0, 0], 2);
|
||||
assert.deepEqual(list.length, 3);
|
||||
});
|
||||
|
||||
test('collapse', () => {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new IndexTreeModel<number>('test', toList(list), -1);
|
||||
|
||||
model.splice([0], 0, [
|
||||
{
|
||||
element: 0, children: [
|
||||
{ element: 10 },
|
||||
{ element: 11 },
|
||||
{ element: 12 },
|
||||
]
|
||||
},
|
||||
{ element: 1 },
|
||||
{ element: 2 }
|
||||
]);
|
||||
|
||||
assert.deepEqual(list.length, 6);
|
||||
|
||||
model.setCollapsed([0], true);
|
||||
assert.deepEqual(list.length, 3);
|
||||
assert.deepEqual(list[0].element, 0);
|
||||
assert.deepEqual(list[0].collapsed, true);
|
||||
assert.deepEqual(list[0].depth, 1);
|
||||
assert.deepEqual(list[1].element, 1);
|
||||
assert.deepEqual(list[1].collapsed, false);
|
||||
assert.deepEqual(list[1].depth, 1);
|
||||
assert.deepEqual(list[2].element, 2);
|
||||
assert.deepEqual(list[2].collapsed, false);
|
||||
assert.deepEqual(list[2].depth, 1);
|
||||
});
|
||||
|
||||
test('expand', () => {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new IndexTreeModel<number>('test', toList(list), -1);
|
||||
|
||||
model.splice([0], 0, [
|
||||
{
|
||||
element: 0, collapsed: true, children: [
|
||||
{ element: 10 },
|
||||
{ element: 11 },
|
||||
{ element: 12 },
|
||||
]
|
||||
},
|
||||
{ element: 1 },
|
||||
{ element: 2 }
|
||||
]);
|
||||
|
||||
assert.deepEqual(list.length, 3);
|
||||
|
||||
model.setCollapsed([0], false);
|
||||
assert.deepEqual(list.length, 6);
|
||||
assert.deepEqual(list[0].element, 0);
|
||||
assert.deepEqual(list[0].collapsed, false);
|
||||
assert.deepEqual(list[0].depth, 1);
|
||||
assert.deepEqual(list[1].element, 10);
|
||||
assert.deepEqual(list[1].collapsed, false);
|
||||
assert.deepEqual(list[1].depth, 2);
|
||||
assert.deepEqual(list[2].element, 11);
|
||||
assert.deepEqual(list[2].collapsed, false);
|
||||
assert.deepEqual(list[2].depth, 2);
|
||||
assert.deepEqual(list[3].element, 12);
|
||||
assert.deepEqual(list[3].collapsed, false);
|
||||
assert.deepEqual(list[3].depth, 2);
|
||||
assert.deepEqual(list[4].element, 1);
|
||||
assert.deepEqual(list[4].collapsed, false);
|
||||
assert.deepEqual(list[4].depth, 1);
|
||||
assert.deepEqual(list[5].element, 2);
|
||||
assert.deepEqual(list[5].collapsed, false);
|
||||
assert.deepEqual(list[5].depth, 1);
|
||||
});
|
||||
|
||||
test('collapse should recursively adjust visible count', function () {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new IndexTreeModel<number>('test', toList(list), -1);
|
||||
|
||||
model.splice([0], 0, [
|
||||
{
|
||||
element: 1, children: [
|
||||
{
|
||||
element: 11, children: [
|
||||
{ element: 111 }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
element: 2, children: [
|
||||
{ element: 21 }
|
||||
]
|
||||
}
|
||||
]);
|
||||
|
||||
assert.deepEqual(list.length, 5);
|
||||
assert.deepEqual(toArray(list), [1, 11, 111, 2, 21]);
|
||||
|
||||
model.setCollapsed([0, 0], true);
|
||||
assert.deepEqual(list.length, 4);
|
||||
assert.deepEqual(toArray(list), [1, 11, 2, 21]);
|
||||
|
||||
model.setCollapsed([1], true);
|
||||
assert.deepEqual(list.length, 3);
|
||||
assert.deepEqual(toArray(list), [1, 11, 2]);
|
||||
});
|
||||
|
||||
test('setCollapsible', () => {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new IndexTreeModel<number>('test', toList(list), -1);
|
||||
|
||||
model.splice([0], 0, [
|
||||
{
|
||||
element: 0, children: [
|
||||
{ element: 10 }
|
||||
]
|
||||
}
|
||||
]);
|
||||
|
||||
assert.deepEqual(list.length, 2);
|
||||
|
||||
model.setCollapsible([0], false);
|
||||
assert.deepEqual(list.length, 2);
|
||||
assert.deepEqual(list[0].element, 0);
|
||||
assert.deepEqual(list[0].collapsible, false);
|
||||
assert.deepEqual(list[0].collapsed, false);
|
||||
assert.deepEqual(list[1].element, 10);
|
||||
assert.deepEqual(list[1].collapsible, false);
|
||||
assert.deepEqual(list[1].collapsed, false);
|
||||
|
||||
assert.deepEqual(model.setCollapsed([0], true), false);
|
||||
assert.deepEqual(list[0].element, 0);
|
||||
assert.deepEqual(list[0].collapsible, false);
|
||||
assert.deepEqual(list[0].collapsed, false);
|
||||
assert.deepEqual(list[1].element, 10);
|
||||
assert.deepEqual(list[1].collapsible, false);
|
||||
assert.deepEqual(list[1].collapsed, false);
|
||||
|
||||
assert.deepEqual(model.setCollapsed([0], false), false);
|
||||
assert.deepEqual(list[0].element, 0);
|
||||
assert.deepEqual(list[0].collapsible, false);
|
||||
assert.deepEqual(list[0].collapsed, false);
|
||||
assert.deepEqual(list[1].element, 10);
|
||||
assert.deepEqual(list[1].collapsible, false);
|
||||
assert.deepEqual(list[1].collapsed, false);
|
||||
|
||||
model.setCollapsible([0], true);
|
||||
assert.deepEqual(list.length, 2);
|
||||
assert.deepEqual(list[0].element, 0);
|
||||
assert.deepEqual(list[0].collapsible, true);
|
||||
assert.deepEqual(list[0].collapsed, false);
|
||||
assert.deepEqual(list[1].element, 10);
|
||||
assert.deepEqual(list[1].collapsible, false);
|
||||
assert.deepEqual(list[1].collapsed, false);
|
||||
|
||||
assert.deepEqual(model.setCollapsed([0], true), true);
|
||||
assert.deepEqual(list.length, 1);
|
||||
assert.deepEqual(list[0].element, 0);
|
||||
assert.deepEqual(list[0].collapsible, true);
|
||||
assert.deepEqual(list[0].collapsed, true);
|
||||
|
||||
assert.deepEqual(model.setCollapsed([0], false), true);
|
||||
assert.deepEqual(list[0].element, 0);
|
||||
assert.deepEqual(list[0].collapsible, true);
|
||||
assert.deepEqual(list[0].collapsed, false);
|
||||
assert.deepEqual(list[1].element, 10);
|
||||
assert.deepEqual(list[1].collapsible, false);
|
||||
assert.deepEqual(list[1].collapsed, false);
|
||||
});
|
||||
|
||||
test('simple filter', function () {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const filter = new class implements ITreeFilter<number> {
|
||||
filter(element: number): TreeVisibility {
|
||||
return element % 2 === 0 ? TreeVisibility.Visible : TreeVisibility.Hidden;
|
||||
}
|
||||
};
|
||||
|
||||
const model = new IndexTreeModel<number>('test', toList(list), -1, { filter });
|
||||
|
||||
model.splice([0], 0, [
|
||||
{
|
||||
element: 0, children: [
|
||||
{ element: 1 },
|
||||
{ element: 2 },
|
||||
{ element: 3 },
|
||||
{ element: 4 },
|
||||
{ element: 5 },
|
||||
{ element: 6 },
|
||||
{ element: 7 }
|
||||
]
|
||||
}
|
||||
]);
|
||||
|
||||
assert.deepEqual(list.length, 4);
|
||||
assert.deepEqual(toArray(list), [0, 2, 4, 6]);
|
||||
|
||||
model.setCollapsed([0], true);
|
||||
assert.deepEqual(toArray(list), [0]);
|
||||
|
||||
model.setCollapsed([0], false);
|
||||
assert.deepEqual(toArray(list), [0, 2, 4, 6]);
|
||||
});
|
||||
|
||||
test('recursive filter on initial model', function () {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const filter = new class implements ITreeFilter<number> {
|
||||
filter(element: number): TreeVisibility {
|
||||
return element === 0 ? TreeVisibility.Recurse : TreeVisibility.Hidden;
|
||||
}
|
||||
};
|
||||
|
||||
const model = new IndexTreeModel<number>('test', toList(list), -1, { filter });
|
||||
|
||||
model.splice([0], 0, [
|
||||
{
|
||||
element: 0, children: [
|
||||
{ element: 1 },
|
||||
{ element: 2 }
|
||||
]
|
||||
}
|
||||
]);
|
||||
|
||||
assert.deepEqual(toArray(list), []);
|
||||
});
|
||||
|
||||
test('refilter', function () {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
let shouldFilter = false;
|
||||
const filter = new class implements ITreeFilter<number> {
|
||||
filter(element: number): TreeVisibility {
|
||||
return (!shouldFilter || element % 2 === 0) ? TreeVisibility.Visible : TreeVisibility.Hidden;
|
||||
}
|
||||
};
|
||||
|
||||
const model = new IndexTreeModel<number>('test', toList(list), -1, { filter });
|
||||
|
||||
model.splice([0], 0, [
|
||||
{
|
||||
element: 0, children: [
|
||||
{ element: 1 },
|
||||
{ element: 2 },
|
||||
{ element: 3 },
|
||||
{ element: 4 },
|
||||
{ element: 5 },
|
||||
{ element: 6 },
|
||||
{ element: 7 }
|
||||
]
|
||||
},
|
||||
]);
|
||||
|
||||
assert.deepEqual(toArray(list), [0, 1, 2, 3, 4, 5, 6, 7]);
|
||||
|
||||
model.refilter();
|
||||
assert.deepEqual(toArray(list), [0, 1, 2, 3, 4, 5, 6, 7]);
|
||||
|
||||
shouldFilter = true;
|
||||
model.refilter();
|
||||
assert.deepEqual(toArray(list), [0, 2, 4, 6]);
|
||||
|
||||
shouldFilter = false;
|
||||
model.refilter();
|
||||
assert.deepEqual(toArray(list), [0, 1, 2, 3, 4, 5, 6, 7]);
|
||||
});
|
||||
|
||||
test('recursive filter', function () {
|
||||
const list: ITreeNode<string>[] = [];
|
||||
let query = new RegExp('');
|
||||
const filter = new class implements ITreeFilter<string> {
|
||||
filter(element: string): TreeVisibility {
|
||||
return query.test(element) ? TreeVisibility.Visible : TreeVisibility.Recurse;
|
||||
}
|
||||
};
|
||||
|
||||
const model = new IndexTreeModel<string>('test', toList(list), 'root', { filter });
|
||||
|
||||
model.splice([0], 0, [
|
||||
{
|
||||
element: 'vscode', children: [
|
||||
{ element: '.build' },
|
||||
{ element: 'git' },
|
||||
{
|
||||
element: 'github', children: [
|
||||
{ element: 'calendar.yml' },
|
||||
{ element: 'endgame' },
|
||||
{ element: 'build.js' },
|
||||
]
|
||||
},
|
||||
{
|
||||
element: 'build', children: [
|
||||
{ element: 'lib' },
|
||||
{ element: 'gulpfile.js' }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
]);
|
||||
|
||||
assert.deepEqual(list.length, 10);
|
||||
|
||||
query = /build/;
|
||||
model.refilter();
|
||||
assert.deepEqual(toArray(list), ['vscode', '.build', 'github', 'build.js', 'build']);
|
||||
|
||||
model.setCollapsed([0], true);
|
||||
assert.deepEqual(toArray(list), ['vscode']);
|
||||
|
||||
model.setCollapsed([0], false);
|
||||
assert.deepEqual(toArray(list), ['vscode', '.build', 'github', 'build.js', 'build']);
|
||||
});
|
||||
|
||||
test('recursive filter with collapse', function () {
|
||||
const list: ITreeNode<string>[] = [];
|
||||
let query = new RegExp('');
|
||||
const filter = new class implements ITreeFilter<string> {
|
||||
filter(element: string): TreeVisibility {
|
||||
return query.test(element) ? TreeVisibility.Visible : TreeVisibility.Recurse;
|
||||
}
|
||||
};
|
||||
|
||||
const model = new IndexTreeModel<string>('test', toList(list), 'root', { filter });
|
||||
|
||||
model.splice([0], 0, [
|
||||
{
|
||||
element: 'vscode', children: [
|
||||
{ element: '.build' },
|
||||
{ element: 'git' },
|
||||
{
|
||||
element: 'github', children: [
|
||||
{ element: 'calendar.yml' },
|
||||
{ element: 'endgame' },
|
||||
{ element: 'build.js' },
|
||||
]
|
||||
},
|
||||
{
|
||||
element: 'build', children: [
|
||||
{ element: 'lib' },
|
||||
{ element: 'gulpfile.js' }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
]);
|
||||
|
||||
assert.deepEqual(list.length, 10);
|
||||
|
||||
query = /gulp/;
|
||||
model.refilter();
|
||||
assert.deepEqual(toArray(list), ['vscode', 'build', 'gulpfile.js']);
|
||||
|
||||
model.setCollapsed([0, 3], true);
|
||||
assert.deepEqual(toArray(list), ['vscode', 'build']);
|
||||
|
||||
model.setCollapsed([0], true);
|
||||
assert.deepEqual(toArray(list), ['vscode']);
|
||||
});
|
||||
|
||||
test('recursive filter while collapsed', function () {
|
||||
const list: ITreeNode<string>[] = [];
|
||||
let query = new RegExp('');
|
||||
const filter = new class implements ITreeFilter<string> {
|
||||
filter(element: string): TreeVisibility {
|
||||
return query.test(element) ? TreeVisibility.Visible : TreeVisibility.Recurse;
|
||||
}
|
||||
};
|
||||
|
||||
const model = new IndexTreeModel<string>('test', toList(list), 'root', { filter });
|
||||
|
||||
model.splice([0], 0, [
|
||||
{
|
||||
element: 'vscode', collapsed: true, children: [
|
||||
{ element: '.build' },
|
||||
{ element: 'git' },
|
||||
{
|
||||
element: 'github', children: [
|
||||
{ element: 'calendar.yml' },
|
||||
{ element: 'endgame' },
|
||||
{ element: 'build.js' },
|
||||
]
|
||||
},
|
||||
{
|
||||
element: 'build', children: [
|
||||
{ element: 'lib' },
|
||||
{ element: 'gulpfile.js' }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
]);
|
||||
|
||||
assert.deepEqual(toArray(list), ['vscode']);
|
||||
|
||||
query = /gulp/;
|
||||
model.refilter();
|
||||
assert.deepEqual(toArray(list), ['vscode']);
|
||||
|
||||
model.setCollapsed([0], false);
|
||||
assert.deepEqual(toArray(list), ['vscode', 'build', 'gulpfile.js']);
|
||||
|
||||
model.setCollapsed([0], true);
|
||||
assert.deepEqual(toArray(list), ['vscode']);
|
||||
|
||||
query = new RegExp('');
|
||||
model.refilter();
|
||||
assert.deepEqual(toArray(list), ['vscode']);
|
||||
|
||||
model.setCollapsed([0], false);
|
||||
assert.deepEqual(list.length, 10);
|
||||
});
|
||||
|
||||
suite('getNodeLocation', function () {
|
||||
|
||||
test('simple', function () {
|
||||
const list: IIndexTreeNode<number>[] = [];
|
||||
const model = new IndexTreeModel<number>('test', toList(list), -1);
|
||||
|
||||
model.splice([0], 0, [
|
||||
{
|
||||
element: 0, children: [
|
||||
{ element: 10 },
|
||||
{ element: 11 },
|
||||
{ element: 12 },
|
||||
]
|
||||
},
|
||||
{ element: 1 },
|
||||
{ element: 2 }
|
||||
]);
|
||||
|
||||
assert.deepEqual(model.getNodeLocation(list[0]), [0]);
|
||||
assert.deepEqual(model.getNodeLocation(list[1]), [0, 0]);
|
||||
assert.deepEqual(model.getNodeLocation(list[2]), [0, 1]);
|
||||
assert.deepEqual(model.getNodeLocation(list[3]), [0, 2]);
|
||||
assert.deepEqual(model.getNodeLocation(list[4]), [1]);
|
||||
assert.deepEqual(model.getNodeLocation(list[5]), [2]);
|
||||
});
|
||||
|
||||
test('with filter', function () {
|
||||
const list: IIndexTreeNode<number>[] = [];
|
||||
const filter = new class implements ITreeFilter<number> {
|
||||
filter(element: number): TreeVisibility {
|
||||
return element % 2 === 0 ? TreeVisibility.Visible : TreeVisibility.Hidden;
|
||||
}
|
||||
};
|
||||
|
||||
const model = new IndexTreeModel<number>('test', toList(list), -1, { filter });
|
||||
|
||||
model.splice([0], 0, [
|
||||
{
|
||||
element: 0, children: [
|
||||
{ element: 1 },
|
||||
{ element: 2 },
|
||||
{ element: 3 },
|
||||
{ element: 4 },
|
||||
{ element: 5 },
|
||||
{ element: 6 },
|
||||
{ element: 7 }
|
||||
]
|
||||
}
|
||||
]);
|
||||
|
||||
assert.deepEqual(model.getNodeLocation(list[0]), [0]);
|
||||
assert.deepEqual(model.getNodeLocation(list[1]), [0, 1]);
|
||||
assert.deepEqual(model.getNodeLocation(list[2]), [0, 3]);
|
||||
assert.deepEqual(model.getNodeLocation(list[3]), [0, 5]);
|
||||
});
|
||||
});
|
||||
|
||||
test('refilter with filtered out nodes', function () {
|
||||
const list: ITreeNode<string>[] = [];
|
||||
let query = new RegExp('');
|
||||
const filter = new class implements ITreeFilter<string> {
|
||||
filter(element: string): boolean {
|
||||
return query.test(element);
|
||||
}
|
||||
};
|
||||
|
||||
const model = new IndexTreeModel<string>('test', toList(list), 'root', { filter });
|
||||
|
||||
model.splice([0], 0, [
|
||||
{ element: 'silver' },
|
||||
{ element: 'gold' },
|
||||
{ element: 'platinum' }
|
||||
]);
|
||||
|
||||
assert.deepEqual(toArray(list), ['silver', 'gold', 'platinum']);
|
||||
|
||||
query = /platinum/;
|
||||
model.refilter();
|
||||
assert.deepEqual(toArray(list), ['platinum']);
|
||||
|
||||
model.splice([0], Number.POSITIVE_INFINITY, [
|
||||
{ element: 'silver' },
|
||||
{ element: 'gold' },
|
||||
{ element: 'platinum' }
|
||||
]);
|
||||
assert.deepEqual(toArray(list), ['platinum']);
|
||||
|
||||
model.refilter();
|
||||
assert.deepEqual(toArray(list), ['platinum']);
|
||||
});
|
||||
|
||||
test('explicit hidden nodes should have renderNodeCount == 0, issue #83211', function () {
|
||||
const list: ITreeNode<string>[] = [];
|
||||
let query = new RegExp('');
|
||||
const filter = new class implements ITreeFilter<string> {
|
||||
filter(element: string): boolean {
|
||||
return query.test(element);
|
||||
}
|
||||
};
|
||||
|
||||
const model = new IndexTreeModel<string>('test', toList(list), 'root', { filter });
|
||||
|
||||
model.splice([0], 0, [
|
||||
{ element: 'a', children: [{ element: 'aa' }] },
|
||||
{ element: 'b', children: [{ element: 'bb' }] }
|
||||
]);
|
||||
|
||||
assert.deepEqual(toArray(list), ['a', 'aa', 'b', 'bb']);
|
||||
assert.deepEqual(model.getListIndex([0]), 0);
|
||||
assert.deepEqual(model.getListIndex([0, 0]), 1);
|
||||
assert.deepEqual(model.getListIndex([1]), 2);
|
||||
assert.deepEqual(model.getListIndex([1, 0]), 3);
|
||||
|
||||
query = /b/;
|
||||
model.refilter();
|
||||
assert.deepEqual(toArray(list), ['b', 'bb']);
|
||||
assert.deepEqual(model.getListIndex([0]), -1);
|
||||
assert.deepEqual(model.getListIndex([0, 0]), -1);
|
||||
assert.deepEqual(model.getListIndex([1]), 0);
|
||||
assert.deepEqual(model.getListIndex([1, 0]), 1);
|
||||
});
|
||||
});
|
||||
375
lib/vscode/src/vs/base/test/browser/ui/tree/objectTree.test.ts
Normal file
375
lib/vscode/src/vs/base/test/browser/ui/tree/objectTree.test.ts
Normal file
@@ -0,0 +1,375 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { ITreeNode, ITreeRenderer } from 'vs/base/browser/ui/tree/tree';
|
||||
import { IListVirtualDelegate, IIdentityProvider } from 'vs/base/browser/ui/list/list';
|
||||
import { ObjectTree, CompressibleObjectTree, ICompressibleTreeRenderer } from 'vs/base/browser/ui/tree/objectTree';
|
||||
import { ICompressedTreeNode } from 'vs/base/browser/ui/tree/compressedObjectTreeModel';
|
||||
|
||||
suite('ObjectTree', function () {
|
||||
suite('TreeNavigator', function () {
|
||||
let tree: ObjectTree<number>;
|
||||
let filter = (_: number) => true;
|
||||
|
||||
setup(() => {
|
||||
const container = document.createElement('div');
|
||||
container.style.width = '200px';
|
||||
container.style.height = '200px';
|
||||
|
||||
const delegate = new class implements IListVirtualDelegate<number> {
|
||||
getHeight() { return 20; }
|
||||
getTemplateId(): string { return 'default'; }
|
||||
};
|
||||
|
||||
const renderer = new class implements ITreeRenderer<number, void, HTMLElement> {
|
||||
readonly templateId = 'default';
|
||||
renderTemplate(container: HTMLElement): HTMLElement {
|
||||
return container;
|
||||
}
|
||||
renderElement(element: ITreeNode<number, void>, index: number, templateData: HTMLElement): void {
|
||||
templateData.textContent = `${element.element}`;
|
||||
}
|
||||
disposeTemplate(): void { }
|
||||
};
|
||||
|
||||
tree = new ObjectTree<number>('test', container, delegate, [renderer], { filter: { filter: (el) => filter(el) } });
|
||||
tree.layout(200);
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
tree.dispose();
|
||||
filter = (_: number) => true;
|
||||
});
|
||||
|
||||
test('should be able to navigate', () => {
|
||||
tree.setChildren(null, [
|
||||
{
|
||||
element: 0, children: [
|
||||
{ element: 10 },
|
||||
{ element: 11 },
|
||||
{ element: 12 },
|
||||
]
|
||||
},
|
||||
{ element: 1 },
|
||||
{ element: 2 }
|
||||
]);
|
||||
|
||||
const navigator = tree.navigate();
|
||||
|
||||
assert.equal(navigator.current(), null);
|
||||
assert.equal(navigator.next(), 0);
|
||||
assert.equal(navigator.current(), 0);
|
||||
assert.equal(navigator.next(), 10);
|
||||
assert.equal(navigator.current(), 10);
|
||||
assert.equal(navigator.next(), 11);
|
||||
assert.equal(navigator.current(), 11);
|
||||
assert.equal(navigator.next(), 12);
|
||||
assert.equal(navigator.current(), 12);
|
||||
assert.equal(navigator.next(), 1);
|
||||
assert.equal(navigator.current(), 1);
|
||||
assert.equal(navigator.next(), 2);
|
||||
assert.equal(navigator.current(), 2);
|
||||
assert.equal(navigator.previous(), 1);
|
||||
assert.equal(navigator.current(), 1);
|
||||
assert.equal(navigator.previous(), 12);
|
||||
assert.equal(navigator.previous(), 11);
|
||||
assert.equal(navigator.previous(), 10);
|
||||
assert.equal(navigator.previous(), 0);
|
||||
assert.equal(navigator.previous(), null);
|
||||
assert.equal(navigator.next(), 0);
|
||||
assert.equal(navigator.next(), 10);
|
||||
assert.equal(navigator.first(), 0);
|
||||
assert.equal(navigator.last(), 2);
|
||||
});
|
||||
|
||||
test('should skip collapsed nodes', () => {
|
||||
tree.setChildren(null, [
|
||||
{
|
||||
element: 0, collapsed: true, children: [
|
||||
{ element: 10 },
|
||||
{ element: 11 },
|
||||
{ element: 12 },
|
||||
]
|
||||
},
|
||||
{ element: 1 },
|
||||
{ element: 2 }
|
||||
]);
|
||||
|
||||
const navigator = tree.navigate();
|
||||
|
||||
assert.equal(navigator.current(), null);
|
||||
assert.equal(navigator.next(), 0);
|
||||
assert.equal(navigator.next(), 1);
|
||||
assert.equal(navigator.next(), 2);
|
||||
assert.equal(navigator.next(), null);
|
||||
assert.equal(navigator.previous(), 2);
|
||||
assert.equal(navigator.previous(), 1);
|
||||
assert.equal(navigator.previous(), 0);
|
||||
assert.equal(navigator.previous(), null);
|
||||
assert.equal(navigator.next(), 0);
|
||||
assert.equal(navigator.first(), 0);
|
||||
assert.equal(navigator.last(), 2);
|
||||
});
|
||||
|
||||
test('should skip filtered elements', () => {
|
||||
filter = el => el % 2 === 0;
|
||||
|
||||
tree.setChildren(null, [
|
||||
{
|
||||
element: 0, children: [
|
||||
{ element: 10 },
|
||||
{ element: 11 },
|
||||
{ element: 12 },
|
||||
]
|
||||
},
|
||||
{ element: 1 },
|
||||
{ element: 2 }
|
||||
]);
|
||||
|
||||
const navigator = tree.navigate();
|
||||
|
||||
assert.equal(navigator.current(), null);
|
||||
assert.equal(navigator.next(), 0);
|
||||
assert.equal(navigator.next(), 10);
|
||||
assert.equal(navigator.next(), 12);
|
||||
assert.equal(navigator.next(), 2);
|
||||
assert.equal(navigator.next(), null);
|
||||
assert.equal(navigator.previous(), 2);
|
||||
assert.equal(navigator.previous(), 12);
|
||||
assert.equal(navigator.previous(), 10);
|
||||
assert.equal(navigator.previous(), 0);
|
||||
assert.equal(navigator.previous(), null);
|
||||
assert.equal(navigator.next(), 0);
|
||||
assert.equal(navigator.next(), 10);
|
||||
assert.equal(navigator.first(), 0);
|
||||
assert.equal(navigator.last(), 2);
|
||||
});
|
||||
|
||||
test('should be able to start from node', () => {
|
||||
tree.setChildren(null, [
|
||||
{
|
||||
element: 0, children: [
|
||||
{ element: 10 },
|
||||
{ element: 11 },
|
||||
{ element: 12 },
|
||||
]
|
||||
},
|
||||
{ element: 1 },
|
||||
{ element: 2 }
|
||||
]);
|
||||
|
||||
const navigator = tree.navigate(1);
|
||||
|
||||
assert.equal(navigator.current(), 1);
|
||||
assert.equal(navigator.next(), 2);
|
||||
assert.equal(navigator.current(), 2);
|
||||
assert.equal(navigator.previous(), 1);
|
||||
assert.equal(navigator.current(), 1);
|
||||
assert.equal(navigator.previous(), 12);
|
||||
assert.equal(navigator.previous(), 11);
|
||||
assert.equal(navigator.previous(), 10);
|
||||
assert.equal(navigator.previous(), 0);
|
||||
assert.equal(navigator.previous(), null);
|
||||
assert.equal(navigator.next(), 0);
|
||||
assert.equal(navigator.next(), 10);
|
||||
assert.equal(navigator.first(), 0);
|
||||
assert.equal(navigator.last(), 2);
|
||||
});
|
||||
});
|
||||
|
||||
test('traits are preserved according to string identity', function () {
|
||||
const container = document.createElement('div');
|
||||
container.style.width = '200px';
|
||||
container.style.height = '200px';
|
||||
|
||||
const delegate = new class implements IListVirtualDelegate<number> {
|
||||
getHeight() { return 20; }
|
||||
getTemplateId(): string { return 'default'; }
|
||||
};
|
||||
|
||||
const renderer = new class implements ITreeRenderer<number, void, HTMLElement> {
|
||||
readonly templateId = 'default';
|
||||
renderTemplate(container: HTMLElement): HTMLElement {
|
||||
return container;
|
||||
}
|
||||
renderElement(element: ITreeNode<number, void>, index: number, templateData: HTMLElement): void {
|
||||
templateData.textContent = `${element.element}`;
|
||||
}
|
||||
disposeTemplate(): void { }
|
||||
};
|
||||
|
||||
const identityProvider = new class implements IIdentityProvider<number> {
|
||||
getId(element: number): { toString(): string; } {
|
||||
return `${element % 100}`;
|
||||
}
|
||||
};
|
||||
|
||||
const tree = new ObjectTree<number>('test', container, delegate, [renderer], { identityProvider });
|
||||
tree.layout(200);
|
||||
|
||||
tree.setChildren(null, [{ element: 0 }, { element: 1 }, { element: 2 }, { element: 3 }]);
|
||||
tree.setFocus([1]);
|
||||
assert.deepStrictEqual(tree.getFocus(), [1]);
|
||||
|
||||
tree.setChildren(null, [{ element: 100 }, { element: 101 }, { element: 102 }, { element: 103 }]);
|
||||
assert.deepStrictEqual(tree.getFocus(), [101]);
|
||||
});
|
||||
});
|
||||
|
||||
function toArray(list: NodeList): Node[] {
|
||||
const result: Node[] = [];
|
||||
list.forEach(node => result.push(node));
|
||||
return result;
|
||||
}
|
||||
|
||||
suite('CompressibleObjectTree', function () {
|
||||
|
||||
class Delegate implements IListVirtualDelegate<number> {
|
||||
getHeight() { return 20; }
|
||||
getTemplateId(): string { return 'default'; }
|
||||
}
|
||||
|
||||
class Renderer implements ICompressibleTreeRenderer<number, void, HTMLElement> {
|
||||
readonly templateId = 'default';
|
||||
renderTemplate(container: HTMLElement): HTMLElement {
|
||||
return container;
|
||||
}
|
||||
renderElement(node: ITreeNode<number, void>, _: number, templateData: HTMLElement): void {
|
||||
templateData.textContent = `${node.element}`;
|
||||
}
|
||||
renderCompressedElements(node: ITreeNode<ICompressedTreeNode<number>, void>, _: number, templateData: HTMLElement): void {
|
||||
templateData.textContent = `${node.element.elements.join('/')}`;
|
||||
}
|
||||
disposeTemplate(): void { }
|
||||
}
|
||||
|
||||
test('empty', function () {
|
||||
const container = document.createElement('div');
|
||||
container.style.width = '200px';
|
||||
container.style.height = '200px';
|
||||
|
||||
const tree = new CompressibleObjectTree<number>('test', container, new Delegate(), [new Renderer()]);
|
||||
tree.layout(200);
|
||||
|
||||
const rows = toArray(container.querySelectorAll('.monaco-tl-contents'));
|
||||
assert.equal(rows.length, 0);
|
||||
});
|
||||
|
||||
test('simple', function () {
|
||||
const container = document.createElement('div');
|
||||
container.style.width = '200px';
|
||||
container.style.height = '200px';
|
||||
|
||||
const tree = new CompressibleObjectTree<number>('test', container, new Delegate(), [new Renderer()]);
|
||||
tree.layout(200);
|
||||
|
||||
tree.setChildren(null, [
|
||||
{
|
||||
element: 0, children: [
|
||||
{ element: 10 },
|
||||
{ element: 11 },
|
||||
{ element: 12 },
|
||||
]
|
||||
},
|
||||
{ element: 1 },
|
||||
{ element: 2 }
|
||||
]);
|
||||
|
||||
const rows = toArray(container.querySelectorAll('.monaco-tl-contents')).map(row => row.textContent);
|
||||
assert.deepEqual(rows, ['0', '10', '11', '12', '1', '2']);
|
||||
});
|
||||
|
||||
test('compressed', () => {
|
||||
const container = document.createElement('div');
|
||||
container.style.width = '200px';
|
||||
container.style.height = '200px';
|
||||
|
||||
const tree = new CompressibleObjectTree<number>('test', container, new Delegate(), [new Renderer()]);
|
||||
tree.layout(200);
|
||||
|
||||
tree.setChildren(null, [
|
||||
{
|
||||
element: 1, children: [{
|
||||
element: 11, children: [{
|
||||
element: 111, children: [
|
||||
{ element: 1111 },
|
||||
{ element: 1112 },
|
||||
{ element: 1113 },
|
||||
]
|
||||
}]
|
||||
}]
|
||||
}
|
||||
]);
|
||||
|
||||
let rows = toArray(container.querySelectorAll('.monaco-tl-contents')).map(row => row.textContent);
|
||||
assert.deepEqual(rows, ['1/11/111', '1111', '1112', '1113']);
|
||||
|
||||
tree.setChildren(11, [
|
||||
{ element: 111 },
|
||||
{ element: 112 },
|
||||
{ element: 113 },
|
||||
]);
|
||||
|
||||
rows = toArray(container.querySelectorAll('.monaco-tl-contents')).map(row => row.textContent);
|
||||
assert.deepEqual(rows, ['1/11', '111', '112', '113']);
|
||||
|
||||
tree.setChildren(113, [
|
||||
{ element: 1131 }
|
||||
]);
|
||||
|
||||
rows = toArray(container.querySelectorAll('.monaco-tl-contents')).map(row => row.textContent);
|
||||
assert.deepEqual(rows, ['1/11', '111', '112', '113/1131']);
|
||||
|
||||
tree.setChildren(1131, [
|
||||
{ element: 1132 }
|
||||
]);
|
||||
|
||||
rows = toArray(container.querySelectorAll('.monaco-tl-contents')).map(row => row.textContent);
|
||||
assert.deepEqual(rows, ['1/11', '111', '112', '113/1131/1132']);
|
||||
|
||||
tree.setChildren(1131, [
|
||||
{ element: 1132 },
|
||||
{ element: 1133 },
|
||||
]);
|
||||
|
||||
rows = toArray(container.querySelectorAll('.monaco-tl-contents')).map(row => row.textContent);
|
||||
assert.deepEqual(rows, ['1/11', '111', '112', '113/1131', '1132', '1133']);
|
||||
});
|
||||
|
||||
test('enableCompression', () => {
|
||||
const container = document.createElement('div');
|
||||
container.style.width = '200px';
|
||||
container.style.height = '200px';
|
||||
|
||||
const tree = new CompressibleObjectTree<number>('test', container, new Delegate(), [new Renderer()]);
|
||||
tree.layout(200);
|
||||
|
||||
tree.setChildren(null, [
|
||||
{
|
||||
element: 1, children: [{
|
||||
element: 11, children: [{
|
||||
element: 111, children: [
|
||||
{ element: 1111 },
|
||||
{ element: 1112 },
|
||||
{ element: 1113 },
|
||||
]
|
||||
}]
|
||||
}]
|
||||
}
|
||||
]);
|
||||
|
||||
let rows = toArray(container.querySelectorAll('.monaco-tl-contents')).map(row => row.textContent);
|
||||
assert.deepEqual(rows, ['1/11/111', '1111', '1112', '1113']);
|
||||
|
||||
tree.updateOptions({ compressionEnabled: false });
|
||||
rows = toArray(container.querySelectorAll('.monaco-tl-contents')).map(row => row.textContent);
|
||||
assert.deepEqual(rows, ['1', '11', '111', '1111', '1112', '1113']);
|
||||
|
||||
tree.updateOptions({ compressionEnabled: true });
|
||||
rows = toArray(container.querySelectorAll('.monaco-tl-contents')).map(row => row.textContent);
|
||||
assert.deepEqual(rows, ['1/11/111', '1111', '1112', '1113']);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,276 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { ITreeNode, ITreeFilter, TreeVisibility } from 'vs/base/browser/ui/tree/tree';
|
||||
import { ObjectTreeModel } from 'vs/base/browser/ui/tree/objectTreeModel';
|
||||
import { IList } from 'vs/base/browser/ui/tree/indexTreeModel';
|
||||
|
||||
function toList<T>(arr: T[]): IList<T> {
|
||||
return {
|
||||
splice(start: number, deleteCount: number, elements: T[]): void {
|
||||
// console.log(`splice (${start}, ${deleteCount}, ${elements.length} [${elements.join(', ')}] )`); // debugging
|
||||
arr.splice(start, deleteCount, ...elements);
|
||||
},
|
||||
updateElementHeight() { }
|
||||
};
|
||||
}
|
||||
|
||||
function toArray<T>(list: ITreeNode<T>[]): T[] {
|
||||
return list.map(i => i.element);
|
||||
}
|
||||
|
||||
suite('ObjectTreeModel', function () {
|
||||
|
||||
test('ctor', () => {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new ObjectTreeModel<number>('test', toList(list));
|
||||
assert(model);
|
||||
assert.equal(list.length, 0);
|
||||
assert.equal(model.size, 0);
|
||||
});
|
||||
|
||||
test('flat', () => {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new ObjectTreeModel<number>('test', toList(list));
|
||||
|
||||
model.setChildren(null, [
|
||||
{ element: 0 },
|
||||
{ element: 1 },
|
||||
{ element: 2 }
|
||||
]);
|
||||
|
||||
assert.deepEqual(toArray(list), [0, 1, 2]);
|
||||
assert.equal(model.size, 3);
|
||||
|
||||
model.setChildren(null, [
|
||||
{ element: 3 },
|
||||
{ element: 4 },
|
||||
{ element: 5 },
|
||||
]);
|
||||
|
||||
assert.deepEqual(toArray(list), [3, 4, 5]);
|
||||
assert.equal(model.size, 3);
|
||||
|
||||
model.setChildren(null);
|
||||
assert.deepEqual(toArray(list), []);
|
||||
assert.equal(model.size, 0);
|
||||
});
|
||||
|
||||
test('nested', () => {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new ObjectTreeModel<number>('test', toList(list));
|
||||
|
||||
model.setChildren(null, [
|
||||
{
|
||||
element: 0, children: [
|
||||
{ element: 10 },
|
||||
{ element: 11 },
|
||||
{ element: 12 },
|
||||
]
|
||||
},
|
||||
{ element: 1 },
|
||||
{ element: 2 }
|
||||
]);
|
||||
|
||||
assert.deepEqual(toArray(list), [0, 10, 11, 12, 1, 2]);
|
||||
assert.equal(model.size, 6);
|
||||
|
||||
model.setChildren(12, [
|
||||
{ element: 120 },
|
||||
{ element: 121 }
|
||||
]);
|
||||
|
||||
assert.deepEqual(toArray(list), [0, 10, 11, 12, 120, 121, 1, 2]);
|
||||
assert.equal(model.size, 8);
|
||||
|
||||
model.setChildren(0);
|
||||
assert.deepEqual(toArray(list), [0, 1, 2]);
|
||||
assert.equal(model.size, 3);
|
||||
|
||||
model.setChildren(null);
|
||||
assert.deepEqual(toArray(list), []);
|
||||
assert.equal(model.size, 0);
|
||||
});
|
||||
|
||||
test('setChildren on collapsed node', () => {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new ObjectTreeModel<number>('test', toList(list));
|
||||
|
||||
model.setChildren(null, [
|
||||
{ element: 0, collapsed: true }
|
||||
]);
|
||||
|
||||
assert.deepEqual(toArray(list), [0]);
|
||||
|
||||
model.setChildren(0, [
|
||||
{ element: 1 },
|
||||
{ element: 2 }
|
||||
]);
|
||||
|
||||
assert.deepEqual(toArray(list), [0]);
|
||||
|
||||
model.setCollapsed(0, false);
|
||||
assert.deepEqual(toArray(list), [0, 1, 2]);
|
||||
});
|
||||
|
||||
test('setChildren on expanded, unrevealed node', () => {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new ObjectTreeModel<number>('test', toList(list));
|
||||
|
||||
model.setChildren(null, [
|
||||
{
|
||||
element: 1, collapsed: true, children: [
|
||||
{ element: 11, collapsed: false }
|
||||
]
|
||||
},
|
||||
{ element: 2 }
|
||||
]);
|
||||
|
||||
assert.deepEqual(toArray(list), [1, 2]);
|
||||
|
||||
model.setChildren(11, [
|
||||
{ element: 111 },
|
||||
{ element: 112 }
|
||||
]);
|
||||
|
||||
assert.deepEqual(toArray(list), [1, 2]);
|
||||
|
||||
model.setCollapsed(1, false);
|
||||
assert.deepEqual(toArray(list), [1, 11, 111, 112, 2]);
|
||||
});
|
||||
|
||||
test('collapse state is preserved with strict identity', () => {
|
||||
const list: ITreeNode<string>[] = [];
|
||||
const model = new ObjectTreeModel<string>('test', toList(list), { collapseByDefault: true });
|
||||
const data = [{ element: 'father', children: [{ element: 'child' }] }];
|
||||
|
||||
model.setChildren(null, data);
|
||||
assert.deepEqual(toArray(list), ['father']);
|
||||
|
||||
model.setCollapsed('father', false);
|
||||
assert.deepEqual(toArray(list), ['father', 'child']);
|
||||
|
||||
model.setChildren(null, data);
|
||||
assert.deepEqual(toArray(list), ['father', 'child']);
|
||||
|
||||
const data2 = [{ element: 'father', children: [{ element: 'child' }] }, { element: 'uncle' }];
|
||||
model.setChildren(null, data2);
|
||||
assert.deepEqual(toArray(list), ['father', 'child', 'uncle']);
|
||||
|
||||
model.setChildren(null, [{ element: 'uncle' }]);
|
||||
assert.deepEqual(toArray(list), ['uncle']);
|
||||
|
||||
model.setChildren(null, data2);
|
||||
assert.deepEqual(toArray(list), ['father', 'uncle']);
|
||||
|
||||
model.setChildren(null, data);
|
||||
assert.deepEqual(toArray(list), ['father']);
|
||||
});
|
||||
|
||||
test('sorter', () => {
|
||||
let compare: (a: string, b: string) => number = (a, b) => a < b ? -1 : 1;
|
||||
|
||||
const list: ITreeNode<string>[] = [];
|
||||
const model = new ObjectTreeModel<string>('test', toList(list), { sorter: { compare(a, b) { return compare(a, b); } } });
|
||||
const data = [
|
||||
{ element: 'cars', children: [{ element: 'sedan' }, { element: 'convertible' }, { element: 'compact' }] },
|
||||
{ element: 'airplanes', children: [{ element: 'passenger' }, { element: 'jet' }] },
|
||||
{ element: 'bicycles', children: [{ element: 'dutch' }, { element: 'mountain' }, { element: 'electric' }] },
|
||||
];
|
||||
|
||||
model.setChildren(null, data);
|
||||
assert.deepEqual(toArray(list), ['airplanes', 'jet', 'passenger', 'bicycles', 'dutch', 'electric', 'mountain', 'cars', 'compact', 'convertible', 'sedan']);
|
||||
});
|
||||
|
||||
test('resort', () => {
|
||||
let compare: (a: string, b: string) => number = () => 0;
|
||||
|
||||
const list: ITreeNode<string>[] = [];
|
||||
const model = new ObjectTreeModel<string>('test', toList(list), { sorter: { compare(a, b) { return compare(a, b); } } });
|
||||
const data = [
|
||||
{ element: 'cars', children: [{ element: 'sedan' }, { element: 'convertible' }, { element: 'compact' }] },
|
||||
{ element: 'airplanes', children: [{ element: 'passenger' }, { element: 'jet' }] },
|
||||
{ element: 'bicycles', children: [{ element: 'dutch' }, { element: 'mountain' }, { element: 'electric' }] },
|
||||
];
|
||||
|
||||
model.setChildren(null, data);
|
||||
assert.deepEqual(toArray(list), ['cars', 'sedan', 'convertible', 'compact', 'airplanes', 'passenger', 'jet', 'bicycles', 'dutch', 'mountain', 'electric']);
|
||||
|
||||
// lexicographical
|
||||
compare = (a, b) => a < b ? -1 : 1;
|
||||
|
||||
// non-recursive
|
||||
model.resort(null, false);
|
||||
assert.deepEqual(toArray(list), ['airplanes', 'passenger', 'jet', 'bicycles', 'dutch', 'mountain', 'electric', 'cars', 'sedan', 'convertible', 'compact']);
|
||||
|
||||
// recursive
|
||||
model.resort();
|
||||
assert.deepEqual(toArray(list), ['airplanes', 'jet', 'passenger', 'bicycles', 'dutch', 'electric', 'mountain', 'cars', 'compact', 'convertible', 'sedan']);
|
||||
|
||||
// reverse
|
||||
compare = (a, b) => a < b ? 1 : -1;
|
||||
|
||||
// scoped
|
||||
model.resort('cars');
|
||||
assert.deepEqual(toArray(list), ['airplanes', 'jet', 'passenger', 'bicycles', 'dutch', 'electric', 'mountain', 'cars', 'sedan', 'convertible', 'compact']);
|
||||
|
||||
// recursive
|
||||
model.resort();
|
||||
assert.deepEqual(toArray(list), ['cars', 'sedan', 'convertible', 'compact', 'bicycles', 'mountain', 'electric', 'dutch', 'airplanes', 'passenger', 'jet']);
|
||||
});
|
||||
|
||||
test('expandTo', () => {
|
||||
const list: ITreeNode<number>[] = [];
|
||||
const model = new ObjectTreeModel<number>('test', toList(list), { collapseByDefault: true });
|
||||
|
||||
model.setChildren(null, [
|
||||
{
|
||||
element: 0, children: [
|
||||
{ element: 10, children: [{ element: 100, children: [{ element: 1000 }] }] },
|
||||
{ element: 11 },
|
||||
{ element: 12 },
|
||||
]
|
||||
},
|
||||
{ element: 1 },
|
||||
{ element: 2 }
|
||||
]);
|
||||
|
||||
assert.deepEqual(toArray(list), [0, 1, 2]);
|
||||
model.expandTo(1000);
|
||||
assert.deepEqual(toArray(list), [0, 10, 100, 1000, 11, 12, 1, 2]);
|
||||
});
|
||||
|
||||
test('issue #95641', () => {
|
||||
const list: ITreeNode<string>[] = [];
|
||||
let fn = (_: string) => true;
|
||||
const filter = new class implements ITreeFilter<string> {
|
||||
filter(element: string, parentVisibility: TreeVisibility): TreeVisibility {
|
||||
if (element === 'file') {
|
||||
return TreeVisibility.Recurse;
|
||||
}
|
||||
|
||||
return fn(element) ? TreeVisibility.Visible : parentVisibility;
|
||||
}
|
||||
};
|
||||
const model = new ObjectTreeModel<string>('test', toList(list), { filter });
|
||||
|
||||
model.setChildren(null, [{ element: 'file', children: [{ element: 'hello' }] }]);
|
||||
assert.deepEqual(toArray(list), ['file', 'hello']);
|
||||
|
||||
fn = (el: string) => el === 'world';
|
||||
model.refilter();
|
||||
assert.deepEqual(toArray(list), []);
|
||||
|
||||
model.setChildren('file', [{ element: 'world' }]);
|
||||
assert.deepEqual(toArray(list), ['file', 'world']);
|
||||
|
||||
model.setChildren('file', [{ element: 'hello' }]);
|
||||
assert.deepEqual(toArray(list), []);
|
||||
|
||||
model.setChildren('file', [{ element: 'world' }]);
|
||||
assert.deepEqual(toArray(list), ['file', 'world']);
|
||||
});
|
||||
});
|
||||
372
lib/vscode/src/vs/base/test/common/arrays.test.ts
Normal file
372
lib/vscode/src/vs/base/test/common/arrays.test.ts
Normal file
@@ -0,0 +1,372 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as assert from 'assert';
|
||||
import * as arrays from 'vs/base/common/arrays';
|
||||
|
||||
suite('Arrays', () => {
|
||||
test('findFirst', () => {
|
||||
const array = [1, 4, 5, 7, 55, 59, 60, 61, 64, 69];
|
||||
|
||||
let idx = arrays.findFirstInSorted(array, e => e >= 0);
|
||||
assert.equal(array[idx], 1);
|
||||
|
||||
idx = arrays.findFirstInSorted(array, e => e > 1);
|
||||
assert.equal(array[idx], 4);
|
||||
|
||||
idx = arrays.findFirstInSorted(array, e => e >= 8);
|
||||
assert.equal(array[idx], 55);
|
||||
|
||||
idx = arrays.findFirstInSorted(array, e => e >= 61);
|
||||
assert.equal(array[idx], 61);
|
||||
|
||||
idx = arrays.findFirstInSorted(array, e => e >= 69);
|
||||
assert.equal(array[idx], 69);
|
||||
|
||||
idx = arrays.findFirstInSorted(array, e => e >= 70);
|
||||
assert.equal(idx, array.length);
|
||||
|
||||
idx = arrays.findFirstInSorted([], e => e >= 0);
|
||||
assert.equal(array[idx], 1);
|
||||
});
|
||||
|
||||
test('quickSelect', () => {
|
||||
|
||||
function assertMedian(expexted: number, data: number[], nth: number = Math.floor(data.length / 2)) {
|
||||
const compare = (a: number, b: number) => a - b;
|
||||
let actual1 = arrays.quickSelect(nth, data, compare);
|
||||
assert.equal(actual1, expexted);
|
||||
|
||||
let actual2 = data.slice().sort(compare)[nth];
|
||||
assert.equal(actual2, expexted);
|
||||
}
|
||||
|
||||
assertMedian(5, [9, 1, 0, 2, 3, 4, 6, 8, 7, 10, 5]);
|
||||
assertMedian(8, [9, 1, 0, 2, 3, 4, 6, 8, 7, 10, 5], 8);
|
||||
assertMedian(8, [13, 4, 8]);
|
||||
assertMedian(4, [13, 4, 8, 4, 4]);
|
||||
assertMedian(13, [13, 4, 8], 2);
|
||||
});
|
||||
|
||||
test('stableSort', () => {
|
||||
function fill<T>(num: number, valueFn: () => T, arr: T[] = []): T[] {
|
||||
for (let i = 0; i < num; i++) {
|
||||
arr[i] = valueFn();
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
let counter = 0;
|
||||
let data = fill(10000, () => ({ n: 1, m: counter++ }));
|
||||
|
||||
arrays.mergeSort(data, (a, b) => a.n - b.n);
|
||||
|
||||
let lastM = -1;
|
||||
for (const element of data) {
|
||||
assert.ok(lastM < element.m);
|
||||
lastM = element.m;
|
||||
}
|
||||
});
|
||||
|
||||
test('mergeSort', () => {
|
||||
let data = arrays.mergeSort([6, 5, 3, 1, 8, 7, 2, 4], (a, b) => a - b);
|
||||
assert.deepEqual(data, [1, 2, 3, 4, 5, 6, 7, 8]);
|
||||
});
|
||||
|
||||
test('mergeSort, sorted array', function () {
|
||||
let data = arrays.mergeSort([1, 2, 3, 4, 5, 6], (a, b) => a - b);
|
||||
assert.deepEqual(data, [1, 2, 3, 4, 5, 6]);
|
||||
});
|
||||
|
||||
test('mergeSort, is stable', function () {
|
||||
|
||||
let numbers = arrays.mergeSort([33, 22, 11, 4, 99, 1], (a, b) => 0);
|
||||
assert.deepEqual(numbers, [33, 22, 11, 4, 99, 1]);
|
||||
});
|
||||
|
||||
test('mergeSort, many random numbers', function () {
|
||||
|
||||
function compare(a: number, b: number) {
|
||||
if (a < b) {
|
||||
return -1;
|
||||
} else if (a > b) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function assertSorted(array: number[]) {
|
||||
let last = array[0];
|
||||
for (let i = 1; i < array.length; i++) {
|
||||
let n = array[i];
|
||||
if (last > n) {
|
||||
assert.fail(JSON.stringify(array.slice(i - 10, i + 10)));
|
||||
}
|
||||
}
|
||||
}
|
||||
const MAX = 101;
|
||||
const data: number[][] = [];
|
||||
for (let i = 1; i < MAX; i++) {
|
||||
let array: number[] = [];
|
||||
for (let j = 0; j < 10 + i; j++) {
|
||||
array.push(Math.random() * 10e8 | 0);
|
||||
}
|
||||
data.push(array);
|
||||
}
|
||||
|
||||
for (const array of data) {
|
||||
arrays.mergeSort(array, compare);
|
||||
assertSorted(array);
|
||||
}
|
||||
});
|
||||
|
||||
test('sortedDiff', () => {
|
||||
function compare(a: number, b: number): number {
|
||||
return a - b;
|
||||
}
|
||||
|
||||
let d = arrays.sortedDiff([1, 2, 4], [], compare);
|
||||
assert.deepEqual(d, [
|
||||
{ start: 0, deleteCount: 3, toInsert: [] }
|
||||
]);
|
||||
|
||||
d = arrays.sortedDiff([], [1, 2, 4], compare);
|
||||
assert.deepEqual(d, [
|
||||
{ start: 0, deleteCount: 0, toInsert: [1, 2, 4] }
|
||||
]);
|
||||
|
||||
d = arrays.sortedDiff([1, 2, 4], [1, 2, 4], compare);
|
||||
assert.deepEqual(d, []);
|
||||
|
||||
d = arrays.sortedDiff([1, 2, 4], [2, 3, 4, 5], compare);
|
||||
assert.deepEqual(d, [
|
||||
{ start: 0, deleteCount: 1, toInsert: [] },
|
||||
{ start: 2, deleteCount: 0, toInsert: [3] },
|
||||
{ start: 3, deleteCount: 0, toInsert: [5] },
|
||||
]);
|
||||
|
||||
d = arrays.sortedDiff([2, 3, 4, 5], [1, 2, 4], compare);
|
||||
assert.deepEqual(d, [
|
||||
{ start: 0, deleteCount: 0, toInsert: [1] },
|
||||
{ start: 1, deleteCount: 1, toInsert: [] },
|
||||
{ start: 3, deleteCount: 1, toInsert: [] },
|
||||
]);
|
||||
|
||||
d = arrays.sortedDiff([1, 3, 5, 7], [5, 9, 11], compare);
|
||||
assert.deepEqual(d, [
|
||||
{ start: 0, deleteCount: 2, toInsert: [] },
|
||||
{ start: 3, deleteCount: 1, toInsert: [9, 11] }
|
||||
]);
|
||||
|
||||
d = arrays.sortedDiff([1, 3, 7], [5, 9, 11], compare);
|
||||
assert.deepEqual(d, [
|
||||
{ start: 0, deleteCount: 3, toInsert: [5, 9, 11] }
|
||||
]);
|
||||
});
|
||||
|
||||
test('delta sorted arrays', function () {
|
||||
function compare(a: number, b: number): number {
|
||||
return a - b;
|
||||
}
|
||||
|
||||
let d = arrays.delta([1, 2, 4], [], compare);
|
||||
assert.deepEqual(d.removed, [1, 2, 4]);
|
||||
assert.deepEqual(d.added, []);
|
||||
|
||||
d = arrays.delta([], [1, 2, 4], compare);
|
||||
assert.deepEqual(d.removed, []);
|
||||
assert.deepEqual(d.added, [1, 2, 4]);
|
||||
|
||||
d = arrays.delta([1, 2, 4], [1, 2, 4], compare);
|
||||
assert.deepEqual(d.removed, []);
|
||||
assert.deepEqual(d.added, []);
|
||||
|
||||
d = arrays.delta([1, 2, 4], [2, 3, 4, 5], compare);
|
||||
assert.deepEqual(d.removed, [1]);
|
||||
assert.deepEqual(d.added, [3, 5]);
|
||||
|
||||
d = arrays.delta([2, 3, 4, 5], [1, 2, 4], compare);
|
||||
assert.deepEqual(d.removed, [3, 5]);
|
||||
assert.deepEqual(d.added, [1]);
|
||||
|
||||
d = arrays.delta([1, 3, 5, 7], [5, 9, 11], compare);
|
||||
assert.deepEqual(d.removed, [1, 3, 7]);
|
||||
assert.deepEqual(d.added, [9, 11]);
|
||||
|
||||
d = arrays.delta([1, 3, 7], [5, 9, 11], compare);
|
||||
assert.deepEqual(d.removed, [1, 3, 7]);
|
||||
assert.deepEqual(d.added, [5, 9, 11]);
|
||||
});
|
||||
|
||||
test('binarySearch', () => {
|
||||
function compare(a: number, b: number): number {
|
||||
return a - b;
|
||||
}
|
||||
const array = [1, 4, 5, 7, 55, 59, 60, 61, 64, 69];
|
||||
|
||||
assert.equal(arrays.binarySearch(array, 1, compare), 0);
|
||||
assert.equal(arrays.binarySearch(array, 5, compare), 2);
|
||||
|
||||
// insertion point
|
||||
assert.equal(arrays.binarySearch(array, 0, compare), ~0);
|
||||
assert.equal(arrays.binarySearch(array, 6, compare), ~3);
|
||||
assert.equal(arrays.binarySearch(array, 70, compare), ~10);
|
||||
|
||||
});
|
||||
|
||||
test('distinct', () => {
|
||||
function compare(a: string): string {
|
||||
return a;
|
||||
}
|
||||
|
||||
assert.deepEqual(arrays.distinct(['32', '4', '5'], compare), ['32', '4', '5']);
|
||||
assert.deepEqual(arrays.distinct(['32', '4', '5', '4'], compare), ['32', '4', '5']);
|
||||
assert.deepEqual(arrays.distinct(['32', 'constructor', '5', '1'], compare), ['32', 'constructor', '5', '1']);
|
||||
assert.deepEqual(arrays.distinct(['32', 'constructor', 'proto', 'proto', 'constructor'], compare), ['32', 'constructor', 'proto']);
|
||||
assert.deepEqual(arrays.distinct(['32', '4', '5', '32', '4', '5', '32', '4', '5', '5'], compare), ['32', '4', '5']);
|
||||
});
|
||||
|
||||
test('top', () => {
|
||||
const cmp = (a: number, b: number) => {
|
||||
assert.strictEqual(typeof a, 'number', 'typeof a');
|
||||
assert.strictEqual(typeof b, 'number', 'typeof b');
|
||||
return a - b;
|
||||
};
|
||||
|
||||
assert.deepEqual(arrays.top([], cmp, 1), []);
|
||||
assert.deepEqual(arrays.top([1], cmp, 0), []);
|
||||
assert.deepEqual(arrays.top([1, 2], cmp, 1), [1]);
|
||||
assert.deepEqual(arrays.top([2, 1], cmp, 1), [1]);
|
||||
assert.deepEqual(arrays.top([1, 3, 2], cmp, 2), [1, 2]);
|
||||
assert.deepEqual(arrays.top([3, 2, 1], cmp, 3), [1, 2, 3]);
|
||||
assert.deepEqual(arrays.top([4, 6, 2, 7, 8, 3, 5, 1], cmp, 3), [1, 2, 3]);
|
||||
});
|
||||
|
||||
test('topAsync', async () => {
|
||||
const cmp = (a: number, b: number) => {
|
||||
assert.strictEqual(typeof a, 'number', 'typeof a');
|
||||
assert.strictEqual(typeof b, 'number', 'typeof b');
|
||||
return a - b;
|
||||
};
|
||||
|
||||
await testTopAsync(cmp, 1);
|
||||
return testTopAsync(cmp, 2);
|
||||
});
|
||||
|
||||
async function testTopAsync(cmp: any, m: number) {
|
||||
{
|
||||
const result = await arrays.topAsync([], cmp, 1, m);
|
||||
assert.deepEqual(result, []);
|
||||
}
|
||||
{
|
||||
const result = await arrays.topAsync([1], cmp, 0, m);
|
||||
assert.deepEqual(result, []);
|
||||
}
|
||||
{
|
||||
const result = await arrays.topAsync([1, 2], cmp, 1, m);
|
||||
assert.deepEqual(result, [1]);
|
||||
}
|
||||
{
|
||||
const result = await arrays.topAsync([2, 1], cmp, 1, m);
|
||||
assert.deepEqual(result, [1]);
|
||||
}
|
||||
{
|
||||
const result = await arrays.topAsync([1, 3, 2], cmp, 2, m);
|
||||
assert.deepEqual(result, [1, 2]);
|
||||
}
|
||||
{
|
||||
const result = await arrays.topAsync([3, 2, 1], cmp, 3, m);
|
||||
assert.deepEqual(result, [1, 2, 3]);
|
||||
}
|
||||
{
|
||||
const result = await arrays.topAsync([4, 6, 2, 7, 8, 3, 5, 1], cmp, 3, m);
|
||||
assert.deepEqual(result, [1, 2, 3]);
|
||||
}
|
||||
}
|
||||
|
||||
test('coalesce', () => {
|
||||
let a: Array<number | null> = arrays.coalesce([null, 1, null, 2, 3]);
|
||||
assert.equal(a.length, 3);
|
||||
assert.equal(a[0], 1);
|
||||
assert.equal(a[1], 2);
|
||||
assert.equal(a[2], 3);
|
||||
|
||||
arrays.coalesce([null, 1, null, undefined, undefined, 2, 3]);
|
||||
assert.equal(a.length, 3);
|
||||
assert.equal(a[0], 1);
|
||||
assert.equal(a[1], 2);
|
||||
assert.equal(a[2], 3);
|
||||
|
||||
let b: number[] = [];
|
||||
b[10] = 1;
|
||||
b[20] = 2;
|
||||
b[30] = 3;
|
||||
b = arrays.coalesce(b);
|
||||
assert.equal(b.length, 3);
|
||||
assert.equal(b[0], 1);
|
||||
assert.equal(b[1], 2);
|
||||
assert.equal(b[2], 3);
|
||||
|
||||
let sparse: number[] = [];
|
||||
sparse[0] = 1;
|
||||
sparse[1] = 1;
|
||||
sparse[17] = 1;
|
||||
sparse[1000] = 1;
|
||||
sparse[1001] = 1;
|
||||
|
||||
assert.equal(sparse.length, 1002);
|
||||
|
||||
sparse = arrays.coalesce(sparse);
|
||||
assert.equal(sparse.length, 5);
|
||||
});
|
||||
|
||||
test('coalesce - inplace', function () {
|
||||
let a: Array<number | null> = [null, 1, null, 2, 3];
|
||||
arrays.coalesceInPlace(a);
|
||||
assert.equal(a.length, 3);
|
||||
assert.equal(a[0], 1);
|
||||
assert.equal(a[1], 2);
|
||||
assert.equal(a[2], 3);
|
||||
|
||||
a = [null, 1, null, undefined!, undefined!, 2, 3];
|
||||
arrays.coalesceInPlace(a);
|
||||
assert.equal(a.length, 3);
|
||||
assert.equal(a[0], 1);
|
||||
assert.equal(a[1], 2);
|
||||
assert.equal(a[2], 3);
|
||||
|
||||
let b: number[] = [];
|
||||
b[10] = 1;
|
||||
b[20] = 2;
|
||||
b[30] = 3;
|
||||
arrays.coalesceInPlace(b);
|
||||
assert.equal(b.length, 3);
|
||||
assert.equal(b[0], 1);
|
||||
assert.equal(b[1], 2);
|
||||
assert.equal(b[2], 3);
|
||||
|
||||
let sparse: number[] = [];
|
||||
sparse[0] = 1;
|
||||
sparse[1] = 1;
|
||||
sparse[17] = 1;
|
||||
sparse[1000] = 1;
|
||||
sparse[1001] = 1;
|
||||
|
||||
assert.equal(sparse.length, 1002);
|
||||
|
||||
arrays.coalesceInPlace(sparse);
|
||||
assert.equal(sparse.length, 5);
|
||||
});
|
||||
|
||||
test('insert, remove', function () {
|
||||
const array: string[] = [];
|
||||
const remove = arrays.insert(array, 'foo');
|
||||
assert.equal(array[0], 'foo');
|
||||
|
||||
remove();
|
||||
assert.equal(array.length, 0);
|
||||
});
|
||||
});
|
||||
34
lib/vscode/src/vs/base/test/common/assert.test.ts
Normal file
34
lib/vscode/src/vs/base/test/common/assert.test.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { ok } from 'vs/base/common/assert';
|
||||
|
||||
suite('Assert', () => {
|
||||
test('ok', () => {
|
||||
assert.throws(function () {
|
||||
ok(false);
|
||||
});
|
||||
|
||||
assert.throws(function () {
|
||||
ok(null);
|
||||
});
|
||||
|
||||
assert.throws(function () {
|
||||
ok();
|
||||
});
|
||||
|
||||
assert.throws(function () {
|
||||
ok(null, 'Foo Bar');
|
||||
}, function (e: Error) {
|
||||
return e.message.indexOf('Foo Bar') >= 0;
|
||||
});
|
||||
|
||||
ok(true);
|
||||
ok('foo');
|
||||
ok({});
|
||||
ok(5);
|
||||
});
|
||||
});
|
||||
722
lib/vscode/src/vs/base/test/common/async.test.ts
Normal file
722
lib/vscode/src/vs/base/test/common/async.test.ts
Normal file
@@ -0,0 +1,722 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import * as async from 'vs/base/common/async';
|
||||
import { isPromiseCanceledError } from 'vs/base/common/errors';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
|
||||
suite('Async', () => {
|
||||
|
||||
test('cancelablePromise - set token, don\'t wait for inner promise', function () {
|
||||
let canceled = 0;
|
||||
let promise = async.createCancelablePromise(token => {
|
||||
token.onCancellationRequested(_ => { canceled += 1; });
|
||||
return new Promise(resolve => { /*never*/ });
|
||||
});
|
||||
let result = promise.then(_ => assert.ok(false), err => {
|
||||
assert.equal(canceled, 1);
|
||||
assert.ok(isPromiseCanceledError(err));
|
||||
});
|
||||
promise.cancel();
|
||||
promise.cancel(); // cancel only once
|
||||
return result;
|
||||
});
|
||||
|
||||
test('cancelablePromise - cancel despite inner promise being resolved', function () {
|
||||
let canceled = 0;
|
||||
let promise = async.createCancelablePromise(token => {
|
||||
token.onCancellationRequested(_ => { canceled += 1; });
|
||||
return Promise.resolve(1234);
|
||||
});
|
||||
let result = promise.then(_ => assert.ok(false), err => {
|
||||
assert.equal(canceled, 1);
|
||||
assert.ok(isPromiseCanceledError(err));
|
||||
});
|
||||
promise.cancel();
|
||||
return result;
|
||||
});
|
||||
|
||||
// Cancelling a sync cancelable promise will fire the cancelled token.
|
||||
// Also, every `then` callback runs in another execution frame.
|
||||
test('CancelablePromise execution order (sync)', function () {
|
||||
const order: string[] = [];
|
||||
|
||||
const cancellablePromise = async.createCancelablePromise(token => {
|
||||
order.push('in callback');
|
||||
token.onCancellationRequested(_ => order.push('cancelled'));
|
||||
return Promise.resolve(1234);
|
||||
});
|
||||
|
||||
order.push('afterCreate');
|
||||
|
||||
const promise = cancellablePromise
|
||||
.then(undefined, err => null)
|
||||
.then(() => order.push('finally'));
|
||||
|
||||
cancellablePromise.cancel();
|
||||
order.push('afterCancel');
|
||||
|
||||
return promise.then(() => assert.deepEqual(order, ['in callback', 'afterCreate', 'cancelled', 'afterCancel', 'finally']));
|
||||
});
|
||||
|
||||
// Cancelling an async cancelable promise is just the same as a sync cancellable promise.
|
||||
test('CancelablePromise execution order (async)', function () {
|
||||
const order: string[] = [];
|
||||
|
||||
const cancellablePromise = async.createCancelablePromise(token => {
|
||||
order.push('in callback');
|
||||
token.onCancellationRequested(_ => order.push('cancelled'));
|
||||
return new Promise(c => setTimeout(c.bind(1234), 0));
|
||||
});
|
||||
|
||||
order.push('afterCreate');
|
||||
|
||||
const promise = cancellablePromise
|
||||
.then(undefined, err => null)
|
||||
.then(() => order.push('finally'));
|
||||
|
||||
cancellablePromise.cancel();
|
||||
order.push('afterCancel');
|
||||
|
||||
return promise.then(() => assert.deepEqual(order, ['in callback', 'afterCreate', 'cancelled', 'afterCancel', 'finally']));
|
||||
});
|
||||
|
||||
test('cancelablePromise - get inner result', async function () {
|
||||
let promise = async.createCancelablePromise(token => {
|
||||
return async.timeout(12).then(_ => 1234);
|
||||
});
|
||||
|
||||
let result = await promise;
|
||||
assert.equal(result, 1234);
|
||||
});
|
||||
|
||||
test('Throttler - non async', function () {
|
||||
let count = 0;
|
||||
let factory = () => {
|
||||
return Promise.resolve(++count);
|
||||
};
|
||||
|
||||
let throttler = new async.Throttler();
|
||||
|
||||
return Promise.all([
|
||||
throttler.queue(factory).then((result) => { assert.equal(result, 1); }),
|
||||
throttler.queue(factory).then((result) => { assert.equal(result, 2); }),
|
||||
throttler.queue(factory).then((result) => { assert.equal(result, 2); }),
|
||||
throttler.queue(factory).then((result) => { assert.equal(result, 2); }),
|
||||
throttler.queue(factory).then((result) => { assert.equal(result, 2); })
|
||||
]).then(() => assert.equal(count, 2));
|
||||
});
|
||||
|
||||
test('Throttler', () => {
|
||||
let count = 0;
|
||||
let factory = () => async.timeout(0).then(() => ++count);
|
||||
|
||||
let throttler = new async.Throttler();
|
||||
|
||||
return Promise.all([
|
||||
throttler.queue(factory).then((result) => { assert.equal(result, 1); }),
|
||||
throttler.queue(factory).then((result) => { assert.equal(result, 2); }),
|
||||
throttler.queue(factory).then((result) => { assert.equal(result, 2); }),
|
||||
throttler.queue(factory).then((result) => { assert.equal(result, 2); }),
|
||||
throttler.queue(factory).then((result) => { assert.equal(result, 2); })
|
||||
]).then(() => {
|
||||
return Promise.all([
|
||||
throttler.queue(factory).then((result) => { assert.equal(result, 3); }),
|
||||
throttler.queue(factory).then((result) => { assert.equal(result, 4); }),
|
||||
throttler.queue(factory).then((result) => { assert.equal(result, 4); }),
|
||||
throttler.queue(factory).then((result) => { assert.equal(result, 4); }),
|
||||
throttler.queue(factory).then((result) => { assert.equal(result, 4); })
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
test('Throttler - last factory should be the one getting called', function () {
|
||||
let factoryFactory = (n: number) => () => {
|
||||
return async.timeout(0).then(() => n);
|
||||
};
|
||||
|
||||
let throttler = new async.Throttler();
|
||||
|
||||
let promises: Promise<any>[] = [];
|
||||
|
||||
promises.push(throttler.queue(factoryFactory(1)).then((n) => { assert.equal(n, 1); }));
|
||||
promises.push(throttler.queue(factoryFactory(2)).then((n) => { assert.equal(n, 3); }));
|
||||
promises.push(throttler.queue(factoryFactory(3)).then((n) => { assert.equal(n, 3); }));
|
||||
|
||||
return Promise.all(promises);
|
||||
});
|
||||
|
||||
test('Delayer', () => {
|
||||
let count = 0;
|
||||
let factory = () => {
|
||||
return Promise.resolve(++count);
|
||||
};
|
||||
|
||||
let delayer = new async.Delayer(0);
|
||||
let promises: Promise<any>[] = [];
|
||||
|
||||
assert(!delayer.isTriggered());
|
||||
|
||||
promises.push(delayer.trigger(factory).then((result) => { assert.equal(result, 1); assert(!delayer.isTriggered()); }));
|
||||
assert(delayer.isTriggered());
|
||||
|
||||
promises.push(delayer.trigger(factory).then((result) => { assert.equal(result, 1); assert(!delayer.isTriggered()); }));
|
||||
assert(delayer.isTriggered());
|
||||
|
||||
promises.push(delayer.trigger(factory).then((result) => { assert.equal(result, 1); assert(!delayer.isTriggered()); }));
|
||||
assert(delayer.isTriggered());
|
||||
|
||||
return Promise.all(promises).then(() => {
|
||||
assert(!delayer.isTriggered());
|
||||
});
|
||||
});
|
||||
|
||||
test('Delayer - simple cancel', function () {
|
||||
let count = 0;
|
||||
let factory = () => {
|
||||
return Promise.resolve(++count);
|
||||
};
|
||||
|
||||
let delayer = new async.Delayer(0);
|
||||
|
||||
assert(!delayer.isTriggered());
|
||||
|
||||
const p = delayer.trigger(factory).then(() => {
|
||||
assert(false);
|
||||
}, () => {
|
||||
assert(true, 'yes, it was cancelled');
|
||||
});
|
||||
|
||||
assert(delayer.isTriggered());
|
||||
delayer.cancel();
|
||||
assert(!delayer.isTriggered());
|
||||
|
||||
return p;
|
||||
});
|
||||
|
||||
test('Delayer - cancel should cancel all calls to trigger', function () {
|
||||
let count = 0;
|
||||
let factory = () => {
|
||||
return Promise.resolve(++count);
|
||||
};
|
||||
|
||||
let delayer = new async.Delayer(0);
|
||||
let promises: Promise<any>[] = [];
|
||||
|
||||
assert(!delayer.isTriggered());
|
||||
|
||||
promises.push(delayer.trigger(factory).then(undefined, () => { assert(true, 'yes, it was cancelled'); }));
|
||||
assert(delayer.isTriggered());
|
||||
|
||||
promises.push(delayer.trigger(factory).then(undefined, () => { assert(true, 'yes, it was cancelled'); }));
|
||||
assert(delayer.isTriggered());
|
||||
|
||||
promises.push(delayer.trigger(factory).then(undefined, () => { assert(true, 'yes, it was cancelled'); }));
|
||||
assert(delayer.isTriggered());
|
||||
|
||||
delayer.cancel();
|
||||
|
||||
return Promise.all(promises).then(() => {
|
||||
assert(!delayer.isTriggered());
|
||||
});
|
||||
});
|
||||
|
||||
test('Delayer - trigger, cancel, then trigger again', function () {
|
||||
let count = 0;
|
||||
let factory = () => {
|
||||
return Promise.resolve(++count);
|
||||
};
|
||||
|
||||
let delayer = new async.Delayer(0);
|
||||
let promises: Promise<any>[] = [];
|
||||
|
||||
assert(!delayer.isTriggered());
|
||||
|
||||
const p = delayer.trigger(factory).then((result) => {
|
||||
assert.equal(result, 1);
|
||||
assert(!delayer.isTriggered());
|
||||
|
||||
promises.push(delayer.trigger(factory).then(undefined, () => { assert(true, 'yes, it was cancelled'); }));
|
||||
assert(delayer.isTriggered());
|
||||
|
||||
promises.push(delayer.trigger(factory).then(undefined, () => { assert(true, 'yes, it was cancelled'); }));
|
||||
assert(delayer.isTriggered());
|
||||
|
||||
delayer.cancel();
|
||||
|
||||
const p = Promise.all(promises).then(() => {
|
||||
promises = [];
|
||||
|
||||
assert(!delayer.isTriggered());
|
||||
|
||||
promises.push(delayer.trigger(factory).then(() => { assert.equal(result, 1); assert(!delayer.isTriggered()); }));
|
||||
assert(delayer.isTriggered());
|
||||
|
||||
promises.push(delayer.trigger(factory).then(() => { assert.equal(result, 1); assert(!delayer.isTriggered()); }));
|
||||
assert(delayer.isTriggered());
|
||||
|
||||
const p = Promise.all(promises).then(() => {
|
||||
assert(!delayer.isTriggered());
|
||||
});
|
||||
|
||||
assert(delayer.isTriggered());
|
||||
|
||||
return p;
|
||||
});
|
||||
|
||||
return p;
|
||||
});
|
||||
|
||||
assert(delayer.isTriggered());
|
||||
|
||||
return p;
|
||||
});
|
||||
|
||||
test('Delayer - last task should be the one getting called', function () {
|
||||
let factoryFactory = (n: number) => () => {
|
||||
return Promise.resolve(n);
|
||||
};
|
||||
|
||||
let delayer = new async.Delayer(0);
|
||||
let promises: Promise<any>[] = [];
|
||||
|
||||
assert(!delayer.isTriggered());
|
||||
|
||||
promises.push(delayer.trigger(factoryFactory(1)).then((n) => { assert.equal(n, 3); }));
|
||||
promises.push(delayer.trigger(factoryFactory(2)).then((n) => { assert.equal(n, 3); }));
|
||||
promises.push(delayer.trigger(factoryFactory(3)).then((n) => { assert.equal(n, 3); }));
|
||||
|
||||
const p = Promise.all(promises).then(() => {
|
||||
assert(!delayer.isTriggered());
|
||||
});
|
||||
|
||||
assert(delayer.isTriggered());
|
||||
|
||||
return p;
|
||||
});
|
||||
|
||||
test('Sequence', () => {
|
||||
let factoryFactory = (n: number) => () => {
|
||||
return Promise.resolve(n);
|
||||
};
|
||||
|
||||
return async.sequence([
|
||||
factoryFactory(1),
|
||||
factoryFactory(2),
|
||||
factoryFactory(3),
|
||||
factoryFactory(4),
|
||||
factoryFactory(5),
|
||||
]).then((result) => {
|
||||
assert.equal(5, result.length);
|
||||
assert.equal(1, result[0]);
|
||||
assert.equal(2, result[1]);
|
||||
assert.equal(3, result[2]);
|
||||
assert.equal(4, result[3]);
|
||||
assert.equal(5, result[4]);
|
||||
});
|
||||
});
|
||||
|
||||
test('Limiter - sync', function () {
|
||||
let factoryFactory = (n: number) => () => {
|
||||
return Promise.resolve(n);
|
||||
};
|
||||
|
||||
let limiter = new async.Limiter(1);
|
||||
|
||||
let promises: Promise<any>[] = [];
|
||||
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9].forEach(n => promises.push(limiter.queue(factoryFactory(n))));
|
||||
|
||||
return Promise.all(promises).then((res) => {
|
||||
assert.equal(10, res.length);
|
||||
|
||||
limiter = new async.Limiter(100);
|
||||
|
||||
promises = [];
|
||||
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9].forEach(n => promises.push(limiter.queue(factoryFactory(n))));
|
||||
|
||||
return Promise.all(promises).then((res) => {
|
||||
assert.equal(10, res.length);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('Limiter - async', function () {
|
||||
let factoryFactory = (n: number) => () => async.timeout(0).then(() => n);
|
||||
|
||||
let limiter = new async.Limiter(1);
|
||||
let promises: Promise<any>[] = [];
|
||||
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9].forEach(n => promises.push(limiter.queue(factoryFactory(n))));
|
||||
|
||||
return Promise.all(promises).then((res) => {
|
||||
assert.equal(10, res.length);
|
||||
|
||||
limiter = new async.Limiter(100);
|
||||
|
||||
promises = [];
|
||||
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9].forEach(n => promises.push(limiter.queue(factoryFactory(n))));
|
||||
|
||||
return Promise.all(promises).then((res) => {
|
||||
assert.equal(10, res.length);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('Limiter - assert degree of paralellism', function () {
|
||||
let activePromises = 0;
|
||||
let factoryFactory = (n: number) => () => {
|
||||
activePromises++;
|
||||
assert(activePromises < 6);
|
||||
return async.timeout(0).then(() => { activePromises--; return n; });
|
||||
};
|
||||
|
||||
let limiter = new async.Limiter(5);
|
||||
|
||||
let promises: Promise<any>[] = [];
|
||||
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9].forEach(n => promises.push(limiter.queue(factoryFactory(n))));
|
||||
|
||||
return Promise.all(promises).then((res) => {
|
||||
assert.equal(10, res.length);
|
||||
assert.deepEqual([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], res);
|
||||
});
|
||||
});
|
||||
|
||||
test('Queue - simple', function () {
|
||||
let queue = new async.Queue();
|
||||
|
||||
let syncPromise = false;
|
||||
let f1 = () => Promise.resolve(true).then(() => syncPromise = true);
|
||||
|
||||
let asyncPromise = false;
|
||||
let f2 = () => async.timeout(10).then(() => asyncPromise = true);
|
||||
|
||||
assert.equal(queue.size, 0);
|
||||
|
||||
queue.queue(f1);
|
||||
assert.equal(queue.size, 1);
|
||||
|
||||
const p = queue.queue(f2);
|
||||
assert.equal(queue.size, 2);
|
||||
return p.then(() => {
|
||||
assert.equal(queue.size, 0);
|
||||
assert.ok(syncPromise);
|
||||
assert.ok(asyncPromise);
|
||||
});
|
||||
});
|
||||
|
||||
test('Queue - order is kept', function () {
|
||||
let queue = new async.Queue();
|
||||
|
||||
let res: number[] = [];
|
||||
|
||||
let f1 = () => Promise.resolve(true).then(() => res.push(1));
|
||||
let f2 = () => async.timeout(10).then(() => res.push(2));
|
||||
let f3 = () => Promise.resolve(true).then(() => res.push(3));
|
||||
let f4 = () => async.timeout(20).then(() => res.push(4));
|
||||
let f5 = () => async.timeout(0).then(() => res.push(5));
|
||||
|
||||
queue.queue(f1);
|
||||
queue.queue(f2);
|
||||
queue.queue(f3);
|
||||
queue.queue(f4);
|
||||
return queue.queue(f5).then(() => {
|
||||
assert.equal(res[0], 1);
|
||||
assert.equal(res[1], 2);
|
||||
assert.equal(res[2], 3);
|
||||
assert.equal(res[3], 4);
|
||||
assert.equal(res[4], 5);
|
||||
});
|
||||
});
|
||||
|
||||
test('Queue - errors bubble individually but not cause stop', function () {
|
||||
let queue = new async.Queue();
|
||||
|
||||
let res: number[] = [];
|
||||
let error = false;
|
||||
|
||||
let f1 = () => Promise.resolve(true).then(() => res.push(1));
|
||||
let f2 = () => async.timeout(10).then(() => res.push(2));
|
||||
let f3 = () => Promise.resolve(true).then(() => Promise.reject(new Error('error')));
|
||||
let f4 = () => async.timeout(20).then(() => res.push(4));
|
||||
let f5 = () => async.timeout(0).then(() => res.push(5));
|
||||
|
||||
queue.queue(f1);
|
||||
queue.queue(f2);
|
||||
queue.queue(f3).then(undefined, () => error = true);
|
||||
queue.queue(f4);
|
||||
return queue.queue(f5).then(() => {
|
||||
assert.equal(res[0], 1);
|
||||
assert.equal(res[1], 2);
|
||||
assert.ok(error);
|
||||
assert.equal(res[2], 4);
|
||||
assert.equal(res[3], 5);
|
||||
});
|
||||
});
|
||||
|
||||
test('Queue - order is kept (chained)', function () {
|
||||
let queue = new async.Queue();
|
||||
|
||||
let res: number[] = [];
|
||||
|
||||
let f1 = () => Promise.resolve(true).then(() => res.push(1));
|
||||
let f2 = () => async.timeout(10).then(() => res.push(2));
|
||||
let f3 = () => Promise.resolve(true).then(() => res.push(3));
|
||||
let f4 = () => async.timeout(20).then(() => res.push(4));
|
||||
let f5 = () => async.timeout(0).then(() => res.push(5));
|
||||
|
||||
return queue.queue(f1).then(() => {
|
||||
return queue.queue(f2).then(() => {
|
||||
return queue.queue(f3).then(() => {
|
||||
return queue.queue(f4).then(() => {
|
||||
return queue.queue(f5).then(() => {
|
||||
assert.equal(res[0], 1);
|
||||
assert.equal(res[1], 2);
|
||||
assert.equal(res[2], 3);
|
||||
assert.equal(res[3], 4);
|
||||
assert.equal(res[4], 5);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('Queue - events', function (done) {
|
||||
let queue = new async.Queue();
|
||||
|
||||
let finished = false;
|
||||
queue.onFinished(() => {
|
||||
done();
|
||||
});
|
||||
|
||||
let res: number[] = [];
|
||||
|
||||
let f1 = () => async.timeout(10).then(() => res.push(2));
|
||||
let f2 = () => async.timeout(20).then(() => res.push(4));
|
||||
let f3 = () => async.timeout(0).then(() => res.push(5));
|
||||
|
||||
const q1 = queue.queue(f1);
|
||||
const q2 = queue.queue(f2);
|
||||
queue.queue(f3);
|
||||
|
||||
q1.then(() => {
|
||||
assert.ok(!finished);
|
||||
q2.then(() => {
|
||||
assert.ok(!finished);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('ResourceQueue - simple', function () {
|
||||
let queue = new async.ResourceQueue();
|
||||
|
||||
const r1Queue = queue.queueFor(URI.file('/some/path'));
|
||||
|
||||
r1Queue.onFinished(() => console.log('DONE'));
|
||||
|
||||
const r2Queue = queue.queueFor(URI.file('/some/other/path'));
|
||||
|
||||
assert.ok(r1Queue);
|
||||
assert.ok(r2Queue);
|
||||
assert.equal(r1Queue, queue.queueFor(URI.file('/some/path'))); // same queue returned
|
||||
|
||||
let syncPromiseFactory = () => Promise.resolve(undefined);
|
||||
|
||||
r1Queue.queue(syncPromiseFactory);
|
||||
|
||||
return new Promise<void>(c => setTimeout(() => c(), 0)).then(() => {
|
||||
const r1Queue2 = queue.queueFor(URI.file('/some/path'));
|
||||
assert.notEqual(r1Queue, r1Queue2); // previous one got disposed after finishing
|
||||
});
|
||||
});
|
||||
|
||||
test('retry - success case', async () => {
|
||||
let counter = 0;
|
||||
|
||||
const res = await async.retry(() => {
|
||||
counter++;
|
||||
if (counter < 2) {
|
||||
return Promise.reject(new Error('fail'));
|
||||
}
|
||||
|
||||
return Promise.resolve(true);
|
||||
}, 10, 3);
|
||||
|
||||
assert.equal(res, true);
|
||||
});
|
||||
|
||||
test('retry - error case', async () => {
|
||||
let expectedError = new Error('fail');
|
||||
try {
|
||||
await async.retry(() => {
|
||||
return Promise.reject(expectedError);
|
||||
}, 10, 3);
|
||||
} catch (error) {
|
||||
assert.equal(error, error);
|
||||
}
|
||||
});
|
||||
|
||||
test('TaskSequentializer - pending basics', async function () {
|
||||
const sequentializer = new async.TaskSequentializer();
|
||||
|
||||
assert.ok(!sequentializer.hasPending());
|
||||
assert.ok(!sequentializer.hasPending(2323));
|
||||
assert.ok(!sequentializer.pending);
|
||||
|
||||
// pending removes itself after done
|
||||
await sequentializer.setPending(1, Promise.resolve());
|
||||
assert.ok(!sequentializer.hasPending());
|
||||
assert.ok(!sequentializer.hasPending(1));
|
||||
assert.ok(!sequentializer.pending);
|
||||
|
||||
// pending removes itself after done (use async.timeout)
|
||||
sequentializer.setPending(2, async.timeout(1));
|
||||
assert.ok(sequentializer.hasPending());
|
||||
assert.ok(sequentializer.hasPending(2));
|
||||
assert.ok(!sequentializer.hasPending(1));
|
||||
assert.ok(sequentializer.pending);
|
||||
|
||||
await async.timeout(2);
|
||||
assert.ok(!sequentializer.hasPending());
|
||||
assert.ok(!sequentializer.hasPending(2));
|
||||
assert.ok(!sequentializer.pending);
|
||||
});
|
||||
|
||||
test('TaskSequentializer - pending and next (finishes instantly)', async function () {
|
||||
const sequentializer = new async.TaskSequentializer();
|
||||
|
||||
let pendingDone = false;
|
||||
sequentializer.setPending(1, async.timeout(1).then(() => { pendingDone = true; return; }));
|
||||
|
||||
// next finishes instantly
|
||||
let nextDone = false;
|
||||
const res = sequentializer.setNext(() => Promise.resolve(null).then(() => { nextDone = true; return; }));
|
||||
|
||||
await res;
|
||||
assert.ok(pendingDone);
|
||||
assert.ok(nextDone);
|
||||
});
|
||||
|
||||
test('TaskSequentializer - pending and next (finishes after timeout)', async function () {
|
||||
const sequentializer = new async.TaskSequentializer();
|
||||
|
||||
let pendingDone = false;
|
||||
sequentializer.setPending(1, async.timeout(1).then(() => { pendingDone = true; return; }));
|
||||
|
||||
// next finishes after async.timeout
|
||||
let nextDone = false;
|
||||
const res = sequentializer.setNext(() => async.timeout(1).then(() => { nextDone = true; return; }));
|
||||
|
||||
await res;
|
||||
assert.ok(pendingDone);
|
||||
assert.ok(nextDone);
|
||||
});
|
||||
|
||||
test('TaskSequentializer - pending and multiple next (last one wins)', async function () {
|
||||
const sequentializer = new async.TaskSequentializer();
|
||||
|
||||
let pendingDone = false;
|
||||
sequentializer.setPending(1, async.timeout(1).then(() => { pendingDone = true; return; }));
|
||||
|
||||
// next finishes after async.timeout
|
||||
let firstDone = false;
|
||||
let firstRes = sequentializer.setNext(() => async.timeout(2).then(() => { firstDone = true; return; }));
|
||||
|
||||
let secondDone = false;
|
||||
let secondRes = sequentializer.setNext(() => async.timeout(3).then(() => { secondDone = true; return; }));
|
||||
|
||||
let thirdDone = false;
|
||||
let thirdRes = sequentializer.setNext(() => async.timeout(4).then(() => { thirdDone = true; return; }));
|
||||
|
||||
await Promise.all([firstRes, secondRes, thirdRes]);
|
||||
assert.ok(pendingDone);
|
||||
assert.ok(!firstDone);
|
||||
assert.ok(!secondDone);
|
||||
assert.ok(thirdDone);
|
||||
});
|
||||
|
||||
test('TaskSequentializer - cancel pending', async function () {
|
||||
const sequentializer = new async.TaskSequentializer();
|
||||
|
||||
let pendingCancelled = false;
|
||||
sequentializer.setPending(1, async.timeout(1), () => pendingCancelled = true);
|
||||
sequentializer.cancelPending();
|
||||
|
||||
assert.ok(pendingCancelled);
|
||||
});
|
||||
|
||||
test('raceCancellation', async () => {
|
||||
const cts = new CancellationTokenSource();
|
||||
|
||||
const now = Date.now();
|
||||
|
||||
const p = async.raceCancellation(async.timeout(100), cts.token);
|
||||
cts.cancel();
|
||||
|
||||
await p;
|
||||
|
||||
assert.ok(Date.now() - now < 100);
|
||||
});
|
||||
|
||||
test('raceTimeout', async () => {
|
||||
const cts = new CancellationTokenSource();
|
||||
|
||||
// timeout wins
|
||||
let now = Date.now();
|
||||
let timedout = false;
|
||||
|
||||
const p1 = async.raceTimeout(async.timeout(100), 1, () => timedout = true);
|
||||
cts.cancel();
|
||||
|
||||
await p1;
|
||||
|
||||
assert.ok(Date.now() - now < 100);
|
||||
assert.equal(timedout, true);
|
||||
|
||||
// promise wins
|
||||
now = Date.now();
|
||||
timedout = false;
|
||||
|
||||
const p2 = async.raceTimeout(async.timeout(1), 100, () => timedout = true);
|
||||
cts.cancel();
|
||||
|
||||
await p2;
|
||||
|
||||
assert.ok(Date.now() - now < 100);
|
||||
assert.equal(timedout, false);
|
||||
});
|
||||
|
||||
test('SequencerByKey', async () => {
|
||||
const s = new async.SequencerByKey<string>();
|
||||
|
||||
const r1 = await s.queue('key1', () => Promise.resolve('hello'));
|
||||
assert.equal(r1, 'hello');
|
||||
|
||||
await s.queue('key2', () => Promise.reject(new Error('failed'))).then(() => {
|
||||
throw new Error('should not be resolved');
|
||||
}, err => {
|
||||
// Expected error
|
||||
assert.equal(err.message, 'failed');
|
||||
});
|
||||
|
||||
// Still works after a queued promise is rejected
|
||||
const r3 = await s.queue('key2', () => Promise.resolve('hello'));
|
||||
assert.equal(r3, 'hello');
|
||||
});
|
||||
|
||||
test('IntervalCounter', async () => {
|
||||
const counter = new async.IntervalCounter(10);
|
||||
assert.equal(counter.increment(), 1);
|
||||
assert.equal(counter.increment(), 2);
|
||||
assert.equal(counter.increment(), 3);
|
||||
|
||||
await async.timeout(20);
|
||||
|
||||
assert.equal(counter.increment(), 1);
|
||||
assert.equal(counter.increment(), 2);
|
||||
assert.equal(counter.increment(), 3);
|
||||
});
|
||||
});
|
||||
65
lib/vscode/src/vs/base/test/common/cache.test.ts
Normal file
65
lib/vscode/src/vs/base/test/common/cache.test.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { Cache } from 'vs/base/common/cache';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
|
||||
suite('Cache', () => {
|
||||
|
||||
test('simple value', () => {
|
||||
let counter = 0;
|
||||
const cache = new Cache(_ => Promise.resolve(counter++));
|
||||
|
||||
return cache.get().promise
|
||||
.then(c => assert.equal(c, 0), () => assert.fail('Unexpected assertion error'))
|
||||
.then(() => cache.get().promise)
|
||||
.then(c => assert.equal(c, 0), () => assert.fail('Unexpected assertion error'));
|
||||
});
|
||||
|
||||
test('simple error', () => {
|
||||
let counter = 0;
|
||||
const cache = new Cache(_ => Promise.reject(new Error(String(counter++))));
|
||||
|
||||
return cache.get().promise
|
||||
.then(() => assert.fail('Unexpected assertion error'), err => assert.equal(err.message, 0))
|
||||
.then(() => cache.get().promise)
|
||||
.then(() => assert.fail('Unexpected assertion error'), err => assert.equal(err.message, 0));
|
||||
});
|
||||
|
||||
test('should retry cancellations', () => {
|
||||
let counter1 = 0, counter2 = 0;
|
||||
|
||||
const cache = new Cache(token => {
|
||||
counter1++;
|
||||
return Promise.resolve(timeout(2, token).then(() => counter2++));
|
||||
});
|
||||
|
||||
assert.equal(counter1, 0);
|
||||
assert.equal(counter2, 0);
|
||||
let result = cache.get();
|
||||
assert.equal(counter1, 1);
|
||||
assert.equal(counter2, 0);
|
||||
result.promise.then(undefined, () => assert(true));
|
||||
result.dispose();
|
||||
assert.equal(counter1, 1);
|
||||
assert.equal(counter2, 0);
|
||||
|
||||
result = cache.get();
|
||||
assert.equal(counter1, 2);
|
||||
assert.equal(counter2, 0);
|
||||
|
||||
return result.promise
|
||||
.then(c => {
|
||||
assert.equal(counter1, 2);
|
||||
assert.equal(counter2, 1);
|
||||
})
|
||||
.then(() => cache.get().promise)
|
||||
.then(c => {
|
||||
assert.equal(counter1, 2);
|
||||
assert.equal(counter2, 1);
|
||||
});
|
||||
});
|
||||
});
|
||||
126
lib/vscode/src/vs/base/test/common/cancellation.test.ts
Normal file
126
lib/vscode/src/vs/base/test/common/cancellation.test.ts
Normal file
@@ -0,0 +1,126 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as assert from 'assert';
|
||||
import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
||||
suite('CancellationToken', function () {
|
||||
|
||||
test('None', () => {
|
||||
assert.equal(CancellationToken.None.isCancellationRequested, false);
|
||||
assert.equal(typeof CancellationToken.None.onCancellationRequested, 'function');
|
||||
});
|
||||
|
||||
test('cancel before token', function (done) {
|
||||
|
||||
const source = new CancellationTokenSource();
|
||||
assert.equal(source.token.isCancellationRequested, false);
|
||||
source.cancel();
|
||||
|
||||
assert.equal(source.token.isCancellationRequested, true);
|
||||
|
||||
source.token.onCancellationRequested(function () {
|
||||
assert.ok(true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('cancel happens only once', function () {
|
||||
|
||||
let source = new CancellationTokenSource();
|
||||
assert.equal(source.token.isCancellationRequested, false);
|
||||
|
||||
let cancelCount = 0;
|
||||
function onCancel() {
|
||||
cancelCount += 1;
|
||||
}
|
||||
|
||||
source.token.onCancellationRequested(onCancel);
|
||||
|
||||
source.cancel();
|
||||
source.cancel();
|
||||
|
||||
assert.equal(cancelCount, 1);
|
||||
});
|
||||
|
||||
test('cancel calls all listeners', function () {
|
||||
|
||||
let count = 0;
|
||||
|
||||
let source = new CancellationTokenSource();
|
||||
source.token.onCancellationRequested(function () {
|
||||
count += 1;
|
||||
});
|
||||
source.token.onCancellationRequested(function () {
|
||||
count += 1;
|
||||
});
|
||||
source.token.onCancellationRequested(function () {
|
||||
count += 1;
|
||||
});
|
||||
|
||||
source.cancel();
|
||||
assert.equal(count, 3);
|
||||
});
|
||||
|
||||
test('token stays the same', function () {
|
||||
|
||||
let source = new CancellationTokenSource();
|
||||
let token = source.token;
|
||||
assert.ok(token === source.token); // doesn't change on get
|
||||
|
||||
source.cancel();
|
||||
assert.ok(token === source.token); // doesn't change after cancel
|
||||
|
||||
source.cancel();
|
||||
assert.ok(token === source.token); // doesn't change after 2nd cancel
|
||||
|
||||
source = new CancellationTokenSource();
|
||||
source.cancel();
|
||||
token = source.token;
|
||||
assert.ok(token === source.token); // doesn't change on get
|
||||
});
|
||||
|
||||
test('dispose calls no listeners', function () {
|
||||
|
||||
let count = 0;
|
||||
|
||||
let source = new CancellationTokenSource();
|
||||
source.token.onCancellationRequested(function () {
|
||||
count += 1;
|
||||
});
|
||||
|
||||
source.dispose();
|
||||
source.cancel();
|
||||
assert.equal(count, 0);
|
||||
});
|
||||
|
||||
test('dispose calls no listeners (unless told to cancel)', function () {
|
||||
|
||||
let count = 0;
|
||||
|
||||
let source = new CancellationTokenSource();
|
||||
source.token.onCancellationRequested(function () {
|
||||
count += 1;
|
||||
});
|
||||
|
||||
source.dispose(true);
|
||||
// source.cancel();
|
||||
assert.equal(count, 1);
|
||||
});
|
||||
|
||||
test('parent cancels child', function () {
|
||||
|
||||
let parent = new CancellationTokenSource();
|
||||
let child = new CancellationTokenSource(parent.token);
|
||||
|
||||
let count = 0;
|
||||
child.token.onCancellationRequested(() => count += 1);
|
||||
|
||||
parent.cancel();
|
||||
|
||||
assert.equal(count, 1);
|
||||
assert.equal(child.token.isCancellationRequested, true);
|
||||
assert.equal(parent.token.isCancellationRequested, true);
|
||||
});
|
||||
});
|
||||
121
lib/vscode/src/vs/base/test/common/charCode.test.ts
Normal file
121
lib/vscode/src/vs/base/test/common/charCode.test.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { CharCode } from 'vs/base/common/charCode';
|
||||
|
||||
suite('CharCode', () => {
|
||||
test('has good values', () => {
|
||||
|
||||
function assertValue(actual: CharCode, expected: string): void {
|
||||
assert.equal(actual, expected.charCodeAt(0), 'char code ok for <<' + expected + '>>');
|
||||
}
|
||||
|
||||
assertValue(CharCode.Tab, '\t');
|
||||
assertValue(CharCode.LineFeed, '\n');
|
||||
assertValue(CharCode.CarriageReturn, '\r');
|
||||
assertValue(CharCode.Space, ' ');
|
||||
assertValue(CharCode.ExclamationMark, '!');
|
||||
assertValue(CharCode.DoubleQuote, '"');
|
||||
assertValue(CharCode.Hash, '#');
|
||||
assertValue(CharCode.DollarSign, '$');
|
||||
assertValue(CharCode.PercentSign, '%');
|
||||
assertValue(CharCode.Ampersand, '&');
|
||||
assertValue(CharCode.SingleQuote, '\'');
|
||||
assertValue(CharCode.OpenParen, '(');
|
||||
assertValue(CharCode.CloseParen, ')');
|
||||
assertValue(CharCode.Asterisk, '*');
|
||||
assertValue(CharCode.Plus, '+');
|
||||
assertValue(CharCode.Comma, ',');
|
||||
assertValue(CharCode.Dash, '-');
|
||||
assertValue(CharCode.Period, '.');
|
||||
assertValue(CharCode.Slash, '/');
|
||||
|
||||
assertValue(CharCode.Digit0, '0');
|
||||
assertValue(CharCode.Digit1, '1');
|
||||
assertValue(CharCode.Digit2, '2');
|
||||
assertValue(CharCode.Digit3, '3');
|
||||
assertValue(CharCode.Digit4, '4');
|
||||
assertValue(CharCode.Digit5, '5');
|
||||
assertValue(CharCode.Digit6, '6');
|
||||
assertValue(CharCode.Digit7, '7');
|
||||
assertValue(CharCode.Digit8, '8');
|
||||
assertValue(CharCode.Digit9, '9');
|
||||
|
||||
assertValue(CharCode.Colon, ':');
|
||||
assertValue(CharCode.Semicolon, ';');
|
||||
assertValue(CharCode.LessThan, '<');
|
||||
assertValue(CharCode.Equals, '=');
|
||||
assertValue(CharCode.GreaterThan, '>');
|
||||
assertValue(CharCode.QuestionMark, '?');
|
||||
assertValue(CharCode.AtSign, '@');
|
||||
|
||||
assertValue(CharCode.A, 'A');
|
||||
assertValue(CharCode.B, 'B');
|
||||
assertValue(CharCode.C, 'C');
|
||||
assertValue(CharCode.D, 'D');
|
||||
assertValue(CharCode.E, 'E');
|
||||
assertValue(CharCode.F, 'F');
|
||||
assertValue(CharCode.G, 'G');
|
||||
assertValue(CharCode.H, 'H');
|
||||
assertValue(CharCode.I, 'I');
|
||||
assertValue(CharCode.J, 'J');
|
||||
assertValue(CharCode.K, 'K');
|
||||
assertValue(CharCode.L, 'L');
|
||||
assertValue(CharCode.M, 'M');
|
||||
assertValue(CharCode.N, 'N');
|
||||
assertValue(CharCode.O, 'O');
|
||||
assertValue(CharCode.P, 'P');
|
||||
assertValue(CharCode.Q, 'Q');
|
||||
assertValue(CharCode.R, 'R');
|
||||
assertValue(CharCode.S, 'S');
|
||||
assertValue(CharCode.T, 'T');
|
||||
assertValue(CharCode.U, 'U');
|
||||
assertValue(CharCode.V, 'V');
|
||||
assertValue(CharCode.W, 'W');
|
||||
assertValue(CharCode.X, 'X');
|
||||
assertValue(CharCode.Y, 'Y');
|
||||
assertValue(CharCode.Z, 'Z');
|
||||
|
||||
assertValue(CharCode.OpenSquareBracket, '[');
|
||||
assertValue(CharCode.Backslash, '\\');
|
||||
assertValue(CharCode.CloseSquareBracket, ']');
|
||||
assertValue(CharCode.Caret, '^');
|
||||
assertValue(CharCode.Underline, '_');
|
||||
assertValue(CharCode.BackTick, '`');
|
||||
|
||||
assertValue(CharCode.a, 'a');
|
||||
assertValue(CharCode.b, 'b');
|
||||
assertValue(CharCode.c, 'c');
|
||||
assertValue(CharCode.d, 'd');
|
||||
assertValue(CharCode.e, 'e');
|
||||
assertValue(CharCode.f, 'f');
|
||||
assertValue(CharCode.g, 'g');
|
||||
assertValue(CharCode.h, 'h');
|
||||
assertValue(CharCode.i, 'i');
|
||||
assertValue(CharCode.j, 'j');
|
||||
assertValue(CharCode.k, 'k');
|
||||
assertValue(CharCode.l, 'l');
|
||||
assertValue(CharCode.m, 'm');
|
||||
assertValue(CharCode.n, 'n');
|
||||
assertValue(CharCode.o, 'o');
|
||||
assertValue(CharCode.p, 'p');
|
||||
assertValue(CharCode.q, 'q');
|
||||
assertValue(CharCode.r, 'r');
|
||||
assertValue(CharCode.s, 's');
|
||||
assertValue(CharCode.t, 't');
|
||||
assertValue(CharCode.u, 'u');
|
||||
assertValue(CharCode.v, 'v');
|
||||
assertValue(CharCode.w, 'w');
|
||||
assertValue(CharCode.x, 'x');
|
||||
assertValue(CharCode.y, 'y');
|
||||
assertValue(CharCode.z, 'z');
|
||||
|
||||
assertValue(CharCode.OpenCurlyBrace, '{');
|
||||
assertValue(CharCode.Pipe, '|');
|
||||
assertValue(CharCode.CloseCurlyBrace, '}');
|
||||
assertValue(CharCode.Tilde, '~');
|
||||
});
|
||||
});
|
||||
78
lib/vscode/src/vs/base/test/common/codicon.test.ts
Normal file
78
lib/vscode/src/vs/base/test/common/codicon.test.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { IMatch } from 'vs/base/common/filters';
|
||||
import { matchesFuzzyCodiconAware, parseCodicons, IParsedCodicons } from 'vs/base/common/codicon';
|
||||
import { stripCodicons } from 'vs/base/common/codicons';
|
||||
|
||||
export interface ICodiconFilter {
|
||||
// Returns null if word doesn't match.
|
||||
(query: string, target: IParsedCodicons): IMatch[] | null;
|
||||
}
|
||||
|
||||
function filterOk(filter: ICodiconFilter, word: string, target: IParsedCodicons, highlights?: { start: number; end: number; }[]) {
|
||||
let r = filter(word, target);
|
||||
assert(r);
|
||||
if (highlights) {
|
||||
assert.deepEqual(r, highlights);
|
||||
}
|
||||
}
|
||||
|
||||
suite('Codicon', () => {
|
||||
test('matchesFuzzzyCodiconAware', () => {
|
||||
|
||||
// Camel Case
|
||||
|
||||
filterOk(matchesFuzzyCodiconAware, 'ccr', parseCodicons('$(codicon)CamelCaseRocks$(codicon)'), [
|
||||
{ start: 10, end: 11 },
|
||||
{ start: 15, end: 16 },
|
||||
{ start: 19, end: 20 }
|
||||
]);
|
||||
|
||||
filterOk(matchesFuzzyCodiconAware, 'ccr', parseCodicons('$(codicon) CamelCaseRocks $(codicon)'), [
|
||||
{ start: 11, end: 12 },
|
||||
{ start: 16, end: 17 },
|
||||
{ start: 20, end: 21 }
|
||||
]);
|
||||
|
||||
filterOk(matchesFuzzyCodiconAware, 'iut', parseCodicons('$(codicon) Indent $(octico) Using $(octic) Tpaces'), [
|
||||
{ start: 11, end: 12 },
|
||||
{ start: 28, end: 29 },
|
||||
{ start: 43, end: 44 },
|
||||
]);
|
||||
|
||||
// Prefix
|
||||
|
||||
filterOk(matchesFuzzyCodiconAware, 'using', parseCodicons('$(codicon) Indent Using Spaces'), [
|
||||
{ start: 18, end: 23 },
|
||||
]);
|
||||
|
||||
// Broken Codicon
|
||||
|
||||
filterOk(matchesFuzzyCodiconAware, 'codicon', parseCodicons('This $(codicon Indent Using Spaces'), [
|
||||
{ start: 7, end: 14 },
|
||||
]);
|
||||
|
||||
filterOk(matchesFuzzyCodiconAware, 'indent', parseCodicons('This $codicon Indent Using Spaces'), [
|
||||
{ start: 14, end: 20 },
|
||||
]);
|
||||
|
||||
// Testing #59343
|
||||
filterOk(matchesFuzzyCodiconAware, 'unt', parseCodicons('$(primitive-dot) $(file-text) Untitled-1'), [
|
||||
{ start: 30, end: 33 },
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
suite('Codicons', () => {
|
||||
|
||||
test('stripCodicons', () => {
|
||||
assert.equal(stripCodicons('Hello World'), 'Hello World');
|
||||
assert.equal(stripCodicons('$(Hello World'), '$(Hello World');
|
||||
assert.equal(stripCodicons('$(Hello) World'), ' World');
|
||||
assert.equal(stripCodicons('$(Hello) W$(oi)rld'), ' Wrld');
|
||||
});
|
||||
});
|
||||
56
lib/vscode/src/vs/base/test/common/collections.test.ts
Normal file
56
lib/vscode/src/vs/base/test/common/collections.test.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import * as collections from 'vs/base/common/collections';
|
||||
|
||||
suite('Collections', () => {
|
||||
|
||||
test('forEach', () => {
|
||||
collections.forEach({}, () => assert(false));
|
||||
collections.forEach(Object.create(null), () => assert(false));
|
||||
|
||||
let count = 0;
|
||||
collections.forEach({ toString: 123 }, () => count++);
|
||||
assert.equal(count, 1);
|
||||
|
||||
count = 0;
|
||||
let dict = Object.create(null);
|
||||
dict['toString'] = 123;
|
||||
collections.forEach(dict, () => count++);
|
||||
assert.equal(count, 1);
|
||||
|
||||
collections.forEach(dict, () => false);
|
||||
|
||||
collections.forEach(dict, (x, remove) => remove());
|
||||
assert.equal(dict['toString'], null);
|
||||
|
||||
// don't iterate over properties that are not on the object itself
|
||||
let test = Object.create({ 'derived': true });
|
||||
collections.forEach(test, () => assert(false));
|
||||
});
|
||||
|
||||
test('groupBy', () => {
|
||||
|
||||
const group1 = 'a', group2 = 'b';
|
||||
const value1 = 1, value2 = 2, value3 = 3;
|
||||
let source = [
|
||||
{ key: group1, value: value1 },
|
||||
{ key: group1, value: value2 },
|
||||
{ key: group2, value: value3 },
|
||||
];
|
||||
|
||||
let grouped = collections.groupBy(source, x => x.key);
|
||||
|
||||
// Group 1
|
||||
assert.equal(grouped[group1].length, 2);
|
||||
assert.equal(grouped[group1][0].value, value1);
|
||||
assert.equal(grouped[group1][1].value, value2);
|
||||
|
||||
// Group 2
|
||||
assert.equal(grouped[group2].length, 1);
|
||||
assert.equal(grouped[group2][0].value, value3);
|
||||
});
|
||||
});
|
||||
253
lib/vscode/src/vs/base/test/common/color.test.ts
Normal file
253
lib/vscode/src/vs/base/test/common/color.test.ts
Normal file
@@ -0,0 +1,253 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { Color, RGBA, HSLA, HSVA } from 'vs/base/common/color';
|
||||
|
||||
suite('Color', () => {
|
||||
|
||||
test('isLighterColor', () => {
|
||||
let color1 = new Color(new HSLA(60, 1, 0.5, 1)), color2 = new Color(new HSLA(0, 0, 0.753, 1));
|
||||
|
||||
assert.ok(color1.isLighterThan(color2));
|
||||
|
||||
// Abyss theme
|
||||
assert.ok(Color.fromHex('#770811').isLighterThan(Color.fromHex('#000c18')));
|
||||
});
|
||||
|
||||
test('getLighterColor', () => {
|
||||
let color1 = new Color(new HSLA(60, 1, 0.5, 1)), color2 = new Color(new HSLA(0, 0, 0.753, 1));
|
||||
|
||||
assert.deepEqual(color1.hsla, Color.getLighterColor(color1, color2).hsla);
|
||||
assert.deepEqual(new HSLA(0, 0, 0.916, 1), Color.getLighterColor(color2, color1).hsla);
|
||||
assert.deepEqual(new HSLA(0, 0, 0.851, 1), Color.getLighterColor(color2, color1, 0.3).hsla);
|
||||
assert.deepEqual(new HSLA(0, 0, 0.981, 1), Color.getLighterColor(color2, color1, 0.7).hsla);
|
||||
assert.deepEqual(new HSLA(0, 0, 1, 1), Color.getLighterColor(color2, color1, 1).hsla);
|
||||
|
||||
});
|
||||
|
||||
test('isDarkerColor', () => {
|
||||
let color1 = new Color(new HSLA(60, 1, 0.5, 1)), color2 = new Color(new HSLA(0, 0, 0.753, 1));
|
||||
|
||||
assert.ok(color2.isDarkerThan(color1));
|
||||
|
||||
});
|
||||
|
||||
test('getDarkerColor', () => {
|
||||
let color1 = new Color(new HSLA(60, 1, 0.5, 1)), color2 = new Color(new HSLA(0, 0, 0.753, 1));
|
||||
|
||||
assert.deepEqual(color2.hsla, Color.getDarkerColor(color2, color1).hsla);
|
||||
assert.deepEqual(new HSLA(60, 1, 0.392, 1), Color.getDarkerColor(color1, color2).hsla);
|
||||
assert.deepEqual(new HSLA(60, 1, 0.435, 1), Color.getDarkerColor(color1, color2, 0.3).hsla);
|
||||
assert.deepEqual(new HSLA(60, 1, 0.349, 1), Color.getDarkerColor(color1, color2, 0.7).hsla);
|
||||
assert.deepEqual(new HSLA(60, 1, 0.284, 1), Color.getDarkerColor(color1, color2, 1).hsla);
|
||||
|
||||
// Abyss theme
|
||||
assert.deepEqual(new HSLA(355, 0.874, 0.157, 1), Color.getDarkerColor(Color.fromHex('#770811'), Color.fromHex('#000c18'), 0.4).hsla);
|
||||
});
|
||||
|
||||
test('luminance', () => {
|
||||
assert.deepEqual(0, new Color(new RGBA(0, 0, 0, 1)).getRelativeLuminance());
|
||||
assert.deepEqual(1, new Color(new RGBA(255, 255, 255, 1)).getRelativeLuminance());
|
||||
|
||||
assert.deepEqual(0.2126, new Color(new RGBA(255, 0, 0, 1)).getRelativeLuminance());
|
||||
assert.deepEqual(0.7152, new Color(new RGBA(0, 255, 0, 1)).getRelativeLuminance());
|
||||
assert.deepEqual(0.0722, new Color(new RGBA(0, 0, 255, 1)).getRelativeLuminance());
|
||||
|
||||
assert.deepEqual(0.9278, new Color(new RGBA(255, 255, 0, 1)).getRelativeLuminance());
|
||||
assert.deepEqual(0.7874, new Color(new RGBA(0, 255, 255, 1)).getRelativeLuminance());
|
||||
assert.deepEqual(0.2848, new Color(new RGBA(255, 0, 255, 1)).getRelativeLuminance());
|
||||
|
||||
assert.deepEqual(0.5271, new Color(new RGBA(192, 192, 192, 1)).getRelativeLuminance());
|
||||
|
||||
assert.deepEqual(0.2159, new Color(new RGBA(128, 128, 128, 1)).getRelativeLuminance());
|
||||
assert.deepEqual(0.0459, new Color(new RGBA(128, 0, 0, 1)).getRelativeLuminance());
|
||||
assert.deepEqual(0.2003, new Color(new RGBA(128, 128, 0, 1)).getRelativeLuminance());
|
||||
assert.deepEqual(0.1544, new Color(new RGBA(0, 128, 0, 1)).getRelativeLuminance());
|
||||
assert.deepEqual(0.0615, new Color(new RGBA(128, 0, 128, 1)).getRelativeLuminance());
|
||||
assert.deepEqual(0.17, new Color(new RGBA(0, 128, 128, 1)).getRelativeLuminance());
|
||||
assert.deepEqual(0.0156, new Color(new RGBA(0, 0, 128, 1)).getRelativeLuminance());
|
||||
});
|
||||
|
||||
test('blending', () => {
|
||||
assert.deepEqual(new Color(new RGBA(0, 0, 0, 0)).blend(new Color(new RGBA(243, 34, 43))), new Color(new RGBA(243, 34, 43)));
|
||||
assert.deepEqual(new Color(new RGBA(255, 255, 255)).blend(new Color(new RGBA(243, 34, 43))), new Color(new RGBA(255, 255, 255)));
|
||||
assert.deepEqual(new Color(new RGBA(122, 122, 122, 0.7)).blend(new Color(new RGBA(243, 34, 43))), new Color(new RGBA(158, 95, 98)));
|
||||
assert.deepEqual(new Color(new RGBA(0, 0, 0, 0.58)).blend(new Color(new RGBA(255, 255, 255, 0.33))), new Color(new RGBA(49, 49, 49, 0.719)));
|
||||
});
|
||||
|
||||
suite('HSLA', () => {
|
||||
test('HSLA.toRGBA', () => {
|
||||
assert.deepEqual(HSLA.toRGBA(new HSLA(0, 0, 0, 0)), new RGBA(0, 0, 0, 0));
|
||||
assert.deepEqual(HSLA.toRGBA(new HSLA(0, 0, 0, 1)), new RGBA(0, 0, 0, 1));
|
||||
assert.deepEqual(HSLA.toRGBA(new HSLA(0, 0, 1, 1)), new RGBA(255, 255, 255, 1));
|
||||
|
||||
assert.deepEqual(HSLA.toRGBA(new HSLA(0, 1, 0.5, 1)), new RGBA(255, 0, 0, 1));
|
||||
assert.deepEqual(HSLA.toRGBA(new HSLA(120, 1, 0.5, 1)), new RGBA(0, 255, 0, 1));
|
||||
assert.deepEqual(HSLA.toRGBA(new HSLA(240, 1, 0.5, 1)), new RGBA(0, 0, 255, 1));
|
||||
|
||||
assert.deepEqual(HSLA.toRGBA(new HSLA(60, 1, 0.5, 1)), new RGBA(255, 255, 0, 1));
|
||||
assert.deepEqual(HSLA.toRGBA(new HSLA(180, 1, 0.5, 1)), new RGBA(0, 255, 255, 1));
|
||||
assert.deepEqual(HSLA.toRGBA(new HSLA(300, 1, 0.5, 1)), new RGBA(255, 0, 255, 1));
|
||||
|
||||
assert.deepEqual(HSLA.toRGBA(new HSLA(0, 0, 0.753, 1)), new RGBA(192, 192, 192, 1));
|
||||
|
||||
assert.deepEqual(HSLA.toRGBA(new HSLA(0, 0, 0.502, 1)), new RGBA(128, 128, 128, 1));
|
||||
assert.deepEqual(HSLA.toRGBA(new HSLA(0, 1, 0.251, 1)), new RGBA(128, 0, 0, 1));
|
||||
assert.deepEqual(HSLA.toRGBA(new HSLA(60, 1, 0.251, 1)), new RGBA(128, 128, 0, 1));
|
||||
assert.deepEqual(HSLA.toRGBA(new HSLA(120, 1, 0.251, 1)), new RGBA(0, 128, 0, 1));
|
||||
assert.deepEqual(HSLA.toRGBA(new HSLA(300, 1, 0.251, 1)), new RGBA(128, 0, 128, 1));
|
||||
assert.deepEqual(HSLA.toRGBA(new HSLA(180, 1, 0.251, 1)), new RGBA(0, 128, 128, 1));
|
||||
assert.deepEqual(HSLA.toRGBA(new HSLA(240, 1, 0.251, 1)), new RGBA(0, 0, 128, 1));
|
||||
});
|
||||
|
||||
test('HSLA.fromRGBA', () => {
|
||||
assert.deepEqual(HSLA.fromRGBA(new RGBA(0, 0, 0, 0)), new HSLA(0, 0, 0, 0));
|
||||
assert.deepEqual(HSLA.fromRGBA(new RGBA(0, 0, 0, 1)), new HSLA(0, 0, 0, 1));
|
||||
assert.deepEqual(HSLA.fromRGBA(new RGBA(255, 255, 255, 1)), new HSLA(0, 0, 1, 1));
|
||||
|
||||
assert.deepEqual(HSLA.fromRGBA(new RGBA(255, 0, 0, 1)), new HSLA(0, 1, 0.5, 1));
|
||||
assert.deepEqual(HSLA.fromRGBA(new RGBA(0, 255, 0, 1)), new HSLA(120, 1, 0.5, 1));
|
||||
assert.deepEqual(HSLA.fromRGBA(new RGBA(0, 0, 255, 1)), new HSLA(240, 1, 0.5, 1));
|
||||
|
||||
assert.deepEqual(HSLA.fromRGBA(new RGBA(255, 255, 0, 1)), new HSLA(60, 1, 0.5, 1));
|
||||
assert.deepEqual(HSLA.fromRGBA(new RGBA(0, 255, 255, 1)), new HSLA(180, 1, 0.5, 1));
|
||||
assert.deepEqual(HSLA.fromRGBA(new RGBA(255, 0, 255, 1)), new HSLA(300, 1, 0.5, 1));
|
||||
|
||||
assert.deepEqual(HSLA.fromRGBA(new RGBA(192, 192, 192, 1)), new HSLA(0, 0, 0.753, 1));
|
||||
|
||||
assert.deepEqual(HSLA.fromRGBA(new RGBA(128, 128, 128, 1)), new HSLA(0, 0, 0.502, 1));
|
||||
assert.deepEqual(HSLA.fromRGBA(new RGBA(128, 0, 0, 1)), new HSLA(0, 1, 0.251, 1));
|
||||
assert.deepEqual(HSLA.fromRGBA(new RGBA(128, 128, 0, 1)), new HSLA(60, 1, 0.251, 1));
|
||||
assert.deepEqual(HSLA.fromRGBA(new RGBA(0, 128, 0, 1)), new HSLA(120, 1, 0.251, 1));
|
||||
assert.deepEqual(HSLA.fromRGBA(new RGBA(128, 0, 128, 1)), new HSLA(300, 1, 0.251, 1));
|
||||
assert.deepEqual(HSLA.fromRGBA(new RGBA(0, 128, 128, 1)), new HSLA(180, 1, 0.251, 1));
|
||||
assert.deepEqual(HSLA.fromRGBA(new RGBA(0, 0, 128, 1)), new HSLA(240, 1, 0.251, 1));
|
||||
});
|
||||
});
|
||||
|
||||
suite('HSVA', () => {
|
||||
test('HSVA.toRGBA', () => {
|
||||
assert.deepEqual(HSVA.toRGBA(new HSVA(0, 0, 0, 0)), new RGBA(0, 0, 0, 0));
|
||||
assert.deepEqual(HSVA.toRGBA(new HSVA(0, 0, 0, 1)), new RGBA(0, 0, 0, 1));
|
||||
assert.deepEqual(HSVA.toRGBA(new HSVA(0, 0, 1, 1)), new RGBA(255, 255, 255, 1));
|
||||
|
||||
assert.deepEqual(HSVA.toRGBA(new HSVA(0, 1, 1, 1)), new RGBA(255, 0, 0, 1));
|
||||
assert.deepEqual(HSVA.toRGBA(new HSVA(120, 1, 1, 1)), new RGBA(0, 255, 0, 1));
|
||||
assert.deepEqual(HSVA.toRGBA(new HSVA(240, 1, 1, 1)), new RGBA(0, 0, 255, 1));
|
||||
|
||||
assert.deepEqual(HSVA.toRGBA(new HSVA(60, 1, 1, 1)), new RGBA(255, 255, 0, 1));
|
||||
assert.deepEqual(HSVA.toRGBA(new HSVA(180, 1, 1, 1)), new RGBA(0, 255, 255, 1));
|
||||
assert.deepEqual(HSVA.toRGBA(new HSVA(300, 1, 1, 1)), new RGBA(255, 0, 255, 1));
|
||||
|
||||
assert.deepEqual(HSVA.toRGBA(new HSVA(0, 0, 0.753, 1)), new RGBA(192, 192, 192, 1));
|
||||
|
||||
assert.deepEqual(HSVA.toRGBA(new HSVA(0, 0, 0.502, 1)), new RGBA(128, 128, 128, 1));
|
||||
assert.deepEqual(HSVA.toRGBA(new HSVA(0, 1, 0.502, 1)), new RGBA(128, 0, 0, 1));
|
||||
assert.deepEqual(HSVA.toRGBA(new HSVA(60, 1, 0.502, 1)), new RGBA(128, 128, 0, 1));
|
||||
assert.deepEqual(HSVA.toRGBA(new HSVA(120, 1, 0.502, 1)), new RGBA(0, 128, 0, 1));
|
||||
assert.deepEqual(HSVA.toRGBA(new HSVA(300, 1, 0.502, 1)), new RGBA(128, 0, 128, 1));
|
||||
assert.deepEqual(HSVA.toRGBA(new HSVA(180, 1, 0.502, 1)), new RGBA(0, 128, 128, 1));
|
||||
assert.deepEqual(HSVA.toRGBA(new HSVA(240, 1, 0.502, 1)), new RGBA(0, 0, 128, 1));
|
||||
|
||||
assert.deepEqual(HSVA.toRGBA(new HSVA(360, 0, 0, 0)), new RGBA(0, 0, 0, 0));
|
||||
assert.deepEqual(HSVA.toRGBA(new HSVA(360, 0, 0, 1)), new RGBA(0, 0, 0, 1));
|
||||
assert.deepEqual(HSVA.toRGBA(new HSVA(360, 0, 1, 1)), new RGBA(255, 255, 255, 1));
|
||||
assert.deepEqual(HSVA.toRGBA(new HSVA(360, 1, 1, 1)), new RGBA(255, 0, 0, 1));
|
||||
assert.deepEqual(HSVA.toRGBA(new HSVA(360, 0, 0.753, 1)), new RGBA(192, 192, 192, 1));
|
||||
assert.deepEqual(HSVA.toRGBA(new HSVA(360, 0, 0.502, 1)), new RGBA(128, 128, 128, 1));
|
||||
assert.deepEqual(HSVA.toRGBA(new HSVA(360, 1, 0.502, 1)), new RGBA(128, 0, 0, 1));
|
||||
|
||||
});
|
||||
|
||||
test('HSVA.fromRGBA', () => {
|
||||
|
||||
assert.deepEqual(HSVA.fromRGBA(new RGBA(0, 0, 0, 0)), new HSVA(0, 0, 0, 0));
|
||||
assert.deepEqual(HSVA.fromRGBA(new RGBA(0, 0, 0, 1)), new HSVA(0, 0, 0, 1));
|
||||
assert.deepEqual(HSVA.fromRGBA(new RGBA(255, 255, 255, 1)), new HSVA(0, 0, 1, 1));
|
||||
|
||||
assert.deepEqual(HSVA.fromRGBA(new RGBA(255, 0, 0, 1)), new HSVA(0, 1, 1, 1));
|
||||
assert.deepEqual(HSVA.fromRGBA(new RGBA(0, 255, 0, 1)), new HSVA(120, 1, 1, 1));
|
||||
assert.deepEqual(HSVA.fromRGBA(new RGBA(0, 0, 255, 1)), new HSVA(240, 1, 1, 1));
|
||||
|
||||
assert.deepEqual(HSVA.fromRGBA(new RGBA(255, 255, 0, 1)), new HSVA(60, 1, 1, 1));
|
||||
assert.deepEqual(HSVA.fromRGBA(new RGBA(0, 255, 255, 1)), new HSVA(180, 1, 1, 1));
|
||||
assert.deepEqual(HSVA.fromRGBA(new RGBA(255, 0, 255, 1)), new HSVA(300, 1, 1, 1));
|
||||
|
||||
assert.deepEqual(HSVA.fromRGBA(new RGBA(192, 192, 192, 1)), new HSVA(0, 0, 0.753, 1));
|
||||
|
||||
assert.deepEqual(HSVA.fromRGBA(new RGBA(128, 128, 128, 1)), new HSVA(0, 0, 0.502, 1));
|
||||
assert.deepEqual(HSVA.fromRGBA(new RGBA(128, 0, 0, 1)), new HSVA(0, 1, 0.502, 1));
|
||||
assert.deepEqual(HSVA.fromRGBA(new RGBA(128, 128, 0, 1)), new HSVA(60, 1, 0.502, 1));
|
||||
assert.deepEqual(HSVA.fromRGBA(new RGBA(0, 128, 0, 1)), new HSVA(120, 1, 0.502, 1));
|
||||
assert.deepEqual(HSVA.fromRGBA(new RGBA(128, 0, 128, 1)), new HSVA(300, 1, 0.502, 1));
|
||||
assert.deepEqual(HSVA.fromRGBA(new RGBA(0, 128, 128, 1)), new HSVA(180, 1, 0.502, 1));
|
||||
assert.deepEqual(HSVA.fromRGBA(new RGBA(0, 0, 128, 1)), new HSVA(240, 1, 0.502, 1));
|
||||
});
|
||||
|
||||
test('Keep hue value when saturation is 0', () => {
|
||||
assert.deepEqual(HSVA.toRGBA(new HSVA(10, 0, 0, 0)), HSVA.toRGBA(new HSVA(20, 0, 0, 0)));
|
||||
assert.deepEqual(new Color(new HSVA(10, 0, 0, 0)).rgba, new Color(new HSVA(20, 0, 0, 0)).rgba);
|
||||
assert.notDeepEqual(new Color(new HSVA(10, 0, 0, 0)).hsva, new Color(new HSVA(20, 0, 0, 0)).hsva);
|
||||
});
|
||||
|
||||
test('bug#36240', () => {
|
||||
assert.deepEqual(HSVA.fromRGBA(new RGBA(92, 106, 196, 1)), new HSVA(232, 0.531, 0.769, 1));
|
||||
assert.deepEqual(HSVA.toRGBA(HSVA.fromRGBA(new RGBA(92, 106, 196, 1))), new RGBA(92, 106, 196, 1));
|
||||
});
|
||||
});
|
||||
|
||||
suite('Format', () => {
|
||||
suite('CSS', () => {
|
||||
test('parseHex', () => {
|
||||
|
||||
// invalid
|
||||
assert.deepEqual(Color.Format.CSS.parseHex(''), null);
|
||||
assert.deepEqual(Color.Format.CSS.parseHex('#'), null);
|
||||
assert.deepEqual(Color.Format.CSS.parseHex('#0102030'), null);
|
||||
|
||||
// somewhat valid
|
||||
assert.deepEqual(Color.Format.CSS.parseHex('#FFFFG0')!.rgba, new RGBA(255, 255, 0, 1));
|
||||
assert.deepEqual(Color.Format.CSS.parseHex('#FFFFg0')!.rgba, new RGBA(255, 255, 0, 1));
|
||||
assert.deepEqual(Color.Format.CSS.parseHex('#-FFF00')!.rgba, new RGBA(15, 255, 0, 1));
|
||||
|
||||
// valid
|
||||
assert.deepEqual(Color.Format.CSS.parseHex('#000000')!.rgba, new RGBA(0, 0, 0, 1));
|
||||
assert.deepEqual(Color.Format.CSS.parseHex('#FFFFFF')!.rgba, new RGBA(255, 255, 255, 1));
|
||||
|
||||
assert.deepEqual(Color.Format.CSS.parseHex('#FF0000')!.rgba, new RGBA(255, 0, 0, 1));
|
||||
assert.deepEqual(Color.Format.CSS.parseHex('#00FF00')!.rgba, new RGBA(0, 255, 0, 1));
|
||||
assert.deepEqual(Color.Format.CSS.parseHex('#0000FF')!.rgba, new RGBA(0, 0, 255, 1));
|
||||
|
||||
assert.deepEqual(Color.Format.CSS.parseHex('#FFFF00')!.rgba, new RGBA(255, 255, 0, 1));
|
||||
assert.deepEqual(Color.Format.CSS.parseHex('#00FFFF')!.rgba, new RGBA(0, 255, 255, 1));
|
||||
assert.deepEqual(Color.Format.CSS.parseHex('#FF00FF')!.rgba, new RGBA(255, 0, 255, 1));
|
||||
|
||||
assert.deepEqual(Color.Format.CSS.parseHex('#C0C0C0')!.rgba, new RGBA(192, 192, 192, 1));
|
||||
|
||||
assert.deepEqual(Color.Format.CSS.parseHex('#808080')!.rgba, new RGBA(128, 128, 128, 1));
|
||||
assert.deepEqual(Color.Format.CSS.parseHex('#800000')!.rgba, new RGBA(128, 0, 0, 1));
|
||||
assert.deepEqual(Color.Format.CSS.parseHex('#808000')!.rgba, new RGBA(128, 128, 0, 1));
|
||||
assert.deepEqual(Color.Format.CSS.parseHex('#008000')!.rgba, new RGBA(0, 128, 0, 1));
|
||||
assert.deepEqual(Color.Format.CSS.parseHex('#800080')!.rgba, new RGBA(128, 0, 128, 1));
|
||||
assert.deepEqual(Color.Format.CSS.parseHex('#008080')!.rgba, new RGBA(0, 128, 128, 1));
|
||||
assert.deepEqual(Color.Format.CSS.parseHex('#000080')!.rgba, new RGBA(0, 0, 128, 1));
|
||||
|
||||
assert.deepEqual(Color.Format.CSS.parseHex('#010203')!.rgba, new RGBA(1, 2, 3, 1));
|
||||
assert.deepEqual(Color.Format.CSS.parseHex('#040506')!.rgba, new RGBA(4, 5, 6, 1));
|
||||
assert.deepEqual(Color.Format.CSS.parseHex('#070809')!.rgba, new RGBA(7, 8, 9, 1));
|
||||
assert.deepEqual(Color.Format.CSS.parseHex('#0a0A0a')!.rgba, new RGBA(10, 10, 10, 1));
|
||||
assert.deepEqual(Color.Format.CSS.parseHex('#0b0B0b')!.rgba, new RGBA(11, 11, 11, 1));
|
||||
assert.deepEqual(Color.Format.CSS.parseHex('#0c0C0c')!.rgba, new RGBA(12, 12, 12, 1));
|
||||
assert.deepEqual(Color.Format.CSS.parseHex('#0d0D0d')!.rgba, new RGBA(13, 13, 13, 1));
|
||||
assert.deepEqual(Color.Format.CSS.parseHex('#0e0E0e')!.rgba, new RGBA(14, 14, 14, 1));
|
||||
assert.deepEqual(Color.Format.CSS.parseHex('#0f0F0f')!.rgba, new RGBA(15, 15, 15, 1));
|
||||
assert.deepEqual(Color.Format.CSS.parseHex('#a0A0a0')!.rgba, new RGBA(160, 160, 160, 1));
|
||||
assert.deepEqual(Color.Format.CSS.parseHex('#CFA')!.rgba, new RGBA(204, 255, 170, 1));
|
||||
assert.deepEqual(Color.Format.CSS.parseHex('#CFA8')!.rgba, new RGBA(204, 255, 170, 0.533));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
200
lib/vscode/src/vs/base/test/common/decorators.test.ts
Normal file
200
lib/vscode/src/vs/base/test/common/decorators.test.ts
Normal file
@@ -0,0 +1,200 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as sinon from 'sinon';
|
||||
import * as assert from 'assert';
|
||||
import { memoize, createMemoizer, throttle } from 'vs/base/common/decorators';
|
||||
|
||||
suite('Decorators', () => {
|
||||
test('memoize should memoize methods', () => {
|
||||
class Foo {
|
||||
count = 0;
|
||||
|
||||
constructor(private _answer: number | null | undefined) { }
|
||||
|
||||
@memoize
|
||||
answer() {
|
||||
this.count++;
|
||||
return this._answer;
|
||||
}
|
||||
}
|
||||
|
||||
const foo = new Foo(42);
|
||||
assert.equal(foo.count, 0);
|
||||
assert.equal(foo.answer(), 42);
|
||||
assert.equal(foo.count, 1);
|
||||
assert.equal(foo.answer(), 42);
|
||||
assert.equal(foo.count, 1);
|
||||
|
||||
const foo2 = new Foo(1337);
|
||||
assert.equal(foo2.count, 0);
|
||||
assert.equal(foo2.answer(), 1337);
|
||||
assert.equal(foo2.count, 1);
|
||||
assert.equal(foo2.answer(), 1337);
|
||||
assert.equal(foo2.count, 1);
|
||||
|
||||
assert.equal(foo.answer(), 42);
|
||||
assert.equal(foo.count, 1);
|
||||
|
||||
const foo3 = new Foo(null);
|
||||
assert.equal(foo3.count, 0);
|
||||
assert.equal(foo3.answer(), null);
|
||||
assert.equal(foo3.count, 1);
|
||||
assert.equal(foo3.answer(), null);
|
||||
assert.equal(foo3.count, 1);
|
||||
|
||||
const foo4 = new Foo(undefined);
|
||||
assert.equal(foo4.count, 0);
|
||||
assert.equal(foo4.answer(), undefined);
|
||||
assert.equal(foo4.count, 1);
|
||||
assert.equal(foo4.answer(), undefined);
|
||||
assert.equal(foo4.count, 1);
|
||||
});
|
||||
|
||||
test('memoize should memoize getters', () => {
|
||||
class Foo {
|
||||
count = 0;
|
||||
|
||||
constructor(private _answer: number | null | undefined) { }
|
||||
|
||||
@memoize
|
||||
get answer() {
|
||||
this.count++;
|
||||
return this._answer;
|
||||
}
|
||||
}
|
||||
|
||||
const foo = new Foo(42);
|
||||
assert.equal(foo.count, 0);
|
||||
assert.equal(foo.answer, 42);
|
||||
assert.equal(foo.count, 1);
|
||||
assert.equal(foo.answer, 42);
|
||||
assert.equal(foo.count, 1);
|
||||
|
||||
const foo2 = new Foo(1337);
|
||||
assert.equal(foo2.count, 0);
|
||||
assert.equal(foo2.answer, 1337);
|
||||
assert.equal(foo2.count, 1);
|
||||
assert.equal(foo2.answer, 1337);
|
||||
assert.equal(foo2.count, 1);
|
||||
|
||||
assert.equal(foo.answer, 42);
|
||||
assert.equal(foo.count, 1);
|
||||
|
||||
const foo3 = new Foo(null);
|
||||
assert.equal(foo3.count, 0);
|
||||
assert.equal(foo3.answer, null);
|
||||
assert.equal(foo3.count, 1);
|
||||
assert.equal(foo3.answer, null);
|
||||
assert.equal(foo3.count, 1);
|
||||
|
||||
const foo4 = new Foo(undefined);
|
||||
assert.equal(foo4.count, 0);
|
||||
assert.equal(foo4.answer, undefined);
|
||||
assert.equal(foo4.count, 1);
|
||||
assert.equal(foo4.answer, undefined);
|
||||
assert.equal(foo4.count, 1);
|
||||
});
|
||||
|
||||
test('memoized property should not be enumerable', () => {
|
||||
class Foo {
|
||||
@memoize
|
||||
get answer() {
|
||||
return 42;
|
||||
}
|
||||
}
|
||||
|
||||
const foo = new Foo();
|
||||
assert.equal(foo.answer, 42);
|
||||
|
||||
assert(!Object.keys(foo).some(k => /\$memoize\$/.test(k)));
|
||||
});
|
||||
|
||||
test('memoized property should not be writable', () => {
|
||||
class Foo {
|
||||
@memoize
|
||||
get answer() {
|
||||
return 42;
|
||||
}
|
||||
}
|
||||
|
||||
const foo = new Foo();
|
||||
assert.equal(foo.answer, 42);
|
||||
|
||||
try {
|
||||
(foo as any)['$memoize$answer'] = 1337;
|
||||
assert(false);
|
||||
} catch (e) {
|
||||
assert.equal(foo.answer, 42);
|
||||
}
|
||||
});
|
||||
|
||||
test('memoize clear', () => {
|
||||
const memoizer = createMemoizer();
|
||||
let counter = 0;
|
||||
class Foo {
|
||||
@memoizer
|
||||
get answer() {
|
||||
return ++counter;
|
||||
}
|
||||
}
|
||||
|
||||
const foo = new Foo();
|
||||
assert.equal(foo.answer, 1);
|
||||
assert.equal(foo.answer, 1);
|
||||
memoizer.clear();
|
||||
assert.equal(foo.answer, 2);
|
||||
assert.equal(foo.answer, 2);
|
||||
memoizer.clear();
|
||||
assert.equal(foo.answer, 3);
|
||||
assert.equal(foo.answer, 3);
|
||||
assert.equal(foo.answer, 3);
|
||||
});
|
||||
|
||||
test('throttle', () => {
|
||||
const spy = sinon.spy();
|
||||
const clock = sinon.useFakeTimers();
|
||||
try {
|
||||
class ThrottleTest {
|
||||
private _handle: Function;
|
||||
|
||||
constructor(fn: Function) {
|
||||
this._handle = fn;
|
||||
}
|
||||
|
||||
@throttle(
|
||||
100,
|
||||
(a: number, b: number) => a + b,
|
||||
() => 0
|
||||
)
|
||||
report(p: number): void {
|
||||
this._handle(p);
|
||||
}
|
||||
}
|
||||
|
||||
const t = new ThrottleTest(spy);
|
||||
|
||||
t.report(1);
|
||||
t.report(2);
|
||||
t.report(3);
|
||||
assert.deepEqual(spy.args, [[1]]);
|
||||
|
||||
clock.tick(200);
|
||||
assert.deepEqual(spy.args, [[1], [5]]);
|
||||
spy.reset();
|
||||
|
||||
t.report(4);
|
||||
t.report(5);
|
||||
clock.tick(50);
|
||||
t.report(6);
|
||||
|
||||
assert.deepEqual(spy.args, [[4]]);
|
||||
clock.tick(60);
|
||||
assert.deepEqual(spy.args, [[4], [11]]);
|
||||
} finally {
|
||||
clock.restore();
|
||||
}
|
||||
});
|
||||
});
|
||||
180
lib/vscode/src/vs/base/test/common/diff/diff.test.ts
Normal file
180
lib/vscode/src/vs/base/test/common/diff/diff.test.ts
Normal file
@@ -0,0 +1,180 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { LcsDiff, IDiffChange, StringDiffSequence } from 'vs/base/common/diff/diff';
|
||||
|
||||
function createArray<T>(length: number, value: T): T[] {
|
||||
const r: T[] = [];
|
||||
for (let i = 0; i < length; i++) {
|
||||
r[i] = value;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
function maskBasedSubstring(str: string, mask: boolean[]): string {
|
||||
let r = '';
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
if (mask[i]) {
|
||||
r += str.charAt(i);
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
function assertAnswer(originalStr: string, modifiedStr: string, changes: IDiffChange[], answerStr: string, onlyLength: boolean = false): void {
|
||||
let originalMask = createArray(originalStr.length, true);
|
||||
let modifiedMask = createArray(modifiedStr.length, true);
|
||||
|
||||
let i, j, change;
|
||||
for (i = 0; i < changes.length; i++) {
|
||||
change = changes[i];
|
||||
|
||||
if (change.originalLength) {
|
||||
for (j = 0; j < change.originalLength; j++) {
|
||||
originalMask[change.originalStart + j] = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (change.modifiedLength) {
|
||||
for (j = 0; j < change.modifiedLength; j++) {
|
||||
modifiedMask[change.modifiedStart + j] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let originalAnswer = maskBasedSubstring(originalStr, originalMask);
|
||||
let modifiedAnswer = maskBasedSubstring(modifiedStr, modifiedMask);
|
||||
|
||||
if (onlyLength) {
|
||||
assert.equal(originalAnswer.length, answerStr.length);
|
||||
assert.equal(modifiedAnswer.length, answerStr.length);
|
||||
} else {
|
||||
assert.equal(originalAnswer, answerStr);
|
||||
assert.equal(modifiedAnswer, answerStr);
|
||||
}
|
||||
}
|
||||
|
||||
function lcsInnerTest(originalStr: string, modifiedStr: string, answerStr: string, onlyLength: boolean = false): void {
|
||||
let diff = new LcsDiff(new StringDiffSequence(originalStr), new StringDiffSequence(modifiedStr));
|
||||
let changes = diff.ComputeDiff(false).changes;
|
||||
assertAnswer(originalStr, modifiedStr, changes, answerStr, onlyLength);
|
||||
}
|
||||
|
||||
function stringPower(str: string, power: number): string {
|
||||
let r = str;
|
||||
for (let i = 0; i < power; i++) {
|
||||
r += r;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
function lcsTest(originalStr: string, modifiedStr: string, answerStr: string) {
|
||||
lcsInnerTest(originalStr, modifiedStr, answerStr);
|
||||
for (let i = 2; i <= 5; i++) {
|
||||
lcsInnerTest(stringPower(originalStr, i), stringPower(modifiedStr, i), stringPower(answerStr, i), true);
|
||||
}
|
||||
}
|
||||
|
||||
suite('Diff', () => {
|
||||
test('LcsDiff - different strings tests', function () {
|
||||
this.timeout(10000);
|
||||
lcsTest('heLLo world', 'hello orlando', 'heo orld');
|
||||
lcsTest('abcde', 'acd', 'acd'); // simple
|
||||
lcsTest('abcdbce', 'bcede', 'bcde'); // skip
|
||||
lcsTest('abcdefgabcdefg', 'bcehafg', 'bceafg'); // long
|
||||
lcsTest('abcde', 'fgh', ''); // no match
|
||||
lcsTest('abcfabc', 'fabc', 'fabc');
|
||||
lcsTest('0azby0', '9axbzby9', 'azby');
|
||||
lcsTest('0abc00000', '9a1b2c399999', 'abc');
|
||||
|
||||
lcsTest('fooBar', 'myfooBar', 'fooBar'); // all insertions
|
||||
lcsTest('fooBar', 'fooMyBar', 'fooBar'); // all insertions
|
||||
lcsTest('fooBar', 'fooBar', 'fooBar'); // identical sequences
|
||||
});
|
||||
});
|
||||
|
||||
suite('Diff - Ported from VS', () => {
|
||||
test('using continue processing predicate to quit early', function () {
|
||||
let left = 'abcdef';
|
||||
let right = 'abxxcyyydzzzzezzzzzzzzzzzzzzzzzzzzf';
|
||||
|
||||
// We use a long non-matching portion at the end of the right-side string, so the backwards tracking logic
|
||||
// doesn't get there first.
|
||||
let predicateCallCount = 0;
|
||||
|
||||
let diff = new LcsDiff(new StringDiffSequence(left), new StringDiffSequence(right), function (leftIndex, longestMatchSoFar) {
|
||||
assert.equal(predicateCallCount, 0);
|
||||
|
||||
predicateCallCount++;
|
||||
|
||||
assert.equal(leftIndex, 1);
|
||||
|
||||
// cancel processing
|
||||
return false;
|
||||
});
|
||||
let changes = diff.ComputeDiff(true).changes;
|
||||
|
||||
assert.equal(predicateCallCount, 1);
|
||||
|
||||
// Doesn't include 'c', 'd', or 'e', since we quit on the first request
|
||||
assertAnswer(left, right, changes, 'abf');
|
||||
|
||||
|
||||
|
||||
// Cancel after the first match ('c')
|
||||
diff = new LcsDiff(new StringDiffSequence(left), new StringDiffSequence(right), function (leftIndex, longestMatchSoFar) {
|
||||
assert(longestMatchSoFar <= 1); // We never see a match of length > 1
|
||||
|
||||
// Continue processing as long as there hasn't been a match made.
|
||||
return longestMatchSoFar < 1;
|
||||
});
|
||||
changes = diff.ComputeDiff(true).changes;
|
||||
|
||||
assertAnswer(left, right, changes, 'abcf');
|
||||
|
||||
|
||||
|
||||
// Cancel after the second match ('d')
|
||||
diff = new LcsDiff(new StringDiffSequence(left), new StringDiffSequence(right), function (leftIndex, longestMatchSoFar) {
|
||||
assert(longestMatchSoFar <= 2); // We never see a match of length > 2
|
||||
|
||||
// Continue processing as long as there hasn't been a match made.
|
||||
return longestMatchSoFar < 2;
|
||||
});
|
||||
changes = diff.ComputeDiff(true).changes;
|
||||
|
||||
assertAnswer(left, right, changes, 'abcdf');
|
||||
|
||||
|
||||
|
||||
// Cancel *one iteration* after the second match ('d')
|
||||
let hitSecondMatch = false;
|
||||
diff = new LcsDiff(new StringDiffSequence(left), new StringDiffSequence(right), function (leftIndex, longestMatchSoFar) {
|
||||
assert(longestMatchSoFar <= 2); // We never see a match of length > 2
|
||||
|
||||
let hitYet = hitSecondMatch;
|
||||
hitSecondMatch = longestMatchSoFar > 1;
|
||||
// Continue processing as long as there hasn't been a match made.
|
||||
return !hitYet;
|
||||
});
|
||||
changes = diff.ComputeDiff(true).changes;
|
||||
|
||||
assertAnswer(left, right, changes, 'abcdf');
|
||||
|
||||
|
||||
|
||||
// Cancel after the third and final match ('e')
|
||||
diff = new LcsDiff(new StringDiffSequence(left), new StringDiffSequence(right), function (leftIndex, longestMatchSoFar) {
|
||||
assert(longestMatchSoFar <= 3); // We never see a match of length > 3
|
||||
|
||||
// Continue processing as long as there hasn't been a match made.
|
||||
return longestMatchSoFar < 3;
|
||||
});
|
||||
changes = diff.ComputeDiff(true).changes;
|
||||
|
||||
assertAnswer(left, right, changes, 'abcdef');
|
||||
});
|
||||
});
|
||||
33
lib/vscode/src/vs/base/test/common/errors.test.ts
Normal file
33
lib/vscode/src/vs/base/test/common/errors.test.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { toErrorMessage } from 'vs/base/common/errorMessage';
|
||||
|
||||
suite('Errors', () => {
|
||||
test('Get Error Message', function () {
|
||||
assert.strictEqual(toErrorMessage('Foo Bar'), 'Foo Bar');
|
||||
assert.strictEqual(toErrorMessage(new Error('Foo Bar')), 'Foo Bar');
|
||||
|
||||
let error: any = new Error();
|
||||
error = new Error();
|
||||
error.detail = {};
|
||||
error.detail.exception = {};
|
||||
error.detail.exception.message = 'Foo Bar';
|
||||
assert.strictEqual(toErrorMessage(error), 'Foo Bar');
|
||||
assert.strictEqual(toErrorMessage(error, true), 'Foo Bar');
|
||||
|
||||
assert(toErrorMessage());
|
||||
assert(toErrorMessage(null));
|
||||
assert(toErrorMessage({}));
|
||||
|
||||
try {
|
||||
throw new Error();
|
||||
} catch (error) {
|
||||
assert.strictEqual(toErrorMessage(error), 'An unknown error occurred. Please consult the log for more details.');
|
||||
assert.ok(toErrorMessage(error, true).length > 'An unknown error occurred. Please consult the log for more details.'.length);
|
||||
}
|
||||
});
|
||||
});
|
||||
896
lib/vscode/src/vs/base/test/common/event.test.ts
Normal file
896
lib/vscode/src/vs/base/test/common/event.test.ts
Normal file
@@ -0,0 +1,896 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as assert from 'assert';
|
||||
import { Event, Emitter, EventBufferer, EventMultiplexer, IWaitUntil, PauseableEmitter, AsyncEmitter } from 'vs/base/common/event';
|
||||
import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import * as Errors from 'vs/base/common/errors';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
||||
namespace Samples {
|
||||
|
||||
export class EventCounter {
|
||||
|
||||
count = 0;
|
||||
|
||||
reset() {
|
||||
this.count = 0;
|
||||
}
|
||||
|
||||
onEvent() {
|
||||
this.count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
export class Document3 {
|
||||
|
||||
private readonly _onDidChange = new Emitter<string>();
|
||||
|
||||
onDidChange: Event<string> = this._onDidChange.event;
|
||||
|
||||
setText(value: string) {
|
||||
//...
|
||||
this._onDidChange.fire(value);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
suite('Event', function () {
|
||||
|
||||
const counter = new Samples.EventCounter();
|
||||
|
||||
setup(() => counter.reset());
|
||||
|
||||
test('Emitter plain', function () {
|
||||
|
||||
let doc = new Samples.Document3();
|
||||
|
||||
document.createElement('div').onclick = function () { };
|
||||
let subscription = doc.onDidChange(counter.onEvent, counter);
|
||||
|
||||
doc.setText('far');
|
||||
doc.setText('boo');
|
||||
|
||||
// unhook listener
|
||||
subscription.dispose();
|
||||
doc.setText('boo');
|
||||
assert.equal(counter.count, 2);
|
||||
});
|
||||
|
||||
|
||||
test('Emitter, bucket', function () {
|
||||
|
||||
let bucket: IDisposable[] = [];
|
||||
let doc = new Samples.Document3();
|
||||
let subscription = doc.onDidChange(counter.onEvent, counter, bucket);
|
||||
|
||||
doc.setText('far');
|
||||
doc.setText('boo');
|
||||
|
||||
// unhook listener
|
||||
while (bucket.length) {
|
||||
bucket.pop()!.dispose();
|
||||
}
|
||||
doc.setText('boo');
|
||||
|
||||
// noop
|
||||
subscription.dispose();
|
||||
|
||||
doc.setText('boo');
|
||||
assert.equal(counter.count, 2);
|
||||
});
|
||||
|
||||
test('Emitter, store', function () {
|
||||
|
||||
let bucket = new DisposableStore();
|
||||
let doc = new Samples.Document3();
|
||||
let subscription = doc.onDidChange(counter.onEvent, counter, bucket);
|
||||
|
||||
doc.setText('far');
|
||||
doc.setText('boo');
|
||||
|
||||
// unhook listener
|
||||
bucket.clear();
|
||||
doc.setText('boo');
|
||||
|
||||
// noop
|
||||
subscription.dispose();
|
||||
|
||||
doc.setText('boo');
|
||||
assert.equal(counter.count, 2);
|
||||
});
|
||||
|
||||
test('onFirstAdd|onLastRemove', () => {
|
||||
|
||||
let firstCount = 0;
|
||||
let lastCount = 0;
|
||||
let a = new Emitter({
|
||||
onFirstListenerAdd() { firstCount += 1; },
|
||||
onLastListenerRemove() { lastCount += 1; }
|
||||
});
|
||||
|
||||
assert.equal(firstCount, 0);
|
||||
assert.equal(lastCount, 0);
|
||||
|
||||
let subscription = a.event(function () { });
|
||||
assert.equal(firstCount, 1);
|
||||
assert.equal(lastCount, 0);
|
||||
|
||||
subscription.dispose();
|
||||
assert.equal(firstCount, 1);
|
||||
assert.equal(lastCount, 1);
|
||||
|
||||
subscription = a.event(function () { });
|
||||
assert.equal(firstCount, 2);
|
||||
assert.equal(lastCount, 1);
|
||||
});
|
||||
|
||||
test('throwingListener', () => {
|
||||
const origErrorHandler = Errors.errorHandler.getUnexpectedErrorHandler();
|
||||
Errors.setUnexpectedErrorHandler(() => null);
|
||||
|
||||
try {
|
||||
let a = new Emitter<undefined>();
|
||||
let hit = false;
|
||||
a.event(function () {
|
||||
// eslint-disable-next-line no-throw-literal
|
||||
throw 9;
|
||||
});
|
||||
a.event(function () {
|
||||
hit = true;
|
||||
});
|
||||
a.fire(undefined);
|
||||
assert.equal(hit, true);
|
||||
|
||||
} finally {
|
||||
Errors.setUnexpectedErrorHandler(origErrorHandler);
|
||||
}
|
||||
});
|
||||
|
||||
test('reusing event function and context', function () {
|
||||
let counter = 0;
|
||||
function listener() {
|
||||
counter += 1;
|
||||
}
|
||||
const context = {};
|
||||
|
||||
let emitter = new Emitter<undefined>();
|
||||
let reg1 = emitter.event(listener, context);
|
||||
let reg2 = emitter.event(listener, context);
|
||||
|
||||
emitter.fire(undefined);
|
||||
assert.equal(counter, 2);
|
||||
|
||||
reg1.dispose();
|
||||
emitter.fire(undefined);
|
||||
assert.equal(counter, 3);
|
||||
|
||||
reg2.dispose();
|
||||
emitter.fire(undefined);
|
||||
assert.equal(counter, 3);
|
||||
});
|
||||
|
||||
test('Debounce Event', function (done: () => void) {
|
||||
let doc = new Samples.Document3();
|
||||
|
||||
let onDocDidChange = Event.debounce(doc.onDidChange, (prev: string[] | undefined, cur) => {
|
||||
if (!prev) {
|
||||
prev = [cur];
|
||||
} else if (prev.indexOf(cur) < 0) {
|
||||
prev.push(cur);
|
||||
}
|
||||
return prev;
|
||||
}, 10);
|
||||
|
||||
let count = 0;
|
||||
|
||||
onDocDidChange(keys => {
|
||||
count++;
|
||||
assert.ok(keys, 'was not expecting keys.');
|
||||
if (count === 1) {
|
||||
doc.setText('4');
|
||||
assert.deepEqual(keys, ['1', '2', '3']);
|
||||
} else if (count === 2) {
|
||||
assert.deepEqual(keys, ['4']);
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
doc.setText('1');
|
||||
doc.setText('2');
|
||||
doc.setText('3');
|
||||
});
|
||||
|
||||
test('Debounce Event - leading', async function () {
|
||||
const emitter = new Emitter<void>();
|
||||
let debounced = Event.debounce(emitter.event, (l, e) => e, 0, /*leading=*/true);
|
||||
|
||||
let calls = 0;
|
||||
debounced(() => {
|
||||
calls++;
|
||||
});
|
||||
|
||||
// If the source event is fired once, the debounced (on the leading edge) event should be fired only once
|
||||
emitter.fire();
|
||||
|
||||
await timeout(1);
|
||||
assert.equal(calls, 1);
|
||||
});
|
||||
|
||||
test('Debounce Event - leading', async function () {
|
||||
const emitter = new Emitter<void>();
|
||||
let debounced = Event.debounce(emitter.event, (l, e) => e, 0, /*leading=*/true);
|
||||
|
||||
let calls = 0;
|
||||
debounced(() => {
|
||||
calls++;
|
||||
});
|
||||
|
||||
// If the source event is fired multiple times, the debounced (on the leading edge) event should be fired twice
|
||||
emitter.fire();
|
||||
emitter.fire();
|
||||
emitter.fire();
|
||||
await timeout(1);
|
||||
assert.equal(calls, 2);
|
||||
});
|
||||
|
||||
test('Debounce Event - leading reset', async function () {
|
||||
const emitter = new Emitter<number>();
|
||||
let debounced = Event.debounce(emitter.event, (l, e) => l ? l + 1 : 1, 0, /*leading=*/true);
|
||||
|
||||
let calls: number[] = [];
|
||||
debounced((e) => calls.push(e));
|
||||
|
||||
emitter.fire(1);
|
||||
emitter.fire(1);
|
||||
|
||||
await timeout(1);
|
||||
assert.deepEqual(calls, [1, 1]);
|
||||
});
|
||||
|
||||
test('Emitter - In Order Delivery', function () {
|
||||
const a = new Emitter<string>();
|
||||
const listener2Events: string[] = [];
|
||||
a.event(function listener1(event) {
|
||||
if (event === 'e1') {
|
||||
a.fire('e2');
|
||||
// assert that all events are delivered at this point
|
||||
assert.deepEqual(listener2Events, ['e1', 'e2']);
|
||||
}
|
||||
});
|
||||
a.event(function listener2(event) {
|
||||
listener2Events.push(event);
|
||||
});
|
||||
a.fire('e1');
|
||||
|
||||
// assert that all events are delivered in order
|
||||
assert.deepEqual(listener2Events, ['e1', 'e2']);
|
||||
});
|
||||
});
|
||||
|
||||
suite('AsyncEmitter', function () {
|
||||
|
||||
test('event has waitUntil-function', async function () {
|
||||
|
||||
interface E extends IWaitUntil {
|
||||
foo: boolean;
|
||||
bar: number;
|
||||
}
|
||||
|
||||
let emitter = new AsyncEmitter<E>();
|
||||
|
||||
emitter.event(e => {
|
||||
assert.equal(e.foo, true);
|
||||
assert.equal(e.bar, 1);
|
||||
assert.equal(typeof e.waitUntil, 'function');
|
||||
});
|
||||
|
||||
emitter.fireAsync({ foo: true, bar: 1, }, CancellationToken.None);
|
||||
emitter.dispose();
|
||||
});
|
||||
|
||||
test('sequential delivery', async function () {
|
||||
|
||||
interface E extends IWaitUntil {
|
||||
foo: boolean;
|
||||
}
|
||||
|
||||
let globalState = 0;
|
||||
let emitter = new AsyncEmitter<E>();
|
||||
|
||||
emitter.event(e => {
|
||||
e.waitUntil(timeout(10).then(_ => {
|
||||
assert.equal(globalState, 0);
|
||||
globalState += 1;
|
||||
}));
|
||||
});
|
||||
|
||||
emitter.event(e => {
|
||||
e.waitUntil(timeout(1).then(_ => {
|
||||
assert.equal(globalState, 1);
|
||||
globalState += 1;
|
||||
}));
|
||||
});
|
||||
|
||||
await emitter.fireAsync({ foo: true }, CancellationToken.None);
|
||||
assert.equal(globalState, 2);
|
||||
});
|
||||
|
||||
test('sequential, in-order delivery', async function () {
|
||||
interface E extends IWaitUntil {
|
||||
foo: number;
|
||||
}
|
||||
let events: number[] = [];
|
||||
let done = false;
|
||||
let emitter = new AsyncEmitter<E>();
|
||||
|
||||
// e1
|
||||
emitter.event(e => {
|
||||
e.waitUntil(timeout(10).then(async _ => {
|
||||
if (e.foo === 1) {
|
||||
await emitter.fireAsync({ foo: 2 }, CancellationToken.None);
|
||||
assert.deepEqual(events, [1, 2]);
|
||||
done = true;
|
||||
}
|
||||
}));
|
||||
});
|
||||
|
||||
// e2
|
||||
emitter.event(e => {
|
||||
events.push(e.foo);
|
||||
e.waitUntil(timeout(7));
|
||||
});
|
||||
|
||||
await emitter.fireAsync({ foo: 1 }, CancellationToken.None);
|
||||
assert.ok(done);
|
||||
});
|
||||
|
||||
test('catch errors', async function () {
|
||||
const origErrorHandler = Errors.errorHandler.getUnexpectedErrorHandler();
|
||||
Errors.setUnexpectedErrorHandler(() => null);
|
||||
|
||||
interface E extends IWaitUntil {
|
||||
foo: boolean;
|
||||
}
|
||||
|
||||
let globalState = 0;
|
||||
let emitter = new AsyncEmitter<E>();
|
||||
|
||||
emitter.event(e => {
|
||||
globalState += 1;
|
||||
e.waitUntil(new Promise((_r, reject) => reject(new Error())));
|
||||
});
|
||||
|
||||
emitter.event(e => {
|
||||
globalState += 1;
|
||||
e.waitUntil(timeout(10));
|
||||
});
|
||||
|
||||
await emitter.fireAsync({ foo: true }, CancellationToken.None).then(() => {
|
||||
assert.equal(globalState, 2);
|
||||
}).catch(e => {
|
||||
console.log(e);
|
||||
assert.ok(false);
|
||||
});
|
||||
|
||||
Errors.setUnexpectedErrorHandler(origErrorHandler);
|
||||
});
|
||||
});
|
||||
|
||||
suite('PausableEmitter', function () {
|
||||
|
||||
test('basic', function () {
|
||||
const data: number[] = [];
|
||||
const emitter = new PauseableEmitter<number>();
|
||||
|
||||
emitter.event(e => data.push(e));
|
||||
emitter.fire(1);
|
||||
emitter.fire(2);
|
||||
|
||||
assert.deepEqual(data, [1, 2]);
|
||||
});
|
||||
|
||||
test('pause/resume - no merge', function () {
|
||||
const data: number[] = [];
|
||||
const emitter = new PauseableEmitter<number>();
|
||||
|
||||
emitter.event(e => data.push(e));
|
||||
emitter.fire(1);
|
||||
emitter.fire(2);
|
||||
assert.deepEqual(data, [1, 2]);
|
||||
|
||||
emitter.pause();
|
||||
emitter.fire(3);
|
||||
emitter.fire(4);
|
||||
assert.deepEqual(data, [1, 2]);
|
||||
|
||||
emitter.resume();
|
||||
assert.deepEqual(data, [1, 2, 3, 4]);
|
||||
emitter.fire(5);
|
||||
assert.deepEqual(data, [1, 2, 3, 4, 5]);
|
||||
});
|
||||
|
||||
test('pause/resume - merge', function () {
|
||||
const data: number[] = [];
|
||||
const emitter = new PauseableEmitter<number>({ merge: (a) => a.reduce((p, c) => p + c, 0) });
|
||||
|
||||
emitter.event(e => data.push(e));
|
||||
emitter.fire(1);
|
||||
emitter.fire(2);
|
||||
assert.deepEqual(data, [1, 2]);
|
||||
|
||||
emitter.pause();
|
||||
emitter.fire(3);
|
||||
emitter.fire(4);
|
||||
assert.deepEqual(data, [1, 2]);
|
||||
|
||||
emitter.resume();
|
||||
assert.deepEqual(data, [1, 2, 7]);
|
||||
|
||||
emitter.fire(5);
|
||||
assert.deepEqual(data, [1, 2, 7, 5]);
|
||||
});
|
||||
|
||||
test('double pause/resume', function () {
|
||||
const data: number[] = [];
|
||||
const emitter = new PauseableEmitter<number>();
|
||||
|
||||
emitter.event(e => data.push(e));
|
||||
emitter.fire(1);
|
||||
emitter.fire(2);
|
||||
assert.deepEqual(data, [1, 2]);
|
||||
|
||||
emitter.pause();
|
||||
emitter.pause();
|
||||
emitter.fire(3);
|
||||
emitter.fire(4);
|
||||
assert.deepEqual(data, [1, 2]);
|
||||
|
||||
emitter.resume();
|
||||
assert.deepEqual(data, [1, 2]);
|
||||
|
||||
emitter.resume();
|
||||
assert.deepEqual(data, [1, 2, 3, 4]);
|
||||
|
||||
emitter.resume();
|
||||
assert.deepEqual(data, [1, 2, 3, 4]);
|
||||
});
|
||||
|
||||
test('resume, no pause', function () {
|
||||
const data: number[] = [];
|
||||
const emitter = new PauseableEmitter<number>();
|
||||
|
||||
emitter.event(e => data.push(e));
|
||||
emitter.fire(1);
|
||||
emitter.fire(2);
|
||||
assert.deepEqual(data, [1, 2]);
|
||||
|
||||
emitter.resume();
|
||||
emitter.fire(3);
|
||||
assert.deepEqual(data, [1, 2, 3]);
|
||||
});
|
||||
|
||||
test('nested pause', function () {
|
||||
const data: number[] = [];
|
||||
const emitter = new PauseableEmitter<number>();
|
||||
|
||||
let once = true;
|
||||
emitter.event(e => {
|
||||
data.push(e);
|
||||
|
||||
if (once) {
|
||||
emitter.pause();
|
||||
once = false;
|
||||
}
|
||||
});
|
||||
emitter.event(e => {
|
||||
data.push(e);
|
||||
});
|
||||
|
||||
emitter.pause();
|
||||
emitter.fire(1);
|
||||
emitter.fire(2);
|
||||
assert.deepEqual(data, []);
|
||||
|
||||
emitter.resume();
|
||||
assert.deepEqual(data, [1, 1]); // paused after first event
|
||||
|
||||
emitter.resume();
|
||||
assert.deepEqual(data, [1, 1, 2, 2]); // remaing event delivered
|
||||
|
||||
emitter.fire(3);
|
||||
assert.deepEqual(data, [1, 1, 2, 2, 3, 3]);
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
suite('Event utils', () => {
|
||||
|
||||
suite('EventBufferer', () => {
|
||||
|
||||
test('should not buffer when not wrapped', () => {
|
||||
const bufferer = new EventBufferer();
|
||||
const counter = new Samples.EventCounter();
|
||||
const emitter = new Emitter<void>();
|
||||
const event = bufferer.wrapEvent(emitter.event);
|
||||
const listener = event(counter.onEvent, counter);
|
||||
|
||||
assert.equal(counter.count, 0);
|
||||
emitter.fire();
|
||||
assert.equal(counter.count, 1);
|
||||
emitter.fire();
|
||||
assert.equal(counter.count, 2);
|
||||
emitter.fire();
|
||||
assert.equal(counter.count, 3);
|
||||
|
||||
listener.dispose();
|
||||
});
|
||||
|
||||
test('should buffer when wrapped', () => {
|
||||
const bufferer = new EventBufferer();
|
||||
const counter = new Samples.EventCounter();
|
||||
const emitter = new Emitter<void>();
|
||||
const event = bufferer.wrapEvent(emitter.event);
|
||||
const listener = event(counter.onEvent, counter);
|
||||
|
||||
assert.equal(counter.count, 0);
|
||||
emitter.fire();
|
||||
assert.equal(counter.count, 1);
|
||||
|
||||
bufferer.bufferEvents(() => {
|
||||
emitter.fire();
|
||||
assert.equal(counter.count, 1);
|
||||
emitter.fire();
|
||||
assert.equal(counter.count, 1);
|
||||
});
|
||||
|
||||
assert.equal(counter.count, 3);
|
||||
emitter.fire();
|
||||
assert.equal(counter.count, 4);
|
||||
|
||||
listener.dispose();
|
||||
});
|
||||
|
||||
test('once', () => {
|
||||
const emitter = new Emitter<void>();
|
||||
|
||||
let counter1 = 0, counter2 = 0, counter3 = 0;
|
||||
|
||||
const listener1 = emitter.event(() => counter1++);
|
||||
const listener2 = Event.once(emitter.event)(() => counter2++);
|
||||
const listener3 = Event.once(emitter.event)(() => counter3++);
|
||||
|
||||
assert.equal(counter1, 0);
|
||||
assert.equal(counter2, 0);
|
||||
assert.equal(counter3, 0);
|
||||
|
||||
listener3.dispose();
|
||||
emitter.fire();
|
||||
assert.equal(counter1, 1);
|
||||
assert.equal(counter2, 1);
|
||||
assert.equal(counter3, 0);
|
||||
|
||||
emitter.fire();
|
||||
assert.equal(counter1, 2);
|
||||
assert.equal(counter2, 1);
|
||||
assert.equal(counter3, 0);
|
||||
|
||||
listener1.dispose();
|
||||
listener2.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
suite('fromPromise', () => {
|
||||
|
||||
test('should emit when done', async () => {
|
||||
let count = 0;
|
||||
|
||||
const event = Event.fromPromise(Promise.resolve(null));
|
||||
event(() => count++);
|
||||
|
||||
assert.equal(count, 0);
|
||||
|
||||
await timeout(10);
|
||||
assert.equal(count, 1);
|
||||
});
|
||||
|
||||
test('should emit when done - setTimeout', async () => {
|
||||
let count = 0;
|
||||
|
||||
const promise = timeout(5);
|
||||
const event = Event.fromPromise(promise);
|
||||
event(() => count++);
|
||||
|
||||
assert.equal(count, 0);
|
||||
await promise;
|
||||
assert.equal(count, 1);
|
||||
});
|
||||
});
|
||||
|
||||
suite('stopwatch', () => {
|
||||
|
||||
test('should emit', () => {
|
||||
const emitter = new Emitter<void>();
|
||||
const event = Event.stopwatch(emitter.event);
|
||||
|
||||
return new Promise((c, e) => {
|
||||
event(duration => {
|
||||
try {
|
||||
assert(duration > 0);
|
||||
} catch (err) {
|
||||
e(err);
|
||||
}
|
||||
|
||||
c(undefined);
|
||||
});
|
||||
|
||||
setTimeout(() => emitter.fire(), 10);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
suite('buffer', () => {
|
||||
|
||||
test('should buffer events', () => {
|
||||
const result: number[] = [];
|
||||
const emitter = new Emitter<number>();
|
||||
const event = emitter.event;
|
||||
const bufferedEvent = Event.buffer(event);
|
||||
|
||||
emitter.fire(1);
|
||||
emitter.fire(2);
|
||||
emitter.fire(3);
|
||||
assert.deepEqual(result, []);
|
||||
|
||||
const listener = bufferedEvent(num => result.push(num));
|
||||
assert.deepEqual(result, [1, 2, 3]);
|
||||
|
||||
emitter.fire(4);
|
||||
assert.deepEqual(result, [1, 2, 3, 4]);
|
||||
|
||||
listener.dispose();
|
||||
emitter.fire(5);
|
||||
assert.deepEqual(result, [1, 2, 3, 4]);
|
||||
});
|
||||
|
||||
test('should buffer events on next tick', async () => {
|
||||
const result: number[] = [];
|
||||
const emitter = new Emitter<number>();
|
||||
const event = emitter.event;
|
||||
const bufferedEvent = Event.buffer(event, true);
|
||||
|
||||
emitter.fire(1);
|
||||
emitter.fire(2);
|
||||
emitter.fire(3);
|
||||
assert.deepEqual(result, []);
|
||||
|
||||
const listener = bufferedEvent(num => result.push(num));
|
||||
assert.deepEqual(result, []);
|
||||
|
||||
await timeout(10);
|
||||
emitter.fire(4);
|
||||
assert.deepEqual(result, [1, 2, 3, 4]);
|
||||
listener.dispose();
|
||||
emitter.fire(5);
|
||||
assert.deepEqual(result, [1, 2, 3, 4]);
|
||||
});
|
||||
|
||||
test('should fire initial buffer events', () => {
|
||||
const result: number[] = [];
|
||||
const emitter = new Emitter<number>();
|
||||
const event = emitter.event;
|
||||
const bufferedEvent = Event.buffer(event, false, [-2, -1, 0]);
|
||||
|
||||
emitter.fire(1);
|
||||
emitter.fire(2);
|
||||
emitter.fire(3);
|
||||
assert.deepEqual(result, []);
|
||||
|
||||
bufferedEvent(num => result.push(num));
|
||||
assert.deepEqual(result, [-2, -1, 0, 1, 2, 3]);
|
||||
});
|
||||
});
|
||||
|
||||
suite('EventMultiplexer', () => {
|
||||
|
||||
test('works', () => {
|
||||
const result: number[] = [];
|
||||
const m = new EventMultiplexer<number>();
|
||||
m.event(r => result.push(r));
|
||||
|
||||
const e1 = new Emitter<number>();
|
||||
m.add(e1.event);
|
||||
|
||||
assert.deepEqual(result, []);
|
||||
|
||||
e1.fire(0);
|
||||
assert.deepEqual(result, [0]);
|
||||
});
|
||||
|
||||
test('multiplexer dispose works', () => {
|
||||
const result: number[] = [];
|
||||
const m = new EventMultiplexer<number>();
|
||||
m.event(r => result.push(r));
|
||||
|
||||
const e1 = new Emitter<number>();
|
||||
m.add(e1.event);
|
||||
|
||||
assert.deepEqual(result, []);
|
||||
|
||||
e1.fire(0);
|
||||
assert.deepEqual(result, [0]);
|
||||
|
||||
m.dispose();
|
||||
assert.deepEqual(result, [0]);
|
||||
|
||||
e1.fire(0);
|
||||
assert.deepEqual(result, [0]);
|
||||
});
|
||||
|
||||
test('event dispose works', () => {
|
||||
const result: number[] = [];
|
||||
const m = new EventMultiplexer<number>();
|
||||
m.event(r => result.push(r));
|
||||
|
||||
const e1 = new Emitter<number>();
|
||||
m.add(e1.event);
|
||||
|
||||
assert.deepEqual(result, []);
|
||||
|
||||
e1.fire(0);
|
||||
assert.deepEqual(result, [0]);
|
||||
|
||||
e1.dispose();
|
||||
assert.deepEqual(result, [0]);
|
||||
|
||||
e1.fire(0);
|
||||
assert.deepEqual(result, [0]);
|
||||
});
|
||||
|
||||
test('mutliplexer event dispose works', () => {
|
||||
const result: number[] = [];
|
||||
const m = new EventMultiplexer<number>();
|
||||
m.event(r => result.push(r));
|
||||
|
||||
const e1 = new Emitter<number>();
|
||||
const l1 = m.add(e1.event);
|
||||
|
||||
assert.deepEqual(result, []);
|
||||
|
||||
e1.fire(0);
|
||||
assert.deepEqual(result, [0]);
|
||||
|
||||
l1.dispose();
|
||||
assert.deepEqual(result, [0]);
|
||||
|
||||
e1.fire(0);
|
||||
assert.deepEqual(result, [0]);
|
||||
});
|
||||
|
||||
test('hot start works', () => {
|
||||
const result: number[] = [];
|
||||
const m = new EventMultiplexer<number>();
|
||||
m.event(r => result.push(r));
|
||||
|
||||
const e1 = new Emitter<number>();
|
||||
m.add(e1.event);
|
||||
const e2 = new Emitter<number>();
|
||||
m.add(e2.event);
|
||||
const e3 = new Emitter<number>();
|
||||
m.add(e3.event);
|
||||
|
||||
e1.fire(1);
|
||||
e2.fire(2);
|
||||
e3.fire(3);
|
||||
assert.deepEqual(result, [1, 2, 3]);
|
||||
});
|
||||
|
||||
test('cold start works', () => {
|
||||
const result: number[] = [];
|
||||
const m = new EventMultiplexer<number>();
|
||||
|
||||
const e1 = new Emitter<number>();
|
||||
m.add(e1.event);
|
||||
const e2 = new Emitter<number>();
|
||||
m.add(e2.event);
|
||||
const e3 = new Emitter<number>();
|
||||
m.add(e3.event);
|
||||
|
||||
m.event(r => result.push(r));
|
||||
|
||||
e1.fire(1);
|
||||
e2.fire(2);
|
||||
e3.fire(3);
|
||||
assert.deepEqual(result, [1, 2, 3]);
|
||||
});
|
||||
|
||||
test('late add works', () => {
|
||||
const result: number[] = [];
|
||||
const m = new EventMultiplexer<number>();
|
||||
|
||||
const e1 = new Emitter<number>();
|
||||
m.add(e1.event);
|
||||
const e2 = new Emitter<number>();
|
||||
m.add(e2.event);
|
||||
|
||||
m.event(r => result.push(r));
|
||||
|
||||
e1.fire(1);
|
||||
e2.fire(2);
|
||||
|
||||
const e3 = new Emitter<number>();
|
||||
m.add(e3.event);
|
||||
e3.fire(3);
|
||||
|
||||
assert.deepEqual(result, [1, 2, 3]);
|
||||
});
|
||||
|
||||
test('add dispose works', () => {
|
||||
const result: number[] = [];
|
||||
const m = new EventMultiplexer<number>();
|
||||
|
||||
const e1 = new Emitter<number>();
|
||||
m.add(e1.event);
|
||||
const e2 = new Emitter<number>();
|
||||
m.add(e2.event);
|
||||
|
||||
m.event(r => result.push(r));
|
||||
|
||||
e1.fire(1);
|
||||
e2.fire(2);
|
||||
|
||||
const e3 = new Emitter<number>();
|
||||
const l3 = m.add(e3.event);
|
||||
e3.fire(3);
|
||||
assert.deepEqual(result, [1, 2, 3]);
|
||||
|
||||
l3.dispose();
|
||||
e3.fire(4);
|
||||
assert.deepEqual(result, [1, 2, 3]);
|
||||
|
||||
e2.fire(4);
|
||||
e1.fire(5);
|
||||
assert.deepEqual(result, [1, 2, 3, 4, 5]);
|
||||
});
|
||||
});
|
||||
|
||||
test('latch', () => {
|
||||
const emitter = new Emitter<number>();
|
||||
const event = Event.latch(emitter.event);
|
||||
|
||||
const result: number[] = [];
|
||||
const listener = event(num => result.push(num));
|
||||
|
||||
assert.deepEqual(result, []);
|
||||
|
||||
emitter.fire(1);
|
||||
assert.deepEqual(result, [1]);
|
||||
|
||||
emitter.fire(2);
|
||||
assert.deepEqual(result, [1, 2]);
|
||||
|
||||
emitter.fire(2);
|
||||
assert.deepEqual(result, [1, 2]);
|
||||
|
||||
emitter.fire(1);
|
||||
assert.deepEqual(result, [1, 2, 1]);
|
||||
|
||||
emitter.fire(1);
|
||||
assert.deepEqual(result, [1, 2, 1]);
|
||||
|
||||
emitter.fire(3);
|
||||
assert.deepEqual(result, [1, 2, 1, 3]);
|
||||
|
||||
emitter.fire(3);
|
||||
assert.deepEqual(result, [1, 2, 1, 3]);
|
||||
|
||||
emitter.fire(3);
|
||||
assert.deepEqual(result, [1, 2, 1, 3]);
|
||||
|
||||
listener.dispose();
|
||||
});
|
||||
|
||||
});
|
||||
177
lib/vscode/src/vs/base/test/common/extpath.test.ts
Normal file
177
lib/vscode/src/vs/base/test/common/extpath.test.ts
Normal file
@@ -0,0 +1,177 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import * as extpath from 'vs/base/common/extpath';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { CharCode } from 'vs/base/common/charCode';
|
||||
|
||||
suite('Paths', () => {
|
||||
|
||||
test('toForwardSlashes', () => {
|
||||
assert.equal(extpath.toSlashes('\\\\server\\share\\some\\path'), '//server/share/some/path');
|
||||
assert.equal(extpath.toSlashes('c:\\test'), 'c:/test');
|
||||
assert.equal(extpath.toSlashes('foo\\bar'), 'foo/bar');
|
||||
assert.equal(extpath.toSlashes('/user/far'), '/user/far');
|
||||
});
|
||||
|
||||
test('getRoot', () => {
|
||||
assert.equal(extpath.getRoot('/user/far'), '/');
|
||||
assert.equal(extpath.getRoot('\\\\server\\share\\some\\path'), '//server/share/');
|
||||
assert.equal(extpath.getRoot('//server/share/some/path'), '//server/share/');
|
||||
assert.equal(extpath.getRoot('//server/share'), '/');
|
||||
assert.equal(extpath.getRoot('//server'), '/');
|
||||
assert.equal(extpath.getRoot('//server//'), '/');
|
||||
assert.equal(extpath.getRoot('c:/user/far'), 'c:/');
|
||||
assert.equal(extpath.getRoot('c:user/far'), 'c:');
|
||||
assert.equal(extpath.getRoot('http://www'), '');
|
||||
assert.equal(extpath.getRoot('http://www/'), 'http://www/');
|
||||
assert.equal(extpath.getRoot('file:///foo'), 'file:///');
|
||||
assert.equal(extpath.getRoot('file://foo'), '');
|
||||
});
|
||||
|
||||
test('isUNC', () => {
|
||||
if (platform.isWindows) {
|
||||
assert.ok(!extpath.isUNC('foo'));
|
||||
assert.ok(!extpath.isUNC('/foo'));
|
||||
assert.ok(!extpath.isUNC('\\foo'));
|
||||
assert.ok(!extpath.isUNC('\\\\foo'));
|
||||
assert.ok(extpath.isUNC('\\\\a\\b'));
|
||||
assert.ok(!extpath.isUNC('//a/b'));
|
||||
assert.ok(extpath.isUNC('\\\\server\\share'));
|
||||
assert.ok(extpath.isUNC('\\\\server\\share\\'));
|
||||
assert.ok(extpath.isUNC('\\\\server\\share\\path'));
|
||||
}
|
||||
});
|
||||
|
||||
test('isValidBasename', () => {
|
||||
assert.ok(!extpath.isValidBasename(null));
|
||||
assert.ok(!extpath.isValidBasename(''));
|
||||
assert.ok(extpath.isValidBasename('test.txt'));
|
||||
assert.ok(!extpath.isValidBasename('/test.txt'));
|
||||
assert.ok(!extpath.isValidBasename('\\test.txt'));
|
||||
|
||||
if (platform.isWindows) {
|
||||
assert.ok(!extpath.isValidBasename('aux'));
|
||||
assert.ok(!extpath.isValidBasename('Aux'));
|
||||
assert.ok(!extpath.isValidBasename('LPT0'));
|
||||
assert.ok(!extpath.isValidBasename('aux.txt'));
|
||||
assert.ok(!extpath.isValidBasename('com0.abc'));
|
||||
assert.ok(extpath.isValidBasename('LPT00'));
|
||||
assert.ok(extpath.isValidBasename('aux1'));
|
||||
assert.ok(extpath.isValidBasename('aux1.txt'));
|
||||
assert.ok(extpath.isValidBasename('aux1.aux.txt'));
|
||||
|
||||
assert.ok(!extpath.isValidBasename('test.txt.'));
|
||||
assert.ok(!extpath.isValidBasename('test.txt..'));
|
||||
assert.ok(!extpath.isValidBasename('test.txt '));
|
||||
assert.ok(!extpath.isValidBasename('test.txt\t'));
|
||||
assert.ok(!extpath.isValidBasename('tes:t.txt'));
|
||||
assert.ok(!extpath.isValidBasename('tes"t.txt'));
|
||||
}
|
||||
});
|
||||
|
||||
test('sanitizeFilePath', () => {
|
||||
if (platform.isWindows) {
|
||||
assert.equal(extpath.sanitizeFilePath('.', 'C:\\the\\cwd'), 'C:\\the\\cwd');
|
||||
assert.equal(extpath.sanitizeFilePath('', 'C:\\the\\cwd'), 'C:\\the\\cwd');
|
||||
|
||||
assert.equal(extpath.sanitizeFilePath('C:', 'C:\\the\\cwd'), 'C:\\');
|
||||
assert.equal(extpath.sanitizeFilePath('C:\\', 'C:\\the\\cwd'), 'C:\\');
|
||||
assert.equal(extpath.sanitizeFilePath('C:\\\\', 'C:\\the\\cwd'), 'C:\\');
|
||||
|
||||
assert.equal(extpath.sanitizeFilePath('C:\\folder\\my.txt', 'C:\\the\\cwd'), 'C:\\folder\\my.txt');
|
||||
assert.equal(extpath.sanitizeFilePath('C:\\folder\\my', 'C:\\the\\cwd'), 'C:\\folder\\my');
|
||||
assert.equal(extpath.sanitizeFilePath('C:\\folder\\..\\my', 'C:\\the\\cwd'), 'C:\\my');
|
||||
assert.equal(extpath.sanitizeFilePath('C:\\folder\\my\\', 'C:\\the\\cwd'), 'C:\\folder\\my');
|
||||
assert.equal(extpath.sanitizeFilePath('C:\\folder\\my\\\\\\', 'C:\\the\\cwd'), 'C:\\folder\\my');
|
||||
|
||||
assert.equal(extpath.sanitizeFilePath('my.txt', 'C:\\the\\cwd'), 'C:\\the\\cwd\\my.txt');
|
||||
assert.equal(extpath.sanitizeFilePath('my.txt\\', 'C:\\the\\cwd'), 'C:\\the\\cwd\\my.txt');
|
||||
|
||||
assert.equal(extpath.sanitizeFilePath('\\\\localhost\\folder\\my', 'C:\\the\\cwd'), '\\\\localhost\\folder\\my');
|
||||
assert.equal(extpath.sanitizeFilePath('\\\\localhost\\folder\\my\\', 'C:\\the\\cwd'), '\\\\localhost\\folder\\my');
|
||||
} else {
|
||||
assert.equal(extpath.sanitizeFilePath('.', '/the/cwd'), '/the/cwd');
|
||||
assert.equal(extpath.sanitizeFilePath('', '/the/cwd'), '/the/cwd');
|
||||
assert.equal(extpath.sanitizeFilePath('/', '/the/cwd'), '/');
|
||||
|
||||
assert.equal(extpath.sanitizeFilePath('/folder/my.txt', '/the/cwd'), '/folder/my.txt');
|
||||
assert.equal(extpath.sanitizeFilePath('/folder/my', '/the/cwd'), '/folder/my');
|
||||
assert.equal(extpath.sanitizeFilePath('/folder/../my', '/the/cwd'), '/my');
|
||||
assert.equal(extpath.sanitizeFilePath('/folder/my/', '/the/cwd'), '/folder/my');
|
||||
assert.equal(extpath.sanitizeFilePath('/folder/my///', '/the/cwd'), '/folder/my');
|
||||
|
||||
assert.equal(extpath.sanitizeFilePath('my.txt', '/the/cwd'), '/the/cwd/my.txt');
|
||||
assert.equal(extpath.sanitizeFilePath('my.txt/', '/the/cwd'), '/the/cwd/my.txt');
|
||||
}
|
||||
});
|
||||
|
||||
test('isRoot', () => {
|
||||
if (platform.isWindows) {
|
||||
assert.ok(extpath.isRootOrDriveLetter('c:'));
|
||||
assert.ok(extpath.isRootOrDriveLetter('D:'));
|
||||
assert.ok(extpath.isRootOrDriveLetter('D:/'));
|
||||
assert.ok(extpath.isRootOrDriveLetter('D:\\'));
|
||||
assert.ok(!extpath.isRootOrDriveLetter('D:\\path'));
|
||||
assert.ok(!extpath.isRootOrDriveLetter('D:/path'));
|
||||
} else {
|
||||
assert.ok(extpath.isRootOrDriveLetter('/'));
|
||||
assert.ok(!extpath.isRootOrDriveLetter('/path'));
|
||||
}
|
||||
});
|
||||
|
||||
test('isWindowsDriveLetter', () => {
|
||||
assert.ok(!extpath.isWindowsDriveLetter(0));
|
||||
assert.ok(!extpath.isWindowsDriveLetter(-1));
|
||||
assert.ok(extpath.isWindowsDriveLetter(CharCode.A));
|
||||
assert.ok(extpath.isWindowsDriveLetter(CharCode.z));
|
||||
});
|
||||
|
||||
test('indexOfPath', () => {
|
||||
assert.equal(extpath.indexOfPath('/foo', '/bar', true), -1);
|
||||
assert.equal(extpath.indexOfPath('/foo', '/FOO', false), -1);
|
||||
assert.equal(extpath.indexOfPath('/foo', '/FOO', true), 0);
|
||||
assert.equal(extpath.indexOfPath('/some/long/path', '/some/long', false), 0);
|
||||
assert.equal(extpath.indexOfPath('/some/long/path', '/PATH', true), 10);
|
||||
});
|
||||
|
||||
test('parseLineAndColumnAware', () => {
|
||||
let res = extpath.parseLineAndColumnAware('/foo/bar');
|
||||
assert.equal(res.path, '/foo/bar');
|
||||
assert.equal(res.line, undefined);
|
||||
assert.equal(res.column, undefined);
|
||||
|
||||
res = extpath.parseLineAndColumnAware('/foo/bar:33');
|
||||
assert.equal(res.path, '/foo/bar');
|
||||
assert.equal(res.line, 33);
|
||||
assert.equal(res.column, 1);
|
||||
|
||||
res = extpath.parseLineAndColumnAware('/foo/bar:33:34');
|
||||
assert.equal(res.path, '/foo/bar');
|
||||
assert.equal(res.line, 33);
|
||||
assert.equal(res.column, 34);
|
||||
|
||||
res = extpath.parseLineAndColumnAware('C:\\foo\\bar');
|
||||
assert.equal(res.path, 'C:\\foo\\bar');
|
||||
assert.equal(res.line, undefined);
|
||||
assert.equal(res.column, undefined);
|
||||
|
||||
res = extpath.parseLineAndColumnAware('C:\\foo\\bar:33');
|
||||
assert.equal(res.path, 'C:\\foo\\bar');
|
||||
assert.equal(res.line, 33);
|
||||
assert.equal(res.column, 1);
|
||||
|
||||
res = extpath.parseLineAndColumnAware('C:\\foo\\bar:33:34');
|
||||
assert.equal(res.path, 'C:\\foo\\bar');
|
||||
assert.equal(res.line, 33);
|
||||
assert.equal(res.column, 34);
|
||||
|
||||
res = extpath.parseLineAndColumnAware('/foo/bar:abb');
|
||||
assert.equal(res.path, '/foo/bar:abb');
|
||||
assert.equal(res.line, undefined);
|
||||
assert.equal(res.column, undefined);
|
||||
});
|
||||
});
|
||||
5
lib/vscode/src/vs/base/test/common/filters.perf.data.d.ts
vendored
Normal file
5
lib/vscode/src/vs/base/test/common/filters.perf.data.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
export const data: string[];
|
||||
7
lib/vscode/src/vs/base/test/common/filters.perf.data.js
Normal file
7
lib/vscode/src/vs/base/test/common/filters.perf.data.js
Normal file
File diff suppressed because one or more lines are too long
72
lib/vscode/src/vs/base/test/common/filters.perf.test.ts
Normal file
72
lib/vscode/src/vs/base/test/common/filters.perf.test.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as filters from 'vs/base/common/filters';
|
||||
import { data } from './filters.perf.data';
|
||||
|
||||
const patterns = ['cci', 'ida', 'pos', 'CCI', 'enbled', 'callback', 'gGame', 'cons', 'zyx', 'aBc'];
|
||||
|
||||
const _enablePerf = false;
|
||||
|
||||
function perfSuite(name: string, callback: (this: Mocha.ISuiteCallbackContext) => void) {
|
||||
if (_enablePerf) {
|
||||
suite(name, callback);
|
||||
}
|
||||
}
|
||||
|
||||
perfSuite('Performance - fuzzyMatch', function () {
|
||||
|
||||
console.log(`Matching ${data.length} items against ${patterns.length} patterns (${data.length * patterns.length} operations) `);
|
||||
|
||||
function perfTest(name: string, match: filters.FuzzyScorer) {
|
||||
test(name, () => {
|
||||
|
||||
const t1 = Date.now();
|
||||
let count = 0;
|
||||
for (let i = 0; i < 2; i++) {
|
||||
for (const pattern of patterns) {
|
||||
const patternLow = pattern.toLowerCase();
|
||||
for (const item of data) {
|
||||
count += 1;
|
||||
match(pattern, patternLow, 0, item, item.toLowerCase(), 0, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
const d = Date.now() - t1;
|
||||
console.log(name, `${d}ms, ${Math.round(count / d) * 15}/15ms, ${Math.round(count / d)}/1ms`);
|
||||
});
|
||||
}
|
||||
|
||||
perfTest('fuzzyScore', filters.fuzzyScore);
|
||||
perfTest('fuzzyScoreGraceful', filters.fuzzyScoreGraceful);
|
||||
perfTest('fuzzyScoreGracefulAggressive', filters.fuzzyScoreGracefulAggressive);
|
||||
});
|
||||
|
||||
|
||||
perfSuite('Performance - IFilter', function () {
|
||||
|
||||
function perfTest(name: string, match: filters.IFilter) {
|
||||
test(name, () => {
|
||||
|
||||
const t1 = Date.now();
|
||||
let count = 0;
|
||||
for (let i = 0; i < 2; i++) {
|
||||
for (const pattern of patterns) {
|
||||
for (const item of data) {
|
||||
count += 1;
|
||||
match(pattern, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
const d = Date.now() - t1;
|
||||
console.log(name, `${d}ms, ${Math.round(count / d) * 15}/15ms, ${Math.round(count / d)}/1ms`);
|
||||
});
|
||||
}
|
||||
|
||||
perfTest('matchesFuzzy', filters.matchesFuzzy);
|
||||
perfTest('matchesFuzzy2', filters.matchesFuzzy2);
|
||||
perfTest('matchesPrefix', filters.matchesPrefix);
|
||||
perfTest('matchesContiguousSubString', filters.matchesContiguousSubString);
|
||||
perfTest('matchesCamelCase', filters.matchesCamelCase);
|
||||
});
|
||||
541
lib/vscode/src/vs/base/test/common/filters.test.ts
Normal file
541
lib/vscode/src/vs/base/test/common/filters.test.ts
Normal file
@@ -0,0 +1,541 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as assert from 'assert';
|
||||
import { IFilter, or, matchesPrefix, matchesStrictPrefix, matchesCamelCase, matchesSubString, matchesContiguousSubString, matchesWords, fuzzyScore, IMatch, fuzzyScoreGraceful, fuzzyScoreGracefulAggressive, FuzzyScorer, createMatches } from 'vs/base/common/filters';
|
||||
|
||||
function filterOk(filter: IFilter, word: string, wordToMatchAgainst: string, highlights?: { start: number; end: number; }[]) {
|
||||
let r = filter(word, wordToMatchAgainst);
|
||||
assert(r, `${word} didn't match ${wordToMatchAgainst}`);
|
||||
if (highlights) {
|
||||
assert.deepEqual(r, highlights);
|
||||
}
|
||||
}
|
||||
|
||||
function filterNotOk(filter: IFilter, word: string, wordToMatchAgainst: string) {
|
||||
assert(!filter(word, wordToMatchAgainst), `${word} matched ${wordToMatchAgainst}`);
|
||||
}
|
||||
|
||||
suite('Filters', () => {
|
||||
test('or', () => {
|
||||
let filter: IFilter;
|
||||
let counters: number[];
|
||||
let newFilter = function (i: number, r: boolean): IFilter {
|
||||
return function (): IMatch[] { counters[i]++; return r as any; };
|
||||
};
|
||||
|
||||
counters = [0, 0];
|
||||
filter = or(newFilter(0, false), newFilter(1, false));
|
||||
filterNotOk(filter, 'anything', 'anything');
|
||||
assert.deepEqual(counters, [1, 1]);
|
||||
|
||||
counters = [0, 0];
|
||||
filter = or(newFilter(0, true), newFilter(1, false));
|
||||
filterOk(filter, 'anything', 'anything');
|
||||
assert.deepEqual(counters, [1, 0]);
|
||||
|
||||
counters = [0, 0];
|
||||
filter = or(newFilter(0, true), newFilter(1, true));
|
||||
filterOk(filter, 'anything', 'anything');
|
||||
assert.deepEqual(counters, [1, 0]);
|
||||
|
||||
counters = [0, 0];
|
||||
filter = or(newFilter(0, false), newFilter(1, true));
|
||||
filterOk(filter, 'anything', 'anything');
|
||||
assert.deepEqual(counters, [1, 1]);
|
||||
});
|
||||
|
||||
test('PrefixFilter - case sensitive', function () {
|
||||
filterNotOk(matchesStrictPrefix, '', '');
|
||||
filterOk(matchesStrictPrefix, '', 'anything', []);
|
||||
filterOk(matchesStrictPrefix, 'alpha', 'alpha', [{ start: 0, end: 5 }]);
|
||||
filterOk(matchesStrictPrefix, 'alpha', 'alphasomething', [{ start: 0, end: 5 }]);
|
||||
filterNotOk(matchesStrictPrefix, 'alpha', 'alp');
|
||||
filterOk(matchesStrictPrefix, 'a', 'alpha', [{ start: 0, end: 1 }]);
|
||||
filterNotOk(matchesStrictPrefix, 'x', 'alpha');
|
||||
filterNotOk(matchesStrictPrefix, 'A', 'alpha');
|
||||
filterNotOk(matchesStrictPrefix, 'AlPh', 'alPHA');
|
||||
});
|
||||
|
||||
test('PrefixFilter - ignore case', function () {
|
||||
filterOk(matchesPrefix, 'alpha', 'alpha', [{ start: 0, end: 5 }]);
|
||||
filterOk(matchesPrefix, 'alpha', 'alphasomething', [{ start: 0, end: 5 }]);
|
||||
filterNotOk(matchesPrefix, 'alpha', 'alp');
|
||||
filterOk(matchesPrefix, 'a', 'alpha', [{ start: 0, end: 1 }]);
|
||||
filterOk(matchesPrefix, 'ä', 'Älpha', [{ start: 0, end: 1 }]);
|
||||
filterNotOk(matchesPrefix, 'x', 'alpha');
|
||||
filterOk(matchesPrefix, 'A', 'alpha', [{ start: 0, end: 1 }]);
|
||||
filterOk(matchesPrefix, 'AlPh', 'alPHA', [{ start: 0, end: 4 }]);
|
||||
filterNotOk(matchesPrefix, 'T', '4'); // see https://github.com/microsoft/vscode/issues/22401
|
||||
});
|
||||
|
||||
test('CamelCaseFilter', () => {
|
||||
filterNotOk(matchesCamelCase, '', '');
|
||||
filterOk(matchesCamelCase, '', 'anything', []);
|
||||
filterOk(matchesCamelCase, 'alpha', 'alpha', [{ start: 0, end: 5 }]);
|
||||
filterOk(matchesCamelCase, 'AlPhA', 'alpha', [{ start: 0, end: 5 }]);
|
||||
filterOk(matchesCamelCase, 'alpha', 'alphasomething', [{ start: 0, end: 5 }]);
|
||||
filterNotOk(matchesCamelCase, 'alpha', 'alp');
|
||||
|
||||
filterOk(matchesCamelCase, 'c', 'CamelCaseRocks', [
|
||||
{ start: 0, end: 1 }
|
||||
]);
|
||||
filterOk(matchesCamelCase, 'cc', 'CamelCaseRocks', [
|
||||
{ start: 0, end: 1 },
|
||||
{ start: 5, end: 6 }
|
||||
]);
|
||||
filterOk(matchesCamelCase, 'ccr', 'CamelCaseRocks', [
|
||||
{ start: 0, end: 1 },
|
||||
{ start: 5, end: 6 },
|
||||
{ start: 9, end: 10 }
|
||||
]);
|
||||
filterOk(matchesCamelCase, 'cacr', 'CamelCaseRocks', [
|
||||
{ start: 0, end: 2 },
|
||||
{ start: 5, end: 6 },
|
||||
{ start: 9, end: 10 }
|
||||
]);
|
||||
filterOk(matchesCamelCase, 'cacar', 'CamelCaseRocks', [
|
||||
{ start: 0, end: 2 },
|
||||
{ start: 5, end: 7 },
|
||||
{ start: 9, end: 10 }
|
||||
]);
|
||||
filterOk(matchesCamelCase, 'ccarocks', 'CamelCaseRocks', [
|
||||
{ start: 0, end: 1 },
|
||||
{ start: 5, end: 7 },
|
||||
{ start: 9, end: 14 }
|
||||
]);
|
||||
filterOk(matchesCamelCase, 'cr', 'CamelCaseRocks', [
|
||||
{ start: 0, end: 1 },
|
||||
{ start: 9, end: 10 }
|
||||
]);
|
||||
filterOk(matchesCamelCase, 'fba', 'FooBarAbe', [
|
||||
{ start: 0, end: 1 },
|
||||
{ start: 3, end: 5 }
|
||||
]);
|
||||
filterOk(matchesCamelCase, 'fbar', 'FooBarAbe', [
|
||||
{ start: 0, end: 1 },
|
||||
{ start: 3, end: 6 }
|
||||
]);
|
||||
filterOk(matchesCamelCase, 'fbara', 'FooBarAbe', [
|
||||
{ start: 0, end: 1 },
|
||||
{ start: 3, end: 7 }
|
||||
]);
|
||||
filterOk(matchesCamelCase, 'fbaa', 'FooBarAbe', [
|
||||
{ start: 0, end: 1 },
|
||||
{ start: 3, end: 5 },
|
||||
{ start: 6, end: 7 }
|
||||
]);
|
||||
filterOk(matchesCamelCase, 'fbaab', 'FooBarAbe', [
|
||||
{ start: 0, end: 1 },
|
||||
{ start: 3, end: 5 },
|
||||
{ start: 6, end: 8 }
|
||||
]);
|
||||
filterOk(matchesCamelCase, 'c2d', 'canvasCreation2D', [
|
||||
{ start: 0, end: 1 },
|
||||
{ start: 14, end: 16 }
|
||||
]);
|
||||
filterOk(matchesCamelCase, 'cce', '_canvasCreationEvent', [
|
||||
{ start: 1, end: 2 },
|
||||
{ start: 7, end: 8 },
|
||||
{ start: 15, end: 16 }
|
||||
]);
|
||||
});
|
||||
|
||||
test('CamelCaseFilter - #19256', function () {
|
||||
assert(matchesCamelCase('Debug Console', 'Open: Debug Console'));
|
||||
assert(matchesCamelCase('Debug console', 'Open: Debug Console'));
|
||||
assert(matchesCamelCase('debug console', 'Open: Debug Console'));
|
||||
});
|
||||
|
||||
test('matchesContiguousSubString', () => {
|
||||
filterOk(matchesContiguousSubString, 'cela', 'cancelAnimationFrame()', [
|
||||
{ start: 3, end: 7 }
|
||||
]);
|
||||
});
|
||||
|
||||
test('matchesSubString', () => {
|
||||
filterOk(matchesSubString, 'cmm', 'cancelAnimationFrame()', [
|
||||
{ start: 0, end: 1 },
|
||||
{ start: 9, end: 10 },
|
||||
{ start: 18, end: 19 }
|
||||
]);
|
||||
filterOk(matchesSubString, 'abc', 'abcabc', [
|
||||
{ start: 0, end: 3 },
|
||||
]);
|
||||
filterOk(matchesSubString, 'abc', 'aaabbbccc', [
|
||||
{ start: 0, end: 1 },
|
||||
{ start: 3, end: 4 },
|
||||
{ start: 6, end: 7 },
|
||||
]);
|
||||
});
|
||||
|
||||
test('matchesSubString performance (#35346)', function () {
|
||||
filterNotOk(matchesSubString, 'aaaaaaaaaaaaaaaaaaaax', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa');
|
||||
});
|
||||
|
||||
test('WordFilter', () => {
|
||||
filterOk(matchesWords, 'alpha', 'alpha', [{ start: 0, end: 5 }]);
|
||||
filterOk(matchesWords, 'alpha', 'alphasomething', [{ start: 0, end: 5 }]);
|
||||
filterNotOk(matchesWords, 'alpha', 'alp');
|
||||
filterOk(matchesWords, 'a', 'alpha', [{ start: 0, end: 1 }]);
|
||||
filterNotOk(matchesWords, 'x', 'alpha');
|
||||
filterOk(matchesWords, 'A', 'alpha', [{ start: 0, end: 1 }]);
|
||||
filterOk(matchesWords, 'AlPh', 'alPHA', [{ start: 0, end: 4 }]);
|
||||
assert(matchesWords('Debug Console', 'Open: Debug Console'));
|
||||
|
||||
filterOk(matchesWords, 'gp', 'Git: Pull', [{ start: 0, end: 1 }, { start: 5, end: 6 }]);
|
||||
filterOk(matchesWords, 'g p', 'Git: Pull', [{ start: 0, end: 1 }, { start: 3, end: 4 }, { start: 5, end: 6 }]);
|
||||
filterOk(matchesWords, 'gipu', 'Git: Pull', [{ start: 0, end: 2 }, { start: 5, end: 7 }]);
|
||||
|
||||
filterOk(matchesWords, 'gp', 'Category: Git: Pull', [{ start: 10, end: 11 }, { start: 15, end: 16 }]);
|
||||
filterOk(matchesWords, 'g p', 'Category: Git: Pull', [{ start: 10, end: 11 }, { start: 13, end: 14 }, { start: 15, end: 16 }]);
|
||||
filterOk(matchesWords, 'gipu', 'Category: Git: Pull', [{ start: 10, end: 12 }, { start: 15, end: 17 }]);
|
||||
|
||||
filterNotOk(matchesWords, 'it', 'Git: Pull');
|
||||
filterNotOk(matchesWords, 'll', 'Git: Pull');
|
||||
|
||||
filterOk(matchesWords, 'git: プル', 'git: プル', [{ start: 0, end: 7 }]);
|
||||
filterOk(matchesWords, 'git プル', 'git: プル', [{ start: 0, end: 4 }, { start: 5, end: 7 }]);
|
||||
|
||||
filterOk(matchesWords, 'öäk', 'Öhm: Älles Klar', [{ start: 0, end: 1 }, { start: 5, end: 6 }, { start: 11, end: 12 }]);
|
||||
|
||||
// assert.ok(matchesWords('gipu', 'Category: Git: Pull', true) === null);
|
||||
// assert.deepEqual(matchesWords('pu', 'Category: Git: Pull', true), [{ start: 15, end: 17 }]);
|
||||
|
||||
filterOk(matchesWords, 'bar', 'foo-bar');
|
||||
filterOk(matchesWords, 'bar test', 'foo-bar test');
|
||||
filterOk(matchesWords, 'fbt', 'foo-bar test');
|
||||
filterOk(matchesWords, 'bar test', 'foo-bar (test)');
|
||||
filterOk(matchesWords, 'foo bar', 'foo (bar)');
|
||||
|
||||
filterNotOk(matchesWords, 'bar est', 'foo-bar test');
|
||||
filterNotOk(matchesWords, 'fo ar', 'foo-bar test');
|
||||
filterNotOk(matchesWords, 'for', 'foo-bar test');
|
||||
|
||||
filterOk(matchesWords, 'foo bar', 'foo-bar');
|
||||
filterOk(matchesWords, 'foo bar', '123 foo-bar 456');
|
||||
filterOk(matchesWords, 'foo+bar', 'foo-bar');
|
||||
filterOk(matchesWords, 'foo-bar', 'foo bar');
|
||||
filterOk(matchesWords, 'foo:bar', 'foo:bar');
|
||||
});
|
||||
|
||||
function assertMatches(pattern: string, word: string, decoratedWord: string | undefined, filter: FuzzyScorer, opts: { patternPos?: number, wordPos?: number, firstMatchCanBeWeak?: boolean } = {}) {
|
||||
let r = filter(pattern, pattern.toLowerCase(), opts.patternPos || 0, word, word.toLowerCase(), opts.wordPos || 0, opts.firstMatchCanBeWeak || false);
|
||||
assert.ok(!decoratedWord === !r);
|
||||
if (r) {
|
||||
let matches = createMatches(r);
|
||||
let actualWord = '';
|
||||
let pos = 0;
|
||||
for (const match of matches) {
|
||||
actualWord += word.substring(pos, match.start);
|
||||
actualWord += '^' + word.substring(match.start, match.end).split('').join('^');
|
||||
pos = match.end;
|
||||
}
|
||||
actualWord += word.substring(pos);
|
||||
assert.equal(actualWord, decoratedWord);
|
||||
}
|
||||
}
|
||||
|
||||
test('fuzzyScore, #23215', function () {
|
||||
assertMatches('tit', 'win.tit', 'win.^t^i^t', fuzzyScore);
|
||||
assertMatches('title', 'win.title', 'win.^t^i^t^l^e', fuzzyScore);
|
||||
assertMatches('WordCla', 'WordCharacterClassifier', '^W^o^r^dCharacter^C^l^assifier', fuzzyScore);
|
||||
assertMatches('WordCCla', 'WordCharacterClassifier', '^W^o^r^d^Character^C^l^assifier', fuzzyScore);
|
||||
});
|
||||
|
||||
test('fuzzyScore, #23332', function () {
|
||||
assertMatches('dete', '"editor.quickSuggestionsDelay"', undefined, fuzzyScore);
|
||||
});
|
||||
|
||||
test('fuzzyScore, #23190', function () {
|
||||
assertMatches('c:\\do', '& \'C:\\Documents and Settings\'', '& \'^C^:^\\^D^ocuments and Settings\'', fuzzyScore);
|
||||
assertMatches('c:\\do', '& \'c:\\Documents and Settings\'', '& \'^c^:^\\^D^ocuments and Settings\'', fuzzyScore);
|
||||
});
|
||||
|
||||
test('fuzzyScore, #23581', function () {
|
||||
assertMatches('close', 'css.lint.importStatement', '^css.^lint.imp^ort^Stat^ement', fuzzyScore);
|
||||
assertMatches('close', 'css.colorDecorators.enable', '^css.co^l^orDecorator^s.^enable', fuzzyScore);
|
||||
assertMatches('close', 'workbench.quickOpen.closeOnFocusOut', 'workbench.quickOpen.^c^l^o^s^eOnFocusOut', fuzzyScore);
|
||||
assertTopScore(fuzzyScore, 'close', 2, 'css.lint.importStatement', 'css.colorDecorators.enable', 'workbench.quickOpen.closeOnFocusOut');
|
||||
});
|
||||
|
||||
test('fuzzyScore, #23458', function () {
|
||||
assertMatches('highlight', 'editorHoverHighlight', 'editorHover^H^i^g^h^l^i^g^h^t', fuzzyScore);
|
||||
assertMatches('hhighlight', 'editorHoverHighlight', 'editor^Hover^H^i^g^h^l^i^g^h^t', fuzzyScore);
|
||||
assertMatches('dhhighlight', 'editorHoverHighlight', undefined, fuzzyScore);
|
||||
});
|
||||
test('fuzzyScore, #23746', function () {
|
||||
assertMatches('-moz', '-moz-foo', '^-^m^o^z-foo', fuzzyScore);
|
||||
assertMatches('moz', '-moz-foo', '-^m^o^z-foo', fuzzyScore);
|
||||
assertMatches('moz', '-moz-animation', '-^m^o^z-animation', fuzzyScore);
|
||||
assertMatches('moza', '-moz-animation', '-^m^o^z-^animation', fuzzyScore);
|
||||
});
|
||||
|
||||
test('fuzzyScore', () => {
|
||||
assertMatches('ab', 'abA', '^a^bA', fuzzyScore);
|
||||
assertMatches('ccm', 'cacmelCase', '^ca^c^melCase', fuzzyScore);
|
||||
assertMatches('bti', 'the_black_knight', undefined, fuzzyScore);
|
||||
assertMatches('ccm', 'camelCase', undefined, fuzzyScore);
|
||||
assertMatches('cmcm', 'camelCase', undefined, fuzzyScore);
|
||||
assertMatches('BK', 'the_black_knight', 'the_^black_^knight', fuzzyScore);
|
||||
assertMatches('KeyboardLayout=', 'KeyboardLayout', undefined, fuzzyScore);
|
||||
assertMatches('LLL', 'SVisualLoggerLogsList', 'SVisual^Logger^Logs^List', fuzzyScore);
|
||||
assertMatches('LLLL', 'SVilLoLosLi', undefined, fuzzyScore);
|
||||
assertMatches('LLLL', 'SVisualLoggerLogsList', undefined, fuzzyScore);
|
||||
assertMatches('TEdit', 'TextEdit', '^Text^E^d^i^t', fuzzyScore);
|
||||
assertMatches('TEdit', 'TextEditor', '^Text^E^d^i^tor', fuzzyScore);
|
||||
assertMatches('TEdit', 'Textedit', '^T^exte^d^i^t', fuzzyScore);
|
||||
assertMatches('TEdit', 'text_edit', '^text_^e^d^i^t', fuzzyScore);
|
||||
assertMatches('TEditDit', 'TextEditorDecorationType', '^Text^E^d^i^tor^Decorat^ion^Type', fuzzyScore);
|
||||
assertMatches('TEdit', 'TextEditorDecorationType', '^Text^E^d^i^torDecorationType', fuzzyScore);
|
||||
assertMatches('Tedit', 'TextEdit', '^Text^E^d^i^t', fuzzyScore);
|
||||
assertMatches('ba', '?AB?', undefined, fuzzyScore);
|
||||
assertMatches('bkn', 'the_black_knight', 'the_^black_^k^night', fuzzyScore);
|
||||
assertMatches('bt', 'the_black_knight', 'the_^black_knigh^t', fuzzyScore);
|
||||
assertMatches('ccm', 'camelCasecm', '^camel^Casec^m', fuzzyScore);
|
||||
assertMatches('fdm', 'findModel', '^fin^d^Model', fuzzyScore);
|
||||
assertMatches('fob', 'foobar', '^f^oo^bar', fuzzyScore);
|
||||
assertMatches('fobz', 'foobar', undefined, fuzzyScore);
|
||||
assertMatches('foobar', 'foobar', '^f^o^o^b^a^r', fuzzyScore);
|
||||
assertMatches('form', 'editor.formatOnSave', 'editor.^f^o^r^matOnSave', fuzzyScore);
|
||||
assertMatches('g p', 'Git: Pull', '^Git:^ ^Pull', fuzzyScore);
|
||||
assertMatches('g p', 'Git: Pull', '^Git:^ ^Pull', fuzzyScore);
|
||||
assertMatches('gip', 'Git: Pull', '^G^it: ^Pull', fuzzyScore);
|
||||
assertMatches('gip', 'Git: Pull', '^G^it: ^Pull', fuzzyScore);
|
||||
assertMatches('gp', 'Git: Pull', '^Git: ^Pull', fuzzyScore);
|
||||
assertMatches('gp', 'Git_Git_Pull', '^Git_Git_^Pull', fuzzyScore);
|
||||
assertMatches('is', 'ImportStatement', '^Import^Statement', fuzzyScore);
|
||||
assertMatches('is', 'isValid', '^i^sValid', fuzzyScore);
|
||||
assertMatches('lowrd', 'lowWord', '^l^o^wWo^r^d', fuzzyScore);
|
||||
assertMatches('myvable', 'myvariable', '^m^y^v^aria^b^l^e', fuzzyScore);
|
||||
assertMatches('no', '', undefined, fuzzyScore);
|
||||
assertMatches('no', 'match', undefined, fuzzyScore);
|
||||
assertMatches('ob', 'foobar', undefined, fuzzyScore);
|
||||
assertMatches('sl', 'SVisualLoggerLogsList', '^SVisual^LoggerLogsList', fuzzyScore);
|
||||
assertMatches('sllll', 'SVisualLoggerLogsList', '^SVisua^l^Logger^Logs^List', fuzzyScore);
|
||||
assertMatches('Three', 'HTMLHRElement', undefined, fuzzyScore);
|
||||
assertMatches('Three', 'Three', '^T^h^r^e^e', fuzzyScore);
|
||||
assertMatches('fo', 'barfoo', undefined, fuzzyScore);
|
||||
assertMatches('fo', 'bar_foo', 'bar_^f^oo', fuzzyScore);
|
||||
assertMatches('fo', 'bar_Foo', 'bar_^F^oo', fuzzyScore);
|
||||
assertMatches('fo', 'bar foo', 'bar ^f^oo', fuzzyScore);
|
||||
assertMatches('fo', 'bar.foo', 'bar.^f^oo', fuzzyScore);
|
||||
assertMatches('fo', 'bar/foo', 'bar/^f^oo', fuzzyScore);
|
||||
assertMatches('fo', 'bar\\foo', 'bar\\^f^oo', fuzzyScore);
|
||||
});
|
||||
|
||||
test('fuzzyScore (first match can be weak)', function () {
|
||||
|
||||
assertMatches('Three', 'HTMLHRElement', 'H^TML^H^R^El^ement', fuzzyScore, { firstMatchCanBeWeak: true });
|
||||
assertMatches('tor', 'constructor', 'construc^t^o^r', fuzzyScore, { firstMatchCanBeWeak: true });
|
||||
assertMatches('ur', 'constructor', 'constr^ucto^r', fuzzyScore, { firstMatchCanBeWeak: true });
|
||||
assertTopScore(fuzzyScore, 'tor', 2, 'constructor', 'Thor', 'cTor');
|
||||
});
|
||||
|
||||
test('fuzzyScore, many matches', function () {
|
||||
|
||||
assertMatches(
|
||||
'aaaaaa',
|
||||
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
|
||||
'^a^a^a^a^a^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
|
||||
fuzzyScore
|
||||
);
|
||||
});
|
||||
|
||||
test('Freeze when fjfj -> jfjf, https://github.com/microsoft/vscode/issues/91807', function () {
|
||||
assertMatches(
|
||||
'jfjfj',
|
||||
'fjfjfjfjfjfjfjfjfjfjfj',
|
||||
undefined, fuzzyScore
|
||||
);
|
||||
assertMatches(
|
||||
'jfjfjfjfjfjfjfjfjfj',
|
||||
'fjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfj',
|
||||
undefined, fuzzyScore
|
||||
);
|
||||
assertMatches(
|
||||
'jfjfjfjfjfjfjfjfjfjjfjfjfjfjfjfjfjfjfjjfjfjfjfjfjfjfjfjfjjfjfjfjfjfjfjfjfjfjjfjfjfjfjfjfjfjfjfjjfjfjfjfjfjfjfjfjfj',
|
||||
'fjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfj',
|
||||
undefined, fuzzyScore
|
||||
);
|
||||
assertMatches(
|
||||
'jfjfjfjfjfjfjfjfjfj',
|
||||
'fJfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfj',
|
||||
'f^J^f^j^f^j^f^j^f^j^f^j^f^j^f^j^f^j^f^jfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfj', // strong match
|
||||
fuzzyScore
|
||||
);
|
||||
assertMatches(
|
||||
'jfjfjfjfjfjfjfjfjfj',
|
||||
'fjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfj',
|
||||
'f^j^f^j^f^j^f^j^f^j^f^j^f^j^f^j^f^j^f^jfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfjfj', // any match
|
||||
fuzzyScore, { firstMatchCanBeWeak: true }
|
||||
);
|
||||
});
|
||||
|
||||
test('fuzzyScore, issue #26423', function () {
|
||||
|
||||
assertMatches('baba', 'abababab', undefined, fuzzyScore);
|
||||
|
||||
assertMatches(
|
||||
'fsfsfs',
|
||||
'dsafdsafdsafdsafdsafdsafdsafasdfdsa',
|
||||
undefined,
|
||||
fuzzyScore
|
||||
);
|
||||
assertMatches(
|
||||
'fsfsfsfsfsfsfsf',
|
||||
'dsafdsafdsafdsafdsafdsafdsafasdfdsafdsafdsafdsafdsfdsafdsfdfdfasdnfdsajfndsjnafjndsajlknfdsa',
|
||||
undefined,
|
||||
fuzzyScore
|
||||
);
|
||||
});
|
||||
|
||||
test('Fuzzy IntelliSense matching vs Haxe metadata completion, #26995', function () {
|
||||
assertMatches('f', ':Foo', ':^Foo', fuzzyScore);
|
||||
assertMatches('f', ':foo', ':^foo', fuzzyScore);
|
||||
});
|
||||
|
||||
test('Separator only match should not be weak #79558', function () {
|
||||
assertMatches('.', 'foo.bar', 'foo^.bar', fuzzyScore);
|
||||
});
|
||||
|
||||
test('Cannot set property \'1\' of undefined, #26511', function () {
|
||||
let word = new Array<void>(123).join('a');
|
||||
let pattern = new Array<void>(120).join('a');
|
||||
fuzzyScore(pattern, pattern.toLowerCase(), 0, word, word.toLowerCase(), 0, false);
|
||||
assert.ok(true); // must not explode
|
||||
});
|
||||
|
||||
test('Vscode 1.12 no longer obeys \'sortText\' in completion items (from language server), #26096', function () {
|
||||
assertMatches(' ', ' group', undefined, fuzzyScore, { patternPos: 2 });
|
||||
assertMatches(' g', ' group', ' ^group', fuzzyScore, { patternPos: 2 });
|
||||
assertMatches('g', ' group', ' ^group', fuzzyScore);
|
||||
assertMatches('g g', ' groupGroup', undefined, fuzzyScore);
|
||||
assertMatches('g g', ' group Group', ' ^group^ ^Group', fuzzyScore);
|
||||
assertMatches(' g g', ' group Group', ' ^group^ ^Group', fuzzyScore, { patternPos: 1 });
|
||||
assertMatches('zz', 'zzGroup', '^z^zGroup', fuzzyScore);
|
||||
assertMatches('zzg', 'zzGroup', '^z^z^Group', fuzzyScore);
|
||||
assertMatches('g', 'zzGroup', 'zz^Group', fuzzyScore);
|
||||
});
|
||||
|
||||
test('patternPos isn\'t working correctly #79815', function () {
|
||||
assertMatches(':p'.substr(1), 'prop', '^prop', fuzzyScore, { patternPos: 0 });
|
||||
assertMatches(':p', 'prop', '^prop', fuzzyScore, { patternPos: 1 });
|
||||
assertMatches(':p', 'prop', undefined, fuzzyScore, { patternPos: 2 });
|
||||
assertMatches(':p', 'proP', 'pro^P', fuzzyScore, { patternPos: 1, wordPos: 1 });
|
||||
assertMatches(':p', 'aprop', 'a^prop', fuzzyScore, { patternPos: 1, firstMatchCanBeWeak: true });
|
||||
assertMatches(':p', 'aprop', undefined, fuzzyScore, { patternPos: 1, firstMatchCanBeWeak: false });
|
||||
});
|
||||
|
||||
function assertTopScore(filter: typeof fuzzyScore, pattern: string, expected: number, ...words: string[]) {
|
||||
let topScore = -(100 * 10);
|
||||
let topIdx = 0;
|
||||
for (let i = 0; i < words.length; i++) {
|
||||
const word = words[i];
|
||||
const m = filter(pattern, pattern.toLowerCase(), 0, word, word.toLowerCase(), 0, false);
|
||||
if (m) {
|
||||
const [score] = m;
|
||||
if (score > topScore) {
|
||||
topScore = score;
|
||||
topIdx = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert.equal(topIdx, expected, `${pattern} -> actual=${words[topIdx]} <> expected=${words[expected]}`);
|
||||
}
|
||||
|
||||
test('topScore - fuzzyScore', function () {
|
||||
|
||||
assertTopScore(fuzzyScore, 'cons', 2, 'ArrayBufferConstructor', 'Console', 'console');
|
||||
assertTopScore(fuzzyScore, 'Foo', 1, 'foo', 'Foo', 'foo');
|
||||
|
||||
// #24904
|
||||
assertTopScore(fuzzyScore, 'onMess', 1, 'onmessage', 'onMessage', 'onThisMegaEscape');
|
||||
|
||||
assertTopScore(fuzzyScore, 'CC', 1, 'camelCase', 'CamelCase');
|
||||
assertTopScore(fuzzyScore, 'cC', 0, 'camelCase', 'CamelCase');
|
||||
// assertTopScore(fuzzyScore, 'cC', 1, 'ccfoo', 'camelCase');
|
||||
// assertTopScore(fuzzyScore, 'cC', 1, 'ccfoo', 'camelCase', 'foo-cC-bar');
|
||||
|
||||
// issue #17836
|
||||
// assertTopScore(fuzzyScore, 'TEdit', 1, 'TextEditorDecorationType', 'TextEdit', 'TextEditor');
|
||||
assertTopScore(fuzzyScore, 'p', 4, 'parse', 'posix', 'pafdsa', 'path', 'p');
|
||||
assertTopScore(fuzzyScore, 'pa', 0, 'parse', 'pafdsa', 'path');
|
||||
|
||||
// issue #14583
|
||||
assertTopScore(fuzzyScore, 'log', 3, 'HTMLOptGroupElement', 'ScrollLogicalPosition', 'SVGFEMorphologyElement', 'log', 'logger');
|
||||
assertTopScore(fuzzyScore, 'e', 2, 'AbstractWorker', 'ActiveXObject', 'else');
|
||||
|
||||
// issue #14446
|
||||
assertTopScore(fuzzyScore, 'workbench.sideb', 1, 'workbench.editor.defaultSideBySideLayout', 'workbench.sideBar.location');
|
||||
|
||||
// issue #11423
|
||||
assertTopScore(fuzzyScore, 'editor.r', 2, 'diffEditor.renderSideBySide', 'editor.overviewRulerlanes', 'editor.renderControlCharacter', 'editor.renderWhitespace');
|
||||
// assertTopScore(fuzzyScore, 'editor.R', 1, 'diffEditor.renderSideBySide', 'editor.overviewRulerlanes', 'editor.renderControlCharacter', 'editor.renderWhitespace');
|
||||
// assertTopScore(fuzzyScore, 'Editor.r', 0, 'diffEditor.renderSideBySide', 'editor.overviewRulerlanes', 'editor.renderControlCharacter', 'editor.renderWhitespace');
|
||||
|
||||
assertTopScore(fuzzyScore, '-mo', 1, '-ms-ime-mode', '-moz-columns');
|
||||
// // dupe, issue #14861
|
||||
assertTopScore(fuzzyScore, 'convertModelPosition', 0, 'convertModelPositionToViewPosition', 'convertViewToModelPosition');
|
||||
// // dupe, issue #14942
|
||||
assertTopScore(fuzzyScore, 'is', 0, 'isValidViewletId', 'import statement');
|
||||
|
||||
assertTopScore(fuzzyScore, 'title', 1, 'files.trimTrailingWhitespace', 'window.title');
|
||||
|
||||
assertTopScore(fuzzyScore, 'const', 1, 'constructor', 'const', 'cuOnstrul');
|
||||
});
|
||||
|
||||
test('Unexpected suggestion scoring, #28791', function () {
|
||||
assertTopScore(fuzzyScore, '_lines', 1, '_lineStarts', '_lines');
|
||||
assertTopScore(fuzzyScore, '_lines', 1, '_lineS', '_lines');
|
||||
assertTopScore(fuzzyScore, '_lineS', 0, '_lineS', '_lines');
|
||||
});
|
||||
|
||||
test('HTML closing tag proposal filtered out #38880', function () {
|
||||
assertMatches('\t\t<', '\t\t</body>', '^\t^\t^</body>', fuzzyScore, { patternPos: 0 });
|
||||
assertMatches('\t\t<', '\t\t</body>', '\t\t^</body>', fuzzyScore, { patternPos: 2 });
|
||||
assertMatches('\t<', '\t</body>', '\t^</body>', fuzzyScore, { patternPos: 1 });
|
||||
});
|
||||
|
||||
test('fuzzyScoreGraceful', () => {
|
||||
|
||||
assertMatches('rlut', 'result', undefined, fuzzyScore);
|
||||
assertMatches('rlut', 'result', '^res^u^l^t', fuzzyScoreGraceful);
|
||||
|
||||
assertMatches('cno', 'console', '^co^ns^ole', fuzzyScore);
|
||||
assertMatches('cno', 'console', '^co^ns^ole', fuzzyScoreGraceful);
|
||||
assertMatches('cno', 'console', '^c^o^nsole', fuzzyScoreGracefulAggressive);
|
||||
assertMatches('cno', 'co_new', '^c^o_^new', fuzzyScoreGraceful);
|
||||
assertMatches('cno', 'co_new', '^c^o_^new', fuzzyScoreGracefulAggressive);
|
||||
});
|
||||
|
||||
test('List highlight filter: Not all characters from match are highlighterd #66923', () => {
|
||||
assertMatches('foo', 'barbarbarbarbarbarbarbarbarbarbarbarbarbarbarbar_foo', 'barbarbarbarbarbarbarbarbarbarbarbarbarbarbarbar_^f^o^o', fuzzyScore);
|
||||
});
|
||||
|
||||
test('Autocompletion is matched against truncated filterText to 54 characters #74133', () => {
|
||||
assertMatches(
|
||||
'foo',
|
||||
'ffffffffffffffffffffffffffffbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbar_foo',
|
||||
'ffffffffffffffffffffffffffffbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbar_^f^o^o',
|
||||
fuzzyScore
|
||||
);
|
||||
assertMatches(
|
||||
'foo',
|
||||
'Gffffffffffffffffffffffffffffbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbar_foo',
|
||||
undefined,
|
||||
fuzzyScore
|
||||
);
|
||||
});
|
||||
|
||||
test('"Go to Symbol" with the exact method name doesn\'t work as expected #84787', function () {
|
||||
const match = fuzzyScore(':get', ':get', 1, 'get', 'get', 0, true);
|
||||
assert.ok(Boolean(match));
|
||||
});
|
||||
|
||||
test('Suggestion is not highlighted #85826', function () {
|
||||
assertMatches('SemanticTokens', 'SemanticTokensEdits', '^S^e^m^a^n^t^i^c^T^o^k^e^n^sEdits', fuzzyScore);
|
||||
assertMatches('SemanticTokens', 'SemanticTokensEdits', '^S^e^m^a^n^t^i^c^T^o^k^e^n^sEdits', fuzzyScoreGracefulAggressive);
|
||||
});
|
||||
});
|
||||
1208
lib/vscode/src/vs/base/test/common/fuzzyScorer.test.ts
Normal file
1208
lib/vscode/src/vs/base/test/common/fuzzyScorer.test.ts
Normal file
File diff suppressed because it is too large
Load Diff
98
lib/vscode/src/vs/base/test/common/hash.test.ts
Normal file
98
lib/vscode/src/vs/base/test/common/hash.test.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as assert from 'assert';
|
||||
import { hash, StringSHA1 } from 'vs/base/common/hash';
|
||||
|
||||
suite('Hash', () => {
|
||||
test('string', () => {
|
||||
assert.equal(hash('hello'), hash('hello'));
|
||||
assert.notEqual(hash('hello'), hash('world'));
|
||||
assert.notEqual(hash('hello'), hash('olleh'));
|
||||
assert.notEqual(hash('hello'), hash('Hello'));
|
||||
assert.notEqual(hash('hello'), hash('Hello '));
|
||||
assert.notEqual(hash('h'), hash('H'));
|
||||
assert.notEqual(hash('-'), hash('_'));
|
||||
});
|
||||
|
||||
test('number', () => {
|
||||
assert.equal(hash(1), hash(1));
|
||||
assert.notEqual(hash(0), hash(1));
|
||||
assert.notEqual(hash(1), hash(-1));
|
||||
assert.notEqual(hash(0x12345678), hash(0x123456789));
|
||||
});
|
||||
|
||||
test('boolean', () => {
|
||||
assert.equal(hash(true), hash(true));
|
||||
assert.notEqual(hash(true), hash(false));
|
||||
});
|
||||
|
||||
test('array', () => {
|
||||
assert.equal(hash([1, 2, 3]), hash([1, 2, 3]));
|
||||
assert.equal(hash(['foo', 'bar']), hash(['foo', 'bar']));
|
||||
assert.equal(hash([]), hash([]));
|
||||
assert.equal(hash([]), hash(new Array()));
|
||||
assert.notEqual(hash(['foo', 'bar']), hash(['bar', 'foo']));
|
||||
assert.notEqual(hash(['foo', 'bar']), hash(['bar', 'foo', null]));
|
||||
assert.notEqual(hash(['foo', 'bar', null]), hash(['bar', 'foo', null]));
|
||||
assert.notEqual(hash(['foo', 'bar']), hash(['bar', 'foo', undefined]));
|
||||
assert.notEqual(hash(['foo', 'bar', undefined]), hash(['bar', 'foo', undefined]));
|
||||
assert.notEqual(hash(['foo', 'bar', null]), hash(['foo', 'bar', undefined]));
|
||||
});
|
||||
|
||||
test('object', () => {
|
||||
assert.equal(hash({}), hash({}));
|
||||
assert.equal(hash({}), hash(Object.create(null)));
|
||||
assert.equal(hash({ 'foo': 'bar' }), hash({ 'foo': 'bar' }));
|
||||
assert.equal(hash({ 'foo': 'bar', 'foo2': undefined }), hash({ 'foo2': undefined, 'foo': 'bar' }));
|
||||
assert.notEqual(hash({ 'foo': 'bar' }), hash({ 'foo': 'bar2' }));
|
||||
assert.notEqual(hash({}), hash([]));
|
||||
});
|
||||
|
||||
test('array - unexpected collision', function () {
|
||||
const a = hash([undefined, undefined, undefined, undefined, undefined]);
|
||||
const b = hash([undefined, undefined, 'HHHHHH', [{ line: 0, character: 0 }, { line: 0, character: 0 }], undefined]);
|
||||
assert.notEqual(a, b);
|
||||
});
|
||||
|
||||
test('all different', () => {
|
||||
const candidates: any[] = [
|
||||
null, undefined, {}, [], 0, false, true, '', ' ', [null], [undefined], [undefined, undefined], { '': undefined }, { [' ']: undefined },
|
||||
'ab', 'ba', ['ab']
|
||||
];
|
||||
const hashes: number[] = candidates.map(hash);
|
||||
for (let i = 0; i < hashes.length; i++) {
|
||||
assert.equal(hashes[i], hash(candidates[i])); // verify that repeated invocation returns the same hash
|
||||
for (let k = i + 1; k < hashes.length; k++) {
|
||||
assert.notEqual(hashes[i], hashes[k], `Same hash ${hashes[i]} for ${JSON.stringify(candidates[i])} and ${JSON.stringify(candidates[k])}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
function checkSHA1(strings: string[], expected: string) {
|
||||
const hash = new StringSHA1();
|
||||
for (const str of strings) {
|
||||
hash.update(str);
|
||||
}
|
||||
const actual = hash.digest();
|
||||
assert.equal(actual, expected);
|
||||
}
|
||||
|
||||
test('sha1-1', () => {
|
||||
checkSHA1(['\udd56'], '9bdb77276c1852e1fb067820472812fcf6084024');
|
||||
});
|
||||
|
||||
test('sha1-2', () => {
|
||||
checkSHA1(['\udb52'], '9bdb77276c1852e1fb067820472812fcf6084024');
|
||||
});
|
||||
|
||||
test('sha1-3', () => {
|
||||
checkSHA1(['\uda02ꑍ'], '9b483a471f22fe7e09d83f221871a987244bbd3f');
|
||||
});
|
||||
|
||||
test('sha1-4', () => {
|
||||
checkSHA1(['hello'], 'aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d');
|
||||
});
|
||||
});
|
||||
160
lib/vscode/src/vs/base/test/common/history.test.ts
Normal file
160
lib/vscode/src/vs/base/test/common/history.test.ts
Normal file
@@ -0,0 +1,160 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as assert from 'assert';
|
||||
import { HistoryNavigator } from 'vs/base/common/history';
|
||||
|
||||
suite('History Navigator', () => {
|
||||
|
||||
test('create reduces the input to limit', () => {
|
||||
const testObject = new HistoryNavigator(['1', '2', '3', '4'], 2);
|
||||
|
||||
assert.deepEqual(['3', '4'], toArray(testObject));
|
||||
});
|
||||
|
||||
test('create sets the position to last', () => {
|
||||
const testObject = new HistoryNavigator(['1', '2', '3', '4'], 100);
|
||||
|
||||
assert.equal(testObject.current(), null);
|
||||
assert.equal(testObject.next(), null);
|
||||
assert.equal(testObject.previous(), '4');
|
||||
});
|
||||
|
||||
test('last returns last element', () => {
|
||||
const testObject = new HistoryNavigator(['1', '2', '3', '4'], 100);
|
||||
|
||||
assert.equal(testObject.first(), '1');
|
||||
assert.equal(testObject.last(), '4');
|
||||
});
|
||||
|
||||
test('first returns first element', () => {
|
||||
const testObject = new HistoryNavigator(['1', '2', '3', '4'], 3);
|
||||
|
||||
assert.equal('2', testObject.first());
|
||||
});
|
||||
|
||||
test('next returns next element', () => {
|
||||
const testObject = new HistoryNavigator(['1', '2', '3', '4'], 3);
|
||||
|
||||
testObject.first();
|
||||
|
||||
assert.equal(testObject.next(), '3');
|
||||
assert.equal(testObject.next(), '4');
|
||||
assert.equal(testObject.next(), null);
|
||||
});
|
||||
|
||||
test('previous returns previous element', () => {
|
||||
const testObject = new HistoryNavigator(['1', '2', '3', '4'], 3);
|
||||
|
||||
assert.equal(testObject.previous(), '4');
|
||||
assert.equal(testObject.previous(), '3');
|
||||
assert.equal(testObject.previous(), '2');
|
||||
assert.equal(testObject.previous(), null);
|
||||
});
|
||||
|
||||
test('next on last element returs null and remains on last', () => {
|
||||
const testObject = new HistoryNavigator(['1', '2', '3', '4'], 3);
|
||||
|
||||
testObject.first();
|
||||
testObject.last();
|
||||
|
||||
assert.equal(testObject.current(), '4');
|
||||
assert.equal(testObject.next(), null);
|
||||
});
|
||||
|
||||
test('previous on first element returs null and remains on first', () => {
|
||||
const testObject = new HistoryNavigator(['1', '2', '3', '4'], 3);
|
||||
|
||||
testObject.first();
|
||||
|
||||
assert.equal(testObject.current(), '2');
|
||||
assert.equal(testObject.previous(), null);
|
||||
});
|
||||
|
||||
test('add reduces the input to limit', () => {
|
||||
const testObject = new HistoryNavigator(['1', '2', '3', '4'], 2);
|
||||
|
||||
testObject.add('5');
|
||||
|
||||
assert.deepEqual(toArray(testObject), ['4', '5']);
|
||||
});
|
||||
|
||||
test('adding existing element changes the position', () => {
|
||||
const testObject = new HistoryNavigator(['1', '2', '3', '4'], 5);
|
||||
|
||||
testObject.add('2');
|
||||
|
||||
assert.deepEqual(toArray(testObject), ['1', '3', '4', '2']);
|
||||
});
|
||||
|
||||
test('add resets the navigator to last', () => {
|
||||
const testObject = new HistoryNavigator(['1', '2', '3', '4'], 3);
|
||||
|
||||
testObject.first();
|
||||
testObject.add('5');
|
||||
|
||||
assert.equal(testObject.previous(), '5');
|
||||
assert.equal(testObject.next(), null);
|
||||
});
|
||||
|
||||
test('adding an existing item changes the order', () => {
|
||||
const testObject = new HistoryNavigator(['1', '2', '3']);
|
||||
|
||||
testObject.add('1');
|
||||
|
||||
assert.deepEqual(['2', '3', '1'], toArray(testObject));
|
||||
});
|
||||
|
||||
test('previous returns null if the current position is the first one', () => {
|
||||
const testObject = new HistoryNavigator(['1', '2', '3']);
|
||||
|
||||
testObject.first();
|
||||
|
||||
assert.deepEqual(testObject.previous(), null);
|
||||
});
|
||||
|
||||
test('previous returns object if the current position is not the first one', () => {
|
||||
const testObject = new HistoryNavigator(['1', '2', '3']);
|
||||
|
||||
testObject.first();
|
||||
testObject.next();
|
||||
|
||||
assert.deepEqual(testObject.previous(), '1');
|
||||
});
|
||||
|
||||
test('next returns null if the current position is the last one', () => {
|
||||
const testObject = new HistoryNavigator(['1', '2', '3']);
|
||||
|
||||
testObject.last();
|
||||
|
||||
assert.deepEqual(testObject.next(), null);
|
||||
});
|
||||
|
||||
test('next returns object if the current position is not the last one', () => {
|
||||
const testObject = new HistoryNavigator(['1', '2', '3']);
|
||||
|
||||
testObject.last();
|
||||
testObject.previous();
|
||||
|
||||
assert.deepEqual(testObject.next(), '3');
|
||||
});
|
||||
|
||||
test('clear', () => {
|
||||
const testObject = new HistoryNavigator(['a', 'b', 'c']);
|
||||
assert.equal(testObject.previous(), 'c');
|
||||
testObject.clear();
|
||||
assert.equal(testObject.current(), undefined);
|
||||
});
|
||||
|
||||
function toArray(historyNavigator: HistoryNavigator<string>): Array<string | null> {
|
||||
let result: Array<string | null> = [];
|
||||
historyNavigator.first();
|
||||
if (historyNavigator.current()) {
|
||||
do {
|
||||
result.push(historyNavigator.current()!);
|
||||
} while (historyNavigator.next());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
});
|
||||
28
lib/vscode/src/vs/base/test/common/iterator.test.ts
Normal file
28
lib/vscode/src/vs/base/test/common/iterator.test.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { Iterable } from 'vs/base/common/iterator';
|
||||
|
||||
suite('Iterable', function () {
|
||||
|
||||
const customIterable = new class {
|
||||
|
||||
*[Symbol.iterator]() {
|
||||
yield 'one';
|
||||
yield 'two';
|
||||
yield 'three';
|
||||
}
|
||||
};
|
||||
|
||||
test('first', function () {
|
||||
|
||||
assert.equal(Iterable.first([]), undefined);
|
||||
assert.equal(Iterable.first([1]), 1);
|
||||
assert.equal(Iterable.first(customIterable), 'one');
|
||||
assert.equal(Iterable.first(customIterable), 'one'); // fresh
|
||||
});
|
||||
|
||||
});
|
||||
327
lib/vscode/src/vs/base/test/common/json.test.ts
Normal file
327
lib/vscode/src/vs/base/test/common/json.test.ts
Normal file
@@ -0,0 +1,327 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as assert from 'assert';
|
||||
import {
|
||||
SyntaxKind, createScanner, parse, Node, ParseError, parseTree, ParseErrorCode, ParseOptions, ScanError
|
||||
} from 'vs/base/common/json';
|
||||
import { getParseErrorMessage } from 'vs/base/common/jsonErrorMessages';
|
||||
|
||||
function assertKinds(text: string, ...kinds: SyntaxKind[]): void {
|
||||
let scanner = createScanner(text);
|
||||
let kind: SyntaxKind;
|
||||
while ((kind = scanner.scan()) !== SyntaxKind.EOF) {
|
||||
assert.equal(kind, kinds.shift());
|
||||
}
|
||||
assert.equal(kinds.length, 0);
|
||||
}
|
||||
function assertScanError(text: string, expectedKind: SyntaxKind, scanError: ScanError): void {
|
||||
let scanner = createScanner(text);
|
||||
scanner.scan();
|
||||
assert.equal(scanner.getToken(), expectedKind);
|
||||
assert.equal(scanner.getTokenError(), scanError);
|
||||
}
|
||||
|
||||
function assertValidParse(input: string, expected: any, options?: ParseOptions): void {
|
||||
let errors: ParseError[] = [];
|
||||
let actual = parse(input, errors, options);
|
||||
|
||||
if (errors.length !== 0) {
|
||||
assert(false, getParseErrorMessage(errors[0].error));
|
||||
}
|
||||
assert.deepEqual(actual, expected);
|
||||
}
|
||||
|
||||
function assertInvalidParse(input: string, expected: any, options?: ParseOptions): void {
|
||||
let errors: ParseError[] = [];
|
||||
let actual = parse(input, errors, options);
|
||||
|
||||
assert(errors.length > 0);
|
||||
assert.deepEqual(actual, expected);
|
||||
}
|
||||
|
||||
function assertTree(input: string, expected: any, expectedErrors: number[] = [], options?: ParseOptions): void {
|
||||
let errors: ParseError[] = [];
|
||||
let actual = parseTree(input, errors, options);
|
||||
|
||||
assert.deepEqual(errors.map(e => e.error, expected), expectedErrors);
|
||||
let checkParent = (node: Node) => {
|
||||
if (node.children) {
|
||||
for (let child of node.children) {
|
||||
assert.equal(node, child.parent);
|
||||
delete (<any>child).parent; // delete to avoid recursion in deep equal
|
||||
checkParent(child);
|
||||
}
|
||||
}
|
||||
};
|
||||
checkParent(actual);
|
||||
|
||||
assert.deepEqual(actual, expected);
|
||||
}
|
||||
|
||||
suite('JSON', () => {
|
||||
test('tokens', () => {
|
||||
assertKinds('{', SyntaxKind.OpenBraceToken);
|
||||
assertKinds('}', SyntaxKind.CloseBraceToken);
|
||||
assertKinds('[', SyntaxKind.OpenBracketToken);
|
||||
assertKinds(']', SyntaxKind.CloseBracketToken);
|
||||
assertKinds(':', SyntaxKind.ColonToken);
|
||||
assertKinds(',', SyntaxKind.CommaToken);
|
||||
});
|
||||
|
||||
test('comments', () => {
|
||||
assertKinds('// this is a comment', SyntaxKind.LineCommentTrivia);
|
||||
assertKinds('// this is a comment\n', SyntaxKind.LineCommentTrivia, SyntaxKind.LineBreakTrivia);
|
||||
assertKinds('/* this is a comment*/', SyntaxKind.BlockCommentTrivia);
|
||||
assertKinds('/* this is a \r\ncomment*/', SyntaxKind.BlockCommentTrivia);
|
||||
assertKinds('/* this is a \ncomment*/', SyntaxKind.BlockCommentTrivia);
|
||||
|
||||
// unexpected end
|
||||
assertKinds('/* this is a', SyntaxKind.BlockCommentTrivia);
|
||||
assertKinds('/* this is a \ncomment', SyntaxKind.BlockCommentTrivia);
|
||||
|
||||
// broken comment
|
||||
assertKinds('/ ttt', SyntaxKind.Unknown, SyntaxKind.Trivia, SyntaxKind.Unknown);
|
||||
});
|
||||
|
||||
test('strings', () => {
|
||||
assertKinds('"test"', SyntaxKind.StringLiteral);
|
||||
assertKinds('"\\""', SyntaxKind.StringLiteral);
|
||||
assertKinds('"\\/"', SyntaxKind.StringLiteral);
|
||||
assertKinds('"\\b"', SyntaxKind.StringLiteral);
|
||||
assertKinds('"\\f"', SyntaxKind.StringLiteral);
|
||||
assertKinds('"\\n"', SyntaxKind.StringLiteral);
|
||||
assertKinds('"\\r"', SyntaxKind.StringLiteral);
|
||||
assertKinds('"\\t"', SyntaxKind.StringLiteral);
|
||||
assertKinds('"\\v"', SyntaxKind.StringLiteral);
|
||||
assertKinds('"\u88ff"', SyntaxKind.StringLiteral);
|
||||
assertKinds('"\u2028"', SyntaxKind.StringLiteral);
|
||||
|
||||
// unexpected end
|
||||
assertKinds('"test', SyntaxKind.StringLiteral);
|
||||
assertKinds('"test\n"', SyntaxKind.StringLiteral, SyntaxKind.LineBreakTrivia, SyntaxKind.StringLiteral);
|
||||
|
||||
// invalid characters
|
||||
assertScanError('"\t"', SyntaxKind.StringLiteral, ScanError.InvalidCharacter);
|
||||
assertScanError('"\t "', SyntaxKind.StringLiteral, ScanError.InvalidCharacter);
|
||||
});
|
||||
|
||||
test('numbers', () => {
|
||||
assertKinds('0', SyntaxKind.NumericLiteral);
|
||||
assertKinds('0.1', SyntaxKind.NumericLiteral);
|
||||
assertKinds('-0.1', SyntaxKind.NumericLiteral);
|
||||
assertKinds('-1', SyntaxKind.NumericLiteral);
|
||||
assertKinds('1', SyntaxKind.NumericLiteral);
|
||||
assertKinds('123456789', SyntaxKind.NumericLiteral);
|
||||
assertKinds('10', SyntaxKind.NumericLiteral);
|
||||
assertKinds('90', SyntaxKind.NumericLiteral);
|
||||
assertKinds('90E+123', SyntaxKind.NumericLiteral);
|
||||
assertKinds('90e+123', SyntaxKind.NumericLiteral);
|
||||
assertKinds('90e-123', SyntaxKind.NumericLiteral);
|
||||
assertKinds('90E-123', SyntaxKind.NumericLiteral);
|
||||
assertKinds('90E123', SyntaxKind.NumericLiteral);
|
||||
assertKinds('90e123', SyntaxKind.NumericLiteral);
|
||||
|
||||
// zero handling
|
||||
assertKinds('01', SyntaxKind.NumericLiteral, SyntaxKind.NumericLiteral);
|
||||
assertKinds('-01', SyntaxKind.NumericLiteral, SyntaxKind.NumericLiteral);
|
||||
|
||||
// unexpected end
|
||||
assertKinds('-', SyntaxKind.Unknown);
|
||||
assertKinds('.0', SyntaxKind.Unknown);
|
||||
});
|
||||
|
||||
test('keywords: true, false, null', () => {
|
||||
assertKinds('true', SyntaxKind.TrueKeyword);
|
||||
assertKinds('false', SyntaxKind.FalseKeyword);
|
||||
assertKinds('null', SyntaxKind.NullKeyword);
|
||||
|
||||
|
||||
assertKinds('true false null',
|
||||
SyntaxKind.TrueKeyword,
|
||||
SyntaxKind.Trivia,
|
||||
SyntaxKind.FalseKeyword,
|
||||
SyntaxKind.Trivia,
|
||||
SyntaxKind.NullKeyword);
|
||||
|
||||
// invalid words
|
||||
assertKinds('nulllll', SyntaxKind.Unknown);
|
||||
assertKinds('True', SyntaxKind.Unknown);
|
||||
assertKinds('foo-bar', SyntaxKind.Unknown);
|
||||
assertKinds('foo bar', SyntaxKind.Unknown, SyntaxKind.Trivia, SyntaxKind.Unknown);
|
||||
});
|
||||
|
||||
test('trivia', () => {
|
||||
assertKinds(' ', SyntaxKind.Trivia);
|
||||
assertKinds(' \t ', SyntaxKind.Trivia);
|
||||
assertKinds(' \t \n \t ', SyntaxKind.Trivia, SyntaxKind.LineBreakTrivia, SyntaxKind.Trivia);
|
||||
assertKinds('\r\n', SyntaxKind.LineBreakTrivia);
|
||||
assertKinds('\r', SyntaxKind.LineBreakTrivia);
|
||||
assertKinds('\n', SyntaxKind.LineBreakTrivia);
|
||||
assertKinds('\n\r', SyntaxKind.LineBreakTrivia, SyntaxKind.LineBreakTrivia);
|
||||
assertKinds('\n \n', SyntaxKind.LineBreakTrivia, SyntaxKind.Trivia, SyntaxKind.LineBreakTrivia);
|
||||
});
|
||||
|
||||
test('parse: literals', () => {
|
||||
|
||||
assertValidParse('true', true);
|
||||
assertValidParse('false', false);
|
||||
assertValidParse('null', null);
|
||||
assertValidParse('"foo"', 'foo');
|
||||
assertValidParse('"\\"-\\\\-\\/-\\b-\\f-\\n-\\r-\\t"', '"-\\-/-\b-\f-\n-\r-\t');
|
||||
assertValidParse('"\\u00DC"', 'Ü');
|
||||
assertValidParse('9', 9);
|
||||
assertValidParse('-9', -9);
|
||||
assertValidParse('0.129', 0.129);
|
||||
assertValidParse('23e3', 23e3);
|
||||
assertValidParse('1.2E+3', 1.2E+3);
|
||||
assertValidParse('1.2E-3', 1.2E-3);
|
||||
assertValidParse('1.2E-3 // comment', 1.2E-3);
|
||||
});
|
||||
|
||||
test('parse: objects', () => {
|
||||
assertValidParse('{}', {});
|
||||
assertValidParse('{ "foo": true }', { foo: true });
|
||||
assertValidParse('{ "bar": 8, "xoo": "foo" }', { bar: 8, xoo: 'foo' });
|
||||
assertValidParse('{ "hello": [], "world": {} }', { hello: [], world: {} });
|
||||
assertValidParse('{ "a": false, "b": true, "c": [ 7.4 ] }', { a: false, b: true, c: [7.4] });
|
||||
assertValidParse('{ "lineComment": "//", "blockComment": ["/*", "*/"], "brackets": [ ["{", "}"], ["[", "]"], ["(", ")"] ] }', { lineComment: '//', blockComment: ['/*', '*/'], brackets: [['{', '}'], ['[', ']'], ['(', ')']] });
|
||||
assertValidParse('{ "hello": [], "world": {} }', { hello: [], world: {} });
|
||||
assertValidParse('{ "hello": { "again": { "inside": 5 }, "world": 1 }}', { hello: { again: { inside: 5 }, world: 1 } });
|
||||
assertValidParse('{ "foo": /*hello*/true }', { foo: true });
|
||||
});
|
||||
|
||||
test('parse: arrays', () => {
|
||||
assertValidParse('[]', []);
|
||||
assertValidParse('[ [], [ [] ]]', [[], [[]]]);
|
||||
assertValidParse('[ 1, 2, 3 ]', [1, 2, 3]);
|
||||
assertValidParse('[ { "a": null } ]', [{ a: null }]);
|
||||
});
|
||||
|
||||
test('parse: objects with errors', () => {
|
||||
assertInvalidParse('{,}', {});
|
||||
assertInvalidParse('{ "foo": true, }', { foo: true }, { allowTrailingComma: false });
|
||||
assertInvalidParse('{ "bar": 8 "xoo": "foo" }', { bar: 8, xoo: 'foo' });
|
||||
assertInvalidParse('{ ,"bar": 8 }', { bar: 8 });
|
||||
assertInvalidParse('{ ,"bar": 8, "foo" }', { bar: 8 });
|
||||
assertInvalidParse('{ "bar": 8, "foo": }', { bar: 8 });
|
||||
assertInvalidParse('{ 8, "foo": 9 }', { foo: 9 });
|
||||
});
|
||||
|
||||
test('parse: array with errors', () => {
|
||||
assertInvalidParse('[,]', []);
|
||||
assertInvalidParse('[ 1, 2, ]', [1, 2], { allowTrailingComma: false });
|
||||
assertInvalidParse('[ 1 2, 3 ]', [1, 2, 3]);
|
||||
assertInvalidParse('[ ,1, 2, 3 ]', [1, 2, 3]);
|
||||
assertInvalidParse('[ ,1, 2, 3, ]', [1, 2, 3], { allowTrailingComma: false });
|
||||
});
|
||||
|
||||
test('parse: disallow commments', () => {
|
||||
let options = { disallowComments: true };
|
||||
|
||||
assertValidParse('[ 1, 2, null, "foo" ]', [1, 2, null, 'foo'], options);
|
||||
assertValidParse('{ "hello": [], "world": {} }', { hello: [], world: {} }, options);
|
||||
|
||||
assertInvalidParse('{ "foo": /*comment*/ true }', { foo: true }, options);
|
||||
});
|
||||
|
||||
test('parse: trailing comma', () => {
|
||||
// default is allow
|
||||
assertValidParse('{ "hello": [], }', { hello: [] });
|
||||
|
||||
let options = { allowTrailingComma: true };
|
||||
assertValidParse('{ "hello": [], }', { hello: [] }, options);
|
||||
assertValidParse('{ "hello": [] }', { hello: [] }, options);
|
||||
assertValidParse('{ "hello": [], "world": {}, }', { hello: [], world: {} }, options);
|
||||
assertValidParse('{ "hello": [], "world": {} }', { hello: [], world: {} }, options);
|
||||
assertValidParse('{ "hello": [1,] }', { hello: [1] }, options);
|
||||
|
||||
options = { allowTrailingComma: false };
|
||||
assertInvalidParse('{ "hello": [], }', { hello: [] }, options);
|
||||
assertInvalidParse('{ "hello": [], "world": {}, }', { hello: [], world: {} }, options);
|
||||
});
|
||||
|
||||
test('tree: literals', () => {
|
||||
assertTree('true', { type: 'boolean', offset: 0, length: 4, value: true });
|
||||
assertTree('false', { type: 'boolean', offset: 0, length: 5, value: false });
|
||||
assertTree('null', { type: 'null', offset: 0, length: 4, value: null });
|
||||
assertTree('23', { type: 'number', offset: 0, length: 2, value: 23 });
|
||||
assertTree('-1.93e-19', { type: 'number', offset: 0, length: 9, value: -1.93e-19 });
|
||||
assertTree('"hello"', { type: 'string', offset: 0, length: 7, value: 'hello' });
|
||||
});
|
||||
|
||||
test('tree: arrays', () => {
|
||||
assertTree('[]', { type: 'array', offset: 0, length: 2, children: [] });
|
||||
assertTree('[ 1 ]', { type: 'array', offset: 0, length: 5, children: [{ type: 'number', offset: 2, length: 1, value: 1 }] });
|
||||
assertTree('[ 1,"x"]', {
|
||||
type: 'array', offset: 0, length: 8, children: [
|
||||
{ type: 'number', offset: 2, length: 1, value: 1 },
|
||||
{ type: 'string', offset: 4, length: 3, value: 'x' }
|
||||
]
|
||||
});
|
||||
assertTree('[[]]', {
|
||||
type: 'array', offset: 0, length: 4, children: [
|
||||
{ type: 'array', offset: 1, length: 2, children: [] }
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
test('tree: objects', () => {
|
||||
assertTree('{ }', { type: 'object', offset: 0, length: 3, children: [] });
|
||||
assertTree('{ "val": 1 }', {
|
||||
type: 'object', offset: 0, length: 12, children: [
|
||||
{
|
||||
type: 'property', offset: 2, length: 8, colonOffset: 7, children: [
|
||||
{ type: 'string', offset: 2, length: 5, value: 'val' },
|
||||
{ type: 'number', offset: 9, length: 1, value: 1 }
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
assertTree('{"id": "$", "v": [ null, null] }',
|
||||
{
|
||||
type: 'object', offset: 0, length: 32, children: [
|
||||
{
|
||||
type: 'property', offset: 1, length: 9, colonOffset: 5, children: [
|
||||
{ type: 'string', offset: 1, length: 4, value: 'id' },
|
||||
{ type: 'string', offset: 7, length: 3, value: '$' }
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'property', offset: 12, length: 18, colonOffset: 15, children: [
|
||||
{ type: 'string', offset: 12, length: 3, value: 'v' },
|
||||
{
|
||||
type: 'array', offset: 17, length: 13, children: [
|
||||
{ type: 'null', offset: 19, length: 4, value: null },
|
||||
{ type: 'null', offset: 25, length: 4, value: null }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
);
|
||||
assertTree('{ "id": { "foo": { } } , }',
|
||||
{
|
||||
type: 'object', offset: 0, length: 27, children: [
|
||||
{
|
||||
type: 'property', offset: 3, length: 20, colonOffset: 7, children: [
|
||||
{ type: 'string', offset: 3, length: 4, value: 'id' },
|
||||
{
|
||||
type: 'object', offset: 9, length: 14, children: [
|
||||
{
|
||||
type: 'property', offset: 11, length: 10, colonOffset: 16, children: [
|
||||
{ type: 'string', offset: 11, length: 5, value: 'foo' },
|
||||
{ type: 'object', offset: 18, length: 3, children: [] }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
, [ParseErrorCode.PropertyNameExpected, ParseErrorCode.ValueExpected], { allowTrailingComma: false });
|
||||
});
|
||||
});
|
||||
193
lib/vscode/src/vs/base/test/common/jsonEdit.test.ts
Normal file
193
lib/vscode/src/vs/base/test/common/jsonEdit.test.ts
Normal file
@@ -0,0 +1,193 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { FormattingOptions, Edit } from 'vs/base/common/jsonFormatter';
|
||||
import { setProperty, removeProperty } from 'vs/base/common/jsonEdit';
|
||||
import * as assert from 'assert';
|
||||
|
||||
suite('JSON - edits', () => {
|
||||
|
||||
function assertEdit(content: string, edits: Edit[], expected: string) {
|
||||
assert(edits);
|
||||
let lastEditOffset = content.length;
|
||||
for (let i = edits.length - 1; i >= 0; i--) {
|
||||
let edit = edits[i];
|
||||
assert(edit.offset >= 0 && edit.length >= 0 && edit.offset + edit.length <= content.length);
|
||||
assert(typeof edit.content === 'string');
|
||||
assert(lastEditOffset >= edit.offset + edit.length); // make sure all edits are ordered
|
||||
lastEditOffset = edit.offset;
|
||||
content = content.substring(0, edit.offset) + edit.content + content.substring(edit.offset + edit.length);
|
||||
}
|
||||
assert.equal(content, expected);
|
||||
}
|
||||
|
||||
let formatterOptions: FormattingOptions = {
|
||||
insertSpaces: true,
|
||||
tabSize: 2,
|
||||
eol: '\n'
|
||||
};
|
||||
|
||||
test('set property', () => {
|
||||
let content = '{\n "x": "y"\n}';
|
||||
let edits = setProperty(content, ['x'], 'bar', formatterOptions);
|
||||
assertEdit(content, edits, '{\n "x": "bar"\n}');
|
||||
|
||||
content = 'true';
|
||||
edits = setProperty(content, [], 'bar', formatterOptions);
|
||||
assertEdit(content, edits, '"bar"');
|
||||
|
||||
content = '{\n "x": "y"\n}';
|
||||
edits = setProperty(content, ['x'], { key: true }, formatterOptions);
|
||||
assertEdit(content, edits, '{\n "x": {\n "key": true\n }\n}');
|
||||
content = '{\n "a": "b", "x": "y"\n}';
|
||||
edits = setProperty(content, ['a'], null, formatterOptions);
|
||||
assertEdit(content, edits, '{\n "a": null, "x": "y"\n}');
|
||||
});
|
||||
|
||||
test('insert property', () => {
|
||||
let content = '{}';
|
||||
let edits = setProperty(content, ['foo'], 'bar', formatterOptions);
|
||||
assertEdit(content, edits, '{\n "foo": "bar"\n}');
|
||||
|
||||
edits = setProperty(content, ['foo', 'foo2'], 'bar', formatterOptions);
|
||||
assertEdit(content, edits, '{\n "foo": {\n "foo2": "bar"\n }\n}');
|
||||
|
||||
content = '{\n}';
|
||||
edits = setProperty(content, ['foo'], 'bar', formatterOptions);
|
||||
assertEdit(content, edits, '{\n "foo": "bar"\n}');
|
||||
|
||||
content = ' {\n }';
|
||||
edits = setProperty(content, ['foo'], 'bar', formatterOptions);
|
||||
assertEdit(content, edits, ' {\n "foo": "bar"\n }');
|
||||
|
||||
content = '{\n "x": "y"\n}';
|
||||
edits = setProperty(content, ['foo'], 'bar', formatterOptions);
|
||||
assertEdit(content, edits, '{\n "x": "y",\n "foo": "bar"\n}');
|
||||
|
||||
content = '{\n "x": "y"\n}';
|
||||
edits = setProperty(content, ['e'], 'null', formatterOptions);
|
||||
assertEdit(content, edits, '{\n "x": "y",\n "e": "null"\n}');
|
||||
|
||||
edits = setProperty(content, ['x'], 'bar', formatterOptions);
|
||||
assertEdit(content, edits, '{\n "x": "bar"\n}');
|
||||
|
||||
content = '{\n "x": {\n "a": 1,\n "b": true\n }\n}\n';
|
||||
edits = setProperty(content, ['x'], 'bar', formatterOptions);
|
||||
assertEdit(content, edits, '{\n "x": "bar"\n}\n');
|
||||
|
||||
edits = setProperty(content, ['x', 'b'], 'bar', formatterOptions);
|
||||
assertEdit(content, edits, '{\n "x": {\n "a": 1,\n "b": "bar"\n }\n}\n');
|
||||
|
||||
edits = setProperty(content, ['x', 'c'], 'bar', formatterOptions, () => 0);
|
||||
assertEdit(content, edits, '{\n "x": {\n "c": "bar",\n "a": 1,\n "b": true\n }\n}\n');
|
||||
|
||||
edits = setProperty(content, ['x', 'c'], 'bar', formatterOptions, () => 1);
|
||||
assertEdit(content, edits, '{\n "x": {\n "a": 1,\n "c": "bar",\n "b": true\n }\n}\n');
|
||||
|
||||
edits = setProperty(content, ['x', 'c'], 'bar', formatterOptions, () => 2);
|
||||
assertEdit(content, edits, '{\n "x": {\n "a": 1,\n "b": true,\n "c": "bar"\n }\n}\n');
|
||||
|
||||
edits = setProperty(content, ['c'], 'bar', formatterOptions);
|
||||
assertEdit(content, edits, '{\n "x": {\n "a": 1,\n "b": true\n },\n "c": "bar"\n}\n');
|
||||
|
||||
content = '{\n "a": [\n {\n } \n ] \n}';
|
||||
edits = setProperty(content, ['foo'], 'bar', formatterOptions);
|
||||
assertEdit(content, edits, '{\n "a": [\n {\n } \n ],\n "foo": "bar"\n}');
|
||||
|
||||
content = '';
|
||||
edits = setProperty(content, ['foo', 0], 'bar', formatterOptions);
|
||||
assertEdit(content, edits, '{\n "foo": [\n "bar"\n ]\n}');
|
||||
|
||||
content = '//comment';
|
||||
edits = setProperty(content, ['foo', 0], 'bar', formatterOptions);
|
||||
assertEdit(content, edits, '{\n "foo": [\n "bar"\n ]\n} //comment');
|
||||
});
|
||||
|
||||
test('remove property', () => {
|
||||
let content = '{\n "x": "y"\n}';
|
||||
let edits = removeProperty(content, ['x'], formatterOptions);
|
||||
assertEdit(content, edits, '{\n}');
|
||||
|
||||
content = '{\n "x": "y", "a": []\n}';
|
||||
edits = removeProperty(content, ['x'], formatterOptions);
|
||||
assertEdit(content, edits, '{\n "a": []\n}');
|
||||
|
||||
content = '{\n "x": "y", "a": []\n}';
|
||||
edits = removeProperty(content, ['a'], formatterOptions);
|
||||
assertEdit(content, edits, '{\n "x": "y"\n}');
|
||||
});
|
||||
|
||||
test('insert item at 0', () => {
|
||||
let content = '[\n 2,\n 3\n]';
|
||||
let edits = setProperty(content, [0], 1, formatterOptions);
|
||||
assertEdit(content, edits, '[\n 1,\n 2,\n 3\n]');
|
||||
});
|
||||
|
||||
test('insert item at 0 in empty array', () => {
|
||||
let content = '[\n]';
|
||||
let edits = setProperty(content, [0], 1, formatterOptions);
|
||||
assertEdit(content, edits, '[\n 1\n]');
|
||||
});
|
||||
|
||||
test('insert item at an index', () => {
|
||||
let content = '[\n 1,\n 3\n]';
|
||||
let edits = setProperty(content, [1], 2, formatterOptions);
|
||||
assertEdit(content, edits, '[\n 1,\n 2,\n 3\n]');
|
||||
});
|
||||
|
||||
test('insert item at an index im empty array', () => {
|
||||
let content = '[\n]';
|
||||
let edits = setProperty(content, [1], 1, formatterOptions);
|
||||
assertEdit(content, edits, '[\n 1\n]');
|
||||
});
|
||||
|
||||
test('insert item at end index', () => {
|
||||
let content = '[\n 1,\n 2\n]';
|
||||
let edits = setProperty(content, [2], 3, formatterOptions);
|
||||
assertEdit(content, edits, '[\n 1,\n 2,\n 3\n]');
|
||||
});
|
||||
|
||||
test('insert item at end to empty array', () => {
|
||||
let content = '[\n]';
|
||||
let edits = setProperty(content, [-1], 'bar', formatterOptions);
|
||||
assertEdit(content, edits, '[\n "bar"\n]');
|
||||
});
|
||||
|
||||
test('insert item at end', () => {
|
||||
let content = '[\n 1,\n 2\n]';
|
||||
let edits = setProperty(content, [-1], 'bar', formatterOptions);
|
||||
assertEdit(content, edits, '[\n 1,\n 2,\n "bar"\n]');
|
||||
});
|
||||
|
||||
test('remove item in array with one item', () => {
|
||||
let content = '[\n 1\n]';
|
||||
let edits = setProperty(content, [0], undefined, formatterOptions);
|
||||
assertEdit(content, edits, '[]');
|
||||
});
|
||||
|
||||
test('remove item in the middle of the array', () => {
|
||||
let content = '[\n 1,\n 2,\n 3\n]';
|
||||
let edits = setProperty(content, [1], undefined, formatterOptions);
|
||||
assertEdit(content, edits, '[\n 1,\n 3\n]');
|
||||
});
|
||||
|
||||
test('remove last item in the array', () => {
|
||||
let content = '[\n 1,\n 2,\n "bar"\n]';
|
||||
let edits = setProperty(content, [2], undefined, formatterOptions);
|
||||
assertEdit(content, edits, '[\n 1,\n 2\n]');
|
||||
});
|
||||
|
||||
test('remove last item in the array if ends with comma', () => {
|
||||
let content = '[\n 1,\n "foo",\n "bar",\n]';
|
||||
let edits = setProperty(content, [2], undefined, formatterOptions);
|
||||
assertEdit(content, edits, '[\n 1,\n "foo"\n]');
|
||||
});
|
||||
|
||||
test('remove last item in the array if there is a comment in the beginning', () => {
|
||||
let content = '// This is a comment\n[\n 1,\n "foo",\n "bar"\n]';
|
||||
let edits = setProperty(content, [2], undefined, formatterOptions);
|
||||
assertEdit(content, edits, '// This is a comment\n[\n 1,\n "foo"\n]');
|
||||
});
|
||||
|
||||
});
|
||||
441
lib/vscode/src/vs/base/test/common/jsonFormatter.test.ts
Normal file
441
lib/vscode/src/vs/base/test/common/jsonFormatter.test.ts
Normal file
@@ -0,0 +1,441 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as Formatter from 'vs/base/common/jsonFormatter';
|
||||
import * as assert from 'assert';
|
||||
|
||||
suite('JSON - formatter', () => {
|
||||
|
||||
function format(content: string, expected: string, insertSpaces = true) {
|
||||
let range: Formatter.Range | undefined = undefined;
|
||||
const rangeStart = content.indexOf('|');
|
||||
const rangeEnd = content.lastIndexOf('|');
|
||||
if (rangeStart !== -1 && rangeEnd !== -1) {
|
||||
content = content.substring(0, rangeStart) + content.substring(rangeStart + 1, rangeEnd) + content.substring(rangeEnd + 1);
|
||||
range = { offset: rangeStart, length: rangeEnd - rangeStart };
|
||||
}
|
||||
|
||||
const edits = Formatter.format(content, range, { tabSize: 2, insertSpaces: insertSpaces, eol: '\n' });
|
||||
|
||||
let lastEditOffset = content.length;
|
||||
for (let i = edits.length - 1; i >= 0; i--) {
|
||||
let edit = edits[i];
|
||||
assert(edit.offset >= 0 && edit.length >= 0 && edit.offset + edit.length <= content.length);
|
||||
assert(typeof edit.content === 'string');
|
||||
assert(lastEditOffset >= edit.offset + edit.length); // make sure all edits are ordered
|
||||
lastEditOffset = edit.offset;
|
||||
content = content.substring(0, edit.offset) + edit.content + content.substring(edit.offset + edit.length);
|
||||
}
|
||||
|
||||
assert.equal(content, expected);
|
||||
}
|
||||
|
||||
test('object - single property', () => {
|
||||
const content = [
|
||||
'{"x" : 1}'
|
||||
].join('\n');
|
||||
|
||||
const expected = [
|
||||
'{',
|
||||
' "x": 1',
|
||||
'}'
|
||||
].join('\n');
|
||||
|
||||
format(content, expected);
|
||||
});
|
||||
test('object - multiple properties', () => {
|
||||
const content = [
|
||||
'{"x" : 1, "y" : "foo", "z" : true}'
|
||||
].join('\n');
|
||||
|
||||
const expected = [
|
||||
'{',
|
||||
' "x": 1,',
|
||||
' "y": "foo",',
|
||||
' "z": true',
|
||||
'}'
|
||||
].join('\n');
|
||||
|
||||
format(content, expected);
|
||||
});
|
||||
test('object - no properties ', () => {
|
||||
const content = [
|
||||
'{"x" : { }, "y" : {}}'
|
||||
].join('\n');
|
||||
|
||||
const expected = [
|
||||
'{',
|
||||
' "x": {},',
|
||||
' "y": {}',
|
||||
'}'
|
||||
].join('\n');
|
||||
|
||||
format(content, expected);
|
||||
});
|
||||
test('object - nesting', () => {
|
||||
const content = [
|
||||
'{"x" : { "y" : { "z" : { }}, "a": true}}'
|
||||
].join('\n');
|
||||
|
||||
const expected = [
|
||||
'{',
|
||||
' "x": {',
|
||||
' "y": {',
|
||||
' "z": {}',
|
||||
' },',
|
||||
' "a": true',
|
||||
' }',
|
||||
'}'
|
||||
].join('\n');
|
||||
|
||||
format(content, expected);
|
||||
});
|
||||
|
||||
test('array - single items', () => {
|
||||
const content = [
|
||||
'["[]"]'
|
||||
].join('\n');
|
||||
|
||||
const expected = [
|
||||
'[',
|
||||
' "[]"',
|
||||
']'
|
||||
].join('\n');
|
||||
|
||||
format(content, expected);
|
||||
});
|
||||
|
||||
test('array - multiple items', () => {
|
||||
const content = [
|
||||
'[true,null,1.2]'
|
||||
].join('\n');
|
||||
|
||||
const expected = [
|
||||
'[',
|
||||
' true,',
|
||||
' null,',
|
||||
' 1.2',
|
||||
']'
|
||||
].join('\n');
|
||||
|
||||
format(content, expected);
|
||||
});
|
||||
|
||||
test('array - no items', () => {
|
||||
const content = [
|
||||
'[ ]'
|
||||
].join('\n');
|
||||
|
||||
const expected = [
|
||||
'[]'
|
||||
].join('\n');
|
||||
|
||||
format(content, expected);
|
||||
});
|
||||
|
||||
test('array - nesting', () => {
|
||||
const content = [
|
||||
'[ [], [ [ {} ], "a" ] ]'
|
||||
].join('\n');
|
||||
|
||||
const expected = [
|
||||
'[',
|
||||
' [],',
|
||||
' [',
|
||||
' [',
|
||||
' {}',
|
||||
' ],',
|
||||
' "a"',
|
||||
' ]',
|
||||
']',
|
||||
].join('\n');
|
||||
|
||||
format(content, expected);
|
||||
});
|
||||
|
||||
test('syntax errors', () => {
|
||||
const content = [
|
||||
'[ null 1.2 ]'
|
||||
].join('\n');
|
||||
|
||||
const expected = [
|
||||
'[',
|
||||
' null 1.2',
|
||||
']',
|
||||
].join('\n');
|
||||
|
||||
format(content, expected);
|
||||
});
|
||||
|
||||
test('empty lines', () => {
|
||||
const content = [
|
||||
'{',
|
||||
'"a": true,',
|
||||
'',
|
||||
'"b": true',
|
||||
'}',
|
||||
].join('\n');
|
||||
|
||||
const expected = [
|
||||
'{',
|
||||
'\t"a": true,',
|
||||
'\t"b": true',
|
||||
'}',
|
||||
].join('\n');
|
||||
|
||||
format(content, expected, false);
|
||||
});
|
||||
test('single line comment', () => {
|
||||
const content = [
|
||||
'[ ',
|
||||
'//comment',
|
||||
'"foo", "bar"',
|
||||
'] '
|
||||
].join('\n');
|
||||
|
||||
const expected = [
|
||||
'[',
|
||||
' //comment',
|
||||
' "foo",',
|
||||
' "bar"',
|
||||
']',
|
||||
].join('\n');
|
||||
|
||||
format(content, expected);
|
||||
});
|
||||
test('block line comment', () => {
|
||||
const content = [
|
||||
'[{',
|
||||
' /*comment*/ ',
|
||||
'"foo" : true',
|
||||
'}] '
|
||||
].join('\n');
|
||||
|
||||
const expected = [
|
||||
'[',
|
||||
' {',
|
||||
' /*comment*/',
|
||||
' "foo": true',
|
||||
' }',
|
||||
']',
|
||||
].join('\n');
|
||||
|
||||
format(content, expected);
|
||||
});
|
||||
test('single line comment on same line', () => {
|
||||
const content = [
|
||||
' { ',
|
||||
' "a": {}// comment ',
|
||||
' } '
|
||||
].join('\n');
|
||||
|
||||
const expected = [
|
||||
'{',
|
||||
' "a": {} // comment ',
|
||||
'}',
|
||||
].join('\n');
|
||||
|
||||
format(content, expected);
|
||||
});
|
||||
test('single line comment on same line 2', () => {
|
||||
const content = [
|
||||
'{ //comment',
|
||||
'}'
|
||||
].join('\n');
|
||||
|
||||
const expected = [
|
||||
'{ //comment',
|
||||
'}'
|
||||
].join('\n');
|
||||
|
||||
format(content, expected);
|
||||
});
|
||||
test('block comment on same line', () => {
|
||||
const content = [
|
||||
'{ "a": {}, /*comment*/ ',
|
||||
' /*comment*/ "b": {}, ',
|
||||
' "c": {/*comment*/} } ',
|
||||
].join('\n');
|
||||
|
||||
const expected = [
|
||||
'{',
|
||||
' "a": {}, /*comment*/',
|
||||
' /*comment*/ "b": {},',
|
||||
' "c": { /*comment*/}',
|
||||
'}',
|
||||
].join('\n');
|
||||
|
||||
format(content, expected);
|
||||
});
|
||||
|
||||
test('block comment on same line advanced', () => {
|
||||
const content = [
|
||||
' { "d": [',
|
||||
' null',
|
||||
' ] /*comment*/',
|
||||
' ,"e": /*comment*/ [null] }',
|
||||
].join('\n');
|
||||
|
||||
const expected = [
|
||||
'{',
|
||||
' "d": [',
|
||||
' null',
|
||||
' ] /*comment*/,',
|
||||
' "e": /*comment*/ [',
|
||||
' null',
|
||||
' ]',
|
||||
'}',
|
||||
].join('\n');
|
||||
|
||||
format(content, expected);
|
||||
});
|
||||
|
||||
test('multiple block comments on same line', () => {
|
||||
const content = [
|
||||
'{ "a": {} /*comment*/, /*comment*/ ',
|
||||
' /*comment*/ "b": {} /*comment*/ } '
|
||||
].join('\n');
|
||||
|
||||
const expected = [
|
||||
'{',
|
||||
' "a": {} /*comment*/, /*comment*/',
|
||||
' /*comment*/ "b": {} /*comment*/',
|
||||
'}',
|
||||
].join('\n');
|
||||
|
||||
format(content, expected);
|
||||
});
|
||||
test('multiple mixed comments on same line', () => {
|
||||
const content = [
|
||||
'[ /*comment*/ /*comment*/ // comment ',
|
||||
']'
|
||||
].join('\n');
|
||||
|
||||
const expected = [
|
||||
'[ /*comment*/ /*comment*/ // comment ',
|
||||
']'
|
||||
].join('\n');
|
||||
|
||||
format(content, expected);
|
||||
});
|
||||
|
||||
test('range', () => {
|
||||
const content = [
|
||||
'{ "a": {},',
|
||||
'|"b": [null, null]|',
|
||||
'} '
|
||||
].join('\n');
|
||||
|
||||
const expected = [
|
||||
'{ "a": {},',
|
||||
'"b": [',
|
||||
' null,',
|
||||
' null',
|
||||
']',
|
||||
'} ',
|
||||
].join('\n');
|
||||
|
||||
format(content, expected);
|
||||
});
|
||||
|
||||
test('range with existing indent', () => {
|
||||
const content = [
|
||||
'{ "a": {},',
|
||||
' |"b": [null],',
|
||||
'"c": {}',
|
||||
'}|'
|
||||
].join('\n');
|
||||
|
||||
const expected = [
|
||||
'{ "a": {},',
|
||||
' "b": [',
|
||||
' null',
|
||||
' ],',
|
||||
' "c": {}',
|
||||
'}',
|
||||
].join('\n');
|
||||
|
||||
format(content, expected);
|
||||
});
|
||||
|
||||
test('range with existing indent - tabs', () => {
|
||||
const content = [
|
||||
'{ "a": {},',
|
||||
'| "b": [null], ',
|
||||
'"c": {}',
|
||||
'} | '
|
||||
].join('\n');
|
||||
|
||||
const expected = [
|
||||
'{ "a": {},',
|
||||
'\t"b": [',
|
||||
'\t\tnull',
|
||||
'\t],',
|
||||
'\t"c": {}',
|
||||
'}',
|
||||
].join('\n');
|
||||
|
||||
format(content, expected, false);
|
||||
});
|
||||
|
||||
|
||||
test('block comment none-line breaking symbols', () => {
|
||||
const content = [
|
||||
'{ "a": [ 1',
|
||||
'/* comment */',
|
||||
', 2',
|
||||
'/* comment */',
|
||||
']',
|
||||
'/* comment */',
|
||||
',',
|
||||
' "b": true',
|
||||
'/* comment */',
|
||||
'}'
|
||||
].join('\n');
|
||||
|
||||
const expected = [
|
||||
'{',
|
||||
' "a": [',
|
||||
' 1',
|
||||
' /* comment */',
|
||||
' ,',
|
||||
' 2',
|
||||
' /* comment */',
|
||||
' ]',
|
||||
' /* comment */',
|
||||
' ,',
|
||||
' "b": true',
|
||||
' /* comment */',
|
||||
'}',
|
||||
].join('\n');
|
||||
|
||||
format(content, expected);
|
||||
});
|
||||
test('line comment after none-line breaking symbols', () => {
|
||||
const content = [
|
||||
'{ "a":',
|
||||
'// comment',
|
||||
'null,',
|
||||
' "b"',
|
||||
'// comment',
|
||||
': null',
|
||||
'// comment',
|
||||
'}'
|
||||
].join('\n');
|
||||
|
||||
const expected = [
|
||||
'{',
|
||||
' "a":',
|
||||
' // comment',
|
||||
' null,',
|
||||
' "b"',
|
||||
' // comment',
|
||||
' : null',
|
||||
' // comment',
|
||||
'}',
|
||||
].join('\n');
|
||||
|
||||
format(content, expected);
|
||||
});
|
||||
});
|
||||
99
lib/vscode/src/vs/base/test/common/keyCodes.test.ts
Normal file
99
lib/vscode/src/vs/base/test/common/keyCodes.test.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { ChordKeybinding, KeyChord, KeyCode, KeyMod, Keybinding, SimpleKeybinding, createKeybinding } from 'vs/base/common/keyCodes';
|
||||
import { OperatingSystem } from 'vs/base/common/platform';
|
||||
|
||||
suite('keyCodes', () => {
|
||||
|
||||
function testBinaryEncoding(expected: Keybinding | null, k: number, OS: OperatingSystem): void {
|
||||
assert.deepEqual(createKeybinding(k, OS), expected);
|
||||
}
|
||||
|
||||
test('MAC binary encoding', () => {
|
||||
|
||||
function test(expected: Keybinding | null, k: number): void {
|
||||
testBinaryEncoding(expected, k, OperatingSystem.Macintosh);
|
||||
}
|
||||
|
||||
test(null, 0);
|
||||
test(new SimpleKeybinding(false, false, false, false, KeyCode.Enter).toChord(), KeyCode.Enter);
|
||||
test(new SimpleKeybinding(true, false, false, false, KeyCode.Enter).toChord(), KeyMod.WinCtrl | KeyCode.Enter);
|
||||
test(new SimpleKeybinding(false, false, true, false, KeyCode.Enter).toChord(), KeyMod.Alt | KeyCode.Enter);
|
||||
test(new SimpleKeybinding(true, false, true, false, KeyCode.Enter).toChord(), KeyMod.Alt | KeyMod.WinCtrl | KeyCode.Enter);
|
||||
test(new SimpleKeybinding(false, true, false, false, KeyCode.Enter).toChord(), KeyMod.Shift | KeyCode.Enter);
|
||||
test(new SimpleKeybinding(true, true, false, false, KeyCode.Enter).toChord(), KeyMod.Shift | KeyMod.WinCtrl | KeyCode.Enter);
|
||||
test(new SimpleKeybinding(false, true, true, false, KeyCode.Enter).toChord(), KeyMod.Shift | KeyMod.Alt | KeyCode.Enter);
|
||||
test(new SimpleKeybinding(true, true, true, false, KeyCode.Enter).toChord(), KeyMod.Shift | KeyMod.Alt | KeyMod.WinCtrl | KeyCode.Enter);
|
||||
test(new SimpleKeybinding(false, false, false, true, KeyCode.Enter).toChord(), KeyMod.CtrlCmd | KeyCode.Enter);
|
||||
test(new SimpleKeybinding(true, false, false, true, KeyCode.Enter).toChord(), KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.Enter);
|
||||
test(new SimpleKeybinding(false, false, true, true, KeyCode.Enter).toChord(), KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.Enter);
|
||||
test(new SimpleKeybinding(true, false, true, true, KeyCode.Enter).toChord(), KeyMod.CtrlCmd | KeyMod.Alt | KeyMod.WinCtrl | KeyCode.Enter);
|
||||
test(new SimpleKeybinding(false, true, false, true, KeyCode.Enter).toChord(), KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Enter);
|
||||
test(new SimpleKeybinding(true, true, false, true, KeyCode.Enter).toChord(), KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.WinCtrl | KeyCode.Enter);
|
||||
test(new SimpleKeybinding(false, true, true, true, KeyCode.Enter).toChord(), KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.Enter);
|
||||
test(new SimpleKeybinding(true, true, true, true, KeyCode.Enter).toChord(), KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyMod.WinCtrl | KeyCode.Enter);
|
||||
|
||||
test(
|
||||
new ChordKeybinding([
|
||||
new SimpleKeybinding(false, false, false, false, KeyCode.Enter),
|
||||
new SimpleKeybinding(false, false, false, false, KeyCode.Tab)
|
||||
]),
|
||||
KeyChord(KeyCode.Enter, KeyCode.Tab)
|
||||
);
|
||||
test(
|
||||
new ChordKeybinding([
|
||||
new SimpleKeybinding(false, false, false, true, KeyCode.KEY_Y),
|
||||
new SimpleKeybinding(false, false, false, false, KeyCode.KEY_Z)
|
||||
]),
|
||||
KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_Y, KeyCode.KEY_Z)
|
||||
);
|
||||
});
|
||||
|
||||
test('WINDOWS & LINUX binary encoding', () => {
|
||||
|
||||
[OperatingSystem.Linux, OperatingSystem.Windows].forEach((OS) => {
|
||||
|
||||
function test(expected: Keybinding | null, k: number): void {
|
||||
testBinaryEncoding(expected, k, OS);
|
||||
}
|
||||
|
||||
test(null, 0);
|
||||
test(new SimpleKeybinding(false, false, false, false, KeyCode.Enter).toChord(), KeyCode.Enter);
|
||||
test(new SimpleKeybinding(false, false, false, true, KeyCode.Enter).toChord(), KeyMod.WinCtrl | KeyCode.Enter);
|
||||
test(new SimpleKeybinding(false, false, true, false, KeyCode.Enter).toChord(), KeyMod.Alt | KeyCode.Enter);
|
||||
test(new SimpleKeybinding(false, false, true, true, KeyCode.Enter).toChord(), KeyMod.Alt | KeyMod.WinCtrl | KeyCode.Enter);
|
||||
test(new SimpleKeybinding(false, true, false, false, KeyCode.Enter).toChord(), KeyMod.Shift | KeyCode.Enter);
|
||||
test(new SimpleKeybinding(false, true, false, true, KeyCode.Enter).toChord(), KeyMod.Shift | KeyMod.WinCtrl | KeyCode.Enter);
|
||||
test(new SimpleKeybinding(false, true, true, false, KeyCode.Enter).toChord(), KeyMod.Shift | KeyMod.Alt | KeyCode.Enter);
|
||||
test(new SimpleKeybinding(false, true, true, true, KeyCode.Enter).toChord(), KeyMod.Shift | KeyMod.Alt | KeyMod.WinCtrl | KeyCode.Enter);
|
||||
test(new SimpleKeybinding(true, false, false, false, KeyCode.Enter).toChord(), KeyMod.CtrlCmd | KeyCode.Enter);
|
||||
test(new SimpleKeybinding(true, false, false, true, KeyCode.Enter).toChord(), KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.Enter);
|
||||
test(new SimpleKeybinding(true, false, true, false, KeyCode.Enter).toChord(), KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.Enter);
|
||||
test(new SimpleKeybinding(true, false, true, true, KeyCode.Enter).toChord(), KeyMod.CtrlCmd | KeyMod.Alt | KeyMod.WinCtrl | KeyCode.Enter);
|
||||
test(new SimpleKeybinding(true, true, false, false, KeyCode.Enter).toChord(), KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Enter);
|
||||
test(new SimpleKeybinding(true, true, false, true, KeyCode.Enter).toChord(), KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.WinCtrl | KeyCode.Enter);
|
||||
test(new SimpleKeybinding(true, true, true, false, KeyCode.Enter).toChord(), KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.Enter);
|
||||
test(new SimpleKeybinding(true, true, true, true, KeyCode.Enter).toChord(), KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyMod.WinCtrl | KeyCode.Enter);
|
||||
|
||||
test(
|
||||
new ChordKeybinding([
|
||||
new SimpleKeybinding(false, false, false, false, KeyCode.Enter),
|
||||
new SimpleKeybinding(false, false, false, false, KeyCode.Tab)
|
||||
]),
|
||||
KeyChord(KeyCode.Enter, KeyCode.Tab)
|
||||
);
|
||||
test(
|
||||
new ChordKeybinding([
|
||||
new SimpleKeybinding(true, false, false, false, KeyCode.KEY_Y),
|
||||
new SimpleKeybinding(false, false, false, false, KeyCode.KEY_Z)
|
||||
]),
|
||||
KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_Y, KeyCode.KEY_Z)
|
||||
);
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
182
lib/vscode/src/vs/base/test/common/labels.test.ts
Normal file
182
lib/vscode/src/vs/base/test/common/labels.test.ts
Normal file
@@ -0,0 +1,182 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import * as labels from 'vs/base/common/labels';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
|
||||
suite('Labels', () => {
|
||||
test('shorten - windows', () => {
|
||||
if (!platform.isWindows) {
|
||||
assert.ok(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// nothing to shorten
|
||||
assert.deepEqual(labels.shorten(['a']), ['a']);
|
||||
assert.deepEqual(labels.shorten(['a', 'b']), ['a', 'b']);
|
||||
assert.deepEqual(labels.shorten(['a', 'b', 'c']), ['a', 'b', 'c']);
|
||||
|
||||
// completely different paths
|
||||
assert.deepEqual(labels.shorten(['a\\b', 'c\\d', 'e\\f']), ['…\\b', '…\\d', '…\\f']);
|
||||
|
||||
// same beginning
|
||||
assert.deepEqual(labels.shorten(['a', 'a\\b']), ['a', '…\\b']);
|
||||
assert.deepEqual(labels.shorten(['a\\b', 'a\\b\\c']), ['…\\b', '…\\c']);
|
||||
assert.deepEqual(labels.shorten(['a', 'a\\b', 'a\\b\\c']), ['a', '…\\b', '…\\c']);
|
||||
assert.deepEqual(labels.shorten(['x:\\a\\b', 'x:\\a\\c']), ['x:\\…\\b', 'x:\\…\\c']);
|
||||
assert.deepEqual(labels.shorten(['\\\\a\\b', '\\\\a\\c']), ['\\\\a\\b', '\\\\a\\c']);
|
||||
|
||||
// same ending
|
||||
assert.deepEqual(labels.shorten(['a', 'b\\a']), ['a', 'b\\…']);
|
||||
assert.deepEqual(labels.shorten(['a\\b\\c', 'd\\b\\c']), ['a\\…', 'd\\…']);
|
||||
assert.deepEqual(labels.shorten(['a\\b\\c\\d', 'f\\b\\c\\d']), ['a\\…', 'f\\…']);
|
||||
assert.deepEqual(labels.shorten(['d\\e\\a\\b\\c', 'd\\b\\c']), ['…\\a\\…', 'd\\b\\…']);
|
||||
assert.deepEqual(labels.shorten(['a\\b\\c\\d', 'a\\f\\b\\c\\d']), ['a\\b\\…', '…\\f\\…']);
|
||||
assert.deepEqual(labels.shorten(['a\\b\\a', 'b\\b\\a']), ['a\\b\\…', 'b\\b\\…']);
|
||||
assert.deepEqual(labels.shorten(['d\\f\\a\\b\\c', 'h\\d\\b\\c']), ['…\\a\\…', 'h\\…']);
|
||||
assert.deepEqual(labels.shorten(['a\\b\\c', 'x:\\0\\a\\b\\c']), ['a\\b\\c', 'x:\\0\\…']);
|
||||
assert.deepEqual(labels.shorten(['x:\\a\\b\\c', 'x:\\0\\a\\b\\c']), ['x:\\a\\…', 'x:\\0\\…']);
|
||||
assert.deepEqual(labels.shorten(['x:\\a\\b', 'y:\\a\\b']), ['x:\\…', 'y:\\…']);
|
||||
assert.deepEqual(labels.shorten(['x:\\a', 'x:\\c']), ['x:\\a', 'x:\\c']);
|
||||
assert.deepEqual(labels.shorten(['x:\\a\\b', 'y:\\x\\a\\b']), ['x:\\…', 'y:\\…']);
|
||||
assert.deepEqual(labels.shorten(['\\\\x\\b', '\\\\y\\b']), ['\\\\x\\…', '\\\\y\\…']);
|
||||
assert.deepEqual(labels.shorten(['\\\\x\\a', '\\\\x\\b']), ['\\\\x\\a', '\\\\x\\b']);
|
||||
|
||||
// same name ending
|
||||
assert.deepEqual(labels.shorten(['a\\b', 'a\\c', 'a\\e-b']), ['…\\b', '…\\c', '…\\e-b']);
|
||||
|
||||
// same in the middle
|
||||
assert.deepEqual(labels.shorten(['a\\b\\c', 'd\\b\\e']), ['…\\c', '…\\e']);
|
||||
|
||||
// case-sensetive
|
||||
assert.deepEqual(labels.shorten(['a\\b\\c', 'd\\b\\C']), ['…\\c', '…\\C']);
|
||||
|
||||
// empty or null
|
||||
assert.deepEqual(labels.shorten(['', null!]), ['.\\', null]);
|
||||
|
||||
assert.deepEqual(labels.shorten(['a', 'a\\b', 'a\\b\\c', 'd\\b\\c', 'd\\b']), ['a', 'a\\b', 'a\\b\\c', 'd\\b\\c', 'd\\b']);
|
||||
assert.deepEqual(labels.shorten(['a', 'a\\b', 'b']), ['a', 'a\\b', 'b']);
|
||||
assert.deepEqual(labels.shorten(['', 'a', 'b', 'b\\c', 'a\\c']), ['.\\', 'a', 'b', 'b\\c', 'a\\c']);
|
||||
assert.deepEqual(labels.shorten(['src\\vs\\workbench\\parts\\execution\\electron-browser', 'src\\vs\\workbench\\parts\\execution\\electron-browser\\something', 'src\\vs\\workbench\\parts\\terminal\\electron-browser']), ['…\\execution\\electron-browser', '…\\something', '…\\terminal\\…']);
|
||||
});
|
||||
|
||||
test('shorten - not windows', () => {
|
||||
if (platform.isWindows) {
|
||||
assert.ok(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// nothing to shorten
|
||||
assert.deepEqual(labels.shorten(['a']), ['a']);
|
||||
assert.deepEqual(labels.shorten(['a', 'b']), ['a', 'b']);
|
||||
assert.deepEqual(labels.shorten(['a', 'b', 'c']), ['a', 'b', 'c']);
|
||||
|
||||
// completely different paths
|
||||
assert.deepEqual(labels.shorten(['a/b', 'c/d', 'e/f']), ['…/b', '…/d', '…/f']);
|
||||
|
||||
// same beginning
|
||||
assert.deepEqual(labels.shorten(['a', 'a/b']), ['a', '…/b']);
|
||||
assert.deepEqual(labels.shorten(['a/b', 'a/b/c']), ['…/b', '…/c']);
|
||||
assert.deepEqual(labels.shorten(['a', 'a/b', 'a/b/c']), ['a', '…/b', '…/c']);
|
||||
assert.deepEqual(labels.shorten(['/a/b', '/a/c']), ['/a/b', '/a/c']);
|
||||
|
||||
// same ending
|
||||
assert.deepEqual(labels.shorten(['a', 'b/a']), ['a', 'b/…']);
|
||||
assert.deepEqual(labels.shorten(['a/b/c', 'd/b/c']), ['a/…', 'd/…']);
|
||||
assert.deepEqual(labels.shorten(['a/b/c/d', 'f/b/c/d']), ['a/…', 'f/…']);
|
||||
assert.deepEqual(labels.shorten(['d/e/a/b/c', 'd/b/c']), ['…/a/…', 'd/b/…']);
|
||||
assert.deepEqual(labels.shorten(['a/b/c/d', 'a/f/b/c/d']), ['a/b/…', '…/f/…']);
|
||||
assert.deepEqual(labels.shorten(['a/b/a', 'b/b/a']), ['a/b/…', 'b/b/…']);
|
||||
assert.deepEqual(labels.shorten(['d/f/a/b/c', 'h/d/b/c']), ['…/a/…', 'h/…']);
|
||||
assert.deepEqual(labels.shorten(['/x/b', '/y/b']), ['/x/…', '/y/…']);
|
||||
|
||||
// same name ending
|
||||
assert.deepEqual(labels.shorten(['a/b', 'a/c', 'a/e-b']), ['…/b', '…/c', '…/e-b']);
|
||||
|
||||
// same in the middle
|
||||
assert.deepEqual(labels.shorten(['a/b/c', 'd/b/e']), ['…/c', '…/e']);
|
||||
|
||||
// case-sensitive
|
||||
assert.deepEqual(labels.shorten(['a/b/c', 'd/b/C']), ['…/c', '…/C']);
|
||||
|
||||
// empty or null
|
||||
assert.deepEqual(labels.shorten(['', null!]), ['./', null]);
|
||||
|
||||
assert.deepEqual(labels.shorten(['a', 'a/b', 'a/b/c', 'd/b/c', 'd/b']), ['a', 'a/b', 'a/b/c', 'd/b/c', 'd/b']);
|
||||
assert.deepEqual(labels.shorten(['a', 'a/b', 'b']), ['a', 'a/b', 'b']);
|
||||
assert.deepEqual(labels.shorten(['', 'a', 'b', 'b/c', 'a/c']), ['./', 'a', 'b', 'b/c', 'a/c']);
|
||||
});
|
||||
|
||||
test('template', () => {
|
||||
|
||||
// simple
|
||||
assert.strictEqual(labels.template('Foo Bar'), 'Foo Bar');
|
||||
assert.strictEqual(labels.template('Foo${}Bar'), 'FooBar');
|
||||
assert.strictEqual(labels.template('$FooBar'), '');
|
||||
assert.strictEqual(labels.template('}FooBar'), '}FooBar');
|
||||
assert.strictEqual(labels.template('Foo ${one} Bar', { one: 'value' }), 'Foo value Bar');
|
||||
assert.strictEqual(labels.template('Foo ${one} Bar ${two}', { one: 'value', two: 'other value' }), 'Foo value Bar other value');
|
||||
|
||||
// conditional separator
|
||||
assert.strictEqual(labels.template('Foo${separator}Bar'), 'FooBar');
|
||||
assert.strictEqual(labels.template('Foo${separator}Bar', { separator: { label: ' - ' } }), 'Foo - Bar');
|
||||
assert.strictEqual(labels.template('${separator}Foo${separator}Bar', { value: 'something', separator: { label: ' - ' } }), 'Foo - Bar');
|
||||
assert.strictEqual(labels.template('${value} Foo${separator}Bar', { value: 'something', separator: { label: ' - ' } }), 'something Foo - Bar');
|
||||
|
||||
// // real world example (macOS)
|
||||
let t = '${activeEditorShort}${separator}${rootName}';
|
||||
assert.strictEqual(labels.template(t, { activeEditorShort: '', rootName: '', separator: { label: ' - ' } }), '');
|
||||
assert.strictEqual(labels.template(t, { activeEditorShort: '', rootName: 'root', separator: { label: ' - ' } }), 'root');
|
||||
assert.strictEqual(labels.template(t, { activeEditorShort: 'markdown.txt', rootName: 'root', separator: { label: ' - ' } }), 'markdown.txt - root');
|
||||
|
||||
// // real world example (other)
|
||||
t = '${dirty}${activeEditorShort}${separator}${rootName}${separator}${appName}';
|
||||
assert.strictEqual(labels.template(t, { dirty: '', activeEditorShort: '', rootName: '', appName: '', separator: { label: ' - ' } }), '');
|
||||
assert.strictEqual(labels.template(t, { dirty: '', activeEditorShort: '', rootName: '', appName: 'Visual Studio Code', separator: { label: ' - ' } }), 'Visual Studio Code');
|
||||
assert.strictEqual(labels.template(t, { dirty: '', activeEditorShort: 'Untitled-1', rootName: '', appName: 'Visual Studio Code', separator: { label: ' - ' } }), 'Untitled-1 - Visual Studio Code');
|
||||
assert.strictEqual(labels.template(t, { dirty: '', activeEditorShort: '', rootName: 'monaco', appName: 'Visual Studio Code', separator: { label: ' - ' } }), 'monaco - Visual Studio Code');
|
||||
assert.strictEqual(labels.template(t, { dirty: '', activeEditorShort: 'somefile.txt', rootName: 'monaco', appName: 'Visual Studio Code', separator: { label: ' - ' } }), 'somefile.txt - monaco - Visual Studio Code');
|
||||
assert.strictEqual(labels.template(t, { dirty: '* ', activeEditorShort: 'somefile.txt', rootName: 'monaco', appName: 'Visual Studio Code', separator: { label: ' - ' } }), '* somefile.txt - monaco - Visual Studio Code');
|
||||
});
|
||||
|
||||
test('getBaseLabel - unix', () => {
|
||||
if (platform.isWindows) {
|
||||
assert.ok(true);
|
||||
return;
|
||||
}
|
||||
|
||||
assert.equal(labels.getBaseLabel('/some/folder/file.txt'), 'file.txt');
|
||||
assert.equal(labels.getBaseLabel('/some/folder'), 'folder');
|
||||
assert.equal(labels.getBaseLabel('/'), '/');
|
||||
});
|
||||
|
||||
test('getBaseLabel - windows', () => {
|
||||
if (!platform.isWindows) {
|
||||
assert.ok(true);
|
||||
return;
|
||||
}
|
||||
|
||||
assert.equal(labels.getBaseLabel('c:'), 'C:');
|
||||
assert.equal(labels.getBaseLabel('c:\\'), 'C:');
|
||||
assert.equal(labels.getBaseLabel('c:\\some\\folder\\file.txt'), 'file.txt');
|
||||
assert.equal(labels.getBaseLabel('c:\\some\\folder'), 'folder');
|
||||
});
|
||||
|
||||
test('mnemonicButtonLabel', () => {
|
||||
assert.equal(labels.mnemonicButtonLabel('Hello World'), 'Hello World');
|
||||
assert.equal(labels.mnemonicButtonLabel(''), '');
|
||||
if (platform.isWindows) {
|
||||
assert.equal(labels.mnemonicButtonLabel('Hello & World'), 'Hello && World');
|
||||
assert.equal(labels.mnemonicButtonLabel('Do &¬ Save & Continue'), 'Do ¬ Save && Continue');
|
||||
} else if (platform.isMacintosh) {
|
||||
assert.equal(labels.mnemonicButtonLabel('Hello & World'), 'Hello & World');
|
||||
assert.equal(labels.mnemonicButtonLabel('Do &¬ Save & Continue'), 'Do not Save & Continue');
|
||||
} else {
|
||||
assert.equal(labels.mnemonicButtonLabel('Hello & World'), 'Hello & World');
|
||||
assert.equal(labels.mnemonicButtonLabel('Do &¬ Save & Continue'), 'Do _not Save & Continue');
|
||||
}
|
||||
});
|
||||
});
|
||||
64
lib/vscode/src/vs/base/test/common/lazy.test.ts
Normal file
64
lib/vscode/src/vs/base/test/common/lazy.test.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { Lazy } from 'vs/base/common/lazy';
|
||||
|
||||
suite('Lazy', () => {
|
||||
|
||||
test('lazy values should only be resolved once', () => {
|
||||
let counter = 0;
|
||||
const value = new Lazy(() => ++counter);
|
||||
|
||||
assert.strictEqual(value.hasValue(), false);
|
||||
assert.strictEqual(value.getValue(), 1);
|
||||
assert.strictEqual(value.hasValue(), true);
|
||||
assert.strictEqual(value.getValue(), 1); // make sure we did not evaluate again
|
||||
});
|
||||
|
||||
test('lazy values handle error case', () => {
|
||||
let counter = 0;
|
||||
const value = new Lazy(() => { throw new Error(`${++counter}`); });
|
||||
|
||||
assert.strictEqual(value.hasValue(), false);
|
||||
assert.throws(() => value.getValue(), /\b1\b/);
|
||||
assert.strictEqual(value.hasValue(), true);
|
||||
assert.throws(() => value.getValue(), /\b1\b/);
|
||||
});
|
||||
|
||||
test('map should not cause lazy values to be re-resolved', () => {
|
||||
let outer = 0;
|
||||
let inner = 10;
|
||||
const outerLazy = new Lazy(() => ++outer);
|
||||
const innerLazy = outerLazy.map(x => [x, ++inner]);
|
||||
|
||||
assert.strictEqual(outerLazy.hasValue(), false);
|
||||
assert.strictEqual(innerLazy.hasValue(), false);
|
||||
|
||||
assert.deepEqual(innerLazy.getValue(), [1, 11]);
|
||||
assert.strictEqual(outerLazy.hasValue(), true);
|
||||
assert.strictEqual(innerLazy.hasValue(), true);
|
||||
assert.strictEqual(outerLazy.getValue(), 1);
|
||||
|
||||
// make sure we did not evaluate again
|
||||
assert.strictEqual(outerLazy.getValue(), 1);
|
||||
assert.deepEqual(innerLazy.getValue(), [1, 11]);
|
||||
});
|
||||
|
||||
test('map should handle error values', () => {
|
||||
let outer = 0;
|
||||
let inner = 10;
|
||||
const outerLazy = new Lazy(() => { throw new Error(`${++outer}`); });
|
||||
const innerLazy = outerLazy.map(x => { throw new Error(`${++inner}`); });
|
||||
|
||||
assert.strictEqual(outerLazy.hasValue(), false);
|
||||
assert.strictEqual(innerLazy.hasValue(), false);
|
||||
|
||||
assert.throws(() => innerLazy.getValue(), /\b1\b/); // we should get result from outer
|
||||
assert.strictEqual(outerLazy.hasValue(), true);
|
||||
assert.strictEqual(innerLazy.hasValue(), true);
|
||||
assert.throws(() => outerLazy.getValue(), /\b1\b/);
|
||||
});
|
||||
});
|
||||
191
lib/vscode/src/vs/base/test/common/lifecycle.test.ts
Normal file
191
lib/vscode/src/vs/base/test/common/lifecycle.test.ts
Normal file
@@ -0,0 +1,191 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as assert from 'assert';
|
||||
import { DisposableStore, dispose, IDisposable, MultiDisposeError, ReferenceCollection, toDisposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
class Disposable implements IDisposable {
|
||||
isDisposed = false;
|
||||
dispose() { this.isDisposed = true; }
|
||||
}
|
||||
|
||||
suite('Lifecycle', () => {
|
||||
|
||||
test('dispose single disposable', () => {
|
||||
const disposable = new Disposable();
|
||||
|
||||
assert(!disposable.isDisposed);
|
||||
|
||||
dispose(disposable);
|
||||
|
||||
assert(disposable.isDisposed);
|
||||
});
|
||||
|
||||
test('dispose disposable array', () => {
|
||||
const disposable = new Disposable();
|
||||
const disposable2 = new Disposable();
|
||||
|
||||
assert(!disposable.isDisposed);
|
||||
assert(!disposable2.isDisposed);
|
||||
|
||||
dispose([disposable, disposable2]);
|
||||
|
||||
assert(disposable.isDisposed);
|
||||
assert(disposable2.isDisposed);
|
||||
});
|
||||
|
||||
test('dispose disposables', () => {
|
||||
const disposable = new Disposable();
|
||||
const disposable2 = new Disposable();
|
||||
|
||||
assert(!disposable.isDisposed);
|
||||
assert(!disposable2.isDisposed);
|
||||
|
||||
dispose(disposable);
|
||||
dispose(disposable2);
|
||||
|
||||
assert(disposable.isDisposed);
|
||||
assert(disposable2.isDisposed);
|
||||
});
|
||||
|
||||
test('dispose array should dispose all if a child throws on dispose', () => {
|
||||
const disposedValues = new Set<number>();
|
||||
|
||||
let thrownError: any;
|
||||
try {
|
||||
dispose([
|
||||
toDisposable(() => { disposedValues.add(1); }),
|
||||
toDisposable(() => { throw new Error('I am error'); }),
|
||||
toDisposable(() => { disposedValues.add(3); }),
|
||||
]);
|
||||
} catch (e) {
|
||||
thrownError = e;
|
||||
}
|
||||
|
||||
assert.ok(disposedValues.has(1));
|
||||
assert.ok(disposedValues.has(3));
|
||||
assert.strictEqual(thrownError.message, 'I am error');
|
||||
});
|
||||
|
||||
test('dispose array should rethrow composite error if multiple entries throw on dispose', () => {
|
||||
const disposedValues = new Set<number>();
|
||||
|
||||
let thrownError: any;
|
||||
try {
|
||||
dispose([
|
||||
toDisposable(() => { disposedValues.add(1); }),
|
||||
toDisposable(() => { throw new Error('I am error 1'); }),
|
||||
toDisposable(() => { throw new Error('I am error 2'); }),
|
||||
toDisposable(() => { disposedValues.add(4); }),
|
||||
]);
|
||||
} catch (e) {
|
||||
thrownError = e;
|
||||
}
|
||||
|
||||
assert.ok(disposedValues.has(1));
|
||||
assert.ok(disposedValues.has(4));
|
||||
assert.ok(thrownError instanceof MultiDisposeError);
|
||||
assert.strictEqual((thrownError as MultiDisposeError).errors.length, 2);
|
||||
assert.strictEqual((thrownError as MultiDisposeError).errors[0].message, 'I am error 1');
|
||||
assert.strictEqual((thrownError as MultiDisposeError).errors[1].message, 'I am error 2');
|
||||
});
|
||||
|
||||
test('Action bar has broken accessibility #100273', function () {
|
||||
let array = [{ dispose() { } }, { dispose() { } }];
|
||||
let array2 = dispose(array);
|
||||
|
||||
assert.equal(array.length, 2);
|
||||
assert.equal(array2.length, 0);
|
||||
assert.ok(array !== array2);
|
||||
|
||||
let set = new Set<IDisposable>([{ dispose() { } }, { dispose() { } }]);
|
||||
let setValues = set.values();
|
||||
let setValues2 = dispose(setValues);
|
||||
assert.ok(setValues === setValues2);
|
||||
});
|
||||
});
|
||||
|
||||
suite('DisposableStore', () => {
|
||||
test('dispose should call all child disposes even if a child throws on dispose', () => {
|
||||
const disposedValues = new Set<number>();
|
||||
|
||||
const store = new DisposableStore();
|
||||
store.add(toDisposable(() => { disposedValues.add(1); }));
|
||||
store.add(toDisposable(() => { throw new Error('I am error'); }));
|
||||
store.add(toDisposable(() => { disposedValues.add(3); }));
|
||||
|
||||
let thrownError: any;
|
||||
try {
|
||||
store.dispose();
|
||||
} catch (e) {
|
||||
thrownError = e;
|
||||
}
|
||||
|
||||
assert.ok(disposedValues.has(1));
|
||||
assert.ok(disposedValues.has(3));
|
||||
assert.strictEqual(thrownError.message, 'I am error');
|
||||
});
|
||||
|
||||
test('dispose should throw composite error if multiple children throw on dispose', () => {
|
||||
const disposedValues = new Set<number>();
|
||||
|
||||
const store = new DisposableStore();
|
||||
store.add(toDisposable(() => { disposedValues.add(1); }));
|
||||
store.add(toDisposable(() => { throw new Error('I am error 1'); }));
|
||||
store.add(toDisposable(() => { throw new Error('I am error 2'); }));
|
||||
store.add(toDisposable(() => { disposedValues.add(4); }));
|
||||
|
||||
let thrownError: any;
|
||||
try {
|
||||
store.dispose();
|
||||
} catch (e) {
|
||||
thrownError = e;
|
||||
}
|
||||
|
||||
assert.ok(disposedValues.has(1));
|
||||
assert.ok(disposedValues.has(4));
|
||||
assert.ok(thrownError instanceof MultiDisposeError);
|
||||
assert.strictEqual((thrownError as MultiDisposeError).errors.length, 2);
|
||||
assert.strictEqual((thrownError as MultiDisposeError).errors[0].message, 'I am error 1');
|
||||
assert.strictEqual((thrownError as MultiDisposeError).errors[1].message, 'I am error 2');
|
||||
});
|
||||
});
|
||||
|
||||
suite('Reference Collection', () => {
|
||||
class Collection extends ReferenceCollection<number> {
|
||||
private _count = 0;
|
||||
get count() { return this._count; }
|
||||
protected createReferencedObject(key: string): number { this._count++; return key.length; }
|
||||
protected destroyReferencedObject(key: string, object: number): void { this._count--; }
|
||||
}
|
||||
|
||||
test('simple', () => {
|
||||
const collection = new Collection();
|
||||
|
||||
const ref1 = collection.acquire('test');
|
||||
assert(ref1);
|
||||
assert.equal(ref1.object, 4);
|
||||
assert.equal(collection.count, 1);
|
||||
ref1.dispose();
|
||||
assert.equal(collection.count, 0);
|
||||
|
||||
const ref2 = collection.acquire('test');
|
||||
const ref3 = collection.acquire('test');
|
||||
assert.equal(ref2.object, ref3.object);
|
||||
assert.equal(collection.count, 1);
|
||||
|
||||
const ref4 = collection.acquire('monkey');
|
||||
assert.equal(ref4.object, 6);
|
||||
assert.equal(collection.count, 2);
|
||||
|
||||
ref2.dispose();
|
||||
assert.equal(collection.count, 2);
|
||||
|
||||
ref3.dispose();
|
||||
assert.equal(collection.count, 1);
|
||||
|
||||
ref4.dispose();
|
||||
assert.equal(collection.count, 0);
|
||||
});
|
||||
});
|
||||
137
lib/vscode/src/vs/base/test/common/linkedList.test.ts
Normal file
137
lib/vscode/src/vs/base/test/common/linkedList.test.ts
Normal file
@@ -0,0 +1,137 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { LinkedList } from 'vs/base/common/linkedList';
|
||||
|
||||
suite('LinkedList', function () {
|
||||
|
||||
function assertElements<E>(list: LinkedList<E>, ...elements: E[]) {
|
||||
|
||||
// check size
|
||||
assert.equal(list.size, elements.length);
|
||||
|
||||
// assert toArray
|
||||
assert.deepEqual(list.toArray(), elements);
|
||||
|
||||
// assert Symbol.iterator (1)
|
||||
assert.deepEqual([...list], elements);
|
||||
|
||||
// assert Symbol.iterator (2)
|
||||
for (const item of list) {
|
||||
assert.equal(item, elements.shift());
|
||||
}
|
||||
assert.equal(elements.length, 0);
|
||||
}
|
||||
|
||||
test('Push/Iter', () => {
|
||||
const list = new LinkedList<number>();
|
||||
list.push(0);
|
||||
list.push(1);
|
||||
list.push(2);
|
||||
assertElements(list, 0, 1, 2);
|
||||
});
|
||||
|
||||
test('Push/Remove', () => {
|
||||
let list = new LinkedList<number>();
|
||||
let disp = list.push(0);
|
||||
list.push(1);
|
||||
list.push(2);
|
||||
disp();
|
||||
assertElements(list, 1, 2);
|
||||
|
||||
list = new LinkedList<number>();
|
||||
list.push(0);
|
||||
disp = list.push(1);
|
||||
list.push(2);
|
||||
disp();
|
||||
assertElements(list, 0, 2);
|
||||
|
||||
list = new LinkedList<number>();
|
||||
list.push(0);
|
||||
list.push(1);
|
||||
disp = list.push(2);
|
||||
disp();
|
||||
assertElements(list, 0, 1);
|
||||
|
||||
list = new LinkedList<number>();
|
||||
list.push(0);
|
||||
list.push(1);
|
||||
disp = list.push(2);
|
||||
disp();
|
||||
disp();
|
||||
assertElements(list, 0, 1);
|
||||
});
|
||||
|
||||
test('Push/toArray', () => {
|
||||
let list = new LinkedList<string>();
|
||||
list.push('foo');
|
||||
list.push('bar');
|
||||
list.push('far');
|
||||
list.push('boo');
|
||||
|
||||
assertElements(list, 'foo', 'bar', 'far', 'boo');
|
||||
});
|
||||
|
||||
test('unshift/Iter', () => {
|
||||
const list = new LinkedList<number>();
|
||||
list.unshift(0);
|
||||
list.unshift(1);
|
||||
list.unshift(2);
|
||||
assertElements(list, 2, 1, 0);
|
||||
});
|
||||
|
||||
test('unshift/Remove', () => {
|
||||
let list = new LinkedList<number>();
|
||||
let disp = list.unshift(0);
|
||||
list.unshift(1);
|
||||
list.unshift(2);
|
||||
disp();
|
||||
assertElements(list, 2, 1);
|
||||
|
||||
list = new LinkedList<number>();
|
||||
list.unshift(0);
|
||||
disp = list.unshift(1);
|
||||
list.unshift(2);
|
||||
disp();
|
||||
assertElements(list, 2, 0);
|
||||
|
||||
list = new LinkedList<number>();
|
||||
list.unshift(0);
|
||||
list.unshift(1);
|
||||
disp = list.unshift(2);
|
||||
disp();
|
||||
assertElements(list, 1, 0);
|
||||
});
|
||||
|
||||
test('unshift/toArray', () => {
|
||||
let list = new LinkedList<string>();
|
||||
list.unshift('foo');
|
||||
list.unshift('bar');
|
||||
list.unshift('far');
|
||||
list.unshift('boo');
|
||||
assertElements(list, 'boo', 'far', 'bar', 'foo');
|
||||
});
|
||||
|
||||
test('pop/unshift', function () {
|
||||
let list = new LinkedList<string>();
|
||||
list.push('a');
|
||||
list.push('b');
|
||||
|
||||
assertElements(list, 'a', 'b');
|
||||
|
||||
let a = list.shift();
|
||||
assert.equal(a, 'a');
|
||||
assertElements(list, 'b');
|
||||
|
||||
list.unshift('a');
|
||||
assertElements(list, 'a', 'b');
|
||||
|
||||
let b = list.pop();
|
||||
assert.equal(b, 'b');
|
||||
assertElements(list, 'a');
|
||||
|
||||
});
|
||||
});
|
||||
73
lib/vscode/src/vs/base/test/common/linkedText.test.ts
Normal file
73
lib/vscode/src/vs/base/test/common/linkedText.test.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { parseLinkedText } from 'vs/base/common/linkedText';
|
||||
|
||||
suite('LinkedText', () => {
|
||||
test('parses correctly', () => {
|
||||
assert.deepEqual(parseLinkedText('').nodes, []);
|
||||
assert.deepEqual(parseLinkedText('hello').nodes, ['hello']);
|
||||
assert.deepEqual(parseLinkedText('hello there').nodes, ['hello there']);
|
||||
assert.deepEqual(parseLinkedText('Some message with [link text](http://link.href).').nodes, [
|
||||
'Some message with ',
|
||||
{ label: 'link text', href: 'http://link.href' },
|
||||
'.'
|
||||
]);
|
||||
assert.deepEqual(parseLinkedText('Some message with [link text](http://link.href "and a title").').nodes, [
|
||||
'Some message with ',
|
||||
{ label: 'link text', href: 'http://link.href', title: 'and a title' },
|
||||
'.'
|
||||
]);
|
||||
assert.deepEqual(parseLinkedText('Some message with [link text](http://link.href \'and a title\').').nodes, [
|
||||
'Some message with ',
|
||||
{ label: 'link text', href: 'http://link.href', title: 'and a title' },
|
||||
'.'
|
||||
]);
|
||||
assert.deepEqual(parseLinkedText('Some message with [link text](http://link.href "and a \'title\'").').nodes, [
|
||||
'Some message with ',
|
||||
{ label: 'link text', href: 'http://link.href', title: 'and a \'title\'' },
|
||||
'.'
|
||||
]);
|
||||
assert.deepEqual(parseLinkedText('Some message with [link text](http://link.href \'and a "title"\').').nodes, [
|
||||
'Some message with ',
|
||||
{ label: 'link text', href: 'http://link.href', title: 'and a "title"' },
|
||||
'.'
|
||||
]);
|
||||
assert.deepEqual(parseLinkedText('Some message with [link text](random stuff).').nodes, [
|
||||
'Some message with [link text](random stuff).'
|
||||
]);
|
||||
assert.deepEqual(parseLinkedText('Some message with [https link](https://link.href).').nodes, [
|
||||
'Some message with ',
|
||||
{ label: 'https link', href: 'https://link.href' },
|
||||
'.'
|
||||
]);
|
||||
assert.deepEqual(parseLinkedText('Some message with [https link](https:).').nodes, [
|
||||
'Some message with [https link](https:).'
|
||||
]);
|
||||
assert.deepEqual(parseLinkedText('Some message with [a command](command:foobar).').nodes, [
|
||||
'Some message with ',
|
||||
{ label: 'a command', href: 'command:foobar' },
|
||||
'.'
|
||||
]);
|
||||
assert.deepEqual(parseLinkedText('Some message with [a command](command:).').nodes, [
|
||||
'Some message with [a command](command:).'
|
||||
]);
|
||||
assert.deepEqual(parseLinkedText('link [one](command:foo "nice") and link [two](http://foo)...').nodes, [
|
||||
'link ',
|
||||
{ label: 'one', href: 'command:foo', title: 'nice' },
|
||||
' and link ',
|
||||
{ label: 'two', href: 'http://foo' },
|
||||
'...'
|
||||
]);
|
||||
assert.deepEqual(parseLinkedText('link\n[one](command:foo "nice")\nand link [two](http://foo)...').nodes, [
|
||||
'link\n',
|
||||
{ label: 'one', href: 'command:foo', title: 'nice' },
|
||||
'\nand link ',
|
||||
{ label: 'two', href: 'http://foo' },
|
||||
'...'
|
||||
]);
|
||||
});
|
||||
});
|
||||
914
lib/vscode/src/vs/base/test/common/map.test.ts
Normal file
914
lib/vscode/src/vs/base/test/common/map.test.ts
Normal file
@@ -0,0 +1,914 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ResourceMap, TernarySearchTree, PathIterator, StringIterator, LinkedMap, Touch, LRUCache, UriIterator } from 'vs/base/common/map';
|
||||
import * as assert from 'assert';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { extUriIgnorePathCase } from 'vs/base/common/resources';
|
||||
|
||||
suite('Map', () => {
|
||||
|
||||
test('LinkedMap - Simple', () => {
|
||||
let map = new LinkedMap<string, string>();
|
||||
map.set('ak', 'av');
|
||||
map.set('bk', 'bv');
|
||||
assert.deepStrictEqual([...map.keys()], ['ak', 'bk']);
|
||||
assert.deepStrictEqual([...map.values()], ['av', 'bv']);
|
||||
assert.equal(map.first, 'av');
|
||||
assert.equal(map.last, 'bv');
|
||||
});
|
||||
|
||||
test('LinkedMap - Touch Old one', () => {
|
||||
let map = new LinkedMap<string, string>();
|
||||
map.set('ak', 'av');
|
||||
map.set('ak', 'av', Touch.AsOld);
|
||||
assert.deepStrictEqual([...map.keys()], ['ak']);
|
||||
assert.deepStrictEqual([...map.values()], ['av']);
|
||||
});
|
||||
|
||||
test('LinkedMap - Touch New one', () => {
|
||||
let map = new LinkedMap<string, string>();
|
||||
map.set('ak', 'av');
|
||||
map.set('ak', 'av', Touch.AsNew);
|
||||
assert.deepStrictEqual([...map.keys()], ['ak']);
|
||||
assert.deepStrictEqual([...map.values()], ['av']);
|
||||
});
|
||||
|
||||
test('LinkedMap - Touch Old two', () => {
|
||||
let map = new LinkedMap<string, string>();
|
||||
map.set('ak', 'av');
|
||||
map.set('bk', 'bv');
|
||||
map.set('bk', 'bv', Touch.AsOld);
|
||||
assert.deepStrictEqual([...map.keys()], ['bk', 'ak']);
|
||||
assert.deepStrictEqual([...map.values()], ['bv', 'av']);
|
||||
});
|
||||
|
||||
test('LinkedMap - Touch New two', () => {
|
||||
let map = new LinkedMap<string, string>();
|
||||
map.set('ak', 'av');
|
||||
map.set('bk', 'bv');
|
||||
map.set('ak', 'av', Touch.AsNew);
|
||||
assert.deepStrictEqual([...map.keys()], ['bk', 'ak']);
|
||||
assert.deepStrictEqual([...map.values()], ['bv', 'av']);
|
||||
});
|
||||
|
||||
test('LinkedMap - Touch Old from middle', () => {
|
||||
let map = new LinkedMap<string, string>();
|
||||
map.set('ak', 'av');
|
||||
map.set('bk', 'bv');
|
||||
map.set('ck', 'cv');
|
||||
map.set('bk', 'bv', Touch.AsOld);
|
||||
assert.deepStrictEqual([...map.keys()], ['bk', 'ak', 'ck']);
|
||||
assert.deepStrictEqual([...map.values()], ['bv', 'av', 'cv']);
|
||||
});
|
||||
|
||||
test('LinkedMap - Touch New from middle', () => {
|
||||
let map = new LinkedMap<string, string>();
|
||||
map.set('ak', 'av');
|
||||
map.set('bk', 'bv');
|
||||
map.set('ck', 'cv');
|
||||
map.set('bk', 'bv', Touch.AsNew);
|
||||
assert.deepStrictEqual([...map.keys()], ['ak', 'ck', 'bk']);
|
||||
assert.deepStrictEqual([...map.values()], ['av', 'cv', 'bv']);
|
||||
});
|
||||
|
||||
test('LinkedMap - basics', function () {
|
||||
const map = new LinkedMap<string, any>();
|
||||
|
||||
assert.equal(map.size, 0);
|
||||
|
||||
map.set('1', 1);
|
||||
map.set('2', '2');
|
||||
map.set('3', true);
|
||||
|
||||
const obj = Object.create(null);
|
||||
map.set('4', obj);
|
||||
|
||||
const date = Date.now();
|
||||
map.set('5', date);
|
||||
|
||||
assert.equal(map.size, 5);
|
||||
assert.equal(map.get('1'), 1);
|
||||
assert.equal(map.get('2'), '2');
|
||||
assert.equal(map.get('3'), true);
|
||||
assert.equal(map.get('4'), obj);
|
||||
assert.equal(map.get('5'), date);
|
||||
assert.ok(!map.get('6'));
|
||||
|
||||
map.delete('6');
|
||||
assert.equal(map.size, 5);
|
||||
assert.equal(map.delete('1'), true);
|
||||
assert.equal(map.delete('2'), true);
|
||||
assert.equal(map.delete('3'), true);
|
||||
assert.equal(map.delete('4'), true);
|
||||
assert.equal(map.delete('5'), true);
|
||||
|
||||
assert.equal(map.size, 0);
|
||||
assert.ok(!map.get('5'));
|
||||
assert.ok(!map.get('4'));
|
||||
assert.ok(!map.get('3'));
|
||||
assert.ok(!map.get('2'));
|
||||
assert.ok(!map.get('1'));
|
||||
|
||||
map.set('1', 1);
|
||||
map.set('2', '2');
|
||||
map.set('3', true);
|
||||
|
||||
assert.ok(map.has('1'));
|
||||
assert.equal(map.get('1'), 1);
|
||||
assert.equal(map.get('2'), '2');
|
||||
assert.equal(map.get('3'), true);
|
||||
|
||||
map.clear();
|
||||
|
||||
assert.equal(map.size, 0);
|
||||
assert.ok(!map.get('1'));
|
||||
assert.ok(!map.get('2'));
|
||||
assert.ok(!map.get('3'));
|
||||
assert.ok(!map.has('1'));
|
||||
});
|
||||
|
||||
test('LinkedMap - Iterators', () => {
|
||||
const map = new LinkedMap<number, any>();
|
||||
map.set(1, 1);
|
||||
map.set(2, 2);
|
||||
map.set(3, 3);
|
||||
|
||||
for (const elem of map.keys()) {
|
||||
assert.ok(elem);
|
||||
}
|
||||
|
||||
for (const elem of map.values()) {
|
||||
assert.ok(elem);
|
||||
}
|
||||
|
||||
for (const elem of map.entries()) {
|
||||
assert.ok(elem);
|
||||
}
|
||||
|
||||
{
|
||||
const keys = map.keys();
|
||||
const values = map.values();
|
||||
const entries = map.entries();
|
||||
map.get(1);
|
||||
keys.next();
|
||||
values.next();
|
||||
entries.next();
|
||||
}
|
||||
|
||||
{
|
||||
const keys = map.keys();
|
||||
const values = map.values();
|
||||
const entries = map.entries();
|
||||
map.get(1, Touch.AsNew);
|
||||
|
||||
let exceptions: number = 0;
|
||||
try {
|
||||
keys.next();
|
||||
} catch (err) {
|
||||
exceptions++;
|
||||
}
|
||||
try {
|
||||
values.next();
|
||||
} catch (err) {
|
||||
exceptions++;
|
||||
}
|
||||
try {
|
||||
entries.next();
|
||||
} catch (err) {
|
||||
exceptions++;
|
||||
}
|
||||
|
||||
assert.strictEqual(exceptions, 3);
|
||||
}
|
||||
});
|
||||
|
||||
test('LinkedMap - LRU Cache simple', () => {
|
||||
const cache = new LRUCache<number, number>(5);
|
||||
|
||||
[1, 2, 3, 4, 5].forEach(value => cache.set(value, value));
|
||||
assert.strictEqual(cache.size, 5);
|
||||
cache.set(6, 6);
|
||||
assert.strictEqual(cache.size, 5);
|
||||
assert.deepStrictEqual([...cache.keys()], [2, 3, 4, 5, 6]);
|
||||
cache.set(7, 7);
|
||||
assert.strictEqual(cache.size, 5);
|
||||
assert.deepStrictEqual([...cache.keys()], [3, 4, 5, 6, 7]);
|
||||
let values: number[] = [];
|
||||
[3, 4, 5, 6, 7].forEach(key => values.push(cache.get(key)!));
|
||||
assert.deepStrictEqual(values, [3, 4, 5, 6, 7]);
|
||||
});
|
||||
|
||||
test('LinkedMap - LRU Cache get', () => {
|
||||
const cache = new LRUCache<number, number>(5);
|
||||
|
||||
[1, 2, 3, 4, 5].forEach(value => cache.set(value, value));
|
||||
assert.strictEqual(cache.size, 5);
|
||||
assert.deepStrictEqual([...cache.keys()], [1, 2, 3, 4, 5]);
|
||||
cache.get(3);
|
||||
assert.deepStrictEqual([...cache.keys()], [1, 2, 4, 5, 3]);
|
||||
cache.peek(4);
|
||||
assert.deepStrictEqual([...cache.keys()], [1, 2, 4, 5, 3]);
|
||||
let values: number[] = [];
|
||||
[1, 2, 3, 4, 5].forEach(key => values.push(cache.get(key)!));
|
||||
assert.deepStrictEqual(values, [1, 2, 3, 4, 5]);
|
||||
});
|
||||
|
||||
test('LinkedMap - LRU Cache limit', () => {
|
||||
const cache = new LRUCache<number, number>(10);
|
||||
|
||||
for (let i = 1; i <= 10; i++) {
|
||||
cache.set(i, i);
|
||||
}
|
||||
assert.strictEqual(cache.size, 10);
|
||||
cache.limit = 5;
|
||||
assert.strictEqual(cache.size, 5);
|
||||
assert.deepStrictEqual([...cache.keys()], [6, 7, 8, 9, 10]);
|
||||
cache.limit = 20;
|
||||
assert.strictEqual(cache.size, 5);
|
||||
for (let i = 11; i <= 20; i++) {
|
||||
cache.set(i, i);
|
||||
}
|
||||
assert.deepEqual(cache.size, 15);
|
||||
let values: number[] = [];
|
||||
for (let i = 6; i <= 20; i++) {
|
||||
values.push(cache.get(i)!);
|
||||
assert.strictEqual(cache.get(i), i);
|
||||
}
|
||||
assert.deepStrictEqual([...cache.values()], values);
|
||||
});
|
||||
|
||||
test('LinkedMap - LRU Cache limit with ratio', () => {
|
||||
const cache = new LRUCache<number, number>(10, 0.5);
|
||||
|
||||
for (let i = 1; i <= 10; i++) {
|
||||
cache.set(i, i);
|
||||
}
|
||||
assert.strictEqual(cache.size, 10);
|
||||
cache.set(11, 11);
|
||||
assert.strictEqual(cache.size, 5);
|
||||
assert.deepStrictEqual([...cache.keys()], [7, 8, 9, 10, 11]);
|
||||
let values: number[] = [];
|
||||
[...cache.keys()].forEach(key => values.push(cache.get(key)!));
|
||||
assert.deepStrictEqual(values, [7, 8, 9, 10, 11]);
|
||||
assert.deepStrictEqual([...cache.values()], values);
|
||||
});
|
||||
|
||||
test('LinkedMap - toJSON / fromJSON', () => {
|
||||
let map = new LinkedMap<string, string>();
|
||||
map.set('ak', 'av');
|
||||
map.set('bk', 'bv');
|
||||
map.set('ck', 'cv');
|
||||
|
||||
const json = map.toJSON();
|
||||
map = new LinkedMap<string, string>();
|
||||
map.fromJSON(json);
|
||||
|
||||
let i = 0;
|
||||
map.forEach((value, key) => {
|
||||
if (i === 0) {
|
||||
assert.equal(key, 'ak');
|
||||
assert.equal(value, 'av');
|
||||
} else if (i === 1) {
|
||||
assert.equal(key, 'bk');
|
||||
assert.equal(value, 'bv');
|
||||
} else if (i === 2) {
|
||||
assert.equal(key, 'ck');
|
||||
assert.equal(value, 'cv');
|
||||
}
|
||||
i++;
|
||||
});
|
||||
});
|
||||
|
||||
test('LinkedMap - delete Head and Tail', function () {
|
||||
const map = new LinkedMap<string, number>();
|
||||
|
||||
assert.equal(map.size, 0);
|
||||
|
||||
map.set('1', 1);
|
||||
assert.equal(map.size, 1);
|
||||
map.delete('1');
|
||||
assert.equal(map.get('1'), undefined);
|
||||
assert.equal(map.size, 0);
|
||||
assert.equal([...map.keys()].length, 0);
|
||||
});
|
||||
|
||||
test('LinkedMap - delete Head', function () {
|
||||
const map = new LinkedMap<string, number>();
|
||||
|
||||
assert.equal(map.size, 0);
|
||||
|
||||
map.set('1', 1);
|
||||
map.set('2', 2);
|
||||
assert.equal(map.size, 2);
|
||||
map.delete('1');
|
||||
assert.equal(map.get('2'), 2);
|
||||
assert.equal(map.size, 1);
|
||||
assert.equal([...map.keys()].length, 1);
|
||||
assert.equal([...map.keys()][0], 2);
|
||||
});
|
||||
|
||||
test('LinkedMap - delete Tail', function () {
|
||||
const map = new LinkedMap<string, number>();
|
||||
|
||||
assert.equal(map.size, 0);
|
||||
|
||||
map.set('1', 1);
|
||||
map.set('2', 2);
|
||||
assert.equal(map.size, 2);
|
||||
map.delete('2');
|
||||
assert.equal(map.get('1'), 1);
|
||||
assert.equal(map.size, 1);
|
||||
assert.equal([...map.keys()].length, 1);
|
||||
assert.equal([...map.keys()][0], 1);
|
||||
});
|
||||
|
||||
|
||||
test('PathIterator', () => {
|
||||
const iter = new PathIterator();
|
||||
iter.reset('file:///usr/bin/file.txt');
|
||||
|
||||
assert.equal(iter.value(), 'file:');
|
||||
assert.equal(iter.hasNext(), true);
|
||||
assert.equal(iter.cmp('file:'), 0);
|
||||
assert.ok(iter.cmp('a') < 0);
|
||||
assert.ok(iter.cmp('aile:') < 0);
|
||||
assert.ok(iter.cmp('z') > 0);
|
||||
assert.ok(iter.cmp('zile:') > 0);
|
||||
|
||||
iter.next();
|
||||
assert.equal(iter.value(), 'usr');
|
||||
assert.equal(iter.hasNext(), true);
|
||||
|
||||
iter.next();
|
||||
assert.equal(iter.value(), 'bin');
|
||||
assert.equal(iter.hasNext(), true);
|
||||
|
||||
iter.next();
|
||||
assert.equal(iter.value(), 'file.txt');
|
||||
assert.equal(iter.hasNext(), false);
|
||||
|
||||
iter.next();
|
||||
assert.equal(iter.value(), '');
|
||||
assert.equal(iter.hasNext(), false);
|
||||
iter.next();
|
||||
assert.equal(iter.value(), '');
|
||||
assert.equal(iter.hasNext(), false);
|
||||
|
||||
//
|
||||
iter.reset('/foo/bar/');
|
||||
assert.equal(iter.value(), 'foo');
|
||||
assert.equal(iter.hasNext(), true);
|
||||
|
||||
iter.next();
|
||||
assert.equal(iter.value(), 'bar');
|
||||
assert.equal(iter.hasNext(), false);
|
||||
});
|
||||
|
||||
test('URIIterator', function () {
|
||||
const iter = new UriIterator(false);
|
||||
iter.reset(URI.parse('file:///usr/bin/file.txt'));
|
||||
|
||||
assert.equal(iter.value(), 'file');
|
||||
// assert.equal(iter.cmp('FILE'), 0);
|
||||
assert.equal(iter.cmp('file'), 0);
|
||||
assert.equal(iter.hasNext(), true);
|
||||
iter.next();
|
||||
|
||||
assert.equal(iter.value(), 'usr');
|
||||
assert.equal(iter.hasNext(), true);
|
||||
iter.next();
|
||||
|
||||
assert.equal(iter.value(), 'bin');
|
||||
assert.equal(iter.hasNext(), true);
|
||||
iter.next();
|
||||
|
||||
assert.equal(iter.value(), 'file.txt');
|
||||
assert.equal(iter.hasNext(), false);
|
||||
|
||||
|
||||
iter.reset(URI.parse('file://share/usr/bin/file.txt?foo'));
|
||||
|
||||
// scheme
|
||||
assert.equal(iter.value(), 'file');
|
||||
// assert.equal(iter.cmp('FILE'), 0);
|
||||
assert.equal(iter.cmp('file'), 0);
|
||||
assert.equal(iter.hasNext(), true);
|
||||
iter.next();
|
||||
|
||||
// authority
|
||||
assert.equal(iter.value(), 'share');
|
||||
assert.equal(iter.cmp('SHARe'), 0);
|
||||
assert.equal(iter.hasNext(), true);
|
||||
iter.next();
|
||||
|
||||
// path
|
||||
assert.equal(iter.value(), 'usr');
|
||||
assert.equal(iter.hasNext(), true);
|
||||
iter.next();
|
||||
|
||||
// path
|
||||
assert.equal(iter.value(), 'bin');
|
||||
assert.equal(iter.hasNext(), true);
|
||||
iter.next();
|
||||
|
||||
// path
|
||||
assert.equal(iter.value(), 'file.txt');
|
||||
assert.equal(iter.hasNext(), true);
|
||||
iter.next();
|
||||
|
||||
// query
|
||||
assert.equal(iter.value(), 'foo');
|
||||
assert.equal(iter.cmp('z') > 0, true);
|
||||
assert.equal(iter.cmp('a') < 0, true);
|
||||
assert.equal(iter.hasNext(), false);
|
||||
});
|
||||
|
||||
function assertTernarySearchTree<E>(trie: TernarySearchTree<string, E>, ...elements: [string, E][]) {
|
||||
const map = new Map<string, E>();
|
||||
for (const [key, value] of elements) {
|
||||
map.set(key, value);
|
||||
}
|
||||
map.forEach((value, key) => {
|
||||
assert.equal(trie.get(key), value);
|
||||
});
|
||||
|
||||
// forEach
|
||||
let forEachCount = 0;
|
||||
trie.forEach((element, key) => {
|
||||
assert.equal(element, map.get(key));
|
||||
forEachCount++;
|
||||
});
|
||||
assert.equal(map.size, forEachCount);
|
||||
|
||||
// iterator
|
||||
let iterCount = 0;
|
||||
for (let [key, value] of trie) {
|
||||
assert.equal(value, map.get(key));
|
||||
iterCount++;
|
||||
}
|
||||
assert.equal(map.size, iterCount);
|
||||
}
|
||||
|
||||
test('TernarySearchTree - set', function () {
|
||||
|
||||
let trie = TernarySearchTree.forStrings<number>();
|
||||
trie.set('foobar', 1);
|
||||
trie.set('foobaz', 2);
|
||||
|
||||
assertTernarySearchTree(trie, ['foobar', 1], ['foobaz', 2]); // longer
|
||||
|
||||
trie = TernarySearchTree.forStrings<number>();
|
||||
trie.set('foobar', 1);
|
||||
trie.set('fooba', 2);
|
||||
assertTernarySearchTree(trie, ['foobar', 1], ['fooba', 2]); // shorter
|
||||
|
||||
trie = TernarySearchTree.forStrings<number>();
|
||||
trie.set('foo', 1);
|
||||
trie.set('foo', 2);
|
||||
assertTernarySearchTree(trie, ['foo', 2]);
|
||||
|
||||
trie = TernarySearchTree.forStrings<number>();
|
||||
trie.set('foo', 1);
|
||||
trie.set('foobar', 2);
|
||||
trie.set('bar', 3);
|
||||
trie.set('foob', 4);
|
||||
trie.set('bazz', 5);
|
||||
|
||||
assertTernarySearchTree(trie,
|
||||
['foo', 1],
|
||||
['foobar', 2],
|
||||
['bar', 3],
|
||||
['foob', 4],
|
||||
['bazz', 5]
|
||||
);
|
||||
});
|
||||
|
||||
test('TernarySearchTree - findLongestMatch', function () {
|
||||
|
||||
let trie = TernarySearchTree.forStrings<number>();
|
||||
trie.set('foo', 1);
|
||||
trie.set('foobar', 2);
|
||||
trie.set('foobaz', 3);
|
||||
|
||||
assert.equal(trie.findSubstr('f'), undefined);
|
||||
assert.equal(trie.findSubstr('z'), undefined);
|
||||
assert.equal(trie.findSubstr('foo'), 1);
|
||||
assert.equal(trie.findSubstr('fooö'), 1);
|
||||
assert.equal(trie.findSubstr('fooba'), 1);
|
||||
assert.equal(trie.findSubstr('foobarr'), 2);
|
||||
assert.equal(trie.findSubstr('foobazrr'), 3);
|
||||
});
|
||||
|
||||
test('TernarySearchTree - basics', function () {
|
||||
let trie = new TernarySearchTree<string, number>(new StringIterator());
|
||||
|
||||
trie.set('foo', 1);
|
||||
trie.set('bar', 2);
|
||||
trie.set('foobar', 3);
|
||||
|
||||
assert.equal(trie.get('foo'), 1);
|
||||
assert.equal(trie.get('bar'), 2);
|
||||
assert.equal(trie.get('foobar'), 3);
|
||||
assert.equal(trie.get('foobaz'), undefined);
|
||||
assert.equal(trie.get('foobarr'), undefined);
|
||||
|
||||
assert.equal(trie.findSubstr('fo'), undefined);
|
||||
assert.equal(trie.findSubstr('foo'), 1);
|
||||
assert.equal(trie.findSubstr('foooo'), 1);
|
||||
|
||||
|
||||
trie.delete('foobar');
|
||||
trie.delete('bar');
|
||||
assert.equal(trie.get('foobar'), undefined);
|
||||
assert.equal(trie.get('bar'), undefined);
|
||||
|
||||
trie.set('foobar', 17);
|
||||
trie.set('barr', 18);
|
||||
assert.equal(trie.get('foobar'), 17);
|
||||
assert.equal(trie.get('barr'), 18);
|
||||
assert.equal(trie.get('bar'), undefined);
|
||||
});
|
||||
|
||||
test('TernarySearchTree - delete & cleanup', function () {
|
||||
// normal delete
|
||||
let trie = new TernarySearchTree<string, number>(new StringIterator());
|
||||
trie.set('foo', 1);
|
||||
trie.set('foobar', 2);
|
||||
trie.set('bar', 3);
|
||||
assertTernarySearchTree(trie, ['foo', 1], ['foobar', 2], ['bar', 3]);
|
||||
trie.delete('foo');
|
||||
assertTernarySearchTree(trie, ['foobar', 2], ['bar', 3]);
|
||||
trie.delete('foobar');
|
||||
assertTernarySearchTree(trie, ['bar', 3]);
|
||||
|
||||
// superstr-delete
|
||||
trie = new TernarySearchTree<string, number>(new StringIterator());
|
||||
trie.set('foo', 1);
|
||||
trie.set('foobar', 2);
|
||||
trie.set('bar', 3);
|
||||
trie.deleteSuperstr('foo');
|
||||
assertTernarySearchTree(trie, ['bar', 3]);
|
||||
|
||||
trie = new TernarySearchTree<string, number>(new StringIterator());
|
||||
trie.set('foo', 1);
|
||||
trie.set('foobar', 2);
|
||||
trie.set('bar', 3);
|
||||
trie.deleteSuperstr('fo');
|
||||
assertTernarySearchTree(trie, ['bar', 3]);
|
||||
|
||||
// trie = new TernarySearchTree<string, number>(new StringIterator());
|
||||
// trie.set('foo', 1);
|
||||
// trie.set('foobar', 2);
|
||||
// trie.set('bar', 3);
|
||||
// trie.deleteSuperStr('f');
|
||||
// assertTernarySearchTree(trie, ['bar', 3]);
|
||||
});
|
||||
|
||||
test('TernarySearchTree (PathSegments) - basics', function () {
|
||||
let trie = new TernarySearchTree<string, number>(new PathIterator());
|
||||
|
||||
trie.set('/user/foo/bar', 1);
|
||||
trie.set('/user/foo', 2);
|
||||
trie.set('/user/foo/flip/flop', 3);
|
||||
|
||||
assert.equal(trie.get('/user/foo/bar'), 1);
|
||||
assert.equal(trie.get('/user/foo'), 2);
|
||||
assert.equal(trie.get('/user//foo'), 2);
|
||||
assert.equal(trie.get('/user\\foo'), 2);
|
||||
assert.equal(trie.get('/user/foo/flip/flop'), 3);
|
||||
|
||||
assert.equal(trie.findSubstr('/user/bar'), undefined);
|
||||
assert.equal(trie.findSubstr('/user/foo'), 2);
|
||||
assert.equal(trie.findSubstr('\\user\\foo'), 2);
|
||||
assert.equal(trie.findSubstr('/user//foo'), 2);
|
||||
assert.equal(trie.findSubstr('/user/foo/ba'), 2);
|
||||
assert.equal(trie.findSubstr('/user/foo/far/boo'), 2);
|
||||
assert.equal(trie.findSubstr('/user/foo/bar'), 1);
|
||||
assert.equal(trie.findSubstr('/user/foo/bar/far/boo'), 1);
|
||||
});
|
||||
|
||||
test('TernarySearchTree (PathSegments) - lookup', function () {
|
||||
|
||||
const map = new TernarySearchTree<string, number>(new PathIterator());
|
||||
map.set('/user/foo/bar', 1);
|
||||
map.set('/user/foo', 2);
|
||||
map.set('/user/foo/flip/flop', 3);
|
||||
|
||||
assert.equal(map.get('/foo'), undefined);
|
||||
assert.equal(map.get('/user'), undefined);
|
||||
assert.equal(map.get('/user/foo'), 2);
|
||||
assert.equal(map.get('/user/foo/bar'), 1);
|
||||
assert.equal(map.get('/user/foo/bar/boo'), undefined);
|
||||
});
|
||||
|
||||
test('TernarySearchTree (PathSegments) - superstr', function () {
|
||||
|
||||
const map = new TernarySearchTree<string, number>(new PathIterator());
|
||||
map.set('/user/foo/bar', 1);
|
||||
map.set('/user/foo', 2);
|
||||
map.set('/user/foo/flip/flop', 3);
|
||||
map.set('/usr/foo', 4);
|
||||
|
||||
let item: IteratorResult<number>;
|
||||
let iter = map.findSuperstr('/user');
|
||||
|
||||
item = iter!.next();
|
||||
assert.equal(item.value, 2);
|
||||
assert.equal(item.done, false);
|
||||
item = iter!.next();
|
||||
assert.equal(item.value, 1);
|
||||
assert.equal(item.done, false);
|
||||
item = iter!.next();
|
||||
assert.equal(item.value, 3);
|
||||
assert.equal(item.done, false);
|
||||
item = iter!.next();
|
||||
assert.equal(item.value, undefined);
|
||||
assert.equal(item.done, true);
|
||||
|
||||
iter = map.findSuperstr('/usr');
|
||||
item = iter!.next();
|
||||
assert.equal(item.value, 4);
|
||||
assert.equal(item.done, false);
|
||||
|
||||
item = iter!.next();
|
||||
assert.equal(item.value, undefined);
|
||||
assert.equal(item.done, true);
|
||||
|
||||
assert.equal(map.findSuperstr('/not'), undefined);
|
||||
assert.equal(map.findSuperstr('/us'), undefined);
|
||||
assert.equal(map.findSuperstr('/usrr'), undefined);
|
||||
assert.equal(map.findSuperstr('/userr'), undefined);
|
||||
});
|
||||
|
||||
|
||||
test('TernarySearchTree (PathSegments) - delete_superstr', function () {
|
||||
|
||||
const map = new TernarySearchTree<string, number>(new PathIterator());
|
||||
map.set('/user/foo/bar', 1);
|
||||
map.set('/user/foo', 2);
|
||||
map.set('/user/foo/flip/flop', 3);
|
||||
map.set('/usr/foo', 4);
|
||||
|
||||
assertTernarySearchTree(map,
|
||||
['/user/foo/bar', 1],
|
||||
['/user/foo', 2],
|
||||
['/user/foo/flip/flop', 3],
|
||||
['/usr/foo', 4],
|
||||
);
|
||||
|
||||
// not a segment
|
||||
map.deleteSuperstr('/user/fo');
|
||||
assertTernarySearchTree(map,
|
||||
['/user/foo/bar', 1],
|
||||
['/user/foo', 2],
|
||||
['/user/foo/flip/flop', 3],
|
||||
['/usr/foo', 4],
|
||||
);
|
||||
|
||||
// delete a segment
|
||||
map.set('/user/foo/bar', 1);
|
||||
map.set('/user/foo', 2);
|
||||
map.set('/user/foo/flip/flop', 3);
|
||||
map.set('/usr/foo', 4);
|
||||
map.deleteSuperstr('/user/foo');
|
||||
assertTernarySearchTree(map,
|
||||
['/usr/foo', 4],
|
||||
);
|
||||
});
|
||||
|
||||
test('TernarySearchTree (URI) - basics', function () {
|
||||
let trie = new TernarySearchTree<URI, number>(new UriIterator(false));
|
||||
|
||||
trie.set(URI.file('/user/foo/bar'), 1);
|
||||
trie.set(URI.file('/user/foo'), 2);
|
||||
trie.set(URI.file('/user/foo/flip/flop'), 3);
|
||||
|
||||
assert.equal(trie.get(URI.file('/user/foo/bar')), 1);
|
||||
assert.equal(trie.get(URI.file('/user/foo')), 2);
|
||||
assert.equal(trie.get(URI.file('/user/foo/flip/flop')), 3);
|
||||
|
||||
assert.equal(trie.findSubstr(URI.file('/user/bar')), undefined);
|
||||
assert.equal(trie.findSubstr(URI.file('/user/foo')), 2);
|
||||
assert.equal(trie.findSubstr(URI.file('/user/foo/ba')), 2);
|
||||
assert.equal(trie.findSubstr(URI.file('/user/foo/far/boo')), 2);
|
||||
assert.equal(trie.findSubstr(URI.file('/user/foo/bar')), 1);
|
||||
assert.equal(trie.findSubstr(URI.file('/user/foo/bar/far/boo')), 1);
|
||||
});
|
||||
|
||||
test('TernarySearchTree (URI) - lookup', function () {
|
||||
|
||||
const map = new TernarySearchTree<URI, number>(new UriIterator(false));
|
||||
map.set(URI.parse('http://foo.bar/user/foo/bar'), 1);
|
||||
map.set(URI.parse('http://foo.bar/user/foo?query'), 2);
|
||||
map.set(URI.parse('http://foo.bar/user/foo?QUERY'), 3);
|
||||
map.set(URI.parse('http://foo.bar/user/foo/flip/flop'), 3);
|
||||
|
||||
assert.equal(map.get(URI.parse('http://foo.bar/foo')), undefined);
|
||||
assert.equal(map.get(URI.parse('http://foo.bar/user')), undefined);
|
||||
assert.equal(map.get(URI.parse('http://foo.bar/user/foo/bar')), 1);
|
||||
assert.equal(map.get(URI.parse('http://foo.bar/user/foo?query')), 2);
|
||||
assert.equal(map.get(URI.parse('http://foo.bar/user/foo?Query')), undefined);
|
||||
assert.equal(map.get(URI.parse('http://foo.bar/user/foo?QUERY')), 3);
|
||||
assert.equal(map.get(URI.parse('http://foo.bar/user/foo/bar/boo')), undefined);
|
||||
});
|
||||
|
||||
test('TernarySearchTree (PathSegments) - superstr', function () {
|
||||
|
||||
const map = new TernarySearchTree<URI, number>(new UriIterator(false));
|
||||
map.set(URI.file('/user/foo/bar'), 1);
|
||||
map.set(URI.file('/user/foo'), 2);
|
||||
map.set(URI.file('/user/foo/flip/flop'), 3);
|
||||
map.set(URI.file('/usr/foo'), 4);
|
||||
|
||||
let item: IteratorResult<number>;
|
||||
let iter = map.findSuperstr(URI.file('/user'))!;
|
||||
|
||||
item = iter.next();
|
||||
assert.equal(item.value, 2);
|
||||
assert.equal(item.done, false);
|
||||
item = iter.next();
|
||||
assert.equal(item.value, 1);
|
||||
assert.equal(item.done, false);
|
||||
item = iter.next();
|
||||
assert.equal(item.value, 3);
|
||||
assert.equal(item.done, false);
|
||||
item = iter.next();
|
||||
assert.equal(item.value, undefined);
|
||||
assert.equal(item.done, true);
|
||||
|
||||
iter = map.findSuperstr(URI.file('/usr'))!;
|
||||
item = iter.next();
|
||||
assert.equal(item.value, 4);
|
||||
assert.equal(item.done, false);
|
||||
|
||||
item = iter.next();
|
||||
assert.equal(item.value, undefined);
|
||||
assert.equal(item.done, true);
|
||||
|
||||
iter = map.findSuperstr(URI.file('/'))!;
|
||||
item = iter.next();
|
||||
assert.equal(item.value, 2);
|
||||
assert.equal(item.done, false);
|
||||
item = iter.next();
|
||||
assert.equal(item.value, 1);
|
||||
assert.equal(item.done, false);
|
||||
item = iter.next();
|
||||
assert.equal(item.value, 3);
|
||||
assert.equal(item.done, false);
|
||||
item = iter.next();
|
||||
assert.equal(item.value, 4);
|
||||
assert.equal(item.done, false);
|
||||
item = iter.next();
|
||||
assert.equal(item.value, undefined);
|
||||
assert.equal(item.done, true);
|
||||
|
||||
assert.equal(map.findSuperstr(URI.file('/not')), undefined);
|
||||
assert.equal(map.findSuperstr(URI.file('/us')), undefined);
|
||||
assert.equal(map.findSuperstr(URI.file('/usrr')), undefined);
|
||||
assert.equal(map.findSuperstr(URI.file('/userr')), undefined);
|
||||
});
|
||||
|
||||
|
||||
test('ResourceMap - basics', function () {
|
||||
const map = new ResourceMap<any>();
|
||||
|
||||
const resource1 = URI.parse('some://1');
|
||||
const resource2 = URI.parse('some://2');
|
||||
const resource3 = URI.parse('some://3');
|
||||
const resource4 = URI.parse('some://4');
|
||||
const resource5 = URI.parse('some://5');
|
||||
const resource6 = URI.parse('some://6');
|
||||
|
||||
assert.equal(map.size, 0);
|
||||
|
||||
let res = map.set(resource1, 1);
|
||||
assert.ok(res === map);
|
||||
map.set(resource2, '2');
|
||||
map.set(resource3, true);
|
||||
|
||||
const values = [...map.values()];
|
||||
assert.equal(values[0], 1);
|
||||
assert.equal(values[1], '2');
|
||||
assert.equal(values[2], true);
|
||||
|
||||
let counter = 0;
|
||||
map.forEach((value, key, mapObj) => {
|
||||
assert.equal(value, values[counter++]);
|
||||
assert.ok(URI.isUri(key));
|
||||
assert.ok(map === mapObj);
|
||||
});
|
||||
|
||||
const obj = Object.create(null);
|
||||
map.set(resource4, obj);
|
||||
|
||||
const date = Date.now();
|
||||
map.set(resource5, date);
|
||||
|
||||
assert.equal(map.size, 5);
|
||||
assert.equal(map.get(resource1), 1);
|
||||
assert.equal(map.get(resource2), '2');
|
||||
assert.equal(map.get(resource3), true);
|
||||
assert.equal(map.get(resource4), obj);
|
||||
assert.equal(map.get(resource5), date);
|
||||
assert.ok(!map.get(resource6));
|
||||
|
||||
map.delete(resource6);
|
||||
assert.equal(map.size, 5);
|
||||
assert.ok(map.delete(resource1));
|
||||
assert.ok(map.delete(resource2));
|
||||
assert.ok(map.delete(resource3));
|
||||
assert.ok(map.delete(resource4));
|
||||
assert.ok(map.delete(resource5));
|
||||
|
||||
assert.equal(map.size, 0);
|
||||
assert.ok(!map.get(resource5));
|
||||
assert.ok(!map.get(resource4));
|
||||
assert.ok(!map.get(resource3));
|
||||
assert.ok(!map.get(resource2));
|
||||
assert.ok(!map.get(resource1));
|
||||
|
||||
map.set(resource1, 1);
|
||||
map.set(resource2, '2');
|
||||
map.set(resource3, true);
|
||||
|
||||
assert.ok(map.has(resource1));
|
||||
assert.equal(map.get(resource1), 1);
|
||||
assert.equal(map.get(resource2), '2');
|
||||
assert.equal(map.get(resource3), true);
|
||||
|
||||
map.clear();
|
||||
|
||||
assert.equal(map.size, 0);
|
||||
assert.ok(!map.get(resource1));
|
||||
assert.ok(!map.get(resource2));
|
||||
assert.ok(!map.get(resource3));
|
||||
assert.ok(!map.has(resource1));
|
||||
|
||||
map.set(resource1, false);
|
||||
map.set(resource2, 0);
|
||||
|
||||
assert.ok(map.has(resource1));
|
||||
assert.ok(map.has(resource2));
|
||||
});
|
||||
|
||||
test('ResourceMap - files (do NOT ignorecase)', function () {
|
||||
const map = new ResourceMap<any>();
|
||||
|
||||
const fileA = URI.parse('file://some/filea');
|
||||
const fileB = URI.parse('some://some/other/fileb');
|
||||
const fileAUpper = URI.parse('file://SOME/FILEA');
|
||||
|
||||
map.set(fileA, 'true');
|
||||
assert.equal(map.get(fileA), 'true');
|
||||
|
||||
assert.ok(!map.get(fileAUpper));
|
||||
|
||||
assert.ok(!map.get(fileB));
|
||||
|
||||
map.set(fileAUpper, 'false');
|
||||
assert.equal(map.get(fileAUpper), 'false');
|
||||
|
||||
assert.equal(map.get(fileA), 'true');
|
||||
|
||||
const windowsFile = URI.file('c:\\test with %25\\c#code');
|
||||
const uncFile = URI.file('\\\\shäres\\path\\c#\\plugin.json');
|
||||
|
||||
map.set(windowsFile, 'true');
|
||||
map.set(uncFile, 'true');
|
||||
|
||||
assert.equal(map.get(windowsFile), 'true');
|
||||
assert.equal(map.get(uncFile), 'true');
|
||||
});
|
||||
|
||||
test('ResourceMap - files (ignorecase)', function () {
|
||||
const map = new ResourceMap<any>(uri => extUriIgnorePathCase.getComparisonKey(uri));
|
||||
|
||||
const fileA = URI.parse('file://some/filea');
|
||||
const fileB = URI.parse('some://some/other/fileb');
|
||||
const fileAUpper = URI.parse('file://SOME/FILEA');
|
||||
|
||||
map.set(fileA, 'true');
|
||||
assert.equal(map.get(fileA), 'true');
|
||||
|
||||
assert.equal(map.get(fileAUpper), 'true');
|
||||
|
||||
assert.ok(!map.get(fileB));
|
||||
|
||||
map.set(fileAUpper, 'false');
|
||||
assert.equal(map.get(fileAUpper), 'false');
|
||||
|
||||
assert.equal(map.get(fileA), 'false');
|
||||
|
||||
const windowsFile = URI.file('c:\\test with %25\\c#code');
|
||||
const uncFile = URI.file('\\\\shäres\\path\\c#\\plugin.json');
|
||||
|
||||
map.set(windowsFile, 'true');
|
||||
map.set(uncFile, 'true');
|
||||
|
||||
assert.equal(map.get(windowsFile), 'true');
|
||||
assert.equal(map.get(uncFile), 'true');
|
||||
});
|
||||
});
|
||||
72
lib/vscode/src/vs/base/test/common/markdownString.test.ts
Normal file
72
lib/vscode/src/vs/base/test/common/markdownString.test.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { MarkdownString } from 'vs/base/common/htmlContent';
|
||||
|
||||
suite('MarkdownString', () => {
|
||||
|
||||
test('appendText', () => {
|
||||
|
||||
const mds = new MarkdownString();
|
||||
mds.appendText('# foo\n*bar*');
|
||||
|
||||
assert.equal(mds.value, '\\# foo\n\n\\*bar\\*');
|
||||
});
|
||||
|
||||
suite('ThemeIcons', () => {
|
||||
|
||||
suite('Support On', () => {
|
||||
|
||||
test('appendText', () => {
|
||||
const mds = new MarkdownString(undefined, { supportThemeIcons: true });
|
||||
mds.appendText('$(zap) $(not a theme icon) $(add)');
|
||||
|
||||
assert.equal(mds.value, '\\\\$\\(zap\\) $\\(not a theme icon\\) \\\\$\\(add\\)');
|
||||
});
|
||||
|
||||
test('appendMarkdown', () => {
|
||||
const mds = new MarkdownString(undefined, { supportThemeIcons: true });
|
||||
mds.appendMarkdown('$(zap) $(not a theme icon) $(add)');
|
||||
|
||||
assert.equal(mds.value, '$(zap) $(not a theme icon) $(add)');
|
||||
});
|
||||
|
||||
test('appendMarkdown with escaped icon', () => {
|
||||
const mds = new MarkdownString(undefined, { supportThemeIcons: true });
|
||||
mds.appendMarkdown('\\$(zap) $(not a theme icon) $(add)');
|
||||
|
||||
assert.equal(mds.value, '\\$(zap) $(not a theme icon) $(add)');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
suite('Support Off', () => {
|
||||
|
||||
test('appendText', () => {
|
||||
const mds = new MarkdownString(undefined, { supportThemeIcons: false });
|
||||
mds.appendText('$(zap) $(not a theme icon) $(add)');
|
||||
|
||||
assert.equal(mds.value, '$\\(zap\\) $\\(not a theme icon\\) $\\(add\\)');
|
||||
});
|
||||
|
||||
test('appendMarkdown', () => {
|
||||
const mds = new MarkdownString(undefined, { supportThemeIcons: false });
|
||||
mds.appendMarkdown('$(zap) $(not a theme icon) $(add)');
|
||||
|
||||
assert.equal(mds.value, '$(zap) $(not a theme icon) $(add)');
|
||||
});
|
||||
|
||||
test('appendMarkdown with escaped icon', () => {
|
||||
const mds = new MarkdownString(undefined, { supportThemeIcons: true });
|
||||
mds.appendMarkdown('\\$(zap) $(not a theme icon) $(add)');
|
||||
|
||||
assert.equal(mds.value, '\\$(zap) $(not a theme icon) $(add)');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
38
lib/vscode/src/vs/base/test/common/marshalling.test.ts
Normal file
38
lib/vscode/src/vs/base/test/common/marshalling.test.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as assert from 'assert';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { parse, stringify } from 'vs/base/common/marshalling';
|
||||
|
||||
suite('Marshalling', () => {
|
||||
|
||||
test('RegExp', () => {
|
||||
let value = /foo/img;
|
||||
let raw = stringify(value);
|
||||
let clone = <RegExp>parse(raw);
|
||||
|
||||
assert.equal(value.source, clone.source);
|
||||
assert.equal(value.global, clone.global);
|
||||
assert.equal(value.ignoreCase, clone.ignoreCase);
|
||||
assert.equal(value.multiline, clone.multiline);
|
||||
});
|
||||
|
||||
test('URI', () => {
|
||||
const value = URI.from({ scheme: 'file', authority: 'server', path: '/shares/c#files', query: 'q', fragment: 'f' });
|
||||
const raw = stringify(value);
|
||||
const clone = <URI>parse(raw);
|
||||
|
||||
assert.equal(value.scheme, clone.scheme);
|
||||
assert.equal(value.authority, clone.authority);
|
||||
assert.equal(value.path, clone.path);
|
||||
assert.equal(value.query, clone.query);
|
||||
assert.equal(value.fragment, clone.fragment);
|
||||
});
|
||||
|
||||
test('Bug 16793:# in folder name => mirror models get out of sync', () => {
|
||||
const uri1 = URI.file('C:\\C#\\file.txt');
|
||||
assert.equal(parse(stringify(uri1)).toString(), uri1.toString());
|
||||
});
|
||||
});
|
||||
129
lib/vscode/src/vs/base/test/common/mime.test.ts
Normal file
129
lib/vscode/src/vs/base/test/common/mime.test.ts
Normal file
@@ -0,0 +1,129 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { guessMimeTypes, registerTextMime } from 'vs/base/common/mime';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
suite('Mime', () => {
|
||||
|
||||
test('Dynamically Register Text Mime', () => {
|
||||
let guess = guessMimeTypes(URI.file('foo.monaco'));
|
||||
assert.deepEqual(guess, ['application/unknown']);
|
||||
|
||||
registerTextMime({ id: 'monaco', extension: '.monaco', mime: 'text/monaco' });
|
||||
guess = guessMimeTypes(URI.file('foo.monaco'));
|
||||
assert.deepEqual(guess, ['text/monaco', 'text/plain']);
|
||||
|
||||
guess = guessMimeTypes(URI.file('.monaco'));
|
||||
assert.deepEqual(guess, ['text/monaco', 'text/plain']);
|
||||
|
||||
registerTextMime({ id: 'codefile', filename: 'Codefile', mime: 'text/code' });
|
||||
guess = guessMimeTypes(URI.file('Codefile'));
|
||||
assert.deepEqual(guess, ['text/code', 'text/plain']);
|
||||
|
||||
guess = guessMimeTypes(URI.file('foo.Codefile'));
|
||||
assert.deepEqual(guess, ['application/unknown']);
|
||||
|
||||
registerTextMime({ id: 'docker', filepattern: 'Docker*', mime: 'text/docker' });
|
||||
guess = guessMimeTypes(URI.file('Docker-debug'));
|
||||
assert.deepEqual(guess, ['text/docker', 'text/plain']);
|
||||
|
||||
guess = guessMimeTypes(URI.file('docker-PROD'));
|
||||
assert.deepEqual(guess, ['text/docker', 'text/plain']);
|
||||
|
||||
registerTextMime({ id: 'niceregex', mime: 'text/nice-regex', firstline: /RegexesAreNice/ });
|
||||
guess = guessMimeTypes(URI.file('Randomfile.noregistration'), 'RegexesAreNice');
|
||||
assert.deepEqual(guess, ['text/nice-regex', 'text/plain']);
|
||||
|
||||
guess = guessMimeTypes(URI.file('Randomfile.noregistration'), 'RegexesAreNotNice');
|
||||
assert.deepEqual(guess, ['application/unknown']);
|
||||
|
||||
guess = guessMimeTypes(URI.file('Codefile'), 'RegexesAreNice');
|
||||
assert.deepEqual(guess, ['text/code', 'text/plain']);
|
||||
});
|
||||
|
||||
test('Mimes Priority', () => {
|
||||
registerTextMime({ id: 'monaco', extension: '.monaco', mime: 'text/monaco' });
|
||||
registerTextMime({ id: 'foobar', mime: 'text/foobar', firstline: /foobar/ });
|
||||
|
||||
let guess = guessMimeTypes(URI.file('foo.monaco'));
|
||||
assert.deepEqual(guess, ['text/monaco', 'text/plain']);
|
||||
|
||||
guess = guessMimeTypes(URI.file('foo.monaco'), 'foobar');
|
||||
assert.deepEqual(guess, ['text/monaco', 'text/plain']);
|
||||
|
||||
registerTextMime({ id: 'docker', filename: 'dockerfile', mime: 'text/winner' });
|
||||
registerTextMime({ id: 'docker', filepattern: 'dockerfile*', mime: 'text/looser' });
|
||||
guess = guessMimeTypes(URI.file('dockerfile'));
|
||||
assert.deepEqual(guess, ['text/winner', 'text/plain']);
|
||||
|
||||
registerTextMime({ id: 'azure-looser', mime: 'text/azure-looser', firstline: /azure/ });
|
||||
registerTextMime({ id: 'azure-winner', mime: 'text/azure-winner', firstline: /azure/ });
|
||||
guess = guessMimeTypes(URI.file('azure'), 'azure');
|
||||
assert.deepEqual(guess, ['text/azure-winner', 'text/plain']);
|
||||
});
|
||||
|
||||
test('Specificity priority 1', () => {
|
||||
registerTextMime({ id: 'monaco2', extension: '.monaco2', mime: 'text/monaco2' });
|
||||
registerTextMime({ id: 'monaco2', filename: 'specific.monaco2', mime: 'text/specific-monaco2' });
|
||||
|
||||
assert.deepEqual(guessMimeTypes(URI.file('specific.monaco2')), ['text/specific-monaco2', 'text/plain']);
|
||||
assert.deepEqual(guessMimeTypes(URI.file('foo.monaco2')), ['text/monaco2', 'text/plain']);
|
||||
});
|
||||
|
||||
test('Specificity priority 2', () => {
|
||||
registerTextMime({ id: 'monaco3', filename: 'specific.monaco3', mime: 'text/specific-monaco3' });
|
||||
registerTextMime({ id: 'monaco3', extension: '.monaco3', mime: 'text/monaco3' });
|
||||
|
||||
assert.deepEqual(guessMimeTypes(URI.file('specific.monaco3')), ['text/specific-monaco3', 'text/plain']);
|
||||
assert.deepEqual(guessMimeTypes(URI.file('foo.monaco3')), ['text/monaco3', 'text/plain']);
|
||||
});
|
||||
|
||||
test('Mimes Priority - Longest Extension wins', () => {
|
||||
registerTextMime({ id: 'monaco', extension: '.monaco', mime: 'text/monaco' });
|
||||
registerTextMime({ id: 'monaco', extension: '.monaco.xml', mime: 'text/monaco-xml' });
|
||||
registerTextMime({ id: 'monaco', extension: '.monaco.xml.build', mime: 'text/monaco-xml-build' });
|
||||
|
||||
let guess = guessMimeTypes(URI.file('foo.monaco'));
|
||||
assert.deepEqual(guess, ['text/monaco', 'text/plain']);
|
||||
|
||||
guess = guessMimeTypes(URI.file('foo.monaco.xml'));
|
||||
assert.deepEqual(guess, ['text/monaco-xml', 'text/plain']);
|
||||
|
||||
guess = guessMimeTypes(URI.file('foo.monaco.xml.build'));
|
||||
assert.deepEqual(guess, ['text/monaco-xml-build', 'text/plain']);
|
||||
});
|
||||
|
||||
test('Mimes Priority - User configured wins', () => {
|
||||
registerTextMime({ id: 'monaco', extension: '.monaco.xnl', mime: 'text/monaco', userConfigured: true });
|
||||
registerTextMime({ id: 'monaco', extension: '.monaco.xml', mime: 'text/monaco-xml' });
|
||||
|
||||
let guess = guessMimeTypes(URI.file('foo.monaco.xnl'));
|
||||
assert.deepEqual(guess, ['text/monaco', 'text/plain']);
|
||||
});
|
||||
|
||||
test('Mimes Priority - Pattern matches on path if specified', () => {
|
||||
registerTextMime({ id: 'monaco', filepattern: '**/dot.monaco.xml', mime: 'text/monaco' });
|
||||
registerTextMime({ id: 'other', filepattern: '*ot.other.xml', mime: 'text/other' });
|
||||
|
||||
let guess = guessMimeTypes(URI.file('/some/path/dot.monaco.xml'));
|
||||
assert.deepEqual(guess, ['text/monaco', 'text/plain']);
|
||||
});
|
||||
|
||||
test('Mimes Priority - Last registered mime wins', () => {
|
||||
registerTextMime({ id: 'monaco', filepattern: '**/dot.monaco.xml', mime: 'text/monaco' });
|
||||
registerTextMime({ id: 'other', filepattern: '**/dot.monaco.xml', mime: 'text/other' });
|
||||
|
||||
let guess = guessMimeTypes(URI.file('/some/path/dot.monaco.xml'));
|
||||
assert.deepEqual(guess, ['text/other', 'text/plain']);
|
||||
});
|
||||
|
||||
test('Data URIs', () => {
|
||||
registerTextMime({ id: 'data', extension: '.data', mime: 'text/data' });
|
||||
|
||||
assert.deepEqual(guessMimeTypes(URI.parse(`data:;label:something.data;description:data,`)), ['text/data', 'text/plain']);
|
||||
});
|
||||
});
|
||||
12
lib/vscode/src/vs/base/test/common/mock.ts
Normal file
12
lib/vscode/src/vs/base/test/common/mock.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export interface Ctor<T> {
|
||||
new(): T;
|
||||
}
|
||||
|
||||
export function mock<T>(): Ctor<T> {
|
||||
return function () { } as any;
|
||||
}
|
||||
65
lib/vscode/src/vs/base/test/common/normalization.test.ts
Normal file
65
lib/vscode/src/vs/base/test/common/normalization.test.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { removeAccents } from 'vs/base/common/normalization';
|
||||
|
||||
suite('Normalization', () => {
|
||||
|
||||
test('removeAccents', function () {
|
||||
assert.equal(removeAccents('joào'), 'joao');
|
||||
assert.equal(removeAccents('joáo'), 'joao');
|
||||
assert.equal(removeAccents('joâo'), 'joao');
|
||||
assert.equal(removeAccents('joäo'), 'joao');
|
||||
// assert.equal(strings.removeAccents('joæo'), 'joao'); // not an accent
|
||||
assert.equal(removeAccents('joão'), 'joao');
|
||||
assert.equal(removeAccents('joåo'), 'joao');
|
||||
assert.equal(removeAccents('joåo'), 'joao');
|
||||
assert.equal(removeAccents('joāo'), 'joao');
|
||||
|
||||
assert.equal(removeAccents('fôo'), 'foo');
|
||||
assert.equal(removeAccents('föo'), 'foo');
|
||||
assert.equal(removeAccents('fòo'), 'foo');
|
||||
assert.equal(removeAccents('fóo'), 'foo');
|
||||
// assert.equal(strings.removeAccents('fœo'), 'foo');
|
||||
// assert.equal(strings.removeAccents('føo'), 'foo');
|
||||
assert.equal(removeAccents('fōo'), 'foo');
|
||||
assert.equal(removeAccents('fõo'), 'foo');
|
||||
|
||||
assert.equal(removeAccents('andrè'), 'andre');
|
||||
assert.equal(removeAccents('andré'), 'andre');
|
||||
assert.equal(removeAccents('andrê'), 'andre');
|
||||
assert.equal(removeAccents('andrë'), 'andre');
|
||||
assert.equal(removeAccents('andrē'), 'andre');
|
||||
assert.equal(removeAccents('andrė'), 'andre');
|
||||
assert.equal(removeAccents('andrę'), 'andre');
|
||||
|
||||
assert.equal(removeAccents('hvîc'), 'hvic');
|
||||
assert.equal(removeAccents('hvïc'), 'hvic');
|
||||
assert.equal(removeAccents('hvíc'), 'hvic');
|
||||
assert.equal(removeAccents('hvīc'), 'hvic');
|
||||
assert.equal(removeAccents('hvįc'), 'hvic');
|
||||
assert.equal(removeAccents('hvìc'), 'hvic');
|
||||
|
||||
assert.equal(removeAccents('ûdo'), 'udo');
|
||||
assert.equal(removeAccents('üdo'), 'udo');
|
||||
assert.equal(removeAccents('ùdo'), 'udo');
|
||||
assert.equal(removeAccents('údo'), 'udo');
|
||||
assert.equal(removeAccents('ūdo'), 'udo');
|
||||
|
||||
assert.equal(removeAccents('heÿ'), 'hey');
|
||||
|
||||
// assert.equal(strings.removeAccents('gruß'), 'grus');
|
||||
assert.equal(removeAccents('gruś'), 'grus');
|
||||
assert.equal(removeAccents('gruš'), 'grus');
|
||||
|
||||
assert.equal(removeAccents('çool'), 'cool');
|
||||
assert.equal(removeAccents('ćool'), 'cool');
|
||||
assert.equal(removeAccents('čool'), 'cool');
|
||||
|
||||
assert.equal(removeAccents('ñice'), 'nice');
|
||||
assert.equal(removeAccents('ńice'), 'nice');
|
||||
});
|
||||
});
|
||||
228
lib/vscode/src/vs/base/test/common/objects.test.ts
Normal file
228
lib/vscode/src/vs/base/test/common/objects.test.ts
Normal file
@@ -0,0 +1,228 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as assert from 'assert';
|
||||
import * as objects from 'vs/base/common/objects';
|
||||
|
||||
let check = (one: any, other: any, msg: string) => {
|
||||
assert(objects.equals(one, other), msg);
|
||||
assert(objects.equals(other, one), '[reverse] ' + msg);
|
||||
};
|
||||
|
||||
let checkNot = (one: any, other: any, msg: string) => {
|
||||
assert(!objects.equals(one, other), msg);
|
||||
assert(!objects.equals(other, one), '[reverse] ' + msg);
|
||||
};
|
||||
|
||||
suite('Objects', () => {
|
||||
|
||||
test('equals', () => {
|
||||
check(null, null, 'null');
|
||||
check(undefined, undefined, 'undefined');
|
||||
check(1234, 1234, 'numbers');
|
||||
check('', '', 'empty strings');
|
||||
check('1234', '1234', 'strings');
|
||||
check([], [], 'empty arrays');
|
||||
// check(['', 123], ['', 123], 'arrays');
|
||||
check([[1, 2, 3], [4, 5, 6]], [[1, 2, 3], [4, 5, 6]], 'nested arrays');
|
||||
check({}, {}, 'empty objects');
|
||||
check({ a: 1, b: '123' }, { a: 1, b: '123' }, 'objects');
|
||||
check({ a: 1, b: '123' }, { b: '123', a: 1 }, 'objects (key order)');
|
||||
check({ a: { b: 1, c: 2 }, b: 3 }, { a: { b: 1, c: 2 }, b: 3 }, 'nested objects');
|
||||
|
||||
checkNot(null, undefined, 'null != undefined');
|
||||
checkNot(null, '', 'null != empty string');
|
||||
checkNot(null, [], 'null != empty array');
|
||||
checkNot(null, {}, 'null != empty object');
|
||||
checkNot(null, 0, 'null != zero');
|
||||
checkNot(undefined, '', 'undefined != empty string');
|
||||
checkNot(undefined, [], 'undefined != empty array');
|
||||
checkNot(undefined, {}, 'undefined != empty object');
|
||||
checkNot(undefined, 0, 'undefined != zero');
|
||||
checkNot('', [], 'empty string != empty array');
|
||||
checkNot('', {}, 'empty string != empty object');
|
||||
checkNot('', 0, 'empty string != zero');
|
||||
checkNot([], {}, 'empty array != empty object');
|
||||
checkNot([], 0, 'empty array != zero');
|
||||
checkNot(0, [], 'zero != empty array');
|
||||
|
||||
checkNot('1234', 1234, 'string !== number');
|
||||
|
||||
checkNot([[1, 2, 3], [4, 5, 6]], [[1, 2, 3], [4, 5, 6000]], 'arrays');
|
||||
checkNot({ a: { b: 1, c: 2 }, b: 3 }, { b: 3, a: { b: 9, c: 2 } }, 'objects');
|
||||
});
|
||||
|
||||
test('mixin - array', function () {
|
||||
|
||||
let foo: any = {};
|
||||
objects.mixin(foo, { bar: [1, 2, 3] });
|
||||
|
||||
assert(foo.bar);
|
||||
assert(Array.isArray(foo.bar));
|
||||
assert.equal(foo.bar.length, 3);
|
||||
assert.equal(foo.bar[0], 1);
|
||||
assert.equal(foo.bar[1], 2);
|
||||
assert.equal(foo.bar[2], 3);
|
||||
});
|
||||
|
||||
test('mixin - no overwrite', function () {
|
||||
let foo: any = {
|
||||
bar: '123'
|
||||
};
|
||||
|
||||
let bar: any = {
|
||||
bar: '456'
|
||||
};
|
||||
|
||||
objects.mixin(foo, bar, false);
|
||||
|
||||
assert.equal(foo.bar, '123');
|
||||
});
|
||||
|
||||
test('cloneAndChange', () => {
|
||||
let o1 = { something: 'hello' };
|
||||
let o = {
|
||||
o1: o1,
|
||||
o2: o1
|
||||
};
|
||||
assert.deepEqual(objects.cloneAndChange(o, () => { }), o);
|
||||
});
|
||||
|
||||
test('safeStringify', () => {
|
||||
let obj1: any = {
|
||||
friend: null
|
||||
};
|
||||
|
||||
let obj2: any = {
|
||||
friend: null
|
||||
};
|
||||
|
||||
obj1.friend = obj2;
|
||||
obj2.friend = obj1;
|
||||
|
||||
let arr: any = [1];
|
||||
arr.push(arr);
|
||||
|
||||
let circular: any = {
|
||||
a: 42,
|
||||
b: null,
|
||||
c: [
|
||||
obj1, obj2
|
||||
],
|
||||
d: null
|
||||
};
|
||||
|
||||
arr.push(circular);
|
||||
|
||||
|
||||
circular.b = circular;
|
||||
circular.d = arr;
|
||||
|
||||
let result = objects.safeStringify(circular);
|
||||
|
||||
assert.deepEqual(JSON.parse(result), {
|
||||
a: 42,
|
||||
b: '[Circular]',
|
||||
c: [
|
||||
{
|
||||
friend: {
|
||||
friend: '[Circular]'
|
||||
}
|
||||
},
|
||||
'[Circular]'
|
||||
],
|
||||
d: [1, '[Circular]', '[Circular]']
|
||||
});
|
||||
});
|
||||
|
||||
test('distinct', () => {
|
||||
let base = {
|
||||
one: 'one',
|
||||
two: 2,
|
||||
three: {
|
||||
3: true
|
||||
},
|
||||
four: false
|
||||
};
|
||||
|
||||
let diff = objects.distinct(base, base);
|
||||
assert.deepEqual(diff, {});
|
||||
|
||||
let obj = {};
|
||||
|
||||
diff = objects.distinct(base, obj);
|
||||
assert.deepEqual(diff, {});
|
||||
|
||||
obj = {
|
||||
one: 'one',
|
||||
two: 2
|
||||
};
|
||||
|
||||
diff = objects.distinct(base, obj);
|
||||
assert.deepEqual(diff, {});
|
||||
|
||||
obj = {
|
||||
three: {
|
||||
3: true
|
||||
},
|
||||
four: false
|
||||
};
|
||||
|
||||
diff = objects.distinct(base, obj);
|
||||
assert.deepEqual(diff, {});
|
||||
|
||||
obj = {
|
||||
one: 'two',
|
||||
two: 2,
|
||||
three: {
|
||||
3: true
|
||||
},
|
||||
four: true
|
||||
};
|
||||
|
||||
diff = objects.distinct(base, obj);
|
||||
assert.deepEqual(diff, {
|
||||
one: 'two',
|
||||
four: true
|
||||
});
|
||||
|
||||
obj = {
|
||||
one: null,
|
||||
two: 2,
|
||||
three: {
|
||||
3: true
|
||||
},
|
||||
four: undefined
|
||||
};
|
||||
|
||||
diff = objects.distinct(base, obj);
|
||||
assert.deepEqual(diff, {
|
||||
one: null,
|
||||
four: undefined
|
||||
});
|
||||
|
||||
obj = {
|
||||
one: 'two',
|
||||
two: 3,
|
||||
three: { 3: false },
|
||||
four: true
|
||||
};
|
||||
|
||||
diff = objects.distinct(base, obj);
|
||||
assert.deepEqual(diff, obj);
|
||||
});
|
||||
|
||||
test('getCaseInsensitive', () => {
|
||||
const obj1 = {
|
||||
lowercase: 123,
|
||||
mIxEdCaSe: 456
|
||||
};
|
||||
|
||||
assert.equal(obj1.lowercase, objects.getCaseInsensitive(obj1, 'lowercase'));
|
||||
assert.equal(obj1.lowercase, objects.getCaseInsensitive(obj1, 'lOwErCaSe'));
|
||||
|
||||
assert.equal(obj1.mIxEdCaSe, objects.getCaseInsensitive(obj1, 'MIXEDCASE'));
|
||||
assert.equal(obj1.mIxEdCaSe, objects.getCaseInsensitive(obj1, 'mixedcase'));
|
||||
});
|
||||
});
|
||||
184
lib/vscode/src/vs/base/test/common/paging.test.ts
Normal file
184
lib/vscode/src/vs/base/test/common/paging.test.ts
Normal file
@@ -0,0 +1,184 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { IPager, PagedModel } from 'vs/base/common/paging';
|
||||
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { isPromiseCanceledError, canceled } from 'vs/base/common/errors';
|
||||
|
||||
function getPage(pageIndex: number, cancellationToken: CancellationToken): Promise<number[]> {
|
||||
if (cancellationToken.isCancellationRequested) {
|
||||
return Promise.reject(canceled());
|
||||
}
|
||||
|
||||
return Promise.resolve([0, 1, 2, 3, 4].map(i => i + (pageIndex * 5)));
|
||||
}
|
||||
|
||||
class TestPager implements IPager<number> {
|
||||
|
||||
readonly firstPage = [0, 1, 2, 3, 4];
|
||||
readonly pageSize = 5;
|
||||
readonly total = 100;
|
||||
readonly getPage: (pageIndex: number, cancellationToken: CancellationToken) => Promise<number[]>;
|
||||
|
||||
constructor(getPageFn?: (pageIndex: number, cancellationToken: CancellationToken) => Promise<number[]>) {
|
||||
this.getPage = getPageFn || getPage;
|
||||
}
|
||||
}
|
||||
|
||||
suite('PagedModel', () => {
|
||||
|
||||
test('isResolved', () => {
|
||||
const pager = new TestPager();
|
||||
const model = new PagedModel(pager);
|
||||
|
||||
assert(model.isResolved(0));
|
||||
assert(model.isResolved(1));
|
||||
assert(model.isResolved(2));
|
||||
assert(model.isResolved(3));
|
||||
assert(model.isResolved(4));
|
||||
assert(!model.isResolved(5));
|
||||
assert(!model.isResolved(6));
|
||||
assert(!model.isResolved(7));
|
||||
assert(!model.isResolved(8));
|
||||
assert(!model.isResolved(9));
|
||||
assert(!model.isResolved(10));
|
||||
assert(!model.isResolved(99));
|
||||
});
|
||||
|
||||
test('resolve single', async () => {
|
||||
const pager = new TestPager();
|
||||
const model = new PagedModel(pager);
|
||||
|
||||
assert(!model.isResolved(5));
|
||||
|
||||
await model.resolve(5, CancellationToken.None);
|
||||
assert(model.isResolved(5));
|
||||
});
|
||||
|
||||
test('resolve page', async () => {
|
||||
const pager = new TestPager();
|
||||
const model = new PagedModel(pager);
|
||||
|
||||
assert(!model.isResolved(5));
|
||||
assert(!model.isResolved(6));
|
||||
assert(!model.isResolved(7));
|
||||
assert(!model.isResolved(8));
|
||||
assert(!model.isResolved(9));
|
||||
assert(!model.isResolved(10));
|
||||
|
||||
await model.resolve(5, CancellationToken.None);
|
||||
assert(model.isResolved(5));
|
||||
assert(model.isResolved(6));
|
||||
assert(model.isResolved(7));
|
||||
assert(model.isResolved(8));
|
||||
assert(model.isResolved(9));
|
||||
assert(!model.isResolved(10));
|
||||
});
|
||||
|
||||
test('resolve page 2', async () => {
|
||||
const pager = new TestPager();
|
||||
const model = new PagedModel(pager);
|
||||
|
||||
assert(!model.isResolved(5));
|
||||
assert(!model.isResolved(6));
|
||||
assert(!model.isResolved(7));
|
||||
assert(!model.isResolved(8));
|
||||
assert(!model.isResolved(9));
|
||||
assert(!model.isResolved(10));
|
||||
|
||||
await model.resolve(10, CancellationToken.None);
|
||||
assert(!model.isResolved(5));
|
||||
assert(!model.isResolved(6));
|
||||
assert(!model.isResolved(7));
|
||||
assert(!model.isResolved(8));
|
||||
assert(!model.isResolved(9));
|
||||
assert(model.isResolved(10));
|
||||
});
|
||||
|
||||
test('preemptive cancellation works', async function () {
|
||||
const pager = new TestPager(() => {
|
||||
assert(false);
|
||||
return Promise.resolve([]);
|
||||
});
|
||||
|
||||
const model = new PagedModel(pager);
|
||||
|
||||
try {
|
||||
await model.resolve(5, CancellationToken.Cancelled);
|
||||
return assert(false);
|
||||
}
|
||||
catch (err) {
|
||||
return assert(isPromiseCanceledError(err));
|
||||
}
|
||||
});
|
||||
|
||||
test('cancellation works', function () {
|
||||
const pager = new TestPager((_, token) => new Promise((_, e) => {
|
||||
token.onCancellationRequested(() => e(canceled()));
|
||||
}));
|
||||
|
||||
const model = new PagedModel(pager);
|
||||
const tokenSource = new CancellationTokenSource();
|
||||
|
||||
const promise = model.resolve(5, tokenSource.token).then(
|
||||
() => assert(false),
|
||||
err => assert(isPromiseCanceledError(err))
|
||||
);
|
||||
|
||||
setTimeout(() => tokenSource.cancel(), 10);
|
||||
|
||||
return promise;
|
||||
});
|
||||
|
||||
test('same page cancellation works', function () {
|
||||
let state = 'idle';
|
||||
|
||||
const pager = new TestPager((pageIndex, token) => {
|
||||
state = 'resolving';
|
||||
|
||||
return new Promise((_, e) => {
|
||||
token.onCancellationRequested(() => {
|
||||
state = 'idle';
|
||||
e(canceled());
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const model = new PagedModel(pager);
|
||||
|
||||
assert.equal(state, 'idle');
|
||||
|
||||
const tokenSource1 = new CancellationTokenSource();
|
||||
const promise1 = model.resolve(5, tokenSource1.token).then(
|
||||
() => assert(false),
|
||||
err => assert(isPromiseCanceledError(err))
|
||||
);
|
||||
|
||||
assert.equal(state, 'resolving');
|
||||
|
||||
const tokenSource2 = new CancellationTokenSource();
|
||||
const promise2 = model.resolve(6, tokenSource2.token).then(
|
||||
() => assert(false),
|
||||
err => assert(isPromiseCanceledError(err))
|
||||
);
|
||||
|
||||
assert.equal(state, 'resolving');
|
||||
|
||||
setTimeout(() => {
|
||||
assert.equal(state, 'resolving');
|
||||
tokenSource1.cancel();
|
||||
assert.equal(state, 'resolving');
|
||||
|
||||
setTimeout(() => {
|
||||
assert.equal(state, 'resolving');
|
||||
tokenSource2.cancel();
|
||||
assert.equal(state, 'idle');
|
||||
}, 10);
|
||||
}, 10);
|
||||
|
||||
return Promise.all([promise1, promise2]);
|
||||
});
|
||||
});
|
||||
35
lib/vscode/src/vs/base/test/common/processes.test.ts
Normal file
35
lib/vscode/src/vs/base/test/common/processes.test.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import * as processes from 'vs/base/common/processes';
|
||||
|
||||
suite('Processes', () => {
|
||||
test('sanitizeProcessEnvironment', () => {
|
||||
let env = {
|
||||
FOO: 'bar',
|
||||
ELECTRON_ENABLE_STACK_DUMPING: 'x',
|
||||
ELECTRON_ENABLE_LOGGING: 'x',
|
||||
ELECTRON_NO_ASAR: 'x',
|
||||
ELECTRON_NO_ATTACH_CONSOLE: 'x',
|
||||
ELECTRON_RUN_AS_NODE: 'x',
|
||||
GOOGLE_API_KEY: 'x',
|
||||
VSCODE_CLI: 'x',
|
||||
VSCODE_DEV: 'x',
|
||||
VSCODE_IPC_HOOK: 'x',
|
||||
VSCODE_LOGS: 'x',
|
||||
VSCODE_NLS_CONFIG: 'x',
|
||||
VSCODE_PORTABLE: 'x',
|
||||
VSCODE_PID: 'x',
|
||||
VSCODE_NODE_CACHED_DATA_DIR: 'x',
|
||||
VSCODE_NEW_VAR: 'x',
|
||||
GDK_PIXBUF_MODULE_FILE: 'x',
|
||||
GDK_PIXBUF_MODULEDIR: 'x',
|
||||
};
|
||||
processes.sanitizeProcessEnvironment(env);
|
||||
assert.equal(env['FOO'], 'bar');
|
||||
assert.equal(Object.keys(env).length, 1);
|
||||
});
|
||||
});
|
||||
73
lib/vscode/src/vs/base/test/common/resourceTree.test.ts
Normal file
73
lib/vscode/src/vs/base/test/common/resourceTree.test.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { ResourceTree } from 'vs/base/common/resourceTree';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
||||
suite('ResourceTree', function () {
|
||||
test('ctor', function () {
|
||||
const tree = new ResourceTree<string, null>(null);
|
||||
assert.equal(tree.root.childrenCount, 0);
|
||||
});
|
||||
|
||||
test('simple', function () {
|
||||
const tree = new ResourceTree<string, null>(null);
|
||||
|
||||
tree.add(URI.file('/foo/bar.txt'), 'bar contents');
|
||||
assert.equal(tree.root.childrenCount, 1);
|
||||
|
||||
let foo = tree.root.get('foo')!;
|
||||
assert(foo);
|
||||
assert.equal(foo.childrenCount, 1);
|
||||
|
||||
let bar = foo.get('bar.txt')!;
|
||||
assert(bar);
|
||||
assert.equal(bar.element, 'bar contents');
|
||||
|
||||
tree.add(URI.file('/hello.txt'), 'hello contents');
|
||||
assert.equal(tree.root.childrenCount, 2);
|
||||
|
||||
let hello = tree.root.get('hello.txt')!;
|
||||
assert(hello);
|
||||
assert.equal(hello.element, 'hello contents');
|
||||
|
||||
tree.delete(URI.file('/foo/bar.txt'));
|
||||
assert.equal(tree.root.childrenCount, 1);
|
||||
hello = tree.root.get('hello.txt')!;
|
||||
assert(hello);
|
||||
assert.equal(hello.element, 'hello contents');
|
||||
});
|
||||
|
||||
test('folders with data', function () {
|
||||
const tree = new ResourceTree<string, null>(null);
|
||||
|
||||
assert.equal(tree.root.childrenCount, 0);
|
||||
|
||||
tree.add(URI.file('/foo'), 'foo');
|
||||
assert.equal(tree.root.childrenCount, 1);
|
||||
assert.equal(tree.root.get('foo')!.element, 'foo');
|
||||
|
||||
tree.add(URI.file('/bar'), 'bar');
|
||||
assert.equal(tree.root.childrenCount, 2);
|
||||
assert.equal(tree.root.get('bar')!.element, 'bar');
|
||||
|
||||
tree.add(URI.file('/foo/file.txt'), 'file');
|
||||
assert.equal(tree.root.childrenCount, 2);
|
||||
assert.equal(tree.root.get('foo')!.element, 'foo');
|
||||
assert.equal(tree.root.get('bar')!.element, 'bar');
|
||||
assert.equal(tree.root.get('foo')!.get('file.txt')!.element, 'file');
|
||||
|
||||
tree.delete(URI.file('/foo'));
|
||||
assert.equal(tree.root.childrenCount, 1);
|
||||
assert(!tree.root.get('foo'));
|
||||
assert.equal(tree.root.get('bar')!.element, 'bar');
|
||||
|
||||
tree.delete(URI.file('/bar'));
|
||||
assert.equal(tree.root.childrenCount, 0);
|
||||
assert(!tree.root.get('foo'));
|
||||
assert(!tree.root.get('bar'));
|
||||
});
|
||||
});
|
||||
432
lib/vscode/src/vs/base/test/common/resources.test.ts
Normal file
432
lib/vscode/src/vs/base/test/common/resources.test.ts
Normal file
@@ -0,0 +1,432 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as assert from 'assert';
|
||||
import { dirname, basename, distinctParents, joinPath, normalizePath, isAbsolutePath, relativePath, removeTrailingPathSeparator, hasTrailingPathSeparator, resolvePath, addTrailingPathSeparator, extUri, extUriIgnorePathCase } from 'vs/base/common/resources';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { isWindows } from 'vs/base/common/platform';
|
||||
import { toSlashes } from 'vs/base/common/extpath';
|
||||
import { win32, posix } from 'vs/base/common/path';
|
||||
|
||||
|
||||
suite('Resources', () => {
|
||||
|
||||
test('distinctParents', () => {
|
||||
|
||||
// Basic
|
||||
let resources = [
|
||||
URI.file('/some/folderA/file.txt'),
|
||||
URI.file('/some/folderB/file.txt'),
|
||||
URI.file('/some/folderC/file.txt')
|
||||
];
|
||||
|
||||
let distinct = distinctParents(resources, r => r);
|
||||
assert.equal(distinct.length, 3);
|
||||
assert.equal(distinct[0].toString(), resources[0].toString());
|
||||
assert.equal(distinct[1].toString(), resources[1].toString());
|
||||
assert.equal(distinct[2].toString(), resources[2].toString());
|
||||
|
||||
// Parent / Child
|
||||
resources = [
|
||||
URI.file('/some/folderA'),
|
||||
URI.file('/some/folderA/file.txt'),
|
||||
URI.file('/some/folderA/child/file.txt'),
|
||||
URI.file('/some/folderA2/file.txt'),
|
||||
URI.file('/some/file.txt')
|
||||
];
|
||||
|
||||
distinct = distinctParents(resources, r => r);
|
||||
assert.equal(distinct.length, 3);
|
||||
assert.equal(distinct[0].toString(), resources[0].toString());
|
||||
assert.equal(distinct[1].toString(), resources[3].toString());
|
||||
assert.equal(distinct[2].toString(), resources[4].toString());
|
||||
});
|
||||
|
||||
test('dirname', () => {
|
||||
if (isWindows) {
|
||||
assert.equal(dirname(URI.file('c:\\some\\file\\test.txt')).toString(), 'file:///c%3A/some/file');
|
||||
assert.equal(dirname(URI.file('c:\\some\\file')).toString(), 'file:///c%3A/some');
|
||||
assert.equal(dirname(URI.file('c:\\some\\file\\')).toString(), 'file:///c%3A/some');
|
||||
assert.equal(dirname(URI.file('c:\\some')).toString(), 'file:///c%3A/');
|
||||
assert.equal(dirname(URI.file('C:\\some')).toString(), 'file:///c%3A/');
|
||||
assert.equal(dirname(URI.file('c:\\')).toString(), 'file:///c%3A/');
|
||||
} else {
|
||||
assert.equal(dirname(URI.file('/some/file/test.txt')).toString(), 'file:///some/file');
|
||||
assert.equal(dirname(URI.file('/some/file/')).toString(), 'file:///some');
|
||||
assert.equal(dirname(URI.file('/some/file')).toString(), 'file:///some');
|
||||
}
|
||||
assert.equal(dirname(URI.parse('foo://a/some/file/test.txt')).toString(), 'foo://a/some/file');
|
||||
assert.equal(dirname(URI.parse('foo://a/some/file/')).toString(), 'foo://a/some');
|
||||
assert.equal(dirname(URI.parse('foo://a/some/file')).toString(), 'foo://a/some');
|
||||
assert.equal(dirname(URI.parse('foo://a/some')).toString(), 'foo://a/');
|
||||
assert.equal(dirname(URI.parse('foo://a/')).toString(), 'foo://a/');
|
||||
assert.equal(dirname(URI.parse('foo://a')).toString(), 'foo://a');
|
||||
|
||||
// does not explode (https://github.com/microsoft/vscode/issues/41987)
|
||||
dirname(URI.from({ scheme: 'file', authority: '/users/someone/portal.h' }));
|
||||
|
||||
assert.equal(dirname(URI.parse('foo://a/b/c?q')).toString(), 'foo://a/b?q');
|
||||
});
|
||||
|
||||
test('basename', () => {
|
||||
if (isWindows) {
|
||||
assert.equal(basename(URI.file('c:\\some\\file\\test.txt')), 'test.txt');
|
||||
assert.equal(basename(URI.file('c:\\some\\file')), 'file');
|
||||
assert.equal(basename(URI.file('c:\\some\\file\\')), 'file');
|
||||
assert.equal(basename(URI.file('C:\\some\\file\\')), 'file');
|
||||
} else {
|
||||
assert.equal(basename(URI.file('/some/file/test.txt')), 'test.txt');
|
||||
assert.equal(basename(URI.file('/some/file/')), 'file');
|
||||
assert.equal(basename(URI.file('/some/file')), 'file');
|
||||
assert.equal(basename(URI.file('/some')), 'some');
|
||||
}
|
||||
assert.equal(basename(URI.parse('foo://a/some/file/test.txt')), 'test.txt');
|
||||
assert.equal(basename(URI.parse('foo://a/some/file/')), 'file');
|
||||
assert.equal(basename(URI.parse('foo://a/some/file')), 'file');
|
||||
assert.equal(basename(URI.parse('foo://a/some')), 'some');
|
||||
assert.equal(basename(URI.parse('foo://a/')), '');
|
||||
assert.equal(basename(URI.parse('foo://a')), '');
|
||||
});
|
||||
|
||||
test('joinPath', () => {
|
||||
if (isWindows) {
|
||||
assert.equal(joinPath(URI.file('c:\\foo\\bar'), '/file.js').toString(), 'file:///c%3A/foo/bar/file.js');
|
||||
assert.equal(joinPath(URI.file('c:\\foo\\bar\\'), 'file.js').toString(), 'file:///c%3A/foo/bar/file.js');
|
||||
assert.equal(joinPath(URI.file('c:\\foo\\bar\\'), '/file.js').toString(), 'file:///c%3A/foo/bar/file.js');
|
||||
assert.equal(joinPath(URI.file('c:\\'), '/file.js').toString(), 'file:///c%3A/file.js');
|
||||
assert.equal(joinPath(URI.file('c:\\'), 'bar/file.js').toString(), 'file:///c%3A/bar/file.js');
|
||||
assert.equal(joinPath(URI.file('c:\\foo'), './file.js').toString(), 'file:///c%3A/foo/file.js');
|
||||
assert.equal(joinPath(URI.file('c:\\foo'), '/./file.js').toString(), 'file:///c%3A/foo/file.js');
|
||||
assert.equal(joinPath(URI.file('C:\\foo'), '../file.js').toString(), 'file:///c%3A/file.js');
|
||||
assert.equal(joinPath(URI.file('C:\\foo\\.'), '../file.js').toString(), 'file:///c%3A/file.js');
|
||||
} else {
|
||||
assert.equal(joinPath(URI.file('/foo/bar'), '/file.js').toString(), 'file:///foo/bar/file.js');
|
||||
assert.equal(joinPath(URI.file('/foo/bar'), 'file.js').toString(), 'file:///foo/bar/file.js');
|
||||
assert.equal(joinPath(URI.file('/foo/bar/'), '/file.js').toString(), 'file:///foo/bar/file.js');
|
||||
assert.equal(joinPath(URI.file('/'), '/file.js').toString(), 'file:///file.js');
|
||||
assert.equal(joinPath(URI.file('/foo/bar'), './file.js').toString(), 'file:///foo/bar/file.js');
|
||||
assert.equal(joinPath(URI.file('/foo/bar'), '/./file.js').toString(), 'file:///foo/bar/file.js');
|
||||
assert.equal(joinPath(URI.file('/foo/bar'), '../file.js').toString(), 'file:///foo/file.js');
|
||||
}
|
||||
assert.equal(joinPath(URI.parse('foo://a/foo/bar')).toString(), 'foo://a/foo/bar');
|
||||
assert.equal(joinPath(URI.parse('foo://a/foo/bar'), '/file.js').toString(), 'foo://a/foo/bar/file.js');
|
||||
assert.equal(joinPath(URI.parse('foo://a/foo/bar'), 'file.js').toString(), 'foo://a/foo/bar/file.js');
|
||||
assert.equal(joinPath(URI.parse('foo://a/foo/bar/'), '/file.js').toString(), 'foo://a/foo/bar/file.js');
|
||||
assert.equal(joinPath(URI.parse('foo://a/'), '/file.js').toString(), 'foo://a/file.js');
|
||||
assert.equal(joinPath(URI.parse('foo://a/foo/bar/'), './file.js').toString(), 'foo://a/foo/bar/file.js');
|
||||
assert.equal(joinPath(URI.parse('foo://a/foo/bar/'), '/./file.js').toString(), 'foo://a/foo/bar/file.js');
|
||||
assert.equal(joinPath(URI.parse('foo://a/foo/bar/'), '../file.js').toString(), 'foo://a/foo/file.js');
|
||||
|
||||
assert.equal(
|
||||
joinPath(URI.from({ scheme: 'myScheme', authority: 'authority', path: '/path', query: 'query', fragment: 'fragment' }), '/file.js').toString(),
|
||||
'myScheme://authority/path/file.js?query#fragment');
|
||||
});
|
||||
|
||||
test('normalizePath', () => {
|
||||
if (isWindows) {
|
||||
assert.equal(normalizePath(URI.file('c:\\foo\\.\\bar')).toString(), 'file:///c%3A/foo/bar');
|
||||
assert.equal(normalizePath(URI.file('c:\\foo\\.')).toString(), 'file:///c%3A/foo');
|
||||
assert.equal(normalizePath(URI.file('c:\\foo\\.\\')).toString(), 'file:///c%3A/foo/');
|
||||
assert.equal(normalizePath(URI.file('c:\\foo\\..')).toString(), 'file:///c%3A/');
|
||||
assert.equal(normalizePath(URI.file('c:\\foo\\..\\bar')).toString(), 'file:///c%3A/bar');
|
||||
assert.equal(normalizePath(URI.file('c:\\foo\\..\\..\\bar')).toString(), 'file:///c%3A/bar');
|
||||
assert.equal(normalizePath(URI.file('c:\\foo\\foo\\..\\..\\bar')).toString(), 'file:///c%3A/bar');
|
||||
assert.equal(normalizePath(URI.file('C:\\foo\\foo\\.\\..\\..\\bar')).toString(), 'file:///c%3A/bar');
|
||||
assert.equal(normalizePath(URI.file('C:\\foo\\foo\\.\\..\\some\\..\\bar')).toString(), 'file:///c%3A/foo/bar');
|
||||
} else {
|
||||
assert.equal(normalizePath(URI.file('/foo/./bar')).toString(), 'file:///foo/bar');
|
||||
assert.equal(normalizePath(URI.file('/foo/.')).toString(), 'file:///foo');
|
||||
assert.equal(normalizePath(URI.file('/foo/./')).toString(), 'file:///foo/');
|
||||
assert.equal(normalizePath(URI.file('/foo/..')).toString(), 'file:///');
|
||||
assert.equal(normalizePath(URI.file('/foo/../bar')).toString(), 'file:///bar');
|
||||
assert.equal(normalizePath(URI.file('/foo/../../bar')).toString(), 'file:///bar');
|
||||
assert.equal(normalizePath(URI.file('/foo/foo/../../bar')).toString(), 'file:///bar');
|
||||
assert.equal(normalizePath(URI.file('/foo/foo/./../../bar')).toString(), 'file:///bar');
|
||||
assert.equal(normalizePath(URI.file('/foo/foo/./../some/../bar')).toString(), 'file:///foo/bar');
|
||||
assert.equal(normalizePath(URI.file('/f')).toString(), 'file:///f');
|
||||
}
|
||||
assert.equal(normalizePath(URI.parse('foo://a/foo/./bar')).toString(), 'foo://a/foo/bar');
|
||||
assert.equal(normalizePath(URI.parse('foo://a/foo/.')).toString(), 'foo://a/foo');
|
||||
assert.equal(normalizePath(URI.parse('foo://a/foo/./')).toString(), 'foo://a/foo/');
|
||||
assert.equal(normalizePath(URI.parse('foo://a/foo/..')).toString(), 'foo://a/');
|
||||
assert.equal(normalizePath(URI.parse('foo://a/foo/../bar')).toString(), 'foo://a/bar');
|
||||
assert.equal(normalizePath(URI.parse('foo://a/foo/../../bar')).toString(), 'foo://a/bar');
|
||||
assert.equal(normalizePath(URI.parse('foo://a/foo/foo/../../bar')).toString(), 'foo://a/bar');
|
||||
assert.equal(normalizePath(URI.parse('foo://a/foo/foo/./../../bar')).toString(), 'foo://a/bar');
|
||||
assert.equal(normalizePath(URI.parse('foo://a/foo/foo/./../some/../bar')).toString(), 'foo://a/foo/bar');
|
||||
assert.equal(normalizePath(URI.parse('foo://a')).toString(), 'foo://a');
|
||||
assert.equal(normalizePath(URI.parse('foo://a/')).toString(), 'foo://a/');
|
||||
assert.equal(normalizePath(URI.parse('foo://a/foo/./bar?q=1')).toString(), URI.parse('foo://a/foo/bar?q%3D1').toString());
|
||||
});
|
||||
|
||||
test('isAbsolute', () => {
|
||||
if (isWindows) {
|
||||
assert.equal(isAbsolutePath(URI.file('c:\\foo\\')), true);
|
||||
assert.equal(isAbsolutePath(URI.file('C:\\foo\\')), true);
|
||||
assert.equal(isAbsolutePath(URI.file('bar')), true); // URI normalizes all file URIs to be absolute
|
||||
} else {
|
||||
assert.equal(isAbsolutePath(URI.file('/foo/bar')), true);
|
||||
assert.equal(isAbsolutePath(URI.file('bar')), true); // URI normalizes all file URIs to be absolute
|
||||
}
|
||||
assert.equal(isAbsolutePath(URI.parse('foo:foo')), false);
|
||||
assert.equal(isAbsolutePath(URI.parse('foo://a/foo/.')), true);
|
||||
});
|
||||
|
||||
function assertTrailingSeparator(u1: URI, expected: boolean) {
|
||||
assert.equal(hasTrailingPathSeparator(u1), expected, u1.toString());
|
||||
}
|
||||
|
||||
function assertRemoveTrailingSeparator(u1: URI, expected: URI) {
|
||||
assertEqualURI(removeTrailingPathSeparator(u1), expected, u1.toString());
|
||||
}
|
||||
|
||||
function assertAddTrailingSeparator(u1: URI, expected: URI) {
|
||||
assertEqualURI(addTrailingPathSeparator(u1), expected, u1.toString());
|
||||
}
|
||||
|
||||
test('trailingPathSeparator', () => {
|
||||
assertTrailingSeparator(URI.parse('foo://a/foo'), false);
|
||||
assertTrailingSeparator(URI.parse('foo://a/foo/'), true);
|
||||
assertTrailingSeparator(URI.parse('foo://a/'), false);
|
||||
assertTrailingSeparator(URI.parse('foo://a'), false);
|
||||
|
||||
assertRemoveTrailingSeparator(URI.parse('foo://a/foo'), URI.parse('foo://a/foo'));
|
||||
assertRemoveTrailingSeparator(URI.parse('foo://a/foo/'), URI.parse('foo://a/foo'));
|
||||
assertRemoveTrailingSeparator(URI.parse('foo://a/'), URI.parse('foo://a/'));
|
||||
assertRemoveTrailingSeparator(URI.parse('foo://a'), URI.parse('foo://a'));
|
||||
|
||||
assertAddTrailingSeparator(URI.parse('foo://a/foo'), URI.parse('foo://a/foo/'));
|
||||
assertAddTrailingSeparator(URI.parse('foo://a/foo/'), URI.parse('foo://a/foo/'));
|
||||
assertAddTrailingSeparator(URI.parse('foo://a/'), URI.parse('foo://a/'));
|
||||
assertAddTrailingSeparator(URI.parse('foo://a'), URI.parse('foo://a/'));
|
||||
|
||||
if (isWindows) {
|
||||
assertTrailingSeparator(URI.file('c:\\a\\foo'), false);
|
||||
assertTrailingSeparator(URI.file('c:\\a\\foo\\'), true);
|
||||
assertTrailingSeparator(URI.file('c:\\'), false);
|
||||
assertTrailingSeparator(URI.file('\\\\server\\share\\some\\'), true);
|
||||
assertTrailingSeparator(URI.file('\\\\server\\share\\'), false);
|
||||
|
||||
assertRemoveTrailingSeparator(URI.file('c:\\a\\foo'), URI.file('c:\\a\\foo'));
|
||||
assertRemoveTrailingSeparator(URI.file('c:\\a\\foo\\'), URI.file('c:\\a\\foo'));
|
||||
assertRemoveTrailingSeparator(URI.file('c:\\'), URI.file('c:\\'));
|
||||
assertRemoveTrailingSeparator(URI.file('\\\\server\\share\\some\\'), URI.file('\\\\server\\share\\some'));
|
||||
assertRemoveTrailingSeparator(URI.file('\\\\server\\share\\'), URI.file('\\\\server\\share\\'));
|
||||
|
||||
assertAddTrailingSeparator(URI.file('c:\\a\\foo'), URI.file('c:\\a\\foo\\'));
|
||||
assertAddTrailingSeparator(URI.file('c:\\a\\foo\\'), URI.file('c:\\a\\foo\\'));
|
||||
assertAddTrailingSeparator(URI.file('c:\\'), URI.file('c:\\'));
|
||||
assertAddTrailingSeparator(URI.file('\\\\server\\share\\some'), URI.file('\\\\server\\share\\some\\'));
|
||||
assertAddTrailingSeparator(URI.file('\\\\server\\share\\some\\'), URI.file('\\\\server\\share\\some\\'));
|
||||
} else {
|
||||
assertTrailingSeparator(URI.file('/foo/bar'), false);
|
||||
assertTrailingSeparator(URI.file('/foo/bar/'), true);
|
||||
assertTrailingSeparator(URI.file('/'), false);
|
||||
|
||||
assertRemoveTrailingSeparator(URI.file('/foo/bar'), URI.file('/foo/bar'));
|
||||
assertRemoveTrailingSeparator(URI.file('/foo/bar/'), URI.file('/foo/bar'));
|
||||
assertRemoveTrailingSeparator(URI.file('/'), URI.file('/'));
|
||||
|
||||
assertAddTrailingSeparator(URI.file('/foo/bar'), URI.file('/foo/bar/'));
|
||||
assertAddTrailingSeparator(URI.file('/foo/bar/'), URI.file('/foo/bar/'));
|
||||
assertAddTrailingSeparator(URI.file('/'), URI.file('/'));
|
||||
}
|
||||
});
|
||||
|
||||
function assertEqualURI(actual: URI, expected: URI, message?: string, ignoreCase?: boolean) {
|
||||
let util = ignoreCase ? extUriIgnorePathCase : extUri;
|
||||
if (!util.isEqual(expected, actual)) {
|
||||
assert.equal(actual.toString(), expected.toString(), message);
|
||||
}
|
||||
}
|
||||
|
||||
function assertRelativePath(u1: URI, u2: URI, expectedPath: string | undefined, ignoreJoin?: boolean, ignoreCase?: boolean) {
|
||||
let util = ignoreCase ? extUriIgnorePathCase : extUri;
|
||||
|
||||
assert.equal(util.relativePath(u1, u2), expectedPath, `from ${u1.toString()} to ${u2.toString()}`);
|
||||
if (expectedPath !== undefined && !ignoreJoin) {
|
||||
assertEqualURI(removeTrailingPathSeparator(joinPath(u1, expectedPath)), removeTrailingPathSeparator(u2), 'joinPath on relativePath should be equal', ignoreCase);
|
||||
}
|
||||
}
|
||||
|
||||
test('relativePath', () => {
|
||||
assertRelativePath(URI.parse('foo://a/foo'), URI.parse('foo://a/foo/bar'), 'bar');
|
||||
assertRelativePath(URI.parse('foo://a/foo'), URI.parse('foo://a/foo/bar/'), 'bar');
|
||||
assertRelativePath(URI.parse('foo://a/foo'), URI.parse('foo://a/foo/bar/goo'), 'bar/goo');
|
||||
assertRelativePath(URI.parse('foo://a/'), URI.parse('foo://a/foo/bar/goo'), 'foo/bar/goo');
|
||||
assertRelativePath(URI.parse('foo://a/foo/xoo'), URI.parse('foo://a/foo/bar'), '../bar');
|
||||
assertRelativePath(URI.parse('foo://a/foo/xoo/yoo'), URI.parse('foo://a'), '../../..', true);
|
||||
assertRelativePath(URI.parse('foo://a/foo'), URI.parse('foo://a/foo/'), '');
|
||||
assertRelativePath(URI.parse('foo://a/foo/'), URI.parse('foo://a/foo'), '');
|
||||
assertRelativePath(URI.parse('foo://a/foo/'), URI.parse('foo://a/foo/'), '');
|
||||
assertRelativePath(URI.parse('foo://a/foo'), URI.parse('foo://a/foo'), '');
|
||||
assertRelativePath(URI.parse('foo://a'), URI.parse('foo://a'), '', true);
|
||||
assertRelativePath(URI.parse('foo://a/'), URI.parse('foo://a/'), '');
|
||||
assertRelativePath(URI.parse('foo://a/'), URI.parse('foo://a'), '', true);
|
||||
assertRelativePath(URI.parse('foo://a/foo?q'), URI.parse('foo://a/foo/bar#h'), 'bar', true);
|
||||
assertRelativePath(URI.parse('foo://'), URI.parse('foo://a/b'), undefined);
|
||||
assertRelativePath(URI.parse('foo://a2/b'), URI.parse('foo://a/b'), undefined);
|
||||
assertRelativePath(URI.parse('goo://a/b'), URI.parse('foo://a/b'), undefined);
|
||||
|
||||
assertRelativePath(URI.parse('foo://a/foo'), URI.parse('foo://A/FOO/bar/goo'), 'bar/goo', false, true);
|
||||
assertRelativePath(URI.parse('foo://a/foo'), URI.parse('foo://A/FOO/BAR/GOO'), 'BAR/GOO', false, true);
|
||||
assertRelativePath(URI.parse('foo://a/foo/xoo'), URI.parse('foo://A/FOO/BAR/GOO'), '../BAR/GOO', false, true);
|
||||
assertRelativePath(URI.parse('foo:///c:/a/foo'), URI.parse('foo:///C:/a/foo/xoo/'), 'xoo', false, true);
|
||||
|
||||
if (isWindows) {
|
||||
assertRelativePath(URI.file('c:\\foo\\bar'), URI.file('c:\\foo\\bar'), '');
|
||||
assertRelativePath(URI.file('c:\\foo\\bar\\huu'), URI.file('c:\\foo\\bar'), '..');
|
||||
assertRelativePath(URI.file('c:\\foo\\bar\\a1\\a2'), URI.file('c:\\foo\\bar'), '../..');
|
||||
assertRelativePath(URI.file('c:\\foo\\bar\\'), URI.file('c:\\foo\\bar\\a1\\a2'), 'a1/a2');
|
||||
assertRelativePath(URI.file('c:\\foo\\bar\\'), URI.file('c:\\foo\\bar\\a1\\a2\\'), 'a1/a2');
|
||||
assertRelativePath(URI.file('c:\\'), URI.file('c:\\foo\\bar'), 'foo/bar');
|
||||
assertRelativePath(URI.file('\\\\server\\share\\some\\'), URI.file('\\\\server\\share\\some\\path'), 'path');
|
||||
assertRelativePath(URI.file('\\\\server\\share\\some\\'), URI.file('\\\\server\\share2\\some\\path'), '../../share2/some/path', true); // ignore joinPath assert: path.join is not root aware
|
||||
} else {
|
||||
assertRelativePath(URI.file('/a/foo'), URI.file('/a/foo/bar'), 'bar');
|
||||
assertRelativePath(URI.file('/a/foo'), URI.file('/a/foo/bar/'), 'bar');
|
||||
assertRelativePath(URI.file('/a/foo'), URI.file('/a/foo/bar/goo'), 'bar/goo');
|
||||
assertRelativePath(URI.file('/a/'), URI.file('/a/foo/bar/goo'), 'foo/bar/goo');
|
||||
assertRelativePath(URI.file('/'), URI.file('/a/foo/bar/goo'), 'a/foo/bar/goo');
|
||||
assertRelativePath(URI.file('/a/foo/xoo'), URI.file('/a/foo/bar'), '../bar');
|
||||
assertRelativePath(URI.file('/a/foo/xoo/yoo'), URI.file('/a'), '../../..');
|
||||
assertRelativePath(URI.file('/a/foo'), URI.file('/a/foo/'), '');
|
||||
assertRelativePath(URI.file('/a/foo'), URI.file('/b/foo/'), '../../b/foo');
|
||||
}
|
||||
});
|
||||
|
||||
function assertResolve(u1: URI, path: string, expected: URI) {
|
||||
const actual = resolvePath(u1, path);
|
||||
assertEqualURI(actual, expected, `from ${u1.toString()} and ${path}`);
|
||||
|
||||
const p = path.indexOf('/') !== -1 ? posix : win32;
|
||||
if (!p.isAbsolute(path)) {
|
||||
let expectedPath = isWindows ? toSlashes(path) : path;
|
||||
expectedPath = expectedPath.startsWith('./') ? expectedPath.substr(2) : expectedPath;
|
||||
assert.equal(relativePath(u1, actual), expectedPath, `relativePath (${u1.toString()}) on actual (${actual.toString()}) should be to path (${expectedPath})`);
|
||||
}
|
||||
}
|
||||
|
||||
test('resolve', () => {
|
||||
if (isWindows) {
|
||||
assertResolve(URI.file('c:\\foo\\bar'), 'file.js', URI.file('c:\\foo\\bar\\file.js'));
|
||||
assertResolve(URI.file('c:\\foo\\bar'), 't\\file.js', URI.file('c:\\foo\\bar\\t\\file.js'));
|
||||
assertResolve(URI.file('c:\\foo\\bar'), '.\\t\\file.js', URI.file('c:\\foo\\bar\\t\\file.js'));
|
||||
assertResolve(URI.file('c:\\foo\\bar'), 'a1/file.js', URI.file('c:\\foo\\bar\\a1\\file.js'));
|
||||
assertResolve(URI.file('c:\\foo\\bar'), './a1/file.js', URI.file('c:\\foo\\bar\\a1\\file.js'));
|
||||
assertResolve(URI.file('c:\\foo\\bar'), '\\b1\\file.js', URI.file('c:\\b1\\file.js'));
|
||||
assertResolve(URI.file('c:\\foo\\bar'), '/b1/file.js', URI.file('c:\\b1\\file.js'));
|
||||
assertResolve(URI.file('c:\\foo\\bar\\'), 'file.js', URI.file('c:\\foo\\bar\\file.js'));
|
||||
|
||||
assertResolve(URI.file('c:\\'), 'file.js', URI.file('c:\\file.js'));
|
||||
assertResolve(URI.file('c:\\'), '\\b1\\file.js', URI.file('c:\\b1\\file.js'));
|
||||
assertResolve(URI.file('c:\\'), '/b1/file.js', URI.file('c:\\b1\\file.js'));
|
||||
assertResolve(URI.file('c:\\'), 'd:\\foo\\bar.txt', URI.file('d:\\foo\\bar.txt'));
|
||||
|
||||
assertResolve(URI.file('\\\\server\\share\\some\\'), 'b1\\file.js', URI.file('\\\\server\\share\\some\\b1\\file.js'));
|
||||
assertResolve(URI.file('\\\\server\\share\\some\\'), '\\file.js', URI.file('\\\\server\\share\\file.js'));
|
||||
|
||||
assertResolve(URI.file('c:\\'), '\\\\server\\share\\some\\', URI.file('\\\\server\\share\\some'));
|
||||
assertResolve(URI.file('\\\\server\\share\\some\\'), 'c:\\', URI.file('c:\\'));
|
||||
} else {
|
||||
assertResolve(URI.file('/foo/bar'), 'file.js', URI.file('/foo/bar/file.js'));
|
||||
assertResolve(URI.file('/foo/bar'), './file.js', URI.file('/foo/bar/file.js'));
|
||||
assertResolve(URI.file('/foo/bar'), '/file.js', URI.file('/file.js'));
|
||||
assertResolve(URI.file('/foo/bar/'), 'file.js', URI.file('/foo/bar/file.js'));
|
||||
assertResolve(URI.file('/'), 'file.js', URI.file('/file.js'));
|
||||
assertResolve(URI.file(''), './file.js', URI.file('/file.js'));
|
||||
assertResolve(URI.file(''), '/file.js', URI.file('/file.js'));
|
||||
}
|
||||
|
||||
assertResolve(URI.parse('foo://server/foo/bar'), 'file.js', URI.parse('foo://server/foo/bar/file.js'));
|
||||
assertResolve(URI.parse('foo://server/foo/bar'), './file.js', URI.parse('foo://server/foo/bar/file.js'));
|
||||
assertResolve(URI.parse('foo://server/foo/bar'), './file.js', URI.parse('foo://server/foo/bar/file.js'));
|
||||
assertResolve(URI.parse('foo://server/foo/bar'), 'c:\\a1\\b1', URI.parse('foo://server/c:/a1/b1'));
|
||||
assertResolve(URI.parse('foo://server/foo/bar'), 'c:\\', URI.parse('foo://server/c:'));
|
||||
|
||||
|
||||
});
|
||||
|
||||
function assertIsEqual(u1: URI, u2: URI, ignoreCase: boolean | undefined, expected: boolean) {
|
||||
|
||||
let util = ignoreCase ? extUriIgnorePathCase : extUri;
|
||||
|
||||
assert.equal(util.isEqual(u1, u2), expected, `${u1.toString()}${expected ? '===' : '!=='}${u2.toString()}`);
|
||||
assert.equal(util.compare(u1, u2) === 0, expected);
|
||||
assert.equal(util.getComparisonKey(u1) === util.getComparisonKey(u2), expected, `comparison keys ${u1.toString()}, ${u2.toString()}`);
|
||||
assert.equal(util.isEqualOrParent(u1, u2), expected, `isEqualOrParent ${u1.toString()}, ${u2.toString()}`);
|
||||
if (!ignoreCase) {
|
||||
assert.equal(u1.toString() === u2.toString(), expected);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
test('isEqual', () => {
|
||||
let fileURI = isWindows ? URI.file('c:\\foo\\bar') : URI.file('/foo/bar');
|
||||
let fileURI2 = isWindows ? URI.file('C:\\foo\\Bar') : URI.file('/foo/Bar');
|
||||
assertIsEqual(fileURI, fileURI, true, true);
|
||||
assertIsEqual(fileURI, fileURI, false, true);
|
||||
assertIsEqual(fileURI, fileURI, undefined, true);
|
||||
assertIsEqual(fileURI, fileURI2, true, true);
|
||||
assertIsEqual(fileURI, fileURI2, false, false);
|
||||
|
||||
let fileURI3 = URI.parse('foo://server:453/foo/bar');
|
||||
let fileURI4 = URI.parse('foo://server:453/foo/Bar');
|
||||
assertIsEqual(fileURI3, fileURI3, true, true);
|
||||
assertIsEqual(fileURI3, fileURI3, false, true);
|
||||
assertIsEqual(fileURI3, fileURI3, undefined, true);
|
||||
assertIsEqual(fileURI3, fileURI4, true, true);
|
||||
assertIsEqual(fileURI3, fileURI4, false, false);
|
||||
|
||||
assertIsEqual(fileURI, fileURI3, true, false);
|
||||
|
||||
assertIsEqual(URI.parse('file://server'), URI.parse('file://server/'), true, true);
|
||||
assertIsEqual(URI.parse('http://server'), URI.parse('http://server/'), true, true);
|
||||
assertIsEqual(URI.parse('foo://server'), URI.parse('foo://server/'), true, false); // only selected scheme have / as the default path
|
||||
assertIsEqual(URI.parse('foo://server/foo'), URI.parse('foo://server/foo/'), true, false);
|
||||
assertIsEqual(URI.parse('foo://server/foo'), URI.parse('foo://server/foo?'), true, true);
|
||||
|
||||
let fileURI5 = URI.parse('foo://server:453/foo/bar?q=1');
|
||||
let fileURI6 = URI.parse('foo://server:453/foo/bar#xy');
|
||||
|
||||
assertIsEqual(fileURI5, fileURI5, true, true);
|
||||
assertIsEqual(fileURI5, fileURI3, true, false);
|
||||
assertIsEqual(fileURI6, fileURI6, true, true);
|
||||
assertIsEqual(fileURI6, fileURI5, true, false);
|
||||
assertIsEqual(fileURI6, fileURI3, true, false);
|
||||
});
|
||||
|
||||
test('isEqualOrParent', () => {
|
||||
|
||||
let fileURI = isWindows ? URI.file('c:\\foo\\bar') : URI.file('/foo/bar');
|
||||
let fileURI2 = isWindows ? URI.file('c:\\foo') : URI.file('/foo');
|
||||
let fileURI2b = isWindows ? URI.file('C:\\Foo\\') : URI.file('/Foo/');
|
||||
assert.equal(extUriIgnorePathCase.isEqualOrParent(fileURI, fileURI), true, '1');
|
||||
assert.equal(extUri.isEqualOrParent(fileURI, fileURI), true, '2');
|
||||
assert.equal(extUriIgnorePathCase.isEqualOrParent(fileURI, fileURI2), true, '3');
|
||||
assert.equal(extUri.isEqualOrParent(fileURI, fileURI2), true, '4');
|
||||
assert.equal(extUriIgnorePathCase.isEqualOrParent(fileURI, fileURI2b), true, '5');
|
||||
assert.equal(extUri.isEqualOrParent(fileURI, fileURI2b), false, '6');
|
||||
|
||||
assert.equal(extUri.isEqualOrParent(fileURI2, fileURI), false, '7');
|
||||
assert.equal(extUriIgnorePathCase.isEqualOrParent(fileURI2b, fileURI2), true, '8');
|
||||
|
||||
let fileURI3 = URI.parse('foo://server:453/foo/bar/goo');
|
||||
let fileURI4 = URI.parse('foo://server:453/foo/');
|
||||
let fileURI5 = URI.parse('foo://server:453/foo');
|
||||
assert.equal(extUriIgnorePathCase.isEqualOrParent(fileURI3, fileURI3, true), true, '11');
|
||||
assert.equal(extUri.isEqualOrParent(fileURI3, fileURI3), true, '12');
|
||||
assert.equal(extUriIgnorePathCase.isEqualOrParent(fileURI3, fileURI4, true), true, '13');
|
||||
assert.equal(extUri.isEqualOrParent(fileURI3, fileURI4), true, '14');
|
||||
assert.equal(extUriIgnorePathCase.isEqualOrParent(fileURI3, fileURI, true), false, '15');
|
||||
assert.equal(extUriIgnorePathCase.isEqualOrParent(fileURI5, fileURI5, true), true, '16');
|
||||
|
||||
let fileURI6 = URI.parse('foo://server:453/foo?q=1');
|
||||
let fileURI7 = URI.parse('foo://server:453/foo/bar?q=1');
|
||||
assert.equal(extUriIgnorePathCase.isEqualOrParent(fileURI6, fileURI5), false, '17');
|
||||
assert.equal(extUriIgnorePathCase.isEqualOrParent(fileURI6, fileURI6), true, '18');
|
||||
assert.equal(extUriIgnorePathCase.isEqualOrParent(fileURI7, fileURI6), true, '19');
|
||||
assert.equal(extUriIgnorePathCase.isEqualOrParent(fileURI7, fileURI5), false, '20');
|
||||
});
|
||||
});
|
||||
118
lib/vscode/src/vs/base/test/common/scrollable.test.ts
Normal file
118
lib/vscode/src/vs/base/test/common/scrollable.test.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { SmoothScrollingOperation, SmoothScrollingUpdate } from 'vs/base/common/scrollable';
|
||||
|
||||
class TestSmoothScrollingOperation extends SmoothScrollingOperation {
|
||||
|
||||
constructor(from: number, to: number, viewportSize: number, startTime: number, duration: number) {
|
||||
duration = duration + 10;
|
||||
startTime = startTime - 10;
|
||||
|
||||
super(
|
||||
{ scrollLeft: 0, scrollTop: from, width: 0, height: viewportSize },
|
||||
{ scrollLeft: 0, scrollTop: to, width: 0, height: viewportSize },
|
||||
startTime,
|
||||
duration
|
||||
);
|
||||
}
|
||||
|
||||
public testTick(now: number): SmoothScrollingUpdate {
|
||||
return this._tick(now);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
suite('SmoothScrollingOperation', () => {
|
||||
|
||||
const VIEWPORT_HEIGHT = 800;
|
||||
const ANIMATION_DURATION = 125;
|
||||
const LINE_HEIGHT = 20;
|
||||
|
||||
function extractLines(scrollable: TestSmoothScrollingOperation, now: number): [number, number] {
|
||||
let scrollTop = scrollable.testTick(now).scrollTop;
|
||||
let scrollBottom = scrollTop + VIEWPORT_HEIGHT;
|
||||
|
||||
const startLineNumber = Math.floor(scrollTop / LINE_HEIGHT);
|
||||
const endLineNumber = Math.ceil(scrollBottom / LINE_HEIGHT);
|
||||
|
||||
return [startLineNumber, endLineNumber];
|
||||
}
|
||||
|
||||
function simulateSmoothScroll(from: number, to: number): [number, number][] {
|
||||
const scrollable = new TestSmoothScrollingOperation(from, to, VIEWPORT_HEIGHT, 0, ANIMATION_DURATION);
|
||||
|
||||
let result: [number, number][] = [], resultLen = 0;
|
||||
result[resultLen++] = extractLines(scrollable, 0);
|
||||
result[resultLen++] = extractLines(scrollable, 25);
|
||||
result[resultLen++] = extractLines(scrollable, 50);
|
||||
result[resultLen++] = extractLines(scrollable, 75);
|
||||
result[resultLen++] = extractLines(scrollable, 100);
|
||||
result[resultLen++] = extractLines(scrollable, 125);
|
||||
return result;
|
||||
}
|
||||
|
||||
function assertSmoothScroll(from: number, to: number, expected: [number, number][]): void {
|
||||
const actual = simulateSmoothScroll(from, to);
|
||||
assert.deepEqual(actual, expected);
|
||||
}
|
||||
|
||||
test('scroll 25 lines (40 fit)', () => {
|
||||
assertSmoothScroll(0, 500, [
|
||||
[5, 46],
|
||||
[14, 55],
|
||||
[20, 61],
|
||||
[23, 64],
|
||||
[24, 65],
|
||||
[25, 65],
|
||||
]);
|
||||
});
|
||||
|
||||
test('scroll 75 lines (40 fit)', () => {
|
||||
assertSmoothScroll(0, 1500, [
|
||||
[15, 56],
|
||||
[44, 85],
|
||||
[62, 103],
|
||||
[71, 112],
|
||||
[74, 115],
|
||||
[75, 115],
|
||||
]);
|
||||
});
|
||||
|
||||
test('scroll 100 lines (40 fit)', () => {
|
||||
assertSmoothScroll(0, 2000, [
|
||||
[20, 61],
|
||||
[59, 100],
|
||||
[82, 123],
|
||||
[94, 135],
|
||||
[99, 140],
|
||||
[100, 140],
|
||||
]);
|
||||
});
|
||||
|
||||
test('scroll 125 lines (40 fit)', () => {
|
||||
assertSmoothScroll(0, 2500, [
|
||||
[16, 57],
|
||||
[29, 70],
|
||||
[107, 148],
|
||||
[119, 160],
|
||||
[124, 165],
|
||||
[125, 165],
|
||||
]);
|
||||
});
|
||||
|
||||
test('scroll 500 lines (40 fit)', () => {
|
||||
assertSmoothScroll(0, 10000, [
|
||||
[16, 57],
|
||||
[29, 70],
|
||||
[482, 523],
|
||||
[494, 535],
|
||||
[499, 540],
|
||||
[500, 540],
|
||||
]);
|
||||
});
|
||||
|
||||
});
|
||||
218
lib/vscode/src/vs/base/test/common/skipList.test.ts
Normal file
218
lib/vscode/src/vs/base/test/common/skipList.test.ts
Normal file
@@ -0,0 +1,218 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { SkipList } from 'vs/base/common/skipList';
|
||||
import { StopWatch } from 'vs/base/common/stopwatch';
|
||||
import { binarySearch } from 'vs/base/common/arrays';
|
||||
|
||||
|
||||
suite('SkipList', function () {
|
||||
|
||||
function assertValues<V>(list: SkipList<any, V>, expected: V[]) {
|
||||
assert.equal(list.size, expected.length);
|
||||
assert.deepEqual([...list.values()], expected);
|
||||
|
||||
let valuesFromEntries = [...list.entries()].map(entry => entry[1]);
|
||||
assert.deepEqual(valuesFromEntries, expected);
|
||||
|
||||
let valuesFromIter = [...list].map(entry => entry[1]);
|
||||
assert.deepEqual(valuesFromIter, expected);
|
||||
|
||||
let i = 0;
|
||||
list.forEach((value, _key, map) => {
|
||||
assert.ok(map === list);
|
||||
assert.deepEqual(value, expected[i++]);
|
||||
});
|
||||
}
|
||||
|
||||
function assertKeys<K>(list: SkipList<K, any>, expected: K[]) {
|
||||
assert.equal(list.size, expected.length);
|
||||
assert.deepEqual([...list.keys()], expected);
|
||||
|
||||
let keysFromEntries = [...list.entries()].map(entry => entry[0]);
|
||||
assert.deepEqual(keysFromEntries, expected);
|
||||
|
||||
let keysFromIter = [...list].map(entry => entry[0]);
|
||||
assert.deepEqual(keysFromIter, expected);
|
||||
|
||||
let i = 0;
|
||||
list.forEach((_value, key, map) => {
|
||||
assert.ok(map === list);
|
||||
assert.deepEqual(key, expected[i++]);
|
||||
});
|
||||
}
|
||||
|
||||
test('set/get/delete', function () {
|
||||
let list = new SkipList<number, number>((a, b) => a - b);
|
||||
|
||||
assert.equal(list.get(3), undefined);
|
||||
list.set(3, 1);
|
||||
assert.equal(list.get(3), 1);
|
||||
assertValues(list, [1]);
|
||||
|
||||
list.set(3, 3);
|
||||
assertValues(list, [3]);
|
||||
|
||||
list.set(1, 1);
|
||||
list.set(4, 4);
|
||||
assert.equal(list.get(3), 3);
|
||||
assert.equal(list.get(1), 1);
|
||||
assert.equal(list.get(4), 4);
|
||||
assertValues(list, [1, 3, 4]);
|
||||
|
||||
assert.equal(list.delete(17), false);
|
||||
|
||||
assert.equal(list.delete(1), true);
|
||||
assert.equal(list.get(1), undefined);
|
||||
assert.equal(list.get(3), 3);
|
||||
assert.equal(list.get(4), 4);
|
||||
|
||||
assertValues(list, [3, 4]);
|
||||
});
|
||||
|
||||
test('Figure 3', function () {
|
||||
let list = new SkipList<number, boolean>((a, b) => a - b);
|
||||
list.set(3, true);
|
||||
list.set(6, true);
|
||||
list.set(7, true);
|
||||
list.set(9, true);
|
||||
list.set(12, true);
|
||||
list.set(19, true);
|
||||
list.set(21, true);
|
||||
list.set(25, true);
|
||||
|
||||
assertKeys(list, [3, 6, 7, 9, 12, 19, 21, 25]);
|
||||
|
||||
list.set(17, true);
|
||||
assert.deepEqual(list.size, 9);
|
||||
assertKeys(list, [3, 6, 7, 9, 12, 17, 19, 21, 25]);
|
||||
});
|
||||
|
||||
test('capacity max', function () {
|
||||
let list = new SkipList<number, boolean>((a, b) => a - b, 10);
|
||||
list.set(1, true);
|
||||
list.set(2, true);
|
||||
list.set(3, true);
|
||||
list.set(4, true);
|
||||
list.set(5, true);
|
||||
list.set(6, true);
|
||||
list.set(7, true);
|
||||
list.set(8, true);
|
||||
list.set(9, true);
|
||||
list.set(10, true);
|
||||
list.set(11, true);
|
||||
list.set(12, true);
|
||||
|
||||
assertKeys(list, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]);
|
||||
});
|
||||
|
||||
const cmp = (a: number, b: number): number => {
|
||||
if (a < b) {
|
||||
return -1;
|
||||
} else if (a > b) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
function insertArraySorted(array: number[], element: number) {
|
||||
let idx = binarySearch(array, element, cmp);
|
||||
if (idx >= 0) {
|
||||
array[idx] = element;
|
||||
} else {
|
||||
idx = ~idx;
|
||||
// array = array.slice(0, idx).concat(element, array.slice(idx));
|
||||
array.splice(idx, 0, element);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
function delArraySorted(array: number[], element: number) {
|
||||
let idx = binarySearch(array, element, cmp);
|
||||
if (idx >= 0) {
|
||||
// array = array.slice(0, idx).concat(array.slice(idx));
|
||||
array.splice(idx, 1);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
|
||||
test('perf', function () {
|
||||
this.skip();
|
||||
|
||||
// data
|
||||
const max = 2 ** 16;
|
||||
const values = new Set<number>();
|
||||
for (let i = 0; i < max; i++) {
|
||||
let value = Math.floor(Math.random() * max);
|
||||
values.add(value);
|
||||
}
|
||||
console.log(values.size);
|
||||
|
||||
// init
|
||||
let list = new SkipList<number, boolean>(cmp, max);
|
||||
let sw = new StopWatch(true);
|
||||
values.forEach(value => list.set(value, true));
|
||||
sw.stop();
|
||||
console.log(`[LIST] ${list.size} elements after ${sw.elapsed()}ms`);
|
||||
let array: number[] = [];
|
||||
sw = new StopWatch(true);
|
||||
values.forEach(value => array = insertArraySorted(array, value));
|
||||
sw.stop();
|
||||
console.log(`[ARRAY] ${array.length} elements after ${sw.elapsed()}ms`);
|
||||
|
||||
// get
|
||||
sw = new StopWatch(true);
|
||||
let someValues = [...values].slice(0, values.size / 4);
|
||||
someValues.forEach(key => {
|
||||
let value = list.get(key); // find
|
||||
console.assert(value, '[LIST] must have ' + key);
|
||||
list.get(-key); // miss
|
||||
});
|
||||
sw.stop();
|
||||
console.log(`[LIST] retrieve ${sw.elapsed()}ms (${(sw.elapsed() / (someValues.length * 2)).toPrecision(4)}ms/op)`);
|
||||
sw = new StopWatch(true);
|
||||
someValues.forEach(key => {
|
||||
let idx = binarySearch(array, key, cmp); // find
|
||||
console.assert(idx >= 0, '[ARRAY] must have ' + key);
|
||||
binarySearch(array, -key, cmp); // miss
|
||||
});
|
||||
sw.stop();
|
||||
console.log(`[ARRAY] retrieve ${sw.elapsed()}ms (${(sw.elapsed() / (someValues.length * 2)).toPrecision(4)}ms/op)`);
|
||||
|
||||
|
||||
// insert
|
||||
sw = new StopWatch(true);
|
||||
someValues.forEach(key => {
|
||||
list.set(-key, false);
|
||||
});
|
||||
sw.stop();
|
||||
console.log(`[LIST] insert ${sw.elapsed()}ms (${(sw.elapsed() / someValues.length).toPrecision(4)}ms/op)`);
|
||||
sw = new StopWatch(true);
|
||||
someValues.forEach(key => {
|
||||
array = insertArraySorted(array, -key);
|
||||
});
|
||||
sw.stop();
|
||||
console.log(`[ARRAY] insert ${sw.elapsed()}ms (${(sw.elapsed() / someValues.length).toPrecision(4)}ms/op)`);
|
||||
|
||||
// delete
|
||||
sw = new StopWatch(true);
|
||||
someValues.forEach(key => {
|
||||
list.delete(key); // find
|
||||
list.delete(-key); // miss
|
||||
});
|
||||
sw.stop();
|
||||
console.log(`[LIST] delete ${sw.elapsed()}ms (${(sw.elapsed() / (someValues.length * 2)).toPrecision(4)}ms/op)`);
|
||||
sw = new StopWatch(true);
|
||||
someValues.forEach(key => {
|
||||
array = delArraySorted(array, key); // find
|
||||
array = delArraySorted(array, -key); // miss
|
||||
});
|
||||
sw.stop();
|
||||
console.log(`[ARRAY] delete ${sw.elapsed()}ms (${(sw.elapsed() / (someValues.length * 2)).toPrecision(4)}ms/op)`);
|
||||
});
|
||||
});
|
||||
335
lib/vscode/src/vs/base/test/common/stream.test.ts
Normal file
335
lib/vscode/src/vs/base/test/common/stream.test.ts
Normal file
@@ -0,0 +1,335 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { isReadableStream, newWriteableStream, Readable, consumeReadable, peekReadable, consumeStream, ReadableStream, toStream, toReadable, transform, peekStream, isReadableBufferedStream } from 'vs/base/common/stream';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
|
||||
suite('Stream', () => {
|
||||
|
||||
test('isReadableStream', () => {
|
||||
assert.ok(!isReadableStream(Object.create(null)));
|
||||
assert.ok(isReadableStream(newWriteableStream(d => d)));
|
||||
});
|
||||
|
||||
test('isReadableBufferedStream', async () => {
|
||||
assert.ok(!isReadableBufferedStream(Object.create(null)));
|
||||
|
||||
const stream = newWriteableStream(d => d);
|
||||
stream.end();
|
||||
const bufferedStream = await peekStream(stream, 1);
|
||||
assert.ok(isReadableBufferedStream(bufferedStream));
|
||||
});
|
||||
|
||||
test('WriteableStream - basics', () => {
|
||||
const stream = newWriteableStream<string>(strings => strings.join());
|
||||
|
||||
let error = false;
|
||||
stream.on('error', e => {
|
||||
error = true;
|
||||
});
|
||||
|
||||
let end = false;
|
||||
stream.on('end', () => {
|
||||
end = true;
|
||||
});
|
||||
|
||||
stream.write('Hello');
|
||||
|
||||
const chunks: string[] = [];
|
||||
stream.on('data', data => {
|
||||
chunks.push(data);
|
||||
});
|
||||
|
||||
assert.equal(chunks[0], 'Hello');
|
||||
|
||||
stream.write('World');
|
||||
assert.equal(chunks[1], 'World');
|
||||
|
||||
assert.equal(error, false);
|
||||
assert.equal(end, false);
|
||||
|
||||
stream.pause();
|
||||
stream.write('1');
|
||||
stream.write('2');
|
||||
stream.write('3');
|
||||
|
||||
assert.equal(chunks.length, 2);
|
||||
|
||||
stream.resume();
|
||||
|
||||
assert.equal(chunks.length, 3);
|
||||
assert.equal(chunks[2], '1,2,3');
|
||||
|
||||
stream.error(new Error());
|
||||
assert.equal(error, true);
|
||||
|
||||
stream.end('Final Bit');
|
||||
assert.equal(chunks.length, 4);
|
||||
assert.equal(chunks[3], 'Final Bit');
|
||||
|
||||
stream.destroy();
|
||||
|
||||
stream.write('Unexpected');
|
||||
assert.equal(chunks.length, 4);
|
||||
});
|
||||
|
||||
test('WriteableStream - removeListener', () => {
|
||||
const stream = newWriteableStream<string>(strings => strings.join());
|
||||
|
||||
let error = false;
|
||||
const errorListener = (e: Error) => {
|
||||
error = true;
|
||||
};
|
||||
stream.on('error', errorListener);
|
||||
|
||||
let data = false;
|
||||
const dataListener = () => {
|
||||
data = true;
|
||||
};
|
||||
stream.on('data', dataListener);
|
||||
|
||||
stream.write('Hello');
|
||||
assert.equal(data, true);
|
||||
|
||||
data = false;
|
||||
stream.removeListener('data', dataListener);
|
||||
|
||||
stream.write('World');
|
||||
assert.equal(data, false);
|
||||
|
||||
stream.error(new Error());
|
||||
assert.equal(error, true);
|
||||
|
||||
error = false;
|
||||
stream.removeListener('error', errorListener);
|
||||
|
||||
stream.error(new Error());
|
||||
assert.equal(error, false);
|
||||
});
|
||||
|
||||
test('WriteableStream - highWaterMark', async () => {
|
||||
const stream = newWriteableStream<string>(strings => strings.join(), { highWaterMark: 3 });
|
||||
|
||||
let res = stream.write('1');
|
||||
assert.ok(!res);
|
||||
|
||||
res = stream.write('2');
|
||||
assert.ok(!res);
|
||||
|
||||
res = stream.write('3');
|
||||
assert.ok(!res);
|
||||
|
||||
let promise1 = stream.write('4');
|
||||
assert.ok(promise1 instanceof Promise);
|
||||
|
||||
let promise2 = stream.write('5');
|
||||
assert.ok(promise2 instanceof Promise);
|
||||
|
||||
let drained1 = false;
|
||||
(async () => {
|
||||
await promise1;
|
||||
drained1 = true;
|
||||
})();
|
||||
|
||||
let drained2 = false;
|
||||
(async () => {
|
||||
await promise2;
|
||||
drained2 = true;
|
||||
})();
|
||||
|
||||
let data: string | undefined = undefined;
|
||||
stream.on('data', chunk => {
|
||||
data = chunk;
|
||||
});
|
||||
assert.ok(data);
|
||||
|
||||
await timeout(0);
|
||||
assert.equal(drained1, true);
|
||||
assert.equal(drained2, true);
|
||||
});
|
||||
|
||||
test('consumeReadable', () => {
|
||||
const readable = arrayToReadable(['1', '2', '3', '4', '5']);
|
||||
const consumed = consumeReadable(readable, strings => strings.join());
|
||||
assert.equal(consumed, '1,2,3,4,5');
|
||||
});
|
||||
|
||||
test('peekReadable', () => {
|
||||
for (let i = 0; i < 5; i++) {
|
||||
const readable = arrayToReadable(['1', '2', '3', '4', '5']);
|
||||
|
||||
const consumedOrReadable = peekReadable(readable, strings => strings.join(), i);
|
||||
if (typeof consumedOrReadable === 'string') {
|
||||
assert.fail('Unexpected result');
|
||||
} else {
|
||||
const consumed = consumeReadable(consumedOrReadable, strings => strings.join());
|
||||
assert.equal(consumed, '1,2,3,4,5');
|
||||
}
|
||||
}
|
||||
|
||||
let readable = arrayToReadable(['1', '2', '3', '4', '5']);
|
||||
let consumedOrReadable = peekReadable(readable, strings => strings.join(), 5);
|
||||
assert.equal(consumedOrReadable, '1,2,3,4,5');
|
||||
|
||||
readable = arrayToReadable(['1', '2', '3', '4', '5']);
|
||||
consumedOrReadable = peekReadable(readable, strings => strings.join(), 6);
|
||||
assert.equal(consumedOrReadable, '1,2,3,4,5');
|
||||
});
|
||||
|
||||
test('peekReadable - error handling', async () => {
|
||||
|
||||
// 0 Chunks
|
||||
let stream = newWriteableStream(data => data);
|
||||
|
||||
let error: Error | undefined = undefined;
|
||||
let promise = (async () => {
|
||||
try {
|
||||
await peekStream(stream, 1);
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
})();
|
||||
|
||||
stream.error(new Error());
|
||||
await promise;
|
||||
|
||||
assert.ok(error);
|
||||
|
||||
// 1 Chunk
|
||||
stream = newWriteableStream(data => data);
|
||||
|
||||
error = undefined;
|
||||
promise = (async () => {
|
||||
try {
|
||||
await peekStream(stream, 1);
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
})();
|
||||
|
||||
stream.write('foo');
|
||||
stream.error(new Error());
|
||||
await promise;
|
||||
|
||||
assert.ok(error);
|
||||
|
||||
// 2 Chunks
|
||||
stream = newWriteableStream(data => data);
|
||||
|
||||
error = undefined;
|
||||
promise = (async () => {
|
||||
try {
|
||||
await peekStream(stream, 1);
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
})();
|
||||
|
||||
stream.write('foo');
|
||||
stream.write('bar');
|
||||
stream.error(new Error());
|
||||
await promise;
|
||||
|
||||
assert.ok(!error);
|
||||
|
||||
stream.on('error', err => error = err);
|
||||
stream.on('data', chunk => { });
|
||||
assert.ok(error);
|
||||
});
|
||||
|
||||
function arrayToReadable<T>(array: T[]): Readable<T> {
|
||||
return {
|
||||
read: () => array.shift() || null
|
||||
};
|
||||
}
|
||||
|
||||
function readableToStream(readable: Readable<string>): ReadableStream<string> {
|
||||
const stream = newWriteableStream<string>(strings => strings.join());
|
||||
|
||||
// Simulate async behavior
|
||||
setTimeout(() => {
|
||||
let chunk: string | null = null;
|
||||
while ((chunk = readable.read()) !== null) {
|
||||
stream.write(chunk);
|
||||
}
|
||||
|
||||
stream.end();
|
||||
}, 0);
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
test('consumeStream', async () => {
|
||||
const stream = readableToStream(arrayToReadable(['1', '2', '3', '4', '5']));
|
||||
const consumed = await consumeStream(stream, strings => strings.join());
|
||||
assert.equal(consumed, '1,2,3,4,5');
|
||||
});
|
||||
|
||||
test('peekStream', async () => {
|
||||
for (let i = 0; i < 5; i++) {
|
||||
const stream = readableToStream(arrayToReadable(['1', '2', '3', '4', '5']));
|
||||
|
||||
const result = await peekStream(stream, i);
|
||||
assert.equal(stream, result.stream);
|
||||
if (result.ended) {
|
||||
assert.fail('Unexpected result, stream should not have ended yet');
|
||||
} else {
|
||||
assert.equal(result.buffer.length, i + 1, `maxChunks: ${i}`);
|
||||
|
||||
const additionalResult: string[] = [];
|
||||
await consumeStream(stream, strings => {
|
||||
additionalResult.push(...strings);
|
||||
|
||||
return strings.join();
|
||||
});
|
||||
|
||||
assert.equal([...result.buffer, ...additionalResult].join(), '1,2,3,4,5');
|
||||
}
|
||||
}
|
||||
|
||||
let stream = readableToStream(arrayToReadable(['1', '2', '3', '4', '5']));
|
||||
let result = await peekStream(stream, 5);
|
||||
assert.equal(stream, result.stream);
|
||||
assert.equal(result.buffer.join(), '1,2,3,4,5');
|
||||
assert.equal(result.ended, true);
|
||||
|
||||
stream = readableToStream(arrayToReadable(['1', '2', '3', '4', '5']));
|
||||
result = await peekStream(stream, 6);
|
||||
assert.equal(stream, result.stream);
|
||||
assert.equal(result.buffer.join(), '1,2,3,4,5');
|
||||
assert.equal(result.ended, true);
|
||||
});
|
||||
|
||||
test('toStream', async () => {
|
||||
const stream = toStream('1,2,3,4,5', strings => strings.join());
|
||||
const consumed = await consumeStream(stream, strings => strings.join());
|
||||
assert.equal(consumed, '1,2,3,4,5');
|
||||
});
|
||||
|
||||
test('toReadable', async () => {
|
||||
const readable = toReadable('1,2,3,4,5');
|
||||
const consumed = await consumeReadable(readable, strings => strings.join());
|
||||
assert.equal(consumed, '1,2,3,4,5');
|
||||
});
|
||||
|
||||
test('transform', async () => {
|
||||
const source = newWriteableStream<string>(strings => strings.join());
|
||||
|
||||
const result = transform(source, { data: string => string + string }, strings => strings.join());
|
||||
|
||||
// Simulate async behavior
|
||||
setTimeout(() => {
|
||||
source.write('1');
|
||||
source.write('2');
|
||||
source.write('3');
|
||||
source.write('4');
|
||||
source.end('5');
|
||||
}, 0);
|
||||
|
||||
const consumed = await consumeStream(result, strings => strings.join());
|
||||
assert.equal(consumed, '11,22,33,44,55');
|
||||
});
|
||||
});
|
||||
420
lib/vscode/src/vs/base/test/common/strings.test.ts
Normal file
420
lib/vscode/src/vs/base/test/common/strings.test.ts
Normal file
@@ -0,0 +1,420 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as assert from 'assert';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
|
||||
suite('Strings', () => {
|
||||
test('equalsIgnoreCase', () => {
|
||||
assert(strings.equalsIgnoreCase('', ''));
|
||||
assert(!strings.equalsIgnoreCase('', '1'));
|
||||
assert(!strings.equalsIgnoreCase('1', ''));
|
||||
|
||||
assert(strings.equalsIgnoreCase('a', 'a'));
|
||||
assert(strings.equalsIgnoreCase('abc', 'Abc'));
|
||||
assert(strings.equalsIgnoreCase('abc', 'ABC'));
|
||||
assert(strings.equalsIgnoreCase('Höhenmeter', 'HÖhenmeter'));
|
||||
assert(strings.equalsIgnoreCase('ÖL', 'Öl'));
|
||||
});
|
||||
|
||||
test('beginsWithIgnoreCase', () => {
|
||||
assert(strings.startsWithIgnoreCase('', ''));
|
||||
assert(!strings.startsWithIgnoreCase('', '1'));
|
||||
assert(strings.startsWithIgnoreCase('1', ''));
|
||||
|
||||
assert(strings.startsWithIgnoreCase('a', 'a'));
|
||||
assert(strings.startsWithIgnoreCase('abc', 'Abc'));
|
||||
assert(strings.startsWithIgnoreCase('abc', 'ABC'));
|
||||
assert(strings.startsWithIgnoreCase('Höhenmeter', 'HÖhenmeter'));
|
||||
assert(strings.startsWithIgnoreCase('ÖL', 'Öl'));
|
||||
|
||||
assert(strings.startsWithIgnoreCase('alles klar', 'a'));
|
||||
assert(strings.startsWithIgnoreCase('alles klar', 'A'));
|
||||
assert(strings.startsWithIgnoreCase('alles klar', 'alles k'));
|
||||
assert(strings.startsWithIgnoreCase('alles klar', 'alles K'));
|
||||
assert(strings.startsWithIgnoreCase('alles klar', 'ALLES K'));
|
||||
assert(strings.startsWithIgnoreCase('alles klar', 'alles klar'));
|
||||
assert(strings.startsWithIgnoreCase('alles klar', 'ALLES KLAR'));
|
||||
|
||||
assert(!strings.startsWithIgnoreCase('alles klar', ' ALLES K'));
|
||||
assert(!strings.startsWithIgnoreCase('alles klar', 'ALLES K '));
|
||||
assert(!strings.startsWithIgnoreCase('alles klar', 'öALLES K '));
|
||||
assert(!strings.startsWithIgnoreCase('alles klar', ' '));
|
||||
assert(!strings.startsWithIgnoreCase('alles klar', 'ö'));
|
||||
});
|
||||
|
||||
test('compareIgnoreCase', () => {
|
||||
|
||||
function assertCompareIgnoreCase(a: string, b: string, recurse = true): void {
|
||||
let actual = strings.compareIgnoreCase(a, b);
|
||||
actual = actual > 0 ? 1 : actual < 0 ? -1 : actual;
|
||||
|
||||
let expected = strings.compare(a.toLowerCase(), b.toLowerCase());
|
||||
expected = expected > 0 ? 1 : expected < 0 ? -1 : expected;
|
||||
assert.equal(actual, expected, `${a} <> ${b}`);
|
||||
|
||||
if (recurse) {
|
||||
assertCompareIgnoreCase(b, a, false);
|
||||
}
|
||||
}
|
||||
|
||||
assertCompareIgnoreCase('', '');
|
||||
assertCompareIgnoreCase('abc', 'ABC');
|
||||
assertCompareIgnoreCase('abc', 'ABc');
|
||||
assertCompareIgnoreCase('abc', 'ABcd');
|
||||
assertCompareIgnoreCase('abc', 'abcd');
|
||||
assertCompareIgnoreCase('foo', 'föo');
|
||||
assertCompareIgnoreCase('Code', 'code');
|
||||
assertCompareIgnoreCase('Code', 'cöde');
|
||||
|
||||
assertCompareIgnoreCase('B', 'a');
|
||||
assertCompareIgnoreCase('a', 'B');
|
||||
assertCompareIgnoreCase('b', 'a');
|
||||
assertCompareIgnoreCase('a', 'b');
|
||||
|
||||
assertCompareIgnoreCase('aa', 'ab');
|
||||
assertCompareIgnoreCase('aa', 'aB');
|
||||
assertCompareIgnoreCase('aa', 'aA');
|
||||
assertCompareIgnoreCase('a', 'aa');
|
||||
assertCompareIgnoreCase('ab', 'aA');
|
||||
assertCompareIgnoreCase('O', '/');
|
||||
});
|
||||
|
||||
test('compareIgnoreCase (substring)', () => {
|
||||
|
||||
function assertCompareIgnoreCase(a: string, b: string, aStart: number, aEnd: number, bStart: number, bEnd: number, recurse = true): void {
|
||||
let actual = strings.compareSubstringIgnoreCase(a, b, aStart, aEnd, bStart, bEnd);
|
||||
actual = actual > 0 ? 1 : actual < 0 ? -1 : actual;
|
||||
|
||||
let expected = strings.compare(a.toLowerCase().substring(aStart, aEnd), b.toLowerCase().substring(bStart, bEnd));
|
||||
expected = expected > 0 ? 1 : expected < 0 ? -1 : expected;
|
||||
assert.equal(actual, expected, `${a} <> ${b}`);
|
||||
|
||||
if (recurse) {
|
||||
assertCompareIgnoreCase(b, a, bStart, bEnd, aStart, aEnd, false);
|
||||
}
|
||||
}
|
||||
|
||||
assertCompareIgnoreCase('', '', 0, 0, 0, 0);
|
||||
assertCompareIgnoreCase('abc', 'ABC', 0, 1, 0, 1);
|
||||
assertCompareIgnoreCase('abc', 'Aabc', 0, 3, 1, 4);
|
||||
assertCompareIgnoreCase('abcABc', 'ABcd', 3, 6, 0, 4);
|
||||
});
|
||||
|
||||
test('format', () => {
|
||||
assert.strictEqual(strings.format('Foo Bar'), 'Foo Bar');
|
||||
assert.strictEqual(strings.format('Foo {0} Bar'), 'Foo {0} Bar');
|
||||
assert.strictEqual(strings.format('Foo {0} Bar', 'yes'), 'Foo yes Bar');
|
||||
assert.strictEqual(strings.format('Foo {0} Bar {0}', 'yes'), 'Foo yes Bar yes');
|
||||
assert.strictEqual(strings.format('Foo {0} Bar {1}{2}', 'yes'), 'Foo yes Bar {1}{2}');
|
||||
assert.strictEqual(strings.format('Foo {0} Bar {1}{2}', 'yes', undefined), 'Foo yes Bar undefined{2}');
|
||||
assert.strictEqual(strings.format('Foo {0} Bar {1}{2}', 'yes', 5, false), 'Foo yes Bar 5false');
|
||||
assert.strictEqual(strings.format('Foo {0} Bar. {1}', '(foo)', '.test'), 'Foo (foo) Bar. .test');
|
||||
});
|
||||
|
||||
test('lcut', () => {
|
||||
assert.strictEqual(strings.lcut('foo bar', 0), '');
|
||||
assert.strictEqual(strings.lcut('foo bar', 1), 'bar');
|
||||
assert.strictEqual(strings.lcut('foo bar', 3), 'bar');
|
||||
assert.strictEqual(strings.lcut('foo bar', 4), 'bar'); // Leading whitespace trimmed
|
||||
assert.strictEqual(strings.lcut('foo bar', 5), 'foo bar');
|
||||
assert.strictEqual(strings.lcut('test string 0.1.2.3', 3), '2.3');
|
||||
|
||||
assert.strictEqual(strings.lcut('', 10), '');
|
||||
assert.strictEqual(strings.lcut('a', 10), 'a');
|
||||
});
|
||||
|
||||
test('escape', () => {
|
||||
assert.strictEqual(strings.escape(''), '');
|
||||
assert.strictEqual(strings.escape('foo'), 'foo');
|
||||
assert.strictEqual(strings.escape('foo bar'), 'foo bar');
|
||||
assert.strictEqual(strings.escape('<foo bar>'), '<foo bar>');
|
||||
assert.strictEqual(strings.escape('<foo>Hello</foo>'), '<foo>Hello</foo>');
|
||||
});
|
||||
|
||||
test('ltrim', () => {
|
||||
assert.strictEqual(strings.ltrim('foo', 'f'), 'oo');
|
||||
assert.strictEqual(strings.ltrim('foo', 'o'), 'foo');
|
||||
assert.strictEqual(strings.ltrim('http://www.test.de', 'http://'), 'www.test.de');
|
||||
assert.strictEqual(strings.ltrim('/foo/', '/'), 'foo/');
|
||||
assert.strictEqual(strings.ltrim('//foo/', '/'), 'foo/');
|
||||
assert.strictEqual(strings.ltrim('/', ''), '/');
|
||||
assert.strictEqual(strings.ltrim('/', '/'), '');
|
||||
assert.strictEqual(strings.ltrim('///', '/'), '');
|
||||
assert.strictEqual(strings.ltrim('', ''), '');
|
||||
assert.strictEqual(strings.ltrim('', '/'), '');
|
||||
});
|
||||
|
||||
test('rtrim', () => {
|
||||
assert.strictEqual(strings.rtrim('foo', 'o'), 'f');
|
||||
assert.strictEqual(strings.rtrim('foo', 'f'), 'foo');
|
||||
assert.strictEqual(strings.rtrim('http://www.test.de', '.de'), 'http://www.test');
|
||||
assert.strictEqual(strings.rtrim('/foo/', '/'), '/foo');
|
||||
assert.strictEqual(strings.rtrim('/foo//', '/'), '/foo');
|
||||
assert.strictEqual(strings.rtrim('/', ''), '/');
|
||||
assert.strictEqual(strings.rtrim('/', '/'), '');
|
||||
assert.strictEqual(strings.rtrim('///', '/'), '');
|
||||
assert.strictEqual(strings.rtrim('', ''), '');
|
||||
assert.strictEqual(strings.rtrim('', '/'), '');
|
||||
});
|
||||
|
||||
test('trim', () => {
|
||||
assert.strictEqual(strings.trim(' foo '), 'foo');
|
||||
assert.strictEqual(strings.trim(' foo'), 'foo');
|
||||
assert.strictEqual(strings.trim('bar '), 'bar');
|
||||
assert.strictEqual(strings.trim(' '), '');
|
||||
assert.strictEqual(strings.trim('foo bar', 'bar'), 'foo ');
|
||||
});
|
||||
|
||||
test('trimWhitespace', () => {
|
||||
assert.strictEqual(' foo '.trim(), 'foo');
|
||||
assert.strictEqual(' foo '.trim(), 'foo');
|
||||
assert.strictEqual(' foo'.trim(), 'foo');
|
||||
assert.strictEqual('bar '.trim(), 'bar');
|
||||
assert.strictEqual(' '.trim(), '');
|
||||
assert.strictEqual(' '.trim(), '');
|
||||
});
|
||||
|
||||
test('lastNonWhitespaceIndex', () => {
|
||||
assert.strictEqual(strings.lastNonWhitespaceIndex('abc \t \t '), 2);
|
||||
assert.strictEqual(strings.lastNonWhitespaceIndex('abc'), 2);
|
||||
assert.strictEqual(strings.lastNonWhitespaceIndex('abc\t'), 2);
|
||||
assert.strictEqual(strings.lastNonWhitespaceIndex('abc '), 2);
|
||||
assert.strictEqual(strings.lastNonWhitespaceIndex('abc \t \t '), 2);
|
||||
assert.strictEqual(strings.lastNonWhitespaceIndex('abc \t \t abc \t \t '), 11);
|
||||
assert.strictEqual(strings.lastNonWhitespaceIndex('abc \t \t abc \t \t ', 8), 2);
|
||||
assert.strictEqual(strings.lastNonWhitespaceIndex(' \t \t '), -1);
|
||||
});
|
||||
|
||||
test('containsRTL', () => {
|
||||
assert.equal(strings.containsRTL('a'), false);
|
||||
assert.equal(strings.containsRTL(''), false);
|
||||
assert.equal(strings.containsRTL(strings.UTF8_BOM_CHARACTER + 'a'), false);
|
||||
assert.equal(strings.containsRTL('hello world!'), false);
|
||||
assert.equal(strings.containsRTL('a📚📚b'), false);
|
||||
assert.equal(strings.containsRTL('هناك حقيقة مثبتة منذ زمن طويل'), true);
|
||||
assert.equal(strings.containsRTL('זוהי עובדה מבוססת שדעתו'), true);
|
||||
});
|
||||
|
||||
test('containsEmoji', () => {
|
||||
assert.equal(strings.containsEmoji('a'), false);
|
||||
assert.equal(strings.containsEmoji(''), false);
|
||||
assert.equal(strings.containsEmoji(strings.UTF8_BOM_CHARACTER + 'a'), false);
|
||||
assert.equal(strings.containsEmoji('hello world!'), false);
|
||||
assert.equal(strings.containsEmoji('هناك حقيقة مثبتة منذ زمن طويل'), false);
|
||||
assert.equal(strings.containsEmoji('זוהי עובדה מבוססת שדעתו'), false);
|
||||
|
||||
assert.equal(strings.containsEmoji('a📚📚b'), true);
|
||||
assert.equal(strings.containsEmoji('1F600 # 😀 grinning face'), true);
|
||||
assert.equal(strings.containsEmoji('1F47E # 👾 alien monster'), true);
|
||||
assert.equal(strings.containsEmoji('1F467 1F3FD # 👧🏽 girl: medium skin tone'), true);
|
||||
assert.equal(strings.containsEmoji('26EA # ⛪ church'), true);
|
||||
assert.equal(strings.containsEmoji('231B # ⌛ hourglass'), true);
|
||||
assert.equal(strings.containsEmoji('2702 # ✂ scissors'), true);
|
||||
assert.equal(strings.containsEmoji('1F1F7 1F1F4 # 🇷🇴 Romania'), true);
|
||||
});
|
||||
|
||||
test('isBasicASCII', () => {
|
||||
function assertIsBasicASCII(str: string, expected: boolean): void {
|
||||
assert.equal(strings.isBasicASCII(str), expected, str + ` (${str.charCodeAt(0)})`);
|
||||
}
|
||||
assertIsBasicASCII('abcdefghijklmnopqrstuvwxyz', true);
|
||||
assertIsBasicASCII('ABCDEFGHIJKLMNOPQRSTUVWXYZ', true);
|
||||
assertIsBasicASCII('1234567890', true);
|
||||
assertIsBasicASCII('`~!@#$%^&*()-_=+[{]}\\|;:\'",<.>/?', true);
|
||||
assertIsBasicASCII(' ', true);
|
||||
assertIsBasicASCII('\t', true);
|
||||
assertIsBasicASCII('\n', true);
|
||||
assertIsBasicASCII('\r', true);
|
||||
|
||||
let ALL = '\r\t\n';
|
||||
for (let i = 32; i < 127; i++) {
|
||||
ALL += String.fromCharCode(i);
|
||||
}
|
||||
assertIsBasicASCII(ALL, true);
|
||||
|
||||
assertIsBasicASCII(String.fromCharCode(31), false);
|
||||
assertIsBasicASCII(String.fromCharCode(127), false);
|
||||
assertIsBasicASCII('ü', false);
|
||||
assertIsBasicASCII('a📚📚b', false);
|
||||
});
|
||||
|
||||
test('createRegExp', () => {
|
||||
// Empty
|
||||
assert.throws(() => strings.createRegExp('', false));
|
||||
|
||||
// Escapes appropriately
|
||||
assert.equal(strings.createRegExp('abc', false).source, 'abc');
|
||||
assert.equal(strings.createRegExp('([^ ,.]*)', false).source, '\\(\\[\\^ ,\\.\\]\\*\\)');
|
||||
assert.equal(strings.createRegExp('([^ ,.]*)', true).source, '([^ ,.]*)');
|
||||
|
||||
// Whole word
|
||||
assert.equal(strings.createRegExp('abc', false, { wholeWord: true }).source, '\\babc\\b');
|
||||
assert.equal(strings.createRegExp('abc', true, { wholeWord: true }).source, '\\babc\\b');
|
||||
assert.equal(strings.createRegExp(' abc', true, { wholeWord: true }).source, ' abc\\b');
|
||||
assert.equal(strings.createRegExp('abc ', true, { wholeWord: true }).source, '\\babc ');
|
||||
assert.equal(strings.createRegExp(' abc ', true, { wholeWord: true }).source, ' abc ');
|
||||
|
||||
const regExpWithoutFlags = strings.createRegExp('abc', true);
|
||||
assert(!regExpWithoutFlags.global);
|
||||
assert(regExpWithoutFlags.ignoreCase);
|
||||
assert(!regExpWithoutFlags.multiline);
|
||||
|
||||
const regExpWithFlags = strings.createRegExp('abc', true, { global: true, matchCase: true, multiline: true });
|
||||
assert(regExpWithFlags.global);
|
||||
assert(!regExpWithFlags.ignoreCase);
|
||||
assert(regExpWithFlags.multiline);
|
||||
});
|
||||
|
||||
test('regExpContainsBackreference', () => {
|
||||
assert(strings.regExpContainsBackreference('foo \\5 bar'));
|
||||
assert(strings.regExpContainsBackreference('\\2'));
|
||||
assert(strings.regExpContainsBackreference('(\\d)(\\n)(\\1)'));
|
||||
assert(strings.regExpContainsBackreference('(A).*?\\1'));
|
||||
assert(strings.regExpContainsBackreference('\\\\\\1'));
|
||||
assert(strings.regExpContainsBackreference('foo \\\\\\1'));
|
||||
|
||||
assert(!strings.regExpContainsBackreference(''));
|
||||
assert(!strings.regExpContainsBackreference('\\\\1'));
|
||||
assert(!strings.regExpContainsBackreference('foo \\\\1'));
|
||||
assert(!strings.regExpContainsBackreference('(A).*?\\\\1'));
|
||||
assert(!strings.regExpContainsBackreference('foo \\d1 bar'));
|
||||
assert(!strings.regExpContainsBackreference('123'));
|
||||
});
|
||||
|
||||
test('getLeadingWhitespace', () => {
|
||||
assert.equal(strings.getLeadingWhitespace(' foo'), ' ');
|
||||
assert.equal(strings.getLeadingWhitespace(' foo', 2), '');
|
||||
assert.equal(strings.getLeadingWhitespace(' foo', 1, 1), '');
|
||||
assert.equal(strings.getLeadingWhitespace(' foo', 0, 1), ' ');
|
||||
assert.equal(strings.getLeadingWhitespace(' '), ' ');
|
||||
assert.equal(strings.getLeadingWhitespace(' ', 1), ' ');
|
||||
assert.equal(strings.getLeadingWhitespace(' ', 0, 1), ' ');
|
||||
assert.equal(strings.getLeadingWhitespace('\t\tfunction foo(){', 0, 1), '\t');
|
||||
assert.equal(strings.getLeadingWhitespace('\t\tfunction foo(){', 0, 2), '\t\t');
|
||||
});
|
||||
|
||||
test('fuzzyContains', () => {
|
||||
assert.ok(!strings.fuzzyContains((undefined)!, null!));
|
||||
assert.ok(strings.fuzzyContains('hello world', 'h'));
|
||||
assert.ok(!strings.fuzzyContains('hello world', 'q'));
|
||||
assert.ok(strings.fuzzyContains('hello world', 'hw'));
|
||||
assert.ok(strings.fuzzyContains('hello world', 'horl'));
|
||||
assert.ok(strings.fuzzyContains('hello world', 'd'));
|
||||
assert.ok(!strings.fuzzyContains('hello world', 'wh'));
|
||||
assert.ok(!strings.fuzzyContains('d', 'dd'));
|
||||
});
|
||||
|
||||
test('startsWithUTF8BOM', () => {
|
||||
assert(strings.startsWithUTF8BOM(strings.UTF8_BOM_CHARACTER));
|
||||
assert(strings.startsWithUTF8BOM(strings.UTF8_BOM_CHARACTER + 'a'));
|
||||
assert(strings.startsWithUTF8BOM(strings.UTF8_BOM_CHARACTER + 'aaaaaaaaaa'));
|
||||
assert(!strings.startsWithUTF8BOM(' ' + strings.UTF8_BOM_CHARACTER));
|
||||
assert(!strings.startsWithUTF8BOM('foo'));
|
||||
assert(!strings.startsWithUTF8BOM(''));
|
||||
});
|
||||
|
||||
test('stripUTF8BOM', () => {
|
||||
assert.equal(strings.stripUTF8BOM(strings.UTF8_BOM_CHARACTER), '');
|
||||
assert.equal(strings.stripUTF8BOM(strings.UTF8_BOM_CHARACTER + 'foobar'), 'foobar');
|
||||
assert.equal(strings.stripUTF8BOM('foobar' + strings.UTF8_BOM_CHARACTER), 'foobar' + strings.UTF8_BOM_CHARACTER);
|
||||
assert.equal(strings.stripUTF8BOM('abc'), 'abc');
|
||||
assert.equal(strings.stripUTF8BOM(''), '');
|
||||
});
|
||||
|
||||
test('containsUppercaseCharacter', () => {
|
||||
[
|
||||
[null, false],
|
||||
['', false],
|
||||
['foo', false],
|
||||
['föö', false],
|
||||
['ناك', false],
|
||||
['מבוססת', false],
|
||||
['😀', false],
|
||||
['(#@()*&%()@*#&09827340982374}{:">?></\'\\~`', false],
|
||||
|
||||
['Foo', true],
|
||||
['FOO', true],
|
||||
['FöÖ', true],
|
||||
['FöÖ', true],
|
||||
['\\Foo', true],
|
||||
].forEach(([str, result]) => {
|
||||
assert.equal(strings.containsUppercaseCharacter(<string>str), result, `Wrong result for ${str}`);
|
||||
});
|
||||
});
|
||||
|
||||
test('containsUppercaseCharacter (ignoreEscapedChars)', () => {
|
||||
[
|
||||
['\\Woo', false],
|
||||
['f\\S\\S', false],
|
||||
['foo', false],
|
||||
|
||||
['Foo', true],
|
||||
].forEach(([str, result]) => {
|
||||
assert.equal(strings.containsUppercaseCharacter(<string>str, true), result, `Wrong result for ${str}`);
|
||||
});
|
||||
});
|
||||
|
||||
test('uppercaseFirstLetter', () => {
|
||||
[
|
||||
['', ''],
|
||||
['foo', 'Foo'],
|
||||
['f', 'F'],
|
||||
['123', '123'],
|
||||
['.a', '.a'],
|
||||
].forEach(([inStr, result]) => {
|
||||
assert.equal(strings.uppercaseFirstLetter(inStr), result, `Wrong result for ${inStr}`);
|
||||
});
|
||||
});
|
||||
|
||||
test('getNLines', () => {
|
||||
assert.equal(strings.getNLines('', 5), '');
|
||||
assert.equal(strings.getNLines('foo', 5), 'foo');
|
||||
assert.equal(strings.getNLines('foo\nbar', 5), 'foo\nbar');
|
||||
assert.equal(strings.getNLines('foo\nbar', 2), 'foo\nbar');
|
||||
|
||||
assert.equal(strings.getNLines('foo\nbar', 1), 'foo');
|
||||
assert.equal(strings.getNLines('foo\nbar'), 'foo');
|
||||
assert.equal(strings.getNLines('foo\nbar\nsomething', 2), 'foo\nbar');
|
||||
assert.equal(strings.getNLines('foo', 0), '');
|
||||
});
|
||||
|
||||
test('encodeUTF8', function () {
|
||||
function assertEncodeUTF8(str: string, expected: number[]): void {
|
||||
const actual = strings.encodeUTF8(str);
|
||||
const actualArr: number[] = [];
|
||||
for (let offset = 0; offset < actual.byteLength; offset++) {
|
||||
actualArr[offset] = actual[offset];
|
||||
}
|
||||
assert.deepEqual(actualArr, expected);
|
||||
}
|
||||
|
||||
function assertDecodeUTF8(data: number[], expected: string): void {
|
||||
const actual = strings.decodeUTF8(new Uint8Array(data));
|
||||
assert.deepEqual(actual, expected);
|
||||
}
|
||||
|
||||
function assertEncodeDecodeUTF8(str: string, buff: number[]): void {
|
||||
assertEncodeUTF8(str, buff);
|
||||
assertDecodeUTF8(buff, str);
|
||||
}
|
||||
|
||||
assertEncodeDecodeUTF8('\u0000', [0]);
|
||||
assertEncodeDecodeUTF8('!', [33]);
|
||||
assertEncodeDecodeUTF8('\u007F', [127]);
|
||||
assertEncodeDecodeUTF8('\u0080', [194, 128]);
|
||||
assertEncodeDecodeUTF8('Ɲ', [198, 157]);
|
||||
assertEncodeDecodeUTF8('\u07FF', [223, 191]);
|
||||
assertEncodeDecodeUTF8('\u0800', [224, 160, 128]);
|
||||
assertEncodeDecodeUTF8('ஂ', [224, 174, 130]);
|
||||
assertEncodeDecodeUTF8('\uffff', [239, 191, 191]);
|
||||
assertEncodeDecodeUTF8('\u10000', [225, 128, 128, 48]);
|
||||
assertEncodeDecodeUTF8('🧝', [240, 159, 167, 157]);
|
||||
|
||||
});
|
||||
|
||||
test('getGraphemeBreakType', () => {
|
||||
assert.equal(strings.getGraphemeBreakType(0xBC1), strings.GraphemeBreakType.SpacingMark);
|
||||
});
|
||||
});
|
||||
212
lib/vscode/src/vs/base/test/common/types.test.ts
Normal file
212
lib/vscode/src/vs/base/test/common/types.test.ts
Normal file
@@ -0,0 +1,212 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import * as types from 'vs/base/common/types';
|
||||
|
||||
suite('Types', () => {
|
||||
|
||||
test('isFunction', () => {
|
||||
assert(!types.isFunction(undefined));
|
||||
assert(!types.isFunction(null));
|
||||
assert(!types.isFunction('foo'));
|
||||
assert(!types.isFunction(5));
|
||||
assert(!types.isFunction(true));
|
||||
assert(!types.isFunction([]));
|
||||
assert(!types.isFunction([1, 2, '3']));
|
||||
assert(!types.isFunction({}));
|
||||
assert(!types.isFunction({ foo: 'bar' }));
|
||||
assert(!types.isFunction(/test/));
|
||||
assert(!types.isFunction(new RegExp('')));
|
||||
assert(!types.isFunction(new Date()));
|
||||
|
||||
assert(types.isFunction(assert));
|
||||
assert(types.isFunction(function foo() { /**/ }));
|
||||
});
|
||||
|
||||
test('areFunctions', () => {
|
||||
assert(!types.areFunctions());
|
||||
assert(!types.areFunctions(null));
|
||||
assert(!types.areFunctions('foo'));
|
||||
assert(!types.areFunctions(5));
|
||||
assert(!types.areFunctions(true));
|
||||
assert(!types.areFunctions([]));
|
||||
assert(!types.areFunctions([1, 2, '3']));
|
||||
assert(!types.areFunctions({}));
|
||||
assert(!types.areFunctions({ foo: 'bar' }));
|
||||
assert(!types.areFunctions(/test/));
|
||||
assert(!types.areFunctions(new RegExp('')));
|
||||
assert(!types.areFunctions(new Date()));
|
||||
assert(!types.areFunctions(assert, ''));
|
||||
|
||||
assert(types.areFunctions(assert));
|
||||
assert(types.areFunctions(assert, assert));
|
||||
assert(types.areFunctions(function foo() { /**/ }));
|
||||
});
|
||||
|
||||
test('isObject', () => {
|
||||
assert(!types.isObject(undefined));
|
||||
assert(!types.isObject(null));
|
||||
assert(!types.isObject('foo'));
|
||||
assert(!types.isObject(5));
|
||||
assert(!types.isObject(true));
|
||||
assert(!types.isObject([]));
|
||||
assert(!types.isObject([1, 2, '3']));
|
||||
assert(!types.isObject(/test/));
|
||||
assert(!types.isObject(new RegExp('')));
|
||||
assert(!types.isFunction(new Date()));
|
||||
assert(!types.isObject(assert));
|
||||
assert(!types.isObject(function foo() { }));
|
||||
|
||||
assert(types.isObject({}));
|
||||
assert(types.isObject({ foo: 'bar' }));
|
||||
});
|
||||
|
||||
test('isEmptyObject', () => {
|
||||
assert(!types.isEmptyObject(undefined));
|
||||
assert(!types.isEmptyObject(null));
|
||||
assert(!types.isEmptyObject('foo'));
|
||||
assert(!types.isEmptyObject(5));
|
||||
assert(!types.isEmptyObject(true));
|
||||
assert(!types.isEmptyObject([]));
|
||||
assert(!types.isEmptyObject([1, 2, '3']));
|
||||
assert(!types.isEmptyObject(/test/));
|
||||
assert(!types.isEmptyObject(new RegExp('')));
|
||||
assert(!types.isEmptyObject(new Date()));
|
||||
assert(!types.isEmptyObject(assert));
|
||||
assert(!types.isEmptyObject(function foo() { /**/ }));
|
||||
assert(!types.isEmptyObject({ foo: 'bar' }));
|
||||
|
||||
assert(types.isEmptyObject({}));
|
||||
});
|
||||
|
||||
test('isArray', () => {
|
||||
assert(!types.isArray(undefined));
|
||||
assert(!types.isArray(null));
|
||||
assert(!types.isArray('foo'));
|
||||
assert(!types.isArray(5));
|
||||
assert(!types.isArray(true));
|
||||
assert(!types.isArray({}));
|
||||
assert(!types.isArray(/test/));
|
||||
assert(!types.isArray(new RegExp('')));
|
||||
assert(!types.isArray(new Date()));
|
||||
assert(!types.isArray(assert));
|
||||
assert(!types.isArray(function foo() { /**/ }));
|
||||
assert(!types.isArray({ foo: 'bar' }));
|
||||
|
||||
assert(types.isArray([]));
|
||||
assert(types.isArray([1, 2, '3']));
|
||||
});
|
||||
|
||||
test('isString', () => {
|
||||
assert(!types.isString(undefined));
|
||||
assert(!types.isString(null));
|
||||
assert(!types.isString(5));
|
||||
assert(!types.isString([]));
|
||||
assert(!types.isString([1, 2, '3']));
|
||||
assert(!types.isString(true));
|
||||
assert(!types.isString({}));
|
||||
assert(!types.isString(/test/));
|
||||
assert(!types.isString(new RegExp('')));
|
||||
assert(!types.isString(new Date()));
|
||||
assert(!types.isString(assert));
|
||||
assert(!types.isString(function foo() { /**/ }));
|
||||
assert(!types.isString({ foo: 'bar' }));
|
||||
|
||||
assert(types.isString('foo'));
|
||||
});
|
||||
|
||||
test('isNumber', () => {
|
||||
assert(!types.isNumber(undefined));
|
||||
assert(!types.isNumber(null));
|
||||
assert(!types.isNumber('foo'));
|
||||
assert(!types.isNumber([]));
|
||||
assert(!types.isNumber([1, 2, '3']));
|
||||
assert(!types.isNumber(true));
|
||||
assert(!types.isNumber({}));
|
||||
assert(!types.isNumber(/test/));
|
||||
assert(!types.isNumber(new RegExp('')));
|
||||
assert(!types.isNumber(new Date()));
|
||||
assert(!types.isNumber(assert));
|
||||
assert(!types.isNumber(function foo() { /**/ }));
|
||||
assert(!types.isNumber({ foo: 'bar' }));
|
||||
assert(!types.isNumber(parseInt('A', 10)));
|
||||
|
||||
assert(types.isNumber(5));
|
||||
});
|
||||
|
||||
test('isUndefined', () => {
|
||||
assert(!types.isUndefined(null));
|
||||
assert(!types.isUndefined('foo'));
|
||||
assert(!types.isUndefined([]));
|
||||
assert(!types.isUndefined([1, 2, '3']));
|
||||
assert(!types.isUndefined(true));
|
||||
assert(!types.isUndefined({}));
|
||||
assert(!types.isUndefined(/test/));
|
||||
assert(!types.isUndefined(new RegExp('')));
|
||||
assert(!types.isUndefined(new Date()));
|
||||
assert(!types.isUndefined(assert));
|
||||
assert(!types.isUndefined(function foo() { /**/ }));
|
||||
assert(!types.isUndefined({ foo: 'bar' }));
|
||||
|
||||
assert(types.isUndefined(undefined));
|
||||
});
|
||||
|
||||
test('isUndefinedOrNull', () => {
|
||||
assert(!types.isUndefinedOrNull('foo'));
|
||||
assert(!types.isUndefinedOrNull([]));
|
||||
assert(!types.isUndefinedOrNull([1, 2, '3']));
|
||||
assert(!types.isUndefinedOrNull(true));
|
||||
assert(!types.isUndefinedOrNull({}));
|
||||
assert(!types.isUndefinedOrNull(/test/));
|
||||
assert(!types.isUndefinedOrNull(new RegExp('')));
|
||||
assert(!types.isUndefinedOrNull(new Date()));
|
||||
assert(!types.isUndefinedOrNull(assert));
|
||||
assert(!types.isUndefinedOrNull(function foo() { /**/ }));
|
||||
assert(!types.isUndefinedOrNull({ foo: 'bar' }));
|
||||
|
||||
assert(types.isUndefinedOrNull(undefined));
|
||||
assert(types.isUndefinedOrNull(null));
|
||||
});
|
||||
|
||||
test('assertIsDefined / assertAreDefined', () => {
|
||||
assert.throws(() => types.assertIsDefined(undefined));
|
||||
assert.throws(() => types.assertIsDefined(null));
|
||||
assert.throws(() => types.assertAllDefined(null, undefined));
|
||||
assert.throws(() => types.assertAllDefined(true, undefined));
|
||||
assert.throws(() => types.assertAllDefined(undefined, false));
|
||||
|
||||
assert.equal(types.assertIsDefined(true), true);
|
||||
assert.equal(types.assertIsDefined(false), false);
|
||||
assert.equal(types.assertIsDefined('Hello'), 'Hello');
|
||||
assert.equal(types.assertIsDefined(''), '');
|
||||
|
||||
const res = types.assertAllDefined(1, true, 'Hello');
|
||||
assert.equal(res[0], 1);
|
||||
assert.equal(res[1], true);
|
||||
assert.equal(res[2], 'Hello');
|
||||
});
|
||||
|
||||
test('validateConstraints', () => {
|
||||
types.validateConstraints([1, 'test', true], [Number, String, Boolean]);
|
||||
types.validateConstraints([1, 'test', true], ['number', 'string', 'boolean']);
|
||||
types.validateConstraints([console.log], [Function]);
|
||||
types.validateConstraints([undefined], [types.isUndefined]);
|
||||
types.validateConstraints([1], [types.isNumber]);
|
||||
|
||||
class Foo { }
|
||||
types.validateConstraints([new Foo()], [Foo]);
|
||||
|
||||
function isFoo(f: any) { }
|
||||
assert.throws(() => types.validateConstraints([new Foo()], [isFoo]));
|
||||
|
||||
function isFoo2(f: any) { return true; }
|
||||
types.validateConstraints([new Foo()], [isFoo2]);
|
||||
|
||||
assert.throws(() => types.validateConstraints([1, true], [types.isNumber, types.isString]));
|
||||
assert.throws(() => types.validateConstraints(['2'], [types.isNumber]));
|
||||
assert.throws(() => types.validateConstraints([1, 'test', true], [Number, String, Number]));
|
||||
});
|
||||
});
|
||||
570
lib/vscode/src/vs/base/test/common/uri.test.ts
Normal file
570
lib/vscode/src/vs/base/test/common/uri.test.ts
Normal file
@@ -0,0 +1,570 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as assert from 'assert';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { isWindows } from 'vs/base/common/platform';
|
||||
|
||||
|
||||
suite('URI', () => {
|
||||
test('file#toString', () => {
|
||||
assert.equal(URI.file('c:/win/path').toString(), 'file:///c%3A/win/path');
|
||||
assert.equal(URI.file('C:/win/path').toString(), 'file:///c%3A/win/path');
|
||||
assert.equal(URI.file('c:/win/path/').toString(), 'file:///c%3A/win/path/');
|
||||
assert.equal(URI.file('/c:/win/path').toString(), 'file:///c%3A/win/path');
|
||||
});
|
||||
|
||||
test('URI.file (win-special)', () => {
|
||||
if (isWindows) {
|
||||
assert.equal(URI.file('c:\\win\\path').toString(), 'file:///c%3A/win/path');
|
||||
assert.equal(URI.file('c:\\win/path').toString(), 'file:///c%3A/win/path');
|
||||
} else {
|
||||
assert.equal(URI.file('c:\\win\\path').toString(), 'file:///c%3A%5Cwin%5Cpath');
|
||||
assert.equal(URI.file('c:\\win/path').toString(), 'file:///c%3A%5Cwin/path');
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
test('file#fsPath (win-special)', () => {
|
||||
if (isWindows) {
|
||||
assert.equal(URI.file('c:\\win\\path').fsPath, 'c:\\win\\path');
|
||||
assert.equal(URI.file('c:\\win/path').fsPath, 'c:\\win\\path');
|
||||
|
||||
assert.equal(URI.file('c:/win/path').fsPath, 'c:\\win\\path');
|
||||
assert.equal(URI.file('c:/win/path/').fsPath, 'c:\\win\\path\\');
|
||||
assert.equal(URI.file('C:/win/path').fsPath, 'c:\\win\\path');
|
||||
assert.equal(URI.file('/c:/win/path').fsPath, 'c:\\win\\path');
|
||||
assert.equal(URI.file('./c/win/path').fsPath, '\\.\\c\\win\\path');
|
||||
} else {
|
||||
assert.equal(URI.file('c:/win/path').fsPath, 'c:/win/path');
|
||||
assert.equal(URI.file('c:/win/path/').fsPath, 'c:/win/path/');
|
||||
assert.equal(URI.file('C:/win/path').fsPath, 'c:/win/path');
|
||||
assert.equal(URI.file('/c:/win/path').fsPath, 'c:/win/path');
|
||||
assert.equal(URI.file('./c/win/path').fsPath, '/./c/win/path');
|
||||
}
|
||||
});
|
||||
|
||||
test('URI#fsPath - no `fsPath` when no `path`', () => {
|
||||
const value = URI.parse('file://%2Fhome%2Fticino%2Fdesktop%2Fcpluscplus%2Ftest.cpp');
|
||||
assert.equal(value.authority, '/home/ticino/desktop/cpluscplus/test.cpp');
|
||||
assert.equal(value.path, '/');
|
||||
if (isWindows) {
|
||||
assert.equal(value.fsPath, '\\');
|
||||
} else {
|
||||
assert.equal(value.fsPath, '/');
|
||||
}
|
||||
});
|
||||
|
||||
test('http#toString', () => {
|
||||
assert.equal(URI.from({ scheme: 'http', authority: 'www.msft.com', path: '/my/path' }).toString(), 'http://www.msft.com/my/path');
|
||||
assert.equal(URI.from({ scheme: 'http', authority: 'www.msft.com', path: '/my/path' }).toString(), 'http://www.msft.com/my/path');
|
||||
assert.equal(URI.from({ scheme: 'http', authority: 'www.MSFT.com', path: '/my/path' }).toString(), 'http://www.msft.com/my/path');
|
||||
assert.equal(URI.from({ scheme: 'http', authority: '', path: 'my/path' }).toString(), 'http:/my/path');
|
||||
assert.equal(URI.from({ scheme: 'http', authority: '', path: '/my/path' }).toString(), 'http:/my/path');
|
||||
//http://a-test-site.com/#test=true
|
||||
assert.equal(URI.from({ scheme: 'http', authority: 'a-test-site.com', path: '/', query: 'test=true' }).toString(), 'http://a-test-site.com/?test%3Dtrue');
|
||||
assert.equal(URI.from({ scheme: 'http', authority: 'a-test-site.com', path: '/', query: '', fragment: 'test=true' }).toString(), 'http://a-test-site.com/#test%3Dtrue');
|
||||
});
|
||||
|
||||
test('http#toString, encode=FALSE', () => {
|
||||
assert.equal(URI.from({ scheme: 'http', authority: 'a-test-site.com', path: '/', query: 'test=true' }).toString(true), 'http://a-test-site.com/?test=true');
|
||||
assert.equal(URI.from({ scheme: 'http', authority: 'a-test-site.com', path: '/', query: '', fragment: 'test=true' }).toString(true), 'http://a-test-site.com/#test=true');
|
||||
assert.equal(URI.from({ scheme: 'http', path: '/api/files/test.me', query: 't=1234' }).toString(true), 'http:/api/files/test.me?t=1234');
|
||||
|
||||
const value = URI.parse('file://shares/pröjects/c%23/#l12');
|
||||
assert.equal(value.authority, 'shares');
|
||||
assert.equal(value.path, '/pröjects/c#/');
|
||||
assert.equal(value.fragment, 'l12');
|
||||
assert.equal(value.toString(), 'file://shares/pr%C3%B6jects/c%23/#l12');
|
||||
assert.equal(value.toString(true), 'file://shares/pröjects/c%23/#l12');
|
||||
|
||||
const uri2 = URI.parse(value.toString(true));
|
||||
const uri3 = URI.parse(value.toString());
|
||||
assert.equal(uri2.authority, uri3.authority);
|
||||
assert.equal(uri2.path, uri3.path);
|
||||
assert.equal(uri2.query, uri3.query);
|
||||
assert.equal(uri2.fragment, uri3.fragment);
|
||||
});
|
||||
|
||||
test('with, identity', () => {
|
||||
let uri = URI.parse('foo:bar/path');
|
||||
|
||||
let uri2 = uri.with(null!);
|
||||
assert.ok(uri === uri2);
|
||||
uri2 = uri.with(undefined!);
|
||||
assert.ok(uri === uri2);
|
||||
uri2 = uri.with({});
|
||||
assert.ok(uri === uri2);
|
||||
uri2 = uri.with({ scheme: 'foo', path: 'bar/path' });
|
||||
assert.ok(uri === uri2);
|
||||
});
|
||||
|
||||
test('with, changes', () => {
|
||||
assert.equal(URI.parse('before:some/file/path').with({ scheme: 'after' }).toString(), 'after:some/file/path');
|
||||
assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'http', path: '/api/files/test.me', query: 't=1234' }).toString(), 'http:/api/files/test.me?t%3D1234');
|
||||
assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'http', authority: '', path: '/api/files/test.me', query: 't=1234', fragment: '' }).toString(), 'http:/api/files/test.me?t%3D1234');
|
||||
assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'https', authority: '', path: '/api/files/test.me', query: 't=1234', fragment: '' }).toString(), 'https:/api/files/test.me?t%3D1234');
|
||||
assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'HTTP', authority: '', path: '/api/files/test.me', query: 't=1234', fragment: '' }).toString(), 'HTTP:/api/files/test.me?t%3D1234');
|
||||
assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'HTTPS', authority: '', path: '/api/files/test.me', query: 't=1234', fragment: '' }).toString(), 'HTTPS:/api/files/test.me?t%3D1234');
|
||||
assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'boo', authority: '', path: '/api/files/test.me', query: 't=1234', fragment: '' }).toString(), 'boo:/api/files/test.me?t%3D1234');
|
||||
});
|
||||
|
||||
test('with, remove components #8465', () => {
|
||||
assert.equal(URI.parse('scheme://authority/path').with({ authority: '' }).toString(), 'scheme:/path');
|
||||
assert.equal(URI.parse('scheme:/path').with({ authority: 'authority' }).with({ authority: '' }).toString(), 'scheme:/path');
|
||||
assert.equal(URI.parse('scheme:/path').with({ authority: 'authority' }).with({ authority: null }).toString(), 'scheme:/path');
|
||||
assert.equal(URI.parse('scheme:/path').with({ authority: 'authority' }).with({ path: '' }).toString(), 'scheme://authority');
|
||||
assert.equal(URI.parse('scheme:/path').with({ authority: 'authority' }).with({ path: null }).toString(), 'scheme://authority');
|
||||
assert.equal(URI.parse('scheme:/path').with({ authority: '' }).toString(), 'scheme:/path');
|
||||
assert.equal(URI.parse('scheme:/path').with({ authority: null }).toString(), 'scheme:/path');
|
||||
});
|
||||
|
||||
test('with, validation', () => {
|
||||
let uri = URI.parse('foo:bar/path');
|
||||
assert.throws(() => uri.with({ scheme: 'fai:l' }));
|
||||
assert.throws(() => uri.with({ scheme: 'fäil' }));
|
||||
assert.throws(() => uri.with({ authority: 'fail' }));
|
||||
assert.throws(() => uri.with({ path: '//fail' }));
|
||||
});
|
||||
|
||||
test('parse', () => {
|
||||
let value = URI.parse('http:/api/files/test.me?t=1234');
|
||||
assert.equal(value.scheme, 'http');
|
||||
assert.equal(value.authority, '');
|
||||
assert.equal(value.path, '/api/files/test.me');
|
||||
assert.equal(value.query, 't=1234');
|
||||
assert.equal(value.fragment, '');
|
||||
|
||||
value = URI.parse('http://api/files/test.me?t=1234');
|
||||
assert.equal(value.scheme, 'http');
|
||||
assert.equal(value.authority, 'api');
|
||||
assert.equal(value.path, '/files/test.me');
|
||||
assert.equal(value.query, 't=1234');
|
||||
assert.equal(value.fragment, '');
|
||||
|
||||
value = URI.parse('file:///c:/test/me');
|
||||
assert.equal(value.scheme, 'file');
|
||||
assert.equal(value.authority, '');
|
||||
assert.equal(value.path, '/c:/test/me');
|
||||
assert.equal(value.fragment, '');
|
||||
assert.equal(value.query, '');
|
||||
assert.equal(value.fsPath, isWindows ? 'c:\\test\\me' : 'c:/test/me');
|
||||
|
||||
value = URI.parse('file://shares/files/c%23/p.cs');
|
||||
assert.equal(value.scheme, 'file');
|
||||
assert.equal(value.authority, 'shares');
|
||||
assert.equal(value.path, '/files/c#/p.cs');
|
||||
assert.equal(value.fragment, '');
|
||||
assert.equal(value.query, '');
|
||||
assert.equal(value.fsPath, isWindows ? '\\\\shares\\files\\c#\\p.cs' : '//shares/files/c#/p.cs');
|
||||
|
||||
value = URI.parse('file:///c:/Source/Z%C3%BCrich%20or%20Zurich%20(%CB%88zj%CA%8A%C9%99r%C9%AAk,/Code/resources/app/plugins/c%23/plugin.json');
|
||||
assert.equal(value.scheme, 'file');
|
||||
assert.equal(value.authority, '');
|
||||
assert.equal(value.path, '/c:/Source/Zürich or Zurich (ˈzjʊərɪk,/Code/resources/app/plugins/c#/plugin.json');
|
||||
assert.equal(value.fragment, '');
|
||||
assert.equal(value.query, '');
|
||||
|
||||
value = URI.parse('file:///c:/test %25/path');
|
||||
assert.equal(value.scheme, 'file');
|
||||
assert.equal(value.authority, '');
|
||||
assert.equal(value.path, '/c:/test %/path');
|
||||
assert.equal(value.fragment, '');
|
||||
assert.equal(value.query, '');
|
||||
|
||||
value = URI.parse('inmemory:');
|
||||
assert.equal(value.scheme, 'inmemory');
|
||||
assert.equal(value.authority, '');
|
||||
assert.equal(value.path, '');
|
||||
assert.equal(value.query, '');
|
||||
assert.equal(value.fragment, '');
|
||||
|
||||
value = URI.parse('foo:api/files/test');
|
||||
assert.equal(value.scheme, 'foo');
|
||||
assert.equal(value.authority, '');
|
||||
assert.equal(value.path, 'api/files/test');
|
||||
assert.equal(value.query, '');
|
||||
assert.equal(value.fragment, '');
|
||||
|
||||
value = URI.parse('file:?q');
|
||||
assert.equal(value.scheme, 'file');
|
||||
assert.equal(value.authority, '');
|
||||
assert.equal(value.path, '/');
|
||||
assert.equal(value.query, 'q');
|
||||
assert.equal(value.fragment, '');
|
||||
|
||||
value = URI.parse('file:#d');
|
||||
assert.equal(value.scheme, 'file');
|
||||
assert.equal(value.authority, '');
|
||||
assert.equal(value.path, '/');
|
||||
assert.equal(value.query, '');
|
||||
assert.equal(value.fragment, 'd');
|
||||
|
||||
value = URI.parse('f3ile:#d');
|
||||
assert.equal(value.scheme, 'f3ile');
|
||||
assert.equal(value.authority, '');
|
||||
assert.equal(value.path, '');
|
||||
assert.equal(value.query, '');
|
||||
assert.equal(value.fragment, 'd');
|
||||
|
||||
value = URI.parse('foo+bar:path');
|
||||
assert.equal(value.scheme, 'foo+bar');
|
||||
assert.equal(value.authority, '');
|
||||
assert.equal(value.path, 'path');
|
||||
assert.equal(value.query, '');
|
||||
assert.equal(value.fragment, '');
|
||||
|
||||
value = URI.parse('foo-bar:path');
|
||||
assert.equal(value.scheme, 'foo-bar');
|
||||
assert.equal(value.authority, '');
|
||||
assert.equal(value.path, 'path');
|
||||
assert.equal(value.query, '');
|
||||
assert.equal(value.fragment, '');
|
||||
|
||||
value = URI.parse('foo.bar:path');
|
||||
assert.equal(value.scheme, 'foo.bar');
|
||||
assert.equal(value.authority, '');
|
||||
assert.equal(value.path, 'path');
|
||||
assert.equal(value.query, '');
|
||||
assert.equal(value.fragment, '');
|
||||
});
|
||||
|
||||
test('parse, disallow //path when no authority', () => {
|
||||
assert.throws(() => URI.parse('file:////shares/files/p.cs'));
|
||||
});
|
||||
|
||||
test('URI#file, win-speciale', () => {
|
||||
if (isWindows) {
|
||||
let value = URI.file('c:\\test\\drive');
|
||||
assert.equal(value.path, '/c:/test/drive');
|
||||
assert.equal(value.toString(), 'file:///c%3A/test/drive');
|
||||
|
||||
value = URI.file('\\\\shäres\\path\\c#\\plugin.json');
|
||||
assert.equal(value.scheme, 'file');
|
||||
assert.equal(value.authority, 'shäres');
|
||||
assert.equal(value.path, '/path/c#/plugin.json');
|
||||
assert.equal(value.fragment, '');
|
||||
assert.equal(value.query, '');
|
||||
assert.equal(value.toString(), 'file://sh%C3%A4res/path/c%23/plugin.json');
|
||||
|
||||
value = URI.file('\\\\localhost\\c$\\GitDevelopment\\express');
|
||||
assert.equal(value.scheme, 'file');
|
||||
assert.equal(value.path, '/c$/GitDevelopment/express');
|
||||
assert.equal(value.fsPath, '\\\\localhost\\c$\\GitDevelopment\\express');
|
||||
assert.equal(value.query, '');
|
||||
assert.equal(value.fragment, '');
|
||||
assert.equal(value.toString(), 'file://localhost/c%24/GitDevelopment/express');
|
||||
|
||||
value = URI.file('c:\\test with %\\path');
|
||||
assert.equal(value.path, '/c:/test with %/path');
|
||||
assert.equal(value.toString(), 'file:///c%3A/test%20with%20%25/path');
|
||||
|
||||
value = URI.file('c:\\test with %25\\path');
|
||||
assert.equal(value.path, '/c:/test with %25/path');
|
||||
assert.equal(value.toString(), 'file:///c%3A/test%20with%20%2525/path');
|
||||
|
||||
value = URI.file('c:\\test with %25\\c#code');
|
||||
assert.equal(value.path, '/c:/test with %25/c#code');
|
||||
assert.equal(value.toString(), 'file:///c%3A/test%20with%20%2525/c%23code');
|
||||
|
||||
value = URI.file('\\\\shares');
|
||||
assert.equal(value.scheme, 'file');
|
||||
assert.equal(value.authority, 'shares');
|
||||
assert.equal(value.path, '/'); // slash is always there
|
||||
|
||||
value = URI.file('\\\\shares\\');
|
||||
assert.equal(value.scheme, 'file');
|
||||
assert.equal(value.authority, 'shares');
|
||||
assert.equal(value.path, '/');
|
||||
}
|
||||
});
|
||||
|
||||
test('VSCode URI module\'s driveLetterPath regex is incorrect, #32961', function () {
|
||||
let uri = URI.parse('file:///_:/path');
|
||||
assert.equal(uri.fsPath, isWindows ? '\\_:\\path' : '/_:/path');
|
||||
});
|
||||
|
||||
test('URI#file, no path-is-uri check', () => {
|
||||
|
||||
// we don't complain here
|
||||
let value = URI.file('file://path/to/file');
|
||||
assert.equal(value.scheme, 'file');
|
||||
assert.equal(value.authority, '');
|
||||
assert.equal(value.path, '/file://path/to/file');
|
||||
});
|
||||
|
||||
test('URI#file, always slash', () => {
|
||||
|
||||
let value = URI.file('a.file');
|
||||
assert.equal(value.scheme, 'file');
|
||||
assert.equal(value.authority, '');
|
||||
assert.equal(value.path, '/a.file');
|
||||
assert.equal(value.toString(), 'file:///a.file');
|
||||
|
||||
value = URI.parse(value.toString());
|
||||
assert.equal(value.scheme, 'file');
|
||||
assert.equal(value.authority, '');
|
||||
assert.equal(value.path, '/a.file');
|
||||
assert.equal(value.toString(), 'file:///a.file');
|
||||
});
|
||||
|
||||
test('URI.toString, only scheme and query', () => {
|
||||
const value = URI.parse('stuff:?qüery');
|
||||
assert.equal(value.toString(), 'stuff:?q%C3%BCery');
|
||||
});
|
||||
|
||||
test('URI#toString, upper-case percent espaces', () => {
|
||||
const value = URI.parse('file://sh%c3%a4res/path');
|
||||
assert.equal(value.toString(), 'file://sh%C3%A4res/path');
|
||||
});
|
||||
|
||||
test('URI#toString, lower-case windows drive letter', () => {
|
||||
assert.equal(URI.parse('untitled:c:/Users/jrieken/Code/abc.txt').toString(), 'untitled:c%3A/Users/jrieken/Code/abc.txt');
|
||||
assert.equal(URI.parse('untitled:C:/Users/jrieken/Code/abc.txt').toString(), 'untitled:c%3A/Users/jrieken/Code/abc.txt');
|
||||
});
|
||||
|
||||
test('URI#toString, escape all the bits', () => {
|
||||
|
||||
const value = URI.file('/Users/jrieken/Code/_samples/18500/Mödel + Other Thîngß/model.js');
|
||||
assert.equal(value.toString(), 'file:///Users/jrieken/Code/_samples/18500/M%C3%B6del%20%2B%20Other%20Th%C3%AEng%C3%9F/model.js');
|
||||
});
|
||||
|
||||
test('URI#toString, don\'t encode port', () => {
|
||||
let value = URI.parse('http://localhost:8080/far');
|
||||
assert.equal(value.toString(), 'http://localhost:8080/far');
|
||||
|
||||
value = URI.from({ scheme: 'http', authority: 'löcalhost:8080', path: '/far', query: undefined, fragment: undefined });
|
||||
assert.equal(value.toString(), 'http://l%C3%B6calhost:8080/far');
|
||||
});
|
||||
|
||||
test('URI#toString, user information in authority', () => {
|
||||
let value = URI.parse('http://foo:bar@localhost/far');
|
||||
assert.equal(value.toString(), 'http://foo:bar@localhost/far');
|
||||
|
||||
value = URI.parse('http://foo@localhost/far');
|
||||
assert.equal(value.toString(), 'http://foo@localhost/far');
|
||||
|
||||
value = URI.parse('http://foo:bAr@localhost:8080/far');
|
||||
assert.equal(value.toString(), 'http://foo:bAr@localhost:8080/far');
|
||||
|
||||
value = URI.parse('http://foo@localhost:8080/far');
|
||||
assert.equal(value.toString(), 'http://foo@localhost:8080/far');
|
||||
|
||||
value = URI.from({ scheme: 'http', authority: 'föö:bör@löcalhost:8080', path: '/far', query: undefined, fragment: undefined });
|
||||
assert.equal(value.toString(), 'http://f%C3%B6%C3%B6:b%C3%B6r@l%C3%B6calhost:8080/far');
|
||||
});
|
||||
|
||||
test('correctFileUriToFilePath2', () => {
|
||||
|
||||
const test = (input: string, expected: string) => {
|
||||
const value = URI.parse(input);
|
||||
assert.equal(value.fsPath, expected, 'Result for ' + input);
|
||||
const value2 = URI.file(value.fsPath);
|
||||
assert.equal(value2.fsPath, expected, 'Result for ' + input);
|
||||
assert.equal(value.toString(), value2.toString());
|
||||
};
|
||||
|
||||
test('file:///c:/alex.txt', isWindows ? 'c:\\alex.txt' : 'c:/alex.txt');
|
||||
test('file:///c:/Source/Z%C3%BCrich%20or%20Zurich%20(%CB%88zj%CA%8A%C9%99r%C9%AAk,/Code/resources/app/plugins', isWindows ? 'c:\\Source\\Zürich or Zurich (ˈzjʊərɪk,\\Code\\resources\\app\\plugins' : 'c:/Source/Zürich or Zurich (ˈzjʊərɪk,/Code/resources/app/plugins');
|
||||
test('file://monacotools/folder/isi.txt', isWindows ? '\\\\monacotools\\folder\\isi.txt' : '//monacotools/folder/isi.txt');
|
||||
test('file://monacotools1/certificates/SSL/', isWindows ? '\\\\monacotools1\\certificates\\SSL\\' : '//monacotools1/certificates/SSL/');
|
||||
});
|
||||
|
||||
test('URI - http, query & toString', function () {
|
||||
|
||||
let uri = URI.parse('https://go.microsoft.com/fwlink/?LinkId=518008');
|
||||
assert.equal(uri.query, 'LinkId=518008');
|
||||
assert.equal(uri.toString(true), 'https://go.microsoft.com/fwlink/?LinkId=518008');
|
||||
assert.equal(uri.toString(), 'https://go.microsoft.com/fwlink/?LinkId%3D518008');
|
||||
|
||||
let uri2 = URI.parse(uri.toString());
|
||||
assert.equal(uri2.query, 'LinkId=518008');
|
||||
assert.equal(uri2.query, uri.query);
|
||||
|
||||
uri = URI.parse('https://go.microsoft.com/fwlink/?LinkId=518008&foö&ké¥=üü');
|
||||
assert.equal(uri.query, 'LinkId=518008&foö&ké¥=üü');
|
||||
assert.equal(uri.toString(true), 'https://go.microsoft.com/fwlink/?LinkId=518008&foö&ké¥=üü');
|
||||
assert.equal(uri.toString(), 'https://go.microsoft.com/fwlink/?LinkId%3D518008%26fo%C3%B6%26k%C3%A9%C2%A5%3D%C3%BC%C3%BC');
|
||||
|
||||
uri2 = URI.parse(uri.toString());
|
||||
assert.equal(uri2.query, 'LinkId=518008&foö&ké¥=üü');
|
||||
assert.equal(uri2.query, uri.query);
|
||||
|
||||
// #24849
|
||||
uri = URI.parse('https://twitter.com/search?src=typd&q=%23tag');
|
||||
assert.equal(uri.toString(true), 'https://twitter.com/search?src=typd&q=%23tag');
|
||||
});
|
||||
|
||||
|
||||
test('class URI cannot represent relative file paths #34449', function () {
|
||||
|
||||
let path = '/foo/bar';
|
||||
assert.equal(URI.file(path).path, path);
|
||||
path = 'foo/bar';
|
||||
assert.equal(URI.file(path).path, '/foo/bar');
|
||||
path = './foo/bar';
|
||||
assert.equal(URI.file(path).path, '/./foo/bar'); // missing normalization
|
||||
|
||||
const fileUri1 = URI.parse(`file:foo/bar`);
|
||||
assert.equal(fileUri1.path, '/foo/bar');
|
||||
assert.equal(fileUri1.authority, '');
|
||||
const uri = fileUri1.toString();
|
||||
assert.equal(uri, 'file:///foo/bar');
|
||||
const fileUri2 = URI.parse(uri);
|
||||
assert.equal(fileUri2.path, '/foo/bar');
|
||||
assert.equal(fileUri2.authority, '');
|
||||
});
|
||||
|
||||
test('Ctrl click to follow hash query param url gets urlencoded #49628', function () {
|
||||
let input = 'http://localhost:3000/#/foo?bar=baz';
|
||||
let uri = URI.parse(input);
|
||||
assert.equal(uri.toString(true), input);
|
||||
|
||||
input = 'http://localhost:3000/foo?bar=baz';
|
||||
uri = URI.parse(input);
|
||||
assert.equal(uri.toString(true), input);
|
||||
});
|
||||
|
||||
test('Unable to open \'%A0.txt\': URI malformed #76506', function () {
|
||||
|
||||
let uri = URI.file('/foo/%A0.txt');
|
||||
let uri2 = URI.parse(uri.toString());
|
||||
assert.equal(uri.scheme, uri2.scheme);
|
||||
assert.equal(uri.path, uri2.path);
|
||||
|
||||
uri = URI.file('/foo/%2e.txt');
|
||||
uri2 = URI.parse(uri.toString());
|
||||
assert.equal(uri.scheme, uri2.scheme);
|
||||
assert.equal(uri.path, uri2.path);
|
||||
});
|
||||
|
||||
test('Unable to open \'%A0.txt\': URI malformed #76506', function () {
|
||||
assert.equal(URI.parse('file://some/%.txt'), 'file://some/%25.txt');
|
||||
assert.equal(URI.parse('file://some/%A0.txt'), 'file://some/%25A0.txt');
|
||||
});
|
||||
|
||||
test('Links in markdown are broken if url contains encoded parameters #79474', function () {
|
||||
this.skip();
|
||||
let strIn = 'https://myhost.com/Redirect?url=http%3A%2F%2Fwww.bing.com%3Fsearch%3Dtom';
|
||||
let uri1 = URI.parse(strIn);
|
||||
let strOut = uri1.toString();
|
||||
let uri2 = URI.parse(strOut);
|
||||
|
||||
assert.equal(uri1.scheme, uri2.scheme);
|
||||
assert.equal(uri1.authority, uri2.authority);
|
||||
assert.equal(uri1.path, uri2.path);
|
||||
assert.equal(uri1.query, uri2.query);
|
||||
assert.equal(uri1.fragment, uri2.fragment);
|
||||
assert.equal(strIn, strOut); // fails here!!
|
||||
});
|
||||
|
||||
test('Uri#parse can break path-component #45515', function () {
|
||||
this.skip();
|
||||
let strIn = 'https://firebasestorage.googleapis.com/v0/b/brewlangerie.appspot.com/o/products%2FzVNZkudXJyq8bPGTXUxx%2FBetterave-Sesame.jpg?alt=media&token=0b2310c4-3ea6-4207-bbde-9c3710ba0437';
|
||||
let uri1 = URI.parse(strIn);
|
||||
let strOut = uri1.toString();
|
||||
let uri2 = URI.parse(strOut);
|
||||
|
||||
assert.equal(uri1.scheme, uri2.scheme);
|
||||
assert.equal(uri1.authority, uri2.authority);
|
||||
assert.equal(uri1.path, uri2.path);
|
||||
assert.equal(uri1.query, uri2.query);
|
||||
assert.equal(uri1.fragment, uri2.fragment);
|
||||
assert.equal(strIn, strOut); // fails here!!
|
||||
});
|
||||
|
||||
test('URI - (de)serialize', function () {
|
||||
|
||||
const values = [
|
||||
URI.parse('http://localhost:8080/far'),
|
||||
URI.file('c:\\test with %25\\c#code'),
|
||||
URI.file('\\\\shäres\\path\\c#\\plugin.json'),
|
||||
URI.parse('http://api/files/test.me?t=1234'),
|
||||
URI.parse('http://api/files/test.me?t=1234#fff'),
|
||||
URI.parse('http://api/files/test.me#fff'),
|
||||
];
|
||||
|
||||
// console.profile();
|
||||
// let c = 100000;
|
||||
// while (c-- > 0) {
|
||||
for (let value of values) {
|
||||
let data = value.toJSON() as UriComponents;
|
||||
let clone = URI.revive(data);
|
||||
|
||||
assert.equal(clone.scheme, value.scheme);
|
||||
assert.equal(clone.authority, value.authority);
|
||||
assert.equal(clone.path, value.path);
|
||||
assert.equal(clone.query, value.query);
|
||||
assert.equal(clone.fragment, value.fragment);
|
||||
assert.equal(clone.fsPath, value.fsPath);
|
||||
assert.equal(clone.toString(), value.toString());
|
||||
}
|
||||
// }
|
||||
// console.profileEnd();
|
||||
});
|
||||
function assertJoined(base: string, fragment: string, expected: string, checkWithUrl: boolean = true) {
|
||||
const baseUri = URI.parse(base);
|
||||
const newUri = URI.joinPath(baseUri, fragment);
|
||||
const actual = newUri.toString(true);
|
||||
assert.equal(actual, expected);
|
||||
|
||||
if (checkWithUrl) {
|
||||
const actualUrl = new URL(fragment, base).href;
|
||||
assert.equal(actualUrl, expected, 'DIFFERENT from URL');
|
||||
}
|
||||
}
|
||||
test('URI#joinPath', function () {
|
||||
|
||||
assertJoined(('file:///foo/'), '../../bazz', 'file:///bazz');
|
||||
assertJoined(('file:///foo'), '../../bazz', 'file:///bazz');
|
||||
assertJoined(('file:///foo'), '../../bazz', 'file:///bazz');
|
||||
assertJoined(('file:///foo/bar/'), './bazz', 'file:///foo/bar/bazz');
|
||||
assertJoined(('file:///foo/bar'), './bazz', 'file:///foo/bar/bazz', false);
|
||||
assertJoined(('file:///foo/bar'), 'bazz', 'file:///foo/bar/bazz', false);
|
||||
|
||||
// "auto-path" scheme
|
||||
assertJoined(('file:'), 'bazz', 'file:///bazz');
|
||||
assertJoined(('http://domain'), 'bazz', 'http://domain/bazz');
|
||||
assertJoined(('https://domain'), 'bazz', 'https://domain/bazz');
|
||||
assertJoined(('http:'), 'bazz', 'http:/bazz', false);
|
||||
assertJoined(('https:'), 'bazz', 'https:/bazz', false);
|
||||
|
||||
// no "auto-path" scheme with and w/o paths
|
||||
assertJoined(('foo:/'), 'bazz', 'foo:/bazz');
|
||||
assertJoined(('foo://bar/'), 'bazz', 'foo://bar/bazz');
|
||||
|
||||
// no "auto-path" + no path -> error
|
||||
assert.throws(() => assertJoined(('foo:'), 'bazz', ''));
|
||||
assert.throws(() => new URL('bazz', 'foo:'));
|
||||
assert.throws(() => assertJoined(('foo://bar'), 'bazz', ''));
|
||||
// assert.throws(() => new URL('bazz', 'foo://bar')); Edge, Chrome => THROW, Firefox, Safari => foo://bar/bazz
|
||||
});
|
||||
|
||||
test('URI#joinPath (posix)', function () {
|
||||
if (isWindows) {
|
||||
this.skip();
|
||||
}
|
||||
assertJoined(('file:///c:/foo/'), '../../bazz', 'file:///bazz', false);
|
||||
assertJoined(('file://server/share/c:/'), '../../bazz', 'file://server/bazz', false);
|
||||
assertJoined(('file://server/share/c:'), '../../bazz', 'file://server/bazz', false);
|
||||
|
||||
assertJoined(('file://ser/foo/'), '../../bazz', 'file://ser/bazz', false); // Firefox -> Different, Edge, Chrome, Safar -> OK
|
||||
assertJoined(('file://ser/foo'), '../../bazz', 'file://ser/bazz', false); // Firefox -> Different, Edge, Chrome, Safar -> OK
|
||||
});
|
||||
|
||||
test('URI#joinPath (windows)', function () {
|
||||
if (!isWindows) {
|
||||
this.skip();
|
||||
}
|
||||
assertJoined(('file:///c:/foo/'), '../../bazz', 'file:///c:/bazz', false);
|
||||
assertJoined(('file://server/share/c:/'), '../../bazz', 'file://server/share/bazz', false);
|
||||
assertJoined(('file://server/share/c:'), '../../bazz', 'file://server/share/bazz', false);
|
||||
|
||||
assertJoined(('file://ser/foo/'), '../../bazz', 'file://ser/foo/bazz', false);
|
||||
assertJoined(('file://ser/foo'), '../../bazz', 'file://ser/foo/bazz', false);
|
||||
|
||||
//https://github.com/microsoft/vscode/issues/93831
|
||||
assertJoined('file:///c:/foo/bar', './other/foo.img', 'file:///c:/foo/bar/other/foo.img', false);
|
||||
});
|
||||
});
|
||||
67
lib/vscode/src/vs/base/test/common/utils.ts
Normal file
67
lib/vscode/src/vs/base/test/common/utils.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { join } from 'vs/base/common/path';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { canceled } from 'vs/base/common/errors';
|
||||
import { isWindows } from 'vs/base/common/platform';
|
||||
|
||||
export type ValueCallback<T = any> = (value: T | Promise<T>) => void;
|
||||
|
||||
export class DeferredPromise<T> {
|
||||
|
||||
private completeCallback!: ValueCallback<T>;
|
||||
private errorCallback!: (err: any) => void;
|
||||
|
||||
public p: Promise<any>;
|
||||
|
||||
constructor() {
|
||||
this.p = new Promise<any>((c, e) => {
|
||||
this.completeCallback = c;
|
||||
this.errorCallback = e;
|
||||
});
|
||||
}
|
||||
|
||||
public complete(value: T) {
|
||||
return new Promise<void>(resolve => {
|
||||
this.completeCallback(value);
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
public error(err: any) {
|
||||
return new Promise<void>(resolve => {
|
||||
this.errorCallback(err);
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
public cancel() {
|
||||
new Promise<void>(resolve => {
|
||||
this.errorCallback(canceled());
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function toResource(this: any, path: string) {
|
||||
if (isWindows) {
|
||||
return URI.file(join('C:\\', btoa(this.test.fullTitle()), path));
|
||||
}
|
||||
|
||||
return URI.file(join('/', btoa(this.test.fullTitle()), path));
|
||||
}
|
||||
|
||||
export function suiteRepeat(n: number, description: string, callback: (this: any) => void): void {
|
||||
for (let i = 0; i < n; i++) {
|
||||
suite(`${description} (iteration ${i})`, callback);
|
||||
}
|
||||
}
|
||||
|
||||
export function testRepeat(n: number, description: string, callback: (this: any, done: MochaDone) => any): void {
|
||||
for (let i = 0; i < n; i++) {
|
||||
test(`${description} (iteration ${i})`, callback);
|
||||
}
|
||||
}
|
||||
23
lib/vscode/src/vs/base/test/common/uuid.test.ts
Normal file
23
lib/vscode/src/vs/base/test/common/uuid.test.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as assert from 'assert';
|
||||
import * as uuid from 'vs/base/common/uuid';
|
||||
|
||||
suite('UUID', () => {
|
||||
test('generation', () => {
|
||||
const asHex = uuid.generateUuid();
|
||||
assert.equal(asHex.length, 36);
|
||||
assert.equal(asHex[14], '4');
|
||||
assert.ok(asHex[19] === '8' || asHex[19] === '9' || asHex[19] === 'a' || asHex[19] === 'b');
|
||||
});
|
||||
|
||||
test('self-check', function () {
|
||||
const t1 = Date.now();
|
||||
while (Date.now() - t1 < 50) {
|
||||
const value = uuid.generateUuid();
|
||||
assert.ok(uuid.isUUID(value));
|
||||
}
|
||||
});
|
||||
});
|
||||
413
lib/vscode/src/vs/base/test/node/buffer.test.ts
Normal file
413
lib/vscode/src/vs/base/test/node/buffer.test.ts
Normal file
@@ -0,0 +1,413 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { VSBuffer, bufferToReadable, readableToBuffer, bufferToStream, streamToBuffer, newWriteableBufferStream, bufferedStreamToBuffer } from 'vs/base/common/buffer';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
import { peekStream } from 'vs/base/common/stream';
|
||||
|
||||
suite('Buffer', () => {
|
||||
|
||||
test('issue #71993 - VSBuffer#toString returns numbers', () => {
|
||||
const data = new Uint8Array([1, 2, 3, 'h'.charCodeAt(0), 'i'.charCodeAt(0), 4, 5]).buffer;
|
||||
const buffer = VSBuffer.wrap(new Uint8Array(data, 3, 2));
|
||||
assert.deepEqual(buffer.toString(), 'hi');
|
||||
});
|
||||
|
||||
test('bufferToReadable / readableToBuffer', () => {
|
||||
const content = 'Hello World';
|
||||
const readable = bufferToReadable(VSBuffer.fromString(content));
|
||||
|
||||
assert.equal(readableToBuffer(readable).toString(), content);
|
||||
});
|
||||
|
||||
test('bufferToStream / streamToBuffer', async () => {
|
||||
const content = 'Hello World';
|
||||
const stream = bufferToStream(VSBuffer.fromString(content));
|
||||
|
||||
assert.equal((await streamToBuffer(stream)).toString(), content);
|
||||
});
|
||||
|
||||
test('bufferedStreamToBuffer', async () => {
|
||||
const content = 'Hello World';
|
||||
const stream = await peekStream(bufferToStream(VSBuffer.fromString(content)), 1);
|
||||
|
||||
assert.equal((await bufferedStreamToBuffer(stream)).toString(), content);
|
||||
});
|
||||
|
||||
test('bufferWriteableStream - basics (no error)', async () => {
|
||||
const stream = newWriteableBufferStream();
|
||||
|
||||
let chunks: VSBuffer[] = [];
|
||||
stream.on('data', data => {
|
||||
chunks.push(data);
|
||||
});
|
||||
|
||||
let ended = false;
|
||||
stream.on('end', () => {
|
||||
ended = true;
|
||||
});
|
||||
|
||||
let errors: Error[] = [];
|
||||
stream.on('error', error => {
|
||||
errors.push(error);
|
||||
});
|
||||
|
||||
await timeout(0);
|
||||
stream.write(VSBuffer.fromString('Hello'));
|
||||
await timeout(0);
|
||||
stream.end(VSBuffer.fromString('World'));
|
||||
|
||||
assert.equal(chunks.length, 2);
|
||||
assert.equal(chunks[0].toString(), 'Hello');
|
||||
assert.equal(chunks[1].toString(), 'World');
|
||||
assert.equal(ended, true);
|
||||
assert.equal(errors.length, 0);
|
||||
});
|
||||
|
||||
test('bufferWriteableStream - basics (error)', async () => {
|
||||
const stream = newWriteableBufferStream();
|
||||
|
||||
let chunks: VSBuffer[] = [];
|
||||
stream.on('data', data => {
|
||||
chunks.push(data);
|
||||
});
|
||||
|
||||
let ended = false;
|
||||
stream.on('end', () => {
|
||||
ended = true;
|
||||
});
|
||||
|
||||
let errors: Error[] = [];
|
||||
stream.on('error', error => {
|
||||
errors.push(error);
|
||||
});
|
||||
|
||||
await timeout(0);
|
||||
stream.write(VSBuffer.fromString('Hello'));
|
||||
await timeout(0);
|
||||
stream.end(new Error());
|
||||
|
||||
assert.equal(chunks.length, 1);
|
||||
assert.equal(chunks[0].toString(), 'Hello');
|
||||
assert.equal(ended, true);
|
||||
assert.equal(errors.length, 1);
|
||||
});
|
||||
|
||||
test('bufferWriteableStream - buffers data when no listener', async () => {
|
||||
const stream = newWriteableBufferStream();
|
||||
|
||||
await timeout(0);
|
||||
stream.write(VSBuffer.fromString('Hello'));
|
||||
await timeout(0);
|
||||
stream.end(VSBuffer.fromString('World'));
|
||||
|
||||
let chunks: VSBuffer[] = [];
|
||||
stream.on('data', data => {
|
||||
chunks.push(data);
|
||||
});
|
||||
|
||||
let ended = false;
|
||||
stream.on('end', () => {
|
||||
ended = true;
|
||||
});
|
||||
|
||||
let errors: Error[] = [];
|
||||
stream.on('error', error => {
|
||||
errors.push(error);
|
||||
});
|
||||
|
||||
assert.equal(chunks.length, 1);
|
||||
assert.equal(chunks[0].toString(), 'HelloWorld');
|
||||
assert.equal(ended, true);
|
||||
assert.equal(errors.length, 0);
|
||||
});
|
||||
|
||||
test('bufferWriteableStream - buffers errors when no listener', async () => {
|
||||
const stream = newWriteableBufferStream();
|
||||
|
||||
await timeout(0);
|
||||
stream.write(VSBuffer.fromString('Hello'));
|
||||
await timeout(0);
|
||||
stream.error(new Error());
|
||||
|
||||
let chunks: VSBuffer[] = [];
|
||||
stream.on('data', data => {
|
||||
chunks.push(data);
|
||||
});
|
||||
|
||||
let errors: Error[] = [];
|
||||
stream.on('error', error => {
|
||||
errors.push(error);
|
||||
});
|
||||
|
||||
let ended = false;
|
||||
stream.on('end', () => {
|
||||
ended = true;
|
||||
});
|
||||
|
||||
stream.end();
|
||||
|
||||
assert.equal(chunks.length, 1);
|
||||
assert.equal(chunks[0].toString(), 'Hello');
|
||||
assert.equal(ended, true);
|
||||
assert.equal(errors.length, 1);
|
||||
});
|
||||
|
||||
test('bufferWriteableStream - buffers end when no listener', async () => {
|
||||
const stream = newWriteableBufferStream();
|
||||
|
||||
await timeout(0);
|
||||
stream.write(VSBuffer.fromString('Hello'));
|
||||
await timeout(0);
|
||||
stream.end(VSBuffer.fromString('World'));
|
||||
|
||||
let ended = false;
|
||||
stream.on('end', () => {
|
||||
ended = true;
|
||||
});
|
||||
|
||||
let chunks: VSBuffer[] = [];
|
||||
stream.on('data', data => {
|
||||
chunks.push(data);
|
||||
});
|
||||
|
||||
let errors: Error[] = [];
|
||||
stream.on('error', error => {
|
||||
errors.push(error);
|
||||
});
|
||||
|
||||
assert.equal(chunks.length, 1);
|
||||
assert.equal(chunks[0].toString(), 'HelloWorld');
|
||||
assert.equal(ended, true);
|
||||
assert.equal(errors.length, 0);
|
||||
});
|
||||
|
||||
test('bufferWriteableStream - nothing happens after end()', async () => {
|
||||
const stream = newWriteableBufferStream();
|
||||
|
||||
let chunks: VSBuffer[] = [];
|
||||
stream.on('data', data => {
|
||||
chunks.push(data);
|
||||
});
|
||||
|
||||
await timeout(0);
|
||||
stream.write(VSBuffer.fromString('Hello'));
|
||||
await timeout(0);
|
||||
stream.end(VSBuffer.fromString('World'));
|
||||
|
||||
let dataCalledAfterEnd = false;
|
||||
stream.on('data', data => {
|
||||
dataCalledAfterEnd = true;
|
||||
});
|
||||
|
||||
let errorCalledAfterEnd = false;
|
||||
stream.on('error', error => {
|
||||
errorCalledAfterEnd = true;
|
||||
});
|
||||
|
||||
let endCalledAfterEnd = false;
|
||||
stream.on('end', () => {
|
||||
endCalledAfterEnd = true;
|
||||
});
|
||||
|
||||
await timeout(0);
|
||||
stream.write(VSBuffer.fromString('Hello'));
|
||||
await timeout(0);
|
||||
stream.error(new Error());
|
||||
await timeout(0);
|
||||
stream.end(VSBuffer.fromString('World'));
|
||||
|
||||
assert.equal(dataCalledAfterEnd, false);
|
||||
assert.equal(errorCalledAfterEnd, false);
|
||||
assert.equal(endCalledAfterEnd, false);
|
||||
|
||||
assert.equal(chunks.length, 2);
|
||||
assert.equal(chunks[0].toString(), 'Hello');
|
||||
assert.equal(chunks[1].toString(), 'World');
|
||||
});
|
||||
|
||||
test('bufferWriteableStream - pause/resume (simple)', async () => {
|
||||
const stream = newWriteableBufferStream();
|
||||
|
||||
let chunks: VSBuffer[] = [];
|
||||
stream.on('data', data => {
|
||||
chunks.push(data);
|
||||
});
|
||||
|
||||
let ended = false;
|
||||
stream.on('end', () => {
|
||||
ended = true;
|
||||
});
|
||||
|
||||
let errors: Error[] = [];
|
||||
stream.on('error', error => {
|
||||
errors.push(error);
|
||||
});
|
||||
|
||||
stream.pause();
|
||||
|
||||
await timeout(0);
|
||||
stream.write(VSBuffer.fromString('Hello'));
|
||||
await timeout(0);
|
||||
stream.end(VSBuffer.fromString('World'));
|
||||
|
||||
assert.equal(chunks.length, 0);
|
||||
assert.equal(errors.length, 0);
|
||||
assert.equal(ended, false);
|
||||
|
||||
stream.resume();
|
||||
|
||||
assert.equal(chunks.length, 1);
|
||||
assert.equal(chunks[0].toString(), 'HelloWorld');
|
||||
assert.equal(ended, true);
|
||||
assert.equal(errors.length, 0);
|
||||
});
|
||||
|
||||
test('bufferWriteableStream - pause/resume (pause after first write)', async () => {
|
||||
const stream = newWriteableBufferStream();
|
||||
|
||||
let chunks: VSBuffer[] = [];
|
||||
stream.on('data', data => {
|
||||
chunks.push(data);
|
||||
});
|
||||
|
||||
let ended = false;
|
||||
stream.on('end', () => {
|
||||
ended = true;
|
||||
});
|
||||
|
||||
let errors: Error[] = [];
|
||||
stream.on('error', error => {
|
||||
errors.push(error);
|
||||
});
|
||||
|
||||
await timeout(0);
|
||||
stream.write(VSBuffer.fromString('Hello'));
|
||||
|
||||
stream.pause();
|
||||
|
||||
await timeout(0);
|
||||
stream.end(VSBuffer.fromString('World'));
|
||||
|
||||
assert.equal(chunks.length, 1);
|
||||
assert.equal(chunks[0].toString(), 'Hello');
|
||||
assert.equal(errors.length, 0);
|
||||
assert.equal(ended, false);
|
||||
|
||||
stream.resume();
|
||||
|
||||
assert.equal(chunks.length, 2);
|
||||
assert.equal(chunks[0].toString(), 'Hello');
|
||||
assert.equal(chunks[1].toString(), 'World');
|
||||
assert.equal(ended, true);
|
||||
assert.equal(errors.length, 0);
|
||||
});
|
||||
|
||||
test('bufferWriteableStream - pause/resume (error)', async () => {
|
||||
const stream = newWriteableBufferStream();
|
||||
|
||||
let chunks: VSBuffer[] = [];
|
||||
stream.on('data', data => {
|
||||
chunks.push(data);
|
||||
});
|
||||
|
||||
let ended = false;
|
||||
stream.on('end', () => {
|
||||
ended = true;
|
||||
});
|
||||
|
||||
let errors: Error[] = [];
|
||||
stream.on('error', error => {
|
||||
errors.push(error);
|
||||
});
|
||||
|
||||
stream.pause();
|
||||
|
||||
await timeout(0);
|
||||
stream.write(VSBuffer.fromString('Hello'));
|
||||
await timeout(0);
|
||||
stream.end(new Error());
|
||||
|
||||
assert.equal(chunks.length, 0);
|
||||
assert.equal(ended, false);
|
||||
assert.equal(errors.length, 0);
|
||||
|
||||
stream.resume();
|
||||
|
||||
assert.equal(chunks.length, 1);
|
||||
assert.equal(chunks[0].toString(), 'Hello');
|
||||
assert.equal(ended, true);
|
||||
assert.equal(errors.length, 1);
|
||||
});
|
||||
|
||||
test('bufferWriteableStream - destroy', async () => {
|
||||
const stream = newWriteableBufferStream();
|
||||
|
||||
let chunks: VSBuffer[] = [];
|
||||
stream.on('data', data => {
|
||||
chunks.push(data);
|
||||
});
|
||||
|
||||
let ended = false;
|
||||
stream.on('end', () => {
|
||||
ended = true;
|
||||
});
|
||||
|
||||
let errors: Error[] = [];
|
||||
stream.on('error', error => {
|
||||
errors.push(error);
|
||||
});
|
||||
|
||||
stream.destroy();
|
||||
|
||||
await timeout(0);
|
||||
stream.write(VSBuffer.fromString('Hello'));
|
||||
await timeout(0);
|
||||
stream.end(VSBuffer.fromString('World'));
|
||||
|
||||
assert.equal(chunks.length, 0);
|
||||
assert.equal(ended, false);
|
||||
assert.equal(errors.length, 0);
|
||||
});
|
||||
|
||||
test('Performance issue with VSBuffer#slice #76076', function () {
|
||||
// Buffer#slice creates a view
|
||||
{
|
||||
const buff = Buffer.from([10, 20, 30, 40]);
|
||||
const b2 = buff.slice(1, 3);
|
||||
assert.equal(buff[1], 20);
|
||||
assert.equal(b2[0], 20);
|
||||
|
||||
buff[1] = 17; // modify buff AND b2
|
||||
assert.equal(buff[1], 17);
|
||||
assert.equal(b2[0], 17);
|
||||
}
|
||||
|
||||
// TypedArray#slice creates a copy
|
||||
{
|
||||
const unit = new Uint8Array([10, 20, 30, 40]);
|
||||
const u2 = unit.slice(1, 3);
|
||||
assert.equal(unit[1], 20);
|
||||
assert.equal(u2[0], 20);
|
||||
|
||||
unit[1] = 17; // modify unit, NOT b2
|
||||
assert.equal(unit[1], 17);
|
||||
assert.equal(u2[0], 20);
|
||||
}
|
||||
|
||||
// TypedArray#subarray creates a view
|
||||
{
|
||||
const unit = new Uint8Array([10, 20, 30, 40]);
|
||||
const u2 = unit.subarray(1, 3);
|
||||
assert.equal(unit[1], 20);
|
||||
assert.equal(u2[0], 20);
|
||||
|
||||
unit[1] = 17; // modify unit AND b2
|
||||
assert.equal(unit[1], 17);
|
||||
assert.equal(u2[0], 17);
|
||||
}
|
||||
});
|
||||
});
|
||||
48
lib/vscode/src/vs/base/test/node/console.test.ts
Normal file
48
lib/vscode/src/vs/base/test/node/console.test.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { getFirstFrame } from 'vs/base/common/console';
|
||||
import { normalize } from 'vs/base/common/path';
|
||||
|
||||
suite('Console', () => {
|
||||
|
||||
test('getFirstFrame', () => {
|
||||
let stack = 'at vscode.commands.registerCommand (/Users/someone/Desktop/test-ts/out/src/extension.js:18:17)';
|
||||
let frame = getFirstFrame(stack)!;
|
||||
|
||||
assert.equal(frame.uri.fsPath, normalize('/Users/someone/Desktop/test-ts/out/src/extension.js'));
|
||||
assert.equal(frame.line, 18);
|
||||
assert.equal(frame.column, 17);
|
||||
|
||||
stack = 'at /Users/someone/Desktop/test-ts/out/src/extension.js:18:17';
|
||||
frame = getFirstFrame(stack)!;
|
||||
|
||||
assert.equal(frame.uri.fsPath, normalize('/Users/someone/Desktop/test-ts/out/src/extension.js'));
|
||||
assert.equal(frame.line, 18);
|
||||
assert.equal(frame.column, 17);
|
||||
|
||||
stack = 'at c:\\Users\\someone\\Desktop\\end-js\\extension.js:18:17';
|
||||
frame = getFirstFrame(stack)!;
|
||||
|
||||
assert.equal(frame.uri.fsPath, 'c:\\Users\\someone\\Desktop\\end-js\\extension.js');
|
||||
assert.equal(frame.line, 18);
|
||||
assert.equal(frame.column, 17);
|
||||
|
||||
stack = 'at e.$executeContributedCommand(c:\\Users\\someone\\Desktop\\end-js\\extension.js:18:17)';
|
||||
frame = getFirstFrame(stack)!;
|
||||
|
||||
assert.equal(frame.uri.fsPath, 'c:\\Users\\someone\\Desktop\\end-js\\extension.js');
|
||||
assert.equal(frame.line, 18);
|
||||
assert.equal(frame.column, 17);
|
||||
|
||||
stack = 'at /Users/someone/Desktop/test-ts/out/src/extension.js:18:17\nat /Users/someone/Desktop/test-ts/out/src/other.js:28:27\nat /Users/someone/Desktop/test-ts/out/src/more.js:38:37';
|
||||
frame = getFirstFrame(stack)!;
|
||||
|
||||
assert.equal(frame.uri.fsPath, normalize('/Users/someone/Desktop/test-ts/out/src/extension.js'));
|
||||
assert.equal(frame.line, 18);
|
||||
assert.equal(frame.column, 17);
|
||||
});
|
||||
});
|
||||
27
lib/vscode/src/vs/base/test/node/crypto.test.ts
Normal file
27
lib/vscode/src/vs/base/test/node/crypto.test.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { checksum } from 'vs/base/node/crypto';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { join } from 'vs/base/common/path';
|
||||
import { tmpdir } from 'os';
|
||||
import { mkdirp, rimraf, RimRafMode, writeFile } from 'vs/base/node/pfs';
|
||||
|
||||
suite('Crypto', () => {
|
||||
|
||||
test('checksum', async () => {
|
||||
const id = generateUuid();
|
||||
const testDir = join(tmpdir(), 'vsctests', id);
|
||||
const testFile = join(testDir, 'checksum.txt');
|
||||
|
||||
await mkdirp(testDir);
|
||||
|
||||
await writeFile(testFile, 'Hello World');
|
||||
|
||||
await checksum(testFile, '0a4d55a8d778e5022fab701977c5d840bbc486d0');
|
||||
|
||||
await rimraf(testDir, RimRafMode.MOVE);
|
||||
});
|
||||
});
|
||||
22
lib/vscode/src/vs/base/test/node/decoder.test.ts
Normal file
22
lib/vscode/src/vs/base/test/node/decoder.test.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import * as decoder from 'vs/base/node/decoder';
|
||||
|
||||
suite('Decoder', () => {
|
||||
|
||||
test('decoding', () => {
|
||||
const lineDecoder = new decoder.LineDecoder();
|
||||
let res = lineDecoder.write(Buffer.from('hello'));
|
||||
assert.equal(res.length, 0);
|
||||
|
||||
res = lineDecoder.write(Buffer.from('\nworld'));
|
||||
assert.equal(res[0], 'hello');
|
||||
assert.equal(res.length, 1);
|
||||
|
||||
assert.equal(lineDecoder.end(), 'world');
|
||||
});
|
||||
});
|
||||
73
lib/vscode/src/vs/base/test/node/extpath.test.ts
Normal file
73
lib/vscode/src/vs/base/test/node/extpath.test.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import * as os from 'os';
|
||||
import * as path from 'vs/base/common/path';
|
||||
import * as uuid from 'vs/base/common/uuid';
|
||||
import * as pfs from 'vs/base/node/pfs';
|
||||
import { realcaseSync, realpath, realpathSync } from 'vs/base/node/extpath';
|
||||
|
||||
suite('Extpath', () => {
|
||||
|
||||
test('realcase', async () => {
|
||||
const id = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
||||
const newDir = path.join(parentDir, 'extpath', id);
|
||||
|
||||
await pfs.mkdirp(newDir, 493);
|
||||
|
||||
// assume case insensitive file system
|
||||
if (process.platform === 'win32' || process.platform === 'darwin') {
|
||||
const upper = newDir.toUpperCase();
|
||||
const real = realcaseSync(upper);
|
||||
|
||||
if (real) { // can be null in case of permission errors
|
||||
assert.notEqual(real, upper);
|
||||
assert.equal(real.toUpperCase(), upper);
|
||||
assert.equal(real, newDir);
|
||||
}
|
||||
}
|
||||
|
||||
// linux, unix, etc. -> assume case sensitive file system
|
||||
else {
|
||||
const real = realcaseSync(newDir);
|
||||
assert.equal(real, newDir);
|
||||
}
|
||||
|
||||
await pfs.rimraf(parentDir, pfs.RimRafMode.MOVE);
|
||||
});
|
||||
|
||||
test('realpath', async () => {
|
||||
const id = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
||||
const newDir = path.join(parentDir, 'extpath', id);
|
||||
|
||||
await pfs.mkdirp(newDir, 493);
|
||||
|
||||
const realpathVal = await realpath(newDir);
|
||||
assert.ok(realpathVal);
|
||||
|
||||
await pfs.rimraf(parentDir, pfs.RimRafMode.MOVE);
|
||||
});
|
||||
|
||||
test('realpathSync', async () => {
|
||||
const id = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
||||
const newDir = path.join(parentDir, 'extpath', id);
|
||||
|
||||
await pfs.mkdirp(newDir, 493);
|
||||
|
||||
let realpath!: string;
|
||||
try {
|
||||
realpath = realpathSync(newDir);
|
||||
} catch (error) {
|
||||
assert.ok(!error);
|
||||
}
|
||||
assert.ok(realpath!);
|
||||
|
||||
await pfs.rimraf(parentDir, pfs.RimRafMode.MOVE);
|
||||
});
|
||||
});
|
||||
1015
lib/vscode/src/vs/base/test/node/glob.test.ts
Normal file
1015
lib/vscode/src/vs/base/test/node/glob.test.ts
Normal file
File diff suppressed because it is too large
Load Diff
23
lib/vscode/src/vs/base/test/node/id.test.ts
Normal file
23
lib/vscode/src/vs/base/test/node/id.test.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as assert from 'assert';
|
||||
import { getMachineId } from 'vs/base/node/id';
|
||||
import { getMac } from 'vs/base/node/macAddress';
|
||||
|
||||
suite('ID', () => {
|
||||
|
||||
test('getMachineId', function () {
|
||||
this.timeout(20000);
|
||||
return getMachineId().then(id => {
|
||||
assert.ok(id);
|
||||
});
|
||||
});
|
||||
|
||||
test('getMac', () => {
|
||||
return getMac().then(macAddress => {
|
||||
assert.ok(/^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/.test(macAddress), `Expected a MAC address, got: ${macAddress}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
37
lib/vscode/src/vs/base/test/node/keytar.test.ts
Normal file
37
lib/vscode/src/vs/base/test/node/keytar.test.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as assert from 'assert';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
|
||||
suite('Keytar', () => {
|
||||
|
||||
test('loads and is functional', function (done) {
|
||||
if (platform.isLinux) {
|
||||
// Skip test due to set up issue with Travis.
|
||||
this.skip();
|
||||
return;
|
||||
}
|
||||
(async () => {
|
||||
const keytar = await import('keytar');
|
||||
const name = `VSCode Test ${Math.floor(Math.random() * 1e9)}`;
|
||||
try {
|
||||
await keytar.setPassword(name, 'foo', 'bar');
|
||||
assert.equal(await keytar.findPassword(name), 'bar');
|
||||
assert.equal((await keytar.findCredentials(name)).length, 1);
|
||||
assert.equal(await keytar.getPassword(name, 'foo'), 'bar');
|
||||
await keytar.deletePassword(name, 'foo');
|
||||
assert.equal(await keytar.getPassword(name, 'foo'), undefined);
|
||||
} catch (err) {
|
||||
// try to clean up
|
||||
try {
|
||||
await keytar.deletePassword(name, 'foo');
|
||||
} finally {
|
||||
// eslint-disable-next-line no-unsafe-finally
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
})().then(done, done);
|
||||
});
|
||||
});
|
||||
819
lib/vscode/src/vs/base/test/node/path.test.ts
Normal file
819
lib/vscode/src/vs/base/test/node/path.test.ts
Normal file
@@ -0,0 +1,819 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
// NOTE: VSCode's copy of nodejs path library to be usable in common (non-node) namespace
|
||||
// Copied from: https://github.com/nodejs/node/tree/43dd49c9782848c25e5b03448c8a0f923f13c158
|
||||
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
import * as assert from 'assert';
|
||||
import * as path from 'vs/base/common/path';
|
||||
import { isWindows } from 'vs/base/common/platform';
|
||||
import * as process from 'vs/base/common/process';
|
||||
|
||||
suite('Paths (Node Implementation)', () => {
|
||||
test('join', () => {
|
||||
const failures = [] as string[];
|
||||
const backslashRE = /\\/g;
|
||||
|
||||
const joinTests: any = [
|
||||
[[path.posix.join, path.win32.join],
|
||||
// arguments result
|
||||
[[['.', 'x/b', '..', '/b/c.js'], 'x/b/c.js'],
|
||||
[[], '.'],
|
||||
[['/.', 'x/b', '..', '/b/c.js'], '/x/b/c.js'],
|
||||
[['/foo', '../../../bar'], '/bar'],
|
||||
[['foo', '../../../bar'], '../../bar'],
|
||||
[['foo/', '../../../bar'], '../../bar'],
|
||||
[['foo/x', '../../../bar'], '../bar'],
|
||||
[['foo/x', './bar'], 'foo/x/bar'],
|
||||
[['foo/x/', './bar'], 'foo/x/bar'],
|
||||
[['foo/x/', '.', 'bar'], 'foo/x/bar'],
|
||||
[['./'], './'],
|
||||
[['.', './'], './'],
|
||||
[['.', '.', '.'], '.'],
|
||||
[['.', './', '.'], '.'],
|
||||
[['.', '/./', '.'], '.'],
|
||||
[['.', '/////./', '.'], '.'],
|
||||
[['.'], '.'],
|
||||
[['', '.'], '.'],
|
||||
[['', 'foo'], 'foo'],
|
||||
[['foo', '/bar'], 'foo/bar'],
|
||||
[['', '/foo'], '/foo'],
|
||||
[['', '', '/foo'], '/foo'],
|
||||
[['', '', 'foo'], 'foo'],
|
||||
[['foo', ''], 'foo'],
|
||||
[['foo/', ''], 'foo/'],
|
||||
[['foo', '', '/bar'], 'foo/bar'],
|
||||
[['./', '..', '/foo'], '../foo'],
|
||||
[['./', '..', '..', '/foo'], '../../foo'],
|
||||
[['.', '..', '..', '/foo'], '../../foo'],
|
||||
[['', '..', '..', '/foo'], '../../foo'],
|
||||
[['/'], '/'],
|
||||
[['/', '.'], '/'],
|
||||
[['/', '..'], '/'],
|
||||
[['/', '..', '..'], '/'],
|
||||
[[''], '.'],
|
||||
[['', ''], '.'],
|
||||
[[' /foo'], ' /foo'],
|
||||
[[' ', 'foo'], ' /foo'],
|
||||
[[' ', '.'], ' '],
|
||||
[[' ', '/'], ' /'],
|
||||
[[' ', ''], ' '],
|
||||
[['/', 'foo'], '/foo'],
|
||||
[['/', '/foo'], '/foo'],
|
||||
[['/', '//foo'], '/foo'],
|
||||
[['/', '', '/foo'], '/foo'],
|
||||
[['', '/', 'foo'], '/foo'],
|
||||
[['', '/', '/foo'], '/foo']
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
// Windows-specific join tests
|
||||
joinTests.push([
|
||||
path.win32.join,
|
||||
joinTests[0][1].slice(0).concat(
|
||||
[// arguments result
|
||||
// UNC path expected
|
||||
[['//foo/bar'], '\\\\foo\\bar\\'],
|
||||
[['\\/foo/bar'], '\\\\foo\\bar\\'],
|
||||
[['\\\\foo/bar'], '\\\\foo\\bar\\'],
|
||||
// UNC path expected - server and share separate
|
||||
[['//foo', 'bar'], '\\\\foo\\bar\\'],
|
||||
[['//foo/', 'bar'], '\\\\foo\\bar\\'],
|
||||
[['//foo', '/bar'], '\\\\foo\\bar\\'],
|
||||
// UNC path expected - questionable
|
||||
[['//foo', '', 'bar'], '\\\\foo\\bar\\'],
|
||||
[['//foo/', '', 'bar'], '\\\\foo\\bar\\'],
|
||||
[['//foo/', '', '/bar'], '\\\\foo\\bar\\'],
|
||||
// UNC path expected - even more questionable
|
||||
[['', '//foo', 'bar'], '\\\\foo\\bar\\'],
|
||||
[['', '//foo/', 'bar'], '\\\\foo\\bar\\'],
|
||||
[['', '//foo/', '/bar'], '\\\\foo\\bar\\'],
|
||||
// No UNC path expected (no double slash in first component)
|
||||
[['\\', 'foo/bar'], '\\foo\\bar'],
|
||||
[['\\', '/foo/bar'], '\\foo\\bar'],
|
||||
[['', '/', '/foo/bar'], '\\foo\\bar'],
|
||||
// No UNC path expected (no non-slashes in first component -
|
||||
// questionable)
|
||||
[['//', 'foo/bar'], '\\foo\\bar'],
|
||||
[['//', '/foo/bar'], '\\foo\\bar'],
|
||||
[['\\\\', '/', '/foo/bar'], '\\foo\\bar'],
|
||||
[['//'], '\\'],
|
||||
// No UNC path expected (share name missing - questionable).
|
||||
[['//foo'], '\\foo'],
|
||||
[['//foo/'], '\\foo\\'],
|
||||
[['//foo', '/'], '\\foo\\'],
|
||||
[['//foo', '', '/'], '\\foo\\'],
|
||||
// No UNC path expected (too many leading slashes - questionable)
|
||||
[['///foo/bar'], '\\foo\\bar'],
|
||||
[['////foo', 'bar'], '\\foo\\bar'],
|
||||
[['\\\\\\/foo/bar'], '\\foo\\bar'],
|
||||
// Drive-relative vs drive-absolute paths. This merely describes the
|
||||
// status quo, rather than being obviously right
|
||||
[['c:'], 'c:.'],
|
||||
[['c:.'], 'c:.'],
|
||||
[['c:', ''], 'c:.'],
|
||||
[['', 'c:'], 'c:.'],
|
||||
[['c:.', '/'], 'c:.\\'],
|
||||
[['c:.', 'file'], 'c:file'],
|
||||
[['c:', '/'], 'c:\\'],
|
||||
[['c:', 'file'], 'c:\\file']
|
||||
]
|
||||
)
|
||||
]);
|
||||
joinTests.forEach((test: any[]) => {
|
||||
if (!Array.isArray(test[0])) {
|
||||
test[0] = [test[0]];
|
||||
}
|
||||
test[0].forEach((join: any) => {
|
||||
test[1].forEach((test: any) => {
|
||||
const actual = join.apply(null, test[0]);
|
||||
const expected = test[1];
|
||||
// For non-Windows specific tests with the Windows join(), we need to try
|
||||
// replacing the slashes since the non-Windows specific tests' `expected`
|
||||
// use forward slashes
|
||||
let actualAlt;
|
||||
let os;
|
||||
if (join === path.win32.join) {
|
||||
actualAlt = actual.replace(backslashRE, '/');
|
||||
os = 'win32';
|
||||
} else {
|
||||
os = 'posix';
|
||||
}
|
||||
const message =
|
||||
`path.${os}.join(${test[0].map(JSON.stringify).join(',')})\n expect=${JSON.stringify(expected)}\n actual=${JSON.stringify(actual)}`;
|
||||
if (actual !== expected && actualAlt !== expected) {
|
||||
failures.push(`\n${message}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
assert.strictEqual(failures.length, 0, failures.join(''));
|
||||
});
|
||||
|
||||
test('dirname', () => {
|
||||
assert.strictEqual(path.dirname(path.normalize(__filename)).substr(-9),
|
||||
isWindows ? 'test\\node' : 'test/node');
|
||||
|
||||
assert.strictEqual(path.posix.dirname('/a/b/'), '/a');
|
||||
assert.strictEqual(path.posix.dirname('/a/b'), '/a');
|
||||
assert.strictEqual(path.posix.dirname('/a'), '/');
|
||||
assert.strictEqual(path.posix.dirname(''), '.');
|
||||
assert.strictEqual(path.posix.dirname('/'), '/');
|
||||
assert.strictEqual(path.posix.dirname('////'), '/');
|
||||
assert.strictEqual(path.posix.dirname('//a'), '//');
|
||||
assert.strictEqual(path.posix.dirname('foo'), '.');
|
||||
|
||||
assert.strictEqual(path.win32.dirname('c:\\'), 'c:\\');
|
||||
assert.strictEqual(path.win32.dirname('c:\\foo'), 'c:\\');
|
||||
assert.strictEqual(path.win32.dirname('c:\\foo\\'), 'c:\\');
|
||||
assert.strictEqual(path.win32.dirname('c:\\foo\\bar'), 'c:\\foo');
|
||||
assert.strictEqual(path.win32.dirname('c:\\foo\\bar\\'), 'c:\\foo');
|
||||
assert.strictEqual(path.win32.dirname('c:\\foo\\bar\\baz'), 'c:\\foo\\bar');
|
||||
assert.strictEqual(path.win32.dirname('\\'), '\\');
|
||||
assert.strictEqual(path.win32.dirname('\\foo'), '\\');
|
||||
assert.strictEqual(path.win32.dirname('\\foo\\'), '\\');
|
||||
assert.strictEqual(path.win32.dirname('\\foo\\bar'), '\\foo');
|
||||
assert.strictEqual(path.win32.dirname('\\foo\\bar\\'), '\\foo');
|
||||
assert.strictEqual(path.win32.dirname('\\foo\\bar\\baz'), '\\foo\\bar');
|
||||
assert.strictEqual(path.win32.dirname('c:'), 'c:');
|
||||
assert.strictEqual(path.win32.dirname('c:foo'), 'c:');
|
||||
assert.strictEqual(path.win32.dirname('c:foo\\'), 'c:');
|
||||
assert.strictEqual(path.win32.dirname('c:foo\\bar'), 'c:foo');
|
||||
assert.strictEqual(path.win32.dirname('c:foo\\bar\\'), 'c:foo');
|
||||
assert.strictEqual(path.win32.dirname('c:foo\\bar\\baz'), 'c:foo\\bar');
|
||||
assert.strictEqual(path.win32.dirname('file:stream'), '.');
|
||||
assert.strictEqual(path.win32.dirname('dir\\file:stream'), 'dir');
|
||||
assert.strictEqual(path.win32.dirname('\\\\unc\\share'),
|
||||
'\\\\unc\\share');
|
||||
assert.strictEqual(path.win32.dirname('\\\\unc\\share\\foo'),
|
||||
'\\\\unc\\share\\');
|
||||
assert.strictEqual(path.win32.dirname('\\\\unc\\share\\foo\\'),
|
||||
'\\\\unc\\share\\');
|
||||
assert.strictEqual(path.win32.dirname('\\\\unc\\share\\foo\\bar'),
|
||||
'\\\\unc\\share\\foo');
|
||||
assert.strictEqual(path.win32.dirname('\\\\unc\\share\\foo\\bar\\'),
|
||||
'\\\\unc\\share\\foo');
|
||||
assert.strictEqual(path.win32.dirname('\\\\unc\\share\\foo\\bar\\baz'),
|
||||
'\\\\unc\\share\\foo\\bar');
|
||||
assert.strictEqual(path.win32.dirname('/a/b/'), '/a');
|
||||
assert.strictEqual(path.win32.dirname('/a/b'), '/a');
|
||||
assert.strictEqual(path.win32.dirname('/a'), '/');
|
||||
assert.strictEqual(path.win32.dirname(''), '.');
|
||||
assert.strictEqual(path.win32.dirname('/'), '/');
|
||||
assert.strictEqual(path.win32.dirname('////'), '/');
|
||||
assert.strictEqual(path.win32.dirname('foo'), '.');
|
||||
|
||||
// Tests from VSCode
|
||||
|
||||
function assertDirname(p: string, expected: string, win = false) {
|
||||
const actual = win ? path.win32.dirname(p) : path.posix.dirname(p);
|
||||
|
||||
if (actual !== expected) {
|
||||
assert.fail(`${p}: expected: ${expected}, ours: ${actual}`);
|
||||
}
|
||||
}
|
||||
|
||||
assertDirname('foo/bar', 'foo');
|
||||
assertDirname('foo\\bar', 'foo', true);
|
||||
assertDirname('/foo/bar', '/foo');
|
||||
assertDirname('\\foo\\bar', '\\foo', true);
|
||||
assertDirname('/foo', '/');
|
||||
assertDirname('\\foo', '\\', true);
|
||||
assertDirname('/', '/');
|
||||
assertDirname('\\', '\\', true);
|
||||
assertDirname('foo', '.');
|
||||
assertDirname('f', '.');
|
||||
assertDirname('f/', '.');
|
||||
assertDirname('/folder/', '/');
|
||||
assertDirname('c:\\some\\file.txt', 'c:\\some', true);
|
||||
assertDirname('c:\\some', 'c:\\', true);
|
||||
assertDirname('c:\\', 'c:\\', true);
|
||||
assertDirname('c:', 'c:', true);
|
||||
assertDirname('\\\\server\\share\\some\\path', '\\\\server\\share\\some', true);
|
||||
assertDirname('\\\\server\\share\\some', '\\\\server\\share\\', true);
|
||||
assertDirname('\\\\server\\share\\', '\\\\server\\share\\', true);
|
||||
});
|
||||
|
||||
test('extname', () => {
|
||||
const failures = [] as string[];
|
||||
const slashRE = /\//g;
|
||||
|
||||
[
|
||||
[__filename, '.js'],
|
||||
['', ''],
|
||||
['/path/to/file', ''],
|
||||
['/path/to/file.ext', '.ext'],
|
||||
['/path.to/file.ext', '.ext'],
|
||||
['/path.to/file', ''],
|
||||
['/path.to/.file', ''],
|
||||
['/path.to/.file.ext', '.ext'],
|
||||
['/path/to/f.ext', '.ext'],
|
||||
['/path/to/..ext', '.ext'],
|
||||
['/path/to/..', ''],
|
||||
['file', ''],
|
||||
['file.ext', '.ext'],
|
||||
['.file', ''],
|
||||
['.file.ext', '.ext'],
|
||||
['/file', ''],
|
||||
['/file.ext', '.ext'],
|
||||
['/.file', ''],
|
||||
['/.file.ext', '.ext'],
|
||||
['.path/file.ext', '.ext'],
|
||||
['file.ext.ext', '.ext'],
|
||||
['file.', '.'],
|
||||
['.', ''],
|
||||
['./', ''],
|
||||
['.file.ext', '.ext'],
|
||||
['.file', ''],
|
||||
['.file.', '.'],
|
||||
['.file..', '.'],
|
||||
['..', ''],
|
||||
['../', ''],
|
||||
['..file.ext', '.ext'],
|
||||
['..file', '.file'],
|
||||
['..file.', '.'],
|
||||
['..file..', '.'],
|
||||
['...', '.'],
|
||||
['...ext', '.ext'],
|
||||
['....', '.'],
|
||||
['file.ext/', '.ext'],
|
||||
['file.ext//', '.ext'],
|
||||
['file/', ''],
|
||||
['file//', ''],
|
||||
['file./', '.'],
|
||||
['file.//', '.'],
|
||||
].forEach((test) => {
|
||||
const expected = test[1];
|
||||
[path.posix.extname, path.win32.extname].forEach((extname) => {
|
||||
let input = test[0];
|
||||
let os;
|
||||
if (extname === path.win32.extname) {
|
||||
input = input.replace(slashRE, '\\');
|
||||
os = 'win32';
|
||||
} else {
|
||||
os = 'posix';
|
||||
}
|
||||
const actual = extname(input);
|
||||
const message = `path.${os}.extname(${JSON.stringify(input)})\n expect=${JSON.stringify(expected)}\n actual=${JSON.stringify(actual)}`;
|
||||
if (actual !== expected) {
|
||||
failures.push(`\n${message}`);
|
||||
}
|
||||
});
|
||||
{
|
||||
const input = `C:${test[0].replace(slashRE, '\\')}`;
|
||||
const actual = path.win32.extname(input);
|
||||
const message = `path.win32.extname(${JSON.stringify(input)})\n expect=${JSON.stringify(expected)}\n actual=${JSON.stringify(actual)}`;
|
||||
if (actual !== expected) {
|
||||
failures.push(`\n${message}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
assert.strictEqual(failures.length, 0, failures.join(''));
|
||||
|
||||
// On Windows, backslash is a path separator.
|
||||
assert.strictEqual(path.win32.extname('.\\'), '');
|
||||
assert.strictEqual(path.win32.extname('..\\'), '');
|
||||
assert.strictEqual(path.win32.extname('file.ext\\'), '.ext');
|
||||
assert.strictEqual(path.win32.extname('file.ext\\\\'), '.ext');
|
||||
assert.strictEqual(path.win32.extname('file\\'), '');
|
||||
assert.strictEqual(path.win32.extname('file\\\\'), '');
|
||||
assert.strictEqual(path.win32.extname('file.\\'), '.');
|
||||
assert.strictEqual(path.win32.extname('file.\\\\'), '.');
|
||||
|
||||
// On *nix, backslash is a valid name component like any other character.
|
||||
assert.strictEqual(path.posix.extname('.\\'), '');
|
||||
assert.strictEqual(path.posix.extname('..\\'), '.\\');
|
||||
assert.strictEqual(path.posix.extname('file.ext\\'), '.ext\\');
|
||||
assert.strictEqual(path.posix.extname('file.ext\\\\'), '.ext\\\\');
|
||||
assert.strictEqual(path.posix.extname('file\\'), '');
|
||||
assert.strictEqual(path.posix.extname('file\\\\'), '');
|
||||
assert.strictEqual(path.posix.extname('file.\\'), '.\\');
|
||||
assert.strictEqual(path.posix.extname('file.\\\\'), '.\\\\');
|
||||
|
||||
// Tests from VSCode
|
||||
assert.equal(path.extname('far.boo'), '.boo');
|
||||
assert.equal(path.extname('far.b'), '.b');
|
||||
assert.equal(path.extname('far.'), '.');
|
||||
assert.equal(path.extname('far.boo/boo.far'), '.far');
|
||||
assert.equal(path.extname('far.boo/boo'), '');
|
||||
});
|
||||
|
||||
test('resolve', () => {
|
||||
const failures = [] as string[];
|
||||
const slashRE = /\//g;
|
||||
const backslashRE = /\\/g;
|
||||
|
||||
const resolveTests = [
|
||||
[path.win32.resolve,
|
||||
// arguments result
|
||||
[[['c:/blah\\blah', 'd:/games', 'c:../a'], 'c:\\blah\\a'],
|
||||
[['c:/ignore', 'd:\\a/b\\c/d', '\\e.exe'], 'd:\\e.exe'],
|
||||
[['c:/ignore', 'c:/some/file'], 'c:\\some\\file'],
|
||||
[['d:/ignore', 'd:some/dir//'], 'd:\\ignore\\some\\dir'],
|
||||
[['.'], process.cwd()],
|
||||
[['//server/share', '..', 'relative\\'], '\\\\server\\share\\relative'],
|
||||
[['c:/', '//'], 'c:\\'],
|
||||
[['c:/', '//dir'], 'c:\\dir'],
|
||||
[['c:/', '//server/share'], '\\\\server\\share\\'],
|
||||
[['c:/', '//server//share'], '\\\\server\\share\\'],
|
||||
[['c:/', '///some//dir'], 'c:\\some\\dir'],
|
||||
[['C:\\foo\\tmp.3\\', '..\\tmp.3\\cycles\\root.js'],
|
||||
'C:\\foo\\tmp.3\\cycles\\root.js']
|
||||
]
|
||||
],
|
||||
[path.posix.resolve,
|
||||
// arguments result
|
||||
[[['/var/lib', '../', 'file/'], '/var/file'],
|
||||
[['/var/lib', '/../', 'file/'], '/file'],
|
||||
[['a/b/c/', '../../..'], process.cwd()],
|
||||
[['.'], process.cwd()],
|
||||
[['/some/dir', '.', '/absolute/'], '/absolute'],
|
||||
[['/foo/tmp.3/', '../tmp.3/cycles/root.js'], '/foo/tmp.3/cycles/root.js']
|
||||
]
|
||||
]
|
||||
];
|
||||
resolveTests.forEach((test) => {
|
||||
const resolve = test[0];
|
||||
//@ts-expect-error
|
||||
test[1].forEach((test) => {
|
||||
//@ts-expect-error
|
||||
const actual = resolve.apply(null, test[0]);
|
||||
let actualAlt;
|
||||
const os = resolve === path.win32.resolve ? 'win32' : 'posix';
|
||||
if (resolve === path.win32.resolve && !isWindows) {
|
||||
actualAlt = actual.replace(backslashRE, '/');
|
||||
}
|
||||
else if (resolve !== path.win32.resolve && isWindows) {
|
||||
actualAlt = actual.replace(slashRE, '\\');
|
||||
}
|
||||
|
||||
const expected = test[1];
|
||||
const message =
|
||||
`path.${os}.resolve(${test[0].map(JSON.stringify).join(',')})\n expect=${JSON.stringify(expected)}\n actual=${JSON.stringify(actual)}`;
|
||||
if (actual !== expected && actualAlt !== expected) {
|
||||
failures.push(`\n${message}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
assert.strictEqual(failures.length, 0, failures.join(''));
|
||||
|
||||
// if (isWindows) {
|
||||
// // Test resolving the current Windows drive letter from a spawned process.
|
||||
// // See https://github.com/nodejs/node/issues/7215
|
||||
// const currentDriveLetter = path.parse(process.cwd()).root.substring(0, 2);
|
||||
// const resolveFixture = fixtures.path('path-resolve.js');
|
||||
// const spawnResult = child.spawnSync(
|
||||
// process.argv[0], [resolveFixture, currentDriveLetter]);
|
||||
// const resolvedPath = spawnResult.stdout.toString().trim();
|
||||
// assert.strictEqual(resolvedPath.toLowerCase(), process.cwd().toLowerCase());
|
||||
// }
|
||||
});
|
||||
|
||||
test('basename', () => {
|
||||
assert.strictEqual(path.basename(__filename), 'path.test.js');
|
||||
assert.strictEqual(path.basename(__filename, '.js'), 'path.test');
|
||||
assert.strictEqual(path.basename('.js', '.js'), '');
|
||||
assert.strictEqual(path.basename(''), '');
|
||||
assert.strictEqual(path.basename('/dir/basename.ext'), 'basename.ext');
|
||||
assert.strictEqual(path.basename('/basename.ext'), 'basename.ext');
|
||||
assert.strictEqual(path.basename('basename.ext'), 'basename.ext');
|
||||
assert.strictEqual(path.basename('basename.ext/'), 'basename.ext');
|
||||
assert.strictEqual(path.basename('basename.ext//'), 'basename.ext');
|
||||
assert.strictEqual(path.basename('aaa/bbb', '/bbb'), 'bbb');
|
||||
assert.strictEqual(path.basename('aaa/bbb', 'a/bbb'), 'bbb');
|
||||
assert.strictEqual(path.basename('aaa/bbb', 'bbb'), 'bbb');
|
||||
assert.strictEqual(path.basename('aaa/bbb//', 'bbb'), 'bbb');
|
||||
assert.strictEqual(path.basename('aaa/bbb', 'bb'), 'b');
|
||||
assert.strictEqual(path.basename('aaa/bbb', 'b'), 'bb');
|
||||
assert.strictEqual(path.basename('/aaa/bbb', '/bbb'), 'bbb');
|
||||
assert.strictEqual(path.basename('/aaa/bbb', 'a/bbb'), 'bbb');
|
||||
assert.strictEqual(path.basename('/aaa/bbb', 'bbb'), 'bbb');
|
||||
assert.strictEqual(path.basename('/aaa/bbb//', 'bbb'), 'bbb');
|
||||
assert.strictEqual(path.basename('/aaa/bbb', 'bb'), 'b');
|
||||
assert.strictEqual(path.basename('/aaa/bbb', 'b'), 'bb');
|
||||
assert.strictEqual(path.basename('/aaa/bbb'), 'bbb');
|
||||
assert.strictEqual(path.basename('/aaa/'), 'aaa');
|
||||
assert.strictEqual(path.basename('/aaa/b'), 'b');
|
||||
assert.strictEqual(path.basename('/a/b'), 'b');
|
||||
assert.strictEqual(path.basename('//a'), 'a');
|
||||
assert.strictEqual(path.basename('a', 'a'), '');
|
||||
|
||||
// On Windows a backslash acts as a path separator.
|
||||
assert.strictEqual(path.win32.basename('\\dir\\basename.ext'), 'basename.ext');
|
||||
assert.strictEqual(path.win32.basename('\\basename.ext'), 'basename.ext');
|
||||
assert.strictEqual(path.win32.basename('basename.ext'), 'basename.ext');
|
||||
assert.strictEqual(path.win32.basename('basename.ext\\'), 'basename.ext');
|
||||
assert.strictEqual(path.win32.basename('basename.ext\\\\'), 'basename.ext');
|
||||
assert.strictEqual(path.win32.basename('foo'), 'foo');
|
||||
assert.strictEqual(path.win32.basename('aaa\\bbb', '\\bbb'), 'bbb');
|
||||
assert.strictEqual(path.win32.basename('aaa\\bbb', 'a\\bbb'), 'bbb');
|
||||
assert.strictEqual(path.win32.basename('aaa\\bbb', 'bbb'), 'bbb');
|
||||
assert.strictEqual(path.win32.basename('aaa\\bbb\\\\\\\\', 'bbb'), 'bbb');
|
||||
assert.strictEqual(path.win32.basename('aaa\\bbb', 'bb'), 'b');
|
||||
assert.strictEqual(path.win32.basename('aaa\\bbb', 'b'), 'bb');
|
||||
assert.strictEqual(path.win32.basename('C:'), '');
|
||||
assert.strictEqual(path.win32.basename('C:.'), '.');
|
||||
assert.strictEqual(path.win32.basename('C:\\'), '');
|
||||
assert.strictEqual(path.win32.basename('C:\\dir\\base.ext'), 'base.ext');
|
||||
assert.strictEqual(path.win32.basename('C:\\basename.ext'), 'basename.ext');
|
||||
assert.strictEqual(path.win32.basename('C:basename.ext'), 'basename.ext');
|
||||
assert.strictEqual(path.win32.basename('C:basename.ext\\'), 'basename.ext');
|
||||
assert.strictEqual(path.win32.basename('C:basename.ext\\\\'), 'basename.ext');
|
||||
assert.strictEqual(path.win32.basename('C:foo'), 'foo');
|
||||
assert.strictEqual(path.win32.basename('file:stream'), 'file:stream');
|
||||
assert.strictEqual(path.win32.basename('a', 'a'), '');
|
||||
|
||||
// On unix a backslash is just treated as any other character.
|
||||
assert.strictEqual(path.posix.basename('\\dir\\basename.ext'),
|
||||
'\\dir\\basename.ext');
|
||||
assert.strictEqual(path.posix.basename('\\basename.ext'), '\\basename.ext');
|
||||
assert.strictEqual(path.posix.basename('basename.ext'), 'basename.ext');
|
||||
assert.strictEqual(path.posix.basename('basename.ext\\'), 'basename.ext\\');
|
||||
assert.strictEqual(path.posix.basename('basename.ext\\\\'), 'basename.ext\\\\');
|
||||
assert.strictEqual(path.posix.basename('foo'), 'foo');
|
||||
|
||||
// POSIX filenames may include control characters
|
||||
// c.f. http://www.dwheeler.com/essays/fixing-unix-linux-filenames.html
|
||||
const controlCharFilename = `Icon${String.fromCharCode(13)}`;
|
||||
assert.strictEqual(path.posix.basename(`/a/b/${controlCharFilename}`),
|
||||
controlCharFilename);
|
||||
|
||||
// Tests from VSCode
|
||||
assert.equal(path.basename('foo/bar'), 'bar');
|
||||
assert.equal(path.posix.basename('foo\\bar'), 'foo\\bar');
|
||||
assert.equal(path.win32.basename('foo\\bar'), 'bar');
|
||||
assert.equal(path.basename('/foo/bar'), 'bar');
|
||||
assert.equal(path.posix.basename('\\foo\\bar'), '\\foo\\bar');
|
||||
assert.equal(path.win32.basename('\\foo\\bar'), 'bar');
|
||||
assert.equal(path.basename('./bar'), 'bar');
|
||||
assert.equal(path.posix.basename('.\\bar'), '.\\bar');
|
||||
assert.equal(path.win32.basename('.\\bar'), 'bar');
|
||||
assert.equal(path.basename('/bar'), 'bar');
|
||||
assert.equal(path.posix.basename('\\bar'), '\\bar');
|
||||
assert.equal(path.win32.basename('\\bar'), 'bar');
|
||||
assert.equal(path.basename('bar/'), 'bar');
|
||||
assert.equal(path.posix.basename('bar\\'), 'bar\\');
|
||||
assert.equal(path.win32.basename('bar\\'), 'bar');
|
||||
assert.equal(path.basename('bar'), 'bar');
|
||||
assert.equal(path.basename('////////'), '');
|
||||
assert.equal(path.posix.basename('\\\\\\\\'), '\\\\\\\\');
|
||||
assert.equal(path.win32.basename('\\\\\\\\'), '');
|
||||
});
|
||||
|
||||
test('relative', () => {
|
||||
const failures = [] as string[];
|
||||
|
||||
const relativeTests = [
|
||||
[path.win32.relative,
|
||||
// arguments result
|
||||
[['c:/blah\\blah', 'd:/games', 'd:\\games'],
|
||||
['c:/aaaa/bbbb', 'c:/aaaa', '..'],
|
||||
['c:/aaaa/bbbb', 'c:/cccc', '..\\..\\cccc'],
|
||||
['c:/aaaa/bbbb', 'c:/aaaa/bbbb', ''],
|
||||
['c:/aaaa/bbbb', 'c:/aaaa/cccc', '..\\cccc'],
|
||||
['c:/aaaa/', 'c:/aaaa/cccc', 'cccc'],
|
||||
['c:/', 'c:\\aaaa\\bbbb', 'aaaa\\bbbb'],
|
||||
['c:/aaaa/bbbb', 'd:\\', 'd:\\'],
|
||||
['c:/AaAa/bbbb', 'c:/aaaa/bbbb', ''],
|
||||
['c:/aaaaa/', 'c:/aaaa/cccc', '..\\aaaa\\cccc'],
|
||||
['C:\\foo\\bar\\baz\\quux', 'C:\\', '..\\..\\..\\..'],
|
||||
['C:\\foo\\test', 'C:\\foo\\test\\bar\\package.json', 'bar\\package.json'],
|
||||
['C:\\foo\\bar\\baz-quux', 'C:\\foo\\bar\\baz', '..\\baz'],
|
||||
['C:\\foo\\bar\\baz', 'C:\\foo\\bar\\baz-quux', '..\\baz-quux'],
|
||||
['\\\\foo\\bar', '\\\\foo\\bar\\baz', 'baz'],
|
||||
['\\\\foo\\bar\\baz', '\\\\foo\\bar', '..'],
|
||||
['\\\\foo\\bar\\baz-quux', '\\\\foo\\bar\\baz', '..\\baz'],
|
||||
['\\\\foo\\bar\\baz', '\\\\foo\\bar\\baz-quux', '..\\baz-quux'],
|
||||
['C:\\baz-quux', 'C:\\baz', '..\\baz'],
|
||||
['C:\\baz', 'C:\\baz-quux', '..\\baz-quux'],
|
||||
['\\\\foo\\baz-quux', '\\\\foo\\baz', '..\\baz'],
|
||||
['\\\\foo\\baz', '\\\\foo\\baz-quux', '..\\baz-quux'],
|
||||
['C:\\baz', '\\\\foo\\bar\\baz', '\\\\foo\\bar\\baz'],
|
||||
['\\\\foo\\bar\\baz', 'C:\\baz', 'C:\\baz']
|
||||
]
|
||||
],
|
||||
[path.posix.relative,
|
||||
// arguments result
|
||||
[['/var/lib', '/var', '..'],
|
||||
['/var/lib', '/bin', '../../bin'],
|
||||
['/var/lib', '/var/lib', ''],
|
||||
['/var/lib', '/var/apache', '../apache'],
|
||||
['/var/', '/var/lib', 'lib'],
|
||||
['/', '/var/lib', 'var/lib'],
|
||||
['/foo/test', '/foo/test/bar/package.json', 'bar/package.json'],
|
||||
['/Users/a/web/b/test/mails', '/Users/a/web/b', '../..'],
|
||||
['/foo/bar/baz-quux', '/foo/bar/baz', '../baz'],
|
||||
['/foo/bar/baz', '/foo/bar/baz-quux', '../baz-quux'],
|
||||
['/baz-quux', '/baz', '../baz'],
|
||||
['/baz', '/baz-quux', '../baz-quux']
|
||||
]
|
||||
]
|
||||
];
|
||||
relativeTests.forEach((test) => {
|
||||
const relative = test[0];
|
||||
//@ts-expect-error
|
||||
test[1].forEach((test) => {
|
||||
//@ts-expect-error
|
||||
const actual = relative(test[0], test[1]);
|
||||
const expected = test[2];
|
||||
const os = relative === path.win32.relative ? 'win32' : 'posix';
|
||||
const message = `path.${os}.relative(${test.slice(0, 2).map(JSON.stringify).join(',')})\n expect=${JSON.stringify(expected)}\n actual=${JSON.stringify(actual)}`;
|
||||
if (actual !== expected) {
|
||||
failures.push(`\n${message}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
assert.strictEqual(failures.length, 0, failures.join(''));
|
||||
});
|
||||
|
||||
test('normalize', () => {
|
||||
assert.strictEqual(path.win32.normalize('./fixtures///b/../b/c.js'),
|
||||
'fixtures\\b\\c.js');
|
||||
assert.strictEqual(path.win32.normalize('/foo/../../../bar'), '\\bar');
|
||||
assert.strictEqual(path.win32.normalize('a//b//../b'), 'a\\b');
|
||||
assert.strictEqual(path.win32.normalize('a//b//./c'), 'a\\b\\c');
|
||||
assert.strictEqual(path.win32.normalize('a//b//.'), 'a\\b');
|
||||
assert.strictEqual(path.win32.normalize('//server/share/dir/file.ext'),
|
||||
'\\\\server\\share\\dir\\file.ext');
|
||||
assert.strictEqual(path.win32.normalize('/a/b/c/../../../x/y/z'), '\\x\\y\\z');
|
||||
assert.strictEqual(path.win32.normalize('C:'), 'C:.');
|
||||
assert.strictEqual(path.win32.normalize('C:..\\abc'), 'C:..\\abc');
|
||||
assert.strictEqual(path.win32.normalize('C:..\\..\\abc\\..\\def'),
|
||||
'C:..\\..\\def');
|
||||
assert.strictEqual(path.win32.normalize('C:\\.'), 'C:\\');
|
||||
assert.strictEqual(path.win32.normalize('file:stream'), 'file:stream');
|
||||
assert.strictEqual(path.win32.normalize('bar\\foo..\\..\\'), 'bar\\');
|
||||
assert.strictEqual(path.win32.normalize('bar\\foo..\\..'), 'bar');
|
||||
assert.strictEqual(path.win32.normalize('bar\\foo..\\..\\baz'), 'bar\\baz');
|
||||
assert.strictEqual(path.win32.normalize('bar\\foo..\\'), 'bar\\foo..\\');
|
||||
assert.strictEqual(path.win32.normalize('bar\\foo..'), 'bar\\foo..');
|
||||
assert.strictEqual(path.win32.normalize('..\\foo..\\..\\..\\bar'),
|
||||
'..\\..\\bar');
|
||||
assert.strictEqual(path.win32.normalize('..\\...\\..\\.\\...\\..\\..\\bar'),
|
||||
'..\\..\\bar');
|
||||
assert.strictEqual(path.win32.normalize('../../../foo/../../../bar'),
|
||||
'..\\..\\..\\..\\..\\bar');
|
||||
assert.strictEqual(path.win32.normalize('../../../foo/../../../bar/../../'),
|
||||
'..\\..\\..\\..\\..\\..\\');
|
||||
assert.strictEqual(
|
||||
path.win32.normalize('../foobar/barfoo/foo/../../../bar/../../'),
|
||||
'..\\..\\'
|
||||
);
|
||||
assert.strictEqual(
|
||||
path.win32.normalize('../.../../foobar/../../../bar/../../baz'),
|
||||
'..\\..\\..\\..\\baz'
|
||||
);
|
||||
assert.strictEqual(path.win32.normalize('foo/bar\\baz'), 'foo\\bar\\baz');
|
||||
|
||||
assert.strictEqual(path.posix.normalize('./fixtures///b/../b/c.js'),
|
||||
'fixtures/b/c.js');
|
||||
assert.strictEqual(path.posix.normalize('/foo/../../../bar'), '/bar');
|
||||
assert.strictEqual(path.posix.normalize('a//b//../b'), 'a/b');
|
||||
assert.strictEqual(path.posix.normalize('a//b//./c'), 'a/b/c');
|
||||
assert.strictEqual(path.posix.normalize('a//b//.'), 'a/b');
|
||||
assert.strictEqual(path.posix.normalize('/a/b/c/../../../x/y/z'), '/x/y/z');
|
||||
assert.strictEqual(path.posix.normalize('///..//./foo/.//bar'), '/foo/bar');
|
||||
assert.strictEqual(path.posix.normalize('bar/foo../../'), 'bar/');
|
||||
assert.strictEqual(path.posix.normalize('bar/foo../..'), 'bar');
|
||||
assert.strictEqual(path.posix.normalize('bar/foo../../baz'), 'bar/baz');
|
||||
assert.strictEqual(path.posix.normalize('bar/foo../'), 'bar/foo../');
|
||||
assert.strictEqual(path.posix.normalize('bar/foo..'), 'bar/foo..');
|
||||
assert.strictEqual(path.posix.normalize('../foo../../../bar'), '../../bar');
|
||||
assert.strictEqual(path.posix.normalize('../.../.././.../../../bar'),
|
||||
'../../bar');
|
||||
assert.strictEqual(path.posix.normalize('../../../foo/../../../bar'),
|
||||
'../../../../../bar');
|
||||
assert.strictEqual(path.posix.normalize('../../../foo/../../../bar/../../'),
|
||||
'../../../../../../');
|
||||
assert.strictEqual(
|
||||
path.posix.normalize('../foobar/barfoo/foo/../../../bar/../../'),
|
||||
'../../'
|
||||
);
|
||||
assert.strictEqual(
|
||||
path.posix.normalize('../.../../foobar/../../../bar/../../baz'),
|
||||
'../../../../baz'
|
||||
);
|
||||
assert.strictEqual(path.posix.normalize('foo/bar\\baz'), 'foo/bar\\baz');
|
||||
});
|
||||
|
||||
test('isAbsolute', () => {
|
||||
assert.strictEqual(path.win32.isAbsolute('/'), true);
|
||||
assert.strictEqual(path.win32.isAbsolute('//'), true);
|
||||
assert.strictEqual(path.win32.isAbsolute('//server'), true);
|
||||
assert.strictEqual(path.win32.isAbsolute('//server/file'), true);
|
||||
assert.strictEqual(path.win32.isAbsolute('\\\\server\\file'), true);
|
||||
assert.strictEqual(path.win32.isAbsolute('\\\\server'), true);
|
||||
assert.strictEqual(path.win32.isAbsolute('\\\\'), true);
|
||||
assert.strictEqual(path.win32.isAbsolute('c'), false);
|
||||
assert.strictEqual(path.win32.isAbsolute('c:'), false);
|
||||
assert.strictEqual(path.win32.isAbsolute('c:\\'), true);
|
||||
assert.strictEqual(path.win32.isAbsolute('c:/'), true);
|
||||
assert.strictEqual(path.win32.isAbsolute('c://'), true);
|
||||
assert.strictEqual(path.win32.isAbsolute('C:/Users/'), true);
|
||||
assert.strictEqual(path.win32.isAbsolute('C:\\Users\\'), true);
|
||||
assert.strictEqual(path.win32.isAbsolute('C:cwd/another'), false);
|
||||
assert.strictEqual(path.win32.isAbsolute('C:cwd\\another'), false);
|
||||
assert.strictEqual(path.win32.isAbsolute('directory/directory'), false);
|
||||
assert.strictEqual(path.win32.isAbsolute('directory\\directory'), false);
|
||||
|
||||
assert.strictEqual(path.posix.isAbsolute('/home/foo'), true);
|
||||
assert.strictEqual(path.posix.isAbsolute('/home/foo/..'), true);
|
||||
assert.strictEqual(path.posix.isAbsolute('bar/'), false);
|
||||
assert.strictEqual(path.posix.isAbsolute('./baz'), false);
|
||||
|
||||
// Tests from VSCode:
|
||||
|
||||
// Absolute Paths
|
||||
[
|
||||
'C:/',
|
||||
'C:\\',
|
||||
'C:/foo',
|
||||
'C:\\foo',
|
||||
'z:/foo/bar.txt',
|
||||
'z:\\foo\\bar.txt',
|
||||
|
||||
'\\\\localhost\\c$\\foo',
|
||||
|
||||
'/',
|
||||
'/foo'
|
||||
].forEach(absolutePath => {
|
||||
assert.ok(path.win32.isAbsolute(absolutePath), absolutePath);
|
||||
});
|
||||
|
||||
[
|
||||
'/',
|
||||
'/foo',
|
||||
'/foo/bar.txt'
|
||||
].forEach(absolutePath => {
|
||||
assert.ok(path.posix.isAbsolute(absolutePath), absolutePath);
|
||||
});
|
||||
|
||||
// Relative Paths
|
||||
[
|
||||
'',
|
||||
'foo',
|
||||
'foo/bar',
|
||||
'./foo',
|
||||
'http://foo.com/bar'
|
||||
].forEach(nonAbsolutePath => {
|
||||
assert.ok(!path.win32.isAbsolute(nonAbsolutePath), nonAbsolutePath);
|
||||
});
|
||||
|
||||
[
|
||||
'',
|
||||
'foo',
|
||||
'foo/bar',
|
||||
'./foo',
|
||||
'http://foo.com/bar',
|
||||
'z:/foo/bar.txt',
|
||||
].forEach(nonAbsolutePath => {
|
||||
assert.ok(!path.posix.isAbsolute(nonAbsolutePath), nonAbsolutePath);
|
||||
});
|
||||
});
|
||||
|
||||
test('path', () => {
|
||||
// path.sep tests
|
||||
// windows
|
||||
assert.strictEqual(path.win32.sep, '\\');
|
||||
// posix
|
||||
assert.strictEqual(path.posix.sep, '/');
|
||||
|
||||
// path.delimiter tests
|
||||
// windows
|
||||
assert.strictEqual(path.win32.delimiter, ';');
|
||||
// posix
|
||||
assert.strictEqual(path.posix.delimiter, ':');
|
||||
|
||||
// if (isWindows) {
|
||||
// assert.strictEqual(path, path.win32);
|
||||
// } else {
|
||||
// assert.strictEqual(path, path.posix);
|
||||
// }
|
||||
});
|
||||
|
||||
// test('perf', () => {
|
||||
// const folderNames = [
|
||||
// 'abc',
|
||||
// 'Users',
|
||||
// 'reallylongfoldername',
|
||||
// 's',
|
||||
// 'reallyreallyreallylongfoldername',
|
||||
// 'home'
|
||||
// ];
|
||||
|
||||
// const basePaths = [
|
||||
// 'C:',
|
||||
// '',
|
||||
// ];
|
||||
|
||||
// const separators = [
|
||||
// '\\',
|
||||
// '/'
|
||||
// ];
|
||||
|
||||
// function randomInt(ciel: number): number {
|
||||
// return Math.floor(Math.random() * ciel);
|
||||
// }
|
||||
|
||||
// let pathsToNormalize = [];
|
||||
// let pathsToJoin = [];
|
||||
// let i;
|
||||
// for (i = 0; i < 1000000; i++) {
|
||||
// const basePath = basePaths[randomInt(basePaths.length)];
|
||||
// let lengthOfPath = randomInt(10) + 2;
|
||||
|
||||
// let pathToNormalize = basePath + separators[randomInt(separators.length)];
|
||||
// while (lengthOfPath-- > 0) {
|
||||
// pathToNormalize = pathToNormalize + folderNames[randomInt(folderNames.length)] + separators[randomInt(separators.length)];
|
||||
// }
|
||||
|
||||
// pathsToNormalize.push(pathToNormalize);
|
||||
|
||||
// let pathToJoin = '';
|
||||
// lengthOfPath = randomInt(10) + 2;
|
||||
// while (lengthOfPath-- > 0) {
|
||||
// pathToJoin = pathToJoin + folderNames[randomInt(folderNames.length)] + separators[randomInt(separators.length)];
|
||||
// }
|
||||
|
||||
// pathsToJoin.push(pathToJoin + '.ts');
|
||||
// }
|
||||
|
||||
// let newTime = 0;
|
||||
|
||||
// let j;
|
||||
// for(j = 0; j < pathsToJoin.length; j++) {
|
||||
// const path1 = pathsToNormalize[j];
|
||||
// const path2 = pathsToNormalize[j];
|
||||
|
||||
// const newStart = performance.now();
|
||||
// path.join(path1, path2);
|
||||
// newTime += performance.now() - newStart;
|
||||
// }
|
||||
|
||||
// assert.ok(false, `Time: ${newTime}ms.`);
|
||||
// });
|
||||
});
|
||||
@@ -0,0 +1,23 @@
|
||||
'use strict';
|
||||
/// <reference path="employee.ts" />
|
||||
var Workforce;
|
||||
(function (Workforce_1) {
|
||||
var Company = (function () {
|
||||
function Company() {
|
||||
}
|
||||
return Company;
|
||||
})();
|
||||
(function (property, Workforce, IEmployee) {
|
||||
if (property === undefined) { property = employees; }
|
||||
if (IEmployee === undefined) { IEmployee = []; }
|
||||
property;
|
||||
calculateMonthlyExpenses();
|
||||
{
|
||||
var result = 0;
|
||||
for (var i = 0; i < employees.length; i++) {
|
||||
result += employees[i].calculatePay();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
});
|
||||
})(Workforce || (Workforce = {}));
|
||||
@@ -0,0 +1,117 @@
|
||||
'use strict';
|
||||
var Conway;
|
||||
(function (Conway) {
|
||||
var Cell = (function () {
|
||||
function Cell() {
|
||||
}
|
||||
return Cell;
|
||||
})();
|
||||
(function (property, number, property, number, property, boolean) {
|
||||
if (property === undefined) { property = row; }
|
||||
if (property === undefined) { property = col; }
|
||||
if (property === undefined) { property = live; }
|
||||
});
|
||||
var GameOfLife = (function () {
|
||||
function GameOfLife() {
|
||||
}
|
||||
return GameOfLife;
|
||||
})();
|
||||
(function () {
|
||||
property;
|
||||
gridSize = 50;
|
||||
property;
|
||||
canvasSize = 600;
|
||||
property;
|
||||
lineColor = '#cdcdcd';
|
||||
property;
|
||||
liveColor = '#666';
|
||||
property;
|
||||
deadColor = '#eee';
|
||||
property;
|
||||
initialLifeProbability = 0.5;
|
||||
property;
|
||||
animationRate = 60;
|
||||
property;
|
||||
cellSize = 0;
|
||||
property;
|
||||
context: ICanvasRenderingContext2D;
|
||||
property;
|
||||
world = createWorld();
|
||||
circleOfLife();
|
||||
function createWorld() {
|
||||
return travelWorld(function (cell) {
|
||||
cell.live = Math.random() < initialLifeProbability;
|
||||
return cell;
|
||||
});
|
||||
}
|
||||
function circleOfLife() {
|
||||
world = travelWorld(function (cell) {
|
||||
cell = world[cell.row][cell.col];
|
||||
draw(cell);
|
||||
return resolveNextGeneration(cell);
|
||||
});
|
||||
setTimeout(function () { circleOfLife(); }, animationRate);
|
||||
}
|
||||
function resolveNextGeneration(cell) {
|
||||
var count = countNeighbors(cell);
|
||||
var newCell = new Cell(cell.row, cell.col, cell.live);
|
||||
if (count < 2 || count > 3)
|
||||
newCell.live = false;
|
||||
else if (count == 3)
|
||||
newCell.live = true;
|
||||
return newCell;
|
||||
}
|
||||
function countNeighbors(cell) {
|
||||
var neighbors = 0;
|
||||
for (var row = -1; row <= 1; row++) {
|
||||
for (var col = -1; col <= 1; col++) {
|
||||
if (row == 0 && col == 0)
|
||||
continue;
|
||||
if (isAlive(cell.row + row, cell.col + col)) {
|
||||
neighbors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return neighbors;
|
||||
}
|
||||
function isAlive(row, col) {
|
||||
// todo - need to guard with world[row] exists?
|
||||
if (row < 0 || col < 0 || row >= gridSize || col >= gridSize)
|
||||
return false;
|
||||
return world[row][col].live;
|
||||
}
|
||||
function travelWorld(callback) {
|
||||
var result = [];
|
||||
for (var row = 0; row < gridSize; row++) {
|
||||
var rowData = [];
|
||||
for (var col = 0; col < gridSize; col++) {
|
||||
rowData.push(callback(new Cell(row, col, false)));
|
||||
}
|
||||
result.push(rowData);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function draw(cell) {
|
||||
if (context == null)
|
||||
context = createDrawingContext();
|
||||
if (cellSize == 0)
|
||||
cellSize = canvasSize / gridSize;
|
||||
context.strokeStyle = lineColor;
|
||||
context.strokeRect(cell.row * cellSize, cell.col * cellSize, cellSize, cellSize);
|
||||
context.fillStyle = cell.live ? liveColor : deadColor;
|
||||
context.fillRect(cell.row * cellSize, cell.col * cellSize, cellSize, cellSize);
|
||||
}
|
||||
function createDrawingContext() {
|
||||
var canvas = document.getElementById('conway-canvas');
|
||||
if (canvas == null) {
|
||||
canvas = document.createElement('canvas');
|
||||
canvas.id = "conway-canvas";
|
||||
canvas.width = canvasSize;
|
||||
canvas.height = canvasSize;
|
||||
document.body.appendChild(canvas);
|
||||
}
|
||||
return canvas.getContext('2d');
|
||||
}
|
||||
});
|
||||
})(Conway || (Conway = {}));
|
||||
var game = new Conway.GameOfLife();
|
||||
@@ -0,0 +1,38 @@
|
||||
'use strict';
|
||||
var Workforce;
|
||||
(function (Workforce) {
|
||||
var Employee = (function () {
|
||||
function Employee() {
|
||||
}
|
||||
return Employee;
|
||||
})();
|
||||
(property);
|
||||
name: string, property;
|
||||
basepay: number;
|
||||
implements;
|
||||
IEmployee;
|
||||
{
|
||||
name;
|
||||
basepay;
|
||||
}
|
||||
var SalesEmployee = (function () {
|
||||
function SalesEmployee() {
|
||||
}
|
||||
return SalesEmployee;
|
||||
})();
|
||||
();
|
||||
Employee(name, basepay);
|
||||
{
|
||||
function calculatePay() {
|
||||
var multiplier = (document.getElementById("mult")), as = any, value;
|
||||
return _super.calculatePay.call(this) * multiplier + bonus;
|
||||
}
|
||||
}
|
||||
var employee = new Employee('Bob', 1000);
|
||||
var salesEmployee = new SalesEmployee('Jim', 800, 400);
|
||||
salesEmployee.calclatePay(); // error: No member 'calclatePay' on SalesEmployee
|
||||
})(Workforce || (Workforce = {}));
|
||||
extern;
|
||||
var $;
|
||||
var s = Workforce.salesEmployee.calculatePay();
|
||||
$('#results').text(s);
|
||||
@@ -0,0 +1,24 @@
|
||||
'use strict';
|
||||
var M;
|
||||
(function (M) {
|
||||
var C = (function () {
|
||||
function C() {
|
||||
}
|
||||
return C;
|
||||
})();
|
||||
(function (x, property, number) {
|
||||
if (property === undefined) { property = w; }
|
||||
var local = 1;
|
||||
// unresolved symbol because x is local
|
||||
//self.x++;
|
||||
self.w--; // ok because w is a property
|
||||
property;
|
||||
f = function (y) {
|
||||
return y + x + local + w + self.w;
|
||||
};
|
||||
function sum(z) {
|
||||
return z + f(z) + w + self.w;
|
||||
}
|
||||
});
|
||||
})(M || (M = {}));
|
||||
var c = new M.C(12, 5);
|
||||
121
lib/vscode/src/vs/base/test/node/pfs/fixtures/index.html
Normal file
121
lib/vscode/src/vs/base/test/node/pfs/fixtures/index.html
Normal file
@@ -0,0 +1,121 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head id='headID'>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>Strada </title>
|
||||
<link href="site.css" rel="stylesheet" type="text/css" />
|
||||
<script src="jquery-1.4.1.js"></script>
|
||||
<script src="../compiler/dtree.js" type="text/javascript"></script>
|
||||
<script src="../compiler/typescript.js" type="text/javascript"></script>
|
||||
<script type="text/javascript">
|
||||
|
||||
// Compile strada source into resulting javascript
|
||||
function compile(prog, libText) {
|
||||
var outfile = {
|
||||
source: "",
|
||||
Write: function (s) { this.source += s; },
|
||||
WriteLine: function (s) { this.source += s + "\r"; },
|
||||
}
|
||||
|
||||
var parseErrors = []
|
||||
|
||||
var compiler=new Tools.TypeScriptCompiler(outfile,true);
|
||||
compiler.setErrorCallback(function(start,len, message) { parseErrors.push({start:start, len:len, message:message}); });
|
||||
compiler.addUnit(libText,"lib.ts");
|
||||
compiler.addUnit(prog,"input.ts");
|
||||
compiler.typeCheck();
|
||||
compiler.emit();
|
||||
|
||||
if(parseErrors.length > 0 ) {
|
||||
//throw new Error(parseErrors);
|
||||
}
|
||||
|
||||
while(outfile.source[0] == '/' && outfile.source[1] == '/' && outfile.source[2] == ' ') {
|
||||
outfile.source = outfile.source.slice(outfile.source.indexOf('\r')+1);
|
||||
}
|
||||
var errorPrefix = "";
|
||||
for(var i = 0;i<parseErrors.length;i++) {
|
||||
errorPrefix += "// Error: (" + parseErrors[i].start + "," + parseErrors[i].len + ") " + parseErrors[i].message + "\r";
|
||||
}
|
||||
|
||||
return errorPrefix + outfile.source;
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
|
||||
var libText = "";
|
||||
$.get("../compiler/lib.ts", function(newLibText) {
|
||||
libText = newLibText;
|
||||
});
|
||||
|
||||
|
||||
// execute the javascript in the compiledOutput pane
|
||||
function execute() {
|
||||
$('#compilation').text("Running...");
|
||||
var txt = $('#compiledOutput').val();
|
||||
var res;
|
||||
try {
|
||||
var ret = eval(txt);
|
||||
res = "Ran successfully!";
|
||||
} catch(e) {
|
||||
res = "Exception thrown: " + e;
|
||||
}
|
||||
$('#compilation').text(String(res));
|
||||
}
|
||||
|
||||
// recompile the stradaSrc and populate the compiledOutput pane
|
||||
function srcUpdated() {
|
||||
var newText = $('#stradaSrc').val();
|
||||
var compiledSource;
|
||||
try {
|
||||
compiledSource = compile(newText, libText);
|
||||
} catch (e) {
|
||||
compiledSource = "//Parse error"
|
||||
for(var i in e)
|
||||
compiledSource += "\r// " + e[i];
|
||||
}
|
||||
$('#compiledOutput').val(compiledSource);
|
||||
}
|
||||
|
||||
// Populate the stradaSrc pane with one of the built in samples
|
||||
function exampleSelectionChanged() {
|
||||
var examples = document.getElementById('examples');
|
||||
var selectedExample = examples.options[examples.selectedIndex].value;
|
||||
if (selectedExample != "") {
|
||||
$.get('examples/' + selectedExample, function (srcText) {
|
||||
$('#stradaSrc').val(srcText);
|
||||
setTimeout(srcUpdated,100);
|
||||
}, function (err) {
|
||||
console.log(err);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>TypeScript</h1>
|
||||
<br />
|
||||
<select id="examples" onchange='exampleSelectionChanged()'>
|
||||
<option value="">Select...</option>
|
||||
<option value="small.ts">Small</option>
|
||||
<option value="employee.ts">Employees</option>
|
||||
<option value="conway.ts">Conway Game of Life</option>
|
||||
<option value="typescript.ts">TypeScript Compiler</option>
|
||||
</select>
|
||||
|
||||
<div>
|
||||
<textarea id='stradaSrc' rows='40' cols='80' onchange='srcUpdated()' onkeyup='srcUpdated()' spellcheck="false">
|
||||
//Type your TypeScript here...
|
||||
</textarea>
|
||||
<textarea id='compiledOutput' rows='40' cols='80' spellcheck="false">
|
||||
//Compiled code will show up here...
|
||||
</textarea>
|
||||
<br />
|
||||
<button onclick='execute()'/>Run</button>
|
||||
<div id='compilation'>Press 'run' to execute code...</div>
|
||||
<div id='results'>...write your results into #results...</div>
|
||||
</div>
|
||||
<div id='bod' style='display:none'></div>
|
||||
</body>
|
||||
</html>
|
||||
40
lib/vscode/src/vs/base/test/node/pfs/fixtures/site.css
Normal file
40
lib/vscode/src/vs/base/test/node/pfs/fixtures/site.css
Normal file
@@ -0,0 +1,40 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/*----------------------------------------------------------
|
||||
The base color for this template is #5c87b2. If you'd like
|
||||
to use a different color start by replacing all instances of
|
||||
#5c87b2 with your new color.
|
||||
----------------------------------------------------------*/
|
||||
body
|
||||
{
|
||||
background-color: #5c87b2;
|
||||
font-size: .75em;
|
||||
font-family: Segoe UI, Verdana, Helvetica, Sans-Serif;
|
||||
margin: 8px;
|
||||
padding: 0;
|
||||
color: #696969;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6
|
||||
{
|
||||
color: #000;
|
||||
font-size: 40px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
textarea
|
||||
{
|
||||
font-family: Consolas
|
||||
}
|
||||
|
||||
#results
|
||||
{
|
||||
margin-top: 2em;
|
||||
margin-left: 2em;
|
||||
color: black;
|
||||
font-size: medium;
|
||||
}
|
||||
|
||||
480
lib/vscode/src/vs/base/test/node/pfs/pfs.test.ts
Normal file
480
lib/vscode/src/vs/base/test/node/pfs/pfs.test.ts
Normal file
@@ -0,0 +1,480 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import * as os from 'os';
|
||||
import * as path from 'vs/base/common/path';
|
||||
import * as fs from 'fs';
|
||||
import * as uuid from 'vs/base/common/uuid';
|
||||
import * as pfs from 'vs/base/node/pfs';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
import { getPathFromAmdModule } from 'vs/base/common/amd';
|
||||
import { isWindows } from 'vs/base/common/platform';
|
||||
import { canNormalize } from 'vs/base/common/normalization';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
|
||||
suite('PFS', function () {
|
||||
|
||||
// Given issues such as https://github.com/microsoft/vscode/issues/84066
|
||||
// we see random test failures when accessing the native file system. To
|
||||
// diagnose further, we retry node.js file access tests up to 3 times to
|
||||
// rule out any random disk issue.
|
||||
this.retries(3);
|
||||
|
||||
test('writeFile', async () => {
|
||||
const id = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
||||
const newDir = path.join(parentDir, 'pfs', id);
|
||||
const testFile = path.join(newDir, 'writefile.txt');
|
||||
|
||||
await pfs.mkdirp(newDir, 493);
|
||||
assert.ok(fs.existsSync(newDir));
|
||||
|
||||
await pfs.writeFile(testFile, 'Hello World', (null!));
|
||||
assert.equal(fs.readFileSync(testFile), 'Hello World');
|
||||
|
||||
await pfs.rimraf(parentDir, pfs.RimRafMode.MOVE);
|
||||
});
|
||||
|
||||
test('writeFile - parallel write on different files works', async () => {
|
||||
const id = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
||||
const newDir = path.join(parentDir, 'pfs', id);
|
||||
const testFile1 = path.join(newDir, 'writefile1.txt');
|
||||
const testFile2 = path.join(newDir, 'writefile2.txt');
|
||||
const testFile3 = path.join(newDir, 'writefile3.txt');
|
||||
const testFile4 = path.join(newDir, 'writefile4.txt');
|
||||
const testFile5 = path.join(newDir, 'writefile5.txt');
|
||||
|
||||
await pfs.mkdirp(newDir, 493);
|
||||
assert.ok(fs.existsSync(newDir));
|
||||
|
||||
await Promise.all([
|
||||
pfs.writeFile(testFile1, 'Hello World 1', (null!)),
|
||||
pfs.writeFile(testFile2, 'Hello World 2', (null!)),
|
||||
pfs.writeFile(testFile3, 'Hello World 3', (null!)),
|
||||
pfs.writeFile(testFile4, 'Hello World 4', (null!)),
|
||||
pfs.writeFile(testFile5, 'Hello World 5', (null!))
|
||||
]);
|
||||
assert.equal(fs.readFileSync(testFile1), 'Hello World 1');
|
||||
assert.equal(fs.readFileSync(testFile2), 'Hello World 2');
|
||||
assert.equal(fs.readFileSync(testFile3), 'Hello World 3');
|
||||
assert.equal(fs.readFileSync(testFile4), 'Hello World 4');
|
||||
assert.equal(fs.readFileSync(testFile5), 'Hello World 5');
|
||||
|
||||
await pfs.rimraf(parentDir, pfs.RimRafMode.MOVE);
|
||||
});
|
||||
|
||||
test('writeFile - parallel write on same files works and is sequentalized', async () => {
|
||||
const id = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
||||
const newDir = path.join(parentDir, 'pfs', id);
|
||||
const testFile = path.join(newDir, 'writefile.txt');
|
||||
|
||||
await pfs.mkdirp(newDir, 493);
|
||||
assert.ok(fs.existsSync(newDir));
|
||||
|
||||
await Promise.all([
|
||||
pfs.writeFile(testFile, 'Hello World 1', undefined),
|
||||
pfs.writeFile(testFile, 'Hello World 2', undefined),
|
||||
timeout(10).then(() => pfs.writeFile(testFile, 'Hello World 3', undefined)),
|
||||
pfs.writeFile(testFile, 'Hello World 4', undefined),
|
||||
timeout(10).then(() => pfs.writeFile(testFile, 'Hello World 5', undefined))
|
||||
]);
|
||||
assert.equal(fs.readFileSync(testFile), 'Hello World 5');
|
||||
|
||||
await pfs.rimraf(parentDir, pfs.RimRafMode.MOVE);
|
||||
});
|
||||
|
||||
test('rimraf - simple - unlink', async () => {
|
||||
const id = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
||||
const newDir = path.join(parentDir, 'pfs', id);
|
||||
|
||||
await pfs.mkdirp(newDir, 493);
|
||||
fs.writeFileSync(path.join(newDir, 'somefile.txt'), 'Contents');
|
||||
fs.writeFileSync(path.join(newDir, 'someOtherFile.txt'), 'Contents');
|
||||
|
||||
await pfs.rimraf(newDir);
|
||||
assert.ok(!fs.existsSync(newDir));
|
||||
});
|
||||
|
||||
test('rimraf - simple - move', async () => {
|
||||
const id = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
||||
const newDir = path.join(parentDir, 'pfs', id);
|
||||
|
||||
await pfs.mkdirp(newDir, 493);
|
||||
fs.writeFileSync(path.join(newDir, 'somefile.txt'), 'Contents');
|
||||
fs.writeFileSync(path.join(newDir, 'someOtherFile.txt'), 'Contents');
|
||||
|
||||
await pfs.rimraf(newDir, pfs.RimRafMode.MOVE);
|
||||
assert.ok(!fs.existsSync(newDir));
|
||||
});
|
||||
|
||||
test('rimraf - recursive folder structure - unlink', async () => {
|
||||
const id = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
||||
const newDir = path.join(parentDir, 'pfs', id);
|
||||
|
||||
await pfs.mkdirp(newDir, 493);
|
||||
fs.writeFileSync(path.join(newDir, 'somefile.txt'), 'Contents');
|
||||
fs.writeFileSync(path.join(newDir, 'someOtherFile.txt'), 'Contents');
|
||||
fs.mkdirSync(path.join(newDir, 'somefolder'));
|
||||
fs.writeFileSync(path.join(newDir, 'somefolder', 'somefile.txt'), 'Contents');
|
||||
|
||||
await pfs.rimraf(newDir);
|
||||
assert.ok(!fs.existsSync(newDir));
|
||||
});
|
||||
|
||||
test('rimraf - recursive folder structure - move', async () => {
|
||||
const id = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
||||
const newDir = path.join(parentDir, 'pfs', id);
|
||||
|
||||
await pfs.mkdirp(newDir, 493);
|
||||
fs.writeFileSync(path.join(newDir, 'somefile.txt'), 'Contents');
|
||||
fs.writeFileSync(path.join(newDir, 'someOtherFile.txt'), 'Contents');
|
||||
fs.mkdirSync(path.join(newDir, 'somefolder'));
|
||||
fs.writeFileSync(path.join(newDir, 'somefolder', 'somefile.txt'), 'Contents');
|
||||
|
||||
await pfs.rimraf(newDir, pfs.RimRafMode.MOVE);
|
||||
assert.ok(!fs.existsSync(newDir));
|
||||
});
|
||||
|
||||
test('rimraf - simple ends with dot - move', async () => {
|
||||
const id = `${uuid.generateUuid()}.`;
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
||||
const newDir = path.join(parentDir, 'pfs', id);
|
||||
|
||||
await pfs.mkdirp(newDir, 493);
|
||||
fs.writeFileSync(path.join(newDir, 'somefile.txt'), 'Contents');
|
||||
fs.writeFileSync(path.join(newDir, 'someOtherFile.txt'), 'Contents');
|
||||
|
||||
await pfs.rimraf(newDir, pfs.RimRafMode.MOVE);
|
||||
assert.ok(!fs.existsSync(newDir));
|
||||
});
|
||||
|
||||
test('rimraf - simple ends with dot slash/backslash - move', async () => {
|
||||
const id = `${uuid.generateUuid()}.`;
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
||||
const newDir = path.join(parentDir, 'pfs', id);
|
||||
|
||||
await pfs.mkdirp(newDir, 493);
|
||||
fs.writeFileSync(path.join(newDir, 'somefile.txt'), 'Contents');
|
||||
fs.writeFileSync(path.join(newDir, 'someOtherFile.txt'), 'Contents');
|
||||
|
||||
await pfs.rimraf(`${newDir}${path.sep}`, pfs.RimRafMode.MOVE);
|
||||
assert.ok(!fs.existsSync(newDir));
|
||||
});
|
||||
|
||||
test('rimrafSync - swallows file not found error', function () {
|
||||
const id = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
||||
const newDir = path.join(parentDir, 'pfs', id);
|
||||
|
||||
pfs.rimrafSync(newDir);
|
||||
|
||||
assert.ok(!fs.existsSync(newDir));
|
||||
});
|
||||
|
||||
test('rimrafSync - simple', async () => {
|
||||
const id = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
||||
const newDir = path.join(parentDir, 'pfs', id);
|
||||
|
||||
await pfs.mkdirp(newDir, 493);
|
||||
|
||||
fs.writeFileSync(path.join(newDir, 'somefile.txt'), 'Contents');
|
||||
fs.writeFileSync(path.join(newDir, 'someOtherFile.txt'), 'Contents');
|
||||
|
||||
pfs.rimrafSync(newDir);
|
||||
|
||||
assert.ok(!fs.existsSync(newDir));
|
||||
});
|
||||
|
||||
test('rimrafSync - recursive folder structure', async () => {
|
||||
const id = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
||||
const newDir = path.join(parentDir, 'pfs', id);
|
||||
|
||||
await pfs.mkdirp(newDir, 493);
|
||||
fs.writeFileSync(path.join(newDir, 'somefile.txt'), 'Contents');
|
||||
fs.writeFileSync(path.join(newDir, 'someOtherFile.txt'), 'Contents');
|
||||
|
||||
fs.mkdirSync(path.join(newDir, 'somefolder'));
|
||||
fs.writeFileSync(path.join(newDir, 'somefolder', 'somefile.txt'), 'Contents');
|
||||
|
||||
pfs.rimrafSync(newDir);
|
||||
|
||||
assert.ok(!fs.existsSync(newDir));
|
||||
});
|
||||
|
||||
test('moveIgnoreError', async () => {
|
||||
const id = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
||||
const newDir = path.join(parentDir, 'pfs', id);
|
||||
|
||||
await pfs.mkdirp(newDir, 493);
|
||||
try {
|
||||
await pfs.renameIgnoreError(path.join(newDir, 'foo'), path.join(newDir, 'bar'));
|
||||
return pfs.rimraf(parentDir, pfs.RimRafMode.MOVE);
|
||||
}
|
||||
catch (error) {
|
||||
assert.fail(error);
|
||||
}
|
||||
});
|
||||
|
||||
test('copy, move and delete', async () => {
|
||||
const id = uuid.generateUuid();
|
||||
const id2 = uuid.generateUuid();
|
||||
const sourceDir = getPathFromAmdModule(require, './fixtures');
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', 'pfs');
|
||||
const targetDir = path.join(parentDir, id);
|
||||
const targetDir2 = path.join(parentDir, id2);
|
||||
|
||||
await pfs.copy(sourceDir, targetDir);
|
||||
|
||||
assert.ok(fs.existsSync(targetDir));
|
||||
assert.ok(fs.existsSync(path.join(targetDir, 'index.html')));
|
||||
assert.ok(fs.existsSync(path.join(targetDir, 'site.css')));
|
||||
assert.ok(fs.existsSync(path.join(targetDir, 'examples')));
|
||||
assert.ok(fs.statSync(path.join(targetDir, 'examples')).isDirectory());
|
||||
assert.ok(fs.existsSync(path.join(targetDir, 'examples', 'small.jxs')));
|
||||
|
||||
await pfs.move(targetDir, targetDir2);
|
||||
|
||||
assert.ok(!fs.existsSync(targetDir));
|
||||
assert.ok(fs.existsSync(targetDir2));
|
||||
assert.ok(fs.existsSync(path.join(targetDir2, 'index.html')));
|
||||
assert.ok(fs.existsSync(path.join(targetDir2, 'site.css')));
|
||||
assert.ok(fs.existsSync(path.join(targetDir2, 'examples')));
|
||||
assert.ok(fs.statSync(path.join(targetDir2, 'examples')).isDirectory());
|
||||
assert.ok(fs.existsSync(path.join(targetDir2, 'examples', 'small.jxs')));
|
||||
|
||||
await pfs.move(path.join(targetDir2, 'index.html'), path.join(targetDir2, 'index_moved.html'));
|
||||
|
||||
assert.ok(!fs.existsSync(path.join(targetDir2, 'index.html')));
|
||||
assert.ok(fs.existsSync(path.join(targetDir2, 'index_moved.html')));
|
||||
|
||||
await pfs.rimraf(parentDir, pfs.RimRafMode.MOVE);
|
||||
|
||||
assert.ok(!fs.existsSync(parentDir));
|
||||
});
|
||||
|
||||
test('mkdirp', async () => {
|
||||
const id = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
||||
const newDir = path.join(parentDir, 'pfs', id);
|
||||
|
||||
await pfs.mkdirp(newDir, 493);
|
||||
|
||||
assert.ok(fs.existsSync(newDir));
|
||||
|
||||
return pfs.rimraf(parentDir, pfs.RimRafMode.MOVE);
|
||||
});
|
||||
|
||||
test('readDirsInDir', async () => {
|
||||
const id = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
||||
const newDir = path.join(parentDir, 'pfs', id);
|
||||
|
||||
await pfs.mkdirp(newDir, 493);
|
||||
|
||||
fs.mkdirSync(path.join(newDir, 'somefolder1'));
|
||||
fs.mkdirSync(path.join(newDir, 'somefolder2'));
|
||||
fs.mkdirSync(path.join(newDir, 'somefolder3'));
|
||||
fs.writeFileSync(path.join(newDir, 'somefile.txt'), 'Contents');
|
||||
fs.writeFileSync(path.join(newDir, 'someOtherFile.txt'), 'Contents');
|
||||
|
||||
const result = await pfs.readDirsInDir(newDir);
|
||||
assert.equal(result.length, 3);
|
||||
assert.ok(result.indexOf('somefolder1') !== -1);
|
||||
assert.ok(result.indexOf('somefolder2') !== -1);
|
||||
assert.ok(result.indexOf('somefolder3') !== -1);
|
||||
|
||||
await pfs.rimraf(newDir);
|
||||
});
|
||||
|
||||
test('stat link', async () => {
|
||||
if (isWindows) {
|
||||
return; // Symlinks are not the same on win, and we can not create them programitically without admin privileges
|
||||
}
|
||||
|
||||
const id1 = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id1);
|
||||
const directory = path.join(parentDir, 'pfs', id1);
|
||||
|
||||
const id2 = uuid.generateUuid();
|
||||
const symbolicLink = path.join(parentDir, 'pfs', id2);
|
||||
|
||||
await pfs.mkdirp(directory, 493);
|
||||
|
||||
fs.symlinkSync(directory, symbolicLink);
|
||||
|
||||
let statAndIsLink = await pfs.statLink(directory);
|
||||
assert.ok(!statAndIsLink?.symbolicLink);
|
||||
|
||||
statAndIsLink = await pfs.statLink(symbolicLink);
|
||||
assert.ok(statAndIsLink?.symbolicLink);
|
||||
assert.ok(!statAndIsLink?.symbolicLink?.dangling);
|
||||
|
||||
pfs.rimrafSync(directory);
|
||||
});
|
||||
|
||||
test('stat link (non existing target)', async () => {
|
||||
if (isWindows) {
|
||||
return; // Symlinks are not the same on win, and we can not create them programitically without admin privileges
|
||||
}
|
||||
|
||||
const id1 = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id1);
|
||||
const directory = path.join(parentDir, 'pfs', id1);
|
||||
|
||||
const id2 = uuid.generateUuid();
|
||||
const symbolicLink = path.join(parentDir, 'pfs', id2);
|
||||
|
||||
await pfs.mkdirp(directory, 493);
|
||||
|
||||
fs.symlinkSync(directory, symbolicLink);
|
||||
|
||||
pfs.rimrafSync(directory);
|
||||
|
||||
const statAndIsLink = await pfs.statLink(symbolicLink);
|
||||
assert.ok(statAndIsLink?.symbolicLink);
|
||||
assert.ok(statAndIsLink?.symbolicLink?.dangling);
|
||||
});
|
||||
|
||||
test('readdir', async () => {
|
||||
if (canNormalize && typeof process.versions['electron'] !== 'undefined' /* needs electron */) {
|
||||
const id = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
||||
const newDir = path.join(parentDir, 'pfs', id, 'öäü');
|
||||
|
||||
await pfs.mkdirp(newDir, 493);
|
||||
|
||||
assert.ok(fs.existsSync(newDir));
|
||||
|
||||
const children = await pfs.readdir(path.join(parentDir, 'pfs', id));
|
||||
assert.equal(children.some(n => n === 'öäü'), true); // Mac always converts to NFD, so
|
||||
|
||||
await pfs.rimraf(parentDir);
|
||||
}
|
||||
});
|
||||
|
||||
test('readdirWithFileTypes', async () => {
|
||||
if (canNormalize && typeof process.versions['electron'] !== 'undefined' /* needs electron */) {
|
||||
const id = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
||||
const testDir = path.join(parentDir, 'pfs', id);
|
||||
|
||||
const newDir = path.join(testDir, 'öäü');
|
||||
await pfs.mkdirp(newDir, 493);
|
||||
|
||||
await pfs.writeFile(path.join(testDir, 'somefile.txt'), 'contents');
|
||||
|
||||
assert.ok(fs.existsSync(newDir));
|
||||
|
||||
const children = await pfs.readdirWithFileTypes(testDir);
|
||||
|
||||
assert.equal(children.some(n => n.name === 'öäü'), true); // Mac always converts to NFD, so
|
||||
assert.equal(children.some(n => n.isDirectory()), true);
|
||||
|
||||
assert.equal(children.some(n => n.name === 'somefile.txt'), true);
|
||||
assert.equal(children.some(n => n.isFile()), true);
|
||||
|
||||
await pfs.rimraf(parentDir);
|
||||
}
|
||||
});
|
||||
|
||||
test('writeFile (string)', async () => {
|
||||
const smallData = 'Hello World';
|
||||
const bigData = (new Array(100 * 1024)).join('Large String\n');
|
||||
|
||||
return testWriteFileAndFlush(smallData, smallData, bigData, bigData);
|
||||
});
|
||||
|
||||
test('writeFile (Buffer)', async () => {
|
||||
const smallData = 'Hello World';
|
||||
const bigData = (new Array(100 * 1024)).join('Large String\n');
|
||||
|
||||
return testWriteFileAndFlush(Buffer.from(smallData), smallData, Buffer.from(bigData), bigData);
|
||||
});
|
||||
|
||||
test('writeFile (UInt8Array)', async () => {
|
||||
const smallData = 'Hello World';
|
||||
const bigData = (new Array(100 * 1024)).join('Large String\n');
|
||||
|
||||
return testWriteFileAndFlush(VSBuffer.fromString(smallData).buffer, smallData, VSBuffer.fromString(bigData).buffer, bigData);
|
||||
});
|
||||
|
||||
async function testWriteFileAndFlush(
|
||||
smallData: string | Buffer | Uint8Array,
|
||||
smallDataValue: string,
|
||||
bigData: string | Buffer | Uint8Array,
|
||||
bigDataValue: string
|
||||
): Promise<void> {
|
||||
const id = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
||||
const newDir = path.join(parentDir, 'pfs', id);
|
||||
const testFile = path.join(newDir, 'flushed.txt');
|
||||
|
||||
await pfs.mkdirp(newDir, 493);
|
||||
assert.ok(fs.existsSync(newDir));
|
||||
|
||||
await pfs.writeFile(testFile, smallData);
|
||||
assert.equal(fs.readFileSync(testFile), smallDataValue);
|
||||
|
||||
await pfs.writeFile(testFile, bigData);
|
||||
assert.equal(fs.readFileSync(testFile), bigDataValue);
|
||||
|
||||
await pfs.rimraf(parentDir);
|
||||
}
|
||||
|
||||
test('writeFile (string, error handling)', async () => {
|
||||
const id = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
||||
const newDir = path.join(parentDir, 'pfs', id);
|
||||
const testFile = path.join(newDir, 'flushed.txt');
|
||||
|
||||
await pfs.mkdirp(newDir, 493);
|
||||
|
||||
assert.ok(fs.existsSync(newDir));
|
||||
|
||||
fs.mkdirSync(testFile); // this will trigger an error because testFile is now a directory!
|
||||
|
||||
let expectedError: Error | undefined;
|
||||
try {
|
||||
await pfs.writeFile(testFile, 'Hello World');
|
||||
} catch (error) {
|
||||
expectedError = error;
|
||||
}
|
||||
|
||||
assert.ok(expectedError);
|
||||
|
||||
await pfs.rimraf(parentDir);
|
||||
});
|
||||
|
||||
test('writeFileSync', async () => {
|
||||
const id = uuid.generateUuid();
|
||||
const parentDir = path.join(os.tmpdir(), 'vsctests', id);
|
||||
const newDir = path.join(parentDir, 'pfs', id);
|
||||
const testFile = path.join(newDir, 'flushed.txt');
|
||||
|
||||
await pfs.mkdirp(newDir, 493);
|
||||
|
||||
assert.ok(fs.existsSync(newDir));
|
||||
|
||||
pfs.writeFileSync(testFile, 'Hello World');
|
||||
assert.equal(fs.readFileSync(testFile), 'Hello World');
|
||||
|
||||
const largeString = (new Array(100 * 1024)).join('Large String\n');
|
||||
|
||||
pfs.writeFileSync(testFile, largeString);
|
||||
assert.equal(fs.readFileSync(testFile), largeString);
|
||||
|
||||
await pfs.rimraf(parentDir);
|
||||
});
|
||||
});
|
||||
36
lib/vscode/src/vs/base/test/node/port.test.ts
Normal file
36
lib/vscode/src/vs/base/test/node/port.test.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import * as net from 'net';
|
||||
import * as ports from 'vs/base/node/ports';
|
||||
|
||||
suite('Ports', () => {
|
||||
test('Finds a free port (no timeout)', function (done) {
|
||||
this.timeout(1000 * 10); // higher timeout for this test
|
||||
|
||||
if (process.env['VSCODE_PID']) {
|
||||
return done(); // this test fails when run from within VS Code
|
||||
}
|
||||
|
||||
// get an initial freeport >= 7000
|
||||
ports.findFreePort(7000, 100, 300000).then(initialPort => {
|
||||
assert.ok(initialPort >= 7000);
|
||||
|
||||
// create a server to block this port
|
||||
const server = net.createServer();
|
||||
server.listen(initialPort, undefined, undefined, () => {
|
||||
|
||||
// once listening, find another free port and assert that the port is different from the opened one
|
||||
ports.findFreePort(7000, 50, 300000).then(freePort => {
|
||||
assert.ok(freePort >= 7000 && freePort !== initialPort);
|
||||
server.close();
|
||||
|
||||
done();
|
||||
}, err => done(err));
|
||||
});
|
||||
}, err => done(err));
|
||||
});
|
||||
});
|
||||
14
lib/vscode/src/vs/base/test/node/processes/fixtures/fork.ts
Normal file
14
lib/vscode/src/vs/base/test/node/processes/fixtures/fork.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as processes from 'vs/base/node/processes';
|
||||
|
||||
const sender = processes.createQueuedSender(<any>process);
|
||||
|
||||
process.on('message', msg => {
|
||||
sender.send(msg);
|
||||
});
|
||||
|
||||
sender.send('ready');
|
||||
@@ -0,0 +1,17 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as processes from 'vs/base/node/processes';
|
||||
|
||||
const sender = processes.createQueuedSender(<any>process);
|
||||
|
||||
process.on('message', msg => {
|
||||
sender.send(msg);
|
||||
sender.send(msg);
|
||||
sender.send(msg);
|
||||
sender.send('done');
|
||||
});
|
||||
|
||||
sender.send('ready');
|
||||
87
lib/vscode/src/vs/base/test/node/processes/processes.test.ts
Normal file
87
lib/vscode/src/vs/base/test/node/processes/processes.test.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import * as cp from 'child_process';
|
||||
import * as objects from 'vs/base/common/objects';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import * as processes from 'vs/base/node/processes';
|
||||
import { getPathFromAmdModule } from 'vs/base/common/amd';
|
||||
|
||||
function fork(id: string): cp.ChildProcess {
|
||||
const opts: any = {
|
||||
env: objects.mixin(objects.deepClone(process.env), {
|
||||
AMD_ENTRYPOINT: id,
|
||||
PIPE_LOGGING: 'true',
|
||||
VERBOSE_LOGGING: true
|
||||
})
|
||||
};
|
||||
|
||||
return cp.fork(getPathFromAmdModule(require, 'bootstrap-fork'), ['--type=processTests'], opts);
|
||||
}
|
||||
|
||||
suite('Processes', () => {
|
||||
test('buffered sending - simple data', function (done: () => void) {
|
||||
if (process.env['VSCODE_PID']) {
|
||||
return done(); // this test fails when run from within VS Code
|
||||
}
|
||||
|
||||
const child = fork('vs/base/test/node/processes/fixtures/fork');
|
||||
const sender = processes.createQueuedSender(child);
|
||||
|
||||
let counter = 0;
|
||||
|
||||
const msg1 = 'Hello One';
|
||||
const msg2 = 'Hello Two';
|
||||
const msg3 = 'Hello Three';
|
||||
|
||||
child.on('message', msgFromChild => {
|
||||
if (msgFromChild === 'ready') {
|
||||
sender.send(msg1);
|
||||
sender.send(msg2);
|
||||
sender.send(msg3);
|
||||
} else {
|
||||
counter++;
|
||||
|
||||
if (counter === 1) {
|
||||
assert.equal(msgFromChild, msg1);
|
||||
} else if (counter === 2) {
|
||||
assert.equal(msgFromChild, msg2);
|
||||
} else if (counter === 3) {
|
||||
assert.equal(msgFromChild, msg3);
|
||||
|
||||
child.kill();
|
||||
done();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test('buffered sending - lots of data (potential deadlock on win32)', function (done: () => void) {
|
||||
if (!platform.isWindows || process.env['VSCODE_PID']) {
|
||||
return done(); // test is only relevant for Windows and seems to crash randomly on some Linux builds
|
||||
}
|
||||
|
||||
const child = fork('vs/base/test/node/processes/fixtures/fork_large');
|
||||
const sender = processes.createQueuedSender(child);
|
||||
|
||||
const largeObj = Object.create(null);
|
||||
for (let i = 0; i < 10000; i++) {
|
||||
largeObj[i] = 'some data';
|
||||
}
|
||||
|
||||
const msg = JSON.stringify(largeObj);
|
||||
child.on('message', msgFromChild => {
|
||||
if (msgFromChild === 'ready') {
|
||||
sender.send(msg);
|
||||
sender.send(msg);
|
||||
sender.send(msg);
|
||||
} else if (msgFromChild === 'done') {
|
||||
child.kill();
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
11
lib/vscode/src/vs/base/test/node/testUtils.ts
Normal file
11
lib/vscode/src/vs/base/test/node/testUtils.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { join } from 'vs/base/common/path';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
|
||||
export function getRandomTestPath(tmpdir: string, ...segments: string[]): string {
|
||||
return join(tmpdir, ...segments, generateUuid());
|
||||
}
|
||||
3061
lib/vscode/src/vs/base/test/node/uri.test.data.txt
Normal file
3061
lib/vscode/src/vs/base/test/node/uri.test.data.txt
Normal file
File diff suppressed because it is too large
Load Diff
61
lib/vscode/src/vs/base/test/node/uri.test.perf.ts
Normal file
61
lib/vscode/src/vs/base/test/node/uri.test.perf.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { readFileSync } from 'fs';
|
||||
import { getPathFromAmdModule } from 'vs/base/common/amd';
|
||||
|
||||
suite('URI - perf', function () {
|
||||
|
||||
let manyFileUris: URI[];
|
||||
setup(function () {
|
||||
manyFileUris = [];
|
||||
let data = readFileSync(getPathFromAmdModule(require, './uri.test.data.txt')).toString();
|
||||
let lines = data.split('\n');
|
||||
for (let line of lines) {
|
||||
manyFileUris.push(URI.file(line));
|
||||
}
|
||||
});
|
||||
|
||||
function perfTest(name: string, callback: Function) {
|
||||
test(name, _done => {
|
||||
let t1 = Date.now();
|
||||
callback();
|
||||
let d = Date.now() - t1;
|
||||
console.log(`${name} took ${d}ms (${(d / manyFileUris.length).toPrecision(3)} ms/uri)`);
|
||||
_done();
|
||||
});
|
||||
}
|
||||
|
||||
perfTest('toString', function () {
|
||||
for (const uri of manyFileUris) {
|
||||
let data = uri.toString();
|
||||
assert.ok(data);
|
||||
}
|
||||
});
|
||||
|
||||
perfTest('toString(skipEncoding)', function () {
|
||||
for (const uri of manyFileUris) {
|
||||
let data = uri.toString(true);
|
||||
assert.ok(data);
|
||||
}
|
||||
});
|
||||
|
||||
perfTest('fsPath', function () {
|
||||
for (const uri of manyFileUris) {
|
||||
let data = uri.fsPath;
|
||||
assert.ok(data);
|
||||
}
|
||||
});
|
||||
|
||||
perfTest('toJSON', function () {
|
||||
for (const uri of manyFileUris) {
|
||||
let data = uri.toJSON();
|
||||
assert.ok(data);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
BIN
lib/vscode/src/vs/base/test/node/zip/fixtures/extract.zip
Normal file
BIN
lib/vscode/src/vs/base/test/node/zip/fixtures/extract.zip
Normal file
Binary file not shown.
28
lib/vscode/src/vs/base/test/node/zip/zip.test.ts
Normal file
28
lib/vscode/src/vs/base/test/node/zip/zip.test.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import * as path from 'vs/base/common/path';
|
||||
import * as os from 'os';
|
||||
import { extract } from 'vs/base/node/zip';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { rimraf, exists } from 'vs/base/node/pfs';
|
||||
import { getPathFromAmdModule } from 'vs/base/common/amd';
|
||||
import { createCancelablePromise } from 'vs/base/common/async';
|
||||
|
||||
const fixtures = getPathFromAmdModule(require, './fixtures');
|
||||
|
||||
suite('Zip', () => {
|
||||
|
||||
test('extract should handle directories', () => {
|
||||
const fixture = path.join(fixtures, 'extract.zip');
|
||||
const target = path.join(os.tmpdir(), generateUuid());
|
||||
|
||||
return createCancelablePromise(token => extract(fixture, target, {}, token)
|
||||
.then(() => exists(path.join(target, 'extension')))
|
||||
.then(exists => assert(exists))
|
||||
.then(() => rimraf(target)));
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user