lunarmodules / luassert Goto Github PK
View Code? Open in Web Editor NEWAssertion library for Lua
License: MIT License
Assertion library for Lua
License: MIT License
Via email:
In the unit testing frameworks I am familiar with, there is usually
functionality for custom output upon failure of an assertion. I am finding
that with my busted assertions, often I am unsure of what input caused the
failure, as I perform a lot of operations like this:
for i = 1, 19 do
local truncated = thingy:pulseTruncate( i )
assert.are.equal( 0, truncated )
end
With the default busted output, I am able to see the invalid return value
that causes the problem, but not which input value caused the problem.
Normally I'd do something like this (pseudocode)
for i = 1, 19 do
local truncated = thingy:pulseTruncate( i )
assert.are.equal({
expect = 0,
actual = truncated,
fail = function()
print("Failed on $i, value of $truncated")
end
})
end
Is this possible with busted? I was unable to find functionality like
this in the documentation or by reviewing the code.
it("tests returning nothing as nil", function()
local f1 = function() return nil end
local f2 = function() return end
assert.is_nil(f1())
assert.is_nil(f2())
end)
fails on the second assertion, becasue f1 returns 1 argument, nil
, f2 returns no arguments.
error message is;
tests returning nothing as nil
spec\state_spec.lua:132: Expected objects to be the same. Passed in:
(nil)
Expected:
type nil
Now the error telling (nil)
was passed in is a bug. What should it return?
Should it pass? (nothing == nil) ?
or should the message make clear that no argument was provided?
I'm a bit new to lua and I'm certain that this probably makes (slightly more) sense to people who do understand the inner workings of lua and luasert, but what I'm running into is inconvenient at best...
when I try to use assert.spy().was_called_with
for a method that's bound with :
, I need to add the object to the obj to was_called_with
as first argument, which makes sense.
but what doesn't make sense is that if the object has been modified between the call and the assert then it fails.
I suspect you have some way to snapshot the arguments being passed in and for a table that means it will think it's a different table being passed in.
this looks like a bug to me, but maybe there's a better way of doing this assertion that doesn't fail, in that case maybe just updating the docs to explain people that would be good enough ;-)
describe("spies", function()
it("replaces an original function", function()
local t = {
defaultmsg = "hiii",
somerandomproperty = true,
}
function t:greet(msg) if msg then print(msg) else print(self.defaultmsg) end end
local s = spy.on(t, "greet")
t:greet("Hey!") -- prints 'Hey!'
assert.spy(t.greet).was_called_with(t, "Hey!")
t:greet("Hey!") -- prints 'Hey!'
-- when touching t the next assert fails
t.somerandomproperty = false
assert.spy(t.greet).was_called_with(t, "Hey!")
end)
end)
it also similarly fails if the mutation it done by the method called, which was ofc my original problem, the above was trying to isolate the problem;
describe("spies", function()
it("replaces an original function", function()
local t = {
cnt = 0,
}
function t:greet(msg)
self.cnt = self.cnt + 1
print(msg)
end
local s = spy.on(t, "greet")
t:greet("Hey!") -- prints 'Hey!'
-- this assert will fail because `t` was touched
assert.spy(s).was_called_with(t, "Hey!")
end)
end)
PS. <3 busted, a light in the dark when learning lua
describe("foo", function()
it("bar", function()
local func = spy.new(function() end);
func();
assert.spy(func).was_not.called();
end)
end)
-
0 successes / 1 failure / 0 errors / 0 pending : 0.0 seconds
Failure  .\tests\foobar_spec.lua @ 2
foo bar
.\tests\foobar_spec.lua:5: Expected not to be called exactly nil time(s), but it was.
When asserting on a table whose metatable has the key __metatable, util.lua will result in an error.
Example:
local troubleSomeTable = {}
setmetatable(troubleSomeTable, {__metatable = 0})
assert.are.same(troubleSomeTable, troubleSomeTable)
It will throw the error: /usr/share/lua/5.1/luassert/util.lua:11: attempt to index local 'mt1' (a number value)
To fix it, getmetatable in util.lua needs to be changed into debug.getmetatable
Hi!
When wrapping a function in Spy, the type of the resulting entity changes to table
. Is it possible to preserve the original type of function when using Spy?
Same behavior when using Mock or Stub
example:
local t = {
some = function () return 42 end
}
local m = mock(t)
assert.is.Function(m.some) -- raise 'type different types'
I'm probably missing something but I can´t see what.
I have downloaded and installed luassert.
I just have an error message:
Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
> require("luassert")
> assert.is.true(true)
stdin:1: '< name >' expected near 'true'
local assert = require "luassert"
assert.same(
{{k = "v1"}, {k = "v2"}},
{{k = "v1"}, {k = "v3"}}
)
currently produces
lua: test.lua:3: Expected objects to be the same.
Passed in:
(table) {
[1] = {
*[k] = 'v1' }
*[2] = {
*[k] = 'v3' } }
Expected:
(table) {
[1] = {
*[k] = 'v1' }
*[2] = {
*[k] = 'v2' } }
Note the incorrect extra asterisks for [1][k]
. They disappear if the keys in the subtables are different.
I have tried the code in the README file, with the addition of a namespace, as per #10:
local assert = require "luassert"
local s = require("say") --our i18n lib, installed through luarocks, included as a luassert dependency
local function has_property(table, prop)
for _, value in pairs(table) do
if value == prop then
return true
end
end
return false, {prop, table}
end
s:set("en", "assertion.has_property.positive", "Expected property %s in:\n%s")
s:set("en", "assertion.has_property.negative", "Expected property %s to not be in:\n%s")
assert:register("assertion", "has_property", has_property, "assertion.has_property.positive", "assertion.has_property.negative")
assert.has_property({ name = "jack" }, "name") -- this should "pass"
assert.has_property({ name = "jack" }, "foo") -- this should "fail"
Unfortunately the error message I get when executing this is empty:
➜ lua lua test_has_property_assertion.lua
lua: /usr/local/share/lua/5.1/luassert/assert.lua:12:
stack traceback:
[C]: in function 'error'
/usr/local/share/lua/5.1/luassert/assert.lua:12: in function 'has_property'
test_has_property_assertion.lua:18: in main chunk
[C]: ?
I expected to see the message "Expected property foo in table #..." somewhere on that text, but it was not.
utils.deepcompare (and hence spy.calledwith) goes into infinite loop if t1 and t2 have references to each other.
I'd argue that the check that assert.same
does for exact type equivalence for table values is unwarranted and results in some unexpected results.
Take the following LuaJIT code. 0ULL
(of type cdata) and 0
(of type number) compare equal, so I'd expect both of the following assertions to pass:
assert.same(0ULL, 0)
assert.same({0ULL}, {0})
In fact, luassert accepts the first and rejects the second.
It doesn't seem like it's possible to test code that branches on a condition like type(x) == "function"
.
For example, the snippet below tests a function example
that branches on that condition:
local function example(arg)
if type(arg) == "function" then
return arg()
end
end
describe("example", function()
it("should handle function arguments", function()
local spy = spy.new(function() end)
example(spy)
assert.spy(spy).was.called()
end)
end)
Since the type()
of a spy is actually "table"
, the test fails with the following output on the spy assertion:
Failure → spec/example_spec.lua @ 8
example should handle function arguments
spec/example_spec.lua:12: Expected to be called >0 time(s), but was called 0 time(s)
Attempts to mock the global type
function to "correctly" return "function"
on spied functions also fail with the validation error thrown here.
Is there a way to bypass the validation error, or is there a better way to go about testing the example function?
For floating point tests, it might be nice to have some kind of
assert.equals_eps(expected, actual, epsilon)
assertion built in.
So I'm turning a real-world bug into a busted test right now, where my input data is a large 2d array. Naively using assert.are.same() leads to a silly amount of output, effectively printing the same giant array twice, in full. I'm settling on rewriting the test like so
for y, row in ipairs(expected) do
for x, cell in ipairs(row) do
print(x, y)
assert.are.same(input[y][x], cell)
end
end
but this is obviously clunky. Since all I need are the differences between each table, it'd be nice to instead have a parameter that just says "elide all unchanged fields below depth N", in the same way deeply nested tables can be elided.
The code sample on the readme includes the following two lines:
s:set("en", "assertion.has_property.positive", "Expected property %s in:\n%s")
s:set("en", "assertion.has_property.negative", "Expected property %s to not be in:\n%s")
Both lines use a variable called 's', which is never initialized or explained.
I would volunteer a pull request, but I'm afraid I honestly don't know what is it supposed to be. Is it the "say" lib, perhaps?
Imagine we have a table City
with the key path City.current.attributes.id = 10
and a function
function isMyCity(my_city_id)
return City.current.attributes.id == my_city_id
end
It would be useful to mock the value of City.current.attributes.id
to test isMyCity
. However luassert only supports mocking for keys which contain functions. Why not allow mocking for keys that contain other values. Such as the number
in our above example.
Looking at the implementation i dont see a reason for this restriction. Is there something im not aware of preventing this?
In my projects I like to write multiple errors in functions, especially for validating arguments. Currently there's no way to pass arguments into a function called with assert.has.error
so it is not possible to test each error message. I would have submitted a pull request, but after reviewing the Guidelines for Contributing I thought I should check with the direction of the project before assuming this is something you would want to include.
The feature is trivial to implement, and I'm already using it in my own projects:
src/assertions.lua: local ok, err_actual = pcall(func, table.unpack(arguments,3,arguments.n))
Hope you agree with it, and thanks!
In my research for this issue on Busted, the direct cause of the output is the decisions by this library to always output crumbs if they exist. For example in my specific case with the table formatter, this bit of code only considers whether the function exists (hard coded directly above) and whether crumbs exist. If they do, it outputs them.
There should be some way to run assert statements such as assert.same()
with an extra argument or after setting some configuration value to suppress the output of crumbs and just get the pass/fail status in return.
Note that referenced code almost certainly isn't the place to fix this, somewhere upstream those formatters are getting called and they should be disabled at the source to suppress even the "Actual/Expected" strings.
Is there a way to create a stub that would return a desired value when stubbed function is called?
local t = {do_something = function(msg) return msg end}
stub(t, "do_something").is_called_with("foo").then_return("bar")
print(t.do_something("foo")) -> prints "bar"
print(t.do_something("bar")) -> prints nothing or nil
or
stub(t, "do_something").is_called_with_any().then_return("bar")
print(t.do_something("foo")) -> prints "bar"
print(t.do_something("bar")) -> prints "bar"
Is it possible to have array include test like follow?
assert.array(a).has(element)
assert.array(a).inlcude(element)
assert.array(a).has_element(element)
Currently I have to write a function include()
local function include(t, element)
for _, v in ipairs(t) do
if v == element then
return true
end
end
return false
end
-- Then:
-- ...
assert.is_true(include(all, agent1))
The examples in the readme and on the homepage are far from exhaustive. Where can I find a complete, exhaustive reference of all functions/assertions/matchers/whatever provided by luassert? Specific case: trying to use assert.are.near()
, not knowing at which position the error/epsilon parameter goes, searching high and low, not finding the answer anywhere. Principally refusing to inspect source code because having to inspect source code in order to learn API is wrong.
Currently an assertion takes 2 parameters
n
field to indicate the number of elements (to take care of nil
values)It returns 1 value; a boolean being true
if the assertion passed
On the side; the in coming arguments list is modified to prepare the arguments for proper display in the output. So actually it returns a second argument, through its second parameter (passed by reference).
imo it should actually get 3 parameters, the last being a (shallow) copy of the arguments table. And it should return 2, the boolean assertion result and an output table, being the modified copy of the arguments table.
having output like this:
./spec/main_spec.lua:146: Expected objects to be the same.
Passed in:
(table): {
[bid] = {
[1] = {
[price] = 105
[quantity] = 3 }
[2] = {
[price] = 102
[quantity] = 2 }
[3] = {
[price] = 100
[quantity] = 1 } }
[key] = 'A:B'
[offer] = {
[1] = {
[price] = 110
[quantity] = 1 }
[2] = {
[price] = 112
[quantity] = 2 }
[3] = {
[price] = 115
[quantity] = 3 } }
[timestamp] = 37230.123456 }
Expected:
(table): {
[bid] = {
[1] = {
[price] = 105
[quantity] = 3 }
[2] = {
[price] = 102
[quantity] = 2 }
[3] = {
[price] = 100
[quantity] = 1 } }
[key] = 'A:B'
[name] = 'l2q'
[offer] = {
[1] = {
[price] = 110
[quantity] = 1 }
[2] = {
[price] = 112
[quantity] = 2 }
[3] = {
[price] = 115
[quantity] = 3 } }
[timestamp] = 37230.123456 }
stack traceback:
./spec/main_spec.lua:146: in function <./spec/main_spec.lua:128>
its hard to understand where is the problem
It would be great to have some pointers on mismatches
for example, smth like this;
./spec/main_spec.lua:146: Expected objects to be the same.
Passed in:
> (table): {
[bid] = {
[1] = {
[price] = 105
[quantity] = 3 }
[2] = {
[price] = 102
[quantity] = 2 }
[3] = {
[price] = 100
[quantity] = 1 } }
[key] = 'A:B'
[offer] = {
[1] = {
[price] = 110
[quantity] = 1 }
[2] = {
[price] = 112
[quantity] = 2 }
[3] = {
[price] = 115
[quantity] = 3 } }
[timestamp] = 37230.123456 }
Expected:
> (table): {
[bid] = {
[1] = {
[price] = 105
[quantity] = 3 }
[2] = {
[price] = 102
[quantity] = 2 }
[3] = {
[price] = 100
[quantity] = 1 } }
[key] = 'A:B'
> [name] = 'l2q'
[offer] = {
[1] = {
[price] = 110
[quantity] = 1 }
[2] = {
[price] = 112
[quantity] = 2 }
[3] = {
[price] = 115
[quantity] = 3 } }
[timestamp] = 37230.123456 }
In example above there is a marker which points to values that are not same:
tables are diferent, and the value of name is different (nil vs 'l2q')
so it becomes very easy to find out problem
I have 2 objects that have a __pairs
metamethod on them.
When I try and use assert.same
on them, they return false, as they don't have an __index
for the 'keys' returned by my __pairs
.
One potential fix is to use next, t
instead of pairs(t)
so that __pairs
is not used.
An alternative solution is to use pairs()
to iterate through each object, building a temporary list of pairs, and then comparing those lists.
When comparing two deep tables and there are minor differences, luassert helpfully marks keys on the path to different value with asterisks, but unhelpfully applies depth limit anyway, replacing subtables with { ... more }
. It would be nice if depth limit wasn't applied to values marked with crumbs.
Lets see and example:
local Foo = {}
function Foo:add(Bar)
Bar.callback(self)
self.bar = Bar
end
local Bar = {}
function Bar.callback() end
describe('Foo', function()
it(':add() calls Bar.callback()', function()
local s = spy.on(Bar, 'callback')
Foo:add(Bar) -- make a deep copy of Foo, before Foo.bar sets to Bar
assert.spy(s).was.called(1) -- OK
assert.spy(s).was.called_with(Foo) -- Failure, because Foo modified after callback...
end)
end)
assert.spy(s).was.called_with(Foo)
Failure because the Foo
was not same as FooCopy
.So, I think it is needs that we have option in spy
or called_with
just keep a reference to its calling args and compare args by ==
(or something else).
I think the easiest way to explain this is with an example:
Let us assume I have the following object.
local MyObject = { name = 'default' }
-- A method that will be stubbed.
function MyObject:mock_method( arg1 ) end
Now we add a method to MyObject
that will first make a call to the stub, then change the value of the 'name' field.
function MyObject:do_something_to_change_state()
-- First call the mocked method which will store a deep
-- copy of "self" when self.name == 'default'
self:mock_method( "hello" )
self.mock_method( self, 'hello')
-- Then change self.name to a new value.
self.name = "Hey! I'm Different"
end
Later in a test we stub out mock_method
and attempt to assert that it was called on the table referenced by MyObject
.
stub( MyObject, 'mock_method')
MyObject:do_something_to_change_state()
-- This assertion fails because the first argument's name field still equals 'default'
-- and MyObject.name == "Hey! I'm Different" instead of 'default'
assert.stub( MyObject.mock_method ).was.called_with( MyObject )
The assertion will fail because the call history made a deep copy of MyObject when MyObject was in a different state.
I don't really have any ideas how to work around this. I feel like in every other case I would absolutely want the state to be copied for deep comparison.
I could always just say "I don't care" about the first argument but that solution feels unsatisfactory. Do you have any ideas on how I could go about dealing with this case?
I've discovered that luassert 1.7.7
(pulled in by busted
) caused a regression with make check
for awesomeWM (initially reported at awesomeWM/awesome#258).
TEST CASE:
(make sure to have busted and luassert >= 1.7.7 installed)
I have not checked if it's fixed in Git. Using luassert 1.7.6 works.
Plain assert does not currently pass it's arguments on.
I found out while trying to use a library that uses assert internally:
Eg, the code below exhibits the problem:
function foo()
if something then
return nil , "error message"
else
return "abc" , "xyz"
end
end
local x1, x2 = assert ( foo() ) -- With luassert x2 is nil.
Fix requires rewriting the function at https://github.com/Olivine-Labs/luassert/blob/2faa83264eb0439bd2772d80bfd4ce8198986105/src/assert.lua#L155
Example:
return require"luassert".are.equal("a\rb", "\r")
Expected objects to be equal.
Passed in:
'string) '
Expected:
b'tring) 'a
stack traceback:
[C]: in function 'error'
...luarocks/2.4.2_5.1/share/lua/5.1/luassert/assert.lua:51: in function <...luarocks/2.4.2_5.1/share/lua/5.1/luassert/assert.lua:25>
(tail call): ?
[C]: ?
Expected results (or similar, just something else than writing on top of the output):
return require"luassert".are.equal("a\rb", "\r")
Expected objects to be equal.
Passed in:
(string) '
'
Expected:
(string) 'a
b'
stack traceback:
[C]: in function 'error'
...luarocks/2.4.2_5.1/share/lua/5.1/luassert/assert.lua:51: in function <...luarocks/2.4.2_5.1/share/lua/5.1/luassert/assert.lua:25>
(tail call): ?
[C]: ?
This seems to come from Lua interpreter:
> = "a\rb"
b
Actually from terminal.
At line 328, the longkey
maybe wrong in further iterations.
For example: if the tokens
is {'is', 'match', 'error'}
, the longkey
variable will be match_match_error
at the second iteration in the inner while loop. So it may fail to get the longest matching key when the key has three or more words.
Here is the potential fix which I brought up:
- longkey = (token .. '_' .. key)
+ longkey = i > 1 and (tokens[i-1] .. '_' .. key) or key
@DorianGray any chance to get a release?
we'd really like to get #144 out so we can clean up our ugly hacks to work around it
Lua 5.2.2 has a check in table.insert
so it's imposible to insert outside the array part:
table.insert({}, 2, false) -- OK on Lua 5.1/Lua 5.2.1/LuaJIT, error on Lua 5.2.2
This may lead to errors here under Lua 5.2.2. In particular, it makes a few tests from busted spec fail.
As a side note, it would be nice to have at least automated testing on travis for Lua 5.2. I've made a script to help testing in several environments; here is example usage.
Edit: this only happens with Lua >= 5.2.2
I'm testing code which uses the common
ok, retval = func( ... )
paradigm, where retval
is an error message/object if ok
is false. Just as with error messages tossed via exceptions (and handled by has_error
) it would be nice to be able to compare the result with a match rather than an exact equality, e.g.
assert.are.matches( '.*: missing file', retval )
Thanks for a great testing framework!
Diab
When using assert spy to check function call with defined arguments, a wrong argument is not displayed. Test example:
it("#42 lua assert spy test", function()
local someTableWithFunc = {foo = function(myArg)end}
spy.on(someTableWithFunc, "foo")
someTableWithFunc.foo(2)
assert.spy(someTableWithFunc.foo).was_called_with(1)
end)
The following error is displayed:
$ busted -t 42
0 successes / 1 failure / 0 errors / 0 pending : 0.077245 seconds
Failure → spec/takeawayDischarger_spec.lua @ 390
Takeaway discharger construction Unit test #42 lua assert spy test
spec/takeawayDischarger_spec.lua:394: Function was not called with the arguments
Hi there!
I was playing around with busted for a project I'm working on. I have a use-case for something like the following:
assert.eventually(f).returns(x)
That is, a way to provide a function that is repeatedly called at some cadence, until the provided function returns an expected result. Specifically in my case, I wanted to assert that after starting a subprocess I expect that process to eventually exist on my system. Then when I issue a kill I expect that process to die eventually.
Other similar test frameworks, such as ginkgo
in the go ecosystem, have support for something like Eventually(f).Should(Equal(x))
. This is useful for firing off async instructions and waiting for a thing to happen.
I would suggest, as with ginkgo, that the timeout and check interval of eventually be configurable and default to a timeout of 1 second and a interval of 50 milliseconds (where the platform supports it). This could be implemented as optional arguments to the eventually matcher or as additional words for a more natural read. For example:
assert.eventually(f, 10, 0.1).returns(x)
assert.eventually(f).within(10).every(0.01).returns(x)
I'm not sure how controversial a suggestion this is, so here's more controversy. Maybe we could provide a more human readable experience for the optional args:
assert.eventually(f).within("10s").every("100ms").returns(x)
If the idea above is well received, I'm happy to also provide a PR for something like:
assert.consistently(f).returns(x)
The usage here would be similar to the above.
I'm happy to PR all of the above - let me know what you think!
Thanks!
I'd like to store a value, and then have other elements in the chain act on that value.
Example;
local r = http:get( ... some request ...)
assert.response(r).has.status(200)
local value = assert.response(r).has.header("Content-Length")
assert.are.equal(123, value)
So basically status
and header
assertions (which I can write myself and add to luassert) would operate on the value provided by the response
modifier.
It's related to/prerequisite for #135 I think
I tried to add a value to the state
parameter that is passed along the chain, but is was unreliable due to all the meta-table magic the state
object has. So I ended up with an ugly wrapper on assert
that would reset a custom state table (upvalue) on each call, and the modifiers storing data in that upvalue.
What would be the right approach to implement this?
Quite common we need to validate behaviour by checking log files. Some helper assertions would be nice.
Issues:
local logfile = require "luassert.logfile"
it("checks a log file", function()
local log = logfile("./logs/error.log") -- sets a start marker (file size?), should not fail if file doesn't exist
-- do stuff
assert.logfile(log).exists()
assert.logfile(log).contains("some Lua pattern", [occurrences])
end)
It would be useful to have an is_calleable
assertion that tests whether is_function(argument)
or is_function(debug.getmetatable(argument)._call)
.
I am testing lua tables and decoded json output for REST APIs
and my tests keep failing because of table ordering. especially those without keys (AKA arrays)
I tried .same
and .equals
and I am getting same behavior
is there a better assertion function I could use ?
even, sometimes, the tables looks exactly the same...
Passed in:
(table) {
[1] = 'dev'
[2] = 'test' }
Expected:
(table) {
[1] = 'dev'
[2] = 'test' }
thanks
assert.true
assert.false
should be
assert.True
assert.False
In this example text not implemented
does not appear in output. So we can not figure out why test fails.
local function foo() return nil, 'not implemented' end
assert.is_true(foo())
i need to make a stub for a function and use it in some tests, and then use function as normal. It may look like:
Describe A
Setup A
stub(f_A)
It A
f_A()
Describe B
It B
f_A()
Now, then i run It B
the stub is called, not a real function. So is there a way to make stub local to block or to destroy it?
moved from lunarmodules/busted#78
The current implementation of util.deepcompare
has a result that is counter-intuitive (to me) in the following case:
local foo = {4}
local bar = {4}
local mt = {}
local function always_true()
return true
end
mt.__eq = always_true
setmetatable(foo, mt)
According to util.deepcompare
, foo
and bar
are the same, but that seems wrong. (They don't both have the same metatable. bar
has no metatable at all.) The problem comes in the fourth line here in util.deepcompare
:
local mt1 = debug.getmetatable(t1)
local mt2 = debug.getmetatable(t2)
-- would equality be determined by metatable __eq?
if mt1 and mt1 == mt2 and mt1.__eq then
-- then use that unless asked not to
if not ignore_mt then return t1 == t2 end
else -- we can skip the deep comparison below if t1 and t2 share identity
if t1 == t2 then return true end
end
Because the two tables do not have equal metatables, they are not compared using ==
. Instead, they are handed off to the key, value checking further down. Since they both have the same single item—4—they appear the same by those sorts of checks.
This may be a judgment call, but util.deepcompare
seems to me to give the wrong result. If two tables are being compared, and one has a metatable and the other doesn't, then that very fact means they are not (at a deep level) the same. underscore and cwtest would consider foo and bar different because they handle the metatable branch the following way:
-- cwtest
local mt = getmetatable(t1)
if mt and mt.__eq then return t1 == t2 end
-- underscore
local mt = getmetatable(o1)
if not ignore_mt and mt and mt.__eq then return o1 == o2 end
Sorry for the novel, but I wanted to see if the result was expected by you before making a PR to change anything. Thanks.
Edit: After thinking this over, I now think it's even more complicated. util.deepcompare
is wrong to consider foo
and bar
the same table, but underscore and cwtest have a parallel problem. In their case, the problem is about order: what if the second (but not the first) table has a metatable with .__eq
? Their way of handling things won't detect this, and they will wrongly call two subtly different tables the same.
So the full logic should be this:
local mt1 = getmetatable(t1)
local mt2 = getmetatable(t2)
if (mt1 and mt1.__eq) or (mt2 and mt2.__eq) then
return t1 == t2
end
The mock
function modifies a table in-place but provides no method of de-mocking it. Thus if you wish to re-use a table you must duplicate it and mock that instead.
This is in contrast to spies and stubs both of which have a revert
method
Hello, it would be nice to release a new version, e.g. so that it had #50 fixed.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.