/* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/
 *
 * testsCFG.cpp
 *
 *  Created on: Jul 17, 2015
 *      Author: pgess <v.melnychenko@xreate.org>
 */

#include "xreatemanager.h"
#include "pass/dfapass.h"
#include "pass/cfapass.h"

#include "analysis/DominatorsTreeAnalysisProvider.h"

#include "gtest/gtest.h"

#include <boost/scoped_ptr.hpp>
#include <boost/smart_ptr/scoped_array.hpp>

using namespace xreate;
using namespace xreate::cfa;
using namespace std;

TEST(CFA, testFunctionAnnotationsClasp){
    string&& program =
        "f2 = function::int; annotationF2 {\n"
        "    0\n"
        "}\n"
        "\n"
        "f1 = function:: int; entry; annotationF1 {\n"
        "    f2() + 10\n"
        "}";


    details::tier1::XreateManager* man = details::tier1::XreateManager::prepare(move(program));
    man->analyse();

    ClaspLayer::ModelFragment answer = man->clasp->query("annotationF1");
    int countNoneValue = 0;
    if (answer) countNoneValue = std::distance(answer->first, answer->second);
    EXPECT_EQ(1, countNoneValue);

    answer = man->clasp->query("annotationF2");
    countNoneValue = 0;
    if (answer) countNoneValue = std::distance(answer->first, answer->second);

    EXPECT_EQ(1, countNoneValue);
}

TEST(CFA, testLoopContextExists){
    details::tier1::XreateManager* man = details::tier1::XreateManager::prepare (
        "interface(cfa){\n"
        "    operator fold:: annotation1.\n"
        "}\n"
        "\n"
        "main = function:: int; entry {\n"
        "    x = [1..10]:: [int].\n"
        "    sum = loop fold (x->el:: int, 0->sum):: int {\n"
        "        el + sum + f1()\n"
        "    }.  \n"
        "    sum\n"
        "}"
        "case context:: annotation1 {"
        " f1 = function::int {\n"
        "  	x = 0:: int.		 "
        "       x\n"
        " }"
        "}"
    );

    man->analyse();
    ClaspLayer::ModelFragment model = man->clasp->query("annotation1");
    ScopePacked scopeIdActual = std::get<0>(ClaspLayer::parse<ScopePacked>(model->first->second));

    CodeScope* scopeEntry = man->root->findFunction("main")->getEntryScope();
    const Expression& exprSum = scopeEntry->getDefinition(scopeEntry->getSymbol("sum"));
    CodeScope* scopeExpected = exprSum.blocks.front();

    ScopePacked scopeIdExpected = man->clasp->pack(scopeExpected);
    ASSERT_EQ(scopeIdExpected, scopeIdActual);
}

TEST(CFA, CFGRoots){
//    std::string program =
//R"CODE(
//    main = function::int{a()+ b()}
//    a= function::int {c1() + c2()}
//    b= function::int {c2()}
//    c1=function::int{0}
//    c2=function::int{0}
//)CODE";
//
//    boost::scoped_ptr<XreateManager> manager
//        (XreateManager::prepare(move(program)));
//
//    manager->registerPass(new CFAPass(manager.get()) , PassId::CFGPass);
//    manager->executePasses();
//    manager->clasp->run();
//
//    dominators::DominatorsTreeAnalysisProvider domProvider;
//    domProvider.run(manager->clasp);
//
//    dominators::DominatorsTreeAnalysisProvider::Dominators expectedFDom= {
//         {0, {0, 9}}
//        ,{1, {1, 4}}
//        ,{2, {7, 8}}
//        ,{3, {2, 3}}
//        ,{4, {5, 6}}
//    };
//
//    dominators::DominatorsTreeAnalysisProvider::Dominators expectedPostDom= {
//         {0, {5, 6}}
//        ,{1, {3, 4}}
//        ,{2, {8, 9}}
//        ,{3, {1, 2}}
//        ,{4, {7, 10}}
//    };
//
//    ASSERT_EQ(expectedFDom, domProvider.getForwardDominators());
//    ASSERT_EQ(expectedPostDom, domProvider.getPostDominators());
}
