Tarantool development patches archive
 help / color / mirror / Atom feed
* [tarantool-patches] [PATCH] lua: show locals when a tap test fails
@ 2018-08-18 12:36 Alexander Turenko
  2018-08-19 15:35 ` [tarantool-patches] " Alexander Turenko
  2018-08-24 12:25 ` Vladislav Shpilevoy
  0 siblings, 2 replies; 9+ messages in thread
From: Alexander Turenko @ 2018-08-18 12:36 UTC (permalink / raw)
  To: Vladislav Shpilevoy, Eugine Blikh; +Cc: Alexander Turenko, tarantool-patches

Fixes #3627.
---

branch: Totktonada/gh-3627-tap-show-local-variables
travis-ci: https://travis-ci.org/tarantool/tarantool/builds/417616160
issue: https://github.com/tarantool/tarantool/issues/3627

 src/lua/tap.lua           | 45 ++++++++++++++++++++++++++++++++++-----
 test/app-tap/tap.result   | 26 ++++++++++++++++++++--
 test/app-tap/tap.test.lua | 21 +++++++++++++++---
 3 files changed, 82 insertions(+), 10 deletions(-)

diff --git a/src/lua/tap.lua b/src/lua/tap.lua
index edc9f2211..9dd531422 100644
--- a/src/lua/tap.lua
+++ b/src/lua/tap.lua
@@ -1,6 +1,6 @@
 --- tap.lua internal file
 ---
---- The Test Anything Protocol vesion 13 producer
+--- The Test Anything Protocol version 13 producer
 ---
 
 -- yaml formatter must be able to encode any Lua variable
@@ -36,12 +36,43 @@ local function traceback(level)
     return trace
 end
 
+local function locals(test, level)
+    level = level or 3
+    local variables = {}
+    local idx = 1
+    while true do
+      local name, value = debug.getlocal(level, idx)
+      if name ~= nil then
+          -- compare a table with a tuple raises an error, so we check types
+          -- first
+          local eq = type(value) == type(test) and value == test
+          -- temporary values start with '('
+          if not name:startswith('(') and not eq then
+              variables[name] = value
+          end
+      else
+          break
+      end
+      idx = 1 + idx
+    end
+    return variables
+end
+
 local function diag(test, fmt, ...)
     io.write(string.rep(' ', 4 * test.level), "# ", string.format(fmt, ...),
         "\n")
 end
 
-local function ok(test, cond, message, extra)
+local function ok(test, cond, message, extra, opts)
+    opts = opts or {}
+    local show_locals
+    if opts.locals ~= nil then
+        show_locals = opts.locals
+    elseif test.locals ~= nil then
+        show_locals = test.locals
+    else
+        show_locals = true
+    end
     test.total = test.total + 1
     io.write(string.rep(' ', 4 * test.level))
     if cond then
@@ -58,6 +89,9 @@ local function ok(test, cond, message, extra)
         extra.filename = extra.trace[#extra.trace].filename
         extra.line = extra.trace[#extra.trace].line
     end
+    if show_locals then
+        extra.locals = locals(test)
+    end
     if next(extra) == nil then
         return false -- don't have extra information
     end
@@ -221,6 +255,7 @@ local function test(parent, name, fun, ...)
         failed  = 0;
         planned = 0;
         trace   = parent == nil and true or parent.trace;
+        locals  = parent == nil and true or parent.locals;
     }, test_mt)
     if fun ~= nil then
         test:diag('%s', test.name)
@@ -245,7 +280,7 @@ local function check(test)
     if test.planned ~= test.total then
         if test.parent ~= nil then
             ok(test.parent, false, "bad plan", { planned = test.planned;
-                run = test.total})
+                run = test.total}, {locals = false})
         else
             diag(test, string.format("bad plan: planned %d run %d",
                 test.planned, test.total))
@@ -255,13 +290,13 @@ local function check(test)
             ok(test.parent, false, "failed subtests", {
                 failed = test.failed;
                 planned = test.planned;
-            })
+            }, {locals = false})
         else
             diag(test, "failed subtest: %d", test.failed)
         end
     else
         if test.parent ~= nil then
-            ok(test.parent, true, test.name)
+            ok(test.parent, true, test.name, {locals = false})
         end
     end
     return test.planned == test.total and test.failed == 0
diff --git a/test/app-tap/tap.result b/test/app-tap/tap.result
index 3e7882331..36caa3023 100644
--- a/test/app-tap/tap.result
+++ b/test/app-tap/tap.result
@@ -1,5 +1,5 @@
 TAP version 13
-1..32
+1..33
 ok - true
 ok - extra information is not printed on success
 not ok - extra printed using yaml only on failure
@@ -148,4 +148,26 @@ not ok - failed subtests
     ok - unlike(abcde, acd)
     # like: end
 ok - like
-# failed subtest: 15
+    # locals
+    1..1
+        # locals nested
+        1..2
+        ok - locals are not printed in case of success
+        not ok - locals are printed in case of fail
+          ---
+          locals:
+            a: 42
+          ...
+        # locals nested: end
+    not ok - failed subtests
+      ---
+      planned: 2
+      failed: 1
+      ...
+    # locals: end
+not ok - failed subtests
+  ---
+  planned: 1
+  failed: 1
+  ...
+# failed subtest: 16
diff --git a/test/app-tap/tap.test.lua b/test/app-tap/tap.test.lua
index 0e1de7f1c..29dc0b100 100755
--- a/test/app-tap/tap.test.lua
+++ b/test/app-tap/tap.test.lua
@@ -12,15 +12,16 @@ local tap = require "tap"
 -- Create a root test
 --
 test = tap.test("root test")
--- Disable stack traces for this test because Tarantool test system also
--- checks test output.
+-- Disable stack traces and locals for this test because Tarantool test system
+-- also checks test output.
 test.trace = false
+test.locals = false
 
 --
 -- ok, fail and skip predicates
 --
 
-test:plan(32) -- plan to run 3 test
+test:plan(33) -- plan to run 3 test
 test:ok(true, 'true') -- basic function
 local extra = { state = 'some userful information to debug on failure',
         details = 'a table argument formatted using yaml.encode()' }
@@ -136,6 +137,20 @@ test:test('like', function(t)
     t:unlike('abcde', 'acd', 'unlike(abcde, acd)')
 end)
 
+-- The test case implicitly checks that locals will not be printed while
+-- checking the plan.
+test:test('locals', function(t)
+    t.locals = true
+    t:plan(1)
+    t:test('locals nested', function(t)
+        local a = 42
+        local tuple = box.tuple.new({})
+        t:plan(2)
+        t:ok(true, 'locals are not printed in case of success')
+        t:fail('locals are printed in case of fail')
+    end)
+end)
+
 --
 -- Finish root test. Since we used non-callback variant, we have to
 -- call check explicitly.
-- 
2.17.1

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2018-10-20 18:36 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-08-18 12:36 [tarantool-patches] [PATCH] lua: show locals when a tap test fails Alexander Turenko
2018-08-19 15:35 ` [tarantool-patches] " Alexander Turenko
2018-08-19 15:36   ` Alexander Turenko
2018-08-24 12:25 ` Vladislav Shpilevoy
2018-08-24 12:51   ` Vladislav Shpilevoy
2018-09-23 17:59   ` Alexander Turenko
2018-09-24 10:47     ` Vladislav Shpilevoy
2018-09-27  0:45       ` Alexander Turenko
2018-10-20 18:36         ` Alexander Turenko

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