summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/ada_files/testfile.adb0
-rw-r--r--test/command_callback/python_paths/with_virtualenv/subdir/foo/bar.pyi0
-rw-r--r--test/command_callback/test_languagetool_command_callback.vader9
-rw-r--r--test/command_callback/test_markdown_mdl_command_callback.vader6
-rw-r--r--test/command_callback/test_solc_command_callback.vader13
-rw-r--r--test/completion/test_completion_events.vader81
-rw-r--r--test/completion/test_lsp_completion_messages.vader33
-rw-r--r--test/completion/test_tsserver_completion_parsing.vader40
-rw-r--r--test/d_files/test.d0
-rw-r--r--test/fix/test_ale_fix.vader90
-rw-r--r--test/fixers/test_black_fixer_callback.vader8
-rw-r--r--test/fixers/test_dfmt_fixer_callback.vader40
-rw-r--r--test/fixers/test_gnatpp_fixer_callback.vader28
-rw-r--r--test/fixers/test_hindent_fixer_callback.vader18
-rw-r--r--test/fixers/test_sqlformat_fixer_callback.vader24
-rw-r--r--test/handler/test_mdl_handler.vader25
-rw-r--r--[-rwxr-xr-x]test/handler/test_powershell_handler.vader0
-rw-r--r--test/handler/test_shell_handler.vader135
-rw-r--r--test/handler/test_solc_handler.vader30
-rw-r--r--[-rwxr-xr-x]test/handler/test_terraform_handler.vader0
-rw-r--r--test/lsp/test_lsp_client_messages.vader3
-rw-r--r--test/lsp/test_other_initialize_message_handling.vader5
-rwxr-xr-xtest/script/check-supported-tools-tables5
-rwxr-xr-xtest/script/check-toc2
-rwxr-xr-xtest/script/custom-checks4
-rw-r--r--test/test_ale_info.vader116
-rw-r--r--test/test_ale_toggle.vader84
-rw-r--r--test/test_autocmd_commands.vader4
-rw-r--r--test/test_c_flag_parsing.vader162
-rw-r--r--test/test_code_action.vader334
-rw-r--r--test/test_filetype_linter_defaults.vader4
-rw-r--r--test/test_highlight_placement.vader246
-rw-r--r--test/test_organize_imports.vader171
-rw-r--r--test/test_rename.vader394
34 files changed, 1920 insertions, 194 deletions
diff --git a/test/ada_files/testfile.adb b/test/ada_files/testfile.adb
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/ada_files/testfile.adb
diff --git a/test/command_callback/python_paths/with_virtualenv/subdir/foo/bar.pyi b/test/command_callback/python_paths/with_virtualenv/subdir/foo/bar.pyi
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/command_callback/python_paths/with_virtualenv/subdir/foo/bar.pyi
diff --git a/test/command_callback/test_languagetool_command_callback.vader b/test/command_callback/test_languagetool_command_callback.vader
index a79662b9..ff6b2064 100644
--- a/test/command_callback/test_languagetool_command_callback.vader
+++ b/test/command_callback/test_languagetool_command_callback.vader
@@ -12,4 +12,11 @@ Execute(Should be able to set a custom executable):
let g:ale_languagetool_executable = 'foobar'
AssertLinter 'foobar' , ale#Escape('foobar')
- \ . ' --autoDetect %s'
+ \ . ' --autoDetect %s'
+
+Execute(Should be able to include custom languagetool options):
+ let g:ale_languagetool_options = '--language en'
+
+ " is now 'foobar' based on above global
+ AssertLinter 'foobar', ale#Escape('foobar')
+ \ . ' --language en %s'
diff --git a/test/command_callback/test_markdown_mdl_command_callback.vader b/test/command_callback/test_markdown_mdl_command_callback.vader
index e029bf9b..1ce4db1a 100644
--- a/test/command_callback/test_markdown_mdl_command_callback.vader
+++ b/test/command_callback/test_markdown_mdl_command_callback.vader
@@ -5,15 +5,15 @@ After:
call ale#assert#TearDownLinterTest()
Execute(The default command should be correct):
- AssertLinter 'mdl', ale#Escape('mdl')
+ AssertLinter 'mdl', ale#Escape('mdl') . ' -j'
Execute(The executable and options should be configurable):
let g:ale_markdown_mdl_executable = 'foo bar'
let g:ale_markdown_mdl_options = '--wat'
- AssertLinter 'foo bar', ale#Escape('foo bar') . ' --wat'
+ AssertLinter 'foo bar', ale#Escape('foo bar') . ' -j --wat'
Execute(Setting bundle appends 'exec mdl'):
let g:ale_markdown_mdl_executable = 'path to/bundle'
- AssertLinter 'path to/bundle', ale#Escape('path to/bundle') . ' exec mdl'
+ AssertLinter 'path to/bundle', ale#Escape('path to/bundle') . ' exec mdl -j'
diff --git a/test/command_callback/test_solc_command_callback.vader b/test/command_callback/test_solc_command_callback.vader
new file mode 100644
index 00000000..23521f6a
--- /dev/null
+++ b/test/command_callback/test_solc_command_callback.vader
@@ -0,0 +1,13 @@
+Before:
+ call ale#assert#SetUpLinterTest('solidity', 'solc')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(The default command should be correct):
+ AssertLinter 'solc', 'solc %s'
+
+Execute(The options should be configurable):
+ let g:ale_solidity_solc_options = '--foobar'
+
+ AssertLinter 'solc', 'solc --foobar %s'
diff --git a/test/completion/test_completion_events.vader b/test/completion/test_completion_events.vader
index 6bc0035e..e06ac98b 100644
--- a/test/completion/test_completion_events.vader
+++ b/test/completion/test_completion_events.vader
@@ -47,6 +47,14 @@ Before:
AssertEqual a:expect_success, g:get_completions_called
endfunction
+ let g:handle_code_action_called = 0
+ function! MockHandleCodeAction() abort
+ " delfunction! ale#code_action#HandleCodeAction
+ function! ale#code_action#HandleCodeAction(action) abort
+ let g:handle_code_action_called += 1
+ endfunction
+ endfunction
+
After:
Restore
@@ -54,6 +62,7 @@ After:
unlet! g:output
unlet! g:fake_mode
unlet! g:get_completions_called
+ unlet! g:handle_code_action_called
unlet! b:ale_old_omnifunc
unlet! b:ale_old_completeopt
unlet! b:ale_completion_info
@@ -61,6 +70,12 @@ After:
unlet! b:ale_complete_done_time
delfunction CheckCompletionCalled
+ delfunction ale#code_action#HandleCodeAction
+ delfunction MockHandleCodeAction
+
+ if exists('*CompleteCallback')
+ delfunction CompleteCallback
+ endif
" Stop any timers we left behind.
" This stops the tests from failing randomly.
@@ -73,6 +88,7 @@ After:
endfunction
runtime autoload/ale/completion.vim
+ runtime autoload/ale/code_action.vim
runtime autoload/ale/util.vim
Execute(ale#completion#GetCompletions should be called when the cursor position stays the same):
@@ -333,6 +349,30 @@ Execute(b:ale_completion_info should be set up correctly for other sources):
\ b:ale_completion_info
Assert !exists('b:ale_completion_result')
+Execute(b:ale_completion_info should be set up correctly when requesting completions via callback):
+ let b:ale_completion_result = []
+ call setpos('.', [bufnr(''), 3, 14, 0])
+
+ function! CompleteCallback() abort
+ echo 'Called'
+ endfunction
+
+
+ call ale#completion#GetCompletions('ale-callback', {'callback': funcref('CompleteCallback')})
+
+ AssertEqual
+ \ {
+ \ 'request_id': 0,
+ \ 'conn_id': 0,
+ \ 'column': 14,
+ \ 'line_length': 14,
+ \ 'line': 3,
+ \ 'prefix': 'ab',
+ \ 'source': 'ale-callback',
+ \ },
+ \ b:ale_completion_info
+ Assert !exists('b:ale_completion_result')
+
Execute(The correct keybinds should be configured):
redir => g:output
silent map <Plug>(ale_show_completion_menu)
@@ -357,3 +397,44 @@ Execute(Running the normal mode <Plug> keybind should reset the settings):
AssertEqual 'menu', &l:completeopt
Assert !has_key(b:, 'ale_old_omnifunc')
Assert !has_key(b:, 'ale_old_completeopt')
+
+Execute(HandleUserData should call ale#code_action#HandleCodeAction):
+ let b:ale_completion_info = {'source': 'ale-manual'}
+ call MockHandleCodeAction()
+
+ call ale#completion#HandleUserData({})
+ AssertEqual g:handle_code_action_called, 0
+
+ call ale#completion#HandleUserData({
+ \ 'user_data': ''
+ \})
+ AssertEqual g:handle_code_action_called, 0
+
+ call ale#completion#HandleUserData({
+ \ 'user_data': '{}'
+ \})
+ AssertEqual g:handle_code_action_called, 0
+
+ call ale#completion#HandleUserData({
+ \ 'user_data': '{"codeActions": []}'
+ \})
+ AssertEqual g:handle_code_action_called, 0
+
+ call ale#completion#HandleUserData({
+ \ 'user_data': '{"codeActions": [{"description":"", "changes": []}]}'
+ \})
+ AssertEqual g:handle_code_action_called, 1
+
+ let b:ale_completion_info = {'source': 'ale-automatic'}
+ call ale#completion#HandleUserData({
+ \ 'user_data': '{"codeActions": [{"description":"", "changes": []}]}'
+ \})
+ AssertEqual g:handle_code_action_called, 2
+
+Execute(ale#code_action#HandleCodeAction should not be called when when source is not ALE):
+ call MockHandleCodeAction()
+ let b:ale_completion_info = {'source': 'syntastic'}
+ call ale#completion#HandleUserData({
+ \ 'user_data': '{"codeActions": [{"description":"", "changes": []}]}'
+ \})
+ AssertEqual g:handle_code_action_called, 0
diff --git a/test/completion/test_lsp_completion_messages.vader b/test/completion/test_lsp_completion_messages.vader
index 6bd241a8..b997ac86 100644
--- a/test/completion/test_lsp_completion_messages.vader
+++ b/test/completion/test_lsp_completion_messages.vader
@@ -116,7 +116,13 @@ Execute(The right message should be sent for the initial tsserver request):
\ string(g:Callback)
" We should send the right message.
AssertEqual
- \ [[0, 'ts@completions', {'file': expand('%:p'), 'line': 1, 'offset': 3, 'prefix': 'fo'}]],
+ \ [[0, 'ts@completions', {
+ \ 'file': expand('%:p'),
+ \ 'line': 1,
+ \ 'offset': 3,
+ \ 'prefix': 'fo',
+ \ 'includeExternalModuleExports': g:ale_completion_tsserver_autoimport,
+ \ }]],
\ g:message_list
" We should set up the completion info correctly.
AssertEqual
@@ -151,7 +157,7 @@ Execute(The right message sent to the tsserver LSP when the first completion mes
\ 'body': [
\ {'name': 'Baz'},
\ {'name': 'dingDong'},
- \ {'name': 'Foo'},
+ \ {'name': 'Foo', 'source': '/path/to/foo.ts'},
\ {'name': 'FooBar'},
\ {'name': 'frazzle'},
\ {'name': 'FFS'},
@@ -160,8 +166,16 @@ Execute(The right message sent to the tsserver LSP when the first completion mes
" We should save the names we got in the buffer, as TSServer doesn't return
" details for every name.
- AssertEqual
- \ ['Foo', 'FooBar', 'frazzle'],
+ AssertEqual [{
+ \ 'word': 'Foo',
+ \ 'source': '/path/to/foo.ts',
+ \ }, {
+ \ 'word': 'FooBar',
+ \ 'source': '',
+ \ }, {
+ \ 'word': 'frazzle',
+ \ 'source': '',
+ \}],
\ get(b:, 'ale_tsserver_completion_names', [])
" The entry details messages should have been sent.
@@ -171,7 +185,16 @@ Execute(The right message sent to the tsserver LSP when the first completion mes
\ 'ts@completionEntryDetails',
\ {
\ 'file': expand('%:p'),
- \ 'entryNames': ['Foo', 'FooBar', 'frazzle'],
+ \ 'entryNames': [{
+ \ 'name': 'Foo',
+ \ 'source': '/path/to/foo.ts',
+ \ }, {
+ \ 'name': 'FooBar',
+ \ 'source': '',
+ \ }, {
+ \ 'name': 'frazzle',
+ \ 'source': '',
+ \ }],
\ 'offset': 1,
\ 'line': 1,
\ },
diff --git a/test/completion/test_tsserver_completion_parsing.vader b/test/completion/test_tsserver_completion_parsing.vader
index dbc4f9e2..dbb8de32 100644
--- a/test/completion/test_tsserver_completion_parsing.vader
+++ b/test/completion/test_tsserver_completion_parsing.vader
@@ -6,10 +6,24 @@ Execute(TypeScript completions responses should be parsed correctly):
\ ale#completion#ParseTSServerCompletions({
\ 'body': [],
\})
- AssertEqual ['foo', 'bar', 'baz'],
+ AssertEqual
+ \ [
+ \ {
+ \ 'word': 'foo',
+ \ 'source': '/path/to/foo.ts',
+ \ },
+ \ {
+ \ 'word': 'bar',
+ \ 'source': '',
+ \ },
+ \ {
+ \ 'word': 'baz',
+ \ 'source': '',
+ \ }
+ \ ],
\ ale#completion#ParseTSServerCompletions({
\ 'body': [
- \ {'name': 'foo'},
+ \ {'name': 'foo', 'source': '/path/to/foo.ts'},
\ {'name': 'bar'},
\ {'name': 'baz'},
\ ],
@@ -24,6 +38,7 @@ Execute(TypeScript completion details responses should be parsed correctly):
\ 'info': '',
\ 'kind': 'f',
\ 'icase': 1,
+ \ 'dup': g:ale_completion_tsserver_autoimport,
\ },
\ {
\ 'word': 'def',
@@ -31,6 +46,7 @@ Execute(TypeScript completion details responses should be parsed correctly):
\ 'info': 'foo bar baz',
\ 'kind': 'f',
\ 'icase': 1,
+ \ 'dup': g:ale_completion_tsserver_autoimport,
\ },
\ {
\ 'word': 'ghi',
@@ -38,6 +54,7 @@ Execute(TypeScript completion details responses should be parsed correctly):
\ 'info': '',
\ 'kind': 'f',
\ 'icase': 1,
+ \ 'dup': g:ale_completion_tsserver_autoimport,
\ },
\ ],
\ ale#completion#ParseTSServerCompletionEntryDetails({
@@ -96,16 +113,26 @@ Execute(TypeScript completion details responses should be parsed correctly):
\})
Execute(Entries without details should be included in the responses):
- let b:ale_tsserver_completion_names = ['xyz']
+ let b:ale_tsserver_completion_names = [{
+ \ 'word': 'xyz',
+ \ 'source': '/path/to/xyz.ts',
+ \ }]
AssertEqual
\ [
\ {
\ 'word': 'abc',
- \ 'menu': '(property) Foo.abc: number',
+ \ 'menu': 'import { def } from "./Foo"; (property) Foo.abc: number',
\ 'info': '',
\ 'kind': 'f',
\ 'icase': 1,
+ \ 'user_data': json_encode({
+ \ 'codeActions': [{
+ \ 'description': 'import { def } from "./Foo";',
+ \ 'changes': [],
+ \ }],
+ \ }),
+ \ 'dup': g:ale_completion_tsserver_autoimport,
\ },
\ {
\ 'word': 'def',
@@ -113,6 +140,7 @@ Execute(Entries without details should be included in the responses):
\ 'info': 'foo bar baz',
\ 'kind': 'f',
\ 'icase': 1,
+ \ 'dup': g:ale_completion_tsserver_autoimport,
\ },
\ {
\ 'word': 'xyz',
@@ -139,6 +167,10 @@ Execute(Entries without details should be included in the responses):
\ {'text': ' '},
\ {'text': 'number'},
\ ],
+ \ 'codeActions': [{
+ \ 'description': 'import { def } from "./Foo";',
+ \ 'changes': [],
+ \ }],
\ },
\ {
\ 'name': 'def',
diff --git a/test/d_files/test.d b/test/d_files/test.d
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/d_files/test.d
diff --git a/test/fix/test_ale_fix.vader b/test/fix/test_ale_fix.vader
index 9dd04213..c3dd20e4 100644
--- a/test/fix/test_ale_fix.vader
+++ b/test/fix/test_ale_fix.vader
@@ -40,8 +40,8 @@ Before:
return map(a:lines, '''^'' . v:val')
endfunction
- function AddDollars(buffer, lines) abort
- return map(a:lines, '''$'' . v:val')
+ function Capitalize(buffer, lines) abort
+ return map(a:lines, 'toupper(v:val)')
endfunction
function DoNothing(buffer, lines) abort
@@ -196,7 +196,7 @@ After:
unlet! b:ale_fix_on_save
unlet! b:ale_quitting
delfunction AddCarets
- delfunction AddDollars
+ delfunction Capitalize
delfunction DoNothing
delfunction CatLine
delfunction CatLineOneArg
@@ -265,28 +265,28 @@ Expect(The first function should be used):
^c
Execute(ALEFix should apply simple functions in a chain):
- let g:ale_fixers.testft = ['AddCarets', 'AddDollars']
+ let g:ale_fixers.testft = ['AddCarets', 'Capitalize']
ALEFix
call ale#test#FlushJobs()
Expect(Both functions should be used):
- $^a
- $^b
- $^c
+ ^A
+ ^B
+ ^C
Execute(ALEFix should allow 0 to be returned to skip functions):
- let g:ale_fixers.testft = ['DoNothing', 'AddDollars']
+ let g:ale_fixers.testft = ['DoNothing', 'Capitalize']
ALEFix
call ale#test#FlushJobs()
Expect(Only the second function should be applied):
- $a
- $b
- $c
+ A
+ B
+ C
Execute(The * fixers shouldn't be used if an empty list is set for fixers):
let g:ale_fixers.testft = []
- let g:ale_fixers['*'] = ['AddDollars']
+ let g:ale_fixers['*'] = ['Capitalize']
ALEFix
call ale#test#FlushJobs()
@@ -296,14 +296,14 @@ Expect(Nothing should be changed):
c
Execute(* fixers should be used if no filetype is matched):
- let g:ale_fixers = {'*': ['AddDollars']}
+ let g:ale_fixers = {'*': ['Capitalize']}
ALEFix
call ale#test#FlushJobs()
Expect(The file should be changed):
- $a
- $b
- $c
+ A
+ B
+ C
Execute(ALEFix should allow commands to be run):
if has('win32')
@@ -323,13 +323,13 @@ Expect(An extra line should be added):
Execute(ALEFix should use fixers passed in commandline when provided):
let g:ale_fixers.testft = ['RemoveLastLine']
- ALEFix AddCarets AddDollars
+ ALEFix AddCarets Capitalize
call ale#test#FlushJobs()
Expect(Only fixers passed via command line should be run):
- $^a
- $^b
- $^c
+ ^A
+ ^B
+ ^C
Execute(ALEFix should allow temporary files to be read):
if has('win32')
@@ -364,43 +364,43 @@ Expect(An extra line should be added):
Execute(ALEFix should allow jobs and simple functions to be combined):
if has('win32')
" Just skip this test on Windows, we can't run it.
- call setline(1, ['$x'])
+ call setline(1, ['X'])
2,3d
else
- let g:ale_fixers.testft = ['ReplaceWithTempFile', 'AddDollars']
+ let g:ale_fixers.testft = ['ReplaceWithTempFile', 'Capitalize']
ALEFix
call ale#test#FlushJobs()
endif
Expect(The lines from the temporary file should be modified):
- $x
+ X
Execute(ALEFix should send lines modified by functions to jobs):
if has('win32')
" Just skip this test on Windows, we can't run it.
- call setline(1, ['$a', '$b', '$c', 'd'])
+ call setline(1, ['A', 'B', 'C', 'd'])
else
- let g:ale_fixers.testft = ['AddDollars', 'CatLine']
+ let g:ale_fixers.testft = ['Capitalize', 'CatLine']
ALEFix
call ale#test#FlushJobs()
endif
Expect(The lines should first be modified by the function, then the job):
- $a
- $b
- $c
+ A
+ B
+ C
d
Execute(ALEFix should skip commands when jobs fail to run):
let g:ale_emulate_job_failure = 1
- let g:ale_fixers.testft = ['CatLine', 'AddDollars']
+ let g:ale_fixers.testft = ['CatLine', 'Capitalize']
ALEFix
call ale#test#FlushJobs()
Expect(Only the second function should be applied):
- $a
- $b
- $c
+ A
+ B
+ C
Execute(ALEFix should handle strings for selecting a single function):
let g:ale_fixers.testft = 'AddCarets'
@@ -459,7 +459,7 @@ Expect(There should be an extra line):
d
Execute(ALEFix should user buffer-local fixer settings):
- let g:ale_fixers.testft = ['AddCarets', 'AddDollars']
+ let g:ale_fixers.testft = ['AddCarets', 'Capitalize']
let b:ale_fixers = {'testft': ['RemoveLastLine']}
ALEFix
call ale#test#FlushJobs()
@@ -469,7 +469,7 @@ Expect(There should be only two lines):
b
Execute(ALEFix should allow Lists to be used for buffer-local fixer settings):
- let g:ale_fixers.testft = ['AddCarets', 'AddDollars']
+ let g:ale_fixers.testft = ['AddCarets', 'Capitalize']
let b:ale_fixers = ['RemoveLastLine']
ALEFix
call ale#test#FlushJobs()
@@ -492,7 +492,7 @@ Execute(ALEFix should fix files on the save event):
execute 'noautocmd silent file ' . fnameescape(g:test_filename)
call writefile(getline(1, '$'), g:test_filename)
- let g:ale_fixers.testft = ['AddDollars']
+ let g:ale_fixers.testft = ['Capitalize']
" We have to set the buftype to empty so the file will be written.
setlocal buftype=
@@ -502,7 +502,7 @@ Execute(ALEFix should fix files on the save event):
call ale#test#FlushJobs()
" We should save the file.
- AssertEqual ['$a', '$b', '$c'], readfile(g:test_filename)
+ AssertEqual ['A', 'B', 'C'], readfile(g:test_filename)
Assert !&modified, 'The file was marked as ''modified'''
if !has('win32')
@@ -521,9 +521,9 @@ Execute(ALEFix should fix files on the save event):
endif
Expect(The buffer should be modified):
- $a
- $b
- $c
+ A
+ B
+ C
Given testft (A file with three lines):
a
@@ -540,7 +540,7 @@ Execute(ALEFix should run the linters with b:ale_lint_on_save = 1):
execute 'noautocmd silent file ' . fnameescape(g:test_filename)
call writefile(getline(1, '$'), g:test_filename)
- let g:ale_fixers.testft = ['AddDollars']
+ let g:ale_fixers.testft = ['Capitalize']
" We have to set the buftype to empty so the file will be written.
setlocal buftype=
@@ -550,7 +550,7 @@ Execute(ALEFix should run the linters with b:ale_lint_on_save = 1):
call ale#test#FlushJobs()
" We should save the file.
- AssertEqual ['$a', '$b', '$c'], readfile(g:test_filename)
+ AssertEqual ['A', 'B', 'C'], readfile(g:test_filename)
Assert !&modified, 'The file was marked as ''modified'''
if !has('win32')
@@ -569,9 +569,9 @@ Execute(ALEFix should run the linters with b:ale_lint_on_save = 1):
endif
Expect(The buffer should be modified):
- $a
- $b
- $c
+ A
+ B
+ C
Execute(ALEFix should not fix files on :wq):
let g:ale_fix_on_save = 1
@@ -582,7 +582,7 @@ Execute(ALEFix should not fix files on :wq):
execute 'noautocmd silent file ' . fnameescape(g:test_filename)
call writefile(getline(1, '$'), g:test_filename)
- let g:ale_fixers.testft = ['AddDollars']
+ let g:ale_fixers.testft = ['Capitalize']
" We have to set the buftype to empty so the file will be written.
setlocal buftype=
diff --git a/test/fixers/test_black_fixer_callback.vader b/test/fixers/test_black_fixer_callback.vader
index 25ad05db..75864479 100644
--- a/test/fixers/test_black_fixer_callback.vader
+++ b/test/fixers/test_black_fixer_callback.vader
@@ -36,6 +36,14 @@ Execute(The black callback should include options):
\ {'command': ale#Escape(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/env/' . b:bin_dir . '/black')) . ' --some-option -' },
\ ale#fixers#black#Fix(bufnr(''))
+Execute(The black callback should include --pyi for .pyi files):
+ let g:ale_python_black_change_directory = 0
+
+ silent execute 'file ' . fnameescape(g:dir . '/python_paths/with_virtualenv/subdir/foo/bar.pyi')
+ AssertEqual
+ \ {'command': ale#Escape(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/env/' . b:bin_dir . '/black')) . ' --pyi -' },
+ \ ale#fixers#black#Fix(bufnr(''))
+
Execute(Pipenv is detected when python_black_auto_pipenv is set):
let g:ale_python_black_auto_pipenv = 1
let g:ale_python_black_change_directory = 0
diff --git a/test/fixers/test_dfmt_fixer_callback.vader b/test/fixers/test_dfmt_fixer_callback.vader
new file mode 100644
index 00000000..5ecb56e6
--- /dev/null
+++ b/test/fixers/test_dfmt_fixer_callback.vader
@@ -0,0 +1,40 @@
+Before:
+ Save g:ale_d_dfmt_executable
+ Save g:ale_d_dfmt_options
+
+ " Use an invalid global executable, so we don't match it.
+ let g:ale_d_dfmt_executable = 'xxxinvalid'
+ let g:ale_d_dfmt_options = ''
+
+ call ale#test#SetDirectory('/testplugin/test/fixers')
+
+After:
+ Restore
+
+ call ale#test#RestoreDirectory()
+
+Execute(The dfmt callback should return the correct default values):
+ call ale#test#SetFilename('../d_files/test.d')
+
+ AssertEqual
+ \ {
+ \ 'read_temporary_file': 1,
+ \ 'command': ale#Escape('xxxinvalid')
+ \ . ' -i'
+ \ . ' %t',
+ \ },
+ \ ale#fixers#dfmt#Fix(bufnr(''))
+
+Execute(The dfmt callback should include custom dfmt options):
+ let g:ale_d_dfmt_options = "--space-after-cast"
+ call ale#test#SetFilename('../d_files/test.d')
+
+ AssertEqual
+ \ {
+ \ 'read_temporary_file': 1,
+ \ 'command': ale#Escape('xxxinvalid')
+ \ . ' -i'
+ \ . ' ' . g:ale_d_dfmt_options
+ \ . ' %t',
+ \ },
+ \ ale#fixers#dfmt#Fix(bufnr(''))
diff --git a/test/fixers/test_gnatpp_fixer_callback.vader b/test/fixers/test_gnatpp_fixer_callback.vader
new file mode 100644
index 00000000..a2bf898e
--- /dev/null
+++ b/test/fixers/test_gnatpp_fixer_callback.vader
@@ -0,0 +1,28 @@
+Before:
+ call ale#assert#SetUpFixerTest('ada', 'gnatpp')
+
+After:
+ " Reset fixers, variables, etc.
+ "
+ " Vader's 'Restore' command will be called here.
+ call ale#assert#TearDownFixerTest()
+
+Execute(The default command should be correct):
+ call ale#test#SetFilename('../ada_files/testfile.adb')
+
+ AssertFixer
+ \ {
+ \ 'command': ale#Escape(g:ale_ada_gnatpp_executable) .' %t',
+ \ 'read_temporary_file': 1,
+ \ }
+
+Execute(The version check should be correct):
+ call ale#test#SetFilename('../ada_files/testfile.adb')
+ let g:ale_ada_gnatpp_options = '--no-alignment'
+
+ AssertFixer
+ \ {
+ \ 'command': ale#Escape(g:ale_ada_gnatpp_executable)
+ \ . ' --no-alignment %t',
+ \ 'read_temporary_file': 1,
+ \ }
diff --git a/test/fixers/test_hindent_fixer_callback.vader b/test/fixers/test_hindent_fixer_callback.vader
new file mode 100644
index 00000000..2e5a8b9f
--- /dev/null
+++ b/test/fixers/test_hindent_fixer_callback.vader
@@ -0,0 +1,18 @@
+Before:
+ call ale#test#SetDirectory('/testplugin/test/fixers')
+
+After:
+ Restore
+
+ call ale#test#RestoreDirectory()
+
+Execute(The hindent callback should return the correct default values):
+ call ale#test#SetFilename('../haskell_files/testfile.hs')
+
+ AssertEqual
+ \ {
+ \ 'read_temporary_file': 1,
+ \ 'command': ale#Escape('hindent')
+ \ . ' %t',
+ \ },
+ \ ale#fixers#hindent#Fix(bufnr(''))
diff --git a/test/fixers/test_sqlformat_fixer_callback.vader b/test/fixers/test_sqlformat_fixer_callback.vader
new file mode 100644
index 00000000..4bace089
--- /dev/null
+++ b/test/fixers/test_sqlformat_fixer_callback.vader
@@ -0,0 +1,24 @@
+Before:
+ Save g:ale_sql_sqlformat_executable
+ Save g:ale_sql_sqlformat_options
+
+After:
+ Restore
+
+Execute(The sqlformat callback should return the correct default values):
+ AssertEqual
+ \ {
+ \ 'command': ale#Escape('sqlformat') . ' -'
+ \ },
+ \ ale#fixers#sqlformat#Fix(bufnr(''))
+
+Execute(The sqlformat executable and options should be configurable):
+ let g:ale_sql_sqlformat_executable = '/path/to/sqlformat'
+ let g:ale_sql_sqlformat_options = '-a'
+
+ AssertEqual
+ \ {
+ \ 'command': ale#Escape('/path/to/sqlformat')
+ \ . ' -a -'
+ \ },
+ \ ale#fixers#sqlformat#Fix(bufnr(''))
diff --git a/test/handler/test_mdl_handler.vader b/test/handler/test_mdl_handler.vader
new file mode 100644
index 00000000..d01b52af
--- /dev/null
+++ b/test/handler/test_mdl_handler.vader
@@ -0,0 +1,25 @@
+Before:
+ runtime ale_linters/markdown/mdl.vim
+
+After:
+ call ale#linter#Reset()
+
+Execute(The mdl handler should parse output correctly):
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 1,
+ \ 'code': 'MD002/first-header-h1',
+ \ 'text': 'First header should be a top level header',
+ \ 'type': 'W'
+ \ },
+ \ {
+ \ 'lnum': 18,
+ \ 'code': 'MD033/no-inline-html',
+ \ 'text': 'Inline HTML',
+ \ 'type': 'W'
+ \ }
+ \ ],
+ \ ale_linters#markdown#mdl#Handle(0, [
+ \ '[{"filename":"README.md","line":1,"rule":"MD002","aliases":["first-header-h1"],"description":"First header should be a top level header"},{"filename":"README.md","line":18,"rule":"MD033","aliases":["no-inline-html"],"description":"Inline HTML"}]'
+ \ ])
diff --git a/test/handler/test_powershell_handler.vader b/test/handler/test_powershell_handler.vader
index 77c3dc65..77c3dc65 100755..100644
--- a/test/handler/test_powershell_handler.vader
+++ b/test/handler/test_powershell_handler.vader
diff --git a/test/handler/test_shell_handler.vader b/test/handler/test_shell_handler.vader
index 2465f179..c61cf37d 100644
--- a/test/handler/test_shell_handler.vader
+++ b/test/handler/test_shell_handler.vader
@@ -40,3 +40,138 @@ Execute(The shell handler should parse lines correctly):
\ 'qfm:22: :11: :33: :44:',
\ 'foo.sh: syntax error at line 9: `done'' unexpected',
\ ])
+
+Execute(The shell handler should parse Simplified Chinese lines correctly):
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 0,
+ \ 'text': '未预期的符号“done”附近有语法错误',
+ \ },
+ \ {
+ \ 'lnum': 90,
+ \ 'text': '寻找匹配的“"”时遇到了未预期的文件结束符',
+ \ },
+ \ {
+ \ 'lnum': 111,
+ \ 'text': '语法错误: 未预期的文件结尾',
+ \ },
+ \ {
+ \ 'lnum': 22,
+ \ 'text': ':11: :33: :44:',
+ \ },
+ \ ],
+ \ ale_linters#sh#shell#Handle(347, [
+ \ '/tmp/nvimWL5sOL/2/a.sh:行0: 未预期的符号“done”附近有语法错误',
+ \ '/tmp/nvimWL5sOL/2/a.sh:行90: 寻找匹配的“"”时遇到了未预期的文件结束符',
+ \ '/tmp/nvimWL5sOL/2/a.sh:行111: 语法错误: 未预期的文件结尾',
+ \ '/tmp/nvimWL5sOL/2/a.sh:行22: :11: :33: :44:',
+ \ ])
+
+Execute(The shell handler should parse Traditional Chinese lines correctly):
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 0,
+ \ 'text': '未預期的字組「(」附近有語法錯誤',
+ \ },
+ \ {
+ \ 'lnum': 90,
+ \ 'text': '尋找匹配的「"」時遇到了未預期的檔案結束符',
+ \ },
+ \ {
+ \ 'lnum': 111,
+ \ 'text': '語法錯誤: 未預期的檔案結尾',
+ \ },
+ \ {
+ \ 'lnum': 22,
+ \ 'text': ':11: :33: :44:',
+ \ },
+ \ ],
+ \ ale_linters#sh#shell#Handle(347, [
+ \ '/tmp/nvimWL5sOL/2/a.sh: 列 0: 未預期的字組「(」附近有語法錯誤',
+ \ '/tmp/nvimWL5sOL/2/a.sh: 列 90: 尋找匹配的「"」時遇到了未預期的檔案結束符',
+ \ '/tmp/nvimWL5sOL/2/a.sh: 列 111: 語法錯誤: 未預期的檔案結尾',
+ \ '/tmp/nvimWL5sOL/2/a.sh: 列 22: :11: :33: :44:',
+ \ ])
+
+Execute(The shell handler should parse Japanese lines correctly):
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 0,
+ \ 'text': "予期しないトークン `(' 周辺に構文エラーがあります",
+ \ },
+ \ {
+ \ 'lnum': 90,
+ \ 'text': "予期しないトークン `done' 周辺に構文エラーがあります",
+ \ },
+ \ {
+ \ 'lnum': 111,
+ \ 'text': "対応する `\"' を探索中に予期しないファイル終了 (EOF) です",
+ \ },
+ \ {
+ \ 'lnum': 22,
+ \ 'text': ':11: :33: :44:',
+ \ },
+ \ ],
+ \ ale_linters#sh#shell#Handle(347, [
+ \ "/tmp/nvimWL5sOL/2/a.sh: 行 0: 予期しないトークン `(' 周辺に構文エラーがあります",
+ \ "/tmp/nvimWL5sOL/2/a.sh: 行 90: 予期しないトークン `done' 周辺に構文エラーがあります",
+ \ "/tmp/nvimWL5sOL/2/a.sh: 行 111: 対応する `\"' を探索中に予期しないファイル終了 (EOF) です",
+ \ "/tmp/nvimWL5sOL/2/a.sh: 行 22: :11: :33: :44:",
+ \ ])
+
+Execute(The shell handler should parse Greek lines correctly):
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 0,
+ \ 'text': 'συντακτικό σφάλμα κοντά στο μη αναμενόμενο σύμβολο «done»',
+ \ },
+ \ {
+ \ 'lnum': 90,
+ \ 'text': 'syntax error: μη αναμενόμενο τέλος αρχείου',
+ \ },
+ \ {
+ \ 'lnum': 111,
+ \ 'text': 'μη αναμενόμενο EOF κατά την αναζήτηση «"»',
+ \ },
+ \ {
+ \ 'lnum': 22,
+ \ 'text': ':11: :33: :44:',
+ \ },
+ \ ],
+ \ ale_linters#sh#shell#Handle(347, [
+ \ '/tmp/nvimWL5sOL/2/a.sh: γραμμή 0: συντακτικό σφάλμα κοντά στο μη αναμενόμενο σύμβολο «done»',
+ \ '/tmp/nvimWL5sOL/2/a.sh: γραμμή 90: syntax error: μη αναμενόμενο τέλος αρχείου',
+ \ '/tmp/nvimWL5sOL/2/a.sh: γραμμή 111: μη αναμενόμενο EOF κατά την αναζήτηση «"»',
+ \ "/tmp/nvimWL5sOL/2/a.sh: γραμμή 22: :11: :33: :44:",
+ \ ])
+
+Execute(The shell handler should parse Russian lines correctly):
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 0,
+ \ 'text': 'синтаксическая ошибка рядом с неожиданным маркером «done»',
+ \ },
+ \ {
+ \ 'lnum': 90,
+ \ 'text': 'синтаксическая ошибка: неожиданный конец файла',
+ \ },
+ \ {
+ \ 'lnum': 111,
+ \ 'text': 'неожиданный конец файла во время поиска «"»',
+ \ },
+ \ {
+ \ 'lnum': 22,
+ \ 'text': ':11: :33: :44:',
+ \ },
+ \ ],
+ \ ale_linters#sh#shell#Handle(347, [
+ \ '/tmp/nvimWL5sOL/2/a.sh: строка 0: синтаксическая ошибка рядом с неожиданным маркером «done»',
+ \ '/tmp/nvimWL5sOL/2/a.sh: строка 90: синтаксическая ошибка: неожиданный конец файла',
+ \ '/tmp/nvimWL5sOL/2/a.sh: строка 111: неожиданный конец файла во время поиска «"»',
+ \ '/tmp/nvimWL5sOL/2/a.sh: строка 22: :11: :33: :44:',
+ \ ])
diff --git a/test/handler/test_solc_handler.vader b/test/handler/test_solc_handler.vader
new file mode 100644
index 00000000..8c197507
--- /dev/null
+++ b/test/handler/test_solc_handler.vader
@@ -0,0 +1,30 @@
+Before:
+ runtime ale_linters/solidity/solc.vim
+
+After:
+ call ale#linter#Reset()
+
+Execute(Check solc output parsing):
+ AssertEqual
+ \ [
+ \ {
+ \ 'lnum': 40,
+ \ 'col': 48,
+ \ 'text': 'This declaration shadows an existing declaration.',
+ \ 'type': 'W',
+ \ },
+ \ {
+ \ 'lnum': 23,
+ \ 'col': 16,
+ \ 'text': 'Member "getSinleSignature" not found or not visible after argument-dependent lookup in type(contract OneToN).',
+ \ 'type': 'E',
+ \ },
+ \ ],
+ \ ale_linters#solidity#solc#Handle(bufnr(''), [
+ \ 'raiden_contracts/data/source/raiden/Token.sol:40:48: Warning: This declaration shadows an existing declaration.',
+ \ ' function decimals() external view returns (uint8 decimals);',
+ \ ' ^------------^',
+ \ '/home/karl/raiden-contracts/raiden_contracts/data/source/test/OneToNInternalsTest.sol:23:16: Error: Member "getSinleSignature" not found or not visible after argument-dependent lookup in type(contract OneToN).',
+ \ ' return OneToN.getSinleSignature(signatures, i);',
+ \ ' ^----------------------^',
+ \ ])
diff --git a/test/handler/test_terraform_handler.vader b/test/handler/test_terraform_handler.vader
index 976ce12a..976ce12a 100755..100644
--- a/test/handler/test_terraform_handler.vader
+++ b/test/handler/test_terraform_handler.vader
diff --git a/test/lsp/test_lsp_client_messages.vader b/test/lsp/test_lsp_client_messages.vader
index 90a20832..bc91bf68 100644
--- a/test/lsp/test_lsp_client_messages.vader
+++ b/test/lsp/test_lsp_client_messages.vader
@@ -275,9 +275,10 @@ Execute(ale#lsp#tsserver_message#Completions() should return correct messages):
\ 'line': 347,
\ 'offset': 12,
\ 'prefix': 'abc',
+ \ 'includeExternalModuleExports': 1,
\ }
\ ],
- \ ale#lsp#tsserver_message#Completions(bufnr(''), 347, 12, 'abc')
+ \ ale#lsp#tsserver_message#Completions(bufnr(''), 347, 12, 'abc', 1)
Execute(ale#lsp#tsserver_message#CompletionEntryDetails() should return correct messages):
AssertEqual
diff --git a/test/lsp/test_other_initialize_message_handling.vader b/test/lsp/test_other_initialize_message_handling.vader
index 0372765d..6473e283 100644
--- a/test/lsp/test_other_initialize_message_handling.vader
+++ b/test/lsp/test_other_initialize_message_handling.vader
@@ -17,6 +17,7 @@ Before:
\ 'init_queue': [],
\ 'capabilities': {
\ 'hover': 0,
+ \ 'rename': 0,
\ 'references': 0,
\ 'completion': 0,
\ 'completion_trigger_characters': [],
@@ -100,6 +101,7 @@ Execute(Capabilities should bet set up correctly):
\ 'hover': 1,
\ 'definition': 1,
\ 'symbol_search': 1,
+ \ 'rename': 1,
\ },
\ b:conn.capabilities
AssertEqual [[1, 'initialized', {}]], g:message_list
@@ -110,7 +112,7 @@ Execute(Disabled capabilities should be recognised correctly):
\ 'id': 1,
\ 'result': {
\ 'capabilities': {
- \ 'renameProvider': v:true,
+ \ 'renameProvider': v:false,
\ 'executeCommandProvider': {
\ 'commands': [],
\ },
@@ -143,6 +145,7 @@ Execute(Disabled capabilities should be recognised correctly):
\ 'hover': 0,
\ 'definition': 0,
\ 'symbol_search': 0,
+ \ 'rename': 0,
\ },
\ b:conn.capabilities
AssertEqual [[1, 'initialized', {}]], g:message_list
diff --git a/test/script/check-supported-tools-tables b/test/script/check-supported-tools-tables
index 65270029..f4305707 100755
--- a/test/script/check-supported-tools-tables
+++ b/test/script/check-supported-tools-tables
@@ -3,8 +3,9 @@
set -e
set -u
-# This script compares the table of supported tools in both the README file
-# and the doc/ale.txt file, so we can complain if they don't match up.
+# This script compares the table of supported tools in both supported-tools.md
+# (for GitHub) and doc/ale-supported-languages-and-tools.txt (for vim), so we
+# can complain if they don't match up.
doc_file="$(mktemp -t doc.XXXXXXXX)"
doc_sorted_file="$(mktemp -t doc-sorted.XXXXXXXX)"
diff --git a/test/script/check-toc b/test/script/check-toc
index f3a57ed2..87a61262 100755
--- a/test/script/check-toc
+++ b/test/script/check-toc
@@ -35,7 +35,7 @@ sed -n "$toc_start_line,$toc_end_line"p doc/ale.txt \
> "$toc_file"
# Get all of the doc files in a natural sorted order.
-doc_files="$(/bin/ls -1v doc | grep ^ale- | sed 's/^/doc\//' | paste -sd ' ' -)"
+doc_files="$(/usr/bin/env ls -1v doc | grep ^ale- | sed 's/^/doc\//' | paste -sd ' ' -)"
# shellcheck disable=SC2086
grep -h '\*ale-.*-options\|^[a-z].*\*ale-.*\*$' $doc_files \
diff --git a/test/script/custom-checks b/test/script/custom-checks
index 20dbfb80..ca9069e4 100755
--- a/test/script/custom-checks
+++ b/test/script/custom-checks
@@ -36,12 +36,12 @@ tag_regex='[gb]\?:\?\(ale\|ALE\)[a-zA-Z_\-]\+'
# Grep for tags and references, and complain if we find a reference without
# a tag for the reference. Only our tags will be included.
diff -u \
- <(grep --exclude=tags -roh "\*$tag_regex\*" doc | sort -u | sed 's/*//g') \
+ <(grep --exclude=tags -roh "\\*$tag_regex\\*" doc | sort -u | sed 's/*//g') \
<(grep --exclude=tags -roh "|$tag_regex|" doc | sort -u | sed 's/|//g') \
| grep '^+[^+]' && exit_code=1
echo '========================================'
-echo 'diff README.md and doc/ale.txt tables'
+echo 'diff supported-tools.md and doc/ale-supported-languages-and-tools.txt tables'
echo '========================================'
echo 'Differences follow:'
echo
diff --git a/test/test_ale_info.vader b/test/test_ale_info.vader
index decd49e9..2bc8c635 100644
--- a/test/test_ale_info.vader
+++ b/test/test_ale_info.vader
@@ -1,50 +1,114 @@
Before:
Save g:ale_buffer_info
Save g:ale_cache_executable_check_failures
+ Save g:ale_change_sign_column_color
+ Save g:ale_command_wrapper
Save g:ale_completion_delay
Save g:ale_completion_enabled
Save g:ale_completion_max_suggestions
+ Save g:ale_echo_cursor
+ Save g:ale_echo_msg_error_str
+ Save g:ale_echo_msg_format
+ Save g:ale_echo_msg_info_str
+ Save g:ale_echo_msg_warning_str
+ Save g:ale_fix_on_save
Save g:ale_fixers
+ Save g:ale_history_enabled
Save g:ale_history_log_output
+ Save g:ale_keep_list_window_open
+ Save g:ale_lint_delay
+ Save g:ale_lint_on_enter
+ Save g:ale_lint_on_filetype_changed
Save g:ale_lint_on_insert_leave
+ Save g:ale_lint_on_save
Save g:ale_lint_on_text_changed
Save g:ale_linters
+ Save g:ale_linters_explicit
+ Save g:ale_list_vertical
+ Save g:ale_list_window_size
+ Save g:ale_loclist_msg_format
Save g:ale_lsp_error_messages
+ Save g:ale_lsp_root
+ Save g:ale_max_buffer_history_size
+ Save g:ale_max_signs
Save g:ale_maximum_file_size
+ Save g:ale_open_list
Save g:ale_pattern_options
Save g:ale_pattern_options_enabled
Save g:ale_set_balloons
+ Save g:ale_set_highlights
+ Save g:ale_set_loclist
+ Save g:ale_set_quickfix
+ Save g:ale_set_signs
+ Save g:ale_sign_column_always
Save g:ale_sign_error
Save g:ale_sign_info
+ Save g:ale_sign_offset
Save g:ale_sign_style_error
Save g:ale_sign_style_warning
Save g:ale_sign_warning
+ Save g:ale_sign_highlight_linenrs
Save g:ale_statusline_format
Save g:ale_type_map
+ Save g:ale_use_global_executables
+ Save g:ale_virtualtext_cursor
+ Save g:ale_warn_about_trailing_blank_lines
Save g:ale_warn_about_trailing_whitespace
unlet! b:ale_history
let g:ale_buffer_info = {}
let g:ale_cache_executable_check_failures = 0
+ let g:ale_change_sign_column_color = 0
+ let g:ale_command_wrapper = ''
let g:ale_completion_delay = 100
let g:ale_completion_enabled = 0
let g:ale_completion_max_suggestions = 50
+ let g:ale_echo_cursor = 1
+ let g:ale_echo_msg_error_str = 'Error'
+ let g:ale_echo_msg_format = '%code: %%s'
+ let g:ale_echo_msg_info_str = 'Info'
+ let g:ale_echo_msg_warning_str = 'Warning'
+ let g:ale_fix_on_save = 0
+ let g:ale_history_enabled = 1
let g:ale_history_log_output = 1
+ let g:ale_keep_list_window_open = 0
+ let g:ale_lint_delay = 200
+ let g:ale_lint_on_enter = 1
+ let g:ale_lint_on_filetype_changed = 1
let g:ale_lint_on_insert_leave = 1
+ let g:ale_lint_on_save = 1
let g:ale_lint_on_text_changed = 'normal'
+ let g:ale_linters_explicit = 0
+ let g:ale_list_vertical = 0
+ let g:ale_list_window_size = 10
+ let g:ale_loclist_msg_format = '%code: %%s'
let g:ale_lsp_error_messages = {}
+ let g:ale_lsp_root = {}
+ let g:ale_max_buffer_history_size = 20
+ let g:ale_max_signs = -1
let g:ale_maximum_file_size = 0
+ let g:ale_open_list = 0
let g:ale_pattern_options = {}
let g:ale_pattern_options_enabled = 0
let g:ale_set_balloons = 0
+ let g:ale_set_highlights = 1
+ let g:ale_set_loclist = 1
+ let g:ale_set_quickfix = 0
+ let g:ale_set_signs = 1
+ let g:ale_sign_column_always = 0
let g:ale_sign_error = '>>'
let g:ale_sign_info = '--'
+ let g:ale_sign_offset = 1000000
let g:ale_sign_style_error = '>>'
let g:ale_sign_style_warning = '--'
let g:ale_sign_warning = '--'
+ let g:ale_sign_highlight_linenrs = 0
let g:ale_statusline_format = ['%d error(s)', '%d warning(s)', 'OK']
let g:ale_type_map = {}
+ let g:ale_use_global_executables = v:null
+ let g:ale_virtualtext_cursor = 0
+ let g:ale_warn_about_trailing_blank_lines = 1
let g:ale_warn_about_trailing_whitespace = 1
let g:testlinter1 = {'name': 'testlinter1', 'executable': 'testlinter1', 'command': 'testlinter1', 'callback': 'testCB1', 'output_stream': 'stdout'}
@@ -116,6 +180,7 @@ Before:
\ 'let g:ale_sign_style_error = ''>>''',
\ 'let g:ale_sign_style_warning = ''--''',
\ 'let g:ale_sign_warning = ''--''',
+ \ 'let g:ale_sign_highlight_linenrs = 0',
\ 'let g:ale_statusline_format = [''%d error(s)'', ''%d warning(s)'', ''OK'']',
\ 'let g:ale_type_map = {}',
\ 'let g:ale_use_global_executables = v:null',
@@ -164,6 +229,8 @@ After:
unlet! b:ale_testft2_testlinter2_foo
unlet! g:ale_testft2_testlinter2_bar
unlet! g:info_test_file
+ unlet! g:ale_testft_build_dir_names
+ unlet! g:ale_testft_testlinter2_option
delfunction CheckInfo
call ale#test#RestoreDirectory()
@@ -632,3 +699,52 @@ Execute (LSP errors for other linters shouldn't appear):
\ + g:globals_lines
\ + g:command_header
\)
+
+Given testft.testft2 (Empty buffer with two filetypes):
+Execute (ALEInfo should include linter global options):
+ call ale#linter#Define('testft', g:testlinter1)
+ call ale#linter#Define('testft2', g:testlinter2)
+
+ " eg: like g:c_build_dir_names
+ let g:ale_testft_build_dir_names = ['build', 'bin']
+
+ call add(g:variables_lines, 'let g:ale_testft_build_dir_names = [''build'', ''bin'']')
+
+ call CheckInfo(
+ \ [
+ \ ' Current Filetype: testft.testft2',
+ \ 'Available Linters: [''testlinter1'', ''testlinter2'']',
+ \ ' Enabled Linters: [''testlinter1'', ''testlinter2'']',
+ \ ]
+ \ + g:fixer_lines
+ \ + g:variables_lines
+ \ + g:globals_lines
+ \ + g:command_header
+ \)
+
+Given testft (Empty buffer with two filetypes):
+Execute (ALEInfo should include linter global options for enabled linters):
+ call ale#linter#Define('testft', g:testlinter1)
+ call ale#linter#Define('testft', g:testlinter2)
+
+ let g:ale_linters = {'testft': ['testlinter1']}
+
+ " should not appear, since not enabled
+ let g:ale_testft_testlinter2_option = 'test'
+
+ let g:globals_lines[index(g:globals_lines, 'let g:ale_linters = {}')]
+ \ = 'let g:ale_linters = {''testft'': [''testlinter1'']}'
+
+ call CheckInfo(
+ \ [
+ \ ' Current Filetype: testft',
+ \ 'Available Linters: [''testlinter1'', ''testlinter2'']',
+ \ ' Enabled Linters: [''testlinter1'']',
+ \ ]
+ \ + g:fixer_lines
+ \ + g:variables_lines
+ \ + g:globals_lines
+ \ + g:command_header
+ \)
+
+
diff --git a/test/test_ale_toggle.vader b/test/test_ale_toggle.vader
index d0bca329..a0763cb1 100644
--- a/test/test_ale_toggle.vader
+++ b/test/test_ale_toggle.vader
@@ -36,6 +36,7 @@ Before:
\ 'ALEEvents',
\ 'ALEHighlightBufferGroup',
\]
+ let g:has_nvim_highlight = exists('*nvim_buf_add_highlight') && exists('*nvim_buf_clear_namespace')
function! ToggleTestCallback(buffer, output)
return [{
@@ -91,6 +92,7 @@ After:
unlet! g:expected_groups
unlet! b:ale_enabled
unlet! g:output
+ unlet! g:has_nvim_highlight
call ale#linter#Reset()
@@ -120,9 +122,14 @@ Execute(ALEToggle should reset everything and then run again):
" First check that everything is there...
AssertEqual g:expected_loclist, ale#test#GetLoclistWithoutModule()
AssertEqual [0, [[2, 1000001, 'ALEErrorSign']]], ale#sign#FindCurrentSigns(bufnr('%'))
- AssertEqual
- \ [{'group': 'ALEError', 'pos1': [2, 3, 1]}],
- \ map(getmatches(), '{''group'': v:val.group, ''pos1'': v:val.pos1}')
+
+ " Only check the legacy matches if not using the new NeoVIM API.
+ if !g:has_nvim_highlight
+ AssertEqual
+ \ [{'group': 'ALEError', 'pos1': [2, 3, 1]}],
+ \ map(getmatches(), '{''group'': v:val.group, ''pos1'': v:val.pos1}')
+ endif
+
AssertEqual g:expected_groups, ParseAuGroups()
AssertEqual [{'lnum': 2, 'bufnr': bufnr(''), 'col': 3, 'linter_name': 'testlinter', 'vcol': 0, 'nr': -1, 'type': 'E', 'text': 'foo bar', 'sign_id': 1000001}], g:ale_buffer_info[bufnr('')].loclist
@@ -133,7 +140,11 @@ Execute(ALEToggle should reset everything and then run again):
Assert !has_key(g:ale_buffer_info, bufnr('')), 'The g:ale_buffer_info Dictionary was not removed'
AssertEqual [], ale#test#GetLoclistWithoutModule(), 'The loclist was not cleared'
AssertEqual [0, []], ale#sign#FindCurrentSigns(bufnr('%')), 'The signs were not cleared'
- AssertEqual [], getmatches(), 'The highlights were not cleared'
+
+ if !g:has_nvim_highlight
+ AssertEqual [], getmatches(), 'The highlights were not cleared'
+ endif
+
AssertEqual g:expected_groups, ParseAuGroups()
" Toggle ALE on, everything should be set up and run again.
@@ -142,9 +153,13 @@ Execute(ALEToggle should reset everything and then run again):
AssertEqual g:expected_loclist, ale#test#GetLoclistWithoutModule()
AssertEqual [0, [[2, 1000001, 'ALEErrorSign']]], ale#sign#FindCurrentSigns(bufnr('%'))
- AssertEqual
- \ [{'group': 'ALEError', 'pos1': [2, 3, 1]}],
- \ map(getmatches(), '{''group'': v:val.group, ''pos1'': v:val.pos1}')
+
+ if !g:has_nvim_highlight
+ AssertEqual
+ \ [{'group': 'ALEError', 'pos1': [2, 3, 1]}],
+ \ map(getmatches(), '{''group'': v:val.group, ''pos1'': v:val.pos1}')
+ endif
+
AssertEqual g:expected_groups, ParseAuGroups()
AssertEqual [{'lnum': 2, 'bufnr': bufnr(''), 'col': 3, 'linter_name': 'testlinter', 'vcol': 0, 'nr': -1, 'type': 'E', 'text': 'foo bar', 'sign_id': 1000001}], g:ale_buffer_info[bufnr('')].loclist
@@ -228,9 +243,13 @@ Execute(ALEReset should reset everything for a buffer):
" First check that everything is there...
AssertEqual g:expected_loclist, ale#test#GetLoclistWithoutModule()
AssertEqual [0, [[2, 1000001, 'ALEErrorSign']]], ale#sign#FindCurrentSigns(bufnr('%'))
- AssertEqual
- \ [{'group': 'ALEError', 'pos1': [2, 3, 1]}],
- \ map(getmatches(), '{''group'': v:val.group, ''pos1'': v:val.pos1}')
+
+ if !g:has_nvim_highlight
+ AssertEqual
+ \ [{'group': 'ALEError', 'pos1': [2, 3, 1]}],
+ \ map(getmatches(), '{''group'': v:val.group, ''pos1'': v:val.pos1}')
+ endif
+
AssertEqual [{'lnum': 2, 'bufnr': bufnr(''), 'col': 3, 'linter_name': 'testlinter', 'vcol': 0, 'nr': -1, 'type': 'E', 'text': 'foo bar', 'sign_id': 1000001}], g:ale_buffer_info[bufnr('')].loclist
" Now Toggle ALE off.
@@ -241,7 +260,10 @@ Execute(ALEReset should reset everything for a buffer):
Assert !has_key(g:ale_buffer_info, bufnr('')), 'The g:ale_buffer_info Dictionary was not removed'
AssertEqual [], ale#test#GetLoclistWithoutModule(), 'The loclist was not cleared'
AssertEqual [0, []], ale#sign#FindCurrentSigns(bufnr('%')), 'The signs were not cleared'
- AssertEqual [], getmatches(), 'The highlights were not cleared'
+
+ if !g:has_nvim_highlight
+ AssertEqual [], getmatches(), 'The highlights were not cleared'
+ endif
AssertEqual 1, g:ale_enabled
@@ -254,9 +276,13 @@ Execute(ALEToggleBuffer should reset everything and then run again):
" First check that everything is there...
AssertEqual g:expected_loclist, ale#test#GetLoclistWithoutModule()
AssertEqual [0, [[2, 1000001, 'ALEErrorSign']]], ale#sign#FindCurrentSigns(bufnr('%'))
- AssertEqual
- \ [{'group': 'ALEError', 'pos1': [2, 3, 1]}],
- \ map(getmatches(), '{''group'': v:val.group, ''pos1'': v:val.pos1}')
+
+ if !g:has_nvim_highlight
+ AssertEqual
+ \ [{'group': 'ALEError', 'pos1': [2, 3, 1]}],
+ \ map(getmatches(), '{''group'': v:val.group, ''pos1'': v:val.pos1}')
+ endif
+
AssertEqual [{'lnum': 2, 'bufnr': bufnr(''), 'col': 3, 'linter_name': 'testlinter', 'vcol': 0, 'nr': -1, 'type': 'E', 'text': 'foo bar', 'sign_id': 1000001}], g:ale_buffer_info[bufnr('')].loclist
" Now Toggle ALE off.
@@ -266,7 +292,10 @@ Execute(ALEToggleBuffer should reset everything and then run again):
Assert !has_key(g:ale_buffer_info, bufnr('')), 'The g:ale_buffer_info Dictionary was not removed'
AssertEqual [], ale#test#GetLoclistWithoutModule(), 'The loclist was not cleared'
AssertEqual [0, []], ale#sign#FindCurrentSigns(bufnr('%')), 'The signs were not cleared'
- AssertEqual [], getmatches(), 'The highlights were not cleared'
+
+ if !g:has_nvim_highlight
+ AssertEqual [], getmatches(), 'The highlights were not cleared'
+ endif
" Toggle ALE on, everything should be set up and run again.
ALEToggleBuffer
@@ -274,9 +303,13 @@ Execute(ALEToggleBuffer should reset everything and then run again):
AssertEqual g:expected_loclist, ale#test#GetLoclistWithoutModule()
AssertEqual [0, [[2, 1000001, 'ALEErrorSign']]], ale#sign#FindCurrentSigns(bufnr('%'))
- AssertEqual
- \ [{'group': 'ALEError', 'pos1': [2, 3, 1]}],
- \ map(getmatches(), '{''group'': v:val.group, ''pos1'': v:val.pos1}')
+
+ if !g:has_nvim_highlight
+ AssertEqual
+ \ [{'group': 'ALEError', 'pos1': [2, 3, 1]}],
+ \ map(getmatches(), '{''group'': v:val.group, ''pos1'': v:val.pos1}')
+ endif
+
AssertEqual g:expected_groups, ParseAuGroups()
AssertEqual [{'lnum': 2, 'bufnr': bufnr(''), 'col': 3, 'linter_name': 'testlinter', 'vcol': 0, 'nr': -1, 'type': 'E', 'text': 'foo bar', 'sign_id': 1000001}], g:ale_buffer_info[bufnr('')].loclist
@@ -325,9 +358,13 @@ Execute(ALEResetBuffer should reset everything for a buffer):
" First check that everything is there...
AssertEqual g:expected_loclist, ale#test#GetLoclistWithoutModule()
AssertEqual [0, [[2, 1000001, 'ALEErrorSign']]], ale#sign#FindCurrentSigns(bufnr('%'))
- AssertEqual
- \ [{'group': 'ALEError', 'pos1': [2, 3, 1]}],
- \ map(getmatches(), '{''group'': v:val.group, ''pos1'': v:val.pos1}')
+
+ if !g:has_nvim_highlight
+ AssertEqual
+ \ [{'group': 'ALEError', 'pos1': [2, 3, 1]}],
+ \ map(getmatches(), '{''group'': v:val.group, ''pos1'': v:val.pos1}')
+ endif
+
AssertEqual [{'lnum': 2, 'bufnr': bufnr(''), 'col': 3, 'linter_name': 'testlinter', 'vcol': 0, 'nr': -1, 'type': 'E', 'text': 'foo bar', 'sign_id': 1000001}], g:ale_buffer_info[bufnr('')].loclist
" Now Toggle ALE off.
@@ -338,7 +375,10 @@ Execute(ALEResetBuffer should reset everything for a buffer):
Assert !has_key(g:ale_buffer_info, bufnr('')), 'The g:ale_buffer_info Dictionary was not removed'
AssertEqual [], ale#test#GetLoclistWithoutModule(), 'The loclist was not cleared'
AssertEqual [0, []], ale#sign#FindCurrentSigns(bufnr('%')), 'The signs were not cleared'
- AssertEqual [], getmatches(), 'The highlights were not cleared'
+
+ if !g:has_nvim_highlight
+ AssertEqual [], getmatches(), 'The highlights were not cleared'
+ endif
AssertEqual 1, g:ale_enabled
AssertEqual 1, get(b:, 'ale_enabled', 1)
diff --git a/test/test_autocmd_commands.vader b/test/test_autocmd_commands.vader
index 241e7d3e..355b4c77 100644
--- a/test/test_autocmd_commands.vader
+++ b/test/test_autocmd_commands.vader
@@ -188,6 +188,10 @@ Execute (ALECleanupGroup should include the right commands):
\], CheckAutocmd('ALECleanupGroup')
endif
+Execute(ALECompletionActions should always be set up):
+ AssertEqual [
+ \ 'CompleteDone * call ale#completion#HandleUserData(v:completed_item)',
+ \], CheckAutocmd('ALECompletionActions')
Execute(Enabling completion should set up autocmd events correctly):
let g:ale_completion_enabled = 0
diff --git a/test/test_c_flag_parsing.vader b/test/test_c_flag_parsing.vader
index 045554a3..8ae6f9dc 100644
--- a/test/test_c_flag_parsing.vader
+++ b/test/test_c_flag_parsing.vader
@@ -14,7 +14,7 @@ Execute(The CFlags parser should be able to parse include directives):
call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
AssertEqual
- \ '-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'),
+ \ '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')),
\ ale#c#ParseCFlagsFromMakeOutput(bufnr(''), ['gcc -Isubdir -c file.c'])
AssertEqual
@@ -25,14 +25,14 @@ Execute(ParseCFlags should ignore -c and -o):
call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
AssertEqual
- \ '-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'),
+ \ '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')),
\ ale#c#ParseCFlagsFromMakeOutput(bufnr(''), ['gcc -Isubdir -c file.c -o a.out'])
Execute(The CFlags parser should be able to parse macro directives):
call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
AssertEqual
- \ '-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')
+ \ '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
\ . ' -DTEST=1',
\ ale#c#ParseCFlagsFromMakeOutput(bufnr(''), ['gcc -Isubdir -DTEST=1 -c file.c'])
@@ -40,7 +40,7 @@ Execute(The CFlags parser should be able to parse macro directives with spaces):
call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
AssertEqual
- \ '-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')
+ \ '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
\ . ' -DTEST=$(( 2 * 4 ))',
\ ale#c#ParseCFlagsFromMakeOutput(bufnr(''), ['gcc -Isubdir -DTEST=$(( 2 * 4 )) -c file.c'])
@@ -48,14 +48,14 @@ Execute(The CFlags parser should be able to parse shell directives with spaces):
call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c')
AssertEqual
- \ '-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')
+ \ '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
\ . ' -DTEST=`date +%s`',
\ ale#c#ParseCFlagsFromMakeOutput(bufnr(''), ['gcc -Isubdir -DTEST=`date +%s` -c file.c'])
Execute(ParseCFlags should be able to parse flags with relative paths):
AssertEqual
- \ '-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')
- \ . ' ' . '-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')
+ \ '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
+ \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include'))
\ . ' -DTEST=`date +%s`',
\ ale#c#ParseCFlags(
\ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
@@ -67,8 +67,8 @@ Execute(ParseCFlags should be able to parse flags with relative paths):
Execute(ParseCFlags should be able to parse -Dgoal):
AssertEqual
\ '-Dgoal=9'
- \ . ' ' . '-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')
- \ . ' ' . '-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')
+ \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
+ \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include'))
\ . ' -DTEST=`date +%s`',
\ ale#c#ParseCFlags(
\ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
@@ -77,16 +77,30 @@ Execute(ParseCFlags should be able to parse -Dgoal):
\ . ' -DTEST=`date +%s` -c file.c'
\ )
+Execute(ParseCFlags should ignore -T and other arguments):
+ AssertEqual
+ \ '-Dgoal=9'
+ \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
+ \ . ' ' . '--sysroot=subdir'
+ \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include'))
+ \ . ' -DTEST=`date +%s`',
+ \ ale#c#ParseCFlags(
+ \ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
+ \ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir --sysroot=subdir '
+ \ . '-I'. ale#path#Simplify('kernel/include')
+ \ . ' -DTEST=`date +%s` -c file.c'
+ \ )
+
Execute(ParseCFlags should handle paths with spaces in double quotes):
AssertEqual
\ '-Dgoal=9'
- \ . ' ' . '-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')
- \ . ' ' . '-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/"dir with spaces"')
- \ . ' ' . '-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')
+ \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
+ \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir with spaces'))
+ \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include'))
\ . ' -DTEST=`date +%s`',
\ ale#c#ParseCFlags(
\ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
- \ 'gcc -Dgoal=9 -Isubdir '
+ \ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir '
\ . '-I"dir with spaces"' . ' -I'. ale#path#Simplify('kernel/include')
\ . ' -DTEST=`date +%s` -c file.c'
\ )
@@ -94,28 +108,29 @@ Execute(ParseCFlags should handle paths with spaces in double quotes):
Execute(ParseCFlags should handle paths with spaces in single quotes):
AssertEqual
\ '-Dgoal=9'
- \ . ' ' . '-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')
- \ . ' ' . '-I' . ale#path#Simplify(g:dir. "/test_c_projects/makefile_project/'dir with spaces'")
- \ . ' ' . '-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')
+ \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
+ \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir with spaces'))
+ \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include'))
\ . ' -DTEST=`date +%s`',
\ ale#c#ParseCFlags(
\ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
- \ 'gcc -Dgoal=9 -Isubdir '
- \ . "-I'dir with spaces'" . ' -I'. ale#path#Simplify('kernel/include')
+ \ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir '
+ \ . '-I''dir with spaces''' . ' -I'. ale#path#Simplify('kernel/include')
\ . ' -DTEST=`date +%s` -c file.c'
\ )
Execute(ParseCFlags should handle paths with minuses):
AssertEqual
\ '-Dgoal=9'
- \ . ' ' . '-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')
- \ . ' ' . '-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir-with-dash')
- \ . ' ' . '-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')
+ \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
+ \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir with spaces'))
+ \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir-with-dash'))
+ \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include'))
\ . ' -DTEST=`date +%s`',
\ ale#c#ParseCFlags(
\ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
- \ 'gcc -Dgoal=9 -Isubdir '
- \ . ' -Idir-with-dash'
+ \ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir '
+ \ . '-I''dir with spaces''' . ' -Idir-with-dash'
\ . ' -I'. ale#path#Simplify('kernel/include')
\ . ' -DTEST=`date +%s` -c file.c'
\ )
@@ -123,14 +138,17 @@ Execute(ParseCFlags should handle paths with minuses):
Execute(ParseCFlags should handle -D with minuses):
AssertEqual
\ '-Dgoal=9'
- \ . ' ' . '-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')
+ \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
\ . ' -Dmacro-with-dash'
- \ . ' ' . '-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')
+ \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir with spaces'))
+ \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir-with-dash'))
+ \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include'))
\ . ' -DTEST=`date +%s`',
\ ale#c#ParseCFlags(
\ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
- \ 'gcc -Dgoal=9 -Isubdir '
+ \ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir '
\ . '-Dmacro-with-dash '
+ \ . '-I''dir with spaces''' . ' -Idir-with-dash'
\ . ' -I'. ale#path#Simplify('kernel/include')
\ . ' -DTEST=`date +%s` -c file.c'
\ )
@@ -138,11 +156,16 @@ Execute(ParseCFlags should handle -D with minuses):
Execute(ParseCFlags should handle flags at the end of the line):
AssertEqual
\ '-Dgoal=9'
- \ . ' ' . '-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')
- \ . ' ' . '-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include'),
+ \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
+ \ . ' -Dmacro-with-dash'
+ \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir with spaces'))
+ \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir-with-dash'))
+ \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')),
\ ale#c#ParseCFlags(
\ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
- \ 'gcc -Dgoal=9 -Isubdir '
+ \ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir '
+ \ . '-Dmacro-with-dash '
+ \ . '-I''dir with spaces''' . ' -Idir-with-dash'
\ . ' -I'. ale#path#Simplify('kernel/include')
\ )
@@ -156,14 +179,14 @@ Execute(ParseCompileCommandsFlags should parse some basic flags):
silent noautocmd execute 'file! ' . fnameescape(ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c'))
AssertEqual
- \ '-I/usr/include/xmms2',
+ \ '-I ' . ale#path#Simplify('/usr/include/xmms2'),
\ ale#c#ParseCompileCommandsFlags(bufnr(''), { "xmms2-mpris.c": [
\ {
- \ 'directory': '/foo/bar/xmms2-mpris',
- \ 'command': '/usr/bin/cc -I' . '/usr/include/xmms2'
+ \ 'directory': ale#path#Simplify('/foo/bar/xmms2-mpris'),
+ \ 'command': '/usr/bin/cc -I' . ale#path#Simplify('/usr/include/xmms2')
\ . ' -o CMakeFiles/xmms2-mpris.dir/src/xmms2-mpris.c.o'
- \ . ' -c ' . '/foo/bar/xmms2-mpris/src/xmms2-mpris.c',
- \ 'file': '/foo/bar/xmms2-mpris/src/xmms2-mpris.c',
+ \ . ' -c ' . ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c'),
+ \ 'file': ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c'),
\ },
\ ] }, {})
@@ -183,14 +206,14 @@ Execute(ParseCompileCommandsFlags should fall back to files in the same director
silent noautocmd execute 'file! ' . fnameescape(ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c'))
AssertEqual
- \ '-I/usr/include/xmms2',
+ \ '-I ' . ale#path#Simplify('/usr/include/xmms2'),
\ ale#c#ParseCompileCommandsFlags(bufnr(''), {}, { "src": [
\ {
- \ 'directory': '/foo/bar/xmms2-mpris',
- \ 'command': '/usr/bin/cc -I' . '/usr/include/xmms2'
+ \ 'directory': ale#path#Simplify('/foo/bar/xmms2-mpris'),
+ \ 'command': '/usr/bin/cc -I' . ale#path#Simplify('/usr/include/xmms2')
\ . ' -o CMakeFiles/xmms2-mpris.dir/src/xmms2-mpris.c.o'
- \ . ' -c ' . '/foo/bar/xmms2-mpris/src/xmms2-mpris.c',
- \ 'file': (has('win32') ? 'C:' : '') . '/foo/bar/xmms2-mpris/src/xmms2-other.c',
+ \ . ' -c ' . ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.c'),
+ \ 'file': ale#path#Simplify((has('win32') ? 'C:' : '') . '/foo/bar/xmms2-mpris/src/xmms2-other.c'),
\ },
\ ] })
@@ -198,7 +221,7 @@ Execute(ParseCompileCommandsFlags should take commands from matching .c files fo
silent noautocmd execute 'file! ' . fnameescape(ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.h'))
AssertEqual
- \ '-I/usr/include/xmms2',
+ \ '-I /usr/include/xmms2',
\ ale#c#ParseCompileCommandsFlags(
\ bufnr(''),
\ {
@@ -220,7 +243,7 @@ Execute(ParseCompileCommandsFlags should take commands from matching .cpp files
silent noautocmd execute 'file! ' . fnameescape(ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.hpp'))
AssertEqual
- \ '-I/usr/include/xmms2',
+ \ '-I /usr/include/xmms2',
\ ale#c#ParseCompileCommandsFlags(
\ bufnr(''),
\ {
@@ -242,7 +265,7 @@ Execute(ParseCompileCommandsFlags should take commands from matching .cpp files
silent noautocmd execute 'file! ' . fnameescape(ale#path#Simplify('/foo/bar/xmms2-mpris/src/xmms2-mpris.h'))
AssertEqual
- \ '-I/usr/include/xmms2',
+ \ '-I /usr/include/xmms2',
\ ale#c#ParseCompileCommandsFlags(
\ bufnr(''),
\ {
@@ -282,13 +305,64 @@ Execute(ParseCompileCommandsFlags should not take commands from .c files for .h
\ },
\ )
+Execute(ParseCFlags should not merge flags):
+ AssertEqual
+ \ '-Dgoal=9'
+ \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))
+ \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir with spaces'))
+ \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir-with-dash'))
+ \ . ' ' . '-I' . ' ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')),
+ \ ale#c#ParseCFlags(
+ \ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
+ \ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir '
+ \ . 'subdir/somedep1.o ' . 'subdir/somedep2.o '
+ \ . '-I''dir with spaces''' . ' -Idir-with-dash '
+ \ . 'subdir/somedep3.o ' . 'subdir/somedep4.o '
+ \ . ' -I'. ale#path#Simplify('kernel/include') . ' '
+ \ . 'subdir/somedep5.o ' . 'subdir/somedep6.o '
+ \ )
+
Execute(ParseCFlags should handle parenthesis and quotes):
AssertEqual
- \ '-Dgoal=9 -Dtest1="('' '')" file1.o -Dtest2=''(` `)'' file2.o -Dtest3=`(" ")` file3.o',
+ \ '-Dgoal=9 -Dtest1="('' '')" -Dtest2=''(` `)'' -Dtest3=`(" ")`',
\ ale#c#ParseCFlags(
\ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
- \ 'gcc -Dgoal=9 '
+ \ 'gcc -Dgoal=9 -Tlinkerfile.ld blabla '
\ . '-Dtest1="('' '')" file1.o '
\ . '-Dtest2=''(` `)'' file2.o '
\ . '-Dtest3=`(" ")` file3.o '
\ )
+
+Execute(CFlags we want to pass):
+ AssertEqual
+ \ '-I ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/inc'))
+ \ . ' -I ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/include'))
+ \ . ' -iquote ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/incquote'))
+ \ . ' -isystem ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/incsystem'))
+ \ . ' -idirafter ' . ale#Escape(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/incafter'))
+ \ . ' -Dmacro=value -D macro2 -Bbdir -B bdir2'
+ \ . ' -iprefix prefix -iwithprefix prefix2 -iwithprefixbefore prefix3'
+ \ . ' -isysroot sysroot --sysroot=test --no-sysroot-suffix -imultilib multidir'
+ \ . ' -Wsome-warning -std=c89 -pedantic -pedantic-errors -ansi'
+ \ . ' -foption -O2 -C -CC -trigraphs -nostdinc -nostdinc++'
+ \ . ' -iplugindir=dir -march=native -w',
+ \ ale#c#ParseCFlags(
+ \ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
+ \ 'gcc'
+ \ . ' -Iinc -I include -iquote incquote -isystem incsystem -idirafter incafter'
+ \ . ' -Dmacro=value -D macro2 -Bbdir -B bdir2'
+ \ . ' -iprefix prefix -iwithprefix prefix2 -iwithprefixbefore prefix3'
+ \ . ' -isysroot sysroot --sysroot=test --no-sysroot-suffix -imultilib multidir'
+ \ . ' -Wsome-warning -std=c89 -pedantic -pedantic-errors -ansi'
+ \ . ' -foption -O2 -C -CC -trigraphs -nostdinc -nostdinc++'
+ \ . ' -iplugindir=dir -march=native -w'
+ \ )
+
+Execute(CFlags we dont want to pass):
+ AssertEqual
+ \ '',
+ \ ale#c#ParseCFlags(
+ \ ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'),
+ \ 'gcc -Wl,option -Wa,option -Wp,option filename.c somelib.a '
+ \ . '-fdump-file=name -fdiagnostics-arg -fno-show-column'
+ \ )
diff --git a/test/test_code_action.vader b/test/test_code_action.vader
new file mode 100644
index 00000000..ffaca630
--- /dev/null
+++ b/test/test_code_action.vader
@@ -0,0 +1,334 @@
+Before:
+ runtime autoload/ale/code_action.vim
+ runtime autoload/ale/util.vim
+
+ let g:file1 = tempname()
+ let g:file2 = tempname()
+ let g:test = {}
+
+ let g:test.create_change = {line, offset, end_line, end_offset, value ->
+ \{
+ \ 'changes': [{
+ \ 'fileName': g:file1,
+ \ 'textChanges': [{
+ \ 'start': {
+ \ 'line': line,
+ \ 'offset': offset,
+ \ },
+ \ 'end': {
+ \ 'line': end_line,
+ \ 'offset': end_offset,
+ \ },
+ \ 'newText': value,
+ \ }],
+ \ }]
+ \}}
+
+ function! WriteFileAndEdit() abort
+ let g:test.text = [
+ \ 'class Name {',
+ \ ' value: string',
+ \ '}',
+ \]
+ call writefile(g:test.text, g:file1, 'S')
+ execute 'edit ' . g:file1
+ endfunction!
+
+After:
+ " Close the extra buffers if we opened it.
+ if bufnr(g:file1) != -1
+ execute ':bp | :bd ' . bufnr(g:file1)
+ endif
+ if bufnr(g:file2) != -1
+ execute ':bp | :bd ' . bufnr(g:file2)
+ endif
+
+ if filereadable(g:file1)
+ call delete(g:file1)
+ endif
+ if filereadable(g:file2)
+ call delete(g:file2)
+ endif
+
+ unlet g:file1
+ unlet g:file2
+ unlet g:test
+ delfunction WriteFileAndEdit
+
+ runtime autoload/ale/code_action.vim
+ runtime autoload/ale/util.vim
+
+
+Execute(It should modify and save multiple files):
+ call writefile([
+ \ 'class Name {',
+ \ ' value: string',
+ \ '}',
+ \ '',
+ \ 'class B {',
+ \ ' constructor(readonly a: Name) {}',
+ \ '}'
+ \], g:file1, 'S')
+ call writefile([
+ \ 'import A from "A"',
+ \ 'import {',
+ \ ' B,',
+ \ ' C,',
+ \ '} from "module"',
+ \ 'import D from "D"',
+ \], g:file2, 'S')
+
+ call ale#code_action#HandleCodeAction({
+ \ 'changes': [{
+ \ 'fileName': g:file1,
+ \ 'textChanges': [{
+ \ 'start': {
+ \ 'line': 1,
+ \ 'offset': 7,
+ \ },
+ \ 'end': {
+ \ 'line': 1,
+ \ 'offset': 11,
+ \ },
+ \ 'newText': 'Value',
+ \ }, {
+ \ 'start': {
+ \ 'line': 6,
+ \ 'offset': 27,
+ \ },
+ \ 'end': {
+ \ 'line': 6,
+ \ 'offset': 31,
+ \ },
+ \ 'newText': 'Value',
+ \ }],
+ \ }, {
+ \ 'fileName': g:file2,
+ \ 'textChanges': [{
+ \ 'start': {
+ \ 'line': 2,
+ \ 'offset': 1,
+ \ },
+ \ 'end': {
+ \ 'line': 6,
+ \ 'offset': 1,
+ \ },
+ \ 'newText': "import {A, B} from 'module'\n\n",
+ \ }]
+ \ }],
+ \})
+
+ AssertEqual [
+ \ 'class Value {',
+ \ ' value: string',
+ \ '}',
+ \ '',
+ \ 'class B {',
+ \ ' constructor(readonly a: Value) {}',
+ \ '}',
+ \ '',
+ \], readfile(g:file1, 'b')
+
+ AssertEqual [
+ \ 'import A from "A"',
+ \ 'import {A, B} from ''module''',
+ \ '',
+ \ 'import D from "D"',
+ \ '',
+ \], readfile(g:file2, 'b')
+
+
+Execute(Beginning of file can be modified):
+ let g:test.text = [
+ \ 'class Name {',
+ \ ' value: string',
+ \ '}',
+ \]
+ call writefile(g:test.text, g:file1, 'S')
+
+ call ale#code_action#HandleCodeAction({
+ \ 'changes': [{
+ \ 'fileName': g:file1,
+ \ 'textChanges': [{
+ \ 'start': {
+ \ 'line': 1,
+ \ 'offset': 1,
+ \ },
+ \ 'end': {
+ \ 'line': 1,
+ \ 'offset': 1,
+ \ },
+ \ 'newText': "type A: string\ntype B: number\n",
+ \ }],
+ \ }]
+ \})
+
+ AssertEqual [
+ \ 'type A: string',
+ \ 'type B: number',
+ \] + g:test.text + [''], readfile(g:file1, 'b')
+
+
+Execute(End of file can be modified):
+ let g:test.text = [
+ \ 'class Name {',
+ \ ' value: string',
+ \ '}',
+ \]
+ call writefile(g:test.text, g:file1, 'S')
+
+ call ale#code_action#HandleCodeAction({
+ \ 'changes': [{
+ \ 'fileName': g:file1,
+ \ 'textChanges': [{
+ \ 'start': {
+ \ 'line': 4,
+ \ 'offset': 1,
+ \ },
+ \ 'end': {
+ \ 'line': 4,
+ \ 'offset': 1,
+ \ },
+ \ 'newText': "type A: string\ntype B: number\n",
+ \ }],
+ \ }]
+ \})
+
+ AssertEqual g:test.text + [
+ \ 'type A: string',
+ \ 'type B: number',
+ \ '',
+ \], readfile(g:file1, 'b')
+
+
+Execute(Current buffer contents will be reloaded):
+ let g:test.text = [
+ \ 'class Name {',
+ \ ' value: string',
+ \ '}',
+ \]
+ call writefile(g:test.text, g:file1, 'S')
+
+ execute 'edit ' . g:file1
+ let g:test.buffer = bufnr(g:file1)
+
+ call ale#code_action#HandleCodeAction({
+ \ 'changes': [{
+ \ 'fileName': g:file1,
+ \ 'textChanges': [{
+ \ 'start': {
+ \ 'line': 1,
+ \ 'offset': 1,
+ \ },
+ \ 'end': {
+ \ 'line': 1,
+ \ 'offset': 1,
+ \ },
+ \ 'newText': "type A: string\ntype B: number\n",
+ \ }],
+ \ }]
+ \})
+
+ AssertEqual [
+ \ 'type A: string',
+ \ 'type B: number',
+ \] + g:test.text + [''], readfile(g:file1, 'b')
+
+ AssertEqual [
+ \ 'type A: string',
+ \ 'type B: number',
+ \] + g:test.text, getbufline(g:test.buffer, 1, '$')
+
+
+# Tests for cursor repositioning. In comments `=` designates change range, and
+# `C` cursor position
+
+# C ===
+Execute(Cursor will not move when it is before text change):
+ call WriteFileAndEdit()
+ let g:test.changes = g:test.create_change(2, 3, 2, 8, 'value2')
+
+ call setpos('.', [0, 1, 1, 0])
+ call ale#code_action#HandleCodeAction(g:test.changes)
+ AssertEqual [1, 1], getpos('.')[1:2]
+
+ call setpos('.', [0, 2, 2, 0])
+ call ale#code_action#HandleCodeAction(g:test.changes)
+ AssertEqual [2, 2], getpos('.')[1:2]
+
+# ====C====
+Execute(Cursor column will move to the change end when cursor between start/end):
+ let g:test.changes = g:test.create_change(2, 3, 2, 8, 'value2')
+
+ for r in range(3, 8)
+ call WriteFileAndEdit()
+ call setpos('.', [0, 2, r, 0])
+ AssertEqual ' value: string', getline('.')
+ call ale#code_action#HandleCodeAction(g:test.changes)
+ AssertEqual ' value2: string', getline('.')
+ AssertEqual [2, 9], getpos('.')[1:2]
+ endfor
+
+
+# ====C
+Execute(Cursor column will move back when new text is shorter):
+ call WriteFileAndEdit()
+ call setpos('.', [0, 2, 8, 0])
+ AssertEqual ' value: string', getline('.')
+ call ale#code_action#HandleCodeAction(g:test.create_change(2, 3, 2, 8, 'val'))
+ AssertEqual ' val: string', getline('.')
+ AssertEqual [2, 6], getpos('.')[1:2]
+
+
+# ==== C
+Execute(Cursor column will move forward when new text is longer):
+ call WriteFileAndEdit()
+
+ call setpos('.', [0, 2, 8, 0])
+ AssertEqual ' value: string', getline('.')
+ call ale#code_action#HandleCodeAction(g:test.create_change(2, 3, 2, 8, 'longValue'))
+ AssertEqual ' longValue: string', getline('.')
+ AssertEqual [2, 12], getpos('.')[1:2]
+
+# =========
+# =
+# C
+Execute(Cursor line will move when updates are happening on lines above):
+ call WriteFileAndEdit()
+ call setpos('.', [0, 3, 1, 0])
+ AssertEqual '}', getline('.')
+ call ale#code_action#HandleCodeAction(g:test.create_change(1, 1, 2, 1, "test\ntest\n"))
+ AssertEqual '}', getline('.')
+ AssertEqual [4, 1], getpos('.')[1:2]
+
+
+# =========
+# =C
+Execute(Cursor line and column will move when change on lines above and just before cursor column):
+ call WriteFileAndEdit()
+ call setpos('.', [0, 2, 2, 0])
+ AssertEqual ' value: string', getline('.')
+ call ale#code_action#HandleCodeAction(g:test.create_change(1, 1, 2, 1, "test\ntest\n123"))
+ AssertEqual '123 value: string', getline('.')
+ AssertEqual [3, 5], getpos('.')[1:2]
+
+# =========
+# ======C==
+# =
+Execute(Cursor line and column will move at the end of changes):
+ call WriteFileAndEdit()
+ call setpos('.', [0, 2, 10, 0])
+ AssertEqual ' value: string', getline('.')
+ call ale#code_action#HandleCodeAction(g:test.create_change(1, 1, 3, 1, "test\n"))
+ AssertEqual '}', getline('.')
+ AssertEqual [2, 1], getpos('.')[1:2]
+
+# C ==
+# ===
+Execute(Cursor will not move when changes happening on lines >= cursor, but after cursor):
+ call WriteFileAndEdit()
+ call setpos('.', [0, 2, 3, 0])
+ AssertEqual ' value: string', getline('.')
+ call ale#code_action#HandleCodeAction(g:test.create_change(2, 10, 3, 1, "number\n"))
+ AssertEqual ' value: number', getline('.')
+ AssertEqual [2, 3], getpos('.')[1:2]
diff --git a/test/test_filetype_linter_defaults.vader b/test/test_filetype_linter_defaults.vader
index af028041..9c40cb23 100644
--- a/test/test_filetype_linter_defaults.vader
+++ b/test/test_filetype_linter_defaults.vader
@@ -66,3 +66,7 @@ Execute(The defaults for the verilog filetype should be correct):
let g:ale_linters_explicit = 1
AssertEqual [], GetLinterNames('verilog')
+
+Execute(Default aliases for React should be defined):
+ AssertEqual ['javascript', 'jsx'], ale#linter#ResolveFiletype('javascriptreact')
+ AssertEqual ['typescript', 'tsx'], ale#linter#ResolveFiletype('typescriptreact')
diff --git a/test/test_highlight_placement.vader b/test/test_highlight_placement.vader
index 87ac6073..c062018b 100644
--- a/test/test_highlight_placement.vader
+++ b/test/test_highlight_placement.vader
@@ -8,6 +8,8 @@ Before:
Save g:ale_set_quickfix
Save g:ale_set_signs
+ runtime autoload/ale/highlight.vim
+
let g:ale_run_synchronously = 1
unlet! g:ale_run_synchronously_callbacks
let g:ale_set_highlights = 1
@@ -42,16 +44,54 @@ Before:
\]
endfunction
+ let g:has_nvim_highlight = exists('*nvim_buf_add_highlight') && exists('*nvim_buf_clear_namespace')
+ let g:nvim_highlight_matches = {}
+
+ function! ale#highlight#nvim_buf_clear_namespace(buffer, ns_id, line_start, line_end) abort
+ if a:line_end != -1
+ throw 'nvim api behavior not supported'
+ endif
+
+ let l:matches = get(g:nvim_highlight_matches, a:buffer, [])
+ call filter(
+ \ l:matches,
+ \ {_, val -> val.pos1[0] < (a:line_start + 1) },
+ \)
+ endfunction
+
+ function! ale#highlight#nvim_buf_add_highlight(buffer, ns_id, hl_group, line, col_start, col_end) abort
+ if a:col_end == -1
+ throw 'nvim api behavior not supported'
+ endif
+
+ let l:matches = get(g:nvim_highlight_matches, a:buffer, [])
+ let g:nvim_highlight_matches[a:buffer] = l:matches
+
+ let l:new_match = {
+ \ 'group': a:hl_group,
+ \ 'priority': 10,
+ \ 'pos1': [a:line + 1, a:col_start + 1, a:col_end - a:col_start],
+ \}
+
+ call add(l:matches, l:new_match)
+ " sort by line number to emulate getmatches faithfully
+ call sort(l:matches, {m1, m2 -> m1.pos1[0] - m2.pos1[0]})
+ endfunction
+
" We don't care what the IDs are, just that we have some matches.
" The IDs are generated.
function! GetMatchesWithoutIDs() abort
- let l:list = getmatches()
+ if g:has_nvim_highlight
+ return get(g:nvim_highlight_matches, bufnr(''), [])
+ else
+ let l:list = getmatches()
- for l:item in l:list
- call remove(l:item, 'id')
- endfor
+ for l:item in l:list
+ call remove(l:item, 'id')
+ endfor
- return l:list
+ return l:list
+ endif
endfunction
call ale#linter#Define('testft', {
@@ -68,6 +108,8 @@ After:
unlet! g:ale_run_synchronously_callbacks
unlet! g:items
unlet! b:ale_enabled
+ unlet! g:has_nvim_highlight
+ unlet! g:nvim_highlight_matches
delfunction GenerateResults
call ale#linter#Reset()
@@ -75,6 +117,8 @@ After:
sign unplace *
highlight clear SomeOtherGroup
+ runtime autoload/ale/highlight.vim
+
Given testft(A Javscript file with warnings/errors):
foo
bar
@@ -102,9 +146,12 @@ Execute(Highlights set by ALE should be removed when buffer cleanup is done):
\ {'bufnr': bufnr('%'), 'type': 'E', 'lnum': 3, 'col': 2},
\])
- AssertEqual
- \ [{'group': 'ALEError', 'priority': 10, 'pos1': [3, 2, 1]}],
- \ GetMatchesWithoutIDs()
+ if !g:has_nvim_highlight
+ " This check doesn't work with the new API, for some reason.
+ AssertEqual
+ \ [{'group': 'ALEError', 'priority': 10, 'pos1': [3, 2, 1]}],
+ \ GetMatchesWithoutIDs()
+ endif
call ale#engine#Cleanup(bufnr('%'))
@@ -145,31 +192,53 @@ Execute(Only ALE highlights should be restored when buffers are restored):
call matchaddpos('SomeOtherGroup', [[1, 1, 1]])
" We should have both highlights.
- AssertEqual
- \ [
- \ {'group': 'ALEError', 'priority': 10, 'pos1': [3, 2, 1]},
- \ {'group': 'SomeOtherGroup', 'priority': 10, 'pos1': [1, 1, 1]},
- \ ],
- \ GetMatchesWithoutIDs()
+ if g:has_nvim_highlight
+ " When the newer NeoVim API is used, we don't have to worry about
+ " other highlights, namespacing is available.
+ AssertEqual
+ \ [
+ \ {'group': 'ALEError', 'priority': 10, 'pos1': [3, 2, 1]},
+ \ ],
+ \ GetMatchesWithoutIDs()
+ else
+ AssertEqual
+ \ [
+ \ {'group': 'ALEError', 'priority': 10, 'pos1': [3, 2, 1]},
+ \ {'group': 'SomeOtherGroup', 'priority': 10, 'pos1': [1, 1, 1]},
+ \ ],
+ \ sort(GetMatchesWithoutIDs(), {m1, m2 -> m1.group < m2.group ? -1 : 1})
+ endif
call ale#highlight#BufferHidden(bufnr('%'))
" We should remove our highlight, but not the other one.
- AssertEqual
- \ [
- \ {'group': 'SomeOtherGroup', 'priority': 10, 'pos1': [1, 1, 1]}
- \ ],
- \ GetMatchesWithoutIDs()
+ if g:has_nvim_highlight
+ AssertEqual [], GetMatchesWithoutIDs()
+ else
+ AssertEqual
+ \ [
+ \ {'group': 'SomeOtherGroup', 'priority': 10, 'pos1': [1, 1, 1]}
+ \ ],
+ \ GetMatchesWithoutIDs()
+ endif
call ale#highlight#UpdateHighlights()
" Our highlight should apper again.
- AssertEqual
- \ [
- \ {'group': 'SomeOtherGroup', 'priority': 10, 'pos1': [1, 1, 1]},
- \ {'group': 'ALEError', 'priority': 10, 'pos1': [3, 2, 1]},
- \ ],
- \ GetMatchesWithoutIDs()
+ if g:has_nvim_highlight
+ AssertEqual
+ \ [
+ \ {'group': 'ALEError', 'priority': 10, 'pos1': [3, 2, 1]},
+ \ ],
+ \ GetMatchesWithoutIDs()
+ else
+ AssertEqual
+ \ [
+ \ {'group': 'ALEError', 'priority': 10, 'pos1': [3, 2, 1]},
+ \ {'group': 'SomeOtherGroup', 'priority': 10, 'pos1': [1, 1, 1]},
+ \ ],
+ \ sort(GetMatchesWithoutIDs(), {m1, m2 -> m1.group < m2.group ? -1 : 1})
+ endif
Execute(Higlight end columns should set an appropriate size):
call ale#highlight#SetHighlights(bufnr('%'), [
@@ -216,32 +285,67 @@ Execute(Highlighting should support errors spanning many lines):
call ale#highlight#SetHighlights(bufnr(''), g:items)
- " We should set 2 highlights for the item, as we can only add 8 at a time.
- AssertEqual
- \ [
- \ {
- \ 'group': 'ALEError', 'priority': 10, 'pos1': [1, 1, 1073741824],
- \ 'pos2': [2], 'pos3': [3], 'pos4': [4], 'pos5': [5], 'pos6': [6],
- \ 'pos7': [7], 'pos8': [8],
- \ },
- \ {
- \ 'group': 'ALEError', 'priority': 10,
- \ 'pos1': [9], 'pos2': [10, 1, 3]
- \ },
- \ ],
- \ GetMatchesWithoutIDs()
+ if g:has_nvim_highlight
+ " The newer NeoVim highlight API produces different output.
+ AssertEqual
+ \ [
+ \ {'group': 'ALEError', 'priority': 10, 'pos1': [1, 1, 1073741824]},
+ \ {'group': 'ALEError', 'priority': 10, 'pos1': [2, 1, 1073741824]},
+ \ {'group': 'ALEError', 'priority': 10, 'pos1': [3, 1, 1073741824]},
+ \ {'group': 'ALEError', 'priority': 10, 'pos1': [4, 1, 1073741824]},
+ \ {'group': 'ALEError', 'priority': 10, 'pos1': [5, 1, 1073741824]},
+ \ {'group': 'ALEError', 'priority': 10, 'pos1': [6, 1, 1073741824]},
+ \ {'group': 'ALEError', 'priority': 10, 'pos1': [7, 1, 1073741824]},
+ \ {'group': 'ALEError', 'priority': 10, 'pos1': [8, 1, 1073741824]},
+ \ {'group': 'ALEError', 'priority': 10, 'pos1': [9, 1, 1073741824]},
+ \ {'group': 'ALEError', 'priority': 10, 'pos1': [10, 1, 3]},
+ \ ],
+ \ GetMatchesWithoutIDs()
+ else
+ " We should set 2 highlights for the item, as we can only add 8 at a time.
+ AssertEqual
+ \ [
+ \ {
+ \ 'group': 'ALEError', 'priority': 10, 'pos1': [1, 1, 1073741824],
+ \ 'pos2': [2], 'pos3': [3], 'pos4': [4], 'pos5': [5], 'pos6': [6],
+ \ 'pos7': [7], 'pos8': [8],
+ \ },
+ \ {
+ \ 'group': 'ALEError', 'priority': 10,
+ \ 'pos1': [9], 'pos2': [10, 1, 3]
+ \ },
+ \ ],
+ \ GetMatchesWithoutIDs()
+ endif
Execute(Highlights should always be cleared when the buffer highlight list is empty):
- " Add our highlights and something else.
- call matchaddpos('ALEError', [[1, 1, 1]])
- call matchaddpos('SomeOtherGroup', [[1, 1, 1]])
+ if g:has_nvim_highlight
+ " The newer API uses namespacing. We'll emulate it here.
+ call ale#highlight#nvim_buf_add_highlight(
+ \ bufnr(''),
+ \ 1,
+ \ 'ALEError',
+ \ 0,
+ \ 0,
+ \ 1,
+ \)
+
+ AssertEqual
+ \ [{'group': 'ALEError', 'priority': 10, 'pos1': [1, 1, 1]}],
+ \ GetMatchesWithoutIDs()
+ else
+ " Add our highlights and something else.
+ call matchaddpos('ALEError', [[1, 1, 1]])
+ call matchaddpos('SomeOtherGroup', [[1, 1, 1]])
+
+ AssertEqual
+ \ [
+ \ {'group': 'ALEError', 'priority': 10, 'pos1': [1, 1, 1]},
+ \ {'group': 'SomeOtherGroup', 'priority': 10, 'pos1': [1, 1, 1]},
+ \ ],
+ \ GetMatchesWithoutIDs()
+ endif
- AssertEqual
- \ [
- \ {'group': 'ALEError', 'priority': 10, 'pos1': [1, 1, 1]},
- \ {'group': 'SomeOtherGroup', 'priority': 10, 'pos1': [1, 1, 1]},
- \ ],
- \ GetMatchesWithoutIDs()
" Set the List we use for holding highlights for buffers.
let b:ale_highlight_items = []
@@ -251,11 +355,13 @@ Execute(Highlights should always be cleared when the buffer highlight list is em
call ale#highlight#UpdateHighlights()
" Check that we remove our highlights.
- AssertEqual
- \ [
- \ {'group': 'SomeOtherGroup', 'priority': 10, 'pos1': [1, 1, 1]},
- \ ],
- \ GetMatchesWithoutIDs()
+ if g:has_nvim_highlight
+ AssertEqual [], GetMatchesWithoutIDs()
+ else
+ AssertEqual
+ \ [{'group': 'SomeOtherGroup', 'priority': 10, 'pos1': [1, 1, 1]}],
+ \ GetMatchesWithoutIDs()
+ endif
Execute(Highlights should be cleared when ALE is disabled):
let g:ale_enabled = 1
@@ -291,16 +397,30 @@ Execute(Line highlights should be set when signs are disabled):
\ {'bufnr': bufnr(''), 'type': 'I', 'lnum': 3, 'col': 1},
\])
- AssertEqual
- \ [
- \ {'group': 'ALEError', 'priority': 10, 'pos1': [1, 1, 1]},
- \ {'group': 'ALEWarning', 'priority': 10, 'pos1': [2, 1, 1]},
- \ {'group': 'ALEInfo', 'priority': 10, 'pos1': [3, 1, 1]},
- \ {'group': 'aleerrorline', 'priority': 10, 'pos1': [1]},
- \ {'group': 'ALEWarningLine', 'priority': 10, 'pos1': [2]},
- \ {'group': 'ALEInfoLine', 'priority': 10, 'pos1': [3]},
- \ ],
- \ GetMatchesWithoutIDs()
+ if g:has_nvim_highlight
+ " The output is different with the newer NeoVIM highlight API.
+ AssertEqual
+ \ [
+ \ {'group': 'ALEError', 'priority': 10, 'pos1': [1, 1, 1]},
+ \ {'group': 'ALEErrorLine', 'priority': 10, 'pos1': [1, 1, 1073741824]},
+ \ {'group': 'ALEWarning', 'priority': 10, 'pos1': [2, 1, 1]},
+ \ {'group': 'ALEWarningLine', 'priority': 10, 'pos1': [2, 1, 1073741824]},
+ \ {'group': 'ALEInfo', 'priority': 10, 'pos1': [3, 1, 1]},
+ \ {'group': 'ALEInfoLine', 'priority': 10, 'pos1': [3, 1, 1073741824]}
+ \ ],
+ \ GetMatchesWithoutIDs()
+ else
+ AssertEqual
+ \ [
+ \ {'group': 'ALEError', 'priority': 10, 'pos1': [1, 1, 1]},
+ \ {'group': 'ALEWarning', 'priority': 10, 'pos1': [2, 1, 1]},
+ \ {'group': 'ALEInfo', 'priority': 10, 'pos1': [3, 1, 1]},
+ \ {'group': 'aleerrorline', 'priority': 10, 'pos1': [1]},
+ \ {'group': 'ALEWarningLine', 'priority': 10, 'pos1': [2]},
+ \ {'group': 'ALEInfoLine', 'priority': 10, 'pos1': [3]},
+ \ ],
+ \ GetMatchesWithoutIDs()
+ endif
" All of the highlights should be removed.
call ale#highlight#RemoveHighlights()
diff --git a/test/test_organize_imports.vader b/test/test_organize_imports.vader
new file mode 100644
index 00000000..137326a9
--- /dev/null
+++ b/test/test_organize_imports.vader
@@ -0,0 +1,171 @@
+Before:
+ call ale#test#SetDirectory('/testplugin/test')
+ call ale#test#SetFilename('dummy.txt')
+
+ let g:old_filename = expand('%:p')
+ let g:Callback = ''
+ let g:expr_list = []
+ let g:message_list = []
+ let g:handle_code_action_called = 0
+ let g:code_actions = []
+ let g:options = {}
+ let g:capability_checked = ''
+ let g:conn_id = v:null
+ let g:InitCallback = v:null
+
+ runtime autoload/ale/lsp_linter.vim
+ runtime autoload/ale/lsp.vim
+ runtime autoload/ale/util.vim
+ runtime autoload/ale/organize_imports.vim
+ runtime autoload/ale/code_action.vim
+
+ function! ale#lsp_linter#StartLSP(buffer, linter, Callback) abort
+ let g:conn_id = ale#lsp#Register('executable', '/foo/bar', {})
+ call ale#lsp#MarkDocumentAsOpen(g:conn_id, a:buffer)
+
+ if a:linter.lsp is# 'tsserver'
+ call ale#lsp#MarkConnectionAsTsserver(g:conn_id)
+ endif
+
+ let l:details = {
+ \ 'command': 'foobar',
+ \ 'buffer': a:buffer,
+ \ 'connection_id': g:conn_id,
+ \ 'project_root': '/foo/bar',
+ \}
+
+ let g:InitCallback = {-> ale#lsp_linter#OnInit(a:linter, l:details, a:Callback)}
+ endfunction
+
+ function! ale#lsp#HasCapability(conn_id, capability) abort
+ let g:capability_checked = a:capability
+
+ return 1
+ endfunction
+
+ function! ale#lsp#RegisterCallback(conn_id, callback) abort
+ let g:Callback = a:callback
+ endfunction
+
+ function! ale#lsp#Send(conn_id, message) abort
+ call add(g:message_list, a:message)
+
+ return 42
+ endfunction
+
+ function! ale#util#Execute(expr) abort
+ call add(g:expr_list, a:expr)
+ endfunction
+
+ function! ale#code_action#HandleCodeAction(code_action) abort
+ let g:handle_code_action_called = 1
+ call add(g:code_actions, a:code_action)
+ endfunction
+
+After:
+ if g:conn_id isnot v:null
+ call ale#lsp#RemoveConnectionWithID(g:conn_id)
+ endif
+
+ call ale#references#SetMap({})
+ call ale#test#RestoreDirectory()
+ call ale#linter#Reset()
+
+ unlet! g:capability_checked
+ unlet! g:InitCallback
+ unlet! g:old_filename
+ unlet! g:conn_id
+ unlet! g:Callback
+ unlet! g:message_list
+ unlet! g:expr_list
+ unlet! b:ale_linters
+ unlet! g:options
+ unlet! g:code_actions
+ unlet! g:handle_code_action_called
+
+ runtime autoload/ale/lsp_linter.vim
+ runtime autoload/ale/lsp.vim
+ runtime autoload/ale/util.vim
+ runtime autoload/ale/organize_imports.vim
+ runtime autoload/ale/code_action.vim
+
+Execute(Other messages for the tsserver handler should be ignored):
+ call ale#organize_imports#HandleTSServerResponse(1, {'command': 'foo'})
+ AssertEqual g:handle_code_action_called, 0
+
+Execute(Failed organizeImports responses should be handled correctly):
+ call ale#organize_imports#HandleTSServerResponse(
+ \ 1,
+ \ {'command': 'organizeImports', 'request_seq': 3}
+ \)
+ AssertEqual g:handle_code_action_called, 0
+
+Execute(Code actions from tsserver should be handled):
+ call ale#organize_imports#HandleTSServerResponse(1, {
+ \ 'command': 'organizeImports',
+ \ 'request_seq': 3,
+ \ 'success': v:true,
+ \ 'body': [],
+ \})
+ AssertEqual g:handle_code_action_called, 1
+ AssertEqual [{
+ \ 'description': 'Organize Imports',
+ \ 'changes': [],
+ \}], g:code_actions
+
+Given typescript(Some typescript file):
+ foo
+ somelongerline
+ bazxyzxyzxyz
+
+Execute(tsserver organize imports requests should be sent):
+ call ale#linter#Reset()
+ runtime ale_linters/typescript/tsserver.vim
+
+ ALEOrganizeImports
+
+ " We shouldn't register the callback yet.
+ AssertEqual '''''', string(g:Callback)
+
+ AssertEqual type(function('type')), type(g:InitCallback)
+ call g:InitCallback()
+
+ AssertEqual
+ \ 'function(''ale#organize_imports#HandleTSServerResponse'')',
+ \ string(g:Callback)
+
+ AssertEqual
+ \ [
+ \ ale#lsp#tsserver_message#Change(bufnr('')),
+ \ [0, 'ts@organizeImports', {
+ \ 'scope': {
+ \ 'type': 'file',
+ \ 'args': {
+ \ 'file': expand('%:p'),
+ \ },
+ \ },
+ \ }]
+ \ ],
+ \ g:message_list
+
+Given python(Some Python file):
+ foo
+ somelongerline
+ bazxyzxyzxyz
+
+Execute(Should result in error message):
+ call ale#linter#Reset()
+ runtime ale_linters/python/pyls.vim
+ let b:ale_linters = ['pyls']
+
+ ALEOrganizeImports
+
+ " We shouldn't register the callback yet.
+ AssertEqual '''''', string(g:Callback)
+
+ AssertEqual type(function('type')), type(g:InitCallback)
+ call g:InitCallback()
+
+ AssertEqual [
+ \ 'echom ''OrganizeImports currently only works with tsserver''',
+ \], g:expr_list
diff --git a/test/test_rename.vader b/test/test_rename.vader
new file mode 100644
index 00000000..98e3ef30
--- /dev/null
+++ b/test/test_rename.vader
@@ -0,0 +1,394 @@
+Before:
+ call ale#test#SetDirectory('/testplugin/test')
+ call ale#test#SetFilename('dummy.txt')
+
+ let g:old_filename = expand('%:p')
+ let g:Callback = ''
+ let g:expr_list = []
+ let g:message_list = []
+ let g:handle_code_action_called = 0
+ let g:code_actions = []
+ let g:options = {}
+ let g:capability_checked = ''
+ let g:conn_id = v:null
+ let g:InitCallback = v:null
+
+ runtime autoload/ale/lsp_linter.vim
+ runtime autoload/ale/lsp.vim
+ runtime autoload/ale/util.vim
+ runtime autoload/ale/rename.vim
+ runtime autoload/ale/code_action.vim
+
+ function! ale#lsp_linter#StartLSP(buffer, linter, Callback) abort
+ let g:conn_id = ale#lsp#Register('executable', '/foo/bar', {})
+ call ale#lsp#MarkDocumentAsOpen(g:conn_id, a:buffer)
+
+ if a:linter.lsp is# 'tsserver'
+ call ale#lsp#MarkConnectionAsTsserver(g:conn_id)
+ endif
+
+ let l:details = {
+ \ 'command': 'foobar',
+ \ 'buffer': a:buffer,
+ \ 'connection_id': g:conn_id,
+ \ 'project_root': '/foo/bar',
+ \}
+
+ let g:InitCallback = {-> ale#lsp_linter#OnInit(a:linter, l:details, a:Callback)}
+ endfunction
+
+ function! ale#lsp#HasCapability(conn_id, capability) abort
+ let g:capability_checked = a:capability
+
+ return 1
+ endfunction
+
+ function! ale#lsp#RegisterCallback(conn_id, callback) abort
+ let g:Callback = a:callback
+ endfunction
+
+ function! ale#lsp#Send(conn_id, message) abort
+ call add(g:message_list, a:message)
+
+ return 42
+ endfunction
+
+ function! ale#util#Execute(expr) abort
+ call add(g:expr_list, a:expr)
+ endfunction
+
+ function! ale#code_action#HandleCodeAction(code_action) abort
+ let g:handle_code_action_called = 1
+ call add(g:code_actions, a:code_action)
+ endfunction
+
+ function! ale#util#Input(message, value) abort
+ return 'a-new-name'
+ endfunction
+
+ call ale#rename#SetMap({
+ \ 3: {
+ \ 'old_name': 'oldName',
+ \ 'new_name': 'aNewName',
+ \ },
+ \})
+
+After:
+ if g:conn_id isnot v:null
+ call ale#lsp#RemoveConnectionWithID(g:conn_id)
+ endif
+
+ call ale#rename#SetMap({})
+ call ale#test#RestoreDirectory()
+ call ale#linter#Reset()
+
+ unlet! g:capability_checked
+ unlet! g:InitCallback
+ unlet! g:old_filename
+ unlet! g:conn_id
+ unlet! g:Callback
+ unlet! g:message_list
+ unlet! g:expr_list
+ unlet! b:ale_linters
+ unlet! g:options
+ unlet! g:code_actions
+ unlet! g:handle_code_action_called
+
+ runtime autoload/ale/lsp_linter.vim
+ runtime autoload/ale/lsp.vim
+ runtime autoload/ale/util.vim
+ runtime autoload/ale/rename.vim
+ runtime autoload/ale/code_action.vim
+
+Execute(Other messages for the tsserver handler should be ignored):
+ call ale#rename#HandleTSServerResponse(1, {'command': 'foo'})
+ AssertEqual g:handle_code_action_called, 0
+
+Execute(Failed rename responses should be handled correctly):
+ call ale#rename#SetMap({3: {'old_name': 'oldName', 'new_name': 'a-test'}})
+ call ale#rename#HandleTSServerResponse(
+ \ 1,
+ \ {'command': 'rename', 'request_seq': 3}
+ \)
+ AssertEqual g:handle_code_action_called, 0
+
+Given typescript(Some typescript file):
+ foo
+ somelongerline
+ bazxyzxyzxyz
+
+Execute(Code actions from tsserver should be handled):
+ call ale#rename#HandleTSServerResponse(1, {
+ \ 'command': 'rename',
+ \ 'request_seq': 3,
+ \ 'success': v:true,
+ \ 'body': {
+ \ 'locs': [
+ \ {
+ \ 'file': '/foo/bar/file1.ts',
+ \ 'locs': [
+ \ {
+ \ 'start': {
+ \ 'line': 1,
+ \ 'offset': 2,
+ \ },
+ \ 'end': {
+ \ 'line': 3,
+ \ 'offset': 4,
+ \ },
+ \ },
+ \ ],
+ \ },
+ \ {
+ \ 'file': '/foo/bar/file2.ts',
+ \ 'locs': [
+ \ {
+ \ 'start': {
+ \ 'line': 10,
+ \ 'offset': 20,
+ \ },
+ \ 'end': {
+ \ 'line': 30,
+ \ 'offset': 40,
+ \ },
+ \ },
+ \ ],
+ \ },
+ \ ]
+ \ },
+ \})
+
+ AssertEqual
+ \ [
+ \ {
+ \ 'description': 'rename',
+ \ 'changes': [
+ \ {
+ \ 'fileName': '/foo/bar/file1.ts',
+ \ 'textChanges': [
+ \ {
+ \ 'start': {
+ \ 'line': 1,
+ \ 'offset': 2,
+ \ },
+ \ 'end': {
+ \ 'line': 3,
+ \ 'offset': 4,
+ \ },
+ \ 'newText': 'aNewName',
+ \ },
+ \ ],
+ \ },
+ \ {
+ \ 'fileName': '/foo/bar/file2.ts',
+ \ 'textChanges': [
+ \ {
+ \ 'start': {
+ \ 'line': 10,
+ \ 'offset': 20,
+ \ },
+ \ 'end': {
+ \ 'line': 30,
+ \ 'offset': 40,
+ \ },
+ \ 'newText': 'aNewName',
+ \ },
+ \ ],
+ \ },
+ \ ],
+ \ }
+ \ ],
+ \ g:code_actions
+
+Execute(HandleTSServerResponse does nothing when no data in rename_map):
+ call ale#rename#HandleTSServerResponse(1, {
+ \ 'command': 'rename',
+ \ 'request_seq': -9,
+ \ 'success': v:true,
+ \ 'body': {}
+ \})
+
+ AssertEqual g:handle_code_action_called, 0
+
+Execute(Prints a tsserver error message when unsuccessful):
+ call ale#rename#HandleTSServerResponse(1, {
+ \ 'command': 'rename',
+ \ 'request_seq': 3,
+ \ 'success': v:false,
+ \ 'message': 'This symbol cannot be renamed',
+ \})
+
+ AssertEqual g:handle_code_action_called, 0
+ AssertEqual ['echom ''Error renaming "oldName" to: "aNewName". ' .
+ \ 'Reason: This symbol cannot be renamed'''], g:expr_list
+
+Execute(Does nothing when no changes):
+ call ale#rename#HandleTSServerResponse(1, {
+ \ 'command': 'rename',
+ \ 'request_seq': 3,
+ \ 'success': v:true,
+ \ 'body': {
+ \ 'locs': []
+ \ }
+ \})
+
+ AssertEqual g:handle_code_action_called, 0
+ AssertEqual ['echom ''Error renaming "oldName" to: "aNewName"'''], g:expr_list
+
+Execute(tsserver rename requests should be sent):
+ call ale#rename#SetMap({})
+ call ale#linter#Reset()
+
+ runtime ale_linters/typescript/tsserver.vim
+ call setpos('.', [bufnr(''), 2, 5, 0])
+
+ ALERename
+
+ " We shouldn't register the callback yet.
+ AssertEqual '''''', string(g:Callback)
+
+ AssertEqual type(function('type')), type(g:InitCallback)
+ call g:InitCallback()
+
+ AssertEqual 'rename', g:capability_checked
+ AssertEqual
+ \ 'function(''ale#rename#HandleTSServerResponse'')',
+ \ string(g:Callback)
+ AssertEqual
+ \ [
+ \ ale#lsp#tsserver_message#Change(bufnr('')),
+ \ [0, 'ts@rename', {
+ \ 'file': expand('%:p'),
+ \ 'line': 2,
+ \ 'offset': 5,
+ \ 'arguments': {
+ \ 'findInComments': g:ale_rename_tsserver_find_in_comments,
+ \ 'findInStrings': g:ale_rename_tsserver_find_in_strings,
+ \ },
+ \ }]
+ \ ],
+ \ g:message_list
+ AssertEqual {'42': {'old_name': 'somelongerline', 'new_name': 'a-new-name'}},
+ \ ale#rename#GetMap()
+
+Given python(Some Python file):
+ foo
+ somelongerline
+ bazxyzxyzxyz
+
+Execute(Code actions from LSP should be handled):
+ call ale#rename#HandleLSPResponse(1, {
+ \ 'id': 3,
+ \ 'result': {
+ \ 'changes': {
+ \ 'file:///foo/bar/file1.ts': [
+ \ {
+ \ 'range': {
+ \ 'start': {
+ \ 'line': 1,
+ \ 'character': 2,
+ \ },
+ \ 'end': {
+ \ 'line': 3,
+ \ 'character': 4,
+ \ },
+ \ },
+ \ 'newText': 'bla123'
+ \ },
+ \ ],
+ \ },
+ \ },
+ \})
+
+ AssertEqual
+ \ [
+ \ {
+ \ 'description': 'rename',
+ \ 'changes': [
+ \ {
+ \ 'fileName': '/foo/bar/file1.ts',
+ \ 'textChanges': [
+ \ {
+ \ 'start': {
+ \ 'line': 2,
+ \ 'offset': 3,
+ \ },
+ \ 'end': {
+ \ 'line': 4,
+ \ 'offset': 5,
+ \ },
+ \ 'newText': 'bla123',
+ \ },
+ \ ],
+ \ },
+ \ ],
+ \ }
+ \ ],
+ \ g:code_actions
+
+Execute(LSP should perform no action when no result):
+ call ale#rename#HandleLSPResponse(1, {
+ \ 'id': 3,
+ \})
+
+ AssertEqual g:handle_code_action_called, 0
+ AssertEqual ['echom ''No rename result received from server'''], g:expr_list
+
+Execute(LSP should perform no action when no changes):
+ call ale#rename#HandleLSPResponse(1, {
+ \ 'id': 3,
+ \ 'result': {},
+ \})
+
+ AssertEqual g:handle_code_action_called, 0
+ AssertEqual ['echom ''No changes received from server'''], g:expr_list
+
+Execute(LSP should perform no action when changes is empty):
+ call ale#rename#HandleLSPResponse(1, {
+ \ 'id': 3,
+ \ 'result': {
+ \ 'changes': [],
+ \ },
+ \})
+
+ AssertEqual g:handle_code_action_called, 0
+ AssertEqual ['echom ''No changes received from server'''], g:expr_list
+
+Execute(LSP rename requests should be sent):
+ call ale#rename#SetMap({})
+ runtime ale_linters/python/pyls.vim
+ let b:ale_linters = ['pyls']
+ call setpos('.', [bufnr(''), 1, 5, 0])
+
+ ALERename
+
+ " We shouldn't register the callback yet.
+ AssertEqual '''''', string(g:Callback)
+
+ AssertEqual type(function('type')), type(g:InitCallback)
+ call g:InitCallback()
+
+ AssertEqual 'rename', g:capability_checked
+ AssertEqual
+ \ 'function(''ale#rename#HandleLSPResponse'')',
+ \ string(g:Callback)
+
+ AssertEqual
+ \ [
+ \ [1, 'textDocument/didChange', {
+ \ 'textDocument': {
+ \ 'uri': ale#path#ToURI(expand('%:p')),
+ \ 'version': g:ale_lsp_next_version_id - 1,
+ \ },
+ \ 'contentChanges': [{'text': join(getline(1, '$'), "\n") . "\n"}]
+ \ }],
+ \ [0, 'textDocument/rename', {
+ \ 'textDocument': {'uri': ale#path#ToURI(expand('%:p'))},
+ \ 'position': {'line': 0, 'character': 2},
+ \ 'newName': 'a-new-name',
+ \ }],
+ \ ],
+ \ g:message_list
+
+ AssertEqual {'42': {'old_name': 'foo', 'new_name': 'a-new-name'}},
+ \ ale#rename#GetMap()