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