From a09a70bd2f28e9d524daee58a0a6ee269d45643e Mon Sep 17 00:00:00 2001 From: "Todd V. Jonker" Date: Sat, 14 Mar 2026 14:59:03 -0700 Subject: [PATCH] Support `assertion_error` in the exception and check modules. Port some assertion test cases to Fusion. --- .../fusion/modules/fusion/exception.fusion | 16 +++--- .../modules/fusion/experimental/check.fusion | 37 +++++++------- .../src/test/fusion/modules/testutils.fusion | 31 ++++++++++++ .../test/fusion/scripts/assert.test.fusion | 24 +++++++++ .../java/dev/ionfusion/fusion/AssertTest.java | 49 ++----------------- 5 files changed, 88 insertions(+), 69 deletions(-) create mode 100644 runtime/src/test/fusion/scripts/assert.test.fusion diff --git a/runtime/src/main/fusion/modules/fusion/exception.fusion b/runtime/src/main/fusion/modules/fusion/exception.fusion index 0782b8e5d..db10ee601 100644 --- a/runtime/src/main/fusion/modules/fusion/exception.fusion +++ b/runtime/src/main/fusion/modules/fusion/exception.fusion @@ -24,6 +24,7 @@ Exceptions can be understood to have an inheritance hierarchy along these lines: * `argument_error`: a procedure was called with an invalid argument * `result_error`: a procedure returned an invalid result + * `assertion_error`: an [`assert`](#assert) failed * `syntax_error`: a syntax form was used incorrectly * `unbound_error`: an identifier has no binding * `break_exn`: the thread was interrupted (not implemented yet) @@ -197,12 +198,13 @@ Returns `true` or `false`. (quote_syntax here) stx)))) - (generate_predicate is_error_exn error_exn "dev.ionfusion.fusion.FusionErrorException") - (generate_predicate is_argument_error argument_error "dev.ionfusion.fusion.ArgumentException") - (generate_predicate is_arity_error arity_error "dev.ionfusion.fusion.ArityFailure") - (generate_predicate is_contract_error contract_error "dev.ionfusion.fusion.ContractException") - (generate_predicate is_result_error result_error "dev.ionfusion.fusion.ResultFailure") - (generate_predicate is_syntax_error syntax_error "dev.ionfusion.fusion.SyntaxException") - (generate_predicate is_unbound_error unbound_error "dev.ionfusion.fusion.UnboundIdentifierException") + (generate_predicate is_error_exn error_exn "dev.ionfusion.fusion.FusionErrorException") + (generate_predicate is_argument_error argument_error "dev.ionfusion.fusion.ArgumentException") + (generate_predicate is_arity_error arity_error "dev.ionfusion.fusion.ArityFailure") + (generate_predicate is_assertion_error assertion_error "dev.ionfusion.fusion.FusionAssertionException") + (generate_predicate is_contract_error contract_error "dev.ionfusion.fusion.ContractException") + (generate_predicate is_result_error result_error "dev.ionfusion.fusion.ResultFailure") + (generate_predicate is_syntax_error syntax_error "dev.ionfusion.fusion.SyntaxException") + (generate_predicate is_unbound_error unbound_error "dev.ionfusion.fusion.UnboundIdentifierException") ) diff --git a/runtime/src/main/fusion/modules/fusion/experimental/check.fusion b/runtime/src/main/fusion/modules/fusion/experimental/check.fusion index 440fdf0ee..3744b6c0e 100644 --- a/runtime/src/main/fusion/modules/fusion/experimental/check.fusion +++ b/runtime/src/main/fusion/modules/fusion/experimental/check.fusion @@ -514,15 +514,16 @@ order: // TODO This should just use `display`. : {{{arity_exn}}} (define (describe_raised v) (cond - ((is_argument_error v) "argument_error") - ((is_arity_error v) "arity_error") - ((is_result_error v) "result_error") - ((is_contract_error v) "contract_error") - ((is_check_error v) "check_error") - ((is_unbound_error v) "unbound_error") - ((is_syntax_error v) "syntax_error") - ((is_error_exn v) "error_exn") - ((is_exn v) "exn") + ((is_argument_error v) "argument_error") + ((is_arity_error v) "arity_error") + ((is_assertion_error v) "assertion_error") + ((is_result_error v) "result_error") + ((is_contract_error v) "contract_error") + ((is_check_error v) "check_error") + ((is_unbound_error v) "unbound_error") + ((is_syntax_error v) "syntax_error") + ((is_error_exn v) "error_exn") + ((is_exn v) "exn") (true v))) (define (_expect_raise pred expected thunk) @@ -611,6 +612,7 @@ another kind of exception is thrown, then the check fails.''')))] expect_any_raise expect_argument_error expect_arity_error + expect_assertion_error expect_check_error expect_contract_error expect_error_exn @@ -618,14 +620,15 @@ another kind of exception is thrown, then the check fails.''')))] expect_result_error ) - (define_exn_check expect_any_raise (always true) "any value") - (define_exn_check expect_exn is_exn "exn") - (define_exn_check expect_error_exn is_error_exn "error_exn") - (define_exn_check expect_argument_error is_argument_error "argument_error") - (define_exn_check expect_arity_error is_arity_error "arity_error") - (define_exn_check expect_check_error is_check_error "check_error") - (define_exn_check expect_contract_error is_contract_error "contract_error") - (define_exn_check expect_result_error is_result_error "result_error") + (define_exn_check expect_any_raise (always true) "any value") + (define_exn_check expect_exn is_exn "exn") + (define_exn_check expect_error_exn is_error_exn "error_exn") + (define_exn_check expect_argument_error is_argument_error "argument_error") + (define_exn_check expect_arity_error is_arity_error "arity_error") + (define_exn_check expect_assertion_error is_assertion_error "assertion_error") + (define_exn_check expect_check_error is_check_error "check_error") + (define_exn_check expect_contract_error is_contract_error "contract_error") + (define_exn_check expect_result_error is_result_error "result_error") // NOT PUBLIC! Only used by the public version below. (define_exn_check _expect_syntax_error is_syntax_error false /*skip frame*/) diff --git a/runtime/src/test/fusion/modules/testutils.fusion b/runtime/src/test/fusion/modules/testutils.fusion index 5a2f0f383..c1ad70396 100644 --- a/runtime/src/test/fusion/modules/testutils.fusion +++ b/runtime/src/test/fusion/modules/testutils.fusion @@ -14,6 +14,8 @@ remove_first test_data_file test_equivalence + truthy_values + untruthy_values ) (define (test_data_file filename) @@ -48,6 +50,35 @@ null.struct))) + (define truthy_values + [true, + 0, + 1, + 0., + nan, + +inf, + -inf, + 0e0, + 2012-10-19T12:54-08:00, + "", + "string", + (quote ''), + (quote symbol), + {{ }}, + {{""}}, + [], + (quote ()), + {}, + (quote ann::true)]) + + (define untruthy_values + (append all_nulls + [(void), + false, + (quote ann::false), // Annotations don't affect truthiness + (quote ann::null)])) + + (defpub representative_ion_data (quote (null diff --git a/runtime/src/test/fusion/scripts/assert.test.fusion b/runtime/src/test/fusion/scripts/assert.test.fusion new file mode 100644 index 000000000..5124a6675 --- /dev/null +++ b/runtime/src/test/fusion/scripts/assert.test.fusion @@ -0,0 +1,24 @@ +// Copyright Ion Fusion contributors. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +(require + "/fusion/experimental/check" + "/testutils" +) + + +(define (expect_assertion_success v) + (check_void (assert v (fail "assertion message should be unreachable")))) + +(define (expect_assertion_failure v) + // TODO check the message; see dev.ionfusion.fusion.AssertTest + (expect_assertion_error (assert v)) + (expect_assertion_error (assert v "it failed")) + (expect_assertion_error (assert v "it" "failed"))) + + +(do expect_assertion_success truthy_values) +(do expect_assertion_failure untruthy_values) + + +(expect_syntax_error (assert)) diff --git a/runtime/src/test/java/dev/ionfusion/fusion/AssertTest.java b/runtime/src/test/java/dev/ionfusion/fusion/AssertTest.java index 62631b391..4cfb55175 100644 --- a/runtime/src/test/java/dev/ionfusion/fusion/AssertTest.java +++ b/runtime/src/test/java/dev/ionfusion/fusion/AssertTest.java @@ -4,20 +4,15 @@ package dev.ionfusion.fusion; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +/** + * These checks can't be ported to Fusion yet because there's no way to inspect an + * exception's message. + */ public class AssertTest extends CoreTestCase { - @BeforeEach - public void requires() - throws Exception - { - topLevel().requireModule("/fusion/exception"); - } - - private void expectAssertFailure(String expr) throws Exception { @@ -61,40 +56,4 @@ public void testAssertFailure() expectAssertFailure(form); } } - - private void expectAssertSuccess(String expr) - throws Exception - { - assertEval(1, "(begin (assert " + expr + " \"barney\") 1)"); - } - - @Test - public void testAssertSuccess() - throws Exception - { - for (String form : BooleanTest.TRUTHY_EXPRESSIONS) - { - expectAssertSuccess(form); - } - } - - @Test - public void testAssertFailureWithExitingMessage() - { - assertEvalThrows(ExitException.class, "(assert false (exit))"); - } - - @Test - public void testAssertSuccessWithExitingMessage() - throws Exception - { - eval("(assert true (exit))"); - } - - @Test - public void testAssertArity() - throws Exception - { - expectSyntaxExn("(assert)"); - } }