Merge pull request #42 from puremourning/test-framework

Fix and test breakpoint issues
This commit is contained in:
mergify[bot] 2019-07-27 10:28:36 +00:00 committed by GitHub
commit 28088c991d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 458 additions and 256 deletions

2
.gitignore vendored
View file

@ -13,3 +13,5 @@ package/
README.md.orig.*
README.md.toc.*
.DS_Store
*.vimspector.log
support/test/csharp/*.exe*

View file

@ -23,8 +23,9 @@ let current_compiler = "vimspector_test"
setlocal errorformat=
\Found\ errors\ in\ %f:%.%#:
let &l:makeprg=fnamemodify( findfile( 'run_tests', '.;' ), ':p' )
\ . ' $* 2>&1'
let s:run_tests = findfile( 'run_tests', '.;' )
let s:root_dir = fnamemodify( s:run_tests, ':h' )
let &l:makeprg=fnamemodify( s:run_tests, ':p' ) . ' $* 2>&1'
let s:make_cmd = get( g:, 'vimspector_test_make_cmd', 'Make' )
@ -86,17 +87,35 @@ function! s:RunTestUnderCursor()
echo "Running test '" . l:test_func_name . "'"
let l:test_arg = expand( '%:p:t' ) . ':' . l:test_func_name
execute s:make_cmd . ' ' . l:test_arg
let l:cwd = getcwd()
execute 'lcd ' . s:root_dir
try
execute s:make_cmd . ' ' . l:test_arg
finally
execute 'lcd ' . l:cwd
endtry
endfunction
function! s:RunTest()
update
execute s:make_cmd . ' %:p:t'
let l:cwd = getcwd()
execute 'lcd ' . s:root_dir
try
execute s:make_cmd . ' %:p:t'
finally
execute 'lcd ' . l:cwd
endtry
endfunction
function! s:RunAllTests()
update
execute s:make_cmd
let l:cwd = getcwd()
execute 'lcd ' . s:root_dir
try
execute s:make_cmd
finally
execute 'lcd ' . l:cwd
endtry
endfunction
if ! has( 'gui_running' )

View file

@ -15,16 +15,30 @@
from collections import defaultdict
import abc
import vim
import os
import logging
import json
from vimspector import utils
class ServerBreakpointHandler( object ):
@abc.abstractmethod
def ClearBreakpoints( self ):
pass
@abc.abstractmethod
def AddBreakpoints( self, source, message ):
pass
class ProjectBreakpoints( object ):
def __init__( self ):
self._connection = None
self._logger = logging.getLogger( __name__ )
utils.SetUpLogging( self._logger )
# These are the user-entered breakpoints.
self._line_breakpoints = defaultdict( list )
@ -55,6 +69,7 @@ class ProjectBreakpoints( object ):
self._exceptionBreakpoints = None
self._server_capabilities = {}
self._connection = None
self.UpdateUI()
# for each breakpoint:
# clear its resolved status
@ -94,6 +109,12 @@ class ProjectBreakpoints( object ):
def ClearBreakpoints( self ):
# These are the user-entered breakpoints.
for file_name, breakpoints in self._line_breakpoints.items():
for bp in breakpoints:
if 'sign_id' in bp:
vim.command( 'sign unplace {0} group=VimspectorBP'.format(
bp[ 'sign_id' ] ) )
self._line_breakpoints = defaultdict( list )
self._func_breakpoints = []
self._exceptionBreakpoints = None
@ -108,16 +129,26 @@ class ProjectBreakpoints( object ):
return
found_bp = False
action = 'New'
for index, bp in enumerate( self._line_breakpoints[ file_name ] ):
if bp[ 'line' ] == line:
found_bp = True
if bp[ 'state' ] == 'ENABLED':
if bp[ 'state' ] == 'ENABLED' and not self._connection:
bp[ 'state' ] = 'DISABLED'
action = 'Disable'
else:
if 'sign_id' in bp:
vim.command( 'sign unplace {0} group=VimspectorBP'.format(
bp[ 'sign_id' ] ) )
del self._line_breakpoints[ file_name ][ index ]
action = 'Delete'
break
self._logger.debug( "Toggle found bp at {}:{} ? {} ({})".format(
file_name,
line,
found_bp,
action ) )
if not found_bp:
self._line_breakpoints[ file_name ].append( {
@ -157,23 +188,22 @@ class ProjectBreakpoints( object ):
def SendBreakpoints( self ):
if not self._breakpoints_handler:
def handler( source, msg ):
return self._ShowBreakpoints()
else:
handler = self._breakpoints_handler
assert self._breakpoints_handler is not None
# Clear any existing breakpoints prior to sending new ones
self._breakpoints_handler.ClearBreakpoints()
for file_name, line_breakpoints in self._line_breakpoints.items():
breakpoints = []
for bp in line_breakpoints:
if bp[ 'state' ] != 'ENABLED':
continue
if 'sign_id' in bp:
vim.command( 'sign unplace {0} group=VimspectorBP'.format(
bp[ 'sign_id' ] ) )
del bp[ 'sign_id' ]
if bp[ 'state' ] != 'ENABLED':
continue
breakpoints.append( { 'line': bp[ 'line' ] } )
source = {
@ -182,7 +212,7 @@ class ProjectBreakpoints( object ):
}
self._connection.DoRequest(
lambda msg: handler( source, msg ),
lambda msg: self._breakpoints_handler.AddBreakpoints( source, msg ),
{
'command': 'setBreakpoints',
'arguments': {
@ -195,7 +225,7 @@ class ProjectBreakpoints( object ):
if self._server_capabilities.get( 'supportsFunctionBreakpoints' ):
self._connection.DoRequest(
lambda msg: handler( None, msg ),
lambda msg: self._breakpoints_handler.AddBreakpoints( None, msg ),
{
'command': 'setFunctionBreakpoints',
'arguments': {

View file

@ -128,23 +128,11 @@ class CodeView( object ):
# Not found. Assume new
self.AddBreakpoints( None, [ bp ] )
def DeleteBreakpoint( self, bp ):
if 'id' not in bp:
return
for _, breakpoint_list in self._breakpoints.items():
for index, breakpoint in enumerate( breakpoint_list ):
if 'id' in breakpoint and breakpoint[ 'id' ] == bp[ 'id' ]:
del breakpoint_list[ index ]
return
# Not found. Shrug.
def _UndisplaySigns( self ):
for sign_id in self._signs[ 'breakpoints' ]:
vim.command( 'sign unplace {} group=VimspectorCode'.format( sign_id ) )
self._signs[ 'breakpoints' ].clear()
self._signs[ 'breakpoints' ] = []
def ClearBreakpoints( self ):
self._UndisplaySigns()
@ -169,7 +157,7 @@ class CodeView( object ):
sign_id,
breakpoint[ 'line' ],
'vimspectorBP' if breakpoint[ 'verified' ]
else 'vimspectorBPDisabled',
else 'vimspectorBPDisabled',
file_name ) )

View file

@ -19,6 +19,7 @@ import json
import os
import subprocess
import shlex
import traceback
from vimspector import ( breakpoints,
code,
@ -39,6 +40,7 @@ class DebugSession( object ):
self._logger = logging.getLogger( __name__ )
utils.SetUpLogging( self._logger )
self._logger.info( "**** INITIALISING NEW VIMSPECTOR SESSION ****" )
self._logger.info( 'VIMSPECTOR_HOME = %s', VIMSPECTOR_HOME )
self._logger.info( 'gadgetDir = %s',
install.GetGadgetDir( VIMSPECTOR_HOME,
@ -63,6 +65,8 @@ class DebugSession( object ):
self._server_capabilities = {}
def Start( self, launch_variables = {} ):
self._logger.info( "User requested start debug session with %s",
launch_variables )
self._configuration = None
self._adapter = None
@ -162,13 +166,16 @@ class DebugSession( object ):
def _StartWithConfiguration( self, configuration, adapter ):
def start():
self._logger.debug( "Starting debugger from stack context: %s",
traceback.format_stack() )
self._configuration = configuration
self._adapter = adapter
self._logger.info( 'Configuration: {0}'.format( json.dumps(
self._configuration ) ) )
self._logger.info( 'Adapter: {0}'.format( json.dumps(
self._adapter ) ) )
self._logger.info( 'Configuration: %s',
json.dumps( self._configuration ) )
self._logger.info( 'Adapter: %s',
json.dumps( self._adapter ) )
if not self._uiTab:
self._SetUpUI()
@ -183,16 +190,23 @@ class DebugSession( object ):
self._outputView.ConnectionUp( self._connection )
self._breakpoints.ConnectionUp( self._connection )
def update_breakpoints( source, message ):
if 'body' not in message:
return
self._codeView.AddBreakpoints( source,
message[ 'body' ][ 'breakpoints' ] )
self._codeView.ShowBreakpoints()
class Handler( breakpoints.ServerBreakpointHandler ):
def __init__( self, codeView ):
self.codeView = codeView
self._breakpoints.SetBreakpointsHandler( update_breakpoints )
def ClearBreakpoints( self ):
self.codeView.ClearBreakpoints()
def AddBreakpoints( self, source, message ):
if 'body' not in message:
return
self.codeView.AddBreakpoints( source,
message[ 'body' ][ 'breakpoints' ] )
self._breakpoints.SetBreakpointsHandler( Handler( self._codeView ) )
if self._connection:
self._logger.debug( "_StopDebugAdapter with callback: start" )
self._StopDebugAdapter( start )
return
@ -212,6 +226,7 @@ class DebugSession( object ):
if self._connection:
self._connection.OnData( data )
def OnServerStderr( self, data ):
self._logger.info( "Server stderr: %s", data )
if self._outputView:
@ -227,22 +242,31 @@ class DebugSession( object ):
self._connection = None
def Stop( self ):
self._logger.debug( "Stop debug adapter with no callback" )
self._StopDebugAdapter()
def Reset( self ):
if self._connection:
self._logger.debug( "Stop debug adapter with callback : self._Reset()" )
self._StopDebugAdapter( lambda: self._Reset() )
else:
self._Reset()
def _Reset( self ):
self._logger.info( "Debugging complete." )
if self._uiTab:
self._logger.debug( "Clearing down UI with stack_trace: %s",
traceback.format_stack() )
vim.current.tabpage = self._uiTab
self._stackTraceView.Reset()
self._variablesView.Reset()
self._outputView.Reset()
self._codeView.Reset()
vim.command( 'tabclose!' )
self._stackTraceView = None
self._variablesView = None
self._outputView = None
self._codeView = None
self._uiTab = None
# make sure that we're displaying signs in any still-open buffers
@ -312,9 +336,9 @@ class DebugSession( object ):
self._variablesView.ShowBalloon( self._stackTraceView.GetCurrentFrame(),
expression )
else:
self._logger.debug( 'Winnr {0} is not the code window {1}'.format(
winnr,
self._codeView._window.number ) )
self._logger.debug( 'Winnr %s is not the code window %s',
winnr,
self._codeView._window.number )
def ExpandFrameOrThread( self ):
self._stackTraceView.ExpandFrameOrThread()
@ -387,8 +411,8 @@ class DebugSession( object ):
persist = True )
return
self._logger.info( 'Starting debug adapter with: {0}'.format( json.dumps(
self._adapter ) ) )
self._logger.info( 'Starting debug adapter with: %s',
json.dumps( self._adapter ) )
self._init_complete = False
self._on_init_complete_handlers = []
@ -428,13 +452,14 @@ class DebugSession( object ):
def _StopDebugAdapter( self, callback = None ):
def handler( *args ):
vim.eval( 'vimspector#internal#{}#StopDebugSession()'.format(
self._connection_type ) )
if callback:
self._logger.debug( "Setting server exit handler before disconnect" )
assert not self._run_on_server_exit
self._run_on_server_exit = callback
vim.eval( 'vimspector#internal#{}#StopDebugSession()'.format(
self._connection_type ) )
arguments = {}
if self._server_capabilities.get( 'supportTerminateDebuggee' ):
arguments[ 'terminateDebugee' ] = True
@ -638,6 +663,11 @@ class DebugSession( object ):
# doesn't respond top threads request when attaching via gdbserver. At
# least it would apear that way.
#
# As it turns out this is due to a bug in gdbserver which means that
# attachment doesn't work due to sending the signal to the process group
# leader rather than the process. The workaround is to manually SIGTRAP the
# PID.
#
if self._launch_complete and self._init_complete:
for h in self._on_init_complete_handlers:
h()
@ -719,6 +749,8 @@ class DebugSession( object ):
self._variablesView.Clear()
def OnServerExit( self, status ):
self._logger.info( "The server has terminated with status %s",
status )
self.Clear()
self._connection.Reset()
@ -730,11 +762,14 @@ class DebugSession( object ):
self._ResetServerState()
if self._run_on_server_exit:
self._logger.debug( "Running server exit handler" )
self._run_on_server_exit()
else:
self._logger.debug( "No server exit handler" )
def OnEvent_terminated( self, message ):
# We will handle this when the server actually exists
utils.UserMessage( "Debugging was terminated." )
utils.UserMessage( "Debugging was terminated by the server." )
def OnEvent_output( self, message ):
if self._outputView:
@ -771,6 +806,9 @@ class DebugSession( object ):
return self._breakpoints.ToggleBreakpoint()
def ClearBreakpoints( self ):
if self._connection:
self._codeView.ClearBreakpoints()
return self._breakpoints.ClearBreakpoints()
def AddFunctionBreakpoint( self, function ):

View file

@ -103,7 +103,7 @@ class OutputView( object ):
if 'E516' not in e:
raise
self._buffers.clear()
self._buffers = {}
def _ShowOutput( self, category ):
utils.JumpToWindow( self._window )

View file

@ -69,8 +69,6 @@ def SetUpCommandBuffer( cmd, name ):
name,
cmd ) )
UserMessage( 'Bufs: {}'.format( [ int( b ) for b in bufs ] ), persist = True )
return [ vim.buffers[ b ] for b in bufs ]
@ -227,6 +225,11 @@ def Escape( msg ):
def UserMessage( msg, persist=False ):
if persist:
_logger.warning( 'User Msg: ' + msg )
else:
_logger.info( 'User Msg: ' + msg )
vim.command( 'redraw' )
cmd = 'echom' if persist else 'echo'
for line in msg.split( '\n' ):
@ -283,7 +286,7 @@ def AppendToBuffer( buf, line_or_lines, modified=False ):
except Exception:
# There seem to be a lot of Vim bugs that lead to E315, whose help says that
# this is an internal error. Ignore the error, but write a trace to the log.
logging.getLogger( __name__ ).exception(
_logger.exception(
'Internal error while updating buffer %s (%s)', buf.name, buf.number )
finally:
if not modified:

View file

@ -1,20 +1,9 @@
source lib/shared.vim
function! SetUp()
if exists ( 'g:loaded_vimpector' )
unlet g:loaded_vimpector
endif
source vimrc
" This is a bit of a hack
runtime! plugin/**/*.vim
call vimspector#test#setup#SetUpWithMappings( v:none )
endfunction
function! ClearDown()
if exists( '*vimspector#internal#state#Reset' )
call vimspector#internal#state#Reset()
endif
call vimspector#test#setup#ClearDown()
endfunction
function! SetUp_Test_Mappings_Are_Added_HUMAN()
@ -62,40 +51,27 @@ function! Test_Signs_Placed_Using_API_Are_Shown()
call vimspector#ToggleBreakpoint()
call assert_true( exists( '*vimspector#ToggleBreakpoint' ) )
let signs = sign_getplaced( '%', {
\ 'group': 'VimspectorBP',
\ 'line': line( '.' )
\ } )
call assert_equal( 1, len( signs ) )
call assert_equal( 1, len( signs[ 0 ].signs ) )
call assert_equal( 'vimspectorBP', signs[ 0 ].signs[ 0 ].name )
call vimspector#test#signs#AssertSignGroupSingletonAtLine( 'VimspectorBP',
\ line( '.' ),
\ 'vimspectorBP' )
" Disable breakpoint
call vimspector#ToggleBreakpoint()
let signs = sign_getplaced( '%', {
\ 'group': 'VimspectorBP',
\ 'line': line( '.' )
\ } )
call assert_equal( 1, len( signs ) )
call assert_equal( 1, len( signs[ 0 ].signs ) )
call assert_equal( 'vimspectorBPDisabled', signs[ 0 ].signs[ 0 ].name )
call vimspector#test#signs#AssertSignGroupSingletonAtLine(
\ 'VimspectorBP',
\ line( '.' ),
\ 'vimspectorBPDisabled' )
" Remove breakpoint
call vimspector#ToggleBreakpoint()
let signs = sign_getplaced( '%', {
\ 'group': 'VimspectorBP',
\ 'line': line( '.' )
\ } )
call assert_equal( 1, len( signs ) )
call assert_equal( 0, len( signs[ 0 ].signs ) )
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorBP',
\ line( '.' ) )
call vimspector#ClearBreakpoints()
call vimspector#test#signs#AssertSignGroupEmpty( 'VimspectorBP' )
call vimspector#test#signs#AssertSignGroupEmpty( 'VimspectorCode' )
%bwipeout!
endfunction
@ -106,54 +82,34 @@ endfunction
function! Test_Use_Mappings_HUMAN()
lcd testdata/cpp/simple
edit simple.cpp
call setpos( '.', [ 0, 15, 1 ] )
15
call assert_equal( 15, line( '.' ) )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 15, 1 )
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorBP', 15 )
" Add the breakpoing
" Add the breakpoint
call feedkeys( "\<F9>", 'xt' )
let signs = sign_getplaced( '%', {
\ 'group': 'VimspectorBP',
\ 'line': line( '.' )
\ } )
call assert_equal( 1, len( signs ), 1 )
call assert_equal( 1, len( signs[ 0 ].signs ), 1 )
call assert_equal( 'vimspectorBP', signs[ 0 ].signs[ 0 ].name )
call vimspector#test#signs#AssertSignGroupSingletonAtLine( 'VimspectorBP',
\ 15,
\ 'vimspectorBP' )
" Disable the breakpoint
call feedkeys( "\<F9>", 'xt' )
let signs = sign_getplaced( '%', {
\ 'group': 'VimspectorBP',
\ 'line': line( '.' )
\ } )
call assert_equal( 1, len( signs ), 1 )
call assert_equal( 1, len( signs[ 0 ].signs ), 1 )
call assert_equal( 'vimspectorBPDisabled', signs[ 0 ].signs[ 0 ].name )
call vimspector#test#signs#AssertSignGroupSingletonAtLine(
\ 'VimspectorBP',
\ 15,
\ 'vimspectorBPDisabled' )
" Delete the breakpoint
call feedkeys( "\<F9>", 'xt' )
let signs = sign_getplaced( '%', {
\ 'group': 'VimspectorBP',
\ 'line': line( '.' )
\ } )
call assert_equal( 1, len( signs ), 1 )
call assert_equal( 0, len( signs[ 0 ].signs ) )
call vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorBP', 15 )
" Add it again
call feedkeys( "\<F9>", 'xt' )
let signs = sign_getplaced( '%', {
\ 'group': 'VimspectorBP',
\ 'line': line( '.' )
\ } )
call assert_equal( 1, len( signs ), 1 )
call assert_equal( 1, len( signs[ 0 ].signs ), 1 )
call assert_equal( 'vimspectorBP', signs[ 0 ].signs[ 0 ].name )
call vimspector#test#signs#AssertSignGroupSingletonAtLine(
\ 'VimspectorBP',
\ 15,
\ 'vimspectorBP' )
" Here we go. Start Debugging
call feedkeys( "\<F5>", 'xt' )
@ -162,72 +118,130 @@ function! Test_Use_Mappings_HUMAN()
let cur_tabnr = tabpagenr()
call assert_equal( 5, len( gettabinfo( cur_tabnr )[ 0 ].windows ) )
call WaitForAssert( {->
\ assert_equal( 'simple.cpp', bufname( '%' ), 'Current buffer' )
\ }, 10000 )
call assert_equal( 15, line( '.' ), 'Current line' )
call assert_equal( 1, col( '.' ), 'Current column' )
let signs = sign_getplaced( '%', {
\ 'group': 'VimspectorCode',
\ } )
call assert_equal( 1, len( signs ), 'Sign-buffers' )
call assert_equal( 2, len( signs[ 0 ].signs ), 'Signs in buffer' )
let pc_index = -1
let index = 0
while index < len( signs[ 0 ].signs )
let s = signs[ 0 ].signs[ index ]
if s.name ==# 'vimspectorPC'
if pc_index >= 0
call assert_report( 'Found too many PC signs!' )
endif
let pc_index = index
endif
let index = index + 1
endwhile
call assert_true( pc_index >= 0 )
call assert_equal( 15, signs[ 0 ].signs[ pc_index ].lnum )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 15, 1 )
" Step
call feedkeys( "\<F10>", 'xt' )
call WaitForAssert( {-> assert_equal( 16, line( '.' ), 'Current line' ) } )
call assert_equal( 'simple.cpp', bufname( '%' ), 'Current buffer' )
call assert_equal( 1, col( '.' ), 'Current column' )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 16, 1 )
call WaitForAssert( {->
\ vimspector#test#signs#AssertPCIsAtLineInBuffer( 'simple.cp', 16 )
\ } )
let signs = sign_getplaced( '%', {
\ 'group': 'VimspectorCode',
\ } )
call assert_equal( 1, len( signs ), 'Sign-buffers' )
call assert_equal( 2, len( signs[ 0 ].signs ), 'Signs in buffer' )
let pc_index = -1
let index = 0
while index < len( signs[ 0 ].signs )
let s = signs[ 0 ].signs[ index ]
if s.name ==# 'vimspectorPC'
if pc_index >= 0
call assert_report( 'Found too many PC signs!' )
endif
let pc_index = index
endif
let index = index + 1
endwhile
call assert_true( pc_index >= 0 )
call assert_equal( 16, signs[ 0 ].signs[ pc_index ].lnum )
call vimspector#Reset()
call vimspector#ClearBreakpoints()
let signs = sign_getplaced( '%', {
\ 'group': 'VimspectorBP'
\ } )
call assert_equal( 1, len( signs ), 1 )
call assert_equal( 0, len( signs[ 0 ].signs ) )
call vimspector#test#setup#Reset()
lcd -
%bwipeout!
endfunction
function! SetUp_Test_StopAtEntry()
let g:vimspector_enable_mappings = 'HUMAN'
endfunction
function Test_StopAtEntry()
lcd testdata/cpp/simple
edit simple.cpp
call setpos( '.', [ 0, 1, 1 ] )
" Test stopAtEntry behaviour
call feedkeys( "\<F5>", 'xt' )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 15, 1 )
call WaitForAssert( {->
\ vimspector#test#signs#AssertPCIsAtLineInBuffer( 'simple.cpp', 15 )
\ } )
call vimspector#test#setup#Reset()
lcd -
%bwipeout!
endfunction
function! SetUp_Test_DisableBreakpointWhileDebugging()
let g:vimspector_enable_mappings = 'HUMAN'
endfunction
function Test_DisableBreakpointWhileDebugging()
lcd testdata/cpp/simple
edit simple.cpp
call setpos( '.', [ 0, 15, 1 ] )
" Test stopAtEntry behaviour
call feedkeys( "\<F5>", 'xt' )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 15, 1 )
call WaitForAssert( {->
\ vimspector#test#signs#AssertPCIsAtLineInBuffer( 'simple.cpp', 15 )
\ } )
call vimspector#test#signs#AssertSignGroupEmpty( 'VimspectorBP' )
call setpos( '.', [ 0, 16, 1 ] )
" Add the breakpoint
call feedkeys( "\<F9>", 'xt' )
call WaitForAssert( {->
\ vimspector#test#signs#AssertSignGroupSingletonAtLine(
\ 'VimspectorCode',
\ 16,
\ 'vimspectorBP' )
\ } )
" Remove the breakpoint
call feedkeys( "\<F9>", 'xt' )
call WaitForAssert( {->
\ vimspector#test#signs#AssertSignGroupEmptyAtLine( 'VimspectorCode',
\ 16 )
\ } )
" Add the breakpoint
call feedkeys( "\<F9>", 'xt' )
call WaitForAssert( {->
\ vimspector#test#signs#AssertSignGroupSingletonAtLine(
\ 'VimspectorCode',
\ 16,
\ 'vimspectorBP' )
\ } )
" Run to breakpoint
call setpos( '.', [ 0, 15, 1 ] )
call feedkeys( "\<F5>", 'xt' )
call vimspector#test#signs#AssertCursorIsAtLineInBuffer( 'simple.cpp', 16, 1 )
call WaitForAssert( {->
\ vimspector#test#signs#AssertPCIsAtLineInBuffer( 'simple.cpp', 16 )
\ } )
call vimspector#Reset()
call WaitForAssert( {->
\ assert_true ( pyxeval( '_vimspector_session._connection is None' ) )
\ } )
call WaitForAssert( {->
\ assert_true( pyxeval( '_vimspector_session._uiTab is None' ) )
\ } )
" Check breakpoint is now a user breakpoint
call setpos( '.', [ bufnr( 'simple.cpp' ), 1, 1 ] )
call vimspector#test#signs#AssertSignGroupSingletonAtLine(
\ 'VimspectorBP',
\ 16,
\ 'vimspectorBP' )
" Disable the breakpoint
call setpos( '.', [ bufnr( 'simple.cpp' ), 16, 1 ] )
call feedkeys( "\<F9>", 'xt' )
call vimspector#test#signs#AssertSignGroupSingletonAtLine(
\ 'VimspectorBP',
\ 16,
\ 'vimspectorBPDisabled' )
" And delete it
call feedkeys( "\<F9>", 'xt' )
call vimspector#test#signs#AssertSignGroupEmptyAtLine(
\ 'VimspectorBP',
\ 16 )
call vimspector#ClearBreakpoints()
call vimspector#test#signs#AssertSignGroupEmpty( 'VimspectorBP' )
call vimspector#test#signs#AssertSignGroupEmpty( 'VimspectorCode' )
lcd -
%bwipeout!

View file

@ -0,0 +1,36 @@
function! vimspector#test#setup#SetUpWithMappings( mappings ) abort
if exists ( 'g:loaded_vimpector' )
unlet g:loaded_vimpector
endif
if a:mappings != v:none
let g:vimspector_enable_mappings = a:mappings
endif
source vimrc
" This is a bit of a hack
runtime! plugin/**/*.vim
endfunction
function! vimspector#test#setup#ClearDown() abort
endfunction
function! vimspector#test#setup#Reset() abort
call vimspector#Reset()
call WaitForAssert( {->
\ assert_true( pyxeval( '_vimspector_session._connection is None' ) )
\ } )
call WaitForAssert( {->
\ assert_true( pyxeval( '_vimspector_session._uiTab is None' ) )
\ }, 10000 )
call vimspector#test#signs#AssertSignGroupEmpty( 'VimspectorCode' )
call vimspector#ClearBreakpoints()
call vimspector#test#signs#AssertSignGroupEmpty( 'VimspectorBP' )
if exists( '*vimspector#internal#state#Reset' )
call vimspector#internal#state#Reset()
endif
endfunction

View file

@ -0,0 +1,93 @@
function! vimspector#test#signs#AssertCursorIsAtLineInBuffer( buffer,
\ line,
\ column ) abort
call WaitForAssert( {->
\ assert_equal( a:buffer, bufname( '%' ), 'Current buffer' )
\ }, 10000 )
call WaitForAssert( {->
\ assert_equal( a:line, line( '.' ), 'Current line' )
\ }, 10000 )
call assert_equal( a:column, col( '.' ), 'Current column' )
endfunction
function! vimspector#test#signs#AssertPCIsAtLineInBuffer( buffer, line ) abort
let signs = sign_getplaced( a:buffer, {
\ 'group': 'VimspectorCode',
\ } )
if assert_equal( 1, len( signs ), 'Number of buffers named ' . a:buffer )
return 1
endif
if assert_true( len( signs[ 0 ].signs ) >= 1,
\ 'At least one VimspectorCode sign' )
return 1
endif
let pc_index = -1
let index = 0
while index < len( signs[ 0 ].signs )
let s = signs[ 0 ].signs[ index ]
if s.name ==# 'vimspectorPC'
if assert_false( pc_index >= 0, 'Too many PC signs' )
return 1
endif
let pc_index = index
endif
let index = index + 1
endwhile
return assert_true( pc_index >= 0 ) ||
\ assert_equal( a:line, signs[ 0 ].signs[ pc_index ].lnum )
endfunction
function! vimspector#test#signs#AssertSignGroupSingletonAtLine( group,
\ line,
\ sign_name )
\ abort
let signs = sign_getplaced( '%', {
\ 'group': a:group,
\ 'lnum': a:line,
\ } )
return assert_equal( 1,
\ len( signs ),
\ 'Num buffers named %' ) ||
\ assert_equal( 1,
\ len( signs[ 0 ].signs ),
\ 'Num signs in ' . a:group . ' at ' . a:line ) ||
\ assert_equal( a:sign_name,
\ signs[ 0 ].signs[ 0 ].name,
\ 'Sign in group ' . a:group . ' at ' . a:line )
endfunction
function! vimspector#test#signs#AssertSignGroupEmptyAtLine( group, line ) abort
let signs = sign_getplaced( '%', {
\ 'group': a:group,
\ 'lnum': line( '.' )
\ } )
return assert_equal( 1,
\ len( signs ),
\ 'Num buffers named %' ) ||
\ assert_equal( 0,
\ len( signs[ 0 ].signs ),
\ 'Num signs in ' . a:group . ' at ' . a:line )
endfunction
function! vimspector#test#signs#AssertSignGroupEmpty( group ) abort
let signs = sign_getplaced( '%', {
\ 'group': a:group,
\ } )
return assert_equal( 1,
\ len( signs ),
\ 'Num buffers named %' ) ||
\ assert_equal( 0,
\ len( signs[ 0 ].signs ),
\ 'Num signs in ' . a:group )
endfunction

View file

@ -17,8 +17,6 @@ if !has('terminal')
finish
endif
source lib/shared.vim
" Run Vim with "arguments" in a new terminal window.
" By default uses a size of 20 lines and 75 columns.
" Returns the buffer number of the terminal.

View file

@ -126,7 +126,7 @@ endfunc
" When running into the timeout an exception is thrown, thus the function does
" not return.
func WaitFor(expr, ...)
let timeout = get(a:000, 0, 5000)
let timeout = get(a:000, 0, 10000)
let slept = s:WaitForCommon(a:expr, v:null, timeout)
if slept < 0
throw 'WaitFor() timed out after ' . timeout . ' msec'
@ -134,8 +134,9 @@ func WaitFor(expr, ...)
return slept
endfunc
" Wait for up to five seconds for "assert" to return zero. "assert" must be a
" (lambda) function containing one assert function. Example:
" Wait for up to five seconds for "assert" to return without adding to v:errors.
" "assert" must be a (lambda) function containing one assert function.
" Example:
" call WaitForAssert({-> assert_equal("dead", job_status(job)})
"
" A second argument can be used to specify a different timeout in msec.
@ -160,13 +161,15 @@ func s:WaitForCommon(expr, assert, timeout)
endif
while 1
let errors_before = len( v:errors )
if type(a:expr) == v:t_func
let success = a:expr()
elseif type(a:assert) == v:t_func
let success = a:assert() == 0
let success = a:assert() == 0 && len( v:errors ) == errors_before
else
let success = eval(a:expr)
endif
if success
return slept
endif
@ -174,9 +177,10 @@ func s:WaitForCommon(expr, assert, timeout)
if slept >= a:timeout
break
endif
if type(a:assert) == v:t_func
" Remove the error added by the assert function.
call remove(v:errors, -1)
" Remove the errors added by the assert function.
call remove(v:errors, -1 * len( v:errors ) - errors_before )
endif
sleep 10m

View file

@ -28,7 +28,7 @@
" When debugging a test it can be useful to add messages to v:errors:
" call add(v:errors, "this happened")
set rtp=$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after
set rtp=$PWD/lib,$VIM/vimfiles,$VIMRUNTIME,$VIM/vimfiles/after
if has('packages')
let &packpath = &rtp
endif
@ -116,6 +116,11 @@ func RunTheTest(test)
try
let s:test = a:test
let s:testid = g:testpath . ':' . a:test
let test_filesafe = substitute( a:test, ')', '_', 'g' )
let test_filesafe = substitute( test_filesafe, '(', '_', 'g' )
let test_filesafe = substitute( test_filesafe, ',', '_', 'g' )
let test_filesafe = substitute( test_filesafe, ':', '_', 'g' )
let s:testid_filesafe = g:testpath . '_' . test_filesafe
au VimLeavePre * call EarlyExit(s:test)
exe 'call ' . a:test
au! VimLeavePre
@ -201,6 +206,12 @@ func AfterTheTest()
call add(s:errors, 'Found errors in ' . s:testid . ':')
call extend(s:errors, v:errors)
let v:errors = []
let log = readfile( expand( '~/.vimspector.log' ) )
let logfile = s:testid_filesafe . '.vimspector.log'
call writefile( log, logfile, 's' )
call add( s:messages, 'Wrote log for failed test: ' . logfile )
call extend( s:messages, log )
endif
endfunc
@ -306,51 +317,7 @@ endif
for s:test in sort(s:tests)
" Silence, please!
set belloff=all
let prev_error = ''
let total_errors = []
let run_nr = 1
call RunTheTest(s:test)
" Repeat a flaky test. Give up when:
" - it fails again with the same message
" - it fails five times (with a different mesage)
if len(v:errors) > 0
\ && (index(s:flaky_tests, s:test) >= 0
\ || v:errors[0] =~ s:flaky_errors_re)
while 1
call add(s:messages, 'Found errors in ' . s:testid . ':')
call extend(s:messages, v:errors)
call add(total_errors, 'Run ' . run_nr . ':')
call extend(total_errors, v:errors)
if run_nr == 5 || prev_error == v:errors[0]
call add(total_errors, 'Flaky test failed too often, giving up')
let v:errors = total_errors
break
endif
call add(s:messages, 'Flaky test failed, running it again')
" Flakiness is often caused by the system being very busy. Sleep a
" couple of seconds to have a higher chance of succeeding the second
" time.
sleep 2
let prev_error = v:errors[0]
let v:errors = []
let run_nr += 1
call RunTheTest(s:test)
if len(v:errors) == 0
" Test passed on rerun.
break
endif
endwhile
endif
call AfterTheTest()
endfor

View file

@ -1,15 +1,9 @@
source lib/shared.vim
function! SetUp()
if exists ( 'g:loaded_vimpector' )
unlet g:loaded_vimpector
endif
call vimspector#test#setup#SetUpWithMappings( 'HUMAN' )
endfunction
let g:vimspector_enable_mappings = 'HUMAN'
source vimrc
" This is a bit of a hack
runtime! plugin/**/*.vim
function! ClearDown()
call vimspector#test#setup#ClearDown()
endfunction
function! Test_Step_With_Different_Tabpage()

View file

@ -1 +1,2 @@
simple
variables

View file

@ -1,7 +1,11 @@
CXXFLAGS=-g -O0
CXXFLAGS=-g -O0 -std=c++17
simple: simple.cpp
.PHONY: all
TARGETS=simple variables
all: $(TARGETS)
clean:
rm -f simple
rm -rf simple.dSYM
rm -f $(TARGETS)
rm -rf $(TARGETS:%=%.dSYM)

11
tests/testdata/cpp/simple/variables.cpp vendored Normal file
View file

@ -0,0 +1,11 @@
#include <iostream>
int main() {
std::cout << "Hello world!" << std::endl;
int a = 1;
++a;
int& b = a;
++a;
std::cout << "a: " << a << " b: " << b << std::endl;
return 0;
}