Testing in Odin

Odin testing is very reminiscent of Go testing:

  1. it requires an import of core:testing
  2. tests must have a particular type, proc "odin" (_: ^testing.T)
  3. test results are communicated by function calls using the received ^testing.T
  4. but: tests need a @test proc attribute, and don't need any particular name
  5. but: tests can be in any file of a package; a test can be defined inline with the code it's testing, or it can be off in its own file. It's up to you.
  6. but: tests are always parsed and typechecked, although not part of normal builds

lang/strings.odin contains a bunch of string-conversion tests. It shows

  • doc comments sandwiched between the attribute and the proc name (where they must be for odin doc to find them)
  • local aliases for convenience, e.g. want :: testing.expect_value
  • use of context.temp_allocator for small allocations (total <4MB) that can be forgotten as soon as each test is over

Here's a much less serious example of a 'useful' program with inline tests:

package fact

import "core:fmt"
import "core:os"
import "core:strconv"
import "core:testing"

fact :: proc(n: $T) -> T {
	if n <= 1 do return 1
	return n * fact(n - 1)
}

@(test)
fact_5 :: proc(t: ^testing.T) {
	testing.expect_value(t, fact(5), 120)
}

@(test)
fact_min :: proc(t: ^testing.T) {
	testing.expect_value(t, fact(0), 1)
	testing.expect_value(t, fact(1), 1)
}

main :: proc() {
	if len(os.args) != 2 {
		fmt.eprintf("usage: %s <n>\n", os.args[0])
		os.exit(1)
	}
	n, ok := strconv.parse_uint(os.args[1])
	if !ok {
		fmt.eprintf("not a uint: %s\n", os.args[1])
		os.exit(1)
	}
	fmt.println(fact(n))
}

usage:

$ odin run o129.odin -file -- 5
120
$ odin test o129.odin -file
[Package: fact]
[Test: fact_5]
[fact_5 : SUCCESS]
[Test: fact_min]
[fact_min : SUCCESS]
----------------------------------------
2/2 SUCCESSFUL