Changes the internals of how JUnit works. Previously, each individual test class would run in its own compilation and do a fresh page load. Methods within that class would run within a single compilation and page load. Now, an entire GWT module is compiled, which is capable of running any GWTTestCase class in that entire module. This means any Suite containing classes all from the same GWT module can run entirely in a single compilation. This ends up being much more efficient-- CompilerSuite can run in around 40 seconds in web mode or hosted mode; it would have taken several minutes before.
Implementation notes:
- Prevously, GWTTestCase had dual responsibility for 1) running its own method by name String and 2) handling onModuleLoad and driving the client-side listening process. I split this responsibility into two classes with separate rebinds. GWTRunner now handles onModuleLoad and the drives the whole process, handling all RPCs. The class is also rebound and generated so that it can serve as a factory for instantiating new GWTTestCase subclasses by fully-qualified name String. GWTTestCase subclasses are still rebound and generated to perform the run-by-method-name.
- The server-side RPC had to be refactored to return a class name AND a method name to the client. Previously, the class name was implied by the compilation.
A few other changes in this patch:
- I removed the hackish ModuleDefLoader.forceInherits stuff which we'd been using to shoehorn the JUnit inclusion into other modules. The new pattern is to create a synthetic module and have it inherit both JUnit and the user's module. If a user runs the module "com.example.Foo", the synthetic module will be named "com.example.Foo.JUnit". This has the additional nice feature that it allows compilations to be cached.
- I removed ModuleDefLoader.enableCaching because it's always on now anyway, and Toby made the necessary changes to CacheManager to make it safe.
- GWTShellServlet's call to loadModule does not actually need to refresh on the first load. It doesn't refresh on subsequent accesses, and there's nothing particularly special about the first one.
Review by: tobyr (TBR, partial), mmendez
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@1817 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/cfg/ModuleDefLoader.java b/dev/core/src/com/google/gwt/dev/cfg/ModuleDefLoader.java
index 71bbbbe..66782a3 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/ModuleDefLoader.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/ModuleDefLoader.java
@@ -28,44 +28,62 @@
import java.net.URL;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* The top-level API for loading module XML.
*/
-public class ModuleDefLoader {
-
- // Should always be true. If it is false complete type oracle analysis and
- // bytecode cache reload will occur on each reload.
- private static boolean enableCachingModules = true;
- private static final Set forceInherits = new HashSet();
- private static final Map loadedModules = new HashMap();
+public final class ModuleDefLoader {
/**
- * Forces all modules loaded via subsequent calls to
- * {@link #loadFromClassPath(TreeLogger, String)} to automatically inherit the
- * specified module. If this method is called multiple times, the order of
- * inclusion is unspecified.
- *
- * @param moduleName The module all subsequently loaded modules should inherit
- * from.
+ * Interface to provide a load strategy to the load process.
*/
- public static void forceInherit(String moduleName) {
- forceInherits.add(moduleName);
+ private interface LoadStrategy {
+ /**
+ * Perform loading on the specified module.
+ *
+ * @param logger logs the process
+ * @param moduleName the name of the process
+ * @param moduleDef a module
+ * @throws UnableToCompleteException
+ */
+ void load(TreeLogger logger, String moduleName, ModuleDef moduleDef)
+ throws UnableToCompleteException;
+ }
+
+ private static final Map<String, ModuleDef> loadedModules = new HashMap<String, ModuleDef>();
+
+ /**
+ * Creates a module in memory that is not associated with a
+ * <code>.gwt.xml</code> file on disk.
+ *
+ * @param logger logs the process
+ * @param moduleName the synthetic module to create
+ * @param inherits a set of modules to inherit from
+ * @param refresh whether to refresh the module
+ * @return the loaded module
+ * @throws UnableToCompleteException
+ */
+ public static ModuleDef createSyntheticModule(TreeLogger logger,
+ String moduleName, String[] inherits, boolean refresh)
+ throws UnableToCompleteException {
+ ModuleDef moduleDef = tryGetLoadedModule(logger, moduleName, refresh);
+ if (moduleDef != null) {
+ return moduleDef;
+ }
+ ModuleDefLoader loader = new ModuleDefLoader(inherits);
+ return loader.doLoadModule(logger, moduleName);
}
/**
- * Gets whether module caching is enabled.
+ * Loads a new module from the class path.
*
- * @return <code>true</code> if module cachine is enabled, otherwise
- * <code>false</code>.
+ * @param logger logs the process
+ * @param moduleName the module to load
+ * @return the loaded module
+ * @throws UnableToCompleteException
*/
- public static boolean getEnableCachingModules() {
- return enableCachingModules;
- }
-
public static ModuleDef loadFromClassPath(TreeLogger logger, String moduleName)
throws UnableToCompleteException {
return loadFromClassPath(logger, moduleName, true);
@@ -74,45 +92,69 @@
/**
* Loads a new module from the class path.
*
- * @param logger Logs the process.
- * @param moduleName The module to load.
- * @return The loaded module.
+ * @param logger logs the process
+ * @param moduleName the module to load
+ * @param refresh whether to refresh the module
+ * @return the loaded module
* @throws UnableToCompleteException
*/
public static ModuleDef loadFromClassPath(TreeLogger logger,
String moduleName, boolean refresh) throws UnableToCompleteException {
- ModuleDef moduleDef = (ModuleDef) loadedModules.get(moduleName);
+ ModuleDef moduleDef = tryGetLoadedModule(logger, moduleName, refresh);
+ if (moduleDef != null) {
+ return moduleDef;
+ }
+ ModuleDefLoader loader = new ModuleDefLoader();
+ return loader.doLoadModule(logger, moduleName);
+ }
+
+ private static ModuleDef tryGetLoadedModule(TreeLogger logger,
+ String moduleName, boolean refresh) throws UnableToCompleteException {
+ ModuleDef moduleDef = loadedModules.get(moduleName);
if (moduleDef == null || moduleDef.isGwtXmlFileStale()) {
- moduleDef = new ModuleDefLoader().load(logger, moduleName);
- if (enableCachingModules) {
- loadedModules.put(moduleName, moduleDef);
- }
- } else {
- if (refresh) {
- moduleDef.refresh(logger);
- }
+ return null;
+ } else if (refresh) {
+ moduleDef.refresh(logger);
}
return moduleDef;
}
- /**
- * Enables or disables caching loaded modules for subsequent requests.
- *
- * @param enableCachingModules If <code>true</code> subsequent calls to
- * {@link #loadFromClassPath(TreeLogger, String)} will cause the
- * resulting module to be cached. If <code>false</code> such
- * modules will not be cached.
- */
- public static void setEnableCachingModules(boolean enableCachingModules) {
- ModuleDefLoader.enableCachingModules = enableCachingModules;
- }
-
- private final Set alreadyLoadedModules = new HashSet();
+ private final Set<String> alreadyLoadedModules = new HashSet<String>();
private final ClassLoader classLoader;
+ private final LoadStrategy strategy;
+
+ /**
+ * Constructs a {@link ModuleDefLoader} that loads from the class path.
+ */
private ModuleDefLoader() {
this.classLoader = Thread.currentThread().getContextClassLoader();
+ this.strategy = new LoadStrategy() {
+ public void load(TreeLogger logger, String moduleName, ModuleDef moduleDef)
+ throws UnableToCompleteException {
+ nestedLoad(logger, moduleName, moduleDef);
+ }
+ };
+ }
+
+ /**
+ * Constructs a {@link ModuleDefLoader} that loads a synthetic module.
+ *
+ * @param inherits a set of modules to inherit from
+ */
+ private ModuleDefLoader(final String[] inherits) {
+ this.classLoader = Thread.currentThread().getContextClassLoader();
+ this.strategy = new LoadStrategy() {
+ public void load(TreeLogger logger, String moduleName, ModuleDef moduleDef)
+ throws UnableToCompleteException {
+ for (String inherit : inherits) {
+ TreeLogger branch = logger.branch(TreeLogger.TRACE,
+ "Loading inherited module '" + inherit + "'", null);
+ nestedLoad(branch, inherit, moduleDef);
+ }
+ }
+ };
}
/**
@@ -186,15 +228,14 @@
}
/**
- *
* This method loads a module.
*
* @param logger used to log the loading process
* @param moduleName the name of the module
* @return the module returned -- cannot be null
- * @throws UnableToCompleteException if module loading failed.
+ * @throws UnableToCompleteException if module loading failed
*/
- private ModuleDef load(TreeLogger logger, String moduleName)
+ private ModuleDef doLoadModule(TreeLogger logger, String moduleName)
throws UnableToCompleteException {
logger = logger.branch(TreeLogger.TRACE, "Loading module '" + moduleName
+ "'", null);
@@ -206,18 +247,12 @@
}
ModuleDef moduleDef = new ModuleDef(moduleName);
- for (Iterator it = forceInherits.iterator(); it.hasNext();) {
- String forceInherit = (String) it.next();
- TreeLogger branch = logger.branch(TreeLogger.TRACE,
- "Loading forceably inherited module '" + forceInherit + "'", null);
- nestedLoad(branch, forceInherit, moduleDef);
- }
- nestedLoad(logger, moduleName, moduleDef);
+ strategy.load(logger, moduleName, moduleDef);
// Do any final setup.
//
moduleDef.normalize(logger);
-
+ loadedModules.put(moduleName, moduleDef);
return moduleDef;
}
}
diff --git a/dev/core/src/com/google/gwt/dev/shell/GWTShellServlet.java b/dev/core/src/com/google/gwt/dev/shell/GWTShellServlet.java
index 5e1535b..bb97ce3 100644
--- a/dev/core/src/com/google/gwt/dev/shell/GWTShellServlet.java
+++ b/dev/core/src/com/google/gwt/dev/shell/GWTShellServlet.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -549,7 +549,7 @@
synchronized (loadedModulesByName) {
ModuleDef moduleDef = loadedModulesByName.get(moduleName);
if (moduleDef == null) {
- moduleDef = ModuleDefLoader.loadFromClassPath(logger, moduleName);
+ moduleDef = ModuleDefLoader.loadFromClassPath(logger, moduleName, false);
loadedModulesByName.put(moduleName, moduleDef);
// BEGIN BACKWARD COMPATIBILITY
diff --git a/dev/core/src/com/google/gwt/dev/shell/ShellModuleSpaceHost.java b/dev/core/src/com/google/gwt/dev/shell/ShellModuleSpaceHost.java
index a9e79d6..c912fca 100644
--- a/dev/core/src/com/google/gwt/dev/shell/ShellModuleSpaceHost.java
+++ b/dev/core/src/com/google/gwt/dev/shell/ShellModuleSpaceHost.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -19,7 +19,6 @@
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.dev.cfg.ModuleDef;
-import com.google.gwt.dev.cfg.ModuleDefLoader;
import com.google.gwt.dev.cfg.Rules;
import com.google.gwt.dev.jdt.ByteCodeCompiler;
import com.google.gwt.dev.jdt.RebindOracle;
@@ -138,9 +137,7 @@
compiler = byteCodeCompilersByModule.get(module);
if (compiler == null) {
compiler = new ByteCodeCompiler(srcOracle, module.getCacheManager());
- if (ModuleDefLoader.getEnableCachingModules()) {
- byteCodeCompilersByModule.put(module, compiler);
- }
+ byteCodeCompilersByModule.put(module, compiler);
}
}
return compiler;
diff --git a/dev/core/test/com/google/gwt/core/ext/typeinfo/TypeOracleAnnotationSupportTest.java b/dev/core/test/com/google/gwt/core/ext/typeinfo/TypeOracleAnnotationSupportTest.java
index 6da80ab..ba170c0 100644
--- a/dev/core/test/com/google/gwt/core/ext/typeinfo/TypeOracleAnnotationSupportTest.java
+++ b/dev/core/test/com/google/gwt/core/ext/typeinfo/TypeOracleAnnotationSupportTest.java
@@ -39,9 +39,6 @@
* Array annotations Enum annotations String from field annotations
*/
public class TypeOracleAnnotationSupportTest extends TestCase {
- static {
- ModuleDefLoader.setEnableCachingModules(true);
- }
private static void validateAnnotation(HasAnnotations annotatedElement,
String testAnnotationValue, String nestedAnnotationValue,
diff --git a/user/src/com/google/gwt/junit/JUnit.gwt.xml b/user/src/com/google/gwt/junit/JUnit.gwt.xml
index 5bf1e50..f03417d 100644
--- a/user/src/com/google/gwt/junit/JUnit.gwt.xml
+++ b/user/src/com/google/gwt/junit/JUnit.gwt.xml
@@ -1,5 +1,5 @@
<!-- -->
-<!-- Copyright 2007 Google Inc. -->
+<!-- Copyright 2008 Google Inc. -->
<!-- Licensed under the Apache License, Version 2.0 (the "License"); you -->
<!-- may not use this file except in compliance with the License. You may -->
<!-- may obtain a copy of the License at -->
@@ -23,6 +23,10 @@
<source path="client"/>
+ <generate-with class="com.google.gwt.junit.rebind.GWTRunnerGenerator">
+ <when-type-is class="com.google.gwt.junit.client.impl.GWTRunner"/>
+ </generate-with>
+
<generate-with class="com.google.gwt.junit.rebind.JUnitTestCaseStubGenerator">
<when-type-assignable class="com.google.gwt.junit.client.GWTTestCase"/>
</generate-with>
diff --git a/user/src/com/google/gwt/junit/JUnitMessageQueue.java b/user/src/com/google/gwt/junit/JUnitMessageQueue.java
index 7e52a0f..bbd3a51 100644
--- a/user/src/com/google/gwt/junit/JUnitMessageQueue.java
+++ b/user/src/com/google/gwt/junit/JUnitMessageQueue.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -16,6 +16,7 @@
package com.google.gwt.junit;
import com.google.gwt.junit.client.TestResults;
+import com.google.gwt.junit.client.impl.JUnitHost.TestInfo;
import java.util.ArrayList;
import java.util.Collection;
@@ -45,7 +46,7 @@
* Key = client-id (e.g. agent+host) Value = the index of the current
* requested test
*/
- private Map<String,Integer> clientTestRequests = new HashMap<String,Integer>();
+ private Map<String, Integer> clientTestRequests = new HashMap<String, Integer>();
/**
* The index of the current test being executed.
@@ -69,6 +70,11 @@
private Object resultsLock = new Object();
/**
+ * The name of the module to execute.
+ */
+ private String testModule;
+
+ /**
* The name of the test class to execute.
*/
private String testClass;
@@ -92,7 +98,7 @@
}
/**
- * Only instantiatable within this package.
+ * Only instantiable within this package.
*
* @param numClients The number of parallel clients being served by this
* queue.
@@ -104,17 +110,17 @@
/**
* Called by the servlet to query for for the next method to test.
*
- * @param testClassName The name of the test class.
- * @param timeout How long to wait for an answer.
- * @return The next test to run, or <code>null</code> if
+ * @param moduleName the name of the executing module
+ * @param timeout how long to wait for an answer
+ * @return the next test to run, or <code>null</code> if
* <code>timeout</code> is exceeded or the next test does not match
- * <code>testClassName</code>.
+ * <code>testClassName</code>
*/
- public String getNextTestName(String clientId, String testClassName,
+ public TestInfo getNextTestInfo(String clientId, String moduleName,
long timeout) {
synchronized (readTestLock) {
long stopTime = System.currentTimeMillis() + timeout;
- while (!testIsAvailableFor(clientId, testClassName)) {
+ while (!testIsAvailableFor(clientId, moduleName)) {
long timeToWait = stopTime - System.currentTimeMillis();
if (timeToWait < 1) {
return null;
@@ -127,25 +133,25 @@
}
}
- if (!testClassName.equals(testClass)) {
+ if (!moduleName.equals(testModule)) {
// it's an old client that is now done
return null;
}
bumpClientTestRequest(clientId);
- return testMethod;
+ return new TestInfo(testClass, testMethod);
}
}
/**
* Called by the servlet to report the results of the last test to run.
*
- * @param testClassName The name of the test class.
- * @param results The result of running the test.
+ * @param moduleName the name of the test module
+ * @param results the result of running the test
*/
- public void reportResults(String testClassName, TestResults results) {
+ public void reportResults(String moduleName, TestResults results) {
synchronized (resultsLock) {
- if (!testClassName.equals(testClass)) {
+ if (!moduleName.equals(testModule)) {
// an old client is trying to report results, do nothing
return;
}
@@ -156,25 +162,25 @@
/**
* Fetches the results of a completed test.
*
- * @param testClassName The name of the test class.
+ * @param moduleName the name of the test module
* @return An getException thrown from a failed test, or <code>null</code>
* if the test completed without error.
*/
- List<TestResults> getResults(String testClassName) {
- assert (testClassName.equals(testClass));
+ List<TestResults> getResults(String moduleName) {
+ assert (moduleName.equals(testModule));
return testResults;
}
/**
* Called by the shell to see if the currently-running test has completed.
*
- * @param testClassName The name of the test class.
+ * @param moduleName the name of the test module
* @return If the test has completed, <code>true</code>, otherwise
* <code>false</code>.
*/
- boolean hasResult(String testClassName) {
+ boolean hasResult(String moduleName) {
synchronized (resultsLock) {
- assert (testClassName.equals(testClass));
+ assert (moduleName.equals(testModule));
return testResults.size() == numClients;
}
}
@@ -207,10 +213,11 @@
* @param testClassName The name of the test class.
* @param testName The name of the method to run.
*/
- void setNextTestName(String testClassName, String testName) {
+ void setNextTestName(String testModule, String testClass, String testMethod) {
synchronized (readTestLock) {
- testClass = testClassName;
- testMethod = testName;
+ this.testModule = testModule;
+ this.testClass = testClass;
+ this.testMethod = testMethod;
++currentTestIndex;
testResults = new ArrayList<TestResults>(numClients);
readTestLock.notifyAll();
@@ -234,8 +241,8 @@
}
// This method requires that readTestLock is being held for the duration.
- private boolean testIsAvailableFor(String clientId, String testClassName) {
- if (!testClassName.equals(testClass)) {
+ private boolean testIsAvailableFor(String clientId, String moduleName) {
+ if (!moduleName.equals(testModule)) {
// the "null" test is always available for an old client
return true;
}
diff --git a/user/src/com/google/gwt/junit/JUnitShell.java b/user/src/com/google/gwt/junit/JUnitShell.java
index eef143b..99b370c 100644
--- a/user/src/com/google/gwt/junit/JUnitShell.java
+++ b/user/src/com/google/gwt/junit/JUnitShell.java
@@ -31,6 +31,7 @@
import com.google.gwt.junit.client.TestResults;
import com.google.gwt.junit.client.TimeoutException;
import com.google.gwt.junit.client.Trial;
+import com.google.gwt.junit.client.impl.GWTRunner;
import com.google.gwt.junit.remote.BrowserManager;
import com.google.gwt.util.tools.ArgHandlerFlag;
import com.google.gwt.util.tools.ArgHandlerString;
@@ -126,11 +127,6 @@
*/
private static JUnitShell unitTestShell;
- static {
- ModuleDefLoader.forceInherit("com.google.gwt.junit.JUnit");
- ModuleDefLoader.setEnableCachingModules(true);
- }
-
/**
* Called by {@link com.google.gwt.junit.server.JUnitHostImpl} to get an
* interface into the test process.
@@ -242,11 +238,6 @@
private long testBeginTimeout;
/**
- * Class name of the current/last test case to run.
- */
- private String testCaseClassName;
-
- /**
* Enforce the singleton pattern. The call to {@link GWTShell}'s ctor forces
* server mode and disables processing extra arguments as URLs to be shown.
*/
@@ -358,28 +349,6 @@
}
/**
- * Overrides the default module loading behavior. Clears any existing entry
- * points and adds an entry point for the class being tested. This test class
- * is then rebound to a generated subclass.
- */
- @Override
- protected ModuleDef doLoadModule(TreeLogger logger, String moduleName)
- throws UnableToCompleteException {
-
- // We don't refresh modules while running unit tests
- ModuleDef module = ModuleDefLoader.loadFromClassPath(logger, moduleName,
- false);
-
- // Tweak the module for JUnit support
- //
- if (moduleName.equals(currentModuleName)) {
- module.clearEntryPoints();
- module.addEntryPointTypeName(testCaseClassName);
- }
- return module;
- }
-
- /**
* Never check for updates in JUnit mode.
*/
@Override
@@ -420,7 +389,7 @@
+ TEST_BEGIN_TIMEOUT_MILLIS + "ms.");
}
- if (messageQueue.hasResult(testCaseClassName)) {
+ if (messageQueue.hasResult(currentModuleName)) {
return false;
}
@@ -448,19 +417,37 @@
private void runTestImpl(String moduleName, TestCase testCase,
TestResult testResult) throws UnableToCompleteException {
- String newTestCaseClassName = testCase.getClass().getName();
- boolean sameTest = newTestCaseClassName.equals(testCaseClassName);
+ String syntheticModuleName = moduleName + ".JUnit";
+ boolean sameTest = syntheticModuleName.equals(currentModuleName);
if (sameTest && lastLaunchFailed) {
throw new UnableToCompleteException();
}
+ currentModuleName = syntheticModuleName;
- messageQueue.setNextTestName(newTestCaseClassName, testCase.getName());
+ if (!sameTest) {
+ /*
+ * Synthesize a synthetic module that derives from the user-specified
+ * module but also includes JUnit support.
+ */
+ ModuleDef synthetic = ModuleDefLoader.createSyntheticModule(
+ getTopLogger(), currentModuleName, new String[] {
+ moduleName, "com.google.gwt.junit.JUnit"}, true);
+ // Replace any user entry points with our test runner.
+ synthetic.clearEntryPoints();
+ synthetic.addEntryPointTypeName(GWTRunner.class.getName());
+ // Squirrel away the name of the active module for GWTRunnerGenerator
+ Property moduleNameProp = synthetic.getProperties().create(
+ "junit.moduleName");
+ moduleNameProp.addKnownValue(moduleName);
+ moduleNameProp.setActiveValue(moduleName);
+ }
+
+ lastLaunchFailed = false;
+ messageQueue.setNextTestName(currentModuleName,
+ testCase.getClass().getName(), testCase.getName());
try {
- lastLaunchFailed = false;
- testCaseClassName = newTestCaseClassName;
- currentModuleName = moduleName;
- runStyle.maybeLaunchModule(moduleName, !sameTest);
+ runStyle.maybeLaunchModule(currentModuleName, !sameTest);
} catch (UnableToCompleteException e) {
lastLaunchFailed = true;
testResult.addError(testCase, e);
@@ -479,7 +466,7 @@
return;
}
- List<TestResults> results = messageQueue.getResults(testCaseClassName);
+ List<TestResults> results = messageQueue.getResults(currentModuleName);
if (results == null) {
return;
diff --git a/user/src/com/google/gwt/junit/client/GWTTestCase.java b/user/src/com/google/gwt/junit/client/GWTTestCase.java
index 9c6b0f1..8a90ee8 100644
--- a/user/src/com/google/gwt/junit/client/GWTTestCase.java
+++ b/user/src/com/google/gwt/junit/client/GWTTestCase.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -178,17 +178,6 @@
}
/**
- * Returns the overall test results for this unit test.
- *
- * These TestResults are more comprehensive than JUnit's default test results,
- * and are automatically collected by GWT's testing infrastructure.
- */
- protected final TestResults getTestResults() {
- // implemented in the translatable version of this class
- return null;
- }
-
- /**
* Runs the test via the {@link JUnitShell} environment.
*/
@Override
diff --git a/user/src/com/google/gwt/junit/client/impl/GWTRunner.java b/user/src/com/google/gwt/junit/client/impl/GWTRunner.java
new file mode 100644
index 0000000..33c701b
--- /dev/null
+++ b/user/src/com/google/gwt/junit/client/impl/GWTRunner.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.junit.client.impl;
+
+import com.google.gwt.core.client.EntryPoint;
+
+/**
+ * A stub for the translatable GWTRunner entry point.
+ *
+ * <p>
+ * There are two versions of this class. This version is the binary version that
+ * just serves as a stub. The other version is a translatable class that is used
+ * within the browser. See the <code>translatable</code> subpackage for the
+ * translatable implementation.
+ * </p>
+ *
+ */
+public class GWTRunner implements EntryPoint {
+
+ public void onModuleLoad() {
+ }
+
+}
diff --git a/user/src/com/google/gwt/junit/client/impl/JUnitHost.java b/user/src/com/google/gwt/junit/client/impl/JUnitHost.java
index 4e76afe..7e92793 100644
--- a/user/src/com/google/gwt/junit/client/impl/JUnitHost.java
+++ b/user/src/com/google/gwt/junit/client/impl/JUnitHost.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -15,30 +15,58 @@
*/
package com.google.gwt.junit.client.impl;
+import com.google.gwt.user.client.rpc.IsSerializable;
import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.junit.client.TestResults;
/**
- * An interface for {@link com.google.gwt.junit.client.GWTTestCase} to communicate with the test process
- * through RPC.
+ * An interface for {@link com.google.gwt.junit.client.GWTTestCase} to
+ * communicate with the test process through RPC.
*/
public interface JUnitHost extends RemoteService {
/**
+ * Returned from the server to tell the system what test to run next.
+ */
+ public static class TestInfo implements IsSerializable {
+ private String testClass;
+ private String testMethod;
+
+ public TestInfo(String testClass, String testMethod) {
+ this.testClass = testClass;
+ this.testMethod = testMethod;
+ }
+
+ /**
+ * Constructor for serialization.
+ */
+ TestInfo() {
+ }
+
+ public String getTestClass() {
+ return testClass;
+ }
+
+ public String getTestMethod() {
+ return testMethod;
+ }
+ }
+
+ /**
* Gets the name of next method to run.
*
- * @param testClassName The class name of the calling test case.
- * @return the name of the next method to run.
+ * @param moduleName the module name of this client
+ * @return the next test to run
*/
- String getFirstMethod(String testClassName);
+ TestInfo getFirstMethod(String moduleName);
/**
* Reports results for the last method run and gets the name of next method to
* run.
*
- * @param testClassName The class name of the calling test case.
+ * @param moduleName the module name of this client
* @param results The results of executing the test
- * @return the name of the next method to run.
+ * @return the next test to run
*/
- String reportResultsAndGetNextMethod(String testClassName, TestResults results);
+ TestInfo reportResultsAndGetNextMethod(String moduleName, TestResults results);
}
diff --git a/user/src/com/google/gwt/junit/client/impl/JUnitHostAsync.java b/user/src/com/google/gwt/junit/client/impl/JUnitHostAsync.java
index 6954c7b..e27baaf 100644
--- a/user/src/com/google/gwt/junit/client/impl/JUnitHostAsync.java
+++ b/user/src/com/google/gwt/junit/client/impl/JUnitHostAsync.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -15,8 +15,9 @@
*/
package com.google.gwt.junit.client.impl;
-import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.junit.client.TestResults;
+import com.google.gwt.junit.client.impl.JUnitHost.TestInfo;
+import com.google.gwt.user.client.rpc.AsyncCallback;
/**
* The asynchronous version of {@link JUnitHost}.
@@ -25,22 +26,22 @@
/**
* Gets the name of next method to run.
- *
- * @param testClassName The class name of the calling test case.
- * @param callBack The object that will receive the name of the next
- * method to run.
+ *
+ * @param moduleName the module name of this client
+ * @param callBack The object that will receive the name of the next method to
+ * run.
*/
- void getFirstMethod(String testClassName, AsyncCallback<String> callBack);
+ void getFirstMethod(String moduleName, AsyncCallback<TestInfo> callBack);
/**
* Reports results for the last method run and gets the name of next method to
* run.
- *
- * @param testClassName The class name of the calling test case.
- * @param results The results of the test.
- * @param callBack The object that will receive the name of the next
- * method to run.
+ *
+ * @param moduleName the module name of this client
+ * @param results The results of the test.
+ * @param callBack The object that will receive the name of the next method to
+ * run.
*/
- void reportResultsAndGetNextMethod(String testClassName, TestResults results,
- AsyncCallback<String> callBack);
+ void reportResultsAndGetNextMethod(String moduleName, TestResults results,
+ AsyncCallback<TestInfo> callBack);
}
diff --git a/user/src/com/google/gwt/junit/rebind/BenchmarkGenerator.java b/user/src/com/google/gwt/junit/rebind/BenchmarkGenerator.java
index 2982f44..0a6959d 100644
--- a/user/src/com/google/gwt/junit/rebind/BenchmarkGenerator.java
+++ b/user/src/com/google/gwt/junit/rebind/BenchmarkGenerator.java
@@ -18,30 +18,30 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.JField;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.JParameter;
-import com.google.gwt.core.ext.typeinfo.JField;
-import com.google.gwt.junit.JUnitShell;
-import com.google.gwt.junit.client.annotations.IterationTimeLimit;
-import com.google.gwt.junit.client.annotations.Setup;
-import com.google.gwt.junit.client.annotations.Teardown;
-import com.google.gwt.junit.client.annotations.RangeField;
-import com.google.gwt.junit.client.annotations.RangeEnum;
-import com.google.gwt.junit.client.Benchmark;
import com.google.gwt.dev.generator.ast.ForLoop;
import com.google.gwt.dev.generator.ast.MethodCall;
import com.google.gwt.dev.generator.ast.Statement;
import com.google.gwt.dev.generator.ast.Statements;
import com.google.gwt.dev.generator.ast.StatementsList;
+import com.google.gwt.junit.JUnitShell;
+import com.google.gwt.junit.client.Benchmark;
+import com.google.gwt.junit.client.annotations.IterationTimeLimit;
+import com.google.gwt.junit.client.annotations.RangeEnum;
+import com.google.gwt.junit.client.annotations.RangeField;
+import com.google.gwt.junit.client.annotations.Setup;
+import com.google.gwt.junit.client.annotations.Teardown;
import com.google.gwt.user.rebind.SourceWriter;
-import java.util.Map;
-import java.util.List;
-import java.util.Set;
-import java.util.HashMap;
+import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
-import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
/**
* Implements a generator for Benchmark classes. Benchmarks require additional
@@ -241,8 +241,7 @@
* wrapped <code>stmts</code>
*/
private Statements benchmark(Statements stmts, String timeMillisName,
- long bound, Statements recordCode, Statements breakCode)
- throws UnableToCompleteException {
+ long bound, Statements recordCode, Statements breakCode) {
Statements benchmarkCode = new StatementsList();
List<Statements> benchStatements = benchmarkCode.getStatements();
@@ -324,11 +323,16 @@
* entering async mode in their Benchmark, even though we're using it
* internally.
*
+ * <p>
* Generates the code for the "supportsAsync" functionality in the
* translatable version of GWTTestCase. This includes:
- * - the supportsAsync flag - the supportsAsync method - the
- * privateDelayTestFinish method - the privateFinishTest method
- *
+ * <ul>
+ * <li>the supportsAsync flag</li>
+ * <li>the supportsAsync method</li>
+ * <li>the privateDelayTestFinish method</li>
+ * <li>the privateFinishTest method</li>
+ * </ul>
+ * </p>
*/
private void generateAsyncCode() {
SourceWriter writer = getSourceWriter();
@@ -584,7 +588,7 @@
new Statement(new MethodCall(method.getName(), paramNames)));
StringBuffer recordResultsCode = new StringBuffer(
- "com.google.gwt.junit.client.TestResults results = getTestResults();\n"
+ "com.google.gwt.junit.client.TestResults results = impl.getTestResults();\n"
+ "com.google.gwt.junit.client.Trial trial = new com.google.gwt.junit.client.Trial();\n"
+ "trial.setRunTimeMillis( "
+ testTimingName
@@ -659,7 +663,7 @@
Statements testBench = genBenchTarget(beginMethod, endMethod,
Collections.<String> emptyList(), testStatements);
- String recordResultsCode = "com.google.gwt.junit.client.TestResults results = getTestResults();\n"
+ String recordResultsCode = "com.google.gwt.junit.client.TestResults results = impl.getTestResults();\n"
+ "com.google.gwt.junit.client.Trial trial = new com.google.gwt.junit.client.Trial();\n"
+ "trial.setRunTimeMillis( "
+ testTimingName
diff --git a/user/src/com/google/gwt/junit/rebind/GWTRunnerGenerator.java b/user/src/com/google/gwt/junit/rebind/GWTRunnerGenerator.java
new file mode 100644
index 0000000..a523d85
--- /dev/null
+++ b/user/src/com/google/gwt/junit/rebind/GWTRunnerGenerator.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.junit.rebind;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.ext.BadPropertyValueException;
+import com.google.gwt.core.ext.Generator;
+import com.google.gwt.core.ext.GeneratorContext;
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.NotFoundException;
+import com.google.gwt.core.ext.typeinfo.TypeOracle;
+import com.google.gwt.dev.util.PerfLogger;
+import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.junit.client.impl.GWTRunner;
+import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
+import com.google.gwt.user.rebind.SourceWriter;
+
+import java.io.PrintWriter;
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ * This class generates a stub class for classes that derive from GWTTestCase.
+ * This stub class provides the necessary bridge between our Hosted or Hybrid
+ * mode classes and the JUnit system.
+ *
+ */
+public class GWTRunnerGenerator extends Generator {
+
+ private static final String GWT_RUNNER_NAME = GWTRunner.class.getName();
+
+ /**
+ * Create a new type that satisfies the rebind request.
+ */
+ @Override
+ public String generate(TreeLogger logger, GeneratorContext context,
+ String typeName) throws UnableToCompleteException {
+
+ if (!GWT_RUNNER_NAME.equals(typeName)) {
+ logger.log(TreeLogger.ERROR, "This generator may only be used with "
+ + GWT_RUNNER_NAME, null);
+ throw new UnableToCompleteException();
+ }
+
+ JClassType requestedClass;
+ try {
+ requestedClass = context.getTypeOracle().getType(typeName);
+ } catch (NotFoundException e) {
+ logger.log(
+ TreeLogger.ERROR,
+ "Could not find type '"
+ + typeName
+ + "'; please see the log, as this usually indicates a previous error ",
+ e);
+ throw new UnableToCompleteException();
+ }
+
+ String moduleName;
+ try {
+ moduleName = context.getPropertyOracle().getPropertyValue(logger,
+ "junit.moduleName");
+ } catch (BadPropertyValueException e) {
+ logger.log(TreeLogger.ERROR,
+ "Could not resolve junit.moduleName property", e);
+ throw new UnableToCompleteException();
+ }
+
+ // Get the stub class name, and see if its source file exists.
+ //
+ String generatedClass = requestedClass.getSimpleSourceName() + "Impl";
+ String packageName = requestedClass.getPackage().getName();
+ String qualifiedStubClassName = packageName + "." + generatedClass;
+
+ SourceWriter sourceWriter = getSourceWriter(logger, context, packageName,
+ generatedClass, GWT_RUNNER_NAME);
+
+ if (sourceWriter != null) {
+ PerfLogger.start("GWTRunnerGenerator");
+ JClassType[] allTestTypes = getAllTestTypes(context.getTypeOracle());
+ Set<String> testClasses = getTestTypesForModule(logger, moduleName,
+ allTestTypes);
+ writeCreateNewTestCaseMethod(testClasses, sourceWriter);
+ sourceWriter.commit(logger);
+ PerfLogger.end();
+ }
+
+ return qualifiedStubClassName;
+ }
+
+ private JClassType[] getAllTestTypes(TypeOracle typeOracle) {
+ PerfLogger.start("GWTRunnerGenerator.getAllTestTypes");
+ JClassType gwtTestType = typeOracle.findType(GWTTestCase.class.getName());
+ PerfLogger.end();
+ if (gwtTestType != null) {
+ return gwtTestType.getSubtypes();
+ } else {
+ return new JClassType[0];
+ }
+ }
+
+ private SourceWriter getSourceWriter(TreeLogger logger, GeneratorContext ctx,
+ String packageName, String className, String superclassName) {
+ PrintWriter printWriter = ctx.tryCreate(logger, packageName, className);
+ if (printWriter == null) {
+ return null;
+ }
+
+ ClassSourceFileComposerFactory composerFactory = new ClassSourceFileComposerFactory(
+ packageName, className);
+ composerFactory.setSuperclass(superclassName);
+ composerFactory.addImport(GWTTestCase.class.getName());
+ composerFactory.addImport(GWT.class.getName());
+ return composerFactory.createSourceWriter(ctx, printWriter);
+ }
+
+ private Set<String> getTestTypesForModule(TreeLogger logger,
+ String moduleName, JClassType[] allTestTypes) {
+ PerfLogger.start("GWTRunnerGenerator.getTestTypesForModule");
+ // Must use sorted set to prevent nondeterminism.
+ Set<String> testClasses = new TreeSet<String>();
+ for (JClassType classType : allTestTypes) {
+ if (!classType.isPublic() || classType.isAbstract()
+ || !classType.isDefaultInstantiable()) {
+ continue;
+ }
+
+ String className = classType.getQualifiedSourceName();
+
+ try {
+ Class<?> testClass = Class.forName(className);
+ GWTTestCase instantiated = (GWTTestCase) testClass.newInstance();
+ if (!moduleName.equals(instantiated.getModuleName())) {
+ continue;
+ }
+ } catch (Throwable e) {
+ logger.log(
+ TreeLogger.INFO,
+ "Error determining if test class '"
+ + className
+ + "' is a part of the current module; skipping; expect subsequent errors if this test class is run",
+ e);
+ continue;
+ }
+ testClasses.add(className);
+ }
+ PerfLogger.end();
+ return testClasses;
+ }
+
+ private void writeCreateNewTestCaseMethod(Set<String> testClasses,
+ SourceWriter sw) {
+ PerfLogger.start("GWTRunnerGenerator.writeCreateNewTestCaseMethod");
+ sw.println();
+ sw.println("protected final GWTTestCase createNewTestCase(String testClass) {");
+ sw.indent();
+ boolean isFirst = true;
+ for (String className : testClasses) {
+ if (isFirst) {
+ isFirst = false;
+ } else {
+ sw.print("else ");
+ }
+
+ sw.println("if (testClass.equals(\"" + className + "\")) {");
+ sw.indentln("return GWT.create(" + className + ".class);");
+ sw.println("}");
+ }
+ sw.println("return null;");
+ sw.outdent();
+ sw.println("}");
+ PerfLogger.end();
+ }
+}
diff --git a/user/src/com/google/gwt/junit/rebind/JUnitTestCaseStubGenerator.java b/user/src/com/google/gwt/junit/rebind/JUnitTestCaseStubGenerator.java
index bd80d6c..96613f8 100644
--- a/user/src/com/google/gwt/junit/rebind/JUnitTestCaseStubGenerator.java
+++ b/user/src/com/google/gwt/junit/rebind/JUnitTestCaseStubGenerator.java
@@ -21,17 +21,17 @@
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
+import com.google.gwt.core.ext.typeinfo.JParameter;
import com.google.gwt.core.ext.typeinfo.NotFoundException;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
-import com.google.gwt.core.ext.typeinfo.JParameter;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;
import java.io.PrintWriter;
-import java.util.Map;
import java.util.ArrayList;
-import java.util.List;
import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
/**
* This class generates a stub class for classes that derive from GWTTestCase.
@@ -44,8 +44,6 @@
boolean accept(JMethod method);
}
- private static final String GWT_TESTCASE_CLASS_NAME = "com.google.gwt.junit.client.GWTTestCase";
-
/**
* Returns the method names for the set of methods that are strictly JUnit
* test methods (have no arguments).
@@ -61,17 +59,16 @@
}
/**
- * Like JClassType.getMethod( String name ), except:
+ * Like JClassType.getMethod(String name) except:
*
* <li>it accepts a filter</li>
- * <li>it searches the inheritance hierarchy (includes subclasses)</li>
+ * <li>it searches the inheritance hierarchy (includes superclasses)</li>
*
- * For methods which are overriden, only the most derived implementations are
+ * For methods which are overridden, only the most derived implementations are
* included.
*
- * @param type The type to search. Must not be null
- * @return Map<String.List<JMethod>> The set of matching methods. Will not
- * be null.
+ * @param type the type to search (non-null)
+ * @return the set of matching methods (non-null)
*/
static Map<String, List<JMethod>> getAllMethods(JClassType type,
MethodFilter filter) {
@@ -153,11 +150,10 @@
return true;
}
- TreeLogger logger;
- String packageName;
- String qualifiedStubClassName;
- String simpleStubClassName;
- String typeName;
+ protected TreeLogger logger;
+ private String packageName;
+ private String qualifiedStubClassName;
+ private String simpleStubClassName;
private JClassType requestedClass;
private SourceWriter sourceWriter;
@@ -180,22 +176,49 @@
return qualifiedStubClassName;
}
- public JClassType getRequestedClass() {
+ protected JClassType getRequestedClass() {
return requestedClass;
}
- public SourceWriter getSourceWriter() {
+ protected SourceWriter getSourceWriter() {
return sourceWriter;
}
- public TypeOracle getTypeOracle() {
+ protected TypeOracle getTypeOracle() {
return typeOracle;
}
- boolean init(TreeLogger logger, GeneratorContext context, String typeName)
- throws UnableToCompleteException {
+ @SuppressWarnings("unused")
+ protected void writeSource() throws UnableToCompleteException {
+ String[] testMethods = getTestMethodNames(requestedClass);
+ writeDoRunTestMethod(testMethods, sourceWriter);
+ }
- this.typeName = typeName;
+ /**
+ * Gets the name of the native stub class.
+ */
+ private String getSimpleStubClassName(JClassType baseClass) {
+ return "__" + baseClass.getSimpleSourceName() + "_unitTestImpl";
+ }
+
+ private SourceWriter getSourceWriter(TreeLogger logger, GeneratorContext ctx,
+ String packageName, String className, String superclassName) {
+
+ PrintWriter printWriter = ctx.tryCreate(logger, packageName, className);
+ if (printWriter == null) {
+ return null;
+ }
+
+ ClassSourceFileComposerFactory composerFactory = new ClassSourceFileComposerFactory(
+ packageName, className);
+
+ composerFactory.setSuperclass(superclassName);
+
+ return composerFactory.createSourceWriter(ctx, printWriter);
+ }
+
+ private boolean init(TreeLogger logger, GeneratorContext context,
+ String typeName) throws UnableToCompleteException {
this.logger = logger;
typeOracle = context.getTypeOracle();
assert typeOracle != null;
@@ -224,37 +247,6 @@
return sourceWriter != null;
}
- @SuppressWarnings("unused")
- void writeSource() throws UnableToCompleteException {
- String[] testMethods = getTestMethodNames(requestedClass);
- writeGetNewTestCase(simpleStubClassName, sourceWriter);
- writeDoRunTestMethod(testMethods, sourceWriter);
- writeGetTestName(typeName, sourceWriter);
- }
-
- /**
- * Gets the name of the native stub class.
- */
- private String getSimpleStubClassName(JClassType baseClass) {
- return "__" + baseClass.getSimpleSourceName() + "_unitTestImpl";
- }
-
- private SourceWriter getSourceWriter(TreeLogger logger, GeneratorContext ctx,
- String packageName, String className, String superclassName) {
-
- PrintWriter printWriter = ctx.tryCreate(logger, packageName, className);
- if (printWriter == null) {
- return null;
- }
-
- ClassSourceFileComposerFactory composerFactory = new ClassSourceFileComposerFactory(
- packageName, className);
-
- composerFactory.setSuperclass(superclassName);
-
- return composerFactory.createSourceWriter(ctx, printWriter);
- }
-
private void writeDoRunTestMethod(String[] testMethodNames, SourceWriter sw) {
sw.println();
sw.println("protected final void doRunTest(String name) throws Throwable {");
@@ -274,30 +266,4 @@
sw.println("}"); // finish doRunTest();
}
- /**
- * Create the appMain method that is the main entry point for the GWT
- * application.
- */
- private void writeGetNewTestCase(String stubClassName, SourceWriter sw) {
- sw.println();
- sw.println("public final " + GWT_TESTCASE_CLASS_NAME
- + " getNewTestCase() {");
- sw.indent();
- sw.println("return new " + stubClassName + "();");
- sw.outdent();
- sw.println("}"); // finish getNewTestCase();
- }
-
- /**
- * Create the appMain method that is the main entry point for the GWT
- * application.
- */
- private void writeGetTestName(String testClassName, SourceWriter sw) {
- sw.println();
- sw.println("public final String getTestName() {");
- sw.indent();
- sw.println("return \"" + testClassName + "\";");
- sw.outdent();
- sw.println("}"); // finish getNewTestCase();
- }
}
diff --git a/user/src/com/google/gwt/junit/server/JUnitHostImpl.java b/user/src/com/google/gwt/junit/server/JUnitHostImpl.java
index 7339e35..ff43a9e 100644
--- a/user/src/com/google/gwt/junit/server/JUnitHostImpl.java
+++ b/user/src/com/google/gwt/junit/server/JUnitHostImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -45,10 +45,6 @@
*/
private static final int TIME_TO_WAIT_FOR_TESTNAME = 300000;
- // DEBUG timeout
- // TODO(tobyr) Make this configurable
- // private static final int TIME_TO_WAIT_FOR_TESTNAME = 500000;
-
/**
* A hook into GWTUnitTestShell, the underlying unit test process.
*/
@@ -80,13 +76,11 @@
fld.set(obj, value);
}
- public String getFirstMethod(String testClassName) {
- return getHost().getNextTestName(getClientId(), testClassName,
- TIME_TO_WAIT_FOR_TESTNAME);
+ public TestInfo getFirstMethod(String moduleName) {
+ return getHost().getNextTestInfo(getClientId(), moduleName, TIME_TO_WAIT_FOR_TESTNAME);
}
- public String reportResultsAndGetNextMethod(String testClassName,
- TestResults results) {
+ public TestInfo reportResultsAndGetNextMethod(String moduleName, TestResults results) {
JUnitMessageQueue host = getHost();
HttpServletRequest request = getThreadLocalRequest();
String agent = request.getHeader("User-Agent");
@@ -98,9 +92,8 @@
ExceptionWrapper ew = trial.getExceptionWrapper();
trial.setException(deserialize(ew));
}
- host.reportResults(testClassName, results);
- return host.getNextTestName(getClientId(), testClassName,
- TIME_TO_WAIT_FOR_TESTNAME);
+ host.reportResults(moduleName, results);
+ return host.getNextTestInfo(getClientId(), moduleName, TIME_TO_WAIT_FOR_TESTNAME);
}
/**
diff --git a/user/super/com/google/gwt/junit/translatable/com/google/gwt/junit/client/GWTTestCase.java b/user/super/com/google/gwt/junit/translatable/com/google/gwt/junit/client/GWTTestCase.java
index 25fe3ba..511943c 100644
--- a/user/super/com/google/gwt/junit/translatable/com/google/gwt/junit/client/GWTTestCase.java
+++ b/user/super/com/google/gwt/junit/translatable/com/google/gwt/junit/client/GWTTestCase.java
@@ -21,7 +21,7 @@
/**
* This class is the translatable version of {@link GWTTestCase}. It uses RPC
- * to communicate test progress back to the GWT environemnt, where the real test
+ * to communicate test progress back to the GWT environment, where the real test
* test is running.
*/
public abstract class GWTTestCase extends TestCase {
@@ -30,7 +30,7 @@
* A reference to my implementation class. All substantive methods simply
* delegate to the implementation class, to make debugging easier.
*/
- public final GWTTestCaseImpl impl = new GWTTestCaseImpl(this);
+ public GWTTestCaseImpl impl;
public final void addCheckpoint(String msg) {
impl.addCheckpoint(msg);
@@ -50,24 +50,6 @@
public abstract String getModuleName();
- /**
- * Do not override this method, the generated class will override it for you.
- */
- public GWTTestCase getNewTestCase() {
- return null;
- }
-
- /**
- * Do not override this method, the generated class will override it for you.
- */
- public String getTestName() {
- return null;
- }
-
- public final void onModuleLoad() {
- impl.onModuleLoad();
- }
-
protected final void delayTestFinish(int timeoutMillis) {
if (supportsAsync()) {
impl.delayTestFinish(timeoutMillis);
@@ -86,20 +68,15 @@
}
}
- protected final TestResults getTestResults() {
- return impl.getTestResults();
- }
-
/**
* Returns true if this test case supports asynchronous mode. By default, this
* is set to true. Originally introduced for Benchmarks which don't currently
* support asynchronous mode.
*
* <p>
- * Note that overriders of this method may report different answers for the
+ * Note that an overrider of this method may report different answers for the
* same test case during the same run, so it is not safe to cache the results.
* </p>
- *
*/
protected boolean supportsAsync() {
return true;
diff --git a/user/super/com/google/gwt/junit/translatable/com/google/gwt/junit/client/impl/GWTRunner.java b/user/super/com/google/gwt/junit/translatable/com/google/gwt/junit/client/impl/GWTRunner.java
new file mode 100644
index 0000000..43704ee
--- /dev/null
+++ b/user/super/com/google/gwt/junit/translatable/com/google/gwt/junit/client/impl/GWTRunner.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.junit.client.impl;
+
+import com.google.gwt.core.client.EntryPoint;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.junit.client.TestResults;
+import com.google.gwt.junit.client.impl.JUnitHost.TestInfo;
+import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.google.gwt.user.client.rpc.ServiceDefTarget;
+
+/**
+ * The entry point class for GWTTestCases.
+ *
+ * This is the main test running logic. Each time a test completes, the results
+ * are reported back through {@link #junitHost}, and the next method to run is
+ * returned. This process repeats until the next method to run is null.
+ */
+abstract class GWTRunner implements EntryPoint {
+
+ /**
+ * The RPC callback object for {@link GWTRunner#junitHost}. When
+ * {@link #onSuccess(Object)} is called, it's time to run the next test case.
+ */
+ private final class JUnitHostListener implements AsyncCallback<TestInfo> {
+
+ /**
+ * A call to junitHost failed.
+ */
+ public void onFailure(Throwable caught) {
+ // We're not doing anything, which will stop the test harness.
+ // TODO: try the call again?
+ }
+
+ /**
+ * A call to junitHost succeeded; run the next test case.
+ */
+ public void onSuccess(TestInfo nextTest) {
+ if (nextTest != null) {
+ runTest(nextTest);
+ }
+ }
+ }
+
+ /**
+ * The singleton instance.
+ */
+ private static GWTRunner sInstance;
+
+ /**
+ * A query param specifying the test class to run, for serverless mode.
+ */
+ private static final String TESTCLASS_QUERY_PARAM = "gwt.junit.testclassname";
+
+ /**
+ * A query param specifying the test method to run, for serverless mode.
+ */
+ private static final String TESTFUNC_QUERY_PARAM = "gwt.junit.testfuncname";
+
+ public static GWTRunner get() {
+ return sInstance;
+ }
+
+ private static native String getQuery() /*-{
+ return $wnd.location.search || '';
+ }-*/;
+
+ private static String getQueryParam(String query, String queryParam) {
+ int pos = query.indexOf("?" + queryParam + "=");
+ if (pos < 0) {
+ pos = query.indexOf("&" + queryParam + "=");
+ }
+ if (pos < 0) {
+ return null;
+ }
+ // advance past param name to to param value; +2 for the '&' and '='
+ pos += queryParam.length() + 2;
+ String result = query.substring(pos);
+ // trim any query params that follow
+ pos = result.indexOf('&');
+ if (pos >= 0) {
+ result = result.substring(0, pos);
+ }
+ return result;
+ }
+
+ /**
+ * The remote service to communicate with.
+ */
+ private final JUnitHostAsync junitHost = (JUnitHostAsync) GWT.create(JUnitHost.class);
+
+ /**
+ * Handles all RPC responses.
+ */
+ private final JUnitHostListener junitHostListener = new JUnitHostListener();
+
+ /**
+ * If true, run a single test case with no RPC.
+ */
+ private boolean serverless = false;
+
+ public GWTRunner() {
+ sInstance = this;
+
+ // Bind junitHost to the appropriate url.
+ ServiceDefTarget endpoint = (ServiceDefTarget) junitHost;
+ String url = GWT.getModuleBaseURL() + "junithost";
+ endpoint.setServiceEntryPoint(url);
+
+ // Null out the default uncaught exception handler since we will control it.
+ GWT.setUncaughtExceptionHandler(null);
+ }
+
+ public void onModuleLoad() {
+ TestInfo queryParamTestToRun = checkForQueryParamTestToRun();
+ if (queryParamTestToRun != null) {
+ /*
+ * Just run a single test with no server-side interaction.
+ */
+ serverless = true;
+ runTest(queryParamTestToRun);
+ } else {
+ /*
+ * Normal operation: Kick off the test running process by getting the
+ * first method to run from the server.
+ */
+ junitHost.getFirstMethod(GWT.getModuleName(), junitHostListener);
+ }
+ }
+
+ /**
+ * Implemented by the generated subclass. Creates an instance of the specified
+ * test class by fully qualified name.
+ */
+ protected abstract GWTTestCase createNewTestCase(String testClass);
+
+ void reportResultsAndGetNextMethod(TestResults results) {
+ if (serverless) {
+ // That's it, we're done
+ return;
+ }
+ junitHost.reportResultsAndGetNextMethod(GWT.getModuleName(), results,
+ junitHostListener);
+ }
+
+ private TestInfo checkForQueryParamTestToRun() {
+ String query = getQuery();
+ String testClass = getQueryParam(query, TESTCLASS_QUERY_PARAM);
+ String testMethod = getQueryParam(query, TESTFUNC_QUERY_PARAM);
+ if (testClass == null || testMethod == null) {
+ return null;
+ }
+ return new TestInfo(testClass, testMethod);
+ }
+
+ private void runTest(TestInfo testToRun) {
+ // Dynamically create a new test case.
+ GWTTestCase testCase = createNewTestCase(testToRun.getTestClass());
+ if (testCase != null) {
+ testCase.setName(testToRun.getTestMethod());
+ }
+ GWTTestCaseImpl impl = new GWTTestCaseImpl(testCase);
+ impl.runTest();
+ }
+
+}
diff --git a/user/super/com/google/gwt/junit/translatable/com/google/gwt/junit/client/impl/GWTTestCaseImpl.java b/user/super/com/google/gwt/junit/translatable/com/google/gwt/junit/client/impl/GWTTestCaseImpl.java
index 7f5208c..50b4fbf 100644
--- a/user/super/com/google/gwt/junit/translatable/com/google/gwt/junit/client/impl/GWTTestCaseImpl.java
+++ b/user/super/com/google/gwt/junit/translatable/com/google/gwt/junit/client/impl/GWTTestCaseImpl.java
@@ -23,8 +23,6 @@
import com.google.gwt.junit.client.TimeoutException;
import com.google.gwt.junit.client.Trial;
import com.google.gwt.user.client.Timer;
-import com.google.gwt.user.client.rpc.AsyncCallback;
-import com.google.gwt.user.client.rpc.ServiceDefTarget;
import java.util.ArrayList;
import java.util.List;
@@ -32,48 +30,20 @@
/**
* The implementation class for the translatable {@link GWTTestCase}.
*
- * This is the main test running logic. Each time a test completes, the results
- * are reported back through {@link #junitHost}, and the next method to run is
- * returned. This process repeats until the next method to run is null.
- *
* This class is split out of {@link GWTTestCase} to make debugging work. Trying
* to debug the translatable {@link GWTTestCase} confuses the debugger, which
* tends to use the non-translatable version.
*/
public class GWTTestCaseImpl implements UncaughtExceptionHandler {
- /**
- * The RPC callback object for {@link GWTTestCaseImpl#junitHost}. When
- * {@link #onSuccess(Object)} is called, it's time to run the next test case.
- */
- private final class JUnitHostListener implements AsyncCallback {
-
- /**
- * A call to junitHost failed.
- */
- public void onFailure(Throwable caught) {
- // just stop the test?
- }
-
- /**
- * A call to junitHost succeeded; run the next test case.
- */
- public void onSuccess(Object result) {
- if (result != null) {
- // Clone the current test case object
- GWTTestCase testCase = outer.getNewTestCase();
- // Tell it what method name to run
- testCase.setName((String) result);
- // Launch it
- testCase.impl.runTest();
- }
- }
- }
+ private static native String getDocumentLocation() /*-{
+ return $doc.location.toString();
+ }-*/;
/**
* A watchdog class for use with asynchronous mode. On construction,
* immediately schedules itself for the specified timeout. If the timeout
- * expires before this timer is cancelled, causes the enclosing test case to
+ * expires before this timer is canceled, causes the enclosing test case to
* fail with {@link TimeoutException}.
*/
private final class KillTimer extends Timer {
@@ -100,87 +70,31 @@
}
/**
- * The remote service to communicate with.
- */
- private static final JUnitHostAsync junitHost = (JUnitHostAsync) GWT.create(JUnitHost.class);
-
- private static String SERVERLESS_QUERY_PARAM = "gwt.junit.testfuncname";
-
- static {
- // Bind junitHost to the appropriate url.
- ServiceDefTarget endpoint = (ServiceDefTarget) junitHost;
- String url = GWT.getModuleBaseURL() + "junithost";
- endpoint.setServiceEntryPoint(url);
-
- // Null out the default uncaught exception handler since control it.
- GWT.setUncaughtExceptionHandler(null);
- }
-
- private static String checkForQueryParamTestToRun() {
- String query = getQuery();
- int pos = query.indexOf("?" + SERVERLESS_QUERY_PARAM + "=");
- if (pos < 0) {
- pos = query.indexOf("&" + SERVERLESS_QUERY_PARAM + "=");
- }
- if (pos < 0) {
- return null;
- }
- // advance past param name to to param value; +2 for the '&' and '='
- pos += SERVERLESS_QUERY_PARAM.length() + 2;
- query = query.substring(pos);
- // trim any query params that follow
- pos = query.indexOf('&');
- if (pos >= 0) {
- query = query.substring(0, pos);
- }
- return query;
- }
-
- private static native String getDocumentLocation() /*-{
- return $doc.location.toString();
- }-*/;
-
- private static native String getQuery() /*-{
- return $wnd.location.search || '';
- }-*/;
-
- /**
* The collected checkpoint messages.
*/
private List<String> checkPoints;
/**
- * Handles all RPC responses.
- */
- private final JUnitHostListener junitHostListener = new JUnitHostListener();
-
- /**
* Tracks whether the main test body has run (for asynchronous mode).
*/
private boolean mainTestHasRun = false;
/**
- * My paired (enclosing) {@link GWTTestCase}.
- */
- private final GWTTestCase outer;
-
- /**
* Collective test results.
- *
*/
private TestResults results = new TestResults();
/**
- * If true, run a single test case with no RPC.
- */
- private boolean serverless = false;
-
- /**
* The time the test began execution.
*/
private long testBeginMillis;
/**
+ * My paired {@link GWTTestCase}.
+ */
+ private final GWTTestCase testCase;
+
+ /**
* Tracks whether this test is completely done.
*/
private boolean testIsFinished = false;
@@ -196,8 +110,12 @@
*
* @param outer The paired (enclosing) GWTTestCase.
*/
- public GWTTestCaseImpl(GWTTestCase outer) {
- this.outer = outer;
+ public GWTTestCaseImpl(GWTTestCase testCase) {
+ this.testCase = testCase;
+ if (testCase != null) {
+ // Initialize the back reference from the test case to myself.
+ testCase.impl = this;
+ }
}
/**
@@ -269,27 +187,6 @@
}
/**
- * Implementation of {@link GWTTestCase#onModuleLoad()}.
- */
- public void onModuleLoad() {
- String queryParamTestToRun = checkForQueryParamTestToRun();
- if (queryParamTestToRun != null) {
- /*
- * Just run a single test with no server-side interaction.
- */
- outer.setName(queryParamTestToRun);
- serverless = true;
- runTest();
- } else {
- /*
- * Normal operation: Kick off the test running process by getting the
- * first method to run from the server.
- */
- junitHost.getFirstMethod(outer.getTestName(), junitHostListener);
- }
- }
-
- /**
* An uncaught exception escaped to the browser; what we should do depends on
* what state we're in.
*/
@@ -304,99 +201,25 @@
}
/**
- * Cleans up any outstanding state, reports ex to the remote runner, and kicks
- * off the next test.
- *
- * @param ex The results of this test.
+ * Actually run the user's test. Called from {@link GWTRunner}.
*/
- private void reportResultsAndRunNextMethod(Throwable ex) {
- List<Trial> trials = results.getTrials();
-
- if (serverless) {
- // That's it, we're done
- return;
- }
-
- // TODO(tobyr) - Consider making this logic polymorphic which will remove
- // instanceof test
- //
- // If this is not a benchmark, we have to create a fake trial run
- if (!(outer instanceof Benchmark)) {
- Trial trial = new Trial();
- long testDurationMillis = System.currentTimeMillis() - testBeginMillis;
- trial.setRunTimeMillis(testDurationMillis);
-
- if (ex != null) {
- ExceptionWrapper ew = new ExceptionWrapper(ex);
- if (checkPoints != null) {
- for (int i = 0, c = checkPoints.size(); i < c; ++i) {
- ew.message += "\n" + checkPoints.get(i);
- }
- }
- trial.setExceptionWrapper(ew);
- }
-
- trials.add(trial);
- } else {
- // If this was a benchmark, we need to handle exceptions specially
- // If an exception occurred, it happened without the trial being recorded
- // We, unfortunately, don't know the trial parameters at this point.
- // We should consider putting the exception handling code directly into
- // the generated Benchmark subclasses.
- if (ex != null) {
- ExceptionWrapper ew = new ExceptionWrapper(ex);
- if (checkPoints != null) {
- for (int i = 0, c = checkPoints.size(); i < c; ++i) {
- ew.message += "\n" + checkPoints.get(i);
- }
- }
- Trial trial = new Trial();
- trial.setExceptionWrapper(ew);
- trials.add(trial);
- }
- }
-
- results.setSourceRef(getDocumentLocation());
- testIsFinished = true;
- resetAsyncState();
- String testName = outer.getTestName();
- junitHost.reportResultsAndGetNextMethod(testName, results,
- junitHostListener);
- }
-
- /**
- * Cleans up any asynchronous mode state.
- */
- private void resetAsyncState() {
- // clear our timer if there is one
- if (timer != null) {
- timer.cancel();
- timer = null;
- }
- }
-
- /**
- * In the mode where we need to let uncaught exceptions escape to the browser,
- * this method serves as a hack to avoid "throws" clause problems.
- */
- private native void runBareTestCaseAvoidingExceptionDecl() /*-{
- this.@com.google.gwt.junit.client.impl.GWTTestCaseImpl::outer.@junit.framework.TestCase::runBare()();
- }-*/;
-
- /**
- * Actually run the user's test.
- */
- private void runTest() {
+ void runTest() {
Throwable caught = null;
testBeginMillis = System.currentTimeMillis();
results = new TestResults();
+ if (testCase == null) {
+ reportResultsAndRunNextMethod(new RuntimeException(
+ "Could not instantiate the requested class"));
+ return;
+ }
+
if (shouldCatchExceptions()) {
// Make sure no exceptions escape
GWT.setUncaughtExceptionHandler(this);
try {
- outer.runBare();
+ testCase.runBare();
} catch (Throwable e) {
caught = e;
}
@@ -422,6 +245,84 @@
}
/**
+ * Cleans up any outstanding state, reports ex to the remote runner, and kicks
+ * off the next test.
+ *
+ * @param ex The results of this test.
+ */
+ private void reportResultsAndRunNextMethod(Throwable ex) {
+ List<Trial> trials = results.getTrials();
+
+ /*
+ * TODO(tobyr) - Consider making this logic polymorphic which will remove
+ * instanceof test. But testCase might be null.
+ *
+ * If this is not a benchmark, we have to create a fake trial run
+ */
+ if (!(testCase instanceof Benchmark)) {
+ Trial trial = new Trial();
+ long testDurationMillis = System.currentTimeMillis() - testBeginMillis;
+ trial.setRunTimeMillis(testDurationMillis);
+
+ if (ex != null) {
+ ExceptionWrapper ew = new ExceptionWrapper(ex);
+ if (checkPoints != null) {
+ for (int i = 0, c = checkPoints.size(); i < c; ++i) {
+ ew.message += "\n" + checkPoints.get(i);
+ }
+ }
+ trial.setExceptionWrapper(ew);
+ }
+
+ trials.add(trial);
+ } else {
+ /*
+ * If this was a benchmark, we need to handle exceptions specially. If an
+ * exception occurred, it happened without the trial being recorded. We,
+ * unfortunately, don't know the trial parameters at this point. We should
+ * consider putting the exception handling code directly into the
+ * generated Benchmark subclasses.
+ */
+ if (ex != null) {
+ ExceptionWrapper ew = new ExceptionWrapper(ex);
+ if (checkPoints != null) {
+ for (int i = 0, c = checkPoints.size(); i < c; ++i) {
+ ew.message += "\n" + checkPoints.get(i);
+ }
+ }
+ Trial trial = new Trial();
+ trial.setExceptionWrapper(ew);
+ trials.add(trial);
+ }
+ }
+
+ results.setSourceRef(getDocumentLocation());
+ testIsFinished = true;
+ resetAsyncState();
+ GWTRunner.get().reportResultsAndGetNextMethod(results);
+ }
+
+ /**
+ * Cleans up any asynchronous mode state.
+ */
+ private void resetAsyncState() {
+ // clear our timer if there is one
+ if (timer != null) {
+ timer.cancel();
+ timer = null;
+ }
+ }
+
+ /**
+ * In the mode where we need to let uncaught exceptions escape to the browser,
+ * this method serves as a hack to avoid "throws" clause problems.
+ */
+ private native void runBareTestCaseAvoidingExceptionDecl() /*-{
+ this.@com.google.gwt.junit.client.impl.GWTTestCaseImpl::testCase
+ .@junit.framework.TestCase::runBare()();
+ }-*/;
+
+ /**
* A helper method to determine if we should catch exceptions. Wraps the call
* into user code with a try/catch; if the user's code throws an exception, we
* just ignore the exception and use the default behavior.
@@ -431,7 +332,7 @@
*/
private boolean shouldCatchExceptions() {
try {
- return outer.catchExceptions();
+ return testCase.catchExceptions();
} catch (Throwable e) {
return true;
}
diff --git a/user/test/com/google/gwt/dev/shell/test/MultiModuleTest.java b/user/test/com/google/gwt/dev/shell/test/MultiModuleTest.java
index bbcdf09..fabbe9f 100644
--- a/user/test/com/google/gwt/dev/shell/test/MultiModuleTest.java
+++ b/user/test/com/google/gwt/dev/shell/test/MultiModuleTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Google Inc.
+ * Copyright 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -169,6 +169,7 @@
String url = getURL();
Map params = getURLParams(url);
params.put("frame", "top");
+ params.put("gwt.junit.testclassname", MultiModuleTest.class.getName());
params.put("gwt.junit.testfuncname", "testInnerModules");
// open a new frame containing the module that drives the actual test
@@ -350,21 +351,21 @@
* @param depth nesting depth of this module, 0 = top level
*/
private native void markLoaded(int depth) /*-{
- var frame = $wnd;
- while (depth-- > 0) {
- frame = frame.parent;
- }
- if (!--frame.__count_to_be_loaded) {
- frame.__done_loading();
- }
- }-*/;
+ var frame = $wnd;
+ while (depth-- > 0) {
+ frame = frame.parent;
+ }
+ if (!--frame.__count_to_be_loaded) {
+ frame.__done_loading();
+ }
+ }-*/;
/**
* Notify our parent frame that the test is complete.
*/
private native void notifyParent() /*-{
- $wnd.parent.__test_complete();
- }-*/;
+ $wnd.parent.__test_complete();
+ }-*/;
/**
* Replace the specified frame with its alternate version.
diff --git a/user/test/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilderTest.java b/user/test/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilderTest.java
index 7d6ba5c..00afa64 100644
--- a/user/test/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilderTest.java
+++ b/user/test/com/google/gwt/user/rebind/rpc/SerializableTypeOracleBuilderTest.java
@@ -93,12 +93,6 @@
*/
private static final boolean SUPPRESS_LOGGER_OUTPUT = true;
- static {
- ModuleDefLoader.setEnableCachingModules(true);
- // Not required for an isolated module that doesn't ref GWTTestCase.
- ModuleDefLoader.forceInherit("com.google.gwt.junit.JUnit");
- }
-
private static TypeInfo[] getActualTypeInfo(SerializableTypeOracle sto) {
JType[] types = sto.getSerializableTypes();
TypeInfo[] actual = new TypeInfo[types.length];
@@ -168,8 +162,11 @@
((AbstractTreeLogger) logger).setMaxDetail(TreeLogger.INFO);
}
- moduleDef = ModuleDefLoader.loadFromClassPath(logger,
- "com.google.gwt.user.rebind.rpc.testcases.RebindRPCTestCases");
+ moduleDef = ModuleDefLoader.createSyntheticModule(logger,
+ "com.google.gwt.user.rebind.rpc.testcases.RebindRPCTestCases.JUnit",
+ new String[] {
+ "com.google.gwt.user.rebind.rpc.testcases.RebindRPCTestCases",
+ "com.google.gwt.junit.JUnit"}, true);
typeOracle = moduleDef.getTypeOracle(logger);
}