Tests

Module tests

import tests

What a test is, before anything runs it.

A test is a function carrying Test that returns a prelude.Result. Nothing else is required: there is no registry and no base type, so the runner reaches for reflect and finds tests by reading a module rather than by being told about them.

The other attributes adjust what happens to one. Skip keeps it out of the run, Todo marks it as expected to be unfinished, Only narrows the run to itself, and Comment attaches a note that reporters print.

This module is only the vocabulary. tests.assert writes the assertions, tests.runner finds and runs them, and tests.tap reports what happened.

Where tests live

zirric test runs every module of the project whose name ends in _t. Both shapes count: a foo/_t/foo_t.zirr submodule beside the code it tests, and a sibling module named foo_t. Nothing has to be registered — the name is the whole convention, and a project has a working zirric test before it has written anything about testing. A Cavefile that declares a test task takes over from the built-in entirely.

mod example.strings._t

import tests { Test, Skip, Comment }
import tests.assert
import strings

@Test()
fn testJoinsWithSeparator() {
	assert.equal("a,b", strings.join(["a", "b"], ","))
}

@Test()
fn testReportsEveryFailedCheck() {
	assert.all([
		assert.equal(0, len("")),
		assert.isTrue(strings.hasPrefix("abc", "a")),
	])
}

@Skip()
@Comment("waiting on the parser")
fn testNotYet() {
	assert.fail("unreachable")
}

A test takes no arguments and returns a prelude.Result — which the assertions above already are, so returning one is the whole body. zirric test exits non-zero when any of them is an Err.

Contents


Unions

TestCaseDetails

`tests/types.zirr:47`
union TestCaseDetails {
	None
	TestCaseDetailsSkip
	TestCaseDetailsTodo
	TestCaseDetailsOnly
}

What Skip, Todo or Only was written on a test, or None when none of them was.

Each member says how to be read as an Option, the way prelude’s own Result members do: a union’s attributes are not read off a value of one of its members.

Cases

Case Interpretation
None The absent value.
TestCaseDetailsSkip The test carries Skip.
TestCaseDetailsTodo The test carries Todo.
TestCaseDetailsOnly The test carries Only.

TestEvent

`tests/types.zirr:63`
union TestEvent {
	Discovered
	Skipped
	Started
	Finished
	Completed
}

What a run emits as it proceeds, in the order a reporter sees it.

Cases

Case Interpretation
Discovered Emitted once, before anything runs, with every case the run will cover.
Skipped A case that will not run.
Started A case that is about to run.
Finished A case that has run, with what it returned.
Completed Emitted once, after everything has run.

Data

Completed

`tests/types.zirr:87`
data Completed {
	report: TestReport
}

Emitted once, after everything has run.

Fields

Field Description
report What the run amounted to.

Discovered

`tests/types.zirr:65`
data Discovered {
	cases: [TestCase]
}

Emitted once, before anything runs, with every case the run will cover.

Fields

Field Description
cases Every case the run will cover, skipped ones included.

FailureRecord

`tests/types.zirr:106`
data FailureRecord {
	test: TestCase
	error: Err
}

A failed case together with the error it returned.

Fields

Field Description
test The case that failed.
error The Err it returned, whose reason says what went wrong.

Finished

`tests/types.zirr:80`
data Finished {
	test: TestCase
	outcome: Result
}

A case that has run, with what it returned.

Fields

Field Description
test The case that ran.
outcome What it returned: an Ok, or an Err whose reason says what went wrong.

Skipped

`tests/types.zirr:70`
data Skipped {
	test: TestCase
}

A case that will not run.

Fields

Field Description
test The case being skipped.

Started

`tests/types.zirr:75`
data Started {
	test: TestCase
}

A case that is about to run.

Fields

Field Description
test The case about to run.

TestCase

`tests/types.zirr:23`
data TestCase {
	name: String
	impl: fn() -> Result
	skipped: Bool
	comment: String
	details: TestCaseDetails
}

One test, as the runner will execute it.

Fields

Field Description
name The fully qualified name, which is the module’s name and the function’s joined with a dot.
impl The test function itself.
skipped Whether the runner will report it without running it.
comment The Comment written on it, or the empty String when none was.
details What Skip, Todo or Only was written on it, if any.

TestCaseDetailsOnly

`tests/types.zirr:59`
data TestCaseDetailsOnly

The test carries Only.


TestCaseDetailsSkip

`tests/types.zirr:53`
data TestCaseDetailsSkip

The test carries Skip.


TestCaseDetailsTodo

`tests/types.zirr:56`
data TestCaseDetailsTodo

The test carries Todo.


TestReport

`tests/types.zirr:94`
data TestReport {
	pass: [TestCase]
	fail: [FailureRecord]
	skip: [TestCase]
	todo: [TestCase]
}

What a run amounted to. A case appears in exactly one of the four.

Fields

Field Description
pass The cases that returned an Ok.
fail The cases that returned an Err, with the error each returned.
skip The cases that carried Skip and so were not run.
todo The cases that carried Todo, whatever they returned.

Attributes

Comment

`tests/types.zirr:17`
attr Comment {
	text: String
}

Attaches a note to a test that reporters print alongside it.

Fields

Field Description
text The note to print.

Only

`tests/types.zirr:11`
attr Only

Narrows the run to the tests carrying it. With no such test, every test runs.


Skip

`tests/types.zirr:8`
attr Skip

Keeps a test out of the run. It is reported as skipped rather than omitted.


Test

`tests/types.zirr:5`
attr Test

Marks a function as a test. The function takes no arguments and returns a Result.
This is the whole of what makes a test: the runner finds functions carrying it by reading a module through reflect.


Todo

`tests/types.zirr:14`
attr Todo

Marks a test as expected to be unfinished. It runs, and its outcome is reported as a todo either way.