diff --git a/urchin b/urchin index f8a8972..3728fa6 100755 --- a/urchin +++ b/urchin @@ -48,6 +48,9 @@ set -e +# Urchin version number +VERSION=master + # Kill subprocesses on interrupt. trap "kill -$$; exit" HUP INT TERM @@ -68,6 +71,94 @@ if [ -n "${ZSH_VERSION}" ]; then emulate sh fi +# -------------------- Usage -------------------- +USAGE="usage: $0 [options]... [test file or directory]..." + +urchin_help() { + cat < Tell Urchin to use a different list of shells. + (You can pass this flag multiple times.) + +-n, --disable-cycling Disable the cycling of shells; Urchin will + execute test files ordinarily, implicitly using + sh for files that lack shebang lines. It will + set the TEST_SHELL variable to "/bin/sh" if and + only if TEST_SHELL is empty or undefined. + +The following flags affect how Urchin processes tests. + +-b, --run-in-series Run tests in series. The default is to run tests + in parallel where possible. +-e, --exit-on-fail Stop running if any single test fails. + This can be useful if you are running something + other than test files with Urchin. +-T, --timeout Kill a test if it runs for longer than the + specified duration. The default is no timeout. +-f, --force Force running even if the test directory's name + does not contain the word "test". + +These options affect how results are formatted. Options -q, and -v +have no effect when combined with --tap. -vv, -vvv, and -vvvv do have +effect when combined with --tap. + +-p, --pretty Print results in color and with fancy symbols. +-t, --tap Format output in Test Anything Protocol (TAP) + +And these options affect how much is printed. + +-q, --quiet Print nothing to stdout; + the only output is the exit code. +(default verbosity) Print names of failed tests and counts + of passed, failed, and skipped tests. +-v Print stdout from failing tests. +-vv Print names of passed tests. +-vvv, --verbose Print stdout from all tests. +-vvvv, --debug Run with set -x. + +The remaining flags provide information about urchin. + +-h, --help Display this help. +--version Display the version number. + +Urchin recognizes certain environment variables. + +TEST_SHELL This is sometimes over-ridden; see -s. +RUN_IN_SERIES Set this to true to have the same effect as + -b/--run-in-series. This is helpful if you are + calling urchin inside an urchin test suite. + +Go to https://thomaslevine.com/!/urchin/ for documentation on writing tests. + +EOF +} + +# -------------------- Temporary directory -------------------- +urchin_tmp=$(mktemp_dir) +> "${urchin_tmp}/log" + +urchin_exit() { + rm -Rf "${urchin_tmp}" + exit "$@" +} + + +# -------------------- Portable wrappers -------------------- epoch_date() { date +%s } @@ -96,6 +187,37 @@ mktemp_file() { echo "${tmp}" } +# -------------------- Utilities -------------------- +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 +} + +validate_strings() { + test $(echo "${1}" | wc -l) -eq 1 || { + echo '$1 may not contain tab or newline characters.' >&2 + echo 'If this is really a problem, tell me, and I may fix it.' >&2 + urchin_exit 11 + } +} + +has_shebang_line() { + head -n 1 "${1}" | grep -v '^#!/bin/sh$' | grep -q '^#!' +} + +indent() { + level="${1}" + if test "${level}" -gt 0; then + printf "%$((2 * ${level}))s" + fi +} validate_test_arg() { # Must be a file or directory @@ -119,33 +241,6 @@ validate_test_arg() { fi } -# All temporary files go here -urchin_tmp=$(mktemp_dir) -> "${urchin_tmp}/log" - -urchin_exit() { - rm -Rf "${urchin_tmp}" - exit "$@" -} - -if which md5 1> /dev/null 2> /dev/null; then - urchin_md5=md5 -elif which md5sum 1> /dev/null 2> /dev/null; then - urchin_md5=md5sum -else - echo Could not find MD5 hash command >&2 - urchin_exit 1 -fi - -if epoch_date 2>&1 > /dev/null; then - epoch=epoch_date -elif epoch_pax 2>&1 > /dev/null; then - epoch=epoch_pax -else - echo I could not find a seconds counter. >&2 - urchin_exit 1 -fi - stdout_file() { the_test="${1}" the_shell="${2}" @@ -199,16 +294,27 @@ urchin_root() { fi } -# Urchin version number -VERSION=0.1.1-unstable +# -------------------- Dependency checks -------------------- +if which md5 1> /dev/null 2> /dev/null; then + urchin_md5=md5 +elif which md5sum 1> /dev/null 2> /dev/null; then + urchin_md5=md5sum +else + echo Could not find MD5 hash command >&2 + urchin_exit 1 +fi -indent() { - level="${1}" - if test "${level}" -gt 0; then - printf "%$((2 * ${level}))s" - fi -} +if epoch_date 2>&1 > /dev/null; then + epoch=epoch_date +elif epoch_pax 2>&1 > /dev/null; then + epoch=epoch_pax +else + echo I could not find a seconds counter. >&2 + urchin_exit 1 +fi + +# -------------------- Main stuff -------------------- recurse() { requested_path="${1}" potential_test="$(fullpath "${2}")" @@ -487,105 +593,6 @@ report_outcome() { test "${not_oks}" -eq '0' } -has_shebang_line() { - head -n 1 "${1}" | grep -v '^#!/bin/sh$' | grep -q '^#!' -} - -USAGE="usage: $0 [options]... [test file or directory]..." - -urchin_help() { - cat < Tell Urchin to use a different list of shells. - (You can pass this flag multiple times.) - --n, --disable-cycling Disable the cycling of shells; Urchin will - execute test files ordinarily, implicitly using - sh for files that lack shebang lines. It will - set the TEST_SHELL variable to "/bin/sh" if and - only if TEST_SHELL is empty or undefined. - -The following flags affect how Urchin processes tests. - --b, --run-in-series Run tests in series. The default is to run tests - in parallel where possible. --e, --exit-on-fail Stop running if any single test fails. - This can be useful if you are running something - other than test files with Urchin. --T, --timeout Kill a test if it runs for longer than the - specified duration. The default is no timeout. --f, --force Force running even if the test directory's name - does not contain the word "test". - -These options affect how results are formatted. Options -q, and -v -have no effect when combined with --tap. -vv, -vvv, and -vvvv do have -effect when combined with --tap. - --p, --pretty Print results in color and with fancy symbols. --t, --tap Format output in Test Anything Protocol (TAP) - -And these options affect how much is printed. - --q, --quiet Print nothing to stdout; - the only output is the exit code. -(default verbosity) Print names of failed tests and counts - of passed, failed, and skipped tests. --v Print stdout from failing tests. --vv Print names of passed tests. --vvv, --verbose Print stdout from all tests. --vvvv, --debug Run with set -x. - -The remaining flags provide information about urchin. - --h, --help Display this help. ---version Display the version number. - -Urchin recognizes certain environment variables. - -TEST_SHELL This is sometimes over-ridden; see -s. -RUN_IN_SERIES Set this to true to have the same effect as - -b/--run-in-series. This is helpful if you are - calling urchin inside an urchin test suite. - -Go to https://thomaslevine.com/!/urchin/ for documentation on writing tests. - -EOF -} - -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 -} - -validate_strings() { - test $(echo "${1}" | wc -l) -eq 1 || { - echo '$1 may not contain tab or newline characters.' >&2 - echo 'If this is really a problem, tell me, and I may fix it.' >&2 - urchin_exit 11 - } -} main() { cycle_shell=true