This commit is contained in:
2026-01-13 22:52:55 +08:00
commit 211a837468
18 changed files with 2831 additions and 0 deletions

150
tests/test_basic.cpp Normal file
View File

@@ -0,0 +1,150 @@
#include <catch2/catch_test_macros.hpp>
#include <catch2/benchmark/catch_benchmark.hpp>
#include "library.h"
#include <memory>
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<NumberValue>(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<NumberValue>(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<ListValue>(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<NumberValue>(first);
auto third_n = std::dynamic_pointer_cast<NumberValue>(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<InstanceValue>(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<NumberValue>(age_val);
auto name_str = std::dynamic_pointer_cast<StringValue>(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<NumberValue>(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<NumberValue>(r_val);
REQUIRE(r_num->value == 499500.0);
};
}