33import io .vavr .Tuple ;
44import io .vavr .Tuple2 ;
55import io .vavr .collection .*;
6+ import io .vavr .control .Option ;
67import org .assertj .core .api .AssertionInfo ;
8+ import org .assertj .core .api .Condition ;
79import org .assertj .core .error .ShouldContainAnyOf ;
10+ import org .assertj .core .internal .Conditions ;
811import org .assertj .core .internal .Failures ;
912import org .assertj .core .internal .Objects ;
1013
1114import java .util .function .Predicate ;
1215
16+ import static io .vavr .Predicates .not ;
17+ import static org .assertj .core .error .ElementsShouldBe .elementsShouldBe ;
1318import static org .assertj .core .error .ShouldContain .shouldContain ;
1419import static org .assertj .core .error .ShouldContainExactly .elementsDifferAtIndex ;
1520import static org .assertj .core .error .ShouldContainExactly .shouldContainExactly ;
@@ -35,16 +40,42 @@ public final class Maps {
3540
3641 private Failures failures = Failures .instance ();
3742
43+ private Conditions conditions = Conditions .instance ();
44+
3845 private Maps () {}
3946
4047 public static Maps instance () {
4148 return INSTANCE ;
4249 }
4350
51+ /**
52+ * Verifies that the given {@code Map} contains the value for given {@code key} that satisfy given {@code valueCondition}.
53+ *
54+ * @param <K> key type
55+ * @param <V> value type
56+ * @param info contains information about the assertion.
57+ * @param actual the given {@code Map}.
58+ * @param key the given key to check.
59+ * @param valueCondition the given condition for check value.
60+ * @throws NullPointerException if the given values is {@code null}.
61+ * @throws AssertionError if the actual map is {@code null}.
62+ * @throws AssertionError if the actual map not contains the given {@code key}.
63+ * @throws AssertionError if the actual map contains the given key, but value does not match the given {@code valueCondition}.
64+ */
65+ @ SuppressWarnings ("unchecked" )
66+ public <K , V > void assertHasEntrySatisfying (AssertionInfo info , Map <K , V > actual , K key ,
67+ Condition <? super V > valueCondition ) {
68+ conditions .assertIsNotNull (valueCondition );
69+ assertContainsKeys (info , actual , key );
70+ Option <V > value = actual .get (key );
71+ value
72+ .filter (valueCondition ::matches )
73+ .getOrElseThrow (() -> failures .failure (info , elementsShouldBe (actual , value , valueCondition )));
74+ }
75+
4476 public <K , V > void assertContainsAnyOf (AssertionInfo info , Map <K , V > actual ,
4577 Tuple2 <K , V >[] entries ) {
4678 doCommonContainsCheck (info , actual , entries );
47- // if both actual and values are empty, then assertion passes.
4879 if (actual .isEmpty () && entries .length == 0 ) return ;
4980 failIfEmptySinceActualIsNotEmpty (entries );
5081 for (Tuple2 <? extends K , ? extends V > entry : entries ) {
@@ -70,10 +101,9 @@ public <K, V> void assertContainsAnyOf(AssertionInfo info, Map<K, V> actual,
70101 public <K , V > void assertContains (AssertionInfo info , Map <K , V > actual ,
71102 Tuple2 <K , V >[] entries ) {
72103 doCommonContainsCheck (info , actual , entries );
73- // if both actual and values are empty, then assertion passes.
74104 if (actual .isEmpty () && entries .length == 0 ) return ;
75105 failIfEmptySinceActualIsNotEmpty (entries );
76- final Set <Tuple2 <K , V >> notFound = Array .of (entries ).filter (notPresentIn (actual )).toSet ();
106+ final Set <Tuple2 <K , V >> notFound = Array .of (entries ).filter (entryNotPresentIn (actual )).toSet ();
77107 if (isNotEmpty (notFound )) {
78108 throw failures .failure (info , shouldContain (actual , entries , notFound ));
79109 }
@@ -123,7 +153,7 @@ public <K, V> void assertContainsKeys(AssertionInfo info, Map<K, V> actual,
123153 if (doCommonEmptinessChecks (actual , keys )) return ;
124154
125155 Set <K > expected = HashSet .of (keys );
126- Set <K > notFound = expected .filter (notPresentIn (actual .keySet ()));
156+ Set <K > notFound = expected .filter (keyNotPresentIn (actual .keySet ()));
127157 if (isNotEmpty (notFound )) {
128158 throw failures .failure (info , shouldContainKeys (actual , notFound .toJavaSet ()));
129159 }
@@ -148,7 +178,7 @@ public <K, V> void assertDoesNotContainKeys(AssertionInfo info, Map<K, V> actual
148178 if (doCommonEmptinessChecks (actual , keys )) return ;
149179
150180 Set <K > expected = HashSet .of (keys );
151- Set <K > found = expected .filter (presentIn (actual .keySet ()));
181+ Set <K > found = expected .filter (keyPresentIn (actual .keySet ()));
152182 if (isNotEmpty (found )) {
153183 throw failures .failure (info , shouldNotContainKeys (actual , found .toJavaSet ()));
154184 }
@@ -171,14 +201,12 @@ public <K, V> void assertDoesNotContainKeys(AssertionInfo info, Map<K, V> actual
171201 public <K , V > void assertContainsOnly (AssertionInfo info , Map <K , V > actual , Iterable <Tuple2 <K , V >> entries ) {
172202 assertNotNull (info , actual );
173203 failIfNull (entries );
174- if (actual .isEmpty () && !entries .iterator ().hasNext ()) {
175- return ;
176- }
204+ if (actual .isEmpty () && !entries .iterator ().hasNext ()) return ;
177205 failIfEmpty (entries );
178206 Map <K , V > expected = HashMap .ofEntries (entries );
179- Map <K , V > notExpected = actual .filter (notPresentIn (expected ));
207+ Map <K , V > notExpected = actual .filter (entryNotPresentIn (expected ));
180208 if (isNotEmpty (notExpected )) {
181- Map <K , V > notFound = expected .filter (notPresentIn (actual ));
209+ Map <K , V > notFound = expected .filter (entryNotPresentIn (actual ));
182210 throw failures .failure (info , shouldContainOnly (actual , expected , notFound , notExpected ));
183211 }
184212 }
@@ -246,9 +274,9 @@ public <K, V> void assertContainsOnlyKeys(AssertionInfo info, Map<K, V> actual,
246274 if (doCommonEmptinessChecks (actual , keys )) return ;
247275
248276 Set <K > expected = HashSet .of (keys );
249- Set <K > notExpected = actual .keySet ().filter (notPresentIn (expected ));
277+ Set <K > notExpected = actual .keySet ().filter (keyNotPresentIn (expected ));
250278 if (isNotEmpty (notExpected )) {
251- Set <K > notFound = expected .filter (notPresentIn (actual .keySet ()));
279+ Set <K > notFound = expected .filter (keyNotPresentIn (actual .keySet ()));
252280 throw failures .failure (info , shouldContainOnlyKeys (actual , expected , notFound , notExpected ));
253281 }
254282 }
@@ -420,24 +448,24 @@ private static <K, V> Map<K, V> asLinkedMap(Tuple2<? extends K, ? extends V>[] e
420448 return Array .of (entries ).filter (java .util .Objects ::nonNull );
421449 }
422450
423- private static <K , V > Predicate <Tuple2 <K , V >> notPresentIn (Map <K , V > map ) {
451+ private static <K , V > Predicate <Tuple2 <K , V >> entryNotPresentIn (Map <K , V > map ) {
424452 return tuple -> !map .contains (tuple );
425453 }
426454
427- private static <K > Predicate <K > notPresentIn (Set <K > elements ) {
428- return elem -> ! elements . contains ( elem );
455+ private static <K > Predicate <K > keyNotPresentIn (Set <K > elements ) {
456+ return not ( keyPresentIn ( elements ) );
429457 }
430458
431- private static <K > Predicate <K > presentIn (Set <K > elements ) {
459+ private static <K > Predicate <K > keyPresentIn (Set <K > elements ) {
432460 return elements ::contains ;
433461 }
434462
435- private <V > Predicate <V > valuePresentIn (Seq <V > elements ) {
463+ private static <V > Predicate <V > valuePresentIn (Seq <V > elements ) {
436464 return elements ::contains ;
437465 }
438466
439467 private static <V > Predicate <V > valueNotPresentIn (Seq <V > elements ) {
440- return elem -> ! elements . contains ( elem );
468+ return not ( valuePresentIn ( elements ) );
441469 }
442470
443471 private static boolean isNotEmpty (Traversable traversable ) {
0 commit comments