Skip to content

Commit ab9b17a

Browse files
authored
Print the tests while traversing an actual tree (#63)
Improvements in the unit tests to copy maven surefire behaviour Improvements in printing the name of the classes and timings Improvements in making the tree printer a bit nicer for nested classes Improvements in the SurefireEmulator Fixes #62 Fixes #46
1 parent 49d7f5d commit ab9b17a

File tree

12 files changed

+626
-48
lines changed

12 files changed

+626
-48
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,14 @@ The output can be printed using two Themes: UNICODE and ASCII (by default).
5959
```
6060
![Imgur](https://i.imgur.com/FzcIWwe.png "ASCII Output")
6161

62+
## Blank line between tests
63+
```xml
64+
<statelessTestsetInfoReporter
65+
implementation="org.apache.maven.plugin.surefire.extensions.junit5.JUnit5StatelessTestsetInfoTreeReporter">
66+
<printBlankLineBetweenTests>true</printBlankLineBetweenTests>
67+
</statelessTestsetInfoReporter>
68+
```
69+
6270

6371
## Reduce verbosity
6472

pom.xml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>me.fabriciorby</groupId>
88
<artifactId>maven-surefire-junit5-tree-reporter</artifactId>
9-
<version>1.4.0</version>
9+
<version>1.5.0-SNAPSHOT</version>
1010
<packaging>jar</packaging>
1111

1212
<name>maven-surefire-junit5-tree-reporter</name>
@@ -160,6 +160,7 @@
160160
</consoleOutputReporter>
161161
<statelessTestsetInfoReporter
162162
implementation="${maven-surefire.testsetInfoReporter}">
163+
<printBlankLineBetweenTests>true</printBlankLineBetweenTests>
163164
<theme>UNICODE</theme>
164165
</statelessTestsetInfoReporter>
165166
</configuration>
@@ -216,6 +217,7 @@
216217
<goal>sign</goal>
217218
</goals>
218219
<configuration>
220+
<skip>true</skip>
219221
<gpgArguments>
220222
<arg>--pinentry-mode</arg>
221223
<arg>loopback</arg>

src/main/java/org/apache/maven/plugin/surefire/extensions/junit5/JUnit5StatelessTestsetInfoTreeReporter.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public class JUnit5StatelessTestsetInfoTreeReporter extends JUnit5StatelessTests
2626
private boolean printStdoutOnFailure;
2727
private boolean printStdoutOnSuccess;
2828
private boolean hideResultsOnSuccess;
29+
private boolean printBlankLineBetweenTests;
2930
private Theme theme = Theme.ASCII;
3031

3132
@Override
@@ -104,6 +105,10 @@ public boolean isHideResultsOnSuccess() {
104105
return hideResultsOnSuccess;
105106
}
106107

108+
public boolean isPrintBlankLineBetweenTests() {
109+
return printBlankLineBetweenTests;
110+
}
111+
107112
public void setPrintStacktraceOnError(boolean printStacktraceOnError) {
108113
this.printStacktraceOnError = printStacktraceOnError;
109114
}
@@ -140,6 +145,10 @@ public void setHideResultsOnSuccess(boolean hideResultsOnSuccess) {
140145
this.hideResultsOnSuccess = hideResultsOnSuccess;
141146
}
142147

148+
public void setPrintBlankLineBetweenTests(boolean printBlankLineBetweenTests) {
149+
this.printBlankLineBetweenTests = printBlankLineBetweenTests;
150+
}
151+
143152
public void setTheme(Theme theme) {
144153
this.theme = theme;
145154
}
@@ -167,7 +176,9 @@ private ReporterOptions newReporterOptions() {
167176
.hideResultsOnSuccess(isHideResultsOnSuccess())
168177
.usePhrasedClassNameInRunning(isUsePhrasedClassNameInRunning())
169178
.usePhrasedClassNameInTestCaseSummary(isUsePhrasedClassNameInTestCaseSummary())
179+
.printBlankLineBetweenTests(isPrintBlankLineBetweenTests())
170180
.theme(getTheme())
171181
.build();
172182
}
183+
173184
}
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
package org.apache.maven.plugin.surefire.report;
2+
3+
import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
4+
import org.apache.maven.surefire.shared.lang3.StringUtils;
5+
import org.apache.maven.surefire.shared.utils.logging.MessageBuilder;
6+
7+
import java.io.IOException;
8+
import java.util.List;
9+
import java.util.stream.LongStream;
10+
11+
import static org.apache.maven.plugin.surefire.report.TextFormatter.abbreviateName;
12+
import static org.apache.maven.surefire.shared.utils.StringUtils.isBlank;
13+
import static org.apache.maven.surefire.shared.utils.logging.MessageUtils.buffer;
14+
15+
public class ActualTreePrinter {
16+
private final Theme theme = Theme.UNICODE;
17+
private final Node tree;
18+
private final ConsoleLogger consoleLogger;
19+
private final ReporterOptions options;
20+
21+
public ActualTreePrinter(Node node, ConsoleLogger consoleLogger, ReporterOptions options) {
22+
this.tree = node;
23+
this.consoleLogger = consoleLogger;
24+
this.options = options;
25+
}
26+
27+
public void print() {
28+
if (options.isPrintBlankLineBetweenTests()) println("");
29+
print(tree.branches.get(0));
30+
Node.clearTree();
31+
}
32+
33+
private void print(Node node) {
34+
printClass(node);
35+
node.wrappedReportEntries.forEach(i -> printTestFormated(node, i));
36+
node.branches.forEach(this::print);
37+
}
38+
39+
private void printTestFormated(Node node, WrappedReportEntry testResult) {
40+
if (testResult.isErrorOrFailure()) {
41+
printFailure(node, testResult);
42+
} else if (testResult.isSkipped()) {
43+
printSkipped(node, testResult);
44+
} else if (isSuccessPrintAllowed() && testResult.isSucceeded()) {
45+
printSuccess(node, testResult);
46+
}
47+
printDetails(testResult);
48+
}
49+
50+
private boolean isSuccessPrintAllowed() {
51+
return !options.isHideResultsOnSuccess();
52+
}
53+
54+
private void printSuccess(Node node, WrappedReportEntry testResult) {
55+
printTestResult(buffer().success(theme.successful() + abbreviateName(testResult.getReportName())), node, testResult);
56+
}
57+
58+
private void printTestResult(MessageBuilder builder, Node node, WrappedReportEntry testResult) {
59+
println(getTestPrefix(node, testResult)
60+
.a(builder)
61+
.a(" - " + testResult.elapsedTimeAsString())
62+
.toString());
63+
}
64+
65+
private void println(String message) {
66+
consoleLogger.info(message);
67+
}
68+
69+
private boolean isLastMissingBranch(Node node) {
70+
Node rootChild = tree.branches.get(0); // first after ROOT
71+
if (rootChild.hasBranches()) {
72+
Node rootChildLastChild = getLastItem(rootChild.branches); // last branch in root child
73+
return node.getParent(rootChildLastChild.getName()).isPresent() || node == rootChildLastChild;
74+
} else {
75+
return true;
76+
}
77+
}
78+
79+
private static <T> T getLastItem(List<T> list) {
80+
return list.get(list.size() - 1);
81+
}
82+
83+
private MessageBuilder getTestPrefix(Node node, WrappedReportEntry testResult) {
84+
MessageBuilder builder = buffer();
85+
if (isLastMissingBranch(node))
86+
builder.a(theme.blank());
87+
else
88+
builder.a(theme.pipe());
89+
if (node.getDepth() > 1) {
90+
LongStream.rangeClosed(0, node.getDepth() - 3)
91+
.forEach(i -> builder.a(theme.blank()));
92+
if (node.getParent().hasBranches() && node.hasBranches()
93+
) {
94+
builder.a(theme.pipe());
95+
} else {
96+
builder.a(theme.blank());
97+
}
98+
}
99+
if (isLastTestToBeEval(node, testResult)) {
100+
builder.a(theme.entry());
101+
} else {
102+
builder.a(theme.end());
103+
}
104+
return builder;
105+
}
106+
107+
private static boolean isLastTestToBeEval(Node node, WrappedReportEntry testResult) {
108+
return node.wrappedReportEntries.indexOf(testResult) + 1 != node.wrappedReportEntries.size();
109+
}
110+
111+
private void printClass(Node node) {
112+
MessageBuilder builder = buffer();
113+
if (node.getDepth() > 1) {
114+
if (node.getDepth() > 2) {
115+
if (isLastMissingBranch(node)) builder.a(theme.blank());
116+
else builder.a(theme.pipe());
117+
LongStream.rangeClosed(0, node.getDepth() - 4)
118+
.forEach(i -> builder.a(theme.blank()));
119+
builder.a(theme.end());
120+
} else {
121+
if (isLastMissingBranch(node)) builder.a(theme.end());
122+
else builder.a(theme.entry());
123+
}
124+
}
125+
if (node.hasBranches()) {
126+
builder.a(theme.down());
127+
} else {
128+
builder.a(theme.dash());
129+
}
130+
131+
builder.strong(cleanReportName(node));
132+
builder.a(" - " + node.getClassReportEntry().elapsedTimeAsString());
133+
134+
println(builder.toString());
135+
}
136+
137+
private String cleanReportName(Node node) {
138+
if (node.getParent().getClassReportEntry() != null) {
139+
int stringSizeToRemove = node.getParent().getClassReportEntry().getReportNameWithGroup().length() + 1;
140+
return node.getClassReportEntry().getReportNameWithGroup().substring(stringSizeToRemove);
141+
} else {
142+
return node.getClassReportEntry().getReportNameWithGroup();
143+
}
144+
}
145+
146+
private void printDetails(WrappedReportEntry testResult) {
147+
boolean isSuccess = testResult.getReportEntryType() == ReportEntryType.SUCCESS;
148+
boolean isError = testResult.getReportEntryType() == ReportEntryType.ERROR;
149+
boolean isFailure = testResult.getReportEntryType() == ReportEntryType.FAILURE;
150+
151+
boolean printStackTrace = options.isPrintStacktraceOnError() && isError
152+
|| options.isPrintStacktraceOnFailure() && isFailure;
153+
boolean printStdOut = options.isPrintStdoutOnSuccess() && isSuccess
154+
|| options.isPrintStdoutOnError() && isError
155+
|| options.isPrintStdoutOnFailure() && isFailure;
156+
boolean printStdErr = options.isPrintStderrOnSuccess() && isSuccess
157+
|| options.isPrintStderrOnError() && isError
158+
|| options.isPrintStderrOnFailure() && isFailure;
159+
160+
if (printStackTrace || printStdOut || printStdErr) {
161+
printPreambleDetails(testResult);
162+
if (printStackTrace) printStackTrace(testResult);
163+
if (printStdOut) printStdOut(testResult);
164+
if (printStdErr) printStdErr(testResult);
165+
}
166+
}
167+
168+
private void printSkipped(Node node, WrappedReportEntry testResult) {
169+
printTestResult(buffer()
170+
.warning(theme.skipped() + getSkippedReport(testResult))
171+
.warning(getSkippedMessage(testResult)), node, testResult);
172+
}
173+
174+
private String getSkippedReport(WrappedReportEntry testResult) {
175+
if (!isBlank(testResult.getReportName())) {
176+
return abbreviateName(testResult.getReportName());
177+
} else {
178+
return testResult.getReportSourceName();
179+
}
180+
}
181+
182+
private String getSkippedMessage(WrappedReportEntry testResult) {
183+
if (!isBlank(testResult.getMessage())) {
184+
return " (" + testResult.getMessage() + ")";
185+
} else {
186+
return "";
187+
}
188+
}
189+
190+
private void printPreambleDetails(WrappedReportEntry testResult) {
191+
if (testResult.isSucceeded()) {
192+
println(buffer().success(theme.details()).success(abbreviateName(testResult.getReportName())).toString());
193+
} else {
194+
println(buffer().failure(theme.details()).failure(abbreviateName(testResult.getReportName())).toString());
195+
}
196+
}
197+
198+
private void printStdOut(WrappedReportEntry testResult) {
199+
println("");
200+
println(buffer().strong("Standard out").toString());
201+
try {
202+
testResult.getStdout().writeTo(System.out);
203+
} catch (final IOException ignored) {
204+
}
205+
}
206+
207+
private void printStdErr(WrappedReportEntry testResult) {
208+
println("");
209+
println(buffer().strong("Standard error").toString());
210+
try {
211+
testResult.getStdErr().writeTo(System.err);
212+
} catch (final IOException ignored) {
213+
}
214+
}
215+
216+
private void printStackTrace(WrappedReportEntry testResult) {
217+
println("");
218+
println(buffer().strong("Stack trace").toString());
219+
String stackTrace = testResult.getStackTrace(false);
220+
if (stackTrace != null && !StringUtils.isBlank(stackTrace)) {
221+
println(testResult.getStackTrace(false));
222+
} else {
223+
println("[No stack trace available]");
224+
}
225+
}
226+
227+
private void printFailure(Node node, WrappedReportEntry testResult) {
228+
printTestResult(buffer()
229+
.failure(theme.failed() + abbreviateName(testResult.getReportName())), node, testResult);
230+
}
231+
}

0 commit comments

Comments
 (0)