diff options
Diffstat (limited to 'test')
151 files changed, 5150 insertions, 570 deletions
diff --git a/test/command_callback/mix_paths/wrapped_project/mix.exs b/test/command_callback/mix_paths/wrapped_project/mix.exs new file mode 100644 index 00000000..d2d855e6 --- /dev/null +++ b/test/command_callback/mix_paths/wrapped_project/mix.exs @@ -0,0 +1 @@ +use Mix.Config diff --git a/test/elm-test-files/app/node_modules/.bin/elm-make b/test/command_callback/php_paths/project-with-php-cs-fixer/test.php index e69de29b..e69de29b 100644 --- a/test/elm-test-files/app/node_modules/.bin/elm-make +++ b/test/command_callback/php_paths/project-with-php-cs-fixer/test.php diff --git a/test/command_callback/php_paths/project-with-php-cs-fixer/vendor/bin/php-cs-fixer b/test/command_callback/php_paths/project-with-php-cs-fixer/vendor/bin/php-cs-fixer new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/test/command_callback/php_paths/project-with-php-cs-fixer/vendor/bin/php-cs-fixer diff --git a/test/command_callback/php_paths/project-without-php-cs-fixer/test.php b/test/command_callback/php_paths/project-without-php-cs-fixer/test.php new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/test/command_callback/php_paths/project-without-php-cs-fixer/test.php diff --git a/test/command_callback/python_paths/with_virtualenv/env/Scripts/black.exe b/test/command_callback/python_paths/with_virtualenv/env/Scripts/black.exe new file mode 100755 index 00000000..e69de29b --- /dev/null +++ b/test/command_callback/python_paths/with_virtualenv/env/Scripts/black.exe diff --git a/test/command_callback/python_paths/with_virtualenv/env/bin/black b/test/command_callback/python_paths/with_virtualenv/env/bin/black new file mode 100755 index 00000000..e69de29b --- /dev/null +++ b/test/command_callback/python_paths/with_virtualenv/env/bin/black diff --git a/test/command_callback/scala_paths/dummy.scala b/test/command_callback/scala_paths/dummy.scala new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/test/command_callback/scala_paths/dummy.scala diff --git a/test/command_callback/test_c_clang_command_callbacks.vader b/test/command_callback/test_c_clang_command_callbacks.vader index d6fc8ca6..2f6d4dd0 100644 --- a/test/command_callback/test_c_clang_command_callbacks.vader +++ b/test/command_callback/test_c_clang_command_callbacks.vader @@ -30,10 +30,10 @@ Execute(The executable should be configurable): Execute(The executable should be used in the command): AssertEqual \ ale#Escape('clang') . b:command_tail, - \ ale_linters#c#clang#GetCommand(bufnr('')) + \ ale_linters#c#clang#GetCommand(bufnr(''), []) let b:ale_c_clang_executable = 'foobar' AssertEqual \ ale#Escape('foobar') . b:command_tail, - \ ale_linters#c#clang#GetCommand(bufnr('')) + \ ale_linters#c#clang#GetCommand(bufnr(''), []) diff --git a/test/command_callback/test_c_flawfinder_command_callbacks.vader b/test/command_callback/test_c_flawfinder_command_callbacks.vader new file mode 100644 index 00000000..38a602dd --- /dev/null +++ b/test/command_callback/test_c_flawfinder_command_callbacks.vader @@ -0,0 +1,51 @@ +Before: + Save g:ale_c_flawfinder_executable + Save g:ale_c_flawfinder_options + Save g:ale_c_flawfinder_minlevel + + unlet! g:ale_c_flawfinder_executable + unlet! b:ale_c_flawfinder_executable + unlet! g:ale_c_flawfinder_options + unlet! b:ale_c_flawfinder_options + unlet! g:ale_c_flawfinder_minlevel + unlet! b:ale_c_flawfinder_minlevel + + runtime ale_linters/c/flawfinder.vim + +After: + unlet! b:ale_c_flawfinder_executable + unlet! b:ale_c_flawfinder_options + unlet! b:ale_c_flawfinder_minlevel + + Restore + call ale#linter#Reset() + +Execute(The flawfinder command should be correct): + AssertEqual + \ ale#Escape('flawfinder') + \ . ' -CDQS --minlevel=1 %t', + \ ale_linters#c#flawfinder#GetCommand(bufnr('')) + +Execute(The minlevel of flawfinder should be configurable): + let b:ale_c_flawfinder_minlevel = 8 + + AssertEqual + \ ale#Escape('flawfinder') + \ . ' -CDQS --minlevel=8 %t', + \ ale_linters#c#flawfinder#GetCommand(bufnr('')) + +Execute(Additional flawfinder options should be configurable): + let b:ale_c_flawfinder_options = ' --foobar' + + AssertEqual + \ ale#Escape('flawfinder') + \ . ' -CDQS --foobar --minlevel=1 %t', + \ ale_linters#c#flawfinder#GetCommand(bufnr('')) + +Execute(The flawfinder exectable should be configurable): + let b:ale_c_flawfinder_executable = 'foo/bar' + + AssertEqual + \ ale#Escape('foo/bar') + \ . ' -CDQS --minlevel=1 %t', + \ ale_linters#c#flawfinder#GetCommand(bufnr('')) diff --git a/test/command_callback/test_c_gcc_command_callbacks.vader b/test/command_callback/test_c_gcc_command_callbacks.vader index 8038f410..3557576e 100644 --- a/test/command_callback/test_c_gcc_command_callbacks.vader +++ b/test/command_callback/test_c_gcc_command_callbacks.vader @@ -30,10 +30,10 @@ Execute(The executable should be configurable): Execute(The executable should be used in the command): AssertEqual \ ale#Escape('gcc') . b:command_tail, - \ ale_linters#c#gcc#GetCommand(bufnr('')) + \ ale_linters#c#gcc#GetCommand(bufnr(''), []) let b:ale_c_gcc_executable = 'foobar' AssertEqual \ ale#Escape('foobar') . b:command_tail, - \ ale_linters#c#gcc#GetCommand(bufnr('')) + \ ale_linters#c#gcc#GetCommand(bufnr(''), []) diff --git a/test/command_callback/test_cargo_command_callbacks.vader b/test/command_callback/test_cargo_command_callbacks.vader index 9c06f27d..f674645f 100644 --- a/test/command_callback/test_cargo_command_callbacks.vader +++ b/test/command_callback/test_cargo_command_callbacks.vader @@ -1,11 +1,15 @@ Before: Save g:ale_rust_cargo_use_check Save g:ale_rust_cargo_check_all_targets + Save g:ale_rust_cargo_check_tests + Save g:ale_rust_cargo_check_examples Save g:ale_rust_cargo_default_feature_behavior Save g:ale_rust_cargo_include_features unlet! g:ale_rust_cargo_use_check - unlet! g:ale_cargo_check_all_targets + unlet! g:ale_rust_cargo_check_all_targets + unlet! g:ale_rust_cargo_check_tests + unlet! g:ale_rust_cargo_check_examples unlet! g:ale_rust_cargo_default_feature_behavior unlet! g:ale_rust_cargo_include_features @@ -119,6 +123,38 @@ Execute(--all-targets should be used when g:ale_rust_cargo_check_all_targets is AssertEqual '', ale_linters#rust#cargo#VersionCheck(bufnr('')) +Execute(--tests should be used when g:ale_rust_cargo_check_tests is set to 1): + let g:ale_rust_cargo_check_tests = 1 + + AssertEqual + \ 'cargo check --tests' . g:suffix, + \ ale_linters#rust#cargo#GetCommand(bufnr(''), [ + \ 'cargo 0.22.0 (3423351a5 2017-10-06)', + \ ]) + + " We should cache the version check + AssertEqual + \ 'cargo check --tests' . g:suffix, + \ ale_linters#rust#cargo#GetCommand(bufnr(''), []) + + AssertEqual '', ale_linters#rust#cargo#VersionCheck(bufnr('')) + +Execute(--examples should be used when g:ale_rust_cargo_check_examples is set to 1): + let g:ale_rust_cargo_check_examples = 1 + + AssertEqual + \ 'cargo check --examples' . g:suffix, + \ ale_linters#rust#cargo#GetCommand(bufnr(''), [ + \ 'cargo 0.22.0 (3423351a5 2017-10-06)', + \ ]) + + " We should cache the version check + AssertEqual + \ 'cargo check --examples' . g:suffix, + \ ale_linters#rust#cargo#GetCommand(bufnr(''), []) + + AssertEqual '', ale_linters#rust#cargo#VersionCheck(bufnr('')) + Execute(--no-default-features should be used when g:ale_rust_cargo_default_feature_behavior is none): let g:ale_rust_cargo_default_feature_behavior = 'none' diff --git a/test/command_callback/test_cpp_clang_command_callbacks.vader b/test/command_callback/test_cpp_clang_command_callbacks.vader index 67d6898c..8c671115 100644 --- a/test/command_callback/test_cpp_clang_command_callbacks.vader +++ b/test/command_callback/test_cpp_clang_command_callbacks.vader @@ -30,10 +30,10 @@ Execute(The executable should be configurable): Execute(The executable should be used in the command): AssertEqual \ ale#Escape('clang++') . b:command_tail, - \ ale_linters#cpp#clang#GetCommand(bufnr('')) + \ ale_linters#cpp#clang#GetCommand(bufnr(''), []) let b:ale_cpp_clang_executable = 'foobar' AssertEqual \ ale#Escape('foobar') . b:command_tail, - \ ale_linters#cpp#clang#GetCommand(bufnr('')) + \ ale_linters#cpp#clang#GetCommand(bufnr(''), []) diff --git a/test/command_callback/test_cpp_cquery_command_callbacks.vader b/test/command_callback/test_cpp_cquery_command_callbacks.vader new file mode 100644 index 00000000..89a3e225 --- /dev/null +++ b/test/command_callback/test_cpp_cquery_command_callbacks.vader @@ -0,0 +1,48 @@ +" Author: Ben Falconer <ben@falconers.me.uk> +" Description: A language server for C++ + +Before: + Save g:ale_cpp_cquery_executable + Save g:ale_cpp_cquery_cache_directory + + unlet! g:ale_cpp_cquery_executable + unlet! b:ale_cpp_cquery_executable + unlet! g:ale_cpp_cquery_cache_directory + unlet! b:ale_cpp_cquery_cache_directory + + runtime ale_linters/cpp/cquery.vim + +After: + Restore + unlet! b:ale_cpp_cquery_executable + unlet! b:ale_cpp_cquery_cache_directory + call ale#linter#Reset() + +Execute(The executable should be configurable): + AssertEqual 'cquery', ale_linters#cpp#cquery#GetExecutable(bufnr('')) + + let b:ale_cpp_cquery_executable = 'foobar' + + AssertEqual 'foobar', ale_linters#cpp#cquery#GetExecutable(bufnr('')) + +Execute(The executable should be used in the command): + AssertEqual + \ ale#Escape('cquery'), + \ ale_linters#cpp#cquery#GetCommand(bufnr('')) + + let b:ale_cpp_cquery_executable = 'foobar' + + AssertEqual + \ ale#Escape('foobar'), + \ ale_linters#cpp#cquery#GetCommand(bufnr('')) + +Execute(The cache directory should be configurable): + AssertEqual + \ {'cacheDirectory': expand('$HOME/.cache/cquery')}, + \ ale_linters#cpp#cquery#GetInitializationOptions(bufnr('')) + + let b:ale_cpp_cquery_cache_directory = '/foo/bar' + + AssertEqual + \ {'cacheDirectory': '/foo/bar'}, + \ ale_linters#cpp#cquery#GetInitializationOptions(bufnr('')) diff --git a/test/command_callback/test_cpp_flawfinder_command_callbacks.vader b/test/command_callback/test_cpp_flawfinder_command_callbacks.vader new file mode 100644 index 00000000..8769ec96 --- /dev/null +++ b/test/command_callback/test_cpp_flawfinder_command_callbacks.vader @@ -0,0 +1,51 @@ +Before: + Save g:ale_cpp_flawfinder_executable + Save g:ale_cpp_flawfinder_options + Save g:ale_cpp_flawfinder_minlevel + + unlet! g:ale_cpp_flawfinder_executable + unlet! b:ale_cpp_flawfinder_executable + unlet! g:ale_cpp_flawfinder_options + unlet! b:ale_cpp_flawfinder_options + unlet! g:ale_cpp_flawfinder_minlevel + unlet! b:ale_cpp_flawfinder_minlevel + + runtime ale_linters/cpp/flawfinder.vim + +After: + unlet! b:ale_cpp_flawfinder_executable + unlet! b:ale_cpp_flawfinder_options + unlet! b:ale_cpp_flawfinder_minlevel + + Restore + call ale#linter#Reset() + +Execute(The flawfinder command should be correct): + AssertEqual + \ ale#Escape('flawfinder') + \ . ' -CDQS --minlevel=1 %t', + \ ale_linters#cpp#flawfinder#GetCommand(bufnr('')) + +Execute(The minlevel of flawfinder should be configurable): + let b:ale_cpp_flawfinder_minlevel = 8 + + AssertEqual + \ ale#Escape('flawfinder') + \ . ' -CDQS --minlevel=8 %t', + \ ale_linters#cpp#flawfinder#GetCommand(bufnr('')) + +Execute(Additional flawfinder options should be configurable): + let b:ale_cpp_flawfinder_options = ' --foobar' + + AssertEqual + \ ale#Escape('flawfinder') + \ . ' -CDQS --foobar --minlevel=1 %t', + \ ale_linters#cpp#flawfinder#GetCommand(bufnr('')) + +Execute(The flawfinder exectable should be configurable): + let b:ale_cpp_flawfinder_executable = 'foo/bar' + + AssertEqual + \ ale#Escape('foo/bar') + \ . ' -CDQS --minlevel=1 %t', + \ ale_linters#cpp#flawfinder#GetCommand(bufnr('')) diff --git a/test/command_callback/test_cpp_gcc_command_callbacks.vader b/test/command_callback/test_cpp_gcc_command_callbacks.vader index 9ab4d5cb..7abebf4c 100644 --- a/test/command_callback/test_cpp_gcc_command_callbacks.vader +++ b/test/command_callback/test_cpp_gcc_command_callbacks.vader @@ -30,10 +30,10 @@ Execute(The executable should be configurable): Execute(The executable should be used in the command): AssertEqual \ ale#Escape('gcc') . b:command_tail, - \ ale_linters#cpp#gcc#GetCommand(bufnr('')) + \ ale_linters#cpp#gcc#GetCommand(bufnr(''), []) let b:ale_cpp_gcc_executable = 'foobar' AssertEqual \ ale#Escape('foobar') . b:command_tail, - \ ale_linters#cpp#gcc#GetCommand(bufnr('')) + \ ale_linters#cpp#gcc#GetCommand(bufnr(''), []) diff --git a/test/command_callback/test_cucumber_command_callback.vader b/test/command_callback/test_cucumber_command_callback.vader new file mode 100644 index 00000000..d09a5712 --- /dev/null +++ b/test/command_callback/test_cucumber_command_callback.vader @@ -0,0 +1,25 @@ +Before: + runtime ale_linters/ruby/rubocop.vim + call ale#test#SetDirectory('/testplugin/test/') + +After: + Restore + + call ale#linter#Reset() + call ale#test#RestoreDirectory() + +Execute(Should require the nearest features dir, if one is found): + call ale#test#SetFilename('cucumber_fixtures/features/cuke.feature') + + AssertEqual + \ 'cucumber --dry-run --quiet --strict --format=json ' + \ . '-r ' . ale#Escape(ale#path#Simplify(g:dir . '/cucumber_fixtures/features/')) . ' %t', + \ ale_linters#cucumber#cucumber#GetCommand(bufnr('')) + +Execute(Should require nothing if no features dir is found): + call ale#test#SetFilename('something/without/a/features/dir') + + AssertEqual + \ 'cucumber --dry-run --quiet --strict --format=json ' + \ . ' %t', + \ ale_linters#cucumber#cucumber#GetCommand(bufnr('')) diff --git a/test/command_callback/test_elixir_mix_command_callbacks.vader b/test/command_callback/test_elixir_mix_command_callbacks.vader new file mode 100644 index 00000000..67785881 --- /dev/null +++ b/test/command_callback/test_elixir_mix_command_callbacks.vader @@ -0,0 +1,37 @@ +Before: + runtime ale_linters/elixir/mix.vim + + call ale#test#SetDirectory('/testplugin/test/command_callback') + + let g:project_root = ale#path#Simplify(g:dir . '/mix_paths/wrapped_project') + + let g:env_prefix = has('win32') + \ ? 'set MIX_BUILD_PATH=TEMP && ' + \ : 'MIX_BUILD_PATH=TEMP ' + + + function! GetCommand(buffer) abort + let l:command = ale_linters#elixir#mix#GetCommand(a:buffer) + + return substitute(l:command, 'MIX_BUILD_PATH=[^ ]\+', 'MIX_BUILD_PATH=TEMP', '') + endfunction + +After: + Restore + + unlet! g:env_prefix + unlet! g:project_root + + call ale#linter#Reset() + call ale#test#RestoreDirectory() + + delfunction GetCommand + +Execute(The default mix command should be correct): + call ale#test#SetFilename('mix_paths/wrapped_project/lib/app.ex') + + AssertEqual + \ GetCommand(bufnr('')), + \ ale#path#CdString(g:project_root) + \ . g:env_prefix + \ . 'mix compile %s' diff --git a/test/command_callback/test_flake8_command_callback.vader b/test/command_callback/test_flake8_command_callback.vader index 1784b81f..1cc50836 100644 --- a/test/command_callback/test_flake8_command_callback.vader +++ b/test/command_callback/test_flake8_command_callback.vader @@ -2,11 +2,13 @@ Before: Save g:ale_python_flake8_executable Save g:ale_python_flake8_options Save g:ale_python_flake8_use_global + Save g:ale_python_flake8_change_directory unlet! g:ale_python_flake8_executable unlet! g:ale_python_flake8_args unlet! g:ale_python_flake8_options unlet! g:ale_python_flake8_use_global + unlet! g:ale_python_flake8_change_directory let b:bin_dir = has('win32') ? 'Scripts' : 'bin' @@ -33,20 +35,30 @@ Execute(The flake8 callbacks should return the correct default values): \ ale#Escape('flake8') . ' --version', \ ale_linters#python#flake8#VersionCheck(bufnr('')) AssertEqual - \ ale#Escape('flake8') . ' --format=default --stdin-display-name %s -', + \ ale#path#BufferCdString(bufnr('')) + \ . ale#Escape('flake8') . ' --format=default --stdin-display-name %s -', \ ale_linters#python#flake8#GetCommand(bufnr(''), ['3.0.0']) " Try with older versions. call ale#semver#ResetVersionCache() AssertEqual - \ ale#Escape('flake8') . ' --format=default -', + \ ale#path#BufferCdString(bufnr('')) + \ . ale#Escape('flake8') . ' --format=default -', \ ale_linters#python#flake8#GetCommand(bufnr(''), ['2.9.9']) +Execute(The option for disabling changing directories should work): + let g:ale_python_flake8_change_directory = 0 + + AssertEqual + \ ale#Escape('flake8') . ' --format=default --stdin-display-name %s -', + \ ale_linters#python#flake8#GetCommand(bufnr(''), ['3.0.0']) + Execute(The flake8 command callback should let you set options): let g:ale_python_flake8_options = '--some-option' AssertEqual - \ ale#Escape('flake8') + \ ale#path#BufferCdString(bufnr('')) + \ . ale#Escape('flake8') \ . ' --some-option --format=default' \ . ' --stdin-display-name %s -', \ ale_linters#python#flake8#GetCommand(bufnr(''), ['3.0.4']) @@ -54,7 +66,8 @@ Execute(The flake8 command callback should let you set options): call ale#semver#ResetVersionCache() AssertEqual - \ ale#Escape('flake8') + \ ale#path#BufferCdString(bufnr('')) + \ . ale#Escape('flake8') \ . ' --some-option --format=default -', \ ale_linters#python#flake8#GetCommand(bufnr(''), ['2.9.9']) @@ -68,7 +81,8 @@ Execute(You should be able to set a custom executable and it should be escaped): \ ale#Escape('executable with spaces') . ' --version', \ ale_linters#python#flake8#VersionCheck(bufnr('')) AssertEqual - \ ale#Escape('executable with spaces') + \ ale#path#BufferCdString(bufnr('')) + \ . ale#Escape('executable with spaces') \ . ' --format=default' \ . ' --stdin-display-name %s -', \ ale_linters#python#flake8#GetCommand(bufnr(''), ['3.0.0']) @@ -87,7 +101,8 @@ Execute(The flake8 callbacks should detect virtualenv directories): \ ale#Escape(b:executable) . ' --version', \ ale_linters#python#flake8#VersionCheck(bufnr('')) AssertEqual - \ ale#Escape(b:executable) + \ ale#path#BufferCdString(bufnr('')) + \ . ale#Escape(b:executable) \ . ' --format=default --stdin-display-name %s -', \ ale_linters#python#flake8#GetCommand(bufnr(''), ['3.0.0']) @@ -140,7 +155,8 @@ Execute(Using `python -m flake8` should be supported for running flake8): \ ale#Escape('python') . ' -m flake8 --version', \ ale_linters#python#flake8#VersionCheck(bufnr('')) AssertEqual - \ ale#Escape('python') . ' -m flake8 --some-option --format=default -', + \ ale#path#BufferCdString(bufnr('')) + \ . ale#Escape('python') . ' -m flake8 --some-option --format=default -', \ ale_linters#python#flake8#GetCommand(bufnr(''), ['2.9.9']) call ale#semver#ResetVersionCache() @@ -155,27 +171,14 @@ Execute(Using `python -m flake8` should be supported for running flake8): \ ale#Escape('python') . ' -m flake8 --version', \ ale_linters#python#flake8#VersionCheck(bufnr('')) AssertEqual - \ ale#Escape('python') . ' -m flake8 --some-option --format=default -', + \ ale#path#BufferCdString(bufnr('')) + \ . ale#Escape('python') . ' -m flake8 --some-option --format=default -', \ ale_linters#python#flake8#GetCommand(bufnr(''), ['2.9.9']) -Execute(Using `python2 -m flake8` should be supported with the old args option): - let g:ale_python_flake8_executable = 'python2' - let g:ale_python_flake8_args = '-m flake8' - let g:ale_python_flake8_use_global = 0 - - unlet! g:ale_python_flake8_options +Execute(Setting executable to 'pipenv' appends 'run flake8'): + let g:ale_python_flake8_executable = 'path/to/pipenv' - call ale#linter#Reset() - runtime ale_linters/python/flake8.vim - - silent execute 'file ' . fnameescape(g:dir . '/python_paths/with_virtualenv/subdir/foo/bar.py') - - AssertEqual - \ 'python2', - \ ale_linters#python#flake8#GetExecutable(bufnr('')) AssertEqual - \ ale#Escape('python2') . ' -m flake8 --version', - \ ale_linters#python#flake8#VersionCheck(bufnr('')) - AssertEqual - \ ale#Escape('python2') . ' -m flake8 --format=default -', - \ ale_linters#python#flake8#GetCommand(bufnr(''), ['2.9.9']) + \ ale#path#BufferCdString(bufnr('')) + \ . ale#Escape('path/to/pipenv') . ' run flake8 --format=default --stdin-display-name %s -', + \ ale_linters#python#flake8#GetCommand(bufnr(''), ['3.0.0']) diff --git a/test/command_callback/test_fsc_command_callback.vader b/test/command_callback/test_fsc_command_callback.vader new file mode 100644 index 00000000..451fa108 --- /dev/null +++ b/test/command_callback/test_fsc_command_callback.vader @@ -0,0 +1,17 @@ +Before: + runtime ale_linters/scala/fsc.vim + +After: + call ale#linter#Reset() + +Given scala(An empty Scala file): +Execute(The default executable and command should be correct): + AssertEqual 'fsc', ale_linters#scala#fsc#GetExecutable(bufnr('')) + AssertEqual + \ ale#Escape('fsc') . ' -Ystop-after:parser %t', + \ ale_linters#scala#fsc#GetCommand(bufnr('')) + +Given scala.sbt(An empty SBT file): +Execute(fsc should not be run for sbt files): + AssertEqual '', ale_linters#scala#fsc#GetExecutable(bufnr('')) + AssertEqual '', ale_linters#scala#fsc#GetCommand(bufnr('')) diff --git a/test/command_callback/test_gawk_command_callback.vader b/test/command_callback/test_gawk_command_callback.vader new file mode 100644 index 00000000..ae128fe5 --- /dev/null +++ b/test/command_callback/test_gawk_command_callback.vader @@ -0,0 +1,40 @@ +Before: + Save g:ale_awk_gawk_executable + Save g:ale_awk_gawk_options + unlet! g:ale_awk_gawk_executable + unlet! g:ale_awk_gawk_options + + runtime ale_linters/awk/gawk.vim + +After: + Restore + unlet! b:command_tail + unlet! b:ale_awk_gawk_executable + unlet! b:ale_awk_gawk_options + + call ale#linter#Reset() + +Execute(The executable should be used in the command): + AssertEqual + \ 'gawk' + \ . " --source 'BEGIN { exit } END { exit 1 }'" + \ . ' ' . '-f %t --lint /dev/null', + \ ale_linters#awk#gawk#GetCommand(bufnr('')) + + let b:ale_awk_gawk_executable = '/other/gawk' + + AssertEqual + \ '/other/gawk' + \ . " --source 'BEGIN { exit } END { exit 1 }'" + \ . ' ' . '-f %t --lint /dev/null', + \ ale_linters#awk#gawk#GetCommand(bufnr('')) + + let b:ale_awk_gawk_executable = 'gawk' + let b:ale_awk_gawk_options = '--something' + + AssertEqual + \ 'gawk' + \ . " --source 'BEGIN { exit } END { exit 1 }'" + \ . ' --something' + \ . ' ' . '-f %t --lint /dev/null', + \ ale_linters#awk#gawk#GetCommand(bufnr('')) diff --git a/test/command_callback/test_gosimple_command_callback.vader b/test/command_callback/test_gosimple_command_callback.vader new file mode 100644 index 00000000..a0b1f468 --- /dev/null +++ b/test/command_callback/test_gosimple_command_callback.vader @@ -0,0 +1,12 @@ +Before: + runtime ale_linters/go/gosimple.vim + call ale#test#SetFilename('../go_files/testfile2.go') + +After: + call ale#linter#Reset() + +Execute(The default gosimple command should be correct): + AssertEqual 'cd ' . ale#Escape(expand('%:p:h')) . ' && ' + \ . ' gosimple .', + \ ale_linters#go#gosimple#GetCommand(bufnr('')) + diff --git a/test/command_callback/test_gotype_command_callback.vader b/test/command_callback/test_gotype_command_callback.vader index f95e8423..4fba3344 100644 --- a/test/command_callback/test_gotype_command_callback.vader +++ b/test/command_callback/test_gotype_command_callback.vader @@ -5,15 +5,11 @@ Before: After: call ale#linter#Reset() - -Execute(The gotype callback should include other files from the directory but exclude the file itself): - let dir = expand('#' . bufnr('') . ':p:h') - AssertEqual - \ "gotype %t ". ale#Escape(ale#path#Simplify(dir . "/testfile.go")), +Execute(The default gotype command should be correct): + AssertEqual 'cd ' . ale#Escape(expand('%:p:h')) . ' && ' + \ . ' gotype .', \ ale_linters#go#gotype#GetCommand(bufnr('')) Execute(The gotype callback should ignore test files): call ale#test#SetFilename('bla_test.go') - AssertEqual - \ 0, - \ ale_linters#go#gotype#GetCommand(bufnr('')) + AssertEqual 0, ale_linters#go#gotype#GetCommand(bufnr('')) diff --git a/test/command_callback/test_govet_command_callback.vader b/test/command_callback/test_govet_command_callback.vader new file mode 100644 index 00000000..a9b29605 --- /dev/null +++ b/test/command_callback/test_govet_command_callback.vader @@ -0,0 +1,16 @@ +Before: + runtime ale_linters/go/govet.vim + + call ale#test#SetDirectory('/testplugin/test/command_callback') + +After: + Restore + + call ale#linter#Reset() + call ale#test#RestoreDirectory() + +Execute(The default command should be correct): + AssertEqual + \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && ' + \ . ' go vet .', + \ ale_linters#go#govet#GetCommand(bufnr('')) diff --git a/test/command_callback/test_javac_command_callback.vader b/test/command_callback/test_javac_command_callback.vader index 7823d030..b0d0e7c7 100644 --- a/test/command_callback/test_javac_command_callback.vader +++ b/test/command_callback/test_javac_command_callback.vader @@ -1,9 +1,11 @@ Before: call ale#test#SetDirectory('/testplugin/test/command_callback') + Save g:ale_java_javac_executable Save g:ale_java_javac_options Save g:ale_java_javac_classpath + unlet! g:ale_java_javac_executable unlet! g:ale_java_javac_options unlet! g:ale_java_javac_classpath @@ -28,7 +30,8 @@ Before: call ale#test#SetFilename('dummy.java') - let g:prefix = 'cd ' . ale#Escape(expand('%:p:h')) . ' && javac -Xlint' + let g:prefix = 'cd ' . ale#Escape(expand('%:p:h')) . ' && ' + \ . ale#Escape('javac') . ' -Xlint' After: call ale#test#RestoreDirectory() @@ -57,6 +60,17 @@ Execute(The javac callback should use g:ale_java_javac_classpath correctly): \ . ' -d TEMP %t', \ GetCommand([]) +Execute(The executable should be configurable): + let g:ale_java_javac_executable = 'foobar' + + AssertEqual 'foobar', ale_linters#java#javac#GetExecutable(bufnr('')) + + AssertEqual + \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && ' + \ . ale#Escape('foobar') . ' -Xlint' + \ . ' -d TEMP %t', + \ GetCommand([]) + Execute(The javac callback should include discovered classpaths): AssertEqual \ g:prefix @@ -120,7 +134,7 @@ Execute(The javac callback should detect source directories): call ale#engine#InitBufferInfo(bufnr('')) AssertEqual - \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && javac -Xlint' + \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && ' . ale#Escape('javac') . ' -Xlint' \ . ' -sourcepath ' . ale#Escape( \ ale#path#Simplify(g:dir . '/java_paths/src/main/java/') \ ) @@ -133,7 +147,7 @@ Execute(The javac callback should combine detected source directories and classp call ale#engine#InitBufferInfo(bufnr('')) AssertEqual - \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && javac -Xlint' + \ 'cd ' . ale#Escape(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/') @@ -164,7 +178,7 @@ Execute(The javac callback should include src/test/java for test paths): call ale#engine#InitBufferInfo(bufnr('')) AssertEqual - \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && javac -Xlint' + \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && ' . ale#Escape('javac') . ' -Xlint' \ . ' -sourcepath ' . ale#Escape(join([ \ ale#path#Simplify(g:dir . '/java_paths/src/main/java/'), \ ale#path#Simplify(g:dir . '/java_paths/src/test/java/'), @@ -178,7 +192,7 @@ Execute(The javac callback should include src/main/jaxb when available): call ale#engine#InitBufferInfo(bufnr('')) AssertEqual - \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && javac -Xlint' + \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && ' . ale#Escape('javac') . ' -Xlint' \ . ' -sourcepath ' . ale#Escape(join([ \ ale#path#Simplify(g:dir . '/java_paths_with_jaxb/src/main/java/'), \ ale#path#Simplify(g:dir . '/java_paths_with_jaxb/src/main/jaxb/'), diff --git a/test/command_callback/test_lintr_command_callback.vader b/test/command_callback/test_lintr_command_callback.vader index e655328b..2f7dfb1d 100644 --- a/test/command_callback/test_lintr_command_callback.vader +++ b/test/command_callback/test_lintr_command_callback.vader @@ -16,7 +16,7 @@ After: Execute(The default lintr command should be correct): AssertEqual \ 'cd ' . ale#Escape(getcwd()) . ' && ' - \ . 'Rscript -e ' + \ . 'Rscript --vanilla -e ' \ . ale#Escape('suppressPackageStartupMessages(library(lintr));' \ . 'lint(cache = FALSE, commandArgs(TRUE), ' \ . 'with_defaults())') @@ -28,7 +28,7 @@ Execute(The lintr options should be configurable): AssertEqual \ 'cd ' . ale#Escape(getcwd()) . ' && ' - \ . 'Rscript -e ' + \ . 'Rscript --vanilla -e ' \ . ale#Escape('suppressPackageStartupMessages(library(lintr));' \ . 'lint(cache = FALSE, commandArgs(TRUE), ' \ . 'with_defaults(object_usage_linter = NULL))') @@ -40,7 +40,7 @@ Execute(If the lint_package flag is set, lintr::lint_package should be called): AssertEqual \ 'cd ' . ale#Escape(getcwd()) . ' && ' - \ . 'Rscript -e ' + \ . 'Rscript --vanilla -e ' \ . ale#Escape('suppressPackageStartupMessages(library(lintr));' \ . 'lint_package(cache = FALSE, ' \ . 'linters = with_defaults())') diff --git a/test/command_callback/test_markdown_mdl_command_callback.vader b/test/command_callback/test_markdown_mdl_command_callback.vader new file mode 100644 index 00000000..2fb9a206 --- /dev/null +++ b/test/command_callback/test_markdown_mdl_command_callback.vader @@ -0,0 +1,35 @@ +Before: + Save g:ale_markdown_mdl_executable + Save g:ale_markdown_mdl_options + + unlet! g:ale_markdown_mdl_executable + unlet! g:ale_markdown_mdl_options + + runtime ale_linters/markdown/mdl.vim + +After: + Restore + + call ale#linter#Reset() + +Execute(The default command should be correct): + AssertEqual ale_linters#markdown#mdl#GetExecutable(bufnr('')), 'mdl' + AssertEqual + \ ale_linters#markdown#mdl#GetCommand(bufnr('')), + \ ale#Escape('mdl') + +Execute(The executable and options should be configurable): + let g:ale_markdown_mdl_executable = 'foo bar' + let g:ale_markdown_mdl_options = '--wat' + + AssertEqual ale_linters#markdown#mdl#GetExecutable(bufnr('')), 'foo bar' + AssertEqual + \ ale_linters#markdown#mdl#GetCommand(bufnr('')), + \ ale#Escape('foo bar') . ' --wat' + +Execute(Setting bundle appends 'exec mdl'): + let g:ale_markdown_mdl_executable = 'path to/bundle' + + AssertEqual + \ ale#Escape('path to/bundle') . ' exec mdl', + \ ale_linters#markdown#mdl#GetCommand(bufnr('')) diff --git a/test/command_callback/test_mercury_mmc_command_callback.vader b/test/command_callback/test_mercury_mmc_command_callback.vader new file mode 100644 index 00000000..7ebf49c3 --- /dev/null +++ b/test/command_callback/test_mercury_mmc_command_callback.vader @@ -0,0 +1,42 @@ +Before: + Save g:ale_mercury_mmc_executable + Save g:ale_mercury_mmc_options + + unlet! g:ale_mercury_mmc_executable + unlet! b:ale_mercury_mmc_executable + unlet! g:ale_mercury_mmc_options + unlet! b:ale_mercury_mmc_options + + runtime ale_linters/mercury/mmc.vim + call ale#test#SetDirectory('/testplugin/test/command_callback') + +After: + unlet! b:ale_mercury_mmc_executable + unlet! b:ale_mercury_mmc_options + + Restore + call ale#test#RestoreDirectory() + call ale#linter#Reset() + +Execute(The default command should be correct): + AssertEqual + \ ale#path#BufferCdString(bufnr('')) + \ . 'mmc --errorcheck-only --make --output-compile-error-lines 100 dummy', + \ + \ ale_linters#mercury#mmc#GetCommand(bufnr('')) + +Execute(The executable should be configurable): + let b:ale_mercury_mmc_executable = 'foo' + AssertEqual + \ ale#path#BufferCdString(bufnr('')) + \ . 'foo --errorcheck-only --make --output-compile-error-lines 100 dummy', + \ + \ ale_linters#mercury#mmc#GetCommand(bufnr('')) + +Execute(The options should be configurable): + let b:ale_mercury_mmc_options = '--bar' + AssertEqual + \ ale#path#BufferCdString(bufnr('')) + \ . 'mmc --errorcheck-only --bar dummy', + \ + \ ale_linters#mercury#mmc#GetCommand(bufnr('')) diff --git a/test/command_callback/test_mypy_command_callback.vader b/test/command_callback/test_mypy_command_callback.vader index 6a0add52..0fb4cc54 100644 --- a/test/command_callback/test_mypy_command_callback.vader +++ b/test/command_callback/test_mypy_command_callback.vader @@ -95,3 +95,12 @@ Execute(You should able able to use the global mypy instead): \ . ' --show-column-numbers ' \ . '--shadow-file %s %t %s', \ ale_linters#python#mypy#GetCommand(bufnr('')) + +Execute(Setting executable to 'pipenv' appends 'run mypy'): + let g:ale_python_mypy_executable = 'path/to/pipenv' + + AssertEqual + \ ale#path#BufferCdString(bufnr('')) + \ . ale#Escape('path/to/pipenv') . ' run mypy' + \ . ' --show-column-numbers --shadow-file %s %t %s', + \ ale_linters#python#mypy#GetCommand(bufnr('')) diff --git a/test/command_callback/test_nasm_nasm_command_callbacks.vader b/test/command_callback/test_nasm_nasm_command_callbacks.vader new file mode 100644 index 00000000..5053e536 --- /dev/null +++ b/test/command_callback/test_nasm_nasm_command_callbacks.vader @@ -0,0 +1,52 @@ +Before: + Save g:ale_nasm_nasm_executable + Save g:ale_nasm_nasm_options + + unlet! g:ale_nasm_nasm_executable + unlet! b:ale_nasm_nasm_executable + unlet! g:ale_nasm_nasm_options + unlet! b:ale_nasm_nasm_options + + runtime ale_linters/nasm/nasm.vim + + let b:command_tail = + \ ' -X gnu -I ' . ale#Escape(getcwd() . (has('win32') ? '\' : '/')) . ' %s' + let b:command_tail_opt = + \ ' -X gnu -I ' . ale#Escape(getcwd() . (has('win32') ? '\' : '/')) . ' -w+orphan-labels %s' + +After: + Restore + unlet! b:command_tail + unlet! b:command_tail_opt + unlet! b:ale_nasm_nasm_executable + unlet! b:ale_nasm_nasm_options + call ale#linter#Reset() + +Execute(The executable should be configurable): + AssertEqual 'nasm', ale_linters#nasm#nasm#GetExecutable(bufnr('')) + + let b:ale_nasm_nasm_executable = '/opt/nasm/nasm' + + AssertEqual '/opt/nasm/nasm', ale_linters#nasm#nasm#GetExecutable(bufnr('')) + +Execute(The executable should be used in the command): + AssertEqual + \ ale#Escape('nasm') . b:command_tail, + \ ale_linters#nasm#nasm#GetCommand(bufnr('')) + + let b:ale_nasm_nasm_executable = '~/nasm' + + AssertEqual + \ ale#Escape('~/nasm') . b:command_tail, + \ ale_linters#nasm#nasm#GetCommand(bufnr('')) + +Execute(The options should be configurable): + AssertEqual '', ale_linters#nasm#nasm#GetOptions(bufnr('')) + let b:ale_nasm_nasm_options = '-w-macro-params' + AssertEqual '-w-macro-params', ale_linters#nasm#nasm#GetOptions(bufnr('')) + +Execute(The options should be used in command): + let b:ale_nasm_nasm_options = '-w+orphan-labels' + AssertEqual + \ ale#Escape('nasm') . b:command_tail_opt, + \ ale_linters#nasm#nasm#GetCommand(bufnr('')) diff --git a/test/command_callback/test_perlcritic_command_callback.vader b/test/command_callback/test_perlcritic_command_callback.vader index 6507868b..e8d8cc18 100644 --- a/test/command_callback/test_perlcritic_command_callback.vader +++ b/test/command_callback/test_perlcritic_command_callback.vader @@ -30,14 +30,18 @@ Execute(The command should be correct with g:ale_perl_perlcritic_showrules off): let b:ale_perl_perlcritic_showrules = 0 AssertEqual - \ ale#Escape('perlcritic') . ' --verbose ''%l:%c %m\n'' --nocolor', + \ ale#Escape('perlcritic') + \ . ' --verbose ' . ale#Escape('%l:%c %m\n') + \ . ' --nocolor', \ ale_linters#perl#perlcritic#GetCommand(bufnr('')) Execute(The command should be correct with g:ale_perl_perlcritic_showrules on): let b:ale_perl_perlcritic_showrules = 1 AssertEqual - \ ale#Escape('perlcritic') . ' --verbose ''%l:%c %m [%p]\n'' --nocolor', + \ ale#Escape('perlcritic') + \ . ' --verbose ' . ale#Escape('%l:%c %m [%p]\n') + \ . ' --nocolor', \ ale_linters#perl#perlcritic#GetCommand(bufnr('')) Execute(The command search for the profile file when set): @@ -46,7 +50,9 @@ Execute(The command search for the profile file when set): let b:readme_path = ale#path#Simplify(expand('%:p:h:h:h') . '/README.md') AssertEqual - \ ale#Escape('perlcritic') . ' --verbose ''%l:%c %m\n'' --nocolor' + \ ale#Escape('perlcritic') + \ . ' --verbose ' . ale#Escape('%l:%c %m\n') + \ . ' --nocolor' \ . ' --profile ' . ale#Escape(b:readme_path), \ ale_linters#perl#perlcritic#GetCommand(bufnr('')) @@ -54,6 +60,8 @@ Execute(Extra options should be set appropriately): let b:ale_perl_perlcritic_options = 'beep boop' AssertEqual - \ ale#Escape('perlcritic') . ' --verbose ''%l:%c %m\n'' --nocolor' + \ ale#Escape('perlcritic') + \ . ' --verbose ' . ale#Escape('%l:%c %m\n') + \ . ' --nocolor' \ . ' beep boop', \ ale_linters#perl#perlcritic#GetCommand(bufnr('')) diff --git a/test/command_callback/test_php_langserver_callbacks.vader b/test/command_callback/test_php_langserver_callbacks.vader index 0dc30630..ebcae0e7 100644 --- a/test/command_callback/test_php_langserver_callbacks.vader +++ b/test/command_callback/test_php_langserver_callbacks.vader @@ -42,9 +42,6 @@ Execute(Vendor executables should be detected): \ )), \ ale_linters#php#langserver#GetCommand(bufnr('')) -Execute(The language string should be correct): - AssertEqual 'php', ale_linters#php#langserver#GetLanguage(bufnr('')) - Execute(The project path should be correct for .git directories): call ale#test#SetFilename('php-langserver-project/test.php') call mkdir(g:dir . '/.git') diff --git a/test/command_callback/test_pony_ponyc_command_callbacks.vader b/test/command_callback/test_pony_ponyc_command_callbacks.vader new file mode 100644 index 00000000..7acbfa9d --- /dev/null +++ b/test/command_callback/test_pony_ponyc_command_callbacks.vader @@ -0,0 +1,23 @@ +Before: + Save g:ale_pony_ponyc_options + + unlet! g:ale_pony_ponyc_options + unlet! b:ale_pony_ponyc_options + + runtime ale_linters/pony/ponyc.vim + +After: + Restore + unlet! b:ale_pony_ponyc_options + call ale#linter#Reset() + +Execute(The options should be used in the command): + AssertEqual + \ ale#Escape('ponyc') . ' --pass paint', + \ ale_linters#pony#ponyc#GetCommand(bufnr('')) + + let b:ale_pony_ponyc_options = 'foobar' + + AssertEqual + \ ale#Escape('ponyc') . ' foobar', + \ ale_linters#pony#ponyc#GetCommand(bufnr('')) diff --git a/test/command_callback/test_prospector_command_callback.vader b/test/command_callback/test_prospector_command_callback.vader new file mode 100644 index 00000000..04cd58ed --- /dev/null +++ b/test/command_callback/test_prospector_command_callback.vader @@ -0,0 +1,23 @@ +Before: + Save g:ale_python_mypy_executable + Save g:ale_python_mypy_options + + unlet! g:ale_python_mypy_executable + unlet! g:ale_python_mypy_options + + runtime ale_linters/python/prospector.vim + +After: + Restore + + unlet! b:executable + + call ale#linter#Reset() + +Execute(Setting executable to 'pipenv' appends 'run prospector'): + let g:ale_python_prospector_executable = 'path/to/pipenv' + + AssertEqual + \ ale#Escape('path/to/pipenv') . ' run prospector' + \ . ' --messages-only --absolute-paths --zero-exit --output-format json %s', + \ ale_linters#python#prospector#GetCommand(bufnr('')) diff --git a/test/command_callback/test_pycodestyle_command_callback.vader b/test/command_callback/test_pycodestyle_command_callback.vader index 5b309e19..90b07a24 100644 --- a/test/command_callback/test_pycodestyle_command_callback.vader +++ b/test/command_callback/test_pycodestyle_command_callback.vader @@ -25,3 +25,10 @@ Execute(The pycodestyle executable should be configurable): AssertEqual ale#Escape('~/.local/bin/pycodestyle') . ' -', \ ale_linters#python#pycodestyle#GetCommand(bufnr('')) + +Execute(Setting executable to 'pipenv' appends 'run pycodestyle'): + let g:ale_python_pycodestyle_executable = 'path/to/pipenv' + + AssertEqual + \ ale#Escape('path/to/pipenv') . ' run pycodestyle -', + \ ale_linters#python#pycodestyle#GetCommand(bufnr('')) diff --git a/test/command_callback/test_pyflakes_command_callback.vader b/test/command_callback/test_pyflakes_command_callback.vader index e8486ca8..491432e9 100644 --- a/test/command_callback/test_pyflakes_command_callback.vader +++ b/test/command_callback/test_pyflakes_command_callback.vader @@ -47,3 +47,10 @@ Execute(You should be able to override the pyflakes virtualenv lookup): AssertEqual ale#Escape('pyflakes') . ' %t', \ ale_linters#python#pyflakes#GetCommand(bufnr('')) + +Execute(Setting executable to 'pipenv' appends 'run pyflakes'): + let g:ale_python_pyflakes_executable = 'path/to/pipenv' + + AssertEqual + \ ale#Escape('path/to/pipenv') . ' run pyflakes %t', + \ ale_linters#python#pyflakes#GetCommand(bufnr('')) diff --git a/test/command_callback/test_pylint_command_callback.vader b/test/command_callback/test_pylint_command_callback.vader index 1ff8e354..f8cb5800 100644 --- a/test/command_callback/test_pylint_command_callback.vader +++ b/test/command_callback/test_pylint_command_callback.vader @@ -2,10 +2,12 @@ Before: Save g:ale_python_pylint_executable Save g:ale_python_pylint_options Save g:ale_python_pylint_use_global + Save g:ale_python_pylint_change_directory unlet! g:ale_python_pylint_executable unlet! g:ale_python_pylint_options unlet! g:ale_python_pylint_use_global + unlet! g:ale_python_pylint_change_directory runtime ale_linters/python/pylint.vim call ale#test#SetDirectory('/testplugin/test/command_callback') @@ -28,6 +30,18 @@ Execute(The pylint callbacks should return the correct default values): \ 'pylint', \ ale_linters#python#pylint#GetExecutable(bufnr('')) AssertEqual + \ ale#path#BufferCdString(bufnr('')) + \ . ale#Escape('pylint') . ' ' . b:command_tail, + \ ale_linters#python#pylint#GetCommand(bufnr('')) + +Execute(The option for disabling changing directories should work): + let g:ale_python_pylint_change_directory = 0 + + AssertEqual + \ 'pylint', + \ ale_linters#python#pylint#GetExecutable(bufnr('')) + \ + AssertEqual \ ale#Escape('pylint') . ' ' . b:command_tail, \ ale_linters#python#pylint#GetCommand(bufnr('')) @@ -38,14 +52,16 @@ Execute(The pylint executable should be configurable, and escaped properly): \ 'executable with spaces', \ ale_linters#python#pylint#GetExecutable(bufnr('')) AssertEqual - \ ale#Escape('executable with spaces') . ' ' . b:command_tail, + \ ale#path#BufferCdString(bufnr('')) + \ . ale#Escape('executable with spaces') . ' ' . b:command_tail, \ ale_linters#python#pylint#GetCommand(bufnr('')) Execute(The pylint command callback should let you set options): let g:ale_python_pylint_options = '--some-option' AssertEqual - \ ale#Escape('pylint') . ' --some-option' . b:command_tail, + \ ale#path#BufferCdString(bufnr('')) + \ . ale#Escape('pylint') . ' --some-option' . b:command_tail, \ ale_linters#python#pylint#GetCommand(bufnr('')) Execute(The pylint callbacks shouldn't detect virtualenv directories where they don't exist): @@ -55,7 +71,8 @@ Execute(The pylint callbacks shouldn't detect virtualenv directories where they \ 'pylint', \ ale_linters#python#pylint#GetExecutable(bufnr('')) AssertEqual - \ ale#Escape('pylint') . ' ' . b:command_tail, + \ ale#path#BufferCdString(bufnr('')) + \ . ale#Escape('pylint') . ' ' . b:command_tail, \ ale_linters#python#pylint#GetCommand(bufnr('')) Execute(The pylint callbacks should detect virtualenv directories): @@ -70,7 +87,8 @@ Execute(The pylint callbacks should detect virtualenv directories): \ ale_linters#python#pylint#GetExecutable(bufnr('')) AssertEqual - \ ale#Escape(b:executable) . ' ' . b:command_tail, + \ ale#path#BufferCdString(bufnr('')) + \ . ale#Escape(b:executable) . ' ' . b:command_tail, \ ale_linters#python#pylint#GetCommand(bufnr('')) Execute(You should able able to use the global pylint instead): @@ -81,5 +99,15 @@ Execute(You should able able to use the global pylint instead): \ 'pylint', \ ale_linters#python#pylint#GetExecutable(bufnr('')) AssertEqual - \ ale#Escape('pylint') . ' ' . b:command_tail, + \ ale#path#BufferCdString(bufnr('')) + \ . ale#Escape('pylint') . ' ' . b:command_tail, + \ ale_linters#python#pylint#GetCommand(bufnr('')) + +Execute(Setting executable to 'pipenv' appends 'run pylint'): + let g:ale_python_pylint_executable = 'path/to/pipenv' + + AssertEqual + \ ale#path#BufferCdString(bufnr('')) + \ . ale#Escape('path/to/pipenv') . ' run pylint' + \ . ' --output-format text --msg-template="{path}:{line}:{column}: {msg_id} ({symbol}) {msg}" --reports n %s', \ ale_linters#python#pylint#GetCommand(bufnr('')) diff --git a/test/command_callback/test_pyls_command_callback.vader b/test/command_callback/test_pyls_command_callback.vader index 06ea718f..4bef4742 100644 --- a/test/command_callback/test_pyls_command_callback.vader +++ b/test/command_callback/test_pyls_command_callback.vader @@ -47,3 +47,10 @@ Execute(You should be able to override the pyls virtualenv lookup): AssertEqual ale#Escape('pyls'), \ ale_linters#python#pyls#GetCommand(bufnr('')) + +Execute(Setting executable to 'pipenv' appends 'run pyls'): + let g:ale_python_pyls_executable = 'path/to/pipenv' + + AssertEqual + \ ale#Escape('path/to/pipenv') . ' run pyls', + \ ale_linters#python#pyls#GetCommand(bufnr('')) diff --git a/test/command_callback/test_qmlfmt_command_callback.vader b/test/command_callback/test_qmlfmt_command_callback.vader new file mode 100644 index 00000000..263caea7 --- /dev/null +++ b/test/command_callback/test_qmlfmt_command_callback.vader @@ -0,0 +1,18 @@ +Before: + runtime ale_linters/qml/qmlfmt.vim + +After: + let g:ale_qml_qmlfmt_executable = 'qmlfmt' + + call ale#linter#Reset() + +Execute(The qml qmlfmt command callback should return the correct default string): + AssertEqual ale#Escape('qmlfmt') . ' -e', + \ join(split(ale_linters#qml#qmlfmt#GetCommand(1))) + +Execute(The qmlfmt executable should be configurable): + let g:ale_qml_qmlfmt_executable = '~/.local/bin/qmlfmt' + + AssertEqual '~/.local/bin/qmlfmt', ale_linters#qml#qmlfmt#GetExecutable(1) + AssertEqual ale#Escape('~/.local/bin/qmlfmt') . ' -e', + \ join(split(ale_linters#qml#qmlfmt#GetCommand(1))) diff --git a/test/command_callback/test_rust_rls_callbacks.vader b/test/command_callback/test_rust_rls_callbacks.vader index 693d6e9f..16bde98a 100644 --- a/test/command_callback/test_rust_rls_callbacks.vader +++ b/test/command_callback/test_rust_rls_callbacks.vader @@ -28,8 +28,12 @@ Execute(The toolchain should be configurable): \ ale#Escape('rls') . ' +' . ale#Escape('stable'), \ ale_linters#rust#rls#GetCommand(bufnr('')) -Execute(The language string should be correct): - AssertEqual 'rust', ale_linters#rust#rls#GetLanguage(bufnr('')) +Execute(The toolchain should be ommitted if not given): + let g:ale_rust_rls_toolchain = '' + + AssertEqual + \ ale#Escape('rls'), + \ ale_linters#rust#rls#GetCommand(bufnr('')) Execute(The project root should be detected correctly): AssertEqual '', ale_linters#rust#rls#GetProjectRoot(bufnr('')) diff --git a/test/command_callback/test_sasslint_command_callback.vader b/test/command_callback/test_sasslint_command_callback.vader new file mode 100644 index 00000000..1db7e5fb --- /dev/null +++ b/test/command_callback/test_sasslint_command_callback.vader @@ -0,0 +1,12 @@ +Before: + call ale#test#SetDirectory('/testplugin/test/command_callback') + call ale#test#SetFilename('test.sass') + +After: + call ale#test#RestoreDirectory() + +Execute(The default sasslint command should be correct): + AssertEqual + \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && ' + \ . ale#Escape('sass-lint') . ' -v -q -f compact %t', + \ ale#handlers#sasslint#GetCommand(bufnr('')) diff --git a/test/handler/test_scalac_handler.vader b/test/command_callback/test_scalac_command_callback.vader index fd222f67..6bb31b3f 100644 --- a/test/handler/test_scalac_handler.vader +++ b/test/command_callback/test_scalac_command_callback.vader @@ -5,7 +5,6 @@ After: call ale#linter#Reset() Given scala(An empty Scala file): - Execute(The default executable and command should be correct): AssertEqual 'scalac', ale_linters#scala#scalac#GetExecutable(bufnr('')) AssertEqual diff --git a/test/command_callback/test_staticcheck_command_callback.vader b/test/command_callback/test_staticcheck_command_callback.vader new file mode 100644 index 00000000..e9628eb6 --- /dev/null +++ b/test/command_callback/test_staticcheck_command_callback.vader @@ -0,0 +1,41 @@ +Before: + Save b:ale_go_staticcheck_options + Save b:ale_go_staticcheck_lint_package + + let b:ale_go_staticcheck_options = '' + let b:ale_go_staticcheck_lint_package = 0 + + runtime ale_linters/go/staticcheck.vim + + call ale#test#SetDirectory('/testplugin/test/command_callback') + call ale#test#SetFilename('test.go') + +After: + Restore + + call ale#test#RestoreDirectory() + call ale#linter#Reset() + +Execute(The staticcheck callback should return the right defaults): + AssertEqual + \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && ' + \ . 'staticcheck ' + \ . ale#Escape(expand('%' . ':t')), + \ ale_linters#go#staticcheck#GetCommand(bufnr('')) + +Execute(The staticcheck callback should use configured options): + let b:ale_go_staticcheck_options = '-test' + + AssertEqual + \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && ' + \ . 'staticcheck ' + \ . '-test ' . ale#Escape(expand('%' . ':t')), + \ ale_linters#go#staticcheck#GetCommand(bufnr('')) + +Execute(The staticcheck `lint_package` option should use the correct command): + let b:ale_go_staticcheck_lint_package = 1 + + AssertEqual + \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && ' + \ . 'staticcheck .', + \ ale_linters#go#staticcheck#GetCommand(bufnr('')) diff --git a/test/command_callback/test_textlint_command_callbacks.vader b/test/command_callback/test_textlint_command_callbacks.vader new file mode 100644 index 00000000..212f34d3 --- /dev/null +++ b/test/command_callback/test_textlint_command_callbacks.vader @@ -0,0 +1,85 @@ +" Author: januswel, w0rp + +Before: + Save g:ale_textlint_executable + Save g:ale_textlint_use_global + Save g:ale_textlint_options + + unlet! g:ale_textlint_executable + unlet! b:ale_textlint_executable + unlet! g:ale_textlint_use_global + unlet! b:ale_textlint_use_global + unlet! g:ale_textlint_options + unlet! b:ale_textlint_options + + runtime autoload/ale/handlers/textlint.vim + + call ale#test#SetDirectory('/testplugin/test/command_callback') + +After: + Restore + + unlet! b:command_tail + unlet! b:ale_textlint_executable + unlet! b:ale_textlint_use_global + unlet! b:ale_textlint_options + + call ale#test#RestoreDirectory() + call ale#linter#Reset() + +Execute(The executable should be configurable): + AssertEqual 'textlint', ale#handlers#textlint#GetExecutable(bufnr('')) + + let b:ale_textlint_executable = 'foobar' + + AssertEqual 'foobar', ale#handlers#textlint#GetExecutable(bufnr('')) + +Execute(The executable should be used in the command): + AssertEqual + \ ale#Escape('textlint') . ' -f json --stdin --stdin-filename %s', + \ ale#handlers#textlint#GetCommand(bufnr('')) + + let b:ale_textlint_executable = 'foobar' + + AssertEqual + \ ale#Escape('foobar') . ' -f json --stdin --stdin-filename %s', + \ ale#handlers#textlint#GetCommand(bufnr('')) + \ + +Execute(The options should be configurable): + let b:ale_textlint_options = '--something' + + AssertEqual + \ ale#Escape('textlint') . ' --something -f json --stdin --stdin-filename %s', + \ ale#handlers#textlint#GetCommand(bufnr('')) + +Execute(The local executable from .bin should be used if available): + call ale#test#SetFilename('textlint_paths/with_bin_path/foo.txt') + + AssertEqual + \ ale#path#Simplify(g:dir . '/textlint_paths/with_bin_path/node_modules/.bin/textlint'), + \ ale#handlers#textlint#GetExecutable(bufnr('')) + + AssertEqual + \ ale#Escape(ale#path#Simplify(g:dir . '/textlint_paths/with_bin_path/node_modules/.bin/textlint')) + \ . ' -f json --stdin --stdin-filename %s', + \ ale#handlers#textlint#GetCommand(bufnr('')) + +Execute(The local executable from textlint/bin should be used if available): + call ale#test#SetFilename('textlint_paths/with_textlint_bin_path/foo.txt') + + AssertEqual + \ ale#path#Simplify(g:dir . '/textlint_paths/with_textlint_bin_path/node_modules/textlint/bin/textlint.js'), + \ ale#handlers#textlint#GetExecutable(bufnr('')) + + if has('win32') + AssertEqual + \ ale#Escape('node.exe') . ' ' . ale#Escape(ale#path#Simplify(g:dir . '/textlint_paths/with_textlint_bin_path/node_modules/textlint/bin/textlint.js')) + \ . ' -f json --stdin --stdin-filename %s', + \ ale#handlers#textlint#GetCommand(bufnr('')) + else + AssertEqual + \ ale#Escape(ale#path#Simplify(g:dir . '/textlint_paths/with_textlint_bin_path/node_modules/textlint/bin/textlint.js')) + \ . ' -f json --stdin --stdin-filename %s', + \ ale#handlers#textlint#GetCommand(bufnr('')) + endif diff --git a/test/command_callback/test_tslint_command_callback.vader b/test/command_callback/test_tslint_command_callback.vader index 4ad42fa5..edab72c8 100644 --- a/test/command_callback/test_tslint_command_callback.vader +++ b/test/command_callback/test_tslint_command_callback.vader @@ -17,7 +17,10 @@ Before: After: Restore + unlet! b:ale_typescript_tslint_executable + unlet! b:ale_typescript_tslint_config_path unlet! b:ale_typescript_tslint_rules_dir + unlet! b:ale_typescript_tslint_use_global call ale#test#RestoreDirectory() call ale#linter#Reset() @@ -25,7 +28,7 @@ After: Execute(The default tslint command should be correct): AssertEqual \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && ' - \ . 'tslint --format json %t', + \ . ale#Escape('tslint') . ' --format json %t', \ ale_linters#typescript#tslint#GetCommand(bufnr('')) Execute(The rules directory option should be included if set): @@ -33,7 +36,16 @@ Execute(The rules directory option should be included if set): AssertEqual \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && ' - \ . 'tslint --format json' + \ . ale#Escape('tslint') . ' --format json' \ . ' -r ' . ale#Escape('/foo/bar') \ . ' %t', \ ale_linters#typescript#tslint#GetCommand(bufnr('')) + +Execute(The executable should be configurable and escaped): + let b:ale_typescript_tslint_executable = 'foo bar' + + AssertEqual 'foo bar', ale_linters#typescript#tslint#GetExecutable(bufnr('')) + AssertEqual + \ 'cd ' . ale#Escape(expand('%:p:h')) . ' && ' + \ . ale#Escape('foo bar') . ' --format json %t', + \ ale_linters#typescript#tslint#GetCommand(bufnr('')) diff --git a/test/command_callback/test_vint_command_callback.vader b/test/command_callback/test_vint_command_callback.vader new file mode 100644 index 00000000..ddf39f31 --- /dev/null +++ b/test/command_callback/test_vint_command_callback.vader @@ -0,0 +1,39 @@ +Before: + Save g:ale_vim_vint_executable + + unlet! g:ale_vim_vint_executable + + runtime ale_linters/vim/vint.vim + + let b:command_tail = (has('nvim') ? ' --enable-neovim' : '') + \ . ' -f "{file_path}:{line_number}:{column_number}: {severity}: {description} (see {reference})" %t' + call ale#semver#ResetVersionCache() + +After: + Restore + + call ale#linter#Reset() + call ale#semver#ResetVersionCache() + + unlet! b:bin_dir + unlet! b:executable + +Execute(The default command should be correct): + AssertEqual 'vint', ale_linters#vim#vint#GetExecutable(bufnr('')) + AssertEqual + \ ale#Escape('vint') .' --version', + \ ale_linters#vim#vint#VersionCommand(bufnr('')) + AssertEqual + \ ale#Escape('vint') .' -s --no-color' . b:command_tail, + \ ale_linters#vim#vint#GetCommand(bufnr(''), []) + +Execute(The executable should be configurable): + let g:ale_vim_vint_executable = 'foobar' + + AssertEqual 'foobar', ale_linters#vim#vint#GetExecutable(bufnr('')) + AssertEqual + \ ale#Escape('foobar') .' --version', + \ ale_linters#vim#vint#VersionCommand(bufnr('')) + AssertEqual + \ ale#Escape('foobar') .' -s --no-color' . b:command_tail, + \ ale_linters#vim#vint#GetCommand(bufnr(''), []) diff --git a/test/command_callback/textlint_paths/with_bin_path/node_modules/.bin/textlint b/test/command_callback/textlint_paths/with_bin_path/node_modules/.bin/textlint new file mode 100755 index 00000000..e69de29b --- /dev/null +++ b/test/command_callback/textlint_paths/with_bin_path/node_modules/.bin/textlint diff --git a/test/command_callback/textlint_paths/with_textlint_bin_path/node_modules/textlint/bin/textlint.js b/test/command_callback/textlint_paths/with_textlint_bin_path/node_modules/textlint/bin/textlint.js new file mode 100755 index 00000000..e69de29b --- /dev/null +++ b/test/command_callback/textlint_paths/with_textlint_bin_path/node_modules/textlint/bin/textlint.js diff --git a/test/command_callback/tidy_paths/.tidyrc b/test/command_callback/tidy_paths/.tidyrc new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/test/command_callback/tidy_paths/.tidyrc diff --git a/test/command_callback/tidy_paths/test.html b/test/command_callback/tidy_paths/test.html new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/test/command_callback/tidy_paths/test.html diff --git a/test/command_callback/tidy_paths/tidy b/test/command_callback/tidy_paths/tidy new file mode 100755 index 00000000..e69de29b --- /dev/null +++ b/test/command_callback/tidy_paths/tidy diff --git a/test/command_callback/tidy_paths/tidy.exe b/test/command_callback/tidy_paths/tidy.exe new file mode 100755 index 00000000..e69de29b --- /dev/null +++ b/test/command_callback/tidy_paths/tidy.exe diff --git a/test/completion/test_completion_events.vader b/test/completion/test_completion_events.vader index 49d485f6..fbe18bb6 100644 --- a/test/completion/test_completion_events.vader +++ b/test/completion/test_completion_events.vader @@ -2,12 +2,9 @@ Before: Save g:ale_completion_enabled Save g:ale_completion_delay Save g:ale_completion_max_suggestions - Save g:ale_completion_experimental_lsp_support Save &l:omnifunc Save &l:completeopt - unlet! g:ale_completion_experimental_lsp_support - let g:ale_completion_enabled = 1 let g:get_completions_called = 0 let g:feedkeys_calls = [] @@ -43,7 +40,6 @@ After: unlet! b:ale_completion_response unlet! b:ale_completion_parser unlet! b:ale_complete_done_time - unlet! g:ale_completion_experimental_lsp_support delfunction CheckCompletionCalled diff --git a/test/completion/test_completion_filtering.vader b/test/completion/test_completion_filtering.vader index 3e461aef..ae91a952 100644 --- a/test/completion/test_completion_filtering.vader +++ b/test/completion/test_completion_filtering.vader @@ -1,15 +1,27 @@ +Before: + Save g:ale_completion_excluded_words + + let g:ale_completion_excluded_words = [] + +After: + Restore + + unlet! b:ale_completion_excluded_words + unlet! b:suggestions + Execute(Prefix filtering should work for Lists of strings): AssertEqual \ ['FooBar', 'foo'], - \ ale#completion#Filter(['FooBar', 'FongBar', 'baz', 'foo'], 'foo') + \ ale#completion#Filter(bufnr(''), ['FooBar', 'FongBar', 'baz', 'foo'], 'foo') AssertEqual \ ['FooBar', 'FongBar', 'baz', 'foo'], - \ ale#completion#Filter(['FooBar', 'FongBar', 'baz', 'foo'], '.') + \ ale#completion#Filter(bufnr(''), ['FooBar', 'FongBar', 'baz', 'foo'], '.') Execute(Prefix filtering should work for completion items): AssertEqual \ [{'word': 'FooBar'}, {'word': 'foo'}], \ ale#completion#Filter( + \ bufnr(''), \ [ \ {'word': 'FooBar'}, \ {'word': 'FongBar'}, @@ -18,6 +30,7 @@ Execute(Prefix filtering should work for completion items): \ ], \ 'foo' \ ) + AssertEqual \ [ \ {'word': 'FooBar'}, @@ -26,6 +39,7 @@ Execute(Prefix filtering should work for completion items): \ {'word': 'foo'}, \ ], \ ale#completion#Filter( + \ bufnr(''), \ [ \ {'word': 'FooBar'}, \ {'word': 'FongBar'}, @@ -34,3 +48,61 @@ Execute(Prefix filtering should work for completion items): \ ], \ '.' \ ) + +Execute(Excluding words from completion results should work): + let b:ale_completion_excluded_words = ['it', 'describe'] + + AssertEqual + \ [{'word': 'Italian'}], + \ ale#completion#Filter( + \ bufnr(''), + \ [ + \ {'word': 'Italian'}, + \ {'word': 'it'}, + \ ], + \ 'it' + \ ) + + AssertEqual + \ [{'word': 'Deutsch'}], + \ ale#completion#Filter( + \ bufnr(''), + \ [ + \ {'word': 'describe'}, + \ {'word': 'Deutsch'}, + \ ], + \ 'de' + \ ) + + AssertEqual + \ [{'word': 'Deutsch'}], + \ ale#completion#Filter( + \ bufnr(''), + \ [ + \ {'word': 'describe'}, + \ {'word': 'Deutsch'}, + \ ], + \ '.' + \ ) + +Execute(Excluding words from completion results should work with lists of Strings): + let b:ale_completion_excluded_words = ['it', 'describe'] + + AssertEqual + \ ['Italian'], + \ ale#completion#Filter(bufnr(''), ['Italian', 'it'], 'it') + AssertEqual + \ ['Deutsch'], + \ ale#completion#Filter(bufnr(''), ['describe', 'Deutsch'], 'de') + AssertEqual + \ ['Deutsch'], + \ ale#completion#Filter(bufnr(''), ['describe', 'Deutsch'], '.') + +Execute(Filtering shouldn't modify the original list): + let b:ale_completion_excluded_words = ['it', 'describe'] + let b:suggestions = [{'word': 'describe'}] + + AssertEqual [], ale#completion#Filter(bufnr(''), b:suggestions, '.') + AssertEqual b:suggestions, [{'word': 'describe'}] + AssertEqual [], ale#completion#Filter(bufnr(''), b:suggestions, 'de') + AssertEqual b:suggestions, [{'word': 'describe'}] diff --git a/test/completion/test_completion_prefixes.vader b/test/completion/test_completion_prefixes.vader index 8ac29326..0b2cfeaf 100644 --- a/test/completion/test_completion_prefixes.vader +++ b/test/completion/test_completion_prefixes.vader @@ -2,6 +2,8 @@ Given typescript(): let abc = y. let foo = ab let foo = (ab) + let string1 = ' + let string2 = " Execute(Completion should be done after dots in TypeScript): AssertEqual '.', ale#completion#GetPrefix(&filetype, 1, 13) @@ -15,5 +17,29 @@ Execute(Completion should be done after words in parens in TypeScript): Execute(Completion should not be done after parens in TypeScript): AssertEqual '', ale#completion#GetPrefix(&filetype, 3, 15) +Execute(Completion should be done after strings in TypeScript): + AssertEqual '''', ale#completion#GetPrefix(&filetype, 4, 16) + AssertEqual '"', ale#completion#GetPrefix(&filetype, 5, 16) + +Execute(Completion prefixes should work for other filetypes): + AssertEqual 'ab', ale#completion#GetPrefix('xxxyyyzzz', 3, 14) + Execute(Completion prefixes should work for other filetypes): AssertEqual 'ab', ale#completion#GetPrefix('xxxyyyzzz', 3, 14) + +Given rust(): + let abc = y. + let abc = String:: + let foo = (ab) + +Execute(Completion should be done after dots in Rust): + AssertEqual '.', ale#completion#GetPrefix(&filetype, 1, 13) + +Execute(Completion should be done after colons in Rust): + AssertEqual '::', ale#completion#GetPrefix(&filetype, 2, 19) + +Execute(Completion should be done after words in parens in Rust): + AssertEqual 'ab', ale#completion#GetPrefix(&filetype, 3, 14) + +Execute(Completion should not be done after parens in Rust): + AssertEqual '', ale#completion#GetPrefix(&filetype, 3, 15) diff --git a/test/completion/test_lsp_completion_messages.vader b/test/completion/test_lsp_completion_messages.vader index f21acfb9..8ba2ad38 100644 --- a/test/completion/test_lsp_completion_messages.vader +++ b/test/completion/test_lsp_completion_messages.vader @@ -2,12 +2,9 @@ Before: Save g:ale_completion_delay Save g:ale_completion_max_suggestions Save g:ale_completion_info - Save g:ale_completion_experimental_lsp_support Save &l:omnifunc Save &l:completeopt - unlet! g:ale_completion_experimental_lsp_support - let g:ale_completion_enabled = 1 call ale#test#SetDirectory('/testplugin/test/completion') @@ -18,12 +15,18 @@ Before: let g:message_list = [] let g:Callback = '' - function! ale#linter#StartLSP(buffer, linter, callback) abort + function! ale#lsp_linter#StartLSP(buffer, linter, callback) abort let g:Callback = a:callback + let l:conn = ale#lsp#NewConnection({}) + let l:conn.id = 347 + let l:conn.open_documents = {a:buffer : -1} + return { + \ 'buffer': a:buffer, \ 'connection_id': 347, \ 'project_root': '/foo/bar', + \ 'language_id': 'python', \} endfunction @@ -44,8 +47,9 @@ After: unlet! b:ale_completion_parser unlet! b:ale_complete_done_time unlet! b:ale_linters - unlet! g:ale_completion_experimental_lsp_support + unlet! b:ale_tsserver_completion_names + call ale#lsp#RemoveConnectionWithID(347) call ale#test#RestoreDirectory() call ale#linter#Reset() @@ -116,6 +120,12 @@ Execute(The right message sent to the tsserver LSP when the first completion mes \ ], \}) + " We should save the names we got in the buffer, as TSServer doesn't return + " details for every name. + AssertEqual + \ ['Foo', 'FooBar', 'frazzle'], + \ get(b:, 'ale_tsserver_completion_names', []) + " The entry details messages should have been sent. AssertEqual \ [[ @@ -136,8 +146,6 @@ Given python(Some Python file): bazxyzxyzxyz Execute(The right message should be sent for the initial LSP request): - let g:ale_completion_experimental_lsp_support = 1 - runtime ale_linters/python/pyls.vim let b:ale_linters = ['pyls'] " The cursor position needs to match what was saved before. diff --git a/test/completion/test_lsp_completion_parsing.vader b/test/completion/test_lsp_completion_parsing.vader new file mode 100644 index 00000000..736353e3 --- /dev/null +++ b/test/completion/test_lsp_completion_parsing.vader @@ -0,0 +1,451 @@ +After: + unlet! b:ale_completion_info + +Execute(Should handle Rust completion results correctly): + AssertEqual + \ [ + \ {'word': 'new', 'menu': 'pub fn new() -> String', 'info': '', 'kind': 'f', 'icase': 1}, + \ {'word': 'with_capacity', 'menu': 'pub fn with_capacity(capacity: usize) -> String', 'info': '', 'kind': 'f', 'icase': 1}, + \ {'word': 'from_utf8', 'menu': 'pub fn from_utf8(vec: Vec<u8>) -> Result<String, FromUtf8Error>', 'info': '', 'kind': 'f', 'icase': 1}, + \ {'word': 'from_utf8_lossy', 'menu': 'pub fn from_utf8_lossy<''a>(v: &''a [u8]) -> Cow<''a, str>', 'info': '', 'kind': 'f', 'icase': 1}, + \ {'word': 'from_utf16', 'menu': 'pub fn from_utf16(v: &[u16]) -> Result<String, FromUtf16Error>', 'info': '', 'kind': 'f', 'icase': 1}, + \ {'word': 'from_utf16_lossy', 'menu': 'pub fn from_utf16_lossy(v: &[u16]) -> String', 'info': '', 'kind': 'f', 'icase': 1}, + \ {'word': 'from_raw_parts', 'menu': 'pub unsafe fn from_raw_parts(buf: *mut u8, length: usize, capacity: usize) -> String', 'info': '', 'kind': 'f', 'icase': 1}, + \ {'word': 'from_utf8_unchecked', 'menu': 'pub unsafe fn from_utf8_unchecked(bytes: Vec<u8>) -> String', 'info': '', 'kind': 'f', 'icase': 1}, + \ {'word': 'from_iter', 'menu': 'fn from_iter<I: IntoIterator<Item = char>>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1}, + \ {'word': 'from_iter', 'menu': 'fn from_iter<I: IntoIterator<Item = &''a char>>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1}, + \ {'word': 'from_iter', 'menu': 'fn from_iter<I: IntoIterator<Item = &''a str>>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1}, + \ {'word': 'from_iter', 'menu': 'fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1}, + \ {'word': 'from_iter', 'menu': 'fn from_iter<I: IntoIterator<Item = Cow<''a, str>>>(iter: I) -> String', 'info': '', 'kind': 'f', 'icase': 1}, + \ {'word': 'Searcher', 'menu': 'type Searcher = <&''b str as Pattern<''a>>::Searcher;', 'info': '', 'kind': 'f', 'icase': 1}, + \ {'word': 'default', 'menu': 'fn default() -> String', 'info': '', 'kind': 'f', 'icase': 1}, + \ {'word': 'Output', 'menu': 'type Output = String;', 'info': '', 'kind': 'f', 'icase': 1}, + \ {'word': 'Output', 'menu': 'type Output = str;', 'info': '', 'kind': 'f', 'icase': 1}, + \ {'word': 'Output', 'menu': 'type Output = str;', 'info': '', 'kind': 'f', 'icase': 1}, + \ {'word': 'Output', 'menu': 'type Output = str;', 'info': '', 'kind': 'f', 'icase': 1}, + \ {'word': 'Output', 'menu': 'type Output = str;', 'info': '', 'kind': 'f', 'icase': 1}, + \ {'word': 'Output', 'menu': 'type Output = str;', 'info': '', 'kind': 'f', 'icase': 1}, + \ {'word': 'Output', 'menu': 'type Output = str;', 'info': '', 'kind': 'f', 'icase': 1}, + \ {'word': 'Target', 'menu': 'type Target = str;', 'info': '', 'kind': 'f', 'icase': 1}, + \ {'word': 'Err', 'menu': 'type Err = ParseError;', 'info': '', 'kind': 'f', 'icase': 1}, + \ {'word': 'from_str', 'menu': 'fn from_str(s: &str) -> Result<String, ParseError>', 'info': '', 'kind': 'f', 'icase': 1}, + \ {'word': 'from', 'menu': 'fn from(s: &''a str) -> String', 'info': '', 'kind': 'f', 'icase': 1}, + \ {'word': 'from', 'menu': 'fn from(s: Box<str>) -> String', 'info': '', 'kind': 'f', 'icase': 1}, + \ {'word': 'from', 'menu': 'fn from(s: Cow<''a, str>) -> String', 'info': '', 'kind': 'f', 'icase': 1}, + \], + \ ale#completion#ParseLSPCompletions({ + \ "jsonrpc":"2.0", + \ "id":65, + \ "result":[ + \ { + \ "label":"new", + \ "kind":3, + \ "detail":"pub fn new() -> String" + \ }, + \ { + \ "label":"with_capacity", + \ "kind":3, + \ "detail":"pub fn with_capacity(capacity: usize) -> String" + \ }, + \ { + \ "label":"from_utf8", + \ "kind":3, + \ "detail":"pub fn from_utf8(vec: Vec<u8>) -> Result<String, FromUtf8Error>" + \ }, + \ { + \ "label":"from_utf8_lossy", + \ "kind":3, + \ "detail":"pub fn from_utf8_lossy<'a>(v: &'a [u8]) -> Cow<'a, str>" + \ }, + \ { + \ "label":"from_utf16", + \ "kind":3, + \ "detail":"pub fn from_utf16(v: &[u16]) -> Result<String, FromUtf16Error>" + \ }, + \ { + \ "label":"from_utf16_lossy", + \ "kind":3, + \ "detail":"pub fn from_utf16_lossy(v: &[u16]) -> String" + \ }, + \ { + \ "label":"from_raw_parts", + \ "kind":3, + \ "detail":"pub unsafe fn from_raw_parts(buf: *mut u8, length: usize, capacity: usize) -> String" + \ }, + \ { + \ "label":"from_utf8_unchecked", + \ "kind":3, + \ "detail":"pub unsafe fn from_utf8_unchecked(bytes: Vec<u8>) -> String" + \ }, + \ { + \ "label":"from_iter", + \ "kind":3, + \ "detail":"fn from_iter<I: IntoIterator<Item = char>>(iter: I) -> String" + \ }, + \ { + \ "label":"from_iter", + \ "kind":3, + \ "detail":"fn from_iter<I: IntoIterator<Item = &'a char>>(iter: I) -> String" + \ }, + \ { + \ "label":"from_iter", + \ "kind":3, + \ "detail":"fn from_iter<I: IntoIterator<Item = &'a str>>(iter: I) -> String" + \ }, + \ { + \ "label":"from_iter", + \ "kind":3, + \ "detail":"fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> String" + \ }, + \ { + \ "label":"from_iter", + \ "kind":3, + \ "detail":"fn from_iter<I: IntoIterator<Item = Cow<'a, str>>>(iter: I) -> String" + \ }, + \ { + \ "label":"Searcher", + \ "kind":8, + \ "detail":"type Searcher = <&'b str as Pattern<'a>>::Searcher;" + \ }, + \ { + \ "label":"default", + \ "kind":3, + \ "detail":"fn default() -> String" + \ }, + \ { + \ "label":"Output", + \ "kind":8, + \ "detail":"type Output = String;" + \ }, + \ { + \ "label":"Output", + \ "kind":8, + \ "detail":"type Output = str;" + \ }, + \ { + \ "label":"Output", + \ "kind":8, + \ "detail":"type Output = str;" + \ }, + \ { + \ "label":"Output", + \ "kind":8, + \ "detail":"type Output = str;" + \ }, + \ { + \ "label":"Output", + \ "kind":8, + \ "detail":"type Output = str;" + \ }, + \ { + \ "label":"Output", + \ "kind":8, + \ "detail":"type Output = str;" + \ }, + \ { + \ "label":"Output", + \ "kind":8, + \ "detail":"type Output = str;" + \ }, + \ { + \ "label":"Target", + \ "kind":8, + \ "detail":"type Target = str;" + \ }, + \ { + \ "label":"Err", + \ "kind":8, + \ "detail":"type Err = ParseError;" + \ }, + \ { + \ "label":"from_str", + \ "kind":3, + \ "detail":"fn from_str(s: &str) -> Result<String, ParseError>" + \ }, + \ { + \ "label":"from", + \ "kind":3, + \ "detail":"fn from(s: &'a str) -> String" + \ }, + \ { + \ "label":"from", + \ "kind":3, + \ "detail":"fn from(s: Box<str>) -> String" + \ }, + \ { + \ "label":"from", + \ "kind":3, + \ "detail":"fn from(s: Cow<'a, str>) -> String" + \ } + \ ] + \ }) + +Execute(Should handle Python completion results correctly): + let b:ale_completion_info = { + \ 'completion_filter': 'ale#completion#python#CompletionItemFilter', + \} + + AssertEqual + \ [ + \ {'word': 'what', 'menu': 'example-python-project.bar.Bar', 'info': "what()\n\n", 'kind': 'f', 'icase': 1}, + \ ], + \ ale#completion#ParseLSPCompletions({ + \ "jsonrpc":"2.0", + \ "id":6, + \ "result":{ + \ "isIncomplete":v:false, + \ "items":[ + \ { + \ "label":"what()", + \ "kind":3, + \ "detail":"example-python-project.bar.Bar", + \ "documentation":"what()\n\n", + \ "sortText":"awhat", + \ "insertText":"what" + \ }, + \ { + \ "label":"__class__", + \ "kind":7, + \ "detail":"object", + \ "documentation":"type(object_or_name, bases, dict)\ntype(object) -> the object's type\ntype(name, bases, dict) -> a new type", + \ "sortText":"z__class__", + \ "insertText":"__class__" + \ }, + \ { + \ "label":"__delattr__(name)", + \ "kind":3, + \ "detail":"object", + \ "documentation":"Implement delattr(self, name).", + \ "sortText":"z__delattr__", + \ "insertText":"__delattr__" + \ }, + \ { + \ "label":"__dir__()", + \ "kind":3, + \ "detail":"object", + \ "documentation":"__dir__() -> list\ndefault dir() implementation", + \ "sortText":"z__dir__", + \ "insertText":"__dir__" + \ }, + \ { + \ "label":"__doc__", + \ "kind":18, + \ "detail":"object", + \ "documentation":"str(object='') -> str\nstr(bytes_or_buffer[, encoding[, errors]]) -> str\n\nCreate a new string object from the given object. If encoding or\nerrors is specified, then the object must expose a data buffer\nthat will be decoded using the given encoding and error handler.\nOtherwise, returns the result of object.__str__() (if defined)\nor repr(object).\nencoding defaults to sys.getdefaultencoding().\nerrors defaults to 'strict'.", + \ "sortText":"z__doc__", + \ "insertText":"__doc__" + \ }, + \ { + \ "label":"__eq__(value)", + \ "kind":3, + \ "detail":"object", + \ "documentation":"Return self==value.", + \ "sortText":"z__eq__", + \ "insertText":"__eq__" + \ }, + \ { + \ "label":"__format__()", + \ "kind":3, + \ "detail":"object", + \ "documentation":"default object formatter", + \ "sortText":"z__format__", + \ "insertText":"__format__" + \ }, + \ { + \ "label":"__ge__(value)", + \ "kind":3, + \ "detail":"object", + \ "documentation":"Return self>=value.", + \ "sortText":"z__ge__", + \ "insertText":"__ge__" + \ }, + \ { + \ "label":"__getattribute__(name)", + \ "kind":3, + \ "detail":"object", + \ "documentation":"Return getattr(self, name).", + \ "sortText":"z__getattribute__", + \ "insertText":"__getattribute__" + \ }, + \ { + \ "label":"__gt__(value)", + \ "kind":3, + \ "detail":"object", + \ "documentation":"Return self>value.", + \ "sortText":"z__gt__", + \ "insertText":"__gt__" + \ }, + \ { + \ "label":"__hash__()", + \ "kind":3, + \ "detail":"object", + \ "documentation":"Return hash(self).", + \ "sortText":"z__hash__", + \ "insertText":"__hash__" + \ }, + \ { + \ "label":"__init__(args, kwargs)", + \ "kind":3, + \ "detail":"object", + \ "documentation":"Initialize self.\u00a0\u00a0See help(type(self)) for accurate signature.", + \ "sortText":"z__init__", + \ "insertText":"__init__" + \ }, + \ { + \ "label":"__init_subclass__()", + \ "kind":3, + \ "detail":"object", + \ "documentation":"This method is called when a class is subclassed.\n\nThe default implementation does nothing. It may be\noverridden to extend subclasses.", + \ "sortText":"z__init_subclass__", + \ "insertText":"__init_subclass__" + \ }, + \ { + \ "label":"__le__(value)", + \ "kind":3, + \ "detail":"object", + \ "documentation":"Return self<=value.", + \ "sortText":"z__le__", + \ "insertText":"__le__" + \ }, + \ { + \ "label":"__lt__(value)", + \ "kind":3, + \ "detail":"object", + \ "documentation":"Return self<value.", + \ "sortText":"z__lt__", + \ "insertText":"__lt__" + \ }, + \ { + \ "label":"__ne__(value)", + \ "kind":3, + \ "detail":"object", + \ "documentation":"Return self!=value.", + \ "sortText":"z__ne__", + \ "insertText":"__ne__" + \ }, + \ { + \ "label":"__new__(kwargs)", + \ "kind":3, + \ "detail":"object", + \ "documentation":"Create and return a new object.\u00a0\u00a0See help(type) for accurate signature.", + \ "sortText":"z__new__", + \ "insertText":"__new__" + \ }, + \ { + \ "label":"__reduce__()", + \ "kind":3, + \ "detail":"object", + \ "documentation":"helper for pickle", + \ "sortText":"z__reduce__", + \ "insertText":"__reduce__" + \ }, + \ { + \ "label":"__reduce_ex__()", + \ "kind":3, + \ "detail":"object", + \ "documentation":"helper for pickle", + \ "sortText":"z__reduce_ex__", + \ "insertText":"__reduce_ex__" + \ }, + \ { + \ "label":"__repr__()", + \ "kind":3, + \ "detail":"object", + \ "documentation":"Return repr(self).", + \ "sortText":"z__repr__", + \ "insertText":"__repr__" + \ }, + \ { + \ "label":"__setattr__(name, value)", + \ "kind":3, + \ "detail":"object", + \ "documentation":"Implement setattr(self, name, value).", + \ "sortText":"z__setattr__", + \ "insertText":"__setattr__" + \ }, + \ { + \ "label":"__sizeof__()", + \ "kind":3, + \ "detail":"object", + \ "documentation":"__sizeof__() -> int\nsize of object in memory, in bytes", + \ "sortText":"z__sizeof__", + \ "insertText":"__sizeof__" + \ }, + \ { + \ "label":"__str__()", + \ "kind":3, + \ "detail":"object", + \ "documentation":"Return str(self).", + \ "sortText":"z__str__", + \ "insertText":"__str__" + \ }, + \ { + \ "label":"__subclasshook__()", + \ "kind":3, + \ "detail":"object", + \ "documentation":"Abstract classes can override this to customize issubclass().\n\nThis is invoked early on by abc.ABCMeta.__subclasscheck__().\nIt should return True, False or NotImplemented.\u00a0\u00a0If it returns\nNotImplemented, the normal algorithm is used.\u00a0\u00a0Otherwise, it\noverrides the normal algorithm (and the outcome is cached).", + \ "sortText":"z__subclasshook__", + \ "insertText":"__subclasshook__" + \ } + \ ] + \ } + \ }) + +Execute(Should handle Python completion results correctly): + let b:ale_completion_info = { + \ 'completion_filter': 'ale#completion#python#CompletionItemFilter', + \ 'prefix': 'mig', + \} + + AssertEqual + \ [ + \ {'word': 'migrations', 'menu': 'xxx', 'info': 'migrations', 'kind': 'f', 'icase': 1}, + \ {'word': 'MigEngine', 'menu': 'xxx', 'info': 'mig engine', 'kind': 'f', 'icase': 1}, + \ ], + \ ale#completion#ParseLSPCompletions({ + \ 'jsonrpc': '2.0', + \ 'id': 6, + \ 'result': { + \ 'isIncomplete': v:false, + \ 'items': [ + \ { + \ 'label': 'migrations', + \ 'kind': 3, + \ 'detail': 'xxx', + \ 'documentation': 'migrations', + \ }, + \ { + \ 'label': 'MigEngine', + \ 'kind': 3, + \ 'detail': 'xxx', + \ 'documentation': 'mig engine', + \ }, + \ { + \ 'label': 'ignore me', + \ 'kind': 3, + \ 'detail': 'nope', + \ 'documentation': 'nope', + \ }, + \ ] + \ } + \ }) + +Execute(Should handle missing detail keys): + AssertEqual + \ [ + \ {'word': 'x', 'menu': '', 'info': 'y', 'kind': 'f', 'icase': 1}, + \ ], + \ ale#completion#ParseLSPCompletions({ + \ 'jsonrpc': '2.0', + \ 'id': 6, + \ 'result': { + \ 'isIncomplete': v:false, + \ 'items': [ + \ { + \ 'label': 'x', + \ 'kind': 3, + \ 'documentation': 'y', + \ }, + \ ] + \ } + \ }) diff --git a/test/completion/test_tsserver_completion_parsing.vader b/test/completion/test_tsserver_completion_parsing.vader index b663ef40..c8e2c993 100644 --- a/test/completion/test_tsserver_completion_parsing.vader +++ b/test/completion/test_tsserver_completion_parsing.vader @@ -1,3 +1,6 @@ +After: + unlet! b:ale_tsserver_completion_names + Execute(TypeScript completions responses should be parsed correctly): AssertEqual [], \ ale#completion#ParseTSServerCompletions({ @@ -73,3 +76,74 @@ Execute(TypeScript completion details responses should be parsed correctly): \ }, \ ], \}) + +Execute(Entries without details should be included in the responses): + let b:ale_tsserver_completion_names = ['xyz'] + + AssertEqual + \ [ + \ { + \ 'word': 'abc', + \ 'menu': '(property) Foo.abc: number', + \ 'info': '', + \ 'kind': 'f', + \ 'icase': 1, + \ }, + \ { + \ 'word': 'def', + \ 'menu': '(property) Foo.def: number', + \ 'info': 'foo bar baz', + \ 'kind': 'f', + \ 'icase': 1, + \ }, + \ { + \ 'word': 'xyz', + \ 'menu': '', + \ 'info': '', + \ 'kind': 'v', + \ 'icase': 1, + \ }, + \ ], + \ ale#completion#ParseTSServerCompletionEntryDetails({ + \ 'body': [ + \ { + \ 'name': 'abc', + \ 'kind': 'parameterName', + \ 'displayParts': [ + \ {'text': '('}, + \ {'text': 'property'}, + \ {'text': ')'}, + \ {'text': ' '}, + \ {'text': 'Foo'}, + \ {'text': '.'}, + \ {'text': 'abc'}, + \ {'text': ':'}, + \ {'text': ' '}, + \ {'text': 'number'}, + \ ], + \ }, + \ { + \ 'name': 'def', + \ 'kind': 'parameterName', + \ 'displayParts': [ + \ {'text': '('}, + \ {'text': 'property'}, + \ {'text': ')'}, + \ {'text': ' '}, + \ {'text': 'Foo'}, + \ {'text': '.'}, + \ {'text': 'def'}, + \ {'text': ':'}, + \ {'text': ' '}, + \ {'text': 'number'}, + \ ], + \ 'documentation': [ + \ {'text': 'foo'}, + \ {'text': ' '}, + \ {'text': 'bar'}, + \ {'text': ' '}, + \ {'text': 'baz'}, + \ ], + \ }, + \ ], + \}) diff --git a/test/cucumber_fixtures/features/cuke.feature b/test/cucumber_fixtures/features/cuke.feature new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/test/cucumber_fixtures/features/cuke.feature diff --git a/test/cucumber_fixtures/features/step_definitions/base_steps.rb b/test/cucumber_fixtures/features/step_definitions/base_steps.rb new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/test/cucumber_fixtures/features/step_definitions/base_steps.rb diff --git a/test/elm-test-files/app/node_modules/.bin/elm b/test/elm-test-files/app/node_modules/.bin/elm new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/test/elm-test-files/app/node_modules/.bin/elm diff --git a/test/fix/test_ale_fix.vader b/test/fix/test_ale_fix.vader index 817c243d..417394c3 100644 --- a/test/fix/test_ale_fix.vader +++ b/test/fix/test_ale_fix.vader @@ -17,6 +17,14 @@ Before: \ 'testft': [], \} + let g:pre_success = 0 + let g:post_success = 0 + augroup VaderTest + autocmd! + autocmd User ALEFixPre let g:pre_success = 1 + autocmd User ALEFixPost let g:post_success = 1 + augroup end + if !has('win32') let &shell = '/bin/bash' endif @@ -171,6 +179,7 @@ After: unlet! g:ale_emulate_job_failure unlet! b:ale_fixers unlet! b:ale_fix_on_save + augroup! VaderTest delfunction AddCarets delfunction AddDollars delfunction DoNothing @@ -248,6 +257,25 @@ Expect(Only the second function should be applied): $b $c +Execute(The * fixers shouldn't be used if an empty list is set for fixers): + let g:ale_fixers.testft = [] + let g:ale_fixers['*'] = ['AddDollars'] + ALEFix + +Expect(Nothing should be changed): + a + b + c + +Execute(* fixers should be used if no filetype is matched): + let g:ale_fixers = {'*': ['AddDollars']} + ALEFix + +Expect(The file should be changed): + $a + $b + $c + Execute(ALEFix should allow commands to be run): if has('win32') " Just skip this test on Windows, we can't run it. @@ -263,6 +291,15 @@ Expect(An extra line should be added): c d +Execute(ALEFix should use fixers passed in commandline when provided): + let g:ale_fixers.testft = ['RemoveLastLine'] + ALEFix AddCarets AddDollars + +Expect(Only fixers passed via command line should be run): + $^a + $^b + $^c + Execute(ALEFix should allow temporary files to be read): if has('win32') " Just skip this test on Windows, we can't run it. @@ -574,6 +611,16 @@ Execute(ALE should print a message telling you something isn't a valid fixer whe AssertEqual 'There is no fixer named `invalidname`. Check :ALEFixSuggest', GetLastMessage() +Execute(ALE should complain about invalid fixers with minuses in the name): + let g:ale_fixers.testft = ['foo-bar'] + ALEFix + + AssertEqual 'There is no fixer named `foo-bar`. Check :ALEFixSuggest', GetLastMessage() + +Execute(ALE should tolerate valid fixers with minuses in the name): + let g:ale_fixers.testft = ['prettier-standard'] + ALEFix + Execute(Test fixing with chained callbacks): let g:ale_fixers.testft = ['FirstChainCallback'] ALEFix @@ -654,3 +701,9 @@ Expect(The lines in the JSON should be used): x y z + +Execute(ALEFix should apply autocmds): + let g:ale_fixers.testft = ['AddCarets'] + ALEFix + AssertEqual g:pre_success, 1 + AssertEqual g:post_success, 1 diff --git a/test/fix/test_ale_fix_completion.vader b/test/fix/test_ale_fix_completion.vader new file mode 100644 index 00000000..6c38bb8d --- /dev/null +++ b/test/fix/test_ale_fix_completion.vader @@ -0,0 +1,23 @@ +Execute (List of available fixers is empty): + call ale#fix#registry#Clear() + +Then (List of applicable fixers for python file is empty): + AssertEqual [], ale#fix#registry#GetApplicableFixers('python') + +Execute (Add ruby fixer): + call ale#fix#registry#Add('ruby_fixer', 'fixer_fun', ['ruby'], 'ruby fixer') + +Then (List of applicable fixers for python file is still empty): + AssertEqual [], ale#fix#registry#GetApplicableFixers('python') + +Execute (Add generic fixer): + call ale#fix#registry#Add('generic_fixer', 'fixer_fun', [], 'generic fixer') + +Then (Generic fixer should be returned as applicable for python file): + AssertEqual ['generic_fixer'], ale#fix#registry#GetApplicableFixers('python') + +Execute (Add python fixer): + call ale#fix#registry#Add('python_fixer', 'fixer_func', ['python'], 'python fixer') + +Then (List of fixers should contain both generic and python fixers): + AssertEqual ['generic_fixer', 'python_fixer'], ale#fix#registry#GetApplicableFixers('python') diff --git a/test/fix/test_ale_fix_completion_filter.vader b/test/fix/test_ale_fix_completion_filter.vader new file mode 100644 index 00000000..536b7138 --- /dev/null +++ b/test/fix/test_ale_fix_completion_filter.vader @@ -0,0 +1,14 @@ +Before: + call ale#fix#registry#Clear() + call ale#test#SetFilename('test.js') + call ale#fix#registry#Add('prettier', '', ['javascript'], 'prettier') + call ale#fix#registry#Add('eslint', '', ['javascript'], 'eslint') + setfiletype javascript + +Execute(completeFixers returns all of the applicable fixers without an arglead): + AssertEqual ['eslint', 'prettier'], + \ ale#fix#registry#CompleteFixers('', 'ALEFix ', 7) + +Execute(completeFixers returns all of the applicable fixers without an arglead): + AssertEqual ['prettier'], + \ ale#fix#registry#CompleteFixers('pre', 'ALEFix ', 10) diff --git a/test/fixers/test_black_fixer_callback.vader b/test/fixers/test_black_fixer_callback.vader new file mode 100644 index 00000000..365b0fa6 --- /dev/null +++ b/test/fixers/test_black_fixer_callback.vader @@ -0,0 +1,39 @@ +Before: + Save g:ale_python_black_executable + Save g:ale_python_black_options + + " Use an invalid global executable, so we don't match it. + let g:ale_python_black_executable = 'xxxinvalid' + let g:ale_python_black_options = '' + + call ale#test#SetDirectory('/testplugin/test/fixers') + silent cd .. + silent cd command_callback + let g:dir = getcwd() + + let b:bin_dir = has('win32') ? 'Scripts' : 'bin' + +After: + Restore + + unlet! b:bin_dir + + call ale#test#RestoreDirectory() + +Execute(The black callback should return the correct default values): + AssertEqual + \ 0, + \ ale#fixers#black#Fix(bufnr('')) + + silent execute 'file ' . fnameescape(g:dir . '/python_paths/with_virtualenv/subdir/foo/bar.py') + AssertEqual + \ {'command': ale#Escape(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/env/' . b:bin_dir . '/black')) . ' -'}, + \ ale#fixers#black#Fix(bufnr('')) + +Execute(The black callback should include options): + let g:ale_python_black_options = '--some-option' + + silent execute 'file ' . fnameescape(g:dir . '/python_paths/with_virtualenv/subdir/foo/bar.py') + AssertEqual + \ {'command': ale#Escape(ale#path#Simplify(g:dir . '/python_paths/with_virtualenv/env/' . b:bin_dir . '/black')) . ' --some-option -' }, + \ ale#fixers#black#Fix(bufnr('')) diff --git a/test/fixers/test_brittany_fixer_callback.vader b/test/fixers/test_brittany_fixer_callback.vader index a0182b52..073e368c 100644 --- a/test/fixers/test_brittany_fixer_callback.vader +++ b/test/fixers/test_brittany_fixer_callback.vader @@ -18,6 +18,7 @@ Execute(The brittany callback should return the correct default values): \ { \ 'read_temporary_file': 1, \ 'command': ale#Escape('xxxinvalid') + \ . ' --write-mode inplace' \ . ' %t', \ }, \ ale#fixers#brittany#Fix(bufnr('')) diff --git a/test/fixers/test_elm_format_fixer_callback.vader b/test/fixers/test_elm_format_fixer_callback.vader index d613aa84..682c22ca 100644 --- a/test/fixers/test_elm_format_fixer_callback.vader +++ b/test/fixers/test_elm_format_fixer_callback.vader @@ -18,7 +18,7 @@ Execute(The elm-format command should have default params): \ ale#Escape(ale#path#Simplify(g:dir . '/../elm-test-files/node_modules/.bin/elm-format')) \ . ' %t --yes', \ }, - \ ale#fixers#format#Fix(bufnr('')) + \ ale#fixers#elm_format#Fix(bufnr('')) Execute(The elm-format command should manage use_global = 1 param): call ale#test#SetFilename('../elm-test-files/src/subdir/testfile.elm') @@ -31,7 +31,7 @@ Execute(The elm-format command should manage use_global = 1 param): \ ale#Escape('elm-format') \ . ' %t --yes', \ }, - \ ale#fixers#format#Fix(bufnr('')) + \ ale#fixers#elm_format#Fix(bufnr('')) Execute(The elm-format command should manage executable param): call ale#test#SetFilename('../elm-test-files/src/subdir/testfile.elm') @@ -45,7 +45,7 @@ Execute(The elm-format command should manage executable param): \ ale#Escape('elmformat') \ . ' %t --yes', \ }, - \ ale#fixers#format#Fix(bufnr('')) + \ ale#fixers#elm_format#Fix(bufnr('')) Execute(The elm-format command should manage empty options): call ale#test#SetFilename('../elm-test-files/src/subdir/testfile.elm') @@ -58,7 +58,7 @@ Execute(The elm-format command should manage empty options): \ ale#Escape(ale#path#Simplify(g:dir . '/../elm-test-files/node_modules/.bin/elm-format')) \ . ' %t', \ }, - \ ale#fixers#format#Fix(bufnr('')) + \ ale#fixers#elm_format#Fix(bufnr('')) Execute(The elm-format command should manage custom options): call ale#test#SetFilename('../elm-test-files/src/subdir/testfile.elm') @@ -71,4 +71,4 @@ Execute(The elm-format command should manage custom options): \ ale#Escape(ale#path#Simplify(g:dir . '/../elm-test-files/node_modules/.bin/elm-format')) \ . ' %t --param1 --param2', \ }, - \ ale#fixers#format#Fix(bufnr('')) + \ ale#fixers#elm_format#Fix(bufnr('')) diff --git a/test/fixers/test_mix_format_fixer_callback.vader b/test/fixers/test_mix_format_fixer_callback.vader index c6c97c57..365fbecf 100644 --- a/test/fixers/test_mix_format_fixer_callback.vader +++ b/test/fixers/test_mix_format_fixer_callback.vader @@ -1,10 +1,15 @@ Before: - call ale#test#SetDirectory('/testplugin/test/fixers') Save g:ale_elixir_mix_executable + Save g:ale_elixir_mix_format_options let g:ale_elixir_mix_executable = 'xxxinvalid' + let g:ale_elixir_mix_format_options = '' + + call ale#test#SetDirectory('/testplugin/test/fixers') After: + Restore + call ale#test#RestoreDirectory() Execute(The mix_format callback should return the correct default values): @@ -18,3 +23,14 @@ Execute(The mix_format callback should return the correct default values): \ }, \ ale#fixers#mix_format#Fix(bufnr('')) +Execute(The mix_format callback should include the correct format options): + let g:ale_elixir_mix_format_options = 'invalid_options' + call ale#test#SetFilename('../elixir-test-files/testfile.ex') + + AssertEqual + \ { + \ 'read_temporary_file': 1, + \ 'command': ale#Escape('xxxinvalid') + \ . ' format invalid_options %t', + \ }, + \ ale#fixers#mix_format#Fix(bufnr('')) diff --git a/test/fixers/test_perltidy_fixer_callback.vader b/test/fixers/test_perltidy_fixer_callback.vader new file mode 100644 index 00000000..c7430bfa --- /dev/null +++ b/test/fixers/test_perltidy_fixer_callback.vader @@ -0,0 +1,40 @@ +Before: + Save g:ale_perl_perltidy_executable + Save g:ale_perl_perltidy_options + + " Use an invalid global executable, so we don't match it. + let g:ale_perl_perltidy_executable = 'xxxinvalid' + let g:ale_perl_perltidy_options = '' + + call ale#test#SetDirectory('/testplugin/test/fixers') + +After: + Restore + + call ale#test#RestoreDirectory() + +Execute(The perltidy callback should return the correct default values): + call ale#test#SetFilename('../pl_files/testfile.pl') + + AssertEqual + \ { + \ 'read_temporary_file': 1, + \ 'command': ale#Escape('xxxinvalid') + \ . ' -b' + \ . ' %t', + \ }, + \ ale#fixers#perltidy#Fix(bufnr('')) + +Execute(The perltidy callback should include custom perltidy options): + let g:ale_perl_perltidy_options = "-r '(a) -> a'" + call ale#test#SetFilename('../pl_files/testfile.pl') + + AssertEqual + \ { + \ 'read_temporary_file': 1, + \ 'command': ale#Escape('xxxinvalid') + \ . ' -b' + \ . ' ' . g:ale_perl_perltidy_options + \ . ' %t', + \ }, + \ ale#fixers#perltidy#Fix(bufnr('')) diff --git a/test/fixers/test_php_cs_fixer.vader b/test/fixers/test_php_cs_fixer.vader new file mode 100644 index 00000000..b47c190c --- /dev/null +++ b/test/fixers/test_php_cs_fixer.vader @@ -0,0 +1,65 @@ +Before: + Save g:ale_php_cs_fixer_executable + Save g:ale_php_cs_fixer_options + let g:ale_php_cs_fixer_executable = 'php-cs-fixer' + let g:ale_php_cs_fixer_options = '' + + call ale#test#SetDirectory('/testplugin/test/fixers') + silent cd .. + silent cd command_callback + let g:dir = getcwd() + +After: + Restore + + call ale#test#RestoreDirectory() + + +Execute(project with php-cs-fixer should use local by default): + call ale#test#SetFilename('php_paths/project-with-php-cs-fixer/test.php') + + AssertEqual + \ ale#path#Simplify(g:dir . '/php_paths/project-with-php-cs-fixer/vendor/bin/php-cs-fixer'), + \ ale#fixers#php_cs_fixer#GetExecutable(bufnr('')) + +Execute(use-global should override local detection): + let g:ale_php_cs_fixer_use_global = 1 + call ale#test#SetFilename('php_paths/project-with-php-cs-fixer/test.php') + + AssertEqual + \ 'php-cs-fixer', + \ ale#fixers#php_cs_fixer#GetExecutable(bufnr('')) + +Execute(project without php-cs-fixer should use global): + call ale#test#SetFilename('php_paths/project-without-php-cs-fixer/test.php') + + AssertEqual + \ 'php-cs-fixer', + \ ale#fixers#php_cs_fixer#GetExecutable(bufnr('')) + + + + +Execute(The php-cs-fixer callback should return the correct default values): + call ale#test#SetFilename('php_paths/project-without-php-cs-fixer/foo/test.php') + + AssertEqual + \ { + \ 'read_temporary_file': 1, + \ 'command': ale#Escape('php-cs-fixer') + \ . ' ' . g:ale_php_cs_fixer_options + \ . ' fix %t' + \ }, + \ ale#fixers#php_cs_fixer#Fix(bufnr('')) + +Execute(The php-cs-fixer callback should include custom php-cs-fixer options): + let g:ale_php_cs_fixer_options = '--config="$HOME/.php_cs"' + call ale#test#SetFilename('php_paths/project-without-php-cs-fixer/test.php') + + AssertEqual + \ { + \ 'command': ale#Escape(g:ale_php_cs_fixer_executable) + \ . ' --config="$HOME/.php_cs" fix %t', + \ 'read_temporary_file': 1, + \ }, + \ ale#fixers#php_cs_fixer#Fix(bufnr('')) diff --git a/test/fixers/test_prettier_fixer_callback.vader b/test/fixers/test_prettier_fixer_callback.vader index c4f36f52..2018c3a6 100644 --- a/test/fixers/test_prettier_fixer_callback.vader +++ b/test/fixers/test_prettier_fixer_callback.vader @@ -95,3 +95,143 @@ Execute(The version number should be cached): \ . ' --stdin-filepath %s --stdin', \ }, \ ale#fixers#prettier#ApplyFixForVersion(bufnr(''), []) + +Execute(Should set --parser based on filetype, TypeScript): + call ale#test#SetFilename('../prettier-test-files/testfile') + + set filetype=typescript + + AssertEqual + \ { + \ 'command': 'cd ' . ale#Escape(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 + \ { + \ 'command': 'cd ' . ale#Escape(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 + \ { + \ 'command': 'cd ' . ale#Escape(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 + \ { + \ 'command': 'cd ' . ale#Escape(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 + \ { + \ 'command': 'cd ' . ale#Escape(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 + \ { + \ 'command': 'cd ' . ale#Escape(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 + \ { + \ 'command': 'cd ' . ale#Escape(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 + \ { + \ 'command': 'cd ' . ale#Escape(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 + \ { + \ 'command': 'cd ' . ale#Escape(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 first filetype of multiple filetypes): + call ale#test#SetFilename('../prettier-test-files/testfile') + + set filetype=css.scss + + AssertEqual + \ { + \ 'command': 'cd ' . ale#Escape(expand('%:p:h')) . ' && ' + \ . ale#Escape(g:ale_javascript_prettier_executable) + \ . ' --parser css' + \ . ' --stdin-filepath %s --stdin', + \ }, + \ ale#fixers#prettier#ApplyFixForVersion(bufnr(''), ['1.6.0']) diff --git a/test/fixers/test_qmlfmt_fixer_callback.vader b/test/fixers/test_qmlfmt_fixer_callback.vader new file mode 100644 index 00000000..e216f2e1 --- /dev/null +++ b/test/fixers/test_qmlfmt_fixer_callback.vader @@ -0,0 +1,12 @@ +Before: + Save g:ale_qml_qmlfmt_executable + +After: + Restore + +Execute(The qmlfmt fixer should use the options you set): + let g:ale_qml_qmlfmt_executable = 'foo-exe' + + AssertEqual + \ {'command': ale#Escape('foo-exe')}, + \ ale#fixers#qmlfmt#Fix(bufnr('')) diff --git a/test/fixers/test_rufo_fixer_callback.vader b/test/fixers/test_rufo_fixer_callback.vader new file mode 100644 index 00000000..a0828406 --- /dev/null +++ b/test/fixers/test_rufo_fixer_callback.vader @@ -0,0 +1,33 @@ +Before: + Save g:ale_ruby_rufo_executable + + " Use an invalid global executable, so we don't match it. + let g:ale_ruby_rufo_executable = 'xxxinvalid' + + call ale#test#SetDirectory('/testplugin/test/fixers') + silent cd .. + silent cd command_callback + let g:dir = getcwd() + +After: + Restore + + call ale#test#RestoreDirectory() + +Execute(The rufo command should contain `bundle exec` when executable is `bundle`): + let g:ale_ruby_rufo_executable = 'bundle' + call ale#test#SetFilename('ruby_paths/dummy.rb') + + AssertEqual + \ ale#Escape('bundle') . ' exec rufo %t', + \ ale#fixers#rufo#GetCommand(bufnr('')) + +Execute(The rufo callback should return the correct default values): + call ale#test#SetFilename('ruby_paths/dummy.rb') + + AssertEqual + \ { + \ 'read_temporary_file': 1, + \ 'command': ale#Escape('xxxinvalid') . ' %t' + \ }, + \ ale#fixers#rufo#Fix(bufnr('')) diff --git a/test/fixers/test_scalafmt_fixer_callback.vader b/test/fixers/test_scalafmt_fixer_callback.vader new file mode 100644 index 00000000..d82fda43 --- /dev/null +++ b/test/fixers/test_scalafmt_fixer_callback.vader @@ -0,0 +1,69 @@ +Before: + Save g:ale_scala_scalafmt_executable + Save g:ale_scala_scalafmt_options + + " Use an invalid global executable, so we don't match it. + let g:ale_scala_scalafmt_executable = 'xxxinvalid' + let g:ale_scala_scalafmt_options = '' + + call ale#test#SetDirectory('/testplugin/test/fixers') + silent cd .. + silent cd command_callback + let g:dir = getcwd() + +After: + Restore + + call ale#test#RestoreDirectory() + +Execute(The scalafmt callback should return the correct default values): + call ale#test#SetFilename('scala_paths/dummy.scala') + + AssertEqual + \ { + \ 'read_temporary_file': 1, + \ 'command': ale#Escape(g:ale_scala_scalafmt_executable) + \ . ' %t', + \ }, + \ ale#fixers#scalafmt#Fix(bufnr('')) + +Execute(The scalafmt callback should use ng with scalafmt automatically): + let g:ale_scala_scalafmt_executable = 'ng' + call ale#test#SetFilename('scala_paths/dummy.scala') + + AssertEqual + \ { + \ 'read_temporary_file': 1, + \ 'command': ale#Escape('ng') + \ . ' scalafmt' + \ . ' %t', + \ }, + \ ale#fixers#scalafmt#Fix(bufnr('')) + +Execute(The scalafmt callback should include custom scalafmt options): + let g:ale_scala_scalafmt_options = '--diff' + call ale#test#SetFilename('scala_paths/dummy.scala') + + AssertEqual + \ { + \ 'read_temporary_file': 1, + \ 'command': ale#Escape(g:ale_scala_scalafmt_executable) + \ . ' --diff' + \ . ' %t', + \ }, + \ ale#fixers#scalafmt#Fix(bufnr('')) + +Execute(The scalafmt callback should include custom scalafmt options and use ng with scalafmt): + let g:ale_scala_scalafmt_options = '--diff' + let g:ale_scala_scalafmt_executable = 'ng' + call ale#test#SetFilename('scala_paths/dummy.scala') + + AssertEqual + \ { + \ 'read_temporary_file': 1, + \ 'command': ale#Escape('ng') + \ . ' scalafmt' + \ . ' --diff' + \ . ' %t', + \ }, + \ ale#fixers#scalafmt#Fix(bufnr('')) diff --git a/test/fixers/test_tidy_fixer_callback.vader b/test/fixers/test_tidy_fixer_callback.vader new file mode 100644 index 00000000..5677d8fd --- /dev/null +++ b/test/fixers/test_tidy_fixer_callback.vader @@ -0,0 +1,29 @@ +Before: + Save g:ale_html_tidy_executable + + let g:ale_html_tidy_executable = 'tidy_paths/tidy' + + call ale#test#SetDirectory('/testplugin/test/fixers') + + silent cd .. + silent cd command_callback + let g:dir = getcwd() + +After: + Restore + + call ale#test#RestoreDirectory() + +Execute(The tidy callback should return 0 if tidy not found): + let g:ale_html_tidy_executable = 'xxxinvalidpath' + AssertEqual + \ 0, + \ ale#fixers#tidy#Fix(bufnr('')) + +Execute(The tidy callback should return the correct default command): + AssertEqual + \ { + \ 'command': ale#Escape('tidy_paths/tidy') + \ . ' -q --tidy-mark no --show-errors 0 --show-warnings 0' + \ }, + \ ale#fixers#tidy#Fix(bufnr('')) diff --git a/test/handler/test_cfn_python_lint_handler.vader b/test/handler/test_cfn_python_lint_handler.vader new file mode 100644 index 00000000..2c7ddc62 --- /dev/null +++ b/test/handler/test_cfn_python_lint_handler.vader @@ -0,0 +1,33 @@ +Before: + runtime! ale_linters/cloudformation/cfn_python_lint.vim + call ale#test#SetFilename('sample.template.yaml') + +After: + call ale#linter#Reset() + +Execute(The cfn_python_lint handler should parse items correctly): + AssertEqual + \ [ + \ { + \ 'lnum': '96', + \ 'col': '7', + \ 'end_lnum': '96', + \ 'end_col': '15', + \ 'text': 'Property Resources/Sample/Properties/FromPort should be of type Integer', + \ 'code': 'E3012', + \ 'type': 'E', + \ }, + \ { + \ 'lnum': '97', + \ 'col': '7', + \ 'end_lnum': '97', + \ 'end_col': '15', + \ 'text': 'AllowedPattern and/or AllowedValues for Parameter should be specified at Parameters/SampleIpAddress. Example for AllowedPattern "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$"', + \ 'code': 'W2509', + \ 'type': 'W', + \ }, + \ ], + \ ale_linters#cloudformation#cfn_python_lint#Handle(bufnr(''), [ + \ fnamemodify(tempname(), ':h') . '/sample.template.yaml:96:7:96:15:E3012:Property Resources/Sample/Properties/FromPort should be of type Integer', + \ fnamemodify(tempname(), ':h') . '/sample.template.yaml:97:7:97:15:W2509:AllowedPattern and/or AllowedValues for Parameter should be specified at Parameters/SampleIpAddress. Example for AllowedPattern "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$"', + \ ]) diff --git a/test/handler/test_cucumber_handler.vader b/test/handler/test_cucumber_handler.vader new file mode 100644 index 00000000..2b69a784 --- /dev/null +++ b/test/handler/test_cucumber_handler.vader @@ -0,0 +1,18 @@ +Before: + runtime ale_linters/cucumber/cucumber.vim + +After: + call ale#linter#Reset() + +Execute(The cucumber handler parses JSON correctly): + AssertEqual + \ [ + \ { + \ 'lnum': 13, + \ 'code': 'E', + \ 'text': 'Undefined step' + \ } + \ ], + \ ale_linters#cucumber#cucumber#Handle(bufnr(''), [ + \ '[{"elements": [{"steps": [{"result": {"status": "undefined"},"match": {"location": "features/cuke.feature:13"},"line": 13,"name": "Something undefined","keyword": "Given "},{"result": {"status": "skipped"},"match": {"location": "/var/lib/gems/2.3.0/gems/cucumber-3.1.0/lib/cucumber/step_match.rb:103"},"line": 14,"name": "I visit the profile page for Alice","keyword": "When "}],"type": "scenario","line": 12,"description": "","name": "Another scenario","keyword": "Scenario","id": "a-user-can-view-another-users-profile;another-scenario"}],"line": 1,"description": "","name": "A user can view another users profile","keyword": "Feature","id": "a-user-can-view-another-users-profile","uri": "features/cuke.feature"}]' + \ ]) diff --git a/test/handler/test_elmmake_handler.vader b/test/handler/test_elmmake_handler.vader index f3424b4b..41c9646f 100644 --- a/test/handler/test_elmmake_handler.vader +++ b/test/handler/test_elmmake_handler.vader @@ -9,7 +9,139 @@ After: call ale#linter#Reset() -Execute(The elm-make handler should parse lines correctly): + +" Elm 0.19 + +Execute(The elm-make handler should parse Elm 0.19 general problems correctly): + AssertEqual + \ [ + \ { + \ 'lnum': 1, + \ 'type': 'E', + \ 'text': "error details\n\nstyled details" + \ } + \ ], + \ ale_linters#elm#make#Handle(347, [ + \ '{ + \ "type": "error", + \ "path": "' . b:tmp . '/Module.elm", + \ "title": "UNKNOWN IMPORT", + \ "message": ["error details\n\n", { "string": "styled details" }] + \ }' + \ ]) + +Execute(The elm-make handler should parse Elm 0.19 compilation errors correctly): + AssertEqual + \ [ + \ { + \ 'lnum': 404, + \ 'col': 1, + \ 'end_lnum': 408, + \ 'end_col': 18, + \ 'type': 'E', + \ 'text': "error details 1\n\nstyled details" + \ }, + \ { + \ 'lnum': 406, + \ 'col': 5, + \ 'end_lnum': 407, + \ 'end_col': 17, + \ 'type': 'E', + \ 'text': "error details 2", + \ }, + \ { + \ 'lnum': 406, + \ 'col': 5, + \ 'end_lnum': 406, + \ 'end_col': 93, + \ 'type': 'E', + \ 'text': "error details 3", + \ }, + \ ], + \ ale_linters#elm#make#Handle(347, [ + \ '{ + \ "type": "compile-errors", + \ "errors": [ + \ { + \ "path": "' . b:tmp . '/Module.elm", + \ "problems": [ + \ { + \ "title": "TYPE MISMATCH", + \ "message": ["error details 1\n\n", { "string": "styled details" }], + \ "region": { "start": { "line": 404, "column": 1 }, "end": { "line": 408, "column": 18 } } + \ }, + \ { + \ "title": "TYPE MISMATCH", + \ "message": ["error details 2"], + \ "region": { "start": {"line": 406, "column": 5}, "end": {"line": 407, "column": 17 } } + \ }, + \ { + \ "title": "TYPE MISMATCH", + \ "message": ["error details 3"], + \ "region": { "start": { "line": 406, "column": 5}, "end": {"line": 406, "column": 93 } } + \ } + \ ] + \ } + \ ] + \ }' + \ ]) + +Execute(The elm-make handler should handle errors in Elm 0.19 imported modules): + AssertEqual + \ [ + \ { + \ 'lnum': 1, + \ 'type': 'E', + \ 'text': "src/Module.elm - error details\n\nstyled details", + \ 'detail': "src/Module.elm ----------\n\nerror details\n\nstyled details" + \ }, + \ { + \ 'lnum': 1, + \ 'type': 'E', + \ 'text': "Elm - error details\n\nstyled details", + \ 'detail': "Elm ----------\n\nerror details\n\nstyled details" + \ }, + \ { + \ 'lnum': 1, + \ 'type': 'E', + \ 'text': "src/Module.elm:404 - error details\n\nstyled details", + \ 'detail': "src/Module.elm:404 ----------\n\nerror details\n\nstyled details" + \ }, + \ ], + \ ale_linters#elm#make#Handle(347, [ + \ '{ + \ "type": "error", + \ "path": "src/Module.elm", + \ "title": "UNKNOWN IMPORT", + \ "message": ["error details\n\n", { "string": "styled details" }] + \ }', + \ '{ + \ "type": "error", + \ "path": null, + \ "title": "UNKNOWN IMPORT", + \ "message": ["error details\n\n", { "string": "styled details" }] + \ }', + \ '{ + \ "type": "compile-errors", + \ "errors": [ + \ { + \ "path": "src/Module.elm", + \ "problems": [ + \ { + \ "title": "TYPE MISMATCH", + \ "message": ["error details\n\n", { "string": "styled details" }], + \ "region": { "start": { "line": 404, "column": 1 }, "end": { "line": 408, "column": 18 } } + \ } + \ ] + \ } + \ ] + \ }' + \ ]) + + +" Elm 0.18 + +Execute(The elm-make handler should parse Elm 0.18 compilation errors correctly): AssertEqual \ [ \ { @@ -50,21 +182,90 @@ Execute(The elm-make handler should parse lines correctly): \ }, \ ], \ ale_linters#elm#make#Handle(347, [ - \ '[{"tag":"unused import","overview":"warning overview","details":"warning details","region":{"start":{"line":33,"column":1},"end":{"line":33,"column":19}},"type":"warning","file":"' . b:tmp . 'Module.elm"}]', - \ '[{"tag":"TYPE MISMATCH","overview":"error overview 1","subregion":{"start":{"line":406,"column":5},"end":{"line":408,"column":18}},"details":"error details 1","region":{"start":{"line":404,"column":1},"end":{"line":408,"column":18}},"type":"error","file":"' . b:tmp . 'Module.elm"},{"tag":"TYPE MISMATCH","overview":"error overview 2","subregion":{"start":{"line":407,"column":12},"end":{"line":407,"column":17}},"details":"error details 2","region":{"start":{"line":406,"column":5},"end":{"line":407,"column":17}},"type":"error","file":"' . b:tmp . 'Module.elm"},{"tag":"TYPE MISMATCH","overview":"error overview 3","subregion":{"start":{"line":406,"column":88},"end":{"line":406,"column":93}},"details":"error details 3","region":{"start":{"line":406,"column":5},"end":{"line":406,"column":93}},"type":"error","file":"' . b:tmp . 'Module.elm"}]' + \ '[ + \ { + \ "tag": "unused import", + \ "overview": "warning overview", + \ "details": "warning details", + \ "region": {"start": { "line": 33, "column": 1 }, "end": { "line": 33, "column": 19 } }, + \ "type": "warning", + \ "file": "' . b:tmp . '/Module.elm" + \ } + \ ]', + \ '[ + \ { + \ "tag": "TYPE MISMATCH", + \ "overview": "error overview 1", + \ "subregion": { "start": { "line": 406, "column": 5 }, "end": { "line": 408, "column": 18 } }, + \ "details": "error details 1", + \ "region": { "start": { "line": 404, "column": 1 }, "end": { "line": 408, "column": 18 } }, + \ "type": "error", + \ "file":"' . b:tmp . '/Module.elm" + \ }, + \ { + \ "tag": "TYPE MISMATCH", + \ "overview": "error overview 2", + \ "subregion": { "start": { "line": 407, "column": 12 }, "end": { "line": 407, "column": 17 } }, + \ "details": "error details 2", + \ "region": { "start": { "line": 406, "column": 5}, "end": { "line": 407, "column": 17 } }, + \ "type":"error", + \ "file":"' . b:tmp . '/Module.elm" + \ }, + \ { + \ "tag": "TYPE MISMATCH", + \ "overview": "error overview 3", + \ "subregion": { "start": { "line": 406, "column": 88 }, "end": { "line": 406, "column": 93 } }, + \ "details": "error details 3", + \ "region": { "start": { "line": 406, "column": 5 }, "end": { "line": 406, "column": 93 } }, + \ "type":"error", + \ "file":"' . b:tmp . '/Module.elm" + \ } + \ ]' \ ]) +Execute(The elm-make handler should handle errors in Elm 0.18 imported modules): + AssertEqual + \ [ + \ { + \ 'lnum': 1, + \ 'type': 'E', + \ 'text': "src/Module.elm:33 - error overview", + \ 'detail': "src/Module.elm:33 ----------\n\nerror overview\n\nerror details" + \ } + \ ], + \ ale_linters#elm#make#Handle(347, [ + \ '[ + \ { + \ "tag": "unused import", + \ "overview": "warning overview", + \ "details": "warning details", + \ "region": {"start": { "line": 33, "column": 1 }, "end": { "line": 33, "column": 19 } }, + \ "type": "warning", + \ "file": "src/Module.elm" + \ }, + \ { + \ "tag": "type error", + \ "overview": "error overview", + \ "details": "error details", + \ "region": {"start": { "line": 33, "column": 1 }, "end": { "line": 33, "column": 19 } }, + \ "type": "error", + \ "file": "src/Module.elm" + \ } + \ ]', + \ ]) + +" Generic + Execute(The elm-make handler should put an error on the first line if a line cannot be parsed): AssertEqual \ [ \ { - \ 'lnum': 33, + \ 'lnum': 404, \ 'col': 1, - \ 'end_lnum': 33, - \ 'end_col': 19, - \ 'type': 'W', - \ 'text': 'warning overview', - \ 'detail': "warning overview\n\nwarning details", + \ 'end_lnum': 408, + \ 'end_col': 18, + \ 'type': 'E', + \ 'text': "error details 1\n\nstyled details" \ }, \ { \ 'lnum': 1, @@ -74,7 +275,28 @@ Execute(The elm-make handler should put an error on the first line if a line can \ }, \ ], \ ale_linters#elm#make#Handle(347, [ - \ '[{"tag":"unused import","overview":"warning overview","details":"warning details","region":{"start":{"line":33,"column":1},"end":{"line":33,"column":19}},"type":"warning","file":"' . b:tmp . 'Module.elm"}]', - \ "Not JSON", - \ "Also not JSON", + \ '{ + \ "type": "compile-errors", + \ "errors": [ + \ { + \ "path": "' . b:tmp . '/Module.elm", + \ "problems": [ + \ { + \ "title": "TYPE MISMATCH", + \ "message": ["error details 1\n\n", { "string": "styled details" }], + \ "region": { "start": { "line": 404, "column": 1 }, "end": { "line": 408, "column": 18 } } + \ } + \ ] + \ } + \ ] + \ }', + \ 'Not JSON', + \ 'Also not JSON', + \ ]) + +Execute(The elm-make handler should ignore success lines): + AssertEqual + \ [], + \ ale_linters#elm#make#Handle(347, [ + \ 'Successfully generated /dev/null', \ ]) diff --git a/test/handler/test_fish_handler.vader b/test/handler/test_fish_handler.vader index 567952e4..ad3a963c 100644 --- a/test/handler/test_fish_handler.vader +++ b/test/handler/test_fish_handler.vader @@ -37,3 +37,25 @@ Execute(The fish handler should handle basic warnings and syntax errors): \ "abbr --add p 'cd ~/Projects'", \ '^', \ ]) + +Execute(The fish handler should handle problems where the problem before before the line with the line number): + AssertEqual + \ [ + \ { + \ 'lnum': 2, + \ 'col': 23, + \ 'text': 'Unsupported use of ''||''. In fish, please use ''COMMAND; or COMMAND''.', + \ }, + \ { + \ 'lnum': 5, + \ 'col': 1, + \ 'text': 'wat', + \ }, + \ ], + \ ale_linters#fish#fish#Handle(bufnr(''), [ + \ 'Unsupported use of ''||''. In fish, please use ''COMMAND; or COMMAND''.', + \ '/tmp/vLz620o/258/test.fish (line 2): if set -q SSH_CLIENT || set -q SSH_TTY', + \ ' ^', + \ '/tmp/vLz620o/258/test.fish (line 5): wat', + \ ' ^', + \ ]) diff --git a/test/handler/test_flake8_handler.vader b/test/handler/test_flake8_handler.vader index 492941c9..efacdfb2 100644 --- a/test/handler/test_flake8_handler.vader +++ b/test/handler/test_flake8_handler.vader @@ -214,3 +214,33 @@ Execute(Disabling trailing blank line warnings should work): \ ale_linters#python#flake8#Handle(bufnr(''), [ \ 'foo.py:6:1: W391 blank line at end of file', \ ]) + +Execute(F401 should be a warning): + AssertEqual + \ [ + \ { + \ 'lnum': 6, + \ 'col': 1, + \ 'code': 'F401', + \ 'type': 'W', + \ 'text': 'module imported but unused', + \ }, + \ ], + \ ale_linters#python#flake8#Handle(bufnr(''), [ + \ 'foo.py:6:1: F401 module imported but unused', + \ ]) + +Execute(E112 should be a syntax error): + AssertEqual + \ [ + \ { + \ 'lnum': 6, + \ 'col': 1, + \ 'code': 'E112', + \ 'type': 'E', + \ 'text': 'expected an indented block', + \ }, + \ ], + \ ale_linters#python#flake8#Handle(bufnr(''), [ + \ 'foo.py:6:1: E112 expected an indented block', + \ ]) diff --git a/test/handler/test_flawfinder_handler.vader b/test/handler/test_flawfinder_handler.vader new file mode 100644 index 00000000..708bac2a --- /dev/null +++ b/test/handler/test_flawfinder_handler.vader @@ -0,0 +1,57 @@ +Before: + Save g:ale_c_flawfinder_error_severity + + unlet! g:ale_c_flawfinder_error_severity + unlet! b:ale_c_flawfinder_error_severity + + runtime ale_linters/c/flawfinder.vim + +After: + unlet! g:ale_c_flawfinder_error_severity + Restore + +Execute(The Flawfinder handler should ignore other lines of output): + AssertEqual + \ [], + \ ale#handlers#flawfinder#HandleFlawfinderFormat(347, [ + \ 'foo', + \ 'bar', + \ 'baz', + \ ]) + +Execute(The Flawfinder handler should work): + AssertEqual + \ [ + \ { + \ 'lnum': 31, + \ 'col': 4, + \ 'type': 'W', + \ 'text': "(buffer) strncpy: Easily used incorrectly", + \ }, + \ ], + \ ale#handlers#flawfinder#HandleFlawfinderFormat(347, [ + \ "<stdin>:31:4: [1] (buffer) strncpy:Easily used incorrectly", + \ ]) + +Execute(The Flawfinder error severity level should be configurable): + let b:ale_c_flawfinder_error_severity = 2 + + AssertEqual + \ [ + \ { + \ 'lnum': 12, + \ 'col': 4, + \ 'type': 'E', + \ 'text': "(buffer) char: Statically-sized arrays can be bad", + \ }, + \ { + \ 'lnum': 31, + \ 'col': 4, + \ 'type': 'W', + \ 'text': "(buffer) strncpy: Easily used incorrectly", + \ }, + \ ], + \ ale#handlers#flawfinder#HandleFlawfinderFormat(bufnr(''), [ + \ "<stdin>:12:4: [2] (buffer) char:Statically-sized arrays can be bad", + \ "<stdin>:31:4: [1] (buffer) strncpy:Easily used incorrectly", + \ ]) diff --git a/test/handler/test_gawk_handler.vader b/test/handler/test_gawk_handler.vader new file mode 100644 index 00000000..3a7b5457 --- /dev/null +++ b/test/handler/test_gawk_handler.vader @@ -0,0 +1,39 @@ +Before: + runtime ale_linters/awk/gawk.vim + +After: + call ale#linter#Reset() + +Execute(gawk syntax errors should be parsed correctly): + + AssertEqual + \ [ + \ { + \ 'lnum': 1, + \ 'col': 0, + \ 'text': "invalid char ''' in expression", + \ 'code': 0, + \ 'type': 'E', + \ }, + \ { + \ 'lnum': 5, + \ 'col': 0, + \ 'text': 'unterminated string', + \ 'code': 0, + \ 'type': 'E', + \ }, + \ { + \ 'lnum': 10, + \ 'col': 0, + \ 'text': "escape sequence `\u' treated as plain `u'", + \ 'code': 0, + \ 'type': 'W', + \ }, + \ ], + \ ale#handlers#gawk#HandleGawkFormat(347, [ + \ "gawk: something.awk:1: BEGIN { system('touch aaaaaaaaa') }", + \ "gawk: something.awk:1: ^ invalid char ''' in expression", + \ 'gawk: something.awk:5: { x = "aaaaaaaaaaa', + \ 'gawk: something.awk:5: ^ unterminated string', + \ "gawk: something.awk:10: warning: escape sequence `\u' treated as plain `u'", + \ ]) diff --git a/test/handler/test_gcc_handler.vader b/test/handler/test_gcc_handler.vader index 79f17899..678d3f42 100644 --- a/test/handler/test_gcc_handler.vader +++ b/test/handler/test_gcc_handler.vader @@ -148,3 +148,17 @@ Execute(The GCC handler should interpret - as being the current file): \ ale#handlers#gcc#HandleGCCFormat(347, [ \ '-:6:12: error: Some error', \ ]) + +Execute(The GCC handler should handle fatal error messages due to missing files): + AssertEqual + \ [ + \ { + \ 'lnum': 3, + \ 'col': 12, + \ 'type': 'E', + \ 'text': 'foo.h: No such file or directory' + \ }, + \ ], + \ ale#handlers#gcc#HandleGCCFormat(347, [ + \ '<stdin>:3:12: fatal error: foo.h: No such file or directory', + \ ]) diff --git a/test/handler/test_gitlint_handler.vader b/test/handler/test_gitlint_handler.vader index 73ee988f..60d632a0 100644 --- a/test/handler/test_gitlint_handler.vader +++ b/test/handler/test_gitlint_handler.vader @@ -1,8 +1,16 @@ Before: - runtime ale_linters/gitcommit/gitlint.vim + Save g:ale_warn_about_trailing_whitespace + + let g:ale_warn_about_trailing_whitespace = 1 + + runtime ale_linters/gitcommit/gitlint.vim After: - call ale#linter#Reset() + Restore + + unlet! b:ale_warn_about_trailing_whitespace + + call ale#linter#Reset() Execute(The gitlint handler should handle basic warnings and syntax errors): AssertEqual @@ -39,3 +47,24 @@ Execute(The gitlint handler should handle basic warnings and syntax errors): \ '8: T1 Title exceeds max length (92>72): "some very long commit subject line where the author can''t wait to explain what he just fixed"' \ ]) +Execute(Disabling trailing whitespace warnings should work): + AssertEqual + \ [ + \ { + \ 'lnum': 8, + \ 'type': 'E', + \ 'text': 'Trailing whitespace', + \ 'code': 'T2', + \ }, + \ ], + \ ale_linters#gitcommit#gitlint#Handle(bufnr(''), [ + \ '8: T2 Trailing whitespace', + \]) + + let b:ale_warn_about_trailing_whitespace = 0 + + AssertEqual + \ [], + \ ale_linters#gitcommit#gitlint#Handle(bufnr(''), [ + \ '8: T2 Trailing whitespace', + \ ]) diff --git a/test/handler/test_go_generic_handler.vader b/test/handler/test_go_generic_handler.vader new file mode 100644 index 00000000..624e56c1 --- /dev/null +++ b/test/handler/test_go_generic_handler.vader @@ -0,0 +1,22 @@ +Execute(The golang handler should return the correct filenames): + AssertEqual + \ [ + \ { + \ 'lnum': 27, + \ 'col': 0, + \ 'text': 'some error', + \ 'type': 'E', + \ 'filename': ale#path#Simplify(expand('%:p:h') . '/test.go'), + \ }, + \ { + \ 'lnum': 27, + \ 'col': 5, + \ 'text': 'some error with a column', + \ 'type': 'E', + \ 'filename': ale#path#Simplify(expand('%:p:h') . '/other.go'), + \ }, + \ ], + \ ale#handlers#go#Handler(bufnr(''), [ + \ 'test.go:27: some error', + \ 'other.go:27:5: some error with a column', + \ ]) diff --git a/test/handler/test_markdownlint_handler.vader b/test/handler/test_markdownlint_handler.vader new file mode 100644 index 00000000..db6acc66 --- /dev/null +++ b/test/handler/test_markdownlint_handler.vader @@ -0,0 +1,24 @@ +Before: + runtime ale_linters/markdown/markdownlint.vim + +After: + call ale#linter#Reset() + +Execute(The Markdownlint handler should parse output correctly): + AssertEqual + \ [ + \ { + \ 'lnum': 1, + \ 'text': '(MD002/first-header-h1) First header should be a top level header [Expected: h1; Actual: h2]', + \ 'type': 'W' + \ }, + \ { + \ 'lnum': 298, + \ 'text': '(MD033/no-inline-html) Inline HTML [Element: p]', + \ 'type': 'W' + \ } + \ ], + \ ale#handlers#markdownlint#Handle(0, [ + \ 'README.md: 1: MD002/first-header-h1 First header should be a top level header [Expected: h1; Actual: h2]', + \ 'README.md: 298: MD033/no-inline-html Inline HTML [Element: p]' + \ ]) diff --git a/test/handler/test_mcsc_handler.vader b/test/handler/test_mcsc_handler.vader index ac55ee81..8ae47357 100644 --- a/test/handler/test_mcsc_handler.vader +++ b/test/handler/test_mcsc_handler.vader @@ -3,10 +3,15 @@ Before: unlet! g:ale_cs_mcsc_source + call ale#test#SetDirectory('/testplugin/test/handler') + call ale#test#SetFilename('Test.cs') + runtime ale_linters/cs/mcsc.vim After: unlet! g:ale_cs_mcsc_source + + call ale#test#RestoreDirectory() call ale#linter#Reset() Execute(The mcs handler should work with the default of the buffer's directory): @@ -18,10 +23,10 @@ Execute(The mcs handler should work with the default of the buffer's directory): \ 'text': '; expected', \ 'code': 'CS1001', \ 'type': 'E', - \ 'filename': ale#path#Simplify(expand('%:p:h') . '/Test.cs'), + \ 'filename': ale#path#Simplify(g:dir . '/Test.cs'), \ }, \ ], - \ ale_linters#cs#mcsc#Handle(347, [ + \ ale_linters#cs#mcsc#Handle(bufnr(''), [ \ 'Test.cs(12,29): error CS1001: ; expected', \ 'Compilation failed: 2 error(s), 1 warnings', \ ]) @@ -56,7 +61,7 @@ Execute(The mcs handler should handle cannot find symbol errors): \ 'filename': ale#path#Simplify('/home/foo/project/bar/Test.cs'), \ }, \ ], - \ ale_linters#cs#mcsc#Handle(347, [ + \ ale_linters#cs#mcsc#Handle(bufnr(''), [ \ 'Test.cs(12,29): error CS1001: ; expected', \ 'Test.cs(101,0): error CS1028: Unexpected processor directive (no #if for this #endif)', \ 'Test.cs(10,12): warning CS0123: some warning', diff --git a/test/handler/test_mercury_mmc_handler.vader b/test/handler/test_mercury_mmc_handler.vader new file mode 100644 index 00000000..e862f287 --- /dev/null +++ b/test/handler/test_mercury_mmc_handler.vader @@ -0,0 +1,58 @@ +Before: + runtime ale_linters/mercury/mmc.vim + +After: + call ale#linter#Reset() + +Execute(The mmc handler should handle syntax errors): + AssertEqual + \ [ + \ { + \ 'lnum': 3, + \ 'type': 'E', + \ 'text': "Syntax error at token ',': operator precedence error." + \ } + \ ], + \ ale_linters#mercury#mmc#Handle(1, [ + \ "file_name.m:003: Syntax error at token ',': operator precedence error." + \ ]) + +Execute(The mmc handler should handle warnings): + AssertEqual + \ [ + \ { + \ 'lnum': 10, + \ 'type': 'W', + \ 'text': 'Warning: reference to uninitialized state variable !.X.' + \ }, + \ { + \ 'lnum': 12, + \ 'type': 'W', + \ 'text': 'warning: determinism declaration could be tighter.' + \ } + \ ], + \ ale_linters#mercury#mmc#Handle(1, [ + \ 'file_name.m:010: Warning: reference to uninitialized state variable !.X.', + \ "file_name.m:012: In `some_predicate':", + \ 'file_name.m:012: warning: determinism declaration could be tighter.' + \ ]) + +Execute(The mmc handler should handle semantic errors): + AssertEqual + \ [ + \ { + \ 'lnum': 7, + \ 'type': 'E', + \ 'text': "error: undefined type `bar'/0." + \ }, + \ { + \ 'lnum': 15, + \ 'type': 'E', + \ 'text': "Error: circular equivalence type `file_name.foo'/0." + \ } + \ ], + \ ale_linters#mercury#mmc#Handle(1, [ + \ "file_name.m:007: In clause for predicate `foldit'/4:", + \ "file_name.m:007: error: undefined type `bar'/0.", + \ "file_name.m:015: Error: circular equivalence type `file_name.foo'/0." + \ ]) diff --git a/test/handler/test_mix_handler.vader b/test/handler/test_mix_handler.vader new file mode 100644 index 00000000..a5549b5d --- /dev/null +++ b/test/handler/test_mix_handler.vader @@ -0,0 +1,21 @@ +Before: + runtime ale_linters/elixir/mix.vim + +After: + call ale#linter#Reset() + +Execute(The mix handler should parse lines correctly): + + AssertEqual + \ [ + \ { + \ 'bufnr': 347, + \ 'lnum': 87, + \ 'col': 0, + \ 'text': 'undefined function update_in/4', + \ 'type': 'E', + \ }, + \ ], + \ ale_linters#elixir#mix#Handle(347, [ + \ '** (CompileError) apps/sim/lib/sim/server.ex:87: undefined function update_in/4' + \ ]) diff --git a/test/handler/test_msgfmt_hander.vader b/test/handler/test_msgfmt_hander.vader new file mode 100644 index 00000000..1a67dbc6 --- /dev/null +++ b/test/handler/test_msgfmt_hander.vader @@ -0,0 +1,24 @@ +Before: + runtime ale_linters/po/msgfmt.vim + +After: + call ale#linter#Reset() + +Execute(Duplicate messages should be made easier to navigate): + AssertEqual + \ [ + \ {'lnum': 14, 'col': 0, 'type': 'W', 'text': 'some other thing'}, + \ {'lnum': 1746, 'col': 0, 'type': 'W', 'text': 'duplicate of message at line 262'}, + \ {'lnum': 262, 'col': 0, 'type': 'W', 'text': 'first location of duplicate of message at line 1746'}, + \ {'lnum': 666, 'col': 0, 'type': 'W', 'text': 'duplicate message definition...'}, + \ {'lnum': 888, 'col': 0, 'type': 'W', 'text': 'some other thing'}, + \ {'lnum': 999, 'col': 0, 'type': 'W', 'text': '...this is the location of the first definition'}, + \ ], + \ ale_linters#po#msgfmt#Handle(bufnr(''), [ + \ '/tmp/v6GMUFf/16/foo.po:14: some other thing', + \ '/tmp/v6GMUFf/16/foo.po:1746: duplicate message definition...', + \ '/tmp/v6GMUFf/16/foo.po:262: ...this is the location of the first definition', + \ '/tmp/v6GMUFf/16/foo.po:666: duplicate message definition...', + \ '/tmp/v6GMUFf/16/foo.po:888: some other thing', + \ '/tmp/v6GMUFf/16/foo.po:999: ...this is the location of the first definition', + \ ]) diff --git a/test/handler/test_nasm_handler.vader b/test/handler/test_nasm_handler.vader new file mode 100644 index 00000000..9c7d9650 --- /dev/null +++ b/test/handler/test_nasm_handler.vader @@ -0,0 +1,30 @@ +Before: + runtime ale_linters/nasm/nasm.vim + +After: + call ale#linter#Reset() + +Execute(The nasm handler should parse GCC style output from nasm correctly): + AssertEqual + \ [ + \ { + \ 'lnum': 2, + \ 'text': "label alone on a line without a colon might be in error", + \ 'type': 'W', + \ }, + \ { + \ 'lnum': 4, + \ 'text': "invalid combination of opcode and operands", + \ 'type': 'E', + \ }, + \ { + \ 'lnum': 7, + \ 'text': "unable to open include file `bar.asm'", + \ 'type': 'E', + \ }, + \ ], + \ ale_linters#nasm#nasm#Handle(bufnr(''), [ + \ "tmp.asm:2: warning: label alone on a line without a colon might be in error", + \ "tmp.asm:4: error: invalid combination of opcode and operands", + \ "tmp.asm:7: fatal: unable to open include file `bar.asm'" + \ ]) diff --git a/test/handler/test_perl_handler.vader b/test/handler/test_perl_handler.vader index 75e8f226..c5791d76 100644 --- a/test/handler/test_perl_handler.vader +++ b/test/handler/test_perl_handler.vader @@ -47,3 +47,42 @@ Execute(The Perl linter should complain about failing to locate modules): \ 'Unable to build `ro` accessor for slot `path` in `App::CPANFileUpdate` because the slot cannot be found. at /extlib/Method/Traits.pm line 189.', \ 'BEGIN failed--compilation aborted at - line 10.', \ ]) + +Execute(The Perl linter should not report warnings as errors): + AssertEqual + \ [ + \ {'lnum': '5', 'type': 'W', 'text': '"my" variable $foo masks earlier declaration in same scope'}, + \ ], + \ ale_linters#perl#perl#Handle(bufnr(''), [ + \ '"my" variable $foo masks earlier declaration in same scope at - line 5.', + \ 't.pl syntax OK', + \ ]) + +Execute(The Perl linter does not default to reporting generic error): + AssertEqual + \ [ + \ {'lnum': '8', 'type': 'E', 'text': 'Missing right curly or square bracket'}, + \ ], + \ ale_linters#perl#perl#Handle(bufnr(''), [ + \ 'Missing right curly or square bracket at - line 8, at end of line', + \ 'syntax error at - line 8, at EOF', + \ 'Execution of t.pl aborted due to compilation errors.', + \ ]) + +" The first "error" is actually a warning, but the current implementation +" doesn't have a good way of teasing out the warnings from amongst the +" errors. If we're able to do this in future, then we'll want to switch +" the first "E" to a "W". + +Execute(The Perl linter reports errors even when mixed with warnings): + AssertEqual + \ [ + \ {'lnum': '5', 'type': 'E', 'text': '"my" variable $foo masks earlier declaration in same scope'}, + \ {'lnum': '8', 'type': 'E', 'text': 'Missing right curly or square bracket'}, + \ ], + \ ale_linters#perl#perl#Handle(bufnr(''), [ + \ '"my" variable $foo masks earlier declaration in same scope at - line 5.', + \ 'Missing right curly or square bracket at - line 8, at end of line', + \ 'syntax error at - line 8, at EOF', + \ 'Execution of t.pl aborted due to compilation errors.', + \ ]) diff --git a/test/handler/test_pmd_handler.vader b/test/handler/test_pmd_handler.vader new file mode 100644 index 00000000..0c95fb2a --- /dev/null +++ b/test/handler/test_pmd_handler.vader @@ -0,0 +1,27 @@ +Before: + runtime ale_linters/java/pmd.vim + +After: + call ale#linter#Reset() + +Execute(The pmd handler should parse lines correctly): + AssertEqual + \ [ + \ { + \ 'lnum': 18, + \ 'text': 'Each class should declare at least one constructor', + \ 'code': 'Code Style - AtLeastOneConstructor', + \ 'type': 'W', + \ }, + \ { + \ 'lnum': 36, + \ 'text': 'Local variable ''node'' could be declared final', + \ 'code': 'Code Style - LocalVariableCouldBeFinal', + \ 'type': 'W', + \ }, + \ ], + \ ale_linters#java#pmd#Handle(666, [ + \ '"Problem","Package","File","Priority","Line","Description","Rule set","Rule"', + \ '"1","rsb.performance.test.ros","/home/languitar/src/rsb-performance-test-api-ros/src/main/java/rsb/performance/test/ros/NodeHolder.java","3","18","Each class should declare at least one constructor","Code Style","AtLeastOneConstructor"', + \ '"2","rsb.performance.test.ros","/home/languitar/src/rsb-performance-test-api-ros/src/main/java/rsb/performance/test/ros/NodeHolder.java","1","36","Local variable ''node'' could be declared final","Code Style","LocalVariableCouldBeFinal"' + \ ]) diff --git a/test/handler/test_pony_handler.vader b/test/handler/test_pony_handler.vader new file mode 100644 index 00000000..25a8254b --- /dev/null +++ b/test/handler/test_pony_handler.vader @@ -0,0 +1,21 @@ +Execute(The pony handler should handle ponyc output): + call ale#test#SetFilename('foo.pony') + + AssertEqual + \ [ + \ { + \ 'filename': '/home/projects/Wombat.pony', + \ 'lnum': 22, + \ 'type': 'E', + \ 'col': 30, + \ 'text': 'can''t lookup private fields from outside the type', + \ }, + \ ], + \ ale#handlers#pony#HandlePonycFormat(bufnr(''), [ + \ 'Building builtin -> /usr/lib/pony/0.21.3/packages/builtin', + \ 'Building . -> /home/projects', + \ 'Error:', + \ '/home/projects/Wombat.pony:22:30: can''t lookup private fields from outside the type', + \ ' env.out.print(defaultWombat._hunger_level)', + \ ' ^', + \ ]) diff --git a/test/handler/test_puppet_handler.vader b/test/handler/test_puppet_handler.vader index 0d274fd2..e73c9dc7 100644 --- a/test/handler/test_puppet_handler.vader +++ b/test/handler/test_puppet_handler.vader @@ -37,9 +37,15 @@ Execute(The puppet handler should parse lines and column correctly): \ 'lnum': 54, \ 'col': 9, \ 'text': "Syntax error at ':'" - \ } + \ }, + \ { + \ 'lnum': 45, + \ 'col': 12, + \ 'text': "Syntax error at 'parameter1'" + \ }, \ ], \ ale_linters#puppet#puppet#Handle(255, [ \ "Error: Could not parse for environment production: Syntax error at ':' at /root/puppetcode/modules/nginx/manifests/init.pp:43:12", \ "Error: Could not parse for environment production: Syntax error at ':' at C:/puppet/modules/nginx/manifests/init.pp:54:9", + \ "Error: Could not parse for environment production: Syntax error at 'parameter1' (file: /tmp/modules/mariadb/manifests/slave.pp, line: 45, column: 12)", \ ]) diff --git a/test/handler/test_pycodestyle_handler.vader b/test/handler/test_pycodestyle_handler.vader index 0fd885d6..3664455e 100644 --- a/test/handler/test_pycodestyle_handler.vader +++ b/test/handler/test_pycodestyle_handler.vader @@ -137,3 +137,18 @@ Execute(Disabling trailing blank line warnings should work): \ ale_linters#python#pycodestyle#Handle(bufnr(''), [ \ 'foo.py:6:1: W391 blank line at end of file', \ ]) + +Execute(E112 should be a syntax error): + AssertEqual + \ [ + \ { + \ 'lnum': 6, + \ 'col': 1, + \ 'code': 'E112', + \ 'type': 'E', + \ 'text': 'expected an indented block', + \ }, + \ ], + \ ale_linters#python#pycodestyle#Handle(bufnr(''), [ + \ 'foo.py:6:1: E112 expected an indented block', + \ ]) diff --git a/test/handler/test_pylint_handler.vader b/test/handler/test_pylint_handler.vader index aff40845..18f66526 100644 --- a/test/handler/test_pylint_handler.vader +++ b/test/handler/test_pylint_handler.vader @@ -94,3 +94,22 @@ Execute(Ignoring trailing whitespace messages should work): \ '------------------------------------------------------------------', \ 'Your code has been rated at 0.00/10 (previous run: 2.50/10, -2.50)', \ ]) + +Execute(The pylint handler should parse Windows filenames): + AssertEqual + \ [ + \ { + \ 'lnum': 13, + \ 'col': 6, + \ 'text': 'Undefined variable ''x''', + \ 'code': 'undefined-variable', + \ 'type': 'E', + \ }, + \ ], + \ ale_linters#python#pylint#Handle(bufnr(''), [ + \ '************* Module test', + \ 'D:\acm\github\vim\tools\test.py:13:5: E0602 (undefined-variable) Undefined variable ''x''', + \ '', + \ '------------------------------------------------------------------', + \ 'Your code has been rated at 5.83/10 (previous run: 5.83/10, +0.00)', + \ ]) diff --git a/test/handler/test_qmlfmt_handler.vader b/test/handler/test_qmlfmt_handler.vader new file mode 100644 index 00000000..fc8ef355 --- /dev/null +++ b/test/handler/test_qmlfmt_handler.vader @@ -0,0 +1,19 @@ +Before: + runtime ale_linters/qml/qmlfmt.vim + +After: + call ale#linter#Reset() + +Execute(The qmlfmt handler should parse error messages correctly): + AssertEqual + \ [ + \ { + \ 'lnum': 22, + \ 'col': 1, + \ 'type': 'E', + \ 'text': 'Expected token ''}''.' + \ } + \ ], + \ ale_linters#qml#qmlfmt#Handle(1, [ + \ 'Error:22:1: Expected token ''}''.' + \ ]) diff --git a/test/handler/test_qmllint_handler.vader b/test/handler/test_qmllint_handler.vader new file mode 100644 index 00000000..fcc65eb5 --- /dev/null +++ b/test/handler/test_qmllint_handler.vader @@ -0,0 +1,19 @@ +Before: + runtime ale_linters/qml/qmllint.vim + +After: + call ale#linter#Reset() + +Execute(The qmllint handler should parse error messages correctly): + AssertEqual + \ [ + \ { + \ 'lnum': 2, + \ 'col': 0, + \ 'type': 'E', + \ 'text': 'Expected token ''}''' + \ } + \ ], + \ ale_linters#qml#qmllint#Handle(1, [ + \ '/tmp/ab34cd56/Test.qml:2 : Expected token ''}''' + \ ]) diff --git a/test/handler/test_redpen_handler.vader b/test/handler/test_redpen_handler.vader index f28d6923..4490bcba 100644 --- a/test/handler/test_redpen_handler.vader +++ b/test/handler/test_redpen_handler.vader @@ -23,6 +23,15 @@ Execute(redpen handler should handle errors output): \ 'type': 'W', \ 'code': 'Spelling', \ }, + \ { + \ 'lnum': 1, + \ 'col': 35, + \ 'end_lnum': 1, + \ 'end_col': 55, + \ 'text': 'Found possibly misspelled word "コードチェック".', + \ 'type': 'W', + \ 'code': 'Spelling', + \ }, \ ], \ ale#handlers#redpen#HandleRedpenOutput(bufnr(''), [ \ '[', @@ -50,6 +59,21 @@ Execute(redpen handler should handle errors output): \ ' "lineNum": 1,', \ ' "sentenceStartColumnNum": 0,', \ ' "message": "Found possibly misspelled word \"NeoVim\"."', + \ ' },', + \ ' {', + \ ' "sentence": "ALEはNeoVimとVim8で非同期のコードチェックを実現するプラグインです。",', + \ ' "endPosition": {', + \ ' "offset": 27,', + \ ' "lineNum": 1', + \ ' },', + \ ' "validator": "Spelling",', + \ ' "lineNum": 1,', + \ ' "sentenceStartColumnNum": 0,', + \ ' "message": "Found possibly misspelled word \"コードチェック\".",', + \ ' "startPosition": {', + \ ' "offset": 20,', + \ ' "lineNum": 1', + \ ' }', \ ' }', \ ' ]', \ ' }', diff --git a/test/handler/test_remark_lint_handler.vader b/test/handler/test_remark_lint_handler.vader index f61da199..0794d51c 100644 --- a/test/handler/test_remark_lint_handler.vader +++ b/test/handler/test_remark_lint_handler.vader @@ -19,12 +19,21 @@ Execute(Warning and error messages should be handled correctly): \ 'type': 'E', \ 'text': 'Incorrect list-item indent: remove 1 space list-item-indent remark-lint', \ }, + \ { + \ 'lnum': 18, + \ 'col': 71, + \ 'end_lnum': 19, + \ 'end_col': 1, + \ 'type': 'E', + \ 'text': 'Missing new line after list item list-item-spacing remark-lint', + \ }, \ ], \ ale_linters#markdown#remark_lint#Handle(1, [ \ 'foo.md', \ ' 1:4 warning Incorrect list-item indent: add 1 space list-item-indent remark-lint', \ ' 3:5 error Incorrect list-item indent: remove 1 space list-item-indent remark-lint', + \ ' 18:71-19:1 error Missing new line after list item list-item-spacing remark-lint', \ '', \ '⚠ 1 warnings', - \ '✘ 1 errors', + \ '✘ 2 errors', \]) diff --git a/test/handler/test_scala_handler.vader b/test/handler/test_scala_handler.vader new file mode 100644 index 00000000..3214bdbc --- /dev/null +++ b/test/handler/test_scala_handler.vader @@ -0,0 +1,32 @@ +After: + call ale#linter#Reset() + +Execute(The handler should return an empty list with empty input): + AssertEqual [], ale#handlers#scala#HandleScalacLintFormat(bufnr(''), []) + +Execute(The handler should correctly parse error messages): + AssertEqual + \ [ + \ { + \ 'lnum': 4, + \ 'col': 8, + \ 'text': ''':'' expected but identifier found.', + \ 'type': 'E' + \ }, + \ { + \ 'lnum': 6, + \ 'col': 2, + \ 'text': 'identifier expected but eof found.', + \ 'type': 'E' + \ } + \ ], + \ ale#handlers#scala#HandleScalacLintFormat(bufnr(''), + \ [ + \ "hi.scala:4: error: ':' expected but identifier found.", + \ " Some stupid scala code", + \ " ^", + \ "hi.scala:6: error: identifier expected but eof found.", + \ ")", + \ " ^", + \ "two errors found", + \ ]) diff --git a/test/handler/test_textlint_handler.vader b/test/handler/test_textlint_handler.vader new file mode 100644 index 00000000..c00d54de --- /dev/null +++ b/test/handler/test_textlint_handler.vader @@ -0,0 +1,41 @@ +Before: + runtime! ale_linters/markdown/textlint.vim + +After: + call ale#linter#Reset() + +Execute(textlint handler should handle errors output): + AssertEqual + \ [ + \ { + \ 'lnum': 16, + \ 'col': 50, + \ 'text': 'Found possibly misspelled word "NeoVim".', + \ 'type': 'W', + \ 'code': 'preset-japanese/no-doubled-joshi', + \ }, + \ ], + \ ale#handlers#textlint#HandleTextlintOutput(bufnr(''), [ + \ '[', + \ ' {', + \ ' "filePath": "test.md",', + \ ' "messages": [', + \ ' {', + \ ' "type": "lint",', + \ ' "ruleId": "preset-japanese/no-doubled-joshi",', + \ ' "index": 1332,', + \ ' "line": 16,', + \ ' "column": 50,', + \ ' "severity": 2,', + \ ' "message": "Found possibly misspelled word \"NeoVim\"."', + \ ' }', + \ ' ]', + \ ' }', + \ ']', + \ ]) + +Execute(textlint handler should no error output): + AssertEqual + \ [], + \ ale#handlers#textlint#HandleTextlintOutput(bufnr(''), [ + \ ]) diff --git a/test/lsp/test_did_save_event.vader b/test/lsp/test_did_save_event.vader index 042a3ce2..97774372 100644 --- a/test/lsp/test_did_save_event.vader +++ b/test/lsp/test_did_save_event.vader @@ -34,12 +34,18 @@ Before: \ }) let g:ale_linters = {'foobar': ['dummy_linter']} - function! ale#linter#StartLSP(buffer, linter, callback) abort + function! ale#lsp_linter#StartLSP(buffer, linter, callback) abort let g:Callback = a:callback + let l:conn = ale#lsp#NewConnection({}) + let l:conn.id = 347 + let l:conn.open_documents = {a:buffer : -1} + return { + \ 'buffer': a:buffer, \ 'connection_id': 347, \ 'project_root': '/foo/bar', + \ 'language_id': 'foobar', \} endfunction @@ -59,6 +65,7 @@ After: delfunction LanguageCallback delfunction ProjectRootCallback + call ale#lsp#RemoveConnectionWithID(347) call ale#test#RestoreDirectory() call ale#linter#Reset() diff --git a/test/lsp/test_lsp_client_messages.vader b/test/lsp/test_lsp_client_messages.vader index 053da803..dc28c2e9 100644 --- a/test/lsp/test_lsp_client_messages.vader +++ b/test/lsp/test_lsp_client_messages.vader @@ -16,9 +16,11 @@ Execute(ale#lsp#message#Initialize() should return correct messages): \ 'processId': getpid(), \ 'rootPath': '/foo/bar', \ 'capabilities': {}, + \ 'initializationOptions': {'foo': 'bar'}, + \ 'rootUri': 'file:///foo/bar', \ } \ ], - \ ale#lsp#message#Initialize('/foo/bar') + \ ale#lsp#message#Initialize('/foo/bar', {'foo': 'bar'}) Execute(ale#lsp#message#Initialized() should return correct messages): AssertEqual [1, 'initialized'], ale#lsp#message#Initialized() @@ -144,6 +146,35 @@ Execute(ale#lsp#message#Definition() should return correct messages): \ ], \ ale#lsp#message#Definition(bufnr(''), 12, 34) +Execute(ale#lsp#message#References() should return correct messages): + AssertEqual + \ [ + \ 0, + \ 'textDocument/references', + \ { + \ 'textDocument': { + \ 'uri': ale#path#ToURI(g:dir . '/foo/bar.ts'), + \ }, + \ 'position': {'line': 11, 'character': 34}, + \ 'context': {'includeDeclaration': v:false}, + \ } + \ ], + \ ale#lsp#message#References(bufnr(''), 12, 34) + +Execute(ale#lsp#message#Hover() should return correct messages): + AssertEqual + \ [ + \ 0, + \ 'textDocument/hover', + \ { + \ 'textDocument': { + \ 'uri': ale#path#ToURI(g:dir . '/foo/bar.ts'), + \ }, + \ 'position': {'line': 11, 'character': 34}, + \ } + \ ], + \ ale#lsp#message#Hover(bufnr(''), 12, 34) + Execute(ale#lsp#tsserver_message#Open() should return correct messages): AssertEqual \ [ @@ -233,3 +264,29 @@ Execute(ale#lsp#tsserver_message#Definition() should return correct messages): \ } \ ], \ ale#lsp#tsserver_message#Definition(bufnr(''), 347, 12) + +Execute(ale#lsp#tsserver_message#References() should return correct messages): + AssertEqual + \ [ + \ 0, + \ 'ts@references', + \ { + \ 'file': ale#path#Simplify(g:dir . '/foo/bar.ts'), + \ 'line': 347, + \ 'offset': 12, + \ } + \ ], + \ ale#lsp#tsserver_message#References(bufnr(''), 347, 12) + +Execute(ale#lsp#tsserver_message#Quickinfo() should return correct messages): + AssertEqual + \ [ + \ 0, + \ 'ts@quickinfo', + \ { + \ 'file': ale#path#Simplify(g:dir . '/foo/bar.ts'), + \ 'line': 347, + \ 'offset': 12, + \ } + \ ], + \ ale#lsp#tsserver_message#Quickinfo(bufnr(''), 347, 12) diff --git a/test/lsp/test_lsp_error_parsing.vader b/test/lsp/test_lsp_error_parsing.vader new file mode 100644 index 00000000..7464b0e7 --- /dev/null +++ b/test/lsp/test_lsp_error_parsing.vader @@ -0,0 +1,65 @@ +Execute(Invalid responses should be handled): + AssertEqual '', ale#lsp#response#GetErrorMessage({}) + AssertEqual '', ale#lsp#response#GetErrorMessage({'error': 0}) + AssertEqual '', ale#lsp#response#GetErrorMessage({'error': {}}) + AssertEqual '', ale#lsp#response#GetErrorMessage({ + \ 'error': { + \ 'code': 0, + \ 'message': 'x', + \ }, + \}) + AssertEqual '', ale#lsp#response#GetErrorMessage({'error': {'code': -32602}}) + AssertEqual '', ale#lsp#response#GetErrorMessage({'error': {'code': -32603}}) + +Execute(Messages without tracebacks should be handled): + AssertEqual 'xyz', ale#lsp#response#GetErrorMessage({ + \ 'error': { + \ 'code': -32602, + \ 'message': 'xyz', + \ }, + \}) + AssertEqual 'abc', ale#lsp#response#GetErrorMessage({ + \ 'error': { + \ 'code': -32603, + \ 'message': 'abc', + \ }, + \}) + +Execute(Invalid traceback data should be tolerated): + AssertEqual 'xyz', ale#lsp#response#GetErrorMessage({ + \ 'error': { + \ 'code': -32602, + \ 'message': 'xyz', + \ 'data': { + \ }, + \ }, + \}) + AssertEqual 'xyz', ale#lsp#response#GetErrorMessage({ + \ 'error': { + \ 'code': -32602, + \ 'message': 'xyz', + \ 'data': { + \ 'traceback': 0, + \ }, + \ }, + \}) + AssertEqual 'xyz', ale#lsp#response#GetErrorMessage({ + \ 'error': { + \ 'code': -32602, + \ 'message': 'xyz', + \ 'data': { + \ 'traceback': [], + \ }, + \ }, + \}) + +Execute(Messages with tracebacks should be handled): + AssertEqual "xyz\n123\n456", ale#lsp#response#GetErrorMessage({ + \ 'error': { + \ 'code': -32602, + \ 'message': 'xyz', + \ 'data': { + \ 'traceback': ['123', '456'], + \ }, + \ }, + \}) diff --git a/test/lsp/test_read_lsp_diagnostics.vader b/test/lsp/test_read_lsp_diagnostics.vader index 3e637418..444272aa 100644 --- a/test/lsp/test_read_lsp_diagnostics.vader +++ b/test/lsp/test_read_lsp_diagnostics.vader @@ -121,7 +121,8 @@ Execute(ale#lsp#response#ReadDiagnostics() should handle multiple messages): \ ]}}) Execute(ale#lsp#response#ReadTSServerDiagnostics() should handle tsserver responses): - AssertEqual [ + AssertEqual + \ [ \ { \ 'type': 'E', \ 'nr': 2365, @@ -131,5 +132,35 @@ Execute(ale#lsp#response#ReadTSServerDiagnostics() should handle tsserver respon \ 'end_lnum': 1, \ 'end_col': 17, \ }, - \], + \ ], \ ale#lsp#response#ReadTSServerDiagnostics({"seq":0,"type":"event","event":"semanticDiag","body":{"file":"/bar/foo.ts","diagnostics":[{"start":{"line":1,"offset":11},"end":{"line":1,"offset":17},"text":"Operator ''+'' cannot be applied to types ''3'' and ''{}''.","code":2365}]}}) + +Execute(ale#lsp#response#ReadTSServerDiagnostics() should handle warnings from tsserver): + AssertEqual + \ [ + \ { + \ 'lnum': 27, + \ 'col': 3, + \ 'nr': 2515, + \ 'end_lnum': 27, + \ 'type': 'W', + \ 'end_col': 14, + \ 'text': 'Calls to ''console.log'' are not allowed. (no-console)', + \ } + \ ], + \ ale#lsp#response#ReadTSServerDiagnostics({"seq":0,"type":"event","event":"semanticDiag","body":{"file":"<removed>","diagnostics":[{"start":{"line":27,"offset":3},"end":{"line":27,"offset":14},"text":"Calls to 'console.log' are not allowed. (no-console)","code":2515,"category":"warning","source":"tslint"}]}}) + +Execute(ale#lsp#response#ReadTSServerDiagnostics() should handle suggestions from tsserver): + AssertEqual + \ [ + \ { + \ 'lnum': 27, + \ 'col': 3, + \ 'nr': 2515, + \ 'end_lnum': 27, + \ 'type': 'I', + \ 'end_col': 14, + \ 'text': 'Some info', + \ } + \ ], + \ ale#lsp#response#ReadTSServerDiagnostics({"seq":0,"type":"event","event":"semanticDiag","body":{"file":"<removed>","diagnostics":[{"start":{"line":27,"offset":3},"end":{"line":27,"offset":14},"text":"Some info","code":2515,"category":"suggestion","source":"tslint"}]}}) diff --git a/test/lsp/test_reset_lsp.vader b/test/lsp/test_reset_lsp.vader new file mode 100644 index 00000000..2bec13dc --- /dev/null +++ b/test/lsp/test_reset_lsp.vader @@ -0,0 +1,90 @@ +Before: + Save g:ale_enabled + Save g:ale_set_signs + Save g:ale_set_quickfix + Save g:ale_set_loclist + Save g:ale_set_highlights + Save g:ale_echo_cursor + + let g:ale_enabled = 0 + let g:ale_set_signs = 0 + let g:ale_set_quickfix = 0 + let g:ale_set_loclist = 0 + let g:ale_set_highlights = 0 + let g:ale_echo_cursor = 0 + + function EmptyString() abort + return '' + endfunction + + call ale#engine#InitBufferInfo(bufnr('')) + + call ale#linter#Define('testft', { + \ 'name': 'lsplinter', + \ 'lsp': 'tsserver', + \ 'executable_callback': 'EmptyString', + \ 'command_callback': 'EmptyString', + \ 'project_root_callback': 'EmptyString', + \ 'language_callback': 'EmptyString', + \}) + + call ale#linter#Define('testft', { + \ 'name': 'otherlinter', + \ 'callback': 'TestCallback', + \ 'executable': has('win32') ? 'cmd': 'true', + \ 'command': 'true', + \ 'read_buffer': 0, + \}) + +After: + Restore + + unlet! b:ale_save_event_fired + + delfunction EmptyString + call ale#linter#Reset() + +Given testft(Some file with an imaginary filetype): +Execute(ALEStopAllLSPs should clear the loclist): + let g:ale_buffer_info[bufnr('')].loclist = [ + \ { + \ 'text': 'a', + \ 'lnum': 10, + \ 'col': 0, + \ 'bufnr': bufnr(''), + \ 'vcol': 0, + \ 'type': 'E', + \ 'nr': -1, + \ 'linter_name': 'lsplinter', + \ }, + \ { + \ 'text': 'a', + \ 'lnum': 10, + \ 'col': 0, + \ 'bufnr': bufnr(''), + \ 'vcol': 0, + \ 'type': 'E', + \ 'nr': -1, + \ 'linter_name': 'otherlinter', + \ }, + \] + let g:ale_buffer_info[bufnr('')].active_linter_list = ['lsplinter', 'otherlinter'] + + ALEStopAllLSPs + + " The loclist should be updated. + AssertEqual g:ale_buffer_info[bufnr('')].loclist, [ + \ { + \ 'text': 'a', + \ 'lnum': 10, + \ 'col': 0, + \ 'bufnr': bufnr(''), + \ 'vcol': 0, + \ 'type': 'E', + \ 'nr': -1, + \ 'linter_name': 'otherlinter', + \ }, + \] + + " The LSP linter should be removed from the active linter list. + AssertEqual g:ale_buffer_info[bufnr('')].active_linter_list, ['otherlinter'] diff --git a/test/prettier-test-files/testfile b/test/prettier-test-files/testfile new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/test/prettier-test-files/testfile diff --git a/test/script/check-supported-tools-tables b/test/script/check-supported-tools-tables index 32cebb2d..220c7427 100755 --- a/test/script/check-supported-tools-tables +++ b/test/script/check-supported-tools-tables @@ -1,4 +1,7 @@ -#!/bin/bash -eu +#!/usr/bin/env bash + +set -e +set -u # This script compares the table of supported tools in both the README file # and the doc/ale.txt file, so we can complain if they don't match up. diff --git a/test/script/check-toc b/test/script/check-toc index cc2d2b9c..8e411589 100755 --- a/test/script/check-toc +++ b/test/script/check-toc @@ -1,4 +1,7 @@ -#!/bin/bash -eu +#!/usr/bin/env bash + +set -e +set -u # This script checks that the table of contents for the supported tools is # sorted, and that the table matches the files. diff --git a/test/script/custom-checks b/test/script/custom-checks index 791053d4..76b9bc86 100755 --- a/test/script/custom-checks +++ b/test/script/custom-checks @@ -1,4 +1,7 @@ -#!/bin/bash -eu +#!/usr/bin/env bash + +set -e +set -u exit_code=0 image=w0rp/ale diff --git a/test/script/custom-linting-rules b/test/script/custom-linting-rules index ef6d792f..0d1a0fd1 100755 --- a/test/script/custom-linting-rules +++ b/test/script/custom-linting-rules @@ -1,4 +1,7 @@ -#!/bin/bash -eu +#!/usr/bin/env bash + +set -e +set -u # This Bash script implements custom sanity checks for scripts beyond what # Vint covers, which are easy to check with regex. diff --git a/test/script/run-vader-tests b/test/script/run-vader-tests index a10b8baf..3e7e815c 100755 --- a/test/script/run-vader-tests +++ b/test/script/run-vader-tests @@ -1,4 +1,7 @@ -#!/bin/bash -eu +#!/usr/bin/env bash + +set -e +set -u image=w0rp/ale docker_flags=(--rm -v "$PWD:/testplugin" -v "$PWD/test:/home" -w /testplugin "$image") diff --git a/test/script/run-vint b/test/script/run-vint index e1140307..0d5b6e11 100755 --- a/test/script/run-vint +++ b/test/script/run-vint @@ -1,4 +1,7 @@ -#!/bin/bash -eu +#!/usr/bin/env bash + +set -e +set -u exit_code=0 image=w0rp/ale diff --git a/test/sign/test_sign_placement.vader b/test/sign/test_sign_placement.vader index 36f34e16..19267fe7 100644 --- a/test/sign/test_sign_placement.vader +++ b/test/sign/test_sign_placement.vader @@ -1,7 +1,9 @@ Before: Save g:ale_set_signs + Save g:ale_buffer_info let g:ale_set_signs = 1 + let g:ale_buffer_info = {} call ale#linter#Reset() sign unplace * diff --git a/test/smoke_test.vader b/test/smoke_test.vader index f6d0be56..843bddab 100644 --- a/test/smoke_test.vader +++ b/test/smoke_test.vader @@ -93,7 +93,7 @@ Execute(Linters should run in PowerShell too): \}) call ale#Lint() - call ale#engine#WaitForJobs(2000) + call ale#engine#WaitForJobs(4000) AssertEqual [ \ { diff --git a/test/test_ale_info.vader b/test/test_ale_info.vader index e20125a3..39a2a85a 100644 --- a/test/test_ale_info.vader +++ b/test/test_ale_info.vader @@ -1,30 +1,50 @@ Before: Save g:ale_buffer_info Save g:ale_cache_executable_check_failures + Save g:ale_completion_delay Save g:ale_completion_enabled + Save g:ale_completion_max_suggestions Save g:ale_fixers Save g:ale_history_log_output Save g:ale_lint_on_insert_leave Save g:ale_lint_on_text_changed Save g:ale_linters + Save g:ale_lsp_error_messages Save g:ale_maximum_file_size Save g:ale_pattern_options Save g:ale_pattern_options_enabled Save g:ale_set_balloons + Save g:ale_sign_error + Save g:ale_sign_info + Save g:ale_sign_style_error + Save g:ale_sign_style_warning + Save g:ale_sign_warning + Save g:ale_statusline_format + Save g:ale_type_map Save g:ale_warn_about_trailing_whitespace unlet! b:ale_history let g:ale_buffer_info = {} let g:ale_cache_executable_check_failures = 0 + let g:ale_completion_delay = 100 let g:ale_completion_enabled = 0 + let g:ale_completion_max_suggestions = 50 let g:ale_history_log_output = 1 let g:ale_lint_on_insert_leave = 0 let g:ale_lint_on_text_changed = 'always' + let g:ale_lsp_error_messages = {} let g:ale_maximum_file_size = 0 let g:ale_pattern_options = {} let g:ale_pattern_options_enabled = 0 let g:ale_set_balloons = 0 + let g:ale_sign_error = '>>' + let g:ale_sign_info = '--' + let g:ale_sign_style_error = '>>' + let g:ale_sign_style_warning = '--' + let g:ale_sign_warning = '--' + let g:ale_statusline_format = ['%d error(s)', '%d warning(s)', 'OK'] + let g:ale_type_map = {} let g:ale_warn_about_trailing_whitespace = 1 let g:testlinter1 = {'name': 'testlinter1', 'executable': 'testlinter1', 'command': 'testlinter1', 'callback': 'testCB1', 'output_stream': 'stdout'} @@ -32,10 +52,19 @@ Before: call ale#engine#ResetExecutableCache() call ale#linter#Reset() + call ale#linter#PreventLoading('testft') let g:ale_linters = {} let g:ale_fixers = {} let g:ale_linter_aliases = {} let g:ale_buffer_info = {} + let g:fixer_lines = [ + \ ' Suggested Fixers: ', + \ ' ''foo'' - Fix things the foo way', + \] + let g:variables_lines = [ + \ ' Linter Variables:', + \ '', + \] let g:globals_lines = [ \ ' Global Variables:', \ '', @@ -66,6 +95,7 @@ Before: \ 'let g:ale_linters = {}', \ 'let g:ale_linters_explicit = 0', \ 'let g:ale_list_window_size = 10', + \ 'let g:ale_list_vertical = 0', \ 'let g:ale_loclist_msg_format = ''%code: %%s''', \ 'let g:ale_max_buffer_history_size = 20', \ 'let g:ale_max_signs = -1', @@ -87,6 +117,7 @@ Before: \ 'let g:ale_sign_warning = ''--''', \ 'let g:ale_statusline_format = [''%d error(s)'', ''%d warning(s)'', ''OK'']', \ 'let g:ale_type_map = {}', + \ 'let g:ale_use_global_executables = v:null', \ 'let g:ale_warn_about_trailing_blank_lines = 1', \ 'let g:ale_warn_about_trailing_whitespace = 1', \] @@ -104,6 +135,11 @@ Before: AssertEqual a:expected_list, split(l:output, "\n") endfunction + call ale#test#SetDirectory('/testplugin/test') + + call ale#fix#registry#Clear() + call ale#fix#registry#Add('foo', 'x', [], 'Fix things the foo way') + After: Restore @@ -113,6 +149,8 @@ After: unlet! b:ale_history unlet! b:ale_linters unlet! g:output + unlet! g:fixer_lines + unlet! g:variables_lines unlet! g:globals_string unlet! g:command_header unlet! g:ale_testft_testlinter1_foo @@ -122,15 +160,22 @@ After: unlet! g:ale_testft2_testlinter2_bar delfunction CheckInfo + call ale#test#RestoreDirectory() + call ale#fix#registry#ResetToDefaults() + Given nolintersft (Empty buffer with no linters): Execute (ALEInfo with no linters should return the right output): - call CheckInfo([ - \ ' Current Filetype: nolintersft', - \ 'Available Linters: []', - \ ' Enabled Linters: []', - \ ' Linter Variables:', - \ '', - \] + g:globals_lines + g:command_header) + call CheckInfo( + \ [ + \ ' Current Filetype: nolintersft', + \ 'Available Linters: []', + \ ' Enabled Linters: []', + \ ] + \ + g:fixer_lines + \ + g:variables_lines + \ + g:globals_lines + \ + g:command_header + \) Given (Empty buffer with no filetype): Execute (ALEInfo should return buffer-local global ALE settings): @@ -142,48 +187,64 @@ Execute (ALEInfo should return buffer-local global ALE settings): \ index(g:globals_lines, 'let g:ale_linters = {}') + 1 \) - call CheckInfo([ - \ ' Current Filetype: ', - \ 'Available Linters: []', - \ ' Enabled Linters: []', - \ ' Linter Variables:', - \ '', - \] + g:globals_lines + g:command_header) + call CheckInfo( + \ [ + \ ' Current Filetype: ', + \ 'Available Linters: []', + \ ' Enabled Linters: []', + \ ] + \ + g:fixer_lines + \ + g:variables_lines + \ + g:globals_lines + \ + g:command_header + \) Given (Empty buffer with no filetype): Execute (ALEInfo with no filetype should return the right output): - call CheckInfo([ - \ ' Current Filetype: ', - \ 'Available Linters: []', - \ ' Enabled Linters: []', - \ ' Linter Variables:', - \ '', - \] + g:globals_lines + g:command_header) + call CheckInfo( + \ [ + \ ' Current Filetype: ', + \ 'Available Linters: []', + \ ' Enabled Linters: []', + \ ] + \ + g:fixer_lines + \ + g:variables_lines + \ + g:globals_lines + \ + g:command_header + \) Given testft (Empty buffer): Execute (ALEInfo with a single linter should return the right output): call ale#linter#Define('testft', g:testlinter1) - call CheckInfo([ - \ ' Current Filetype: testft', - \ 'Available Linters: [''testlinter1'']', - \ ' Enabled Linters: [''testlinter1'']', - \ ' Linter Variables:', - \ '', - \] + g:globals_lines + g:command_header) + call CheckInfo( + \ [ + \ ' Current Filetype: testft', + \ 'Available Linters: [''testlinter1'']', + \ ' Enabled Linters: [''testlinter1'']', + \ ] + \ + g:fixer_lines + \ + g:variables_lines + \ + g:globals_lines + \ + g:command_header + \) Given testft (Empty buffer): Execute (ALEInfo with two linters should return the right output): call ale#linter#Define('testft', g:testlinter1) call ale#linter#Define('testft', g:testlinter2) - call CheckInfo([ - \ ' Current Filetype: testft', - \ 'Available Linters: [''testlinter1'', ''testlinter2'']', - \ ' Enabled Linters: [''testlinter1'', ''testlinter2'']', - \ ' Linter Variables:', - \ '', - \] + g:globals_lines + g:command_header) + call CheckInfo( + \ [ + \ ' Current Filetype: testft', + \ 'Available Linters: [''testlinter1'', ''testlinter2'']', + \ ' Enabled Linters: [''testlinter1'', ''testlinter2'']', + \ ] + \ + g:fixer_lines + \ + g:variables_lines + \ + g:globals_lines + \ + g:command_header + \) Given testft (Empty buffer): Execute (ALEInfo should calculate enabled linters correctly): @@ -194,39 +255,51 @@ Execute (ALEInfo should calculate enabled linters correctly): let g:globals_lines[index(g:globals_lines, 'let g:ale_linters = {}')] \ = 'let g:ale_linters = {''testft'': [''testlinter2'']}' - call CheckInfo([ - \ ' Current Filetype: testft', - \ 'Available Linters: [''testlinter1'', ''testlinter2'']', - \ ' Enabled Linters: [''testlinter2'']', - \ ' Linter Variables:', - \ '', - \] + g:globals_lines + g:command_header) + call CheckInfo( + \ [ + \ ' Current Filetype: testft', + \ 'Available Linters: [''testlinter1'', ''testlinter2'']', + \ ' Enabled Linters: [''testlinter2'']', + \ ] + \ + g:fixer_lines + \ + g:variables_lines + \ + g:globals_lines + \ + g:command_header + \) Given testft (Empty buffer): Execute (ALEInfo should only return linters for current filetype): call ale#linter#Define('testft', g:testlinter1) call ale#linter#Define('testft2', g:testlinter2) - call CheckInfo([ - \ ' Current Filetype: testft', - \ 'Available Linters: [''testlinter1'']', - \ ' Enabled Linters: [''testlinter1'']', - \ ' Linter Variables:', - \ '', - \] + g:globals_lines + g:command_header) + call CheckInfo( + \ [ + \ ' Current Filetype: testft', + \ 'Available Linters: [''testlinter1'']', + \ ' Enabled Linters: [''testlinter1'']', + \ ] + \ + g:fixer_lines + \ + g:variables_lines + \ + g:globals_lines + \ + g:command_header + \) Given testft.testft2 (Empty buffer with two filetypes): Execute (ALEInfo with compound filetypes should return linters for both of them): call ale#linter#Define('testft', g:testlinter1) call ale#linter#Define('testft2', g:testlinter2) - call CheckInfo([ - \ ' Current Filetype: testft.testft2', - \ 'Available Linters: [''testlinter1'', ''testlinter2'']', - \ ' Enabled Linters: [''testlinter1'', ''testlinter2'']', - \ ' Linter Variables:', - \ '', - \] + g:globals_lines + g:command_header) + call CheckInfo( + \ [ + \ ' Current Filetype: testft.testft2', + \ 'Available Linters: [''testlinter1'', ''testlinter2'']', + \ ' Enabled Linters: [''testlinter1'', ''testlinter2'']', + \ ] + \ + g:fixer_lines + \ + g:variables_lines + \ + g:globals_lines + \ + g:command_header + \) Given testft.testft2 (Empty buffer with two filetypes): Execute (ALEInfo should return appropriately named global variables): @@ -238,17 +311,58 @@ Execute (ALEInfo should return appropriately named global variables): call ale#linter#Define('testft', g:testlinter1) call ale#linter#Define('testft2', g:testlinter2) - call CheckInfo([ - \ ' Current Filetype: testft.testft2', - \ 'Available Linters: [''testlinter1'', ''testlinter2'']', - \ ' Enabled Linters: [''testlinter1'', ''testlinter2'']', - \ ' Linter Variables:', - \ '', - \ 'let g:ale_testft2_testlinter2_bar = {''x'': ''y''}', - \ 'let g:ale_testft2_testlinter2_foo = 123', - \ 'let g:ale_testft_testlinter1_bar = [''abc'']', - \ 'let g:ale_testft_testlinter1_foo = ''abc''', - \] + g:globals_lines + g:command_header) + call CheckInfo( + \ [ + \ ' Current Filetype: testft.testft2', + \ 'Available Linters: [''testlinter1'', ''testlinter2'']', + \ ' Enabled Linters: [''testlinter1'', ''testlinter2'']', + \ ] + \ + g:fixer_lines + \ + [ + \ ' Linter Variables:', + \ '', + \ 'let g:ale_testft2_testlinter2_bar = {''x'': ''y''}', + \ 'let g:ale_testft2_testlinter2_foo = 123', + \ 'let g:ale_testft_testlinter1_bar = [''abc'']', + \ 'let g:ale_testft_testlinter1_foo = ''abc''', + \ ] + \ + g:globals_lines + \ + g:command_header + \) + +Execute (ALEInfoToFile should write to a file correctly): + if filereadable(g:dir . '/ale-info-test-file') + call delete(g:dir . '/ale-info-test-file') + endif + + let g:ale_testft_testlinter1_foo = 'abc' + let g:ale_testft_testlinter1_bar = ['abc'] + let g:ale_testft2_testlinter2_foo = 123 + let g:ale_testft2_testlinter2_bar = {'x': 'y'} + + call ale#linter#Define('testft', g:testlinter1) + call ale#linter#Define('testft2', g:testlinter2) + + execute 'ALEInfoToFile ' . fnameescape(g:dir . '/ale-info-test-file') + + AssertEqual + \ [ + \ ' Current Filetype: testft.testft2', + \ 'Available Linters: [''testlinter1'', ''testlinter2'']', + \ ' Enabled Linters: [''testlinter1'', ''testlinter2'']', + \ ] + \ + g:fixer_lines + \ + [ + \ ' Linter Variables:', + \ '', + \ 'let g:ale_testft2_testlinter2_bar = {''x'': ''y''}', + \ 'let g:ale_testft2_testlinter2_foo = 123', + \ 'let g:ale_testft_testlinter1_bar = [''abc'']', + \ 'let g:ale_testft_testlinter1_foo = ''abc''', + \ ] + \ + g:globals_lines + \ + g:command_header, + \ readfile(g:dir . '/ale-info-test-file') Given testft.testft2 (Empty buffer with two filetypes): Execute (ALEInfo should buffer-local linter variables): @@ -258,15 +372,22 @@ Execute (ALEInfo should buffer-local linter variables): call ale#linter#Define('testft', g:testlinter1) call ale#linter#Define('testft2', g:testlinter2) - call CheckInfo([ - \ ' Current Filetype: testft.testft2', - \ 'Available Linters: [''testlinter1'', ''testlinter2'']', - \ ' Enabled Linters: [''testlinter1'', ''testlinter2'']', - \ ' Linter Variables:', - \ '', - \ 'let g:ale_testft2_testlinter2_foo = 123', - \ 'let b:ale_testft2_testlinter2_foo = 456', - \] + g:globals_lines + g:command_header) + call CheckInfo( + \ [ + \ ' Current Filetype: testft.testft2', + \ 'Available Linters: [''testlinter1'', ''testlinter2'']', + \ ' Enabled Linters: [''testlinter1'', ''testlinter2'']', + \ ] + \ + g:fixer_lines + \ + [ + \ ' Linter Variables:', + \ '', + \ 'let g:ale_testft2_testlinter2_foo = 123', + \ 'let b:ale_testft2_testlinter2_foo = 456', + \ ] + \ + g:globals_lines + \ + g:command_header + \) Given testft.testft2 (Empty buffer with two filetypes): Execute (ALEInfo should output linter aliases): @@ -279,18 +400,25 @@ Execute (ALEInfo should output linter aliases): call ale#linter#Define('testft', g:testlinter1) call ale#linter#Define('testft2', g:testlinter2) - call CheckInfo([ - \ ' Current Filetype: testft.testft2', - \ 'Available Linters: [''testlinter1'', ''testlinter2'']', - \ ' Linter Aliases:', - \ '''testlinter1'' -> [''testftalias1'', ''testftalias2'']', - \ '''testlinter2'' -> [''testftalias3'', ''testftalias4'']', - \ ' Enabled Linters: [''testlinter1'', ''testlinter2'']', - \ ' Linter Variables:', - \ '', - \ 'let g:ale_testft2_testlinter2_foo = 123', - \ 'let b:ale_testft2_testlinter2_foo = 456', - \] + g:globals_lines + g:command_header) + call CheckInfo( + \ [ + \ ' Current Filetype: testft.testft2', + \ 'Available Linters: [''testlinter1'', ''testlinter2'']', + \ ' Linter Aliases:', + \ '''testlinter1'' -> [''testftalias1'', ''testftalias2'']', + \ '''testlinter2'' -> [''testftalias3'', ''testftalias4'']', + \ ' Enabled Linters: [''testlinter1'', ''testlinter2'']', + \ ] + \ + g:fixer_lines + \ + [ + \ ' Linter Variables:', + \ '', + \ 'let g:ale_testft2_testlinter2_foo = 123', + \ 'let b:ale_testft2_testlinter2_foo = 456', + \ ] + \ + g:globals_lines + \ + g:command_header + \) Given testft.testft2 (Empty buffer with two filetypes): Execute (ALEInfo should return command history): @@ -302,17 +430,22 @@ Execute (ALEInfo should return command history): call ale#linter#Define('testft', g:testlinter1) call ale#linter#Define('testft2', g:testlinter2) - call CheckInfo([ + call CheckInfo( + \ [ \ ' Current Filetype: testft.testft2', \ 'Available Linters: [''testlinter1'', ''testlinter2'']', \ ' Enabled Linters: [''testlinter1'', ''testlinter2'']', - \ ' Linter Variables:', - \ '', - \] + g:globals_lines + g:command_header + [ - \ '', - \ '(started) ''first command''', - \ '(started) [''/bin/bash'', ''\c'', ''last command'']', - \]) + \ ] + \ + g:fixer_lines + \ + g:variables_lines + \ + g:globals_lines + \ + g:command_header + \ + [ + \ '', + \ '(started) ''first command''', + \ '(started) [''/bin/bash'', ''\c'', ''last command'']', + \ ] + \) Given testft.testft2 (Empty buffer with two filetypes): Execute (ALEInfo command history should print exit codes correctly): @@ -324,17 +457,22 @@ Execute (ALEInfo command history should print exit codes correctly): call ale#linter#Define('testft', g:testlinter1) call ale#linter#Define('testft2', g:testlinter2) - call CheckInfo([ + call CheckInfo( + \ [ \ ' Current Filetype: testft.testft2', \ 'Available Linters: [''testlinter1'', ''testlinter2'']', \ ' Enabled Linters: [''testlinter1'', ''testlinter2'']', - \ ' Linter Variables:', - \ '', - \] + g:globals_lines + g:command_header + [ - \ '', - \ '(finished - exit code 0) ''first command''', - \ '(finished - exit code 1) [''/bin/bash'', ''\c'', ''last command'']', - \]) + \ ] + \ + g:fixer_lines + \ + g:variables_lines + \ + g:globals_lines + \ + g:command_header + \ + [ + \ '', + \ '(finished - exit code 0) ''first command''', + \ '(finished - exit code 1) [''/bin/bash'', ''\c'', ''last command'']', + \ ] + \) Given testft.testft2 (Empty buffer with two filetypes): Execute (ALEInfo command history should print command output if logging is on): @@ -367,31 +505,36 @@ Execute (ALEInfo command history should print command output if logging is on): call ale#linter#Define('testft', g:testlinter1) call ale#linter#Define('testft2', g:testlinter2) - call CheckInfo([ + call CheckInfo( + \ [ \ ' Current Filetype: testft.testft2', \ 'Available Linters: [''testlinter1'', ''testlinter2'']', \ ' Enabled Linters: [''testlinter1'', ''testlinter2'']', - \ ' Linter Variables:', - \ '', - \] + g:globals_lines + g:command_header + [ - \ '', - \ '(finished - exit code 0) ''first command''', - \ '', - \ '<<<OUTPUT STARTS>>>', - \ 'some', - \ 'first command output', - \ '<<<OUTPUT ENDS>>>', - \ '', - \ '(finished - exit code 1) [''/bin/bash'', ''\c'', ''last command'']', - \ '', - \ '<<<OUTPUT STARTS>>>', - \ 'different second command output', - \ '<<<OUTPUT ENDS>>>', - \ '', - \ '(finished - exit code 0) ''command with no output''', - \ '', - \ '<<<NO OUTPUT RETURNED>>>', - \]) + \ ] + \ + g:fixer_lines + \ + g:variables_lines + \ + g:globals_lines + \ + g:command_header + \ + [ + \ '', + \ '(finished - exit code 0) ''first command''', + \ '', + \ '<<<OUTPUT STARTS>>>', + \ 'some', + \ 'first command output', + \ '<<<OUTPUT ENDS>>>', + \ '', + \ '(finished - exit code 1) [''/bin/bash'', ''\c'', ''last command'']', + \ '', + \ '<<<OUTPUT STARTS>>>', + \ 'different second command output', + \ '<<<OUTPUT ENDS>>>', + \ '', + \ '(finished - exit code 0) ''command with no output''', + \ '', + \ '<<<NO OUTPUT RETURNED>>>', + \ ] + \) Execute (ALEInfo should include executable checks in the history): call ale#linter#Define('testft', g:testlinter1) @@ -400,18 +543,23 @@ Execute (ALEInfo should include executable checks in the history): call ale#engine#IsExecutable(bufnr(''), 'TheresNoWayThisIsExecutable') call ale#engine#IsExecutable(bufnr(''), 'TheresNoWayThisIsExecutable') - call CheckInfo([ + call CheckInfo( + \ [ \ ' Current Filetype: testft.testft2', \ 'Available Linters: [''testlinter1'']', \ ' Enabled Linters: [''testlinter1'']', - \ ' Linter Variables:', - \ '', - \] + g:globals_lines + g:command_header + [ - \ '', - \ '(executable check - success) ' . (has('win32') ? 'cmd' : 'echo'), - \ '(executable check - failure) TheresNoWayThisIsExecutable', - \ '(executable check - failure) TheresNoWayThisIsExecutable', - \]) + \ ] + \ + g:fixer_lines + \ + g:variables_lines + \ + g:globals_lines + \ + g:command_header + \ + [ + \ '', + \ '(executable check - success) ' . (has('win32') ? 'cmd' : 'echo'), + \ '(executable check - failure) TheresNoWayThisIsExecutable', + \ '(executable check - failure) TheresNoWayThisIsExecutable', + \ ] + \) Execute (The option for caching failing executable checks should work): let g:ale_cache_executable_check_failures = 1 @@ -424,14 +572,60 @@ Execute (The option for caching failing executable checks should work): call ale#engine#IsExecutable(bufnr(''), 'TheresNoWayThisIsExecutable') call ale#engine#IsExecutable(bufnr(''), 'TheresNoWayThisIsExecutable') - call CheckInfo([ + call CheckInfo( + \ [ \ ' Current Filetype: testft.testft2', \ 'Available Linters: [''testlinter1'']', \ ' Enabled Linters: [''testlinter1'']', - \ ' Linter Variables:', - \ '', - \] + g:globals_lines + g:command_header + [ - \ '', - \ '(executable check - success) ' . (has('win32') ? 'cmd' : 'echo'), - \ '(executable check - failure) TheresNoWayThisIsExecutable', - \]) + \ ] + \ + g:fixer_lines + \ + g:variables_lines + \ + g:globals_lines + \ + g:command_header + \ + [ + \ '', + \ '(executable check - success) ' . (has('win32') ? 'cmd' : 'echo'), + \ '(executable check - failure) TheresNoWayThisIsExecutable', + \ ] + \) + +Given testft (Empty buffer): +Execute (LSP errors for a linter should be outputted): + let g:ale_lsp_error_messages = {'testlinter1': ['foo', 'bar']} + call ale#linter#Define('testft', g:testlinter1) + + call CheckInfo( + \ [ + \ ' Current Filetype: testft', + \ 'Available Linters: [''testlinter1'']', + \ ' Enabled Linters: [''testlinter1'']', + \ ] + \ + g:fixer_lines + \ + g:variables_lines + \ + g:globals_lines + \ + [ + \ ' LSP Error Messages:', + \ '', + \ '(Errors for testlinter1)', + \ 'foo', + \ 'bar', + \ ] + \ + g:command_header + \) + +Given testft (Empty buffer): +Execute (LSP errors for other linters shouldn't appear): + let g:ale_lsp_error_messages = {'testlinter2': ['foo']} + call ale#linter#Define('testft', g:testlinter1) + + call CheckInfo( + \ [ + \ ' Current Filetype: testft', + \ 'Available Linters: [''testlinter1'']', + \ ' Enabled Linters: [''testlinter1'']', + \ ] + \ + g:fixer_lines + \ + g:variables_lines + \ + g:globals_lines + \ + g:command_header + \) diff --git a/test/test_ale_lint_command.vader b/test/test_ale_lint_command.vader index d36b2177..7b4f7613 100644 --- a/test/test_ale_lint_command.vader +++ b/test/test_ale_lint_command.vader @@ -14,13 +14,6 @@ Before: \ 'pattern': '', \ 'valid': 1, \}] - let g:expected_groups = [ - \ 'ALECleanupGroup', - \ 'ALECursorGroup', - \ 'ALEHighlightBufferGroup', - \ 'ALERunOnEnterGroup', - \ 'ALERunOnTextChangedGroup', - \] function! ToggleTestCallback(buffer, output) return [{ @@ -45,7 +38,6 @@ After: Restore unlet! g:expected_loclist - unlet! g:expected_groups let g:ale_buffer_info = {} call ale#linter#Reset() diff --git a/test/test_ale_toggle.vader b/test/test_ale_toggle.vader index d56f8c2b..cac762b4 100644 --- a/test/test_ale_toggle.vader +++ b/test/test_ale_toggle.vader @@ -5,12 +5,16 @@ Before: Save g:ale_run_synchronously Save g:ale_pattern_options Save g:ale_pattern_options_enabled + Save g:ale_set_balloons let g:ale_set_signs = 1 let g:ale_set_lists_synchronously = 1 let g:ale_run_synchronously = 1 let g:ale_pattern_options = {} let g:ale_pattern_options_enabled = 1 + let g:ale_set_balloons = + \ has('balloon_eval') && has('gui_running') || + \ has('balloon_eval_term') && !has('gui_running') unlet! b:ale_enabled @@ -28,12 +32,8 @@ Before: \}] let g:expected_groups = [ \ 'ALECleanupGroup', - \ 'ALECursorGroup', + \ 'ALEEvents', \ 'ALEHighlightBufferGroup', - \ 'ALERunOnEnterGroup', - \ 'ALERunOnFiletypeChangeGroup', - \ 'ALERunOnSaveGroup', - \ 'ALERunOnTextChangedGroup', \] function! ToggleTestCallback(buffer, output) @@ -56,7 +56,7 @@ Before: let l:results = [] for l:line in split(l:output, "\n") - let l:match = matchlist(l:line, '^ALE[a-zA-Z]\+Group') + let l:match = matchlist(l:line, '^ALE[a-zA-Z]\+') " We don't care about some groups here. if !empty(l:match) @@ -135,13 +135,7 @@ Execute(ALEToggle should reset everything and then run again): AssertEqual [], getloclist(0), 'The loclist was not cleared' AssertEqual [0, []], ale#sign#FindCurrentSigns(bufnr('%')), 'The signs were not cleared' AssertEqual [], getmatches(), 'The highlights were not cleared' - AssertEqual - \ [ - \ 'ALECleanupGroup', - \ 'ALEHighlightBufferGroup', - \ 'ALERunOnSaveGroup', - \ ], - \ ParseAuGroups() + AssertEqual g:expected_groups, ParseAuGroups() " Toggle ALE on, everything should be set up and run again. ALEToggle @@ -344,3 +338,43 @@ Execute(ALEResetBuffer should reset everything for a buffer): AssertEqual 1, g:ale_enabled AssertEqual 1, get(b:, 'ale_enabled', 1) + +Execute(Disabling ALE should disable balloons): + " These tests won't run in the console, but we can run them manually in GVim. + if has('balloon_eval') && has('gui_running') || + \ has('balloon_eval_term') && !has('gui_running') + call ale#linter#Reset() + + " Enable balloons, so we can check the expr value. + call ale#balloon#Enable() + + AssertEqual 1, &ballooneval + AssertEqual 'ale#balloon#Expr()', &balloonexpr + + " Toggle ALE off. + ALEToggle + + " The balloon settings should be reset. + AssertEqual 0, &ballooneval + AssertEqual '', &balloonexpr + endif + +Execute(Enabling ALE should enable balloons if the setting is on): + if has('balloon_eval') && has('gui_running') || + \ has('balloon_eval_term') && !has('gui_running') + call ale#linter#Reset() + call ale#balloon#Disable() + ALEDisable + let g:ale_set_balloons = 0 + ALEEnable + + AssertEqual 0, &ballooneval + AssertEqual '', &balloonexpr + + ALEDisable + let g:ale_set_balloons = 1 + ALEEnable + + AssertEqual 1, &ballooneval + AssertEqual 'ale#balloon#Expr()', &balloonexpr + endif diff --git a/test/test_alejobstarted_autocmd.vader b/test/test_alejobstarted_autocmd.vader new file mode 100644 index 00000000..51a57881 --- /dev/null +++ b/test/test_alejobstarted_autocmd.vader @@ -0,0 +1,42 @@ +Given testft (An empty file): + +Before: + let g:job_started_success = 0 + let g:ale_run_synchronously = 1 + + unlet! b:ale_linted + + function! TestCallback(buffer, output) + return [] + endfunction + + call ale#linter#Define('testft', { + \ 'name': 'testlinter', + \ 'callback': 'TestCallback', + \ 'executable': has('win32') ? 'cmd' : 'true', + \ 'command': 'true', + \}) + +After: + let g:ale_run_synchronously = 0 + let g:ale_buffer_info = {} + + try + augroup! VaderTest + catch + endtry + + unlet! g:job_started_success + + delfunction TestCallback + call ale#linter#Reset() + +Execute(Run a lint cycle with an actual job to check for ALEJobStarted): + augroup VaderTest + autocmd! + autocmd User ALEJobStarted let g:job_started_success = 1 + augroup end + + call ale#Lint() + + AssertEqual g:job_started_success, 1 diff --git a/test/test_alelint_autocmd.vader b/test/test_alelint_autocmd.vader index b19e6b4e..5af1cd47 100644 --- a/test/test_alelint_autocmd.vader +++ b/test/test_alelint_autocmd.vader @@ -3,12 +3,19 @@ Before: let g:post_success = 0 let g:ale_run_synchronously = 1 + unlet! b:ale_linted + After: let g:ale_run_synchronously = 0 let g:ale_buffer_info = {} - augroup! VaderTest -Execute (Run a lint cycle, and check that a variable is set in the autocmd): + try + augroup! VaderTest + catch + endtry + +Given foobar(An empty file): +Execute(Run a lint cycle, and check that a variable is set in the autocmd): augroup VaderTest autocmd! autocmd User ALELintPre let g:pre_success = 1 @@ -19,3 +26,14 @@ Execute (Run a lint cycle, and check that a variable is set in the autocmd): AssertEqual g:pre_success, 1 AssertEqual g:post_success, 1 + +Execute(b:ale_linted should be increased after each lint cycle): + AssertEqual get(b:, 'ale_linted'), 0 + + call ale#Lint() + + AssertEqual get(b:, 'ale_linted'), 1 + + call ale#Lint() + + AssertEqual get(b:, 'ale_linted'), 2 diff --git a/test/test_autocmd_commands.vader b/test/test_autocmd_commands.vader index c03e8fb7..01646606 100644 --- a/test/test_autocmd_commands.vader +++ b/test/test_autocmd_commands.vader @@ -1,6 +1,6 @@ Before: function! CheckAutocmd(group) - call ale#toggle#InitAuGroups() + call ale#events#Init() redir => l:output execute 'silent! autocmd ' . a:group @@ -26,8 +26,9 @@ Before: " for the one matching the current buffer. if l:line =~# '<buffer=' . bufnr('') . '>' let l:header .= ' <buffer>' - else + elseif l:line[:0] is# ' ' call add(l:matches, join(split(l:header . l:line))) + else let l:header = '' endif endif @@ -38,16 +39,28 @@ Before: return l:matches endfunction + Save g:ale_completion_enabled + Save g:ale_echo_cursor Save g:ale_enabled - Save g:ale_lint_on_text_changed - Save g:ale_lint_on_insert_leave - Save g:ale_pattern_options_enabled + Save g:ale_fix_on_save Save g:ale_lint_on_enter Save g:ale_lint_on_filetype_changed + Save g:ale_lint_on_insert_leave Save g:ale_lint_on_save - Save g:ale_echo_cursor - Save g:ale_fix_on_save - Save g:ale_completion_enabled + Save g:ale_lint_on_text_changed + Save g:ale_pattern_options_enabled + + " Turn everything on by defaul for these tests. + let g:ale_completion_enabled = 1 + let g:ale_echo_cursor = 1 + let g:ale_enabled = 1 + let g:ale_fix_on_save = 1 + let g:ale_lint_on_enter = 1 + let g:ale_lint_on_filetype_changed = 1 + let g:ale_lint_on_insert_leave = 1 + let g:ale_lint_on_save = 1 + let g:ale_lint_on_text_changed = 1 + let g:ale_pattern_options_enabled = 1 After: delfunction CheckAutocmd @@ -59,100 +72,97 @@ After: call ale#completion#Disable() endif - call ale#toggle#InitAuGroups() + call ale#events#Init() -Execute (g:ale_lint_on_text_changed = 0 should bind no events): +Execute (All events should be set up when everything is on): + let g:ale_echo_cursor = 1 + + AssertEqual + \ [ + \ 'BufEnter * call ale#pattern_options#SetOptions(str2nr(expand(''<abuf>'')))', + \ 'BufEnter call ale#events#EnterEvent(str2nr(expand(''<abuf>'')))', + \ 'BufReadPost * call ale#pattern_options#SetOptions(str2nr(expand(''<abuf>'')))', + \ 'BufReadPost call ale#Queue(0, ''lint_file'', str2nr(expand(''<abuf>'')))', + \ 'BufWinEnter * call ale#Queue(0, ''lint_file'', str2nr(expand(''<abuf>'')))', + \ 'BufWritePost * call ale#events#SaveEvent(str2nr(expand(''<abuf>'')))', + \ 'CursorHold * call ale#cursor#EchoCursorWarningWithDelay()', + \ 'CursorMoved * call ale#cursor#EchoCursorWarningWithDelay()', + \ 'FileChangedShellPost * call ale#events#FileChangedEvent(str2nr(expand(''<abuf>'')))', + \ 'FileType * call ale#events#FileTypeEvent( str2nr(expand(''<abuf>'')), expand(''<amatch>''))', + \ 'InsertLeave * call ale#Queue(0)', + \ 'InsertLeave call ale#cursor#EchoCursorWarning()', + \ 'TextChanged * call ale#Queue(g:ale_lint_delay)', + \ 'TextChangedI * call ale#Queue(g:ale_lint_delay)', + \ ], + \ CheckAutocmd('ALEEvents') + +Execute (Only the required events should be bound even if various settings are off): + let g:ale_completion_enabled = 0 + let g:ale_echo_cursor = 0 + let g:ale_enabled = 0 + let g:ale_fix_on_save = 0 + let g:ale_lint_on_enter = 0 + let g:ale_lint_on_filetype_changed = 0 + let g:ale_lint_on_insert_leave = 0 + let g:ale_lint_on_save = 0 let g:ale_lint_on_text_changed = 0 + let g:ale_pattern_options_enabled = 0 - AssertEqual [], CheckAutocmd('ALERunOnTextChangedGroup') + AssertEqual + \ [ + \ 'BufEnter * call ale#pattern_options#SetOptions(str2nr(expand(''<abuf>'')))', + \ 'BufReadPost * call ale#pattern_options#SetOptions(str2nr(expand(''<abuf>'')))', + \ 'BufWritePost * call ale#events#SaveEvent(str2nr(expand(''<abuf>'')))', + \ ], + \ CheckAutocmd('ALEEvents') Execute (g:ale_lint_on_text_changed = 1 bind both events): let g:ale_lint_on_text_changed = 1 - AssertEqual [ - \ 'TextChanged * call ale#Queue(g:ale_lint_delay)', - \ 'TextChangedI * call ale#Queue(g:ale_lint_delay)' - \], CheckAutocmd('ALERunOnTextChangedGroup') + AssertEqual + \ [ + \ 'TextChanged * call ale#Queue(g:ale_lint_delay)', + \ 'TextChangedI * call ale#Queue(g:ale_lint_delay)', + \ ], + \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^TextChanged''') Execute (g:ale_lint_on_text_changed = 'always' should bind both events): let g:ale_lint_on_text_changed = 'always' - AssertEqual [ - \ 'TextChanged * call ale#Queue(g:ale_lint_delay)', - \ 'TextChangedI * call ale#Queue(g:ale_lint_delay)' - \], CheckAutocmd('ALERunOnTextChangedGroup') + AssertEqual + \ [ + \ 'TextChanged * call ale#Queue(g:ale_lint_delay)', + \ 'TextChangedI * call ale#Queue(g:ale_lint_delay)', + \ ], + \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^TextChanged''') Execute (g:ale_lint_on_text_changed = 'normal' should bind only TextChanged): let g:ale_lint_on_text_changed = 'normal' - AssertEqual [ - \ 'TextChanged * call ale#Queue(g:ale_lint_delay)', - \], CheckAutocmd('ALERunOnTextChangedGroup') + AssertEqual + \ [ + \ 'TextChanged * call ale#Queue(g:ale_lint_delay)', + \ ], + \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^TextChanged''') Execute (g:ale_lint_on_text_changed = 'insert' should bind only TextChangedI): let g:ale_lint_on_text_changed = 'insert' - AssertEqual [ - \ 'TextChangedI * call ale#Queue(g:ale_lint_delay)', - \], CheckAutocmd('ALERunOnTextChangedGroup') + AssertEqual + \ [ + \ 'TextChangedI * call ale#Queue(g:ale_lint_delay)', + \ ], + \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^TextChanged''') Execute (g:ale_lint_on_insert_leave = 1 should bind InsertLeave): let g:ale_lint_on_insert_leave = 1 - - AssertEqual [ - \ 'InsertLeave * call ale#Queue(0)', - \], CheckAutocmd('ALERunOnInsertLeave') - -Execute (g:ale_lint_on_insert_leave = 0 should bind no events): - let g:ale_lint_on_insert_leave = 0 - - AssertEqual [], CheckAutocmd('ALERunOnInsertLeave') - -Execute (g:ale_pattern_options_enabled = 1 should bind BufReadPost and BufEnter): - let g:ale_pattern_options_enabled = 1 - - AssertEqual [ - \ 'BufEnter * call ale#pattern_options#SetOptions(str2nr(expand(''<abuf>'')))', - \ 'BufReadPost * call ale#pattern_options#SetOptions(str2nr(expand(''<abuf>'')))', - \], CheckAutocmd('ALEPatternOptionsGroup') - -Execute (g:ale_pattern_options_enabled = 0 should still bind events): - let g:ale_pattern_options_enabled = 0 - - AssertEqual [ - \ 'BufEnter * call ale#pattern_options#SetOptions(str2nr(expand(''<abuf>'')))', - \ 'BufReadPost * call ale#pattern_options#SetOptions(str2nr(expand(''<abuf>'')))', - \], CheckAutocmd('ALEPatternOptionsGroup') - -Execute (g:ale_enabled = 0 should still bind pattern events): - let g:ale_enabled = 0 - - AssertEqual [ - \ 'BufEnter * call ale#pattern_options#SetOptions(str2nr(expand(''<abuf>'')))', - \ 'BufReadPost * call ale#pattern_options#SetOptions(str2nr(expand(''<abuf>'')))', - \], CheckAutocmd('ALEPatternOptionsGroup') - -Execute (g:ale_lint_on_enter = 0 should bind only the BufEnter event): - let g:ale_lint_on_enter = 0 + let g:ale_echo_cursor = 0 AssertEqual - \ ['BufEnter * call ale#events#EnterEvent(str2nr(expand(''<abuf>'')))'], - \ CheckAutocmd('ALERunOnEnterGroup') - -Execute (g:ale_lint_on_enter = 1 should bind the required events): - let g:ale_lint_on_enter = 1 - - AssertEqual [ - \ 'BufEnter * call ale#events#EnterEvent(str2nr(expand(''<abuf>'')))', - \ 'BufReadPost * call ale#Queue(0, ''lint_file'', str2nr(expand(''<abuf>'')))', - \ 'BufWinEnter * call ale#Queue(0, ''lint_file'', str2nr(expand(''<abuf>'')))', - \ 'FileChangedShellPost * call ale#events#FileChangedEvent(str2nr(expand(''<abuf>'')))', - \], CheckAutocmd('ALERunOnEnterGroup') - -Execute (g:ale_lint_on_filetype_changed = 0 should bind no events): - let g:ale_lint_on_filetype_changed = 0 - - AssertEqual [], CheckAutocmd('ALERunOnFiletypeChangeGroup') + \ [ + \ 'InsertLeave * call ale#Queue(0)', + \ ], + \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^InsertLeave''') Execute (g:ale_lint_on_filetype_changed = 1 should bind the FileType event): let g:ale_lint_on_filetype_changed = 1 @@ -164,34 +174,11 @@ Execute (g:ale_lint_on_filetype_changed = 1 should bind the FileType event): \ . 'expand(''<amatch>'')' \ . ')', \ ], - \ CheckAutocmd('ALERunOnFiletypeChangeGroup') - -Execute (The SaveEvent should always be bound): - let g:ale_enabled = 0 - let g:ale_lint_on_save = 0 - let g:ale_fix_on_save = 0 - - AssertEqual [ - \ 'BufWritePost * call ale#events#SaveEvent(str2nr(expand(''<abuf>'')))', - \], CheckAutocmd('ALERunOnSaveGroup') - -Execute (g:ale_echo_cursor = 0 should bind no events): - let g:ale_echo_cursor = 0 - - AssertEqual [], CheckAutocmd('ALECursorGroup') - -Execute (g:ale_echo_cursor = 1 should bind cursor events): - let g:ale_echo_cursor = 1 - - AssertEqual [ - \ 'CursorHold * call ale#cursor#EchoCursorWarningWithDelay()', - \ 'CursorMoved * call ale#cursor#EchoCursorWarningWithDelay()', - \ 'InsertLeave * call ale#cursor#EchoCursorWarning()', - \], CheckAutocmd('ALECursorGroup') + \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''\v^FileType''') Execute (ALECleanupGroup should include the right commands): AssertEqual [ - \ 'BufDelete * call ale#engine#Cleanup(str2nr(expand(''<abuf>'')))', + \ 'BufDelete * if exists(''*ale#engine#Cleanup'') | call ale#engine#Cleanup(str2nr(expand(''<abuf>''))) | endif', \ 'QuitPre * call ale#events#QuitEvent(str2nr(expand(''<abuf>'')))', \], CheckAutocmd('ALECleanupGroup') diff --git a/test/test_balloon_messages.vader b/test/test_balloon_messages.vader index ec09fe29..d0724c21 100644 --- a/test/test_balloon_messages.vader +++ b/test/test_balloon_messages.vader @@ -1,21 +1,34 @@ Before: Save g:ale_buffer_info + Save g:ale_enabled + Save g:ale_set_balloons - let g:ale_buffer_info[347] = {'loclist': [ + let g:ale_set_balloons = 1 + + let g:ale_buffer_info[bufnr('')] = {'loclist': [ + \ { + \ 'bufnr': bufnr('%'), + \ 'lnum': 1, + \ 'col': 10, + \ 'linter_name': 'eslint', + \ 'type': 'W', + \ 'text': 'Ignore me.', + \ }, \ { - \ 'bufnr': 347, + \ 'bufnr': bufnr(''), \ 'lnum': 1, \ 'col': 10, \ 'text': 'Missing semicolon. (semi)', + \ 'type': 'E', \ }, \ { - \ 'bufnr': 347, + \ 'bufnr': bufnr(''), \ 'lnum': 2, \ 'col': 10, \ 'text': 'Infix operators must be spaced. (space-infix-ops)' \ }, \ { - \ 'bufnr': 347, + \ 'bufnr': bufnr(''), \ 'lnum': 2, \ 'col': 15, \ 'text': 'Missing radix parameter (radix)' @@ -25,17 +38,50 @@ Before: After: Restore + unlet! b:ale_enabled + unlet! b:ale_set_balloons + Execute(Balloon messages should be shown for the correct lines): AssertEqual \ 'Missing semicolon. (semi)', - \ ale#balloon#MessageForPos(347, 1, 1) + \ ale#balloon#MessageForPos(bufnr(''), 1, 1) Execute(Balloon messages should be shown for earlier columns): AssertEqual \ 'Infix operators must be spaced. (space-infix-ops)', - \ ale#balloon#MessageForPos(347, 2, 1) + \ ale#balloon#MessageForPos(bufnr(''), 2, 1) Execute(Balloon messages should be shown for later columns): AssertEqual \ 'Missing radix parameter (radix)', - \ ale#balloon#MessageForPos(347, 2, 16) + \ ale#balloon#MessageForPos(bufnr(''), 2, 16) + +Execute(Balloon messages should be disabled if ALE is disabled globally): + let g:ale_enabled = 0 + " Enabling the buffer should not make a difference. + let b:ale_enabled = 1 + + AssertEqual '', ale#balloon#MessageForPos(bufnr(''), 1, 1) + +Execute(Balloon messages should be disabled if ALE is disabled for a buffer): + let b:ale_enabled = 0 + + AssertEqual '', ale#balloon#MessageForPos(bufnr(''), 1, 1) + +Execute(Balloon messages should be disabled if the global setting is off): + let g:ale_set_balloons = 0 + + AssertEqual '', ale#balloon#MessageForPos(bufnr(''), 1, 1) + +Execute(Balloon messages should be disabled if the buffer setting is off): + let b:ale_set_balloons = 0 + + AssertEqual '', ale#balloon#MessageForPos(bufnr(''), 1, 1) + +Execute(The balloon buffer setting should override the global one): + let g:ale_set_balloons = 0 + let b:ale_set_balloons = 1 + + AssertEqual + \ 'Missing semicolon. (semi)', + \ ale#balloon#MessageForPos(bufnr(''), 1, 1) diff --git a/test/test_c_import_paths.vader b/test/test_c_import_paths.vader index 6080779f..f2a06781 100644 --- a/test/test_c_import_paths.vader +++ b/test/test_c_import_paths.vader @@ -42,7 +42,7 @@ Execute(The C GCC handler should include 'include' directories for projects with \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/subdir')) . ' ' \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/include')) . ' ' \ . ' -' - \ , ale_linters#c#gcc#GetCommand(bufnr('')) + \ , ale_linters#c#gcc#GetCommand(bufnr(''), []) Execute(The C GCC handler should include 'include' directories for projects with a configure file): runtime! ale_linters/c/gcc.vim @@ -55,7 +55,7 @@ Execute(The C GCC handler should include 'include' directories for projects with \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/configure_project/subdir')) . ' ' \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/configure_project/include')) . ' ' \ . ' -' - \ , ale_linters#c#gcc#GetCommand(bufnr('')) + \ , ale_linters#c#gcc#GetCommand(bufnr(''), []) Execute(The C GCC handler should include root directories for projects with .h files in them): runtime! ale_linters/c/gcc.vim @@ -68,7 +68,7 @@ Execute(The C GCC handler should include root directories for projects with .h f \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/h_file_project/subdir')) . ' ' \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/h_file_project')) . ' ' \ . ' -' - \ , ale_linters#c#gcc#GetCommand(bufnr('')) + \ , ale_linters#c#gcc#GetCommand(bufnr(''), []) Execute(The C GCC handler should include root directories for projects with .hpp files in them): runtime! ale_linters/c/gcc.vim @@ -81,7 +81,7 @@ Execute(The C GCC handler should include root directories for projects with .hpp \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/hpp_file_project/subdir')) . ' ' \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/hpp_file_project')) . ' ' \ . ' -' - \ , ale_linters#c#gcc#GetCommand(bufnr('')) + \ , ale_linters#c#gcc#GetCommand(bufnr(''), []) Execute(The C Clang handler should include 'include' directories for projects with a Makefile): runtime! ale_linters/c/clang.vim @@ -94,7 +94,7 @@ Execute(The C Clang handler should include 'include' directories for projects wi \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/subdir')) . ' ' \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/include')) . ' ' \ . ' -' - \ , ale_linters#c#clang#GetCommand(bufnr('')) + \ , ale_linters#c#clang#GetCommand(bufnr(''), []) Execute(The C Clang handler should include 'include' directories for projects with a configure file): runtime! ale_linters/c/clang.vim @@ -107,7 +107,7 @@ Execute(The C Clang handler should include 'include' directories for projects wi \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/h_file_project/subdir')) . ' ' \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/h_file_project')) . ' ' \ . ' -' - \ , ale_linters#c#clang#GetCommand(bufnr('')) + \ , ale_linters#c#clang#GetCommand(bufnr(''), []) Execute(The C Clang handler should include root directories for projects with .h files in them): runtime! ale_linters/c/clang.vim @@ -120,7 +120,7 @@ Execute(The C Clang handler should include root directories for projects with .h \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/h_file_project/subdir')) . ' ' \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/h_file_project')) . ' ' \ . ' -' - \ , ale_linters#c#clang#GetCommand(bufnr('')) + \ , ale_linters#c#clang#GetCommand(bufnr(''), []) Execute(The C Clang handler should include root directories for projects with .hpp files in them): runtime! ale_linters/c/clang.vim @@ -133,7 +133,7 @@ Execute(The C Clang handler should include root directories for projects with .h \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/hpp_file_project/subdir')) . ' ' \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/hpp_file_project')) . ' ' \ . ' -' - \ , ale_linters#c#clang#GetCommand(bufnr('')) + \ , ale_linters#c#clang#GetCommand(bufnr(''), []) Execute(The C++ GCC handler should include 'include' directories for projects with a Makefile): runtime! ale_linters/cpp/gcc.vim @@ -146,7 +146,7 @@ Execute(The C++ GCC handler should include 'include' directories for projects wi \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/subdir')) . ' ' \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/include')) . ' ' \ . ' -' - \ , ale_linters#cpp#gcc#GetCommand(bufnr('')) + \ , ale_linters#cpp#gcc#GetCommand(bufnr(''), []) Execute(The C++ GCC handler should include 'include' directories for projects with a configure file): runtime! ale_linters/cpp/gcc.vim @@ -159,7 +159,7 @@ Execute(The C++ GCC handler should include 'include' directories for projects wi \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/configure_project/subdir')) . ' ' \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/configure_project/include')) . ' ' \ . ' -' - \ , ale_linters#cpp#gcc#GetCommand(bufnr('')) + \ , ale_linters#cpp#gcc#GetCommand(bufnr(''), []) Execute(The C++ GCC handler should include root directories for projects with .h files in them): runtime! ale_linters/cpp/gcc.vim @@ -172,7 +172,7 @@ Execute(The C++ GCC handler should include root directories for projects with .h \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/h_file_project/subdir')) . ' ' \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/h_file_project')) . ' ' \ . ' -' - \ , ale_linters#cpp#gcc#GetCommand(bufnr('')) + \ , ale_linters#cpp#gcc#GetCommand(bufnr(''), []) Execute(The C++ GCC handler should include root directories for projects with .hpp files in them): runtime! ale_linters/cpp/gcc.vim @@ -185,7 +185,7 @@ Execute(The C++ GCC handler should include root directories for projects with .h \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/hpp_file_project/subdir')) . ' ' \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/hpp_file_project')) . ' ' \ . ' -' - \ , ale_linters#cpp#gcc#GetCommand(bufnr('')) + \ , ale_linters#cpp#gcc#GetCommand(bufnr(''), []) Execute(The C++ Clang handler should include 'include' directories for projects with a Makefile): runtime! ale_linters/cpp/clang.vim @@ -198,7 +198,7 @@ Execute(The C++ Clang handler should include 'include' directories for projects \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/subdir')) . ' ' \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/makefile_project/include')) . ' ' \ . ' -' - \ , ale_linters#cpp#clang#GetCommand(bufnr('')) + \ , ale_linters#cpp#clang#GetCommand(bufnr(''), []) Execute(The C++ Clang handler should include 'include' directories for projects with a configure file): runtime! ale_linters/cpp/clang.vim @@ -211,7 +211,7 @@ Execute(The C++ Clang handler should include 'include' directories for projects \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/configure_project/subdir')) . ' ' \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/configure_project/include')) . ' ' \ . ' -' - \ , ale_linters#cpp#clang#GetCommand(bufnr('')) + \ , ale_linters#cpp#clang#GetCommand(bufnr(''), []) Execute(The C++ Clang handler should include root directories for projects with .h files in them): runtime! ale_linters/cpp/clang.vim @@ -224,7 +224,7 @@ Execute(The C++ Clang handler should include root directories for projects with \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/h_file_project/subdir')) . ' ' \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/h_file_project')) . ' ' \ . ' -' - \ , ale_linters#cpp#clang#GetCommand(bufnr('')) + \ , ale_linters#cpp#clang#GetCommand(bufnr(''), []) Execute(The C++ Clang handler should include root directories for projects with .hpp files in them): runtime! ale_linters/cpp/clang.vim @@ -237,7 +237,7 @@ Execute(The C++ Clang handler should include root directories for projects with \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/hpp_file_project/subdir')) . ' ' \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/hpp_file_project')) . ' ' \ . ' -' - \ , ale_linters#cpp#clang#GetCommand(bufnr('')) + \ , ale_linters#cpp#clang#GetCommand(bufnr(''), []) Execute(The C++ Clang handler shoud use the include directory based on the .git location): runtime! ale_linters/cpp/clang.vim @@ -258,7 +258,7 @@ Execute(The C++ Clang handler shoud use the include directory based on the .git \ . '-iquote ' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/git_and_nested_makefiles/src')) . ' ' \ . ' -I' . ale#Escape(ale#path#Simplify(g:dir . '/test_c_projects/git_and_nested_makefiles/include')) . ' ' \ . ' -' - \ , ale_linters#cpp#clang#GetCommand(bufnr('')) + \ , ale_linters#cpp#clang#GetCommand(bufnr(''), []) Execute(The C++ ClangTidy handler should include json folders for projects with suitable build directory in them): runtime! ale_linters/cpp/clangtidy.vim diff --git a/test/test_c_parse_makefile.vader b/test/test_c_parse_makefile.vader new file mode 100644 index 00000000..7c2fc21e --- /dev/null +++ b/test/test_c_parse_makefile.vader @@ -0,0 +1,184 @@ +Before: + Save g:ale_c_parse_makefile + Save g:ale_c_gcc_options + Save g:ale_c_clang_options + Save g:ale_cpp_gcc_options + Save g:ale_cpp_clang_options + + call ale#test#SetDirectory('/testplugin/test') + + let g:ale_c_parse_makefile=1 + let g:ale_c_gcc_options = '' + let g:ale_c_clang_options = '' + let g:ale_cpp_gcc_options = '' + let g:ale_cpp_clang_options = '' + +After: + Restore + + call ale#test#RestoreDirectory() + call ale#linter#Reset() + +Execute(The CFlags parser should be able to parse include directives): + runtime! ale_linters/c/gcc.vim + + call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c') + + AssertEqual + \ [ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir'))] + \ , ale#c#ParseCFlags(bufnr(''), 'gcc -Isubdir -c file.c') + +Execute(The CFlags parser should be able to parse macro directives): + runtime! ale_linters/c/gcc.vim + + call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c') + + AssertEqual + \ [ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')), + \ '-DTEST=1'] + \ , ale#c#ParseCFlags(bufnr(''), 'gcc -Isubdir -DTEST=1 -c file.c') + +Execute(The CFlags parser should be able to parse macro directives with spaces): + runtime! ale_linters/c/gcc.vim + + call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c') + + AssertEqual + \ [ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')), + \ '-DTEST=$(( 2 * 4 ))'] + \ , ale#c#ParseCFlags(bufnr(''), 'gcc -Isubdir -DTEST=$(( 2 * 4 )) -c file.c') + +Execute(The CFlags parser should be able to parse shell directives with spaces): + runtime! ale_linters/c/gcc.vim + + call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c') + + AssertEqual + \ [ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')), + \ '-DTEST=`date +%s`'] + \ , ale#c#ParseCFlags(bufnr(''), 'gcc -Isubdir -DTEST=`date +%s` -c file.c') + +Execute(The CFlagsToList parser should be able to parse multiple cflags): + runtime! ale_linters/c/gcc.vim + + call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c') + + AssertEqual + \ [ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')), + \ '-DTEST=`date +%s`'] + \ , ale#c#ParseCFlagsToList(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'), + \ split('gcc -Isubdir -DTEST=`date +%s` -c file.c', '-')) + +Execute(The CFlagsToList parser should be able to parse multiple cflags #2): + runtime! ale_linters/c/gcc.vim + + call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c') + + AssertEqual + \ [ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')), + \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')), + \ '-DTEST=`date +%s`'] + \ , ale#c#ParseCFlagsToList(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'), + \ split('gcc -Isubdir ' . + \ '-I'. ale#path#Simplify('kernel/include') . + \ ' -DTEST=`date +%s` -c file.c', '-')) + +Execute(The CFlagsToList parser should be able to parse multiple cflags #3): + runtime! ale_linters/c/gcc.vim + + call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c') + + AssertEqual + \ ['-Dgoal=9', + \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')), + \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')), + \ '-DTEST=`date +%s`'] + \ , ale#c#ParseCFlagsToList(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'), + \ split('gcc -Dgoal=9 -Isubdir ' . + \ '-I'. ale#path#Simplify('kernel/include') . + \ ' -DTEST=`date +%s` -c file.c', '-')) + +Execute(The CFlagsToList parser should be able to parse multiple cflags #4): + runtime! ale_linters/c/gcc.vim + + call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c') + + AssertEqual + \ ['-Dgoal=9', + \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')), + \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')), + \ '-DTEST=`date +%s`'] + \ , ale#c#ParseCFlagsToList(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'), + \ split('gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir ' . + \ '-I'. ale#path#Simplify('kernel/include') . + \ ' -DTEST=`date +%s` -c file.c', '-')) + +Execute(The CFlagsToList parser should be able to parse multiple cflags #5): + runtime! ale_linters/c/gcc.vim + + call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c') + + AssertEqual + \ ['-Dgoal=9', + \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')), + \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir with spaces')), + \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')), + \ '-DTEST=`date +%s`'] + \ , ale#c#ParseCFlagsToList(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'), + \ split('gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir ' . + \ '-I"dir with spaces"' . ' -I'. ale#path#Simplify('kernel/include') . + \ ' -DTEST=`date +%s` -c file.c', '-')) + +Execute(The CFlagsToList parser should be able to parse multiple cflags #6): + runtime! ale_linters/c/gcc.vim + + call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c') + + AssertEqual + \ ['-Dgoal=9', + \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')), + \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir with spaces')), + \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')), + \ '-DTEST=`date +%s`'] + \ , ale#c#ParseCFlagsToList(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'), + \ split('gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir ' . + \ '-I''dir with spaces''' . ' -I'. ale#path#Simplify('kernel/include') . + \ ' -DTEST=`date +%s` -c file.c', '-')) + +Execute(The CFlagsToList parser should be able to parse multiple cflags #7): + runtime! ale_linters/c/gcc.vim + + call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c') + + AssertEqual + \ ['-Dgoal=9', + \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')), + \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir with spaces')), + \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir-with-dash')), + \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')), + \ '-DTEST=`date +%s`'] + \ , ale#c#ParseCFlagsToList(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'), + \ split('gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir ' . + \ '-I''dir with spaces''' . ' -Idir-with-dash' . + \ ' -I'. ale#path#Simplify('kernel/include') . + \ ' -DTEST=`date +%s` -c file.c', '-')) + +Execute(The CFlagsToList parser should be able to parse multiple cflags #8): + runtime! ale_linters/c/gcc.vim + + call ale#test#SetFilename('test_c_projects/makefile_project/subdir/file.c') + + AssertEqual + \ ['-Dgoal=9', + \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/subdir')), + \ '-Dmacro-with-dash', + \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir with spaces')), + \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/dir-with-dash')), + \ ale#Escape('-I' . ale#path#Simplify(g:dir. '/test_c_projects/makefile_project/kernel/include')), + \ '-DTEST=`date +%s`'] + \ , ale#c#ParseCFlagsToList(ale#path#Simplify(g:dir. '/test_c_projects/makefile_project'), + \ split('gcc -Dgoal=9 -Tlinkerfile.ld blabla -Isubdir ' . + \ '-Dmacro-with-dash ' . + \ '-I''dir with spaces''' . ' -Idir-with-dash' . + \ ' -I'. ale#path#Simplify('kernel/include') . + \ ' -DTEST=`date +%s` -c file.c', '-')) diff --git a/test/test_c_projects/makefile_project/subdir/file.c b/test/test_c_projects/makefile_project/subdir/file.c new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/test/test_c_projects/makefile_project/subdir/file.c diff --git a/test/test_checkingbuffer_autocmd.vader b/test/test_checkingbuffer_autocmd.vader new file mode 100644 index 00000000..1cbfa342 --- /dev/null +++ b/test/test_checkingbuffer_autocmd.vader @@ -0,0 +1,57 @@ +Given testft (An empty file): + +Before: + Save g:ale_run_synchronously + Save g:ale_buffer_info + + let g:ale_run_synchronously = 1 + let g:ale_buffer_info = {} + + let g:checking_buffer = 0 + + unlet! b:ale_linted + + function! TestCallback(buffer, output) + return [] + endfunction + + call ale#linter#Define('testft', { + \ 'name': 'testlinter', + \ 'callback': 'TestCallback', + \ 'executable': has('win32') ? 'cmd' : 'true', + \ 'command': 'true', + \}) + +After: + Restore + + unlet! g:checking_buffer + + delfunction TestCallback + call ale#linter#Reset() + + augroup VaderTest + autocmd! + augroup end + + augroup! VaderTest + +Execute(ALELintPre should not return success on ale#engine#IsCheckingBuffer): + augroup VaderTest + autocmd! + autocmd User ALELintPre let g:checking_buffer = ale#engine#IsCheckingBuffer(bufnr('')) ? 1 : 0 + augroup end + + call ale#Lint() + + AssertEqual g:checking_buffer, 0 + +Execute(ALEJobStarted should return success on ale#engine#IsCheckingBuffer): + augroup VaderTest + autocmd! + autocmd User ALEJobStarted let g:checking_buffer = ale#engine#IsCheckingBuffer(bufnr('')) ? 1 : 0 + augroup end + + call ale#Lint() + + AssertEqual g:checking_buffer, 1 diff --git a/test/test_conflicting_plugin_warnings.vader b/test/test_conflicting_plugin_warnings.vader deleted file mode 100644 index 08a4c412..00000000 --- a/test/test_conflicting_plugin_warnings.vader +++ /dev/null @@ -1,74 +0,0 @@ -Execute(The after file should have been loaded for real): - " FIXME: Fix these tests in NeoVim. - if !has('nvim') - Assert has_key(g:, 'loaded_ale_after'), 'g:loaded_ale_after was not set!' - Assert g:loaded_ale_after - endif - -Before: - silent! cd /testplugin/test - cd .. - unlet! g:loaded_ale_after - -After: - cd test - let g:loaded_ale_after = 1 - let g:ale_emit_conflict_warnings = 1 - unlet! g:loaded_syntastic_plugin - unlet! g:loaded_neomake - unlet! g:loaded_validator_plugin - -Execute(ALE should not warn when nothing extra is installed): - " Nothing should be thrown when loading the after file. - source after/plugin/ale.vim - -Execute(ALE should warn users when Syntastic is installed): - let g:loaded_syntastic_plugin = 1 - - AssertThrows source after/plugin/ale.vim - AssertEqual - \ 'ALE conflicts with Syntastic' - \ . '. Uninstall it, or disable this warning with ' - \ . '`let g:ale_emit_conflict_warnings = 0` in your vimrc file, ' - \ . '*before* plugins are loaded.', - \ g:vader_exception - -Execute(ALE should not warn about Syntastic when the flag is set): - let g:loaded_syntastic_plugin = 1 - let g:ale_emit_conflict_warnings = 0 - - source after/plugin/ale.vim - -Execute(ALE should warn users when Neomake is installed): - let g:loaded_neomake = 1 - - AssertThrows source after/plugin/ale.vim - AssertEqual - \ 'ALE conflicts with Neomake' - \ . '. Uninstall it, or disable this warning with ' - \ . '`let g:ale_emit_conflict_warnings = 0` in your vimrc file, ' - \ . '*before* plugins are loaded.', - \ g:vader_exception - -Execute(ALE should not warn about Neomake when the flag is set): - let g:loaded_neomake = 1 - let g:ale_emit_conflict_warnings = 0 - - source after/plugin/ale.vim - -Execute(ALE should warn users when Validator is installed): - let g:loaded_validator_plugin = 1 - - AssertThrows source after/plugin/ale.vim - AssertEqual - \ 'ALE conflicts with Validator' - \ . '. Uninstall it, or disable this warning with ' - \ . '`let g:ale_emit_conflict_warnings = 0` in your vimrc file, ' - \ . '*before* plugins are loaded.', - \ g:vader_exception - -Execute(ALE should not warn about Validator when the flag is set): - let g:loaded_validator_plugin = 1 - let g:ale_emit_conflict_warnings = 0 - - source after/plugin/ale.vim diff --git a/test/test_cursor_warnings.vader b/test/test_cursor_warnings.vader index 19592217..24652909 100644 --- a/test/test_cursor_warnings.vader +++ b/test/test_cursor_warnings.vader @@ -2,6 +2,7 @@ Before: Save g:ale_echo_msg_format Save g:ale_echo_cursor + " We should prefer the error message at column 10 instead of the warning. let g:ale_buffer_info = { \ bufnr('%'): { \ 'loclist': [ @@ -12,6 +13,17 @@ Before: \ 'vcol': 0, \ 'linter_name': 'eslint', \ 'nr': -1, + \ 'type': 'W', + \ 'code': 'semi', + \ 'text': 'Ignore me.', + \ }, + \ { + \ 'lnum': 1, + \ 'col': 10, + \ 'bufnr': bufnr('%'), + \ 'vcol': 0, + \ 'linter_name': 'eslint', + \ 'nr': -1, \ 'type': 'E', \ 'code': 'semi', \ 'text': 'Missing semicolon.', diff --git a/test/test_elm_executable_detection.vader b/test/test_elm_executable_detection.vader index 4227cbfa..9146eea6 100644 --- a/test/test_elm_executable_detection.vader +++ b/test/test_elm_executable_detection.vader @@ -12,7 +12,7 @@ Execute(should get valid executable with default params): call ale#test#SetFilename('elm-test-files/app/testfile.elm') AssertEqual - \ ale#path#Simplify(g:dir . '/elm-test-files/app/node_modules/.bin/elm-make'), + \ ale#path#Simplify(g:dir . '/elm-test-files/app/node_modules/.bin/elm'), \ ale_linters#elm#make#GetExecutable(bufnr('')) Execute(should get valid executable with 'use_global' params): @@ -21,16 +21,16 @@ Execute(should get valid executable with 'use_global' params): call ale#test#SetFilename('elm-test-files/app/testfile.elm') AssertEqual - \ 'elm-make', + \ 'elm', \ ale_linters#elm#make#GetExecutable(bufnr('')) Execute(should get valid executable with 'use_global' and 'executable' params): - let g:ale_elm_make_executable = 'other-elm-make' + let g:ale_elm_make_executable = 'other-elm' let g:ale_elm_make_use_global = 1 call ale#test#SetFilename('elm-test-files/app/testfile.elm') AssertEqual - \ 'other-elm-make', + \ 'other-elm', \ ale_linters#elm#make#GetExecutable(bufnr('')) diff --git a/test/test_engine_lsp_response_handling.vader b/test/test_engine_lsp_response_handling.vader index b3a45b14..18bad0a1 100644 --- a/test/test_engine_lsp_response_handling.vader +++ b/test/test_engine_lsp_response_handling.vader @@ -1,5 +1,9 @@ Before: Save g:ale_buffer_info + Save g:ale_lsp_error_messages + + unlet! g:ale_lsp_error_messages + call ale#test#SetDirectory('/testplugin/test') After: @@ -7,7 +11,9 @@ After: call ale#test#RestoreDirectory() call ale#linter#Reset() + call ale#lsp_linter#ClearLSPData() +Given foobar(An empty file): Execute(tsserver syntax error responses should be handled correctly): runtime ale_linters/typescript/tsserver.vim call ale#test#SetFilename('filename.ts') @@ -15,7 +21,7 @@ Execute(tsserver syntax error responses should be handled correctly): " When we get syntax errors and no semantic errors, we should keep the " syntax errors. - call ale#engine#HandleLSPResponse(1, { + call ale#lsp_linter#HandleLSPResponse(1, { \ 'seq': 0, \ 'type': 'event', \ 'event': 'syntaxDiag', @@ -37,7 +43,7 @@ Execute(tsserver syntax error responses should be handled correctly): \ ], \ }, \}) - call ale#engine#HandleLSPResponse(1, { + call ale#lsp_linter#HandleLSPResponse(1, { \ 'seq': 0, \ 'type': 'event', \ 'event': 'semanticDiag', @@ -65,7 +71,7 @@ Execute(tsserver syntax error responses should be handled correctly): \ getloclist(0) " After we get empty syntax errors, we should clear them. - call ale#engine#HandleLSPResponse(1, { + call ale#lsp_linter#HandleLSPResponse(1, { \ 'seq': 0, \ 'type': 'event', \ 'event': 'syntaxDiag', @@ -88,7 +94,7 @@ Execute(tsserver semantic error responses should be handled correctly): " When we get syntax errors and no semantic errors, we should keep the " syntax errors. - call ale#engine#HandleLSPResponse(1, { + call ale#lsp_linter#HandleLSPResponse(1, { \ 'seq': 0, \ 'type': 'event', \ 'event': 'syntaxDiag', @@ -98,7 +104,7 @@ Execute(tsserver semantic error responses should be handled correctly): \ ], \ }, \}) - call ale#engine#HandleLSPResponse(1, { + call ale#lsp_linter#HandleLSPResponse(1, { \ 'seq': 0, \ 'type': 'event', \ 'event': 'semanticDiag', @@ -138,7 +144,7 @@ Execute(tsserver semantic error responses should be handled correctly): \ getloclist(0) " After we get empty syntax errors, we should clear them. - call ale#engine#HandleLSPResponse(1, { + call ale#lsp_linter#HandleLSPResponse(1, { \ 'seq': 0, \ 'type': 'event', \ 'event': 'semanticDiag', @@ -153,3 +159,20 @@ Execute(tsserver semantic error responses should be handled correctly): \ [ \ ], \ getloclist(0) + +Execute(LSP errors should be logged in the history): + call ale#lsp_linter#SetLSPLinterMap({'347': 'foobar'}) + call ale#lsp_linter#HandleLSPResponse(347, { + \ 'jsonrpc': '2.0', + \ 'error': { + \ 'code': -32602, + \ 'message': 'xyz', + \ 'data': { + \ 'traceback': ['123', '456'], + \ }, + \ }, + \}) + + AssertEqual + \ {'foobar': ["xyz\n123\n456"]}, + \ get(g:, 'ale_lsp_error_messages', {}) diff --git a/test/test_find_references.vader b/test/test_find_references.vader new file mode 100644 index 00000000..c2290ca3 --- /dev/null +++ b/test/test_find_references.vader @@ -0,0 +1,250 @@ +Before: + call ale#test#SetDirectory('/testplugin/test') + call ale#test#SetFilename('dummy.txt') + + let g:old_filename = expand('%:p') + let g:Callback = 0 + let g:expr_list = [] + let g:message_list = [] + let g:preview_called = 0 + let g:item_list = [] + + runtime autoload/ale/linter.vim + runtime autoload/ale/lsp.vim + runtime autoload/ale/util.vim + runtime autoload/ale/preview.vim + + function! ale#lsp_linter#StartLSP(buffer, linter, callback) abort + let g:Callback = a:callback + + let l:conn = ale#lsp#NewConnection({}) + let l:conn.id = 347 + let l:conn.open_documents = {a:buffer : -1} + + return { + \ 'buffer': a:buffer, + \ 'connection_id': 347, + \ 'project_root': '/foo/bar', + \ 'language_id': 'python', + \} + endfunction + + function! ale#lsp#Send(conn_id, message, root) abort + call add(g:message_list, a:message) + + return 42 + endfunction + + function! ale#util#Execute(expr) abort + call add(g:expr_list, a:expr) + endfunction + + function! ale#preview#ShowSelection(item_list) abort + let g:preview_called = 1 + let g:item_list = a:item_list + endfunction + +After: + call ale#lsp#RemoveConnectionWithID(347) + call ale#references#SetMap({}) + call ale#test#RestoreDirectory() + call ale#linter#Reset() + + unlet! g:old_filename + unlet! g:Callback + unlet! g:message_list + unlet! g:expr_list + unlet! b:ale_linters + unlet! g:item_list + unlet! g:preview_called + + runtime autoload/ale/linter.vim + runtime autoload/ale/lsp.vim + runtime autoload/ale/util.vim + runtime autoload/ale/preview.vim + +Execute(Other messages for the tsserver handler should be ignored): + call ale#references#HandleTSServerResponse(1, {'command': 'foo'}) + +Execute(Failed reference responses should be handled correctly): + call ale#references#SetMap({3: {}}) + call ale#references#HandleTSServerResponse( + \ 1, + \ {'command': 'references', 'request_seq': 3} + \) + AssertEqual {}, ale#references#GetMap() + +Given typescript(Some typescript file): + foo + somelongerline + bazxyzxyzxyz + +Execute(Results should be shown for tsserver responses): + call ale#references#SetMap({3: {}}) + call ale#references#HandleTSServerResponse(1, { + \ 'command': 'references', + \ 'request_seq': 3, + \ 'success': v:true, + \ 'body': { + \ 'symbolStartOffset': 9, + \ 'refs': [ + \ { + \ 'file': '/foo/bar/app.ts', + \ 'isWriteAccess': v:true, + \ 'lineText': 'import {doSomething} from ''./whatever''', + \ 'end': {'offset': 24, 'line': 9}, + \ 'start': {'offset': 9, 'line': 9}, + \ 'isDefinition': v:true, + \ }, + \ { + \ 'file': '/foo/bar/app.ts', + \ 'isWriteAccess': v:false, + \ 'lineText': ' doSomething()', + \ 'end': {'offset': 18, 'line': 804}, + \ 'start': {'offset': 3, 'line': 804}, + \ 'isDefinition': v:false, + \ }, + \ { + \ 'file': '/foo/bar/other/app.ts', + \ 'isWriteAccess': v:false, + \ 'lineText': ' doSomething()', + \ 'end': {'offset': 18, 'line': 51}, + \ 'start': {'offset': 3, 'line': 51}, + \ 'isDefinition': v:false, + \ }, + \ ], + \ 'symbolDisplayString': 'import doSomething', + \ 'symbolName': 'doSomething()', + \ }, + \}) + + AssertEqual + \ [ + \ {'filename': '/foo/bar/app.ts', 'column': 9, 'line': 9}, + \ {'filename': '/foo/bar/app.ts', 'column': 3, 'line': 804}, + \ {'filename': '/foo/bar/other/app.ts', 'column': 3, 'line': 51}, + \ ], + \ g:item_list + AssertEqual {}, ale#references#GetMap() + +Execute(The preview window should not be opened for empty tsserver responses): + call ale#references#SetMap({3: {}}) + call ale#references#HandleTSServerResponse(1, { + \ 'command': 'references', + \ 'request_seq': 3, + \ 'success': v:true, + \ 'body': { + \ 'symbolStartOffset': 9, + \ 'refs': [ + \ ], + \ 'symbolDisplayString': 'import doSomething', + \ 'symbolName': 'doSomething()', + \ }, + \}) + + Assert !g:preview_called + AssertEqual {}, ale#references#GetMap() + AssertEqual ['echom ''No references found.'''], g:expr_list + +Execute(tsserver reference requests should be sent): + runtime ale_linters/typescript/tsserver.vim + call setpos('.', [bufnr(''), 2, 5, 0]) + + ALEFindReferences + + AssertEqual + \ 'function(''ale#references#HandleTSServerResponse'')', + \ string(g:Callback) + AssertEqual + \ [[0, 'ts@references', {'file': expand('%:p'), 'line': 2, 'offset': 5}]], + \ g:message_list + AssertEqual {'42': {}}, ale#references#GetMap() + +Given python(Some Python file): + foo + somelongerline + bazxyzxyzxyz + +Execute(LSP reference responses should be handled): + call ale#references#SetMap({3: {}}) + call ale#references#HandleLSPResponse( + \ 1, + \ { + \ 'id': 3, + \ 'result': [ + \ { + \ 'uri': ale#path#ToURI(ale#path#Simplify(g:dir . '/completion_dummy_file')), + \ 'range': { + \ 'start': {'line': 2, 'character': 7}, + \ }, + \ }, + \ { + \ 'uri': ale#path#ToURI(ale#path#Simplify(g:dir . '/other_file')), + \ 'range': { + \ 'start': {'line': 7, 'character': 15}, + \ }, + \ }, + \ ], + \ } + \) + + AssertEqual + \ [ + \ { + \ 'filename': ale#path#Simplify(g:dir . '/completion_dummy_file'), + \ 'line': 3, + \ 'column': 8, + \ }, + \ { + \ 'filename': ale#path#Simplify(g:dir . '/other_file'), + \ 'line': 8, + \ 'column': 16, + \ }, + \ ], + \ g:item_list + AssertEqual {}, ale#references#GetMap() + +Execute(Preview windows should not be opened for empty LSP reference responses): + call ale#references#SetMap({3: {}}) + call ale#references#HandleLSPResponse( + \ 1, + \ { + \ 'id': 3, + \ 'result': [ + \ ], + \ } + \) + + Assert !g:preview_called + AssertEqual {}, ale#references#GetMap() + AssertEqual ['echom ''No references found.'''], g:expr_list + +Execute(LSP reference requests should be sent): + runtime ale_linters/python/pyls.vim + let b:ale_linters = ['pyls'] + call setpos('.', [bufnr(''), 1, 5, 0]) + + ALEFindReferences + + AssertEqual + \ 'function(''ale#references#HandleLSPResponse'')', + \ string(g:Callback) + + AssertEqual + \ [ + \ [1, 'textDocument/didChange', { + \ 'textDocument': { + \ 'uri': ale#path#ToURI(expand('%:p')), + \ 'version': g:ale_lsp_next_version_id - 1, + \ }, + \ 'contentChanges': [{'text': join(getline(1, '$'), "\n") . "\n"}] + \ }], + \ [0, 'textDocument/references', { + \ 'textDocument': {'uri': ale#path#ToURI(expand('%:p'))}, + \ 'position': {'line': 0, 'character': 3}, + \ 'context': {'includeDeclaration': v:false}, + \ }], + \ ], + \ g:message_list + + AssertEqual {'42': {}}, ale#references#GetMap() diff --git a/test/test_flow_command.vader b/test/test_flow_command.vader index 49546e94..c673ce0a 100644 --- a/test/test_flow_command.vader +++ b/test/test_flow_command.vader @@ -1,8 +1,11 @@ Before: runtime ale_linters/javascript/flow.vim + 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() @@ -15,6 +18,16 @@ Execute(flow should return a command to run if a .flowconfig file exists): \ . ' check-contents --respect-pragma --json --from ale %s', \ ale_linters#javascript#flow#GetCommand(bufnr('%'), []) +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 + \ ale#Escape('flow') + \ . ' check-contents --json --from ale %s', + \ ale_linters#javascript#flow#GetCommand(bufnr('%'), []) + Execute(flow should should not use --respect-pragma for old versions): call ale#test#SetFilename('flow/a/sub/dummy') diff --git a/test/test_go_to_definition.vader b/test/test_go_to_definition.vader index b77a75ac..78373a65 100644 --- a/test/test_go_to_definition.vader +++ b/test/test_go_to_definition.vader @@ -7,16 +7,22 @@ Before: let g:message_list = [] let g:expr_list = [] - runtime autoload/ale/definition.vim runtime autoload/ale/linter.vim runtime autoload/ale/lsp.vim + runtime autoload/ale/util.vim - function! ale#linter#StartLSP(buffer, linter, callback) abort + function! ale#lsp_linter#StartLSP(buffer, linter, callback) abort let g:Callback = a:callback + let l:conn = ale#lsp#NewConnection({}) + let l:conn.id = 347 + let l:conn.open_documents = {a:buffer : -1} + return { + \ 'buffer': a:buffer, \ 'connection_id': 347, \ 'project_root': '/foo/bar', + \ 'language_id': 'python', \} endfunction @@ -26,11 +32,13 @@ Before: return 42 endfunction - function! ale#definition#Execute(expr) abort + function! ale#util#Execute(expr) abort call add(g:expr_list, a:expr) endfunction After: + call ale#lsp#RemoveConnectionWithID(347) + call ale#definition#SetMap({}) call ale#test#RestoreDirectory() call ale#linter#Reset() @@ -40,9 +48,9 @@ After: unlet! g:expr_list unlet! b:ale_linters - runtime autoload/ale/definition.vim runtime autoload/ale/linter.vim runtime autoload/ale/lsp.vim + runtime autoload/ale/util.vim Execute(Other messages for the tsserver handler should be ignored): call ale#definition#HandleTSServerResponse(1, {'command': 'foo'}) @@ -55,6 +63,19 @@ Execute(Failed definition responses should be handled correctly): \) AssertEqual {}, ale#definition#GetMap() +Execute(Failed definition responses with no files should be handled correctly): + call ale#definition#SetMap({3: {'open_in_tab': 0}}) + call ale#definition#HandleTSServerResponse( + \ 1, + \ { + \ 'command': 'definition', + \ 'request_seq': 3, + \ 'success': v:true, + \ 'body': [], + \ } + \) + AssertEqual {}, ale#definition#GetMap() + Given typescript(Some typescript file): foo somelongerline @@ -166,6 +187,28 @@ Execute(Other files should be jumped to for LSP definition responses): AssertEqual [3, 7], getpos('.')[1:2] AssertEqual {}, ale#definition#GetMap() +Execute(Locations inside the same file should be jumped to without using :edit): + call ale#definition#SetMap({3: {'open_in_tab': 0}}) + call ale#definition#HandleLSPResponse( + \ 1, + \ { + \ 'id': 3, + \ 'result': { + \ 'uri': ale#path#ToURI(ale#path#Simplify(expand('%:p'))), + \ 'range': { + \ 'start': {'line': 2, 'character': 7}, + \ }, + \ }, + \ } + \) + + AssertEqual + \ [ + \ ], + \ g:expr_list + AssertEqual [3, 7], getpos('.')[1:2] + AssertEqual {}, ale#definition#GetMap() + Execute(Other files should be jumped to in tabs for LSP definition responses): call ale#definition#SetMap({3: {'open_in_tab': 1}}) call ale#definition#HandleLSPResponse( diff --git a/test/test_hover.vader b/test/test_hover.vader new file mode 100644 index 00000000..15f164f0 --- /dev/null +++ b/test/test_hover.vader @@ -0,0 +1,151 @@ +Before: + call ale#test#SetDirectory('/testplugin/test') + call ale#test#SetFilename('dummy.txt') + + let g:Callback = 0 + let g:message_list = [] + let g:item_list = [] + let g:echo_list = [] + + runtime autoload/ale/linter.vim + runtime autoload/ale/lsp.vim + runtime autoload/ale/util.vim + + function! ale#lsp_linter#StartLSP(buffer, linter, callback) abort + let g:Callback = a:callback + + return { + \ 'connection_id': 347, + \ 'project_root': '/foo/bar', + \} + endfunction + + function! ale#lsp#Send(conn_id, message, root) abort + call add(g:message_list, a:message) + + return 42 + endfunction + + function! ale#util#ShowMessage(string) abort + call add(g:echo_list, a:string) + endfunction + + function! HandleValidLSPResult(result) abort + " The cursor is beyond the length of the line. + " We will clamp the cursor position with the line length. + call setpos('.', [bufnr(''), 1, 5, 0]) + + call ale#hover#SetMap({3: { + \ 'buffer': bufnr(''), + \ 'line': 1, + \ 'column': 5, + \}}) + call ale#hover#HandleLSPResponse( + \ 1, + \ { + \ 'id': 3, + \ 'result': a:result, + \ } + \) + endfunction + +After: + call ale#hover#SetMap({}) + call ale#test#RestoreDirectory() + call ale#linter#Reset() + + unlet! g:Callback + unlet! g:message_list + unlet! b:ale_linters + unlet! g:echo_list + + delfunction HandleValidLSPResult + + runtime autoload/ale/linter.vim + runtime autoload/ale/lsp.vim + runtime autoload/ale/util.vim + +Given python(Some Python file): + foo + somelongerline + bazxyzxyzxyz + +Execute(Other messages for the tsserver handler should be ignored): + call ale#hover#HandleTSServerResponse(1, {'command': 'foo'}) + +Execute(Failed hover responses should be handled correctly): + call ale#hover#SetMap({3: {}}) + call ale#hover#HandleTSServerResponse( + \ 1, + \ {'command': 'quickinfo', 'request_seq': 3} + \) + AssertEqual {}, ale#hover#GetMap() + +Given typescript(Some typescript file): + foo + somelongerline + bazxyzxyzxyz + +Execute(tsserver quickinfo responses will null missing bodies should be handled): + call ale#hover#SetMap({3: {}}) + call ale#hover#HandleTSServerResponse( + \ 1, + \ { + \ 'command': 'quickinfo', + \ 'request_seq': 3, + \ 'success': v:true, + \ } + \) + + AssertEqual {}, ale#hover#GetMap() + +Execute(tsserver quickinfo displayString values should be displayed): + call ale#hover#SetMap({3: {}}) + call ale#hover#HandleTSServerResponse( + \ 1, + \ { + \ 'command': 'quickinfo', + \ 'request_seq': 3, + \ 'success': v:true, + \ 'body': {'displayString': 'foo bar'}, + \ } + \) + + AssertEqual ['foo bar'], g:echo_list + AssertEqual {}, ale#hover#GetMap() + +Execute(LSP hover responses with just a string should be handled): + call HandleValidLSPResult({'contents': 'foobar'}) + + AssertEqual ['foobar'], g:echo_list + AssertEqual {}, ale#hover#GetMap() + +Execute(LSP hover null responses should be handled): + call HandleValidLSPResult(v:null) + + AssertEqual [], g:echo_list + AssertEqual {}, ale#hover#GetMap() + +Execute(LSP hover responses with markup content should be handled): + call HandleValidLSPResult({'contents': {'kind': 'something', 'value': 'markup'}}) + + AssertEqual ['markup'], g:echo_list + AssertEqual {}, ale#hover#GetMap() + +Execute(LSP hover response with lists of strings should be handled): + call HandleValidLSPResult({'contents': [ + \ "foo\n", + \ "bar\n", + \]}) + + AssertEqual ["foo\n\nbar\n"], g:echo_list + AssertEqual {}, ale#hover#GetMap() + +Execute(LSP hover response with lists of strings and marked strings should be handled): + call HandleValidLSPResult({'contents': [ + \ {'language': 'rust', 'value': 'foo'}, + \ "bar\n", + \]}) + + AssertEqual ["foo\nbar\n"], g:echo_list + AssertEqual {}, ale#hover#GetMap() diff --git a/test/test_ignoring_linters.vader b/test/test_ignoring_linters.vader new file mode 100644 index 00000000..af31fce3 --- /dev/null +++ b/test/test_ignoring_linters.vader @@ -0,0 +1,250 @@ +Execute(GetList should ignore some invalid values): + AssertEqual [], ale#engine#ignore#GetList('', 'foo') + AssertEqual [], ale#engine#ignore#GetList('', 0) + AssertEqual [], ale#engine#ignore#GetList('', v:null) + +Execute(GetList should handle Lists): + AssertEqual ['foo', 'bar'], ale#engine#ignore#GetList('', ['foo', 'bar']) + +Execute(GetList should handle Dictionaries): + AssertEqual + \ ['linter1', 'linter2'], + \ uniq(sort(ale#engine#ignore#GetList('x.y.z', { + \ 'x': ['linter1'], + \ 'abc': ['linter3'], + \ 'z': ['linter2'], + \ }))) + +Execute(Exclude should ignore some invalid values): + AssertEqual + \ [ + \ {'name': 'linter1', 'aliases': []}, + \ {'name': 'linter2', 'aliases': ['alias1']}, + \ {'name': 'linter3', 'aliases': []}, + \ ], + \ ale#engine#ignore#Exclude( + \ 'foo.bar', + \ [ + \ {'name': 'linter1', 'aliases': []}, + \ {'name': 'linter2', 'aliases': ['alias1']}, + \ {'name': 'linter3', 'aliases': []}, + \ ], + \ 'foo', + \ ) + AssertEqual + \ [ + \ {'name': 'linter1', 'aliases': []}, + \ {'name': 'linter2', 'aliases': ['alias1']}, + \ {'name': 'linter3', 'aliases': []}, + \ ], + \ ale#engine#ignore#Exclude( + \ 'foo.bar', + \ [ + \ {'name': 'linter1', 'aliases': []}, + \ {'name': 'linter2', 'aliases': ['alias1']}, + \ {'name': 'linter3', 'aliases': []}, + \ ], + \ 0, + \ ) + AssertEqual + \ [ + \ {'name': 'linter1', 'aliases': []}, + \ {'name': 'linter2', 'aliases': ['alias1']}, + \ {'name': 'linter3', 'aliases': []}, + \ ], + \ ale#engine#ignore#Exclude( + \ 'foo.bar', + \ [ + \ {'name': 'linter1', 'aliases': []}, + \ {'name': 'linter2', 'aliases': ['alias1']}, + \ {'name': 'linter3', 'aliases': []}, + \ ], + \ v:null, + \ ) + +Execute(Exclude should handle Lists): + AssertEqual + \ [ + \ {'name': 'linter3', 'aliases': []}, + \ ], + \ ale#engine#ignore#Exclude( + \ 'foo.bar', + \ [ + \ {'name': 'linter1', 'aliases': []}, + \ {'name': 'linter2', 'aliases': ['alias1']}, + \ {'name': 'linter3', 'aliases': []}, + \ ], + \ ['linter1', 'alias1'], + \ ) + +Execute(Exclude should handle Dictionaries): + AssertEqual + \ [ + \ {'name': 'linter3', 'aliases': []}, + \ ], + \ ale#engine#ignore#Exclude( + \ 'foo.bar', + \ [ + \ {'name': 'linter1', 'aliases': []}, + \ {'name': 'linter2', 'aliases': ['alias1']}, + \ {'name': 'linter3', 'aliases': []}, + \ ], + \ {'foo': ['linter1'], 'bar': ['alias1']}, + \ ) + +Before: + Save g:ale_linters_ignore + Save g:ale_buffer_info + + let g:linters = [] + let g:loclist = [] + let g:run_linters_called = 0 + + runtime autoload/ale/engine.vim + + " Mock the engine function so we can set it up. + function! ale#engine#RunLinters(buffer, linters, should_lint_file) abort + let g:linters = a:linters + let g:run_linters_called = 1 + endfunction + + function! ale#engine#HandleLoclist(linter_name, buffer, loclist) abort + let g:loclist = a:loclist + endfunction + + call ale#linter#Define('foobar', { + \ 'name': 'testlinter', + \ 'callback': 'TestCallback', + \ 'executable': has('win32') ? 'cmd' : 'true', + \ 'command': has('win32') ? 'echo' : 'true', + \}) + call ale#test#SetDirectory('/testplugin/test') + +After: + Restore + + unlet! b:ale_linted + unlet! b:ale_linters_ignore + unlet! b:ale_quitting + unlet! b:ale_save_event_fired + unlet! g:linters + unlet! g:loclist + unlet! g:lsp_message + + call ale#test#RestoreDirectory() + call ale#linter#Reset() + call ale#lsp_linter#ClearLSPData() + runtime autoload/ale/engine.vim + +Given foobar(An empty file): +Execute(Global ignore lists should be applied for linters): + ALELint + Assert g:run_linters_called, "The mock callback wasn't called" + AssertEqual ['testlinter'], map(g:linters, 'v:val.name') + + let g:ale_linters_ignore = ['testlinter'] + ALELint + AssertEqual [], g:linters + +Execute(buffer ignore lists should be applied for linters): + ALELint + Assert g:run_linters_called, "The mock callback wasn't called" + AssertEqual ['testlinter'], map(g:linters, 'v:val.name') + + let b:ale_linters_ignore = ['testlinter'] + ALELint + AssertEqual [], g:linters + +Execute(Buffer ignore lists should be applied for tsserver): + call ale#test#SetFilename('filename.ts') + call ale#engine#InitBufferInfo(bufnr('')) + + let g:lsp_message = { + \ 'seq': 0, + \ 'type': 'event', + \ 'event': 'syntaxDiag', + \ 'body': { + \ 'file': g:dir . '/filename.ts', + \ 'diagnostics':[ + \ { + \ 'start': { + \ 'line':2, + \ 'offset':14, + \ }, + \ 'end': { + \ 'line':2, + \ 'offset':15, + \ }, + \ 'text': ''','' expected.', + \ "code":1005 + \ }, + \ ], + \ }, + \} + + call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message) + + AssertEqual + \ [ + \ { + \ 'lnum': 2, + \ 'col': 14, + \ 'nr': 1005, + \ 'type': 'E', + \ 'end_col': 15, + \ 'end_lnum': 2, + \ 'text': ''','' expected.', + \ }, + \ ], + \ g:loclist + + let g:loclist = [] + let b:ale_linters_ignore = ['tsserver'] + call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message) + + AssertEqual [], g:loclist + +Execute(Buffer ignore lists should be applied for LSP linters): + call ale#test#SetFilename('filename.py') + call ale#engine#InitBufferInfo(bufnr('')) + call ale#lsp_linter#SetLSPLinterMap({'347': 'lsplinter'}) + + let g:lsp_message = { + \ 'jsonrpc': '2.0', + \ 'method': 'textDocument/publishDiagnostics', + \ 'params': { + \ 'uri': ale#path#ToURI(expand('%:p')), + \ 'diagnostics': [ + \ { + \ 'severity': 1, + \ 'message': 'x', + \ 'range': { + \ 'start': {'line': 0, 'character': 9}, + \ 'end': {'line': 0, 'character': 9}, + \ }, + \ } + \ ], + \ }, + \} + + call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message) + + AssertEqual + \ [ + \ { + \ 'lnum': 1, + \ 'col': 10, + \ 'type': 'E', + \ 'end_col': 10, + \ 'end_lnum': 1, + \ 'text': 'x', + \ } + \ ], + \ g:loclist + + let b:ale_linters_ignore = ['lsplinter'] + let g:loclist = [] + + call ale#lsp_linter#HandleLSPResponse(347, g:lsp_message) + + AssertEqual [], g:loclist diff --git a/test/test_lint_error_delay.vader b/test/test_lint_error_delay.vader deleted file mode 100644 index 7f081794..00000000 --- a/test/test_lint_error_delay.vader +++ /dev/null @@ -1,22 +0,0 @@ -Before: - Save g:ale_filetype_blacklist - - " Delete some variable which should be defined. - unlet! g:ale_filetype_blacklist - -After: - Restore - - call ale#ResetErrorDelays() - -Execute(ALE should stop queuing for a while after exceptions are thrown): - AssertThrows call ale#Queue(100) - call ale#Queue(100) - -Execute(ALE should stop linting for a while after exceptions are thrown): - AssertThrows call ale#Lint() - call ale#Lint() - -Execute(ALE should stop echoing messages for a while after exceptions are thrown): - AssertThrows call ale#cursor#EchoCursorWarning() - call ale#cursor#EchoCursorWarning() diff --git a/test/test_linter_defintion_processing.vader b/test/test_linter_defintion_processing.vader index d946a600..48a4a394 100644 --- a/test/test_linter_defintion_processing.vader +++ b/test/test_linter_defintion_processing.vader @@ -421,6 +421,30 @@ Execute(PreProcess should accept LSP server configurations): AssertEqual 'socket', ale#linter#PreProcess(g:linter).lsp +Execute(PreProcess should accept let you specify the language as just a string): + let g:linter = { + \ 'name': 'x', + \ 'lsp': 'socket', + \ 'address_callback': 'X', + \ 'language': 'foobar', + \ 'project_root_callback': 'x', + \} + + AssertEqual 'foobar', ale#linter#PreProcess(g:linter).language_callback(0) + +Execute(PreProcess should complain about using language and language_callback together): + let g:linter = { + \ 'name': 'x', + \ 'lsp': 'socket', + \ 'address_callback': 'X', + \ 'language': 'x', + \ 'language_callback': 'x', + \ 'project_root_callback': 'x', + \} + + AssertThrows call ale#linter#PreProcess(g:linter) + AssertEqual 'Only one of `language` or `language_callback` should be set', g:vader_exception + Execute(PreProcess should require an address_callback for LSP socket configurations): let g:linter = { \ 'name': 'x', @@ -441,3 +465,28 @@ Execute(PreProcess should complain about address_callback for non-LSP linters): AssertThrows call ale#linter#PreProcess(g:linter) AssertEqual '`address_callback` cannot be used when lsp != ''socket''', g:vader_exception + +Execute(PreProcess should complain about using initialization_options and initialization_options_callback together): + let g:linter = { + \ 'name': 'x', + \ 'lsp': 'socket', + \ 'address_callback': 'X', + \ 'language': 'x', + \ 'project_root_callback': 'x', + \ 'initialization_options': 'x', + \ 'initialization_options_callback': 'x', + \} + + AssertThrows call ale#linter#PreProcess(g:linter) + AssertEqual 'Only one of `initialization_options` or `initialization_options_callback` should be set', g:vader_exception + +Execute (PreProcess should throw when initialization_options_callback is not a callback): + AssertThrows call ale#linter#PreProcess({ + \ 'name': 'foo', + \ 'lsp': 'socket', + \ 'address_callback': 'X', + \ 'language': 'x', + \ 'project_root_callback': 'x', + \ 'initialization_options_callback': {}, + \}) + AssertEqual '`initialization_options_callback` must be a callback if defined', g:vader_exception diff --git a/test/test_linter_retrieval.vader b/test/test_linter_retrieval.vader index 5d1ee451..6c402d54 100644 --- a/test/test_linter_retrieval.vader +++ b/test/test_linter_retrieval.vader @@ -5,6 +5,9 @@ Before: let g:testlinter1 = {'name': 'testlinter1', 'executable': 'testlinter1', 'command': 'testlinter1', 'callback': 'testCB1', 'output_stream': 'stdout', 'read_buffer': 1, 'lint_file': 0, 'aliases': [], 'lsp': '', 'add_newline': 0} let g:testlinter2 = {'name': 'testlinter2', 'executable': 'testlinter2', 'command': 'testlinter2', 'callback': 'testCB2', 'output_stream': 'stdout', 'read_buffer': 0, 'lint_file': 1, 'aliases': [], 'lsp': '', 'add_newline': 0} call ale#linter#Reset() + call ale#linter#PreventLoading('testft') + call ale#linter#PreventLoading('javascript') + call ale#linter#PreventLoading('typescript') After: Restore @@ -145,6 +148,7 @@ Execute (Buffer-local overrides for aliases should be used): AssertEqual [g:testlinter1, g:testlinter2], ale#linter#Get('testft1') Execute (Linters should be loaded from disk appropriately): + call ale#linter#Reset() AssertEqual [{'name': 'testlinter', 'output_stream': 'stdout', 'executable': 'testlinter', 'command': 'testlinter', 'callback': 'testCB', 'read_buffer': 1, 'lint_file': 0, 'aliases': [], 'lsp': '', 'add_newline': 0}], ale#linter#Get('testft') diff --git a/test/test_list_opening.vader b/test/test_list_opening.vader index 63b30ef1..a24e8de9 100644 --- a/test/test_list_opening.vader +++ b/test/test_list_opening.vader @@ -5,6 +5,7 @@ Before: Save g:ale_open_list Save g:ale_keep_list_window_open Save g:ale_list_window_size + Save g:ale_list_vertical Save g:ale_buffer_info Save g:ale_set_lists_synchronously @@ -13,6 +14,7 @@ Before: let g:ale_open_list = 0 let g:ale_keep_list_window_open = 0 let g:ale_list_window_size = 10 + let g:ale_list_vertical = 0 let g:ale_set_lists_synchronously = 1 let g:loclist = [ @@ -33,16 +35,29 @@ Before: return 0 endfunction + " If the window is vertical, window size should match column size/width + function GetQuickfixIsVertical(cols) abort + for l:win in range(1, winnr('$')) + if getwinvar(l:win, '&buftype') is# 'quickfix' + return winwidth(l:win) == a:cols + endif + endfor + + return 0 + endfunction + After: Restore unlet! g:loclist + unlet! b:ale_list_vertical unlet! b:ale_list_window_size unlet! b:ale_open_list unlet! b:ale_keep_list_window_open unlet! b:ale_save_event_fired delfunction GetQuickfixHeight + delfunction GetQuickfixIsVertical " Close quickfix window after every execute block lcl @@ -98,6 +113,24 @@ Execute(The quickfix window height should be correct for the loclist with buffer AssertEqual 8, GetQuickfixHeight() +Execute(The quickfix window should be vertical for the loclist with appropriate variables): + let g:ale_open_list = 1 + let b:ale_list_window_size = 8 + let b:ale_list_vertical = 1 + + call ale#list#SetLists(bufnr('%'), g:loclist) + + AssertEqual 1, GetQuickfixIsVertical(b:ale_list_window_size) + +Execute(The quickfix window should be horizontal for the loclist with appropriate variables): + let g:ale_open_list = 1 + let b:ale_list_window_size = 8 + let b:ale_list_vertical = 0 + + call ale#list#SetLists(bufnr('%'), g:loclist) + + AssertEqual 0, GetQuickfixIsVertical(b:ale_list_window_size) + Execute(The quickfix window should stay open for just the loclist): let g:ale_open_list = 1 let g:ale_keep_list_window_open = 1 @@ -167,6 +200,24 @@ Execute(The quickfix window height should be correct for the quickfix list with AssertEqual 8, GetQuickfixHeight() +Execute(The quickfix window should be vertical for the quickfix with appropriate variables): + let g:ale_open_list = 1 + let b:ale_list_window_size = 8 + let b:ale_list_vertical = 1 + + call ale#list#SetLists(bufnr('%'), g:loclist) + + AssertEqual 1, GetQuickfixIsVertical(b:ale_list_window_size) + +Execute(The quickfix window should be horizontal for the quickfix with appropriate variables): + let g:ale_open_list = 1 + let b:ale_list_window_size = 8 + let b:ale_list_vertical = 0 + + call ale#list#SetLists(bufnr('%'), g:loclist) + + AssertEqual 0, GetQuickfixIsVertical(b:ale_list_window_size) + Execute(The buffer ale_open_list option should be respected): let b:ale_open_list = 1 diff --git a/test/test_loclist_binary_search.vader b/test/test_loclist_binary_search.vader index 5558191c..219fb314 100644 --- a/test/test_loclist_binary_search.vader +++ b/test/test_loclist_binary_search.vader @@ -47,3 +47,20 @@ Execute(Searches should work with just one item): let g:loclist = [{'bufnr': 1, 'lnum': 3, 'col': 10}] AssertEqual 0, ale#util#BinarySearch(g:loclist, 1, 3, 2) + +Execute(Searches should return the last item on a single column): + let g:loclist = [ + \ {'bufnr': 1, 'lnum': 1, 'col': 10, 'type': 'W'}, + \ {'bufnr': 1, 'lnum': 1, 'col': 10, 'type': 'E'}, + \ {'bufnr': 1, 'lnum': 1, 'col': 11, 'type': 'W'}, + \ {'bufnr': 1, 'lnum': 1, 'col': 11, 'type': 'E'}, + \ {'bufnr': 1, 'lnum': 1, 'col': 20, 'type': 'W'}, + \ {'bufnr': 1, 'lnum': 1, 'col': 20, 'type': 'E'}, + \] + + " We should return the index for the last item at some column to the right. + AssertEqual 1, ale#util#BinarySearch(g:loclist, 1, 1, 1) + " We should return the index for the last item at the column we are on. + AssertEqual 3, ale#util#BinarySearch(g:loclist, 1, 1, 11) + " We should prefer items to the left of the cursor, over the right. + AssertEqual 3, ale#util#BinarySearch(g:loclist, 1, 1, 19) diff --git a/test/test_loclist_corrections.vader b/test/test_loclist_corrections.vader index 6224d608..48aa1f78 100644 --- a/test/test_loclist_corrections.vader +++ b/test/test_loclist_corrections.vader @@ -52,7 +52,7 @@ Execute(FixLocList should use the values we supply): \ 'lnum': 3, \ 'col': 4, \ 'bufnr': 10000, - \ 'vcol': 1, + \ 'vcol': 0, \ 'type': 'W', \ 'nr': 42, \ 'linter_name': 'foobar', @@ -324,7 +324,7 @@ Execute(FixLocList should interpret temporary filenames as being the current buf \ 'foobar', \ [ \ {'text': 'a', 'lnum': 2, 'filename': b:temp_name}, - \ {'text': 'a', 'lnum': 3, 'filename': b:temp_name}, + \ {'text': 'a', 'lnum': 3, 'filename': substitute(b:temp_name, '\\', '/', 'g')}, \ ], \ ) @@ -348,3 +348,33 @@ Execute(The error code should be passed on): \ 'foobar', \ [{'text': 'a', 'lnum': 11, 'code': 'some-code'}], \ ) + +Given(A file with Japanese multi-byte text): + はじめまして! + -私はワープです。 +Execute(character positions should be converted to byte positions): + AssertEqual + \ [ + \ {'lnum': 1, 'bufnr': bufnr(''), 'col': 0, 'linter_name': 'foobar', 'nr': -1, 'type': 'E', 'vcol': 0, 'text': 'a'}, + \ {'lnum': 1, 'bufnr': bufnr(''), 'col': 1, 'linter_name': 'foobar', 'nr': -1, 'type': 'E', 'vcol': 0, 'text': 'a'}, + \ {'lnum': 1, 'bufnr': bufnr(''), 'col': 4, 'linter_name': 'foobar', 'nr': -1, 'type': 'E', 'vcol': 0, 'text': 'a'}, + \ {'lnum': 1, 'bufnr': bufnr(''), 'col': 7, 'linter_name': 'foobar', 'nr': -1, 'type': 'E', 'vcol': 0, 'text': 'a'}, + \ {'lnum': 1, 'bufnr': bufnr(''), 'col': 7, 'end_col': 13, 'linter_name': 'foobar', 'nr': -1, 'type': 'E', 'vcol': 0, 'text': 'a'}, + \ {'lnum': 1, 'bufnr': bufnr(''), 'col': 7, 'end_col': 13, 'end_lnum': 1, 'linter_name': 'foobar', 'nr': -1, 'type': 'E', 'vcol': 0, 'text': 'a'}, + \ {'lnum': 1, 'bufnr': bufnr(''), 'col': 7, 'end_col': 17, 'end_lnum': 2, 'linter_name': 'foobar', 'nr': -1, 'type': 'E', 'vcol': 0, 'text': 'a'}, + \ {'lnum': 2, 'bufnr': bufnr(''), 'col': 17, 'linter_name': 'foobar', 'nr': -1, 'type': 'E', 'vcol': 0, 'text': 'a'}, + \], + \ ale#engine#FixLocList( + \ bufnr('%'), + \ 'foobar', + \ [ + \ {'text': 'a', 'lnum': 1, 'col': 0, 'vcol': 1}, + \ {'text': 'a', 'lnum': 1, 'col': 1, 'vcol': 1}, + \ {'text': 'a', 'lnum': 1, 'col': 2, 'vcol': 1}, + \ {'text': 'a', 'lnum': 1, 'col': 3, 'vcol': 1}, + \ {'text': 'a', 'lnum': 1, 'col': 3, 'end_col': 5, 'vcol': 1}, + \ {'text': 'a', 'lnum': 1, 'col': 3, 'end_col': 5, 'end_lnum': 1, 'vcol': 1}, + \ {'text': 'a', 'lnum': 1, 'col': 3, 'end_col': 7, 'end_lnum': 2, 'vcol': 1}, + \ {'text': 'a', 'lnum': 2, 'col': 7, 'vcol': 1}, + \ ], + \ ) diff --git a/test/test_loclist_jumping.vader b/test/test_loclist_jumping.vader index 5e18499e..da9a1f57 100644 --- a/test/test_loclist_jumping.vader +++ b/test/test_loclist_jumping.vader @@ -2,15 +2,15 @@ Before: let g:ale_buffer_info = { \ bufnr(''): { \ 'loclist': [ - \ {'bufnr': bufnr('') - 1, 'lnum': 3, 'col': 2}, - \ {'bufnr': bufnr(''), 'lnum': 1, 'col': 2}, - \ {'bufnr': bufnr(''), 'lnum': 1, 'col': 3}, - \ {'bufnr': bufnr(''), 'lnum': 2, 'col': 1}, - \ {'bufnr': bufnr(''), 'lnum': 2, 'col': 2}, - \ {'bufnr': bufnr(''), 'lnum': 2, 'col': 3}, - \ {'bufnr': bufnr(''), 'lnum': 2, 'col': 6}, - \ {'bufnr': bufnr(''), 'lnum': 2, 'col': 700}, - \ {'bufnr': bufnr('') + 1, 'lnum': 3, 'col': 2}, + \ {'type': 'E', 'bufnr': bufnr('') - 1, 'lnum': 3, 'col': 2}, + \ {'type': 'E', 'bufnr': bufnr(''), 'lnum': 1, 'col': 2}, + \ {'type': 'E', 'bufnr': bufnr(''), 'lnum': 1, 'col': 3}, + \ {'type': 'E', 'bufnr': bufnr(''), 'lnum': 2, 'col': 1}, + \ {'type': 'E', 'bufnr': bufnr(''), 'lnum': 2, 'col': 2}, + \ {'type': 'E', 'bufnr': bufnr(''), 'lnum': 2, 'col': 3}, + \ {'type': 'E', 'bufnr': bufnr(''), 'lnum': 2, 'col': 6}, + \ {'type': 'E', 'bufnr': bufnr(''), 'lnum': 2, 'col': 700}, + \ {'type': 'E', 'bufnr': bufnr('') + 1, 'lnum': 3, 'col': 2}, \ ], \ }, \} @@ -81,7 +81,7 @@ Execute(We should be able to jump when the error line is blank): " Add a blank line at the end. call setline(1, getline('.', '$') + ['']) " Add a problem on the blank line. - call add(g:ale_buffer_info[bufnr('%')].loclist, {'bufnr': bufnr(''), 'lnum': 3, 'col': 1}) + call add(g:ale_buffer_info[bufnr('%')].loclist, {'type': 'E', 'bufnr': bufnr(''), 'lnum': 3, 'col': 1}) AssertEqual 0, len(getline(3)) AssertEqual [2, 8], TestJump('before', 0, [3, 1]) diff --git a/test/test_loclist_sorting.vader b/test/test_loclist_sorting.vader index 157b2a25..376e743a 100644 --- a/test/test_loclist_sorting.vader +++ b/test/test_loclist_sorting.vader @@ -25,3 +25,19 @@ Execute(loclist item should be sorted): \ {'bufnr': 2, 'lnum': 1, 'col': 2}, \ {'bufnr': -1, 'filename': 'c', 'lnum': 3, 'col': 2}, \], 'ale#util#LocItemCompare') + +Execute(Items should be sorted in by their problem priority when they lie on the same column): + AssertEqual [ + \ {'bufnr': 1, 'lnum': 1, 'col': 1, 'type': 'W', 'sub_type': 'style'}, + \ {'bufnr': 1, 'lnum': 1, 'col': 1, 'type': 'E', 'sub_type': 'style'}, + \ {'bufnr': 1, 'lnum': 1, 'col': 1, 'type': 'I'}, + \ {'bufnr': 1, 'lnum': 1, 'col': 1, 'type': 'W'}, + \ {'bufnr': 1, 'lnum': 1, 'col': 1, 'type': 'E'}, + \ ], + \ sort([ + \ {'bufnr': 1, 'lnum': 1, 'col': 1, 'type': 'E'}, + \ {'bufnr': 1, 'lnum': 1, 'col': 1, 'type': 'I'}, + \ {'bufnr': 1, 'lnum': 1, 'col': 1, 'type': 'W'}, + \ {'bufnr': 1, 'lnum': 1, 'col': 1, 'type': 'E', 'sub_type': 'style'}, + \ {'bufnr': 1, 'lnum': 1, 'col': 1, 'type': 'W', 'sub_type': 'style'}, + \], 'ale#util#LocItemCompare') diff --git a/test/test_pattern_options.vader b/test/test_pattern_options.vader index 0e26eaaa..f439afbd 100644 --- a/test/test_pattern_options.vader +++ b/test/test_pattern_options.vader @@ -90,3 +90,14 @@ Execute(Patterns should be applied after the Dictionary changes): call ale#pattern_options#SetOptions(bufnr('')) AssertEqual 666, b:some_option + +Execute(SetOptions should tolerate settings being unset): + " This might happen if ALE is loaded in a weird way, so tolerate it. + unlet! g:ale_pattern_options + unlet! g:ale_pattern_options_enabled + + call ale#pattern_options#SetOptions(bufnr('')) + + let g:ale_pattern_options_enabled = 1 + + call ale#pattern_options#SetOptions(bufnr('')) diff --git a/test/test_prepare_command.vader b/test/test_prepare_command.vader index ed9272ab..75e4c0c6 100644 --- a/test/test_prepare_command.vader +++ b/test/test_prepare_command.vader @@ -22,6 +22,23 @@ Execute(sh should be used when the shell is fish): AssertEqual ['/bin/sh', '-c', 'foobar'], ale#job#PrepareCommand(bufnr(''), 'foobar') endif +Execute(sh should be used when the shell is powershell): + if !has('win32') + " Set something else, so we will replace that too. + let &shellcmdflag = '-f' + let &shell = 'pwsh' + + AssertEqual ['/bin/sh', '-c', 'foobar'], ale#job#PrepareCommand(bufnr(''), 'foobar') + + let &shell = '/usr/bin/pwsh' + + AssertEqual ['/bin/sh', '-c', 'foobar'], ale#job#PrepareCommand(bufnr(''), 'foobar') + + let &shell = '/usr/local/bin/pwsh' + + AssertEqual ['/bin/sh', '-c', 'foobar'], ale#job#PrepareCommand(bufnr(''), 'foobar') + endif + Execute(Other shells should be used when set): if !has('win32') let &shell = '/bin/bash' diff --git a/test/test_quickfix_deduplication.vader b/test/test_quickfix_deduplication.vader index 0dff3f2e..9cb8b931 100644 --- a/test/test_quickfix_deduplication.vader +++ b/test/test_quickfix_deduplication.vader @@ -9,42 +9,42 @@ Execute: " Equal problems should be de-duplicated. let g:ale_buffer_info = { \ '1': {'loclist': [ - \ {'bufnr': 2, 'lnum': 1, 'col': 2, 'text': 'foo'}, - \ {'bufnr': 2, 'lnum': 1, 'col': 5, 'text': 'bar'}, - \ {'bufnr': -1, 'filename': 'c', 'lnum': 3, 'col': 2, 'text': 'x'}, - \ {'bufnr': 1, 'lnum': 5, 'col': 4, 'text': 'x'}, - \ {'bufnr': 2, 'lnum': 5, 'col': 5, 'text': 'foo'}, - \ {'bufnr': 1, 'lnum': 2, 'col': 10, 'text': 'x'}, - \ {'bufnr': 1, 'lnum': 3, 'col': 2, 'text': 'x'}, - \ {'bufnr': 1, 'lnum': 5, 'col': 5, 'text': 'x'}, - \ {'bufnr': -1, 'filename': 'b', 'lnum': 4, 'col': 2, 'text': 'x'}, - \ {'bufnr': -1, 'filename': 'b', 'lnum': 5, 'col': 2, 'text': 'x'}, - \ {'bufnr': 3, 'lnum': 1, 'col': 1, 'text': 'foo'}, + \ {'type': 'E', 'bufnr': 2, 'lnum': 1, 'col': 2, 'text': 'foo'}, + \ {'type': 'E', 'bufnr': 2, 'lnum': 1, 'col': 5, 'text': 'bar'}, + \ {'type': 'E', 'bufnr': -1, 'filename': 'c', 'lnum': 3, 'col': 2, 'text': 'x'}, + \ {'type': 'E', 'bufnr': 1, 'lnum': 5, 'col': 4, 'text': 'x'}, + \ {'type': 'E', 'bufnr': 2, 'lnum': 5, 'col': 5, 'text': 'foo'}, + \ {'type': 'E', 'bufnr': 1, 'lnum': 2, 'col': 10, 'text': 'x'}, + \ {'type': 'E', 'bufnr': 1, 'lnum': 3, 'col': 2, 'text': 'x'}, + \ {'type': 'E', 'bufnr': 1, 'lnum': 5, 'col': 5, 'text': 'x'}, + \ {'type': 'E', 'bufnr': -1, 'filename': 'b', 'lnum': 4, 'col': 2, 'text': 'x'}, + \ {'type': 'E', 'bufnr': -1, 'filename': 'b', 'lnum': 5, 'col': 2, 'text': 'x'}, + \ {'type': 'E', 'bufnr': 3, 'lnum': 1, 'col': 1, 'text': 'foo'}, \ ]}, \ '2': {'loclist': [ - \ {'bufnr': 1, 'lnum': 2, 'col': 10, 'text': 'x'}, - \ {'bufnr': 1, 'lnum': 5, 'col': 5, 'text': 'x'}, - \ {'bufnr': 2, 'lnum': 1, 'col': 2, 'text': 'foo'}, - \ {'bufnr': 1, 'lnum': 3, 'col': 2, 'text': 'x'}, - \ {'bufnr': 1, 'lnum': 5, 'col': 4, 'text': 'x'}, - \ {'bufnr': 2, 'lnum': 1, 'col': 5, 'text': 'bar'}, - \ {'bufnr': 2, 'lnum': 5, 'col': 5, 'text': 'another error'}, + \ {'type': 'E', 'bufnr': 1, 'lnum': 2, 'col': 10, 'text': 'x'}, + \ {'type': 'E', 'bufnr': 1, 'lnum': 5, 'col': 5, 'text': 'x'}, + \ {'type': 'E', 'bufnr': 2, 'lnum': 1, 'col': 2, 'text': 'foo'}, + \ {'type': 'E', 'bufnr': 1, 'lnum': 3, 'col': 2, 'text': 'x'}, + \ {'type': 'E', 'bufnr': 1, 'lnum': 5, 'col': 4, 'text': 'x'}, + \ {'type': 'E', 'bufnr': 2, 'lnum': 1, 'col': 5, 'text': 'bar'}, + \ {'type': 'E', 'bufnr': 2, 'lnum': 5, 'col': 5, 'text': 'another error'}, \ ]}, \} AssertEqual \ [ - \ {'bufnr': -1, 'filename': 'b', 'lnum': 4, 'col': 2, 'text': 'x'}, - \ {'bufnr': -1, 'filename': 'b', 'lnum': 5, 'col': 2, 'text': 'x'}, - \ {'bufnr': -1, 'filename': 'c', 'lnum': 3, 'col': 2, 'text': 'x'}, - \ {'bufnr': 1, 'lnum': 2, 'col': 10, 'text': 'x'}, - \ {'bufnr': 1, 'lnum': 3, 'col': 2, 'text': 'x'}, - \ {'bufnr': 1, 'lnum': 5, 'col': 4, 'text': 'x'}, - \ {'bufnr': 1, 'lnum': 5, 'col': 5, 'text': 'x'}, - \ {'bufnr': 2, 'lnum': 1, 'col': 2, 'text': 'foo'}, - \ {'bufnr': 2, 'lnum': 1, 'col': 5, 'text': 'bar'}, - \ {'bufnr': 2, 'lnum': 5, 'col': 5, 'text': 'another error'}, - \ {'bufnr': 2, 'lnum': 5, 'col': 5, 'text': 'foo'}, - \ {'bufnr': 3, 'lnum': 1, 'col': 1, 'text': 'foo'}, + \ {'type': 'E', 'bufnr': -1, 'filename': 'b', 'lnum': 4, 'col': 2, 'text': 'x'}, + \ {'type': 'E', 'bufnr': -1, 'filename': 'b', 'lnum': 5, 'col': 2, 'text': 'x'}, + \ {'type': 'E', 'bufnr': -1, 'filename': 'c', 'lnum': 3, 'col': 2, 'text': 'x'}, + \ {'type': 'E', 'bufnr': 1, 'lnum': 2, 'col': 10, 'text': 'x'}, + \ {'type': 'E', 'bufnr': 1, 'lnum': 3, 'col': 2, 'text': 'x'}, + \ {'type': 'E', 'bufnr': 1, 'lnum': 5, 'col': 4, 'text': 'x'}, + \ {'type': 'E', 'bufnr': 1, 'lnum': 5, 'col': 5, 'text': 'x'}, + \ {'type': 'E', 'bufnr': 2, 'lnum': 1, 'col': 2, 'text': 'foo'}, + \ {'type': 'E', 'bufnr': 2, 'lnum': 1, 'col': 5, 'text': 'bar'}, + \ {'type': 'E', 'bufnr': 2, 'lnum': 5, 'col': 5, 'text': 'another error'}, + \ {'type': 'E', 'bufnr': 2, 'lnum': 5, 'col': 5, 'text': 'foo'}, + \ {'type': 'E', 'bufnr': 3, 'lnum': 1, 'col': 1, 'text': 'foo'}, \ ], \ ale#list#GetCombinedList() diff --git a/test/test_quitting_variable.vader b/test/test_quitting_variable.vader index bef344a8..38b43bb4 100644 --- a/test/test_quitting_variable.vader +++ b/test/test_quitting_variable.vader @@ -11,12 +11,12 @@ After: unlet! b:time_before Execute(QuitEvent should set b:ale_quitting some time from the clock): - let b:time_before = ale#util#ClockMilliseconds() + let b:time_before = ale#events#ClockMilliseconds() call ale#events#QuitEvent(bufnr('')) Assert b:ale_quitting >= b:time_before - Assert b:ale_quitting <= ale#util#ClockMilliseconds() + Assert b:ale_quitting <= ale#events#ClockMilliseconds() Execute(EnterEvent should set b:ale_quitting to 0): let b:ale_quitting = 1 @@ -29,11 +29,11 @@ Execute(The QuitRecently function should work when the variable isn't set): AssertEqual 0, ale#events#QuitRecently(bufnr('')) Execute(The QuitRecently function should return 1 when ALE quit recently): - let b:ale_quitting = ale#util#ClockMilliseconds() + let b:ale_quitting = ale#events#ClockMilliseconds() AssertEqual 1, ale#events#QuitRecently(bufnr('')) Execute(The QuitRecently function should return 0 when a second has passed): - let b:ale_quitting = ale#util#ClockMilliseconds() - 1001 + let b:ale_quitting = ale#events#ClockMilliseconds() - 1001 AssertEqual 0, ale#events#QuitRecently(bufnr('')) diff --git a/test/test_should_do_nothing_conditions.vader b/test/test_should_do_nothing_conditions.vader index 23ebd92e..062ab875 100644 --- a/test/test_should_do_nothing_conditions.vader +++ b/test/test_should_do_nothing_conditions.vader @@ -1,4 +1,7 @@ Before: + Save g:ale_filetype_blacklist + Save g:ale_maximum_file_size + Save g:ale_enabled Save &l:statusline call ale#test#SetDirectory('/testplugin/test') @@ -12,6 +15,8 @@ Before: endif After: + Restore + call ale#test#RestoreDirectory() if b:funky_command_created @@ -21,8 +26,7 @@ After: unlet! b:funky_command_created - Restore - +Given foobar(An empty file): Execute(ALE shouldn't do much of anything for ctrlp-funky buffers): Assert !ale#ShouldDoNothing(bufnr('')), 'The preliminary check failed' @@ -39,3 +43,21 @@ Execute(ALE shouldn't try to check buffers with '.' as the filename): silent! noautocmd file . Assert ale#ShouldDoNothing(bufnr('')) + +Execute(DoNothing should return 0 when the filetype is empty): + AssertEqual + \ 0, + \ ale#ShouldDoNothing(bufnr('')), + \ 'ShouldDoNothing() was 1 for some other reason' + + set filetype= + + AssertEqual 1, ale#ShouldDoNothing(bufnr('')) + +Execute(The DoNothing check should work if the ALE globals aren't defined): + unlet! g:ale_filetype_blacklist + unlet! g:ale_maximum_file_size + unlet! g:ale_enabled + + " This shouldn't throw exceptions. + call ale#ShouldDoNothing(bufnr('')) diff --git a/test/test_temporary_file_management.vader b/test/test_temporary_file_management.vader index ae2bf251..e248331c 100644 --- a/test/test_temporary_file_management.vader +++ b/test/test_temporary_file_management.vader @@ -1,4 +1,7 @@ Before: + Save g:ale_buffer_info + + let g:ale_buffer_info = {} let g:ale_run_synchronously = 1 let g:command = 'echo test' @@ -41,6 +44,8 @@ Before: \}) After: + Restore + if !empty(g:preserved_directory) call delete(g:preserved_directory, 'rf') endif @@ -111,3 +116,17 @@ Execute(ALE should create and delete directories for ale#engine#CreateDirectory( Assert !isdirectory(b:dir), 'The directory was not deleted' Assert !isdirectory(b:dir2), 'The second directory was not deleted' + +Execute(ale#engine#ManageFile should add the file even if the buffer info hasn't be set yet): + let g:ale_buffer_info = {} + call ale#engine#ManageFile(bufnr(''), '/foo/bar') + AssertEqual + \ ['/foo/bar'], + \ g:ale_buffer_info[bufnr('')].temporary_file_list + +Execute(ale#engine#ManageDirectory should add the directory even if the buffer info hasn't be set yet): + let g:ale_buffer_info = {} + call ale#engine#ManageDirectory(bufnr(''), '/foo/bar') + AssertEqual + \ ['/foo/bar'], + \ g:ale_buffer_info[bufnr('')].temporary_directory_list diff --git a/test/test_verilog_verilator_options.vader b/test/test_verilog_verilator_options.vader index 561786ee..e53037b1 100644 --- a/test/test_verilog_verilator_options.vader +++ b/test/test_verilog_verilator_options.vader @@ -22,4 +22,3 @@ Execute(Set Verilog Verilator linter additional options to `-sv --default-langua \ g:matched , \ -1 , \ 'Additionnal arguments not found in the run command' - |