Experiments in using Lua with sol2 and how best to structure the data. Contains a shoot out of SOA, vs AOS vs. MOA. SOA = Struct of Arrays AOS = Array of Structs MOA = Many Array of Structs (kind of a hybrid)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
sol2_test/tests/sol2_test.cpp

322 lines
7.0 KiB

#include <fmt/core.h>
#include <deque>
#include <string>
#include <fuc2/testing.hpp>
#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>
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<vars> 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>("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>("vars", "boop", &vars::boop);
lua.script("beep = vars.new()\n"
"beep.boop = 1");
EQUAL(lua.get<vars>("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::protected_function>();
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<int, int, int> 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<int>() && b.is<int>()) {
return sol::make_object(lua, a.as<int>() + b.as<int>());
} else if(a.is<bool>()) {
bool do_triple = a.as<bool>();
return sol::make_object(lua, b.as<double>() * (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> player_type = lua.new_usertype<player>("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),
}
};
}