657 lines
15 KiB
Plaintext
657 lines
15 KiB
Plaintext
Before:
|
|
Save g:ale_fixers
|
|
Save &shell
|
|
Save g:ale_enabled
|
|
Save g:ale_fix_on_save
|
|
Save g:ale_lint_on_save
|
|
Save g:ale_echo_cursor
|
|
|
|
silent! cd /testplugin/test/fix
|
|
|
|
let g:ale_enabled = 0
|
|
let g:ale_echo_cursor = 0
|
|
let g:ale_run_synchronously = 1
|
|
let g:ale_set_lists_synchronously = 1
|
|
let g:ale_fix_buffer_data = {}
|
|
let g:ale_fixers = {
|
|
\ 'testft': [],
|
|
\}
|
|
|
|
if !has('win32')
|
|
let &shell = '/bin/bash'
|
|
endif
|
|
|
|
call ale#test#SetDirectory('/testplugin/test')
|
|
call ale#test#SetFilename('test.txt')
|
|
|
|
function AddCarets(buffer, lines) abort
|
|
" map() is applied to the original lines here.
|
|
" This way, we can ensure that defensive copies are made.
|
|
return map(a:lines, '''^'' . v:val')
|
|
endfunction
|
|
|
|
function AddDollars(buffer, lines) abort
|
|
return map(a:lines, '''$'' . v:val')
|
|
endfunction
|
|
|
|
function DoNothing(buffer, lines) abort
|
|
return 0
|
|
endfunction
|
|
|
|
function CatLine(buffer, lines) abort
|
|
return {'command': 'cat - <(echo d)'}
|
|
endfunction
|
|
|
|
function CatLineOneArg(buffer) abort
|
|
return {'command': 'cat - <(echo d)'}
|
|
endfunction
|
|
|
|
function ReplaceWithTempFile(buffer, lines) abort
|
|
return {'command': 'echo x > %t', 'read_temporary_file': 1}
|
|
endfunction
|
|
|
|
function RemoveLastLine(buffer, lines) abort
|
|
return ['a', 'b']
|
|
endfunction
|
|
|
|
function RemoveLastLineOneArg(buffer) abort
|
|
return ['a', 'b']
|
|
endfunction
|
|
|
|
function! TestCallback(buffer, output)
|
|
return [{'lnum': 1, 'col': 1, 'text': 'xxx'}]
|
|
endfunction
|
|
|
|
function! FirstChainCallback(buffer)
|
|
return {'command': 'echo echoline', 'chain_with': 'SecondChainCallback'}
|
|
endfunction
|
|
|
|
function! FirstChainCallbackSkipped(buffer)
|
|
let l:ChainWith = 'SecondChainCallback'
|
|
|
|
" Test with lambdas where support is available.
|
|
if has('lambda')
|
|
let l:ChainWith = {buffer, output -> SecondChainCallback(buffer, output)}
|
|
endif
|
|
|
|
return {'command': '', 'chain_with': l:ChainWith}
|
|
endfunction
|
|
|
|
function! FirstChainCallbackSecondSkipped(buffer)
|
|
return {'command': 'echo skipit', 'chain_with': 'SecondChainCallback'}
|
|
endfunction
|
|
|
|
function! SecondChainCallback(buffer, output)
|
|
let l:previous_line = empty(a:output)
|
|
\ ? 'emptydefault'
|
|
\ : join(split(a:output[0]))
|
|
|
|
if l:previous_line is# 'skipit'
|
|
return {'command': '', 'chain_with': 'ThirdChainCallback'}
|
|
endif
|
|
|
|
return {
|
|
\ 'command': 'echo ' . l:previous_line,
|
|
\ 'chain_with': 'ThirdChainCallback',
|
|
\}
|
|
endfunction
|
|
|
|
function! ThirdChainCallback(buffer, output, input)
|
|
let l:previous_line = empty(a:output)
|
|
\ ? 'thirddefault'
|
|
\ : join(split(a:output[0]))
|
|
|
|
return a:input + [l:previous_line]
|
|
endfunction
|
|
|
|
function! ChainWhereLastIsSkipped(buffer)
|
|
return {'command': 'echo echoline', 'chain_with': 'ChainEndSkipped'}
|
|
endfunction
|
|
|
|
function! ChainEndSkipped(buffer, output)
|
|
return {'command': ''}
|
|
endfunction
|
|
|
|
" echo will output a single blank line, and we should ingore it.
|
|
function! IgnoredEmptyOutput(buffer, output)
|
|
return {'command': has('win32') ? 'echo(' : 'echo'}
|
|
endfunction
|
|
|
|
function! EchoLineNoPipe(buffer, output)
|
|
return {'command': 'echo new line', 'read_buffer': 0}
|
|
endfunction
|
|
|
|
function! SetUpLinters()
|
|
call ale#linter#Define('testft', {
|
|
\ 'name': 'testlinter',
|
|
\ 'callback': 'TestCallback',
|
|
\ 'executable': 'true',
|
|
\ 'command': 'true',
|
|
\})
|
|
endfunction
|
|
|
|
function GetLastMessage()
|
|
redir => l:output
|
|
silent mess
|
|
redir END
|
|
|
|
let l:lines = split(l:output, "\n")
|
|
|
|
return empty(l:lines) ? '' : l:lines[-1]
|
|
endfunction
|
|
|
|
function! FixWithJSONPostProcessing(buffer) abort
|
|
let l:ProcessWith = 'JSONPostProcessor'
|
|
|
|
" Test with lambdas where support is available.
|
|
if has('lambda')
|
|
let l:ProcessWith = {buffer, output -> JSONPostProcessor(buffer, output)}
|
|
endif
|
|
|
|
" Escaping needs to be handled specially for CMD on Windows.
|
|
let l:json_string = has('win32')
|
|
\ ? '{"output":["x","y","z"]}'
|
|
\ : ale#Escape('{"output": ["x", "y", "z"]}')
|
|
|
|
return {
|
|
\ 'command': 'echo ' . l:json_string,
|
|
\ 'read_buffer': 0,
|
|
\ 'process_with': l:ProcessWith,
|
|
\}
|
|
endfunction
|
|
|
|
function! JSONPostProcessor(buffer, output) abort
|
|
return json_decode(a:output[0]).output
|
|
endfunction
|
|
|
|
After:
|
|
Restore
|
|
unlet! g:ale_run_synchronously
|
|
unlet! g:ale_set_lists_synchronously
|
|
unlet! g:ale_emulate_job_failure
|
|
unlet! b:ale_fixers
|
|
unlet! b:ale_fix_on_save
|
|
delfunction AddCarets
|
|
delfunction AddDollars
|
|
delfunction DoNothing
|
|
delfunction CatLine
|
|
delfunction CatLineOneArg
|
|
delfunction ReplaceWithTempFile
|
|
delfunction RemoveLastLine
|
|
delfunction RemoveLastLineOneArg
|
|
delfunction TestCallback
|
|
delfunction FirstChainCallback
|
|
delfunction FirstChainCallbackSkipped
|
|
delfunction FirstChainCallbackSecondSkipped
|
|
delfunction SecondChainCallback
|
|
delfunction ThirdChainCallback
|
|
delfunction ChainWhereLastIsSkipped
|
|
delfunction ChainEndSkipped
|
|
delfunction SetUpLinters
|
|
delfunction GetLastMessage
|
|
delfunction IgnoredEmptyOutput
|
|
delfunction EchoLineNoPipe
|
|
delfunction FixWithJSONPostProcessing
|
|
delfunction JSONPostProcessor
|
|
|
|
call ale#test#RestoreDirectory()
|
|
|
|
call ale#fix#registry#ResetToDefaults()
|
|
call ale#linter#Reset()
|
|
|
|
setlocal buftype=nofile
|
|
|
|
if filereadable('fix_test_file')
|
|
call delete('fix_test_file')
|
|
endif
|
|
|
|
call setloclist(0, [])
|
|
|
|
let g:ale_fix_buffer_data = {}
|
|
|
|
" Clear the messages between tests.
|
|
echomsg ''
|
|
|
|
Given testft (A file with three lines):
|
|
a
|
|
b
|
|
c
|
|
|
|
Execute(ALEFix should complain when there are no functions to call):
|
|
ALEFix
|
|
AssertEqual 'No fixers have been defined. Try :ALEFixSuggest', GetLastMessage()
|
|
|
|
Execute(ALEFix should apply simple functions):
|
|
let g:ale_fixers.testft = ['AddCarets']
|
|
ALEFix
|
|
|
|
Expect(The first function should be used):
|
|
^a
|
|
^b
|
|
^c
|
|
|
|
Execute(ALEFix should apply simple functions in a chain):
|
|
let g:ale_fixers.testft = ['AddCarets', 'AddDollars']
|
|
ALEFix
|
|
|
|
Expect(Both functions should be used):
|
|
$^a
|
|
$^b
|
|
$^c
|
|
|
|
Execute(ALEFix should allow 0 to be returned to skip functions):
|
|
let g:ale_fixers.testft = ['DoNothing', 'AddDollars']
|
|
ALEFix
|
|
|
|
Expect(Only the second function should be applied):
|
|
$a
|
|
$b
|
|
$c
|
|
|
|
Execute(ALEFix should allow commands to be run):
|
|
if has('win32')
|
|
" Just skip this test on Windows, we can't run it.
|
|
call setline(1, ['a', 'b', 'c', 'd'])
|
|
else
|
|
let g:ale_fixers.testft = ['CatLine']
|
|
ALEFix
|
|
endif
|
|
|
|
Expect(An extra line should be added):
|
|
a
|
|
b
|
|
c
|
|
d
|
|
|
|
Execute(ALEFix should allow temporary files to be read):
|
|
if has('win32')
|
|
" Just skip this test on Windows, we can't run it.
|
|
call setline(1, ['x'])
|
|
2,3d
|
|
else
|
|
let g:ale_fixers.testft = ['ReplaceWithTempFile']
|
|
ALEFix
|
|
endif
|
|
|
|
Expect(The line we wrote to the temporary file should be used here):
|
|
x
|
|
|
|
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'])
|
|
2,3d
|
|
else
|
|
let g:ale_fixers.testft = ['ReplaceWithTempFile', 'AddDollars']
|
|
ALEFix
|
|
endif
|
|
|
|
Expect(The lines from the temporary file should be modified):
|
|
$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'])
|
|
else
|
|
let g:ale_fixers.testft = ['AddDollars', 'CatLine']
|
|
ALEFix
|
|
endif
|
|
|
|
Expect(The lines should first be modified by the function, then the job):
|
|
$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']
|
|
ALEFix
|
|
|
|
Expect(Only the second function should be applied):
|
|
$a
|
|
$b
|
|
$c
|
|
|
|
Execute(ALEFix should handle strings for selecting a single function):
|
|
let g:ale_fixers.testft = 'AddCarets'
|
|
ALEFix
|
|
|
|
Expect(The first function should be used):
|
|
^a
|
|
^b
|
|
^c
|
|
|
|
Execute(ALEFix should use functions from the registry):
|
|
call ale#fix#registry#Add('add_carets', 'AddCarets', [], 'Add some carets')
|
|
let g:ale_fixers.testft = ['add_carets']
|
|
ALEFix
|
|
|
|
Expect(The registry function should be used):
|
|
^a
|
|
^b
|
|
^c
|
|
|
|
Execute(ALEFix should be able to remove the last line for files):
|
|
let g:ale_fixers.testft = ['RemoveLastLine']
|
|
ALEFix
|
|
|
|
Expect(There should be only two lines):
|
|
a
|
|
b
|
|
|
|
Execute(ALEFix should accept funcrefs):
|
|
let g:ale_fixers.testft = [function('RemoveLastLine')]
|
|
ALEFix
|
|
|
|
Expect(There should be only two lines):
|
|
a
|
|
b
|
|
|
|
Execute(ALEFix should accept lambdas):
|
|
if has('nvim')
|
|
" NeoVim 0.1.7 can't interpret lambdas correctly, so just set the lines
|
|
" to make the test pass.
|
|
call setline(1, ['a', 'b', 'c', 'd'])
|
|
else
|
|
let g:ale_fixers.testft = [{buffer, lines -> lines + ['d']}]
|
|
ALEFix
|
|
endif
|
|
|
|
Expect(There should be an extra line):
|
|
a
|
|
b
|
|
c
|
|
d
|
|
|
|
Execute(ALEFix should user buffer-local fixer settings):
|
|
let g:ale_fixers.testft = ['AddCarets', 'AddDollars']
|
|
let b:ale_fixers = {'testft': ['RemoveLastLine']}
|
|
ALEFix
|
|
|
|
Expect(There should be only two lines):
|
|
a
|
|
b
|
|
|
|
Execute(ALEFix should allow Lists to be used for buffer-local fixer settings):
|
|
let g:ale_fixers.testft = ['AddCarets', 'AddDollars']
|
|
let b:ale_fixers = ['RemoveLastLine']
|
|
ALEFix
|
|
|
|
Expect(There should be only two lines):
|
|
a
|
|
b
|
|
|
|
Given testft (A file with three lines):
|
|
a
|
|
b
|
|
c
|
|
|
|
Execute(ALEFix should save files on the save event):
|
|
let g:ale_fix_on_save = 1
|
|
let g:ale_lint_on_save = 1
|
|
let g:ale_enabled = 1
|
|
|
|
noautocmd silent file fix_test_file
|
|
call writefile(getline(1, '$'), 'fix_test_file')
|
|
|
|
let g:ale_fixers.testft = ['AddDollars']
|
|
|
|
" We have to set the buftype to empty so the file will be written.
|
|
setlocal buftype=
|
|
|
|
call SetUpLinters()
|
|
call ale#events#SaveEvent(bufnr(''))
|
|
|
|
" We should save the file.
|
|
AssertEqual ['$a', '$b', '$c'], readfile('fix_test_file')
|
|
Assert !&modified, 'The was marked as ''modified'''
|
|
|
|
if !has('win32')
|
|
" We should have run the linter.
|
|
AssertEqual [{
|
|
\ 'bufnr': bufnr('%'),
|
|
\ 'lnum': 1,
|
|
\ 'vcol': 0,
|
|
\ 'col': 1,
|
|
\ 'text': 'xxx',
|
|
\ 'type': 'E',
|
|
\ 'nr': -1,
|
|
\ 'pattern': '',
|
|
\ 'valid': 1,
|
|
\}], getloclist(0)
|
|
endif
|
|
|
|
Expect(The buffer should be modified):
|
|
$a
|
|
$b
|
|
$c
|
|
|
|
Given testft (A file with three lines):
|
|
a
|
|
b
|
|
c
|
|
|
|
Execute(ALEFix should still lint with no linters to be applied):
|
|
let g:ale_fix_on_save = 1
|
|
let g:ale_lint_on_save = 1
|
|
let g:ale_enabled = 1
|
|
|
|
noautocmd silent file fix_test_file
|
|
|
|
let g:ale_fixers.testft = []
|
|
|
|
call SetUpLinters()
|
|
call ale#events#SaveEvent(bufnr(''))
|
|
|
|
Assert !filereadable('fix_test_file'), 'The file should not have been saved'
|
|
|
|
if !has('win32')
|
|
" We have run the linter.
|
|
AssertEqual [{
|
|
\ 'bufnr': bufnr('%'),
|
|
\ 'lnum': 1,
|
|
\ 'vcol': 0,
|
|
\ 'col': 1,
|
|
\ 'text': 'xxx',
|
|
\ 'type': 'E',
|
|
\ 'nr': -1,
|
|
\ 'pattern': '',
|
|
\ 'valid': 1,
|
|
\}], getloclist(0)
|
|
endif
|
|
|
|
Expect(The buffer should be the same):
|
|
a
|
|
b
|
|
c
|
|
|
|
Execute(ALEFix should still lint when nothing was fixed on save):
|
|
let g:ale_fix_on_save = 1
|
|
let g:ale_lint_on_save = 1
|
|
let g:ale_enabled = 1
|
|
|
|
noautocmd silent file fix_test_file
|
|
|
|
let g:ale_fixers.testft = ['DoNothing']
|
|
|
|
call SetUpLinters()
|
|
call ale#events#SaveEvent(bufnr(''))
|
|
|
|
Assert !filereadable('fix_test_file'), 'The file should not have been saved'
|
|
|
|
if !has('win32')
|
|
" We should have run the linter.
|
|
AssertEqual [{
|
|
\ 'bufnr': bufnr('%'),
|
|
\ 'lnum': 1,
|
|
\ 'vcol': 0,
|
|
\ 'col': 1,
|
|
\ 'text': 'xxx',
|
|
\ 'type': 'E',
|
|
\ 'nr': -1,
|
|
\ 'pattern': '',
|
|
\ 'valid': 1,
|
|
\}], getloclist(0)
|
|
endif
|
|
|
|
Expect(The buffer should be the same):
|
|
a
|
|
b
|
|
c
|
|
|
|
Given testft (A file with three lines):
|
|
a
|
|
b
|
|
c
|
|
|
|
Execute(ale#fix#InitBufferData() should set up the correct data):
|
|
noautocmd silent file fix_test_file
|
|
|
|
call ale#fix#InitBufferData(bufnr(''), 'save_file')
|
|
|
|
AssertEqual {
|
|
\ bufnr(''): {
|
|
\ 'temporary_directory_list': [],
|
|
\ 'vars': b:,
|
|
\ 'filename': ale#path#Simplify(getcwd() . '/fix_test_file'),
|
|
\ 'done': 0,
|
|
\ 'lines_before': ['a', 'b', 'c'],
|
|
\ 'should_save': 1,
|
|
\ },
|
|
\}, g:ale_fix_buffer_data
|
|
|
|
Execute(ALEFix simple functions should be able to accept one argument, the buffer):
|
|
let g:ale_fixers.testft = ['RemoveLastLineOneArg']
|
|
ALEFix
|
|
|
|
Expect(There should be only two lines):
|
|
a
|
|
b
|
|
|
|
Execute(b:ale_fix_on_save = 1 should override g:ale_fix_on_save = 0):
|
|
let g:ale_fix_on_save = 0
|
|
let b:ale_fix_on_save = 1
|
|
|
|
let g:ale_fixers.testft = ['RemoveLastLineOneArg']
|
|
call ale#events#SaveEvent(bufnr(''))
|
|
|
|
Expect(There should be only two lines):
|
|
a
|
|
b
|
|
|
|
Execute(b:ale_fix_on_save = 0 should override g:ale_fix_on_save = 1):
|
|
let g:ale_fix_on_save = 1
|
|
let b:ale_fix_on_save = 0
|
|
|
|
let g:ale_fixers.testft = ['RemoveLastLineOneArg']
|
|
call ale#events#SaveEvent(bufnr(''))
|
|
|
|
Expect(The lines should be the same):
|
|
a
|
|
b
|
|
c
|
|
|
|
Execute(ALEFix functions returning jobs should be able to accept one argument):
|
|
if has('win32')
|
|
" Just skip this test on Windows, we can't run it.
|
|
call setline(1, ['a', 'b', 'c', 'd'])
|
|
else
|
|
let g:ale_fixers.testft = ['CatLine']
|
|
ALEFix
|
|
endif
|
|
|
|
Expect(An extra line should be added):
|
|
a
|
|
b
|
|
c
|
|
d
|
|
|
|
Execute(ALE should print a message telling you something isn't a valid fixer when you type some nonsense):
|
|
let g:ale_fixers.testft = ['CatLine', 'invalidname']
|
|
ALEFix
|
|
|
|
AssertEqual 'There is no fixer named `invalidname`. Check :ALEFixSuggest', GetLastMessage()
|
|
|
|
Execute(Test fixing with chained callbacks):
|
|
let g:ale_fixers.testft = ['FirstChainCallback']
|
|
ALEFix
|
|
|
|
" The buffer shouldn't be piped in for earlier commands in the chain.
|
|
AssertEqual
|
|
\ [
|
|
\ string(ale#job#PrepareCommand(bufnr(''), 'echo echoline')),
|
|
\ string(ale#job#PrepareCommand(bufnr(''), 'echo echoline')),
|
|
\ ],
|
|
\ map(ale#history#Get(bufnr(''))[-2:-1], 'string(v:val.command)')
|
|
|
|
Expect(The echoed line should be added):
|
|
a
|
|
b
|
|
c
|
|
echoline
|
|
|
|
Execute(Test fixing with chained callback where the first command is skipped):
|
|
let g:ale_fixers.testft = ['FirstChainCallbackSkipped']
|
|
ALEFix
|
|
|
|
Expect(The default line should be added):
|
|
a
|
|
b
|
|
c
|
|
emptydefault
|
|
|
|
Execute(Test fixing with chained callback where the second command is skipped):
|
|
let g:ale_fixers.testft = ['FirstChainCallbackSecondSkipped']
|
|
ALEFix
|
|
|
|
Expect(The default line should be added):
|
|
a
|
|
b
|
|
c
|
|
thirddefault
|
|
|
|
Execute(Test fixing with chained callback where the final callback is skipped):
|
|
let g:ale_fixers.testft = ['ChainWhereLastIsSkipped']
|
|
ALEFix
|
|
|
|
Expect(The lines should be the same):
|
|
a
|
|
b
|
|
c
|
|
|
|
Execute(Empty output should be ignored):
|
|
let g:ale_fixers.testft = ['IgnoredEmptyOutput']
|
|
ALEFix
|
|
|
|
Expect(The lines should be the same):
|
|
a
|
|
b
|
|
c
|
|
|
|
Execute(A temporary file shouldn't be piped into the command when disabled):
|
|
let g:ale_fixers.testft = ['EchoLineNoPipe']
|
|
ALEFix
|
|
|
|
AssertEqual
|
|
\ string(ale#job#PrepareCommand(bufnr(''), 'echo new line')),
|
|
\ string(ale#history#Get(bufnr(''))[-1].command)
|
|
|
|
" Remove trailing whitespace for Windows.
|
|
if has('win32')
|
|
%s/[[:space:]]*$//g
|
|
endif
|
|
|
|
Expect(The new line should be used):
|
|
new line
|
|
|
|
Execute(Post-processing should work):
|
|
let g:ale_fixers.testft = ['FixWithJSONPostProcessing']
|
|
ALEFix
|
|
|
|
Expect(The lines in the JSON should be used):
|
|
x
|
|
y
|
|
z
|