com.technophobia.substeps.model.serialize.SubstepsRunSessionSerializer.java Source code

Java tutorial

Introduction

Here is the source code for com.technophobia.substeps.model.serialize.SubstepsRunSessionSerializer.java

Source

/*******************************************************************************
 * Copyright Technophobia Ltd 2012
 * 
 * This file is part of the Substeps Eclipse Plugin.
 * 
 * The Substeps Eclipse Plugin is free software: you can redistribute it and/or modify
 * it under the terms of the Eclipse Public License v1.0.
 * 
 * The Substeps Eclipse Plugin is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * Eclipse Public License for more details.
 * 
 * You should have received a copy of the Eclipse Public License
 * along with the Substeps Eclipse Plugin.  If not, see <http://www.eclipse.org/legal/epl-v10.html>.
 ******************************************************************************/
package com.technophobia.substeps.model.serialize;

import java.io.IOException;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.util.Locale;

import org.eclipse.core.runtime.Assert;
import org.eclipse.jdt.core.IJavaProject;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.DTDHandler;
import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.AttributesImpl;

import com.technophobia.substeps.junit.ui.SubstepsRunSession;
import com.technophobia.substeps.model.structure.FailureTrace;
import com.technophobia.substeps.model.structure.Result;
import com.technophobia.substeps.model.structure.SubstepsTestElement;
import com.technophobia.substeps.model.structure.SubstepsTestLeafElement;
import com.technophobia.substeps.model.structure.SubstepsTestParentElement;
import com.technophobia.substeps.model.structure.SubstepsTestRootElement;

public class SubstepsRunSessionSerializer implements XMLReader {

    private static final String EMPTY = ""; //$NON-NLS-1$
    private static final String CDATA = "CDATA"; //$NON-NLS-1$
    private static final Attributes NO_ATTS = new AttributesImpl();

    private final SubstepsRunSession substepsRunSession;
    private ContentHandler handler;
    private ErrorHandler errorHandler;

    private final NumberFormat timeFormat = new DecimalFormat("0.0##", new DecimalFormatSymbols(Locale.US)); //$NON-NLS-1$ // not localized, parseable by Double.parseDouble(..)

    /**
     * @param substepsRunSession
     *            the test run session to serialize
     */
    public SubstepsRunSessionSerializer(final SubstepsRunSession substepsRunSession) {
        Assert.isNotNull(substepsRunSession);
        this.substepsRunSession = substepsRunSession;
    }

    @Override
    public void parse(final InputSource input) throws IOException, SAXException {
        if (handler == null)
            throw new SAXException("ContentHandler missing"); //$NON-NLS-1$

        handler.startDocument();
        handleTestRun();
        handler.endDocument();
    }

    private void handleTestRun() throws SAXException {
        final AttributesImpl atts = new AttributesImpl();
        addCDATA(atts, IXMLTags.ATTR_NAME, substepsRunSession.getTestRunName());
        final IJavaProject project = substepsRunSession.getLaunchedProject();
        if (project != null)
            addCDATA(atts, IXMLTags.ATTR_PROJECT, project.getElementName());
        addCDATA(atts, IXMLTags.ATTR_TESTS, substepsRunSession.getTotalCount());
        addCDATA(atts, IXMLTags.ATTR_STARTED, substepsRunSession.getStartedCount());
        addCDATA(atts, IXMLTags.ATTR_FAILURES, substepsRunSession.getFailureCount());
        addCDATA(atts, IXMLTags.ATTR_ERRORS, substepsRunSession.getErrorCount());
        addCDATA(atts, IXMLTags.ATTR_IGNORED, substepsRunSession.getIgnoredCount());
        startElement(IXMLTags.NODE_TESTRUN, atts);

        final SubstepsTestRootElement root = substepsRunSession.getTestRoot();
        final SubstepsTestElement[] topSuites = root.getChildren();
        for (int i = 0; i < topSuites.length; i++) {
            handleTestElement(topSuites[i]);
        }

        endElement(IXMLTags.NODE_TESTRUN);
    }

    private void handleTestElement(final SubstepsTestElement testElement) throws SAXException {
        if (testElement instanceof SubstepsTestParentElement) {
            final SubstepsTestParentElement parentElement = (SubstepsTestParentElement) testElement;

            final AttributesImpl atts = new AttributesImpl();
            addCDATA(atts, IXMLTags.ATTR_NAME, parentElement.getTestName());
            if (!Double.isNaN(parentElement.getElapsedTimeInSeconds()))
                addCDATA(atts, IXMLTags.ATTR_TIME, timeFormat.format(parentElement.getElapsedTimeInSeconds()));
            if (!testElement.getStatus().isComplete() || !testElement.getTestResult(false).equals(Result.UNDEFINED))
                addCDATA(atts, IXMLTags.ATTR_INCOMPLETE, Boolean.TRUE.toString());

            startElement(IXMLTags.NODE_TESTSUITE, atts);
            addFailure(testElement);

            final SubstepsTestElement[] children = parentElement.getChildren();
            for (int i = 0; i < children.length; i++) {
                handleTestElement(children[i]);
            }
            endElement(IXMLTags.NODE_TESTSUITE);

        } else if (testElement instanceof SubstepsTestLeafElement) {
            final SubstepsTestLeafElement leafElement = (SubstepsTestLeafElement) testElement;

            final AttributesImpl atts = new AttributesImpl();
            addCDATA(atts, IXMLTags.ATTR_NAME, leafElement.getTestMethodName());
            // addCDATA(atts, IXMLTags.ATTR_CLASSNAME,
            // leafElement.getClassName());
            if (!Double.isNaN(leafElement.getElapsedTimeInSeconds()))
                addCDATA(atts, IXMLTags.ATTR_TIME, timeFormat.format(leafElement.getElapsedTimeInSeconds()));
            if (!testElement.getStatus().isComplete())
                addCDATA(atts, IXMLTags.ATTR_INCOMPLETE, Boolean.TRUE.toString());
            if (leafElement.isIgnored())
                addCDATA(atts, IXMLTags.ATTR_IGNORED, Boolean.TRUE.toString());

            startElement(IXMLTags.NODE_TESTCASE, atts);
            addFailure(testElement);

            endElement(IXMLTags.NODE_TESTCASE);

        } else {
            throw new IllegalStateException(String.valueOf(testElement));
        }

    }

    private void addFailure(final SubstepsTestElement testElement) throws SAXException {
        final FailureTrace failureTrace = testElement.getFailureTrace();
        if (failureTrace != null) {
            final AttributesImpl failureAtts = new AttributesImpl();
            // addCDATA(failureAtts, IXMLTags.ATTR_MESSAGE, xx);
            // addCDATA(failureAtts, IXMLTags.ATTR_TYPE, xx);
            final String failureKind = testElement.getTestResult(false) == Result.ERROR ? IXMLTags.NODE_ERROR
                    : IXMLTags.NODE_FAILURE;
            startElement(failureKind, failureAtts);
            final String expected = failureTrace.getExpected();
            final String actual = failureTrace.getActual();
            if (expected != null) {
                startElement(IXMLTags.NODE_EXPECTED, NO_ATTS);
                addCharacters(expected);
                endElement(IXMLTags.NODE_EXPECTED);
            }
            if (actual != null) {
                startElement(IXMLTags.NODE_ACTUAL, NO_ATTS);
                addCharacters(actual);
                endElement(IXMLTags.NODE_ACTUAL);
            }
            final String trace = failureTrace.getTrace();
            addCharacters(trace);
            endElement(failureKind);
        }
    }

    private void startElement(final String name, final Attributes atts) throws SAXException {
        handler.startElement(EMPTY, name, name, atts);
    }

    private void endElement(final String name) throws SAXException {
        handler.endElement(EMPTY, name, name);
    }

    private static void addCDATA(final AttributesImpl atts, final String name, final int value) {
        addCDATA(atts, name, Integer.toString(value));
    }

    private static void addCDATA(final AttributesImpl atts, final String name, final String value) {
        atts.addAttribute(EMPTY, EMPTY, name, CDATA, value);
    }

    private void addCharacters(final String string) throws SAXException {
        final String escapedString = escapeNonUnicodeChars(string);
        handler.characters(escapedString.toCharArray(), 0, escapedString.length());
    }

    /**
     * Replaces all non-Unicode characters in the given string.
     * 
     * @param string
     *            a string
     * @return string with Java-escapes
     * @since 3.6
     */
    private static String escapeNonUnicodeChars(final String string) {
        StringBuffer buf = null;
        for (int i = 0; i < string.length(); i++) {
            final char ch = string.charAt(i);
            if (!(ch == 9 || ch == 10 || ch == 13 || ch >= 32)) {
                if (buf == null) {
                    buf = new StringBuffer(string.substring(0, i));
                }
                buf.append("\\u"); //$NON-NLS-1$
                final String hex = Integer.toHexString(ch);
                for (int j = hex.length(); j < 4; j++)
                    buf.append('0');
                buf.append(hex);
            } else if (buf != null) {
                buf.append(ch);
            }
        }
        if (buf != null) {
            return buf.toString();
        }
        return string;
    }

    @Override
    public void setContentHandler(final ContentHandler handler) {
        this.handler = handler;
    }

    @Override
    public ContentHandler getContentHandler() {
        return handler;
    }

    @Override
    public void setErrorHandler(final ErrorHandler handler) {
        errorHandler = handler;
    }

    @Override
    public ErrorHandler getErrorHandler() {
        return errorHandler;
    }

    // ignored:

    @Override
    public void parse(final String systemId) throws IOException, SAXException {
        // No-op
    }

    @Override
    public void setDTDHandler(final DTDHandler handler) {
        // No-op
    }

    @Override
    public DTDHandler getDTDHandler() {
        return null;
    }

    @Override
    public void setEntityResolver(final EntityResolver resolver) {
        // No-op
    }

    @Override
    public EntityResolver getEntityResolver() {
        return null;
    }

    @Override
    public void setProperty(final java.lang.String name, final java.lang.Object value) {
        // No-op
    }

    @Override
    public Object getProperty(final java.lang.String name) {
        return null;
    }

    @Override
    public void setFeature(final java.lang.String name, final boolean value) {
        // No-op
    }

    @Override
    public boolean getFeature(final java.lang.String name) {
        return false;
    }
}