001: /*
002: * ========================================================================
003: *
004: * Copyright 2003 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.integration.ant;
021:
022: import java.io.BufferedReader;
023: import java.io.File;
024: import java.io.FileNotFoundException;
025: import java.io.FileOutputStream;
026: import java.io.IOException;
027: import java.io.StringReader;
028: import java.util.HashMap;
029: import java.util.HashSet;
030: import java.util.Map;
031: import java.util.Set;
032:
033: import junit.framework.AssertionFailedError;
034: import junit.framework.TestCase;
035:
036: import org.apache.tools.ant.BuildEvent;
037: import org.apache.tools.ant.BuildException;
038: import org.apache.tools.ant.BuildListener;
039: import org.apache.tools.ant.Project;
040: import org.apache.tools.ant.ProjectHelper;
041: import org.apache.tools.ant.Target;
042:
043: /**
044: * An AntTestCase is a TestCase specialization for unit testing Ant tasks.
045: *
046: * @version $Id: AntTestCase.java 239003 2004-05-31 20:05:27Z vmassol $
047: */
048: public abstract class AntTestCase extends TestCase implements
049: BuildListener {
050: // Instance Variables ------------------------------------------------------
051:
052: /**
053: * The Ant project.
054: */
055: private Project project;
056:
057: /**
058: * The name of the test build file.
059: */
060: private String buildFile;
061:
062: /**
063: * Buffer containing all messages logged by Ant. Keys correspond to the
064: * message priority as <code>java.lang.Integer</code>, the values are are
065: * <code>java.lang.StringBuffer</code>s containing the actual log messages.
066: */
067: private Map log = new HashMap();
068:
069: /**
070: * File where to log Ant outputs for debugging. If no file location has
071: * been passed, there will be no file logging.
072: */
073: private FileOutputStream outputStream;
074:
075: /**
076: * The targets the have been executed.
077: */
078: private Set executedTargets = new HashSet();
079:
080: // Constructors ------------------------------------------------------------
081:
082: /**
083: * @param theBuildFile The Ant build file corresponding to the test fixture
084: */
085: public AntTestCase(String theBuildFile) {
086: this .buildFile = theBuildFile;
087:
088: String outputString = System.getProperty("logfile");
089: if (outputString != null) {
090: try {
091: this .outputStream = new FileOutputStream(outputString);
092: } catch (FileNotFoundException e) {
093: // Silently ignore error when creating output stream
094: }
095: }
096: }
097:
098: // BuildListener Implementation --------------------------------------------
099:
100: /**
101: * @see BuildListener#buildStarted
102: */
103: public final void buildStarted(BuildEvent theEvent) {
104: }
105:
106: /**
107: * @see BuildListener#buildFinished
108: */
109: public final void buildFinished(BuildEvent theEvent) {
110: }
111:
112: /**
113: * @see BuildListener#targetStarted
114: */
115: public final void targetStarted(BuildEvent theEvent) {
116: }
117:
118: /**
119: * @see BuildListener#targetFinished
120: */
121: public final void targetFinished(BuildEvent theEvent) {
122: this .executedTargets.add(theEvent.getTarget().getName());
123: }
124:
125: /**
126: * @see BuildListener#taskStarted
127: */
128: public final void taskStarted(BuildEvent theEvent) {
129: }
130:
131: /**
132: * @see BuildListener#taskFinished
133: */
134: public final void taskFinished(BuildEvent theEvent) {
135: }
136:
137: /**
138: * @see BuildListener#messageLogged
139: */
140: public final void messageLogged(BuildEvent theEvent) {
141: StringBuffer buffer = (StringBuffer) log.get(new Integer(
142: theEvent.getPriority()));
143: if (buffer == null) {
144: buffer = new StringBuffer();
145: log.put(new Integer(theEvent.getPriority()), buffer);
146: }
147: buffer.append(theEvent.getMessage()).append("\n");
148: if (this .outputStream != null) {
149: try {
150: this .outputStream.write(theEvent.getMessage()
151: .getBytes());
152: this .outputStream.write('\n');
153: } catch (IOException e) {
154: // Silently ignore log error
155: }
156: }
157: }
158:
159: // TestCase Implementation -------------------------------------------------
160:
161: /**
162: * Initializes a fresh Ant project with a target named after the name of the
163: * test case.
164: *
165: * @see junit.framework.TestCase#setUp()
166: */
167: protected void setUp() throws Exception {
168: this .project = new Project();
169: this .project.addBuildListener(this );
170: this .project.init();
171: File buildFile = getBuildFile(this .buildFile);
172: this .project.setUserProperty("ant.file", buildFile
173: .getAbsolutePath());
174: ProjectHelper helper = ProjectHelper.getProjectHelper();
175: helper.parse(this .project, buildFile);
176: if (getProject().getTargets().get("setUp") != null) {
177: getProject().executeTarget("setUp");
178: }
179: }
180:
181: /**
182: * @see junit.framework.TestCase#tearDown()
183: */
184: protected void tearDown() throws Exception {
185: if (getProject().getTargets().get("tearDown") != null) {
186: try {
187: getProject().executeTarget("tearDown");
188: } catch (BuildException be) {
189: // exception has been logged
190: }
191: }
192: }
193:
194: // Protected Methods -------------------------------------------------------
195:
196: /**
197: * @return the buffer containing all Ant logs for the specified
198: * log level
199: * @param theLogLevel The log level of the message
200: */
201: protected String getLog(int theLogLevel) {
202: String result = null;
203: StringBuffer buffer = (StringBuffer) this .log.get(new Integer(
204: theLogLevel));
205: if (buffer != null) {
206: result = buffer.toString();
207: }
208: return result;
209: }
210:
211: /**
212: * Asserts that a specific message has been logged at a specific log level.
213: *
214: * @param theMessage The message to check for
215: * @param theLogLevel The log level of the message
216: * @throws IOException If an error occurred reading the log buffer
217: */
218: protected final void assertMessageLogged(String theMessage,
219: int theLogLevel) throws IOException {
220: String buffer = getLog(theLogLevel);
221: if (buffer != null) {
222: BufferedReader reader = new BufferedReader(
223: new StringReader(buffer));
224: String line = null;
225: while ((line = reader.readLine()) != null) {
226: if (line.equals(theMessage)) {
227: return;
228: }
229: }
230: }
231: throw new AssertionFailedError("Expected log message '"
232: + theMessage + "'");
233: }
234:
235: /**
236: * Asserts that a message containing the specified substring has been logged
237: * at a specific log level.
238: *
239: * @param theSubstring The substring to check for
240: * @param theLogLevel The log level of the message
241: * @throws IOException If an error occurred reading the log buffer
242: */
243: protected final void assertMessageLoggedContaining(
244: String theSubstring, int theLogLevel) throws IOException {
245: StringBuffer buffer = (StringBuffer) log.get(new Integer(
246: theLogLevel));
247: if (buffer != null) {
248: BufferedReader reader = new BufferedReader(
249: new StringReader(buffer.toString()));
250: String line = null;
251: while ((line = reader.readLine()) != null) {
252: if (line.indexOf(theSubstring) >= 0) {
253: return;
254: }
255: }
256: }
257: throw new AssertionFailedError(
258: "Expected log message containing '" + theSubstring
259: + "'");
260: }
261:
262: /**
263: * Asserts that a named target has been executed.
264: *
265: * @param theName The name of the target
266: */
267: protected final void assertTargetExecuted(String theName) {
268: assertTrue(
269: "Target '" + theName + "' should have been executed",
270: this .executedTargets.contains(theName));
271: }
272:
273: /**
274: * Executes the target in the project that corresponds to the current test
275: * case.
276: */
277: protected final void executeTestTarget() {
278: this .project.executeTarget(getName());
279: }
280:
281: /**
282: * Returns the Ant project.
283: *
284: * @return The project
285: */
286: protected final Project getProject() {
287: return this .project;
288: }
289:
290: /**
291: * Returns the base directory of the Ant project.
292: *
293: * @return The base directory
294: */
295: protected final File getProjectDir() {
296: return this .project.getBaseDir();
297: }
298:
299: /**
300: * Returns the target in the project that corresponds to the current test
301: * case.
302: *
303: * @return The test target
304: */
305: protected final Target getTestTarget() {
306: return (Target) getProject().getTargets().get(getName());
307: }
308:
309: // Private Methods ---------------------------------------------------------
310:
311: /**
312: * Returns a file from the test inputs directory, which is determined by the
313: * system property <code>testinput.dir</code>.
314: *
315: * @param theFileName The name of the file relative to the test input
316: * directory
317: * @return The file from the test input directory
318: */
319: private File getBuildFile(String theFileName) {
320: String testInputDirProperty = System
321: .getProperty("testinput.dir");
322: assertTrue("The system property 'testinput.dir' must be set",
323: testInputDirProperty != null);
324: File testInputDir = new File(testInputDirProperty);
325: assertTrue(
326: "The system property 'testinput.dir' must point to an "
327: + "existing directory", testInputDir
328: .isDirectory());
329: File buildFile = new File(testInputDir, theFileName);
330: assertTrue("The test input " + theFileName + " does not exist",
331: buildFile.exists());
332: return buildFile;
333: }
334:
335: }
|