#include "camellya.h" #include "exceptions.h" #include #include using namespace camellya; // Simple Vector3D wrapper for testing class Vector3DValue : public NativeValue { public: double x, y, z; Vector3DValue(double x, double y, double z) : NativeValue("Vector3D"), x(x), y(y), z(z) {} std::string to_string() const override { return "Vector3D(" + std::to_string(x) + ", " + std::to_string(y) + ", " + std::to_string(z) + ")"; } ValuePtr clone() const override { return std::make_shared(x, y, z); } }; TEST_CASE("Generic built-in class (Vector3D) test", "[generic]") { Camellya c; // 1. Create the ClassValue for Vector3D auto v3d_klass = std::make_shared("Vector3D"); // 2. Add a native method 'length' v3d_klass->add_method("length", std::make_shared("length", [](const std::vector& args) -> ValuePtr { if (args.size() != 1) throw RuntimeError("Vector3D.length() expects 0 arguments."); auto vec = std::dynamic_pointer_cast(args[0]); double len = std::sqrt(vec->x * vec->x + vec->y * vec->y + vec->z * vec->z); return std::make_shared(len); })); // 3. Register it as a built-in class for type "Vector3D" c.register_builtin_class("Vector3D", v3d_klass); // 4. Register a factory function to create Vector3D instances from script c.register_function("Vector3D", [](const std::vector& args) -> ValuePtr { if (args.size() != 3) throw RuntimeError("Vector3D() expects 3 arguments."); double x = std::dynamic_pointer_cast(args[0])->value; double y = std::dynamic_pointer_cast(args[1])->value; double z = std::dynamic_pointer_cast(args[2])->value; return std::make_shared(x, y, z); }); SECTION("vector3d methods") { REQUIRE(c.do_string(R"( var v = Vector3D(3, 4, 0); var len = v.length(); )")); auto len = c.get_global("len"); REQUIRE(std::dynamic_pointer_cast(len)->value == 5.0); } }