blob: 2d667b44b4099c28453f361d019964c6ff0bd8ad [file] [log] [blame]
package junit.ui;
import junit.framework.*;
import junit.util.*;
import java.util.Vector;
import java.lang.reflect.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
/**
* A simple user interface to run tests.
* Enter the name of a class with a suite method which should return
* the tests to be run.
* <pre>
* Synopsis: java java.ui.TestRunner [TestCase]
* </pre>
* TestRunner takes as an optional argument the name of the testcase class to be run.
*/
public class TestRunner extends Object implements TestListener {
private Frame fFrame;
private Vector fExceptions;
private Vector fFailedTests;
private Thread fRunner;
private TestResult fTestResult;
private TestSuiteLoader fTestLoader;
private TraceFrame fTraceFrame;
private TextField fSuiteField;
private Button fRun;
private ProgressBar fProgressIndicator;
private List fFailureList;
private Logo fLogo;
private Label fNumberOfErrors;
private Label fNumberOfFailures;
private Label fNumberOfRuns;
private Button fQuitButton;
private Button fShowErrorButton;
private Button fRerunButton;
private TextField fStatusLine;
private Panel fPanel;
private static Font PLAIN_FONT= new Font("dialog", Font.PLAIN, 12);
private static final int GAP= 4;
private static final String SUITE_METHODNAME= "suite";
public TestRunner() {
}
private void about() {
AboutDialog about= new AboutDialog(fFrame);
about.setModal(true);
about.setLocation(300, 300);
about.setVisible(true);
}
public void addError(Test test, Throwable t) {
fNumberOfErrors.setText(Integer.toString(fTestResult.errorCount()));
appendFailure("Error", test, t);
}
public void addFailure(Test test, Throwable t) {
fNumberOfFailures.setText(Integer.toString(fTestResult.failureCount()));
appendFailure("Failure", test, t);
}
private 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+= ":" + StringUtil.truncate(msg, 100);
}
fFailureList.add(kind);
fExceptions.addElement(t);
fFailedTests.addElement(test);
}
/**
* 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("Run Test Suite");
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("Enter the name of the TestCase class:");
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("");
}
}
);
Label suiteLabel2= new Label(".suite()");
fRun= new Button("Run");
fRun.setEnabled(false);
fRun.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
runSuite();
}
}
);
//---- second section
Label progressLabel= new Label("Progress:");
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= new Panel(new FlowLayout());
numbersPanel.add(new Label("Runs:")); numbersPanel.add(fNumberOfRuns);
numbersPanel.add(new Label(" Errors:")); numbersPanel.add(fNumberOfErrors);
numbersPanel.add(new Label(" Failures:")); numbersPanel.add(fNumberOfFailures);
//---- fourth section
Label failureLabel= new Label("Errors and Failures:");
fFailureList= new List(6);
fFailureList.addMouseListener(
new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() >= 2)
showErrorTrace();
}
}
);
fFailureList.addItemListener(
new ItemListener() {
public void itemStateChanged(ItemEvent e) {
fShowErrorButton.setEnabled(isErrorSelected());
fRerunButton.setEnabled(isErrorSelected());
}
}
);
fShowErrorButton= new Button("Show...");
fShowErrorButton.setEnabled(false);
fShowErrorButton.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
showErrorTrace();
}
}
);
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(fShowErrorButton);
failedPanel.add(fRerunButton);
//---- 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());
fPanel= panel;
addGrid(panel, suiteLabel, 0, 0, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST);
addGrid(panel, fSuiteField, 0, 1, 1, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST);
addGrid(panel, suiteLabel2, 1, 1, 1, GridBagConstraints.NONE, 0.0, GridBagConstraints.WEST);
addGrid(panel, fRun, 2, 1, 1, GridBagConstraints.HORIZONTAL, 0.0, GridBagConstraints.CENTER);
addGrid(panel, progressLabel, 0, 2, 2, GridBagConstraints.HORIZONTAL, 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.CENTER);
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, fStatusLine, 0, 7, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.CENTER);
addGrid(panel, fQuitButton, 2, 7, 1, GridBagConstraints.HORIZONTAL, 0.0, GridBagConstraints.CENTER);
frame.add(panel);
frame.pack();
return frame;
}
public void endTest(Test test) {
setLabelValue(fNumberOfRuns, fTestResult.runCount());
fProgressIndicator.step(fTestResult.wasSuccessful());
}
private Test getTest(String suiteClassName) {
if (suiteClassName.length() <= 0) {
fStatusLine.setText("");
return null;
}
Class testClass= null;
try {
testClass= loadSuiteClass(suiteClassName);
} catch(Exception e) {
runFailed("Class \""+suiteClassName+"\" not found");
return null;
}
Method suiteMethod= null;
try {
suiteMethod= testClass.getMethod(SUITE_METHODNAME, new Class[0]);
} catch(Exception e) {
// try to extract a test suite automatically
fStatusLine.setText("");
return new TestSuite(testClass);
}
Test test= null;
try {
test= (Test)suiteMethod.invoke(null, new Class[0]); // static method
if (test == null)
return test;
} catch(Exception e) {
runFailed("Could not invoke the suite() method");
return null;
}
fStatusLine.setText("");
return test;
}
private boolean isErrorSelected() {
return fFailureList.getSelectedIndex() != -1;
}
private Image loadFrameIcon() {
Toolkit toolkit= Toolkit.getDefaultToolkit();
try {
java.net.URL url= getClass().getResource("smalllogo.gif");
return toolkit.createImage((ImageProducer) url.getContent());
} catch (Exception ex) {
}
return null;
}
protected Class loadSuiteClass(String suiteClassName) throws ClassNotFoundException {
return fTestLoader.load(suiteClassName);
}
/**
* main entrypoint
*/
public static void main(String[] args) {
new TestRunner().start(args, new StandardTestSuiteLoader());
}
private void rerun() {
int index= fFailureList.getSelectedIndex();
if (index == -1)
return;
Test test= (Test)fFailedTests.elementAt(index);
if (!(test instanceof TestCase)) {
showInfo("Could not reload "+ test.toString());
return;
}
Test reloadedTest= null;
try {
Class reloadedTestClass= fTestLoader.reload(test.getClass());
Class[] classArgs= { String.class };
Constructor constructor= reloadedTestClass.getConstructor(classArgs);
Object[] args= new Object[]{((TestCase)test).name()};
reloadedTest=(Test)constructor.newInstance(args);
} 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();
fShowErrorButton.setEnabled(false);
fRerunButton.setEnabled(false);
fFailureList.removeAll();
fExceptions= new Vector(10);
fFailedTests= new Vector(10);
}
/**
* runs a suite.
* @deprecated use runSuite() instead
*/
public void run() {
runSuite();
}
private void runFailed(String message) {
showStatus(message);
fRun.setLabel("Run");
fRunner= null;
}
synchronized public void runSuite() {
if (fRunner != null) {
fTestResult.stop();
} else {
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: " + StringUtil.elapsedTimeAsString(runTime) + " seconds");
}
fTestResult= null;
fRun.setLabel("Run");
fRunner= null;
}
};
fRunner.start();
}
}
}
private void setLabelValue(Label label, int value) {
label.setText(Integer.toString(value));
}
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);
if (fTraceFrame == null) {
fTraceFrame= new TraceFrame();
fTraceFrame.setLocation(100, 100);
}
fTraceFrame.showTrace(t);
fTraceFrame.setVisible(true);
}
private void showInfo(String message) {
fStatusLine.setFont(PLAIN_FONT);
fStatusLine.setForeground(Color.black);
fStatusLine.setText(message);
}
private void showStatus(String status) {
fStatusLine.setFont(PLAIN_FONT);
fStatusLine.setForeground(Color.red);
fStatusLine.setText(status);
}
/**
* Starts the TestRunner
*/
public void start(String[] args, TestSuiteLoader loader) {
fTestLoader= loader;
String suiteName= null;
if (args.length == 1)
suiteName= args[0];
else if (args.length == 2 && args[0].equals("-c"))
suiteName= StringUtil.extractClassName(args[1]);
fFrame= createUI(suiteName);
fFrame.setLocation(200, 200);
fFrame.setVisible(true);
if (suiteName != null) {
setSuiteName(suiteName);
runSuite();
}
}
public void startTest(Test test) {
showInfo("Running: "+test);
}
}