#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); }; } TEST_CASE("loop break", "[script][loop]") { State state; const char* script = R"( number sum = 0; for (number i = 0; i < 10; i = i + 1) { if (i == 5) { break; } sum = sum + i; } )"; REQUIRE(state.do_string(script)); auto sum_val = state.get_global("sum"); REQUIRE(sum_val); auto sum_num = std::dynamic_pointer_cast(sum_val); REQUIRE(sum_num->value == 10.0); // 0+1+2+3+4 = 10 } TEST_CASE("loop continue", "[script][loop]") { State state; const char* script = R"( number sum = 0; for (number i = 0; i < 5; i = i + 1) { if (i == 2) { continue; } sum = sum + i; } )"; REQUIRE(state.do_string(script)); auto sum_val = state.get_global("sum"); REQUIRE(sum_val); auto sum_num = std::dynamic_pointer_cast(sum_val); REQUIRE(sum_num->value == 8.0); // 0+1+3+4 = 8 } TEST_CASE("while break and continue", "[script][loop]") { State state; const char* script = R"( number i = 0; number sum = 0; while (i < 10) { i = i + 1; if (i == 3) { continue; } if (i == 6) { break; } sum = sum + i; } )"; REQUIRE(state.do_string(script)); auto sum_val = state.get_global("sum"); REQUIRE(sum_val); auto sum_num = std::dynamic_pointer_cast(sum_val); REQUIRE(sum_num->value == 12.0); // 1st iter: i=1, sum=1 // 2nd iter: i=2, sum=1+2=3 // 3rd iter: i=3, continue // 4th iter: i=4, sum=3+4=7 // 5th iter: i=5, sum=7+5=12 // 6th iter: i=6, break // Result should be 12.0 }