/***************************************************************************
 * SPDX-FileCopyrightText: 2024 S. MANKOWSKI stephane@mankowski.fr
 * SPDX-FileCopyrightText: 2024 G. DE BURE support@mankowski.fr
 * SPDX-License-Identifier: GPL-3.0-or-later
 ***************************************************************************/
/** @file
 * This file is a test script.
 *
 * @author Stephane MANKOWSKI / Guillaume DE BURE
 */
#include "skgtestmacro.h"
#include "skgbankincludes.h"

/**
 * The main function of the unit test
 * @param argc the number of arguments
 * @param argv the list of arguments
 */
int main(int argc, char** argv)
{
    Q_UNUSED(argc)
    Q_UNUSED(argv)

    // Init test
    SKGINITTEST(true)

    {
        // Test category
        SKGDocumentBank document1;
        SKGTESTERROR(QLatin1String("document1.initialize()"), document1.initialize(), true)
        SKGError err;
        SKGCategoryObject parent2;
        {
            // Scope of the transaction
            SKGBEGINTRANSACTION(document1, QLatin1String("CAT_T1"), err)

            // Create category 0
            SKGCategoryObject cat0(&document1);
            SKGTESTERROR(QLatin1String("CAT:setName+invalid name"), cat0.setName(QLatin1Char('a') % OBJECTSEPARATOR % QLatin1Char('b')), false)
            SKGTESTBOOL("CAT:exist", cat0.exist(), false)
            SKGTESTERROR(QLatin1String("CAT:save"), cat0.save(), false)

            // Create category 1
            SKGCategoryObject cat1(&document1);

            SKGCategoryObject cat1_1;
            SKGTESTERROR(QLatin1String("CAT:addCategory"), cat1.addCategory(cat1_1), false)
            SKGTESTERROR(QLatin1String("CAT:setParentCategory"), cat1.setParentCategory(cat1_1), false)

            SKGTESTERROR(QLatin1String("CAT:setName"), cat1.setName(QLatin1String("root1")), true)
            SKGTESTBOOL("CAT:getFullName", cat1.isBookmarked(), false)
            SKGTESTERROR(QLatin1String("CAT:bookmark"), cat1.bookmark(true), true)
            SKGTESTBOOL("CAT:getFullName", cat1.isBookmarked(), true)
            SKGTESTERROR(QLatin1String("CAT:save"), cat1.save(), true)
            SKGTEST(QLatin1String("CAT:getFullName"), cat1.getFullName(), QLatin1String("root1"))
            SKGTESTERROR(QLatin1String("CAT:load"), cat1.load(), true)
            SKGTEST(QLatin1String("CAT:getFullName"), cat1.getFullName(), QLatin1String("root1"))

            SKGTESTBOOL("REF:isClosed", cat1.isClosed(), false)
            SKGTESTERROR(QLatin1String("REF:setClosed"), cat1.setClosed(true), true)
            SKGTESTBOOL("REF:isClosed", cat1.isClosed(), true)

            SKGObjectBase obj1 = static_cast<SKGObjectBase>(cat1);
            SKGCategoryObject cat11(obj1);

            // Update with bad name
            SKGTESTERROR(QLatin1String("CAT:setName"), cat1.setName("root1" % OBJECTSEPARATOR % QLatin1Char('A')), false)
            SKGTESTERROR(QLatin1String("CAT:load"), cat1.load(), true)
            SKGTEST(QLatin1String("CAT:getFullName"), cat1.getFullName(), QLatin1String("root1"))

            // Create category 1.1
            SKGTESTERROR(QLatin1String("CAT:addCategory"), cat1.addCategory(cat1_1), true)
            SKGTESTERROR(QLatin1String("CAT:setName"), cat1_1.setName(QLatin1String("cat1")), true)
            SKGTESTERROR(QLatin1String("CAT:save"), cat1_1.save(), true)
            SKGTEST(QLatin1String("CAT:getFullName"), cat1_1.getFullName(), "root1" % OBJECTSEPARATOR % "cat1")

            // Update cat1_1
            SKGTESTERROR(QLatin1String("CAT:setName"), cat1_1.setName(QLatin1String("CAT1")), true)
            SKGTESTERROR(QLatin1String("CAT:save"), cat1_1.save(), true)
            SKGTEST(QLatin1String("CAT:getFullName"), cat1_1.getFullName(), "root1" % OBJECTSEPARATOR % "CAT1")

            // Update cat1
            SKGTESTERROR(QLatin1String("CAT:setName"), cat1.setName(QLatin1String("ROOT1")), true)
            SKGTESTERROR(QLatin1String("CAT:save"), cat1.save(), true)
            SKGTEST(QLatin1String("CAT:getFullName"), cat1.getFullName(), QLatin1String("ROOT1"))

            SKGTESTERROR(QLatin1String("CAT:load"), cat1_1.load(), true)
            SKGTEST(QLatin1String("CAT:getFullName"), cat1_1.getFullName(), "ROOT1" % OBJECTSEPARATOR % "CAT1")

            // Create category 1.2
            SKGCategoryObject cat1_2;
            SKGTESTERROR(QLatin1String("CAT:addCategory"), cat1.addCategory(cat1_2), true)
            SKGTESTERROR(QLatin1String("CAT:setName"), cat1_2.setName(QLatin1String("CAT2")), true)
            SKGTESTERROR(QLatin1String("CAT:save"), cat1_2.save(), true)
            SKGTEST(QLatin1String("CAT:getFullName"), cat1_2.getFullName(), "ROOT1" % OBJECTSEPARATOR % "CAT2")

            // Create category end
            SKGCategoryObject end1;
            SKGTESTERROR(QLatin1String("CAT:addCategory"), cat1_1.addCategory(end1), true)
            SKGTESTERROR(QLatin1String("CAT:setName"), end1.setName(QLatin1String("END")), true)
            SKGTESTERROR(QLatin1String("CAT:save"), end1.save(), true)
            SKGTEST(QLatin1String("CAT:getFullName"), end1.getFullName(), "ROOT1" % OBJECTSEPARATOR % "CAT1" % OBJECTSEPARATOR % "END")

            // Create category end
            SKGCategoryObject end2;
            SKGTESTERROR(QLatin1String("CAT:addCategory"), cat1_2.addCategory(end2), true)
            SKGTESTERROR(QLatin1String("CAT:setName"), end2.setName(QLatin1String("END")), true)
            SKGTESTERROR(QLatin1String("CAT:save"), end2.save(), true)
            SKGTEST(QLatin1String("CAT:getFullName"), end2.getFullName(), "ROOT1" % OBJECTSEPARATOR % "CAT2" % OBJECTSEPARATOR % "END")

            SKGCategoryObject end2_1;
            SKGTESTERROR(QLatin1String("CAT:addCategory"), end2.addCategory(end2_1), true)
            SKGTESTERROR(QLatin1String("CAT:setName"), end2_1.setName(QLatin1String("REALEND")), true)
            SKGTESTERROR(QLatin1String("CAT:save"), end2_1.save(), true)
            SKGTEST(QLatin1String("CAT:getFullName"), end2_1.getFullName(), "ROOT1" % OBJECTSEPARATOR % "CAT2" % OBJECTSEPARATOR % "END" % OBJECTSEPARATOR % "REALEND")

            // Get parent
            SKGCategoryObject parent1;
            SKGTESTERROR(QLatin1String("CAT:getParentCategory"), end2.getParentCategory(parent1), true)
            SKGTEST(QLatin1String("CAT:getFullName"), parent1.getFullName(), "ROOT1" % OBJECTSEPARATOR % "CAT2")

            // Get parent
            SKGTESTERROR(QLatin1String("CAT:getParentCategory"), parent1.getParentCategory(parent2), true)
            SKGTEST(QLatin1String("CAT:getFullName"), parent2.getFullName(), QLatin1String("ROOT1"))

            SKGCategoryObject root;
            SKGTESTERROR(QLatin1String("CAT:getRootCategory"), end2_1.getRootCategory(root), true)
            SKGTEST(QLatin1String("CAT:getFullName"), root.getFullName(), QLatin1String("ROOT1"))

            // Get children
            SKGObjectBase::SKGListSKGObjectBase CategoryList;
            SKGTESTERROR(QLatin1String("CAT:getCategories"), parent2.getCategories(CategoryList), true)
            SKGTEST(QLatin1String("CAT:nb categories"), CategoryList.size(), 2)

            // Simple delete
            SKGTESTERROR(QLatin1String("CAT:delete"), end1.remove(), true)
            QStringList oResult;
            SKGTESTERROR(QLatin1String("CAT:getDistinctValues"), document1.getDistinctValues(QLatin1String("category"), QLatin1String("id"), oResult), true)
            SKGTEST(QLatin1String("CAT:oResult.size"), oResult.size(), 5)
        }
        {
            // Scope of the transaction
            SKGBEGINTRANSACTION(document1, QLatin1String("CAT_T2"), err)

            // Cascading delete
            SKGTESTERROR(QLatin1String("CAT:delete"), parent2.remove(), true)
            QStringList oResult;
            SKGTESTERROR(QLatin1String("CAT:getDistinctValues"), document1.getDistinctValues(QLatin1String("category"), QLatin1String("id"), oResult), true)
            SKGTEST(QLatin1String("CAT:oResult.size"), oResult.size(), 0)
        }

        // Undo
        SKGTESTERROR(QLatin1String("CAT:undoRedoTransaction"), document1.undoRedoTransaction(), true)
        QStringList oResult;
        SKGTESTERROR(QLatin1String("CAT:getDistinctValues"), document1.getDistinctValues(QLatin1String("category"), QLatin1String("id"), oResult), true)
        SKGTEST(QLatin1String("CAT:oResult.size"), oResult.size(), 5)

        SKGTESTERROR(QLatin1String("CAT:undoRedoTransaction"), document1.undoRedoTransaction(), true)
        SKGTESTERROR(QLatin1String("CAT:getDistinctValues"), document1.getDistinctValues(QLatin1String("category"), QLatin1String("id"), oResult), true)
        SKGTEST(QLatin1String("CAT:oResult.size"), oResult.size(), 0)

        // Redo
        SKGTESTERROR(QLatin1String("CAT:undoRedoTransaction(SKGDocument::REDO)"), document1.undoRedoTransaction(SKGDocument::REDO), true)
        SKGTESTERROR(QLatin1String("CAT:getDistinctValues"), document1.getDistinctValues(QLatin1String("category"), QLatin1String("id"), oResult), true)
        SKGTEST(QLatin1String("CAT:oResult.size"), oResult.size(), 5)

        SKGTESTERROR(QLatin1String("CAT:undoRedoTransaction(SKGDocument::REDO)"), document1.undoRedoTransaction(SKGDocument::REDO), true)
        SKGTESTERROR(QLatin1String("CAT:getDistinctValues"), document1.getDistinctValues(QLatin1String("category"), QLatin1String("id"), oResult), true)
        SKGTEST(QLatin1String("CAT:oResult.size"), oResult.size(), 0)
    }

    {
        SKGDocumentBank document1;
        SKGTESTERROR(QLatin1String("document1.initialize()"), document1.initialize(), true)
        SKGError err;
        {
            // Scope of the transaction
            SKGBEGINTRANSACTION(document1, QLatin1String("CAT_T1"), err)

            SKGCategoryObject cat;
            SKGTESTERROR(QLatin1String("CAT:createPathCategory"), SKGCategoryObject::createPathCategory(&document1, QLatin1String(""), cat), true)
            SKGTESTERROR(QLatin1String("CAT:createPathCategory"), SKGCategoryObject::createPathCategory(&document1, QLatin1Char('A') % OBJECTSEPARATOR % QLatin1Char('A'), cat, true), true)
            SKGTEST(QLatin1String("CAT:getName"), cat.getName(), QLatin1String("A"))

            QStringList oResult;
            SKGTESTERROR(QLatin1String("CAT:getDistinctValues"), document1.getDistinctValues(QLatin1String("category"), QLatin1String("id"), oResult), true)
            SKGTEST(QLatin1String("CAT:oResult.size"), oResult.size(), 2)

            SKGTESTERROR(QLatin1String("CAT:createPathCategory"), SKGCategoryObject::createPathCategory(&document1, QLatin1Char('A') % OBJECTSEPARATOR % QLatin1Char('B'), cat, true, true), true)
            SKGTEST(QLatin1String("CAT:getName"), cat.getName(), QLatin1String("B"))
            SKGTESTERROR(QLatin1String("CAT:createPathCategory"), SKGCategoryObject::createPathCategory(&document1, QLatin1Char('A') % OBJECTSEPARATOR % QLatin1Char('B'), cat, true, true), true)
            SKGTEST(QLatin1String("CAT:getName"), cat.getName(), QLatin1String("B (2)"))

            SKGTESTERROR(QLatin1String("CAT:createPathCategory"), SKGCategoryObject::createPathCategory(&document1, QLatin1String("C"), cat, true, true), true)
            SKGTEST(QLatin1String("CAT:getName"), cat.getName(), QLatin1String("C"))
            SKGTESTERROR(QLatin1String("CAT:createPathCategory"), SKGCategoryObject::createPathCategory(&document1, QLatin1String("C"), cat, true, true), true)
            SKGTEST(QLatin1String("CAT:getName"), cat.getName(), QLatin1String("C (2)"))
        }
    }

    {
        SKGDocumentBank document1;
        SKGTESTERROR(QLatin1String("document1.initialize()"), document1.initialize(), true)
        SKGError err;
        {
            // Scope of the transaction
            SKGBEGINTRANSACTION(document1, QLatin1String("NODE_T1"), err)

            SKGCategoryObject categoryB;
            SKGTESTERROR(QLatin1String("NOD:createPathCategory"), SKGCategoryObject::createPathCategory(&document1, QLatin1Char('A') % OBJECTSEPARATOR % QLatin1Char('B'), categoryB), true)
            SKGCategoryObject categoryC;
            SKGTESTERROR(QLatin1String("NOD:createPathCategory"), SKGCategoryObject::createPathCategory(&document1, QLatin1String("C"), categoryC), true)
            SKGCategoryObject categoryA;
            SKGTESTERROR(QLatin1String("NOD:getParentCategory"), categoryB.getParentCategory(categoryA), true)

            SKGTESTERROR(QLatin1String("NOD:setParentCategory"), categoryA.setParentCategory(categoryB), false)
            SKGTESTERROR(QLatin1String("NOD:setParentCategory"), categoryA.setParentCategory(categoryA), false)
            SKGTESTERROR(QLatin1String("NOD:setParentCategory"), categoryB.setParentCategory(categoryB), false)
            SKGTESTERROR(QLatin1String("NOD:setParentCategory"), categoryC.setParentCategory(categoryB), true)
            SKGTESTERROR(QLatin1String("NOD:removeParentCategory"), categoryB.removeParentCategory(), true)
        }
    }

    // Bug 245254
    {
        SKGDocumentBank document1;
        SKGTESTERROR(QLatin1String("document1.initialize()"), document1.initialize(), true)
        SKGError err;
        {
            // Scope of the transaction
            SKGBEGINTRANSACTION(document1, QLatin1String("NODE_T1"), err)

            SKGCategoryObject categoryB;
            SKGTESTERROR(QLatin1String("NOD:createPathCategory"), SKGCategoryObject::createPathCategory(&document1, QLatin1Char('A') % OBJECTSEPARATOR % QLatin1Char('B'), categoryB), true)
            SKGCategoryObject categoryC;
            SKGTESTERROR(QLatin1String("NOD:createPathCategory"), SKGCategoryObject::createPathCategory(&document1, QLatin1String("C"), categoryC), true)
            SKGCategoryObject categoryA;
            SKGTESTERROR(QLatin1String("NOD:createPathCategory"), SKGCategoryObject::createPathCategory(&document1, QLatin1Char('C') % OBJECTSEPARATOR % QLatin1Char('A'), categoryA), true)

            QStringList oResult;
            SKGTESTERROR(QLatin1String("CAT:getDistinctValues"), document1.getDistinctValues(QLatin1String("category"), QLatin1String("id"), oResult), true)
            SKGTEST(QLatin1String("CAT:oResult.size"), oResult.size(), 4)

            // Merge
            SKGTESTERROR(QLatin1String("CAT:merge"), categoryB.merge(categoryA), true)
        }
    }

    // Cascading delete
    {
        SKGDocumentBank document1;
        SKGTESTERROR(QLatin1String("document1.initialize()"), document1.initialize(), true)
        SKGError err;
        {
            // Scope of the transaction
            SKGBEGINTRANSACTION(document1, QLatin1String("NODE_T1"), err)

            SKGCategoryObject categoryA;
            SKGTESTERROR(QLatin1String("NOD:createPathCategory"), SKGCategoryObject::createPathCategory(&document1, QLatin1String("A"), categoryA), true)
            SKGCategoryObject categoryC;
            SKGTESTERROR(QLatin1String("NOD:createPathCategory"), SKGCategoryObject::createPathCategory(&document1, QLatin1Char('A') % OBJECTSEPARATOR % QLatin1Char('B') % OBJECTSEPARATOR % QLatin1Char('C'), categoryC), true)

            QStringList oResult;
            SKGTESTERROR(QLatin1String("CAT:getDistinctValues"), document1.getDistinctValues(QLatin1String("category"), QLatin1String("id"), oResult), true)
            SKGTEST(QLatin1String("CAT:oResult.size"), oResult.size(), 3)

            // Delete
            SKGTESTERROR(QLatin1String("CAT:remove"), categoryA.remove(), true)

            SKGTESTERROR(QLatin1String("CAT:getDistinctValues"), document1.getDistinctValues(QLatin1String("category"), QLatin1String("id"), oResult), true)
            SKGTEST(QLatin1String("CAT:oResult.size"), oResult.size(), 0)
        }
    }
    // End test
    SKGENDTEST()
}
