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