File: TestClassParser.java

package info (click to toggle)
libgroboutils-java 5-3
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 9,396 kB
  • ctags: 11,186
  • sloc: java: 59,748; xml: 12,762; sh: 377; perl: 104; makefile: 20
file content (262 lines) | stat: -rw-r--r-- 7,260 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
/*
 * @(#)TestClassParser.java
 */

package net.sourceforge.groboutils.junit.v1.parser;

import java.util.Vector;
import java.util.Enumeration;

import java.io.PrintWriter;
import java.io.StringWriter;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import junit.framework.TestSuite;
import junit.framework.TestCase;
import junit.framework.Test;

import org.apache.log4j.Logger;


/**
 * Parses Test classes to discover the usable test methods.
 * <P>
 * Ripped the test method discovery code out of junit.framework.TestSuite to
 * allow it to have usable logic.
 * <P>
 * This is not covered under the GroboUtils license, but rather under the
 * JUnit license (IBM Public License).  This heading may not be totally
 * in line with the license, so I'll change it when I find out what needs to
 * be changed.
 *
 * @author     Matt Albrecht <a href="mailto:groboclown@users.sourceforge.net">groboclown@users.sourceforge.net</a>
 * @version    $Date: 2002/11/05 00:49:31 $
 * @since      March 28, 2002
 */
public class TestClassParser
{
    private static final Logger LOG = Logger.getLogger(
        TestClassParser.class );
    
    private Class testClass;
    Vector testMethods = new Vector();
    private Vector warnings = new Vector();
    
    
    /**
     * The primary constructor, which will cause this instance to know how to
     * parse only the passed-in class.
     *
     * @param theClass the class to parse for testing.
     * @exception IllegalArgumentException if <tt>theClass</tt> is
     *      <tt>null</tt>.
     */
    public TestClassParser(final Class theClass)
    {
        if (theClass == null)
        {
            throw new IllegalArgumentException("no null arguments");
        }
        this.testClass = theClass;
        
        if (testClass( theClass ))
        {
            discoverTestMethods( theClass );
        }
    }
    
    
    //-------------------------------------------------------------------------
    // Public methods
    
    
    /**
     * Retrieve all warnings generated during the introspection of the class,
     * or test creation.  If a <tt>clearWarnings()</tt> call was ever made, then
     * only those warnings that were encountered after the call will be
     * returned.
     *
     * @return an array of all warnings generated while creating the test
     *      array.
     */
    public String[] getWarnings()
    {
        String w[] = new String[ this.warnings.size() ];
        this.warnings.copyInto( w );
        return w;
    }
    
    
    /**
     * Remove all current warnings.
     */
    public void clearWarnings()
    {
        this.warnings.removeAllElements();
    }
    
    
    /**
     * Retrieve all public test methods discovered through inspection.
     *
     * @return all test methods.
     */
    public Method[] getTestMethods()
    {
        Method m[] = new Method[ this.testMethods.size() ];
        this.testMethods.copyInto( m );
        return m;
    }
    
    
    /**
     * Get the name of the test suite.  By default, this is the class name.
     *
     * @return the name of the test suite.
     */
    public String getName()
    {
        return this.testClass.getName();
    }
    
    
    /**
     * Get the class under test.  This will never return <tt>null</tt>, and
     * will always match the class passed into the constructor.
     *
     * @return the class under test.
     */
    public Class getTestClass()
    {
        return this.testClass;
    }
    
    
    //-------------------------------------------------------------------------
    // Parse methods
    
    
    /**
     * Discover if the given class is a valid testing class.
     *
     * @param theClass the class to parse for testing.
     * @return <tt>true</tt> if the class is a public test class, otherwise
     *      <tt>false</tt>.
     */
    protected boolean testClass( final Class theClass )
    {
        boolean result = true;
        if (!Modifier.isPublic( theClass.getModifiers() ))
        {
            warning("Class " + theClass.getName() + " is not public.");
            result = false;
        }
        if (!Test.class.isAssignableFrom( theClass ))
        {
            warning("Class " + theClass.getName() +
                " does not implement "+Test.class.getName() );
            result = false;
        }
        return result;
    }
    
    
    /**
     * Discover and record the test methods of the public test class
     * <tt>theClass</tt>.
     *
     * @param theClass the class to parse for testing.
     */
    protected void discoverTestMethods( final Class theClass )
    {
        Class superClass = theClass;
        Vector names = new Vector();
        while (Test.class.isAssignableFrom( superClass ))
        {
            Method[] methods = superClass.getDeclaredMethods();
            for (int i = 0; i < methods.length; i++)
            {
                addTestMethod( methods[i], names );
            }
            superClass = superClass.getSuperclass();
        }
    }
    
    
    /**
     * Adds the method <tt>m</tt> to the inner list of known test methods,
     * but only if it is a public test method.
     *
     * @param m the method to add.
     * @param names a list of method names that have already been inspected.
     */
    protected void addTestMethod( Method m, Vector names )
    {
        String name = m.getName();
        if (names.contains(name) || this.testMethods.contains( m ))
        {
            return;
        }
        
        if (isPublicTestMethod(m))
        {
            names.addElement(name);

            this.testMethods.addElement( m );
        }
        else
        {
            // almost a test method
            if (isTestMethod(m))
            {
                warning("Test method isn't public: "+m.getName());
            }
        }
    }
    
    
    /**
     * Asserts that the method is public, and that it is also a test method.
     *
     * @param m the method under scrutiny.
     * @return <tt>true</tt> if <tt>m</tt> is a public test method, otherwise
     *      <tt>false</tt>.
     * @see #isTestMethod( Method )
     */
    protected boolean isPublicTestMethod( Method m )
    {
        return isTestMethod(m) && Modifier.isPublic(m.getModifiers());
    }
    
    /**
     * Test if method <tt>m</tt> is a test method, which means it accepts
     * no parameters, returns <tt>void</tt>, and the name of the method
     * begins with <tt>test</tt>.
     *
     * @param m the method under scrutiny.
     * @return <tt>true</tt> if <tt>m</tt> is a public test method, otherwise
     *      <tt>false</tt>.
     */
    protected boolean isTestMethod( Method m )
    {
        String name= m.getName();
        Class[] parameters= m.getParameterTypes();
        Class returnType= m.getReturnType();
        return parameters.length == 0 && name.startsWith("test") &&
            returnType.equals(Void.TYPE);
    }
    
    
    /**
     * Adds a warning message to the inner list of warnings.
     *
     * @param message the message describing the warning.
     */
    protected void warning( final String message )
    {
        LOG.debug( "WARNING: "+message );
        this.warnings.addElement( message );
    }
}