1 /* 2 * Copyright (c) 2011 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.CaseFormat.LOWER_CAMEL; 19 import static com.google.common.base.CaseFormat.UPPER_CAMEL; 20 import static com.google.common.base.CharMatcher.whitespace; 21 import static com.google.common.base.MoreObjects.firstNonNull; 22 import static com.google.common.base.Preconditions.checkArgument; 23 import static com.google.common.base.Preconditions.checkNotNull; 24 import static com.google.common.base.Strings.lenientFormat; 25 import static com.google.common.truth.Fact.fact; 26 import static com.google.common.truth.Fact.simpleFact; 27 import static com.google.common.truth.Platform.doubleToString; 28 import static com.google.common.truth.Platform.floatToString; 29 import static com.google.common.truth.Platform.isKotlinRange; 30 import static com.google.common.truth.Platform.kotlinRangeContains; 31 import static com.google.common.truth.Platform.stringValueOfNonFloatingPoint; 32 import static com.google.common.truth.Subject.EqualityCheck.SAME_INSTANCE; 33 import static com.google.common.truth.SubjectUtils.accumulate; 34 import static com.google.common.truth.SubjectUtils.append; 35 import static com.google.common.truth.SubjectUtils.concat; 36 import static com.google.common.truth.SubjectUtils.sandwich; 37 import static java.util.Arrays.asList; 38 39 import com.google.common.base.Objects; 40 import com.google.common.collect.ImmutableList; 41 import com.google.common.collect.Iterables; 42 import com.google.common.collect.Lists; 43 import com.google.common.primitives.Booleans; 44 import com.google.common.primitives.Bytes; 45 import com.google.common.primitives.Chars; 46 import com.google.common.primitives.Ints; 47 import com.google.common.primitives.Longs; 48 import com.google.common.primitives.Shorts; 49 import com.google.common.truth.FailureMetadata.OldAndNewValuesAreSimilar; 50 import com.google.errorprone.annotations.DoNotCall; 51 import com.google.errorprone.annotations.ForOverride; 52 import java.lang.reflect.Array; 53 import java.util.ArrayList; 54 import java.util.Arrays; 55 import java.util.List; 56 import org.jspecify.annotations.Nullable; 57 58 /** 59 * An object that lets you perform checks on the value under test. For example, {@code Subject} 60 * contains {@link #isEqualTo(Object)} and {@link #isInstanceOf(Class)}, and {@link StringSubject} 61 * contains {@link StringSubject#startsWith startsWith(String)}. 62 * 63 * <p>To create a {@code Subject} instance, most users will call an {@link Truth#assertThat 64 * assertThat} method. For information about other ways to create an instance, see <a 65 * href="https://truth.dev/faq#full-chain">this FAQ entry</a>. 66 * 67 * <h3>For people extending Truth</h3> 68 * 69 * <p>For information about writing a custom {@link Subject}, see <a 70 * href="https://truth.dev/extension">our doc on extensions</a>. 71 * 72 * @author David Saff 73 * @author Christian Gruber 74 */ 75 public class Subject { 76 /** 77 * In a fluent assertion chain, the argument to the common overload of {@link 78 * StandardSubjectBuilder#about(Subject.Factory) about}, the method that specifies what kind of 79 * {@link Subject} to create. 80 * 81 * <p>For more information about the fluent chain, see <a 82 * href="https://truth.dev/faq#full-chain">this FAQ entry</a>. 83 * 84 * <h3>For people extending Truth</h3> 85 * 86 * <p>When you write a custom subject, see <a href="https://truth.dev/extension">our doc on 87 * extensions</a>. It explains where {@code Subject.Factory} fits into the process. 88 */ 89 public interface Factory<SubjectT extends Subject, ActualT> { 90 /** Creates a new {@link Subject}. */ createSubject(FailureMetadata metadata, @Nullable ActualT actual)91 SubjectT createSubject(FailureMetadata metadata, @Nullable ActualT actual); 92 } 93 94 private final @Nullable FailureMetadata metadata; 95 private final @Nullable Object actual; 96 private final @Nullable String typeDescriptionOverride; 97 98 /** 99 * Constructor for use by subclasses. If you want to create an instance of this class itself, call 100 * {@link Subject#check(String, Object...) check(...)}{@code .that(actual)}. 101 */ Subject(FailureMetadata metadata, @Nullable Object actual)102 protected Subject(FailureMetadata metadata, @Nullable Object actual) { 103 this(metadata, actual, /* typeDescriptionOverride= */ null); 104 } 105 106 /** 107 * Special constructor that lets subclasses provide a description of the type they're testing. For 108 * example, {@link ThrowableSubject} passes the description "throwable." Normally, Truth is able 109 * to infer this name from the class name. However, if we lack runtime type information (notably, 110 * under j2cl with class metadata off), we might not have access to the original class name. 111 * 112 * <p>We don't expect to make this a public API: Class names are nearly always available. It's 113 * just that we want to be able to run Truth's own tests run with class metadata off, and it's 114 * easier to tweak the subjects to know their own names rather than generalize the tests to accept 115 * obfuscated names. 116 */ Subject( @ullable FailureMetadata metadata, @Nullable Object actual, @Nullable String typeDescriptionOverride)117 Subject( 118 @Nullable FailureMetadata metadata, 119 @Nullable Object actual, 120 @Nullable String typeDescriptionOverride) { 121 this.metadata = metadata == null ? null : metadata.updateForSubject(this); 122 this.actual = actual; 123 this.typeDescriptionOverride = typeDescriptionOverride; 124 } 125 126 /** Fails if the subject is not null. */ isNull()127 public void isNull() { 128 standardIsEqualTo(null); 129 } 130 131 /** Fails if the subject is null. */ isNotNull()132 public void isNotNull() { 133 standardIsNotEqualTo(null); 134 } 135 136 /** 137 * Fails if the subject is not equal to the given object. For the purposes of this comparison, two 138 * objects are equal if any of the following is true: 139 * 140 * <ul> 141 * <li>they are equal according to {@link Objects#equal} 142 * <li>they are arrays and are considered equal by the appropriate {@link Arrays#equals} 143 * overload 144 * <li>they are boxed integer types ({@code Byte}, {@code Short}, {@code Character}, {@code 145 * Integer}, or {@code Long}) and they are numerically equal when converted to {@code Long}. 146 * <li>the actual value is a boxed floating-point type ({@code Double} or {@code Float}), the 147 * expected value is an {@code Integer}, and the two are numerically equal when converted to 148 * {@code Double}. (This allows {@code assertThat(someDouble).isEqualTo(0)} to pass.) 149 * </ul> 150 * 151 * <p><b>Note:</b> This method does not test the {@link Object#equals} implementation itself; it 152 * <i>assumes</i> that method is functioning correctly according to its contract. Testing an 153 * {@code equals} implementation requires a utility such as <a 154 * href="https://mvnrepository.com/artifact/com.google.guava/guava-testlib">guava-testlib</a>'s <a 155 * href="https://static.javadoc.io/com.google.guava/guava-testlib/23.0/com/google/common/testing/EqualsTester.html">EqualsTester</a>. 156 * 157 * <p>In some cases, this method might not even call {@code equals}. It may instead perform other 158 * tests that will return the same result as long as {@code equals} is implemented according to 159 * the contract for its type. 160 */ 161 /* 162 * TODO(cpovirk): Possibly ban overriding isEqualTo+isNotEqualTo in favor of a 163 * compareForEquality(Object, Object) method. That way, people would need to override only one 164 * method, they would get a ComparisonFailure and other message niceties, and they'd have less to 165 * test. 166 */ isEqualTo(@ullable Object expected)167 public void isEqualTo(@Nullable Object expected) { 168 standardIsEqualTo(expected); 169 } 170 standardIsEqualTo(@ullable Object expected)171 private void standardIsEqualTo(@Nullable Object expected) { 172 ComparisonResult difference = compareForEquality(expected); 173 if (!difference.valuesAreEqual()) { 174 failEqualityCheck(EqualityCheck.EQUAL, expected, difference); 175 } 176 } 177 178 /** 179 * Fails if the subject is equal to the given object. The meaning of equality is the same as for 180 * the {@link #isEqualTo} method. 181 */ isNotEqualTo(@ullable Object unexpected)182 public void isNotEqualTo(@Nullable Object unexpected) { 183 standardIsNotEqualTo(unexpected); 184 } 185 standardIsNotEqualTo(@ullable Object unexpected)186 private void standardIsNotEqualTo(@Nullable Object unexpected) { 187 ComparisonResult difference = compareForEquality(unexpected); 188 if (difference.valuesAreEqual()) { 189 String unexpectedAsString = formatActualOrExpected(unexpected); 190 if (actualCustomStringRepresentation().equals(unexpectedAsString)) { 191 failWithoutActual(fact("expected not to be", unexpectedAsString)); 192 } else { 193 failWithoutActual( 194 fact("expected not to be", unexpectedAsString), 195 fact( 196 "but was; string representation of actual value", 197 actualCustomStringRepresentation())); 198 } 199 } 200 } 201 202 /** 203 * Returns whether {@code actual} equals {@code expected} differ and, in some cases, a description 204 * of how they differ. 205 * 206 * <p>The equality check follows the rules described on {@link #isEqualTo}. 207 */ compareForEquality(@ullable Object expected)208 private ComparisonResult compareForEquality(@Nullable Object expected) { 209 if (actual == null && expected == null) { 210 return ComparisonResult.equal(); 211 } else if (actual == null || expected == null) { 212 return ComparisonResult.differentNoDescription(); 213 } else if (actual instanceof byte[] && expected instanceof byte[]) { 214 /* 215 * For a special error message and to use faster Arrays.equals to avoid at least one timeout. 216 * 217 * TODO(cpovirk): For performance, use Arrays.equals for other array types (here and/or in 218 * checkArrayEqualsRecursive)? Exception: double[] and float[], whose GWT implementations I 219 * think may have both false positives and false negatives (so we can't even use Arrays.equals 220 * as a fast path for them, nor deepEquals for an Object[] that might contain them). We would 221 * still fall back to the slower checkArrayEqualsRecursive to produce a nicer failure message 222 * -- but naturally only for tests that are about to fail, when performance matters less. 223 */ 224 return checkByteArrayEquals((byte[]) expected, (byte[]) actual); 225 } else if (actual.getClass().isArray() && expected.getClass().isArray()) { 226 return checkArrayEqualsRecursive(expected, actual, ""); 227 } else if (isIntegralBoxedPrimitive(actual) && isIntegralBoxedPrimitive(expected)) { 228 return ComparisonResult.fromEqualsResult(integralValue(actual) == integralValue(expected)); 229 } else if (actual instanceof Double && expected instanceof Double) { 230 return ComparisonResult.fromEqualsResult( 231 Double.compare((Double) actual, (Double) expected) == 0); 232 } else if (actual instanceof Float && expected instanceof Float) { 233 return ComparisonResult.fromEqualsResult( 234 Float.compare((Float) actual, (Float) expected) == 0); 235 } else if (actual instanceof Double && expected instanceof Integer) { 236 return ComparisonResult.fromEqualsResult( 237 Double.compare((Double) actual, (Integer) expected) == 0); 238 } else if (actual instanceof Float && expected instanceof Integer) { 239 return ComparisonResult.fromEqualsResult( 240 Double.compare((Float) actual, (Integer) expected) == 0); 241 } else { 242 return ComparisonResult.fromEqualsResult(actual == expected || actual.equals(expected)); 243 } 244 } 245 isIntegralBoxedPrimitive(@ullable Object o)246 private static boolean isIntegralBoxedPrimitive(@Nullable Object o) { 247 return o instanceof Byte 248 || o instanceof Short 249 || o instanceof Character 250 || o instanceof Integer 251 || o instanceof Long; 252 } 253 integralValue(Object o)254 private static long integralValue(Object o) { 255 if (o instanceof Character) { 256 return (long) ((Character) o).charValue(); 257 } else if (o instanceof Number) { 258 return ((Number) o).longValue(); 259 } else { 260 throw new AssertionError(o + " must be either a Character or a Number."); 261 } 262 } 263 264 /** Fails if the subject is not the same instance as the given object. */ isSameInstanceAs(@ullable Object expected)265 public final void isSameInstanceAs(@Nullable Object expected) { 266 if (actual != expected) { 267 failEqualityCheck( 268 SAME_INSTANCE, 269 expected, 270 /* 271 * Pass through *whether* the values are equal so that failEqualityCheck() can print that 272 * information. But remove the description of the difference, which is always about 273 * content, since people calling isSameInstanceAs() are explicitly not interested in 274 * content, only object identity. 275 */ 276 compareForEquality(expected).withoutDescription()); 277 } 278 } 279 280 /** Fails if the subject is the same instance as the given object. */ isNotSameInstanceAs(@ullable Object unexpected)281 public final void isNotSameInstanceAs(@Nullable Object unexpected) { 282 if (actual == unexpected) { 283 /* 284 * We use actualCustomStringRepresentation() because it might be overridden to be better than 285 * actual.toString()/unexpected.toString(). 286 */ 287 failWithoutActual( 288 fact("expected not to be specific instance", actualCustomStringRepresentation())); 289 } 290 } 291 292 /** Fails if the subject is not an instance of the given class. */ isInstanceOf(Class<?> clazz)293 public void isInstanceOf(Class<?> clazz) { 294 if (clazz == null) { 295 throw new NullPointerException("clazz"); 296 } 297 if (actual == null) { 298 failWithActual("expected instance of", clazz.getName()); 299 return; 300 } 301 if (!isInstanceOfType(actual, clazz)) { 302 if (Platform.classMetadataUnsupported()) { 303 throw new UnsupportedOperationException( 304 actualCustomStringRepresentation() 305 + ", an instance of " 306 + actual.getClass().getName() 307 + ", may or may not be an instance of " 308 + clazz.getName() 309 + ". Under -XdisableClassMetadata, we do not have enough information to tell."); 310 } 311 failWithoutActual( 312 fact("expected instance of", clazz.getName()), 313 fact("but was instance of", actual.getClass().getName()), 314 fact("with value", actualCustomStringRepresentation())); 315 } 316 } 317 318 /** Fails if the subject is an instance of the given class. */ isNotInstanceOf(Class<?> clazz)319 public void isNotInstanceOf(Class<?> clazz) { 320 if (clazz == null) { 321 throw new NullPointerException("clazz"); 322 } 323 if (Platform.classMetadataUnsupported()) { 324 throw new UnsupportedOperationException( 325 "isNotInstanceOf is not supported under -XdisableClassMetadata"); 326 } 327 if (actual == null) { 328 return; // null is not an instance of clazz. 329 } 330 if (isInstanceOfType(actual, clazz)) { 331 failWithActual("expected not to be an instance of", clazz.getName()); 332 /* 333 * TODO(cpovirk): Consider including actual.getClass() if it's not clazz itself but only a 334 * subtype. 335 */ 336 } 337 } 338 isInstanceOfType(Object instance, Class<?> clazz)339 private static boolean isInstanceOfType(Object instance, Class<?> clazz) { 340 checkArgument( 341 !clazz.isPrimitive(), 342 "Cannot check instanceof for primitive type %s. Pass the wrapper class instead.", 343 clazz.getSimpleName()); 344 /* 345 * TODO(cpovirk): Make the message include `Primitives.wrap(clazz).getSimpleName()` once that 346 * method is available in a public guava-gwt release that we depend on. 347 */ 348 return Platform.isInstanceOfType(instance, clazz); 349 } 350 351 /** Fails unless the subject is equal to any element in the given iterable. */ isIn(@ullable Iterable<?> iterable)352 public void isIn(@Nullable Iterable<?> iterable) { 353 checkNotNull(iterable); 354 if (!contains(iterable, actual)) { 355 failWithActual("expected any of", iterable); 356 } 357 } 358 contains(Iterable<?> haystack, @Nullable Object needle)359 private static boolean contains(Iterable<?> haystack, @Nullable Object needle) { 360 if (isKotlinRange(haystack)) { 361 return kotlinRangeContains(haystack, needle); 362 } 363 return Iterables.contains(haystack, needle); 364 } 365 366 /** Fails unless the subject is equal to any of the given elements. */ isAnyOf( @ullable Object first, @Nullable Object second, @Nullable Object @Nullable ... rest)367 public void isAnyOf( 368 @Nullable Object first, @Nullable Object second, @Nullable Object @Nullable ... rest) { 369 isIn(accumulate(first, second, rest)); 370 } 371 372 /** Fails if the subject is equal to any element in the given iterable. */ isNotIn(@ullable Iterable<?> iterable)373 public void isNotIn(@Nullable Iterable<?> iterable) { 374 checkNotNull(iterable); 375 if (Iterables.contains(iterable, actual)) { 376 failWithActual("expected not to be any of", iterable); 377 } 378 } 379 380 /** Fails if the subject is equal to any of the given elements. */ isNoneOf( @ullable Object first, @Nullable Object second, @Nullable Object @Nullable ... rest)381 public void isNoneOf( 382 @Nullable Object first, @Nullable Object second, @Nullable Object @Nullable ... rest) { 383 isNotIn(accumulate(first, second, rest)); 384 } 385 386 /** Returns the actual value under test. */ actual()387 final @Nullable Object actual() { 388 return actual; 389 } 390 391 /** 392 * Supplies the direct string representation of the actual value to other methods which may prefix 393 * or otherwise position it in an error message. This should only be overridden to provide an 394 * improved string representation of the value under test, as it would appear in any given error 395 * message, and should not be used for additional prefixing. 396 * 397 * <p>Subjects should override this with care. 398 * 399 * <p>By default, this returns {@code String.ValueOf(getActualValue())}. 400 */ 401 /* 402 * TODO(cpovirk): Consider whether this API pulls its weight. If users want to format the actual 403 * value, maybe they should do so themselves? Of course, they won't have a chance to use a custom 404 * format for inherited implementations like isEqualTo(). But if they want to format the actual 405 * value specially, then it seems likely that they'll want to format the expected value specially, 406 * too. And that applies just as well to APIs like isIn(). Maybe we'll want an API that supports 407 * formatting those values, too (like formatActualOrExpected below)? See also the related 408 * b/70930431. But note that we are likely to use this from FailureMetadata, at least in the short 409 * term, for better or for worse. 410 */ 411 @ForOverride actualCustomStringRepresentation()412 protected String actualCustomStringRepresentation() { 413 return formatActualOrExpected(actual); 414 } 415 actualCustomStringRepresentationForPackageMembersToCall()416 final String actualCustomStringRepresentationForPackageMembersToCall() { 417 return actualCustomStringRepresentation(); 418 } 419 formatActualOrExpected(@ullable Object o)420 private String formatActualOrExpected(@Nullable Object o) { 421 if (o instanceof byte[]) { 422 return base16((byte[]) o); 423 } else if (o != null && o.getClass().isArray()) { 424 return String.valueOf(arrayAsListRecursively(o)); 425 } else if (o instanceof Double) { 426 return doubleToString((Double) o); 427 } else if (o instanceof Float) { 428 return floatToString((Float) o); 429 } else { 430 // TODO(cpovirk): Consider renaming the called method to mention "NonArray." 431 /* 432 * TODO(cpovirk): Should the called method and arrayAsListRecursively(...) both call back into 433 * formatActualOrExpected for its handling of byte[] and float/double? Or is there some other 434 * restructuring of this set of methods that we should undertake? 435 */ 436 return stringValueOfNonFloatingPoint(o); 437 } 438 } 439 440 // We could add a dep on com.google.common.io, but that seems overkill for base16 encoding base16(byte[] bytes)441 private static String base16(byte[] bytes) { 442 StringBuilder sb = new StringBuilder(2 * bytes.length); 443 for (byte b : bytes) { 444 sb.append(hexDigits[(b >> 4) & 0xf]).append(hexDigits[b & 0xf]); 445 } 446 return sb.toString(); 447 } 448 449 private static final char[] hexDigits = "0123456789ABCDEF".toCharArray(); 450 arrayAsListRecursively(@ullable Object input)451 private static @Nullable Object arrayAsListRecursively(@Nullable Object input) { 452 if (input instanceof Object[]) { 453 return Lists.<@Nullable Object, @Nullable Object>transform( 454 asList((@Nullable Object[]) input), Subject::arrayAsListRecursively); 455 } else if (input instanceof boolean[]) { 456 return Booleans.asList((boolean[]) input); 457 } else if (input instanceof int[]) { 458 return Ints.asList((int[]) input); 459 } else if (input instanceof long[]) { 460 return Longs.asList((long[]) input); 461 } else if (input instanceof short[]) { 462 return Shorts.asList((short[]) input); 463 } else if (input instanceof byte[]) { 464 return Bytes.asList((byte[]) input); 465 } else if (input instanceof double[]) { 466 return doubleArrayAsString((double[]) input); 467 } else if (input instanceof float[]) { 468 return floatArrayAsString((float[]) input); 469 } else if (input instanceof char[]) { 470 return Chars.asList((char[]) input); 471 } else { 472 return input; 473 } 474 } 475 476 /** 477 * The result of comparing two objects for equality. This includes both the "equal"/"not-equal" 478 * bit and, in the case of "not equal," optional facts describing the difference. 479 */ 480 private static final class ComparisonResult { 481 /** 482 * If {@code equal} is true, returns an equal result; if false, a non-equal result with no 483 * description. 484 */ fromEqualsResult(boolean equal)485 static ComparisonResult fromEqualsResult(boolean equal) { 486 return equal ? EQUAL : DIFFERENT_NO_DESCRIPTION; 487 } 488 489 /** Returns a non-equal result with the given description. */ differentWithDescription(Fact... facts)490 static ComparisonResult differentWithDescription(Fact... facts) { 491 return new ComparisonResult(ImmutableList.copyOf(facts)); 492 } 493 494 /** Returns an equal result. */ equal()495 static ComparisonResult equal() { 496 return EQUAL; 497 } 498 499 /** Returns a non-equal result with no description. */ differentNoDescription()500 static ComparisonResult differentNoDescription() { 501 return DIFFERENT_NO_DESCRIPTION; 502 } 503 504 private static final ComparisonResult EQUAL = new ComparisonResult(null); 505 private static final ComparisonResult DIFFERENT_NO_DESCRIPTION = 506 new ComparisonResult(ImmutableList.<Fact>of()); 507 508 private final @Nullable ImmutableList<Fact> facts; 509 ComparisonResult(@ullable ImmutableList<Fact> facts)510 private ComparisonResult(@Nullable ImmutableList<Fact> facts) { 511 this.facts = facts; 512 } 513 valuesAreEqual()514 boolean valuesAreEqual() { 515 return facts == null; 516 } 517 factsOrEmpty()518 ImmutableList<Fact> factsOrEmpty() { 519 return firstNonNull(facts, ImmutableList.<Fact>of()); 520 } 521 522 /** Returns an instance with the same "equal"/"not-equal" bit but with no description. */ withoutDescription()523 ComparisonResult withoutDescription() { 524 return fromEqualsResult(valuesAreEqual()); 525 } 526 } 527 528 /** 529 * Returns null if the arrays are equal. If not equal, returns a string comparing the two arrays, 530 * displaying them in the style "[1, 2, 3]" to supplement the main failure message, which uses the 531 * style "010203." 532 */ checkByteArrayEquals(byte[] expected, byte[] actual)533 private static ComparisonResult checkByteArrayEquals(byte[] expected, byte[] actual) { 534 if (Arrays.equals(expected, actual)) { 535 return ComparisonResult.equal(); 536 } 537 return ComparisonResult.differentWithDescription( 538 fact("expected", Arrays.toString(expected)), fact("but was", Arrays.toString(actual))); 539 } 540 541 /** 542 * Returns null if the arrays are equal, recursively. If not equal, returns the string of the 543 * index at which they're different. 544 */ 545 /* 546 * TODO(cpovirk): Decide whether it's worthwhile to go to this trouble to display the index at 547 * which the arrays differ. If we were to stop doing that, we could mostly delegate to 548 * Arrays.equals() and our float/double arrayEquals methods. (We'd use deepEquals, but it doesn't 549 * have our special double/float handling for GWT.) 550 */ checkArrayEqualsRecursive( Object expectedArray, Object actualArray, String lastIndex)551 private static ComparisonResult checkArrayEqualsRecursive( 552 Object expectedArray, Object actualArray, String lastIndex) { 553 if (expectedArray == actualArray) { 554 return ComparisonResult.equal(); 555 } 556 String expectedType = arrayType(expectedArray); 557 String actualType = arrayType(actualArray); 558 if (!expectedType.equals(actualType)) { 559 Fact indexFact = 560 lastIndex.isEmpty() ? simpleFact("wrong type") : fact("wrong type for index", lastIndex); 561 return ComparisonResult.differentWithDescription( 562 indexFact, fact("expected", expectedType), fact("but was", actualType)); 563 } 564 int actualLength = Array.getLength(actualArray); 565 int expectedLength = Array.getLength(expectedArray); 566 if (expectedLength != actualLength) { 567 Fact indexFact = 568 lastIndex.isEmpty() 569 ? simpleFact("wrong length") 570 : fact("wrong length for index", lastIndex); 571 return ComparisonResult.differentWithDescription( 572 indexFact, fact("expected", expectedLength), fact("but was", actualLength)); 573 } 574 for (int i = 0; i < actualLength; i++) { 575 String index = lastIndex + "[" + i + "]"; 576 Object expected = Array.get(expectedArray, i); 577 Object actual = Array.get(actualArray, i); 578 if (actual != null 579 && actual.getClass().isArray() 580 && expected != null 581 && expected.getClass().isArray()) { 582 ComparisonResult result = checkArrayEqualsRecursive(expected, actual, index); 583 if (!result.valuesAreEqual()) { 584 return result; 585 } 586 } else if (!gwtSafeObjectEquals(actual, expected)) { 587 return ComparisonResult.differentWithDescription(fact("differs at index", index)); 588 } 589 } 590 return ComparisonResult.equal(); 591 } 592 arrayType(Object array)593 private static String arrayType(Object array) { 594 if (array.getClass() == boolean[].class) { 595 return "boolean[]"; 596 } else if (array.getClass() == int[].class) { 597 return "int[]"; 598 } else if (array.getClass() == long[].class) { 599 return "long[]"; 600 } else if (array.getClass() == short[].class) { 601 return "short[]"; 602 } else if (array.getClass() == byte[].class) { 603 return "byte[]"; 604 } else if (array.getClass() == double[].class) { 605 return "double[]"; 606 } else if (array.getClass() == float[].class) { 607 return "float[]"; 608 } else if (array.getClass() == char[].class) { 609 return "char[]"; 610 } else { 611 return "Object[]"; 612 } 613 } 614 gwtSafeObjectEquals(@ullable Object actual, @Nullable Object expected)615 private static boolean gwtSafeObjectEquals(@Nullable Object actual, @Nullable Object expected) { 616 if (actual instanceof Double && expected instanceof Double) { 617 return Double.doubleToLongBits((Double) actual) == Double.doubleToLongBits((Double) expected); 618 } else if (actual instanceof Float && expected instanceof Float) { 619 return Float.floatToIntBits((Float) actual) == Float.floatToIntBits((Float) expected); 620 } else { 621 return Objects.equal(actual, expected); 622 } 623 } 624 doubleArrayAsString(double[] items)625 private static List<String> doubleArrayAsString(double[] items) { 626 List<String> itemAsStrings = new ArrayList<>(items.length); 627 for (double item : items) { 628 itemAsStrings.add(doubleToString(item)); 629 } 630 return itemAsStrings; 631 } 632 floatArrayAsString(float[] items)633 private static List<String> floatArrayAsString(float[] items) { 634 List<String> itemAsStrings = new ArrayList<>(items.length); 635 for (float item : items) { 636 itemAsStrings.add(floatToString(item)); 637 } 638 return itemAsStrings; 639 } 640 641 /** 642 * Returns a builder for creating a derived subject but without providing information about how 643 * the derived subject will relate to the current subject. In most cases, you should provide such 644 * information by using {@linkplain #check(String, Object...) the other overload}. 645 * 646 * @deprecated Use {@linkplain #check(String, Object...) the other overload}, which requires you 647 * to supply more information to include in any failure messages. 648 */ 649 @Deprecated check()650 final StandardSubjectBuilder check() { 651 return new StandardSubjectBuilder(checkNotNull(metadata).updateForCheckCall()); 652 } 653 654 /** 655 * Returns a builder for creating a derived subject. 656 * 657 * <p>Derived subjects retain the {@link FailureStrategy} and {@linkplain 658 * StandardSubjectBuilder#withMessage messages} of the current subject, and in some cases, they 659 * automatically supplement their failure message with information about the original subject. 660 * 661 * <p>For example, {@link ThrowableSubject#hasMessageThat}, which returns a {@link StringSubject}, 662 * is implemented with {@code check("getMessage()").that(actual.getMessage())}. 663 * 664 * <p>The arguments to {@code check} describe how the new subject was derived from the old, 665 * formatted like a chained method call. This allows Truth to include that information in its 666 * failure messages. For example, {@code assertThat(caught).hasCauseThat().hasMessageThat()} will 667 * produce a failure message that includes the string "throwable.getCause().getMessage()," thanks 668 * to internal {@code check} calls that supplied "getCause()" and "getMessage()" as arguments. 669 * 670 * <p>If the method you're delegating to accepts parameters, you can pass {@code check} a format 671 * string. For example, {@link MultimapSubject#valuesForKey} calls {@code 672 * check("valuesForKey(%s)", key)}. 673 * 674 * <p>If you aren't really delegating to an instance method on the actual value -- maybe you're 675 * calling a static method, or you're calling a chain of several methods -- you can supply 676 * whatever string will be most useful to users. For example, if you're delegating to {@code 677 * getOnlyElement(actual.colors())}, you might call {@code check("onlyColor()")}. 678 * 679 * @param format a template with {@code %s} placeholders 680 * @param args the arguments to be inserted into those placeholders 681 */ check(String format, @Nullable Object... args)682 protected final StandardSubjectBuilder check(String format, @Nullable Object... args) { 683 return doCheck(OldAndNewValuesAreSimilar.DIFFERENT, format, args); 684 } 685 686 // TODO(b/134064106): Figure out a public API for this. 687 checkNoNeedToDisplayBothValues( String format, @Nullable Object... args)688 final StandardSubjectBuilder checkNoNeedToDisplayBothValues( 689 String format, @Nullable Object... args) { 690 return doCheck(OldAndNewValuesAreSimilar.SIMILAR, format, args); 691 } 692 doCheck( OldAndNewValuesAreSimilar valuesAreSimilar, String format, @Nullable Object[] args)693 private StandardSubjectBuilder doCheck( 694 OldAndNewValuesAreSimilar valuesAreSimilar, String format, @Nullable Object[] args) { 695 LazyMessage message = new LazyMessage(format, args); 696 return new StandardSubjectBuilder( 697 checkNotNull(metadata) 698 .updateForCheckCall( 699 valuesAreSimilar, /* descriptionUpdate= */ input -> input + "." + message)); 700 } 701 702 /** 703 * Begins a new call chain that ignores any failures. This is useful for subjects that normally 704 * delegate with to other subjects by using {@link #check} but have already reported a failure. In 705 * such cases it may still be necessary to return a {@code Subject} instance even though any 706 * subsequent assertions are meaningless. For example, if a user chains together more {@link 707 * ThrowableSubject#hasCauseThat} calls than the actual exception has causes, {@code hasCauseThat} 708 * returns {@code ignoreCheck().that(... a dummy exception ...)}. 709 */ ignoreCheck()710 protected final StandardSubjectBuilder ignoreCheck() { 711 return StandardSubjectBuilder.forCustomFailureStrategy(failure -> {}); 712 } 713 714 /** 715 * Fails, reporting a message with two "{@linkplain Fact facts}": 716 * 717 * <ul> 718 * <li><i>key</i>: <i>value</i> 719 * <li>but was: <i>actual value</i>. 720 * </ul> 721 * 722 * <p>This is the simplest failure API. For more advanced needs, see {@linkplain 723 * #failWithActual(Fact, Fact...) the other overload} and {@link #failWithoutActual(Fact, Fact...) 724 * failWithoutActual}. 725 * 726 * <p>Example usage: The check {@code contains(String)} calls {@code failWithActual("expected to 727 * contain", string)}. 728 */ failWithActual(String key, @Nullable Object value)729 protected final void failWithActual(String key, @Nullable Object value) { 730 failWithActual(fact(key, value)); 731 } 732 733 /** 734 * Fails, reporting a message with the given facts, followed by an automatically added fact of the 735 * form: 736 * 737 * <ul> 738 * <li>but was: <i>actual value</i>. 739 * </ul> 740 * 741 * <p>If you have only one fact to report (and it's a {@linkplain Fact#fact key-value fact}), 742 * prefer {@linkplain #failWithActual(String, Object) the simpler overload}. 743 * 744 * <p>Example usage: The check {@code isEmpty()} calls {@code failWithActual(simpleFact("expected 745 * to be empty"))}. 746 */ failWithActual(Fact first, Fact... rest)747 protected final void failWithActual(Fact first, Fact... rest) { 748 doFail(sandwich(first, rest, butWas())); 749 } 750 751 // TODO(cpovirk): Consider making this protected if there's a need for it. failWithActual(Iterable<Fact> facts)752 final void failWithActual(Iterable<Fact> facts) { 753 doFail(append(ImmutableList.copyOf(facts), butWas())); 754 } 755 756 /** 757 * Reports a failure constructing a message from a simple verb. 758 * 759 * @param check the check being asserted 760 * @deprecated Prefer to construct {@link Fact}-style methods, typically by using {@link 761 * #failWithActual(Fact, Fact...) failWithActual}{@code (}{@link Fact#simpleFact 762 * simpleFact(...)}{@code )}. However, if you want to preserve your exact failure message as a 763 * migration aid, you can inline this method (and then inline the resulting method call, as 764 * well). 765 */ 766 @Deprecated fail(String check)767 final void fail(String check) { 768 fail(check, new Object[0]); 769 } 770 771 /** 772 * Assembles a failure message and passes such to the FailureStrategy 773 * 774 * @param verb the check being asserted 775 * @param other the value against which the subject is compared 776 * @deprecated Prefer to construct {@link Fact}-style methods, typically by using {@link 777 * #failWithActual(String, Object)}. However, if you want to preserve your exact failure 778 * message as a migration aid, you can inline this method (and then inline the resulting 779 * method call, as well). 780 */ 781 @Deprecated fail(String verb, Object other)782 final void fail(String verb, Object other) { 783 fail(verb, new Object[] {other}); 784 } 785 786 /** 787 * Assembles a failure message and passes such to the FailureStrategy 788 * 789 * @param verb the check being asserted 790 * @param messageParts the expectations against which the subject is compared 791 * @deprecated Prefer to construct {@link Fact}-style methods, typically by using {@link 792 * #failWithActual(Fact, Fact...)}. However, if you want to preserve your exact failure 793 * message as a migration aid, you can inline this method. 794 */ 795 @Deprecated fail(String verb, @Nullable Object... messageParts)796 final void fail(String verb, @Nullable Object... messageParts) { 797 StringBuilder message = new StringBuilder("Not true that <"); 798 message.append(actualCustomStringRepresentation()).append("> ").append(verb); 799 for (Object part : messageParts) { 800 message.append(" <").append(part).append(">"); 801 } 802 failWithoutActual(simpleFact(message.toString())); 803 } 804 805 enum EqualityCheck { 806 EQUAL("expected"), 807 SAME_INSTANCE("expected specific instance"); 808 809 final String keyForExpected; 810 EqualityCheck(String keyForExpected)811 EqualityCheck(String keyForExpected) { 812 this.keyForExpected = keyForExpected; 813 } 814 } 815 816 /** 817 * Special version of {@link #failEqualityCheck} for use from {@link IterableSubject}, documented 818 * further there. 819 */ failEqualityCheckForEqualsWithoutDescription(@ullable Object expected)820 final void failEqualityCheckForEqualsWithoutDescription(@Nullable Object expected) { 821 failEqualityCheck(EqualityCheck.EQUAL, expected, ComparisonResult.differentNoDescription()); 822 } 823 failEqualityCheck( EqualityCheck equalityCheck, @Nullable Object expected, ComparisonResult difference)824 private void failEqualityCheck( 825 EqualityCheck equalityCheck, @Nullable Object expected, ComparisonResult difference) { 826 String actualString = actualCustomStringRepresentation(); 827 String expectedString = formatActualOrExpected(expected); 828 String actualClass = actual == null ? "(null reference)" : actual.getClass().getName(); 829 String expectedClass = expected == null ? "(null reference)" : expected.getClass().getName(); 830 831 /* 832 * It's a little odd for expectedString to be formatActualOrExpected(expected) but actualString 833 * *not* to be formatActualOrExpected(actual), since we're going to compare the two. Instead, 834 * actualString is actualCustomStringRepresentation() -- as it is for other assertions, since 835 * users may have overridden that method. While actualCustomStringRepresentation() defaults to 836 * formatActualOrExpected(actual), it's only a default. 837 * 838 * What we really want here is probably to delete actualCustomStringRepresentation() and migrate 839 * users to formatActualOrExpected(actual). 840 */ 841 boolean sameToStrings = actualString.equals(expectedString); 842 boolean sameClassNames = actualClass.equals(expectedClass); 843 // TODO(cpovirk): Handle "same class name, different class loader." 844 // `equal` is always false for isEqualTo, but it varies for isSameInstanceAs: 845 boolean equal = difference.valuesAreEqual(); 846 847 if (equalityCheck == EqualityCheck.EQUAL 848 && (tryFailForTrailingWhitespaceOnly(expected) || tryFailForEmptyString(expected))) { 849 // tryFailForTrailingWhitespaceOnly or tryFailForEmptyString reported a failure, so we're done 850 return; 851 } 852 853 if (sameToStrings) { 854 if (sameClassNames) { 855 String doppelgangerDescription = 856 equal 857 ? "(different but equal instance of same class with same string representation)" 858 : "(non-equal instance of same class with same string representation)"; 859 failEqualityCheckNoComparisonFailure( 860 difference, 861 fact(equalityCheck.keyForExpected, expectedString), 862 fact("but was", doppelgangerDescription)); 863 } else { 864 failEqualityCheckNoComparisonFailure( 865 difference, 866 fact(equalityCheck.keyForExpected, expectedString), 867 fact("an instance of", expectedClass), 868 fact("but was", "(non-equal value with same string representation)"), 869 fact("an instance of", actualClass)); 870 } 871 } else { 872 if (equalityCheck == EqualityCheck.EQUAL && actual != null && expected != null) { 873 checkNotNull(metadata) 874 .failEqualityCheck(difference.factsOrEmpty(), expectedString, actualString); 875 } else { 876 failEqualityCheckNoComparisonFailure( 877 difference, 878 fact(equalityCheck.keyForExpected, expectedString), 879 fact("but was", actualString)); 880 } 881 } 882 } 883 884 /** 885 * Checks whether the actual and expected values are strings that match except for trailing 886 * whitespace. If so, reports a failure and returns true. 887 */ tryFailForTrailingWhitespaceOnly(@ullable Object expected)888 private boolean tryFailForTrailingWhitespaceOnly(@Nullable Object expected) { 889 if (!(actual instanceof String) || !(expected instanceof String)) { 890 return false; 891 } 892 893 /* 894 * TODO(cpovirk): Consider applying this for non-String types. The danger there is that we don't 895 * know whether toString() (or actualCustomStringRepresentation/formatActualOrExpected) and 896 * equals() are consistent for those types. 897 */ 898 String actualString = (String) actual; 899 String expectedString = (String) expected; 900 String actualNoTrailing = whitespace().trimTrailingFrom(actualString); 901 String expectedNoTrailing = whitespace().trimTrailingFrom(expectedString); 902 String expectedTrailing = 903 escapeWhitespace(expectedString.substring(expectedNoTrailing.length())); 904 String actualTrailing = escapeWhitespace(actualString.substring(actualNoTrailing.length())); 905 906 if (!actualNoTrailing.equals(expectedNoTrailing)) { 907 return false; 908 } 909 910 if (actualString.startsWith(expectedString)) { 911 failWithoutActual( 912 fact("expected", expectedString), 913 fact("but contained extra trailing whitespace", actualTrailing)); 914 } else if (expectedString.startsWith(actualString)) { 915 failWithoutActual( 916 fact("expected", expectedString), 917 fact("but was missing trailing whitespace", expectedTrailing)); 918 } else { 919 failWithoutActual( 920 fact("expected", expectedString), 921 fact("with trailing whitespace", expectedTrailing), 922 fact("but trailing whitespace was", actualTrailing)); 923 } 924 925 return true; 926 } 927 escapeWhitespace(String in)928 private static String escapeWhitespace(String in) { 929 StringBuilder out = new StringBuilder(); 930 for (char c : in.toCharArray()) { 931 out.append(escapeWhitespace(c)); 932 } 933 return out.toString(); 934 } 935 escapeWhitespace(char c)936 private static String escapeWhitespace(char c) { 937 switch (c) { 938 case '\t': 939 return "\\t"; 940 case '\n': 941 return "\\n"; 942 case '\f': 943 return "\\f"; 944 case '\r': 945 return "\\r"; 946 case ' ': 947 return "␣"; 948 default: 949 return new String(asUnicodeHexEscape(c)); 950 } 951 } 952 953 /** 954 * Checks whether the actual and expected values are empty strings. If so, reports a failure and 955 * returns true. 956 */ tryFailForEmptyString(@ullable Object expected)957 private boolean tryFailForEmptyString(@Nullable Object expected) { 958 if (!(actual instanceof String) || !(expected instanceof String)) { 959 return false; 960 } 961 962 String actualString = (String) actual; 963 String expectedString = (String) expected; 964 if (actualString.isEmpty()) { 965 failWithoutActual(fact("expected", expectedString), simpleFact("but was an empty string")); 966 return true; 967 } else if (expectedString.isEmpty()) { 968 failWithoutActual(simpleFact("expected an empty string"), fact("but was", actualString)); 969 return true; 970 } 971 972 // Neither string was empty 973 return false; 974 } 975 976 // From SourceCodeEscapers: 977 978 private static final char[] HEX_DIGITS = "0123456789abcdef".toCharArray(); 979 asUnicodeHexEscape(char c)980 private static char[] asUnicodeHexEscape(char c) { 981 // Equivalent to String.format("\\u%04x", (int) c); 982 char[] r = new char[6]; 983 r[0] = '\\'; 984 r[1] = 'u'; 985 r[5] = HEX_DIGITS[c & 0xF]; 986 c = (char) (c >>> 4); 987 r[4] = HEX_DIGITS[c & 0xF]; 988 c = (char) (c >>> 4); 989 r[3] = HEX_DIGITS[c & 0xF]; 990 c = (char) (c >>> 4); 991 r[2] = HEX_DIGITS[c & 0xF]; 992 return r; 993 } 994 failEqualityCheckNoComparisonFailure(ComparisonResult difference, Fact... facts)995 private void failEqualityCheckNoComparisonFailure(ComparisonResult difference, Fact... facts) { 996 // TODO(cpovirk): Is it possible for difference.factsOrEmpty() to be nonempty? If not, remove. 997 doFail(concat(asList(facts), difference.factsOrEmpty())); 998 } 999 1000 /** 1001 * Assembles a failure message and passes it to the FailureStrategy 1002 * 1003 * @param verb the check being asserted 1004 * @param expected the expectations against which the subject is compared 1005 * @param failVerb the failure of the check being asserted 1006 * @param actual the actual value the subject was compared against 1007 * @deprecated Prefer to construct {@link Fact}-style methods, typically by using {@link 1008 * #failWithActual(Fact, Fact...)}. However, if you want to preserve your exact failure 1009 * message as a migration aid, you can inline this method. 1010 */ 1011 @Deprecated failWithBadResults(String verb, Object expected, String failVerb, Object actual)1012 final void failWithBadResults(String verb, Object expected, String failVerb, Object actual) { 1013 String message = 1014 lenientFormat( 1015 "Not true that <%s> %s <%s>. It %s <%s>", 1016 actualCustomStringRepresentation(), 1017 verb, 1018 expected, 1019 failVerb, 1020 (actual == null) ? "null reference" : actual); 1021 failWithoutActual(simpleFact(message)); 1022 } 1023 1024 /** 1025 * Assembles a failure message with an alternative representation of the wrapped subject and 1026 * passes it to the FailureStrategy 1027 * 1028 * @param verb the check being asserted 1029 * @param expected the expected value of the check 1030 * @param actual the custom representation of the subject to be reported in the failure. 1031 * @deprecated Prefer to construct {@link Fact}-style methods, typically by using {@link 1032 * #failWithoutActual(Fact, Fact...)}. However, if you want to preserve your exact failure 1033 * message as a migration aid, you can inline this method. 1034 */ 1035 @Deprecated failWithCustomSubject(String verb, Object expected, Object actual)1036 final void failWithCustomSubject(String verb, Object expected, Object actual) { 1037 String message = 1038 lenientFormat( 1039 "Not true that <%s> %s <%s>", 1040 (actual == null) ? "null reference" : actual, verb, expected); 1041 failWithoutActual(simpleFact(message)); 1042 } 1043 1044 /** 1045 * @deprecated Prefer to construct {@link Fact}-style methods, typically by using {@link 1046 * #failWithoutActual(Fact, Fact...) failWithoutActual}{@code (}{@link Fact#simpleFact 1047 * simpleFact(...)}{@code )}. However, if you want to preserve your exact failure message as a 1048 * migration aid, you can inline this method. 1049 */ 1050 @Deprecated failWithoutSubject(String check)1051 final void failWithoutSubject(String check) { 1052 failWithoutActual(simpleFact(lenientFormat("Not true that the subject %s", check))); 1053 } 1054 1055 /** 1056 * Fails, reporting a message with the given facts, <i>without automatically adding the actual 1057 * value.</i> 1058 * 1059 * <p>Most failure messages should report the actual value, so most checks should call {@link 1060 * #failWithActual(Fact, Fact...) failWithActual} instead. However, {@code failWithoutActual} is 1061 * useful in some cases: 1062 * 1063 * <ul> 1064 * <li>when the actual value is obvious from the rest of the message. For example, {@code 1065 * isNotEmpty()} calls {@code failWithoutActual(simpleFact("expected not to be empty")}. 1066 * <li>when the actual value shouldn't come last or should have a different key than the default 1067 * of "but was." For example, {@code isNotWithin(...).of(...)} calls {@code 1068 * failWithoutActual} so that it can put the expected and actual values together, followed 1069 * by the tolerance. 1070 * </ul> 1071 * 1072 * <p>Example usage: The check {@code isEmpty()} calls {@code failWithActual(simpleFact("expected 1073 * to be empty"))}. 1074 */ failWithoutActual(Fact first, Fact... rest)1075 protected final void failWithoutActual(Fact first, Fact... rest) { 1076 doFail(ImmutableList.copyOf(Lists.asList(first, rest))); 1077 } 1078 1079 // TODO(cpovirk): Consider making this protected if there's a need for it. failWithoutActual(Iterable<Fact> facts)1080 final void failWithoutActual(Iterable<Fact> facts) { 1081 doFail(ImmutableList.copyOf(facts)); 1082 } 1083 1084 /** 1085 * Assembles a failure message without a given subject and passes it to the FailureStrategy 1086 * 1087 * @param check the check being asserted 1088 * @deprecated Prefer to construct {@link Fact}-style methods, typically by using {@link 1089 * #failWithoutActual(Fact, Fact...) failWithoutActual}{@code (}{@link Fact#simpleFact 1090 * simpleFact(...)}{@code )}. However, if you want to preserve your exact failure message as a 1091 * migration aid, you can inline this method (and then inline the resulting method call, as 1092 * well). 1093 */ 1094 @Deprecated failWithoutActual(String check)1095 final void failWithoutActual(String check) { 1096 failWithoutSubject(check); 1097 } 1098 1099 /** 1100 * @throws UnsupportedOperationException always 1101 * @deprecated {@link Object#equals(Object)} is not supported on Truth subjects. If you are 1102 * writing a test assertion (actual vs. expected), use {@link #isEqualTo(Object)} instead. 1103 */ 1104 @DoNotCall( 1105 "Subject.equals() is not supported. Did you mean to call" 1106 + " assertThat(actual).isEqualTo(expected) instead of" 1107 + " assertThat(actual).equals(expected)?") 1108 @Deprecated 1109 @Override equals(@ullable Object o)1110 public final boolean equals(@Nullable Object o) { 1111 throw new UnsupportedOperationException( 1112 "Subject.equals() is not supported. Did you mean to call" 1113 + " assertThat(actual).isEqualTo(expected) instead of" 1114 + " assertThat(actual).equals(expected)?"); 1115 } 1116 1117 /** 1118 * @throws UnsupportedOperationException always 1119 * @deprecated {@link Object#hashCode()} is not supported on Truth subjects. 1120 */ 1121 @DoNotCall("Subject.hashCode() is not supported.") 1122 @Deprecated 1123 @Override hashCode()1124 public final int hashCode() { 1125 throw new UnsupportedOperationException("Subject.hashCode() is not supported."); 1126 } 1127 1128 /** 1129 * @throws UnsupportedOperationException always 1130 * @deprecated {@link Object#toString()} is not supported on Truth subjects. 1131 */ 1132 @Deprecated 1133 @Override 1134 public toString()1135 String toString() { 1136 throw new UnsupportedOperationException( 1137 "Subject.toString() is not supported. Did you mean to call assertThat(foo.toString())" 1138 + " instead of assertThat(foo).toString()?"); 1139 } 1140 1141 /** 1142 * Returns a "but was: <actual value>" string. This method should be rarely needed, since Truth 1143 * inserts a "but was" fact by default for assertions. However, it's occasionally useful for calls 1144 * to {@code failWithoutActual} that want a "but was" fact but don't want it to come last, where 1145 * Truth inserts it by default. 1146 */ 1147 /* 1148 * TODO(cpovirk): Consider giving this protected access. 1149 * 1150 * It is likely better than what users would otherwise do -- `fact("but was", actual)`, which 1151 * ignores actualCustomStringRepresentation() (which is inaccessible outside the package). 1152 * 1153 * But I want to think more about this. In particular, if people use this to reimplement 1154 * isEqualTo(), I would be sad that they're missing out on its normal special handling. That's 1155 * probably not enough reason to avoid adding this, but we can hold it back for now. 1156 */ butWas()1157 final Fact butWas() { 1158 return fact("but was", actualCustomStringRepresentation()); 1159 } 1160 1161 /* 1162 * Computed lazily so that we're not doing expensive string operations during every assertion, 1163 * only during every failure. 1164 */ typeDescription()1165 final String typeDescription() { 1166 return typeDescriptionOrGuess(getClass(), typeDescriptionOverride); 1167 } 1168 typeDescriptionOrGuess( Class<? extends Subject> clazz, @Nullable String typeDescriptionOverride)1169 private static String typeDescriptionOrGuess( 1170 Class<? extends Subject> clazz, @Nullable String typeDescriptionOverride) { 1171 if (typeDescriptionOverride != null) { 1172 return typeDescriptionOverride; 1173 } 1174 /* 1175 * j2cl doesn't store enough metadata to know whether "Foo$BarSubject" is a nested class, so it 1176 * can't tell whether the simple name is "Foo$BarSubject" or just "BarSubject": b/71808768. It 1177 * returns "Foo$BarSubject" to err on the side of preserving information. We want just 1178 * "BarSubject," so we strip any likely enclosing type ourselves. 1179 */ 1180 String subjectClass = clazz.getSimpleName().replaceFirst(".*[$]", ""); 1181 String actualClass = 1182 (subjectClass.endsWith("Subject") && !subjectClass.equals("Subject")) 1183 ? subjectClass.substring(0, subjectClass.length() - "Subject".length()) 1184 : "Object"; 1185 return UPPER_CAMEL.to(LOWER_CAMEL, actualClass); 1186 } 1187 doFail(ImmutableList<Fact> facts)1188 private void doFail(ImmutableList<Fact> facts) { 1189 checkNotNull(metadata).fail(facts); 1190 } 1191 } 1192