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.Preconditions.checkNotNull; 19 import static com.google.common.base.Preconditions.checkState; 20 import static com.google.common.base.Verify.verifyNotNull; 21 import static com.google.common.truth.ComparisonFailures.makeComparisonFailureFacts; 22 import static com.google.common.truth.Fact.fact; 23 import static com.google.common.truth.LazyMessage.evaluateAll; 24 import static com.google.common.truth.Platform.cleanStackTrace; 25 import static com.google.common.truth.Platform.inferDescription; 26 import static com.google.common.truth.Platform.makeComparisonFailure; 27 import static com.google.common.truth.SubjectUtils.append; 28 import static com.google.common.truth.SubjectUtils.concat; 29 30 import com.google.common.base.Function; 31 import com.google.common.collect.ImmutableList; 32 import org.checkerframework.checker.nullness.qual.Nullable; 33 34 /** 35 * An opaque, immutable object containing state from the previous calls in the fluent assertion 36 * chain. It appears primarily as a parameter to {@link Subject} constructors (and {@link 37 * Subject.Factory} methods), which should pass it to the superclass constructor and not otherwise 38 * use or store it. In particular, users should not attempt to call {@code Subject} constructors or 39 * {@code Subject.Factory} methods directly. Instead, they should use the appropriate factory 40 * method: 41 * 42 * <ul> 43 * <li>If you're writing a test: {@link Truth#assertAbout(Subject.Factory)}{@code .that(...)} 44 * <li>If you're creating a derived subject from within another subject: {@code 45 * check(...).about(...).that(...)} 46 * <li>If you're testing your subject to verify that assertions fail when they should: {@link 47 * ExpectFailure} 48 * </ul> 49 * 50 * <p>(One exception: Implementations of {@link CustomSubjectBuilder} do directly call constructors, 51 * using their {@link CustomSubjectBuilder#metadata()} method to get an instance to pass to the 52 * constructor.) 53 */ 54 public final class FailureMetadata { forFailureStrategy(FailureStrategy failureStrategy)55 static FailureMetadata forFailureStrategy(FailureStrategy failureStrategy) { 56 return new FailureMetadata( 57 failureStrategy, ImmutableList.<LazyMessage>of(), ImmutableList.<Step>of()); 58 } 59 60 private final FailureStrategy strategy; 61 62 /** 63 * The data from a call to either (a) a {@link Subject} constructor or (b) {@link Subject#check}. 64 */ 65 private static final class Step { subjectCreation(Subject subject)66 static Step subjectCreation(Subject subject) { 67 return new Step(checkNotNull(subject), null, null); 68 } 69 checkCall( OldAndNewValuesAreSimilar valuesAreSimilar, @Nullable Function<String, String> descriptionUpdate)70 static Step checkCall( 71 OldAndNewValuesAreSimilar valuesAreSimilar, 72 @Nullable Function<String, String> descriptionUpdate) { 73 return new Step(null, descriptionUpdate, valuesAreSimilar); 74 } 75 76 /* 77 * We store Subject, rather than the actual value itself, so that we can call 78 * actualCustomStringRepresentation(). Why not call actualCustomStringRepresentation() 79 * immediately? First, it might be expensive, and second, the Subject isn't initialized at the 80 * time we receive it. We *might* be able to make it safe to call if it looks only at actual(), 81 * but it might try to look at facts initialized by a subclass, which aren't ready yet. 82 */ 83 final @Nullable Subject subject; 84 85 final @Nullable Function<String, String> descriptionUpdate; 86 87 // Present only when descriptionUpdate is. 88 final @Nullable OldAndNewValuesAreSimilar valuesAreSimilar; 89 Step( @ullable Subject subject, @Nullable Function<String, String> descriptionUpdate, @Nullable OldAndNewValuesAreSimilar valuesAreSimilar)90 private Step( 91 @Nullable Subject subject, 92 @Nullable Function<String, String> descriptionUpdate, 93 @Nullable OldAndNewValuesAreSimilar valuesAreSimilar) { 94 this.subject = subject; 95 this.descriptionUpdate = descriptionUpdate; 96 this.valuesAreSimilar = valuesAreSimilar; 97 } 98 isCheckCall()99 boolean isCheckCall() { 100 return subject == null; 101 } 102 } 103 104 /* 105 * TODO(cpovirk): This implementation is wasteful, especially because `steps` is used even by 106 * non-chaining assertions. If it ever does matter, we could use an immutable cactus stack -- or 107 * probably even avoid storing most of the chain entirely (unless we end up wanting more of the 108 * chain to show "telescoping context," as in "the int value of this optional in this list in this 109 * multimap"). 110 */ 111 112 private final ImmutableList<LazyMessage> messages; 113 114 private final ImmutableList<Step> steps; 115 FailureMetadata( FailureStrategy strategy, ImmutableList<LazyMessage> messages, ImmutableList<Step> steps)116 FailureMetadata( 117 FailureStrategy strategy, ImmutableList<LazyMessage> messages, ImmutableList<Step> steps) { 118 this.strategy = checkNotNull(strategy); 119 this.messages = checkNotNull(messages); 120 this.steps = checkNotNull(steps); 121 } 122 123 /** 124 * Returns a new instance that includes the given subject in its chain of values. Truth users do 125 * not need to call this method directly; Truth automatically accumulates context, starting from 126 * the initial that(...) call and continuing into any chained calls, like {@link 127 * ThrowableSubject#hasMessageThat}. 128 */ updateForSubject(Subject subject)129 FailureMetadata updateForSubject(Subject subject) { 130 ImmutableList<Step> steps = append(this.steps, Step.subjectCreation(subject)); 131 return derive(messages, steps); 132 } 133 updateForCheckCall()134 FailureMetadata updateForCheckCall() { 135 ImmutableList<Step> steps = append(this.steps, Step.checkCall(null, null)); 136 return derive(messages, steps); 137 } 138 updateForCheckCall( OldAndNewValuesAreSimilar valuesAreSimilar, Function<String, String> descriptionUpdate)139 FailureMetadata updateForCheckCall( 140 OldAndNewValuesAreSimilar valuesAreSimilar, Function<String, String> descriptionUpdate) { 141 checkNotNull(descriptionUpdate); 142 ImmutableList<Step> steps = 143 append(this.steps, Step.checkCall(valuesAreSimilar, descriptionUpdate)); 144 return derive(messages, steps); 145 } 146 147 /** 148 * Whether the value of the original subject and the value of the derived subject are "similar 149 * enough" that we don't need to display both. For example, if we're printing a message about the 150 * value of optional.get(), there's no need to print the optional itself because it adds no 151 * information. Similarly, if we're printing a message about the asList() view of an array, 152 * there's no need to also print the array. 153 */ 154 enum OldAndNewValuesAreSimilar { 155 SIMILAR, 156 DIFFERENT; 157 } 158 159 /** 160 * Returns a new instance whose failures will contain the given message. The way for Truth users 161 * to set a message is {@code check(...).withMessage(...).that(...)} (for calls from within a 162 * {@code Subject}) or {@link Truth#assertWithMessage} (for most other calls). 163 */ withMessage(String format, Object[] args)164 FailureMetadata withMessage(String format, /*@Nullable*/ Object[] args) { 165 ImmutableList<LazyMessage> messages = append(this.messages, new LazyMessage(format, args)); 166 return derive(messages, steps); 167 } 168 failEqualityCheck( ImmutableList<Fact> headFacts, ImmutableList<Fact> tailFacts, String expected, String actual)169 void failEqualityCheck( 170 ImmutableList<Fact> headFacts, 171 ImmutableList<Fact> tailFacts, 172 String expected, 173 String actual) { 174 doFail( 175 makeComparisonFailure( 176 evaluateAll(messages), 177 makeComparisonFailureFacts( 178 concat(description(), headFacts), 179 concat(tailFacts, rootUnlessThrowable()), 180 expected, 181 actual), 182 expected, 183 actual, 184 rootCause())); 185 } 186 fail(ImmutableList<Fact> facts)187 void fail(ImmutableList<Fact> facts) { 188 doFail( 189 new AssertionErrorWithFacts( 190 evaluateAll(messages), 191 concat(description(), facts, rootUnlessThrowable()), 192 rootCause())); 193 } 194 doFail(AssertionError failure)195 private void doFail(AssertionError failure) { 196 cleanStackTrace(failure); 197 strategy.fail(failure); 198 } 199 derive(ImmutableList<LazyMessage> messages, ImmutableList<Step> steps)200 private FailureMetadata derive(ImmutableList<LazyMessage> messages, ImmutableList<Step> steps) { 201 return new FailureMetadata(strategy, messages, steps); 202 } 203 204 /** 205 * Returns a description of the final actual value, if it appears "interesting" enough to show. 206 * The description is considered interesting if the chain of derived subjects ends with at least 207 * one derivation that we have a name for. It's also considered interesting in the absence of 208 * derived subjects if we inferred a name for the root actual value from the bytecode. 209 * 210 * <p>We don't want to say: "value of string: expected [foo] but was [bar]" (OK, we might still 211 * decide to say this, but for now, we don't.) 212 * 213 * <p>We do want to say: "value of throwable.getMessage(): expected [foo] but was [bar]" 214 * 215 * <p>We also want to say: "value of getLogMessages(): expected not to be empty" 216 * 217 * <p>To support that, {@code descriptionIsInteresting} tracks whether we've been given context 218 * through {@code check} calls <i>that include names</i> or, initially, whether we inferred a name 219 * for the root actual value from the bytecode. 220 * 221 * <p>If we're missing a naming function halfway through, we have to reset: We don't want to claim 222 * that the value is "foo.bar.baz" when it's "foo.bar.somethingelse.baz." We have to go back to 223 * "object.baz." (But note that {@link #rootUnlessThrowable} will still provide the value of the 224 * root foo to the user as long as we had at least one naming function: We might not know the 225 * root's exact relationship to the final object, but we know it's some object "different enough" 226 * to be worth displaying.) 227 */ description()228 private ImmutableList<Fact> description() { 229 String description = inferDescription(); 230 boolean descriptionIsInteresting = description != null; 231 for (Step step : steps) { 232 if (step.isCheckCall()) { 233 checkState(description != null); 234 if (step.descriptionUpdate == null) { 235 description = null; 236 descriptionIsInteresting = false; 237 } else { 238 description = verifyNotNull(step.descriptionUpdate.apply(description)); 239 descriptionIsInteresting = true; 240 } 241 continue; 242 } 243 244 if (description == null) { 245 description = step.subject.typeDescription(); 246 } 247 } 248 return descriptionIsInteresting 249 ? ImmutableList.of(fact("value of", description)) 250 : ImmutableList.<Fact>of(); 251 } 252 253 /** 254 * Returns the root actual value, if we know it's "different enough" from the final actual value. 255 * 256 * <p>We don't want to say: "expected [foo] but was [bar]. string: [bar]" 257 * 258 * <p>We do want to say: "expected [foo] but was [bar]. myObject: MyObject[string=bar, i=0]" 259 * 260 * <p>To support that, {@code seenDerivation} tracks whether we've seen multiple actual values, 261 * which is equivalent to whether we've seen multiple Subject instances or, more informally, 262 * whether the user is making a chained assertion. 263 * 264 * <p>There's one wrinkle: Sometimes chaining doesn't add information. This is often true with 265 * "internal" chaining, like when StreamSubject internally creates an IterableSubject to delegate 266 * to. The two subjects' string representations will be identical (or, in some cases, _almost_ 267 * identical), so there is no value in showing both. In such cases, implementations can call the 268 * no-arg {@code checkNoNeedToDisplayBothValues()}, which sets {@code valuesAreSimilar}, 269 * instructing this method that that particular chain link "doesn't count." (Note also that there 270 * are some edge cases that we're not sure how to handle yet, for which we might introduce 271 * additional {@code check}-like methods someday.) 272 */ 273 // TODO(b/134505914): Consider returning multiple facts in some cases. rootUnlessThrowable()274 private ImmutableList<Fact> rootUnlessThrowable() { 275 Step rootSubject = null; 276 boolean seenDerivation = false; 277 for (Step step : steps) { 278 if (step.isCheckCall()) { 279 /* 280 * If we don't have a description update, don't trigger display of a root object. (If we 281 * did, we'd change the messages of a bunch of existing subjects, and we don't want to bite 282 * that off yet.) 283 * 284 * If we do have a description update, then trigger display of a root object but only if the 285 * old and new values are "different enough" to be worth both displaying. 286 */ 287 seenDerivation |= 288 step.descriptionUpdate != null 289 && step.valuesAreSimilar == OldAndNewValuesAreSimilar.DIFFERENT; 290 continue; 291 } 292 293 if (rootSubject == null) { 294 if (step.subject.actual() instanceof Throwable) { 295 /* 296 * We'll already include the Throwable as a cause of the AssertionError (see rootCause()), 297 * so we don't need to include it again in the message. 298 */ 299 return ImmutableList.of(); 300 } 301 rootSubject = step; 302 } 303 } 304 /* 305 * TODO(cpovirk): Maybe say "root foo was: ..." instead of just "foo was: ..." if there's more 306 * than one foo in the chain, if the description string doesn't start with "foo," and/or if the 307 * name we have is just "object?" 308 */ 309 return seenDerivation 310 ? ImmutableList.of( 311 fact( 312 // TODO(cpovirk): Use inferDescription() here when appropriate? But it can be long. 313 rootSubject.subject.typeDescription() + " was", 314 rootSubject.subject.actualCustomStringRepresentationForPackageMembersToCall())) 315 : ImmutableList.<Fact>of(); 316 } 317 318 /** 319 * Returns the first {@link Throwable} in the chain of actual values. Typically, we'll have a root 320 * cause only if the assertion chain contains a {@link ThrowableSubject}. 321 */ rootCause()322 private @Nullable Throwable rootCause() { 323 for (Step step : steps) { 324 if (!step.isCheckCall() && step.subject.actual() instanceof Throwable) { 325 return (Throwable) step.subject.actual(); 326 } 327 } 328 return null; 329 } 330 } 331