Full codebase including API server (32 modules + routes), dashboard frontend, DashCA certificate distribution, installer script, and deployment skills.
290 lines
9.6 KiB
JavaScript
290 lines
9.6 KiB
JavaScript
const fc = require('fast-check');
|
|
const platformUtils = require('./platform-utils');
|
|
|
|
/**
|
|
* Feature: dashcaddy-installer, Property 1: OS Detection Accuracy
|
|
* For any supported platform (Windows, macOS, Linux), the installer should
|
|
* correctly detect the operating system and architecture.
|
|
* Validates: Requirements 1.1, 14.1, 14.2, 14.3
|
|
*/
|
|
describe('Property 1: OS Detection Accuracy', () => {
|
|
test('detectOS returns valid OS for any platform value', () => {
|
|
fc.assert(
|
|
fc.property(
|
|
fc.constantFrom('win32', 'darwin', 'linux', 'freebsd', 'openbsd', 'sunos', 'aix'),
|
|
(platform) => {
|
|
const originalPlatform = process.platform;
|
|
Object.defineProperty(process, 'platform', { value: platform, configurable: true });
|
|
|
|
const detectedOS = platformUtils.detectOS();
|
|
const validOSes = ['windows', 'macos', 'linux', 'unknown'];
|
|
const isValid = validOSes.includes(detectedOS);
|
|
|
|
// Restore original platform
|
|
Object.defineProperty(process, 'platform', { value: originalPlatform, configurable: true });
|
|
|
|
return isValid;
|
|
}
|
|
),
|
|
{ numRuns: 100 }
|
|
);
|
|
});
|
|
|
|
test('detectOS maps supported platforms correctly', () => {
|
|
const platformMappings = [
|
|
{ platform: 'win32', expected: 'windows' },
|
|
{ platform: 'darwin', expected: 'macos' },
|
|
{ platform: 'linux', expected: 'linux' }
|
|
];
|
|
|
|
platformMappings.forEach(({ platform, expected }) => {
|
|
const originalPlatform = process.platform;
|
|
Object.defineProperty(process, 'platform', { value: platform, configurable: true });
|
|
|
|
expect(platformUtils.detectOS()).toBe(expected);
|
|
|
|
Object.defineProperty(process, 'platform', { value: originalPlatform, configurable: true });
|
|
});
|
|
});
|
|
|
|
test('detectArchitecture always returns a non-empty string', () => {
|
|
fc.assert(
|
|
fc.property(
|
|
fc.constant(null), // We don't need to generate anything, just run the test
|
|
() => {
|
|
const arch = platformUtils.detectArchitecture();
|
|
return typeof arch === 'string' && arch.length > 0;
|
|
}
|
|
),
|
|
{ numRuns: 100 }
|
|
);
|
|
});
|
|
|
|
test('getPlatformInfo returns consistent data structure', () => {
|
|
fc.assert(
|
|
fc.property(
|
|
fc.constant(null),
|
|
() => {
|
|
const info = platformUtils.getPlatformInfo();
|
|
|
|
// Check all required fields exist
|
|
const hasAllFields =
|
|
typeof info.os === 'string' &&
|
|
typeof info.arch === 'string' &&
|
|
typeof info.shell === 'string' &&
|
|
typeof info.platform === 'string' &&
|
|
typeof info.hostname === 'string' &&
|
|
typeof info.homedir === 'string' &&
|
|
typeof info.defaultInstallPath === 'string' &&
|
|
typeof info.userInstallPath === 'string';
|
|
|
|
// Check that OS is valid
|
|
const validOSes = ['windows', 'macos', 'linux', 'unknown'];
|
|
const hasValidOS = validOSes.includes(info.os);
|
|
|
|
// Check that shell is valid
|
|
const validShells = ['powershell', 'bash', 'zsh'];
|
|
const hasValidShell = validShells.includes(info.shell);
|
|
|
|
return hasAllFields && hasValidOS && hasValidShell;
|
|
}
|
|
),
|
|
{ numRuns: 100 }
|
|
);
|
|
});
|
|
|
|
test('platform detection is deterministic', () => {
|
|
fc.assert(
|
|
fc.property(
|
|
fc.constant(null),
|
|
() => {
|
|
const info1 = platformUtils.getPlatformInfo();
|
|
const info2 = platformUtils.getPlatformInfo();
|
|
|
|
// Same platform should return same results
|
|
return (
|
|
info1.os === info2.os &&
|
|
info1.arch === info2.arch &&
|
|
info1.shell === info2.shell &&
|
|
info1.platform === info2.platform
|
|
);
|
|
}
|
|
),
|
|
{ numRuns: 100 }
|
|
);
|
|
});
|
|
});
|
|
|
|
/**
|
|
* Feature: dashcaddy-installer, Property 18: Platform-Specific Path Handling
|
|
* For any detected operating system, the installer should use the correct
|
|
* default installation path and path separator for that platform.
|
|
* Validates: Requirements 2.1, 14.1, 14.2, 14.3, 14.6
|
|
*/
|
|
describe('Property 18: Platform-Specific Path Handling', () => {
|
|
test('getDefaultInstallPath returns platform-appropriate paths', () => {
|
|
const testCases = [
|
|
{ platform: 'win32', shouldContain: 'C:\\', shouldNotContain: '/' },
|
|
{ platform: 'darwin', shouldContain: '/Applications', shouldNotContain: '\\' },
|
|
{ platform: 'linux', shouldContain: '/opt', shouldNotContain: '\\' }
|
|
];
|
|
|
|
testCases.forEach(({ platform, shouldContain, shouldNotContain }) => {
|
|
const originalPlatform = process.platform;
|
|
Object.defineProperty(process, 'platform', { value: platform, configurable: true });
|
|
|
|
const path = platformUtils.getDefaultInstallPath();
|
|
expect(path).toContain(shouldContain);
|
|
if (shouldNotContain) {
|
|
expect(path).not.toContain(shouldNotContain);
|
|
}
|
|
|
|
Object.defineProperty(process, 'platform', { value: originalPlatform, configurable: true });
|
|
});
|
|
});
|
|
|
|
test('normalizePath handles any path string', () => {
|
|
fc.assert(
|
|
fc.property(
|
|
fc.string(),
|
|
(pathStr) => {
|
|
try {
|
|
const normalized = platformUtils.normalizePath(pathStr);
|
|
return typeof normalized === 'string';
|
|
} catch (error) {
|
|
// Some strings might be invalid paths, that's okay
|
|
return true;
|
|
}
|
|
}
|
|
),
|
|
{ numRuns: 100 }
|
|
);
|
|
});
|
|
|
|
test('joinPath produces valid paths for any segments', () => {
|
|
fc.assert(
|
|
fc.property(
|
|
fc.array(fc.string({ minLength: 1, maxLength: 20 }), { minLength: 1, maxLength: 5 }),
|
|
(segments) => {
|
|
try {
|
|
const joined = platformUtils.joinPath(...segments);
|
|
return typeof joined === 'string' && joined.length > 0;
|
|
} catch (error) {
|
|
// Some combinations might be invalid, that's okay
|
|
return true;
|
|
}
|
|
}
|
|
),
|
|
{ numRuns: 100 }
|
|
);
|
|
});
|
|
|
|
test('getUserInstallPath always includes DashCaddy', () => {
|
|
fc.assert(
|
|
fc.property(
|
|
fc.constant(null),
|
|
() => {
|
|
const userPath = platformUtils.getUserInstallPath();
|
|
return userPath.includes('DashCaddy');
|
|
}
|
|
),
|
|
{ numRuns: 100 }
|
|
);
|
|
});
|
|
});
|
|
|
|
/**
|
|
* Feature: dashcaddy-installer, Property 19: Platform-Specific Shell Selection
|
|
* For any detected operating system, the installer should use the appropriate
|
|
* shell (PowerShell on Windows, bash/zsh on Unix-like systems) for executing commands.
|
|
* Validates: Requirements 14.7
|
|
*/
|
|
describe('Property 19: Platform-Specific Shell Selection', () => {
|
|
test('detectShell returns valid shell for any platform', () => {
|
|
fc.assert(
|
|
fc.property(
|
|
fc.constantFrom('win32', 'darwin', 'linux'),
|
|
(platform) => {
|
|
const originalPlatform = process.platform;
|
|
Object.defineProperty(process, 'platform', { value: platform, configurable: true });
|
|
|
|
const shell = platformUtils.detectShell();
|
|
const validShells = ['powershell', 'bash', 'zsh'];
|
|
const isValid = validShells.includes(shell);
|
|
|
|
Object.defineProperty(process, 'platform', { value: originalPlatform, configurable: true });
|
|
|
|
return isValid;
|
|
}
|
|
),
|
|
{ numRuns: 100 }
|
|
);
|
|
});
|
|
|
|
test('Windows always uses PowerShell', () => {
|
|
const originalPlatform = process.platform;
|
|
Object.defineProperty(process, 'platform', { value: 'win32', configurable: true });
|
|
|
|
expect(platformUtils.detectShell()).toBe('powershell');
|
|
|
|
Object.defineProperty(process, 'platform', { value: originalPlatform, configurable: true });
|
|
});
|
|
|
|
test('Unix-like systems use bash or zsh', () => {
|
|
const unixPlatforms = ['darwin', 'linux'];
|
|
|
|
unixPlatforms.forEach(platform => {
|
|
const originalPlatform = process.platform;
|
|
Object.defineProperty(process, 'platform', { value: platform, configurable: true });
|
|
|
|
const shell = platformUtils.detectShell();
|
|
expect(['bash', 'zsh']).toContain(shell);
|
|
|
|
Object.defineProperty(process, 'platform', { value: originalPlatform, configurable: true });
|
|
});
|
|
});
|
|
|
|
test('getCommandExecution returns valid structure for any command', () => {
|
|
fc.assert(
|
|
fc.property(
|
|
fc.string({ minLength: 1, maxLength: 100 }),
|
|
(command) => {
|
|
const exec = platformUtils.getCommandExecution(command);
|
|
|
|
return (
|
|
typeof exec === 'object' &&
|
|
typeof exec.shell === 'string' &&
|
|
Array.isArray(exec.args) &&
|
|
exec.args.length > 0 &&
|
|
exec.args.includes(command)
|
|
);
|
|
}
|
|
),
|
|
{ numRuns: 100 }
|
|
);
|
|
});
|
|
|
|
test('getCommandExecution uses correct shell for platform', () => {
|
|
const testCases = [
|
|
{ platform: 'win32', expectedShell: 'powershell.exe' },
|
|
{ platform: 'darwin', expectedShells: ['bash', 'zsh'] },
|
|
{ platform: 'linux', expectedShells: ['bash', 'zsh'] }
|
|
];
|
|
|
|
testCases.forEach(({ platform, expectedShell, expectedShells }) => {
|
|
const originalPlatform = process.platform;
|
|
Object.defineProperty(process, 'platform', { value: platform, configurable: true });
|
|
|
|
const exec = platformUtils.getCommandExecution('test');
|
|
|
|
if (expectedShell) {
|
|
expect(exec.shell).toBe(expectedShell);
|
|
} else if (expectedShells) {
|
|
expect(expectedShells).toContain(exec.shell);
|
|
}
|
|
|
|
Object.defineProperty(process, 'platform', { value: originalPlatform, configurable: true });
|
|
});
|
|
});
|
|
});
|