std.test
Tests and benchmarks: the assertions a test fails by (assertEq, assertTrue, assertThrows,
assertPanics and the others, fail), subtest, and the runners that lyric test (run,
TestCase) and lyric bench (runBenches, BenchCase) hand a package's tests and benchmarks
to. A test is a function marked @Test — no parameters, void, possibly throwing — in a
module of the package or under its tests/.
An assertion that does not hold panics with what it got against what was expected, each as
Debug writes it, and names the expression it got it from: xs.length() = 2, expected 3. The
actual value comes first. Two values too long to compare by eye get their first difference
named below: a text's first line that differs, else the first character.
Examples
Compiles; not run here
import std.test { assertEq, assertTrue };
@Test
fn aListGrows() {
let xs = List.of([1, 2]);
xs.push(3);
assertEq(xs.length(), 3);
assertTrue(xs.contains(3));
}
Types
lyric test hands it to run: its name — the module's path and the function's —, its body, why it is skipped, if it is, how many seconds it may take, and whether it runs beside the others that say so (@Test { skip = "…", timeout = 10, parallel = true }).lyric bench hands it to runBenches: its name — the module's path and the function's — and its body, handed a bench to measure through.Functions
pub fn run(cases: TestCase[]): int
Runs the tests one after another, each in a task of its own: a panic or an error that leaves a
test fails it, and the run goes on. Those marked parallel run after the others, all at once.
It writes a line for each test once it has ended — what the test printed comes before —, then
the count. A test that outlives its time ends the run as a failure. Returns the program's exit
code: 0 when no test failed, 1 when one did.
pub fn subtest(name: string, body: fn() -> void throws Error): void
Runs a part of the running test, reported under its own name — parent/name — and run in a
task of its own, so the test goes on after one fails: a table-driven test, a row each. A failed
subtest fails the test.
Panics
Fails the test when called from a parallel test, which has no subtests: it runs beside others, and a subtest is reported under the one test that runs.
pub fn assertThrows<E :: [Error]>(f: fn() -> void throws E, message: string = ""): E
Fails the test unless f throws, and returns what it threw — of the type f says it throws —,
for the test to look at.
pub fn assertPanics(f: fn() -> void throws Error, message: string = ""): PanicInfo
Fails the test unless f, run in a task of its own, panics; returns what the panic left.
pub fn assertEq<T :: [Equatable, Debug]>(
actual: T,
expected: T,
message: string = "",
@callerExpr(actual) written: string = ""
): void
Fails the test unless actual equals expected: xs.length() = 2, expected 3 — the
expression the call wrote for actual, where it is not the value itself —, then message,
then, for values too long to compare by eye, their first difference.
pub fn assertNotEq<T :: [Equatable, Debug]>(
actual: T,
unexpected: T,
message: string = "",
@callerExpr(actual) written: string = ""
): void
Fails the test where actual equals unexpected — the assertion for "it changed", where
assertEq says "it is".
pub fn assertTrue(
condition: bool,
message: string = "",
@callerExpr(condition) written: string = ""
): void
Fails the test unless condition holds.
pub fn assertFalse(
condition: bool,
message: string = "",
@callerExpr(condition) written: string = ""
): void
Fails the test where condition holds.
pub fn assertNull<T :: [Debug]>(
value: ?T,
message: string = "",
@callerExpr(value) written: string = ""
): void
Fails the test where value is present.
pub fn assertNotNull<T>(
value: ?T,
message: string = "",
@callerExpr(value) written: string = ""
): T
Fails the test where value is absent; returns the value otherwise, for the test to go on with.
pub fn assertClose(
actual: float,
expected: float,
tolerance: float,
message: string = "",
@callerExpr(actual) written: string = ""
): void
Fails the test unless actual lies within tolerance of expected — the comparison
assertEq cannot make for floating point, where 0.1 + 0.2 is not 0.3. NaN on either side
fails: it is close to nothing.
pub fn assertLess<T :: [Ordered, Debug]>(
actual: T,
bound: T,
message: string = "",
@callerExpr(actual) written: string = ""
): void
Fails the test unless actual is less than bound.
pub fn assertGreater<T :: [Ordered, Debug]>(
actual: T,
bound: T,
message: string = "",
@callerExpr(actual) written: string = ""
): void
Fails the test unless actual is greater than bound.
pub fn assertContains<T :: [Debug], C :: [Contains<T>, Debug]>(
container: C,
x: T,
message: string = "",
@callerExpr(container) written: string = ""
): void
Fails the test unless container holds x — what x in container asks (Contains):
assertContains("abc", 'b'), assertContains(xs, 3).
pub fn assertEmpty<C :: [Iterable, Debug]>(
c: C,
message: string = "",
@callerExpr(c) written: string = ""
): void throws C.Iter.Error
Fails the test unless c holds nothing: its iterator gives no value — a list, a map, a set, an
array, a slice.
Errors
Throws what the iterator of c throws — nothing, for the collections above.
pub fn fail(message: string): never
Fails the test outright, with message — for a branch a test must not reach.
pub fn runBenches(cases: BenchCase[], save: string = "", compare: string = ""): int
Runs the benchmarks one after another on this thread, each with a bench of its own, and writes
a line for each: the nanoseconds per run, its allocations and their bytes, the megabytes per
second where the bench said how many bytes a run handles, and the runs measured. Where compare
names a file an earlier run saved, each line also says how the time per run changed against
it; where save names one, this run writes it — a line per benchmark: its name, then the
nanoseconds, the allocations and the bytes per run, separated by tabs. Returns the program's
exit code: 0, or 1 where such a file could not be read or written.