10

I have a list of some objects - let's assume companies. Now I want to check if this list contains companies with some names but not taking order into consideration. Currently I'm using such construction:

companyList.name.sort() == ["First", "Second"]

Is there any operator in Spock or Groovy that allows me to compare arrays without order?

Jakub Kubrynski
  • 13,724
  • 6
  • 60
  • 85

4 Answers4

17

You can make use of Hamcrest support in Spock and use the Matcher designed explicitly for this case - containsInAnyOrder. You need the following imports:

import static org.hamcrest.Matchers.containsInAnyOrder
import static spock.util.matcher.HamcrestSupport.that

Then you can write your test code as follows:

given:
    def companyList = [ "Second", "First"]
expect:
    that companyList, containsInAnyOrder("First", "Second")

This has the benefit over using .sort() in that duplicate elements in the List will be considered correctly. The following test will fail using Hamcrest but passes using .sort()

given:
    def companyList = [ "Second", "First", "Second"]
expect:
    that companyList, containsInAnyOrder("First", "Second")

Condition not satisfied:

that companyList, containsInAnyOrder("First", "Second")
|    |
|    [Second, First, Second]
false

Expected: iterable over ["First", "Second"] in any order
     but: Not matched: "Second"

If you're using then: instead of expect: you can use the expect instead of that import for readability.

then:
    expect companyList, containsInAnyOrder("First", "Second")
tddmonkey
  • 20,798
  • 10
  • 58
  • 67
15

There's no such operator as far as I know. If the list doesn't contain any duplicates the following assertion may be used:

companyList.name as Set == ["First", "Second"] as Set

Or something like that:

companyList.name.size() == ["First", "Second"].size() && companyList.name.containsAll(["First", "Second"])
Opal
  • 81,889
  • 28
  • 189
  • 210
2

Upvoted for @Opal answer, it's probably the best in all terms. As a curiosity I would only add an example of usage of minus operator to compare two unsorted lists:

import spock.lang.Specification

class ComparingListsSpec extends Specification {

    def "should contain all companies in two unsorted lists"() {
        when:
        def companies = ["Lorem", "ipsum", "dolor", "sit", "amet"]
        def unsorted = ["ipsum", "sit", "Lorem", "dolor", "amet"]

        then:
        companies - unsorted == []

        and:
        unsorted - companies == []

        and:
        companies - unsorted in [[]]
    }
}

It also works if one of the lists contains redundant data.

Szymon Stepniak
  • 40,216
  • 10
  • 104
  • 131
  • 3
    i'd stay away from `-` for anything, that is not a trivial type. `assert [[x:0,y:0]]-[[x:1,y:1]] == []` – cfrick Feb 11 '15 at 21:45
0

Now there are dedicated matchers available in Spock:

You can compare list elements ignoring their ordering using the following operators:

  1. ==~ - Strict match (accounting for duplicated elements, etc.)
  2. =~ - Lenient match (ignoring duplicates)

So [1,2,3] ==~ [2,3,1] is truthy.

jrd
  • 3,047
  • 2
  • 23
  • 15