001: /*
002: * @(#)TestClassCreator.java
003: *
004: * Copyright (C) 2002-2003 Matt Albrecht
005: * groboclown@users.sourceforge.net
006: * http://groboutils.sourceforge.net
007: *
008: * Permission is hereby granted, free of charge, to any person obtaining a
009: * copy of this software and associated documentation files (the "Software"),
010: * to deal in the Software without restriction, including without limitation
011: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
012: * and/or sell copies of the Software, and to permit persons to whom the
013: * Software is furnished to do so, subject to the following conditions:
014: *
015: * The above copyright notice and this permission notice shall be included in
016: * all copies or substantial portions of the Software.
017: *
018: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
019: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
020: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
021: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
022: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
023: * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
024: * DEALINGS IN THE SOFTWARE.
025: */
026:
027: package net.sourceforge.groboutils.junit.v1.parser;
028:
029: import java.util.Vector;
030: import java.util.Enumeration;
031: import java.io.PrintWriter;
032: import java.io.StringWriter;
033:
034: import java.lang.reflect.Method;
035: import java.lang.reflect.InvocationTargetException;
036:
037: import junit.framework.TestSuite;
038: import junit.framework.TestCase;
039: import junit.framework.Test;
040:
041: import org.apache.log4j.Logger;
042:
043: /**
044: * Creates Test instances based on a <tt>TestClassParser</tt>.
045: * <P>
046: * Ripped the test method discovery code out of junit.framework.TestSuite to
047: * allow it to have usable logic.
048: * <P>
049: * This is not covered under the GroboUtils license, but rather under the
050: * JUnit license (IBM Public License). This heading may not be totally
051: * in line with the license, so I'll change it when I find out what needs to
052: * be changed.
053: *
054: * @author Matt Albrecht <a href="mailto:groboclown@users.sourceforge.net">groboclown@users.sourceforge.net</a>
055: * @version $Date: 2003/02/10 22:52:21 $
056: * @since November 4, 2002
057: */
058: public class TestClassCreator {
059: private static final Logger LOG = Logger
060: .getLogger(TestClassCreator.class);
061:
062: private ITestCreator creator;
063: private Vector warnings = new Vector();
064:
065: /**
066: * Creates an instance that creates test instances based on the given
067: * creator.
068: *
069: * @exception IllegalArgumentException if <tt>theClass</tt> is
070: * <tt>null</tt>.
071: */
072: public TestClassCreator(final ITestCreator tc) {
073: if (tc == null) {
074: throw new IllegalArgumentException("no null arguments");
075: }
076: this .creator = tc;
077: }
078:
079: //-------------------------------------------------------------------------
080: // Public methods
081:
082: /**
083: * Retrieve all warnings generated during the introspection of the class,
084: * or test creation. If a <tt>clearWarnings()</tt> call was ever made, then
085: * only those warnings that were encountered after the call will be
086: * returned.
087: *
088: * @return an array of all warnings generated while creating the test
089: * array.
090: */
091: public String[] getWarnings() {
092: String w[] = new String[this .warnings.size()];
093: this .warnings.copyInto(w);
094: return w;
095: }
096:
097: /**
098: * Remove all current warnings.
099: */
100: public void clearWarnings() {
101: this .warnings.removeAllElements();
102: }
103:
104: /**
105: * This will create all test objects for the test registered with the
106: * parser. Any errors reported during generation will be added to the
107: * warnings list.
108: *
109: * @return all valid tests created through inspection.
110: */
111: public Test[] createTests(TestClassParser tcp) {
112: Vector t = new Vector();
113: if (this .creator.canCreate(tcp.getTestClass())) {
114: Method m[] = tcp.getTestMethods();
115: for (int i = 0; i < m.length; ++i) {
116: try {
117: Test tt = this .creator.createTest(tcp
118: .getTestClass(), m[i]);
119: if (tt != null) {
120: t.addElement(tt);
121: } else {
122: warning("Could not create test for class "
123: + tcp.getTestClass().getName()
124: + " and method " + m[i].getName() + ".");
125: }
126: } catch (InstantiationException ie) {
127: warning("Method " + m[i].getName()
128: + " could not be added as a test: " + ie);
129: } catch (NoSuchMethodException nsme) {
130: warning("No valid constructor for "
131: + tcp.getTestClass().getName() + ": "
132: + nsme);
133: } catch (InvocationTargetException ite) {
134: warning("Construction of class "
135: + tcp.getTestClass().getName()
136: + " caused an exception: "
137: + ite.getTargetException());
138: } catch (IllegalAccessException iae) {
139: warning("Protection on constructor for class "
140: + tcp.getTestClass().getName()
141: + " was invalid: " + iae);
142: } catch (ClassCastException cce) {
143: warning("Class " + tcp.getTestClass().getName()
144: + " is not of Test type.");
145: }
146: }
147: } else {
148: warning("TestCreator does not know how to handle class "
149: + tcp.getTestClass().getName() + ".");
150: }
151:
152: Test tt[] = new Test[t.size()];
153: t.copyInto(tt);
154: return tt;
155: }
156:
157: /**
158: * For every warning currently known in this creator and the parser,
159: * create a Test that fails with the warning's message. Note that after
160: * creating a test with the warnings, this instance will still know about
161: * the warnings.
162: *
163: * @return an array of tests that fail with a particular warning.
164: */
165: public Test[] createWarningTests(TestClassParser tcp) {
166: String s1[] = getWarnings();
167: String s2[] = tcp.getWarnings();
168: Test t[] = new Test[s1.length + s2.length];
169: for (int i = 0; i < s1.length; ++i) {
170: t[i] = createWarningTest(s1[i]);
171: }
172: for (int i = 0; i < s2.length; ++i) {
173: t[i + s1.length] = createWarningTest(s2[i]);
174: }
175: return t;
176: }
177:
178: /**
179: * Create a new TestSuite, containing the tests returned by the call to
180: * <tt>createTests()</tt>. No warning tests will be added.
181: *
182: * @return a new TestSuite with all the valid, discovered tests.
183: */
184: public TestSuite createTestSuite(TestClassParser tcp) {
185: TestSuite ts = new TestSuite(tcp.getName());
186: Test t[] = createTests(tcp);
187: for (int i = 0; i < t.length; ++i) {
188: if (t[i] != null) {
189: ts.addTest(t[i]);
190: }
191: }
192: return ts;
193: }
194:
195: /**
196: * Create a new TestSuite, containing the tests returned by the call to
197: * <tt>createTests()</tt> and <tt>createWarningTests</tt>.
198: *
199: * @return a new TestSuite with all the valid, discovered tests, and the
200: * warning tests.
201: */
202: public TestSuite createAllTestSuite(TestClassParser tcp) {
203: TestSuite ts = createTestSuite(tcp);
204: Test t[] = createWarningTests(tcp);
205: for (int i = 0; i < t.length; ++i) {
206: if (t[i] != null) {
207: ts.addTest(t[i]);
208: }
209: }
210: return ts;
211: }
212:
213: /**
214: * Create a new Test that will fail with the given error message.
215: *
216: * @param message the text to report in the failure of the created
217: * Test.
218: * @return a test that will fail with the given message.
219: */
220: public static Test createWarningTest(final String message) {
221: return new TestCase("warning") {
222: protected void runTest() {
223: fail(message);
224: }
225: };
226: }
227:
228: //-------------------------------------------------------------------------
229: // Protected methods
230:
231: /**
232: * Adds a warning message to the inner list of warnings.
233: *
234: * @param message the message describing the warning.
235: */
236: protected void warning(final String message) {
237: LOG.info("WARNING: " + message);
238: this.warnings.addElement(message);
239: }
240: }
|