KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > google > gwt > junit > rebind > JUnitTestCaseStubGenerator


1 /*
2  * Copyright 2007 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */

16 package com.google.gwt.junit.rebind;
17
18 import com.google.gwt.core.ext.Generator;
19 import com.google.gwt.core.ext.GeneratorContext;
20 import com.google.gwt.core.ext.TreeLogger;
21 import com.google.gwt.core.ext.UnableToCompleteException;
22 import com.google.gwt.core.ext.typeinfo.JClassType;
23 import com.google.gwt.core.ext.typeinfo.JMethod;
24 import com.google.gwt.core.ext.typeinfo.NotFoundException;
25 import com.google.gwt.core.ext.typeinfo.TypeOracle;
26 import com.google.gwt.core.ext.typeinfo.JParameter;
27 import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
28 import com.google.gwt.user.rebind.SourceWriter;
29
30 import java.io.PrintWriter JavaDoc;
31 import java.util.Map JavaDoc;
32 import java.util.ArrayList JavaDoc;
33 import java.util.List JavaDoc;
34 import java.util.HashMap JavaDoc;
35
36 /**
37  * This class generates a stub class for classes that derive from GWTTestCase.
38  * This stub class provides the necessary bridge between our Hosted or Hybrid
39  * mode classes and the JUnit system.
40  *
41  */

42 public class JUnitTestCaseStubGenerator extends Generator {
43
44   interface MethodFilter {
45     public boolean accept( JMethod method );
46   }
47
48   private static final String JavaDoc GWT_TESTCASE_CLASS_NAME = "com.google.gwt.junit.client.GWTTestCase";
49
50   /**
51    * Returns the method names for the set of methods that are strictly JUnit
52    * test methods (have no arguments).
53    *
54    * @param requestedClass
55    */

56   public static String JavaDoc[] getTestMethodNames(JClassType requestedClass) {
57     return (String JavaDoc[]) getAllMethods( requestedClass, new MethodFilter() {
58       public boolean accept(JMethod method) {
59         return isJUnitTestMethod(method,false);
60       }
61     } ).keySet().toArray( new String JavaDoc[] {} );
62   }
63
64   /**
65    * Like JClassType.getMethod( String name ), except:
66    *
67    * <li>it accepts a filter</li>
68    * <li>it searches the inheritance hierarchy (includes subclasses)</li>
69    *
70    * For methods which are overriden, only the most derived implementations are included.
71    *
72    * @param type The type to search. Must not be null
73    * @return Map<String.List<JMethod>> The set of matching methods. Will not be null.
74    */

75   static Map JavaDoc getAllMethods( JClassType type, MethodFilter filter ) {
76     Map JavaDoc methods = new HashMap JavaDoc/*<String,List<JMethod>>*/();
77     JClassType cls = type;
78
79     while (cls != null) {
80       JMethod[] clsDeclMethods = cls.getMethods();
81
82       // For every method, include it iff our filter accepts it
83
// and we don't already have a matching method
84
for (int i = 0, n = clsDeclMethods.length; i < n; ++i) {
85
86         JMethod declMethod = clsDeclMethods[i];
87
88         if ( ! filter.accept(declMethod) ) {
89           continue;
90         }
91
92         List JavaDoc list = (List JavaDoc)methods.get(declMethod.getName());
93
94         if (list == null) {
95           list = new ArrayList JavaDoc();
96           methods.put(declMethod.getName(),list);
97           list.add(declMethod);
98           continue;
99         }
100
101         JParameter[] declParams = declMethod.getParameters();
102
103         for (int j = 0; j < list.size(); ++j) {
104           JMethod method = (JMethod)list.get(j);
105           JParameter[] parameters = method.getParameters();
106           if ( ! equals( declParams, parameters )) {
107             list.add(declMethod );
108           }
109         }
110       }
111       cls = cls.getSuperclass();
112     }
113
114     return methods;
115   }
116
117   /**
118    * Returns true if the method is considered to be a valid JUnit test method.
119    * The criteria are that the method's name begin with "test" and have public
120    * access. The method may be static. You must choose to include or exclude
121    * methods which have arguments.
122    *
123    */

124   static boolean isJUnitTestMethod(JMethod method, boolean acceptArgs) {
125     if (!method.getName().startsWith("test")) {
126       return false;
127     }
128
129     if (!method.isPublic()) {
130       return false;
131     }
132
133     return acceptArgs || method.getParameters().length == 0 && ! acceptArgs;
134   }
135
136   /**
137    * Returns true iff the two sets of parameters are of the same lengths and types.
138    *
139    * @param params1 must not be null
140    * @param params2 must not be null
141    */

142   private static boolean equals( JParameter[] params1, JParameter[] params2 ) {
143     if ( params1.length != params2.length ) {
144       return false;
145     }
146     for ( int i = 0; i < params1.length; ++i ) {
147       if ( params1[ i ].getType() != params2[ i ].getType() ) {
148         return false;
149       }
150     }
151     return true;
152   }
153
154   String JavaDoc qualifiedStubClassName;
155   String JavaDoc simpleStubClassName;
156   String JavaDoc typeName;
157   TreeLogger logger;
158   String JavaDoc packageName;
159
160   private JClassType requestedClass;
161   private SourceWriter sourceWriter;
162   private TypeOracle typeOracle;
163
164   /**
165    * Create a new type that statisfies the rebind request.
166    */

167   public String JavaDoc generate(TreeLogger logger, GeneratorContext context,
168       String JavaDoc typeName) throws UnableToCompleteException {
169
170     if ( ! init( logger, context, typeName ) ) {
171       return qualifiedStubClassName;
172     }
173
174     writeSource();
175     sourceWriter.commit( logger );
176
177     return qualifiedStubClassName;
178   }
179
180   public JClassType getRequestedClass() {
181     return requestedClass;
182   }
183
184   public SourceWriter getSourceWriter() {
185     return sourceWriter;
186   }
187
188   public TypeOracle getTypeOracle() {
189     return typeOracle;
190   }
191
192   boolean init(TreeLogger logger, GeneratorContext context,String JavaDoc typeName) throws
193       UnableToCompleteException {
194
195     this.typeName = typeName;
196     this.logger = logger;
197     typeOracle = context.getTypeOracle();
198     assert typeOracle != null;
199
200     try {
201       requestedClass = typeOracle.getType(typeName);
202     } catch (NotFoundException e) {
203       logger.log(TreeLogger.ERROR, "Could not find type '" + typeName
204           + "'; please see the log, as this usually indicates a previous error ",
205           e);
206       throw new UnableToCompleteException();
207     }
208
209     // Get the stub class name, and see if its source file exists.
210
//
211
simpleStubClassName = getSimpleStubClassName(requestedClass);
212     packageName = requestedClass.getPackage().getName();
213     qualifiedStubClassName = packageName + "." + simpleStubClassName;
214
215     sourceWriter = getSourceWriter(logger, context, packageName,
216         simpleStubClassName, requestedClass.getQualifiedSourceName());
217
218     return sourceWriter != null;
219   }
220
221   void writeSource() throws UnableToCompleteException {
222     String JavaDoc[] testMethods = getTestMethodNames(requestedClass);
223     writeGetNewTestCase(simpleStubClassName, sourceWriter);
224     writeDoRunTestMethod(testMethods, sourceWriter);
225     writeGetTestName(typeName, sourceWriter);
226   }
227
228   /**
229    * Gets the name of the native stub class.
230    */

231   private String JavaDoc getSimpleStubClassName(JClassType baseClass) {
232     return "__" + baseClass.getSimpleSourceName() + "_unitTestImpl";
233   }
234
235   private SourceWriter getSourceWriter(TreeLogger logger, GeneratorContext ctx,
236       String JavaDoc packageName, String JavaDoc className, String JavaDoc superclassName) {
237
238     PrintWriter JavaDoc printWriter = ctx.tryCreate(logger, packageName, className);
239     if (printWriter == null) {
240       return null;
241     }
242
243     ClassSourceFileComposerFactory composerFactory = new ClassSourceFileComposerFactory(
244       packageName, className);
245
246     composerFactory.setSuperclass(superclassName);
247
248     return composerFactory.createSourceWriter(ctx, printWriter);
249   }
250
251   private void writeDoRunTestMethod(String JavaDoc[] testMethodNames, SourceWriter sw) {
252     sw.println();
253     sw.println("protected final void doRunTest(String name) throws Throwable {");
254     sw.indent();
255     for (int i = 0, n = testMethodNames.length; i < n; ++i) {
256       String JavaDoc methodName = testMethodNames[i];
257
258       if (i > 0) {
259         sw.print("else ");
260       }
261
262       sw.println("if (name.equals(\"" + methodName + "\")) {");
263       sw.indentln(methodName + "();");
264       sw.println("}");
265     }
266     sw.outdent();
267     sw.println("}"); // finish doRunTest();
268
}
269
270   /**
271    * Create the appMain method that is the main entry point for the GWT
272    * application.
273    */

274   private void writeGetNewTestCase(String JavaDoc stubClassName, SourceWriter sw) {
275     sw.println();
276     sw.println("public final " + GWT_TESTCASE_CLASS_NAME
277       + " getNewTestCase() {");
278     sw.indent();
279     sw.println("return new " + stubClassName + "();");
280     sw.outdent();
281     sw.println("}"); // finish getNewTestCase();
282
}
283
284   /**
285    * Create the appMain method that is the main entry point for the GWT
286    * application.
287    */

288   private void writeGetTestName(String JavaDoc testClassName, SourceWriter sw) {
289     sw.println();
290     sw.println("public final String getTestName() {");
291     sw.indent();
292     sw.println("return \"" + testClassName + "\";");
293     sw.outdent();
294     sw.println("}"); // finish getNewTestCase();
295
}
296 }
297
Popular Tags