#ifdef TESTS_BUILD
#include <catch.hpp>
#include <cfloat>
#include <cmath>
#include <cstring>
#include "../src/Script.hpp"
#include "../../src/ScriptOptions.hpp"

using namespace Porygon;

TEST_CASE( "Abs positive returns positive", "[integration]" ) {
    Script* script = Script::Create(u"return math.abs(684)");
    REQUIRE(!script->Diagnostics -> HasErrors());
    auto result = script -> Evaluate();
    CHECK(result->EvaluateInteger() == 684);
    delete script;
}

TEST_CASE( "Abs negative returns positive", "[integration]" ) {
    Script* script = Script::Create(u"return math.abs(-684)");
    REQUIRE(!script->Diagnostics -> HasErrors());
    auto result = script -> Evaluate();
    CHECK(result->EvaluateInteger() == 684);
    delete script;
}

TEST_CASE( "math.acos(1) == 0", "[integration]" ) {
    Script* script = Script::Create(u"return math.acos(1)");
    REQUIRE(!script->Diagnostics -> HasErrors());
    auto result = script -> Evaluate();
    CHECK(result->EvaluateFloat() == 0);
    delete script;
}

TEST_CASE( "math.acos(0) == 1.5707963267949", "[integration]" ) {
    Script* script = Script::Create(u"return math.acos(0)");
    REQUIRE(!script->Diagnostics -> HasErrors());
    auto result = script -> Evaluate();
    CHECK(result->EvaluateFloat() == Approx(1.5707963267949));
    delete script;
}

TEST_CASE( "math.asin(0) == 0", "[integration]" ) {
    Script* script = Script::Create(u"return math.asin(0)");
    REQUIRE(!script->Diagnostics -> HasErrors());
    auto result = script -> Evaluate();
    CHECK(result->EvaluateFloat() == 0);
    delete script;
}

TEST_CASE( "math.asin(1) == 1.5707963267949", "[integration]" ) {
    Script* script = Script::Create(u"return math.asin(1)");
    REQUIRE(!script->Diagnostics -> HasErrors());
    auto result = script -> Evaluate();
    CHECK(result->EvaluateFloat() == Approx(1.5707963267949));
    delete script;
}

TEST_CASE( "math.atan(1,0) == 1.5707963267949", "[integration]" ) {
    Script* script = Script::Create(u"return math.atan(1,0)");
    REQUIRE(!script->Diagnostics -> HasErrors());
    auto result = script -> Evaluate();
    CHECK(result->EvaluateFloat() == Approx(1.5707963267949));
    delete script;
}

TEST_CASE( "math.atan(-1,0) == -1.5707963267949", "[integration]" ) {
    Script* script = Script::Create(u"return math.atan(-1,0)");
    REQUIRE(!script->Diagnostics -> HasErrors());
    auto result = script -> Evaluate();
    CHECK(result->EvaluateFloat() == Approx(-1.5707963267949));
    delete script;
}

TEST_CASE( "math.atan(0,1) == 0", "[integration]" ) {
    Script* script = Script::Create(u"return math.atan(0,1)");
    REQUIRE(!script->Diagnostics -> HasErrors());
    auto result = script -> Evaluate();
    CHECK(result->EvaluateFloat() == Approx(0));
    delete script;
}

TEST_CASE( "math.atan(0,-1) == 3.1415926535898", "[integration]" ) {
    Script* script = Script::Create(u"return math.atan(0,-1)");
    REQUIRE(!script->Diagnostics -> HasErrors());
    auto result = script -> Evaluate();
    CHECK(result->EvaluateFloat() == Approx(3.1415926535898));
    delete script;
}

TEST_CASE( "math.ceil(0.5) == 1", "[integration]" ) {
    Script* script = Script::Create(u"return math.ceil(0.5)");
    REQUIRE(!script->Diagnostics -> HasErrors());
    auto result = script -> Evaluate();
    CHECK(result->EvaluateInteger() == 1);
    delete script;
}

TEST_CASE( "math.ceil(0.1) == 1", "[integration]" ) {
    Script* script = Script::Create(u"return math.ceil(0.1)");
    REQUIRE(!script->Diagnostics -> HasErrors());
    auto result = script -> Evaluate();
    CHECK(result->EvaluateInteger() == 1);
    delete script;
}

TEST_CASE( "math.floor(0.5) == 0", "[integration]" ) {
    Script* script = Script::Create(u"return math.floor(0.5)");
    REQUIRE(!script->Diagnostics -> HasErrors());
    auto result = script -> Evaluate();
    CHECK(result->EvaluateInteger() == 0);
    delete script;
}

TEST_CASE( "math.floor(0.9) == 0", "[integration]" ) {
    Script* script = Script::Create(u"return math.floor(0.9)");
    REQUIRE(!script->Diagnostics -> HasErrors());
    auto result = script -> Evaluate();
    CHECK(result->EvaluateInteger() == 0);
    delete script;
}

TEST_CASE( "math.cos(0.7853981634) == 0.70710678118655", "[integration]" ) {
    Script* script = Script::Create(u"return math.cos(0.7853981634)");
    REQUIRE(!script->Diagnostics -> HasErrors());
    auto result = script -> Evaluate();
    CHECK(result->EvaluateFloat() == Approx(0.70710678118655));
    delete script;
}

TEST_CASE( "math.sin(0.123) == 0.12269009002432", "[integration]" ) {
    Script* script = Script::Create(u"return math.sin(0.123)");
    REQUIRE(!script->Diagnostics -> HasErrors());
    auto result = script -> Evaluate();
    CHECK(result->EvaluateFloat() == Approx(0.12269009002432));
    delete script;
}

TEST_CASE( "math.tan(1.25) == 3.0095696738628", "[integration]" ) {
    Script* script = Script::Create(u"return math.tan(1.25)");
    REQUIRE(!script->Diagnostics -> HasErrors());
    auto result = script -> Evaluate();
    CHECK(result->EvaluateFloat() == Approx(3.0095696738628));
    delete script;
}

TEST_CASE( "math.tan(0.77) == 0.96966832796149", "[integration]" ) {
    Script* script = Script::Create(u"return math.tan(0.77)");
    REQUIRE(!script->Diagnostics -> HasErrors());
    auto result = script -> Evaluate();
    CHECK(result->EvaluateFloat() == Approx(0.96966832796149));
    delete script;
}

TEST_CASE( "math.deg(3.1415926535898) == 180", "[integration]" ) {
    Script* script = Script::Create(u"return math.deg(3.1415926535898)");
    REQUIRE(!script->Diagnostics -> HasErrors());
    auto result = script -> Evaluate();
    CHECK(result->EvaluateFloat() == Approx(180));
    delete script;
}

TEST_CASE( "math.deg(1.5707963267949) == 90", "[integration]" ) {
    Script* script = Script::Create(u"return math.deg(1.5707963267949)");
    REQUIRE(!script->Diagnostics -> HasErrors());
    auto result = script -> Evaluate();
    CHECK(result->EvaluateFloat() == Approx(90));
    delete script;
}

TEST_CASE( "math.rad(180) == 3.1415926535898", "[integration]" ) {
    Script* script = Script::Create(u"return math.rad(180)");
    REQUIRE(!script->Diagnostics -> HasErrors());
    auto result = script -> Evaluate();
    CHECK(result->EvaluateFloat() == Approx(3.1415926535898));
    delete script;
}

TEST_CASE( "math.rad(1) == 0.017453292519943", "[integration]" ) {
    Script* script = Script::Create(u"return math.rad(1)");
    REQUIRE(!script->Diagnostics -> HasErrors());
    auto result = script -> Evaluate();
    CHECK(result->EvaluateFloat() == Approx(0.017453292519943));
    delete script;
}

TEST_CASE( "math.exp(0) == 1", "[integration]" ) {
    Script* script = Script::Create(u"return math.exp(0)");
    REQUIRE(!script->Diagnostics -> HasErrors());
    auto result = script -> Evaluate();
    CHECK(result->EvaluateFloat() == Approx(1));
    delete script;
}

TEST_CASE( "math.exp(1) == 2.718281828459", "[integration]" ) {
    Script* script = Script::Create(u"return math.exp(1)");
    REQUIRE(!script->Diagnostics -> HasErrors());
    auto result = script -> Evaluate();
    CHECK(result->EvaluateFloat() == Approx(2.718281828459));
    delete script;
}

TEST_CASE( "math.exp(27) == 532048240601.8", "[integration]" ) {
    Script* script = Script::Create(u"return math.exp(27)");
    REQUIRE(!script->Diagnostics -> HasErrors());
    auto result = script -> Evaluate();
    CHECK(result->EvaluateFloat() == Approx(532048240601.8));
    delete script;
}

TEST_CASE( "math.log(532048240601) == 26.999999999998", "[integration]" ) {
    Script* script = Script::Create(u"return math.log(532048240601)");
    REQUIRE(!script->Diagnostics -> HasErrors());
    auto result = script -> Evaluate();
    CHECK(result->EvaluateFloat() == Approx(26.999999999998));
    delete script;
}

TEST_CASE( "math.log(3) == 1.0986122886681", "[integration]" ) {
    Script* script = Script::Create(u"return math.log(3)");
    REQUIRE(!script->Diagnostics -> HasErrors());
    auto result = script -> Evaluate();
    CHECK(result->EvaluateFloat() == Approx(1.0986122886681));
    delete script;
}

TEST_CASE( "math.sqrt(100) == 10", "[integration]" ) {
    Script* script = Script::Create(u"return math.sqrt(100)");
    REQUIRE(!script->Diagnostics -> HasErrors());
    auto result = script -> Evaluate();
    CHECK(result->EvaluateFloat() == Approx(10));
    delete script;
}

TEST_CASE( "math.sqrt(1234) == 35.128336140501", "[integration]" ) {
    Script* script = Script::Create(u"return math.sqrt(1234)");
    REQUIRE(!script->Diagnostics -> HasErrors());
    auto result = script -> Evaluate();
    CHECK(result->EvaluateFloat() == Approx(35.128336140501));
    delete script;
}

TEST_CASE( "math.sqrt(-7) == nan", "[integration]" ) {
    Script* script = Script::Create(u"return math.sqrt(-7)");
    REQUIRE(!script->Diagnostics -> HasErrors());
    auto result = script -> Evaluate();
    CHECK(isnan(result->EvaluateFloat()));
    delete script;
}

TEST_CASE( "math.huge == max_double", "[integration]" ) {
    Script* script = Script::Create(u"return math.huge");
    REQUIRE(!script->Diagnostics -> HasErrors());
    auto result = script -> Evaluate();
    CHECK(result->EvaluateFloat() == DBL_MAX);
    delete script;
}

TEST_CASE( "math.pi == pi", "[integration]" ) {
    Script* script = Script::Create(u"return math.pi");
    REQUIRE(!script->Diagnostics -> HasErrors());
    auto result = script -> Evaluate();
    CHECK(result->EvaluateFloat() == M_PI);
    delete script;
}


#endif

