Files
ale/autoload/ale/assert.vim
brian m. carlson 6fc016ad05 Add additional ways to detect LSP project root
Currently, we detect the linter root based on a variety of techniques.
However, these techniques are not foolproof. For example, clangd works
fine for many things without a compile_commands.json file, and Go
projects may be built outside of the GOPATH to take advantage of Go
1.11's automatic module support.

Add global and buffer-specific variables to allow the user to specify
the root, either as a string or a funcref. Make the funcrefs accept the
buffer number as an argument to make sure that they can function easily
in an asynchronous environment.

We define the global variable in the main plugin, since the LSP linter
code is not loaded unless required, and we want the variable to be able
to be read correctly by :ALEInfo regardless.
2019-01-26 04:46:41 +00:00

225 lines
6.9 KiB
VimL

let s:chain_results = []
function! ale#assert#WithChainResults(...) abort
let s:chain_results = a:000
endfunction
function! s:GetLinter() abort
let l:linters = ale#linter#GetLintersLoaded()
let l:filetype_linters = get(values(l:linters), 0, [])
if len(l:linters) is 0 || len(l:filetype_linters) is 0
throw 'No linters were loaded'
endif
if len(l:linters) > 1 || len(l:filetype_linters) > 1
throw 'More than one linter was loaded'
endif
return l:filetype_linters[0]
endfunction
" Load the currently loaded linter for a test case, and check that the command
" matches the given string.
function! ale#assert#Linter(expected_executable, expected_command) abort
let l:buffer = bufnr('')
let l:linter = s:GetLinter()
let l:executable = ale#linter#GetExecutable(l:buffer, l:linter)
if has_key(l:linter, 'command_chain')
let l:callbacks = map(copy(l:linter.command_chain), 'v:val.callback')
" If the expected command is a string, just check the last one.
if type(a:expected_command) is v:t_string
if len(l:callbacks) is 1
let l:command = call(l:callbacks[0], [l:buffer])
else
let l:input = get(s:chain_results, len(l:callbacks) - 2, [])
let l:command = call(l:callbacks[-1], [l:buffer, l:input])
endif
else
let l:command = []
let l:chain_index = 0
for l:Callback in l:callbacks
if l:chain_index is 0
call add(l:command, call(l:Callback, [l:buffer]))
else
let l:input = get(s:chain_results, l:chain_index - 1, [])
call add(l:command, call(l:Callback, [l:buffer, l:input]))
endif
let l:chain_index += 1
endfor
endif
else
let l:command = ale#linter#GetCommand(l:buffer, l:linter)
endif
if type(l:command) is v:t_string
" Replace %e with the escaped executable, so tests keep passing after
" linters are changed to use %e.
let l:command = substitute(l:command, '%e', '\=ale#Escape(l:executable)', 'g')
else
call map(l:command, 'substitute(v:val, ''%e'', ''\=ale#Escape(l:executable)'', ''g'')')
endif
AssertEqual
\ [a:expected_executable, a:expected_command],
\ [l:executable, l:command]
endfunction
function! ale#assert#LinterNotExecuted() abort
let l:buffer = bufnr('')
let l:linter = s:GetLinter()
let l:executable = ale#linter#GetExecutable(l:buffer, l:linter)
Assert empty(l:executable), "The linter will be executed when it shouldn't be"
endfunction
function! ale#assert#LSPOptions(expected_options) abort
let l:buffer = bufnr('')
let l:linter = s:GetLinter()
let l:initialization_options = ale#lsp_linter#GetOptions(l:buffer, l:linter)
AssertEqual a:expected_options, l:initialization_options
endfunction
function! ale#assert#LSPConfig(expected_config) abort
let l:buffer = bufnr('')
let l:linter = s:GetLinter()
let l:config = ale#lsp_linter#GetConfig(l:buffer, l:linter)
AssertEqual a:expected_config, l:config
endfunction
function! ale#assert#LSPLanguage(expected_language) abort
let l:buffer = bufnr('')
let l:linter = s:GetLinter()
let l:language = ale#util#GetFunction(l:linter.language_callback)(l:buffer)
AssertEqual a:expected_language, l:language
endfunction
function! ale#assert#LSPProject(expected_root) abort
let l:buffer = bufnr('')
let l:linter = s:GetLinter()
let l:root = ale#util#GetFunction(l:linter.project_root_callback)(l:buffer)
AssertEqual a:expected_root, l:root
endfunction
function! ale#assert#LSPProjectFull(expected_root) abort
let l:buffer = bufnr('')
let l:linter = s:GetLinter()
let l:root = ale#lsp_linter#FindProjectRoot(l:buffer, l:linter)
AssertEqual a:expected_root, l:root
endfunction
function! ale#assert#LSPAddress(expected_address) abort
let l:buffer = bufnr('')
let l:linter = s:GetLinter()
let l:address = ale#util#GetFunction(l:linter.address_callback)(l:buffer)
AssertEqual a:expected_address, l:address
endfunction
" A dummy function for making sure this module is loaded.
function! ale#assert#SetUpLinterTest(filetype, name) abort
" Set up a marker so ALE doesn't create real random temporary filenames.
let g:ale_create_dummy_temporary_file = 1
" Remove current linters.
call ale#linter#Reset()
call ale#linter#PreventLoading(a:filetype)
let l:prefix = 'ale_' . a:filetype . '_' . a:name
let b:filter_expr = 'v:val[: len(l:prefix) - 1] is# l:prefix'
Save g:ale_c_build_dir
unlet! g:ale_c_build_dir
" Save and clear linter variables.
" We'll load the runtime file to reset them to defaults.
for l:key in filter(keys(g:), b:filter_expr)
execute 'Save g:' . l:key
unlet g:[l:key]
endfor
unlet! b:ale_c_build_dir
for l:key in filter(keys(b:), b:filter_expr)
unlet b:[l:key]
endfor
execute 'runtime ale_linters/' . a:filetype . '/' . a:name . '.vim'
if !exists('g:dir')
call ale#test#SetDirectory('/testplugin/test/command_callback')
endif
command! -nargs=+ WithChainResults :call ale#assert#WithChainResults(<args>)
command! -nargs=+ AssertLinter :call ale#assert#Linter(<args>)
command! -nargs=0 AssertLinterNotExecuted :call ale#assert#LinterNotExecuted()
command! -nargs=+ AssertLSPOptions :call ale#assert#LSPOptions(<args>)
command! -nargs=+ AssertLSPConfig :call ale#assert#LSPConfig(<args>)
command! -nargs=+ AssertLSPLanguage :call ale#assert#LSPLanguage(<args>)
command! -nargs=+ AssertLSPProject :call ale#assert#LSPProject(<args>)
command! -nargs=+ AssertLSPProjectFull :call ale#assert#LSPProjectFull(<args>)
command! -nargs=+ AssertLSPAddress :call ale#assert#LSPAddress(<args>)
endfunction
function! ale#assert#TearDownLinterTest() abort
unlet! g:ale_create_dummy_temporary_file
let s:chain_results = []
if exists(':WithChainResults')
delcommand WithChainResults
endif
if exists(':AssertLinter')
delcommand AssertLinter
endif
if exists(':AssertLinterNotExecuted')
delcommand AssertLinterNotExecuted
endif
if exists(':AssertLSPOptions')
delcommand AssertLSPOptions
endif
if exists(':AssertLSPConfig')
delcommand AssertLSPConfig
endif
if exists(':AssertLSPLanguage')
delcommand AssertLSPLanguage
endif
if exists(':AssertLSPProject')
delcommand AssertLSPProject
endif
if exists(':AssertLSPProjectFull')
delcommand AssertLSPProjectFull
endif
if exists(':AssertLSPAddress')
delcommand AssertLSPAddress
endif
if exists('g:dir')
call ale#test#RestoreDirectory()
endif
Restore
call ale#linter#Reset()
if exists('*ale#semver#ResetVersionCache')
call ale#semver#ResetVersionCache()
endif
endfunction