Add check-skills: verify skill symlinks match source repo
Compares installed skill symlinks against the source directory, reporting missing, stale, and orphan entries. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
125
tests/test-check-skills.sh
Executable file
125
tests/test-check-skills.sh
Executable file
@@ -0,0 +1,125 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Test check-skills script
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
SCRIPT="$SCRIPT_DIR/../scripts/check-skills"
|
||||
|
||||
GREEN='\033[0;32m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m'
|
||||
|
||||
pass=0
|
||||
fail=0
|
||||
|
||||
assert_exit() {
|
||||
local desc="$1" expected="$2"
|
||||
shift 2
|
||||
local actual
|
||||
if "$@" >/dev/null 2>&1; then actual=0; else actual=$?; fi
|
||||
if [[ "$actual" -eq "$expected" ]]; then
|
||||
echo -e " ${GREEN}PASS${NC} $desc"
|
||||
pass=$((pass + 1))
|
||||
else
|
||||
echo -e " ${RED}FAIL${NC} $desc (expected exit $expected, got $actual)"
|
||||
fail=$((fail + 1))
|
||||
fi
|
||||
}
|
||||
|
||||
assert_output_contains() {
|
||||
local desc="$1" pattern="$2"
|
||||
shift 2
|
||||
local output
|
||||
output="$("$@" 2>&1)" || true
|
||||
if echo "$output" | grep -qE "$pattern"; then
|
||||
echo -e " ${GREEN}PASS${NC} $desc"
|
||||
pass=$((pass + 1))
|
||||
else
|
||||
echo -e " ${RED}FAIL${NC} $desc (pattern '$pattern' not found in output)"
|
||||
fail=$((fail + 1))
|
||||
fi
|
||||
}
|
||||
|
||||
# Setup temp dirs
|
||||
TMPDIR_ROOT="$(mktemp -d)"
|
||||
trap 'rm -rf "$TMPDIR_ROOT"' EXIT
|
||||
|
||||
# Create a fake skills source with two skills
|
||||
FAKE_SOURCE="$TMPDIR_ROOT/source"
|
||||
mkdir -p "$FAKE_SOURCE/skill-a" "$FAKE_SOURCE/skill-b" "$FAKE_SOURCE/not-a-skill"
|
||||
echo "---" > "$FAKE_SOURCE/skill-a/SKILL.md"
|
||||
echo "---" > "$FAKE_SOURCE/skill-b/SKILL.md"
|
||||
# not-a-skill has no SKILL.md — should be skipped
|
||||
|
||||
# Test 1: All linked
|
||||
echo "Test: All skills linked"
|
||||
FAKE_PROFILE="$TMPDIR_ROOT/profile-all"
|
||||
mkdir -p "$FAKE_PROFILE/skills"
|
||||
ln -s "$FAKE_SOURCE/skill-a" "$FAKE_PROFILE/skills/skill-a"
|
||||
ln -s "$FAKE_SOURCE/skill-b" "$FAKE_PROFILE/skills/skill-b"
|
||||
assert_exit "exits 0 when all linked" 0 "$SCRIPT" --profile "$FAKE_PROFILE" "$FAKE_SOURCE"
|
||||
assert_output_contains "shows LINKED for skill-a" "LINKED.*skill-a" "$SCRIPT" --profile "$FAKE_PROFILE" "$FAKE_SOURCE"
|
||||
assert_output_contains "shows LINKED for skill-b" "LINKED.*skill-b" "$SCRIPT" --profile "$FAKE_PROFILE" "$FAKE_SOURCE"
|
||||
assert_output_contains "summary shows 2 linked" "2 linked" "$SCRIPT" --profile "$FAKE_PROFILE" "$FAKE_SOURCE"
|
||||
|
||||
# Test 2: Missing skill
|
||||
echo "Test: Missing skill"
|
||||
FAKE_PROFILE2="$TMPDIR_ROOT/profile-missing"
|
||||
mkdir -p "$FAKE_PROFILE2/skills"
|
||||
ln -s "$FAKE_SOURCE/skill-a" "$FAKE_PROFILE2/skills/skill-a"
|
||||
assert_exit "exits 1 when skill missing" 1 "$SCRIPT" --profile "$FAKE_PROFILE2" "$FAKE_SOURCE"
|
||||
assert_output_contains "shows MISSING for skill-b" "MISSING.*skill-b" "$SCRIPT" --profile "$FAKE_PROFILE2" "$FAKE_SOURCE"
|
||||
|
||||
# Test 3: Stale symlink (points elsewhere)
|
||||
echo "Test: Stale symlink"
|
||||
FAKE_PROFILE3="$TMPDIR_ROOT/profile-stale"
|
||||
mkdir -p "$FAKE_PROFILE3/skills"
|
||||
ln -s "$FAKE_SOURCE/skill-a" "$FAKE_PROFILE3/skills/skill-a"
|
||||
ln -s "/some/other/path" "$FAKE_PROFILE3/skills/skill-b"
|
||||
assert_exit "exits 1 when stale" 1 "$SCRIPT" --profile "$FAKE_PROFILE3" "$FAKE_SOURCE"
|
||||
assert_output_contains "shows STALE for skill-b" "STALE.*skill-b" "$SCRIPT" --profile "$FAKE_PROFILE3" "$FAKE_SOURCE"
|
||||
|
||||
# Test 4: Orphan skill
|
||||
echo "Test: Orphan skill"
|
||||
FAKE_PROFILE4="$TMPDIR_ROOT/profile-orphan"
|
||||
mkdir -p "$FAKE_PROFILE4/skills/extra-skill"
|
||||
ln -s "$FAKE_SOURCE/skill-a" "$FAKE_PROFILE4/skills/skill-a"
|
||||
ln -s "$FAKE_SOURCE/skill-b" "$FAKE_PROFILE4/skills/skill-b"
|
||||
assert_exit "exits 0 (orphans are informational)" 0 "$SCRIPT" --profile "$FAKE_PROFILE4" "$FAKE_SOURCE"
|
||||
assert_output_contains "shows ORPHAN for extra-skill" "ORPHAN.*extra-skill" "$SCRIPT" --profile "$FAKE_PROFILE4" "$FAKE_SOURCE"
|
||||
|
||||
# Test 5: No profile skills dir
|
||||
echo "Test: No profile skills directory"
|
||||
FAKE_PROFILE5="$TMPDIR_ROOT/profile-empty"
|
||||
mkdir -p "$FAKE_PROFILE5"
|
||||
assert_exit "exits 1 when no skills dir (all missing)" 1 "$SCRIPT" --profile "$FAKE_PROFILE5" "$FAKE_SOURCE"
|
||||
assert_output_contains "shows MISSING for both" "2 missing" "$SCRIPT" --profile "$FAKE_PROFILE5" "$FAKE_SOURCE"
|
||||
|
||||
# Test 6: Invalid source dir
|
||||
echo "Test: Invalid source directory"
|
||||
assert_exit "exits 1 for nonexistent source" 1 "$SCRIPT" --profile "$FAKE_PROFILE" "/nonexistent/path"
|
||||
|
||||
# Test 7: --help
|
||||
echo "Test: Help flag"
|
||||
assert_exit "--help exits 0" 0 "$SCRIPT" --help
|
||||
assert_output_contains "--help shows usage" "Usage:" "$SCRIPT" --help
|
||||
|
||||
# Test 8: --dryrun accepted
|
||||
echo "Test: Dryrun flag"
|
||||
assert_exit "--dryrun accepted" 0 "$SCRIPT" --dryrun --profile "$FAKE_PROFILE" "$FAKE_SOURCE"
|
||||
|
||||
# Test 9: Skips dirs without SKILL.md
|
||||
echo "Test: Skips non-skill directories"
|
||||
output="$("$SCRIPT" --profile "$FAKE_PROFILE" "$FAKE_SOURCE" 2>&1)"
|
||||
if echo "$output" | grep -q "not-a-skill"; then
|
||||
echo -e " ${RED}FAIL${NC} should not list not-a-skill"
|
||||
fail=$((fail + 1))
|
||||
else
|
||||
echo -e " ${GREEN}PASS${NC} correctly skips dir without SKILL.md"
|
||||
pass=$((pass + 1))
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Results: $pass passed, $fail failed"
|
||||
[[ $fail -eq 0 ]]
|
||||
Reference in New Issue
Block a user