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.general;
16  
17  import static org.htmlunit.BrowserVersionFeatures.JS_ERROR_STACK_TRACE_LIMIT;
18  
19  import java.net.URL;
20  import java.util.ArrayList;
21  import java.util.Collection;
22  import java.util.Collections;
23  import java.util.Comparator;
24  import java.util.HashMap;
25  import java.util.List;
26  import java.util.Set;
27  
28  import org.htmlunit.TestCaseTest;
29  import org.htmlunit.WebDriverTestCase;
30  import org.htmlunit.javascript.configuration.ClassConfiguration;
31  import org.htmlunit.javascript.configuration.ClassConfiguration.ConstantInfo;
32  import org.htmlunit.javascript.configuration.WorkerJavaScriptConfiguration;
33  import org.htmlunit.junit.annotation.Alerts;
34  import org.htmlunit.util.MimeType;
35  import org.junit.jupiter.params.ParameterizedTest;
36  import org.junit.jupiter.params.provider.Arguments;
37  import org.junit.jupiter.params.provider.MethodSource;
38  
39  /**
40   * Tests that constants class are correct.
41   *
42   * @author Ronald Brill
43   */
44  public class DedicatedWorkerGlobalScopeConstantsTest extends WebDriverTestCase {
45  
46      /**
47       * Returns the parameterized data.
48       * @return the parameterized data
49       * @throws Exception if an error occurs
50       */
51      public static Collection<Arguments> data() throws Exception {
52          final List<Arguments> list = new ArrayList<>();
53          final Set<String> classNames = TestCaseTest.getAllConfiguredJsClassNames();
54          final ArrayList<String> classNamesSorted = new ArrayList<>(classNames);
55          Collections.sort(classNamesSorted);
56  
57          for (final String host : classNamesSorted) {
58              if (!"Audio".equals(host)) {
59                  list.add(Arguments.of(host));
60              }
61          }
62          return list;
63      }
64  
65      /**
66       * The default test.
67       * @throws Exception if an error occurs
68       */
69      @ParameterizedTest(name = "_{0}")
70      @MethodSource("data")
71      void test(final String host) throws Exception {
72          test(host, getExpectedString(host));
73      }
74  
75      private void test(final String className, final String[] expectedAlerts) throws Exception {
76          final String html = DOCTYPE_HTML
77                  + "<html><body>"
78                  + "<script>\n"
79                  + LOG_TITLE_FUNCTION
80                  + "try {\n"
81                  + "  var myWorker = new Worker('worker.js');\n"
82                  + "  myWorker.onmessage = function(e) {\n"
83                  + "    window.document.title = '' + e.data;\n"
84                  + "  };\n"
85                  + "  setTimeout(function() { myWorker.postMessage('test');}, 10);\n"
86                  + "} catch(e) { window.document.title = 'exception'; }\n"
87                  + "</script></body></html>\n";
88  
89          final String workerJs = "onmessage = function(e) {\n"
90                  + "  var workerResult = '';\n"
91                  + "  try {\n"
92                  + "    var all = [];\n"
93                  + "    for (var x in " + className + ") {\n"
94                  + "      if (typeof " + className + "[x] == 'number') {\n"
95                  + "        all.push(x);\n"
96                  + "      }\n"
97                  + "    }\n"
98                  + "    all.sort();\n"
99  
100                 + "    for (var i in all) {\n"
101                 + "      var x = all[i];\n"
102                 + "      workerResult += x + ':' + " + className + "[x] + '\\u00a7';\n"
103                 + "    }\n"
104                 + "  } catch(e) {}\n"
105                 + "  postMessage(workerResult);\n"
106                 + "}\n";
107 
108         getMockWebConnection().setResponse(new URL(URL_FIRST, "worker.js"), workerJs, MimeType.TEXT_JAVASCRIPT);
109 
110         loadPage2(html);
111         verifyTitle2(DEFAULT_WAIT_TIME, getWebDriver(), expectedAlerts);
112     }
113 
114     private String[] getExpectedString(final String className) {
115         final String[] expectedAlerts = getExpectedAlerts();
116 
117         if (expectedAlerts != null && expectedAlerts.length == 1
118                 && "-".equals(expectedAlerts[0])) {
119             return new String[0];
120         }
121 
122         if (expectedAlerts != null && expectedAlerts.length > 0) {
123             return expectedAlerts;
124         }
125 
126         if (className.endsWith("Array") || "Image".equals(className) || "Option".equals(className)) {
127             return new String[0];
128         }
129         if ("Error".equals(className) && getBrowserVersion().hasFeature(JS_ERROR_STACK_TRACE_LIMIT)) {
130             return new String[] {"stackTraceLimit:10"};
131         }
132 
133         final WorkerJavaScriptConfiguration javaScriptConfig
134                 = WorkerJavaScriptConfiguration.getInstance(getBrowserVersion());
135         final HashMap<String, ClassConfiguration> classConfigurationIndex = new HashMap<>();
136         for (final ClassConfiguration config : javaScriptConfig.getAll()) {
137             classConfigurationIndex.put(config.getClassName(), config);
138         }
139 
140         final List<String> constants = new ArrayList<>();
141         ClassConfiguration classConfig = classConfigurationIndex.get(className);
142 
143         boolean first = true;
144         while (classConfig != null) {
145             if (first && !classConfig.isJsObject()) {
146                 break;
147             }
148             if (first || classConfig.getJsConstructor() != null) {
149                 final List<ConstantInfo> constantInfos = classConfig.getConstants();
150                 if (constantInfos != null) {
151                     for (final ConstantInfo constantInfo : constantInfos) {
152                         constants.add(constantInfo.getName() + ":" + constantInfo.getValue());
153                     }
154                 }
155             }
156             classConfig = classConfigurationIndex.get(classConfig.getExtendedClassName());
157             first = false;
158         }
159 
160         Collections.sort(constants, new Comparator<String>() {
161             @Override
162             public int compare(final String o1, final String o2) {
163                 return o1.substring(0, o1.indexOf(':')).compareTo(o2.substring(0, o2.indexOf(':')));
164             }
165         });
166         return constants.toArray(new String[0]);
167     }
168 
169     /**
170      * {@inheritDoc}
171      */
172     @Override
173     protected boolean isWebClientCached() {
174         return true;
175     }
176 
177     /**
178      * @throws Exception if the test fails
179      */
180     @Alerts(CHROME = {"AT_TARGET:2", "BUBBLING_PHASE:3", "CAPTURING_PHASE:1", "NONE:0"},
181             EDGE = {"AT_TARGET:2", "BUBBLING_PHASE:3", "CAPTURING_PHASE:1", "NONE:0"},
182             FF = "-",
183             FF_ESR = "-")
184     void _SecurityPolicyViolationEvent() throws Exception {
185         test("SecurityPolicyViolationEvent", getExpectedString("SecurityPolicyViolationEvent"));
186     }
187 }