package monolipse.nunit.views;
import java.util.ArrayList;
import java.util.HashMap;
import monolipse.core.IAssemblySource;
import monolipse.core.foundation.Strings;
import monolipse.nunit.*;
import monolipse.nunit.launching.NUnitLauncher;
import monolipse.ui.*;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.viewers.*;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.ui.part.ViewPart;
public class NUnitView extends ViewPart {
static class TestInfo {
private String _testName;
private IAssemblySource _assemblySource;
private String _trace;
private boolean _isFailure;
public TestInfo() {
this(null, "");
}
public TestInfo(IAssemblySource assemblySource, String testName) {
this(assemblySource, testName, "", false);
}
public TestInfo(IAssemblySource assemblySource, String testName, String trace) {
this(assemblySource, testName, trace, true);
}
protected TestInfo(IAssemblySource assemblySource, String testName, String trace, boolean isFailure) {
_assemblySource = assemblySource;
_testName = testName;
_trace = trace;
_isFailure = isFailure;
}
public IAssemblySource getAssemblySource() {
return _assemblySource;
}
public String getTestName() {
return _testName;
}
public String getTrace() {
return _trace;
}
public boolean isFailure() {
return _isFailure;
}
public String[] splitName() {
String[] result = new String[3];
result[0] = result[1] = result[2] = "";
String[] splitted = _testName.split("\\.");
if (splitted.length > 2) {
for (int i = 0; i < splitted.length - 2; i++) {
result[0] = result[0] + splitted[i];
if (i != splitted.length - 3) {
result[0] += ".";
}
}
result[1] = splitted[splitted.length-2];
result[2] = splitted[splitted.length-1];
}
if (splitted.length == 2) {
result[0] = splitted[0];
result[1] = splitted[1];
}
if (splitted.length == 1) {
result[0] = splitted[0];
}
return result;
}
}
static class ResultNode {
private String _name;
private TestInfo _info;
private HashMap<String, ResultNode> _children;
private ResultNode _parent;
public ResultNode(String name, ResultNode parent, TestInfo info) {
_name = name;
_parent = parent;
_info = info;
_children = new HashMap<String, ResultNode>();
}
public String getName() {
return _name;
}
public ResultNode getParent() {
return _parent;
}
public TestInfo getInfo() {
return _info;
}
public HashMap<String, ResultNode> getChildren() {
return _children;
}
public void reset() {
_name = "";
_info = null;
_children = new HashMap<String, ResultNode>();
}
public IAssemblySource getAssemblySource() {
if (_info != null) {
return _info.getAssemblySource();
}
for(ResultNode node: _children.values()) {
if (node.getInfo() != null) {
return node.getInfo().getAssemblySource();
}
}
return null;
}
public ArrayList<ResultNode> getFailedNodes() {
return this.getFailedNodes(this);
}
private ArrayList<ResultNode> getFailedNodes(ResultNode root) {
ArrayList<ResultNode> result = new ArrayList<ResultNode>();
HashMap<String, ResultNode> target = root.getChildren();
for(ResultNode node: target.values()) {
if (node.hasFailures()) {
if (node.isEmpty())
result.add(node);
else
result.addAll(node.getFailedNodes());
}
}
return result;
}
public void add(TestInfo info) {
String[] names = info.splitName();
ResultNode root = null;
HashMap<String, ResultNode> target = _children;
for(String name: names) {
ResultNode next = null;
if (!target.containsKey(name)) {
next = new ResultNode(name, root, info);
target.put(name, next);
}
else
next = target.get(name);
root = next;
target = next.getChildren();
}
}
public boolean isEmpty() {
return _children.size() == 0;
}
public boolean hasFailures() {
if (_info != null && _info._isFailure)
return true;
for (ResultNode node: _children.values()) {
if (node.hasFailures())
return true;
}
return false;
}
}
private NUnitProgressBar _progressBar;
private CounterPanel _counterPanel;
private SashForm _sashForm;
private Composite _counterComposite;
private final TestListener _listener = new TestListener();
private final ResultNode _testRoot = new ResultNode("Root", null, null);
private StackTraceViewer _traceView;
private TreeViewer _testsView;
public NUnitView() {
}
public void createPartControl(Composite parent) {
GridLayout gridLayout = new GridLayout();
gridLayout.marginWidth = 0;
gridLayout.marginHeight = 0;
parent.setLayout(gridLayout);
_counterComposite = createProgressCountPanel(parent);
_counterComposite.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL
| GridData.HORIZONTAL_ALIGN_FILL));
SashForm sashForm = createSashForm(parent);
sashForm.setLayoutData(new GridData(GridData.FILL_BOTH));
NUnitPlugin.getDefault().addTestListener(_listener);
}
private SashForm createSashForm(Composite parent) {
_sashForm = new SashForm(parent, SWT.HORIZONTAL);
ViewForm left = new ViewForm(_sashForm, SWT.NONE);
ViewForm right = new ViewForm(_sashForm, SWT.NONE);
setFormLabel(left, "Tests");
setFormLabel(right, "Failure Trace");
createTestCasesView(left);
createTraceView(right);
_sashForm.setWeights(new int[] { 50, 50 });
return _sashForm;
}
private void createTestCasesView(ViewForm left) {
_testsView = new TreeViewer(left, SWT.FLAT);
_testsView.setContentProvider(new TestsContentProvider());
_testsView.setLabelProvider(new TestsLabelProvider());
_testsView.setInput(_testRoot);
_testsView.expandAll();
_testsView.addDoubleClickListener(new IDoubleClickListener() {
public void doubleClick(DoubleClickEvent event) {
Object element = ((IStructuredSelection) event
.getSelection()).getFirstElement();
if (null == element)
return;
rerunChildrenTests(((ResultNode) element));
}
});
_testsView.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
Object element = ((IStructuredSelection) event
.getSelection()).getFirstElement();
if (null == element)
return;
_traceView.setStackTrace(((ResultNode) element).getInfo()
.getTrace());
}
});
_testsView.getControl().setMenu(createFailureMenu(_testsView.getControl()));
left.setContent(_testsView.getControl());
}
private void createTraceView(ViewForm right) {
_traceView = new StackTraceViewer(right);
_traceView.setBackground(_testsView.getControl().getBackground());
right.setContent(_traceView.getControl());
}
private Menu createFailureMenu(final Control control) {
final Menu menu = new Menu(control);
final MenuItem rerunFailures = new MenuItem(menu, SWT.PUSH);
rerunFailures.setText("Rerun failed tests");
rerunFailures.addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent e) {
rerunLastFailures();
}
public void widgetDefaultSelected(SelectionEvent e) {
}
});
return menu;
}
protected void rerunLastFailures() {
if (!_testRoot.hasFailures())
return;
if (_testRoot.getAssemblySource() == null) {
NUnitPlugin.logInfo("Cant get AssemblySource");
return;
}
try {
NUnitPlugin.logInfo(Strings.commaSeparatedList(failedTestNames()));
NUnitLauncher.launch(_testRoot.getAssemblySource(),
"run", failedTestNames());
} catch (CoreException x) {
NUnitPlugin.logException(x);
}
}
protected void rerunChildrenTests(ResultNode resultNode) {
try {
ArrayList<String> childrenTestNames = childrenTestNames(resultNode);
if (childrenTestNames.size() == 0)
return;
NUnitPlugin.logInfo(Strings.commaSeparatedList(childrenTestNames));
NUnitLauncher.launch(_testRoot.getAssemblySource(),
"run", childrenTestNames);
} catch (CoreException x) {
NUnitPlugin.logException(x);
}
}
private ArrayList<String> childrenTestNames(ResultNode root) {
ArrayList<String> result = new ArrayList<String>();
if (root.isEmpty()) {
result.add(root.getInfo().getTestName());
return result;
}
for (ResultNode node: root.getChildren().values()) {
if (node.isEmpty())
result.add(node.getInfo().getTestName());
else
result.addAll(childrenTestNames(node));
}
return result;
}
private ArrayList<String> failedTestNames() {
ArrayList<String> result = new ArrayList<String>();
for(ResultNode node: _testRoot.getFailedNodes()) {
if (node.hasFailures() && node.isEmpty()) {
result.add(node.getInfo().getTestName());
}
}
return result;
}
private void setFormLabel(ViewForm form, final String labelText) {
CLabel label = new CLabel(form, SWT.NONE);
label.setText(labelText);
form.setTopLeft(label);
}
protected Composite createProgressCountPanel(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
composite.setLayout(layout);
layout.numColumns = 2;
_counterPanel = new CounterPanel(composite);
_counterPanel.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL
| GridData.HORIZONTAL_ALIGN_FILL));
_progressBar = new NUnitProgressBar(composite);
_progressBar.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL
| GridData.HORIZONTAL_ALIGN_FILL));
return composite;
}
public void dispose() {
super.dispose();
NUnitPlugin.getDefault().removeTestListener(_listener);
}
public void setFocus() {
}
private void selectFirstFailure() {
if (!_testRoot.hasFailures())
return;
for (ResultNode node: _testRoot.getFailedNodes()) {
_testsView.expandToLevel(node, AbstractTreeViewer.ALL_LEVELS);
}
_testsView.setSelection(new StructuredSelection(_testRoot.getFailedNodes().get(0)));
}
private void activateNUnitView() {
getSite().getPage().activate(NUnitView.this);
}
class TestListener implements ITestRunListener {
private int _errors;
private int _runs;
private int _failures;
private TestInfo _lastTest;
public void testsStarted(IAssemblySource source, final int testCount) {
updateUI(new Runnable() {
public void run() {
_testRoot.reset();
_runs = 0;
_errors = 0;
_failures = 0;
_lastTest = null;
_counterPanel.setTotal(testCount);
_progressBar.reset();
_progressBar.setMaximum(testCount);
_traceView.setStackTrace("");
}
});
}
public void testsFinished(IAssemblySource source) {
updateUI(new Runnable() {
public void run() {
activateNUnitView();
selectFirstFailure();
}
});
}
public void testStarted(final IAssemblySource source,
final String fullName) {
updateUI(new Runnable() {
public void run() {
if (_lastTest != null) {
_testRoot.add(_lastTest);
}
_lastTest = new TestInfo(source, fullName);
updateProgressBar();
++_runs;
}
});
}
public void testFailed(final IAssemblySource source,
final String fullName, final String trace) {
updateUI(new Runnable() {
public void run() {
_testRoot.add(new TestInfo(source, fullName, trace));
_failures++;
_lastTest = null;
_progressBar.refresh(failuresOccurred());
}
});
}
private void updateUI(final Runnable runnable) {
getDisplay().asyncExec(new Runnable() {
public void run() {
synchronized (TestListener.this) {
runnable.run();
updateUI();
}
}
});
}
private Display getDisplay() {
return _counterComposite.getDisplay();
}
private void updateUI() {
_counterPanel.setFailureValue(_failures);
_counterPanel.setRunValue(_runs);
_counterPanel.setErrorValue(_errors);
_testsView.refresh();
}
private void updateProgressBar() {
_progressBar.step(failuresOccurred());
}
private boolean failuresOccurred() {
return _failures != 0;
}
}
public class TestsContentProvider implements ITreeContentProvider {
public Object[] getChildren(Object element) {
return ((ResultNode)element).getChildren().values().toArray();
}
public Object[] getElements(Object element) {
return ((ResultNode)element).getChildren().values().toArray();
}
public boolean hasChildren(Object element) {
return getChildren(element).length > 0;
}
public Object getParent(Object element) {
return ((ResultNode)element).getParent();
}
public void dispose() {
}
public void inputChanged(Viewer viewer, Object old_input,
Object new_input) {
}
}
class TestsLabelProvider implements ILabelProvider {
private final Image _warningIcon = BooUI.getImage(IBooUIConstants.WARNING);
private final Image _successIcon = BooUI.getImage(IBooUIConstants.SUCCESS);
public void addListener(ILabelProviderListener listener) {
}
public void dispose() {
}
public boolean isLabelProperty(Object element, String property) {
return false;
}
public void removeListener(ILabelProviderListener listener) {
}
public Image getImage(Object element) {
return ((ResultNode)element).hasFailures() ? _warningIcon: _successIcon;
}
public String getText(Object element) {
return ((ResultNode)element).getName();
}
}
}