filters.test.ts 11.8 KB
Newer Older
E
Erich Gamma 已提交
1 2 3 4 5 6 7
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
'use strict';

import * as assert from 'assert';
J
Johannes Rieken 已提交
8
import { IFilter, or, matchesPrefix, matchesStrictPrefix, matchesCamelCase, matchesSubString, matchesContiguousSubString, matchesWords, fuzzyMatchAndScore } from 'vs/base/common/filters';
E
Erich Gamma 已提交
9 10

function filterOk(filter: IFilter, word: string, wordToMatchAgainst: string, highlights?: { start: number; end: number; }[]) {
11
	let r = filter(word, wordToMatchAgainst);
E
Erich Gamma 已提交
12 13 14 15 16 17 18 19 20 21
	assert(r);
	if (highlights) {
		assert.deepEqual(r, highlights);
	}
}

function filterNotOk(filter, word, suggestion) {
	assert(!filter(word, suggestion));
}

22 23
suite('Filters', () => {
	test('or', function () {
24 25
		let filter, counters;
		let newFilter = function (i, r) {
E
Erich Gamma 已提交
26 27 28
			return function () { counters[i]++; return r; };
		};

J
Johannes Rieken 已提交
29
		counters = [0, 0];
E
Erich Gamma 已提交
30
		filter = or(newFilter(0, false), newFilter(1, false));
31
		filterNotOk(filter, 'anything', 'anything');
J
Johannes Rieken 已提交
32
		assert.deepEqual(counters, [1, 1]);
E
Erich Gamma 已提交
33

J
Johannes Rieken 已提交
34
		counters = [0, 0];
E
Erich Gamma 已提交
35
		filter = or(newFilter(0, true), newFilter(1, false));
36
		filterOk(filter, 'anything', 'anything');
J
Johannes Rieken 已提交
37
		assert.deepEqual(counters, [1, 0]);
E
Erich Gamma 已提交
38

J
Johannes Rieken 已提交
39
		counters = [0, 0];
E
Erich Gamma 已提交
40
		filter = or(newFilter(0, true), newFilter(1, true));
41
		filterOk(filter, 'anything', 'anything');
J
Johannes Rieken 已提交
42
		assert.deepEqual(counters, [1, 0]);
E
Erich Gamma 已提交
43

J
Johannes Rieken 已提交
44
		counters = [0, 0];
E
Erich Gamma 已提交
45
		filter = or(newFilter(0, false), newFilter(1, true));
46
		filterOk(filter, 'anything', 'anything');
J
Johannes Rieken 已提交
47
		assert.deepEqual(counters, [1, 1]);
E
Erich Gamma 已提交
48 49
	});

50 51 52 53 54 55 56 57 58 59
	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');
E
Erich Gamma 已提交
60 61
	});

62 63 64 65 66
	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 }]);
67
		filterOk(matchesPrefix, 'ä', 'Älpha', [{ start: 0, end: 1 }]);
68 69 70
		filterNotOk(matchesPrefix, 'x', 'alpha');
		filterOk(matchesPrefix, 'A', 'alpha', [{ start: 0, end: 1 }]);
		filterOk(matchesPrefix, 'AlPh', 'alPHA', [{ start: 0, end: 4 }]);
71
		filterNotOk(matchesPrefix, 'T', '4'); // see https://github.com/Microsoft/vscode/issues/22401
E
Erich Gamma 已提交
72 73
	});

74 75 76 77 78 79 80
	test('CamelCaseFilter', function () {
		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');
E
Erich Gamma 已提交
81

82
		filterOk(matchesCamelCase, 'c', 'CamelCaseRocks', [
E
Erich Gamma 已提交
83 84
			{ start: 0, end: 1 }
		]);
85
		filterOk(matchesCamelCase, 'cc', 'CamelCaseRocks', [
E
Erich Gamma 已提交
86 87 88
			{ start: 0, end: 1 },
			{ start: 5, end: 6 }
		]);
89
		filterOk(matchesCamelCase, 'ccr', 'CamelCaseRocks', [
E
Erich Gamma 已提交
90 91 92 93
			{ start: 0, end: 1 },
			{ start: 5, end: 6 },
			{ start: 9, end: 10 }
		]);
94
		filterOk(matchesCamelCase, 'cacr', 'CamelCaseRocks', [
E
Erich Gamma 已提交
95 96 97 98
			{ start: 0, end: 2 },
			{ start: 5, end: 6 },
			{ start: 9, end: 10 }
		]);
99
		filterOk(matchesCamelCase, 'cacar', 'CamelCaseRocks', [
E
Erich Gamma 已提交
100 101 102 103
			{ start: 0, end: 2 },
			{ start: 5, end: 7 },
			{ start: 9, end: 10 }
		]);
104
		filterOk(matchesCamelCase, 'ccarocks', 'CamelCaseRocks', [
E
Erich Gamma 已提交
105 106 107 108
			{ start: 0, end: 1 },
			{ start: 5, end: 7 },
			{ start: 9, end: 14 }
		]);
109
		filterOk(matchesCamelCase, 'cr', 'CamelCaseRocks', [
E
Erich Gamma 已提交
110 111 112
			{ start: 0, end: 1 },
			{ start: 9, end: 10 }
		]);
113
		filterOk(matchesCamelCase, 'fba', 'FooBarAbe', [
E
Erich Gamma 已提交
114 115 116
			{ start: 0, end: 1 },
			{ start: 3, end: 5 }
		]);
117
		filterOk(matchesCamelCase, 'fbar', 'FooBarAbe', [
E
Erich Gamma 已提交
118 119 120
			{ start: 0, end: 1 },
			{ start: 3, end: 6 }
		]);
121
		filterOk(matchesCamelCase, 'fbara', 'FooBarAbe', [
E
Erich Gamma 已提交
122 123 124
			{ start: 0, end: 1 },
			{ start: 3, end: 7 }
		]);
125
		filterOk(matchesCamelCase, 'fbaa', 'FooBarAbe', [
E
Erich Gamma 已提交
126 127 128 129
			{ start: 0, end: 1 },
			{ start: 3, end: 5 },
			{ start: 6, end: 7 }
		]);
130
		filterOk(matchesCamelCase, 'fbaab', 'FooBarAbe', [
E
Erich Gamma 已提交
131 132 133 134
			{ start: 0, end: 1 },
			{ start: 3, end: 5 },
			{ start: 6, end: 8 }
		]);
135
		filterOk(matchesCamelCase, 'c2d', 'canvasCreation2D', [
E
Erich Gamma 已提交
136 137 138
			{ start: 0, end: 1 },
			{ start: 14, end: 16 }
		]);
139
		filterOk(matchesCamelCase, 'cce', '_canvasCreationEvent', [
E
Erich Gamma 已提交
140 141 142 143 144 145
			{ start: 1, end: 2 },
			{ start: 7, end: 8 },
			{ start: 15, end: 16 }
		]);
	});

146
	test('CamelCaseFilter - #19256', function () {
E
Erich Gamma 已提交
147 148 149 150
		assert(matchesCamelCase('Debug Console', 'Open: Debug Console'));
		assert(matchesCamelCase('Debug console', 'Open: Debug Console'));
		assert(matchesCamelCase('debug console', 'Open: Debug Console'));
	});
B
Benjamin Pasero 已提交
151

152 153
	test('matchesContiguousSubString', function () {
		filterOk(matchesContiguousSubString, 'cela', 'cancelAnimationFrame()', [
B
Benjamin Pasero 已提交
154 155 156 157
			{ start: 3, end: 7 }
		]);
	});

158 159
	test('matchesSubString', function () {
		filterOk(matchesSubString, 'cmm', 'cancelAnimationFrame()', [
B
Benjamin Pasero 已提交
160 161 162 163 164
			{ start: 0, end: 1 },
			{ start: 9, end: 10 },
			{ start: 18, end: 19 }
		]);
	});
165 166 167 168 169 170 171 172 173 174 175

	test('WordFilter', function () {
		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'));

J
Johannes Rieken 已提交
176 177 178
		filterOk(matchesWords, 'gp', 'Git: Pull', [{ start: 0, end: 1 }, { start: 5, end: 6 }]);
		filterOk(matchesWords, 'g p', 'Git: Pull', [{ start: 0, end: 1 }, { start: 4, end: 6 }]);
		filterOk(matchesWords, 'gipu', 'Git: Pull', [{ start: 0, end: 2 }, { start: 5, end: 7 }]);
179

J
Johannes Rieken 已提交
180 181 182
		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: 14, end: 16 }]);
		filterOk(matchesWords, 'gipu', 'Category: Git: Pull', [{ start: 10, end: 12 }, { start: 15, end: 17 }]);
183 184 185 186 187

		filterNotOk(matchesWords, 'it', 'Git: Pull');
		filterNotOk(matchesWords, 'll', 'Git: Pull');

		filterOk(matchesWords, 'git: プル', 'git: プル', [{ start: 0, end: 7 }]);
J
Johannes Rieken 已提交
188
		filterOk(matchesWords, 'git プル', 'git: プル', [{ start: 0, end: 3 }, { start: 4, end: 7 }]);
189 190

		filterOk(matchesWords, 'öäk', 'Öhm: Älles Klar', [{ start: 0, end: 1 }, { start: 5, end: 6 }, { start: 11, end: 12 }]);
S
Sandeep Somavarapu 已提交
191 192 193

		assert.ok(matchesWords('gipu', 'Category: Git: Pull', true) === null);
		assert.deepEqual(matchesWords('pu', 'Category: Git: Pull', true), [{ start: 15, end: 17 }]);
194
	});
J
Johannes Rieken 已提交
195

196
	test('fuzzyMatchAndScore', function () {
J
Johannes Rieken 已提交
197

J
Johannes Rieken 已提交
198
		function assertMatches(pattern: string, word: string, decoratedWord: string, filter: typeof fuzzyMatchAndScore) {
199
			let r = filter(pattern, word);
J
Johannes Rieken 已提交
200 201 202 203 204 205 206 207 208
			assert.ok(Boolean(r) === Boolean(decoratedWord));
			if (r) {
				const [, matches] = r;
				let pos = 0;
				for (let i = 0; i < matches.length; i++) {
					let actual = matches[i];
					let expected = decoratedWord.indexOf('^', pos) - i;
					assert.equal(actual, expected);
					pos = expected + 1 + i;
J
Johannes Rieken 已提交
209 210 211 212
				}
			}
		}

J
Johannes Rieken 已提交
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
		assertMatches('no', 'match', undefined, fuzzyMatchAndScore);
		assertMatches('no', '', undefined, fuzzyMatchAndScore);
		assertMatches('BK', 'the_black_knight', 'the_^black_^knight', fuzzyMatchAndScore);
		assertMatches('bkn', 'the_black_knight', 'the_^black_^k^night', fuzzyMatchAndScore);
		assertMatches('bt', 'the_black_knight', 'the_^black_knigh^t', fuzzyMatchAndScore);
		assertMatches('bti', 'the_black_knight', undefined, fuzzyMatchAndScore);
		assertMatches('LLL', 'SVisualLoggerLogsList', 'SVisual^Logger^Logs^List', fuzzyMatchAndScore);
		assertMatches('LLLL', 'SVisualLoggerLogsList', undefined, fuzzyMatchAndScore);
		assertMatches('sllll', 'SVisualLoggerLogsList', '^SVisua^l^Logger^Logs^List', fuzzyMatchAndScore);
		assertMatches('sl', 'SVisualLoggerLogsList', '^SVisual^LoggerLogsList', fuzzyMatchAndScore);
		assertMatches('foobar', 'foobar', '^f^o^o^b^a^r', fuzzyMatchAndScore);
		assertMatches('fob', 'foobar', '^f^oo^bar', fuzzyMatchAndScore);
		assertMatches('ob', 'foobar', undefined, fuzzyMatchAndScore);
		assertMatches('gp', 'Git: Pull', '^Git: ^Pull', fuzzyMatchAndScore);
		assertMatches('gp', 'Git_Git_Pull', '^Git_Git_^Pull', fuzzyMatchAndScore);
		assertMatches('g p', 'Git: Pull', '^Git:^ ^Pull', fuzzyMatchAndScore);
		assertMatches('gip', 'Git: Pull', '^G^it: ^Pull', fuzzyMatchAndScore);
		assertMatches('is', 'isValid', '^i^sValid', fuzzyMatchAndScore);
		assertMatches('is', 'ImportStatement', '^Import^Statement', fuzzyMatchAndScore);
		assertMatches('lowrd', 'lowWord', '^l^o^wWo^r^d', fuzzyMatchAndScore);
		assertMatches('ccm', 'cacmelCase', '^ca^c^melCase', fuzzyMatchAndScore);
		assertMatches('ccm', 'camelCase', undefined, fuzzyMatchAndScore);
		assertMatches('ccm', 'camelCasecm', '^camel^Casec^m', fuzzyMatchAndScore);
J
Johannes Rieken 已提交
236 237
		assertMatches('myvable', 'myvariable', '^m^y^v^aria^b^l^e', fuzzyMatchAndScore);
		assertMatches('fdm', 'findModel', '^fin^d^Model', fuzzyMatchAndScore);
238
		assertMatches('form', 'editor.formatOnSave', 'editor.^f^o^r^matOnSave', fuzzyMatchAndScore);
239
		assertMatches('KeyboardLayoutEventChange=', 'KeyboardLayoutEventChange', undefined, fuzzyMatchAndScore);
240
	});
J
Johannes Rieken 已提交
241

242
	test('topScore', function () {
J
Johannes Rieken 已提交
243

244
		function assertTopScore(pattern: string, expected: number, ...words: string[]) {
J
Johannes Rieken 已提交
245
			let topScore = Number.MIN_VALUE;
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
			let topIdx = 0;
			for (let i = 0; i < words.length; i++) {
				const word = words[i];
				const m = fuzzyMatchAndScore(pattern, word);
				if (m) {
					const [score] = m;
					if (score > topScore) {
						topScore = score;
						topIdx = i;
					}
				}
			}
			assert.equal(topIdx, expected);
		}

J
Johannes Rieken 已提交
261
		assertTopScore('cons', 2, 'ArrayBufferConstructor', 'Console', 'console');
J
Johannes Rieken 已提交
262
		assertTopScore('Foo', 1, 'foo', 'Foo', 'foo');
263

J
Johannes Rieken 已提交
264 265
		assertTopScore('CC', 1, 'camelCase', 'CamelCase');
		assertTopScore('cC', 0, 'camelCase', 'CamelCase');
266 267
		assertTopScore('cC', 1, 'ccfoo', 'camelCase');
		assertTopScore('cC', 1, 'ccfoo', 'camelCase', 'foo-cC-bar');
J
Johannes Rieken 已提交
268

269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
		// issue #17836
		assertTopScore('p', 0, 'parse', 'posix', 'pafdsa', 'path', 'p');
		assertTopScore('pa', 0, 'parse', 'pafdsa', 'path');

		// issue #14583
		assertTopScore('log', 3, 'HTMLOptGroupElement', 'ScrollLogicalPosition', 'SVGFEMorphologyElement', 'log');
		assertTopScore('e', 2, 'AbstractWorker', 'ActiveXObject', 'else');

		// issue #14446
		assertTopScore('workbench.sideb', 1, 'workbench.editor.defaultSideBySideLayout', 'workbench.sideBar.location');

		// issue #11423
		assertTopScore('editor.r', 2, 'diffEditor.renderSideBySide', 'editor.overviewRulerlanes', 'editor.renderControlCharacter', 'editor.renderWhitespace');
		// assertTopScore('editor.R', 1, 'diffEditor.renderSideBySide', 'editor.overviewRulerlanes', 'editor.renderControlCharacter', 'editor.renderWhitespace');
		// assertTopScore('Editor.r', 0, 'diffEditor.renderSideBySide', 'editor.overviewRulerlanes', 'editor.renderControlCharacter', 'editor.renderWhitespace');

		assertTopScore('-mo', 1, '-ms-ime-mode', '-moz-columns');
		// // dupe, issue #14861
		assertTopScore('convertModelPosition', 0, 'convertModelPositionToViewPosition', 'convertViewToModelPosition');
		// // dupe, issue #14942
		assertTopScore('is', 0, 'isValidViewletId', 'import statement');

	});
E
Erich Gamma 已提交
292
});