001: /* QuiltTask.java */
002:
003: package org.quilt.frontend.ant;
004:
005: import org.apache.tools.ant.BuildException;
006: import org.apache.tools.ant.Project;
007: import org.apache.tools.ant.Task;
008: import org.apache.tools.ant.taskdefs.optional.junit.Enumerations;
009: import org.apache.tools.ant.types.Commandline;
010: import org.apache.tools.ant.types.CommandlineJava;
011: import org.apache.tools.ant.types.Environment;
012: import org.apache.tools.ant.types.Path;
013:
014: import java.io.File;
015: import java.net.URL;
016: import java.util.Enumeration;
017: import java.util.Vector;
018:
019: import org.quilt.cl.QuiltClassLoader;
020: import org.quilt.framework.QuiltTest;
021: import org.quilt.reports.FmtSelector;
022: import org.quilt.cover.stmt.StmtRegistry;
023:
024: //import org.quilt.runner.*;
025:
026: /**
027: * Ant task for running Quilt and JUnit.
028: *
029: * <p>The Quilt Ant task is meant to be a plug-in replacement for
030: * the Ant JUnitTask. Whatever build.xml works with JUnitTask
031: * should behave identically with QuiltTask. The opposite is not
032: * true: using QuiltTask allows you to run coverage tests in
033: * addition to JUnit unit tests</p>
034: *
035: * <p>Parameter names / build file options are compatible with
036: * the build.xml options for JUnitTask as of Ant 1.5.3-1, so that
037: * if <junit> and </junit> are replaced with <quilt> and </quilt>
038: * respectively in the build.xml file, test behavior should be the same.</p>
039: *
040: * <p>Build file options either control the individual test and so
041: * are passed to Quilt and JUnit, or manage QuiltTask and the test
042: * process.</p>
043: *
044: * <p>Most test options will go through Quilt to JUnit.
045: * All are set by Ant set* methods, where the name for the method
046: * setting the variable 'var' is 'setVar'. That is, the first
047: * letter of the variable name is capitalized, then the modified
048: * name is appended to 'set'.</p>
049: *
050: * <p>Task control parameters are NOT passed through to Quilt or JUnit.
051: * These variables are modified by Ant add*, set*, and create* routines, where
052: * the names are determined as described above.</p>
053: *
054: * <p>QuiltTest options can be set at three levels. First, then can
055: * be set as attributes to the <quilt&gr; element. In this case,
056: * they are the defaults for all tests.</p>
057: *
058: * <p>Next, they can be set at the <batchtest> leve.. In this case,
059: * these attributes will be used for all files in the batch test.</p>
060: *
061: * <p>Finally, they can be set at the <test> level, in which case
062: * they will override the defaults set higher up.</p>
063: *
064: * <p>QuiltTask collects filesets from batch test elements and the
065: * names of individual tests. These are then passed to a Scheduler
066: * which unpacks the batch tests and schedules all tests for running.</p>
067: *
068: * <p>It may be important to understand that under certain circumstances
069: * batches of tests will be run more than once result. This will normally
070: * be the result of an error in the way that dependencies are structured
071: * in build.xml. </p>
072: *
073: * @see QuiltTest
074: * @see Scheduler
075: * @see TaskControl
076: */
077: public class QuiltTask extends Task {
078: private Scheduler sch = null;
079: private TaskControl tc = null;
080:
081: // // THESE DUPLICATE ELEMENTS OF TaskControl //////////////////
082: // // XXX and this apparently isn't set -- leading to bugs
083: // private CommandlineJava commandline = new CommandlineJava();
084:
085: // DO THESE BELONG IN TaskControl ?
086: private boolean includeAntRuntime = true;
087: private Path antRuntimeClasses = null;
088:
089: // COLLECT ANT PARAMETERS USING ADD/CREATE/SET //////////////////
090: // Please keep in order by variable name ////////////////////////
091:
092: // TEST PARAMETERS //////////////////////////////////////////////
093: // Ant creates child elements (individual tests and BatchTests),
094: // then assigns values to task attributes, and THEN assigns
095: // values to child element attributes. This means that the
096: // default values assigned at the task level can be overridden
097: // by test and batch level assignments, IF the task-level values
098: // are applied immediately to all tests and batch tests.
099: //
100: // The methods that follow assign such task-level defaults. It
101: // is important to bear in mind that Ant uses methods of the same
102: // name and call QuiltTask to assign defaults and to call
103: // QuiltTest and BatchTest to override these defaults.
104: // //////////////////////////////////////////////////////////////
105: private QuiltTest qt // scratch variable
106: = new QuiltTest(); // to keep the compiler quiet
107:
108: public void setCheckCoverage(boolean b) {
109: sch.schedule();
110: while ((qt = sch.nextTest()) != null) {
111: qt.setCheckCoverage(b);
112: }
113: }
114:
115: public void setCheckExcludes(String s) {
116: sch.schedule();
117: while ((qt = sch.nextTest()) != null) {
118: qt.setCheckExcludes(s);
119: }
120: }
121:
122: public void setCheckIncludes(String s) {
123: sch.schedule();
124: while ((qt = sch.nextTest()) != null) {
125: qt.setCheckIncludes(s);
126: }
127: }
128:
129: public void setErrorProperty(String propertyName) {
130: sch.schedule();
131: while ((qt = sch.nextTest()) != null) {
132: qt.setErrorProperty(propertyName);
133: }
134: }
135:
136: public void setFailureProperty(String propertyName) {
137: sch.schedule();
138: while ((qt = sch.nextTest()) != null) {
139: qt.setFailureProperty(propertyName);
140: }
141: }
142:
143: public void setFiltertrace(boolean b) {
144: sch.schedule();
145: while ((qt = sch.nextTest()) != null) {
146: qt.setFiltertrace(b);
147: }
148: }
149:
150: public void setFork(boolean b) {
151: sch.schedule();
152: while ((qt = sch.nextTest()) != null) {
153: qt.setFork(b);
154: }
155: }
156:
157: public void setHaltOnError(boolean b) {
158: sch.schedule();
159: while ((qt = sch.nextTest()) != null) {
160: qt.setHaltOnError(b);
161: }
162: }
163:
164: public void setHaltOnFailure(boolean b) {
165: sch.schedule();
166: while ((qt = sch.nextTest()) != null) {
167: qt.setHaltOnFailure(b);
168: }
169: }
170:
171: public void setMockTestRun(boolean b) {
172: sch.schedule();
173: while ((qt = sch.nextTest()) != null) {
174: qt.setMockTestRun(b);
175: }
176: }
177:
178: public void setShowOutput(boolean b) {
179: tc.setShowOutput(b); // NEEDS FIXING
180: sch.schedule();
181: while ((qt = sch.nextTest()) != null) {
182: qt.setShowOutput(b);
183: }
184: }
185:
186: // TASK PARAMETERS //////////////////////////////////////////////
187: // //////////////////////////////////////////////////////////////
188:
189: public BatchTest createBatchTest() {
190: BatchTest bt = new BatchTest(getProject());
191: sch.addBatchTest(bt);
192: return bt; // returns to Ant a reference to the object created
193: }
194:
195: public Path createClasspath() {
196: // commandline.createClasspath(getProject()).createPath(); // XXX
197: return tc.createClasspath();
198: }
199:
200: public void setDir(File dir) {
201: tc.setDir(dir);
202: }
203:
204: public void addEnv(Environment.Variable var) {
205: tc.addEnv(var);
206: }
207:
208: public void addFormatter(FmtSelector fe) {
209: tc.addFormatter(fe);
210: }
211:
212: public void setIncludeAntRuntime(boolean b) {
213: tc.setIncludeAntRuntime(b);
214: }
215:
216: public void setJvm(String value) {
217: tc.setJvm(value);
218: }
219:
220: public Commandline.Argument createJvmarg() {
221: return tc.createJvmarg();
222: }
223:
224: public void setMaxmemory(String max) {
225: tc.setMaxmemory(max);
226: }
227:
228: public void setMockExec(boolean b) {
229: tc.setMockExec(b);
230: }
231:
232: public void setNewenvironment(boolean b) {
233: tc.setNewEnvironment(b);
234: }
235:
236: // compatible with JUnitTask but kludgey
237: public void setPrintsummary(String sValue) {
238: SummaryAttribute sa = new SummaryAttribute(sValue);
239: tc.setSummary(sa.asBoolean());
240: tc.setSummaryValue(sa.getValue());
241: }
242:
243: public void addSysproperty(Environment.Variable sysp) {
244: tc.addSysproperty(sysp);
245: }
246:
247: public void addTest(QuiltTest qt) {
248: sch.addTest(qt);
249: }
250:
251: public void setTimeout(Long t) {
252: tc.setTimeout(t);
253: }
254:
255: // CONSTRUCTOR //////////////////////////////////////////////////
256: public QuiltTask() throws Exception {
257: sch = new Scheduler(this );
258: tc = sch.getTaskControl();
259: }
260:
261: private MockExec mockE = null;
262: private TestExec testE = null;
263: private boolean mockery = false;
264:
265: private boolean firstTimeThrough = true;
266:
267: private void addCPEs() {
268: mockery = tc.getMockExec();
269: if (mockery) {
270: mockE = new MockExec();
271: } else {
272: testE = new TestExec();
273: }
274: addClasspathEntry("/junit/framework/TestCase.class");
275: addClasspathEntry("/org/apache/tools/ant/Task.class");
276: addClasspathEntry("/org/quilt/runner/BaseTestRunner.class");
277: }
278:
279: // FIRST ANT ENTRY POINT: init() ////////////////////////////////
280: // only called once /////////////////////////////////////////////
281: public void init() {
282: antRuntimeClasses = new Path(getProject());
283: }
284:
285: // SECOND ANT ENTRY POINT: execute () ///////////////////////////
286: // May be called many times /////////////////////////////////////
287: public void execute() throws BuildException {
288: if (firstTimeThrough) {
289: firstTimeThrough = false;
290: addCPEs();
291: sch.unbatch(); // merge batch tests with other tests
292: }
293: sch.schedule();
294:
295: Path quiltClassPath = tc.getCommandline().getClasspath();
296: if (tc.getIncludeAntRuntime()) {
297: quiltClassPath.append(tc.getAntRuntimeClasses());
298: }
299: QuiltClassLoader qcl = new QuiltClassLoader(
300: QuiltClassLoader.cpToURLs(tc.getCommandline()
301: .getClasspath().toString()), this .getClass()
302: .getClassLoader(), // we delegate to ..
303: // delegated included excluded
304: (String[]) null, (String[]) null, (String[]) null);
305: StmtRegistry stmtReg = (StmtRegistry) qcl
306: .addQuiltRegistry("org.quilt.cover.stmt.StmtRegistry");
307: if (stmtReg == null) {
308: System.out
309: .println("QuiltTask.execute: org.quilt.cover.stmt.StmtRegistry not found\n"
310: + " classpath error?");
311: }
312: tc.setLoader(qcl);
313: while ((qt = sch.nextTest()) != null) {
314: if (tc.getMockExec()) {
315: mockE.run(qt, tc);
316: } else if (qt.runMe(getProject())) {
317: testE.execute(qt, tc);
318: }
319: }
320: if (stmtReg != null) {
321: System.out.println(stmtReg.getReport());
322: }
323: // DEBUG
324: else
325: System.out
326: .println("QuiltTask.execute: after running tests, stmtReg is null");
327: // END
328: }
329:
330: // //////////////////////////////////////////////////////////////
331: // CLEAN ME UP. This code is per JUnit task, needs work.
332: // //////////////////////////////////////////////////////////////
333:
334: protected void addClasspathEntry(String resource) {
335: URL url = getClass().getResource(resource);
336: if (url != null) {
337: String u = url.toString();
338: if (u.startsWith("jar:file:")) {
339: int pling = u.indexOf("!"); // Ant standard term
340: String jarName = u.substring(9, pling);
341: log("Found " + jarName, Project.MSG_DEBUG);
342: antRuntimeClasses.createPath()
343: .setLocation(
344: new File((new File(jarName))
345: .getAbsolutePath()));
346: } else if (u.startsWith("file:")) {
347: int tail = u.indexOf(resource);
348: String dirName = u.substring(5, tail);
349: log("Found " + dirName, Project.MSG_DEBUG);
350: antRuntimeClasses.createPath()
351: .setLocation(
352: new File((new File(dirName))
353: .getAbsolutePath()));
354: } else {
355: log("Don\'t know how to handle resource URL " + u,
356: Project.MSG_DEBUG);
357: }
358: } else {
359: log("Couldn\'t find " + resource, Project.MSG_DEBUG);
360: }
361: }
362:
363: // TASK CONTROL SUPPORT //////////////////////////////////////////
364: public void handleTheOutput(String line) {
365: super .handleOutput(line);
366: }
367:
368: public void handleTheFlush(String line) {
369: super .handleFlush(line);
370: }
371:
372: public void handleTheErrorOutput(String line) {
373: super .handleErrorOutput(line);
374: }
375:
376: public void handleTheErrorFlush(String line) {
377: super.handleErrorFlush(line);
378: }
379: }
|