# tests Tests are declared in `project.cpp` via `cfg.AddTest(name)`. One line per test; deps and other options chain off the returned builder. ```sh cd examples/tests crafter-build test ``` Layout: ``` mylib/MyMath.cppm # the library being tested project.cpp # declares the library and its tests tests/Smoke/main.cpp # zero-config test tests/UnitMyMath/main.cpp # test that links MyMath ``` `project.cpp` does: ```cpp cfg.AddTest("Smoke"); // exit 0 = pass cfg.AddTest("UnitMyMath").Dependencies({ &cfg }); // imports MyMath ``` `AddTest(name)` defaults the source to `tests//main.cpp` (resolved at the project root) and the target/march/mtune to the parent project's. The builder methods overlay overrides: - `.Target(triple)` / `.March(...)` / `.Mtune(...)` / `.Sysroot(path)` - `.Define(name, value)` / `.Debug()` - `.Timeout(seconds)` - `.Args(vec)` — runtime args - `.Requires("tool:foo")` / `.Requires("file:/path")` / `.Requires("env:VAR")` - `.Dependencies({ &otherCfg, ... })` - `.Path(p)` — rebase the test's source-resolution path - `.LinkFlag(s)` / `.CompileFlag(s)` ## Test conventions - Exit code `0` = pass, anything nonzero = fail, **`77` = skipped** (autoconf convention). Use `std::exit(77)` for runtime skips like "tool not on PATH". - Each test runs in its own subprocess; a segfault doesn't take down the runner. - Default timeout is 60 s (`crafter-build test --timeout=N` overrides). - Filter by name: `crafter-build test 'Unit*'`. List without running: `crafter-build test --list`. ## Linking the parent project `UnitMyMath` depends on the library via `.Dependencies({ &cfg })` — the test imports `MyMath` and the build engine links `cfg`'s output into the test exe. ## Cross-target test runs `AddTest` inherits the parent project's target; for per-test cross-arch runs, override via the builder: ```cpp cfg.AddTest("CrossArchAarch64") .Target("aarch64-linux-gnu") .Sysroot("/opt/aarch64-rootfs") .Requires("tool:qemu-aarch64"); ``` `crafter-build test` sweeps every distinct target declared across the project's tests plus the host triple, so cross-arch tests run by default. `--target=` restricts the run to that target. `--runner=` overrides the per-target runner for one invocation. Useful specs: `local`, `cmd:` (e.g. `cmd:wine`, `cmd:qemu-aarch64`). Persistent override via env: `CRAFTER_BUILD_RUNNER_=`. ## SIMD march fan-out For libraries with per-march SIMD codegen (e.g. Crafter.Math), use `AddMarchVariants` to produce one Test per tier sharing the same source and interface set: ```cpp constexpr MarchTier tiers[] = { {"sapphirerapids", "native"}, {"x86-64-v4", "generic"}, {"x86-64-v3", "generic"}, }; cfg.AddMarchVariants("Vector", libInterfaces, tiers); ``` Each tier becomes a Test named `Vector-`, with the library's interfaces rebuilt under that tier's `-march`/`-mtune` (so codegen actually varies). Per-arch gating is just an `if (target.starts_with("x86_64"))` guard around the call — no special toml syntax.