The test-suite map and the few rules that keep it trustworthy. Everything runs
under plain cargo test — no display, GPU, or root — and CI runs exactly that.
- Unit tests —
#[cfg(test)]modules acrosssrc/(canvas math, config parsing, membership, persistence change detection, …). Pure logic; smithay glue (handlers, delegates) is deliberately untested — see caveats.md. - Integration tests —
tests/*.rs, linking the lib crate: config parse/docs-sync gates, canvas transforms, snap, window-rule matching. - Stage proptest harness —
src/stage/tests.rs(mod harness): random op-histories (map/close/crash/fullscreen/pin/fit/cluster/hotplug/auto-place) drive the realStagealongside a model ofDriftWmpolicy, with structural invariants checked after every op. This layer found the suspended-pin output-unplug bug. - Config robustness proptests —
tests/config_robustness_test.rs: arbitrary and hostile TOML throughConfig::from_toml_collectmust never panic — the mechanical form of the hot-reload "a bad edit never crashes" promise. - In-process conformance fixture —
src/tests/(bin-crate unit tests): a realDriftWmruns headless (backend = None), real wayland-client test clients connect over socketpairs, and oneFixture::dispatch()pumps the whole graph deterministically.verify_stage_invariantsruns on every dispatch, so a state leak aborts the test and an in-process deadlock becomes a hang you can't miss. Covers the layer nothing else reaches: protocol wiring, configure sequences as the client sees them, crash paths, focus timing. Start reading atsrc/tests/window_opening.rs— the idiom is map → roundtrip → snapshot/assert, and new scenarios should read as specification sentences. Every scenario is also leak-checked at teardown: the fixture'sDroptears down all clients and assertsdebug-countersreturn to the construction-time baseline (opt out withskip_baseline_check).
Config options end in the reference, and the generated doc is committed.
config.reference.toml is the single source of truth for every option
(grammar: reference-config-format.md). Adding or
changing an option means documenting it there, regenerating with
UPDATE_CONFIG_DOCS=1 cargo test docs_config_md_is_up_to_date, and committing
both files. Never hand-edit docs/config.md. Tests gate the loop: reference
examples must parse warning-free, reference defaults must equal code defaults,
and the generated doc must be current.
Never touch Space window APIs — go through the stage. clippy.toml
rejects every Space element read and write via disallowed-methods; the
stage is the sole window store and Space is output-registry only. Applies to
tests too: drive DriftWm methods or the fixture. Details in
caveats.md.
Proptests run 256 cases in CI; go deeper before merging. Plain
cargo test uses proptest's default 256 cases per property. Work that touches
the stage, layout, or config parsing deserves a deeper local pass:
PROPTEST_CASES=4000 cargo test (seconds, not minutes). When proptest finds a
counterexample it writes a seed under proptest-regressions/ — commit it;
seeds replay first on every subsequent run, pinning the bug forever.
Non-hermetic tests are #[ignore]d, not env-gated. The default
cargo test lane stays hermetic and deterministic; anything that steps
outside it carries #[ignore = "reason"] and runs via
cargo test -- --include-ignored (or -- --ignored for just those). CI runs
the full include-ignored lane. Two exist today: the soak/leak scenario
(src/tests/soak.rs) churns hundreds of windows and asserts counters, file
descriptors, and RSS all plateau — the fd/RSS assertions are process-wide, so
prefer running it alone (cargo test --bin driftwm soak -- --ignored) when
debugging a failure; and the real-client scenario
(src/tests/real_clients.rs) spawns an actual foot/weston-terminal
against a private wayland + IPC socket and drives it over the wire,
self-skipping when neither is on PATH. Mark any future non-hermetic or
genuinely slow test the same way.
Fixture tests never touch the real session. Construct configs with
Config::from_toml + Fixture::with_config — never read
~/.config/driftwm/config.toml (that's what DriftWm::new_with_config is
for). Never read or write $XDG_RUNTIME_DIR/driftwm; the test pump
deliberately excludes the state-file writer. Don't set process env vars in
tests — the harness is multi-threaded.