Source code: org/apache/batik/test/AbstractTest.java
1 /*
2
3 Copyright 2001-2003 The Apache Software Foundation
4
5 Licensed under the Apache License, Version 2.0 (the "License");
6 you may not use this file except in compliance with the License.
7 You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
16
17 */
18 package org.apache.batik.test;
19
20 import java.io.StringWriter;
21 import java.io.PrintWriter;
22
23 /**
24 * Base class containing convenience methods for writing tests. <br />
25 * There are at least three approaches to write new tests derived from
26 * <tt>AbstractTest</tt>:<br /><ul>
27 * <li>You can simply override the <tt>runImplBase</tt> method and
28 * return true or false depending on whether or not the test fails.</li>
29 * <li>You can choose to report more complex test failure conditions
30 * by overriding the <tt>runImpl</tt> method which returns a <tt>TestReport</tt>.
31 * In that case, you can use the convenience methods such as <tt>reportFailure</tt>
32 * <tt>reportSuccess</tt> or <tt>reportException</tt> to help build a <tt>TestReport</tt>,
33 * and use the <tt>TestReport</tt>'s <tt>addDescriptionEntry</tt> to populate
34 * the report with relevant error description.</li>
35 * <li>You can choose to use the various assertion methods such as <tt>assertNull</tt>,
36 * <tt>assertEquals</tt> or <tt>assertTrue</tt>. These methods throw exceptions which
37 * will be turned in <tt>TestReports</tt> by the <tt>AbstractTest</tt>.</li>
38 * </ul>
39 *
40 * Here are some examples:
41 * <code>
42 * public class MyTestA extends AbstractTest {
43 * public boolean runImplBase() {
44 * if(someConditionFails){
45 * return false;
46 * }
47 * return true;
48 * }
49 * }
50 * </code>
51 *
52 * <code>
53 * public class MyTestB extends AbstractTest {
54 * public TestReport runImpl() {
55 * if(someConditionFails){
56 * TestReport report = reportError(MY_ERROR_CODE);
57 * report.addDescriptionEntry(ENTRY_KEY_MY_ERROR_DESCRIPTION_KEY,
58 * myErrorDescriptionValue);
59 * return report;
60 * }
61 *
62 * return reportSuccess();
63 * }
64 * </code>
65 *
66 * <code>
67 * public class MyTestC extends AbstractTest {
68 * public TestReport runImpl() throws Exception {
69 * assertTrue(somCondition);
70 * assertEquals(valueA, valueB);
71 * assertNull(shouldBeNullRef);
72 *
73 * if(someErrorCondition){
74 * error(MY_ERROR_CODE);
75 * }
76 *
77 * return reportSuccess();
78 * }
79 * </code>
80 *
81 * @author <a href="mailto:vhardy@apache.lorg">Vincent Hardy</a>
82 * @version $Id: AbstractTest.java,v 1.12 2004/08/18 07:16:55 vhardy Exp $
83 */
84 public abstract class AbstractTest implements Test {
85 /**
86 * This test's id.
87 */
88 protected String id = "";
89
90 /**
91 * This test's parent, in case this test is part of
92 * a suite.
93 */
94 protected TestSuite parent;
95
96 /**
97 * This test's name. If null, the class' name is returned.
98 */
99 protected String name;
100
101 /**
102 * TestReport
103 */
104 private DefaultTestReport report
105 = new DefaultTestReport(this) {
106 {
107 setErrorCode(ERROR_INTERNAL_TEST_FAILURE);
108 setPassed(false);
109 }
110 };
111
112 /**
113 * Returns this <tt>Test</tt>'s name.
114 */
115 public String getName(){
116 if(name == null){
117 if (id != null && !"".equals(id)){
118 return id;
119 } else {
120 return getClass().getName();
121 }
122 }
123
124 return name;
125 }
126
127 /**
128 * Sets this test's name
129 */
130 public void setName(String name){
131 this.name = name;
132 }
133
134 /**
135 * Return this <tt>Test</tt>'s id.
136 */
137 public String getId(){
138 return id;
139 }
140
141 /**
142 * Return this <tt>Test</tt>'s qualified id.
143 */
144 public String getQualifiedId(){
145 if(parent == null){
146 return getId();
147 }
148 return getParent().getQualifiedId() + "." + getId();
149 }
150
151 /**
152 * Set this <tt>Test</tt>'s id. Null is not allowed.
153 */
154 public void setId(String id){
155 if(id == null){
156 throw new IllegalArgumentException();
157 }
158
159 this.id = id;
160 }
161
162 public TestSuite getParent(){
163 return parent;
164 }
165
166 public void setParent(TestSuite parent){
167 this.parent = parent;
168 }
169
170 /**
171 * This default implementation of the run method
172 * catches any Exception thrown from the
173 * runImpl method and creates a <tt>TestReport</tt>
174 * indicating an internal <tt>Test</tt> failure
175 * when that happens. Otherwise, this method
176 * simply returns the <tt>TestReport</tt> generated
177 * by the <tt>runImpl</tt> method.
178 */
179 public TestReport run(){
180 try{
181 return runImpl();
182 } catch(TestErrorConditionException e){
183 return e.getTestReport(this);
184 } catch(Exception e){
185 try {
186
187 StringWriter trace = new StringWriter();
188 e.printStackTrace(new PrintWriter(trace));
189
190 TestReport.Entry[] entries = new TestReport.Entry[]{
191 new TestReport.Entry
192 (Messages.formatMessage
193 (TestReport.ENTRY_KEY_INTERNAL_TEST_FAILURE_EXCEPTION_CLASS, null),
194 e.getClass().getName()),
195 new TestReport.Entry
196 (Messages.formatMessage
197 (TestReport.ENTRY_KEY_INTERNAL_TEST_FAILURE_EXCEPTION_MESSAGE, null),
198 e.getMessage()),
199 new TestReport.Entry
200 (Messages.formatMessage
201 (TestReport.ENTRY_KEY_INTERNAL_TEST_FAILURE_EXCEPTION_STACK_TRACE, null),
202 trace.toString())
203 };
204
205 report.setDescription(entries);
206
207 }catch(Exception ex){
208 ex.printStackTrace();
209 }finally {
210 //
211 // In case we are in severe trouble, even filling in the
212 // TestReport may fail. Because the TestReport instance
213 // was created up-front, this ensures we can return
214 // the report, even though it may be incomplete.
215 e.printStackTrace();
216 System.out.println("SERIOUS ERROR");
217 return report;
218 }
219
220 }
221 }
222
223 /**
224 * Subclasses should implement this method with the content of
225 * the test case. Typically, implementations will choose to
226 * catch and process all exceptions and error conditions they
227 * are looking for in the code they exercise but will let
228 * exceptions due to their own processing propagate.
229 */
230 public TestReport runImpl() throws Exception {
231 boolean passed = runImplBasic();
232
233 // No exception was thrown if we get to this
234 // portion of rumImpl. The test result is
235 // given by passed.
236 DefaultTestReport report = new DefaultTestReport(this);
237 if(!passed){
238 report.setErrorCode(TestReport.ERROR_TEST_FAILED);
239 }
240 report.setPassed(passed);
241 return report;
242 }
243
244 /**
245 * In the simplest test implementation, developers can
246 * simply implement the following method.
247 */
248 public boolean runImplBasic() throws Exception {
249 return true;
250 }
251
252 /**
253 * Convenience method.
254 */
255 public TestReport reportSuccess() {
256 DefaultTestReport report = new DefaultTestReport(this);
257 report.setPassed(true);
258 return report;
259 }
260
261 /**
262 * Convenience method to report a simple error code.
263 */
264 public TestReport reportError(String errorCode){
265 DefaultTestReport report = new DefaultTestReport(this);
266 report.setErrorCode(errorCode);
267 report.setPassed(false);
268 return report;
269 }
270
271 /**
272 * Convenience method to report an error condition.
273 */
274 public void error(String errorCode) throws TestErrorConditionException {
275 throw new TestErrorConditionException(errorCode);
276 }
277
278 /**
279 * Convenience method to check that a reference is null
280 */
281 public void assertNull(Object ref) throws AssertNullException {
282 if(ref != null){
283 throw new AssertNullException();
284 }
285 }
286
287 /**
288 * Convenience method to check that a given boolean is true.
289 */
290 public void assertTrue(boolean b) throws AssertTrueException {
291 if (!b){
292 throw new AssertTrueException();
293 }
294 }
295
296 /**
297 * Convenience method to check for a specific condition.
298 * Returns true if both objects are null or if ref is not
299 * null and ref.equals(cmp) is true.
300 */
301 public void assertEquals(Object ref, Object cmp) throws AssertEqualsException {
302 if(ref == null && cmp != null){
303 throw new AssertEqualsException(ref, cmp);
304 }
305
306 if(ref != null && !ref.equals(cmp)){
307 throw new AssertEqualsException(ref, cmp);
308 }
309 }
310
311 public void assertEquals(int ref, int cmp) throws AssertEqualsException {
312 assertEquals(new Integer(ref), new Integer(cmp));
313 }
314
315 /**
316 * Convenience method to help implementations report errors.
317 * An <tt>AbstractTest</tt> extension will typically catch
318 * exceptions for specific error conditions it wants to point
319 * out. For example:<tt>
320 * public TestReport runImpl() throws Exception { <br />
321 * try{ <br />
322 * .... something .... <br />
323 * catch(MySpecialException e){ <br />
324 * return reportException(MY_SPECIAL_ERROR_CODE, e); <br />
325 * } <br />
326 * <br />
327 * public static final String MY_SPECIAL_ERROR_CODE = "myNonQualifiedClassName.my.error.code" <br />
328 * <br />
329 * </tt> <br />
330 * Note that the implementor will also need to add an entry
331 * in its Messages.properties file. That file is expected to be
332 * in a resource file called <tt>Messages</tt> having the same package
333 * name as the <tt>Test</tt> class, appended with "<tt>.resources</tt>".
334 */
335 public TestReport reportException(String errorCode,
336 Exception e){
337 DefaultTestReport report
338 = new DefaultTestReport(this);
339
340 StringWriter trace = new StringWriter();
341 e.printStackTrace(new PrintWriter(trace));
342 report.setErrorCode(errorCode);
343
344
345 TestReport.Entry[] entries = new TestReport.Entry[]{
346 new TestReport.Entry
347 (Messages.formatMessage
348 (TestReport.ENTRY_KEY_REPORTED_TEST_FAILURE_EXCEPTION_CLASS, null),
349 e.getClass().getName()),
350 new TestReport.Entry
351 (Messages.formatMessage
352 (TestReport.ENTRY_KEY_REPORTED_TEST_FAILURE_EXCEPTION_MESSAGE, null),
353 e.getMessage()),
354 new TestReport.Entry
355 (Messages.formatMessage
356 (TestReport.ENTRY_KEY_REPORTED_TEST_FAILURE_EXCEPTION_STACK_TRACE, null),
357 trace.toString())
358 };
359 report.setDescription(entries);
360 report.setPassed(false);
361 return report;
362 }
363
364
365 }