diff options
| author | Ralph Amissah <ralph.amissah@gmail.com> | 2026-09-21 12:49:54 -0400 |
|---|---|---|
| committer | Ralph Amissah <ralph.amissah@gmail.com> | 2026-09-22 15:11:02 -0400 |
| commit | eeabf6216fde5f387d6173da93d0df882ed8a34e (patch) | |
| tree | 1aab8a2fdba5f13199eeea6caebb7bea7b271670 /org | |
| parent | check: warn when document's languages ocn diverge (diff) | |
test: ocn alignment check
Asserts the two known divergences in live-manual's translations by name
and value: ja two objects short of en, and pl's ocn 313 a paragraph in
English and a heading in Polish.
It asserts that nothing else is reported: exactly one document warned
about, exactly two languages of it.
Also the exit codes: 0 without --strict, non-zero with it on the
diverging document, and 0 with it on a single language document.
It will fail when those two translations are mended, which is the right
moment to hear about it, and the message names the expectation that went
stale.
test-abstraction-db.sh excludes translation.ocn_aligned from its header
block comparison, with the other two keys that are the database's notes
about the artefact rather than properties of the document.
(assisted by Claude-Code)
Diffstat (limited to 'org')
| -rw-r--r-- | org/tests_for_document_abstraction_shell_scripts.org | 435 |
1 files changed, 303 insertions, 132 deletions
diff --git a/org/tests_for_document_abstraction_shell_scripts.org b/org/tests_for_document_abstraction_shell_scripts.org index 0f41ca6..b4d71f8 100644 --- a/org/tests_for_document_abstraction_shell_scripts.org +++ b/org/tests_for_document_abstraction_shell_scripts.org @@ -45,7 +45,8 @@ # 2 test-abstraction-ssp-roundtrip.sh the .ssp can be read back whole # 3 test-abstraction-db.sh the two serialisations agree # 4 test-abstraction-db-roundtrip.sh the .db can be read back whole -# 5 test-epub-validity.sh the epubs a reader can actually open +# 5 test-ocn-alignment.sh the languages agree on their ocns +# 6 test-epub-validity.sh the epubs a reader can actually open # # None of them calls another, and each can be run on its own. The order # matters only for reading the result: @@ -59,6 +60,11 @@ # - 3 and 4 generate both artefacts themselves and depend on nothing # committed. Since the database is built from the .ssp, they are checks # on the reader rather than on two independent writers. +# - 5 is about the sample documents rather than about a serialisation: it +# asserts that spine reports the two known divergences in live-manual's +# translations and reports nothing about the other documents. It will +# fail if those translations are mended, which is the right moment to +# hear about it. set -e @@ -84,6 +90,7 @@ TESTS="test-abstraction-ssp.sh test-abstraction-ssp-roundtrip.sh test-abstraction-db.sh test-abstraction-db-roundtrip.sh +test-ocn-alignment.sh test-epub-validity.sh" PASSED=0 @@ -122,8 +129,8 @@ else fi #+END_SRC -** ssp ocda abstraction -*** document.ssp abstraction test/test-abstraction-ssp.sh +** 1&2. ssp ocda abstraction +*** 1. document.ssp abstraction test/test-abstraction-ssp.sh #+HEADER: :tangle ../test/test-abstraction-ssp.sh #+HEADER: :tangle-mode (identity #o755) @@ -314,7 +321,7 @@ else fi #+END_SRC -*** document.ssp abstraction test/test-abstraction-ssp-roundtrip.sh +*** 2. document.ssp abstraction test/test-abstraction-ssp-roundtrip.sh #+HEADER: :tangle ../test/test-abstraction-ssp-roundtrip.sh #+HEADER: :tangle-mode (identity #o755) @@ -404,8 +411,8 @@ else fi #+END_SRC -** db ocda abstraction -*** document db ocda test/test-abstraction-db.sh +** 3&4. db ocda abstraction +*** 3. document db ocda test/test-abstraction-db.sh #+HEADER: :tangle ../test/test-abstraction-db.sh #+HEADER: :tangle-mode (identity #o755) @@ -646,7 +653,11 @@ for ssp in $(find "$OUT_DIR/pod" -name "*.ssp" 2>/dev/null | sort); do done # the header blocks: every @source/@meta/@make/@doc_has property in the .ssp - # must be in the database under its own key, with the same value. this is + # must be in the database under its own key, with the same value. the three + # excluded keys are the database's own notes about the artefact rather than + # properties of the document: what it was built from (source.filename, + # source.ssp_digest) and how its languages compared once they had all been + # read (translation.ocn_aligned), which no single .ssp can state. this is # what catches a header property that reaches one artefact and not the # other, which a count of objects cannot see. awk ' @@ -661,7 +672,7 @@ for ssp in $(find "$OUT_DIR/pod" -name "*.ssp" 2>/dev/null | sort); do ' "$ssp" | sort > "$OUT_DIR/.sspmeta.$$" sqlite3 -separator "$(printf '\t')" "$db" \ "select key, value from metadata where doc_id=$did and key not in - ('source.filename','source.ssp_digest');" \ + ('source.filename','source.ssp_digest','translation.ocn_aligned');" \ 2>/dev/null | sort > "$OUT_DIR/.dbmeta.$$" if ! diff -q "$OUT_DIR/.sspmeta.$$" "$OUT_DIR/.dbmeta.$$" > /dev/null 2>&1; then [ $doc_fail -eq 0 ] && echo "$base" @@ -726,7 +737,7 @@ else fi #+END_SRC * -*** document db ocda test-abstraction-db-roundtrip.sh +*** 4. document db ocda test-abstraction-db-roundtrip.sh #+HEADER: :tangle ../test/test-abstraction-db-roundtrip.sh #+HEADER: :tangle-mode (identity #o755) @@ -868,6 +879,289 @@ else fi #+END_SRC +** 5. test ocn alignment + +#+HEADER: :tangle ../test/test-ocn-alignment.sh +#+HEADER: :tangle-mode (identity #o755) +#+HEADER: :shebang "#!/usr/bin/env sh" +#+BEGIN_SRC shell +# test-ocn-alignment.sh +# +# The languages of a document share their object numbering, and spine warns +# when they stop doing so. This checks that the warning appears where it +# should and, just as importantly, nowhere else. +# +# The sample set is the fixture, and it is a good one because it contains +# both answers: +# +# live-manual ten languages, two of which diverge. +# ja has two fewer numbered objects than en. A missing +# translation of a short paragraph; everything below it +# is renumbered. +# pl has the same count, but the object at ocn 313 is a +# paragraph in en and a heading in pl. A heading given as +# running text, or running text given as a heading. +# everything else single language, or aligned. Silent. +# +# A check that only ever fires is as useless as one that never does, so the +# silence over the other documents is asserted too. +# +# It also asserts that --strict turns the warning into a non-zero exit, and +# that without --strict the run still succeeds: a document with a diverging +# translation is still a document. +# +# Usage: +# SpinePOD=../../markup/sisudoc-spine-samples/markup/pod-samples/pod \ +# ./test/test-ocn-alignment.sh ./bin/spine-ldc +# +# Exit codes: +# 0 the check reports what it should, and nothing else +# 1 it does not (printed) +# 2 set-up problem (no $SpinePOD, no binary, no samples) + +set -e + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +SPINE_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" + +if [ -z "$SpinePOD" ]; then + echo "ERROR: \$SpinePOD is not set." >&2 + echo " e.g. SpinePOD=../../markup/sisudoc-spine-samples/markup/pod-samples/pod" >&2 + exit 2 +fi +SAMPLES_RAW="$SPINE_DIR/$SpinePOD" +if [ -d "$SAMPLES_RAW" ]; then + SAMPLES_DIR="$(cd "$SAMPLES_RAW" && pwd)" +else + SAMPLES_DIR="$SAMPLES_RAW" +fi +if [ ! -d "$SAMPLES_DIR" ]; then + echo "ERROR: sample documents not found at $SAMPLES_DIR" >&2 + exit 2 +fi + +SPINE_BIN="${1:-}" +if [ -z "$SPINE_BIN" ]; then + if [ -x "$SPINE_DIR/result/bin/spine" ]; then SPINE_BIN="$SPINE_DIR/result/bin/spine" + elif [ -x "$SPINE_DIR/bin/spine-ldc" ]; then SPINE_BIN="$SPINE_DIR/bin/spine-ldc" + elif [ -x "$SPINE_DIR/bin/spine" ]; then SPINE_BIN="$SPINE_DIR/bin/spine" + else + echo "ERROR: spine binary not found. Specify path as argument." >&2 + exit 2 + fi +fi + +OUT_DIR="$SCRIPT_DIR/current-ocn-alignment" +rm -rf "$OUT_DIR" +mkdir -p "$OUT_DIR" + +echo "spine binary: $SPINE_BIN" +echo "samples: $SAMPLES_DIR" + +FAILURES=0 +fail() { echo " FAIL: $*"; FAILURES=$((FAILURES + 1)); } + +# the whole sample set, abstraction only: the check does not need outputs +echo "Abstracting the sample set ..." +set +e +$SPINE_BIN --show-abstraction --skip-output \ + --output="$OUT_DIR" "$SAMPLES_DIR"/* \ + > "$OUT_DIR/run.out" 2> "$OUT_DIR/run.err" +RUN_RC=$? +set -e + +# without --strict a diverging document is still built +if [ "$RUN_RC" -ne 0 ]; then + fail "the run exited $RUN_RC without --strict; a warning must not fail a run" + head -5 "$OUT_DIR/run.err" +fi + +# what it said +if ! grep -q "^WARNING ocn alignment: live-manual$" "$OUT_DIR/run.err"; then + fail "no ocn alignment warning for live-manual" +fi +if ! grep -q "^ \[ja\] differs from \[en\]$" "$OUT_DIR/run.err"; then + fail "ja not reported as differing from en" +fi +if ! grep -q "numbered objects: en 1019, ja 1017 (-2)" "$OUT_DIR/run.err"; then + fail "ja's object count difference not reported as -2" +fi +if ! grep -q "^ \[pl\] differs from \[en\]$" "$OUT_DIR/run.err"; then + fail "pl not reported as differing from en" +fi +if ! grep -q "ocn 313: para in en, heading:2 in pl" "$OUT_DIR/run.err"; then + fail "pl's substituted heading at ocn 313 not reported" +fi + +# and what it did not say: exactly one document warned about, exactly two +# languages of it +n_docs=$(grep -c "^WARNING ocn alignment: " "$OUT_DIR/run.err" || true) +if [ "$n_docs" != "1" ]; then + fail "$n_docs documents warned about, expected 1" + grep "^WARNING ocn alignment: " "$OUT_DIR/run.err" | sed 's/^/ /' +fi +n_langs=$(grep -c "^ \[.*\] differs from " "$OUT_DIR/run.err" || true) +if [ "$n_langs" != "2" ]; then + fail "$n_langs languages reported, expected 2 (ja and pl)" + grep "^ \[.*\] differs from " "$OUT_DIR/run.err" | sed 's/^/ /' +fi + +# --strict makes the same run fail +set +e +$SPINE_BIN --show-abstraction --skip-output --strict \ + --output="$OUT_DIR/strict" "$SAMPLES_DIR"/live-manual \ + > "$OUT_DIR/strict.out" 2> "$OUT_DIR/strict.err" +STRICT_RC=$? +set -e +if [ "$STRICT_RC" -eq 0 ]; then + fail "--strict exited 0 on a document whose languages diverge" +fi + +# and does not fail a document whose languages agree, or one that has only +# the one language +set +e +$SPINE_BIN --show-abstraction --skip-output --strict \ + --output="$OUT_DIR/strict-ok" "$SAMPLES_DIR"/the_wealth_of_networks.yochai_benkler \ + > "$OUT_DIR/strict-ok.out" 2> "$OUT_DIR/strict-ok.err" +STRICT_OK_RC=$? +set -e +if [ "$STRICT_OK_RC" -ne 0 ]; then + fail "--strict exited $STRICT_OK_RC on a single language document" + head -5 "$OUT_DIR/strict-ok.err" +fi + +rm -rf "$OUT_DIR" + +if [ "$FAILURES" -eq 0 ]; then + echo "PASS: ja and pl reported on live-manual, silent elsewhere, --strict fails" + exit 0 +else + echo "FAIL: $FAILURES check(s)" + exit 1 +fi +#+END_SRC +** 6. test epub validity + +#+HEADER: :tangle ../test/test-epub-validity.sh +#+HEADER: :tangle-mode (identity #o755) +#+HEADER: :shebang "#!/usr/bin/env sh" +#+BEGIN_SRC shell +# epubcheck over the sample set, as a regression guard. +# +# Every epub spine writes is checked with epubcheck. A *fatal* is never +# acceptable: it means a reader cannot parse the file at all. Errors are +# compared against a recorded allowance, so that the ones known to be +# outstanding do not fail the run while any new one does. +# +# The allowance is deliberately a single number rather than a list of +# messages: a list invites adding to it. When the number goes down, lower it +# here in the same commit that lowers it in the output. +# +# Usage: +# SpinePOD=../../markup/sisudoc-spine-samples/markup/pod-samples/pod \ +# ./test/test-epub-validity.sh ./bin/spine-ldc +# +# Exit codes: +# 0 no fatals, and errors within the allowance +# 1 a fatal, or more errors than allowed +# 2 set-up problem (no $SpinePOD, no binary, no epubcheck, no samples) + +set -e + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +SPINE_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" + +# What is known to be outstanding over the whole sample set. Both numbers are +# a ceiling, so a regression fails and an improvement does not; lower them in +# the commit that lowers the output, and say in that commit what went. +# +# There is no allowance for a fatal, and there must never be one. The last +# one - the_public_domain, chapter_2: a bare url ending a footnote body +# swallowed the "}~" close delimiter, so the note closed inside the link +# markup and left an unbalanced </a> behind - was a url boundary defect in +# the abstraction, and is fixed. +# +# No error is allowed either, and none is outstanding. Both numbers being +# zero is the point: anything at all that epubcheck calls an error is a +# regression, and there is no list to add to. +# +# No warning is outstanding either, though warnings are not counted here. +FATALS_ALLOWED=${SpineEpubFatalsAllowed:-0} +ERRORS_ALLOWED=${SpineEpubErrorsAllowed:-0} + +if [ -z "$SpinePOD" ]; then + echo "ERROR: \$SpinePOD is not set." >&2 + echo " e.g. SpinePOD=../../markup/sisudoc-spine-samples/markup/pod-samples/pod" >&2 + exit 2 +fi +SAMPLES_RAW="$SPINE_DIR/$SpinePOD" +if [ -d "$SAMPLES_RAW" ]; then + SAMPLES_DIR="$(cd "$SAMPLES_RAW" && pwd)" +else + SAMPLES_DIR="$SAMPLES_RAW" +fi +SPINE_BIN="${1:-}" +# find spine binary +if [ -z "$SPINE_BIN" ]; then + if [ -x "$SPINE_DIR/result/bin/spine" ]; then SPINE_BIN="$SPINE_DIR/result/bin/spine" + elif [ -x "$SPINE_DIR/bin/spine-ldc" ]; then SPINE_BIN="$SPINE_DIR/bin/spine-ldc" + elif [ -x "$SPINE_DIR/bin/spine" ]; then SPINE_BIN="$SPINE_DIR/bin/spine" + else + echo "ERROR: spine binary not found. Specify path as argument." >&2 + exit 2 + fi +fi +if [ ! -d "$SAMPLES_DIR" ]; then + echo "ERROR: samples not found: $SAMPLES_DIR" >&2 + exit 2 +fi +if ! command -v epubcheck >/dev/null 2>&1; then + echo "ERROR: epubcheck not on PATH." >&2 + echo " e.g. nix shell \"nixpkgs#epubcheck\" -c $0 $SPINE_BIN" >&2 + exit 2 +fi + +echo "spine binary: $SPINE_BIN" +echo "samples: $SAMPLES_DIR" + +OUT_DIR="$(mktemp -d)" +trap 'rm -rf "$OUT_DIR"' EXIT + +echo "Generating epubs ..." +"$SPINE_BIN" --epub --output="$OUT_DIR" "$SAMPLES_DIR"/* 2>&1 | tail -1 + +FATALS=0 +ERRORS=0 +DOCS=0 +for f in $(find "$OUT_DIR" -name '*.epub' | sort); do + DOCS=$((DOCS + 1)) + msg=$(epubcheck "$f" 2>&1 | grep -E '^Messages:' || true) + ff=$(echo "$msg" | sed -n 's/.*: \([0-9]*\) fatal.*/\1/p') + ee=$(echo "$msg" | sed -n 's/.*\/ \([0-9]*\) error.*/\1/p') + ff=${ff:-0}; ee=${ee:-0} + FATALS=$((FATALS + ff)) + ERRORS=$((ERRORS + ee)) + if [ "$ff" -gt 0 ]; then + echo " FATAL in $(basename "$f"): $ff" + epubcheck "$f" 2>&1 | grep -i 'FATAL' | head -3 | sed 's/^/ /' + fi +done + +echo "checked $DOCS epubs: $FATALS fatal (allowed $FATALS_ALLOWED), $ERRORS errors (allowed $ERRORS_ALLOWED)" + +if [ "$FATALS" -gt "$FATALS_ALLOWED" ]; then + echo "FAIL: $FATALS fatal(s), more than the $FATALS_ALLOWED allowed;" + echo " a fatal means a reader cannot parse that file at all" + exit 1 +fi +if [ "$ERRORS" -gt "$ERRORS_ALLOWED" ]; then + echo "FAIL: $ERRORS errors, more than the $ERRORS_ALLOWED allowed" + echo " if this is a deliberate change, say why and adjust ERRORS_ALLOWED" + exit 1 +fi +echo "PASS: $FATALS fatal and $ERRORS errors, both within what is recorded" +exit 0 +#+END_SRC * collection search db + cgi form ** test search db schema @@ -1317,126 +1611,3 @@ else exit 1 fi #+END_SRC - -** test epub validity - -#+HEADER: :tangle ../test/test-epub-validity.sh -#+HEADER: :tangle-mode (identity #o755) -#+HEADER: :shebang "#!/usr/bin/env sh" -#+BEGIN_SRC shell -# epubcheck over the sample set, as a regression guard. -# -# Every epub spine writes is checked with epubcheck. A *fatal* is never -# acceptable: it means a reader cannot parse the file at all. Errors are -# compared against a recorded allowance, so that the ones known to be -# outstanding do not fail the run while any new one does. -# -# The allowance is deliberately a single number rather than a list of -# messages: a list invites adding to it. When the number goes down, lower it -# here in the same commit that lowers it in the output. -# -# Usage: -# SpinePOD=../../markup/sisudoc-spine-samples/markup/pod-samples/pod \ -# ./test/test-epub-validity.sh ./bin/spine-ldc -# -# Exit codes: -# 0 no fatals, and errors within the allowance -# 1 a fatal, or more errors than allowed -# 2 set-up problem (no $SpinePOD, no binary, no epubcheck, no samples) - -set -e - -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -SPINE_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" - -# What is known to be outstanding over the whole sample set. Both numbers are -# a ceiling, so a regression fails and an improvement does not; lower them in -# the commit that lowers the output, and say in that commit what went. -# -# There is no allowance for a fatal, and there must never be one. The last -# one - the_public_domain, chapter_2: a bare url ending a footnote body -# swallowed the "}~" close delimiter, so the note closed inside the link -# markup and left an unbalanced </a> behind - was a url boundary defect in -# the abstraction, and is fixed. -# -# No error is allowed either, and none is outstanding. Both numbers being -# zero is the point: anything at all that epubcheck calls an error is a -# regression, and there is no list to add to. -# -# No warning is outstanding either, though warnings are not counted here. -FATALS_ALLOWED=${SpineEpubFatalsAllowed:-0} -ERRORS_ALLOWED=${SpineEpubErrorsAllowed:-0} - -if [ -z "$SpinePOD" ]; then - echo "ERROR: \$SpinePOD is not set." >&2 - echo " e.g. SpinePOD=../../markup/sisudoc-spine-samples/markup/pod-samples/pod" >&2 - exit 2 -fi -SAMPLES_RAW="$SPINE_DIR/$SpinePOD" -if [ -d "$SAMPLES_RAW" ]; then - SAMPLES_DIR="$(cd "$SAMPLES_RAW" && pwd)" -else - SAMPLES_DIR="$SAMPLES_RAW" -fi -SPINE_BIN="${1:-}" -# find spine binary -if [ -z "$SPINE_BIN" ]; then - if [ -x "$SPINE_DIR/result/bin/spine" ]; then SPINE_BIN="$SPINE_DIR/result/bin/spine" - elif [ -x "$SPINE_DIR/bin/spine-ldc" ]; then SPINE_BIN="$SPINE_DIR/bin/spine-ldc" - elif [ -x "$SPINE_DIR/bin/spine" ]; then SPINE_BIN="$SPINE_DIR/bin/spine" - else - echo "ERROR: spine binary not found. Specify path as argument." >&2 - exit 2 - fi -fi -if [ ! -d "$SAMPLES_DIR" ]; then - echo "ERROR: samples not found: $SAMPLES_DIR" >&2 - exit 2 -fi -if ! command -v epubcheck >/dev/null 2>&1; then - echo "ERROR: epubcheck not on PATH." >&2 - echo " e.g. nix shell \"nixpkgs#epubcheck\" -c $0 $SPINE_BIN" >&2 - exit 2 -fi - -echo "spine binary: $SPINE_BIN" -echo "samples: $SAMPLES_DIR" - -OUT_DIR="$(mktemp -d)" -trap 'rm -rf "$OUT_DIR"' EXIT - -echo "Generating epubs ..." -"$SPINE_BIN" --epub --output="$OUT_DIR" "$SAMPLES_DIR"/* 2>&1 | tail -1 - -FATALS=0 -ERRORS=0 -DOCS=0 -for f in $(find "$OUT_DIR" -name '*.epub' | sort); do - DOCS=$((DOCS + 1)) - msg=$(epubcheck "$f" 2>&1 | grep -E '^Messages:' || true) - ff=$(echo "$msg" | sed -n 's/.*: \([0-9]*\) fatal.*/\1/p') - ee=$(echo "$msg" | sed -n 's/.*\/ \([0-9]*\) error.*/\1/p') - ff=${ff:-0}; ee=${ee:-0} - FATALS=$((FATALS + ff)) - ERRORS=$((ERRORS + ee)) - if [ "$ff" -gt 0 ]; then - echo " FATAL in $(basename "$f"): $ff" - epubcheck "$f" 2>&1 | grep -i 'FATAL' | head -3 | sed 's/^/ /' - fi -done - -echo "checked $DOCS epubs: $FATALS fatal (allowed $FATALS_ALLOWED), $ERRORS errors (allowed $ERRORS_ALLOWED)" - -if [ "$FATALS" -gt "$FATALS_ALLOWED" ]; then - echo "FAIL: $FATALS fatal(s), more than the $FATALS_ALLOWED allowed;" - echo " a fatal means a reader cannot parse that file at all" - exit 1 -fi -if [ "$ERRORS" -gt "$ERRORS_ALLOWED" ]; then - echo "FAIL: $ERRORS errors, more than the $ERRORS_ALLOWED allowed" - echo " if this is a deliberate change, say why and adjust ERRORS_ALLOWED" - exit 1 -fi -echo "PASS: $FATALS fatal and $ERRORS errors, both within what is recorded" -exit 0 -#+END_SRC |
