--- `assert_` macro library support. -- This module may of course be used on its own; `assert_` merely provides -- some syntactical sugar for its functionality. It is based on Penlight's -- `pl.test` module. -- @module macro.libs.test local test = {} local _eq,_tostring -- very much like tablex.deepcompare from Penlight function _eq (v1,v2) if type(v1) ~= type(v2) then return false end -- if the value isn't a table, or it has defined the equality operator.. local mt = getmetatable(v1) if (mt and mt.__eq) or type(v1) ~= 'table' then return v1 == v2 end -- both values are plain tables if v1 == v2 then return true end -- they were the same table... for k1,x1 in pairs(v1) do local x2 = v2[k1] if x2 == nil or not _eq(x1,x2) then return false end end for k2,x2 in pairs(v2) do local x1 = v1[k2] if x1 == nil or not _eq(x1,x2) then return false end end return true end local function keyv (k) if type(k) ~= 'string' then k = '['..k..']' end return k end function _tostring (val) local mt = getmetatable(val) if (mt and mt.__tostring) or type(val) ~= 'table' then if type(val) == 'string' then return '"'..tostring(val)..'"' else return tostring(val) end end -- dump the table; doesn't need to be pretty! local res = {} local function put(s) res[#res+1] = s end put '{' for k,v in pairs(val) do put(keyv(k)..'=') put(_tostring(v)) put ',' end table.remove(res) -- remove last ',' put '}' return table.concat(res) end local function _lt (v1,v2) return v1 < v2 end local function _gt (v1,v2) return v1 > v2 end local function _match (v1,v2) return v1:match(v2) end local function _assert (v1,v2,cmp,msg) if not cmp(v1,v2) then print('first:',_tostring(v1)) print(msg) print('second:',_tostring(v2)) error('assertion failed',3) end end --- assert if parameters are not equal. If the values are tables, -- they will be compared by value. -- @param v1 given value -- @param v2 test value function test.assert_eq (v1,v2) _assert(v1,v2,_eq,"is not equal to"); end --- assert if first parameter is not less than second. -- @param v1 given value -- @param v2 test value function test.assert_lt (v1,v2) _assert(v1,v2,_lt,"is not less than") end --- assert if first parameter is not greater than second. -- @param v1 given value -- @param v2 test value function test.assert_gt (v1,v2) _assert(v1,v2,_gt,"is not greater than") end --- assert if first parameter string does not match the second. -- The condition is `v1:match(v2)`. -- @param v1 given value -- @param v2 test value function test.assert_match (v1,v2) _assert(v1,v2,_match,"does not match") end -- return the error message from a function that raises an error. -- Will raise an error if the function did not raise an error. -- @param fun the function -- @param ... any arguments to the function -- @return the error message function test.pcall_no(fun,...) local ok,err = pcall(fun,...) if ok then error('expression did not throw error',3) end return err end local tuple = {} function tuple.__eq (a,b) if a.n ~= b.n then return false end for i=1, a.n do if not _eq(a[i],b[i]) then return false end end return true end function tuple.__tostring (self) local ts = {} for i = 1,self.n do ts[i] = _tostring(self[i]) end return '('..table.concat(ts,',')..')' end --- create a tuple capturing multiple return values. -- Equality between tuples means that all of their values are equal; -- values may be `nil` -- @param ... any values -- @return a tuple object function test.tuple(...) return setmetatable({n=select('#',...),...},tuple) end return test