mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-01-25 02:08:11 +00:00
Co-authored-by: Alan-TheGentleman <alan@thegentleman.dev> Co-authored-by: pedrooot <pedromarting3@gmail.com> Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com>
341 lines
10 KiB
Bash
Executable File
341 lines
10 KiB
Bash
Executable File
#!/bin/bash
|
|
# Unit tests for setup.sh
|
|
# Run: ./skills/setup_test.sh
|
|
#
|
|
# shellcheck disable=SC2317
|
|
# Reason: Test functions are discovered and called dynamically via declare -F
|
|
|
|
set -e
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
SETUP_SCRIPT="$SCRIPT_DIR/setup.sh"
|
|
|
|
# Colors
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
NC='\033[0m'
|
|
|
|
# Test counters
|
|
TESTS_RUN=0
|
|
TESTS_PASSED=0
|
|
TESTS_FAILED=0
|
|
|
|
# Test environment
|
|
TEST_DIR=""
|
|
|
|
# =============================================================================
|
|
# TEST FRAMEWORK
|
|
# =============================================================================
|
|
|
|
setup_test_env() {
|
|
TEST_DIR=$(mktemp -d)
|
|
|
|
# Create mock repo structure
|
|
mkdir -p "$TEST_DIR/skills/typescript"
|
|
mkdir -p "$TEST_DIR/skills/react-19"
|
|
mkdir -p "$TEST_DIR/api"
|
|
mkdir -p "$TEST_DIR/ui"
|
|
mkdir -p "$TEST_DIR/.github"
|
|
|
|
# Create mock SKILL.md files
|
|
echo "# TypeScript Skill" > "$TEST_DIR/skills/typescript/SKILL.md"
|
|
echo "# React 19 Skill" > "$TEST_DIR/skills/react-19/SKILL.md"
|
|
|
|
# Create mock AGENTS.md files
|
|
echo "# Root AGENTS" > "$TEST_DIR/AGENTS.md"
|
|
echo "# API AGENTS" > "$TEST_DIR/api/AGENTS.md"
|
|
echo "# UI AGENTS" > "$TEST_DIR/ui/AGENTS.md"
|
|
|
|
# Copy setup.sh to test dir
|
|
cp "$SETUP_SCRIPT" "$TEST_DIR/skills/setup.sh"
|
|
}
|
|
|
|
teardown_test_env() {
|
|
if [ -n "$TEST_DIR" ] && [ -d "$TEST_DIR" ]; then
|
|
rm -rf "$TEST_DIR"
|
|
fi
|
|
}
|
|
|
|
run_setup() {
|
|
(cd "$TEST_DIR/skills" && bash setup.sh "$@" 2>&1)
|
|
}
|
|
|
|
# Assertions return 0 on success, 1 on failure
|
|
assert_equals() {
|
|
local expected="$1" actual="$2" message="$3"
|
|
if [ "$expected" = "$actual" ]; then
|
|
return 0
|
|
fi
|
|
echo -e "${RED} FAIL: $message${NC}"
|
|
echo " Expected: $expected"
|
|
echo " Actual: $actual"
|
|
return 1
|
|
}
|
|
|
|
assert_contains() {
|
|
local haystack="$1" needle="$2" message="$3"
|
|
if echo "$haystack" | grep -q -F -- "$needle"; then
|
|
return 0
|
|
fi
|
|
echo -e "${RED} FAIL: $message${NC}"
|
|
echo " String not found: $needle"
|
|
return 1
|
|
}
|
|
|
|
assert_file_exists() {
|
|
local file="$1" message="$2"
|
|
if [ -f "$file" ]; then
|
|
return 0
|
|
fi
|
|
echo -e "${RED} FAIL: $message${NC}"
|
|
echo " File not found: $file"
|
|
return 1
|
|
}
|
|
|
|
assert_file_not_exists() {
|
|
local file="$1" message="$2"
|
|
if [ ! -f "$file" ]; then
|
|
return 0
|
|
fi
|
|
echo -e "${RED} FAIL: $message${NC}"
|
|
echo " File should not exist: $file"
|
|
return 1
|
|
}
|
|
|
|
assert_symlink_exists() {
|
|
local link="$1" message="$2"
|
|
if [ -L "$link" ]; then
|
|
return 0
|
|
fi
|
|
echo -e "${RED} FAIL: $message${NC}"
|
|
echo " Symlink not found: $link"
|
|
return 1
|
|
}
|
|
|
|
assert_symlink_not_exists() {
|
|
local link="$1" message="$2"
|
|
if [ ! -L "$link" ]; then
|
|
return 0
|
|
fi
|
|
echo -e "${RED} FAIL: $message${NC}"
|
|
echo " Symlink should not exist: $link"
|
|
return 1
|
|
}
|
|
|
|
assert_dir_exists() {
|
|
local dir="$1" message="$2"
|
|
if [ -d "$dir" ]; then
|
|
return 0
|
|
fi
|
|
echo -e "${RED} FAIL: $message${NC}"
|
|
echo " Directory not found: $dir"
|
|
return 1
|
|
}
|
|
|
|
# =============================================================================
|
|
# TESTS: FLAG PARSING
|
|
# =============================================================================
|
|
|
|
test_flag_help_shows_usage() {
|
|
local output
|
|
output=$(run_setup --help)
|
|
assert_contains "$output" "Usage:" "Help should show usage" && \
|
|
assert_contains "$output" "--all" "Help should mention --all flag" && \
|
|
assert_contains "$output" "--claude" "Help should mention --claude flag"
|
|
}
|
|
|
|
test_flag_unknown_reports_error() {
|
|
local output
|
|
output=$(run_setup --unknown 2>&1) || true
|
|
assert_contains "$output" "Unknown option" "Should report unknown option"
|
|
}
|
|
|
|
test_flag_all_configures_everything() {
|
|
local output
|
|
output=$(run_setup --all)
|
|
assert_contains "$output" "Claude Code" "Should setup Claude" && \
|
|
assert_contains "$output" "Gemini CLI" "Should setup Gemini" && \
|
|
assert_contains "$output" "Codex" "Should setup Codex" && \
|
|
assert_contains "$output" "Copilot" "Should setup Copilot"
|
|
}
|
|
|
|
test_flag_single_claude() {
|
|
local output
|
|
output=$(run_setup --claude)
|
|
assert_contains "$output" "Claude Code" "Should setup Claude" && \
|
|
assert_contains "$output" "[1/1]" "Should show 1/1 steps"
|
|
}
|
|
|
|
test_flag_multiple_combined() {
|
|
local output
|
|
output=$(run_setup --claude --codex)
|
|
assert_contains "$output" "[1/2]" "Should show step 1/2" && \
|
|
assert_contains "$output" "[2/2]" "Should show step 2/2"
|
|
}
|
|
|
|
# =============================================================================
|
|
# TESTS: SYMLINK CREATION
|
|
# =============================================================================
|
|
|
|
test_symlink_claude_created() {
|
|
run_setup --claude > /dev/null
|
|
assert_symlink_exists "$TEST_DIR/.claude/skills" "Claude skills symlink should exist"
|
|
}
|
|
|
|
test_symlink_gemini_created() {
|
|
run_setup --gemini > /dev/null
|
|
assert_symlink_exists "$TEST_DIR/.gemini/skills" "Gemini skills symlink should exist"
|
|
}
|
|
|
|
test_symlink_codex_created() {
|
|
run_setup --codex > /dev/null
|
|
assert_symlink_exists "$TEST_DIR/.codex/skills" "Codex skills symlink should exist"
|
|
}
|
|
|
|
test_symlink_not_created_without_flag() {
|
|
run_setup --copilot > /dev/null
|
|
assert_symlink_not_exists "$TEST_DIR/.claude/skills" "Claude symlink should not exist" && \
|
|
assert_symlink_not_exists "$TEST_DIR/.gemini/skills" "Gemini symlink should not exist" && \
|
|
assert_symlink_not_exists "$TEST_DIR/.codex/skills" "Codex symlink should not exist"
|
|
}
|
|
|
|
# =============================================================================
|
|
# TESTS: AGENTS.md COPYING
|
|
# =============================================================================
|
|
|
|
test_copy_claude_agents_md() {
|
|
run_setup --claude > /dev/null
|
|
assert_file_exists "$TEST_DIR/CLAUDE.md" "Root CLAUDE.md should exist" && \
|
|
assert_file_exists "$TEST_DIR/api/CLAUDE.md" "api/CLAUDE.md should exist" && \
|
|
assert_file_exists "$TEST_DIR/ui/CLAUDE.md" "ui/CLAUDE.md should exist"
|
|
}
|
|
|
|
test_copy_gemini_agents_md() {
|
|
run_setup --gemini > /dev/null
|
|
assert_file_exists "$TEST_DIR/GEMINI.md" "Root GEMINI.md should exist" && \
|
|
assert_file_exists "$TEST_DIR/api/GEMINI.md" "api/GEMINI.md should exist" && \
|
|
assert_file_exists "$TEST_DIR/ui/GEMINI.md" "ui/GEMINI.md should exist"
|
|
}
|
|
|
|
test_copy_copilot_to_github() {
|
|
run_setup --copilot > /dev/null
|
|
assert_file_exists "$TEST_DIR/.github/copilot-instructions.md" "Copilot instructions should exist"
|
|
}
|
|
|
|
test_copy_codex_no_extra_files() {
|
|
run_setup --codex > /dev/null
|
|
assert_file_not_exists "$TEST_DIR/CODEX.md" "CODEX.md should not be created"
|
|
}
|
|
|
|
test_copy_not_created_without_flag() {
|
|
run_setup --codex > /dev/null
|
|
assert_file_not_exists "$TEST_DIR/CLAUDE.md" "CLAUDE.md should not exist" && \
|
|
assert_file_not_exists "$TEST_DIR/GEMINI.md" "GEMINI.md should not exist"
|
|
}
|
|
|
|
test_copy_content_matches_source() {
|
|
run_setup --claude > /dev/null
|
|
local source_content target_content
|
|
source_content=$(cat "$TEST_DIR/AGENTS.md")
|
|
target_content=$(cat "$TEST_DIR/CLAUDE.md")
|
|
assert_equals "$source_content" "$target_content" "CLAUDE.md content should match AGENTS.md"
|
|
}
|
|
|
|
# =============================================================================
|
|
# TESTS: DIRECTORY CREATION
|
|
# =============================================================================
|
|
|
|
test_dir_claude_created() {
|
|
rm -rf "$TEST_DIR/.claude"
|
|
run_setup --claude > /dev/null
|
|
assert_dir_exists "$TEST_DIR/.claude" ".claude directory should be created"
|
|
}
|
|
|
|
test_dir_gemini_created() {
|
|
rm -rf "$TEST_DIR/.gemini"
|
|
run_setup --gemini > /dev/null
|
|
assert_dir_exists "$TEST_DIR/.gemini" ".gemini directory should be created"
|
|
}
|
|
|
|
test_dir_codex_created() {
|
|
rm -rf "$TEST_DIR/.codex"
|
|
run_setup --codex > /dev/null
|
|
assert_dir_exists "$TEST_DIR/.codex" ".codex directory should be created"
|
|
}
|
|
|
|
# =============================================================================
|
|
# TESTS: IDEMPOTENCY
|
|
# =============================================================================
|
|
|
|
test_idempotent_multiple_runs() {
|
|
run_setup --claude > /dev/null
|
|
run_setup --claude > /dev/null
|
|
assert_symlink_exists "$TEST_DIR/.claude/skills" "Symlink should still exist after second run" && \
|
|
assert_file_exists "$TEST_DIR/CLAUDE.md" "CLAUDE.md should still exist after second run"
|
|
}
|
|
|
|
# =============================================================================
|
|
# TEST RUNNER (autodiscovery)
|
|
# =============================================================================
|
|
|
|
run_all_tests() {
|
|
local test_functions current_section=""
|
|
|
|
# Discover all test_* functions
|
|
test_functions=$(declare -F | awk '{print $3}' | grep '^test_' | sort)
|
|
|
|
for test_func in $test_functions; do
|
|
# Extract section from function name (e.g., test_flag_* -> "Flag")
|
|
local section
|
|
section=$(echo "$test_func" | sed 's/^test_//' | cut -d'_' -f1)
|
|
section="$(echo "${section:0:1}" | tr '[:lower:]' '[:upper:]')${section:1}"
|
|
|
|
# Print section header if changed
|
|
if [ "$section" != "$current_section" ]; then
|
|
[ -n "$current_section" ] && echo ""
|
|
echo -e "${YELLOW}${section} tests:${NC}"
|
|
current_section="$section"
|
|
fi
|
|
|
|
# Convert function name to readable test name
|
|
local test_name
|
|
test_name=$(echo "$test_func" | sed 's/^test_//' | tr '_' ' ')
|
|
|
|
TESTS_RUN=$((TESTS_RUN + 1))
|
|
echo -n " $test_name... "
|
|
|
|
setup_test_env
|
|
|
|
if $test_func; then
|
|
echo -e "${GREEN}PASS${NC}"
|
|
TESTS_PASSED=$((TESTS_PASSED + 1))
|
|
else
|
|
TESTS_FAILED=$((TESTS_FAILED + 1))
|
|
fi
|
|
|
|
teardown_test_env
|
|
done
|
|
}
|
|
|
|
# =============================================================================
|
|
# MAIN
|
|
# =============================================================================
|
|
|
|
echo ""
|
|
echo "🧪 Running setup.sh unit tests"
|
|
echo "==============================="
|
|
echo ""
|
|
|
|
run_all_tests
|
|
|
|
echo ""
|
|
echo "==============================="
|
|
if [ $TESTS_FAILED -eq 0 ]; then
|
|
echo -e "${GREEN}✅ All $TESTS_RUN tests passed!${NC}"
|
|
exit 0
|
|
else
|
|
echo -e "${RED}❌ $TESTS_FAILED of $TESTS_RUN tests failed${NC}"
|
|
exit 1
|
|
fi
|