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