View Javadoc

1   /*
2       Jameleon - An automation testing tool..
3       Copyright (C) 2003-2007 Christian W. Hargraves (engrean@hotmail.com)
4       
5       This library is free software; you can redistribute it and/or
6       modify it under the terms of the GNU Lesser General Public
7       License as published by the Free Software Foundation; either
8       version 2.1 of the License, or (at your option) any later version.
9   
10      This library is distributed in the hope that it will be useful,
11      but WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13      Lesser General Public License for more details.
14  
15      You should have received a copy of the GNU Lesser General Public
16      License along with this library; if not, write to the Free Software
17      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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     // Append to the given StringBuffer an escaped version of the
320     // given text string where XML special characters have been escaped
321     // For a null string we appebd "<null>"
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("&lt;");
331             } else if (ch == '>') {
332                 sb.append("&gt;");
333             } else if (ch == '&') {
334                 sb.append("&amp;");
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     //          LocationAware implementation                                  //
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     		//I guess this means false
483     	}
484     	return isInstance;
485     }
486 }