| /* | |
| * Copyright 2009 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; | |
| import com.google.gwt.core.ext.TreeLogger; | |
| import com.google.gwt.core.ext.UnableToCompleteException; | |
| import com.google.gwt.dev.cfg.ConfigurationProperty; | |
| import com.google.gwt.dev.cfg.ModuleDef; | |
| import com.google.gwt.dev.cfg.ModuleDefLoader; | |
| import com.google.gwt.dev.util.collect.HashSet; | |
| import com.google.gwt.junit.JUnitShell.Strategy; | |
| import com.google.gwt.junit.client.GWTTestCase; | |
| import com.google.gwt.junit.client.impl.GWTRunner; | |
| import com.google.gwt.junit.client.impl.JUnitHost.TestInfo; | |
| import java.util.ArrayList; | |
| import java.util.List; | |
| import java.util.Set; | |
| /** | |
| * An interface that specifies how modules should be compiled. | |
| */ | |
| public abstract class CompileStrategy { | |
| /** | |
| * The list of modules that have already been compiled. We use this to avoid | |
| * adding test batches that have already been added. | |
| */ | |
| private Set<String> compiledModuleNames = new HashSet<String>(); | |
| private final JUnitShell junitShell; | |
| /** | |
| * Construct a CompileStrategy. | |
| * | |
| * @param junitShell | |
| */ | |
| public CompileStrategy(JUnitShell junitShell) { | |
| this.junitShell = junitShell; | |
| } | |
| /** | |
| * Maybe add a test block for the currently executed test case. | |
| * | |
| * @param testCase the test case being run | |
| * @param batchingStrategy the batching strategy | |
| */ | |
| public void maybeAddTestBlockForCurrentTest(GWTTestCase testCase, | |
| BatchingStrategy batchingStrategy) { | |
| if (batchingStrategy.isSingleTestOnly()) { | |
| TestInfo testInfo = new TestInfo(testCase.getSyntheticModuleName(), | |
| testCase.getClass().getName(), testCase.getName()); | |
| List<TestInfo[]> testBlocks = new ArrayList<TestInfo[]>(1); | |
| testBlocks.add(new TestInfo[]{testInfo}); | |
| getMessageQueue().addTestBlocks(testBlocks, false); | |
| } | |
| } | |
| /** | |
| * Let the compile strategy compile another module. This is called while | |
| * {@link JUnitShell} is waiting for the current test to complete. | |
| * | |
| * @throws UnableToCompleteException if the compilation fails | |
| */ | |
| public void maybeCompileAhead() throws UnableToCompleteException { | |
| } | |
| /** | |
| * Compile a single module using a synthetic module that adds JUnit support. | |
| * | |
| * @param moduleName the module name | |
| * @param syntheticModuleName the synthetic module name | |
| * @param strategy the strategy | |
| * @param batchingStrategy the batching strategy | |
| * @param treeLogger the logger | |
| * @return the {@link ModuleDef} describing the synthetic module | |
| * @throws UnableToCompleteException | |
| */ | |
| public abstract ModuleDef maybeCompileModule(String moduleName, | |
| String syntheticModuleName, Strategy strategy, | |
| BatchingStrategy batchingStrategy, TreeLogger treeLogger) | |
| throws UnableToCompleteException; | |
| /** | |
| * Compile a single module using a synthetic module that adds JUnit support. | |
| * | |
| * @param moduleName the module name | |
| * @param syntheticModuleName the synthetic module name | |
| * @param strategy the strategy | |
| * @param batchingStrategy the batching strategy | |
| * @param treeLogger the logger | |
| * @return the {@link ModuleDef} describing the synthetic module | |
| */ | |
| protected ModuleDef maybeCompileModuleImpl(String moduleName, | |
| String syntheticModuleName, Strategy strategy, | |
| BatchingStrategy batchingStrategy, TreeLogger treeLogger) | |
| throws UnableToCompleteException { | |
| ModuleDef moduleDef = maybeCompileModuleImpl2(moduleName, | |
| syntheticModuleName, strategy, treeLogger); | |
| // Add all test blocks for the module if we haven't seen this module before. | |
| if (!compiledModuleNames.contains(syntheticModuleName)) { | |
| compiledModuleNames.add(syntheticModuleName); | |
| if (!batchingStrategy.isSingleTestOnly()) { | |
| // Use >= so we can mock getModuleCount and force isFinalModule to true | |
| boolean isFinalModule = compiledModuleNames.size() >= getModuleCount(); | |
| List<TestInfo[]> testBlocks = batchingStrategy.getTestBlocks(syntheticModuleName); | |
| getMessageQueue().addTestBlocks(testBlocks, isFinalModule); | |
| } | |
| } | |
| return moduleDef; | |
| } | |
| /** | |
| * Visible for testing and mocking. | |
| * | |
| * @return the {@link JUnitMessageQueue} | |
| */ | |
| JUnitMessageQueue getMessageQueue() { | |
| return JUnitShell.getMessageQueue(); | |
| } | |
| /** | |
| * Visible for testing and mocking. | |
| * | |
| * @return the number of modules to test | |
| */ | |
| int getModuleCount() { | |
| return GWTTestCase.getModuleCount(); | |
| } | |
| /** | |
| * Compile the module if needed. | |
| * | |
| * Visible for testing and mocking. | |
| * | |
| * @param moduleName the module name | |
| * @param syntheticModuleName the synthetic module name | |
| * @param strategy the strategy | |
| * @param treeLogger the logger | |
| * @return the {@link ModuleDef} describing the synthetic module | |
| */ | |
| ModuleDef maybeCompileModuleImpl2(String moduleName, | |
| String syntheticModuleName, Strategy strategy, TreeLogger treeLogger) | |
| throws UnableToCompleteException { | |
| /* | |
| * Synthesize a synthetic module that derives from the user-specified module | |
| * but also includes JUnit support. | |
| */ | |
| ModuleDef moduleDef = ModuleDefLoader.createSyntheticModule(treeLogger, | |
| syntheticModuleName, new String[]{ | |
| moduleName, strategy.getModuleInherit()}, false); | |
| // Replace any user entry points with our test runner. | |
| moduleDef.clearEntryPoints(); | |
| moduleDef.addEntryPointTypeName(GWTRunner.class.getName()); | |
| // Squirrel away the name of the active module for GWTRunnerGenerator | |
| ConfigurationProperty moduleNameProp = moduleDef.getProperties().createConfiguration( | |
| "junit.moduleName", false); | |
| moduleNameProp.setValue(syntheticModuleName); | |
| strategy.processModule(moduleDef); | |
| junitShell.maybeCompileForWebMode(moduleDef, | |
| JUnitShell.getRemoteUserAgents()); | |
| return moduleDef; | |
| } | |
| } |