--- source: src/main.rs expression: compiled input_file: test-data/lua5.3-tests/nextvar.lua --- print('testing tables, next, and for'); local fn checkerror(msg, f, ...) { local s, err = pcall(f, ...) assert(!s && string.find(err, msg)); } local a = {} for i = 1, 100 { a[(i .. "+")] = true } for i = 1, 100 { a[(i .. "+")] = nil } for i = 1, 100 { a[(i)] = true assert(#a == i); } local x = 0 for k, v with ipairs({ 10, 20, 30, x = 12 }) { x = x + 1 assert(k == x && v == x * 10); } for _ with ipairs({ x = 12, y = 24 }) { assert(nil); } x = false local i = 0 for k, v with ipairs({ true, false, true, false }) { i = i + 1 x = !x assert(x == v); } assert(i == 4); assert(type(ipairs({})) == 'function' && ipairs({}) == ipairs({})); if !T { (Message || print)('\n >>> testC not active: skipping tests for table sizes <<<\n'); } else { local fn log2(x) { return math.log(x, 2) } local fn mp2(n) { local mp = 2 ^ math.ceil(log2(n)) assert(n == 0 || (mp / 2 < n && n <= mp)); return mp } local fn fb(n) { local r, nn = T.int2fb(n) assert(r < 256); return nn } for a = 1, 10000 { local n = fb(a) assert(a <= n && n <= a * 1.125); } local a = 1024 local lim = 2 ^ 30 while a < lim { local n = fb(a) assert(a <= n && n <= a * 1.125); a = math.ceil(a * 1.3) } local fn check(t, na, nh) { local a, h = T.querytab(t) if a != na || h != nh { print(na, nh, a, h); assert(nil); } } { local s = 0 for _ with pairs(math) { s = s + 1 } check(math, 0, mp2(s)); } local lim = 40 local s = 'return {' for i = 1, lim { s = s .. i .. ',' local s = s for k = 0, lim { local t = load(s .. '}', '')() assert(#t == i); check(t, fb(i), mp2(k)); s = string.format('%sa%d=%d,', s, k, k) } } local a = {} for i = 1, lim { a[(i)] = i } for k = 0, lim { local a = { table.unpack(a, 1, k) } assert(#a == k); check(a, k, 0); a = { 1, 2, 3, table.unpack(a, 1, k) } check(a, k + 3, 0); assert(#a == k + 3); } local lim = 130 local a = {} a[(2)] = 1 check(a, 0, 1); a = {} a[(0)] = 1 check(a, 0, 1); a[(2)] = 1 check(a, 0, 2); a = {} a[(0)] = 1 a[(1)] = 1 check(a, 1, 1); a = {} for i = 1, lim { a[(i)] = 1 assert(#a == i); check(a, mp2(i), 0); } a = {} for i = 1, lim { a[('a' .. i)] = 1 assert(#a == 0); check(a, 0, mp2(i)); } a = {} for i = 1, 16 { a[(i)] = i } check(a, 16, 0); { for i = 1, 11 { a[(i)] = nil } for i = 30, 50 { a[(i)] = nil } check(a, 0, 8); a[(10)] = 1 for i = 30, 50 { a[(i)] = nil } check(a, 0, 8); for i = 1, 14 { a[(i)] = nil } for i = 18, 50 { a[(i)] = nil } check(a, 0, 4); } for i = 1, lim { local a = {} for i = i, 1, -1 { a[(i)] = i } check(a, mp2(i), 0); } lim = 35 global fn foo(n, ...) { local arg = { ... } check(arg, n, 0); assert(select('#', ...) == n); arg[(n + 1)] = true check(arg, mp2(n + 1), 0); arg.x = true check(arg, mp2(n + 1), 1); } local a = {} for i = 1, lim { a[(i)] = true foo(i, table.unpack(a)); } } assert(#{} == 0); assert(#{ nil } == 0); assert(#{ nil, nil } == 0); assert(#{ nil, nil, nil } == 0); assert(#{ nil, nil, nil, nil } == 0); print('+'); local nofind = {} a, b, c = 1, 2, 3 a, b, c = nil assert(next({}) == next({})); local fn find(name) { local n, v while 1 { n, v = next(_G, n) if !n { return nofind } assert(v != nil); if n == name { return v } } } local fn find1(name) { for n, v with pairs(_G) { if n == name { return v } } return nil } assert(print == find("print") && print == find1("print")); assert(_G[("print")] == find("print")); assert(assert == find1("assert")); assert(nofind == find("return")); assert(!find1("return")); _G[("ret" .. "urn")] = nil assert(nofind == find("return")); _G[("xxx")] = 1 assert(xxx == find("xxx")); checkerror("invalid key", next, { 10, 20 }, 3); checkerror("bad argument", pairs); checkerror("bad argument", ipairs); print('+'); a = {} for i = 0, 10000 { if math.fmod(i, 10) != 0 { a[('x' .. i)] = i } } n = { n = 0 } for i, v with pairs(a) { n.n = n.n + 1 assert(i && v && a[(i)] == v); } assert(n.n == 9000); a = nil { local a = {} for n, v with pairs(_G) { a[(n)] = v } for n, v with pairs(a) { if !package.loaded[(n)] && type(v) != "function" && !string.find(n, "^[%u_]") { _G[(n)] = nil } collectgarbage(); } } local fn checknext(a) { local b = {} { local k, v = next(a) while k { b[(k)] = v k, v = next(a, k) } } for k, v with pairs(b) { assert(a[(k)] == v); } for k, v with pairs(a) { assert(b[(k)] == v); } } checknext({ 1, x = 1, y = 2, z = 3 }); checknext({ 1, 2, x = 1, y = 2, z = 3 }); checknext({ 1, 2, 3, x = 1, y = 2, z = 3 }); checknext({ 1, 2, 3, 4, x = 1, y = 2, z = 3 }); checknext({ 1, 2, 3, 4, 5, x = 1, y = 2, z = 3 }); assert(#{} == 0); assert(#{ -1 = 2 } == 0); assert(#{ 1, 2, 3, nil, nil } == 3); for i = 0, 40 { local a = {} for j = 1, i { a[(j)] = j } assert(#a == i); } method table.maxn(t) { local max = 0 for k with pairs(t) { max = (type(k) == 'number') && math.max(max, k) || max } return max } assert(table.maxn({}) == 0); assert(table.maxn({ "1000" = true }) == 0); assert(table.maxn({ "1000" = true, 24.5 = 3 }) == 24.5); assert(table.maxn({ 1000 = true }) == 1000); assert(table.maxn({ 10 = true, 100 * math.pi = print }) == 100 * math.pi); table.maxn = nil a = {} for i = 0, 50 { a[(2 ^ i)] = true } assert(a[(#a)]); print('+'); local t = { { 1 } = 1, { 2 } = 2, string.rep("x ", 4) = 3, 100.3 = 4, 4 = 5 } local n = 0 for k, v with pairs(t) { n = n + 1 assert(t[(k)] == v); t[(k)] = nil collectgarbage(); assert(t[(k)] == nil); } assert(n == 5); local fn test(a) { assert(!pcall(table.insert, a, 2, 20)); table.insert(a, 10); table.insert(a, 2, 20); table.insert(a, 1, -1); table.insert(a, 40); table.insert(a, #a + 1, 50); table.insert(a, 2, -2); assert(!pcall(table.insert, a, 0, 20)); assert(!pcall(table.insert, a, #a + 2, 20)); assert(table.remove(a, 1) == -1); assert(table.remove(a, 1) == -2); assert(table.remove(a, 1) == 10); assert(table.remove(a, 1) == 20); assert(table.remove(a, 1) == 40); assert(table.remove(a, 1) == 50); assert(table.remove(a, 1) == nil); assert(table.remove(a) == nil); assert(table.remove(a, #a) == nil); } a = { n = 0, -7 = "ban" } test(a); assert(a.n == 0 && a[(-7)] == "ban"); a = { -7 = "ban" } test(a); assert(a.n == nil && #a == 0 && a[(-7)] == "ban"); a = { -1 = "ban" } test(a); assert(#a == 0 && table.remove(a) == nil && a[(-1)] == "ban"); a = { 0 = "ban" } assert(#a == 0 && table.remove(a) == "ban" && a[(0)] == nil); table.insert(a, 1, 10); table.insert(a, 1, 20); table.insert(a, 1, -1); assert(table.remove(a) == 10); assert(table.remove(a) == 20); assert(table.remove(a) == -1); assert(table.remove(a) == nil); a = { 'c', 'd' } table.insert(a, 3, 'a'); table.insert(a, 'b'); assert(table.remove(a, 1) == 'c'); assert(table.remove(a, 1) == 'd'); assert(table.remove(a, 1) == 'a'); assert(table.remove(a, 1) == 'b'); assert(table.remove(a, 1) == nil); assert(#a == 0 && a.n == nil); a = { 10, 20, 30, 40 } assert(table.remove(a, #a + 1) == nil); assert(!pcall(table.remove, a, 0)); assert(a[(#a)] == 40); assert(table.remove(a, #a) == 40); assert(a[(#a)] == 30); assert(table.remove(a, 2) == 20); assert(a[(#a)] == 30 && #a == 2); { local fn test(proxy, t) { for i = 1, 10 { table.insert(proxy, 1, i); } assert(#proxy == 10 && #t == 10); for i = 1, 10 { assert(t[(i)] == 11 - i); } table.sort(proxy); for i = 1, 10 { assert(t[(i)] == i && proxy[(i)] == i); } assert(table.concat(proxy, ",") == "1,2,3,4,5,6,7,8,9,10"); for i = 1, 8 { assert(table.remove(proxy, 1) == i); } assert(#proxy == 2 && #t == 2); local a, b, c = table.unpack(proxy) assert(a == 9 && b == 10 && c == nil); } local t = {} local proxy = setmetatable({}, { __len = fn () { return #t }, __index = t, __newindex = t }) test(proxy, t); local count = 0 t = setmetatable({}, { __newindex = fn (t, k, v) { count = count + 1 rawset(t, k, v); } }) test(t, t); assert(count == 10); t = setmetatable({}, { __index = fn (_, k) { return k + 1 }, __len = fn (_) { return 5 } }) assert(table.concat(t, ";") == "2;3;4;5;6"); } if !T { (Message || print)('\n >>> testC not active: skipping tests for table library on non-tables <<<\n'); } else { local debug = require('debug') local tab = { 10, 20, 30 } local mt = {} local u = T.newuserdata(0) checkerror("table expected", table.insert, u, 40); checkerror("table expected", table.remove, u); debug.setmetatable(u, mt); checkerror("table expected", table.insert, u, 40); checkerror("table expected", table.remove, u); mt.__index = tab checkerror("table expected", table.insert, u, 40); checkerror("table expected", table.remove, u); mt.__newindex = tab checkerror("table expected", table.insert, u, 40); checkerror("table expected", table.remove, u); mt.__len = fn () { return #tab } table.insert(u, 40); assert(#u == 4 && #tab == 4 && u[(4)] == 40 && tab[(4)] == 40); assert(table.remove(u) == 40); table.insert(u, 1, 50); assert(#u == 4 && #tab == 4 && u[(4)] == 30 && tab[(1)] == 50); mt.__newindex = nil mt.__len = nil local tab2 = {} local u2 = T.newuserdata(0) debug.setmetatable(u2, { __newindex = fn (_, k, v) { tab2[(k)] = v } }); table.move(u, 1, 4, 1, u2); assert(#tab2 == 4 && tab2[(1)] == tab[(1)] && tab2[(4)] == tab[(4)]); } print('+'); a = {} for i = 1, 1000 { a[(i)] = i a[(i - 1)] = nil } assert(next(a, nil) == 1000 && next(a, 1000) == nil); assert(next({}) == nil); assert(next({}, nil) == nil); for a, b with pairs({}) { error("not here"); } for i = 1, 0 { error('not here'); } for i = 0, 1, -1 { error('not here'); } a = nil for i = 1, 1 { assert(!a); a = 1 } assert(a); a = nil for i = 1, 1, -1 { assert(!a); a = 1 } assert(a); { print("testing floats in numeric for"); local a a = 0 for i = 1, 1, 1 { a = a + 1 } assert(a == 1); a = 0 for i = 10000, 1e4, -1 { a = a + 1 } assert(a == 1); a = 0 for i = 1, 0.99999, 1 { a = a + 1 } assert(a == 0); a = 0 for i = 9999, 1e4, -1 { a = a + 1 } assert(a == 0); a = 0 for i = 1, 0.99999, -1 { a = a + 1 } assert(a == 1); a = 0 for i = 0, 0.999999999, 0.1 { a = a + 1 } assert(a == 10); a = 0 for i = 1.0, 1, 1 { a = a + 1 } assert(a == 1); a = 0 for i = -1.5, -1.5, 1 { a = a + 1 } assert(a == 1); a = 0 for i = 1e6, 1e6, -1 { a = a + 1 } assert(a == 1); a = 0 for i = 1.0, 0.99999, 1 { a = a + 1 } assert(a == 0); a = 0 for i = 99999, 1e5, -1.0 { a = a + 1 } assert(a == 0); a = 0 for i = 1.0, 0.99999, -1 { a = a + 1 } assert(a == 1); } a = 0 for i = "10", "1", "-2" { a = a + 1 } assert(a == 5); { local c local fn checkfloat(i) { assert(math.type(i) == "float"); c = c + 1 } c = 0 for i = 1.0, 10 { checkfloat(i); } assert(c == 10); c = 0 for i = -1, -10, -1.0 { checkfloat(i); } assert(c == 10); local fn checkint(i) { assert(math.type(i) == "integer"); c = c + 1 } local m = math.maxinteger c = 0 for i = m, m - 10, -1 { checkint(i); } assert(c == 11); c = 0 for i = 1, 10.9 { checkint(i); } assert(c == 10); c = 0 for i = 10, 0.001, -1 { checkint(i); } assert(c == 10); c = 0 for i = 1, "10.8" { checkint(i); } assert(c == 10); c = 0 for i = 9, "3.4", -1 { checkint(i); } assert(c == 6); c = 0 for i = 0, " -3.4 ", -1 { checkint(i); } assert(c == 4); c = 0 for i = 100, "96.3", -2 { checkint(i); } assert(c == 2); c = 0 for i = 1, math.huge { if i > 10 { break } checkint(i); } assert(c == 10); c = 0 for i = -1, -math.huge, -1 { if i < -10 { break } checkint(i); } assert(c == 10); for i = math.mininteger, -10e100 { assert(false); } for i = math.maxinteger, 10e100, -1 { assert(false); } } collectgarbage(); local fn f(n, p) { local t = {} for i = 1, p { t[(i)] = i * 10 } return fn (_, n) { if n > 0 { n = n - 1 return n, table.unpack(t) } }, nil, n } local x = 0 for n, a, b, c, d with f(5, 3) { x = x + 1 assert(a == 10 && b == 20 && c == 30 && d == nil); } assert(x == 5); a = {} { local x, y, z = pairs(a) assert(type(x) == 'function' && y == a && z == nil); } local fn foo(e, i) { assert(e == a); if i <= 10 { return i + 1, i + 2 } } local fn foo1(e, i) { i = i + 1 assert(e == a); if i <= e.n { return i, a[(i)] } } setmetatable(a, { __pairs = fn (x) { return foo, x, 0 } }); local i = 0 for k, v with pairs(a) { i = i + 1 assert(k == i && v == k + 1); } a.n = 5 a[(3)] = 30 a = { n = 10 } setmetatable(a, { __index = fn (t, k) { if k <= t.n { return k * 10 } } }); i = 0 for k, v with ipairs(a) { i = i + 1 assert(k == i && v == i * 10); } assert(i == a.n); print("OK");