Add lua exception handling test code 1579/head
authorsapier <Sapier at GMX dot net>
Sat, 23 Aug 2014 11:24:37 +0000 (13:24 +0200)
committersapier <Sapier at GMX dot net>
Sat, 23 Aug 2014 18:53:34 +0000 (20:53 +0200)
Catch some error situations when mod used without thinking about it

games/minimal/mods/errorhandler_test/init.lua [new file with mode: 0644]
src/script/lua_api/l_server.cpp
src/script/lua_api/l_server.h

diff --git a/games/minimal/mods/errorhandler_test/init.lua b/games/minimal/mods/errorhandler_test/init.lua
new file mode 100644 (file)
index 0000000..9d1535c
--- /dev/null
@@ -0,0 +1,106 @@
+--
+-- exception handler test module
+--
+--
+-- To avoid this from crashing the module will startup in inactive mode.
+-- to make specific errors happen you need to cause them by following
+-- chat command:
+--
+-- exceptiontest <location> <errortype>
+--
+-- location has to be one of:
+--   * mapgen:          cause in next on_generate call
+--   * entity_step:     spawn a entity and make it do error in on_step
+--   * globalstep:      do error in next globalstep
+--   * immediate:       cause right in chat handler
+--
+-- errortypes defined are:
+--   * segv:            make sigsegv happen
+--   * zerodivision:    cause a division by zero to happen
+--   * exception:       throw an exception
+
+if core.cause_error == nil or
+       type(core.cause_error) ~= "function" then
+       return
+end
+       
+
+core.log("action", "WARNING: loading exception handler test module!")
+
+local exceptiondata = {
+       tocause = "none",
+       mapgen = false,
+       entity_step = false,
+       globalstep = false,
+}
+
+local exception_entity =
+{
+       on_step = function(self, dtime)
+               if exceptiondata.entity_step then
+                       core.cause_error(exceptiondata.tocause)
+               end
+       end,
+}
+local exception_entity_name = "errorhandler_test:error_entity"
+
+local function exception_chat_handler(playername, param)
+       local parameters = param:split(" ")
+       
+       if #parameters ~= 2 then
+               core.chat_send_player(playername, "Invalid argument count for exceptiontest")
+       end
+       
+       core.log("error", "Causing error at:" .. parameters[1])
+       
+       if parameters[1] == "mapgen" then
+               exceptiondata.tocause = parameters[2]
+               exceptiondata.mapgen = true
+       elseif parameters[1] == "entity_step" then
+               --spawn entity at player location
+               local player = core.get_player_by_name(playername)
+               
+               if player:is_player() then
+                       local pos = player:getpos()
+                       
+                       core.add_entity(pos, exception_entity_name)
+               end
+               
+               exceptiondata.tocause = parameters[2]
+               exceptiondata.entity_step = true
+               
+       elseif parameters[1] == "globalstep" then
+               exceptiondata.tocause = parameters[2]
+               exceptiondata.globalstep = true
+               
+       elseif parameters[1] == "immediate" then
+               core.cause_error(parameters[2])
+               
+       else
+               core.chat_send_player(playername, "Invalid error location: " .. dump(parameters[1]))
+       end
+end
+
+core.register_chatcommand("exceptiontest",
+       {
+               params      = "<location> <errortype>",
+               description = "cause a given error to happen.\n" ..
+                               " location=(mapgen,entity_step,globalstep,immediate)\n" ..
+                               " errortype=(segv,zerodivision,exception)",
+               func        = exception_chat_handler,
+               privs       = { server=true }
+       })
+       
+core.register_globalstep(function(dtime)
+       if exceptiondata.globalstep then
+               core.cause_error(exceptiondata.tocause)
+       end
+end)
+
+core.register_on_generated(function(minp, maxp, blockseed)
+       if exceptiondata.mapgen then
+               core.cause_error(exceptiondata.tocause)
+       end
+end)
+
+core.register_entity(exception_entity_name, exception_entity)
index 76fe439eb87c659be1d0f235b66b6188b05929ae..8d7f6512e1cbc695ca20e1a51ac04987b7b38c88 100644 (file)
@@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "server.h"
 #include "environment.h"
 #include "player.h"
+#include "log.h"
 
 // request_shutdown()
 int ModApiServer::l_request_shutdown(lua_State *L)
@@ -449,6 +450,36 @@ int ModApiServer::l_notify_authentication_modified(lua_State *L)
        return 0;
 }
 
+#ifndef NDEBUG
+// cause_error(type_of_error)
+int ModApiServer::l_cause_error(lua_State *L)
+{
+       NO_MAP_LOCK_REQUIRED;
+       std::string type_of_error = "none";
+       if(lua_isstring(L, 1))
+               type_of_error = lua_tostring(L, 1);
+
+       errorstream << "Error handler test called, errortype=" << type_of_error << std::endl;
+
+       if(type_of_error == "segv") {
+               volatile int* some_pointer = 0;
+               errorstream << "Cause a sigsegv now: " << (*some_pointer) << std::endl;
+
+       } else if (type_of_error == "zerodivision") {
+
+               unsigned int some_number = porting::getTimeS();
+               unsigned int zerovalue = 0;
+               unsigned int result = some_number / zerovalue;
+               errorstream << "Well this shouldn't ever be shown: " << result << std::endl;
+
+       } else if (type_of_error == "exception") {
+               throw BaseException("Errorhandler test fct called");
+       }
+
+       return 0;
+}
+#endif
+
 void ModApiServer::Initialize(lua_State *L, int top)
 {
        API_FCT(request_shutdown);
@@ -475,4 +506,8 @@ void ModApiServer::Initialize(lua_State *L, int top)
        API_FCT(kick_player);
        API_FCT(unban_player_or_ip);
        API_FCT(notify_authentication_modified);
+
+#ifndef NDEBUG
+       API_FCT(cause_error);
+#endif
 }
index 4101f2856a7cdcccb7ab93c06ecccd941b3e6bb6..fd85a897505d8006c395cdfedc462faa538040bf 100644 (file)
@@ -88,6 +88,11 @@ private:
        // notify_authentication_modified(name)
        static int l_notify_authentication_modified(lua_State *L);
 
+#ifndef NDEBUG
+       //  cause_error(type_of_error)
+       static int l_cause_error(lua_State *L);
+#endif
+
 public:
        static void Initialize(lua_State *L, int top);