Tarantool development patches archive
 help / color / mirror / Atom feed
From: olegrok@tarantool.org
To: tarantool-patches@dev.tarantool.org, imun@tarantool.org,
	v.shpilevoy@tarantool.org
Cc: Oleg Babin <babinoleg@mail.ru>
Subject: [Tarantool-patches] [PATCH 3/3] tap: is_deeply ignores __pairs metamethod
Date: Thu, 13 Feb 2020 23:33:53 +0300	[thread overview]
Message-ID: <9330b681273b2789ff147d5769736406695ca23a.1581625524.git.babinoleg@mail.ru> (raw)
In-Reply-To: <cover.1581625524.git.babinoleg@mail.ru>

From: Oleg Babin <babinoleg@mail.ru>

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

  parent reply	other threads:[~2020-02-13 20:34 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-02-13 20:33 [Tarantool-patches] [PATCH 0/3] lua: table fixes olegrok
2020-02-13 20:33 ` [Tarantool-patches] [PATCH 1/3] lua: fix incorrect table.deepcopy __metatable handling olegrok
2020-02-13 22:50   ` Vladislav Shpilevoy
2020-02-20 11:12   ` Igor Munkin
2020-02-13 20:33 ` [Tarantool-patches] [PATCH 2/3] lua: table.deepcopy ignores __pairs metamethod olegrok
2020-02-13 22:50   ` Vladislav Shpilevoy
2020-02-20 11:00   ` Igor Munkin
2020-02-13 20:33 ` olegrok [this message]
2020-02-13 22:50   ` [Tarantool-patches] [PATCH 3/3] tap: is_deeply " Vladislav Shpilevoy
2020-02-20 10:57   ` Igor Munkin
2020-02-13 22:50 ` [Tarantool-patches] [PATCH 0/3] lua: table fixes Vladislav Shpilevoy
2020-02-15 10:05   ` Oleg Babin
2020-02-15 15:35     ` Vladislav Shpilevoy

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=9330b681273b2789ff147d5769736406695ca23a.1581625524.git.babinoleg@mail.ru \
    --to=olegrok@tarantool.org \
    --cc=babinoleg@mail.ru \
    --cc=imun@tarantool.org \
    --cc=tarantool-patches@dev.tarantool.org \
    --cc=v.shpilevoy@tarantool.org \
    --subject='Re: [Tarantool-patches] [PATCH 3/3] tap: is_deeply ignores __pairs metamethod' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox