Odin provides a good testing toolbox.
Let’s make a simple project to practice testing.
String count library
We will create a project that wraps around the procedures strings.rune_count
and len
.
This will be our project structure.
.
├── README.md
├── lib
│ └── String
│ └── count.odin
├── test
│ ├── lib
│ │ └── String
│ │ └── count_test.odin
│ └── test_helper.odin
└──test.bin
This the main sources will be inside the lib/String
directory and the test directory will share the same structure of the lib
directory.
lib/String/count.odin
The contents of our library will be as follow:
package String
import "core:strings"
length :: proc(binary: string) -> int {
return strings.rune_count(binary)
}
byte_size :: proc(binary: string) -> int {
return len(binary)
}
test.bin
This file is generated by Odin compiler to run the tests. You can add it to your .gitignore
.
test/test_helper.odin
This file will import all the other tests, and configure general settings.
package Test
// Import the tests inside test/lib
import "lib/String"
// Mark the package as used to pass -vet
_ :: String
test/lib/String/count_test.odin
package Test_String
import "core:log"
import "core:testing"
import "core:os"
// We are using a custom collection path
import "project:lib/String"
// Test are marked with @(test) if this is not present then Odin will not run the test
@(test)
test_that_string_can_count_length :: proc(t: ^testing.T) {
result := String.length("mate")
testing.expect_value(t, result, 4)
result = String.length("maté")
// The last expect must return early so testing.cleanup
// is not triggered if the test is sucessfull
if testing.expect_value(t, result, 4) {
return
}
// Cleans up the test procedure. This is useful
// when some tests fails and can clodge the testing process.
// This is a way to ensure the testing process goes smoothly.
testing.cleanup(t, proc (raw_handle: rawptr) {
handle := cast(^os.Handle) raw_handle
os.close(handle^)
log.debug("Test cleanup")
}, &result)
}
@(test)
test_that_string_can_count_byte_size :: proc(t: ^testing.T) {
result := String.byte_size("mate")
testing.expect_value(t, result, 4)
result = String.byte_size("maté")
if testing.expect_value(t, result, 5) {
return
}
testing.cleanup(t, proc (raw_handle: rawptr) {
handle := cast(^os.Handle) raw_handle
os.close(handle^)
log.debug("Test cleanup")
}, &result)
}
Test Command
For running the commands we will be at the root directory of our project and run odin test
command. We can pass params to this command, for example we are using a collection named project that holds the path to our root project directory.
$ odin test test/ -vet -all-packages -collection:project=.
If run correctly an output similar to this will appear.
[INFO ] --- [2024-11-18 16:12:34] Starting test runner with 4 threads. Set with -define:ODIN_TEST_THREADS=n.
[INFO ] --- [2024-11-18 16:12:34] The random seed sent to every test is: 32611758867092. Set with -define:ODIN_TEST_RANDOM_SEED=n.
[INFO ] --- [2024-11-18 16:12:34] Memory tracking is enabled. Tests will log their memory usage if there's an issue.
[INFO ] --- [2024-11-18 16:12:34] < Final Mem/ Total Mem> < Peak Mem> (#Free/Alloc) :: [package.test_name]
Test_String [|||||||||||||||||| ] 2 :: [package done]
Finished 2 tests in 1.124ms. All tests were successful.