diff --git a/COPYING b/COPYING index 3eca3450..99f7245c 100644 --- a/COPYING +++ b/COPYING @@ -5,6 +5,7 @@ Some included files and subdirectories are licensed with an MIT license, not with the GPL. These are: * engines/LuaCommon/lualib/package.lua (as described in that file) +* engines/LuaCommon/lualib/strict.lua (as described in that file) * engines/LuaCommon/lualib/luabit/ (as described in readme.txt in that directory) * engines/LuaCommon/lualib/ustring/ (as described in README in that directory) * engines/LuaStandalone/binaries/ (as described in README in that directory) diff --git a/includes/engines/LuaCommon/lualib/strict.lua b/includes/engines/LuaCommon/lualib/strict.lua new file mode 100644 index 00000000..5655798a --- /dev/null +++ b/includes/engines/LuaCommon/lualib/strict.lua @@ -0,0 +1,31 @@ +-- strict.lua (fork of http://www.lua.org/extras/5.1/strict.lua) +-- checks uses of undeclared global variables +-- All global variables must be 'declared' through a regular assignment +-- (even assigning nil will do) in a main chunk before being used +-- anywhere or assigned to inside a function. +-- distributed under the Lua license: http://www.lua.org/license.html +-- Scribunto modifications: +-- * exempt arg, used by require() +-- * remove what(), since debug.getinfo isn't allowed + +local error, rawset, rawget = error, rawset, rawget + +local mt = getmetatable(_G) +if mt == nil then + mt = {} + setmetatable(_G, mt) +end + +mt.__newindex = function (t, n, v) + if n ~= "arg" then + error("assign to undeclared variable '"..n.."'", 2) + end + rawset(t, n, v) +end + +mt.__index = function (t, n) + if n ~= "arg" then + error("variable '"..n.."' is not declared", 2) + end + return rawget(t, n) +end diff --git a/tests/phpunit/engines/LuaCommon/CommonTests.lua b/tests/phpunit/engines/LuaCommon/CommonTests.lua index 80fd5f85..b6bece2b 100644 --- a/tests/phpunit/engines/LuaCommon/CommonTests.lua +++ b/tests/phpunit/engines/LuaCommon/CommonTests.lua @@ -166,6 +166,22 @@ function test.noLeaksViaPackageLoaded() return 'ok' end +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 + test.loadData = {} function test.loadData.get( ... ) @@ -300,6 +316,19 @@ return testframework.getTestProvider( { expect = { 'ok' }, }, + { 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'", + }, + { name = 'mw.loadData, returning non-table', func = mw.loadData, args = { 'Module:CommonTests-data-fail1' }, expect = "Module:CommonTests-data-fail1 returned string, table expected",