tsrc/qtestutils/src/testrunner.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Fri, 17 Sep 2010 08:28:43 +0300
changeset 37 e9675fb210bd
permissions -rw-r--r--
Revision: 201035 Kit: 201037

/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: 
*
*/

#include "testrunner.h"
#include <QtTest/QtTest>
#include <QDir>
#include <stdio.h>

const char testCaseElement[] = "TestCase";
const char testFunctionElement[] = "TestFunction";
const char incidentElement[] = "Incident";
const char descriptionElement[] = "Description";
const char nameAttr[] = "name";
const char typeAttr[] = "type";
const char fileAttr[] = "file";
const char lineAttr[] = "line";
const char attrValueFail[] = "fail";


TestRunner::TestRunner(const QString& name, const QString& combinedOutputFileName)
: mTestCount(0),
  mParsingIncidentElement(false),
  mParsingDescriptionElement(false),
  mCurrentTestFailed(false),
  mCurrentTestFailureLine(0),
  mCombinedOutputFileName(combinedOutputFileName)
{
    mTestRunParams.append(name);
    mTestRunParams.append("-xml");
    mTestRunParams.append("-o");
    mHomeDir = QDir::homePath();
    mTestRunParams.append(QString()); // Initial result file name

    if (!mHomeDir.endsWith(QString::fromAscii("/")))
        mHomeDir += QString::fromAscii("/");
}

TestRunner::~TestRunner()
{
}

int TestRunner::runTests(QObject& testObject)
{
    QString className(testObject.metaObject()->className());
    printf("Running tests for %s ... ", className.toUtf8().data());
    QString resultFileName = mHomeDir + className + ".xml";
    mTestRunParams.replace(mTestRunParams.count()-1,resultFileName);
    int errorsBefore = mErrors.count();
    int error = QTest::qExec(&testObject, mTestRunParams);
    parse(resultFileName);
    mResultFiles.append(resultFileName);
    printf("Failures: %d\n",mErrors.count()-errorsBefore);
    fflush(stdout);
    return error;
}

void TestRunner::printResults()
{
    printf("\nTests executed: %d\n",mTestCount);
    if (mErrors.count() > 0) {
        printf("Failures (%d):\n", mErrors.count());
        foreach(QString error, mErrors) {
            printf("\n%s", error.toUtf8().data());
        }
        printf("\n");
    } else {
        printf("All passed.\n\n");
    }
    fflush(stdout);
    
    combineResults();
}

void TestRunner::parse(const QString& fileName)
{
    QFile file(fileName);
    QXmlInputSource inputSource(&file);
    QXmlSimpleReader reader;
    reader.setContentHandler(this);
    reader.parse(inputSource);
}

bool TestRunner::startElement(
    const QString& /*namespaceURI*/, 
    const QString& /*localName*/, 
    const QString& qName, 
    const QXmlAttributes& atts)
{
    if (qName == QString::fromAscii(testFunctionElement)) {
        mTestCount++;
        mCurrentTestName = atts.value(QString::fromAscii(nameAttr));
        return true;
    }
    if (qName == QString::fromAscii(incidentElement)) {
        mParsingIncidentElement = true;
        if (atts.value(QString::fromAscii(typeAttr)) == QString::fromAscii(attrValueFail)) {
            mCurrentTestFailed = true;
            mCurrentTestFile = atts.value(QString::fromAscii(fileAttr));
            mCurrentTestFailureLine = atts.value(QString::fromAscii(lineAttr)).toInt();
        }
        return true;
    }
    mParsingDescriptionElement =
        (qName == QString::fromAscii(descriptionElement));
    return true;
}

bool TestRunner::endElement(
    const QString& /*namespaceURI*/,
    const QString& /*localName*/,
    const QString& qName)
{
    if (qName == QString::fromAscii(incidentElement)) {
        mParsingIncidentElement = false;
        mCurrentTestFailed = false;
        return true;
    }
    if (qName == QString::fromAscii(descriptionElement)) {
        mParsingDescriptionElement = false;
    }    
    return true;
}

bool TestRunner::characters(const QString& ch)
{
    if (mParsingIncidentElement && 
        mParsingDescriptionElement &&
        mCurrentTestFailed) {
        QByteArray testResult = mCurrentTestName.toAscii() + " failed:\n";
        testResult += "File: ";
        testResult += mCurrentTestFile.toAscii();
        testResult += "\n";
        testResult += "Line: ";
        testResult += QByteArray::number(mCurrentTestFailureLine);
        testResult += "\n";
        testResult += "Reason: ";
        testResult += ch.toAscii();
        testResult += "\n";
        mErrors.append(QString::fromAscii(testResult.data()));
    }
    return true;
}

void TestRunner::combineResults()
{
    if ( mCombinedOutputFileName.isEmpty() ){
        return;
    }
    if ( !mCombinedOutputFileName.contains(QString::fromAscii("/")) ){
        mCombinedOutputFileName.prepend( mHomeDir );
    }
    QFile file(mCombinedOutputFileName);
    if (!file.open(QIODevice::WriteOnly)){
        return;
    }

    QXmlStreamWriter writer(&file);
    writer.setAutoFormatting(true);
    writer.writeStartDocument();
    QString caseName;
    foreach ( QString resultFile, mResultFiles ){
        QFile readFile( resultFile );
        if ( resultFile != mCombinedOutputFileName && readFile.open(QIODevice::ReadOnly) ){
            QXmlStreamReader reader(&readFile);
            appendToXml(writer, reader, caseName);
            readFile.close();
        }
    }
    writer.writeEndDocument();
    file.close();
}

void TestRunner::appendToXml(QXmlStreamWriter& writer, QXmlStreamReader& reader, QString& caseName)
{
    while (!reader.atEnd()) {
        QXmlStreamReader::TokenType type = reader.readNext();
        if ( type == QXmlStreamReader::StartDocument  || 
             type == QXmlStreamReader::EndDocument ){
            // Ignored
        } else if ( reader.name() == testCaseElement ){
            if ( type == QXmlStreamReader::StartElement ){
                QString tempCaseName = reader.attributes().value(nameAttr).toString();
                if ( caseName.isEmpty() && type == QXmlStreamReader::StartElement){
                    writer.writeStartElement(testCaseElement);
                    writer.writeAttribute(nameAttr, mTestRunParams.at(0));
                }
                caseName = tempCaseName;
            }  
        } else if ( type == QXmlStreamReader::StartElement ) {
            if ( reader.name() == testFunctionElement ){
                QString tempFuncName = reader.attributes().value(nameAttr).toString();
                if ( !tempFuncName.isEmpty() ){
                    writer.writeStartElement(testFunctionElement);
                    writer.writeAttribute(nameAttr, caseName + "::" + tempFuncName);
                }
            } else {
                writer.writeCurrentToken( reader );
            }
        } else {
            writer.writeCurrentToken( reader );
        }
    }
}