View Javadoc
1   /*
2    * Copyright (c) 2002-2025 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit;
16  
17  import static java.nio.charset.StandardCharsets.ISO_8859_1;
18  
19  import java.io.File;
20  import java.io.IOException;
21  import java.util.List;
22  import java.util.Set;
23  import java.util.TreeSet;
24  
25  import org.apache.commons.io.FileUtils;
26  import org.htmlunit.general.ElementPropertiesTest;
27  import org.junit.Test;
28  
29  /**
30   * Generates HTML file with all <tt>NotYetImplemented</tt> methods.
31   *
32   * @author Ahmed Ashour
33   * @author Ronald Brill
34   */
35  public class NotYetImplementedTest {
36  
37      private Set<String> entries_ = new TreeSet<>();
38  
39      /**
40       * @throws Exception if the test fails
41       */
42      @Test
43      public void test() throws Exception {
44          process(new File("src/test/java"));
45          save();
46      }
47  
48      private void process(final File dir) throws IOException {
49          final File[] files = dir.listFiles();
50          if (files != null) {
51              for (final File file : files) {
52                  final String fileName = file.getName();
53                  if (file.isDirectory()
54                          && !"huge".equals(fileName)
55                          && !".git".equals(fileName)) {
56                      process(file);
57                  }
58                  else {
59                      if (fileName.endsWith(".java")
60                              && !"SimpleWebTestCase.java".equals(fileName)
61                              && !"AnnotationUtilsTest.java".equals(fileName)
62                              && !"NotYetImplementedTest.java".equals(fileName)
63                              && !"CodeStyleTest.java".equals(fileName)) {
64                          final List<String> lines = FileUtils.readLines(file, ISO_8859_1);
65                          final String relativePath = file.getAbsolutePath().substring(
66                              new File(".").getAbsolutePath().length() - 1).replace('\\', '/');
67                          process(lines, relativePath);
68                      }
69                  }
70              }
71          }
72      }
73  
74      private void process(final List<String> lines, final String path) {
75          int index = 1;
76          for (final String line : lines) {
77              if (line.startsWith("    @NotYetImplemented")) {
78                  String browser = "All";
79                  if (line.contains("(")) {
80                      browser = line.replaceAll(".*\\((.*)\\).*", "$1");
81                      browser = browser.replaceAll("Browser\\.", "");
82                      browser = browser.replaceAll("[{}]", "");
83                      browser = browser.trim();
84                  }
85                  String methodName = null;
86                  for (int i = index; i < lines.size(); i++) {
87                      final String l = lines.get(i);
88                      if (l.startsWith("    public ")) {
89                          methodName = l.split(" ")[6];
90                          break;
91                      }
92                  }
93                  final int lineNumber = getLineNumber(lines, index);
94                  final String description = getDescription(lines, index);
95                  entries_.add(path + ';' + methodName + ';' + lineNumber + ";" + browser
96                          + ';' + description);
97              }
98              else if (line.startsWith("    @HtmlUnitNYI")) {
99                  String browser = "All";
100                 final StringBuilder nyi = new StringBuilder(line);
101 
102                 String methodName = null;
103                 for (int i = index; i < lines.size(); i++) {
104                     final String l = lines.get(i);
105                     if (l.startsWith("    public ")) {
106                         methodName = l.split(" ")[6];
107                         break;
108                     }
109                     nyi.append(l);
110                 }
111                 final int lineNumber = getLineNumber(lines, index);
112                 final String description = getDescription(lines, index);
113 
114                 final String nyiString = nyi.toString();
115                 if (nyiString.startsWith("    @HtmlUnitNYI(")) {
116                     browser = "";
117                     if (nyiString.contains("CHROME = ")) {
118                         browser += "CHROME";
119                     }
120                     if (nyiString.contains("EDGE = ")) {
121                         browser += "EDGE";
122                     }
123                     if (nyiString.contains("FF_ESR = ")) {
124                         if (browser.length() > 0) {
125                             browser += ", ";
126                         }
127                         browser += "FF_ESR";
128                     }
129                     if (nyiString.contains("FF = ")) {
130                         if (browser.length() > 0) {
131                             browser += ", ";
132                         }
133                         browser += "FF";
134                     }
135                 }
136                 if (browser.length() < 2) {
137                     throw new IllegalArgumentException("'" + nyiString + "' seems to be not supported by @HtmlUnitNYI");
138                 }
139                 entries_.add(path + ';' + methodName + ';' + lineNumber + ";" + browser
140                         + ';' + description);
141             }
142             index++;
143         }
144     }
145 
146     private static int getLineNumber(final List<String> lines, final int index) {
147         for (int i = index; i >= 0; i--) {
148             final String l = lines.get(i);
149             if (l.startsWith("    /**")) {
150                 return i;
151             }
152         }
153         return 0;
154     }
155 
156     private static String getDescription(final List<String> lines, final int index) {
157         final StringBuilder builder = new StringBuilder();
158         for (int i = getLineNumber(lines, index); i < lines.size(); i++) {
159             final String line = lines.get(i).trim();
160             final int start = line.indexOf(' ') != -1 ? line.indexOf(' ') + 1 : -1;
161             final boolean end = line.endsWith("*/");
162             if (line.contains("* @throws ") || line.contains("* @exception")) {
163                 break;
164             }
165             if (start != -1) {
166                 if (builder.length() != 0) {
167                     builder.append(' ');
168                 }
169                 builder.append(line, start, line.length() - (end ? 2 : 0));
170             }
171             if (end) {
172                 break;
173             }
174         }
175         return builder.toString().replace(";", "__semicolon__");
176     }
177 
178     private void save() throws Exception {
179         final StringBuilder builder = new StringBuilder();
180         builder.append("<html><head>\n");
181         builder.append("<style type=\"text/css\">\n");
182         builder.append("table.bottomBorder { border-collapse:collapse; }\n");
183         builder.append("table.bottomBorder td, table.bottomBorder th { "
184                             + "border-bottom:1px dotted black;padding:5px; }\n");
185         builder.append("table.bottomBorder td.numeric { text-align:right; }\n");
186         builder.append("</style>\n");
187         builder.append("</head><body>\n");
188         builder.append("<p>NotYetImplemented is a condition in which a test is known to fail with HtmlUnit.</p>");
189         // statistics
190         builder.append("<h3>Overview</h3>");
191         final int overviewPos = builder.length();
192         // per browser
193 
194         // details
195         builder.append("<h3>Details</h3>");
196         builder.append("<table class='bottomBorder'>\n");
197         builder.append("  <tr><th>File</th><th>#</th><th>Method</th><th>Line</th><th>Description</th></tr>\n");
198         String lastFile = null;
199 
200         int count = 0;
201         int countFFESR = 0;
202         int countFF = 0;
203         int countChrome = 0;
204         for (final String entry : entries_) {
205             final String[] values = entry.split(";");
206             final String file = values[0];
207             final String fileName = file.substring(file.lastIndexOf('/') + 1, file.length() - 5);
208             final String method = values[1];
209             final String line = values[2];
210             String browser = values[3];
211             final String description = entry.endsWith(";") ? "&nbsp;"
212                     : values[values.length - 1].replace("__semicolon__", ";");
213             builder.append("  <tr>\n");
214             if (!file.equals(lastFile)) {
215                 int totalCount = 0;
216                 for (final String e : entries_) {
217                     if (e.startsWith(file)) {
218                         totalCount++;
219                     }
220                 }
221                 if (totalCount != 1) {
222                     builder.append("    <td rowspan='" + totalCount + "'>");
223                 }
224                 else {
225                     builder.append("    <td>");
226                 }
227                 builder.append("<a target='_blank' href='https://github.com/HtmlUnit/htmlunit/blob/master/")
228                         .append(file)
229                         .append("'>")
230                         .append(fileName)
231                         .append("</a>");
232                 builder.append("</td>\n");
233                 lastFile = file;
234             }
235             builder.append("    <td>").append(Integer.toString(count++)).append("</td>\n");
236 
237             builder.append("    <td><a target='_blank' href='https://github.com/HtmlUnit/htmlunit/blob/master/")
238                     .append(file)
239                     .append("#L")
240                     .append(line)
241                     .append("'>")
242                     .append(method)
243                     .append("</a> ")
244                     .append(browser)
245                     .append("</td>\n");
246             builder.append("    <td class='numeric'>").append(line).append("</td>\n");
247             builder.append("    <td>").append(description).append("</td>\n");
248             builder.append("  </tr>\n");
249 
250             if (browser.contains("FF_ESR")) {
251                 browser = browser.replace("FF_ESR", "");
252                 countFFESR++;
253             }
254             if (browser.contains("FF")) {
255                 countFF++;
256             }
257             if (browser.contains("CHROME")) {
258                 countChrome++;
259             }
260             if (browser.contains("All")) {
261                 countFFESR++;
262                 countFF++;
263                 countChrome++;
264             }
265         }
266         builder.append("</table>\n").append("</body></html>");
267 
268         final StringBuilder overview = new StringBuilder();
269         overview.append("<table class='bottomBorder'>\n");
270         overview.append("  <tr>\n");
271         overview.append("    <td class='numeric'>").append(Integer.toString(count)).append("</td>\n");
272         overview.append("    <td>methods marked as NotYetImplemented</td>\n");
273         overview.append("  </tr>\n");
274 
275         overview.append("  <tr>\n");
276         overview.append("    <td class='numeric'>").append(countFFESR).append("</td>\n");
277         overview.append("    <td>for FF_ESR</td>\n");
278         overview.append("  </tr>\n");
279 
280         overview.append("  <tr>\n");
281         overview.append("    <td class='numeric'>").append(countFF).append("</td>\n");
282         overview.append("    <td>for FF</td>\n");
283         overview.append("  </tr>\n");
284 
285         overview.append("  <tr>\n");
286         overview.append("    <td class='numeric'>").append(Integer.toString(countChrome)).append("</td>\n");
287         overview.append("    <td>for Chrome</td>\n");
288         overview.append("  </tr>\n");
289 
290         overview.append("</table>\n");
291 
292         builder.insert(overviewPos, overview);
293 
294         FileUtils.writeStringToFile(new File(ElementPropertiesTest.getTargetDirectory(), "notYetImplemented.html"),
295                 builder.toString(), ISO_8859_1);
296     }
297 
298 }