agentsqripts
Version:
Comprehensive static code analysis toolkit for identifying technical debt, security vulnerabilities, performance issues, and code quality problems
223 lines (183 loc) • 8.46 kB
JavaScript
/**
* @file Unit tests for path utilities
* @description Tests path resolution, normalization, and cross-platform path handling
*/
const {
resolvePath,
normalizePath,
isAbsolutePath,
joinPaths,
getRelativePath,
getPathExtension,
changePathExtension
} = require('./pathUtils');
const path = require('path');
const qtests = require('qtests');
/**
* Test runner for path utilities
*/
async function runTests() {
console.log('=== Testing Path Utilities ===');
const results = {
total: 0,
passed: 0
};
// Test resolvePath function
results.total++;
try {
const relativePath = './test/file.js';
const absolutePath = path.resolve('/absolute/path/file.js');
const resolvedRelative = resolvePath(relativePath);
const resolvedAbsolute = resolvePath(absolutePath);
qtests.assert(path.isAbsolute(resolvedRelative), 'resolvePath should return absolute path for relative input');
qtests.assert(path.isAbsolute(resolvedAbsolute), 'resolvePath should return absolute path for absolute input');
qtests.assert(resolvedRelative.includes('test/file.js'), 'resolvePath should preserve relative structure');
console.log('✓ resolvePath correctly resolves paths to absolute');
results.passed++;
} catch (error) {
console.log(`✗ resolvePath test failed: ${error.message}`);
}
// Test normalizePath function
results.total++;
try {
const windowsPath = 'C:\\Users\\test\\file.js';
const unixPath = '/home/test/file.js';
const mixedPath = 'C:/Users/test\\file.js';
const normalizedWindows = normalizePath(windowsPath);
const normalizedUnix = normalizePath(unixPath);
const normalizedMixed = normalizePath(mixedPath);
qtests.assert(typeof normalizedWindows === 'string', 'normalizePath should return string');
qtests.assert(typeof normalizedUnix === 'string', 'normalizePath should return string');
qtests.assert(typeof normalizedMixed === 'string', 'normalizePath should return string');
// Normalized paths should be consistent
qtests.assert(!normalizedMixed.includes('\\') || !normalizedMixed.includes('/'), 'normalizePath should use consistent separators');
console.log('✓ normalizePath correctly normalizes path separators');
results.passed++;
} catch (error) {
console.log(`✗ normalizePath test failed: ${error.message}`);
}
// Test isAbsolutePath function
results.total++;
try {
const absolutePaths = [
'/home/user/file.js',
'C:\\Users\\test\\file.js',
'/absolute/path'
];
const relativePaths = [
'./relative/file.js',
'../parent/file.js',
'file.js',
'subfolder/file.js'
];
absolutePaths.forEach(p => {
qtests.assert(isAbsolutePath(p), `isAbsolutePath should detect absolute path: ${p}`);
});
relativePaths.forEach(p => {
qtests.assert(!isAbsolutePath(p), `isAbsolutePath should detect relative path: ${p}`);
});
console.log('✓ isAbsolutePath correctly identifies absolute and relative paths');
results.passed++;
} catch (error) {
console.log(`✗ isAbsolutePath test failed: ${error.message}`);
}
// Test joinPaths function
results.total++;
try {
const joined1 = joinPaths('/base', 'folder', 'file.js');
const joined2 = joinPaths('relative', 'path', 'to', 'file.txt');
const joined3 = joinPaths('/base/', '/folder/', 'file.js');
qtests.assert(typeof joined1 === 'string', 'joinPaths should return string');
qtests.assert(joined1.includes('base'), 'joinPaths should include all path segments');
qtests.assert(joined1.includes('folder'), 'joinPaths should include all path segments');
qtests.assert(joined1.includes('file.js'), 'joinPaths should include all path segments');
qtests.assert(joined2.includes('relative'), 'joinPaths should work with relative paths');
qtests.assert(joined2.includes('file.txt'), 'joinPaths should preserve file names');
// Should handle redundant separators
qtests.assert(!joined3.includes('//'), 'joinPaths should handle redundant separators');
console.log('✓ joinPaths correctly joins path segments');
results.passed++;
} catch (error) {
console.log(`✗ joinPaths test failed: ${error.message}`);
}
// Test getRelativePath function
results.total++;
try {
const basePath = '/project/src';
const targetPath1 = '/project/src/components/Button.js';
const targetPath2 = '/project/lib/utils.js';
const targetPath3 = '/different/project/file.js';
const relative1 = getRelativePath(basePath, targetPath1);
const relative2 = getRelativePath(basePath, targetPath2);
const relative3 = getRelativePath(basePath, targetPath3);
qtests.assert(typeof relative1 === 'string', 'getRelativePath should return string');
qtests.assert(relative1.includes('components'), 'getRelativePath should show relative path from base');
qtests.assert(relative2.includes('..'), 'getRelativePath should use .. for parent directories');
qtests.assert(typeof relative3 === 'string', 'getRelativePath should handle completely different paths');
console.log('✓ getRelativePath correctly calculates relative paths');
results.passed++;
} catch (error) {
console.log(`✗ getRelativePath test failed: ${error.message}`);
}
// Test getPathExtension function
results.total++;
try {
const testCases = [
{ path: '/path/to/file.js', expected: '.js' },
{ path: '/path/to/file.test.js', expected: '.js' },
{ path: '/path/to/component.jsx', expected: '.jsx' },
{ path: '/path/to/styles.css', expected: '.css' },
{ path: '/path/to/README', expected: '' },
{ path: '/path/to/.gitignore', expected: '' }
];
testCases.forEach(({ path: testPath, expected }) => {
const result = getPathExtension(testPath);
qtests.assert(result === expected, `getPathExtension should return ${expected} for ${testPath}, got ${result}`);
});
console.log('✓ getPathExtension correctly extracts file extensions');
results.passed++;
} catch (error) {
console.log(`✗ getPathExtension test failed: ${error.message}`);
}
// Test changePathExtension function
results.total++;
try {
const originalPath = '/path/to/file.js';
const changedToTs = changePathExtension(originalPath, '.ts');
const changedToJsx = changePathExtension('/path/to/component.js', '.jsx');
const addedExtension = changePathExtension('/path/to/README', '.md');
qtests.assert(changedToTs === '/path/to/file.ts', 'changePathExtension should change extension correctly');
qtests.assert(changedToJsx === '/path/to/component.jsx', 'changePathExtension should work with different extensions');
qtests.assert(addedExtension === '/path/to/README.md', 'changePathExtension should add extension to files without one');
console.log('✓ changePathExtension correctly changes file extensions');
results.passed++;
} catch (error) {
console.log(`✗ changePathExtension test failed: ${error.message}`);
}
// Test edge cases and error handling
results.total++;
try {
// Test empty and null inputs
const emptyPath = resolvePath('');
const nullPath = resolvePath(null);
qtests.assert(typeof emptyPath === 'string', 'resolvePath should handle empty string');
qtests.assert(typeof nullPath === 'string', 'resolvePath should handle null input');
// Test very long paths
const longPath = 'a'.repeat(1000) + '/file.js';
const resolvedLong = resolvePath(longPath);
qtests.assert(typeof resolvedLong === 'string', 'resolvePath should handle long paths');
// Test special characters
const specialPath = '/path with spaces/file-name_test.js';
const resolvedSpecial = resolvePath(specialPath);
qtests.assert(resolvedSpecial.includes('file-name_test.js'), 'resolvePath should preserve special characters');
console.log('✓ Path utilities handle edge cases correctly');
results.passed++;
} catch (error) {
console.log(`✗ Edge cases test failed: ${error.message}`);
}
console.log(`=== Path Utilities Test Results ===`);
console.log(`Tests passed: ${results.passed}/${results.total}`);
console.log(`Success rate: ${((results.passed / results.total) * 100).toFixed(1)}%`);
return results;
}
module.exports = { runTests };