|
|
@ -232,7 +232,11 @@ end |
|
|
|
do |
|
|
|
local X = false |
|
|
|
|
|
|
|
local x, closescope = func2close(function () stack(10); X = true end, 100) |
|
|
|
local x, closescope = func2close(function (_, msg) |
|
|
|
stack(10); |
|
|
|
assert(msg == nil) |
|
|
|
X = true |
|
|
|
end, 100) |
|
|
|
assert(x == 100); x = 101; -- 'x' is not read-only |
|
|
|
|
|
|
|
-- closing functions do not corrupt returning values |
|
|
@ -246,10 +250,11 @@ do |
|
|
|
|
|
|
|
X = false |
|
|
|
foo = function (x) |
|
|
|
local _<close> = func2close(function () |
|
|
|
local _<close> = func2close(function (_, msg) |
|
|
|
-- without errors, enclosing function should be still active when |
|
|
|
-- __close is called |
|
|
|
assert(debug.getinfo(2).name == "foo") |
|
|
|
assert(msg == nil) |
|
|
|
end) |
|
|
|
local _<close> = closescope |
|
|
|
local y = 15 |
|
|
@ -328,64 +333,20 @@ do |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
-- auxiliary functions for testing warnings in '__close' |
|
|
|
local function prepwarn () |
|
|
|
if not T then -- no test library? |
|
|
|
warn("@off") -- do not show (lots of) warnings |
|
|
|
else |
|
|
|
warn("@store") -- to test the warnings |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
local function endwarn () |
|
|
|
if not T then |
|
|
|
warn("@on") -- back to normal |
|
|
|
else |
|
|
|
assert(_WARN == false) |
|
|
|
warn("@normal") |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
-- errors inside __close can generate a warning instead of an |
|
|
|
-- error. This new 'assert' force them to appear. |
|
|
|
local function assert(cond, msg) |
|
|
|
if not cond then |
|
|
|
local line = debug.getinfo(2).currentline or "?" |
|
|
|
msg = string.format("assertion failed! line %d (%s)\n", line, msg or "") |
|
|
|
io.stderr:write(msg) |
|
|
|
os.exit(1) |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|
local function checkwarn (msg) |
|
|
|
if T then |
|
|
|
assert(_WARN and string.find(_WARN, msg)) |
|
|
|
_WARN = false -- reset variable to check next warning |
|
|
|
end |
|
|
|
end |
|
|
|
|
|
|
|
warn("@on") |
|
|
|
|
|
|
|
do print("testing errors in __close") |
|
|
|
|
|
|
|
prepwarn() |
|
|
|
|
|
|
|
-- original error is in __close |
|
|
|
local function foo () |
|
|
|
|
|
|
|
local x <close> = |
|
|
|
func2close(function (self, msg) |
|
|
|
assert(string.find(msg, "@z")) |
|
|
|
assert(string.find(msg, "@y")) |
|
|
|
error("@x") |
|
|
|
end) |
|
|
|
|
|
|
|
local x1 <close> = |
|
|
|
func2close(function (self, msg) |
|
|
|
checkwarn("@y") |
|
|
|
assert(string.find(msg, "@z")) |
|
|
|
assert(string.find(msg, "@y")) |
|
|
|
end) |
|
|
|
|
|
|
|
local gc <close> = func2close(function () collectgarbage() end) |
|
|
@ -406,8 +367,7 @@ do print("testing errors in __close") |
|
|
|
end |
|
|
|
|
|
|
|
local stat, msg = pcall(foo, false) |
|
|
|
assert(string.find(msg, "@z")) |
|
|
|
checkwarn("@x") |
|
|
|
assert(string.find(msg, "@x")) |
|
|
|
|
|
|
|
|
|
|
|
-- original error not in __close |
|
|
@ -418,14 +378,13 @@ do print("testing errors in __close") |
|
|
|
-- after error, 'foo' was discarded, so caller now |
|
|
|
-- must be 'pcall' |
|
|
|
assert(debug.getinfo(2).name == "pcall") |
|
|
|
assert(msg == 4) |
|
|
|
assert(string.find(msg, "@x1")) |
|
|
|
end) |
|
|
|
|
|
|
|
local x1 <close> = |
|
|
|
func2close(function (self, msg) |
|
|
|
assert(debug.getinfo(2).name == "pcall") |
|
|
|
checkwarn("@y") |
|
|
|
assert(msg == 4) |
|
|
|
assert(string.find(msg, "@y")) |
|
|
|
error("@x1") |
|
|
|
end) |
|
|
|
|
|
|
@ -434,8 +393,7 @@ do print("testing errors in __close") |
|
|
|
local y <close> = |
|
|
|
func2close(function (self, msg) |
|
|
|
assert(debug.getinfo(2).name == "pcall") |
|
|
|
assert(msg == 4) -- error in body |
|
|
|
checkwarn("@z") |
|
|
|
assert(string.find(msg, "@z")) |
|
|
|
error("@y") |
|
|
|
end) |
|
|
|
|
|
|
@ -453,8 +411,7 @@ do print("testing errors in __close") |
|
|
|
end |
|
|
|
|
|
|
|
local stat, msg = pcall(foo, true) |
|
|
|
assert(msg == 4) |
|
|
|
checkwarn("@x1") -- last error |
|
|
|
assert(string.find(msg, "@x1")) |
|
|
|
|
|
|
|
-- error leaving a block |
|
|
|
local function foo (...) |
|
|
@ -466,7 +423,8 @@ do print("testing errors in __close") |
|
|
|
end) |
|
|
|
|
|
|
|
local x123 <close> = |
|
|
|
func2close(function () |
|
|
|
func2close(function (_, msg) |
|
|
|
assert(msg == nil) |
|
|
|
error("@X") |
|
|
|
end) |
|
|
|
end |
|
|
@ -474,9 +432,7 @@ do print("testing errors in __close") |
|
|
|
end |
|
|
|
|
|
|
|
local st, msg = xpcall(foo, debug.traceback) |
|
|
|
assert(string.match(msg, "^[^ ]* @X")) |
|
|
|
assert(string.find(msg, "in metamethod 'close'")) |
|
|
|
checkwarn("@Y") |
|
|
|
assert(string.match(msg, "^[^ ]* @Y")) |
|
|
|
|
|
|
|
-- error in toclose in vararg function |
|
|
|
local function foo (...) |
|
|
@ -486,7 +442,6 @@ do print("testing errors in __close") |
|
|
|
local st, msg = xpcall(foo, debug.traceback) |
|
|
|
assert(string.match(msg, "^[^ ]* @x123")) |
|
|
|
assert(string.find(msg, "in metamethod 'close'")) |
|
|
|
endwarn() |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
@ -511,8 +466,6 @@ end |
|
|
|
|
|
|
|
if rawget(_G, "T") then |
|
|
|
|
|
|
|
warn("@off") |
|
|
|
|
|
|
|
-- memory error inside closing function |
|
|
|
local function foo () |
|
|
|
local y <close> = func2close(function () T.alloccount() end) |
|
|
@ -527,7 +480,7 @@ if rawget(_G, "T") then |
|
|
|
-- despite memory error, 'y' will be executed and |
|
|
|
-- memory limit will be lifted |
|
|
|
local _, msg = pcall(foo) |
|
|
|
assert(msg == 1000) |
|
|
|
assert(msg == "not enough memory") |
|
|
|
|
|
|
|
local close = func2close(function (self, msg) |
|
|
|
T.alloccount() |
|
|
@ -570,7 +523,7 @@ if rawget(_G, "T") then |
|
|
|
end |
|
|
|
|
|
|
|
local _, msg = pcall(test) |
|
|
|
assert(msg == "not enough memory") -- reported error is the first one |
|
|
|
assert(msg == 1000) |
|
|
|
|
|
|
|
do -- testing 'toclose' in C string buffer |
|
|
|
collectgarbage() |
|
|
@ -625,7 +578,6 @@ if rawget(_G, "T") then |
|
|
|
print'+' |
|
|
|
end |
|
|
|
|
|
|
|
warn("@on") |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
@ -655,14 +607,14 @@ end |
|
|
|
|
|
|
|
|
|
|
|
do |
|
|
|
prepwarn() |
|
|
|
|
|
|
|
-- error in a wrapped coroutine raising errors when closing a variable |
|
|
|
local x = 0 |
|
|
|
local co = coroutine.wrap(function () |
|
|
|
local xx <close> = func2close(function () |
|
|
|
local xx <close> = func2close(function (_, msg) |
|
|
|
x = x + 1; |
|
|
|
checkwarn("@XXX"); error("@YYY") |
|
|
|
assert(string.find(msg, "@XXX")) |
|
|
|
error("@YYY") |
|
|
|
end) |
|
|
|
local xv <close> = func2close(function () x = x + 1; error("@XXX") end) |
|
|
|
coroutine.yield(100) |
|
|
@ -670,8 +622,7 @@ do |
|
|
|
end) |
|
|
|
assert(co() == 100); assert(x == 0) |
|
|
|
local st, msg = pcall(co); assert(x == 2) |
|
|
|
assert(not st and msg == 200) -- should get first error raised |
|
|
|
checkwarn("@YYY") |
|
|
|
assert(not st and string.find(msg, "@YYY")) -- should get error raised |
|
|
|
|
|
|
|
local x = 0 |
|
|
|
local y = 0 |
|
|
@ -691,10 +642,8 @@ do |
|
|
|
local st, msg = pcall(co) |
|
|
|
assert(x == 1 and y == 1) |
|
|
|
-- should get first error raised |
|
|
|
assert(not st and string.find(msg, "%w+%.%w+:%d+: XXX")) |
|
|
|
checkwarn("YYY") |
|
|
|
assert(not st and string.find(msg, "%w+%.%w+:%d+: YYY")) |
|
|
|
|
|
|
|
endwarn() |
|
|
|
end |
|
|
|
|
|
|
|
|
|
|
|