@@ -72,9 +72,39 @@ public static <K,V> Matcher<Map<? extends K,? extends V>> hasEntry(Matcher<? sup
72
72
* the value that, in combination with the key, must be describe at least one entry
73
73
*/
74
74
public static <K ,V > Matcher <Map <? extends K ,? extends V >> hasEntry (K key , V value ) {
75
- return new IsMapContaining <>(equalTo ( key ), equalTo ( value ) );
75
+ return new IsMapContainingEntry <>(key , value );
76
76
}
77
-
77
+
78
+ /**
79
+ * Provides a type-safe optimization over the O(n) linear search in {@link IsMapContaining#matchesSafely(Map)},
80
+ * by leveraging the speed of the map's own {@link Map#containsKey(Object)} check.
81
+ * <p>
82
+ * It preserves the same descriptors.
83
+ */
84
+ private static class IsMapContainingEntry <K , V > extends IsMapContaining <K , V >
85
+ {
86
+ private final K key ;
87
+
88
+ public IsMapContainingEntry (K key , V value )
89
+ {
90
+ super (equalTo (key ), equalTo (value ));
91
+ this .key = key ;
92
+ }
93
+
94
+ @ Override
95
+ public boolean matchesSafely (Map <? extends K , ? extends V > map )
96
+ {
97
+ try {
98
+ return map .containsKey (key ) && super .valueMatcher .matches (map .get (key ));
99
+ } catch (NullPointerException e ){
100
+ // some maps (like Hashtable) don't want to let you check for a null key.
101
+ // to be consistent with previous behavior checking each entry,
102
+ // we squash any error coming from that to indicate simply that there's no entry with that key.
103
+ return false ;
104
+ }
105
+ }
106
+ }
107
+
78
108
/**
79
109
* Creates a matcher for {@link java.util.Map}s matching when the examined {@link java.util.Map} contains
80
110
* at least one key that satisfies the specified matcher.
@@ -98,7 +128,51 @@ public static <K,V> Matcher<Map<? extends K,? extends V>> hasEntry(K key, V valu
98
128
* the key that satisfying maps must contain
99
129
*/
100
130
public static <K > Matcher <Map <? extends K , ?>> hasKey (K key ) {
101
- return new IsMapContaining <>(equalTo (key ), anything ());
131
+ return new IsMapContainingKey <>(key );
132
+ }
133
+
134
+ /**
135
+ * Provides a type-safe optimization over the O(n) linear search in {@link IsMapContaining#matchesSafely(Map)},
136
+ * by leveraging the speed of the map's own {@link Map#containsKey(Object)} check.
137
+ * <p>
138
+ * It preserves the same descriptors.
139
+ */
140
+ private static class IsMapContainingKey <K , V > extends IsMapContaining <K , V >
141
+ {
142
+ private final K key ;
143
+
144
+ public IsMapContainingKey (K key )
145
+ {
146
+ super (equalTo (key ), anything ());
147
+ this .key = key ;
148
+ }
149
+
150
+ @ Override
151
+ public boolean matchesSafely (Map <? extends K , ? extends V > map )
152
+ {
153
+ try
154
+ {
155
+ return map .containsKey (key );
156
+ } catch (NullPointerException e ){
157
+ // some maps (like Hashtable) don't want to let you check for a null key.
158
+ // to be consistent with previous behavior checking each entry,
159
+ // we squash any error coming from that to indicate simply that there's no entry with that key.
160
+ return false ;
161
+ }
162
+ }
163
+
164
+ @ Override
165
+ public void describeMismatchSafely (Map <? extends K , ? extends V > map , Description mismatchDescription )
166
+ {
167
+ mismatchDescription .appendText ("map keys were " ).appendValueList ("[" , ", " , "]" , map .keySet ());
168
+ }
169
+
170
+ @ Override
171
+ public void describeTo (Description description )
172
+ {
173
+ description .appendText ("map containing key " )
174
+ .appendDescriptionOf (super .keyMatcher );
175
+ }
102
176
}
103
177
104
178
/**
0 commit comments