diff --git a/lib/haskell/testlib.sx b/lib/haskell/testlib.sx index 5803b741..1c814fd8 100644 --- a/lib/haskell/testlib.sx +++ b/lib/haskell/testlib.sx @@ -56,3 +56,21 @@ (append! hk-test-fails {:actual actual :expected expected :name name}))))) + +(define + hk-test-error + (fn + (name thunk expected-substring) + (let + ((caught (guard (e (true (if (string? e) e (str e)))) (begin (thunk) nil)))) + (cond + ((nil? caught) + (do + (set! hk-test-fail (+ hk-test-fail 1)) + (append! hk-test-fails {:actual "no error raised" :expected (str "error containing: " expected-substring) :name name}))) + ((>= (index-of caught expected-substring) 0) + (set! hk-test-pass (+ hk-test-pass 1))) + (:else + (do + (set! hk-test-fail (+ hk-test-fail 1)) + (append! hk-test-fails {:actual caught :expected (str "error containing: " expected-substring) :name name}))))))) diff --git a/lib/haskell/tests/eval.sx b/lib/haskell/tests/eval.sx index 7bbeec29..f9ced488 100644 --- a/lib/haskell/tests/eval.sx +++ b/lib/haskell/tests/eval.sx @@ -289,6 +289,16 @@ (hk-deep-force (hk-run "main = head [42]")) 42) +(hk-test-error + "hk-test-error helper: catches matching error" + (fn () (hk-deep-force (hk-run "main = error \"boom\""))) + "hk-error: boom") + +(hk-test-error + "hk-test-error helper: catches head [] error" + (fn () (hk-deep-force (hk-run "main = head []"))) + "Prelude.head: empty list") + (hk-test "second arg never forced" (hk-eval-expr-source "(\\x y -> x) 1 (error \"never\")") diff --git a/plans/haskell-completeness.md b/plans/haskell-completeness.md index ae5be084..b0f972ee 100644 --- a/plans/haskell-completeness.md +++ b/plans/haskell-completeness.md @@ -133,7 +133,7 @@ No OCaml changes are needed. The view type is fully representable as an SX dict. `fromJust Nothing` → `"Maybe.fromJust: Nothing"`. - [x] Top-level `hk-run-io` catches `hk-error` tag and returns it as a tagged error result so test suites can inspect it without crashing. -- [ ] `hk-test-error` helper in `testlib.sx`: +- [x] `hk-test-error` helper in `testlib.sx`: `(hk-test-error "desc" thunk expected-substring)` — asserts the thunk raises an `hk-error` whose message contains the given substring. - [ ] Tests in `lib/haskell/tests/errors.sx` (≥ 10 tests: error message @@ -293,6 +293,13 @@ No OCaml changes are needed. The view type is fully representable as an SX dict. _Newest first._ +**2026-05-07** — Phase 9 `hk-test-error` helper in testlib.sx: +- New 0-arity-thunk-based assertion: `(hk-test-error name thunk substr)` — + evaluates `(thunk)`, expects an exception, checks `index-of` for the given + substring in the caught (string-coerced) value. Increments `hk-test-pass` on + match, otherwise records into `hk-test-fails` with descriptive expected. +- Added 2 quick uses to `tests/eval.sx` (error and head []). Suite now 66/66. + **2026-05-07** — Phase 9 `hk-run-io` catches errors, appends to io-lines: - Wrapped both `hk-run-io` and `hk-run-io-with-input` in `(guard (e (true …)))` that appends the caught exception to `hk-io-lines`. Also added `hk-deep-force`