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

Map entry matchers #160

Open
wants to merge 3 commits 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
83 changes: 83 additions & 0 deletions hamcrest-library/src/main/java/org/hamcrest/Matchers.java
Original file line number Diff line number Diff line change
Expand Up @@ -1112,6 +1112,89 @@ public static <K, V> org.hamcrest.Matcher<java.util.Map<? extends K,? extends V>
return org.hamcrest.collection.IsMapContaining.hasEntry(key, value);
}

/**
* Creates a matcher for {@link java.util.Map}s matching when the examined {@link java.util.Map}'s set of entries
* satisfies the specified <code>entriesMatcher</code>.
* For example:
* <pre>assertThat(myMap, hasEntries(hasSize(2)))</pre>
*
* @param entriesMatcher
* the matcher that must be satisfied by the set of entries
*/
public static <K, V> org.hamcrest.Matcher<java.util.Map<? extends K,? extends V>> hasEntries(Matcher<? super java.util.Set<? extends java.util.Map.Entry<? extends K, ? extends V>>> entriesMatcher) {
return org.hamcrest.collection.IsMapWithEntries.hasEntries(entriesMatcher);
}

/**
* Creates a matcher for {@link java.util.Map}s matching when the examined {@link java.util.Map}'s set of entries
* contains, in any order, entries satisfying the specified <code>entriesMatchers</code>.
* For example:
* <pre>assertThat(myMap, hasEntries(entry("a key"), entry("another key")))</pre>
*
* @param entriesMatchers
* the matchers that must be satisfied by the entries
*/
@SafeVarargs
public static <K, V> Matcher<java.util.Map<? extends K, ? extends V>> hasEntries(Matcher<? super java.util.Map.Entry<? extends K, ? extends V>>... entriesMatchers) {
return org.hamcrest.collection.IsMapWithEntries.hasEntries(entriesMatchers);
}

/**
* Creates a matcher for {@link java.util.Map.Entry}s matching when the examined {@link java.util.Map.Entry} has a key which satisfies
* the specified <code>keyMatcher</code>, and a value which satisfies the specified <code>valueMatcher</code>.
* For example:
* <pre>assertThat(myMap.keySet(), hasItem(entry(equalTo("key"), notNullValue())))</pre>
*
* @param keyMatcher
* the matcher that must be satisfied by the key
* @param valueMatcher
* the matcher that must be satisfied by the value
*/
public static <K, V> Matcher<? super java.util.Map.Entry<? extends K, ? extends V>> entry(Matcher<? super K> keyMatcher, Matcher<? super V> valueMatcher) {
return org.hamcrest.collection.IsMapEntry.entry(keyMatcher, valueMatcher);
}

/**
* Creates a matcher for {@link java.util.Map.Entry}s matching when the examined {@link java.util.Map.Entry} has a key which satisfies
* the specified <code>keyMatcher</code>; the value is ignored.
* For example:
* <pre>assertThat(myMap.keySet(), hasItem(entry(equalTo("key"))))</pre>
*
* @param keyMatcher
* the matcher that must be satisfied by the key
*/
public static <K> Matcher<? super java.util.Map.Entry<? extends K, ?>> entry(Matcher<? super K> keyMatcher) {
return org.hamcrest.collection.IsMapEntry.entry(keyMatcher);
}

/**
* Creates a matcher for {@link java.util.Map.Entry}s matching when the examined {@link java.util.Map.Entry} has the specified
* <code>key</code>, and a value which satisfies the specified <code>valueMatcher</code>.
* For example:
* <pre>assertThat(myMap.keySet(), hasItem(entry("key", notNullValue())))</pre>
*
* @param key
* the required key
* @param valueMatcher
* the matcher that must be satisfied by the value
*/
public static <K, V> Matcher<? super java.util.Map.Entry<? extends K, ? extends V>> entry(K key, Matcher<? super V> valueMatcher) {
return org.hamcrest.collection.IsMapEntry.entry(key, valueMatcher);
}

/**
* Creates a matcher for {@link java.util.Map.Entry}s matching when the examined {@link java.util.Map.Entry} has the specified
* <code>key</code>; the value is ignored.
* For example:
* <pre>assertThat(myMap.keySet(), hasItem(entry("key")))</pre>
*
* @param key
* the required key
*/
public static <K> Matcher<? super java.util.Map.Entry<? extends K, ?>> entry(K key) {
return org.hamcrest.collection.IsMapEntry.entry(key);
}

/**
* Creates a matcher for {@link java.util.Map}s matching when the examined {@link java.util.Map} contains
* at least one key that satisfies the specified matcher.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package org.hamcrest.collection;

import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.Matchers;
import org.hamcrest.TypeSafeDiagnosingMatcher;

import java.util.Map;

import static java.util.Map.Entry;

public class IsMapEntry<K, V> extends TypeSafeDiagnosingMatcher<Map.Entry<? extends K, ? extends V>> {

private final Matcher<? super K> keyMatcher;
private final Matcher<? super V> valueMatcher;

public IsMapEntry(Matcher<? super K> keyMatcher, Matcher<? super V> valueMatcher) {
this.keyMatcher = keyMatcher;
this.valueMatcher = valueMatcher;
}

@Override
protected boolean matchesSafely(Map.Entry<? extends K, ? extends V> item, Description mismatchDescription) {
boolean matches = true;

if (!keyMatcher.matches(item.getKey())) {
matches = false;
mismatchDescription.appendText("key ");
keyMatcher.describeMismatch(item.getKey(), mismatchDescription);
}

if (valueMatcher != null && !valueMatcher.matches(item.getValue())) {
if (!matches) mismatchDescription.appendText(" and ");
matches = false;
mismatchDescription.appendText("value ");
valueMatcher.describeMismatch(item.getValue(), mismatchDescription);
}

return matches;
}

@Override
public void describeTo(Description description) {
description.appendText("an entry with key ").appendDescriptionOf(keyMatcher);
if (valueMatcher != null) description.appendText(" and value ").appendDescriptionOf(valueMatcher);
}

/**
* Creates a matcher for {@link Entry}s matching when the examined {@link Entry} has a key which satisfies
* the specified <code>keyMatcher</code>, and a value which satisfies the specified <code>valueMatcher</code>.
* For example:
* <pre>assertThat(myMap.keySet(), hasItem(entry(equalTo("key"), notNullValue())))</pre>
*
* @param keyMatcher the matcher that must be satisfied by the key
* @param valueMatcher the matcher that must be satisfied by the value
*/
public static <K, V> Matcher<? super Map.Entry<? extends K, ? extends V>> entry(Matcher<? super K> keyMatcher, Matcher<? super V> valueMatcher) {
return new IsMapEntry<>(keyMatcher, valueMatcher);
}

/**
* Creates a matcher for {@link Entry}s matching when the examined {@link Entry} has a key which satisfies
* the specified <code>keyMatcher</code>; the value is ignored.
* For example:
* <pre>assertThat(myMap.keySet(), hasItem(entry(equalTo("key"))))</pre>
*
* @param keyMatcher the matcher that must be satisfied by the key
*/
public static <K> Matcher<? super Map.Entry<? extends K, ?>> entry(Matcher<? super K> keyMatcher) {
return new IsMapEntry<>(keyMatcher, null);
}

/**
* Creates a matcher for {@link Entry}s matching when the examined {@link Entry} has the specified
* <code>key</code>, and a value which satisfies the specified <code>valueMatcher</code>.
* For example:
* <pre>assertThat(myMap.keySet(), hasItem(entry("key", notNullValue())))</pre>
*
* @param key the required key
* @param valueMatcher the matcher that must be satisfied by the value
*/
public static <K, V> Matcher<? super Map.Entry<? extends K, ? extends V>> entry(K key, Matcher<? super V> valueMatcher) {
return new IsMapEntry<>(Matchers.equalTo(key), valueMatcher);
}

/**
* Creates a matcher for {@link Entry}s matching when the examined {@link Entry} has the specified
* <code>key</code>; the value is ignored.
* For example:
* <pre>assertThat(myMap.keySet(), hasItem(entry("key")))</pre>
*
* @param key the required key
*/
public static <K> Matcher<? super Map.Entry<? extends K, ?>> entry(K key) {
return new IsMapEntry<>(Matchers.equalTo(key), null);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package org.hamcrest.collection;

import org.hamcrest.FeatureMatcher;
import org.hamcrest.Matcher;

import java.util.Map;
import java.util.Set;

public class IsMapWithEntries<K, V> extends FeatureMatcher<Map<? extends K, ? extends V>, Set<? extends Map.Entry<? extends K, ? extends V>>> {

public IsMapWithEntries(Matcher<? super Set<? extends Map.Entry<? extends K, ? extends V>>> entriesMatcher) {
super(entriesMatcher, "a map with entries", "map entries");
}

@Override
protected Set<? extends Map.Entry<? extends K, ? extends V>> featureValueOf(Map<? extends K, ? extends V> actual) {
return actual.entrySet();
}

/**
* Creates a matcher for {@link Map}s matching when the examined {@link Map}'s set of entries
* satisfies the specified <code>entriesMatcher</code>.
* For example:
* <pre>assertThat(myMap, hasEntries(hasSize(2)))</pre>
*
* @param entriesMatcher
* the matcher that must be satisfied by the set of entries
*/
public static <K, V> Matcher<Map<? extends K, ? extends V>> hasEntries(Matcher<? super Set<? extends Map.Entry<? extends K, ? extends V>>> entriesMatcher) {
return new IsMapWithEntries<>(entriesMatcher);
}

/**
* Creates a matcher for {@link Map}s matching when the examined {@link Map}'s set of entries
* contains, in any order, entries satisfying the specified <code>entriesMatchers</code>.
* For example:
* <pre>assertThat(myMap, hasEntries(entry("a key"), entry("another key")))</pre>
*
* @param entriesMatchers
* the matchers that must be satisfied by the entries
*/
@SafeVarargs
public static <K, V> Matcher<Map<? extends K, ? extends V>> hasEntries(Matcher<? super Map.Entry<? extends K, ? extends V>>... entriesMatchers) {
return new IsMapWithEntries<>(IsIterableContainingInAnyOrder.containsInAnyOrder(entriesMatchers));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package org.hamcrest.collection;

import org.hamcrest.AbstractMatcherTest;
import org.hamcrest.Matcher;
import org.hamcrest.Matchers;

import java.util.AbstractMap;
import java.util.Map;

import static org.hamcrest.collection.IsMapEntry.entry;

public class IsMapEntryTest extends AbstractMatcherTest {

@Override
protected Matcher<?> createMatcher() {
return entry(Matchers.equalTo("key"), Matchers.equalTo(23));
}

public void testDoesNotMatchNull() {
assertMismatchDescription("was null", entry(Matchers.equalTo(23), Matchers.equalTo("key")), null);
}

public void testDoesNotMatchAnEntryWithTheWrongKey() {
assertMismatchDescription("key was \"jey\"", entry(Matchers.equalTo("key"), Matchers.equalTo(23)), new AbstractMap.SimpleEntry<>("jey", 23));
}

public void testDoesNotMatchAnEntryWithTheWrongValue() {
assertMismatchDescription("value was <24>", entry(Matchers.equalTo("key"), Matchers.equalTo(23)), new AbstractMap.SimpleEntry<>("key", 24));
}

public void testDoesNotMatchAnEntryWithTheWrongKeyAndValue() {
assertMismatchDescription("key was \"jey\" and value was <24>", entry(Matchers.equalTo("key"), Matchers.equalTo(23)), new AbstractMap.SimpleEntry<>("jey", 24));
}

public void testMatchesAnEntryWithTheRightKeyAndValue() {
assertMatches(entry(Matchers.equalTo("key"), Matchers.equalTo(23)), new AbstractMap.SimpleEntry<>("key", 23));
}

public void testHasReadableDescription() {
assertDescription("an entry with key \"key\" and value a value greater than <22>", entry(Matchers.equalTo("key"), Matchers.greaterThan(22)));
}

public void testCanCreateWithLiteralKey() {
Matcher<? super Map.Entry<? extends String, ? extends Integer>> matcher = IsMapEntry.entry("key", Matchers.greaterThan(22));
assertMatches(matcher, new AbstractMap.SimpleEntry<>("key", 23));
assertDescription("an entry with key \"key\" and value a value greater than <22>", matcher);
}

public void testCanCreateWithKeyOnly() {
Matcher<? super Map.Entry<? extends String, ?>> matcher = IsMapEntry.entry(Matchers.equalTo("key"));
assertMatches(matcher, new AbstractMap.SimpleEntry<>("key", 99));
assertDescription("an entry with key \"key\"", matcher);
}

public void testCanCreateWithLiteralKeyOnly() {
Matcher<? super Map.Entry<? extends String, ?>> matcher = IsMapEntry.entry("key");
assertMatches(matcher, new AbstractMap.SimpleEntry<>("key", 99));
assertDescription("an entry with key \"key\"", matcher);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package org.hamcrest.collection;

import org.hamcrest.AbstractMatcherTest;
import org.hamcrest.Matcher;
import org.hamcrest.Matchers;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;

import static org.hamcrest.collection.IsMapEntry.entry;
import static org.hamcrest.collection.IsMapWithEntries.hasEntries;

public class IsMapWithEntriesTest extends AbstractMatcherTest {

@Override
protected Matcher<?> createMatcher() {
return hasEntries(Matchers.empty());
}

public void testDoesNotMatchNull() {
assertMismatchDescription("was null", hasEntries(Matchers.empty()), null);
}

public void testDoesNotMatchAMapWhoseEntriesDoNotSatisfyTheEntriesMatcher() {
assertMismatchDescription("map entries collection size was <0>", hasEntries(Matchers.hasSize(1)), Collections.emptyMap());
}

public void testMatchesAMapWhoseEntriesSatisfyTheEntriesMatcher() {
assertMatches(hasEntries(Matchers.hasSize(1)), Collections.singletonMap("k", "v"));
}

public void testHasReadableDescription() {
assertDescription("a map with entries an empty collection", hasEntries(Matchers.empty()));
}

public void testMatchesANumberOfExplicitEntriesInAnyOrder() {
Map<String, Integer> map = new LinkedHashMap<>();
map.put("c", 3);
map.put("b", 2);
map.put("a", 1);

assertMatches(hasEntries(entry("a", Matchers.equalTo(1)), entry("b", Matchers.equalTo(2)), entry("c", Matchers.equalTo(3))), map);
}

}