;; lib/flow/tests/hygiene.sx — Phase 5: store hygiene (flow/gc, flow/forget).

(define flow-hyg-pass 0)
(define flow-hyg-fail 0)
(define flow-hyg-fails (list))

(define
  flow-hyg-test
  (fn
    (name actual expected)
    (if
      (= actual expected)
      (set! flow-hyg-pass (+ flow-hyg-pass 1))
      (begin
        (set! flow-hyg-fail (+ flow-hyg-fail 1))
        (append! flow-hyg-fails {:name name :expected expected :actual actual})))))

(define flow-h (fn (src) (flow-run src)))

;; ── flow/gc ─────────────────────────────────────────────────────
(flow-hyg-test
  "gc: empty store removes nothing"
  (flow-h "(flow/gc)")
  0)
(flow-hyg-test
  "gc: removes a done flow, keeps a suspended one"
  (flow-h
    "(defflow w (lambda (x) (suspend (quote q)))) (flow/start w 0) (flow/start (lambda (x) x) 5) (define removed (flow/gc)) (list removed (flow/list))")
  (list 1 (list (list 1 "suspended"))))
(flow-hyg-test
  "gc: removes a cancelled flow"
  (flow-h
    "(defflow w (lambda (x) (suspend (quote q)))) (define id (car (cdr (flow/start w 0)))) (flow/cancel id) (flow/gc)")
  1)
(flow-hyg-test
  "gc: a kept suspended flow is still resumable"
  (flow-h
    "(defflow w (sequence (lambda (x) (suspend (quote q))) (lambda (v) (* v 2)))) (define id (car (cdr (flow/start w 0)))) (flow/start (lambda (x) x) 1) (flow/gc) (flow/resume id 21)")
  42)
(flow-hyg-test
  "gc: counts every terminal flow it drops"
  (flow-h
    "(flow/start (lambda (x) x) 1) (flow/start (lambda (x) x) 2) (defflow w (lambda (x) (suspend (quote q)))) (flow/start w 0) (flow/gc)")
  2)

;; ── flow/forget ─────────────────────────────────────────────────
(flow-hyg-test
  "forget: drops a completed flow"
  (flow-h
    "(defflow w (sequence (lambda (x) (suspend (quote q))) (lambda (v) v))) (define id (car (cdr (flow/start w 0)))) (flow/resume id 7) (list (flow/forget id) (flow/status id))")
  (list true "unknown"))
(flow-hyg-test
  "forget: refuses to drop a live (suspended) flow"
  (flow-h
    "(defflow w (lambda (x) (suspend (quote q)))) (define id (car (cdr (flow/start w 0)))) (list (flow/forget id) (flow/status id))")
  (list false "suspended"))
(flow-hyg-test
  "forget: drops a cancelled flow"
  (flow-h
    "(defflow w (lambda (x) (suspend (quote q)))) (define id (car (cdr (flow/start w 0)))) (flow/cancel id) (list (flow/forget id) (flow/status id))")
  (list true "unknown"))
(flow-hyg-test
  "forget: unknown id yields false"
  (flow-h "(flow/forget 999)")
  false)

(define flow-hyg-tests-run! (fn () {:total (+ flow-hyg-pass flow-hyg-fail) :passed flow-hyg-pass :failed flow-hyg-fail :fails flow-hyg-fails}))
