Skip to content
1 change: 1 addition & 0 deletions .github/instructions/testing-workflow.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -548,5 +548,6 @@ envConfig.inspect
- When fixing mock environment creation, use `null` to truly omit properties rather than `undefined` (1)
- Always recompile TypeScript after making import/export changes before running tests, as stubs won't work if they're applied to old compiled JavaScript that doesn't have the updated imports (2)
- Create proxy abstraction functions for Node.js APIs like `cp.spawn` to enable clean testing - use function overloads to preserve Node.js's intelligent typing while making the functions mockable (1)
- When a targeted test run yields 0 tests, first verify the compiled JS exists under `out/test` (rootDir is `src`); absence almost always means the test file sits outside `src` or compilation hasn't run yet (1)
- When unit tests fail with VS Code API errors like `TypeError: X is not a constructor` or `Cannot read properties of undefined (reading 'Y')`, check if VS Code APIs are properly mocked in `/src/test/unittests.ts` - add missing Task-related APIs (`Task`, `TaskScope`, `ShellExecution`, `TaskRevealKind`, `TaskPanelKind`) and namespace mocks (`tasks`) following the existing pattern of `mockedVSCode.X = vscodeMocks.vscMockExtHostedTypes.X` (1)
- Create minimal mock objects with only required methods and use TypeScript type assertions (e.g., mockApi as PythonEnvironmentApi) to satisfy interface requirements instead of implementing all interface methods when only specific methods are needed for the test (1)
158 changes: 158 additions & 0 deletions src/test/features/execution/execUtils.unit.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import * as assert from 'assert';
import { quoteArgs, quoteStringIfNecessary } from '../../../features/execution/execUtils';

suite('Execution Utils Tests', () => {
suite('quoteStringIfNecessary', () => {
test('should not quote string without spaces', () => {
const input = 'simplestring';
const result = quoteStringIfNecessary(input);
assert.strictEqual(result, 'simplestring');
});

test('should not quote string without spaces containing special characters', () => {
const input = 'path/to/file.txt';
const result = quoteStringIfNecessary(input);
assert.strictEqual(result, 'path/to/file.txt');
});

test('should quote string with spaces', () => {
const input = 'string with spaces';
const result = quoteStringIfNecessary(input);
assert.strictEqual(result, '"string with spaces"');
});

test('should quote path with spaces', () => {
const input = 'C:\\Program Files\\Python';
const result = quoteStringIfNecessary(input);
assert.strictEqual(result, '"C:\\Program Files\\Python"');
});

test('should not double-quote already quoted string', () => {
const input = '"already quoted"';
const result = quoteStringIfNecessary(input);
assert.strictEqual(result, '"already quoted"');
});

test('should not double-quote already quoted string with spaces', () => {
const input = '"string with spaces"';
const result = quoteStringIfNecessary(input);
assert.strictEqual(result, '"string with spaces"');
});

test('should quote string with space that is partially quoted', () => {
const input = '"partially quoted';
const result = quoteStringIfNecessary(input);
assert.strictEqual(result, '""partially quoted"');
});

test('should quote string with space that ends with quote', () => {
const input = 'partially quoted"';
const result = quoteStringIfNecessary(input);
assert.strictEqual(result, '"partially quoted""');
});

test('should handle empty string', () => {
const input = '';
const result = quoteStringIfNecessary(input);
assert.strictEqual(result, '');
});

test('should handle string with only spaces', () => {
const input = ' ';
const result = quoteStringIfNecessary(input);
assert.strictEqual(result, '" "');
});

test('should handle string with leading space', () => {
const input = ' leading';
const result = quoteStringIfNecessary(input);
assert.strictEqual(result, '" leading"');
});

test('should handle string with trailing space', () => {
const input = 'trailing ';
const result = quoteStringIfNecessary(input);
assert.strictEqual(result, '"trailing "');
});

test('should handle string with multiple spaces', () => {
const input = 'multiple spaces here';
const result = quoteStringIfNecessary(input);
assert.strictEqual(result, '"multiple spaces here"');
});

test('should not quote single character without space', () => {
const input = 'a';
const result = quoteStringIfNecessary(input);
assert.strictEqual(result, 'a');
});

test('should handle dash and hyphen characters without spaces', () => {
const input = '--flag-name';
const result = quoteStringIfNecessary(input);
assert.strictEqual(result, '--flag-name');
});
});

suite('quoteArgs', () => {
test('should return empty array for empty input', () => {
const input: string[] = [];
const result = quoteArgs(input);
assert.deepStrictEqual(result, []);
});

test('should not quote args without spaces', () => {
const input = ['arg1', 'arg2', 'arg3'];
const result = quoteArgs(input);
assert.deepStrictEqual(result, ['arg1', 'arg2', 'arg3']);
});

test('should quote args with spaces', () => {
const input = ['arg with spaces', 'another arg'];
const result = quoteArgs(input);
assert.deepStrictEqual(result, ['"arg with spaces"', '"another arg"']);
});

test('should handle mixed args with and without spaces', () => {
const input = ['simplearg', 'arg with spaces', 'anotherarg'];
const result = quoteArgs(input);
assert.deepStrictEqual(result, ['simplearg', '"arg with spaces"', 'anotherarg']);
});

test('should not double-quote already quoted args', () => {
const input = ['"already quoted"', 'normal'];
const result = quoteArgs(input);
assert.deepStrictEqual(result, ['"already quoted"', 'normal']);
});

test('should handle array with single element', () => {
const input = ['single element with space'];
const result = quoteArgs(input);
assert.deepStrictEqual(result, ['"single element with space"']);
});

test('should handle paths correctly', () => {
const input = ['C:\\Program Files\\Python', '/usr/bin/python', 'simple'];
const result = quoteArgs(input);
assert.deepStrictEqual(result, ['"C:\\Program Files\\Python"', '/usr/bin/python', 'simple']);
});

test('should handle command line flags and values', () => {
const input = ['--flag', 'value with spaces', '-f', 'normalvalue'];
const result = quoteArgs(input);
assert.deepStrictEqual(result, ['--flag', '"value with spaces"', '-f', 'normalvalue']);
});

test('should handle empty strings in array', () => {
const input = ['', 'arg1', ''];
const result = quoteArgs(input);
assert.deepStrictEqual(result, ['', 'arg1', '']);
});

test('should preserve order of arguments', () => {
const input = ['first', 'second with space', 'third', 'fourth with space'];
const result = quoteArgs(input);
assert.deepStrictEqual(result, ['first', '"second with space"', 'third', '"fourth with space"']);
});
});
});
Loading