2012-12-19 20:10:01 +00:00
|
|
|
local testframework = require 'Module:TestFramework'
|
2012-04-19 07:40:56 +00:00
|
|
|
|
|
|
|
local test = {}
|
|
|
|
|
|
|
|
function test.clone1()
|
|
|
|
local x = 1
|
|
|
|
local y = mw.clone( x )
|
2012-12-19 20:10:01 +00:00
|
|
|
return ( x == y )
|
2012-04-19 07:40:56 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function test.clone2()
|
|
|
|
local x = { 'a' }
|
|
|
|
local y = mw.clone( x )
|
|
|
|
assert( x ~= y )
|
2012-12-19 20:10:01 +00:00
|
|
|
return testframework.deepEquals( x, y )
|
|
|
|
end
|
|
|
|
|
|
|
|
function test.clone2b()
|
|
|
|
local x = { 'a' }
|
|
|
|
local y = mw.clone( x )
|
|
|
|
assert( x ~= y )
|
2012-04-19 07:40:56 +00:00
|
|
|
y[2] = 'b'
|
2012-12-19 20:10:01 +00:00
|
|
|
return testframework.deepEquals( x, y )
|
2012-04-19 07:40:56 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function test.clone3()
|
|
|
|
local mt = { __add = function() end }
|
|
|
|
local x = {}
|
|
|
|
setmetatable( x, mt )
|
|
|
|
local y = mw.clone( x )
|
|
|
|
assert( getmetatable( x ) ~= getmetatable( y ) )
|
2012-12-19 20:10:01 +00:00
|
|
|
return testframework.deepEquals( getmetatable( x ), getmetatable( y ) )
|
2012-04-19 07:40:56 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function test.clone4()
|
|
|
|
local x = {}
|
|
|
|
x.x = x
|
|
|
|
local y = mw.clone( x )
|
|
|
|
assert( x ~= y )
|
2012-12-19 20:10:01 +00:00
|
|
|
return y == y.x
|
2012-04-19 07:40:56 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function test.setfenv1()
|
|
|
|
setfenv( 0, {} )
|
|
|
|
end
|
|
|
|
|
|
|
|
function test.setfenv2()
|
|
|
|
setfenv( 1000, {} )
|
|
|
|
end
|
|
|
|
|
|
|
|
function test.setfenv3()
|
|
|
|
local function jailbreak()
|
|
|
|
setfenv( 2, {} )
|
|
|
|
end
|
2013-02-14 20:44:50 +00:00
|
|
|
local new_setfenv, new_getfenv = mw.makeProtectedEnvFuncsForTest( { [_G] = true }, {} )
|
2012-04-19 07:40:56 +00:00
|
|
|
setfenv( jailbreak, {setfenv = new_setfenv} )
|
|
|
|
jailbreak()
|
|
|
|
end
|
|
|
|
|
|
|
|
function test.setfenv4()
|
2012-12-19 20:10:01 +00:00
|
|
|
-- Set an unprotected environment at a higher stack level than a protected
|
|
|
|
-- environment. It's assumed that any higher-level environment will protect
|
2012-04-24 02:33:06 +00:00
|
|
|
-- itself with its own setfenv wrapper, so this succeeds.
|
|
|
|
local function level3()
|
2013-02-14 20:44:50 +00:00
|
|
|
local protected = {setfenv = setfenv, getfenv = getfenv, mw = mw}
|
2012-04-24 02:33:06 +00:00
|
|
|
local function level2()
|
|
|
|
local function level1()
|
|
|
|
setfenv( 3, {} )
|
|
|
|
end
|
2012-12-19 20:10:01 +00:00
|
|
|
|
2013-02-14 20:44:50 +00:00
|
|
|
local env = {}
|
|
|
|
env.setfenv, env.getfenv = mw.makeProtectedEnvFuncsForTest(
|
|
|
|
{[protected] = true}, {} )
|
2012-04-24 02:33:06 +00:00
|
|
|
setfenv( level1, env )()
|
|
|
|
end
|
|
|
|
setfenv( level2, protected )()
|
2012-04-19 07:40:56 +00:00
|
|
|
end
|
2012-04-24 02:33:06 +00:00
|
|
|
local unprotected = {setfenv = setfenv, getfenv = getfenv, mw = mw}
|
|
|
|
setfenv( level3, unprotected )()
|
|
|
|
assert( getfenv( level3 ) ~= unprotected )
|
2012-05-22 03:56:07 +00:00
|
|
|
return 'ok'
|
2012-04-19 07:40:56 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function test.setfenv5()
|
|
|
|
local function allowed()
|
|
|
|
(function() setfenv( 2, {} ) end )()
|
|
|
|
end
|
2013-02-14 20:44:50 +00:00
|
|
|
local new_setfenv, new_getfenv = mw.makeProtectedEnvFuncsForTest( { [_G] = true }, {} )
|
2012-04-19 07:40:56 +00:00
|
|
|
setfenv( allowed, {setfenv = new_setfenv} )()
|
2012-05-22 03:56:07 +00:00
|
|
|
return 'ok'
|
2012-04-19 07:40:56 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function test.setfenv6()
|
|
|
|
local function target() end
|
|
|
|
local function jailbreak()
|
|
|
|
setfenv( target, {} )
|
|
|
|
end
|
2013-02-14 20:44:50 +00:00
|
|
|
local new_setfenv, new_getfenv = mw.makeProtectedEnvFuncsForTest( {}, { [target] = true } )
|
2012-04-19 07:40:56 +00:00
|
|
|
setfenv( jailbreak, {setfenv = new_setfenv} )()
|
|
|
|
end
|
|
|
|
|
|
|
|
function test.setfenv7()
|
|
|
|
setfenv( {}, {} )
|
|
|
|
end
|
|
|
|
|
|
|
|
function test.getfenv1()
|
|
|
|
assert( getfenv( 1 ) == _G )
|
2012-05-22 03:56:07 +00:00
|
|
|
return 'ok'
|
2012-04-19 07:40:56 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
function test.getfenv2()
|
|
|
|
getfenv( 0 )
|
|
|
|
end
|
|
|
|
|
2012-04-24 02:33:06 +00:00
|
|
|
function test.getfenv3()
|
|
|
|
local function foo()
|
|
|
|
return getfenv( 2 )
|
|
|
|
end
|
|
|
|
|
|
|
|
local function bar()
|
|
|
|
return foo()
|
|
|
|
end
|
|
|
|
|
2012-12-19 20:10:01 +00:00
|
|
|
-- The "at level #" bit varies between environments, so
|
|
|
|
-- catch the error and strip that part out
|
|
|
|
local ok, err = pcall( bar )
|
|
|
|
if not ok then
|
|
|
|
err = string.gsub( err, '^%S+:%d+: ', '' )
|
|
|
|
err = string.gsub( err, ' at level %d$', '' )
|
|
|
|
error( err )
|
|
|
|
end
|
2012-04-24 02:33:06 +00:00
|
|
|
end
|
|
|
|
|
2013-02-01 20:43:32 +00:00
|
|
|
function test.executeExpensiveCalls( n )
|
|
|
|
for i = 1, n do
|
|
|
|
mw.incrementExpensiveFunctionCount()
|
|
|
|
end
|
|
|
|
return 'Did not error out'
|
|
|
|
end
|
|
|
|
|
2012-12-24 15:37:47 +00:00
|
|
|
function test.stringMetatableHidden1()
|
|
|
|
return getmetatable( "" )
|
|
|
|
end
|
|
|
|
|
|
|
|
function test.stringMetatableHidden2()
|
|
|
|
string.foo = 42
|
|
|
|
return ("").foo
|
|
|
|
end
|
|
|
|
|
2012-12-27 21:21:04 +00:00
|
|
|
local pairs_test_table = {}
|
|
|
|
setmetatable( pairs_test_table, {
|
|
|
|
__pairs = function () return 1, 2, 3, 'ignore' end,
|
|
|
|
__ipairs = function () return 4, 5, 6, 'ignore' end,
|
|
|
|
} )
|
|
|
|
|
2012-12-27 16:22:44 +00:00
|
|
|
function test.noLeaksViaPackageLoaded()
|
|
|
|
assert( package.loaded.debug == debug, "package.loaded.debug ~= debug" )
|
|
|
|
assert( package.loaded.string == string, "package.loaded.string ~= string" )
|
|
|
|
assert( package.loaded.math == math, "package.loaded.math ~= math" )
|
|
|
|
assert( package.loaded.io == io, "package.loaded.io ~= io" )
|
|
|
|
assert( package.loaded.os == os, "package.loaded.os ~= os" )
|
|
|
|
assert( package.loaded.table == table, "package.loaded.table ~= table" )
|
|
|
|
assert( package.loaded._G == _G , "package.loaded._G ~= _G " )
|
|
|
|
assert( package.loaded.coroutine == coroutine, "package.loaded.coroutine ~= coroutine" )
|
|
|
|
assert( package.loaded.package == package, "package.loaded.package ~= package" )
|
|
|
|
return 'ok'
|
|
|
|
end
|
|
|
|
|
Add strict.lua to replace "Module:No globals"
For the most part, it is a good idea to avoid global variables and use
`local` variables instead. Quoting from the ScopeTutorial[1], "The
general rule is to always use local variables, unless it's necessary for
every part of your program to be able to access the variable (which is
very rare)."
Wikimedia module authors have written "Module:No globals", which errors
on the use of any global variable. On the English Wikipedia, this is
used on 32% of pages (18 million). Wikidata[2] indicates that it's been
copied to 334 other wikis.
Lua itself distributes an extra named "strict.lua"[3], which is what
this is based off of. Similar to bit32.lua, this is a pure-Lua library
that can be imported/enabled with `require( "strict" )` at the top of a
module.
The two changes I made from Lua's strict is to exempt the `arg` key,
which is used internally by Scribunto, and remove `what()`, since we
don't enable access to `debug.getinfo()` for security reasons.
[1] https://lua-users.org/wiki/ScopeTutorial
[2] https://www.wikidata.org/wiki/Q16748603
[3] http://www.lua.org/extras/5.1/strict.lua
Bug: T209310
Change-Id: I46ee6f630ac6b26c68c31becd1f3b9d961bcab29
2022-09-24 04:23:03 +00:00
|
|
|
function test.strictGood()
|
|
|
|
require( 'strict' )
|
|
|
|
local foo = "bar"
|
|
|
|
return foo
|
|
|
|
end
|
|
|
|
|
|
|
|
function test.strictBad1()
|
|
|
|
require( 'strict' )
|
|
|
|
return bar
|
|
|
|
end
|
|
|
|
|
|
|
|
function test.strictBad2()
|
|
|
|
require( 'strict' )
|
|
|
|
bar = "foo"
|
|
|
|
end
|
|
|
|
|
2013-02-21 21:31:23 +00:00
|
|
|
test.loadData = {}
|
|
|
|
|
|
|
|
function test.loadData.get( ... )
|
|
|
|
local d = mw.loadData( 'Module:CommonTests-data' )
|
|
|
|
for i = 1, select( '#', ... ) do
|
|
|
|
local k = select( i, ... )
|
|
|
|
d = d[k]
|
|
|
|
end
|
|
|
|
return d
|
|
|
|
end
|
|
|
|
|
|
|
|
function test.loadData.set( v, ... )
|
|
|
|
local d = mw.loadData( 'Module:CommonTests-data' )
|
|
|
|
local n = select( '#', ... )
|
|
|
|
for i = 1, n - 1 do
|
|
|
|
local k = select( i, ... )
|
|
|
|
d = d[k]
|
|
|
|
end
|
|
|
|
d[select( n, ... )] = v
|
|
|
|
return d[select( n, ... )]
|
|
|
|
end
|
|
|
|
|
|
|
|
function test.loadData.recursion()
|
|
|
|
local d = mw.loadData( 'Module:CommonTests-data' )
|
|
|
|
return d == d.t, d.t == d.t.t, d.table2 == d.table
|
|
|
|
end
|
|
|
|
|
|
|
|
function test.loadData.iterate( func )
|
|
|
|
local d = mw.loadData( 'Module:CommonTests-data' )
|
|
|
|
local ret = {}
|
|
|
|
for k, v in func( d.table ) do
|
|
|
|
ret[k] = v
|
|
|
|
end
|
|
|
|
return ret
|
|
|
|
end
|
|
|
|
|
|
|
|
function test.loadData.setmetatable()
|
|
|
|
local d = mw.loadData( 'Module:CommonTests-data' )
|
|
|
|
setmetatable( d, {} )
|
|
|
|
return 'setmetatable succeeded'
|
|
|
|
end
|
|
|
|
|
|
|
|
function test.loadData.rawset()
|
|
|
|
-- We can't easily prevent rawset (and it's not worth trying to redefine
|
|
|
|
-- it), but we can make sure it doesn't affect other instances of the data
|
|
|
|
local d1 = mw.loadData( 'Module:CommonTests-data' )
|
|
|
|
local d2 = mw.loadData( 'Module:CommonTests-data' )
|
|
|
|
rawset( d1, 'str', 'ugh' )
|
|
|
|
local d3 = mw.loadData( 'Module:CommonTests-data' )
|
|
|
|
return d1.str, d2.str, d3.str
|
|
|
|
end
|
|
|
|
|
2022-09-22 07:45:47 +00:00
|
|
|
test.loadJsonData = {}
|
|
|
|
|
|
|
|
function test.loadJsonData.get( ... )
|
|
|
|
local d = mw.loadJsonData( 'Module:CommonTests-data.json' )
|
|
|
|
for i = 1, select( '#', ... ) do
|
|
|
|
local k = select( i, ... )
|
|
|
|
d = d[k]
|
|
|
|
end
|
|
|
|
return d
|
|
|
|
end
|
|
|
|
|
|
|
|
function test.loadJsonData.set( v, ... )
|
|
|
|
local d = mw.loadJsonData( 'Module:CommonTests-data.json' )
|
|
|
|
local n = select( '#', ... )
|
|
|
|
for i = 1, n - 1 do
|
|
|
|
local k = select( i, ... )
|
|
|
|
d = d[k]
|
|
|
|
end
|
|
|
|
d[select( n, ... )] = v
|
|
|
|
return d[select( n, ... )]
|
|
|
|
end
|
|
|
|
|
|
|
|
function test.loadJsonData.iterate( func )
|
|
|
|
local d = mw.loadJsonData( 'Module:CommonTests-data.json' )
|
|
|
|
local ret = {}
|
|
|
|
for k, v in func( d.table ) do
|
|
|
|
ret[k] = v
|
|
|
|
end
|
|
|
|
return ret
|
|
|
|
end
|
|
|
|
|
|
|
|
function test.loadJsonData.setmetatable()
|
|
|
|
local d = mw.loadJsonData( 'Module:CommonTests-data.json' )
|
|
|
|
setmetatable( d, {} )
|
|
|
|
return 'setmetatable succeeded'
|
|
|
|
end
|
|
|
|
|
|
|
|
function test.loadJsonData.rawset()
|
|
|
|
-- We can't easily prevent rawset (and it's not worth trying to redefine
|
|
|
|
-- it), but we can make sure it doesn't affect other instances of the data
|
|
|
|
local d1 = mw.loadJsonData( 'Module:CommonTests-data.json' )
|
|
|
|
local d2 = mw.loadJsonData( 'Module:CommonTests-data.json' )
|
|
|
|
rawset( d1, 'str', 'ugh' )
|
|
|
|
local d3 = mw.loadJsonData( 'Module:CommonTests-data.json' )
|
|
|
|
return d1.str, d2.str, d3.str
|
|
|
|
end
|
|
|
|
|
|
|
|
function test.loadJsonData.error( name )
|
|
|
|
mw.loadJsonData( name )
|
|
|
|
end
|
|
|
|
|
2012-12-19 20:10:01 +00:00
|
|
|
return testframework.getTestProvider( {
|
|
|
|
{ name = 'clone', func = test.clone1,
|
2020-10-23 15:39:12 +00:00
|
|
|
expect = { true },
|
2012-12-19 20:10:01 +00:00
|
|
|
},
|
|
|
|
{ name = 'clone table', func = test.clone2,
|
2020-10-23 15:39:12 +00:00
|
|
|
expect = { true },
|
2012-12-19 20:10:01 +00:00
|
|
|
},
|
|
|
|
{ name = 'clone table then modify', func = test.clone2b,
|
2020-10-23 15:39:12 +00:00
|
|
|
expect = { false, { 2 }, nil, 'b' },
|
2012-12-19 20:10:01 +00:00
|
|
|
},
|
|
|
|
{ name = 'clone table with metatable', func = test.clone3,
|
2020-10-23 15:39:12 +00:00
|
|
|
expect = { true },
|
2012-12-19 20:10:01 +00:00
|
|
|
},
|
|
|
|
{ name = 'clone recursive table', func = test.clone4,
|
2020-10-23 15:39:12 +00:00
|
|
|
expect = { true },
|
2012-12-19 20:10:01 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
{ name = 'setfenv global', func = test.setfenv1,
|
2020-10-23 15:39:12 +00:00
|
|
|
expect = "'setfenv' cannot set the global environment, it is protected",
|
2012-12-19 20:10:01 +00:00
|
|
|
},
|
|
|
|
{ name = 'setfenv invalid level', func = test.setfenv2,
|
2020-10-23 15:39:12 +00:00
|
|
|
expect = "'setfenv' cannot set an environment at a level greater than 10",
|
2012-12-19 20:10:01 +00:00
|
|
|
},
|
|
|
|
{ name = 'setfenv invalid environment', func = test.setfenv3,
|
2020-10-23 15:39:12 +00:00
|
|
|
expect = "'setfenv' cannot set the requested environment, it is protected",
|
2012-12-19 20:10:01 +00:00
|
|
|
},
|
|
|
|
{ name = 'setfenv on unprotected past protected', func = test.setfenv4,
|
2020-10-23 15:39:12 +00:00
|
|
|
expect = { 'ok' },
|
2012-12-19 20:10:01 +00:00
|
|
|
},
|
|
|
|
{ name = 'setfenv from inside protected', func = test.setfenv5,
|
2020-10-23 15:39:12 +00:00
|
|
|
expect = { 'ok' },
|
2012-12-19 20:10:01 +00:00
|
|
|
},
|
|
|
|
{ name = 'setfenv protected function', func = test.setfenv6,
|
2020-10-23 15:39:12 +00:00
|
|
|
expect = "'setfenv' cannot be called on a protected function",
|
2012-12-19 20:10:01 +00:00
|
|
|
},
|
|
|
|
{ name = 'setfenv on a non-function', func = test.setfenv7,
|
2020-10-23 15:39:12 +00:00
|
|
|
expect = "'setfenv' can only be called with a function or integer as the first argument",
|
2012-12-19 20:10:01 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
{ name = 'getfenv(1)', func = test.getfenv1,
|
2020-10-23 15:39:12 +00:00
|
|
|
expect = { 'ok' },
|
2012-12-19 20:10:01 +00:00
|
|
|
},
|
|
|
|
{ name = 'getfenv(0)', func = test.getfenv2,
|
2020-10-23 15:39:12 +00:00
|
|
|
expect = "'getfenv' cannot get the global environment",
|
2012-12-19 20:10:01 +00:00
|
|
|
},
|
|
|
|
{ name = 'getfenv with tail call', func = test.getfenv3,
|
2020-10-23 15:39:12 +00:00
|
|
|
expect = "no function environment for tail call",
|
2012-12-19 20:10:01 +00:00
|
|
|
},
|
2012-12-24 15:37:47 +00:00
|
|
|
|
2013-02-01 20:43:32 +00:00
|
|
|
{ name = 'Not quite too many expensive function calls',
|
2020-10-23 15:39:12 +00:00
|
|
|
func = test.executeExpensiveCalls, args = { 10 },
|
|
|
|
expect = { 'Did not error out' }
|
2013-02-01 20:43:32 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
{ name = 'Too many expensive function calls',
|
2020-10-23 15:39:12 +00:00
|
|
|
func = test.executeExpensiveCalls, args = { 11 },
|
|
|
|
expect = 'too many expensive function calls'
|
2013-02-01 20:43:32 +00:00
|
|
|
},
|
|
|
|
|
2012-12-24 15:37:47 +00:00
|
|
|
{ name = 'string metatable is hidden', func = test.stringMetatableHidden1,
|
2020-10-23 15:39:12 +00:00
|
|
|
expect = { nil }
|
2012-12-24 15:37:47 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
{ name = 'string is not string metatable', func = test.stringMetatableHidden2,
|
2020-10-23 15:39:12 +00:00
|
|
|
expect = { nil }
|
2012-12-24 15:37:47 +00:00
|
|
|
},
|
2012-12-27 21:21:04 +00:00
|
|
|
|
|
|
|
{ name = 'pairs with __pairs',
|
2020-10-23 15:39:12 +00:00
|
|
|
func = pairs, args = { pairs_test_table },
|
|
|
|
expect = { 1, 2, 3 },
|
2012-12-27 21:21:04 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
{ name = 'ipairs with __ipairs',
|
2020-10-23 15:39:12 +00:00
|
|
|
func = ipairs, args = { pairs_test_table },
|
|
|
|
expect = { 4, 5, 6 },
|
2012-12-27 21:21:04 +00:00
|
|
|
},
|
2012-12-27 16:22:44 +00:00
|
|
|
|
|
|
|
{ name = 'package.loaded does not leak references to out-of-environment objects',
|
2020-10-23 15:39:12 +00:00
|
|
|
func = test.noLeaksViaPackageLoaded,
|
|
|
|
expect = { 'ok' },
|
2012-12-27 16:22:44 +00:00
|
|
|
},
|
2013-02-21 21:31:23 +00:00
|
|
|
|
Add strict.lua to replace "Module:No globals"
For the most part, it is a good idea to avoid global variables and use
`local` variables instead. Quoting from the ScopeTutorial[1], "The
general rule is to always use local variables, unless it's necessary for
every part of your program to be able to access the variable (which is
very rare)."
Wikimedia module authors have written "Module:No globals", which errors
on the use of any global variable. On the English Wikipedia, this is
used on 32% of pages (18 million). Wikidata[2] indicates that it's been
copied to 334 other wikis.
Lua itself distributes an extra named "strict.lua"[3], which is what
this is based off of. Similar to bit32.lua, this is a pure-Lua library
that can be imported/enabled with `require( "strict" )` at the top of a
module.
The two changes I made from Lua's strict is to exempt the `arg` key,
which is used internally by Scribunto, and remove `what()`, since we
don't enable access to `debug.getinfo()` for security reasons.
[1] https://lua-users.org/wiki/ScopeTutorial
[2] https://www.wikidata.org/wiki/Q16748603
[3] http://www.lua.org/extras/5.1/strict.lua
Bug: T209310
Change-Id: I46ee6f630ac6b26c68c31becd1f3b9d961bcab29
2022-09-24 04:23:03 +00:00
|
|
|
{ name = 'strict on good code raises no errors',
|
|
|
|
func = test.strictGood,
|
|
|
|
expect = { 'bar' },
|
|
|
|
},
|
|
|
|
{ name = 'strict on code reading from a global errors',
|
|
|
|
func = test.strictBad1,
|
|
|
|
expect = "variable 'bar' is not declared",
|
|
|
|
},
|
|
|
|
{ name = 'strict on code setting from a global errors',
|
|
|
|
func = test.strictBad2,
|
|
|
|
expect = "assign to undeclared variable 'bar'",
|
|
|
|
},
|
|
|
|
|
2013-02-21 21:31:23 +00:00
|
|
|
{ name = 'mw.loadData, returning non-table',
|
2020-10-23 15:39:12 +00:00
|
|
|
func = mw.loadData, args = { 'Module:CommonTests-data-fail1' },
|
|
|
|
expect = "Module:CommonTests-data-fail1 returned string, table expected",
|
2013-02-21 21:31:23 +00:00
|
|
|
},
|
|
|
|
{ name = 'mw.loadData, containing function',
|
2020-10-23 15:39:12 +00:00
|
|
|
func = mw.loadData, args = { 'Module:CommonTests-data-fail2' },
|
|
|
|
expect = "data for mw.loadData contains unsupported data type 'function'",
|
2013-02-21 21:31:23 +00:00
|
|
|
},
|
|
|
|
{ name = 'mw.loadData, containing table-with-metatable',
|
2020-10-23 15:39:12 +00:00
|
|
|
func = mw.loadData, args = { 'Module:CommonTests-data-fail3' },
|
|
|
|
expect = "data for mw.loadData contains a table with a metatable",
|
2013-02-21 21:31:23 +00:00
|
|
|
},
|
|
|
|
{ name = 'mw.loadData, containing function as key',
|
2020-10-23 15:39:12 +00:00
|
|
|
func = mw.loadData, args = { 'Module:CommonTests-data-fail4' },
|
|
|
|
expect = "data for mw.loadData contains unsupported data type 'function'",
|
2013-02-21 21:31:23 +00:00
|
|
|
},
|
|
|
|
{ name = 'mw.loadData, containing table-with-metatable as key',
|
2020-10-23 15:39:12 +00:00
|
|
|
func = mw.loadData, args = { 'Module:CommonTests-data-fail5' },
|
|
|
|
expect = "data for mw.loadData contains a table as a key",
|
2013-02-21 21:31:23 +00:00
|
|
|
},
|
|
|
|
{ name = 'mw.loadData, getter (true)',
|
2020-10-23 15:39:12 +00:00
|
|
|
func = test.loadData.get, args = { 'true' },
|
|
|
|
expect = { true }
|
2013-02-21 21:31:23 +00:00
|
|
|
},
|
|
|
|
{ name = 'mw.loadData, getter (false)',
|
2020-10-23 15:39:12 +00:00
|
|
|
func = test.loadData.get, args = { 'false' },
|
|
|
|
expect = { false }
|
2013-02-21 21:31:23 +00:00
|
|
|
},
|
|
|
|
{ name = 'mw.loadData, getter (NaN)',
|
2020-10-23 15:39:12 +00:00
|
|
|
func = test.loadData.get, args = { 'NaN' },
|
|
|
|
expect = { 0/0 }
|
2013-02-21 21:31:23 +00:00
|
|
|
},
|
|
|
|
{ name = 'mw.loadData, getter (inf)',
|
2020-10-23 15:39:12 +00:00
|
|
|
func = test.loadData.get, args = { 'inf' },
|
|
|
|
expect = { 1/0 }
|
2013-02-21 21:31:23 +00:00
|
|
|
},
|
|
|
|
{ name = 'mw.loadData, getter (num)',
|
2020-10-23 15:39:12 +00:00
|
|
|
func = test.loadData.get, args = { 'num' },
|
|
|
|
expect = { 12.5 }
|
2013-02-21 21:31:23 +00:00
|
|
|
},
|
|
|
|
{ name = 'mw.loadData, getter (str)',
|
2020-10-23 15:39:12 +00:00
|
|
|
func = test.loadData.get, args = { 'str' },
|
|
|
|
expect = { 'foo bar' }
|
2013-02-21 21:31:23 +00:00
|
|
|
},
|
|
|
|
{ name = 'mw.loadData, getter (table.2)',
|
2020-10-23 15:39:12 +00:00
|
|
|
func = test.loadData.get, args = { 'table', 2 },
|
|
|
|
expect = { 'two' }
|
2013-02-21 21:31:23 +00:00
|
|
|
},
|
|
|
|
{ name = 'mw.loadData, getter (t.t.t.t.str)',
|
2020-10-23 15:39:12 +00:00
|
|
|
func = test.loadData.get, args = { 't', 't', 't', 't', 'str' },
|
|
|
|
expect = { 'foo bar' }
|
2013-02-21 21:31:23 +00:00
|
|
|
},
|
|
|
|
{ name = 'mw.loadData, getter recursion',
|
2020-10-23 15:39:12 +00:00
|
|
|
func = test.loadData.recursion,
|
|
|
|
expect = { true, true, true },
|
2013-02-21 21:31:23 +00:00
|
|
|
},
|
|
|
|
{ name = 'mw.loadData, pairs',
|
2020-10-23 15:39:12 +00:00
|
|
|
func = test.loadData.iterate, args = { pairs },
|
|
|
|
expect = { { 'one', 'two', 'three', foo = 'bar' } },
|
2013-02-21 21:31:23 +00:00
|
|
|
},
|
|
|
|
{ name = 'mw.loadData, ipairs',
|
2020-10-23 15:39:12 +00:00
|
|
|
func = test.loadData.iterate, args = { ipairs },
|
|
|
|
expect = { { 'one', 'two', 'three' } },
|
2013-02-21 21:31:23 +00:00
|
|
|
},
|
|
|
|
{ name = 'mw.loadData, setmetatable',
|
2020-10-23 15:39:12 +00:00
|
|
|
func = test.loadData.setmetatable,
|
|
|
|
expect = "cannot change a protected metatable"
|
2013-02-21 21:31:23 +00:00
|
|
|
},
|
|
|
|
{ name = 'mw.loadData, setter (1)',
|
2020-10-23 15:39:12 +00:00
|
|
|
func = test.loadData.set, args = { 'ugh', 'str' },
|
|
|
|
expect = "table from mw.loadData is read-only",
|
2013-02-21 21:31:23 +00:00
|
|
|
},
|
|
|
|
{ name = 'mw.loadData, setter (2)',
|
2020-10-23 15:39:12 +00:00
|
|
|
func = test.loadData.set, args = { 'ugh', 'table', 2 },
|
|
|
|
expect = "table from mw.loadData is read-only",
|
2013-02-21 21:31:23 +00:00
|
|
|
},
|
|
|
|
{ name = 'mw.loadData, setter (3)',
|
2020-10-23 15:39:12 +00:00
|
|
|
func = test.loadData.set, args = { 'ugh', 't' },
|
|
|
|
expect = "table from mw.loadData is read-only",
|
2013-02-21 21:31:23 +00:00
|
|
|
},
|
|
|
|
{ name = 'mw.loadData, rawset',
|
2020-10-23 15:39:12 +00:00
|
|
|
func = test.loadData.rawset,
|
|
|
|
expect = { 'ugh', 'foo bar', 'foo bar' },
|
2013-02-21 21:31:23 +00:00
|
|
|
},
|
2020-04-03 15:26:59 +00:00
|
|
|
|
2022-09-22 07:45:47 +00:00
|
|
|
{ name = 'mw.loadJsonData, getter (true)',
|
|
|
|
func = test.loadJsonData.get, args = { 'true' },
|
|
|
|
expect = { true }
|
|
|
|
},
|
|
|
|
{ name = 'mw.loadJsonData, getter (false)',
|
|
|
|
func = test.loadJsonData.get, args = { 'false' },
|
|
|
|
expect = { false }
|
|
|
|
},
|
|
|
|
{ name = 'mw.loadJsonData, getter (num)',
|
|
|
|
func = test.loadJsonData.get, args = { 'num' },
|
|
|
|
expect = { 12.5 }
|
|
|
|
},
|
|
|
|
{ name = 'mw.loadJsonData, getter (str)',
|
|
|
|
func = test.loadJsonData.get, args = { 'str' },
|
|
|
|
expect = { 'foo bar' }
|
|
|
|
},
|
|
|
|
{ name = 'mw.loadJsonData, getter (table.2)',
|
|
|
|
func = test.loadJsonData.get, args = { 'table', 2 },
|
|
|
|
expect = { 'two' }
|
|
|
|
},
|
|
|
|
{ name = 'mw.loadJsonData, pairs',
|
|
|
|
func = test.loadJsonData.iterate, args = { pairs },
|
|
|
|
expect = { { 'one', 'two', 'three' } },
|
|
|
|
},
|
|
|
|
{ name = 'mw.loadJsonData, ipairs',
|
|
|
|
func = test.loadJsonData.iterate, args = { ipairs },
|
|
|
|
expect = { { 'one', 'two', 'three' } },
|
|
|
|
},
|
|
|
|
{ name = 'mw.loadJsonData, setmetatable',
|
|
|
|
func = test.loadJsonData.setmetatable,
|
|
|
|
expect = "cannot change a protected metatable"
|
|
|
|
},
|
|
|
|
{ name = 'mw.loadJsonData, setter (1)',
|
|
|
|
func = test.loadJsonData.set, args = { 'ugh', 'str' },
|
|
|
|
expect = "table from mw.loadJsonData is read-only",
|
|
|
|
},
|
|
|
|
{ name = 'mw.loadJsonData, setter (2)',
|
|
|
|
func = test.loadJsonData.set, args = { 'ugh', 'table', 2 },
|
|
|
|
expect = "table from mw.loadJsonData is read-only",
|
|
|
|
},
|
|
|
|
{ name = 'mw.loadJsonData, setter (3)',
|
|
|
|
func = test.loadJsonData.set, args = { 'ugh', 't' },
|
|
|
|
expect = "table from mw.loadJsonData is read-only",
|
|
|
|
},
|
|
|
|
{ name = 'mw.loadJsonData, rawset',
|
|
|
|
func = test.loadJsonData.rawset,
|
|
|
|
expect = { 'ugh', 'foo bar', 'foo bar' },
|
|
|
|
},
|
|
|
|
{ name = 'mw.loadJsonData, bad title (1)',
|
|
|
|
func = test.loadJsonData.error, args = { 0 },
|
|
|
|
expect = "bad argument #1 to 'mw.loadJsonData' (string expected, got nil)",
|
|
|
|
},
|
|
|
|
{ name = 'mw.loadJsonData, bad title (2)',
|
|
|
|
func = test.loadJsonData.error, args = { "<invalid title>" },
|
|
|
|
expect = "bad argument #1 to 'mw.loadJsonData' ('<invalid title>' is not a valid JSON page)",
|
|
|
|
},
|
|
|
|
{ name = 'mw.loadJsonData, bad title (3)',
|
|
|
|
func = test.loadJsonData.error, args = { "Help:Foo" },
|
|
|
|
expect = "bad argument #1 to 'mw.loadJsonData' ('Help:Foo' is not a valid JSON page)",
|
|
|
|
},
|
|
|
|
{ name = 'mw.loadJsonData, bad title (4)',
|
|
|
|
func = test.loadJsonData.error, args = { "Help:Does not exist" },
|
|
|
|
expect = "bad argument #1 to 'mw.loadJsonData' ('Help:Does not exist' is not a valid JSON page)",
|
|
|
|
},
|
|
|
|
|
2020-04-03 15:26:59 +00:00
|
|
|
{ name = 'mw.addWarning',
|
2020-10-23 15:39:12 +00:00
|
|
|
func = mw.addWarning, args = { 'warn' },
|
|
|
|
expect = {},
|
2020-04-03 15:26:59 +00:00
|
|
|
},
|
|
|
|
{ name = 'mw.addWarning, bad type',
|
2020-10-23 15:39:12 +00:00
|
|
|
func = mw.addWarning, args = { true },
|
|
|
|
expect = "bad argument #1 to 'addWarning' (string expected)",
|
2020-04-03 15:26:59 +00:00
|
|
|
},
|
2012-12-19 20:10:01 +00:00
|
|
|
} )
|