diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 405fa26..456025e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -93,6 +93,9 @@ jobs: - name: cargo test run: cargo test --locked + - name: Sweep helper regression check + run: bash tests/gate03_sweep_test.sh + # TEST-02 (issue #29). The criterion benches in `benches/scan.rs` cover the # four shapes that matter — pattern-set compile, one large file, 500 small # files, and a pathological line — but nothing ran them, so they could rot diff --git a/scripts/gate03-sweep.sh b/scripts/gate03-sweep.sh index a518167..89e0647 100755 --- a/scripts/gate03-sweep.sh +++ b/scripts/gate03-sweep.sh @@ -95,8 +95,9 @@ redact_home() { } sweep_one() { - out_dir="$1" - dir="$2" + local out_dir="$1" + local dir="$2" + local abs_dir slug report status files_scanned findings if [ ! -d "$dir" ]; then echo "WARNING: skipping '$dir' -- not present on this machine" >&2 @@ -150,7 +151,7 @@ print(sum(len(r['matches']) for r in data)) # Aggregates findings across every per-directory JSON report already written # into by pattern id and severity. build_summary() { - out_dir="$1" + local out_dir="$1" python3 -c " import glob, json, os, sys from collections import Counter @@ -202,6 +203,8 @@ sys.exit(1 if new else 0) } main() { + local out_dir dir + if [ "$#" -eq 0 ]; then usage exit 2 diff --git a/tests/gate03_sweep_test.sh b/tests/gate03_sweep_test.sh new file mode 100644 index 0000000..1fe2811 --- /dev/null +++ b/tests/gate03_sweep_test.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +# Run with: bash tests/gate03_sweep_test.sh +set -euo pipefail + +repo_dir="$(cd "$(dirname "$0")/.." && pwd)" +# Load the real helpers without executing the command-line entry point. +source <(sed '/^main "\$@"$/d' "${1:-$repo_dir/scripts/gate03-sweep.sh}") + +scratch="$(mktemp -d)" +trap 'rm -rf -- "$scratch"' EXIT +mkdir -p "$scratch/input" "$scratch/output" "$scratch/empty" + +# A deterministic scanner substitute exercises the helpers' JSON processing. +fake_scanner() { + printf '[{"file":"probe.md","matches":[{"line":1,"pattern_id":"PI001","severity":"CRITICAL"}]}]\n' + return "$scanner_status" +} +BIN=fake_scanner +require_binary() { :; } + +out_dir=outer_out_dir dir=outer_dir abs_dir=outer_abs_dir slug=outer_slug +report=outer_report status=outer_status files_scanned=outer_files findings=outer_findings +before="$(declare -p out_dir dir abs_dir slug report status files_scanned findings)" + +scanner_status=0 +sweep_one "$scratch/output" "$scratch/input" +build_summary "$scratch/output" +[[ "$(declare -p out_dir dir abs_dir slug report status files_scanned findings)" == "$before" ]] + +for scanner_status in 0 1 2; do + main "$scratch/output" "$scratch/input" "$scratch/missing" + [[ "$(declare -p out_dir dir abs_dir slug report status files_scanned findings)" == "$before" ]] + [[ "$(wc -l < "$scratch/output/manifest.tsv")" -eq 2 ]] + grep -q $'\t1\t1\tswept$' "$scratch/output/manifest.tsv" + grep -q $'\t0\t0\tskipped-missing$' "$scratch/output/manifest.tsv" + [[ "$(cat "$scratch/output/summary.tsv")" == $'PI001\tCRITICAL\t1' ]] +done + +do_compare "$scratch/output" "$scratch/output" +if do_compare "$scratch/empty" "$scratch/output" > "$scratch/delta"; then + echo 'comparison must return 1 for a new finding' >&2 + exit 1 +else + [[ "$?" -eq 1 ]] +fi +[[ "$(cat "$scratch/delta")" == $'probe.md:1\tPI001' ]] +[[ "$(declare -p out_dir dir abs_dir slug report status files_scanned findings)" == "$before" ]] +echo 'gate03 sweep helper checks passed'