/* * 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.platform.launcher.listeners; import static java.util.stream.Collectors.joining; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.concurrent.atomic.AtomicLong; import org.junit.platform.launcher.TestIdentifier; import org.junit.platform.launcher.TestPlan; /** * Mutable, internal implementation of the {@link TestExecutionSummary} API. * * @since 1.0 */ class MutableTestExecutionSummary implements TestExecutionSummary { private static final String TAB = " "; private static final String DOUBLE_TAB = TAB + TAB; final AtomicLong containersFound = new AtomicLong(); final AtomicLong containersStarted = new AtomicLong(); final AtomicLong containersSkipped = new AtomicLong(); final AtomicLong containersAborted = new AtomicLong(); final AtomicLong containersSucceeded = new AtomicLong(); final AtomicLong containersFailed = new AtomicLong(); final AtomicLong testsFound = new AtomicLong(); final AtomicLong testsStarted = new AtomicLong(); final AtomicLong testsSkipped = new AtomicLong(); final AtomicLong testsAborted = new AtomicLong(); final AtomicLong testsSucceeded = new AtomicLong(); final AtomicLong testsFailed = new AtomicLong(); private final TestPlan testPlan; private final List<Failure> failures = new ArrayList<>(); private final long timeStarted; long timeFinished; MutableTestExecutionSummary(TestPlan testPlan) { this.testPlan = testPlan; this.containersFound.set(testPlan.countTestIdentifiers(TestIdentifier::isContainer)); this.testsFound.set(testPlan.countTestIdentifiers(TestIdentifier::isTest)); this.timeStarted = System.currentTimeMillis(); } void addFailure(TestIdentifier testIdentifier, Throwable throwable) { this.failures.add(new DefaultFailure(testIdentifier, throwable)); } @Override public long getTimeStarted() { return this.timeStarted; } @Override public long getTimeFinished() { return this.timeFinished; } @Override public long getTotalFailureCount() { return getTestsFailedCount() + getContainersFailedCount(); } @Override public long getContainersFoundCount() { return this.containersFound.get(); } @Override public long getContainersStartedCount() { return this.containersStarted.get(); } @Override public long getContainersSkippedCount() { return this.containersSkipped.get(); } @Override public long getContainersAbortedCount() { return this.containersAborted.get(); } @Override public long getContainersSucceededCount() { return this.containersSucceeded.get(); } @Override public long getContainersFailedCount() { return this.containersFailed.get(); } @Override public long getTestsFoundCount() { return this.testsFound.get(); } @Override public long getTestsStartedCount() { return this.testsStarted.get(); } @Override public long getTestsSkippedCount() { return this.testsSkipped.get(); } @Override public long getTestsAbortedCount() { return this.testsAborted.get(); } @Override public long getTestsSucceededCount() { return this.testsSucceeded.get(); } @Override public long getTestsFailedCount() { return this.testsFailed.get(); } @Override public void printTo(PrintWriter writer) { // @formatter:off writer.println(String.format( "%nTest run finished after %d ms%n" + "[%10d containers found ]%n" + "[%10d containers skipped ]%n" + "[%10d containers started ]%n" + "[%10d containers aborted ]%n" + "[%10d containers successful ]%n" + "[%10d containers failed ]%n" + "[%10d tests found ]%n" + "[%10d tests skipped ]%n" + "[%10d tests started ]%n" + "[%10d tests aborted ]%n" + "[%10d tests successful ]%n" + "[%10d tests failed ]%n", (this.timeFinished - this.timeStarted), getContainersFoundCount(), getContainersSkippedCount(), getContainersStartedCount(), getContainersAbortedCount(), getContainersSucceededCount(), getContainersFailedCount(), getTestsFoundCount(), getTestsSkippedCount(), getTestsStartedCount(), getTestsAbortedCount(), getTestsSucceededCount(), getTestsFailedCount() )); // @formatter:on writer.flush(); } @Override public void printFailuresTo(PrintWriter writer) { if (getTotalFailureCount() > 0) { writer.println(); writer.println(String.format("Failures (%d):", getTotalFailureCount())); this.failures.forEach(failure -> { writer.println(TAB + describeTest(failure.getTestIdentifier())); failure.getTestIdentifier().getSource().ifPresent(source -> writer.println(DOUBLE_TAB + source)); writer.println(String.format("%s=> %s", DOUBLE_TAB, failure.getException())); }); writer.flush(); } } @Override public List<Failure> getFailures() { return Collections.unmodifiableList(failures); } private String describeTest(TestIdentifier testIdentifier) { List<String> descriptionParts = new ArrayList<>(); collectTestDescription(Optional.of(testIdentifier), descriptionParts); return descriptionParts.stream().collect(joining(":")); } private void collectTestDescription(Optional<TestIdentifier> optionalIdentifier, List<String> descriptionParts) { optionalIdentifier.ifPresent(testIdentifier -> { descriptionParts.add(0, testIdentifier.getDisplayName()); collectTestDescription(this.testPlan.getParent(testIdentifier), descriptionParts); }); } private static class DefaultFailure implements Failure { private final TestIdentifier testIdentifier; private final Throwable exception; DefaultFailure(TestIdentifier testIdentifier, Throwable exception) { this.testIdentifier = testIdentifier; this.exception = exception; } @Override public TestIdentifier getTestIdentifier() { return testIdentifier; } @Override public Throwable getException() { return exception; } } }