This commit improves the handling of paths with spaces or special characters during script execution in the desktop application. Key improvements: - Paths are now quoted for macOS/Linux, addressing issues with whitespace or single quotes. - Windows paths are enclosed in double quotes to handle special characters. Other supporting changes: - Add more documentation for terminal execution commands. - Refactor terminal script file execution into a dedicated file for improved separation of concerns. - Refactor naming of `RuntimeEnvironment` to align with naming conventions (no interface with I prefix) and for clarity. - Refactor `TemporaryFileCodeRunner` to simplify it by removing the `os` parameter and handling OS-specific logic within the filename generator instead. - Refactor `fileName` to `filename` for consistency.
104 lines
3.8 KiB
TypeScript
104 lines
3.8 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { AllSupportedOperatingSystems, SupportedOperatingSystem } from '@tests/shared/TestCases/SupportedOperatingSystems';
|
|
import { OperatingSystem } from '@/domain/OperatingSystem';
|
|
import { OsTimestampedFilenameGenerator } from '@/infrastructure/CodeRunner/Filename/OsTimestampedFilenameGenerator';
|
|
import { formatAssertionMessage } from '@tests/shared/FormatAssertionMessage';
|
|
import { RuntimeEnvironmentStub } from '@tests/unit/shared/Stubs/RuntimeEnvironmentStub';
|
|
|
|
describe('OsTimestampedFilenameGenerator', () => {
|
|
describe('generateFilename', () => {
|
|
it('generates correct prefix', () => {
|
|
// arrange
|
|
const expectedPrefix = 'run';
|
|
// act
|
|
const filename = generateFilenamePartsForTesting();
|
|
// assert
|
|
expect(filename.prefix).to.equal(expectedPrefix);
|
|
});
|
|
it('generates correct timestamp', () => {
|
|
// arrange
|
|
const currentDate = '2023-01-01T12:00:00.000Z';
|
|
const expectedTimestamp = '2023-01-01_12-00-00';
|
|
const date = new Date(currentDate);
|
|
// act
|
|
const filename = generateFilenamePartsForTesting({ date });
|
|
// assert
|
|
expect(filename.timestamp).to.equal(expectedTimestamp, formatAssertionMessage[
|
|
`Generated file name: ${filename.generatedFileName}`
|
|
]);
|
|
});
|
|
describe('generates correct extension', () => {
|
|
const testScenarios: Record<SupportedOperatingSystem, string> = {
|
|
[OperatingSystem.Windows]: 'bat',
|
|
[OperatingSystem.Linux]: 'sh',
|
|
[OperatingSystem.macOS]: 'sh',
|
|
};
|
|
AllSupportedOperatingSystems.forEach((operatingSystem) => {
|
|
it(`on ${OperatingSystem[operatingSystem]}`, () => {
|
|
// arrange
|
|
const expectedExtension = testScenarios[operatingSystem];
|
|
// act
|
|
const filename = generateFilenamePartsForTesting({ operatingSystem });
|
|
// assert
|
|
expect(filename.extension).to.equal(expectedExtension, formatAssertionMessage[
|
|
`Generated file name: ${filename.generatedFileName}`
|
|
]);
|
|
});
|
|
});
|
|
});
|
|
describe('generates filename without extension for unknown OS', () => {
|
|
// arrange
|
|
const testScenarios: ReadonlyArray<{
|
|
readonly description: string;
|
|
readonly unknownOs?: OperatingSystem;
|
|
}> = [
|
|
{
|
|
description: 'unsupported OS',
|
|
unknownOs: 'Unsupported' as unknown as OperatingSystem,
|
|
},
|
|
{
|
|
description: 'undefined OS',
|
|
unknownOs: undefined,
|
|
},
|
|
];
|
|
testScenarios.forEach(({ description, unknownOs }) => {
|
|
it(description, () => {
|
|
// act
|
|
const filename = generateFilenamePartsForTesting({ operatingSystem: unknownOs });
|
|
// assert
|
|
expect(filename.extension).toBeUndefined();
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
interface TestFileNameComponents {
|
|
readonly prefix: string;
|
|
readonly timestamp: string;
|
|
readonly extension?: string;
|
|
readonly generatedFileName: string;
|
|
}
|
|
|
|
function generateFilenamePartsForTesting(testScenario?: {
|
|
operatingSystem?: OperatingSystem,
|
|
date?: Date,
|
|
}): TestFileNameComponents {
|
|
const date = testScenario?.date ?? new Date();
|
|
const sut = new OsTimestampedFilenameGenerator(
|
|
new RuntimeEnvironmentStub().withOs(testScenario?.operatingSystem),
|
|
);
|
|
const filename = sut.generateFilename(date);
|
|
const pattern = /^(?<prefix>[^-]+)-(?<timestamp>[^.]+)(?:\.(?<extension>[^.]+))?$/; // prefix-timestamp.extension
|
|
const match = filename.match(pattern);
|
|
if (!match?.groups?.prefix || !match?.groups?.timestamp) {
|
|
throw new Error(`Failed to parse prefix or timestamp: ${filename}`);
|
|
}
|
|
return {
|
|
generatedFileName: filename,
|
|
prefix: match.groups.prefix,
|
|
timestamp: match.groups.timestamp,
|
|
extension: match.groups.extension,
|
|
};
|
|
}
|