summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-07-27 19:47:07 +0200
committerBram Moolenaar <Bram@vim.org>2020-07-27 19:47:07 +0200
commit6ca6ca48898750dd55cad13c88a9c1dfd7fdaad5 (patch)
tree7e21eb75ee69713e747dd38ebd8a2545fda0ae2b
parent6d585f4c5c8d120f768dd61bfd32f6e57ad562a7 (diff)
patch 8.2.1304: debug backtrace isn't tested muchv8.2.1304
Problem: Debug backtrace isn't tested much. Solution: Add more specific tests. (Ben Jackson, closes #6540)
-rw-r--r--src/testdir/runtest.vim5
-rw-r--r--src/testdir/test_debugger.vim452
-rw-r--r--src/version.c2
3 files changed, 453 insertions, 6 deletions
diff --git a/src/testdir/runtest.vim b/src/testdir/runtest.vim
index 3cf2a506c9..6cc7202dc7 100644
--- a/src/testdir/runtest.vim
+++ b/src/testdir/runtest.vim
@@ -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
diff --git a/src/testdir/test_debugger.vim b/src/testdir/test_debugger.vim
index a99154a5af..e019617e68 100644
--- a/src/testdir/test_debugger.vim
+++ b/src/testdir/test_debugger.vim
@@ -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
diff --git a/src/version.c b/src/version.c
index 73ab8c3998..c41d932188 100644
--- a/src/version.c
+++ b/src/version.c
@@ -755,6 +755,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1304,
+/**/
1303,
/**/
1302,