| /******************************************************************************* |
| * 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 v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Christian Pontesegger - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.ease.modules.unittest.ui.views; |
| |
| import java.io.IOException; |
| import java.text.SimpleDateFormat; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.ease.debugging.IScriptDebugFrame; |
| import org.eclipse.ease.modules.platform.UIModule; |
| import org.eclipse.ease.modules.unittest.ITestListener; |
| import org.eclipse.ease.modules.unittest.components.Test; |
| import org.eclipse.ease.modules.unittest.components.TestComposite; |
| import org.eclipse.ease.modules.unittest.components.TestFile; |
| import org.eclipse.ease.modules.unittest.components.TestResult; |
| import org.eclipse.ease.modules.unittest.components.TestStatus; |
| import org.eclipse.ease.modules.unittest.components.TestSuite; |
| import org.eclipse.ease.modules.unittest.components.TestSuiteModel; |
| import org.eclipse.ease.modules.unittest.ui.Activator; |
| import org.eclipse.ease.modules.unittest.ui.sourceprovider.TestSuiteSource; |
| import org.eclipse.ease.ui.console.ScriptConsole; |
| import org.eclipse.ease.ui.tools.DecoratedLabelProvider; |
| 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.DoubleClickEvent; |
| import org.eclipse.jface.viewers.IDoubleClickListener; |
| import org.eclipse.jface.viewers.ISelectionChangedListener; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.jface.viewers.ITreeSelection; |
| import org.eclipse.jface.viewers.LabelProvider; |
| import org.eclipse.jface.viewers.SelectionChangedEvent; |
| import org.eclipse.jface.viewers.StructuredViewer; |
| import org.eclipse.jface.viewers.TreeViewer; |
| import org.eclipse.jface.viewers.TreeViewerColumn; |
| import org.eclipse.jface.viewers.ViewerComparator; |
| 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.graphics.RGB; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.layout.GridLayout; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.swt.widgets.Menu; |
| import org.eclipse.swt.widgets.ProgressBar; |
| import org.eclipse.ui.IMemento; |
| import org.eclipse.ui.IViewSite; |
| import org.eclipse.ui.PartInitException; |
| import org.eclipse.ui.console.ConsolePlugin; |
| import org.eclipse.ui.console.IConsole; |
| import org.eclipse.ui.console.IConsoleListener; |
| import org.eclipse.ui.handlers.CollapseAllHandler; |
| import org.eclipse.ui.handlers.ExpandAllHandler; |
| import org.eclipse.ui.handlers.IHandlerService; |
| import org.eclipse.ui.part.ViewPart; |
| import org.eclipse.ui.progress.UIJob; |
| import org.eclipse.ui.texteditor.ITextEditor; |
| |
| public class UnitTestView extends ViewPart implements ITestListener, IConsoleListener { |
| public static final String VIEW_ID = "org.eclipse.ease.views.unittest"; |
| |
| public static final String TEST_STATUS_PROPERTY = "test status"; |
| |
| private static class Statistics { |
| private final Map<Object, Integer> mCounters = new HashMap<>(); |
| |
| public synchronized void updateCounter(final Object identifier, final int value) { |
| if (mCounters.containsKey(identifier)) |
| mCounters.put(identifier, mCounters.get(identifier) + value); |
| else |
| mCounters.put(identifier, value); |
| } |
| |
| public void reset() { |
| mCounters.clear(); |
| } |
| |
| public synchronized int getCounter(final Object identifier) { |
| if (mCounters.containsKey(identifier)) |
| return mCounters.get(identifier); |
| |
| return 0; |
| } |
| } |
| |
| private static final String XML_CURRENT_SUITE = "currentSuite"; |
| |
| private static final Object STATISTICS_TESTFILES_FINISHED = "testFiles"; |
| |
| private static final Object STATISTICS_TEST_ERROR = "test errors"; |
| |
| private static final Object STATISTICS_TEST_FAILURE = "test failures"; |
| |
| private static final Object STATISTICS_TEST_VALID = "valid tests"; |
| |
| private static final Object STATISTICS_TESTFILE_COUNT = "testFile count"; |
| |
| private static final Object STATISTICS_TEST_FINISHED = "test count"; |
| |
| private ProgressBar fProgressBar; |
| private TreeViewer fFileTreeViewer; |
| private TreeViewer fTestTreeViewer; |
| private SashForm sashForm; |
| |
| private int[] fSashWeights = new int[] { 70, 30 }; |
| |
| private IMemento mMemento; |
| |
| private CollapseAllHandler mCollapseAllHandler; |
| |
| private ExpandAllHandler mExpandAllHandler; |
| |
| private Label lblTimeLeftText; |
| |
| private LocalResourceManager fResourceManager; |
| |
| private final UpdateUI fUIUpdater = new UpdateUI(); |
| private final Statistics fStatistics = new Statistics(); |
| |
| private Label lblErrorCount; |
| private Label lblFailureCount; |
| |
| private SuiteRuntimeInformation fRuntimeInformation = null; |
| private Label lblTimeLeft; |
| private ScriptConsole fConsole = null; |
| |
| public UnitTestView() { |
| } |
| |
| @Override |
| public void init(final IViewSite site, final IMemento memento) throws PartInitException { |
| mMemento = memento; |
| super.init(site, memento); |
| } |
| |
| @Override |
| public void createPartControl(final Composite parent) { |
| parent.setLayout(new GridLayout(1, false)); |
| |
| final Composite composite = new Composite(parent, SWT.NONE); |
| composite.setLayout(new GridLayout(8, false)); |
| composite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); |
| |
| fResourceManager = new LocalResourceManager(JFaceResources.getResources(), composite); |
| |
| final Label lblErrorIcon = new Label(composite, SWT.NONE); |
| final GridData gdLblErrorIcon = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1); |
| gdLblErrorIcon.horizontalIndent = 50; |
| lblErrorIcon.setLayoutData(gdLblErrorIcon); |
| lblErrorIcon.setImage(fResourceManager.createImage(Activator.getImageDescriptor(Activator.ICON_ERROR))); |
| |
| final Label lblErrors = new Label(composite, SWT.NONE); |
| lblErrors.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); |
| lblErrors.setAlignment(SWT.CENTER); |
| lblErrors.setText("Errors:"); |
| |
| lblErrorCount = new Label(composite, SWT.NONE); |
| final GridData gd_lblErrorCount = new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1); |
| 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.horizontalIndent = 50; |
| lblFailureIcon.setLayoutData(gdLblFailureIcon); |
| lblFailureIcon.setImage(fResourceManager.createImage(Activator.getImageDescriptor(Activator.ICON_FAILURE))); |
| |
| final Label lblFailures = new Label(composite, SWT.NONE); |
| lblFailures.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); |
| lblFailures.setAlignment(SWT.CENTER); |
| lblFailures.setText("Failures:"); |
| |
| lblFailureCount = new Label(composite, SWT.NONE); |
| final GridData gdLblFailureCount = new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1); |
| gdLblFailureCount.horizontalIndent = 20; |
| lblFailureCount.setLayoutData(gdLblFailureCount); |
| |
| lblTimeLeftText = new Label(composite, SWT.NONE); |
| final GridData gdLabel = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1); |
| gdLabel.horizontalIndent = 50; |
| lblTimeLeftText.setLayoutData(gdLabel); |
| lblTimeLeftText.setText("Time left: "); |
| lblTimeLeftText.setVisible(false); |
| |
| lblTimeLeft = new Label(composite, SWT.NONE); |
| final GridData gdLblTimeLeft = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1); |
| gdLblTimeLeft.horizontalIndent = 20; |
| lblTimeLeft.setLayoutData(gdLblTimeLeft); |
| lblTimeLeft.setVisible(false); |
| |
| 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.setComparator(new ViewerComparator() { |
| @Override |
| public final int category(final Object element) { |
| if (element instanceof TestFile) |
| return 1; |
| |
| return 0; |
| } |
| }); |
| |
| // use a decorated label provider |
| final LabelProvider provider = new TestSuiteLabelProvider(fResourceManager); |
| fFileTreeViewer.setLabelProvider(new DecoratedLabelProvider(provider)); |
| |
| fFileTreeViewer.addDoubleClickListener(new IDoubleClickListener() { |
| @Override |
| public void doubleClick(final DoubleClickEvent event) { |
| try { |
| final Object element = ((IStructuredSelection) event.getSelection()).getFirstElement(); |
| if (element instanceof TestFile) { |
| final Object file = ((TestFile) element).getFile(); |
| if (file instanceof IFile) |
| UIModule.showEditor((IFile) ((TestFile) element).getFile()); |
| |
| } else if (element instanceof TestSuite) |
| UIModule.showEditor(((TestSuite) element).getModel().getFile()); |
| |
| } catch (final Throwable e) { |
| // TODO handle this exception (but for now, at least know it happened) |
| throw new RuntimeException(e); |
| |
| } |
| } |
| }); |
| fFileTreeViewer.addSelectionChangedListener(new ISelectionChangedListener() { |
| |
| @Override |
| public void selectionChanged(final SelectionChangedEvent event) { |
| final ITreeSelection selection = (ITreeSelection) event.getSelection(); |
| final Object element = selection.getFirstElement(); |
| |
| if (element instanceof TestComposite) { |
| // 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.getTree().setMenu(menu); |
| getSite().registerContextMenu(menuManager, fFileTreeViewer); |
| |
| final MenuManager menuManager2 = new MenuManager(); |
| final Menu menu2 = menuManager2.createContextMenu(fFileTreeViewer.getTree()); |
| fTestTreeViewer.getTree().setMenu(menu2); |
| getSite().registerContextMenu(menuManager2, fTestTreeViewer); |
| |
| // add collapseAll/expandAll handlers |
| final IHandlerService handlerService = getSite().getService(IHandlerService.class); |
| mCollapseAllHandler = new CollapseAllHandler(fFileTreeViewer); |
| handlerService.activateHandler(CollapseAllHandler.COMMAND_ID, mCollapseAllHandler); |
| mExpandAllHandler = new ExpandAllHandler(fFileTreeViewer); |
| handlerService.activateHandler(ExpandAllHandler.COMMAND_ID, mExpandAllHandler); |
| |
| // menuManager.setRemoveAllWhenShown(true); |
| |
| // load last suite |
| if (mMemento != null) { |
| final IMemento currentSuiteNode = mMemento.getChild(XML_CURRENT_SUITE); |
| if (currentSuiteNode != null) { |
| final Path path = new Path(currentSuiteNode.getTextData()); |
| final IFile suiteFile = ResourcesPlugin.getWorkspace().getRoot().getFile(path); |
| try { |
| loadSuite(new TestSuite(new TestSuiteModel(suiteFile))); |
| } catch (final Exception e) { |
| // loading failed, ignore |
| } |
| } |
| } |
| |
| // register for console events |
| ConsolePlugin.getDefault().getConsoleManager().addConsoleListener(UnitTestView.this); |
| |
| 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); |
| viewer.addDoubleClickListener(new IDoubleClickListener() { |
| |
| @Override |
| public void doubleClick(final DoubleClickEvent event) { |
| final Object element = ((IStructuredSelection) event.getSelection()).getFirstElement(); |
| if (element instanceof Test) { |
| |
| List<IScriptDebugFrame> trace; |
| final List<TestResult> messages = ((Test) element).getMessages(); |
| if ((messages != null) && (!messages.isEmpty())) |
| trace = messages.get(0).getStackTrace(); |
| else |
| trace = ((Test) element).getTestLocation(); |
| |
| if (trace != null) { |
| // open trace location |
| for (final IScriptDebugFrame traceElement : trace) { |
| final Object file = traceElement.getScript().getFile(); |
| if (file instanceof IFile) { |
| if (((IFile) file).exists()) { |
| try { |
| final int line = Math.max(traceElement.getLineNumber(), 1); |
| final ITextEditor textEditor = (ITextEditor) UIModule.showEditor((IFile) file); |
| final IDocument document = textEditor.getDocumentProvider().getDocument(textEditor.getEditorInput()); |
| try { |
| textEditor.selectAndReveal(document.getLineOffset(line - 1), document.getLineLength(line - 1)); |
| } catch (final BadLocationException e) { |
| // TODO implement |
| throw new RuntimeException(e); |
| } |
| } catch (final Throwable e) { |
| // TODO handle this exception (but for now, at least know it happened) |
| throw new RuntimeException(e); |
| |
| } |
| |
| break; |
| } |
| } |
| } |
| |
| } else { |
| // we do not have a trace, open test set |
| final Object input = viewer.getInput(); |
| if (input instanceof TestFile) { |
| |
| try { |
| final Object file = ((TestFile) input).getFile(); |
| if (file instanceof IFile) |
| UIModule.showEditor((IFile) ((TestFile) input).getFile()); |
| |
| } catch (final Throwable e) { |
| // TODO handle this exception (but for now, at least know it happened) |
| throw new RuntimeException(e); |
| |
| } |
| } |
| } |
| } |
| } |
| }); |
| |
| viewer.getTree().setHeaderVisible(true); |
| viewer.getTree().setLinesVisible(true); |
| |
| viewer.setContentProvider(new TestFileContentProvider()); |
| |
| 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 Test) |
| return ((Test) element).getTitle(); |
| |
| if (element instanceof Entry<?, ?>) |
| // metadata |
| return ((Entry<?, ?>) element).getKey().toString(); |
| |
| return ""; |
| } |
| |
| @Override |
| public Image getImage(final Object element) { |
| |
| if (element instanceof Entry<?, ?>) |
| // metadata |
| return fResourceManager.createImage(Activator.getImageDescriptor(Activator.ICON_METADATA)); |
| |
| TestStatus status = null; |
| if (element instanceof Test) |
| status = ((Test) element).getStatus(); |
| else if (element instanceof TestResult) |
| status = ((TestResult) element).getStatus(); |
| |
| if (status != null) { |
| switch (status) { |
| case PASS: |
| return fResourceManager.createImage(Activator.getImageDescriptor(Activator.ICON_PASS)); |
| case ERROR: |
| return fResourceManager.createImage(Activator.getImageDescriptor(Activator.ICON_ERROR)); |
| case FAILURE: |
| return fResourceManager.createImage(Activator.getImageDescriptor(Activator.ICON_FAILURE)); |
| case RUNNING: |
| return fResourceManager.createImage(Activator.getImageDescriptor(Activator.ICON_RUNNING)); |
| default: |
| return super.getImage(element); |
| } |
| } |
| |
| return super.getImage(element); |
| } |
| |
| @Override |
| public String getToolTipText(final Object element) { |
| if (element instanceof Test) { |
| if ((((Test) element).getDescription() != null) && (!((Test) element).getDescription().isEmpty())) |
| return ((Test) element).getDescription(); |
| } |
| |
| return super.getToolTipText(element); |
| } |
| }); |
| |
| final TreeViewerColumn messageColumn = new TreeViewerColumn(viewer, SWT.NONE); |
| messageColumn.getColumn().setWidth(100); |
| messageColumn.getColumn().setText("Message"); |
| layout.setColumnData(messageColumn.getColumn(), new ColumnWeightData(70, 50, true)); |
| messageColumn.setLabelProvider(new ColumnLabelProvider() { |
| @Override |
| public String getText(final Object element) { |
| if (element instanceof Test) { |
| final TestResult message = ((Test) element).getSeverestMessage(); |
| if (message != null) |
| return message.getDescription(); |
| |
| return ((Test) element).getDescription(); |
| } |
| |
| if (element instanceof Entry<?, ?>) |
| // metadata |
| return ((Entry<?, ?>) element).getValue().toString(); |
| |
| return super.getText(element); |
| } |
| }); |
| |
| ColumnViewerToolTipSupport.enableFor(viewer, ToolTip.NO_RECREATE); |
| |
| return viewer; |
| } |
| |
| @Override |
| public void setFocus() { |
| // nothing to do |
| } |
| |
| public TreeViewer getFileTreeViewer() { |
| return fFileTreeViewer; |
| } |
| |
| private class UpdateUI extends UIJob { |
| |
| private final List<Object> fElements = new ArrayList<>(); |
| |
| public UpdateUI() { |
| super("Update Script Unit View"); |
| } |
| |
| public void addElement(final Object element) { |
| synchronized (fElements) { |
| if (fElements.isEmpty()) { |
| // we might have added the same element again, so we cannot check for size() == 1 afterwards |
| fElements.add(element); |
| schedule(300); |
| } else |
| fElements.add(element); |
| } |
| } |
| |
| @Override |
| public IStatus runInUIThread(final IProgressMonitor monitor) { |
| // create a local copy of elements so we can continue tests without waiting for the UI updater |
| ArrayList<Object> localElements; |
| synchronized (fElements) { |
| localElements = new ArrayList<>(fElements); |
| fElements.clear(); |
| } |
| |
| // update tree elements |
| for (final Object element : localElements) { |
| TestComposite affectedComposite = null; |
| if (element instanceof Test) |
| affectedComposite = ((Test) element).getParent(); |
| |
| else if (element instanceof TestComposite) |
| affectedComposite = (TestComposite) element; |
| |
| while (affectedComposite != null) { |
| // update tree element and all its parents (no folders) |
| fFileTreeViewer.update(affectedComposite, new String[] { TEST_STATUS_PROPERTY }); |
| affectedComposite = affectedComposite.getParent(); |
| } |
| } |
| |
| // update table |
| if (fTestTreeViewer.getInput() != null) { |
| // update only if tableviewer is visible at all |
| for (final Object element : localElements) { |
| if (element instanceof Test) { |
| final TestComposite testComposite = ((Test) element).getParent(); |
| |
| if (fTestTreeViewer.getInput().equals(testComposite)) { |
| fTestTreeViewer.refresh(); |
| // TODO scroll to last element |
| |
| // one refresh is enough for the whole table, so bail out |
| break; |
| } |
| } |
| } |
| } |
| |
| // update statistics |
| if (!fProgressBar.isDisposed()) { |
| |
| lblErrorCount.setText(Integer.toString(fStatistics.getCounter(STATISTICS_TEST_ERROR))); |
| lblFailureCount.setText(Integer.toString(fStatistics.getCounter(STATISTICS_TEST_FAILURE))); |
| lblFailureCount.getParent().layout(); |
| |
| fProgressBar.setSelection(fStatistics.getCounter(STATISTICS_TESTFILES_FINISHED)); |
| lblTimeLeft.setText(getEstimatedTime()); |
| |
| if ((fStatistics.getCounter(STATISTICS_TEST_ERROR) > 0) || (fStatistics.getCounter(STATISTICS_TEST_FAILURE) > 0)) |
| fProgressBar.setForeground(fResourceManager.createColor(new RGB(0xaa, 0, 0))); |
| |
| else if (fStatistics.getCounter(STATISTICS_TESTFILES_FINISHED) == fStatistics.getCounter(STATISTICS_TESTFILE_COUNT)) { |
| if ((fStatistics.getCounter(STATISTICS_TEST_ERROR) == 0) && (fStatistics.getCounter(STATISTICS_TEST_FAILURE) == 0)) |
| fProgressBar.setForeground(fResourceManager.createColor(new RGB(0, 0xaa, 0))); |
| } |
| } |
| |
| synchronized (fElements) { |
| if (!fElements.isEmpty()) |
| schedule(1000); |
| } |
| |
| return Status.OK_STATUS; |
| } |
| |
| private String getEstimatedTime() { |
| if (getCurrentSuite().getStatus() != TestStatus.RUNNING) { |
| lblTimeLeft.setVisible(false); |
| lblTimeLeftText.setVisible(false); |
| return ""; |
| } |
| |
| if (fRuntimeInformation != null) { |
| final long time = fRuntimeInformation.getEstimatedTestTime(); |
| |
| if (time < 0) |
| return "calculating..."; |
| |
| if (time < 60000) |
| return new SimpleDateFormat("ss 'seconds'").format(time); |
| |
| if (time < 3600000) |
| return new SimpleDateFormat("mm:ss").format(time); |
| |
| return new SimpleDateFormat("hh:mm:ss").format(time); |
| } |
| |
| return "unknown"; |
| } |
| } |
| |
| @Override |
| public void notify(final Object testObject, final TestStatus status) { |
| if ((testObject instanceof TestSuite) && (status == TestStatus.RUNNING)) { |
| |
| Display.getDefault().syncExec(new Runnable() { |
| |
| @Override |
| public void run() { |
| try { |
| loadSuite((TestSuite) testObject); |
| } catch (final Exception e) { |
| // TODO handle this exception (but for now, at least know it happened) |
| throw new RuntimeException(e); |
| } |
| |
| fStatistics.reset(); |
| fStatistics.updateCounter(STATISTICS_TESTFILE_COUNT, ((TestSuite) testObject).getActiveTestCount()); |
| |
| // initialize progress bar |
| fProgressBar.setMaximum(fStatistics.getCounter(STATISTICS_TESTFILE_COUNT)); |
| fProgressBar.setSelection(0); |
| fProgressBar.setForeground(null); |
| |
| // create console |
| if (fConsole == null) |
| fConsole = ScriptConsole.create(testObject.toString(), null); |
| |
| // clear & attach to suite |
| fConsole.clearConsole(); |
| fConsole.activate(); |
| ((TestSuite) testObject).setOutputStream(fConsole.getOutputStream()); |
| ((TestSuite) testObject).setErrorStream(fConsole.getErrorStream()); |
| ((TestSuite) testObject).setErrorStream(fConsole.getInputStream()); |
| |
| // update estimated runtime |
| lblTimeLeft.setVisible(true); |
| lblTimeLeftText.setVisible(true); |
| } |
| }); |
| |
| } else { |
| // update statistics |
| if ((status != TestStatus.RUNNING) && (status != TestStatus.NOT_RUN)) { |
| // test finished |
| |
| if (testObject instanceof Test) { |
| // do not track when this is a temporary tests in test count |
| if (!((Test) testObject).isTransient()) |
| fStatistics.updateCounter(STATISTICS_TEST_FINISHED, 1); |
| |
| // do not track when this is a temporary test that passed |
| if ((!((Test) testObject).isTransient()) || (!((Test) testObject).getMessages().isEmpty())) { |
| |
| switch (status) { |
| case FAILURE: |
| fStatistics.updateCounter(STATISTICS_TEST_FAILURE, 1); |
| break; |
| case ERROR: |
| fStatistics.updateCounter(STATISTICS_TEST_ERROR, 1); |
| break; |
| case PASS: |
| // do not track when global test file scope is valid |
| fStatistics.updateCounter(STATISTICS_TEST_VALID, 1); |
| break; |
| default: |
| // nothing to do |
| break; |
| } |
| } |
| |
| } else if (testObject instanceof TestFile) { |
| fStatistics.updateCounter(STATISTICS_TESTFILES_FINISHED, 1); |
| } |
| } |
| } |
| |
| fUIUpdater.addElement(testObject); |
| } |
| |
| public StructuredViewer getTableViewer() { |
| return fTestTreeViewer; |
| } |
| |
| @Override |
| public void saveState(final IMemento memento) { |
| final TestSuite suite = getCurrentSuite(); |
| |
| if (suite != null) { |
| final IFile file = suite.getModel().getFile(); |
| |
| if ((file != null) && (file.exists())) { |
| // we finally detected the current test suite |
| memento.createChild(XML_CURRENT_SUITE).putTextData(file.getFullPath().toString()); |
| } |
| } |
| |
| super.saveState(memento); |
| } |
| |
| public TestSuite getCurrentSuite() { |
| final Object input = fFileTreeViewer.getInput(); |
| if (input instanceof Object[]) { |
| if (((Object[]) input).length > 0) { |
| final Object suite = ((Object[]) input)[0]; |
| if (suite instanceof TestSuite) |
| return (TestSuite) suite; |
| } |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Loads a suite file and populates the treeview. Needs to be called from UIThread. |
| * |
| * @param suite |
| * testSuite |
| * @return |
| * @throws IOException |
| * cannot read from suite file |
| * @throws CoreException |
| * invalid data within suite file |
| */ |
| public void loadSuite(final TestSuite suite) throws IOException, CoreException { |
| // save current suite |
| final TestSuite currentSuite = getCurrentSuite(); |
| if (!suite.equals(currentSuite)) { |
| if (currentSuite != null) { |
| Activator.getDefault().addRecentFile(currentSuite.getModel().getFile()); |
| |
| // save timing information |
| if (fRuntimeInformation != null) |
| fRuntimeInformation.save(); |
| |
| // clear data to minimize memory footprint in eclipse caches |
| currentSuite.reset(); |
| } |
| |
| fFileTreeViewer.setInput(new Object[] { suite }); |
| fRuntimeInformation = new SuiteRuntimeInformation(suite); |
| |
| // update source provider |
| final TestSuiteSource instance = TestSuiteSource.getActiveInstance(); |
| if (instance != null) |
| instance.setActiveSuite(suite); |
| |
| suite.addTestListener(this); |
| |
| // refresh console |
| if (fConsole != null) { |
| fConsole.terminate(); |
| fConsole = null; |
| } |
| } |
| |
| fFileTreeViewer.refresh(); |
| fFileTreeViewer.expandAll(); |
| } |
| |
| @Override |
| public void dispose() { |
| // unregister from console events |
| ConsolePlugin.getDefault().getConsoleManager().removeConsoleListener(this); |
| |
| // dispose handlers |
| mCollapseAllHandler.dispose(); |
| mExpandAllHandler.dispose(); |
| |
| // save current suite |
| final TestSuite currentSuite = getCurrentSuite(); |
| if (currentSuite != null) |
| Activator.getDefault().addRecentFile(currentSuite.getModel().getFile()); |
| |
| // save timing information |
| if (fRuntimeInformation != null) |
| fRuntimeInformation.save(); |
| |
| // allow for garbage collection as eclipse does not clean up views correctly on clode |
| fRuntimeInformation = null; |
| final TestSuiteSource instance = TestSuiteSource.getActiveInstance(); |
| if (instance != null) |
| instance.setActiveSuite(null); |
| |
| fFileTreeViewer.setInput(new Object[0]); |
| |
| // clear data to minimize memory footprint in eclipse caches |
| if (currentSuite != null) |
| currentSuite.reset(); |
| |
| super.dispose(); |
| } |
| |
| @Override |
| public void consolesAdded(final IConsole[] consoles) { |
| // nothing to do |
| } |
| |
| @Override |
| public void consolesRemoved(final IConsole[] consoles) { |
| for (final IConsole console : consoles) { |
| if (console.equals(fConsole)) |
| fConsole = null; |
| } |
| } |
| } |