]> granicus.if.org Git - vim/commitdiff
patch 8.2.1304: debug backtrace isn't tested much v8.2.1304
authorBram Moolenaar <Bram@vim.org>
Mon, 27 Jul 2020 17:47:07 +0000 (19:47 +0200)
committerBram Moolenaar <Bram@vim.org>
Mon, 27 Jul 2020 17:47:07 +0000 (19:47 +0200)
Problem:    Debug backtrace isn't tested much.
Solution:   Add more specific tests. (Ben Jackson, closes #6540)

src/testdir/runtest.vim
src/testdir/test_debugger.vim
src/version.c

index 3cf2a506c975e470305101a7222f3e836ebf1c87..6cc7202dc7037fb73fcc3090ddaf89b118f8a043 100644 (file)
@@ -13,6 +13,9 @@
 " For csh:
 "     setenv TEST_FILTER Test_channel
 "
+" While working on a test you can make $TEST_NO_RETRY non-empty to not retry:
+"     export TEST_NO_RETRY=yes
+"
 " To ignore failure for tests that are known to fail in a certain environment,
 " set $TEST_MAY_FAIL to a comma separated list of function names.  E.g. for
 " sh/bash:
@@ -440,9 +443,11 @@ for g:testfunc in sort(s:tests)
   call RunTheTest(g:testfunc)
 
   " Repeat a flaky test.  Give up when:
+  " - $TEST_NO_RETRY is not empty
   " - it fails again with the same message
   " - it fails five times (with a different message)
   if len(v:errors) > 0
+        \ $TEST_NO_RETRY == ''
         \ && (index(s:flaky_tests, g:testfunc) >= 0
         \      || g:test_is_flaky)
     while 1
index a99154a5af19c9ff30a341a260053b04f3a85aff..e019617e685d570b25adcc7b45459573f0320b77 100644 (file)
@@ -4,6 +4,19 @@ source shared.vim
 source screendump.vim
 source check.vim
 
+func CheckDbgOutput(buf, lines, options = {})
+  " Verify the expected output
+  let lnum = 20 - len(a:lines)
+  for l in a:lines
+    if get(a:options, 'match', 'equal') ==# 'pattern'
+      call WaitForAssert({-> assert_match(l, term_getline(a:buf, lnum))}, 200)
+    else
+      call WaitForAssert({-> assert_equal(l, term_getline(a:buf, lnum))}, 200)
+    endif
+    let lnum += 1
+  endfor
+endfunc
+
 " Run a Vim debugger command
 " If the expected output argument is supplied, then check for it.
 func RunDbgCmd(buf, cmd, ...)
@@ -11,12 +24,11 @@ func RunDbgCmd(buf, cmd, ...)
   call TermWait(a:buf)
 
   if a:0 != 0
-    " Verify the expected output
-    let lnum = 20 - len(a:1)
-    for l in a:1
-      call WaitForAssert({-> assert_equal(l, term_getline(a:buf, lnum))}, 200)
-      let lnum += 1
-    endfor
+    let options = #{match: 'equal'}
+    if a:0 > 1
+      call extend(options, a:2)
+    endif
+    call CheckDbgOutput(a:buf, a:1, options)
   endif
 endfunc
 
@@ -315,3 +327,431 @@ func Test_Debugger()
 
   call delete('Xtest.vim')
 endfunc
+
+func Test_Backtrace_Through_Source()
+  CheckRunVimInTerminal
+
+  let file1 =<< trim END
+    func SourceAnotherFile()
+      source Xtest2.vim
+    endfunc
+
+    func CallAFunction()
+      call SourceAnotherFile()
+      call File2Function()
+    endfunc
+
+    func GlobalFunction()
+      call CallAFunction()
+    endfunc
+  END
+  call writefile(file1, 'Xtest1.vim')
+
+  let file2 =<< trim END
+    func DoAThing()
+      echo "DoAThing"
+    endfunc
+
+    func File2Function()
+      call DoAThing()
+    endfunc
+
+    call File2Function()
+  END
+  call writefile(file2, 'Xtest2.vim')
+
+  let buf = RunVimInTerminal('-S Xtest1.vim', {})
+
+  call RunDbgCmd(buf,
+                \ ':debug call GlobalFunction()',
+                \ ['cmd: call GlobalFunction()'])
+  call RunDbgCmd(buf, 'step', ['line 1: call CallAFunction()'])
+
+  call RunDbgCmd(buf, 'backtrace', ['>backtrace',
+                                    \ '->0 function GlobalFunction',
+                                    \ 'line 1: call CallAFunction()'])
+
+  call RunDbgCmd(buf, 'step', ['line 1: call SourceAnotherFile()'])
+  call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim'])
+
+  call RunDbgCmd(buf, 'backtrace', ['>backtrace',
+                                    \ '  2 function GlobalFunction[1]',
+                                    \ '  1 CallAFunction[1]',
+                                    \ '->0 SourceAnotherFile',
+                                    \ 'line 1: source Xtest2.vim'])
+
+  " Step into the 'source' command. Note that we print the full trace all the
+  " way though the source command.
+  call RunDbgCmd(buf, 'step', ['line 1: func DoAThing()'])
+  call RunDbgCmd(buf, 'backtrace', [
+        \ '>backtrace',
+        \ '  3 function GlobalFunction[1]',
+        \ '  2 CallAFunction[1]',
+        \ '  1 SourceAnotherFile[1]',
+        \ '->0 script ' .. getcwd() .. '/Xtest2.vim',
+        \ 'line 1: func DoAThing()'])
+
+  " step until we have another meaninfgul trace
+  call RunDbgCmd(buf, 'step', ['line 5: func File2Function()'])
+  call RunDbgCmd(buf, 'step', ['line 9: call File2Function()'])
+  call RunDbgCmd(buf, 'backtrace', [
+        \ '>backtrace',
+        \ '  3 function GlobalFunction[1]',
+        \ '  2 CallAFunction[1]',
+        \ '  1 SourceAnotherFile[1]',
+        \ '->0 script ' .. getcwd() .. '/Xtest2.vim',
+        \ 'line 9: call File2Function()'])
+
+  call RunDbgCmd(buf, 'step', ['line 1: call DoAThing()'])
+  call RunDbgCmd(buf, 'step', ['line 1: echo "DoAThing"'])
+  call RunDbgCmd(buf, 'backtrace', [
+        \ '>backtrace',
+        \ '  5 function GlobalFunction[1]',
+        \ '  4 CallAFunction[1]',
+        \ '  3 SourceAnotherFile[1]',
+        \ '  2 script ' .. getcwd() .. '/Xtest2.vim[9]',
+        \ '  1 function File2Function[1]',
+        \ '->0 DoAThing',
+        \ 'line 1: echo "DoAThing"'])
+
+  " Now, step (back to Xfile1.vim), and call the function _in_ Xfile2.vim
+  call RunDbgCmd(buf, 'step', ['line 1: End of function'])
+  call RunDbgCmd(buf, 'step', ['line 1: End of function'])
+  call RunDbgCmd(buf, 'step', ['line 10: End of sourced file'])
+  call RunDbgCmd(buf, 'step', ['line 1: End of function'])
+  call RunDbgCmd(buf, 'step', ['line 2: call File2Function()'])
+  call RunDbgCmd(buf, 'backtrace', [
+        \ '>backtrace',
+        \ '  1 function GlobalFunction[1]',
+        \ '->0 CallAFunction',
+        \ 'line 2: call File2Function()'])
+
+  call RunDbgCmd(buf, 'step', ['line 1: call DoAThing()'])
+  call RunDbgCmd(buf, 'backtrace', [
+        \ '>backtrace',
+        \ '  2 function GlobalFunction[1]',
+        \ '  1 CallAFunction[2]',
+        \ '->0 File2Function',
+        \ 'line 1: call DoAThing()'])
+
+  call StopVimInTerminal(buf)
+  call delete('Xtest1.vim')
+  call delete('Xtest2.vim')
+endfunc
+
+func Test_Backtrace_Autocmd()
+  CheckRunVimInTerminal
+
+  let file1 =<< trim END
+    func SourceAnotherFile()
+      source Xtest2.vim
+    endfunc
+
+    func CallAFunction()
+      call SourceAnotherFile()
+      call File2Function()
+    endfunc
+
+    func GlobalFunction()
+      call CallAFunction()
+    endfunc
+
+    au User TestGlobalFunction :call GlobalFunction() | echo "Done"
+  END
+  call writefile(file1, 'Xtest1.vim')
+
+  let file2 =<< trim END
+    func DoAThing()
+      echo "DoAThing"
+    endfunc
+
+    func File2Function()
+      call DoAThing()
+    endfunc
+
+    call File2Function()
+  END
+  call writefile(file2, 'Xtest2.vim')
+
+  let buf = RunVimInTerminal('-S Xtest1.vim', {})
+
+  call RunDbgCmd(buf,
+                \ ':debug doautocmd User TestGlobalFunction',
+                \ ['cmd: doautocmd User TestGlobalFunction'])
+  call RunDbgCmd(buf, 'step', ['cmd: call GlobalFunction() | echo "Done"'])
+
+  " At this point the ontly thing in the stack is the autocommand
+  call RunDbgCmd(buf, 'backtrace', [
+        \ '>backtrace',
+        \ '->0 User Autocommands for "TestGlobalFunction"',
+        \ 'cmd: call GlobalFunction() | echo "Done"'])
+
+  " And now we're back into the call stack
+  call RunDbgCmd(buf, 'step', ['line 1: call CallAFunction()'])
+  call RunDbgCmd(buf, 'backtrace', [
+        \ '>backtrace',
+        \ '  1 User Autocommands for "TestGlobalFunction"',
+        \ '->0 function GlobalFunction',
+        \ 'line 1: call CallAFunction()'])
+
+  call RunDbgCmd(buf, 'step', ['line 1: call SourceAnotherFile()'])
+  call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim'])
+
+  call RunDbgCmd(buf, 'backtrace', [
+        \ '>backtrace',
+        \ '  3 User Autocommands for "TestGlobalFunction"',
+        \ '  2 function GlobalFunction[1]',
+        \ '  1 CallAFunction[1]',
+        \ '->0 SourceAnotherFile',
+        \ 'line 1: source Xtest2.vim'])
+
+  " Step into the 'source' command. Note that we print the full trace all the
+  " way though the source command.
+  call RunDbgCmd(buf, 'step', ['line 1: func DoAThing()'])
+  call RunDbgCmd(buf, 'backtrace', [
+        \ '>backtrace',
+        \ '  4 User Autocommands for "TestGlobalFunction"',
+        \ '  3 function GlobalFunction[1]',
+        \ '  2 CallAFunction[1]',
+        \ '  1 SourceAnotherFile[1]',
+        \ '->0 script ' .. getcwd() .. '/Xtest2.vim',
+        \ 'line 1: func DoAThing()'])
+
+  " step until we have another meaninfgul trace
+  call RunDbgCmd(buf, 'step', ['line 5: func File2Function()'])
+  call RunDbgCmd(buf, 'step', ['line 9: call File2Function()'])
+  call RunDbgCmd(buf, 'backtrace', [
+        \ '>backtrace',
+        \ '  4 User Autocommands for "TestGlobalFunction"',
+        \ '  3 function GlobalFunction[1]',
+        \ '  2 CallAFunction[1]',
+        \ '  1 SourceAnotherFile[1]',
+        \ '->0 script ' .. getcwd() .. '/Xtest2.vim',
+        \ 'line 9: call File2Function()'])
+
+  call RunDbgCmd(buf, 'step', ['line 1: call DoAThing()'])
+  call RunDbgCmd(buf, 'step', ['line 1: echo "DoAThing"'])
+  call RunDbgCmd(buf, 'backtrace', [
+        \ '>backtrace',
+        \ '  6 User Autocommands for "TestGlobalFunction"',
+        \ '  5 function GlobalFunction[1]',
+        \ '  4 CallAFunction[1]',
+        \ '  3 SourceAnotherFile[1]',
+        \ '  2 script ' .. getcwd() .. '/Xtest2.vim[9]',
+        \ '  1 function File2Function[1]',
+        \ '->0 DoAThing',
+        \ 'line 1: echo "DoAThing"'])
+
+  " Now, step (back to Xfile1.vim), and call the function _in_ Xfile2.vim
+  call RunDbgCmd(buf, 'step', ['line 1: End of function'])
+  call RunDbgCmd(buf, 'step', ['line 1: End of function'])
+  call RunDbgCmd(buf, 'step', ['line 10: End of sourced file'])
+  call RunDbgCmd(buf, 'step', ['line 1: End of function'])
+  call RunDbgCmd(buf, 'step', ['line 2: call File2Function()'])
+  call RunDbgCmd(buf, 'backtrace', [
+        \ '>backtrace',
+        \ '  2 User Autocommands for "TestGlobalFunction"',
+        \ '  1 function GlobalFunction[1]',
+        \ '->0 CallAFunction',
+        \ 'line 2: call File2Function()'])
+
+  call RunDbgCmd(buf, 'step', ['line 1: call DoAThing()'])
+  call RunDbgCmd(buf, 'backtrace', [
+        \ '>backtrace',
+        \ '  3 User Autocommands for "TestGlobalFunction"',
+        \ '  2 function GlobalFunction[1]',
+        \ '  1 CallAFunction[2]',
+        \ '->0 File2Function',
+        \ 'line 1: call DoAThing()'])
+
+
+  " Now unwind so that we get back to the original autocommand (and the second
+  " cmd echo "Done")
+  call RunDbgCmd(buf, 'finish', ['line 1: End of function'])
+  call RunDbgCmd(buf, 'backtrace', [
+        \ '>backtrace',
+        \ '  3 User Autocommands for "TestGlobalFunction"',
+        \ '  2 function GlobalFunction[1]',
+        \ '  1 CallAFunction[2]',
+        \ '->0 File2Function',
+        \ 'line 1: End of function'])
+
+  call RunDbgCmd(buf, 'finish', ['line 2: End of function'])
+  call RunDbgCmd(buf, 'backtrace', [
+        \ '>backtrace',
+        \ '  2 User Autocommands for "TestGlobalFunction"',
+        \ '  1 function GlobalFunction[1]',
+        \ '->0 CallAFunction',
+        \ 'line 2: End of function'])
+
+  call RunDbgCmd(buf, 'finish', ['line 1: End of function'])
+  call RunDbgCmd(buf, 'backtrace', [
+        \ '>backtrace',
+        \ '  1 User Autocommands for "TestGlobalFunction"',
+        \ '->0 function GlobalFunction',
+        \ 'line 1: End of function'])
+
+  call RunDbgCmd(buf, 'step', ['cmd: echo "Done"'])
+  call RunDbgCmd(buf, 'backtrace', [
+        \ '>backtrace',
+        \ '->0 User Autocommands for "TestGlobalFunction"',
+        \ 'cmd: echo "Done"'])
+
+  call StopVimInTerminal(buf)
+  call delete('Xtest1.vim')
+  call delete('Xtest2.vim')
+endfunc
+
+func Test_Backtrace_CmdLine()
+  CheckRunVimInTerminal
+
+  let file1 =<< trim END
+    func SourceAnotherFile()
+      source Xtest2.vim
+    endfunc
+
+    func CallAFunction()
+      call SourceAnotherFile()
+      call File2Function()
+    endfunc
+
+    func GlobalFunction()
+      call CallAFunction()
+    endfunc
+
+    au User TestGlobalFunction :call GlobalFunction() | echo "Done"
+  END
+  call writefile(file1, 'Xtest1.vim')
+
+  let file2 =<< trim END
+    func DoAThing()
+      echo "DoAThing"
+    endfunc
+
+    func File2Function()
+      call DoAThing()
+    endfunc
+
+    call File2Function()
+  END
+  call writefile(file2, 'Xtest2.vim')
+
+  let buf = RunVimInTerminal(
+        \ '-S Xtest1.vim -c "debug call GlobalFunction()"',
+        \ {'wait_for_ruler': 0})
+
+  " Need to wait for the vim-in-terminal to be ready
+  call CheckDbgOutput(buf, ['command line',
+                            \ 'cmd: call GlobalFunction()'])
+
+  " At this point the ontly thing in the stack is the cmdline
+  call RunDbgCmd(buf, 'backtrace', [
+        \ '>backtrace',
+        \ '->0 command line',
+        \ 'cmd: call GlobalFunction()'])
+
+  " And now we're back into the call stack
+  call RunDbgCmd(buf, 'step', ['line 1: call CallAFunction()'])
+  call RunDbgCmd(buf, 'backtrace', [
+        \ '>backtrace',
+        \ '  1 command line',
+        \ '->0 function GlobalFunction',
+        \ 'line 1: call CallAFunction()'])
+
+  call StopVimInTerminal(buf)
+  call delete('Xtest1.vim')
+  call delete('Xtest2.vim')
+endfunc
+
+func Test_Backtrace_DefFunction()
+  CheckRunVimInTerminal
+
+  let file1 =<< trim END
+    vim9script
+    import File2Function from './Xtest2.vim'
+
+    def SourceAnotherFile()
+      source Xtest2.vim
+    enddef
+
+    def CallAFunction()
+      SourceAnotherFile()
+      File2Function()
+    enddef
+
+    def g:GlobalFunction()
+      CallAFunction()
+    enddef
+
+    defcompile
+  END
+  call writefile(file1, 'Xtest1.vim')
+
+  let file2 =<< trim END
+    vim9script
+
+    def DoAThing(): number
+      let a = 100 * 2
+      a += 3
+      return a
+    enddef
+
+    export def File2Function()
+      DoAThing()
+    enddef
+
+    defcompile
+    File2Function()
+  END
+  call writefile(file2, 'Xtest2.vim')
+
+  let buf = RunVimInTerminal('-S Xtest1.vim', {})
+
+  call RunDbgCmd(buf,
+                \ ':debug call GlobalFunction()',
+                \ ['cmd: call GlobalFunction()'])
+
+  " FIXME: Vim9 lines are not debugged!
+  call RunDbgCmd(buf, 'step', ['line 1: source Xtest2.vim'])
+
+  " But they do appear in the backtrace
+  call RunDbgCmd(buf, 'backtrace', [
+        \ '\V>backtrace',
+        \ '\V  2 function GlobalFunction[1]',
+        \ '\V  1 <SNR>\.\*_CallAFunction[1]',
+        \ '\V->0 <SNR>\.\*_SourceAnotherFile',
+        \ '\Vline 1: source Xtest2.vim'],
+        \ #{match: 'pattern'})
+
+
+  call RunDbgCmd(buf, 'step', ['line 1: vim9script'])
+  call RunDbgCmd(buf, 'step', ['line 3: def DoAThing(): number'])
+  call RunDbgCmd(buf, 'step', ['line 9: export def File2Function()'])
+  call RunDbgCmd(buf, 'step', ['line 9: def File2Function()'])
+  call RunDbgCmd(buf, 'step', ['line 13: defcompile'])
+  call RunDbgCmd(buf, 'step', ['line 14: File2Function()'])
+  call RunDbgCmd(buf, 'backtrace', [
+        \ '\V>backtrace',
+        \ '\V  3 function GlobalFunction[1]',
+        \ '\V  2 <SNR>\.\*_CallAFunction[1]',
+        \ '\V  1 <SNR>\.\*_SourceAnotherFile[1]',
+        \ '\V->0 script ' .. getcwd() .. '/Xtest2.vim',
+        \ '\Vline 14: File2Function()'],
+        \ #{match: 'pattern'})
+
+  " Don't step into compiled functions...
+  call RunDbgCmd(buf, 'step', ['line 15: End of sourced file'])
+  call RunDbgCmd(buf, 'backtrace', [
+        \ '\V>backtrace',
+        \ '\V  3 function GlobalFunction[1]',
+        \ '\V  2 <SNR>\.\*_CallAFunction[1]',
+        \ '\V  1 <SNR>\.\*_SourceAnotherFile[1]',
+        \ '\V->0 script ' .. getcwd() .. '/Xtest2.vim',
+        \ '\Vline 15: End of sourced file'],
+        \ #{match: 'pattern'})
+
+
+  call StopVimInTerminal(buf)
+  call delete('Xtest1.vim')
+  call delete('Xtest2.vim')
+endfunc
index 73ab8c3998eb711cc50532f27c9df7b8f0a0b498..c41d93218851331436c2da3d56206b6211860d3c 100644 (file)
@@ -754,6 +754,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1304,
 /**/
     1303,
 /**/