This is an attempt to make assert more friendly by including more details in the assertion error.
- show the result of the assertion expression
- show local variable values used in assertion form
In other words, this should make assertion errors easier to reason about:
AssertionError Assert failed: Should be equal
(= x y) => false
where x is 222
where y is 1
This approach handles form pre/post conditions as well as inline asserts.
An easy way to include in your clojure code is:
(defproject my-proj "0.1.0-SNAPSHOT"
...
:injections [(load-file "scripts/patch_assert.clj")])
NOTE: I'd love to know how to do the same for clojurecript but I can't see how. I'd appreciate any advice.
Examples of use:
(defn boom [s]
{:pre [(string? s)]}
(str s "!!!"))
=> #'user/boom
(boom "ROAR")
=> "ROAR!!!"
(boom 123)
AssertionError Assert failed: (string? s) => false
where s is 123
user/boom (form-init1236645087160261984.clj:1)
(let [x 222 y 1 z (range 10)]
(assert (= x y ) "Should be equal"))
=> #'clojure.core/assert
AssertionError Assert failed: Should be equal
(= x y) => false
where x is 222
where y is 1
user/eval9905 (form-init1236645087160261984.clj:3)
(let [x 222 y 1 z (range 10)]
(assert (= 3 (count z)) "Should be 3 long"))
=> #'clojure.core/assert
AssertionError Assert failed: Should be 3 long
(= 3 (count z)) => false
where z is (0 1 2 3 4 5 6 7 8 9)
user/eval9806 (form-init1236645087160261984.clj:3)
Test in a repl with something like this:
(load-file "scripts/patch_assert.clj")
(let [x 222 y 1 z (range 10)]
(assert (= x y ) "Should be equal"))
How it works...
- defmacro has access to
&env
which is a map of variables. Using this and the assert form we can lookup relevant variables. - lein
:injections
allows code to be run before your project code. With this we can patch the assert macro before loading project code.