diff options
| author | Vaxry <43317083+vaxerski@users.noreply.github.com> | 2026-04-26 15:16:36 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-04-26 15:16:36 +0100 |
| commit | 5ba33f846129f3e6c0505b19f94634b24505e828 (patch) | |
| tree | aaacabe678006040c342935481a86607c66607fd /tests/config/lua/LuaObjectsBasic.cpp | |
| parent | 329b2b356dd92ac07f4e2aa69cbce82ee9ba9d19 (diff) | |
config/lua: init lua config manager, use lua if available (#13817)
Adds a new lua config manager, which will automatically be used if there is a lua config present.
Diffstat (limited to 'tests/config/lua/LuaObjectsBasic.cpp')
| -rw-r--r-- | tests/config/lua/LuaObjectsBasic.cpp | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/tests/config/lua/LuaObjectsBasic.cpp b/tests/config/lua/LuaObjectsBasic.cpp new file mode 100644 index 00000000..10758b7d --- /dev/null +++ b/tests/config/lua/LuaObjectsBasic.cpp @@ -0,0 +1,266 @@ +#include <config/lua/LuaEventHandler.hpp> + +#include <config/lua/objects/LuaEventSubscription.hpp> +#include <config/lua/objects/LuaKeybind.hpp> + +#include <managers/KeybindManager.hpp> +#include <event/EventBus.hpp> + +#include <gtest/gtest.h> + +extern "C" { +#include <lualib.h> +#include <lauxlib.h> +} + +using namespace Config::Lua; + +namespace { + class CLuaState { + public: + CLuaState() : m_lua(luaL_newstate()) { + luaL_openlibs(m_lua); + } + + ~CLuaState() { + if (m_lua) + lua_close(m_lua); + } + + lua_State* get() const { + return m_lua; + } + + private: + lua_State* m_lua = nullptr; + }; + + int getGlobalInt(lua_State* L, const char* name) { + lua_getglobal(L, name); + const int v = sc<int>(lua_tointeger(L, -1)); + lua_pop(L, 1); + return v; + } + + bool getGlobalBool(lua_State* L, const char* name) { + lua_getglobal(L, name); + const bool v = lua_toboolean(L, -1) != 0; + lua_pop(L, 1); + return v; + } +} + +TEST(ConfigLuaObjects, keybindCanToggleEnabledFromLua) { + CLuaState S; + const auto L = S.get(); + + Objects::CLuaKeybind{}.setup(L); + + auto keybind = makeShared<SKeybind>(); + keybind->enabled = true; + + Objects::CLuaKeybind::push(L, keybind); + lua_setglobal(L, "kb"); + + ASSERT_EQ(luaL_dostring(L, R"( + assert(kb:is_enabled() == true) + kb:set_enabled(false) + assert(kb:is_enabled() == false) + )"), + LUA_OK); + + EXPECT_FALSE(keybind->enabled); +} + +TEST(ConfigLuaObjects, keybindExposesMetadataAndRemoveMethods) { + CLuaState S; + const auto L = S.get(); + + Objects::CLuaKeybind{}.setup(L); + + auto keybind = makeShared<SKeybind>(); + keybind->enabled = true; + keybind->description = "Close active window"; + keybind->hasDescription = true; + keybind->displayKey = "SUPER + Q"; + keybind->submap.name = "default"; + keybind->handler = "exec"; + keybind->arg = "kitty"; + keybind->modmask = HL_MODIFIER_META; + keybind->key = "Q"; + keybind->keycode = 24; + keybind->repeat = true; + keybind->locked = true; + keybind->release = false; + keybind->nonConsuming = true; + keybind->transparent = false; + keybind->ignoreMods = false; + keybind->longPress = false; + keybind->dontInhibit = true; + keybind->click = false; + keybind->drag = false; + keybind->submapUniversal = false; + keybind->deviceInclusive = true; + keybind->devices = {"kbd-a", "kbd-b"}; + + Objects::CLuaKeybind::push(L, keybind); + lua_setglobal(L, "kb"); + + ASSERT_EQ(luaL_dostring(L, R"( + assert(kb.enabled == true) + assert(kb.description == "Close active window") + assert(kb.display_key == "SUPER + Q") + assert(kb.submap == "default") + assert(kb.handler == "exec") + assert(kb.arg == "kitty") + assert(kb.modmask ~= nil) + assert(kb.key == "Q") + assert(kb.keycode == 24) + assert(kb.repeating == true) + assert(kb.locked == true) + assert(kb.non_consuming == true) + assert(kb.dont_inhibit == true) + assert(type(kb.devices) == "table") + + kb:remove() + kb:unbind() + )"), + LUA_OK); +} + +TEST(ConfigLuaObjects, objectsAreReadOnlyFromLua) { + CLuaState S; + const auto L = S.get(); + + Objects::CLuaKeybind{}.setup(L); + + auto keybind = makeShared<SKeybind>(); + Objects::CLuaKeybind::push(L, keybind); + lua_setglobal(L, "kb"); + + EXPECT_NE(luaL_dostring(L, "kb.foo = 1"), LUA_OK); + ASSERT_TRUE(lua_isstring(L, -1)); + EXPECT_NE(std::string(lua_tostring(L, -1)).find("read-only"), std::string::npos); + lua_pop(L, 1); +} + +TEST(ConfigLuaObjects, keybindSupportsEqAndToString) { + CLuaState S; + const auto L = S.get(); + + Objects::CLuaKeybind{}.setup(L); + + auto keybindA = makeShared<SKeybind>(); + auto keybindB = makeShared<SKeybind>(); + + Objects::CLuaKeybind::push(L, keybindA); + lua_setglobal(L, "kb1"); + + Objects::CLuaKeybind::push(L, keybindA); + lua_setglobal(L, "kb2"); + + Objects::CLuaKeybind::push(L, keybindB); + lua_setglobal(L, "kb3"); + + ASSERT_EQ(luaL_dostring(L, R"( + eq12 = (kb1 == kb2) + neq13 = (kb1 ~= kb3) + + local s = tostring(kb1) + hasPrefix = type(s) == "string" and string.sub(s, 1, 11) == "HL.Keybind(" + )"), + LUA_OK); + + EXPECT_TRUE(getGlobalBool(L, "eq12")); + EXPECT_TRUE(getGlobalBool(L, "neq13")); + EXPECT_TRUE(getGlobalBool(L, "hasPrefix")); +} + +TEST(ConfigLuaObjects, eventSubscriptionRemoveAndIsActive) { + CLuaState S; + const auto L = S.get(); + + Objects::CLuaEventSubscription{}.setup(L); + CLuaEventHandler handler(L); + + ASSERT_EQ(luaL_dostring(L, R"( + count = 0 + function onReload() + count = count + 1 + end + )"), + LUA_OK); + + lua_getglobal(L, "onReload"); + ASSERT_TRUE(lua_isfunction(L, -1)); + const int ref = luaL_ref(L, LUA_REGISTRYINDEX); + + const auto handle = handler.registerEvent("config.reloaded", ref); + ASSERT_TRUE(handle.has_value()); + + Objects::CLuaEventSubscription::push(L, &handler, *handle); + lua_setglobal(L, "sub"); + + Event::bus()->m_events.config.reloaded.emit(); + EXPECT_EQ(getGlobalInt(L, "count"), 1); + + ASSERT_EQ(luaL_dostring(L, R"( + assert(sub:is_active() == true) + sub:remove() + assert(sub:is_active() == false) + sub:remove() + )"), + LUA_OK); + + Event::bus()->m_events.config.reloaded.emit(); + EXPECT_EQ(getGlobalInt(L, "count"), 1); +} + +TEST(ConfigLuaObjects, eventSubscriptionSupportsEqAndToString) { + CLuaState S; + const auto L = S.get(); + + Objects::CLuaEventSubscription{}.setup(L); + CLuaEventHandler handler(L); + + ASSERT_EQ(luaL_dostring(L, R"( + function cbA() end + function cbB() end + )"), + LUA_OK); + + lua_getglobal(L, "cbA"); + ASSERT_TRUE(lua_isfunction(L, -1)); + const int refA = luaL_ref(L, LUA_REGISTRYINDEX); + + lua_getglobal(L, "cbB"); + ASSERT_TRUE(lua_isfunction(L, -1)); + const int refB = luaL_ref(L, LUA_REGISTRYINDEX); + + const auto handleA = handler.registerEvent("config.reloaded", refA); + const auto handleB = handler.registerEvent("config.reloaded", refB); + ASSERT_TRUE(handleA.has_value()); + ASSERT_TRUE(handleB.has_value()); + + Objects::CLuaEventSubscription::push(L, &handler, *handleA); + lua_setglobal(L, "sub1"); + + Objects::CLuaEventSubscription::push(L, &handler, *handleA); + lua_setglobal(L, "sub2"); + + Objects::CLuaEventSubscription::push(L, &handler, *handleB); + lua_setglobal(L, "sub3"); + + ASSERT_EQ(luaL_dostring(L, R"( + eq12 = (sub1 == sub2) + neq13 = (sub1 ~= sub3) + + local s = tostring(sub1) + hasPrefix = type(s) == "string" and string.sub(s, 1, 21) == "HL.EventSubscription(" + )"), + LUA_OK); + + EXPECT_TRUE(getGlobalBool(L, "eq12")); + EXPECT_TRUE(getGlobalBool(L, "neq13")); + EXPECT_TRUE(getGlobalBool(L, "hasPrefix")); +} |
