From 7063e684ba70c16d5642cd039f8b58e666df6dca Mon Sep 17 00:00:00 2001 From: m0tholith <48518572+m0tholith@users.noreply.github.com> Date: Tue, 4 Nov 2025 17:26:34 +0300 Subject: [PATCH] Make expected error in `test::@error` macro optional If not supplied with a fault, `test::@error` checks if a fault of any type/value was returned --- lib/std/core/test.c3 | 10 ++++++++-- test/unit/stdlib/core/test_test.c3 | 28 ++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/lib/std/core/test.c3 b/lib/std/core/test.c3 index c5d4dc897..5dcf20413 100644 --- a/lib/std/core/test.c3 +++ b/lib/std/core/test.c3 @@ -26,6 +26,7 @@ fn void? test_div() @test test::le(2, 3); test::eq_approx(m::divide(1, 3)!, 0.333, places: 3); test::@check(2 == 2, "divide: %d", divide(6, 3)!); + test::@error(m::divide(3, 0)); test::@error(m::divide(3, 0), MathError.DIVISION_BY_ZERO); } @@ -78,14 +79,15 @@ macro @check(#condition, String format = "", args...) } <* - Check if function returns specific error + Check if function returns (specific) error @param #funcresult : `result of function execution` @param error_expected : `expected error of function execution` @require runtime::test_context != null : "Only allowed in @test functions" *> -macro @error(#funcresult, fault error_expected) +macro @error(#funcresult, fault error_expected = ...) { + $if $defined(error_expected): if (catch err = #funcresult) { if (err != error_expected) @@ -96,6 +98,10 @@ macro @error(#funcresult, fault error_expected) return; } print_panicf("`%s` error [%s] was not returned.", $stringify(#funcresult), error_expected); + $else + if (catch err = #funcresult) return; + print_panicf("`%s` unexpectedly did not return error.", $stringify(#funcresult)); + $endif } <* diff --git a/test/unit/stdlib/core/test_test.c3 b/test/unit/stdlib/core/test_test.c3 index 6fdc5328c..1597fdba1 100644 --- a/test/unit/stdlib/core/test_test.c3 +++ b/test/unit/stdlib/core/test_test.c3 @@ -303,6 +303,34 @@ fn void test_error_not_raised() test::@error(ffail_int(1, 1), io::FILE_NOT_FOUND); } +fn void test_error_nofault() +{ + TestFailFn ffail_void = fn void?(bool to_fail) + { + if (to_fail) return io::FILE_NOT_FOUND?; + }; + TestIntFn ffail_int = fn int?(int a, int b) + { + if (b == 0) return io::FILE_NOT_FOUND?; + return a / b; + }; + test::@setup(state.setup_fn, state.teardown_fn); + + test::@error(ffail_void(true)); + test::@error(ffail_int(1, 0)); +} + +fn void test_error_nofault_not_raised() +{ + TestIntFn ffail_int = fn int?(int a, int b) { + if (b == 0) return io::FILE_NOT_FOUND?; + return a / b; + }; + test::@setup(state.setup_fn, state.teardown_fn); + state.expected_fail = true; + test::@error(ffail_int(1, 1)); +} + fn void test_error_wrong_error_expected() { TestIntFn ffail_int = fn int?(int a, int b) {