#!/bin/sh fullpath() { ( cd -- "$1" pwd ) } indent() { level="$1" printf "%$((2 * ${level}))s" } recurse() { potential_test="$1" indent_level="$2" [ "$potential_test" = 'setup_dir' ] && return [ "$potential_test" = 'teardown_dir' ] && return [ "$potential_test" = 'setup' ] && return [ "$potential_test" = 'teardown' ] && return [ $indent_level -eq 0 ] && : > "$stdout_file" if [ -d "$potential_test" ] then ( indent $indent_level echo " ${potential_test}" cd -- "$potential_test" [ -f setup_dir ] && [ -x setup_dir ] && ./setup_dir >> "$stdout_file" for test in * do [ -f setup ] && [ -x setup ] && ./setup >> "$stdout_file" # $2 instead of $indent_level so it doesn't clash recurse "${test}" $(( $2 + 1 )) [ -f teardown ] && [ -x teardown ] && ./teardown >> "$stdout_file" done [ -f teardown_dir ] && [ -x teardown_dir ] && ./teardown_dir >> "$stdout_file" echo ) elif [ -x "$potential_test" ] then [ -f setup ] && [ -x setup ] && ./setup >> "$stdout_file" # Run the test ./"$potential_test" > "$stdout_file" 2>&1 exit_code="$?" [ -f teardown ] && [ -x teardown ] && ./teardown >> "$stdout_file" indent $indent_level if [ $exit_code -eq 0 ] then # On success, print a green '✓' printf '\033[32m✓ \033[0m' printf '%s\n' "${potential_test}" printf '%s\n' "${potential_test} passed" >> "$logfile" else # On fail, print a red '✗' printf '\033[31m✗ \033[0m' printf '%s\n' "${potential_test}" printf '%s\n' "${potential_test} failed" >> "$logfile" printf '\033[31m' # Print output captured from failed test in red. cat "$stdout_file" printf '\033[0m' fi fi [ $indent_level -eq 0 ] && rm "$stdout_file" } USAGE="usage: $0 " urchin_help() { echo echo "$USAGE" echo echo '-f Force urchin to run on directories whose name does not contain' echo ' the word "test".' echo '-h This help' # echo # echo '--xsd Output xUnit XML schema for an integration server.' echo echo 'Go to https://github.com/scraperwiki/urchin for documentation on writing tests.' echo } plural () { # Make $1 a plural according to the number $2. # If $3 is supplied, use that instead of "${1}s". # Result is written to stdout. if [ "$2" = 1 ] then printf '%s\n' "$1" else printf '%s\n' "${3-${1}s}" fi } urchin_go() { echo Running tests at $(date +%Y-%m-%dT%H:%M:%S) | tee "$logfile" start=$(date +%s) recurse "$1" 0 # test folder, indentation level finish=$(date +%s) elapsed=$(($finish - $start)) echo "Done, took $elapsed $(plural second $elapsed)." set -- $(grep -e 'passed$' "$logfile"|wc -l) $(grep -e 'failed$' "$logfile"|wc -l) printf '%s\n' "$1 $(plural test "$1") passed." [ $2 -gt 0 ] && printf '\033[31m' || printf '\033[32m' # If tests failed, print the message in red, otherwise in green. printf '%s\n' "$2 $(plural test "$2") failed." printf '\033[m' return "$2" } urchin_molly_guard() { { echo echo 'The name of the directory on which you are running urchin' echo 'does not contain the word "test", so I am not running,' echo 'in case that was an accident. Use the -f flag if you really' echo 'want to run urchin on that directory.' echo } >&2 exit 1 } force=false while [ $# -gt 0 ] do case "$1" in -f) force=true;; -h|--help) urchin_help exit 0;; # --xsd) action=testsuite;; # --) shift; break;; -*) urchin_help 1>&2 exit 1;; *) break;; esac shift done # Verify argument for main stuff if [ "$#" != '1' ] || [ ! -d "$1" ] then [ -d "$1" ] || echo "Not a directory: '$1'" >&2 echo "$USAGE" >&2 exit 1 fi # Constants logfile=$(fullpath "$1")/.urchin.log stdout_file=$(fullpath "$1")/.urchin_stdout # Run or present the Molly guard. if basename "$(fullpath "$1")" | grep -Fi 'test' > /dev/null || $force then urchin_go "$1" else urchin_molly_guard fi