#include #include #include #include #define SOL_ALL_SAFETIES_ON 1 #include using namespace fuc2; namespace sol2_tests { void test_basic_lua_run() { sol::state lua; int x = 0; lua.set_function("beep", [&x]{++x; }); lua.script("beep()"); EQUAL(x, 1, "Lua failed to set x"); } struct vars { int boop = 0; }; void test_big_ass_vector() { std::vector variables; for(int i = 0; i < 100; i++) { variables.emplace_back(i); } sol::state lua; lua.open_libraries(sol::lib::base); lua.new_usertype("vars", "boop", &vars::boop); lua.script(R"( function handler(v) v.boop = v.boop + 1 end )"); sol::function handler = lua["handler"]; for(auto& v : variables) { int boop_before = v.boop; handler(v); CHECK(boop_before == v.boop - 1); } } void test_usertype_vars() { sol::state lua; lua.new_usertype("vars", "boop", &vars::boop); lua.script("beep = vars.new()\n" "beep.boop = 1"); EQUAL(lua.get("beep").boop, 1); } void test_base_libraries() { using L = sol::lib; sol::state lua; lua.open_libraries( L::base, L::package, L::coroutine, L::string, L::os, L::math, L::table, L::debug, L::bit32, L::io, L::ffi, L::jit); lua.script("print('bark bark bark!')"); fmt::println(""); } void test_sol_lua_error() { BLOWS_UP([]() { sol::state lua; auto result1 = lua.safe_script("bad.code"); }); } void test_variables_from_file() { sol::state lua; lua.script_file("tests/variables.lua"); CHECK(lua["config"]["fullscreen"] == false); sol::table config = lua["config"]; CHECK(config["fullscreen"] == false); } void test_passing_args_to_scripts() { sol::state lua; lua.open_libraries(sol::lib::base); const auto& my_script = R"( local a,b,c = ... print(a, b, c) )"; sol::load_result fx = lua.load(my_script); if(!fx.valid()) { sol::error err = fx; throw err; } fx("your", "arguments", "here"); } void test_transfer_func() { sol::state lua; sol::state lua2; lua2.open_libraries(sol::lib::base); sol::load_result lr = lua.load("a = function(v) print(v) return v end"); CHECK(lr.valid()); sol::protected_function target = lr.get(); sol::bytecode target_bc = target.dump(); auto result2 = lua2.safe_script(target_bc.as_string_view(), sol::script_pass_on_error); CHECK(result2.valid()); sol::protected_function pf = lua2["a"]; int v = pf(25557); CHECK(v == 25557); } void test_get_variables() { sol::state lua; lua.open_libraries(sol::lib::base); lua.set("number", 24); CHECK(lua["number"] == 24); lua["number"] = 24.5; CHECK(lua["number"] == 24.5); // how to compare a string? lua["important_string"] = "test"; std::string a_string = "test"; CHECK(lua["important_string"] == a_string); lua["a_function"] = []() { return 100; }; auto result = lua["a_function"](); CHECK(result.valid()); int as_int = result; CHECK(as_int == 100); lua["some_table"] = lua.create_table_with("value", 24); CHECK(lua["some_table"]["value"] == 24); } void test_this_has_a_bug_in_sol2() { sol::state lua; lua.script(R"( function handler (message) return "Handled this message: " .. message end function f (a) if a < 0 then error("negative number detected") end return a + 5 end )"); sol::protected_function f = lua["f"]; // this fails, error_handler is private // f.error_handler = lua["handler"]; sol::protected_function_result result = f(-500); if (result.valid()) { // Call succeeded int x = result; } else { // Call failed sol::error err = result; std::string what = err.what(); // 'what' Should read // "Handled this message: negative number detected" } } void test_multiple_returns() { sol::state lua; lua.script("function f(a,b,c) return a, b, c end"); std::tuple result; result = lua["f"](1, 2, 3); CHECK(std::get<0>(result) == 1); CHECK(std::get<1>(result) == 2); CHECK(std::get<2>(result) == 3); int a; int b; std::string c; sol::tie(a, b, c) = lua["f"](1, 2, "bar"); CHECK(a == 1); CHECK(b == 2); CHECK(c == "bar"); } sol::object fancy_func(sol::object a, sol::object b, sol::this_state s) { sol::state_view lua(s); if(a.is() && b.is()) { return sol::make_object(lua, a.as() + b.as()); } else if(a.is()) { bool do_triple = a.as(); return sol::make_object(lua, b.as() * (do_triple ? 3 : 1)); } else { return sol::make_object(lua, sol::lua_nil); } } void test_any_object_types() { sol::state lua; lua["f"] = fancy_func; int result = lua["f"](1, 2); CHECK(result == 3); double result2 = lua["f"](false, 2.5); CHECK(result2 == 2.5); lua.script("result3 = f(true, 5.5)"); double result3 = lua["result3"]; CHECK(result3 == 16.5); } struct player { int bullets; int speed; player() : player(3, 100) {} player(int ammo) : player(ammo, 100) {} player(int ammo, int hitpoints) : bullets(ammo), hp(hitpoints) {} void boost() { speed += 10; } bool shoot() { if(bullets < 1) { return false; } --bullets; return true; } void set_hp(int value) { hp = value; } int get_hp() const { return hp; } private: int hp; }; void test_udt_operations() { sol::state lua; lua.open_libraries(sol::lib::base); lua["p2"] = player(0); sol::usertype player_type = lua.new_usertype("player", sol::constructors< player(), player(int), player(int, int)>()); player_type["shoot"] = &player::shoot; player_type["boost"] = &player::boost; player_type["hp"] = sol::property(&player::get_hp, &player::set_hp); player_type["speed"] = &player::speed; player_type.set("bullets", sol::readonly(&player::bullets)); lua.script_file("tests/prelude_script.lua"); lua.script_file("tests/player_script.lua"); } fuc2::Set TESTS{ .name="sol2", .options={ .fail_fast=false }, .tests={ TEST(test_basic_lua_run), TEST(test_usertype_vars), TEST(test_base_libraries), TEST(test_sol_lua_error), TEST(test_variables_from_file), TEST(test_big_ass_vector), TEST(test_passing_args_to_scripts), TEST(test_get_variables), TEST(test_this_has_a_bug_in_sol2), TEST(test_multiple_returns), TEST(test_any_object_types), TEST(test_udt_operations), } }; }