1 /*
2 * Copyright 2006 Edward Kuns
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * $Id: TestWithCustomTest.java 0000 2006-10-19 22:00:00Z ekuns $
17 */
18 package org.castor.xmlctf;
19
20 import java.util.Iterator;
21 import java.util.List;
22
23 import junit.framework.TestCase;
24
25 import org.exolab.castor.tests.framework.testDescriptor.ConfigurationType;
26 import org.exolab.castor.tests.framework.testDescriptor.CustomTest;
27 import org.exolab.castor.tests.framework.testDescriptor.FailureType;
28 import org.exolab.castor.tests.framework.testDescriptor.types.FailureStepType;
29 import org.exolab.castor.xml.XMLContext;
30
31 /**
32 * Implements a test case that tests code written by the XML source generator.
33 * This class uses a user-provided test class to test the generated source.
34 * <p>
35 * Each user-provided test is allowed to return a Boolean, either a primitive or
36 * a java.lang.Boolean -- it does not matter. If the user-provided test returns
37 * a Boolean and it is false, then the test is considered to have failed. If the
38 * user-provided test throws <i>or returns</i> a Throwable, it is considered to
39 * have failed. If the user-provided test returns <b>anything else</b>
40 * (including void) then the test is considered to have passed.
41 * <p>
42 * Note: Returning Throwable is a little bit cleaner than throwing an Exception,
43 * but either is acceptable as a sign of test failure. This is because when a
44 * Throwable is returned, if -printStack is in effect, then the CORRECT stack
45 * trace can be displayed and not a stack dump from the refective invocation.
46 * <p>
47 * There is no requirement that the user-provided test implement any interface,
48 * nor any requirement that the user-provided test return anything at all.
49 * However, a test that returns "void" and that never throws an Exception is not
50 * a very useful test as it can never fail.
51 *
52 * @author <a href="mailto:edward.kuns@aspect.com">Edward Kuns</a>
53 * @version $Revision: 0000 $ $Date: $
54 */
55 class TestWithCustomTest extends TestCase {
56 /** We add this fixed string to the end of our testcase name. */
57 private static final String CUSTOM = "_CustomTest";
58
59 /** We delegate all actions to this test case. */
60 private final XMLTestCase _delegate;
61
62 /** The failure object that is not null is the test intends to fail. */
63 protected final FailureType _failure;
64 /** True if the test is supposed to return failure or throw an Exception. */
65 protected final boolean _failureExpected;
66
67 /**
68 * Blank constructor for this test case. This contructor is not useful,
69 * since no delegate test case is provided.
70 *
71 * @param name
72 * Name of our delegate test case
73 */
74 TestWithCustomTest(final String name) {
75 super(name + CUSTOM);
76 throw new IllegalArgumentException("You cannot use the name-only constructor");
77 }
78
79 /**
80 * Constructs a test case that when invoked will delegate to the provided
81 * test case.
82 * @param name Name of our delegate test case
83 * @param tc
84 */
85 TestWithCustomTest(final String name, final XMLTestCase tc) {
86 super(name + CUSTOM);
87 _delegate = tc;
88 _failure = tc._failure;
89 _failureExpected = _failure != null && _failure.getContent();
90 }
91
92 /**
93 * Provides setup for our delegated test case, depending on the type of
94 * test case we are delegating for.
95 * @throws Exception if anything goes wrong during setup
96 */
97 protected void setUp() throws Exception {
98 _delegate.setXMLContext(new XMLContext());
99
100 if (_delegate instanceof MarshallingFrameworkTestCase) {
101 ((MarshallingFrameworkTestCase)_delegate).setUp();
102 } else if (_delegate instanceof SourceGeneratorTestCase) {
103 ((SourceGeneratorTestCase)_delegate).setUp();
104 }
105 }
106
107 /**
108 * Provides tear down for our delegated test case, depending on the type of
109 * test case we are delegating for.
110 * @throws Exception if anything goes wrong during teardown
111 */
112 protected void tearDown() throws Exception {
113 if (_delegate instanceof MarshallingFrameworkTestCase) {
114 ((MarshallingFrameworkTestCase)_delegate).tearDown();
115 } else if (_delegate instanceof SourceGeneratorTestCase) {
116 ((SourceGeneratorTestCase)_delegate).tearDown();
117 }
118 }
119
120 /**
121 * Runs our test case using our delegate object where necessary.
122 * @throws Exception when anything goes wrong (this is temporary)
123 */
124 public void runTest() {
125 verbose("\n------------------------------");
126 verbose("Run the custom test case");
127 verbose("------------------------------\n");
128 if (_delegate._skip) {
129 verbose("-->Skipping the test");
130 return;
131 }
132
133 List returnValues = null;
134
135 try {
136 CustomTest customTest = _delegate._unitTest.getCustomTest();
137 ConfigurationType testConfig = customTest.getMethods();
138 Object object = getTestObject(customTest.getTestClass());
139 returnValues = _delegate.invokeEnumeratedMethods(object, testConfig);
140 } catch (Exception e) {
141 if (!_delegate.checkExceptionWasExpected(e, FailureStepType.CUSTOM_TEST)) {
142 fail("Exception running the custom test " + e);
143 }
144 return;
145 }
146
147 // Loop over all our return values ... any FALSE or Throwable means a failure
148 int count = 0;
149 boolean testFailed = false;
150
151 for (Iterator i = returnValues.iterator(); i.hasNext(); count++) {
152 Object o = i.next();
153
154 // If this test returned false and we DID NOT expect to fail, error!!!
155 if (o instanceof Boolean && !((Boolean)o).booleanValue() && !_failureExpected) {
156 // Mark failure, complain, but keep checking so we give ALL complaints
157 testFailed = true;
158 System.out.println("Custom test #" + count + " was expected to succeed, but returned false");
159 }
160
161 // If this test *returned* (not threw) an Exception, consider that a failure
162 if (o instanceof Throwable && !_failureExpected) {
163 testFailed = true;
164 System.out.println("Custom test #" + count + " was expected to succeed, but returned Throwable");
165 if (XMLTestCase._printStack) {
166 ((Throwable)o).printStackTrace();
167 }
168 }
169 }
170
171 // Did we fail to meet our expected result, either success or failure?
172 if (testFailed ^ _failureExpected) {
173 if (testFailed) {
174 fail("The custom test failed");
175 } else {
176 fail("The custom test was expected to fail, but succeeded");
177 }
178 }
179 }
180
181 /**
182 * Gets an instance of our test object, as configured.
183 * @param testClassName name of the test class
184 * @return an instance of our test object
185 * @throws ClassNotFoundException when the test object's class cannot be found
186 * @throws IllegalAccessException when the test object's constructor is private or protected
187 * @throws InstantiationException when the test object is abstract or an interface
188 */
189 protected Object getTestObject(final String testClassName) throws ClassNotFoundException,
190 IllegalAccessException, InstantiationException {
191 Class testObject = null;
192 if (_delegate._test.getClassLoader() != null) {
193 testObject = _delegate._test.getClassLoader().loadClass(testClassName);
194 } else {
195 testObject = this.getClass().getClassLoader().loadClass(testClassName);
196 }
197 return testObject.newInstance();
198 }
199
200 /**
201 * print the message if in verbose mode.
202 * @param message the message to print
203 */
204 private void verbose(final String message) {
205 _delegate.verbose(message);
206 }
207
208 }