mirror of
https://github.com/lua/lua.git
synced 2024-11-23 18:23:43 +08:00
488 lines
12 KiB
Lua
488 lines
12 KiB
Lua
|
-- $Id: attrib.lua,v 1.69 2018/03/12 13:51:02 roberto Exp $
|
||
|
-- See Copyright Notice in file all.lua
|
||
|
|
||
|
print "testing require"
|
||
|
|
||
|
assert(require"string" == string)
|
||
|
assert(require"math" == math)
|
||
|
assert(require"table" == table)
|
||
|
assert(require"io" == io)
|
||
|
assert(require"os" == os)
|
||
|
assert(require"coroutine" == coroutine)
|
||
|
|
||
|
assert(type(package.path) == "string")
|
||
|
assert(type(package.cpath) == "string")
|
||
|
assert(type(package.loaded) == "table")
|
||
|
assert(type(package.preload) == "table")
|
||
|
|
||
|
assert(type(package.config) == "string")
|
||
|
print("package config: "..string.gsub(package.config, "\n", "|"))
|
||
|
|
||
|
do
|
||
|
-- create a path with 'max' templates,
|
||
|
-- each with 1-10 repetitions of '?'
|
||
|
local max = _soft and 100 or 2000
|
||
|
local t = {}
|
||
|
for i = 1,max do t[i] = string.rep("?", i%10 + 1) end
|
||
|
t[#t + 1] = ";" -- empty template
|
||
|
local path = table.concat(t, ";")
|
||
|
-- use that path in a search
|
||
|
local s, err = package.searchpath("xuxu", path)
|
||
|
-- search fails; check that message has an occurence of
|
||
|
-- '??????????' with ? replaced by xuxu and at least 'max' lines
|
||
|
assert(not s and
|
||
|
string.find(err, string.rep("xuxu", 10)) and
|
||
|
#string.gsub(err, "[^\n]", "") >= max)
|
||
|
-- path with one very long template
|
||
|
local path = string.rep("?", max)
|
||
|
local s, err = package.searchpath("xuxu", path)
|
||
|
assert(not s and string.find(err, string.rep('xuxu', max)))
|
||
|
end
|
||
|
|
||
|
do
|
||
|
local oldpath = package.path
|
||
|
package.path = {}
|
||
|
local s, err = pcall(require, "no-such-file")
|
||
|
assert(not s and string.find(err, "package.path"))
|
||
|
package.path = oldpath
|
||
|
end
|
||
|
|
||
|
print('+')
|
||
|
|
||
|
|
||
|
-- The next tests for 'require' assume some specific directories and
|
||
|
-- libraries.
|
||
|
|
||
|
if not _port then --[
|
||
|
|
||
|
local dirsep = string.match(package.config, "^([^\n]+)\n")
|
||
|
|
||
|
-- auxiliary directory with C modules and temporary files
|
||
|
local DIR = "libs" .. dirsep
|
||
|
|
||
|
-- prepend DIR to a name and correct directory separators
|
||
|
local function D (x)
|
||
|
x = string.gsub(x, "/", dirsep)
|
||
|
return DIR .. x
|
||
|
end
|
||
|
|
||
|
-- prepend DIR and pospend proper C lib. extension to a name
|
||
|
local function DC (x)
|
||
|
local ext = (dirsep == '\\') and ".dll" or ".so"
|
||
|
return D(x .. ext)
|
||
|
end
|
||
|
|
||
|
|
||
|
local function createfiles (files, preextras, posextras)
|
||
|
for n,c in pairs(files) do
|
||
|
io.output(D(n))
|
||
|
io.write(string.format(preextras, n))
|
||
|
io.write(c)
|
||
|
io.write(string.format(posextras, n))
|
||
|
io.close(io.output())
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function removefiles (files)
|
||
|
for n in pairs(files) do
|
||
|
os.remove(D(n))
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local files = {
|
||
|
["names.lua"] = "do return {...} end\n",
|
||
|
["err.lua"] = "B = 15; a = a + 1;",
|
||
|
["synerr.lua"] = "B =",
|
||
|
["A.lua"] = "",
|
||
|
["B.lua"] = "assert(...=='B');require 'A'",
|
||
|
["A.lc"] = "",
|
||
|
["A"] = "",
|
||
|
["L"] = "",
|
||
|
["XXxX"] = "",
|
||
|
["C.lua"] = "package.loaded[...] = 25; require'C'",
|
||
|
}
|
||
|
|
||
|
AA = nil
|
||
|
local extras = [[
|
||
|
NAME = '%s'
|
||
|
REQUIRED = ...
|
||
|
return AA]]
|
||
|
|
||
|
createfiles(files, "", extras)
|
||
|
|
||
|
-- testing explicit "dir" separator in 'searchpath'
|
||
|
assert(package.searchpath("C.lua", D"?", "", "") == D"C.lua")
|
||
|
assert(package.searchpath("C.lua", D"?", ".", ".") == D"C.lua")
|
||
|
assert(package.searchpath("--x-", D"?", "-", "X") == D"XXxX")
|
||
|
assert(package.searchpath("---xX", D"?", "---", "XX") == D"XXxX")
|
||
|
assert(package.searchpath(D"C.lua", "?", dirsep) == D"C.lua")
|
||
|
assert(package.searchpath(".\\C.lua", D"?", "\\") == D"./C.lua")
|
||
|
|
||
|
local oldpath = package.path
|
||
|
|
||
|
package.path = string.gsub("D/?.lua;D/?.lc;D/?;D/??x?;D/L", "D/", DIR)
|
||
|
|
||
|
local try = function (p, n, r)
|
||
|
NAME = nil
|
||
|
local rr = require(p)
|
||
|
assert(NAME == n)
|
||
|
assert(REQUIRED == p)
|
||
|
assert(rr == r)
|
||
|
end
|
||
|
|
||
|
a = require"names"
|
||
|
assert(a[1] == "names" and a[2] == D"names.lua")
|
||
|
|
||
|
_G.a = nil
|
||
|
local st, msg = pcall(require, "err")
|
||
|
assert(not st and string.find(msg, "arithmetic") and B == 15)
|
||
|
st, msg = pcall(require, "synerr")
|
||
|
assert(not st and string.find(msg, "error loading module"))
|
||
|
|
||
|
assert(package.searchpath("C", package.path) == D"C.lua")
|
||
|
assert(require"C" == 25)
|
||
|
assert(require"C" == 25)
|
||
|
AA = nil
|
||
|
try('B', 'B.lua', true)
|
||
|
assert(package.loaded.B)
|
||
|
assert(require"B" == true)
|
||
|
assert(package.loaded.A)
|
||
|
assert(require"C" == 25)
|
||
|
package.loaded.A = nil
|
||
|
try('B', nil, true) -- should not reload package
|
||
|
try('A', 'A.lua', true)
|
||
|
package.loaded.A = nil
|
||
|
os.remove(D'A.lua')
|
||
|
AA = {}
|
||
|
try('A', 'A.lc', AA) -- now must find second option
|
||
|
assert(package.searchpath("A", package.path) == D"A.lc")
|
||
|
assert(require("A") == AA)
|
||
|
AA = false
|
||
|
try('K', 'L', false) -- default option
|
||
|
try('K', 'L', false) -- default option (should reload it)
|
||
|
assert(rawget(_G, "_REQUIREDNAME") == nil)
|
||
|
|
||
|
AA = "x"
|
||
|
try("X", "XXxX", AA)
|
||
|
|
||
|
|
||
|
removefiles(files)
|
||
|
|
||
|
|
||
|
-- testing require of sub-packages
|
||
|
|
||
|
local _G = _G
|
||
|
|
||
|
package.path = string.gsub("D/?.lua;D/?/init.lua", "D/", DIR)
|
||
|
|
||
|
files = {
|
||
|
["P1/init.lua"] = "AA = 10",
|
||
|
["P1/xuxu.lua"] = "AA = 20",
|
||
|
}
|
||
|
|
||
|
createfiles(files, "_ENV = {}\n", "\nreturn _ENV\n")
|
||
|
AA = 0
|
||
|
|
||
|
local m = assert(require"P1")
|
||
|
assert(AA == 0 and m.AA == 10)
|
||
|
assert(require"P1" == m)
|
||
|
assert(require"P1" == m)
|
||
|
|
||
|
assert(package.searchpath("P1.xuxu", package.path) == D"P1/xuxu.lua")
|
||
|
m.xuxu = assert(require"P1.xuxu")
|
||
|
assert(AA == 0 and m.xuxu.AA == 20)
|
||
|
assert(require"P1.xuxu" == m.xuxu)
|
||
|
assert(require"P1.xuxu" == m.xuxu)
|
||
|
assert(require"P1" == m and m.AA == 10)
|
||
|
|
||
|
|
||
|
removefiles(files)
|
||
|
|
||
|
|
||
|
package.path = ""
|
||
|
assert(not pcall(require, "file_does_not_exist"))
|
||
|
package.path = "??\0?"
|
||
|
assert(not pcall(require, "file_does_not_exist1"))
|
||
|
|
||
|
package.path = oldpath
|
||
|
|
||
|
-- check 'require' error message
|
||
|
local fname = "file_does_not_exist2"
|
||
|
local m, err = pcall(require, fname)
|
||
|
for t in string.gmatch(package.path..";"..package.cpath, "[^;]+") do
|
||
|
t = string.gsub(t, "?", fname)
|
||
|
assert(string.find(err, t, 1, true))
|
||
|
end
|
||
|
|
||
|
do -- testing 'package.searchers' not being a table
|
||
|
local searchers = package.searchers
|
||
|
package.searchers = 3
|
||
|
local st, msg = pcall(require, 'a')
|
||
|
assert(not st and string.find(msg, "must be a table"))
|
||
|
package.searchers = searchers
|
||
|
end
|
||
|
|
||
|
local function import(...)
|
||
|
local f = {...}
|
||
|
return function (m)
|
||
|
for i=1, #f do m[f[i]] = _G[f[i]] end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- cannot change environment of a C function
|
||
|
assert(not pcall(module, 'XUXU'))
|
||
|
|
||
|
|
||
|
|
||
|
-- testing require of C libraries
|
||
|
|
||
|
|
||
|
local p = "" -- On Mac OS X, redefine this to "_"
|
||
|
|
||
|
-- check whether loadlib works in this system
|
||
|
local st, err, when = package.loadlib(DC"lib1", "*")
|
||
|
if not st then
|
||
|
local f, err, when = package.loadlib("donotexist", p.."xuxu")
|
||
|
assert(not f and type(err) == "string" and when == "absent")
|
||
|
;(Message or print)('\n >>> cannot load dynamic library <<<\n')
|
||
|
print(err, when)
|
||
|
else
|
||
|
-- tests for loadlib
|
||
|
local f = assert(package.loadlib(DC"lib1", p.."onefunction"))
|
||
|
local a, b = f(15, 25)
|
||
|
assert(a == 25 and b == 15)
|
||
|
|
||
|
f = assert(package.loadlib(DC"lib1", p.."anotherfunc"))
|
||
|
assert(f(10, 20) == "10%20\n")
|
||
|
|
||
|
-- check error messages
|
||
|
local f, err, when = package.loadlib(DC"lib1", p.."xuxu")
|
||
|
assert(not f and type(err) == "string" and when == "init")
|
||
|
f, err, when = package.loadlib("donotexist", p.."xuxu")
|
||
|
assert(not f and type(err) == "string" and when == "open")
|
||
|
|
||
|
-- symbols from 'lib1' must be visible to other libraries
|
||
|
f = assert(package.loadlib(DC"lib11", p.."luaopen_lib11"))
|
||
|
assert(f() == "exported")
|
||
|
|
||
|
-- test C modules with prefixes in names
|
||
|
package.cpath = DC"?"
|
||
|
local lib2 = require"lib2-v2"
|
||
|
-- check correct access to global environment and correct
|
||
|
-- parameters
|
||
|
assert(_ENV.x == "lib2-v2" and _ENV.y == DC"lib2-v2")
|
||
|
assert(lib2.id("x") == "x")
|
||
|
|
||
|
-- test C submodules
|
||
|
local fs = require"lib1.sub"
|
||
|
assert(_ENV.x == "lib1.sub" and _ENV.y == DC"lib1")
|
||
|
assert(fs.id(45) == 45)
|
||
|
end
|
||
|
|
||
|
_ENV = _G
|
||
|
|
||
|
|
||
|
-- testing preload
|
||
|
|
||
|
do
|
||
|
local p = package
|
||
|
package = {}
|
||
|
p.preload.pl = function (...)
|
||
|
local _ENV = {...}
|
||
|
function xuxu (x) return x+20 end
|
||
|
return _ENV
|
||
|
end
|
||
|
|
||
|
local pl = require"pl"
|
||
|
assert(require"pl" == pl)
|
||
|
assert(pl.xuxu(10) == 30)
|
||
|
assert(pl[1] == "pl" and pl[2] == nil)
|
||
|
|
||
|
package = p
|
||
|
assert(type(package.path) == "string")
|
||
|
end
|
||
|
|
||
|
print('+')
|
||
|
|
||
|
end --]
|
||
|
|
||
|
print("testing assignments, logical operators, and constructors")
|
||
|
|
||
|
local res, res2 = 27
|
||
|
|
||
|
a, b = 1, 2+3
|
||
|
assert(a==1 and b==5)
|
||
|
a={}
|
||
|
function f() return 10, 11, 12 end
|
||
|
a.x, b, a[1] = 1, 2, f()
|
||
|
assert(a.x==1 and b==2 and a[1]==10)
|
||
|
a[f()], b, a[f()+3] = f(), a, 'x'
|
||
|
assert(a[10] == 10 and b == a and a[13] == 'x')
|
||
|
|
||
|
do
|
||
|
local f = function (n) local x = {}; for i=1,n do x[i]=i end;
|
||
|
return table.unpack(x) end;
|
||
|
local a,b,c
|
||
|
a,b = 0, f(1)
|
||
|
assert(a == 0 and b == 1)
|
||
|
A,b = 0, f(1)
|
||
|
assert(A == 0 and b == 1)
|
||
|
a,b,c = 0,5,f(4)
|
||
|
assert(a==0 and b==5 and c==1)
|
||
|
a,b,c = 0,5,f(0)
|
||
|
assert(a==0 and b==5 and c==nil)
|
||
|
end
|
||
|
|
||
|
a, b, c, d = 1 and nil, 1 or nil, (1 and (nil or 1)), 6
|
||
|
assert(not a and b and c and d==6)
|
||
|
|
||
|
d = 20
|
||
|
a, b, c, d = f()
|
||
|
assert(a==10 and b==11 and c==12 and d==nil)
|
||
|
a,b = f(), 1, 2, 3, f()
|
||
|
assert(a==10 and b==1)
|
||
|
|
||
|
assert(a<b == false and a>b == true)
|
||
|
assert((10 and 2) == 2)
|
||
|
assert((10 or 2) == 10)
|
||
|
assert((10 or assert(nil)) == 10)
|
||
|
assert(not (nil and assert(nil)))
|
||
|
assert((nil or "alo") == "alo")
|
||
|
assert((nil and 10) == nil)
|
||
|
assert((false and 10) == false)
|
||
|
assert((true or 10) == true)
|
||
|
assert((false or 10) == 10)
|
||
|
assert(false ~= nil)
|
||
|
assert(nil ~= false)
|
||
|
assert(not nil == true)
|
||
|
assert(not not nil == false)
|
||
|
assert(not not 1 == true)
|
||
|
assert(not not a == true)
|
||
|
assert(not not (6 or nil) == true)
|
||
|
assert(not not (nil and 56) == false)
|
||
|
assert(not not (nil and true) == false)
|
||
|
assert(not 10 == false)
|
||
|
assert(not {} == false)
|
||
|
assert(not 0.5 == false)
|
||
|
assert(not "x" == false)
|
||
|
|
||
|
assert({} ~= {})
|
||
|
print('+')
|
||
|
|
||
|
a = {}
|
||
|
a[true] = 20
|
||
|
a[false] = 10
|
||
|
assert(a[1<2] == 20 and a[1>2] == 10)
|
||
|
|
||
|
function f(a) return a end
|
||
|
|
||
|
local a = {}
|
||
|
for i=3000,-3000,-1 do a[i + 0.0] = i; end
|
||
|
a[10e30] = "alo"; a[true] = 10; a[false] = 20
|
||
|
assert(a[10e30] == 'alo' and a[not 1] == 20 and a[10<20] == 10)
|
||
|
for i=3000,-3000,-1 do assert(a[i] == i); end
|
||
|
a[print] = assert
|
||
|
a[f] = print
|
||
|
a[a] = a
|
||
|
assert(a[a][a][a][a][print] == assert)
|
||
|
a[print](a[a[f]] == a[print])
|
||
|
assert(not pcall(function () local a = {}; a[nil] = 10 end))
|
||
|
assert(not pcall(function () local a = {[nil] = 10} end))
|
||
|
assert(a[nil] == undef)
|
||
|
a = nil
|
||
|
|
||
|
a = {10,9,8,7,6,5,4,3,2; [-3]='a', [f]=print, a='a', b='ab'}
|
||
|
a, a.x, a.y = a, a[-3]
|
||
|
assert(a[1]==10 and a[-3]==a.a and a[f]==print and a.x=='a' and not a.y)
|
||
|
a[1], f(a)[2], b, c = {['alo']=assert}, 10, a[1], a[f], 6, 10, 23, f(a), 2
|
||
|
a[1].alo(a[2]==10 and b==10 and c==print)
|
||
|
|
||
|
a.aVeryLongName012345678901234567890123456789012345678901234567890123456789 = 10
|
||
|
local function foo ()
|
||
|
return a.aVeryLongName012345678901234567890123456789012345678901234567890123456789
|
||
|
end
|
||
|
assert(foo() == 10 and
|
||
|
a.aVeryLongName012345678901234567890123456789012345678901234567890123456789 ==
|
||
|
10)
|
||
|
|
||
|
|
||
|
|
||
|
-- test of large float/integer indices
|
||
|
|
||
|
-- compute maximum integer where all bits fit in a float
|
||
|
local maxint = math.maxinteger
|
||
|
|
||
|
-- trim (if needed) to fit in a float
|
||
|
while maxint ~= (maxint + 0.0) or (maxint - 1) ~= (maxint - 1.0) do
|
||
|
maxint = maxint // 2
|
||
|
end
|
||
|
|
||
|
maxintF = maxint + 0.0 -- float version
|
||
|
|
||
|
assert(maxintF == maxint and math.type(maxintF) == "float" and
|
||
|
maxintF >= 2.0^14)
|
||
|
|
||
|
-- floats and integers must index the same places
|
||
|
a[maxintF] = 10; a[maxintF - 1.0] = 11;
|
||
|
a[-maxintF] = 12; a[-maxintF + 1.0] = 13;
|
||
|
|
||
|
assert(a[maxint] == 10 and a[maxint - 1] == 11 and
|
||
|
a[-maxint] == 12 and a[-maxint + 1] == 13)
|
||
|
|
||
|
a[maxint] = 20
|
||
|
a[-maxint] = 22
|
||
|
|
||
|
assert(a[maxintF] == 20 and a[maxintF - 1.0] == 11 and
|
||
|
a[-maxintF] == 22 and a[-maxintF + 1.0] == 13)
|
||
|
|
||
|
a = nil
|
||
|
|
||
|
|
||
|
-- test conflicts in multiple assignment
|
||
|
do
|
||
|
local a,i,j,b
|
||
|
a = {'a', 'b'}; i=1; j=2; b=a
|
||
|
i, a[i], a, j, a[j], a[i+j] = j, i, i, b, j, i
|
||
|
assert(i == 2 and b[1] == 1 and a == 1 and j == b and b[2] == 2 and
|
||
|
b[3] == 1)
|
||
|
a = {}
|
||
|
local function foo () -- assigining to upvalues
|
||
|
b, a.x, a = a, 10, 20
|
||
|
end
|
||
|
foo()
|
||
|
assert(a == 20 and b.x == 10)
|
||
|
end
|
||
|
|
||
|
-- repeat test with upvalues
|
||
|
do
|
||
|
local a,i,j,b
|
||
|
a = {'a', 'b'}; i=1; j=2; b=a
|
||
|
local function foo ()
|
||
|
i, a[i], a, j, a[j], a[i+j] = j, i, i, b, j, i
|
||
|
end
|
||
|
foo()
|
||
|
assert(i == 2 and b[1] == 1 and a == 1 and j == b and b[2] == 2 and
|
||
|
b[3] == 1)
|
||
|
local t = {}
|
||
|
(function (a) t[a], a = 10, 20 end)(1);
|
||
|
assert(t[1] == 10)
|
||
|
end
|
||
|
|
||
|
-- bug in 5.2 beta
|
||
|
local function foo ()
|
||
|
local a
|
||
|
return function ()
|
||
|
local b
|
||
|
a, b = 3, 14 -- local and upvalue have same index
|
||
|
return a, b
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local a, b = foo()()
|
||
|
assert(a == 3 and b == 14)
|
||
|
|
||
|
print('OK')
|
||
|
|
||
|
return res
|
||
|
|