- Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathassert.lua
More file actions
Latest commit
195 lines (177 loc) · 5.62 KB
/
Copy pathassert.lua
File metadata and controls
195 lines (177 loc) · 5.62 KB
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
--[[
the original assert() asserts that the first arg is true, and returns all args, therefore we can assert that the first returned value will also always coerce to true
1) should asserts always return a true value?
2) or should asserts always return the forwarded value?
I'm voting for #2 so assert can be used for wrapping args and not changing behvaior. when would you need to assert the first arg is true afer the assert has already bene carried out anyways?
... except for certain specified operations that cannot return their first argument, like assertindex()
--]]
-- cheap 'tolua'
localfunctiontostr(x)
--[[ just tostring
return tostring(x)
--]]
--[[ also quotes to help distinguish strings-of-numbers from numbers
if type(x) == 'string' then return ('%q'):format(x) end
return tostring(x)
--]]
--[[ full-on lua serialization ... might have trouble with cdata, especially cdata-primitives
return require 'ext.tolua'(x)
--]]
-- [[ lua type and value
returntype(x)..'('..tostring(x)..')'
--]]
end
localfunctionprependmsg(msg, str)
iftype(msg) =='number' then
msg=tostring(msg)
end
iftype(msg) =='nil' then
returnstr
end
iftype(msg) =='string' then
returnmsg..': '..str
end
-- not implicitly converted to string -- return as is without message
returnmsg
end
localfunctionasserttype(x, t, msg, ...)
localxt=type(x)
ifxt~=tthen
error(prependmsg(msg, "expected "..tostring(t).." found "..tostring(xt)))
end
returnx, t, msg, ...
end
localfunctionassertis(obj, cl, msg, ...)
ifnotcl.isathen
error(prependmsg(msg, "assertis expected 2nd arg to be a class"))
end
ifnotcl:isa(obj) then
error(prependmsg(msg, "object "..tostring(obj).." is not of class "..tostring(cl)))
end
returnobj, cl, msg, ...
end
-- how to specify varargs...
-- for now: (msg, N, type1, ..., typeN, arg1, ..., argN)
localfunctionasserttypes(msg, n, ...)
asserttype(n, 'number', prependmsg(msg, "asserttypes number of args"))
fori=1,ndo
asserttype(select(n+i, ...), select(i, ...), prependmsg(msg, "asserttypes arg "..i))
end
returnselect(n+1, ...)
end
localfunctionasserteq(a, b, msg, ...)
ifnot (a==b) then
error(prependmsg(msg, "expected "..tostr(a).." == "..tostr(b)))
end
returna, b, msg, ...
end
localfunctionasserteqeps(a, b, eps, msg, ...)
eps=epsor1e-7
localnormval=math.abs(a-b)
ifnormval>epsthen
error((msgandmsg..': ' or'').."expected |"..tostr(a).." - "..tostr(b).."| <= "..eps..' but found norm to be '..tostr(normval))
end
returna, b, eps, msg, ...
end
localfunctionabsdiff(a,b) returnmath.abs(a-b) end
localfunctionasserteqepsnorm(a, b, eps, norm, msg, ...)
eps=epsor1e-7
norm=normorabsdiff
localnormval=norm(a, b)
ifnormval>epsthen
error((msgandmsg..': ' or'').."expected |"..tostr(a)..", "..tostr(b).."| <= "..eps..' but found norm to be '..tostr(normval))
end
returna, b, eps, norm, msg, ...
end
localfunctionassertne(a, b, msg, ...)
ifnot (a~=b) then
error(prependmsg(msg, "expected "..tostr(a).." ~= "..tostr(b)))
end
returna, b, msg, ...
end
localfunctionassertlt(a, b, msg, ...)
ifnot (a<b) then
error(prependmsg(msg, "expected "..tostr(a).." < "..tostr(b)))
end
returna, b, msg, ...
end
localfunctionassertle(a, b, msg, ...)
ifnot (a<=b) then
error(prependmsg(msg, "expected "..tostr(a).." <= "..tostr(b)))
end
returna, b, msg, ...
end
localfunctionassertgt(a, b, msg, ...)
ifnot (a>b) then
error(prependmsg(msg, "expected "..tostr(a).." > "..tostr(b)))
end
returna, b, msg, ...
end
localfunctionassertge(a, b, msg, ...)
ifnot (a>=b) then
error(prependmsg(msg, "expected "..tostr(a).." >= "..tostr(b)))
end
returna, b, msg, ...
end
-- this is a t[k] operation + assert
localfunctionassertindex(t, k, msg, ...)
ifnottthen
error(prependmsg(msg, "object is nil"))
end
localv=t[k]
ifnotvthen
error(prependmsg(msg, "expected "..tostr(t).."["..tostr(k).." ]"))
end
returnv, msg, ...
end
-- assert integer indexes 1 to len, and len of tables matches
-- maybe I'll use ipairs... maybe
localfunctionasserttableieq(t1, t2, msg, ...)
asserteq(#t1, #t2, msg)
fori=1,#t1do
asserteq(t1[i], t2[i], msg)
end
returnt1, t2, msg, ...
end
-- for when you want to assert a table's length but still want to return the table
-- TODO should this be like assertindex() where it performs the operation and returns the operator value, i.e. returns the length instead of the table?
-- or would that be less usable than asserting the length and returning the table?
localfunctionassertlen(t, n, msg, ...)
asserteq(#t, n, msg)
returnt, n, msg, ...
end
localfunctionasserterror(f, msg, ...)
localresult, errmsg=pcall(f, ...)
asserteq(result, false, prependmsg(prependmsg(msg, errmsg), 'asserterror'))
-- I'd like to forward all arguments like every assert above
--return f, msg, ...
-- but by its nature, "asserterror" means "we expect a discontinuity in execution from this code"
-- and the calling code wants to see the resulting error information
-- and since I already error'd if no error was found,
-- then we already know the pcall's result at this point is false
-- so I'll do this:
returnerrmsg
end
localorigassert=_G.assert
returnsetmetatable({
type=asserttype,
types=asserttypes,
is=assertis,
eq=asserteq,
ne=assertne,
lt=assertlt,
le=assertle,
gt=assertgt,
ge=assertge,
index=assertindex,
eqeps=asserteqeps,
eqepsnorm=asserteqepsnorm,
tableieq=asserttableieq,
len=assertlen,
error=asserterror,
}, {
-- default `assert = require 'ext.assert'` works, as well as `assertle = assert.le`
__call=function(t, ...)
returnorigassert(...)
end,
})