views:

498

answers:

2

Hello!

Is there a matcher in Hamcrest to compare collections for equality? There is contains and containsInAnyOrder but I need equals not bound to concrete collection type. E.g. I cannot compare Arrays.asList and Map.values with Hamcrest equals.

Thanks in advance!

A: 

I cannot compare Arrays.asList and Map.values with Hamcrest equals.

This is because of hamcrest's over-zealous type signatures. You can do this equality comparison, but you need to cast the List object to Collection before it'll compile.

I often have to do casting with Hamcrest, which feels wrong, but it's the only way to get it to compile sometimes.

skaffman
A: 

Casting to a Collection may work, but it makes some assumptions about the underlying Collection implementations (e.g., order?). A more general approach would be to write your own matcher.

Here's a nearly complete matcher implementation that does what you want (you'll need to fill in the imports and describeTo method). Note that this implementation requires all elements of two collections to be equal, but not necessarily in the same order.

public class IsCollectionOf<T> extends TypeSafeMatcher<Collection<T>> {
    private final Collection<T> expected;
    public IsCollectionOf(Collection<T> expected) {
        this.expected = expected;
    }
    public boolean matchesSafely(Collection<T> given) {
        List<T> tmp = new ArrayList<T>(expected);
        for (T t : given) {
            if (!tmp.remove(t)) {
                return false;
            }
        return tmp.isEmpty();
    }
    // describeTo here
    public static <T> Matcher<Collection<T>> ofItems(T... items) {
        return new IsCollectionOf<T>(Arrays.asList(items));
    }
}
Mark