Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract interface for assertion errors. #60

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion src/main/java/org/opentest4j/AssertionFailedError.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,23 @@
* <p>In addition to a message and a cause, this class stores the expected
* and actual values of an assertion using the {@link ValueWrapper} type.
*
* <p>As an alternative to extending this class, assertion frameworks can
* directly implement the {@link IAssertionFailedError} interface. This
* enables them to leverage OpenTest4J without changing the hierarchy of
* their own assertions (which could break backwards
* compatibility).
*
* * <p>For IDEs and other frameworks that catch these errors, it is preferable that
* they catch {@link AssertionError} and then check to see if it is an instance of
* {@link IAssertionFailedError} rather than to catch this error directly. This
* makes them compatible with other frameworks that implement the interface
* directly.
*
* @author Sam Brannen
* @author Marc Philipp
* @since 1.0
*/
public class AssertionFailedError extends AssertionError {
public class AssertionFailedError extends AssertionError implements IAssertionFailedError {

private static final long serialVersionUID = 1L;

Expand Down
70 changes: 70 additions & 0 deletions src/main/java/org/opentest4j/IAssertionFailedError.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright 2015-2018 the original author or authors.
*
* 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 org.opentest4j;

/**
* {@code IAssertionFailedError} is a common interface for test-related
* {@link AssertionError AssertionErrors} that compare two values.
*
* <p>In addition to a message and a cause, classes that implement
* this interface store the expected and actual values of an assertion
* using the {@link ValueWrapper} type.
*
* <p>The reference implementation for this interface is
* {@link AssertionFailedError}. As an alternative to inheriting from
* {@link AssertionFailedError}, assertion frameworks can implement
* this interface in the class hierarchy of their own assertions.
* This enables them to leverage OpenTest4J compatibility without
* changing the class hierarchy of their own assertions (which could
* break backwards compatibility for users of their framework).
*
* @author Sam Brannen
* @author Marc Philipp
* @since 1.0
*/
public interface IAssertionFailedError {
Copy link

@dgroup dgroup Jun 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi,
Please don't bring the C# notations to Java, especially for JVM direction...


/**
* Returns {@code true} if an <em>expected value</em> was supplied via an
* appropriate constructor.
*
* @see #getExpected()
*/
public boolean isExpectedDefined();

/**
* Returns {@code true} if an <em>actual value</em> was supplied via an
* appropriate constructor.
*
* @see #getActual()
*/
public boolean isActualDefined();

/**
* Returns the wrapped expected value if it is defined; otherwise {@code null}.
*
* @see #isExpectedDefined()
*/
public ValueWrapper getExpected();

/**
* Returns the wrapped actual value if it is defined; otherwise {@code null}.
*
* @see #isActualDefined()
*/
public ValueWrapper getActual();
}
61 changes: 61 additions & 0 deletions src/main/java/org/opentest4j/IMultipleFailuresError.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright 2015-2018 the original author or authors.
*
* 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 org.opentest4j;

import java.util.List;

/**
* {@link IMultipleFailuresError} is an interface for subclasses of
* {@link AssertionError} which aggregate multiple {@code AssertionErrors}
* thrown in a given context (i.e., typically within the invocation of a
* single test).
*
* <p>{@link MultipleFailuresError} exists as a concrete implementation of
* this interface, and is preferred in new implementations. This
* interface exists as a way of retro-fitting OpenTest4J multiple-failure
* support into assertion frameworks that already have their own assertion
* hierarchy, in a way that allows them to preserve backwards compatibility.
*
* @author Johannes Link
* @author Sam Brannen
* @author Marc Philipp
* @since 1.0
*/
public interface IMultipleFailuresError<T extends Throwable> {

/**
* Returns the heading that describes this class of errors.
* @return The string describing this group of failures.
*/
public String getHeading();

/**
* Retrieves the list of individual failures represented by this error.
* @return The list of individual failures represented by this error.
* @see #hasFailures()
*/
public List<T> getFailures();

/**
* Indicates whether this error has any individual failures.
* @return <tt>true</tt> if the erro has individual failures; <tt>false</tt>
* if it has none.
*
* @see #getFailures()
*/
public boolean hasFailures();
}
44 changes: 35 additions & 9 deletions src/main/java/org/opentest4j/MultipleFailuresError.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,29 @@
import java.util.List;

/**
* {@link MultipleFailuresError} is an {@link AssertionError} which
* aggregates multiple {@code AssertionErrors} thrown in a given context
* (i.e., typically within the invocation of a single test).
* {@link MultipleFailuresError} is a concrete {@link AssertionError} that implements
* the {@link IMultipleFailuresError} interface. It aggregates multiple
* {@code AssertionErrors} thrown in a given context (i.e., typically within the
* invocation of a single test).
*
* <p>For assertion frameworks that wish to preserve backwards compatibility, they can
* implement {@link IMultipleFailuresError} directly in their own assertion hierarchies
* rather than directly extend from this class. The static
* {@link #getMessage(IMultipleFailuresError)} method exists to simplify the custom
* implementation of {@link #getMessage()} if desired.
*
* <p>For IDEs and other frameworks that catch these errors, it is preferable that
* they catch {@link AssertionError} and then check to see if it is an instance of
* {@link IMultipleFailuresError} rather than to catch this error directly. This
* makes them compatible with other frameworks that implement the interface
* directly.
*
* @author Johannes Link
* @author Sam Brannen
* @author Marc Philipp
* @since 1.0
*/
public class MultipleFailuresError extends AssertionError {
public class MultipleFailuresError extends AssertionError implements IMultipleFailuresError<Throwable> {

private static final long serialVersionUID = 1L;

Expand All @@ -51,16 +64,27 @@ public MultipleFailuresError(String heading, List<? extends Throwable> failures)
}
}

@Override
public String getHeading() {
return heading;
}

@Override
public String getMessage() {
int failureCount = this.failures.size();
return getMessage(this);
}

public static String getMessage(IMultipleFailuresError<? extends Throwable> me) {
final List<? extends Throwable> failures = me.getFailures();
int failureCount = failures.size();

final String heading = me.getHeading();
if (failureCount == 0) {
return this.heading;
return heading;
}

// @formatter:off
StringBuilder builder = new StringBuilder(this.heading)
StringBuilder builder = new StringBuilder(heading)
.append(" (")
.append(failureCount).append(" ")
.append(pluralize(failureCount, "failure", "failures"))
Expand All @@ -69,18 +93,20 @@ public String getMessage() {
// @formatter:on

int lastIndex = failureCount - 1;
for (Throwable failure : this.failures.subList(0, lastIndex)) {
for (Throwable failure : failures.subList(0, lastIndex)) {
builder.append("\t").append(nullSafeMessage(failure)).append(EOL);
}
builder.append('\t').append(nullSafeMessage(this.failures.get(lastIndex)));
builder.append('\t').append(nullSafeMessage(failures.get(lastIndex)));

return builder.toString();
}

@Override
public List<Throwable> getFailures() {
return Collections.unmodifiableList(this.failures);
}

@Override
public boolean hasFailures() {
return !this.failures.isEmpty();
}
Expand Down