- Updates benchmarking to support annotations and
deprecate the existing metadata attributes.
- Includes some existing benchmarks.
- Adds a new BenchmarkTest.
Patch by: tobyr
Review by: jat
Issue: 2045
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@1753 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/javadoc/com/google/gwt/examples/benchmarks/AllocBenchmark.java b/user/javadoc/com/google/gwt/examples/benchmarks/AllocBenchmark.java
index 54e4c58..208e52a 100644
--- a/user/javadoc/com/google/gwt/examples/benchmarks/AllocBenchmark.java
+++ b/user/javadoc/com/google/gwt/examples/benchmarks/AllocBenchmark.java
@@ -15,27 +15,15 @@
*/
package com.google.gwt.examples.benchmarks;
-import com.google.gwt.junit.client.Category;
import com.google.gwt.junit.client.Benchmark;
/**
* Provides profile statistics on allocation times for different kinds of
* objects.
*
- * @gwt.benchmark.category com.google.gwt.user.client.ui.AllocBenchmark.AllocCategory
- *
*/
public class AllocBenchmark extends Benchmark {
- /**
- * @gwt.benchmark.name Allocation Benchmarks
- * @gwt.benchmark.description A series of benchmarks that tests the impact of
- * different kinds of allocations.
- *
- */
- class AllocCategory implements Category {
- }
-
private static final int numAllocs = 1000;
public String getModuleName() {
diff --git a/user/javadoc/com/google/gwt/examples/benchmarks/ArrayListBenchmark.java b/user/javadoc/com/google/gwt/examples/benchmarks/ArrayListBenchmark.java
new file mode 100644
index 0000000..c9609ff
--- /dev/null
+++ b/user/javadoc/com/google/gwt/examples/benchmarks/ArrayListBenchmark.java
@@ -0,0 +1,226 @@
+/*
+ * 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.examples.benchmarks;
+import com.google.gwt.junit.client.IntRange;
+import com.google.gwt.junit.client.Benchmark;
+import com.google.gwt.junit.client.Operator;
+import com.google.gwt.junit.client.annotations.RangeField;
+import com.google.gwt.junit.client.annotations.RangeEnum;
+import com.google.gwt.junit.client.annotations.Setup;
+
+import java.util.List;
+import java.util.Arrays;
+import java.util.ArrayList;
+
+/**
+ * Benchmarks common operations on {@link List Lists}. This test covers
+ * appends, inserts, and removes for various sizes and positions.
+ */
+public class ArrayListBenchmark extends Benchmark {
+
+ private static final int PRIME = 3001;
+
+ /**
+ * The various positions that data can be inserted into a list.
+ */
+ protected enum Position {
+
+ BEGIN("at the beginning"),
+ EXPLICIT_END("explicitly at the end"),
+ IMPLICIT_END("implicitly at the end"),
+ VARIED("in varied locations");
+
+ private String label;
+
+ /**
+ * Constructor for <code>Position</code>.
+ *
+ * @param label a not <code>null</code> label describing this
+ * <code>Position</code>.
+ */
+ Position(String label) {
+ this.label = label;
+ }
+
+ /**
+ * Returns the textual description for the position.
+ *
+ * @return a not <code>null</code> description.
+ */
+ public String toString() {
+ return label;
+ }
+ }
+
+ protected final List<Position> explicitPositions = Arrays
+ .asList(Position.BEGIN, Position.EXPLICIT_END, Position.VARIED);
+
+ protected final IntRange insertRemoveRange = new IntRange(64,
+ Integer.MAX_VALUE, Operator.MULTIPLY, 2);
+
+ protected final IntRange baseRange = new IntRange(512, Integer.MAX_VALUE,
+ Operator.MULTIPLY, 2);
+
+ List<String> list;
+
+ int index = 0;
+
+ public String getModuleName() {
+ return "com.google.gwt.emultest.EmulSuite";
+ }
+
+ /**
+ * Appends <code>size</code> items to an empty {@code List}.
+ *
+ * @param size the size of the {@code List}
+ */
+ @Setup("beginListAdds")
+ public void testListAdds(@RangeField("baseRange") Integer size) {
+ int num = size.intValue();
+ for (int i = 0; i < num; i++) {
+ list.add("hello");
+ }
+ }
+
+ // Required for JUnit
+ public void testListAdds() {
+ }
+
+ /**
+ * Performs <code>size</code> gets on a {@code List} of size,
+ * <code>size</code>.
+ *
+ * @param size the size of the {@code List}
+ */
+ @Setup("beginListGets")
+ public void testListGets(@RangeField("baseRange") Integer size) {
+ int num = size.intValue();
+ for (int i = 0; i < num; i++) {
+ list.get(i);
+ }
+ }
+
+ // Required for JUnit
+ public void testListGets() {
+ }
+
+ /**
+ * Performs <code>size</code> inserts at position, <code>where</code>, on an
+ * empty <code>List</code>.
+ *
+ * @param where Where the inserts happen
+ * @param size The size of the <code>List</code>
+ *
+ */
+ @Setup("beginListInserts")
+ public void testListInserts(
+ @RangeEnum(Position.class)Position where,
+ @RangeField("insertRemoveRange")Integer size) {
+ insertIntoCollection(size, where, list);
+ }
+
+ // Required for JUnit
+ public void testListInserts() {
+ }
+
+ /**
+ * Performs <code>size</code> removes at position, <code>where</code>, on an
+ * ArrayList of size, <code>size</code>.
+ *
+ * @param where Where the inserts happen
+ * @param size The size of the <code>List</code>
+ */
+ @Setup("beginListRemoves")
+ public void testListRemoves(
+ @RangeField("explicitPositions")Position where,
+ @RangeField("insertRemoveRange")Integer size) {
+ removeFromCollection(size, where, list);
+ }
+
+ // Required for JUnit
+ public void testListRemoves() {
+ }
+
+ /**
+ * Creates a new empty List.
+ *
+ * @return a not <code>null</code>, empty List
+ */
+ protected List<String> newList() {
+ return new ArrayList<String>();
+ }
+
+ void beginListAdds(Integer size) {
+ list = newList();
+ }
+
+ void beginListGets(Integer size) {
+ createList(size);
+ }
+
+ void beginListInserts(Position where, Integer size) {
+ list = newList();
+ index = 0;
+ }
+
+ void beginListRemoves(Position where, Integer size) {
+ beginListInserts(where, size);
+ testListInserts(where, size);
+ }
+
+ private void createList(Integer size) {
+ beginListAdds(size);
+ testListAdds(size);
+ }
+
+ private void insertIntoCollection(Integer size, Position where, List<String> l) {
+ int num = size.intValue();
+ for (int i = 0; i < num; i++) {
+ if (where == Position.IMPLICIT_END) {
+ l.add("hello");
+ } else if (where == Position.BEGIN) {
+ l.add(0, "hello");
+ } else if (where == Position.EXPLICIT_END) {
+ l.add(l.size(), "hello");
+ } else if (where == Position.VARIED) {
+ l.add(index, "hello");
+ index += PRIME;
+ index %= l.size();
+ }
+ }
+ }
+
+ private int removeFromCollection(Integer size, Position where, List<String> l) {
+ int num = size.intValue();
+ for (int i = 0; i < num; i++) {
+ if (where == Position.IMPLICIT_END) {
+ throw new RuntimeException("cannot remove from the end implicitly");
+ } else if (where == Position.BEGIN) {
+ l.remove(0);
+ } else if (where == Position.EXPLICIT_END) {
+ l.remove(l.size() - 1);
+ } else if (where == Position.VARIED) {
+ l.remove(index);
+ index += PRIME;
+ int currentSize = l.size();
+ if (currentSize > 0) {
+ index %= l.size();
+ }
+ }
+ }
+ return index;
+ }
+}
diff --git a/user/src/com/google/gwt/junit/benchmarks/BenchmarkReport.java b/user/src/com/google/gwt/junit/benchmarks/BenchmarkReport.java
index 2fe858d..79330b3 100644
--- a/user/src/com/google/gwt/junit/benchmarks/BenchmarkReport.java
+++ b/user/src/com/google/gwt/junit/benchmarks/BenchmarkReport.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
@@ -20,9 +20,11 @@
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JMethod;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
+import com.google.gwt.core.ext.typeinfo.HasAnnotations;
import com.google.gwt.dev.util.Util;
import com.google.gwt.junit.client.TestResults;
import com.google.gwt.junit.client.Trial;
+import com.google.gwt.junit.client.Benchmark;
import com.google.gwt.junit.rebind.BenchmarkGenerator;
import com.google.gwt.util.tools.Utility;
@@ -312,6 +314,8 @@
return resultString.equals("") ? null : resultString;
}
+ private TreeLogger deprecationBranch;
+
private TreeLogger logger;
private Parser parser = new Parser();
@@ -326,6 +330,10 @@
public BenchmarkReport(TreeLogger logger) {
this.logger = logger;
+ deprecationBranch = logger.branch(TreeLogger.INFO,
+ "Scanning Benchmarks for deprecated annotations; "
+ + "Please see " + Benchmark.class.getName()
+ + " for more information.", null);
}
/**
@@ -340,8 +348,7 @@
public void addBenchmark(JClassType benchmarkClass, TypeOracle typeOracle) {
this.typeOracle = typeOracle;
- String categoryType = getSimpleMetaData(benchmarkClass,
- GWT_BENCHMARK_CATEGORY);
+ String categoryType = getBenchmarkCategory(benchmarkClass);
Map<String, JMethod> zeroArgMethods = BenchmarkGenerator.getNotOverloadedTestMethods(benchmarkClass);
Map<String, JMethod> parameterizedMethods = BenchmarkGenerator.getParameterizedTestMethods(
@@ -360,8 +367,7 @@
// Add all of the benchmark methods
for (JMethod method : testMethods) {
String methodName = method.getName();
- String methodCategoryType = getSimpleMetaData(method,
- GWT_BENCHMARK_CATEGORY);
+ String methodCategoryType = getBenchmarkCategory(method);
if (methodCategoryType == null) {
methodCategoryType = categoryType;
}
@@ -438,6 +444,16 @@
// docOut.close();
}
+ private <T extends HasMetaData & HasAnnotations> String getBenchmarkCategory(
+ T element) {
+ String category = getSimpleMetaData(element, GWT_BENCHMARK_CATEGORY);
+ if (category != null) {
+ deprecationBranch.log(TreeLogger.WARN, GWT_BENCHMARK_CATEGORY + " has "
+ + "been deprecated with no replacement.", null);
+ }
+ return category;
+ }
+
private CategoryImpl getCategory(String name) {
CategoryImpl c = testCategories.get(name);
@@ -445,24 +461,39 @@
return c;
}
- String categoryName = "";
- String categoryDescription = "";
-
- if (name != null) {
- JClassType categoryType = typeOracle.findType(name);
-
- if (categoryType != null) {
- categoryName = getSimpleMetaData(categoryType, GWT_BENCHMARK_NAME);
- categoryDescription = getSimpleMetaData(categoryType,
- GWT_BENCHMARK_DESCRIPTION);
- }
- }
-
- c = new CategoryImpl(name, categoryName, categoryDescription);
+ c = getCategoryMetaData(name);
testCategories.put(name, c);
return c;
}
+ private CategoryImpl getCategoryMetaData(String typeName) {
+ if (typeName == null) {
+ return new CategoryImpl(null, "", "");
+ }
+
+ JClassType categoryType = typeOracle.findType(typeName);
+
+ if (categoryType == null) {
+ return new CategoryImpl(typeName, "", "");
+ }
+
+ String categoryName = getSimpleMetaData(categoryType, GWT_BENCHMARK_NAME);
+ String categoryDescription = getSimpleMetaData(categoryType,
+ GWT_BENCHMARK_DESCRIPTION);
+
+ if (categoryName != null || categoryDescription != null) {
+ deprecationBranch.log(TreeLogger.WARN, GWT_BENCHMARK_NAME + " and " +
+ GWT_BENCHMARK_DESCRIPTION + " have been deprecated with no "
+ + "replacement", null);
+ }
+
+ categoryName = categoryName == null ? "" : categoryName;
+ categoryDescription = categoryDescription == null ? "" : categoryDescription;
+
+ return new CategoryImpl(typeName, categoryName,
+ categoryDescription);
+ }
+
/**
* Parses out the JavaDoc comment from a string of source code. Returns the
* first sentence summary in <code>summary</code> and the body of the entire
diff --git a/user/src/com/google/gwt/junit/client/Benchmark.java b/user/src/com/google/gwt/junit/client/Benchmark.java
index eaa2a65..e226308 100644
--- a/user/src/com/google/gwt/junit/client/Benchmark.java
+++ b/user/src/com/google/gwt/junit/client/Benchmark.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
@@ -17,71 +17,56 @@
/**
* A type of {@link com.google.gwt.junit.client.GWTTestCase} which specifically
- * records performance results. {@link com.google.gwt.junit.client.Benchmark}s
- * have additional functionality above and beyond GWT's JUnit support for
- * standard <code>TestCases</code>.
+ * records performance results. {@code Benchmarks} have additional functionality
+ * above and beyond GWT's JUnit support for standard <code>TestCases</code>.
*
- * <ul>
- * <li>In a single <code>JUnit</code> run, the results of all executed
+ * <h2>Reporting</h2>
+ * <p>
+ * In a single <code>JUnit</code> run, the results of all executed
* benchmarks are collected and stored in an XML report viewable with the
- * <code>benchmarkViewer</code>.</li>
+ * <code>benchmarkViewer</code>.
+ * </p><br>
*
- * <li>GWT automatically removes jitter from your benchmark methods by running
- * them for a minimum period of time (150ms). GWT also optionally limits your
- * benchmark execution to a maximum period of time (1000ms).</li>
+ * <h2>Permutations</h2>
+ * <p>GWT supports test methods that have parameters. GWT will execute each
+ * benchmark method multiple times in order to exhaustively test all the
+ * possible combinations of parameter values. All of your test method parameters
+ * must be annotated with a {@code Range} annotation such as
+ * {@link com.google.gwt.junit.client.annotations.RangeField RangeField}
+ * or {@link com.google.gwt.junit.client.annotations.RangeEnum RangeEnum}.
*
- * <li>GWT supports "begin" and "end" test methods that separate setup and
- * teardown costs from the actual work being benchmarked. Simply name your
- * functions "begin[TestMethodName]" and "end[TestMethodName]" and they will
- * be executed before and after every execution of your test method. The
- * timings of these setup methods are not included in the test results.</li>
+ * For example,
*
- * <li>GWT supports test methods that have parameters. GWT will execute each
- * benchmark method multiple times in order to exhaustively test all the possible
- * combinations of parameter values. For each parameter that your test method
- * accepts, it should document it with the annotation,
- * <code>@gwt.benchmark.param</code>.
- *
- * <p>The syntax for gwt.benchmark.param is
- * <code><param name> = <Iterable></code>. For example,
- *
- * <pre>
- * @gwt.benchmark.param where = java.util.Arrays.asList(
- * new Position[] { Position.BEGIN, Position.END, Position.VARIED } )
- * @gwt.benchmark.param size -limit = insertRemoveRange
- * public void testArrayListRemoves(Position where, Integer size) { ... }
- * </pre></p>
- *
- * <p>In this example, the annotated function is executed with all the possible
- * permutations of <code>Position = (BEGIN, END, and VARIED)</code> and
- * <code>insertRemoveRange = IntRange( 64, Integer.MAX_VALUE, "*", 2 )</code>.
+ * <code><pre>
+ * public void testArrayListRemoves(
+ * @RangeEnum(Position.class) Position where,
+ * @RangeField("insertRemoveRange") Integer size) { ...
+ * }
+ * </pre></code>
* </p>
+ *
+ * <h2>Timing</h2>
+ * <ul>
+ * <li>GWT automatically removes jitter from your benchmark methods by running
+ * them for a minimum period of time (150ms).</li>
*
- * <p>This particular example also demonstrates how GWT can automatically limit
- * the number of executions of your test. Your final parameter (in this example,
- * size) can optionally be decorated with -limit to indicate to GWT that
- * it should stop executing additional permutations of the test when the
- * execution time becomes too long (over 1000ms). So, in this example,
- * for each value of <code>Position</code>, <code>testArrayListRemoves</code>
- * will be executed for increasing values of <code>size</code> (beginning with
- * 64 and increasing in steps of 2), until either it reaches
- * <code>Integer.MAX_VALUE</code> or the execution time for the last
- * permutation is > 1000ms.</p>
+ * <li>GWT supports {@link com.google.gwt.junit.client.annotations.IterationTimeLimit
+ * time limits} on the maximum duration of each permutation of a benchmark
+ * method. With this feature, you can supply very high upper bounds on your
+ * ranges (such as Integer.MAX_VALUE), which future-proofs your benchmarks
+ * against faster hardware.
+ * </li>
+ *
+ * <li>GWT supports {@link com.google.gwt.junit.client.annotations.Setup Setup}
+ * and {@link com.google.gwt.junit.client.annotations.Teardown Teardown} methods
+ * which separate test overhead from the actual work being benchmarked. The
+ * timings of these lifecycle methods are excluded from test results.
* </li>
* </ul>
*
- * <p>{@link Benchmark}s support the following annotations on each test method
- * in order to decorate each test with additional information useful for
- * reporting.</p>
- *
- * <ul>
- * <li><code>@gwt.benchmark.category</code> - The class name of the {@link Category} the
- * benchmark belongs to. This property may also be set at the
- * {@link com.google.gwt.junit.client.Benchmark} class level.</li>
- * </ul>
- *
- * <p>Please note that {@link Benchmark}s do not currently support asynchronous
- * testing mode. Calling
+ * <h2>Notes</h2>
+ * <p>Please note that {@code Benchmarks} do not currently support
+ * asynchronous testing mode. Calling
* {@link com.google.gwt.junit.client.GWTTestCase#delayTestFinish(int)}
* or {@link com.google.gwt.junit.client.GWTTestCase#finishTest()} will result
* in an UnsupportedOperationException.</p>
@@ -96,12 +81,12 @@
* {@example com.google.gwt.examples.benchmarks.AllocBenchmark}
*
* <h3>An advanced benchmark example</h3>
- * {@link com.google.gwt.examples.benchmarks.ArrayListAndVectorBenchmark} is a more
- * sophisticated example of benchmarking. It demonstrates the use of "begin"
- * and "end" test methods, parameterized test methods, and automatic
- * test execution limits.
+ * {@link com.google.gwt.examples.benchmarks.ArrayListBenchmark} is a
+ * more sophisticated example of benchmarking. It demonstrates the use of
+ * {@code Setup} and {@code Teardown} test methods, parameterized test methods,
+ * and time limits.
*
- * {@example com.google.gwt.examples.benchmarks.ArrayListAndVectorBenchmark}
+ * {@example com.google.gwt.examples.benchmarks.ArrayListBenchmark}
*/
public abstract class Benchmark extends GWTTestCase {
diff --git a/user/src/com/google/gwt/junit/client/Category.java b/user/src/com/google/gwt/junit/client/Category.java
index 6ef1147..ff9c233 100644
--- a/user/src/com/google/gwt/junit/client/Category.java
+++ b/user/src/com/google/gwt/junit/client/Category.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,20 +16,10 @@
package com.google.gwt.junit.client;
/**
- * A benchmark category. {@link com.google.gwt.junit.client.Benchmark}s which
- * use the GWT annotation, <code>@gwt.benchmark.category</code>, must set it to
- * a class which implements this interface.
- *
- * <p>The following GWT annotations can be set on a <code>Category</code>:
- *
- * <ul>
- * <li><code>@gwt.benchmark.name</code> The name of the <code>Category</code>
- * </li>
- * <li><code>@gwt.benchmark.description</code> The description of the
- * <code>Category</code></li>
- * </ul>
- * </p>
+ * A named category that provides classification for
+ * {@link Benchmark Benchmarks}. Categories are now deprecated.
*
*/
+@Deprecated
public interface Category {
}
diff --git a/user/src/com/google/gwt/junit/client/Range.java b/user/src/com/google/gwt/junit/client/Range.java
index 4ee369c..db00c8a 100644
--- a/user/src/com/google/gwt/junit/client/Range.java
+++ b/user/src/com/google/gwt/junit/client/Range.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
@@ -26,7 +26,6 @@
*
* @param <T> the type that this range contains
*
- * TODO: Should iterator() return a RangeIterator<T>?
*/
public interface Range<T> extends Iterable<T> {
}
diff --git a/user/src/com/google/gwt/junit/client/annotations/IterationTimeLimit.java b/user/src/com/google/gwt/junit/client/annotations/IterationTimeLimit.java
new file mode 100644
index 0000000..bf578d5
--- /dev/null
+++ b/user/src/com/google/gwt/junit/client/annotations/IterationTimeLimit.java
@@ -0,0 +1,41 @@
+/*
+ * 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.annotations;
+
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Documented;
+
+/**
+ * Specifies a custom time limit for iterations on the decorated
+ * {@link com.google.gwt.junit.client.Benchmark Benchmark} method. Methods
+ * that aren't explicitly decorated with an IterationTimeLimit, receive the
+ * default value.
+ *
+ */
+@Target(ElementType.METHOD)
+@Documented
+public @interface IterationTimeLimit {
+
+ /**
+ * The maximum amount of time, in milliseconds, an iteration is persued before
+ * skipping to the next set of values in the {@code Range}. A value of 0 means
+ * that all values in the {@code Range} will be exhaustively tested.
+ *
+ * @return a maximum duration in milliseconds >= 0
+ */
+ long value() default 1000;
+}
diff --git a/user/src/com/google/gwt/junit/client/annotations/RangeEnum.java b/user/src/com/google/gwt/junit/client/annotations/RangeEnum.java
new file mode 100644
index 0000000..056710c
--- /dev/null
+++ b/user/src/com/google/gwt/junit/client/annotations/RangeEnum.java
@@ -0,0 +1,38 @@
+/*
+ * 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.annotations;
+
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Documented;
+
+/**
+ * Specifies an Enum containing the entire range of values for a parameter
+ * to a {@link com.google.gwt.junit.client.Benchmark} method.
+ *
+ */
+@Target(ElementType.PARAMETER)
+@Documented
+public @interface RangeEnum {
+
+ /**
+ * An <code>Enum</code> that contains the range of values that will be
+ * supplied to the test method.
+ *
+ * @return For example, {@code MyEnum.class}
+ */
+ Class<? extends Enum<?>> value();
+}
diff --git a/user/src/com/google/gwt/junit/client/annotations/RangeField.java b/user/src/com/google/gwt/junit/client/annotations/RangeField.java
new file mode 100644
index 0000000..ca569c2
--- /dev/null
+++ b/user/src/com/google/gwt/junit/client/annotations/RangeField.java
@@ -0,0 +1,42 @@
+/*
+ * 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.annotations;
+
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Documented;
+
+/**
+ * Specifies a field containing the entire range of values for a parameter
+ * to a {@link com.google.gwt.junit.client.Benchmark} method. The field must belong
+ * to the same class being decorated by this annotation. The field must
+ * be either an Iterable, Enum, or array whose type matches the parameter
+ * being annotated.
+ *
+ * Also see {@link RangeEnum}.
+ *
+ */
+@Target(ElementType.PARAMETER)
+@Documented
+public @interface RangeField {
+
+ /**
+ * The name of the field that this range refers to.
+ *
+ * @return For example, {@code myCommonRange}.
+ */
+ String value();
+}
diff --git a/user/src/com/google/gwt/junit/client/annotations/Setup.java b/user/src/com/google/gwt/junit/client/annotations/Setup.java
new file mode 100644
index 0000000..6bd3b6a
--- /dev/null
+++ b/user/src/com/google/gwt/junit/client/annotations/Setup.java
@@ -0,0 +1,44 @@
+/*
+ * 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.annotations;
+
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Documented;
+
+/**
+ * Specifies a setup method that will be executed before the annotated
+ * {@link com.google.gwt.junit.client.Benchmark} test method. Setup methods are automatically executed
+ * by the benchmarking framework before their matching test methods. Setup
+ * measurements are excluded from final benchmark reports.
+ *
+ * <p>For example, you might annotate a {@code Benchmark} method named
+ * <code>testInserts</code> with <code>@Setup("setupTestInserts")</code> to
+ * ensure <code>setupTestInserts</code> is always executed before
+ * <code>testInserts</code>.
+ *
+ */
+@Target(ElementType.METHOD)
+@Documented
+public @interface Setup {
+
+ /**
+ * The name of the method to execute before the annotated test method.
+ *
+ * @return For example, "setupTestInserts".
+ */
+ public String value();
+}
diff --git a/user/src/com/google/gwt/junit/client/annotations/Teardown.java b/user/src/com/google/gwt/junit/client/annotations/Teardown.java
new file mode 100644
index 0000000..581a1c4
--- /dev/null
+++ b/user/src/com/google/gwt/junit/client/annotations/Teardown.java
@@ -0,0 +1,44 @@
+/*
+ * 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.annotations;
+
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Documented;
+
+/**
+ * Specifies a teardown method that will be executed after the annotated
+ * {@link com.google.gwt.junit.client.Benchmark} test method. Teardown methods are automatically executed
+ * by the benchmarking framework after their matching test methods. Teardown
+ * measurements are excluded from final benchmark reports.
+ *
+ * <p>For example, you might annotate a {@code Benchmark} method named
+ * <code>testInserts</code> with <code>@Teardown("endTestInserts")</code> to
+ * ensure <code>endTestInserts</code> is always executed after
+ * <code>testInserts</code>.
+ *
+ */
+@Target(ElementType.METHOD)
+@Documented
+public @interface Teardown {
+
+ /**
+ * The name of the method to execute after the annotated test method.
+ *
+ * @return For example, "endTestInserts".
+ */
+ public String value();
+}
diff --git a/user/src/com/google/gwt/junit/client/impl/IterableAdapter.java b/user/src/com/google/gwt/junit/client/impl/IterableAdapter.java
new file mode 100644
index 0000000..140c6a5
--- /dev/null
+++ b/user/src/com/google/gwt/junit/client/impl/IterableAdapter.java
@@ -0,0 +1,46 @@
+/*
+ * 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 java.util.Arrays;
+
+/**
+ * Provides convenience methods for adapting various values to the Iterable
+ * interface.
+ *
+ */
+public class IterableAdapter {
+
+ /**
+ * Returns an <code>Iterable</code> from an array.
+ *
+ * @param array a not <code>null</code> array
+ * @return an <code>Iterable</code> that wraps the array
+ */
+ public static <T> Iterable<T> toIterable(T[] array) {
+ return Arrays.asList(array);
+ }
+
+ /**
+ * Returns <code>iterable</code> as itself. Useful for code-gen situations.
+ *
+ * @param iterable a maybe <code>null</code> <code>Iterable</code>
+ * @return <code>iterable</code>
+ */
+ public static <T> Iterable<T> toIterable(Iterable<T> iterable) {
+ return iterable;
+ }
+}
diff --git a/user/src/com/google/gwt/junit/client/impl/PermutationIterator.java b/user/src/com/google/gwt/junit/client/impl/PermutationIterator.java
index b660871..25d1504 100644
--- a/user/src/com/google/gwt/junit/client/impl/PermutationIterator.java
+++ b/user/src/com/google/gwt/junit/client/impl/PermutationIterator.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,32 +15,29 @@
*/
package com.google.gwt.junit.client.impl;
-import com.google.gwt.junit.client.Range;
-
import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
/**
- * Iterates over all the possible permutations available in a list of
- * {@link com.google.gwt.junit.client.Range}s.
- *
- * <p>
- * The simplest way to iterate over the permutations of multiple iterators is in
- * a nested for loop. The PermutationIterator turns that for loop inside out
- * into a single iterator, which enables you to access each permutation in a
- * piecemeal fashion.
- * </p>
+ * Iterates over all the possible permutations available in a list of {@link
+ * Iterable Iterables}.
+ *
+ * <p> The simplest way to iterate over the permutations of multiple iterators
+ * is in a nested for loop. The PermutationIterator turns that for loop inside
+ * out into a single iterator, which enables you to access each permutation in a
+ * piecemeal fashion. </p>
*/
-public class PermutationIterator implements
- Iterator<PermutationIterator.Permutation> {
+public class PermutationIterator
+ implements Iterator<PermutationIterator.Permutation> {
/**
* A single permutation of all the iterators. Contains the current value of
* each iterator for the permutation.
*/
public static class Permutation {
+
private List<Object> values;
public Permutation(List<?> values) {
@@ -57,45 +54,27 @@
}
}
- /**
- * A Range implemented using a list of data.
- *
- * @param <T> the type of data in the range.
- */
- private static class ListRange<T> implements Range<T> {
- private List<T> list;
-
- public ListRange(List<T> list) {
- this.list = list;
- }
-
- public Iterator<T> iterator() {
- return list.iterator();
- }
- }
-
public static void main(String[] args) {
- List<Range<String>> ranges = new ArrayList<Range<String>>(3);
- ranges.add(new ListRange<String>(
- Arrays.asList("a", "b", "c")));
- ranges.add(new ListRange<String>(
- Arrays.asList("1", "2", "3")));
- ranges.add(new ListRange<String>(Arrays.asList(
- "alpha", "beta", "gamma", "delta")));
+ List<Iterable<String>> iterables = new ArrayList<Iterable<String>>(3);
+ iterables.add(Arrays.asList("a", "b", "c"));
+ iterables.add(Arrays.asList("1", "2", "3"));
+ iterables.add(Arrays.asList("alpha", "beta", "gamma", "delta"));
System.out.println("Testing normal iteration.");
- for (Iterator<Permutation> it = new PermutationIterator(ranges); it.hasNext();) {
+ for (Iterator<Permutation> it = new PermutationIterator(iterables);
+ it.hasNext();) {
Permutation p = it.next();
System.out.println(p);
}
System.out.println("\nTesting skipping iteration.");
- Iterator<String> skipIterator = Arrays.asList(
- "alpha", "beta", "gamma", "delta").iterator();
+ Iterator<String> skipIterator = Arrays
+ .asList("alpha", "beta", "gamma", "delta").iterator();
boolean skipped = true;
String skipValue = null;
- for (PermutationIterator it = new PermutationIterator(ranges); it.hasNext();) {
+ for (PermutationIterator it = new PermutationIterator(iterables);
+ it.hasNext();) {
Permutation p = it.next();
if (skipped) {
@@ -132,9 +111,9 @@
private boolean maybeHaveMore = true;
/**
- * The ranges to permutate.
+ * The {@code Iterables} to permute.
*/
- private List<? extends Range<?>> ranges;
+ private List<? extends Iterable<?>> iterables;
/**
* Did we just skip a range? If so, the values List already contains the
@@ -149,22 +128,21 @@
/**
* Constructs a new PermutationIterator that provides the values for each
- * possible permutation of <code>ranges</code>.
- *
- * @param ranges non-null. Each {@link com.google.gwt.junit.client.Range} must
- * have at least one element. ranges.size() must be > 1
- *
- * TODO(tobyr) Consider if empty Ranges ever make sense in the context of
- * permutations.
- *
+ * possible permutation of <code>iterables</code>.
+ *
+ * @param iterables non-null. Each {@link Iterable} must have at least one
+ * element. iterables.size() must be > 1
+ *
+ * TODO(tobyr) Consider if empty Iterables ever make sense in
+ * the context of permutations.
*/
- public PermutationIterator(List<? extends Range<?>> ranges) {
- this.ranges = ranges;
+ public PermutationIterator(List<? extends Iterable<?>> iterables) {
+ this.iterables = iterables;
iterators = new ArrayList<Iterator<?>>();
- for (Range<?> r : ranges) {
- iterators.add(r.iterator());
+ for (Iterable<?> iterable : iterables) {
+ iterators.add(iterable.iterator());
}
values = new ArrayList<Object>();
@@ -173,7 +151,7 @@
/**
* Returns a new <code>Permutation</code> containing the values of the next
* permutation.
- *
+ *
* @return a non-null <code>Permutation</code>
*/
public boolean hasNext() {
@@ -185,7 +163,8 @@
// Walk the iterators from bottom to top checking to see if any still have
// any available values
- for (int currentIterator = iterators.size() - 1; currentIterator >= 0; --currentIterator) {
+ for (int currentIterator = iterators.size() - 1; currentIterator >= 0;
+ --currentIterator) {
Iterator<?> it = iterators.get(currentIterator);
if (it.hasNext()) {
return true;
@@ -216,13 +195,14 @@
// Walk through the iterators from bottom to top, finding the first one
// which has a value available. Increment it, reset all of the subsequent
// iterators, and then return the current permutation.
- for (int currentIteratorIndex = iterators.size() - 1; currentIteratorIndex >= 0; --currentIteratorIndex) {
+ for (int currentIteratorIndex = iterators.size() - 1;
+ currentIteratorIndex >= 0; --currentIteratorIndex) {
Iterator<?> it = iterators.get(currentIteratorIndex);
if (it.hasNext()) {
values.set(currentIteratorIndex, it.next());
for (int i = currentIteratorIndex + 1; i < iterators.size(); ++i) {
- Range<?> resetRange = ranges.get(i);
- Iterator<?> resetIterator = resetRange.iterator();
+ Iterable<?> resetIterable = iterables.get(i);
+ Iterator<?> resetIterator = resetIterable.iterator();
iterators.set(i, resetIterator);
values.set(i, resetIterator.next());
}
@@ -240,24 +220,23 @@
}
/**
- * Skips the remaining set of values in the bottom
- * {@link com.google.gwt.junit.client.Range}. This method affects the results
- * of both hasNext() and next().
- *
+ * Skips the remaining set of values in the bottom {@code Iterable}. This
+ * method affects the results of both hasNext() and next().
*/
public void skipCurrentRange() {
rangeSkipped = true;
- for ( int currentIteratorIndex = iterators.size() - 2; currentIteratorIndex >= 0; --currentIteratorIndex ) {
- Iterator<?> it = iterators.get( currentIteratorIndex );
- if ( it.hasNext() ) {
- values.set( currentIteratorIndex, it.next() );
- for ( int i = currentIteratorIndex + 1; i < iterators.size(); ++i ) {
- Range<?> resetRange = ranges.get( i );
- Iterator<?> resetIterator = resetRange.iterator();
- iterators.set( i, resetIterator );
- values.set( i, resetIterator.next() );
+ for (int currentIteratorIndex = iterators.size() - 2;
+ currentIteratorIndex >= 0; --currentIteratorIndex) {
+ Iterator<?> it = iterators.get(currentIteratorIndex);
+ if (it.hasNext()) {
+ values.set(currentIteratorIndex, it.next());
+ for (int i = currentIteratorIndex + 1; i < iterators.size(); ++i) {
+ Iterable<?> resetIterable = iterables.get(i);
+ Iterator<?> resetIterator = resetIterable.iterator();
+ iterators.set(i, resetIterator);
+ values.set(i, resetIterator.next());
}
return;
}
diff --git a/user/src/com/google/gwt/junit/rebind/BenchmarkGenerator.java b/user/src/com/google/gwt/junit/rebind/BenchmarkGenerator.java
index df74865..5ddbfeb 100644
--- a/user/src/com/google/gwt/junit/rebind/BenchmarkGenerator.java
+++ b/user/src/com/google/gwt/junit/rebind/BenchmarkGenerator.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
@@ -20,7 +20,14 @@
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.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;
@@ -34,6 +41,7 @@
import java.util.HashMap;
import java.util.ArrayList;
import java.util.Collections;
+import java.lang.reflect.Method;
/**
* Implements a generator for Benchmark classes. Benchmarks require additional
@@ -41,8 +49,9 @@
*/
public class BenchmarkGenerator extends JUnitTestCaseStubGenerator {
- private static class MutableBoolean {
- boolean value;
+ private static class MutableLong {
+
+ long value;
}
private static final String BEGIN_PREFIX = "begin";
@@ -55,20 +64,23 @@
private static final String ESCAPE_LOOP = "__escapeLoop";
+ private static long defaultTimeout = -1;
+
/**
* Returns all the zero-argument JUnit test methods that do not have
* overloads.
*
* @return Map<String,JMethod>
*/
- public static Map<String, JMethod> getNotOverloadedTestMethods(JClassType requestedClass) {
- Map<String, List<JMethod>> methods =
- getAllMethods(requestedClass, new MethodFilter() {
- public boolean accept(JMethod method) {
- return isJUnitTestMethod(method, true);
- }
- });
-
+ public static Map<String, JMethod> getNotOverloadedTestMethods(
+ JClassType requestedClass) {
+ Map<String, List<JMethod>> methods = getAllMethods(requestedClass,
+ new MethodFilter() {
+ public boolean accept(JMethod method) {
+ return isJUnitTestMethod(method, true);
+ }
+ });
+
// Create a new map to store the methods
Map<String, JMethod> notOverloadedMethods = new HashMap<String, JMethod>();
for (Map.Entry<String, List<JMethod>> entry : methods.entrySet()) {
@@ -87,19 +99,18 @@
*
* @return Map<String,JMethod>
*/
- public static Map<String, JMethod> getParameterizedTestMethods(JClassType requestedClass,
- TreeLogger logger) {
-
- Map<String, List<JMethod>> testMethods =
- getAllMethods(requestedClass, new MethodFilter() {
- public boolean accept(JMethod method) {
- return isJUnitTestMethod(method, true);
- }
- });
+ public static Map<String, JMethod> getParameterizedTestMethods(
+ JClassType requestedClass, TreeLogger logger) {
+ Map<String, List<JMethod>> testMethods = getAllMethods(requestedClass,
+ new MethodFilter() {
+ public boolean accept(JMethod method) {
+ return isJUnitTestMethod(method, true);
+ }
+ });
// Create a new mapping to return
Map<String, JMethod> overloadedMethods = new HashMap<String, JMethod>();
-
+
// Remove all non-overloaded test methods
for (Map.Entry<String, List<JMethod>> entry : testMethods.entrySet()) {
String name = entry.getKey();
@@ -107,8 +118,8 @@
if (methods.size() > 2) {
String msg = requestedClass + "." + name
- + " has more than one overloaded version.\n" +
- "It will not be included in the test case execution.";
+ + " has more than one overloaded version.\n"
+ + "It will not be included in the test case execution.";
logger.log(TreeLogger.WARN, msg, null);
continue;
}
@@ -122,8 +133,8 @@
* test to make the benchmarks run correctly (JUnit artifact).
*/
String msg = requestedClass + "." + name
- + " does not have a zero-argument overload.\n" +
- "It will not be included in the test case execution.";
+ + " does not have a zero-argument overload.\n"
+ + "It will not be included in the test case execution.";
logger.log(TreeLogger.WARN, msg, null);
}
// Only a zero-argument version, we don't need to process it.
@@ -149,8 +160,8 @@
if (noArgMethod == null) {
String msg = requestedClass + "." + name
- + " does not have a zero-argument overload.\n" +
- "It will not be included in the test case execution.";
+ + " does not have a zero-argument overload.\n"
+ + "It will not be included in the test case execution.";
logger.log(TreeLogger.WARN, msg, null);
continue;
}
@@ -161,16 +172,28 @@
return overloadedMethods;
}
- private static JMethod getBeginMethod(JClassType type, String name) {
- StringBuffer methodName = new StringBuffer(name);
- methodName.replace(0, "test".length(), BEGIN_PREFIX);
- return getMethod(type, methodName.toString());
+ private static JMethod getBeginMethod(JClassType type, JMethod method) {
+ Setup setup = method.getAnnotation(Setup.class);
+ String methodName;
+ if (setup != null) {
+ methodName = setup.value();
+ } else {
+ methodName = new StringBuffer(method.getName())
+ .replace(0, "test".length(), BEGIN_PREFIX).toString();
+ }
+ return getMethod(type, methodName);
}
- private static JMethod getEndMethod(JClassType type, String name) {
- StringBuffer methodName = new StringBuffer(name);
- methodName.replace(0, "test".length(), END_PREFIX);
- return getMethod(type, methodName.toString());
+ private static JMethod getEndMethod(JClassType type, JMethod method) {
+ Teardown teardown = method.getAnnotation(Teardown.class);
+ String methodName;
+ if (teardown != null) {
+ methodName = teardown.value();
+ } else {
+ methodName = new StringBuffer(method.getName())
+ .replace(0, "test".length(), END_PREFIX).toString();
+ }
+ return getMethod(type, methodName);
}
private static JMethod getMethod(JClassType type, MethodFilter filter) {
@@ -191,10 +214,16 @@
});
}
+ private TreeLogger deprecationBranch;
+
@Override
public void writeSource() throws UnableToCompleteException {
super.writeSource();
+ deprecationBranch = logger.branch(TreeLogger.TRACE,
+ "Scanning Benchmarks for deprecated annotations; " + "Please see "
+ + Benchmark.class.getName() + " for more information.", null);
+
generateEmptyFunc(getSourceWriter());
implementZeroArgTestMethods();
implementParameterizedTestMethods();
@@ -211,7 +240,8 @@
* wrapped <code>stmts</code>
*/
private Statements benchmark(Statements stmts, String timeMillisName,
- boolean generateEscape, Statements recordCode, Statements breakCode) {
+ long bound, Statements recordCode, Statements breakCode)
+ throws UnableToCompleteException {
Statements benchmarkCode = new StatementsList();
List<Statements> benchStatements = benchmarkCode.getStatements();
@@ -225,17 +255,15 @@
loopStatements.add(runLoop);
// Put the rest of the code in 1 big statement to simplify things
- String benchCode =
- "long duration = System.currentTimeMillis() - start;\n\n" +
+ String benchCode = "long duration = System.currentTimeMillis() - start;\n\n"
+ +
- "if ( duration < 150 ) {\n" +
- " numLoops += numLoops;\n" +
- " continue;\n" +
- "}\n\n" +
+ "if ( duration < 150 ) {\n" + " numLoops += numLoops;\n"
+ + " continue;\n" + "}\n\n" +
- "double durationMillis = duration * 1.0;\n" +
- "double numLoopsAsDouble = numLoops * 1.0;\n" +
- timeMillisName + " = durationMillis / numLoopsAsDouble";
+ "double durationMillis = duration * 1.0;\n"
+ + "double numLoopsAsDouble = numLoops * 1.0;\n" + timeMillisName
+ + " = durationMillis / numLoopsAsDouble";
loopStatements.add(new Statement(benchCode));
@@ -243,12 +271,10 @@
loopStatements.add(recordCode);
}
- if (generateEscape) {
- loopStatements.add(new Statement(
- "if ( numLoops == 1 && duration > 1000 ) {\n" +
- breakCode.toString() + "\n" +
- "}\n\n"
- ));
+ if (bound != 0) {
+ loopStatements.add(new Statement("if ( numLoops == 1 && duration > "
+ + bound + " ) {\n" + breakCode.toString() + "\n"
+ + "}\n\n"));
}
loopStatements.add(new Statement("break"));
@@ -256,44 +282,17 @@
return benchmarkCode;
}
- /**
- * Generates code that executes <code>statements</code> for all possible
- * values of <code>params</code>. Exports a label named ESCAPE_LOOP that
- * points to the the "inner loop" that should be escaped to for a limited
- * variable.
- *
- * @return the generated code
- * TODO: Is this used anywhere?
- */
- private Statements executeForAllValues(JParameter[] methodParams,
- Map<String, String> params, Statements statements) {
- Statements root = new StatementsList();
- Statements currentContext = root;
-
- // Profile the setup and teardown costs for this test method
- // but only if 1 of them exists.
- for (int i = 0; i < methodParams.length; ++i) {
- JParameter methodParam = methodParams[i];
- String paramName = methodParam.getName();
- String paramValue = params.get(paramName);
- String typeName = methodParam.getType().getQualifiedSourceName();
-
- String iteratorName = "it_" + paramName;
- String initializer = "java.util.Iterator<" + typeName + "> " + iteratorName + " = "
- + paramValue + ".iterator()";
- ForLoop loop = new ForLoop(initializer, iteratorName + ".hasNext()", "");
- if (i == methodParams.length - 1) {
- loop.setLabel(ESCAPE_LOOP);
+ private boolean fieldExists(JClassType type, String fieldName) {
+ JField field = type.findField(fieldName);
+ if (field == null) {
+ JClassType superClass = type.getSuperclass();
+ // noinspection SimplifiableIfStatement
+ if (superClass == null) {
+ return false;
}
- currentContext.getStatements().add(loop);
- loop.getStatements().add(new Statement(typeName + " " + paramName + " = "
- + iteratorName + ".next()"));
- currentContext = loop;
+ return fieldExists(superClass, fieldName);
}
-
- currentContext.getStatements().add(statements);
-
- return root;
+ return true;
}
private Statements genBenchTarget(JMethod beginMethod, JMethod endMethod,
@@ -317,10 +316,10 @@
}
/**
- * Currently, the benchmarking subsystem does not support async Benchmarks,
- * so we need to generate some additional code that prevents the user
- * from entering async mode in their Benchmark, even though we're using
- * it internally.
+ * Currently, the benchmarking subsystem does not support async Benchmarks, so
+ * we need to generate some additional code that prevents the user from
+ * entering async mode in their Benchmark, even though we're using it
+ * internally.
*
* Generates the code for the "supportsAsync" functionality in the
* translatable version of GWTTestCase. This includes:
@@ -334,29 +333,29 @@
private void generateAsyncCode() {
SourceWriter writer = getSourceWriter();
- writer.println( "private boolean supportsAsync;" );
+ writer.println("private boolean supportsAsync;");
writer.println();
- writer.println( "public boolean supportsAsync() {");
- writer.println( " return supportsAsync;");
- writer.println( "}");
+ writer.println("public boolean supportsAsync() {");
+ writer.println(" return supportsAsync;");
+ writer.println("}");
writer.println();
- writer.println( "private void privateDelayTestFinish(int timeout) {" );
- writer.println( " supportsAsync = true;");
- writer.println( " try {");
- writer.println( " delayTestFinish(timeout);");
- writer.println( " } finally {");
- writer.println( " supportsAsync = false;");
- writer.println( " }");
- writer.println( "}");
+ writer.println("private void privateDelayTestFinish(int timeout) {");
+ writer.println(" supportsAsync = true;");
+ writer.println(" try {");
+ writer.println(" delayTestFinish(timeout);");
+ writer.println(" } finally {");
+ writer.println(" supportsAsync = false;");
+ writer.println(" }");
+ writer.println("}");
writer.println();
- writer.println( "private void privateFinishTest() {" );
- writer.println( " supportsAsync = true;");
- writer.println( " try {");
- writer.println( " finishTest();");
- writer.println( " } finally {");
- writer.println( " supportsAsync = false;");
- writer.println( " }");
- writer.println( "}");
+ writer.println("private void privateFinishTest() {");
+ writer.println(" supportsAsync = true;");
+ writer.println(" try {");
+ writer.println(" finishTest();");
+ writer.println(" } finally {");
+ writer.println(" supportsAsync = false;");
+ writer.println(" }");
+ writer.println("}");
writer.println();
}
@@ -383,17 +382,99 @@
writer.println("}-*/;");
writer.println();
}
+
+ private Map<String, String> getAnnotationMetaData(JMethod method,
+ MutableLong bound) throws UnableToCompleteException {
- private Map<String,String> getParamMetaData(JMethod method,
- MutableBoolean isBounded) throws UnableToCompleteException {
- Map<String,String> params = new HashMap<String,String>();
+ IterationTimeLimit limit = method.getAnnotation(IterationTimeLimit.class);
+ // noinspection SimplifiableIfStatement
+ if (limit == null) {
+ bound.value = getDefaultTimeout();
+ } else {
+ bound.value = limit.value();
+ }
+ Map<String, String> paramMetaData = new HashMap<String, String>();
+
+ JParameter[] params = method.getParameters();
+
+ for (JParameter param : params) {
+ RangeField rangeField = param.getAnnotation(RangeField.class);
+ if (rangeField != null) {
+ String fieldName = rangeField.value();
+ JClassType enclosingType = method.getEnclosingType();
+ if (!fieldExists(enclosingType, fieldName)) {
+ logger.log(TreeLogger.ERROR, "The RangeField annotation on " +
+ enclosingType + " at " + method + " specifies a field, " +
+ fieldName + ", which could not be found. Perhaps it is " +
+ "mis-spelled?", null);
+ throw new UnableToCompleteException();
+ }
+ paramMetaData.put(param.getName(), fieldName);
+ continue;
+ }
+ RangeEnum rangeEnum = param.getAnnotation(RangeEnum.class);
+ if (rangeEnum != null) {
+ Class<? extends Enum<?>> enumClass = rangeEnum.value();
+ // Handle inner classes
+ String className = enumClass.getName().replace('$', '.');
+ paramMetaData.put(param.getName(), className + ".values()");
+ continue;
+ }
+
+ String msg = "The parameter, " + param.getName() + ", on method, "
+ + method.getName() + ", must have it's range specified"
+ + "by a RangeField or RangeEnum annotation.";
+ logger.log(TreeLogger.ERROR, msg, null);
+ throw new UnableToCompleteException();
+ }
+
+ return paramMetaData;
+ }
+
+ private synchronized long getDefaultTimeout()
+ throws UnableToCompleteException {
+ if (defaultTimeout != -1) {
+ return defaultTimeout;
+ }
+ Method m = null;
+ try {
+ m = IterationTimeLimit.class.getDeclaredMethod("value");
+ defaultTimeout = (Long) m.getDefaultValue();
+ } catch (Exception e) {
+ /* Possibly one of:
+ * - NullPointerException (if somehow TimeLimit weren't an annotation
+ * or value() didn't have a default).
+ * - NoSuchMethodException if we somehow spelled value wrong
+ * - TypeNotPresentException if somehow value were some type of Class
+ * that couldn't be loaded instead of long
+ * It really doesn't make any difference, because regardless of what
+ * could possibly have failed, we'll still need to go this route.
+ */
+ logger.log(TreeLogger.ERROR,
+ "Unable to retrieve the default benchmark time limit", e);
+ throw new UnableToCompleteException();
+ }
+
+ return defaultTimeout;
+ }
+
+ private Map<String, String> getParamMetaData(JMethod method,
+ MutableLong bound) throws UnableToCompleteException {
String[][] allValues = method.getMetaData(BENCHMARK_PARAM_META);
- if (allValues == null) {
- return params;
+ if (allValues == null || allValues.length == 0) {
+ return getAnnotationMetaData(method, bound);
}
+ deprecationBranch.log(TreeLogger.WARN, "Deprecated use of "
+ + BENCHMARK_PARAM_META + " at " + method.getEnclosingType()
+ + " in " + method
+ + "; Please use the new Benchmark JDK 1.5 annotations in " +
+ "com.google.gwt.junit.client.annotations.", null);
+
+ Map<String, String> params = new HashMap<String, String>();
+
for (int i = 0; i < allValues.length; ++i) {
String[] values = allValues[i];
StringBuffer result = new StringBuffer();
@@ -409,15 +490,15 @@
paramName = nameExprs[0];
// Make sure this is the last parameter
JParameter[] parameters = method.getParameters();
- if (! parameters[parameters.length - 1].getName().equals(paramName)) {
+ if (!parameters[parameters.length - 1].getName().equals(paramName)) {
JClassType cls = method.getEnclosingType();
- String msg = "Error at " + cls + "." + method.getName() + "\n" +
- "Only the last parameter of a method can be marked with the -limit flag.";
+ String msg = "Error at " + cls + "." + method.getName() + "\n"
+ + "Only the last parameter of a method can be marked with the -limit flag.";
logger.log(TreeLogger.ERROR, msg, null);
throw new UnableToCompleteException();
}
- isBounded.value = true;
+ bound.value = getDefaultTimeout();
}
String paramValue = lhsAndRhs[1].trim();
params.put(paramName, paramValue);
@@ -426,10 +507,10 @@
return params;
}
- private void implementParameterizedTestMethods() throws
- UnableToCompleteException {
+ private void implementParameterizedTestMethods()
+ throws UnableToCompleteException {
- Map<String,JMethod> parameterizedMethods = getParameterizedTestMethods(
+ Map<String, JMethod> parameterizedMethods = getParameterizedTestMethods(
getRequestedClass(), logger);
SourceWriter sw = getSourceWriter();
JClassType type = getRequestedClass();
@@ -438,20 +519,20 @@
// a) overhead (setup + teardown + loop + function calls) and
// b) execution time
// for all possible parameter values
- for (Map.Entry<String,JMethod> entry : parameterizedMethods.entrySet() ) {
+ for (Map.Entry<String, JMethod> entry : parameterizedMethods.entrySet()) {
String name = entry.getKey();
JMethod method = entry.getValue();
- JMethod beginMethod = getBeginMethod(type, name);
- JMethod endMethod = getEndMethod(type, name);
+ JMethod beginMethod = getBeginMethod(type, method);
+ JMethod endMethod = getEndMethod(type, method);
sw.println("public void " + name + "() {");
sw.indent();
sw.println(" privateDelayTestFinish( 2000 );");
sw.println();
- MutableBoolean isBounded = new MutableBoolean();
- Map<String, String> params = getParamMetaData(method, isBounded);
- validateParams(method, params);
+ MutableLong bound = new MutableLong();
+ Map<String, String> metaDataByParams = getParamMetaData(method, bound);
+ validateParams(method, metaDataByParams);
JParameter[] methodParams = method.getParameters();
List<String> paramNames = new ArrayList<String>(methodParams.length);
@@ -459,39 +540,35 @@
paramNames.add(methodParams[i].getName());
}
- List<String> paramValues = new ArrayList<String>(methodParams.length);
- for (int i = 0; i < methodParams.length; ++i) {
- paramValues.add(params.get(methodParams[i].getName()));
- }
-
- sw.print( "final java.util.List<com.google.gwt.junit.client.Range/*<?>*/> ranges = java.util.Arrays.asList( new com.google.gwt.junit.client.Range/*<?>*/[] { " );
+ sw.print(
+ "final java.util.List<Iterable<?>> iterables = java.util.Arrays.asList( new Iterable<?>[] { ");
for (int i = 0; i < paramNames.size(); ++i) {
String paramName = paramNames.get(i);
- sw.print( params.get(paramName) );
+ sw.print("com.google.gwt.junit.client.impl.IterableAdapter.toIterable("
+ + metaDataByParams.get(paramName) + ")");
if (i != paramNames.size() - 1) {
- sw.print( ",");
+ sw.print(",");
} else {
- sw.println( "} );" );
+ sw.println("} );");
}
- sw.print( " " );
+ sw.print(" ");
}
sw.println(
- "final com.google.gwt.junit.client.impl.PermutationIterator permutationIt = new com.google.gwt.junit.client.impl.PermutationIterator( ranges );\n" +
- "com.google.gwt.user.client.DeferredCommand.addCommand( new com.google.gwt.user.client.IncrementalCommand() {\n" +
- " public boolean execute() {\n" +
- " privateDelayTestFinish( 10000 );\n" +
- " if ( permutationIt.hasNext() ) {\n" +
- " com.google.gwt.junit.client.impl.PermutationIterator.Permutation permutation = permutationIt.next();\n"
- );
+ "final com.google.gwt.junit.client.impl.PermutationIterator permutationIt = new com.google.gwt.junit.client.impl.PermutationIterator(iterables);\n"
+ + "com.google.gwt.user.client.DeferredCommand.addCommand( new com.google.gwt.user.client.IncrementalCommand() {\n"
+ + " public boolean execute() {\n"
+ + " privateDelayTestFinish( 10000 );\n"
+ + " if ( permutationIt.hasNext() ) {\n"
+ + " com.google.gwt.junit.client.impl.PermutationIterator.Permutation permutation = permutationIt.next();\n");
for (int i = 0; i < methodParams.length; ++i) {
JParameter methodParam = methodParams[i];
String typeName = methodParam.getType().getQualifiedSourceName();
String paramName = paramNames.get(i);
- sw.println( " " + typeName + " " + paramName + " = (" +
- typeName + ") permutation.getValues().get(" + i + ");");
+ sw.println(" " + typeName + " " + paramName + " = (" + typeName
+ + ") permutation.getValues().get(" + i + ");");
}
final String setupTimingName = "__setupTiming";
@@ -506,10 +583,11 @@
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.Trial trial = new com.google.gwt.junit.client.Trial();\n" +
- "trial.setRunTimeMillis( " + testTimingName + " - " + setupTimingName + " );\n" +
- "java.util.Map<String, String> variables = trial.getVariables();\n");
+ "com.google.gwt.junit.client.TestResults results = getTestResults();\n"
+ + "com.google.gwt.junit.client.Trial trial = new com.google.gwt.junit.client.Trial();\n"
+ + "trial.setRunTimeMillis( " + testTimingName + " - "
+ + setupTimingName + " );\n"
+ + "java.util.Map<String, String> variables = trial.getVariables();\n");
for (String paramName : paramNames) {
recordResultsCode.append("variables.put( \"")
@@ -522,15 +600,17 @@
recordResultsCode.append("results.getTrials().add( trial )");
Statements recordCode = new Statement(recordResultsCode.toString());
- Statements breakCode = new Statement( " permutationIt.skipCurrentRange()" );
- setupBench = benchmark(setupBench, setupTimingName, false, null, breakCode);
- testBench = benchmark(testBench, testTimingName, isBounded.value, recordCode, breakCode);
+ Statements breakCode = new Statement(
+ " permutationIt.skipCurrentRange()");
+ setupBench = benchmark(setupBench, setupTimingName, 0, null, breakCode);
+ testBench = benchmark(testBench, testTimingName, bound.value, recordCode,
+ breakCode);
Statements testAndSetup = new StatementsList();
testAndSetup.getStatements().addAll(setupBench.getStatements());
testAndSetup.getStatements().addAll(testBench.getStatements());
- sw.println( testAndSetup.toString() );
+ sw.println(testAndSetup.toString());
sw.println(
" return true;\n" +
@@ -554,17 +634,17 @@
* implementParameterizedTestMethods and they should probably be refactored
* into a single function.
*/
- private void implementZeroArgTestMethods() {
- Map<String, JMethod> zeroArgMethods =
- getNotOverloadedTestMethods(getRequestedClass());
+ private void implementZeroArgTestMethods() throws UnableToCompleteException {
+ Map<String, JMethod> zeroArgMethods = getNotOverloadedTestMethods(
+ getRequestedClass());
SourceWriter sw = getSourceWriter();
JClassType type = getRequestedClass();
for (Map.Entry<String, JMethod> entry : zeroArgMethods.entrySet()) {
String name = entry.getKey();
JMethod method = entry.getValue();
- JMethod beginMethod = getBeginMethod(type, name);
- JMethod endMethod = getEndMethod(type, name);
+ JMethod beginMethod = getBeginMethod(type, method);
+ JMethod endMethod = getEndMethod(type, method);
sw.println("public void " + name + "() {");
sw.indent();
@@ -586,15 +666,15 @@
Collections.<String>emptyList(), testStatements);
String recordResultsCode =
- "com.google.gwt.junit.client.TestResults results = getTestResults();\n" +
- "com.google.gwt.junit.client.Trial trial = new com.google.gwt.junit.client.Trial();\n" +
- "trial.setRunTimeMillis( " + testTimingName + " - " + setupTimingName + " );\n" +
- "results.getTrials().add( trial )";
+ "com.google.gwt.junit.client.TestResults results = getTestResults();\n"
+ + "com.google.gwt.junit.client.Trial trial = new com.google.gwt.junit.client.Trial();\n"
+ + "trial.setRunTimeMillis( " + testTimingName + " - "
+ + setupTimingName + " );\n" + "results.getTrials().add( trial )";
- Statements breakCode = new Statement( " break " + ESCAPE_LOOP );
+ Statements breakCode = new Statement(" break " + ESCAPE_LOOP);
- setupBench = benchmark(setupBench, setupTimingName, false, null, breakCode);
- testBench = benchmark(testBench, testTimingName, true,
+ setupBench = benchmark(setupBench, setupTimingName, 0, null, breakCode);
+ testBench = benchmark(testBench, testTimingName, getDefaultTimeout(),
new Statement(recordResultsCode), breakCode);
ForLoop loop = (ForLoop) testBench.getStatements().get(0);
loop.setLabel(ESCAPE_LOOP);
@@ -616,8 +696,8 @@
if (paramValue == null) {
String msg = "Could not find the meta data attribute "
- + BENCHMARK_PARAM_META +
- " for the parameter " + paramName + " on method " + method
+ + BENCHMARK_PARAM_META + " for the parameter " + paramName
+ + " on method " + method
.getName();
logger.log(TreeLogger.ERROR, msg, null);
throw new UnableToCompleteException();
diff --git a/user/test/com/google/gwt/emultest/java/util/ArrayListBenchmark.java b/user/test/com/google/gwt/emultest/java/util/ArrayListBenchmark.java
new file mode 100644
index 0000000..9de8a5e
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java/util/ArrayListBenchmark.java
@@ -0,0 +1,29 @@
+/*
+ * 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.emultest.java.util;
+
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * A {@link ListBenchmark} for {@link ArrayList ArrayLists}.
+ */
+public class ArrayListBenchmark extends ListBenchmark {
+
+ protected List<String> newList() {
+ return new ArrayList<String>();
+ }
+}
diff --git a/user/test/com/google/gwt/emultest/java/util/HashMapBenchmark.java b/user/test/com/google/gwt/emultest/java/util/HashMapBenchmark.java
new file mode 100644
index 0000000..e1486e1
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java/util/HashMapBenchmark.java
@@ -0,0 +1,198 @@
+/*
+ * 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.emultest.java.util;
+
+import com.google.gwt.junit.client.Range;
+import com.google.gwt.junit.client.IntRange;
+import com.google.gwt.junit.client.Operator;
+import com.google.gwt.junit.client.Benchmark;
+import com.google.gwt.junit.client.annotations.RangeField;
+import com.google.gwt.junit.client.annotations.Setup;
+
+import java.util.HashMap;
+
+/**
+ * Benchmarks the HashMap implementation.
+ */
+public class HashMapBenchmark extends Benchmark {
+
+ protected Range baseRange = new IntRange(32, Integer.MAX_VALUE,
+ Operator.MULTIPLY, 2);
+
+ protected Range containsRange = new IntRange(10, 200, Operator.ADD, 20);
+
+ private HashMap<Object, Object> map;
+
+ public String getModuleName() {
+ return "com.google.gwt.emultest.EmulSuite";
+ }
+
+ public void testHashMapContainsValueInt() {
+ }
+
+ /**
+ * Checks for <code>size</code> values in a populated HashMap. All items are
+ * Integers, and contain duplicate values.
+ */
+ @Setup("beginHashMapContainsValueInt")
+ public void testHashMapContainsValueInt(
+ @RangeField("containsRange")Integer size) {
+ int num = size.intValue();
+ for (int i = 0; i < num; i++) {
+ Integer intVal = new Integer(i);
+ map.containsValue(intVal);
+ }
+ }
+
+ public void testHashMapContainsValueString() {
+ }
+
+ /**
+ * Checks for <code>size</code> values in a populated HashMap. All items are
+ * Strings, and contain duplicate values.
+ */
+ @Setup("beginHashMapContainsValueString")
+ public void testHashMapContainsValueString(
+ @RangeField("containsRange")Integer size) {
+ int num = size.intValue();
+ for (int i = 0; i < num; i++) {
+ String strVal = Integer.toString(i);
+ map.containsValue(strVal);
+ }
+ }
+
+ public void testHashMapDuplicateIntAdds() {
+ }
+
+ /**
+ * Appends <code>size</code> items to an empty HashMap. All items are
+ * Integers, and contain duplicate values.
+ */
+ @Setup("initMap")
+ public void testHashMapDuplicateIntAdds(
+ @RangeField("baseRange")Integer size) {
+ int num = size.intValue();
+ for (int i = 0; i < num; i++) {
+ Integer intVal = new Integer(i / 10);
+ map.put(intVal, intVal);
+ }
+ }
+
+ public void testHashMapDuplicateStringAdds() {
+ }
+
+ /**
+ * Appends <code>size</code> items to an empty HashMap. All items are Strings,
+ * and contain duplicate values.
+ */
+ @Setup("initMap")
+ public void testHashMapDuplicateStringAdds(
+ @RangeField("baseRange")Integer size) {
+ int num = size.intValue();
+ for (int i = 0; i < num; i++) {
+ String strVal = Integer.toString(i / 10);
+ map.put(strVal, strVal);
+ }
+ }
+
+ public void testHashMapIntAdds() {
+ }
+
+ /**
+ * Appends <code>size</code> items to an empty HashMap. All items are
+ * Integers, and do not contain duplicate values.
+ */
+ @Setup("initMap")
+ public void testHashMapIntAdds(@RangeField("baseRange")Integer size) {
+ int num = size.intValue();
+ for (int i = 0; i < num; i++) {
+ Integer intVal = new Integer(i);
+ map.put(intVal, intVal);
+ }
+ }
+
+ public void testHashMapIntGets() {
+ }
+
+ /**
+ * Checks for <code>size</code> values in a populated HashMap. All items are
+ * Integers, and contain duplicate values.
+ */
+ @Setup("beginHashMapIntGets")
+ public void testHashMapIntGets(@RangeField("baseRange")Integer size) {
+ int num = size.intValue();
+ for (int i = 0; i < num; i++) {
+ Integer intVal = new Integer(i);
+ map.get(intVal);
+ }
+ }
+
+ public void testHashMapStringAdds() {
+ }
+
+ /**
+ * Appends <code>size</code> items to an empty HashMap. All items are Strings,
+ * and do not contain duplicate values.
+ */
+ @Setup("initMap")
+ public void testHashMapStringAdds(@RangeField("baseRange")Integer size) {
+ int num = size.intValue();
+ for (int i = 0; i < num; i++) {
+ String strVal = Integer.toString(i);
+ map.put(strVal, strVal);
+ }
+ }
+
+ public void testHashMapStringGets() {
+ }
+
+ /**
+ * Checks for size values in a populated HashMap. All items are Strings, and
+ * contain duplicate values.
+ */
+ @Setup("beginHashMapStringGets")
+ public void testHashMapStringGets(@RangeField("baseRange")Integer size) {
+ int num = size.intValue();
+ for (int i = 0; i < num; i++) {
+ String strVal = Integer.toString(i);
+ map.get(strVal);
+ }
+ }
+
+ protected void beginHashMapContainsValueInt(Integer size) {
+ map = new HashMap<Object, Object>();
+ testHashMapDuplicateIntAdds(size);
+ }
+
+ protected void beginHashMapContainsValueString(Integer size) {
+ map = new HashMap<Object, Object>();
+ testHashMapDuplicateStringAdds(size);
+ }
+
+ protected void beginHashMapIntGets(Integer size) {
+ map = new HashMap<Object, Object>();
+ testHashMapIntAdds(size);
+ }
+
+ protected void beginHashMapStringGets(Integer size) {
+ map = new HashMap<Object, Object>();
+ testHashMapStringAdds(size);
+ }
+
+ protected void initMap() {
+ map = new HashMap<Object, Object>();
+ }
+}
diff --git a/user/test/com/google/gwt/emultest/java/util/ListBenchmark.java b/user/test/com/google/gwt/emultest/java/util/ListBenchmark.java
new file mode 100644
index 0000000..9719853
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java/util/ListBenchmark.java
@@ -0,0 +1,231 @@
+/*
+ * 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.emultest.java.util;
+
+import com.google.gwt.junit.client.IntRange;
+import com.google.gwt.junit.client.Benchmark;
+import com.google.gwt.junit.client.Operator;
+import com.google.gwt.junit.client.annotations.RangeField;
+import com.google.gwt.junit.client.annotations.RangeEnum;
+import com.google.gwt.junit.client.annotations.Setup;
+
+import java.util.List;
+import java.util.Arrays;
+
+/**
+ * Benchmarks common operations on {@link List Lists}. This test covers
+ * appends, inserts, and removes for various sizes and positions.
+ *
+ */
+public abstract class ListBenchmark extends Benchmark {
+
+ /* TODO(tobyr) Add more tests such as iteration, non-sequential
+ * random access, and sublists.
+ */
+
+ private static final int PRIME = 3001;
+
+ /**
+ * The various positions that data can be inserted into a list.
+ */
+ protected enum Position {
+
+ BEGIN("at the beginning"),
+ EXPLICIT_END("explicitly at the end"),
+ IMPLICIT_END("implicitly at the end"),
+ VARIED("in varied locations");
+
+ private String label;
+
+ /**
+ * Constructor for <code>Position</code>.
+ *
+ * @param label a not <code>null</code> label describing this
+ * <code>Position</code>.
+ */
+ Position(String label) {
+ this.label = label;
+ }
+
+ /**
+ * Returns the textual description for the position.
+ *
+ * @return a not <code>null</code> description.
+ */
+ public String toString() {
+ return label;
+ }
+ }
+
+ protected final List<Position> explicitPositions = Arrays
+ .asList(Position.BEGIN, Position.EXPLICIT_END, Position.VARIED);
+
+ protected final IntRange insertRemoveRange = new IntRange(64,
+ Integer.MAX_VALUE, Operator.MULTIPLY, 2);
+
+ protected final IntRange baseRange = new IntRange(512, Integer.MAX_VALUE,
+ Operator.MULTIPLY, 2);
+
+ List<String> list;
+
+ int index = 0;
+
+ public String getModuleName() {
+ return "com.google.gwt.emultest.EmulSuite";
+ }
+
+ /**
+ * Appends <code>size</code> items to an empty {@code List}.
+ *
+ * @param size the size of the {@code List}
+ */
+ @Setup("beginListAdds")
+ public void testListAdds(@RangeField("baseRange") Integer size) {
+ int num = size.intValue();
+ for (int i = 0; i < num; i++) {
+ list.add("hello");
+ }
+ }
+
+ // Required for JUnit
+ public void testListAdds() {
+ }
+
+ /**
+ * Performs <code>size</code> gets on a {@code List} of size,
+ * <code>size</code>.
+ *
+ * @param size the size of the {@code List}
+ */
+ @Setup("beginListGets")
+ public void testListGets(@RangeField("baseRange") Integer size) {
+ int num = size.intValue();
+ for (int i = 0; i < num; i++) {
+ list.get(i);
+ }
+ }
+
+ // Required for JUnit
+ public void testListGets() {
+ }
+
+ /**
+ * Performs <code>size</code> inserts at position, <code>where</code>, on an
+ * empty <code>List</code>.
+ *
+ * @param where Where the inserts happen
+ * @param size The size of the <code>List</code>
+ *
+ */
+ @Setup("beginListInserts")
+ public void testListInserts(
+ @RangeEnum(Position.class)Position where,
+ @RangeField("insertRemoveRange")Integer size) {
+ insertIntoCollection(size, where, list);
+ }
+
+ // Required for JUnit
+ public void testListInserts() {
+ }
+
+ /**
+ * Performs <code>size</code> removes at position, <code>where</code>, on an
+ * ArrayList of size, <code>size</code>.
+ *
+ * @param where Where the inserts happen
+ * @param size The size of the <code>List</code>
+ */
+ @Setup("beginListRemoves")
+ public void testListRemoves(
+ @RangeField("explicitPositions")Position where,
+ @RangeField("insertRemoveRange")Integer size) {
+ removeFromCollection(size, where, list);
+ }
+
+ // Required for JUnit
+ public void testListRemoves() {
+ }
+
+ /**
+ * Creates a new empty List.
+ *
+ * @return a not <code>null</code>, empty List
+ */
+ protected abstract List<String> newList();
+
+ void beginListAdds(Integer size) {
+ list = newList();
+ }
+
+ void beginListGets(Integer size) {
+ createList(size);
+ }
+
+ void beginListInserts(Position where, Integer size) {
+ list = newList();
+ index = 0;
+ }
+
+ void beginListRemoves(Position where, Integer size) {
+ beginListInserts(where, size);
+ testListInserts(where, size);
+ }
+
+ private void createList(Integer size) {
+ beginListAdds(size);
+ testListAdds(size);
+ }
+
+ private void insertIntoCollection(Integer size, Position where,
+ List<String> l) {
+ int num = size.intValue();
+ for (int i = 0; i < num; i++) {
+ if (where == Position.IMPLICIT_END) {
+ l.add("hello");
+ } else if (where == Position.BEGIN) {
+ l.add(0, "hello");
+ } else if (where == Position.EXPLICIT_END) {
+ l.add(l.size(), "hello");
+ } else if (where == Position.VARIED) {
+ l.add(index, "hello");
+ index += PRIME;
+ index %= l.size();
+ }
+ }
+ }
+
+ private int removeFromCollection(Integer size, Position where,
+ List<String> l) {
+ int num = size.intValue();
+ for (int i = 0; i < num; i++) {
+ if (where == Position.IMPLICIT_END) {
+ throw new RuntimeException("cannot remove from the end implicitly");
+ } else if (where == Position.BEGIN) {
+ l.remove(0);
+ } else if (where == Position.EXPLICIT_END) {
+ l.remove(l.size() - 1);
+ } else if (where == Position.VARIED) {
+ l.remove(index);
+ index += PRIME;
+ int currentSize = l.size();
+ if (currentSize > 0) {
+ index %= l.size();
+ }
+ }
+ }
+ return index;
+ }
+}
diff --git a/user/test/com/google/gwt/emultest/java/util/VectorBenchmark.java b/user/test/com/google/gwt/emultest/java/util/VectorBenchmark.java
new file mode 100644
index 0000000..e75bef7
--- /dev/null
+++ b/user/test/com/google/gwt/emultest/java/util/VectorBenchmark.java
@@ -0,0 +1,29 @@
+/*
+ * 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.emultest.java.util;
+
+import java.util.List;
+import java.util.Vector;
+
+/**
+ * A {@link ListBenchmark} for {@link Vector Vectors}.
+ */
+public class VectorBenchmark extends ListBenchmark {
+
+ protected List<String> newList() {
+ return new Vector<String>();
+ }
+}
diff --git a/user/test/com/google/gwt/junit/client/BenchmarkTest.java b/user/test/com/google/gwt/junit/client/BenchmarkTest.java
new file mode 100644
index 0000000..62787cb
--- /dev/null
+++ b/user/test/com/google/gwt/junit/client/BenchmarkTest.java
@@ -0,0 +1,152 @@
+/*
+ * 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;
+
+import com.google.gwt.junit.client.annotations.RangeField;
+import com.google.gwt.junit.client.annotations.RangeEnum;
+import com.google.gwt.junit.client.annotations.Setup;
+import com.google.gwt.junit.client.annotations.Teardown;
+import com.google.gwt.junit.client.annotations.IterationTimeLimit;
+
+/**
+ * Basic Benchmark testing.
+ *
+ */
+public class BenchmarkTest extends Benchmark {
+
+ /**
+ * Test enum.
+ */
+ protected enum TestEnum {
+ A, B, C;
+ }
+
+ final String stringField = "foo";
+
+ final IntRange intRange = new IntRange(0, 20, Operator.ADD, 5);
+
+ final IntRange intRange2 = new IntRange(10, 1000, Operator.MULTIPLY, 10);
+
+ final IntRange veryLargeRange = new IntRange(0, Integer.MAX_VALUE,
+ Operator.ADD, 1);
+
+ String stateString = null;
+
+ long startTime;
+
+ public String getModuleName() {
+ return "com.google.gwt.junit.JUnit";
+ }
+
+ public void testEnumRange() {
+ }
+
+ /**
+ * Tests that we receive the enums in a range.
+ *
+ * @param enumValue
+ */
+ @Setup("setupEnum")
+ @Teardown("teardownEnum")
+ public void testEnumRange(@RangeEnum(TestEnum.class) TestEnum enumValue) {
+ assertNotNull(enumValue);
+ }
+
+ /**
+ * Tests that a zero argument function works correctly.
+ *
+ */
+ public void testNoParameters() {
+ assertEquals("foo", stringField);
+ }
+
+ public void testOneParameterField() {
+ }
+
+ /**
+ * Tests that a single argument function works correctly.
+ *
+ * @param value
+ */
+ public void testOneParameterField(@RangeField("intRange") Integer value) {
+ assertTrue(value >= 0 && value <= 100 && value % 5 == 0);
+ }
+
+ /**
+ * Tests {@link Setup} and {@link Teardown}.
+ *
+ */
+ @Setup("setup")
+ @Teardown("teardown")
+ public void testSetupAndTeardown() {
+ assertEquals("setup", stateString);
+ stateString = "running";
+ }
+
+ public void testTimeLimit() {
+ }
+
+ /**
+ * Tests {@link @IterationTimeLimit}.
+ *
+ * @param numIterations
+ */
+ @IterationTimeLimit(1L)
+ public void testTimeLimit(@RangeField("veryLargeRange") Integer numIterations) {
+
+ somethingExpensive();
+
+ // Make sure we hit the time limit, instead of running through all
+ // iterations.
+ assertTrue( numIterations < Integer.MAX_VALUE );
+ }
+
+ public void testTwoParameterField() {
+ }
+
+ /**
+ * Tests that a multiple argument function works correctly.
+ *
+ */
+ public void testTwoParameterField(@RangeField("intRange") Integer intOne,
+ @RangeField("intRange2") Integer intTwo) {
+ assertTrue(intOne >= 0 && intOne <= 100 && intOne % 5 == 0);
+ assertTrue(intTwo >= 10 && intTwo <= 1000 && intTwo % 10 == 0);
+ }
+
+ protected void setup() {
+ assertNull(stateString);
+ stateString = "setup";
+ }
+
+ protected void teardown() {
+ assertNotNull(stateString);
+ assertTrue(stateString.equals("running") || stateString.equals("setup"));
+ stateString = null;
+ }
+
+ /**
+ * Do something that is relatively expensive both in hosted mode
+ * and web mode.
+ */
+ private native void somethingExpensive() /*-{
+ var deadField = 0;
+ for (var i = 0; i < 10000; ++i) {
+ deadField += Math.pow(deadField, i);
+ }
+ }-*/;
+}