/*
 *  Created on: Dec 16, 2016
 *      Author: pgess
 */

#include "pass/versionspass.h"
#include "passmanager.h"

#include "gtest/gtest.h"

using namespace xreate;

TEST(Effects, syntax_versions_1){
    PassManager* man = PassManager::prepareForCode(R"Code(
            test= function(a:: num):: num; entry {
                x= b[8].
                b = 5:: num.
                x{1} = a:: num.

                x{1} + a
            }
    )Code");
}

TEST(Effects, analysis_versions_1){
    PassManager* man = PassManager::prepareForCode(
    R"Code(
            test= function:: num; entry {
                x{0}= 3:: int.
                x{1} = x{0} + 1.

                x{1}
            }
    )Code");

    VersionsPass* pass = new VersionsPass(man);
    pass->run();

    VersionsGraph graph = pass->getResultGraph();
    ASSERT_TRUE(graph.validate());
}

TEST(Effects, analysis_versions_2){
    PassManager* man = PassManager::prepareForCode(
    R"Code(
            test= function(a:: num):: num; entry {
                x{0}= 3:: int.
                b = [1, 2, x{0}].
                x{1} = b[2].

                x{1} + a
            }
    )Code");

    VersionsPass* pass = new VersionsPass(man);
    pass->run();

    VersionsGraph graph = pass->getResultGraph();
    ASSERT_TRUE(graph.validate());
}

TEST(Effects, analysis_versions_2_1_fail){
    PassManager* man = PassManager::prepareForCode(
    R"Code(
            test= function(a:: num):: num; entry {
                x{0}= 5:: int.
                b = x{0}.
                x{1} = 2.

                b + x{1}
            }
    )Code");

    VersionsPass* pass = new VersionsPass(man);
    pass->run();

    VersionsGraph graph = pass->getResultGraph();
    graph.__debug_print(std::cout);
    ASSERT_FALSE(graph.validate());
}

TEST(Effects, analysis_versions_2_2){
    PassManager* man = PassManager::prepareForCode(
    R"Code(
            test= function(a:: num):: num; entry {
                x{0}= 5:: int.
                b = intrinsic copy(x{0}).
                x{1} = 2.

                b + x{1}
            }
    )Code");

    VersionsPass* pass = new VersionsPass(man);
    pass->run();

    VersionsGraph graph = pass->getResultGraph();
    graph.__debug_print(std::cout);
    ASSERT_TRUE(graph.validate());
}

TEST(Effects, analysis_versions_3){
    PassManager* man = PassManager::prepareForCode(
    R"Code(
            test= function:: num; entry {
                x{0}= 3:: int.
                a = x{0}:: int.
                b = a :: int.
                x{1} = b.

                x{1}
            }
    )Code");

    VersionsPass* pass = new VersionsPass(man);
    pass->run();

    VersionsGraph graph = pass->getResultGraph();
    graph.__debug_print(std::cout);
    ASSERT_TRUE(graph.validate());
    std::cout << "========================\n";
    graph.__debug_print(std::cout);
    AttachmentsContainerDefault<std::list<Symbol>>* attachmentsDependency = graph.representAsAttachments();

    CodeScope* scope = man->root->findFunction("test")->getEntryScope();
    const std::list<Symbol>& dependenciesX1  = attachmentsDependency->get(Symbol{ScopedSymbol{1, 1}, scope});
    ASSERT_EQ(3, dependenciesX1.size());
}

TEST(Effects, compilation_versions_1){
    PassManager* man = PassManager::prepareForCode(
    R"Code(
    test= function:: num; entry {
        x{1} = b.
        b = a :: int.
        a = x{0}:: int.
        x{0}= 3:: int.

        x{1}
    }
    )Code");

    man->runWithoutCompilation();
    if (!man->isPassRegistered(PassId::VersionsPass)){
            VersionsPass* pass = new VersionsPass(man);
            pass->run();
            pass->finish();
    }

    int (*body)() = (int (*)())man->run();
    int answer = body();

    ASSERT_EQ(3, answer);
}

TEST(Effects, compilation_versions_versionInit1){
    PassManager* man = PassManager::prepareForCode(
    R"Code(
    test= function:: num; entry {
        x{0} = 3.

        x{0}
    }
    )Code");

    man->runWithoutCompilation();
    if (!man->isPassRegistered(PassId::VersionsPass)){
            VersionsPass* pass = new VersionsPass(man);
            pass->run();
            pass->finish();
    }

    int (*body)() = (int (*)())man->run();
    int answer = body();

    ASSERT_EQ(3, answer);
}

TEST(Effects, compilation_versions_versionNext1){
    PassManager* man = PassManager::prepareForCode(
    R"Code(
    test= function:: num; entry {
        x{0} = 5.
        x{1} = x{0} - 2.

        x{1}
    }
    )Code");

    man->runWithoutCompilation();
    if (!man->isPassRegistered(PassId::VersionsPass)){
            VersionsPass* pass = new VersionsPass(man);
            pass->run();
            pass->finish();
    }

    int (*body)() = (int (*)())man->run();
    int answer = body();

    ASSERT_EQ(3, answer);
}

TEST(Effects, compilation_versions_IntrinsicCopy1){
    PassManager* man = PassManager::prepareForCode(
    R"Code(
    test= function:: num; entry {
        x{0} = 5.
        b = intrinsic copy (x{0}).
        x{1} = 2.

        b - x{1}
    }
    )Code");

    man->runWithoutCompilation();
    if (!man->isPassRegistered(PassId::VersionsPass)){
            VersionsPass* pass = new VersionsPass(man);
            pass->run();
            pass->finish();
    }

    int (*body)() = (int (*)())man->run();
    int answer = body();

    ASSERT_EQ(3, answer);
}

TEST(Effects, compilation_versions_varexchange){
    PassManager* man = PassManager::prepareForCode(
    R"Code(
    test= function:: num; entry {
            a{0} = 3.
            b{0} = 5.
            tmp = intrinsic copy (a{0}).
            a{1} = b{0}.
            b{1} = tmp.

            b{1}
    }
    )Code");

    man->runWithoutCompilation();
    if (!man->isPassRegistered(PassId::VersionsPass)){
            VersionsPass* pass = new VersionsPass(man);
            pass->run();
            pass->finish();
    }

    int (*body)() = (int (*)())man->run();
    int answer = body();

    ASSERT_EQ(3, answer);
}





/*
TEST(Effects, analysis_versions_copy){

}

TEST(Effects, syntax_references1){

}

TEST(Effects, syntax_scope_versions1){

}

TEST(Effects, DynamicVersions_analysis){

}
 */

