From 3bebcb5d48a7150f5a318952ee309acb67fb376d Mon Sep 17 00:00:00 2001 From: w0rp Date: Sun, 7 Apr 2019 14:58:06 +0100 Subject: [PATCH] #2132 - Replace command_chain and chain_with with ale#command#Run --- ale_linters/c/clang.vim | 5 +- ale_linters/c/gcc.vim | 5 +- ale_linters/cpp/clang.vim | 5 +- ale_linters/cpp/gcc.vim | 5 +- ale_linters/d/dmd.vim | 21 ++- ale_linters/erlang/syntaxerl.vim | 17 +- ale_linters/eruby/erubi.vim | 17 +- ale_linters/java/javac.vim | 30 ++-- ale_linters/javascript/flow.vim | 36 +--- ale_linters/kotlin/kotlinc.vim | 49 ++--- ale_linters/php/phpstan.vim | 37 +--- ale_linters/python/flake8.vim | 28 ++- ale_linters/ruby/reek.vim | 29 +-- ale_linters/rust/cargo.vim | 28 ++- ale_linters/sh/shellcheck.vim | 34 ++-- ale_linters/vim/vint.vim | 36 ++-- autoload/ale/assert.vim | 170 +++++++++++++----- autoload/ale/c.vim | 14 ++ autoload/ale/command.vim | 52 ++++-- autoload/ale/d.vim | 4 + autoload/ale/fixers/eslint.vim | 24 ++- autoload/ale/fixers/prettier.vim | 23 +-- autoload/ale/fixers/prettier_eslint.vim | 34 ++-- autoload/ale/node.vim | 2 +- autoload/ale/semver.vim | 49 +++-- doc/ale-development.txt | 48 ++++- .../test_c_clang_command_callbacks.vader | 4 +- .../test_c_gcc_command_callbacks.vader | 4 +- .../test_cargo_command_callbacks.vader | 106 ++++++----- ...st_erlang_syntaxerl_command_callback.vader | 4 +- .../test_erubi_command_callback.vader | 2 +- .../test_flake8_command_callback.vader | 19 +- .../test_gobuild_command_callback.vader | 2 +- .../test_javac_command_callback.vader | 42 +++-- .../test_phpstan_command_callbacks.vader | 4 +- .../test_reek_command_callback.vader | 13 +- .../test_shellcheck_command_callback.vader | 10 +- test/fix/test_ale_fix.vader | 1 - test/fixers/test_eslint_fixer_callback.vader | 112 +++++------- .../test_prettier_eslint_fixer.callback.vader | 87 ++++----- .../fixers/test_prettier_fixer_callback.vader | 148 +++++++-------- test/lsp/test_lsp_startup.vader | 2 + test/sign/test_linting_sets_signs.vader | 2 + test/sign/test_sign_placement.vader | 1 + test/test_deferred_command_string.vader | 4 + test/test_eslint_executable_detection.vader | 18 +- test/test_flow_command.vader | 32 ++-- test/test_semver_utils.vader | 26 +-- 48 files changed, 751 insertions(+), 694 deletions(-) diff --git a/ale_linters/c/clang.vim b/ale_linters/c/clang.vim index 5b243bfe..681101fc 100644 --- a/ale_linters/c/clang.vim +++ b/ale_linters/c/clang.vim @@ -19,9 +19,6 @@ call ale#linter#Define('c', { \ 'name': 'clang', \ 'output_stream': 'stderr', \ 'executable': {b -> ale#Var(b, 'c_clang_executable')}, -\ 'command_chain': [ -\ {'callback': 'ale#c#GetMakeCommand', 'output_stream': 'stdout'}, -\ {'callback': 'ale_linters#c#clang#GetCommand'} -\ ], +\ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#c#clang#GetCommand'))}, \ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes', \}) diff --git a/ale_linters/c/gcc.vim b/ale_linters/c/gcc.vim index ccb1912b..d965965d 100644 --- a/ale_linters/c/gcc.vim +++ b/ale_linters/c/gcc.vim @@ -19,9 +19,6 @@ call ale#linter#Define('c', { \ 'name': 'gcc', \ 'output_stream': 'stderr', \ 'executable': {b -> ale#Var(b, 'c_gcc_executable')}, -\ 'command_chain': [ -\ {'callback': 'ale#c#GetMakeCommand', 'output_stream': 'stdout'}, -\ {'callback': 'ale_linters#c#gcc#GetCommand'} -\ ], +\ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#c#gcc#GetCommand'))}, \ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes', \}) diff --git a/ale_linters/cpp/clang.vim b/ale_linters/cpp/clang.vim index 5a465812..e48291eb 100644 --- a/ale_linters/cpp/clang.vim +++ b/ale_linters/cpp/clang.vim @@ -19,9 +19,6 @@ call ale#linter#Define('cpp', { \ 'name': 'clang', \ 'output_stream': 'stderr', \ 'executable': {b -> ale#Var(b, 'cpp_clang_executable')}, -\ 'command_chain': [ -\ {'callback': 'ale#c#GetMakeCommand', 'output_stream': 'stdout'}, -\ {'callback': 'ale_linters#cpp#clang#GetCommand'}, -\ ], +\ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#cpp#clang#GetCommand'))}, \ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes', \}) diff --git a/ale_linters/cpp/gcc.vim b/ale_linters/cpp/gcc.vim index 831620d5..c427020b 100644 --- a/ale_linters/cpp/gcc.vim +++ b/ale_linters/cpp/gcc.vim @@ -20,9 +20,6 @@ call ale#linter#Define('cpp', { \ 'aliases': ['g++'], \ 'output_stream': 'stderr', \ 'executable': {b -> ale#Var(b, 'cpp_gcc_executable')}, -\ 'command_chain': [ -\ {'callback': 'ale#c#GetMakeCommand', 'output_stream': 'stdout'}, -\ {'callback': 'ale_linters#cpp#gcc#GetCommand'}, -\ ], +\ 'command': {b -> ale#c#RunMakeCommand(b, function('ale_linters#cpp#gcc#GetCommand'))}, \ 'callback': 'ale#handlers#gcc#HandleGCCFormatWithIncludes', \}) diff --git a/ale_linters/d/dmd.vim b/ale_linters/d/dmd.vim index c816d592..14461ae6 100644 --- a/ale_linters/d/dmd.vim +++ b/ale_linters/d/dmd.vim @@ -1,7 +1,7 @@ " Author: w0rp " Description: "dmd for D files" -function! ale_linters#d#dmd#DUBCommand(buffer) abort +function! ale_linters#d#dmd#GetDUBCommand(buffer) abort " If we can't run dub, then skip this command. if !executable('dub') " Returning an empty string skips to the DMD command. @@ -21,7 +21,18 @@ function! ale_linters#d#dmd#DUBCommand(buffer) abort \ . ' && dub describe --import-paths' endfunction -function! ale_linters#d#dmd#DMDCommand(buffer, dub_output) abort +function! ale_linters#d#dmd#RunDUBCommand(buffer) abort + let l:command = ale_linters#d#dmd#GetDUBCommand(a:buffer) + + if empty(l:command) + " If we can't run DUB, just run DMD. + return ale_linters#d#dmd#DMDCommand(a:buffer, [], {}) + endif + + return ale#command#Run(a:buffer, l:command, function('ale_linters#d#dmd#DMDCommand')) +endfunction + +function! ale_linters#d#dmd#DMDCommand(buffer, dub_output, meta) abort let l:import_list = [] " Build a list of import paths generated from DUB, if available. @@ -57,9 +68,7 @@ endfunction call ale#linter#Define('d', { \ 'name': 'dmd', \ 'executable': 'dmd', -\ 'command_chain': [ -\ {'callback': 'ale_linters#d#dmd#DUBCommand', 'output_stream': 'stdout'}, -\ {'callback': 'ale_linters#d#dmd#DMDCommand', 'output_stream': 'stderr'}, -\ ], +\ 'command': function('ale_linters#d#dmd#RunDUBCommand'), \ 'callback': 'ale_linters#d#dmd#Handle', +\ 'output_stream': 'stderr', \}) diff --git a/ale_linters/erlang/syntaxerl.vim b/ale_linters/erlang/syntaxerl.vim index 2b7276a1..5d555a8d 100644 --- a/ale_linters/erlang/syntaxerl.vim +++ b/ale_linters/erlang/syntaxerl.vim @@ -3,7 +3,17 @@ call ale#Set('erlang_syntaxerl_executable', 'syntaxerl') -function! ale_linters#erlang#syntaxerl#GetCommand(buffer, output) abort +function! ale_linters#erlang#syntaxerl#RunHelpCommand(buffer) abort + let l:executable = ale#Var(a:buffer, 'erlang_syntaxerl_executable') + + return ale#command#Run( + \ a:buffer, + \ ale#Escape(l:executable) . ' -h', + \ function('ale_linters#erlang#syntaxerl#GetCommand'), + \) +endfunction + +function! ale_linters#erlang#syntaxerl#GetCommand(buffer, output, meta) abort let l:use_b_option = match(a:output, '\C\V-b, --base\>') > -1 return '%e' . (l:use_b_option ? ' -b %s %t' : ' %t') @@ -27,9 +37,6 @@ endfunction call ale#linter#Define('erlang', { \ 'name': 'syntaxerl', \ 'executable': {b -> ale#Var(b, 'erlang_syntaxerl_executable')}, -\ 'command_chain': [ -\ {'callback': {-> '%e -h'}}, -\ {'callback': 'ale_linters#erlang#syntaxerl#GetCommand'}, -\ ], +\ 'command': {b -> ale_linters#erlang#syntaxerl#RunHelpCommand(b)}, \ 'callback': 'ale_linters#erlang#syntaxerl#Handle', \}) diff --git a/ale_linters/eruby/erubi.vim b/ale_linters/eruby/erubi.vim index 6f2d3ac6..ddca3f61 100644 --- a/ale_linters/eruby/erubi.vim +++ b/ale_linters/eruby/erubi.vim @@ -1,14 +1,10 @@ " Author: Eddie Lebow https://github.com/elebow " Description: eruby checker using `erubi` -function! ale_linters#eruby#erubi#CheckErubi(buffer) abort - return 'ruby -r erubi/capture_end -e ' . ale#Escape('""') -endfunction - -function! ale_linters#eruby#erubi#GetCommand(buffer, check_erubi_output) abort +function! ale_linters#eruby#erubi#GetCommand(buffer, output, meta) abort let l:rails_root = ale#ruby#FindRailsRoot(a:buffer) - if (!empty(a:check_erubi_output)) + if !empty(a:output) " The empty command in CheckErubi returns nothing if erubi runs and " emits an error if erubi is not present return '' @@ -27,9 +23,10 @@ endfunction call ale#linter#Define('eruby', { \ 'name': 'erubi', \ 'executable': 'ruby', -\ 'command_chain': [ -\ {'callback': 'ale_linters#eruby#erubi#CheckErubi'}, -\ {'callback': 'ale_linters#eruby#erubi#GetCommand', 'output_stream': 'stderr'}, -\ ], +\ 'command': {buffer -> ale#command#Run( +\ buffer, +\ 'ruby -r erubi/capture_end -e ' . ale#Escape('""'), +\ function('ale_linters#eruby#erubi#GetCommand'), +\ )}, \ 'callback': 'ale#handlers#ruby#HandleSyntaxErrors', \}) diff --git a/ale_linters/java/javac.vim b/ale_linters/java/javac.vim index 50cabacd..7ca95ba5 100644 --- a/ale_linters/java/javac.vim +++ b/ale_linters/java/javac.vim @@ -7,21 +7,29 @@ call ale#Set('java_javac_executable', 'javac') call ale#Set('java_javac_options', '') call ale#Set('java_javac_classpath', '') -function! ale_linters#java#javac#GetImportPaths(buffer) abort +function! ale_linters#java#javac#RunWithImportPaths(buffer) abort + let l:command = '' let l:pom_path = ale#path#FindNearestFile(a:buffer, 'pom.xml') if !empty(l:pom_path) && executable('mvn') - return ale#path#CdString(fnamemodify(l:pom_path, ':h')) + let l:command = ale#path#CdString(fnamemodify(l:pom_path, ':h')) \ . 'mvn dependency:build-classpath' endif - let l:classpath_command = ale#gradle#BuildClasspathCommand(a:buffer) - - if !empty(l:classpath_command) - return l:classpath_command + " Try to use Gradle if Maven isn't available. + if empty(l:command) + let l:command = ale#gradle#BuildClasspathCommand(a:buffer) endif - return '' + if empty(l:command) + return ale_linters#java#javac#GetCommand(a:buffer, [], {}) + endif + + return ale#command#Run( + \ a:buffer, + \ l:command, + \ function('ale_linters#java#javac#GetCommand') + \) endfunction function! s:BuildClassPathOption(buffer, import_paths) abort @@ -37,7 +45,7 @@ function! s:BuildClassPathOption(buffer, import_paths) abort \ : '' endfunction -function! ale_linters#java#javac#GetCommand(buffer, import_paths) abort +function! ale_linters#java#javac#GetCommand(buffer, import_paths, meta) abort let l:cp_option = s:BuildClassPathOption(a:buffer, a:import_paths) let l:sp_option = '' @@ -120,9 +128,7 @@ endfunction call ale#linter#Define('java', { \ 'name': 'javac', \ 'executable': {b -> ale#Var(b, 'java_javac_executable')}, -\ 'command_chain': [ -\ {'callback': 'ale_linters#java#javac#GetImportPaths', 'output_stream': 'stdout'}, -\ {'callback': 'ale_linters#java#javac#GetCommand', 'output_stream': 'stderr'}, -\ ], +\ 'command': function('ale_linters#java#javac#RunWithImportPaths'), +\ 'output_stream': 'stderr', \ 'callback': 'ale_linters#java#javac#Handle', \}) diff --git a/ale_linters/javascript/flow.vim b/ale_linters/javascript/flow.vim index 05aae030..3135e2e9 100755 --- a/ale_linters/javascript/flow.vim +++ b/ale_linters/javascript/flow.vim @@ -27,32 +27,13 @@ function! ale_linters#javascript#flow#GetExecutable(buffer) abort \]) endfunction -function! ale_linters#javascript#flow#VersionCheck(buffer) abort - let l:executable = ale_linters#javascript#flow#GetExecutable(a:buffer) - - if empty(l:executable) - return '' - endif - - return ale#Escape(l:executable) . ' --version' -endfunction - -function! ale_linters#javascript#flow#GetCommand(buffer, version_lines) abort - let l:executable = ale_linters#javascript#flow#GetExecutable(a:buffer) - - if empty(l:executable) - return '' - endif - - let l:version = ale#semver#GetVersion(l:executable, a:version_lines) - +function! ale_linters#javascript#flow#GetCommand(buffer, version) abort " If we can parse the version number, then only use --respect-pragma " if the version is >= 0.36.0, which added the argument. let l:use_respect_pragma = ale#Var(a:buffer, 'javascript_flow_use_respect_pragma') - \ && (empty(l:version) || ale#semver#GTE(l:version, [0, 36])) + \ && (empty(a:version) || ale#semver#GTE(a:version, [0, 36])) - return ale#Escape(l:executable) - \ . ' check-contents' + return '%e check-contents' \ . (l:use_respect_pragma ? ' --respect-pragma': '') \ . ' --json --from ale %s < %t' \ . (!has('win32') ? '; echo' : '') @@ -87,7 +68,6 @@ function! s:ExtraErrorMsg(current, new) abort return l:newMsg endfunction - function! s:GetDetails(error) abort let l:detail = '' @@ -169,10 +149,12 @@ endfunction call ale#linter#Define('javascript', { \ 'name': 'flow', \ 'executable': function('ale_linters#javascript#flow#GetExecutable'), -\ 'command_chain': [ -\ {'callback': 'ale_linters#javascript#flow#VersionCheck'}, -\ {'callback': 'ale_linters#javascript#flow#GetCommand'}, -\ ], +\ 'command': {buffer -> ale#semver#RunWithVersionCheck( +\ buffer, +\ ale_linters#javascript#flow#GetExecutable(buffer), +\ '%e --version', +\ function('ale_linters#javascript#flow#GetCommand'), +\ )}, \ 'callback': 'ale_linters#javascript#flow#Handle', \ 'read_buffer': 0, \}) diff --git a/ale_linters/kotlin/kotlinc.vim b/ale_linters/kotlin/kotlinc.vim index 32dcc6d1..fddd6625 100644 --- a/ale_linters/kotlin/kotlinc.vim +++ b/ale_linters/kotlin/kotlinc.vim @@ -11,26 +11,33 @@ let g:ale_kotlin_kotlinc_module_filename = get(g:, 'ale_kotlin_kotlinc_module_fi let s:classpath_sep = has('unix') ? ':' : ';' -function! ale_linters#kotlin#kotlinc#GetImportPaths(buffer) abort +function! ale_linters#kotlin#kotlinc#RunWithImportPaths(buffer) abort " exec maven/gradle only if classpath is not set if ale#Var(a:buffer, 'kotlin_kotlinc_classpath') isnot# '' - return '' - else - let l:pom_path = ale#path#FindNearestFile(a:buffer, 'pom.xml') - - if !empty(l:pom_path) && executable('mvn') - return ale#path#CdString(fnamemodify(l:pom_path, ':h')) - \ . 'mvn dependency:build-classpath' - endif - - let l:classpath_command = ale#gradle#BuildClasspathCommand(a:buffer) - - if !empty(l:classpath_command) - return l:classpath_command - endif - - return '' + return ale_linters#kotlin#kotlinc#GetCommand(a:buffer, [], {}) endif + + let l:pom_path = ale#path#FindNearestFile(a:buffer, 'pom.xml') + + if !empty(l:pom_path) && executable('mvn') + let l:command = ale#path#CdString(fnamemodify(l:pom_path, ':h')) + \ . 'mvn dependency:build-classpath' + endif + + " Try to use Gradle if Maven isn't available. + if empty(l:command) + let l:command = ale#gradle#BuildClasspathCommand(a:buffer) + endif + + if empty(l:command) + return ale_linters#kotlin#kotlinc#GetCommand(a:buffer, [], {}) + endif + + return ale#command#Run( + \ a:buffer, + \ l:command, + \ function('ale_linters#kotlin#kotlinc#GetCommand') + \) endfunction function! s:BuildClassPathOption(buffer, import_paths) abort @@ -46,7 +53,7 @@ function! s:BuildClassPathOption(buffer, import_paths) abort \ : '' endfunction -function! ale_linters#kotlin#kotlinc#GetCommand(buffer, import_paths) abort +function! ale_linters#kotlin#kotlinc#GetCommand(buffer, import_paths, meta) abort let l:kotlinc_opts = ale#Var(a:buffer, 'kotlin_kotlinc_options') let l:command = 'kotlinc ' @@ -165,11 +172,7 @@ endfunction call ale#linter#Define('kotlin', { \ 'name': 'kotlinc', \ 'executable': 'kotlinc', -\ 'command_chain': [ -\ {'callback': 'ale_linters#kotlin#kotlinc#GetImportPaths', 'output_stream': 'stdout'}, -\ {'callback': 'ale_linters#kotlin#kotlinc#GetCommand', 'output_stream': 'stderr'}, -\ ], +\ 'command': function('ale_linters#kotlin#kotlinc#RunWithImportPaths'), \ 'callback': 'ale_linters#kotlin#kotlinc#Handle', \ 'lint_file': 1, \}) - diff --git a/ale_linters/php/phpstan.vim b/ale_linters/php/phpstan.vim index 34d4e799..ecd80a83 100644 --- a/ale_linters/php/phpstan.vim +++ b/ale_linters/php/phpstan.vim @@ -6,34 +6,13 @@ let g:ale_php_phpstan_executable = get(g:, 'ale_php_phpstan_executable', 'phpsta let g:ale_php_phpstan_level = get(g:, 'ale_php_phpstan_level', '4') let g:ale_php_phpstan_configuration = get(g:, 'ale_php_phpstan_configuration', '') -function! ale_linters#php#phpstan#GetExecutable(buffer) abort - return ale#Var(a:buffer, 'php_phpstan_executable') -endfunction - -function! ale_linters#php#phpstan#VersionCheck(buffer) abort - let l:executable = ale_linters#php#phpstan#GetExecutable(a:buffer) - - " If we have previously stored the version number in a cache, then - " don't look it up again. - if ale#semver#HasVersion(l:executable) - " Returning an empty string skips this command. - return '' - endif - - let l:executable = ale#Escape(l:executable) - - return l:executable . ' --version' -endfunction - -function! ale_linters#php#phpstan#GetCommand(buffer, version_output) abort +function! ale_linters#php#phpstan#GetCommand(buffer, version) abort let l:configuration = ale#Var(a:buffer, 'php_phpstan_configuration') let l:configuration_option = !empty(l:configuration) \ ? ' -c ' . l:configuration \ : '' - let l:executable = ale_linters#php#phpstan#GetExecutable(a:buffer) - let l:version = ale#semver#GetVersion(l:executable, a:version_output) - let l:error_format = ale#semver#GTE(l:version, [0, 10, 3]) + let l:error_format = ale#semver#GTE(a:version, [0, 10, 3]) \ ? ' --error-format raw' \ : ' --errorFormat raw' @@ -65,10 +44,12 @@ endfunction call ale#linter#Define('php', { \ 'name': 'phpstan', -\ 'executable': function('ale_linters#php#phpstan#GetExecutable'), -\ 'command_chain': [ -\ {'callback': 'ale_linters#php#phpstan#VersionCheck'}, -\ {'callback': 'ale_linters#php#phpstan#GetCommand'}, -\ ], +\ 'executable': {b -> ale#Var(b, 'php_phpstan_executable')}, +\ 'command': {buffer -> ale#semver#RunWithVersionCheck( +\ buffer, +\ ale#Var(buffer, 'php_phpstan_executable'), +\ '%e --version', +\ function('ale_linters#php#phpstan#GetCommand'), +\ )}, \ 'callback': 'ale_linters#php#phpstan#Handle', \}) diff --git a/ale_linters/python/flake8.vim b/ale_linters/python/flake8.vim index 993d7adb..e2e7b743 100644 --- a/ale_linters/python/flake8.vim +++ b/ale_linters/python/flake8.vim @@ -24,28 +24,25 @@ function! ale_linters#python#flake8#GetExecutable(buffer) abort return ale#Var(a:buffer, 'python_flake8_executable') endfunction -function! ale_linters#python#flake8#VersionCheck(buffer) abort +function! ale_linters#python#flake8#RunWithVersionCheck(buffer) abort let l:executable = ale_linters#python#flake8#GetExecutable(a:buffer) - " If we have previously stored the version number in a cache, then - " don't look it up again. - if ale#semver#HasVersion(l:executable) - " Returning an empty string skips this command. - return '' - endif - - let l:executable = ale#Escape(l:executable) let l:module_string = s:UsingModule(a:buffer) ? ' -m flake8' : '' + let l:command = ale#Escape(l:executable) . l:module_string . ' --version' - return l:executable . l:module_string . ' --version' + return ale#semver#RunWithVersionCheck( + \ a:buffer, + \ l:executable, + \ l:command, + \ function('ale_linters#python#flake8#GetCommand'), + \) endfunction -function! ale_linters#python#flake8#GetCommand(buffer, version_output) abort +function! ale_linters#python#flake8#GetCommand(buffer, version) abort let l:cd_string = ale#Var(a:buffer, 'python_flake8_change_directory') \ ? ale#path#BufferCdString(a:buffer) \ : '' let l:executable = ale_linters#python#flake8#GetExecutable(a:buffer) - let l:version = ale#semver#GetVersion(l:executable, a:version_output) let l:exec_args = l:executable =~? 'pipenv$' \ ? ' run flake8' @@ -53,7 +50,7 @@ function! ale_linters#python#flake8#GetCommand(buffer, version_output) abort " Only include the --stdin-display-name argument if we can parse the " flake8 version, and it is recent enough to support it. - let l:display_name_args = ale#semver#GTE(l:version, [3, 0, 0]) + let l:display_name_args = ale#semver#GTE(a:version, [3, 0, 0]) \ ? ' --stdin-display-name %s' \ : '' @@ -144,9 +141,6 @@ endfunction call ale#linter#Define('python', { \ 'name': 'flake8', \ 'executable': function('ale_linters#python#flake8#GetExecutable'), -\ 'command_chain': [ -\ {'callback': 'ale_linters#python#flake8#VersionCheck'}, -\ {'callback': 'ale_linters#python#flake8#GetCommand', 'output_stream': 'both'}, -\ ], +\ 'command': function('ale_linters#python#flake8#RunWithVersionCheck'), \ 'callback': 'ale_linters#python#flake8#Handle', \}) diff --git a/ale_linters/ruby/reek.vim b/ale_linters/ruby/reek.vim index 26f6e36c..e39e366f 100644 --- a/ale_linters/ruby/reek.vim +++ b/ale_linters/ruby/reek.vim @@ -6,26 +6,11 @@ call ale#Set('ruby_reek_show_wiki_link', 0) call ale#Set('ruby_reek_options', '') call ale#Set('ruby_reek_executable', 'reek') -function! ale_linters#ruby#reek#VersionCheck(buffer) abort - " If we have previously stored the version number in a cache, then - " don't look it up again. - if ale#semver#HasVersion('reek') - " Returning an empty string skips this command. - return '' - endif - - let l:executable = ale#Var(a:buffer, 'ruby_reek_executable') - - return ale#handlers#ruby#EscapeExecutable(l:executable, 'reek') - \ . ' --version' -endfunction - -function! ale_linters#ruby#reek#GetCommand(buffer, version_output) abort - let l:version = ale#semver#GetVersion('reek', a:version_output) +function! ale_linters#ruby#reek#GetCommand(buffer, version) abort let l:executable = ale#Var(a:buffer, 'ruby_reek_executable') " Tell reek what the filename is if the version of reek is new enough. - let l:display_name_args = ale#semver#GTE(l:version, [5, 0, 0]) + let l:display_name_args = ale#semver#GTE(a:version, [5, 0, 0]) \ ? ' --stdin-filename %s' \ : '' @@ -70,9 +55,11 @@ endfunction call ale#linter#Define('ruby', { \ 'name': 'reek', \ 'executable': {b -> ale#Var(b, 'ruby_reek_executable')}, -\ 'command_chain': [ -\ {'callback': 'ale_linters#ruby#reek#VersionCheck'}, -\ {'callback': 'ale_linters#ruby#reek#GetCommand'}, -\ ], +\ 'command': {buffer -> ale#semver#RunWithVersionCheck( +\ buffer, +\ ale#Var(buffer, 'ruby_reek_executable'), +\ '%e --version', +\ function('ale_linters#ruby#reek#GetCommand'), +\ )}, \ 'callback': 'ale_linters#ruby#reek#Handle', \}) diff --git a/ale_linters/rust/cargo.vim b/ale_linters/rust/cargo.vim index b4eabfae..f98dee9b 100644 --- a/ale_linters/rust/cargo.vim +++ b/ale_linters/rust/cargo.vim @@ -22,26 +22,18 @@ function! ale_linters#rust#cargo#GetCargoExecutable(bufnr) abort endif endfunction -function! ale_linters#rust#cargo#VersionCheck(buffer) abort - return !ale#semver#HasVersion('cargo') - \ ? 'cargo --version' - \ : '' -endfunction - -function! ale_linters#rust#cargo#GetCommand(buffer, version_output) abort - let l:version = ale#semver#GetVersion('cargo', a:version_output) - +function! ale_linters#rust#cargo#GetCommand(buffer, version) abort let l:use_check = ale#Var(a:buffer, 'rust_cargo_use_check') - \ && ale#semver#GTE(l:version, [0, 17, 0]) + \ && ale#semver#GTE(a:version, [0, 17, 0]) let l:use_all_targets = l:use_check \ && ale#Var(a:buffer, 'rust_cargo_check_all_targets') - \ && ale#semver#GTE(l:version, [0, 22, 0]) + \ && ale#semver#GTE(a:version, [0, 22, 0]) let l:use_examples = l:use_check \ && ale#Var(a:buffer, 'rust_cargo_check_examples') - \ && ale#semver#GTE(l:version, [0, 22, 0]) + \ && ale#semver#GTE(a:version, [0, 22, 0]) let l:use_tests = l:use_check \ && ale#Var(a:buffer, 'rust_cargo_check_tests') - \ && ale#semver#GTE(l:version, [0, 22, 0]) + \ && ale#semver#GTE(a:version, [0, 22, 0]) let l:include_features = ale#Var(a:buffer, 'rust_cargo_include_features') @@ -94,10 +86,12 @@ endfunction call ale#linter#Define('rust', { \ 'name': 'cargo', \ 'executable': function('ale_linters#rust#cargo#GetCargoExecutable'), -\ 'command_chain': [ -\ {'callback': 'ale_linters#rust#cargo#VersionCheck'}, -\ {'callback': 'ale_linters#rust#cargo#GetCommand'}, -\ ], +\ 'command': {buffer -> ale#semver#RunWithVersionCheck( +\ buffer, +\ ale_linters#rust#cargo#GetCargoExecutable(buffer), +\ '%e --version', +\ function('ale_linters#rust#cargo#GetCommand'), +\ )}, \ 'callback': 'ale#handlers#rust#HandleRustErrors', \ 'output_stream': 'both', \ 'lint_file': 1, diff --git a/ale_linters/sh/shellcheck.vim b/ale_linters/sh/shellcheck.vim index bb7048cd..3920cab8 100644 --- a/ale_linters/sh/shellcheck.vim +++ b/ale_linters/sh/shellcheck.vim @@ -11,10 +11,6 @@ call ale#Set('sh_shellcheck_executable', 'shellcheck') call ale#Set('sh_shellcheck_dialect', 'auto') call ale#Set('sh_shellcheck_options', '') -function! ale_linters#sh#shellcheck#GetExecutable(buffer) abort - return ale#Var(a:buffer, 'sh_shellcheck_executable') -endfunction - function! ale_linters#sh#shellcheck#GetDialectArgument(buffer) abort let l:shell_type = ale#handlers#sh#GetShellType(a:buffer) @@ -39,30 +35,18 @@ function! ale_linters#sh#shellcheck#GetDialectArgument(buffer) abort return '' endfunction -function! ale_linters#sh#shellcheck#VersionCheck(buffer) abort - let l:executable = ale_linters#sh#shellcheck#GetExecutable(a:buffer) - - " Don't check the version again if we've already cached it. - return !ale#semver#HasVersion(l:executable) - \ ? ale#Escape(l:executable) . ' --version' - \ : '' -endfunction - -function! ale_linters#sh#shellcheck#GetCommand(buffer, version_output) abort - let l:executable = ale_linters#sh#shellcheck#GetExecutable(a:buffer) - let l:version = ale#semver#GetVersion(l:executable, a:version_output) - +function! ale_linters#sh#shellcheck#GetCommand(buffer, version) abort let l:options = ale#Var(a:buffer, 'sh_shellcheck_options') let l:exclude_option = ale#Var(a:buffer, 'sh_shellcheck_exclusions') let l:dialect = ale#Var(a:buffer, 'sh_shellcheck_dialect') - let l:external_option = ale#semver#GTE(l:version, [0, 4, 0]) ? ' -x' : '' + let l:external_option = ale#semver#GTE(a:version, [0, 4, 0]) ? ' -x' : '' if l:dialect is# 'auto' let l:dialect = ale_linters#sh#shellcheck#GetDialectArgument(a:buffer) endif return ale#path#BufferCdString(a:buffer) - \ . ale#Escape(l:executable) + \ . '%e' \ . (!empty(l:dialect) ? ' -s ' . l:dialect : '') \ . (!empty(l:options) ? ' ' . l:options : '') \ . (!empty(l:exclude_option) ? ' -e ' . l:exclude_option : '') @@ -108,10 +92,12 @@ endfunction call ale#linter#Define('sh', { \ 'name': 'shellcheck', -\ 'executable': function('ale_linters#sh#shellcheck#GetExecutable'), -\ 'command_chain': [ -\ {'callback': 'ale_linters#sh#shellcheck#VersionCheck'}, -\ {'callback': 'ale_linters#sh#shellcheck#GetCommand'}, -\ ], +\ 'executable': {buffer -> ale#Var(buffer, 'sh_shellcheck_executable')}, +\ 'command': {buffer -> ale#semver#RunWithVersionCheck( +\ buffer, +\ ale#Var(buffer, 'sh_shellcheck_executable'), +\ '%e --version', +\ function('ale_linters#sh#shellcheck#GetCommand'), +\ )}, \ 'callback': 'ale_linters#sh#shellcheck#Handle', \}) diff --git a/ale_linters/vim/vint.vim b/ale_linters/vim/vint.vim index 3808c47e..65e19126 100644 --- a/ale_linters/vim/vint.vim +++ b/ale_linters/vim/vint.vim @@ -7,29 +7,13 @@ call ale#Set('vim_vint_executable', 'vint') let s:enable_neovim = has('nvim') ? ' --enable-neovim' : '' let s:format = '-f "{file_path}:{line_number}:{column_number}: {severity}: {description} (see {reference})"' -function! ale_linters#vim#vint#GetExecutable(buffer) abort - return ale#Var(a:buffer, 'vim_vint_executable') -endfunction - -function! ale_linters#vim#vint#VersionCommand(buffer) abort - let l:executable = ale_linters#vim#vint#GetExecutable(a:buffer) - - " Check the Vint version if we haven't checked it already. - return !ale#semver#HasVersion(l:executable) - \ ? ale#Escape(l:executable) . ' --version' - \ : '' -endfunction - -function! ale_linters#vim#vint#GetCommand(buffer, version_output) abort - let l:executable = ale_linters#vim#vint#GetExecutable(a:buffer) - let l:version = ale#semver#GetVersion(l:executable, a:version_output) - - let l:can_use_no_color_flag = empty(l:version) - \ || ale#semver#GTE(l:version, [0, 3, 7]) +function! ale_linters#vim#vint#GetCommand(buffer, version) abort + let l:can_use_no_color_flag = empty(a:version) + \ || ale#semver#GTE(a:version, [0, 3, 7]) let l:warning_flag = ale#Var(a:buffer, 'vim_vint_show_style_issues') ? '-s' : '-w' - return ale#Escape(l:executable) + return '%e' \ . ' ' . l:warning_flag \ . (l:can_use_no_color_flag ? ' --no-color' : '') \ . s:enable_neovim @@ -65,10 +49,12 @@ endfunction call ale#linter#Define('vim', { \ 'name': 'vint', -\ 'executable': function('ale_linters#vim#vint#GetExecutable'), -\ 'command_chain': [ -\ {'callback': 'ale_linters#vim#vint#VersionCommand', 'output_stream': 'stderr'}, -\ {'callback': 'ale_linters#vim#vint#GetCommand', 'output_stream': 'stdout'}, -\ ], +\ 'executable': {buffer -> ale#Var(buffer, 'vim_vint_executable')}, +\ 'command': {buffer -> ale#semver#RunWithVersionCheck( +\ buffer, +\ ale#Var(buffer, 'vim_vint_executable'), +\ '%e --version', +\ function('ale_linters#vim#vint#GetCommand'), +\ )}, \ 'callback': 'ale_linters#vim#vint#Handle', \}) diff --git a/autoload/ale/assert.vim b/autoload/ale/assert.vim index 6c2586a6..ed90792d 100644 --- a/autoload/ale/assert.vim +++ b/autoload/ale/assert.vim @@ -1,7 +1,7 @@ -let s:chain_results = [] +let s:command_output = [] -function! ale#assert#WithChainResults(...) abort - let s:chain_results = a:000 +function! ale#assert#GivenCommandOutput(...) abort + let s:command_output = a:000 endfunction function! s:GetLinter() abort @@ -19,6 +19,39 @@ function! s:GetLinter() abort return l:filetype_linters[0] endfunction +function! s:FormatExe(command, executable) abort + return substitute(a:command, '%e', '\=ale#Escape(a:executable)', 'g') +endfunction + +function! s:ProcessDeferredCommands(initial_result) abort + let l:result = a:initial_result + let l:command_index = 0 + let l:command = [] + + while ale#command#IsDeferred(l:result) + call add(l:command, s:FormatExe(l:result.command, l:result.executable)) + + if get(g:, 'ale_run_synchronously_emulate_commands') + " Don't run commands, but simulate the results. + let l:Callback = g:ale_run_synchronously_callbacks[0] + let l:output = get(s:command_output, l:command_index, []) + call l:Callback(0, l:output) + unlet g:ale_run_synchronously_callbacks + + let l:command_index += 1 + else + " Run the commands in the shell, synchronously. + call ale#test#FlushJobs() + endif + + let l:result = l:result.value + endwhile + + call add(l:command, l:result) + + return l:command +endfunction + " Load the currently loaded linter for a test case, and check that the command " matches the given string. function! ale#assert#Linter(expected_executable, expected_command) abort @@ -31,47 +64,20 @@ function! ale#assert#Linter(expected_executable, expected_command) abort let l:executable = l:executable.value endwhile - if has_key(l:linter, 'command_chain') - let l:callbacks = map(copy(l:linter.command_chain), 'v:val.callback') + let l:command = s:ProcessDeferredCommands( + \ ale#linter#GetCommand(l:buffer, l:linter), + \) - " If the expected command is a string, just check the last one. - if type(a:expected_command) is v:t_string - if len(l:callbacks) is 1 - let l:command = call(l:callbacks[0], [l:buffer]) - else - let l:input = get(s:chain_results, len(l:callbacks) - 2, []) - let l:command = call(l:callbacks[-1], [l:buffer, l:input]) - endif - else - let l:command = [] - let l:chain_index = 0 - - for l:Callback in l:callbacks - if l:chain_index is 0 - call add(l:command, call(l:Callback, [l:buffer])) - else - let l:input = get(s:chain_results, l:chain_index - 1, []) - call add(l:command, call(l:Callback, [l:buffer, l:input])) - endif - - let l:chain_index += 1 - endfor - endif - else - let l:command = ale#linter#GetCommand(l:buffer, l:linter) - - while ale#command#IsDeferred(l:command) - call ale#test#FlushJobs() - let l:command = l:command.value - endwhile + if type(a:expected_command) isnot v:t_list + let l:command = l:command[-1] endif if type(l:command) is v:t_string " Replace %e with the escaped executable, so tests keep passing after " linters are changed to use %e. - let l:command = substitute(l:command, '%e', '\=ale#Escape(l:executable)', 'g') + let l:command = s:FormatExe(l:command, l:executable) elseif type(l:command) is v:t_list - call map(l:command, 'substitute(v:val, ''%e'', ''\=ale#Escape(l:executable)'', ''g'')') + call map(l:command, 's:FormatExe(v:val, l:executable)') endif AssertEqual @@ -79,6 +85,17 @@ function! ale#assert#Linter(expected_executable, expected_command) abort \ [l:executable, l:command] endfunction +function! ale#assert#Fixer(expected_result) abort + let l:buffer = bufnr('') + let l:result = s:ProcessDeferredCommands(s:FixerFunction(l:buffer)) + + if type(a:expected_result) isnot v:t_list + let l:result = l:result[-1] + endif + + AssertEqual a:expected_result, l:result +endfunction + function! ale#assert#LinterNotExecuted() abort let l:buffer = bufnr('') let l:linter = s:GetLinter() @@ -128,7 +145,7 @@ function! ale#assert#LSPAddress(expected_address) abort endfunction function! ale#assert#SetUpLinterTestCommands() abort - command! -nargs=+ WithChainResults :call ale#assert#WithChainResults() + command! -nargs=+ GivenCommandOutput :call ale#assert#GivenCommandOutput() command! -nargs=+ AssertLinter :call ale#assert#Linter() command! -nargs=0 AssertLinterNotExecuted :call ale#assert#LinterNotExecuted() command! -nargs=+ AssertLSPOptions :call ale#assert#LSPOptions() @@ -138,6 +155,11 @@ function! ale#assert#SetUpLinterTestCommands() abort command! -nargs=+ AssertLSPAddress :call ale#assert#LSPAddress() endfunction +function! ale#assert#SetUpFixerTestCommands() abort + command! -nargs=+ GivenCommandOutput :call ale#assert#GivenCommandOutput() + command! -nargs=+ AssertFixer :call ale#assert#Fixer() +endfunction + " A dummy function for making sure this module is loaded. function! ale#assert#SetUpLinterTest(filetype, name) abort " Set up a marker so ALE doesn't create real random temporary filenames. @@ -179,14 +201,21 @@ function! ale#assert#SetUpLinterTest(filetype, name) abort endif call ale#assert#SetUpLinterTestCommands() + + let g:ale_run_synchronously = 1 + let g:ale_run_synchronously_emulate_commands = 1 endfunction function! ale#assert#TearDownLinterTest() abort unlet! g:ale_create_dummy_temporary_file - let s:chain_results = [] + unlet! g:ale_run_synchronously + unlet! g:ale_run_synchronously_callbacks + unlet! g:ale_run_synchronously_emulate_commands + unlet! g:ale_run_synchronously_command_results + let s:command_output = [] - if exists(':WithChainResults') - delcommand WithChainResults + if exists(':GivenCommandOutput') + delcommand GivenCommandOutput endif if exists(':AssertLinter') @@ -229,3 +258,62 @@ function! ale#assert#TearDownLinterTest() abort call ale#semver#ResetVersionCache() endif endfunction + +function! ale#assert#SetUpFixerTest(filetype, name) abort + " Set up a marker so ALE doesn't create real random temporary filenames. + let g:ale_create_dummy_temporary_file = 1 + + let l:function_name = ale#fix#registry#GetFunc(a:name) + let s:FixerFunction = function(l:function_name) + + let l:prefix = 'ale_' . a:filetype . '_' . a:name + let b:filter_expr = 'v:val[: len(l:prefix) - 1] is# l:prefix' + + for l:key in filter(keys(g:), b:filter_expr) + execute 'Save g:' . l:key + unlet g:[l:key] + endfor + + for l:key in filter(keys(b:), b:filter_expr) + unlet b:[l:key] + endfor + + execute 'runtime autoload/ale/fixers/' . a:name . '.vim' + + if !exists('g:dir') + call ale#test#SetDirectory('/testplugin/test/fixers') + endif + + call ale#assert#SetUpFixerTestCommands() + + let g:ale_run_synchronously = 1 + let g:ale_run_synchronously_emulate_commands = 1 +endfunction + +function! ale#assert#TearDownFixerTest() abort + unlet! g:ale_create_dummy_temporary_file + unlet! g:ale_run_synchronously + unlet! g:ale_run_synchronously_callbacks + unlet! g:ale_run_synchronously_emulate_commands + unlet! g:ale_run_synchronously_command_results + let s:command_output = [] + unlet! s:FixerFunction + + if exists('g:dir') + call ale#test#RestoreDirectory() + endif + + Restore + + if exists('*ale#semver#ResetVersionCache') + call ale#semver#ResetVersionCache() + endif + + if exists(':GivenCommandOutput') + delcommand GivenCommandOutput + endif + + if exists(':AssertFixer') + delcommand AssertFixer + endif +endfunction diff --git a/autoload/ale/c.vim b/autoload/ale/c.vim index d759b25a..eeb512ba 100644 --- a/autoload/ale/c.vim +++ b/autoload/ale/c.vim @@ -284,6 +284,20 @@ function! ale#c#GetMakeCommand(buffer) abort return '' endfunction +function! ale#c#RunMakeCommand(buffer, Callback) abort + let l:command = ale#c#GetMakeCommand(a:buffer) + + if empty(l:command) + return a:Callback(a:buffer, []) + endif + + return ale#command#Run( + \ a:buffer, + \ l:command, + \ {b, output -> a:Callback(a:buffer, output)}, + \) +endfunction + " Given a buffer number, search for a project root, and output a List " of directories to include based on some heuristics. " diff --git a/autoload/ale/command.vim b/autoload/ale/command.vim index 33ce577c..1bbc4f4c 100644 --- a/autoload/ale/command.vim +++ b/autoload/ale/command.vim @@ -329,30 +329,46 @@ function! ale#command#Run(buffer, command, Callback, ...) abort " " The `_deferred_job_id` is used for both checking the type of object, and " for checking the job ID and status. - let l:result = {'_deferred_job_id': l:job_id} + " + " The original command here is used in tests. + let l:result = { + \ '_deferred_job_id': l:job_id, + \ 'executable': get(l:options, 'executable', ''), + \ 'command': a:command, + \} if get(g:, 'ale_run_synchronously') == 1 && l:job_id - " Run a command synchronously if this test option is set. - call extend(l:line_list, systemlist( - \ type(l:command) is v:t_list - \ ? join(l:command[0:1]) . ' ' . ale#Escape(l:command[2]) - \ : l:command - \)) - - " Don't capture output when the callbacks aren't set. - if !has_key(l:job_options, 'out_cb') - \&& !has_key(l:job_options, 'err_cb') - let l:line_list = [] - endif - if !exists('g:ale_run_synchronously_callbacks') let g:ale_run_synchronously_callbacks = [] endif - call add( - \ g:ale_run_synchronously_callbacks, - \ {-> l:job_options.exit_cb(l:job_id, v:shell_error)} - \) + if get(g:, 'ale_run_synchronously_emulate_commands', 0) + call add( + \ g:ale_run_synchronously_callbacks, + \ {exit_code, output -> [ + \ extend(l:line_list, output), + \ l:job_options.exit_cb(l:job_id, exit_code), + \ ]} + \) + else + " Run a command synchronously if this test option is set. + call extend(l:line_list, systemlist( + \ type(l:command) is v:t_list + \ ? join(l:command[0:1]) . ' ' . ale#Escape(l:command[2]) + \ : l:command + \)) + + " Don't capture output when the callbacks aren't set. + if !has_key(l:job_options, 'out_cb') + \&& !has_key(l:job_options, 'err_cb') + let l:line_list = [] + endif + + call add( + \ g:ale_run_synchronously_callbacks, + \ {-> l:job_options.exit_cb(l:job_id, v:shell_error)} + \) + endif endif return l:result diff --git a/autoload/ale/d.vim b/autoload/ale/d.vim index 0e232203..2cbfda0d 100644 --- a/autoload/ale/d.vim +++ b/autoload/ale/d.vim @@ -1,6 +1,10 @@ " Author: Auri " Description: Functions for integrating with D linters. +function! otherproject#util#Double(x) abort + return a:x * 2 +endfunction + function! ale#d#FindDUBConfig(buffer) abort " Find a DUB configuration file in ancestor paths. " The most DUB-specific names will be tried first. diff --git a/autoload/ale/fixers/eslint.vim b/autoload/ale/fixers/eslint.vim index ea5b2a63..0f57cba6 100644 --- a/autoload/ale/fixers/eslint.vim +++ b/autoload/ale/fixers/eslint.vim @@ -3,15 +3,15 @@ function! ale#fixers#eslint#Fix(buffer) abort let l:executable = ale#handlers#eslint#GetExecutable(a:buffer) + let l:command = ale#node#Executable(a:buffer, l:executable) + \ . ' --version' - let l:command = ale#semver#HasVersion(l:executable) - \ ? '' - \ : ale#node#Executable(a:buffer, l:executable) . ' --version' - - return { - \ 'command': l:command, - \ 'chain_with': 'ale#fixers#eslint#ApplyFixForVersion', - \} + return ale#semver#RunWithVersionCheck( + \ a:buffer, + \ l:executable, + \ l:command, + \ function('ale#fixers#eslint#ApplyFixForVersion'), + \) endfunction function! ale#fixers#eslint#ProcessFixDryRunOutput(buffer, output) abort @@ -33,10 +33,8 @@ function! ale#fixers#eslint#ProcessEslintDOutput(buffer, output) abort return a:output endfunction -function! ale#fixers#eslint#ApplyFixForVersion(buffer, version_output) abort +function! ale#fixers#eslint#ApplyFixForVersion(buffer, version) abort let l:executable = ale#handlers#eslint#GetExecutable(a:buffer) - let l:version = ale#semver#GetVersion(l:executable, a:version_output) - let l:config = ale#handlers#eslint#FindConfig(a:buffer) if empty(l:config) @@ -44,7 +42,7 @@ function! ale#fixers#eslint#ApplyFixForVersion(buffer, version_output) abort endif " Use --fix-to-stdout with eslint_d - if l:executable =~# 'eslint_d$' && ale#semver#GTE(l:version, [3, 19, 0]) + if l:executable =~# 'eslint_d$' && ale#semver#GTE(a:version, [3, 19, 0]) return { \ 'command': ale#node#Executable(a:buffer, l:executable) \ . ' --stdin-filename %s --stdin --fix-to-stdout', @@ -53,7 +51,7 @@ function! ale#fixers#eslint#ApplyFixForVersion(buffer, version_output) abort endif " 4.9.0 is the first version with --fix-dry-run - if ale#semver#GTE(l:version, [4, 9, 0]) + if ale#semver#GTE(a:version, [4, 9, 0]) return { \ 'command': ale#node#Executable(a:buffer, l:executable) \ . ' --stdin-filename %s --stdin --fix-dry-run --format=json', diff --git a/autoload/ale/fixers/prettier.vim b/autoload/ale/fixers/prettier.vim index 0f99ae97..b7f0ecd7 100644 --- a/autoload/ale/fixers/prettier.vim +++ b/autoload/ale/fixers/prettier.vim @@ -15,16 +15,12 @@ function! ale#fixers#prettier#GetExecutable(buffer) abort endfunction function! ale#fixers#prettier#Fix(buffer) abort - let l:executable = ale#fixers#prettier#GetExecutable(a:buffer) - - let l:command = ale#semver#HasVersion(l:executable) - \ ? '' - \ : ale#Escape(l:executable) . ' --version' - - return { - \ 'command': l:command, - \ 'chain_with': 'ale#fixers#prettier#ApplyFixForVersion', - \} + return ale#semver#RunWithVersionCheck( + \ a:buffer, + \ ale#fixers#prettier#GetExecutable(a:buffer), + \ '%e --version', + \ function('ale#fixers#prettier#ApplyFixForVersion'), + \) endfunction function! ale#fixers#prettier#ProcessPrettierDOutput(buffer, output) abort @@ -38,10 +34,9 @@ function! ale#fixers#prettier#ProcessPrettierDOutput(buffer, output) abort return a:output endfunction -function! ale#fixers#prettier#ApplyFixForVersion(buffer, version_output) abort +function! ale#fixers#prettier#ApplyFixForVersion(buffer, version) abort let l:executable = ale#fixers#prettier#GetExecutable(a:buffer) let l:options = ale#Var(a:buffer, 'javascript_prettier_options') - let l:version = ale#semver#GetVersion(l:executable, a:version_output) let l:parser = '' " Append the --parser flag depending on the current filetype (unless it's @@ -50,7 +45,7 @@ function! ale#fixers#prettier#ApplyFixForVersion(buffer, version_output) abort " Mimic Prettier's defaults. In cases without a file extension or " filetype (scratch buffer), Prettier needs `parser` set to know how " to process the buffer. - if ale#semver#GTE(l:version, [1, 16, 0]) + if ale#semver#GTE(a:version, [1, 16, 0]) let l:parser = 'babel' else let l:parser = 'babylon' @@ -94,7 +89,7 @@ function! ale#fixers#prettier#ApplyFixForVersion(buffer, version_output) abort endif " 1.4.0 is the first version with --stdin-filepath - if ale#semver#GTE(l:version, [1, 4, 0]) + if ale#semver#GTE(a:version, [1, 4, 0]) return { \ 'command': ale#path#BufferCdString(a:buffer) \ . ale#Escape(l:executable) diff --git a/autoload/ale/fixers/prettier_eslint.vim b/autoload/ale/fixers/prettier_eslint.vim index bc0caadd..1e66f49e 100644 --- a/autoload/ale/fixers/prettier_eslint.vim +++ b/autoload/ale/fixers/prettier_eslint.vim @@ -2,13 +2,9 @@ " w0rp , morhetz (Pavel Pertsev) " Description: Integration between Prettier and ESLint. -function! ale#fixers#prettier_eslint#SetOptionDefaults() abort - call ale#Set('javascript_prettier_eslint_executable', 'prettier-eslint') - call ale#Set('javascript_prettier_eslint_use_global', get(g:, 'ale_use_global_executables', 0)) - call ale#Set('javascript_prettier_eslint_options', '') -endfunction - -call ale#fixers#prettier_eslint#SetOptionDefaults() +call ale#Set('javascript_prettier_eslint_executable', 'prettier-eslint') +call ale#Set('javascript_prettier_eslint_use_global', get(g:, 'ale_use_global_executables', 0)) +call ale#Set('javascript_prettier_eslint_options', '') function! ale#fixers#prettier_eslint#GetExecutable(buffer) abort return ale#node#FindExecutable(a:buffer, 'javascript_prettier_eslint', [ @@ -18,26 +14,20 @@ function! ale#fixers#prettier_eslint#GetExecutable(buffer) abort endfunction function! ale#fixers#prettier_eslint#Fix(buffer) abort - let l:executable = ale#fixers#prettier_eslint#GetExecutable(a:buffer) - - let l:command = ale#semver#HasVersion(l:executable) - \ ? '' - \ : ale#Escape(l:executable) . ' --version' - - return { - \ 'command': l:command, - \ 'chain_with': 'ale#fixers#prettier_eslint#ApplyFixForVersion', - \} + return ale#semver#RunWithVersionCheck( + \ a:buffer, + \ ale#fixers#prettier_eslint#GetExecutable(a:buffer), + \ '%e --version', + \ function('ale#fixers#prettier_eslint#ApplyFixForVersion'), + \) endfunction -function! ale#fixers#prettier_eslint#ApplyFixForVersion(buffer, version_output) abort +function! ale#fixers#prettier_eslint#ApplyFixForVersion(buffer, version) abort let l:options = ale#Var(a:buffer, 'javascript_prettier_eslint_options') let l:executable = ale#fixers#prettier_eslint#GetExecutable(a:buffer) - let l:version = ale#semver#GetVersion(l:executable, a:version_output) - " 4.2.0 is the first version with --eslint-config-path - let l:config = ale#semver#GTE(l:version, [4, 2, 0]) + let l:config = ale#semver#GTE(a:version, [4, 2, 0]) \ ? ale#handlers#eslint#FindConfig(a:buffer) \ : '' let l:eslint_config_option = !empty(l:config) @@ -45,7 +35,7 @@ function! ale#fixers#prettier_eslint#ApplyFixForVersion(buffer, version_output) \ : '' " 4.4.0 is the first version with --stdin-filepath - if ale#semver#GTE(l:version, [4, 4, 0]) + if ale#semver#GTE(a:version, [4, 4, 0]) return { \ 'command': ale#path#BufferCdString(a:buffer) \ . ale#Escape(l:executable) diff --git a/autoload/ale/node.vim b/autoload/ale/node.vim index f75280b7..69060122 100644 --- a/autoload/ale/node.vim +++ b/autoload/ale/node.vim @@ -32,7 +32,7 @@ endfunction " " The executable is only prefixed for Windows machines function! ale#node#Executable(buffer, executable) abort - if ale#Has('win32') && a:executable =~? '\.js$' + if has('win32') && a:executable =~? '\.js$' let l:node = ale#Var(a:buffer, 'windows_node_executable_path') return ale#Escape(l:node) . ' ' . ale#Escape(a:executable) diff --git a/autoload/ale/semver.vim b/autoload/ale/semver.vim index 5f1b46fc..e3eb49c0 100644 --- a/autoload/ale/semver.vim +++ b/autoload/ale/semver.vim @@ -5,31 +5,52 @@ function! ale#semver#ResetVersionCache() abort let s:version_cache = {} endfunction +function! ale#semver#ParseVersion(version_lines) abort + for l:line in a:version_lines + let l:match = matchlist(l:line, '\v(\d+)\.(\d+)(\.(\d+))?') + + if !empty(l:match) + return [l:match[1] + 0, l:match[2] + 0, l:match[4] + 0] + endif + endfor + + return [] +endfunction + " Given an executable name and some lines of output, which can be empty, " parse the version from the lines of output, or return the cached version " triple [major, minor, patch] " " If the version cannot be found, an empty List will be returned instead. -function! ale#semver#GetVersion(executable, version_lines) abort +function! s:GetVersion(executable, version_lines) abort let l:version = get(s:version_cache, a:executable, []) + let l:parsed_version = ale#semver#ParseVersion(a:version_lines) - for l:line in a:version_lines - let l:match = matchlist(l:line, '\v(\d+)\.(\d+)(\.(\d+))?') - - if !empty(l:match) - let l:version = [l:match[1] + 0, l:match[2] + 0, l:match[4] + 0] - let s:version_cache[a:executable] = l:version - - break - endif - endfor + if !empty(l:parsed_version) + let l:version = l:parsed_version + let s:version_cache[a:executable] = l:version + endif return l:version endfunction -" Return 1 if the semver version has been cached for a given executable. -function! ale#semver#HasVersion(executable) abort - return has_key(s:version_cache, a:executable) +function! ale#semver#RunWithVersionCheck(buffer, executable, command, Callback) abort + if empty(a:executable) + return '' + endif + + let l:cache = s:version_cache + + if has_key(s:version_cache, a:executable) + return a:Callback(a:buffer, s:version_cache[a:executable]) + endif + + return ale#command#Run( + \ a:buffer, + \ a:command, + \ {_, output -> a:Callback(a:buffer, s:GetVersion(a:executable, output))}, + \ {'output_stream': 'both', 'executable': a:executable} + \) endfunction " Given two triples of integers [major, minor, patch], compare the triples diff --git a/doc/ale-development.txt b/doc/ale-development.txt index 408b176f..9c9f0394 100644 --- a/doc/ale-development.txt +++ b/doc/ale-development.txt @@ -12,6 +12,7 @@ CONTENTS *ale-development-contents* 3. Coding Standards.....................|ale-coding-standards| 4. Testing ALE..........................|ale-development-tests| 4.1. Writing Linter Tests.............|ale-development-linter-tests| + 4.2. Writing Fixer Tests..............|ale-development-fixer-tests| =============================================================================== 1. Introduction *ale-development-introduction* @@ -288,10 +289,10 @@ and should be written like so. > AssertLinter 'some-command', ale#Escape('some-command') . ' --foo' Execute(Check chained commands): - " WithChainResults can be called with 1 or more list for passing output + " GivenCommandOutput can be called with 1 or more list for passing output " to chained commands. The output for each callback defaults to an empty " list. - WithChainResults ['v2.1.2'] + GivenCommandOutput ['v2.1.2'] " Given a List of commands, check all of them. " Given a String, only the last command in the chain will be checked. AssertLinter 'some-command', [ @@ -302,7 +303,7 @@ and should be written like so. > The full list of commands that will be temporarily defined for linter tests given the above setup are as follows. -`WithChainResults [...]` - Define output for command chain functions. +`GivenCommandOutput [...]` - Define output for ale#command#Run. `AssertLinter executable, command` - Check the executable and command. `AssertLinterNotExecuted` - Check that linters will not be executed. `AssertLSPLanguage language` - Check the language given to an LSP server. @@ -311,5 +312,46 @@ given the above setup are as follows. `AssertLSPProject project_root` - Check the root given to an LSP server. `AssertLSPAddress address` - Check the address to an LSP server. + +=============================================================================== +4.2 Writing Fixer Tests *ale-development-fixer-tests* + +Tests for ALE fixers should go in the `test/fixers` directory, and should +be written like so. > + + Before: + " Load the fixer and set up a series of commands, reset fixer variables, + " clear caches, etc. + " + " Vader's 'Save' command will be called here for fixer variables. + call ale#assert#SetUpFixerTest('filetype', 'fixer_name') + + After: + " Reset fixers, variables, etc. + " + " Vader's 'Restore' command will be called here. + call ale#assert#TearDownFixerTest() + + Execute(The default command should be correct): + " AssertFixer checks the result of the loaded fixer function. + AssertFixer {'command': ale#Escape('some-command') . ' --foo'} + + Execute(Check chained commands): + " Same as above for linter tests. + GivenCommandOutput ['v2.1.2'] + " Given a List of commands, check all of them. + " Given anything else, only the last result will be checked. + AssertFixer [ + \ ale#Escape('some-command') . ' --version', + \ {'command': ale#Escape('some-command') . ' --foo'} + \] +< +The full list of commands that will be temporarily defined for fixer tests +given the above setup are as follows. + +`GivenCommandOutput [...]` - Define output for ale#command#Run. +`AssertFixer results` - Check the fixer results + + =============================================================================== vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl: diff --git a/test/command_callback/test_c_clang_command_callbacks.vader b/test/command_callback/test_c_clang_command_callbacks.vader index 7d2ff0bf..b8c02e4d 100644 --- a/test/command_callback/test_c_clang_command_callbacks.vader +++ b/test/command_callback/test_c_clang_command_callbacks.vader @@ -13,8 +13,8 @@ After: call ale#assert#TearDownLinterTest() Execute(The executable should be configurable): - AssertLinter 'clang', ['', ale#Escape('clang') . b:command_tail] + AssertLinter 'clang', [ale#Escape('clang') . b:command_tail] let b:ale_c_clang_executable = 'foobar' - AssertLinter 'foobar', ['', ale#Escape('foobar') . b:command_tail] + AssertLinter 'foobar', [ale#Escape('foobar') . b:command_tail] diff --git a/test/command_callback/test_c_gcc_command_callbacks.vader b/test/command_callback/test_c_gcc_command_callbacks.vader index 1f51c3bc..c5b316c8 100644 --- a/test/command_callback/test_c_gcc_command_callbacks.vader +++ b/test/command_callback/test_c_gcc_command_callbacks.vader @@ -14,8 +14,8 @@ After: unlet! b:command_tail Execute(The executable should be configurable): - AssertLinter 'gcc', ['', ale#Escape('gcc') . b:command_tail] + AssertLinter 'gcc', [ale#Escape('gcc') . b:command_tail] let b:ale_c_gcc_executable = 'foobar' - AssertLinter 'foobar', ['', ale#Escape('foobar') . b:command_tail] + AssertLinter 'foobar', [ale#Escape('foobar') . b:command_tail] diff --git a/test/command_callback/test_cargo_command_callbacks.vader b/test/command_callback/test_cargo_command_callbacks.vader index f0afbc91..438c97db 100644 --- a/test/command_callback/test_cargo_command_callbacks.vader +++ b/test/command_callback/test_cargo_command_callbacks.vader @@ -1,106 +1,113 @@ Before: call ale#assert#SetUpLinterTest('rust', 'cargo') + call ale#test#SetFilename('cargo_paths/test.rs') + let g:cd = 'cd ' . ale#Escape(ale#path#Simplify(g:dir . '/cargo_paths')) . ' && ' let g:suffix = ' --frozen --message-format=json -q' + let g:ale_rust_cargo_avoid_whole_workspace = 0 " Test with version 0.22.0 by default. - WithChainResults ['cargo 0.22.0 (3423351a5 2017-10-06)'] + GivenCommandOutput ['cargo 0.22.0 (3423351a5 2017-10-06)'] After: call ale#assert#TearDownLinterTest() + unlet! g:cd unlet! g:suffix Execute(The linter should not be executed when there's no Cargo.toml file): + call ale#test#SetFilename('../foo.rs') AssertLinterNotExecuted Execute(The linter should be executed when there is a Cargo.toml file): - call ale#test#SetFilename('cargo_paths/test.rs') - - WithChainResults [] - AssertLinter 'cargo', - \ 'cd ' . ale#Escape(ale#path#Simplify(g:dir . '/cargo_paths')) . ' && ' - \ . 'cargo build --frozen --message-format=json -q' - -Execute(The default command should be correct): - WithChainResults [] - AssertLinter '', ['cargo --version', 'cargo build' . g:suffix] + GivenCommandOutput [] + AssertLinter 'cargo', 'cargo build --frozen --message-format=json -q' Execute(`cargo check` should be used when the version is new enough): - WithChainResults ['cargo 0.17.0 (3423351a5 2017-10-06)'] - AssertLinter '', ['cargo --version', 'cargo check' . g:suffix] + GivenCommandOutput ['cargo 0.17.0 (3423351a5 2017-10-06)'] + AssertLinter 'cargo', [ + \ ale#Escape('cargo') . ' --version', + \ 'cargo check' . g:suffix, + \] " We should cache the version check - WithChainResults [] - AssertLinter '', ['', 'cargo check' . g:suffix] + GivenCommandOutput [] + AssertLinter 'cargo', ['cargo check' . g:suffix] Execute(`cargo build` should be used when cargo is too old): - WithChainResults ['cargo 0.16.0 (3423351a5 2017-10-06)'] - AssertLinter '', ['cargo --version', 'cargo build' . g:suffix] + GivenCommandOutput ['cargo 0.16.0 (3423351a5 2017-10-06)'] + AssertLinter 'cargo', [ + \ ale#Escape('cargo') . ' --version', + \ 'cargo build' . g:suffix, + \] - WithChainResults [] - AssertLinter '', ['', 'cargo build' . g:suffix] + GivenCommandOutput [] + AssertLinter 'cargo', ['cargo build' . g:suffix] Execute(`cargo build` should be used when g:ale_rust_cargo_use_check is set to 0): let g:ale_rust_cargo_use_check = 0 - WithChainResults ['cargo 0.24.0 (3423351a5 2017-10-06)'] - AssertLinter '', ['cargo --version', 'cargo build' . g:suffix] + GivenCommandOutput ['cargo 0.24.0 (3423351a5 2017-10-06)'] + AssertLinter 'cargo', [ + \ ale#Escape('cargo') . ' --version', + \ 'cargo build' . g:suffix, + \] " We should cache the version check - WithChainResults [] - AssertLinter '', ['', 'cargo build' . g:suffix] + GivenCommandOutput [] + AssertLinter 'cargo', ['cargo build' . g:suffix] Execute(`cargo check` should be used when the version is new enough): - AssertLinter '', ['cargo --version', 'cargo check' . g:suffix] + AssertLinter 'cargo', [ + \ ale#Escape('cargo') . ' --version', + \ 'cargo check' . g:suffix, + \] " We should cache the version check - WithChainResults [] - AssertLinter '', ['', 'cargo check' . g:suffix] + GivenCommandOutput [] + AssertLinter 'cargo', ['cargo check' . g:suffix] Execute(--all-targets should be used when g:ale_rust_cargo_check_all_targets is set to 1): let g:ale_rust_cargo_check_all_targets = 1 - AssertLinter '', ['cargo --version', 'cargo check --all-targets' . g:suffix] - + AssertLinter 'cargo', [ale#Escape('cargo') . ' --version', 'cargo check --all-targets' . g:suffix] " We should cache the version check - WithChainResults [] - AssertLinter '', ['', 'cargo check --all-targets' . g:suffix] + AssertLinter 'cargo', ['cargo check --all-targets' . g:suffix] Execute(--tests should be used when g:ale_rust_cargo_check_tests is set to 1): let g:ale_rust_cargo_check_tests = 1 - AssertLinter '', ['cargo --version', 'cargo check --tests' . g:suffix] + AssertLinter 'cargo', [ale#Escape('cargo') . ' --version', 'cargo check --tests' . g:suffix] " We should cache the version check - WithChainResults [] - AssertLinter '', ['', 'cargo check --tests' . g:suffix] + GivenCommandOutput [] + AssertLinter 'cargo', ['cargo check --tests' . g:suffix] Execute(--examples should be used when g:ale_rust_cargo_check_examples is set to 1): let g:ale_rust_cargo_check_examples = 1 - AssertLinter '', ['cargo --version', 'cargo check --examples' . g:suffix] + AssertLinter 'cargo', [ale#Escape('cargo') . ' --version', 'cargo check --examples' . g:suffix] " We should cache the version check - WithChainResults [] - AssertLinter '', ['', 'cargo check --examples' . g:suffix] + GivenCommandOutput [] + AssertLinter 'cargo', ['cargo check --examples' . g:suffix] Execute(--no-default-features should be used when g:ale_rust_cargo_default_feature_behavior is none): let b:ale_rust_cargo_default_feature_behavior = 'none' - AssertLinter '', ['cargo --version', 'cargo check --frozen --message-format=json -q --no-default-features'] + AssertLinter 'cargo', [ale#Escape('cargo') . ' --version', 'cargo check --frozen --message-format=json -q --no-default-features'] Execute(g:ale_rust_cargo_include_features added when g:ale_rust_cargo_default_feature_behavior is none): let b:ale_rust_cargo_default_feature_behavior = 'none' let b:ale_rust_cargo_include_features = 'foo bar' - AssertLinter '', ['cargo --version', 'cargo check --frozen --message-format=json -q --no-default-features --features ' . ale#Escape('foo bar')] + AssertLinter 'cargo', [ale#Escape('cargo') . ' --version', 'cargo check --frozen --message-format=json -q --no-default-features --features ' . ale#Escape('foo bar')] Execute(g:ale_rust_cargo_include_features added and escaped): let b:ale_rust_cargo_default_feature_behavior = 'default' let b:ale_rust_cargo_include_features = "foo bar baz" - AssertLinter '', ['cargo --version', 'cargo check --frozen --message-format=json -q --features ' . ale#Escape('foo bar baz')] + AssertLinter 'cargo', [ale#Escape('cargo') . ' --version', 'cargo check --frozen --message-format=json -q --features ' . ale#Escape('foo bar baz')] Execute(--all-features should be used when g:ale_rust_cargo_default_feature_behavior is all): let b:ale_rust_cargo_default_feature_behavior = 'all' @@ -108,14 +115,15 @@ Execute(--all-features should be used when g:ale_rust_cargo_default_feature_beha " since it won't do anything let b:ale_rust_cargo_include_features = 'foo bar' - WithChainResults ['cargo 0.22.0 (3423351a5 2017-10-06)'] - AssertLinter '', ['cargo --version', 'cargo check --frozen --message-format=json -q --all-features'] + GivenCommandOutput ['cargo 0.22.0 (3423351a5 2017-10-06)'] + AssertLinter 'cargo', [ale#Escape('cargo') . ' --version', 'cargo check --frozen --message-format=json -q --all-features'] Execute(When a crate belongs to a workspace we should cd into the crate): + let g:ale_rust_cargo_avoid_whole_workspace = 1 call ale#test#SetFilename('cargo_workspace_paths/subpath/test.rs') AssertLinter 'cargo', [ - \ 'cargo --version', + \ ale#Escape('cargo') . ' --version', \ 'cd ' . ale#Escape(ale#path#Simplify(g:dir . '/cargo_workspace_paths/subpath')) . ' && ' \ . 'cargo check --frozen --message-format=json -q', \] @@ -125,22 +133,22 @@ Execute(When a crate belongs to a workspace we chdir into the crate, unless we d call ale#test#SetFilename('cargo_workspace_paths/subpath/test.rs') AssertLinter 'cargo', [ - \ 'cargo --version', + \ ale#Escape('cargo') . ' --version', \ 'cargo check --frozen --message-format=json -q', \] Execute(When ale_rust_cargo_use_clippy is set, cargo-clippy is used as linter): let b:ale_rust_cargo_use_clippy = 1 - AssertLinter '', [ - \ 'cargo --version', + AssertLinter 'cargo', [ + \ ale#Escape('cargo') . ' --version', \ 'cargo clippy --frozen --message-format=json -q ', \] Execute(When ale_rust_cargo_clippy_options is set, cargo-clippy appends it to commandline): let b:ale_rust_cargo_use_clippy = 1 let b:ale_rust_cargo_clippy_options = '-- -D warnings' - AssertLinter '', [ - \ 'cargo --version', + AssertLinter 'cargo', [ + \ ale#Escape('cargo') . ' --version', \ 'cargo clippy --frozen --message-format=json -q -- -D warnings', \] @@ -148,7 +156,7 @@ Execute(cargo-check does not refer ale_rust_cargo_clippy_options): let b:ale_rust_cargo_use_clippy = 0 let b:ale_rust_cargo_use_check = 1 let b:ale_rust_cargo_clippy_options = '-- -D warnings' - AssertLinter '', [ - \ 'cargo --version', + AssertLinter 'cargo', [ + \ ale#Escape('cargo') . ' --version', \ 'cargo check --frozen --message-format=json -q', \] diff --git a/test/command_callback/test_erlang_syntaxerl_command_callback.vader b/test/command_callback/test_erlang_syntaxerl_command_callback.vader index 28cff9b9..e7cc26ea 100644 --- a/test/command_callback/test_erlang_syntaxerl_command_callback.vader +++ b/test/command_callback/test_erlang_syntaxerl_command_callback.vader @@ -19,7 +19,7 @@ Execute (The executable should be configurable): \] Execute (The -b option should be used when available): - WithChainResults [ + GivenCommandOutput [ \ 'Syntax checker for Erlang (0.14.0)', \ 'Usage: syntaxerl [-d | --debug] ', \ ' syntaxerl <-h | --help>', @@ -31,7 +31,7 @@ Execute (The -b option should be used when available): \ ale#Escape('syntaxerl') . ' %t', \] - WithChainResults [ + GivenCommandOutput [ \ 'Syntax checker for Erlang (0.14.0)', \ 'Usage: syntaxerl [-b | --base ] [-d | --debug] ', \ ' syntaxerl <-h | --help>', diff --git a/test/command_callback/test_erubi_command_callback.vader b/test/command_callback/test_erubi_command_callback.vader index 0643efc2..0d88ff93 100644 --- a/test/command_callback/test_erubi_command_callback.vader +++ b/test/command_callback/test_erubi_command_callback.vader @@ -21,7 +21,7 @@ Execute(Executable should filter invalid eRuby when inside a Rails project): \] Execute(Command should be blank if the first command in the chain returns output): - WithChainResults [ + GivenCommandOutput [ \ "/usr/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require': cannot load such file -- erubi/capture_end (LoadError)", \ " from /usr/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require'", \] diff --git a/test/command_callback/test_flake8_command_callback.vader b/test/command_callback/test_flake8_command_callback.vader index ede511e0..f082a63a 100644 --- a/test/command_callback/test_flake8_command_callback.vader +++ b/test/command_callback/test_flake8_command_callback.vader @@ -3,7 +3,7 @@ Before: let b:bin_dir = has('win32') ? 'Scripts' : 'bin' - WithChainResults ['3.0.0'] + GivenCommandOutput ['3.0.0'] After: unlet! b:executable @@ -18,16 +18,15 @@ Execute(The flake8 callbacks should return the correct default values): \] " The version check should be cached. - WithChainResults [] + GivenCommandOutput [] AssertLinter 'flake8', [ - \ '', \ ale#path#BufferCdString(bufnr('')) \ . ale#Escape('flake8') . ' --format=default --stdin-display-name %s -', \] " Try with older versions. call ale#semver#ResetVersionCache() - WithChainResults ['2.9.9'] + GivenCommandOutput ['2.9.9'] AssertLinter 'flake8', [ \ ale#Escape('flake8') . ' --version', \ ale#path#BufferCdString(bufnr('')) @@ -45,7 +44,7 @@ Execute(The option for disabling changing directories should work): Execute(The flake8 command callback should let you set options): let g:ale_python_flake8_options = '--some-option' - WithChainResults ['3.0.4'] + GivenCommandOutput ['3.0.4'] AssertLinter 'flake8', [ \ ale#Escape('flake8') . ' --version', \ ale#path#BufferCdString(bufnr('')) @@ -54,7 +53,7 @@ Execute(The flake8 command callback should let you set options): \] call ale#semver#ResetVersionCache() - WithChainResults ['2.9.9'] + GivenCommandOutput ['2.9.9'] AssertLinter 'flake8', [ \ ale#Escape('flake8') . ' --version', \ ale#path#BufferCdString(bufnr('')) @@ -129,7 +128,7 @@ Execute(Using `python -m flake8` should be supported for running flake8): let g:ale_python_flake8_executable = 'python' let g:ale_python_flake8_options = '-m flake8 --some-option' - WithChainResults ['2.9.9'] + GivenCommandOutput ['2.9.9'] AssertLinter 'python', [ \ ale#Escape('python') . ' -m flake8 --version', \ ale#path#BufferCdString(bufnr('')) @@ -142,7 +141,7 @@ Execute(Using `python -m flake8` should be supported for running flake8): " Leading spaces shouldn't matter let g:ale_python_flake8_options = ' -m flake8 --some-option' - WithChainResults ['2.9.9'] + GivenCommandOutput ['2.9.9'] AssertLinter 'python', [ \ ale#Escape('python') . ' -m flake8 --version', \ ale#path#BufferCdString(bufnr('')) @@ -154,14 +153,14 @@ Execute(Setting executable to 'pipenv' should append 'run flake8'): let g:ale_python_flake8_executable = 'path/to/pipenv' " FIXME: pipenv should check the version with flake8. - WithChainResults [] + GivenCommandOutput [] AssertLinter 'path/to/pipenv', \ ale#path#BufferCdString(bufnr('')) \ . ale#Escape('path/to/pipenv') . ' run flake8 --format=default -' Execute(Pipenv is detected when python_flake8_auto_pipenv is set): let g:ale_python_flake8_auto_pipenv = 1 - call ale#test#SetFilename('/testplugin/test/python_fixtures/pipenv/whatever.py') + call ale#test#SetFilename('../python_fixtures/pipenv/whatever.py') AssertLinter 'pipenv', \ ale#path#BufferCdString(bufnr('')) diff --git a/test/command_callback/test_gobuild_command_callback.vader b/test/command_callback/test_gobuild_command_callback.vader index c6e324f2..79015b75 100644 --- a/test/command_callback/test_gobuild_command_callback.vader +++ b/test/command_callback/test_gobuild_command_callback.vader @@ -3,7 +3,7 @@ Before: call ale#assert#SetUpLinterTest('go', 'gobuild') - WithChainResults ['/foo/bar', '/foo/baz'] + GivenCommandOutput ['/foo/bar', '/foo/baz'] After: Restore diff --git a/test/command_callback/test_javac_command_callback.vader b/test/command_callback/test_javac_command_callback.vader index a7a928e4..42c64e54 100644 --- a/test/command_callback/test_javac_command_callback.vader +++ b/test/command_callback/test_javac_command_callback.vader @@ -48,30 +48,30 @@ Execute(The executable should be configurable): \ . ' -d ' . ale#Escape('TEMP_DIR') . ' %t' Execute(The javac callback should include discovered classpaths): - WithChainResults [ + let b:command = ale_linters#java#javac#GetCommand(bufnr(''), [ \ '[DEBUG] Ignore this.', \ '[INFO] Something we should ignore.', \ '/foo/bar.jar', \ '/xyz/abc.jar', - \] + \], {}) - AssertLinter 'javac', + AssertEqual \ g:prefix \ . ' -cp ' \ . ale#Escape(join(['/foo/bar.jar', '/xyz/abc.jar'], g:cp_sep)) - \ . ' -d ' . ale#Escape('TEMP_DIR') . ' %t' + \ . ' -d ' . ale#Escape('TEMP_DIR') . ' %t', + \ substitute(b:command, '%e', '\=ale#Escape(''javac'')', 'g') Execute(The javac callback should combine discovered classpaths and manual ones): let g:ale_java_javac_classpath = 'configured.jar' - - WithChainResults [ + let b:command = ale_linters#java#javac#GetCommand(bufnr(''), [ \ '[DEBUG] Ignore this.', \ '[INFO] Something we should ignore.', \ '/foo/bar.jar', \ '/xyz/abc.jar', - \] + \], {}) - AssertLinter 'javac', + AssertEqual \ g:prefix \ . ' -cp ' \ . ale#Escape(join( @@ -82,11 +82,18 @@ Execute(The javac callback should combine discovered classpaths and manual ones) \ ], \ g:cp_sep \ )) - \ . ' -d ' . ale#Escape('TEMP_DIR') . ' %t' + \ . ' -d ' . ale#Escape('TEMP_DIR') . ' %t', + \ substitute(b:command, '%e', '\=ale#Escape(''javac'')', 'g') let g:ale_java_javac_classpath = 'configured.jar' . g:cp_sep . 'configured2.jar' + let b:command = ale_linters#java#javac#GetCommand(bufnr(''), [ + \ '[DEBUG] Ignore this.', + \ '[INFO] Something we should ignore.', + \ '/foo/bar.jar', + \ '/xyz/abc.jar', + \], {}) - AssertLinter 'javac', + AssertEqual \ g:prefix \ . ' -cp ' \ . ale#Escape(join( @@ -98,7 +105,8 @@ Execute(The javac callback should combine discovered classpaths and manual ones) \ ], \ g:cp_sep \ )) - \ . ' -d ' . ale#Escape('TEMP_DIR') . ' %t' + \ . ' -d ' . ale#Escape('TEMP_DIR') . ' %t', + \ substitute(b:command, '%e', '\=ale#Escape(''javac'')', 'g') Execute(The javac callback should detect source directories): call ale#engine#Cleanup(bufnr('')) @@ -117,25 +125,25 @@ Execute(The javac callback should combine detected source directories and classp call ale#test#SetFilename('java_paths/src/main/java/com/something/dummy.java') call ale#engine#InitBufferInfo(bufnr('')) - WithChainResults [ + let b:command = ale_linters#java#javac#GetCommand(bufnr(''), [ \ '[DEBUG] Ignore this.', \ '[INFO] Something we should ignore.', \ '/foo/bar.jar', \ '/xyz/abc.jar', - \] - AssertLinter 'javac', + \], {}) + + AssertEqual \ ale#path#CdString(expand('%:p:h')) . ale#Escape('javac') . ' -Xlint' \ . ' -cp ' . ale#Escape(join(['/foo/bar.jar', '/xyz/abc.jar'], g:cp_sep)) \ . ' -sourcepath ' . ale#Escape( \ ale#path#Simplify(g:dir . '/java_paths/src/main/java/') \ ) - \ . ' -d ' . ale#Escape('TEMP_DIR') . ' %t' + \ . ' -d ' . ale#Escape('TEMP_DIR') . ' %t', + \ substitute(b:command, '%e', '\=ale#Escape(''javac'')', 'g') Execute(The javac callback should use g:ale_java_javac_options correctly): let g:ale_java_javac_options = '--anything --else' - let b:command = ale_linters#java#javac#GetCommand(bufnr(''), []) - AssertLinter 'javac', \ g:prefix . ' -d ' . ale#Escape('TEMP_DIR') . ' --anything --else %t' diff --git a/test/command_callback/test_phpstan_command_callbacks.vader b/test/command_callback/test_phpstan_command_callbacks.vader index 665661a3..a9df2d7c 100644 --- a/test/command_callback/test_phpstan_command_callbacks.vader +++ b/test/command_callback/test_phpstan_command_callbacks.vader @@ -1,7 +1,7 @@ Before: call ale#assert#SetUpLinterTest('php', 'phpstan') - WithChainResults ['0.10.2'] + GivenCommandOutput ['0.10.2'] After: call ale#assert#TearDownLinterTest() @@ -26,7 +26,7 @@ Execute(Custom phpstan configuration file): \ ale#Escape('phpstan') . ' analyze -l4 --errorFormat raw -c phpstan_config %s' Execute(Choose the right format for error format param): - WithChainResults ['0.10.3'] + GivenCommandOutput ['0.10.3'] AssertLinter 'phpstan', [ \ ale#Escape('phpstan') . ' --version', diff --git a/test/command_callback/test_reek_command_callback.vader b/test/command_callback/test_reek_command_callback.vader index a7cb7fb9..798c3314 100644 --- a/test/command_callback/test_reek_command_callback.vader +++ b/test/command_callback/test_reek_command_callback.vader @@ -5,7 +5,7 @@ After: call ale#assert#TearDownLinterTest() Execute(The reek callbacks should return the correct default values): - WithChainResults ['reek 5.0.0'] + GivenCommandOutput ['reek 5.0.0'] AssertLinter 'reek', [ \ ale#Escape('reek') . ' --version', \ ale#Escape('reek') . ' -f json --no-progress --no-color --force-exclusion --stdin-filename %s', @@ -14,7 +14,7 @@ Execute(The reek callbacks should return the correct default values): " Try with older versions. call ale#semver#ResetVersionCache() - WithChainResults ['reek 4.8.2'] + GivenCommandOutput ['reek 4.8.2'] AssertLinter 'reek', [ \ ale#Escape('reek') . ' --version', \ ale#Escape('reek') . ' -f json --no-progress --no-color --force-exclusion', @@ -23,7 +23,7 @@ Execute(The reek callbacks should return the correct default values): Execute(Setting bundle appends 'exec reek'): let g:ale_ruby_reek_executable = 'bundle' - WithChainResults ['reek 5.0.0'] + GivenCommandOutput ['reek 5.0.0'] AssertLinter 'bundle', ale#Escape('bundle') \ . ' exec reek' \ . ' -f json --no-progress --no-color --force-exclusion --stdin-filename %s', @@ -31,20 +31,19 @@ Execute(Setting bundle appends 'exec reek'): " Try with older versions. call ale#semver#ResetVersionCache() - WithChainResults ['reek 4.8.2'] + GivenCommandOutput ['reek 4.8.2'] AssertLinter 'bundle', ale#Escape('bundle') \ . ' exec reek' \ . ' -f json --no-progress --no-color --force-exclusion' Execute(The reek version check should be cached): - WithChainResults ['reek 5.0.0'] + GivenCommandOutput ['reek 5.0.0'] AssertLinter 'reek', [ \ ale#Escape('reek') . ' --version', \ ale#Escape('reek') . ' -f json --no-progress --no-color --force-exclusion --stdin-filename %s', \] - WithChainResults [] + GivenCommandOutput [] AssertLinter 'reek', [ - \ '', \ ale#Escape('reek') . ' -f json --no-progress --no-color --force-exclusion --stdin-filename %s', \] diff --git a/test/command_callback/test_shellcheck_command_callback.vader b/test/command_callback/test_shellcheck_command_callback.vader index c5360b7d..fcdb184a 100644 --- a/test/command_callback/test_shellcheck_command_callback.vader +++ b/test/command_callback/test_shellcheck_command_callback.vader @@ -60,7 +60,7 @@ Execute(The -x option should be added when the version is new enough): \ b:prefix . ale#Escape('shellcheck') . b:suffix, \] - WithChainResults [ + GivenCommandOutput [ \ 'ShellCheck - shell script analysis tool', \ 'version: 0.4.4', \ 'license: GNU General Public License, version 3', @@ -72,14 +72,13 @@ Execute(The -x option should be added when the version is new enough): \] " We should cache the version check - WithChainResults [] + GivenCommandOutput [] AssertLinter 'shellcheck', [ - \ '', \ b:prefix . ale#Escape('shellcheck') . ' -x' . b:suffix, \] Execute(The -x option should not be added when the version is too old): - WithChainResults [ + GivenCommandOutput [ \ 'ShellCheck - shell script analysis tool', \ 'version: 0.3.9', \ 'license: GNU General Public License, version 3', @@ -91,7 +90,7 @@ Execute(The -x option should not be added when the version is too old): \] Execute(The version check shouldn't be run again for old versions): - WithChainResults [ + GivenCommandOutput [ \ 'ShellCheck - shell script analysis tool', \ 'version: 0.3.9', \ 'license: GNU General Public License, version 3', @@ -102,6 +101,5 @@ Execute(The version check shouldn't be run again for old versions): \ b:prefix . ale#Escape('shellcheck') . b:suffix, \] AssertLinter 'shellcheck', [ - \ '', \ b:prefix . ale#Escape('shellcheck') . b:suffix, \] diff --git a/test/fix/test_ale_fix.vader b/test/fix/test_ale_fix.vader index 52df2a62..9e5ad027 100644 --- a/test/fix/test_ale_fix.vader +++ b/test/fix/test_ale_fix.vader @@ -11,7 +11,6 @@ Before: let g:ale_enabled = 0 let g:ale_echo_cursor = 0 let g:ale_run_synchronously = 1 - unlet! g:ale_run_synchronously_callbacks let g:ale_set_lists_synchronously = 1 let g:ale_fix_buffer_data = {} let g:ale_fixers = { diff --git a/test/fixers/test_eslint_fixer_callback.vader b/test/fixers/test_eslint_fixer_callback.vader index 774595e3..7ea9c2cf 100644 --- a/test/fixers/test_eslint_fixer_callback.vader +++ b/test/fixers/test_eslint_fixer_callback.vader @@ -1,143 +1,129 @@ Before: - call ale#test#SetDirectory('/testplugin/test/fixers') + call ale#assert#SetUpFixerTest('javascript', 'eslint') + runtime autoload/ale/handlers/eslint.vim After: - call ale#test#RestoreDirectory() - call ale#semver#ResetVersionCache() + call ale#assert#TearDownFixerTest() Execute(The executable path should be correct): call ale#test#SetFilename('../eslint-test-files/react-app/subdir/testfile.js') " eslint_d output with an older eslint version is used here. - AssertEqual + GivenCommandOutput ['v4.4.1 (eslint_d v5.1.0)'] + AssertFixer \ { \ 'read_temporary_file': 1, \ 'command': (has('win32') ? 'node.exe ' : '') \ . ale#Escape(ale#path#Simplify(g:dir . '/../eslint-test-files/react-app/node_modules/eslint/bin/eslint.js')) \ . ' -c ' . ale#Escape(ale#path#Simplify(g:dir . '/../eslint-test-files/react-app/.eslintrc.js')) \ . ' --fix %t', - \ }, - \ ale#fixers#eslint#ApplyFixForVersion(bufnr(''), ['v4.4.1 (eslint_d v5.1.0)']) + \ } Execute(The lower priority configuration file in a nested directory should be preferred): call ale#test#SetFilename('../eslint-test-files/react-app/subdir-with-config/testfile.js') - AssertEqual + AssertFixer \ { \ 'read_temporary_file': 1, \ 'command': (has('win32') ? 'node.exe ' : '') \ . ale#Escape(ale#path#Simplify(g:dir . '/../eslint-test-files/react-app/node_modules/eslint/bin/eslint.js')) \ . ' -c ' . ale#Escape(ale#path#Simplify(g:dir . '/../eslint-test-files/react-app/subdir-with-config/.eslintrc')) \ . ' --fix %t', - \ }, - \ ale#fixers#eslint#ApplyFixForVersion(bufnr(''), []) + \ } Execute(package.json should be used as a last resort): call ale#test#SetFilename('../eslint-test-files/react-app/subdir-with-package-json/testfile.js') - AssertEqual + AssertFixer \ { \ 'read_temporary_file': 1, \ 'command': (has('win32') ? 'node.exe ' : '') \ . ale#Escape(ale#path#Simplify(g:dir . '/../eslint-test-files/react-app/node_modules/eslint/bin/eslint.js')) \ . ' -c ' . ale#Escape(ale#path#Simplify(g:dir . '/../eslint-test-files/react-app/.eslintrc.js')) \ . ' --fix %t', - \ }, - \ ale#fixers#eslint#ApplyFixForVersion(bufnr(''), []) + \ } call ale#test#SetFilename('../eslint-test-files/package.json') - AssertEqual + AssertFixer \ { \ 'read_temporary_file': 1, \ 'command': \ ale#Escape(ale#path#Simplify(g:dir . '/../eslint-test-files/node_modules/.bin/eslint')) \ . ' -c ' . ale#Escape(ale#path#Simplify(g:dir . '/../eslint-test-files/package.json')) \ . ' --fix %t', - \ }, - \ ale#fixers#eslint#ApplyFixForVersion(bufnr(''), []) + \ } Execute(The version check should be correct): - call ale#test#SetFilename('../eslint-test-files/react-app/subdir/testfile.js') + call ale#test#SetFilename('../eslint-test-files/react-app/subdir-with-config/testfile.js') - AssertEqual - \ { - \ 'chain_with': 'ale#fixers#eslint#ApplyFixForVersion', - \ 'command': (has('win32') ? 'node.exe ' : '') - \ . ale#Escape(ale#path#Simplify(g:dir . '/../eslint-test-files/react-app/node_modules/eslint/bin/eslint.js')) - \ . ' --version' - \ }, - \ ale#fixers#eslint#Fix(bufnr('')) - -Execute(--fix-dry-run should be used for 4.9.0 and up): - call ale#test#SetFilename('../eslint-test-files/react-app/subdir/testfile.js') - - AssertEqual + " We should run the command to get the version the first time. + GivenCommandOutput ['4.9.0'] + AssertFixer [ + \ (has('win32') ? 'node.exe ' : '') + \ . ale#Escape(ale#path#Simplify(g:dir . '/../eslint-test-files/react-app/node_modules/eslint/bin/eslint.js')) + \ . ' --version', \ { \ 'command': (has('win32') ? 'node.exe ' : '') \ . ale#Escape(ale#path#Simplify(g:dir . '/../eslint-test-files/react-app/node_modules/eslint/bin/eslint.js')) \ . ' --stdin-filename %s --stdin --fix-dry-run --format=json', \ 'process_with': 'ale#fixers#eslint#ProcessFixDryRunOutput', \ }, - \ ale#fixers#eslint#ApplyFixForVersion(bufnr(''), ['4.9.0']) + \] + + AssertFixer [ + \ { + \ 'command': (has('win32') ? 'node.exe ' : '') + \ . ale#Escape(ale#path#Simplify(g:dir . '/../eslint-test-files/react-app/node_modules/eslint/bin/eslint.js')) + \ . ' --stdin-filename %s --stdin --fix-dry-run --format=json', + \ 'process_with': 'ale#fixers#eslint#ProcessFixDryRunOutput', + \ }, + \] + +Execute(--fix-dry-run should be used for 4.9.0 and up): + call ale#test#SetFilename('../eslint-test-files/react-app/subdir/testfile.js') + + GivenCommandOutput ['4.9.0'] + AssertFixer + \ { + \ 'command': (has('win32') ? 'node.exe ' : '') + \ . ale#Escape(ale#path#Simplify(g:dir . '/../eslint-test-files/react-app/node_modules/eslint/bin/eslint.js')) + \ . ' --stdin-filename %s --stdin --fix-dry-run --format=json', + \ 'process_with': 'ale#fixers#eslint#ProcessFixDryRunOutput', + \ } Execute(--fix-to-stdout should be used for eslint_d): call ale#test#SetFilename('../eslint-test-files/app-with-eslint-d/testfile.js') - AssertEqual + AssertFixer \ { \ 'read_temporary_file': 1, \ 'command': \ ale#Escape(ale#path#Simplify(g:dir . '/../eslint-test-files/app-with-eslint-d/node_modules/.bin/eslint_d')) \ . ' -c ' . ale#Escape(ale#path#Simplify(g:dir . '/../eslint-test-files/package.json')) \ . ' --fix %t', - \ }, - \ ale#fixers#eslint#ApplyFixForVersion(bufnr(''), ['']) + \ } " The option should be used when eslint_d is new enough. " We look at the ESLint version instead of the eslint_d version. - AssertEqual + GivenCommandOutput ['v3.19.0 (eslint_d v4.2.0)'] + AssertFixer \ { \ 'command': \ ale#Escape(ale#path#Simplify(g:dir . '/../eslint-test-files/app-with-eslint-d/node_modules/.bin/eslint_d')) \ . ' --stdin-filename %s --stdin --fix-to-stdout', \ 'process_with': 'ale#fixers#eslint#ProcessEslintDOutput', - \ }, - \ ale#fixers#eslint#ApplyFixForVersion(bufnr(''), ['v3.19.0 (eslint_d v4.2.0)']) + \ } " The option should be used for new versions too. - AssertEqual + GivenCommandOutput ['4.9.0'] + AssertFixer \ { \ 'command': \ ale#Escape(ale#path#Simplify(g:dir . '/../eslint-test-files/app-with-eslint-d/node_modules/.bin/eslint_d')) \ . ' --stdin-filename %s --stdin --fix-to-stdout', \ 'process_with': 'ale#fixers#eslint#ProcessEslintDOutput', - \ }, - \ ale#fixers#eslint#ApplyFixForVersion(bufnr(''), ['4.9.0']) - -Execute(The version number should be cached): - call ale#test#SetFilename('../eslint-test-files/react-app/subdir-with-config/testfile.js') - - " Call the second callback with the version output. - call ale#fixers#eslint#ApplyFixForVersion(bufnr(''), ['4.9.0']) - - " The version command should be skipped. - AssertEqual - \ { - \ 'chain_with': 'ale#fixers#eslint#ApplyFixForVersion', - \ 'command': '', - \ }, - \ ale#fixers#eslint#Fix(bufnr('')) - - " Call it again without the version output. We should use the newer command. - AssertEqual - \ { - \ 'command': (has('win32') ? 'node.exe ' : '') - \ . ale#Escape(ale#path#Simplify(g:dir . '/../eslint-test-files/react-app/node_modules/eslint/bin/eslint.js')) - \ . ' --stdin-filename %s --stdin --fix-dry-run --format=json', - \ 'process_with': 'ale#fixers#eslint#ProcessFixDryRunOutput', - \ }, - \ ale#fixers#eslint#ApplyFixForVersion(bufnr(''), []) + \ } Execute(The --fix-dry-run post-processor should handle JSON output correctly): AssertEqual diff --git a/test/fixers/test_prettier_eslint_fixer.callback.vader b/test/fixers/test_prettier_eslint_fixer.callback.vader index 5c899d86..90e11672 100644 --- a/test/fixers/test_prettier_eslint_fixer.callback.vader +++ b/test/fixers/test_prettier_eslint_fixer.callback.vader @@ -1,54 +1,36 @@ Before: - call ale#test#SetDirectory('/testplugin/test/fixers') - - Save g:ale_javascript_prettier_eslint_executable - Save g:ale_javascript_prettier_eslint_use_global - Save g:ale_javascript_prettier_eslint_options - - unlet! g:ale_javascript_prettier_eslint_executable - unlet! g:ale_javascript_prettier_eslint_use_global - unlet! g:ale_javascript_prettier_eslint_options - - call ale#fixers#prettier_eslint#SetOptionDefaults() + call ale#assert#SetUpFixerTest('javascript', 'prettier_eslint') After: - Restore - - unlet! b:ale_javascript_prettier_eslint_executable - unlet! b:ale_javascript_prettier_eslint_use_global - unlet! b:ale_javascript_prettier_eslint_options - - call ale#test#RestoreDirectory() - call ale#semver#ResetVersionCache() + call ale#assert#TearDownFixerTest() Execute(The default command should be correct): - AssertEqual + AssertFixer \ { \ 'read_temporary_file': 1, \ 'command': \ ale#Escape('prettier-eslint') \ . ' %t' \ . ' --write' - \ }, - \ ale#fixers#prettier_eslint#ApplyFixForVersion(bufnr(''), []) + \ } Execute(Additional options should be used when set): let b:ale_javascript_prettier_eslint_options = '--foobar' - AssertEqual + AssertFixer \ { \ 'read_temporary_file': 1, \ 'command': \ ale#Escape('prettier-eslint') \ . ' %t' \ . ' --foobar --write' - \ }, - \ ale#fixers#prettier_eslint#ApplyFixForVersion(bufnr(''), []) + \ } Execute(--eslint-config-path should be set for 4.2.0 and up): call ale#test#SetFilename('eslint-test-files/react-app/foo/bar.js') - AssertEqual + GivenCommandOutput ['4.2.0'] + AssertFixer \ { \ 'read_temporary_file': 1, \ 'command': @@ -56,58 +38,57 @@ Execute(--eslint-config-path should be set for 4.2.0 and up): \ . ' %t' \ . ' --eslint-config-path ' . ale#Escape(ale#path#Simplify(g:dir . '/eslint-test-files/react-app/.eslintrc.js')) \ . ' --write' - \ }, - \ ale#fixers#prettier_eslint#ApplyFixForVersion(bufnr(''), ['4.2.0']) + \ } Execute(--eslint-config-path shouldn't be used for older versions): call ale#test#SetFilename('eslint-test-files/react-app/foo/bar.js') - AssertEqual + AssertFixer \ { \ 'read_temporary_file': 1, \ 'command': \ ale#Escape('prettier-eslint') \ . ' %t' \ . ' --write' - \ }, - \ ale#fixers#prettier_eslint#ApplyFixForVersion(bufnr(''), []) + \ } Execute(The version check should be correct): - AssertEqual + AssertFixer [ + \ ale#Escape('prettier-eslint') . ' --version', \ { - \ 'chain_with': 'ale#fixers#prettier_eslint#ApplyFixForVersion', - \ 'command': ale#Escape('prettier-eslint') . ' --version', - \ }, - \ ale#fixers#prettier_eslint#Fix(bufnr('')) + \ 'read_temporary_file': 1, + \ 'command': + \ ale#Escape('prettier-eslint') + \ . ' %t' + \ . ' --write' + \ } + \] Execute(The new --stdin-filepath option should be used when the version is new enough): call ale#test#SetFilename('eslint-test-files/react-app/foo/bar.js') - AssertEqual + GivenCommandOutput ['4.4.0'] + AssertFixer \ { \ 'command': ale#path#CdString(expand('%:p:h')) \ . ale#Escape('prettier-eslint') \ . ' --eslint-config-path ' . ale#Escape(ale#path#Simplify(g:dir . '/eslint-test-files/react-app/.eslintrc.js')) \ . ' --stdin-filepath %s --stdin', - \ }, - \ ale#fixers#prettier_eslint#ApplyFixForVersion(bufnr(''), ['4.4.0']) + \ } Execute(The version number should be cached): - call ale#fixers#prettier_eslint#ApplyFixForVersion(bufnr(''), ['4.4.0']) - - " The version command should be skipped. - AssertEqual - \ { - \ 'chain_with': 'ale#fixers#prettier_eslint#ApplyFixForVersion', - \ 'command': '', - \ }, - \ ale#fixers#prettier_eslint#Fix(bufnr('')) - - " The newer command should be used. - AssertEqual + GivenCommandOutput ['4.4.0'] + AssertFixer \ { \ 'command': ale#path#CdString(expand('%:p:h')) \ . ale#Escape('prettier-eslint') \ . ' --stdin-filepath %s --stdin', - \ }, - \ ale#fixers#prettier_eslint#ApplyFixForVersion(bufnr(''), []) + \ } + + GivenCommandOutput [] + AssertFixer + \ { + \ 'command': ale#path#CdString(expand('%:p:h')) + \ . ale#Escape('prettier-eslint') + \ . ' --stdin-filepath %s --stdin', + \ } diff --git a/test/fixers/test_prettier_fixer_callback.vader b/test/fixers/test_prettier_fixer_callback.vader index 05ed421e..02bae9c1 100644 --- a/test/fixers/test_prettier_fixer_callback.vader +++ b/test/fixers/test_prettier_fixer_callback.vader @@ -1,296 +1,286 @@ Before: - call ale#test#SetDirectory('/testplugin/test/fixers') - Save g:ale_javascript_prettier_executable - Save g:ale_javascript_prettier_options + call ale#assert#SetUpFixerTest('javascript', 'prettier') - " Use an invalid global executable, so we don't match it. - let g:ale_javascript_prettier_executable = 'xxxinvalid' - let g:ale_javascript_prettier_options = '' - - call ale#test#SetDirectory('/testplugin/test/fixers') silent cd .. silent cd command_callback let g:dir = getcwd() After: - let g:ale_has_override = {} + call ale#assert#TearDownFixerTest() - call ale#test#RestoreDirectory() - call ale#semver#ResetVersionCache() + let g:ale_has_override = {} Execute(The prettier callback should return the correct default values): call ale#test#SetFilename('../prettier-test-files/testfile.js') - AssertEqual + AssertFixer \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape(g:ale_javascript_prettier_executable) \ . ' %t' \ . ' --write', - \ }, - \ ale#fixers#prettier#ApplyFixForVersion(bufnr(''), []) + \ } Execute(The --config option should not be set automatically): let g:ale_javascript_prettier_use_local_config = 1 call ale#test#SetFilename('../prettier-test-files/with_config/testfile.js') - AssertEqual + AssertFixer \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape(g:ale_javascript_prettier_executable) \ . ' %t' \ . ' --write', - \ }, - \ ale#fixers#prettier#ApplyFixForVersion(bufnr(''), []) + \ } Execute(The prettier callback should include custom prettier options): let g:ale_javascript_prettier_options = '--no-semi' call ale#test#SetFilename('../prettier-test-files/with_config/testfile.js') - AssertEqual + AssertFixer \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape(g:ale_javascript_prettier_executable) \ . ' %t' \ . ' --no-semi' \ . ' --write', - \ }, - \ ale#fixers#prettier#ApplyFixForVersion(bufnr(''), []) + \ } Execute(The version check should be correct): call ale#test#SetFilename('../prettier-test-files/testfile.js') - AssertEqual - \ { - \ 'chain_with': 'ale#fixers#prettier#ApplyFixForVersion', - \ 'command': ale#Escape(g:ale_javascript_prettier_executable) - \ . ' --version', - \ }, - \ ale#fixers#prettier#Fix(bufnr('')) + AssertFixer [ + \ ale#Escape('prettier') . ' --version', + \ {'read_temporary_file': 1, 'command': ale#Escape('prettier') . ' %t --write'} + \] Execute(--stdin-filepath should be used when prettier is new enough): let g:ale_javascript_prettier_options = '--no-semi' call ale#test#SetFilename('../prettier-test-files/with_config/testfile.js') - AssertEqual + GivenCommandOutput ['1.6.0'] + AssertFixer \ { \ 'command': ale#path#CdString(expand('%:p:h')) \ . ale#Escape(g:ale_javascript_prettier_executable) \ . ' --no-semi' \ . ' --stdin-filepath %s --stdin', - \ }, - \ ale#fixers#prettier#ApplyFixForVersion(bufnr(''), ['1.6.0']) + \ } Execute(The version number should be cached): call ale#test#SetFilename('../prettier-test-files/with_config/testfile.js') - " Call the second callback with the version output. - call ale#fixers#prettier#ApplyFixForVersion(bufnr(''), ['1.6.0']) - - " Call it again without the version output. We should use the newer command. - AssertEqual + GivenCommandOutput ['1.6.0'] + AssertFixer \ { \ 'command': ale#path#CdString(expand('%:p:h')) \ . ale#Escape(g:ale_javascript_prettier_executable) \ . ' --stdin-filepath %s --stdin', - \ }, - \ ale#fixers#prettier#ApplyFixForVersion(bufnr(''), []) + \ } + + GivenCommandOutput [] + AssertFixer + \ { + \ 'command': ale#path#CdString(expand('%:p:h')) + \ . ale#Escape(g:ale_javascript_prettier_executable) + \ . ' --stdin-filepath %s --stdin', + \ } Execute(Should set --parser to `babylon` by default, < 1.16.0): call ale#test#SetFilename('../prettier-test-files/testfile') set filetype=javascript - AssertEqual + GivenCommandOutput ['1.6.0'] + AssertFixer \ { \ 'command': ale#path#CdString(expand('%:p:h')) \ . ale#Escape(g:ale_javascript_prettier_executable) \ . ' --parser babylon' \ . ' --stdin-filepath %s --stdin', - \ }, - \ ale#fixers#prettier#ApplyFixForVersion(bufnr(''), ['1.6.0']) + \ } Execute(Should set --parser to `babel` by default, >= 1.16.0): call ale#test#SetFilename('../prettier-test-files/testfile') set filetype=javascript - AssertEqual + GivenCommandOutput ['1.16.0'] + AssertFixer \ { \ 'command': ale#path#CdString(expand('%:p:h')) \ . ale#Escape(g:ale_javascript_prettier_executable) \ . ' --parser babel' \ . ' --stdin-filepath %s --stdin', - \ }, - \ ale#fixers#prettier#ApplyFixForVersion(bufnr(''), ['1.16.0']) + \ } Execute(Should set --parser based on filetype, TypeScript): call ale#test#SetFilename('../prettier-test-files/testfile') set filetype=typescript - AssertEqual + GivenCommandOutput ['1.6.0'] + AssertFixer \ { \ 'command': ale#path#CdString(expand('%:p:h')) \ . ale#Escape(g:ale_javascript_prettier_executable) \ . ' --parser typescript' \ . ' --stdin-filepath %s --stdin', - \ }, - \ ale#fixers#prettier#ApplyFixForVersion(bufnr(''), ['1.6.0']) + \ } Execute(Should set --parser based on filetype, CSS): call ale#test#SetFilename('../prettier-test-files/testfile') set filetype=css - AssertEqual + GivenCommandOutput ['1.6.0'] + AssertFixer \ { \ 'command': ale#path#CdString(expand('%:p:h')) \ . ale#Escape(g:ale_javascript_prettier_executable) \ . ' --parser css' \ . ' --stdin-filepath %s --stdin', - \ }, - \ ale#fixers#prettier#ApplyFixForVersion(bufnr(''), ['1.6.0']) + \ } Execute(Should set --parser based on filetype, LESS): call ale#test#SetFilename('../prettier-test-files/testfile') set filetype=less - AssertEqual + GivenCommandOutput ['1.6.0'] + AssertFixer \ { \ 'command': ale#path#CdString(expand('%:p:h')) \ . ale#Escape(g:ale_javascript_prettier_executable) \ . ' --parser less' \ . ' --stdin-filepath %s --stdin', - \ }, - \ ale#fixers#prettier#ApplyFixForVersion(bufnr(''), ['1.6.0']) + \ } Execute(Should set --parser based on filetype, SCSS): call ale#test#SetFilename('../prettier-test-files/testfile') set filetype=scss - AssertEqual + GivenCommandOutput ['1.6.0'] + AssertFixer \ { \ 'command': ale#path#CdString(expand('%:p:h')) \ . ale#Escape(g:ale_javascript_prettier_executable) \ . ' --parser scss' \ . ' --stdin-filepath %s --stdin', - \ }, - \ ale#fixers#prettier#ApplyFixForVersion(bufnr(''), ['1.6.0']) + \ } Execute(Should set --parser based on filetype, JSON): call ale#test#SetFilename('../prettier-test-files/testfile') set filetype=json - AssertEqual + GivenCommandOutput ['1.6.0'] + AssertFixer \ { \ 'command': ale#path#CdString(expand('%:p:h')) \ . ale#Escape(g:ale_javascript_prettier_executable) \ . ' --parser json' \ . ' --stdin-filepath %s --stdin', - \ }, - \ ale#fixers#prettier#ApplyFixForVersion(bufnr(''), ['1.6.0']) + \ } Execute(Should set --parser based on filetype, JSON5): call ale#test#SetFilename('../prettier-test-files/testfile') set filetype=json5 - AssertEqual + GivenCommandOutput ['1.6.0'] + AssertFixer \ { \ 'command': ale#path#CdString(expand('%:p:h')) \ . ale#Escape(g:ale_javascript_prettier_executable) \ . ' --parser json5' \ . ' --stdin-filepath %s --stdin', - \ }, - \ ale#fixers#prettier#ApplyFixForVersion(bufnr(''), ['1.6.0']) + \ } Execute(Should set --parser based on filetype, GraphQL): call ale#test#SetFilename('../prettier-test-files/testfile') set filetype=graphql - AssertEqual + GivenCommandOutput ['1.6.0'] + AssertFixer \ { \ 'command': ale#path#CdString(expand('%:p:h')) \ . ale#Escape(g:ale_javascript_prettier_executable) \ . ' --parser graphql' \ . ' --stdin-filepath %s --stdin', - \ }, - \ ale#fixers#prettier#ApplyFixForVersion(bufnr(''), ['1.6.0']) + \ } Execute(Should set --parser based on filetype, Markdown): call ale#test#SetFilename('../prettier-test-files/testfile') set filetype=markdown - AssertEqual + GivenCommandOutput ['1.6.0'] + AssertFixer \ { \ 'command': ale#path#CdString(expand('%:p:h')) \ . ale#Escape(g:ale_javascript_prettier_executable) \ . ' --parser markdown' \ . ' --stdin-filepath %s --stdin', - \ }, - \ ale#fixers#prettier#ApplyFixForVersion(bufnr(''), ['1.6.0']) + \ } Execute(Should set --parser based on filetype, Vue): call ale#test#SetFilename('../prettier-test-files/testfile') set filetype=vue - AssertEqual + GivenCommandOutput ['1.6.0'] + AssertFixer \ { \ 'command': ale#path#CdString(expand('%:p:h')) \ . ale#Escape(g:ale_javascript_prettier_executable) \ . ' --parser vue' \ . ' --stdin-filepath %s --stdin', - \ }, - \ ale#fixers#prettier#ApplyFixForVersion(bufnr(''), ['1.6.0']) + \ } Execute(Should set --parser based on filetype, YAML): call ale#test#SetFilename('../prettier-test-files/testfile') set filetype=yaml - AssertEqual + GivenCommandOutput ['1.6.0'] + AssertFixer \ { \ 'command': ale#path#CdString(expand('%:p:h')) \ . ale#Escape(g:ale_javascript_prettier_executable) \ . ' --parser yaml' \ . ' --stdin-filepath %s --stdin', - \ }, - \ ale#fixers#prettier#ApplyFixForVersion(bufnr(''), ['1.6.0']) + \ } Execute(Should set --parser based on filetype, HTML): call ale#test#SetFilename('../prettier-test-files/testfile') set filetype=html - AssertEqual + GivenCommandOutput ['1.6.0'] + AssertFixer \ { \ 'command': ale#path#CdString(expand('%:p:h')) \ . ale#Escape(g:ale_javascript_prettier_executable) \ . ' --parser html' \ . ' --stdin-filepath %s --stdin', - \ }, - \ ale#fixers#prettier#ApplyFixForVersion(bufnr(''), ['1.6.0']) + \ } Execute(Should set --parser based on first filetype of multiple filetypes): call ale#test#SetFilename('../prettier-test-files/testfile') set filetype=css.scss - AssertEqual + GivenCommandOutput ['1.6.0'] + AssertFixer \ { \ 'command': ale#path#CdString(expand('%:p:h')) \ . ale#Escape(g:ale_javascript_prettier_executable) \ . ' --parser css' \ . ' --stdin-filepath %s --stdin', - \ }, - \ ale#fixers#prettier#ApplyFixForVersion(bufnr(''), ['1.6.0']) + \ } Execute(The prettier_d post-processor should permit regular JavaScript content): AssertEqual diff --git a/test/lsp/test_lsp_startup.vader b/test/lsp/test_lsp_startup.vader index 2fbd32de..028ec9b1 100644 --- a/test/lsp/test_lsp_startup.vader +++ b/test/lsp/test_lsp_startup.vader @@ -3,6 +3,7 @@ Before: let g:ale_run_synchronously = 1 unlet! g:ale_run_synchronously_callbacks + unlet! g:ale_run_synchronously_emulate_commands runtime autoload/ale/lsp.vim runtime autoload/ale/lsp_linter.vim @@ -234,6 +235,7 @@ After: call ale#linter#Reset() call ale#lsp#ResetConnections() + unlet! g:ale_run_synchronously_callbacks unlet! g:job_map unlet! g:emulate_job_failure unlet! g:next_job_id diff --git a/test/sign/test_linting_sets_signs.vader b/test/sign/test_linting_sets_signs.vader index c72b0882..a8d5761f 100644 --- a/test/sign/test_linting_sets_signs.vader +++ b/test/sign/test_linting_sets_signs.vader @@ -13,6 +13,7 @@ Before: let g:ale_buffer_info = {} let g:ale_run_synchronously = 1 + unlet! g:ale_run_synchronously_callbacks let g:ale_set_signs = 1 " Disable features we don't need for these tests. let g:ale_set_quickfix = 0 @@ -58,6 +59,7 @@ After: delfunction TestCallback delfunction CollectSigns + unlet! g:ale_run_synchronously_callbacks sign unplace * call ale#linter#Reset() diff --git a/test/sign/test_sign_placement.vader b/test/sign/test_sign_placement.vader index 41bed715..f0b3ba2f 100644 --- a/test/sign/test_sign_placement.vader +++ b/test/sign/test_sign_placement.vader @@ -87,6 +87,7 @@ Before: After: Restore + unlet! g:ale_run_synchronously_callbacks unlet! g:loclist delfunction GenerateResults delfunction ParseSigns diff --git a/test/test_deferred_command_string.vader b/test/test_deferred_command_string.vader index 4d0c8977..026be6fe 100644 --- a/test/test_deferred_command_string.vader +++ b/test/test_deferred_command_string.vader @@ -17,10 +17,14 @@ Before: \ 'read_buffer': 0, \}) + " Run the test commands in the shell. + let g:ale_run_synchronously_emulate_commands = 0 + After: Restore call ale#assert#TearDownLinterTest() + unlet! g:ale_run_synchronously_callbacks Given foobar (Some imaginary filetype): Execute(It should be possible to compute an executable to check based on the result of commands): diff --git a/test/test_eslint_executable_detection.vader b/test/test_eslint_executable_detection.vader index c1438ed8..0d12e665 100644 --- a/test/test_eslint_executable_detection.vader +++ b/test/test_eslint_executable_detection.vader @@ -54,11 +54,17 @@ Execute(eslint_d should be detected correctly): Execute(eslint.js executables should be run with node on Windows): call ale#test#SetFilename('eslint-test-files/react-app/subdir/testfile.js') - let g:ale_has_override['win32'] = 1 " We have to execute the file with node. - AssertEqual - \ ale#Escape('node.exe') . ' ' - \ . ale#Escape(ale#path#Simplify(g:dir . '/eslint-test-files/react-app/node_modules/eslint/bin/eslint.js')) - \ . ' -f unix --stdin --stdin-filename %s', - \ ale#handlers#eslint#GetCommand(bufnr('')) + if has('win32') + AssertEqual + \ ale#Escape('node.exe') . ' ' + \ . ale#Escape(ale#path#Simplify(g:dir . '/eslint-test-files/react-app/node_modules/eslint/bin/eslint.js')) + \ . ' -f unix --stdin --stdin-filename %s', + \ ale#handlers#eslint#GetCommand(bufnr('')) + else + AssertEqual + \ ale#Escape(ale#path#Simplify(g:dir . '/eslint-test-files/react-app/node_modules/eslint/bin/eslint.js')) + \ . ' -f unix --stdin --stdin-filename %s', + \ ale#handlers#eslint#GetCommand(bufnr('')) + endif diff --git a/test/test_flow_command.vader b/test/test_flow_command.vader index 9fc38930..4805e121 100644 --- a/test/test_flow_command.vader +++ b/test/test_flow_command.vader @@ -1,48 +1,46 @@ Before: runtime ale_linters/javascript/flow.vim - call ale#test#SetDirectory('/testplugin/test') + call ale#assert#SetUpLinterTest('javascript', 'flow') + call ale#test#SetDirectory('/testplugin/test/') After: unlet! b:ale_javascript_flow_use_respect_pragma - - call ale#test#RestoreDirectory() - call ale#linter#Reset() - call ale#semver#ResetVersionCache() + call ale#assert#TearDownLinterTest() Execute(flow should return a command to run if a .flowconfig file exists): call ale#test#SetFilename('flow/a/sub/dummy') - AssertEqual + AssertLinter 'flow', \ ale#Escape('flow') \ . ' check-contents --respect-pragma --json --from ale %s < %t' - \ . (!has('win32') ? '; echo' : ''), - \ ale_linters#javascript#flow#GetCommand(bufnr('%'), []) + \ . (!has('win32') ? '; echo' : '') Execute(flow should not use the respect pragma argument if the option is off): call ale#test#SetFilename('flow/a/sub/dummy') let b:ale_javascript_flow_use_respect_pragma = 0 - AssertEqual + AssertLinter 'flow', \ ale#Escape('flow') \ . ' check-contents --json --from ale %s < %t' - \ . (!has('win32') ? '; echo' : ''), - \ ale_linters#javascript#flow#GetCommand(bufnr('%'), []) + \ . (!has('win32') ? '; echo' : '') Execute(flow should should not use --respect-pragma for old versions): call ale#test#SetFilename('flow/a/sub/dummy') - AssertEqual + GivenCommandOutput [ + \ 'Warning: `flow --version` is deprecated in favor of `flow version`', + \ 'Flow, a static type checker for JavaScript, version 0.27.0', + \] + AssertLinter 'flow', [ + \ ale#Escape('flow') . ' --version', \ ale#Escape('flow') \ . ' check-contents --json --from ale %s < %t' \ . (!has('win32') ? '; echo' : ''), - \ ale_linters#javascript#flow#GetCommand(bufnr('%'), [ - \ 'Warning: `flow --version` is deprecated in favor of `flow version`', - \ 'Flow, a static type checker for JavaScript, version 0.27.0', - \ ]) + \] Execute(flow should not return a command to run if no .flowconfig file exists): call ale#test#SetFilename('flow/b/sub/dummy') - AssertEqual '', ale_linters#javascript#flow#GetCommand(bufnr('%'), []) + AssertLinterNotExecuted diff --git a/test/test_semver_utils.vader b/test/test_semver_utils.vader index 62483505..b38feb06 100644 --- a/test/test_semver_utils.vader +++ b/test/test_semver_utils.vader @@ -1,32 +1,20 @@ After: call ale#semver#ResetVersionCache() -Execute(GetVersion should return the version from the lines of output): +Execute(ParseVersion should return the version from the lines of output): " We should be able to parse the semver string from flake8 - AssertEqual [3, 0, 4], ale#semver#GetVersion('dummy', [ + AssertEqual [3, 0, 4], ale#semver#ParseVersion([ \ '3.0.4 (mccabe: 0.5.2, pyflakes: 1.2.3, pycodestyle: 2.0.0) CPython 2.7.12 on Linux', \ '1.2.3', \]) -Execute(GetVersion should return an empty list when no vesrion can be found): - AssertEqual [], ale#semver#GetVersion('dummy', ['x']) - AssertEqual [], ale#semver#GetVersion('dummy', []) +Execute(ParseVersion should return an empty list when no vesrion can be found): + AssertEqual [], ale#semver#ParseVersion(['x']) + AssertEqual [], ale#semver#ParseVersion([]) -Execute(GetVersion should cache the version): - AssertEqual [], ale#semver#GetVersion('dummy', []) - AssertEqual [3, 4, 7], ale#semver#GetVersion('dummy', ['Version 3.4.7']) - AssertEqual [3, 4, 17], ale#semver#GetVersion('dummy', ['Version 3.4.17']) - AssertEqual [3, 4, 17], ale#semver#GetVersion('dummy', []) - -Execute(GetVersion should tolerate missing patch numbers): +Execute(ParseVersion should tolerate missing patch numbers): " This goes against the semver spec, but we handle it anyway. - AssertEqual [3, 4, 0], ale#semver#GetVersion('dummy', ['Version 3.4']) - -Execute(HasVersion should return 1 when the version has been cached): - call ale#semver#GetVersion('dummy', []) - AssertEqual 0, ale#semver#HasVersion('dummy') - call ale#semver#GetVersion('dummy', ['3.4.7']) - AssertEqual 1, ale#semver#HasVersion('dummy') + AssertEqual [3, 4, 0], ale#semver#ParseVersion(['Version 3.4']) Execute(GTE should compare triples correctly): Assert ale#semver#GTE([3, 0, 4], [3, 0, 0])