Prints a line to the test's output, which jacket test shows when the test fails.
This one is only checked to compile, not run.
#import "Extensions/Testing";
A test framework. A test is a procedure with a @test note, found at compile time and run by
jacket test. The expect* checks report a failure and let the test go on; the require*
ones report it and return from the test. assert_that checks a value against a matcher,
@cases and @property run a test over a list or over generated inputs, and
expect_snapshot compares output with a stored file.
#import "Extensions/Testing";
parses_numbers :: (t: *Test) {
value, ok := string_to_int("42");
require(ok);
expect_equal(value, 42);
} @testThis one is only checked to compile, not run.
A test runs with a context allocator that fails it on a leak or a bad free, and with temporary storage reset first.
Prints a line to the test's output, which jacket test shows when the test fails.
This one is only checked to compile, not run.
Ends the test as skipped, from the procedure it is written in.
This one is only checked to compile, not run.
Marks the test as failed and lets it go on.
fail(t, "this never worked");This one is meant to fail, so there is nothing to run.
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.
#import "File";
writes_a_file :: (t: *Test) {
path := tprint("%/out.txt", temp_dir(t));
expect(write_entire_file(path, "hi"));
} @testThis one is only checked to compile, not run.
Calls callback(data) when the test ends, after its body; the last registered runs first.
uses_a_buffer :: (t: *Test) {
buffer := alloc(1024);
cleanup(t, (data: *void) { free(data); }, buffer);
} @test↗This one is only checked to compile, not run.
Runs body as the subtest name, reported and filtered as test/name. Returns whether it
passed.
passed := run(t, "addition", (t: *Test) {
expect_equal(1 + 1, 2);
});
assert(passed);Checks condition, reports a failure at the caller's line and returns whether it held. The
other expect* checks work the same way; jacket test shows the line's source next to the
message.
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_equal(2 + 2, 4);
expect_equal("abc", "abc");
expect_equal(s32.[1, 2, 3], s32.[1, 2, 3]);
expect_equal(2 + 2, 4, "cut point 3"); // on failure, the message leads the difference|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.
Checks that pointer is null.
p: *int;
expect_null(p);Checks that pointer is not null.
x := 1;
expect_not_null(*x);The require forms check the same way and, when the check fails, return from the procedure
they are written in (which must return nothing). Use them when the rest of the test needs the
check to hold. In a helper that returns a value, use the expect form instead.
items: [..] int;
array_add(*items, 1);
require(items.count == 1);
expect_equal(items[0], 1);expect_equal, then returns from the calling procedure on a failure.
require_equal(1 + 1, 2);↗expect_near, then returns from the calling procedure on a failure.
require_near(0.1 + 0.2, 0.3, 0.0001);↗expect_not_null, then returns from the calling procedure on a failure.
x := 1;
require_not_null(*x);↗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);
}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);↗The names run_cases gives the subtests of cases: the entry's values, without /, shortened,
repeats numbered. In temporary storage.
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.
assert_that, then returns from the procedure it is written in (which must return nothing)
when the check fails.
require_that("hello", has_length(5));↗The message assert_that would report, or an empty string when value matches.
assert(explain(5, is(5)) == "");
assert(explain(4, greater_than(5)) != "");↗Equal by value, as expect_equal compares; strings, arrays and structs fail with its diff.
assert_that("abc", is("abc"));↗Holds when matcher does not.
assert_that(5, not(is(6)));↗Every matcher holds.
assert_that(7, all_of(greater_than(5), less_than(10)));↗At least one matcher holds.
assert_that(7, any_of(is(1), is(7)));↗The value is greater than limit. Numbers of any width compare by value, strings byte by byte.
assert_that(6, greater_than(5));↗The value is at least limit.
assert_that(5, at_least(5));↗The value is less than limit.
assert_that(4, less_than(5));↗The value is at most limit.
assert_that(5, at_most(5));↗low <= value <= high.
assert_that(5, between(1, 10));↗|value - want| <= tolerance. NaN is never near anything.
assert_that(0.1 + 0.2, near(0.3, 0.0001));↗A string holds part as a substring; an array holds part as an element.
assert_that("hello world", contains("lo w"));
assert_that(s32.[1, 2, 3], contains(2));↗A string begins with prefix; an array begins with the elements of the array prefix.
assert_that("hello", starts_with("he"));↗A string ends with suffix; an array ends with the elements of the array suffix.
assert_that("hello", ends_with("llo"));↗A string or array with nothing in it.
assert_that("", is_empty());↗A string with count bytes or an array with count elements.
assert_that(s32.[1, 2, 3], has_length(3));↗An array with an element matcher holds for.
assert_that(s32.[1, 2, 3], has_item(greater_than(2)));↗An array whose every element matcher holds for (an empty array qualifies).
assert_that(s32.[1, 2, 3], each(greater_than(0)));↗A pointer that is null.
p: *int;
assert_that(p, is_null());↗A pointer that is not null.
x := 1;
assert_that(*x, not_null());↗A bool that is true.
assert_that(1 < 2, is_true());↗A bool that is false.
assert_that(2 < 1, is_false());↗The value's type is T exactly; for an Any, the type of what it holds.
value: Any = 5;
assert_that(value, of_type(s64));↗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");
} @testThis one is only checked to compile, not run.
value as the text a snapshot of it holds.
assert(snapshot_text("plain") == "plain");↗A generator started from seed.
a := rng_seeded(42);
b := rng_seeded(42);
assert(rng_u64(*a) == rng_u64(*b));↗The next 64 random bits.
rng := rng_seeded(1);
first := rng_u64(*rng);
assert(first != rng_u64(*rng));↗A number from 0 to count - 1; 0 when count is 0.
rng := rng_seeded(1);
assert(rng_below(*rng, 6) < 6);↗A number from low to high, both included.
rng := rng_seeded(1);
n := rng_range(*rng, -5, 5);
assert(n >= -5 && n <= 5);↗True once in one_in calls on average.
rng := rng_seeded(1);
assert(rng_chance(*rng, 1));↗A number from 0 up to, not including, 1.
rng := rng_seeded(1);
x := rng_unit(*rng);
assert(x >= 0 && x < 1);↗Wraps make as a Custom_Generator for run_property.
even :: (rng: *Rng) -> s64 { return rng_range(rng, -500, 500) * 2; }
run_property(t, (n: s64) { expect_equal(n % 2, 0); }, 20, .[generator(even)]);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_property(t, (divisor: s64) {
assume(divisor != 0);
expect_equal(10 / divisor * divisor + 10 % divisor, 10);
});What a @property test runs: body on count generated inputs. Call it by hand to give
the arguments custom generators or another count.
run_property(t, (a: s32, b: s32) {
expect_equal(cast(s64) a + b, cast(s64) b + a);
}, 50);Whether the test that is running is a @compile_time one, run by the compiler now.
assert(!at_compile_time());↗Runs cases without benchmarks.
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.
Returns value and hides it from the optimizer: the compiler cannot know the result, and
cannot drop the work that made it, so wrap what a bench computes and the inputs it must not
see through. It is an intrinsic that costs no instruction: an empty assembly block takes the
value and may change it (and any memory), see docs/language/intrinsics.md.
Each iteration handles count bytes, so the report shows a rate in bytes per second.
Each iteration handles count items (requests, elements), shown as items per second.
Starts the measured time and the count of allocations again, for a bench that sets up its input before the loop.
The test that is running. name is parent/child inside a subtest.
The benchmark that is running (bench.jai). A @bench procedure loops iterations times.
What a Matcher checks.
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. Use it with assert_that.
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.
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)One entry of the table run_tests takes: a test's name, procedure, source location and flags.
How a test is run.
@cases test: its body is run_casesOne @bench the Discovery plugin found.
@samples(N) and @min_time(MS); 0 means the default.Settings of a run from the command line (--samples, --warmup, --measure-ms); 0 keeps
what the bench or the defaults say.