(defsuite
  "closure-isolation"
  (deftest
    "basic factory: two closures are independent"
    (let
      ((mk (fn (x) (fn () x))) (a (mk 1)) (b (mk 2)))
      (assert-equal (a) 1)
      (assert-equal (b) 2)))
  (deftest
    "factory with multiple params"
    (let
      ((mk (fn (x y) (fn (s) (str x s y))))
        (a (mk "A" "1"))
        (b (mk "B" "2"))
        (c (mk "C" "3")))
      (assert-equal (a "-") "A-1")
      (assert-equal (b "-") "B-2")
      (assert-equal (c "-") "C-3")))
  (deftest
    "earlier closure unaffected by later factory call"
    (let
      ((mk (fn (x y) (fn (s) (str x s y)))) (a (mk "A" "1")))
      (let
        ((b (mk "B" "2")) (c (mk "C" "3")))
        (assert-equal (a "x") "Ax1")
        (assert-equal (b "x") "Bx2")
        (assert-equal (c "x") "Cx3"))))
  (deftest
    "factory with nil branch (make-page-fn pattern)"
    (let
      ((mk (fn (default prefix suffix) (fn (slug) (if (nil? slug) default (str prefix slug suffix)))))
        (examples (mk "EX-DEFAULT" "EX-" ""))
        (sxtp (mk "SX-DEFAULT" "SX-" "-content")))
      (assert-equal (examples nil) "EX-DEFAULT")
      (assert-equal (examples "counter") "EX-counter")
      (assert-equal (sxtp nil) "SX-DEFAULT")
      (assert-equal (sxtp "overview") "SX-overview-content")
      (assert-equal (examples nil) "EX-DEFAULT")))
  (deftest
    "ten closures from same factory all independent"
    (let
      ((mk (fn (tag) (fn () tag)))
        (fns (map mk (list "a" "b" "c" "d" "e" "f" "g" "h" "i" "j"))))
      (assert-equal
        (map (fn (f) (f)) fns)
        (list "a" "b" "c" "d" "e" "f" "g" "h" "i" "j"))))
  (deftest
    "nested factory: inner closures independent"
    (let
      ((outer (fn (x) (fn (y) (fn () (str x y))))))
      (let
        ((a (outer "A")) (b (outer "B")))
        (let
          ((a1 (a "1")) (a2 (a "2")) (b1 (b "1")))
          (assert-equal (a1) "A1")
          (assert-equal (a2) "A2")
          (assert-equal (b1) "B1")
          (assert-equal (a1) "A1")))))
  (deftest
    "closure captures survive across define"
    (do
      (define _ci-mk (fn (x y) (fn (s) (str x s y))))
      (define _ci-f1 (_ci-mk "A" "1"))
      (define _ci-f2 (_ci-mk "B" "2"))
      (define _ci-f3 (_ci-mk "C" "3"))
      (assert-equal (_ci-f1 "-") "A-1")
      (assert-equal (_ci-f2 "-") "B-2")
      (assert-equal (_ci-f3 "-") "C-3")
      (assert-equal (_ci-f1 "x") "Ax1"))))
