blob: e3c7e8f3b39353c23373172984906f1c6e939061 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015 Christian Pontesegger and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* Contributors:
* Christian Pontesegger - initial API and implementation
*******************************************************************************/
package org.eclipse.ease.lang.unittest.ui.views;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.ease.Logger;
import org.eclipse.ease.debugging.IScriptDebugFrame;
import org.eclipse.ease.debugging.ScriptStackTrace;
import org.eclipse.ease.lang.unittest.TestSuiteScriptEngine;
import org.eclipse.ease.lang.unittest.runtime.IMetadata;
import org.eclipse.ease.lang.unittest.runtime.IRuntimePackage;
import org.eclipse.ease.lang.unittest.runtime.ITest;
import org.eclipse.ease.lang.unittest.runtime.ITestClass;
import org.eclipse.ease.lang.unittest.runtime.ITestContainer;
import org.eclipse.ease.lang.unittest.runtime.ITestEntity;
import org.eclipse.ease.lang.unittest.runtime.ITestFile;
import org.eclipse.ease.lang.unittest.runtime.ITestResult;
import org.eclipse.ease.lang.unittest.runtime.ITestSuite;
import org.eclipse.ease.lang.unittest.runtime.TestStatus;
import org.eclipse.ease.lang.unittest.ui.Activator;
import org.eclipse.ease.lang.unittest.ui.sourceprovider.TestSuiteSource;
import org.eclipse.ease.ui.tools.DecoratedLabelProvider;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.ecore.util.EContentAdapter;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.layout.TreeColumnLayout;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.LocalResourceManager;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.ITreeSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.TreeViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.window.ToolTip;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
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.Menu;
import org.eclipse.swt.widgets.ProgressBar;
import org.eclipse.ui.IEditorDescriptor;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.editors.text.EditorsUI;
import org.eclipse.ui.handlers.CollapseAllHandler;
import org.eclipse.ui.handlers.ExpandAllHandler;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.ui.progress.UIJob;
import org.eclipse.ui.texteditor.ITextEditor;
public class UnitTestView extends ViewPart {
public static final String VIEW_ID = "org.eclipse.ease.views.unittest";
public static final String TEST_STATUS_PROPERTY = "test status";
private class TestEntityContentProvider implements ITreeContentProvider {
@Override
public Object[] getElements(Object inputElement) {
return getChildren(inputElement);
}
@Override
public Object[] getChildren(Object parentElement) {
final List<Object> children = new ArrayList<>();
if (parentElement instanceof ITestEntity) {
children.addAll(((ITestEntity) parentElement).getMetadata());
if ((!(parentElement instanceof ITest)) || (((ITestEntity) parentElement).getResults().size() > 1))
children.addAll(((ITestEntity) parentElement).getResults());
if (parentElement instanceof ITestContainer) {
for (final ITestEntity child : ((ITestContainer) parentElement).getCopyOfChildren()) {
if (child instanceof ITest)
children.add(child);
}
}
}
return children.toArray();
}
@Override
public Object getParent(Object element) {
if (element instanceof ITestEntity)
return ((ITestEntity) element).getParent();
return null;
}
@Override
public boolean hasChildren(Object element) {
if (element instanceof ITestEntity) {
if (!((ITestEntity) element).getMetadata().isEmpty())
return true;
if (((ITestEntity) element).getResults().size() > 1)
return true;
if (!(element instanceof ITest) && (!((ITestEntity) element).getResults().isEmpty()))
return true;
if (element instanceof ITestContainer) {
for (final Object child : ((ITestContainer) element).getCopyOfChildren()) {
if (child instanceof ITest)
return true;
}
}
}
return false;
}
}
/**
* Opens the given resource in an editor. Needs to be run from the UI thread.
*
* @param resource
* resource to open
* @param lineNumber
* line number to jump to in editor
*/
public static void openEditor(Object resource, int lineNumber) {
if (resource instanceof IFile) {
IEditorDescriptor descriptor = PlatformUI.getWorkbench().getEditorRegistry().getDefaultEditor(((IFile) resource).getName());
if (descriptor == null)
descriptor = PlatformUI.getWorkbench().getEditorRegistry().findEditor(EditorsUI.DEFAULT_TEXT_EDITOR_ID);
if (descriptor != null) {
final IEditorDescriptor editorDescriptor = descriptor;
try {
final IEditorPart editor = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage()
.openEditor(new FileEditorInput((IFile) resource), editorDescriptor.getId());
if ((lineNumber > 0) && (editor instanceof ITextEditor)) {
final IDocument document = ((ITextEditor) editor).getDocumentProvider().getDocument(editor.getEditorInput());
try {
((ITextEditor) editor).selectAndReveal(document.getLineOffset(lineNumber - 1), document.getLineLength(lineNumber - 1));
} catch (final BadLocationException e) {
// failed to open editor at corresponding line number
}
}
} catch (final PartInitException e) {
Logger.error(Activator.PLUGIN_ID, "Could not open editor for <" + resource + ">", e);
}
}
}
}
private static int getTestFileCount(ITestContainer testContainer) {
if (testContainer instanceof ITestFile)
return 1;
int files = 0;
for (final ITestContainer child : testContainer.getChildContainers())
files += getTestFileCount(child);
return files;
}
/**
* @param stackTrace
*/
private static boolean openEditor(ScriptStackTrace stackTrace) {
if (stackTrace != null) {
for (final IScriptDebugFrame trace : stackTrace) {
if (trace.getScript() != null) {
if (trace.getScript().getCommand() instanceof IFile) {
openEditor(trace.getScript().getCommand(), trace.getLineNumber());
return true;
}
if (trace.getScript().getCommand() instanceof File) {
openEditor(trace.getScript().getCommand(), trace.getLineNumber());
return true;
}
}
}
}
return false;
}
private ProgressBar fProgressBar;
private TreeViewer fFileTreeViewer;
private TreeViewer fTestTreeViewer;
private SashForm sashForm;
private int[] fSashWeights = new int[] { 70, 30 };
private CollapseAllHandler fCollapseAllHandler;
private ExpandAllHandler fExpandAllHandler;
private LocalResourceManager fResourceManager;
private Label lblErrorCount;
private Label lblFailureCount;
private SuiteRuntimeInformation fRuntimeInformation = null;
private TestSuiteScriptEngine fCurrentEngine;
/** Counts errors during test execution. */
private int fErrorCount = 0;
/** Counts failures during test execution. */
private int fFailureCount = 0;
/** Counts finished test files during test execution. */
private int fFinishedFileCount = 0;
public UnitTestView() {
}
@Override
public void createPartControl(final Composite parent) {
parent.setLayout(new GridLayout(1, false));
final Composite composite = new Composite(parent, SWT.NONE);
final GridLayout gl_composite = new GridLayout(6, false);
gl_composite.verticalSpacing = 0;
composite.setLayout(gl_composite);
composite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
fResourceManager = new LocalResourceManager(JFaceResources.getResources(), composite);
fLblDuration = new Label(composite, SWT.NONE);
fLblDuration.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 6, 1));
fLblDuration.setText("");
final Label label = new Label(composite, SWT.SEPARATOR | SWT.HORIZONTAL);
label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 6, 1));
final Label lblErrorIcon = new Label(composite, SWT.NONE);
final GridData gdLblErrorIcon = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1);
gdLblErrorIcon.verticalIndent = 10;
gdLblErrorIcon.horizontalIndent = 50;
lblErrorIcon.setLayoutData(gdLblErrorIcon);
lblErrorIcon.setImage(fResourceManager.createImage(Activator.getImageDescriptor(Activator.PLUGIN_ID, "/icons/eobj16/status_error.png")));
lblErrorIcon.setToolTipText("Exceptions and fatal execution errors.");
final Label lblErrors = new Label(composite, SWT.NONE);
final GridData gd_lblErrors = new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1);
gd_lblErrors.verticalIndent = 10;
lblErrors.setLayoutData(gd_lblErrors);
lblErrors.setAlignment(SWT.CENTER);
lblErrors.setText("Errors:");
lblErrors.setToolTipText("Exceptions and fatal execution errors.");
lblErrorCount = new Label(composite, SWT.NONE);
final GridData gd_lblErrorCount = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1);
gd_lblErrorCount.verticalIndent = 10;
gd_lblErrorCount.horizontalIndent = 20;
lblErrorCount.setLayoutData(gd_lblErrorCount);
final Label lblFailureIcon = new Label(composite, SWT.NONE);
final GridData gdLblFailureIcon = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1);
gdLblFailureIcon.verticalIndent = 10;
gdLblFailureIcon.horizontalIndent = 50;
lblFailureIcon.setLayoutData(gdLblFailureIcon);
lblFailureIcon.setImage(fResourceManager.createImage(Activator.getImageDescriptor(Activator.PLUGIN_ID, "/icons/eobj16/status_failure.png")));
lblFailureIcon.setToolTipText("Failed test assertions.");
final Label lblFailures = new Label(composite, SWT.NONE);
final GridData gd_lblFailures = new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1);
gd_lblFailures.verticalIndent = 10;
lblFailures.setLayoutData(gd_lblFailures);
lblFailures.setAlignment(SWT.CENTER);
lblFailures.setText("Failures:");
lblFailures.setToolTipText("Failed test assertions.");
lblFailureCount = new Label(composite, SWT.NONE);
final GridData gdLblFailureCount = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1);
gdLblFailureCount.verticalIndent = 10;
gdLblFailureCount.horizontalIndent = 20;
lblFailureCount.setLayoutData(gdLblFailureCount);
fProgressBar = new ProgressBar(parent, SWT.NONE);
fProgressBar.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
sashForm = new SashForm(parent, SWT.NONE);
sashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
sashForm.setOrientation(SWT.VERTICAL);
fFileTreeViewer = new TreeViewer(sashForm, SWT.BORDER | SWT.MULTI);
fFileTreeViewer.setContentProvider(new TestSuiteContentProvider());
fFileTreeViewer.setFilters(new ViewerFilter() {
@Override
public boolean select(Viewer viewer, Object parentElement, Object element) {
return (element instanceof ITestContainer);
}
});
fFileTreeViewer.setComparator(new ViewerComparator() {
@Override
public int category(Object element) {
return (element instanceof ITestFile) ? 1 : 0;
}
});
// use a decorated label provider
final LabelProvider provider = new TestSuiteLabelProvider(fResourceManager);
fFileTreeViewer.setLabelProvider(new DecoratedLabelProvider(provider));
fFileTreeViewer.addDoubleClickListener(event -> {
final Object element = ((IStructuredSelection) event.getSelection()).getFirstElement();
if (element instanceof ITestSuite)
openEditor(((ITestSuite) element).getResource(), 0);
if (element instanceof ITestFile)
openEditor(((ITestFile) element).getResource(), 0);
if (element instanceof ITestClass)
openEditor(((ITestClass) element).getStackTrace());
});
// a changed selection will update the test detail part
fFileTreeViewer.addSelectionChangedListener(event -> {
final ITreeSelection selection = (ITreeSelection) event.getSelection();
final Object element = selection.getFirstElement();
if ((element instanceof ITestFile) || (element instanceof ITestClass) || (element instanceof ITestSuite)) {
// test set selected
fTestTreeViewer.setInput(element);
if (sashForm.getWeights()[1] == 0)
sashForm.setWeights(fSashWeights);
fTestTreeViewer.refresh();
} else {
// test container selected, or no selection at all
fTestTreeViewer.setInput(null);
if (sashForm.getWeights()[1] != 0)
fSashWeights = sashForm.getWeights();
sashForm.setWeights(new int[] { 100, 0 });
}
});
// create tree viewer for tests
fTestTreeViewer = createTestArea(sashForm);
sashForm.setWeights(new int[] { 1, 1 });
// add context menu support
final MenuManager menuManager = new MenuManager();
final Menu menu = menuManager.createContextMenu(fFileTreeViewer.getTree());
fFileTreeViewer.getControl().setMenu(menu);
getSite().registerContextMenu(menuManager, fFileTreeViewer);
final MenuManager menuManager2 = new MenuManager();
final Menu menu2 = menuManager2.createContextMenu(fFileTreeViewer.getTree());
fTestTreeViewer.getControl().setMenu(menu2);
getSite().registerContextMenu(menuManager2, fTestTreeViewer);
// add collapseAll/expandAll handlers
final IHandlerService handlerService = getSite().getService(IHandlerService.class);
fCollapseAllHandler = new CollapseAllHandler(fFileTreeViewer);
handlerService.activateHandler(CollapseAllHandler.COMMAND_ID, fCollapseAllHandler);
fExpandAllHandler = new ExpandAllHandler(fFileTreeViewer);
handlerService.activateHandler(ExpandAllHandler.COMMAND_ID, fExpandAllHandler);
// menuManager.setRemoveAllWhenShown(true);
final MultiSelectionProvider selectionProvider = new MultiSelectionProvider();
selectionProvider.addSelectionProvider(fFileTreeViewer);
selectionProvider.addSelectionProvider(fTestTreeViewer);
getSite().setSelectionProvider(selectionProvider);
}
private TreeViewer createTestArea(final Composite parent) {
final Composite composite = new Composite(parent, SWT.NONE);
final TreeColumnLayout layout = new TreeColumnLayout();
composite.setLayout(layout);
final TreeViewer viewer = new TreeViewer(composite, SWT.BORDER | SWT.FULL_SELECTION);
// open resource on the corresponding location a double click
viewer.addDoubleClickListener(event -> {
final Object element = ((IStructuredSelection) event.getSelection()).getFirstElement();
if (element instanceof ITest) {
boolean editorOpen = false;
if ((TestStatus.ERROR.equals(((ITest) element).getStatus())) || (TestStatus.FAILURE.equals(((ITest) element).getStatus()))) {
final ITestResult result = ((ITest) element).getWorstResult();
if (result != null)
editorOpen = openEditor(result.getStackTrace());
}
if (!editorOpen)
editorOpen = openEditor(((ITest) element).getStackTrace());
}
});
viewer.getTree().setHeaderVisible(true);
viewer.getTree().setLinesVisible(true);
viewer.setContentProvider(new TestEntityContentProvider());
final TreeViewerColumn testColumn = new TreeViewerColumn(viewer, SWT.NONE);
testColumn.getColumn().setWidth(100);
testColumn.getColumn().setText("Test");
layout.setColumnData(testColumn.getColumn(), new ColumnWeightData(30, 50, true));
testColumn.setLabelProvider(new ColumnLabelProvider() {
@Override
public String getText(final Object element) {
if (element instanceof ITestEntity)
return super.getText(((ITestEntity) element).getName());
else if (element instanceof IMetadata)
return super.getText(((IMetadata) element).getKey());
else if (element instanceof ITestResult)
return ((ITestResult) element).getStatus().toString();
return super.getText(element);
}
@Override
public Image getImage(Object element) {
if (element instanceof ITestEntity)
element = ((ITestEntity) element).getStatus();
else if (element instanceof ITestResult)
element = ((ITestResult) element).getStatus();
else if (element instanceof IMetadata)
return fResourceManager.createImage(Activator.getImageDescriptor(Activator.PLUGIN_ID, "/icons/eobj16/metadata.png"));
if (element instanceof TestStatus) {
switch ((TestStatus) element) {
case PASS:
return fResourceManager.createImage(Activator.getImageDescriptor(Activator.PLUGIN_ID, "/icons/eobj16/status_pass.png"));
case FAILURE:
return fResourceManager.createImage(Activator.getImageDescriptor(Activator.PLUGIN_ID, "/icons/eobj16/status_failure.png"));
case ERROR:
return fResourceManager.createImage(Activator.getImageDescriptor(Activator.PLUGIN_ID, "/icons/eobj16/status_error.png"));
case RUNNING:
return fResourceManager.createImage(Activator.getImageDescriptor(Activator.PLUGIN_ID, "/icons/eobj16/status_running.png"));
case DISABLED:
return fResourceManager.createImage(Activator.getImageDescriptor(Activator.PLUGIN_ID, "/icons/eobj16/status_ignore.png"));
default:
return super.getImage(element);
}
}
return super.getImage(element);
}
@Override
public String getToolTipText(final Object element) {
if (element instanceof ITestEntity)
return ((ITestEntity) element).getDescription();
return super.getToolTipText(element);
}
});
final TreeViewerColumn messageColumn = new TreeViewerColumn(viewer, SWT.NONE);
messageColumn.getColumn().setWidth(100);
messageColumn.getColumn().setText("Description/Status");
layout.setColumnData(messageColumn.getColumn(), new ColumnWeightData(70, 50, true));
messageColumn.setLabelProvider(new ColumnLabelProvider() {
@Override
public String getText(final Object element) {
if (element instanceof ITest) {
switch (((ITest) element).getStatus()) {
case RUNNING:
return "executing ...";
case NOT_RUN:
return "waiting for execution";
case DISABLED:
// fall through
case ERROR:
// fall through
case FAILURE:
final ITestResult result = ((ITest) element).getWorstResult();
if (result != null)
return result.getMessage();
// fall through
default:
return super.getText(((ITestEntity) element).getDescription());
}
} else if (element instanceof IMetadata) {
return super.getText(((IMetadata) element).getValue());
} else if (element instanceof ITestResult)
return super.getText(((ITestResult) element).getMessage());
else if (element instanceof ITestEntity)
return ((ITestEntity) element).getDescription();
return super.getText(element);
}
});
ColumnViewerToolTipSupport.enableFor(viewer, ToolTip.NO_RECREATE);
return viewer;
}
@Override
public void setFocus() {
// nothing to do
}
public TreeViewer getFileTreeViewer() {
return fFileTreeViewer;
}
public StructuredViewer getTableViewer() {
return fTestTreeViewer;
}
public void notifyEngineCreation(TestSuiteScriptEngine engine) {
if ((fCurrentEngine == null) || (fCurrentEngine.isFinished())) {
// switch to a new engine
if (fCurrentEngine != null)
fCurrentEngine.getTestRoot().eAdapters().remove(fContentAdapter);
fErrorCount = 0;
fFailureCount = 0;
fFinishedFileCount = 0;
fFileTreeViewer.setInput(null);
fProgressBar.setSelection(0);
fProgressBar.setMaximum(1);
lblErrorCount.setText(Integer.toString(fErrorCount));
lblFailureCount.setText(Integer.toString(fFailureCount));
lblErrorCount.getParent().layout(true, true);
fCurrentEngine = engine;
fCurrentEngine.getTestRoot().eAdapters().add(fContentAdapter);
}
}
private class ContentAdapter extends EContentAdapter {
@Override
public void notifyChanged(Notification notification) {
super.notifyChanged(notification);
// filter some events
if (notification.getEventType() == Notification.REMOVING_ADAPTER)
return;
if (notification.getEventType() == ITestEntity.CUSTOM_CODE)
return;
if (IRuntimePackage.Literals.TEST_ENTITY__END_TIMESTAMP.equals(notification.getFeature()))
return;
if (IRuntimePackage.Literals.TEST_ENTITY__START_TIMESTAMP.equals(notification.getFeature()))
return;
if (IRuntimePackage.Literals.TEST_ENTITY__ESTIMATED_DURATION.equals(notification.getFeature()))
return;
if (IRuntimePackage.Literals.STACK_TRACE_CONTAINER__STACK_TRACE.equals(notification.getFeature()))
return;
if (IRuntimePackage.Literals.TEST_ENTITY__TERMINATED.equals(notification.getFeature()))
return;
if (IRuntimePackage.Literals.TEST_ENTITY__DESCRIPTION.equals(notification.getFeature()))
return;
if (IRuntimePackage.Literals.TEST__DURATION_LIMIT.equals(notification.getFeature()))
return;
if (IRuntimePackage.Literals.TEST_SUITE__MASTER_ENGINE.equals(notification.getFeature()))
return;
if ((IRuntimePackage.Literals.TEST_ENTITY__RESULTS.equals(notification.getFeature())) && (notification.getEventType() == Notification.ADD)) {
// new result added, see if it was an error/failure
final Object value = notification.getNewValue();
if (value instanceof ITestResult) {
if (TestStatus.ERROR.equals(((ITestResult) value).getStatus()))
fErrorCount++;
if (TestStatus.FAILURE.equals(((ITestResult) value).getStatus()))
fFailureCount++;
}
}
if ((notification.getNotifier() instanceof ITestFile) && (IRuntimePackage.Literals.TEST_ENTITY__ENTITY_STATUS.equals(notification.getFeature()))
&& (TestStatus.FINISHED.equals(notification.getNewValue()))) {
// testfile finished
fFinishedFileCount++;
}
fUIJob.refresh(notification);
}
@Override
public boolean isAdapterForType(Object type) {
return (type instanceof ITestEntity);
}
}
private final ContentAdapter fContentAdapter = new ContentAdapter();
private final UIUpdateJob fUIJob = new UIUpdateJob();
private Label fLblDuration;
private class UIUpdateJob extends UIJob {
private final Collection<Notification> fElements = new HashSet<>();
public UIUpdateJob() {
super("Script Unittest UI update");
}
public void refresh(Notification notification) {
synchronized (fElements) {
fElements.add(notification);
}
schedule(300);
}
@Override
public IStatus runInUIThread(IProgressMonitor monitor) {
if (fFileTreeViewer.getTree().isDisposed())
return Status.CANCEL_STATUS;
if (fFileTreeViewer.getInput() == null) {
// full update
synchronized (fElements) {
fElements.clear();
}
fFileTreeViewer.setInput(fCurrentEngine.getTestRoot());
fFileTreeViewer.expandAll();
TestSuiteSource.getActiveInstance().setActiveSuite(getCurrentTestSuite());
} else {
// partial update
boolean testRefresh = false;
final Object selection = fFileTreeViewer.getStructuredSelection().getFirstElement();
final Collection<ITestContainer> changedTestContainers = new HashSet<>();
final Collection<ITestContainer> changedStatus = new HashSet<>();
synchronized (fElements) {
for (final Notification notification : fElements) {
if (notification.getNotifier() instanceof ITest) {
// check details view
if (((ITest) notification.getNotifier()).getParent().equals(selection))
testRefresh = true;
} else if (notification.getNotifier() instanceof ITestContainer) {
if ((notification.getEventType() == Notification.ADD) || (notification.getEventType() == Notification.REMOVE_MANY)) {
// structure
changedTestContainers.add((ITestContainer) notification.getNotifier());
} else {
// decorator
changedStatus.add((ITestContainer) notification.getNotifier());
}
}
}
fElements.clear();
}
for (final ITestContainer container : changedTestContainers) {
fFileTreeViewer.refresh(container);
changedStatus.add(container);
}
for (ITestContainer container : changedStatus) {
while (container != null) {
fFileTreeViewer.update(container, null);
container = container.getParent();
}
}
if (testRefresh)
fTestTreeViewer.refresh();
}
// check if we are done
final ITestSuite testSuite = getCurrentTestSuite();
if (testSuite.getStatus() != TestStatus.RUNNING) {
fLblDuration.setText("Finished after " + (testSuite.getDuration() / 1000) + " s");
// store runtime information
if (fRuntimeInformation != null) {
fRuntimeInformation.save();
fRuntimeInformation = null;
}
TestSuiteSource.getActiveInstance().setActiveSuite(getCurrentTestSuite());
}
else {
// update remaining time
final long estimatedDuration = testSuite.getEstimatedDuration();
if ((estimatedDuration < 0) && (fRuntimeInformation == null)) {
// load estimations
fRuntimeInformation = new SuiteRuntimeInformation(testSuite);
fLblDuration.setText("running ...");
schedule(1000);
} else if (estimatedDuration >= 0) {
final long estimatedLeft = (testSuite.getStartTimestamp() + estimatedDuration) - System.currentTimeMillis();
if (estimatedLeft > 0) {
fLblDuration.setText("Finished in " + getDurationString(estimatedLeft));
schedule(1000);
} else
fLblDuration.setText("running ...");
}
}
// update error/failure counters
lblErrorCount.setText(Integer.toString(fErrorCount));
lblFailureCount.setText(Integer.toString(fFailureCount));
lblErrorCount.getParent().layout(true, true);
// update progress bar
if (fProgressBar.getMaximum() == 1) {
// not initialized
fProgressBar.setMaximum(getTestFileCount(testSuite));
fProgressBar.setState(SWT.PAUSED);
}
if (fProgressBar.getSelection() != fFinishedFileCount) {
fProgressBar.setSelection(fFinishedFileCount);
if (testSuite.hasError())
fProgressBar.setState(SWT.ERROR);
}
if (testSuite.getStatus() != TestStatus.RUNNING) {
// we are done, no matter what, set the bar to its full length
fProgressBar.setSelection(fProgressBar.getMaximum());
switch (testSuite.getStatus()) {
case ERROR:
case FAILURE:
fProgressBar.setState(SWT.ERROR);
break;
default:
fProgressBar.setState(SWT.NORMAL);
break;
}
}
return Status.OK_STATUS;
}
}
public static String getDurationString(long duration) {
if (duration >= (60 * 60 * 1000))
// >= 1 hour
return new SimpleDateFormat("HH:mm:ss").format(duration);
if (duration >= (60 * 1000))
// >= 1 minute
return new SimpleDateFormat("mm:ss").format(duration);
return (duration / 1000) + " s";
}
@Override
public void dispose() {
if (fCurrentEngine != null)
fCurrentEngine.getTestRoot().eAdapters().remove(fContentAdapter);
if (fCollapseAllHandler != null)
fCollapseAllHandler.dispose();
if (fExpandAllHandler != null)
fExpandAllHandler.dispose();
if (fResourceManager != null) {
fResourceManager.dispose();
fResourceManager = null;
}
super.dispose();
}
public void terminateSuite() {
if (fCurrentEngine != null)
fCurrentEngine.terminate();
}
/**
* @return the currentEngine
*/
public TestSuiteScriptEngine getCurrentEngine() {
return fCurrentEngine;
}
public ITestSuite getCurrentTestSuite() {
final Object input = getFileTreeViewer().getInput();
if (input instanceof ITestContainer) {
final List<ITestEntity> children = ((ITestContainer) input).getCopyOfChildren();
if (!children.isEmpty()) {
final ITestEntity testSuite = children.get(0);
if (testSuite instanceof ITestSuite)
return (ITestSuite) testSuite;
}
}
return null;
}
}