1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package net.sf.jameleon.result;
20
21 import net.sf.jameleon.XMLable;
22 import net.sf.jameleon.bean.FunctionalPoint;
23 import net.sf.jameleon.util.JameleonUtility;
24 import org.apache.commons.jelly.LocationAware;
25
26 import java.io.File;
27 import java.util.Calendar;
28
29 /***
30 * An abstract Test Result.
31 * Generic <code>toXML</code> and <codetoString</codetoString methods are provided
32 * for easy extension.
33 */
34 public abstract class JameleonTestResult implements XMLable, LocationAware {
35 /***
36 * The time it took to execute the entire test step
37 */
38 protected long executionTime;
39 /***
40 * Whether this result failed or not
41 */
42 protected boolean failed;
43 /***
44 * The tag that this result represents
45 */
46 protected FunctionalPoint tag;
47 /***
48 * The stack trace from the failure if one occured
49 */
50 protected Throwable error;
51 /***
52 * The file that contains the display of the error
53 */
54 protected File errorFile;
55 /***
56 * The parent results
57 */
58 protected HasChildResults parentResults;
59 /***
60 * Syntax for opening cdata value
61 */
62 public final static String S_CDATA = "<![CDATA[";
63 /***
64 * Syntax for closing cdata value
65 */
66 public final static String E_CDATA = "]]>";
67 protected int lineNumber = -1;
68 protected int columnNumber = -1;
69 protected String scriptFileName;
70 protected String elementTagName;
71 private Calendar dateTimeExecuted;
72
73 /***
74 * Default Constructor - Does nothing
75 */
76 public JameleonTestResult(){
77 dateTimeExecuted = Calendar.getInstance();
78 }
79
80 /***
81 * Constructor
82 * @param tag - the tag of the restults
83 */
84 public JameleonTestResult(FunctionalPoint tag){
85 this();
86 this.tag = tag;
87 }
88
89 /***
90 * Constructor
91 * @param tag - the tag of the restults
92 * @param parentResults - the results which are parents to this result
93 */
94 public JameleonTestResult(FunctionalPoint tag, HasChildResults parentResults){
95 this(tag);
96 this.parentResults = parentResults;
97 parentResults.addChildResult(this);
98 }
99
100 public void destroy(){
101 error = null;
102 errorFile = null;
103 failed = false;
104 }
105
106 /***
107 * @return the error that occured
108 */
109 public Throwable getError(){
110 return this.error;
111 }
112
113 /***
114 * Sets the error of the function point if one occured
115 * @param error - The error of the function point if one occured
116 */
117 public void setError(Throwable error){
118 setFailed();
119 this.error = error;
120 recordFailureToCountableResult();
121 }
122
123 public JameleonTestResult findAncestorByClass(Class clzz){
124 JameleonTestResult ancestorResult = null;
125 if (parentResults != null && clzz.isInstance(parentResults)) {
126 ancestorResult = (JameleonTestResult)parentResults;
127 }else if (parentResults != null){
128 ancestorResult = ((JameleonTestResult)parentResults).findAncestorByClass(clzz);
129 }
130 return ancestorResult;
131 }
132
133 public int getFailedRowNum(){
134 int rowNum = 0;
135 if (failed()){
136 DataDrivableRowResult ddr = (DataDrivableRowResult)findAncestorByClass(DataDrivableRowResult.class);
137 if (ddr != null){
138 rowNum = ddr.getRowNum();
139 }
140 }
141 return rowNum;
142 }
143
144
145 public void recordFailureToCountableResult(){
146 CountableResult countableRes = (CountableResult)findAncestorByClass(CountableResult.class);
147 if (countableRes != null) {
148 countableRes.countFailure();
149 }
150 }
151
152 /***
153 * @return the stack trace stating was happened
154 */
155 public String getErrorMsg(){
156 String msg = null;
157 if (error != null) {
158 msg = error.getMessage();
159 }
160 return msg;
161 }
162
163 /***
164 * @return the stack trace stating was happened
165 */
166 public String getHtmlFormattedErrorMsg(){
167 String em = "";
168 if (getErrorMsg() != null){
169 em = JameleonUtility.decodeTextToXML(getErrorMsg());
170 }
171 return em;
172 }
173
174 /***
175 * Gets the stack trace of the error formatted HTML-friendly
176 * @return an html formatted stack trace
177 */
178 public String getHtmlFormattedStackTrace() {
179 String stack = "";
180 if (getError() != null){
181 stack = JameleonUtility.getStack(getError());
182 stack = JameleonUtility.decodeTextToXML(stack);
183 }
184 return stack;
185 }
186
187
188 /***
189 * @return the time it took to run this step
190 */
191 public long getExecutionTime(){
192 return executionTime;
193 }
194
195 /***
196 * @return the time it took to run this step
197 */
198 public String getExecutionTimeToDisplay(){
199 return JameleonUtility.executionTimeToString(executionTime);
200 }
201
202 /***
203 * Set the execution time
204 * @param executionTime - The time it took to run this step
205 */
206 public void setExecutionTime(long executionTime){
207 this.executionTime = executionTime;
208 }
209
210 /***
211 * @return The file that contains the display of the error
212 */
213 public File getErrorFile(){
214 return errorFile;
215 }
216
217 /***
218 * Sets the file that contains the display of the error
219 * @param errorFile - The file that contains the display of the error
220 */
221 public void setErrorFile(File errorFile){
222 this.errorFile = errorFile;
223 }
224
225 public String getIdentifier(){
226 String id = null;
227 if (tag != null && tag.getFunctionId() != null) {
228 id = tag.getFunctionId();
229 }else if (tag != null) {
230 id = tag.getDefaultTagName();
231 }
232 return id;
233 }
234
235 public void setFailed(){
236 failed = true;
237 if (getParentResults() != null) {
238 getParentResults().addFailedResult(this);
239 }
240 }
241
242 public String getOutcome(){
243 String outcome;
244 if (passed()) {
245 outcome = "PASSED";
246 } else {
247 outcome = "FAILED";
248 }
249 return outcome;
250 }
251
252 /***
253 * Tells whether this result is a parent result or not.
254 * @return <code>true</code> if this result is a parent result or <code>false</code>
255 * if it is a leaf node result
256 */
257 public abstract boolean isParent();
258
259 /***
260 * Tells whether this result is data driven or not.
261 * @return <code>true</code> if this result is a data driven result or <code>false</code>
262 * if it is not.
263 */
264 public abstract boolean isDataDriven();
265
266 /***
267 * Tells whether this result has children or not.
268 * @return <code>true</code> if this result has children
269 */
270 public abstract boolean hasChildren();
271
272 /***
273 * Gets the parent results
274 *
275 * @return The parent result of this result
276 */
277 public HasChildResults getParentResults(){
278 return parentResults;
279 }
280
281 /***
282 * Sets the parent results
283 * @param parentResults - the parent results of this result
284 */
285 public void setParentResults(HasChildResults parentResults){
286 this.parentResults = parentResults;
287 }
288
289 /***
290 * Gets the tag that is tied to the results
291 * @return The tag that is tied to the results
292 */
293 public FunctionalPoint getTag(){
294 return tag;
295 }
296
297 /***
298 * Sets the tag that is tied to the results
299 * @param tag - The tag that the result is tried to
300 */
301 public void setTag(FunctionalPoint tag){
302 this.tag = tag;
303 }
304
305 /***
306 * @return true if no errors happened and no asserts failed and at least one asserts were executed
307 */
308 public boolean passed(){
309 return !failed;
310 }
311
312 /***
313 * @return true if any errors happened or any asserts failed
314 */
315 public boolean failed(){
316 return failed;
317 }
318
319
320
321
322 protected String escapeXML(String text) {
323 if (text == null) {
324 text = "<null>";
325 }
326 StringBuffer sb = new StringBuffer();
327 for (int i = 0; i < text.length(); i++) {
328 char ch = text.charAt(i);
329 if (ch == '<') {
330 sb.append("<");
331 } else if (ch == '>') {
332 sb.append(">");
333 } else if (ch == '&') {
334 sb.append("&");
335 } else {
336 sb.append(ch);
337 }
338 }
339 return sb.toString();
340 }
341
342 public boolean equals(Object obj){
343 boolean eqls = false;
344 if (obj instanceof JameleonTestResult) {
345 JameleonTestResult tcr = (JameleonTestResult) obj;
346 eqls = tcr.tag != null && tcr.tag.equals(tag);
347 eqls &= tcr.executionTime == executionTime;
348 }
349 return eqls;
350 }
351
352 public int hashCode(){
353 return super.hashCode();
354 }
355
356 public String toString(){
357 StringBuffer str = new StringBuffer();
358 str.append("Execution Time: ").append(JameleonUtility.executionTimeToString(executionTime)).append("\n");
359 if (tag != null) {
360 str.append("Tag: ").append(tag.getDefaultTagName()).append("\n");
361 }
362 str.append("Outcome: ");
363 String outcome = getOutcome();
364 str.append(outcome);
365 if (failed()) {
366 str.append("\n").append(getErrorMsg()).append("\n");
367 }
368 if (errorFile != null) {
369 str.append("Error File Name:").append(errorFile.getPath()).append("\n");
370 }
371 str.append("line: ").append(getLineNumber()).append(" column: ").append(getColumnNumber());
372 return str.toString();
373 }
374
375 public String toXML(){
376 StringBuffer str = new StringBuffer();
377 String outcome = getOutcome();
378 str.append("\t\t<outcome>").append(outcome).append("</outcome>\n");
379 str.append("\t\t<execution-time>").append(JameleonUtility.executionTimeToString(executionTime)).append("</execution-time>\n");
380 str.append("\t\t<execution-time-millis>").append(executionTime).append("</execution-time-millis>\n");
381 if (error != null && error.getMessage() != null) {
382 str.append("\t\t<error-message>").append(escapeXML(error.getMessage())).append("</error-message>\n");
383 str.append("\t\t<error-stack>").append(escapeXML(JameleonUtility.getStack(error))).append("\t\t</error-stack>\n");
384 }
385 if (errorFile != null) {
386 str.append("\t\t<error-file-name>").append(escapeXML(JameleonUtility.fixFileSeparators(errorFile.getPath()))).append("</error-file-name>\n");
387 }
388 if (tag != null) {
389 str.append(tag.toXML());
390 }
391 return str.toString();
392 }
393
394 public void copyLocationAwareProperties(LocationAware la){
395 setLineNumber(la.getLineNumber());
396 setColumnNumber(la.getColumnNumber());
397 setFileName(la.getFileName());
398 setElementName(la.getElementName());
399 }
400
401
402
403
404
405 /***
406 * @return the line number of the tag
407 */
408 public int getLineNumber(){
409 return lineNumber;
410 }
411
412 /***
413 * Sets the line number of the tag
414 */
415 public void setLineNumber(int lineNumber){
416 this.lineNumber = lineNumber;
417 }
418
419 /***
420 * @return the column number of the tag
421 */
422 public int getColumnNumber(){
423 return columnNumber;
424 }
425
426 /***
427 * Sets the column number of the tag
428 */
429 public void setColumnNumber(int columnNumber){
430 this.columnNumber = columnNumber;
431 }
432
433 /***
434 * @return the Jelly file which caused the problem
435 */
436 public String getFileName(){
437 return scriptFileName;
438 }
439
440 /***
441 * Sets the Jelly file which caused the problem
442 */
443 public void setFileName(String fileName){
444 this.scriptFileName = fileName;
445 }
446
447 /***
448 * @return the element name which caused the problem
449 */
450 public String getElementName(){
451 return elementTagName;
452 }
453
454 /***
455 * Gets the date and time this result was executed
456 * @return The date and time this result was executed
457 */
458 public Calendar getDateTimeExecuted() {
459 return dateTimeExecuted;
460 }
461
462 /***
463 * Sets the date and time this result was executed
464 * @param dateTimeExecuted The date and time this result was executed
465 */
466 public void setDateTimeExecuted(Calendar dateTimeExecuted) {
467 this.dateTimeExecuted = dateTimeExecuted;
468 }
469
470 /***
471 * Sets the element name which caused the problem
472 */
473 public void setElementName(String elementName){
474 this.elementTagName = elementName;
475 }
476
477 public boolean isA(String clss){
478 boolean isInstance = false;
479 try{
480 isInstance = Class.forName(clss).isInstance(this);
481 }catch(ClassNotFoundException cnfe){
482
483 }
484 return isInstance;
485 }
486 }