From b5bc8d207ca139f4c63b20b15054cce841b03f0e Mon Sep 17 00:00:00 2001 From: kaitranntt Date: Wed, 5 Nov 2025 10:35:49 -0500 Subject: [PATCH] fix: clean up tests directory structure - Remove old test files that were moved to native/ subdirectories - Clean install-test.sh, install-test.ps1, uninstall-test.sh, uninstall-test.ps1, test-custom-claude-path.ps1 - Tests now properly organized: native/, npm/, shared/, unit/, integration/ - Maintains clean root test directory with only orchestrators and docs --- tests/install-test.ps1 | 273 ---------- tests/install-test.sh | 446 --------------- tests/npm/cli.test.js | 4 +- tests/test-custom-claude-path.ps1 | 874 ------------------------------ tests/uninstall-test.ps1 | 454 ---------------- tests/uninstall-test.sh | 310 ----------- 6 files changed, 2 insertions(+), 2359 deletions(-) delete mode 100644 tests/install-test.ps1 delete mode 100755 tests/install-test.sh delete mode 100644 tests/test-custom-claude-path.ps1 delete mode 100644 tests/uninstall-test.ps1 delete mode 100755 tests/uninstall-test.sh diff --git a/tests/install-test.ps1 b/tests/install-test.ps1 deleted file mode 100644 index a3afea37..00000000 --- a/tests/install-test.ps1 +++ /dev/null @@ -1,273 +0,0 @@ -#!/usr/bin/env pwsh - -<# -.SYNOPSIS - Test suite for CCS --install functionality (Windows PowerShell) - -.DESCRIPTION - Tests the --install flag for CCS executable on Windows PowerShell. - Tests against actual system installation for simplicity. - -.NOTES - Author: CCS Test Suite - Version: 1.0 - Based on: edge-cases.ps1 patterns -#> - -#Requires -Version 5.1 - -# Don't exit on errors, we're testing -$ErrorActionPreference = "Continue" - -# Test statistics -$Script:TotalTests = 0 -$Script:PassedTests = 0 -$Script:FailedTests = 0 - -# Colors -$Colors = @{ - Red = "Red" - Green = "Green" - Yellow = "Yellow" - Cyan = "Cyan" - White = "White" -} - -function Write-ColorOutput { - param([string]$Message, [string]$Color = "White") - Write-Host $Message -ForegroundColor $Colors[$Color] -} - -function Test-Case { - param( - [string]$Name, - [string]$Description, - [scriptblock]$TestCode - ) - - $Script:TotalTests++ - Write-Host "" - Write-ColorOutput "[$Script:TotalTests] $Name" "Cyan" - Write-ColorOutput " Expected: $Description" "White" - - try { - if (& $TestCode) { - Write-ColorOutput " Result: PASS" "Green" - $Script:PassedTests++ - return $true - } else { - Write-ColorOutput " Result: FAIL" "Red" - $Script:FailedTests++ - return $false - } - } - catch { - Write-ColorOutput " Result: FAIL" "Red" - Write-ColorOutput " Error: $($_.Exception.Message)" "Red" - $Script:FailedTests++ - return $false - } -} - -Write-ColorOutput "========================================" "Yellow" -Write-ColorOutput "CCS --INSTALL FUNCTIONALITY TESTING" "Yellow" -Write-ColorOutput "========================================" "Yellow" -Write-Host "" - -# Get script paths -$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path -$CcsRoot = Split-Path -Parent $ScriptDir -$CcsPath = Join-Path $CcsRoot "ccs.ps1" - -# Backup existing .claude directory -Write-ColorOutput "Safety: Backing up existing ~/.claude/..." "Cyan" -$BackupDir = Join-Path $env:TEMP "ccs-test-backup-$(Get-Date -Format 'yyyyMMddHHmmss')" -if (Test-Path $env:USERPROFILE\.claude) { - Write-Host " Found existing ~/.claude/, creating backup at $BackupDir" - Copy-Item -Path $env:USERPROFILE\.claude -Destination $BackupDir -Recurse -Force - Write-ColorOutput " Backup created successfully" "Green" -} else { - Write-ColorOutput " No existing ~/.claude/ found" "Yellow" -} -Write-Host "" - -# ============================================================================ -# PRE-CHECKS -# ============================================================================ -Write-ColorOutput "===== PRE-CHECKS =====" "Yellow" - -Test-Case "CCS executable exists" "ccs.ps1 script found" { - Test-Path $CcsPath -} - -Test-Case "Source .claude directory exists" ".claude/ in CCS repo" { - Test-Path (Join-Path $CcsRoot ".claude") -} - -Test-Case "Source commands exist" "ccs.md command file exists" { - Test-Path (Join-Path $CcsRoot ".claude\commands\ccs.md") -} - -Test-Case "Source skills exist" "ccs-delegation skill directory exists" { - Test-Path (Join-Path $CcsRoot ".claude\skills\ccs-delegation") -} - -# ============================================================================ -# SECTION 1: INSTALLATION -# ============================================================================ -Write-Host "" -Write-ColorOutput "===== SECTION 1: INSTALLATION =====" "Yellow" - -Test-Case "Install: Command executes without error" "Exit code 0" { - $process = Start-Process -FilePath "pwsh" -ArgumentList "-File", "`"$CcsPath`"", "--install" -Wait -PassThru -NoNewWindow - $process.ExitCode -eq 0 -} - -Test-Case "Install: Commands directory created" "~/.claude/commands/ exists" { - Test-Path "$env:USERPROFILE\.claude\commands" -} - -Test-Case "Install: Skills directory created" "~/.claude/skills/ exists" { - Test-Path "$env:USERPROFILE\.claude\skills" -} - -Test-Case "Install: ccs.md command installed" "ccs.md file exists" { - Test-Path "$env:USERPROFILE\.claude\commands\ccs.md" -} - -Test-Case "Install: ccs-delegation skill installed" "ccs-delegation/ exists" { - Test-Path "$env:USERPROFILE\.claude\skills\ccs-delegation" -} - -Test-Case "Install: SKILL.md exists" "SKILL.md in ccs-delegation/" { - Test-Path "$env:USERPROFILE\.claude\skills\ccs-delegation\SKILL.md" -} - -Test-Case "Install: references directory exists" "references/ subdirectory present" { - Test-Path "$env:USERPROFILE\.claude\skills\ccs-delegation\references" -} - -# ============================================================================ -# SECTION 2: IDEMPOTENCY -# ============================================================================ -Write-Host "" -Write-ColorOutput "===== SECTION 2: IDEMPOTENCY =====" "Yellow" - -Test-Case "Idempotent: Second run succeeds" "Second --install doesn't error" { - $process = Start-Process -FilePath "pwsh" -ArgumentList "-File", "`"$CcsPath`"", "--install" -Wait -PassThru -NoNewWindow - $process.ExitCode -eq 0 -} - -# ============================================================================ -# SECTION 3: FILE INTEGRITY -# ============================================================================ -Write-Host "" -Write-ColorOutput "===== SECTION 3: FILE INTEGRITY =====" "Yellow" - -Test-Case "Integrity: Command file not empty" "ccs.md has content" { - $content = Get-Content "$env:USERPROFILE\.claude\commands\ccs.md" -Raw - $content.Length -gt 0 -} - -Test-Case "Integrity: Skill file not empty" "SKILL.md has content" { - $content = Get-Content "$env:USERPROFILE\.claude\skills\ccs-delegation\SKILL.md" -Raw - $content.Length -gt 0 -} - -Test-Case "Integrity: Command file matches source" "ccs.md content identical" { - $source = Get-Content (Join-Path $CcsRoot ".claude\commands\ccs.md") -Raw - $target = Get-Content "$env:USERPROFILE\.claude\commands\ccs.md" -Raw - $source -eq $target -} - -Test-Case "Integrity: Skill file matches source" "SKILL.md content identical" { - $source = Get-Content (Join-Path $CcsRoot ".claude\skills\ccs-delegation\SKILL.md") -Raw - $target = Get-Content "$env:USERPROFILE\.claude\skills\ccs-delegation\SKILL.md" -Raw - $source -eq $target -} - -# ============================================================================ -# SECTION 4: INTEGRATION -# ============================================================================ -Write-Host "" -Write-ColorOutput "===== SECTION 4: INTEGRATION WITH CCS =====" "Yellow" - -Test-Case "Integration: --install executes without profile error" "No profile error on --install" { - $process = Start-Process -FilePath "pwsh" -ArgumentList "-File", "`"$CcsPath`"", "--install" -Wait -PassThru -NoNewWindow - $process.ExitCode -eq 0 -} - -Test-Case "Integration: --version still works" "Version command exits successfully" { - $process = Start-Process -FilePath "pwsh" -ArgumentList "-File", "`"$CcsPath`"", "--version" -Wait -PassThru -NoNewWindow - $process.ExitCode -eq 0 -} - -Test-Case "Integration: --help still works" "Help command exits successfully" { - $process = Start-Process -FilePath "pwsh" -ArgumentList "-File", "`"$CcsPath`"", "--help" -Wait -PassThru -NoNewWindow - $process.ExitCode -eq 0 -} - -# ============================================================================ -# FINAL RESULTS -# ============================================================================ -Write-Host "" -Write-ColorOutput "========================================" "Yellow" -Write-ColorOutput "TEST RESULTS SUMMARY" "Yellow" -Write-ColorOutput "========================================" "Yellow" -Write-Host "" - -Write-ColorOutput "Total Tests: $Script:TotalTests" "Cyan" -Write-ColorOutput "Passed: $Script:PassedTests" "Green" -if ($Script:FailedTests -eq 0) { - Write-ColorOutput "Failed: $Script:FailedTests" "Green" -} else { - Write-ColorOutput "Failed: $Script:FailedTests" "Red" -} -Write-Host "" - -$SuccessRate = if ($Script:TotalTests -gt 0) { - [math]::Round(($Script:PassedTests / $Script:TotalTests) * 100, 2) -} else { 0 } - -if ($SuccessRate -ge 90) { - Write-ColorOutput "Success Rate: $SuccessRate%" "Green" -} elseif ($SuccessRate -ge 70) { - Write-ColorOutput "Success Rate: $SuccessRate%" "Yellow" -} else { - Write-ColorOutput "Success Rate: $SuccessRate%" "Red" -} - -Write-Host "" - -if ($Script:FailedTests -eq 0) { - Write-ColorOutput "========================================" "Green" - Write-ColorOutput "ALL TESTS PASSED!" "Green" - Write-ColorOutput "========================================" "Green" - Write-ColorOutput "--install functionality is production ready!" "Green" -} else { - Write-ColorOutput "========================================" "Red" - Write-ColorOutput "SOME TESTS FAILED" "Red" - Write-ColorOutput "========================================" "Red" - Write-ColorOutput "Review failed tests above for details" "Red" -} - -# Restore backup -Write-Host "" -Write-ColorOutput "Cleaning up and restoring..." "Yellow" -if (Test-Path $env:USERPROFILE\.claude) { - Write-Host " Removing test data from $env:USERPROFILE\.claude" - Remove-Item -Path $env:USERPROFILE\.claude -Recurse -Force -} - -if (Test-Path $BackupDir) { - Write-Host " Restoring backup from $BackupDir" - Move-Item -Path $BackupDir -Destination $env:USERPROFILE\.claude - Write-ColorOutput " Backup restored successfully" "Green" -} - -# Exit with appropriate code -if ($Script:FailedTests -gt 0) { - exit 1 -} else { - exit 0 -} \ No newline at end of file diff --git a/tests/install-test.sh b/tests/install-test.sh deleted file mode 100755 index e34cb887..00000000 --- a/tests/install-test.sh +++ /dev/null @@ -1,446 +0,0 @@ -#!/usr/bin/env bash -# CCS --install Functionality Testing (Linux/macOS) -# Comprehensive tests for the --install command - -set +e # Don't exit on errors, we're testing -PASS_COUNT=0 -FAIL_COUNT=0 -TOTAL_TESTS=0 - -# Colors -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -CYAN='\033[0;36m' -GRAY='\033[0;37m' -NC='\033[0m' # No Color - -# Get script directory -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -CCS_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" -CCS_PATH="$CCS_ROOT/ccs" - -# Backup/restore paths -CLAUDE_DIR="$HOME/.claude" -BACKUP_DIR="/tmp/ccs-test-backup-$(date +%s)" -TEST_HOME="/tmp/ccs-test-home" -TEST_CLAUDE_DIR="$TEST_HOME/.claude" - -test_case() { - local name="$1" - local expected="$2" - shift 2 - - ((TOTAL_TESTS++)) - echo "" - echo -e "${CYAN}[$TOTAL_TESTS] $name${NC}" - echo -e "${GRAY} Expected: $expected${NC}" - - if "$@"; then - echo -e "${GREEN} Result: PASS${NC}" - ((PASS_COUNT++)) - return 0 - else - echo -e "${RED} Result: FAIL${NC}" - ((FAIL_COUNT++)) - return 1 - fi -} - -cleanup_and_restore() { - echo "" - echo -e "${YELLOW}Cleaning up and restoring...${NC}" - - # Remove test directory - rm -rf "$TEST_HOME" - - # Restore backup if it exists - if [[ -d "$BACKUP_DIR" ]]; then - if [[ -d "$CLAUDE_DIR" ]]; then - echo " Removing test data from $CLAUDE_DIR" - rm -rf "$CLAUDE_DIR" - fi - echo " Restoring backup from $BACKUP_DIR" - mv "$BACKUP_DIR" "$CLAUDE_DIR" - echo -e "${GREEN} Backup restored successfully${NC}" - fi -} - -# Trap to ensure cleanup happens even if script fails -trap cleanup_and_restore EXIT - -echo -e "${YELLOW}========================================${NC}" -echo -e "${YELLOW}CCS --INSTALL FUNCTIONALITY TESTING${NC}" -echo -e "${YELLOW}========================================${NC}" -echo "" - -# ============================================================================ -# SAFETY: BACKUP EXISTING ~/.claude/ -# ============================================================================ -echo -e "${CYAN}Safety: Backing up existing ~/.claude/...${NC}" - -if [[ -d "$CLAUDE_DIR" ]]; then - echo " Found existing ~/.claude/, creating backup at $BACKUP_DIR" - cp -r "$CLAUDE_DIR" "$BACKUP_DIR" - echo -e "${GREEN} Backup created successfully${NC}" -else - echo " No existing ~/.claude/ found, no backup needed" -fi - -echo "" - -# ============================================================================ -# PRE-CHECKS -# ============================================================================ -echo -e "${YELLOW}===== PRE-CHECKS =====${NC}" - -test_case "CCS executable exists" "ccs script found at $CCS_PATH" bash -c " - [[ -f '$CCS_PATH' ]] -" - -test_case "CCS executable is executable" "ccs has execute permissions" bash -c " - [[ -x '$CCS_PATH' ]] -" - -test_case "Source .claude directory exists" ".claude/ in CCS repo" bash -c " - [[ -d '$CCS_ROOT/.claude' ]] -" - -test_case "Source commands exist" "ccs.md command file exists" bash -c " - [[ -f '$CCS_ROOT/.claude/commands/ccs.md' ]] -" - -test_case "Source skills exist" "ccs-delegation skill directory exists" bash -c " - [[ -d '$CCS_ROOT/.claude/skills/ccs-delegation' ]] -" - -# ============================================================================ -# SECTION 1: FRESH INSTALLATION (NO ~/.claude/) -# ============================================================================ -echo "" -echo -e "${YELLOW}===== SECTION 1: FRESH INSTALLATION =====${NC}" - -# Clean any existing test directory -rm -rf "$TEST_HOME" -mkdir -p "$TEST_HOME" - -test_case "Fresh install: Command executes without error" "Exit code 0" bash -c " - HOME='$TEST_HOME' '$CCS_PATH' --install > /tmp/ccs-install-output.txt 2>&1 -" - -test_case "Fresh install: Commands directory created" "~/.claude/commands/ exists" bash -c " - [[ -d '$TEST_CLAUDE_DIR/commands' ]] -" - -test_case "Fresh install: Skills directory created" "~/.claude/skills/ exists" bash -c " - [[ -d '$TEST_CLAUDE_DIR/skills' ]] -" - -test_case "Fresh install: ccs.md command installed" "ccs.md file exists in commands/" bash -c " - [[ -f '$TEST_CLAUDE_DIR/commands/ccs.md' ]] -" - -test_case "Fresh install: ccs-delegation skill installed" "ccs-delegation/ exists in skills/" bash -c " - [[ -d '$TEST_CLAUDE_DIR/skills/ccs-delegation' ]] -" - -test_case "Fresh install: SKILL.md exists" "SKILL.md in ccs-delegation/" bash -c " - [[ -f '$TEST_CLAUDE_DIR/skills/ccs-delegation/SKILL.md' ]] -" - -test_case "Fresh install: references directory exists" "references/ subdirectory present" bash -c " - [[ -d '$TEST_CLAUDE_DIR/skills/ccs-delegation/references' ]] -" - -test_case "Fresh install: delegation-patterns.md exists" "Pattern reference file present" bash -c " - [[ -f '$TEST_CLAUDE_DIR/skills/ccs-delegation/references/delegation-patterns.md' ]] -" - -# ============================================================================ -# SECTION 2: OUTPUT FORMATTING (BOX-DRAWING CHARACTERS) -# ============================================================================ -echo "" -echo -e "${YELLOW}===== SECTION 2: OUTPUT FORMATTING =====${NC}" - -# Clean for fresh test -rm -rf "$TEST_HOME" -mkdir -p "$TEST_HOME" - -test_case "Output: Contains box-drawing header" "Output has ┌─" bash -c " - output=\$(HOME='$TEST_HOME' '$CCS_PATH' --install 2>&1) - [[ \$output =~ ┌─ ]] -" - -test_case "Output: Contains box-drawing footer" "Output has └─" bash -c " - output=\$(HOME='$TEST_HOME' '$CCS_PATH' --install 2>&1) - [[ \$output =~ └─ ]] -" - -test_case "Output: Contains pipe for indentation" "Output has │" bash -c " - output=\$(HOME='$TEST_HOME' '$CCS_PATH' --install 2>&1) - [[ \$output =~ │ ]] -" - -test_case "Output: Contains checkmark indicator" "Output has ✓" bash -c " - output=\$(HOME='$TEST_HOME' '$CCS_PATH' --install 2>&1) - [[ \$output =~ ✓ ]] -" - -test_case "Output: Shows source directory" "Output includes source path" bash -c " - output=\$(HOME='$TEST_HOME' '$CCS_PATH' --install 2>&1) - [[ \$output =~ Source: ]] -" - -test_case "Output: Shows target directory" "Output includes target path" bash -c " - output=\$(HOME='$TEST_HOME' '$CCS_PATH' --install 2>&1) - [[ \$output =~ Target: ]] -" - -test_case "Output: Shows installation complete message" "Success message present" bash -c " - output=\$(HOME='$TEST_HOME' '$CCS_PATH' --install 2>&1) - [[ \$output =~ 'Installation complete' ]] -" - -test_case "Output: Shows installed count" "Displays number of installed items" bash -c " - output=\$(HOME='$TEST_HOME' '$CCS_PATH' --install 2>&1) - [[ \$output =~ 'Installed:' ]] -" - -test_case "Output: NO emoji characters used" "Output uses only box-drawing and symbols" bash -c " - # Check for actual emoji characters (not box-drawing or symbols like ✓ ℹ ✗) - output=\$(HOME='$TEST_HOME' '$CCS_PATH' --install 2>&1) - ! [[ \$output =~ [🚀📋🎯🎉] ]] -" - -# ============================================================================ -# SECTION 3: IDEMPOTENCY (MULTIPLE RUNS) -# ============================================================================ -echo "" -echo -e "${YELLOW}===== SECTION 3: IDEMPOTENCY =====${NC}" - -# Start fresh -rm -rf "$TEST_HOME" -mkdir -p "$TEST_HOME" -HOME="$TEST_HOME" "$CCS_PATH" --install > /dev/null 2>&1 - -test_case "Idempotent: Second run succeeds" "Second --install doesn't error" bash -c " - HOME='$TEST_HOME' '$CCS_PATH' --install > /tmp/ccs-install-second.txt 2>&1 -" - -test_case "Idempotent: Shows skip messages" "Output contains 'Skipping existing'" bash -c " - output=\$(HOME='$TEST_HOME' '$CCS_PATH' --install 2>&1) - [[ \$output =~ 'Skipping existing' ]] -" - -test_case "Idempotent: Uses info indicator ℹ" "Skip messages have ℹ indicator" bash -c " - output=\$(HOME='$TEST_HOME' '$CCS_PATH' --install 2>&1) - [[ \$output =~ ℹ ]] -" - -test_case "Idempotent: Skipped count shown" "Displays number of skipped items" bash -c " - output=\$(HOME='$TEST_HOME' '$CCS_PATH' --install 2>&1) - [[ \$output =~ 'Skipped:' ]] -" - -test_case "Idempotent: Files remain unchanged" "Original files not modified" bash -c " - # Get modification time before second install - mtime1=\$(stat -c %Y '$TEST_CLAUDE_DIR/commands/ccs.md' 2>/dev/null || stat -f %m '$TEST_CLAUDE_DIR/commands/ccs.md') - sleep 1 - HOME='$TEST_HOME' '$CCS_PATH' --install > /dev/null 2>&1 - mtime2=\$(stat -c %Y '$TEST_CLAUDE_DIR/commands/ccs.md' 2>/dev/null || stat -f %m '$TEST_CLAUDE_DIR/commands/ccs.md') - [[ \$mtime1 == \$mtime2 ]] -" - -test_case "Idempotent: Third run still safe" "Multiple runs are safe" bash -c " - HOME='$TEST_HOME' '$CCS_PATH' --install > /dev/null 2>&1 - HOME='$TEST_HOME' '$CCS_PATH' --install > /dev/null 2>&1 - [[ -f '$TEST_CLAUDE_DIR/commands/ccs.md' ]] && [[ -d '$TEST_CLAUDE_DIR/skills/ccs-delegation' ]] -" - -# ============================================================================ -# SECTION 4: CONFLICT HANDLING (EXISTING FILES) -# ============================================================================ -echo "" -echo -e "${YELLOW}===== SECTION 4: CONFLICT HANDLING =====${NC}" - -# Create existing files with different content -rm -rf "$TEST_CLAUDE_DIR" -mkdir -p "$TEST_CLAUDE_DIR/commands" -mkdir -p "$TEST_CLAUDE_DIR/skills/ccs-delegation" -echo "EXISTING COMMAND CONTENT" > "$TEST_CLAUDE_DIR/commands/ccs.md" -echo "EXISTING SKILL CONTENT" > "$TEST_CLAUDE_DIR/skills/ccs-delegation/SKILL.md" - -test_case "Conflict: Skips existing command file" "Doesn't overwrite ccs.md" bash -c " - HOME='$TEST_HOME' '$CCS_PATH' --install > /dev/null 2>&1 - content=\$(cat '$TEST_CLAUDE_DIR/commands/ccs.md') - [[ \$content == 'EXISTING COMMAND CONTENT' ]] -" - -test_case "Conflict: Skips existing skill directory" "Doesn't overwrite skill" bash -c " - content=\$(cat '$TEST_CLAUDE_DIR/skills/ccs-delegation/SKILL.md') - [[ \$content == 'EXISTING SKILL CONTENT' ]] -" - -test_case "Conflict: Output shows skip message" "User informed about skips" bash -c " - output=\$(HOME='$TEST_HOME' '$CCS_PATH' --install 2>&1) - [[ \$output =~ 'Skipping existing command: ccs.md' ]] -" - -test_case "Conflict: No data loss" "Original files preserved" bash -c " - [[ -f '$TEST_CLAUDE_DIR/commands/ccs.md' ]] && - grep -q 'EXISTING COMMAND CONTENT' '$TEST_CLAUDE_DIR/commands/ccs.md' -" - -# ============================================================================ -# SECTION 5: FILE INTEGRITY -# ============================================================================ -echo "" -echo -e "${YELLOW}===== SECTION 5: FILE INTEGRITY =====${NC}" - -# Fresh install for integrity checks -rm -rf "$TEST_HOME" -mkdir -p "$TEST_HOME" -HOME="$TEST_HOME" "$CCS_PATH" --install > /dev/null 2>&1 - -test_case "Integrity: Command file not empty" "ccs.md has content" bash -c " - [[ -s '$TEST_CLAUDE_DIR/commands/ccs.md' ]] -" - -test_case "Integrity: Skill file not empty" "SKILL.md has content" bash -c " - [[ -s '$TEST_CLAUDE_DIR/skills/ccs-delegation/SKILL.md' ]] -" - -test_case "Integrity: Command file matches source" "ccs.md content identical" bash -c " - diff -q '$CCS_ROOT/.claude/commands/ccs.md' '$TEST_CLAUDE_DIR/commands/ccs.md' -" - -test_case "Integrity: Skill file matches source" "SKILL.md content identical" bash -c " - diff -q '$CCS_ROOT/.claude/skills/ccs-delegation/SKILL.md' '$TEST_CLAUDE_DIR/skills/ccs-delegation/SKILL.md' -" - -test_case "Integrity: Reference file matches source" "delegation-patterns.md identical" bash -c " - diff -q '$CCS_ROOT/.claude/skills/ccs-delegation/references/delegation-patterns.md' \ - '$TEST_CLAUDE_DIR/skills/ccs-delegation/references/delegation-patterns.md' -" - -test_case "Integrity: Directory structure preserved" "All subdirectories present" bash -c " - [[ -d '$TEST_CLAUDE_DIR/skills/ccs-delegation/references' ]] -" - -# ============================================================================ -# SECTION 6: ERROR HANDLING -# ============================================================================ -echo "" -echo -e "${YELLOW}===== SECTION 6: ERROR HANDLING =====${NC}" - -test_case "Error: Missing source directory handled" "Graceful error when source missing" bash -c " - # Temporarily move .claude directory - mv '$CCS_ROOT/.claude' '$CCS_ROOT/.claude.backup' - output=\$(HOME='$TEST_HOME' '$CCS_PATH' --install 2>&1 || true) - mv '$CCS_ROOT/.claude.backup' '$CCS_ROOT/.claude' - [[ \$output =~ 'Error: Source directory not found' ]] -" - -test_case "Error: Shows helpful error message" "Error message explains the issue" bash -c " - mv '$CCS_ROOT/.claude' '$CCS_ROOT/.claude.backup' - output=\$(HOME='$TEST_HOME' '$CCS_PATH' --install 2>&1 || true) - mv '$CCS_ROOT/.claude.backup' '$CCS_ROOT/.claude' - [[ \$output =~ 'CCS repository directory' ]] -" - -test_case "Error: Uses error indicator ✗" "Error messages have ✗ indicator" bash -c " - mv '$CCS_ROOT/.claude' '$CCS_ROOT/.claude.backup' - output=\$(HOME='$TEST_HOME' '$CCS_PATH' --install 2>&1 || true) - mv '$CCS_ROOT/.claude.backup' '$CCS_ROOT/.claude' - [[ \$output =~ ✗ ]] -" - -# ============================================================================ -# SECTION 7: PERMISSIONS AND OWNERSHIP -# ============================================================================ -echo "" -echo -e "${YELLOW}===== SECTION 7: PERMISSIONS AND OWNERSHIP =====${NC}" - -rm -rf "$TEST_CLAUDE_DIR" -HOME=$(dirname "$TEST_CLAUDE_DIR") "$CCS_PATH" --install > /dev/null 2>&1 - -test_case "Permissions: Command file is readable" "ccs.md has read permissions" bash -c " - [[ -r '$TEST_CLAUDE_DIR/commands/ccs.md' ]] -" - -test_case "Permissions: Skill file is readable" "SKILL.md has read permissions" bash -c " - [[ -r '$TEST_CLAUDE_DIR/skills/ccs-delegation/SKILL.md' ]] -" - -test_case "Permissions: Directories are accessible" "Can list directory contents" bash -c " - ls '$TEST_CLAUDE_DIR/commands' > /dev/null 2>&1 && - ls '$TEST_CLAUDE_DIR/skills' > /dev/null 2>&1 -" - -# ============================================================================ -# SECTION 8: INTEGRATION WITH CCS -# ============================================================================ -echo "" -echo -e "${YELLOW}===== SECTION 8: INTEGRATION WITH CCS =====${NC}" - -test_case "Integration: --install flag recognized" "--install doesn't show 'Profile not found'" bash -c " - output=\$('$CCS_PATH' --install 2>&1 || true) - ! [[ \$output =~ 'Profile.*--install.*not found' ]] -" - -test_case "Integration: --version still works after --install" "Version command functional" bash -c " - output=\$('$CCS_PATH' --version 2>&1) - [[ \$output =~ 'CCS' ]] -" - -test_case "Integration: --help still works after --install" "Help command functional" bash -c " - output=\$('$CCS_PATH' --help 2>&1) - [[ \$output =~ 'Usage' ]] || [[ \$output =~ 'Claude' ]] -" - -# ============================================================================ -# FINAL RESULTS -# ============================================================================ -echo "" -echo -e "${YELLOW}========================================${NC}" -echo -e "${YELLOW}TEST RESULTS SUMMARY${NC}" -echo -e "${YELLOW}========================================${NC}" -echo "" -echo -e "${CYAN}Total Tests: $TOTAL_TESTS${NC}" -echo -e "${GREEN}Passed: $PASS_COUNT${NC}" - -if [[ $FAIL_COUNT -eq 0 ]]; then - echo -e "${GREEN}Failed: $FAIL_COUNT${NC}" -else - echo -e "${RED}Failed: $FAIL_COUNT${NC}" -fi - -echo "" - -SUCCESS_RATE=$(awk "BEGIN {printf \"%.2f\", ($PASS_COUNT / $TOTAL_TESTS) * 100}") - -if awk "BEGIN {exit !($SUCCESS_RATE >= 90)}"; then - echo -e "${GREEN}Success Rate: $SUCCESS_RATE%${NC}" -elif awk "BEGIN {exit !($SUCCESS_RATE >= 70)}"; then - echo -e "${YELLOW}Success Rate: $SUCCESS_RATE%${NC}" -else - echo -e "${RED}Success Rate: $SUCCESS_RATE%${NC}" -fi - -echo "" - -if [[ $FAIL_COUNT -eq 0 ]]; then - echo -e "${GREEN}========================================${NC}" - echo -e "${GREEN}ALL TESTS PASSED!${NC}" - echo -e "${GREEN}========================================${NC}" - echo "" - echo -e "${GREEN}--install functionality is production ready!${NC}" - exit 0 -else - echo -e "${YELLOW}========================================${NC}" - echo -e "${YELLOW}SOME TESTS FAILED${NC}" - echo -e "${YELLOW}========================================${NC}" - echo "" - echo -e "${YELLOW}Review failed tests above for details${NC}" - exit 1 -fi diff --git a/tests/npm/cli.test.js b/tests/npm/cli.test.js index 27ece8a4..5c99bb98 100644 --- a/tests/npm/cli.test.js +++ b/tests/npm/cli.test.js @@ -42,10 +42,10 @@ describe('npm CLI', () => { }); it('handles flag -p with value', function() { - this.timeout(5000); + this.timeout(10000); try { - execSync(`node "${ccsPath}" -p "test prompt"`, { stdio: 'pipe' }); + execSync(`node "${ccsPath}" -p "test prompt"`, { stdio: 'pipe', timeout: 8000 }); } catch (e) { const output = e.stderr?.toString() || e.stdout?.toString() || ''; assert(!output.includes("Profile '-p' not found"), 'Should not treat -p as profile'); diff --git a/tests/test-custom-claude-path.ps1 b/tests/test-custom-claude-path.ps1 deleted file mode 100644 index 1f09cdd1..00000000 --- a/tests/test-custom-claude-path.ps1 +++ /dev/null @@ -1,874 +0,0 @@ -# CCS Custom Claude CLI Path - Comprehensive Test Suite -# Tests CCS_CLAUDE_PATH environment variable support (v2.3.0) -# Windows PowerShell 5.1+ compatible - -param( - [switch]$Verbose, - [switch]$QuickTest # Skip slow tests -) - -$ErrorActionPreference = "Stop" - -# --- Test Framework --- - -$Script:TotalTests = 0 -$Script:PassedTests = 0 -$Script:FailedTests = 0 -$Script:SkippedTests = 0 -$Script:StartTime = Get-Date -$Script:TestResults = @() - -function Write-TestHeader { - param([string]$Category) - Write-Host "`n========================================" -ForegroundColor Cyan - Write-Host " $Category" -ForegroundColor Cyan - Write-Host "========================================`n" -ForegroundColor Cyan -} - -function Write-TestResult { - param( - [string]$TestName, - [string]$Status, # PASS, FAIL, SKIP - [string]$Details = "", - [int]$DurationMs = 0 - ) - - $Script:TotalTests++ - - $Symbol = switch ($Status) { - "PASS" { "[OK]"; $Script:PassedTests++; $Color = "Green" } - "FAIL" { "[X]"; $Script:FailedTests++; $Color = "Red" } - "SKIP" { "[i]"; $Script:SkippedTests++; $Color = "Yellow" } - } - - Write-Host "$Symbol $TestName" -ForegroundColor $Color - if ($Details) { - Write-Host " $Details" -ForegroundColor Gray - } - if ($DurationMs -gt 0) { - Write-Host " Duration: ${DurationMs}ms" -ForegroundColor Gray - } - - $Script:TestResults += [PSCustomObject]@{ - TestName = $TestName - Status = $Status - Details = $Details - DurationMs = $DurationMs - } -} - -# --- Test Environment Setup --- - -$Script:TestDir = "$env:TEMP\ccs-test-$(Get-Random)" -$Script:MockClaudeDir = Join-Path $TestDir "mock-claude" -$Script:OriginalEnv = @{ - CCS_CLAUDE_PATH = $env:CCS_CLAUDE_PATH - PATH = $env:PATH -} - -function Initialize-TestEnvironment { - Write-Host "`n[Initializing Test Environment]" -ForegroundColor Cyan - Write-Host " Test Directory: $Script:TestDir" - - # Create test directories - New-Item -ItemType Directory -Path $Script:TestDir -Force | Out-Null - New-Item -ItemType Directory -Path $Script:MockClaudeDir -Force | Out-Null - - # Create mock claude.exe (simple executable that returns version) - $MockExePath = Join-Path $Script:MockClaudeDir "claude.exe" - - # PowerShell script wrapped as executable - $MockScript = @' -# Mock Claude CLI -Write-Host "Mock Claude CLI v1.0.0" -exit 0 -'@ - - # Create a batch file that calls PowerShell (simplest executable) - $BatchContent = @" -@echo off -echo Mock Claude CLI v1.0.0 -exit /b 0 -"@ - - Set-Content -Path $MockExePath -Value $BatchContent -Force - - Write-Host " [OK] Created mock claude.exe at $MockExePath" -ForegroundColor Green - Write-Host "" -} - -function Restore-TestEnvironment { - Write-Host "`n[Cleaning Up Test Environment]" -ForegroundColor Cyan - - # Restore original environment variables - $env:CCS_CLAUDE_PATH = $Script:OriginalEnv.CCS_CLAUDE_PATH - $env:PATH = $Script:OriginalEnv.PATH - - # Remove test directory - if (Test-Path $Script:TestDir) { - Remove-Item -Path $Script:TestDir -Recurse -Force -ErrorAction SilentlyContinue - Write-Host " [OK] Removed test directory" -ForegroundColor Green - } - - Write-Host "" -} - -# --- Helper Functions --- - -function Get-CcsPath { - # Try to find CCS in multiple locations - $PossiblePaths = @( - "$env:USERPROFILE\.ccs\ccs.ps1", # Installed location - (Join-Path (Split-Path -Parent (Split-Path -Parent $PSCommandPath)) "ccs.ps1"), # Repo location - (Get-Command ccs -ErrorAction SilentlyContinue).Source # From PATH - ) - - foreach ($Path in $PossiblePaths) { - if ($Path -and (Test-Path $Path)) { - return $Path - } - } - - throw "CCS script not found. Checked: $($PossiblePaths -join ', ')" -} - -function Test-ClaudeDetection { - param( - [string]$ExpectedPath = "", - [bool]$ShouldSucceed = $true - ) - - $CcsPath = Get-CcsPath - - try { - # Extract Find-ClaudeCli function and test it - $CcsContent = Get-Content $CcsPath -Raw - - # Execute detection logic in isolated scope - $DetectionScript = { - param($CcsContent, $TestEnv) - - # Set up test environment - foreach ($key in $TestEnv.Keys) { - Set-Item -Path "env:$key" -Value $TestEnv[$key] - } - - # Extract and execute Find-ClaudeCli function - $FunctionStart = $CcsContent.IndexOf("function Find-ClaudeCli {") - $FunctionEnd = $CcsContent.IndexOf("`n}", $FunctionStart) + 2 - $Function = $CcsContent.Substring($FunctionStart, $FunctionEnd - $FunctionStart) - - Invoke-Expression $Function - - return Find-ClaudeCli - } - - $TestEnv = @{ - CCS_CLAUDE_PATH = $env:CCS_CLAUDE_PATH - PATH = $env:PATH - } - - $Result = & $DetectionScript -CcsContent $CcsContent -TestEnv $TestEnv - - if ($ShouldSucceed) { - if ([string]::IsNullOrEmpty($Result)) { - throw "Detection failed: No path returned" - } - if ($ExpectedPath -and ($Result -ne $ExpectedPath)) { - throw "Detection returned wrong path: $Result (expected: $ExpectedPath)" - } - return $Result - } else { - if (-not [string]::IsNullOrEmpty($Result)) { - throw "Detection should have failed but returned: $Result" - } - return "" - } - } catch { - if ($ShouldSucceed) { - throw $_ - } - return "" - } -} - -function Get-MockClaudePath { - return Join-Path $Script:MockClaudeDir "claude.exe" -} - -# --- Test Category 1: Environment Variable Detection (Priority 1) --- - -function Test-Category1-EnvVarDetection { - Write-TestHeader "Category 1: Environment Variable Detection (Priority 1)" - - # Test 1.1: Valid CCS_CLAUDE_PATH - $TestStart = Get-Date - try { - $MockPath = Get-MockClaudePath - $env:CCS_CLAUDE_PATH = $MockPath - - $DetectedPath = Test-ClaudeDetection -ExpectedPath $MockPath -ShouldSucceed $true - - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 1.1: Valid CCS_CLAUDE_PATH" ` - -Status "PASS" ` - -Details "Detected: $DetectedPath" ` - -DurationMs $Duration - } catch { - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 1.1: Valid CCS_CLAUDE_PATH" ` - -Status "FAIL" ` - -Details $_.Exception.Message ` - -DurationMs $Duration - } finally { - $env:CCS_CLAUDE_PATH = $null - } - - # Test 1.2: Invalid CCS_CLAUDE_PATH (non-existent file) - $TestStart = Get-Date - try { - $env:CCS_CLAUDE_PATH = "D:\nonexistent\claude.exe" - - # Should fall back to PATH or common locations - $DetectedPath = Test-ClaudeDetection -ShouldSucceed $false - - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 1.2: Invalid CCS_CLAUDE_PATH (non-existent)" ` - -Status "PASS" ` - -Details "Correctly fell back to search" ` - -DurationMs $Duration - } catch { - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 1.2: Invalid CCS_CLAUDE_PATH (non-existent)" ` - -Status "FAIL" ` - -Details $_.Exception.Message ` - -DurationMs $Duration - } finally { - $env:CCS_CLAUDE_PATH = $null - } - - # Test 1.3: CCS_CLAUDE_PATH is a directory (not file) - $TestStart = Get-Date - try { - $env:CCS_CLAUDE_PATH = $Script:TestDir - - # Should fail validation and fall back - $DetectedPath = Test-ClaudeDetection -ShouldSucceed $false - - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 1.3: CCS_CLAUDE_PATH is directory" ` - -Status "PASS" ` - -Details "Validation correctly rejected directory" ` - -DurationMs $Duration - } catch { - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 1.3: CCS_CLAUDE_PATH is directory" ` - -Status "FAIL" ` - -Details $_.Exception.Message ` - -DurationMs $Duration - } finally { - $env:CCS_CLAUDE_PATH = $null - } - - # Test 1.4: CCS_CLAUDE_PATH with special characters (spaces) - $TestStart = Get-Date - try { - # Create mock in path with spaces - $SpacePath = Join-Path $Script:TestDir "Program Files (x86)" - New-Item -ItemType Directory -Path $SpacePath -Force | Out-Null - $SpaceClaudePath = Join-Path $SpacePath "claude.exe" - Copy-Item (Get-MockClaudePath) $SpaceClaudePath -Force - - $env:CCS_CLAUDE_PATH = $SpaceClaudePath - - $DetectedPath = Test-ClaudeDetection -ExpectedPath $SpaceClaudePath -ShouldSucceed $true - - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 1.4: CCS_CLAUDE_PATH with spaces" ` - -Status "PASS" ` - -Details "Handled spaces correctly" ` - -DurationMs $Duration - } catch { - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 1.4: CCS_CLAUDE_PATH with spaces" ` - -Status "FAIL" ` - -Details $_.Exception.Message ` - -DurationMs $Duration - } finally { - $env:CCS_CLAUDE_PATH = $null - } -} - -# --- Test Category 2: PATH Detection (Priority 2) --- - -function Test-Category2-PathDetection { - Write-TestHeader "Category 2: PATH Detection (Priority 2)" - - # Test 2.1: Claude in PATH - $TestStart = Get-Date - try { - $env:CCS_CLAUDE_PATH = $null - $MockPath = Get-MockClaudePath - $env:PATH = "$Script:MockClaudeDir;$env:PATH" - - $DetectedPath = Test-ClaudeDetection -ShouldSucceed $true - - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 2.1: Claude in PATH" ` - -Status "PASS" ` - -Details "Found via PATH: $DetectedPath" ` - -DurationMs $Duration - } catch { - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 2.1: Claude in PATH" ` - -Status "FAIL" ` - -Details $_.Exception.Message ` - -DurationMs $Duration - } finally { - $env:PATH = $Script:OriginalEnv.PATH - } - - # Test 2.2: No CCS_CLAUDE_PATH, no PATH - $TestStart = Get-Date - try { - $env:CCS_CLAUDE_PATH = $null - # Keep original PATH (no mock claude in it) - - # Should fall back to common locations (will fail in test environment) - $DetectedPath = Test-ClaudeDetection -ShouldSucceed $false - - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 2.2: No CCS_CLAUDE_PATH, no PATH" ` - -Status "PASS" ` - -Details "Correctly fell back to Priority 3" ` - -DurationMs $Duration - } catch { - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 2.2: No CCS_CLAUDE_PATH, no PATH" ` - -Status "FAIL" ` - -Details $_.Exception.Message ` - -DurationMs $Duration - } -} - -# --- Test Category 3: Common Locations (Priority 3) --- - -function Test-Category3-CommonLocations { - Write-TestHeader "Category 3: Common Locations (Priority 3)" - - # Test 3.1: Claude in C:\Program Files - $TestStart = Get-Date - try { - if ($QuickTest) { - Write-TestResult -TestName "Test 3.1: Claude in C:\Program Files" ` - -Status "SKIP" ` - -Details "Skipped in quick test mode" - } else { - # This test requires admin rights to create in C:\Program Files - Write-TestResult -TestName "Test 3.1: Claude in C:\Program Files" ` - -Status "SKIP" ` - -Details "Requires admin rights to test" - } - } catch { - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 3.1: Claude in C:\Program Files" ` - -Status "FAIL" ` - -Details $_.Exception.Message ` - -DurationMs $Duration - } - - # Test 3.2: Claude on D drive - $TestStart = Get-Date - try { - if ($QuickTest) { - Write-TestResult -TestName "Test 3.2: Claude on D drive" ` - -Status "SKIP" ` - -Details "Skipped in quick test mode" - } else { - # This test requires D: drive to exist - if (Test-Path "D:\") { - Write-TestResult -TestName "Test 3.2: Claude on D drive" ` - -Status "SKIP" ` - -Details "Requires D: drive setup" - } else { - Write-TestResult -TestName "Test 3.2: Claude on D drive" ` - -Status "SKIP" ` - -Details "D: drive not available" - } - } - } catch { - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 3.2: Claude on D drive" ` - -Status "FAIL" ` - -Details $_.Exception.Message ` - -DurationMs $Duration - } - - # Test 3.3: Claude not found anywhere - $TestStart = Get-Date - try { - $env:CCS_CLAUDE_PATH = $null - $env:PATH = $Script:OriginalEnv.PATH - - # Remove mock from PATH, should fail to find anywhere - $DetectedPath = Test-ClaudeDetection -ShouldSucceed $false - - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 3.3: Claude not found anywhere" ` - -Status "PASS" ` - -Details "Correctly returned empty when not found" ` - -DurationMs $Duration - } catch { - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 3.3: Claude not found anywhere" ` - -Status "FAIL" ` - -Details $_.Exception.Message ` - -DurationMs $Duration - } -} - -# --- Test Category 4: Security Validation --- - -function Test-Category4-SecurityValidation { - Write-TestHeader "Category 4: Security Validation" - - # Test 4.1: Command injection attempt (semicolon) - $TestStart = Get-Date - try { - $env:CCS_CLAUDE_PATH = "claude.exe; rm -rf /" - - # Should be rejected by character validation - $DetectedPath = Test-ClaudeDetection -ShouldSucceed $false - - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 4.1: Injection attempt (semicolon)" ` - -Status "PASS" ` - -Details "Blocked semicolon character" ` - -DurationMs $Duration - } catch { - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 4.1: Injection attempt (semicolon)" ` - -Status "FAIL" ` - -Details $_.Exception.Message ` - -DurationMs $Duration - } finally { - $env:CCS_CLAUDE_PATH = $null - } - - # Test 4.2: Command injection attempt (pipe) - $TestStart = Get-Date - try { - $env:CCS_CLAUDE_PATH = "claude.exe | malicious.exe" - - # Should be rejected by character validation - $DetectedPath = Test-ClaudeDetection -ShouldSucceed $false - - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 4.2: Injection attempt (pipe)" ` - -Status "PASS" ` - -Details "Blocked pipe character" ` - -DurationMs $Duration - } catch { - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 4.2: Injection attempt (pipe)" ` - -Status "FAIL" ` - -Details $_.Exception.Message ` - -DurationMs $Duration - } finally { - $env:CCS_CLAUDE_PATH = $null - } - - # Test 4.3: Command injection attempt (backtick) - $TestStart = Get-Date - try { - $env:CCS_CLAUDE_PATH = "claude.exe`nmalicious.exe" - - # Should be rejected by character validation - $DetectedPath = Test-ClaudeDetection -ShouldSucceed $false - - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 4.3: Injection attempt (backtick)" ` - -Status "PASS" ` - -Details "Blocked backtick/newline" ` - -DurationMs $Duration - } catch { - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 4.3: Injection attempt (backtick)" ` - -Status "FAIL" ` - -Details $_.Exception.Message ` - -DurationMs $Duration - } finally { - $env:CCS_CLAUDE_PATH = $null - } - - # Test 4.4: Path traversal attempt - $TestStart = Get-Date - try { - # Relative paths should be allowed (valid use case) - $RelativePath = "..\..\Windows\System32\cmd.exe" - $env:CCS_CLAUDE_PATH = $RelativePath - - # Should resolve to absolute path and validate - # Will fail on non-executable, but path format is OK - $DetectedPath = Test-ClaudeDetection -ShouldSucceed $false - - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 4.4: Path traversal (relative paths OK)" ` - -Status "PASS" ` - -Details "Relative paths allowed, validation on file type" ` - -DurationMs $Duration - } catch { - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 4.4: Path traversal (relative paths OK)" ` - -Status "FAIL" ` - -Details $_.Exception.Message ` - -DurationMs $Duration - } finally { - $env:CCS_CLAUDE_PATH = $null - } -} - -# --- Test Category 5: Error Messages --- - -function Test-Category5-ErrorMessages { - Write-TestHeader "Category 5: Error Messages" - - # Test 5.1: Error message completeness - $TestStart = Get-Date - try { - $env:CCS_CLAUDE_PATH = $null - $env:PATH = $Script:OriginalEnv.PATH - - # Capture error output - $CcsPath = Get-CcsPath - - $ErrorOutput = & $CcsPath --help 2>&1 | Out-String - - # Check for required sections in error message - $HasCcsClaudePathStatus = $ErrorOutput -match "CCS_CLAUDE_PATH:" - $HasPathSearch = $ErrorOutput -match "System PATH:" - $HasCommonLocations = $ErrorOutput -match "Common locations:" - $HasSolutions = $ErrorOutput -match "Solutions:" - $HasDebugging = $ErrorOutput -match "Debugging:" - - $AllSectionsPresent = $HasCcsClaudePathStatus -and $HasPathSearch -and - $HasCommonLocations -and $HasSolutions -and $HasDebugging - - if ($AllSectionsPresent) { - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 5.1: Error message completeness" ` - -Status "PASS" ` - -Details "All required sections present" ` - -DurationMs $Duration - } else { - throw "Missing sections in error message" - } - } catch { - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 5.1: Error message completeness" ` - -Status "FAIL" ` - -Details $_.Exception.Message ` - -DurationMs $Duration - } - - # Test 5.2: Error message D drive examples - $TestStart = Get-Date - try { - $env:CCS_CLAUDE_PATH = $null - $env:PATH = $Script:OriginalEnv.PATH - - $CcsPath = Get-CcsPath - - $ErrorOutput = & $CcsPath --help 2>&1 | Out-String - - $HasDDriveExample = $ErrorOutput -match "D:" - - if ($HasDDriveExample) { - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 5.2: Error message D drive examples" ` - -Status "PASS" ` - -Details "D: drive examples present" ` - -DurationMs $Duration - } else { - throw "D: drive examples missing" - } - } catch { - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 5.2: Error message D drive examples" ` - -Status "FAIL" ` - -Details $_.Exception.Message ` - -DurationMs $Duration - } -} - -# --- Test Category 6: Integration Tests --- - -function Test-Category6-Integration { - Write-TestHeader "Category 6: Integration Tests" - - # Test 6.1: Full workflow with CCS_CLAUDE_PATH - $TestStart = Get-Date - try { - $MockPath = Get-MockClaudePath - $env:CCS_CLAUDE_PATH = $MockPath - - $CcsPath = Get-CcsPath - - # Run ccs with mock claude (will fail on config but detection should work) - $Output = & $CcsPath --help 2>&1 | Out-String - - # Check if it used the custom Claude path (not error about not finding) - $UsedCustomPath = -not ($Output -match "Claude CLI not found") - - if ($UsedCustomPath) { - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 6.1: Full workflow with CCS_CLAUDE_PATH" ` - -Status "PASS" ` - -Details "Used custom Claude path successfully" ` - -DurationMs $Duration - } else { - throw "Did not use custom Claude path" - } - } catch { - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 6.1: Full workflow with CCS_CLAUDE_PATH" ` - -Status "FAIL" ` - -Details $_.Exception.Message ` - -DurationMs $Duration - } finally { - $env:CCS_CLAUDE_PATH = $null - } - - # Test 6.2: Version command bypasses detection - $TestStart = Get-Date - try { - $env:CCS_CLAUDE_PATH = $null - - $CcsPath = Get-CcsPath - - $Output = & $CcsPath --version 2>&1 | Out-String - - $ShowsVersion = $Output -match "CCS \(Claude Code Switch\) version" - - if ($ShowsVersion) { - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 6.2: Version command bypasses detection" ` - -Status "PASS" ` - -Details "Version shown without Claude detection" ` - -DurationMs $Duration - } else { - throw "Version command failed" - } - } catch { - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 6.2: Version command bypasses detection" ` - -Status "FAIL" ` - -Details $_.Exception.Message ` - -DurationMs $Duration - } - - # Test 6.3: Help command uses detection - $TestStart = Get-Date - try { - $env:CCS_CLAUDE_PATH = $null - - $CcsPath = Get-CcsPath - - $Output = & $CcsPath --help 2>&1 | Out-String - - $TriedDetection = $Output -match "Claude CLI not found" - - if ($TriedDetection) { - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 6.3: Help command uses detection" ` - -Status "PASS" ` - -Details "Help command triggered Claude detection" ` - -DurationMs $Duration - } else { - throw "Help command did not trigger detection" - } - } catch { - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 6.3: Help command uses detection" ` - -Status "FAIL" ` - -Details $_.Exception.Message ` - -DurationMs $Duration - } -} - -# --- Test Category 7: Edge Cases --- - -function Test-Category7-EdgeCases { - Write-TestHeader "Category 7: Edge Cases" - - # Test 7.1: Empty CCS_CLAUDE_PATH - $TestStart = Get-Date - try { - $env:CCS_CLAUDE_PATH = "" - - # Should treat as unset and continue fallback - $DetectedPath = Test-ClaudeDetection -ShouldSucceed $false - - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 7.1: Empty CCS_CLAUDE_PATH" ` - -Status "PASS" ` - -Details "Treated as unset, continued fallback" ` - -DurationMs $Duration - } catch { - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 7.1: Empty CCS_CLAUDE_PATH" ` - -Status "FAIL" ` - -Details $_.Exception.Message ` - -DurationMs $Duration - } finally { - $env:CCS_CLAUDE_PATH = $null - } - - # Test 7.2: Whitespace-only CCS_CLAUDE_PATH - $TestStart = Get-Date - try { - $env:CCS_CLAUDE_PATH = " " - - # Should fail validation and continue fallback - $DetectedPath = Test-ClaudeDetection -ShouldSucceed $false - - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 7.2: Whitespace-only CCS_CLAUDE_PATH" ` - -Status "PASS" ` - -Details "Validation failed, continued fallback" ` - -DurationMs $Duration - } catch { - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 7.2: Whitespace-only CCS_CLAUDE_PATH" ` - -Status "FAIL" ` - -Details $_.Exception.Message ` - -DurationMs $Duration - } finally { - $env:CCS_CLAUDE_PATH = $null - } - - # Test 7.3: Very long path (>260 characters) - $TestStart = Get-Date - try { - if ($QuickTest) { - Write-TestResult -TestName "Test 7.3: Very long path (>260 chars)" ` - -Status "SKIP" ` - -Details "Skipped in quick test mode" - } else { - # Create a path longer than 260 characters - $LongPath = "C:\" + ("very-long-directory-name\" * 20) + "claude.exe" - $env:CCS_CLAUDE_PATH = $LongPath - - # Should handle long paths (may fail on file not found, not path length) - $DetectedPath = Test-ClaudeDetection -ShouldSucceed $false - - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 7.3: Very long path (>260 chars)" ` - -Status "PASS" ` - -Details "Handled long path without crash" ` - -DurationMs $Duration - } - } catch { - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 7.3: Very long path (>260 chars)" ` - -Status "FAIL" ` - -Details $_.Exception.Message ` - -DurationMs $Duration - } finally { - $env:CCS_CLAUDE_PATH = $null - } - - # Test 7.4: Unicode in path - $TestStart = Get-Date - try { - # Create directory with Unicode characters - $UnicodePath = Join-Path $Script:TestDir "文件夹" - New-Item -ItemType Directory -Path $UnicodePath -Force | Out-Null - $UnicodeClaudePath = Join-Path $UnicodePath "claude.exe" - Copy-Item (Get-MockClaudePath) $UnicodeClaudePath -Force - - $env:CCS_CLAUDE_PATH = $UnicodeClaudePath - - $DetectedPath = Test-ClaudeDetection -ExpectedPath $UnicodeClaudePath -ShouldSucceed $true - - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 7.4: Unicode in path" ` - -Status "PASS" ` - -Details "Handled Unicode characters correctly" ` - -DurationMs $Duration - } catch { - $Duration = ((Get-Date) - $TestStart).TotalMilliseconds - Write-TestResult -TestName "Test 7.4: Unicode in path" ` - -Status "FAIL" ` - -Details $_.Exception.Message ` - -DurationMs $Duration - } finally { - $env:CCS_CLAUDE_PATH = $null - } -} - -# --- Main Execution --- - -function Show-TestSummary { - $EndTime = Get-Date - $TotalDuration = ($EndTime - $Script:StartTime).TotalSeconds - - Write-Host "`n========================================" -ForegroundColor Cyan - Write-Host " TEST SUMMARY" -ForegroundColor Cyan - Write-Host "========================================`n" -ForegroundColor Cyan - - Write-Host "Total Tests: $Script:TotalTests" - Write-Host "Passed: $Script:PassedTests" -ForegroundColor Green - Write-Host "Failed: $Script:FailedTests" -ForegroundColor Red - Write-Host "Skipped: $Script:SkippedTests" -ForegroundColor Yellow - - $PassRate = if ($Script:TotalTests -gt 0) { - [math]::Round(($Script:PassedTests / $Script:TotalTests) * 100, 2) - } else { - 0 - } - Write-Host "Pass Rate: $PassRate%" - Write-Host "Duration: ${TotalDuration}s" - - Write-Host "`n" - - # Show failures - if ($Script:FailedTests -gt 0) { - Write-Host "FAILED TESTS:" -ForegroundColor Red - $Script:TestResults | Where-Object { $_.Status -eq "FAIL" } | ForEach-Object { - Write-Host " - $($_.TestName)" -ForegroundColor Red - Write-Host " $($_.Details)" -ForegroundColor Gray - } - Write-Host "`n" - } - - # Exit code - if ($Script:FailedTests -gt 0) { - exit 1 - } else { - exit 0 - } -} - -# --- Run Tests --- - -Write-Host "========================================" -ForegroundColor Cyan -Write-Host " CCS Custom Claude CLI Path Test Suite" -ForegroundColor Cyan -Write-Host " Version: 2.3.0" -ForegroundColor Cyan -Write-Host "========================================`n" -ForegroundColor Cyan - -Initialize-TestEnvironment - -try { - Test-Category1-EnvVarDetection - Test-Category2-PathDetection - Test-Category3-CommonLocations - Test-Category4-SecurityValidation - Test-Category5-ErrorMessages - Test-Category6-Integration - Test-Category7-EdgeCases - - Show-TestSummary -} finally { - Restore-TestEnvironment -} diff --git a/tests/uninstall-test.ps1 b/tests/uninstall-test.ps1 deleted file mode 100644 index 978c8b24..00000000 --- a/tests/uninstall-test.ps1 +++ /dev/null @@ -1,454 +0,0 @@ -#!/usr/bin/env pwsh - -<# -.SYNOPSIS - Test suite for CCS --uninstall functionality (Windows PowerShell) - -.DESCRIPTION - Tests the --uninstall flag for CCS executable on Windows PowerShell. - Tests against actual system installation for simplicity. - -.NOTES - Author: CCS Test Suite - Version: 1.0 - Based on: install-test.ps1 patterns -#> - -#Requires -Version 5.1 - -param( - [Parameter(Mandatory=$false)] - [string]$CcsPath = (Join-Path $PSScriptRoot "..\ccs.ps1") -) - -# Set error action preference -$ErrorActionPreference = "Stop" - -# Test variables -$PassCount = 0 -$FailCount = 0 -$TotalTests = 0 - -# Colors -$Colors = @{ - Red = "Red" - Green = "Green" - Yellow = "Yellow" - Cyan = "Cyan" - Gray = "Gray" - White = "White" -} - -# Test paths -$ClaudeDir = Join-Path $env:USERPROFILE ".claude" -$BackupDir = Join-Path $env:TEMP "ccs-test-backup-$(Get-Date -Format 'yyyyMMddHHmmss')" -$TestHome = Join-Path $env:TEMP "ccs-test-home" -$TestClaudeDir = Join-Path $TestHome ".claude" - -function Write-ColorOutput { - param( - [string]$Message, - [string]$Color = "White" - ) - Write-Host $Message -ForegroundColor $Colors[$Color] -} - -function Test-Case { - param( - [string]$Name, - [string]$Expected, - [scriptblock]$TestCode - ) - - $script:TotalTests++ - Write-Host "" - Write-ColorOutput "[$TotalTests] $Name" "Cyan" - Write-ColorOutput " Expected: $Expected" "Gray" - - try { - $result = & $TestCode - if ($result) { - Write-ColorOutput " Result: PASS" "Green" - $script:PassCount++ - return $true - } else { - Write-ColorOutput " Result: FAIL" "Red" - $script:FailCount++ - return $false - } - } catch { - Write-ColorOutput " Result: FAIL - Exception: $($_.Exception.Message)" "Red" - $script:FailCount++ - return $false - } -} - -function Cleanup-AndRestore { - Write-Host "" - Write-ColorOutput "Cleaning up and restoring..." "Yellow" - - # Remove test directory - if (Test-Path $TestHome) { - Remove-Item $TestHome -Recurse -Force - } - - # Restore backup if it exists - if (Test-Path $BackupDir) { - if (Test-Path $ClaudeDir) { - Remove-Item $ClaudeDir -Recurse -Force - } - Move-Item $BackupDir $ClaudeDir - } - - Write-ColorOutput "Cleanup complete." "Green" -} - -# ============================================================================ -# SETUP -# ============================================================================ - -Write-Host "" -Write-ColorOutput "========================================" "Cyan" -Write-ColorOutput "CCS --uninstall Functionality Tests" "Cyan" -Write-ColorOutput "========================================" "Cyan" -Write-Host "" - -# Backup existing .claude directory if it exists -if (Test-Path $ClaudeDir) { - Write-ColorOutput "Backing up existing .claude directory..." "Yellow" - Copy-Item $ClaudeDir $BackupDir -Recurse -} - -# Clean any existing test directory -if (Test-Path $TestHome) { - Remove-Item $TestHome -Recurse -Force -} - -New-Item -ItemType Directory -Path $TestHome -Force | Out-Null - -# Verify CCS executable exists -if (-not (Test-Path $CcsPath)) { - Write-ColorOutput "ERROR: CCS executable not found at $CcsPath" "Red" - exit 1 -} - -# Test CCS executable basic functionality -Write-ColorOutput "Testing CCS executable basic functionality..." "Yellow" -try { - $versionOutput = & "$CcsPath" --version 2>&1 | Out-String - Write-ColorOutput "CCS Version: $versionOutput" "Green" -} catch { - Write-ColorOutput "Warning: CCS executable test failed: $($_.Exception.Message)" "Yellow" - Write-ColorOutput "Attempting to continue with tests..." "Yellow" -} - -# ============================================================================ -# TEST SECTION 1: UNINSTALL WHEN NOTHING IS INSTALLED -# ============================================================================ - -Write-Host "" -Write-ColorOutput "========================================" "Yellow" -Write-ColorOutput "SECTION 1: UNINSTALL WHEN NOTHING IS INSTALLED" "Yellow" -Write-ColorOutput "========================================" "Yellow" - -Test-Case "Empty uninstall: Command executes without error" "Exit code 0" { - $originalHome = $env:HOME - $env:HOME = $TestHome - try { - $exitCode = 0 - & "$CcsPath" --uninstall 2>&1 | Out-Null - if ($LASTEXITCODE) { $exitCode = $LASTEXITCODE } - $exitCode -eq 0 - } finally { - $env:HOME = $originalHome - } -} - -Test-Case "Empty uninstall: Output contains appropriate message" "Nothing to uninstall message" { - $originalHome = $env:HOME - $env:HOME = $TestHome - try { - $output = & "$CcsPath" --uninstall 2>&1 | Out-String - $output -match "Nothing to uninstall" -or $output -match "not found" - } finally { - $env:HOME = $originalHome - } -} - -Test-Case "Empty uninstall: Reports 0 items removed" "Zero removed count" { - $originalHome = $env:HOME - $env:HOME = $TestHome - try { - $output = & "$CcsPath" --uninstall 2>&1 | Out-String - $output -match "Removed: 0 items" - } finally { - $env:HOME = $originalHome - } -} - -# ============================================================================ -# SETUP FOR FULL INSTALL/UNINSTALL CYCLE -# ============================================================================ - -# Install first so we can test uninstall -Write-Host "" -Write-ColorOutput "Setting up for install/uninstall cycle test..." "Yellow" -$originalHome = $env:HOME -$env:HOME = $TestHome -try { - & $CcsPath --install | Out-Null - Write-ColorOutput "Install completed successfully" "Green" -} catch { - Write-ColorOutput "Warning: Install command failed, but continuing with tests" "Yellow" -} finally { - $env:HOME = $originalHome -} - -# ============================================================================ -# TEST SECTION 2: UNINSTALL AFTER INSTALL -# ============================================================================ - -Write-Host "" -Write-ColorOutput "========================================" "Yellow" -Write-ColorOutput "SECTION 2: UNINSTALL AFTER INSTALL" "Yellow" -Write-ColorOutput "========================================" "Yellow" - -Test-Case "Uninstall: Command executes without error" "Exit code 0" { - $originalHome = $env:HOME - $env:HOME = $TestHome - try { - $exitCode = 0 - & "$CcsPath" --uninstall 2>&1 | Out-Null - if ($LASTEXITCODE) { $exitCode = $LASTEXITCODE } - $exitCode -eq 0 - } finally { - $env:HOME = $originalHome - } -} - -Test-Case "Uninstall: Removes ccs.md command file" "Command file removed" { - -not (Test-Path (Join-Path $TestClaudeDir "commands\ccs.md")) -} - -Test-Case "Uninstall: Removes ccs-delegation skill directory" "Skill directory removed" { - -not (Test-Path (Join-Path $TestClaudeDir "skills\ccs-delegation")) -} - -Test-Case "Uninstall: Preserves other commands" "Other commands unaffected" { - # Create a dummy command file first - $commandsDir = Join-Path $TestClaudeDir "commands" - New-Item -ItemType Directory -Path $commandsDir -Force | Out-Null - Set-Content -Path (Join-Path $commandsDir "test.md") -Value "test" - - # Install CCS, then uninstall - $originalHome = $env:HOME - $env:HOME = $TestHome - try { - & $CcsPath --install | Out-Null - & $CcsPath --uninstall | Out-Null - } finally { - $env:HOME = $originalHome - } - - # Check that test.md still exists - Test-Path (Join-Path $commandsDir "test.md") -} - -Test-Case "Uninstall: Preserves other skills" "Other skills unaffected" { - # Create a dummy skill directory first - $skillDir = Join-Path $TestClaudeDir "skills\test-skill" - New-Item -ItemType Directory -Path $skillDir -Force | Out-Null - Set-Content -Path (Join-Path $skillDir "SKILL.md") -Value "test" - - # Install CCS, then uninstall - $originalHome = $env:HOME - $env:HOME = $TestHome - try { - & $CcsPath --install | Out-Null - & $CcsPath --uninstall | Out-Null - } finally { - $env:HOME = $originalHome - } - - # Check that test-skill still exists - Test-Path $skillDir -} - -# ============================================================================ -# TEST SECTION 3: IDEMPOTENCY -# ============================================================================ - -Write-Host "" -Write-ColorOutput "========================================" "Yellow" -Write-ColorOutput "SECTION 3: IDEMPOTENCY" "Yellow" -Write-ColorOutput "========================================" "Yellow" - -Test-Case "Idempotent: Second uninstall succeeds" "Second --uninstall doesn't error" { - $env:HOME = $TestHome - try { - & $CcsPath --uninstall | Out-Null - return $true - } catch { - return $false - } -} - -Test-Case "Idempotent: Reports nothing to remove on second run" "Reports nothing found" { - $env:HOME = $TestHome - $output = try { & $CcsPath --uninstall 2>&1 | Out-String } catch { $_.Exception.Message } - $output -match "not found" -or $output -match "Nothing to uninstall" -} - -# ============================================================================ -# TEST SECTION 4: OUTPUT FORMATTING -# ============================================================================ - -Write-Host "" -Write-ColorOutput "========================================" "Yellow" -Write-ColorOutput "SECTION 4: OUTPUT FORMATTING" "Yellow" -Write-ColorOutput "========================================" "Yellow" - -# Set up fresh install for output testing -$env:HOME = $TestHome -try { & $CcsPath --install | Out-Null } catch { } - -Test-Case "Output: Contains uninstall header" "Contains uninstall message" { - $env:HOME = $TestHome - $output = try { & $CcsPath --uninstall 2>&1 | Out-String } catch { $_.Exception.Message } - $output -match "Uninstalling CCS" -} - -Test-Case "Output: Shows removal success message" "Contains success message" { - $env:HOME = $TestHome - $output = try { & $CcsPath --uninstall 2>&1 | Out-String } catch { $_.Exception.Message } - $output -match "\[OK\] Uninstall complete!" -} - -Test-Case "Output: Shows reinstallation instruction" "Contains reinstallation hint" { - $env:HOME = $TestHome - $output = try { & $CcsPath --uninstall 2>&1 | Out-String } catch { $_.Exception.Message } - $output -match "To reinstall: ccs --install" -} - -# ============================================================================ -# TEST SECTION 5: INTEGRATION WITH CCS -# ============================================================================ - -Write-Host "" -Write-ColorOutput "========================================" "Yellow" -Write-ColorOutput "SECTION 5: INTEGRATION WITH CCS" "Yellow" -Write-ColorOutput "========================================" "Yellow" - -Test-Case "Integration: --uninstall executes without profile error" "No profile error on --uninstall" { - $env:HOME = $TestHome - try { - & $CcsPath --uninstall | Out-Null - return $true - } catch { - return $false - } -} - -Test-Case "Integration: --version still works after uninstall" "Version command exits successfully" { - $env:HOME = $TestHome - try { - & $CcsPath --version | Out-Null - return $true - } catch { - return $false - } -} - -Test-Case "Integration: --help still works after uninstall" "Help command exits successfully" { - $env:HOME = $TestHome - try { - & $CcsPath --help | Out-Null - return $true - } catch { - return $false - } -} - -# ============================================================================ -# TEST SECTION 6: EDGE CASES -# ============================================================================ - -Write-Host "" -Write-ColorOutput "========================================" "Yellow" -Write-ColorOutput "SECTION 6: EDGE CASES" "Yellow" -Write-ColorOutput "========================================" "Yellow" - -Test-Case "Edge case: Partial install (commands only)" "Handles partial installation" { - # Create only command file - $commandsDir = Join-Path $TestClaudeDir "commands" - New-Item -ItemType Directory -Path $commandsDir -Force | Out-Null - Set-Content -Path (Join-Path $commandsDir "ccs.md") -Value "test" - - # Uninstall should handle this gracefully - $env:HOME = $TestHome - try { - & $CcsPath --uninstall | Out-Null - return $true - } catch { - return $false - } -} - -Test-Case "Edge case: Partial install (skills only)" "Handles partial installation" { - # Create only skill directory - $skillDir = Join-Path $TestClaudeDir "skills\ccs-delegation" - New-Item -ItemType Directory -Path $skillDir -Force | Out-Null - Set-Content -Path (Join-Path $skillDir "SKILL.md") -Value "test" - - # Uninstall should handle this gracefully - $env:HOME = $TestHome - try { - & $CcsPath --uninstall | Out-Null - return $true - } catch { - return $false - } -} - -Test-Case "Edge case: Missing parent directories" "Handles missing .claude directory" { - # Ensure .claude directory doesn't exist - if (Test-Path $TestClaudeDir) { - Remove-Item $TestClaudeDir -Recurse -Force - } - - $env:HOME = $TestHome - try { - & $CcsPath --uninstall | Out-Null - return $true - } catch { - return $false - } -} - -# ============================================================================ -# SUMMARY -# ============================================================================ - -Write-Host "" -Write-ColorOutput "========================================" "Cyan" -if ($FailCount -eq 0) { - Write-ColorOutput "ALL TESTS PASSED!" "Green" - Write-ColorOutput "========================================" "Green" - Write-ColorOutput "--uninstall functionality is production ready!" "Green" -} else { - Write-ColorOutput "SOME TESTS FAILED" "Red" - Write-ColorOutput "========================================" "Red" - Write-ColorOutput "Review failed tests above for details" "Red" -} - -Write-Host "" -Write-ColorOutput "Test Summary:" "Cyan" -Write-Host " Total tests: $TotalTests" -Write-ColorOutput " Passed: $PassCount" "Green" -Write-ColorOutput " Failed: $FailCount" "Red" -Write-Host "" - -# Cleanup -Cleanup-AndRestore - -exit $FailCount \ No newline at end of file diff --git a/tests/uninstall-test.sh b/tests/uninstall-test.sh deleted file mode 100755 index b4f5273e..00000000 --- a/tests/uninstall-test.sh +++ /dev/null @@ -1,310 +0,0 @@ -#!/usr/bin/env bash -# CCS --uninstall Functionality Testing (Linux/macOS) -# Comprehensive tests for the --uninstall command - -set +e # Don't exit on errors, we're testing -PASS_COUNT=0 -FAIL_COUNT=0 -TOTAL_TESTS=0 - -# Colors -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -CYAN='\033[0;36m' -GRAY='\033[0;37m' -NC='\033[0m' # No Color - -# Get script directory -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -CCS_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" -CCS_PATH="$CCS_ROOT/ccs" - -# Backup/restore paths -CLAUDE_DIR="$HOME/.claude" -BACKUP_DIR="/tmp/ccs-test-backup-$(date +%s)" -TEST_HOME="/tmp/ccs-test-home" -TEST_CLAUDE_DIR="$TEST_HOME/.claude" - -test_case() { - local name="$1" - local expected="$2" - shift 2 - - ((TOTAL_TESTS++)) - echo "" - echo -e "${CYAN}[$TOTAL_TESTS] $name${NC}" - echo -e "${GRAY} Expected: $expected${NC}" - - if "$@"; then - echo -e "${GREEN} Result: PASS${NC}" - ((PASS_COUNT++)) - return 0 - else - echo -e "${RED} Result: FAIL${NC}" - ((FAIL_COUNT++)) - return 1 - fi -} - -cleanup_and_restore() { - echo "" - echo -e "${YELLOW}Cleaning up and restoring...${NC}" - - # Remove test directory - if [[ -d "$TEST_HOME" ]]; then - rm -rf "$TEST_HOME" - fi - - # Restore backup if it exists - if [[ -d "$BACKUP_DIR" ]]; then - if [[ -d "$CLAUDE_DIR" ]]; then - rm -rf "$CLAUDE_DIR" - fi - mv "$BACKUP_DIR" "$CLAUDE_DIR" - fi - - echo -e "${GREEN}Cleanup complete.${NC}" -} - -# ============================================================================ -# SETUP -# ============================================================================ - -echo "" -echo "========================================" -echo "CCS --uninstall Functionality Tests" -echo "========================================" -echo "" - -# Backup existing .claude directory if it exists -if [[ -d "$CLAUDE_DIR" ]]; then - echo -e "${YELLOW}Backing up existing .claude directory...${NC}" - cp -r "$CLAUDE_DIR" "$BACKUP_DIR" -fi - -# Clean any existing test directory -if [[ -d "$TEST_HOME" ]]; then - rm -rf "$TEST_HOME" -fi - -mkdir -p "$TEST_HOME" - -# ============================================================================ -# TEST SECTION 1: UNINSTALL WHEN NOTHING IS INSTALLED -# ============================================================================ - -echo "" -echo "========================================" -echo "SECTION 1: UNINSTALL WHEN NOTHING IS INSTALLED" -echo "========================================" - -test_case "Empty uninstall: Command executes without error" "Exit code 0" bash -c " - HOME='$TEST_HOME' '$CCS_PATH' --uninstall > /tmp/ccs-uninstall-empty.txt 2>&1 -" - -test_case "Empty uninstall: Output contains 'Nothing to uninstall'" "Appropriate message" bash -c " - output=\$(HOME='$TEST_HOME' '$CCS_PATH' --uninstall 2>&1) - [[ \$output =~ 'Nothing to uninstall' ]] -" - -test_case "Empty uninstall: Reports 0 items removed" "Zero removed count" bash -c " - output=\$(HOME='$TEST_HOME' '$CCS_PATH' --uninstall 2>&1) - [[ \$output =~ 'Removed: 0 items' ]] -" - -# ============================================================================ -# SETUP FOR FULL INSTALL/UNINSTALL CYCLE -# ============================================================================ - -# Install first so we can test uninstall -echo "" -echo -e "${YELLOW}Setting up for install/uninstall cycle test...${NC}" -bash -c "HOME='$TEST_HOME' '$CCS_PATH' --install > /dev/null 2>&1" - -# ============================================================================ -# TEST SECTION 2: UNINSTALL AFTER INSTALL -# ============================================================================ - -echo "" -echo "========================================" -echo "SECTION 2: UNINSTALL AFTER INSTALL" -echo "========================================" - -test_case "Uninstall: Command executes without error" "Exit code 0" bash -c " - HOME='$TEST_HOME' '$CCS_PATH' --uninstall > /tmp/ccs-uninstall-after-install.txt 2>&1 -" - -test_case "Uninstall: Removes ccs.md command file" "Command file removed" bash -c " - [[ ! -f '$TEST_CLAUDE_DIR/commands/ccs.md' ]] -" - -test_case "Uninstall: Removes ccs-delegation skill directory" "Skill directory removed" bash -c " - [[ ! -d '$TEST_CLAUDE_DIR/skills/ccs-delegation' ]] -" - -test_case "Uninstall: Preserves other commands" "Other commands unaffected" bash -c " - # Create a dummy command file first - mkdir -p '$TEST_CLAUDE_DIR/commands' - echo 'test' > '$TEST_CLAUDE_DIR/commands/test.md' - # Install CCS, then uninstall - HOME='$TEST_HOME' '$CCS_PATH' --install > /dev/null 2>&1 - HOME='$TEST_HOME' '$CCS_PATH' --uninstall > /dev/null 2>&1 - # Check that test.md still exists - [[ -f '$TEST_CLAUDE_DIR/commands/test.md' ]] -" - -test_case "Uninstall: Preserves other skills" "Other skills unaffected" bash -c " - # Create a dummy skill directory first - mkdir -p '$TEST_CLAUDE_DIR/skills/test-skill' - echo 'test' > '$TEST_CLAUDE_DIR/skills/test-skill/SKILL.md' - # Install CCS, then uninstall - HOME='$TEST_HOME' '$CCS_PATH' --install > /dev/null 2>&1 - HOME='$TEST_HOME' '$CCS_PATH' --uninstall > /dev/null 2>&1 - # Check that test-skill still exists - [[ -d '$TEST_CLAUDE_DIR/skills/test-skill' ]] -" - -# ============================================================================ -# TEST SECTION 3: IDEMPOTENCY -# ============================================================================ - -echo "" -echo "========================================" -echo "SECTION 3: IDEMPOTENCY" -echo "========================================" - -test_case "Idempotent: Second uninstall succeeds" "Second --uninstall doesn't error" bash -c " - HOME='$TEST_HOME' '$CCS_PATH' --uninstall > /dev/null 2>&1 - exit_code=\$? - [[ \$exit_code -eq 0 ]] -" - -test_case "Idempotent: Reports nothing to remove on second run" "Reports nothing found" bash -c " - output=\$(HOME='$TEST_HOME' '$CCS_PATH' --uninstall 2>&1) - [[ \$output =~ 'not found' ]] || [[ \$output =~ 'Nothing to uninstall' ]] -" - -# ============================================================================ -# TEST SECTION 4: OUTPUT FORMATTING -# ============================================================================ - -echo "" -echo "========================================" -echo "SECTION 4: OUTPUT FORMATTING" -echo "========================================" - -# Set up fresh install for output testing -bash -c "HOME='$TEST_HOME' '$CCS_PATH' --install > /dev/null 2>&1" - -test_case "Output: Contains box-drawing header" "Output has ┌─" bash -c " - output=\$(HOME='$TEST_HOME' '$CCS_PATH' --uninstall 2>&1) - [[ \$output =~ ┌─ ]] -" - -test_case "Output: Contains box-drawing footer" "Output has └─" bash -c " - output=\$(HOME='$TEST_HOME' '$CCS_PATH' --uninstall 2>&1) - [[ \$output =~ └─ ]] -" - -test_case "Output: Shows removal success message" "Contains '[OK] Uninstall complete!'" bash -c " - output=\$(HOME='$TEST_HOME' '$CCS_PATH' --uninstall 2>&1) - echo \"\$output\" | grep -q '\[OK\] Uninstall complete!' -" - -test_case "Output: Shows reinstallation instruction" "Contains reinstallation hint" bash -c " - output=\$(HOME='$TEST_HOME' '$CCS_PATH' --uninstall 2>&1) - [[ \$output =~ 'To reinstall: ccs --install' ]] -" - -# ============================================================================ -# TEST SECTION 5: INTEGRATION WITH CCS -# ============================================================================ - -echo "" -echo "========================================" -echo "SECTION 5: INTEGRATION WITH CCS" -echo "========================================" - -test_case "Integration: --uninstall executes without profile error" "No profile error on --uninstall" bash -c " - HOME='$TEST_HOME' '$CCS_PATH' --uninstall > /dev/null 2>&1 - exit_code=\$? - [[ \$exit_code -eq 0 ]] -" - -test_case "Integration: --version still works after uninstall" "Version command exits successfully" bash -c " - HOME='$TEST_HOME' '$CCS_PATH' --version > /dev/null 2>&1 - exit_code=\$? - [[ \$exit_code -eq 0 ]] -" - -test_case "Integration: --help still works after uninstall" "Help command exits successfully" bash -c " - HOME='$TEST_HOME' '$CCS_PATH' --help > /dev/null 2>&1 - exit_code=\$? - [[ \$exit_code -eq 0 ]] -" - -# ============================================================================ -# TEST SECTION 6: EDGE CASES -# ============================================================================ - -echo "" -echo "========================================" -echo "SECTION 6: EDGE CASES" -echo "========================================" - -test_case "Edge case: Partial install (commands only)" "Handles partial installation" bash -c " - # Create only command file - mkdir -p '$TEST_CLAUDE_DIR/commands' - echo 'test' > '$TEST_CLAUDE_DIR/commands/ccs.md' - # Uninstall should handle this gracefully - HOME='$TEST_HOME' '$CCS_PATH' --uninstall > /dev/null 2>&1 - exit_code=\$? - [[ \$exit_code -eq 0 ]] -" - -test_case "Edge case: Partial install (skills only)" "Handles partial installation" bash -c " - # Create only skill directory - mkdir -p '$TEST_CLAUDE_DIR/skills/ccs-delegation' - echo 'test' > '$TEST_CLAUDE_DIR/skills/ccs-delegation/SKILL.md' - # Uninstall should handle this gracefully - HOME='$TEST_HOME' '$CCS_PATH' --uninstall > /dev/null 2>&1 - exit_code=\$? - [[ \$exit_code -eq 0 ]] -" - -test_case "Edge case: Missing parent directories" "Handles missing .claude directory" bash -c " - # Ensure .claude directory doesn't exist - rm -rf '$TEST_CLAUDE_DIR' - HOME='$TEST_HOME' '$CCS_PATH' --uninstall > /dev/null 2>&1 - exit_code=\$? - [[ \$exit_code -eq 0 ]] -" - -# ============================================================================ -# SUMMARY -# ============================================================================ - -echo "" -echo "========================================" -if [[ $FAIL_COUNT -eq 0 ]]; then - echo -e "${GREEN}ALL TESTS PASSED!${NC}" - echo -e "${GREEN}========================================${NC}" - echo -e "${GREEN}--uninstall functionality is production ready!${NC}" -else - echo -e "${RED}SOME TESTS FAILED${NC}" - echo -e "${RED}========================================${NC}" - echo -e "${RED}Review failed tests above for details${NC}" -fi - -echo "" -echo -e "${CYAN}Test Summary:${NC}" -echo -e " Total tests: $TOTAL_TESTS" -echo -e " ${GREEN}Passed: $PASS_COUNT${NC}" -echo -e " ${RED}Failed: $FAIL_COUNT${NC}" -echo "" - -# Cleanup -cleanup_and_restore - -exit $FAIL_COUNT \ No newline at end of file