 (ns com.nomistech.clojure-the-language.c-850-utils.s-100-utils-test
-  (:require [com.nomistech.clojure-the-language.c-850-utils.s-100-utils :refer :all]
+  (:require [com.nomistech.clojure-the-language.c-850-utils.s-100-utils :as sut]
             [midje.sweet :refer :all]))
 
 ;;;; ___________________________________________________________________________
-;;;; ---- do1 ----
-
-(fact "`do1` works"
+;;;; ---- sut/do1 ----
+
+(fact "`sut/do1` works"
 
   (fact "Fails to compile when there are no forms"
-    (macroexpand-1 '(do1))
+    (macroexpand-1 '(sut/do1))
     => (throws clojure.lang.ArityException))
   
   (fact "Returns value of first form when there is one form"
-    (do1 :a)
+    (sut/do1 :a)
     => :a)
   
   (fact "Returns value of first form when there are two forms"
-    (do1
+    (sut/do1
         :a
       :b)
     => :a)
   
   (fact "Returns value of first form when there are three forms"
-    (do1
+    (sut/do1
         :a
       :b
       :c)


  (fact "Forms are evaluated in correct order"
    (let [side-effect-place (atom [])]
      (do2
          (swap! side-effect-place conj 1)
          (swap! side-effect-place conj 2)
        (swap! side-effect-place conj 3))

        @side-effect-place => [1 2 3]))))

;;;; ___________________________________________________________________________
;;;; ---- sut/econd ----

(fact "`sut/econd` works"
  (fact "no clauses"
    (sut/econd)
    => (throws RuntimeException))
  (fact "many clauses"
    (fact "last clause truthy"
      (sut/econd false 1
                 nil   2
                 :this-one 3)
      => 3)
    (fact "non-last clause truthy"
      (sut/econd false 1
                 nil   2
                 :this-one 3
                 :not-this-one 4)
      => 3)
    (fact "none truthy"
      (sut/econd false 1
                 nil   2
                 false 3
                 nil   4)
      => (throws RuntimeException))))

;;;; ___________________________________________________________________________
;;;; ---- sut/map-keys ----

(fact "`sut/map-keys`" works
  (sut/map-keys keyword
                {"a" 1
                 "b" 2})
  => {:a 1
      :b 2})

;;;; ___________________________________________________________________________
;;;; ---- sut/map-vals ----

(fact "`sut/map-vals`" works
  (sut/map-vals inc
                {:a 1
                 :b 2})
  => {:a 2
      :b 3})

;;;; ___________________________________________________________________________
;;;; ---- sut/transitive-closure ----

;; TODO: More substantial tests of `sut/transitive-closure`, e.g. edge cases.

(fact "`sut/transitive-closure` works"
  (sut/transitive-closure (fn [x]
                            (case x
                              1 [1 2 3 4]
                              2 [200 1]
                              3 [300 1]
                              4 [1]
                              []))
                          1)
  => #{1 2 3 4 200 300})

;;;; ___________________________________________________________________________
;;;; ---- sut/transitive-closure-excluding-self ----

;; TODO: More substantial tests of `sut/transitive-closure-excluding-self`,
;;       e.g. edge cases.

(fact "`sut/transitive-closure-excluding-self` works"
  (sut/transitive-closure-excluding-self (fn [x]
                                           (case x
                                             1 [1 2 3 4]
                                             2 [200 1]
                                             3 [300 1]
                                             4 [1]
                                             []))
                                         1)
  => #{2 3 4 200 300})

;;;; ___________________________________________________________________________
;;;; ---- sut/invert-function sut/invert-relation ----

(fact "`sut/invert-function` works"
  (sut/invert-function {:a 1
                        :b 2
                        :c 3
                        :d 1}
                       [:a :b :c :d :e])
  =>
  {1 [:a :d]
   2 [:b]
   3 [:c]})

(fact "`sut/invert-relation` works"
  (sut/invert-relation {:a [1 2]
                        :b [2 3]
                        :c []
                        :d [2]}
                       [:a :b :c :d :e])
  =>
  {1 [:a]
   2 [:a :b :d]
   3 [:b]})

;;;; ___________________________________________________________________________
;;;; ---- sut/with-extras ----

(fact "`sut/with-extras` works"

  (fact "without an exception"
    (let [side-effect-place (atom [])]
      (fact "Value is correct"
        (sut/with-extras [:before (swap! side-effect-place conj 1)
                          :after  (swap! side-effect-place conj 3)] 
          (do (swap! side-effect-place conj 2)
              :a))
        => :a)
