/******************************************************************************* * Copyright (c) 2000, 2007 IBM Corporation 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: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.dltk.internal.testing.model; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.ListenerList; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchManager; import org.eclipse.debug.core.ILaunchesListener2; import org.eclipse.dltk.annotations.Internal; import org.eclipse.dltk.core.IScriptProject; import org.eclipse.dltk.internal.testing.TestCategoryEngineManager; import org.eclipse.dltk.internal.testing.launcher.NullTestRunnerUI; import org.eclipse.dltk.internal.testing.launcher.NullTestingEngine; import org.eclipse.dltk.internal.testing.model.TestElement.Status; import org.eclipse.dltk.testing.DLTKTestingConstants; import org.eclipse.dltk.testing.DLTKTestingMessages; import org.eclipse.dltk.testing.DLTKTestingPlugin; import org.eclipse.dltk.testing.ITestCategoryEngine; import org.eclipse.dltk.testing.ITestRunnerUI; import org.eclipse.dltk.testing.ITestRunnerUIExtension; import org.eclipse.dltk.testing.ITestSession; import org.eclipse.dltk.testing.ITestingClient; import org.eclipse.dltk.testing.ITestingEngine; import org.eclipse.dltk.testing.MessageIds; import org.eclipse.dltk.testing.TestCategoryDescriptor; import org.eclipse.dltk.testing.model.ITestElement; import org.eclipse.dltk.testing.model.ITestElementContainer; import org.eclipse.dltk.testing.model.ITestElementPredicate; import org.eclipse.dltk.testing.model.ITestRunSession; import com.ibm.icu.text.SimpleDateFormat; /** * A test run session holds all information about a test run, i.e. * launch configuration, launch, test tree (including results). */ public class TestRunSession implements ITestRunSession, ITestSession { /** * The launch, or <code>null</code> iff this session was run externally. */ private final ILaunch fLaunch; private final String fTestRunName; /** * Java project, or <code>null</code>. */ private final IScriptProject fProject; private final ITestingEngine fTestingEngine; private final ITestRunnerUI testRunnerUI; private final ITestCategoryEngine[] categoryEngines; /** * Test runner client or <code>null</code>. */ private ITestRunnerClient fTestRunnerClient; private final ListenerList/*<ITestSessionListener>*/ fSessionListeners; /** * The model root, or <code>null</code> if swapped to disk. */ private TestRoot fTestRoot; /** * The test run session's cached result, or <code>null</code> if <code>fTestRoot != null</code>. */ private Result fTestResult; /** * Map from testId to testElement. */ private Map<String, TestElement> fIdToTest; /** * test categories */ private Map<String, TestCategoryElement> fCategoryMap; /** * The TestSuites for which additional children are expected. */ private List<IncompleteTestSuite> fIncompleteTestSuites; /** * Suite for unrooted test case elements, or <code>null</code>. */ private TestSuiteElement fUnrootedSuite; /** * Number of tests started during this test run. */ volatile int fStartedCount; /** * Number of tests ignored during this test run. */ volatile int fIgnoredCount; /** * Number of errors during this test run. */ volatile int fErrorCount; /** * Number of failures during this test run. */ volatile int fFailureCount; /** * Total number of tests to run. */ volatile int fTotalCount; /** * Number of created test cases. */ volatile int fCreatedTestCaseCount; /** * Start time in millis. */ volatile long fStartTime; volatile boolean fIsRunning; volatile boolean fIsStopped; /** * @param testRunName * @param project may be <code>null</code> */ public TestRunSession(String testRunName, IScriptProject project) { //TODO: check assumptions about non-null fields fLaunch= null; fProject= null; //TODO Assert.isNotNull(testRunName); fTestRunName= testRunName; fTestingEngine= NullTestingEngine.getInstance(); testRunnerUI= NullTestRunnerUI.getInstance(); categoryEngines = null; fTestRoot= new TestRoot(this); fIdToTest = new HashMap<String, TestElement>(); fCategoryMap = new HashMap<String, TestCategoryElement>(); fTestRunnerClient= null; fSessionListeners= new ListenerList(); } public TestRunSession(ILaunch launch, IScriptProject project, ITestRunnerClient runnerClient) { Assert.isNotNull(launch); Assert.isNotNull(runnerClient); fLaunch= launch; fProject= project; ILaunchConfiguration launchConfiguration= launch.getLaunchConfiguration(); if (launchConfiguration != null) { fTestRunName= launchConfiguration.getName(); fTestingEngine= DLTKTestingConstants.getTestingEngine(launchConfiguration); testRunnerUI= fTestingEngine.getTestRunnerUI(project, launchConfiguration); categoryEngines = TestCategoryEngineManager .getCategoryEngines(testRunnerUI); } else { fTestRunName= project.getElementName(); fTestingEngine= NullTestingEngine.getInstance(); testRunnerUI= NullTestRunnerUI.getInstance(); categoryEngines = null; } fTestRoot= new TestRoot(this); fIdToTest = new HashMap<String, TestElement>(); fCategoryMap = new HashMap<String, TestCategoryElement>(); fTestRunnerClient= runnerClient; fTestRunnerClient.startListening(new TestSessionNotifier()); final ILaunchManager launchManager= DebugPlugin.getDefault().getLaunchManager(); launchManager.addLaunchListener(new ILaunchesListener2() { public void launchesTerminated(ILaunch[] launches) { if (Arrays.asList(launches).contains(fLaunch)) { if (fTestRunnerClient != null) { fTestRunnerClient.stopWaiting(); } launchManager.removeLaunchListener(this); scheduleTestRunTerminated(); } } public void launchesRemoved(ILaunch[] launches) { if (Arrays.asList(launches).contains(fLaunch)) { if (fTestRunnerClient != null) { fTestRunnerClient.stopWaiting(); } launchManager.removeLaunchListener(this); scheduleTestRunTerminated(); } } public void launchesChanged(ILaunch[] launches) { } public void launchesAdded(ILaunch[] launches) { } private void scheduleTestRunTerminated() { if (!fIsRunning) return; final Job job = new Job( "TestRunSession - notify launch terminated") { //$NON-NLS-1$ @Override protected IStatus run(IProgressMonitor monitor) { testRunTerminated(); return org.eclipse.core.runtime.Status.OK_STATUS; } }; job.setSystem(true); // small delay, giving a chance for the client to notify in a // normal way. job.schedule(750); } }); fSessionListeners= new ListenerList(); addTestSessionListener(new TestRunListenerAdapter(this)); } void reset() { fStartedCount= 0; fFailureCount= 0; fErrorCount= 0; fIgnoredCount= 0; fTotalCount= 0; fCreatedTestCaseCount=0; fTestRoot= new TestRoot(this); fTestResult= null; fIdToTest = new HashMap<String, TestElement>(); fCategoryMap = new HashMap<String, TestCategoryElement>(); } /* * @see org.eclipse.dltk.testing.model.ITestElement#getId() */ public String getId() { return fTestRunName; } /* (non-Javadoc) * @see org.eclipse.jdt.junit.ITestRunSession#getProgressState() */ public ProgressState getProgressState() { if (isRunning()) { return ProgressState.RUNNING; } if (isStopped()) { return ProgressState.STOPPED; } return ProgressState.COMPLETED; } /* (non-Javadoc) * @see org.eclipse.jdt.junit.model.ITestElement#getTestResult(boolean) */ public Result getTestResult(boolean includeChildren) { if (fTestRoot != null) { return fTestRoot.getTestResult(true); } else { return fTestResult; } } /* (non-Javadoc) * @see org.eclipse.jdt.junit.model.ITestElementContainer#getChildren() */ public ITestElement[] getChildren() { return getTestRoot().getChildren(); } /* (non-Javadoc) * @see org.eclipse.jdt.junit.model.ITestElement#getFailureTrace() */ /* (non-Javadoc) * @see org.eclipse.dltk.internal.testing.model.ITestSession#getFailureTrace() */ public FailureTrace getFailureTrace() { return null; } /* (non-Javadoc) * @see org.eclipse.jdt.junit.model.ITestElement#getParentContainer() */ public ITestElementContainer getParentContainer() { return null; } /* (non-Javadoc) * @see org.eclipse.jdt.junit.model.ITestElement#getTestRunSession() */ public ITestRunSession getTestRunSession() { return this; } public TestRoot getTestRoot() { swapIn(); //TODO: TestRoot should stay (e.g. for getTestRoot().getStatus()) return fTestRoot; } /** * @return the Java project, or <code>null</code> */ public IScriptProject getLaunchedProject() { return fProject; } public ITestingEngine getTestingEngine() { return fTestingEngine; } /* (non-Javadoc) * @see org.eclipse.dltk.internal.testing.model.ITestSession#getLaunch() */ public ILaunch getLaunch() { return fLaunch; } public String getTestRunName() { return fTestRunName; } /* (non-Javadoc) * @see org.eclipse.dltk.internal.testing.model.ITestSession#getErrorCount() */ public int getErrorCount() { return fErrorCount; } /* (non-Javadoc) * @see org.eclipse.dltk.internal.testing.model.ITestSession#getFailureCount() */ public int getFailureCount() { return fFailureCount; } /* (non-Javadoc) * @see org.eclipse.dltk.internal.testing.model.ITestSession#getStartedCount() */ public int getStartedCount() { return fStartedCount; } /* (non-Javadoc) * @see org.eclipse.dltk.internal.testing.model.ITestSession#getIgnoredCount() */ public int getIgnoredCount() { return fIgnoredCount; } public int getTotalCount() { return fTotalCount; } /* (non-Javadoc) * @see org.eclipse.dltk.internal.testing.model.ITestSession#setTotalCount(int) */ public void setTotalCount(int count) { this.fTotalCount = count; // System.out.println("COUNT:" + count); } /** * @param value */ protected void adjustTotalCount(int value) { if (value > fTotalCount) { fTotalCount = value; } } /* (non-Javadoc) * @see org.eclipse.dltk.internal.testing.model.ITestSession#getStartTime() */ public long getStartTime() { return fStartTime; } /* (non-Javadoc) * @see org.eclipse.dltk.internal.testing.model.ITestSession#isStopped() */ public boolean isStopped() { return fIsStopped; } public void addTestSessionListener(ITestSessionListener listener) { swapIn(); fSessionListeners.add(listener); } public void removeTestSessionListener(ITestSessionListener listener) { fSessionListeners.remove(listener); } public void swapOut() { if (fTestRoot == null) return; if (isRunning() || isStarting() || isKeptAlive()) return; Object[] listeners= fSessionListeners.getListeners(); for (int i= 0; i < listeners.length; ++i) { ITestSessionListener registered= (ITestSessionListener) listeners[i]; if (! registered.acceptsSwapToDisk()) return; } try { File swapFile= getSwapFile(); DLTKTestingModel.exportTestRunSession(this, swapFile); fTestResult= fTestRoot.getTestResult(true); fTestRoot= null; fTestRunnerClient= null; fIdToTest = new HashMap<String, TestElement>(); fCategoryMap = new HashMap<String, TestCategoryElement>(); fIncompleteTestSuites= null; fUnrootedSuite= null; } catch (IllegalStateException e) { DLTKTestingPlugin.log(e); } catch (CoreException e) { DLTKTestingPlugin.log(e); } } /* (non-Javadoc) * @see org.eclipse.dltk.internal.testing.model.ITestSession#isStarting() */ public boolean isStarting() { return getStartTime() == 0 && fLaunch != null && ! fLaunch.isTerminated(); } public void removeSwapFile() { File swapFile= getSwapFile(); if (swapFile.exists()) swapFile.delete(); } private File getSwapFile() throws IllegalStateException { File historyDir= DLTKTestingPlugin.getHistoryDirectory(); String isoTime= new SimpleDateFormat("yyyyMMdd-HHmmss.SSS").format(new Date(getStartTime())); //$NON-NLS-1$ String swapFileName= isoTime + ".xml"; //$NON-NLS-1$ return new File(historyDir, swapFileName); } public void swapIn() { if (fTestRoot != null) return; try { DLTKTestingModel.importIntoTestRunSession(getSwapFile(), this); } catch (IllegalStateException e) { DLTKTestingPlugin.log(e); fTestRoot= new TestRoot(this); fTestResult= null; } catch (CoreException e) { DLTKTestingPlugin.log(e); fTestRoot= new TestRoot(this); fTestResult= null; } } public void stopTestRun() { if (isRunning() || ! isKeptAlive()) fIsStopped= true; if (fTestRunnerClient != null) fTestRunnerClient.stopTest(); } /** * @return <code>true</code> iff the runtime VM of this test session is still alive */ public boolean isKeptAlive() { if (fTestRunnerClient != null && fLaunch != null && fTestRunnerClient.isRunning() && ILaunchManager.DEBUG_MODE.equals(fLaunch.getLaunchMode())) { ILaunchConfiguration config= fLaunch.getLaunchConfiguration(); try { return config != null && config.getAttribute(DLTKTestingConstants.ATTR_KEEPRUNNING, false); } catch (CoreException e) { return false; } } else { return false; } } /* (non-Javadoc) * @see org.eclipse.dltk.internal.testing.model.ITestSession#isRunning() */ public boolean isRunning() { return fIsRunning; } /** * @param testElement * @param launchMode * @return <code>false</code> iff the rerun could not be started * @throws CoreException */ public boolean rerunTest(ITestElement testElement, String launchMode) throws CoreException { if (isKeptAlive()) { Status status= ((TestCaseElement) getTestElement(testElement.getId())).getStatus(); if (status == Status.ERROR) { fErrorCount--; } else if (status == Status.FAILURE) { fFailureCount--; } /* TODO fTestRunnerClient.rerunTest(testId, className, testName); */ return true; } else if (fLaunch != null) { if (testRunnerUI instanceof ITestRunnerUIExtension) { return ((ITestRunnerUIExtension) testRunnerUI).rerunTest( fLaunch, testElement, launchMode); } // run the selected test using the previous launch configuration ILaunchConfiguration launchConfiguration= fLaunch.getLaunchConfiguration(); if (launchConfiguration != null) { //String name= className; //if (testName != null) //name+= "."+testName; //$NON-NLS-1$ //String configName= Messages.format(DLTKTestingMessages.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(ScriptLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, className); // reset the container //tmp.setAttribute(DLTKTestingConstants.ATTR_TEST_CONTAINER, ""); //$NON-NLS-1$ //if (testName != null) { //tmp.setAttribute(DLTKTestingConstants.ATTR_TEST_METHOD_NAME, testName); // String args= "-rerun "+testId; // tmp.setAttribute(IJavaLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS, args); //} //tmp.launch(launchMode, null); return true; } } return false; } public TestElement getTestElement(String id) { return fIdToTest.get(id); } private TestCategoryElement selectCategory(String id, String testName, boolean isSuite) { if (categoryEngines != null) { for (int i = 0; i < categoryEngines.length; ++i) { final TestCategoryDescriptor descriptor = categoryEngines[i] .getCategory(id, testName, isSuite); if (descriptor != null) { TestCategoryElement categoryElement = fCategoryMap .get(descriptor.getId()); if (categoryElement == null) { categoryElement = new TestCategoryElement(fTestRoot, descriptor.getId(), descriptor.getName()); fCategoryMap.put(descriptor.getId(), categoryElement); } return categoryElement; } } } return null; } private TestElement addTreeEntry(String treeEntry) { // format: testId","testName","isSuite","testcount int index0= treeEntry.indexOf(','); String id= treeEntry.substring(0, index0); StringBuffer testNameBuffer= new StringBuffer(100); int index1 = scanTestName(treeEntry, index0 + 1, testNameBuffer, true); String testName= testNameBuffer.toString().trim(); int index2= treeEntry.indexOf(',', index1 + 1); boolean isSuite= treeEntry.substring(index1 + 1, index2).equals("true"); //$NON-NLS-1$ int testCount= Integer.parseInt(treeEntry.substring(index2 + 1)); return addTreeEntry(id, testName, isSuite, testCount); } private TestElement addTreeEntry(String id, String testName, boolean isSuite, int testCount) { if (fIncompleteTestSuites.isEmpty()) { TestContainerElement category = selectCategory(id, testName, isSuite); if (category == null) { category = fTestRoot; } return createTestElement(category, id, testName, isSuite, testCount); } else { int suiteIndex= fIncompleteTestSuites.size() - 1; IncompleteTestSuite openSuite= fIncompleteTestSuites.get(suiteIndex); openSuite.fOutstandingChildren--; if (openSuite.fOutstandingChildren <= 0) fIncompleteTestSuites.remove(suiteIndex); return createTestElement(openSuite.fTestSuiteElement, id, testName, isSuite, testCount); } } public TestElement createTestElement(TestContainerElement parent, String id, String testName, boolean isSuite, int testCount) { TestElement testElement; if (isSuite) { TestSuiteElement testSuiteElement= new TestSuiteElement(parent, id, testName, testCount); testElement= testSuiteElement; if (testCount > 0) fIncompleteTestSuites.add(new IncompleteTestSuite(testSuiteElement, testCount)); } else { testElement= new TestCaseElement(parent, id, testName); ++fCreatedTestCaseCount; adjustTotalCount(fCreatedTestCaseCount); } fIdToTest.put(id, testElement); return testElement; } /** * Append the test name from <code>s</code> to <code>testName</code>. * * @param s the string to scan * @param start the offset of the first character in <code>s</code> * @param testName the result * * @return the index of the next ',' */ static int scanTestName(String s, int start, StringBuffer testName, boolean breakOnComma) { boolean inQuote= false; int i= start; for (; i < s.length(); i++) { char c= s.charAt(i); if (c == '\\' && !inQuote) { inQuote= true; continue; } else if (inQuote) { inQuote= false; testName.append(c); } else if (breakOnComma && c == ',') break; else testName.append(c); } return i; } /** * An {@link ITestRunListener2} that listens to events from the * {@link RemoteTestRunnerClient} and translates them into high-level model * events (broadcasted to {@link ITestSessionListener}s). */ private class TestSessionNotifier implements ITestRunListener2 { public void testRunStarted(int testCount) { fIncompleteTestSuites= new ArrayList<IncompleteTestSuite>(); fStartedCount= 0; fIgnoredCount= 0; fFailureCount= 0; fErrorCount= 0; fTotalCount= testCount; fCreatedTestCaseCount = 0; fStartTime= System.currentTimeMillis(); fIsRunning= true; Object[] listeners= fSessionListeners.getListeners(); for (int i= 0; i < listeners.length; ++i) { ((ITestSessionListener) listeners[i]).sessionStarted(); } } public void testRunEnded(long elapsedTime) { fIsRunning= false; Object[] listeners= fSessionListeners.getListeners(); for (int i= 0; i < listeners.length; ++i) { ((ITestSessionListener) listeners[i]).sessionEnded(elapsedTime); } } public void testRunStopped(long elapsedTime) { fIsRunning= false; fIsStopped= true; Object[] listeners= fSessionListeners.getListeners(); for (int i= 0; i < listeners.length; ++i) { ((ITestSessionListener) listeners[i]).sessionStopped(elapsedTime); } } public void testRunTerminated() { TestRunSession.this.testRunTerminated(); } /* (non-Javadoc) * @see org.eclipse.jdt.internal.junit.model.ITestRunListener2#testTreeEntry(java.lang.String) */ public void testTreeEntry(String description) { TestElement testElement= addTreeEntry(description); Object[] listeners= fSessionListeners.getListeners(); for (int i= 0; i < listeners.length; ++i) { ((ITestSessionListener) listeners[i]).testAdded(testElement); } } public void testTreeEntry(String testId, String testName, boolean isSuite, int testCount) { TestElement testElement = addTreeEntry(testId, testName, isSuite, testCount); Object[] listeners = fSessionListeners.getListeners(); for (int i = 0; i < listeners.length; ++i) { ((ITestSessionListener) listeners[i]).testAdded(testElement); } } private TestElement createUnrootedTestElement(String testId, String testName) { TestSuiteElement unrootedSuite= getUnrootedSuite(); TestElement testElement= createTestElement(unrootedSuite, testId, testName, false, 1); Object[] listeners= fSessionListeners.getListeners(); for (int i= 0; i < listeners.length; ++i) { ((ITestSessionListener) listeners[i]).testAdded(testElement); } return testElement; } private TestSuiteElement getUnrootedSuite() { if (fUnrootedSuite == null) { fUnrootedSuite= (TestSuiteElement) createTestElement(fTestRoot, "-2", DLTKTestingMessages.TestRunSession_unrootedTests, true, 0); //$NON-NLS-1$ } return fUnrootedSuite; } public void testStarted(String testId, String testName) { if (fStartedCount == 0) { Object[] listeners= fSessionListeners.getListeners(); for (int i= 0; i < listeners.length; ++i) { ((ITestSessionListener) listeners[i]).runningBegins(); } } TestElement testElement= getTestElement(testId); if (testElement == null) { testElement= createUnrootedTestElement(testId, testName); } else if (! (testElement instanceof TestCaseElement)) { logUnexpectedTest(testId, testElement); return; } TestCaseElement testCaseElement= (TestCaseElement) testElement; setStatus(testCaseElement, Status.RUNNING); fStartedCount++; Object[] listeners= fSessionListeners.getListeners(); for (int i= 0; i < listeners.length; ++i) { ((ITestSessionListener) listeners[i]).testStarted(testCaseElement); } } public void testEnded(String testId, String testName) { TestElement testElement= getTestElement(testId); if (testElement == null) { testElement= createUnrootedTestElement(testId, testName); } else if (! (testElement instanceof TestCaseElement)) { logUnexpectedTest(testId, testElement); return; } TestCaseElement testCaseElement= (TestCaseElement) testElement; if (testName.startsWith(MessageIds.IGNORED_TEST_PREFIX)) { testCaseElement.setIgnored(true); fIgnoredCount++; } else if (testName.length() != 0 && !testName.equals(testCaseElement.getTestName())) { testCaseElement.setTestName(testName); } if (testCaseElement.getStatus() == Status.RUNNING) setStatus(testCaseElement, Status.OK); Object[] listeners= fSessionListeners.getListeners(); for (int i= 0; i < listeners.length; ++i) { ((ITestSessionListener) listeners[i]).testEnded(testCaseElement); } } public void testFailed(int status, String testId, String testName, String trace) { testFailed(status, testId, testName, trace, null, null, -1); } /* (non-Javadoc) * @see org.eclipse.jdt.internal.junit.model.ITestRunListener2#testFailed(int, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String) */ public void testFailed(int statusCode, String testId, String testName, String trace, String expected, String actual, int code) { TestElement testElement= getTestElement(testId); if (testElement == null) { testElement= createUnrootedTestElement(testId, testName); return; } Status status= Status.convert(statusCode, code); registerTestFailureStatus(testElement, status, trace, nullifyEmpty(expected), nullifyEmpty(actual)); Object[] listeners= fSessionListeners.getListeners(); for (int i= 0; i < listeners.length; ++i) { ((ITestSessionListener) listeners[i]).testFailed(testElement, status, trace, expected, actual, code); } } private String nullifyEmpty(String string) { if (string != null) { int length = string.length(); if (length == 0) return null; else if (string.charAt(length - 1) == '\n') return string.substring(0, length - 1); } return string; } public void testReran(String testId, String testClass, String testName, int status, String trace) { testReran(testId, testClass, testName, status, trace, "", ""); //$NON-NLS-1$ //$NON-NLS-2$ } /* (non-Javadoc) * @see org.eclipse.jdt.internal.junit.model.ITestRunListener2#testReran(java.lang.String, java.lang.String, java.lang.String, int, java.lang.String, java.lang.String, java.lang.String) */ public void testReran(String testId, String className, String testName, int statusCode, String trace, String expectedResult, String actualResult) { TestElement testElement= getTestElement(testId); if (testElement == null) { testElement= createUnrootedTestElement(testId, testName); } else if (! (testElement instanceof TestCaseElement)) { logUnexpectedTest(testId, testElement); return; } TestCaseElement testCaseElement= (TestCaseElement) testElement; Status status= Status.convert(statusCode, ITestingClient.PASSED); registerTestFailureStatus(testElement, status, trace, nullifyEmpty(expectedResult), nullifyEmpty(actualResult)); Object[] listeners= fSessionListeners.getListeners(); for (int i= 0; i < listeners.length; ++i) { //TODO: post old & new status? ((ITestSessionListener) listeners[i]).testReran(testCaseElement, status, trace, expectedResult, actualResult); } } private void logUnexpectedTest(String testId, TestElement testElement) { // DLTKTestingPlugin.log(new Exception("Unexpected TestElement type for testId '" + testId + "': " + testElement)); //$NON-NLS-1$ //$NON-NLS-2$ } } @Internal void testRunTerminated() { if (!fIsRunning || fIsStopped) return; fIsRunning = false; fIsStopped = true; Object[] listeners = fSessionListeners.getListeners(); for (int i = 0; i < listeners.length; ++i) { ((ITestSessionListener) listeners[i]).sessionTerminated(); } } private static class IncompleteTestSuite { public TestSuiteElement fTestSuiteElement; public int fOutstandingChildren; public IncompleteTestSuite(TestSuiteElement testSuiteElement, int outstandingChildren) { fTestSuiteElement= testSuiteElement; fOutstandingChildren= outstandingChildren; } } public void registerTestFailureStatus(TestElement testElement, Status status, String trace, String expected, String actual) { testElement.setStatus(status, trace, expected, actual); if (status.isError()) { fErrorCount++; } else if (status.isFailure()) { fFailureCount++; } } public void registerTestEnded(TestElement testElement, boolean completed) { if (testElement instanceof TestCaseElement) { if (! completed) { return; } fStartedCount++; if (((TestCaseElement) testElement).isIgnored()) { fIgnoredCount++; } if (! testElement.getStatus().isErrorOrFailure()) setStatus(testElement, Status.OK); } } private void setStatus(TestElement testElement, Status status) { testElement.setStatus(status); } public ITestElement[] getFailedTestElements(ITestElementPredicate predicate) { List<ITestElement> failures = new ArrayList<ITestElement>(); addFailures(failures, getTestRoot(), predicate); return failures.toArray(new TestElement[failures.size()]); } private void addFailures(List<ITestElement> failures, ITestElement testElement, ITestElementPredicate predicate) { Result testResult = testElement.getTestResult(true); if ((testResult == Result.ERROR || testResult == Result.FAILURE) && predicate.matches(testElement)) { failures.add(testElement); } if (testElement instanceof TestSuiteElement) { TestSuiteElement testSuiteElement = (TestSuiteElement) testElement; ITestElement[] children = testSuiteElement.getChildren(); for (int i = 0; i < children.length; i++) { addFailures(failures, children[i], predicate); } } } public ITestingClient getTestRunnerClient() { if (fTestRunnerClient instanceof ITestingClient) { return (ITestingClient) fTestRunnerClient; } else { return null; } } /** * @return */ public final ITestRunnerUI getTestRunnerUI() { return testRunnerUI; } /* (non-Javadoc) * @see org.eclipse.jdt.junit.model.ITestElement#getElapsedTimeInSeconds() */ public double getElapsedTimeInSeconds() { if (fTestRoot == null) return Double.NaN; return fTestRoot.getElapsedTimeInSeconds(); } }