Skip to content

Commit 80c29ca

Browse files
committed
chore: report HTML with fj-doc
1 parent 5495e8c commit 80c29ca

File tree

9 files changed

+298
-115
lines changed

9 files changed

+298
-115
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
6161
<maven-core-version>3.9.11</maven-core-version>
6262
<sonar.organization>fugerit-org</sonar.organization>
63-
<fj-doc-version>8.17.7</fj-doc-version>
63+
<fj-doc-version>8.17.8</fj-doc-version>
6464
</properties>
6565
<dependencyManagement>
6666
<dependencies>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package org.fugerit.java.junit5.tag.check.facade;
2+
3+
import org.fugerit.java.core.function.SafeFunction;
4+
import org.fugerit.java.doc.base.process.DocProcessContext;
5+
import org.fugerit.java.doc.freemarker.process.FreemarkerDocProcessConfig;
6+
import org.fugerit.java.doc.freemarker.process.FreemarkerDocProcessConfigFacade;
7+
import org.fugerit.java.junit5.tag.check.model.ReportHelper;
8+
9+
import java.io.OutputStream;
10+
11+
/**
12+
* DocHelper, version : auto generated on 2025-11-26 21:15:51.279
13+
*/
14+
public class DocHelper {
15+
16+
/*
17+
* FreemarkerDocProcessConfig is thread-safe and should be initialized once for each config file.
18+
*
19+
* Consider using a @ApplicationScoped or Singleton approach.
20+
*/
21+
private static final FreemarkerDocProcessConfig docProcessConfig = FreemarkerDocProcessConfigFacade
22+
.loadConfigSafe("cl://junit5-tag-check-maven-plugin/fm-doc-process-config.xml");
23+
24+
public static void generateReport(String handlerId, ReportHelper reportHelper, OutputStream os ) {
25+
SafeFunction.apply( () -> docProcessConfig.
26+
fullProcess( "report",
27+
DocProcessContext.newContext( "report", reportHelper )
28+
.withDocType( handlerId ), handlerId, os ) );
29+
}
30+
31+
32+
}

src/main/java/org/fugerit/java/junit5/tag/check/facade/TagReportFacade.java

Lines changed: 11 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,13 @@
66
import org.fugerit.java.core.xml.dom.DOMIO;
77
import org.fugerit.java.doc.base.config.DocConfig;
88
import org.fugerit.java.junit5.tag.check.model.ExecutedTest;
9+
import org.fugerit.java.junit5.tag.check.model.ReportHelper;
910
import org.fugerit.java.junit5.tag.check.model.ReportModel;
1011
import org.fugerit.java.junit5.tag.check.model.TestStats;
1112
import org.w3c.dom.Document;
1213
import org.w3c.dom.Element;
1314

14-
import java.io.File;
15-
import java.io.FileWriter;
16-
import java.io.IOException;
15+
import java.io.*;
1716
import java.util.*;
1817
import java.util.stream.Collectors;
1918

@@ -42,33 +41,23 @@ private void generateReport(Map<ExecutedTest, Set<String>> testTagMap)
4241
throws IOException {
4342
outputFile.getParentFile().mkdirs();
4443

45-
ReportModel model = this.toReportModel(testTagMap);
44+
ReportHelper helper = new ReportHelper( testTagMap );
45+
4646
switch (format.toLowerCase()) {
4747
case DocConfig.TYPE_JSON:
48-
generateJsonReport(model);
48+
generateJsonReport( helper.getReportModel() );
4949
break;
5050
case DocConfig.TYPE_XML:
51-
generateXmlReport(testTagMap);
51+
generateXmlReport( testTagMap );
5252
break;
53-
case "html":
54-
generateHtmlReport(testTagMap);
53+
case DocConfig.TYPE_HTML:
54+
generateHtmlReport( helper );
5555
break;
5656
default:
5757
generateTextReport(testTagMap);
5858
}
5959
}
6060

61-
private ReportModel toReportModel(Map<ExecutedTest, Set<String>> testTagMap) {
62-
ReportModel model = new ReportModel();
63-
for (Map.Entry<ExecutedTest, Set<String>> entry : testTagMap.entrySet()) {
64-
ExecutedTest current = entry.getKey();
65-
current.getTags().addAll(entry.getValue());
66-
model.getExecutedTests().add( current );
67-
}
68-
log.info( "report model, getExecutedTests().size() : {}", model.getExecutedTests().size() );
69-
return model;
70-
}
71-
7261
private void generateTextReport(Map<ExecutedTest, Set<String>> testTagMap)
7362
throws IOException {
7463
// Helper method for String.repeat(80)
@@ -201,85 +190,9 @@ private String repeatString(String s, int count) {
201190
return sb.toString();
202191
}
203192

204-
private void generateHtmlReport(Map<ExecutedTest, Set<String>> testTagMap)
205-
throws IOException {
206-
try (FileWriter writer = new FileWriter(outputFile)) {
207-
writer.write("<!DOCTYPE html>\n<html>\n<head>\n");
208-
writer.write("<meta charset=\"UTF-8\">\n");
209-
writer.write("<title>Executed Test Tag Report</title>\n");
210-
writer.write("<style>\n");
211-
writer.write("body { font-family: Arial, sans-serif; margin: 20px; }\n");
212-
writer.write("table { border-collapse: collapse; width: 100%; margin: 20px 0; }\n");
213-
writer.write("th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }\n");
214-
writer.write("th { background-color: #4CAF50; color: white; }\n");
215-
writer.write("tr:nth-child(even) { background-color: #f2f2f2; }\n");
216-
writer.write(".pass { color: green; }\n");
217-
writer.write(".fail { color: red; }\n");
218-
writer.write(".error { color: orange; }\n");
219-
writer.write(".skip { color: gray; }\n");
220-
writer.write(".tag { background-color: #e7f3ff; padding: 2px 8px; ");
221-
writer.write("border-radius: 3px; margin: 2px; display: inline-block; }\n");
222-
writer.write("</style>\n");
223-
writer.write("</head>\n<body>\n");
224-
writer.write("<h1>Executed Test Tag Report</h1>\n");
225-
226-
// Summary
227-
writer.write("<h2>Summary</h2>\n");
228-
writer.write("<table>\n");
229-
writer.write("<tr><th>Metric</th><th>Count</th></tr>\n");
230-
writer.write("<tr><td>Total Tests</td><td>" + testTagMap.size() + "</td></tr>\n");
231-
232-
long passed = testTagMap.keySet().stream()
233-
.filter(t -> !t.isFailed() && !t.isError()).count();
234-
long failed = testTagMap.keySet().stream().filter(ExecutedTest::isFailed).count();
235-
long errors = testTagMap.keySet().stream().filter(ExecutedTest::isError).count();
236-
237-
writer.write("<tr><td>Passed</td><td class='pass'>" + passed + "</td></tr>\n");
238-
writer.write("<tr><td>Failed</td><td class='fail'>" + failed + "</td></tr>\n");
239-
writer.write("<tr><td>Errors</td><td class='error'>" + errors + "</td></tr>\n");
240-
writer.write("</table>\n");
241-
242-
// Tags summary
243-
Map<String, List<ExecutedTest>> tagToTests = new HashMap<>();
244-
for (Map.Entry<ExecutedTest, Set<String>> entry : testTagMap.entrySet()) {
245-
for (String tag : entry.getValue()) {
246-
tagToTests.computeIfAbsent(tag, k -> new ArrayList<>()).add(entry.getKey());
247-
}
248-
}
249-
250-
writer.write("<h2>Tags Summary</h2>\n");
251-
writer.write("<table>\n");
252-
writer.write("<tr><th>Tag</th><th>Tests</th></tr>\n");
253-
for (Map.Entry<String, List<ExecutedTest>> entry : tagToTests.entrySet()) {
254-
writer.write("<tr><td>" + entry.getKey() + "</td><td>" +
255-
entry.getValue().size() + "</td></tr>\n");
256-
}
257-
writer.write("</table>\n");
258-
259-
// All tests
260-
writer.write("<h2>All Executed Tests</h2>\n");
261-
writer.write("<table>\n");
262-
writer.write("<tr><th>Status</th><th>Test</th><th>Tags</th><th>Time</th></tr>\n");
263-
for (Map.Entry<ExecutedTest, Set<String>> entry : testTagMap.entrySet()) {
264-
ExecutedTest test = entry.getKey();
265-
String statusClass = test.isFailed() ? "fail" :
266-
test.isError() ? "error" : "pass";
267-
String status = getStatusIcon(test);
268-
269-
writer.write("<tr>");
270-
writer.write("<td class='" + statusClass + "'>" + status + "</td>");
271-
writer.write("<td>" + test.getClassName() + "#" + test.getMethodName() + "</td>");
272-
writer.write("<td>");
273-
for (String tag : entry.getValue()) {
274-
writer.write("<span class='tag'>" + tag + "</span> ");
275-
}
276-
writer.write("</td>");
277-
writer.write("<td>" + test.getTime() + "s</td>");
278-
writer.write("</tr>\n");
279-
}
280-
writer.write("</table>\n");
281-
282-
writer.write("</body>\n</html>");
193+
private void generateHtmlReport(ReportHelper reportHelper) throws IOException {
194+
try (OutputStream os = new FileOutputStream(outputFile)) {
195+
DocHelper.generateReport( DocConfig.TYPE_HTML, reportHelper, os );
283196
}
284197
}
285198

@@ -325,18 +238,4 @@ private String getStatusIcon(ExecutedTest test) {
325238
return "✅";
326239
}
327240

328-
private String escapeJson(String str) {
329-
return str.replace("\\", "\\\\")
330-
.replace("\"", "\\\"")
331-
.replace("\n", "\\n");
332-
}
333-
334-
private String escapeXml(String str) {
335-
return str.replace("&", "&amp;")
336-
.replace("<", "&lt;")
337-
.replace(">", "&gt;")
338-
.replace("\"", "&quot;")
339-
.replace("'", "&apos;");
340-
}
341-
342241
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package org.fugerit.java.junit5.tag.check.model;
2+
3+
import lombok.extern.slf4j.Slf4j;
4+
5+
import java.util.*;
6+
7+
@Slf4j
8+
public class ReportHelper {
9+
10+
private Map<ExecutedTest, Set<String>> testTagMap;
11+
12+
private ReportModel reportModel;
13+
14+
public ReportHelper(Map<ExecutedTest, Set<String>> testTagMap) {
15+
this.testTagMap = testTagMap;
16+
this.reportModel = new ReportModel();
17+
for (Map.Entry<ExecutedTest, Set<String>> entry : this.getTestTagMap().entrySet()) {
18+
ExecutedTest current = entry.getKey();
19+
current.getTags().addAll(entry.getValue());
20+
reportModel.getExecutedTests().add( current );
21+
}
22+
}
23+
24+
public Map<ExecutedTest, Set<String>> getTestTagMap() {
25+
return this.testTagMap;
26+
}
27+
28+
public ReportModel getReportModel() {
29+
return this.reportModel;
30+
}
31+
32+
public long getSummaryPass() {
33+
return this.getTestTagMap().keySet().stream().filter(t -> !t.isFailed() && !t.isError()).count();
34+
}
35+
36+
public long getSummaryFail() {
37+
return this.getTestTagMap().keySet().stream().filter(ExecutedTest::isFailed).count();
38+
}
39+
40+
public long getSummaryError() {
41+
return this.getTestTagMap().keySet().stream().filter(ExecutedTest::isError).count();
42+
}
43+
44+
public Map<String, List<ExecutedTest>> getTagsSummary() {
45+
Map<String, List<ExecutedTest>> tagToTests = new LinkedHashMap<>();
46+
for (Map.Entry<ExecutedTest, Set<String>> entry : this.getTestTagMap().entrySet()) {
47+
for (String tag : entry.getValue()) {
48+
tagToTests.computeIfAbsent(tag, k -> new ArrayList<>()).add(entry.getKey());
49+
}
50+
}
51+
log.debug( "getTagsSummary() : {}", tagToTests );
52+
return tagToTests;
53+
}
54+
55+
}

src/main/java/org/fugerit/java/junit5/tag/check/model/ReportModel.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,6 @@ public List<ExecutedTest> getExecutedTests() {
1515
return this.executedTests;
1616
}
1717

18+
19+
1820
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!-- generated from template 'fm-doc-process-config-template.ftl' on 2025-11-26T21:15:51.247+01:00 -->
3+
<freemarker-doc-process-config
4+
xmlns="https://freemarkerdocprocess.fugerit.org"
5+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
6+
xsi:schemaLocation="https://freemarkerdocprocess.fugerit.org https://www.fugerit.org/data/java/doc/xsd/freemarker-doc-process-1-0.xsd" >
7+
8+
<!--
9+
Documentation :
10+
https://venusdocs.fugerit.org/guide/
11+
12+
Configuration reference :
13+
https://venusdocs.fugerit.org/fj-doc-freemarker/src/main/docs/fdp_xsd_config_ref.html
14+
-->
15+
16+
<docHandlerConfig registerById="true">
17+
18+
<!-- Type handler for markdown format -->
19+
<docHandler id="md-ext" info="md" type="org.fugerit.java.doc.base.typehandler.markdown.SimpleMarkdownExtTypeHandler" />
20+
<!-- Type handler for xml format, generates the source xml:doc -->
21+
<docHandler id="xml-doc" info="xml" type="org.fugerit.java.doc.base.typehandler.core.DocTypeHandlerCoreXMLUTF8" />
22+
<!-- Type handler for JSON format, generates the source json:doc -->
23+
<docHandler id="json-doc" info="json" type="org.fugerit.java.doc.json.typehandler.DocTypeHandlerCoreJSONUTF8" />
24+
<!-- Type handler for html using freemarker -->
25+
<docHandler id="html-fm" info="html" type="org.fugerit.java.doc.freemarker.html.FreeMarkerHtmlTypeHandlerEscapeUTF8" />
26+
<!-- Type handler for html using freemarker (fragment version, only generates body content no html or head part -->
27+
<docHandler id="html-fragment-fm" info="fhtml" type="org.fugerit.java.doc.freemarker.html.FreeMarkerHtmlFragmentTypeHandlerEscapeUTF8" />
28+
<!-- type handler for asciidoc using freemarker -->
29+
<docHandler id="asciidoc-fm" info="adoc" type="org.fugerit.java.doc.freemarker.asciidoc.FreeMarkerAsciidocTypeHandlerUTF8" />
30+
<!-- Type handler generating xls:fo style sheet -->
31+
<docHandler id="fo-fop" info="fo" type="org.fugerit.java.doc.mod.fop.FreeMarkerFopTypeHandlerUTF8" />
32+
<!-- Type handler generating pdf -->
33+
<docHandler id="pdf-fop" info="pdf" type="org.fugerit.java.doc.mod.fop.PdfFopTypeHandler">
34+
<docHandlerCustomConfig charset="UTF-8" fop-config-mode="classloader" fop-config-classloader-path="junit5-tag-check-maven-plugin/fop-config.xml" fop-suppress-events="1"/>
35+
</docHandler>
36+
</docHandlerConfig>
37+
38+
<docChain id="shared">
39+
<chainStep stepType="config">
40+
<config
41+
id="fj_doc_config_fm_junit5tagcheckmavenplugin"
42+
class="org.fugerit.java.junit5.tag.check.facade.DocHelper"
43+
exception-handler="RETHROW_HANDLER"
44+
fallback-on-null-loop-variable="false"
45+
log-exception="false"
46+
mode="class"
47+
path="/junit5-tag-check-maven-plugin/template/"
48+
version="2.3.34"
49+
wrap-unchecked-exceptions="true"
50+
load-bundled-functions="true"
51+
/>
52+
</chainStep>
53+
</docChain>
54+
55+
<!-- example document chain xml -->
56+
<docChain id="report" parent="shared">
57+
<chainStep stepType="complex" map-all="true" template-path="${chainId}.ftl"/>
58+
</docChain>
59+
60+
</freemarker-doc-process-config>
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<fop version="1.0">
2+
3+
<!-- Strict user configuration -->
4+
<strict-configuration>true</strict-configuration>
5+
6+
<!-- Strict FO validation -->
7+
<strict-validation>true</strict-validation>
8+
9+
<!-- Base URL for resolving relative URLs -->
10+
<base>.</base>
11+
12+
<!-- Font Base URL for resolving relative font URLs -->
13+
<font-base>.</font-base>
14+
15+
<renderers>
16+
<renderer mime="application/pdf">
17+
<version>1.4</version>
18+
</renderer>
19+
</renderers>
20+
21+
22+
<!-- Source resolution in dpi (dots/pixels per inch) for determining the size of pixels in SVG and bitmap images, default: 72dpi -->
23+
<source-resolution>72</source-resolution>
24+
<!-- Target resolution in dpi (dots/pixels per inch) for specifying the target resolution for generated bitmaps, default: 72dpi -->
25+
<target-resolution>72</target-resolution>
26+
27+
<!-- default page-height and page-width, in case
28+
value is specified as auto -->
29+
<default-page-settings height="11in" width="8.26in"/>
30+
31+
</fop>

0 commit comments

Comments
 (0)