;; lib/minikanren/tests/clpfd-in-label.sx — fd-in (domain narrowing) + fd-label.

;; --- fd-in: domain narrowing ---

(mk-test
  "fd-in-bare-label"
  (run*
    q
    (fresh
      (x)
      (fd-in x (list 1 2 3 4 5))
      (fd-label (list x))
      (== q x)))
  (list 1 2 3 4 5))

(mk-test
  "fd-in-intersection"
  (run*
    q
    (fresh
      (x)
      (fd-in x (list 1 2 3 4 5))
      (fd-in x (list 3 4 5 6 7))
      (fd-label (list x))
      (== q x)))
  (list 3 4 5))

(mk-test
  "fd-in-disjoint-empty"
  (run*
    q
    (fresh
      (x)
      (fd-in x (list 1 2 3))
      (fd-in x (list 7 8 9))
      (fd-label (list x))
      (== q x)))
  (list))

(mk-test
  "fd-in-singleton-domain"
  (run*
    q
    (fresh (x) (fd-in x (list 5)) (fd-label (list x)) (== q x)))
  (list 5))

;; --- ground value checks the domain ---

(mk-test
  "fd-in-ground-in-domain"
  (run*
    q
    (fresh
      (x)
      (== x 3)
      (fd-in x (list 1 2 3 4 5))
      (== q x)))
  (list 3))

(mk-test
  "fd-in-ground-not-in-domain"
  (run*
    q
    (fresh
      (x)
      (== x 9)
      (fd-in x (list 1 2 3 4 5))
      (== q x)))
  (list))

;; --- fd-label across multiple vars ---

(mk-test
  "fd-label-multiple-vars"
  (let
    ((res (run* q (fresh (a b) (fd-in a (list 1 2 3)) (fd-in b (list 10 20)) (fd-label (list a b)) (== q (list a b))))))
    (= (len res) 6))
  true)

(mk-test
  "fd-label-empty-vars"
  (run* q (fd-label (list)))
  (list (make-symbol "_.0")))

;; --- composition with regular goals ---

(mk-test
  "fd-in-with-membero-style-filtering"
  (run*
    q
    (fresh
      (x)
      (fd-in
        x
        (list
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10))
      (fd-label (list x))
      (== q x)))
  (list
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10))

(mk-tests-run!)
