KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > junitx > tool > TestClassValidator


1 /*
2  * The JUnit-addons Software License, Version 1.0
3  * (based on the Apache Software License, Version 1.1)
4  *
5  * Copyright (c) 2002-2003 Vladimir R. Bossicard. All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright
15  * notice, this list of conditions and the following disclaimer in
16  * the documentation and/or other materials provided with the
17  * distribution.
18  *
19  * 3. The end-user documentation included with the redistribution, if
20  * any, must include the following acknowlegement:
21  * "This product includes software developed by Vladimir R.
22  * Bossicard as well as other contributors
23  * (http://junit-addons.sourceforge.net/)."
24  * Alternately, this acknowlegement may appear in the software itself,
25  * if and wherever such third-party acknowlegements normally appear.
26  *
27  * 4. The name "JUnit-addons" must not be used to endorse or promote
28  * products derived from this software without prior written
29  * permission. For written permission, please contact
30  * vbossica@users.sourceforge.net.
31  *
32  * 5. Products derived from this software may not be called "JUnit-addons"
33  * nor may "JUnit-addons" appear in their names without prior written
34  * permission of the project managers.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  * ======================================================================
49  *
50  * This software consists of voluntary contributions made by many
51  * individuals. For more information on the JUnit-addons Project, please
52  * see <http://junit-addons.sourceforge.net/>.
53  */

54
55 package junitx.tool;
56
57 import junit.framework.Test;
58
59 import java.lang.reflect.Method JavaDoc;
60 import java.lang.reflect.Modifier JavaDoc;
61
62 /**
63  * Checks if a test class can be recognized by the JUnit framework.
64  *
65  * <h4>Usage</h4>
66  *
67  * <pre>
68  * java TestCaseValidator [-listener classname] [-validator classname] classname
69  * </pre>
70  *
71  * <h4>Example</h4>
72  *
73  * <pre>
74  * java TestCaseValidator ValidationExample
75  * </pre>
76  *
77  * <pre>
78  * public class ValidationExample
79  * extends TestCase {
80  *
81  * public ValidationExample( String name ) {
82  * super( name );
83  * }
84  *
85  * public Test suite() {
86  * return null;
87  * }
88  *
89  * public void setup() {
90  * }
91  *
92  * public void tearDown() {
93  * }
94  *
95  * public void atestDummy() {
96  * assertTrue( true );
97  * }
98  * }
99  * </pre>
100  *
101  * prints the following report:
102  *
103  * <pre>
104  * TestClassValidator, by Vladimir R. Bossicard
105  * WARN > junitx.example.ValidationExample: method potentially misspelled <setup>
106  * ERROR> junitx.example.ValidationExample: method 'suite' must be static
107  * INFO > junitx.example.ValidationExample: method seems to be a test <atestDummy>
108  * </pre>
109  *
110  * @version $Revision: 1.9 $ $Date: 2003/02/06 20:43:54 $
111  * @author <a HREF="mailto:vbossica@users.sourceforge.net">Vladimir R. Bossicard</a>
112  * @author <a HREF="mailto:benoitx@users.sourceforge.net">Benoit Xhenseval</a>
113  */

114 public class TestClassValidator {
115
116     /** Advertising message */
117     public static final String JavaDoc BANNER = "TestClassValidator, by Vladimir R. Bossicard";
118
119     private ClassValidator validator = null;
120     private ClassValidatorListener listener = null;
121
122     public void setValidator(ClassValidator validator) {
123         this.validator = validator;
124     }
125
126     public void setValidatorListener(ClassValidatorListener listener) {
127         this.listener = listener;
128     }
129
130     private void init(String JavaDoc[] args)
131             throws ClassNotFoundException JavaDoc,
132             InstantiationException JavaDoc,
133             IllegalAccessException JavaDoc {
134         this.validator = createValidator(args);
135         this.listener = createValidatorListener(args);
136         go(args);
137     }
138
139     private ClassValidator createValidator(String JavaDoc[] args)
140             throws ClassNotFoundException JavaDoc,
141             InstantiationException JavaDoc,
142             IllegalAccessException JavaDoc {
143         ClassValidator res = null;
144         if (args[0].equals("-validator")) {
145             res = (ClassValidator) Class.forName(args[1]).newInstance();
146         } else if ((args.length >= 3) &&
147                 args[2].equals("-validator")) {
148             if (res == null) {
149                 throw new IllegalStateException JavaDoc("Two validators are defined");
150             } else {
151                 res = (ClassValidator) Class.forName(args[3]).newInstance();
152             }
153         }
154         return res;
155     }
156
157     private ClassValidatorListener createValidatorListener(String JavaDoc[] args)
158             throws ClassNotFoundException JavaDoc,
159             InstantiationException JavaDoc,
160             IllegalAccessException JavaDoc {
161         ClassValidatorListener res = null;
162         if (args[0].equals("-listener")) {
163             res = (ClassValidatorListener) Class.forName(args[1]).newInstance();
164         } else if ((args.length >= 3) &&
165                 args[2].equals("-listener")) {
166             if (res == null) {
167                 throw new IllegalStateException JavaDoc("Two listeners are defined");
168             } else {
169                 res = (ClassValidatorListener) Class.forName(args[3]).newInstance();
170             }
171         }
172         return res;
173     }
174
175     private void go(String JavaDoc[] args)
176             throws ClassNotFoundException JavaDoc {
177         if (this.validator == null) {
178             this.validator = new DefaultClassValidator();
179         }
180
181         if (this.listener == null) {
182             this.listener = new ClassValidatorListener() {
183
184                 public void info(String JavaDoc message) {
185                     System.out.println("INFO > " + message);
186                 }
187
188                 public void warning(String JavaDoc message) {
189                     System.out.println("WARN > " + message);
190                 }
191
192                 public void error(String JavaDoc message) {
193                     System.out.println("ERROR> " + message);
194                 }
195             };
196         }
197
198         this.validator.setListener(this.listener);
199         this.validator.validate(Class.forName(args[args.length - 1]));
200     }
201
202     private static void man() {
203         System.out.println("usage: junitx.tool.TestClassValidator [-validator classname] [-listener classname] classname");
204     }
205
206     public static void main(String JavaDoc[] args) {
207         try {
208             System.out.println(BANNER);
209             new TestClassValidator().init(args);
210         } catch (Exception JavaDoc e) {
211             man();
212             System.out.println();
213             e.printStackTrace(System.err);
214         }
215     }
216
217     /**
218      * Class reponsible for validating a given class. Users willing to
219      * program their own validator can implement this interface or extend the
220      * <tt>DefaultClassValidator</tt> class.<p>
221      *
222      * The information can be of the following types:
223      * <ul>
224      * <li><i>info</i>: just an information.</li>
225      * <li><i>warning</i>: a minor problem has been found. The tests can still
226      * be executed.</li>
227      * <li><i>error</i>: a major problem that will prevent the tests from
228      * beeing correctly executed has been found.</li>
229      * </ul>
230      *
231      * @version $Revision: 1.9 $ $Date: 2003/02/06 20:43:54 $
232      * @author <a HREF="mailto:vbossica@users.sourceforge.net">Vladimir R. Bossicard</a>
233      * @see TestClassValidator
234      * @see TestClassValidator.ClassValidatorListener
235      */

236     public interface ClassValidator {
237
238         /**
239          * Sets the listener that will report to the user. As a general rule
240          * All information must be handled by the listener and not by the
241          * <tt>ClassValidator</> object itselfs.
242          */

243         public void setListener(ClassValidatorListener listener);
244
245         /**
246          * Validates a given class and report infos, warnings and errors via
247          * the <tt>ClassValidatorListener</tt> object (if any was set).
248          */

249         public void validate(Class JavaDoc cls);
250
251     }
252
253     /**
254      * Listener that will receive update from the <tt>ClassValidator</tt>
255      * object.
256      *
257      * @version $Revision: 1.9 $ $Date: 2003/02/06 20:43:54 $
258      * @author <a HREF="mailto:vbossica@users.sourceforge.net">Vladimir R. Bossicard</a>
259      * @see TestClassValidator.ClassValidator
260      * @see TestClassValidator.ClassValidator#setListener
261      */

262     public interface ClassValidatorListener {
263
264         /**
265          * Fired when the <tt>ClassValidator</tt> has something to say.
266          */

267         void info(String JavaDoc message);
268
269         /**
270          * Fired when the <tt>ClassValidator</tt> has something important to
271          * say.
272          */

273         void warning(String JavaDoc message);
274
275         /**
276          * Fired when the <tt>ClassValidator</tt> has something very important
277          * to say.
278          */

279         void error(String JavaDoc message);
280
281     }
282
283     /**
284      * Provides a default implementation for the <code>ClassValidator</code>
285      * interface. This class is meant to become the base class for other, more
286      * specific, validators.
287      *
288      * @version $Revision: 1.9 $ $Date: 2003/02/06 20:43:54 $
289      * @author <a HREF="mailto:vbossica@users.sourceforge.net">Vladimir R. Bossicard</a>
290      * @see TestClassValidator
291      */

292     public static class DefaultClassValidator
293             implements ClassValidator {
294
295         private ClassValidatorListener listener = null;
296
297         public void setListener(ClassValidatorListener listener) {
298             this.listener = listener;
299         }
300
301         public void validate(Class JavaDoc cls) {
302             Class JavaDoc base = cls;
303             while (base != null) {
304                 Method JavaDoc mtds[] = base.getDeclaredMethods();
305                 for (int ii = 0; ii < mtds.length; ii++) {
306                     Method JavaDoc mtd = mtds[ii];
307                     String JavaDoc name = mtd.getName();
308                     if (name.equals("suite")) {
309                         validateSuiteMethod(mtd);
310                     } else if (name.equals("setUp")) {
311                         validateSetUpMethod(mtd);
312                     } else if (name.equals("tearDown")) {
313                         validateTearDownMethod(mtd);
314                     } else if (name.startsWith("test")) {
315                         validateTestMethod(mtd);
316                     } else {
317                         validateOtherMethod(mtd);
318                     }
319                 }
320                 base = base.getSuperclass();
321             }
322         }
323
324         /**
325          * Verifies that the 'suite' method is recognized by the JUnit
326          * framework.<p>
327          *
328          * The method must:
329          * <ul>
330          * <li>be static</li>
331          * <li>be public</li>
332          * <li>return Test</li>
333          * <li>have no argument</li>
334          * </ul>
335          */

336         protected void validateSuiteMethod(Method JavaDoc method) {
337             int modifier = method.getModifiers();
338             if (!Modifier.isPublic(modifier)) {
339                 fireError(method.getDeclaringClass().getName() + ": method 'suite' must be public");
340             }
341             if (!Modifier.isStatic(modifier)) {
342                 fireError(method.getDeclaringClass().getName() + ": method 'suite' must be static");
343             }
344             if (method.getReturnType() != Test.class) {
345                 fireError(method.getDeclaringClass().getName() + ": method 'suite' must return Test");
346             }
347             if (method.getParameterTypes().length != 0) {
348                 fireError(method.getDeclaringClass().getName() + ": method 'suite' must have no argument");
349             }
350         }
351
352         /**
353          * Verifies that the 'setUp' method is recognized by the JUnit
354          * framework.<p>
355          *
356          * The method must:
357          * <ul>
358          * <li>have no argument</li>
359          * </ul>
360          */

361         protected void validateSetUpMethod(Method JavaDoc method) {
362             if (method.getParameterTypes().length != 0) {
363                 fireError(method.getDeclaringClass().getName() + ".setUp: method must have no argument");
364             }
365         }
366
367         /**
368          * Verifies that the 'tearDown' method is recognized by the JUnit
369          * framework.<p>
370          *
371          * The method must:
372          * <ul>
373          * <li>have no argument</li>
374          * </ul>
375          */

376         protected void validateTearDownMethod(Method JavaDoc method) {
377             if (method.getParameterTypes().length != 0) {
378                 fireError(method.getDeclaringClass().getName() + ".tearDown: method must have no argument");
379             }
380         }
381
382         /**
383          * Verifies that the 'test' method is recognized by the JUnit
384          * framework.<p>
385          *
386          * The method must:
387          * <ul>
388          * <li>be public</li>
389          * <li>have no argument</li>
390          * </ul>
391          */

392         protected void validateTestMethod(Method JavaDoc method) {
393             if (method.getParameterTypes().length != 0) {
394                 fireError(method.getDeclaringClass().getName() + ": test method must have no argument");
395             }
396             if (!Modifier.isPublic(method.getModifiers())) {
397                 fireError(method.getDeclaringClass().getName() + ": test method must be public");
398             }
399         }
400
401         /**
402          * Validates all other methods whose name did not match either 'suite',
403          * 'setUp' or 'tearDown'.
404          */

405         protected void validateOtherMethod(Method JavaDoc method) {
406             String JavaDoc name = method.getName();
407             if (name.toLowerCase().equals("setup")) {
408                 fireWarning(method.getDeclaringClass().getName() + ": method potentially misspelled <" + name + ">");
409             } else if (name.toLowerCase().equals("teardown")) {
410                 fireWarning(method.getDeclaringClass().getName() + ": method potentially misspelled <" + name + ">");
411             } else if (name.toLowerCase().equals("suite")) {
412                 fireWarning(method.getDeclaringClass().getName() + ": method potentially misspelled <" + name + ">");
413             } else if (name.indexOf("test") > 0) {
414                 fireInfo(method.getDeclaringClass().getName() + ": method seems to be a test <" + name + ">");
415             }
416         }
417
418         private void fireInfo(String JavaDoc message) {
419             if (this.listener != null) {
420                 this.listener.info(message);
421             }
422         }
423
424         private void fireWarning(String JavaDoc message) {
425             if (this.listener != null) {
426                 this.listener.warning(message);
427             }
428         }
429
430         private void fireError(String JavaDoc message) {
431             if (this.listener != null) {
432                 this.listener.error(message);
433             }
434         }
435
436     }
437
438 }
439
Popular Tags