#include #include #include "camellya.h" #include using namespace camellya; TEST_CASE("basic arithmetic", "[script]") { State state; const char* script = R"( number x = 10; number y = 20; number z = x + y; )"; REQUIRE(state.do_string(script)); auto z = state.get_global("z"); REQUIRE(z); REQUIRE(z->type() == Type::NUMBER); auto nz = std::dynamic_pointer_cast(z); REQUIRE(nz); REQUIRE(nz->value == 30.0); } TEST_CASE("basic function", "[script][func]") { State state; const char* script = R"( func add(number x, number y) -> number { return x + y; } number z = add(10, 20); )"; REQUIRE(state.do_string(script)); auto z = state.get_global("z"); REQUIRE(z); REQUIRE(z->type() == Type::NUMBER); auto nz = std::dynamic_pointer_cast(z); REQUIRE(nz); REQUIRE(nz->value == 30.0); } TEST_CASE("list indexing is 0-based", "[list]") { State state; const char* script = R"( list numbers = [10, 20, 30]; )"; REQUIRE(state.do_string(script)); auto list_val = state.get_global("numbers"); REQUIRE(list_val); REQUIRE(list_val->type() == Type::LIST); auto list = std::dynamic_pointer_cast(list_val); REQUIRE(list); REQUIRE(list->size() == 3); auto first = list->get(0); auto third = list->get(2); REQUIRE(first->type() == Type::NUMBER); REQUIRE(third->type() == Type::NUMBER); auto first_n = std::dynamic_pointer_cast(first); auto third_n = std::dynamic_pointer_cast(third); REQUIRE(first_n->value == 10.0); REQUIRE(third_n->value == 30.0); } TEST_CASE("class init is called on declaration", "[class][init]") { State state; const char* script = R"( class Person { number age; string name; func init() -> nil { age = 18; name = "Default"; } func getAge() -> number { return this.age; } } Person p; number a = p.getAge(); )"; REQUIRE(state.do_string(script)); auto p_val = state.get_global("p"); REQUIRE(p_val); REQUIRE(p_val->type() == Type::INSTANCE); auto instance = std::dynamic_pointer_cast(p_val); REQUIRE(instance); auto age_val = instance->get("age"); auto name_val = instance->get("name"); REQUIRE(age_val->type() == Type::NUMBER); REQUIRE(name_val->type() == Type::STRING); auto age_num = std::dynamic_pointer_cast(age_val); auto name_str = std::dynamic_pointer_cast(name_val); REQUIRE(age_num->value == 18.0); REQUIRE(name_str->value == "Default"); auto a_val = state.get_global("a"); REQUIRE(a_val); REQUIRE(a_val->type() == Type::NUMBER); auto a_num = std::dynamic_pointer_cast(a_val); REQUIRE(a_num->value == 18.0); } TEST_CASE("interpreter performance: simple loop", "[perf][script]") { State state; const char* script = R"( func sum_to(number n) -> number { number s = 0; for (number i = 0; i < n; i = i + 1) { s = s + i; } return s; } number r = sum_to(1000); )"; BENCHMARK("sum_to(1000)") { if (!state.do_string(script)) { auto last_error = state.get_error(); REQUIRE(last_error.empty()); } auto r_val = state.get_global("r"); REQUIRE(r_val); REQUIRE(r_val->type() == Type::NUMBER); auto r_num = std::dynamic_pointer_cast(r_val); REQUIRE(r_num->value == 499500.0); }; }