Testing & verification¶
faultflow has two test suites — Catch2 for the C++ core and pytest for the Python layer — organized by subsystem, plus an optional iverilog gate that checks generated vectors against independently-simulated golden outputs. The methodology is test-first: behavior is specified by a failing test before it’s implemented, and every simulation result is cross-checked against a scalar reference simulator.
The golden-reference cross-check¶
The golden reference (GoldenRefSim, src/core/sim/golden_ref/) is a scalar
simulator: one fault at a time, plain maps, no batching, no bit-tricks — built to
be obviously correct rather than fast. It is the ground truth the 64-lane
bit-parallel engine is measured against.
flowchart LR
A[test vector + fault] --> B["GoldenRefSim<br/>scalar, one fault at a time"]
A --> C["Bit-parallel engine<br/>64-lane, batched"]
B --> D{results match?}
C --> D
D -- yes --> E([test passes])
D -- no --> F([bit-parallel engine has a bug])
If the two ever disagree, the bit-parallel engine is considered wrong — never the golden reference. This is a hard rule, not a guideline: a mismatch is a bug to fix, not a golden file to update. The same golden reference also re-verifies every SAT-ATPG-generated vector before it is trusted and written to the campaign database.
Test organization¶
C++ (Catch2) — tests/cpp/¶
Directory |
Covers |
|---|---|
|
ParsedGraph, NormalizedGraph, CompiledSimGraph, WBR cell lowering |
|
Enumeration, collapsing, batch manager, fault-effect polymorphism |
|
Gate evaluation (30+ gate types), golden reference, bit-parallel engine, fault injection, sequential FF, WBR modes |
|
Miter construction, CNF truth tables, compaction, cone ordering/equivalence, incremental-SAT, SAT timeout, transition + scan-transition + scan-LOS |
|
Scan chain extraction, multi-clock stagger, scan sequences |
|
SQLite campaign store — schema, fingerprinting, resume validation |
|
Performance benchmarks ( |
Style: every test follows GIVEN / WHEN / THEN, runs in under a second, and uses small hand-authored Yosys-JSON fixtures rather than external tools.
Python (pytest) — tests/python/¶
Directory |
Covers |
|---|---|
|
Shell and CLI command parsing, subcommand flow, config loading |
|
Vector application, fault batching, observable-set tracking, cycle-based sequential simulation |
|
Progressive ATPG, transition-fault queries, compaction, timeout/unknown handling, redundancy persistence |
|
Scan-chain insertion and protocol, INTEST/EXTEST fusion, scan ATPG |
|
IEEE 1500 wrapper boundary cells — modes, tri-state control, port observation |
|
Hierarchical block-to-SoC aggregation, owning-role rules, SoC retargeting |
(root level) |
|
tests/unit/ is reserved for future use and currently empty.
Markers¶
Registered in tests/python/conftest.py:
Marker |
Meaning |
|---|---|
|
Fast, no external tools |
|
Requires the |
|
Requires external tools (Yosys, iverilog, Quaigh, …) |
|
Benchmark circuits or long-running operations (>30s) |
|
Vector-verification-gate tests (iverilog) |
|
Sequential-circuit feature tests |
Coverage targets¶
The project’s internal TDD contract records per-module coverage targets — these are documented goals to keep critical paths well-tested, not (today) an automated CI gate: there is no committed coverage-threshold config, and the CI job below runs the test suites without failing the build on a numeric coverage shortfall.
Scope |
Target |
|---|---|
Global |
85% |
|
99% |
|
95% |
|
90% |
|
90% |
|
85% |
|
80% |
|
75% |
How to run the tests¶
All commands run in WSL (see the WSL-only note — there is no native Windows build). Build the C++ extension first; every test suite needs it:
cmake -S . -B build -G Ninja
cmake --build build -- -j4
Python:
pytest tests/python/ -v # everything
pytest tests/python/ -m 'not slow' -v # skip slow benchmarks
pytest tests/python/scan/ -v # one subsystem
pytest tests/python/ -k 'collapsing' -v # by name pattern
pytest tests/python/ --cov=faultflow --cov-report=html
C++:
ctest --test-dir build --output-on-failure -j4
ctest --test-dir build -R 'SimEngine' --output-on-failure # one suite
Lint and type-check (required before a PR):
black . && flake8 . && mypy .
The iverilog verification gate¶
Separate from the golden-reference cross-check, faultflow/verify/gate.py is an
independent, external correctness check: it compiles the Yosys
write_verilog gate-level netlist together with the PDK’s behavioral Verilog
models and a generated testbench, then simulates the faultflow-generated vectors
through Icarus Verilog and compares the results against faultflow’s own golden
outputs. It is off by default ([simulation] verify = false) since it needs
iverilog on PATH; enable it with -v true (CLI) or [simulation] verify = true (config) when you want that extra, tool-independent confirmation. See
External tools.
Continuous integration¶
CI is a single GitHub Actions job (.github/workflows/nix.yml, flake-check)
that runs nix flake check on every push and pull request:
flowchart TD
A[push / pull request] --> B["nix flake check<br/>hermetic Nix sandbox"]
B --> C[build faultflow-core + pinned CaDiCaL 1.7.4]
C --> D[regenerate ISCAS benchmark netlists via Yosys]
D --> E["Catch2: ctest (201/201)"]
D --> F["pytest: tests/python/"]
E --> G{both green?}
F --> G
G -- yes --> H([check passes])
G -- no --> I([blocked])
Both suites run fully hermetically inside the Nix sandbox — no manual
checkout step, no local nix develop shell required, and no external network
access. The ISCAS benchmark netlists the checks need are regenerated from the
tracked RTL sources via a Yosys preCheck/checkPhase step rather than being
committed. First runs are slow (roughly 15–30 minutes, since faultflow-core
and the pinned CaDiCaL 1.7.4 compile from source); a binary cache (e.g. Cachix)
speeds up repeat runs — see
Building with Nix.
The documentation site has its own, separate CI path
(.github/workflows/docs.yml) that builds and deploys docs/ — see
Contributing.