source: release-kits/wirk3/ant-scripts/tasks/antelope/src/ise/antelope/tasks/TestCase.java@ 15023

Last change on this file since 15023 was 15023, checked in by oranfry, 16 years ago

did the bulk of the work on wirk3

File size: 14.1 KB
Line 
1package ise.antelope.tasks;
2
3import java.io.*;
4import java.util.*;
5
6import org.apache.tools.ant.*;
7
8import ise.library.ascii.MessageBox;
9
10/**
11 * Modeled after the TestCase provided by jUnit, this class is an Ant task that
12 * looks through the build file set in the <code>setFile</code> method, calls a
13 * 'setUp' target in that build file (if it exists), then all targets whose
14 * names start with 'test', and last calls a target named 'tearDown' (if it
15 * exists). Both 'setUp' and 'tearDown' are optional targets in the build file.
16 * <p>
17 *
18 * Ant stores targets in a hashtable, so there is no guaranteed order in which
19 * the 'test*' classes will be called. If order is important, use the 'depends'
20 * attribue of a target to enforce order, and do not name dependent targets with
21 * a name starting with 'test'. <p>
22 *
23 * Test targets may also be imported with the import task. Imported files should
24 * not have a "suite" task in the implicit target as such a task would rerun all
25 * test targets in all files.
26 *
27 * @author Dale Anson
28 * @version $Revision: 1.3 $
29 */
30public class TestCase extends Task implements TestStatisticAccumulator {
31
32 private boolean enabled = true;
33 private boolean assertEnabled = true;
34 private Target setUp = null;
35 private Target tearDown = null;
36 private Vector testTargets = new Vector();
37 private Vector failures = new Vector();
38 private boolean failOnError = false;
39 private boolean showSummary = true;
40 private boolean showOutput = true;
41 private File testFile = null;
42 private String test_name = "";
43
44 private int tests_passed = 0;
45 private int tests_failed = 0;
46 private int tests_warning = 0;
47
48 /** task initilization */
49 public void init() {
50 super.init();
51 setTaskName("testcase");
52 }
53
54 /**
55 * @return the count of test targets.
56 */
57 public int getTestCaseCount() {
58 return testTargets.size();
59 }
60
61 /**
62 * @return the number of tests targets actually executed.
63 */
64 public int getRanCount() {
65 return tests_passed + tests_warning + tests_failed;
66 }
67
68 /**
69 * @return the number of tests that failed.
70 */
71 public int getFailedCount() {
72 return tests_failed;
73 }
74
75 public int getWarningCount() {
76 return tests_warning;
77 }
78
79 /**
80 * @return the number of tests that passed.
81 */
82 public int getPassedCount() {
83 return tests_passed;
84 }
85
86 /**
87 * @return an Enumeration of the failures. Individual elements are Strings
88 * containing the name of the failed target and the reason why it
89 * failed.
90 */
91 public Enumeration getFailures() {
92 return failures.elements();
93 }
94
95 /**
96 * @param b if true, show the output of the tests as they run. Optional,
97 * default is true, do show output.
98 */
99 public void setShowoutput(boolean b) {
100 showOutput = b;
101 }
102
103 /**
104 * @param b if true, show the summary output (number of tests, passed,
105 * failed) after the completion of all tests. Optional, default is
106 * true, do show summary.
107 */
108 public void setShowsummary(boolean b) {
109 showSummary = b;
110 }
111
112 /**
113 * @param f the file containing the tests to execute. Required. The file
114 * itself is a standard Ant build file, but will be treated differently
115 * than if Ant itself ran it. If there is a target named "setUp", that
116 * target will be executed first, then all targets with names starting
117 * with "test" (not in any particular order), then if there is a target
118 * named "tearDown", that target will be executed last. All other
119 * targets are ignored.
120 */
121 public void setFile(File f) {
122 testFile = f;
123 }
124
125 /**
126 * Should Asserts be enabled? Many (most?) tests will use the Assert task,
127 * which requires a property to be set to actually enable the asserts. By
128 * default, Asserts are enabled for testcases.
129 *
130 * @param b if false, do not enable asserts. Note that this sets an Ant
131 * property, and due to property immutability, this attribute may have
132 * no effect if it has been set already. Generally, asserts are enabled
133 * or disabled for an entire build.
134 */
135 public void setAssertsenabled(boolean b) {
136 assertEnabled = b;
137 }
138
139 /**
140 * Should the build fail if the test fails? By default, a failed test does
141 * not cause the build to fail, so all tests may have the opportunity to
142 * run.
143 *
144 * @param b set to true to cause the build to fail if the test fails
145 */
146 public void setFailonerror(boolean b) {
147 failOnError = b;
148 }
149
150 /**
151 * @return the name of the test as set by <code>setName</code>. If the
152 * name has not be explicitly set, then the test name is the project
153 * name if there is one, otherwise, the filename of the test file.
154 */
155 public String getName() {
156 return test_name;
157 }
158
159 /**
160 * Set the name for this testcase.
161 *
162 * @param n the name for the testcase
163 */
164 public void setName(String n) {
165 test_name = n;
166 }
167
168 /**
169 * @param b if true, execute the test. This is handy for enabling or
170 * disabling groups of tests in a 'suite' by setting a single property.
171 * Optional, default is true, the test should run.
172 */
173 public void setEnabled(boolean b) {
174 enabled = b;
175 }
176
177 /** Run tests. */
178 public void execute() {
179
180 /*
181 Hashtable parent_targets = getProject().getTargets();
182
183 for (Iterator it = parent_targets.keySet().iterator(); it.hasNext(); ) {
184 log(it.next());
185 }
186 */
187
188 if (!enabled)
189 return;
190
191 // check the test file
192 if (testFile == null)
193 throw ProjectHelper.addLocationToBuildException(new BuildException("missing file for testcase"), getLocation());
194 if (!testFile.exists())
195 throw ProjectHelper.addLocationToBuildException(new BuildException("file not found for testcase: " + testFile), getLocation());
196
197 // make sure asserts are enabled
198 String ae = assertEnabled ? "true" : "false";
199 if (assertEnabled)
200 getProject().setProperty("ant.enable.asserts", ae);
201
202 // create a new project, similar to the "ant" task, but not nearly as involved.
203 // All properties will be copied from the parent project to the subproject, and
204 // any properties set during execution of the subproject will be copied back to
205 // the parent project.
206 Project myProject = new Project();
207 initializeProject(myProject);
208 try {
209 ProjectHelper.configureProject(myProject, testFile);
210 }
211 catch (BuildException be) {
212 throw ProjectHelper.addLocationToBuildException(be, getLocation());
213 }
214
215 // set the test name, use a name that was set as an attribute first,
216 // otherwise, use the project name, and if all else fails, use the name
217 // of the test file
218 if (test_name == null || test_name.equals(""))
219 test_name = myProject.getName();
220 if (test_name == null || test_name.equals(""))
221 test_name = testFile.getName();
222
223 if (showOutput) {
224 // output start of test
225 log(MessageBox.box("Starting test: " + test_name));
226 }
227
228 // get the setUp, tearDown, and test targets
229 Hashtable targets = myProject.getTargets();
230 Enumeration en = targets.keys();
231 while (en.hasMoreElements()) {
232 String target = (String) en.nextElement();
233 if (target.equals("setUp"))
234 setUp = (Target) targets.get(target);
235 else if (target.equals("tearDown"))
236 tearDown = (Target) targets.get(target);
237 else if (target.startsWith("test"))
238 testTargets.addElement(targets.get(target));
239 // also check for imported targets. Imported targets are named like
240 // projectname.targetname, so check for whatever follows the last dot.
241 // This is somewhat naive, as there is no restriction using dots in
242 // target names, so a target named "build.testimonials" would be treated
243 // as a test target.
244 else if (target.lastIndexOf(".") > 0 && target.substring(target.lastIndexOf(".") + 1).startsWith("test")) {
245 testTargets.addElement(targets.get(target));
246 }
247 }
248
249 // run the setUp target
250 if (setUp != null)
251 setUp.execute();
252
253 // run the test targets
254 StringBuffer messages = new StringBuffer();
255 en = testTargets.elements();
256 while (en.hasMoreElements()) {
257 Target target = (Target) en.nextElement();
258 try {
259 myProject.executeTarget(target.getName());
260 if (showOutput)
261 log(target.getName() + " passed.");
262 ++tests_passed;
263 }
264 catch (Exception e) {
265 String error = "ERROR: ";
266 if (e instanceof AssertException) {
267 int level = ((AssertException)e).getLevel();
268 if (level == AssertException.ERROR)
269 ++ tests_failed;
270 else if (level == AssertException.WARN) {
271 ++ tests_warning;
272 error = "WARNING: ";
273 }
274 else {
275 // info or debug level
276 if (showOutput)
277 log(target.getName() + ": " + e.getMessage());
278 continue;
279 }
280 }
281 else
282 ++tests_failed;
283 if (showOutput)
284 log(error + target.getName() + " failed: " + e.getMessage());
285 failures.addElement(error + test_name + ": " + target.getName() + " failed: " + e.getMessage());
286 if (failOnError)
287 throw new BuildException(e.getMessage());
288 }
289 }
290
291 // run the tearDown target
292 if (tearDown != null)
293 tearDown.execute();
294
295 // copy any new properties to parent project
296 addAlmostAll(getProject(), myProject.getProperties());
297 /*
298 Hashtable props = myProject.getProperties();
299 for (en = props.keys(); en.hasMoreElements(); ) {
300 String key = (String)en.nextElement();
301 String value = (String)props.get(key);
302 if (value != null)
303 getProject().setNewProperty(key, value);
304 }
305 */
306 // print any error messages
307 if (showSummary) {
308 log(getSummary());
309 }
310 }
311
312 /**
313 * Gets the summary attribute of the TestCase object
314 *
315 * @return The summary value
316 */
317 public String getSummary() {
318 String title = (test_name == null ? "Test" : test_name) + " Results";
319 StringBuffer msg = new StringBuffer();
320 String ls = System.getProperty("line.separator");
321 // log the failures
322 if (failures.size() > 0) {
323 String error_title = "Errors";
324 StringBuffer error_msg = new StringBuffer();
325 Enumeration en = failures.elements();
326 while (en.hasMoreElements()) {
327 error_msg.append((String) en.nextElement()).append(ls);
328 }
329 int box_width = MessageBox.getMaxWidth();
330 MessageBox.setMaxWidth(box_width - 8);
331 msg.append(MessageBox.box(error_title, error_msg));
332 MessageBox.setMaxWidth(box_width);
333 msg.append(ls);
334 }
335
336 // log the test count info
337 msg.append("Ran: ").append(getRanCount()).append(" out of ").append(getTestCaseCount()).append(" tests.").append(ls);
338 msg.append("Passed: ").append(getPassedCount()).append(ls);
339 msg.append("Warning: ").append(getWarningCount()).append(ls);
340 msg.append("Failed: ").append(getFailedCount()).append(ls);
341 return MessageBox.box(title, msg);
342 }
343
344 /**
345 * Attaches the build listeners of the current project to the new project,
346 * configures a possible logfile, transfers task and data-type definitions,
347 * transfers properties (either all or just the ones specified as user
348 * properties to the current project, depending on inheritall), transfers
349 * the input handler.
350 *
351 * @param newProject
352 */
353 private void initializeProject(Project newProject) {
354 newProject.setBaseDir(getProject().getBaseDir());
355 newProject.setInputHandler(getProject().getInputHandler());
356
357 Iterator iter = getProject().getBuildListeners().iterator();
358 while (iter.hasNext()) {
359 newProject.addBuildListener((BuildListener) iter.next());
360 }
361
362 getProject().initSubProject(newProject);
363
364 // copy properties
365 /// are these necessary? Does addAlmostAll cover these properties?
366 getProject().copyInheritedProperties(newProject);
367 getProject().copyUserProperties(newProject);
368
369 // set all properties from calling project
370 addAlmostAll(newProject, getProject().getProperties());
371
372 }
373
374 /**
375 * Copies all properties from the given table to the given project -
376 * omitting those that have already been set in the project as well as
377 * properties named basedir or ant.file.
378 *
379 * @param props properties to copy to the project
380 * @param project The feature to be added to the AlmostAll attribute
381 */
382 private void addAlmostAll(Project project, Hashtable props) {
383 Enumeration e = props.keys();
384 while (e.hasMoreElements()) {
385 String key = e.nextElement().toString();
386 if ("basedir".equals(key) || "ant.file".equals(key)) {
387 // basedir and ant.file get special treatment in execute()
388 continue;
389 }
390
391 String value = props.get(key).toString();
392 // don't re-set user properties, avoid the warning message
393 if (project.getProperty(key) == null) {
394 // no user property
395 project.setNewProperty(key, value);
396 }
397 }
398 }
399
400}
401
Note: See TracBrowser for help on using the repository browser.