Sigil Testing
First-Class Tests
Sigil tests are first-class language declarations, not a separate test framework. For the shared debugging workflow across inspect, run, test, replay, and stepping, see [DEBUGGING.md](/sigil/docs/debugging/).
Repo-level integration tests are ordinary Sigil test files under language/integrationTests/tests/. They run through the same sigil test machinery as project tests rather than through separate shell launchers.
Canonical Layout
- tests live under
tests/ testdeclarations outsidetests/are canonical errors- test files are ordinary
.sigilfiles - test files may include helpers alongside
testdeclarations
Application/library code should live under src/ and be referenced from tests with rooted module syntax.
Referencing Real Modules
Library code is file-based, not export-based:
λcompletedCount(todos:[µTodo])=>Int=todos reduce (λ(acc:Int,todo:µTodo)=>Int match todo.done{
true=>acc+1|
false=>acc
}) from 0
λmain()=>Unit=()
test "count completed todos" {
•todoDomain.completedCount([{done:true,id:1,text:"A"},{done:false,id:2,text:"B"}])=1
}
Test Syntax
λmain()=>Unit=()
test "adds numbers" {
1+1=2
}
Rules:
- test description is a string literal and may span lines
- test body must evaluate to
Bool truepassesfalsefails
In project code, named project types still live in src/types.lib.sigil and tests refer to them through µ....
Effectful tests use explicit effects:
λmain()=>Unit=()
test "writes log" =>!Log {
l _=(§io.println("x"):Unit);
true
}
Tests may also derive a local world:
λmain()=>Unit=()
test "worlds capture logs" =>!Log world {
c log=(†log.capture():†log.LogEntry)
} {
l _=(§io.println("captured"):Unit);
※check::log.contains("captured")
}
Multiline descriptions use the same string syntax:
λmain()=>Unit=()
test "multiline
test description works" {
§string.lines("alpha
beta")=["alpha","beta"]
}
Worlds, Observation, and Coverage
Sigil no longer treats tests as code plus ad hoc mocks.
Instead:
config/exports the baseline.lib.sigil world- each
testmay derive that world locally withworld { ... } †...builds world entries forClock,Fs,Http,Log,Process,Random,Tcp, andTimer※observe::...exposes raw traces from the active test world※check::...exposes Bool-returning helpers over those traces
Canonical split:
†is compiler-owned runtime world construction※observeis raw test-world inspection※checkis ergonomic Bool helpers for tests
Canonical note:
- if a world entry exists only as shared baseline behavior, keep it in
config/ instead of restating it in every test
Example:
λmain()=>Unit=()
test "captured log contains line" =>!Log world {
c log=(†log.capture():†log.LogEntry)
} {
l _=(§io.println("captured"):Unit);
※check::log.contains("captured")
}
sigil test also enforces project-surface coverage for project source modules:
- every project
src/*.lib.sigilfunction must be executed by the suite - sum-returning project functions must observe each relevant output variant
- missing surface coverage is reported as ordinary failing test results
- this coverage gate applies to suite-style runs such as
sigil testorsigil test path/to/tests/ - focused single-file runs such as
sigil test path/to/tests/file.sigilskip the project-wide coverage gate
Library tests may call •... exports directly. Executable tests exercise program behavior through main.
CLI
Default output mode is JSON. This section keeps the test-specific surface. For the broader debugging workflow and when to choose inspect, run, test, or debug, use [DEBUGGING.md](/sigil/docs/debugging/).
Examples:
# Run all tests in the current project tests/ directory
cargo run -q -p sigil-cli --manifest-path language/compiler/Cargo.toml -- test
# Run a specific file or subdirectory
cargo run -q -p sigil-cli --manifest-path language/compiler/Cargo.toml -- test projects/algorithms/tests/basicTesting.sigil
# Filter by test name substring
cargo run -q -p sigil-cli --manifest-path language/compiler/Cargo.toml -- test --match "cache"
# Trace one test file
cargo run -q -p sigil-cli --manifest-path language/compiler/Cargo.toml -- test --trace projects/algorithms/tests/basicTesting.sigil
# Stop the current test when a function is reached
cargo run -q -p sigil-cli --manifest-path language/compiler/Cargo.toml -- test --break-fn helper projects/algorithms/tests/basicTesting.sigil
# Record and replay a test run
cargo run -q -p sigil-cli --manifest-path language/compiler/Cargo.toml -- test --record .local/tests.replay.json projects/algorithms/tests/basicTesting.sigil
cargo run -q -p sigil-cli --manifest-path language/compiler/Cargo.toml -- test --replay .local/tests.replay.json projects/algorithms/tests/basicTesting.sigil
# Start a replay-backed stepping session for one exact test id
cargo run -q -p sigil-cli --manifest-path language/compiler/Cargo.toml -- debug test start --replay .local/tests.replay.json --test "projects/algorithms/tests/basicTesting.sigil::cache hit returns cached value" --watch result.value projects/algorithms/tests/basicTesting.sigil
cargo run -q -p sigil-cli --manifest-path language/compiler/Cargo.toml -- debug test step-into .local/debug/.json
For runtime-world projects, --env is required. sigil test --replay cannot be combined with --env; the replay artifact owns the resolved per-test world.
For process-heavy harness code, prefer:
§processfor child processes§file.makeTempDirfor scratch workspaces§time.sleepMsfor retry loops
JSON Output
test emits a single JSON object to stdout by default.
Top-level fields:
formatVersioncommandoksummaryresults
Each result currently includes:
idfilenamestatus
- pass | fail | error | stopped
durationMslocation- optional
failure - optional
trace - optional
breakpoints - optional
replay - optional
exception
summary now also includes:
stopped
Stop-mode breakpoint hits are not runtime errors:
- the current test result becomes
status: "stopped" - the suite keeps running later selected tests
- top-level
okis stillfalse
Replay-backed debug snapshots may also include:
watches
- ordered results for any configured --watch local(.field)* selectors
Current aggregated test output does not include:
declaredEffects- structured
assertionmetadata - raw per-test coverage traces
Formal references:
language/docs/DEBUGGING.mdlanguage/docs/TESTING_JSON_SCHEMA.mdlanguage/spec/cli-json.mdlanguage/spec/cli-json.schema.json