diff options
Diffstat (limited to 'dotfiles/.vim/contrib/run-tests-watch')
-rwxr-xr-x | dotfiles/.vim/contrib/run-tests-watch | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/dotfiles/.vim/contrib/run-tests-watch b/dotfiles/.vim/contrib/run-tests-watch new file mode 100755 index 0000000..11edbdf --- /dev/null +++ b/dotfiles/.vim/contrib/run-tests-watch @@ -0,0 +1,127 @@ +#!/bin/sh -x +# +# Wrapper around inotifywait to run tests on file changes. +# If a test file changes, only this file is run (first), while the whole test +# suite is run afterwards (and initially). +# +# The recommended way to run it is via `make testwatch`, or `make testwatchx` +# (to exit on first failure). +# +# # Internal documentation: +# The default run command is "make %s" (where %s gets replaced with the test +# file(s)), and can be given as first argument. +# +# You can specify VADER_OPTIONS=-x to exit on the first test failure: +# VADER_OPTIONS=-x contrib/run-tests-watch +# or use the following: +# contrib/run-tests-watch 'make %s VADER_OPTIONS=-x' +# +# VADER_ARGS gets used to focus on a specific test file initially, until +# another test file gets changed. + +watch="autoload plugin tests" +echo "Watching: $watch" + +if [ -n "$1" ]; then + cmdpattern="$1" +else + cmdpattern="make %s VADER_OPTIONS='$VADER_OPTIONS'" +fi + +title() { + printf '\e]1;%s\a' "$*" + printf '\e]2;%s\a' "$*" +} + +status_file=$(mktemp) +handle_cmd_result() { + if [ "$1" = 0 ]; then + last_test_succeeded=1 + title "✔ $2" + if [ "${2#*${alltestsfile}*}" != "$2" ]; then + alltests_succeeded=1 + fi + else + last_test_succeeded=0 + title "✘ $2" + if [ "${2#*${alltestsfile}*}" != "$2" ]; then + alltests_succeeded=0 + fi + fi + echo "$last_test_succeeded $alltests_succeeded" > "$status_file" +} + +# Recursively kill childs - required to get out of a running pdb. +kill_with_childs() { + for p in $(pgrep -P "$1"); do + kill_with_childs "$p" + done + if kill -0 "$1" 2>/dev/null; then + kill "$1" || true + fi +} + +alltestsfile='tests/all.vader' +alltests_succeeded=0 +pid= +changed_files= +set -e +last_changed_testsfile="${VADER_ARGS:-$alltestsfile}" + +while true; do + testfiles="$last_changed_testsfile" + if [ -n "$changed_files" ]; then + # There was a previous run + echo "=================================================================" + echo "changed file: $changed_files" + + read -r last_test_succeeded alltests_succeeded < "$status_file" || alltests_succeeded=0 + + if [ "${changed_files#tests/}" != "$changed_files" ] \ + && [ "${changed_files#tests/include/}" = "$changed_files" ]; then + # A test file was changed (but not an include file). + last_changed_testsfile="$changed_files" + testfiles="$last_changed_testsfile" + + # Run full tests afterwards (if not successful before). + if [ "$testfiles" != "$alltestsfile" ] && [ "$alltests_succeeded" = 0 ]; then + testfiles="$testfiles $alltestsfile" + fi + + elif [ "$last_test_succeeded" = 1 ]; then + # Run all tests. + alltests_succeeded=0 + testfiles="$alltestsfile" + + if [ "${VADER_OPTIONS#*-x*}" != "$VADER_OPTIONS" ]; then + # Run tests matching the changed file first, e.g. tests/config.vader for + # autoload/neomake/config.vim. + test_file_for_changed_file="tests/${changed_files#autoload/neomake/}" + test_file_for_changed_file="${test_file_for_changed_file%.vim}.vader" + declare -p test_file_for_changed_file + if [ -f "$test_file_for_changed_file" ]; then + testfiles="$test_file_for_changed_file $testfiles" + fi + fi + fi + + if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then + echo 'Killing previous run…' + kill_with_childs "$pid" + fi + fi + + # shellcheck disable=SC2059 + cmd="$(printf "$cmdpattern" "$testfiles")" + echo "Running $cmd" + title "… $testfiles" + # shellcheck disable=SC2015 + (set +e; eval "$cmd"; handle_cmd_result "$?" "$testfiles") </dev/tty & + pid=$! + + sleep 1 + # shellcheck disable=SC2086 + changed_files="$(inotifywait -q -r -e close_write \ + --exclude '/(__pycache__/|\.)|.*\@neomake_.*' \ + --format '%w%f' $watch)" +done |