feat(plugins): add debug.traceback (#6652)

Reviewed-by: Mm2PL <mm2pl+gh@kotmisia.pl>
This commit is contained in:
nerix
2025-12-28 13:03:43 +01:00
committed by GitHub
parent a9ab584cbb
commit e2ba7dff03
7 changed files with 178 additions and 22 deletions
+82 -22
View File
@@ -157,6 +157,24 @@ std::string luaTestPath(const QString &category, const QString &entry)
return luaTestBaseDir(category).filePath(entry + ".lua").toStdString();
}
bool runLuaTest(const QString &category, const QString &entry,
sol::state_view lua)
{
auto loadResult = lua.load_file(luaTestPath(category, entry));
auto pfn = loadResult.get<sol::protected_function>();
pfn.set_error_handler(lua["debug"]["traceback"]);
auto pfr = pfn.call();
EXPECT_TRUE(pfr.valid());
if (!pfr.valid())
{
qDebug().noquote() << "Test" << entry << "failed:";
sol::error err = pfr;
qDebug().noquote() << err.what();
return false;
}
return true;
}
} // namespace
namespace chatterino {
@@ -1528,23 +1546,15 @@ TEST_P(PluginJsonTest, Run)
auto reg = lua->registry().size();
auto globals = lua->globals().size();
auto pfr = lua->safe_script_file(luaTestPath("json", GetParam()));
EXPECT_TRUE(pfr.valid());
if (!pfr.valid())
{
qDebug() << "Test" << GetParam() << "failed:";
sol::error err = pfr;
qDebug() << err.what();
return;
}
runLuaTest("json", GetParam(), *this->lua);
for (size_t i = 0; i < 5; i++)
{
lua->collect_garbage();
}
// make sure we don't leak anything to globals or the registry
// but give the registry some room of 1 slot
EXPECT_LE(lua->registry().size(), reg + 1);
// but give the registry some room of 3 slots (two from getting the debug library)
EXPECT_LE(lua->registry().size(), reg + 3);
EXPECT_EQ(lua->globals().size(), globals);
}
@@ -1557,17 +1567,8 @@ class PluginMessageTest : public PluginTest,
};
TEST_P(PluginMessageTest, Run)
{
configure();
auto pfr = lua->safe_script_file(luaTestPath("message", GetParam()));
EXPECT_TRUE(pfr.valid());
if (!pfr.valid())
{
qDebug() << "Test" << GetParam() << "failed:";
sol::error err = pfr;
qDebug() << err.what();
return;
}
this->configure();
runLuaTest("message", GetParam(), *this->lua);
}
INSTANTIATE_TEST_SUITE_P(PluginMessage, PluginMessageTest,
@@ -1593,4 +1594,63 @@ TEST_F(PluginTest, testAccounts)
ASSERT_TRUE(res.valid()) << res.get<sol::error>().what();
}
TEST_F(PluginTest, debugTraceback)
{
configure();
QString traceback = lua->script(R"lua(
local function other()
error("oh no")
end
local function main()
local function inner()
other()
end
inner()
end
local ok, res = xpcall(main, debug.traceback)
return res
)lua")
.get<QString>();
ASSERT_TRUE(traceback.contains("[C]: in function 'error'"));
ASSERT_TRUE(traceback.contains("[string \"...\"]:3: in upvalue 'other'"));
ASSERT_TRUE(traceback.contains("[string \"...\"]:7: in local 'inner'"));
ASSERT_TRUE(traceback.contains(
"[string \"...\"]:9: in function <[string \"...\"]:5>"));
ASSERT_TRUE(traceback.contains("[C]: in function 'xpcall'"));
ASSERT_TRUE(traceback.contains("[string \"...\"]:12: in main chunk"));
traceback = lua->script(R"lua(
return debug.traceback()
)lua")
.get<QString>();
ASSERT_TRUE(traceback.contains("[string \"...\"]:2: in main chunk"));
traceback = lua->script(R"lua(
return debug.traceback("my message")
)lua")
.get<QString>();
ASSERT_TRUE(traceback.contains("my message"));
ASSERT_TRUE(traceback.contains("[string \"...\"]:2: in main chunk"));
traceback = lua->script(R"lua(
local coro = coroutine.create(function ()
coroutine.yield()
end)
coroutine.resume(coro)
return debug.traceback(coro)
)lua")
.get<QString>();
ASSERT_TRUE(traceback.contains("[C]: in function 'coroutine.yield'"));
ASSERT_TRUE(traceback.contains(
"[string \"...\"]:3: in function <[string \"...\"]:2>"));
auto msg = lua->script(R"lua(
return debug.traceback(c2.Message.new({id = "who would do this"}))
)lua")
.get<std::shared_ptr<Message>>();
ASSERT_EQ(msg->id, "who would do this");
}
#endif