001: /*
002: * Copyright 2002,2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.apache.commons.jelly.tags.junit;
017:
018: import org.apache.commons.jelly.JellyException;
019: import org.apache.commons.jelly.JellyTagException;
020: import org.apache.commons.jelly.XMLOutput;
021: import org.apache.commons.jelly.util.ClassLoaderUtils;
022: import org.apache.commons.logging.Log;
023: import org.apache.commons.logging.LogFactory;
024:
025: /**
026: * Runs its body and asserts that an exception is thrown by it. If no
027: * exception is thrown the tag fails. By default all exceptions are caught.
028: * If however <code>expected</code> was specified the body must throw
029: * an exception of the given class, otherwise the assertion fails. The
030: * exception thrown by the body can also be of any subtype of the specified
031: * exception class. The optional <code>var</code> attribute can be specified if
032: * the caught exception is to be exported to a variable.
033: */
034: public class AssertThrowsTag extends AssertTagSupport {
035:
036: /** The Log to which logging calls will be made. */
037: private static final Log log = LogFactory
038: .getLog(AssertThrowsTag.class);
039:
040: /**
041: * The variable name to export the caught exception to.
042: */
043: private String var;
044:
045: /**
046: * The class name (fully qualified) of the exception expected to be thrown
047: * by the body. Also a superclass of the expected exception can be given.
048: */
049: private String expected;
050:
051: /**
052: * Sets the ClassLoader to be used when loading an exception class
053: */
054: private ClassLoader classLoader;
055:
056: // Tag interface
057: //-------------------------------------------------------------------------
058: public void doTag(XMLOutput output) throws JellyTagException {
059: Class throwableClass = null;
060: try {
061: throwableClass = getThrowableClass();
062: invokeBody(output);
063: } catch (Throwable t) {
064: if (t instanceof JellyException) {
065: // unwrap Jelly exceptions which wrap other exceptions
066: JellyException je = (JellyException) t;
067: if (je.getCause() != null) {
068: t = je.getCause();
069: }
070: }
071: if (var != null) {
072: context.setVariable(var, t);
073: }
074: if (throwableClass != null
075: && !throwableClass.isAssignableFrom(t.getClass())) {
076: fail("Unexpected exception: " + t);
077: } else {
078: return;
079: }
080: }
081: fail("No exception was thrown.");
082: }
083:
084: // Properties
085: //-------------------------------------------------------------------------
086: /**
087: * Sets the class name of exception expected to be thrown by the body. The
088: * class name must be fully qualified and can either be the expected
089: * exception class itself or any supertype of it, but must be a subtype of
090: * <code>java.lang.Throwable</code>.
091: */
092: public void setExpected(String expected) {
093: this .expected = expected;
094: }
095:
096: /**
097: * Sets the variable name to define for this expression.
098: */
099: public void setVar(String var) {
100: this .var = var;
101: }
102:
103: /**
104: * Sets the class loader to be used to load the exception type
105: */
106: public void setClassLoader(ClassLoader classLoader) {
107: this .classLoader = classLoader;
108: }
109:
110: public ClassLoader getClassLoader() {
111: return ClassLoaderUtils.getClassLoader(classLoader, getClass());
112: }
113:
114: // Implementation methods
115: //-------------------------------------------------------------------------
116:
117: /**
118: * Returns the <code>Class</code> corresponding to the class
119: * specified by <code>expected</code>. If
120: * <code>expected</code> was either not specified then <code>java. lang.
121: * Throwable</code> is returned.
122: * Otherwise if the class couldn't be
123: * found or doesn't denote an exception class then an exception is thrown.
124: *
125: * @return Class The class of the exception to expect
126: */
127: protected Class getThrowableClass() throws ClassNotFoundException {
128: if (expected == null) {
129: return Throwable.class;
130: }
131:
132: Class throwableClass = null;
133: try {
134: throwableClass = getClassLoader().loadClass(expected);
135: } catch (ClassNotFoundException e) {
136: try {
137: throwableClass = Thread.currentThread()
138: .getContextClassLoader().loadClass(expected);
139: } catch (ClassNotFoundException e2) {
140: log.warn("Could not find exception class: " + expected);
141: throw e;
142: }
143: }
144:
145: if (!Throwable.class.isAssignableFrom(throwableClass)) {
146: log.warn("The class: " + expected
147: + " is not an Exception class.");
148: return null;
149: }
150: return throwableClass;
151: }
152: }
|