All checks were successful
PR Checklist / pr-checklist (pull_request) Successful in 1m19s
196 lines
4.6 KiB
Bash
Executable File
196 lines
4.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# test_harness.sh — Common CLI safety/test harness for the scripts/ suite
|
|
# Usage: ./scripts/test_harness.sh [--verbose] [--ci] [directory]
|
|
#
|
|
# Discovers .sh, .py, and .yaml files in the target directory and validates them:
|
|
# - .sh : runs shellcheck (or SKIPS if unavailable)
|
|
# - .py : runs python3 -m py_compile
|
|
# - .yaml: validates with python3 yaml.safe_load
|
|
#
|
|
# Exit codes: 0 = all pass, 1 = any fail
|
|
|
|
set -euo pipefail
|
|
|
|
# --- Defaults ---
|
|
VERBOSE=0
|
|
CI_MODE=0
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
TARGET_DIR="${SCRIPT_DIR}"
|
|
|
|
# --- Colors (disabled in CI) ---
|
|
RED=""
|
|
GREEN=""
|
|
YELLOW=""
|
|
CYAN=""
|
|
RESET=""
|
|
if [[ -t 1 && "${CI:-}" != "true" ]]; then
|
|
RED=$'\033[0;31m'
|
|
GREEN=$'\033[0;32m'
|
|
YELLOW=$'\033[0;33m'
|
|
CYAN=$'\033[0;36m'
|
|
RESET=$'\033[0m'
|
|
fi
|
|
|
|
# --- Argument parsing ---
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--verbose|-v) VERBOSE=1; shift ;;
|
|
--ci) CI_MODE=1; shift ;;
|
|
-*) echo "Unknown option: $1" >&2; exit 2 ;;
|
|
*) TARGET_DIR="$1"; shift ;;
|
|
esac
|
|
done
|
|
|
|
# --- Counters ---
|
|
PASS=0
|
|
FAIL=0
|
|
SKIP=0
|
|
TOTAL=0
|
|
|
|
# --- Helpers ---
|
|
log_verbose() {
|
|
if [[ "${VERBOSE}" -eq 1 ]]; then
|
|
echo " ${CYAN}[DEBUG]${RESET} $*"
|
|
fi
|
|
}
|
|
|
|
record_pass() {
|
|
((PASS++))
|
|
((TOTAL++))
|
|
echo "${GREEN}PASS${RESET} $1"
|
|
}
|
|
|
|
record_fail() {
|
|
((FAIL++))
|
|
((TOTAL++))
|
|
echo "${RED}FAIL${RESET} $1"
|
|
if [[ -n "${2:-}" ]]; then
|
|
echo " ${2}"
|
|
fi
|
|
}
|
|
|
|
record_skip() {
|
|
((SKIP++))
|
|
((TOTAL++))
|
|
echo "${YELLOW}SKIP${RESET} $1 — $2"
|
|
}
|
|
|
|
# --- Checkers ---
|
|
check_shell_file() {
|
|
local file="$1"
|
|
local rel="${file#${TARGET_DIR}/}"
|
|
if command -v shellcheck &>/dev/null; then
|
|
log_verbose "Running shellcheck on ${rel}"
|
|
local output
|
|
if output=$(shellcheck -x -S warning "${file}" 2>&1); then
|
|
record_pass "${rel}"
|
|
else
|
|
record_fail "${rel}" "${output}"
|
|
fi
|
|
else
|
|
record_skip "${rel}" "shellcheck not installed"
|
|
fi
|
|
}
|
|
|
|
check_python_file() {
|
|
local file="$1"
|
|
local rel="${file#${TARGET_DIR}/}"
|
|
log_verbose "Running py_compile on ${rel}"
|
|
local output
|
|
if output=$(python3 -m py_compile "${file}" 2>&1); then
|
|
record_pass "${rel}"
|
|
else
|
|
record_fail "${rel}" "${output}"
|
|
fi
|
|
}
|
|
|
|
check_yaml_file() {
|
|
local file="$1"
|
|
local rel="${file#${TARGET_DIR}/}"
|
|
log_verbose "Validating YAML: ${rel}"
|
|
local output
|
|
if output=$(python3 -c "import yaml; yaml.safe_load(open('${file}'))" 2>&1); then
|
|
record_pass "${rel}"
|
|
else
|
|
record_fail "${rel}" "${output}"
|
|
fi
|
|
}
|
|
|
|
# --- Main ---
|
|
echo ""
|
|
echo "=== scripts/ test harness ==="
|
|
echo "Target: ${TARGET_DIR}"
|
|
echo ""
|
|
|
|
if [[ ! -d "${TARGET_DIR}" ]]; then
|
|
echo "Error: target directory '${TARGET_DIR}' not found" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Check python3 availability
|
|
if ! command -v python3 &>/dev/null; then
|
|
echo "${RED}Error: python3 is required but not found${RESET}" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Check PyYAML availability
|
|
if ! python3 -c "import yaml" 2>/dev/null; then
|
|
echo "${YELLOW}Warning: PyYAML not installed — YAML checks will be skipped${RESET}" >&2
|
|
YAML_AVAILABLE=0
|
|
else
|
|
YAML_AVAILABLE=1
|
|
fi
|
|
|
|
# Discover and check .sh files
|
|
sh_files=()
|
|
while IFS= read -r -d '' f; do
|
|
sh_files+=("$f")
|
|
done < <(find "${TARGET_DIR}" -maxdepth 1 -name "*.sh" ! -name "test_harness.sh" ! -name "test_runner.sh" -print0 | sort -z)
|
|
|
|
for f in "${sh_files[@]:-}"; do
|
|
[[ -n "$f" ]] && check_shell_file "$f"
|
|
done
|
|
|
|
# Discover and check .py files
|
|
py_files=()
|
|
while IFS= read -r -d '' f; do
|
|
py_files+=("$f")
|
|
done < <(find "${TARGET_DIR}" -maxdepth 1 -name "*.py" -print0 | sort -z)
|
|
|
|
for f in "${py_files[@]:-}"; do
|
|
[[ -n "$f" ]] && check_python_file "$f"
|
|
done
|
|
|
|
# Discover and check .yaml files in target dir
|
|
yaml_files=()
|
|
while IFS= read -r -d '' f; do
|
|
yaml_files+=("$f")
|
|
done < <(find "${TARGET_DIR}" -maxdepth 1 -name "*.yaml" -print0 | sort -z)
|
|
|
|
if [[ "${YAML_AVAILABLE}" -eq 1 ]]; then
|
|
for f in "${yaml_files[@]:-}"; do
|
|
[[ -n "$f" ]] && check_yaml_file "$f"
|
|
done
|
|
else
|
|
for f in "${yaml_files[@]:-}"; do
|
|
[[ -n "$f" ]] && record_skip "${f#${TARGET_DIR}/}" "PyYAML not installed"
|
|
done
|
|
fi
|
|
|
|
# --- Summary ---
|
|
echo ""
|
|
echo "=== Results ==="
|
|
echo " ${GREEN}PASS${RESET}: ${PASS}"
|
|
echo " ${RED}FAIL${RESET}: ${FAIL}"
|
|
echo " ${YELLOW}SKIP${RESET}: ${SKIP}"
|
|
echo " Total: ${TOTAL}"
|
|
echo ""
|
|
|
|
if [[ "${FAIL}" -gt 0 ]]; then
|
|
echo "${RED}FAILED${RESET} — ${FAIL} file(s) did not pass validation."
|
|
exit 1
|
|
else
|
|
echo "${GREEN}ALL CLEAR${RESET} — all checked files passed."
|
|
exit 0
|
|
fi
|