/**************************************************************************
 *  This file is part of QXmlEdit                                         *
 *  Copyright (C) 2011 by Luca Bellonda and individual contributors       *
 *    as indicated in the AUTHORS file                                    *
 *  lbellonda _at_ gmail.com                                              *
 *                                                                        *
 * This library is free software; you can redistribute it and/or          *
 * modify it under the terms of the GNU Library General Public            *
 * License as published by the Free Software Foundation; either           *
 * version 2 of the License, or (at your option) any later version.       *
 *                                                                        *
 * This library 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      *
 * Library General Public License for more details.                       *
 *                                                                        *
 * You should have received a copy of the GNU Library General Public      *
 * License along with this library; if not, write to the                  *
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,       *
 * Boston, MA  02110-1301  USA                                            *
 **************************************************************************/

#include <QtCore/QString>
#include <QtTest/QtTest>
#include <QtCore/QCoreApplication>
#include <QtCore/QMap>

#include "searchinfiles.h"
#include "utils.h"
#include "comparexml.h"
#include "testpaste.h"
#include "testcomment.h"
#include "testsplit.h"
#include "testxsd.h"
#include "testmixedcontent.h"
#include "testbase64.h"
#include "testeditingcommands.h"
#include "testvalidation.h"
#include "testuifile.h"
#include "testsessions.h"
#include "testsqlaccess.h"
#include "testeditelements.h"
#include "testvis.h"
#include "testundoredo.h"
#include "testdoctype.h"
#include "testxsddiff.h"
#include "exportcsvtest.h"
#include "testfilterattributes.h"
#include "testcomparexml.h"
#include "testspringandforces.h"

class TestQXmlEdit : public QObject
{
    Q_OBJECT
public:
    TestQXmlEdit();
    bool verifyMaps(QMap<int, int> &reference, QMap<int, int> &candidate);

private Q_SLOTS:
    void initTestCase();
    void cleanupTestCase();

    void testSpringAndForces();
    void testLoop();
    //

    void testCompareXml();
    void testExportCSV();
    void testXSDDiff12();
    void testXSDDiff2();
    void testXSDDiff3();
    void testXSDDiff4();
    void testXSDDiff5();
    void testXSDDiff6();
    void testXSDDiff7();
    void testXSDDiff8();
    void testXSDDiff9();
    void testXSDDiff10();
    void testXSDDiff11();
    //void testXSDDiff12();

    void testDocType();
    void testBase64();
    void testUndoRedo();
    void testVis();
    void testEditing();
    void testSql();
    void testSessions();
    void testFileUI();
    void testValidation();
    void testSplit();
    void testEditingCommands();
    void test2();
    void test();
    void test1();
    void testComment();
    void testXsd();
    void test_data();
    void testPaste();
    void testMixed();
    void testMixed2();
    void testMixedContent();
    void testFilterAttributes();
};

void testSearchInFileWorking(volatile bool *running, XmlScanInfo *info, const QString &filePath);

TestQXmlEdit::TestQXmlEdit()
{
}

void TestQXmlEdit::initTestCase()
{
    Utils::isUnitTest = true ;
    Utils::silenceMessages1 = true ;
    Utils::silenceMessages2 = true ;
}

void TestQXmlEdit::cleanupTestCase()
{
}

void TestQXmlEdit::test1()
{
    CompareXML  c;
    bool result = c.comparePlainDocuments();
    QVERIFY2(result, QString("compare1").toAscii().data());
}

void TestQXmlEdit::test2()
{
    CompareXML  c;
    bool result = !c.comparePlainDocumentsFalse();
    QVERIFY2(result, QString("compare2").toAscii().data());
}

void TestQXmlEdit::testMixed()
{
    CompareXML  c;
    bool result = c.compareMixedDocuments();
    QVERIFY2(result, QString("compareMixed").toAscii().data());
}

void TestQXmlEdit::testMixed2()
{
    CompareXML  c;
    bool result = !c.compareMixedDocumentsFalse();
    QVERIFY2(result, QString("compareMixed False").toAscii().data());
}

void TestQXmlEdit::test()
{
    XmlScanInfo info;
    if(!info.init("/a/b/c", true)) {
        QVERIFY2(false, "SFC: Unable to begin the search.");
    }
    if(!info.check()) {
        QVERIFY2(false, "SFC: The pattern to search is not well formed.");
        return ;
    }

    bool running = true ;
    QFuture<void> future = QtConcurrent::run(testSearchInFileWorking, &running, &info, QString("../test/data/testcount.xml"));
    future.waitForFinished();
    QVERIFY2(!info.isError, "SFC: error in method.");
    // check the result
    QVERIFY2(info.size == 3, "SFC: Number of rows");
    // devo verificare l'equivalenza degli hash map.
    // Costruisco le mappe corrispondenti al test
    QMap<int, int> expecteds [3];
    expecteds[0][1] = 1;
    expecteds[1][17] = 1;
    expecteds[2][0] = 1;
    expecteds[2][1] = 2;
    expecteds[2][2] = 6;
    expecteds[2][3] = 3;
    expecteds[2][4] = 5;

    for(int i = 0 ; i < info.size ; i ++) {
        //verify Hash Map equivalence
        if(!verifyMaps(info.groups[i], expecteds[i])) {
            QVERIFY2(false, QString("SFC: Map %1 different").arg(i).toAscii().data());
        }
    }
}

bool TestQXmlEdit::verifyMaps(QMap<int, int> &reference, QMap<int, int> &candidate)
{
    if(reference.count() != candidate.count()) {
        return false ;
    }
    foreach(int key1, reference.keys()) {
        if(!candidate.contains(key1)) {
            return false;
        }
        if(reference[key1] != candidate[key1]) {
            return false ;
        }
    }
    return true ;
}

void TestQXmlEdit::testComment()
{
    TestComment tc;
    bool result ;
    result = tc.testMakeComment();
    QVERIFY2(result, "Test Comment: make a comment.");
    result = tc.testUndoComment();
    QVERIFY2(result, "Test Comment: undo a comment.");
    result = tc.testUndoUndoableComment();
    QVERIFY2(!result, "Test Comment: undo an undoable comment.");
}

void TestQXmlEdit::testXsd()
{
    TestXsd tx ;
    bool result ;
    result = tx.TestNonamespace();
    QVERIFY2(result, "Test XSD: TestNonamespace.");
    result = tx.TestNonamespaceFalse();
    QVERIFY2(result, "Test XSD: TestNonamespaceFalse.");
    result = tx.TestOneSchema();
    QVERIFY2(result, "Test XSD: TestOneSchema.");
    result = tx.TestMoreSchema();
    QVERIFY2(result, "Test XSD: TestMoreSchema.");
    result = tx.testAttributes();
    QVERIFY2(result, "Test XSD: testAttributes.");
}

void TestQXmlEdit::testPaste()
{
    TestPaste tp;
    bool result ;
    result = tp.testAPaste();
    QVERIFY2(result, "Test Paste.");
}


void TestQXmlEdit::test_data()
{
    QTest::addColumn<QString>("data");
    QTest::newRow("0") << QString();
}

void TestQXmlEdit::testSplit()
{
    TestSplit ts;
    bool result ;

    result = ts.testParameters();
    QVERIFY2(result, "Test Split: parameters.");
    result = ts.testParametersNoExtract();
    QVERIFY2(result, "Test Split: parameters w/o extraction.");
    result = ts.testSplit();
    QVERIFY2(result, "Test Split: split.");
    result = ts.testSplitAndNavigate();
    QVERIFY2(result, "Test Split: split and navigate.");

    //-------- others
    result = ts.testSplitAndNavigateFilter();
    QVERIFY2(result, "Test Split: filter.");
    result = ts.testSplitAndNavigateFilterMoreComplex();
    QVERIFY2(result, "Test Split: more complex filter.");
    result = ts.testSplitAndNavigateFilterReverse();
    QVERIFY2(result, "Test Split: filter reverserange.");
    result = ts.testSplitAndNavigateFilterMore();
    QVERIFY2(result, "Test Split: filter more.");
    //------------------------
    result = ts.testSplitAndNavigateFilterIdDifferent();
    QVERIFY2(result, "Test Split: filter diff.");
    result = ts.testSplitAndNavigateFilterIdEqual();
    QVERIFY2(result, "Test Split: filter equal.");
    //------
    result = ts.testSplitByDepth();
    QVERIFY2(result, "Test Split: by depth");
}

void TestQXmlEdit::testMixedContent()
{
    TestMixedContent testMixedContent;
    bool result ;
    result = testMixedContent.test_m1();
    QVERIFY2(result, "TestMixedContent: case 1.");
    result = testMixedContent.test_m3();
    QVERIFY2(result, "TestMixedContent: case 3.");
    result = testMixedContent.test_m6();
    QVERIFY2(result, "TestMixedContent: case 6.");
}

void TestQXmlEdit::testBase64()
{
    TestBase64 testBase64;
    bool result ;
    result = testBase64.test_base64();
    QVERIFY2(result, "TestBase64");
    result = testBase64.test_base64_base();
    QVERIFY2(result, "TestBase64 base");
}


void TestQXmlEdit::testEditingCommands()
{
    TestEditingCommands te;
    bool result ;
    result = te.testInnerAppendElement();
    QVERIFY2(result, "Test inner append");
}

void TestQXmlEdit::testValidation()
{
    TestValidation tv;
    bool result ;
    result = tv.test();
    QVERIFY2(result, "Test validation");
}

void TestQXmlEdit::testFileUI()
{
    TestUIFile tf;
    bool result ;
    result = tf.testNew();
    QVERIFY2(result, "Test FileUI");
}

void TestQXmlEdit::testSessions()
{
    TestSessions ts;
    bool result ;
    result = ts.testUI1();
    QVERIFY2(result, "0 Test Sessions testUI1");
    result = ts.testStartSessionDisabled();
    QVERIFY2(result, "-1 testStartSessionDisabled");
    result = ts.testStartWithoutSessions();
    QVERIFY2(result, "1 testStartWithoutSessions");
    result = ts.testStartWithLastSessionIdStateActive();
    QVERIFY2(result, "2 testStartWithLastSessionIdStateActive");
    result = ts.testStartWithLastSessionIdStatePaused();
    QVERIFY2(result, "3 testStartWithLastSessionIdStatePaused");
    result = ts.testStartWithLastSessionIllegalState();
    QVERIFY2(result, "4 testStartWithLastSessionIllegalState");
    result = ts.testCmdPauseCheck();
    QVERIFY2(result, "5 testCmdPauseCheck");
    result = ts.testCmdResume();
    QVERIFY2(result, "6 testCmdResume");
    result = ts.testCmdClose();
    QVERIFY2(result, "7 testCmdClose");
    result = ts.testRegisterAccess();
    QVERIFY2(result, "8 testRegisterAccess");
    result = ts.testSummaryData();
    QVERIFY2(result, QString("9 testSummaryData: %1").arg(ts.errorString()).toLatin1().data());
    result = ts.testAccessFileWithSessionsDisabled();
    QVERIFY2(result, "11 testAccessFileWithSessionsDisabled");
}

void TestQXmlEdit::testSql()
{
    TestSQLAccess tsa;
    bool result ;

    result = tsa.insertSession();
    QVERIFY2(result, "Test insert Sessions");
    result = tsa.testFile();
    QVERIFY2(result, "Test insert File");
    result = tsa.testTransCommands();
    QVERIFY2(result, "Test transactions");
    result = tsa.testFileNotFound();
    QVERIFY2(result, "Test file not found");
    result = tsa.insertFileAccessLow();
    QVERIFY2(result, "Test file access low");
    result = tsa.insertFileAccess();
    QVERIFY2(result, "Test file access");
    result = tsa.readFileAccess();
    QVERIFY2(result, "Test read file access");
    result = tsa.deleteSession();
    QVERIFY2(result, "Test delete session");
    result = tsa.updateSession();
    QVERIFY2(result, "Test update session");
    result = tsa.touchSession();
    QVERIFY2(result, "Test touch session");

    result = tsa.deleteByDate1Month();
    QVERIFY2(result, QString("deleteByDate1Month %1").arg(tsa.msg()).toLatin1().data());
    result = tsa.deleteByDate6Months();
    QVERIFY2(result, QString("deleteByDate6Months %1").arg(tsa.msg()).toLatin1().data());
    result = tsa.deleteByGivenDate();
    QVERIFY2(result, QString("deleteByGivenDate %1").arg(tsa.msg()).toLatin1().data());
    result = tsa.deleteByDateWrongType();
    QVERIFY2(result, QString("deleteByDateWrongType %1").arg(tsa.msg()).toLatin1().data());
    //-----------------
    result = tsa.deleteByDate1MonthFiles();
    QVERIFY2(result, "deleteByDate1MonthFiles");
    result = tsa.deleteByDate6MonthsFiles();
    QVERIFY2(result, "deleteByDate6MonthsFiles");
    result = tsa.deleteByGivenDateFiles();
    QVERIFY2(result, "deleteByGivenDateFiles");
}

void TestQXmlEdit::testEditing()
{
    TestEditElements tee;
    bool result ;

    result = tee.test();
    QVERIFY2(result, "TestEditElements test");
}


void TestQXmlEdit::testVis()
{
    TestVis tv;
    bool result ;

    result = tv.test();
    QVERIFY2(result, "TestVis test");
}

void TestQXmlEdit::testUndoRedo()
{
    bool result ;
    TestUndoRedo tu;
    result = tu.test();
    QVERIFY2(result, (QString("undo-redo %1").arg(tu.cause)).toLatin1());
}

void TestQXmlEdit::testDocType()
{
    bool result ;
    TestDocType testDT;
    result = testDT.test();
    QVERIFY2(result, "document type");
}


void TestQXmlEdit::testXSDDiff2()
{
    bool result ;
    TestXSDDiff testXsdEqual;
    result = testXsdEqual.testEqual();
    QVERIFY2(result, QString("xsd diff: %1").arg(testXsdEqual.errorString()).toLatin1().data());
}

void TestQXmlEdit::testXSDDiff3()
{
    bool result ;
    TestXSDDiff testXsdAdd;
    result = testXsdAdd.testAdd();
    QVERIFY2(result, QString("xsd diff: %1").arg(testXsdAdd.errorString()).toLatin1().data());
}

void TestQXmlEdit::testXSDDiff4()
{
    bool result ;
    TestXSDDiff testXsdDel;
    result = testXsdDel.testDel();
    QVERIFY2(result, QString("xsd diff: %1").arg(testXsdDel.errorString()).toLatin1().data());
}

void TestQXmlEdit::testXSDDiff5()
{
    bool result ;
    TestXSDDiff testXsdMixed;
    result = testXsdMixed.testMixed();
    QVERIFY2(result, QString("xsd diff: %1").arg(testXsdMixed.errorString()).toLatin1().data());
}

//-
void TestQXmlEdit::testXSDDiff6()
{
    bool result ;
    TestXSDDiff testXsdEqualUnordered;
    result = testXsdEqualUnordered.testEqualUnordered();
    QVERIFY2(result, QString("xsd diff: %1").arg(testXsdEqualUnordered.errorString()).toLatin1().data());
}

void TestQXmlEdit::testXSDDiff7()
{
    bool result ;
    TestXSDDiff testXsdAddUnordered;
    result = testXsdAddUnordered.testAddUnordered();
    QVERIFY2(result, QString("xsd diff: %1").arg(testXsdAddUnordered.errorString()).toLatin1().data());
}

void TestQXmlEdit::testXSDDiff8()
{
    bool result ;
    TestXSDDiff testXsdDelUnordered;
    result = testXsdDelUnordered.testDelUnordered();
    QVERIFY2(result, QString("xsd diff: %1").arg(testXsdDelUnordered.errorString()).toLatin1().data());
}

void TestQXmlEdit::testXSDDiff9()
{
    bool result ;
    TestXSDDiff testXsdMixedUnordered;
    result = testXsdMixedUnordered.testMixedUnordered();
    QVERIFY2(result, QString("xsd diff: %1").arg(testXsdMixedUnordered.errorString()).toLatin1().data());
}

void TestQXmlEdit::testXSDDiff10()
{
    bool result ;
    TestXSDDiff test;
    result = test.testCompareBase();
    QVERIFY2(result, QString("xsd diff: %1").arg(test.errorString()).toLatin1().data());
}

void TestQXmlEdit::testXSDDiff11()
{
    bool result ;
    TestXSDDiff test;
    result = test.testDiffOpAttributes();
    QVERIFY2(result, QString("xsd diff: %1").arg(test.errorString()).toLatin1().data());
}

void TestQXmlEdit::testXSDDiff12()
{
    bool result ;
    TestXSDDiff test;
    result = test.testDiffObjects();
    QVERIFY2(result, QString("xsd diff: %1").arg(test.errorString()).toLatin1().data());
}

void TestQXmlEdit::testExportCSV()
{
    bool result ;
    ExportCSVTest test1;
    result = test1.testUnitTest();
    QVERIFY2(result, QString("csv export unit test").toLatin1().data());

    ExportCSVTest test2;
    result = test2.testExportSiblingsAttributes();
    QVERIFY2(result, QString("csv export functional test").toLatin1().data());

}

void TestQXmlEdit::testFilterAttributes()
{
    bool result ;
    TestFilterAttributes test1;
    result = test1.testUnit();
    QVERIFY2(result, QString("filter attributes unit test").toLatin1().data());

    TestFilterAttributes tests;
    result = tests.testStorage();
    QVERIFY2(result, QString("filter attributes storage test").toLatin1().data());

    TestFilterAttributes test2;
    result = test2.testFunctionality();
    QVERIFY2(result, QString("filter attributes functional test").toLatin1().data());

    TestFilterAttributes test3;
    result = test3.testDetailFunctionality();
    QVERIFY2(result, QString("filter attributes detail functional test").toLatin1().data());
}

void TestQXmlEdit::testCompareXml()
{
    bool result ;

    TestCompareXml test1;
    result = test1.testUnit();
    QVERIFY2(result, (QString("test compare xml unit test: '%1'").arg(test1.errorString())).toLatin1().data());

    TestCompareXml test2;
    result = test2.testLoadFile();
    QVERIFY2(result, (QString("test compare xml load file: '%1'").arg(test2.errorString())).toLatin1().data());

    TestCompareXml test3;
    result = test3.testResults();
    QVERIFY2(result, (QString("test compare xml result test: '%1'").arg(test3.errorString())).toLatin1().data());
}


void TestQXmlEdit::testSpringAndForces()
{
    bool result ;

    TestSpringAndForces test1;
    result = test1.testUnitForces();
    QVERIFY2(result, (QString("test testUnitForces: '%1'").arg(test1.errorString())).toLatin1().data());

}

//-
void TestQXmlEdit::testLoop()
{
    for( int i = 0 ; i < 10 ; i ++ ) {
        TestSQLAccess tsa;
        bool result = tsa.deleteByDate1Month();
        QVERIFY2(result, QString("deleteByDate1Month %1").arg(tsa.msg()).toLatin1().data());
        QTest::qSleep(100);
    }
}


QTEST_MAIN(TestQXmlEdit)

#include "tst_qxmledit.moc"
