mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-11 10:38:31 -05:00
Merge from vscode 79a1f5a5ca0c6c53db617aa1fa5a2396d2caebe2
This commit is contained in:
@@ -3,48 +3,294 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { compareFileNames, compareFileExtensions } from 'vs/base/common/comparers';
|
||||
import { compareFileNames, compareFileExtensions, compareFileNamesNumeric, compareFileExtensionsNumeric } 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 compareFileNamesNumeric
|
||||
//
|
||||
|
||||
// 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('.abc', '.abc') === 0, 'equal full names should be equal');
|
||||
assert(compareFileNames('.env', '.env.example') < 0, 'filenames with extensions should come after those without');
|
||||
assert(compareFileNames('.env.example', '.gitattributes') < 0, 'filenames starting with dots and with extensions should still sort properly');
|
||||
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');
|
||||
|
||||
// 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 compareFileNamesNumeric
|
||||
//
|
||||
|
||||
// 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');
|
||||
|
||||
// name plus extension comparisons
|
||||
assert(compareFileNames('aggregate.go', 'aggregate_repo.go') > 0, 'compares the whole name all at once by locale');
|
||||
|
||||
// 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 compareFileExtensionsNumeric
|
||||
//
|
||||
|
||||
// name-only comparisons
|
||||
assert(compareFileExtensions(null, null) === 0, 'null should be equal');
|
||||
assert(compareFileExtensions(null, '.abc') < 0, 'null should come before real files');
|
||||
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('.abc', '.abc') === 0, 'equal full 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('.ext', 'a.ext') < 0, 'if equal extensions, filenames should be compared, empty filename should come before others');
|
||||
assert(compareFileExtensions('file.aaa', 'file.bbb') < 0, 'files should be compared by extensions');
|
||||
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('file2.ext2', 'file1.ext10') < 0, 'extensions with numbers should be in numerical order, not alphabetical order');
|
||||
assert(compareFileExtensions('file.ext01', 'file.ext1') < 0, 'extensions with equal numbers should be in alphabetical order');
|
||||
assert(compareFileExtensions('a10.txt', 'A2.txt') > 0, 'filenames with number and case differences compare numerically');
|
||||
|
||||
// Same extension comparison that has the same result as compareFileExtensionsNumeric, but a different result than compareFileNames
|
||||
// This is an edge case caused by compareFileNames comparing the whole name all at once instead of the name and then the extension.
|
||||
assert(compareFileExtensions('aggregate.go', 'aggregate_repo.go') < 0, 'when extensions are equal, names sort in dictionary order');
|
||||
|
||||
//
|
||||
// Comparisons with different results from compareFileExtensionsNumeric
|
||||
//
|
||||
|
||||
// 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');
|
||||
|
||||
// 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('compareFileNamesNumeric', () => {
|
||||
|
||||
//
|
||||
// Comparisons with the same results as compareFileNames
|
||||
//
|
||||
|
||||
// name-only comparisons
|
||||
assert(compareFileNamesNumeric(null, null) === 0, 'null should be equal');
|
||||
assert(compareFileNamesNumeric(null, 'abc') < 0, 'null should be come before real values');
|
||||
assert(compareFileNamesNumeric('', '') === 0, 'empty should be equal');
|
||||
assert(compareFileNamesNumeric('abc', 'abc') === 0, 'equal names should be equal');
|
||||
assert(compareFileNamesNumeric('z', 'A') > 0, 'z comes is after A regardless of case');
|
||||
assert(compareFileNamesNumeric('Z', 'a') > 0, 'Z comes after a regardless of case');
|
||||
|
||||
// name plus extension comparisons
|
||||
assert(compareFileNamesNumeric('file.ext', 'file.ext') === 0, 'equal full names should be equal');
|
||||
assert(compareFileNamesNumeric('a.ext', 'b.ext') < 0, 'if equal extensions, filenames should be compared');
|
||||
assert(compareFileNamesNumeric('file.aaa', 'file.bbb') < 0, 'files with equal names should be compared by extensions');
|
||||
assert(compareFileNamesNumeric('bbb.aaa', 'aaa.bbb') > 0, 'files should be compared by names even if extensions compare differently');
|
||||
|
||||
// dotfile comparisons
|
||||
assert(compareFileNamesNumeric('.abc', '.abc') === 0, 'equal dotfile names should be equal');
|
||||
assert(compareFileNamesNumeric('.env.', '.gitattributes') < 0, 'filenames starting with dots and with extensions should still sort properly');
|
||||
assert(compareFileNamesNumeric('.env', '.aaa.env') > 0, 'dotfiles sort alphabetically when they contain multiple dots');
|
||||
assert(compareFileNamesNumeric('.env', '.env.aaa') < 0, 'dotfiles with the same root sort shortest first');
|
||||
assert(compareFileNamesNumeric('.aaa_env', '.aaa.env') < 0, 'and underscore in a dotfile name will sort before a dot');
|
||||
|
||||
// dotfile vs non-dotfile comparisons
|
||||
assert(compareFileNamesNumeric(null, '.abc') < 0, 'null should come before dotfiles');
|
||||
assert(compareFileNamesNumeric('.env', 'aaa') < 0, 'dotfiles come before filenames without extensions');
|
||||
assert(compareFileNamesNumeric('.env', 'aaa.env') < 0, 'dotfiles come before filenames with extensions');
|
||||
assert(compareFileNamesNumeric('.md', 'A.MD') < 0, 'dotfiles sort before uppercase files');
|
||||
assert(compareFileNamesNumeric('.MD', 'a.md') < 0, 'dotfiles sort before lowercase files');
|
||||
|
||||
// numeric comparisons
|
||||
assert(compareFileNamesNumeric('1', '1') === 0, 'numerically equal full names should be equal');
|
||||
assert(compareFileNamesNumeric('abc1.txt', 'abc1.txt') === 0, 'equal filenames with numbers should be equal');
|
||||
assert(compareFileNamesNumeric('abc1.txt', 'abc2.txt') < 0, 'filenames with numbers should be in numerical order, not alphabetical order');
|
||||
assert(compareFileNamesNumeric('abc2.txt', 'abc10.txt') < 0, 'filenames with numbers should be in numerical order even when they are multiple digits long');
|
||||
assert(compareFileNamesNumeric('abc02.txt', 'abc010.txt') < 0, 'filenames with numbers that have leading zeros sort numerically');
|
||||
assert(compareFileNamesNumeric('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(compareFileNamesNumeric('a', 'A') === compareLocale('a', 'A'), 'the same letter sorts by locale');
|
||||
assert(compareFileNamesNumeric('â', 'Â') === compareLocale('â', 'Â'), 'the same accented letter sorts by locale');
|
||||
assert.deepEqual(['artichoke', 'Artichoke', 'art', 'Art'].sort(compareFileNamesNumeric), ['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(compareFileNamesNumeric), ['email', 'Email', 'émail', 'Émail'].sort(compareLocale), 'the same base characters with different case or accents sort in locale order');
|
||||
|
||||
// name plus extensions comparisons
|
||||
assert(compareFileNamesNumeric('aggregate.go', 'aggregate_repo.go') < 0, 'compares the name first, then the extension');
|
||||
|
||||
// numeric comparisons
|
||||
assert(compareFileNamesNumeric('abc02.txt', 'abc002.txt') < 0, 'filenames with equivalent numbers and leading zeros sort shortest number first');
|
||||
assert(compareFileNamesNumeric('abc.txt1', 'abc.txt01') < 0, 'same name plus extensions with equal numbers sort shortest number first');
|
||||
assert(compareFileNamesNumeric('art01', 'Art01') === compareLocaleNumeric('art01', 'Art01'), 'a numerically equivalent word of a different case compares numerically based on locale');
|
||||
|
||||
});
|
||||
|
||||
test('compareFileExtensionsNumeric', () => {
|
||||
|
||||
//
|
||||
// Comparisons with the same result as compareFileExtensions
|
||||
//
|
||||
|
||||
// name-only comparisons
|
||||
assert(compareFileExtensionsNumeric(null, null) === 0, 'null should be equal');
|
||||
assert(compareFileExtensionsNumeric(null, 'abc') < 0, 'null should come before real files without extensions');
|
||||
assert(compareFileExtensionsNumeric('', '') === 0, 'empty should be equal');
|
||||
assert(compareFileExtensionsNumeric('abc', 'abc') === 0, 'equal names should be equal');
|
||||
assert(compareFileExtensionsNumeric('z', 'A') > 0, 'z comes after A');
|
||||
assert(compareFileExtensionsNumeric('Z', 'a') > 0, 'Z comes after a');
|
||||
|
||||
// name plus extension comparisons
|
||||
assert(compareFileExtensionsNumeric('file.ext', 'file.ext') === 0, 'equal full filenames should be equal');
|
||||
assert(compareFileExtensionsNumeric('a.ext', 'b.ext') < 0, 'if equal extensions, filenames should be compared');
|
||||
assert(compareFileExtensionsNumeric('file.aaa', 'file.bbb') < 0, 'files with equal names should be compared by extensions');
|
||||
assert(compareFileExtensionsNumeric('bbb.aaa', 'aaa.bbb') < 0, 'files should be compared by extension first');
|
||||
assert(compareFileExtensionsNumeric('agg.go', 'aggrepo.go') < 0, 'shorter names sort before longer names');
|
||||
assert(compareFileExtensionsNumeric('agg.go', 'agg_repo.go') < 0, 'shorter names short before longer names even when the longer name contains an underscore');
|
||||
assert(compareFileExtensionsNumeric('a.MD', 'b.md') < 0, 'when extensions are the same except for case, the files sort by name');
|
||||
|
||||
// dotfile comparisons
|
||||
assert(compareFileExtensionsNumeric('.abc', '.abc') === 0, 'equal dotfiles should be equal');
|
||||
assert(compareFileExtensionsNumeric('.md', '.Gitattributes') > 0, 'dotfiles sort alphabetically regardless of case');
|
||||
|
||||
// dotfile vs non-dotfile comparisons
|
||||
assert(compareFileExtensionsNumeric(null, '.abc') < 0, 'null should come before dotfiles');
|
||||
assert(compareFileExtensionsNumeric('.env', 'aaa.env') < 0, 'dotfiles come before filenames with extensions');
|
||||
assert(compareFileExtensionsNumeric('.MD', 'a.md') < 0, 'dotfiles sort before lowercase files');
|
||||
|
||||
// numeric comparisons
|
||||
assert(compareFileExtensionsNumeric('1', '1') === 0, 'numerically equal full names should be equal');
|
||||
assert(compareFileExtensionsNumeric('abc1.txt', 'abc1.txt') === 0, 'equal filenames with numbers should be equal');
|
||||
assert(compareFileExtensionsNumeric('abc1.txt', 'abc2.txt') < 0, 'filenames with numbers should be in numerical order, not alphabetical order');
|
||||
assert(compareFileExtensionsNumeric('abc2.txt', 'abc10.txt') < 0, 'filenames with numbers should be in numerical order');
|
||||
assert(compareFileExtensionsNumeric('abc02.txt', 'abc010.txt') < 0, 'filenames with numbers that have leading zeros sort numerically');
|
||||
assert(compareFileExtensionsNumeric('abc1.10.txt', 'abc1.2.txt') > 0, 'numbers with dots between them are treated as two separate numbers, not one decimal number');
|
||||
assert(compareFileExtensionsNumeric('abc2.txt2', 'abc1.txt10') < 0, 'extensions with numbers should be in numerical order, not alphabetical order');
|
||||
assert(compareFileExtensionsNumeric('txt.abc1', 'txt.abc1') === 0, 'equal extensions with numbers should be equal');
|
||||
assert(compareFileExtensionsNumeric('txt.abc1', 'txt.abc2') < 0, 'extensions with numbers should be in numerical order, not alphabetical order');
|
||||
assert(compareFileExtensionsNumeric('txt.abc2', 'txt.abc10') < 0, 'extensions with numbers should be in numerical order even when they are multiple digits long');
|
||||
assert(compareFileExtensionsNumeric('a.ext1', 'b.ext1') < 0, 'if equal extensions with numbers, filenames should be compared');
|
||||
assert(compareFileExtensionsNumeric('a10.txt', 'A2.txt') > 0, 'filenames with number and case differences compare numerically');
|
||||
|
||||
// Same extension comparison that has the same result as compareFileExtensions, but a different result than compareFileNames
|
||||
// This is an edge case caused by compareFileNames comparing the whole name all at once instead of the name and then the extension.
|
||||
assert(compareFileExtensionsNumeric('aggregate.go', 'aggregate_repo.go') < 0, 'when extensions are equal, names sort in dictionary order');
|
||||
|
||||
//
|
||||
// Comparisons with different results than compareFileExtensions
|
||||
//
|
||||
|
||||
// name-only comparisons
|
||||
assert(compareFileExtensionsNumeric('a', 'A') === compareLocale('a', 'A'), 'the same letter of different case sorts by locale');
|
||||
assert(compareFileExtensionsNumeric('â', 'Â') === compareLocale('â', 'Â'), 'the same accented letter of different case sorts by locale');
|
||||
assert.deepEqual(['artichoke', 'Artichoke', 'art', 'Art'].sort(compareFileExtensionsNumeric), ['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(compareFileExtensionsNumeric), ['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(compareFileExtensionsNumeric('a.MD', 'a.md') === compareLocale('MD', 'md'), 'case differences in extensions sort by locale');
|
||||
assert(compareFileExtensionsNumeric('a.md', 'A.md') === compareLocale('a', 'A'), 'case differences in names sort by locale');
|
||||
|
||||
// dotfile comparisons
|
||||
assert(compareFileExtensionsNumeric('.env', '.aaa.env') > 0, 'dotfiles sort alphabetically when they contain multiple dots');
|
||||
assert(compareFileExtensionsNumeric('.env', '.env.aaa') < 0, 'dotfiles with the same root sort shortest first');
|
||||
|
||||
// dotfile vs non-dotfile comparisons
|
||||
assert(compareFileExtensionsNumeric('.env', 'aaa') < 0, 'dotfiles come before filenames without extensions');
|
||||
assert(compareFileExtensionsNumeric('.md', 'A.MD') < 0, 'dotfiles sort before uppercase files');
|
||||
|
||||
// numeric comparisons
|
||||
assert(compareFileExtensionsNumeric('abc.txt01', 'abc.txt1') > 0, 'extensions with equal numbers should be in shortest-first order');
|
||||
assert(compareFileExtensionsNumeric('art01', 'Art01') === compareLocaleNumeric('art01', 'Art01'), 'a numerically equivalent word of a different case compares numerically based on locale');
|
||||
assert(compareFileExtensionsNumeric('abc02.txt', 'abc002.txt') < 0, 'filenames with equivalent numbers and leading zeros sort shortest string first');
|
||||
assert(compareFileExtensionsNumeric('txt.abc01', 'txt.abc1') > 0, 'extensions with equivalent numbers sort shortest extension first');
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -130,4 +130,41 @@ suite('Paths', () => {
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,8 +13,8 @@ suite('Map', () => {
|
||||
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.deepStrictEqual([...map.keys()], ['ak', 'bk']);
|
||||
assert.deepStrictEqual([...map.values()], ['av', 'bv']);
|
||||
assert.equal(map.first, 'av');
|
||||
assert.equal(map.last, 'bv');
|
||||
});
|
||||
@@ -23,16 +23,16 @@ suite('Map', () => {
|
||||
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']);
|
||||
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']);
|
||||
assert.deepStrictEqual([...map.keys()], ['ak']);
|
||||
assert.deepStrictEqual([...map.values()], ['av']);
|
||||
});
|
||||
|
||||
test('LinkedMap - Touch Old two', () => {
|
||||
@@ -40,8 +40,8 @@ suite('Map', () => {
|
||||
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']);
|
||||
assert.deepStrictEqual([...map.keys()], ['bk', 'ak']);
|
||||
assert.deepStrictEqual([...map.values()], ['bv', 'av']);
|
||||
});
|
||||
|
||||
test('LinkedMap - Touch New two', () => {
|
||||
@@ -49,8 +49,8 @@ suite('Map', () => {
|
||||
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']);
|
||||
assert.deepStrictEqual([...map.keys()], ['bk', 'ak']);
|
||||
assert.deepStrictEqual([...map.values()], ['bv', 'av']);
|
||||
});
|
||||
|
||||
test('LinkedMap - Touch Old from middle', () => {
|
||||
@@ -59,8 +59,8 @@ suite('Map', () => {
|
||||
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']);
|
||||
assert.deepStrictEqual([...map.keys()], ['bk', 'ak', 'ck']);
|
||||
assert.deepStrictEqual([...map.values()], ['bv', 'av', 'cv']);
|
||||
});
|
||||
|
||||
test('LinkedMap - Touch New from middle', () => {
|
||||
@@ -69,8 +69,8 @@ suite('Map', () => {
|
||||
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']);
|
||||
assert.deepStrictEqual([...map.keys()], ['ak', 'ck', 'bk']);
|
||||
assert.deepStrictEqual([...map.values()], ['av', 'cv', 'bv']);
|
||||
});
|
||||
|
||||
test('LinkedMap - basics', function () {
|
||||
@@ -129,6 +129,61 @@ suite('Map', () => {
|
||||
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);
|
||||
|
||||
@@ -136,10 +191,10 @@ suite('Map', () => {
|
||||
assert.strictEqual(cache.size, 5);
|
||||
cache.set(6, 6);
|
||||
assert.strictEqual(cache.size, 5);
|
||||
assert.deepStrictEqual(cache.keys(), [2, 3, 4, 5, 6]);
|
||||
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]);
|
||||
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]);
|
||||
@@ -150,11 +205,11 @@ suite('Map', () => {
|
||||
|
||||
[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]);
|
||||
assert.deepStrictEqual([...cache.keys()], [1, 2, 3, 4, 5]);
|
||||
cache.get(3);
|
||||
assert.deepStrictEqual(cache.keys(), [1, 2, 4, 5, 3]);
|
||||
assert.deepStrictEqual([...cache.keys()], [1, 2, 4, 5, 3]);
|
||||
cache.peek(4);
|
||||
assert.deepStrictEqual(cache.keys(), [1, 2, 4, 5, 3]);
|
||||
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]);
|
||||
@@ -169,7 +224,7 @@ suite('Map', () => {
|
||||
assert.strictEqual(cache.size, 10);
|
||||
cache.limit = 5;
|
||||
assert.strictEqual(cache.size, 5);
|
||||
assert.deepStrictEqual(cache.keys(), [6, 7, 8, 9, 10]);
|
||||
assert.deepStrictEqual([...cache.keys()], [6, 7, 8, 9, 10]);
|
||||
cache.limit = 20;
|
||||
assert.strictEqual(cache.size, 5);
|
||||
for (let i = 11; i <= 20; i++) {
|
||||
@@ -181,7 +236,7 @@ suite('Map', () => {
|
||||
values.push(cache.get(i)!);
|
||||
assert.strictEqual(cache.get(i), i);
|
||||
}
|
||||
assert.deepStrictEqual(cache.values(), values);
|
||||
assert.deepStrictEqual([...cache.values()], values);
|
||||
});
|
||||
|
||||
test('LinkedMap - LRU Cache limit with ratio', () => {
|
||||
@@ -193,11 +248,11 @@ suite('Map', () => {
|
||||
assert.strictEqual(cache.size, 10);
|
||||
cache.set(11, 11);
|
||||
assert.strictEqual(cache.size, 5);
|
||||
assert.deepStrictEqual(cache.keys(), [7, 8, 9, 10, 11]);
|
||||
assert.deepStrictEqual([...cache.keys()], [7, 8, 9, 10, 11]);
|
||||
let values: number[] = [];
|
||||
cache.keys().forEach(key => values.push(cache.get(key)!));
|
||||
[...cache.keys()].forEach(key => values.push(cache.get(key)!));
|
||||
assert.deepStrictEqual(values, [7, 8, 9, 10, 11]);
|
||||
assert.deepStrictEqual(cache.values(), values);
|
||||
assert.deepStrictEqual([...cache.values()], values);
|
||||
});
|
||||
|
||||
test('LinkedMap - toJSON / fromJSON', () => {
|
||||
@@ -222,7 +277,6 @@ suite('Map', () => {
|
||||
assert.equal(key, 'ck');
|
||||
assert.equal(value, 'cv');
|
||||
}
|
||||
|
||||
i++;
|
||||
});
|
||||
});
|
||||
@@ -237,7 +291,7 @@ suite('Map', () => {
|
||||
map.delete('1');
|
||||
assert.equal(map.get('1'), undefined);
|
||||
assert.equal(map.size, 0);
|
||||
assert.equal(map.keys().length, 0);
|
||||
assert.equal([...map.keys()].length, 0);
|
||||
});
|
||||
|
||||
test('LinkedMap - delete Head', function () {
|
||||
@@ -251,8 +305,8 @@ suite('Map', () => {
|
||||
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);
|
||||
assert.equal([...map.keys()].length, 1);
|
||||
assert.equal([...map.keys()][0], 2);
|
||||
});
|
||||
|
||||
test('LinkedMap - delete Tail', function () {
|
||||
@@ -266,8 +320,8 @@ suite('Map', () => {
|
||||
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);
|
||||
assert.equal([...map.keys()].length, 1);
|
||||
assert.equal([...map.keys()][0], 1);
|
||||
});
|
||||
|
||||
|
||||
@@ -317,7 +371,8 @@ suite('Map', () => {
|
||||
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.cmp('file'), 0);
|
||||
assert.equal(iter.hasNext(), true);
|
||||
iter.next();
|
||||
|
||||
@@ -337,7 +392,8 @@ suite('Map', () => {
|
||||
|
||||
// scheme
|
||||
assert.equal(iter.value(), 'file');
|
||||
assert.equal(iter.cmp('FILE'), 0);
|
||||
// assert.equal(iter.cmp('FILE'), 0);
|
||||
assert.equal(iter.cmp('file'), 0);
|
||||
assert.equal(iter.hasNext(), true);
|
||||
iter.next();
|
||||
|
||||
|
||||
12
src/vs/base/test/common/mock.ts
Normal file
12
src/vs/base/test/common/mock.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. 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;
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as assert from 'assert';
|
||||
import { dirname, basename, distinctParents, joinPath, isEqual, isEqualOrParent, hasToIgnoreCase, normalizePath, isAbsolutePath, relativePath, removeTrailingPathSeparator, hasTrailingPathSeparator, resolvePath, addTrailingPathSeparator, getComparisonKey } from 'vs/base/common/resources';
|
||||
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';
|
||||
@@ -235,16 +235,19 @@ suite('Resources', () => {
|
||||
}
|
||||
});
|
||||
|
||||
function assertEqualURI(actual: URI, expected: URI, message?: string) {
|
||||
if (!isEqual(expected, actual, hasToIgnoreCase(expected), false)) {
|
||||
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) {
|
||||
assert.equal(relativePath(u1, u2, ignoreCase), expectedPath, `from ${u1.toString()} to ${u2.toString()}`);
|
||||
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');
|
||||
assertEqualURI(removeTrailingPathSeparator(joinPath(u1, expectedPath)), removeTrailingPathSeparator(u2), 'joinPath on relativePath should be equal', ignoreCase);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,14 +257,14 @@ suite('Resources', () => {
|
||||
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'), '../../..');
|
||||
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'), '');
|
||||
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'), '');
|
||||
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);
|
||||
@@ -346,10 +349,17 @@ suite('Resources', () => {
|
||||
|
||||
});
|
||||
|
||||
function assertIsEqual(u1: URI, u2: URI, ignoreCase: boolean, expected: boolean) {
|
||||
assert.equal(isEqual(u1, u2, ignoreCase), expected, `${u1.toString()}${expected ? '===' : '!=='}${u2.toString()}`);
|
||||
assert.equal(getComparisonKey(u1, ignoreCase) === getComparisonKey(u2, ignoreCase), expected, `comparison keys ${u1.toString()}, ${u2.toString()}`);
|
||||
assert.equal(isEqualOrParent(u1, u2, ignoreCase), expected, `isEqualOrParent ${u1.toString()}, ${u2.toString()}`);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -358,7 +368,7 @@ suite('Resources', () => {
|
||||
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, hasToIgnoreCase(fileURI), true);
|
||||
assertIsEqual(fileURI, fileURI, undefined, true);
|
||||
assertIsEqual(fileURI, fileURI2, true, true);
|
||||
assertIsEqual(fileURI, fileURI2, false, false);
|
||||
|
||||
@@ -366,13 +376,15 @@ suite('Resources', () => {
|
||||
let fileURI4 = URI.parse('foo://server:453/foo/Bar');
|
||||
assertIsEqual(fileURI3, fileURI3, true, true);
|
||||
assertIsEqual(fileURI3, fileURI3, false, true);
|
||||
assertIsEqual(fileURI3, fileURI3, hasToIgnoreCase(fileURI3), true);
|
||||
assertIsEqual(fileURI3, fileURI3, undefined, true);
|
||||
assertIsEqual(fileURI3, fileURI4, true, true);
|
||||
assertIsEqual(fileURI3, fileURI4, false, false);
|
||||
|
||||
assertIsEqual(fileURI, fileURI3, true, false);
|
||||
|
||||
assertIsEqual(URI.parse('foo://server'), URI.parse('foo://server/'), true, true);
|
||||
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);
|
||||
|
||||
@@ -383,38 +395,39 @@ suite('Resources', () => {
|
||||
assertIsEqual(fileURI5, fileURI3, true, false);
|
||||
assertIsEqual(fileURI6, fileURI6, true, true);
|
||||
assertIsEqual(fileURI6, fileURI5, true, false);
|
||||
assertIsEqual(fileURI6, fileURI3, true, true);
|
||||
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(isEqualOrParent(fileURI, fileURI, true), true, '1');
|
||||
assert.equal(isEqualOrParent(fileURI, fileURI, false), true, '2');
|
||||
assert.equal(isEqualOrParent(fileURI, fileURI2, true), true, '3');
|
||||
assert.equal(isEqualOrParent(fileURI, fileURI2, false), true, '4');
|
||||
assert.equal(isEqualOrParent(fileURI, fileURI2b, true), true, '5');
|
||||
assert.equal(isEqualOrParent(fileURI, fileURI2b, false), false, '6');
|
||||
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(isEqualOrParent(fileURI2, fileURI, false), false, '7');
|
||||
assert.equal(isEqualOrParent(fileURI2b, fileURI2, true), true, '8');
|
||||
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(isEqualOrParent(fileURI3, fileURI3, true), true, '11');
|
||||
assert.equal(isEqualOrParent(fileURI3, fileURI3, false), true, '12');
|
||||
assert.equal(isEqualOrParent(fileURI3, fileURI4, true), true, '13');
|
||||
assert.equal(isEqualOrParent(fileURI3, fileURI4, false), true, '14');
|
||||
assert.equal(isEqualOrParent(fileURI3, fileURI, true), false, '15');
|
||||
assert.equal(isEqualOrParent(fileURI5, fileURI5, true), true, '16');
|
||||
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(isEqualOrParent(fileURI6, fileURI5, true), false, '17');
|
||||
assert.equal(isEqualOrParent(fileURI6, fileURI6, true), true, '18');
|
||||
assert.equal(isEqualOrParent(fileURI7, fileURI6, true), true, '19');
|
||||
assert.equal(isEqualOrParent(fileURI7, fileURI5, true), false, '20');
|
||||
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');
|
||||
});
|
||||
});
|
||||
|
||||
218
src/vs/base/test/common/skipList.test.ts
Normal file
218
src/vs/base/test/common/skipList.test.ts
Normal file
@@ -0,0 +1,218 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { 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)`);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user