luau/tests/conformance/iter.lua

217 lines
4.8 KiB
Lua

-- This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
-- This file is based on Lua 5.x tests -- https://github.com/lua/lua/tree/master/testes
print('testing iteration')
-- basic for loop tests
do
local a
for a,b in pairs{} do error("not here") end
for i=1,0 do error("not here") end
for i=0,1,-1 do error("not here") end
a = nil; for i=1,1 do assert(not a); a=1 end; assert(a)
a = nil; for i=1,1,-1 do assert(not a); a=1 end; assert(a)
a = 0; for i=0, 1, 0.1 do a=a+1 end; assert(a==11)
end
-- precision tests for for loops
do
local a
--a = 0; for i=1, 0, -0.01 do a=a+1 end; assert(a==101)
a = 0; for i=0, 0.999999999, 0.1 do a=a+1 end; assert(a==10)
a = 0; for i=1, 1, 1 do a=a+1 end; assert(a==1)
a = 0; for i=1e10, 1e10, -1 do a=a+1 end; assert(a==1)
a = 0; for i=1, 0.99999, 1 do a=a+1 end; assert(a==0)
a = 0; for i=99999, 1e5, -1 do a=a+1 end; assert(a==0)
a = 0; for i=1, 0.99999, -1 do a=a+1 end; assert(a==1)
end
-- for loops do string->number coercion
do
local a = 0; for i="10","1","-2" do a=a+1 end; assert(a==5)
end
-- generic for with function iterators
do
local function f (n, p)
local t = {}; for i=1,p do t[i] = i*10 end
return function (_,n)
if n > 0 then
n = n-1
return n, unpack(t)
end
end, nil, n
end
local x = 0
for n,a,b,c,d in f(5,3) do
x = x+1
assert(a == 10 and b == 20 and c == 30 and d == nil)
end
assert(x == 5)
end
-- generic for with __call (tables)
do
local f = {}
setmetatable(f, { __call = function(_, _, n) if n > 0 then return n - 1 end end })
local x = 0
for n in f, nil, 5 do
x += n
end
assert(x == 10)
end
-- generic for with __call (userdata)
do
local f = newproxy(true)
getmetatable(f).__call = function(_, _, n) if n > 0 then return n - 1 end end
local x = 0
for n in f, nil, 5 do
x += n
end
assert(x == 10)
end
-- generic for with pairs
do
local x = 0
for k, v in pairs({a = 1, b = 2, c = 3}) do
x += v
end
assert(x == 6)
end
-- generic for with pairs with holes
do
local x = 0
for k, v in pairs({1, 2, 3, nil, 5}) do
x += v
end
assert(x == 11)
end
-- generic for with ipairs
do
local x = 0
for k, v in ipairs({1, 2, 3, nil, 5}) do
x += v
end
assert(x == 6)
end
-- generic for with __iter (tables)
do
local f = {}
setmetatable(f, { __iter = function(x)
assert(f == x)
return next, {1, 2, 3, 4}
end })
local x = 0
for n in f do
x += n
end
assert(x == 10)
end
-- generic for with __iter (userdata)
do
local f = newproxy(true)
getmetatable(f).__iter = function(x)
assert(f == x)
return next, {1, 2, 3, 4}
end
local x = 0
for n in f do
x += n
end
assert(x == 10)
end
-- generic for with tables (dictionary)
do
local x = 0
for k, v in {a = 1, b = 2, c = 3} do
print(k, v)
x += v
end
assert(x == 6)
end
-- generic for with tables (arrays)
do
local x = ''
for k, v in {1, 2, 3, nil, 5} do
x ..= tostring(v)
end
assert(x == "1235")
end
-- generic for with tables (mixed)
do
local x = 0
for k, v in {1, 2, 3, nil, 5, a = 1, b = 2, c = 3} do
x += v
end
assert(x == 17)
end
-- generic for over a non-iterable object
do
local ok, err = pcall(function() for x in 42 do end end)
assert(not ok and err:match("attempt to iterate"))
end
-- generic for over an iterable object that doesn't return a function
do
local obj = {}
setmetatable(obj, { __iter = function() end })
local ok, err = pcall(function() for x in obj do end end)
assert(not ok and err:match("attempt to call a nil value"))
end
-- it's okay to iterate through a table with a single variable
do
local x = 0
for k in {1, 2, 3, 4, 5} do
x += k
end
assert(x == 15)
end
-- all extra variables should be set to nil during builtin traversal
do
local x = 0
for k,v,a,b,c,d,e in {1, 2, 3, 4, 5} do
x += k
assert(a == nil and b == nil and c == nil and d == nil and e == nil)
end
assert(x == 15)
end
-- pairs/ipairs/next may be substituted through getfenv
-- however, they *must* be substituted with functions - we don't support them falling back to generalized iteration
function testgetfenv()
local env = getfenv(1)
env.pairs = function() return "nope" end
env.ipairs = function() return "nope" end
env.next = {1, 2, 3}
local ok, err = pcall(function() for k, v in pairs({}) do end end)
assert(not ok and err:match("attempt to iterate over a string value"))
local ok, err = pcall(function() for k, v in ipairs({}) do end end)
assert(not ok and err:match("attempt to iterate over a string value"))
local ok, err = pcall(function() for k, v in next, {} do end end)
assert(not ok and err:match("attempt to iterate over a table value"))
end
testgetfenv() -- DONT MOVE THIS LINE
return"OK"