Skip to content

Commit 51dc804

Browse files
committed
Use local date, remove workarounds
1 parent 94e6639 commit 51dc804

File tree

6 files changed

+113
-100
lines changed

6 files changed

+113
-100
lines changed

dev/core/src/com/google/gwt/dev/shell/HostedModePluginObject.java

-9
Original file line numberDiff line numberDiff line change
@@ -185,15 +185,6 @@ public boolean connect(String url, String sessionKey, String address,
185185
return false;
186186
}
187187
// TODO: add whitelist and default-port support?
188-
189-
// We know that legacy dev mode is running, we need to tell HtmlUnit that it is safe
190-
// to permit plain Java objects to leak into JS - the JavaObject type will return a
191-
// Object[] with a success boolean and a value, and HtmlUnit will guard against this.
192-
// The simplest way to do that here is to mark java.lang.Object as the java equivalent
193-
// of some JS type - the name of the type doesn't matter.
194-
// webClient.setActiveXObjectMap(Collections.singletonMap(
195-
// "GwtLegacyDevModeExceptionOrReturnValue", "java.lang.Object"));
196-
197188
try {
198189
HtmlUnitSessionHandler htmlUnitSessionHandler = new HtmlUnitSessionHandler(
199190
window, jsEngine, webClient);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2025 GWT Project Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
package com.google.gwt.junit;
17+
18+
import java.lang.annotation.ElementType;
19+
import java.lang.annotation.Repeatable;
20+
import java.lang.annotation.Retention;
21+
import java.lang.annotation.RetentionPolicy;
22+
import java.lang.annotation.Target;
23+
24+
/**
25+
* Browser options that may be set independently for each test.class.
26+
*/
27+
@Retention(RetentionPolicy.RUNTIME)
28+
@Repeatable(BrowserOption.BrowserOptionList.class)
29+
@Target(ElementType.TYPE)
30+
public @interface BrowserOption {
31+
OptionType type();
32+
String value();
33+
34+
/**
35+
* Allows setting multiple browser properties for a single class.
36+
*/
37+
@Retention(RetentionPolicy.RUNTIME)
38+
@Target(ElementType.TYPE)
39+
@interface BrowserOptionList {
40+
BrowserOption[] value();
41+
}
42+
43+
enum OptionType {
44+
TIMEZONE, LANGUAGE
45+
}
46+
}

user/src/com/google/gwt/junit/JUnitShell.java

+23-4
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ private static class ArgHandlerRunCompiledJavascript extends ArgHandlerFlag {
154154

155155
private JUnitShell shell;
156156

157-
public ArgHandlerRunCompiledJavascript(JUnitShell shell) {
157+
ArgHandlerRunCompiledJavascript(JUnitShell shell) {
158158
this.shell = shell;
159159

160160
addTagValue("-web", false);
@@ -187,7 +187,7 @@ private static class ArgHandlerShowWindows extends ArgHandlerFlag {
187187

188188
private JUnitShell shell;
189189

190-
public ArgHandlerShowWindows(JUnitShell shell) {
190+
ArgHandlerShowWindows(JUnitShell shell) {
191191
this.shell = shell;
192192

193193
addTagValue("-notHeadless", true);
@@ -218,7 +218,7 @@ public boolean getDefaultValue() {
218218
static class ArgProcessor extends ArgProcessorBase {
219219

220220
@SuppressWarnings("deprecation")
221-
public ArgProcessor(final JUnitShell shell) {
221+
ArgProcessor(final JUnitShell shell) {
222222
final HostedModeOptions options = shell.options;
223223
/*
224224
* ----- Options from DevModeBase -------
@@ -636,7 +636,7 @@ public static Set<String> getRemoteUserAgents() {
636636
}
637637

638638
/**
639-
* Get the compiler options
639+
* Get the compiler options.
640640
*
641641
* @return the compiler options that have been set.
642642
*/
@@ -1378,6 +1378,8 @@ private void runTestImpl(GWTTestCase testCase, TestResult testResult,
13781378

13791379
try {
13801380
if (!runStyleStarted) {
1381+
runStyle.resetOptions();
1382+
getOptions(testCase.getClass());
13811383
runStyle.launchModule(currentModule.getName());
13821384
}
13831385
} catch (UnableToCompleteException e) {
@@ -1425,6 +1427,23 @@ private void runTestImpl(GWTTestCase testCase, TestResult testResult,
14251427
processTestResult(testCase, testResult);
14261428
}
14271429

1430+
private void getOptions(Class<?> testClass) {
1431+
if (testClass.getSuperclass() != null) {
1432+
getOptions(testClass.getSuperclass());
1433+
}
1434+
if (testClass.isAnnotationPresent(BrowserOption.class)) {
1435+
BrowserOption option = testClass.getAnnotation(BrowserOption.class);
1436+
runStyle.setOption(option.type(), option.value());
1437+
}
1438+
if (testClass.isAnnotationPresent(BrowserOption.BrowserOptionList.class)) {
1439+
BrowserOption.BrowserOptionList optionList = testClass
1440+
.getAnnotation(BrowserOption.BrowserOptionList.class);
1441+
for (BrowserOption option: optionList.value()) {
1442+
runStyle.setOption(option.type(), option.value());
1443+
}
1444+
}
1445+
}
1446+
14281447
/**
14291448
* Synthesize command line arguments from a system property.
14301449
*/

user/src/com/google/gwt/junit/RunStyle.java

+19
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import com.google.gwt.core.ext.UnableToCompleteException;
2020

2121
import java.util.Collections;
22+
import java.util.EnumMap;
2223
import java.util.Set;
2324

2425
/**
@@ -34,6 +35,8 @@ public abstract class RunStyle {
3435
private int tries = 1;
3536

3637
private Set<String> userAgents;
38+
protected EnumMap<BrowserOption.OptionType, String> options
39+
= new EnumMap<>(BrowserOption.OptionType.class);
3740

3841
/**
3942
* Constructor for RunStyle. Any subclass must provide a constructor with the
@@ -158,4 +161,20 @@ public boolean shouldAutoGenerateResources() {
158161
protected TreeLogger getLogger() {
159162
return shell.getTopLogger();
160163
}
164+
165+
/**
166+
* Set browser option for the next test class.
167+
* @param type option type
168+
* @param value option value
169+
*/
170+
public void setOption(BrowserOption.OptionType type, String value) {
171+
options.put(type, value);
172+
}
173+
174+
/**
175+
* Reset all browser options.
176+
*/
177+
public void resetOptions() {
178+
options.clear();
179+
}
161180
}

user/src/com/google/gwt/junit/RunStyleHtmlUnit.java

+21-86
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@
2020
import com.google.gwt.thirdparty.guava.common.collect.ImmutableSet;
2121
import com.google.gwt.thirdparty.guava.common.collect.Maps;
2222

23-
import org.apache.commons.logging.Log;
24-
import org.apache.commons.logging.LogFactory;
2523
import org.htmlunit.AlertHandler;
2624
import org.htmlunit.BrowserVersion;
2725
import org.htmlunit.FailingHttpStatusCodeException;
@@ -31,9 +29,6 @@
3129
import org.htmlunit.ScriptException;
3230
import org.htmlunit.WebClient;
3331
import org.htmlunit.WebWindow;
34-
import org.htmlunit.corejs.javascript.Context;
35-
import org.htmlunit.corejs.javascript.Function;
36-
import org.htmlunit.corejs.javascript.JavaScriptException;
3732
import org.htmlunit.corejs.javascript.ScriptableObject;
3833
import org.htmlunit.html.HtmlPage;
3934
import org.htmlunit.javascript.JavaScriptEngine;
@@ -67,15 +62,18 @@ protected static class HtmlUnitThread extends Thread implements AlertHandler,
6762
private final boolean developmentMode;
6863
private final TreeLogger treeLogger;
6964
private final String url;
65+
private final Map<BrowserOption.OptionType, String> properties;
7066
private Object waitForUnload = new Object();
7167

7268
public HtmlUnitThread(BrowserVersion browser, String url,
73-
TreeLogger treeLogger, boolean developmentMode) {
69+
TreeLogger treeLogger, boolean developmentMode,
70+
Map<BrowserOption.OptionType, String> properties) {
7471
this.browser = browser;
7572
this.url = url;
7673
this.treeLogger = treeLogger;
7774
this.setName("htmlUnit client thread");
7875
this.developmentMode = developmentMode;
76+
this.properties = properties;
7977
}
8078

8179
public void handleAlert(Page page, String message) {
@@ -177,7 +175,7 @@ protected void setupWebClient(WebClient webClient) {
177175
treeLogger);
178176
webClient.setJavaScriptEngine(hostedEngine);
179177
} else {
180-
JavaScriptEngine webEngine = new WebJavaScriptEngine(webClient);
178+
JavaScriptEngine webEngine = new JavaScriptEngine(webClient);
181179
webClient.setJavaScriptEngine(webEngine);
182180
}
183181
if (System.getProperty("gwt.htmlunit.debug") != null) {
@@ -207,85 +205,12 @@ private static class HostedJavaScriptEngine extends JavaScriptEngine {
207205
public void initialize(WebWindow webWindow, Page page) {
208206
// Hook in the hosted-mode plugin after initializing the JS engine.
209207
super.initialize(webWindow, page);
210-
Window window = (Window) webWindow.getScriptableObject();
208+
Window window = webWindow.getScriptableObject();
211209
window.defineProperty("__gwt_HostedModePlugin",
212210
new HostedModePluginObject(this, webClient, logger), ScriptableObject.READONLY);
213211
}
214212
}
215213

216-
/**
217-
* JavaScriptEngine subclass that fixes a bug when calling {@code window.onerror}.
218-
* Make sure to remove when updating HtmlUnit.
219-
*
220-
* @see <a href="https://sourceforge.net/p/htmlunit/bugs/1924/">HtmlUnit bug #1924</a>
221-
*/
222-
private static class WebJavaScriptEngine extends JavaScriptEngine {
223-
private static final Log LOG = LogFactory.getLog(JavaScriptEngine.class);
224-
private final WebClient webClient;
225-
226-
WebJavaScriptEngine(WebClient webClient) {
227-
super(webClient);
228-
this.webClient = webClient;
229-
}
230-
231-
@Override
232-
protected void handleJavaScriptException(ScriptException scriptException,
233-
boolean triggerOnError) {
234-
// XXX(tbroyer): copied from JavaScriptEngine to call below triggerOnError
235-
// instead of Window's triggerOnError.
236-
237-
// Trigger window.onerror, if it has been set.
238-
final HtmlPage page = scriptException.getPage();
239-
if (triggerOnError && page != null) {
240-
final WebWindow window = page.getEnclosingWindow();
241-
if (window != null) {
242-
final Window w = (Window) window.getScriptableObject();
243-
if (w != null) {
244-
try {
245-
triggerOnError(w, scriptException);
246-
} catch (final Exception e) {
247-
handleJavaScriptException(new ScriptException(page, e, null), false);
248-
}
249-
}
250-
}
251-
}
252-
final JavaScriptErrorListener javaScriptErrorListener =
253-
webClient.getJavaScriptErrorListener();
254-
if (javaScriptErrorListener != null) {
255-
javaScriptErrorListener.scriptException(page, scriptException);
256-
}
257-
// Throw a Java exception if the user wants us to.
258-
if (webClient.getOptions().isThrowExceptionOnScriptError()) {
259-
throw scriptException;
260-
}
261-
// Log the error; ScriptException instances provide good debug info.
262-
LOG.info("Caught script exception", scriptException);
263-
}
264-
265-
private void triggerOnError(Window w, ScriptException e) {
266-
// XXX(tbroyer): copied from HtmlUnit's javascript.host.Window
267-
// with fix unwrapping the JS exception before passing it back to JS.
268-
final Object o = w.getOnerror();
269-
if (o instanceof Function) {
270-
final Function f = (Function) o;
271-
final String msg = e.getMessage();
272-
final String url = e.getPage().getUrl().toExternalForm();
273-
final int line = e.getFailingLineNumber();
274-
275-
final int column = e.getFailingColumnNumber();
276-
277-
Object jsError = null;
278-
if (e.getCause() instanceof JavaScriptException) {
279-
jsError = ((JavaScriptException) e.getCause()).getValue();
280-
}
281-
282-
Object[] args = new Object[]{msg, url, line, column, jsError};
283-
284-
f.call(Context.getCurrentContext(), w, w, args);
285-
}
286-
}
287-
}
288-
289214
private static final Map<String, BrowserVersion> BROWSER_MAP = Maps.newHashMap();
290215
private static final Map<BrowserVersion, String> USER_AGENT_MAP = Maps.newHashMap();
291216

@@ -297,9 +222,7 @@ private void triggerOnError(Window w, ScriptException e) {
297222
addBrowser(BrowserVersion.CHROME, "safari");
298223
}
299224

300-
private static void addBrowser(BrowserVersion baseBrowser, String userAgent) {
301-
BrowserVersion browser = new BrowserVersion.BrowserVersionBuilder(baseBrowser)
302-
.setSystemTimezone(TimeZone.getDefault()).build();
225+
private static void addBrowser(BrowserVersion browser, String userAgent) {
303226
BROWSER_MAP.put(browser.getNickname(), browser);
304227
USER_AGENT_MAP.put(browser, userAgent);
305228
}
@@ -357,7 +280,19 @@ public int initialize(String args) {
357280

358281
@Override
359282
public void launchModule(String moduleName) {
360-
for (BrowserVersion browser : browsers) {
283+
for (BrowserVersion baseBrowser : browsers) {
284+
BrowserVersion.BrowserVersionBuilder builder
285+
= new BrowserVersion.BrowserVersionBuilder(baseBrowser);
286+
if (options.containsKey(BrowserOption.OptionType.TIMEZONE)) {
287+
builder.setSystemTimezone(TimeZone.getTimeZone(
288+
options.get(BrowserOption.OptionType.TIMEZONE)));
289+
} else {
290+
builder.setSystemTimezone(TimeZone.getDefault());
291+
}
292+
if (options.containsKey(BrowserOption.OptionType.LANGUAGE)) {
293+
builder.setBrowserLanguage(options.get(BrowserOption.OptionType.LANGUAGE));
294+
}
295+
BrowserVersion browser = builder.build();
361296
String url = shell.getModuleUrl(moduleName);
362297
HtmlUnitThread hut = createHtmlUnitThread(browser, url);
363298
TreeLogger logger = shell.getTopLogger();
@@ -387,6 +322,6 @@ public boolean setupMode(TreeLogger logger, boolean developmentMode) {
387322
protected HtmlUnitThread createHtmlUnitThread(BrowserVersion browser,
388323
String url) {
389324
return new HtmlUnitThread(browser, url, shell.getTopLogger().branch(
390-
TreeLogger.SPAM, "logging for HtmlUnit thread"), developmentMode);
325+
TreeLogger.SPAM, "logging for HtmlUnit thread"), developmentMode, options);
391326
}
392327
}

user/test/com/google/gwt/emultest/java/util/DateTest.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package com.google.gwt.emultest.java.util;
1717

18+
import com.google.gwt.junit.BrowserOption;
1819
import com.google.gwt.junit.client.GWTTestCase;
1920
import com.google.gwt.testing.TestUtils;
2021

@@ -25,6 +26,8 @@
2526
* Tests for GWT's emulation of the JRE Date class.
2627
*/
2728
@SuppressWarnings("deprecation")
29+
@BrowserOption(type = BrowserOption.OptionType.TIMEZONE,
30+
value = "GMT")
2831
public class DateTest extends GWTTestCase {
2932
public static final String CURRENT = "CURRENT";
3033
public static final String TO_STRING_PATTERN =
@@ -581,7 +584,7 @@ public void testToLocaleString() {
581584
Date accum2 = create(FUTURE);
582585
String a2 = accum2.toLocaleString();
583586
assertTrue(a2 + " should describe 12/30/2030",
584-
a2.contains("2030") || a2.contains("12/30/2030"));
587+
a2.contains("2030") || a2.contains("12/30/30"));
585588
}
586589
}
587590

0 commit comments

Comments
 (0)