def YouCompleteMe_UpdateMatches_ClearDiagnosticMatchesInNewBuffer_test(ycm): current_buffer = VimBuffer('buffer', filetype='c', number=5, window=2) test_utils.VIM_MATCHES = [ VimMatch('YcmWarningSection', '\%3l\%5c\_.\{-}\%3l\%7c'), VimMatch('YcmWarningSection', '\%3l\%3c\_.\{-}\%3l\%9c'), VimMatch('YcmErrorSection', '\%3l\%8c') ] with MockVimBuffers([current_buffer], current_buffer): ycm.UpdateMatches() assert_that(test_utils.VIM_MATCHES, empty())
def YouCompleteMe_UpdateMatches_ClearDiagnosticMatchesInNewBuffer_test(ycm): current_buffer = VimBuffer('buffer', filetype='c', number=5) test_utils.VIM_MATCHES_FOR_WINDOW[1] = [ VimMatch('YcmWarningSection', '\\%3l\\%5c\\_.\\{-}\\%3l\\%7c'), VimMatch('YcmWarningSection', '\\%3l\\%3c\\_.\\{-}\\%3l\\%9c'), VimMatch('YcmErrorSection', '\\%3l\\%8c') ] with MockVimBuffers([current_buffer], [current_buffer]): ycm.UpdateMatches() assert_that(test_utils.VIM_MATCHES_FOR_WINDOW, has_entries({1: empty()}))
def YouCompleteMe_UpdateDiagnosticInterface_PrioritizeErrorsOverWarnings_test( ycm, vim_command, post_vim_message, *args): contents = """int main() { int x, y; x == y }""" # List of diagnostics returned by ycmd for the above code. diagnostics = [ { 'kind': 'ERROR', 'text': "expected ';' after expression", 'location': { 'filepath': 'buffer', 'line_num': 3, 'column_num': 9 }, # Looks strange but this is really what ycmd is returning. 'location_extent': { 'start': { 'filepath': '', 'line_num': 0, 'column_num': 0, }, 'end': { 'filepath': '', 'line_num': 0, 'column_num': 0, } }, 'ranges': [], 'fixit_available': True }, { 'kind': 'WARNING', 'text': 'equality comparison result unused', 'location': { 'filepath': 'buffer', 'line_num': 3, 'column_num': 7, }, 'location_extent': { 'start': { 'filepath': 'buffer', 'line_num': 3, 'column_num': 5, }, 'end': { 'filepath': 'buffer', 'line_num': 3, 'column_num': 7, } }, 'ranges': [{ 'start': { 'filepath': 'buffer', 'line_num': 3, 'column_num': 3, }, 'end': { 'filepath': 'buffer', 'line_num': 3, 'column_num': 9, } }], 'fixit_available': True } ] current_buffer = VimBuffer('buffer', filetype='c', contents=contents.splitlines(), number=5, window=2) test_utils.VIM_MATCHES = [] with MockVimBuffers([current_buffer], current_buffer, (3, 1)): with patch('ycm.client.event_notification.EventNotification.Response', return_value=diagnostics): ycm.OnFileReadyToParse() ycm.HandleFileParseRequest(block=True) # The error on the current line is echoed, not the warning. post_vim_message.assert_called_once_with( "expected ';' after expression (FixIt)", truncate=True, warning=False) # Error match is added after warning matches. assert_that( test_utils.VIM_MATCHES, contains(VimMatch('YcmWarningSection', '\%3l\%5c\_.\{-}\%3l\%7c'), VimMatch('YcmWarningSection', '\%3l\%3c\_.\{-}\%3l\%9c'), VimMatch('YcmErrorSection', '\%3l\%8c'))) # Only the error sign is placed. vim_command.assert_has_exact_calls([ call('sign place 1 name=YcmError line=3 buffer=5'), ]) # The error is not echoed again when moving the cursor along the line. with MockVimBuffers([current_buffer], current_buffer, (3, 2)): post_vim_message.reset_mock() ycm.OnCursorMoved() post_vim_message.assert_not_called() # The error is cleared when moving the cursor to another line. with MockVimBuffers([current_buffer], current_buffer, (2, 2)): post_vim_message.reset_mock() ycm.OnCursorMoved() post_vim_message.assert_called_once_with("", warning=False) # The error is echoed when moving the cursor back. with MockVimBuffers([current_buffer], current_buffer, (3, 2)): post_vim_message.reset_mock() ycm.OnCursorMoved() post_vim_message.assert_called_once_with( "expected ';' after expression (FixIt)", truncate=True, warning=False) vim_command.reset_mock() with patch('ycm.client.event_notification.EventNotification.Response', return_value=diagnostics[1:]): ycm.OnFileReadyToParse() ycm.HandleFileParseRequest(block=True) assert_that( test_utils.VIM_MATCHES, contains(VimMatch('YcmWarningSection', '\%3l\%5c\_.\{-}\%3l\%7c'), VimMatch('YcmWarningSection', '\%3l\%3c\_.\{-}\%3l\%9c'))) vim_command.assert_has_exact_calls([ call('sign place 2 name=YcmWarning line=3 buffer=5'), call( 'try | exec "sign unplace 1 buffer=5" | catch /E158/ | endtry') ])
def YouCompleteMe_AsyncDiagnosticUpdate_PerFile_test(ycm, post_vim_message, *args): # This test simulates asynchronous diagnostic updates which are delivered per # file, including files which are open and files which are not. # Ordered to ensure that the calls to update are deterministic diagnostics_per_file = [ ('/current', [{ 'kind': 'ERROR', 'text': 'error text in current buffer', 'location': { 'filepath': '/current', 'line_num': 1, 'column_num': 1 }, 'location_extent': { 'start': { 'filepath': '/current', 'line_num': 1, 'column_num': 1, }, 'end': { 'filepath': '/current', 'line_num': 1, 'column_num': 1, } }, 'ranges': [], }]), ('/separate_window', [{ 'kind': 'ERROR', 'text': 'error text in a buffer open in a separate window', 'location': { 'filepath': '/separate_window', 'line_num': 3, 'column_num': 3 }, 'location_extent': { 'start': { 'filepath': '/separate_window', 'line_num': 3, 'column_num': 3, }, 'end': { 'filepath': '/separate_window', 'line_num': 3, 'column_num': 3, } }, 'ranges': [] }]), ('/hidden', [{ 'kind': 'ERROR', 'text': 'error text in hidden buffer', 'location': { 'filepath': '/hidden', 'line_num': 4, 'column_num': 2 }, 'location_extent': { 'start': { 'filepath': '/hidden', 'line_num': 4, 'column_num': 2, }, 'end': { 'filepath': '/hidden', 'line_num': 4, 'column_num': 2, } }, 'ranges': [] }]), ('/not_open', [{ 'kind': 'ERROR', 'text': 'error text in buffer not open in Vim', 'location': { 'filepath': '/not_open', 'line_num': 8, 'column_num': 4 }, 'location_extent': { 'start': { 'filepath': '/not_open', 'line_num': 8, 'column_num': 4, }, 'end': { 'filepath': '/not_open', 'line_num': 8, 'column_num': 4, } }, 'ranges': [] }]) ] current_buffer = VimBuffer('/current', filetype='ycmtest', contents=['current'] * 10, number=1) no_diags_buffer = VimBuffer('/no_diags', filetype='ycmtest', contents=['no_diags'] * 10, number=2) separate_window = VimBuffer('/separate_window', filetype='ycmtest', contents=['separate_window'] * 10, number=3) hidden_buffer = VimBuffer('/hidden', filetype='ycmtest', contents=['hidden'] * 10, number=4) buffers = [current_buffer, no_diags_buffer, separate_window, hidden_buffer] windows = [current_buffer, no_diags_buffer, separate_window] # Register each buffer internally with YCM for current in buffers: with MockVimBuffers(buffers, [current]): ycm.OnFileReadyToParse() with patch('ycm.vimsupport.SetLocationListForWindow', new_callable=ExtendedMock) as set_location_list_for_window: with MockVimBuffers(buffers, windows): for filename, diagnostics in diagnostics_per_file: ycm.UpdateWithNewDiagnosticsForFile(filename, diagnostics) # We update the diagnostic on the current cursor position post_vim_message.assert_has_exact_calls([ call("error text in current buffer", truncate=True, warning=False), ]) # Ensure we included all the diags though set_location_list_for_window.assert_has_exact_calls([ call(1, [ { 'lnum': 1, 'col': 1, 'bufnr': 1, 'valid': 1, 'type': 'E', 'text': 'error text in current buffer', }, ]), call(3, [ { 'lnum': 3, 'col': 3, 'bufnr': 3, 'valid': 1, 'type': 'E', 'text': 'error text in a buffer open in a separate window', }, ]) ]) # FIXME: diagnostic matches in windows other than the current one are not # updated. assert_that( test_utils.VIM_MATCHES_FOR_WINDOW, has_entries({ 1: contains( VimMatch('YcmErrorSection', '\\%1l\\%1c\\_.\\{-}\\%1l\\%1c')) }))
def YouCompleteMe_AsyncDiagnosticUpdate_SingleFile_test( ycm, post_vim_message, *args): # This test simulates asynchronous diagnostic updates associated with a single # file (e.g. Translation Unit), but where the actual errors refer to other # open files and other non-open files. This is not strictly invalid, nor is it # completely normal, but it is supported and does work. # Contrast with the next test which sends the diagnostics filewise, which is # what the language server protocol will do. diagnostics = [{ 'kind': 'ERROR', 'text': 'error text in current buffer', 'location': { 'filepath': '/current', 'line_num': 1, 'column_num': 1 }, 'location_extent': { 'start': { 'filepath': '/current', 'line_num': 1, 'column_num': 1, }, 'end': { 'filepath': '/current', 'line_num': 1, 'column_num': 1, } }, 'ranges': [] }, { 'kind': 'ERROR', 'text': 'error text in hidden buffer', 'location': { 'filepath': '/has_diags', 'line_num': 4, 'column_num': 2 }, 'location_extent': { 'start': { 'filepath': '/has_diags', 'line_num': 4, 'column_num': 2, }, 'end': { 'filepath': '/has_diags', 'line_num': 4, 'column_num': 2, } }, 'ranges': [] }, { 'kind': 'ERROR', 'text': 'error text in buffer not open in Vim', 'location': { 'filepath': '/not_open', 'line_num': 8, 'column_num': 4 }, 'location_extent': { 'start': { 'filepath': '/not_open', 'line_num': 8, 'column_num': 4, }, 'end': { 'filepath': '/not_open', 'line_num': 8, 'column_num': 4, } }, 'ranges': [] }] current_buffer = VimBuffer('/current', filetype='ycmtest', contents=['current'] * 10, number=1) no_diags_buffer = VimBuffer('/no_diags', filetype='ycmtest', contents=['nodiags'] * 10, number=2) hidden_buffer = VimBuffer('/has_diags', filetype='ycmtest', contents=['hasdiags'] * 10, number=3) buffers = [current_buffer, no_diags_buffer, hidden_buffer] windows = [current_buffer, no_diags_buffer] # Register each buffer internally with YCM for current in buffers: with MockVimBuffers(buffers, [current]): ycm.OnFileReadyToParse() with patch('ycm.vimsupport.SetLocationListForWindow', new_callable=ExtendedMock) as set_location_list_for_window: with MockVimBuffers(buffers, windows): ycm.UpdateWithNewDiagnosticsForFile('/current', diagnostics) # We update the diagnostic on the current cursor position post_vim_message.assert_has_exact_calls([ call("error text in current buffer", truncate=True, warning=False), ]) # Ensure we included all the diags though set_location_list_for_window.assert_has_exact_calls([ call( 1, [ { 'lnum': 1, 'col': 1, 'bufnr': 1, 'valid': 1, 'type': 'E', 'text': 'error text in current buffer', }, { 'lnum': 4, 'col': 2, 'bufnr': 3, 'valid': 1, 'type': 'E', 'text': 'error text in hidden buffer', }, { 'lnum': 8, 'col': 4, 'bufnr': -1, # sic: Our mocked bufnr function actually returns -1, # even though YCM is passing "create if needed". # FIXME? we shouldn't do that, and we should pass # filename instead 'valid': 1, 'type': 'E', 'text': 'error text in buffer not open in Vim' } ]) ]) assert_that( test_utils.VIM_MATCHES_FOR_WINDOW, has_entries({ 1: contains( VimMatch('YcmErrorSection', '\\%1l\\%1c\\_.\\{-}\\%1l\\%1c')) }))
def YouCompleteMe_UpdateDiagnosticInterface(ycm, post_vim_message, *args): contents = """int main() { int x, y; x == y }""" # List of diagnostics returned by ycmd for the above code. diagnostics = [ { 'kind': 'ERROR', 'text': "expected ';' after expression", 'location': { 'filepath': 'buffer', 'line_num': 3, 'column_num': 9 }, # Looks strange but this is really what ycmd is returning. 'location_extent': { 'start': { 'filepath': '', 'line_num': 0, 'column_num': 0, }, 'end': { 'filepath': '', 'line_num': 0, 'column_num': 0, } }, 'ranges': [], 'fixit_available': True }, { 'kind': 'WARNING', 'text': 'equality comparison result unused', 'location': { 'filepath': 'buffer', 'line_num': 3, 'column_num': 7, }, 'location_extent': { 'start': { 'filepath': 'buffer', 'line_num': 3, 'column_num': 5, }, 'end': { 'filepath': 'buffer', 'line_num': 3, 'column_num': 7, } }, 'ranges': [{ 'start': { 'filepath': 'buffer', 'line_num': 3, 'column_num': 3, }, 'end': { 'filepath': 'buffer', 'line_num': 3, 'column_num': 9, } }], 'fixit_available': True } ] current_buffer = VimBuffer('buffer', filetype='c', contents=contents.splitlines(), number=5) test_utils.VIM_SIGNS = [] vimsupport.SIGN_ID_FOR_BUFFER.clear() with MockVimBuffers([current_buffer], [current_buffer], (3, 1)): with patch('ycm.client.event_notification.EventNotification.Response', return_value=diagnostics): ycm.OnFileReadyToParse() ycm.HandleFileParseRequest(block=True) # The error on the current line is echoed, not the warning. post_vim_message.assert_called_once_with( "expected ';' after expression (FixIt)", truncate=True, warning=False) # Error match is added after warning matches. assert_that( test_utils.VIM_MATCHES_FOR_WINDOW, has_entries({ 1: contains( VimMatch('YcmWarningSection', '\\%3l\\%5c\\_.\\{-}\\%3l\\%7c'), VimMatch('YcmWarningSection', '\\%3l\\%3c\\_.\\{-}\\%3l\\%9c'), VimMatch('YcmErrorSection', '\\%3l\\%8c')) })) # Only the error sign is placed. assert_that( test_utils.VIM_SIGNS, contains(VimSign(SIGN_BUFFER_ID_INITIAL_VALUE, 3, 'YcmError', 5))) # The error is not echoed again when moving the cursor along the line. with MockVimBuffers([current_buffer], [current_buffer], (3, 2)): post_vim_message.reset_mock() ycm.OnCursorMoved() post_vim_message.assert_not_called() # The error is cleared when moving the cursor to another line. with MockVimBuffers([current_buffer], [current_buffer], (2, 2)): post_vim_message.reset_mock() ycm.OnCursorMoved() post_vim_message.assert_called_once_with("", warning=False) # The error is echoed when moving the cursor back. with MockVimBuffers([current_buffer], [current_buffer], (3, 2)): post_vim_message.reset_mock() ycm.OnCursorMoved() post_vim_message.assert_called_once_with( "expected ';' after expression (FixIt)", truncate=True, warning=False) with patch('ycm.client.event_notification.EventNotification.Response', return_value=diagnostics[1:]): ycm.OnFileReadyToParse() ycm.HandleFileParseRequest(block=True) assert_that( test_utils.VIM_MATCHES_FOR_WINDOW, has_entries({ 1: contains( VimMatch('YcmWarningSection', '\\%3l\\%5c\\_.\\{-}\\%3l\\%7c'), VimMatch('YcmWarningSection', '\\%3l\\%3c\\_.\\{-}\\%3l\\%9c')) })) assert_that( test_utils.VIM_SIGNS, contains( VimSign(SIGN_BUFFER_ID_INITIAL_VALUE + 1, 3, 'YcmWarning', 5)))
def YouCompleteMe_UpdateDiagnosticInterface_PrioritizeErrorsOverWarnings_test( ycm, vim_command, post_vim_message, *args): contents = """int main() { int x, y; x == y }""" # List of diagnostics returned by ycmd for the above code. diagnostics = [ { 'kind': 'ERROR', 'text': "expected ';' after expression", 'location': { 'filepath': 'buffer', 'line_num': 3, 'column_num': 9 }, # Looks strange but this is really what ycmd is returning. 'location_extent': { 'start': { 'filepath': '', 'line_num': 0, 'column_num': 0, }, 'end': { 'filepath': '', 'line_num': 0, 'column_num': 0, } }, 'ranges': [], 'fixit_available': True }, { 'kind': 'WARNING', 'text': 'equality comparison result unused', 'location': { 'filepath': 'buffer', 'line_num': 3, 'column_num': 7, }, 'location_extent': { 'start': { 'filepath': 'buffer', 'line_num': 3, 'column_num': 5, }, 'end': { 'filepath': 'buffer', 'line_num': 3, 'column_num': 7, } }, 'ranges': [{ 'start': { 'filepath': 'buffer', 'line_num': 3, 'column_num': 3, }, 'end': { 'filepath': 'buffer', 'line_num': 3, 'column_num': 9, } }], 'fixit_available': True } ] current_buffer = VimBuffer('buffer', filetype='c', contents=contents.splitlines(), number=5, window=2) test_utils.VIM_MATCHES = [] with MockVimBuffers([current_buffer], current_buffer, (3, 1)): with patch('ycm.client.event_notification.EventNotification.Response', return_value=diagnostics): ycm.OnFileReadyToParse() ycm.HandleFileParseRequest(block=True) # Error match is added after warning matches. assert_that( test_utils.VIM_MATCHES, contains( VimMatch('YcmWarningSection', '\%3l\%5c\_.\{-}\%3l\%7c'), VimMatch('YcmWarningSection', '\%3l\%3c\_.\{-}\%3l\%9c'), # FIXME: match should be inserted at the end of line 3 (missing ";"). VimMatch('YcmErrorSection', '\%0l\%0c'))) # Only the error sign is placed. vim_command.assert_has_exact_calls([ call('sign define ycm_dummy_sign'), call('sign place 3 name=ycm_dummy_sign line=3 buffer=5'), call('sign place 1 name=YcmError line=3 buffer=5'), call('sign undefine ycm_dummy_sign'), call('sign unplace 3 buffer=5') ]) # When moving the cursor on the diagnostics, the error is displayed to the # user, not the warning. ycm.OnCursorMoved() post_vim_message.assert_has_exact_calls([ call("expected ';' after expression (FixIt)", truncate=True, warning=False) ])