1print('testing metatables')
2
3X = 20; B = 30
4
5setfenv(1, setmetatable({}, {__index=_G}))
6
7collectgarbage()
8
9X = X+10
10assert(X == 30 and _G.X == 20)
11B = false
12assert(B == false)
13B = nil
14assert(B == 30)
15
16assert(getmetatable{} == nil)
17assert(getmetatable(4) == nil)
18assert(getmetatable(nil) == nil)
19a={}; setmetatable(a, {__metatable = "xuxu",
20                    __tostring=function(x) return x.name end})
21assert(getmetatable(a) == "xuxu")
22assert(tostring(a) == nil)
23-- cannot change a protected metatable
24assert(pcall(setmetatable, a, {}) == false)
25a.name = "gororoba"
26assert(tostring(a) == "gororoba")
27
28local a, t = {10,20,30; x="10", y="20"}, {}
29assert(setmetatable(a,t) == a)
30assert(getmetatable(a) == t)
31assert(setmetatable(a,nil) == a)
32assert(getmetatable(a) == nil)
33assert(setmetatable(a,t) == a)
34
35
36function f (t, i, e)
37  assert(not e)
38  local p = rawget(t, "parent")
39  return (p and p[i]+3), "dummy return"
40end
41
42t.__index = f
43
44a.parent = {z=25, x=12, [4] = 24}
45assert(a[1] == 10 and a.z == 28 and a[4] == 27 and a.x == "10")
46
47collectgarbage()
48
49a = setmetatable({}, t)
50function f(t, i, v) rawset(t, i, v-3) end
51t.__newindex = f
52a[1] = 30; a.x = "101"; a[5] = 200
53assert(a[1] == 27 and a.x == 98 and a[5] == 197)
54
55
56local c = {}
57a = setmetatable({}, t)
58t.__newindex = c
59a[1] = 10; a[2] = 20; a[3] = 90
60assert(c[1] == 10 and c[2] == 20 and c[3] == 90)
61
62
63do
64  local a;
65  a = setmetatable({}, {__index = setmetatable({},
66                     {__index = setmetatable({},
67                     {__index = function (_,n) return a[n-3]+4, "lixo" end})})})
68  a[0] = 20
69  for i=0,10 do
70    assert(a[i*3] == 20 + i*4)
71  end
72end
73
74
75do  -- newindex
76  local foi
77  local a = {}
78  for i=1,10 do a[i] = 0; a['a'..i] = 0; end
79  setmetatable(a, {__newindex = function (t,k,v) foi=true; rawset(t,k,v) end})
80  foi = false; a[1]=0; assert(not foi)
81  foi = false; a['a1']=0; assert(not foi)
82  foi = false; a['a11']=0; assert(foi)
83  foi = false; a[11]=0; assert(foi)
84  foi = false; a[1]=nil; assert(not foi)
85  foi = false; a[1]=nil; assert(foi)
86end
87
88
89function f (t, ...) return t, {...} end
90t.__call = f
91
92do
93  local x,y = a(unpack{'a', 1})
94  assert(x==a and y[1]=='a' and y[2]==1 and y[3]==nil)
95  x,y = a()
96  assert(x==a and y[1]==nil)
97end
98
99
100local b = setmetatable({}, t)
101setmetatable(b,t)
102
103function f(op)
104  return function (...) cap = {[0] = op, ...} ; return (...) end
105end
106t.__add = f("add")
107t.__sub = f("sub")
108t.__mul = f("mul")
109t.__div = f("div")
110t.__mod = f("mod")
111t.__unm = f("unm")
112t.__pow = f("pow")
113
114assert(b+5 == b)
115assert(cap[0] == "add" and cap[1] == b and cap[2] == 5 and cap[3]==nil)
116assert(b+'5' == b)
117assert(cap[0] == "add" and cap[1] == b and cap[2] == '5' and cap[3]==nil)
118assert(5+b == 5)
119assert(cap[0] == "add" and cap[1] == 5 and cap[2] == b and cap[3]==nil)
120assert('5'+b == '5')
121assert(cap[0] == "add" and cap[1] == '5' and cap[2] == b and cap[3]==nil)
122b=b-3; assert(getmetatable(b) == t)
123assert(5-a == 5)
124assert(cap[0] == "sub" and cap[1] == 5 and cap[2] == a and cap[3]==nil)
125assert('5'-a == '5')
126assert(cap[0] == "sub" and cap[1] == '5' and cap[2] == a and cap[3]==nil)
127assert(a*a == a)
128assert(cap[0] == "mul" and cap[1] == a and cap[2] == a and cap[3]==nil)
129assert(a/0 == a)
130assert(cap[0] == "div" and cap[1] == a and cap[2] == 0 and cap[3]==nil)
131assert(a%2 == a)
132assert(cap[0] == "mod" and cap[1] == a and cap[2] == 2 and cap[3]==nil)
133assert(-a == a)
134assert(cap[0] == "unm" and cap[1] == a)
135assert(a^4 == a)
136assert(cap[0] == "pow" and cap[1] == a and cap[2] == 4 and cap[3]==nil)
137assert(a^'4' == a)
138assert(cap[0] == "pow" and cap[1] == a and cap[2] == '4' and cap[3]==nil)
139assert(4^a == 4)
140assert(cap[0] == "pow" and cap[1] == 4 and cap[2] == a and cap[3]==nil)
141assert('4'^a == '4')
142assert(cap[0] == "pow" and cap[1] == '4' and cap[2] == a and cap[3]==nil)
143
144
145t = {}
146t.__lt = function (a,b,c)
147  collectgarbage()
148  assert(c == nil)
149  if type(a) == 'table' then a = a.x end
150  if type(b) == 'table' then b = b.x end
151 return a<b, "dummy"
152end
153
154function Op(x) return setmetatable({x=x}, t) end
155
156local function test ()
157  assert(not(Op(1)<Op(1)) and (Op(1)<Op(2)) and not(Op(2)<Op(1)))
158  assert(not(Op('a')<Op('a')) and (Op('a')<Op('b')) and not(Op('b')<Op('a')))
159  assert((Op(1)<=Op(1)) and (Op(1)<=Op(2)) and not(Op(2)<=Op(1)))
160  assert((Op('a')<=Op('a')) and (Op('a')<=Op('b')) and not(Op('b')<=Op('a')))
161  assert(not(Op(1)>Op(1)) and not(Op(1)>Op(2)) and (Op(2)>Op(1)))
162  assert(not(Op('a')>Op('a')) and not(Op('a')>Op('b')) and (Op('b')>Op('a')))
163  assert((Op(1)>=Op(1)) and not(Op(1)>=Op(2)) and (Op(2)>=Op(1)))
164  assert((Op('a')>=Op('a')) and not(Op('a')>=Op('b')) and (Op('b')>=Op('a')))
165end
166
167test()
168
169t.__le = function (a,b,c)
170  assert(c == nil)
171  if type(a) == 'table' then a = a.x end
172  if type(b) == 'table' then b = b.x end
173 return a<=b, "dummy"
174end
175
176test()  -- retest comparisons, now using both `lt' and `le'
177
178
179-- test `partial order'
180
181local function Set(x)
182  local y = {}
183  for _,k in pairs(x) do y[k] = 1 end
184  return setmetatable(y, t)
185end
186
187t.__lt = function (a,b)
188  for k in pairs(a) do
189    if not b[k] then return false end
190    b[k] = nil
191  end
192  return next(b) ~= nil
193end
194
195t.__le = nil
196
197assert(Set{1,2,3} < Set{1,2,3,4})
198assert(not(Set{1,2,3,4} < Set{1,2,3,4}))
199assert((Set{1,2,3,4} <= Set{1,2,3,4}))
200assert((Set{1,2,3,4} >= Set{1,2,3,4}))
201assert((Set{1,3} <= Set{3,5}))   -- wrong!! model needs a `le' method ;-)
202
203t.__le = function (a,b)
204  for k in pairs(a) do
205    if not b[k] then return false end
206  end
207  return true
208end
209
210assert(not (Set{1,3} <= Set{3,5}))   -- now its OK!
211assert(not(Set{1,3} <= Set{3,5}))
212assert(not(Set{1,3} >= Set{3,5}))
213
214t.__eq = function (a,b)
215  for k in pairs(a) do
216    if not b[k] then return false end
217    b[k] = nil
218  end
219  return next(b) == nil
220end
221
222local s = Set{1,3,5}
223assert(s == Set{3,5,1})
224assert(not rawequal(s, Set{3,5,1}))
225assert(rawequal(s, s))
226assert(Set{1,3,5,1} == Set{3,5,1})
227assert(Set{1,3,5} ~= Set{3,5,1,6})
228t[Set{1,3,5}] = 1
229assert(t[Set{1,3,5}] == nil)   -- `__eq' is not valid for table accesses
230
231
232t.__concat = function (a,b,c)
233  assert(c == nil)
234  if type(a) == 'table' then a = a.val end
235  if type(b) == 'table' then b = b.val end
236  if A then return a..b
237  else
238    return setmetatable({val=a..b}, t)
239  end
240end
241
242c = {val="c"}; setmetatable(c, t)
243d = {val="d"}; setmetatable(d, t)
244
245A = true
246assert(c..d == 'cd')
247assert(0 .."a".."b"..c..d.."e".."f"..(5+3).."g" == "0abcdef8g")
248
249A = false
250x = c..d
251assert(getmetatable(x) == t and x.val == 'cd')
252x = 0 .."a".."b"..c..d.."e".."f".."g"
253assert(x.val == "0abcdefg")
254
255
256-- test comparison compatibilities
257local t1, t2, c, d
258t1 = {};  c = {}; setmetatable(c, t1)
259d = {}
260t1.__eq = function () return true end
261t1.__lt = function () return true end
262assert(c ~= d and not pcall(function () return c < d end))
263setmetatable(d, t1)
264assert(c == d and c < d and not(d <= c))
265t2 = {}
266t2.__eq = t1.__eq
267t2.__lt = t1.__lt
268setmetatable(d, t2)
269assert(c == d and c < d and not(d <= c))
270
271
272
273-- test for several levels of calls
274local i
275local tt = {
276  __call = function (t, ...)
277    i = i+1
278    if t.f then return t.f(...)
279    else return {...}
280    end
281  end
282}
283
284local a = setmetatable({}, tt)
285local b = setmetatable({f=a}, tt)
286local c = setmetatable({f=b}, tt)
287
288i = 0
289x = c(3,4,5)
290assert(i == 3 and x[1] == 3 and x[3] == 5)
291
292
293assert(_G.X == 20)
294assert(_G == getfenv(0))
295
296print'+'
297
298local _g = _G
299setfenv(1, setmetatable({}, {__index=function (_,k) return _g[k] end}))
300
301--[[
302-- testing proxies
303assert(getmetatable(newproxy()) == nil)
304assert(getmetatable(newproxy(false)) == nil)
305
306local u = newproxy(true)
307
308getmetatable(u).__newindex = function (u,k,v)
309  getmetatable(u)[k] = v
310end
311
312getmetatable(u).__index = function (u,k)
313  return getmetatable(u)[k]
314end
315
316for i=1,10 do u[i] = i end
317for i=1,10 do assert(u[i] == i) end
318
319local k = newproxy(u)
320assert(getmetatable(k) == getmetatable(u))
321
322
323a = {}
324rawset(a, "x", 1, 2, 3)
325assert(a.x == 1 and rawget(a, "x", 3) == 1)
326
327print '+'
328--]]
329
330-- testing metatables for basic types
331mt = {}
332debug.setmetatable(10, mt)
333assert(getmetatable(-2) == mt)
334mt.__index = function (a,b) return a+b end
335assert((10)[3] == 13)
336assert((10)["3"] == 13)
337debug.setmetatable(23, nil)
338assert(getmetatable(-2) == nil)
339
340debug.setmetatable(true, mt)
341assert(getmetatable(false) == mt)
342mt.__index = function (a,b) return a or b end
343assert((true)[false] == true)
344assert((false)[false] == false)
345debug.setmetatable(false, nil)
346assert(getmetatable(true) == nil)
347
348debug.setmetatable(nil, mt)
349assert(getmetatable(nil) == mt)
350mt.__add = function (a,b) return (a or 0) + (b or 0) end
351assert(10 + nil == 10)
352assert(nil + 23 == 23)
353assert(nil + nil == 0)
354debug.setmetatable(nil, nil)
355assert(getmetatable(nil) == nil)
356
357debug.setmetatable(nil, {})
358
359
360print 'OK'
361
362return 12
363