diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..0798bdd3 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,27 @@ +name: Tests and Checks + +on: + pull_request: + branches: + - main + types: + - opened + - synchronize + - reopened + - ready_for_review + +jobs: + test: + name: Run Bats Test Suite + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v6 + + - name: Install Bats + uses: mig4/setup-bats@v1 + with: + bats-version: 1.8.2 + + - name: Run Bats Tests + run: bats tests diff --git a/tests/01-setup.bats b/tests/01-setup.bats new file mode 100644 index 00000000..70169d19 --- /dev/null +++ b/tests/01-setup.bats @@ -0,0 +1,53 @@ +#!/usr/bin/env bats + +load "$BATS_TEST_DIRNAME/helpers.bash" + +setup() { + setup_test_tmp_dir + export RUNNER_TEMP="$TEST_TMP_DIR/runner-temp" + export GITHUB_SHA="abcd1234" + export GITHUB_RUN_ID="99" + export GITHUB_RUN_ATTEMPT="3" + export GITHUB_ACTION_PATH="$BATS_TEST_DIRNAME/.." + export TEST_WORK_DIR="$TEST_TMP_DIR/workspace" + export GITHUB_ENV="$TEST_TMP_DIR/github.env" + mkdir -p "$RUNNER_TEMP" "$TEST_WORK_DIR" + : > "$GITHUB_ENV" +} + +teardown() { + teardown_test_tmp_dir +} + +@test "setup exports variables and falls back to engine php version" { + run bash -c "cd \"$TEST_WORK_DIR\" && bash \"$BATS_TEST_DIRNAME/../bin/setup.sh\" \"clean/phpdoc-md\"" + [ "$status" -eq 0 ] + + run grep -F "NEEDED_PHP_VERSION=8.1" "$GITHUB_ENV" + [ "$status" -eq 0 ] + + NEW_WIKI_PATH=$(grep '^NEW_WIKI_CHECKOUT_PATH=' "$GITHUB_ENV" | cut -d'=' -f2-) + [ -d "$NEW_WIKI_PATH" ] +} + +@test "setup uses composer.json php constraint when present" { + cat > "$TEST_WORK_DIR/composer.json" <<'EOF' +{ + "require": { + "php": "^8.2" + } +} +EOF + + run bash -c "cd \"$TEST_WORK_DIR\" && bash \"$BATS_TEST_DIRNAME/../bin/setup.sh\" \"clean/phpdoc-md\"" + [ "$status" -eq 0 ] + + run grep -F "NEEDED_PHP_VERSION=8.2" "$GITHUB_ENV" + [ "$status" -eq 0 ] +} + +@test "setup fails on unknown engine" { + run bash -c "cd \"$TEST_WORK_DIR\" && bash \"$BATS_TEST_DIRNAME/../bin/setup.sh\" \"unknown/engine\"" + [ "$status" -eq 1 ] + [[ "$output" == *"ERROR: unknown engine"* ]] +} diff --git a/tests/02-rename-index.bats b/tests/02-rename-index.bats new file mode 100644 index 00000000..695d0aa4 --- /dev/null +++ b/tests/02-rename-index.bats @@ -0,0 +1,31 @@ +#!/usr/bin/env bats + +load "$BATS_TEST_DIRNAME/helpers.bash" + +setup() { + setup_test_tmp_dir + export NEW_WIKI_CHECKOUT_PATH="$TEST_TMP_DIR/new-wiki" + mkdir -p "$NEW_WIKI_CHECKOUT_PATH" +} + +teardown() { + teardown_test_tmp_dir +} + +@test "rename_index renames README.md for clean engine" { + touch "$NEW_WIKI_CHECKOUT_PATH/README.md" + + run bash "$BATS_TEST_DIRNAME/../bin/rename_index.sh" "clean/phpdoc-md" + [ "$status" -eq 0 ] + [ -f "$NEW_WIKI_CHECKOUT_PATH/Home.md" ] + [ ! -f "$NEW_WIKI_CHECKOUT_PATH/README.md" ] +} + +@test "rename_index renames ApiIndex.md for evert engine" { + touch "$NEW_WIKI_CHECKOUT_PATH/ApiIndex.md" + + run bash "$BATS_TEST_DIRNAME/../bin/rename_index.sh" "evert/phpdoc-md" + [ "$status" -eq 0 ] + [ -f "$NEW_WIKI_CHECKOUT_PATH/Home.md" ] + [ ! -f "$NEW_WIKI_CHECKOUT_PATH/ApiIndex.md" ] +} diff --git a/tests/03-get-mapped-branch.bats b/tests/03-get-mapped-branch.bats new file mode 100644 index 00000000..bc969b49 --- /dev/null +++ b/tests/03-get-mapped-branch.bats @@ -0,0 +1,39 @@ +#!/usr/bin/env bats + +load "$BATS_TEST_DIRNAME/helpers.bash" + +setup() { + setup_test_tmp_dir + setup_fake_bin_path + + export TMP_BRANCH_MAP_FILE="$TEST_TMP_DIR/branches.yml" + export GITHUB_REF_NAME="main" + printf "main: wiki-main\n" > "$TMP_BRANCH_MAP_FILE" + + cat > "$FAKE_BIN_DIR/yq" <<'EOF' +#!/usr/bin/env bash +if [ -n "$YQ_OUTPUT_OVERRIDE" ]; then + echo "$YQ_OUTPUT_OVERRIDE" +else + echo "wiki-main" +fi +EOF + chmod +x "$FAKE_BIN_DIR/yq" +} + +teardown() { + teardown_test_tmp_dir +} + +@test "get-mapped-branch returns mapped branch when mapping exists" { + run bash "$BATS_TEST_DIRNAME/../bin/get-mapped-branch.sh" + [ "$status" -eq 0 ] + [ "$output" = "wiki-main" ] +} + +@test "get-mapped-branch falls back to GITHUB_REF_NAME when map is null" { + export YQ_OUTPUT_OVERRIDE="null" + run bash "$BATS_TEST_DIRNAME/../bin/get-mapped-branch.sh" + [ "$status" -eq 0 ] + [ "$output" = "main" ] +} diff --git a/tests/04-configure-git.bats b/tests/04-configure-git.bats new file mode 100644 index 00000000..29086352 --- /dev/null +++ b/tests/04-configure-git.bats @@ -0,0 +1,33 @@ +#!/usr/bin/env bats + +load "$BATS_TEST_DIRNAME/helpers.bash" + +setup() { + setup_test_tmp_dir + export OLD_WIKI_CHECKOUT_PATH="$TEST_TMP_DIR/old-wiki" + mkdir -p "$OLD_WIKI_CHECKOUT_PATH" + git init "$OLD_WIKI_CHECKOUT_PATH" > /dev/null +} + +teardown() { + teardown_test_tmp_dir +} + +@test "configure_git sets git identity and defaults" { + run bash "$BATS_TEST_DIRNAME/../bin/configure_git.sh" "impressbot" "bot@example.com" + [ "$status" -eq 0 ] + + run git -C "$OLD_WIKI_CHECKOUT_PATH" config user.name + [ "$status" -eq 0 ] + [ "$output" = "impressbot" ] + + run git -C "$OLD_WIKI_CHECKOUT_PATH" config user.email + [ "$status" -eq 0 ] + [ "$output" = "bot@example.com" ] +} + +@test "configure_git fails when wiki_github_update_user is empty" { + run bash "$BATS_TEST_DIRNAME/../bin/configure_git.sh" "" "bot@example.com" + [ "$status" -eq 3 ] + [[ "$output" == *"ERROR: 'wiki_github_update_user' not set"* ]] +} diff --git a/tests/05-cloning.bats b/tests/05-cloning.bats new file mode 100644 index 00000000..3c4cc379 --- /dev/null +++ b/tests/05-cloning.bats @@ -0,0 +1,46 @@ +#!/usr/bin/env bats + +load "$BATS_TEST_DIRNAME/helpers.bash" + +setup() { + setup_test_tmp_dir + setup_fake_bin_path + + export GITHUB_REPOSITORY="impresscms-dev/phpdocs-wiki-update-action" + export OLD_WIKI_CHECKOUT_PATH="$TEST_TMP_DIR/old-wiki" + export GIT_CLONE_URL_FILE="$TEST_TMP_DIR/clone-url.txt" + + cat > "$FAKE_BIN_DIR/git" <<'EOF' +#!/usr/bin/env bash +if [ "$1" = "clone" ]; then + echo "$3" > "$GIT_CLONE_URL_FILE" + if [ -z "$SKIP_CLONE_DIR_CREATE" ]; then + mkdir -p "$4" + fi + exit 0 +fi +exit 1 +EOF + chmod +x "$FAKE_BIN_DIR/git" +} + +teardown() { + teardown_test_tmp_dir +} + +@test "cloning uses wiki clone URL and creates checkout folder" { + run bash "$BATS_TEST_DIRNAME/../bin/cloning.sh" "my-token" "my-user" + [ "$status" -eq 0 ] + [ -d "$OLD_WIKI_CHECKOUT_PATH" ] + + run cat "$GIT_CLONE_URL_FILE" + [ "$status" -eq 0 ] + [ "$output" = "https://my-user:my-token@github.com/impresscms-dev/phpdocs-wiki-update-action.wiki.git" ] +} + +@test "cloning fails when wiki directory was not created" { + export SKIP_CLONE_DIR_CREATE="1" + run bash "$BATS_TEST_DIRNAME/../bin/cloning.sh" "my-token" "my-user" + [ "$status" -eq 1 ] + [[ "$output" == *"ERROR: wiki directory not created."* ]] +} diff --git a/tests/06-checkout.bats b/tests/06-checkout.bats new file mode 100644 index 00000000..8949ca4e --- /dev/null +++ b/tests/06-checkout.bats @@ -0,0 +1,68 @@ +#!/usr/bin/env bats + +load "$BATS_TEST_DIRNAME/helpers.bash" + +setup() { + setup_test_tmp_dir + setup_fake_bin_path + + export OLD_WIKI_CHECKOUT_PATH="$TEST_TMP_DIR/old-wiki" + export ACTION_BIN_PATH="$TEST_TMP_DIR/action-bin" + export GIT_CALLS_FILE="$TEST_TMP_DIR/git-calls.log" + mkdir -p "$OLD_WIKI_CHECKOUT_PATH" "$ACTION_BIN_PATH" + : > "$GIT_CALLS_FILE" + + cat > "$ACTION_BIN_PATH/get-mapped-branch.sh" <<'EOF' +#!/usr/bin/env bash +echo "wiki-main" +EOF + chmod +x "$ACTION_BIN_PATH/get-mapped-branch.sh" + + cat > "$FAKE_BIN_DIR/git" <<'EOF' +#!/usr/bin/env bash +echo "$*" >> "$GIT_CALLS_FILE" +case "$1" in + ls-remote) + exit "${GIT_LS_REMOTE_EXIT_CODE:-1}" + ;; + show-ref) + exit "${GIT_SHOW_REF_EXIT_CODE:-1}" + ;; + *) + exit 0 + ;; +esac +EOF + chmod +x "$FAKE_BIN_DIR/git" +} + +teardown() { + teardown_test_tmp_dir +} + +@test "checkout takes existing-branch path when remote or local checks fail" { + export GIT_LS_REMOTE_EXIT_CODE="1" + export GIT_SHOW_REF_EXIT_CODE="1" + + run bash "$BATS_TEST_DIRNAME/../bin/checkout.sh" + [ "$status" -eq 0 ] + [[ "$output" == *"Remote 'wiki-main' found."* ]] + + run grep -F "checkout wiki-main" "$GIT_CALLS_FILE" + [ "$status" -eq 0 ] +} + +@test "checkout creates and pushes branch when both checks succeed" { + export GIT_LS_REMOTE_EXIT_CODE="0" + export GIT_SHOW_REF_EXIT_CODE="0" + + run bash "$BATS_TEST_DIRNAME/../bin/checkout.sh" + [ "$status" -eq 0 ] + [[ "$output" == *"Remote 'wiki-main' not found. Creating."* ]] + + run grep -F "checkout -b wiki-main" "$GIT_CALLS_FILE" + [ "$status" -eq 0 ] + + run grep -F "push --set-upstream origin wiki-main" "$GIT_CALLS_FILE" + [ "$status" -eq 0 ] +} diff --git a/tests/07-commit-and-push.bats b/tests/07-commit-and-push.bats new file mode 100644 index 00000000..4a35675b --- /dev/null +++ b/tests/07-commit-and-push.bats @@ -0,0 +1,54 @@ +#!/usr/bin/env bats + +load "$BATS_TEST_DIRNAME/helpers.bash" + +setup() { + setup_test_tmp_dir + setup_fake_bin_path + + export NEW_WIKI_CHECKOUT_PATH="$TEST_TMP_DIR/new-wiki" + export GIT_CALLS_FILE="$TEST_TMP_DIR/git-calls.log" + mkdir -p "$NEW_WIKI_CHECKOUT_PATH" + : > "$GIT_CALLS_FILE" + + cat > "$FAKE_BIN_DIR/git" <<'EOF' +#!/usr/bin/env bash +echo "$*" >> "$GIT_CALLS_FILE" +case "$1" in + pull) + exit "${GIT_PULL_EXIT_CODE:-0}" + ;; + push) + exit "${GIT_PUSH_EXIT_CODE:-0}" + ;; + *) + exit 0 + ;; +esac +EOF + chmod +x "$FAKE_BIN_DIR/git" +} + +teardown() { + teardown_test_tmp_dir +} + +@test "commit_and_push continues when pull fails and still pushes" { + export GIT_PULL_EXIT_CODE="1" + + run bash "$BATS_TEST_DIRNAME/../bin/commit_and_push.sh" "Update wiki docs" + [ "$status" -eq 0 ] + + run grep -F "pull -s recursive -X ours" "$GIT_CALLS_FILE" + [ "$status" -eq 0 ] + + run grep -F "push" "$GIT_CALLS_FILE" + [ "$status" -eq 0 ] +} + +@test "commit_and_push fails when push fails" { + export GIT_PUSH_EXIT_CODE="1" + + run bash "$BATS_TEST_DIRNAME/../bin/commit_and_push.sh" "Update wiki docs" + [ "$status" -eq 1 ] +} diff --git a/tests/08-clear-tmp-data.bats b/tests/08-clear-tmp-data.bats new file mode 100644 index 00000000..d9e22f35 --- /dev/null +++ b/tests/08-clear-tmp-data.bats @@ -0,0 +1,24 @@ +#!/usr/bin/env bats + +load "$BATS_TEST_DIRNAME/helpers.bash" + +setup() { + setup_test_tmp_dir + export OLD_WIKI_CHECKOUT_PATH="$TEST_TMP_DIR/old-wiki" + export NEW_WIKI_CHECKOUT_PATH="$TEST_TMP_DIR/new-wiki" + export TMP_BRANCH_MAP_FILE="$TEST_TMP_DIR/branches-map.yml" + mkdir -p "$OLD_WIKI_CHECKOUT_PATH" "$NEW_WIKI_CHECKOUT_PATH" + printf "main: master\n" > "$TMP_BRANCH_MAP_FILE" +} + +teardown() { + teardown_test_tmp_dir +} + +@test "clear_tmp_data removes temp files and directories" { + run bash "$BATS_TEST_DIRNAME/../bin/clear_tmp_data.sh" + [ "$status" -eq 0 ] + [ ! -e "$OLD_WIKI_CHECKOUT_PATH" ] + [ ! -e "$NEW_WIKI_CHECKOUT_PATH" ] + [ ! -e "$TMP_BRANCH_MAP_FILE" ] +} diff --git a/tests/09-resolve-php-version.bats b/tests/09-resolve-php-version.bats new file mode 100644 index 00000000..0c682027 --- /dev/null +++ b/tests/09-resolve-php-version.bats @@ -0,0 +1,64 @@ +#!/usr/bin/env bats + +load "$BATS_TEST_DIRNAME/helpers.bash" + +setup() { + setup_test_tmp_dir + export RESOLVER_SCRIPT="$BATS_TEST_DIRNAME/../bin/resolve-php-version.sh" +} + +teardown() { + teardown_test_tmp_dir +} + +@test "resolve-php-version uses engine defaults when composer files are missing" { + run bash -c "cd \"$TEST_TMP_DIR\" && bash \"$RESOLVER_SCRIPT\" \"clean/phpdoc-md\"" + [ "$status" -eq 0 ] + [ "$output" = "8.1" ] + + run bash -c "cd \"$TEST_TMP_DIR\" && bash \"$RESOLVER_SCRIPT\" \"evert/phpdoc-md\"" + [ "$status" -eq 0 ] + [ "$output" = "7.4" ] +} + +@test "resolve-php-version reads composer.json require.php first" { + cat > "$TEST_TMP_DIR/composer.json" <<'EOF' +{ + "require": { + "php": "^8.3 || ^8.4" + } +} +EOF + + run bash -c "cd \"$TEST_TMP_DIR\" && bash \"$RESOLVER_SCRIPT\" \"clean/phpdoc-md\"" + [ "$status" -eq 0 ] + [ "$output" = "8.3" ] +} + +@test "resolve-php-version reads composer.lock when composer.json has no php requirement" { + cat > "$TEST_TMP_DIR/composer.json" <<'EOF' +{ + "require": { + "monolog/monolog": "^3.0" + } +} +EOF + + cat > "$TEST_TMP_DIR/composer.lock" <<'EOF' +{ + "platform": { + "php": ">=8.2" + } +} +EOF + + run bash -c "cd \"$TEST_TMP_DIR\" && bash \"$RESOLVER_SCRIPT\" \"clean/phpdoc-md\"" + [ "$status" -eq 0 ] + [ "$output" = "8.2" ] +} + +@test "resolve-php-version fails for unknown engine" { + run bash -c "cd \"$TEST_TMP_DIR\" && bash \"$RESOLVER_SCRIPT\" \"unknown/engine\"" + [ "$status" -eq 1 ] + [[ "$output" == *"ERROR: unknown engine"* ]] +} diff --git a/tests/helpers.bash b/tests/helpers.bash new file mode 100644 index 00000000..f717f7ac --- /dev/null +++ b/tests/helpers.bash @@ -0,0 +1,13 @@ +setup_test_tmp_dir() { + TEST_TMP_DIR="$(mktemp -d)" +} + +teardown_test_tmp_dir() { + rm -rf "$TEST_TMP_DIR" +} + +setup_fake_bin_path() { + FAKE_BIN_DIR="$TEST_TMP_DIR/fake-bin" + mkdir -p "$FAKE_BIN_DIR" + export PATH="$FAKE_BIN_DIR:$PATH" +}