Files
pi-imgen/tests/render-fixtures.sh
T
mozempk 5d27417c54 fix(render): resolve ink contrast per surface, not once per poster
templates/lib.typ gains WCAG luminance/contrast-ratio/ink-on and a
surface-aware palette-of(). framed and split place type on flat colour and
were inheriting an ink measured against the artwork, rendering white on
cream at 1.15:1. Now computed per surface: 18.34:1 on the regression
fixture. Accent held to the same bar with fallback to ink.

Adds tests/contrast-check.typ, run per fixture by the harness.
35/35 render combos and 7/7 contrast assertions pass.
2026-08-27 09:33:08 +02:00

86 lines
3.2 KiB
Bash
Executable File

#!/usr/bin/env bash
# Compile every template against every fixture spec.
#
# This is the golden-file harness: because Typst is invoked with
# --ignore-system-fonts and every template sets `#set document(date: none)`,
# output is byte-identical across runs and machines, so a diff is a real regression.
#
# GOTCHA: Typst resolves a leading "/" against --root, NOT the filesystem. So the spec
# path passed via --input must be ROOT-RELATIVE ("/tests/fixtures/x.json"); handing it an
# absolute filesystem path silently produces "<root>/home/you/...", i.e. file not found.
# extensions/imgen/render/typst.ts must obey the same rule.
#
# Usage: tests/render-fixtures.sh [path-to-typst]
set -uo pipefail
cd "$(dirname "$0")/.."
ROOT="$PWD"
TYPST="${1:-${TYPST:-typst}}"
command -v "$TYPST" >/dev/null 2>&1 || { echo "typst non trovato: $TYPST"; exit 127; }
FONTS="$ROOT/vendor/fonts"
[ -d "$FONTS" ] && [ -n "$(ls -A "$FONTS" 2>/dev/null | grep -v '^\.')" ] || {
echo "ATTENZIONE: vendor/fonts è vuoto — esegui scripts/fetch-fonts.sh"
FONTS="$ROOT/tests/fonts"
}
OUT="$ROOT/tests/out"
mkdir -p "$OUT"
pass=0; fail=0; failed=()
for tpl in "$ROOT"/templates/*.typ; do
name="$(basename "$tpl" .typ)"
[ "$name" = "lib" ] && continue
for fx in "$ROOT"/tests/fixtures/*.json; do
fxname="$(basename "$fx" .json)"
out="$OUT/${name}__${fxname}.pdf"
if SOURCE_DATE_EPOCH=0 "$TYPST" compile "$tpl" "$out" \
--input specfile="/tests/fixtures/${fxname}.json" \
--font-path "$FONTS" --ignore-system-fonts \
--root "$ROOT" >"$OUT/${name}__${fxname}.log" 2>&1; then
pass=$((pass+1)); printf ' ok %s / %s\n' "$name" "$fxname"
else
fail=$((fail+1)); failed+=("$name/$fxname")
printf ' FAIL %s / %s\n' "$name" "$fxname"
sed -n '1,6p' "$OUT/${name}__${fxname}.log" | sed 's/^/ /'
fi
done
done
echo
echo "passati: $pass falliti: $fail"
if [ "$fail" -gt 0 ]; then printf 'falliti: %s\n' "${failed[*]}"; exit 1; fi
# Contrast assertion: every surface must resolve to a legible ink (>= 3.0:1).
echo
echo "controllo contrasto:"
cbad=0
for fx in "$ROOT"/tests/fixtures/*.json; do
fxname="$(basename "$fx" .json)"
if out=$("$TYPST" compile "$ROOT/tests/contrast-check.typ" "$OUT/contrast_${fxname}.pdf" \
--input specfile="/tests/fixtures/${fxname}.json" --root "$ROOT" 2>&1); then
printf ' ok %s\n' "$fxname"
else
cbad=$((cbad+1))
printf ' FAIL %s\n' "$fxname"
echo "$out" | grep -m1 'contrasto insufficiente' | sed 's/^/ /'
fi
done
[ "$cbad" -gt 0 ] && { echo "contrasto: $cbad fixture non conformi"; exit 1; }
echo
# Geometry assertion on the print fixtures: A3 trim must be exactly 297x420mm.
python3 - "$OUT" <<'PY'
import glob, re, sys, os
bad = 0
for p in glob.glob(os.path.join(sys.argv[1], "*__accents.pdf")):
d = open(p, "rb").read()
m = re.search(rb"/TrimBox\s*\[([^\]]*)\]", d)
if not m:
print("TrimBox ASSENTE:", os.path.basename(p)); bad += 1; continue
x0, y0, x1, y1 = (float(v) for v in m.group(1).split())
w, h = (x1-x0)/72*25.4, (y1-y0)/72*25.4
if abs(w-297) > 0.5 or abs(h-420) > 0.5:
print(f"geometria errata {os.path.basename(p)}: {w:.1f}x{h:.1f}mm"); bad += 1
sys.exit(1 if bad else 0)
PY