Skip to content

Differential testing

aowlparser's job is to emit the same tree as native nifler, so it is tested by running both on the same input and comparing output. There is no hand-written expected output; nifler is the oracle.


Two levels of match

For each input the harness runs nifler and aowlparser and compares the .p.aif:

  • Structural (the pass criterion) — tests/canon.py strips line-info (@…/~…) and comment suffixes and normalises whitespace; the token trees must then be identical. String contents are preserved: AIF escapes every marker byte inside strings, so a @ in "a@b" is never read as line-info.
  • Exact — the .p.aif bytes are identical, line-info included. This is the check that the relative line-info model is right, not just structurally plausible.

The only intentional byte difference is the (.vendor "aowlparser") header (nifler emits "Nifler"); both harnesses normalise it before comparing.

The harnesses

sh
bash tests/diff.sh                    # curated corpus, PASS/FAIL per file
VERBOSE=1 bash tests/diff.sh          # + a canonical diff per failure
bash tests/stress.sh                  # differential over nimony/lib
bash tests/stress.sh /path/dir ...    # differential over any dirs/files
bash tests/diag.sh                    # check-mode diagnostics

diff.sh runs the curated corpus under tests/corpus/ — one file per construct, so a failure names the broken grammar rule.

stress.sh points the same comparison at real .nim files and reports failure modes:

stress: total=310  pass=310  mismatch=0  our-crash=0  oracle-skip=0  byte-exact=283
  • our-crash — aowlparser produced no output (crash or hang). Must stay zero: a mismatch is a wrong tree, a crash is a broken tool.
  • oracle-skip — nifler itself failed on the file, so it is excluded.
  • byte-exact — of the passing files, how many matched to the byte.

Current results

targetcommandstructuralbyte-exactcrash/hang
curated corpustests/diff.sh172 / 1721560
nimony/srcstress.sh …/nimony/src184 / 1841840
nimony/libstress.sh …/nimony/lib105 / 105910
upstream Nim/libstress.sh …/Nim/lib310 / 3102830

599 valid files round-trip structure-identical to nifler; 558 are byte-identical (relative line-info included). See Coverage.

Why differential

A parser that emits a compiler wire format has a sharp oracle: the format is only useful if a second, independent implementation agrees byte-for-byte. That makes nifler both the spec and the test suite — any drift shows up as a concrete AIF diff against the tool the rest of the pipeline already trusts.

aoughwl — self-hosted platform for things n stuff. Contact / Support on Discord for access to the private backends.