diff --git a/CHANGELOG.md b/CHANGELOG.md index 4326148..e0ab94b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +- Implemented verbose serialization of uncaught box errors thrown in tests + (gh-445). - Fixed a bug when errors reported by the address sanitizer during process termination were ignored (gh-460). diff --git a/luatest/assertions.lua b/luatest/assertions.lua index 66f49d5..08b8ae3 100644 --- a/luatest/assertions.lua +++ b/luatest/assertions.lua @@ -13,7 +13,6 @@ local log = require('luatest.log') local utils = require('luatest.utils') local tarantool = require('tarantool') local fio = require('fio') -local ffi = require('ffi') local prettystr = pp.tostring local prettystr_pairs = pp.tostring_pair @@ -22,8 +21,6 @@ local M = {} local xfail = false -local box_error_type = ffi.typeof(box.error.new(box.error.UNKNOWN)) - -- private exported functions (for testing) M.private = {} @@ -159,7 +156,7 @@ local function pcall_check_trace(level, fn, ...) if ok then return ok, err end - if type(err) ~= 'cdata' or ffi.typeof(err) ~= box_error_type then + if not utils.is_box_error(err) then fail_fmt(level + 1, nil, 'Error raised is not a box.error: %s', prettystr(err)) end @@ -704,21 +701,6 @@ function M.assert_error_msg_matches(pattern, fn, ...) end end --- If it is box.error that unpack it recursively. If it is not then --- return argument unchanged. -local function error_unpack(err) - if type(err) ~= 'cdata' or ffi.typeof(err) ~= box_error_type then - return err - end - local unpacked = err:unpack() - local tmp = unpacked - while tmp.prev ~= nil do - tmp.prev = tmp.prev:unpack() - tmp = tmp.prev - end - return unpacked -end - --- Checks that error raised by function is table that includes expected one. --- box.error is unpacked to convert to table. Stacked errors are supported. --- That is if there is prev field in expected then it should cover prev field @@ -734,7 +716,7 @@ function M.assert_error_covers(expected, fn, ...) 'Function successfully returned: %s\nExpected error: %s', prettystr(actual), prettystr(expected)) end - local unpacked = error_unpack(actual) + local unpacked = utils.error_unpack(actual) if not comparator.equals(table_slice(unpacked, expected), expected) then actual, expected = prettystr_pairs(unpacked, expected) fail_fmt(2, nil, 'Error expected: %s\nError received: %s', diff --git a/luatest/pp.lua b/luatest/pp.lua index eeeb226..ab5b181 100644 --- a/luatest/pp.lua +++ b/luatest/pp.lua @@ -1,5 +1,6 @@ local Class = require('luatest.class') local sorted_pairs = require('luatest.sorted_pairs') +local utils = require('luatest.utils') -- Pretty printer. local pp = { @@ -160,6 +161,8 @@ function Formatter.mt:format(v, indentLevel) return tostring(i) end end + elseif utils.is_box_error(v) then + return self:format_table(utils.error_unpack(v), indentLevel) end return tostring(v) diff --git a/luatest/utils.lua b/luatest/utils.lua index b03839e..7ceb3af 100644 --- a/luatest/utils.lua +++ b/luatest/utils.lua @@ -1,10 +1,13 @@ local digest = require('digest') +local ffi = require('ffi') local fio = require('fio') local fun = require('fun') local yaml = require('yaml') local utils = {} +local box_error_type = ffi.typeof(box.error.new(box.error.UNKNOWN)) + -- Helper to override methods. -- -- utils.patch(target, 'method_name', function(super) return function(...) @@ -251,4 +254,23 @@ function utils.table_is_array(t) return true end +function utils.is_box_error(err) + return type(err) == 'cdata' and ffi.typeof(err) == box_error_type +end + +-- If it is box.error that unpack it recursively. If it is not then +-- return argument unchanged. +function utils.error_unpack(err) + if not utils.is_box_error(err) then + return err + end + local unpacked = err:unpack() + local tmp = unpacked + while tmp.prev ~= nil do + tmp.prev = tmp.prev:unpack() + tmp = tmp.prev + end + return unpacked +end + return utils diff --git a/test/pp_test.lua b/test/pp_test.lua index e703b6f..55ec6e5 100644 --- a/test/pp_test.lua +++ b/test/pp_test.lua @@ -31,3 +31,11 @@ g.test_tostring_huge_table = function() t.assert_equals(result, 0) t.assert_almost_equals(clock.time() - start, 0, 0.5) end + +g.test_tostring_box_error = function() + local s = pp.tostring(box.error.new({ + type = 'MyError', reason = 'FOOBAR', + })) + t.assert_str_contains(s, 'type = "MyError"') + t.assert_str_contains(s, 'message = "FOOBAR"') +end diff --git a/test/utils_test.lua b/test/utils_test.lua index 0c45122..1760a99 100644 --- a/test/utils_test.lua +++ b/test/utils_test.lua @@ -30,3 +30,16 @@ g.test_table_pack = function() t.assert_equals(utils.table_pack(1, 2, nil), {n = 3, 1, 2}) t.assert_equals(utils.table_pack(1, 2, nil, 3), {n = 4, 1, 2, nil, 3}) end + +g.test_box_error = function() + local err = 'FOOBAR' + t.assert_not(utils.is_box_error(err)) + t.assert_equals(utils.error_unpack(err), err) + err = box.error.new({type = 'MyError', reason = 'FOOBAR'}) + err:set_prev(box.error.new({type = 'MyError2', reason = 'FUZZ'})) + t.assert(utils.is_box_error(err)) + t.assert_covers(utils.error_unpack(err), { + type = 'MyError', message = 'FOOBAR', + prev = {type = 'MyError2', message = 'FUZZ'} + }) +end