View Javadoc

1   /*
2       Jameleon - An automation testing tool..
3       Copyright (C) 2005-2006 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.ui;
20  
21  import net.sf.jameleon.LocationAwareTagSupport;
22  import net.sf.jameleon.TestCaseTag;
23  import net.sf.jameleon.data.DataDrivable;
24  import net.sf.jameleon.event.*;
25  import net.sf.jameleon.function.FunctionTag;
26  import net.sf.jameleon.result.DataDrivableRowResult;
27  import net.sf.jameleon.result.FunctionResult;
28  import net.sf.jameleon.result.JameleonTestResult;
29  import net.sf.jameleon.result.TestCaseResult;
30  import net.sf.jameleon.util.JameleonUtility;
31  import org.apache.commons.jelly.LocationAware;
32  
33  import javax.swing.*;
34  import javax.swing.event.ListSelectionEvent;
35  import javax.swing.event.ListSelectionListener;
36  import javax.swing.table.DefaultTableModel;
37  import javax.swing.text.BadLocationException;
38  import java.awt.*;
39  import java.awt.event.MouseAdapter;
40  import java.awt.event.MouseEvent;
41  import java.io.File;
42  import java.net.URI;
43  import java.net.URL;
44  import java.text.NumberFormat;
45  import java.util.*;
46  import java.util.List;
47  
48  public class TestCaseResultsPane extends JSplitPane implements TestCaseListener,
49                                                                  FunctionListener,
50                                                                  DataDrivableListener{
51  	private static final long serialVersionUID = 1L;
52      protected DefaultTableModel tcModel, tcReasonModel;
53      protected JTable tcTable, tcReasonTable;
54      protected Map testCases = new HashMap();
55      private static final int TC_NUM = 0;
56      private static final int STATUS = 1;
57      private static final int TEST_CASE = 2;
58      private static final int EXEC_TIME = 3;
59      private static final int RUN = 4;
60      private static final int FAIL = 5;
61      private static final int PASS = 6;
62      private static final int TC = 7;
63      protected ImageIcon passedImg, failedImg, runningImg, snapShotImg;
64      private List results = new ArrayList();
65      private JTextArea stackTrace = new JTextArea();
66      private TestCaseTree tcTree;
67      private JTextArea sourceArea;
68      private JFrame rootFrame;
69      private boolean stepNextTag;
70      private boolean debug;
71      private boolean stopExecution;
72      private BasicHtmlBrowser snapShotBrowser = new BasicHtmlBrowser("Snapshot of Error");
73  
74      public TestCaseResultsPane(JFrame rootFrame) {
75          super(JSplitPane.VERTICAL_SPLIT);
76          this.rootFrame = rootFrame;
77          setResizeWeight(0.5);
78          setDividerSize(4);
79          initResultsTable();
80          initIcons();
81      }
82  
83      protected void setSourceArea(JTextArea sourceArea){
84          this.sourceArea = sourceArea;
85      }
86  
87      protected void setTestCaseTree(TestCaseTree tcTree){
88          this.tcTree = tcTree;
89      }
90  
91      private void initIcons() {
92          passedImg = createImageIcon("/icons/passed.gif", "Test Passed");
93          failedImg = createImageIcon("/icons/failed.gif", "Test Failed");
94          runningImg = createImageIcon("/icons/running.gif", "Test Running");
95          snapShotImg = createImageIcon("/icons/snapShot.gif", "View Snapshot of Application at Failure Time");
96      }
97  
98      public void stopExecution(){
99          this.stopExecution = true;
100     }
101 
102     public void proceedExecution(){
103         this.stopExecution = false;
104     }
105 
106     public void setDebug(boolean debug){
107         this.debug = debug;
108     }
109 
110     protected void setStepNextTag(boolean stepNextTag){
111         this.stepNextTag = stepNextTag;
112     }
113     
114     private String convertObjectToToolTip(Object obj){
115     	String tip = null;
116     	if (obj != null){
117             if (obj instanceof ImageIcon) { //Status column
118                 tip = ((ImageIcon)obj).getDescription();
119             } else {
120                 tip = obj.toString();
121             }
122         }
123         return tip;
124    	
125     }
126 
127     private void initResultsTable() {
128         tcModel = new DefaultTableModel(new Object[]{"#","Status","Test Case","Execution Time"," Run","Fail","Pass","."},0) {
129             public Class getColumnClass(int columnIndex) {
130                 Class dataType = super.getColumnClass(columnIndex);
131                 if (columnIndex == STATUS) {
132                     dataType = Icon.class;
133                 }
134                 return dataType;
135             }
136         };
137         tcTable = new SortableJTable(new TableSorter(tcModel)) {
138             public String getToolTipText(MouseEvent e) {
139                 Point p = e.getPoint();
140                 int rowIndex = rowAtPoint(p);
141                 int colIndex = columnAtPoint(p);
142                 return convertObjectToToolTip(getValueAt(rowIndex, colIndex));
143             }
144 
145         };
146         tcTable.setColumnSelectionAllowed(false);
147         tcTable.getColumnModel().getColumn(TEST_CASE).setPreferredWidth(200);
148         tcTable.getColumnModel().getColumn(STATUS).setPreferredWidth(40);
149         tcTable.getColumnModel().getColumn(STATUS).setMaxWidth(40);
150         tcTable.getColumnModel().getColumn(TC_NUM).setPreferredWidth(30);
151         tcTable.getColumnModel().getColumn(TC_NUM).setMaxWidth(30);
152         tcTable.getColumnModel().getColumn(RUN).setPreferredWidth(30);
153         tcTable.getColumnModel().getColumn(RUN).setMaxWidth(30);
154         tcTable.getColumnModel().getColumn(FAIL).setPreferredWidth(30);
155         tcTable.getColumnModel().getColumn(FAIL).setMaxWidth(30);
156         tcTable.getColumnModel().getColumn(PASS).setPreferredWidth(40);
157         tcTable.getColumnModel().getColumn(PASS).setMaxWidth(40);
158         tcTable.getColumnModel().getColumn(EXEC_TIME).setPreferredWidth(100);
159         tcTable.getColumnModel().getColumn(EXEC_TIME).setMaxWidth(100);
160         tcTable.getColumnModel().getColumn(TC).setPreferredWidth(0);
161         tcTable.getColumnModel().getColumn(TC).setMaxWidth(0);
162         tcTable.getSelectionModel().addListSelectionListener(new TCResultsSelectionListeners());
163         tcTable.addMouseListener(new TCResultsMouseListener());
164 
165 
166         tcReasonModel = new DefaultTableModel(new Object[]{"Row", "Line", " ", "Function Id", "Failed Reason","."},0) {
167             public Class getColumnClass(int columnIndex) {
168                 Class dataType = super.getColumnClass(columnIndex);
169                 if (columnIndex == TCResultsSelectionListeners.URL) {
170                     dataType = Icon.class;
171                 }
172                 return dataType;
173             }
174         };
175         tcReasonTable = new SortableJTable(new TableSorter(tcReasonModel)){
176             public String getToolTipText(MouseEvent e) {
177                 Point p = e.getPoint();
178                 int rowIndex = rowAtPoint(p);
179                 int colIndex = columnAtPoint(p);
180                 return convertObjectToToolTip(getValueAt(rowIndex, colIndex));
181             }
182         };
183 
184         tcReasonTable.addMouseListener(new FTResultsMouseListener());
185 
186         tcReasonTable.getColumn("Row").setMaxWidth(40);
187         tcReasonTable.getColumn("Line").setMaxWidth(40);
188         tcReasonTable.getColumn(".").setMaxWidth(0);
189         tcReasonTable.getColumn(" ").setMaxWidth(20);
190         tcReasonTable.setColumnSelectionAllowed(false);
191         tcReasonTable.getSelectionModel().addListSelectionListener(new FTResultsSelectionListeners());
192         setTopComponent(new JScrollPane(tcTable));
193         JPanel panel = new JPanel(new SpringLayout());
194         panel.add(new JScrollPane(tcReasonTable));
195         stackTrace.setEditable(false);
196         stackTrace.setLineWrap(false);
197         stackTrace.setRows(20);
198         panel.add(new JScrollPane(stackTrace));
199         SpringUtilities.makeCompactGrid(panel,
200                                         2, 1,   //rows, cols
201                                         6, 6,   //initX, initY
202                                         6, 6);  //xPad, yPad
203         setBottomComponent(panel);
204     }
205 
206     public void resetTable() {
207         while (tcModel.getRowCount() > 0) {
208             tcModel.removeRow(0);
209         }
210         testCases.clear();
211         results.clear();
212         clearReasonTable();
213     }
214 
215     protected void addTestCaseRow(TestCaseTag tct) {
216         String tcFileName = getScriptName(tct);
217         if ( ! testCases.containsKey(tcFileName) ) {
218             Object[] cols = new Object[8];
219             cols[TC_NUM] = new  Integer(results.size() + 1);
220             cols[TEST_CASE] = tct.getName();
221             cols[STATUS] = runningImg;
222             cols[TC] = tct;
223             tcModel.addRow(cols);
224             Integer rowNum = new Integer(tcModel.getRowCount() - 1);
225             testCases.put(tcFileName, rowNum);
226         }
227     }
228 
229     private String getScriptName(TestCaseTag tct) {
230         String scriptName = tct.getTestCase().getFile();
231         boolean notFound = true;
232         String tmpScriptName = null;
233         for (int i = 1; notFound; i++){
234             tmpScriptName = scriptName + i;
235             if (testCases.containsKey(tmpScriptName)){
236                 Integer rowNum = (Integer)testCases.get(tmpScriptName);
237                 ImageIcon statusImg = (ImageIcon)tcModel.getValueAt(rowNum.intValue(), STATUS);
238                 if (statusImg == runningImg){
239                     notFound = false;
240                 }
241             }else{
242                 notFound = false;
243             }
244         }
245         return tmpScriptName;
246     }
247 
248     protected void reportTcResults(TestCaseTag tct) {
249         String tcFileName = getScriptName(tct);
250         int rowNum = ((Integer)testCases.get(tcFileName)).intValue();
251         TestCaseResult tcr = tct.getResults();
252         ImageIcon statusImg;
253 
254         if (tcr.passed()) {
255             statusImg = passedImg;
256         } else {
257             statusImg = failedImg;
258         }
259         tcModel.setValueAt(statusImg, rowNum, STATUS);
260 
261         String execTime = JameleonUtility.executionTimeToString(tcr.getExecutionTime());
262         tcModel.setValueAt(execTime, rowNum, EXEC_TIME);
263         int numRun = tcr.getCountableResults().size();
264         int numFailed = tcr.getFailedCountableResults().size();
265         tcModel.setValueAt(new Integer(numRun), rowNum, RUN);
266         tcModel.setValueAt(new Integer(numFailed), rowNum, FAIL);
267 
268         String percentagePassed = "N/A";
269         try {
270             NumberFormat nf = NumberFormat.getPercentInstance();
271             int numPassed = numRun - numFailed;
272             if (numRun > 0) {
273                 percentagePassed = nf.format((double) numPassed/numRun);
274             } else {
275                 percentagePassed = nf.format(0);
276             }
277         } catch (ArithmeticException ae) {
278             System.err.println("Could not divide by 0 " + ae.getMessage());
279 
280         }
281 
282         tcModel.setValueAt(percentagePassed, rowNum, PASS);
283         results.add(tcr);
284     }
285 
286     /***
287      * @param path The path to the image
288      * @param description The description of the image
289      * @return ImageIcon, or null if the path was invalid.
290      */
291     protected ImageIcon createImageIcon(String path, String description) {
292         URL imgURL = this.getClass().getResource(path);
293         ImageIcon icon = null;
294         if (imgURL != null) {
295             icon = new ImageIcon(imgURL, description);
296         } else {
297             System.err.println("Couldn't find file: " + path);
298         }
299         return icon;
300     }
301 
302     public void clearReasonTable(){
303         while (tcReasonModel.getRowCount() > 0) {
304             tcReasonModel.setRowCount(0);
305         }
306         stackTrace.setText("");
307     }
308 
309     private void checkForStop(TestCaseTag tct){
310         if (stopExecution) {
311             tct.setExecuteTestCase(false);
312         }
313     }
314 
315     ///////////////////////////////////////////////////////////////////////////////
316     //          TestCaseListener methods                                         //
317     ///////////////////////////////////////////////////////////////////////////////
318     public void beginTestCase(TestCaseEvent event) {
319         TestCaseTag tct = (TestCaseTag)event.getSource();
320         checkForStop(tct);
321         addTestCaseRow(tct);
322         if (tcTable.getSelectedRow() == -1) {
323             clearReasonTable();
324         }
325     }
326 
327     public void endTestCase(TestCaseEvent event) {
328         TestCaseTag tct = (TestCaseTag)event.getSource();
329         stepNextTag = false;
330         reportTcResults(tct);
331     }
332 
333     ///////////////////////////////////////////////////////////////////////////////
334     //          FunctionListener methods                                         //
335     ///////////////////////////////////////////////////////////////////////////////
336     public void beginFunction(FunctionEvent event, int rowNum) {
337         FunctionTag ft = (FunctionTag)event.getSource();
338         if (ft != null) {
339             highlightScriptLocation(ft);
340             checkForStop(ft.getTestCaseTag());
341             if (debug && (ft.isBreakPoint() || stepNextTag)) {
342                 new FunctionDebugDialog(ft, rootFrame, this, ft.getElementName() +": " +ft.getFunctionId());
343             }
344         }
345     }
346 
347     public void endFunction(FunctionEvent event, int rowNum) {
348         FunctionTag ft = (FunctionTag)event.getSource();
349         checkForStop(ft.getTestCaseTag());
350         FunctionResult fr = ft.getFunctionResults();
351         if (fr.failed() && tcTable.getSelectedRow() == -1) {
352             Object[] row = new Object[6];
353             row[TCResultsSelectionListeners.LINE] = new Integer(fr.getLineNumber());
354             if (fr.getErrorFile() != null) {
355                 row[TCResultsSelectionListeners.URL] = snapShotImg;
356             }
357             row[TCResultsSelectionListeners.FUNCTION_ID] = fr.getIdentifier();
358             row[TCResultsSelectionListeners.ERR_MSG] = fr.getErrorMsg();
359             row[TCResultsSelectionListeners.OBJECT] = fr;
360             row[TCResultsSelectionListeners.ROW] = getFailedRowNum(fr);
361     
362             tcReasonModel.addRow(row);
363         }
364     }
365 
366     ///////////////////////////////////////////////////////////////////////////////
367     //          DataDrivableListener methods                                         //
368     ///////////////////////////////////////////////////////////////////////////////
369     /***
370      * Gets called before the open method of a DataDrivable
371      * @param event - a DataDrivableEvent Object
372      */
373     public void openEvent(DataDrivableEvent event){
374         //Not currently supported
375     }
376 
377     /***
378      * Gets called before the close method of a DataDrivable
379      * @param event - a DataDrivableEvent Object
380      */
381     public void closeEvent(DataDrivableEvent event){
382         //Not currently supported
383     }
384 
385     /***
386      * Gets called before the executeDrivableRow
387      * @param event - a DataDrivableEvent Object
388      * @param rowNum - the current row number being executed from the data source.
389      */
390     public void executeRowEvent(DataDrivableEvent event, int rowNum){
391         DataDrivable dd = (DataDrivable)event.getSource();
392         if (dd instanceof LocationAwareTagSupport) {
393             highlightScriptLocation((LocationAwareTagSupport)dd);
394         }
395         
396         if (debug && (stepNextTag || (dd instanceof BreakPoint && ((BreakPoint)dd).isBreakPoint()))) {
397             String title = "data drivable tag";
398             if (dd instanceof LocationAwareTagSupport) {
399                 title = ((LocationAwareTagSupport)dd).getElementName();
400             }
401             new DataDrivableDebugDialog(event, rootFrame, this, title);
402         }
403     }
404 
405     private void highlightScriptLocation(LocationAware la){
406         highlightScriptLocation(la, debug);
407     }
408 
409     private void highlightScriptLocation(LocationAware la, boolean highlight){
410         if (highlight) {
411             int lineNum = la.getLineNumber()-1;
412             try{
413                 if (sourceArea.getSelectionEnd() == 0) {
414                     sourceArea.setCaretPosition(0);
415                 }
416                 sourceArea.setCaretPosition(sourceArea.getLineStartOffset(lineNum));
417                 sourceArea.moveCaretPosition(sourceArea.getLineEndOffset(lineNum));
418             }catch(BadLocationException ble){
419                 ble.printStackTrace();
420             }
421         }
422     }
423     
424     protected Integer getFailedRowNum(JameleonTestResult result){
425     	int rowNum = 0;
426     	DataDrivableRowResult ddr = (DataDrivableRowResult)result.findAncestorByClass(DataDrivableRowResult.class);
427     	if (ddr != null){
428     		rowNum = ddr.getRowNum();
429     	}
430     	return new Integer(rowNum);
431     }
432 
433 
434     ///////////////////////////////////////////////////////////////////////////////
435     //          Event Listeners                                                  //
436     ///////////////////////////////////////////////////////////////////////////////
437     public class TCResultsSelectionListeners implements ListSelectionListener{
438         protected static final int ROW = 0;
439         protected static final int LINE = 1;
440         protected static final int URL = 2;
441         protected static final int FUNCTION_ID = 3;
442         protected static final int ERR_MSG = 4;
443         protected static final int OBJECT = 5;
444         
445         /***
446          * Called whenever the value of the selection changes.
447          * @param e the event that characterizes the change.
448          */
449         public void valueChanged(ListSelectionEvent e) {
450             clearReasonTable();
451             int selectedRow = tcTable.getSelectedRow();
452             if (selectedRow > -1) {
453                 TestCaseTag tct = (TestCaseTag)tcTable.getModel().getValueAt(selectedRow, TC);
454                 TestCaseResult result = tct.getResults();
455                 if (result.failed()) {
456                     Object[] row = new Object[6];
457                     List failedResults = result.getFailedResults();
458                     Iterator it = failedResults.iterator();
459                     JameleonTestResult tr;
460                     while (it.hasNext()) {
461                         tr = (JameleonTestResult)it.next();
462                         row[LINE] = new Integer(tr.getLineNumber());
463                         row[FUNCTION_ID] = tr.getIdentifier();
464                         if (tr.getErrorFile() != null) {
465                             row[URL] = snapShotImg;
466                         }
467                         row[ERR_MSG] = tr.getError().getMessage();
468                         row[OBJECT] = tr;
469                         row[ROW] = getFailedRowNum(tr);
470                         tcReasonModel.addRow(row);
471                     }
472                 }
473             }
474             
475         }
476         
477     }
478 
479     public class FTResultsSelectionListeners implements ListSelectionListener{
480         /***
481          * Called whenever the value of the selection changes.
482          * @param e the event that characterizes the change.
483          */
484         public void valueChanged(ListSelectionEvent e) {
485             int selectedRow = tcReasonTable.getSelectedRow();
486             if (selectedRow > -1) {
487                 Object obj = tcReasonTable.getValueAt(selectedRow, TCResultsSelectionListeners.OBJECT);
488                 if (obj instanceof JameleonTestResult) {
489                     JameleonTestResult result = (JameleonTestResult) obj;
490                     Throwable t = result.getError();
491                     if (t != null) {
492                         t = getCause(t);
493                         stackTrace.setText(JameleonUtility.getStack(t));
494                         stackTrace.setCaretPosition(0);
495                     }
496                 }
497             }
498         }
499 
500         private Throwable getCause(Throwable t){
501             Throwable cause = t.getCause();
502             if (cause == null) {
503                 cause = t;
504             }
505             return cause;
506         }
507 
508     }
509 
510     public class FTResultsMouseListener extends MouseAdapter{
511         public void mouseClicked(MouseEvent e) {
512             if (e.getClickCount() == 1) {
513                 Point origin = e.getPoint();
514                 int row = tcReasonTable.rowAtPoint(origin);
515                 int col = tcReasonTable.columnAtPoint(origin);
516                 if (row > -1 && col == TCResultsSelectionListeners.URL &&
517                     tcReasonTable.getValueAt(row,TCResultsSelectionListeners.OBJECT) instanceof JameleonTestResult) {
518                     JameleonTestResult tr = (JameleonTestResult)tcReasonTable.getValueAt(row,TCResultsSelectionListeners.OBJECT);
519                     if (tr.getErrorFile() != null) {
520                         try{
521                             snapShotBrowser.goToUrl(tr.getErrorFile().toURI().toURL());
522                         }catch (Exception ex){
523                             ex.printStackTrace();
524                         }
525                     }
526                 }else if (row > -1 && col == TCResultsSelectionListeners.LINE) {
527                     JameleonTestResult tr = (JameleonTestResult)tcReasonTable.getValueAt(row, TCResultsSelectionListeners.OBJECT);
528                     int selectedRow = tcTable.getSelectedRow();
529                     if (selectedRow == -1) {
530                         selectedRow = 0;
531                     }
532                     TestCaseTag tct = (TestCaseTag)tcTable.getValueAt(selectedRow, TC);
533                     if (tct != null) {
534                         try{
535                             tcTree.setTestCaseSource(new File(new URI(tct.getFileName())), true);
536                             highlightScriptLocation(tr, true);
537                         }catch(Exception ex){
538                             ex.printStackTrace();
539                         }
540                     }
541                 }
542             }
543         }
544     }
545 
546     public class TCResultsMouseListener extends MouseAdapter{
547         public void mouseClicked(MouseEvent e) {
548             if (e.getClickCount() == 1) {
549                 Point origin = e.getPoint();
550                 int row = tcTable.rowAtPoint(origin);
551                 int col = tcTable.columnAtPoint(origin);
552                 if (row > -1 && col == TestCaseResultsPane.STATUS &&
553                     tcTable.getValueAt(row,TestCaseResultsPane.TC) instanceof TestCaseTag) {
554                     TestCaseTag tct = (TestCaseTag)tcTable.getValueAt(row,TestCaseResultsPane.TC);
555                     if (tct != null) {
556                         try{
557                             System.out.println(tct.getResultsFile());
558                             snapShotBrowser.goToUrl(tct.getResultsFile().toURI().toURL());
559                         }catch (Exception ex){
560                             ex.printStackTrace();
561                         }
562                     }
563                 }
564             }
565         }
566     }
567 
568 
569 
570 }