/*
 * adhoc-exceptions.cpp

 *
 *  Created on: Nov 19, 2015
 *      Author: pgess
 */

class Adhoc_pass_Adhoc1_Test;
#define FRIEND_ADHOC_UNITTESTS \
	friend class ::Adhoc_pass_Adhoc1_Test;


#include "ast.h"
#include "passmanager.h"

#include "gtest/gtest.h"
#include <stdio.h>
#include <memory>
#include <sstream>
#include <stdlib.h>


#include "pass/adhocpass.h"
#include "pass/compilepass.h"
#include "llvmlayer.h"

using namespace xreate;
using namespace std;

TEST(Adhoc, ast_operatorAdhoc1){
	PassManager* man = PassManager::prepareForCode (
		"		test = "
		"function:: int {\n"
		"			ad hoc Exception(NonImplemented)\n"
		"		}"
	);

	Expression subject = man->root->findFunction("test")->getEntryScope()->getBody();
	ASSERT_EQ(Operator::ADHOC, subject.op);
	ASSERT_EQ(1, subject.getOperands().size());

	Expression exception = subject.getOperands()[0];
	ASSERT_EQ("Exception", exception.getValueString());
}

TEST(Adhoc, ast_schemeAdhoc1){
	PassManager* man = PassManager::prepareForCode (
	"interface(adhoc){\n"
	"		pre function expectNoErrors:: bool {\n"
	"			case Error  {false}\n"
	"			case Success {true}\n"
	"		}\n"
	"	}");

	assert(man->root->__interfacesData.count(ASTInterface::Adhoc));
	Expression adhocData = man->root->__interfacesData.find(ASTInterface::Adhoc)->second;
	ASSERT_EQ(Operator::SWITCH, adhocData.operands[0].op);
}

TEST(Adhoc, pass_Adhoc1){
	PassManager* man = PassManager::prepareForCode (
		"interface(adhoc){\n"
		"		pre function expectNoErrors:: bool {\n"
		"			case Error  {false}\n"
		"			case Success {true}\n"
		"		}\n"
		"}\n"

                "main = function::int; entry {0} \n"
                );

	man->runWithoutCompilation();
	AdhocPass* pass = reinterpret_cast<AdhocPass* >(man->getPassById(PassId::AdhocPass));
	EXPECT_TRUE(pass->__schemes.size() > 0);

	AdhocScheme* scheme =  pass->__schemes.begin()->second;
	EXPECT_EQ("expectNoErrors", scheme->getContext());
}

TEST(Adhoc, full_1){
	PassManager* man = PassManager::prepareForCode (
		"	import raw (\"core/control-context.lp\")"

		"	interface(adhoc){\n"
		"		pre function expectNoErrors:: bool {\n"
		"			case Error  {0}\n"
		"			case Success {1}\n"
		"		}\n"
		"	}"

		"	test1 = pre function {\n"
		"		context:: expectNoErrors."
		"		ad hoc \"Success\"\n"
		"	}"

		"main = function::bool;entry {\n"
		"			test1()\n"
		"		}");

	bool (*main)() = (bool (*)()) man->run();
	bool result = main();
	ASSERT_EQ(true, result);
}

TEST(Adhoc, full_contextExpectNoErrrors){
	PassManager* man = PassManager::prepareForCode (
	"import raw (\"core/control-context.lp\")\n"

	"interface(extern-c){\n"
	"  xml2 = library:: pkgconfig(\"libxml-2.0\").\n"
	"  \n"
	"  include {\n"
	"    xml2 = [\"stdlib.h\"]\n"
	"  }.\n"
	"}"

	"interface(adhoc){\n"
	"	pre function expectNoErrors:: bool {\n"
	"		case Error  {0}\n"
	"		case Success {1}\n"
	"	}\n"
	"}\n"

	"expectErrorCode = pre function(x::int){\n"
	"	if (x==0)::bool {ad hoc \"Success\"}\n"
	"	else {ad hoc \"Error\"}\n"
	"}\n"

	"main = function::bool; entry {\n"
	"		context:: expectNoErrors."
	"		expectErrorCode(system(\"ls -la\"))\n"
	"}"	);

	int (*main)() = (int (*)()) man->run();
	ASSERT_EQ(1, main());
}

TEST(Adhoc, ast_switchAdhoc1){
	PassManager* man = PassManager::prepareForCode (
	"test1 = function:: bool {\n"
	"		switch ad hoc (x:: errors)\n"
	"			case ERROR {0}\n"
	"			case SUCCESS {1}\n"
	"		\n"
	"	}"
	);

	Expression eSwitch = man->root->findFunction("test1")->getEntryScope()->getBody();
	EXPECT_EQ(Operator::SWITCH_ADHOC, eSwitch.op);
	EXPECT_EQ(3, eSwitch.operands.size());

	EXPECT_EQ(1, eSwitch.tags.size());
	EXPECT_EQ("errors", eSwitch.tags.begin()->first);

	Expression eCondition = eSwitch.getOperands()[0];
	EXPECT_EQ("x", eCondition.getValueString());
}


