/*
* 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.vintage.engine.execution;
import java.util.Optional;
import java.util.function.Function;
import org.junit.Ignore;
import org.junit.platform.engine.EngineExecutionListener;
import org.junit.platform.engine.TestDescriptor;
import org.junit.platform.engine.TestExecutionResult;
import org.junit.runner.Description;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunListener;
import org.junit.vintage.engine.descriptor.RunnerTestDescriptor;
/**
* @since 4.12
*/
class RunListenerAdapter extends RunListener {
private final TestRun testRun;
private final EngineExecutionListener listener;
RunListenerAdapter(TestRun testRun, EngineExecutionListener listener) {
this.testRun = testRun;
this.listener = listener;
}
@Override
public void testRunStarted(Description description) {
// If it's not a suite it might be skipped entirely later on.
if (description.isSuite()) {
fireExecutionStarted(testRun.getRunnerTestDescriptor());
}
}
@Override
public void testIgnored(Description description) {
testRun.lookupTestDescriptor(description).ifPresent(
testDescriptor -> testIgnored(testDescriptor, determineReasonForIgnoredTest(description)));
}
@Override
public void testStarted(Description description) {
testRun.lookupTestDescriptor(description).ifPresent(this::testStarted);
}
@Override
public void testAssumptionFailure(Failure failure) {
handleFailure(failure, TestExecutionResult::aborted);
}
@Override
public void testFailure(Failure failure) {
handleFailure(failure, TestExecutionResult::failed);
}
@Override
public void testFinished(Description description) {
testRun.lookupTestDescriptor(description).ifPresent(this::testFinished);
}
@Override
public void testRunFinished(Result result) {
RunnerTestDescriptor runnerTestDescriptor = testRun.getRunnerTestDescriptor();
if (testRun.isNotSkipped(runnerTestDescriptor)) {
if (testRun.isNotStarted(runnerTestDescriptor)) {
fireExecutionStarted(runnerTestDescriptor);
}
fireExecutionFinished(runnerTestDescriptor);
}
}
private void handleFailure(Failure failure, Function<Throwable, TestExecutionResult> resultCreator) {
testRun.lookupTestDescriptor(failure.getDescription()).ifPresent(
testDescriptor -> handleFailure(failure, resultCreator, testDescriptor));
}
private void handleFailure(Failure failure, Function<Throwable, TestExecutionResult> resultCreator,
TestDescriptor testDescriptor) {
TestExecutionResult result = resultCreator.apply(failure.getException());
testRun.storeResult(testDescriptor, result);
if (testDescriptor.isContainer() && testRun.isDescendantOfRunnerTestDescriptor(testDescriptor)) {
fireMissingContainerEvents(testDescriptor);
}
}
private void fireMissingContainerEvents(TestDescriptor testDescriptor) {
if (testRun.isNotStarted(testDescriptor)) {
testStarted(testDescriptor);
}
if (testRun.isNotFinished(testDescriptor)) {
testFinished(testDescriptor);
}
}
private void testIgnored(TestDescriptor testDescriptor, String reason) {
fireExecutionStartedIncludingUnstartedAncestors(testDescriptor.getParent());
fireExecutionSkipped(testDescriptor, reason);
fireExecutionFinishedIncludingAncestorsWithoutPendingChildren(testDescriptor.getParent());
}
private String determineReasonForIgnoredTest(Description description) {
Ignore ignoreAnnotation = description.getAnnotation(Ignore.class);
return Optional.ofNullable(ignoreAnnotation).map(Ignore::value).orElse("<unknown>");
}
private void testStarted(TestDescriptor testDescriptor) {
fireExecutionStartedIncludingUnstartedAncestors(testDescriptor.getParent());
fireExecutionStarted(testDescriptor);
}
private void testFinished(TestDescriptor descriptor) {
fireExecutionFinished(descriptor);
fireExecutionFinishedIncludingAncestorsWithoutPendingChildren(descriptor.getParent());
}
private void fireExecutionStartedIncludingUnstartedAncestors(Optional<TestDescriptor> parent) {
if (parent.isPresent() && canStart(parent.get())) {
fireExecutionStartedIncludingUnstartedAncestors(parent.get().getParent());
fireExecutionStarted(parent.get());
}
}
private void fireExecutionFinishedIncludingAncestorsWithoutPendingChildren(Optional<TestDescriptor> parent) {
if (parent.isPresent() && canFinish(parent.get())) {
fireExecutionFinished(parent.get());
fireExecutionFinishedIncludingAncestorsWithoutPendingChildren(parent.get().getParent());
}
}
private boolean canStart(TestDescriptor testDescriptor) {
return testRun.isNotStarted(testDescriptor) //
&& testRun.isDescendantOfRunnerTestDescriptor(testDescriptor);
}
private boolean canFinish(TestDescriptor testDescriptor) {
return testRun.isNotFinished(testDescriptor) //
&& testRun.isDescendantOfRunnerTestDescriptor(testDescriptor)
&& testRun.areAllFinishedOrSkipped(testDescriptor.getChildren());
}
private void fireExecutionSkipped(TestDescriptor testDescriptor, String reason) {
testRun.markSkipped(testDescriptor);
listener.executionSkipped(testDescriptor, reason);
}
private void fireExecutionStarted(TestDescriptor testDescriptor) {
testRun.markStarted(testDescriptor);
listener.executionStarted(testDescriptor);
}
private void fireExecutionFinished(TestDescriptor testDescriptor) {
testRun.markFinished(testDescriptor);
listener.executionFinished(testDescriptor, testRun.getStoredResultOrSuccessful(testDescriptor));
}
}