#!/usr/bin/env bash set -euo pipefail SCRIPTS_DIR="$(cd "$(dirname "$0")/../scripts" && pwd)" PASS=0; FAIL=0 # Use += to avoid ((var++)) returning 0 exit code when var was 0 under set -e # ── helpers ───────────────────────────────────────────────────────────────── tmpdir() { mktemp -d; } assert_contains() { local label="$1" expected="$2" actual="$3" if echo "$actual" | grep -qF "$expected"; then echo " PASS: $label" PASS=$((PASS+1)) else echo " FAIL: $label" echo " expected to contain: $expected" echo " got: $(echo "$actual" | head -5)" FAIL=$((FAIL+1)) fi } assert_not_contains() { local label="$1" unexpected="$2" actual="$3" if echo "$actual" | grep -qF "$unexpected"; then echo " FAIL: $label" echo " expected NOT to contain: $unexpected" FAIL=$((FAIL+1)) else echo " PASS: $label" PASS=$((PASS+1)) fi } assert_exit() { local label="$1" expected="$2" actual="$3" if [[ "$actual" -eq "$expected" ]]; then echo " PASS: $label" PASS=$((PASS+1)) else echo " FAIL: $label" echo " expected exit $expected, got $actual" FAIL=$((FAIL+1)) fi } assert_file_exists() { local label="$1" path="$2" if [[ -f "$path" ]]; then echo " PASS: $label" PASS=$((PASS+1)) else echo " FAIL: $label" echo " file not found: $path" FAIL=$((FAIL+1)) fi } assert_file_absent() { local label="$1" path="$2" if [[ ! -e "$path" ]]; then echo " PASS: $label" PASS=$((PASS+1)) else echo " FAIL: $label" echo " file should not exist: $path" FAIL=$((FAIL+1)) fi } # ── inventory.sh tests ─────────────────────────────────────────────────────── echo "=== inventory.sh ===" # 1. SKILL.md classified as skill t=$(tmpdir) mkdir -p "$t/skills/my-skill" echo "---" > "$t/skills/my-skill/SKILL.md" out=$("$SCRIPTS_DIR/inventory.sh" "$t") assert_contains "SKILL.md classified as skill" "skill" "$out" rm -rf "$t" # 2. agents/foo.agent.md classified as agent-copilot t=$(tmpdir) mkdir -p "$t/agents" touch "$t/agents/my-agent.agent.md" out=$("$SCRIPTS_DIR/inventory.sh" "$t") assert_contains "agents/*.agent.md classified as agent-copilot" "agent-copilot" "$out" rm -rf "$t" # 3. ../ in file content produces cross-reference warning t=$(tmpdir) mkdir -p "$t/skills/my-skill" printf -- '---\ndescription: test\n---\nSee ../shared/file.md\n' > "$t/skills/my-skill/SKILL.md" out=$("$SCRIPTS_DIR/inventory.sh" "$t") assert_contains "../ cross-reference warning emitted" "Cross-reference" "$out" assert_contains "../ path shown in warning" "../shared/file.md" "$out" rm -rf "$t" # ── gen_manifests.sh tests ─────────────────────────────────────────────────── echo "" echo "=== gen_manifests.sh ===" # 4. Without --write, no files are created t=$(tmpdir) mkdir -p "$t/plugins/my-plugin/skills/hello" echo "---" > "$t/plugins/my-plugin/skills/hello/SKILL.md" "$SCRIPTS_DIR/gen_manifests.sh" "$t" --marketplace-name my-marketplace >/dev/null assert_file_absent "dry run: .claude-plugin/marketplace.json not written" "$t/.claude-plugin/marketplace.json" assert_file_absent "dry run: plugin.json not written" "$t/plugins/my-plugin/plugin.json" rm -rf "$t" # 5. With --write, creates plugin.json in both locations t=$(tmpdir) mkdir -p "$t/plugins/my-plugin/skills/hello" echo "---" > "$t/plugins/my-plugin/skills/hello/SKILL.md" "$SCRIPTS_DIR/gen_manifests.sh" "$t" --marketplace-name my-marketplace --write >/dev/null assert_file_exists "--write: plugin root plugin.json created" "$t/plugins/my-plugin/plugin.json" assert_file_exists "--write: .claude-plugin/plugin.json created" "$t/plugins/my-plugin/.claude-plugin/plugin.json" rm -rf "$t" # 6. Reserved name exits 1 t=$(tmpdir) mkdir -p "$t/plugins/my-plugin" set +e out=$("$SCRIPTS_DIR/gen_manifests.sh" "$t" --marketplace-name claude-plugins-official 2>&1) code=$? set -e assert_exit "reserved name: exit 1" 1 "$code" assert_contains "reserved name: error message" "reserved" "$out" rm -rf "$t" # ── validate.sh tests ──────────────────────────────────────────────────────── echo "" echo "=== validate.sh ===" # 7. Invalid JSON exits 1 t=$(tmpdir) mkdir -p "$t/.claude-plugin" echo "not json" > "$t/.claude-plugin/marketplace.json" set +e out=$("$SCRIPTS_DIR/validate.sh" "$t" 2>&1) code=$? set -e assert_exit "invalid JSON: exit 1" 1 "$code" assert_contains "invalid JSON: error message" "ERROR" "$out" rm -rf "$t" # 8. Reserved marketplace name exits 1 t=$(tmpdir) mkdir -p "$t/.claude-plugin" printf '{"name":"claude-plugins-official","plugins":[]}\n' > "$t/.claude-plugin/marketplace.json" set +e out=$("$SCRIPTS_DIR/validate.sh" "$t" 2>&1) code=$? set -e assert_exit "reserved marketplace name: exit 1" 1 "$code" assert_contains "reserved marketplace name: error message" "reserved" "$out" rm -rf "$t" # 9. ../ in plugin file exits 1 t=$(tmpdir) mkdir -p "$t/.claude-plugin" "$t/plugins/my-plugin/skills/hello" printf '{"name":"my-marketplace","plugins":[{"name":"my-plugin","source":"./plugins/my-plugin"}]}\n' \ > "$t/.claude-plugin/marketplace.json" printf -- '---\ndescription: test\n---\nSee ../shared.md\n' \ > "$t/plugins/my-plugin/skills/hello/SKILL.md" set +e out=$("$SCRIPTS_DIR/validate.sh" "$t" 2>&1) code=$? set -e assert_exit "..// in plugin: exit 1" 1 "$code" assert_contains "..// in plugin: error message" "../" "$out" rm -rf "$t" # 10. No marketplace.json warns but exits 0 t=$(tmpdir) set +e out=$("$SCRIPTS_DIR/validate.sh" "$t" 2>&1) code=$? set -e assert_exit "no marketplace.json: exit 0" 0 "$code" assert_contains "no marketplace.json: warning emitted" "WARN" "$out" rm -rf "$t" # ── summary ────────────────────────────────────────────────────────────────── echo "" echo "Results: $PASS passed, $FAIL failed" [[ $FAIL -eq 0 ]]