1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
--- `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
|