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