/***************************************************************************
 *   Copyright (C) 2008 by S. MANKOWSKI / G. DE BURE support@mankowski.fr  *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program 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         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>  *
 ***************************************************************************/
#ifndef SKGTESTMACRO_H
#define SKGTESTMACRO_H
/** @file
 * This file contains macro for unit tests.
 *
 * @author Stephane MANKOWSKI / Guillaume DE BURE
 */
#include <qfile.h>
#include <qdir.h>
#include <qcoreapplication.h>

#include "skgtransactionmng.h"
#include "skgerror.h"
#include "skgtraces.h"
#include "skgservices.h"
#include "skgdocument.h"
#include "skgnodeobject.h"
#include "skgpropertyobject.h"

class SKGTest
{
public:
    /**
    * Return the test directory
    * @param iPath can be IN or OUT or REF
    * @return the test directory
    */
    static QString getTestPath(const QString& iPath)
    {
        QString pPath = SKGServices::getEnvVariable(iPath);
        if (pPath.isEmpty()) {
            return QStringLiteral("./tests/") % (iPath == QStringLiteral("IN") ? "input" : (iPath == QStringLiteral("OUT") ? "output" : "ref"));
        }
        return pPath;
    }
};

/**
 * @def SKGINITTEST(SHOWERRONLY)
 * Initialise the test
 */
#ifndef Q_OS_WIN
#define SKGINITTEST(SHOWERRONLY) \
    QCoreApplication app(argc, argv); \
    app.setApplicationName(QStringLiteral("qttest") ); \
    SKGTRACESEPARATOR; \
    SKGTRACE << "STARTING TEST" << endl << flush; \
    SKGTRACE << "homePath=" << QDir::homePath() << endl << flush; \
    SKGTRACESEPARATOR; \
    bool showonlyfailures = SHOWERRONLY; \
    if (showonlyfailures) {SKGTRACE << "Only failures will be displayed" << endl;}\
    int nberror = 0;  \
    int nbcheck = 0;
#else
#define SKGINITTEST(SHOWERRONLY) \
    QCoreApplication app(argc, argv); \
    app.setApplicationName(QStringLiteral("qttest")); \
    SKGTRACESEPARATOR; \
    SKGTRACE << "STARTING TEST" << endl << flush; \
    SKGTRACE << "homePath=" << QDir::homePath() << endl << flush; \
    SKGTRACESEPARATOR; \
    bool showonlyfailures = SHOWERRONLY; \
    if (showonlyfailures) {SKGTRACE << "Only failures will be displayed" << endl;}\
    int nberror = 0;  \
    int nbcheck = 0;
#endif

/*

*/
/**
 * @def SKGENDTEST()
 * Exit test
 */
#define SKGENDTEST()\
    if (nbcheck > 0) \
    { \
        SKGTRACE << nberror << " errors / " << nbcheck << " checks =" << (100.0*(static_cast<double>(nberror)) / (static_cast<double>(nbcheck))) << "%" << endl;\
    } \
    SKGTraces::dumpProfilingStatistics();\
    return nberror;

/**
 * @def SKGRETURNTEST()
 * Return test
 */
#define SKGRETURNTEST()\
    if (nbcheck > 0) \
    { \
        SKGTRACE << nberror << " errors / " << nbcheck << " checks =" << (100.0*(static_cast<double>(nberror)) / (static_cast<double>(nbcheck))) << "%" << endl;\
    } \
    return nberror;

/**
 * @def SKGTEST(MESSAGE, RESULT, EXPECTEDRESULT)
 * To check the return of a method
 * Example of usage:
 * @code
 * SKGTEST(QStringLiteral("ERR:getHistoricalSize"), err.getHistoricalSize(), 0);
 * @endcode
 */
#define SKGTEST(MESSAGE, RESULT, EXPECTEDRESULT) \
    if ((RESULT) == (EXPECTEDRESULT))\
    {\
        if (!showonlyfailures) {SKGTRACE << "Test [" << (MESSAGE) << "] : OK" << endl;}\
    }\
    else\
    {\
        SKGTRACE << "!!! Test [" << (MESSAGE) << "] : KO in line " << __LINE__ << endl;\
        SKGTRACE << "     Expected: [" << (EXPECTEDRESULT) << ']' << endl;\
        SKGTRACE << "     Result  : [" << (RESULT) << ']' << endl;\
        ++nberror;\
    }\
    ++nbcheck;
/**
 * @def SKGTESTBOOL(MESSAGE, RESULT, EXPECTEDRESULT)
* To check the return of a method returning a boll
* Example of usage:
* @code
* SKGTESTBOOL("isWarning", err.isWarning(), true);
* @endcode
*/
#define SKGTESTBOOL(MESSAGE, RESULT, EXPECTEDRESULT) \
    if ((RESULT) == (EXPECTEDRESULT))\
    {\
        if (!showonlyfailures) {SKGTRACE << "Test [" << (MESSAGE) << "] : OK" << endl;}\
    }\
    else\
    {\
        SKGTRACE << "!!! Test [" << (MESSAGE) << "] : KO in line " << __LINE__ << endl;\
        SKGTRACE << "     Expected: [" << ((EXPECTEDRESULT) ? "TRUE" : "FALSE") << ']' << endl;\
        SKGTRACE << "     Result  : [" << ((RESULT) ? "TRUE" : "FALSE") << ']' << endl;\
        ++nberror;\
    }\
    ++nbcheck;

/**
 * @def SKGTESTERROR(MESSAGE, RESULT, EXPECTEDRESULT)
 * To check the return of a method
 * Example of usage:
 * @code
 * SKGTESTERROR(QStringLiteral("DOC:setParameter"), document1.setParameter(QStringLiteral("ATT1"), QStringLiteral("VAL1")), true);
 * @endcode
 */
#define SKGTESTERROR(MESSAGE, RESULT, EXPECTEDRESULT) \
    { \
        SKGError _err_ = RESULT; \
        if (!_err_ == (EXPECTEDRESULT)) { \
            if (!showonlyfailures) { \
                SKGTRACE << "Test [" << (MESSAGE) << "] : OK" << endl; \
                if (!(EXPECTEDRESULT)) { \
                    SKGTRACE << "     Error Message  :\n" << _err_.getFullMessageWithHistorical()  << endl; \
                }     \
            }\
        } else {\
            SKGTRACE << "!!! Test [" << (MESSAGE) << "] : KO in line " << __LINE__ << endl;\
            SKGTRACE << "     Expected: [" << ((EXPECTEDRESULT) ? "TRUE" : "FALSE") << ']' << endl;\
            SKGTRACE << "     Result  : [" << (!_err_ ? "TRUE" : "FALSE") << ']' << endl;\
            SKGTRACE << "     Error Message  :\n" << _err_.getFullMessageWithHistorical()  << endl;\
            ++nberror;\
        }\
        ++nbcheck;\
    }

/**
 * @def SKGTESTACCOUNT(DOC, ACCOUNT, AMOUNT)
 * To check the account amount
 * Example of usage:
 * @code
 * SKGTESTACCOUNT(document1, QStringLiteral("act1"), 12345);
 * @endcode
 */
#define SKGTESTACCOUNT(DOC, ACCOUNT, AMOUNT) \
    { \
        SKGAccountObject account(&(DOC)); \
        SKGTESTERROR(QStringLiteral(ACCOUNT) % ".setName(QStringLiteral(" % (ACCOUNT) % "))", account.setName(QStringLiteral(ACCOUNT)), true); \
        SKGTESTERROR(QStringLiteral(ACCOUNT) % ".load(QStringLiteral(" % QStringLiteral(ACCOUNT) % "))", account.load(), true); \
        SKGTEST(QStringLiteral(ACCOUNT) % ".getCurrentAmount(" % QStringLiteral(ACCOUNT) % ")", SKGServices::doubleToString(account.getCurrentAmount()), SKGServices::doubleToString(AMOUNT));\
    }

#endif
