Skip to content

Commit

Permalink
Removing the IllegalStateException types and updating the assertions …
Browse files Browse the repository at this point in the history
…to use the built in expected/actual fields for better tool support
  • Loading branch information
littleclay committed Jan 5, 2018
1 parent 9bebfdc commit 9298046
Show file tree
Hide file tree
Showing 15 changed files with 335 additions and 222 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ To install, you can simply include the dependency from Maven Central:
<dependency>
<groupId>com.redfin</groupId>
<artifactId>insist</artifactId>
<version>3.0.1</version>
<version>4.0.0</version>
</dependency>
```

Expand Down Expand Up @@ -102,3 +102,5 @@ until either a `true` value is received or until the Duration of 1 minute is rea
is reached than an assertion failure is thrown.
Note that it might stop before 1 minute has been reached if it had a failed attempt and waiting for 500 milliseconds
would put it after the requested timeout as per the Patience library.
Also note that it does not interrupt the retrieval of a boolean from the `thatEventually(BooleanSupplier)` so
if the code you are checking hangs it will hang as well or could take longer than the given duration and be successful.
6 changes: 3 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

<groupId>com.redfin</groupId>
<artifactId>insist</artifactId>
<version>3.0.1</version>
<version>4.0.0</version>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>

Expand Down Expand Up @@ -76,12 +76,12 @@
<dependency>
<groupId>com.redfin</groupId>
<artifactId>validity</artifactId>
<version>5.0.0</version>
<version>5.1.0</version>
</dependency>
<dependency>
<groupId>com.redfin</groupId>
<artifactId>patience</artifactId>
<version>3.5.0</version>
<version>3.6.0</version>
</dependency>
<dependency>
<groupId>org.opentest4j</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright: (c) 2016 Redfin
*
* 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.redfin.insist;

import com.redfin.validity.ValidityUtils;
import org.opentest4j.TestAbortedException;

/**
* Concrete subclass of the {@link AbstractStackTrimmingFailedValidationExecutor} that
* throws {@link TestAbortedException} exceptions upon failure.
*/
public final class AbortedFailedValidationExecutor
extends AbstractStackTrimmingFailedValidationExecutor<TestAbortedException> {

@Override
protected String getDefaultMessage() {
return "Test aborted";
}

@Override
protected <T> TestAbortedException buildThrowable(String expected,
T actual,
String message) {
if (null == expected) {
throw new NullPointerException(ValidityUtils.nullArgumentMessage("expected"));
}
return new TestAbortedException(String.format("%s\n expected : %s\n actual : <%s>",
message,
expected,
ValidityUtils.describe(actual)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,73 +21,42 @@
import com.redfin.validity.ValidityUtils;

import java.util.OptionalInt;
import java.util.function.Function;
import java.util.function.Supplier;

import static com.redfin.validity.Validity.validate;

/**
* An implementation of {@link FailedValidationExecutor} thatEventually will remove all stack frames
* from the generated {@link Throwable} except for the actual line thatEventually called for validation.
* This is intended for use with Assertions and Assumptions thatEventually will be used in actual test methods
* where the extended stack frame is noisy and not helpful. It should not be used in frameworks or
* production code where the stack trace is essential for debugging.
* Base class for {@link FailedValidationExecutor} instances that will be trimming out all except for the first
* non-Insist, non-Validity libraries line from the stack trace.
*
* @param <X> the type of the Throwable it will throw.
*/
final class StackTrimmingFailedValidationExecutor<X extends Throwable>
implements FailedValidationExecutor<X> {

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Constants
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public abstract class AbstractStackTrimmingFailedValidationExecutor<X extends Throwable>
implements FailedValidationExecutor<X> {

private static final String DEFAULT_MESSAGE = "Insistence failure";
private static final String MESSAGE_FORMAT = "%s\n expected : %s\n subject : <%s>";
private static final String PACKAGE_NAME = StackTrimmingFailedValidationExecutor.class.getPackage().getName() + ".";
private static final String PACKAGE_NAME = AssertionFailedValidationExecutor.class.getPackage().getName() + ".";
private static final String VALIDITY_PACKAGE_NAME = Validity.class.getPackage().getName() + ".";

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Members
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
protected abstract String getDefaultMessage();

private final Function<String, X> throwableFunction;

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Instance Methods
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

/**
* Create a new instance of a {@link StackTrimmingFailedValidationExecutor} thatEventually
* will use the given throwableFunction when the {@link #fail(String, Object, Supplier)}
* method is called.
*
* @param throwableFunction the {@link Function} thatEventually takes in a String and returns a
* Throwable of type X.
* May not be null.
* Should never return a null Throwable.
*
* @throws IllegalArgumentException if throwableFunction is null.
*/
StackTrimmingFailedValidationExecutor(Function<String, X> throwableFunction) {
this.throwableFunction = validate().that(throwableFunction).isNotNull();
}
protected abstract <T> X buildThrowable(String expected,
T actual,
String message);

@Override
public <T> void fail(String expected,
T subject,
Supplier<String> messageSupplier) throws X {
public final <T> void fail(String expected,
T actual,
Supplier<String> messageSupplier) throws X {
if (null == expected) {
throw new NullPointerException(ValidityUtils.nullArgumentMessage("expected"));
}
if (null == messageSupplier) {
throw new NullPointerException(ValidityUtils.nullArgumentMessage("messageSupplier"));
}
String subjectDescription = ValidityUtils.describe(subject);
String message = messageSupplier.get();
if (null == message) {
message = DEFAULT_MESSAGE;
message = getDefaultMessage();
}
// Create the throwable
X throwable = throwableFunction.apply(String.format(MESSAGE_FORMAT, message, expected, subjectDescription));
X throwable = buildThrowable(expected, actual, message);
if (null == throwable) {
throw new NullPointerException(ValidityUtils.nullThrowableFromFunction());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright: (c) 2016 Redfin
*
* 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.redfin.insist;

import com.redfin.validity.ValidityUtils;
import org.opentest4j.AssertionFailedError;

/**
* Concrete subclass of the {@link AbstractStackTrimmingFailedValidationExecutor} that
* throws {@link AssertionFailedError} errors upon failure.
*/
public final class AssertionFailedValidationExecutor
extends AbstractStackTrimmingFailedValidationExecutor<AssertionFailedError> {

@Override
protected String getDefaultMessage() {
return "Assertion failure";
}

@Override
protected <T> AssertionFailedError buildThrowable(String expected,
T actual,
String message) {
if (null == expected) {
throw new NullPointerException(ValidityUtils.nullArgumentMessage("expected"));
}
return new AssertionFailedError(message,
expected,
actual);
}
}
20 changes: 4 additions & 16 deletions src/main/java/com/redfin/insist/Insist.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,8 @@ public final class Insist {
// Constants
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

private static final StackTrimmingFailedValidationExecutor<AssertionFailedError> ASSERT_EXECUTOR;
private static final StackTrimmingFailedValidationExecutor<TestAbortedException> ASSUME_EXECUTOR;
private static final StackTrimmingFailedValidationExecutor<IllegalStateException> EXPECT_EXECUTOR;
private static final AssertionFailedValidationExecutor ASSERT_EXECUTOR;
private static final AbortedFailedValidationExecutor ASSUME_EXECUTOR;

/*
* The null message instances of the factories can be re-used safely. Cache them
Expand All @@ -40,15 +39,12 @@ public final class Insist {

private static final InsistVerifiableFactory<AssertionFailedError> NULL_MESSAGE_ASSERT_FACTORY;
private static final InsistVerifiableFactory<TestAbortedException> NULL_MESSAGE_ASSUME_FACTORY;
private static final InsistVerifiableFactory<IllegalStateException> NULL_MESSAGE_EXPECT_FACTORY;

static {
ASSERT_EXECUTOR = new StackTrimmingFailedValidationExecutor<>(AssertionFailedError::new);
ASSUME_EXECUTOR = new StackTrimmingFailedValidationExecutor<>(TestAbortedException::new);
EXPECT_EXECUTOR = new StackTrimmingFailedValidationExecutor<>(IllegalStateException::new);
ASSERT_EXECUTOR = new AssertionFailedValidationExecutor();
ASSUME_EXECUTOR = new AbortedFailedValidationExecutor();
NULL_MESSAGE_ASSERT_FACTORY = new InsistVerifiableFactory<>(() -> null, ASSERT_EXECUTOR);
NULL_MESSAGE_ASSUME_FACTORY = new InsistVerifiableFactory<>(() -> null, ASSUME_EXECUTOR);
NULL_MESSAGE_EXPECT_FACTORY = new InsistVerifiableFactory<>(() -> null, EXPECT_EXECUTOR);
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand All @@ -71,14 +67,6 @@ public static InsistVerifiableFactory<TestAbortedException> assumes() {
return NULL_MESSAGE_ASSUME_FACTORY;
}

/**
* @return an {@link InsistVerifiableFactory} instance with the default message prefix thatEventually
* throws an {@link IllegalStateException} on validation failure.
*/
public static InsistVerifiableFactory<IllegalStateException> expects() {
return NULL_MESSAGE_EXPECT_FACTORY;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Instance Methods
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/com/redfin/insist/InsistVerifiableFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,9 @@ public InsistCompletableFuture<X> withWait(PatientWait wait) {
/**
* Like calling {@link #withWait(PatientWait)} with a wait object that retries
* repeatedly up to the set tryingFor maximum with a short delay between
* attempts. Any throwable thrown during the execution will be ignored.
* attempts. Any throwable thrown during the execution will be ignored. Note that this
* does NOT interrupt the attempt to get a valid result but checks the timeout between
* successive attempts to get a true value.
*
* @param tryingFor the {@link Duration} object to be used as the maximum
* time to wait.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@
import org.junit.jupiter.api.Test;
import org.opentest4j.AssertionFailedError;

import java.time.Duration;

/*
* A separate package is used for this test since the default behavior
* of the DefaultValidityFailedValidationExecutor supplied in the library
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright: (c) 2016 Redfin
*
* 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.redfin.insist;

import com.redfin.validity.FailedValidationExecutor;
import org.opentest4j.TestAbortedException;

final class AbortedFailedValidationExecutorTest
implements StackTrimmingFailedValidationExecutorContract<TestAbortedException, AbortedFailedValidationExecutor> {

@Override
public AbortedFailedValidationExecutor getStackTrimmingFailedValidationExecutor() {
return new AbortedFailedValidationExecutor();
}

@Override
public FailedValidationExecutor<TestAbortedException> getFailedValidationExecutor() {
return getStackTrimmingFailedValidationExecutor();
}

@Override
public Class<TestAbortedException> getThrowableClass() {
return TestAbortedException.class;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright: (c) 2016 Redfin
*
* 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.redfin.insist;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

final class AbstractStackTrimmingFailedValidationExecutorTest {

private static class MockImplementation
extends AbstractStackTrimmingFailedValidationExecutor<IllegalArgumentException> {

@Override
protected String getDefaultMessage() {
return "hello";
}

@Override
protected <T> IllegalArgumentException buildThrowable(String expected,
T actual,
String message) {
return null;
}
}

@Test
void testFailThrowsForNullThrowableReturnedbySubclass() {
Assertions.assertThrows(NullPointerException.class,
() -> new MockImplementation().fail("t -> t.equals(\"hello\")", "world", () -> "default message"),
"AbstractStackTrimmingFailedValidationExecutor should throw an exception if buildThrowable returns a null throwable.");
}
}
Loading

0 comments on commit 9298046

Please sign in to comment.