• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2016 Google, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.google.common.truth;
17 
18 import static com.google.common.base.Functions.identity;
19 import static com.google.common.base.Preconditions.checkNotNull;
20 import static com.google.common.base.Preconditions.checkState;
21 import static com.google.common.truth.DoubleSubject.checkTolerance;
22 import static com.google.common.truth.Fact.fact;
23 import static com.google.common.truth.Fact.simpleFact;
24 import static com.google.common.truth.Platform.getStackTraceAsString;
25 import static java.util.Arrays.asList;
26 
27 import com.google.common.base.Function;
28 import com.google.common.base.Joiner;
29 import com.google.common.base.Objects;
30 import com.google.common.base.Strings;
31 import com.google.common.collect.ImmutableList;
32 import java.util.Arrays;
33 import java.util.List;
34 import org.checkerframework.checker.nullness.qual.Nullable;
35 
36 /**
37  * Determines whether an instance of type {@code A} corresponds in some way to an instance of type
38  * {@code E} for the purposes of a test assertion. For example, the implementation returned by the
39  * {@link #tolerance(double)} factory method implements approximate equality between numeric values,
40  * with values being said to correspond if the difference between them does not exceed the given
41  * fixed tolerance. The instances of type {@code A} are typically actual values from a collection
42  * returned by the code under test; the instances of type {@code E} are typically expected values
43  * with which the actual values are compared by the test.
44  *
45  * <p>The correspondence is required to be consistent: for any given values {@code actual} and
46  * {@code expected}, multiple invocations of {@code compare(actual, expected)} must consistently
47  * return {@code true} or consistently return {@code false} (provided that neither value is
48  * modified). Although {@code A} and {@code E} will often be the same types, they are <i>not</i>
49  * required to be the same, and even if they are it is <i>not</i> required that the correspondence
50  * should have any of the other properties of an equivalence relation (reflexivity, symmetry, or
51  * transitivity).
52  *
53  * <p>Optionally, instances of this class can also provide functionality to format the difference
54  * between values which do not correspond. This results in failure messages including formatted
55  * diffs between expected and actual value, where possible.
56  *
57  * <p>The recommended approach for creating an instance of this class is to use one of the static
58  * factory methods. The most general of these is {@link #from}; the other methods are more
59  * convenient in specific cases. The optional diff-formatting functionality can be added using
60  * {@link #formattingDiffsUsing}. (Alternatively, you can subclass this class yourself, but that is
61  * generally not recommended.)
62  *
63  * <p>Instances of this are typically used via {@link IterableSubject#comparingElementsUsing},
64  * {@link MapSubject#comparingValuesUsing}, or {@link MultimapSubject#comparingValuesUsing}.
65  *
66  * @author Pete Gillin
67  */
68 public abstract class Correspondence<A extends @Nullable Object, E extends @Nullable Object> {
69 
70   /**
71    * Constructs a {@link Correspondence} that compares actual and expected elements using the given
72    * binary predicate.
73    *
74    * <p>The correspondence does not support formatting of diffs (see {@link #formatDiff}). You can
75    * add that behaviour by calling {@link Correspondence#formattingDiffsUsing}.
76    *
77    * <p>Note that, if the data you are asserting about contains nulls, your predicate may be invoked
78    * with null arguments. If this causes it to throw a {@link NullPointerException}, then your test
79    * will fail. (See {@link Correspondence#compare} for more detail on how exceptions are handled.)
80    * In particular, if your predicate is an instance method reference on the actual value (as in the
81    * {@code String::contains} example below), your test will fail if it sees null actual values.
82    *
83    * <p>Example using an instance method reference:
84    *
85    * <pre>{@code
86    * static final Correspondence<String, String> CONTAINS_SUBSTRING =
87    *     Correspondence.from(String::contains, "contains");
88    * }</pre>
89    *
90    * <p>Example using a static method reference:
91    *
92    * <pre>{@code
93    * class MyRecordTestHelper {
94    *   static final Correspondence<MyRecord, MyRecord> EQUIVALENCE =
95    *       Correspondence.from(MyRecordTestHelper::recordsEquivalent, "is equivalent to");
96    *   static boolean recordsEquivalent(MyRecord actual, MyRecord expected) {
97    *     // code to check whether records should be considered equivalent for testing purposes
98    *   }
99    * }
100    * }</pre>
101    *
102    * <p>Example using a lambda:
103    *
104    * <pre>{@code
105    * static final Correspondence<Object, Class<?>> INSTANCE_OF =
106    *     Correspondence.from((obj, clazz) -> clazz.isInstance(obj), "is an instance of");
107    * }</pre>
108    *
109    * @param predicate a {@link BinaryPredicate} taking an actual and expected value (in that order)
110    *     and returning whether the actual value corresponds to the expected value in some way
111    * @param description should fill the gap in a failure message of the form {@code "not true that
112    *     <some actual element> is an element that <description> <some expected element>"}, e.g.
113    *     {@code "contains"}, {@code "is an instance of"}, or {@code "is equivalent to"}
114    */
from( BinaryPredicate<A, E> predicate, String description)115   public static <A extends @Nullable Object, E extends @Nullable Object> Correspondence<A, E> from(
116       BinaryPredicate<A, E> predicate, String description) {
117     return new FromBinaryPredicate<>(predicate, description);
118   }
119 
120   /**
121    * A functional interface for a binary predicate, to be used to test whether a pair of objects of
122    * types {@code A} and {@code E} satisfy some condition.
123    *
124    * <p>This interface will normally be implemented using a lambda or a method reference, and the
125    * resulting object will normally be passed directly to {@link Correspondence#from}. As a result,
126    * you should almost never see {@code BinaryPredicate} used as the type of a field or variable, or
127    * a return type.
128    */
129   public interface BinaryPredicate<A extends @Nullable Object, E extends @Nullable Object> {
130 
131     /**
132      * Returns whether or not the actual and expected values satisfy the condition defined by this
133      * predicate.
134      */
apply(A actual, E expected)135     boolean apply(A actual, E expected);
136   }
137 
138   private static final class FromBinaryPredicate<
139           A extends @Nullable Object, E extends @Nullable Object>
140       extends Correspondence<A, E> {
141     private final BinaryPredicate<A, E> predicate;
142     private final String description;
143 
FromBinaryPredicate(BinaryPredicate<A, E> correspondencePredicate, String description)144     private FromBinaryPredicate(BinaryPredicate<A, E> correspondencePredicate, String description) {
145       this.predicate = checkNotNull(correspondencePredicate);
146       this.description = checkNotNull(description);
147     }
148 
149     @Override
compare(A actual, E expected)150     public boolean compare(A actual, E expected) {
151       return predicate.apply(actual, expected);
152     }
153 
154     @Override
toString()155     public String toString() {
156       return description;
157     }
158   }
159 
160   /**
161    * Constructs a {@link Correspondence} that compares elements by transforming the actual elements
162    * using the given function and testing for equality with the expected elements. If the
163    * transformed actual element (i.e. the output of the given function) is null, it will correspond
164    * to a null expected element.
165    *
166    * <p>The correspondence does not support formatting of diffs (see {@link #formatDiff}). You can
167    * add that behaviour by calling {@link Correspondence#formattingDiffsUsing}.
168    *
169    * <p>Note that, if you the data you are asserting about contains null actual values, your
170    * function may be invoked with a null argument. If this causes it to throw a {@link
171    * NullPointerException}, then your test will fail. (See {@link Correspondence#compare} for more
172    * detail on how exceptions are handled.) In particular, this applies if your function is an
173    * instance method reference on the actual value (as in the example below). If you want a null
174    * actual element to correspond to a null expected element, you must ensure that your function
175    * transforms a null input to a null output.
176    *
177    * <p>Example:
178    *
179    * <pre>{@code
180    * static final Correspondence<MyRecord, Integer> HAS_ID =
181    *     Correspondence.transforming(MyRecord::getId, "has an ID of");
182    * }</pre>
183    *
184    * This can be used as follows:
185    *
186    * <pre>{@code
187    * assertThat(myRecords).comparingElementsUsing(HAS_ID).containsExactly(123, 456, 789);
188    * }</pre>
189    *
190    * @param actualTransform a {@link Function} taking an actual value and returning a new value
191    *     which will be compared with an expected value to determine whether they correspond
192    * @param description should fill the gap in a failure message of the form {@code "not true that
193    *     <some actual element> is an element that <description> <some expected element>"}, e.g.
194    *     {@code "has an ID of"}
195    */
196   public static <A extends @Nullable Object, E extends @Nullable Object>
transforming( Function<A, ? extends E> actualTransform, String description)197       Correspondence<A, E> transforming(
198           Function<A, ? extends E> actualTransform, String description) {
199     return new Transforming<>(actualTransform, identity(), description);
200   }
201 
202   /**
203    * Constructs a {@link Correspondence} that compares elements by transforming the actual and the
204    * expected elements using the given functions and testing the transformed values for equality. If
205    * an actual element is transformed to null, it will correspond to an expected element that is
206    * also transformed to null.
207    *
208    * <p>The correspondence does not support formatting of diffs (see {@link #formatDiff}). You can
209    * add that behaviour by calling {@link Correspondence#formattingDiffsUsing}.
210    *
211    * <p>Note that, if you the data you are asserting about contains null actual or expected values,
212    * the appropriate function may be invoked with a null argument. If this causes it to throw a
213    * {@link NullPointerException}, then your test will fail. (See {@link Correspondence#compare} for
214    * more detail on how exceptions are handled.) In particular, this applies if your function is an
215    * instance method reference on the actual or expected value (as in the example below). If you
216    * want a null actual element to correspond to a null expected element, you must ensure that your
217    * functions both transform a null input to a null output.
218    *
219    * <p>If you want to apply the same function to both the actual and expected elements, just
220    * provide the same argument twice.
221    *
222    * <p>Example:
223    *
224    * <pre>{@code
225    * static final Correspondence<MyRequest, MyResponse> SAME_IDS =
226    *     Correspondence.transforming(MyRequest::getId, MyResponse::getId, "has the same ID as");
227    * }</pre>
228    *
229    * This can be used as follows:
230    *
231    * <pre>{@code
232    * assertThat(myResponses).comparingElementsUsing(SAME_IDS).containsExactlyElementsIn(myRequests);
233    * }</pre>
234    *
235    * @param actualTransform a {@link Function} taking an actual value and returning a new value
236    *     which will be compared with a transformed expected value to determine whether they
237    *     correspond
238    * @param expectedTransform a {@link Function} taking an expected value and returning a new value
239    *     which will be compared with a transformed actual value
240    * @param description should fill the gap in a failure message of the form {@code "not true that
241    *     <some actual element> is an element that <description> <some expected element>"}, e.g.
242    *     {@code "has the same ID as"}
243    */
244   public static <A extends @Nullable Object, E extends @Nullable Object>
transforming( Function<A, ?> actualTransform, Function<E, ?> expectedTransform, String description)245       Correspondence<A, E> transforming(
246           Function<A, ?> actualTransform, Function<E, ?> expectedTransform, String description) {
247     return new Transforming<>(actualTransform, expectedTransform, description);
248   }
249 
250   private static final class Transforming<A extends @Nullable Object, E extends @Nullable Object>
251       extends Correspondence<A, E> {
252 
253     private final Function<? super A, ?> actualTransform;
254     private final Function<? super E, ?> expectedTransform;
255     private final String description;
256 
Transforming( Function<? super A, ?> actualTransform, Function<? super E, ?> expectedTransform, String description)257     private Transforming(
258         Function<? super A, ?> actualTransform,
259         Function<? super E, ?> expectedTransform,
260         String description) {
261       this.actualTransform = actualTransform;
262       this.expectedTransform = expectedTransform;
263       this.description = description;
264     }
265 
266     @Override
compare(A actual, E expected)267     public boolean compare(A actual, E expected) {
268       return Objects.equal(actualTransform.apply(actual), expectedTransform.apply(expected));
269     }
270 
271     @Override
toString()272     public String toString() {
273       return description;
274     }
275   }
276 
277   /**
278    * Returns a {@link Correspondence} between {@link Number} instances that considers instances to
279    * correspond (i.e. {@link Correspondence#compare(Object, Object)} returns {@code true}) if the
280    * double values of each instance (i.e. the result of calling {@link Number#doubleValue()} on
281    * them) are finite values within {@code tolerance} of each other.
282    *
283    * <ul>
284    *   <li>It does not consider instances to correspond if either value is infinite or NaN.
285    *   <li>The conversion to double may result in a loss of precision for some numeric types.
286    *   <li>The {@link Correspondence#compare(Object, Object)} method throws a {@link
287    *       NullPointerException} if either {@link Number} instance is null.
288    * </ul>
289    *
290    * @param tolerance an inclusive upper bound on the difference between the double values of the
291    *     two {@link Number} instances, which must be a non-negative finite value, i.e. not {@link
292    *     Double#NaN}, {@link Double#POSITIVE_INFINITY}, or negative, including {@code -0.0}
293    */
tolerance(double tolerance)294   public static Correspondence<Number, Number> tolerance(double tolerance) {
295     return new TolerantNumericEquality(tolerance);
296   }
297 
298   private static final class TolerantNumericEquality extends Correspondence<Number, Number> {
299 
300     private final double tolerance;
301 
TolerantNumericEquality(double tolerance)302     private TolerantNumericEquality(double tolerance) {
303       checkTolerance(tolerance);
304       this.tolerance = tolerance;
305     }
306 
307     @Override
compare(Number actual, Number expected)308     public boolean compare(Number actual, Number expected) {
309       double actualDouble = checkNotNull(actual).doubleValue();
310       double expectedDouble = checkNotNull(expected).doubleValue();
311       return MathUtil.equalWithinTolerance(actualDouble, expectedDouble, tolerance);
312     }
313 
314     @Override
toString()315     public String toString() {
316       return "is a finite number within " + tolerance + " of";
317     }
318   }
319 
320   /**
321    * Returns a correspondence which compares elements using object equality, i.e. giving the same
322    * assertions as you would get without a correspondence. This exists so that we can add a
323    * diff-formatting functionality to it. See e.g. {@link IterableSubject#formattingDiffsUsing}.
324    */
325   @SuppressWarnings("unchecked") // safe covariant cast
equality()326   static <T> Correspondence<T, T> equality() {
327     return (Equality<T>) Equality.INSTANCE;
328   }
329 
330   private static final class Equality<T> extends Correspondence<T, T> {
331 
332     private static final Equality<Object> INSTANCE = new Equality<>();
333 
334     @Override
compare(T actual, T expected)335     public boolean compare(T actual, T expected) {
336       return Objects.equal(actual, expected);
337     }
338 
339     @Override
toString()340     public String toString() {
341       // This should normally not be used, since isEquality() returns true, but it should do
342       // something sensible anyway:
343       return "is equal to";
344     }
345 
346     @Override
isEquality()347     boolean isEquality() {
348       return true;
349     }
350   }
351 
352   /**
353    * Constructor. Creating subclasses (anonymous or otherwise) of this class is <i>not
354    * recommended</i>, but is possible via this constructor. The recommended approach is to use the
355    * factory methods instead (see {@linkplain Correspondence class-level documentation}).
356    *
357    * @deprecated Construct an instance with the static factory methods instead. The most mechanical
358    *     migration is usually to {@link #from}.
359    */
360   @Deprecated
Correspondence()361   Correspondence() {}
362 
363   /**
364    * Returns a new correspondence which is like this one, except that the given formatter may be
365    * used to format the difference between a pair of elements that do not correspond.
366    *
367    * <p>Note that, if you the data you are asserting about contains null actual or expected values,
368    * the formatter may be invoked with a null argument. If this causes it to throw a {@link
369    * NullPointerException}, that will be taken to indicate that the values cannot be diffed. (See
370    * {@link Correspondence#formatDiff} for more detail on how exceptions are handled.) If you think
371    * null values are likely, it is slightly cleaner to have the formatter return null in that case
372    * instead of throwing.
373    *
374    * <p>Example:
375    *
376    * <pre>{@code
377    * class MyRecordTestHelper {
378    *   static final Correspondence<MyRecord, MyRecord> EQUIVALENCE =
379    *       Correspondence.from(MyRecordTestHelper::recordsEquivalent, "is equivalent to")
380    *           .formattingDiffsUsing(MyRecordTestHelper::formatRecordDiff);
381    *   static boolean recordsEquivalent(MyRecord actual, MyRecord expected) {
382    *     // code to check whether records should be considered equivalent for testing purposes
383    *   }
384    *   static String formatRecordDiff(MyRecord actual, MyRecord expected) {
385    *     // code to format the diff between the records
386    *   }
387    * }
388    * }</pre>
389    */
formattingDiffsUsing(DiffFormatter<? super A, ? super E> formatter)390   public Correspondence<A, E> formattingDiffsUsing(DiffFormatter<? super A, ? super E> formatter) {
391     return new FormattingDiffs<>(this, formatter);
392   }
393 
394   /**
395    * A functional interface to be used format the diff between a pair of objects of types {@code A}
396    * and {@code E}.
397    *
398    * <p>This interface will normally be implemented using a lambda or a method reference, and the
399    * resulting object will normally be passed directly to {@link
400    * Correspondence#formattingDiffsUsing}. As a result, you should almost never see {@code
401    * DiffFormatter} used as the type of a field or variable, or a return type.
402    */
403   public interface DiffFormatter<A extends @Nullable Object, E extends @Nullable Object> {
404 
405     /**
406      * Returns a {@link String} describing the difference between the {@code actual} and {@code
407      * expected} values, if possible, or {@code null} if not.
408      */
409     @Nullable
formatDiff(A actual, E expected)410     String formatDiff(A actual, E expected);
411   }
412 
413   private static class FormattingDiffs<A extends @Nullable Object, E extends @Nullable Object>
414       extends Correspondence<A, E> {
415 
416     private final Correspondence<A, E> delegate;
417     private final DiffFormatter<? super A, ? super E> formatter;
418 
FormattingDiffs(Correspondence<A, E> delegate, DiffFormatter<? super A, ? super E> formatter)419     FormattingDiffs(Correspondence<A, E> delegate, DiffFormatter<? super A, ? super E> formatter) {
420       this.delegate = checkNotNull(delegate);
421       this.formatter = checkNotNull(formatter);
422     }
423 
424     @Override
compare(A actual, E expected)425     public boolean compare(A actual, E expected) {
426       return delegate.compare(actual, expected);
427     }
428 
429     @Override
formatDiff(A actual, E expected)430     public @Nullable String formatDiff(A actual, E expected) {
431       return formatter.formatDiff(actual, expected);
432     }
433 
434     @Override
toString()435     public String toString() {
436       return delegate.toString();
437     }
438 
439     @Override
isEquality()440     boolean isEquality() {
441       return delegate.isEquality();
442     }
443   }
444 
445   /**
446    * Returns whether or not the {@code actual} value is said to correspond to the {@code expected}
447    * value for the purposes of this test.
448    *
449    * <h3>Exception handling</h3>
450    *
451    * <p>Throwing a {@link RuntimeException} from this method indicates that this {@link
452    * Correspondence} cannot compare the given values. Any assertion which encounters such an
453    * exception during the course of evaluating its condition must not pass. However, an assertion is
454    * not required to invoke this method for every pair of values in its input just in order to check
455    * for exceptions, if it is able to evaluate its condition without doing so.
456    *
457    * <h4>Conventions for handling exceptions</h4>
458    *
459    * <p>(N.B. This section is only really of interest when implementing assertion methods that call
460    * {@link Correspondence#compare}, not to users making such assertions in their tests.)
461    *
462    * <p>The only requirement on an assertion is that, if it encounters an exception from this
463    * method, it must not pass. The simplest implementation choice is simply to allow the exception
464    * to propagate. However, it is normally more helpful to catch the exception and instead fail with
465    * a message which includes more information about the assertion in progress and the nature of the
466    * failure.
467    *
468    * <p>By convention, an assertion may catch and store the exception and continue evaluating the
469    * condition as if the method had returned false instead of throwing. If the assertion's condition
470    * does not hold with this alternative behaviour, it may choose to fail with a message that gives
471    * details about how the condition does not hold, additionally mentioning that assertions were
472    * encountered and giving details about one of the stored exceptions. (See the first example
473    * below.) If the assertion's condition does hold with this alternative behaviour, the requirement
474    * that the assertion must not pass still applies, so it should fail with a message giving details
475    * about one of the stored exceptions. (See the second and third examples below.)
476    *
477    * <p>This behaviour is only a convention and should only be implemented when it makes sense to do
478    * so. In particular, in an assertion that has multiple stages, it may be better to only continue
479    * evaluation to the end of the current stage, and fail citing a stored exception at the end of
480    * the stage, rather than accumulating exceptions through the multiple stages.
481    *
482    * <h4>Examples of exception handling</h4>
483    *
484    * <p>Suppose that we have the correspondence
485    *
486    * <pre>{@code
487    * static final Correspondence<String, String> CASE_INSENSITIVE_EQUALITY =
488    *     Correspondence.from(String::equalsIgnoreCase, "equals ignoring case"}
489    * }</pre>
490    *
491    * whose {@code compare} method throws {@link NullPointerException} if the actual value is null.
492    * The assertion
493    *
494    * <pre>{@code
495    * assertThat(asList(null, "xyz", "abc", "def"))
496    *     .comparingElementsUsing(CASE_INSENSITIVE_EQUALITY)
497    *     .containsExactly("ABC", "DEF", "GHI", "JKL");
498    * }</pre>
499    *
500    * may fail saying that the actual iterable contains unexpected values {@code null} and {@code
501    * xyz} and is missing values corresponding to {@code GHI} and {@code JKL}, which is what it would
502    * do if the {@code compare} method returned false instead of throwing, and additionally mention
503    * the exception. (This is more helpful than allowing the {@link NullPointerException} to
504    * propagate to the caller, or than failing with only a description of the exception.)
505    *
506    * <p>However, the assertions
507    *
508    * <pre>{@code
509    * assertThat(asList(null, "xyz", "abc", "def"))
510    *     .comparingElementsUsing(CASE_INSENSITIVE_EQUALITY)
511    *     .doesNotContain("MNO");
512    * }</pre>
513    *
514    * and
515    *
516    * <pre>{@code
517    * assertThat(asList(null, "xyz", "abc", "def"))
518    *     .comparingElementsUsing(CASE_INSENSITIVE_EQUALITY)
519    *     .doesNotContain(null);
520    * }</pre>
521    *
522    * must both fail citing the exception, even though they would pass if the {@code compare} method
523    * returned false. (Note that, in the latter case at least, it is likely that the test author's
524    * intention was <i>not</i> for the test to pass with these values.)
525    */
compare(A actual, E expected)526   public abstract boolean compare(A actual, E expected);
527 
528   private static class StoredException {
529 
530     private static final Joiner ARGUMENT_JOINER = Joiner.on(", ").useForNull("null");
531 
532     private final Exception exception;
533     private final String methodName;
534     private final List<@Nullable Object> methodArguments;
535 
StoredException( Exception exception, String methodName, List<@Nullable Object> methodArguments)536     StoredException(
537         Exception exception, String methodName, List<@Nullable Object> methodArguments) {
538       this.exception = checkNotNull(exception);
539       this.methodName = checkNotNull(methodName);
540       this.methodArguments = checkNotNull(methodArguments);
541     }
542 
543     /**
544      * Returns a String describing the exception stored. This includes a stack trace (except under
545      * j2cl, where this is not available). It also has a separator at the end, so that when this
546      * appears at the end of an {@code AssertionError} message, the stack trace of the stored
547      * exception is distinguishable from the stack trace of the {@code AssertionError}.
548      */
describe()549     private String describe() {
550       return Strings.lenientFormat(
551           "%s(%s) threw %s\n---",
552           methodName, ARGUMENT_JOINER.join(methodArguments), getStackTraceAsString(exception));
553     }
554   }
555 
556   /**
557    * Helper object to store exceptions encountered while executing a {@link Correspondence} method.
558    */
559   static final class ExceptionStore {
560 
561     private final String argumentLabel;
562     private @Nullable StoredException firstCompareException = null;
563     private @Nullable StoredException firstPairingException = null;
564     private @Nullable StoredException firstFormatDiffException = null;
565 
forIterable()566     static ExceptionStore forIterable() {
567       return new ExceptionStore("elements");
568     }
569 
forMapValues()570     static ExceptionStore forMapValues() {
571       return new ExceptionStore("values");
572     }
573 
ExceptionStore(String argumentLabel)574     private ExceptionStore(String argumentLabel) {
575       this.argumentLabel = argumentLabel;
576     }
577 
578     /**
579      * Adds an exception that was thrown during a {@code compare} call.
580      *
581      * @param callingClass The class from which the {@code compare} method was called. When
582      *     reporting failures, stack traces will be truncated above elements in this class.
583      * @param exception The exception encountered
584      * @param actual The {@code actual} argument to the {@code compare} call during which the
585      *     exception was encountered
586      * @param expected The {@code expected} argument to the {@code compare} call during which the
587      *     exception was encountered
588      */
addCompareException( Class<?> callingClass, Exception exception, @Nullable Object actual, @Nullable Object expected)589     void addCompareException(
590         Class<?> callingClass,
591         Exception exception,
592         @Nullable Object actual,
593         @Nullable Object expected) {
594       if (firstCompareException == null) {
595         truncateStackTrace(exception, callingClass);
596         firstCompareException = new StoredException(exception, "compare", asList(actual, expected));
597       }
598     }
599 
600     /**
601      * Adds an exception that was thrown during an {@code apply} call on the function used to key
602      * actual elements.
603      *
604      * @param callingClass The class from which the {@code apply} method was called. When reporting
605      *     failures, stack traces will be truncated above elements in this class.
606      * @param exception The exception encountered
607      * @param actual The {@code actual} argument to the {@code apply} call during which the
608      *     exception was encountered
609      */
addActualKeyFunctionException( Class<?> callingClass, Exception exception, @Nullable Object actual)610     void addActualKeyFunctionException(
611         Class<?> callingClass, Exception exception, @Nullable Object actual) {
612       if (firstPairingException == null) {
613         truncateStackTrace(exception, callingClass);
614         firstPairingException =
615             new StoredException(exception, "actualKeyFunction.apply", asList(actual));
616       }
617     }
618 
619     /**
620      * Adds an exception that was thrown during an {@code apply} call on the function used to key
621      * expected elements.
622      *
623      * @param callingClass The class from which the {@code apply} method was called. When reporting
624      *     failures, stack traces will be truncated above elements in this class.
625      * @param exception The exception encountered
626      * @param expected The {@code expected} argument to the {@code apply} call during which the
627      *     exception was encountered
628      */
addExpectedKeyFunctionException( Class<?> callingClass, Exception exception, @Nullable Object expected)629     void addExpectedKeyFunctionException(
630         Class<?> callingClass, Exception exception, @Nullable Object expected) {
631       if (firstPairingException == null) {
632         truncateStackTrace(exception, callingClass);
633         firstPairingException =
634             new StoredException(exception, "expectedKeyFunction.apply", asList(expected));
635       }
636     }
637 
638     /**
639      * Adds an exception that was thrown during a {@code formatDiff} call.
640      *
641      * @param callingClass The class from which the {@code formatDiff} method was called. When
642      *     reporting failures, stack traces will be truncated above elements in this class.
643      * @param exception The exception encountered
644      * @param actual The {@code actual} argument to the {@code formatDiff} call during which the
645      *     exception was encountered
646      * @param expected The {@code expected} argument to the {@code formatDiff} call during which the
647      *     exception was encountered
648      */
addFormatDiffException( Class<?> callingClass, Exception exception, @Nullable Object actual, @Nullable Object expected)649     void addFormatDiffException(
650         Class<?> callingClass,
651         Exception exception,
652         @Nullable Object actual,
653         @Nullable Object expected) {
654       if (firstFormatDiffException == null) {
655         truncateStackTrace(exception, callingClass);
656         firstFormatDiffException =
657             new StoredException(exception, "formatDiff", asList(actual, expected));
658       }
659     }
660 
661     /** Returns whether any exceptions thrown during {@code compare} calls were stored. */
hasCompareException()662     boolean hasCompareException() {
663       return firstCompareException != null;
664     }
665 
666     /**
667      * Returns facts to use in a failure message when the exceptions from {@code compare} calls are
668      * the main cause of the failure. At least one exception thrown during a {@code compare} call
669      * must have been stored, and no exceptions from a {@code formatDiff} call. Assertions should
670      * use this when exceptions were thrown while comparing elements and no more meaningful failure
671      * was discovered by assuming a false return and continuing (see the javadoc for {@link
672      * Correspondence#compare}). C.f. {@link #describeAsAdditionalInfo}.
673      */
describeAsMainCause()674     ImmutableList<Fact> describeAsMainCause() {
675       checkState(firstCompareException != null);
676       // We won't do pairing or diff formatting unless a more meaningful failure was found, and if a
677       // more meaningful failure was found then we shouldn't be using this method:
678       checkState(firstPairingException == null);
679       checkState(firstFormatDiffException == null);
680       return ImmutableList.of(
681           simpleFact("one or more exceptions were thrown while comparing " + argumentLabel),
682           fact("first exception", firstCompareException.describe()));
683     }
684 
685     /**
686      * If any exceptions are stored, returns facts to use in a failure message when the exceptions
687      * should be noted as additional info; if empty, returns an empty list. Assertions should use
688      * this when exceptions were thrown while comparing elements but more meaningful failures were
689      * discovered by assuming a false return and continuing (see the javadoc for {@link
690      * Correspondence#compare}), or when exceptions were thrown by other methods while generating
691      * the failure message. C.f. {@link #describeAsMainCause}.
692      */
describeAsAdditionalInfo()693     ImmutableList<Fact> describeAsAdditionalInfo() {
694       ImmutableList.Builder<Fact> builder = ImmutableList.builder();
695       if (firstCompareException != null) {
696         builder.add(
697             simpleFact(
698                 "additionally, one or more exceptions were thrown while comparing "
699                     + argumentLabel));
700         builder.add(fact("first exception", firstCompareException.describe()));
701       }
702       if (firstPairingException != null) {
703         builder.add(
704             simpleFact(
705                 "additionally, one or more exceptions were thrown while keying "
706                     + argumentLabel
707                     + " for pairing"));
708         builder.add(fact("first exception", firstPairingException.describe()));
709       }
710       if (firstFormatDiffException != null) {
711         builder.add(
712             simpleFact("additionally, one or more exceptions were thrown while formatting diffs"));
713         builder.add(fact("first exception", firstFormatDiffException.describe()));
714       }
715       return builder.build();
716     }
717 
truncateStackTrace(Exception exception, Class<?> callingClass)718     private static void truncateStackTrace(Exception exception, Class<?> callingClass) {
719       StackTraceElement[] original = exception.getStackTrace();
720       int keep = 0;
721       while (keep < original.length
722           && !original[keep].getClassName().equals(callingClass.getName())) {
723         keep++;
724       }
725       exception.setStackTrace(Arrays.copyOf(original, keep));
726     }
727   }
728 
729   /**
730    * Invokes {@link #compare}, catching any exceptions. If the comparison does not throw, returns
731    * the result. If it does throw, adds the exception to the given {@link ExceptionStore} and
732    * returns false. This method can help with implementing the exception-handling policy described
733    * above, but note that assertions using it <i>must</i> fail later if an exception was stored.
734    */
safeCompare(A actual, E expected, ExceptionStore exceptions)735   final boolean safeCompare(A actual, E expected, ExceptionStore exceptions) {
736     try {
737       return compare(actual, expected);
738     } catch (RuntimeException e) {
739       exceptions.addCompareException(Correspondence.class, e, actual, expected);
740       return false;
741     }
742   }
743 
744   /**
745    * Returns a {@link String} describing the difference between the {@code actual} and {@code
746    * expected} values, if possible, or {@code null} if not.
747    *
748    * <p>The implementation on the {@link Correspondence} base class always returns {@code null}. To
749    * enable diffing, use {@link #formattingDiffsUsing} (or override this method in a subclass, but
750    * factory methods are recommended over subclassing).
751    *
752    * <p>Assertions should only invoke this with parameters for which {@link #compare} returns {@code
753    * false}.
754    *
755    * <p>If this throws an exception, that implies that it is not possible to describe the diffs. An
756    * assertion will normally only call this method if it has established that its condition does not
757    * hold: good practice dictates that, if this method throws, the assertion should catch the
758    * exception and continue to describe the original failure as if this method had returned null,
759    * mentioning the failure from this method as additional information.
760    */
formatDiff(A actual, E expected)761   public @Nullable String formatDiff(A actual, E expected) {
762     return null;
763   }
764 
765   /**
766    * Invokes {@link #formatDiff}, catching any exceptions. If the comparison does not throw, returns
767    * the result. If it does throw, adds the exception to the given {@link ExceptionStore} and
768    * returns null.
769    */
safeFormatDiff(A actual, E expected, ExceptionStore exceptions)770   final @Nullable String safeFormatDiff(A actual, E expected, ExceptionStore exceptions) {
771     try {
772       return formatDiff(actual, expected);
773     } catch (RuntimeException e) {
774       exceptions.addFormatDiffException(Correspondence.class, e, actual, expected);
775       return null;
776     }
777   }
778 
779   /**
780    * Returns a description of the correspondence, suitable to fill the gap in a failure message of
781    * the form {@code "<some actual element> is an element that ... <some expected element>"}. Note
782    * that this is a fragment of a verb phrase which takes a singular subject.
783    *
784    * <p>Example 1: For a {@code Correspondence<String, Integer>} that tests whether the actual
785    * string parses to the expected integer, this would return {@code "parses to"} to result in a
786    * failure message of the form {@code "<some actual string> is an element that parses to <some
787    * expected integer>"}.
788    *
789    * <p>Example 2: For the {@code Correspondence<Number, Number>} returns by {@link #tolerance} this
790    * returns {@code "is a finite number within " + tolerance + " of"} to result in a failure message
791    * of the form {@code "<some actual number> is an element that is a finite number within 0.0001 of
792    * <some expected number>"}.
793    */
794   @Override
toString()795   public abstract String toString();
796 
797   /**
798    * Returns whether this is an equality correspondence, i.e. one returned by {@link #equality} or
799    * one whose {@link #compare} delegates to one returned by {@link #equality}.
800    */
isEquality()801   boolean isEquality() {
802     return false;
803   }
804 
805   /**
806    * Returns a list of {@link Fact} instance describing how this correspondence compares elements of
807    * an iterable. There will be one "testing whether" fact, unless this {@link #isEquality is an
808    * equality correspondence}, in which case the list will be empty.
809    */
describeForIterable()810   final ImmutableList<Fact> describeForIterable() {
811     if (!isEquality()) {
812       return ImmutableList.of(
813           fact("testing whether", "actual element " + this + " expected element"));
814     } else {
815       return ImmutableList.of();
816     }
817   }
818 
819   /**
820    * Returns a list of {@link Fact} instance describing how this correspondence compares values in a
821    * map (or multimap). There will be one "testing whether" fact, unless this {@link #isEquality is
822    * an equality correspondence}, in which case the list will be empty.
823    */
describeForMapValues()824   final ImmutableList<Fact> describeForMapValues() {
825     if (!isEquality()) {
826       return ImmutableList.of(fact("testing whether", "actual value " + this + " expected value"));
827     } else {
828       return ImmutableList.of();
829     }
830   }
831 
832   /**
833    * @throws UnsupportedOperationException always
834    * @deprecated {@link Object#equals(Object)} is not supported. If you meant to compare objects
835    *     using this {@link Correspondence}, use {@link #compare}.
836    */
837   @Deprecated
838   @Override
equals(@ullable Object o)839   public final boolean equals(@Nullable Object o) {
840     throw new UnsupportedOperationException(
841         "Correspondence.equals(object) is not supported. If you meant to compare objects, use"
842             + " .compare(actual, expected) instead.");
843   }
844 
845   /**
846    * @throws UnsupportedOperationException always
847    * @deprecated {@link Object#hashCode()} is not supported.
848    */
849   @Deprecated
850   @Override
hashCode()851   public final int hashCode() {
852     throw new UnsupportedOperationException("Correspondence.hashCode() is not supported.");
853   }
854 }
855