Initial commit: DashCaddy v1.0
Full codebase including API server (32 modules + routes), dashboard frontend, DashCA certificate distribution, installer script, and deployment skills.
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
// Installation tiers
|
||||
const TIERS = {
|
||||
BASIC: 'basic',
|
||||
INTERMEDIATE: 'intermediate',
|
||||
ADVANCED: 'advanced'
|
||||
};
|
||||
|
||||
// Default installation paths by platform
|
||||
const DEFAULT_PATHS = {
|
||||
win32: 'C:\\Program Files\\DashCaddy',
|
||||
darwin: '/Applications/DashCaddy',
|
||||
linux: '/opt/dashcaddy'
|
||||
};
|
||||
|
||||
// Required subdirectories (matches production layout)
|
||||
const REQUIRED_DIRS = ['sites', 'sites/status', 'sites/status/assets', 'sites/dashcaddy-api'];
|
||||
|
||||
// Default ports
|
||||
const DEFAULT_PORTS = {
|
||||
API: 3001,
|
||||
CADDY_ADMIN: 2019
|
||||
};
|
||||
|
||||
// Error categories
|
||||
const ERROR_CATEGORIES = {
|
||||
CRITICAL: 'critical',
|
||||
RECOVERABLE: 'recoverable',
|
||||
NON_CRITICAL: 'non-critical',
|
||||
USER_ERROR: 'user-error'
|
||||
};
|
||||
|
||||
// Installation steps
|
||||
const INSTALLATION_STEPS = [
|
||||
{ id: 'welcome', label: 'Welcome' },
|
||||
{ id: 'dependencies', label: 'Dependencies' },
|
||||
{ id: 'folder', label: 'Installation Path' },
|
||||
{ id: 'tier', label: 'Deployment Tier' },
|
||||
{ id: 'dns', label: 'DNS Configuration' },
|
||||
{ id: 'dashboard', label: 'Dashboard Setup' },
|
||||
{ id: 'install', label: 'Installation' },
|
||||
{ id: 'complete', label: 'Complete' }
|
||||
];
|
||||
|
||||
module.exports = {
|
||||
TIERS,
|
||||
DEFAULT_PATHS,
|
||||
REQUIRED_DIRS,
|
||||
DEFAULT_PORTS,
|
||||
ERROR_CATEGORIES,
|
||||
INSTALLATION_STEPS
|
||||
};
|
||||
@@ -0,0 +1,174 @@
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
|
||||
/**
|
||||
* Detects the current operating system
|
||||
* @returns {string} 'windows', 'macos', or 'linux'
|
||||
*/
|
||||
function detectOS() {
|
||||
const platform = process.platform;
|
||||
|
||||
switch (platform) {
|
||||
case 'win32':
|
||||
return 'windows';
|
||||
case 'darwin':
|
||||
return 'macos';
|
||||
case 'linux':
|
||||
return 'linux';
|
||||
default:
|
||||
return 'unknown';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects the system architecture
|
||||
* @returns {string} 'x64', 'arm64', etc.
|
||||
*/
|
||||
function detectArchitecture() {
|
||||
return process.arch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects the appropriate shell for the platform
|
||||
* @returns {string} 'powershell', 'bash', or 'zsh'
|
||||
*/
|
||||
function detectShell() {
|
||||
const platform = process.platform;
|
||||
|
||||
if (platform === 'win32') {
|
||||
return 'powershell';
|
||||
}
|
||||
|
||||
// Check for zsh on macOS (default since Catalina)
|
||||
if (platform === 'darwin') {
|
||||
const shell = process.env.SHELL || '';
|
||||
if (shell.includes('zsh')) {
|
||||
return 'zsh';
|
||||
}
|
||||
return 'bash';
|
||||
}
|
||||
|
||||
// Linux typically uses bash
|
||||
return 'bash';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default installation path for the current platform
|
||||
* @returns {string} Default installation path
|
||||
*/
|
||||
function getDefaultInstallPath() {
|
||||
const platform = process.platform;
|
||||
|
||||
switch (platform) {
|
||||
case 'win32':
|
||||
return 'C:\\Program Files\\DashCaddy';
|
||||
case 'darwin':
|
||||
return '/Applications/DashCaddy';
|
||||
case 'linux':
|
||||
// Use /opt for system-wide or home directory for user install
|
||||
return '/opt/dashcaddy';
|
||||
default:
|
||||
return path.join(os.homedir(), 'DashCaddy');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the user's home directory installation path
|
||||
* @returns {string} User home installation path
|
||||
*/
|
||||
function getUserInstallPath() {
|
||||
return path.join(os.homedir(), 'DashCaddy');
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes a file path for the current platform
|
||||
* @param {string} filePath - Path to normalize
|
||||
* @returns {string} Normalized path
|
||||
*/
|
||||
function normalizePath(filePath) {
|
||||
return path.normalize(filePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins path segments using the correct separator for the platform
|
||||
* @param {...string} segments - Path segments to join
|
||||
* @returns {string} Joined path
|
||||
*/
|
||||
function joinPath(...segments) {
|
||||
return path.join(...segments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets platform-specific information
|
||||
* @returns {Object} Platform information
|
||||
*/
|
||||
function getPlatformInfo() {
|
||||
return {
|
||||
os: detectOS(),
|
||||
arch: detectArchitecture(),
|
||||
shell: detectShell(),
|
||||
platform: process.platform,
|
||||
hostname: os.hostname(),
|
||||
homedir: os.homedir(),
|
||||
defaultInstallPath: getDefaultInstallPath(),
|
||||
userInstallPath: getUserInstallPath()
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if running on Windows
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isWindows() {
|
||||
return process.platform === 'win32';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if running on macOS
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isMacOS() {
|
||||
return process.platform === 'darwin';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if running on Linux
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isLinux() {
|
||||
return process.platform === 'linux';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the command to execute based on platform
|
||||
* @param {string} command - Base command
|
||||
* @returns {Object} Command execution details
|
||||
*/
|
||||
function getCommandExecution(command) {
|
||||
if (isWindows()) {
|
||||
return {
|
||||
shell: 'powershell.exe',
|
||||
args: ['-Command', command]
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
shell: detectShell(),
|
||||
args: ['-c', command]
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
detectOS,
|
||||
detectArchitecture,
|
||||
detectShell,
|
||||
getDefaultInstallPath,
|
||||
getUserInstallPath,
|
||||
normalizePath,
|
||||
joinPath,
|
||||
getPlatformInfo,
|
||||
isWindows,
|
||||
isMacOS,
|
||||
isLinux,
|
||||
getCommandExecution
|
||||
};
|
||||
@@ -0,0 +1,289 @@
|
||||
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 });
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,195 @@
|
||||
const platformUtils = require('./platform-utils');
|
||||
|
||||
describe('Platform Detection', () => {
|
||||
describe('detectOS', () => {
|
||||
test('detects Windows correctly', () => {
|
||||
const originalPlatform = process.platform;
|
||||
Object.defineProperty(process, 'platform', { value: 'win32' });
|
||||
|
||||
expect(platformUtils.detectOS()).toBe('windows');
|
||||
|
||||
Object.defineProperty(process, 'platform', { value: originalPlatform });
|
||||
});
|
||||
|
||||
test('detects macOS correctly', () => {
|
||||
const originalPlatform = process.platform;
|
||||
Object.defineProperty(process, 'platform', { value: 'darwin' });
|
||||
|
||||
expect(platformUtils.detectOS()).toBe('macos');
|
||||
|
||||
Object.defineProperty(process, 'platform', { value: originalPlatform });
|
||||
});
|
||||
|
||||
test('detects Linux correctly', () => {
|
||||
const originalPlatform = process.platform;
|
||||
Object.defineProperty(process, 'platform', { value: 'linux' });
|
||||
|
||||
expect(platformUtils.detectOS()).toBe('linux');
|
||||
|
||||
Object.defineProperty(process, 'platform', { value: originalPlatform });
|
||||
});
|
||||
|
||||
test('returns unknown for unsupported platforms', () => {
|
||||
const originalPlatform = process.platform;
|
||||
Object.defineProperty(process, 'platform', { value: 'freebsd' });
|
||||
|
||||
expect(platformUtils.detectOS()).toBe('unknown');
|
||||
|
||||
Object.defineProperty(process, 'platform', { value: originalPlatform });
|
||||
});
|
||||
});
|
||||
|
||||
describe('detectArchitecture', () => {
|
||||
test('returns current architecture', () => {
|
||||
const arch = platformUtils.detectArchitecture();
|
||||
expect(typeof arch).toBe('string');
|
||||
expect(arch.length).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('detectShell', () => {
|
||||
test('returns powershell for Windows', () => {
|
||||
const originalPlatform = process.platform;
|
||||
Object.defineProperty(process, 'platform', { value: 'win32' });
|
||||
|
||||
expect(platformUtils.detectShell()).toBe('powershell');
|
||||
|
||||
Object.defineProperty(process, 'platform', { value: originalPlatform });
|
||||
});
|
||||
|
||||
test('returns bash or zsh for macOS', () => {
|
||||
const originalPlatform = process.platform;
|
||||
Object.defineProperty(process, 'platform', { value: 'darwin' });
|
||||
|
||||
const shell = platformUtils.detectShell();
|
||||
expect(['bash', 'zsh']).toContain(shell);
|
||||
|
||||
Object.defineProperty(process, 'platform', { value: originalPlatform });
|
||||
});
|
||||
|
||||
test('returns bash for Linux', () => {
|
||||
const originalPlatform = process.platform;
|
||||
Object.defineProperty(process, 'platform', { value: 'linux' });
|
||||
|
||||
expect(platformUtils.detectShell()).toBe('bash');
|
||||
|
||||
Object.defineProperty(process, 'platform', { value: originalPlatform });
|
||||
});
|
||||
});
|
||||
|
||||
describe('getDefaultInstallPath', () => {
|
||||
test('returns Windows path for Windows', () => {
|
||||
const originalPlatform = process.platform;
|
||||
Object.defineProperty(process, 'platform', { value: 'win32' });
|
||||
|
||||
expect(platformUtils.getDefaultInstallPath()).toBe('C:\\Program Files\\DashCaddy');
|
||||
|
||||
Object.defineProperty(process, 'platform', { value: originalPlatform });
|
||||
});
|
||||
|
||||
test('returns macOS path for macOS', () => {
|
||||
const originalPlatform = process.platform;
|
||||
Object.defineProperty(process, 'platform', { value: 'darwin' });
|
||||
|
||||
expect(platformUtils.getDefaultInstallPath()).toBe('/Applications/DashCaddy');
|
||||
|
||||
Object.defineProperty(process, 'platform', { value: originalPlatform });
|
||||
});
|
||||
|
||||
test('returns Linux path for Linux', () => {
|
||||
const originalPlatform = process.platform;
|
||||
Object.defineProperty(process, 'platform', { value: 'linux' });
|
||||
|
||||
expect(platformUtils.getDefaultInstallPath()).toBe('/opt/dashcaddy');
|
||||
|
||||
Object.defineProperty(process, 'platform', { value: originalPlatform });
|
||||
});
|
||||
});
|
||||
|
||||
describe('Platform checks', () => {
|
||||
test('isWindows returns boolean', () => {
|
||||
expect(typeof platformUtils.isWindows()).toBe('boolean');
|
||||
});
|
||||
|
||||
test('isMacOS returns boolean', () => {
|
||||
expect(typeof platformUtils.isMacOS()).toBe('boolean');
|
||||
});
|
||||
|
||||
test('isLinux returns boolean', () => {
|
||||
expect(typeof platformUtils.isLinux()).toBe('boolean');
|
||||
});
|
||||
|
||||
test('exactly one platform check returns true', () => {
|
||||
const checks = [
|
||||
platformUtils.isWindows(),
|
||||
platformUtils.isMacOS(),
|
||||
platformUtils.isLinux()
|
||||
];
|
||||
const trueCount = checks.filter(Boolean).length;
|
||||
expect(trueCount).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getPlatformInfo', () => {
|
||||
test('returns complete platform information', () => {
|
||||
const info = platformUtils.getPlatformInfo();
|
||||
|
||||
expect(info).toHaveProperty('os');
|
||||
expect(info).toHaveProperty('arch');
|
||||
expect(info).toHaveProperty('shell');
|
||||
expect(info).toHaveProperty('platform');
|
||||
expect(info).toHaveProperty('hostname');
|
||||
expect(info).toHaveProperty('homedir');
|
||||
expect(info).toHaveProperty('defaultInstallPath');
|
||||
expect(info).toHaveProperty('userInstallPath');
|
||||
|
||||
expect(typeof info.os).toBe('string');
|
||||
expect(typeof info.arch).toBe('string');
|
||||
expect(typeof info.shell).toBe('string');
|
||||
expect(typeof info.hostname).toBe('string');
|
||||
expect(typeof info.homedir).toBe('string');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Path utilities', () => {
|
||||
test('normalizePath normalizes paths', () => {
|
||||
const normalized = platformUtils.normalizePath('/path//to///file');
|
||||
expect(normalized).not.toContain('//');
|
||||
});
|
||||
|
||||
test('joinPath joins path segments', () => {
|
||||
const joined = platformUtils.joinPath('path', 'to', 'file');
|
||||
expect(joined).toContain('path');
|
||||
expect(joined).toContain('file');
|
||||
});
|
||||
|
||||
test('getUserInstallPath returns path in home directory', () => {
|
||||
const userPath = platformUtils.getUserInstallPath();
|
||||
expect(userPath).toContain('DashCaddy');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getCommandExecution', () => {
|
||||
test('returns PowerShell execution for Windows', () => {
|
||||
const originalPlatform = process.platform;
|
||||
Object.defineProperty(process, 'platform', { value: 'win32' });
|
||||
|
||||
const exec = platformUtils.getCommandExecution('test command');
|
||||
expect(exec.shell).toBe('powershell.exe');
|
||||
expect(exec.args).toEqual(['-Command', 'test command']);
|
||||
|
||||
Object.defineProperty(process, 'platform', { value: originalPlatform });
|
||||
});
|
||||
|
||||
test('returns shell execution for Unix-like systems', () => {
|
||||
const originalPlatform = process.platform;
|
||||
Object.defineProperty(process, 'platform', { value: 'linux' });
|
||||
|
||||
const exec = platformUtils.getCommandExecution('test command');
|
||||
expect(['bash', 'zsh']).toContain(exec.shell);
|
||||
expect(exec.args).toEqual(['-c', 'test command']);
|
||||
|
||||
Object.defineProperty(process, 'platform', { value: originalPlatform });
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user