Skip to content

Commit 558b6a6

Browse files
committed
Merge pull request hamcrest#123 from tomwhoiscontrary/pr-map-matchers
Map entry matchers
2 parents e20e58d + 1de3808 commit 558b6a6

File tree

5 files changed

+335
-2
lines changed

5 files changed

+335
-2
lines changed

hamcrest-library/src/main/java/org/hamcrest/Matchers.java

Lines changed: 83 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package org.hamcrest;
22

3-
import org.hamcrest.collection.IsCollectionContaining;
4-
53
import java.util.Collection;
64
import java.util.List;
75

@@ -1068,6 +1066,89 @@ public static <K, V> org.hamcrest.Matcher<java.util.Map<? extends K,? extends V>
10681066
return org.hamcrest.collection.IsMapContaining.<K,V>hasEntry(key, value);
10691067
}
10701068

1069+
/**
1070+
* Creates a matcher for {@link java.util.Map}s matching when the examined {@link java.util.Map}'s set of entries
1071+
* satisfies the specified <code>entriesMatcher</code>.
1072+
* For example:
1073+
* <pre>assertThat(myMap, hasEntries(hasSize(2)))</pre>
1074+
*
1075+
* @param entriesMatcher
1076+
* the matcher that must be satisfied by the set of entries
1077+
*/
1078+
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) {
1079+
return org.hamcrest.collection.IsMapWithEntries.hasEntries(entriesMatcher);
1080+
}
1081+
1082+
/**
1083+
* Creates a matcher for {@link java.util.Map}s matching when the examined {@link java.util.Map}'s set of entries
1084+
* contains, in any order, entries satisfying the specified <code>entriesMatchers</code>.
1085+
* For example:
1086+
* <pre>assertThat(myMap, hasEntries(entry("a key"), entry("another key")))</pre>
1087+
*
1088+
* @param entriesMatchers
1089+
* the matchers that must be satisfied by the entries
1090+
*/
1091+
@SafeVarargs
1092+
public static <K, V> Matcher<java.util.Map<? extends K, ? extends V>> hasEntries(Matcher<? super java.util.Map.Entry<? extends K, ? extends V>>... entriesMatchers) {
1093+
return org.hamcrest.collection.IsMapWithEntries.hasEntries(entriesMatchers);
1094+
}
1095+
1096+
/**
1097+
* Creates a matcher for {@link java.util.Map.Entry}s matching when the examined {@link java.util.Map.Entry} has a key which satisfies
1098+
* the specified <code>keyMatcher</code>, and a value which satisfies the specified <code>valueMatcher</code>.
1099+
* For example:
1100+
* <pre>assertThat(myMap.keySet(), hasItem(entry(equalTo("key"), notNullValue())))</pre>
1101+
*
1102+
* @param keyMatcher
1103+
* the matcher that must be satisfied by the key
1104+
* @param valueMatcher
1105+
* the matcher that must be satisfied by the value
1106+
*/
1107+
public static <K, V> Matcher<? super java.util.Map.Entry<? extends K, ? extends V>> entry(Matcher<? super K> keyMatcher, Matcher<? super V> valueMatcher) {
1108+
return org.hamcrest.collection.IsMapEntry.entry(keyMatcher, valueMatcher);
1109+
}
1110+
1111+
/**
1112+
* Creates a matcher for {@link java.util.Map.Entry}s matching when the examined {@link java.util.Map.Entry} has a key which satisfies
1113+
* the specified <code>keyMatcher</code>; the value is ignored.
1114+
* For example:
1115+
* <pre>assertThat(myMap.keySet(), hasItem(entry(equalTo("key"))))</pre>
1116+
*
1117+
* @param keyMatcher
1118+
* the matcher that must be satisfied by the key
1119+
*/
1120+
public static <K> Matcher<? super java.util.Map.Entry<? extends K, ?>> entry(Matcher<? super K> keyMatcher) {
1121+
return org.hamcrest.collection.IsMapEntry.entry(keyMatcher);
1122+
}
1123+
1124+
/**
1125+
* Creates a matcher for {@link java.util.Map.Entry}s matching when the examined {@link java.util.Map.Entry} has the specified
1126+
* <code>key</code>, and a value which satisfies the specified <code>valueMatcher</code>.
1127+
* For example:
1128+
* <pre>assertThat(myMap.keySet(), hasItem(entry("key", notNullValue())))</pre>
1129+
*
1130+
* @param key
1131+
* the required key
1132+
* @param valueMatcher
1133+
* the matcher that must be satisfied by the value
1134+
*/
1135+
public static <K, V> Matcher<? super java.util.Map.Entry<? extends K, ? extends V>> entry(K key, Matcher<? super V> valueMatcher) {
1136+
return org.hamcrest.collection.IsMapEntry.entry(key, valueMatcher);
1137+
}
1138+
1139+
/**
1140+
* Creates a matcher for {@link java.util.Map.Entry}s matching when the examined {@link java.util.Map.Entry} has the specified
1141+
* <code>key</code>; the value is ignored.
1142+
* For example:
1143+
* <pre>assertThat(myMap.keySet(), hasItem(entry("key")))</pre>
1144+
*
1145+
* @param key
1146+
* the required key
1147+
*/
1148+
public static <K> Matcher<? super java.util.Map.Entry<? extends K, ?>> entry(K key) {
1149+
return org.hamcrest.collection.IsMapEntry.entry(key);
1150+
}
1151+
10711152
/**
10721153
* Creates a matcher for {@link java.util.Map}s matching when the examined {@link java.util.Map} contains
10731154
* at least one key that satisfies the specified matcher.
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package org.hamcrest.collection;
2+
3+
import org.hamcrest.Description;
4+
import org.hamcrest.Matcher;
5+
import org.hamcrest.Matchers;
6+
import org.hamcrest.TypeSafeDiagnosingMatcher;
7+
8+
import java.util.Map;
9+
10+
import static java.util.Map.Entry;
11+
12+
public class IsMapEntry<K, V> extends TypeSafeDiagnosingMatcher<Map.Entry<? extends K, ? extends V>> {
13+
14+
private final Matcher<? super K> keyMatcher;
15+
private final Matcher<? super V> valueMatcher;
16+
17+
public IsMapEntry(Matcher<? super K> keyMatcher, Matcher<? super V> valueMatcher) {
18+
this.keyMatcher = keyMatcher;
19+
this.valueMatcher = valueMatcher;
20+
}
21+
22+
@Override
23+
protected boolean matchesSafely(Map.Entry<? extends K, ? extends V> item, Description mismatchDescription) {
24+
boolean matches = true;
25+
26+
if (!keyMatcher.matches(item.getKey())) {
27+
matches = false;
28+
mismatchDescription.appendText("key ");
29+
keyMatcher.describeMismatch(item.getKey(), mismatchDescription);
30+
}
31+
32+
if (valueMatcher != null && !valueMatcher.matches(item.getValue())) {
33+
if (!matches) mismatchDescription.appendText(" and ");
34+
matches = false;
35+
mismatchDescription.appendText("value ");
36+
valueMatcher.describeMismatch(item.getValue(), mismatchDescription);
37+
}
38+
39+
return matches;
40+
}
41+
42+
@Override
43+
public void describeTo(Description description) {
44+
description.appendText("an entry with key ").appendDescriptionOf(keyMatcher);
45+
if (valueMatcher != null) description.appendText(" and value ").appendDescriptionOf(valueMatcher);
46+
}
47+
48+
/**
49+
* Creates a matcher for {@link Entry}s matching when the examined {@link Entry} has a key which satisfies
50+
* the specified <code>keyMatcher</code>, and a value which satisfies the specified <code>valueMatcher</code>.
51+
* For example:
52+
* <pre>assertThat(myMap.keySet(), hasItem(entry(equalTo("key"), notNullValue())))</pre>
53+
*
54+
* @param keyMatcher the matcher that must be satisfied by the key
55+
* @param valueMatcher the matcher that must be satisfied by the value
56+
*/
57+
public static <K, V> Matcher<? super Map.Entry<? extends K, ? extends V>> entry(Matcher<? super K> keyMatcher, Matcher<? super V> valueMatcher) {
58+
return new IsMapEntry<>(keyMatcher, valueMatcher);
59+
}
60+
61+
/**
62+
* Creates a matcher for {@link Entry}s matching when the examined {@link Entry} has a key which satisfies
63+
* the specified <code>keyMatcher</code>; the value is ignored.
64+
* For example:
65+
* <pre>assertThat(myMap.keySet(), hasItem(entry(equalTo("key"))))</pre>
66+
*
67+
* @param keyMatcher the matcher that must be satisfied by the key
68+
*/
69+
public static <K> Matcher<? super Map.Entry<? extends K, ?>> entry(Matcher<? super K> keyMatcher) {
70+
return new IsMapEntry<>(keyMatcher, null);
71+
}
72+
73+
/**
74+
* Creates a matcher for {@link Entry}s matching when the examined {@link Entry} has the specified
75+
* <code>key</code>, and a value which satisfies the specified <code>valueMatcher</code>.
76+
* For example:
77+
* <pre>assertThat(myMap.keySet(), hasItem(entry("key", notNullValue())))</pre>
78+
*
79+
* @param key the required key
80+
* @param valueMatcher the matcher that must be satisfied by the value
81+
*/
82+
public static <K, V> Matcher<? super Map.Entry<? extends K, ? extends V>> entry(K key, Matcher<? super V> valueMatcher) {
83+
return new IsMapEntry<>(Matchers.equalTo(key), valueMatcher);
84+
}
85+
86+
/**
87+
* Creates a matcher for {@link Entry}s matching when the examined {@link Entry} has the specified
88+
* <code>key</code>; the value is ignored.
89+
* For example:
90+
* <pre>assertThat(myMap.keySet(), hasItem(entry("key")))</pre>
91+
*
92+
* @param key the required key
93+
*/
94+
public static <K> Matcher<? super Map.Entry<? extends K, ?>> entry(K key) {
95+
return new IsMapEntry<>(Matchers.equalTo(key), null);
96+
}
97+
98+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package org.hamcrest.collection;
2+
3+
import org.hamcrest.FeatureMatcher;
4+
import org.hamcrest.Matcher;
5+
6+
import java.util.Map;
7+
import java.util.Set;
8+
9+
public class IsMapWithEntries<K, V> extends FeatureMatcher<Map<? extends K, ? extends V>, Set<? extends Map.Entry<? extends K, ? extends V>>> {
10+
11+
public IsMapWithEntries(Matcher<? super Set<? extends Map.Entry<? extends K, ? extends V>>> entriesMatcher) {
12+
super(entriesMatcher, "a map with entries", "map entries");
13+
}
14+
15+
@Override
16+
protected Set<? extends Map.Entry<? extends K, ? extends V>> featureValueOf(Map<? extends K, ? extends V> actual) {
17+
return actual.entrySet();
18+
}
19+
20+
/**
21+
* Creates a matcher for {@link Map}s matching when the examined {@link Map}'s set of entries
22+
* satisfies the specified <code>entriesMatcher</code>.
23+
* For example:
24+
* <pre>assertThat(myMap, hasEntries(hasSize(2)))</pre>
25+
*
26+
* @param entriesMatcher
27+
* the matcher that must be satisfied by the set of entries
28+
*/
29+
public static <K, V> Matcher<Map<? extends K, ? extends V>> hasEntries(Matcher<? super Set<? extends Map.Entry<? extends K, ? extends V>>> entriesMatcher) {
30+
return new IsMapWithEntries<>(entriesMatcher);
31+
}
32+
33+
/**
34+
* Creates a matcher for {@link Map}s matching when the examined {@link Map}'s set of entries
35+
* contains, in any order, entries satisfying the specified <code>entriesMatchers</code>.
36+
* For example:
37+
* <pre>assertThat(myMap, hasEntries(entry("a key"), entry("another key")))</pre>
38+
*
39+
* @param entriesMatchers
40+
* the matchers that must be satisfied by the entries
41+
*/
42+
@SafeVarargs
43+
public static <K, V> Matcher<Map<? extends K, ? extends V>> hasEntries(Matcher<? super Map.Entry<? extends K, ? extends V>>... entriesMatchers) {
44+
return new IsMapWithEntries<>(IsIterableContainingInAnyOrder.containsInAnyOrder(entriesMatchers));
45+
}
46+
47+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package org.hamcrest.collection;
2+
3+
import org.hamcrest.AbstractMatcherTest;
4+
import org.hamcrest.Matcher;
5+
import org.hamcrest.Matchers;
6+
7+
import java.util.AbstractMap;
8+
import java.util.Map;
9+
10+
import static org.hamcrest.collection.IsMapEntry.entry;
11+
12+
public class IsMapEntryTest extends AbstractMatcherTest {
13+
14+
@Override
15+
protected Matcher<?> createMatcher() {
16+
return entry(Matchers.equalTo("key"), Matchers.equalTo(23));
17+
}
18+
19+
public void testDoesNotMatchNull() {
20+
assertMismatchDescription("was null", entry(Matchers.equalTo(23), Matchers.equalTo("key")), null);
21+
}
22+
23+
public void testDoesNotMatchAnEntryWithTheWrongKey() {
24+
assertMismatchDescription("key was \"jey\"", entry(Matchers.equalTo("key"), Matchers.equalTo(23)), new AbstractMap.SimpleEntry<>("jey", 23));
25+
}
26+
27+
public void testDoesNotMatchAnEntryWithTheWrongValue() {
28+
assertMismatchDescription("value was <24>", entry(Matchers.equalTo("key"), Matchers.equalTo(23)), new AbstractMap.SimpleEntry<>("key", 24));
29+
}
30+
31+
public void testDoesNotMatchAnEntryWithTheWrongKeyAndValue() {
32+
assertMismatchDescription("key was \"jey\" and value was <24>", entry(Matchers.equalTo("key"), Matchers.equalTo(23)), new AbstractMap.SimpleEntry<>("jey", 24));
33+
}
34+
35+
public void testMatchesAnEntryWithTheRightKeyAndValue() {
36+
assertMatches(entry(Matchers.equalTo("key"), Matchers.equalTo(23)), new AbstractMap.SimpleEntry<>("key", 23));
37+
}
38+
39+
public void testHasReadableDescription() {
40+
assertDescription("an entry with key \"key\" and value a value greater than <22>", entry(Matchers.equalTo("key"), Matchers.greaterThan(22)));
41+
}
42+
43+
public void testCanCreateWithLiteralKey() {
44+
Matcher<? super Map.Entry<? extends String, ? extends Integer>> matcher = IsMapEntry.entry("key", Matchers.greaterThan(22));
45+
assertMatches(matcher, new AbstractMap.SimpleEntry<>("key", 23));
46+
assertDescription("an entry with key \"key\" and value a value greater than <22>", matcher);
47+
}
48+
49+
public void testCanCreateWithKeyOnly() {
50+
Matcher<? super Map.Entry<? extends String, ?>> matcher = IsMapEntry.entry(Matchers.equalTo("key"));
51+
assertMatches(matcher, new AbstractMap.SimpleEntry<>("key", 99));
52+
assertDescription("an entry with key \"key\"", matcher);
53+
}
54+
55+
public void testCanCreateWithLiteralKeyOnly() {
56+
Matcher<? super Map.Entry<? extends String, ?>> matcher = IsMapEntry.entry("key");
57+
assertMatches(matcher, new AbstractMap.SimpleEntry<>("key", 99));
58+
assertDescription("an entry with key \"key\"", matcher);
59+
}
60+
61+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package org.hamcrest.collection;
2+
3+
import org.hamcrest.AbstractMatcherTest;
4+
import org.hamcrest.Matcher;
5+
import org.hamcrest.Matchers;
6+
7+
import java.util.Collections;
8+
import java.util.LinkedHashMap;
9+
import java.util.Map;
10+
11+
import static org.hamcrest.collection.IsMapEntry.entry;
12+
import static org.hamcrest.collection.IsMapWithEntries.hasEntries;
13+
14+
public class IsMapWithEntriesTest extends AbstractMatcherTest {
15+
16+
@Override
17+
protected Matcher<?> createMatcher() {
18+
return hasEntries(Matchers.empty());
19+
}
20+
21+
public void testDoesNotMatchNull() {
22+
assertMismatchDescription("was null", hasEntries(Matchers.empty()), null);
23+
}
24+
25+
public void testDoesNotMatchAMapWhoseEntriesDoNotSatisfyTheEntriesMatcher() {
26+
assertMismatchDescription("map entries collection size was <0>", hasEntries(Matchers.hasSize(1)), Collections.emptyMap());
27+
}
28+
29+
public void testMatchesAMapWhoseEntriesSatisfyTheEntriesMatcher() {
30+
assertMatches(hasEntries(Matchers.hasSize(1)), Collections.singletonMap("k", "v"));
31+
}
32+
33+
public void testHasReadableDescription() {
34+
assertDescription("a map with entries an empty collection", hasEntries(Matchers.empty()));
35+
}
36+
37+
public void testMatchesANumberOfExplicitEntriesInAnyOrder() {
38+
Map<String, Integer> map = new LinkedHashMap<>();
39+
map.put("c", 3);
40+
map.put("b", 2);
41+
map.put("a", 1);
42+
43+
assertMatches(hasEntries(entry("a", Matchers.equalTo(1)), entry("b", Matchers.equalTo(2)), entry("c", Matchers.equalTo(3))), map);
44+
}
45+
46+
}

0 commit comments

Comments
 (0)