/*
* Copyright 2010-2011, Sikuli.org
* Released under the MIT License.
*
*/
package org.sikuli.ide.z_notused.sikuli_test;
import org.sikuli.ide.SikuliIDE;
import java.util.Vector;
import java.util.HashMap;
import java.util.Enumeration;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.*;
import javax.swing.event.*;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestFailure;
import junit.framework.TestResult;
import junit.framework.TestSuite;
import junit.runner.BaseTestRunner;
import junit.runner.FailureDetailView;
import junit.runner.SimpleTestCollector;
import junit.runner.TestCollector;
import junit.runner.TestRunListener;
import junit.runner.StandardTestSuiteLoader;
import junit.runner.TestSuiteLoader;
import org.sikuli.script.Debug;
import java.io.PrintStream;
import java.io.File;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import org.python.util.PythonInterpreter;
import org.python.core.*;
public class UnitTestRunner extends BaseTestRunner implements TestRunContext{
private static final int GAP= 4;
private JFrame minFrame;
private JPanel mainPane, minPane;
private JToolBar toolbar;
private JButton fRun;
private ProgressBar fProgressIndicator;
private CounterPanel fCounterPanel;
private JTabbedPane fTestViewTab;
private FailureDetailView fFailureView;
private JScrollPane tracePane;
private Vector fTestRunViews= new Vector(); // view associated with tab in tabbed pane
private DefaultListModel fFailures;
private Thread fRunner;
private TestResult fTestResult;
//private HashMap<String, Integer> _lineNoOfTest;
public JComponent getTracePane(){ return tracePane; }
public JPanel getPanel(){
return mainPane;
}
public JFrame getMinFrame(){
return minFrame;
}
private JToolBar initToolbar(){
JToolBar toolbar = new JToolBar();
toolbar.setFloatable(false);
fRun = createRunButton();
toolbar.add(fRun);
return toolbar;
}
protected JButton createRunButton() {
JButton run= new JButton("Run");
run.setEnabled(true);
run.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
runSuite();
}
}
);
return run;
}
protected CounterPanel createCounterPanel() {
return new CounterPanel();
}
protected JTabbedPane createTestRunViews() {
JTabbedPane pane= new JTabbedPane();
FailureRunView lv= new FailureRunView(this);
fTestRunViews.addElement(lv);
lv.addTab(pane);
TestHierarchyRunView tv= new TestHierarchyRunView(this);
fTestRunViews.addElement(tv);
tv.addTab(pane);
pane.addChangeListener(
new ChangeListener() {
public void stateChanged(ChangeEvent e) {
testViewChanged();
}
}
);
return pane;
}
public void testViewChanged() {
TestRunView view= (TestRunView)fTestRunViews.elementAt(fTestViewTab.getSelectedIndex());
view.activate();
}
private void initComponents(){
toolbar = initToolbar();
/*
if (inMac())
fProgressIndicator= new MacProgressBar(fStatusLine);
else
*/
fProgressIndicator= new ProgressBar();
fCounterPanel= createCounterPanel();
fFailures= new DefaultListModel();
fTestViewTab= createTestRunViews();
fFailureView= createFailureDetailView();
tracePane= new JScrollPane(fFailureView.getComponent(), ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
initMinFrame();
}
private void initMinFrame(){
minFrame = new JFrame("Sikuli Test");
minFrame.setAlwaysOnTop(true);
minFrame.setSize(255, 85);
minFrame.getRootPane().putClientProperty("Window.alpha", new Float(0.7f));
/*
Container con = minFrame.getContentPane();
con.add(minPane);
minFrame.doLayout();
minFrame.setVisible(true);
*/
}
private static final String FAILUREDETAILVIEW_KEY= "FailureViewClass";
protected FailureDetailView createFailureDetailView() {
String className= BaseTestRunner.getPreference(FAILUREDETAILVIEW_KEY);
if (className != null) {
Class viewClass= null;
try {
viewClass= Class.forName(className);
return (FailureDetailView)viewClass.newInstance();
} catch(Exception e) {
JOptionPane.showMessageDialog(mainPane, "Could not create Failure DetailView - using default view");
}
}
return new DefaultFailureDetailView();
}
public UnitTestRunner(){
mainPane = new JPanel(new GridBagLayout());
mainPane.setMinimumSize(new Dimension(0,0));
mainPane.setPreferredSize(new Dimension(270,200));
minPane = new JPanel(new GridBagLayout());
initComponents();
addGrid(mainPane, toolbar, 0, 0, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST);
addGrid(mainPane, new JSeparator(), 0, 1, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST);
addGrid(mainPane, fCounterPanel, 0, 2, 2, GridBagConstraints.NONE, 0.0, GridBagConstraints.WEST);
addGrid(mainPane, fProgressIndicator, 0, 3, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST);
addGrid(mainPane, new JSeparator(), 0, 5, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST);
addGrid(mainPane, new JLabel("Results:"), 0, 6, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST);
addGrid(mainPane, fTestViewTab, 0, 7, 2, GridBagConstraints.BOTH, 1.0, GridBagConstraints.WEST);
//_lineNoOfTest = new HashMap<String, Integer>();
}
void addMinComponentsToPane(JPanel pane){
addGrid(pane, toolbar, 0, 0, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST);
addGrid(pane, fCounterPanel, 0, 2, 2, GridBagConstraints.NONE, 0.0, GridBagConstraints.WEST);
addGrid(pane, fProgressIndicator, 0, 3, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST);
}
private void addGrid(JPanel 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 ? 10 : 0, GAP, GAP, GAP);
p.add(co, c);
}
public ListModel getFailures() {
return fFailures;
}
public void handleTestSelected(Test test){
moveCursorToTest(test);
showFailureDetail(test);
}
private void moveCursorToTest(Test test){
if( test instanceof TestCase ){
String func = ((TestCase)test).getName();
try{
SikuliIDE.getInstance().jumpTo(func);
}
catch(BadLocationException e){
e.printStackTrace();
}
}
}
private void showFailureDetail(Test test) {
if (test != null) {
ListModel failures= getFailures();
for (int i= 0; i < failures.getSize(); i++) {
TestFailure failure= (TestFailure)failures.getElementAt(i);
if (failure.failedTest() == test) {
fFailureView.showFailure(failure);
return;
}
}
}
fFailureView.clear();
}
synchronized public void runSuite() {
SikuliIDE ide = SikuliIDE.getInstance();
if (fRunner != null) {
fTestResult.stop();
showIDE(true);
} else {
try{
showIDE(false);
reset();
String filename = ide.getCurrentFilename();
String path = ide.getCurrentBundlePath();
Test suite = genTestSuite(filename, path);
doRun(suite);
}
catch(IOException e){
e.printStackTrace();
showIDE(true);
}
}
}
private void showInfo(String message) {
//fStatusLine.showInfo(message);
System.out.println(message);
}
private void postInfo(final String message) {
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
showInfo(message);
}
}
);
}
protected void reset() {
fCounterPanel.reset();
fProgressIndicator.reset();
fFailureView.clear();
fFailures.clear();
}
private void setButtonLabel(final JButton button, final String label) {
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
button.setText(label);
}
}
);
}
protected void runFinished(final Test testSuite) {
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
for (Enumeration e= fTestRunViews.elements(); e.hasMoreElements(); ) {
TestRunView v= (TestRunView) e.nextElement();
v.runFinished(testSuite, fTestResult);
}
}
}
);
}
public static final int SUCCESS_EXIT= 0;
public static final int FAILURE_EXIT= 1;
public static final int EXCEPTION_EXIT= 2;
public TestSuiteLoader getLoader() {
return new StandardTestSuiteLoader();
}
private void revealFailure(Test test) {
for (Enumeration e= fTestRunViews.elements(); e.hasMoreElements(); ) {
TestRunView v= (TestRunView) e.nextElement();
v.revealFailure(test);
}
}
private void appendFailure(Test test, Throwable t) {
fFailures.addElement(new TestFailure(test, t));
if (fFailures.size() == 1)
revealFailure(test);
}
public void testFailed(final int status, final Test test, final Throwable t) {
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
switch (status) {
case TestRunListener.STATUS_ERROR:
fCounterPanel.setErrorValue(fTestResult.errorCount());
appendFailure(test, t);
break;
case TestRunListener.STATUS_FAILURE:
fCounterPanel.setFailureValue(fTestResult.failureCount());
appendFailure(test, t);
break;
}
}
}
);
}
public void testStarted(String testName) {
Debug.log(8,"test started: " + testName);
}
public void testEnded(String testName) {
Debug.log(8,"test ended: " + testName);
synchUI();
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
if (fTestResult != null) {
fCounterPanel.setRunValue(fTestResult.runCount());
fProgressIndicator.step(fTestResult.runCount(), fTestResult.wasSuccessful());
}
}
}
);
}
private void synchUI() {
try {
SwingUtilities.invokeAndWait(
new Runnable() {
public void run() {}
}
);
}
catch (Exception e) {
}
}
protected TestResult createTestResult() {
return new TestResult();
}
private void doRun(final Test testSuite) {
setButtonLabel(fRun, "Stop");
fRunner= new Thread("TestRunner-Thread") {
public void run() {
UnitTestRunner.this.start(testSuite);
postInfo("Running...");
long startTime= System.currentTimeMillis();
testSuite.run(fTestResult);
if (fTestResult.shouldStop()) {
postInfo("Stopped");
} else {
long endTime= System.currentTimeMillis();
long runTime= endTime-startTime;
postInfo("Finished: " + elapsedTimeAsString(runTime) + " seconds");
}
runFinished(testSuite);
setButtonLabel(fRun, "Run");
showIDE(true);
fRunner= null;
System.gc();
}
};
// make sure that the test result is created before we start the
// test runner thread so that listeners can register for it.
fTestResult= createTestResult();
fTestResult.addListener(UnitTestRunner.this);
aboutToStart(testSuite);
fRunner.start();
}
private void showIDE(boolean show){
SikuliIDE.getInstance().setVisible(show);
if(show){
addMinComponentsToPane(mainPane);
}
else{
addMinComponentsToPane(minPane);
Container con = minFrame.getContentPane();
con.add(minPane);
minFrame.doLayout();
}
minFrame.setVisible(!show);
}
protected void aboutToStart(final Test testSuite) {
for (Enumeration e= fTestRunViews.elements(); e.hasMoreElements(); ) {
TestRunView v= (TestRunView) e.nextElement();
v.aboutToStart(testSuite, fTestResult);
}
}
private void start(final Test test) {
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
int total= test.countTestCases();
fProgressIndicator.start(total);
fCounterPanel.setTotal(total);
}
}
);
}
private String genTestClassName(String filename){
String fname = new File(filename).getName();
int dot = fname.indexOf(".");
return fname.substring(0, dot);
}
private Test genTestSuite(String filename, String bundlePath) throws IOException{
String className = genTestClassName(filename);
TestSuite ret = new TestSuite(className);
PythonInterpreter interp = new PythonInterpreter();
String testCode =
"# coding=utf-8\n"+
"from __future__ import with_statement\n"+
"import junit\n"+
"from junit.framework.Assert import *\n"+
"from sikuli.Sikuli import *\n"+
"class "+className+" (junit.framework.TestCase):\n"+
"\tdef __init__(self, name):\n"+
"\t\tjunit.framework.TestCase.__init__(self,name)\n"+
"\t\tself.theTestFunction = getattr(self,name)\n"+
"\t\tsetBundlePath('"+bundlePath+"')\n"+
"\tdef runTest(self):\n"+
"\t\tself.theTestFunction()\n";
BufferedReader in = new BufferedReader(new FileReader(filename));
String line;
//int lineNo = 0;
//Pattern patDef = Pattern.compile("def\\s+(\\w+)\\s*\\(");
while( (line = in.readLine()) != null ){
// lineNo++;
testCode += "\t" + line + "\n";
/*
Matcher matcher = patDef.matcher(line);
if(matcher.find()){
String func = matcher.group(1);
Debug.log("Parsed " + lineNo + ": " + func);
_lineNoOfTest.put( func, lineNo );
}
*/
}
interp.exec(testCode);
PyList tests = (PyList)interp.eval(
"["+className+"(f) for f in dir("+className+") if f.startswith(\"test\")]");
while( tests.size() > 0 ){
PyObject t = tests.pop();
Test t2 = (Test)(t).__tojava__(TestCase.class);
ret.addTest( t2 );
}
return ret;
}
protected void runFailed(String message) {
System.err.println(message);
fRunner= null;
}
}