How to check if collection contains items in given order using Hamcrest

JavaCollectionsHamcrest

Java Problem Overview


How to check using Hamcrest if given collection is containing given items in given order? I tried hasItems but it simply ignores the order.

List<String> list = Arrays.asList("foo", "bar", "boo");

assertThat(list, hasItems("foo", "boo"));

//I want this to fail, because the order is different than in "list"
assertThat(list, hasItems("boo", "foo")); 

Java Solutions


Solution 1 - Java

You can use contains matcher instead, but you probably need to use latest version of Hamcrest. That method checks the order.

assertThat(list, contains("foo", "boo"));

You can also try using containsInAnyOrder if order does not matter to you.

That's the code for contains matcher:

  public static <E> Matcher<Iterable<? extends E>> contains(List<Matcher<? super E>> itemMatchers)
  {
    return IsIterableContainingInOrder.contains(itemMatchers);
  }

Solution 2 - Java

To check tha collection contains items in expected (given) order you can use Hamcrest's containsInRelativeOrder method.

From javadoc:

> Creates a matcher for Iterable's that matches when a single pass over > the examined Iterable yields a series of items, that contains items > logically equal to the corresponding item in the specified items, in > the same relative order For example: assertThat(Arrays.asList("a", > "b", "c", "d", "e"), containsInRelativeOrder("b", "d")).

Actual for Java Hamcrest 2.0.0.0.

Hope this helps.

Solution 3 - Java

You need to implement a custom Matcher, something like this

class ListMatcher extends BaseMatcher {
	String[] items;

	ListMatcher(String... items) {
		this.items = items;
	}

	@Override
	public boolean matches(Object item) {
		List list = (List) (item);
		int l = -1;
		for (String s : items) {
			int i = list.indexOf(s);
			if (i == -1 || i < l) {
			    return false;
			}
			l = i;
		}
		return true;
	}
	
	@Override
	public void describeTo(Description description) {
		// not implemented
	}
}

@Test
public void test1() {
	List<String> list = Arrays.asList("foo", "bar", "boo");
	Assert.assertThat(list, new ListMatcher("foo", "boo"));
	Assert.assertThat(list, new ListMatcher("boo", "foo"));
}

Solution 4 - Java

The accepted answer is not working for me. It still fails, saying

Expected: iterable containing ["foo", "boo"] but: Not matched: "bar"

So I wrote my own IsIterableContainingInRelativeOrder, and submitted it as a patch.

Solution 5 - Java

I found a solution at http://www.baeldung.com/hamcrest-collections-arrays

Look for the section that has an example with strict order.

List<String> collection = Lists.newArrayList("ab", "cd", "ef");
assertThat(collection, contains("ab", "cd", "ef"));

Basically you need to use the contains Matcher (org.hamcrest.Matchers.contains)

Solution 6 - Java

You can combine is and equalTo of matchers library. The assert statement looks longer but the error message is better. Since contains is fail first it breaks when it finds the first mismatch and wouldn't find failures further down the list. Where as is and equalTo will print the entire list from which you see all the mismatches.

Example using contains

List<String> list = Arrays.asList("foo", "bar", "boo");
assertThat(list, contains("foo", "boo", "bar"));

Gives the following error message:

Expected: iterable containing ["foo", "boo", "bar"]
 but: item 1: was "bar"

Example using is and equalTo

List<String> list = Arrays.asList("foo", "bar", "boo");
assertThat(list, is(equalTo(Lists.newArrayList("foo", "boo", "bar"))));

Gives the following error message:

Expected: is <[foo, boo, bar]>
     but: was <[foo, bar, boo]>

The second method doesn't tell you the index where the mismatch is but to me this is still better as you can fix the test by looking at the failure message just once. Whereas in method one, you'll first fix index 1, run the test, detect mismatch at index 2 and do the final fix.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMariusz JamroView Question on Stackoverflow
Solution 1 - JavaAndrey AdamovichView Answer on Stackoverflow
Solution 2 - JavanndruView Answer on Stackoverflow
Solution 3 - JavaEvgeniy DorofeevView Answer on Stackoverflow
Solution 4 - JavaKevin PauliView Answer on Stackoverflow
Solution 5 - JavaAndreas GutherView Answer on Stackoverflow
Solution 6 - JavaSelvaram GView Answer on Stackoverflow