2011/08/05 - Jakarta Cactus has been retired.

For more information, please explore the Attic.

View Javadoc

1   /* 
2    * ========================================================================
3    * 
4    * Licensed to the Apache Software Foundation (ASF) under one or more
5    * contributor license agreements.  See the NOTICE file distributed with
6    * this work for additional information regarding copyright ownership.
7    * The ASF licenses this file to You under the Apache License, Version 2.0
8    * (the "License"); you may not use this file except in compliance with
9    * the License.  You may obtain a copy of the License at
10   * 
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   * 
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   * 
19   * ========================================================================
20   */
21  package org.apache.cactus.internal;
22  
23  import java.io.PrintWriter;
24  import java.io.StringWriter;
25  import java.lang.reflect.Constructor;
26  import java.lang.reflect.InvocationTargetException;
27  import java.lang.reflect.Method;
28  import java.lang.reflect.Modifier;
29  import java.util.Enumeration;
30  import java.util.Vector;
31  
32  import org.apache.cactus.ServletTestCase;
33  
34  import junit.framework.Test;
35  import junit.framework.TestCase;
36  import junit.framework.TestResult;
37  
38  /**
39   * Test Suite that wraps all the tests of the suite in Cactus Test Case 
40   * objects so that pure JUnit tests can be run on the server side.
41   *
42   * @version $Id: AbstractTestSuite.java 238991 2004-05-22 11:34:50Z vmassol $
43   * @since 1.5
44   */
45  public abstract class AbstractTestSuite implements Test
46  {
47      /**
48       * Lists of tests to execute (Test objects).
49       */
50      private Vector tests = new Vector(10);
51  
52      /**
53       * Name of the current test suite.
54       */
55      private String name;
56      
57      /**
58       * {@inheritDoc}
59       * @see junit.framework.TestSuite#TestSuite()
60       */
61      public AbstractTestSuite()
62      {
63      }
64  
65      /**
66       * {@inheritDoc}
67       * @see junit.framework.TestSuite#TestSuite(Class)
68       */
69      public AbstractTestSuite(final Class theClass)
70      {
71          setName(theClass.getName());
72          Constructor constructor;
73          try
74          {
75              // Avoid generating multiple error messages
76              constructor = getTestConstructor(theClass); 
77          }
78          catch (NoSuchMethodException e)
79          {
80              addTest(warning("Class " + theClass.getName()
81                  + " has no public constructor TestCase(String name)"));
82              return;
83          }
84  
85          if (!Modifier.isPublic(theClass.getModifiers()))
86          {
87              addTest(warning("Class " + theClass.getName() + " is not public"));
88              return;
89          }
90  
91          Class superClass = theClass;
92          Vector names = new Vector();
93          while (Test.class.isAssignableFrom(superClass))
94          {
95              Method[] methods = superClass.getDeclaredMethods();
96              for (int i = 0; i < methods.length; i++)
97              {
98                  addTestMethod(methods[i], names, constructor);
99              }
100             superClass = superClass.getSuperclass();
101         }
102         if (this.tests.size() == 0)
103         {
104             addTest(warning("No tests found in " + theClass.getName()));
105         }
106     }
107 
108     /**
109      * {@inheritDoc}
110      * @see junit.framework.TestSuite#TestSuite(String)
111      */
112     public AbstractTestSuite(String theName)
113     {
114         setName(theName);
115     }
116 
117     /**
118      * {@inheritDoc}
119      * @see junit.framework.TestSuite#addTest(Test)
120      */
121     protected void addTest(Test theTest)
122     {
123         this.tests.addElement(theTest);
124     }
125 
126     /**
127      * {@inheritDoc}
128      * @see junit.framework.TestSuite#addTestSuite(Class)
129      */
130     protected void addTestSuite(Class theTestClass)
131     {
132         addTest(createTestSuite(theTestClass));
133     }
134 
135     /**
136      * {@inheritDoc}
137      * @see junit.framework.TestSuite#addTestMethod(Method, Vector, Constructor)
138      */
139     private void addTestMethod(Method theMethod, Vector theNames, 
140         Constructor theConstructor)
141     {
142         String name = theMethod.getName();
143         if (theNames.contains(name))
144         {
145             return;
146         }
147         if (isPublicTestMethod(theMethod))
148         {
149             theNames.addElement(name);
150 
151             try
152             {
153                 // Note: We wrap the Test in a Cactus Test Case
154                 Object constructorInstance;
155                 if (theConstructor.getParameterTypes().length == 0)
156                 {
157                     constructorInstance = theConstructor.newInstance(
158                         new Object[0]);
159                     if (constructorInstance instanceof TestCase)
160                     {
161                         ((TestCase) constructorInstance).setName(name);
162                     }
163                 }
164                 else
165                 {
166                     constructorInstance = theConstructor.newInstance(
167                         new Object[] {name});
168                 }
169                 addTest(new ServletTestCase(name, (Test) constructorInstance));
170             }
171             catch (InstantiationException e)
172             {
173                 addTest(warning("Cannot instantiate test case: " + name
174                     + " (" + exceptionToString(e) + ")"));
175             }
176             catch (InvocationTargetException e)
177             {
178                 addTest(warning("Exception in constructor: " + name + " (" 
179                     + exceptionToString(e.getTargetException()) + ")"));
180             }
181             catch (IllegalAccessException e)
182             {
183                 addTest(warning("Cannot access test case: " + name + " ("
184                     + exceptionToString(e) + ")"));
185             }
186         }
187         else
188         { 
189             // Almost a test method
190             if (isTestMethod(theMethod))
191             {
192                 addTest(warning("Test method isn't public: " 
193                     + theMethod.getName()));
194             }
195         }
196     }
197 
198     /**
199      * {@inheritDoc}
200      * @see junit.framework.TestSuite#exceptionToString(Throwable)
201      */
202     private String exceptionToString(Throwable theThrowable)
203     {
204         StringWriter stringWriter = new StringWriter();
205         PrintWriter writer = new PrintWriter(stringWriter);
206         theThrowable.printStackTrace(writer);
207         return stringWriter.toString();
208     }
209 
210     /**
211      * {@inheritDoc}
212      * @see junit.framework.TestSuite#countTestCases()
213      */
214     public int countTestCases()
215     {
216         int count = 0;
217         for (Enumeration e = tests(); e.hasMoreElements();)
218         {
219             Test test = (Test) e.nextElement();
220             count = count + test.countTestCases();
221         }
222         return count;
223     }
224 
225     /**
226      * {@inheritDoc}
227      * @see junit.framework.TestSuite#isPublicTestMethod(Method)
228      */
229     private boolean isPublicTestMethod(Method theMethod)
230     {
231         return isTestMethod(theMethod) 
232             && Modifier.isPublic(theMethod.getModifiers());
233     }
234 
235     /**
236      * {@inheritDoc}
237      * @see junit.framework.TestSuite#isTestMethod(Method)
238      */
239     private boolean isTestMethod(Method theMethod)
240     {
241         String name = theMethod.getName();
242         Class[] parameters = theMethod.getParameterTypes();
243         Class returnType = theMethod.getReturnType();
244         return parameters.length == 0
245             && name.startsWith("test")
246             && returnType.equals(Void.TYPE);
247     }
248 
249     /**
250      * {@inheritDoc}
251      * @see junit.framework.TestSuite#run(TestResult)
252      */
253     public void run(TestResult theResult)
254     {
255         for (Enumeration e = tests(); e.hasMoreElements();)
256         {
257             if (theResult.shouldStop())
258             {
259                 break;
260             }
261             Test test = (Test) e.nextElement();
262             runTest(test, theResult);
263         }
264     }
265     
266     /**
267      * {@inheritDoc}
268      * @see junit.framework.TestSuite#runTest(Test, TestResult)
269      */
270     protected void runTest(Test theTest, TestResult theResult)
271     {
272         theTest.run(theResult);
273     }
274     
275     /**
276      * {@inheritDoc}
277      * @see junit.framework.TestSuite#testAt(int)
278      */
279     protected Test testAt(int theIndex)
280     {
281         return (Test) this.tests.elementAt(theIndex);
282     }
283 
284     /**
285      * Gets a constructor which takes a single String as
286      * its argument or a no arg constructor.
287      * 
288      * @param theClass the class for which to find the constructor
289      * @return the valid constructor found
290      * @exception NoSuchMethodException if no valid constructor is
291      *            found
292      */
293     protected static Constructor getTestConstructor(Class theClass) 
294         throws NoSuchMethodException
295     {
296         Constructor result;
297         try
298         {
299             result = theClass.getConstructor(new Class[] {String.class});
300         }
301         catch (NoSuchMethodException e)
302         {
303             result = theClass.getConstructor(new Class[0]);
304         }
305         return result; 
306     }
307 
308     /**
309      * {@inheritDoc}
310      * @see junit.framework.TestSuite#testCount()
311      */
312     protected int testCount()
313     {
314         return this.tests.size();
315     }
316 
317     /**
318      * {@inheritDoc}
319      * @see junit.framework.TestSuite#tests()
320      */
321     protected Enumeration tests()
322     {
323         return this.tests.elements();
324     }
325 
326     /**
327      * {@inheritDoc}
328      * @see junit.framework.TestSuite#toString()
329      */
330     public String toString()
331     {
332         if (getName() != null)
333         {
334             return getName();
335         }
336         return super.toString();
337     }
338 
339     /**
340      * {@inheritDoc}
341      * @see junit.framework.TestSuite#setName(String)
342      */
343     protected void setName(String theName)
344     {
345         this.name = theName;
346     }
347 
348     /**
349      * {@inheritDoc}
350      * @see junit.framework.TestSuite#getName()
351      */
352     protected String getName()
353     {
354         return this.name;
355     }
356 
357     /**
358      * {@inheritDoc}
359      * @see junit.framework.TestSuite#warning(String)
360      */
361     private static Test warning(final String theMessage)
362     {
363         return new TestCase("warning")
364         {
365             protected void runTest()
366             {
367                 fail(theMessage);
368             }
369         };
370     }
371 
372     /**
373      * @param theTestClass the test class containing the tests to be included
374      *        in the Cactus Test Suite
375      * @return a Cactus Test Suite (ex: ServletTestSuite) initialized with a
376      *         test class
377      */
378     protected abstract Test createTestSuite(Class theTestClass);
379 
380     /**
381      * @param theName the name of the Cactus Test Case
382      * @param theTest the wrapped test
383      * @return a Cactus Test Case object initialized with the give name and
384      *         wrapped test
385      */
386     protected abstract Test createCactusTestCase(String theName, Test theTest);
387 }