Skip to content

Commit

Permalink
Adding in another entry point in the Insist class and updating depend…
Browse files Browse the repository at this point in the history
…encies
  • Loading branch information
littleclay committed Oct 5, 2017
1 parent a633133 commit 9ed6a7a
Show file tree
Hide file tree
Showing 10 changed files with 111 additions and 59 deletions.
6 changes: 3 additions & 3 deletions 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>2.0.0</version>
<version>2.1.0</version>
</dependency>
```

Expand All @@ -31,8 +31,8 @@ import static com.redfin.insist.Insist.*;

## Assertion vs. Assumption

There are two entry methods when using `Insist`.
They are `assumes()`, and `asserts()` in the `Insist` static class.
There are three entry methods when using `Insist`.
They are `assumes()`, `asserts()`, and `expects()` in the `Insist` static class.
The difference is in what will be thrown upon validation failure.

## Stack trace example
Expand Down
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>2.0.0</version>
<version>2.1.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>4.1.0</version>
<version>5.0.0</version>
</dependency>
<dependency>
<groupId>com.redfin</groupId>
<artifactId>patience</artifactId>
<version>3.2.0</version>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>org.opentest4j</groupId>
Expand Down
18 changes: 16 additions & 2 deletions src/main/java/com/redfin/insist/Insist.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@ public final class Insist {

private static final BiFunction<String, Throwable, AssertionFailedError> ASSERT_BI_FUNCTION;
private static final BiFunction<String, Throwable, TestAbortedException> ASSUME_BI_FUNCTION;
private static final BiFunction<String, Throwable, IllegalStateException> EXPECT_BI_FUNCTION;
private static final StackTrimmingFailedValidationExecutor<AssertionFailedError> ASSERT_EXECUTOR;
private static final StackTrimmingFailedValidationExecutor<TestAbortedException> ASSUME_EXECUTOR;
private static final StackTrimmingFailedValidationExecutor<IllegalStateException> EXPECT_EXECUTOR;

/*
* The null message instances of the factories can be re-used safely. Cache them
Expand All @@ -43,14 +45,18 @@ 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_BI_FUNCTION = AssertionFailedError::new;
ASSUME_BI_FUNCTION = TestAbortedException::new;
EXPECT_BI_FUNCTION = IllegalStateException::new;
ASSERT_EXECUTOR = new StackTrimmingFailedValidationExecutor<>(AssertionFailedError::new);
ASSUME_EXECUTOR = new StackTrimmingFailedValidationExecutor<>(TestAbortedException::new);
NULL_MESSAGE_ASSERT_FACTORY = new InsistVerifiableFactory<>(null, ASSERT_BI_FUNCTION, ASSERT_EXECUTOR);
NULL_MESSAGE_ASSUME_FACTORY = new InsistVerifiableFactory<>(null, ASSUME_BI_FUNCTION, ASSUME_EXECUTOR);
EXPECT_EXECUTOR = new StackTrimmingFailedValidationExecutor<>(IllegalStateException::new);
NULL_MESSAGE_ASSERT_FACTORY = new InsistVerifiableFactory<>(() -> null, ASSERT_BI_FUNCTION, ASSERT_EXECUTOR);
NULL_MESSAGE_ASSUME_FACTORY = new InsistVerifiableFactory<>(() -> null, ASSUME_BI_FUNCTION, ASSUME_EXECUTOR);
NULL_MESSAGE_EXPECT_FACTORY = new InsistVerifiableFactory<>(() -> null, EXPECT_BI_FUNCTION, EXPECT_EXECUTOR);
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand All @@ -73,6 +79,14 @@ 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
19 changes: 11 additions & 8 deletions src/main/java/com/redfin/insist/InsistCompletableFutureImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.time.Duration;
import java.util.function.BiFunction;
import java.util.function.BooleanSupplier;
import java.util.function.Supplier;

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

Expand All @@ -45,7 +46,7 @@ final class InsistCompletableFutureImpl<X extends Throwable>
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

private final BiFunction<String, Throwable, X> throwableFunction;
private final String message;
private final Supplier<String> messageSupplier;
private final PatientWait wait;

private Duration timeout;
Expand All @@ -56,17 +57,18 @@ final class InsistCompletableFutureImpl<X extends Throwable>
* @param throwableFunction the function to take in a string and throwable and
* create a new throwable.
* May not be null.
* @param message the String message prefix if validation fails.
* @param messageSupplier the {@link Supplier} of the String message prefix if validation fails.
* May not be null.
* @param wait the {@link com.redfin.patience.PatientWait} to use if waiting for validation to succeed.
* May not be null.
*
* @throws IllegalArgumentException if throwableFunction or wait are null.
* @throws IllegalArgumentException if throwableFunction, messageSupplier, or wait are null.
*/
InsistCompletableFutureImpl(BiFunction<String, Throwable, X> throwableFunction,
String message,
Supplier<String> messageSupplier,
PatientWait wait) {
this.throwableFunction = validate().that(throwableFunction).isNotNull();
this.message = message;
this.messageSupplier = validate().that(messageSupplier).isNotNull();
this.wait = validate().that(wait).isNotNull();
this.timeout = wait.getDefaultTimeout();
}
Expand All @@ -87,7 +89,7 @@ public void thatEventually(BooleanSupplier supplier) throws X {
.get(timeout);
} catch (PatientTimeoutException exception) {
// Failure, throw requested throwable type
throw throwableFunction.apply(fail(message, exception.getAttemptsCount()), exception);
throw throwableFunction.apply(fail(messageSupplier, exception.getAttemptsCount()), exception);
}
}

Expand Down Expand Up @@ -115,12 +117,13 @@ public <T extends Throwable> T thatEventuallyThrows(Class<T> expectedThrowableCl
}).get(timeout);
} catch (PatientTimeoutException exception) {
// Failure, throw requested throwable type
throw throwableFunction.apply(fail(message, exception.getAttemptsCount()), exception);
throw throwableFunction.apply(fail(messageSupplier, exception.getAttemptsCount()), exception);
}
return caught;
}

private static String fail(String message, int numAttempts) {
private static String fail(Supplier<String> messageSupplier, int numAttempts) {
String message = messageSupplier.get();
if (null == message) {
return String.format(DEFAULT_FORMAT, numAttempts);
} else {
Expand Down
14 changes: 8 additions & 6 deletions src/main/java/com/redfin/insist/InsistVerifiableFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.time.Duration;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Supplier;

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

Expand Down Expand Up @@ -58,7 +59,8 @@ public final class InsistVerifiableFactory<X extends Throwable>
/**
* Create a new InsistVerifiableFactory instance with the given arguments.
*
* @param message the String message prefix for use upon validation failure.
* @param messageSupplier the {@link Supplier} of the String message prefix for use upon validation failure.
* May not be null.
* @param throwableFunction the function thatEventually takes in a message and cause and creates
* a throwable for failed validation.
* May not be null.
Expand All @@ -68,17 +70,17 @@ public final class InsistVerifiableFactory<X extends Throwable>
*
* @throws NullPointerException if throwableFunction or failedValidationExecutor are null.
*/
InsistVerifiableFactory(String message,
InsistVerifiableFactory(Supplier<String> messageSupplier,
BiFunction<String, Throwable, X> throwableFunction,
FailedValidationExecutor<X> failedValidationExecutor) {
super(message, failedValidationExecutor);
super(messageSupplier, failedValidationExecutor);
this.throwableFunction = Objects.requireNonNull(throwableFunction);
}

@Override
protected InsistVerifiableFactory<X> getFactory(String message,
protected InsistVerifiableFactory<X> getFactory(Supplier<String> messageSupplier,
FailedValidationExecutor<X> failedValidationExecutor) {
return new InsistVerifiableFactory<>(message,
return new InsistVerifiableFactory<>(messageSupplier,
throwableFunction,
failedValidationExecutor);
}
Expand All @@ -92,7 +94,7 @@ protected InsistVerifiableFactory<X> getFactory(String message,
*/
public InsistCompletableFuture<X> withWait(PatientWait wait) {
validate().that(wait).isNotNull();
return new InsistCompletableFutureImpl<>(throwableFunction, getMessage(), wait);
return new InsistCompletableFutureImpl<>(throwableFunction, getMessageSupplier(), wait);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

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

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

Expand Down Expand Up @@ -56,7 +57,7 @@ final class StackTrimmingFailedValidationExecutor<X extends Throwable>

/**
* Create a new instance of a {@link StackTrimmingFailedValidationExecutor} thatEventually
* will use the given throwableFunction when the {@link #fail(String, Object, String)}
* 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
Expand All @@ -71,11 +72,17 @@ final class StackTrimmingFailedValidationExecutor<X extends Throwable>
}

@Override
public <T> void fail(String expected, T subject, String message) throws X {
public <T> void fail(String expected,
T subject,
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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,24 +55,30 @@ default void testValidationExecutorIsNotNull() {
@Test
default void testValidationExecutorThrowsExpectedExceptionForNullExpected() {
Assertions.assertThrows(NullPointerException.class,
() -> getFailedValidationExecutor().fail(null, "subject", "message"));
() -> getFailedValidationExecutor().fail(null, "subject", () -> "message"));
}

@Test
default void testValidationExecutorThrowsExpectedExceptionForNullMessageSupplier() {
Assertions.assertThrows(NullPointerException.class,
() -> getFailedValidationExecutor().fail("expected", "subject", null));
}

@Test
default void testValidationExecutorThrowsExpectedExceptionForNullSubject() {
Assertions.assertThrows(getThrowableClass(),
() -> getFailedValidationExecutor().fail("expected", null, "message"));
() -> getFailedValidationExecutor().fail("expected", null, () -> "message"));
}

@Test
default void testValidationExecutorThrowsExpectedExceptionForNullMessage() {
Assertions.assertThrows(getThrowableClass(),
() -> getFailedValidationExecutor().fail("expected", "subject", null));
() -> getFailedValidationExecutor().fail("expected", "subject", () -> null));
}

@Test
default void testValidationExecutorThrowsExpectedExceptionWithValidArguments() {
Assertions.assertThrows(getThrowableClass(),
() -> getFailedValidationExecutor().fail("expected", "subject", "message"));
() -> getFailedValidationExecutor().fail("expected", "subject", () -> "message"));
}
}
31 changes: 25 additions & 6 deletions src/test/java/com/redfin/insist/InsistTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import java.util.function.Supplier;

final class InsistTest {

Expand All @@ -39,17 +40,18 @@ final class InsistTest {
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

@Test
void testInsistAssumeReturnsNonNullFactory() {
void testInsistAssumesReturnsNonNullFactory() {
Assertions.assertNotNull(Insist.assumes(),
"Insist.assumes() should return a non-null factory.");
}

@Test
void testInsistAssumeReturnsNullMessageFactory() throws Exception {
@SuppressWarnings("unchecked")
void testInsistAssumesReturnsNullMessageFactory() throws Exception {
AbstractVerifiableFactory<?, ?> factory = Insist.assumes();
Field field = factory.getClass().getSuperclass().getDeclaredField("message");
Field field = factory.getClass().getSuperclass().getDeclaredField("messageSupplier");
field.setAccessible(true);
Assertions.assertNull(field.get(factory),
Assertions.assertNull(((Supplier<String>) field.get(factory)).get(),
"Insist.assumes() should return a factory with a null message.");
}

Expand All @@ -60,14 +62,31 @@ void testInsistAssertsReturnsNonNullFactory() {
}

@Test
@SuppressWarnings("unchecked")
void testInsistAssertsReturnsNullMessageFactory() throws Exception {
AbstractVerifiableFactory<?, ?> factory = Insist.asserts();
Field field = factory.getClass().getSuperclass().getDeclaredField("message");
Field field = factory.getClass().getSuperclass().getDeclaredField("messageSupplier");
field.setAccessible(true);
Assertions.assertNull(field.get(factory),
Assertions.assertNull(((Supplier<String>) field.get(factory)).get(),
"Insist.asserts() should return a factory with a null message.");
}

@Test
void testInsistExpectsReturnsNonNullFactory() {
Assertions.assertNotNull(Insist.expects(),
"Insist.expects() should return a non-null factory.");
}

@Test
@SuppressWarnings("unchecked")
void testInsistExpectsReturnsNullMessageFactory() throws Exception {
AbstractVerifiableFactory<?, ?> factory = Insist.expects();
Field field = factory.getClass().getSuperclass().getDeclaredField("messageSupplier");
field.setAccessible(true);
Assertions.assertNull(((Supplier<String>) field.get(factory)).get(),
"Insist.expects() should return a factory with a null message.");
}

@Test
void testInsistIsMarkedAsFinal() {
Assertions.assertTrue(Modifier.isFinal(Insist.class.getModifiers()),
Expand Down
Loading

0 comments on commit 9ed6a7a

Please sign in to comment.