1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.htmlunit.junit;
16
17 import static java.nio.charset.StandardCharsets.UTF_8;
18
19 import java.io.File;
20 import java.io.IOException;
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.Collections;
24 import java.util.HashSet;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.Locale;
28 import java.util.Set;
29
30 import org.apache.commons.io.FileUtils;
31 import org.apache.commons.text.StringEscapeUtils;
32 import org.htmlunit.BrowserVersion;
33 import org.htmlunit.CodeStyleTest;
34 import org.htmlunit.general.HostExtractor;
35 import org.junit.ComparisonFailure;
36 import org.junit.runners.model.FrameworkMethod;
37
38
39
40
41
42
43
44
45 final class TestCaseCorrector {
46
47 private TestCaseCorrector() {
48 }
49
50 static void correct(final FrameworkMethod method, final boolean realBrowser, final BrowserVersion browserVersion,
51 final boolean notYetImplemented, final Throwable t) throws IOException {
52 final String testRoot = "src/test/java/";
53 String browserString = browserVersion.getNickname().toUpperCase(Locale.ROOT);
54 browserString = browserString.replace('-', '_');
55
56 final File file = new File(testRoot + method.getDeclaringClass().getName().replace('.', '/') + ".java");
57 final List<String> lines = FileUtils.readLines(file, UTF_8);
58 final String methodLine = " public void " + method.getName() + "()";
59 if (realBrowser) {
60 String defaultExpectation = null;
61 for (int i = 0; i < lines.size(); i++) {
62 if (" @Default".equals(lines.get(i))) {
63 defaultExpectation = getDefaultExpectation(lines, i);
64 }
65 if (lines.get(i).startsWith(methodLine)) {
66 i = addExpectation(lines, i, browserString, (ComparisonFailure) t);
67 break;
68 }
69 if (i == lines.size() - 2) {
70 addMethodWithExpectation(lines, i, browserString, method.getName(), (ComparisonFailure) t,
71 defaultExpectation);
72 break;
73 }
74 }
75 }
76 else if (!notYetImplemented) {
77 String defaultExpectation = null;
78 for (int i = 0; i < lines.size(); i++) {
79 if (" @Default".equals(lines.get(i))) {
80 defaultExpectation = getDefaultExpectation(lines, i);
81 }
82 if (lines.get(i).startsWith(methodLine)) {
83 addNotYetImplemented(lines, i, browserString);
84 break;
85 }
86 if (i == lines.size() - 2) {
87 addNotYetImplementedMethod(lines, i, browserString, method.getName(), defaultExpectation);
88 break;
89 }
90 }
91 }
92 else {
93 for (int i = 0; i < lines.size(); i++) {
94 if (lines.get(i).startsWith(methodLine)) {
95 removeNotYetImplemented(lines, i, browserString);
96 break;
97 }
98 }
99 }
100 FileUtils.writeLines(file, UTF_8.name(), lines);
101 }
102
103 private static String getDefaultExpectation(final List<String> lines, final int defaultIndex) {
104 int index = defaultIndex;
105 while (index >= 0 && !lines.get(index).contains("Alerts")) {
106 index--;
107 }
108 if (index >= 0) {
109 final String line = lines.get(index);
110 return line.substring(line.indexOf('"') + 1, line.lastIndexOf('"'));
111 }
112 return null;
113 }
114
115 private static int addExpectation(final List<String> lines, int i,
116 final String browserString, final ComparisonFailure comparisonFailure) {
117 while (!lines.get(i).startsWith(" @Alerts")) {
118 i--;
119 }
120 final List<String> alerts = CodeStyleTest.alertsToList(lines, i);
121 for (final Iterator<String> it = alerts.iterator(); it.hasNext();) {
122 if (it.next().startsWith(browserString + " = ")) {
123 it.remove();
124 }
125 }
126 alerts.add(browserString + " = " + getActualString(comparisonFailure));
127 lines.remove(i);
128 while (lines.get(i).startsWith(" ")) {
129 lines.remove(i);
130 }
131
132 Collections.sort(alerts);
133 String defaultAlert = null;
134 for (final String alert : alerts) {
135 if (alert.startsWith("DEFAULT = ")) {
136 defaultAlert = alert;
137 break;
138 }
139 }
140
141 if (defaultAlert != null) {
142 alerts.remove(defaultAlert);
143 alerts.add(0, defaultAlert);
144 }
145
146 for (int x = 0; x < alerts.size(); x++) {
147 String line = alerts.get(x);
148 if (x == 0) {
149 if (!line.contains(" = ")) {
150 line = "DEFAULT = " + line;
151 }
152 line = " @Alerts(" + line;
153 }
154 else {
155 line = " " + line;
156 }
157 if (x < alerts.size() - 1) {
158 line += ",";
159 }
160 else {
161 line += ")";
162 }
163 lines.add(i++, line);
164 }
165 return i;
166 }
167
168 private static String getActualString(final ComparisonFailure failure) {
169 final int lineLength = 96;
170
171 String actual = failure.getActual();
172 actual = actual.substring(0, actual.length() - 1);
173 actual = StringEscapeUtils.escapeJava(actual);
174 if (actual.length() > lineLength) {
175 final StringBuilder builder = new StringBuilder();
176 while (!actual.isEmpty()) {
177 int length = actual.lastIndexOf(',', lineLength) + 1;
178 if (length == 0 && !actual.isEmpty()) {
179 length = Math.min(lineLength, actual.length());
180 }
181 if (builder.length() != 0) {
182 builder.append(System.lineSeparator()).append(" + ");
183 }
184 builder.append('"').append(actual.substring(0, length)).append('"');
185 actual = actual.substring(length);
186 }
187 return builder.toString();
188 }
189 return "\"" + actual + "\"";
190 }
191
192 private static void removeNotYetImplemented(final List<String> lines,
193 final int i, final String browserString) {
194 final String previous = lines.get(i - 1);
195 if (previous.contains("@NotYetImplemented")) {
196 if (previous.indexOf('(') != -1) {
197 final int p0 = previous.indexOf('(') + 1;
198 final int p1 = previous.lastIndexOf(')');
199 String browsers = previous.substring(p0, p1);
200 if (browsers.indexOf('{') != -1) {
201 browsers = browsers.substring(1, browsers.length() - 1).trim();
202 }
203 final Set<String> browserSet = new HashSet<>();
204 for (final String browser : browsers.split(",")) {
205 browserSet.add(browser.trim());
206 }
207 browserSet.remove(browserString);
208 if (browserSet.size() == 1) {
209 lines.set(i - 1, " @NotYetImplemented(" + browserSet.iterator().next() + ")");
210 }
211 else if (browserSet.size() > 1) {
212 lines.set(i - 1, " @NotYetImplemented({" + String.join(", ", browserSet) + "})");
213 }
214 else {
215 lines.remove(i - 1);
216 }
217 }
218 else {
219 final List<String> allBrowsers = new ArrayList<>(Arrays.asList("CHROME", "EDGE", "FF", "FF_ESR"));
220 for (final Iterator<String> it = allBrowsers.iterator(); it.hasNext();) {
221 if (it.next().equals(browserString)) {
222 it.remove();
223 }
224 }
225 lines.set(i - 1, " @NotYetImplemented({" + String.join(", ", allBrowsers) + "})");
226 }
227 }
228 }
229
230 private static void addNotYetImplementedMethod(final List<String> lines,
231 int i, final String browserString, final String methodName, final String defaultExpectations) {
232 String parent = methodName;
233 final String child = parent.substring(parent.lastIndexOf('_') + 1);
234 parent = parent.substring(1, parent.indexOf('_', 1));
235
236 if (!lines.get(i).isEmpty()) {
237 i++;
238 }
239 lines.add(i++, "");
240 lines.add(i++, " /**");
241 lines.add(i++, " * @throws Exception if the test fails");
242 lines.add(i++, " */");
243 lines.add(i++, " @Test");
244 lines.add(i++, " @Alerts(\"" + defaultExpectations + "\")");
245 lines.add(i++, " @NotYetImplemented(" + browserString + ")");
246 lines.add(i++, " public void _" + parent + "_" + child + "() throws Exception {");
247 lines.add(i++, " test(\"" + parent + "\", \"" + child + "\");");
248 lines.add(i++, " }");
249 lines.add(i++, "}");
250 while (lines.size() > i) {
251 lines.remove(i);
252 }
253 }
254
255 private static void addNotYetImplemented(final List<String> lines, final int i, final String browserString) {
256 final String previous = lines.get(i - 1);
257 if (previous.contains("@NotYetImplemented")) {
258 if (previous.indexOf('(') != -1 && !previous.contains(browserString)) {
259 final int p0 = previous.indexOf('(') + 1;
260 final int p1 = previous.lastIndexOf(')');
261 String browsers = previous.substring(p0, p1);
262 if (browsers.indexOf('{') != -1) {
263 browsers = browsers.substring(1, browsers.length() - 1).trim();
264 }
265 browsers += ", " + browserString;
266 lines.set(i - 1, " @NotYetImplemented({" + browsers + "})");
267 }
268 }
269 else {
270 lines.add(i, " @NotYetImplemented(" + browserString + ")");
271 }
272 }
273
274 private static void addMethodWithExpectation(final List<String> lines,
275 int i, final String browserString, final String methodName, final ComparisonFailure comparisonFailure,
276 final String defaultExpectations) {
277 String parent = methodName;
278 final String child = parent.substring(parent.lastIndexOf('_') + 1);
279 final int index = parent.indexOf('_', 1);
280 if (index != -1) {
281 parent = parent.substring(1, index);
282 }
283 else {
284 parent = parent.substring(1);
285 }
286
287 if (!lines.get(i).isEmpty()) {
288 i++;
289 }
290 lines.add(i++, "");
291 lines.add(i++, " /**");
292 lines.add(i++, " * @throws Exception if the test fails");
293 lines.add(i++, " */");
294 lines.add(i++, " @Test");
295 lines.add(i++, " @Alerts(DEFAULT = \"" + defaultExpectations + "\",");
296 lines.add(i++, " " + browserString + " = " + getActualString(comparisonFailure) + ")");
297 if (index != -1) {
298 lines.add(i++, " public void _" + parent + "_" + child + "() throws Exception {");
299 lines.add(i++, " test(\"" + parent + "\", \"" + child + "\");");
300 }
301 else {
302 String method = parent;
303 for (final String prefix : HostExtractor.PREFIXES_) {
304 if (method.startsWith(prefix)) {
305 method = prefix.toLowerCase(Locale.ROOT) + method.substring(prefix.length());
306 break;
307 }
308 }
309 if (Character.isUpperCase(method.charAt(0))) {
310 method = Character.toLowerCase(method.charAt(0)) + method.substring(1);
311 }
312 lines.add(i++, " public void " + method + "() throws Exception {");
313 lines.add(i++, " test(\"" + parent + "\");");
314 }
315 lines.add(i++, " }");
316 lines.add(i++, "}");
317 while (lines.size() > i) {
318 lines.remove(i);
319 }
320 }
321 }