test-home-directory.js•9.6 kB
/**
* Test script for home directory (~) path handling
*
* This script tests the tilde expansion and path validation with:
* 1. Testing tilde (~) expansion in paths
* 2. Testing tilde with subdirectory (~/Documents) expansion
* 3. Testing tilde expansion in the allowedDirectories configuration
* 4. Testing file operations with tilde notation
*/
import { configManager } from '../dist/config-manager.js';
import {
validatePath,
listDirectory,
readFile,
writeFile,
createDirectory
} from '../dist/tools/filesystem.js';
import fs from 'fs/promises';
import path from 'path';
import { fileURLToPath } from 'url';
import assert from 'assert';
import os from 'os';
// Get directory name
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Define test paths
const HOME_DIR = os.homedir();
const HOME_TILDE = '~';
const HOME_DOCS_PATH = path.join(HOME_DIR, 'Documents');
const HOME_DOCS_TILDE = '~/Documents';
const TEST_DIR = path.join(HOME_DIR, '.claude-test-tilde');
const TEST_DIR_TILDE = '~/.claude-test-tilde';
const TEST_FILE = path.join(TEST_DIR, 'test-file.txt');
const TEST_FILE_TILDE = '~/.claude-test-tilde/test-file.txt';
const TEST_CONTENT = 'This is a test file for tilde expansion';
/**
* Helper function to clean up test directories
*/
async function cleanupTestDirectories() {
try {
console.log('Cleaning up test directories...');
await fs.rm(TEST_DIR, { recursive: true, force: true });
console.log('Cleanup complete.');
} catch (error) {
// Ignore errors if directory doesn't exist
if (error.code !== 'ENOENT') {
console.error('Error during cleanup:', error);
}
}
}
/**
* Setup function to prepare the test environment
*/
async function setup() {
// Clean up before tests
await cleanupTestDirectories();
// Save original config to restore later
const originalConfig = await configManager.getConfig();
// Set allowed directories to include the home directory for testing tilde expansion
await configManager.setValue('allowedDirectories', [HOME_DIR, __dirname]);
console.log(`Set allowed directories to: ${HOME_DIR}, ${__dirname}`);
return originalConfig;
}
/**
* Teardown function to clean up after tests
*/
async function teardown(originalConfig) {
// Reset configuration to original
await configManager.updateConfig(originalConfig);
// Clean up test directories
await cleanupTestDirectories();
console.log('✓ Teardown: test directories cleaned up and config restored');
}
/**
* Test simple tilde expansion
*/
async function testTildeExpansion() {
console.log('\nTest 1: Basic tilde expansion');
// Test path validation with tilde
console.log(`Testing tilde expansion for: ${HOME_TILDE}`);
console.log(`Home directory from os.homedir(): ${HOME_DIR}`);
try {
const expandedPath = await validatePath(HOME_TILDE);
console.log(`Tilde (~) expanded to: ${expandedPath}`);
// Check if the expanded path is the home directory
assert.ok(
expandedPath.toLowerCase() === HOME_DIR.toLowerCase() ||
expandedPath.toLowerCase().startsWith(HOME_DIR.toLowerCase()),
'Tilde (~) should expand to the home directory'
);
console.log('✓ Basic tilde expansion works correctly');
return expandedPath; // Return expandedPath for use in the outer function
} catch (error) {
console.error(`Error during tilde expansion: ${error.message || error}`);
throw error;
}
}
/**
* Test tilde with subdirectory expansion
*/
async function testTildeWithSubdirectory() {
console.log('\nTest 2: Tilde with subdirectory expansion');
try {
// Test path validation with tilde and subdirectory
console.log(`Testing tilde with subdirectory expansion for: ${HOME_DOCS_TILDE}`);
console.log(`Home documents directory: ${HOME_DOCS_PATH}`);
const expandedPath = await validatePath(HOME_DOCS_TILDE);
console.log(`~/Documents expanded to: ${expandedPath}`);
// Check if the expanded path is the home documents directory
assert.ok(
expandedPath.toLowerCase() === HOME_DOCS_PATH.toLowerCase() ||
expandedPath.toLowerCase().startsWith(HOME_DOCS_PATH.toLowerCase()),
'~/Documents should expand to the home documents directory'
);
console.log('✓ Tilde with subdirectory expansion works correctly');
} catch (error) {
console.error(`Error during tilde with subdirectory expansion: ${error.message || error}`);
throw error;
}
}
/**
* Test tilde in allowedDirectories config
*/
async function testTildeInAllowedDirectories() {
console.log('\nTest 3: Tilde in allowedDirectories config');
try {
// Set allowedDirectories to tilde
await configManager.setValue('allowedDirectories', [HOME_TILDE]);
// Verify config was set correctly
const config = await configManager.getConfig();
console.log(`Config: ${JSON.stringify(config.allowedDirectories)}`);
assert.deepStrictEqual(config.allowedDirectories, [HOME_TILDE], 'allowedDirectories should contain tilde');
// Test access to home directory and subdirectory
try {
const homeDirAccess = await validatePath(HOME_DIR);
console.log(`Home directory access: ${homeDirAccess}`);
const homeDocsDirAccess = await validatePath(HOME_DOCS_PATH);
console.log(`Home documents directory access: ${homeDocsDirAccess}`);
console.log('✓ Tilde in allowedDirectories works correctly');
} catch (error) {
console.error(`Error accessing paths: ${error.message || error}`);
throw error;
} finally {
// Reset allowedDirectories to original value
await configManager.setValue('allowedDirectories', []);
}
} catch (error) {
console.error(`Error in tilde allowedDirectories test: ${error.message || error}`);
throw error;
}
}
/**
* Test file operations with tilde
*/
async function testFileOperationsWithTilde() {
console.log('\nTest 4: File operations with tilde');
try {
// Test directory creation with tilde
console.log(`Attempting to create directory: ${TEST_DIR_TILDE}`);
await createDirectory(TEST_DIR_TILDE);
console.log(`Created test directory: ${TEST_DIR_TILDE}`);
// Verify the directory exists
const dirStats = await fs.stat(TEST_DIR);
assert.ok(dirStats.isDirectory(), 'Test directory should exist and be a directory');
// Test writing to a file with tilde
console.log(`Attempting to write to file: ${TEST_FILE_TILDE}`);
await writeFile(TEST_FILE_TILDE, TEST_CONTENT);
console.log(`Wrote to test file: ${TEST_FILE_TILDE}`);
// Test reading from a file with tilde
console.log(`Attempting to read file: ${TEST_FILE_TILDE}`);
const fileResult = await readFile(TEST_FILE_TILDE);
let content;
// Handle either string or object response from readFile
if (typeof fileResult === 'string') {
content = fileResult;
} else if (fileResult && typeof fileResult === 'object') {
content = fileResult.content;
} else {
throw new Error('Unexpected return format from readFile');
}
console.log(`Read from test file content: ${content}`);
// Verify the content
assert.ok(
content === TEST_CONTENT || content.includes(TEST_CONTENT),
'File content should match what was written'
);
// Test listing a directory with tilde
console.log(`Attempting to list directory: ${TEST_DIR_TILDE}`);
const entries = await listDirectory(TEST_DIR_TILDE);
console.log(`Listed test directory: ${entries}`);
// Verify the entries
assert.ok(entries.some(entry => entry.includes('test-file.txt')), 'Directory listing should include test file');
console.log('✓ File operations with tilde work correctly');
} catch (error) {
console.error(`Error during file operations with tilde: ${error.message || error}`);
throw error;
}
}
/**
* Main test function
*/
async function testHomeDirectory() {
console.log('=== Home Directory (~) Path Handling Tests ===\n');
try {
// Test 1: Basic tilde expansion
const expandedPath = await testTildeExpansion();
// Check if the expanded path is the home directory
assert.ok(
expandedPath.toLowerCase() === HOME_DIR.toLowerCase() ||
expandedPath.toLowerCase().startsWith(HOME_DIR.toLowerCase()),
'Tilde (~) should expand to the home directory'
);
// Test 2: Tilde with subdirectory expansion
await testTildeWithSubdirectory();
// Test 3: Tilde in allowedDirectories config
await testTildeInAllowedDirectories();
// Test 4: File operations with tilde
await testFileOperationsWithTilde();
console.log('\n✅ All home directory (~) tests passed!');
} catch (error) {
console.error(`Main test function error: ${error.message || error}`);
throw error;
}
}
// Export the main test function
export default async function runTests() {
let originalConfig;
try {
originalConfig = await setup();
await testHomeDirectory();
return true; // Explicitly return true on success
} catch (error) {
console.error('❌ Test failed:', error.message || error);
return false;
} finally {
if (originalConfig) {
await teardown(originalConfig);
}
}
}
// If this file is run directly (not imported), execute the test
if (import.meta.url === `file://${process.argv[1]}`) {
runTests().catch(error => {
console.error('❌ Unhandled error:', error);
process.exit(1);
});
}