Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/base/test/common/fuzzyScorer.test.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import assert from 'assert';
7
import { compareItemsByFuzzyScore, FuzzyScore, FuzzyScore2, FuzzyScorerCache, IItemAccessor, IItemScore, pieceToQuery, prepareQuery, scoreFuzzy, scoreFuzzy2, scoreItemFuzzy } from '../../common/fuzzyScorer.js';
8
import { Schemas } from '../../common/network.js';
9
import { basename, dirname, posix, sep, win32 } from '../../common/path.js';
10
import { isWindows } from '../../common/platform.js';
11
import { URI } from '../../common/uri.js';
12
import { ensureNoDisposablesAreLeakedInTestSuite } from './utils.js';
13
14
class ResourceAccessorClass implements IItemAccessor<URI> {
15
16
getItemLabel(resource: URI): string {
17
return basename(resource.fsPath);
18
}
19
20
getItemDescription(resource: URI): string {
21
return dirname(resource.fsPath);
22
}
23
24
getItemPath(resource: URI): string {
25
return resource.fsPath;
26
}
27
}
28
29
const ResourceAccessor = new ResourceAccessorClass();
30
31
class ResourceWithSlashAccessorClass implements IItemAccessor<URI> {
32
33
getItemLabel(resource: URI): string {
34
return basename(resource.fsPath);
35
}
36
37
getItemDescription(resource: URI): string {
38
return posix.normalize(dirname(resource.path));
39
}
40
41
getItemPath(resource: URI): string {
42
return posix.normalize(resource.path);
43
}
44
}
45
46
const ResourceWithSlashAccessor = new ResourceWithSlashAccessorClass();
47
48
class ResourceWithBackslashAccessorClass implements IItemAccessor<URI> {
49
50
getItemLabel(resource: URI): string {
51
return basename(resource.fsPath);
52
}
53
54
getItemDescription(resource: URI): string {
55
return win32.normalize(dirname(resource.path));
56
}
57
58
getItemPath(resource: URI): string {
59
return win32.normalize(resource.path);
60
}
61
}
62
63
const ResourceWithBackslashAccessor = new ResourceWithBackslashAccessorClass();
64
65
class NullAccessorClass implements IItemAccessor<URI> {
66
67
getItemLabel(resource: URI): string {
68
return undefined!;
69
}
70
71
getItemDescription(resource: URI): string {
72
return undefined!;
73
}
74
75
getItemPath(resource: URI): string {
76
return undefined!;
77
}
78
}
79
80
function _doScore(target: string, query: string, allowNonContiguousMatches?: boolean): FuzzyScore {
81
const preparedQuery = prepareQuery(query);
82
83
return scoreFuzzy(target, preparedQuery.normalized, preparedQuery.normalizedLowercase, allowNonContiguousMatches ?? !preparedQuery.expectContiguousMatch);
84
}
85
86
function _doScore2(target: string, query: string, matchOffset: number = 0): FuzzyScore2 {
87
const preparedQuery = prepareQuery(query);
88
89
return scoreFuzzy2(target, preparedQuery, 0, matchOffset);
90
}
91
92
function scoreItem<T>(item: T, query: string, allowNonContiguousMatches: boolean, accessor: IItemAccessor<T>, cache: FuzzyScorerCache = Object.create(null)): IItemScore {
93
return scoreItemFuzzy(item, prepareQuery(query), allowNonContiguousMatches, accessor, cache);
94
}
95
96
function compareItemsByScore<T>(itemA: T, itemB: T, query: string, allowNonContiguousMatches: boolean, accessor: IItemAccessor<T>): number {
97
return compareItemsByFuzzyScore(itemA, itemB, prepareQuery(query), allowNonContiguousMatches, accessor, Object.create(null));
98
}
99
100
const NullAccessor = new NullAccessorClass();
101
102
suite('Fuzzy Scorer', () => {
103
104
test('score (fuzzy)', function () {
105
const target = 'HelLo-World';
106
107
const scores: FuzzyScore[] = [];
108
scores.push(_doScore(target, 'HelLo-World', true)); // direct case match
109
scores.push(_doScore(target, 'hello-world', true)); // direct mix-case match
110
scores.push(_doScore(target, 'HW', true)); // direct case prefix (multiple)
111
scores.push(_doScore(target, 'hw', true)); // direct mix-case prefix (multiple)
112
scores.push(_doScore(target, 'H', true)); // direct case prefix
113
scores.push(_doScore(target, 'h', true)); // direct mix-case prefix
114
scores.push(_doScore(target, 'W', true)); // direct case word prefix
115
scores.push(_doScore(target, 'Ld', true)); // in-string case match (multiple)
116
scores.push(_doScore(target, 'ld', true)); // in-string mix-case match (consecutive, avoids scattered hit)
117
scores.push(_doScore(target, 'w', true)); // direct mix-case word prefix
118
scores.push(_doScore(target, 'L', true)); // in-string case match
119
scores.push(_doScore(target, 'l', true)); // in-string mix-case match
120
scores.push(_doScore(target, '4', true)); // no match
121
122
// Assert scoring order
123
const sortedScores = scores.concat().sort((a, b) => b[0] - a[0]);
124
assert.deepStrictEqual(scores, sortedScores);
125
126
// Assert scoring positions
127
// let positions = scores[0][1];
128
// assert.strictEqual(positions.length, 'HelLo-World'.length);
129
130
// positions = scores[2][1];
131
// assert.strictEqual(positions.length, 'HW'.length);
132
// assert.strictEqual(positions[0], 0);
133
// assert.strictEqual(positions[1], 6);
134
});
135
136
test('score (non fuzzy)', function () {
137
const target = 'HelLo-World';
138
139
assert.ok(_doScore(target, 'HelLo-World', false)[0] > 0);
140
assert.strictEqual(_doScore(target, 'HelLo-World', false)[1].length, 'HelLo-World'.length);
141
142
assert.ok(_doScore(target, 'hello-world', false)[0] > 0);
143
assert.strictEqual(_doScore(target, 'HW', false)[0], 0);
144
assert.ok(_doScore(target, 'h', false)[0] > 0);
145
assert.ok(_doScore(target, 'ello', false)[0] > 0);
146
assert.ok(_doScore(target, 'ld', false)[0] > 0);
147
assert.strictEqual(_doScore(target, 'eo', false)[0], 0);
148
});
149
150
test('scoreItem - matches are proper', function () {
151
let res = scoreItem(null, 'something', true, ResourceAccessor);
152
assert.ok(!res.score);
153
154
const resource = URI.file('/xyz/some/path/someFile123.txt');
155
156
res = scoreItem(resource, 'something', true, NullAccessor);
157
assert.ok(!res.score);
158
159
// Path Identity
160
const identityRes = scoreItem(resource, ResourceAccessor.getItemPath(resource), true, ResourceAccessor);
161
assert.ok(identityRes.score);
162
assert.strictEqual(identityRes.descriptionMatch!.length, 1);
163
assert.strictEqual(identityRes.labelMatch!.length, 1);
164
assert.strictEqual(identityRes.descriptionMatch![0].start, 0);
165
assert.strictEqual(identityRes.descriptionMatch![0].end, ResourceAccessor.getItemDescription(resource).length);
166
assert.strictEqual(identityRes.labelMatch![0].start, 0);
167
assert.strictEqual(identityRes.labelMatch![0].end, ResourceAccessor.getItemLabel(resource).length);
168
169
// Basename Prefix
170
const basenamePrefixRes = scoreItem(resource, 'som', true, ResourceAccessor);
171
assert.ok(basenamePrefixRes.score);
172
assert.ok(!basenamePrefixRes.descriptionMatch);
173
assert.strictEqual(basenamePrefixRes.labelMatch!.length, 1);
174
assert.strictEqual(basenamePrefixRes.labelMatch![0].start, 0);
175
assert.strictEqual(basenamePrefixRes.labelMatch![0].end, 'som'.length);
176
177
// Basename Camelcase
178
const basenameCamelcaseRes = scoreItem(resource, 'sF', true, ResourceAccessor);
179
assert.ok(basenameCamelcaseRes.score);
180
assert.ok(!basenameCamelcaseRes.descriptionMatch);
181
assert.strictEqual(basenameCamelcaseRes.labelMatch!.length, 2);
182
assert.strictEqual(basenameCamelcaseRes.labelMatch![0].start, 0);
183
assert.strictEqual(basenameCamelcaseRes.labelMatch![0].end, 1);
184
assert.strictEqual(basenameCamelcaseRes.labelMatch![1].start, 4);
185
assert.strictEqual(basenameCamelcaseRes.labelMatch![1].end, 5);
186
187
// Basename Match
188
const basenameRes = scoreItem(resource, 'of', true, ResourceAccessor);
189
assert.ok(basenameRes.score);
190
assert.ok(!basenameRes.descriptionMatch);
191
assert.strictEqual(basenameRes.labelMatch!.length, 2);
192
assert.strictEqual(basenameRes.labelMatch![0].start, 1);
193
assert.strictEqual(basenameRes.labelMatch![0].end, 2);
194
assert.strictEqual(basenameRes.labelMatch![1].start, 4);
195
assert.strictEqual(basenameRes.labelMatch![1].end, 5);
196
197
// Path Match
198
const pathRes = scoreItem(resource, 'xyz123', true, ResourceAccessor);
199
assert.ok(pathRes.score);
200
assert.ok(pathRes.descriptionMatch);
201
assert.ok(pathRes.labelMatch);
202
assert.strictEqual(pathRes.labelMatch.length, 1);
203
assert.strictEqual(pathRes.labelMatch[0].start, 8);
204
assert.strictEqual(pathRes.labelMatch[0].end, 11);
205
assert.strictEqual(pathRes.descriptionMatch.length, 1);
206
assert.strictEqual(pathRes.descriptionMatch[0].start, 1);
207
assert.strictEqual(pathRes.descriptionMatch[0].end, 4);
208
209
// No Match
210
const noRes = scoreItem(resource, '987', true, ResourceAccessor);
211
assert.ok(!noRes.score);
212
assert.ok(!noRes.labelMatch);
213
assert.ok(!noRes.descriptionMatch);
214
215
// No Exact Match
216
const noExactRes = scoreItem(resource, '"sF"', true, ResourceAccessor);
217
assert.ok(!noExactRes.score);
218
assert.ok(!noExactRes.labelMatch);
219
assert.ok(!noExactRes.descriptionMatch);
220
assert.strictEqual(noRes.score, noExactRes.score);
221
222
// Verify Scores
223
assert.ok(identityRes.score > basenamePrefixRes.score);
224
assert.ok(basenamePrefixRes.score > basenameRes.score);
225
assert.ok(basenameRes.score > pathRes.score);
226
assert.ok(pathRes.score > noRes.score);
227
});
228
229
test('scoreItem - multiple', function () {
230
const resource = URI.file('/xyz/some/path/someFile123.txt');
231
232
const res1 = scoreItem(resource, 'xyz some', true, ResourceAccessor);
233
assert.ok(res1.score);
234
assert.strictEqual(res1.labelMatch?.length, 1);
235
assert.strictEqual(res1.labelMatch[0].start, 0);
236
assert.strictEqual(res1.labelMatch[0].end, 4);
237
assert.strictEqual(res1.descriptionMatch?.length, 1);
238
assert.strictEqual(res1.descriptionMatch[0].start, 1);
239
assert.strictEqual(res1.descriptionMatch[0].end, 4);
240
241
const res2 = scoreItem(resource, 'some xyz', true, ResourceAccessor);
242
assert.ok(res2.score);
243
assert.strictEqual(res1.score, res2.score);
244
assert.strictEqual(res2.labelMatch?.length, 1);
245
assert.strictEqual(res2.labelMatch[0].start, 0);
246
assert.strictEqual(res2.labelMatch[0].end, 4);
247
assert.strictEqual(res2.descriptionMatch?.length, 1);
248
assert.strictEqual(res2.descriptionMatch[0].start, 1);
249
assert.strictEqual(res2.descriptionMatch[0].end, 4);
250
251
const res3 = scoreItem(resource, 'some xyz file file123', true, ResourceAccessor);
252
assert.ok(res3.score);
253
assert.ok(res3.score > res2.score);
254
assert.strictEqual(res3.labelMatch?.length, 1);
255
assert.strictEqual(res3.labelMatch[0].start, 0);
256
assert.strictEqual(res3.labelMatch[0].end, 11);
257
assert.strictEqual(res3.descriptionMatch?.length, 1);
258
assert.strictEqual(res3.descriptionMatch[0].start, 1);
259
assert.strictEqual(res3.descriptionMatch[0].end, 4);
260
261
const res4 = scoreItem(resource, 'path z y', true, ResourceAccessor);
262
assert.ok(res4.score);
263
assert.ok(res4.score < res2.score);
264
assert.strictEqual(res4.labelMatch?.length, 0);
265
assert.strictEqual(res4.descriptionMatch?.length, 2);
266
assert.strictEqual(res4.descriptionMatch[0].start, 2);
267
assert.strictEqual(res4.descriptionMatch[0].end, 4);
268
assert.strictEqual(res4.descriptionMatch[1].start, 10);
269
assert.strictEqual(res4.descriptionMatch[1].end, 14);
270
});
271
272
test('scoreItem - multiple with cache yields different results', function () {
273
const resource = URI.file('/xyz/some/path/someFile123.txt');
274
const cache = {};
275
const res1 = scoreItem(resource, 'xyz sm', true, ResourceAccessor, cache);
276
assert.ok(res1.score);
277
278
// from the cache's perspective this should be a totally different query
279
const res2 = scoreItem(resource, 'xyz "sm"', true, ResourceAccessor, cache);
280
assert.ok(!res2.score);
281
});
282
283
test('scoreItem - invalid input', function () {
284
285
let res = scoreItem(null, null!, true, ResourceAccessor);
286
assert.strictEqual(res.score, 0);
287
288
res = scoreItem(null, 'null', true, ResourceAccessor);
289
assert.strictEqual(res.score, 0);
290
});
291
292
test('scoreItem - optimize for file paths', function () {
293
const resource = URI.file('/xyz/others/spath/some/xsp/file123.txt');
294
295
// xsp is more relevant to the end of the file path even though it matches
296
// fuzzy also in the beginning. we verify the more relevant match at the
297
// end gets returned.
298
const pathRes = scoreItem(resource, 'xspfile123', true, ResourceAccessor);
299
assert.ok(pathRes.score);
300
assert.ok(pathRes.descriptionMatch);
301
assert.ok(pathRes.labelMatch);
302
assert.strictEqual(pathRes.labelMatch.length, 1);
303
assert.strictEqual(pathRes.labelMatch[0].start, 0);
304
assert.strictEqual(pathRes.labelMatch[0].end, 7);
305
assert.strictEqual(pathRes.descriptionMatch.length, 1);
306
assert.strictEqual(pathRes.descriptionMatch[0].start, 23);
307
assert.strictEqual(pathRes.descriptionMatch[0].end, 26);
308
});
309
310
test('scoreItem - avoid match scattering (bug #36119)', function () {
311
const resource = URI.file('projects/ui/cula/ats/target.mk');
312
313
const pathRes = scoreItem(resource, 'tcltarget.mk', true, ResourceAccessor);
314
assert.ok(pathRes.score);
315
assert.ok(pathRes.descriptionMatch);
316
assert.ok(pathRes.labelMatch);
317
assert.strictEqual(pathRes.labelMatch.length, 1);
318
assert.strictEqual(pathRes.labelMatch[0].start, 0);
319
assert.strictEqual(pathRes.labelMatch[0].end, 9);
320
});
321
322
test('scoreItem - prefers more compact matches', function () {
323
const resource = URI.file('/1a111d1/11a1d1/something.txt');
324
325
// expect "ad" to be matched towards the end of the file because the
326
// match is more compact
327
const res = scoreItem(resource, 'ad', true, ResourceAccessor);
328
assert.ok(res.score);
329
assert.ok(res.descriptionMatch);
330
assert.ok(!res.labelMatch!.length);
331
assert.strictEqual(res.descriptionMatch.length, 2);
332
assert.strictEqual(res.descriptionMatch[0].start, 11);
333
assert.strictEqual(res.descriptionMatch[0].end, 12);
334
assert.strictEqual(res.descriptionMatch[1].start, 13);
335
assert.strictEqual(res.descriptionMatch[1].end, 14);
336
});
337
338
test('scoreItem - proper target offset', function () {
339
const resource = URI.file('etem');
340
341
const res = scoreItem(resource, 'teem', true, ResourceAccessor);
342
assert.ok(!res.score);
343
});
344
345
test('scoreItem - proper target offset #2', function () {
346
const resource = URI.file('ede');
347
348
const res = scoreItem(resource, 'de', true, ResourceAccessor);
349
350
assert.strictEqual(res.labelMatch!.length, 1);
351
assert.strictEqual(res.labelMatch![0].start, 1);
352
assert.strictEqual(res.labelMatch![0].end, 3);
353
});
354
355
test('scoreItem - proper target offset #3', function () {
356
const resource = URI.file('/src/vs/editor/browser/viewParts/lineNumbers/flipped-cursor-2x.svg');
357
358
const res = scoreItem(resource, 'debug', true, ResourceAccessor);
359
360
assert.strictEqual(res.descriptionMatch!.length, 3);
361
assert.strictEqual(res.descriptionMatch![0].start, 9);
362
assert.strictEqual(res.descriptionMatch![0].end, 10);
363
assert.strictEqual(res.descriptionMatch![1].start, 36);
364
assert.strictEqual(res.descriptionMatch![1].end, 37);
365
assert.strictEqual(res.descriptionMatch![2].start, 40);
366
assert.strictEqual(res.descriptionMatch![2].end, 41);
367
368
assert.strictEqual(res.labelMatch!.length, 2);
369
assert.strictEqual(res.labelMatch![0].start, 9);
370
assert.strictEqual(res.labelMatch![0].end, 10);
371
assert.strictEqual(res.labelMatch![1].start, 20);
372
assert.strictEqual(res.labelMatch![1].end, 21);
373
});
374
375
test('scoreItem - no match unless query contained in sequence', function () {
376
const resource = URI.file('abcde');
377
378
const res = scoreItem(resource, 'edcda', true, ResourceAccessor);
379
assert.ok(!res.score);
380
});
381
382
test('scoreItem - match if using slash or backslash (local, remote resource)', function () {
383
const localResource = URI.file('abcde/super/duper');
384
const remoteResource = URI.from({ scheme: Schemas.vscodeRemote, path: 'abcde/super/duper' });
385
386
for (const resource of [localResource, remoteResource]) {
387
let res = scoreItem(resource, 'abcde\\super\\duper', true, ResourceAccessor);
388
assert.ok(res.score);
389
390
res = scoreItem(resource, 'abcde\\super\\duper', true, ResourceWithSlashAccessor);
391
assert.ok(res.score);
392
393
res = scoreItem(resource, 'abcde\\super\\duper', true, ResourceWithBackslashAccessor);
394
assert.ok(res.score);
395
396
res = scoreItem(resource, 'abcde/super/duper', true, ResourceAccessor);
397
assert.ok(res.score);
398
399
res = scoreItem(resource, 'abcde/super/duper', true, ResourceWithSlashAccessor);
400
assert.ok(res.score);
401
402
res = scoreItem(resource, 'abcde/super/duper', true, ResourceWithBackslashAccessor);
403
assert.ok(res.score);
404
}
405
});
406
407
test('scoreItem - ensure upper case bonus only applies on non-consecutive matches (bug #134723)', function () {
408
const resourceWithUpper = URI.file('ASDFasdfasdf');
409
const resourceAllLower = URI.file('asdfasdfasdf');
410
411
assert.ok(scoreItem(resourceAllLower, 'asdf', true, ResourceAccessor).score > scoreItem(resourceWithUpper, 'asdf', true, ResourceAccessor).score);
412
});
413
414
test('compareItemsByScore - identity', function () {
415
const resourceA = URI.file('/some/path/fileA.txt');
416
const resourceB = URI.file('/some/path/other/fileB.txt');
417
const resourceC = URI.file('/unrelated/some/path/other/fileC.txt');
418
419
// Full resource A path
420
let query = ResourceAccessor.getItemPath(resourceA);
421
422
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
423
assert.strictEqual(res[0], resourceA);
424
assert.strictEqual(res[1], resourceB);
425
assert.strictEqual(res[2], resourceC);
426
427
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
428
assert.strictEqual(res[0], resourceA);
429
assert.strictEqual(res[1], resourceB);
430
assert.strictEqual(res[2], resourceC);
431
432
// Full resource B path
433
query = ResourceAccessor.getItemPath(resourceB);
434
435
res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
436
assert.strictEqual(res[0], resourceB);
437
assert.strictEqual(res[1], resourceA);
438
assert.strictEqual(res[2], resourceC);
439
440
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
441
assert.strictEqual(res[0], resourceB);
442
assert.strictEqual(res[1], resourceA);
443
assert.strictEqual(res[2], resourceC);
444
});
445
446
test('compareFilesByScore - basename prefix', function () {
447
const resourceA = URI.file('/some/path/fileA.txt');
448
const resourceB = URI.file('/some/path/other/fileB.txt');
449
const resourceC = URI.file('/unrelated/some/path/other/fileC.txt');
450
451
// Full resource A basename
452
let query = ResourceAccessor.getItemLabel(resourceA);
453
454
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
455
assert.strictEqual(res[0], resourceA);
456
assert.strictEqual(res[1], resourceB);
457
assert.strictEqual(res[2], resourceC);
458
459
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
460
assert.strictEqual(res[0], resourceA);
461
assert.strictEqual(res[1], resourceB);
462
assert.strictEqual(res[2], resourceC);
463
464
// Full resource B basename
465
query = ResourceAccessor.getItemLabel(resourceB);
466
467
res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
468
assert.strictEqual(res[0], resourceB);
469
assert.strictEqual(res[1], resourceA);
470
assert.strictEqual(res[2], resourceC);
471
472
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
473
assert.strictEqual(res[0], resourceB);
474
assert.strictEqual(res[1], resourceA);
475
assert.strictEqual(res[2], resourceC);
476
});
477
478
test('compareFilesByScore - basename camelcase', function () {
479
const resourceA = URI.file('/some/path/fileA.txt');
480
const resourceB = URI.file('/some/path/other/fileB.txt');
481
const resourceC = URI.file('/unrelated/some/path/other/fileC.txt');
482
483
// resource A camelcase
484
let query = 'fA';
485
486
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
487
assert.strictEqual(res[0], resourceA);
488
assert.strictEqual(res[1], resourceB);
489
assert.strictEqual(res[2], resourceC);
490
491
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
492
assert.strictEqual(res[0], resourceA);
493
assert.strictEqual(res[1], resourceB);
494
assert.strictEqual(res[2], resourceC);
495
496
// resource B camelcase
497
query = 'fB';
498
499
res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
500
assert.strictEqual(res[0], resourceB);
501
assert.strictEqual(res[1], resourceA);
502
assert.strictEqual(res[2], resourceC);
503
504
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
505
assert.strictEqual(res[0], resourceB);
506
assert.strictEqual(res[1], resourceA);
507
assert.strictEqual(res[2], resourceC);
508
});
509
510
test('compareFilesByScore - basename scores', function () {
511
const resourceA = URI.file('/some/path/fileA.txt');
512
const resourceB = URI.file('/some/path/other/fileB.txt');
513
const resourceC = URI.file('/unrelated/some/path/other/fileC.txt');
514
515
// Resource A part of basename
516
let query = 'fileA';
517
518
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
519
assert.strictEqual(res[0], resourceA);
520
assert.strictEqual(res[1], resourceB);
521
assert.strictEqual(res[2], resourceC);
522
523
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
524
assert.strictEqual(res[0], resourceA);
525
assert.strictEqual(res[1], resourceB);
526
assert.strictEqual(res[2], resourceC);
527
528
// Resource B part of basename
529
query = 'fileB';
530
531
res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
532
assert.strictEqual(res[0], resourceB);
533
assert.strictEqual(res[1], resourceA);
534
assert.strictEqual(res[2], resourceC);
535
536
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
537
assert.strictEqual(res[0], resourceB);
538
assert.strictEqual(res[1], resourceA);
539
assert.strictEqual(res[2], resourceC);
540
});
541
542
test('compareFilesByScore - path scores', function () {
543
const resourceA = URI.file('/some/path/fileA.txt');
544
const resourceB = URI.file('/some/path/other/fileB.txt');
545
const resourceC = URI.file('/unrelated/some/path/other/fileC.txt');
546
547
// Resource A part of path
548
let query = 'pathfileA';
549
550
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
551
assert.strictEqual(res[0], resourceA);
552
assert.strictEqual(res[1], resourceB);
553
assert.strictEqual(res[2], resourceC);
554
555
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
556
assert.strictEqual(res[0], resourceA);
557
assert.strictEqual(res[1], resourceB);
558
assert.strictEqual(res[2], resourceC);
559
560
// Resource B part of path
561
query = 'pathfileB';
562
563
res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
564
assert.strictEqual(res[0], resourceB);
565
assert.strictEqual(res[1], resourceA);
566
assert.strictEqual(res[2], resourceC);
567
568
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
569
assert.strictEqual(res[0], resourceB);
570
assert.strictEqual(res[1], resourceA);
571
assert.strictEqual(res[2], resourceC);
572
});
573
574
test('compareFilesByScore - prefer shorter basenames', function () {
575
const resourceA = URI.file('/some/path/fileA.txt');
576
const resourceB = URI.file('/some/path/other/fileBLonger.txt');
577
const resourceC = URI.file('/unrelated/the/path/other/fileC.txt');
578
579
// Resource A part of path
580
const query = 'somepath';
581
582
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
583
assert.strictEqual(res[0], resourceA);
584
assert.strictEqual(res[1], resourceB);
585
assert.strictEqual(res[2], resourceC);
586
587
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
588
assert.strictEqual(res[0], resourceA);
589
assert.strictEqual(res[1], resourceB);
590
assert.strictEqual(res[2], resourceC);
591
});
592
593
test('compareFilesByScore - prefer shorter basenames (match on basename)', function () {
594
const resourceA = URI.file('/some/path/fileA.txt');
595
const resourceB = URI.file('/some/path/other/fileBLonger.txt');
596
const resourceC = URI.file('/unrelated/the/path/other/fileC.txt');
597
598
// Resource A part of path
599
const query = 'file';
600
601
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
602
assert.strictEqual(res[0], resourceA);
603
assert.strictEqual(res[1], resourceC);
604
assert.strictEqual(res[2], resourceB);
605
606
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
607
assert.strictEqual(res[0], resourceA);
608
assert.strictEqual(res[1], resourceC);
609
assert.strictEqual(res[2], resourceB);
610
});
611
612
test('compareFilesByScore - prefer shorter paths', function () {
613
const resourceA = URI.file('/some/path/fileA.txt');
614
const resourceB = URI.file('/some/path/other/fileB.txt');
615
const resourceC = URI.file('/unrelated/some/path/other/fileC.txt');
616
617
// Resource A part of path
618
const query = 'somepath';
619
620
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
621
assert.strictEqual(res[0], resourceA);
622
assert.strictEqual(res[1], resourceB);
623
assert.strictEqual(res[2], resourceC);
624
625
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
626
assert.strictEqual(res[0], resourceA);
627
assert.strictEqual(res[1], resourceB);
628
assert.strictEqual(res[2], resourceC);
629
});
630
631
test('compareFilesByScore - prefer shorter paths (bug #17443)', function () {
632
const resourceA = URI.file('config/test/t1.js');
633
const resourceB = URI.file('config/test.js');
634
const resourceC = URI.file('config/test/t2.js');
635
636
const query = 'co/te';
637
638
const res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
639
assert.strictEqual(res[0], resourceB);
640
assert.strictEqual(res[1], resourceA);
641
assert.strictEqual(res[2], resourceC);
642
});
643
644
test('compareFilesByScore - prefer matches in label over description if scores are otherwise equal', function () {
645
const resourceA = URI.file('parts/quick/arrow-left-dark.svg');
646
const resourceB = URI.file('parts/quickopen/quickopen.ts');
647
648
const query = 'partsquick';
649
650
const res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
651
assert.strictEqual(res[0], resourceB);
652
assert.strictEqual(res[1], resourceA);
653
});
654
655
test('compareFilesByScore - prefer camel case matches', function () {
656
const resourceA = URI.file('config/test/NullPointerException.java');
657
const resourceB = URI.file('config/test/nopointerexception.java');
658
659
for (const query of ['npe', 'NPE']) {
660
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
661
assert.strictEqual(res[0], resourceA);
662
assert.strictEqual(res[1], resourceB);
663
664
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
665
assert.strictEqual(res[0], resourceA);
666
assert.strictEqual(res[1], resourceB);
667
}
668
});
669
670
test('compareFilesByScore - prefer more compact camel case matches', function () {
671
const resourceA = URI.file('config/test/openthisAnythingHandler.js');
672
const resourceB = URI.file('config/test/openthisisnotsorelevantforthequeryAnyHand.js');
673
674
const query = 'AH';
675
676
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
677
assert.strictEqual(res[0], resourceB);
678
assert.strictEqual(res[1], resourceA);
679
680
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
681
assert.strictEqual(res[0], resourceB);
682
assert.strictEqual(res[1], resourceA);
683
});
684
685
test('compareFilesByScore - prefer more compact matches (label)', function () {
686
const resourceA = URI.file('config/test/examasdaple.js');
687
const resourceB = URI.file('config/test/exampleasdaasd.ts');
688
689
const query = 'xp';
690
691
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
692
assert.strictEqual(res[0], resourceB);
693
assert.strictEqual(res[1], resourceA);
694
695
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
696
assert.strictEqual(res[0], resourceB);
697
assert.strictEqual(res[1], resourceA);
698
});
699
700
test('compareFilesByScore - prefer more compact matches (path)', function () {
701
const resourceA = URI.file('config/test/examasdaple/file.js');
702
const resourceB = URI.file('config/test/exampleasdaasd/file.ts');
703
704
const query = 'xp';
705
706
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
707
assert.strictEqual(res[0], resourceB);
708
assert.strictEqual(res[1], resourceA);
709
710
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
711
assert.strictEqual(res[0], resourceB);
712
assert.strictEqual(res[1], resourceA);
713
});
714
715
test('compareFilesByScore - prefer more compact matches (label and path)', function () {
716
const resourceA = URI.file('config/example/thisfile.ts');
717
const resourceB = URI.file('config/24234243244/example/file.js');
718
719
const query = 'exfile';
720
721
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
722
assert.strictEqual(res[0], resourceB);
723
assert.strictEqual(res[1], resourceA);
724
725
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
726
assert.strictEqual(res[0], resourceB);
727
assert.strictEqual(res[1], resourceA);
728
});
729
730
test('compareFilesByScore - avoid match scattering (bug #34210)', function () {
731
const resourceA = URI.file('node_modules1/bundle/lib/model/modules/ot1/index.js');
732
const resourceB = URI.file('node_modules1/bundle/lib/model/modules/un1/index.js');
733
const resourceC = URI.file('node_modules1/bundle/lib/model/modules/modu1/index.js');
734
const resourceD = URI.file('node_modules1/bundle/lib/model/modules/oddl1/index.js');
735
736
let query = isWindows ? 'modu1\\index.js' : 'modu1/index.js';
737
738
let res = [resourceA, resourceB, resourceC, resourceD].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
739
assert.strictEqual(res[0], resourceC);
740
741
res = [resourceC, resourceB, resourceA, resourceD].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
742
assert.strictEqual(res[0], resourceC);
743
744
query = isWindows ? 'un1\\index.js' : 'un1/index.js';
745
746
res = [resourceA, resourceB, resourceC, resourceD].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
747
assert.strictEqual(res[0], resourceB);
748
749
res = [resourceC, resourceB, resourceA, resourceD].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
750
assert.strictEqual(res[0], resourceB);
751
});
752
753
test('compareFilesByScore - avoid match scattering (bug #21019 1.)', function () {
754
const resourceA = URI.file('app/containers/Services/NetworkData/ServiceDetails/ServiceLoad/index.js');
755
const resourceB = URI.file('app/containers/Services/NetworkData/ServiceDetails/ServiceDistribution/index.js');
756
const resourceC = URI.file('app/containers/Services/NetworkData/ServiceDetailTabs/ServiceTabs/StatVideo/index.js');
757
758
const query = 'StatVideoindex';
759
760
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
761
assert.strictEqual(res[0], resourceC);
762
763
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
764
assert.strictEqual(res[0], resourceC);
765
});
766
767
test('compareFilesByScore - avoid match scattering (bug #21019 2.)', function () {
768
const resourceA = URI.file('src/build-helper/store/redux.ts');
769
const resourceB = URI.file('src/repository/store/redux.ts');
770
771
const query = 'reproreduxts';
772
773
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
774
assert.strictEqual(res[0], resourceB);
775
776
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
777
assert.strictEqual(res[0], resourceB);
778
});
779
780
test('compareFilesByScore - avoid match scattering (bug #26649)', function () {
781
const resourceA = URI.file('photobook/src/components/AddPagesButton/index.js');
782
const resourceB = URI.file('photobook/src/components/ApprovalPageHeader/index.js');
783
const resourceC = URI.file('photobook/src/canvasComponents/BookPage/index.js');
784
785
const query = 'bookpageIndex';
786
787
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
788
assert.strictEqual(res[0], resourceC);
789
790
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
791
assert.strictEqual(res[0], resourceC);
792
});
793
794
test('compareFilesByScore - avoid match scattering (bug #33247)', function () {
795
const resourceA = URI.file('ui/src/utils/constants.js');
796
const resourceB = URI.file('ui/src/ui/Icons/index.js');
797
798
const query = isWindows ? 'ui\\icons' : 'ui/icons';
799
800
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
801
assert.strictEqual(res[0], resourceB);
802
803
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
804
assert.strictEqual(res[0], resourceB);
805
});
806
807
test('compareFilesByScore - avoid match scattering (bug #33247 comment)', function () {
808
const resourceA = URI.file('ui/src/components/IDInput/index.js');
809
const resourceB = URI.file('ui/src/ui/Input/index.js');
810
811
const query = isWindows ? 'ui\\input\\index' : 'ui/input/index';
812
813
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
814
assert.strictEqual(res[0], resourceB);
815
816
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
817
assert.strictEqual(res[0], resourceB);
818
});
819
820
test('compareFilesByScore - avoid match scattering (bug #36166)', function () {
821
const resourceA = URI.file('django/contrib/sites/locale/ga/LC_MESSAGES/django.mo');
822
const resourceB = URI.file('django/core/signals.py');
823
824
const query = 'djancosig';
825
826
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
827
assert.strictEqual(res[0], resourceB);
828
829
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
830
assert.strictEqual(res[0], resourceB);
831
});
832
833
test('compareFilesByScore - avoid match scattering (bug #32918)', function () {
834
const resourceA = URI.file('adsys/protected/config.php');
835
const resourceB = URI.file('adsys/protected/framework/smarty/sysplugins/smarty_internal_config.php');
836
const resourceC = URI.file('duowanVideo/wap/protected/config.php');
837
838
const query = 'protectedconfig.php';
839
840
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
841
assert.strictEqual(res[0], resourceA);
842
assert.strictEqual(res[1], resourceC);
843
assert.strictEqual(res[2], resourceB);
844
845
res = [resourceC, resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
846
assert.strictEqual(res[0], resourceA);
847
assert.strictEqual(res[1], resourceC);
848
assert.strictEqual(res[2], resourceB);
849
});
850
851
test('compareFilesByScore - avoid match scattering (bug #14879)', function () {
852
const resourceA = URI.file('pkg/search/gradient/testdata/constraint_attrMatchString.yml');
853
const resourceB = URI.file('cmd/gradient/main.go');
854
855
const query = 'gradientmain';
856
857
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
858
assert.strictEqual(res[0], resourceB);
859
860
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
861
assert.strictEqual(res[0], resourceB);
862
});
863
864
test('compareFilesByScore - avoid match scattering (bug #14727 1)', function () {
865
const resourceA = URI.file('alpha-beta-cappa.txt');
866
const resourceB = URI.file('abc.txt');
867
868
const query = 'abc';
869
870
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
871
assert.strictEqual(res[0], resourceB);
872
873
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
874
assert.strictEqual(res[0], resourceB);
875
});
876
877
test('compareFilesByScore - avoid match scattering (bug #14727 2)', function () {
878
const resourceA = URI.file('xerxes-yak-zubba/index.js');
879
const resourceB = URI.file('xyz/index.js');
880
881
const query = 'xyz';
882
883
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
884
assert.strictEqual(res[0], resourceB);
885
886
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
887
assert.strictEqual(res[0], resourceB);
888
});
889
890
test('compareFilesByScore - avoid match scattering (bug #18381)', function () {
891
const resourceA = URI.file('AssymblyInfo.cs');
892
const resourceB = URI.file('IAsynchronousTask.java');
893
894
const query = 'async';
895
896
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
897
assert.strictEqual(res[0], resourceB);
898
899
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
900
assert.strictEqual(res[0], resourceB);
901
});
902
903
test('compareFilesByScore - avoid match scattering (bug #35572)', function () {
904
const resourceA = URI.file('static/app/source/angluar/-admin/-organization/-settings/layout/layout.js');
905
const resourceB = URI.file('static/app/source/angular/-admin/-project/-settings/_settings/settings.js');
906
907
const query = 'partisettings';
908
909
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
910
assert.strictEqual(res[0], resourceB);
911
912
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
913
assert.strictEqual(res[0], resourceB);
914
});
915
916
test('compareFilesByScore - avoid match scattering (bug #36810)', function () {
917
const resourceA = URI.file('Trilby.TrilbyTV.Web.Portal/Views/Systems/Index.cshtml');
918
const resourceB = URI.file('Trilby.TrilbyTV.Web.Portal/Areas/Admins/Views/Tips/Index.cshtml');
919
920
const query = 'tipsindex.cshtml';
921
922
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
923
assert.strictEqual(res[0], resourceB);
924
925
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
926
assert.strictEqual(res[0], resourceB);
927
});
928
929
test('compareFilesByScore - prefer shorter hit (bug #20546)', function () {
930
const resourceA = URI.file('editor/core/components/tests/list-view-spec.js');
931
const resourceB = URI.file('editor/core/components/list-view.js');
932
933
const query = 'listview';
934
935
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
936
assert.strictEqual(res[0], resourceB);
937
938
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
939
assert.strictEqual(res[0], resourceB);
940
});
941
942
test('compareFilesByScore - avoid match scattering (bug #12095)', function () {
943
const resourceA = URI.file('src/vs/workbench/contrib/files/common/explorerViewModel.ts');
944
const resourceB = URI.file('src/vs/workbench/contrib/files/browser/views/explorerView.ts');
945
const resourceC = URI.file('src/vs/workbench/contrib/files/browser/views/explorerViewer.ts');
946
947
const query = 'filesexplorerview.ts';
948
949
let res = [resourceA, resourceB, resourceC].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
950
assert.strictEqual(res[0], resourceB);
951
952
res = [resourceA, resourceC, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
953
assert.strictEqual(res[0], resourceB);
954
});
955
956
test('compareFilesByScore - prefer case match (bug #96122)', function () {
957
const resourceA = URI.file('lists.php');
958
const resourceB = URI.file('lib/Lists.php');
959
960
const query = 'Lists.php';
961
962
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
963
assert.strictEqual(res[0], resourceB);
964
965
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
966
assert.strictEqual(res[0], resourceB);
967
});
968
969
test('compareFilesByScore - prefer shorter match (bug #103052) - foo bar', function () {
970
const resourceA = URI.file('app/emails/foo.bar.js');
971
const resourceB = URI.file('app/emails/other-footer.other-bar.js');
972
973
for (const query of ['foo bar', 'foobar']) {
974
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
975
assert.strictEqual(res[0], resourceA);
976
assert.strictEqual(res[1], resourceB);
977
978
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
979
assert.strictEqual(res[0], resourceA);
980
assert.strictEqual(res[1], resourceB);
981
}
982
});
983
984
test('compareFilesByScore - prefer shorter match (bug #103052) - payment model', function () {
985
const resourceA = URI.file('app/components/payment/payment.model.js');
986
const resourceB = URI.file('app/components/online-payments-history/online-payments-history.model.js');
987
988
for (const query of ['payment model', 'paymentmodel']) {
989
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
990
assert.strictEqual(res[0], resourceA);
991
assert.strictEqual(res[1], resourceB);
992
993
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
994
assert.strictEqual(res[0], resourceA);
995
assert.strictEqual(res[1], resourceB);
996
}
997
});
998
999
test('compareFilesByScore - prefer shorter match (bug #103052) - color', function () {
1000
const resourceA = URI.file('app/constants/color.js');
1001
const resourceB = URI.file('app/components/model/input/pick-avatar-color.js');
1002
1003
for (const query of ['color js', 'colorjs']) {
1004
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
1005
assert.strictEqual(res[0], resourceA);
1006
assert.strictEqual(res[1], resourceB);
1007
1008
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
1009
assert.strictEqual(res[0], resourceA);
1010
assert.strictEqual(res[1], resourceB);
1011
}
1012
});
1013
1014
test('compareFilesByScore - prefer strict case prefix', function () {
1015
const resourceA = URI.file('app/constants/color.js');
1016
const resourceB = URI.file('app/components/model/input/Color.js');
1017
1018
let query = 'Color';
1019
1020
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
1021
assert.strictEqual(res[0], resourceB);
1022
assert.strictEqual(res[1], resourceA);
1023
1024
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
1025
assert.strictEqual(res[0], resourceB);
1026
assert.strictEqual(res[1], resourceA);
1027
1028
query = 'color';
1029
1030
res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
1031
assert.strictEqual(res[0], resourceA);
1032
assert.strictEqual(res[1], resourceB);
1033
1034
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
1035
assert.strictEqual(res[0], resourceA);
1036
assert.strictEqual(res[1], resourceB);
1037
});
1038
1039
test('compareFilesByScore - prefer prefix (bug #103052)', function () {
1040
const resourceA = URI.file('test/smoke/src/main.ts');
1041
const resourceB = URI.file('src/vs/editor/common/services/semantikTokensProviderStyling.ts');
1042
1043
const query = 'smoke main.ts';
1044
1045
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
1046
assert.strictEqual(res[0], resourceA);
1047
assert.strictEqual(res[1], resourceB);
1048
1049
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
1050
assert.strictEqual(res[0], resourceA);
1051
assert.strictEqual(res[1], resourceB);
1052
});
1053
1054
test('compareFilesByScore - boost better prefix match if multiple queries are used', function () {
1055
const resourceA = URI.file('src/vs/workbench/services/host/browser/browserHostService.ts');
1056
const resourceB = URI.file('src/vs/workbench/browser/workbench.ts');
1057
1058
for (const query of ['workbench.ts browser', 'browser workbench.ts', 'browser workbench', 'workbench browser']) {
1059
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
1060
assert.strictEqual(res[0], resourceB);
1061
assert.strictEqual(res[1], resourceA);
1062
1063
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
1064
assert.strictEqual(res[0], resourceB);
1065
assert.strictEqual(res[1], resourceA);
1066
}
1067
});
1068
1069
test('compareFilesByScore - boost shorter prefix match if multiple queries are used', function () {
1070
const resourceA = URI.file('src/vs/workbench/node/actions/windowActions.ts');
1071
const resourceB = URI.file('src/vs/workbench/electron-node/window.ts');
1072
1073
for (const query of ['window node', 'window.ts node']) {
1074
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
1075
assert.strictEqual(res[0], resourceB);
1076
assert.strictEqual(res[1], resourceA);
1077
1078
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
1079
assert.strictEqual(res[0], resourceB);
1080
assert.strictEqual(res[1], resourceA);
1081
}
1082
});
1083
1084
test('compareFilesByScore - skip preference on label match when using path sep', function () {
1085
const resourceA = URI.file('djangosite/ufrela/def.py');
1086
const resourceB = URI.file('djangosite/urls/default.py');
1087
1088
const query = 'url/def';
1089
1090
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
1091
assert.strictEqual(res[0], resourceB);
1092
assert.strictEqual(res[1], resourceA);
1093
1094
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
1095
assert.strictEqual(res[0], resourceB);
1096
assert.strictEqual(res[1], resourceA);
1097
});
1098
1099
test('compareFilesByScore - boost shorter prefix match if multiple queries are used (#99171)', function () {
1100
const resourceA = URI.file('mesh_editor_lifetime_job.h');
1101
const resourceB = URI.file('lifetime_job.h');
1102
1103
const query = 'm life, life m';
1104
1105
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
1106
assert.strictEqual(res[0], resourceB);
1107
assert.strictEqual(res[1], resourceA);
1108
1109
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
1110
assert.strictEqual(res[0], resourceB);
1111
assert.strictEqual(res[1], resourceA);
1112
});
1113
1114
test('compareFilesByScore - boost consecutive matches in the beginning over end', function () {
1115
const resourceA = URI.file('src/vs/server/node/extensionHostStatusService.ts');
1116
const resourceB = URI.file('src/vs/workbench/browser/parts/notifications/notificationsStatus.ts');
1117
1118
const query = 'notStatus';
1119
1120
let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
1121
assert.strictEqual(res[0], resourceB);
1122
assert.strictEqual(res[1], resourceA);
1123
1124
res = [resourceB, resourceA].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor));
1125
assert.strictEqual(res[0], resourceB);
1126
assert.strictEqual(res[1], resourceA);
1127
});
1128
1129
test('prepareQuery', () => {
1130
assert.strictEqual(prepareQuery(' f*a ').normalized, 'fa');
1131
assert.strictEqual(prepareQuery('model Tester.ts').original, 'model Tester.ts');
1132
assert.strictEqual(prepareQuery('model Tester.ts').originalLowercase, 'model Tester.ts'.toLowerCase());
1133
assert.strictEqual(prepareQuery('model Tester.ts').normalized, 'modelTester.ts');
1134
assert.strictEqual(prepareQuery('model Tester.ts').expectContiguousMatch, false); // doesn't have quotes in it
1135
assert.strictEqual(prepareQuery('Model Tester.ts').normalizedLowercase, 'modeltester.ts');
1136
assert.strictEqual(prepareQuery('ModelTester.ts').containsPathSeparator, false);
1137
assert.strictEqual(prepareQuery('Model' + sep + 'Tester.ts').containsPathSeparator, true);
1138
assert.strictEqual(prepareQuery('"hello"').expectContiguousMatch, true);
1139
assert.strictEqual(prepareQuery('"hello"').normalized, 'hello');
1140
1141
// with spaces
1142
let query = prepareQuery('He*llo World');
1143
assert.strictEqual(query.original, 'He*llo World');
1144
assert.strictEqual(query.normalized, 'HelloWorld');
1145
assert.strictEqual(query.normalizedLowercase, 'HelloWorld'.toLowerCase());
1146
assert.strictEqual(query.values?.length, 2);
1147
assert.strictEqual(query.values?.[0].original, 'He*llo');
1148
assert.strictEqual(query.values?.[0].normalized, 'Hello');
1149
assert.strictEqual(query.values?.[0].normalizedLowercase, 'Hello'.toLowerCase());
1150
assert.strictEqual(query.values?.[1].original, 'World');
1151
assert.strictEqual(query.values?.[1].normalized, 'World');
1152
assert.strictEqual(query.values?.[1].normalizedLowercase, 'World'.toLowerCase());
1153
1154
const restoredQuery = pieceToQuery(query.values);
1155
assert.strictEqual(restoredQuery.original, query.original);
1156
assert.strictEqual(restoredQuery.values?.length, query.values?.length);
1157
assert.strictEqual(restoredQuery.containsPathSeparator, query.containsPathSeparator);
1158
1159
// with spaces that are empty
1160
query = prepareQuery(' Hello World ');
1161
assert.strictEqual(query.original, ' Hello World ');
1162
assert.strictEqual(query.originalLowercase, ' Hello World '.toLowerCase());
1163
assert.strictEqual(query.normalized, 'HelloWorld');
1164
assert.strictEqual(query.normalizedLowercase, 'HelloWorld'.toLowerCase());
1165
assert.strictEqual(query.values?.length, 2);
1166
assert.strictEqual(query.values?.[0].original, 'Hello');
1167
assert.strictEqual(query.values?.[0].originalLowercase, 'Hello'.toLowerCase());
1168
assert.strictEqual(query.values?.[0].normalized, 'Hello');
1169
assert.strictEqual(query.values?.[0].normalizedLowercase, 'Hello'.toLowerCase());
1170
assert.strictEqual(query.values?.[1].original, 'World');
1171
assert.strictEqual(query.values?.[1].originalLowercase, 'World'.toLowerCase());
1172
assert.strictEqual(query.values?.[1].normalized, 'World');
1173
assert.strictEqual(query.values?.[1].normalizedLowercase, 'World'.toLowerCase());
1174
1175
// Path related
1176
if (isWindows) {
1177
assert.strictEqual(prepareQuery('C:\\some\\path').pathNormalized, 'C:\\some\\path');
1178
assert.strictEqual(prepareQuery('C:\\some\\path').normalized, 'C:\\some\\path');
1179
assert.strictEqual(prepareQuery('C:\\some\\path').containsPathSeparator, true);
1180
assert.strictEqual(prepareQuery('C:/some/path').pathNormalized, 'C:\\some\\path');
1181
assert.strictEqual(prepareQuery('C:/some/path').normalized, 'C:\\some\\path');
1182
assert.strictEqual(prepareQuery('C:/some/path').containsPathSeparator, true);
1183
} else {
1184
assert.strictEqual(prepareQuery('/some/path').pathNormalized, '/some/path');
1185
assert.strictEqual(prepareQuery('/some/path').normalized, '/some/path');
1186
assert.strictEqual(prepareQuery('/some/path').containsPathSeparator, true);
1187
assert.strictEqual(prepareQuery('\\some\\path').pathNormalized, '/some/path');
1188
assert.strictEqual(prepareQuery('\\some\\path').normalized, '/some/path');
1189
assert.strictEqual(prepareQuery('\\some\\path').containsPathSeparator, true);
1190
}
1191
});
1192
1193
test('fuzzyScore2 (matching)', function () {
1194
const target = 'HelLo-World';
1195
1196
for (const offset of [0, 3]) {
1197
let [score, matches] = _doScore2(offset === 0 ? target : `123${target}`, 'HelLo-World', offset);
1198
1199
assert.ok(score);
1200
assert.strictEqual(matches.length, 1);
1201
assert.strictEqual(matches[0].start, 0 + offset);
1202
assert.strictEqual(matches[0].end, target.length + offset);
1203
1204
[score, matches] = _doScore2(offset === 0 ? target : `123${target}`, 'HW', offset);
1205
1206
assert.ok(score);
1207
assert.strictEqual(matches.length, 2);
1208
assert.strictEqual(matches[0].start, 0 + offset);
1209
assert.strictEqual(matches[0].end, 1 + offset);
1210
assert.strictEqual(matches[1].start, 6 + offset);
1211
assert.strictEqual(matches[1].end, 7 + offset);
1212
}
1213
});
1214
1215
test('fuzzyScore2 (multiple queries)', function () {
1216
const target = 'HelLo-World';
1217
1218
const [firstSingleScore, firstSingleMatches] = _doScore2(target, 'HelLo');
1219
const [secondSingleScore, secondSingleMatches] = _doScore2(target, 'World');
1220
const firstAndSecondSingleMatches = [...firstSingleMatches || [], ...secondSingleMatches || []];
1221
1222
let [multiScore, multiMatches] = _doScore2(target, 'HelLo World');
1223
1224
function assertScore() {
1225
assert.ok(multiScore ?? 0 >= ((firstSingleScore ?? 0) + (secondSingleScore ?? 0)));
1226
for (let i = 0; multiMatches && i < multiMatches.length; i++) {
1227
const multiMatch = multiMatches[i];
1228
const firstAndSecondSingleMatch = firstAndSecondSingleMatches[i];
1229
1230
if (multiMatch && firstAndSecondSingleMatch) {
1231
assert.strictEqual(multiMatch.start, firstAndSecondSingleMatch.start);
1232
assert.strictEqual(multiMatch.end, firstAndSecondSingleMatch.end);
1233
} else {
1234
assert.fail();
1235
}
1236
}
1237
}
1238
1239
function assertNoScore() {
1240
assert.strictEqual(multiScore, undefined);
1241
assert.strictEqual(multiMatches.length, 0);
1242
}
1243
1244
assertScore();
1245
1246
[multiScore, multiMatches] = _doScore2(target, 'World HelLo');
1247
assertScore();
1248
1249
[multiScore, multiMatches] = _doScore2(target, 'World HelLo World');
1250
assertScore();
1251
1252
[multiScore, multiMatches] = _doScore2(target, 'World HelLo Nothing');
1253
assertNoScore();
1254
1255
[multiScore, multiMatches] = _doScore2(target, 'More Nothing');
1256
assertNoScore();
1257
});
1258
1259
test('fuzzyScore2 (#95716)', function () {
1260
const target = '# ❌ Wow';
1261
1262
const score = _doScore2(target, '❌');
1263
assert.ok(score);
1264
assert.ok(typeof score[0] === 'number');
1265
assert.ok(score[1].length > 0);
1266
});
1267
1268
test('Using quotes should expect contiguous matches match', function () {
1269
// missing the "i" in the query
1270
assert.strictEqual(_doScore('contiguous', '"contguous"')[0], 0);
1271
1272
const score = _doScore('contiguous', '"contiguous"');
1273
assert.ok(score[0] > 0);
1274
});
1275
1276
test('Using quotes should highlight contiguous indexes', function () {
1277
const score = _doScore('2021-7-26.md', '"26"');
1278
assert.strictEqual(score[0], 14);
1279
1280
// The indexes of the 2 and 6 of "26"
1281
assert.strictEqual(score[1][0], 7);
1282
assert.strictEqual(score[1][1], 8);
1283
});
1284
1285
ensureNoDisposablesAreLeakedInTestSuite();
1286
});
1287
1288