/*
* 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.engine.extension;
import static org.assertj.core.api.Assertions.allOf;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectMethod;
import static org.junit.platform.engine.test.event.ExecutionEventConditions.assertRecordedExecutionEventsContainsExactly;
import static org.junit.platform.engine.test.event.ExecutionEventConditions.container;
import static org.junit.platform.engine.test.event.ExecutionEventConditions.engine;
import static org.junit.platform.engine.test.event.ExecutionEventConditions.event;
import static org.junit.platform.engine.test.event.ExecutionEventConditions.finishedSuccessfully;
import static org.junit.platform.engine.test.event.ExecutionEventConditions.finishedWithFailure;
import static org.junit.platform.engine.test.event.ExecutionEventConditions.started;
import static org.junit.platform.engine.test.event.ExecutionEventConditions.test;
import static org.junit.platform.engine.test.event.TestExecutionResultConditions.isA;
import static org.junit.platform.engine.test.event.TestExecutionResultConditions.message;
import static org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder.request;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.TestExecutionExceptionHandler;
import org.junit.jupiter.api.extension.TestExtensionContext;
import org.junit.jupiter.engine.AbstractJupiterTestEngineTests;
import org.junit.platform.engine.test.event.ExecutionEventRecorder;
import org.junit.platform.launcher.LauncherDiscoveryRequest;
/**
* Integration tests that verify support for {@link TestExecutionExceptionHandler}.
*
* @since 5.0
*/
class TestExecutionExceptionHandlerTests extends AbstractJupiterTestEngineTests {
static List<String> handlerCalls = new ArrayList<>();
@BeforeEach
void resetStatics() {
handlerCalls.clear();
RethrowException.handleExceptionCalled = false;
ConvertException.handleExceptionCalled = false;
SwallowException.handleExceptionCalled = false;
ShouldNotBeCalled.handleExceptionCalled = false;
}
@Test
void exceptionHandlerRethrowsException() {
LauncherDiscoveryRequest request = request().selectors(selectMethod(ATestCase.class, "testRethrow")).build();
ExecutionEventRecorder eventRecorder = executeTests(request);
assertTrue(RethrowException.handleExceptionCalled, "TestExecutionExceptionHandler should have been called");
assertRecordedExecutionEventsContainsExactly(eventRecorder.getExecutionEvents(), //
event(engine(), started()), //
event(container(ATestCase.class), started()), //
event(test("testRethrow"), started()), //
event(test("testRethrow"), finishedWithFailure(allOf(isA(IOException.class), message("checked")))), //
event(container(ATestCase.class), finishedSuccessfully()), //
event(engine(), finishedSuccessfully()));
}
@Test
void exceptionHandlerSwallowsException() {
LauncherDiscoveryRequest request = request().selectors(selectMethod(ATestCase.class, "testSwallow")).build();
ExecutionEventRecorder eventRecorder = executeTests(request);
assertTrue(SwallowException.handleExceptionCalled, "TestExecutionExceptionHandler should have been called");
assertRecordedExecutionEventsContainsExactly(eventRecorder.getExecutionEvents(), //
event(engine(), started()), //
event(container(ATestCase.class), started()), //
event(test("testSwallow"), started()), //
event(test("testSwallow"), finishedSuccessfully()), //
event(container(ATestCase.class), finishedSuccessfully()), //
event(engine(), finishedSuccessfully()));
}
@Test
void exceptionHandlerConvertsException() {
LauncherDiscoveryRequest request = request().selectors(selectMethod(ATestCase.class, "testConvert")).build();
ExecutionEventRecorder eventRecorder = executeTests(request);
assertTrue(ConvertException.handleExceptionCalled, "TestExecutionExceptionHandler should have been called");
assertRecordedExecutionEventsContainsExactly(eventRecorder.getExecutionEvents(), //
event(engine(), started()), //
event(container(ATestCase.class), started()), //
event(test("testConvert"), started()), //
event(test("testConvert"), finishedWithFailure(allOf(isA(IOException.class), message("checked")))), //
event(container(ATestCase.class), finishedSuccessfully()), //
event(engine(), finishedSuccessfully()));
}
@Test
void severalHandlersAreCalledInOrder() {
LauncherDiscoveryRequest request = request().selectors(selectMethod(ATestCase.class, "testSeveral")).build();
ExecutionEventRecorder eventRecorder = executeTests(request);
assertTrue(ConvertException.handleExceptionCalled, "ConvertException should have been called");
assertTrue(RethrowException.handleExceptionCalled, "RethrowException should have been called");
assertTrue(SwallowException.handleExceptionCalled, "SwallowException should have been called");
assertFalse(ShouldNotBeCalled.handleExceptionCalled, "ShouldNotBeCalled should not have been called");
assertRecordedExecutionEventsContainsExactly(eventRecorder.getExecutionEvents(), //
event(engine(), started()), //
event(container(ATestCase.class), started()), //
event(test("testSeveral"), started()), //
event(test("testSeveral"), finishedSuccessfully()), //
event(container(ATestCase.class), finishedSuccessfully()), //
event(engine(), finishedSuccessfully()));
assertEquals(Arrays.asList("convert", "rethrow", "swallow"), handlerCalls);
}
// -------------------------------------------------------------------
private static class ATestCase {
@Test
@ExtendWith(RethrowException.class)
void testRethrow() throws IOException {
throw new IOException("checked");
}
@Test
@ExtendWith(SwallowException.class)
void testSwallow() throws IOException {
throw new IOException("checked");
}
@Test
@ExtendWith(ConvertException.class)
void testConvert() {
throw new RuntimeException("unchecked");
}
@Test
@ExtendWith(ShouldNotBeCalled.class)
@ExtendWith(SwallowException.class)
@ExtendWith(RethrowException.class)
@ExtendWith(ConvertException.class)
void testSeveral() {
throw new RuntimeException("unchecked");
}
}
private static class RethrowException implements TestExecutionExceptionHandler {
static boolean handleExceptionCalled = false;
@Override
public void handleTestExecutionException(TestExtensionContext context, Throwable throwable) throws Throwable {
assertTrue(throwable instanceof IOException);
handleExceptionCalled = true;
handlerCalls.add("rethrow");
throw throwable;
}
}
private static class SwallowException implements TestExecutionExceptionHandler {
static boolean handleExceptionCalled = false;
@Override
public void handleTestExecutionException(TestExtensionContext context, Throwable throwable) throws Throwable {
assertTrue(throwable instanceof IOException);
handleExceptionCalled = true;
handlerCalls.add("swallow");
//swallow exception by not rethrowing it
}
}
private static class ConvertException implements TestExecutionExceptionHandler {
static boolean handleExceptionCalled = false;
@Override
public void handleTestExecutionException(TestExtensionContext context, Throwable throwable) throws Throwable {
assertTrue(throwable instanceof RuntimeException);
handleExceptionCalled = true;
handlerCalls.add("convert");
throw new IOException("checked");
}
}
private static class ShouldNotBeCalled implements TestExecutionExceptionHandler {
static boolean handleExceptionCalled = false;
@Override
public void handleTestExecutionException(TestExtensionContext context, Throwable throwable) throws Throwable {
handleExceptionCalled = true;
}
}
}