; Tcl-on-SX error handling tests (Phase 4) (define tcl-err-pass 0) (define tcl-err-fail 0) (define tcl-err-failures (list)) (define tcl-err-assert (fn (label expected actual) (if (equal? expected actual) (set! tcl-err-pass (+ tcl-err-pass 1)) (begin (set! tcl-err-fail (+ tcl-err-fail 1)) (append! tcl-err-failures (str label ": expected=" (str expected) " got=" (str actual))))))) (define tcl-run-error-tests (fn () (set! tcl-err-pass 0) (set! tcl-err-fail 0) (set! tcl-err-failures (list)) (define interp (fn () (make-default-tcl-interp))) (define run (fn (src) (tcl-eval-string (interp) src))) (define ok (fn (label actual expected) (tcl-err-assert label expected actual))) (define ok? (fn (label condition) (tcl-err-assert label true condition))) ; --- catch basic --- (ok "catch-ok-code" (get (run "catch {set x 1}") :result) "0") (ok "catch-ok-result-var" (tcl-var-get (run "catch {set x hello} r") "r") "hello") (ok "catch-ok-returns-0" (get (run "catch {set x hello} r") :result) "0") ; --- catch error --- (ok "catch-error-code" (get (run "catch {error oops} r") :result) "1") (ok "catch-error-result-var" (tcl-var-get (run "catch {error oops} r") "r") "oops") ; --- catch outer code stays 0 --- (ok? "catch-outer-code-ok" (= (get (run "catch {error boom} r") :code) 0)) ; --- catch code 2 (return) --- (ok "catch-return-code" (get (run "proc p {} {return hello}\ncatch {p} r") :result) "0") (ok "catch-return-val" (tcl-var-get (run "proc p {} {return hello}\ncatch {p} r") "r") "hello") ; --- catch code 3 (break) --- (ok "catch-break-code" (get (run "catch {break} r") :result) "3") ; --- catch code 4 (continue) --- (ok "catch-continue-code" (get (run "catch {continue} r") :result) "4") ; --- catch no resultVar --- (ok "catch-no-var-ok" (get (run "catch {set x 1}") :result) "0") (ok "catch-no-var-err" (get (run "catch {error boom}") :result) "1") ; --- catch with optsVar --- (ok? "catch-opts-var-set" (let ((i (run "catch {error boom} r opts"))) (not (equal? (tcl-var-get i "opts") "")))) (ok? "catch-opts-contains-code" (let ((i (run "catch {error boom} r opts"))) (let ((opts-str (tcl-var-get i "opts"))) (not (equal? (tcl-string-first "-code" opts-str 0) "-1"))))) ; --- catch nested --- (ok "catch-nested" (tcl-var-get (run "catch {catch {error inner} r2} outer") "r2") "inner") ; --- return -code error --- (ok "return-code-error-code" (get (run "catch {return -code error oops} r") :result) "1") (ok "return-code-error-val" (tcl-var-get (run "catch {return -code error oops} r") "r") "oops") ; --- return -code ok --- (ok "return-code-ok" (get (run "catch {return -code ok hello} r") :result) "0") (ok "return-code-ok-val" (tcl-var-get (run "catch {return -code ok hello} r") "r") "hello") ; --- return -code break --- (ok "return-code-break" (get (run "catch {return -code break} r") :result) "3") ; --- return -code continue --- (ok "return-code-continue" (get (run "catch {return -code continue} r") :result) "4") ; --- return -code numeric --- (ok "return-code-numeric-5" (get (run "catch {return -code 5 msg} r") :result) "5") ; --- return plain still code 2 (catch sees raw return code) --- (ok "return-plain-code" (get (run "catch {return hello} r") :result) "2") (ok "return-plain-val" (tcl-var-get (run "catch {return hello} r") "r") "hello") ; --- proc return -code error --- (ok "proc-return-code-error" (get (run "proc p {} {return -code error bad}\ncatch {p} r") :result) "1") (ok "proc-return-code-error-val" (tcl-var-get (run "proc p {} {return -code error bad}\ncatch {p} r") "r") "bad") ; --- error with info/code args --- (ok? "error-errorinfo-stored" (let ((i (run "catch {error msg myinfo mycode} r"))) (= (get i :code) 0))) ; --- throw --- (ok "throw-code" (get (run "catch {throw MYERR something} r") :result) "1") (ok "throw-msg" (tcl-var-get (run "catch {throw MYERR something} r") "r") "something") ; --- try basic ok --- (ok "try-ok-result" (get (run "try {set x hello} on ok {r} {set r2 $r}") :result) "hello") ; --- try on error --- (ok "try-on-error-handled" (get (run "try {error boom} on error {e} {set caught $e}") :result) "boom") (ok "try-on-error-var" (tcl-var-get (run "try {error boom} on error {e} {set caught $e}") "caught") "boom") ; --- try finally always runs --- (ok "try-finally-ok" (tcl-var-get (run "try {set x 1} finally {set done yes}") "done") "yes") (ok "try-finally-error" (tcl-var-get (run "catch {try {error boom} finally {set done yes}} r") "done") "yes") ; --- try on error + finally --- (ok "try-error-finally" (tcl-var-get (run "try {error oops} on error {e} {set caught $e} finally {set cleaned yes}") "cleaned") "yes") (ok "try-error-finally-caught" (tcl-var-get (run "try {error oops} on error {e} {set caught $e} finally {set cleaned yes}") "caught") "oops") ; --- try on ok and on error --- (ok "try-multi-clause-ok" (tcl-var-get (run "try {set x 1} on ok {r} {set which ok} on error {e} {set which err}") "which") "ok") (ok "try-multi-clause-err" (tcl-var-get (run "try {error boom} on ok {r} {set which ok} on error {e} {set which err}") "which") "err") ; --- catch preserves output --- (ok "catch-output-preserved" (get (run "puts -nonewline before\ncatch {puts -nonewline inside\nerror oops}\nputs -nonewline after") :output) "beforeinsideafter") (dict "passed" tcl-err-pass "failed" tcl-err-fail "failures" tcl-err-failures)))