;; lib/minikanren/tests/fresh.sx — Phase 2 piece B tests for `fresh`.

;; --- empty fresh: pure goal grouping ---

(mk-test
  "fresh-empty-vars-equiv-conj"
  (stream-take 5 ((fresh () (== 1 1)) empty-s))
  (list empty-s))

(mk-test
  "fresh-empty-vars-no-goals-is-succeed"
  (stream-take 5 ((fresh ()) empty-s))
  (list empty-s))

;; --- single var ---

(mk-test
  "fresh-one-var-bound"
  (let
    ((s (first (stream-take 5 ((fresh (x) (== x 7)) empty-s)))))
    (first (vals s)))
  7)

;; --- multiple vars + multiple goals ---

(mk-test
  "fresh-two-vars-three-goals"
  (let
    ((q (mk-var "q"))
      (g
        (fresh
          (x y)
          (== x 10)
          (== y 20)
          (== q (list x y)))))
    (mk-walk* q (first (stream-take 5 (g empty-s)))))
  (list 10 20))

(mk-test
  "fresh-three-vars"
  (let
    ((q (mk-var "q"))
      (g
        (fresh
          (a b c)
          (== a 1)
          (== b 2)
          (== c 3)
          (== q (list a b c)))))
    (mk-walk* q (first (stream-take 5 (g empty-s)))))
  (list 1 2 3))

;; --- fresh interacts with disj ---

(mk-test
  "fresh-with-disj"
  (let
    ((q (mk-var "q")))
    (let
      ((g (fresh (x) (mk-disj (== x 1) (== x 2)) (== q x))))
      (let
        ((res (stream-take 5 (g empty-s))))
        (map (fn (s) (mk-walk q s)) res))))
  (list 1 2))

;; --- nested fresh ---

(mk-test
  "fresh-nested"
  (let
    ((q (mk-var "q"))
      (g
        (fresh
          (x)
          (fresh
            (y)
            (== x 1)
            (== y 2)
            (== q (list x y))))))
    (mk-walk* q (first (stream-take 5 (g empty-s)))))
  (list 1 2))

;; --- call-fresh (functional alternative) ---

(mk-test
  "call-fresh-binds-and-walks"
  (let
    ((s (first (stream-take 5 ((call-fresh (fn (x) (== x 99))) empty-s)))))
    (first (vals s)))
  99)

(mk-test
  "call-fresh-distinct-from-outer-vars"
  (let
    ((q (mk-var "q")))
    (let
      ((g (call-fresh (fn (x) (mk-conj (== x 5) (== q (list x x)))))))
      (mk-walk* q (first (stream-take 5 (g empty-s))))))
  (list 5 5))

(mk-tests-run!)
