Skip to content

Verify it yourself

Everything on the Fidelity page comes from commands you can run in a clone of the repository. Most of them need only Rust: C’s outputs are committed, as hashes or as goldens.

Terminal window
cargo test --workspace # every ratchet, both kinds of check
cargo run --release -p graphviz-pure-diff -- e2e --list # full-SVG identity, list differences
cargo run --release -p graphviz-pure-diff -- --filter clust --worst 20 # layout geometry, a subset
cargo run --release -p graphviz-pure-diff -- render # renderers on C's own layouts
cargo run --release -p graphviz-pure-diff -- structure # same nodes, edges and labels as C, on canvas
node scripts/wasm-e2e.mjs --pkg <wasm-bindgen nodejs output> # the same check under WASM
scripts/update-baselines.sh [--portable] # after an improvement

cargo test --workspace runs the corpus checks as ratchets (crates/graphviz-pure-diff/tests/*_fidelity.rs): each one fails if a file listed in its baseline stops matching. The profile is chosen by the build: macOS uses Apple’s libm and the *.json baselines; Linux, WASM, or macOS with --features graphviz-pure-core/portable-math use the portable math library and the *.portable.json baselines.

To see the portable profile on a Mac:

Terminal window
cargo build --release -p graphviz-pure-diff --features graphviz-pure-core/portable-math --target-dir target/portable
target/portable/release/gv-diff e2e

The browser checks on this site run the same build as the npm package. To check it against the whole corpus in Node:

Terminal window
cargo build --release --target wasm32-unknown-unknown -p graphviz-pure-wasm
wasm-bindgen --target nodejs --out-dir /tmp/gvwasm/pkg \
target/wasm32-unknown-unknown/release/graphviz_pure_wasm.wasm
node scripts/wasm-e2e.mjs --pkg /tmp/gvwasm/pkg --hashes /tmp/wasm-hashes.json
cargo build --release -p graphviz-pure-diff && target/release/gv-diff e2e --hashes /tmp/native-hashes.json
cmp /tmp/native-hashes.json /tmp/wasm-hashes.json # on Linux: WASM and native agree on every file

wasm-bindgen-cli must match the wasm-bindgen version in Cargo.lock exactly; CI reads it from there.

The reference is Graphviz 16.1.0 with only three of its plugins loaded: core, dot layout and neato layout. With no Pango text-layout plugin available, C measures text with the built-in font metric tables in lib/common/textspan_lut.c, which is what the port does. A default Graphviz installation measures text with Pango and cairo, places labels differently, and matches neither build.

scripts/gen-golden.sh builds such a plugin directory from an installed Graphviz 16.1.0 (Homebrew’s by default) and points GVBINDIR at it:

Terminal window
mkdir -p ~/src/gv-ref/lutplugins
cp /opt/homebrew/lib/graphviz/libgvplugin_{core,dot_layout,neato_layout}.*dylib ~/src/gv-ref/lutplugins/
GVBINDIR=~/src/gv-ref/lutplugins dot -c # writes the plugin config
GVBINDIR=~/src/gv-ref/lutplugins dot -V # dot - graphviz version 16.1.0

Then compare one file yourself. Pass files as arguments, not on stdin, as every check does:

Terminal window
cargo build --release -p graphviz-pure-cli
GVBINDIR=~/src/gv-ref/lutplugins dot -Kneato -Tsvg graph.gv | grep -v '^<!-- Generated by ' > c.svg
target/release/graphviz-pure -Kneato -Tsvg graph.gv | grep -v '^<!-- Generated by ' > rust.svg
cmp c.svg rust.svg && echo identical

The grep drops the generator comment, the one line gv-diff ignores (normalize in crates/graphviz-pure-diff/src/e2e.rs). Regenerating the references takes the same setup: scripts/gen-golden.sh, scripts/gen-render-golden.sh and GVBINDIR=<plugin dir> gv-diff e2e --generate.

C’s output for some inputs is not stable: it depends on heap addresses, or C reads freed memory. gv-diff e2e --generate runs C twice and records those inputs as unstable; they are skipped, and listed on the Fidelity page.

Path What it holds Used by
tests/wild, tests/fixtures, tests/<engine>/, tests/render The inputs (.gv) of the nine corpora every check
tests/golden/e2e.json 64-bit FNV-1a hashes of C’s normalised -Tsvg, and the unstable list gv-diff e2e
tests/golden/e2e-baseline{,.portable}.json The files that match, per profile e2e ratchet
tests/golden/*.dot, tests/golden/<engine>/*.dot C’s -Tdot layouts layout check
tests/golden/*baseline{,.portable}.json Per-file element counts and errors, per profile layout ratchets
tests/golden/render/ C’s layouts (laid/) and its renderings in seven formats gv-diff render

The render goldens are moving into a compressed archive, tests/golden/render.tar.xz, which the harness unpacks before comparing; the baselines stay as JSON.

The site is built from the same files:

Terminal window
python3 -I scripts/site-data.py --measure # runs gv-diff e2e in both profiles -> site/src/data/fidelity.json
scripts/site-samples.sh # needs the C reference -> site/public/samples, samples.json
node scripts/site-issues.mjs # docs/issues/manifest.json -> What's left
node scripts/site-sync-docs.mjs # docs/porting/*.md -> Porting notes
scripts/site-wasm.sh # the WASM build for the live checks

Without --measure, site-data.py counts the committed baselines instead of re-running the check. The generated JSON is committed, so the site builds in CI without the C reference.