diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/command_callback/python_paths/with_bandit/.bandit | 0 | ||||
-rw-r--r-- | test/command_callback/python_paths/with_bandit/namespace/foo/__init__.py | 0 | ||||
-rw-r--r-- | test/command_callback/python_paths/with_bandit/namespace/foo/bar.py | 0 | ||||
-rw-r--r-- | test/command_callback/test_bandit_command_callback.vader | 22 | ||||
-rw-r--r-- | test/command_callback/test_pylint_command_callback.vader | 6 | ||||
-rw-r--r-- | test/command_callback/test_rust_rls_callbacks.vader | 5 | ||||
-rw-r--r-- | test/fix/test_ale_fix.vader | 77 | ||||
-rw-r--r-- | test/fixers/test_break_up_long_lines_python_fixer.vader | 4 | ||||
-rw-r--r-- | test/fixers/test_trim_whitespace.vader | 18 | ||||
-rw-r--r-- | test/lsp/test_lsp_root_detection.vader | 17 | ||||
-rw-r--r-- | test/lsp/test_lsp_startup.vader | 364 | ||||
-rw-r--r-- | test/test_deferred_command_string.vader | 46 | ||||
-rw-r--r-- | test/test_deferred_executable_string.vader | 16 | ||||
-rw-r--r-- | test/test_linter_defintion_processing.vader | 203 | ||||
-rw-r--r-- | test/test_no_linting_on_write_quit.vader | 2 | ||||
-rw-r--r-- | test/test_path_uri.vader | 14 |
16 files changed, 735 insertions, 59 deletions
diff --git a/test/command_callback/python_paths/with_bandit/.bandit b/test/command_callback/python_paths/with_bandit/.bandit new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/test/command_callback/python_paths/with_bandit/.bandit diff --git a/test/command_callback/python_paths/with_bandit/namespace/foo/__init__.py b/test/command_callback/python_paths/with_bandit/namespace/foo/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/test/command_callback/python_paths/with_bandit/namespace/foo/__init__.py diff --git a/test/command_callback/python_paths/with_bandit/namespace/foo/bar.py b/test/command_callback/python_paths/with_bandit/namespace/foo/bar.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/test/command_callback/python_paths/with_bandit/namespace/foo/bar.py diff --git a/test/command_callback/test_bandit_command_callback.vader b/test/command_callback/test_bandit_command_callback.vader index 5d1e6fd3..274ce901 100644 --- a/test/command_callback/test_bandit_command_callback.vader +++ b/test/command_callback/test_bandit_command_callback.vader @@ -47,3 +47,25 @@ Execute(Pipenv is detected when python_bandit_auto_pipenv is set): \ . ' run bandit' \ . b:bandit_flags \ . ' -' + +Execute(The bandit command callback should add .bandit by default): + silent execute 'file ' . fnameescape(g:dir . '/python_paths/with_bandit/namespace/foo/bar.py') + + let b:config_path = ale#path#Simplify( + \ g:dir . '/python_paths/with_bandit/.bandit' + \) + + AssertLinter 'bandit', + \ ale#Escape('bandit') + \ . ' --ini ' . ale#Escape(b:config_path) + \ . b:bandit_flags + \ . ' -' + +Execute(The bandit command callback should support not using .bandit): + silent execute 'file ' . fnameescape(g:dir . '/python_paths/with_bandit/subdir/foo/bar.py') + let g:ale_python_bandit_use_config = 0 + + AssertLinter 'bandit', + \ ale#Escape('bandit') + \ . b:bandit_flags + \ . ' -' diff --git a/test/command_callback/test_pylint_command_callback.vader b/test/command_callback/test_pylint_command_callback.vader index 6b21b127..c41c8398 100644 --- a/test/command_callback/test_pylint_command_callback.vader +++ b/test/command_callback/test_pylint_command_callback.vader @@ -39,7 +39,7 @@ Execute(The pylint callbacks shouldn't detect virtualenv directories where they silent execute 'file ' . fnameescape(g:dir . '/python_paths/no_virtualenv/subdir/foo/bar.py') AssertLinter 'pylint', - \ ale#path#BufferCdString(bufnr('')) + \ ale#path#CdString(ale#path#Simplify(g:dir . '/python_paths/no_virtualenv/subdir')) \ . ale#Escape('pylint') . ' ' . b:command_tail Execute(The pylint callbacks should detect virtualenv directories): @@ -50,7 +50,7 @@ Execute(The pylint callbacks should detect virtualenv directories): \) AssertLinter b:executable, - \ ale#path#BufferCdString(bufnr('')) + \ ale#path#CdString(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/subdir')) \ . ale#Escape(b:executable) . ' ' . b:command_tail Execute(You should able able to use the global pylint instead): @@ -58,7 +58,7 @@ Execute(You should able able to use the global pylint instead): let g:ale_python_pylint_use_global = 1 AssertLinter 'pylint', - \ ale#path#BufferCdString(bufnr('')) + \ ale#path#CdString(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/subdir')) \ . ale#Escape('pylint') . ' ' . b:command_tail Execute(Setting executable to 'pipenv' appends 'run pylint'): diff --git a/test/command_callback/test_rust_rls_callbacks.vader b/test/command_callback/test_rust_rls_callbacks.vader index a710161d..ef4735d2 100644 --- a/test/command_callback/test_rust_rls_callbacks.vader +++ b/test/command_callback/test_rust_rls_callbacks.vader @@ -23,3 +23,8 @@ Execute(The project root should be detected correctly): call ale#test#SetFilename('rust-rls-project/test.rs') AssertLSPProject ale#path#Simplify(g:dir . '/rust-rls-project') + +Execute(Should accept configuration settings): + AssertLSPConfig {} + let b:ale_rust_rls_config = {'rust': {'clippy_preference': 'on'}} + AssertLSPConfig {'rust': {'clippy_preference': 'on'}} diff --git a/test/fix/test_ale_fix.vader b/test/fix/test_ale_fix.vader index 500eb71c..52df2a62 100644 --- a/test/fix/test_ale_fix.vader +++ b/test/fix/test_ale_fix.vader @@ -34,21 +34,21 @@ Before: call ale#test#SetFilename('test.txt') call ale#linter#PreventLoading('testft') - function AddCarets(buffer, done, lines) abort + function AddCarets(buffer, lines) abort " map() is applied to the original lines here. " This way, we can ensure that defensive copies are made. return map(a:lines, '''^'' . v:val') endfunction - function AddDollars(buffer, done, lines) abort + function AddDollars(buffer, lines) abort return map(a:lines, '''$'' . v:val') endfunction - function DoNothing(buffer, done, lines) abort + function DoNothing(buffer, lines) abort return 0 endfunction - function CatLine(buffer, done, lines) abort + function CatLine(buffer, lines) abort return {'command': 'cat - <(echo d)'} endfunction @@ -56,15 +56,21 @@ Before: return {'command': 'cat - <(echo d)'} endfunction - function ReplaceWithTempFile(buffer, done, lines) abort + function CatLineDeferred(buffer, lines) abort + return ale#command#Run(a:buffer, 'echo', { + \ -> ale#command#Run(a:buffer, 'echo', {-> {'command': 'cat - <(echo d)'}}) + \}) + endfunction + + function ReplaceWithTempFile(buffer, lines) abort return {'command': 'echo x > %t', 'read_temporary_file': 1} endfunction - function CatWithTempFile(buffer, done, lines) abort + function CatWithTempFile(buffer, lines) abort return {'command': 'cat %t <(echo d)'} endfunction - function RemoveLastLine(buffer, done, lines) abort + function RemoveLastLine(buffer, lines) abort return ['a', 'b'] endfunction @@ -127,11 +133,11 @@ Before: endfunction " echo will output a single blank line, and we should ingore it. - function! IgnoredEmptyOutput(buffer, done, output) + function! IgnoredEmptyOutput(buffer, output) return {'command': has('win32') ? 'echo(' : 'echo'} endfunction - function! EchoLineNoPipe(buffer, done, output) + function! EchoLineNoPipe(buffer, output) return {'command': 'echo new line', 'read_buffer': 0} endfunction @@ -180,6 +186,7 @@ Before: After: Restore + unlet! g:test_filename unlet! g:ale_run_synchronously unlet! g:ale_set_lists_synchronously unlet! g:ale_run_synchronously_callbacks @@ -192,6 +199,7 @@ After: delfunction DoNothing delfunction CatLine delfunction CatLineOneArg + delfunction CatLineDeferred delfunction ReplaceWithTempFile delfunction CatWithTempFile delfunction RemoveLastLine @@ -224,8 +232,8 @@ After: setlocal buftype=nofile - if filereadable('fix_test_file') - call delete('fix_test_file') + if exists('g:test_filename') && filereadable(g:test_filename) + call delete(g:test_filename) endif call setloclist(0, []) @@ -438,7 +446,7 @@ Execute(ALEFix should accept lambdas): " to make the test pass. call setline(1, ['a', 'b', 'c', 'd']) else - let g:ale_fixers.testft = [{buffer, done, lines -> lines + ['d']}] + let g:ale_fixers.testft = [{buffer, lines -> lines + ['d']}] ALEFix call ale#test#FlushJobs() endif @@ -479,8 +487,9 @@ Execute(ALEFix should fix files on the save event): let g:ale_lint_on_save = 1 let g:ale_enabled = 1 - noautocmd silent file fix_test_file - call writefile(getline(1, '$'), 'fix_test_file') + let g:test_filename = tempname() + execute 'noautocmd silent file ' . fnameescape(g:test_filename) + call writefile(getline(1, '$'), g:test_filename) let g:ale_fixers.testft = ['AddDollars'] @@ -492,8 +501,8 @@ Execute(ALEFix should fix files on the save event): call ale#test#FlushJobs() " We should save the file. - AssertEqual ['$a', '$b', '$c'], readfile('fix_test_file') - Assert !&modified, 'The was marked as ''modified''' + AssertEqual ['$a', '$b', '$c'], readfile(g:test_filename) + Assert !&modified, 'The file was marked as ''modified''' if !has('win32') " We should have run the linter. @@ -520,8 +529,9 @@ Execute(ALEFix should not fix files on :wq): let g:ale_lint_on_save = 1 let g:ale_enabled = 1 - noautocmd silent file fix_test_file - call writefile(getline(1, '$'), 'fix_test_file') + let g:test_filename = tempname() + execute 'noautocmd silent file ' . fnameescape(g:test_filename) + call writefile(getline(1, '$'), g:test_filename) let g:ale_fixers.testft = ['AddDollars'] @@ -534,7 +544,7 @@ Execute(ALEFix should not fix files on :wq): call ale#events#SaveEvent(bufnr('')) " We should save the file. - AssertEqual ['a', 'b', 'c'], readfile('fix_test_file') + AssertEqual ['a', 'b', 'c'], readfile(g:test_filename) Assert &modified, 'The was not marked as ''modified''' " We should not run the linter. @@ -555,7 +565,8 @@ Execute(ALEFix should still lint with no linters to be applied): let g:ale_lint_on_save = 1 let g:ale_enabled = 1 - noautocmd silent file fix_test_file + let g:test_filename = tempname() + execute 'noautocmd silent file ' . fnameescape(g:test_filename) let g:ale_fixers.testft = [] @@ -563,7 +574,7 @@ Execute(ALEFix should still lint with no linters to be applied): call ale#events#SaveEvent(bufnr('')) call ale#test#FlushJobs() - Assert !filereadable('fix_test_file'), 'The file should not have been saved' + Assert !filereadable(g:test_filename), 'The file should not have been saved' if !has('win32') " We have run the linter. @@ -590,7 +601,8 @@ Execute(ALEFix should still lint when nothing was fixed on save): let g:ale_lint_on_save = 1 let g:ale_enabled = 1 - noautocmd silent file fix_test_file + let g:test_filename = tempname() + execute 'noautocmd silent file ' . fnameescape(g:test_filename) let g:ale_fixers.testft = ['DoNothing'] @@ -598,7 +610,7 @@ Execute(ALEFix should still lint when nothing was fixed on save): call ale#events#SaveEvent(bufnr('')) call ale#test#FlushJobs() - Assert !filereadable('fix_test_file'), 'The file should not have been saved' + Assert !filereadable(g:test_filename), 'The file should not have been saved' if !has('win32') " We should have run the linter. @@ -626,7 +638,8 @@ Given testft (A file with three lines): c Execute(ale#fix#InitBufferData() should set up the correct data): - noautocmd silent file fix_test_file + let g:test_filename = tempname() + execute 'noautocmd silent file ' . fnameescape(g:test_filename) call ale#fix#InitBufferData(bufnr(''), 'save_file') @@ -801,3 +814,19 @@ Execute(ALEFix should apply autocmds): AssertEqual g:pre_success, 1 AssertEqual g:post_success, 1 + +Execute(ALEFix should support ale#command#Run): + if has('win32') + " Just skip this test on Windows, we can't run it. + call setline(1, ['a', 'b', 'c', 'd']) + else + let g:ale_fixers.testft = ['CatLineDeferred'] + ALEFix + call ale#test#FlushJobs() + endif + +Expect(The extra line should be added): + a + b + c + d diff --git a/test/fixers/test_break_up_long_lines_python_fixer.vader b/test/fixers/test_break_up_long_lines_python_fixer.vader index 847d3358..5fd991f0 100644 --- a/test/fixers/test_break_up_long_lines_python_fixer.vader +++ b/test/fixers/test_break_up_long_lines_python_fixer.vader @@ -16,7 +16,7 @@ Execute(Long lines with basic function calls should be broken up correctly): \ ' bar,', \ '))', \ ], - \ ale#fixers#generic_python#BreakUpLongLines(bufnr(''), v:null, [ + \ ale#fixers#generic_python#BreakUpLongLines(bufnr(''), [ \ 'def foo():', \ ' some_variable = this_is_a_longer_function(first_argument, second_argument, third_with_function_call(foo, bar))', \ ]) @@ -33,7 +33,7 @@ Execute(Longer lines should be permitted if a configuration file allows it): \ ' a_third_long_word,', \ ')' \ ], - \ ale#fixers#generic_python#BreakUpLongLines(bufnr(''), v:null, [ + \ ale#fixers#generic_python#BreakUpLongLines(bufnr(''), [ \ 'x = this_line_is_between_79_and_90_characters(first, second, third, fourth, fifth)', \ 'y = this_line_is_longer_than_90_characters(much_longer_word, another_longer_word, a_third_long_word)', \ ]) diff --git a/test/fixers/test_trim_whitespace.vader b/test/fixers/test_trim_whitespace.vader index 10070374..2ffbcb04 100644 --- a/test/fixers/test_trim_whitespace.vader +++ b/test/fixers/test_trim_whitespace.vader @@ -16,13 +16,13 @@ Execute(Should delete all whitespace at the end of different lines): \ ' bar,', \ '))', \ ], - \ ale#fixers#generic#TrimWhitespace(bufnr(''), v:null, [ - \ 'def foo():', - \ ' some_variable = this_is_a_longer_function(', - \ 'first_argument,', - \ ' second_argument,', - \ ' third_with_function_call(', - \ 'foo,', - \ ' bar,', - \ '))', + \ ale#fixers#generic#TrimWhitespace(bufnr(''), [ + \ 'def foo():', + \ ' some_variable = this_is_a_longer_function(', + \ 'first_argument,', + \ ' second_argument,', + \ ' third_with_function_call(', + \ 'foo,', + \ ' bar,', + \ '))', \ ]) diff --git a/test/lsp/test_lsp_root_detection.vader b/test/lsp/test_lsp_root_detection.vader index 2575a62c..b7827248 100644 --- a/test/lsp/test_lsp_root_detection.vader +++ b/test/lsp/test_lsp_root_detection.vader @@ -16,48 +16,47 @@ Execute(The buffer-specific variable can be a string): let b:ale_lsp_root = '/some/path' call ale#test#SetFilename('other-file.c') - AssertLSPProjectFull '/some/path' + AssertLSPProject '/some/path' Execute(The buffer-specific variable can be a dictionary): let b:ale_lsp_root = {'clangd': '/some/path', 'golangserver': '/other/path'} call ale#test#SetFilename('other-file.c') - AssertLSPProjectFull '/some/path' + AssertLSPProject '/some/path' Execute(The buffer-specific variable can have funcrefs): let b:ale_lsp_root = {'clangd': function('Hook1'), 'golangserver': '/path'} call ale#test#SetFilename('other-file.c') - AssertLSPProjectFull 'abc123' + AssertLSPProject 'abc123' Execute(The global variable can be a dictionary): let g:ale_lsp_root = {'clangd': '/some/path', 'golangserver': '/other/path'} call ale#test#SetFilename('other-file.c') - AssertLSPProjectFull '/some/path' + AssertLSPProject '/some/path' Execute(The global variable can have funcrefs): let g:ale_lsp_root = {'clangd': function('Hook1'), 'golangserver': '/path'} call ale#test#SetFilename('other-file.c') - AssertLSPProjectFull 'abc123' + AssertLSPProject 'abc123' Execute(The buffer-specific variable overrides the global variable): let b:ale_lsp_root = {'clangd': '/some/path', 'golangserver': '/other/path'} let g:ale_lsp_root = {'clangd': '/not/this/path', 'golangserver': '/elsewhere'} call ale#test#SetFilename('other-file.c') - AssertLSPProjectFull '/some/path' + AssertLSPProject '/some/path' Execute(The global variable is queried if the buffer-specific has no value): let b:ale_lsp_root = {'golangserver': '/other/path'} let g:ale_lsp_root = {'clangd': '/some/path', 'golangserver': '/elsewhere'} call ale#test#SetFilename('other-file.c') - AssertLSPProjectFull '/some/path' - + AssertLSPProject '/some/path' Execute(The default hook value is acceptable): call ale#test#SetFilename('other-file.c') - AssertLSPProjectFull '' + AssertLSPProject '' diff --git a/test/lsp/test_lsp_startup.vader b/test/lsp/test_lsp_startup.vader new file mode 100644 index 00000000..2fbd32de --- /dev/null +++ b/test/lsp/test_lsp_startup.vader @@ -0,0 +1,364 @@ +Before: + Save g:ale_run_synchronously + + let g:ale_run_synchronously = 1 + unlet! g:ale_run_synchronously_callbacks + + runtime autoload/ale/lsp.vim + runtime autoload/ale/lsp_linter.vim + runtime autoload/ale/engine.vim + runtime autoload/ale/job.vim + runtime autoload/ale/socket.vim + + let g:job_map = {} + let g:emulate_job_failure = 0 + let g:next_job_id = 1 + + let g:socket_map = {} + let g:emulate_socket_failure = 0 + let g:next_channel_id = 0 + + let g:message_buffer = '' + let g:calls = [] + + function! ale#engine#IsExecutable(buffer, executable) abort + return !empty(a:executable) + endfunction + + function! ale#job#HasOpenChannel(job_id) abort + return has_key(g:job_map, a:job_id) + endfunction + + function! ale#job#Stop(job_id) abort + if has_key(g:job_map, a:job_id) + call remove(g:job_map, a:job_id) + endif + endfunction + + function! ale#job#Start(command, options) abort + if g:emulate_job_failure + return 0 + endif + + let l:job_id = g:next_job_id + let g:next_job_id += 1 + let g:job_map[l:job_id] = [a:command, a:options] + + return l:job_id + endfunction + + function! ale#job#SendRaw(job_id, data) abort + let g:message_buffer .= a:data + endfunction + + function! ale#socket#IsOpen(channel_id) abort + return has_key(g:socket_map, a:channel_id) + endfunction + + function! ale#socket#Close(channel_id) abort + if has_key(g:socket_map, a:channel_id) + call remove(g:socket_map, a:channel_id) + endif + endfunction + + function! ale#socket#Open(address, options) abort + if g:emulate_socket_failure + return -1 + endif + + let l:channel_id = g:next_channel_id + let g:next_channel_id += 1 + let g:socket_map[l:channel_id] = [a:address, a:options] + + return l:channel_id + endfunction + + function! ale#socket#Send(channel_id, data) abort + let g:message_buffer .= a:data + endfunction + + function! PopMessages() abort + let l:message_list = [] + + for l:line in split(g:message_buffer, '\(\r\|\n\|Content-Length\)\+') + if l:line[:0] is '{' + let l:data = json_decode(l:line) + + call add(l:message_list, l:data) + endif + endfor + + let g:message_buffer = '' + + return l:message_list + endfunction + + function! SendMessage(message) abort + let l:conn_id = keys(ale#lsp#GetConnections())[0] + let l:body = json_encode(a:message) + let l:data = 'Content-Length: ' . strlen(l:body) . "\r\n\r\n" . l:body + + call ale#lsp#HandleMessage(l:conn_id, l:data) + endfunction + + function! Start() abort + let l:linter = values(ale#linter#GetLintersLoaded())[0][0] + + return ale#lsp_linter#StartLSP( + \ bufnr(''), + \ l:linter, + \ {linter, details -> add(g:calls, [linter.name, details])}, + \) + endfunction + + function! AssertInitSuccess(linter_name, conn_prefix, language, root, command) abort + let l:messages = PopMessages() + + if a:linter_name is# 'tsserver' + AssertEqual + \ [ + \ { + \ 'seq': v:null, + \ 'arguments': { + \ 'file': expand('%:p'), + \ }, + \ 'type': 'request', + \ 'command': 'open', + \ }, + \ ], + \ l:messages + else + AssertEqual + \ [ + \ { + \ 'method': 'initialize', + \ 'jsonrpc': '2.0', + \ 'id': 1, + \ 'params': { + \ 'initializationOptions': {}, + \ 'rootUri': ale#path#ToURI(a:root), + \ 'capabilities': {}, + \ 'rootPath': a:root, + \ 'processId': getpid(), + \ }, + \ }, + \ ], + \ l:messages + + call SendMessage({ + \ 'jsonrpc': '2.0', + \ 'id': 1, + \ 'result': { + \ 'capabilities': { + \ 'renameProvider': v:true, + \ 'executeCommandProvider': { + \ 'commands': [], + \ }, + \ 'hoverProvider': v:true, + \ 'documentSymbolProvider': v:true, + \ 'documentRangeFormattingProvider': v:true, + \ 'codeLensProvider': { + \ 'resolveProvider': v:false + \ }, + \ 'referencesProvider': v:true, + \ 'textDocumentSync': 2, + \ 'documentFormattingProvider': v:true, + \ 'codeActionProvider': v:true, + \ 'signatureHelpProvider': { + \ 'triggerCharacters': ['(', ','], + \ }, + \ 'completionProvider': { + \ 'triggerCharacters': ['.'], + \ 'resolveProvider': v:false + \ }, + \ 'definitionProvider': v:true, + \ 'experimental': {}, + \ 'documentHighlightProvider': v:true, + \ 'workspaceSymbolProvider': v:true, + \ }, + \ }, + \}) + + let l:messages = PopMessages() + + AssertEqual + \ [ + \ { + \ 'method': 'initialized', + \ 'jsonrpc': '2.0', + \ 'params': {}, + \ }, + \ { + \ 'method': 'textDocument/didOpen', + \ 'jsonrpc': '2.0', + \ 'params': { + \ 'textDocument': { + \ 'uri': ale#path#ToURI(expand('%:p')), + \ 'version': ale#lsp#message#GetNextVersionID() - 1, + \ 'languageId': a:language, + \ 'text': "\n", + \ }, + \ }, + \ }, + \ ], + \ l:messages + endif + + AssertEqual + \ [ + \ [ + \ a:linter_name, + \ { + \ 'connection_id': a:conn_prefix . ':' . a:root, + \ 'project_root': a:root, + \ 'buffer': bufnr(''), + \ 'command': !empty(a:command) ? ale#job#PrepareCommand(bufnr(''), a:command) : '', + \ }, + \ ], + \ ], + \ g:calls + endfunction + + function! AssertInitFailure() abort + let l:messages = PopMessages() + + AssertEqual [], l:messages + AssertEqual [], g:calls + endfunction + + call ale#linter#Reset() + +After: + Restore + + call ale#linter#Reset() + call ale#lsp#ResetConnections() + + unlet! g:job_map + unlet! g:emulate_job_failure + unlet! g:next_job_id + + unlet! g:socket_map + unlet! g:emulate_socket_failure + unlet! g:next_channel_id + + unlet! g:message_buffer + unlet! g:calls + + delfunction PopMessages + delfunction Start + delfunction AssertInitSuccess + delfunction AssertInitFailure + + runtime autoload/ale/engine.vim + runtime autoload/ale/job.vim + runtime autoload/ale/socket.vim + +Execute(tsserver should be started correctly): + runtime ale_linters/typescript/tsserver.vim + + Assert Start() + call AssertInitSuccess('tsserver', 'tsserver', '', '', ale#Escape('tsserver')) + +Execute(tsserver failures should be handled appropriately): + runtime ale_linters/typescript/tsserver.vim + + let g:emulate_job_failure = 1 + + Assert !Start() + call AssertInitFailure() + +Execute(LSP jobs should start correctly): + call ale#linter#Define('foobar', { + \ 'name': 'foo', + \ 'lsp': 'stdio', + \ 'executable': 'foo', + \ 'command': 'foo', + \ 'project_root': '/foo/bar', + \ 'initialization_options': {}, + \}) + + Assert Start() + call AssertInitSuccess('foo', 'foo', 'foobar', '/foo/bar', 'foo') + +Execute(LSP job failures should be handled): + call ale#linter#Define('foobar', { + \ 'name': 'foo', + \ 'lsp': 'stdio', + \ 'executable': 'foo', + \ 'command': 'foo', + \ 'project_root': '/foo/bar', + \ 'initialization_options': {}, + \}) + + let g:emulate_job_failure = 1 + + Assert !Start() + call AssertInitFailure() + +Execute(LSP TCP connections should start correctly): + call ale#linter#Define('foobar', { + \ 'name': 'foo', + \ 'lsp': 'socket', + \ 'address': 'foo', + \ 'project_root': '/foo/bar', + \ 'initialization_options': {}, + \}) + + Assert Start() + call AssertInitSuccess('foo', 'foo', 'foobar', '/foo/bar', '') + +Execute(LSP TCP connection failures should be handled): + call ale#linter#Define('foobar', { + \ 'name': 'foo', + \ 'lsp': 'socket', + \ 'address': 'foo', + \ 'project_root': '/foo/bar', + \ 'initialization_options': {}, + \}) + + let g:emulate_socket_failure = 1 + + Assert !Start() + call AssertInitFailure() + +Execute(Deferred executables should be handled correctly): + call ale#linter#Define('foobar', { + \ 'name': 'foo', + \ 'lsp': 'stdio', + \ 'executable': {b -> ale#command#Run(b, 'echo', {-> 'foo'})}, + \ 'command': '%e -c', + \ 'project_root': '/foo/bar', + \ 'initialization_options': {}, + \}) + + Assert Start() + call ale#test#FlushJobs() + call AssertInitSuccess('foo', 'foo', 'foobar', '/foo/bar', ale#Escape('foo') . ' -c') + +Execute(Deferred commands should be handled correctly): + call ale#linter#Define('foobar', { + \ 'name': 'foo', + \ 'lsp': 'stdio', + \ 'executable': 'foo', + \ 'command': {b -> ale#command#Run(b, 'echo', {-> '%e -c'})}, + \ 'project_root': '/foo/bar', + \ 'initialization_options': {}, + \}) + + Assert Start() + call ale#test#FlushJobs() + call AssertInitSuccess('foo', 'foo', 'foobar', '/foo/bar', ale#Escape('foo') . ' -c') + +Execute(Deferred addresses should be handled correctly): + call ale#linter#Define('foobar', { + \ 'name': 'foo', + \ 'lsp': 'socket', + \ 'address': {b -> ale#command#Run(b, 'echo', {-> 'localhost:1234'})}, + \ 'project_root': '/foo/bar', + \ 'initialization_options': {}, + \}) + + Assert Start() + call ale#test#FlushJobs() + call AssertInitSuccess('foo', 'localhost:1234', 'foobar', '/foo/bar', '') diff --git a/test/test_deferred_command_string.vader b/test/test_deferred_command_string.vader new file mode 100644 index 00000000..4d0c8977 --- /dev/null +++ b/test/test_deferred_command_string.vader @@ -0,0 +1,46 @@ +Before: + Save g:ale_run_synchronously + Save g:ale_emulate_job_failure + Save g:ale_buffer_info + + let g:ale_run_synchronously = 1 + let g:ale_buffer_info = {} + let b:ale_history = [] + + call ale#linter#Reset() + call ale#assert#SetUpLinterTestCommands() + call ale#linter#Define('foobar', { + \ 'name': 'lint_file_linter', + \ 'callback': 'LintFileCallback', + \ 'executable': 'echo', + \ 'command': {b -> ale#command#Run(b, 'echo', {-> ale#command#Run(b, 'echo', {-> 'foo'})})}, + \ 'read_buffer': 0, + \}) + +After: + Restore + + call ale#assert#TearDownLinterTest() + +Given foobar (Some imaginary filetype): +Execute(It should be possible to compute an executable to check based on the result of commands): + AssertLinter 'echo', 'foo' + + ALELint + call ale#test#FlushJobs() + + AssertEqual + \ 1, + \ len(filter(copy(b:ale_history), 'string(v:val.command) =~# ''foo''')) + +Execute(It handle the deferred command failing): + let g:ale_emulate_job_failure = 1 + + AssertLinter 'echo', 0 + + ALELint + call ale#test#FlushJobs() + + AssertEqual + \ 0, + \ len(filter(copy(b:ale_history), 'string(v:val.command) =~# ''foo''')) diff --git a/test/test_deferred_executable_string.vader b/test/test_deferred_executable_string.vader index ad2e752b..3bdc5251 100644 --- a/test/test_deferred_executable_string.vader +++ b/test/test_deferred_executable_string.vader @@ -1,9 +1,11 @@ Before: Save g:ale_run_synchronously + Save g:ale_emulate_job_failure Save g:ale_buffer_info let g:ale_run_synchronously = 1 let g:ale_buffer_info = {} + let b:ale_history = [] call ale#linter#Reset() call ale#assert#SetUpLinterTestCommands() @@ -22,8 +24,6 @@ After: Given foobar (Some imaginary filetype): Execute(It should be possible to compute an executable to check based on the result of commands): - let b:ale_history = [] - AssertLinter 'foo', 'echo' ALELint @@ -32,3 +32,15 @@ Execute(It should be possible to compute an executable to check based on the res AssertEqual \ [{'status': 0, 'job_id': 'executable', 'command': 'foo'}], \ filter(copy(b:ale_history), 'v:val.job_id is# ''executable''') + +Execute(It handle the deferred command failing): + let g:ale_emulate_job_failure = 1 + + AssertLinter 0, 'echo' + + ALELint + call ale#test#FlushJobs() + + AssertEqual + \ [], + \ filter(copy(b:ale_history), 'v:val.job_id is# ''executable''') diff --git a/test/test_linter_defintion_processing.vader b/test/test_linter_defintion_processing.vader index 321c6212..cd32ebc8 100644 --- a/test/test_linter_defintion_processing.vader +++ b/test/test_linter_defintion_processing.vader @@ -1,4 +1,10 @@ Before: + Save g:ale_lsp_root + Save b:ale_lsp_root + + let g:ale_lsp_root = {} + unlet! b:ale_lsp_root + let g:linter = {} After: @@ -82,7 +88,15 @@ Execute (PreProcess should throw when command is not a string): \ 'executable': 'echo', \ 'command': [], \}) - AssertEqual '`command` must be a string if defined', g:vader_exception + AssertEqual '`command` must be a String or Function if defined', g:vader_exception + +Execute (PreProcess should allow command to be a callback): + call ale#linter#PreProcess('testft', { + \ 'name': 'foo', + \ 'callback': 'SomeFunction', + \ 'executable': 'echo', + \ 'command': function('type'), + \}) Execute (PreProcess should throw when command_callback is not a callback): AssertThrows call ale#linter#PreProcess('testft', { @@ -453,6 +467,18 @@ Execute(PreProcess should complain about using language and language_callback to AssertThrows call ale#linter#PreProcess('testft', g:linter) AssertEqual 'Only one of `language` or `language_callback` should be set', g:vader_exception +Execute(PreProcess should complain about invalid language values): + let g:linter = { + \ 'name': 'x', + \ 'lsp': 'socket', + \ 'address_callback': 'X', + \ 'language': 0, + \ 'project_root_callback': 'x', + \} + + AssertThrows call ale#linter#PreProcess('testft', g:linter) + AssertEqual '`language` must be a String or Funcref', g:vader_exception + Execute(PreProcess should use the filetype as the language string by default): let g:linter = { \ 'name': 'x', @@ -463,6 +489,17 @@ Execute(PreProcess should use the filetype as the language string by default): AssertEqual 'testft', ale#linter#PreProcess('testft', g:linter).language_callback(0) +Execute(PreProcess should allow language to be set to a callback): + let g:linter = { + \ 'name': 'x', + \ 'lsp': 'socket', + \ 'address_callback': 'X', + \ 'language': {-> 'foo'}, + \ 'project_root_callback': 'x', + \} + + AssertEqual 'foo', ale#linter#PreProcess('testft', g:linter).language_callback(0) + Execute(PreProcess should require an address_callback for LSP socket configurations): let g:linter = { \ 'name': 'x', @@ -470,7 +507,7 @@ Execute(PreProcess should require an address_callback for LSP socket configurati \} AssertThrows call ale#linter#PreProcess('testft', g:linter) - AssertEqual '`address_callback` must be defined for getting the LSP address', g:vader_exception + AssertEqual '`address` or `address_callback` must be defined for getting the LSP address', g:vader_exception Execute(PreProcess should complain about address_callback for non-LSP linters): let g:linter = { @@ -482,7 +519,112 @@ Execute(PreProcess should complain about address_callback for non-LSP linters): \} AssertThrows call ale#linter#PreProcess('testft', g:linter) - AssertEqual '`address_callback` cannot be used when lsp != ''socket''', g:vader_exception + AssertEqual '`address` or `address_callback` cannot be used when lsp != ''socket''', g:vader_exception + +Execute(PreProcess accept valid address_callback values): + let g:linter = ale#linter#PreProcess('testft', { + \ 'name': 'x', + \ 'lsp': 'socket', + \ 'address_callback': {-> 'foo:123'}, + \ 'language': 'x', + \ 'project_root_callback': 'x', + \}) + + AssertEqual 'foo:123', ale#linter#GetAddress(0, g:linter) + +Execute(PreProcess accept address as a String): + let g:linter = ale#linter#PreProcess('testft', { + \ 'name': 'x', + \ 'lsp': 'socket', + \ 'address': 'foo:123', + \ 'language': 'x', + \ 'project_root_callback': 'x', + \}) + + AssertEqual 'foo:123', ale#linter#GetAddress(0, g:linter) + +Execute(PreProcess accept address as a Function): + let g:linter = ale#linter#PreProcess('testft', { + \ 'name': 'x', + \ 'lsp': 'socket', + \ 'address': {-> 'foo:123'}, + \ 'language': 'x', + \ 'project_root_callback': 'x', + \}) + + AssertEqual 'foo:123', ale#linter#GetAddress(0, g:linter) + +Execute(PreProcess should complain about invalid address values): + AssertThrows call ale#linter#PreProcess('testft', { + \ 'name': 'x', + \ 'lsp': 'socket', + \ 'address': 0, + \ 'language': 'x', + \ 'project_root_callback': 'x', + \}) + AssertEqual '`address` must be a String or Function if defined', g:vader_exception + +Execute(PreProcess should accept allow the project root be set as a String): + let g:linter = ale#linter#PreProcess('testft', { + \ 'name': 'x', + \ 'lsp': 'socket', + \ 'address': 'foo:123', + \ 'language': 'x', + \ 'project_root': '/foo/bar', + \}) + + AssertEqual '/foo/bar', ale#lsp_linter#FindProjectRoot(0, g:linter) + +Execute(PreProcess should accept allow the project root be set as a Function): + let g:linter = ale#linter#PreProcess('testft', { + \ 'name': 'x', + \ 'lsp': 'socket', + \ 'address': 'foo:123', + \ 'language': 'x', + \ 'project_root': {-> '/foo/bar'}, + \}) + + AssertEqual '/foo/bar', ale#lsp_linter#FindProjectRoot(0, g:linter) + +Execute(PreProcess should complain when the project_root valid is invalid): + AssertThrows call ale#linter#PreProcess('testft', { + \ 'name': 'x', + \ 'lsp': 'socket', + \ 'address': 'foo:123', + \ 'language': 'x', + \ 'project_root': 0, + \}) + AssertEqual '`project_root` must be a String or Function if defined', g:vader_exception + +Execute(PreProcess should accept project_root_callback as a String): + call ale#linter#PreProcess('testft', { + \ 'name': 'x', + \ 'lsp': 'socket', + \ 'address': 'foo:123', + \ 'language': 'x', + \ 'project_root_callback': 'Foobar', + \}) + +Execute(PreProcess should accept project_root_callback as a Function): + let g:linter = ale#linter#PreProcess('testft', { + \ 'name': 'x', + \ 'lsp': 'socket', + \ 'address': 'foo:123', + \ 'language': 'x', + \ 'project_root_callback': {-> '/foo/bar'}, + \}) + + AssertEqual '/foo/bar', ale#lsp_linter#FindProjectRoot(0, g:linter) + +Execute(PreProcess should complain when the project_root_callback valid is invalid): + AssertThrows call ale#linter#PreProcess('testft', { + \ 'name': 'x', + \ 'lsp': 'socket', + \ 'address': 'foo:123', + \ 'language': 'x', + \ 'project_root_callback': 0, + \}) + AssertEqual '`project_root_callback` must be a callback if defined', g:vader_exception Execute(PreProcess should complain about using initialization_options and initialization_options_callback together): let g:linter = { @@ -509,6 +651,41 @@ Execute(PreProcess should throw when initialization_options_callback is not a ca \}) AssertEqual '`initialization_options_callback` must be a callback if defined', g:vader_exception +Execute(PreProcess should throw when initialization_options is not a Dictionary or callback): + AssertThrows call ale#linter#PreProcess('testft', { + \ 'name': 'foo', + \ 'lsp': 'socket', + \ 'address_callback': 'X', + \ 'language': 'x', + \ 'project_root_callback': 'x', + \ 'initialization_options': 0, + \}) + AssertEqual '`initialization_options` must be a String or Function if defined', g:vader_exception + +Execute(PreProcess should accept initialization_options as a Dictionary): + let g:linter = ale#linter#PreProcess('testft', { + \ 'name': 'foo', + \ 'lsp': 'socket', + \ 'address_callback': 'X', + \ 'language': 'x', + \ 'project_root_callback': 'x', + \ 'initialization_options': {'foo': v:true}, + \}) + + AssertEqual {'foo': v:true}, ale#lsp_linter#GetOptions(0, g:linter) + +Execute(PreProcess should accept initialization_options as a Funcref): + let g:linter = ale#linter#PreProcess('testft', { + \ 'name': 'foo', + \ 'lsp': 'socket', + \ 'address_callback': 'X', + \ 'language': 'x', + \ 'project_root_callback': 'x', + \ 'initialization_options': {-> {'foo': v:true}}, + \}) + + AssertEqual {'foo': v:true}, ale#lsp_linter#GetOptions(0, g:linter) + Execute(PreProcess should complain about using lsp_config and lsp_config_callback together): let g:linter = { \ 'name': 'x', @@ -535,22 +712,30 @@ Execute(PreProcess should throw when lsp_config_callback is not a callback): AssertEqual '`lsp_config_callback` must be a callback if defined', g:vader_exception Execute(PreProcess should accept LSP configuration options via lsp_config): - let g:ale_lsp_configuration = { - \ 'foo': 'bar' + let g:linter = { + \ 'name': 'x', + \ 'lsp': 'socket', + \ 'address_callback': 'X', + \ 'language_callback': 'x', + \ 'project_root_callback': 'x', + \ 'lsp_config': {'foo': 'bar'}, \} + AssertEqual {'foo': 'bar'}, ale#lsp_linter#GetConfig(0, g:linter) + +Execute(PreProcess should accept LSP configuration options via lsp_config as a function): let g:linter = { \ 'name': 'x', \ 'lsp': 'socket', \ 'address_callback': 'X', \ 'language_callback': 'x', \ 'project_root_callback': 'x', - \ 'lsp_config': g:ale_lsp_configuration, + \ 'lsp_config': {-> {'foo': 'bar'}}, \} - AssertEqual {'foo': 'bar'}, ale#linter#PreProcess('testft', g:linter).lsp_config + AssertEqual {'foo': 'bar'}, ale#lsp_linter#GetConfig(0, g:linter) -Execute(PreProcess should throw when lsp_config is not a Dictionary): +Execute(PreProcess should throw when lsp_config is not a Dictionary or Function): AssertThrows call ale#linter#PreProcess('testft', { \ 'name': 'foo', \ 'lsp': 'socket', @@ -559,4 +744,4 @@ Execute(PreProcess should throw when lsp_config is not a Dictionary): \ 'project_root_callback': 'x', \ 'lsp_config': 'x', \}) - AssertEqual '`lsp_config` must be a Dictionary', g:vader_exception + AssertEqual '`lsp_config` must be a Dictionary or Function if defined', g:vader_exception diff --git a/test/test_no_linting_on_write_quit.vader b/test/test_no_linting_on_write_quit.vader index 7ad08d08..bbd80d8f 100644 --- a/test/test_no_linting_on_write_quit.vader +++ b/test/test_no_linting_on_write_quit.vader @@ -23,7 +23,7 @@ Before: return [{'lnum': 1, 'col': 1, 'text': 'xxx'}] endfunction - function AddLine(buffer, done, lines) abort + function AddLine(buffer, lines) abort return a:lines + ['x'] endfunction diff --git a/test/test_path_uri.vader b/test/test_path_uri.vader index a3e68d98..504aba77 100644 --- a/test/test_path_uri.vader +++ b/test/test_path_uri.vader @@ -2,8 +2,22 @@ Execute(ale#path#ToURI should work for Windows paths): AssertEqual 'file:///C:/foo/bar/baz.tst', ale#path#ToURI('C:\foo\bar\baz.tst') AssertEqual 'foo/bar/baz.tst', ale#path#ToURI('foo\bar\baz.tst') +Execute(ale#path#FromURI should work for Unix paths): + AssertEqual '/foo/bar/baz.tst', ale#path#FromURI('file:///foo/bar/baz.tst') + AssertEqual '/foo/bar/baz.tst', ale#path#FromURI('file:/foo/bar/baz.tst') + AssertEqual '/foo/bar/baz.tst', ale#path#FromURI('FILE:///foo/bar/baz.tst') + AssertEqual '/foo/bar/baz.tst', ale#path#FromURI('FILE:/foo/bar/baz.tst') + Execute(ale#path#FromURI should work for Windows paths): AssertEqual 'C:\foo\bar\baz.tst', ale#path#FromURI('file:///C:/foo/bar/baz.tst') + AssertEqual 'C:\foo\bar\baz.tst', ale#path#FromURI('file:/C:/foo/bar/baz.tst') + AssertEqual 'c:\foo\bar\baz.tst', ale#path#FromURI('file:///c:/foo/bar/baz.tst') + AssertEqual 'c:\foo\bar\baz.tst', ale#path#FromURI('file:/c:/foo/bar/baz.tst') + AssertEqual 'C:\foo\bar\baz.tst', ale#path#FromURI('FILE:///C:/foo/bar/baz.tst') + AssertEqual 'C:\foo\bar\baz.tst', ale#path#FromURI('FILE:/C:/foo/bar/baz.tst') + +Execute(ale#path#FromURI should handle encoded paths that look like drive letters): + AssertEqual '/C:/foo/bar/baz.tst', ale#path#FromURI('file:///C%3A/foo/bar/baz.tst') Execute(ale#path#ToURI should work for Unix paths): AssertEqual 'file:///foo/bar/baz.tst', ale#path#ToURI('/foo/bar/baz.tst') |