koans with signals, errors and stuff

this is a bit complicated, espeially with different objects representing conditions
and how hard it is to check inner parts of expressions
This commit is contained in:
efim 2022-08-11 12:36:22 +00:00
parent f4759c5685
commit b4fe711abb
1 changed files with 25 additions and 16 deletions

View File

@ -101,7 +101,7 @@
(very-silly-condition #'handle-very-silly-condition)
(most-silly-condition #'handle-most-silly-condition))
(signal (make-condition 'most-silly-condition)))
(assert-equal ____ *list*)))
(assert-equal '(:most-silly-condition :very-silly-condition :silly-condition) *list*)))
(define-test multiple-handler-binds
;; It is possible to bind handlers in steps.
@ -110,7 +110,7 @@
(most-silly-condition #'handle-most-silly-condition))
(handler-bind ((very-silly-condition #'handle-very-silly-condition))
(signal (make-condition 'most-silly-condition))))
(assert-equal ____ *list*)))
(assert-equal '(:most-silly-condition :silly-condition :very-silly-condition) *list*)))
(define-test same-handler
;; The same handler may be bound multiple times.
@ -121,7 +121,7 @@
(silly-condition #'handle-silly-condition)
(very-silly-condition #'handle-very-silly-condition))
(signal (make-condition 'most-silly-condition))))
(assert-equal ____ *list*)))
(assert-equal '(:silly-condition :silly-condition :very-silly-condition :silly-condition :very-silly-condition ) *list*)))
(define-test handler-types
;; A handler is not executed if it does not match the condition type.
@ -130,7 +130,7 @@
(very-silly-condition #'handle-very-silly-condition)
(most-silly-condition #'handle-most-silly-condition))
(signal (make-condition 'very-silly-condition)))
(assert-equal ____ *list*)))
(assert-equal '(:very-silly-condition :silly-condition) *list*)))
(define-test handler-transfer-of-control
;; A handler may decline to handle the condition if it returns normally,
@ -143,7 +143,7 @@
(return-from my-block)))
(silly-condition #'handle-silly-condition))
(signal (make-condition 'silly-condition))))
(assert-equal ____ *list*)))
(assert-equal '(:silly-condition) *list*)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -163,7 +163,7 @@
(handler-case (signal (make-condition 'my-error))
(error (condition) (handle-error condition))
(my-error (condition) (handle-my-error condition)))
(assert-equal ____ *list*)))
(assert-equal '(:error) *list*))) ; well, I don't really understand that
(define-test handler-case-order
;; The order of handler cases matters.
@ -171,7 +171,7 @@
(handler-case (signal (make-condition 'my-error))
(my-error (condition) (handle-my-error condition))
(error (condition) (handle-error condition)))
(assert-equal ____ *list*)))
(assert-equal '(:my-error) *list*)))
(define-test handler-case-type
;; A handler cases is not executed if it does not match the condition type.
@ -179,7 +179,16 @@
(handler-case (signal (make-condition 'error))
(my-error (condition) (handle-my-error condition))
(error (condition) (handle-error condition)))
(assert-equal ____ *list*)))
(assert-equal '(:error) *list*)))
;;; it seems that difference between #'handler-case and #'handler-bind
;; is that first is like try-catch, where single, first condition for signal is executed
;; (and expressions are not handlers, but things to evaluate)
;; and handler-bind executes all handlers applicable?
;; here handlers are functions
;; http://www.lispworks.com/documentation/HyperSpec/Body/09_ada.htm
;; here it seems that handler can either transfer control - by return-from of return
;; and that "handles" the signal, or "decline" by returning, that that means that following handlers get called
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -199,27 +208,27 @@
(handler-case (divide numerator denominator)
(division-by-zero () :division-by-zero)
(type-error () :type-error))))
(assert-equal ____ (try-to-divide 6 2))
(assert-equal ____ (try-to-divide 6 0))
(assert-equal ____ (try-to-divide 6 :zero))))
(assert-equal 3 (try-to-divide 6 2))
(assert-equal :division-by-zero (try-to-divide 6 0))
(assert-equal :type-error (try-to-divide 6 :zero))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Condition objects can contain metadata about the specific situation that
;;; occurred in the code.
(define-test accessors-division-by-zero
(let ((condition (handler-case (divide 6 0) (division-by-zero (c) c))))
(setq my-cond (handler-case (divide 6 0) (division-by-zero (c) c)))
(let ((my-cond (handler-case (divide 6 0) (division-by-zero (c) c))))
;; Disabled on CLISP and ABCL due to conformance bugs.
;; See https://gitlab.com/gnu-clisp/clisp/-/issues/22
;; See https://github.com/armedbear/abcl/issues/177
#-(or clisp abcl)
(assert-equal ____ (arithmetic-error-operands condition))
(let ((operation (arithmetic-error-operation condition)))
(assert-equal '(6 0) (arithmetic-error-operands my-cond)) ; returns '(6 0)
(let ((operation (arithmetic-error-operation my-cond))) ; returns #'/ holy cow
;; Disabled on ABCL due to a conformance bug.
;; See https://github.com/armedbear/abcl/issues/177
#-abcl
(assert-equal ____ (funcall operation 12 4)))))
(assert-equal 3 (funcall operation 12 4)))))
(define-test accessors-type-error
(let ((condition (handler-case (divide 6 :zero) (type-error (c) c))))