diff --git a/errors.lua b/errors.lua index 5340a15..7fc94e3 100644 --- a/errors.lua +++ b/errors.lua @@ -58,7 +58,7 @@ local function internal_error (self, module_suffix, format_msg, ...) format_msg = format_msg or DEFAULT_ERROR_MSG_NORMAL assert(type(format_msg) == 'string') -- Format - return error(('[%s%s]: '..format_msg):format(self.module_name, module_suffix, ...), 1) + error(('[%s%s]: '..format_msg):format(self.module_name, module_suffix, ...), 3) end local function external_error (self, module_suffix, format_msg, ...) @@ -75,25 +75,27 @@ local function external_error (self, module_suffix, format_msg, ...) level = level + 1 end -- Format - return error(('[%s%s]: '..format_msg):format(self.module_name, module_suffix, ...), 1) + error(('[%s%s]: '..format_msg):format(self.module_name, module_suffix, ...), 1) end -local function correct_error (self, module_suffix, format_msg, gotten_string, possible_strings) +local function correct_error (self, module_suffix, format_msg, gotten_string, possible_strings, lvl) -- correct_error(error_handler, module_suffix [, format_msg], gotten_string, possible_strings) -- Error check assert(type(self) == 'table' and self.is_error_handler) assert(type(module_suffix) == 'string') format_msg = format_msg or DEFAULT_ERROR_MSG_CORRECT + lvl = lvl or 0 assert(type(format_msg) == 'string') assert(type(gotten_string) == 'string') assert(type(possible_strings) == 'table') + assert(type(lvl) == 'number') -- Do stuff local possible_strings = string_dist.strings_with_highest_similarity(gotten_string, possible_strings) local list_string = format_probable_strings(possible_strings, 3) -- Format - return error(('[%s%s]: '..format_msg):format(self.module_name, module_suffix, gotten_string, list_string), 1) + error(('[%s%s]: '..format_msg):format(self.module_name, module_suffix, gotten_string, list_string), lvl + 1) end ---- @@ -180,14 +182,34 @@ return function (module_name) function err_hdl.strict_table (...) local args = {...} if args[1] == err_hdl then table.remove(args, 1) end - return setmetatable(args[1] or {}, { + local t = setmetatable(args[1] or {}, { __index = function (t, k) return handle_index_error(err_hdl, t, k) end }) + return t + end + + local function keys_of_table (t) + local keys = {} + for k in pairs(t) do keys[#keys+1] = k end + table.sort(keys) + return keys + end + + function err_hdl.enable_strict_globals () + setmetatable(getfenv(2), { + __index = function(env, key) + return err_hdl.correct('Attempting to access unknown global: \'%s\'. Perhaps you meant %s?', key, keys_of_table(env), 2) + end, + __newindex = function (env, key, value) + return err_hdl.correct('Attempting to create new global \'%s\' with value: '..tostring(value)..'. Perhaps you misspelled %s?', key, keys_of_table(env), 2) + end + }) end err_hdl.register(format_probable_strings, internal_error, external_error, correct_error, handle_index_error, err_hdl.internal, err_hdl.external, err_hdl.correct, err_hdl.register, err_hdl.strict_table) return err_hdl end + diff --git a/test/test_errors.lua b/test/test_errors.lua index 45acfe0..b81ff12 100644 --- a/test/test_errors.lua +++ b/test/test_errors.lua @@ -9,40 +9,40 @@ SUITE:setEnviroment { SUITE:addTest('Basic error', function() local expected_error = './test/test_errors.lua:'..curline(1)..': [test_errors]: Hello World' - assert_equal(expected_error, select(2, pcall(error, 'Hello World'))) + assert_equal(expected_error, select(2, pcall(function() error 'Hello World' end))) end) SUITE:addTest('Basic formatting', function() local expected_error = './test/test_errors.lua:'..curline(1)..': [test_errors]: Welcome to the Errors' - assert_equal(expected_error, select(2, pcall(error, '%s to the %s', 'Welcome', 'Errors'))) + assert_equal(expected_error, select(2, pcall(function() error('%s to the %s', 'Welcome', 'Errors') end))) end) SUITE:addTest('Default generic error', function() local expected_error = './test/test_errors.lua:'..curline(1)..': [test_errors]: Unknown error occured' - assert_equal(expected_error, select(2, pcall(error))) + assert_equal(expected_error, select(2, pcall(function() error() end))) end) SUITE:addTest('Internal is almost the same as error in itself', function() local expected_error = './test/test_errors.lua:'..curline(1)..': [test_errors/internal]: World Hello' - assert_equal(expected_error, select(2, pcall(error.internal, 'World Hello'))) + assert_equal(expected_error, select(2, pcall(function() error.internal 'World Hello' end))) end) SUITE:addTest('Internal can also be called using object index', function() local expected_error = './test/test_errors.lua:'..curline(1)..': [test_errors/internal]: André the Giant' - assert_equal(expected_error, select(2, pcall(error.internal, error, 'André the Giant'))) + assert_equal(expected_error, select(2, pcall(function() error:internal 'André the Giant' end))) end) SUITE:addTest('Internal includes the stack', function() local func_a = function() error.internal 'Thomas the Steam Train' end local expected_error = './test/test_errors.lua:'..curline(-1)..': [test_errors/internal]: Thomas the Steam Train' - assert_equal(expected_error, select(2, pcall(func_a))) + assert_equal(expected_error, select(2, pcall(function() func_a() end))) end) SUITE:addTest('Internal includes the stack 2', function() local func_a = function() error.internal 'Thomas the Steam Train' end - local func_b = function() return pcall(func_a) end + local func_b = function() pcall(func_a) end local expected_error = './test/test_errors.lua:'..curline(-2)..': [test_errors/internal]: Thomas the Steam Train' - assert_equal(expected_error, select(2, pcall(func_a))) + assert_equal(expected_error, select(2, pcall(function() func_a() end))) end) -------------------------------------------------------------------------------- @@ -54,7 +54,7 @@ SUITE:addTest('External errors hides the stack', function() error.register(func_a) local expected_error = './test/test_errors.lua:'..curline(-3)..': [test_errors]: Hello World' - assert_equal(expected_error, select(2, pcall(func_b))) + assert_equal(expected_error, select(2, pcall(function() func_b() end))) end) SUITE:addTest('External errors can be triggered deep', function() @@ -64,7 +64,7 @@ SUITE:addTest('External errors can be triggered deep', function() error.register(func_a, func_b) local expected_error = './test/test_errors.lua:'..curline(-3)..': [test_errors]: Hello World' - assert_equal(expected_error, select(2, pcall(func_c))) + assert_equal(expected_error, select(2, pcall(function() func_c() end))) end) SUITE:addTest('Internal errors don\'t hide the stack', function() @@ -74,7 +74,7 @@ SUITE:addTest('Internal errors don\'t hide the stack', function() error.register(func_a, func_b) local expected_error = './test/test_errors.lua:'..curline(-5)..': [test_errors/internal]: Hello World' - assert_equal(expected_error, select(2, pcall(func_c))) + assert_equal(expected_error, select(2, pcall(function() func_c() end))) end) -------------------------------------------------------------------------------- @@ -149,8 +149,34 @@ SUITE:addTest('Strict tables throws error when indexing non-integer in sequence' assert_equal('./test/test_errors.lua:'..curline(-1)..': [test_errors]: Cannot index non-integer 2.5, for sequence with length 4.', msg) end) +-------------------------------------------------------------------------------- +SUITE:addTest('Strict global bad key', function() + local glob = { require = require, print = print } + glob._G = glob + local f = setfenv(function() + print(_G) + local error = require 'errors' 'test_strict_global' + error.enable_strict_globals() + local a = some_global + end, glob) + local _, msg = pcall(f) + assert_equal('./test/test_errors.lua:'..curline(-3)..': [test_strict_global]: Attempting to access unknown global: \'some_global\'. Perhaps you meant _G, require or print?', msg) +end) + +SUITE:addTest('Strict global bad insert', function() + local glob = { require = require } + glob._G = glob + local f = setfenv(function() + local error = require 'errors' 'test_strict_global' + error.enable_strict_globals() + some_global = "hello" + end, glob) + local _, msg = pcall(f) + assert_equal('./test/test_errors.lua:'..curline(-3)..': [test_strict_global]: Attempting to create new global \'some_global\' with value: hello. Perhaps you misspelled _G or require?', msg) +end) -------------------------------------------------------------------------------- return SUITE +