diff --git a/src/utils/utils.test.ts b/src/utils/utils.test.ts new file mode 100644 index 0000000..125e3be --- /dev/null +++ b/src/utils/utils.test.ts @@ -0,0 +1,95 @@ +import { after, before } from 'node:test'; +import { strictEqual, throws } from 'assert'; + +import promiseSpawn from '@npmcli/promise-spawn'; +import sinon from 'sinon'; +import * as vscode from 'vscode'; + +import { + buildTypedDirectory, + checkNull, + createFileSystemObject, + focusFileExplorer, + runCommand, +} from './utils'; + +describe('Utils Tests', () => { + before(() => { + (promiseSpawn as unknown as jest.Mock).mockReset(); + // swap the showErrorMessage function with a console.error + vscode.window.showErrorMessage = ( + message: string, + ...items: T[] + ): Thenable => { + console.error(message); + return Promise.resolve(undefined); + }; + }); + + after(() => { + vscode.window.showInformationMessage('Test end!'); + }); + + describe('checkNull', () => { + it('should return the value if not null', () => { + const result = checkNull('test', 'Error message'); + strictEqual(result, 'test'); + }); + + it('should throw an error if value is null', () => { + throws(() => checkNull(null, 'Error message'), /Error message/); + }); + }); + + describe('buildTypedDirectory', () => { + it('should return a typed directory object', async () => { + const uri = vscode.Uri.file('/path/to/dir'); + const statStub = sinon.stub(vscode.workspace.fs, 'stat').resolves({ + type: vscode.FileType.Directory, + ctime: 0, + mtime: 0, + size: 0, + }); + const result = await buildTypedDirectory(uri); + strictEqual(result.name, 'dir'); + strictEqual(result.path, '/path/to/dir'); + strictEqual(result.type, vscode.FileType.Directory); + statStub.restore(); + }); + }); + + describe('createFileSystemObject', () => { + it('should create a FileSystemObject', () => { + const uri = vscode.Uri.file('/path/to/file'); + const result = createFileSystemObject('folder', vscode.FileType.File, uri, true); + strictEqual(result.resourceUri.path, '/path/to/file'); + }); + }); + + describe('focusFileExplorer', () => { + it('should execute revealInExplorer command', () => { + const uri = vscode.Uri.file('/path/to/file'); + const executeCommandStub = sinon.stub(vscode.commands, 'executeCommand'); + focusFileExplorer(uri); + strictEqual(executeCommandStub.calledWith('revealInExplorer', uri), true); + executeCommandStub.restore(); + }); + }); + + describe('runCommand', () => { + before(() => { + vscode.window.showErrorMessage = ( + message: string, + ...items: T[] + ): Thenable => { + console.error(message); + return Promise.resolve(undefined); + }; + }); + + it('should return stdout on success', async () => { + const result = await runCommand('git', ['status'], '.'); + // result.startsWith('On branch'); + }); + }); +}); diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 533afc8..1048c5f 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -1,10 +1,19 @@ import * as path from 'path'; +import promiseSpawn from '@npmcli/promise-spawn'; import * as vscode from 'vscode'; import { FileSystemObject } from '../types/FileSystemObject'; import type { ITypedDirectory } from '../types/TypedDirectory'; +export function checkNull(value: T | null | undefined, errorMessage: string): T { + if (value == null) { + vscode.window.showErrorMessage(errorMessage); + throw new Error(errorMessage); + } + return value; +} + export async function buildTypedDirectory( uri: vscode.Uri, name?: string, @@ -32,3 +41,19 @@ export function createFileSystemObject( export function focusFileExplorer(uri: vscode.Uri) { vscode.commands.executeCommand('revealInExplorer', uri); } + +export async function runCommand( + cmdPath: string, + safeArgs: string[], + repoPath: string, +): Promise { + try { + const res = await promiseSpawn(cmdPath, safeArgs, { cwd: repoPath }); + return res.stdout; + } catch (error: any) { + vscode.window.showErrorMessage( + `Error calling command "${cmdPath} ${safeArgs.join(' ')}" : ${error.message} - ${error.stderr}`, + ); + throw error; + } +}