Search code examples
error-handlingclojurepreconditions

Clojure :pre report failing value when destructuring


Following this SO post, I would like to print the value of the preconditions in my function. However it fails for me in the following case (probably destructuring) :

I have a dir? helper function (feel free to skip this one) :

(defn dir? [s]
  "returns true if the string passed is is an existing directory"
  (->> (clojure.java.io/file s)
       ((juxt #(.exists %) #(.isDirectory %)))
       (every? true?)))

It works just fine, and using the is macro, I get some nice error messages where I can see both the test and the parameters that were passed :

(is (dir? (io/file "resources/static"))) ;; => true

(is (dir? (io/file "resources/statice"))) ;; typo, error below

FAIL in clojure.lang.PersistentList$EmptyList@1 (boot.user4515592986834245937.clj:86) expected: (dir? (io/file "resources/statice")) actual: (not (dir? #object[java.io.File 0x6730a420 "resources/statice"]))

However, when trying to use it in the precondition :pre, I get an ugly error :

(defn make-something
  [&{:keys [dir]
     :or {dir "default-dir"}}]
  {:pre [(is (dir? (clojure.java.io/file dir)))]}
  ;;... do something with these
 )

(make-something :dir "resources/statices") ;; doesn't exist

clojure.lang.Compiler$CompilerException: java.lang.AssertionError: Assert failed: (is (dir? (io/file dir))), compiling:(boot.user4515592986834245937.clj:80:12) java.lang.AssertionError: Assert failed: (is (dir? (io/file dir)))

How can I get a nice error message in my function just like the one above ?

In case it matters, I am using Clojure 1.7.


Solution

  • You need to check your code (dir? function). Following snippet works for me:

    (require '[clojure.java.io :as io])
    
    (defn dir? [s]
      (let [dir (io/file s)]
        (and (.exists dir)
             (.isDirectory dir))))
    
    (defn make-something
      [& {:keys [dir] :or {dir "default-dir"}}]
      {:pre [(is (dir? dir))]}
      (println dir))
    
    (make-something :dir "/tmp")
    out => /tmp
    ret => nil
    
    (make-something :dir "/xxxx")
    FAIL in clojure.lang.PersistentList$EmptyList@1 (form-init3332271312167175068.clj:1)
    expected: (dir? dir)
    actual: (not (dir? "/xxxx"))
    
    AssertionError Assert failed: (is (dir? dir))  user/make-sth (form-init3332271312167175068.clj:1)