From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtp48.i.mail.ru (smtp48.i.mail.ru [94.100.177.108]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id 7CFE54696C3 for ; Thu, 13 Feb 2020 23:34:12 +0300 (MSK) From: olegrok@tarantool.org Date: Thu, 13 Feb 2020 23:33:53 +0300 Message-Id: <9330b681273b2789ff147d5769736406695ca23a.1581625524.git.babinoleg@mail.ru> In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Subject: [Tarantool-patches] [PATCH 3/3] tap: is_deeply ignores __pairs metamethod List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: tarantool-patches@dev.tarantool.org, imun@tarantool.org, v.shpilevoy@tarantool.org Cc: Oleg Babin From: Oleg Babin After 1d85144a9b4bbbb026402848efde1ab98bf72633 is_deeply could use __pairs metamethod when iterated through tables. It led to situation when two similar tables could be considered as different. To eliminate such situation default pairs was replaced with "pure" pairs that ignores __pairs metamethod Follow-up #4770, #4560 --- src/lua/tap.lua | 9 ++++++--- test/app-tap/tap.result | 6 ++++-- test/app-tap/tap.test.lua | 24 +++++++++++++++++++++++- 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/lua/tap.lua b/src/lua/tap.lua index 94b080d5a..23ca79f0b 100644 --- a/src/lua/tap.lua +++ b/src/lua/tap.lua @@ -77,7 +77,10 @@ local function skip(test, message, extra) end -local nan = 0/0 +-- This pairs implementation doesn't trigger __pairs metamethod +local function internal_pairs(tbl) + return next, tbl, nil +end local function cmpdeeply(got, expected, extra) if type(expected) == "number" or type(got) == "number" then @@ -107,7 +110,7 @@ local function cmpdeeply(got, expected, extra) local path = extra.path or '/' local visited_keys = {} - for i, v in pairs(got) do + for i, v in internal_pairs(got) do visited_keys[i] = true extra.path = path .. '/' .. i if not cmpdeeply(v, expected[i], extra) then @@ -116,7 +119,7 @@ local function cmpdeeply(got, expected, extra) end -- check if expected contains more keys then got - for i, v in pairs(expected) do + for i, v in internal_pairs(expected) do if visited_keys[i] ~= true and (extra.strict or v ~= box.NULL) then extra.expected = 'key ' .. tostring(i) extra.got = 'nil' diff --git a/test/app-tap/tap.result b/test/app-tap/tap.result index 12bf86ec2..ecfdf11d1 100644 --- a/test/app-tap/tap.result +++ b/test/app-tap/tap.result @@ -137,7 +137,7 @@ not ok - failed subtests failed: 1 ... # is_deeply - 1..20 + 1..22 ok - 1 and 1 ok - abc and abc ok - empty tables @@ -203,10 +203,12 @@ not ok - failed subtests strict: true ... ok - {a = box.NULL} and {a = box.NULL} strict true + ok - is_deeply ignores __pairs metamethod + ok - is_deeply ignores __pairs metamethod # is_deeply: end not ok - failed subtests --- - planned: 20 + planned: 22 failed: 8 ... # like diff --git a/test/app-tap/tap.test.lua b/test/app-tap/tap.test.lua index e2a78f630..757781636 100755 --- a/test/app-tap/tap.test.lua +++ b/test/app-tap/tap.test.lua @@ -131,7 +131,7 @@ end) test:test('is_deeply', function(t) - t:plan(20) + t:plan(22) t:is_deeply(1, 1, '1 and 1') t:is_deeply('abc', 'abc', 'abc and abc') @@ -166,6 +166,28 @@ test:test('is_deeply', function(t) t:is_deeply({a = box.NULL}, {a = box.NULL}, '{a = box.NULL} and {a = box.NULL} strict true') t.strict = false + + -- + -- gh-4770: is_deeply uses __pairs for iteration through the table. + -- + local original = { a = 1, b = 2 } + + local function custom_pairs(self) + local function step(tbl, k) + local k, v = next(tbl, k) + if v ~= nil then + v = v + 1 + end + return k, v + end + return step, self, nil + end + + setmetatable(original, {__pairs = custom_pairs }) + t:is_deeply(original, {a = 1, b = 2}, + 'is_deeply ignores __pairs metamethod') + t:is_deeply({a = 1, b = 2}, original, + 'is_deeply ignores __pairs metamethod') end) -- 2.23.0