package org.rubypeople.rdt.internal.testunit.ui; import java.net.MalformedURLException; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Vector; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.commands.IHandler; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.MultiStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.debug.core.ILaunchManager; import org.eclipse.debug.ui.DebugUITools; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IMenuListener; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.IStatusLineManager; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.dialogs.ErrorDialog; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.CLabel; import org.eclipse.swt.custom.CTabFolder; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.custom.ViewForm; import org.eclipse.swt.dnd.Clipboard; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.events.ControlListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; 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.ToolBar; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IEditorActionBarContributor; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IPartListener2; import org.eclipse.ui.IViewPart; import org.eclipse.ui.IViewSite; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchPartReference; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PartInitException; import org.eclipse.ui.handlers.IHandlerActivation; import org.eclipse.ui.handlers.IHandlerService; import org.eclipse.ui.keys.IBindingService; import org.eclipse.ui.part.EditorActionBarContributor; import org.eclipse.ui.part.ViewPart; import org.eclipse.ui.progress.UIJob; import org.rubypeople.rdt.core.ElementChangedEvent; import org.rubypeople.rdt.core.IElementChangedListener; import org.rubypeople.rdt.core.IRubyElement; import org.rubypeople.rdt.core.IRubyElementDelta; import org.rubypeople.rdt.core.IRubyProject; import org.rubypeople.rdt.core.IType; import org.rubypeople.rdt.core.RubyCore; import org.rubypeople.rdt.internal.core.RubyModelManager; import org.rubypeople.rdt.launching.IRubyLaunchConfigurationConstants; import org.rubypeople.rdt.testunit.ITestRunListener; import org.rubypeople.rdt.testunit.launcher.TestUnitLaunchConfigurationDelegate; public class TestUnitView extends ViewPart implements ITestRunListener3 { public static final String NAME = "org.rubypeople.rdt.testunit.views.TestUnitView"; private static final String RERUN_LAST_COMMAND = "org.rubypeople.rdt.testunit.rerunLastTest"; static final int REFRESH_INTERVAL = 200; public static final String ID_EXTENSION_POINT_TESTRUN_TABS = TestunitPlugin.PLUGIN_ID + "." + "internalTestRunTabs"; //$NON-NLS-1$ //$NON-NLS-2$ static enum VIEW_ORIENTATION {VERTICAL, HORIZONTAL, AUTOMATIC}; private VIEW_ORIENTATION fOrientation= VIEW_ORIENTATION.AUTOMATIC; private VIEW_ORIENTATION fCurrentOrientation; private ToggleOrientationAction[] fToggleOrientationActions; final Image fStackViewIcon= TestUnitView.createImage("eview16/stackframe.gif");//$NON-NLS-1$ final Image fTestRunOKIcon= TestUnitView.createImage("eview16/testunitsucc.gif"); //$NON-NLS-1$ final Image fTestRunFailIcon= TestUnitView.createImage("eview16/testuniterr.gif"); //$NON-NLS-1$ final Image fTestRunOKDirtyIcon= TestUnitView.createImage("eview16/testunitsuccq.gif"); //$NON-NLS-1$ final Image fTestRunFailDirtyIcon= TestUnitView.createImage("eview16/testuniterrq.gif"); //$NON-NLS-1$ /** * The currently active run tab */ private TestRunTab fActiveRunTab; /** * The collection of ITestRunTabs */ protected Vector<TestRunTab> fTestRunTabs = new Vector<TestRunTab>(); /** * Map storing TestInfos for each executed test keyed by the test name. */ private Map<String, TestRunInfo> fTestInfos = new HashMap<String, TestRunInfo>(); /** * Is the UI disposed */ private boolean fIsDisposed = false; /** * The client side of the remote test runner */ private RemoteTestRunnerClient fTestRunnerClient; /** * The launcher that has started the test */ private String fLaunchMode; private ILaunch fLastLaunch; /** * Actions */ private Action fRerunLastTestAction; /** * Number of executed tests during a test run */ protected volatile int fExecutedTests; /** * Number of errors during this test run */ protected volatile int fErrorCount; /** * Number of failures during this test run */ protected volatile int fFailureCount; /** * Number of tests run */ protected volatile int fTestCount; /** * The first failure of a test run. Used to reveal the first failed tests at * the end of a run. */ private List<TestRunInfo> fFailures = new ArrayList<TestRunInfo>(); protected boolean fShowOnErrorOnly = false; private CounterPanel fCounterPanel; private TestUnitProgressBar fProgressBar; protected ProgressImages fProgressImages; protected Image fViewImage; private Composite fCounterComposite; private Composite fParent; private SashForm fSashForm; private CTabFolder fTabFolder; private FailureTrace fFailureTrace; private Clipboard fClipboard; protected volatile String fStatus; Image fOriginalViewImage; IElementChangedListener fDirtyListener; private UpdateUIJob fUpdateJob; /** * Whether the output scrolls and reveals tests as they are executed. */ private boolean fAutoScroll = true; private ScrollLockAction fScrollLockAction; private IRubyProject fTestProject; private IMenuListener fViewMenuListener; private ActivateOnErrorAction fActivateOnErrorAction; private boolean fIsRunning = false; private boolean fIsStopped = false; private int fStartedCount = 0; private IPartListener2 fPartListener= new IPartListener2() { public void partActivated(IWorkbenchPartReference ref) { } public void partBroughtToTop(IWorkbenchPartReference ref) { } public void partInputChanged(IWorkbenchPartReference ref) { } public void partClosed(IWorkbenchPartReference ref) { } public void partDeactivated(IWorkbenchPartReference ref) { } public void partOpened(IWorkbenchPartReference ref) { } public void partVisible(IWorkbenchPartReference ref) { if (getSite().getId().equals(ref.getId())) { fPartIsVisible= true; } } public void partHidden(IWorkbenchPartReference ref) { if (getSite().getId().equals(ref.getId())) { fPartIsVisible= false; } } }; protected boolean fPartIsVisible= false; private IHandlerActivation fRerunLastActivation; /** * The constructor. */ public TestUnitView() {} public static Image createImage(String path) { try { ImageDescriptor id = ImageDescriptor.createFromURL(TestunitPlugin.makeIconFileURL(path)); return id.createImage(); } catch (MalformedURLException e) { // fall through } return null; } /** * This is a callback that will allow us to create the viewer and initialize * it. */ public void createPartControl(Composite parent) { fParent = parent; addResizeListener(parent); fClipboard = new Clipboard(parent.getDisplay()); GridLayout gridLayout = new GridLayout(); gridLayout.marginWidth = 0; gridLayout.marginHeight = 0; parent.setLayout(gridLayout); configureToolBar(); fCounterComposite = createProgressCountPanel(parent); fCounterComposite.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL)); SashForm sashForm = createSashForm(parent); sashForm.setLayoutData(new GridData(GridData.FILL_BOTH)); fOriginalViewImage= getTitleImage(); fProgressImages= new ProgressImages(); getViewSite().getPage().addPartListener(fPartListener); } private class ToggleOrientationAction extends Action { private final VIEW_ORIENTATION fActionOrientation; public ToggleOrientationAction(TestUnitView v, VIEW_ORIENTATION orientation) { super("", AS_RADIO_BUTTON); //$NON-NLS-1$ if (orientation == VIEW_ORIENTATION.HORIZONTAL) { setText(TestUnitMessages.TestRunnerViewPart_toggle_horizontal_label); setImageDescriptor(TestunitPlugin.getImageDescriptor("elcl16/th_horizontal.gif")); //$NON-NLS-1$ } else if (orientation == VIEW_ORIENTATION.VERTICAL) { setText(TestUnitMessages.TestRunnerViewPart_toggle_vertical_label); setImageDescriptor(TestunitPlugin.getImageDescriptor("elcl16/th_vertical.gif")); //$NON-NLS-1$ } else if (orientation == VIEW_ORIENTATION.AUTOMATIC) { setText(TestUnitMessages.TestRunnerViewPart_toggle_automatic_label); setImageDescriptor(TestunitPlugin.getImageDescriptor("elcl16/th_automatic.gif")); //$NON-NLS-1$ } fActionOrientation= orientation; } public VIEW_ORIENTATION getOrientation() { return fActionOrientation; } public void run() { if (isChecked()) { fOrientation= fActionOrientation; computeOrientation(); } } } private void configureToolBar() { IActionBars actionBars = getViewSite().getActionBars(); IToolBarManager toolBar = actionBars.getToolBarManager(); // TODO Uncomment when other actions are available IMenuManager viewMenu = actionBars.getMenuManager(); fRerunLastTestAction = new RerunLastAction(); IHandlerService handlerService= (IHandlerService) getSite().getWorkbenchWindow().getService(IHandlerService.class); IHandler handler = new AbstractHandler() { public Object execute(ExecutionEvent event) throws ExecutionException { fRerunLastTestAction.run(); return null; } public boolean isEnabled() { return fRerunLastTestAction.isEnabled(); } }; fRerunLastActivation= handlerService.activateHandler(RERUN_LAST_COMMAND, handler); fScrollLockAction = new ScrollLockAction(this); //fNextAction= new ShowNextFailureAction(this); //fPreviousAction= new ShowPreviousFailureAction(this); //fStopAction= new StopAction(); //fNextAction.setEnabled(false); //fPreviousAction.setEnabled(false); //fStopAction.setEnabled(false); //actionBars.setGlobalActionHandler(ActionFactory.NEXT.getId(), // fNextAction); //actionBars.setGlobalActionHandler(ActionFactory.PREVIOUS.getId(), // fPreviousAction); //toolBar.add(fNextAction); //toolBar.add(fPreviousAction); //toolBar.add(fStopAction); toolBar.add(new Separator()); toolBar.add(fRerunLastTestAction); toolBar.add(fScrollLockAction); fToggleOrientationActions = new ToggleOrientationAction[] { new ToggleOrientationAction(this, VIEW_ORIENTATION.VERTICAL), new ToggleOrientationAction(this, VIEW_ORIENTATION.HORIZONTAL), new ToggleOrientationAction(this, VIEW_ORIENTATION.AUTOMATIC)}; MenuManager layoutSubMenu= new MenuManager(TestUnitMessages.TestRunnerViewPart_layout_menu); for (int i = 0; i < fToggleOrientationActions.length; ++i) { layoutSubMenu.add(fToggleOrientationActions[i]); } viewMenu.add(layoutSubMenu); viewMenu.add(new Separator()); fScrollLockAction.setChecked(!fAutoScroll); fActivateOnErrorAction= new ActivateOnErrorAction(); viewMenu.add(fActivateOnErrorAction); fViewMenuListener= new IMenuListener() { public void menuAboutToShow(IMenuManager manager) { fActivateOnErrorAction.update(); } }; viewMenu.addMenuListener(fViewMenuListener); actionBars.updateActionBars(); } private SashForm createSashForm(Composite parent) { fSashForm = new SashForm(parent, SWT.VERTICAL); ViewForm top = new ViewForm(fSashForm, SWT.NONE); fTabFolder = createTestRunTabs(top); fTabFolder.setLayoutData(new TabFolderLayout()); top.setContent(fTabFolder); ViewForm bottom = new ViewForm(fSashForm, SWT.NONE); CLabel label = new CLabel(bottom, SWT.NONE); label.setText(TestUnitMessages.TestRunnerViewPart_label_failure); label.setImage(fStackViewIcon); bottom.setTopLeft(label); ToolBar failureToolBar = new ToolBar(bottom, SWT.FLAT | SWT.WRAP); bottom.setTopCenter(failureToolBar); fFailureTrace = new FailureTrace(bottom, fClipboard, this, failureToolBar); bottom.setContent(fFailureTrace.getComposite()); fSashForm.setWeights(new int[] { 50, 50}); return fSashForm; } protected CTabFolder createTestRunTabs(Composite parent) { CTabFolder tabFolder = new CTabFolder(parent, SWT.TOP); tabFolder.setLayoutData(new GridData(GridData.FILL_BOTH | GridData.GRAB_VERTICAL)); loadTestRunTabs(tabFolder); tabFolder.setSelection(0); fActiveRunTab = fTestRunTabs.firstElement(); tabFolder.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent event) { testTabChanged(event); } }); return tabFolder; } private void testTabChanged(SelectionEvent event) { for (Enumeration e = fTestRunTabs.elements(); e.hasMoreElements();) { TestRunTab v = (TestRunTab) e.nextElement(); if (((CTabFolder) event.widget).getSelection().getText() == v.getName()) { v.setSelectedTest(fActiveRunTab.getSelectedTestId()); fActiveRunTab = v; fActiveRunTab.activate(); } } } private void loadTestRunTabs(CTabFolder tabFolder) { IExtensionPoint extensionPoint = Platform.getExtensionRegistry().getExtensionPoint(ID_EXTENSION_POINT_TESTRUN_TABS); if (extensionPoint == null) { return; } IConfigurationElement[] configs = extensionPoint.getConfigurationElements(); MultiStatus status = new MultiStatus(TestunitPlugin.PLUGIN_ID, IStatus.OK, "Could not load some testRunTabs extension points", null); //$NON-NLS-1$ for (int i = 0; i < configs.length; i++) { try { TestRunTab testRunTab = (TestRunTab) configs[i].createExecutableExtension("class"); //$NON-NLS-1$ testRunTab.createTabControl(tabFolder, fClipboard, this); fTestRunTabs.addElement(testRunTab); } catch (CoreException e) { status.add(e.getStatus()); } } if (!status.isOK()) { TestunitPlugin.log(status); } } protected Composite createProgressCountPanel(Composite parent) { Composite composite = new Composite(parent, SWT.NONE); GridLayout layout = new GridLayout(); composite.setLayout(layout); setCounterColumns(layout); fCounterPanel = new CounterPanel(composite); fCounterPanel.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL)); fProgressBar = new TestUnitProgressBar(composite); fProgressBar.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL)); return composite; } private void setCounterColumns(GridLayout layout) { if (fCurrentOrientation == VIEW_ORIENTATION.HORIZONTAL) layout.numColumns = 2; else layout.numColumns = 1; } /** * Passing the focus request to the viewer's control. */ public void setFocus() { if (fActiveRunTab != null) fActiveRunTab.setFocus(); } public void showTest(TestRunInfo test) { fActiveRunTab.setSelectedTest(test.getTestId()); handleTestSelected(test.getTestId()); // TODO Allow OpenTestAction again! // new OpenTestAction(this, test.getClassName(), // test.getTestMethodName()).run(); } public void handleTestSelected(String testId) { TestRunInfo testInfo = getTestInfo(testId); if (testInfo == null) { showFailure(null); //$NON-NLS-1$ } else { showFailure(testInfo); } } public TestRunInfo getTestInfo(String testId) { if (testId == null) return null; return fTestInfos.get(testId); } private void showFailure(final TestRunInfo failure) { postSyncRunnable(new Runnable() { public void run() { if (!isDisposed()) fFailureTrace.showFailure(failure); } }); } private void postSyncRunnable(Runnable r) { if (!isDisposed()) getDisplay().syncExec(r); } private boolean isDisposed() { return fIsDisposed || fCounterPanel.isDisposed(); } private Display getDisplay() { return getViewSite().getShell().getDisplay(); } public synchronized void dispose() { fIsDisposed = true; stopTest(); IHandlerService handlerService= (IHandlerService) getSite().getWorkbenchWindow().getService(IHandlerService.class); handlerService.deactivateHandler(fRerunLastActivation); if (fProgressImages != null) fProgressImages.dispose(); // TestunitPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(this); fTestRunOKIcon.dispose(); fTestRunFailIcon.dispose(); fStackViewIcon.dispose(); fTestRunOKDirtyIcon.dispose(); fTestRunFailDirtyIcon.dispose(); getViewSite().getPage().removePartListener(fPartListener); if (fClipboard != null) fClipboard.dispose(); } public void rerunTest(String testId, String className, String testName, String launchMode) { DebugUITools.saveAndBuildBeforeLaunch(); if (lastLaunchIsKeptAlive()) fTestRunnerClient.rerunTest(testId, className, testName); else if (fLastLaunch != null) { // run the selected test using the previous launch configuration ILaunchConfiguration launchConfiguration = fLastLaunch.getLaunchConfiguration(); if (launchConfiguration != null) { // TODO Cleanup //rerunWithNewPort(className, launchMode, launchConfiguration); try { String name = className; if (testName != null) name += "." + testName; //$NON-NLS-1$ String configName = TestUnitMessages.getFormattedString(TestUnitMessages.TestRunnerViewPart_configName, name); ILaunchConfigurationWorkingCopy tmp = launchConfiguration.copy(configName); // fix for bug: 64838 junit view run single test does not // use // correct class [JUnit] tmp.setAttribute(TestUnitLaunchConfigurationDelegate.TESTTYPE_ATTR, className); if (testName != null) { tmp.setAttribute(TestUnitLaunchConfigurationDelegate.TESTNAME_ATTR, testName); } tmp.launch(launchMode, null); return; } catch (CoreException e) { ErrorDialog.openError(getSite().getShell(), TestUnitMessages.TestRunnerViewPart_error_cannotrerun, e.getMessage(), e.getStatus() //$NON-NLS-1$ ); } } MessageDialog.openInformation(getSite().getShell(), TestUnitMessages.TestRunnerViewPart_cannotrerun_title, TestUnitMessages.TestRunnerViewPart_cannotrerurn_message ); } } public boolean lastLaunchIsKeptAlive() { return fTestRunnerClient != null && fTestRunnerClient.isRunning() && ILaunchManager.DEBUG_MODE.equals(fLaunchMode); } public void startTestRunListening(int port, IType type, ILaunch launch, Set<ITestRunListener> testRunListeners) { if(type != null) fTestProject= type.getRubyProject(); else { try { String projectName = launch.getLaunchConfiguration().getAttribute(IRubyLaunchConfigurationConstants.ATTR_PROJECT_NAME, (String)null); fTestProject = RubyModelManager.getRubyModelManager().getRubyModel().getRubyProject(projectName); } catch (CoreException e) { TestunitPlugin.log(e); } } fLaunchMode = launch.getLaunchMode(); aboutToLaunch(); if (fTestRunnerClient != null) { stopTest(); } fTestRunnerClient = new RemoteTestRunnerClient(); // add the TestUnitView to the list of registered listeners ITestRunListener[] listenerArray = new ITestRunListener[testRunListeners.size() + 1]; listenerArray[0] = this; Iterator<ITestRunListener> iter = testRunListeners.iterator(); for (int i = 0; i < testRunListeners.size(); i++) { listenerArray[i + 1] = iter.next(); } fTestRunnerClient.startListening(listenerArray, port); fLastLaunch = launch; setViewPartTitle(type); if (type instanceof IType) setTitleToolTip(((IType)type).getFullyQualifiedName()); else if (type != null) setTitleToolTip(type.getElementName()); } protected void aboutToLaunch() { String msg = TestUnitMessages.TestRunnerViewPart_message_launching; showInformation(msg); setInfoMessage(msg); fViewImage= fOriginalViewImage; firePropertyChange(IWorkbenchPart.PROP_TITLE); } protected void showInformation(final String info) { postSyncRunnable(new Runnable() { public void run() { if (!isDisposed()) fFailureTrace.setInformation(info); } }); } protected void setInfoMessage(final String message) { fStatus = message; } /** * Stops the currently running test and shuts down the RemoteTestRunner */ public void stopTest() { if (fTestRunnerClient != null) fTestRunnerClient.stopTest(); stopUpdateJob(); } private void stopUpdateJob() { if (fUpdateJob != null) { fUpdateJob.stop(); fUpdateJob = null; } } public void setAutoScroll(boolean scroll) { fAutoScroll = scroll; } public boolean isAutoScroll() { return fAutoScroll; } public boolean isCreated() { return fCounterPanel != null; } public void reset() { reset(0); setViewPartTitle(null); clearStatus(); resetViewIcon(); } private void clearStatus() { getStatusLine().setMessage(null); getStatusLine().setErrorMessage(null); } private IStatusLineManager getStatusLine() { // we want to show messages globally hence we // have to go through the active part IViewSite site = getViewSite(); IWorkbenchPage page = site.getPage(); IWorkbenchPart activePart = page.getActivePart(); if (activePart instanceof IViewPart) { IViewPart activeViewPart = (IViewPart) activePart; IViewSite activeViewSite = activeViewPart.getViewSite(); return activeViewSite.getActionBars().getStatusLineManager(); } if (activePart instanceof IEditorPart) { IEditorPart activeEditorPart = (IEditorPart) activePart; IEditorActionBarContributor contributor = activeEditorPart.getEditorSite().getActionBarContributor(); if (contributor instanceof EditorActionBarContributor) return ((EditorActionBarContributor) contributor).getActionBars().getStatusLineManager(); } // no active part return getViewSite().getActionBars().getStatusLineManager(); } private void resetViewIcon() { fViewImage = fOriginalViewImage; firePropertyChange(IWorkbenchPart.PROP_TITLE); } private void setViewPartTitle(IRubyElement type) { String title; if (type == null) title = " "; //$NON-NLS-1$ else { if (type instanceof IType) { title = ((IType) type).getFullyQualifiedName(); } else title = type.getElementName(); } setContentDescription(title); } private void reset(final int testCount) { postSyncRunnable(new Runnable() { public void run() { if (isDisposed()) return; fCounterPanel.reset(); fFailureTrace.clear(); fProgressBar.reset(); // TODO enable stop action //fStopAction.setEnabled(true); clearStatus(); start(testCount); } }); fExecutedTests = 0; fFailureCount = 0; fErrorCount = 0; fTestCount = testCount; fIsRunning = false; fIsStopped = false; fStartedCount = 0; aboutToStart(); fTestInfos.clear(); fFailures = new ArrayList<TestRunInfo>(); } protected void start(final int total) { resetProgressBar(total); fCounterPanel.setTotal(total); fCounterPanel.setRunValue(0); } private void resetProgressBar(final int total) { fProgressBar.reset(); fProgressBar.setMaximum(total); } private void aboutToStart() { postSyncRunnable(new Runnable() { public void run() { if (!isDisposed()) { for (Enumeration e = fTestRunTabs.elements(); e.hasMoreElements();) { TestRunTab v = (TestRunTab) e.nextElement(); v.aboutToStart(); } // TODO Re-enable actions //fNextAction.setEnabled(false); //fPreviousAction.setEnabled(false); } } }); } /* * @see ITestRunListener#testEnded */ public void testEnded(String testId, String testName) { postEndTest(testId, testName); fExecutedTests++; } /* * @see ITestRunListener#testFailed */ public void testFailed(int status, String testId, String testName, String trace) { testFailed(status, testId, testName, trace, null, null); } /* * @see ITestRunListener#testFailed */ public void testFailed(int status, String testId, String testName, String trace, String expected, String actual) { TestRunInfo testInfo = getTestInfo(testId); if (testInfo == null) { testInfo = new TestRunInfo(testId, testName); fTestInfos.put(testName, testInfo); } testInfo.setTrace(trace); testInfo.setStatus(status); if (expected != null) { testInfo.setExpected(expected.substring(0, expected.length() - 1)); } if (actual != null) testInfo.setActual(actual.substring(0, actual.length() - 1)); if (status == ITestRunListener.STATUS_ERROR) fErrorCount++; else fFailureCount++; fFailures.add(testInfo); // show the view on the first error only if (fShowOnErrorOnly && (fErrorCount + fFailureCount == 1)) postShowTestResultsView(); } protected void postShowTestResultsView() { postSyncRunnable(new Runnable() { public void run() { if (isDisposed()) return; showTestResultsView(); } }); } public void showTestResultsView() { IWorkbenchWindow window = getSite().getWorkbenchWindow(); IWorkbenchPage page = window.getActivePage(); TestUnitView testRunner = null; if (page != null) { try { // show the result view testRunner = (TestUnitView) page.findView(TestUnitView.NAME); if (testRunner == null) { IWorkbenchPart activePart = page.getActivePart(); testRunner = (TestUnitView) page.showView(TestUnitView.NAME); //restore focus stolen by the creation of the console page.activate(activePart); } else { page.bringToTop(testRunner); } } catch (PartInitException pie) { TestunitPlugin.log(pie); } } } /* * @see ITestRunListener#testReran */ public void testReran(String testId, String className, String testName, int status, String trace) { if (status == ITestRunListener.STATUS_ERROR) { String msg = TestUnitMessages.getFormattedString(TestUnitMessages.TestRunnerViewPart_message_error, new String[] { testName, className}); postError(msg); } else if (status == ITestRunListener.STATUS_FAILURE) { String msg = TestUnitMessages.getFormattedString(TestUnitMessages.TestRunnerViewPart_message_failure, new String[] { testName, className}); postError(msg); } else { String msg = TestUnitMessages.getFormattedString(TestUnitMessages.TestRunnerViewPart_message_success, new String[] { testName, className}); setInfoMessage(msg); } TestRunInfo info = getTestInfo(testId); updateTest(info, status); if (info.getTrace() == null || !info.getTrace().equals(trace)) { info.setTrace(trace); showFailure(info); } } protected void postError(final String message) { fStatus = message; } private void updateTest(TestRunInfo info, final int status) { if (status == info.getStatus()) return; if (info.getStatus() == ITestRunListener.STATUS_OK) { if (status == ITestRunListener.STATUS_FAILURE) fFailureCount++; else if (status == ITestRunListener.STATUS_ERROR) fErrorCount++; } else if (info.getStatus() == ITestRunListener.STATUS_ERROR) { if (status == ITestRunListener.STATUS_OK) fErrorCount--; else if (status == ITestRunListener.STATUS_FAILURE) { fErrorCount--; fFailureCount++; } } else if (info.getStatus() == ITestRunListener.STATUS_FAILURE) { if (status == ITestRunListener.STATUS_OK) fFailureCount--; else if (status == ITestRunListener.STATUS_ERROR) { fFailureCount--; fErrorCount++; } } info.setStatus(status); final TestRunInfo finalInfo = info; postSyncRunnable(new Runnable() { public void run() { for (Enumeration e = fTestRunTabs.elements(); e.hasMoreElements();) { TestRunTab v = (TestRunTab) e.nextElement(); v.testStatusChanged(finalInfo); } } }); } public void testReran(String testId, String className, String testName, int statusCode, String trace, String expectedResult, String actualResult) { testReran(testId, className, testName, statusCode, trace); TestRunInfo info = getTestInfo(testId); info.setActual(actualResult); info.setExpected(expectedResult); fFailureTrace.updateEnablement(info); } private void postEndTest(final String testId, final String testName) { postSyncRunnable(new Runnable() { public void run() { if (isDisposed()) return; handleEndTest(); for (Enumeration e = fTestRunTabs.elements(); e.hasMoreElements();) { TestRunTab v = (TestRunTab) e.nextElement(); v.endTest(testId); } if (fFailureCount + fErrorCount > 0) { // TODO Re-enable actions //fNextAction.setEnabled(true); //fPreviousAction.setEnabled(true); } } }); } private void handleEndTest() { fProgressBar.step(fFailureCount + fErrorCount); if (fShowOnErrorOnly) { Image progress = fProgressImages.getImage(fExecutedTests, fTestCount, fErrorCount, fFailureCount); if (progress != fViewImage) { fViewImage = progress; firePropertyChange(IWorkbenchPart.PROP_TITLE); } } } public void setShowOnErrorOnly(boolean showOnErrorOnly) { this.fShowOnErrorOnly = showOnErrorOnly; } public boolean getShowOnErrorOnly() { return this.fShowOnErrorOnly; } /* * @see ITestRunListener#testStarted */ public void testStarted(String testId, String testName) { postStartTest(testId, testName); // reveal the part when the first test starts if (!fShowOnErrorOnly && fExecutedTests == 1) postShowTestResultsView(); TestRunInfo testInfo = getTestInfo(testId); if (testInfo == null) { testInfo = new TestRunInfo(testId, testName); fTestInfos.put(testId, testInfo); } String className = testInfo.getClassName(); String method = testInfo.getTestMethodName(); String status = TestUnitMessages.getFormattedString(TestUnitMessages.TestRunnerViewPart_message_started, new String[] { className, method}); setInfoMessage(status); fStartedCount++; } private void postStartTest(final String testId, final String testName) { postSyncRunnable(new Runnable() { public void run() { if (isDisposed()) return; for (Enumeration e = fTestRunTabs.elements(); e.hasMoreElements();) { TestRunTab v = (TestRunTab) e.nextElement(); v.startTest(testId); } } }); } /* * @see ITestRunListener#testRunStopped */ public void testRunStopped(final long elapsedTime) { setInfoMessage(TestUnitMessages.TestRunnerViewPart_message_stopped); handleStopped(); fIsRunning = false; fIsStopped = true; } private void handleStopped() { postSyncRunnable(new Runnable() { public void run() { if (isDisposed()) return; resetViewIcon(); //fStopAction.setEnabled(false); fProgressBar.stopped(); } }); stopUpdateJob(); } /* * @see ITestRunListener#testRunEnded */ public void testRunEnded(long elapsedTime) { fExecutedTests--; fIsRunning = false; String[] keys = { elapsedTimeAsString(elapsedTime)}; String msg = TestUnitMessages.getFormattedString(TestUnitMessages.TestRunnerViewPart_message_finish, keys); if (hasErrorsOrFailures()) postError(msg); else setInfoMessage(msg); postSyncRunnable(new Runnable() { public void run() { if (isDisposed()) return; //fStopAction.setEnabled(lastLaunchIsKeptAlive()); if (fFailures.size() > 0) { selectFirstFailure(); } updateViewIcon(); if (fDirtyListener == null) { fDirtyListener = new DirtyListener(); RubyCore.addElementChangedListener(fDirtyListener); } for (Enumeration e = fTestRunTabs.elements(); e.hasMoreElements();) { TestRunTab v = (TestRunTab) e.nextElement(); v.aboutToEnd(); } } }); stopUpdateJob(); } private String elapsedTimeAsString(long runTime) { return NumberFormat.getInstance().format((double) runTime / 1000); } private boolean hasErrorsOrFailures() { return fErrorCount + fFailureCount > 0; } protected void selectFirstFailure() { TestRunInfo firstFailure = fFailures.get(0); if (firstFailure != null && fAutoScroll) { fActiveRunTab.setSelectedTest(firstFailure.getTestId()); handleTestSelected(firstFailure.getTestId()); } } /* * @see ITestRunListener#testRunTerminated */ public void testRunTerminated() { String msg = TestUnitMessages.TestRunnerViewPart_message_terminated; showMessage(msg); handleStopped(); fIsRunning = false; fIsStopped= true; } private void showMessage(String msg) { postError(msg); } /* * @see ITestRunListener#testRunStarted(testCount) */ public void testRunStarted(final int testCount) { reset(testCount); // fShowOnErrorOnly = TestUnitPreferencePage.getShowOnErrorOnly(); fExecutedTests++; stopUpdateJob(); fUpdateJob = new UpdateUIJob(TestUnitMessages.TestRunnerViewPart_jobName); fUpdateJob.schedule(REFRESH_INTERVAL); fIsRunning = true; } private void refreshCounters() { fCounterPanel.setErrorValue(fErrorCount); fCounterPanel.setFailureValue(fFailureCount); fCounterPanel.setRunValue(fExecutedTests); fProgressBar.refresh(fErrorCount + fFailureCount > 0); } protected void doShowStatus() { setContentDescription(fStatus); } /* * @see ITestRunListener2#testTreeEntry */ public void testTreeEntry(final String treeEntry) { postSyncRunnable(new Runnable() { public void run() { if (isDisposed()) return; for (Enumeration e = fTestRunTabs.elements(); e.hasMoreElements();) { TestRunTab v = (TestRunTab) e.nextElement(); v.newTreeEntry(treeEntry); } } }); } /** * Stops the currently running test and shuts down the RemoteTestRunner */ public void rerunTestRun() { if (lastLaunchIsKeptAlive()) { // prompt for terminating the existing run if (MessageDialog.openQuestion(getSite().getShell(), TestUnitMessages.TestRunnerViewPart_terminate_title, TestUnitMessages.TestRunnerViewPart_terminate_message)) { if (fTestRunnerClient != null) fTestRunnerClient.stopTest(); } } if (fLastLaunch != null && fLastLaunch.getLaunchConfiguration() != null) { DebugUITools.launch(fLastLaunch.getLaunchConfiguration(), fLastLaunch.getLaunchMode()); } } private void addResizeListener(Composite parent) { parent.addControlListener(new ControlListener() { public void controlMoved(ControlEvent e) { } public void controlResized(ControlEvent e) { computeOrientation(); } }); } void computeOrientation() { if (fOrientation != VIEW_ORIENTATION.AUTOMATIC) { fCurrentOrientation= fOrientation; setOrientation(fCurrentOrientation); } else { Point size= fParent.getSize(); if (size.x != 0 && size.y != 0) { if (size.x > size.y) setOrientation(VIEW_ORIENTATION.HORIZONTAL); else setOrientation(VIEW_ORIENTATION.VERTICAL); } } } private void setOrientation(VIEW_ORIENTATION orientation) { if ((fSashForm == null) || fSashForm.isDisposed()) return; boolean horizontal = orientation == VIEW_ORIENTATION.HORIZONTAL; fSashForm.setOrientation(horizontal ? SWT.HORIZONTAL : SWT.VERTICAL); for (int i = 0; i < fToggleOrientationActions.length; ++i) fToggleOrientationActions[i].setChecked(fOrientation == fToggleOrientationActions[i].getOrientation()); fCurrentOrientation = orientation; GridLayout layout= (GridLayout) fCounterComposite.getLayout(); setCounterColumns(layout); fParent.layout(); } public IRubyProject getLaunchedProject() { return fTestProject; } public ILaunch getLastLaunch() { return fLastLaunch; } private void processChangesInUI() { if (fSashForm.isDisposed()) return; // doShowInfoMessage(); doShowStatus(); refreshCounters(); if (!fPartIsVisible) updateViewTitleProgress(); else { updateViewIcon(); } // boolean hasErrorsOrFailures= hasErrorsOrFailures(); // fNextAction.setEnabled(hasErrorsOrFailures); // fPreviousAction.setEnabled(hasErrorsOrFailures); // fTestViewer.processChangesInUI(); } private void updateViewIcon() { if (fIsStopped || fIsRunning || fStartedCount == 0) fViewImage= fOriginalViewImage; else if (hasErrorsOrFailures()) fViewImage= fTestRunFailIcon; else fViewImage= fTestRunOKIcon; firePropertyChange(IWorkbenchPart.PROP_TITLE); } /* * @see IWorkbenchPart#getTitleImage() */ public Image getTitleImage() { if (fOriginalViewImage == null) fOriginalViewImage= super.getTitleImage(); if (fViewImage == null) return super.getTitleImage(); return fViewImage; } private void updateViewTitleProgress() { // if (fTestRunSession != null) { if (fIsRunning) { Image progress= fProgressImages.getImage( fStartedCount, fTestCount, fErrorCount, fFailureCount); if (progress != fViewImage) { fViewImage= progress; firePropertyChange(IWorkbenchPart.PROP_TITLE); } } else { updateViewIcon(); } // } else { // resetViewIcon(); // } } void codeHasChanged() { if (fDirtyListener != null) { RubyCore.removeElementChangedListener(fDirtyListener); fDirtyListener= null; } if (fViewImage == fTestRunOKIcon) fViewImage= fTestRunOKDirtyIcon; else if (fViewImage == fTestRunFailIcon) fViewImage= fTestRunFailDirtyIcon; Runnable r= new Runnable() { public void run() { if (isDisposed()) return; firePropertyChange(IWorkbenchPart.PROP_TITLE); } }; if (!isDisposed()) getDisplay().asyncExec(r); } class UpdateUIJob extends UIJob { private boolean fRunning = true; public UpdateUIJob(String name) { super(name); setSystem(true); } public IStatus runInUIThread(IProgressMonitor monitor) { if (!isDisposed()) { processChangesInUI(); } schedule(REFRESH_INTERVAL); return Status.OK_STATUS; } public void stop() { fRunning = false; } public boolean shouldSchedule() { return fRunning; } } private class RerunLastAction extends Action { public RerunLastAction() { setText(TestUnitMessages.TestRunnerViewPart_rerunaction_label); setToolTipText(TestUnitMessages.TestRunnerViewPart_rerunaction_tooltip); setDisabledImageDescriptor(TestunitPlugin.getImageDescriptor("dlcl16/relaunch.gif")); //$NON-NLS-1$ setHoverImageDescriptor(TestunitPlugin.getImageDescriptor("elcl16/relaunch.gif")); //$NON-NLS-1$ setImageDescriptor(TestunitPlugin.getImageDescriptor("elcl16/relaunch.gif")); //$NON-NLS-1$ setActionDefinitionId(RERUN_LAST_COMMAND); } public void run() { rerunTestRun(); } } private class ActivateOnErrorAction extends Action { public ActivateOnErrorAction() { super(TestUnitMessages.TestRunnerViewPart_activate_on_failure_only, IAction.AS_CHECK_BOX); update(); } public void update() { setChecked(getShowOnErrorOnly()); } public void run() { boolean checked= isChecked(); fShowOnErrorOnly= checked; IPreferenceStore store= TestunitPlugin.getDefault().getPreferenceStore(); store.setValue(TestUnitPreferencesConstants.SHOW_ON_ERROR_ONLY, checked); } } /** * Listen for for modifications to Ruby elements */ private class DirtyListener implements IElementChangedListener { public void elementChanged(ElementChangedEvent event) { processDelta(event.getDelta()); } private boolean processDelta(IRubyElementDelta delta) { int kind= delta.getKind(); int details= delta.getFlags(); int type= delta.getElement().getElementType(); switch (type) { // Consider containers for class files. case IRubyElement.RUBY_MODEL: case IRubyElement.RUBY_PROJECT: case IRubyElement.SOURCE_FOLDER_ROOT: case IRubyElement.SOURCE_FOLDER: // If we did something different than changing a child we flush the undo / redo stack. if (kind != IRubyElementDelta.CHANGED || details != IRubyElementDelta.F_CHILDREN) { codeHasChanged(); return false; } break; case IRubyElement.SCRIPT: // if we have changed a primary working copy (e.g created, removed, ...) // then we do nothing. if ((details & IRubyElementDelta.F_PRIMARY_WORKING_COPY) != 0) return true; codeHasChanged(); return false; default: codeHasChanged(); return false; } IRubyElementDelta[] affectedChildren= delta.getAffectedChildren(); if (affectedChildren == null) return true; for (int i= 0; i < affectedChildren.length; i++) { if (!processDelta(affectedChildren[i])) return false; } return true; } } }