# Checking sequential collections

##### Clone this wiki locally

Executable examples

The checkers relevant to sequential collections are `just`, `contains`, `has-prefix`, `has-suffix`, `has` and `n-of`. They apply to strings, too, but the details are more helpfully explained separately.

A sequential collection on the right-hand side of a prediction is checked using equality. As is typical for Clojure, that means that lists and vectors and lazy sequences can all be equal to one another:

```(fact
'(1 2 3) => [1 2 3]
[1 '(2) 3] => '(1 [2] 3)
(map inc (range 0 3)) => [1 2 3])```

## `just` - the actual and expected results must have the same number of elements.

If you want a comparison that uses extended equality instead of equality, you can use `just`:

```(fact "just uses extended equality"
[1 2 3] => (just [odd? even? odd?])
["a" "aa" "aaa"] (just [#"a+" #"a+" #"a+"]))```

As a side note, the second prediction can be more economically written like this:

`(fact ["a" "aa" "aaa"] => (three-of #"a+"))`

`three-of` (more generally, `n-of`, is covered below.)

Since `just` always takes a collection, wrapping the expected collection in brackets or quoted parentheses is redundant. So they can be omitted.

```(fact "when `just` takes no options, you can omit brackets"
[1 2 3] => (just odd? even? odd?))```

Whether you do that is very much a matter of taste.

`just` isn't as convenient for trees as it is for flat lists because extended equality in `just` is not recursive. That is:

```(fact "extended equality only applies to the top level"
[[[1]]] =not=> (just [[[odd?]]]))```

If you want extended equality to apply to embedded structures, you have to use `just` (or other checkers) at each level:

```(fact "you have to do this"
[[[1]]] => (just (just (just odd?))))```

At some point, I hope to see checkers tailored to make terse expected results for tree structures, but they don't exist yet.

### order

It's sometimes the case that you care about the contents of the sequence, but not the order. You can do that by using a set in `just`:

`(fact [2 1 3] => (just #{1 2 3}))`

... but it's perhaps better to be explicit with the `:in-any-order` flag:

```(fact "you can specify that order is irrelevant"
[2 1 3] => (just [1 2 3] :in-any-order))```

(Note: you can leave out the brackets in this case as well, but that looks creepy to me.)

Midje goes to some effort not to be fooled by overcommitting to matches. For example, consider this:

`(fact [1 3] => (just [odd? 1] :in-any-order))`

If Midje decided that the actual value `1` matched `odd?`, then a mismatch of `3` and the `1` after `odd?` would lead to a spurious failure. But Midje correctly discovers the match in the alternate order.

## `contains` - the actual result may have extra elements

`contains` searches for a matching subsequence of the actual results:

```(fact "contains requires only a subset to match"
[1 2 3] => (contains even? odd?))```

(Note that `contains`, like `just`, allows you to omit brackets.)

`contains` searches for a contiguous sequence of matches. That is:

`(fact [1 2 3] =not=> (contains odd? odd?))`

If you want to relax that requirement, use `:gaps-ok`:

`(fact [1 2 3] => (contains [odd? odd?] :gaps-ok))`

`contains`, like `just`, supports `:in-any-order`. Here's an example that uses both it and `:gaps-ok`.

`(fact [5 1 4 2] => (contains [1 2 5] :gaps-ok :in-any-order))`

You can also use a set if you want to be more terse:

`(fact [5 1 4 2] => (contains #{1 2 5} :gaps-ok))`

Note: the algorithm used for this complicated case is inefficient and also won't work on longer sequences. I keep hoping someone will replace it.

## `has-prefix` and `has-suffix` for anchored subsequences

Whereas `contains` finds matches anywhere within the sequence, `has-prefix` forces the match to be at the beginning:

```(fact "has-prefix is anchored to the left"
[1 2 3] =not=> (has-prefix [2 3])     ; it's not a prefix
[1 2 3] =>     (has-prefix [1 2])
[1 2 3] =not=> (has-prefix [2 1])     ; order matters
[1 2 3] =>     (has-prefix [2 1] :in-any-order)
[1 2 3] =>     (has-prefix #{2 1}))```

`has-suffix` is like `has-prefix`, except the match has to be at the very end.

## `n-of` and friends

These are used to avoid giving `just` a sequence of n identical elements:

```(fact "one checker to match exactly N elements."
["a"] => (one-of "a")
[:k :w] => (two-of keyword?)
["a" "aa" "aaa"] => (three-of #"a+")
;; ...
[1 3 5 7 9 11 13 15 17] => (nine-of odd?)
["a" "b" "c" "d" "e" "f" "g" "h" "i" "j"] => (ten-of string?)

;; to go above ten-of
(repeat 100 "a") => (n-of "a" 100))```

Note that `n-of` and friends use extended equality. So here's how you might check for a 2x2 array of even numbers:

```(fact "the result is an even square"
[[2 4]
[6 8]] => (two-of (two-of even?)))```

## `has` checks a property against some or all of the sequence values

You can apply Clojure's quantification functions (`every?`, `some`, and so on) to all the values of a sequence:

```(fact
[2 3 4] =>     (has some odd?)
[2 4 6] =not=> (has some odd?))```

`has` looks silly, in that it appears you can do the same with `partial`:

```(fact
[2 3 4] =>     (partial some odd?)
[2 4 6] =not=> (partial some odd?))```

That indeed works correctly. There are two reasons to use `has` instead:

1. You can use regular expressions, which match according to the rules of extended-equality.

```(fact
["ab" "aab" "aaab"] => (has every? #"a+b"))

(fact
[1 2 3] => (has not-any? #"a+b"))```
2. Some more elaborate uses of `partial` will not work as you expect:

```user=> (fact [[1] [2]] => (partial every? (just [1])))
true```

This incorrectly checks out because of how the collection checkers report failures. That's a mistake in Midje's design, one that will be fixed. In the meantime, use `has`.

Something went wrong with that request. Please try again.