1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package dev.aherscu.qa.jgiven.reporter;
18
19 import static dev.aherscu.qa.testing.utils.StringUtilsExtensions.*;
20 import static java.lang.Double.*;
21 import static java.lang.Long.*;
22 import static java.text.MessageFormat.format;
23 import static java.time.format.DateTimeFormatter.*;
24
25 import java.io.*;
26 import java.nio.charset.*;
27 import java.time.*;
28 import java.util.*;
29 import java.util.Base64;
30
31 import org.apache.commons.codec.binary.*;
32 import org.apache.commons.io.output.*;
33
34 import com.samskivert.mustache.*;
35 import com.tngtech.jgiven.report.model.*;
36
37 import dev.aherscu.qa.testing.utils.*;
38 import lombok.*;
39 import lombok.experimental.*;
40 import lombok.extern.slf4j.*;
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64 @SuperBuilder(toBuilder = true)
65 @Slf4j
66 @SuppressWarnings("ClassWithTooManyFields")
67 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
68 value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD",
69 justification = "referenced from JMustache template at runtime")
70 public class QaJGivenReportModel<T> {
71 public final String screenshotScale;
72 public final String testDocumentId;
73 public final String testDocumentRev;
74 public final String specDocumentId;
75 public final String specDocumentRev;
76 public final String planDocumentId;
77 public final String planDocumentRev;
78 public final String traceabilityDocumentId;
79 public final String traceabilityDocumentRev;
80 public final String productName;
81 public final String productVersion;
82 public final T jgivenReport;
83 public final String datePattern;
84 public final File targetReportFile;
85
86 public final Mustache.Lambda shorten =
87 (frag, out) -> out.write(abbreviateMiddle(prettified(frag.execute()),
88 ELLIPSIS, 1024));
89
90 public final Mustache.Lambda deleteEOL =
91 (frag, out) -> out.write(normalizeSpace(frag.execute()
92 .replaceAll("[\\r\\n]", SPACE)));
93
94 public final Mustache.Lambda nanoToMillis =
95 (frag, out) -> out.write(Long
96 .toString(parseLong(frag.execute()) / 1_000_000));
97
98 public final Mustache.Lambda asId =
99 (frag, out) -> out.write(Integer
100 .toHexString(frag.execute().hashCode())
101 .toUpperCase(Locale.ENGLISH));
102
103 public final Mustache.Lambda simpleName =
104 (frag, out) -> out.write(substringAfterLast(frag.execute(), DOT));
105
106 public final Mustache.Lambda translateIntroWord =
107 this::translateIntroWord;
108
109 public final Mustache.Lambda scaleImage =
110 this::scaleImage;
111
112 public final Mustache.Lambda isStepFailed =
113 (frag, out) -> out.write(
114 StepStatus.FAILED.equals(((StepModel) frag.context()).getStatus())
115 ? frag.execute()
116 : EMPTY);
117
118 public final Mustache.Lambda isStepPassed =
119 (frag, out) -> out.write(
120 StepStatus.PASSED.equals(((StepModel) frag.context()).getStatus())
121 ? frag.execute()
122 : EMPTY);
123
124 private final ZonedDateTime date =
125 ZonedDateTime.now();
126
127 public final String date() {
128 return date.format(ofPattern(datePattern));
129 }
130
131 @SuppressWarnings("resource")
132 public void scaleImage(
133 final Template.Fragment frag,
134 final Writer out) {
135 ImageUtils.Pipeline
136 .from(new ByteArrayInputStream(Base64
137 .getMimeDecoder()
138 .decode(frag.execute().getBytes(StandardCharsets.UTF_8))))
139 .scale(parseDouble(screenshotScale), parseDouble(screenshotScale))
140
141 .into(new Base64OutputStream(
142 new WriterOutputStream(out, StandardCharsets.UTF_8),
143 true, -1, null),
144 "png");
145 }
146
147 @SneakyThrows
148 private void translateIntroWord(
149 final Template.Fragment frag,
150 final Writer out) {
151
152 val introWord = frag.execute().toLowerCase(Locale.US);
153 switch (introWord) {
154 case "given":
155 out.write("Pre-condition(s)");
156 break;
157 case "when":
158 out.write("Operation(s)");
159 break;
160 case "then":
161 out.write("Verification(s)");
162 break;
163 case "and":
164 case "with":
165 out.write("and");
166 break;
167 default:
168 log.warn(format("unrecognized introduction word [{0}]",
169 introWord));
170 }
171 }
172 }