Assertions Reference¶
The assert object and all combinator factories are exported from 'utest'. Import each symbol by name:
import { assert } from 'utest'; // assertion methods
import { contains, truthy, falsy, any } from 'utest'; // combinator factories
// All factories are imported the same way — see the full list below.
All assertions call die() on failure. They do not return a value. A passing assertion is silent.
assert.match(expected, actual, msg)¶
| Parameter | Type | Description |
|---|---|---|
expected |
any | A combinator, a plain value, or a nested structure mixing both. |
actual |
any | Value under test. |
msg |
string | null | Optional failure message overriding the combinator's own message. |
Structural matching assertion. Recursively compares actual against expected:
- Combinators (values returned by the factories below) — delegates to the combinator's own
matchlogic. - Plain objects — compared key-for-key with exact key count (no extra keys allowed). Values may themselves be combinators.
- Plain arrays — compared element-by-element in order with exact length. Elements may be combinators.
- Scalars — compared with deep equality.
import { assert, contains, any_order, any, regex, equals } from 'utest';
// Plain value — deep equality check
assert.match('ok', status);
// Partial object — only listed keys are checked
assert.match(contains({ code: 200 }), response);
// Nested combinators
assert.match(contains({
code: 200,
body: contains({ status: 'ok' })
}), response);
// Array with flexible matching
assert.match(any_order([
contains({ id: 1 }),
contains({ id: 2 })
]), items);
assert.throws(fn, pattern, msg)¶
| Parameter | Type | Description |
|---|---|---|
fn |
function | Function expected to throw. |
pattern |
regexp | null | When provided, the stringified exception must match this pattern. |
msg |
string | null | Optional failure message. |
Fails when fn completes without throwing. When pattern is given, also fails when the thrown exception's string representation does not match it. The string representation is sprintf('%s', e): for die("msg") calls that is the message string directly; for runtime interpreter exceptions (null dereference, type errors, etc.) it is the interpreter error message text — for example, a null dereference produces "left-hand side expression is null".
Failure message format — no exception thrown:
<msg or "Expected exception but none was thrown">
Failure message format — exception does not match pattern:
<msg or "Exception '<e>' did not match pattern <pattern>">
assert.throws(() => { die("boom"); });
assert.throws(() => { null.x; }, /null/);
assert.throws(() => load_config("missing.uc"), /not found/, "missing config must throw");
assert.fail(msg)¶
| Parameter | Type | Description |
|---|---|---|
msg |
string | null | The failure message. Defaults to "assert.fail() called". |
Unconditionally raises an assertion failure. Reports as FAIL (like a failed assert.match, not an ERROR), so it is caught by an enclosing assert.throws with a matching pattern. Use it for an unreachable branch or a precondition that has no natural match form.
if (state !== 'ready')
assert.fail("expected ready, got " + state);
Combinator factories¶
Combinators are composable predicates used with assert.match. Import them from 'utest':
import { equals, contains, truthy, falsy, not, pred, regex, any, any_order,
starts_with, ends_with, has_length, between, is_type } from 'utest';
Each factory returns a combinator object. Combinators can be nested inside each other and inside the plain-value expected argument of assert.match.
equals(expected)¶
Passes when actual is deeply equal to expected.
assert.match(equals(42), result);
assert.match(any_order([equals('a'), equals('b')]), tags);
A plain scalar passed directly to assert.match performs an identical check.
contains(expected)¶
A partial-match combinator with three modes:
- String
actual: passes whenexpectedis a substring ofactual. - Array
actual: passes whenexpected(an array) is an ordered subsequence ofactual. Elements ofexpectedmay themselves be combinators. - Object
actual: passes whenactualcontains at least all the keys inexpected, with matching values. Extra keys inactualare ignored. Values inexpectedmay be combinators.
assert.match(contains("ERROR"), log_line);
assert.match(contains([1, 3]), [1, 2, 3]);
assert.match(contains({ code: 200 }), response);
assert.match(contains({ name: contains('Alice') }), user);
truthy()¶
Passes when actual is truthy (true, non-zero number, non-empty string, object, etc.).
assert.match(truthy(), is_connected);
assert.match(truthy(), items);
falsy()¶
Passes when actual is falsy (false, null, 0, "", or undefined).
assert.match(falsy(), error_flag);
assert.match(falsy(), m_fs.readfile('/absent'));
not(combinator)¶
Inverts a combinator — passes when combinator would fail.
assert.match(not(equals(4)), 5);
assert.match(not(regex(/^\d+/)), 'hello');
assert.match(not(contains({ code: 200 })), { code: 404 });
pred(fn)¶
Passes when the predicate function fn(actual) returns a truthy value.
assert.match(pred(x => x % 2 == 0), 4);
assert.match(contains([pred(x => x > 2)]), [1, 2, 3]);
When the predicate fails, the msg argument of assert.match is used as the failure message if provided; otherwise the default is "Predicate failed for <value>".
assert.match(pred(x => x % 2 == 0), 3, 'expected even');
// → fails with: expected even
regex(re)¶
Passes when actual is a string that matches the regular expression re.
assert.match(regex(/^\d+\.\d+/), version);
assert.match(contains({ message: regex(/connected/) }), log);
any_order(expected)¶
Passes when actual is an array of the same length as expected whose elements match the elements of expected in any order.
Elements of expected may be plain values (compared with equals) or combinators. The matcher backtracks: a wildcard (any()) will not permanently block a later specific matcher from claiming its element.
assert.match(any_order([1, 2, 3]), [3, 1, 2]);
assert.match(any_order([
contains({ type: 'connect' }),
contains({ type: 'auth' })
]), events);
any()¶
Always passes, regardless of what actual is. Commonly used as a wildcard position inside composite patterns.
assert.match(contains({ id: any(), name: 'Alice' }), record);
assert.match(any_order([any(), 1]), [1, 2]);
starts_with(expected)¶
- String
actual: passes whenactualstarts with the stringexpected. - Array
actual: passes whenactualhas at least as many elements asexpectedand its leading elements matchexpectedelement-by-element. Elements ofexpectedmay be plain values (compared withequals) or combinators. The length ofactualbeyondexpectedis unconstrained; use a plain array orequalsif you also need to fix the total length.
assert.match(starts_with('OpenWrt'), 'OpenWrt 24.10');
assert.match(starts_with([1, 2]), [1, 2, 3, 4]);
assert.match(starts_with([any(), 2]), [99, 2, 3]);
ends_with(expected)¶
- String
actual: passes whenactualends with the stringexpected. - Array
actual: passes whenactualhas at least as many elements asexpectedand its trailing elements matchexpectedelement-by-element. Elements ofexpectedmay be plain values (compared withequals) or combinators. The length ofactualbeyondexpectedis unconstrained; use a plain array orequalsif you also need to fix the total length.
assert.match(ends_with('24.10'), 'OpenWrt 24.10');
assert.match(ends_with([3, 4]), [1, 2, 3, 4]);
assert.match(ends_with([any(), 4]), [1, 2, 3, 4]);
has_length(n)¶
Passes when actual is a string, array, or object whose length equals n.
assert.match(has_length(3), [1, 2, 3]);
assert.match(has_length(5), 'hello');
assert.match(contains({ items: has_length(0) }), response);
between(min, max)¶
Passes when actual is a number in the range [min, max] (inclusive).
assert.match(between(0, 100), signal_strength);
assert.match(contains({ port: between(1024, 65535) }), config);
is_type(t)¶
Passes when type(actual) == t. The type string must match ucode's type() return values: 'int', 'double', 'string', 'bool', 'array', 'object', 'function'. type(null) returns null (not a string), so is_type cannot match null; use equals(null) instead.
assert.match(is_type('int'), result);
assert.match(is_type('string'), hostname);
assert.match(contains({ timeout: is_type('int') }), config);
Utility¶
is_combinator(v)¶
Returns true when v is a combinator object (a value produced by one of the factories above), false otherwise. Exported from 'utest'. Useful when building your own matcher that must decide whether a supplied expected value is a combinator or a plain value.
import { is_combinator, equals } from 'utest';
is_combinator(equals(1)); // true
is_combinator(1); // false