KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sourceforge > groboutils > junit > v1 > parser > TestClassParser


1 /*
2  * @(#)TestClassParser.java
3  */

4
5 package net.sourceforge.groboutils.junit.v1.parser;
6
7 import java.util.Vector JavaDoc;
8 import java.util.Enumeration JavaDoc;
9
10 import java.io.PrintWriter JavaDoc;
11 import java.io.StringWriter JavaDoc;
12
13 import java.lang.reflect.Method JavaDoc;
14 import java.lang.reflect.Modifier JavaDoc;
15
16 import junit.framework.TestSuite;
17 import junit.framework.TestCase;
18 import junit.framework.Test;
19
20 import org.apache.log4j.Logger;
21
22
23 /**
24  * Parses Test classes to discover the usable test methods.
25  * <P>
26  * Ripped the test method discovery code out of junit.framework.TestSuite to
27  * allow it to have usable logic.
28  * <P>
29  * This is not covered under the GroboUtils license, but rather under the
30  * JUnit license (IBM Public License). This heading may not be totally
31  * in line with the license, so I'll change it when I find out what needs to
32  * be changed.
33  *
34  * @author Matt Albrecht <a HREF="mailto:groboclown@users.sourceforge.net">groboclown@users.sourceforge.net</a>
35  * @version $Date: 2002/11/05 00:49:31 $
36  * @since March 28, 2002
37  */

38 public class TestClassParser
39 {
40     private static final Logger LOG = Logger.getLogger(
41         TestClassParser.class );
42     
43     private Class JavaDoc testClass;
44     Vector JavaDoc testMethods = new Vector JavaDoc();
45     private Vector JavaDoc warnings = new Vector JavaDoc();
46     
47     
48     /**
49      * The primary constructor, which will cause this instance to know how to
50      * parse only the passed-in class.
51      *
52      * @param theClass the class to parse for testing.
53      * @exception IllegalArgumentException if <tt>theClass</tt> is
54      * <tt>null</tt>.
55      */

56     public TestClassParser(final Class JavaDoc theClass)
57     {
58         if (theClass == null)
59         {
60             throw new IllegalArgumentException JavaDoc("no null arguments");
61         }
62         this.testClass = theClass;
63         
64         if (testClass( theClass ))
65         {
66             discoverTestMethods( theClass );
67         }
68     }
69     
70     
71     //-------------------------------------------------------------------------
72
// Public methods
73

74     
75     /**
76      * Retrieve all warnings generated during the introspection of the class,
77      * or test creation. If a <tt>clearWarnings()</tt> call was ever made, then
78      * only those warnings that were encountered after the call will be
79      * returned.
80      *
81      * @return an array of all warnings generated while creating the test
82      * array.
83      */

84     public String JavaDoc[] getWarnings()
85     {
86         String JavaDoc w[] = new String JavaDoc[ this.warnings.size() ];
87         this.warnings.copyInto( w );
88         return w;
89     }
90     
91     
92     /**
93      * Remove all current warnings.
94      */

95     public void clearWarnings()
96     {
97         this.warnings.removeAllElements();
98     }
99     
100     
101     /**
102      * Retrieve all public test methods discovered through inspection.
103      *
104      * @return all test methods.
105      */

106     public Method JavaDoc[] getTestMethods()
107     {
108         Method JavaDoc m[] = new Method JavaDoc[ this.testMethods.size() ];
109         this.testMethods.copyInto( m );
110         return m;
111     }
112     
113     
114     /**
115      * Get the name of the test suite. By default, this is the class name.
116      *
117      * @return the name of the test suite.
118      */

119     public String JavaDoc getName()
120     {
121         return this.testClass.getName();
122     }
123     
124     
125     /**
126      * Get the class under test. This will never return <tt>null</tt>, and
127      * will always match the class passed into the constructor.
128      *
129      * @return the class under test.
130      */

131     public Class JavaDoc getTestClass()
132     {
133         return this.testClass;
134     }
135     
136     
137     //-------------------------------------------------------------------------
138
// Parse methods
139

140     
141     /**
142      * Discover if the given class is a valid testing class.
143      *
144      * @param theClass the class to parse for testing.
145      * @return <tt>true</tt> if the class is a public test class, otherwise
146      * <tt>false</tt>.
147      */

148     protected boolean testClass( final Class JavaDoc theClass )
149     {
150         boolean result = true;
151         if (!Modifier.isPublic( theClass.getModifiers() ))
152         {
153             warning("Class " + theClass.getName() + " is not public.");
154             result = false;
155         }
156         if (!Test.class.isAssignableFrom( theClass ))
157         {
158             warning("Class " + theClass.getName() +
159                 " does not implement "+Test.class.getName() );
160             result = false;
161         }
162         return result;
163     }
164     
165     
166     /**
167      * Discover and record the test methods of the public test class
168      * <tt>theClass</tt>.
169      *
170      * @param theClass the class to parse for testing.
171      */

172     protected void discoverTestMethods( final Class JavaDoc theClass )
173     {
174         Class JavaDoc superClass = theClass;
175         Vector JavaDoc names = new Vector JavaDoc();
176         while (Test.class.isAssignableFrom( superClass ))
177         {
178             Method JavaDoc[] methods = superClass.getDeclaredMethods();
179             for (int i = 0; i < methods.length; i++)
180             {
181                 addTestMethod( methods[i], names );
182             }
183             superClass = superClass.getSuperclass();
184         }
185     }
186     
187     
188     /**
189      * Adds the method <tt>m</tt> to the inner list of known test methods,
190      * but only if it is a public test method.
191      *
192      * @param m the method to add.
193      * @param names a list of method names that have already been inspected.
194      */

195     protected void addTestMethod( Method JavaDoc m, Vector JavaDoc names )
196     {
197         String JavaDoc name = m.getName();
198         if (names.contains(name) || this.testMethods.contains( m ))
199         {
200             return;
201         }
202         
203         if (isPublicTestMethod(m))
204         {
205             names.addElement(name);
206
207             this.testMethods.addElement( m );
208         }
209         else
210         {
211             // almost a test method
212
if (isTestMethod(m))
213             {
214                 warning("Test method isn't public: "+m.getName());
215             }
216         }
217     }
218     
219     
220     /**
221      * Asserts that the method is public, and that it is also a test method.
222      *
223      * @param m the method under scrutiny.
224      * @return <tt>true</tt> if <tt>m</tt> is a public test method, otherwise
225      * <tt>false</tt>.
226      * @see #isTestMethod( Method )
227      */

228     protected boolean isPublicTestMethod( Method JavaDoc m )
229     {
230         return isTestMethod(m) && Modifier.isPublic(m.getModifiers());
231     }
232     
233     /**
234      * Test if method <tt>m</tt> is a test method, which means it accepts
235      * no parameters, returns <tt>void</tt>, and the name of the method
236      * begins with <tt>test</tt>.
237      *
238      * @param m the method under scrutiny.
239      * @return <tt>true</tt> if <tt>m</tt> is a public test method, otherwise
240      * <tt>false</tt>.
241      */

242     protected boolean isTestMethod( Method JavaDoc m )
243     {
244         String JavaDoc name= m.getName();
245         Class JavaDoc[] parameters= m.getParameterTypes();
246         Class JavaDoc returnType= m.getReturnType();
247         return parameters.length == 0 && name.startsWith("test") &&
248             returnType.equals(Void.TYPE);
249     }
250     
251     
252     /**
253      * Adds a warning message to the inner list of warnings.
254      *
255      * @param message the message describing the warning.
256      */

257     protected void warning( final String JavaDoc message )
258     {
259         LOG.debug( "WARNING: "+message );
260         this.warnings.addElement( message );
261     }
262 }
263
Popular Tags