snowape
snowape

Reputation: 1404

Can I include a message in pre and postconditions

I have this (not (some #(= (:length %1) 0) %)) as a postcondition. Written like this it's pretty clear, but when this condition isn't met I get this:

Assert failed: (not (some (fn* [p1__17852#] (= (:length p1__17852#) 0)) %))

Which isn't very readable. Is there a way to define the message for a postcondition, or for a precondition?

Edit 1:

Following noahlz and noisesmiths suggestion, (but using an external named function):

(defn not-zero-length
  [evseq]
  (not (some (fn [item] (= (:length item) 0)) evseq)))

(defn my-func
  [evseq]
  {:post [(not-zero-length %)]}
  evseq)

(my-func '({:length 3}{:length 0}))

gives:

AssertionError Assert failed: (not-zero-length %)

Which is alot clearer.

Upvotes: 8

Views: 1354

Answers (3)

shark8me
shark8me

Reputation: 668

This post in the same thread suggests the use of the clojure.test/is macro, which returns a meaningful error message.

(require '[clojure.test :refer [is]])

(defn get-key [m k]
  {:pre [(is (map? m) "m is not a map!")]}
  (m k))

(get-key [] 0)

returns

FAIL in clojure.lang.PersistentList$EmptyList@1 (form-init8401797809408331100.clj:2)
m is not a map!
expected: (map? m)
  actual: (not (map? []))
AssertionError Assert failed: (is (map? m) "m is not a map!")  

Upvotes: 6

O.Powell
O.Powell

Reputation: 172

This is discussed in the following clojure mailing list thread.

Looking at the clojure.core source you can see the fn macro only passes in a boolean to the assert function, and does not include an optional parameter for passing an additional message argument in.

So it looks like there is no way to do this cleanly yet.

Upvotes: 7

noisesmith
noisesmith

Reputation: 20194

expanding on a suggestion above:

(not (some (fn zero-length [item] (= (:length item) 0)) %))

when you name an anonymous function, any errors involving that fn will be more readable

also, how is it that you have two % substitutions above? #() does not nest.

Upvotes: 2

Related Questions