1 | /* |
2 | * JTiger Unit Testing Framework for J2SE 1.5 |
3 | * Copyright (C) 2005 Tony Morris |
4 | * |
5 | * This software is licenced under the |
6 | * Common Public Licence version 1.0 |
7 | * http://www.opensource.org/licenses/cpl1.0.php |
8 | * |
9 | * You received a copy of this licence with this software. |
10 | */ |
11 | package org.jtiger.ant; |
12 | |
13 | import static org.jtiger.ant.FixtureResultsHandlerFactory.newFixtureResultsHandler; |
14 | import static org.jtiger.ant.BuildExceptionMessages.missingJavaElement; |
15 | import static org.jtiger.ant.BuildExceptionMessages.missingFixturesElement; |
16 | import static org.jtiger.ant.BuildExceptionMessages.missingFixturesClasses; |
17 | import static org.jtiger.ant.BuildExceptionMessages.missingClassnameAttributeFixtureElement; |
18 | import static org.jtiger.ant.BuildExceptionMessages.missingNameAttributeResultElement; |
19 | import static org.jtiger.ant.BuildExceptionMessages.missingRegexAttributeCategoryElement; |
20 | import static org.jtiger.ant.BuildExceptionMessages.badResultName; |
21 | |
22 | import static org.jtiger.ant.LogMessages.usingDefinitionClass; |
23 | import static org.jtiger.ant.LogMessages.usingSetUpTearDownClass; |
24 | import static org.jtiger.ant.LogMessages.usingJUnit; |
25 | import static org.jtiger.ant.LogMessages.haltOnFailure; |
26 | import static org.jtiger.ant.LogMessages.totalNumberOfCategories; |
27 | import static org.jtiger.ant.LogMessages.usingDefaultResultName; |
28 | import static org.jtiger.ant.LogMessages.usingResultName; |
29 | import static org.jtiger.ant.LogMessages.usingCategoryRegularExpression; |
30 | import static org.jtiger.ant.LogMessages.usingResultParams; |
31 | import static org.jtiger.ant.LogMessages.usingFixtureClasses; |
32 | |
33 | import static org.jtiger.framework.FixturesRunnerMain.ARG_FIXTURE_CLASSES; |
34 | import static org.jtiger.framework.FixturesRunnerMain.ARG_DEFINITION_CLASS; |
35 | import static org.jtiger.framework.FixturesRunnerMain.ARG_SUTD_CLASS; |
36 | import static org.jtiger.framework.FixturesRunnerMain.ARG_JUNIT; |
37 | import static org.jtiger.framework.FixturesRunnerMain.ARG_HALT_ON_FAILURE; |
38 | import static org.jtiger.framework.FixturesRunnerMain.ARG_CATEGORIES; |
39 | import static org.jtiger.framework.FixturesRunnerMain.ARG_RESULT; |
40 | import static org.jtiger.framework.FixturesRunnerMain.ARG_RESULT_PARAMETERS; |
41 | |
42 | import static org.apache.tools.ant.Project.MSG_VERBOSE; |
43 | |
44 | import java.util.LinkedList; |
45 | import java.util.List; |
46 | import org.apache.tools.ant.BuildException; |
47 | import org.apache.tools.ant.Task; |
48 | import org.jtiger.framework.FixturesRunnerMain; |
49 | |
50 | /** |
51 | * An <a href="%ant.url%/manual/using.html#tasks" target="_blank">Apache Ant task</a> for performing a test execution |
52 | * run from an Ant build. |
53 | * <br/> |
54 | * An example excerpt of an Ant build file that uses this task: |
55 | * <br/> |
56 | <pre> |
57 | <target name="test" description="Execute JTiger tests"> |
58 | <mkdir dir="test-report"/> |
59 | <taskdef name="jtiger" classname="org.jtiger.ant.JTigerTask" classpathref="project.class.path"/> |
60 | |
61 | <jtiger haltonfailure="true"> |
62 | <category regex="DatabaseTest"/> |
63 | <fixtures> |
64 | <fixture classname="com.foo.AdditionalTestFixture"/> |
65 | <fileset dir="test-src"> |
66 | <include name="**/*.java"/> |
67 | </fileset> |
68 | </fixtures> |
69 | <result name="~html"> |
70 | <param value="test-report"/> |
71 | </result> |
72 | <java> |
73 | <classpath refid="project.class.path"/> |
74 | </java> |
75 | </jtiger> |
76 | </target> |
77 | </pre> |
78 | * @see Category |
79 | * @see Fixture |
80 | * @see Fixtures |
81 | * @see Java |
82 | * @see Result |
83 | * @author %javadoc.author.tag% |
84 | * @version %version%<br/> |
85 | * <i>Build Number %build.number%</i><br/> |
86 | * <i>Build Time %build.time% CET (GMT + 1)</i> |
87 | */ |
88 | public final class JTigerTask extends Task |
89 | { |
90 | private Fixtures fixtures; |
91 | private String definitionClass; |
92 | private String sutdClass; |
93 | private final List<Category> categories; |
94 | private boolean haltOnFailure; |
95 | private boolean jUnit; |
96 | private Result result; |
97 | private Java j; |
98 | |
99 | /** |
100 | * Create a default <tt>JTigerTask</tt>. |
101 | */ |
102 | public JTigerTask() |
103 | { |
104 | categories = new LinkedList<Category>(); |
105 | } |
106 | |
107 | /** |
108 | * Creates a {@link Fixtures}. |
109 | * |
110 | * @return A new {@link Fixtures}. |
111 | */ |
112 | public Fixtures createFixtures() |
113 | { |
114 | final Fixtures fixtures = new Fixtures(); |
115 | this.fixtures = fixtures; |
116 | return fixtures; |
117 | } |
118 | |
119 | /** |
120 | * Sets the test definition class name for this task. |
121 | * @see org.jtiger.framework.FixturesRunnerConfig#getDefinitionClass() |
122 | * @see org.jtiger.framework.TestDefinition |
123 | * |
124 | * @param definitionClass The test definition class name for this task. |
125 | */ |
126 | public void setDefinitionClass(final String definitionClass) |
127 | { |
128 | this.definitionClass = definitionClass; |
129 | } |
130 | |
131 | /** |
132 | * Sets the set up/tear down class name for this task. |
133 | * @see org.jtiger.framework.FixturesRunnerConfig#getSutdClass() |
134 | * @see org.jtiger.framework.SetUpTearDown |
135 | * |
136 | * @param sutdClass The set up/tear down class name for this task. |
137 | */ |
138 | public void setSutdClass(final String sutdClass) |
139 | { |
140 | this.sutdClass = sutdClass; |
141 | } |
142 | |
143 | /** |
144 | * Creates a {@link Category}. |
145 | * |
146 | * @return A new {@link Category}. |
147 | */ |
148 | public Category createCategory() |
149 | { |
150 | final Category c = new Category(); |
151 | categories.add(c); |
152 | return c; |
153 | } |
154 | |
155 | /** |
156 | * Sets the halt on failure attribute for this task. |
157 | * @see org.jtiger.framework.FixturesRunnerConfig#isHaltOnFailure() |
158 | * |
159 | * @param haltOnFailure The halt on failure attribute for this task. |
160 | */ |
161 | public void setHaltOnFailure(final boolean haltOnFailure) |
162 | { |
163 | this.haltOnFailure = haltOnFailure; |
164 | } |
165 | |
166 | /** |
167 | * Sets the junit attribute for this task. |
168 | * Setting this value to <code>true</code> overrides any values set for {@link #setDefinitionClass(String)} and |
169 | * {@link #setSutdClass(String)}. |
170 | * Set this attribute to execute <a href="%junit.url%" target="_blank">JUnit</a> unit test cases. |
171 | * |
172 | * @param jUnit The junit attribute for this task. |
173 | */ |
174 | public void setJUnit(final boolean jUnit) |
175 | { |
176 | this.jUnit = jUnit; |
177 | } |
178 | |
179 | /** |
180 | * Creates a {@link Result}. |
181 | * |
182 | * @return A new {@link Result}. |
183 | */ |
184 | public Result createResult() |
185 | { |
186 | final Result r = new Result(); |
187 | result = r; |
188 | return r; |
189 | } |
190 | |
191 | /** |
192 | * Creates a {@link Java}. |
193 | * |
194 | * @return A new {@link Java}. |
195 | */ |
196 | public Java createJava() |
197 | { |
198 | final Java j = new Java(new org.apache.tools.ant.taskdefs.Java()); |
199 | |
200 | j.setProject(super.getProject()); |
201 | j.setClassname(FixturesRunnerMain.class.getName()); |
202 | j.setFork(true); |
203 | j.setOwningTarget(super.getOwningTarget()); |
204 | j.setLocation(super.getLocation()); |
205 | j.setTaskName(super.getTaskName()); |
206 | |
207 | this.j = j; |
208 | return j; |
209 | } |
210 | |
211 | /** |
212 | * Executes the Ant task by calling {@link Java#execute()} and passing the set arguments to |
213 | * {@link FixturesRunnerMain#main(String[])}. These parameters are set by specifying attributes and elements in the |
214 | * Ant build file. |
215 | * |
216 | * @throws BuildException |
217 | * <li>If the <java> element is not present in the Ant build file.</li> |
218 | * <li>If the <fixtures> element is not present in the Ant build file.</li> |
219 | * <li>If the <fixtures> element does not contain any classes from <fixture> or <fileset> |
220 | * subelements in the Ant build file.</li> |
221 | * <li>If a <fixture> element does not contain a <code>classname</code> attribute in the Ant build file.</li> |
222 | * <li>If a <category> element does not contain a <code>regex</code> attribute in the Ant build file.</li> |
223 | * <li>If a <result> element does not contain a <code>type</code> attribute in the Ant build file.</li> |
224 | * <li>If a <result> element does not contain a <code>destination</code> attribute in the Ant build file.</li> |
225 | * <li>If a <result> element contains a <code>destination</code> attribute that is an invalid value in the Ant |
226 | * build file.</li> |
227 | */ |
228 | public void execute() throws BuildException |
229 | { |
230 | if(j == null) |
231 | { |
232 | throw new BuildException(missingJavaElement()); |
233 | } |
234 | |
235 | if(fixtures == null) |
236 | { |
237 | throw new BuildException(missingFixturesElement()); |
238 | } |
239 | |
240 | final String[] fixtureClasses = fixtures.toStringArray(super.getProject()); |
241 | |
242 | if(fixtureClasses.length == 0) |
243 | { |
244 | throw new BuildException(missingFixturesClasses()); |
245 | } |
246 | |
247 | super.log(usingFixtureClasses(fixtureClasses), MSG_VERBOSE); |
248 | |
249 | for(Fixture f : fixtures.getFixtures()) |
250 | { |
251 | if(f.getClassname() == null || f.getClassname().length() == 0) |
252 | { |
253 | throw new BuildException(missingClassnameAttributeFixtureElement()); |
254 | } |
255 | } |
256 | |
257 | if(fixtures != null) |
258 | { |
259 | j.createArg().setValue(ARG_FIXTURE_CLASSES); |
260 | |
261 | for(String fixtureClass : fixtureClasses) |
262 | { |
263 | j.createArg().setValue(fixtureClass); |
264 | } |
265 | } |
266 | |
267 | if(definitionClass != null) |
268 | { |
269 | super.log(usingDefinitionClass(definitionClass), MSG_VERBOSE); |
270 | |
271 | j.createArg().setValue(ARG_DEFINITION_CLASS); |
272 | j.createArg().setValue(definitionClass); |
273 | } |
274 | |
275 | if(sutdClass != null) |
276 | { |
277 | super.log(usingSetUpTearDownClass(sutdClass), MSG_VERBOSE); |
278 | |
279 | j.createArg().setValue(ARG_SUTD_CLASS); |
280 | j.createArg().setValue(sutdClass); |
281 | } |
282 | |
283 | if(jUnit) |
284 | { |
285 | super.log(usingJUnit(), MSG_VERBOSE); |
286 | |
287 | j.createArg().setValue(ARG_JUNIT); |
288 | } |
289 | |
290 | if(haltOnFailure) |
291 | { |
292 | j.createArg().setValue(ARG_HALT_ON_FAILURE); |
293 | } |
294 | |
295 | super.log(haltOnFailure(haltOnFailure), MSG_VERBOSE); |
296 | |
297 | if(categories != null && categories.size() > 0) |
298 | { |
299 | j.createArg().setValue(ARG_CATEGORIES); |
300 | |
301 | for(Category category : categories) |
302 | { |
303 | final String regex = category.getRegex(); |
304 | |
305 | if(regex == null) |
306 | { |
307 | throw new BuildException(missingRegexAttributeCategoryElement()); |
308 | } |
309 | |
310 | super.log(usingCategoryRegularExpression(regex), MSG_VERBOSE); |
311 | |
312 | j.createArg().setValue(regex); |
313 | } |
314 | } |
315 | |
316 | super.log(totalNumberOfCategories(categories.size()), MSG_VERBOSE); |
317 | |
318 | if(result == null) |
319 | { |
320 | super.log(usingDefaultResultName(), MSG_VERBOSE); |
321 | } |
322 | else |
323 | { |
324 | final String name = result.getName(); |
325 | |
326 | if(name == null) |
327 | { |
328 | throw new BuildException(missingNameAttributeResultElement()); |
329 | } |
330 | |
331 | super.log(usingResultName(name), MSG_VERBOSE); |
332 | |
333 | final List<Param> params = result.getParams(); |
334 | |
335 | j.createArg().setValue(ARG_RESULT); |
336 | |
337 | try |
338 | { |
339 | final Class<?> c = newFixtureResultsHandler(name); |
340 | |
341 | if(c == null) |
342 | { |
343 | throw new BuildException(badResultName(name)); |
344 | } |
345 | |
346 | j.createArg().setValue(c.getName()); |
347 | } |
348 | catch(ClassNotFoundException e) |
349 | { |
350 | throw new BuildException(e.getMessage(), e); |
351 | } |
352 | |
353 | super.log(usingResultParams(params), MSG_VERBOSE); |
354 | |
355 | j.createArg().setValue(ARG_RESULT_PARAMETERS); |
356 | |
357 | for(Param p : params) |
358 | { |
359 | final String value = p.getValue(); |
360 | |
361 | if(value != null && value.length() > 0) |
362 | { |
363 | j.createArg().setValue(value); |
364 | } |
365 | } |
366 | } |
367 | |
368 | j.execute(); |
369 | } |
370 | } |