Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@

import java.io.IOException;
import java.security.PrivilegedExceptionAction;
import java.util.Collection;
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
Expand Down Expand Up @@ -383,7 +382,7 @@ public static <T, E extends Throwable> E intercept(
Callable<T> eval)
throws Exception {
return intercept(clazz,
(String) null,
null,
"Expected a " + clazz.getName() + " to be thrown," +
" but got the result: ",
eval);
Expand Down Expand Up @@ -509,61 +508,6 @@ public static <T, E extends Throwable> E intercept(
return ex;
}

/**
* Intercept an exception; throw an {@code AssertionError} if one not raised.
* The caught exception is rethrown if it is of the wrong class or
* does not contain the text defined in {@code contained}.
* <p>
* Example: expect deleting a nonexistent file to raise a
* {@code FileNotFoundException} with the {@code toString()} value
* containing the text {@code "missing"}.
* <pre>
* FileNotFoundException ioe = intercept(FileNotFoundException.class,
* "missing",
* "path should not be found",
* () -> {
* filesystem.delete(new Path("/missing"), false);
* });
* </pre>
*
* @param clazz class of exception; the raised exception must be this class
* <i>or a subclass</i>.
* @param contains strings which must be in the {@code toString()} value
* of the exception (order does not matter)
* @param message any message tho include in exception/log messages
* @param eval expression to eval
* @param <T> return type of expression
* @param <E> exception class
* @return the caught exception if it was of the expected type and contents
* @throws Exception any other exception raised
* @throws AssertionError if the evaluation call didn't raise an exception.
* The error includes the {@code toString()} value of the result, if this
* can be determined.
* @see GenericTestUtils#assertExceptionContains(String, Throwable)
*/
public static <T, E extends Throwable> E intercept(
Copy link
Contributor

Choose a reason for hiding this comment

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

I do think this is a good feature, it's just we need to give it a name which doesn't run any risk of causing compilation problems.

alternatively, in GenericTestUtils add a new method assertExceptionContainsAllStrings() taking a varargs list of strings.

Class<E> clazz,
Collection<String> contains,
String message,
Callable<T> eval)
throws Exception {
E ex;
try {
T result = eval.call();
throw new AssertionError(message + ": " + robustToString(result));
} catch (Throwable e) {
if (!clazz.isAssignableFrom(e.getClass())) {
throw e;
} else {
ex = (E) e;
}
}
for (String contained : contains) {
GenericTestUtils.assertExceptionContains(contained, ex, message);
}
return ex;
}

/**
* Variant of {@link #intercept(Class, Callable)} to simplify void
* invocations.
Expand Down Expand Up @@ -592,34 +536,6 @@ public static <E extends Throwable> E intercept(
});
}

/**
* Variant of {@link #intercept(Class, Callable)} to simplify void
* invocations.
* @param clazz class of exception; the raised exception must be this class
* <i>or a subclass</i>.
* @param contains string which must be in the {@code toString()} value
* of the exception (order does not matter)
* @param eval expression to eval
* @param <E> exception class
* @return the caught exception if it was of the expected type
* @throws Exception any other exception raised
* @throws AssertionError if the evaluation call didn't raise an exception.
*/
public static <E extends Throwable> E intercept(
Class<E> clazz,
Collection<String> contains,
VoidCallable eval)
throws Exception {
return intercept(clazz, contains,
"Expecting " + clazz.getName()
+ (contains.isEmpty() ? "" : (" with text values " + toString(contains)))
+ " but got ",
() -> {
eval.call();
return "void";
});
}

/**
* Variant of {@link #intercept(Class, Callable)} to simplify void
* invocations.
Expand Down Expand Up @@ -691,6 +607,7 @@ public static <T> void assertOptionalEquals(String message,
* Assert that an optional value matches an expected one;
* checks include null and empty on the actual value.
* @param message message text
* @param expected expected value
* @param actual actual optional value
* @param <T> type
*/
Expand Down Expand Up @@ -724,6 +641,7 @@ public static <T> T eval(Callable<T> closure) {
* Invoke a callable; wrap all checked exceptions with an
* AssertionError.
* @param closure closure to execute
* @return the value of the closure
* @throws AssertionError if the operation raised an IOE or
* other checked exception.
*/
Expand Down Expand Up @@ -887,19 +805,6 @@ public static <T, E extends Throwable> E interceptFuture(
});
}

private static String toString(Collection<String> strings) {
StringBuilder sb = new StringBuilder();
sb.append('[');
int pos = 0;
for (String s : strings) {
if (pos++ > 0)
sb.append(", ");
sb.append(s);
}
sb.append(']');
return sb.toString();
}

/**
* Verify that the cause of an exception is of the given type.
* @param <E> exception class
Expand Down Expand Up @@ -1132,3 +1037,4 @@ public Void run() throws Exception {
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,8 @@
import java.net.HttpURLConnection;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class TestHttpExceptionUtils {

Expand Down Expand Up @@ -87,18 +84,16 @@ public void testCreateJerseyException() throws IOException {
@Test
public void testValidateResponseOK() throws IOException {
HttpURLConnection conn = Mockito.mock(HttpURLConnection.class);
Mockito.when(conn.getResponseCode()).thenReturn(
HttpURLConnection.HTTP_CREATED);
Mockito.when(conn.getResponseCode()).thenReturn(HttpURLConnection.HTTP_CREATED);
HttpExceptionUtils.validateResponse(conn, HttpURLConnection.HTTP_CREATED);
}

@Test
public void testValidateResponseFailNoErrorMessage() throws Exception {
HttpURLConnection conn = Mockito.mock(HttpURLConnection.class);
Mockito.when(conn.getResponseCode()).thenReturn(
HttpURLConnection.HTTP_BAD_REQUEST);
Mockito.when(conn.getResponseCode()).thenReturn(HttpURLConnection.HTTP_BAD_REQUEST);
LambdaTestUtils.intercept(IOException.class,
() -> HttpExceptionUtils.validateResponse(conn, HttpURLConnection.HTTP_CREATED));
() -> HttpExceptionUtils.validateResponse(conn, HttpURLConnection.HTTP_CREATED));
}

@Test
Expand All @@ -108,14 +103,12 @@ public void testValidateResponseNonJsonErrorMessage() throws Exception {
HttpURLConnection conn = Mockito.mock(HttpURLConnection.class);
Mockito.when(conn.getErrorStream()).thenReturn(is);
Mockito.when(conn.getResponseMessage()).thenReturn("msg");
Mockito.when(conn.getResponseCode()).thenReturn(
HttpURLConnection.HTTP_BAD_REQUEST);
Collection<String> expectedValues =
Stream.of(Integer.toString(HttpURLConnection.HTTP_BAD_REQUEST), "msg", "com.fasterxml.jackson.core.JsonParseException")
.collect(Collectors.toList());
LambdaTestUtils.intercept(IOException.class,
expectedValues,
() -> HttpExceptionUtils.validateResponse(conn, HttpURLConnection.HTTP_CREATED));
Mockito.when(conn.getResponseCode()).thenReturn(HttpURLConnection.HTTP_BAD_REQUEST);
IOException ex = LambdaTestUtils.intercept(IOException.class,
() -> HttpExceptionUtils.validateResponse(conn, HttpURLConnection.HTTP_CREATED));
assertContains(Integer.toString(HttpURLConnection.HTTP_BAD_REQUEST), ex.getMessage());
assertContains("msg", ex.getMessage());
assertContains("com.fasterxml.jackson.core.JsonParseException", ex.getMessage());
}

@Test
Expand All @@ -132,11 +125,10 @@ public void testValidateResponseJsonErrorKnownException() throws Exception {
HttpURLConnection conn = Mockito.mock(HttpURLConnection.class);
Mockito.when(conn.getErrorStream()).thenReturn(is);
Mockito.when(conn.getResponseMessage()).thenReturn("msg");
Mockito.when(conn.getResponseCode()).thenReturn(
HttpURLConnection.HTTP_BAD_REQUEST);
Mockito.when(conn.getResponseCode()).thenReturn(HttpURLConnection.HTTP_BAD_REQUEST);
LambdaTestUtils.intercept(IllegalStateException.class,
"EX",
() -> HttpExceptionUtils.validateResponse(conn, HttpURLConnection.HTTP_CREATED));
"EX",
() -> HttpExceptionUtils.validateResponse(conn, HttpURLConnection.HTTP_CREATED));
}

@Test
Expand All @@ -154,14 +146,12 @@ public void testValidateResponseJsonErrorUnknownException()
HttpURLConnection conn = Mockito.mock(HttpURLConnection.class);
Mockito.when(conn.getErrorStream()).thenReturn(is);
Mockito.when(conn.getResponseMessage()).thenReturn("msg");
Mockito.when(conn.getResponseCode()).thenReturn(
HttpURLConnection.HTTP_BAD_REQUEST);
Collection<String> expectedValues =
Stream.of(Integer.toString(HttpURLConnection.HTTP_BAD_REQUEST), "foo.FooException", "EX")
.collect(Collectors.toList());
LambdaTestUtils.intercept(IOException.class,
expectedValues,
() -> HttpExceptionUtils.validateResponse(conn, HttpURLConnection.HTTP_CREATED));
Mockito.when(conn.getResponseCode()).thenReturn(HttpURLConnection.HTTP_BAD_REQUEST);
IOException ex = LambdaTestUtils.intercept(IOException.class,
() -> HttpExceptionUtils.validateResponse(conn, HttpURLConnection.HTTP_CREATED));
assertContains(Integer.toString(HttpURLConnection.HTTP_BAD_REQUEST), ex.getMessage());
assertContains("foo.FooException", ex.getMessage());
assertContains("EX", ex.getMessage());
}

@Test
Expand All @@ -179,14 +169,17 @@ public void testValidateResponseJsonErrorNonException() throws Exception {
HttpURLConnection conn = Mockito.mock(HttpURLConnection.class);
Mockito.when(conn.getErrorStream()).thenReturn(is);
Mockito.when(conn.getResponseMessage()).thenReturn("msg");
Mockito.when(conn.getResponseCode()).thenReturn(
HttpURLConnection.HTTP_BAD_REQUEST);
Collection<String> expectedValues =
Stream.of(Integer.toString(HttpURLConnection.HTTP_BAD_REQUEST), "java.lang.String", "EX")
.collect(Collectors.toList());
LambdaTestUtils.intercept(IOException.class,
expectedValues,
() -> HttpExceptionUtils.validateResponse(conn, HttpURLConnection.HTTP_CREATED));
Mockito.when(conn.getResponseCode()).thenReturn(HttpURLConnection.HTTP_BAD_REQUEST);
IOException ex = LambdaTestUtils.intercept(IOException.class,
() -> HttpExceptionUtils.validateResponse(conn, HttpURLConnection.HTTP_CREATED));
assertContains(Integer.toString(HttpURLConnection.HTTP_BAD_REQUEST), ex.getMessage());
assertContains("java.lang.String", ex.getMessage());
assertContains("EX", ex.getMessage());
}

private static void assertContains(String expected, String actual) {
Assert.assertTrue("Expected: " + expected + ", Actual: " + actual,
actual.contains(expected));
}

}