Checking maps and records

marick edited this page Mar 19, 2013 · 5 revisions
Clone this wiki locally

Executable examples

Using a map on the right-hand side of a prediction means you care about contents, not type:

(defrecord R [x y])

    ;; That the left-hand side below is a record is irrelevant:
    (R. 1 2) => {:x 1, :y 2}
    ;; The contents of the left are compared to the right in exactly
    ;; the same way as if both sides were maps:
    {:x 1, :y 2} => {:x 1, :y 2})

When testing code that generates records, you may require that the result be one of those records, not, say, some random map:

(fact "using a record on the right implies that you care about *both* contents and type"
  {:x 1, :y 2} =not=> (R. 1 2)
  (NotR. 1 2)  =not=> (R. 1 2)
  (R. 1 2)     =>     (R. 1 2)))

just applies extended equality to values

Use just if you want a more flexible check of values than equality. For example:

(fact "`just` provides extended equality"
  {:a 1, :b 2, :c "some text"} => (just {:a odd?, :b 2, :c #"text"}))

contains works with subsets of maps or records

Use contains when you don't care about parts of a map or record:

(fact "contains ignores unmentioned keys"
  (R. 1 'IGNORE!) => (contains {:x 1}))

contains also provides extended equality:

(fact "`contains` provides extended equality"
  (R. 1 'IGNORE) => (contains {:x odd?}))

In both of the previous examples, contains will ignore the type of the left-hand size. If you want to say specifically that the left-hand side is an R that contains an odd :x, use a combining checker:

  (R. 1 'IGNORE!) => (every-checker #(instance? R %)
                                    (contains {:x 1})))

has works with quantifiers and values

has lets you make quantified ("every" "some") claims about the values of a map or record:

(fact "`'has` quantifies over values"
  {:a 1, :b 3} => (has every? odd?))

Making claims about keys is more awkward:

(fact "ways to make claims about keys"
  (keys {:x 1, :y 1}) => (just #{:x :y})            ;; Contains every key
  {:x 1, :y 1} => (just {:x anything, :y anything}) ;; a variant

  (keys {:x 1, :y 1}) => (contains #{:x}) ;; Contains some of the keys
  {:x 1, :y 1} => (contains {:x anything}))

Map entries

The just and contains right-hand sides can take arrays of pairs (or Java MapEntry objects) instead of a map or record:

(fact "a sequence of key/value pairs is OK on the right-hand side"
  {:a 1, :b 2} => (just [[:a 1] [:b 2]])
  (R. 1 nil) => (contains [[:x 1]]))