From 6a94ccc270a45c63141635c16aff96a7252e0637 Mon Sep 17 00:00:00 2001 From: Defame1297 Date: Mon, 22 Jun 2026 19:47:31 +0000 Subject: [PATCH] test(kyberforge): add bats test suites for validate.sh and new-skill.sh MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add bats-core, bats-support, bats-assert as git submodules under tests/ - Add tests/run-bats.sh — discovers and runs all *.bats files in the repo - 17 tests for skill-audit/scripts/validate.sh: valid skill, --help, optional dirs, backtick-quoted placeholder exclusion, boundary checks (500 lines / 1024 chars), and failure cases (missing SKILL.md, name mismatch, placeholders, non-executable scripts, interactive prompts, invalid name formats, no args) - 16 tests for skill-write/scripts/new-skill.sh: scaffold structure, name substitution, numbers in name, /skill-audit reference in next-steps, and failure cases (uppercase, consecutive/leading/trailing hyphens, missing dest, existing target, no args) Co-Authored-By: Claude Sonnet 4.6 --- .gitmodules | 9 + .../skill-audit/scripts/tests/validate.bats | 198 ++++++++++++++++++ .../skill-write/scripts/tests/new-skill.bats | 111 ++++++++++ tests/bats | 1 + tests/run-bats.sh | 27 +++ tests/test_helper/bats-assert | 1 + tests/test_helper/bats-support | 1 + 7 files changed, 348 insertions(+) create mode 100644 .gitmodules create mode 100644 plugins/kyberforge/skills/skill-audit/scripts/tests/validate.bats create mode 100644 plugins/kyberforge/skills/skill-write/scripts/tests/new-skill.bats create mode 160000 tests/bats create mode 100755 tests/run-bats.sh create mode 160000 tests/test_helper/bats-assert create mode 160000 tests/test_helper/bats-support diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..fe9d335 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,9 @@ +[submodule "tests/bats"] + path = tests/bats + url = https://github.com/bats-core/bats-core.git +[submodule "tests/test_helper/bats-support"] + path = tests/test_helper/bats-support + url = https://github.com/bats-core/bats-support.git +[submodule "tests/test_helper/bats-assert"] + path = tests/test_helper/bats-assert + url = https://github.com/bats-core/bats-assert.git diff --git a/plugins/kyberforge/skills/skill-audit/scripts/tests/validate.bats b/plugins/kyberforge/skills/skill-audit/scripts/tests/validate.bats new file mode 100644 index 0000000..ceb1645 --- /dev/null +++ b/plugins/kyberforge/skills/skill-audit/scripts/tests/validate.bats @@ -0,0 +1,198 @@ +#!/usr/bin/env bats + +setup() { + REPO_ROOT="$(cd "$BATS_TEST_DIRNAME/../../../../../../" && pwd)" + load "$REPO_ROOT/tests/test_helper/bats-support/load" + load "$REPO_ROOT/tests/test_helper/bats-assert/load" + + SCRIPT="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)/validate.sh" + TMPDIR="$(mktemp -d)" + + # Helper: create a minimal valid skill directory + make_valid_skill() { + local dir="$1" + local name + name="$(basename "$dir")" + mkdir -p "$dir/scripts" + cat > "$dir/SKILL.md" <> "$skill/SKILL.md" + run bash "$SCRIPT" "$skill" + assert_success +} + +@test "passes at exactly 1024-char description" { + local skill="$TMPDIR/my-skill" + local name + name="$(basename "$skill")" + mkdir -p "$skill" + local desc + desc="$(python3 -c "print('x' * 1024)")" + cat > "$skill/SKILL.md" <> "$skill/SKILL.md" + run bash "$SCRIPT" "$skill" + assert_success +} + +# --------------------------------------------------------------------------- +# Failing cases +# --------------------------------------------------------------------------- + +@test "fails when SKILL.md is missing" { + local skill="$TMPDIR/my-skill" + mkdir -p "$skill" + run bash "$SCRIPT" "$skill" + assert_failure +} + +@test "fails when name does not match directory" { + local skill="$TMPDIR/my-skill" + make_valid_skill "$skill" + sed -i 's/^name: .*/name: wrong-name/' "$skill/SKILL.md" + run bash "$SCRIPT" "$skill" + assert_failure +} + +@test "fails when description exceeds 1024 chars" { + local skill="$TMPDIR/my-skill" + local name + name="$(basename "$skill")" + mkdir -p "$skill" + local desc + desc="$(python3 -c "print('x' * 1025)")" + cat > "$skill/SKILL.md" <> "$skill/SKILL.md" + run bash "$SCRIPT" "$skill" + assert_failure +} + +@test "fails when body contains unfilled FILL IN: placeholder" { + local skill="$TMPDIR/my-skill" + make_valid_skill "$skill" + echo "FILL IN: replace this" >> "$skill/SKILL.md" + run bash "$SCRIPT" "$skill" + assert_failure +} + +@test "fails when a script is not executable" { + local skill="$TMPDIR/my-skill" + make_valid_skill "$skill" + echo "#!/usr/bin/env bash" > "$skill/scripts/helper.sh" + chmod -x "$skill/scripts/helper.sh" + run bash "$SCRIPT" "$skill" + assert_failure +} + +@test "fails when a script has an interactive prompt" { + local skill="$TMPDIR/my-skill" + make_valid_skill "$skill" + printf '#!/usr/bin/env bash\nread -p "Enter value: " VAL\n' > "$skill/scripts/helper.sh" + chmod +x "$skill/scripts/helper.sh" + run bash "$SCRIPT" "$skill" + assert_failure +} + +@test "fails when name contains consecutive hyphens" { + local skill="$TMPDIR/my--skill" + make_valid_skill "$skill" + run bash "$SCRIPT" "$skill" + assert_failure +} + +@test "fails when name has a leading hyphen" { + local skill="$TMPDIR/-my-skill" + make_valid_skill "$skill" + run bash "$SCRIPT" "$skill" + assert_failure +} + +@test "fails when no frontmatter block is present" { + local skill="$TMPDIR/my-skill" + mkdir -p "$skill" + echo "Just some content with no frontmatter." > "$skill/SKILL.md" + run bash "$SCRIPT" "$skill" + assert_failure +} + +@test "fails when no arguments are given" { + run bash "$SCRIPT" + assert_failure +} diff --git a/plugins/kyberforge/skills/skill-write/scripts/tests/new-skill.bats b/plugins/kyberforge/skills/skill-write/scripts/tests/new-skill.bats new file mode 100644 index 0000000..65b51f6 --- /dev/null +++ b/plugins/kyberforge/skills/skill-write/scripts/tests/new-skill.bats @@ -0,0 +1,111 @@ +#!/usr/bin/env bats + +setup() { + REPO_ROOT="$(cd "$BATS_TEST_DIRNAME/../../../../../../" && pwd)" + load "$REPO_ROOT/tests/test_helper/bats-support/load" + load "$REPO_ROOT/tests/test_helper/bats-assert/load" + + SCRIPT="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)/new-skill.sh" + DEST="$(mktemp -d)" +} + +teardown() { + rm -rf "$DEST" +} + +# --------------------------------------------------------------------------- +# Passing cases +# --------------------------------------------------------------------------- + +@test "--help exits 0" { + run bash "$SCRIPT" --help + assert_success + assert_output --partial "Usage:" +} + +@test "creates scaffold directory at destination" { + run bash "$SCRIPT" my-tool "$DEST" + assert_success + assert [ -d "$DEST/my-tool" ] +} + +@test "scaffold contains SKILL.md" { + bash "$SCRIPT" my-tool "$DEST" + assert [ -f "$DEST/my-tool/SKILL.md" ] +} + +@test "scaffold contains README.md" { + bash "$SCRIPT" my-tool "$DEST" + assert [ -f "$DEST/my-tool/README.md" ] +} + +@test "scaffold contains scripts/, references/, assets/ directories" { + bash "$SCRIPT" my-tool "$DEST" + assert [ -d "$DEST/my-tool/scripts" ] + assert [ -d "$DEST/my-tool/references" ] + assert [ -d "$DEST/my-tool/assets" ] +} + +@test "substitutes skill name in SKILL.md" { + bash "$SCRIPT" my-tool "$DEST" + run grep "my-tool" "$DEST/my-tool/SKILL.md" + assert_success +} + +@test "substitutes skill name in README.md" { + bash "$SCRIPT" my-tool "$DEST" + run grep "my-tool" "$DEST/my-tool/README.md" + assert_success +} + +@test "skill name with numbers is valid" { + run bash "$SCRIPT" my-tool-2 "$DEST" + assert_success + assert [ -d "$DEST/my-tool-2" ] +} + +@test "next-steps output references /skill-audit not validate.sh" { + run bash "$SCRIPT" my-tool "$DEST" + assert_output --partial "/skill-audit" + refute_output --partial "validate.sh" +} + +# --------------------------------------------------------------------------- +# Failing cases +# --------------------------------------------------------------------------- + +@test "fails when no arguments given" { + run bash "$SCRIPT" + assert_failure +} + +@test "fails when skill name contains uppercase" { + run bash "$SCRIPT" MyTool "$DEST" + assert_failure +} + +@test "fails when skill name has consecutive hyphens" { + run bash "$SCRIPT" my--tool "$DEST" + assert_failure +} + +@test "fails when skill name has a leading hyphen" { + run bash "$SCRIPT" -my-tool "$DEST" + assert_failure +} + +@test "fails when skill name has a trailing hyphen" { + run bash "$SCRIPT" my-tool- "$DEST" + assert_failure +} + +@test "fails when destination directory does not exist" { + run bash "$SCRIPT" my-tool "/nonexistent/path" + assert_failure +} + +@test "fails when target already exists" { + mkdir -p "$DEST/my-tool" + run bash "$SCRIPT" my-tool "$DEST" + assert_failure +} diff --git a/tests/bats b/tests/bats new file mode 160000 index 0000000..5a7db7a --- /dev/null +++ b/tests/bats @@ -0,0 +1 @@ +Subproject commit 5a7db7a98951d9d89b3b5e7800037e655a93345f diff --git a/tests/run-bats.sh b/tests/run-bats.sh new file mode 100755 index 0000000..2f80d1e --- /dev/null +++ b/tests/run-bats.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# Run all bats test files in the repo. +# Usage: bash tests/run-bats.sh +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +BATS="$REPO_ROOT/tests/bats/bin/bats" + +if [[ ! -x "$BATS" ]]; then + echo "Error: bats not found at $BATS" >&2 + echo " Run: git submodule update --init --recursive" >&2 + exit 1 +fi + +mapfile -t TEST_FILES < <( + find "$REPO_ROOT" -name "*.bats" \ + -not -path "*/tests/bats/*" \ + -not -path "*/test_helper/*" \ + | sort +) + +if [[ ${#TEST_FILES[@]} -eq 0 ]]; then + echo "No .bats test files found." >&2 + exit 0 +fi + +"$BATS" "${TEST_FILES[@]}" diff --git a/tests/test_helper/bats-assert b/tests/test_helper/bats-assert new file mode 160000 index 0000000..697471b --- /dev/null +++ b/tests/test_helper/bats-assert @@ -0,0 +1 @@ +Subproject commit 697471b7a89d3ab38571f38c6c7c4b460d1f5e35 diff --git a/tests/test_helper/bats-support b/tests/test_helper/bats-support new file mode 160000 index 0000000..0954abb --- /dev/null +++ b/tests/test_helper/bats-support @@ -0,0 +1 @@ +Subproject commit 0954abb9925cad550424cebca2b99255d4eabe96