blob: ac58ec06eab84362d610dc75c176433ca9027f77 [file] [log] [blame]
/*
* Copyright (c) 2018 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.common.truth;
import static com.google.common.truth.Fact.simpleFact;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assert_;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Tests for chained subjects (produced with {@link Subject#check()}, etc.). */
@RunWith(JUnit4.class)
public final class ChainingTest extends BaseSubjectTestCase {
private static final Throwable throwable = new Throwable("root");
@Test
public void noChaining() {
expectFailureWhenTestingThat("root").isThePresentKingOfFrance();
assertNoCause("message");
}
@Test
public void oneLevel() {
expectFailureWhenTestingThat("root").delegatingTo("child").isThePresentKingOfFrance();
assertNoCause("message");
}
@Test
public void twoLevels() {
expectFailureWhenTestingThat("root")
.delegatingTo("child")
.delegatingTo("grandchild")
.isThePresentKingOfFrance();
assertNoCause("message");
}
@Test
public void noChainingRootThrowable() {
expectFailureWhenTestingThat(throwable).isThePresentKingOfFrance();
assertHasCause("message");
}
@Test
public void oneLevelRootThrowable() {
expectFailureWhenTestingThat(throwable).delegatingTo("child").isThePresentKingOfFrance();
assertHasCause("message");
}
@Test
public void twoLevelsRootThrowable() {
expectFailureWhenTestingThat(throwable)
.delegatingTo("child")
.delegatingTo("grandchild")
.isThePresentKingOfFrance();
assertHasCause("message");
}
// e.g., future.failureCause()
@Test
public void oneLevelDerivedThrowable() {
expectFailureWhenTestingThat("root").delegatingTo(throwable).isThePresentKingOfFrance();
assertHasCause("message");
}
@Test
public void twoLevelsDerivedThrowableMiddle() {
expectFailureWhenTestingThat("root")
.delegatingTo(throwable)
.delegatingTo("grandchild")
.isThePresentKingOfFrance();
assertHasCause("message");
}
@Test
public void twoLevelsDerivedThrowableLast() {
expectFailureWhenTestingThat("root")
.delegatingTo("child")
.delegatingTo(throwable)
.isThePresentKingOfFrance();
assertHasCause("message");
}
@Test
public void oneLevelNamed() {
expectFailureWhenTestingThat("root")
.delegatingToNamed("child", "child")
.isThePresentKingOfFrance();
assertNoCause("value of : myObject.child\nmessage\nmyObject was: root");
}
@Test
public void twoLevelsNamed() {
expectFailureWhenTestingThat("root")
.delegatingToNamed("child", "child")
.delegatingToNamed("grandchild", "grandchild")
.isThePresentKingOfFrance();
assertNoCause("value of : myObject.child.grandchild\nmessage\nmyObject was: root");
}
@Test
public void twoLevelsOnlyFirstNamed() {
expectFailureWhenTestingThat("root")
.delegatingToNamed("child", "child")
.delegatingTo("grandchild")
.isThePresentKingOfFrance();
assertNoCause("message\nmyObject was: root");
}
@Test
public void twoLevelsOnlySecondNamed() {
expectFailureWhenTestingThat("root")
.delegatingTo("child")
.delegatingToNamed("grandchild", "grandchild")
.isThePresentKingOfFrance();
assertNoCause("value of : myObject.grandchild\nmessage\nmyObject was: root");
}
@Test
public void oneLevelNamedNoNeedToDisplayBoth() {
expectFailureWhenTestingThat("root")
.delegatingToNamedNoNeedToDisplayBoth("child", "child")
.isThePresentKingOfFrance();
assertNoCause("value of: myObject.child\nmessage");
}
@Test
public void twoLevelsNamedNoNeedToDisplayBoth() {
expectFailureWhenTestingThat("root")
.delegatingToNamedNoNeedToDisplayBoth("child", "child")
.delegatingToNamedNoNeedToDisplayBoth("grandchild", "grandchild")
.isThePresentKingOfFrance();
assertNoCause("value of: myObject.child.grandchild\nmessage");
}
@Test
public void twoLevelsOnlyFirstNamedNoNeedToDisplayBoth() {
expectFailureWhenTestingThat("root")
.delegatingToNamedNoNeedToDisplayBoth("child", "child")
.delegatingTo("grandchild")
.isThePresentKingOfFrance();
assertNoCause("message");
}
@Test
public void twoLevelsOnlySecondNamedNoNeedToDisplayBoth() {
expectFailureWhenTestingThat("root")
.delegatingTo("child")
.delegatingToNamedNoNeedToDisplayBoth("grandchild", "grandchild")
.isThePresentKingOfFrance();
assertNoCause("value of: myObject.grandchild\nmessage");
}
@Test
public void twoLevelsNamedOnlyFirstNoNeedToDisplayBoth() {
expectFailureWhenTestingThat("root")
.delegatingToNamedNoNeedToDisplayBoth("child", "child")
.delegatingToNamed("grandchild", "grandchild")
.isThePresentKingOfFrance();
assertNoCause("value of : myObject.child.grandchild\nmessage\nmyObject was: root");
}
@Test
public void twoLevelsNamedOnlySecondNoNeedToDisplayBoth() {
expectFailureWhenTestingThat("root")
.delegatingToNamed("child", "child")
.delegatingToNamedNoNeedToDisplayBoth("grandchild", "grandchild")
.isThePresentKingOfFrance();
assertNoCause("value of : myObject.child.grandchild\nmessage\nmyObject was: root");
}
@Test
public void namedAndMessage() {
expectFailure
.whenTesting()
.withMessage("prefix")
.about(myObjects())
.that("root")
.delegatingToNamed("child", "child")
.isThePresentKingOfFrance();
assertNoCause("prefix\nvalue of : myObject.child\nmessage\nmyObject was: root");
}
@Test
public void checkFail() {
expectFailureWhenTestingThat("root").doCheckFail();
assertNoCause("message");
}
@Test
public void checkFailWithName() {
expectFailureWhenTestingThat("root").doCheckFail("child");
assertNoCause("message\nvalue of : myObject.child\nmyObject was: root");
}
@Test
public void badFormat() {
try {
Object unused = assertThat("root").check("%s %s", 1, 2, 3);
assert_().fail();
} catch (IllegalArgumentException expected) {
}
}
/*
* TODO(cpovirk): It would be nice to have multiple Subject subclasses so that we know we're
* pulling the type from the right link in the chain. But we get some coverage of that from other
* tests like MultimapSubjectTest.
*/
private static final class MyObjectSubject extends Subject {
static final Factory<MyObjectSubject, Object> FACTORY =
new Factory<MyObjectSubject, Object>() {
@Override
public MyObjectSubject createSubject(FailureMetadata metadata, Object actual) {
return new MyObjectSubject(metadata, actual);
}
};
private MyObjectSubject(FailureMetadata metadata, Object actual) {
super(metadata, actual);
}
/** Runs a check that always fails with the generic message "message." */
void isThePresentKingOfFrance() {
failWithoutActual(simpleFact("message"));
}
void doCheckFail() {
check().fail("message");
}
void doCheckFail(String name) {
check(name).fail("message");
}
/**
* Returns a new {@code MyObjectSubject} for the given actual value, chaining it to the current
* subject with {@link Subject#check}.
*/
MyObjectSubject delegatingTo(Object actual) {
return check().about(myObjects()).that(actual);
}
/**
* Returns a new {@code MyObjectSubject} for the given actual value, chaining it to the current
* subject with {@link Subject#check}.
*/
MyObjectSubject delegatingToNamed(Object actual, String name) {
return check(name).about(myObjects()).that(actual);
}
MyObjectSubject delegatingToNamedNoNeedToDisplayBoth(Object actual, String name) {
return checkNoNeedToDisplayBothValues(name).about(myObjects()).that(actual);
}
}
private static Subject.Factory<MyObjectSubject, Object> myObjects() {
return MyObjectSubject.FACTORY;
}
private MyObjectSubject expectFailureWhenTestingThat(Object actual) {
return expectFailure.whenTesting().about(myObjects()).that(actual);
}
private void assertNoCause(String message) {
assertThatFailure().hasMessageThat().isEqualTo(message);
assertThatFailure().hasCauseThat().isNull();
}
private void assertHasCause(String message) {
assertThatFailure().hasMessageThat().isEqualTo(message);
assertThatFailure().hasCauseThat().isEqualTo(throwable);
}
}