blob: a97b56240fa1de3dafc4109b12102137b4c519bf [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2008 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
* Brock Janiczak (brockj@tpg.com.au)
* - https://bugs.eclipse.org/bugs/show_bug.cgi?id=102236: [JUnit] display execution time next to each test
*******************************************************************************/
package org.eclipse.jdt.internal.junit.model;
import java.util.Stack;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.jdt.core.IJavaModel;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.internal.junit.model.TestElement.Status;
public class TestRunHandler extends DefaultHandler {
/*
* TODO: validate (currently assumes correct XML)
*/
private int fId;
private TestRunSession fTestRunSession;
private TestSuiteElement fTestSuite;
private TestCaseElement fTestCase;
private Stack/*<Boolean>*/ fNotRun= new Stack();
private StringBuffer fFailureBuffer;
private boolean fInExpected;
private boolean fInActual;
private StringBuffer fExpectedBuffer;
private StringBuffer fActualBuffer;
private Locator fLocator;
private Status fStatus;
public TestRunHandler() {
}
public TestRunHandler(TestRunSession testRunSession) {
fTestRunSession= testRunSession;
}
public void setDocumentLocator(Locator locator) {
fLocator= locator;
}
public void startDocument() throws SAXException {
}
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if (qName.equals(IXMLTags.NODE_TESTRUN)) {
if (fTestRunSession == null) {
String name= attributes.getValue(IXMLTags.ATTR_NAME);
String project= attributes.getValue(IXMLTags.ATTR_PROJECT);
IJavaProject javaProject= null;
if (project != null) {
IJavaModel javaModel= JavaCore.create(ResourcesPlugin.getWorkspace().getRoot());
javaProject= javaModel.getJavaProject(project);
if (! javaProject.exists())
javaProject= null;
}
fTestRunSession= new TestRunSession(name, javaProject);
//TODO: read counts?
} else {
fTestRunSession.reset();
}
fTestSuite= fTestRunSession.getTestRoot();
} else if (qName.equals(IXMLTags.NODE_TESTSUITES)) {
// support Ant's 'junitreport' task; create suite from NODE_TESTSUITE
} else if (qName.equals(IXMLTags.NODE_TESTSUITE)) {
String name= attributes.getValue(IXMLTags.ATTR_NAME);
if (fTestRunSession == null) {
// support standalone suites and Ant's 'junitreport' task:
fTestRunSession= new TestRunSession(name, null);
fTestSuite= fTestRunSession.getTestRoot();
}
String pack= attributes.getValue(IXMLTags.ATTR_PACKAGE);
String suiteName= pack == null ? name : pack + "." + name; //$NON-NLS-1$
fTestSuite= (TestSuiteElement) fTestRunSession.createTestElement(fTestSuite, getNextId(), suiteName, true, 0);
readTime(fTestSuite, attributes);
fNotRun.push(Boolean.valueOf(attributes.getValue(IXMLTags.ATTR_INCOMPLETE)));
} else if (qName.equals(IXMLTags.NODE_PROPERTIES) || qName.equals(IXMLTags.NODE_PROPERTY)) {
// not interested
} else if (qName.equals(IXMLTags.NODE_TESTCASE)) {
String name= attributes.getValue(IXMLTags.ATTR_NAME);
String classname= attributes.getValue(IXMLTags.ATTR_CLASSNAME);
fTestCase= (TestCaseElement) fTestRunSession.createTestElement(fTestSuite, getNextId(), name + '(' + classname + ')', false, 0);
fNotRun.push(Boolean.valueOf(attributes.getValue(IXMLTags.ATTR_INCOMPLETE)));
fTestCase.setIgnored(Boolean.valueOf(attributes.getValue(IXMLTags.ATTR_IGNORED)).booleanValue());
readTime(fTestCase, attributes);
} else if (qName.equals(IXMLTags.NODE_ERROR)) {
//TODO: multiple failures: https://bugs.eclipse.org/bugs/show_bug.cgi?id=125296
fStatus= Status.ERROR;
fFailureBuffer= new StringBuffer();
} else if (qName.equals(IXMLTags.NODE_FAILURE)) {
//TODO: multiple failures: https://bugs.eclipse.org/bugs/show_bug.cgi?id=125296
fStatus= Status.FAILURE;
fFailureBuffer= new StringBuffer();
} else if (qName.equals(IXMLTags.NODE_EXPECTED)) {
fInExpected= true;
fExpectedBuffer= new StringBuffer();
} else if (qName.equals(IXMLTags.NODE_ACTUAL)) {
fInActual= true;
fActualBuffer= new StringBuffer();
} else if (qName.equals(IXMLTags.NODE_SYSTEM_OUT) || qName.equals(IXMLTags.NODE_SYSTEM_ERR)) {
// not interested
} else {
throw new SAXParseException("unknown node '" + qName + "'", fLocator); //$NON-NLS-1$//$NON-NLS-2$
}
}
private void readTime(TestElement testElement, Attributes attributes) {
String timeString= attributes.getValue(IXMLTags.ATTR_TIME);
if (timeString != null) {
try {
testElement.setElapsedTimeInSeconds(Double.parseDouble(timeString));
} catch (NumberFormatException e) {
}
}
}
public void characters(char[] ch, int start, int length) throws SAXException {
if (fInExpected) {
fExpectedBuffer.append(ch, start, length);
} else if (fInActual) {
fActualBuffer.append(ch, start, length);
} else if (fFailureBuffer != null) {
fFailureBuffer.append(ch, start, length);
}
}
public void endElement(String uri, String localName, String qName) throws SAXException {
if (qName.equals(IXMLTags.NODE_TESTRUN)) {
// OK
} else if (qName.equals(IXMLTags.NODE_TESTSUITES)) {
// OK
} else if (qName.equals(IXMLTags.NODE_TESTSUITE)) {
handleTestElementEnd(fTestSuite);
fTestSuite= fTestSuite.getParent();
//TODO: end suite: compare counters?
} else if (qName.equals(IXMLTags.NODE_PROPERTIES) || qName.equals(IXMLTags.NODE_PROPERTY)) {
// OK
} else if (qName.equals(IXMLTags.NODE_TESTCASE)) {
handleTestElementEnd(fTestCase);
fTestCase= null;
} else if (qName.equals(IXMLTags.NODE_FAILURE) || qName.equals(IXMLTags.NODE_ERROR)) {
TestElement testElement= fTestCase;
if (testElement == null)
testElement= fTestSuite;
handleFailure(testElement);
} else if (qName.equals(IXMLTags.NODE_EXPECTED)) {
fInExpected= false;
} else if (qName.equals(IXMLTags.NODE_ACTUAL)) {
fInActual= false;
} else if (qName.equals(IXMLTags.NODE_SYSTEM_OUT) || qName.equals(IXMLTags.NODE_SYSTEM_ERR)) {
// OK
} else {
handleUnknownNode(qName);
}
}
private void handleTestElementEnd(TestElement testElement) {
boolean completed= fNotRun.pop() != Boolean.TRUE;
fTestRunSession.registerTestEnded(testElement, completed);
}
private void handleFailure(TestElement testElement) {
if (fFailureBuffer != null) {
fTestRunSession.registerTestFailureStatus(testElement, fStatus, fFailureBuffer.toString(), toString(fExpectedBuffer), toString(fActualBuffer));
fFailureBuffer= null;
fExpectedBuffer= null;
fActualBuffer= null;
fStatus= null;
}
}
private String toString(StringBuffer buffer) {
return buffer != null ? buffer.toString() : null;
}
private void handleUnknownNode(String qName) throws SAXException {
//TODO: just log if debug option is enabled?
String msg= "unknown node '" + qName + "'"; //$NON-NLS-1$//$NON-NLS-2$
if (fLocator != null) {
msg += " at line " + fLocator.getLineNumber() + ", column " + fLocator.getColumnNumber(); //$NON-NLS-1$//$NON-NLS-2$
}
throw new SAXException(msg);
}
public void error(SAXParseException e) throws SAXException {
throw e;
}
public void warning(SAXParseException e) throws SAXException {
throw e;
}
private String getNextId() {
return Integer.toString(fId++);
}
/**
* @return the parsed test run session, or <code>null</code>
*/
public TestRunSession getTestRunSession() {
return fTestRunSession;
}
}