OpenRemap Docs

Testing & CI

133 test modules, a synthetic golden corpus in the repository, and one very large corpus that is not — which is why the suite has to run in both worlds.

The suites

Directory Modules Covers
tests/tuning/ 85 the engine: extractors, maps, decoders, recipes, apply, parity
tests/cli/ 19 each command's surface and exit codes
tests/tui/ 15 each screen: keys, layout, messages, the file picker
tests/api/ 8 registry, dispatch, error codes, GIL release, transport
tests/checksum/ 1 scheme detection
tests/convert/ 1 HEX / S-Record normalising
tests/recipes/ 1 recipe documents
tests/corpus/ 1 the synthetic golden corpus

Run them with:

uv run pytest tests/ -q            # everything
uv run pytest tests/tui -q         # one area
uv run pytest tests/tuning/manufacturers/test_edc17_extractor.py -v

The corpora

Two committed kinds, and the distinction matters when you write a test.

Corpus Where What it is
Synthetic tests/corpus/ — committed generated by openremap synth: deterministic, no ECU data, safe to publish. It carries a manifest.json of what each file plants, so a test can assert against known truth
Fixture recipes _dev/contrib/ an 89-file mimic corpus the contribution wizard checks candidate markers against

Dump-based tests skip cleanly when no local dump corpus is present — the normal state in CI and on a fresh clone. That rule is enforced by a conftest helper; a test that reaches for a dump without the guard fails everywhere CI runs, and that has happened (it is how the guard became a rule).

Parity goldens

The 0.9.0 apply engine replaced a flag-driven implementation, and the replacement was accepted only after it produced byte-identical output on 47 real stock/tuned pairs. Those pairs are pinned in tests/tuning/parity_goldens.json, so the claim survives the deletion of the old code:

  • the golden file records what the old engine wrote;
  • the test replays the new ladder against the same inputs;
  • a difference is a failure, not a tolerance.

This is the pattern the project prefers over "trust the new code": record the old behaviour, delete the old code, keep the record.

Beyond parity, the tuning suite covers:

  • extractor tests — each family's can_handle() and extract() against its fixtures, including the negative case (a different family must not claim it);
  • doc-path guards — tests/test_doc_paths.py resolves backticked repository paths in the internal docs against the committed tree, so a spec cannot reference a file that does not exist;
  • GIL release — tests/api/test_gil_release.py asserts that a heavy native call does not hold the interpreter lock, as a property rather than a timing;
  • width-sensitive help — CLI help tests pin the terminal width, because a narrow renderer truncates long flag names and the assertion becomes a test of the CI runner's console.

Continuous integration

.github/workflows/ci.yml — two jobs:

Job Runs on What it runs
test ubuntu-latest, matrix Python 3.10, 3.11, 3.12, 3.13, 3.14 installs the Rust toolchain and uv, then uv run pytest tests/ -x
portability ${{ matrix.os }} — Windows and macOS the TUI and console tests

The portability job is advisory (continue-on-error) on purpose, and the reason is documented in the workflow: the suite was written on Linux, wheels were built for Windows and macOS, but the tests had never run there — so "the TUI works on Windows" was an assumption. Its first run caught two real defects (a drive-root path rewrite that mangled UNC paths, and a test that only passed because the corpus was present locally), plus the console-encoding bug that made redirected output crash on the first em dash. The flag is meant to come off once the job is green twice.

.github/workflows/release.yml — three stages:

Stage What it does
test the suite must pass before anything is built
build wheels for Linux (glibc), Linux (musl), macOS and Windows — one wheel each, thanks to abi3
publish uploads to PyPI

The musl build exists because a musllinux wheel published under a glibc tag is rejected on upload; the platform tags are part of the release, not an afterthought.

What the suite does not test

  • Real flashing. Nothing here writes to a vehicle, so no test can.
  • Checksum correction. There is no code to correct a checksum, so there is nothing to test — the guarantee is the absence of a function, not a test.
  • Bit-exact behaviour of third-party decoders. capstone and the oracles are trusted as they are; what is tested is the cascade around them.