;;  Copyright (c) Jeffrey Straszheim. All rights reserved.  The use and
;;  distribution terms for this software are covered by the Eclipse Public
;;  License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) which can
;;  be found in the file epl-v10.html at the root of this distribution.  By
;;  using this software in any fashion, you are agreeing to be bound by the
;;  terms of this license.  You must not remove this notice, or any other,
;;  from this software.
;;
;;  test-rules.clj
;;
;;  A Clojure implementation of Datalog -- Rule Tests
;;
;;  straszheimjeffrey (gmail)
;;  Created 12 Feburary 2009


(ns clojure.contrib.datalog.tests.test-rules
  (:use clojure.test
        clojure.contrib.datalog.rules
        clojure.contrib.datalog.literals
        clojure.contrib.datalog.database))


(def tr-1 (<- (:fred :x ?x :y ?y) (:mary :x ?x :z ?z) (:sally :z ?z :y ?y)))
(def tr-2 (<- (:fred) (not! :mary :x 3)))
(def tr-3 (<- (:fred :x ?x :y ?y) (if > ?x ?y) (:mary :x ?x) (:sally :y ?y)))



(deftest test-rule-safety
  (is (thrown-with-msg? Exception #".*Head vars.*not bound.*"
         (<- (:fred :x ?x) (:sally :y ?y))))
  (is (thrown-with-msg? Exception #".*Body vars.*not bound.*negative position.*"
         (<- (:fred :x ?x) (:becky :x ?x) (not! :sally :y ?y))))
  (is (thrown-with-msg? Exception #".*Body vars.*not bound.*negative position.*"
         (<- (:fred :x ?x) (:becky :x ?x) (if > ?x ?y)))))


(deftest test-sip
  (is (= (compute-sip #{:x} #{:mary :sally} tr-1)
         (<- ({:pred :fred :bound #{:x}} :x ?x :y ?y)
                      ({:pred :mary :bound #{:x}} :z ?z :x ?x)
                      ({:pred :sally :bound #{:z}} :y ?y :z ?z))))

  (is (= (compute-sip #{} #{:mary :sally} tr-1)
         (<- (:fred :y ?y :x ?x) (:mary :z ?z :x ?x) ({:pred :sally :bound #{:z}} :y ?y :z ?z))))

  (is (= (compute-sip #{} #{:mary} tr-2)
         (<- (:fred) (not! {:pred :mary :bound #{:x}} :x 3))))
  
  (is (= (compute-sip #{} #{} tr-2)
         tr-2))

  (is (= (display-rule (compute-sip #{:x} #{:mary :sally} tr-3))
         (display-rule (<- ({:pred :fred :bound #{:x}} :x ?x :y ?y)
                               ({:pred :mary :bound #{:x}} :x ?x)
                               (:sally :y ?y)
                               (if > ?x ?y))))))
                   ; Display rule is used because = does not work on
                   ; (if > ?x ?y) because it contains a closure


(def rs
     (rules-set
        (<- (:path :a ?x :b ?y) (:edge :a ?x :b ?y))
        (<- (:path :a ?x :b ?y) (:edge :a ?x :b ?z) (:path :a ?z :b ?y))
        (<- (:edge :a ?x :b ?y) (:route :a ?x :b ?y) (if not= ?x ?y))))

(deftest test-rules-set
  (is (= (count rs) 3))
  (is (contains? rs (<- (:path :a ?x :b ?y) (:edge :a ?x :b ?z) (:path :a ?z :b ?y)))))
  
(deftest test-predicate-map
  (let [pm (predicate-map rs)]
    (is (= (pm :path)
           #{(<- (:path :a ?x :b ?y) (:edge :a ?x :b ?y))
             (<- (:path :a ?x :b ?y) (:edge :a ?x :b ?z) (:path :a ?z :b ?y))}))
    (is (= (-> :edge pm count) 1))))


(def db1 (make-database
           (relation :fred [:x :y])
           (index :fred :x)
           (relation :sally [:x])
           (relation :ben [:y])))

(def db2 (add-tuples db1
             [:fred :x 1 :y :mary]
             [:fred :x 1 :y :becky]
             [:fred :x 3 :y :sally]
             [:fred :x 4 :y :joe]
             [:fred :x 4 :y :bob]
             [:sally :x 1]
             [:sally :x 2]
             [:sally :x 3]
             [:sally :x 4]
             [:ben :y :bob]))


(deftest test-apply-rule
  (is (= (apply-rule db2 empty-database (<- (:becky :y ?y) (:sally :x ?x)
                                                           (:fred :x ?x :y ?y)
                                                           (not! :ben :y ?y)
                                                           (if not= ?x 3)))
         (datalog-database
          {
           :becky
           (datalog-relation
            ;; Schema
            #{:y}
            ;; Data
            #{
              {:y :joe}
              {:y :mary}
              {:y :becky}
              }
            ;; Indexes
            {
             })
           }))))




(comment
  (run-tests)
)

;; End of file

