;; errors.sx — Phase 9 error / undefined / partial-fn coverage via hk-test-error. ;; ── error builtin ──────────────────────────────────────────── (define hk-as-list (fn (xs) (cond ((and (list? xs) (= (first xs) "[]")) (list)) ((and (list? xs) (= (first xs) ":")) (cons (nth xs 1) (hk-as-list (nth xs 2)))) (:else xs)))) (hk-test-error "error: raises with literal message" (fn () (hk-deep-force (hk-run "main = error \"boom\""))) "hk-error: boom") (hk-test-error "error: raises with computed message" (fn () (hk-deep-force (hk-run "main = error (\"oops: \" ++ show 42)"))) "hk-error: oops: 42") ;; ── undefined ──────────────────────────────────────────────── (hk-test-error "error: nested in if branch (only fires when forced)" (fn () (hk-deep-force (hk-run "main = if 1 == 1 then error \"taken\" else 0"))) "taken") (hk-test-error "undefined: raises Prelude.undefined" (fn () (hk-deep-force (hk-run "main = undefined"))) "Prelude.undefined") ;; The non-strict path: undefined doesn't fire when not forced. (hk-test-error "undefined: forced via arithmetic" (fn () (hk-deep-force (hk-run "main = undefined + 1"))) "Prelude.undefined") ;; ── partial functions ─────────────────────────────────────── (hk-test "undefined: lazy, not forced when discarded" (hk-deep-force (hk-run "main = let _ = undefined in 5")) 5) (hk-test-error "head []: raises Prelude.head: empty list" (fn () (hk-deep-force (hk-run "main = head []"))) "Prelude.head: empty list") (hk-test-error "tail []: raises Prelude.tail: empty list" (fn () (hk-deep-force (hk-run "main = tail []"))) "Prelude.tail: empty list") ;; head and tail still work on non-empty lists. (hk-test-error "fromJust Nothing: raises Maybe.fromJust: Nothing" (fn () (hk-deep-force (hk-run "main = fromJust Nothing"))) "Maybe.fromJust: Nothing") (hk-test "head [42]: still works" (hk-deep-force (hk-run "main = head [42]")) 42) ;; ── error in IO context ───────────────────────────────────── (hk-test "tail [1,2,3]: still works" (hk-as-list (hk-deep-force (hk-run "main = tail [1,2,3]"))) (list 2 3)) (hk-test "hk-run-io: error in main lands in io-lines" (let ((lines (hk-run-io "main = error \"caught here\""))) (>= (index-of (str lines) "caught here") 0)) true) ;; ── hk-test-error helper itself ───────────────────────────── (hk-test "hk-run-io: putStrLn before error preserves earlier output" (let ((lines (hk-run-io "main = do { putStrLn \"first\"; error \"died\"; putStrLn \"never\" }"))) (and (>= (index-of (str lines) "first") 0) (>= (index-of (str lines) "died") 0))) true) ;; hk-as-list helper for converting a forced Haskell cons into an SX list. (hk-test-error "hk-test-error: matches partial substring inside wrapped exception" (fn () (hk-deep-force (hk-run "main = error \"unique-marker-xyz\""))) "unique-marker-xyz") {:fails hk-test-fails :pass hk-test-pass :fail hk-test-fail}