diff options
Diffstat (limited to '3rdparty/sol2/test_tables.cpp')
-rw-r--r-- | 3rdparty/sol2/test_tables.cpp | 548 |
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]); + } +} |