diff options
| author | Jeroen van Rijn <Kelimion@users.noreply.github.com> | 2024-08-08 20:15:08 +0200 |
|---|---|---|
| committer | Jeroen van Rijn <Kelimion@users.noreply.github.com> | 2024-08-08 20:41:32 +0200 |
| commit | 80d1e1ba82cb21edb0a5263ea616d7105038bc0e (patch) | |
| tree | 34989f4b3660b4b0dc014c7d8732da8d2225d848 /core/testing/runner.odin | |
| parent | 94c62fb630265f7c08726e7f15b4fb5cac0a3ad9 (diff) | |
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.
Diffstat (limited to 'core/testing/runner.odin')
| -rw-r--r-- | core/testing/runner.odin | 38 |
1 files changed, 35 insertions, 3 deletions
diff --git a/core/testing/runner.odin b/core/testing/runner.odin index 16967e3c7..5482d93e3 100644 --- a/core/testing/runner.odin +++ b/core/testing/runner.odin @@ -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 +}
\ No newline at end of file |