test
The assertion matchers behind oxigen test. expect(value) wraps a value so
you can assert on it fluently.
<test>("addition works") {
expect(2 + 3).eq(5)
expect([1, 2, 3]).contains(2)
}You do not import this module. The test runner injects expect into every
*_test.oxi file automatically, so there is no introduce test in a test
file. (The module is importable if you want the matchers elsewhere:
introduce {expect} from test.)
For the test runner itself — file discovery, the CLI, output format — see testing.md.
| Matcher | Passes when |
|---|---|
.eq(expected) | actual == expected |
.ne(expected) | actual != expected |
.gt(bound) | actual > bound |
.gte(bound) | actual >= bound |
.lt(bound) | actual < bound |
.lte(bound) | actual <= bound |
.truthy() | actual is truthy |
.falsy() | actual is falsy |
.contains(item) | the collection contains item |
.is_error() | actual is an error value |
.is_value() | actual is an explicitly wrapped <Value> |
#expect(actual)
Wrap a value in an Expectation so a matcher can be
called on it.
expect(compute()).eq(42)A failing matcher calls <fail>, which produces an error and
short-circuits the rest of the test body — statements after the first
failure in a test do not run. Failure messages are returned plain; the
oxigen test runner colorizes them when the terminal supports it.
#Matchers
#.eq(expected)
expect(2 + 3).eq(5)Failure message: expected 5 but got 4.
#.ne(expected)
expect(roll()).ne(0)Failure message: expected value to differ from 0.
#.gt(bound)
expect(len(results)).gt(0)Failure message: expected 0 to be greater than 0.
#.gte(bound)
expect(score).gte(60)#.lt(bound)
expect(elapsed_ms).lt(1000)#.lte(bound)
expect(len(queue)).lte(10)#.truthy()
expect(user["active"]).truthy()Failure message: expected a truthy value but got False.
#.falsy()
expect(strings.is_empty(name)).falsy()#.contains(item)
Works on any collection the has builtin accepts — array, set, map (checks
keys), tuple. Not strings: expect("hello").contains("ell") fails with
has() requires a collection. Use .truthy() over
strings.contains for a
substring check.
expect([1, 2, 3]).contains(2)
expect({"a": 1}).contains("a")
expect((1, 2)).contains(2)
expect(strings.contains("hello", "ell")).truthy()Failure message: expected [1, 2, 3] to contain 9.
#.is_error()
Asserts the value is an error. Pair it with
<type<Error> || <Value>>(...) so the error is a value
rather than something that halts the test.
<test>("rejects a negative factorial") {
expect(<type<Error> || <Value>>(math.factorial(-1))).is_error()
}#.is_value()
Asserts the value is an explicitly wrapped <Value>. This is the is_value
builtin, not "is not an error" — expect(42).is_value() fails with
expected a value but got an error: 42.
expect(<Value>(42)).is_value() // passes
expect(<type<Error> || <Value>>(int("7"))).is_value() // passes
expect(42).is_value() // FAILSFor "this did not fail", assert on the value itself with .eq, or use
result.is_ok.
#Struct: Expectation
| Field | Type | Contents |
|---|---|---|
actual | generic | the value passed to expect |
expect(x) is exactly Expectation(actual=x). The matchers are ordinary
methods on this struct, implemented in pure Oxigen in stdlib/test.oxi — read
it if you want to know precisely what a matcher does.
#Worked example
// math_test.oxi
introduce math
fun add(a <int>, b <int>) { a + b }
<test>("addition") {
expect(add(2, 3)).eq(5)
expect(add(0, 0)).eq(0)
expect(add(2, 2)).gt(3)
}
<test>("factorial rejects negatives") {
expect(math.factorial(5)).eq(120)
expect(<type<Error> || <Value>>(math.factorial(-1))).is_error()
}$ oxigen test math_test.oxi
math_test.oxi
[ok] addition
[ok] factorial rejects negatives
test result: ok. 2 passed; 0 failedA failure names the test and the mismatch:
math_test.oxi
[fail] addition
expected 5 but got 4
test result: FAILED. 0 passed; 1 failedSee also: testing.md for the runner and conventions,
result for the Error || Value helpers.