diff --git a/Source/LuaBridge/detail/Invoke.h b/Source/LuaBridge/detail/Invoke.h index 41c98c5..25b1122 100644 --- a/Source/LuaBridge/detail/Invoke.h +++ b/Source/LuaBridge/detail/Invoke.h @@ -179,8 +179,14 @@ LuaResult callWithHandler(const LuaRef& object, F&& errorHandler, Args&&... args lua_State* L = object.state(); const int stackTop = lua_gettop(L); + bool isNonNullHandler = isValidHandler; if constexpr (isValidHandler) - detail::push_function(L, std::forward(errorHandler), ""); // Stack: error handler (eh) + { + if constexpr (std::is_pointer_v> || std::is_same_v, std::function>) + isNonNullHandler = errorHandler != nullptr; + if (isNonNullHandler) + detail::push_function(L, std::forward(errorHandler), ""); // Stack: error handler (eh) + } object.push(); // Stack: eh, ref @@ -193,17 +199,14 @@ LuaResult callWithHandler(const LuaRef& object, F&& errorHandler, Args&&... args } } - const int code = lua_pcall(L, sizeof...(Args), LUA_MULTRET, isValidHandler ? (-static_cast(sizeof...(Args)) - 2) : 0); + const int code = lua_pcall(L, sizeof...(Args), LUA_MULTRET, isNonNullHandler ? (-static_cast(sizeof...(Args)) - 2) : 0); if (code != LUABRIDGE_LUA_OK) { auto ec = makeErrorCode(ErrorCode::LuaFunctionCallFailed); #if LUABRIDGE_HAS_EXCEPTIONS - if constexpr (! isValidHandler) - { - if (LuaException::areExceptionsEnabled(L)) - LuaException::raise(L, ec); - } + if (LuaException::areExceptionsEnabled(L)) + LuaException::raise(L, ec); #endif return LuaResult::errorFromStack(L, ec); diff --git a/Tests/Source/LuaRefTests.cpp b/Tests/Source/LuaRefTests.cpp index 62d4cbf..18b72f7 100644 --- a/Tests/Source/LuaRefTests.cpp +++ b/Tests/Source/LuaRefTests.cpp @@ -8,6 +8,7 @@ #include "TestBase.h" #include +#include struct LuaRefTests : TestBase { @@ -534,12 +535,68 @@ TEST_F(LuaRefTests, CallableWithHandler) return 0; }; - auto result = f.callWithHandler(handler, "badly"); - EXPECT_FALSE(result); +#if LUABRIDGE_HAS_EXCEPTIONS + EXPECT_ANY_THROW(f.callWithHandler(handler, "badly")); +#else + EXPECT_FALSE(f.callWithHandler(handler, "badly")); +#endif EXPECT_TRUE(calledHandler); EXPECT_TRUE(errorMessage.find("we failed badly") != std::string::npos); } +TEST_F(LuaRefTests, CallableWithStdFunction) +{ + runLua("function f(x) error('we failed ' .. x) end"); + auto f = luabridge::getGlobal(L, "f"); + EXPECT_TRUE(f.isCallable()); + + bool calledHandler = false; + std::string errorMessage; + auto handler = [&](lua_State*) -> int + { + calledHandler = true; + + if (auto msg = lua_tostring(L, 1)) + errorMessage = msg; + + return 0; + }; + std::function pHandler = handler; + +#if LUABRIDGE_HAS_EXCEPTIONS + EXPECT_ANY_THROW(f.callWithHandler(pHandler, "badly")); +#else + EXPECT_FALSE(f.callWithHandler(pHandler, "badly")); +#endif + EXPECT_TRUE(calledHandler); + EXPECT_TRUE(errorMessage.find("we failed badly") != std::string::npos); + + calledHandler = false; + errorMessage = ""; + pHandler = nullptr; +#if LUABRIDGE_HAS_EXCEPTIONS + EXPECT_ANY_THROW(f.callWithHandler(pHandler, "badly")); +#else + EXPECT_FALSE(f.callWithHandler(pHandler, "badly")); +#endif + EXPECT_FALSE(calledHandler); + EXPECT_FALSE(errorMessage.find("we failed badly") != std::string::npos); +} + +TEST_F(LuaRefTests, CallableWithNullCFunction) +{ + runLua("function f(x) error('we failed ' .. x) end"); + auto f = luabridge::getGlobal(L, "f"); + EXPECT_TRUE(f.isCallable()); + + lua_CFunction pHandler = nullptr; +#if LUABRIDGE_HAS_EXCEPTIONS + EXPECT_ANY_THROW(f.callWithHandler(pHandler, "badly")); +#else + EXPECT_FALSE(f.callWithHandler(pHandler, "badly")); +#endif +} + TEST_F(LuaRefTests, Pop) { lua_pushstring(L, "hello");