Files
ale/test/lsp/test_engine_lsp_response_handling.vader
w0rp f90e72ae1f Close #3600 - Implement pull diagnostics in VimL
Implement pull diagnostics in the VimL implementation so ALE is able
to track when servers are busy checking files. Only servers that
support this feature will return diagnostics these ways.
2025-03-27 12:40:11 +00:00

553 lines
13 KiB
Plaintext

Before:
Save g:ale_set_lists_synchronously
Save g:ale_buffer_info
Save g:ale_lsp_error_messages
Save g:ale_set_loclist
Save g:ale_set_signs
Save g:ale_set_quickfix
Save g:ale_set_highlights
Save g:ale_echo_cursor
Save g:ale_disable_lsp
Save g:ale_history_enabled
Save g:ale_history_log_output
let g:ale_disable_lsp = 0
let g:ale_set_lists_synchronously = 1
let g:ale_buffer_info = {}
let g:ale_set_loclist = 1
" Disable features we don't need for these tests.
let g:ale_set_signs = 0
let g:ale_set_quickfix = 0
let g:ale_set_highlights = 0
let g:ale_echo_cursor = 0
let g:ale_history_enabled = 1
let g:ale_history_log_output = 1
unlet! g:ale_lsp_error_messages
unlet! b:ale_linters
unlet! b:ale_disable_lsp
call ale#linter#Reset()
call ale#test#SetDirectory('/testplugin/test')
call setloclist(0, [])
After:
Restore
unlet! b:ale_linters
call setloclist(0, [])
call ale#test#RestoreDirectory()
call ale#linter#Reset()
call ale#lsp_linter#ClearLSPData()
Given foobar(An empty file):
Execute(tsserver syntax error responses should be handled correctly):
runtime ale_linters/typescript/tsserver.vim
if has('win32')
call ale#test#SetFilename('filename,[]^$.ts')
else
call ale#test#SetFilename('filename*?,{}[]^$.ts')
endif
call ale#engine#InitBufferInfo(bufnr(''))
if has('win32')
AssertEqual 'filename,[]^$.ts', expand('%:p:t')
else
AssertEqual 'filename*?,{}[]^$.ts', expand('%:p:t')
endif
" When we get syntax errors and no semantic errors, we should keep the
" syntax errors.
call ale#lsp_linter#HandleLSPResponse(1, {
\ 'seq': 0,
\ 'type': 'event',
\ 'event': 'syntaxDiag',
\ 'body': {
\ 'file': expand('%:p'),
\ 'diagnostics':[
\ {
\ 'start': {
\ 'line':2,
\ 'offset':14,
\ },
\ 'end': {
\ 'line':2,
\ 'offset':15,
\ },
\ 'text': ''','' expected.',
\ "code":1005
\ },
\ ],
\ },
\})
call ale#lsp_linter#HandleLSPResponse(1, {
\ 'seq': 0,
\ 'type': 'event',
\ 'event': 'semanticDiag',
\ 'body': {
\ 'file': expand('%:p'),
\ 'diagnostics':[
\ ],
\ },
\})
AssertEqual
\ [
\ {
\ 'lnum': 1,
\ 'bufnr': bufnr(''),
\ 'col': 14,
\ 'vcol': 0,
\ 'nr': 1005,
\ 'type': 'E',
\ 'text': '1005: '','' expected.',
\ 'valid': 1,
\ 'pattern': '',
\ },
\ ],
\ ale#test#GetLoclistWithoutNewerKeys()
" After we get empty syntax errors, we should clear them.
call ale#lsp_linter#HandleLSPResponse(1, {
\ 'seq': 0,
\ 'type': 'event',
\ 'event': 'syntaxDiag',
\ 'body': {
\ 'file': expand('%:p'),
\ 'diagnostics':[
\ ],
\ },
\})
AssertEqual
\ [
\ ],
\ ale#test#GetLoclistWithoutNewerKeys()
" Syntax errors on the project root should not populate the LocList.
call ale#lsp_linter#HandleLSPResponse(1, {
\ 'seq': 0,
\ 'type': 'event',
\ 'event': 'syntaxDiag',
\ 'body': {
\ 'file': g:dir,
\ 'diagnostics':[
\ {
\ 'start': {
\ 'line':2,
\ 'offset':14,
\ },
\ 'end': {
\ 'line':2,
\ 'offset':15,
\ },
\ 'text': ''','' expected.',
\ "code":1005
\ },
\ ],
\ },
\})
AssertEqual
\ [
\ ],
\ ale#test#GetLoclistWithoutNewerKeys()
Execute(tsserver semantic error responses should be handled correctly):
runtime ale_linters/typescript/tsserver.vim
if has('win32')
call ale#test#SetFilename('filename,[]^$.ts')
else
call ale#test#SetFilename('filename*?,{}[]^$.ts')
endif
call ale#engine#InitBufferInfo(bufnr(''))
if has('win32')
AssertEqual 'filename,[]^$.ts', expand('%:p:t')
else
AssertEqual 'filename*?,{}[]^$.ts', expand('%:p:t')
endif
" When we get syntax errors and no semantic errors, we should keep the
" syntax errors.
call ale#lsp_linter#HandleLSPResponse(1, {
\ 'seq': 0,
\ 'type': 'event',
\ 'event': 'syntaxDiag',
\ 'body': {
\ 'file': expand('%:p'),
\ 'diagnostics':[
\ ],
\ },
\})
call ale#lsp_linter#HandleLSPResponse(1, {
\ 'seq': 0,
\ 'type': 'event',
\ 'event': 'semanticDiag',
\ 'body': {
\ 'file': expand('%:p'),
\ 'diagnostics':[
\ {
\ 'start': {
\ 'line':2,
\ 'offset':14,
\ },
\ 'end': {
\ 'line':2,
\ 'offset':15,
\ },
\ 'text': 'Some semantic error',
\ "code":1005
\ },
\ ],
\ },
\})
AssertEqual
\ [
\ {
\ 'lnum': 1,
\ 'bufnr': bufnr(''),
\ 'col': 14,
\ 'vcol': 0,
\ 'nr': 1005,
\ 'type': 'E',
\ 'text': '1005: Some semantic error',
\ 'valid': 1,
\ 'pattern': '',
\ },
\ ],
\ ale#test#GetLoclistWithoutNewerKeys()
" After we get empty syntax errors, we should clear them.
call ale#lsp_linter#HandleLSPResponse(1, {
\ 'seq': 0,
\ 'type': 'event',
\ 'event': 'semanticDiag',
\ 'body': {
\ 'file': expand('%:p'),
\ 'diagnostics':[
\ ],
\ },
\})
AssertEqual
\ [
\ ],
\ ale#test#GetLoclistWithoutNewerKeys()
" Semantic errors on the project root should not populate the LocList.
call ale#lsp_linter#HandleLSPResponse(1, {
\ 'seq': 0,
\ 'type': 'event',
\ 'event': 'semanticDiag',
\ 'body': {
\ 'file': g:dir,
\ 'diagnostics':[
\ {
\ 'start': {
\ 'line':2,
\ 'offset':14,
\ },
\ 'end': {
\ 'line':2,
\ 'offset':15,
\ },
\ 'text': 'Some semantic error',
\ "code":1005
\ },
\ ],
\ },
\})
AssertEqual
\ [
\ ],
\ ale#test#GetLoclistWithoutNewerKeys()
Execute(tsserver errors should mark tsserver no longer active):
let b:ale_linters = ['tsserver']
runtime ale_linters/typescript/tsserver.vim
call ale#test#SetFilename('filename.ts')
call ale#engine#InitBufferInfo(bufnr(''))
let g:ale_buffer_info[bufnr('')].active_linter_list = ale#linter#Get('typescript')
Assert !empty(g:ale_buffer_info[bufnr('')].active_linter_list)
call ale#lsp_linter#HandleLSPResponse(1, {
\ 'seq': 0,
\ 'type': 'event',
\ 'event': 'semanticDiag',
\ 'body': {
\ 'file': g:dir . '/filename.ts',
\ 'diagnostics':[],
\ },
\})
AssertEqual [], g:ale_buffer_info[bufnr('')].active_linter_list
Execute(LSP diagnostics responses should be handled correctly):
let b:ale_linters = ['eclipselsp']
runtime ale_linters/java/eclipselsp.vim
if has('win32')
call ale#test#SetFilename('filename,[]^$.ts')
else
call ale#test#SetFilename('filename*?,{}[]^$.java')
endif
call ale#engine#InitBufferInfo(bufnr(''))
call ale#lsp_linter#SetLSPLinterMap({'1': {'name': 'eclipselsp', 'aliases': [], 'lsp': 'stdio'}})
if has('win32')
AssertEqual 'filename,[]^$.ts', expand('%:p:t')
else
AssertEqual 'filename*?,{}[]^$.java', expand('%:p:t')
endif
call ale#lsp_linter#HandleLSPResponse(1, {
\ 'jsonrpc':'2.0',
\ 'method':'textDocument/publishDiagnostics',
\ 'params': {
\ 'uri': ale#path#ToFileURI(expand('%:p')),
\ 'diagnostics': [
\ {
\ 'range': {
\ 'start': {
\ 'line': 0,
\ 'character':0
\ },
\ 'end': {
\ 'line': 0,
\ 'character':0
\ }
\ },
\ 'severity': 2,
\ 'code': "",
\ 'source': 'Java',
\ 'message': 'Missing JRE 1-8'
\ }
\ ]
\ }
\})
AssertEqual
\ [
\ {
\ 'lnum': 1,
\ 'bufnr': bufnr(''),
\ 'col': 1,
\ 'pattern': '',
\ 'valid': 1,
\ 'vcol': 0,
\ 'nr': -1,
\ 'type': 'W',
\ 'text': 'Missing JRE 1-8'
\ }
\ ],
\ ale#test#GetLoclistWithoutNewerKeys()
Execute(LSP diagnostics responses on project root should not populate loclist):
let b:ale_linters = ['eclipselsp']
runtime ale_linters/java/eclipselsp.vim
call ale#test#SetFilename('filename.java')
call ale#engine#InitBufferInfo(bufnr(''))
call ale#lsp_linter#SetLSPLinterMap({'1': {'name': 'eclipselsp', 'aliases': [], 'lsp': 'stdio'}})
call ale#lsp_linter#HandleLSPResponse(1, {
\ 'jsonrpc':'2.0',
\ 'method':'textDocument/publishDiagnostics',
\ 'params': {
\ 'uri':'file://' . g:dir,
\ 'diagnostics': [
\ {
\ 'range': {
\ 'start': {
\ 'line': 0,
\ 'character':0
\ },
\ 'end': {
\ 'line': 0,
\ 'character':0
\ }
\ },
\ 'severity': 2,
\ 'code': "",
\ 'source': 'Java',
\ 'message': 'Missing JRE 1-8'
\ }
\ ]
\ }
\})
AssertEqual
\ [
\ ],
\ ale#test#GetLoclistWithoutNewerKeys()
Execute(LSP errors should mark linters no longer active):
let b:ale_linters = ['pylsp']
runtime ale_linters/python/pylsp.vim
call ale#test#SetFilename('filename.py')
call ale#engine#InitBufferInfo(bufnr(''))
call ale#lsp_linter#SetLSPLinterMap({'1': {'name': 'pylsp', 'aliases': [], 'lsp': 'stdio'}})
let g:ale_buffer_info[bufnr('')].active_linter_list = ale#linter#Get('python')
Assert !empty(g:ale_buffer_info[bufnr('')].active_linter_list)
call ale#lsp_linter#HandleLSPResponse(1, {
\ 'method': 'textDocument/publishDiagnostics',
\ 'params': {
\ 'uri': ale#path#ToFileURI(g:dir . '/filename.py'),
\ 'diagnostics': [],
\ },
\})
AssertEqual [], g:ale_buffer_info[bufnr('')].active_linter_list
Execute(LSP pull model diagnostic responses should be handled):
let b:ale_linters = ['eclipselsp']
runtime ale_linters/java/eclipselsp.vim
if has('win32')
call ale#test#SetFilename('filename,[]^$.ts')
else
call ale#test#SetFilename('filename*?,{}[]^$.java')
endif
call ale#engine#InitBufferInfo(bufnr(''))
let g:ale_buffer_info[bufnr('')].active_linter_list = ale#linter#Get('eclipselsp')
call ale#lsp_linter#SetLSPLinterMap({'1': {'name': 'eclipselsp', 'aliases': [], 'lsp': 'stdio'}})
call ale#lsp_linter#SetDiagnosticURIMap({'347': ale#util#ToURI(expand('%:p'))})
if has('win32')
AssertEqual 'filename,[]^$.ts', expand('%:p:t')
else
AssertEqual 'filename*?,{}[]^$.java', expand('%:p:t')
endif
call ale#lsp_linter#HandleLSPResponse(1, {
\ 'jsonrpc':'2.0',
\ 'id': 347,
\ 'result': {
\ 'kind': 'full',
\ 'items': [
\ {
\ 'range': {
\ 'start': {
\ 'line': 0,
\ 'character':0
\ },
\ 'end': {
\ 'line': 0,
\ 'character':0
\ }
\ },
\ 'severity': 2,
\ 'code': "",
\ 'source': 'Java',
\ 'message': 'Missing JRE 1-8'
\ }
\ ]
\ },
\})
AssertEqual
\ [
\ {
\ 'lnum': 1,
\ 'bufnr': bufnr(''),
\ 'col': 1,
\ 'pattern': '',
\ 'valid': 1,
\ 'vcol': 0,
\ 'nr': -1,
\ 'type': 'W',
\ 'text': 'Missing JRE 1-8'
\ }
\ ],
\ ale#test#GetLoclistWithoutNewerKeys()
AssertEqual [], g:ale_buffer_info[bufnr('')].active_linter_list
Execute(LSP pull model diagnostic responses that are 'unchanged' should be handled):
let b:ale_linters = ['eclipselsp']
runtime ale_linters/java/eclipselsp.vim
if has('win32')
call ale#test#SetFilename('filename,[]^$.ts')
else
call ale#test#SetFilename('filename*?,{}[]^$.java')
endif
call ale#engine#InitBufferInfo(bufnr(''))
let g:ale_buffer_info[bufnr('')].active_linter_list = ale#linter#Get('eclipselsp')
let g:ale_buffer_info[bufnr('')].loclist = [
\ {
\ 'lnum': 1,
\ 'bufnr': bufnr(''),
\ 'col': 1,
\ 'pattern': '',
\ 'valid': 1,
\ 'vcol': 0,
\ 'nr': -1,
\ 'type': 'W',
\ 'text': 'Missing JRE 1-8'
\ },
\]
call ale#lsp_linter#SetLSPLinterMap({'1': {'name': 'eclipselsp', 'aliases': [], 'lsp': 'stdio'}})
call ale#lsp_linter#SetDiagnosticURIMap({'347': ale#util#ToURI(expand('%:p'))})
if has('win32')
AssertEqual 'filename,[]^$.ts', expand('%:p:t')
else
AssertEqual 'filename*?,{}[]^$.java', expand('%:p:t')
endif
call ale#lsp_linter#HandleLSPResponse(1, {
\ 'jsonrpc':'2.0',
\ 'id': 347,
\ 'result': {
\ 'kind': 'unchanged',
\ },
\})
AssertEqual
\ [
\ {
\ 'lnum': 1,
\ 'bufnr': bufnr(''),
\ 'col': 1,
\ 'pattern': '',
\ 'valid': 1,
\ 'vcol': 0,
\ 'nr': -1,
\ 'type': 'W',
\ 'text': 'Missing JRE 1-8'
\ }
\ ],
\ g:ale_buffer_info[bufnr('')].loclist
AssertEqual [], g:ale_buffer_info[bufnr('')].active_linter_list
Execute(LSP errors should be logged in the history):
call ale#lsp_linter#SetLSPLinterMap({'347': {'name': 'foobar', 'aliases': [], 'lsp': 'stdio'}})
call ale#lsp_linter#HandleLSPResponse(347, {
\ 'jsonrpc': '2.0',
\ 'error': {
\ 'code': -32602,
\ 'message': 'xyz',
\ 'data': {
\ 'traceback': ['123', '456'],
\ },
\ },
\})
AssertEqual
\ {'foobar': ["xyz\n123\n456"]},
\ get(g:, 'ale_lsp_error_messages', {})