package org.testng.eclipse.ui.summary;
import java.text.MessageFormat;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.testng.eclipse.ui.OpenTestAction;
import org.testng.eclipse.ui.RunInfo;
import org.testng.eclipse.ui.TestRunTab;
import org.testng.eclipse.ui.TestRunnerViewPart;
import org.testng.remote.strprotocol.SuiteMessage;
/**
* A view that shows a summary of the test run and allows the user to sort these results
* by timings, names, counts, etc...
*/
public class SummaryTab extends TestRunTab {
private Map<String, RunInfo> m_tests = Maps.newHashMap();
/** The table that contains all the tests */
private TableViewer m_testViewer;
/** A test result, updated whenever we receive a new test result */
static class TestResult {
Long time = 0L;
Set<String> methods = Sets.newHashSet();
Set<String> classes = Sets.newHashSet();
}
/** The model for the excluded method table */
private Map<String, TestResult> m_testResults = Maps.newHashMap();
/** The table that contains the excluded methods */
private TableViewer m_excludedMethodViewer;
/** The model for the excluded method table */
private List<ExcludedMethod> m_excludedMethodsModel = Lists.newArrayList();
// The filters for the two tables
private RunInfoFilter m_testSearchFilter;
private StringFilter m_excludedMethodFilter;
/** The id of the currently selected item */
private String m_selectedId;
private TestRunnerViewPart m_testRunnerPart;
@Override
public String getTooltipKey() {
return "Summary.tab.tooltip";
}
@Override
public String getNameKey() {
return "Summary.tab.title"; //$NON-NLS-1$
}
@Override
public Image getImage() {
return null;
}
@Override
public Composite createTabControl(Composite parent, TestRunnerViewPart runner) {
m_testRunnerPart = runner;
Composite result = new Composite(parent, SWT.NONE);
GridLayout gridLayout = new GridLayout();
gridLayout.numColumns = 1;
result.setLayout(gridLayout);
//
// Test table
//
{
createLabel(result, "Tests");
createTestViewer(result);
}
//
// Excluded methods
//
{
createLabel(result, "Excluded methods");
createExcludedMethodViewer(result);
}
return result;
}
private void createLabel(Composite parent, String text) {
Label result = new Label(parent, SWT.NONE);
result.setText(text);
result.setFont(JFaceResources.getBannerFont());
result.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false));
}
private void createExcludedMethodViewer(Composite result) {
m_excludedMethodFilter = new StringFilter();
m_excludedMethodViewer = createViewer(result,
new String[] { "Class name", "Method name", "Description" },
new int[] { 300, 250, 300 },
new StringTableSorter(this),
m_excludedMethodFilter
);
m_excludedMethodViewer.getTable().addMouseListener(new MouseAdapter() {
@Override
public void mouseDoubleClick(MouseEvent e) {
handleDoubleClick(e);
}
private void handleDoubleClick(MouseEvent e) {
TableItem[] items = ((Table) e.getSource()).getSelection();
if (items.length > 0) {
ExcludedMethod em = (ExcludedMethod) items[0].getData();
System.out.println("Double click " + em.packageName + "." + em.methodName);
OpenTestAction openAction
= new OpenTestAction(m_testRunnerPart, em.packageName, em.methodName,
true /* activate */);
openAction.run();
}
}
});
//
// Label provider
//
m_excludedMethodViewer.setLabelProvider(new ITableLabelProvider() {
public void removeListener(ILabelProviderListener listener) {
}
public boolean isLabelProperty(Object element, String property) {
return false;
}
public void dispose() {
}
public void addListener(ILabelProviderListener listener) {
}
public String getColumnText(Object element, int columnIndex) {
ExcludedMethod em = (ExcludedMethod) element;
switch(columnIndex) {
case 0: return em.packageName;
case 1: return em.methodName;
case 2: return em.description;
default: return "";
}
}
public Image getColumnImage(Object element, int columnIndex) {
return null;
}
});
//
// Content provider
//
m_excludedMethodViewer.setContentProvider(new IStructuredContentProvider() {
public void dispose() {
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
public Object[] getElements(Object inputElement) {
return ((List<String>) inputElement).toArray();
}
});
}
/**
* Parses the fully qualified name to extract the package and class name.
*
* @return an String array made of the package name and the class name
*/
private String[] parseFqn(String fqn) {
String packageName = fqn;
String className = fqn;
int ind = fqn.lastIndexOf(".");
if (ind >= 0) {
packageName = fqn.substring(0, ind);
className = fqn.substring(ind + 1);
}
return new String[] { packageName, className };
}
private void createTestViewer(Composite result) {
//
// Table sorter
//
m_testSearchFilter = new RunInfoFilter();
m_testViewer = createViewer(result,
new String[] { "Test name", "Time (seconds)", "Class count", "Method count" },
new int[] { 150, 150, 100, 100 },
new RunInfoTableSorter(this),
m_testSearchFilter
);
//
// Row selection
//
m_testViewer.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
ISelection selection = event.getSelection();
if (selection instanceof StructuredSelection) {
StructuredSelection ss = (StructuredSelection) selection;
RunInfo selected = ((RunInfo) ss.getFirstElement());
if (selected != null) {
String selectedId = ((RunInfo) ss.getFirstElement()).getTestId();
if (m_selectedId != null && !m_selectedId.startsWith(selectedId)) {
m_selectedId = selectedId;
}
}
}
}
});
//
// Content provider
//
m_testViewer.setContentProvider(new IStructuredContentProvider() {
public void dispose() {
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
public Object[] getElements(Object inputElement) {
return m_tests.values().toArray();
}
});
//
// Label provider
//
m_testViewer.setLabelProvider(new ITableLabelProvider() {
public void removeListener(ILabelProviderListener listener) {
}
public boolean isLabelProperty(Object element, String property) {
return false;
}
public void dispose() {
}
public void addListener(ILabelProviderListener listener) {
}
public String getColumnText(Object element, int columnIndex) {
RunInfo runInfo = (RunInfo) element;
String testId = runInfo.getTestId();
switch(columnIndex) {
case 0: return ((RunInfo) element).getTestName();
case 1: return MessageFormat.format("{0}", ((float) getTestTime(testId)) / 1000);
case 2: return Integer.toString(getTestClassCount(testId));
case 3: return Integer.toString(getTestMethodCount(testId));
default: return "";
}
}
public Image getColumnImage(Object element, int columnIndex) {
return null;
}
});
m_testViewer.setInput(m_tests);
}
private TableViewer createViewer(Composite parent, String[] columns, int[] bounds,
final AbstractTableSorter tableSorter, ViewerFilter filter) {
final TableViewer result = new TableViewer(parent);
final Table table = result .getTable();
table.setHeaderVisible(true);
table.setLinesVisible(true);
table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
result.setSorter(tableSorter);
for (int i = 0; i < columns.length; i++) {
final int index = i;
TableViewerColumn viewerColumn = new TableViewerColumn(result, SWT.NONE);
final TableColumn column = viewerColumn.getColumn();
column.setText(columns[i]);
column.setWidth(bounds[i]);
column.setResizable(true);
column.setMoveable(true);
column.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (tableSorter != null) {
tableSorter.setColumn(index);
}
int dir = table.getSortDirection();
if (table.getSortColumn() == column) {
dir = dir == SWT.UP ? SWT.DOWN : SWT.UP;
} else {
dir = SWT.DOWN;
}
table.setSortDirection(dir);
table.setSortColumn(column);
result.refresh(); }
});
}
//
// Filter
//
result.setFilters(new ViewerFilter[] { filter });
return result;
}
protected int getTestMethodCount(String testId) {
return m_testResults.get(testId).methods.size();
}
public long getTestTime(String testId) {
return m_testResults.get(testId).time;
}
public int getTestClassCount(String testId) {
return m_testResults.get(testId).classes.size();
}
@Override
public String getSelectedTestId() {
return m_selectedId;
}
@Override
public void setSelectedTest(String id) {
if (id == null) return;
m_selectedId = id;
// We might be receiving the id of a method, but we only store test names,
// so just find the name of the test that contains this method and select
// the corresponding row. Note that we still store the original id so that
// when the user switches to a different tab, their selection there remains
// untouched.
for (String test : m_testResults.keySet()) {
if (id.startsWith(test)) {
m_testViewer.setSelection(new StructuredSelection(m_tests.get(test)));
}
}
}
@Override
public void updateTestResult(RunInfo runInfo, boolean expand) {
//
// Update tests
//
String testId = runInfo.getTestId();
m_tests.put(testId, runInfo);
TestResult tr = m_testResults.get(testId);
if (tr == null) {
tr = new TestResult();
m_testResults.put(testId, tr);
}
tr.time += runInfo.getTime();
tr.methods.add(runInfo.getMethodId());
tr.classes.add(runInfo.getClassId());
m_testViewer.refresh();
}
@Override
public void updateTestResult(List<RunInfo> results) {
if (results.size() > 0) {
aboutToStart(); // do a reset
for (RunInfo ri : results) {
updateTestResult(ri, false /* unused param in this tab */);
}
}
}
@Override
public void aboutToStart() {
m_tests.clear();
m_testResults.clear();
m_testViewer.refresh();
m_excludedMethodViewer.getTable().clearAll();
}
@Override
public void updateSearchFilter(String text) {
m_testSearchFilter.setFilter(text);
m_testViewer.refresh();
m_excludedMethodFilter.setFilter(text);
m_excludedMethodViewer.refresh();
}
private class ExcludedMethod {
public String packageName;
public String methodName;
public String description;
}
public void setExcludedMethodsModel(final SuiteMessage message) {
m_excludedMethodsModel.clear();
for (String method : message.getExcludedMethods()) {
ExcludedMethod em = new ExcludedMethod();
String[] parsed = parseFqn(method);
em.packageName = parsed[0];
em.methodName = parsed[1];
em.description = message.getDescriptionForMethod(method);
m_excludedMethodsModel.add(em);
}
m_excludedMethodViewer.getTable().getDisplay().syncExec(new Runnable() {
public void run() {
m_excludedMethodViewer.setInput(m_excludedMethodsModel);
m_excludedMethodViewer.refresh();
}
});
}
}