Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
.ralph
tasks

# Audit output directories (UTC timestamp format)
vibe-code-audit/[0-9]*T[0-9]*Z/
5 changes: 5 additions & 0 deletions install.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
#!/bin/sh
set -eu

# NOTE: This is a standalone POSIX sh installer that does NOT source _lib.sh.
# It intentionally defines its own output helpers (info, dim, ok, warn, die)
# for colored terminal output. Changes to logging in _lib.sh must be
# manually reconciled here if the installer's output contract changes.

SKILL_NAME="vibe-code-audit"
REPO_OWNER="${VIBE_CODE_AUDIT_REPO_OWNER:-codesoda}"
REPO_NAME="${VIBE_CODE_AUDIT_REPO_NAME:-vibe-code-audit}"
Expand Down
153 changes: 153 additions & 0 deletions tests/_test_lib.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
# shellcheck shell=bash
# _test_lib.sh — shared test harness for vibe-code-audit test suite
#
# Sourced by all test files. Provides:
# - pass()/fail() counter functions
# - assert_eq() helper
# - setup_tmproot() / cleanup_tmproot() for temp dir lifecycle
# - print_results() for uniform summary output
# - build_filtered_path() for hiding commands during testing
# - assert_no_crash_diagnostics() for crash pattern detection
# - Automatic cleanup trap registration
#
# The sourcing script MUST:
# 1. Set `set -euo pipefail` before sourcing.
# 2. Optionally set TEST_NAME before sourcing (used in output prefix).
#
# Optional modes:
# FILE_COUNTERS=1 — use file-based pass/fail counters (safe in subshells).
# Requires setup_tmproot() to be called first.

TEST_NAME="${TEST_NAME:-$(basename "$0" .sh)}"
# shellcheck disable=SC2034 # ROOT_DIR is used by sourcing scripts
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"

PASS=0
FAIL=0

# File-based counter support (for subshell-safe counting)
FILE_COUNTERS="${FILE_COUNTERS:-0}"
_PASS_FILE=""
_FAIL_FILE=""

_init_file_counters() {
if [ "$FILE_COUNTERS" -eq 1 ] && [ -n "${TMPROOT:-}" ]; then
_PASS_FILE="$TMPROOT/.pass_count"
_FAIL_FILE="$TMPROOT/.fail_count"
printf '0\n' > "$_PASS_FILE"
printf '0\n' > "$_FAIL_FILE"
fi
}

pass() {
if [ "$FILE_COUNTERS" -eq 1 ] && [ -n "$_PASS_FILE" ]; then
local c
c="$(cat "$_PASS_FILE")"
printf '%d\n' "$((c + 1))" > "$_PASS_FILE"
else
PASS=$((PASS + 1))
fi
printf 'PASS: %s\n' "$*"
}

fail() {
if [ "$FILE_COUNTERS" -eq 1 ] && [ -n "$_FAIL_FILE" ]; then
local c
c="$(cat "$_FAIL_FILE")"
printf '%d\n' "$((c + 1))" > "$_FAIL_FILE"
else
FAIL=$((FAIL + 1))
fi
printf 'FAIL: %s\n' "$*" >&2
}

# assert_eq LABEL EXPECTED ACTUAL
assert_eq() {
local label="$1" expected="$2" actual="$3"
if [ "$expected" = "$actual" ]; then
pass "$label"
else
fail "$label"
printf ' expected: %s\n' "$expected" >&2
printf ' actual: %s\n' "$actual" >&2
fi
}

# ---------------------------------------------------------------------------
# Temp directory lifecycle
# ---------------------------------------------------------------------------

TMPROOT=""

setup_tmproot() {
TMPROOT="$(mktemp -d "${TMPDIR:-/tmp}/vca-test-${TEST_NAME}.XXXXXX")"
if [ "$FILE_COUNTERS" -eq 1 ]; then
_init_file_counters
fi
}

cleanup_tmproot() {
if [ -n "$TMPROOT" ] && [ -d "$TMPROOT" ]; then
rm -rf "$TMPROOT"
fi
}

trap cleanup_tmproot EXIT INT TERM

# ---------------------------------------------------------------------------
# PATH manipulation helpers
# ---------------------------------------------------------------------------

# build_filtered_path COMMAND
# Builds a colon-separated PATH string with directories containing COMMAND
# removed. Result is stored in FILTERED_PATH.
build_filtered_path() {
local cmd_to_hide="$1"
FILTERED_PATH=""
local segment
IFS=':'
for segment in $PATH; do
if [ -z "$segment" ]; then
continue
fi
if [ -x "$segment/$cmd_to_hide" ]; then
continue
fi
if [ -n "$FILTERED_PATH" ]; then
FILTERED_PATH="$FILTERED_PATH:$segment"
else
FILTERED_PATH="$segment"
fi
done
unset IFS
}

# ---------------------------------------------------------------------------
# Assertion helpers
# ---------------------------------------------------------------------------

# assert_no_crash_diagnostics CONTENT
# Fails if CONTENT contains shell crash patterns (unbound variable, syntax
# error, segfault, core dump, panic).
assert_no_crash_diagnostics() {
local content="$1"
if echo "$content" | grep -Eiq 'unbound variable|syntax error|segmentation fault|core dumped|panic'; then
fail "stderr contains crash diagnostic: $(echo "$content" | grep -Ei 'unbound variable|syntax error|segmentation fault|core dumped|panic' | head -1)"
else
pass "no crash diagnostics in stderr"
fi
}

# ---------------------------------------------------------------------------
# Results summary
# ---------------------------------------------------------------------------

print_results() {
# Sync from file counters if active
if [ "$FILE_COUNTERS" -eq 1 ] && [ -n "$_PASS_FILE" ] && [ -f "$_PASS_FILE" ]; then
PASS="$(cat "$_PASS_FILE")"
FAIL="$(cat "$_FAIL_FILE")"
fi
printf '\n--- Results: %d passed, %d failed ---\n' "$PASS" "$FAIL"
[ "$FAIL" -eq 0 ]
}
48 changes: 10 additions & 38 deletions tests/atomic_index_midrun_failure_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,37 +8,14 @@ set -euo pipefail
# - Any prior audit_index/ is untouched
# - After a successful run, audit_index/ has fresh content and audit_index.tmp/ is absent

ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
RUN_INDEX_SCRIPT="$ROOT_DIR/vibe-code-audit/scripts/run_index.sh"

TEST_TMPDIR=""
cleanup() {
if [ -n "$TEST_TMPDIR" ] && [ -d "$TEST_TMPDIR" ]; then
rm -rf "$TEST_TMPDIR"
fi
}
trap cleanup EXIT INT TERM

TEST_TMPDIR="$(mktemp -d "${TMPDIR:-/tmp}/vca-atomic-idx-test.XXXXXX")"
TEST_NAME="atomic_index_midrun"
FILE_COUNTERS=1
# shellcheck source=_test_lib.sh
. "$(dirname "$0")/_test_lib.sh"

PASS_FILE="$TEST_TMPDIR/.pass_count"
FAIL_FILE="$TEST_TMPDIR/.fail_count"
printf '0\n' > "$PASS_FILE"
printf '0\n' > "$FAIL_FILE"
RUN_INDEX_SCRIPT="$ROOT_DIR/vibe-code-audit/scripts/run_index.sh"

pass() {
local c
c="$(cat "$PASS_FILE")"
printf '%d\n' "$((c + 1))" > "$PASS_FILE"
printf '[atomic_index_midrun] PASS: %s\n' "$1"
}

fail() {
local c
c="$(cat "$FAIL_FILE")"
printf '%d\n' "$((c + 1))" > "$FAIL_FILE"
printf '[atomic_index_midrun] FAIL: %s\n' "$1" >&2
}
setup_tmproot

# --- Helper: create mock binaries ---

Expand Down Expand Up @@ -178,7 +155,7 @@ EOF
(
set -euo pipefail

work_dir="$TEST_TMPDIR/case-failure"
work_dir="$TMPROOT/case-failure"
repo_dir="$work_dir/repo"
output_dir="$work_dir/output"
bin_dir="$work_dir/bin"
Expand Down Expand Up @@ -245,7 +222,7 @@ EOF
(
set -euo pipefail

work_dir="$TEST_TMPDIR/case-success"
work_dir="$TMPROOT/case-success"
repo_dir="$work_dir/repo"
output_dir="$work_dir/output"
bin_dir="$work_dir/bin"
Expand Down Expand Up @@ -318,7 +295,7 @@ EOF
(
set -euo pipefail

work_dir="$TEST_TMPDIR/case-success-replace"
work_dir="$TMPROOT/case-success-replace"
repo_dir="$work_dir/repo"
output_dir="$work_dir/output"
bin_dir="$work_dir/bin"
Expand Down Expand Up @@ -373,9 +350,4 @@ EOF
# Summary
# ============================================================

PASS="$(cat "$PASS_FILE")"
FAIL="$(cat "$FAIL_FILE")"
printf '\n[atomic_index_midrun] Results: %d passed, %d failed\n' "$PASS" "$FAIL"
if [ "$FAIL" -gt 0 ]; then
exit 1
fi
print_results
Loading