Testing

Before you open a merge request, your change must be tested — by the unit tests where they apply, by hand across the axes below, and it must pass CI. This chapter covers all three.

Unit tests

Siril's unit tests live in src/tests/ and use the Criterion framework. They are built only when Criterion is available, so you enable them explicitly at configure time:

meson setup _build -Dcriterion=true
ninja -C _build
meson test -C _build -v --no-suite perfs

Each test is a small executable registered with test() in src/tests/meson.build (for example sorting, stacking_blocks_test, siril_date_test, siril_world_cs_test, and the arithmetic suite imoper_test / soper_test). They link siril_dep, so they exercise the real core code. The perfs suite is a set of performance benchmarks excluded in CI with --no-suite perfs — run it locally when you care about timing, skip it otherwise.

If you add a testable piece of core logic, add a Criterion test next to the others and register it in src/tests/meson.build (put it in a named suite if it belongs to a family). src/tests/ also holds diagnostic harnesses written during the GTK4 port audits — small programs that reproduce a specific GUI or processing scenario; use them as templates when a bug needs a dedicated reproducer.

Headless testing with siril-cli

Most features are quickest to test through a script run headless:

siril-cli -s myscript.ssf     # run a Siril script file
printf 'requires 1.0.0\n' | siril-cli -s -   # read the script from stdin

siril-cli links no GTK, so a script that exercises your command is also a smoke test that your code does not reach into the GUI (see The separation rules). A reproducible test script that loads a known input, runs your command and saves the output is the best regression artifact you can attach to a ticket.

The feature test checklist

As noted in Writing a feature, a feature must work across several axes. Test every applicable combination:

  • By command and through the GUI — both front-ends drive the same worker, but the wiring differs (idle dispatch, undo, preview).

  • Mono and colourfit->naxes[2] is 1 or 3; a loop that assumes three channels will crash on mono, and vice-versa.

  • 16-bit and 32-bitDATA_USHORT vs DATA_FLOAT; honour com.pref.force_16bit (see Process a single image).

  • Single image and sequence — the sequence path adds filtering, parallelism and output plumbing (see generic_sequence_worker).

  • Cancellation — a long operation must stop promptly when cancelled (Threading).

The continuous integration matrix

CI is defined in .gitlab-ci.yml and enumerated in Continuous integration jobs. Two jobs are your first line of defence against the invariants this documentation stresses:

  • siril-headless-build (-Dgtk=false) — fails to link if any core code calls the GUI directly, and runs the unit tests with coverage.

  • siril-lint-gtk-includes — runs scripts/lint-gtk-includes.sh to catch GTK / src/gui-gtk4 includes that leaked outside src/gui-gtk4.

Before pushing, reproduce these locally: a headless build (meson setup _build -Dgtk=false && ninja -C _build) and the test run above.