package junit.awtui;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Checkbox;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.Frame;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Label;
import java.awt.List;
import java.awt.Menu;
import java.awt.MenuBar;
import java.awt.MenuItem;
import java.awt.Panel;
import java.awt.SystemColor;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.TextEvent;
import java.awt.event.TextListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.ImageProducer;
import java.util.Vector;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestResult;
import junit.framework.TestSuite;
import junit.runner.BaseTestRunner;
import junit.runner.TestRunListener;
/**
* An AWT based user interface to run tests.
* Enter the name of a class which either provides a static
* suite method or is a subclass of TestCase.
* <pre>
* Synopsis: java junit.awtui.TestRunner [-noloading] [TestCase]
* </pre>
* TestRunner takes as an optional argument the name of the testcase class to be run.
*/
public class TestRunner extends BaseTestRunner {
protected Frame fFrame;
protected Vector fExceptions;
protected Vector fFailedTests;
protected Thread fRunner;
protected TestResult fTestResult;
protected TextArea fTraceArea;
protected TextField fSuiteField;
protected Button fRun;
protected ProgressBar fProgressIndicator;
protected List fFailureList;
protected Logo fLogo;
protected Label fNumberOfErrors;
protected Label fNumberOfFailures;
protected Label fNumberOfRuns;
protected Button fQuitButton;
protected Button fRerunButton;
protected TextField fStatusLine;
protected Checkbox fUseLoadingRunner;
protected static final Font PLAIN_FONT= new Font("dialog", Font.PLAIN, 12);
private static final int GAP= 4;
public TestRunner() {
}
private void about() {
AboutDialog about= new AboutDialog(fFrame);
about.setModal(true);
about.setLocation(300, 300);
about.setVisible(true);
}
public void testStarted(String testName) {
showInfo("Running: "+testName);
}
public void testEnded(String testName) {
setLabelValue(fNumberOfRuns, fTestResult.runCount());
synchronized(this) {
fProgressIndicator.step(fTestResult.wasSuccessful());
}
}
public void testFailed(int status, Test test, Throwable t) {
switch (status) {
case TestRunListener.STATUS_ERROR:
fNumberOfErrors.setText(Integer.toString(fTestResult.errorCount()));
appendFailure("Error", test, t);
break;
case TestRunListener.STATUS_FAILURE:
fNumberOfFailures.setText(Integer.toString(fTestResult.failureCount()));
appendFailure("Failure", test, t);
break;
}
}
protected void addGrid(Panel p, Component co, int x, int y, int w, int fill, double wx, int anchor) {
GridBagConstraints c= new GridBagConstraints();
c.gridx= x; c.gridy= y;
c.gridwidth= w;
c.anchor= anchor;
c.weightx= wx;
c.fill= fill;
if (fill == GridBagConstraints.BOTH || fill == GridBagConstraints.VERTICAL)
c.weighty= 1.0;
c.insets= new Insets(y == 0 ? GAP : 0, x == 0 ? GAP : 0, GAP, GAP);
p.add(co, c);
}
private void appendFailure(String kind, Test test, Throwable t) {
kind+= ": " + test;
String msg= t.getMessage();
if (msg != null) {
kind+= ":" + truncate(msg);
}
fFailureList.add(kind);
fExceptions.addElement(t);
fFailedTests.addElement(test);
if (fFailureList.getItemCount() == 1) {
fFailureList.select(0);
failureSelected();
}
}
/**
* Creates the JUnit menu. Clients override this
* method to add additional menu items.
*/
protected Menu createJUnitMenu() {
Menu menu= new Menu("JUnit");
MenuItem mi= new MenuItem("About...");
mi.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent event) {
about();
}
}
);
menu.add(mi);
menu.addSeparator();
mi= new MenuItem("Exit");
mi.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent event) {
System.exit(0);
}
}
);
menu.add(mi);
return menu;
}
protected void createMenus(MenuBar mb) {
mb.add(createJUnitMenu());
}
protected TestResult createTestResult() {
return new TestResult();
}
protected Frame createUI(String suiteName) {
Frame frame= new Frame("JUnit");
Image icon= loadFrameIcon();
if (icon != null)
frame.setIconImage(icon);
frame.setLayout(new BorderLayout(0, 0));
frame.setBackground(SystemColor.control);
final Frame finalFrame= frame;
frame.addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
finalFrame.dispose();
System.exit(0);
}
}
);
MenuBar mb = new MenuBar();
createMenus(mb);
frame.setMenuBar(mb);
//---- first section
Label suiteLabel= new Label("Test class name:");
fSuiteField= new TextField(suiteName != null ? suiteName : "");
fSuiteField.selectAll();
fSuiteField.requestFocus();
fSuiteField.setFont(PLAIN_FONT);
fSuiteField.setColumns(40);
fSuiteField.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
runSuite();
}
}
);
fSuiteField.addTextListener(
new TextListener() {
public void textValueChanged(TextEvent e) {
fRun.setEnabled(fSuiteField.getText().length() > 0);
fStatusLine.setText("");
}
}
);
fRun= new Button("Run");
fRun.setEnabled(false);
fRun.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
runSuite();
}
}
);
boolean useLoader= useReloadingTestSuiteLoader();
fUseLoadingRunner= new Checkbox("Reload classes every run", useLoader);
if (inVAJava())
fUseLoadingRunner.setVisible(false);
//---- second section
fProgressIndicator= new ProgressBar();
//---- third section
fNumberOfErrors= new Label("0000", Label.RIGHT);
fNumberOfErrors.setText("0");
fNumberOfErrors.setFont(PLAIN_FONT);
fNumberOfFailures= new Label("0000", Label.RIGHT);
fNumberOfFailures.setText("0");
fNumberOfFailures.setFont(PLAIN_FONT);
fNumberOfRuns= new Label("0000", Label.RIGHT);
fNumberOfRuns.setText("0");
fNumberOfRuns.setFont(PLAIN_FONT);
Panel numbersPanel= createCounterPanel();
//---- fourth section
Label failureLabel= new Label("Errors and Failures:");
fFailureList= new List(5);
fFailureList.addItemListener(
new ItemListener() {
public void itemStateChanged(ItemEvent e) {
failureSelected();
}
}
);
fRerunButton= new Button("Run");
fRerunButton.setEnabled(false);
fRerunButton.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
rerun();
}
}
);
Panel failedPanel= new Panel(new GridLayout(0, 1, 0, 2));
failedPanel.add(fRerunButton);
fTraceArea= new TextArea();
fTraceArea.setRows(5);
fTraceArea.setColumns(60);
//---- fifth section
fStatusLine= new TextField();
fStatusLine.setFont(PLAIN_FONT);
fStatusLine.setEditable(false);
fStatusLine.setForeground(Color.red);
fQuitButton= new Button("Exit");
fQuitButton.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
}
);
// ---------
fLogo= new Logo();
//---- overall layout
Panel panel= new Panel(new GridBagLayout());
addGrid(panel, suiteLabel, 0, 0, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST);
addGrid(panel, fSuiteField, 0, 1, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST);
addGrid(panel, fRun, 2, 1, 1, GridBagConstraints.HORIZONTAL, 0.0, GridBagConstraints.CENTER);
addGrid(panel, fUseLoadingRunner, 0, 2, 2, GridBagConstraints.NONE, 1.0, GridBagConstraints.WEST);
addGrid(panel, fProgressIndicator, 0, 3, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST);
addGrid(panel, fLogo, 2, 3, 1, GridBagConstraints.NONE, 0.0, GridBagConstraints.NORTH);
addGrid(panel, numbersPanel, 0, 4, 2, GridBagConstraints.NONE, 0.0, GridBagConstraints.WEST);
addGrid(panel, failureLabel, 0, 5, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST);
addGrid(panel, fFailureList, 0, 6, 2, GridBagConstraints.BOTH, 1.0, GridBagConstraints.WEST);
addGrid(panel, failedPanel, 2, 6, 1, GridBagConstraints.HORIZONTAL, 0.0, GridBagConstraints.CENTER);
addGrid(panel, fTraceArea, 0, 7, 2, GridBagConstraints.BOTH, 1.0, GridBagConstraints.WEST);
addGrid(panel, fStatusLine, 0, 8, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.CENTER);
addGrid(panel, fQuitButton, 2, 8, 1, GridBagConstraints.HORIZONTAL, 0.0, GridBagConstraints.CENTER);
frame.add(panel, BorderLayout.CENTER);
frame.pack();
return frame;
}
protected Panel createCounterPanel() {
Panel numbersPanel= new Panel(new GridBagLayout());
addToCounterPanel(
numbersPanel,
new Label("Runs:"),
0, 0, 1, 1, 0.0, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.NONE,
new Insets(0, 0, 0, 0)
);
addToCounterPanel(
numbersPanel,
fNumberOfRuns,
1, 0, 1, 1, 0.33, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
new Insets(0, 8, 0, 40)
);
addToCounterPanel(
numbersPanel,
new Label("Errors:"),
2, 0, 1, 1, 0.0, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.NONE,
new Insets(0, 8, 0, 0)
);
addToCounterPanel(
numbersPanel,
fNumberOfErrors,
3, 0, 1, 1, 0.33, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
new Insets(0, 8, 0, 40)
);
addToCounterPanel(
numbersPanel,
new Label("Failures:"),
4, 0, 1, 1, 0.0, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.NONE,
new Insets(0, 8, 0, 0)
);
addToCounterPanel(
numbersPanel,
fNumberOfFailures,
5, 0, 1, 1, 0.33, 0.0,
GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL,
new Insets(0, 8, 0, 0)
);
return numbersPanel;
}
private void addToCounterPanel(Panel counter, Component comp,
int gridx, int gridy, int gridwidth, int gridheight,
double weightx, double weighty,
int anchor, int fill,
Insets insets) {
GridBagConstraints constraints= new GridBagConstraints();
constraints.gridx= gridx;
constraints.gridy= gridy;
constraints.gridwidth= gridwidth;
constraints.gridheight= gridheight;
constraints.weightx= weightx;
constraints.weighty= weighty;
constraints.anchor= anchor;
constraints.fill= fill;
constraints.insets= insets;
counter.add(comp, constraints);
}
public void failureSelected() {
fRerunButton.setEnabled(isErrorSelected());
showErrorTrace();
}
private boolean isErrorSelected() {
return fFailureList.getSelectedIndex() != -1;
}
private Image loadFrameIcon() {
Toolkit toolkit= Toolkit.getDefaultToolkit();
try {
java.net.URL url= BaseTestRunner.class.getResource("smalllogo.gif");
return toolkit.createImage((ImageProducer) url.getContent());
} catch (Exception ex) {
}
return null;
}
public Thread getRunner() {
return fRunner;
}
public static void main(String[] args) {
new TestRunner().start(args);
}
public static void run(Class test) {
String args[]= { test.getName() };
main(args);
}
public void rerun() {
int index= fFailureList.getSelectedIndex();
if (index == -1)
return;
Test test= (Test)fFailedTests.elementAt(index);
rerunTest(test);
}
private void rerunTest(Test test) {
if (!(test instanceof TestCase)) {
showInfo("Could not reload "+ test.toString());
return;
}
Test reloadedTest= null;
TestCase rerunTest= (TestCase)test;
try {
Class reloadedTestClass= getLoader().reload(test.getClass());
reloadedTest= TestSuite.createTest(reloadedTestClass, rerunTest.getName());
} catch(Exception e) {
showInfo("Could not reload "+ test.toString());
return;
}
TestResult result= new TestResult();
reloadedTest.run(result);
String message= reloadedTest.toString();
if(result.wasSuccessful())
showInfo(message+" was successful");
else if (result.errorCount() == 1)
showStatus(message+" had an error");
else
showStatus(message+" had a failure");
}
protected void reset() {
setLabelValue(fNumberOfErrors, 0);
setLabelValue(fNumberOfFailures, 0);
setLabelValue(fNumberOfRuns, 0);
fProgressIndicator.reset();
fRerunButton.setEnabled(false);
fFailureList.removeAll();
fExceptions= new Vector(10);
fFailedTests= new Vector(10);
fTraceArea.setText("");
}
protected void runFailed(String message) {
showStatus(message);
fRun.setLabel("Run");
fRunner= null;
}
synchronized public void runSuite() {
if (fRunner != null && fTestResult != null) {
fTestResult.stop();
} else {
setLoading(shouldReload());
fRun.setLabel("Stop");
showInfo("Initializing...");
reset();
showInfo("Load Test Case...");
final Test testSuite= getTest(fSuiteField.getText());
if (testSuite != null) {
fRunner= new Thread() {
public void run() {
fTestResult= createTestResult();
fTestResult.addListener(TestRunner.this);
fProgressIndicator.start(testSuite.countTestCases());
showInfo("Running...");
long startTime= System.currentTimeMillis();
testSuite.run(fTestResult);
if (fTestResult.shouldStop()) {
showStatus("Stopped");
} else {
long endTime= System.currentTimeMillis();
long runTime= endTime-startTime;
showInfo("Finished: " + elapsedTimeAsString(runTime) + " seconds");
}
fTestResult= null;
fRun.setLabel("Run");
fRunner= null;
System.gc();
}
};
fRunner.start();
}
}
}
private boolean shouldReload() {
return !inVAJava() && fUseLoadingRunner.getState();
}
private void setLabelValue(Label label, int value) {
label.setText(Integer.toString(value));
label.invalidate();
label.getParent().validate();
}
public void setSuiteName(String suite) {
fSuiteField.setText(suite);
}
private void showErrorTrace() {
int index= fFailureList.getSelectedIndex();
if (index == -1)
return;
Throwable t= (Throwable) fExceptions.elementAt(index);
fTraceArea.setText(getFilteredTrace(t));
}
private void showInfo(String message) {
fStatusLine.setFont(PLAIN_FONT);
fStatusLine.setForeground(Color.black);
fStatusLine.setText(message);
}
protected void clearStatus() {
showStatus("");
}
private void showStatus(String status) {
fStatusLine.setFont(PLAIN_FONT);
fStatusLine.setForeground(Color.red);
fStatusLine.setText(status);
}
/**
* Starts the TestRunner
*/
public void start(String[] args) {
String suiteName= processArguments(args);
fFrame= createUI(suiteName);
fFrame.setLocation(200, 200);
fFrame.setVisible(true);
if (suiteName != null) {
setSuiteName(suiteName);
runSuite();
}
}
}