/*
* Copyright 2015-2017 the original author or authors.
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v1.0 which
* accompanies this distribution and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.junit.jupiter.api;
import static org.junit.jupiter.api.AssertionTestUtils.assertMessageContains;
import static org.junit.jupiter.api.AssertionTestUtils.expectAssertionFailedError;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
import java.io.IOException;
import java.net.URLClassLoader;
import org.opentest4j.AssertionFailedError;
/**
* Unit tests for JUnit Jupiter {@link Assertions}.
*
* @since 5.0
*/
class AssertionsAssertThrowsTests {
@Test
void assertThrowsThrowable() {
EnigmaThrowable enigmaThrowable = assertThrows(EnigmaThrowable.class, () -> {
throw new EnigmaThrowable();
});
assertNotNull(enigmaThrowable);
}
@Test
void assertThrowsCheckedException() {
IOException exception = assertThrows(IOException.class, () -> {
throw new IOException();
});
assertNotNull(exception);
}
@Test
void assertThrowsRuntimeException() {
IllegalStateException illegalStateException = assertThrows(IllegalStateException.class, () -> {
throw new IllegalStateException();
});
assertNotNull(illegalStateException);
}
@Test
void assertThrowsError() {
StackOverflowError stackOverflowError = assertThrows(StackOverflowError.class,
AssertionTestUtils::recurseIndefinitely);
assertNotNull(stackOverflowError);
}
@Test
void assertThrowsWithExecutableThatDoesNotThrowAnException() {
try {
assertThrows(IllegalStateException.class, () -> {
});
expectAssertionFailedError();
}
catch (AssertionFailedError ex) {
assertMessageContains(ex, "Expected java.lang.IllegalStateException to be thrown");
}
}
@Test
void assertThrowsWithExecutableThatThrowsAnUnexpectedException() {
try {
assertThrows(IllegalStateException.class, () -> {
throw new NumberFormatException();
});
expectAssertionFailedError();
}
catch (AssertionFailedError ex) {
assertMessageContains(ex, "Unexpected exception type thrown");
assertMessageContains(ex, "expected: <java.lang.IllegalStateException>");
assertMessageContains(ex, "but was: <java.lang.NumberFormatException>");
}
}
@Test
@SuppressWarnings("serial")
void assertThrowsWithExecutableThatThrowsInstanceOfAnonymousInnerClassAsUnexpectedException() {
try {
assertThrows(IllegalStateException.class, () -> {
throw new NumberFormatException() {
};
});
expectAssertionFailedError();
}
catch (AssertionFailedError ex) {
assertMessageContains(ex, "Unexpected exception type thrown");
assertMessageContains(ex, "expected: <java.lang.IllegalStateException>");
// As of the time of this writing, the class name of the above anonymous inner
// class is org.junit.jupiter.api.AssertionsAssertThrowsTests$2; however, hard
// coding "$2" is fragile. So we just check for the presence of the "$"
// appended to this class's name.
assertMessageContains(ex, "but was: <" + getClass().getName() + "$");
}
}
@Test
void assertThrowsWithExecutableThatThrowsInstanceOfStaticNestedClassAsUnexpectedException() {
try {
assertThrows(IllegalStateException.class, () -> {
throw new LocalException();
});
expectAssertionFailedError();
}
catch (AssertionFailedError ex) {
assertMessageContains(ex, "Unexpected exception type thrown");
assertMessageContains(ex, "expected: <java.lang.IllegalStateException>");
// The following verifies that the canonical name is used (i.e., "." instead of "$").
assertMessageContains(ex, "but was: <" + LocalException.class.getName().replace("$", ".") + ">");
}
}
@Test
@SuppressWarnings("unchecked")
void assertThrowsWithExecutableThatThrowsSameExceptionTypeFromDifferentClassLoader() throws Exception {
try (EnigmaClassLoader enigmaClassLoader = new EnigmaClassLoader()) {
// Load expected exception type from different class loader
Class<? extends Throwable> enigmaThrowableClass = (Class<? extends Throwable>) enigmaClassLoader.loadClass(
EnigmaThrowable.class.getName());
try {
assertThrows(enigmaThrowableClass, () -> {
throw new EnigmaThrowable();
});
expectAssertionFailedError();
}
catch (AssertionFailedError ex) {
// Example Output:
//
// Unexpected exception type thrown ==>
// expected: <org.junit.jupiter.api.EnigmaThrowable@5d3411d>
// but was: <org.junit.jupiter.api.EnigmaThrowable@2471cca7>
assertMessageContains(ex, "Unexpected exception type thrown");
// The presence of the "@" sign is sufficient to indicate that the hash was
// generated to disambiguate between the two identical class names.
assertMessageContains(ex, "expected: <org.junit.jupiter.api.EnigmaThrowable@");
assertMessageContains(ex, "but was: <org.junit.jupiter.api.EnigmaThrowable@");
}
}
}
@SuppressWarnings("serial")
private static class LocalException extends RuntimeException {
}
private static class EnigmaClassLoader extends URLClassLoader {
EnigmaClassLoader() {
super(getUrlClassLoader().getURLs());
}
private static URLClassLoader getUrlClassLoader() {
ClassLoader systemClassLoader = getSystemClassLoader();
assumeTrue(systemClassLoader instanceof URLClassLoader,
"aborting test since system ClassLoader is not a URLClassLoader");
return (URLClassLoader) systemClassLoader;
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
return (EnigmaThrowable.class.getName().equals(name) ? findClass(name) : super.loadClass(name));
}
}
}