Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deepcompare keys #194

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions spec/assertions_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,14 @@ describe("Test Assertions", function()
assert.same(t2, t1)
end)

it("Checks same() assertion handles table keys properly", function()
assert.are.same({ [{}] = 1 }, { [{}] = 1 })
assert.are.not_same({ [{}] = 1 }, { [{}] = 2 })
assert.are.not_same({ }, { [{}] = 2 })
assert.are.not_same({ [{"a"}] = 1 }, { [{"b"}] = 1 })
assert.are.not_same({ [{"a"}] = 1, [{"a"}] = 1 }, { [{"b"}] = 1, [{"a"}] = 1, [{"a"}] = 2 })
end)

it("Checks same() assertion to handle recursive tables", function()
local t1 = { k1 = 1, k2 = 2 }
local t2 = { k1 = 1, k2 = 2 }
Expand All @@ -89,6 +97,17 @@ describe("Test Assertions", function()
assert.same(t1, t3)
end)

it("Checks same() assertion handles table keys with recursion properly", function()
local a = {}
local b = {}
local t1 = { [a] = a }
local t2 = { [b] = a }

assert.are.same(t1, t2)
assert.are.same({ [{ [{}] = 2 }] = 1 }, { [{ [{}] = 2 }] = 1 })
assert.are.not_same({ [{ [{}] = 2 }] = 1 }, { [{ [{}] = 3 }] = 1 })
end)

it("Checks same() assertion to handle recursive tables that don't match", function()
local t1 = {}
local t2 = {}
Expand Down Expand Up @@ -168,6 +187,7 @@ describe("Test Assertions", function()
assert.is_table(c1[2][3][3][3][2][3][3][3][2][3][3][3][2])
assert.is_nil(m1[2][3][3][3][2][3][3][3][2][3][3][3][2])
assert.are_not_same(c1, m1)
assert.are_not_same({ [c1] = 1 }, { [m1] = 1 })
end)

it("Checks to see if tables 1 and 2 are equal", function()
Expand All @@ -192,6 +212,11 @@ describe("Test Assertions", function()
assert.is_not.unique(tablenotunique)
end)

it("Checks to see if table1 only contains unique elements, including keys", function()
assert.is.not_unique({ [{}] = 1, [{}] = 1 }, true)
assert.is.not_unique({{ [{}] = 1 }, { [{}] = 1 }}, true)
end)

it("Checks near() assertion handles tolerances", function()
assert.is.error(function() assert.near(0) end) -- minimum 3 arguments
assert.is.error(function() assert.near(0, 0) end) -- minimum 3 arguments
Expand Down
9 changes: 9 additions & 0 deletions spec/matchers_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,10 @@ describe("Test Matchers", function()
assert.is_false(match.is_same(nil)("a string"))
end)

it("Checks same() matcher to handle table keys properly", function()
assert.is_true(match.is_same({ [{}] = 1 })({ [{}] = 1}))
end)

it("Checks ref() matcher", function()
local t = {}
local func = function() end
Expand Down Expand Up @@ -220,6 +224,11 @@ describe("Test Matchers", function()
assert.is_true(match.is_not.unique()(tablenotunique))
end)

it("Checks to see if table1 only contains unique elements, including table keys", function()
assert.is_true(match.is_not.unique(true)({ [{}] = 1, [{}] = 1 }, true))
assert.is_true(match.is_not.unique(true)({{ [{}] = 1 }, { [{}] = 1 }}, true))
end)

it("Checks '_' chaining of modifiers and match", function()
assert.is_true(match.is_string()("abc"))
assert.is_true(match.is_true()(true))
Expand Down
51 changes: 43 additions & 8 deletions src/util.lua
Original file line number Diff line number Diff line change
Expand Up @@ -40,23 +40,58 @@ function util.deepcompare(t1,t2,ignore_mt,cycles,thresh1,thresh2)
cycles[1][t1] = cycles[1][t1] + 1
cycles[2][t2] = cycles[2][t2] + 1

local table_keys = {{}, {}} -- keys of type 'table' that we'll handle later

for k1,v1 in next, t1 do
local v2 = t2[k1]
if v2 == nil then
if v2 == nil and type(k1) == 'table' then
table.insert(table_keys[1], k1)
elseif v2 == nil then
return false, {k1}
else
local same, crumbs = util.deepcompare(v1,v2,nil,cycles,thresh1,thresh2)
if not same then
crumbs = crumbs or {}
table.insert(crumbs, k1)
return false, crumbs
end
end
end
for k2,_ in next, t2 do
-- only check whether each element has a t1 counterpart, actual comparison
-- has been done in first loop above
if t1[k2] == nil then
if type(k2) == 'table' then
table.insert(table_keys[2], k2)
else
return false, {k2}
end
end
end

local same, crumbs = util.deepcompare(v1,v2,nil,cycles,thresh1,thresh2)
if not same then
crumbs = crumbs or {}
-- try to match up every pair with every other pair. remove a matched pair
-- or fail if no match was found.
for _, k1 in ipairs(table_keys[1]) do
local key_same, value_same = false, false
local key_crumbs, value_crumbs = nil, nil
for j, k2 in ipairs(table_keys[2]) do
key_same, key_crumbs = util.deepcompare(k1, k2, nil, cycles, thresh1, thresh2)
value_same, value_crumbs = util.deepcompare(t1[k1], t2[k2], nil, cycles, thresh1, thresh2)
if key_same and value_same then
table.remove(table_keys[2], j)
break
end
end
if not key_same or not value_same then
local crumbs = key_crumbs or value_crumbs or {}
table.insert(crumbs, k1)
return false, crumbs
end
end
for k2,_ in next, t2 do
-- only check whether each element has a t1 counterpart, actual comparison
-- has been done in first loop above
if t1[k2] == nil then return false, {k2} end

-- check that we've matched all keys from the second table as well
if #table_keys[2] > 0 then
return false, {table_keys[2][1]}
end

cycles[1][t1] = cycles[1][t1] - 1
Expand Down