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  import static org.junit.jupiter.api.Assertions.assertTrue;
19  import static org.junit.jupiter.api.Assertions.fail;
20  
21  import java.io.File;
22  import java.io.IOException;
23  import java.lang.reflect.Field;
24  import java.util.ArrayList;
25  import java.util.Iterator;
26  import java.util.LinkedList;
27  import java.util.List;
28  
29  import org.apache.commons.io.FileUtils;
30  import org.htmlunit.javascript.configuration.AbstractJavaScriptConfiguration;
31  import org.htmlunit.javascript.configuration.BrowserFeature;
32  import org.htmlunit.javascript.configuration.SupportedBrowser;
33  import org.junit.jupiter.api.Test;
34  
35  /**
36   * Tests for {@link BrowserVersionFeatures}.
37   *
38   * @author Ahmed Ashour
39   * @author Ronald Brill
40   * @author Frank Danek
41   */
42  public class BrowserVersionFeaturesTest {
43  
44      /**
45       * Test of alphabetical order.
46       */
47      @Test
48      public void lexicographicOrder() {
49          String lastFeatureName = null;
50          for (final BrowserVersionFeatures feature : BrowserVersionFeatures.values()) {
51              final String featureName = feature.name();
52              if (lastFeatureName != null && featureName.compareTo(lastFeatureName) < 1) {
53                  fail("BrowserVersionFeatures.java: '"
54                      + featureName + "' should be before '" + lastFeatureName + "'");
55              }
56              lastFeatureName = featureName;
57          }
58      }
59  
60      /**
61       * Test of usage.
62       * @throws Exception in case of problems
63       */
64      @Test
65      public void unusedFeatures() throws Exception {
66          final List<BrowserVersion> browsers = new LinkedList<>();
67          browsers.add(BrowserVersion.CHROME);
68          browsers.add(BrowserVersion.EDGE);
69          browsers.add(BrowserVersion.FIREFOX);
70          browsers.add(BrowserVersion.FIREFOX_ESR);
71  
72          for (final BrowserVersionFeatures feature : BrowserVersionFeatures.values()) {
73              int useCount = 0;
74              for (final BrowserVersion browserVersion : browsers) {
75                  if (browserVersion.hasFeature(feature)) {
76                      useCount++;
77                  }
78              }
79              assertTrue(useCount > 0, "BrowserVersionFeatures.java: '" + feature.name() + "' in no longer in use.");
80              assertTrue(useCount < browsers.size(),
81                      "BrowserVersionFeatures.java: '" + feature.name() + "' is enabled for all supported browsers.");
82          }
83  
84          for (final BrowserVersionFeatures feature : BrowserVersionFeatures.values()) {
85              final Field field = BrowserVersionFeatures.class.getField(feature.name());
86              final BrowserFeature browserFeature = field.getAnnotation(BrowserFeature.class);
87  
88              if (browserFeature != null) {
89                  for (final SupportedBrowser annotatedBrowser : browserFeature.value()) {
90                      boolean inUse = false;
91                      for (final BrowserVersion supportedBrowser : browsers) {
92                          if (AbstractJavaScriptConfiguration.isCompatible(expectedBrowserName(supportedBrowser),
93                                  annotatedBrowser)) {
94                              inUse = true;
95                              continue;
96                          }
97                      }
98                      assertTrue(inUse,
99                              "BrowserVersionFeatures.java: Annotation '"
100                             + annotatedBrowser + "' of feature '"
101                             + feature.name() + "' in no longer in use.");
102                 }
103             }
104         }
105     }
106 
107     private static SupportedBrowser expectedBrowserName(final BrowserVersion browser) {
108         if (browser == BrowserVersion.EDGE) {
109             return SupportedBrowser.EDGE;
110         }
111         if (browser == BrowserVersion.FIREFOX) {
112             return SupportedBrowser.FF;
113         }
114         if (browser == BrowserVersion.FIREFOX_ESR) {
115             return SupportedBrowser.FF_ESR;
116         }
117 
118         return SupportedBrowser.CHROME;
119     }
120 
121     /**
122      * Test of usage in the Java files.
123      *
124      * @throws Exception in case of problems
125      */
126     @Test
127     public void unusedFeaturesInCode() throws Exception {
128         final List<String> unusedFeatures = new ArrayList<>(BrowserVersionFeatures.values().length);
129         for (final BrowserVersionFeatures feature : BrowserVersionFeatures.values()) {
130             unusedFeatures.add(feature.name());
131         }
132         unusedCheck(new File("src/main/java"), unusedFeatures);
133         if (!unusedFeatures.isEmpty()) {
134             fail("The following " + BrowserVersionFeatures.class.getSimpleName() + " "
135                     + (unusedFeatures.size() == 1 ? "is" : "are") + " not used: "
136                     + String.join(", ", unusedFeatures));
137         }
138     }
139 
140     private void unusedCheck(final File dir, final List<String> unusedFeatures) throws IOException {
141         final File[] files = dir.listFiles();
142         if (files != null) {
143             for (final File file : files) {
144                 if (file.isDirectory() && !".git".equals(file.getName())) {
145                     unusedCheck(file, unusedFeatures);
146                 }
147                 else if (file.getName().endsWith(".java")) {
148                     final List<String> lines = FileUtils.readLines(file, ISO_8859_1);
149                     final String browserVersionFeatures = BrowserVersionFeatures.class.getSimpleName();
150                     for (final String line : lines) {
151                         for (final Iterator<String> it = unusedFeatures.iterator(); it.hasNext();) {
152                             if (line.contains(browserVersionFeatures + '.' + it.next())) {
153                                 it.remove();
154                             }
155                         }
156                     }
157                 }
158             }
159         }
160     }
161 }