#!/usr/bin/env bash
set -uo pipefail
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT="${1:-$(cd "$HERE/../.." && pwd)}"
GATE="$ROOT/scripts/mutants_gate.sh"
[ -f "$GATE" ] || { echo "缺 $GATE" >&2; exit 1; }
PASS=0; FAIL=0
ok() { printf ' ✓ %s\n' "$1"; PASS=$((PASS + 1)); }
no() { printf ' ✗ %s\n' "$1"; FAIL=$((FAIL + 1)); }
TMP="$(mktemp -d)"; trap 'rm -rf "$TMP"' EXIT
echo "== AC3 腿(cargo-mutants)· 面 = $GATE =="
echo "-- G1 真面: 载体 rc=0 ∧ 分母 ≥1 ∧ missed=0"
G1="$TMP/g1.txt"; bash "$GATE" "$ROOT" >"$G1" 2>&1; G1RC=$?
N_F="$(grep -oE '分母 = [0-9]+' "$G1" | grep -oE '[0-9]+' | head -1)"
N_M="$(grep -oE 'missed = [0-9]+' "$G1" | grep -oE '[0-9]+' | head -1)"
if [ "$G1RC" -eq 0 ] && [ "${N_F:-0}" -ge 1 ] && [ "${N_M:-1}" -eq 0 ]; then
ok "G1 rc=0 ∧ 分母 $N_F(≥1)∧ missed $N_M"
else
no "G1 rc=$G1RC ∧ 分母=${N_F:-<空>} ∧ missed=${N_M:-<空>}"; tail -6 "$G1" | sed 's/^/ /'
fi
echo "-- G2 分类之和 ⇔ 分母(无未分类黑洞)"
N_C="$(grep -oE 'caught = [0-9]+' "$G1" | grep -oE '[0-9]+' | head -1)"
N_U="$(grep -oE 'unviable = [0-9]+' "$G1" | grep -oE '[0-9]+' | head -1)"
SUM=$(( ${N_C:-0} + ${N_M:-0} + ${N_U:-0} ))
if [ "${N_F:-0}" -ge 1 ] && [ "$SUM" -eq "${N_F:-0}" ]; then
ok "G2 caught($N_C) + missed($N_M) + unviable($N_U) = $SUM ⇔ 分母 $N_F(对表 ⇒ 无黑洞)"
else
no "G2 分类之和 = $SUM ⇎ 分母 = ${N_F:-<空>}(有未分类 ⇒ 分母不可信)"
fi
face() {
mkdir -p "$1/scripts"
cp -a "$ROOT/src" "$1/src"; cp -a "$ROOT/deep" "$1/deep"; rm -rf "$1/deep/target"
cp "$GATE" "$1/scripts/mutants_gate.sh"
if [ "$2" = "weaken" ]; then
python3 - "$1/deep/src/lib.rs" <<'PY'
import re, sys
p = sys.argv[1]; t = open(p, encoding='utf-8').read()
m = re.search(r'(?ms)^#\[cfg\(test\)\]\nmod tests \{.*\n\}\n', t)
assert m, "锚未命中(测试 mod 形变)"
open(p, 'w', encoding='utf-8').write(t[:m.start()] + t[m.end():])
PY
fi
}
echo "-- R1 阳性对照: 临时仓根删一处断言 ⇒ 逃逸必现 ⇒ 载体必红"
R1F="$TMP/r1"; face "$R1F" weaken
R1="$TMP/r1.txt"; bash "$R1F/scripts/mutants_gate.sh" "$R1F" >"$R1" 2>&1; R1RC=$?
N_M1="$(grep -oE 'missed = [0-9]+' "$R1" | grep -oE '[0-9]+' | head -1)"
if [ "$R1RC" -eq 124 ]; then
no "R1 ★ 逾时被杀 rc=124(**本腿未判**)—— 承裁19 §2: 超时 ≠ 未咬合 · 禁混(候复跑)"
elif [ ! -s "$R1" ]; then
no "R1 ★ 载体无输出 rc=$R1RC(**未判**)—— 无从判咬合(显名 · 非判「未咬合」)"
elif [ -z "$N_M1" ]; then
no "R1 ★ 载体未报 \`missed = N\`(rc=$R1RC ⇒ **载体未真跑**)—— **未判**(承裁19 §2 同律 · 禁以「未跑」充「未咬合」)"
tail -6 "$R1" | sed 's/^/ /'
elif [ "$R1RC" -ne 0 ] && [ "$N_M1" -ge 1 ]; then
ok "R1 咬合 rc=$R1RC ∧ missed=$N_M1(删断言 ⇒ 存活数可释 · 承 AC3 红侧)"
else
no "R1 未咬合 rc=$R1RC ∧ missed=$N_M1(有读数 ∧ 未达咬合阈)"; tail -6 "$R1" | sed 's/^/ /'
fi
echo "-- R2 对照: 同形仓根不删 ⇒ 载体绿(隔离 R1 之差因)"
R2F="$TMP/r2"; face "$R2F" clean
R2="$TMP/r2.txt"; bash "$R2F/scripts/mutants_gate.sh" "$R2F" >"$R2" 2>&1; R2RC=$?
if [ "$R2RC" -eq 124 ]; then no "R2 ★ 逾时被杀 rc=124(**本腿未判**)—— 超时 ≠ 「临时面自身不绿」· 禁混(候复跑)";
elif [ "$R2RC" -eq 0 ]; then ok "R2 rc=0(同形仓根不删)⇒ R1 之差可归于【删断言项】"; else no "R2 rc=$R2RC ⇒ 临时面自身不绿 ⇒ R1 之因不可归"; tail -6 "$R2" | sed 's/^/ /'; fi
echo "== 结果: PASS=$PASS FAIL=$FAIL =="
[ "$FAIL" -eq 0 ] || exit 1
exit 0