mirror of
https://github.com/luau-lang/luau.git
synced 2024-11-15 14:25:44 +08:00
217 lines
4.8 KiB
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"
|