001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018:
019: package org.apache.tools.ant;
020:
021: import junit.framework.TestCase;
022: import java.io.File;
023: import java.io.PrintStream;
024: import java.net.URL;
025:
026: /**
027: * A BuildFileTest is a TestCase which executes targets from an Ant buildfile
028: * for testing.
029: *
030: * This class provides a number of utility methods for particular build file
031: * tests which extend this class.
032: *
033: */
034: public abstract class BuildFileTest extends TestCase {
035:
036: protected Project project;
037:
038: private StringBuffer logBuffer;
039: private StringBuffer fullLogBuffer;
040: private StringBuffer outBuffer;
041: private StringBuffer errBuffer;
042: private BuildException buildException;
043:
044: /**
045: * Default constructor for the BuildFileTest object.
046: */
047: public BuildFileTest() {
048: super ();
049: }
050:
051: /**
052: * Constructor for the BuildFileTest object.
053: *
054: * @param name string to pass up to TestCase constructor
055: */
056: public BuildFileTest(String name) {
057: super (name);
058: }
059:
060: /**
061: * Automatically calls the target called "tearDown"
062: * from the build file tested if it exits.
063: *
064: * This allows to use Ant tasks directly in the build file
065: * to clean up after each test. Note that no "setUp" target
066: * is automatically called, since it's trivial to have a
067: * test target depend on it.
068: */
069: protected void tearDown() throws Exception {
070: final String tearDown = "tearDown";
071: if (project.getTargets().containsKey(tearDown)) {
072: project.executeTarget(tearDown);
073: }
074: }
075:
076: /**
077: * run a target, expect for any build exception
078: *
079: * @param target target to run
080: * @param cause information string to reader of report
081: */
082: public void expectBuildException(String target, String cause) {
083: expectSpecificBuildException(target, cause, null);
084: }
085:
086: /**
087: * Assert that only the given message has been logged with a
088: * priority <= INFO when running the given target.
089: */
090: public void expectLog(String target, String log) {
091: executeTarget(target);
092: String realLog = getLog();
093: assertEquals(log, realLog);
094: }
095:
096: /**
097: * Assert that the given substring is in the log messages.
098: */
099: public void assertLogContaining(String substring) {
100: String realLog = getLog();
101: assertTrue("expecting log to contain \"" + substring
102: + "\" log was \"" + realLog + "\"", realLog
103: .indexOf(substring) >= 0);
104: }
105:
106: /**
107: * Assert that the given substring is in the output messages.
108: * @since Ant1.7
109: */
110: public void assertOutputContaining(String substring) {
111: String realOutput = getOutput();
112: assertTrue("expecting output to contain \"" + substring
113: + "\" output was \"" + realOutput + "\"", realOutput
114: .indexOf(substring) >= 0);
115: }
116:
117: /**
118: * Assert that the given message has been logged with a priority
119: * <= INFO when running the given target.
120: */
121: public void expectLogContaining(String target, String log) {
122: executeTarget(target);
123: assertLogContaining(log);
124: }
125:
126: /**
127: * Gets the log the BuildFileTest object.
128: * Only valid if configureProject() has been called.
129: *
130: * @pre logBuffer!=null
131: * @return The log value
132: */
133: public String getLog() {
134: return logBuffer.toString();
135: }
136:
137: /**
138: * Assert that the given message has been logged with a priority
139: * >= VERBOSE when running the given target.
140: */
141: public void expectDebuglog(String target, String log) {
142: executeTarget(target);
143: String realLog = getFullLog();
144: assertEquals(log, realLog);
145: }
146:
147: /**
148: * Assert that the given substring is in the log messages.
149: */
150: public void assertDebuglogContaining(String substring) {
151: String realLog = getFullLog();
152: assertTrue("expecting debug log to contain \"" + substring
153: + "\" log was \"" + realLog + "\"", realLog
154: .indexOf(substring) >= 0);
155: }
156:
157: /**
158: * Gets the log the BuildFileTest object.
159: *
160: * Only valid if configureProject() has been called.
161: *
162: * @pre fullLogBuffer!=null
163: * @return The log value
164: */
165: public String getFullLog() {
166: return fullLogBuffer.toString();
167: }
168:
169: /**
170: * execute the target, verify output matches expectations
171: *
172: * @param target target to execute
173: * @param output output to look for
174: */
175: public void expectOutput(String target, String output) {
176: executeTarget(target);
177: String realOutput = getOutput();
178: assertEquals(output, realOutput.trim());
179: }
180:
181: /**
182: * Executes the target, verify output matches expectations
183: * and that we got the named error at the end
184: *
185: * @param target target to execute
186: * @param output output to look for
187: * @param error Description of Parameter
188: */
189: public void expectOutputAndError(String target, String output,
190: String error) {
191: executeTarget(target);
192: String realOutput = getOutput();
193: assertEquals(output, realOutput);
194: String realError = getError();
195: assertEquals(error, realError);
196: }
197:
198: public String getOutput() {
199: return cleanBuffer(outBuffer);
200: }
201:
202: public String getError() {
203: return cleanBuffer(errBuffer);
204: }
205:
206: public BuildException getBuildException() {
207: return buildException;
208: }
209:
210: private String cleanBuffer(StringBuffer buffer) {
211: StringBuffer cleanedBuffer = new StringBuffer();
212: boolean cr = false;
213: for (int i = 0; i < buffer.length(); i++) {
214: char ch = buffer.charAt(i);
215: if (ch == '\r') {
216: cr = true;
217: continue;
218: }
219:
220: if (!cr) {
221: cleanedBuffer.append(ch);
222: } else {
223: cleanedBuffer.append(ch);
224: }
225: }
226: return cleanedBuffer.toString();
227: }
228:
229: /**
230: * Sets up to run the named project
231: *
232: * @param filename name of project file to run
233: */
234: public void configureProject(String filename) throws BuildException {
235: configureProject(filename, Project.MSG_DEBUG);
236: }
237:
238: /**
239: * Sets up to run the named project
240: *
241: * @param filename name of project file to run
242: */
243: public void configureProject(String filename, int logLevel)
244: throws BuildException {
245: logBuffer = new StringBuffer();
246: fullLogBuffer = new StringBuffer();
247: project = new Project();
248: project.init();
249: File antFile = new File(System.getProperty("root"), filename);
250: project.setUserProperty("ant.file", antFile.getAbsolutePath());
251: project.addBuildListener(new AntTestListener(logLevel));
252: ProjectHelper.configureProject(project, antFile);
253: }
254:
255: /**
256: * Executes a target we have set up
257: *
258: * @pre configureProject has been called
259: * @param targetName target to run
260: */
261: public void executeTarget(String targetName) {
262: PrintStream sysOut = System.out;
263: PrintStream sysErr = System.err;
264: try {
265: sysOut.flush();
266: sysErr.flush();
267: outBuffer = new StringBuffer();
268: PrintStream out = new PrintStream(new AntOutputStream(
269: outBuffer));
270: System.setOut(out);
271: errBuffer = new StringBuffer();
272: PrintStream err = new PrintStream(new AntOutputStream(
273: errBuffer));
274: System.setErr(err);
275: logBuffer = new StringBuffer();
276: fullLogBuffer = new StringBuffer();
277: buildException = null;
278: project.executeTarget(targetName);
279: } finally {
280: System.setOut(sysOut);
281: System.setErr(sysErr);
282: }
283:
284: }
285:
286: /**
287: * Get the project which has been configured for a test.
288: *
289: * @return the Project instance for this test.
290: */
291: public Project getProject() {
292: return project;
293: }
294:
295: /**
296: * Gets the directory of the project.
297: *
298: * @return the base dir of the project
299: */
300: public File getProjectDir() {
301: return project.getBaseDir();
302: }
303:
304: /**
305: * Runs a target, wait for a build exception.
306: *
307: * @param target target to run
308: * @param cause information string to reader of report
309: * @param msg the message value of the build exception we are waiting
310: * for set to null for any build exception to be valid
311: */
312: public void expectSpecificBuildException(String target,
313: String cause, String msg) {
314: try {
315: executeTarget(target);
316: } catch (org.apache.tools.ant.BuildException ex) {
317: buildException = ex;
318: if ((null != msg) && (!ex.getMessage().equals(msg))) {
319: fail("Should throw BuildException because '" + cause
320: + "' with message '" + msg
321: + "' (actual message '" + ex.getMessage()
322: + "' instead)");
323: }
324: return;
325: }
326: fail("Should throw BuildException because: " + cause);
327: }
328:
329: /**
330: * run a target, expect an exception string
331: * containing the substring we look for (case sensitive match)
332: *
333: * @param target target to run
334: * @param cause information string to reader of report
335: * @param contains substring of the build exception to look for
336: */
337: public void expectBuildExceptionContaining(String target,
338: String cause, String contains) {
339: try {
340: executeTarget(target);
341: } catch (org.apache.tools.ant.BuildException ex) {
342: buildException = ex;
343: if ((null != contains)
344: && (ex.getMessage().indexOf(contains) == -1)) {
345: fail("Should throw BuildException because '" + cause
346: + "' with message containing '" + contains
347: + "' (actual message '" + ex.getMessage()
348: + "' instead)");
349: }
350: return;
351: }
352: fail("Should throw BuildException because: " + cause);
353: }
354:
355: /**
356: * call a target, verify property is as expected
357: *
358: * @param target build file target
359: * @param property property name
360: * @param value expected value
361: */
362: public void expectPropertySet(String target, String property,
363: String value) {
364: executeTarget(target);
365: assertPropertyEquals(property, value);
366: }
367:
368: /**
369: * assert that a property equals a value; comparison is case sensitive.
370: *
371: * @param property property name
372: * @param value expected value
373: */
374: public void assertPropertyEquals(String property, String value) {
375: String result = project.getProperty(property);
376: assertEquals("property " + property, value, result);
377: }
378:
379: /**
380: * assert that a property equals "true".
381: *
382: * @param property property name
383: */
384: public void assertPropertySet(String property) {
385: assertPropertyEquals(property, "true");
386: }
387:
388: /**
389: * assert that a property is null.
390: *
391: * @param property property name
392: */
393: public void assertPropertyUnset(String property) {
394: assertPropertyEquals(property, null);
395: }
396:
397: /**
398: * call a target, verify named property is "true".
399: *
400: * @param target build file target
401: * @param property property name
402: */
403: public void expectPropertySet(String target, String property) {
404: expectPropertySet(target, property, "true");
405: }
406:
407: /**
408: * Call a target, verify property is null.
409: *
410: * @param target build file target
411: * @param property property name
412: */
413: public void expectPropertyUnset(String target, String property) {
414: expectPropertySet(target, property, null);
415: }
416:
417: /**
418: * Retrieve a resource from the caller classloader to avoid
419: * assuming a vm working directory. The resource path must be
420: * relative to the package name or absolute from the root path.
421: *
422: * @param resource the resource to retrieve its url.
423: * @throws junit.framework.AssertionFailedError if the resource is not found.
424: */
425: public URL getResource(String resource) {
426: URL url = getClass().getResource(resource);
427: assertNotNull("Could not find resource :" + resource, url);
428: return url;
429: }
430:
431: /**
432: * an output stream which saves stuff to our buffer.
433: */
434: private static class AntOutputStream extends java.io.OutputStream {
435: private StringBuffer buffer;
436:
437: public AntOutputStream(StringBuffer buffer) {
438: this .buffer = buffer;
439: }
440:
441: public void write(int b) {
442: buffer.append((char) b);
443: }
444: }
445:
446: /**
447: * Our own personal build listener.
448: */
449: private class AntTestListener implements BuildListener {
450: private int logLevel;
451:
452: /**
453: * Constructs a test listener which will ignore log events
454: * above the given level.
455: */
456: public AntTestListener(int logLevel) {
457: this .logLevel = logLevel;
458: }
459:
460: /**
461: * Fired before any targets are started.
462: */
463: public void buildStarted(BuildEvent event) {
464: }
465:
466: /**
467: * Fired after the last target has finished. This event
468: * will still be thrown if an error occurred during the build.
469: *
470: * @see BuildEvent#getException()
471: */
472: public void buildFinished(BuildEvent event) {
473: }
474:
475: /**
476: * Fired when a target is started.
477: *
478: * @see BuildEvent#getTarget()
479: */
480: public void targetStarted(BuildEvent event) {
481: //System.out.println("targetStarted " + event.getTarget().getName());
482: }
483:
484: /**
485: * Fired when a target has finished. This event will
486: * still be thrown if an error occurred during the build.
487: *
488: * @see BuildEvent#getException()
489: */
490: public void targetFinished(BuildEvent event) {
491: //System.out.println("targetFinished " + event.getTarget().getName());
492: }
493:
494: /**
495: * Fired when a task is started.
496: *
497: * @see BuildEvent#getTask()
498: */
499: public void taskStarted(BuildEvent event) {
500: //System.out.println("taskStarted " + event.getTask().getTaskName());
501: }
502:
503: /**
504: * Fired when a task has finished. This event will still
505: * be throw if an error occurred during the build.
506: *
507: * @see BuildEvent#getException()
508: */
509: public void taskFinished(BuildEvent event) {
510: //System.out.println("taskFinished " + event.getTask().getTaskName());
511: }
512:
513: /**
514: * Fired whenever a message is logged.
515: *
516: * @see BuildEvent#getMessage()
517: * @see BuildEvent#getPriority()
518: */
519: public void messageLogged(BuildEvent event) {
520: if (event.getPriority() > logLevel) {
521: // ignore event
522: return;
523: }
524:
525: if (event.getPriority() == Project.MSG_INFO
526: || event.getPriority() == Project.MSG_WARN
527: || event.getPriority() == Project.MSG_ERR) {
528: logBuffer.append(event.getMessage());
529: }
530: fullLogBuffer.append(event.getMessage());
531: }
532: }
533:
534: }
|