bluebird75 / luaunit

LuaUnit is a popular unit-testing framework for Lua, with an interface typical of xUnit libraries (Python unittest, Junit, NUnit, ...). It supports several output formats (Text, TAP, JUnit, ...) to be used directly or work with Continuous Integration platforms (Jenkins, Maven, ...).
Other
572 stars 137 forks source link

assertIs()/assertNotIs() may cause error when failing in comparing tables with protected metatables #118

Closed seahorse47 closed 5 years ago

seahorse47 commented 5 years ago

I use assertIs()/assertNotIs() to verify if two object references (actually two tables with protected metatables) are the same / different. When it fails, I get error cannot change a protected metatable in _table_raw_tostring() function. This is caused by prettystrPairs() function calls when assertIs()/assertNotIs() fails. Here is the example code:

local lu = require "luaunit"

-- To make it easier to reproduce this error, enable `PRINT_TABLE_REF_IN_ERROR_MSG`
lu.PRINT_TABLE_REF_IN_ERROR_MSG = true

local Object = {}
function Object:new(...)
    return setmetatable({
        class = self,
    }, {
        __metatable = "private",
        __index = self,
    })
end

function testA()
    local obj1 = Object:new()
    local obj2 = Object:new()
    lu.assertIs(obj1, obj2) -- will fail
end

local runner = lu.LuaUnit.new()
runner:setOutputType("text")
os.exit(runner:runSuite())

P.S. When I use assertIs() on tables, I don't really care about the contents in the tables. I do only care whether they are the same. assertEquals() may be a better choice when I care about the contents.Is it possible to show only table references in fail messages of assertIs()/assertNotIs()?

bluebird75 commented 5 years ago

Thanks for the report and the Pull Request. I am quite slow those days to react, sorry for that. I need more time to understand the proposal because it touches parts of the code which I have not written myself.

I'll let you know of the progress.

bluebird75 commented 5 years ago

Ok, I get it. The misbehaving code was trying to get the reference value of the table, when the metatable has a tostring(). Now the question is: how do I obtain the reference of a table, whose metatable is both protected and contains a tostring() converter ?

I don't see how to do that right now, but in the meantime, I can still fix your reported bug.

Thanks a lot.

bluebird75 commented 5 years ago

fixed in 2d85352c92303a4032ff5fbde782cb9e765c3f9d