Skip to content

Commit ccf40b4

Browse files
committed
Improve documentation and tests cases
1 parent 1db9ff4 commit ccf40b4

File tree

3 files changed

+57
-25
lines changed

3 files changed

+57
-25
lines changed

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ for a specific value, e.g.
163163
- Note: Given that the default matcher for maps is `embeds`, nested maps continue being matched with embeds (instead of also being matched with `equals`). Check out 'Overriding default matchers' below for instructions on how to match nested maps with equals too.
164164
- sequence: matches when the `expected` sequences's matchers match the given sequence. Similar to midje's `(just expected)`
165165
- set: matches when all the elements in the given set can be matched with a matcher in `expected` set and each matcher is used exactly once.
166+
- `strictly equals`: overrides map's default matchers to `equals`, using it for nested structures (see Overriding default matchers, below)
166167
- `embeds` operates over maps, sequences, and sets
167168
- map: matches when the map contains some of the same key/values as the `expected` map.
168169
- sequence: order-agnostic matcher that will match when provided a subset of the `expected` sequence. Similar to midje's `(contains expected :in-any-order :gaps-ok)`
@@ -264,11 +265,11 @@ For example, if you want to do exact map matching you need to use a log of `m/eq
264265
{:a {:b {:c 1 :extra-c 0} :extra-b 0} :extra-a 0})))
265266
```
266267

267-
This verbosity can be avoided by redefining the matcher data-type defaults using the `match-with` matcher:
268+
For convenience we've also added the built-in matcher `strictly-equals` to reduce this verbosity:
268269

269270
``` clojure
270271
(deftest exact-map-matching-with-match-with
271-
(is (match? (m/match-with [map? m/equals] {:a {:b {:c odd?}}}))
272+
(is (match? (m/strictly-equals {:a {:b {:c odd?}}}))
272273
{:a {:b {:c 1}}}))
273274
```
274275

src/cljc/matcher_combinators/matchers.cljc

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,17 @@
3434
(declare match-with)
3535

3636
(defn strictly-equals
37-
"Return a matcher for the expected value which matches nested maps with `equals`.
38-
This solves a common need of matching nested maps with strict equality.
39-
See also: `match-with`.
37+
"A matcher that always uses the `equals` matcher at every level of nesting.
4038
41-
Usage:
42-
(is (match? (strictly-equals {:a :b})
43-
{:a :b :c :d}))"
39+
Useful given that matchers usually only change the first level of the data
40+
they are applied to, leaving nested data to use the default matcher of that
41+
type of data. For instance, this can be used to assert that any nested map
42+
has exactly the same keys and matching values as provided in the `expected`,
43+
and no more.
44+
45+
Note: this excludes functions, which continue to be invoked
46+
as predicates, and regex, which continue to be invoked with `regex`,
47+
instead of being compared via the `equals` matcher."
4448
[expected]
4549
(match-with [map? equals] expected))
4650

test/clj/matcher_combinators/matchers_test.clj

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
[matcher-combinators.matchers :as m]
1010
[matcher-combinators.result :as result]
1111
[matcher-combinators.test :refer [match?]]
12-
[matcher-combinators.test-helpers :as test-helpers :refer [no-match? abs-value-matcher]])
13-
(:import [matcher_combinators.model Mismatch Missing InvalidMatcherContext InvalidMatcherType]))
12+
[matcher-combinators.test-helpers :refer [abs-value-matcher no-match?]])
13+
(:import [matcher_combinators.model InvalidMatcherContext InvalidMatcherType Mismatch Missing]))
1414

1515
(defn any? [_x] true)
1616

@@ -362,21 +362,48 @@
362362
actual)))))
363363

364364
(deftest strictly-equals-matcher
365-
(testing "passing case with one level map"
366-
(is (match? (m/strictly-equals {:a :b})
367-
{:a :b})))
368-
369-
(testing "passing case with multi level map"
370-
(is (match? (m/strictly-equals {:a :b :c {:d {:e :f}}})
371-
{:a :b :c {:d {:e :f}}})))
372-
373-
(testing "failing case with one level map"
374-
(is (no-match? (m/strictly-equals {:a :b})
375-
{:a :b :c :d})))
376-
377-
(testing "failing case with multi level map"
378-
(is (no-match? (m/strictly-equals {:a :b :c {:d {:e :f}}})
379-
{:a :b :c {:d :e}}))))
365+
(testing "nested maps"
366+
(testing "passing case"
367+
(is (match? (m/strictly-equals {:user1 {:id 5 :name "hennix"}
368+
:user2 {:id 3 :name "flynt"}})
369+
{:user1 {:id 5 :name "hennix"}
370+
:user2 {:id 3 :name "flynt"}})))
371+
372+
(testing "`strictly-equals` fails when nested maps have extra keys"
373+
(is (no-match? (m/strictly-equals {:user1 {:id 5}
374+
:user2 {:id 3}})
375+
{:user1 {:id 5 :name "hennix"}
376+
:user2 {:id 3 :name "flynt"}})))
377+
378+
(testing "`equals` still matchs when nested maps have extra keys"
379+
(is (match? (m/equals {:user1 {:id 5}
380+
:user2 {:id 3}})
381+
{:user1 {:id 5 :name "hennix"}
382+
:user2 {:id 3 :name "flynt"}})))
383+
384+
(testing "`strictly-equals` is similar to using `equals` in each map"
385+
(is (no-match? (m/equals {:user1 (m/equals {:id 5})
386+
:user2 (m/equals {:id 3})})
387+
{:user1 {:id 5 :name "hennix"}
388+
:user2 {:id 3 :name "flynt"}}))))
389+
390+
(testing "functions"
391+
(testing "`strictly-equals` does not apply `equals` to functions"
392+
(is (match? (m/strictly-equals {:x odd?})
393+
{:x 1})))
394+
395+
(testing "`equals` should be aplied directly to the function to fail"
396+
(is (no-match? (m/equals {:x (m/equals odd?)})
397+
{:x 1}))))
398+
399+
(testing "regex"
400+
(testing "`strictly-equals` does not apply `equals` to regex"
401+
(is (match? (m/strictly-equals {:x #"\s+"})
402+
{:x "abc"})))
403+
404+
(testing "`equals` should be aplied directly to the regex to fail"
405+
(is (no-match? (m/equals {:x (m/equals #"\s+")})
406+
{:x "abc"})))))
380407

381408
(def gen-processable-double
382409
(gen/double* {:infinite? false :NaN? false}))

0 commit comments

Comments
 (0)