Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #9 - Printing Nested Tests Accordingly #10

Merged
merged 16 commits into from
Jun 27, 2022
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,18 @@
<version>${maven.surefire.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>4.6.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>4.6.1</version>
<scope>test</scope>
</dependency>
</dependencies>

<licenses>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@
import org.apache.maven.surefire.api.report.TestSetReportEntry;
import org.apache.maven.surefire.shared.utils.logging.MessageBuilder;

import java.util.List;
import java.util.*;
import java.util.stream.LongStream;

import static java.util.stream.Collectors.toList;
import static org.apache.maven.plugin.surefire.report.TestSetStats.concatenateWithTestGroup;
import static org.apache.maven.surefire.shared.utils.StringUtils.isBlank;
import static org.apache.maven.surefire.shared.utils.logging.MessageUtils.buffer;
Expand All @@ -34,76 +36,132 @@
*
* @author <a href="mailto:fabriciorby@hotmail.com">Fabrício Yamamoto</a>
*/
public class ConsoleTreeReporter extends ConsoleReporter
{
private static final String TEST_SET_STARTING_PREFIX = "+-- ";
public class ConsoleTreeReporter extends ConsoleReporter {

private static final int $ = 36;
private static final Tokens tokens = Tokens.ASCII;

private final Map<String, TestSetReportEntry> testBuffer = new HashMap<>();

public ConsoleTreeReporter(ConsoleLogger logger,
boolean usePhrasedClassNameInRunning, boolean usePhrasedClassNameInTestCaseSummary )
{
super( logger, usePhrasedClassNameInRunning, usePhrasedClassNameInTestCaseSummary );
boolean usePhrasedClassNameInRunning, boolean usePhrasedClassNameInTestCaseSummary) {
super(logger, usePhrasedClassNameInRunning, usePhrasedClassNameInTestCaseSummary);
}

@Override
public void testSetStarting( TestSetReportEntry report )
{
getConsoleLogger()
.info( "|" );
public void testSetStarting(TestSetReportEntry report) {
testBuffer.put(report.getSourceName(), report);
}

MessageBuilder builder = buffer().a( TEST_SET_STARTING_PREFIX );
@Override
public void testSetCompleted(WrappedReportEntry report, TestSetStats testSetStats, List<String> testResults) {
List<String> sourceNames = getSourceNames(testSetStats);
for (WrappedReportEntry testResult : testSetStats.getReportEntries()) {
MessageBuilder builder = createMessageBuilderWithPrefix(testResult, sourceNames);
if (testResult.isErrorOrFailure()) {
printFailure(testResult, builder);
} else if (testResult.isSkipped()) {
printSkipped(testResult, builder);
} else if (testResult.isSucceeded()) {
printSuccess(testResult, builder);
}
}
}

String runningTestCase =
concatenateWithTestGroup( builder, report, !isBlank( report.getReportNameWithGroup() ) );
private List<String> getSourceNames(TestSetStats testSetStats) {
return testSetStats.getReportEntries()
.stream()
.map(WrappedReportEntry::getSourceName)
.collect(toList());
}

getConsoleLogger()
.info( runningTestCase );
private void printSuccess(WrappedReportEntry testResult, MessageBuilder builder) {
println(builder.success(tokens.successful() + testResult.getReportName())
.a(" - " + testResult.elapsedTimeAsString() + "s")
.toString());
}

@Override
public void testSetCompleted( WrappedReportEntry report, TestSetStats testSetStats, List<String> testResults )
{

for ( WrappedReportEntry testResult : testSetStats.getReportEntries() )
{
final MessageBuilder builder = buffer().a( "| " + TEST_SET_STARTING_PREFIX );
if ( testResult.isErrorOrFailure() )
{
println( builder.failure( "[XX] " + testResult.getReportName() )
.a( " - " + testResult.elapsedTimeAsString() + "s" )
.toString());
private void printSkipped(WrappedReportEntry testResult, MessageBuilder builder) {
if (!isBlank(testResult.getReportName())) {
builder.warning(tokens.skipped() + testResult.getReportName());
} else {
builder.warning(tokens.skipped() + testResult.getReportSourceName());
}
if (!isBlank(testResult.getMessage())) {
builder.warning(" (" + testResult.getMessage() + ")");
}
println(builder
.a(" - " + testResult.elapsedTimeAsString() + "s")
.toString());
}

private void printFailure(WrappedReportEntry testResult, MessageBuilder builder) {
println(builder.failure(tokens.failed() + testResult.getReportName())
.a(" - " + testResult.elapsedTimeAsString() + "s")
.toString());
}

private MessageBuilder createMessageBuilderWithPrefix(WrappedReportEntry testResult, List<String> sourceNames) {
if(testBuffer.containsKey(testResult.getSourceName())) {
printClassPrefix(testResult, sourceNames);
testBuffer.remove(testResult.getSourceName());
}
return printTestPrefix(testResult, sourceNames);
}

private MessageBuilder printTestPrefix(WrappedReportEntry testResult, List<String> sourceNames) {
MessageBuilder builder = buffer().a(tokens.pipe());
if (getTreeLength(testResult) > 0) {
LongStream.rangeClosed(0, getTreeLength(testResult) - 2)
.forEach(i -> builder.a(tokens.blank()));
if (sourceNames.stream().distinct().count() > 1) {
builder.a(tokens.pipe());
} else {
builder.a(tokens.blank());
}
else if ( testResult.isSkipped() )
{
if ( !isBlank( testResult.getReportName() ) )
{
builder.warning( "[??] " + testResult.getReportName() );
}
else
{
builder.warning( "[??] " + testResult.getReportSourceName() );
}

if ( !isBlank( testResult.getMessage() ) )
{
builder.warning( " (" + testResult.getMessage() + ")" );
}

println( builder
.a( " - " + testResult.elapsedTimeAsString() + "s" )
.toString());
}
sourceNames.remove(testResult.getSourceName());
if (sourceNames.contains(testResult.getSourceName())) {
builder.a(tokens.entry());
} else {
builder.a(tokens.end());
}
return builder;
}

private void printClassPrefix(WrappedReportEntry testResult, List<String> sourceNames) {
MessageBuilder builder = buffer();
if (getTreeLength(testResult) > 0) {
if (getTreeLength(testResult) > 1) {
builder.a(tokens.pipe());
LongStream.rangeClosed(0, getTreeLength(testResult) - 3)
.forEach(i -> builder.a(tokens.blank()));
builder.a(tokens.end());
} else {
builder.a(tokens.entry());
}
else if ( testResult.isSucceeded() )
{
println( builder.success( "[OK] " + testResult.getReportName() )
.a( " - " + testResult.elapsedTimeAsString() + "s" )
.toString());
if (sourceNames.stream().distinct().count() > 1) {
builder.a(tokens.down());
} else {
builder.a(tokens.dash());
}
} else {
builder.a(tokens.entry());
}
String runningTestCase =
concatenateWithTestGroup(builder, testResult, !isBlank(testResult.getReportNameWithGroup()));
println(runningTestCase);
}

private long getTreeLength(TestSetReportEntry entry) {
return entry.getSourceName()
.chars()
.filter(c -> c == $)
.count();
}

private void println(String message) {
this.getConsoleLogger().info(message);
this.getConsoleLogger().info(message);
}

}
113 changes: 113 additions & 0 deletions src/main/java/org/apache/maven/plugin/surefire/report/Tokens.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package org.apache.maven.plugin.surefire.report;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

//Thanks to https://github.com/junit-team/junit5/blob/main/junit-platform-console/src/main/java/org/junit/platform/console/options/Theme.java

public enum Tokens {

/**
* ASCII 7-bit characters form the tree branch.
*
* <p>Example test plan execution tree:
* <pre class="code">
* [INFO] +--Nested Sample
* [INFO] | +-- [OK] Should pass - 0.03s
* [INFO] | '-- [OK] Should pass2 - 0.002s
* [INFO] +--,--Inner Test
* [INFO] | | '-- [OK] Inner test should pass - 0.001s
* [INFO] | '--,--Inner Inner Test
* [INFO] | | '-- [OK] Inner Inner Test should pass - 0.002s
* [INFO] | '-----Inner Inner Inner Test
* [INFO] | '-- [OK] Inner Inner Inner Test should pass - 0.002s
* [INFO] +--My main test class
* [INFO] | +-- [OK] Should pass - 0.001s
* [INFO] | +-- [OK] Should pass again - 0.001s
* [INFO] | +-- [OK] Should pass for the 3rd time - 0.001s
* [INFO] | '-- [OK] Should pass for the 4th time - 0s
* </pre>
*/
ASCII("| ", "+--", "'--", ",--", "---", " [OK] ", " [XX] ", " [??] "),

/**
* Unicode (extended ASCII) characters are used to display the test execution tree.
*
* <p>Example test plan execution tree:
* <pre class="code">
* [INFO] ├─ Nested Sample
* [INFO] │ ├─ ✔ Should pass - 0.013s
* [INFO] │ └─ ✔ Should pass2 - 0.001s
* [INFO] ├─ ┬─ Inner Test
* [INFO] │ │ └─ ✔ Inner test should pass - 0.001s
* [INFO] │ └─ ┬─ Inner Inner Test
* [INFO] │ │ └─ ✔ Inner Inner Test should pass - 0.001s
* [INFO] │ └─ ── Inner Inner Inner Test
* [INFO] │ └─ ✔ Inner Inner Inner Test should pass - 0s
* [INFO] ├─ My main test class
* [INFO] │ ├─ ✔ Should pass - 0.001s
* [INFO] │ ├─ ✔ Should pass again - 0.001s
* [INFO] │ ├─ ✔ Should pass for the 3rd time - 0s
* [INFO] │ └─ ✔ Should pass for the 4th time - 0s
* </pre>
*/
UNICODE("│ ", "├─ ", "└─ ", "┬─ ", "── ", "✔ ", "✘ ", "↷ ");

public static Tokens valueOf(Charset charset) {
if (StandardCharsets.UTF_8.equals(charset)) {
return UNICODE;
}
return ASCII;
}

private final String[] tiles;
fabriciorby marked this conversation as resolved.
Show resolved Hide resolved

Tokens(String... tiles) {
this.tiles = tiles;
}

public final String blank() {
return " ";
}

public final String pipe() {
return tiles[0];
}

public final String entry() {
return tiles[1];
}

public final String end() {
return tiles[2];
}

public final String down() {
return tiles[3];
}

public final String dash() {
return tiles[4];
}

public final String successful() {
return tiles[5];
}

public final String failed() {
return tiles[6];
}

public final String skipped() {
return tiles[7];
}

/**
* Return lower case {@link #name()} for easier usage in help text for
* available options.
*/
@Override
public final String toString() {
return name().toLowerCase();
}
}
5 changes: 5 additions & 0 deletions src/test/java/NestedExampleTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,9 @@ void test() {

}

@Test
@DisplayName("Should pass2")
void test2() {
}

}
Loading