mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-31 11:50:07 +00:00
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:
@@ -25,6 +25,8 @@ TEST_THREADS : int : #config(ODIN_TEST_THREADS, 0)
|
||||
TRACKING_MEMORY : bool : #config(ODIN_TEST_TRACK_MEMORY, true)
|
||||
// Always report how much memory is used, even when there are no leaks or bad frees.
|
||||
ALWAYS_REPORT_MEMORY : bool : #config(ODIN_TEST_ALWAYS_REPORT_MEMORY, false)
|
||||
// Log level for memory leaks and bad frees: debug, info, warning, error, fatal
|
||||
LOG_LEVEL_MEMORY : string : #config(ODIN_TEST_LOG_LEVEL_MEMORY, "warning")
|
||||
// Specify how much memory each thread allocator starts with.
|
||||
PER_THREAD_MEMORY : int : #config(ODIN_TEST_THREAD_MEMORY, mem.ROLLBACK_STACK_DEFAULT_BLOCK_SIZE)
|
||||
// Select a specific set of tests to run by name.
|
||||
@@ -63,6 +65,21 @@ get_log_level :: #force_inline proc() -> runtime.Logger_Level {
|
||||
}
|
||||
}
|
||||
|
||||
get_memory_log_level :: #force_inline proc() -> runtime.Logger_Level {
|
||||
when ODIN_DEBUG {
|
||||
// Always use .Debug in `-debug` mode.
|
||||
return .Debug
|
||||
} else {
|
||||
when LOG_LEVEL_MEMORY == "debug" { return .Debug } else
|
||||
when LOG_LEVEL_MEMORY == "info" { return .Info } else
|
||||
when LOG_LEVEL_MEMORY == "warning" { return .Warning } else
|
||||
when LOG_LEVEL_MEMORY == "error" { return .Error } else
|
||||
when LOG_LEVEL_MEMORY == "fatal" { return .Fatal } else {
|
||||
#panic("Unknown `ODIN_TEST_LOG_LEVEL_MEMORY`: \"" + LOG_LEVEL_MEMORY + "\", possible levels are: \"debug\", \"info\", \"warning\", \"error\", or \"fatal\".")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JSON :: struct {
|
||||
total: int,
|
||||
success: int,
|
||||
@@ -222,6 +239,10 @@ runner :: proc(internal_tests: []Internal_Test) -> bool {
|
||||
total_success_count := 0
|
||||
total_done_count := 0
|
||||
total_test_count := len(internal_tests)
|
||||
when TRACKING_MEMORY {
|
||||
memory_leak_count := 0
|
||||
bad_free_count := 0
|
||||
}
|
||||
|
||||
when !FANCY_OUTPUT {
|
||||
// This is strictly for updating the window title when the progress
|
||||
@@ -498,6 +519,9 @@ runner :: proc(internal_tests: []Internal_Test) -> bool {
|
||||
|
||||
memory_is_in_bad_state := len(tracker.allocation_map) + len(tracker.bad_free_array) > 0
|
||||
|
||||
memory_leak_count += len(tracker.allocation_map)
|
||||
bad_free_count += len(tracker.bad_free_array)
|
||||
|
||||
when ALWAYS_REPORT_MEMORY {
|
||||
should_report := true
|
||||
} else {
|
||||
@@ -507,7 +531,9 @@ runner :: proc(internal_tests: []Internal_Test) -> bool {
|
||||
if should_report {
|
||||
write_memory_report(batch_writer, tracker, data.it.pkg, data.it.name)
|
||||
|
||||
pkg_log.log(.Warning if memory_is_in_bad_state else .Info, bytes.buffer_to_string(&batch_buffer))
|
||||
memory_log_level := get_memory_log_level() if memory_is_in_bad_state else .Info
|
||||
|
||||
pkg_log.log(memory_log_level, bytes.buffer_to_string(&batch_buffer))
|
||||
bytes.buffer_reset(&batch_buffer)
|
||||
}
|
||||
|
||||
@@ -891,5 +917,11 @@ To partly mitigate this, redirect STDERR to a file or use the -define:ODIN_TEST_
|
||||
fmt.assertf(err == nil, "Error writing JSON report: %v", err)
|
||||
}
|
||||
|
||||
return total_success_count == total_test_count
|
||||
}
|
||||
fatal_memory_failures := false
|
||||
when TRACKING_MEMORY {
|
||||
if get_memory_log_level() >= .Error {
|
||||
fatal_memory_failures = (memory_leak_count + bad_free_count) > 0
|
||||
}
|
||||
}
|
||||
return total_success_count == total_test_count && !fatal_memory_failures
|
||||
}
|
||||
Reference in New Issue
Block a user