![JAR search and dependency download from the Maven repository](/logo.png)
com.google.common.truth.Subject Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of truth Show documentation
Show all versions of truth Show documentation
Relocates org.truth0:truth to com.google.truth:truth.
See http://maven.apache.org/guides/mini/guide-relocation.html
The newest version!
/*
* Copyright (c) 2011 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.StringUtil.format;
import com.google.common.annotations.GwtIncompatible;
import java.lang.reflect.Field;
/**
* Propositions for arbitrarily typed subjects and for properties
* of Object
*
* @author David Saff
* @author Christian Gruber ([email protected])
*/
public class Subject,T> {
protected final FailureStrategy failureStrategy;
private final T subject;
private String customName = null;
public Subject(FailureStrategy failureStrategy, T subject) {
this.failureStrategy = failureStrategy;
this.subject = subject;
}
protected String internalCustomName() {
return customName;
}
/**
* Renames the subject so that this name appears in the error messages in place of string
* representations of the subject.
*/
@SuppressWarnings("unchecked")
public S named(String name) {
if (name == null) {
// TODO: use check().withFailureMessage... here?
throw new NullPointerException("Name passed to named() cannot be null.");
}
this.customName = name;
return (S)this;
}
/**
* Soft-deprecated in favor of {@link #named(String)}.
*/
public S labeled(String label) {
return named(label);
}
public void is(Object other) {
isEqualTo(other);
}
public void isNull() {
if (getSubject() != null) {
failWithoutSubject("is a null reference");
}
}
public void isNotNull() {
if (getSubject() == null) {
failWithoutSubject("is a non-null reference");
}
}
public void isEqualTo(Object other) {
if (getSubject() == null) {
if(other != null) {
fail("is equal to", other);
}
} else {
if (!getSubject().equals(other)) {
fail("is equal to", other);
}
}
}
public void isNotEqualTo(Object other) {
if (getSubject() == null) {
if(other == null) {
fail("is not equal to", (Object)null);
}
} else {
if (getSubject().equals(other)) {
fail("is not equal to", other);
}
}
}
public void isA(Class> clazz) {
if (clazz == null) {
throw new NullPointerException("clazz");
}
if (!Platform.isInstanceOfType(getSubject(), clazz)) {
if (getSubject() != null) {
failWithBadResults("is an instance of", clazz.getName(),
"is an instance of", getSubject().getClass().getName());
} else {
fail("is an instance of", clazz.getName());
}
}
}
public void isNotA(Class> clazz) {
if (clazz == null) {
throw new NullPointerException("clazz");
}
if (getSubject() == null) {
return; // null is not an instance of clazz.
}
if (Platform.isInstanceOfType(getSubject(), clazz)) {
failWithRawMessage("%s expected not to be an instance of %s, but was.",
getDisplaySubject(), clazz.getName());
}
}
protected T getSubject() {
return subject;
}
protected String getDisplaySubject() {
return (customName == null)
? "<" + getSubject() + ">"
: "\"" + this.customName + "\"";
}
/**
* A convenience for implementers of {@link Subject} subclasses to use other truth
* {@code Subject} wrappers within their own propositional logic.
*/
protected TestVerb check() {
return new TestVerb(failureStrategy);
}
/**
* Assembles a failure message and passes such to the FailureStrategy
*
* @param verb the proposition being asserted
* @param messageParts the expectations against which the subject is compared
*/
protected void fail(String verb, Object... messageParts) {
StringBuilder message = new StringBuilder("Not true that ");
message.append(getDisplaySubject()).append(" ").append(verb);
for (Object part : messageParts) {
message.append(" <").append(part).append(">");
}
failureStrategy.fail(message.toString());
}
/**
* Assembles a failure message and passes it to the FailureStrategy
*
* @param verb the proposition being asserted
* @param messageParts the expectations against which the subject is compared
*/
protected void failWithBadResults(String verb, Object expected, String failVerb, Object actual) {
String message = format("Not true that %s %s <%s>. It %s <%s>",
getDisplaySubject(),
verb,
expected,
failVerb,
((actual == null) ? "null reference" : actual));
failureStrategy.fail(message);
}
/**
* Assembles a failure message with an alternative representation of the wrapped subject
* and passes it to the FailureStrategy
*
* @param verb the proposition being asserted
* @param expected the expected value of the proposition
* @param actual the custom representation of the subject to be reported in the failure.
*/
protected void failWithCustomSubject(String verb, Object expected, Object actual) {
String message = format("Not true that <%s> %s <%s>",
((actual == null) ? "null reference" : actual),
verb,
expected);
failureStrategy.fail(message);
}
/**
* Assembles a failure message without a given subject and passes it to the FailureStrategy
*
* @param verb the proposition being asserted
*/
protected void failWithoutSubject(String verb) {
String subject = this.customName == null ? "the subject" : "\"" + customName + "\"";
failureStrategy.fail(format("Not true that %s %s", subject, verb));
}
/**
* Passes through a failure message verbatim. Used for {@link Subject} subclasses which
* need to provide alternate language for more fit-to-purpose error messages.
*
*
* @param message the message template to be passed to the failure. Note, this method only
* guarantees to process {@code %s} tokens. It is not guaranteed to be compatible
* with {@code String.format()}. Any other formatting desired (such as floats or
* scientific notation) should be performed before the method call and the formatted
* value passed in as a string.
* @param paramters the object parameters which will be applied to the message template.
*/
protected void failWithRawMessage(String message, Object ... parameters) {
failureStrategy.fail(format(message, parameters));
}
@GwtIncompatible("java.lang.reflect.Field")
public HasField hasField(final String fieldName) {
final T subject = getSubject();
if (subject == null) {
failureStrategy.fail("Cannot determine a field name from a null object.");
// Needed for Expect and other non-terminal failure strategies
return new HasField() {
@Override public void withValue(Object value) {
Subject.this.fail("Cannot test the presence of a value in a null object.");
}
};
}
final Class> subjectClass = subject.getClass();
final Field field;
try {
field = ReflectionUtil.getField(subjectClass, fieldName);
field.setAccessible(true);
} catch (NoSuchFieldException e) {
StringBuilder message = new StringBuilder("Not true that ");
message.append("<").append(subjectClass.getSimpleName()).append(">");
message.append(" has a field named <").append(fieldName).append(">");
failureStrategy.fail(message.toString());
// Needed for Expect and other non-terminal failure strategies
return new HasField() {
@Override public void withValue(Object value) {
Subject.this.fail("Cannot test the presence of a value in a non-present field.");
}
};
}
return new HasField() {
@Override public void withValue(Object expected) {
try {
Object actual = field.get(subject);
if (expected == actual || (expected != null && expected.equals(actual))) {
return;
} else {
StringBuilder message = new StringBuilder("Not true that ");
message.append("<").append(subjectClass.getSimpleName()).append(">'s");
message.append(" field <").append(fieldName).append(">");
message.append(" contains expected value <").append(expected).append(">.");
message.append(" It contains value <").append(actual).append(">");
failureStrategy.fail(message.toString());
}
} catch (IllegalArgumentException e) {
throw new RuntimeException(
"Error checking field " + fieldName + " while testing for value " + expected);
} catch (IllegalAccessException e) {
throw new RuntimeException(
"Cannot access field " + fieldName + " to test for value " + expected);
}
}
};
}
@GwtIncompatible("java.lang.reflect.Field")
public static interface HasField {
/**
* Supplementary assertion in which a present field can be tested
* to determine if it contains a given value.
*/
void withValue(Object value);
}
/**
* @deprecated This method is not a proposition, but the default Object equality method.
* Testing code should use "is" or "isEqualTo" propositions for equality tests.
*/
@Deprecated
@Override public boolean equals(Object o) {
isEqualTo(o);
return false;
}
/**
* @deprecated Equals/Hashcode is not supported on Subjects. Their only use is as a holder of
* propositions. Use of equals() is deprecated and forwards to isEqualTo() and
* hashCode() is disallowed.
*/
@Deprecated
@Override public int hashCode() {
throw new UnsupportedOperationException(""
+ "Equals/Hashcode is not supported on Subjects. Their only use is as a holder of "
+ "propositions. Use of equals() is deprecated and forwards to isEqualTo() and "
+ "hashCode() is disallowed.");
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy