001: /*
002: * ========================================================================
003: *
004: * Copyright 2001-2004 The Apache Software Foundation.
005: *
006: * Licensed under the Apache License, Version 2.0 (the "License");
007: * you may not use this file except in compliance with the License.
008: * You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: *
018: * ========================================================================
019: */
020: package org.apache.cactus.internal;
021:
022: import java.io.PrintWriter;
023: import java.io.StringWriter;
024: import java.lang.reflect.Constructor;
025: import java.lang.reflect.InvocationTargetException;
026: import java.lang.reflect.Method;
027: import java.lang.reflect.Modifier;
028: import java.util.Enumeration;
029: import java.util.Vector;
030:
031: import org.apache.cactus.ServletTestCase;
032:
033: import junit.framework.Test;
034: import junit.framework.TestCase;
035: import junit.framework.TestResult;
036:
037: /**
038: * Test Suite that wraps all the tests of the suite in Cactus Test Case
039: * objects so that pure JUnit tests can be run on the server side.
040: *
041: * @version $Id: AbstractTestSuite.java 238991 2004-05-22 11:34:50Z vmassol $
042: * @since 1.5
043: */
044: public abstract class AbstractTestSuite implements Test {
045: /**
046: * Lists of tests to execute (Test objects)
047: */
048: private Vector tests = new Vector(10);
049:
050: /**
051: * Name of the current test suite
052: */
053: private String name;
054:
055: /**
056: * @see junit.framework.TestSuite#TestSuite()
057: */
058: public AbstractTestSuite() {
059: }
060:
061: /**
062: * @see junit.framework.TestSuite#TestSuite(Class)
063: */
064: public AbstractTestSuite(final Class theClass) {
065: setName(theClass.getName());
066: Constructor constructor;
067: try {
068: // Avoid generating multiple error messages
069: constructor = getTestConstructor(theClass);
070: } catch (NoSuchMethodException e) {
071: addTest(warning("Class "
072: + theClass.getName()
073: + " has no public constructor TestCase(String name)"));
074: return;
075: }
076:
077: if (!Modifier.isPublic(theClass.getModifiers())) {
078: addTest(warning("Class " + theClass.getName()
079: + " is not public"));
080: return;
081: }
082:
083: Class super Class = theClass;
084: Vector names = new Vector();
085: while (Test.class.isAssignableFrom(super Class)) {
086: Method[] methods = super Class.getDeclaredMethods();
087: for (int i = 0; i < methods.length; i++) {
088: addTestMethod(methods[i], names, constructor);
089: }
090: super Class = super Class.getSuperclass();
091: }
092: if (this .tests.size() == 0) {
093: addTest(warning("No tests found in " + theClass.getName()));
094: }
095: }
096:
097: /**
098: * @see junit.framework.TestSuite#TestSuite(String)
099: */
100: public AbstractTestSuite(String theName) {
101: setName(theName);
102: }
103:
104: /**
105: * @see junit.framework.TestSuite#addTest(Test)
106: */
107: protected void addTest(Test theTest) {
108: this .tests.addElement(theTest);
109: }
110:
111: /**
112: * @see junit.framework.TestSuite#addTestSuite(Class)
113: */
114: protected void addTestSuite(Class theTestClass) {
115: addTest(createTestSuite(theTestClass));
116: }
117:
118: /**
119: * @see junit.framework.TestSuite#addTestMethod(Method, Vector, Constructor)
120: */
121: private void addTestMethod(Method theMethod, Vector theNames,
122: Constructor theConstructor) {
123: String name = theMethod.getName();
124: if (theNames.contains(name)) {
125: return;
126: }
127: if (isPublicTestMethod(theMethod)) {
128: theNames.addElement(name);
129:
130: try {
131: // Note: We wrap the Test in a Cactus Test Case
132: Object constructorInstance;
133: if (theConstructor.getParameterTypes().length == 0) {
134: constructorInstance = theConstructor
135: .newInstance(new Object[0]);
136: if (constructorInstance instanceof TestCase) {
137: ((TestCase) constructorInstance).setName(name);
138: }
139: } else {
140: constructorInstance = theConstructor
141: .newInstance(new Object[] { name });
142: }
143: addTest(new ServletTestCase(name,
144: (Test) constructorInstance));
145: } catch (InstantiationException e) {
146: addTest(warning("Cannot instantiate test case: " + name
147: + " (" + exceptionToString(e) + ")"));
148: } catch (InvocationTargetException e) {
149: addTest(warning("Exception in constructor: " + name
150: + " ("
151: + exceptionToString(e.getTargetException())
152: + ")"));
153: } catch (IllegalAccessException e) {
154: addTest(warning("Cannot access test case: " + name
155: + " (" + exceptionToString(e) + ")"));
156: }
157: } else {
158: // Almost a test method
159: if (isTestMethod(theMethod)) {
160: addTest(warning("Test method isn't public: "
161: + theMethod.getName()));
162: }
163: }
164: }
165:
166: /**
167: * @see junit.framework.TestSuite#exceptionToString(Throwable)
168: */
169: private String exceptionToString(Throwable theThrowable) {
170: StringWriter stringWriter = new StringWriter();
171: PrintWriter writer = new PrintWriter(stringWriter);
172: theThrowable.printStackTrace(writer);
173: return stringWriter.toString();
174: }
175:
176: /**
177: * @see junit.framework.TestSuite#countTestCases()
178: */
179: public int countTestCases() {
180: int count = 0;
181: for (Enumeration e = tests(); e.hasMoreElements();) {
182: Test test = (Test) e.nextElement();
183: count = count + test.countTestCases();
184: }
185: return count;
186: }
187:
188: /**
189: * @see junit.framework.TestSuite#isPublicTestMethod(Method)
190: */
191: private boolean isPublicTestMethod(Method theMethod) {
192: return isTestMethod(theMethod)
193: && Modifier.isPublic(theMethod.getModifiers());
194: }
195:
196: /**
197: * @see junit.framework.TestSuite#isTestMethod(Method)
198: */
199: private boolean isTestMethod(Method theMethod) {
200: String name = theMethod.getName();
201: Class[] parameters = theMethod.getParameterTypes();
202: Class returnType = theMethod.getReturnType();
203: return parameters.length == 0 && name.startsWith("test")
204: && returnType.equals(Void.TYPE);
205: }
206:
207: /**
208: * @see junit.framework.TestSuite#run(TestResult)
209: */
210: public void run(TestResult theResult) {
211: for (Enumeration e = tests(); e.hasMoreElements();) {
212: if (theResult.shouldStop()) {
213: break;
214: }
215: Test test = (Test) e.nextElement();
216: runTest(test, theResult);
217: }
218: }
219:
220: /**
221: * @see junit.framework.TestSuite#runTest(Test, TestResult)
222: */
223: protected void runTest(Test theTest, TestResult theResult) {
224: theTest.run(theResult);
225: }
226:
227: /**
228: * @see junit.framework.TestSuite#testAt(int)
229: */
230: protected Test testAt(int theIndex) {
231: return (Test) this .tests.elementAt(theIndex);
232: }
233:
234: /**
235: * Gets a constructor which takes a single String as
236: * its argument or a no arg constructor.
237: *
238: * @param theClass the class for which to find the constructor
239: * @return the valid constructor found
240: * @exception NoSuchMethodException if no valid constructor is
241: * found
242: */
243: protected static Constructor getTestConstructor(Class theClass)
244: throws NoSuchMethodException {
245: Constructor result;
246: try {
247: result = theClass
248: .getConstructor(new Class[] { String.class });
249: } catch (NoSuchMethodException e) {
250: result = theClass.getConstructor(new Class[0]);
251: }
252: return result;
253: }
254:
255: /**
256: * @see junit.framework.TestSuite#testCount()
257: */
258: protected int testCount() {
259: return this .tests.size();
260: }
261:
262: /**
263: * @see junit.framework.TestSuite#tests()
264: */
265: protected Enumeration tests() {
266: return this .tests.elements();
267: }
268:
269: /**
270: * @see junit.framework.TestSuite#toString()
271: */
272: public String toString() {
273: if (getName() != null) {
274: return getName();
275: }
276: return super .toString();
277: }
278:
279: /**
280: * @see junit.framework.TestSuite#setName(String)
281: */
282: protected void setName(String theName) {
283: this .name = theName;
284: }
285:
286: /**
287: * @see junit.framework.TestSuite#getName()
288: */
289: protected String getName() {
290: return this .name;
291: }
292:
293: /**
294: * @see junit.framework.TestSuite#warning(String)
295: */
296: private static Test warning(final String theMessage) {
297: return new TestCase("warning") {
298: protected void runTest() {
299: fail(theMessage);
300: }
301: };
302: }
303:
304: /**
305: * @param theTestClass the test class containing the tests to be included
306: * in the Cactus Test Suite
307: * @return a Cactus Test Suite (ex: ServletTestSuite) initialized with a
308: * test class
309: */
310: protected abstract Test createTestSuite(Class theTestClass);
311:
312: /**
313: * @param theName the name of the Cactus Test Case
314: * @param theTest the wrapped test
315: * @return a Cactus Test Case object initialized with the give name and
316: * wrapped test
317: */
318: protected abstract Test createCactusTestCase(String theName,
319: Test theTest);
320: }
|