/******************************************************************************* * Copyright (c) 2007, 2017 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.util.Stack; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.dltk.core.DLTKCore; import org.eclipse.dltk.core.IScriptModel; import org.eclipse.dltk.core.IScriptProject; import org.eclipse.dltk.internal.testing.model.TestElement.Status; 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; public class TestRunHandler extends DefaultHandler { /* * TODO: validate (currently assumes correct XML) */ private int fId; private TestRunSession fTestRunSession; private TestContainerElement 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; } @Override public void setDocumentLocator(Locator locator) { fLocator = locator; } @Override public void startDocument() throws SAXException { } @Override 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); IScriptProject javaProject = null; if (project != null) { IScriptModel javaModel = DLTKCore .create(ResourcesPlugin.getWorkspace().getRoot()); javaProject = javaModel.getScriptProject(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_CATEGORY)) { String id = attributes.getValue(IXMLTags.ATTR_ID); String name = attributes.getValue(IXMLTags.ATTR_NAME); fTestSuite = new TestCategoryElement(fTestSuite, id, name); } 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, 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 + "'", //$NON-NLS-1$//$NON-NLS-2$ fLocator); } } 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) { } } } @Override 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); } } @Override 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_CATEGORY)) { fTestSuite = fTestSuite.getParent(); } 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 " //$NON-NLS-1$//$NON-NLS-2$ + fLocator.getColumnNumber(); } throw new SAXException(msg); } @Override public void error(SAXParseException e) throws SAXException { throw e; } @Override 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; } }