;; lib/minikanren/tests/laziness.sx — verify Zzz wrapping (in conde)
;; lets infinitely-recursive relations produce finite prefixes via run-n.

;; --- a relation that has no base case but conde-protects via Zzz ---

(define
  listo-aux
  (fn
    (l)
    (conde ((nullo l)) ((fresh (a d) (conso a d l) (listo-aux d))))))

(mk-test
  "infinite-relation-truncates-via-run-n"
  (run 4 q (listo-aux q))
  (list
    (list)
    (list (make-symbol "_.0"))
    (list (make-symbol "_.0") (make-symbol "_.1"))
    (list (make-symbol "_.0") (make-symbol "_.1") (make-symbol "_.2"))))

;; --- two infinite generators interleaved via mk-disj must both produce
;;     answers (no starvation) — the fairness test ---

(define
  ones-gen
  (fn
    (l)
    (conde
      ((== l (list)))
      ((fresh (d) (conso 1 d l) (ones-gen d))))))

(define
  twos-gen
  (fn
    (l)
    (conde
      ((== l (list)))
      ((fresh (d) (conso 2 d l) (twos-gen d))))))

(mk-test
  "interleaving-keeps-both-streams-alive"
  (let
    ((res (run 4 q (mk-disj (ones-gen q) (twos-gen q)))))
    (and
      (= (len res) 4)
      (and
        (some
          (fn
            (x)
            (and
              (list? x)
              (and (not (empty? x)) (= (first x) 1))))
          res)
        (some
          (fn
            (x)
            (and
              (list? x)
              (and (not (empty? x)) (= (first x) 2))))
          res))))
  true)

;; --- run* terminates on a relation whose conde has finite base case
;;     reached from any starting point ---

(mk-test
  "run-star-terminates-on-bounded-relation"
  (run*
    q
    (fresh
      (l)
      (== l (list 1 2 3))
      (listo l)
      (== q :ok)))
  (list :ok))

(mk-tests-run!)
