#!/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")