Skip to content

Commit e1b0a4e

Browse files
cookieMrjoel-costigliola
authored andcommitted
Custom Equality (BiPredicate) Comparator - resolves #3678
1 parent d92ba37 commit e1b0a4e

File tree

3 files changed

+157
-50
lines changed

3 files changed

+157
-50
lines changed

assertj-core/src/main/java/org/assertj/core/api/AbstractAssert.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import java.util.List;
3232
import java.util.Map;
3333
import java.util.Optional;
34+
import java.util.function.BiPredicate;
3435
import java.util.function.Consumer;
3536
import java.util.function.Function;
3637
import java.util.function.Predicate;
@@ -717,6 +718,20 @@ public SELF usingComparator(Comparator<? super ACTUAL> customComparator, String
717718
return myself;
718719
}
719720

721+
/** {@inheritDoc} */
722+
@Override
723+
@CheckReturnValue
724+
public SELF usingEquals(BiPredicate<? super ACTUAL, ? super ACTUAL> predicate) {
725+
return usingEquals(predicate, null);
726+
}
727+
728+
/** {@inheritDoc} */
729+
@Override
730+
@CheckReturnValue
731+
public SELF usingEquals(BiPredicate<? super ACTUAL, ? super ACTUAL> predicate, String customEqualsDescription) {
732+
return usingComparator((o1, o2) -> predicate.test(o1, o2) ? 0 : -1, customEqualsDescription);
733+
}
734+
720735
/** {@inheritDoc} */
721736
@Override
722737
@CheckReturnValue

assertj-core/src/main/java/org/assertj/core/api/Assert.java

Lines changed: 76 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import java.util.Comparator;
1616
import java.util.Date;
1717
import java.util.List;
18+
import java.util.function.BiPredicate;
1819
import java.util.function.Consumer;
1920

2021
import org.assertj.core.presentation.Representation;
@@ -23,11 +24,10 @@
2324
/**
2425
* Base contract of all assertion objects: the minimum functionality that any assertion object should provide.
2526
*
26-
* @param <SELF> the "self" type of this assertion class. Please read &quot;<a href="http://bit.ly/1IZIRcY"
27-
* target="_blank">Emulating
28-
* 'self types' using Java Generics to simplify fluent API implementation</a>&quot; for more details.
27+
* @param <SELF> the "self" type of this assertion class. Please read &quot;<a href="http://bit.ly/1IZIRcY"
28+
* target="_blank">Emulating
29+
* 'self types' using Java Generics to simplify fluent API implementation</a>&quot; for more details.
2930
* @param <ACTUAL> the type of the "actual" value.
30-
*
3131
* @author Yvonne Wang
3232
* @author Alex Ruiz
3333
* @author Nicolas François
@@ -89,7 +89,7 @@ public interface Assert<SELF extends Assert<SELF, ACTUAL>, ACTUAL> extends Descr
8989

9090
/**
9191
* Verifies that the actual value is not {@code null}.
92-
* <p>
92+
* <p>
9393
* Example:
9494
* <pre><code class='java'> // assertions succeed
9595
* assertThat(&quot;abc&quot;).isNotNull();
@@ -166,7 +166,7 @@ public interface Assert<SELF extends Assert<SELF, ACTUAL>, ACTUAL> extends Descr
166166
* @param values the given array to search the actual value in.
167167
* @return {@code this} assertion object.
168168
* @throws NullPointerException if the given array is {@code null}.
169-
* @throws AssertionError if the actual value is not present in the given array.
169+
* @throws AssertionError if the actual value is not present in the given array.
170170
*/
171171
SELF isIn(Object... values);
172172

@@ -188,7 +188,7 @@ public interface Assert<SELF extends Assert<SELF, ACTUAL>, ACTUAL> extends Descr
188188
* @param values the given array to search the actual value in.
189189
* @return {@code this} assertion object.
190190
* @throws NullPointerException if the given array is {@code null}.
191-
* @throws AssertionError if the actual value is present in the given array.
191+
* @throws AssertionError if the actual value is present in the given array.
192192
*/
193193
SELF isNotIn(Object... values);
194194

@@ -210,7 +210,7 @@ public interface Assert<SELF extends Assert<SELF, ACTUAL>, ACTUAL> extends Descr
210210
* @param values the given iterable to search the actual value in.
211211
* @return {@code this} assertion object.
212212
* @throws NullPointerException if the given collection is {@code null}.
213-
* @throws AssertionError if the actual value is not present in the given iterable.
213+
* @throws AssertionError if the actual value is not present in the given iterable.
214214
*/
215215
SELF isIn(Iterable<?> values);
216216

@@ -232,7 +232,7 @@ public interface Assert<SELF extends Assert<SELF, ACTUAL>, ACTUAL> extends Descr
232232
* @param values the given iterable to search the actual value in.
233233
* @return {@code this} assertion object.
234234
* @throws NullPointerException if the given iterable is {@code null}.
235-
* @throws AssertionError if the actual value is present in the given iterable.
235+
* @throws AssertionError if the actual value is present in the given iterable.
236236
*/
237237
SELF isNotIn(Iterable<?> values);
238238

@@ -248,29 +248,64 @@ public interface Assert<SELF extends Assert<SELF, ACTUAL>, ACTUAL> extends Descr
248248
* assertThat(frodo).usingComparator(raceComparator).isEqualTo(sam);</code></pre>
249249
*
250250
* @param customComparator the comparator to use for the incoming assertion checks.
251-
* @throws NullPointerException if the given comparator is {@code null}.
252251
* @return {@code this} assertion object.
252+
* @throws NullPointerException if the given comparator is {@code null}.
253253
*/
254254
SELF usingComparator(Comparator<? super ACTUAL> customComparator);
255255

256256
/**
257257
* Use the given custom comparator instead of relying on actual type A equals method for incoming assertion checks.
258258
* <p>
259-
* The custom comparator is bound to assertion instance, meaning that if a new assertion instance is created, the default
259+
* The custom comparator is bound to the current assertion chain, meaning that if a new assertion instance is created, the default
260260
* comparison strategy will be used.
261261
* <p>
262262
* Examples :
263263
* <pre><code class='java'> // frodo and sam are instances of Character with Hobbit race (obviously :).
264264
* // raceComparator implements Comparator&lt;Character&gt;
265265
* assertThat(frodo).usingComparator(raceComparator, "Hobbit Race Comparator").isEqualTo(sam);</code></pre>
266266
*
267-
* @param customComparator the comparator to use for the incoming assertion checks.
267+
* @param customComparator the comparator to use for the incoming assertion checks.
268268
* @param customComparatorDescription comparator description to be used in assertion error messages
269-
* @throws NullPointerException if the given comparator is {@code null}.
270269
* @return {@code this} assertion object.
270+
* @throws NullPointerException if the given comparator is {@code null}.
271271
*/
272272
SELF usingComparator(Comparator<? super ACTUAL> customComparator, String customComparatorDescription);
273273

274+
/**
275+
* Uses the given custom {@link BiPredicate} instead of relying on actual type A {@code equals} method
276+
* for incoming assertion checks.
277+
* <p>
278+
* The custom equals is bound to the current assertion chain, meaning that if a new assertion instance is created, the default
279+
* comparison strategy will be used.
280+
* <p>
281+
* Examples:
282+
* <pre><code class='java'> // frodo and sam are instances of Character of Hobbit race (obviously :).
283+
* assertThat(frodo).usingEquals((f, s) -> f.race() == s.race()).isEqualTo(sam);</code></pre>
284+
*
285+
* @param predicate the predicate to use for the incoming assertion checks.
286+
* @return {@code this} assertion object.
287+
* @throws NullPointerException if the given biPredicate is {@code null}.
288+
*/
289+
SELF usingEquals(BiPredicate<? super ACTUAL, ? super ACTUAL> predicate);
290+
291+
/**
292+
* Uses the given custom {@link BiPredicate} instead of relying on actual type A {@code equals} method
293+
* for incoming assertion checks. The given description is present in the assertion error if the assertion fails.
294+
* <p>
295+
* The custom equals is bound to the current assertion chain, meaning that if a new assertion instance is created, the default
296+
* comparison strategy will be used.
297+
* <p>
298+
* Examples:
299+
* <pre><code class='java'> // frodo and sam are instances of Character of Hobbit race (obviously :).
300+
* assertThat(frodo).usingEquals((f, s) -> f.race() == s.race(), "comparing race").isEqualTo(sam);</code></pre>
301+
*
302+
* @param predicate the predicate to use for the incoming assertion checks.
303+
* @param customEqualsDescription comparator description to be used in assertion error messages
304+
* @return {@code this} assertion object.
305+
* @throws NullPointerException if the given comparator is {@code null}.
306+
*/
307+
SELF usingEquals(BiPredicate<? super ACTUAL, ? super ACTUAL> predicate, String customEqualsDescription);
308+
274309
/**
275310
* Revert to standard comparison for the incoming assertion checks.
276311
* <p>
@@ -301,12 +336,10 @@ public interface Assert<SELF extends Assert<SELF, ACTUAL>, ACTUAL> extends Descr
301336
*
302337
* @param <ASSERT> the type of the resulting {@code Assert}.
303338
* @param instanceOfAssertFactory the factory which verifies the type and creates the new {@code Assert}.
304-
* @throws NullPointerException if the given factory is {@code null}.
305339
* @return the narrowed {@code Assert} instance.
306-
*
340+
* @throws NullPointerException if the given factory is {@code null}.
307341
* @see InstanceOfAssertFactory
308342
* @see InstanceOfAssertFactories
309-
*
310343
* @since 3.13.0
311344
*/
312345
<ASSERT extends AbstractAssert<?, ?>> ASSERT asInstanceOf(InstanceOfAssertFactory<?, ASSERT> instanceOfAssertFactory);
@@ -327,8 +360,8 @@ public interface Assert<SELF extends Assert<SELF, ACTUAL>, ACTUAL> extends Descr
327360
* @param type the type to check the actual value against.
328361
* @return this assertion object.
329362
* @throws NullPointerException if the given type is {@code null}.
330-
* @throws AssertionError if the actual value is {@code null}.
331-
* @throws AssertionError if the actual value is not an instance of the given type.
363+
* @throws AssertionError if the actual value is {@code null}.
364+
* @throws AssertionError if the actual value is not an instance of the given type.
332365
*/
333366
SELF isInstanceOf(Class<?> type);
334367

@@ -357,14 +390,14 @@ public interface Assert<SELF extends Assert<SELF, ACTUAL>, ACTUAL> extends Descr
357390
* // not a Jedi !
358391
* assertThat("foo").isInstanceOfSatisfying(Jedi.class, jediRequirements);</code></pre>
359392
*
360-
* @param <T> the generic type to check the actual value against.
361-
* @param type the type to check the actual value against.
393+
* @param <T> the generic type to check the actual value against.
394+
* @param type the type to check the actual value against.
362395
* @param requirements the requirements expressed as a {@link Consumer}.
363396
* @return this assertion object.
364397
* @throws NullPointerException if the given type is {@code null}.
365398
* @throws NullPointerException if the given Consumer is {@code null}.
366-
* @throws AssertionError if the actual value is {@code null}.
367-
* @throws AssertionError if the actual value is not an instance of the given type.
399+
* @throws AssertionError if the actual value is {@code null}.
400+
* @throws AssertionError if the actual value is not an instance of the given type.
368401
*/
369402
<T> SELF isInstanceOfSatisfying(Class<T> type, Consumer<T> requirements);
370403

@@ -383,8 +416,8 @@ public interface Assert<SELF extends Assert<SELF, ACTUAL>, ACTUAL> extends Descr
383416
*
384417
* @param types the types to check the actual value against.
385418
* @return this assertion object.
386-
* @throws AssertionError if the actual value is {@code null}.
387-
* @throws AssertionError if the actual value is not an instance of any of the given types.
419+
* @throws AssertionError if the actual value is {@code null}.
420+
* @throws AssertionError if the actual value is not an instance of any of the given types.
388421
* @throws NullPointerException if the given array of types is {@code null}.
389422
* @throws NullPointerException if the given array of types contains {@code null}s.
390423
*/
@@ -406,8 +439,8 @@ public interface Assert<SELF extends Assert<SELF, ACTUAL>, ACTUAL> extends Descr
406439
* @param type the type to check the actual value against.
407440
* @return this assertion object.
408441
* @throws NullPointerException if the given type is {@code null}.
409-
* @throws AssertionError if the actual value is {@code null}.
410-
* @throws AssertionError if the actual value is an instance of the given type.
442+
* @throws AssertionError if the actual value is {@code null}.
443+
* @throws AssertionError if the actual value is an instance of the given type.
411444
*/
412445
SELF isNotInstanceOf(Class<?> type);
413446

@@ -426,8 +459,8 @@ public interface Assert<SELF extends Assert<SELF, ACTUAL>, ACTUAL> extends Descr
426459
*
427460
* @param types the types to check the actual value against.
428461
* @return this assertion object.
429-
* @throws AssertionError if the actual value is {@code null}.
430-
* @throws AssertionError if the actual value is an instance of any of the given types.
462+
* @throws AssertionError if the actual value is {@code null}.
463+
* @throws AssertionError if the actual value is an instance of any of the given types.
431464
* @throws NullPointerException if the given array of types is {@code null}.
432465
* @throws NullPointerException if the given array of types contains {@code null}s.
433466
*/
@@ -448,7 +481,7 @@ public interface Assert<SELF extends Assert<SELF, ACTUAL>, ACTUAL> extends Descr
448481
*
449482
* @param other the object to check type against.
450483
* @return this assertion object.
451-
* @throws AssertionError if {@code actual} has not the same type as the given object.
484+
* @throws AssertionError if {@code actual} has not the same type as the given object.
452485
* @throws NullPointerException if the actual value is null.
453486
* @throws NullPointerException if the given object is null.
454487
*/
@@ -483,7 +516,7 @@ public interface Assert<SELF extends Assert<SELF, ACTUAL>, ACTUAL> extends Descr
483516
* assertThat(wrapper).hasToString("FooWrapper[foo=%s]", foo); </code></pre>
484517
*
485518
* @param expectedStringTemplate the format string to use.
486-
* @param args the arguments to interpolate into the format string.
519+
* @param args the arguments to interpolate into the format string.
487520
* @return this assertion object.
488521
* @throws AssertionError if {@code actual.toString()} result is not equal to the given {@code String}.
489522
* @throws AssertionError if actual is {@code null}.
@@ -520,7 +553,7 @@ public interface Assert<SELF extends Assert<SELF, ACTUAL>, ACTUAL> extends Descr
520553
* assertThat(wrapper).doesNotHaveToString("FooBarWrapper[%s]", foo);</code></pre>
521554
*
522555
* @param expectedStringTemplate the format string to use.
523-
* @param args the arguments to interpolate into the format string.
556+
* @param args the arguments to interpolate into the format string.
524557
* @return this assertion object.
525558
* @throws AssertionError if {@code actual.toString()} result is equal to the given {@code String}.
526559
* @throws AssertionError if actual is {@code null}.
@@ -543,7 +576,7 @@ public interface Assert<SELF extends Assert<SELF, ACTUAL>, ACTUAL> extends Descr
543576
*
544577
* @param other the object to check type against.
545578
* @return this assertion object.
546-
* @throws AssertionError if {@code actual} has the same type as the given object.
579+
* @throws AssertionError if {@code actual} has the same type as the given object.
547580
* @throws NullPointerException if the actual value is null.
548581
* @throws NullPointerException if the given object is null.
549582
*/
@@ -565,7 +598,7 @@ public interface Assert<SELF extends Assert<SELF, ACTUAL>, ACTUAL> extends Descr
565598
*
566599
* @param type the type to check the actual value against.
567600
* @return this assertion object.
568-
* @throws AssertionError if the actual is not <b>exactly</b> an instance of given type.
601+
* @throws AssertionError if the actual is not <b>exactly</b> an instance of given type.
569602
* @throws NullPointerException if the actual value is null.
570603
* @throws NullPointerException if the given object is null.
571604
*/
@@ -587,7 +620,7 @@ public interface Assert<SELF extends Assert<SELF, ACTUAL>, ACTUAL> extends Descr
587620
*
588621
* @param type the type to check the actual value against.
589622
* @return this assertion object.
590-
* @throws AssertionError if the actual is exactly an instance of given type.
623+
* @throws AssertionError if the actual is exactly an instance of given type.
591624
* @throws NullPointerException if the actual value is null.
592625
* @throws NullPointerException if the given object is null.
593626
*/
@@ -607,7 +640,7 @@ public interface Assert<SELF extends Assert<SELF, ACTUAL>, ACTUAL> extends Descr
607640
*
608641
* @param types the types to check the actual value against.
609642
* @return this assertion object.
610-
* @throws AssertionError if the actual value type is not in given type.
643+
* @throws AssertionError if the actual value type is not in given type.
611644
* @throws NullPointerException if the actual value is null.
612645
* @throws NullPointerException if the given types is null.
613646
*/
@@ -627,7 +660,7 @@ public interface Assert<SELF extends Assert<SELF, ACTUAL>, ACTUAL> extends Descr
627660
*
628661
* @param types the types to check the actual value against.
629662
* @return this assertion object.
630-
* @throws AssertionError if the actual value type is in given types.
663+
* @throws AssertionError if the actual value type is in given types.
631664
* @throws NullPointerException if the actual value is null.
632665
* @throws NullPointerException if the given types is null.
633666
*/
@@ -673,10 +706,9 @@ public interface Assert<SELF extends Assert<SELF, ACTUAL>, ACTUAL> extends Descr
673706
AbstractCharSequenceAssert<?, String> asString();
674707

675708
/**
676-
* @deprecated
677-
* Throws <code>{@link UnsupportedOperationException}</code> if called. It is easy to accidentally call
678-
* <code>equals(Object)</code> instead of <code>{@link #isEqualTo(Object)}</code>.
679709
* @throws UnsupportedOperationException if this method is called.
710+
* @deprecated Throws <code>{@link UnsupportedOperationException}</code> if called. It is easy to accidentally call
711+
* <code>equals(Object)</code> instead of <code>{@link #isEqualTo(Object)}</code>.
680712
*/
681713
@Override
682714
@Deprecated
@@ -687,7 +719,7 @@ public interface Assert<SELF extends Assert<SELF, ACTUAL>, ACTUAL> extends Descr
687719
* <p>
688720
* Example :
689721
* <pre><code class='java'> assertThat("Messi").withThreadDumpOnError().isEqualTo("Ronaldo");</code></pre>
690-
*
722+
* <p>
691723
* will print a thread dump, something similar to this:
692724
* <pre>{@code "JDWP Command Reader"
693725
* java.lang.Thread.State: RUNNABLE
@@ -793,13 +825,10 @@ public interface Assert<SELF extends Assert<SELF, ACTUAL>, ACTUAL> extends Descr
793825
* assertThat(&quot;The Force&quot;).hasSameHashCodeAs(&quot;Awakens&quot;);</code></pre>
794826
*
795827
* @param other the object to check hashCode against.
796-
*
797828
* @return this assertion object.
798-
*
799-
* @throws AssertionError if the actual object is null.
829+
* @throws AssertionError if the actual object is null.
800830
* @throws NullPointerException if the other object is null.
801-
* @throws AssertionError if the actual object has not the same hashCode as the given object.
802-
*
831+
* @throws AssertionError if the actual object has not the same hashCode as the given object.
803832
* @since 2.9.0
804833
*/
805834
SELF hasSameHashCodeAs(Object other);
@@ -818,13 +847,10 @@ public interface Assert<SELF extends Assert<SELF, ACTUAL>, ACTUAL> extends Descr
818847
* assertThat(new Jedi(&quot;Yoda&quot;, &quot;Blue&quot;)).doesNotHaveSameHashCodeAs(new Jedi(&quot;Yoda&quot;, &quot;Blue&quot;)); </code></pre>
819848
*
820849
* @param other the object to check hashCode against.
821-
*
822850
* @return this assertion object.
823-
*
824-
* @throws AssertionError if the actual object is null.
851+
* @throws AssertionError if the actual object is null.
825852
* @throws NullPointerException if the other object is null.
826-
* @throws AssertionError if the actual object has the same hashCode as the given object.
827-
*
853+
* @throws AssertionError if the actual object has the same hashCode as the given object.
828854
* @since 3.19.0
829855
*/
830856
SELF doesNotHaveSameHashCodeAs(Object other);

0 commit comments

Comments
 (0)