Skip to content

Commit

Permalink
Add tests for simple completion model and fix bad sorting issue
Browse files Browse the repository at this point in the history
  • Loading branch information
Tyriar committed Feb 3, 2025
1 parent 1fec88a commit e07e4d6
Show file tree
Hide file tree
Showing 2 changed files with 205 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -195,9 +195,14 @@ export class SimpleCompletionModel {
return score;
}

// Sort files with the same score against each other specially
// Sort by underscore penalty (eg. `__init__/` should be penalized)
if (a.underscorePenalty !== b.underscorePenalty) {
return a.underscorePenalty - b.underscorePenalty;
}

// Sort files of the same name by extension
const isArg = leadingLineContent.includes(' ');
if (!isArg && a.fileExtLow.length > 0 && b.fileExtLow.length > 0) {
if (!isArg && a.labelLowExcludeFileExt === b.labelLowExcludeFileExt) {
// Then by label length ascending (excluding file extension if it's a file)
score = a.labelLowExcludeFileExt.length - b.labelLowExcludeFileExt.length;
if (score !== 0) {
Expand All @@ -215,11 +220,6 @@ export class SimpleCompletionModel {
}
}

// Sort by underscore penalty (eg. `__init__/` should be penalized)
if (a.underscorePenalty !== b.underscorePenalty) {
return a.underscorePenalty - b.underscorePenalty;
}

// Sort by folder depth (eg. `vscode/` should come before `vscode-.../`)
if (a.labelLowNormalizedPath && b.labelLowNormalizedPath) {
// Directories
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import assert from 'assert';
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';
import { LineContext, SimpleCompletionModel } from '../../browser/simpleCompletionModel.js';
import { SimpleCompletionItem, type ISimpleCompletion } from '../../browser/simpleCompletionItem.js';

function createItem(options: Partial<ISimpleCompletion>): SimpleCompletionItem {
return new SimpleCompletionItem({
...options,
label: options.label || 'defaultLabel',
provider: options.provider || 'defaultProvider',
replacementIndex: options.replacementIndex || 0,
replacementLength: options.replacementLength || 1,
});
}

function createFileItems(...labels: string[]): SimpleCompletionItem[] {
return labels.map(label => createItem({ label, isFile: true }));
}

function createFileItemsModel(...labels: string[]): SimpleCompletionModel {
return new SimpleCompletionModel(
createFileItems(...labels),
new LineContext('', 0)
);
}

function createFolderItems(...labels: string[]): SimpleCompletionItem[] {
return labels.map(label => createItem({ label, isDirectory: true }));
}

// function createFolderItemsModel(...labels: string[]): SimpleCompletionModel {
// return new SimpleCompletionModel(
// createFolderItems(...labels),
// new LineContext('', 0)
// );
// }

function assertItems(model: SimpleCompletionModel, labels: string[]): void {
assert.deepStrictEqual(model.items.map(i => i.completion.label), labels);
assert.strictEqual(model.items.length, labels.length); // sanity check
}

suite('SimpleCompletionModel', function () {
ensureNoDisposablesAreLeakedInTestSuite();

let model: SimpleCompletionModel;

test('should handle an empty list', function () {
model = new SimpleCompletionModel([], new LineContext('', 0));

assert.strictEqual(model.items.length, 0);
});

test('should handle a list with one item', function () {
model = new SimpleCompletionModel([
createItem({ label: 'a' }),
], new LineContext('', 0));

assert.strictEqual(model.items.length, 1);
assert.strictEqual(model.items[0].completion.label, 'a');
});

test('should sort alphabetically', function () {
model = new SimpleCompletionModel([
createItem({ label: 'b' }),
createItem({ label: 'z' }),
createItem({ label: 'a' }),
], new LineContext('', 0));

assert.strictEqual(model.items.length, 3);
assert.strictEqual(model.items[0].completion.label, 'a');
assert.strictEqual(model.items[1].completion.label, 'b');
assert.strictEqual(model.items[2].completion.label, 'z');
});

suite('files', () => {
test('should deprioritize files that start with underscore', function () {
assertItems(createFileItemsModel('_a', 'a', 'z'), ['a', 'z', '_a']);
});

test('should ignore the dot in dotfiles when sorting', function () {
assertItems(createFileItemsModel('b', '.a', 'a', '.b'), ['.a', 'a', 'b', '.b']);
});
});

suite('folders', () => {
});

suite('files and folders', () => {
test('should handle many files and folders correctly', function () {
// This is VS Code's root directory with some python items added that have special
// sorting
const items = [
...createFolderItems(
'__pycache',
'.build',
'.configurations',
'.devcontainer',
'.eslint-plugin-local',
'.github',
'.profile-oss',
'.vscode',
'.vscode-test',
'build',
'cli',
'extensions',
'node_modules',
'out',
'remote',
'resources',
'scripts',
'src',
'test',
),
...createFileItems(
'__init__.py',
'.editorconfig',
'.eslint-ignore',
'.git-blame-ignore-revs',
'.gitattributes',
'.gitignore',
'.lsifrc.json',
'.mailmap',
'.mention-bot',
'.npmrc',
'.nvmrc',
'.vscode-test.js',
'cglicenses.json',
'cgmanifest.json',
'CodeQL.yml',
'CONTRIBUTING.md',
'eslint.config.js',
'gulpfile.js',
'LICENSE.txt',
'package-lock.json',
'package.json',
'product.json',
'README.md',
'SECURITY.md',
'ThirdPartyNotices.txt',
'tsfmt.json',
)
];
const model = new SimpleCompletionModel(items, new LineContext('', 0));
assertItems(model, [
'.build',
'build',
'cglicenses.json',
'cgmanifest.json',
'cli',
'CodeQL.yml',
'.configurations',
'CONTRIBUTING.md',
'.devcontainer',
'.npmrc',
'.gitignore',
'.editorconfig',
'eslint.config.js',
'.eslint-ignore',
'.eslint-plugin-local',
'extensions',
'.gitattributes',
'.git-blame-ignore-revs',
'.github',
'gulpfile.js',
'LICENSE.txt',
'.lsifrc.json',
'.nvmrc',
'.mailmap',
'.mention-bot',
'node_modules',
'out',
'package.json',
'package-lock.json',
'product.json',
'.profile-oss',
'README.md',
'remote',
'resources',
'scripts',
'SECURITY.md',
'src',
'test',
'ThirdPartyNotices.txt',
'tsfmt.json',
'.vscode',
'.vscode-test',
'.vscode-test.js',
'__init__.py',
'__pycache',
]);
});
});
});

0 comments on commit e07e4d6

Please sign in to comment.