;; Tests for dynamic-wind: after-thunk fires on normal return, ;; non-local exit via raise/guard, and call/cc escape. (defsuite "dynamic-wind-basic" (deftest "after fires on normal return" (let ((log (list))) (dynamic-wind (fn () (append! log "before")) (fn () (append! log "body")) (fn () (append! log "after"))) (assert= 3 (len log)) (assert= "before" (nth log 0)) (assert= "body" (nth log 1)) (assert= "after" (nth log 2)))) (deftest "after fires on raise escape" (let ((log (list))) (guard (e (true nil)) (dynamic-wind (fn () (append! log "before")) (fn () (append! log "body") (error "boom")) (fn () (append! log "after")))) (assert= 3 (len log)) (assert= "before" (nth log 0)) (assert= "body" (nth log 1)) (assert= "after" (nth log 2)))) (deftest "after fires on call/cc escape" (let ((log (list))) (call/cc (fn (k) (dynamic-wind (fn () (append! log "before")) (fn () (append! log "body") (k nil)) (fn () (append! log "after"))))) (assert= 3 (len log)) (assert= "before" (nth log 0)) (assert= "body" (nth log 1)) (assert= "after" (nth log 2)))) (deftest "nested dynamic-wind after-thunks fire LIFO on normal return" (let ((log (list))) (dynamic-wind (fn () (append! log "outer-before")) (fn () (dynamic-wind (fn () (append! log "inner-before")) (fn () (append! log "inner-body")) (fn () (append! log "inner-after")))) (fn () (append! log "outer-after"))) (assert= 5 (len log)) (assert= "outer-before" (nth log 0)) (assert= "inner-before" (nth log 1)) (assert= "inner-body" (nth log 2)) (assert= "inner-after" (nth log 3)) (assert= "outer-after" (nth log 4)))) (deftest "nested dynamic-wind after-thunks fire LIFO on raise" (let ((log (list))) (guard (e (true nil)) (dynamic-wind (fn () (append! log "outer-before")) (fn () (dynamic-wind (fn () (append! log "inner-before")) (fn () (append! log "inner-body") (error "boom")) (fn () (append! log "inner-after")))) (fn () (append! log "outer-after")))) (assert= 5 (len log)) (assert= "outer-before" (nth log 0)) (assert= "inner-before" (nth log 1)) (assert= "inner-body" (nth log 2)) (assert= "inner-after" (nth log 3)) (assert= "outer-after" (nth log 4)))) (deftest "before and after are called" (let ((count 0)) (dynamic-wind (fn () (set! count (+ count 1))) (fn () nil) (fn () (set! count (+ count 10)))) (assert= 11 count))) (deftest "dynamic-wind return value is body result" (let ((result (dynamic-wind (fn () nil) (fn () 42) (fn () nil)))) (assert= 42 result))) (deftest "after fires before guard handler" (let ((log (list))) (guard (e (true (append! log "guard-handler"))) (dynamic-wind (fn () nil) (fn () (error "boom")) (fn () (append! log "after")))) (assert= 2 (len log)) (assert= "after" (nth log 0)) (assert= "guard-handler" (nth log 1)))))