filters.test.ts 24.1 KB
Newer Older
E
Erich Gamma 已提交
1 2 3 4 5
/*---------------------------------------------------------------------------------------------
 *  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';
6
import { IFilter, or, matchesPrefix, matchesStrictPrefix, matchesCamelCase, matchesSubString, matchesContiguousSubString, matchesWords, fuzzyScore, IMatch, fuzzyScoreGraceful, fuzzyScoreGracefulAggressive, FuzzyScorer, createMatches } from 'vs/base/common/filters';
E
Erich Gamma 已提交
7 8

function filterOk(filter: IFilter, word: string, wordToMatchAgainst: string, highlights?: { start: number; end: number; }[]) {
9
	let r = filter(word, wordToMatchAgainst);
10
	assert(r, `${word} didn't match ${wordToMatchAgainst}`);
E
Erich Gamma 已提交
11 12 13 14 15
	if (highlights) {
		assert.deepEqual(r, highlights);
	}
}

16 17
function filterNotOk(filter: IFilter, word: string, wordToMatchAgainst: string) {
	assert(!filter(word, wordToMatchAgainst), `${word} matched ${wordToMatchAgainst}`);
E
Erich Gamma 已提交
18 19
}

20
suite('Filters', () => {
21
	test('or', () => {
22 23 24 25
		let filter: IFilter;
		let counters: number[];
		let newFilter = function (i: number, r: boolean): IFilter {
			return function (): IMatch[] { counters[i]++; return r as any; };
E
Erich Gamma 已提交
26 27
		};

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

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

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

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

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

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

73
	test('CamelCaseFilter', () => {
74 75 76 77 78 79
		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 已提交
80

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

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

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

157
	test('matchesSubString', () => {
158
		filterOk(matchesSubString, 'cmm', 'cancelAnimationFrame()', [
B
Benjamin Pasero 已提交
159 160 161 162
			{ start: 0, end: 1 },
			{ start: 9, end: 10 },
			{ start: 18, end: 19 }
		]);
163 164 165 166 167 168 169 170 171 172 173 174
		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');
B
Benjamin Pasero 已提交
175
	});
176

177
	test('WordFilter', () => {
178 179 180 181 182 183 184 185 186
		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 已提交
187
		filterOk(matchesWords, 'gp', 'Git: Pull', [{ start: 0, end: 1 }, { start: 5, end: 6 }]);
188
		filterOk(matchesWords, 'g p', 'Git: Pull', [{ start: 0, end: 1 }, { start: 3, end: 4 }, { start: 5, end: 6 }]);
J
Johannes Rieken 已提交
189
		filterOk(matchesWords, 'gipu', 'Git: Pull', [{ start: 0, end: 2 }, { start: 5, end: 7 }]);
190

J
Johannes Rieken 已提交
191
		filterOk(matchesWords, 'gp', 'Category: Git: Pull', [{ start: 10, end: 11 }, { start: 15, end: 16 }]);
192
		filterOk(matchesWords, 'g p', 'Category: Git: Pull', [{ start: 10, end: 11 }, { start: 13, end: 14 }, { start: 15, end: 16 }]);
J
Johannes Rieken 已提交
193
		filterOk(matchesWords, 'gipu', 'Category: Git: Pull', [{ start: 10, end: 12 }, { start: 15, end: 17 }]);
194 195 196 197 198

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

		filterOk(matchesWords, 'git: プル', 'git: プル', [{ start: 0, end: 7 }]);
199
		filterOk(matchesWords, 'git プル', 'git: プル', [{ start: 0, end: 4 }, { start: 5, end: 7 }]);
200 201

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

203 204
		// assert.ok(matchesWords('gipu', 'Category: Git: Pull', true) === null);
		// assert.deepEqual(matchesWords('pu', 'Category: Git: Pull', true), [{ start: 15, end: 17 }]);
205 206 207 208 209 210 211 212 213 214

		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');
215 216 217 218 219 220

		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');
221
	});
J
Johannes Rieken 已提交
222

223
	function assertMatches(pattern: string, word: string, decoratedWord: string | undefined, filter: FuzzyScorer, opts: { patternPos?: number, wordPos?: number, firstMatchCanBeWeak?: boolean } = {}) {
224
		let r = filter(pattern, pattern.toLowerCase(), opts.patternPos || 0, word, word.toLowerCase(), opts.wordPos || 0, opts.firstMatchCanBeWeak || false);
225
		assert.ok(!decoratedWord === !r);
226
		if (r) {
227
			let matches = createMatches(r);
228
			let actualWord = '';
229 230 231 232 233
			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;
J
Johannes Rieken 已提交
234
			}
235
			actualWord += word.substring(pos);
236
			assert.equal(actualWord, decoratedWord);
J
Johannes Rieken 已提交
237
		}
238
	}
J
Johannes Rieken 已提交
239

J
Johannes Rieken 已提交
240 241 242
	test('fuzzyScore, #23215', function () {
		assertMatches('tit', 'win.tit', 'win.^t^i^t', fuzzyScore);
		assertMatches('title', 'win.title', 'win.^t^i^t^l^e', fuzzyScore);
243
		assertMatches('WordCla', 'WordCharacterClassifier', '^W^o^r^dCharacter^C^l^assifier', fuzzyScore);
J
Johannes Rieken 已提交
244 245
		assertMatches('WordCCla', 'WordCharacterClassifier', '^W^o^r^d^Character^C^l^assifier', fuzzyScore);
	});
246

247 248 249
	test('fuzzyScore, #23332', function () {
		assertMatches('dete', '"editor.quickSuggestionsDelay"', undefined, fuzzyScore);
	});
J
Johannes Rieken 已提交
250

251 252 253 254 255
	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);
	});

256 257 258 259 260 261 262
	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');
	});

263 264 265 266 267
	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);
	});
268 269 270 271 272 273
	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);
	});
274

275
	test('fuzzyScore', () => {
276 277 278 279
		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);
280
		assertMatches('cmcm', 'camelCase', undefined, fuzzyScore);
281 282
		assertMatches('BK', 'the_black_knight', 'the_^black_^knight', fuzzyScore);
		assertMatches('KeyboardLayout=', 'KeyboardLayout', undefined, fuzzyScore);
283 284
		assertMatches('LLL', 'SVisualLoggerLogsList', 'SVisual^Logger^Logs^List', fuzzyScore);
		assertMatches('LLLL', 'SVilLoLosLi', undefined, fuzzyScore);
285
		assertMatches('LLLL', 'SVisualLoggerLogsList', undefined, fuzzyScore);
286 287
		assertMatches('TEdit', 'TextEdit', '^Text^E^d^i^t', fuzzyScore);
		assertMatches('TEdit', 'TextEditor', '^Text^E^d^i^tor', fuzzyScore);
288
		assertMatches('TEdit', 'Textedit', '^T^exte^d^i^t', fuzzyScore);
289 290 291 292
		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);
293 294 295 296 297 298 299 300
		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);
301 302
		assertMatches('form', 'editor.formatOnSave', 'editor.^f^o^r^matOnSave', fuzzyScore);
		assertMatches('g p', 'Git: Pull', '^Git:^ ^Pull', fuzzyScore);
303
		assertMatches('g p', 'Git: Pull', '^Git:^ ^Pull', fuzzyScore);
304
		assertMatches('gip', 'Git: Pull', '^G^it: ^Pull', fuzzyScore);
305 306 307
		assertMatches('gip', 'Git: Pull', '^G^it: ^Pull', fuzzyScore);
		assertMatches('gp', 'Git: Pull', '^Git: ^Pull', fuzzyScore);
		assertMatches('gp', 'Git_Git_Pull', '^Git_Git_^Pull', fuzzyScore);
308
		assertMatches('is', 'ImportStatement', '^Import^Statement', fuzzyScore);
309
		assertMatches('is', 'isValid', '^i^sValid', fuzzyScore);
J
Johannes Rieken 已提交
310
		assertMatches('lowrd', 'lowWord', '^l^o^wWo^r^d', fuzzyScore);
311 312 313 314 315 316
		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);
317
		assertMatches('Three', 'HTMLHRElement', undefined, fuzzyScore);
J
Johannes Rieken 已提交
318
		assertMatches('Three', 'Three', '^T^h^r^e^e', fuzzyScore);
319 320 321 322 323 324 325
		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);
326
	});
327

328
	test('fuzzyScore (first match can be weak)', function () {
329 330 331 332 333

		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');
334 335
	});

336 337 338 339 340 341 342 343 344 345
	test('fuzzyScore, many matches', function () {

		assertMatches(
			'aaaaaa',
			'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
			'^a^a^a^a^a^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
			fuzzyScore
		);
	});

346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
	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 }
		);
	});

376
	test('fuzzyScore, issue #26423', function () {
377 378 379

		assertMatches('baba', 'abababab', undefined, fuzzyScore);

380 381 382 383 384 385 386 387 388 389 390 391 392 393
		assertMatches(
			'fsfsfs',
			'dsafdsafdsafdsafdsafdsafdsafasdfdsa',
			undefined,
			fuzzyScore
		);
		assertMatches(
			'fsfsfsfsfsfsfsf',
			'dsafdsafdsafdsafdsafdsafdsafasdfdsafdsafdsafdsafdsfdsafdsfdfdfasdnfdsajfndsjnafjndsajlknfdsa',
			undefined,
			fuzzyScore
		);
	});

J
Johannes Rieken 已提交
394 395 396 397 398
	test('Fuzzy IntelliSense matching vs Haxe metadata completion, #26995', function () {
		assertMatches('f', ':Foo', ':^Foo', fuzzyScore);
		assertMatches('f', ':foo', ':^foo', fuzzyScore);
	});

J
Johannes Rieken 已提交
399 400 401 402
	test('Separator only match should not be weak #79558', function () {
		assertMatches('.', 'foo.bar', 'foo^.bar', fuzzyScore);
	});

J
Johannes Rieken 已提交
403 404 405
	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');
406
		fuzzyScore(pattern, pattern.toLowerCase(), 0, word, word.toLowerCase(), 0, false);
J
Johannes Rieken 已提交
407 408 409
		assert.ok(true); // must not explode
	});

410
	test('Vscode 1.12 no longer obeys \'sortText\' in completion items (from language server), #26096', function () {
411 412
		assertMatches('  ', '  group', undefined, fuzzyScore, { patternPos: 2 });
		assertMatches('  g', '  group', '  ^group', fuzzyScore, { patternPos: 2 });
413 414 415
		assertMatches('g', '  group', '  ^group', fuzzyScore);
		assertMatches('g g', '  groupGroup', undefined, fuzzyScore);
		assertMatches('g g', '  group Group', '  ^group^ ^Group', fuzzyScore);
416
		assertMatches(' g g', '  group Group', '  ^group^ ^Group', fuzzyScore, { patternPos: 1 });
417 418 419 420 421
		assertMatches('zz', 'zzGroup', '^z^zGroup', fuzzyScore);
		assertMatches('zzg', 'zzGroup', '^z^z^Group', fuzzyScore);
		assertMatches('g', 'zzGroup', 'zz^Group', fuzzyScore);
	});

J
Johannes Rieken 已提交
422 423 424
	test('patternPos isn\'t working correctly #79815', function () {
		assertMatches(':p'.substr(1), 'prop', '^prop', fuzzyScore, { patternPos: 0 });
		assertMatches(':p', 'prop', '^prop', fuzzyScore, { patternPos: 1 });
J
Johannes Rieken 已提交
425 426 427 428
		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 });
J
Johannes Rieken 已提交
429 430
	});

J
Johannes Rieken 已提交
431
	function assertTopScore(filter: typeof fuzzyScore, pattern: string, expected: number, ...words: string[]) {
432
		let topScore = -(100 * 10);
J
Johannes Rieken 已提交
433 434 435
		let topIdx = 0;
		for (let i = 0; i < words.length; i++) {
			const word = words[i];
436
			const m = filter(pattern, pattern.toLowerCase(), 0, word, word.toLowerCase(), 0, false);
J
Johannes Rieken 已提交
437 438 439 440 441
			if (m) {
				const [score] = m;
				if (score > topScore) {
					topScore = score;
					topIdx = i;
442 443 444
				}
			}
		}
J
Johannes Rieken 已提交
445 446 447 448 449 450 451
		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');
452

453 454
		// #24904
		assertTopScore(fuzzyScore, 'onMess', 1, 'onmessage', 'onMessage', 'onThisMegaEscape');
J
Johannes Rieken 已提交
455

J
Johannes Rieken 已提交
456 457 458 459
		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');
J
Johannes Rieken 已提交
460

461
		// issue #17836
J
Johannes Rieken 已提交
462
		// assertTopScore(fuzzyScore, 'TEdit', 1, 'TextEditorDecorationType', 'TextEdit', 'TextEditor');
463
		assertTopScore(fuzzyScore, 'p', 4, 'parse', 'posix', 'pafdsa', 'path', 'p');
J
Johannes Rieken 已提交
464
		assertTopScore(fuzzyScore, 'pa', 0, 'parse', 'pafdsa', 'path');
465 466

		// issue #14583
467
		assertTopScore(fuzzyScore, 'log', 3, 'HTMLOptGroupElement', 'ScrollLogicalPosition', 'SVGFEMorphologyElement', 'log', 'logger');
J
Johannes Rieken 已提交
468
		assertTopScore(fuzzyScore, 'e', 2, 'AbstractWorker', 'ActiveXObject', 'else');
469 470

		// issue #14446
J
Johannes Rieken 已提交
471
		assertTopScore(fuzzyScore, 'workbench.sideb', 1, 'workbench.editor.defaultSideBySideLayout', 'workbench.sideBar.location');
472 473

		// issue #11423
J
Johannes Rieken 已提交
474 475 476
		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');
477

J
Johannes Rieken 已提交
478
		assertTopScore(fuzzyScore, '-mo', 1, '-ms-ime-mode', '-moz-columns');
479
		// // dupe, issue #14861
J
Johannes Rieken 已提交
480
		assertTopScore(fuzzyScore, 'convertModelPosition', 0, 'convertModelPositionToViewPosition', 'convertViewToModelPosition');
481
		// // dupe, issue #14942
J
Johannes Rieken 已提交
482
		assertTopScore(fuzzyScore, 'is', 0, 'isValidViewletId', 'import statement');
483

484
		assertTopScore(fuzzyScore, 'title', 1, 'files.trimTrailingWhitespace', 'window.title');
485 486

		assertTopScore(fuzzyScore, 'const', 1, 'constructor', 'const', 'cuOnstrul');
487
	});
488

J
Johannes Rieken 已提交
489 490 491 492 493
	test('Unexpected suggestion scoring, #28791', function () {
		assertTopScore(fuzzyScore, '_lines', 1, '_lineStarts', '_lines');
		assertTopScore(fuzzyScore, '_lines', 1, '_lineS', '_lines');
		assertTopScore(fuzzyScore, '_lineS', 0, '_lineS', '_lines');
	});
494

J
Johannes Rieken 已提交
495
	test('HTML closing tag proposal filtered out #38880', function () {
496 497 498
		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 });
J
Johannes Rieken 已提交
499 500
	});

501
	test('fuzzyScoreGraceful', () => {
502 503 504 505 506 507 508 509 510 511

		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);
	});
J
Johannes Rieken 已提交
512

513 514 515
	test('List highlight filter: Not all characters from match are highlighterd #66923', () => {
		assertMatches('foo', 'barbarbarbarbarbarbarbarbarbarbarbarbarbarbarbar_foo', 'barbarbarbarbarbarbarbarbarbarbarbarbarbarbarbar_^f^o^o', fuzzyScore);
	});
516 517 518 519 520 521 522 523 524 525 526 527 528 529 530

	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
		);
	});
J
Johannes Rieken 已提交
531 532 533 534 535

	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));
	});
J
Johannes Rieken 已提交
536 537 538 539 540

	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);
	});
E
Erich Gamma 已提交
541
});