;; lib/minikanren/tests/run.sx — Phase 3 tests for run* / run / reify.

;; --- canonical TRS one-liners ---

(mk-test "run*-eq-one" (run* q (== q 1)) (list 1))
(mk-test "run*-eq-string" (run* q (== q "hello")) (list "hello"))
(mk-test "run*-eq-symbol" (run* q (== q (quote sym))) (list (quote sym)))
(mk-test "run*-fail-empty" (run* q (== 1 2)) (list))

;; --- run with a count ---

(mk-test
  "run-3-of-many"
  (run
    3
    q
    (conde
      ((== q 1))
      ((== q 2))
      ((== q 3))
      ((== q 4))
      ((== q 5))))
  (list 1 2 3))

(mk-test "run-zero-empty" (run 0 q (== q 1)) (list))

(mk-test
  "run-1-takes-one"
  (run 1 q (conde ((== q "a")) ((== q "b"))))
  (list "a"))

;; --- reification: unbound vars get _.N left-to-right ---

(mk-test
  "reify-single-unbound"
  (run* q (fresh (x) (== q x)))
  (list (make-symbol "_.0")))

(mk-test
  "reify-pair-unbound"
  (run* q (fresh (x y) (== q (list x y))))
  (list (list (make-symbol "_.0") (make-symbol "_.1"))))

(mk-test
  "reify-mixed-bound-unbound"
  (run* q (fresh (x y) (== q (list 1 x 2 y))))
  (list
    (list 1 (make-symbol "_.0") 2 (make-symbol "_.1"))))

(mk-test
  "reify-shared-unbound-same-name"
  (run* q (fresh (x) (== q (list x x))))
  (list (list (make-symbol "_.0") (make-symbol "_.0"))))

(mk-test
  "reify-distinct-unbound-distinct-names"
  (run* q (fresh (x y) (== q (list x y x y))))
  (list
    (list
      (make-symbol "_.0")
      (make-symbol "_.1")
      (make-symbol "_.0")
      (make-symbol "_.1"))))

;; --- conde + run* ---

(mk-test
  "run*-conde-three"
  (run*
    q
    (conde ((== q 1)) ((== q 2)) ((== q 3))))
  (list 1 2 3))

(mk-test
  "run*-conde-fresh-mix"
  (run*
    q
    (conde ((fresh (x) (== q (list 1 x)))) ((== q "ground"))))
  (list (list 1 (make-symbol "_.0")) "ground"))

;; --- run* + conjunction ---

(mk-test
  "run*-conj-binds-q"
  (run* q (fresh (x) (== x 5) (== q (list x x))))
  (list (list 5 5)))

;; --- run* + condu ---

(mk-test
  "run*-condu-first-wins"
  (run* q (condu ((== q 1)) ((== q 2))))
  (list 1))

(mk-test
  "run*-onceo-trim"
  (run* q (onceo (conde ((== q "a")) ((== q "b")))))
  (list "a"))

;; --- multi-goal run ---

(mk-test
  "run*-three-goals"
  (run*
    q
    (fresh
      (x y z)
      (== x 1)
      (== y 2)
      (== z 3)
      (== q (list x y z))))
  (list (list 1 2 3)))

(mk-tests-run!)
