def Diagnostics_Multiline_test( app ): contents = """ struct Foo { Foo(int z) {} }; int main() { Foo foo("goo"); } """ diag_data = BuildRequest( compilation_flags = [ '-x', 'c++' ], line_num = 7, contents = contents, filetype = 'cpp' ) event_data = diag_data.copy() event_data.update( { 'event_name': 'FileReadyToParse', } ) app.post_json( '/event_notification', event_data ) results = app.post_json( '/detailed_diagnostic', diag_data ).json assert_that( results, has_entry( 'message', contains_string( "\n" ) ) )
def _ShouldUseNowForLine( filename_completer, contents, extra_data = None, column_num = None ): # Strictly, column numbers are *byte* offsets, not character offsets. If # the contents of the file contain unicode characters, then we should manually # supply the correct byte offset. column_num = len( contents ) + 1 if not column_num else column_num request = BuildRequest( column_num = column_num, filepath = PATH_TO_TEST_FILE, contents = contents ) if extra_data: request.update( extra_data ) request_data = RequestWrap( request ) return filename_completer.ShouldUseNow( request_data )
def Diagnostics_Works_test(app): contents = """ struct Foo { int x // semicolon missing here! int y; int c; int d; }; """ diag_data = BuildRequest(compilation_flags=["-x", "c++"], line_num=3, contents=contents, filetype="cpp") event_data = diag_data.copy() event_data.update({"event_name": "FileReadyToParse"}) app.post_json("/event_notification", event_data) results = app.post_json("/detailed_diagnostic", diag_data).json assert_that(results, has_entry("message", contains_string("expected ';'")))
def Diagnostics_Multiline_test(app): contents = """ struct Foo { Foo(int z) {} }; int main() { Foo foo("goo"); } """ diag_data = BuildRequest(compilation_flags=["-x", "c++"], line_num=7, contents=contents, filetype="cpp") event_data = diag_data.copy() event_data.update({"event_name": "FileReadyToParse"}) app.post_json("/event_notification", event_data) results = app.post_json("/detailed_diagnostic", diag_data).json assert_that(results, has_entry("message", contains_string("\n")))
def _CompletionResultsForLine( filename_completer, contents, extra_data = None, column_num = None ): # Strictly, column numbers are *byte* offsets, not character offsets. If # the contents of the file contain unicode characters, then we should manually # supply the correct byte offset. column_num = len( contents ) + 1 if not column_num else column_num request = BuildRequest( column_num = column_num, filepath = PATH_TO_TEST_FILE, contents = contents ) if extra_data: request.update( extra_data ) request_data = RequestWrap( request ) candidates = filename_completer.ComputeCandidatesInner( request_data ) return [ ( c[ 'insertion_text' ], c[ 'extra_menu_info' ] ) for c in candidates ]
def Diagnostics_Works_test( app ): contents = """ struct Foo { int x // semicolon missing here! int y; int c; int d; }; """ diag_data = BuildRequest( compilation_flags = ['-x', 'c++'], line_num = 3, contents = contents, filetype = 'cpp' ) event_data = diag_data.copy() event_data.update( { 'event_name': 'FileReadyToParse', } ) app.post_json( '/event_notification', event_data ) results = app.post_json( '/detailed_diagnostic', diag_data ).json assert_that( results, has_entry( 'message', contains_string( "expected ';'" ) ) )
def GetDebugInfo( app, filepath ): """ TODO: refactor here and in clangd test to common util """ request_data = BuildRequest( filetype = 'cs', filepath = filepath ) return app.post_json( '/debug_info', request_data ).json
def Poll_Diagnostics_ChangeFileContents_test(app): StartJavaCompleterServerInDirectory(app, PathToTestFile(DEFAULT_PROJECT_DIR)) filepath = youcompleteme_Test old_contents = """package com.youcompleteme; public class Test { public String test; }""" messages_for_filepath = [] with PollingThread(app, messages_for_filepath, filepath, old_contents): new_contents = """package com.youcompleteme; public class Test { public String test; public String test; }""" event_data = BuildRequest(event_name='FileReadyToParse', contents=new_contents, filepath=filepath, filetype='java') app.post_json('/event_notification', event_data).json expiration = time.time() + 10 while True: try: assert_that( messages_for_filepath, has_item( has_entries({ 'filepath': filepath, 'diagnostics': contains_exactly( has_entries({ 'kind': 'ERROR', 'text': 'Duplicate field Test.test [33554772]', 'location': LocationMatcher(youcompleteme_Test, 4, 17), 'location_extent': RangeMatcher(youcompleteme_Test, (4, 17), (4, 21)), 'ranges': contains_exactly( RangeMatcher(youcompleteme_Test, (4, 17), (4, 21))), 'fixit_available': False }), has_entries({ 'kind': 'ERROR', 'text': 'Duplicate field Test.test [33554772]', 'location': LocationMatcher(youcompleteme_Test, 5, 17), 'location_extent': RangeMatcher(youcompleteme_Test, (5, 17), (5, 21)), 'ranges': contains_exactly( RangeMatcher(youcompleteme_Test, (5, 17), (5, 21))), 'fixit_available': False })) }))) break except AssertionError: if time.time() > expiration: raise time.sleep(0.25)
def EventNotification_OnBufferUnload_CloseFile_test(app): # Open main.ts file in a buffer. main_filepath = PathToTestFile('buffer_unload', 'main.ts') main_contents = ReadFile(main_filepath) event_data = BuildRequest(filepath=main_filepath, filetype='typescript', contents=main_contents, event_name='BufferVisit') app.post_json('/event_notification', event_data) # Complete in main.ts buffer an object defined in imported.ts. completion_data = BuildRequest(filepath=main_filepath, filetype='typescript', contents=main_contents, line_num=3, column_num=10) response = app.post_json('/completions', completion_data) assert_that( response.json, has_entries( {'completions': contains(CompletionEntryMatcher('method'))})) # Open imported.ts file in another buffer. imported_filepath = PathToTestFile('buffer_unload', 'imported.ts') imported_contents = ReadFile(imported_filepath) event_data = BuildRequest(filepath=imported_filepath, filetype='typescript', contents=imported_contents, event_name='BufferVisit') app.post_json('/event_notification', event_data) # Modify imported.ts buffer without writing the changes to disk. modified_imported_contents = imported_contents.replace( 'method', 'modified_method') # FIXME: TypeScript completer should not rely on the FileReadyToParse events # to synchronize the contents of dirty buffers but use instead the file_data # field of the request. event_data = BuildRequest(filepath=imported_filepath, filetype='typescript', contents=modified_imported_contents, event_name='FileReadyToParse') app.post_json('/event_notification', event_data) # Complete at same location in main.ts buffer. imported_data = { imported_filepath: { 'filetypes': ['typescript'], 'contents': modified_imported_contents } } completion_data = BuildRequest(filepath=main_filepath, filetype='typescript', contents=main_contents, line_num=3, column_num=10, file_data=imported_data) response = app.post_json('/completions', completion_data) assert_that( response.json, has_entries({ 'completions': contains(CompletionEntryMatcher('modified_method')) })) # Unload imported.ts buffer. event_data = BuildRequest(filepath=imported_filepath, filetype='typescript', contents=imported_contents, event_name='BufferUnload') app.post_json('/event_notification', event_data) # Complete at same location in main.ts buffer. completion_data = BuildRequest(filepath=main_filepath, filetype='typescript', contents=main_contents, line_num=3, column_num=10) response = app.post_json('/completions', completion_data) assert_that( response.json, has_entries( {'completions': contains(CompletionEntryMatcher('method'))}))
def Subcommands_RefactorRename_MultipleFiles_OnFileReadyToParse_test(app): StartJavaScriptCompleterServerInDirectory(app, PathToTestFile()) file1 = PathToTestFile('file1.js') file2 = PathToTestFile('file2.js') file3 = PathToTestFile('file3.js') # This test is roughly the same as the previous one, except here file4.js is # pushed into the Tern engine via 'opening it in the editor' (i.e. # FileReadyToParse event). The first 3 are loaded into the tern server # because they are listed in the .tern-project file's loadEagerly option. file4 = PathToTestFile('file4.js') app.post_json('/event_notification', BuildRequest( **{ 'filetype': 'javascript', 'event_name': 'FileReadyToParse', 'contents': ReadFile(file4), 'filepath': file4, }), expect_errors=False) RunTest( app, { 'description': 'FileReadyToParse loads files into tern server', 'request': { 'command': 'RefactorRename', 'arguments': ['a-quite-long-string'], 'filepath': file1, 'line_num': 3, 'column_num': 14, }, 'expect': { 'response': requests.codes.ok, 'data': has_entries({ 'fixits': contains( has_entries({ 'chunks': contains( ChunkMatcher('a-quite-long-string', LocationMatcher(file1, 1, 5), LocationMatcher(file1, 1, 11)), ChunkMatcher('a-quite-long-string', LocationMatcher(file1, 3, 14), LocationMatcher(file1, 3, 20)), ChunkMatcher('a-quite-long-string', LocationMatcher(file2, 2, 14), LocationMatcher(file2, 2, 20)), ChunkMatcher('a-quite-long-string', LocationMatcher(file3, 3, 12), LocationMatcher(file3, 3, 18)), ChunkMatcher('a-quite-long-string', LocationMatcher(file4, 4, 22), LocationMatcher(file4, 4, 28))), 'location': LocationMatcher(file1, 3, 14) })) }) } })
def CombineRequest(request, data): kw = request request.update(data) return BuildRequest(**kw)
def WorkspaceEditToFixIt_test(): if utils.OnWindows(): filepath = 'C:\\test.test' uri = 'file:///c:/test.test' else: filepath = '/test.test' uri = 'file:/test.test' contents = 'line1\nline2\nline3' request_data = RequestWrap( BuildRequest(filetype='ycmtest', filepath=filepath, contents=contents)) # Null response to textDocument/codeActions is valid assert_that(lsc.WorkspaceEditToFixIt(request_data, None), equal_to(None)) # Empty WorkspaceEdit is not explicitly forbidden assert_that(lsc.WorkspaceEditToFixIt(request_data, {}), equal_to(None)) # We don't support versioned documentChanges workspace_edit = { 'documentChanges': [{ 'textDocument': { 'version': 1, 'uri': uri }, 'edits': [{ 'newText': 'blah', 'range': { 'start': { 'line': 0, 'character': 5 }, 'end': { 'line': 0, 'character': 5 }, } }] }] } response = responses.BuildFixItResponse( [lsc.WorkspaceEditToFixIt(request_data, workspace_edit, 'test')]) print('Response: {0}'.format(response)) assert_that( response, has_entries({ 'fixits': contains( has_entries({ 'text': 'test', 'chunks': contains( ChunkMatcher('blah', LocationMatcher(filepath, 1, 6), LocationMatcher(filepath, 1, 6))) })) })) workspace_edit = { 'changes': { uri: [ { 'newText': 'blah', 'range': { 'start': { 'line': 0, 'character': 5 }, 'end': { 'line': 0, 'character': 5 }, } }, ] } } response = responses.BuildFixItResponse( [lsc.WorkspaceEditToFixIt(request_data, workspace_edit, 'test')]) print('Response: {0}'.format(response)) print('Type Response: {0}'.format(type(response))) assert_that( response, has_entries({ 'fixits': contains( has_entries({ 'text': 'test', 'chunks': contains( ChunkMatcher('blah', LocationMatcher(filepath, 1, 6), LocationMatcher(filepath, 1, 6))) })) }))
def Diagnostics_UpdatedOnBufferVisit_test(app): with TemporaryTestDir() as tmp_dir: source_file = os.path.join(tmp_dir, 'source.cpp') source_contents = """#include "header.h" int main() {return S::h();} """ with open(source_file, 'w') as sf: sf.write(source_contents) header_file = os.path.join(tmp_dir, 'header.h') old_header_content = """#pragma once struct S{static int h();}; """ with open(header_file, 'w') as hf: hf.write(old_header_content) flags_file = os.path.join(tmp_dir, 'compile_flags.txt') flags_content = """-xc++""" with open(flags_file, 'w') as ff: ff.write(flags_content) messages_request = { 'contents': source_contents, 'filepath': source_file, 'filetype': 'cpp' } test = {'request': messages_request, 'route': '/receive_messages'} response = RunAfterInitialized(app, test) assert_that(response, contains_exactly(has_entries({'diagnostics': empty()}))) # Overwrite header.cpp new_header_content = """#pragma once static int h(); """ with open(header_file, 'w') as f: f.write(new_header_content) # Send BufferVisit notification buffer_visit_request = { "event_name": "BufferVisit", "filepath": source_file, "filetype": 'cpp' } app.post_json('/event_notification', BuildRequest(**buffer_visit_request)) # Assert diagnostics for message in PollForMessages(app, messages_request): if 'diagnostics' in message: assert_that( message, has_entries({ 'diagnostics': contains_exactly( has_entries({ 'kind': equal_to('ERROR'), 'text': "Use of undeclared identifier 'S' [undeclared_var_use]", 'ranges': contains_exactly( RangeMatcher(contains_string(source_file), (2, 20), (2, 21))), 'location': LocationMatcher(contains_string(source_file), 2, 20), 'location_extent': RangeMatcher(contains_string(source_file), (2, 20), (2, 21)) })) })) break # Restore original content with open(header_file, 'w') as f: f.write(old_header_content) # Send BufferVisit notification app.post_json('/event_notification', BuildRequest(**buffer_visit_request)) # Assert no diagnostics for message in PollForMessages(app, messages_request): print(f'Message { pformat( message ) }') if 'diagnostics' in message: assert_that(message, has_entries({'diagnostics': empty()})) break # Assert no dirty files with open(header_file, 'r') as f: assert_that(f.read(), equal_to(old_header_content))
def LanguageServerCompleter_Diagnostics_NoLimitToNumberOfDiagnostics_test(): completer = MockCompleter({'max_diagnostics_to_display': 0}) filepath = os.path.realpath('/foo') uri = lsp.FilePathToUri(filepath) request_data = RequestWrap( BuildRequest(line_num=1, column_num=1, filepath=filepath, contents='')) notification = { 'jsonrpc': '2.0', 'method': 'textDocument/publishDiagnostics', 'params': { 'uri': uri, 'diagnostics': [{ 'range': { 'start': { 'line': 3, 'character': 10 }, 'end': { 'line': 3, 'character': 11 } }, 'severity': 1, 'message': 'First error' }, { 'range': { 'start': { 'line': 4, 'character': 7 }, 'end': { 'line': 4, 'character': 13 } }, 'severity': 1, 'message': 'Second error' }] } } completer.GetConnection()._notifications.put(notification) completer.HandleNotificationInPollThread(notification) with patch.object(completer, '_ServerIsInitialized', return_value=True): completer.OnFileReadyToParse(request_data) # Simulate receipt of response and initialization complete initialize_response = {'result': {'capabilities': {}}} completer._HandleInitializeInPollThread(initialize_response) diagnostics = contains( has_entries({ 'kind': equal_to('ERROR'), 'location': LocationMatcher(filepath, 4, 11), 'location_extent': RangeMatcher(filepath, (4, 11), (4, 12)), 'ranges': contains(RangeMatcher(filepath, (4, 11), (4, 12))), 'text': equal_to('First error'), 'fixit_available': False }), has_entries({ 'kind': equal_to('ERROR'), 'location': LocationMatcher(filepath, 5, 8), 'location_extent': RangeMatcher(filepath, (5, 8), (5, 14)), 'ranges': contains(RangeMatcher(filepath, (5, 8), (5, 14))), 'text': equal_to('Second error'), 'fixit_available': False })) assert_that(completer.OnFileReadyToParse(request_data), diagnostics) assert_that( completer.PollForMessages(request_data), contains( has_entries({ 'diagnostics': diagnostics, 'filepath': filepath })))
def LanguageServerCompleter_GoTo_test(): if utils.OnWindows(): filepath = 'C:\\test.test' uri = 'file:///c:/test.test' else: filepath = '/test.test' uri = 'file:/test.test' contents = 'line1\nline2\nline3' completer = MockCompleter() # LSP server supports all code navigation features. completer._server_capabilities = { 'definitionProvider': True, 'declarationProvider': True, 'typeDefinitionProvider': True, 'implementationProvider': True, 'referencesProvider': True } request_data = RequestWrap( BuildRequest(filetype='ycmtest', filepath=filepath, contents=contents, line_num=2, column_num=3)) @patch.object(completer, '_ServerIsInitialized', return_value=True) def Test(responses, command, exception, throws, *args): with patch.object(completer.GetConnection(), 'GetResponse', side_effect=responses): if throws: assert_that( calling(completer.OnUserCommand).with_args([command], request_data), raises(exception)) else: result = completer.OnUserCommand([command], request_data) print('Result: {}'.format(result)) assert_that(result, exception) location = { 'uri': uri, 'range': { 'start': { 'line': 0, 'character': 0 }, 'end': { 'line': 0, 'character': 0 }, } } goto_response = has_entries({ 'filepath': filepath, 'column_num': 1, 'line_num': 1, 'description': 'line1' }) cases = [ ([{ 'result': None }], 'GoToDefinition', RuntimeError, True), ([{ 'result': location }], 'GoToDeclaration', goto_response, False), ([{ 'result': {} }], 'GoToType', RuntimeError, True), ([{ 'result': [] }], 'GoToImplementation', RuntimeError, True), ([{ 'result': [location] }], 'GoToReferences', goto_response, False), ([{ 'result': [location, location] }], 'GoToReferences', contains(goto_response, goto_response), False), ] for response, goto_handlers, exception, throws in cases: yield Test, response, goto_handlers, exception, throws # All requests return an invalid URI. with patch( 'ycmd.completers.language_server.language_server_protocol.UriToFilePath', side_effect=lsp.InvalidUriException): yield Test, [{ 'result': { 'uri': uri, 'range': { 'start': { 'line': 0, 'character': 0 }, 'end': { 'line': 0, 'character': 0 }, } } }], 'GoTo', LocationMatcher('', 1, 1), False with patch('ycmd.completers.completer_utils.GetFileContents', side_effect=IOError): yield Test, [{ 'result': { 'uri': uri, 'range': { 'start': { 'line': 0, 'character': 0 }, 'end': { 'line': 0, 'character': 0 }, } } }], 'GoToDefinition', LocationMatcher(filepath, 1, 1), False # Both requests return the location where the cursor is. yield Test, [{ 'result': { 'uri': uri, 'range': { 'start': { 'line': 1, 'character': 0 }, 'end': { 'line': 1, 'character': 4 }, } } }, { 'result': { 'uri': uri, 'range': { 'start': { 'line': 1, 'character': 0 }, 'end': { 'line': 1, 'character': 4 }, } } }], 'GoTo', LocationMatcher(filepath, 2, 1), False # First request returns two locations. yield Test, [{ 'result': [{ 'uri': uri, 'range': { 'start': { 'line': 0, 'character': 0 }, 'end': { 'line': 0, 'character': 4 }, } }, { 'uri': uri, 'range': { 'start': { 'line': 1, 'character': 0 }, 'end': { 'line': 1, 'character': 4 }, } }], }], 'GoTo', contains(LocationMatcher(filepath, 1, 1), LocationMatcher(filepath, 2, 1)), False # First request returns the location where the cursor is and second request # returns a different URI. if utils.OnWindows(): other_filepath = 'C:\\another.test' other_uri = 'file:///c:/another.test' else: other_filepath = '/another.test' other_uri = 'file:/another.test' yield Test, [{ 'result': { 'uri': uri, 'range': { 'start': { 'line': 1, 'character': 0 }, 'end': { 'line': 1, 'character': 4 }, } } }, { 'result': { 'uri': other_uri, 'range': { 'start': { 'line': 1, 'character': 0 }, 'end': { 'line': 1, 'character': 4 }, } } }], 'GoTo', LocationMatcher(other_filepath, 2, 1), False # First request returns a location before the cursor. yield Test, [{ 'result': { 'uri': uri, 'range': { 'start': { 'line': 0, 'character': 1 }, 'end': { 'line': 1, 'character': 1 }, } } }], 'GoTo', LocationMatcher(filepath, 1, 2), False # First request returns a location after the cursor. yield Test, [{ 'result': { 'uri': uri, 'range': { 'start': { 'line': 1, 'character': 3 }, 'end': { 'line': 2, 'character': 3 }, } } }], 'GoTo', LocationMatcher(filepath, 2, 4), False
def MiscHandlers_EventNotification_AlwaysJsonResponse_test(app): event_data = BuildRequest(contents='foo foogoo ba', event_name='FileReadyToParse') assert_that(app.post_json('/event_notification', event_data).json, empty())
def MiscHandlers_SemanticCompletionAvailable_test(app): with PatchCompleter(DummyCompleter, filetype='dummy_filetype'): request_data = BuildRequest(filetype='dummy_filetype') assert_that( app.post_json('/semantic_completion_available', request_data).json, equal_to(True))
def _CombineRequest( request, data ): return BuildRequest( **_Merge( request, data ) )
def Diagnostics_DoesWork_test(get_detailed_diag, app): with PatchCompleter(DummyCompleter, filetype='dummy_filetype'): diag_data = BuildRequest(contents='foo = 5', filetype='dummy_filetype') response = app.post_json('/detailed_diagnostic', diag_data) assert_that(response.json, MessageMatcher('detailed diagnostic'))
def LanguageServerCompleter_GetCompletions_CompleteOnCurrentColumn_test(): completer = MockCompleter() completer._resolve_completion_items = False a_response = { 'result': { 'items': [{ 'label': 'aba' }, { 'label': 'aab' }, { 'label': 'aaa' }], 'isIncomplete': True } } aa_response = { 'result': { 'items': [{ 'label': 'aab' }, { 'label': 'aaa' }], 'isIncomplete': False } } aaa_response = { 'result': { 'items': [{ 'label': 'aaa' }], 'isIncomplete': False } } ab_response = { 'result': { 'items': [{ 'label': 'abb' }, { 'label': 'aba' }], 'isIncomplete': False } } with patch.object(completer, '_is_completion_provider', True): # User starts by typing the character "a". request_data = RequestWrap( BuildRequest(column_num=2, contents='a', force_semantic=True)) with patch.object(completer.GetConnection(), 'GetResponse', return_value=a_response) as response: assert_that( completer.ComputeCandidates(request_data), contains(has_entry('insertion_text', 'aaa'), has_entry('insertion_text', 'aab'), has_entry('insertion_text', 'aba'))) # Nothing cached yet. assert_that(response.call_count, equal_to(1)) # User types again the character "a". request_data = RequestWrap( BuildRequest(column_num=3, contents='aa', force_semantic=True)) with patch.object(completer.GetConnection(), 'GetResponse', return_value=aa_response) as response: assert_that( completer.ComputeCandidates(request_data), contains(has_entry('insertion_text', 'aaa'), has_entry('insertion_text', 'aab'))) # The server returned an incomplete list of completions the first time so # a new completion request should have been sent. assert_that(response.call_count, equal_to(1)) # User types the character "a" a third time. request_data = RequestWrap( BuildRequest(column_num=4, contents='aaa', force_semantic=True)) with patch.object(completer.GetConnection(), 'GetResponse', return_value=aaa_response) as response: assert_that(completer.ComputeCandidates(request_data), contains(has_entry('insertion_text', 'aaa'))) # The server returned a complete list of completions the second time and # the new query is a prefix of the cached one ("aa" is a prefix of "aaa") # so the cache should be used. assert_that(response.call_count, equal_to(0)) # User deletes the third character. request_data = RequestWrap( BuildRequest(column_num=3, contents='aa', force_semantic=True)) with patch.object(completer.GetConnection(), 'GetResponse', return_value=aa_response) as response: assert_that( completer.ComputeCandidates(request_data), contains(has_entry('insertion_text', 'aaa'), has_entry('insertion_text', 'aab'))) # The new query is still a prefix of the cached one ("aa" is a prefix of # "aa") so the cache should again be used. assert_that(response.call_count, equal_to(0)) # User deletes the second character. request_data = RequestWrap( BuildRequest(column_num=2, contents='a', force_semantic=True)) with patch.object(completer.GetConnection(), 'GetResponse', return_value=a_response) as response: assert_that( completer.ComputeCandidates(request_data), contains(has_entry('insertion_text', 'aaa'), has_entry('insertion_text', 'aab'), has_entry('insertion_text', 'aba'))) # The new query is not anymore a prefix of the cached one ("aa" is not a # prefix of "a") so the cache is invalidated and a new request is sent. assert_that(response.call_count, equal_to(1)) # Finally, user inserts the "b" character. request_data = RequestWrap( BuildRequest(column_num=3, contents='ab', force_semantic=True)) with patch.object(completer.GetConnection(), 'GetResponse', return_value=ab_response) as response: assert_that( completer.ComputeCandidates(request_data), contains(has_entry('insertion_text', 'aba'), has_entry('insertion_text', 'abb'))) # Last response was incomplete so the cache should not be used. assert_that(response.call_count, equal_to(1))
def LanguageServerCompleter_Diagnostics_PercentEncodeCannonical_test(): completer = MockCompleter() filepath = os.path.realpath('/foo?') uri = lsp.FilePathToUri(filepath) assert_that(uri, ends_with('%3F')) request_data = RequestWrap( BuildRequest(line_num=1, column_num=1, filepath=filepath, contents='')) notification = { 'jsonrpc': '2.0', 'method': 'textDocument/publishDiagnostics', 'params': { 'uri': uri.replace('%3F', '%3f'), 'diagnostics': [{ 'range': { 'start': { 'line': 3, 'character': 10 }, 'end': { 'line': 3, 'character': 11 } }, 'severity': 1, 'message': 'First error' }] } } completer.GetConnection()._notifications.put(notification) completer.HandleNotificationInPollThread(notification) with patch.object(completer, 'ServerIsReady', return_value=True): completer.SendInitialize( request_data, completer._GetSettingsFromExtraConf(request_data)) # Simulate receipt of response and initialization complete initialize_response = {'result': {'capabilities': {}}} completer._HandleInitializeInPollThread(initialize_response) diagnostics = contains( has_entries({ 'kind': equal_to('ERROR'), 'location': LocationMatcher(filepath, 4, 11), 'location_extent': RangeMatcher(filepath, (4, 11), (4, 12)), 'ranges': contains(RangeMatcher(filepath, (4, 11), (4, 12))), 'text': equal_to('First error'), 'fixit_available': False })) assert_that(completer.OnFileReadyToParse(request_data), diagnostics) assert_that( completer.PollForMessages(request_data), contains( has_entries({ 'diagnostics': diagnostics, 'filepath': filepath })))
def Diagnostics_LocationExtent_MissingSemicolon_test(app): contents = ReadFile(PathToTestFile('location_extent.cc')) event_data = BuildRequest(contents=contents, event_name='FileReadyToParse', filetype='cpp', filepath='foo', compilation_flags=['-x', 'c++']) response = app.post_json('/event_notification', event_data).json pprint(response) assert_that( response, contains( has_entries({ 'kind': equal_to('ERROR'), 'location': has_entries({ 'line_num': 2, 'column_num': 9, 'filepath': 'foo' }), 'location_extent': has_entries({ 'start': has_entries({ 'line_num': 2, 'column_num': 9, 'filepath': 'foo' }), 'end': has_entries({ 'line_num': 2, 'column_num': 9, 'filepath': 'foo' }) }), 'ranges': empty(), 'text': equal_to("expected ';' at end of declaration list"), 'fixit_available': True }), has_entries({ 'kind': equal_to('ERROR'), 'location': has_entries({ 'line_num': 5, 'column_num': 1, 'filepath': 'foo' }), 'location_extent': has_entries({ 'start': has_entries({ 'line_num': 5, 'column_num': 1, 'filepath': 'foo' }), 'end': has_entries({ 'line_num': 6, 'column_num': 11, 'filepath': 'foo' }) }), 'ranges': empty(), 'text': equal_to("unknown type name 'multiline_identifier'"), 'fixit_available': False }), has_entries({ 'kind': equal_to('ERROR'), 'location': has_entries({ 'line_num': 8, 'column_num': 7, 'filepath': 'foo' }), 'location_extent': has_entries({ 'start': has_entries({ 'line_num': 8, 'column_num': 7, 'filepath': 'foo' }), 'end': has_entries({ 'line_num': 8, 'column_num': 11, 'filepath': 'foo' }) }), 'ranges': contains( # FIXME: empty ranges from libclang should be ignored. has_entries({ 'start': has_entries({ 'line_num': 0, 'column_num': 0, 'filepath': '' }), 'end': has_entries({ 'line_num': 0, 'column_num': 0, 'filepath': '' }) }), has_entries({ 'start': has_entries({ 'line_num': 8, 'column_num': 7, 'filepath': 'foo' }), 'end': has_entries({ 'line_num': 8, 'column_num': 11, 'filepath': 'foo' }) })), 'text': equal_to('constructor cannot have a return type'), 'fixit_available': False })))
def test_Diagnostics_FileReadyToParse(self, app): filepath = PathToTestFile('test.ts') contents = ReadFile(filepath) event_data = BuildRequest(filepath=filepath, filetype='typescript', contents=contents, event_name='BufferVisit') app.post_json('/event_notification', event_data) event_data = BuildRequest(filepath=filepath, filetype='typescript', contents=contents, event_name='FileReadyToParse') assert_that( app.post_json('/event_notification', event_data).json, contains_inanyorder( has_entries({ 'kind': 'ERROR', 'text': "Property 'mA' does not exist on type 'Foo'.", 'location': LocationMatcher(filepath, 17, 5), 'location_extent': RangeMatcher(filepath, (17, 5), (17, 7)), 'ranges': contains_exactly(RangeMatcher(filepath, (17, 5), (17, 7))), 'fixit_available': True }), has_entries({ 'kind': 'ERROR', 'text': "Property 'nonExistingMethod' does not exist on type 'Bar'.", 'location': LocationMatcher(filepath, 35, 5), 'location_extent': RangeMatcher(filepath, (35, 5), (35, 22)), 'ranges': contains_exactly(RangeMatcher(filepath, (35, 5), (35, 22))), 'fixit_available': True }), has_entries({ 'kind': 'ERROR', 'text': 'Expected 1-2 arguments, but got 0.', 'location': LocationMatcher(filepath, 37, 5), 'location_extent': RangeMatcher(filepath, (37, 5), (37, 12)), 'ranges': contains_exactly(RangeMatcher(filepath, (37, 5), (37, 12))), 'fixit_available': False }), has_entries({ 'kind': 'ERROR', 'text': "Cannot find name 'Bår'.", 'location': LocationMatcher(filepath, 39, 1), 'location_extent': RangeMatcher(filepath, (39, 1), (39, 5)), 'ranges': contains_exactly(RangeMatcher(filepath, (39, 1), (39, 5))), 'fixit_available': True }), ))
def Diagnostics_Unity_test(app): app.post_json('/load_extra_conf_file', {'filepath': PathToTestFile('.ycm_extra_conf.py')}) for filename in ['unity.cc', 'unity.h', 'unitya.cc']: contents = ReadFile(PathToTestFile(filename)) event_data = BuildRequest(filepath=PathToTestFile(filename), contents=contents, event_name='FileReadyToParse', filetype='cpp') response = app.post_json('/event_notification', event_data).json pprint(response) assert_that( response, contains_inanyorder( has_entries({ 'kind': equal_to('ERROR'), 'location': has_entries({ 'line_num': 4, 'column_num': 3, 'filepath': PathToTestFile('unity.h') }), 'location_extent': has_entries({ 'start': has_entries({ 'line_num': 4, 'column_num': 3, 'filepath': PathToTestFile('unity.h') }), 'end': has_entries({ 'line_num': 4, 'column_num': 14, 'filepath': PathToTestFile('unity.h') }), }), 'ranges': empty(), 'text': equal_to("use of undeclared identifier 'fake_method'"), 'fixit_available': False }), has_entries({ 'kind': equal_to('ERROR'), 'location': has_entries({ 'line_num': 11, 'column_num': 18, 'filepath': PathToTestFile('unitya.cc') }), 'location_extent': has_entries({ 'start': has_entries({ 'line_num': 11, 'column_num': 18, 'filepath': PathToTestFile('unitya.cc') }), 'end': has_entries({ 'line_num': 11, 'column_num': 18, 'filepath': PathToTestFile('unitya.cc') }), }), 'ranges': empty(), 'text': equal_to("expected ';' after expression"), 'fixit_available': True }), ))
def StopRacerdServer(app): app.post_json('/run_completer_command', BuildRequest(completer_target='filetype_default', command_arguments=['StopServer'], filetype='rust'), expect_errors=True)
def Diagnostics_CUDA_Kernel_test(app): filepath = PathToTestFile('cuda', 'kernel_call.cu') contents = ReadFile(filepath) event_data = BuildRequest( filepath=filepath, contents=contents, event_name='FileReadyToParse', filetype='cuda', compilation_flags=['-x', 'cuda', '-nocudainc', '-nocudalib']) response = app.post_json('/event_notification', event_data).json pprint(response) assert_that( response, contains_inanyorder( has_entries({ 'kind': equal_to('ERROR'), 'location': has_entries({ 'line_num': 59, 'column_num': 5 }), 'location_extent': has_entries({ 'start': has_entries({ 'line_num': 59, 'column_num': 5 }), 'end': has_entries({ 'line_num': 59, 'column_num': 6 }), }), 'ranges': contains( has_entries({ 'start': has_entries({ 'line_num': 59, 'column_num': 3 }), 'end': has_entries({ 'line_num': 59, 'column_num': 5 }), })), 'text': equal_to('call to global function g1 not configured'), 'fixit_available': False }), has_entries({ 'kind': equal_to('ERROR'), 'location': has_entries({ 'line_num': 60, 'column_num': 9 }), 'location_extent': has_entries({ 'start': has_entries({ 'line_num': 60, 'column_num': 9 }), 'end': has_entries({ 'line_num': 60, 'column_num': 12 }), }), 'ranges': contains( has_entries({ 'start': has_entries({ 'line_num': 60, 'column_num': 5 }), 'end': has_entries({ 'line_num': 60, 'column_num': 8 }), })), 'text': equal_to( 'too few execution configuration arguments to kernel function call,' + ' expected at least 2, have 1'), 'fixit_available': False }), has_entries({ 'kind': equal_to('ERROR'), 'location': has_entries({ 'line_num': 61, 'column_num': 20 }), 'location_extent': has_entries({ 'start': has_entries({ 'line_num': 61, 'column_num': 20 }), 'end': has_entries({ 'line_num': 61, 'column_num': 21 }), }), 'ranges': contains( has_entries({ 'start': has_entries({ 'line_num': 61, 'column_num': 5 }), 'end': has_entries({ 'line_num': 61, 'column_num': 8 }), }), has_entries({ 'start': has_entries({ 'line_num': 61, 'column_num': 20 }), 'end': has_entries({ 'line_num': 61, 'column_num': 21 }), }), ), 'text': equal_to( 'too many execution configuration arguments to kernel' + ' function call, expected at most 4, have 5'), 'fixit_available': False }), has_entries({ 'kind': equal_to('ERROR'), 'location': has_entries({ 'line_num': 65, 'column_num': 15 }), 'location_extent': has_entries({ 'start': has_entries({ 'line_num': 65, 'column_num': 15 }), 'end': has_entries({ 'line_num': 65, 'column_num': 16 }), }), 'ranges': contains( has_entries({ 'start': has_entries({ 'line_num': 65, 'column_num': 3 }), 'end': has_entries({ 'line_num': 65, 'column_num': 5 }), })), 'text': equal_to('kernel call to non-global function h1'), 'fixit_available': False }), has_entries({ 'kind': equal_to('ERROR'), 'location': has_entries({ 'line_num': 68, 'column_num': 15 }), 'location_extent': has_entries({ 'start': has_entries({ 'line_num': 68, 'column_num': 15 }), 'end': has_entries({ 'line_num': 68, 'column_num': 16 }), }), 'ranges': contains( has_entries({ 'start': has_entries({ 'line_num': 68, 'column_num': 3 }), 'end': has_entries({ 'line_num': 68, 'column_num': 5 }), })), 'text': equal_to("kernel function type 'int (*)(int)' must have " + "void return type"), 'fixit_available': False }), has_entries({ 'kind': equal_to('ERROR'), 'location': has_entries({ 'line_num': 70, 'column_num': 8 }), 'location_extent': has_entries({ 'start': has_entries({ 'line_num': 70, 'column_num': 8 }), 'end': has_entries({ 'line_num': 70, 'column_num': 18 }), }), 'ranges': empty(), 'text': equal_to("use of undeclared identifier 'undeclared'"), 'fixit_available': False }), ))
def FileReadyToParse_Diagnostics_FileNotOnDisk_test(app): StartJavaCompleterServerInDirectory(app, PathToTestFile(DEFAULT_PROJECT_DIR)) contents = ''' package com.test; class Test { public String test } ''' filepath = ProjectPath('Test.java') event_data = BuildRequest(event_name='FileReadyToParse', contents=contents, filepath=filepath, filetype='java') results = app.post_json('/event_notification', event_data).json # This is a new file, so the diagnostics can't possibly be available when the # initial parse request is sent. We receive these asynchronously. assert_that(results, empty()) diag_matcher = contains_exactly( has_entries({ 'kind': 'ERROR', 'text': 'Syntax error, insert ";" to complete ClassBodyDeclarations ' '[1610612976]', 'location': LocationMatcher(filepath, 4, 21), 'location_extent': RangeMatcher(filepath, (4, 21), (4, 25)), 'ranges': contains_exactly(RangeMatcher(filepath, (4, 21), (4, 25))), 'fixit_available': False })) # Poll until we receive the diags for message in PollForMessages(app, { 'filepath': filepath, 'contents': contents, 'filetype': 'java' }): if 'diagnostics' in message and message['filepath'] == filepath: print('Message {0}'.format(pformat(message))) assert_that( message, has_entries({ 'diagnostics': diag_matcher, 'filepath': filepath })) break # Now confirm that we _also_ get these from the FileReadyToParse request for tries in range(0, 60): results = app.post_json('/event_notification', event_data).json if results: break time.sleep(0.5) print('completer response: {0}'.format(pformat(results))) assert_that(results, diag_matcher)
def JavaCompleter_GetType_test( app ): completer = handlers._server_state.GetFiletypeCompleter( [ 'java' ] ) # The LSP defines the hover response as either: # - a string # - a list of strings # - an object with keys language, value # - a list of objects with keys language, value # = an object with keys kind, value with patch.object( completer, 'GetHoverResponse', return_value = '' ): assert_that( calling( completer.GetType ).with_args( BuildRequest() ), raises( RuntimeError, 'Unknown type' ) ) with patch.object( completer, 'GetHoverResponse', return_value = 'string' ): assert_that( calling( completer.GetType ).with_args( BuildRequest() ), raises( RuntimeError, 'Unknown type' ) ) with patch.object( completer, 'GetHoverResponse', return_value = 'value' ): assert_that( calling( completer.GetType ).with_args( BuildRequest() ), raises( RuntimeError, 'Unknown type' ) ) with patch.object( completer, 'GetHoverResponse', return_value = [] ): assert_that( calling( completer.GetType ).with_args( BuildRequest() ), raises( RuntimeError, 'Unknown type' ) ) with patch.object( completer, 'GetHoverResponse', return_value = [ 'a', 'b' ] ): assert_that( calling( completer.GetType ).with_args( BuildRequest() ), raises( RuntimeError, 'Unknown type' ) ) with patch.object( completer, 'GetHoverResponse', return_value = { 'language': 'java', 'value': 'test' } ): assert_that( completer.GetType( BuildRequest() ), has_entries( { 'message': 'test' } ) ) with patch.object( completer, 'GetHoverResponse', return_value = [ { 'language': 'java', 'value': 'test' } ] ): assert_that( completer.GetType( BuildRequest() ), has_entries( { 'message': 'test' } ) ) with patch.object( completer, 'GetHoverResponse', return_value = [ { 'language': 'java', 'value': 'test' }, { 'language': 'java', 'value': 'not test' } ] ): assert_that( completer.GetType( BuildRequest() ), has_entries( { 'message': 'test' } ) ) with patch.object( completer, 'GetHoverResponse', return_value = [ { 'language': 'java', 'value': 'test' }, 'line 1', 'line 2' ] ): assert_that( completer.GetType( BuildRequest() ), has_entries( { 'message': 'test' } ) ) with patch.object( completer, 'GetHoverResponse', return_value = { 'kind': 'plaintext', 'value': 'test' } ): assert_that( calling( completer.GetType ).with_args( BuildRequest() ), raises( RuntimeError, 'Unknown type' ) )
def FileReadyToParse_ChangeFileContents_test(app): filepath = TestFactory contents = ReadFile(filepath) StartJavaCompleterServerInDirectory(app, ProjectPath()) # It can take a while for the diagnostics to be ready for tries in range(0, 60): event_data = BuildRequest(event_name='FileReadyToParse', contents=contents, filepath=filepath, filetype='java') results = app.post_json('/event_notification', event_data).json if results: break time.sleep(0.5) # To make the test fair, we make sure there are some results prior to the # 'server not running' call assert results # Call the FileReadyToParse handler but pretend that the server isn't running contents = 'package com.test; class TestFactory {}' # It can take a while for the diagnostics to be ready event_data = BuildRequest(event_name='FileReadyToParse', contents=contents, filepath=filepath, filetype='java') app.post_json('/event_notification', event_data) diags = None try: for message in PollForMessages(app, { 'filepath': filepath, 'contents': contents, 'filetype': 'java' }): print('Message {0}'.format(pformat(message))) if 'diagnostics' in message and message['filepath'] == filepath: diags = message['diagnostics'] if not diags: break # Eventually PollForMessages will throw a timeout exception and we'll fail # if we don't see the diagnostics go empty except PollForMessagesTimeoutException as e: raise AssertionError( '{0}. Timed out waiting for diagnostics to clear for updated file. ' 'Expected to see none, but diags were: {1}'.format(e, diags)) assert_that(diags, empty()) # Close the file (ensuring no exception) event_data = BuildRequest(event_name='BufferUnload', contents=contents, filepath=filepath, filetype='java') result = app.post_json('/event_notification', event_data).json assert_that(result, equal_to({})) # Close the file again, someone erroneously (ensuring no exception) event_data = BuildRequest(event_name='BufferUnload', contents=contents, filepath=filepath, filetype='java') result = app.post_json('/event_notification', event_data).json assert_that(result, equal_to({}))
def Subcommands_ExtraConf_SettingsValid_test(app): StartJavaCompleterServerInDirectory( app, PathToTestFile('extra_confs', 'simple_extra_conf_project')) filepath = PathToTestFile('extra_confs', 'simple_extra_conf_project', 'src', 'ExtraConf.java') request_data = BuildRequest(filepath=filepath, filetype='java') assert_that( app.post_json('/debug_info', request_data).json, has_entry( 'completer', has_entries({ 'name': 'Java', 'servers': contains( has_entries({ 'name': 'jdt.ls Java Language Server', 'is_running': instance_of(bool), 'executable': instance_of(str), 'pid': instance_of(int), 'logfiles': contains(instance_of(str), instance_of(str)), 'extras': contains( has_entries({ 'key': 'Startup Status', 'value': 'Ready' }), has_entries({ 'key': 'Java Path', 'value': instance_of(str) }), has_entries({ 'key': 'Launcher Config.', 'value': instance_of(str) }), has_entries({ 'key': 'Workspace Path', 'value': instance_of(str) }), has_entries({ 'key': 'Extension Path', 'value': contains(instance_of(str)) }), has_entries({ 'key': 'Server State', 'value': 'Initialized' }), has_entries({ 'key': 'Project Directory', 'value': PathToTestFile('extra_confs', 'simple_extra_conf_project') }), has_entries({ 'key': 'Settings', 'value': json.dumps( { 'java.rename.enabled': False, 'bundles': [] }, indent=2, sort_keys=True) }), ) })) })))
def GetCompletions_IdentifierCompleter_StartColumn_AfterWord_test( app ): completion_data = BuildRequest( contents = 'oo foo foogoo ba', column_num = 11 ) response_data = app.post_json( '/completions', completion_data ).json eq_( 8, response_data[ 'completion_start_column' ] )
def LanguageServerCompleter_GoToDeclaration_test(): if utils.OnWindows(): filepath = 'C:\\test.test' uri = 'file:///c:/test.test' else: filepath = '/test.test' uri = 'file:/test.test' contents = 'line1\nline2\nline3' completer = MockCompleter() request_data = RequestWrap( BuildRequest(filetype='ycmtest', filepath=filepath, contents=contents)) @patch.object(completer, 'ServerIsReady', return_value=True) def Test(response, checker, throws, *args): with patch.object(completer.GetConnection(), 'GetResponse', return_value=response): if throws: assert_that( calling(completer.GoToDeclaration).with_args(request_data), raises(checker)) else: result = completer.GoToDeclaration(request_data) print('Result: {0}'.format(result)) assert_that(result, checker) location = { 'uri': uri, 'range': { 'start': { 'line': 0, 'character': 0 }, 'end': { 'line': 0, 'character': 0 }, } } goto_response = has_entries({ 'filepath': filepath, 'column_num': 1, 'line_num': 1, 'description': 'line1' }) cases = [ ({ 'result': None }, RuntimeError, True), ({ 'result': location }, goto_response, False), ({ 'result': {} }, RuntimeError, True), ({ 'result': [] }, RuntimeError, True), ({ 'result': [location] }, goto_response, False), ({ 'result': [location, location] }, contains(goto_response, goto_response), False), ] for response, checker, throws in cases: yield Test, response, checker, throws with patch( 'ycmd.completers.language_server.language_server_protocol.UriToFilePath', side_effect=lsp.InvalidUriException): yield Test, { 'result': { 'uri': uri, 'range': { 'start': { 'line': 0, 'character': 0 }, 'end': { 'line': 0, 'character': 0 }, } } }, has_entries({ 'filepath': '', 'column_num': 1, 'line_num': 1, }), False with patch('ycmd.completers.completer_utils.GetFileContents', side_effect=lsp.IOError): yield Test, { 'result': { 'uri': uri, 'range': { 'start': { 'line': 0, 'character': 0 }, 'end': { 'line': 0, 'character': 0 }, } } }, has_entries({ 'filepath': filepath, 'column_num': 1, 'line_num': 1, }), False
def GetPid(): request_data = BuildRequest( filetype = 'cs', filepath = filepath ) debug_info = app.post_json( '/debug_info', request_data ).json return debug_info[ "completer" ][ "servers" ][ 0 ][ "pid" ]
def GetCompletions_RejectInvalid_test(): if utils.OnWindows(): filepath = 'C:\\test.test' else: filepath = '/test.test' contents = 'line1.\nline2.\nline3.' request_data = RequestWrap( BuildRequest(filetype='ycmtest', filepath=filepath, contents=contents, line_num=1, column_num=7)) text_edit = { 'newText': 'blah', 'range': { 'start': { 'line': 0, 'character': 6 }, 'end': { 'line': 0, 'character': 6 }, } } assert_that( lsc._GetCompletionItemStartCodepointOrReject(text_edit, request_data), equal_to(7)) text_edit = { 'newText': 'blah', 'range': { 'start': { 'line': 0, 'character': 6 }, 'end': { 'line': 1, 'character': 6 }, } } assert_that( calling(lsc._GetCompletionItemStartCodepointOrReject).with_args( text_edit, request_data), raises(lsc.IncompatibleCompletionException)) text_edit = { 'newText': 'blah', 'range': { 'start': { 'line': 0, 'character': 20 }, 'end': { 'line': 0, 'character': 20 }, } } assert_that( lsc._GetCompletionItemStartCodepointOrReject(text_edit, request_data), equal_to(7)) text_edit = { 'newText': 'blah', 'range': { 'start': { 'line': 0, 'character': 6 }, 'end': { 'line': 0, 'character': 5 }, } } assert_that( lsc._GetCompletionItemStartCodepointOrReject(text_edit, request_data), equal_to(7))
def BuildRequestWrap(contents, column_num, line_num=1): return RequestWrap( BuildRequest(column_num=column_num, line_num=line_num, contents=contents))
def DebugInfo_test(app): request_data = BuildRequest(filetype='java') assert_that( app.post_json('/debug_info', request_data).json, has_entry( 'completer', has_entries({ 'name': 'Java', 'servers': contains( has_entries({ 'name': 'jdt.ls Java Language Server', 'is_running': instance_of(bool), 'executable': instance_of(str), 'pid': instance_of(int), 'logfiles': contains(instance_of(str), instance_of(str)), 'extras': contains( has_entries({ 'key': 'Startup Status', 'value': 'Ready' }), has_entries({ 'key': 'Java Path', 'value': instance_of(str) }), has_entries({ 'key': 'Launcher Config.', 'value': instance_of(str) }), has_entries({ 'key': 'Workspace Path', 'value': instance_of(str) }), has_entries({ 'key': 'Extension Path', 'value': contains(instance_of(str)) }), has_entries({ 'key': 'Server State', 'value': 'Initialized' }), has_entries({ 'key': 'Project Directory', 'value': PathToTestFile(DEFAULT_PROJECT_DIR) }), has_entries({ 'key': 'Settings', 'value': json.dumps({'bundles': []}, indent=2, sort_keys=True) })) })) })))