summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/sol2/test_tables.cpp
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/sol2/test_tables.cpp')
-rw-r--r--3rdparty/sol2/test_tables.cpp548
1 files changed, 548 insertions, 0 deletions
diff --git a/3rdparty/sol2/test_tables.cpp b/3rdparty/sol2/test_tables.cpp
new file mode 100644
index 00000000000..cb8f291ee09
--- /dev/null
+++ b/3rdparty/sol2/test_tables.cpp
@@ -0,0 +1,548 @@
+#define SOL_CHECK_ARGUMENTS
+
+#include <catch.hpp>
+#include <sol.hpp>
+
+#include <iostream>
+#include <algorithm>
+#include <numeric>
+#include <vector>
+
+#include "test_stack_guard.hpp"
+
+std::string free_function() {
+ INFO("free_function()");
+ return "test";
+}
+
+struct object {
+ std::string operator() () {
+ INFO("member_test()");
+ return "test";
+ }
+};
+
+int plop_xyz(int x, int y, std::string z) {
+ INFO(x << " " << y << " " << z);
+ return 11;
+}
+
+TEST_CASE("tables/as-enums", "Making sure enums can be put in and gotten out as values") {
+ enum direction {
+ up,
+ down,
+ left,
+ right
+ };
+
+ sol::state lua;
+ lua.open_libraries(sol::lib::base);
+
+ lua["direction"] = lua.create_table_with(
+ "up", direction::up,
+ "down", direction::down,
+ "left", direction::left,
+ "right", direction::right
+ );
+
+ sol::object obj = lua["direction"]["up"];
+ bool isdir = obj.is<direction>();
+ REQUIRE(isdir);
+ auto dir = obj.as<direction>();
+ REQUIRE(dir == direction::up);
+}
+
+TEST_CASE("tables/as-enum-classes", "Making sure enums can be put in and gotten out as values") {
+ enum class direction {
+ up,
+ down,
+ left,
+ right
+ };
+
+ sol::state lua;
+ lua.open_libraries(sol::lib::base);
+
+ lua["direction"] = lua.create_table_with(
+ "up", direction::up,
+ "down", direction::down,
+ "left", direction::left,
+ "right", direction::right
+ );
+
+ sol::object obj = lua["direction"]["up"];
+ bool isdir = obj.is<direction>();
+ REQUIRE(isdir);
+ auto dir = obj.as<direction>();
+ REQUIRE(dir == direction::up);
+}
+
+TEST_CASE("tables/cleanup", "make sure tables leave the stack balanced") {
+ sol::state lua;
+ lua.open_libraries();
+
+ auto f = [] { return 5; };
+ for (int i = 0; i < 30; i++) {
+ std::string name = std::string("init") + std::to_string(i);
+ int top = lua_gettop(lua);
+ lua[name] = f;
+ int aftertop = lua_gettop(lua);
+ REQUIRE(aftertop == top);
+ int val = lua[name]();
+ REQUIRE(val == 5);
+ }
+}
+
+TEST_CASE("tables/nested-cleanup", "make sure tables leave the stack balanced") {
+ sol::state lua;
+ lua.open_libraries();
+
+ lua.script("A={}");
+ auto f = [] { return 5; };
+ for (int i = 0; i < 30; i++) {
+ std::string name = std::string("init") + std::to_string(i);
+ int top = lua_gettop(lua);
+ auto A = lua["A"];
+ int beforetop = lua_gettop(lua);
+ REQUIRE(beforetop == top);
+ A[name] = f;
+ int aftertop = lua_gettop(lua);
+ REQUIRE(aftertop == top);
+ int val = A[name]();
+ REQUIRE(val == 5);
+ }
+}
+
+TEST_CASE("tables/new_enum", "Making sure enums can be put in and gotten out as values") {
+ enum class direction {
+ up,
+ down,
+ left,
+ right
+ };
+
+ sol::state lua;
+ lua.open_libraries(sol::lib::base);
+
+ lua.new_enum( "direction",
+ "up", direction::up,
+ "down", direction::down,
+ "left", direction::left,
+ "right", direction::right
+ );
+
+ direction d = lua["direction"]["left"];
+ REQUIRE(d == direction::left);
+ REQUIRE_THROWS(lua.script("direction.left = 50"));
+ d = lua["direction"]["left"];
+ REQUIRE(d == direction::left);
+}
+
+TEST_CASE("tables/for-each", "Testing the use of for_each to get values from a lua table") {
+ sol::state lua;
+ lua.open_libraries(sol::lib::base);
+
+ lua.script("arr = {\n"
+ "[0] = \"Hi\",\n"
+ "[1] = 123.45,\n"
+ "[2] = \"String value\",\n"
+ // Does nothing
+ //"[3] = nil,\n"
+ //"[nil] = 3,\n"
+ "[\"WOOF\"] = 123,\n"
+ "}");
+ sol::table tbl = lua["arr"];
+ std::size_t tablesize = 4;
+ std::size_t iterations = 0;
+ auto fx = [&iterations](sol::object key, sol::object value) {
+ ++iterations;
+ sol::type keytype = key.get_type();
+ switch (keytype) {
+ case sol::type::number:
+ switch (key.as<int>()) {
+ case 0:
+ REQUIRE((value.as<std::string>() == "Hi"));
+ break;
+ case 1:
+ REQUIRE((value.as<double>() == 123.45));
+ break;
+ case 2:
+ REQUIRE((value.as<std::string>() == "String value"));
+ break;
+ case 3:
+ REQUIRE((value.is<sol::nil_t>()));
+ break;
+ }
+ break;
+ case sol::type::string:
+ if (key.as<std::string>() == "WOOF") {
+ REQUIRE((value.as<double>() == 123));
+ }
+ break;
+ case sol::type::nil:
+ REQUIRE((value.as<double>() == 3));
+ break;
+ default:
+ break;
+ }
+ };
+ auto fxpair = [&fx](std::pair<sol::object, sol::object> kvp) { fx(kvp.first, kvp.second); };
+ tbl.for_each(fx);
+ REQUIRE(iterations == tablesize);
+
+ iterations = 0;
+ tbl.for_each(fxpair);
+ REQUIRE(iterations == tablesize);
+}
+
+TEST_CASE("tables/for-each-empty", "empty tables should not crash") {
+ sol::state lua;
+ lua.open_libraries(sol::lib::base);
+
+ lua.script("arr = {}");
+ sol::table tbl = lua["arr"];
+ REQUIRE(tbl.empty());
+ std::size_t tablesize = 0;
+ std::size_t iterations = 0;
+ auto fx = [&iterations](sol::object key, sol::object value) {
+ ++iterations;
+ sol::type keytype = key.get_type();
+ switch (keytype) {
+ case sol::type::number:
+ switch (key.as<int>()) {
+ case 0:
+ REQUIRE((value.as<std::string>() == "Hi"));
+ break;
+ case 1:
+ REQUIRE((value.as<double>() == 123.45));
+ break;
+ case 2:
+ REQUIRE((value.as<std::string>() == "String value"));
+ break;
+ case 3:
+ REQUIRE((value.is<sol::nil_t>()));
+ break;
+ }
+ break;
+ case sol::type::string:
+ if (key.as<std::string>() == "WOOF") {
+ REQUIRE((value.as<double>() == 123));
+ }
+ break;
+ case sol::type::nil:
+ REQUIRE((value.as<double>() == 3));
+ break;
+ default:
+ break;
+ }
+ };
+ auto fxpair = [&fx](std::pair<sol::object, sol::object> kvp) { fx(kvp.first, kvp.second); };
+ tbl.for_each(fx);
+ REQUIRE(iterations == tablesize);
+
+ iterations = 0;
+ tbl.for_each(fxpair);
+ REQUIRE(iterations == tablesize);
+
+ iterations = 0;
+ for (const auto& kvp : tbl) {
+ fxpair(kvp);
+ ++iterations;
+ }
+ REQUIRE(iterations == tablesize);
+}
+
+TEST_CASE("tables/iterators", "Testing the use of iteratrs to get values from a lua table") {
+ sol::state lua;
+ lua.open_libraries(sol::lib::base);
+
+ lua.script("arr = {\n"
+ "[0] = \"Hi\",\n"
+ "[1] = 123.45,\n"
+ "[2] = \"String value\",\n"
+ // Does nothing
+ //"[3] = nil,\n"
+ //"[nil] = 3,\n"
+ "[\"WOOF\"] = 123,\n"
+ "}");
+ sol::table tbl = lua["arr"];
+ std::size_t tablesize = 4;
+ std::size_t iterations = 0;
+
+ int begintop = 0;
+ int endtop = 0;
+ {
+ test_stack_guard s(lua.lua_state(), begintop, endtop);
+ for (auto& kvp : tbl) {
+ [&iterations](sol::object key, sol::object value) {
+ ++iterations;
+ sol::type keytype = key.get_type();
+ switch (keytype) {
+ case sol::type::number:
+ switch (key.as<int>()) {
+ case 0:
+ REQUIRE((value.as<std::string>() == "Hi"));
+ break;
+ case 1:
+ REQUIRE((value.as<double>() == 123.45));
+ break;
+ case 2:
+ REQUIRE((value.as<std::string>() == "String value"));
+ break;
+ case 3:
+ REQUIRE((value.is<sol::nil_t>()));
+ break;
+ }
+ break;
+ case sol::type::string:
+ if (key.as<std::string>() == "WOOF") {
+ REQUIRE((value.as<double>() == 123));
+ }
+ break;
+ case sol::type::nil:
+ REQUIRE((value.as<double>() == 3));
+ break;
+ default:
+ break;
+ }
+ }(kvp.first, kvp.second);
+ }
+ } REQUIRE(begintop == endtop);
+ REQUIRE(iterations == tablesize);
+}
+
+TEST_CASE("tables/variables", "Check if tables and variables work as intended") {
+ sol::state lua;
+ lua.open_libraries(sol::lib::base, sol::lib::os);
+ lua.get<sol::table>("os").set("name", "windows");
+ REQUIRE_NOTHROW(lua.script("assert(os.name == \"windows\")"));
+}
+
+TEST_CASE("tables/create", "Check if creating a table is kosher") {
+ sol::state lua;
+ lua["testtable"] = sol::table::create(lua.lua_state(), 0, 0, "Woof", "Bark", 1, 2, 3, 4);
+ sol::object testobj = lua["testtable"];
+ REQUIRE(testobj.is<sol::table>());
+ sol::table testtable = testobj.as<sol::table>();
+ REQUIRE((testtable["Woof"] == std::string("Bark")));
+ REQUIRE((testtable[1] == 2));
+ REQUIRE((testtable[3] == 4));
+}
+
+TEST_CASE("tables/create-local", "Check if creating a table is kosher") {
+ sol::state lua;
+ lua["testtable"] = lua.create_table(0, 0, "Woof", "Bark", 1, 2, 3, 4);
+ sol::object testobj = lua["testtable"];
+ REQUIRE(testobj.is<sol::table>());
+ sol::table testtable = testobj.as<sol::table>();
+ REQUIRE((testtable["Woof"] == std::string("Bark")));
+ REQUIRE((testtable[1] == 2));
+ REQUIRE((testtable[3] == 4));
+}
+
+TEST_CASE("tables/create-local-named", "Check if creating a table is kosher") {
+ sol::state lua;
+ sol::table testtable = lua.create_table("testtable", 0, 0, "Woof", "Bark", 1, 2, 3, 4);
+ sol::object testobj = lua["testtable"];
+ REQUIRE(testobj.is<sol::table>());
+ REQUIRE((testobj == testtable));
+ REQUIRE_FALSE((testobj != testtable));
+ REQUIRE((testtable["Woof"] == std::string("Bark")));
+ REQUIRE((testtable[1] == 2));
+ REQUIRE((testtable[3] == 4));
+}
+
+TEST_CASE("tables/create-with-local", "Check if creating a table is kosher") {
+ sol::state lua;
+ lua["testtable"] = lua.create_table_with("Woof", "Bark", 1, 2, 3, 4);
+ sol::object testobj = lua["testtable"];
+ REQUIRE(testobj.is<sol::table>());
+ sol::table testtable = testobj.as<sol::table>();
+ REQUIRE((testtable["Woof"] == std::string("Bark")));
+ REQUIRE((testtable[1] == 2));
+ REQUIRE((testtable[3] == 4));
+}
+
+TEST_CASE("tables/functions-variables", "Check if tables and function calls work as intended") {
+ sol::state lua;
+ lua.open_libraries(sol::lib::base, sol::lib::os);
+ auto run_script = [](sol::state& lua) -> void {
+ lua.script("assert(os.fun() == \"test\")");
+ };
+
+ lua.get<sol::table>("os").set_function("fun",
+ []() {
+ INFO("stateless lambda()");
+ return "test";
+ }
+ );
+ REQUIRE_NOTHROW(run_script(lua));
+
+ lua.get<sol::table>("os").set_function("fun", &free_function);
+ REQUIRE_NOTHROW(run_script(lua));
+
+ // l-value, canNOT optimise
+ // prefer value semantics unless wrapped with std::reference_wrapper
+ {
+ auto lval = object();
+ lua.get<sol::table>("os").set_function("fun", &object::operator(), lval);
+ }
+ REQUIRE_NOTHROW(run_script(lua));
+
+ auto reflval = object();
+ lua.get<sol::table>("os").set_function("fun", &object::operator(), std::ref(reflval));
+ REQUIRE_NOTHROW(run_script(lua));
+
+
+ // stateful lambda: non-convertible, cannot be optimised
+ int breakit = 50;
+ lua.get<sol::table>("os").set_function("fun",
+ [&breakit]() {
+ INFO("stateful lambda()");
+ return "test";
+ }
+ );
+ REQUIRE_NOTHROW(run_script(lua));
+
+ // r-value, cannot optimise
+ lua.get<sol::table>("os").set_function("fun", &object::operator(), object());
+ REQUIRE_NOTHROW(run_script(lua));
+
+ // r-value, cannot optimise
+ auto rval = object();
+ lua.get<sol::table>("os").set_function("fun", &object::operator(), std::move(rval));
+ REQUIRE_NOTHROW(run_script(lua));
+}
+
+TEST_CASE("tables/operator[]", "Check if operator[] retrieval and setting works properly") {
+ sol::state lua;
+ lua.open_libraries(sol::lib::base);
+
+ lua.script("foo = 20\nbar = \"hello world\"");
+ // basic retrieval
+ std::string bar = lua["bar"];
+ int foo = lua["foo"];
+ REQUIRE(bar == "hello world");
+ REQUIRE(foo == 20);
+ // test operator= for stringification
+ // errors due to ambiguous operators
+ bar = lua["bar"];
+
+ // basic setting
+ lua["bar"] = 20.4;
+ lua["foo"] = "goodbye";
+
+ // doesn't modify the actual values obviously.
+ REQUIRE(bar == "hello world");
+ REQUIRE(foo == 20);
+
+ // function setting
+ lua["test"] = plop_xyz;
+ REQUIRE_NOTHROW(lua.script("assert(test(10, 11, \"hello\") == 11)"));
+
+ // function retrieval
+ sol::function test = lua["test"];
+ REQUIRE(test.call<int>(10, 11, "hello") == 11);
+
+ // setting a lambda
+ lua["lamb"] = [](int x) {
+ return x * 2;
+ };
+
+ REQUIRE_NOTHROW(lua.script("assert(lamb(220) == 440)"));
+
+ // function retrieval of a lambda
+ sol::function lamb = lua["lamb"];
+ REQUIRE(lamb.call<int>(220) == 440);
+
+ // test const table retrieval
+ auto assert1 = [](const sol::table& t) {
+ std::string a = t["foo"];
+ double b = t["bar"];
+ REQUIRE(a == "goodbye");
+ REQUIRE(b == 20.4);
+ };
+
+ REQUIRE_NOTHROW(assert1(lua.globals()));
+}
+
+TEST_CASE("tables/operator[]-valid", "Test if proxies on tables can lazily evaluate validity") {
+ sol::state lua;
+ bool isFullScreen = false;
+ auto fullscreennopers = lua["fullscreen"]["nopers"];
+ auto fullscreen = lua["fullscreen"];
+ REQUIRE_FALSE(fullscreennopers.valid());
+ REQUIRE_FALSE(fullscreen.valid());
+
+ lua["fullscreen"] = true;
+
+ REQUIRE_FALSE(fullscreennopers.valid());
+ REQUIRE(fullscreen.valid());
+ isFullScreen = lua["fullscreen"];
+ REQUIRE(isFullScreen);
+
+ lua["fullscreen"] = false;
+ REQUIRE_FALSE(fullscreennopers.valid());
+ REQUIRE(fullscreen.valid());
+ isFullScreen = lua["fullscreen"];
+ REQUIRE_FALSE(isFullScreen);
+}
+
+TEST_CASE("tables/operator[]-optional", "Test if proxies on tables can lazily evaluate validity") {
+ sol::state lua;
+
+ sol::optional<int> test1 = lua["no_exist_yet"];
+ bool present = (bool)test1;
+ REQUIRE_FALSE(present);
+
+ lua["no_exist_yet"] = 262;
+ sol::optional<int> test2 = lua["no_exist_yet"];
+ present = (bool)test2;
+ REQUIRE(present);
+ REQUIRE(test2.value() == 262);
+
+ sol::optional<int> nope = lua["nope"]["kek"]["hah"];
+ auto nope2 = lua.get<sol::optional<int>>(std::make_tuple("nope", "kek", "hah"));
+ present = (bool)nope;
+ REQUIRE_FALSE(present);
+ present = (bool)nope2;
+ REQUIRE_FALSE(present);
+ lua.create_named_table("nope", "kek", lua.create_table_with("hah", 1));
+ sol::optional<int> non_nope = lua["nope"]["kek"]["hah"].get<sol::optional<int>>();
+ sol::optional<int> non_nope2 = lua.get<sol::optional<int>>(std::make_tuple("nope", "kek", "hah"));
+ present = (bool)non_nope;
+ REQUIRE(present);
+ present = (bool)non_nope2;
+ REQUIRE(present);
+ REQUIRE(non_nope.value() == 1);
+ REQUIRE(non_nope2.value() == 1);
+
+ INFO("Keys: nope, kek, hah");
+ lua.set(std::make_tuple("nope", "kek", "hah"), 35);
+ sol::optional<int> non_nope3 = lua["nope"]["kek"]["hah"].get<sol::optional<int>>();
+ sol::optional<int> non_nope4 = lua.get<sol::optional<int>>(std::make_tuple("nope", "kek", "hah"));
+ present = (bool)non_nope3;
+ REQUIRE(present);
+ present = (bool)non_nope4;
+ REQUIRE(present);
+ REQUIRE(non_nope3.value() == 35);
+ REQUIRE(non_nope4.value() == 35);
+}
+
+TEST_CASE("tables/add", "Basic test to make sure the 'add' feature works") {
+ static const int sz = 120;
+
+ sol::state lua;
+ sol::table t = lua.create_table(sz, 0);
+
+ std::vector<int> bigvec( sz );
+ std::iota(bigvec.begin(), bigvec.end(), 1);
+
+ for (std::size_t i = 0; i < bigvec.size(); ++i) {
+ t.add(bigvec[i]);
+ }
+ for (std::size_t i = 0; i < bigvec.size(); ++i) {
+ int val = t[i + 1];
+ REQUIRE(val == bigvec[i]);
+ }
+}