Tests: every gate stage asserts how many cases it ran

old-reader-refusal.sh pins the expected case count of each stage as a constant (C# stages from the TRX the run writes, by class; Rust,
Python and TypeScript from their own output) and fails naming '<stage>-count' on any other number, so a probe renamed out of its filter
or a skipped leaf test no longer passes with nothing run.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-10-27 07:59:19 +01:00
commit f41dc3d63b

View file

@ -17,8 +17,14 @@
# old-reader-refusal.sh gate csharp|typescript|python|rust
# Run in a CultLib clone at the revision under test: stage, then probe. For csharp, C2aGateWriter first writes the live
# v3 and v5 stores into $GATE_OUT (default /tmp/gate) and the 2.0.1 probes read them beside the committed vectors; the
# 1.0.60 writer then writes a ref-list store there, 2.0.1 and the tree under test both open it, and their REFLIST-SUMMARY
# lines must be identical.
# 1.0.60 writer then writes a ref-list store there, 2.0.1 and the tree under test both open it, write the same documents
# back and reread the file, and their REFLIST-SUMMARY lines (records by schema id, the list's items in order, the Items
# slot's catalog entry, warnings, header) must be identical.
#
# Every stage asserts how many cases it ran, so a probe that was renamed out of its filter or a leaf test that was skipped
# fails the gate by name ('<stage>-count') instead of passing with nothing run. The expected counts are the constants below;
# each is confirmed against the probe's source: C#, the TRX the run wrote (cases by class); Rust, the sum of 'N passed';
# Python, 'Ran N tests'; TypeScript, node's 'pass N'.
set -euo pipefail
here="tests/vectors/document-variants-c2a"
@ -27,6 +33,15 @@ OLD_READER_REV_CSHARP="${OLD_READER_REV_CSHARP:-b8fc5eb0}" # cultlib-unity-v2.
OLD_READER_REV_LEAF="${OLD_READER_REV_LEAF:-02cf04b5}" # cultcache-rs-v0.3.1
OLD_WRITER_REV="${OLD_WRITER_REV:-45c2f400}" # cultlib-unity-v1.0.60
EXPECT_C2A_WRITER=2 # C2aGateWriter: C2aStamps..., TheCommittedVectorsAreWhatC2aWrites
EXPECT_READER_GATE=12 # OldReaderGateProbe: five TestCaseSource tests over the committed and live stores
EXPECT_READER_REFLIST=1 # OldReaderRefListProbe
EXPECT_OLD_WRITER=1 # OldWriterRefListProbe
EXPECT_HEAD_REFLIST=1 # RefListDriftTests.A_1_0_60_Written_Store_Opens_Like_2_0_1
EXPECT_RUST=3 # tests/old_reader_v3.rs
EXPECT_PYTHON=4 # test_old_reader_v3.py
EXPECT_TYPESCRIPT=3 # old-reader-v3.test.ts
usage() { echo "usage: $0 stage|probe|gate csharp|typescript|python|rust (writer for stage and probe)" >&2; exit 2; }
revision_for() {
@ -73,8 +88,8 @@ stage() {
probe() {
case "$1" in
csharp) CULTLIB_ROOT="$PWD" dotnet test tests/GameCult.Caching.Tests --filter "FullyQualifiedName~OldReaderGateProbe|FullyQualifiedName~OldReaderRefListProbe" --logger "console;verbosity=detailed" ;;
writer) dotnet test tests/GameCult.Caching.Tests --filter FullyQualifiedName~OldWriterRefListProbe --logger "console;verbosity=detailed" ;;
csharp) CULTLIB_ROOT="$PWD" dotnet test tests/GameCult.Caching.Tests --filter "FullyQualifiedName~OldReaderGateProbe|FullyQualifiedName~OldReaderRefListProbe" --logger "console;verbosity=detailed" --logger "trx;LogFileName=reader.trx" --results-directory "${GATE_TRX_DIR:-TestResults}" ;;
writer) dotnet test tests/GameCult.Caching.Tests --filter FullyQualifiedName~OldWriterRefListProbe --logger "console;verbosity=detailed" --logger "trx;LogFileName=writer.trx" --results-directory "${GATE_TRX_DIR:-TestResults}" ;;
typescript)
npm install --no-audit --no-fund >/dev/null 2>&1
cd packages/cultcache-ts
@ -100,18 +115,38 @@ probe_staged() {
summary_of() { grep -o 'REFLIST-SUMMARY .*' "$1" | sort -u; }
# Cases a TRX records for test classes whose name ends in $2 (every class when $2 is empty); 0 when the run wrote no TRX.
trx_cases() { if [ -f "$1" ]; then grep -o "<TestMethod [^>]*className=\"[^\"]*$2\"" "$1" | wc -l; else echo 0; fi; }
# Cases a leaf runtime's own output says it ran.
leaf_cases() {
case "$1" in
rust) awk '/^test result:/ { n += $4 } END { print n + 0 }' "$2" ;;
python) awk '/^Ran [0-9]+ test/ { n = $2 } END { print n + 0 }' "$2" ;;
typescript) awk '/^[^[:alnum:]]*pass [0-9]+$/ { n = $NF } END { print n + 0 }' "$2" ;;
esac
}
# Every csharp stage runs, so a writer that stamps the wrong header is also caught by the 2.0.1 reader opening what it wrote;
# the gate fails if any stage failed and names them.
gate() {
local failures=""
# A stage that ran a number of cases other than the one pinned fails as '<stage>-count'.
expect() { if [ "$2" != "$3" ]; then echo "COUNT $1: expected $2 case(s), ran $3"; failures+=" $1-count"; fi; }
case "$1" in
csharp)
local out="${GATE_OUT:-/tmp/gate}" failures=""
local out="${GATE_OUT:-/tmp/gate}" trx
rm -rf "$out"; mkdir -p "$out"
export CULTLIB_GATE_OUT="$out"
dotnet test tests/GameCult.Caching.Tests --filter FullyQualifiedName~C2aGateWriter --logger "console;verbosity=detailed" || failures+=" c2a-writer"
export CULTLIB_GATE_OUT="$out" GATE_TRX_DIR="$out/trx"
trx="$GATE_TRX_DIR"
dotnet test tests/GameCult.Caching.Tests --filter FullyQualifiedName~C2aGateWriter --logger "console;verbosity=detailed" --logger "trx;LogFileName=c2a-writer.trx" --results-directory "$trx" || failures+=" c2a-writer"
expect c2a-writer "$EXPECT_C2A_WRITER" "$(trx_cases "$trx/c2a-writer.trx" C2aGateWriter)"
probe_staged writer || failures+=" 1.0.60-writer"
expect 1.0.60-writer "$EXPECT_OLD_WRITER" "$(trx_cases "$trx/writer.trx" OldWriterRefListProbe)"
probe_staged csharp 2>&1 | tee "$out/reader.log" || failures+=" 2.0.1-reader"
CULTLIB_GATE_OLD_STORE="$out/v1-0-60-ref-list.cc" dotnet test tests/GameCult.Caching.Tests --filter "FullyQualifiedName~RefListDriftTests.A_1_0_60_Written_Store_Opens_Like_2_0_1" --logger "console;verbosity=detailed" 2>&1 | tee "$out/head.log" || failures+=" head-ref-list"
expect 2.0.1-reader "$EXPECT_READER_GATE+$EXPECT_READER_REFLIST" "$(trx_cases "$trx/reader.trx" OldReaderGateProbe)+$(trx_cases "$trx/reader.trx" OldReaderRefListProbe)"
CULTLIB_GATE_OLD_STORE="$out/v1-0-60-ref-list.cc" dotnet test tests/GameCult.Caching.Tests --filter "FullyQualifiedName~RefListDriftTests.A_1_0_60_Written_Store_Opens_Like_2_0_1" --logger "console;verbosity=detailed" --logger "trx;LogFileName=head.trx" --results-directory "$trx" 2>&1 | tee "$out/head.log" || failures+=" head-ref-list"
expect head-ref-list "$EXPECT_HEAD_REFLIST" "$(trx_cases "$trx/head.trx" RefListDriftTests)"
summary_of "$out/reader.log" > "$out/reader.summary"
summary_of "$out/head.log" > "$out/head.summary"
cat "$out/reader.summary" "$out/head.summary"
@ -122,7 +157,14 @@ gate() {
fi
if [ -n "$failures" ]; then echo "GATE csharp FAILED:$failures"; return 1; fi
echo "GATE csharp ok" ;;
typescript|python|rust) probe_staged "$1" ;;
typescript|python|rust)
local log expected
log="$(mktemp)"
case "$1" in rust) expected="$EXPECT_RUST" ;; python) expected="$EXPECT_PYTHON" ;; typescript) expected="$EXPECT_TYPESCRIPT" ;; esac
probe_staged "$1" 2>&1 | tee "$log" || failures+=" $1"
expect "$1" "$expected" "$(leaf_cases "$1" "$log")"
if [ -n "$failures" ]; then echo "GATE $1 FAILED:$failures"; return 1; fi
echo "GATE $1 ok" ;;
*) usage ;;
esac
}