1 /* 2 * Copyright (c) 2018 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 17 package com.google.common.truth; 18 19 import static com.google.common.truth.Fact.simpleFact; 20 import static com.google.common.truth.Truth.assertThat; 21 import static com.google.common.truth.Truth.assert_; 22 23 import org.junit.Test; 24 import org.junit.runner.RunWith; 25 import org.junit.runners.JUnit4; 26 27 /** Tests for chained subjects (produced with {@link Subject#check(String, Object...)}, etc.). */ 28 @RunWith(JUnit4.class) 29 public final class ChainingTest extends BaseSubjectTestCase { 30 private static final Throwable throwable = new Throwable("root"); 31 32 @Test noChaining()33 public void noChaining() { 34 expectFailureWhenTestingThat("root").isThePresentKingOfFrance(); 35 assertNoCause("message"); 36 } 37 38 @Test oneLevel()39 public void oneLevel() { 40 expectFailureWhenTestingThat("root").delegatingTo("child").isThePresentKingOfFrance(); 41 assertNoCause("message"); 42 } 43 44 @Test twoLevels()45 public void twoLevels() { 46 expectFailureWhenTestingThat("root") 47 .delegatingTo("child") 48 .delegatingTo("grandchild") 49 .isThePresentKingOfFrance(); 50 assertNoCause("message"); 51 } 52 53 @Test noChainingRootThrowable()54 public void noChainingRootThrowable() { 55 expectFailureWhenTestingThat(throwable).isThePresentKingOfFrance(); 56 assertHasCause("message"); 57 } 58 59 @Test oneLevelRootThrowable()60 public void oneLevelRootThrowable() { 61 expectFailureWhenTestingThat(throwable).delegatingTo("child").isThePresentKingOfFrance(); 62 assertHasCause("message"); 63 } 64 65 @Test twoLevelsRootThrowable()66 public void twoLevelsRootThrowable() { 67 expectFailureWhenTestingThat(throwable) 68 .delegatingTo("child") 69 .delegatingTo("grandchild") 70 .isThePresentKingOfFrance(); 71 assertHasCause("message"); 72 } 73 74 // e.g., future.failureCause() 75 @Test oneLevelDerivedThrowable()76 public void oneLevelDerivedThrowable() { 77 expectFailureWhenTestingThat("root").delegatingTo(throwable).isThePresentKingOfFrance(); 78 assertHasCause("message"); 79 } 80 81 @Test twoLevelsDerivedThrowableMiddle()82 public void twoLevelsDerivedThrowableMiddle() { 83 expectFailureWhenTestingThat("root") 84 .delegatingTo(throwable) 85 .delegatingTo("grandchild") 86 .isThePresentKingOfFrance(); 87 assertHasCause("message"); 88 } 89 90 @Test twoLevelsDerivedThrowableLast()91 public void twoLevelsDerivedThrowableLast() { 92 expectFailureWhenTestingThat("root") 93 .delegatingTo("child") 94 .delegatingTo(throwable) 95 .isThePresentKingOfFrance(); 96 assertHasCause("message"); 97 } 98 99 @Test oneLevelNamed()100 public void oneLevelNamed() { 101 expectFailureWhenTestingThat("root") 102 .delegatingToNamed("child", "child") 103 .isThePresentKingOfFrance(); 104 assertNoCause("value of : myObject.child\nmessage\nmyObject was: root"); 105 } 106 107 @Test twoLevelsNamed()108 public void twoLevelsNamed() { 109 expectFailureWhenTestingThat("root") 110 .delegatingToNamed("child", "child") 111 .delegatingToNamed("grandchild", "grandchild") 112 .isThePresentKingOfFrance(); 113 assertNoCause("value of : myObject.child.grandchild\nmessage\nmyObject was: root"); 114 } 115 116 @Test twoLevelsOnlyFirstNamed()117 public void twoLevelsOnlyFirstNamed() { 118 expectFailureWhenTestingThat("root") 119 .delegatingToNamed("child", "child") 120 .delegatingTo("grandchild") 121 .isThePresentKingOfFrance(); 122 assertNoCause("message\nmyObject was: root"); 123 } 124 125 @Test twoLevelsOnlySecondNamed()126 public void twoLevelsOnlySecondNamed() { 127 expectFailureWhenTestingThat("root") 128 .delegatingTo("child") 129 .delegatingToNamed("grandchild", "grandchild") 130 .isThePresentKingOfFrance(); 131 assertNoCause("value of : myObject.grandchild\nmessage\nmyObject was: root"); 132 } 133 134 @Test oneLevelNamedNoNeedToDisplayBoth()135 public void oneLevelNamedNoNeedToDisplayBoth() { 136 expectFailureWhenTestingThat("root") 137 .delegatingToNamedNoNeedToDisplayBoth("child", "child") 138 .isThePresentKingOfFrance(); 139 assertNoCause("value of: myObject.child\nmessage"); 140 } 141 142 @Test twoLevelsNamedNoNeedToDisplayBoth()143 public void twoLevelsNamedNoNeedToDisplayBoth() { 144 expectFailureWhenTestingThat("root") 145 .delegatingToNamedNoNeedToDisplayBoth("child", "child") 146 .delegatingToNamedNoNeedToDisplayBoth("grandchild", "grandchild") 147 .isThePresentKingOfFrance(); 148 assertNoCause("value of: myObject.child.grandchild\nmessage"); 149 } 150 151 @Test twoLevelsOnlyFirstNamedNoNeedToDisplayBoth()152 public void twoLevelsOnlyFirstNamedNoNeedToDisplayBoth() { 153 expectFailureWhenTestingThat("root") 154 .delegatingToNamedNoNeedToDisplayBoth("child", "child") 155 .delegatingTo("grandchild") 156 .isThePresentKingOfFrance(); 157 assertNoCause("message"); 158 } 159 160 @Test twoLevelsOnlySecondNamedNoNeedToDisplayBoth()161 public void twoLevelsOnlySecondNamedNoNeedToDisplayBoth() { 162 expectFailureWhenTestingThat("root") 163 .delegatingTo("child") 164 .delegatingToNamedNoNeedToDisplayBoth("grandchild", "grandchild") 165 .isThePresentKingOfFrance(); 166 assertNoCause("value of: myObject.grandchild\nmessage"); 167 } 168 169 @Test twoLevelsNamedOnlyFirstNoNeedToDisplayBoth()170 public void twoLevelsNamedOnlyFirstNoNeedToDisplayBoth() { 171 expectFailureWhenTestingThat("root") 172 .delegatingToNamedNoNeedToDisplayBoth("child", "child") 173 .delegatingToNamed("grandchild", "grandchild") 174 .isThePresentKingOfFrance(); 175 assertNoCause("value of : myObject.child.grandchild\nmessage\nmyObject was: root"); 176 } 177 178 @Test twoLevelsNamedOnlySecondNoNeedToDisplayBoth()179 public void twoLevelsNamedOnlySecondNoNeedToDisplayBoth() { 180 expectFailureWhenTestingThat("root") 181 .delegatingToNamed("child", "child") 182 .delegatingToNamedNoNeedToDisplayBoth("grandchild", "grandchild") 183 .isThePresentKingOfFrance(); 184 assertNoCause("value of : myObject.child.grandchild\nmessage\nmyObject was: root"); 185 } 186 187 @Test namedAndMessage()188 public void namedAndMessage() { 189 expectFailure 190 .whenTesting() 191 .withMessage("prefix") 192 .about(myObjects()) 193 .that("root") 194 .delegatingToNamed("child", "child") 195 .isThePresentKingOfFrance(); 196 assertNoCause("prefix\nvalue of : myObject.child\nmessage\nmyObject was: root"); 197 } 198 199 @Test checkFail()200 public void checkFail() { 201 expectFailureWhenTestingThat("root").doCheckFail(); 202 assertNoCause("message"); 203 } 204 205 @Test checkFailWithName()206 public void checkFailWithName() { 207 expectFailureWhenTestingThat("root").doCheckFail("child"); 208 assertNoCause("message\nvalue of : myObject.child\nmyObject was: root"); 209 } 210 211 @Test badFormat()212 public void badFormat() { 213 try { 214 @SuppressWarnings("LenientFormatStringValidation") // Intentional for testing. 215 Object unused = assertThat("root").check("%s %s", 1, 2, 3); 216 assert_().fail(); 217 } catch (IllegalArgumentException expected) { 218 } 219 } 220 221 /* 222 * TODO(cpovirk): It would be nice to have multiple Subject subclasses so that we know we're 223 * pulling the type from the right link in the chain. But we get some coverage of that from other 224 * tests like MultimapSubjectTest. 225 */ 226 227 private static final class MyObjectSubject extends Subject { 228 static final Factory<MyObjectSubject, Object> FACTORY = 229 new Factory<MyObjectSubject, Object>() { 230 @Override 231 public MyObjectSubject createSubject(FailureMetadata metadata, Object actual) { 232 return new MyObjectSubject(metadata, actual); 233 } 234 }; 235 MyObjectSubject(FailureMetadata metadata, Object actual)236 private MyObjectSubject(FailureMetadata metadata, Object actual) { 237 super(metadata, actual); 238 } 239 240 /** Runs a check that always fails with the generic message "message." */ isThePresentKingOfFrance()241 void isThePresentKingOfFrance() { 242 failWithoutActual(simpleFact("message")); 243 } 244 doCheckFail()245 void doCheckFail() { 246 check().withMessage("message").fail(); 247 } 248 doCheckFail(String name)249 void doCheckFail(String name) { 250 check(name).withMessage("message").fail(); 251 } 252 253 /** 254 * Returns a new {@code MyObjectSubject} for the given actual value, chaining it to the current 255 * subject with {@link Subject#check}. 256 */ delegatingTo(Object actual)257 MyObjectSubject delegatingTo(Object actual) { 258 return check().about(myObjects()).that(actual); 259 } 260 261 /** 262 * Returns a new {@code MyObjectSubject} for the given actual value, chaining it to the current 263 * subject with {@link Subject#check}. 264 */ delegatingToNamed(Object actual, String name)265 MyObjectSubject delegatingToNamed(Object actual, String name) { 266 return check(name).about(myObjects()).that(actual); 267 } 268 delegatingToNamedNoNeedToDisplayBoth(Object actual, String name)269 MyObjectSubject delegatingToNamedNoNeedToDisplayBoth(Object actual, String name) { 270 return checkNoNeedToDisplayBothValues(name).about(myObjects()).that(actual); 271 } 272 } 273 myObjects()274 private static Subject.Factory<MyObjectSubject, Object> myObjects() { 275 return MyObjectSubject.FACTORY; 276 } 277 expectFailureWhenTestingThat(Object actual)278 private MyObjectSubject expectFailureWhenTestingThat(Object actual) { 279 return expectFailure.whenTesting().about(myObjects()).that(actual); 280 } 281 assertNoCause(String message)282 private void assertNoCause(String message) { 283 assertThatFailure().hasMessageThat().isEqualTo(message); 284 assertThatFailure().hasCauseThat().isNull(); 285 } 286 assertHasCause(String message)287 private void assertHasCause(String message) { 288 assertThatFailure().hasMessageThat().isEqualTo(message); 289 assertThatFailure().hasCauseThat().isEqualTo(throwable); 290 } 291 } 292