Allow testing for intentional leaks in test runner

Adds `expect_leak_or_bad_free :: proc(t: ^T, client_test: proc(t: ^T), verifier: Memory_Verifier_Proc)`.

It sets up its own `Tracking_Allocator`, runs the `client_test`, and then calls the `verifier` procedure.
The verifier can then inspect the contents of the tracking allocator and call `testing.expect*` as sensible for the test in question.

Any allocations are then cleared so that the test runner doesn't itself complain about leaks.

Additionally, `ODIN_TEST_LOG_LEVEL_MEMORY` has been added as a define to set the severity of the test runner's memory tracker. You can use `-define:ODIN_TEST_LOG_LEVEL_MEMORY=error` to make tests fail rather than warn if leaks or bad frees have been found.
This commit is contained in:
Jeroen van Rijn
2024-08-08 20:41:32 +02:00
parent 94c62fb630
commit 80d1e1ba82
3 changed files with 122 additions and 55 deletions
+21 -1
View File
@@ -4,8 +4,10 @@ import "base:intrinsics"
import "base:runtime"
import pkg_log "core:log"
import "core:reflect"
import "core:sync"
import "core:sync/chan"
import "core:time"
import "core:mem"
_ :: reflect // alias reflect to nothing to force visibility for -vet
@@ -136,10 +138,28 @@ expect_value :: proc(t: ^T, value, expected: $T, loc := #caller_location) -> boo
return ok
}
Memory_Verifier_Proc :: #type proc(t: ^T, ta: ^mem.Tracking_Allocator)
expect_leaks :: proc(t: ^T, client_test: proc(t: ^T), verifier: Memory_Verifier_Proc) {
{
ta: mem.Tracking_Allocator
mem.tracking_allocator_init(&ta, context.allocator)
defer mem.tracking_allocator_destroy(&ta)
context.allocator = mem.tracking_allocator(&ta)
client_test(t)
sync.mutex_lock(&ta.mutex)
// The verifier can inspect this local tracking allocator.
// And then call `testing.expect_*` as makes sense for the client test.
verifier(t, &ta)
sync.mutex_unlock(&ta.mutex)
}
free_all(context.allocator)
}
set_fail_timeout :: proc(t: ^T, duration: time.Duration, loc := #caller_location) {
chan.send(t.channel, Event_Set_Fail_Timeout {
at_time = time.time_add(time.now(), duration),
location = loc,
})
}
}