1 package junit.awtui; 2 3 import java.awt.BorderLayout; 4 import java.awt.Button; 5 import java.awt.Checkbox; 6 import java.awt.Color; 7 import java.awt.Component; 8 import java.awt.Font; 9 import java.awt.Frame; 10 import java.awt.GridBagConstraints; 11 import java.awt.GridBagLayout; 12 import java.awt.GridLayout; 13 import java.awt.Image; 14 import java.awt.Insets; 15 import java.awt.Label; 16 import java.awt.List; 17 import java.awt.Menu; 18 import java.awt.MenuBar; 19 import java.awt.MenuItem; 20 import java.awt.Panel; 21 import java.awt.SystemColor; 22 import java.awt.TextArea; 23 import java.awt.TextField; 24 import java.awt.Toolkit; 25 import java.awt.event.ActionEvent; 26 import java.awt.event.ActionListener; 27 import java.awt.event.ItemEvent; 28 import java.awt.event.ItemListener; 29 import java.awt.event.TextEvent; 30 import java.awt.event.TextListener; 31 import java.awt.event.WindowAdapter; 32 import java.awt.event.WindowEvent; 33 import java.awt.image.ImageProducer; 34 import java.util.Vector; 35 36 import junit.framework.Test; 37 import junit.framework.TestCase; 38 import junit.framework.TestResult; 39 import junit.framework.TestSuite; 40 import junit.runner.BaseTestRunner; 41 import junit.runner.TestRunListener; 42 43 /** 44 * An AWT based user interface to run tests. 45 * Enter the name of a class which either provides a static 46 * suite method or is a subclass of TestCase. 47 * <pre> 48 * Synopsis: java junit.awtui.TestRunner [-noloading] [TestCase] 49 * </pre> 50 * TestRunner takes as an optional argument the name of the testcase class to be run. 51 */ 52 public class TestRunner extends BaseTestRunner { 53 protected Frame fFrame; 54 protected Vector fExceptions; 55 protected Vector fFailedTests; 56 protected Thread fRunner; 57 protected TestResult fTestResult; 58 59 protected TextArea fTraceArea; 60 protected TextField fSuiteField; 61 protected Button fRun; 62 protected ProgressBar fProgressIndicator; 63 protected List fFailureList; 64 protected Logo fLogo; 65 protected Label fNumberOfErrors; 66 protected Label fNumberOfFailures; 67 protected Label fNumberOfRuns; 68 protected Button fQuitButton; 69 protected Button fRerunButton; 70 protected TextField fStatusLine; 71 protected Checkbox fUseLoadingRunner; 72 73 protected static final Font PLAIN_FONT= new Font("dialog", Font.PLAIN, 12); 74 private static final int GAP= 4; 75 TestRunner()76 public TestRunner() { 77 } 78 about()79 private void about() { 80 AboutDialog about= new AboutDialog(fFrame); 81 about.setModal(true); 82 about.setLocation(300, 300); 83 about.setVisible(true); 84 } 85 testStarted(String testName)86 public void testStarted(String testName) { 87 showInfo("Running: "+testName); 88 } 89 testEnded(String testName)90 public void testEnded(String testName) { 91 setLabelValue(fNumberOfRuns, fTestResult.runCount()); 92 synchronized(this) { 93 fProgressIndicator.step(fTestResult.wasSuccessful()); 94 } 95 } 96 testFailed(int status, Test test, Throwable t)97 public void testFailed(int status, Test test, Throwable t) { 98 switch (status) { 99 case TestRunListener.STATUS_ERROR: 100 fNumberOfErrors.setText(Integer.toString(fTestResult.errorCount())); 101 appendFailure("Error", test, t); 102 break; 103 case TestRunListener.STATUS_FAILURE: 104 fNumberOfFailures.setText(Integer.toString(fTestResult.failureCount())); 105 appendFailure("Failure", test, t); 106 break; 107 } 108 } 109 addGrid(Panel p, Component co, int x, int y, int w, int fill, double wx, int anchor)110 protected void addGrid(Panel p, Component co, int x, int y, int w, int fill, double wx, int anchor) { 111 GridBagConstraints c= new GridBagConstraints(); 112 c.gridx= x; c.gridy= y; 113 c.gridwidth= w; 114 c.anchor= anchor; 115 c.weightx= wx; 116 c.fill= fill; 117 if (fill == GridBagConstraints.BOTH || fill == GridBagConstraints.VERTICAL) 118 c.weighty= 1.0; 119 c.insets= new Insets(y == 0 ? GAP : 0, x == 0 ? GAP : 0, GAP, GAP); 120 p.add(co, c); 121 } 122 appendFailure(String kind, Test test, Throwable t)123 private void appendFailure(String kind, Test test, Throwable t) { 124 kind+= ": " + test; 125 String msg= t.getMessage(); 126 if (msg != null) { 127 kind+= ":" + truncate(msg); 128 } 129 fFailureList.add(kind); 130 fExceptions.addElement(t); 131 fFailedTests.addElement(test); 132 if (fFailureList.getItemCount() == 1) { 133 fFailureList.select(0); 134 failureSelected(); 135 } 136 } 137 /** 138 * Creates the JUnit menu. Clients override this 139 * method to add additional menu items. 140 */ createJUnitMenu()141 protected Menu createJUnitMenu() { 142 Menu menu= new Menu("JUnit"); 143 MenuItem mi= new MenuItem("About..."); 144 mi.addActionListener( 145 new ActionListener() { 146 public void actionPerformed(ActionEvent event) { 147 about(); 148 } 149 } 150 ); 151 menu.add(mi); 152 153 menu.addSeparator(); 154 mi= new MenuItem("Exit"); 155 mi.addActionListener( 156 new ActionListener() { 157 public void actionPerformed(ActionEvent event) { 158 System.exit(0); 159 } 160 } 161 ); 162 menu.add(mi); 163 return menu; 164 } 165 createMenus(MenuBar mb)166 protected void createMenus(MenuBar mb) { 167 mb.add(createJUnitMenu()); 168 } createTestResult()169 protected TestResult createTestResult() { 170 return new TestResult(); 171 } 172 createUI(String suiteName)173 protected Frame createUI(String suiteName) { 174 Frame frame= new Frame("JUnit"); 175 Image icon= loadFrameIcon(); 176 if (icon != null) 177 frame.setIconImage(icon); 178 179 frame.setLayout(new BorderLayout(0, 0)); 180 frame.setBackground(SystemColor.control); 181 final Frame finalFrame= frame; 182 183 frame.addWindowListener( 184 new WindowAdapter() { 185 public void windowClosing(WindowEvent e) { 186 finalFrame.dispose(); 187 System.exit(0); 188 } 189 } 190 ); 191 192 MenuBar mb = new MenuBar(); 193 createMenus(mb); 194 frame.setMenuBar(mb); 195 196 //---- first section 197 Label suiteLabel= new Label("Test class name:"); 198 199 fSuiteField= new TextField(suiteName != null ? suiteName : ""); 200 fSuiteField.selectAll(); 201 fSuiteField.requestFocus(); 202 fSuiteField.setFont(PLAIN_FONT); 203 fSuiteField.setColumns(40); 204 fSuiteField.addActionListener( 205 new ActionListener() { 206 public void actionPerformed(ActionEvent e) { 207 runSuite(); 208 } 209 } 210 ); 211 fSuiteField.addTextListener( 212 new TextListener() { 213 public void textValueChanged(TextEvent e) { 214 fRun.setEnabled(fSuiteField.getText().length() > 0); 215 fStatusLine.setText(""); 216 } 217 } 218 ); 219 fRun= new Button("Run"); 220 fRun.setEnabled(false); 221 fRun.addActionListener( 222 new ActionListener() { 223 public void actionPerformed(ActionEvent e) { 224 runSuite(); 225 } 226 } 227 ); 228 boolean useLoader= useReloadingTestSuiteLoader(); 229 fUseLoadingRunner= new Checkbox("Reload classes every run", useLoader); 230 if (inVAJava()) 231 fUseLoadingRunner.setVisible(false); 232 233 //---- second section 234 fProgressIndicator= new ProgressBar(); 235 236 //---- third section 237 fNumberOfErrors= new Label("0000", Label.RIGHT); 238 fNumberOfErrors.setText("0"); 239 fNumberOfErrors.setFont(PLAIN_FONT); 240 241 fNumberOfFailures= new Label("0000", Label.RIGHT); 242 fNumberOfFailures.setText("0"); 243 fNumberOfFailures.setFont(PLAIN_FONT); 244 245 fNumberOfRuns= new Label("0000", Label.RIGHT); 246 fNumberOfRuns.setText("0"); 247 fNumberOfRuns.setFont(PLAIN_FONT); 248 249 Panel numbersPanel= createCounterPanel(); 250 251 //---- fourth section 252 Label failureLabel= new Label("Errors and Failures:"); 253 254 fFailureList= new List(5); 255 fFailureList.addItemListener( 256 new ItemListener() { 257 public void itemStateChanged(ItemEvent e) { 258 failureSelected(); 259 } 260 } 261 ); 262 fRerunButton= new Button("Run"); 263 fRerunButton.setEnabled(false); 264 fRerunButton.addActionListener( 265 new ActionListener() { 266 public void actionPerformed(ActionEvent e) { 267 rerun(); 268 } 269 } 270 ); 271 272 Panel failedPanel= new Panel(new GridLayout(0, 1, 0, 2)); 273 failedPanel.add(fRerunButton); 274 275 fTraceArea= new TextArea(); 276 fTraceArea.setRows(5); 277 fTraceArea.setColumns(60); 278 279 //---- fifth section 280 fStatusLine= new TextField(); 281 fStatusLine.setFont(PLAIN_FONT); 282 fStatusLine.setEditable(false); 283 fStatusLine.setForeground(Color.red); 284 285 fQuitButton= new Button("Exit"); 286 fQuitButton.addActionListener( 287 new ActionListener() { 288 public void actionPerformed(ActionEvent e) { 289 System.exit(0); 290 } 291 } 292 ); 293 294 // --------- 295 fLogo= new Logo(); 296 297 //---- overall layout 298 Panel panel= new Panel(new GridBagLayout()); 299 300 addGrid(panel, suiteLabel, 0, 0, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST); 301 302 addGrid(panel, fSuiteField, 0, 1, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST); 303 addGrid(panel, fRun, 2, 1, 1, GridBagConstraints.HORIZONTAL, 0.0, GridBagConstraints.CENTER); 304 addGrid(panel, fUseLoadingRunner, 0, 2, 2, GridBagConstraints.NONE, 1.0, GridBagConstraints.WEST); 305 addGrid(panel, fProgressIndicator, 0, 3, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST); 306 addGrid(panel, fLogo, 2, 3, 1, GridBagConstraints.NONE, 0.0, GridBagConstraints.NORTH); 307 308 addGrid(panel, numbersPanel, 0, 4, 2, GridBagConstraints.NONE, 0.0, GridBagConstraints.WEST); 309 310 addGrid(panel, failureLabel, 0, 5, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST); 311 addGrid(panel, fFailureList, 0, 6, 2, GridBagConstraints.BOTH, 1.0, GridBagConstraints.WEST); 312 addGrid(panel, failedPanel, 2, 6, 1, GridBagConstraints.HORIZONTAL, 0.0, GridBagConstraints.CENTER); 313 addGrid(panel, fTraceArea, 0, 7, 2, GridBagConstraints.BOTH, 1.0, GridBagConstraints.WEST); 314 315 addGrid(panel, fStatusLine, 0, 8, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.CENTER); 316 addGrid(panel, fQuitButton, 2, 8, 1, GridBagConstraints.HORIZONTAL, 0.0, GridBagConstraints.CENTER); 317 318 frame.add(panel, BorderLayout.CENTER); 319 frame.pack(); 320 return frame; 321 } 322 createCounterPanel()323 protected Panel createCounterPanel() { 324 Panel numbersPanel= new Panel(new GridBagLayout()); 325 addToCounterPanel( 326 numbersPanel, 327 new Label("Runs:"), 328 0, 0, 1, 1, 0.0, 0.0, 329 GridBagConstraints.CENTER, GridBagConstraints.NONE, 330 new Insets(0, 0, 0, 0) 331 ); 332 addToCounterPanel( 333 numbersPanel, 334 fNumberOfRuns, 335 1, 0, 1, 1, 0.33, 0.0, 336 GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, 337 new Insets(0, 8, 0, 40) 338 ); 339 addToCounterPanel( 340 numbersPanel, 341 new Label("Errors:"), 342 2, 0, 1, 1, 0.0, 0.0, 343 GridBagConstraints.CENTER, GridBagConstraints.NONE, 344 new Insets(0, 8, 0, 0) 345 ); 346 addToCounterPanel( 347 numbersPanel, 348 fNumberOfErrors, 349 3, 0, 1, 1, 0.33, 0.0, 350 GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, 351 new Insets(0, 8, 0, 40) 352 ); 353 addToCounterPanel( 354 numbersPanel, 355 new Label("Failures:"), 356 4, 0, 1, 1, 0.0, 0.0, 357 GridBagConstraints.CENTER, GridBagConstraints.NONE, 358 new Insets(0, 8, 0, 0) 359 ); 360 addToCounterPanel( 361 numbersPanel, 362 fNumberOfFailures, 363 5, 0, 1, 1, 0.33, 0.0, 364 GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, 365 new Insets(0, 8, 0, 0) 366 ); 367 return numbersPanel; 368 } 369 addToCounterPanel(Panel counter, Component comp, int gridx, int gridy, int gridwidth, int gridheight, double weightx, double weighty, int anchor, int fill, Insets insets)370 private void addToCounterPanel(Panel counter, Component comp, 371 int gridx, int gridy, int gridwidth, int gridheight, 372 double weightx, double weighty, 373 int anchor, int fill, 374 Insets insets) { 375 376 GridBagConstraints constraints= new GridBagConstraints(); 377 constraints.gridx= gridx; 378 constraints.gridy= gridy; 379 constraints.gridwidth= gridwidth; 380 constraints.gridheight= gridheight; 381 constraints.weightx= weightx; 382 constraints.weighty= weighty; 383 constraints.anchor= anchor; 384 constraints.fill= fill; 385 constraints.insets= insets; 386 counter.add(comp, constraints); 387 } 388 389 failureSelected()390 public void failureSelected() { 391 fRerunButton.setEnabled(isErrorSelected()); 392 showErrorTrace(); 393 } 394 isErrorSelected()395 private boolean isErrorSelected() { 396 return fFailureList.getSelectedIndex() != -1; 397 } 398 loadFrameIcon()399 private Image loadFrameIcon() { 400 Toolkit toolkit= Toolkit.getDefaultToolkit(); 401 try { 402 java.net.URL url= BaseTestRunner.class.getResource("smalllogo.gif"); 403 return toolkit.createImage((ImageProducer) url.getContent()); 404 } catch (Exception ex) { 405 } 406 return null; 407 } 408 getRunner()409 public Thread getRunner() { 410 return fRunner; 411 } 412 main(String[] args)413 public static void main(String[] args) { 414 new TestRunner().start(args); 415 } 416 run(Class test)417 public static void run(Class test) { 418 String args[]= { test.getName() }; 419 main(args); 420 } 421 rerun()422 public void rerun() { 423 int index= fFailureList.getSelectedIndex(); 424 if (index == -1) 425 return; 426 427 Test test= (Test)fFailedTests.elementAt(index); 428 rerunTest(test); 429 } 430 rerunTest(Test test)431 private void rerunTest(Test test) { 432 if (!(test instanceof TestCase)) { 433 showInfo("Could not reload "+ test.toString()); 434 return; 435 } 436 Test reloadedTest= null; 437 TestCase rerunTest= (TestCase)test; 438 try { 439 Class reloadedTestClass= getLoader().reload(test.getClass()); 440 reloadedTest= TestSuite.createTest(reloadedTestClass, rerunTest.getName()); 441 } catch(Exception e) { 442 showInfo("Could not reload "+ test.toString()); 443 return; 444 } 445 TestResult result= new TestResult(); 446 reloadedTest.run(result); 447 448 String message= reloadedTest.toString(); 449 if(result.wasSuccessful()) 450 showInfo(message+" was successful"); 451 else if (result.errorCount() == 1) 452 showStatus(message+" had an error"); 453 else 454 showStatus(message+" had a failure"); 455 } 456 reset()457 protected void reset() { 458 setLabelValue(fNumberOfErrors, 0); 459 setLabelValue(fNumberOfFailures, 0); 460 setLabelValue(fNumberOfRuns, 0); 461 fProgressIndicator.reset(); 462 fRerunButton.setEnabled(false); 463 fFailureList.removeAll(); 464 fExceptions= new Vector(10); 465 fFailedTests= new Vector(10); 466 fTraceArea.setText(""); 467 468 } 469 runFailed(String message)470 protected void runFailed(String message) { 471 showStatus(message); 472 fRun.setLabel("Run"); 473 fRunner= null; 474 } 475 runSuite()476 synchronized public void runSuite() { 477 if (fRunner != null && fTestResult != null) { 478 fTestResult.stop(); 479 } else { 480 setLoading(shouldReload()); 481 fRun.setLabel("Stop"); 482 showInfo("Initializing..."); 483 reset(); 484 485 showInfo("Load Test Case..."); 486 487 final Test testSuite= getTest(fSuiteField.getText()); 488 if (testSuite != null) { 489 fRunner= new Thread() { 490 public void run() { 491 fTestResult= createTestResult(); 492 fTestResult.addListener(TestRunner.this); 493 fProgressIndicator.start(testSuite.countTestCases()); 494 showInfo("Running..."); 495 496 long startTime= System.currentTimeMillis(); 497 testSuite.run(fTestResult); 498 499 if (fTestResult.shouldStop()) { 500 showStatus("Stopped"); 501 } else { 502 long endTime= System.currentTimeMillis(); 503 long runTime= endTime-startTime; 504 showInfo("Finished: " + elapsedTimeAsString(runTime) + " seconds"); 505 } 506 fTestResult= null; 507 fRun.setLabel("Run"); 508 fRunner= null; 509 System.gc(); 510 } 511 }; 512 fRunner.start(); 513 } 514 } 515 } 516 shouldReload()517 private boolean shouldReload() { 518 return !inVAJava() && fUseLoadingRunner.getState(); 519 } 520 setLabelValue(Label label, int value)521 private void setLabelValue(Label label, int value) { 522 label.setText(Integer.toString(value)); 523 label.invalidate(); 524 label.getParent().validate(); 525 526 } 527 setSuiteName(String suite)528 public void setSuiteName(String suite) { 529 fSuiteField.setText(suite); 530 } 531 showErrorTrace()532 private void showErrorTrace() { 533 int index= fFailureList.getSelectedIndex(); 534 if (index == -1) 535 return; 536 537 Throwable t= (Throwable) fExceptions.elementAt(index); 538 fTraceArea.setText(getFilteredTrace(t)); 539 } 540 541 showInfo(String message)542 private void showInfo(String message) { 543 fStatusLine.setFont(PLAIN_FONT); 544 fStatusLine.setForeground(Color.black); 545 fStatusLine.setText(message); 546 } 547 clearStatus()548 protected void clearStatus() { 549 showStatus(""); 550 } 551 showStatus(String status)552 private void showStatus(String status) { 553 fStatusLine.setFont(PLAIN_FONT); 554 fStatusLine.setForeground(Color.red); 555 fStatusLine.setText(status); 556 } 557 /** 558 * Starts the TestRunner 559 */ start(String[] args)560 public void start(String[] args) { 561 String suiteName= processArguments(args); 562 fFrame= createUI(suiteName); 563 fFrame.setLocation(200, 200); 564 fFrame.setVisible(true); 565 566 if (suiteName != null) { 567 setSuiteName(suiteName); 568 runSuite(); 569 } 570 } 571 }