From 73d725e45f3667bbc618045b02fda22e215e8e4e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 1 Nov 2026 12:00:02 +0000 Subject: [PATCH] Fix core:testing traps, signals, and expectations --- core/testing/runner.odin | 10 ++- core/testing/signal_handler.odin | 5 +- core/testing/signal_handler_windows.odin | 90 ++++++++++++++---------- core/testing/testing.odin | 7 +- 4 files changed, 70 insertions(+), 42 deletions(-) diff --git a/core/testing/runner.odin b/core/testing/runner.odin index 535dcc0b1..e0afa21d6 100644 --- a/core/testing/runner.odin +++ b/core/testing/runner.odin @@ -163,6 +163,11 @@ run_test_task :: proc(task: thread.Task) { data.it.p(&data.t) + if local_test_expected_failures.signal != 0 || + local_test_expected_failures.message_count + local_test_expected_failures.location_count > 0 { + log.errorf("`%s.%s` returned without the assertion or signal it expected.", data.it.pkg, data.it.name) + } + end_t(&data.t) when TRACKING_MEMORY && FAIL_ON_BAD_MEMORY { @@ -807,8 +812,6 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { if test_index, reason, ok := should_stop_test(); ok { - passed := reason == .Successful_Stop - #no_bounds_check report.all_test_states[test_index] = .Successful if passed else .Failed #no_bounds_check it := internal_tests[test_index] #no_bounds_check pkg := report.packages_by_name[it.pkg] pkg.frame_ready = false @@ -829,6 +832,9 @@ runner :: proc(internal_tests: []Internal_Test) -> bool { fmt.assertf(task_data != nil, "A signal (%v) was raised to stop test #%i %s.%s, but its task data is missing.", reason, test_index, it.pkg, it.name) + passed := reason == .Successful_Stop && !failed(&task_data.t) + #no_bounds_check report.all_test_states[test_index] = .Successful if passed else .Failed + if !passed && !task_data.t._fail_now_called { if test_index not_in failed_test_reason_map { // We only write a new error message here if there wasn't one diff --git a/core/testing/signal_handler.odin b/core/testing/signal_handler.odin index b33732a30..a3981ddeb 100644 --- a/core/testing/signal_handler.odin +++ b/core/testing/signal_handler.odin @@ -39,7 +39,8 @@ Stop_Reason :: enum { } test_assertion_failure_proc :: proc(prefix, message: string, loc: runtime.Source_Code_Location) -> ! { - if local_test_expected_failures.message_count + local_test_expected_failures.location_count > 0 { + if local_test_expected_failures.signal != 0 || + local_test_expected_failures.message_count + local_test_expected_failures.location_count > 0 { local_test_assertion_raised = { message, loc } log.debugf("%s\n\tmessage: %q\n\tlocation: %w", prefix, message, loc) } else { @@ -53,6 +54,8 @@ setup_signal_handler :: proc() { } setup_task_signal_handler :: proc(test_index: int) { + local_test_expected_failures = {} + local_test_assertion_raised = {} _setup_task_signal_handler(test_index) } diff --git a/core/testing/signal_handler_windows.odin b/core/testing/signal_handler_windows.odin index 780be6796..2d736b228 100644 --- a/core/testing/signal_handler_windows.odin +++ b/core/testing/signal_handler_windows.odin @@ -117,49 +117,62 @@ This is a dire bug and should be reported to the Odin developers. win32.TerminateProcess(win32.GetCurrentProcess(), 1) } - if sync.mutex_guard(&stop_test_gate) { - intrinsics.atomic_store(&stop_test_index, local_test_index) - intrinsics.atomic_store(&stop_test_signal, code) - passed: bool - check_passing: { - if location := local_test_assertion_raised.location; location != {} { - for i in 0.. ! { + sync.mutex_lock(&stop_test_gate) + + intrinsics.atomic_store(&stop_test_index, local_test_index) + intrinsics.atomic_store(&stop_test_signal, code) + passed: bool + check_passing: { + if location := local_test_assertion_raised.location; location != {} { + for i in 0.. bool { diff --git a/core/testing/testing.odin b/core/testing/testing.odin index 7182f77f5..660c722ec 100644 --- a/core/testing/testing.odin +++ b/core/testing/testing.odin @@ -160,7 +160,8 @@ set_fail_timeout :: proc(t: ^T, duration: time.Duration, loc := #caller_location /* Let the test runner know that it should expect an assertion failure from a -specific location in the source code for this test. +specific location in the source code for this test. The test fails if it +returns without one. In the event that an assertion fails, a debug message will be logged with its exact message and location in a copyable format to make it convenient to write @@ -183,7 +184,7 @@ expect_assert_from :: proc(t: ^T, expected_place: runtime.Source_Code_Location, /* Let the test runner know that it should expect an assertion failure with a -specific message for this test. +specific message for this test. The test fails if it returns without one. In the event that an assertion fails, a debug message will be logged with its exact message and location in a copyable format to make it convenient to write @@ -211,7 +212,7 @@ expect_assert :: proc { /* Let the test runner know that it should expect a signal to be raised within -this test. +this test. The test fails if it returns without one. This API is for advanced users, as arbitrary signals will not be caught; only the ones already handled by the test runner, such as