forked from nodemcu/nodemcu-firmware
/
gambiarra.lua
176 lines (158 loc) · 4.21 KB
/
gambiarra.lua
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
local function TERMINAL_HANDLER(e, test, msg, errormsg)
if errormsg then
errormsg = ": "..errormsg
else
errormsg = ""
end
if e == 'pass' then
print(" "..e.." "..test..': '..msg)
elseif e == 'fail' then
print(" ==> "..e.." "..test..': '..msg..errormsg)
elseif e == 'except' then
print(" ==> "..e.." "..test..': '..msg..errormsg)
else
print(e.." "..test)
end
end
local function deepeq(a, b)
-- Different types: false
if type(a) ~= type(b) then return {false, "type 1 is "..type(a)..", type 2 is "..type(b)} end
-- Functions
if type(a) == 'function' then
return string.dump(a) == string.dump(b)
end
-- Primitives and equal pointers
if a == b then return true end
-- Only equal tables could have passed previous tests
if type(a) ~= 'table' then return false end
-- Compare tables field by field
for k,v in pairs(a) do
if b[k] == nil or not deepeq(v, b[k]) then return false end
end
for k,v in pairs(b) do
if a[k] == nil or not deepeq(v, a[k]) then return false end
end
return true
end
-- Compatibility for Lua 5.1 and Lua 5.2
local function args(...)
return {n=select('#', ...), ...}
end
local function spy(f)
local s = {}
setmetatable(s, {__call = function(s, ...)
s.called = s.called or {}
local a = args(...)
table.insert(s.called, {...})
if f then
local r
r = args(pcall(f, (unpack or table.unpack)(a, 1, a.n)))
if not r[1] then
s.errors = s.errors or {}
s.errors[#s.called] = r[2]
else
return (unpack or table.unpack)(r, 2, r.n)
end
end
end})
return s
end
local function assertok(handler, name, cond, msg)
if not msg then
-- debug.getinfo() does not exist in NodeMCU
-- msg = debug.getinfo(2, 'S').short_src..":"..debug.getinfo(2, 'l').currentline
msg = debug.traceback()
msg = msg:match("\n[^\n]*\n[^\n]*\n[^\n]*\n\t*([^\n]*): in")
end
local errormsg
if type(cond) == "table" then
errormsg = cond[2]
cond = cond[1]
end
if cond then
handler('pass', name, msg, errormsg)
else
handler('fail', name, msg, errormsg)
end
end
local function fail(handler, name, func, expected, msg)
local status, err = pcall(func)
if status then
local messagePart = ""
if expected then
messagePart = " containing \"" .. expected .. "\""
end
handler('fail', name, msg, "Expected to fail with Error" .. messagePart)
return
end
if (expected and not string.find(err, expected)) then
handler('fail', name, msg, "expected errormessage \"" .. err .. "\" to contain \"" .. expected .. "\"")
return
end
handler('pass', name, msg)
end
local pendingtests = {}
local env = _G
local gambiarrahandler = TERMINAL_HANDLER
local shimhandler
do
local ok
ok, shimhandler = pcall(require,"shim_gambiarra")
if not ok then shimhandler = nil end
end
local function runpending()
if pendingtests[1] ~= nil then pendingtests[1](runpending) end
end
local function copyenv(dest, src)
dest.eq = src.eq
dest.spy = src.spy
dest.ok = src.ok
dest.nok = src.nok
dest.fail = src.fail
end
return function(name, f, async)
if type(name) == 'function' then
gambiarrahandler = name
env = f or _G
return
end
local testfn = function(next)
local prev = {}
copyenv(prev, env)
local restore = function()
copyenv(env, prev)
gambiarrahandler('end', name)
table.remove(pendingtests, 1)
if next then next() end
end
local handler = function(...)
gambiarrahandler(...)
if shimhandler then shimhandler(...) end
end
local function wrap(f, ...)
f(handler, name, ...)
end
env.eq = deepeq
env.spy = spy
env.ok = function (cond, msg) wrap(assertok, cond, msg) end
env.nok = function(cond, msg) env.ok(not cond, msg) end
env.fail = function (func, expected, msg) wrap(fail, func, expected, msg) end
handler('begin', name);
local ok, err = pcall(f, restore)
if not ok then
handler('except', name, err)
end
if not async then
handler('end', name);
copyenv(env, prev)
end
end
if not async then
testfn()
else
table.insert(pendingtests, testfn)
if #pendingtests == 1 then
runpending()
end
end
end