Modules

Testing

moduleSource
macOSLinuxWindowswasm

since 0.28.0

#import "Extensions/Testing";

Procedures#

General#

logsince 0.28.0
(t: *Test, format: string, args: ..Any)

Prints a line to the test's output, which jacket test shows when the test fails.

reports_progress :: (t: *Test) {
    log(t, "step % of %", 1, 3);
}
↗

This one is only checked to compile, not run.

skipsince 0.28.0
(t: *Test, reason := "")

Ends the test as skipped, from the procedure it is written in.

failsince 0.28.0
(t: *Test, message := "failed", loc := #caller_location)

Marks the test as failed and lets it go on.

temp_dirsince 0.28.0
(t: *Test, loc := #caller_location) -> string

A directory for this test's files. jacket test creates it and deletes it after a pass (--keep-temp keeps it); subtests share their test's directory.

cleanupsince 0.28.0
(t: *Test, callback: (data: *void), data: *void = null)

Calls callback(data) when the test ends, after its body; the last registered runs first.

run2 overloadssince 0.28.0
(t: *Test, name: string, body: (t: *Test)) -> bool

Runs body as the subtest name, reported and filtered as test/name. Returns whether it passed.

Checks#

expectsince 0.28.0
(condition: bool, message := "", loc := #caller_location) -> bool
expect(1 + 1 == 2);
expect_equalsince 0.28.0
(got: $T, want: $U, loc := #caller_location) -> bool

got and want are compared by value: numbers of any width, strings, enums, arrays element by element (fixed, view and resizable alike) and structs member by member. Strings and arrays that differ get a diff.

expect_nearsince 0.28.0
(got: float64, want: float64, tolerance: float64, loc := #caller_location) -> bool

|got - want| <= tolerance. NaN is never near anything.

expect_near(0.5, 0.25, 0.1);

This one is meant to fail, so there is nothing to run.

expect_nullsince 0.28.0
(pointer: *$T, loc := #caller_location) -> bool

Checks that pointer is null.

expect_not_nullsince 0.28.0
(pointer: *$T, loc := #caller_location) -> bool

Checks that pointer is not null.

requiresince 0.28.0
(condition: bool, message := "", loc := #caller_location)

The require forms check the same way and, when the check fails, return from the procedure they are written in (which must return nothing).

require_equalsince 0.28.0
(got: $T, want: $U, loc := #caller_location)

expect_equal, then returns from the calling procedure on a failure.

require_nearsince 0.28.0
(got: float64, want: float64, tolerance: float64, loc := #caller_location)

expect_near, then returns from the calling procedure on a failure.

require_not_nullsince 0.28.0
(pointer: *$T, loc := #caller_location)

expect_not_null, then returns from the calling procedure on a failure.

Cases#

run_casessince 0.30.0
(t: *Test, cases: [] $T, $body: $B) -> bool

Runs body once per entry of cases, each as the subtest test/<values>; returns whether every case passed. An entry is the argument of body, or, when body takes several, a struct whose members are its arguments in order. body may take a leading *Test. This is what a @test procedure with a @cases(LIST) note runs; call it by hand to build the list at run time or to run a helper per case:

Case :: struct { input: string; length: s64; }

checks_each_case :: (t: *Test) {
    lengths :: (input: string, length: s64) {
        expect_equal(input.count, length);
    }

    passed := run_cases(t, Case.[.{ "", 0 }, .{ "abc", 3 }], lengths);
    expect(passed);
}
all_valuessince 0.30.0
($T: Type) -> [] T

Every member of the enum T, in declaration order, as a list for @cases:

Color :: enum { RED; GREEN; BLUE; }

values := all_values(Color);

assert(values.count == 3);
assert(values[0] == .RED && values[2] == .BLUE);
↗
case_namessince 0.30.0
(cases: [] $T, body: $B) -> [] string

The names run_cases gives the subtests of cases: the entry's values, without /, shortened, repeats numbered. In temporary storage.

Matchers#

assert_thatsince 0.30.0
(value: $T, matcher: Matcher, loc := #caller_location) -> bool

Checks value against matcher; a failure is reported at the caller's line. Returns whether it held.

assert_that(4, greater_than(5));

This one is meant to fail, so there is nothing to run.

require_thatsince 0.30.0
(value: $T, matcher: Matcher, loc := #caller_location)

assert_that, then returns from the procedure it is written in (which must return nothing) when the check fails.

explainsince 0.30.0
(value: $T, matcher: Matcher) -> string

The message assert_that would report, or an empty string when value matches.

issince 0.30.0
(want: $T) -> Matcher

Equal by value, as expect_equal compares; strings, arrays and structs fail with its diff.

greater_thansince 0.30.0
(limit: $T) -> Matcher

Numbers of any width compare by value, strings byte by byte.

at_mostsince 0.30.0
(limit: $T) -> Matcher

The value is at most limit.

betweensince 0.30.0
(low: $T, high: $U) -> Matcher

low <= value <= high.

nearsince 0.30.0
(want: float64, tolerance: float64) -> Matcher

|value - want| <= tolerance. NaN is never near anything.

containssince 0.30.0
(part: $T) -> Matcher

A string holds part as a substring; an array holds part as an element.

starts_withsince 0.30.0
(prefix: $T) -> Matcher

A string begins with prefix; an array begins with the elements of the array prefix.

ends_withsince 0.30.0
(suffix: $T) -> Matcher

A string ends with suffix; an array ends with the elements of the array suffix.

has_lengthsince 0.30.0
(count: s64) -> Matcher

A string with count bytes or an array with count elements.

eachsince 0.30.0
(matcher: Matcher) -> Matcher

An array whose every element matcher holds for (an empty array qualifies).

of_typesince 0.30.0
($T: Type) -> Matcher

The value's type is T exactly; for an Any, the type of what it holds.

Snapshots#

expect_snapshot2 overloadssince 0.30.0
(t: *Test, value: Any, name := "", loc := #caller_location) -> bool

Compares the printed form of value with its stored snapshot. Strings are compared as they are; any other value is printed with one member or element to a line, so a change shows as a line diff. A test that takes several snapshots numbers them, or names them with name.

Point :: struct { x, y: s32; }

prints_a_point :: (t: *Test) {
    expect_snapshot(t, Point.{ 1, 2 });
    expect_snapshot(t, "a block of text\nwith two lines", "text");
} @test

This one is only checked to compile, not run.

snapshot_textsince 0.30.0
(value: Any) -> string

value as the text a snapshot of it holds.

Property#

rng_seededsince 0.30.0
(seed: u64) -> Rng

A generator started from seed.

rng_u64since 0.30.0
(rng: *Rng) -> u64

The next 64 random bits.

rng_belowsince 0.30.0
(rng: *Rng, count: u64) -> u64

A number from 0 to count - 1; 0 when count is 0.

rng_rangesince 0.30.0
(rng: *Rng, low: s64, high: s64) -> s64

A number from low to high, both included.

rng_chancesince 0.30.0
(rng: *Rng, one_in: s64) -> bool

True once in one_in calls on average.

rng_unitsince 0.30.0
(rng: *Rng) -> float64

A number from 0 up to, not including, 1.

assumesince 0.30.0
(condition: bool)

Checks the arguments of a property: skips the trial, without failing it, when condition does not hold. A property that returns a value writes if !condition return true;.

run_propertysince 0.30.0
(t: *Test, $body: $B, count: s64 = DEFAULT_TRIALS, generators: [] Custom_Generator = .[])

What a @property test runs: body on count generated inputs. Call it by hand to give the arguments custom generators or another count.

Compile time#

at_compile_timesince 0.30.0
() -> bool

Whether the test that is running is a @compile_time one, run by the compiler now.

Runner#

run_examplesince 0.28.0
(body: (t: *Test))

Runs body as a test that prints nothing of its own: a failed check prints its message, and the program exits with status 1. jacket test runs a doc comment's example with it.

Types#

Teststructsince 0.28.0
:: struct

The test that is running. name is parent/child inside a subtest.

Benchstructsince 0.28.0
:: struct

The benchmark that is running (bench.jai). A @bench procedure loops iterations times.

Matcherstructsince 0.30.0
:: struct

What a value should be. Build one with the procedures below; the operands live in temporary storage, so a matcher is for the test that makes it.

Rngstructsince 0.30.0
:: struct

A source of pseudo-random numbers (splitmix64). The same seed gives the same numbers on every OS and in every mode, which is what makes a failing run repeatable. Custom generators take one and draw from it.

Custom_Generatorstructsince 0.30.0
:: struct

A generator the property uses for every argument (or part of one) of the type it returns, in place of the built-in one. Named in a @generate(NAME) note; values it makes are not shrunk.

even :: (rng: *Rng) -> s64 { return rng_range(rng, -500, 500) * 2; }

doubles :: (n: s64) { expect_equal((n * 3) % 2, 0); } @test @property @generate(even)

Constants#