Adding a feature that allows users to define compile properties on test methods in GwtTestCases. A synthetic module will be created using the test module plus the specified properties.
Patch by: pmuetschard
Review by: jlabanca
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@6425 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/benchmarks/client/Benchmark.java b/user/src/com/google/gwt/benchmarks/client/Benchmark.java
index 1532279..b0b2db6 100644
--- a/user/src/com/google/gwt/benchmarks/client/Benchmark.java
+++ b/user/src/com/google/gwt/benchmarks/client/Benchmark.java
@@ -17,6 +17,7 @@
import com.google.gwt.benchmarks.BenchmarkShell;
import com.google.gwt.benchmarks.client.impl.BenchmarkResults;
+import com.google.gwt.junit.PropertyDefiningStrategy;
import com.google.gwt.junit.JUnitShell.Strategy;
import com.google.gwt.junit.client.GWTTestCase;
import com.google.gwt.junit.client.impl.JUnitResult;
@@ -107,31 +108,34 @@
/**
* The {@link Strategy} used for benchmarking.
*/
- private static Strategy BENCHMARK_STRATEGY = new Strategy() {
+ public static class BenchmarkStrategy extends PropertyDefiningStrategy {
+ public BenchmarkStrategy(TestCase test) {
+ super(test);
+ }
+
+ @Override
public String getModuleInherit() {
return "com.google.gwt.benchmarks.Benchmarks";
}
- public String getSyntheticModuleExtension() {
- return "Benchmarks";
- }
-
+ @Override
public void processResult(TestCase testCase, JUnitResult result) {
+ super.processResult(testCase, result);
if (result instanceof BenchmarkResults) {
BenchmarkShell.getReport().addBenchmarkResults(testCase,
(BenchmarkResults) result);
}
}
- };
- /**
- * Get the {@link Strategy} to use when compiling and running this test.
- *
- * @return the test {@link Strategy}
- */
+ @Override
+ protected String getBaseModuleExtension() {
+ return "Benchmarks";
+ }
+ }
+
@Override
- public Strategy getStrategy() {
- return BENCHMARK_STRATEGY;
+ protected Strategy createStrategy() {
+ return new BenchmarkStrategy(this);
}
/**
diff --git a/user/src/com/google/gwt/junit/CompileStrategy.java b/user/src/com/google/gwt/junit/CompileStrategy.java
index c69f645..abc2df8 100644
--- a/user/src/com/google/gwt/junit/CompileStrategy.java
+++ b/user/src/com/google/gwt/junit/CompileStrategy.java
@@ -182,6 +182,8 @@
"junit.moduleName", false);
moduleNameProp.setValue(syntheticModuleName);
+ strategy.processModule(moduleDef);
+
junitShell.maybeCompileForWebMode(syntheticModuleName);
return moduleDef;
diff --git a/user/src/com/google/gwt/junit/JUnitShell.java b/user/src/com/google/gwt/junit/JUnitShell.java
index 55152b6..99a42e3 100644
--- a/user/src/com/google/gwt/junit/JUnitShell.java
+++ b/user/src/com/google/gwt/junit/JUnitShell.java
@@ -94,6 +94,8 @@
String getSyntheticModuleExtension();
+ void processModule(ModuleDef module);
+
void processResult(TestCase testCase, JUnitResult result);
}
diff --git a/user/src/com/google/gwt/junit/PropertyDefiningStrategy.java b/user/src/com/google/gwt/junit/PropertyDefiningStrategy.java
new file mode 100644
index 0000000..b10af04
--- /dev/null
+++ b/user/src/com/google/gwt/junit/PropertyDefiningStrategy.java
@@ -0,0 +1,133 @@
+/*
+ * 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.dev.cfg.BindingProperty;
+import com.google.gwt.dev.cfg.ModuleDef;
+import com.google.gwt.dev.cfg.Properties;
+import com.google.gwt.dev.util.Util;
+import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.junit.client.WithProperties;
+import com.google.gwt.junit.client.WithProperties.Property;
+
+import junit.framework.TestCase;
+
+import java.lang.reflect.Method;
+import java.util.Comparator;
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ * A {@link JUnitShell.Strategy} that will alter the module the tests are run
+ * in by defining module properties as requested by annotations on the tests.
+ */
+public class PropertyDefiningStrategy extends GWTTestCase.BaseStrategy {
+ private TestCase testCase;
+ private Set<Property> properties;
+
+ public PropertyDefiningStrategy(TestCase testCase) {
+ this.testCase = testCase;
+ }
+
+ protected String getBaseModuleExtension() {
+ return super.getSyntheticModuleExtension();
+ }
+
+ @Override
+ public String getSyntheticModuleExtension() {
+ String extension = getBaseModuleExtension();
+ computePropertiesMap();
+ if (properties.size() > 0) {
+ StringBuilder sb = new StringBuilder();
+ for (Property property : properties) {
+ sb.append(".").append(property.name()).append(
+ "$").append(property.value());
+ }
+ extension += sb.toString();
+ }
+ return extension;
+ }
+
+ @Override
+ public void processModule(ModuleDef module) {
+ super.processModule(module);
+ computePropertiesMap();
+ if (properties.size() > 0) {
+ Properties props = module.getProperties();
+ for (Property property : properties) {
+ BindingProperty binding = props.createBinding(property.name());
+ if (!binding.isDefinedValue(property.value())) {
+ binding.addDefinedValue(
+ binding.getRootCondition(), property.value());
+ }
+ binding.setAllowedValues(
+ binding.getRootCondition(), property.value());
+ }
+ }
+ }
+
+ private Property checkProperty(Property property) {
+ String[] tokens = (property.name() + ". ").split("\\.");
+ for (int i = 0; i < tokens.length - 1; i++) {
+ if (!Util.isValidJavaIdent(tokens[i])) {
+ throw new AssertionError(
+ "Property name invalid: " + property.name());
+ }
+ }
+
+ if (!Util.isValidJavaIdent(property.value())) {
+ throw new AssertionError(
+ "Property value invalid: " + property.value());
+ }
+
+ return property;
+ }
+
+ private void computePropertiesMap() {
+ if (properties == null) {
+ Set<Property> props = new TreeSet<Property>(
+ new Comparator<Property>() {
+ public int compare(Property p1, Property p2) {
+ int r = p1.name().compareTo(p2.name());
+ if (r == 0) {
+ r = p1.value().compareTo(p2.value());
+ }
+ return r;
+ }
+ });
+ try {
+ String name = testCase.getName();
+ if (name != null) {
+ Method testMethod = testCase.getClass().getMethod(testCase.getName());
+ if (testMethod.isAnnotationPresent(WithProperties.class)) {
+ WithProperties annotation =
+ testMethod.getAnnotation(WithProperties.class);
+ for (Property property : annotation.value()) {
+ props.add(checkProperty(property));
+ }
+ }
+ }
+ } catch (SecurityException e) {
+ // should not happen
+ e.printStackTrace();
+ } catch (NoSuchMethodException e) {
+ // should not happen
+ e.printStackTrace();
+ }
+ properties = props;
+ }
+ }
+}
diff --git a/user/src/com/google/gwt/junit/client/GWTTestCase.java b/user/src/com/google/gwt/junit/client/GWTTestCase.java
index 176c8a0..29c6fad 100644
--- a/user/src/com/google/gwt/junit/client/GWTTestCase.java
+++ b/user/src/com/google/gwt/junit/client/GWTTestCase.java
@@ -15,7 +15,9 @@
*/
package com.google.gwt.junit.client;
+import com.google.gwt.dev.cfg.ModuleDef;
import com.google.gwt.junit.JUnitShell;
+import com.google.gwt.junit.PropertyDefiningStrategy;
import com.google.gwt.junit.JUnitShell.Strategy;
import com.google.gwt.junit.client.impl.JUnitResult;
import com.google.gwt.junit.client.impl.JUnitHost.TestInfo;
@@ -45,6 +47,25 @@
public abstract class GWTTestCase extends TestCase {
/**
+ * The base class for strategies to use for tests.
+ */
+ public static class BaseStrategy implements Strategy {
+ public String getModuleInherit() {
+ return "com.google.gwt.junit.JUnit";
+ }
+
+ public String getSyntheticModuleExtension() {
+ return "JUnit";
+ }
+
+ public void processModule(ModuleDef module) {
+ }
+
+ public void processResult(TestCase testCase, JUnitResult result) {
+ }
+ }
+
+ /**
* Information about a synthetic module used for testing.
*/
public static final class TestModuleInfo {
@@ -104,22 +125,6 @@
private static final Object ALL_GWT_TESTS_LOCK = new Object();
/**
- * The default strategy to use for tests.
- */
- private static final Strategy DEFAULT_STRATEGY = new Strategy() {
- public String getModuleInherit() {
- return "com.google.gwt.junit.JUnit";
- }
-
- public String getSyntheticModuleExtension() {
- return "JUnit";
- }
-
- public void processResult(TestCase testCase, JUnitResult result) {
- }
- };
-
- /**
* Get the names of all test modules.
*
* @return all test module names
@@ -159,6 +164,11 @@
protected TestResult testResult = null;
/**
+ * The {@link Strategy} used by this test.
+ */
+ private Strategy strategy;
+
+ /**
* A new instance of your subclass is constructed for each test method that is
* to be run. You should avoid running code in your subclass constructor,
* initializer blocks, and field initializations, because if those code blocks
@@ -246,7 +256,10 @@
* @return the test {@link Strategy}
*/
public Strategy getStrategy() {
- return DEFAULT_STRATEGY;
+ if (strategy == null) {
+ strategy = createStrategy();
+ }
+ return strategy;
}
/**
@@ -291,6 +304,13 @@
}
/**
+ * Creates the test strategy to use (see {@link #getStrategy()}).
+ */
+ protected Strategy createStrategy() {
+ return new PropertyDefiningStrategy(this);
+ }
+
+ /**
* Put the current test in asynchronous mode. If the test method completes
* normally, this test will not immediately succeed. Instead, a <i>delay
* period</i> begins. During the delay period, the test system will wait for
diff --git a/user/src/com/google/gwt/junit/client/WithProperties.java b/user/src/com/google/gwt/junit/client/WithProperties.java
new file mode 100644
index 0000000..5f1be89
--- /dev/null
+++ b/user/src/com/google/gwt/junit/client/WithProperties.java
@@ -0,0 +1,41 @@
+/*
+ * 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.client;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation indicating that a test method inside a {@link GWTTestCase}
+ * requires a set of binding properties to be set in its module.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface WithProperties {
+ Property[] value();
+
+ /**
+ * Annotation defining a binding property.
+ */
+ @Retention(RetentionPolicy.RUNTIME)
+ public static @interface Property {
+ String name();
+
+ String value();
+ }
+}
diff --git a/user/src/com/google/gwt/junit/tools/GWTTestSuite.java b/user/src/com/google/gwt/junit/tools/GWTTestSuite.java
index b76f540..d4c0c3d 100644
--- a/user/src/com/google/gwt/junit/tools/GWTTestSuite.java
+++ b/user/src/com/google/gwt/junit/tools/GWTTestSuite.java
@@ -80,7 +80,7 @@
if (test instanceof GWTTestCase) {
GWTTestCase gwtTest = (GWTTestCase) test;
- String moduleName = gwtTest.getModuleName();
+ String moduleName = gwtTest.getSyntheticModuleName();
if (moduleName != null) {
TestSuite suite = moduleSuites.get(moduleName);
if (suite == null) {
diff --git a/user/test/com/google/gwt/junit/JUnitSuite.java b/user/test/com/google/gwt/junit/JUnitSuite.java
index b7f67ce..79833e1 100644
--- a/user/test/com/google/gwt/junit/JUnitSuite.java
+++ b/user/test/com/google/gwt/junit/JUnitSuite.java
@@ -16,6 +16,7 @@
package com.google.gwt.junit;
import com.google.gwt.junit.client.GWTTestCaseTest;
+import com.google.gwt.junit.client.PropertyDefiningGWTTest;
import com.google.gwt.junit.tools.GWTTestSuite;
import junit.framework.Test;
@@ -50,6 +51,9 @@
// Run manually only, launches servers that die on port contention
// suite.addTestSuite(BrowserManagerServerTest.class);
+ suite.addTestSuite(PropertyDefiningStrategyTest.class);
+ suite.addTestSuite(PropertyDefiningGWTTest.class);
+
return suite;
}
}
diff --git a/user/test/com/google/gwt/junit/JUnitTestWithProperties.gwt.xml b/user/test/com/google/gwt/junit/JUnitTestWithProperties.gwt.xml
new file mode 100644
index 0000000..ad0b17f
--- /dev/null
+++ b/user/test/com/google/gwt/junit/JUnitTestWithProperties.gwt.xml
@@ -0,0 +1,37 @@
+<!-- -->
+<!-- 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 -->
+<!-- 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. License for the specific language governing permissions and -->
+<!-- limitations under the License. -->
+
+<!-- This module is for the PropertyDefiningGWTTest -->
+<module>
+ <inherits name="com.google.gwt.user.User" />
+ <define-property name="my.property" values="one,two" />
+
+ <replace-with class="com.google.gwt.junit.client.PropertyDefiningGWTTest$TestImplOne">
+ <when-type-is class="com.google.gwt.junit.client.PropertyDefiningGWTTest$TestInterface" />
+ <when-property-is name="my.property" value="one" />
+ </replace-with>
+ <replace-with class="com.google.gwt.junit.client.PropertyDefiningGWTTest.TestImplOne">
+ <when-type-is class="com.google.gwt.junit.client.PropertyDefiningGWTTest.TestInterface" />
+ <when-property-is name="my.property" value="one" />
+ </replace-with>
+
+ <replace-with class="com.google.gwt.junit.client.PropertyDefiningGWTTest$TestImplTwo">
+ <when-type-is class="com.google.gwt.junit.client.PropertyDefiningGWTTest$TestInterface" />
+ <when-property-is name="my.property" value="two" />
+ </replace-with>
+ <replace-with class="com.google.gwt.junit.client.PropertyDefiningGWTTest.TestImplTwo">
+ <when-type-is class="com.google.gwt.junit.client.PropertyDefiningGWTTest.TestInterface" />
+ <when-property-is name="my.property" value="two" />
+ </replace-with>
+</module>
diff --git a/user/test/com/google/gwt/junit/PropertyDefiningStrategyTest.java b/user/test/com/google/gwt/junit/PropertyDefiningStrategyTest.java
new file mode 100644
index 0000000..e85ed86
--- /dev/null
+++ b/user/test/com/google/gwt/junit/PropertyDefiningStrategyTest.java
@@ -0,0 +1,113 @@
+/*
+ * 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.dev.cfg.BindingProperty;
+import com.google.gwt.dev.cfg.ModuleDef;
+import com.google.gwt.junit.client.WithProperties;
+import com.google.gwt.junit.client.WithProperties.Property;
+
+import junit.framework.TestCase;
+
+import java.util.SortedSet;
+
+/**
+ * Tests the {@link PropertyDefiningStrategy}.
+ */
+public class PropertyDefiningStrategyTest extends TestCase {
+ private static class PropertyValue {
+ public String name, value;
+
+ public PropertyValue(String name, String value) {
+ this.name = name;
+ this.value = value;
+ }
+ }
+
+ @WithProperties({@Property(name = "name", value = "value")})
+ public void methodWithSingleProperty() {
+ }
+
+ @WithProperties({
+ @Property(name = "name2", value = "value2"),
+ @Property(name = "name1", value = "value1")})
+ public void methodWithTwoProperties() {
+ }
+
+ public void methodWithoutProperties() {
+ }
+
+ public void testGetSyntheticModuleExtension() {
+ assertEquals("JUnit.name$value",
+ getStrategyForSingleProperty().getSyntheticModuleExtension());
+ assertEquals("JUnit.name1$value1.name2$value2",
+ getStrategyForTwoProperties().getSyntheticModuleExtension());
+ assertEquals("JUnit",
+ getStrategyForNoProperty().getSyntheticModuleExtension());
+ }
+
+ public void testProcessModuleForTestCaseWithSingleProperty() {
+ ModuleDef module = new ModuleDef("myModule");
+ getStrategyForSingleProperty().processModule(module);
+ assertProperties(module, p("name", "value"));
+ }
+
+ public void testProcessModuleForTestCaseWithTwoProperties() {
+ ModuleDef module = new ModuleDef("myModule");
+ getStrategyForTwoProperties().processModule(module);
+ assertProperties(module, p("name1", "value1"), p("name2", "value2"));
+ }
+
+ public void testProcessModuleForTestCaseWithoutProperties() {
+ ModuleDef module = new ModuleDef("myModule");
+ getStrategyForNoProperty().processModule(module);
+ assertProperties(module);
+ }
+
+ private void assertProperties(ModuleDef module, PropertyValue... props) {
+ SortedSet<BindingProperty> properties = module.getProperties().getBindingProperties();
+ assertEquals(props.length, properties.size());
+ int i = 0;
+ for (BindingProperty property : properties) {
+ assertEquals("property " + i, props[i].name, property.getName());
+ assertEquals("property " + i, props[i].value,
+ property.getConstrainedValue());
+ i++;
+ }
+ }
+
+ private static PropertyValue p(String name, String value) {
+ return new PropertyValue(name, value);
+ }
+
+ private PropertyDefiningStrategy getStrategyForSingleProperty() {
+ TestCase result = new PropertyDefiningStrategyTest();
+ result.setName("methodWithSingleProperty");
+ return new PropertyDefiningStrategy(result);
+ }
+
+ private PropertyDefiningStrategy getStrategyForTwoProperties() {
+ TestCase result = new PropertyDefiningStrategyTest();
+ result.setName("methodWithTwoProperties");
+ return new PropertyDefiningStrategy(result);
+ }
+
+ private PropertyDefiningStrategy getStrategyForNoProperty() {
+ TestCase result = new PropertyDefiningStrategyTest();
+ result.setName("methodWithoutProperties");
+ return new PropertyDefiningStrategy(result);
+ }
+}
diff --git a/user/test/com/google/gwt/junit/client/PropertyDefiningGWTTest.java b/user/test/com/google/gwt/junit/client/PropertyDefiningGWTTest.java
new file mode 100644
index 0000000..b311f39
--- /dev/null
+++ b/user/test/com/google/gwt/junit/client/PropertyDefiningGWTTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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.client;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.junit.client.WithProperties.Property;
+
+import java.util.Date;
+
+/**
+ * A {@link GWTTestCase} that defines module properties.
+ */
+public class PropertyDefiningGWTTest extends GWTTestCase {
+ /**
+ * Base interface used for testing.
+ */
+ public static interface TestInterface {
+ String value();
+ }
+
+ /**
+ * Implementation used in one deferred binding.
+ */
+ public static class TestImplOne implements TestInterface {
+ public String value() {
+ return "one";
+ }
+ }
+
+ /**
+ * Implementation used in the other deferred binding.
+ */
+ public static class TestImplTwo implements TestInterface {
+ public String value() {
+ return "two";
+ }
+ }
+
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.junit.JUnitTestWithProperties";
+ }
+
+ @WithProperties({
+ @Property(name = "locale", value = "en_US"),
+ @Property(name = "my.property", value = "one")
+ })
+ public void testInUSLocaleAndPropertyOne() {
+ assertEquals("June", DateTimeFormat.getFormat("MMMM").format(new Date(99, 5, 13)));
+ assertEquals("one", GWT.<TestInterface> create(TestInterface.class).value());
+ }
+
+ @WithProperties({
+ @Property(name = "locale", value = "de_CH"),
+ @Property(name = "my.property", value = "two")
+ })
+ public void testInSwissLocaleAndPropertyTwo() {
+ assertEquals("Juni", DateTimeFormat.getFormat("MMMM").format(new Date(99, 5, 13)));
+ assertEquals("two", GWT.<TestInterface> create(TestInterface.class).value());
+ }
+}