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