diff --git a/README.md b/README.md index b6edf67..f98dc22 100644 --- a/README.md +++ b/README.md @@ -16,14 +16,13 @@ the miscellaneous scripts, but I don't see any way around this. Sorry! ## Installation -Unzip the most recent [ZIP archive] [download] file inside your Vim profile +Unzip the most recent [ZIP archive] [] file inside your Vim profile directory (usually this is `~/.vim` on UNIX and `%USERPROFILE%\vimfiles` on Windows), restart Vim and execute the command `:helptags ~/.vim/doc` (use `:helptags ~\vimfiles\doc` instead on Windows). -If you prefer you can also use [Pathogen] [pathogen], [Vundle] [vundle] or a -similar tool to install & update the plug-in using a local clone of the git -repository. +If you prefer you can also use [Pathogen] [], [Vundle] [] or a similar tool to +install & update the plug-in using a local clone of the git repository. ## Function documentation @@ -33,13 +32,13 @@ plug-ins. I care about backwards compatibility so won't break it without a good reason to do so. For those who are curious: The function descriptions given below were extracted -from the source code of the miscellaneous scripts using a bit of Python code -that I haven't published yet. +from the source code of the miscellaneous scripts using the Python module +`vimdoctool.py` included in [vim-tools] []. -The documentation of the 44 functions below was extracted from -14 Vim scripts on June 2, 2013 at 21:27. +The documentation of the 66 functions below was extracted from +15 Vim scripts on June 2, 2013 at 22:18. ### Handling of special buffers @@ -421,11 +420,139 @@ Compact whitespace in the string given as the first argument. Trim all whitespace from the start and end of the string given as the first argument. -### Tests for my miscellaneous Vim scripts +### Test runner & infrastructure for Vim plug-ins -#### The `xolox#misc#tests#run_all()` function +The Vim auto-load script `autoload/xolox/misc/test.vim` contains +infrastructure that can be used to run an automated Vim plug-in test suite. +It provides a framework for running test functions, keeping track of the +test status, making assertions and reporting test results to the user. -Run the automated tests of the miscellaneous functions. +#### The `xolox#misc#test#reset()` function + +Reset counters for executed tests and passed/failed assertions. + +#### The `xolox#misc#test#summarize()` function + +Print a summary of test results, to be interpreted interactively. + +#### The `xolox#misc#test#wrap()` function + +Call a function in a try/catch block and prevent exceptions from bubbling. +The name of the function should be passed as the first and only argument; +it should be a string containing the name of a Vim auto-load function. + +#### The `xolox#misc#test#passed()` function + +Record a test which succeeded. + +#### The `xolox#misc#test#failed()` function + +Record a test which failed. + +#### The `xolox#misc#test#assert_true()` function + +Check whether an expression is true. + +#### The `xolox#misc#test#assert_equals()` function + +Check whether two values are the same. + +#### The `xolox#misc#test#assert_same_type()` function + +Check whether two values are of the same type. + +### Tests for the miscellaneous Vim scripts + +The Vim auto-load script `autoload/xolox/misc/tests.vim` contains the +automated test suite of the miscellaneous Vim scripts. Right now the +coverage is not very high yet, but this will improve over time. + +#### The `xolox#misc#tests#run()` function + +Run the automated test suite of the miscellaneous Vim scripts. To be used +interactively. Intended to be safe to execute irrespective of context. + +#### The `xolox#misc#tests#pattern_escaping()` function + +Test escaping of regular expression patterns with +`xolox#misc#escape#pattern()`. + +#### The `xolox#misc#tests#substitute_escaping()` function + +Test escaping of substitution strings with +`xolox#misc#escape#substitute()`. + +#### The `xolox#misc#tests#shell_escaping()` function + +Test escaping of shell arguments with `xolox#misc#escape#shell()`. + +#### The `xolox#misc#tests#making_a_list_unique()` function + +Test removing of duplicate values from lists with +`xolox#misc#list#unique()`. + +#### The `xolox#misc#tests#binary_insertion()` function + +Test the binary insertion algorithm implemented in +`xolox#misc#list#binsert()`. + +#### The `xolox#misc#tests#getting_configuration_options()` function + +Test getting of scoped plug-in configuration "options" with +`xolox#misc#option#get()`. + +#### The `xolox#misc#tests#splitting_of_multi_valued_options()` function + +Test splitting of multi-valued Vim options with +`xolox#misc#option#split()`. + +#### The `xolox#misc#tests#joining_of_multi_valued_options()` function + +Test joining of multi-valued Vim options with `xolox#misc#option#join()`. + +#### The `xolox#misc#tests#evaluation_of_tags_option()` function + +Test evaluation of Vim's ['tags'] [] option. We don't test `~/.tags` style +patterns because `xolox#misc#option#eval_tags()` doesn't support those. +Depending on your perspective this is not a bug, because the ['tags'] [] +option gets special treatment in Vim anyway: + + :set tags=~/.tags + tags=~/.tags + :echo &tags + /home/peter/.tags + +So at the point where `xolox#misc#option#eval_tags()` receives the value +of ['tags'] [], it has already been expanded by Vim. + +['tags']: http://vimdoc.sourceforge.net/htmldoc/options.html#'tags' + +#### The `xolox#misc#tests#finding_vim_on_the_search_path()` function + +Test looking up Vim's executable on the search path using [v:progname] [] +with `xolox#misc#os#find_vim()`. + +[v:progname]: http://vimdoc.sourceforge.net/htmldoc/eval.html#v:progname + +#### The `xolox#misc#tests#synchronous_command_execution()` function + +Test basic functionality of synchronous command execution with +`xolox#misc#os#exec()`. + +#### The `xolox#misc#tests#synchronous_command_execution_with_raising_of_errors()` function + +Test raising of errors during synchronous command execution with +`xolox#misc#os#exec()`. + +#### The `xolox#misc#tests#synchronous_command_execution_without_raising_errors()` function + +Test synchronous command execution without raising of errors with +`xolox#misc#os#exec()`. + +#### The `xolox#misc#tests#asynchronous_command_execution()` function + +Test basic functionality of asynchronous command execution with +`xolox#misc#os#exec()`. ### Timing of long during operations @@ -462,18 +589,19 @@ you pass the list returned by `xolox#misc#timer#start()` as an argument. If you have questions, bug reports, suggestions, etc. the author can be contacted at . The latest version is available at and . -If you like the script please vote for it on [Vim Online] [vim-online]. +If you like the script please vote for it on [Vim Online] []. ## License -This software is licensed under the [MIT license] [mit]. +This software is licensed under the [MIT license] []. © 2013 Peter Odding <>. -[download]: http://peterodding.com/code/vim/downloads/misc.zip -[mit]: http://en.wikipedia.org/wiki/MIT_License -[pathogen]: http://www.vim.org/scripts/script.php?script_id=2332 +[MIT license]: http://en.wikipedia.org/wiki/MIT_License +[Pathogen]: http://www.vim.org/scripts/script.php?script_id=2332 [plugins]: http://peterodding.com/code/vim/ [repository]: https://github.com/xolox/vim-misc -[vim-online]: http://www.vim.org/scripts/script.php?script_id=4597 -[vundle]: https://github.com/gmarik/vundle +[Vim Online]: http://www.vim.org/scripts/script.php?script_id=4597 +[vim-tools]: http://peterodding.com/code/vim/tools/ +[Vundle]: https://github.com/gmarik/vundle +[ZIP archive]: http://peterodding.com/code/vim/downloads/misc.zip diff --git a/autoload/xolox/misc.vim b/autoload/xolox/misc.vim index 1c6656d..37694a9 100644 --- a/autoload/xolox/misc.vim +++ b/autoload/xolox/misc.vim @@ -4,4 +4,4 @@ " Last Change: June 2, 2013 " URL: http://peterodding.com/code/vim/misc/ -let g:xolox#misc#version = '1.3' +let g:xolox#misc#version = '1.4' diff --git a/autoload/xolox/misc/test.vim b/autoload/xolox/misc/test.vim new file mode 100644 index 0000000..df4d465 --- /dev/null +++ b/autoload/xolox/misc/test.vim @@ -0,0 +1,125 @@ +" Test runner & infrastructure for Vim plug-ins. +" +" Author: Peter Odding +" Last Change: June 2, 2013 +" URL: http://peterodding.com/code/vim/misc/ +" +" The Vim auto-load script `autoload/xolox/misc/test.vim` contains +" infrastructure that can be used to run an automated Vim plug-in test suite. +" It provides a framework for running test functions, keeping track of the +" test status, making assertions and reporting test results to the user. + +" The process handling tests cannot use the built-in "echo" command from the +" Windows shell because it has way too much idiosyncrasies for me to put up +" with. Seriously. Instead I'm using an "echo.exe" from the UnxUtils project. +if xolox#misc#os#is_win() + let g:xolox#misc#test#echo = xolox#misc#escape#shell(xolox#misc#path#merge(expand(':p:h'), 'echo.exe')) +else + let g:xolox#misc#test#echo = 'echo' +endif + +function! xolox#misc#test#reset() " {{{1 + " Reset counters for executed tests and passed/failed assertions. + let s:num_executed = 0 + let s:num_passed = 0 + let s:num_failed = 0 + let s:tests_started_at = xolox#misc#timer#start() +endfunction + +function! xolox#misc#test#summarize() " {{{1 + " Print a summary of test results, to be interpreted interactively. + call s:delimit_output() + call xolox#misc#timer#force("Took %s to run %s: %s passed, %s failed.", + \ s:tests_started_at, + \ xolox#misc#format#pluralize(s:num_executed, 'test', 'tests'), + \ xolox#misc#format#pluralize(s:num_passed, 'assertion', 'assertions'), + \ xolox#misc#format#pluralize(s:num_failed, 'assertion', 'assertions')) +endfunction + +function! xolox#misc#test#wrap(function) " {{{1 + " Call a function in a try/catch block and prevent exceptions from bubbling. + " The name of the function should be passed as the first and only argument; + " it should be a string containing the name of a Vim auto-load function. + let num_failed = s:num_failed + try + if s:num_passed + s:num_failed > 0 + call s:delimit_output() + endif + let test_name = split(a:function, '#')[-1] + let test_name = substitute(test_name, '_', ' ', 'g') + let test_name = substitute(test_name, '^.', '\U\0', '') + call xolox#misc#msg#info("Running test #%i: %s", s:num_executed + 1, test_name) + call call(a:function, []) + catch + call xolox#misc#msg#warn("Test %s raised exception:", a:function) + call xolox#misc#msg#warn("%s", v:exception) + call xolox#misc#msg#warn("(at %s)", v:throwpoint) + if num_failed == s:num_failed + " Make sure exceptions are counted as failures, but don't inflate the + " number of failed assertions when it's not needed (it can produce + " confusing test output). + call xolox#misc#test#failed() + endif + endtry + let s:num_executed += 1 +endfunction + +function! xolox#misc#test#passed() " {{{1 + " Record a test which succeeded. + let s:num_passed += 1 + call s:print_feedback() +endfunction + +function! xolox#misc#test#failed() " {{{1 + " Record a test which failed. + let s:num_failed += 1 + call s:print_feedback() +endfunction + +function! s:delimit_output() " {{{1 + " Print a delimiter between output of tests. + call xolox#misc#msg#info("%s", repeat("-", 40)) +endfunction + +function! s:print_feedback() " {{{1 + " Let the user know the status of the test suite. + call xolox#misc#msg#info("Test status: %s passed, %s failed ..", + \ xolox#misc#format#pluralize(s:num_passed, 'assertion', 'assertions'), + \ xolox#misc#format#pluralize(s:num_failed, 'assertion', 'assertions')) +endfunction + +function! xolox#misc#test#assert_true(expr) " {{{1 + " Check whether an expression is true. + if a:expr + call xolox#misc#test#passed() + else + call xolox#misc#test#failed() + let msg = "Expected value to be true, got %s instead" + throw printf(msg, string(a:expr)) + endif +endfunction + +function! xolox#misc#test#assert_equals(expected, received) " {{{1 + " Check whether two values are the same. + call xolox#misc#test#assert_same_type(a:expected, a:received) + if a:expected == a:received + call xolox#misc#test#passed() + else + call xolox#misc#test#failed() + let msg = "Expected value %s, received value %s!" + throw printf(msg, string(a:expected), string(a:received)) + endif +endfunction + +function! xolox#misc#test#assert_same_type(expected, received) " {{{1 + " Check whether two values are of the same type. + if type(a:expected) == type(a:received) + call xolox#misc#test#passed() + else + call xolox#misc#test#failed() + let msg = "Expected value of same type as %s, got value %s!" + throw printf(msg, string(a:expected), string(a:received)) + endif +endfunction + +call xolox#misc#test#reset() diff --git a/autoload/xolox/misc/tests.vim b/autoload/xolox/misc/tests.vim index 014af1c..1854d1d 100644 --- a/autoload/xolox/misc/tests.vim +++ b/autoload/xolox/misc/tests.vim @@ -1,286 +1,230 @@ -" Tests for my miscellaneous Vim scripts. +" Tests for the miscellaneous Vim scripts. " " Author: Peter Odding " Last Change: June 2, 2013 " URL: http://peterodding.com/code/vim/misc/ - -" The process handling tests cannot use the built-in "echo" command from the -" Windows shell because it has way too much idiosyncrasies for me to put up -" with. Seriously. Instead I'm using an "echo.exe" from the UnxUtils project. -if xolox#misc#os#is_win() - let s:echo = xolox#misc#escape#shell(xolox#misc#path#merge(expand(':p:h'), 'echo.exe')) -else - let s:echo = 'echo' -endif - -" Tests for the miscellaneous scripts. {{{1 - -function! xolox#misc#tests#run_all() " {{{2 - " Run the automated tests of the miscellaneous functions. - let starttime = xolox#misc#timer#start() - " Start from a clean slate. - call s:test_reset() +" +" The Vim auto-load script `autoload/xolox/misc/tests.vim` contains the +" automated test suite of the miscellaneous Vim scripts. Right now the +" coverage is not very high yet, but this will improve over time. + +function! xolox#misc#tests#run() " {{{1 + " Run the automated test suite of the miscellaneous Vim scripts. To be used + " interactively. Intended to be safe to execute irrespective of context. + call xolox#misc#test#reset() " Run the tests. call s:test_string_escaping() - call s:test_command_execution() call s:test_list_handling() call s:test_option_handling() + call s:test_command_execution() " Report a short summary to the user. - call xolox#misc#timer#force("Took %s to run %i tests: %i passed, %i failed.", starttime, s:num_passed + s:num_failed, s:num_passed, s:num_failed) + call xolox#misc#test#summarize() endfunction -" Tests for autoload/xolox/misc/escape.vim {{{2 +" Tests for autoload/xolox/misc/escape.vim {{{1 function! s:test_string_escaping() - call s:test_wrap('s:test_pattern_escaping') - call s:test_wrap('s:test_substitute_escaping') - call s:test_wrap('s:test_shell_escaping') + call xolox#misc#test#wrap('xolox#misc#tests#pattern_escaping') + call xolox#misc#test#wrap('xolox#misc#tests#substitute_escaping') + call xolox#misc#test#wrap('xolox#misc#tests#shell_escaping') endfunction -function! s:test_pattern_escaping() " {{{3 - " Test escaping of regular expression patterns. - call s:assert_equals('foo [qux] baz', substitute('foo [bar] baz', xolox#misc#escape#pattern('[bar]'), '[qux]', 'g')) - call s:assert_equals('also very nasty', substitute('also ~ nasty', xolox#misc#escape#pattern('~'), 'very', 'g')) +function! xolox#misc#tests#pattern_escaping() " {{{2 + " Test escaping of regular expression patterns with + " `xolox#misc#escape#pattern()`. + call xolox#misc#test#assert_equals('foo [qux] baz', substitute('foo [bar] baz', xolox#misc#escape#pattern('[bar]'), '[qux]', 'g')) + call xolox#misc#test#assert_equals('also very nasty', substitute('also ~ nasty', xolox#misc#escape#pattern('~'), 'very', 'g')) endfunction -function! s:test_substitute_escaping() " {{{3 - " Test escaping of substitution strings. - call s:assert_equals('nasty & tricky stuff', substitute('tricky stuff', 'tricky', xolox#misc#escape#substitute('nasty & tricky'), 'g')) +function! xolox#misc#tests#substitute_escaping() " {{{2 + " Test escaping of substitution strings with + " `xolox#misc#escape#substitute()`. + call xolox#misc#test#assert_equals('nasty & tricky stuff', substitute('tricky stuff', 'tricky', xolox#misc#escape#substitute('nasty & tricky'), 'g')) endfunction -function! s:test_shell_escaping() " {{{3 - " Test escaping of shell arguments. +function! xolox#misc#tests#shell_escaping() " {{{2 + " Test escaping of shell arguments with `xolox#misc#escape#shell()`. let expected_value = 'this < is > a | very " scary ^ string '' indeed' - let result = xolox#misc#os#exec({'command': s:echo . ' ' . xolox#misc#escape#shell(expected_value)}) - call s:assert_equals(0, result['exit_code']) - call s:assert_equals([expected_value], result['stdout']) -endfunction - -" Tests for autoload/xolox/misc/os.vim {{{2 - -function! s:test_command_execution() - call s:test_wrap('s:test_exec_synchronous') - call s:test_wrap('s:test_exec_synchronous_error_with_raise') - call s:test_wrap('s:test_exec_synchronous_error_without_raise') - call s:test_wrap('s:test_exec_asynchronous') -endfunction - -function! s:test_exec_synchronous() " {{{3 - " Test basic functionality of synchronous command execution. - let result = xolox#misc#os#exec({'command': printf('%s output && %s errors >&2', s:echo, s:echo)}) - call s:assert_type({}, result) - call s:assert_equals(0, result['exit_code']) - call s:assert_equals(['output'], result['stdout']) - call s:assert_equals(['errors'], result['stderr']) -endfunction - -function! s:test_exec_synchronous_error_with_raise() " {{{3 - " Test raising of errors during synchronous command execution. - try - call xolox#misc#os#exec({'command': 'exit 1'}) - call s:assert_true(0) - catch - call s:assert_true(1) - endtry -endfunction - -function! s:test_exec_synchronous_error_without_raise() " {{{3 - " Test synchronous command execution without raising of errors. - try - let result = xolox#misc#os#exec({'command': 'exit 42', 'check': 0}) - call s:assert_true(1) - call s:assert_equals(42, result['exit_code']) - catch - call s:assert_true(0) - endtry -endfunction - -function! s:test_exec_asynchronous() " {{{3 - " Test basic functionality of asynchronous command execution. - let tempfile = tempname() - let expected_value = string(localtime()) - let command = s:echo . ' ' . xolox#misc#escape#shell(expected_value) . ' > ' . tempfile - let result = xolox#misc#os#exec({'command': command, 'async': 1}) - call s:assert_type({}, result) - " Make sure the command is really executed. - let timeout = localtime() + 30 - while !filereadable(tempfile) && localtime() < timeout - sleep 500 m - endwhile - call s:assert_true(filereadable(tempfile)) - call s:assert_equals([expected_value], readfile(tempfile)) + let result = xolox#misc#os#exec({'command': g:xolox#misc#test#echo . ' ' . xolox#misc#escape#shell(expected_value)}) + call xolox#misc#test#assert_equals(0, result['exit_code']) + call xolox#misc#test#assert_equals([expected_value], result['stdout']) endfunction -" Tests for autoload/xolox/misc/list.vim {{{2 +" Tests for autoload/xolox/misc/list.vim {{{1 function! s:test_list_handling() - call s:test_wrap('s:test_list_unique') - call s:test_wrap('s:test_list_binsert') + call xolox#misc#test#wrap('xolox#misc#tests#making_a_list_unique') + call xolox#misc#test#wrap('xolox#misc#tests#binary_insertion') endfunction -function! s:test_list_unique() " {{{3 - " Test removing of duplicate values from lists. - call s:assert_equals([1, 2, 3, 4, 5], xolox#misc#list#unique([1, 1, 2, 3, 3, 4, 5, 5])) +function! xolox#misc#tests#making_a_list_unique() " {{{2 + " Test removing of duplicate values from lists with + " `xolox#misc#list#unique()`. + call xolox#misc#test#assert_equals([1, 2, 3, 4, 5], xolox#misc#list#unique([1, 1, 2, 3, 3, 4, 5, 5])) " Should work for strings just as well. And it should preserve order. - call s:assert_equals(['a', 'b', 'c'], xolox#misc#list#unique(['a', 'a', 'b', 'b', 'c'])) + call xolox#misc#test#assert_equals(['a', 'b', 'c'], xolox#misc#list#unique(['a', 'a', 'b', 'b', 'c'])) " Just to make sure that lists without duplicate values pass through unharmed. - call s:assert_equals([1, 2, 3, 4, 5], xolox#misc#list#unique([1, 2, 3, 4, 5])) + call xolox#misc#test#assert_equals([1, 2, 3, 4, 5], xolox#misc#list#unique([1, 2, 3, 4, 5])) endfunction -function! s:test_list_binsert() " {{{3 - " Test binary insertion algorithm. +function! xolox#misc#tests#binary_insertion() " {{{2 + " Test the binary insertion algorithm implemented in + " `xolox#misc#list#binsert()`. let list = ['a', 'B', 'e'] " Insert 'c' (should end up between 'B' and 'e'). call xolox#misc#list#binsert(list, 'c', 1) - call s:assert_equals(['a', 'B', 'c', 'e'], list) + call xolox#misc#test#assert_equals(['a', 'B', 'c', 'e'], list) " Insert 'D' (should end up between 'c' and 'e'). call xolox#misc#list#binsert(list, 'D', 1) - call s:assert_equals(['a', 'B', 'c', 'D', 'e'], list) + call xolox#misc#test#assert_equals(['a', 'B', 'c', 'D', 'e'], list) " Insert 'f' (should end up after 'e', at the end). call xolox#misc#list#binsert(list, 'f', 1) - call s:assert_equals(['a', 'B', 'c', 'D', 'e', 'f'], list) + call xolox#misc#test#assert_equals(['a', 'B', 'c', 'D', 'e', 'f'], list) endfunction -" Tests for autoload/xolox/misc/option.vim {{{2 +" Tests for autoload/xolox/misc/option.vim {{{1 function! s:test_option_handling() - call s:test_wrap('s:test_option_get') - call s:test_wrap('s:test_option_split') - call s:test_wrap('s:test_option_join') - call s:test_wrap('s:test_option_eval_tags') + call xolox#misc#test#wrap('xolox#misc#tests#getting_configuration_options') + call xolox#misc#test#wrap('xolox#misc#tests#splitting_of_multi_valued_options') + call xolox#misc#test#wrap('xolox#misc#tests#joining_of_multi_valued_options') + call xolox#misc#test#wrap('xolox#misc#tests#evaluation_of_tags_option') endfunction -function! s:test_option_get() " {{{3 - " Test getting of scoped options. +function! xolox#misc#tests#getting_configuration_options() " {{{2 + " Test getting of scoped plug-in configuration "options" with + " `xolox#misc#option#get()`. let magic_name = 'a_variable_that_none_would_use' - call s:assert_equals(0, xolox#misc#option#get(magic_name)) + call xolox#misc#test#assert_equals(0, xolox#misc#option#get(magic_name)) " Test custom default values. - call s:assert_equals([], xolox#misc#option#get(magic_name, [])) + call xolox#misc#test#assert_equals([], xolox#misc#option#get(magic_name, [])) " Set the option as a global variable. let global_value = 'global variable' let g:{magic_name} = global_value - call s:assert_equals(global_value, xolox#misc#option#get(magic_name)) + call xolox#misc#test#assert_equals(global_value, xolox#misc#option#get(magic_name)) " Set the option as a buffer local variable, thereby shadowing the global. let local_value = 'buffer local variable' let b:{magic_name} = local_value - call s:assert_equals(local_value, xolox#misc#option#get(magic_name)) + call xolox#misc#test#assert_equals(local_value, xolox#misc#option#get(magic_name)) " Sanity check that it's possible to unshadow as well. unlet b:{magic_name} - call s:assert_equals(global_value, xolox#misc#option#get(magic_name)) + call xolox#misc#test#assert_equals(global_value, xolox#misc#option#get(magic_name)) " Cleanup after ourselves. unlet g:{magic_name} - call s:assert_equals(0, xolox#misc#option#get(magic_name)) + call xolox#misc#test#assert_equals(0, xolox#misc#option#get(magic_name)) endfunction -function! s:test_option_split() " {{{3 - " Tests splitting of multi-valued Vim options. - call s:assert_equals([], xolox#misc#option#split('')) - call s:assert_equals(['just one value'], xolox#misc#option#split('just one value')) - call s:assert_equals(['value 1', 'value 2'], xolox#misc#option#split('value 1,value 2')) - call s:assert_equals(['value 1', 'value 2', 'tricky,value'], xolox#misc#option#split('value 1,value 2,tricky\,value')) +function! xolox#misc#tests#splitting_of_multi_valued_options() " {{{2 + " Test splitting of multi-valued Vim options with + " `xolox#misc#option#split()`. + call xolox#misc#test#assert_equals([], xolox#misc#option#split('')) + call xolox#misc#test#assert_equals(['just one value'], xolox#misc#option#split('just one value')) + call xolox#misc#test#assert_equals(['value 1', 'value 2'], xolox#misc#option#split('value 1,value 2')) + call xolox#misc#test#assert_equals(['value 1', 'value 2', 'tricky,value'], xolox#misc#option#split('value 1,value 2,tricky\,value')) endfunction -function! s:test_option_join() " {{{3 - " Tests joining of multi-valued Vim options. - call s:assert_equals('', xolox#misc#option#join([])) - call s:assert_equals('just one value', xolox#misc#option#join(['just one value'])) - call s:assert_equals('value 1,value 2', xolox#misc#option#join(['value 1', 'value 2'])) - call s:assert_equals('value 1,value 2,tricky\,value', xolox#misc#option#join(['value 1', 'value 2', 'tricky,value'])) +function! xolox#misc#tests#joining_of_multi_valued_options() " {{{2 + " Test joining of multi-valued Vim options with `xolox#misc#option#join()`. + call xolox#misc#test#assert_equals('', xolox#misc#option#join([])) + call xolox#misc#test#assert_equals('just one value', xolox#misc#option#join(['just one value'])) + call xolox#misc#test#assert_equals('value 1,value 2', xolox#misc#option#join(['value 1', 'value 2'])) + call xolox#misc#test#assert_equals('value 1,value 2,tricky\,value', xolox#misc#option#join(['value 1', 'value 2', 'tricky,value'])) endfunction -function! s:test_option_eval_tags() " {{{3 - " Tests evaluation of Vim's &tags option. We don't test ~/.tags style - " patterns because xolox#misc#option#eval_tags() doesn't support those. - " Depending on your perspective this is not a bug, because &tags gets - " special treatment in Vim anyway: +function! xolox#misc#tests#evaluation_of_tags_option() " {{{2 + " Test evaluation of Vim's ['tags'] [] option. We don't test `~/.tags` style + " patterns because `xolox#misc#option#eval_tags()` doesn't support those. + " Depending on your perspective this is not a bug, because the ['tags'] [] + " option gets special treatment in Vim anyway: " " :set tags=~/.tags " tags=~/.tags " :echo &tags " /home/peter/.tags " - " So at the point where xolox#misc#option#eval_tags() receives the value of - " &tags, it has already been expanded by Vim. - call s:assert_equals([fnamemodify('.tags', ':p')], xolox#misc#option#eval_tags('./.tags')) - call s:assert_equals([fnamemodify('.tags', ':p'), fnamemodify('.more-tags', ':p')], xolox#misc#option#eval_tags('.tags,.more-tags')) + " So at the point where `xolox#misc#option#eval_tags()` receives the value + " of ['tags'] [], it has already been expanded by Vim. + " + " ['tags']: http://vimdoc.sourceforge.net/htmldoc/options.html#'tags' + let buffer_directory = fnamemodify(bufname('%'), ':p:h') + call xolox#misc#test#assert_equals( + \ [xolox#misc#path#merge(buffer_directory, '.tags')], + \ xolox#misc#option#eval_tags('./.tags')) + call xolox#misc#test#assert_equals( + \ [xolox#misc#path#merge(buffer_directory, '.tags'), + \ xolox#misc#path#merge(buffer_directory, '.more-tags')], + \ xolox#misc#option#eval_tags('./.tags,./.more-tags')) + call xolox#misc#test#assert_equals( + \ [xolox#misc#path#merge(buffer_directory, '.tags')], + \ xolox#misc#option#eval_tags('./.tags;')) +endfunction + +" Tests for autoload/xolox/misc/os.vim {{{1 + +function! s:test_command_execution() + call xolox#misc#test#wrap('xolox#misc#tests#finding_vim_on_the_search_path') + call xolox#misc#test#wrap('xolox#misc#tests#synchronous_command_execution') + call xolox#misc#test#wrap('xolox#misc#tests#synchronous_command_execution_with_raising_of_errors') + call xolox#misc#test#wrap('xolox#misc#tests#synchronous_command_execution_without_raising_errors') + call xolox#misc#test#wrap('xolox#misc#tests#asynchronous_command_execution') endfunction -" Testing infrastructure. {{{1 +function! xolox#misc#tests#finding_vim_on_the_search_path() " {{{2 + " Test looking up Vim's executable on the search path using [v:progname] [] + " with `xolox#misc#os#find_vim()`. + " + " [v:progname]: http://vimdoc.sourceforge.net/htmldoc/eval.html#v:progname + let pathname = xolox#misc#os#find_vim() + call xolox#misc#test#assert_same_type('', pathname) + call xolox#misc#test#assert_true(executable(pathname)) +endfunction -function! s:test_reset() " {{{2 - " Reset counters for passed/failed tests. - let s:num_passed = 0 - let s:num_failed = 0 +function! xolox#misc#tests#synchronous_command_execution() " {{{2 + " Test basic functionality of synchronous command execution with + " `xolox#misc#os#exec()`. + let result = xolox#misc#os#exec({'command': printf('%s output && %s errors >&2', g:xolox#misc#test#echo, g:xolox#misc#test#echo)}) + call xolox#misc#test#assert_same_type({}, result) + call xolox#misc#test#assert_equals(0, result['exit_code']) + call xolox#misc#test#assert_equals(['output'], result['stdout']) + call xolox#misc#test#assert_equals(['errors'], result['stderr']) endfunction -function! s:test_wrap(function) " {{{2 - " Call a function in a try/catch block and prevent exceptions from bubbling. - let num_failed = s:num_failed +function! xolox#misc#tests#synchronous_command_execution_with_raising_of_errors() " {{{2 + " Test raising of errors during synchronous command execution with + " `xolox#misc#os#exec()`. try - call xolox#misc#msg#info("Running test: %s", a:function) - call call(a:function, []) + call xolox#misc#os#exec({'command': 'exit 1'}) + call xolox#misc#test#assert_true(0) catch - call xolox#misc#msg#warn("Test %s raised exception:", a:function) - call xolox#misc#msg#warn("%s", v:exception) - call xolox#misc#msg#warn("(at %s)", v:throwpoint) - if num_failed == s:num_failed - " Make sure exceptions are counted as failures, but don't inflate the - " number of failed assertions when it's not needed (it can produce - " confusing test output). - call s:test_failed() - endif + call xolox#misc#test#assert_true(1) endtry endfunction -function! s:test_feedback() " {{{2 - " Let the user know the status of the test suite. - call xolox#misc#msg#info("Test status: %i passed, %i failed assertions ..", s:num_passed, s:num_failed) -endfunction - -function! s:test_passed() " {{{2 - " Record a test which succeeded. - let s:num_passed += 1 - call s:test_feedback() -endfunction - -function! s:test_failed() " {{{2 - " Record a test which failed. - let s:num_failed += 1 - call s:test_feedback() -endfunction - -function! s:assert_true(expr) " {{{2 - " Check whether an expression is true. - if a:expr - call s:test_passed() - return 1 - else - call s:test_failed() - let msg = "Expected value to be true, got %s instead" - throw printf(msg, string(a:expr)) - endif -endfunction - -function! s:assert_equals(expected, received) " {{{2 - " Check whether two values are the same. - if s:assert_type(a:expected, a:received) && a:expected == a:received - call s:test_passed() - return 1 - else - call s:test_failed() - let msg = "Expected value %s, received value %s!" - throw printf(msg, string(a:expected), string(a:received)) - endif +function! xolox#misc#tests#synchronous_command_execution_without_raising_errors() " {{{2 + " Test synchronous command execution without raising of errors with + " `xolox#misc#os#exec()`. + try + let result = xolox#misc#os#exec({'command': 'exit 42', 'check': 0}) + call xolox#misc#test#assert_true(1) + call xolox#misc#test#assert_equals(42, result['exit_code']) + catch + call xolox#misc#test#assert_true(0) + endtry endfunction -function! s:assert_type(expected, received) " {{{2 - " Check whether two values are of the same type. - if type(a:expected) == type(a:received) - call s:test_passed() - return 1 - else - call s:test_failed() - let msg = "Expected value of same type as %s, got value %s!" - throw printf(msg, string(a:expected), string(a:received)) - endif +function! xolox#misc#tests#asynchronous_command_execution() " {{{2 + " Test basic functionality of asynchronous command execution with + " `xolox#misc#os#exec()`. + let tempfile = tempname() + let expected_value = string(localtime()) + let command = g:xolox#misc#test#echo . ' ' . xolox#misc#escape#shell(expected_value) . ' > ' . tempfile + let result = xolox#misc#os#exec({'command': command, 'async': 1}) + call xolox#misc#test#assert_same_type({}, result) + " Make sure the command is really executed. + let timeout = localtime() + 30 + while !filereadable(tempfile) && localtime() < timeout + sleep 500 m + endwhile + call xolox#misc#test#assert_true(filereadable(tempfile)) + call xolox#misc#test#assert_equals([expected_value], readfile(tempfile)) endfunction diff --git a/doc/misc.txt b/doc/misc.txt index fb7d514..08d25ec 100644 --- a/doc/misc.txt +++ b/doc/misc.txt @@ -57,9 +57,34 @@ Contents ~ 11. String handling |misc-string-handling| 1. The |xolox#misc#str#compact()| function 2. The |xolox#misc#str#trim()| function - 12. Tests for my miscellaneous Vim scripts |tests-for-my-miscellaneous-vim-scripts| - 1. The |xolox#misc#tests#run_all()| function - 13. Timing of long during operations |misc-timing-of-long-during-operations| + 12. Test runner & infrastructure for Vim plug-ins |misc-test-runner-infrastructure-for-vim-plug-ins| + 1. The |xolox#misc#test#reset()| function + 2. The |xolox#misc#test#summarize()| function + 3. The |xolox#misc#test#wrap()| function + 4. The |xolox#misc#test#passed()| function + 5. The |xolox#misc#test#failed()| function + 6. The |xolox#misc#test#assert_true()| function + 7. The |xolox#misc#test#assert_equals()| function + 8. The |xolox#misc#test#assert_same_type()| function + 13. Tests for the miscellaneous Vim scripts |tests-for-miscellaneous-vim-scripts| + 1. The |xolox#misc#tests#run()| function + 2. The |xolox#misc#tests#pattern_escaping()| function + 3. The |xolox#misc#tests#substitute_escaping()| function + 4. The |xolox#misc#tests#shell_escaping()| function + 5. The |xolox#misc#tests#making_a_list_unique()| function + 6. The |xolox#misc#tests#binary_insertion()| function + 7. The |xolox#misc#tests#getting_configuration_options()| function + 8. The |xolox#misc#tests#splitting_of_multi_valued_options()| function + 9. The |xolox#misc#tests#joining_of_multi_valued_options()| function + 10. The |xolox#misc#tests#evaluation_of_tags_option()| function + 11. The |xolox#misc#tests#finding_vim_on_the_search_path()| function + 12. The |xolox#misc#tests#synchronous_command_execution()| function + 13. The |xolox#misc#tests#synchronous_command_execution_with_raising_of_errors()| +function + 14. The |xolox#misc#tests#synchronous_command_execution_without_raising_errors()| +function + 15. The |xolox#misc#tests#asynchronous_command_execution()| function + 14. Timing of long during operations |misc-timing-of-long-during-operations| 1. The |xolox#misc#timer#start()| function 2. The |xolox#misc#timer#stop()| function 3. The |xolox#misc#timer#force()| function @@ -107,24 +132,22 @@ plug-ins. I care about backwards compatibility so won't break it without a good reason to do so. For those who are curious: The function descriptions given below were extracted -from the source code of the miscellaneous scripts using a bit of Python code -that I haven't published yet. +from the source code of the miscellaneous scripts using the Python module +'vimdoctool.py' included in vim-tools [5]. -Start of generated documentation - -The documentation of the 44 functions below was extracted from 14 Vim scripts -on June 2, 2013 at 21:27. +The documentation of the 66 functions below was extracted from 15 Vim scripts +on June 2, 2013 at 22:18. ------------------------------------------------------------------------------- *misc-handling-of-special-buffers* Handling of special buffers ~ The functions defined here make it easier to deal with special Vim buffers that -contain text generated by a Vim plug-in. For example my vim-notes plug-in [5] +contain text generated by a Vim plug-in. For example my vim-notes plug-in [6] generates several such buffers: -- :RecentNotes [6] lists recently modified notes -- :ShowTaggedNotes [7] lists notes grouped by tags +- :RecentNotes [7] lists recently modified notes +- :ShowTaggedNotes [8] lists notes grouped by tags - etc. Because the text in these buffers is generated, Vim shouldn't bother with swap @@ -387,7 +410,7 @@ the global variable 'g:xolox#misc#os#vim_progname'. The *xolox#misc#os#exec()* function Execute an external command (hiding the console on Microsoft Windows when my -vim-shell plug-in [8] is installed). +vim-shell plug-in [9] is installed). Expects a dictionary with the following key/value pairs as the first argument: @@ -529,13 +552,156 @@ Trim all whitespace from the start and end of the string given as the first argument. ------------------------------------------------------------------------------- - *tests-for-my-miscellaneous-vim-scripts* -Tests for my miscellaneous Vim scripts ~ + *misc-test-runner-infrastructure-for-vim-plug-ins* +Test runner & infrastructure for Vim plug-ins ~ + +The Vim auto-load script 'autoload/xolox/misc/test.vim' contains infrastructure +that can be used to run an automated Vim plug-in test suite. It provides a +framework for running test functions, keeping track of the test status, making +assertions and reporting test results to the user. + +------------------------------------------------------------------------------- +The *xolox#misc#test#reset()* function + +Reset counters for executed tests and passed/failed assertions. + +------------------------------------------------------------------------------- +The *xolox#misc#test#summarize()* function + +Print a summary of test results, to be interpreted interactively. + +------------------------------------------------------------------------------- +The *xolox#misc#test#wrap()* function + +Call a function in a try/catch block and prevent exceptions from bubbling. The +name of the function should be passed as the first and only argument; it should +be a string containing the name of a Vim auto-load function. + +------------------------------------------------------------------------------- +The *xolox#misc#test#passed()* function + +Record a test which succeeded. + +------------------------------------------------------------------------------- +The *xolox#misc#test#failed()* function + +Record a test which failed. + +------------------------------------------------------------------------------- +The *xolox#misc#test#assert_true()* function + +Check whether an expression is true. + +------------------------------------------------------------------------------- +The *xolox#misc#test#assert_equals()* function + +Check whether two values are the same. + +------------------------------------------------------------------------------- +The *xolox#misc#test#assert_same_type()* function + +Check whether two values are of the same type. + +------------------------------------------------------------------------------- + *tests-for-miscellaneous-vim-scripts* +Tests for the miscellaneous Vim scripts ~ + +The Vim auto-load script 'autoload/xolox/misc/tests.vim' contains the automated +test suite of the miscellaneous Vim scripts. Right now the coverage is not very +high yet, but this will improve over time. + +------------------------------------------------------------------------------- +The *xolox#misc#tests#run()* function + +Run the automated test suite of the miscellaneous Vim scripts. To be used +interactively. Intended to be safe to execute irrespective of context. + +------------------------------------------------------------------------------- +The *xolox#misc#tests#pattern_escaping()* function + +Test escaping of regular expression patterns with +|xolox#misc#escape#pattern()|. + +------------------------------------------------------------------------------- +The *xolox#misc#tests#substitute_escaping()* function + +Test escaping of substitution strings with |xolox#misc#escape#substitute()|. + +------------------------------------------------------------------------------- +The *xolox#misc#tests#shell_escaping()* function + +Test escaping of shell arguments with |xolox#misc#escape#shell()|. + +------------------------------------------------------------------------------- +The *xolox#misc#tests#making_a_list_unique()* function + +Test removing of duplicate values from lists with |xolox#misc#list#unique()|. + +------------------------------------------------------------------------------- +The *xolox#misc#tests#binary_insertion()* function + +Test the binary insertion algorithm implemented in |xolox#misc#list#binsert()|. ------------------------------------------------------------------------------- -The *xolox#misc#tests#run_all()* function +The *xolox#misc#tests#getting_configuration_options()* function -Run the automated tests of the miscellaneous functions. +Test getting of scoped plug-in configuration "options" with +|xolox#misc#option#get()|. + +------------------------------------------------------------------------------- +The *xolox#misc#tests#splitting_of_multi_valued_options()* function + +Test splitting of multi-valued Vim options with |xolox#misc#option#split()|. + +------------------------------------------------------------------------------- +The *xolox#misc#tests#joining_of_multi_valued_options()* function + +Test joining of multi-valued Vim options with |xolox#misc#option#join()|. + +------------------------------------------------------------------------------- +The *xolox#misc#tests#evaluation_of_tags_option()* function + +Test evaluation of Vim's |'tags'| option. We don't test '~/.tags' style +patterns because |xolox#misc#option#eval_tags()| doesn't support those. +Depending on your perspective this is not a bug, because the |'tags'| option +gets special treatment in Vim anyway: + +:set tags=~/.tags tags=~/.tags :echo &tags /home/peter/.tags + +So at the point where |xolox#misc#option#eval_tags()| receives the value of +|'tags'|, it has already been expanded by Vim. + +------------------------------------------------------------------------------- +The *xolox#misc#tests#finding_vim_on_the_search_path()* function + +Test looking up Vim's executable on the search path using |v:progname| with +|xolox#misc#os#find_vim()|. + +------------------------------------------------------------------------------- +The *xolox#misc#tests#synchronous_command_execution()* function + +Test basic functionality of synchronous command execution with +|xolox#misc#os#exec()|. + +------------------------------------------------------------------------------- +The *xolox#misc#tests#synchronous_command_execution_with_raising_of_errors()* +function + +Test raising of errors during synchronous command execution with +|xolox#misc#os#exec()|. + +------------------------------------------------------------------------------- +The *xolox#misc#tests#synchronous_command_execution_without_raising_errors()* +function + +Test synchronous command execution without raising of errors with +|xolox#misc#os#exec()|. + +------------------------------------------------------------------------------- +The *xolox#misc#tests#asynchronous_command_execution()* function + +Test basic functionality of asynchronous command execution with +|xolox#misc#os#exec()|. ------------------------------------------------------------------------------- *misc-timing-of-long-during-operations* @@ -566,8 +732,6 @@ handling as Vim's |printf()| function with one difference: At the point where you want the elapsed time to be embedded, you write '%s' and you pass the list returned by |xolox#misc#timer#start()| as an argument. -End of generated documentation - =============================================================================== *misc-contact* Contact ~ @@ -575,13 +739,13 @@ Contact ~ If you have questions, bug reports, suggestions, etc. the author can be contacted at peter@peterodding.com. The latest version is available at http://peterodding.com/code/vim/misc and http://github.com/xolox/vim-misc. If -you like the script please vote for it on Vim Online [9]. +you like the script please vote for it on Vim Online [10]. =============================================================================== *misc-license* License ~ -This software is licensed under the MIT license [10]. © 2013 Peter Odding +This software is licensed under the MIT license [11]. © 2013 Peter Odding . =============================================================================== @@ -592,11 +756,12 @@ References ~ [2] http://peterodding.com/code/vim/downloads/misc.zip [3] http://www.vim.org/scripts/script.php?script_id=2332 [4] https://github.com/gmarik/vundle -[5] http://peterodding.com/code/vim/notes/ -[6] http://peterodding.com/code/vim/notes/#recentnotes_command -[7] http://peterodding.com/code/vim/notes/#showtaggednotes_command -[8] http://peterodding.com/code/vim/shell/ -[9] http://www.vim.org/scripts/script.php?script_id=4597 -[10] http://en.wikipedia.org/wiki/MIT_License +[5] http://peterodding.com/code/vim/tools/ +[6] http://peterodding.com/code/vim/notes/ +[7] http://peterodding.com/code/vim/notes/#recentnotes_command +[8] http://peterodding.com/code/vim/notes/#showtaggednotes_command +[9] http://peterodding.com/code/vim/shell/ +[10] http://www.vim.org/scripts/script.php?script_id=4597 +[11] http://en.wikipedia.org/wiki/MIT_License vim: ft=help