diff --git a/extensions/terminal-suggest/src/test/completions/cd.test.ts b/extensions/terminal-suggest/src/test/completions/cd.test.ts new file mode 100644 index 00000000000..1c669559d59 --- /dev/null +++ b/extensions/terminal-suggest/src/test/completions/cd.test.ts @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import 'mocha'; +import cdSpec from '../../completions/cd'; +import { testPaths, type ISuiteSpec } from '../helpers'; + +export const cdTestSuiteSpec: ISuiteSpec = { + name: 'cd', + completionSpecs: cdSpec, + availableCommands: 'cd', + testSpecs: [ + // Typing a path + { input: '.|', expectedCompletions: ['cd'], expectedResourceRequests: { type: 'both', cwd: testPaths.cwd } }, + { input: './|', expectedCompletions: ['cd'], expectedResourceRequests: { type: 'both', cwd: testPaths.cwd } }, + { input: './.|', expectedCompletions: ['cd'], expectedResourceRequests: { type: 'both', cwd: testPaths.cwd } }, + + // Typing the command + { input: 'c|', expectedCompletions: ['cd'], expectedResourceRequests: { type: 'both', cwd: testPaths.cwd } }, + { input: 'cd|', expectedCompletions: ['cd'], expectedResourceRequests: { type: 'both', cwd: testPaths.cwd } }, + + // Basic arguments + { input: 'cd |', expectedCompletions: ['~', '-'], expectedResourceRequests: { type: 'folders', cwd: testPaths.cwd } }, + { input: 'cd -|', expectedCompletions: ['-'], expectedResourceRequests: { type: 'folders', cwd: testPaths.cwd } }, + { input: 'cd ~|', expectedCompletions: ['~'], expectedResourceRequests: { type: 'folders', cwd: testPaths.cwd } }, + + // Relative paths + { input: 'cd c|', expectedResourceRequests: { type: 'folders', cwd: testPaths.cwd } }, + { input: 'cd child|', expectedResourceRequests: { type: 'folders', cwd: testPaths.cwd } }, + { input: 'cd .|', expectedResourceRequests: { type: 'folders', cwd: testPaths.cwd } }, + { input: 'cd ./|', expectedResourceRequests: { type: 'folders', cwd: testPaths.cwd } }, + { input: 'cd ./child|', expectedResourceRequests: { type: 'folders', cwd: testPaths.cwd } }, + { input: 'cd ..|', expectedResourceRequests: { type: 'folders', cwd: testPaths.cwd } }, + + // Relative directories (changes cwd due to /) + { input: 'cd child/|', expectedResourceRequests: { type: 'folders', cwd: testPaths.cwdChild } }, + { input: 'cd ../|', expectedResourceRequests: { type: 'folders', cwd: testPaths.cwdParent } }, + { input: 'cd ../sibling|', expectedResourceRequests: { type: 'folders', cwd: testPaths.cwdParent } }, + ] +}; diff --git a/extensions/terminal-suggest/src/test/completions/code-insiders.test.ts b/extensions/terminal-suggest/src/test/completions/code-insiders.test.ts new file mode 100644 index 00000000000..447772ad8b7 --- /dev/null +++ b/extensions/terminal-suggest/src/test/completions/code-insiders.test.ts @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import codeInsidersCompletionSpec from '../../completions/code-insiders'; +import type { ISuiteSpec } from '../helpers'; +import { createCodeTestSpecs } from './code.test'; + +export const codeInsidersTestSuite: ISuiteSpec = { + name: 'code-insiders', + completionSpecs: codeInsidersCompletionSpec, + availableCommands: 'code-insiders', + testSpecs: createCodeTestSpecs('code-insiders') +}; diff --git a/extensions/terminal-suggest/src/test/completions/code.test.ts b/extensions/terminal-suggest/src/test/completions/code.test.ts new file mode 100644 index 00000000000..f65cd2e4d5d --- /dev/null +++ b/extensions/terminal-suggest/src/test/completions/code.test.ts @@ -0,0 +1,58 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import 'mocha'; +import codeCompletionSpec from '../../completions/code'; +import { testPaths, type ISuiteSpec, type ITestSpec } from '../helpers'; + +export function createCodeTestSpecs(executable: string): ITestSpec[] { + const codeOptions = ['-', '--add', '--category', '--diff', '--disable-extension', '--disable-extensions', '--disable-gpu', '--enable-proposed-api', '--extensions-dir', '--goto', '--help', '--inspect-brk-extensions', '--inspect-extensions', '--install-extension', '--list-extensions', '--locale', '--log', '--max-memory', '--merge', '--new-window', '--pre-release', '--prof-startup', '--profile', '--reuse-window', '--show-versions', '--status', '--sync', '--telemetry', '--uninstall-extension', '--user-data-dir', '--verbose', '--version', '--wait', '-a', '-d', '-g', '-h', '-m', '-n', '-r', '-s', '-v', '-w']; + const localeOptions = ['bg', 'de', 'en', 'es', 'fr', 'hu', 'it', 'ja', 'ko', 'pt-br', 'ru', 'tr', 'zh-CN', 'zh-TW']; + const categoryOptions = ['azure', 'data science', 'debuggers', 'extension packs', 'education', 'formatters', 'keymaps', 'language packs', 'linters', 'machine learning', 'notebooks', 'programming languages', 'scm providers', 'snippets', 'testing', 'themes', 'visualization', 'other']; + const logOptions = ['critical', 'error', 'warn', 'info', 'debug', 'trace', 'off']; + const syncOptions = ['on', 'off']; + + const typingTests: ITestSpec[] = []; + for (let i = 1; i < executable.length; i++) { + const input = `${executable.slice(0, i)}|`; + typingTests.push({ input, expectedCompletions: [executable], expectedResourceRequests: input.endsWith(' ') ? undefined : { type: 'both', cwd: testPaths.cwd } }); + } + + return [ + // Typing the command + ...typingTests, + + // Basic arguments + { input: `${executable} |`, expectedCompletions: codeOptions }, + { input: `${executable} --locale |`, expectedCompletions: localeOptions }, + { input: `${executable} --diff |`, expectedResourceRequests: { type: 'files', cwd: testPaths.cwd } }, + { input: `${executable} --diff ./file1 |`, expectedResourceRequests: { type: 'files', cwd: testPaths.cwd } }, + { input: `${executable} --merge |`, expectedResourceRequests: { type: 'files', cwd: testPaths.cwd } }, + { input: `${executable} --merge ./file1 ./file2 |`, expectedResourceRequests: { type: 'files', cwd: testPaths.cwd } }, + { input: `${executable} --merge ./file1 ./file2 ./base |`, expectedResourceRequests: { type: 'files', cwd: testPaths.cwd } }, + { input: `${executable} --goto |`, expectedResourceRequests: { type: 'files', cwd: testPaths.cwd } }, + { input: `${executable} --user-data-dir |`, expectedResourceRequests: { type: 'folders', cwd: testPaths.cwd } }, + { input: `${executable} --profile |`, expectedResourceRequests: { type: 'both', cwd: testPaths.cwd } }, + { input: `${executable} --install-extension |`, expectedResourceRequests: { type: 'both', cwd: testPaths.cwd } }, + { input: `${executable} --uninstall-extension |`, expectedResourceRequests: { type: 'both', cwd: testPaths.cwd } }, + { input: `${executable} --log |`, expectedCompletions: logOptions }, + { input: `${executable} --sync |`, expectedCompletions: syncOptions }, + { input: `${executable} --extensions-dir |`, expectedResourceRequests: { type: 'folders', cwd: testPaths.cwd } }, + { input: `${executable} --list-extensions |`, expectedCompletions: codeOptions }, + { input: `${executable} --show-versions |`, expectedCompletions: codeOptions }, + { input: `${executable} --category |`, expectedCompletions: categoryOptions }, + { input: `${executable} --category a|`, expectedCompletions: categoryOptions.filter(c => c.startsWith('a')) }, + + // Middle of command + { input: `${executable} | --locale`, expectedCompletions: codeOptions }, + ]; +} + +export const codeTestSuite: ISuiteSpec = { + name: 'code', + completionSpecs: codeCompletionSpec, + availableCommands: 'code', + testSpecs: createCodeTestSpecs('code') +}; diff --git a/extensions/terminal-suggest/src/test/helpers.ts b/extensions/terminal-suggest/src/test/helpers.ts new file mode 100644 index 00000000000..3075022d541 --- /dev/null +++ b/extensions/terminal-suggest/src/test/helpers.ts @@ -0,0 +1,38 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import 'mocha'; +import * as vscode from 'vscode'; +import type { Uri } from 'vscode'; + +export interface ISuiteSpec { + name: string; + completionSpecs: Fig.Spec | Fig.Spec[]; + // TODO: This seems unnecessary, ideally getCompletionItemsFromSpecs would only consider the + // spec's completions + availableCommands: string | string[]; + testSpecs: ITestSpec[]; +} + +export interface ITestSpec { + input: string; + expectedResourceRequests?: { + type: 'files' | 'folders' | 'both'; + cwd: Uri; + }; + expectedCompletions?: string[]; +} + +const fixtureDir = vscode.Uri.joinPath(vscode.Uri.file(__dirname), '../../testWorkspace'); + +/** + * A default set of paths shared across tests. + */ +export const testPaths = { + fixtureDir, + cwdParent: vscode.Uri.joinPath(fixtureDir, 'parent'), + cwd: vscode.Uri.joinPath(fixtureDir, 'parent/home'), + cwdChild: vscode.Uri.joinPath(fixtureDir, 'parent/home/child'), +}; diff --git a/extensions/terminal-suggest/src/test/terminalSuggestMain.test.ts b/extensions/terminal-suggest/src/test/terminalSuggestMain.test.ts index 68a2abbb256..c84693144ee 100644 --- a/extensions/terminal-suggest/src/test/terminalSuggestMain.test.ts +++ b/extensions/terminal-suggest/src/test/terminalSuggestMain.test.ts @@ -3,82 +3,15 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as vscode from 'vscode'; import { deepStrictEqual, strictEqual } from 'assert'; import 'mocha'; -import { asArray, getCompletionItemsFromSpecs } from '../terminalSuggestMain'; -import cdSpec from '../completions/cd'; -import codeCompletionSpec from '../completions/code'; -import codeInsidersCompletionSpec from '../completions/code-insiders'; -import type { Uri } from 'vscode'; import { basename } from 'path'; +import { asArray, getCompletionItemsFromSpecs } from '../terminalSuggestMain'; import { getTokenType } from '../tokens'; - -const fixtureDir = vscode.Uri.joinPath(vscode.Uri.file(__dirname), '../../testWorkspace'); -const testCwdParent = vscode.Uri.joinPath(fixtureDir, 'parent'); -const testCwd = vscode.Uri.joinPath(fixtureDir, 'parent/home'); -const testCwdChild = vscode.Uri.joinPath(fixtureDir, 'parent/home/child'); - -interface ISuiteSpec { - name: string; - completionSpecs: Fig.Spec | Fig.Spec[]; - // TODO: This seems unnecessary, ideally getCompletionItemsFromSpecs would only consider the - // spec's completions - availableCommands: string | string[]; - testSpecs: ITestSpec2[]; -} - -interface ITestSpec2 { - input: string; - expectedResourceRequests?: { - type: 'files' | 'folders' | 'both'; - cwd: Uri; - }; - expectedCompletions?: string[]; -} - -function createCodeTestSpecs(executable: string): ITestSpec2[] { - const codeOptions = ['-', '--add', '--category', '--diff', '--disable-extension', '--disable-extensions', '--disable-gpu', '--enable-proposed-api', '--extensions-dir', '--goto', '--help', '--inspect-brk-extensions', '--inspect-extensions', '--install-extension', '--list-extensions', '--locale', '--log', '--max-memory', '--merge', '--new-window', '--pre-release', '--prof-startup', '--profile', '--reuse-window', '--show-versions', '--status', '--sync', '--telemetry', '--uninstall-extension', '--user-data-dir', '--verbose', '--version', '--wait', '-a', '-d', '-g', '-h', '-m', '-n', '-r', '-s', '-v', '-w']; - const localeOptions = ['bg', 'de', 'en', 'es', 'fr', 'hu', 'it', 'ja', 'ko', 'pt-br', 'ru', 'tr', 'zh-CN', 'zh-TW']; - const categoryOptions = ['azure', 'data science', 'debuggers', 'extension packs', 'education', 'formatters', 'keymaps', 'language packs', 'linters', 'machine learning', 'notebooks', 'programming languages', 'scm providers', 'snippets', 'testing', 'themes', 'visualization', 'other']; - const logOptions = ['critical', 'error', 'warn', 'info', 'debug', 'trace', 'off']; - const syncOptions = ['on', 'off']; - - const typingTests: ITestSpec2[] = []; - for (let i = 1; i < executable.length; i++) { - const input = `${executable.slice(0, i)}|`; - typingTests.push({ input, expectedCompletions: [executable], expectedResourceRequests: input.endsWith(' ') ? undefined : { type: 'both', cwd: testCwd } }); - } - - return [ - // Typing the command - ...typingTests, - - // Basic arguments - { input: `${executable} |`, expectedCompletions: codeOptions }, - { input: `${executable} --locale |`, expectedCompletions: localeOptions }, - { input: `${executable} --diff |`, expectedResourceRequests: { type: 'files', cwd: testCwd } }, - { input: `${executable} --diff ./file1 |`, expectedResourceRequests: { type: 'files', cwd: testCwd } }, - { input: `${executable} --merge |`, expectedResourceRequests: { type: 'files', cwd: testCwd } }, - { input: `${executable} --merge ./file1 ./file2 |`, expectedResourceRequests: { type: 'files', cwd: testCwd } }, - { input: `${executable} --merge ./file1 ./file2 ./base |`, expectedResourceRequests: { type: 'files', cwd: testCwd } }, - { input: `${executable} --goto |`, expectedResourceRequests: { type: 'files', cwd: testCwd } }, - { input: `${executable} --user-data-dir |`, expectedResourceRequests: { type: 'folders', cwd: testCwd } }, - { input: `${executable} --profile |`, expectedResourceRequests: { type: 'both', cwd: testCwd } }, - { input: `${executable} --install-extension |`, expectedResourceRequests: { type: 'both', cwd: testCwd } }, - { input: `${executable} --uninstall-extension |`, expectedResourceRequests: { type: 'both', cwd: testCwd } }, - { input: `${executable} --log |`, expectedCompletions: logOptions }, - { input: `${executable} --sync |`, expectedCompletions: syncOptions }, - { input: `${executable} --extensions-dir |`, expectedResourceRequests: { type: 'folders', cwd: testCwd } }, - { input: `${executable} --list-extensions |`, expectedCompletions: codeOptions }, - { input: `${executable} --show-versions |`, expectedCompletions: codeOptions }, - { input: `${executable} --category |`, expectedCompletions: categoryOptions }, - { input: `${executable} --category a|`, expectedCompletions: categoryOptions.filter(c => c.startsWith('a')) }, - - // Middle of command - { input: `${executable} | --locale`, expectedCompletions: codeOptions }, - ]; -} +import { cdTestSuiteSpec as cdTestSuite } from './completions/cd.test'; +import { codeTestSuite } from './completions/code.test'; +import { testPaths, type ISuiteSpec } from './helpers'; +import { codeInsidersTestSuite } from './completions/code-insiders.test'; const testSpecs2: ISuiteSpec[] = [ { @@ -86,56 +19,15 @@ const testSpecs2: ISuiteSpec[] = [ completionSpecs: [], availableCommands: [], testSpecs: [ - { input: '|', expectedCompletions: [], expectedResourceRequests: { type: 'both', cwd: testCwd } }, - { input: '|.', expectedCompletions: [], expectedResourceRequests: { type: 'both', cwd: testCwd } }, - { input: '|./', expectedCompletions: [], expectedResourceRequests: { type: 'both', cwd: testCwd } }, - { input: 'fakecommand |', expectedCompletions: [], expectedResourceRequests: { type: 'both', cwd: testCwd } }, + { input: '|', expectedCompletions: [], expectedResourceRequests: { type: 'both', cwd: testPaths.cwd } }, + { input: '|.', expectedCompletions: [], expectedResourceRequests: { type: 'both', cwd: testPaths.cwd } }, + { input: '|./', expectedCompletions: [], expectedResourceRequests: { type: 'both', cwd: testPaths.cwd } }, + { input: 'fakecommand |', expectedCompletions: [], expectedResourceRequests: { type: 'both', cwd: testPaths.cwd } }, ] }, - { - name: 'cd', - completionSpecs: cdSpec, - availableCommands: 'cd', - testSpecs: [ - // Typing a path - { input: '.|', expectedCompletions: ['cd'], expectedResourceRequests: { type: 'both', cwd: testCwd } }, - { input: './|', expectedCompletions: ['cd'], expectedResourceRequests: { type: 'both', cwd: testCwd } }, - { input: './.|', expectedCompletions: ['cd'], expectedResourceRequests: { type: 'both', cwd: testCwd } }, - // Typing the command - { input: 'c|', expectedCompletions: ['cd'], expectedResourceRequests: { type: 'both', cwd: testCwd } }, - { input: 'cd|', expectedCompletions: ['cd'], expectedResourceRequests: { type: 'both', cwd: testCwd } }, - - // Basic arguments - { input: 'cd |', expectedCompletions: ['~', '-'], expectedResourceRequests: { type: 'folders', cwd: testCwd } }, - { input: 'cd -|', expectedCompletions: ['-'], expectedResourceRequests: { type: 'folders', cwd: testCwd } }, - { input: 'cd ~|', expectedCompletions: ['~'], expectedResourceRequests: { type: 'folders', cwd: testCwd } }, - - // Relative paths - { input: 'cd c|', expectedResourceRequests: { type: 'folders', cwd: testCwd } }, - { input: 'cd child|', expectedResourceRequests: { type: 'folders', cwd: testCwd } }, - { input: 'cd .|', expectedResourceRequests: { type: 'folders', cwd: testCwd } }, - { input: 'cd ./|', expectedResourceRequests: { type: 'folders', cwd: testCwd } }, - { input: 'cd ./child|', expectedResourceRequests: { type: 'folders', cwd: testCwd } }, - { input: 'cd ..|', expectedResourceRequests: { type: 'folders', cwd: testCwd } }, - - // Relative directories (changes cwd due to /) - { input: 'cd child/|', expectedResourceRequests: { type: 'folders', cwd: testCwdChild } }, - { input: 'cd ../|', expectedResourceRequests: { type: 'folders', cwd: testCwdParent } }, - { input: 'cd ../sibling|', expectedResourceRequests: { type: 'folders', cwd: testCwdParent } }, - ] - }, - { - name: 'code', - completionSpecs: codeCompletionSpec, - availableCommands: 'code', - testSpecs: createCodeTestSpecs('code') - }, - { - name: 'code-insiders', - completionSpecs: codeInsidersCompletionSpec, - availableCommands: 'code-insiders', - testSpecs: createCodeTestSpecs('code-insiders') - } + cdTestSuite, + codeTestSuite, + codeInsidersTestSuite, ]; suite('Terminal Suggest', () => { @@ -147,7 +39,7 @@ suite('Terminal Suggest', () => { let expectedString = testSpec.expectedCompletions ? `[${testSpec.expectedCompletions.map(e => `'${e}'`).join(', ')}]` : '[]'; if (testSpec.expectedResourceRequests) { expectedString += ` + ${testSpec.expectedResourceRequests.type}`; - if (testSpec.expectedResourceRequests.cwd.fsPath !== testCwd.fsPath) { + if (testSpec.expectedResourceRequests.cwd.fsPath !== testPaths.cwd.fsPath) { expectedString += ` @ ${basename(testSpec.expectedResourceRequests.cwd.fsPath)}/`; } } @@ -158,7 +50,14 @@ suite('Terminal Suggest', () => { const filesRequested = testSpec.expectedResourceRequests?.type === 'files' || testSpec.expectedResourceRequests?.type === 'both'; const foldersRequested = testSpec.expectedResourceRequests?.type === 'folders' || testSpec.expectedResourceRequests?.type === 'both'; const terminalContext = { commandLine, cursorPosition }; - const result = await getCompletionItemsFromSpecs(completionSpecs, terminalContext, availableCommands.map(c => { return { label: c }; }), prefix, getTokenType(terminalContext, undefined), testCwd); + const result = await getCompletionItemsFromSpecs( + completionSpecs, + terminalContext, + availableCommands.map(c => { return { label: c }; }), + prefix, + getTokenType(terminalContext, undefined), + testPaths.cwd + ); deepStrictEqual(result.items.map(i => i.label).sort(), (testSpec.expectedCompletions ?? []).sort()); strictEqual(result.filesRequested, filesRequested); strictEqual(result.foldersRequested, foldersRequested);