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
|
-- See Copyright Notice in the file LICENSE
module (..., package.seeall)
-- arrays: deep comparison
function eq (t1, t2, lut)
if t1 == t2 then return true end
if type(t1) ~= "table" or type(t2) ~= "table" or #t1 ~= #t2 then
return false
end
lut = lut or {} -- look-up table: are these 2 arrays already compared?
lut[t1] = lut[t1] or {}
if lut[t1][t2] then return true end
lut[t2] = lut[t2] or {}
lut[t1][t2], lut[t2][t1] = true, true
for k,v in ipairs (t1) do
if not eq (t2[k], v, lut) then return false end -- recursion
end
return true
end
NT = {} -- a unique "nil table", to be used instead of nils in datasets
-- pack vararg in table, replacing nils with "NT" table
local function packNT (...)
local t = {}
for i=1, select ("#", ...) do
local v = select (i, ...)
t[i] = (v == nil) and NT or v
end
return t
end
-- unpack table into vararg, replacing "NT" items with nils
local function unpackNT (t)
local len = #t
local function unpack_from (i)
local v = t[i]
if v == NT then v = nil end
if i == len then return v end
return v, unpack_from (i+1)
end
if len > 0 then return unpack_from (1) end
end
-- print results (deep into arrays)
function print_results (val, indent, lut)
indent = indent or ""
lut = lut or {} -- look-up table
local str = tostring (val)
if type (val) == "table" then
if val == NT then
print (indent .. "nil")
elseif lut[val] then
print (indent .. str)
else
lut[val] = true
print (indent .. str)
for i,v in ipairs (val) do
print_results (v, " " .. indent, lut) -- recursion
end
end
else
print (indent .. str)
end
end
-- returns:
-- 1) true, if success; false, if failure
-- 2) test results table or error_message
function test_function (test, func)
local res
local t = packNT (pcall (func, unpackNT (test[1])))
if t[1] then
table.remove (t, 1)
res = t
else
res = t[2] --> error_message
end
local how = (type (res) == type (test[2])) and
(type (res) == "string" or eq (res, test[2])) -- allow error messages to differ
return how, res
end
-- returns:
-- 1) true, if success; false, if failure
-- 2) test results table or error_message
-- 3) test results table or error_message
function test_method (test, constructor, name)
local res1, res2
local ok, r = pcall (constructor, unpackNT (test[1]))
if ok then
local t = packNT (pcall (r[name], r, unpackNT (test[2])))
if t[1] then
table.remove (t, 1)
res1, res2 = t
else
res1, res2 = 2, t[2] --> 2, error_message
end
else
res1, res2 = 1, r --> 1, error_message
end
return eq (res1, test[3]), res1, res2
end
-- returns: a list of failed tests
function test_set (set, lib)
local list = {}
if type (set.Func) == "function" then
local func = set.Func
for i,test in ipairs (set) do
local ok, res = test_function (test, func)
if not ok then
table.insert (list, {i=i, res})
end
end
elseif type (set.Method) == "string" then
for i,test in ipairs (set) do
local ok, res1, res2 = test_method (test, lib.new, set.Method)
if not ok then
table.insert (list, {i=i, res1, res2})
end
end
else
error ("neither set.Func nor set.Method is valid")
end
return list
end
|