Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allows to containsInAnyOrder with a Comparator #404

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeDiagnosingMatcher;
import org.hamcrest.comparator.ComparatorMatcherBuilder;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.*;

import static org.hamcrest.core.IsEqual.equalTo;

Expand Down Expand Up @@ -138,6 +136,42 @@ public static <T> Matcher<Iterable<? extends T>> containsInAnyOrder(T... items)
return new IsIterableContainingInAnyOrder<>(matchers);
}

/**
* <p>
* Creates an order agnostic matcher for {@link Iterable}s that matches when a single pass over
* the examined {@link Iterable} yields a series of items, each logically equal according to
* the comparator to one item anywhere in the specified items. For a positive match, the
* examined iterable must be of the same length as the number of specified items.
* </p>
* <p>
* N.B. each of the specified items will only be used once during a given examination, so be
* careful when specifying items that may be equal to more than one entry in an examined
* iterable.
* </p>
* <p>
* For example:
* </p>
* <pre>assertThat(Arrays.asList("first", "second"), containsInAnyOrder(new StringLengthComparator(), "abcde", "ZYXWVU"))</pre>
*
* @param <T>
* the matcher type.
* @param comparator
* the comparator to use to compare items to the items provided.
* @param items
* the items that must equal (according to the provided comparator) the items provided by
* an examined {@link Iterable} in any order
* @return The matcher.
*/
@SafeVarargs
public static <T> Matcher<Iterable<? extends T>> containsInAnyOrder(Comparator<T> comparator, T... items) {
List<Matcher<? super T>> matchers = new ArrayList<>();
for (T item : items) {
matchers.add(ComparatorMatcherBuilder.comparedBy(comparator).comparesEqualTo(item));
}

return containsInAnyOrder(matchers);
}

/**
* <p>
* Creates an order agnostic matcher for {@link Iterable}s that matches when a single pass over
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@
import org.hamcrest.collection.IsIterableContainingInOrderTest.WithValue;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;

import static java.util.Arrays.asList;
import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder;
import static org.hamcrest.collection.IsIterableContainingInOrderTest.make;
import static org.hamcrest.collection.IsIterableContainingInOrderTest.value;
import static org.hamcrest.collection.IsIterableContainingInAnyOrderTest.Item.item;

public class IsIterableContainingInAnyOrderTest extends AbstractMatcherTest {

Expand Down Expand Up @@ -52,4 +56,98 @@ public void testHasAReadableDescription() {
assertDescription("iterable with items [<1>, <2>] in any order", containsInAnyOrder(1, 2));
}

private static final ItemValueComparator comparator = new ItemValueComparator();

private static class ItemValueComparator implements Comparator<Item> {
@Override
public int compare(Item o1, Item o2) {
return Integer.compare(o1.value, o2.value);
}

@Override
public String toString() {
return ItemValueComparator.class.getSimpleName();
}
}

public static class Item {
private final String key;
private final int value;

private Item(String key, int value) {
this.key = key;
this.value = value;
}

public static Item item(String key, int value) {
return new Item(key, value);
}

public int getValue() {
return value;
}

@Override
public String toString() {
return key + ":" + value;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Item item = (Item) o;
return Objects.equals(key, item.key);
}

@Override
public int hashCode() {
return Objects.hash(key);
}
}

public void testMatchesSingleItemIterableWithComparator() {
assertMatches("single item", containsInAnyOrder(comparator, item("key", 1)), Collections.singletonList(item("foo", 1)));
}

public void testDoesNotMatchEmptyWithComparator() {
List<Integer> actual = Collections.<Integer>emptyList();
Matcher<Iterable<? extends Item>> expected = containsInAnyOrder(comparator, item("key", 5), item("key", 10));
assertMismatchDescription("no item matches: a value equal to <key:5> when compared by <ItemValueComparator>, a value equal to <key:10> when compared by <ItemValueComparator> in []", expected, actual);
}

public void testMatchesIterableOutOfOrderWithComparator() {
List<Item> actual = asList(item("foo", 2), item("bar", 1));
Matcher<Iterable<? extends Item>> expected = containsInAnyOrder(comparator, item("key", 1), item("key", 2));
assertMatches("Out of order", expected, actual);
}

public void testMatchesIterableInOrderWithComparator() {
List<Item> actual = asList(item("foo", 1), item("bar", 2));
Matcher<Iterable<? extends Item>> expected = containsInAnyOrder(comparator, item("key", 1), item("key", 2));
assertMatches("In order", expected, actual);
}

public void testDoesNotMatchIfOneOfMultipleElementsMismatchesWithComparator() {
List<Item> actual = asList(item("foo", 1), item("bar", 2), item("baz", 4));
Matcher<Iterable<? extends Item>> expected = containsInAnyOrder(comparator, item("key", 1), item("key", 2), item("key", 3));
assertMismatchDescription("not matched: <baz:4>", expected, actual);
}

public void testDoesNotMatchIfThereAreMoreElementsThanMatchersWithComparator() {
List<Item> actual = asList(item("foo", 1), item("bar", 2), item("baz", 3));
final Matcher<Iterable<? extends Item>> expected = containsInAnyOrder(comparator, item("key", 1), item("key", 3));
assertMismatchDescription("not matched: <bar:2>", expected, actual);
}

public void testDoesNotMatchIfThereAreMoreMatchersThanElementsWithComparator() {
List<Item> actual = asList(item("foo", 1), item("bar", 2));
Matcher<Iterable<? extends Item>> expected = containsInAnyOrder(comparator, item("key", 1), item("key", 2), item("key", 3));
assertMismatchDescription("no item matches: a value equal to <key:3> when compared by <ItemValueComparator> in [<foo:1>, <bar:2>]", expected, actual);
}

public void testHasAReadableDescriptionWithComparator() {
assertDescription("iterable with items [a value equal to <foo:1> when compared by <ItemValueComparator>, a value equal to <bar:2> when compared by <ItemValueComparator>] in any order",
containsInAnyOrder(comparator, item("foo", 1), item("bar", 2)));
}
}