1*63d4e48fSSadaf Ebrahimi#! /bin/sh 2*63d4e48fSSadaf Ebrahimi# vim:et:ft=sh:sts=2:sw=2 3*63d4e48fSSadaf Ebrahimi# 4*63d4e48fSSadaf Ebrahimi# Unit test suite runner. 5*63d4e48fSSadaf Ebrahimi# 6*63d4e48fSSadaf Ebrahimi# Copyright 2008-2020 Kate Ward. All Rights Reserved. 7*63d4e48fSSadaf Ebrahimi# Released under the Apache 2.0 license. 8*63d4e48fSSadaf Ebrahimi# 9*63d4e48fSSadaf Ebrahimi# Author: [email protected] (Kate Ward) 10*63d4e48fSSadaf Ebrahimi# https://github.com/kward/shlib 11*63d4e48fSSadaf Ebrahimi# 12*63d4e48fSSadaf Ebrahimi# This script runs all the unit tests that can be found, and generates a nice 13*63d4e48fSSadaf Ebrahimi# report of the tests. 14*63d4e48fSSadaf Ebrahimi# 15*63d4e48fSSadaf Ebrahimi### Sample usage: 16*63d4e48fSSadaf Ebrahimi# 17*63d4e48fSSadaf Ebrahimi# Run all tests for all shells. 18*63d4e48fSSadaf Ebrahimi# $ ./test_runner 19*63d4e48fSSadaf Ebrahimi# 20*63d4e48fSSadaf Ebrahimi# Run all tests for single shell. 21*63d4e48fSSadaf Ebrahimi# $ ./test_runner -s /bin/bash 22*63d4e48fSSadaf Ebrahimi# 23*63d4e48fSSadaf Ebrahimi# Run single test for all shells. 24*63d4e48fSSadaf Ebrahimi# $ ./test_runner -t shunit_asserts_test.sh 25*63d4e48fSSadaf Ebrahimi# 26*63d4e48fSSadaf Ebrahimi# Run single test for single shell. 27*63d4e48fSSadaf Ebrahimi# $ ./test_runner -s /bin/bash -t shunit_asserts_test.sh 28*63d4e48fSSadaf Ebrahimi# 29*63d4e48fSSadaf Ebrahimi### ShellCheck (http://www.shellcheck.net/) 30*63d4e48fSSadaf Ebrahimi# Disable source following. 31*63d4e48fSSadaf Ebrahimi# shellcheck disable=SC1090,SC1091 32*63d4e48fSSadaf Ebrahimi# expr may be antiquated, but it is the only solution in some cases. 33*63d4e48fSSadaf Ebrahimi# shellcheck disable=SC2003 34*63d4e48fSSadaf Ebrahimi# $() are not fully portable (POSIX != portable). 35*63d4e48fSSadaf Ebrahimi# shellcheck disable=SC2006 36*63d4e48fSSadaf Ebrahimi 37*63d4e48fSSadaf Ebrahimi# Return if test_runner already loaded. 38*63d4e48fSSadaf Ebrahimi[ -z "${RUNNER_LOADED:-}" ] || return 0 39*63d4e48fSSadaf EbrahimiRUNNER_LOADED=0 40*63d4e48fSSadaf Ebrahimi 41*63d4e48fSSadaf EbrahimiRUNNER_ARGV0=`basename "$0"` 42*63d4e48fSSadaf EbrahimiRUNNER_SHELLS='/bin/sh ash /bin/bash /bin/dash /bin/ksh /bin/mksh /bin/zsh' 43*63d4e48fSSadaf EbrahimiRUNNER_TEST_SUFFIX='_test.sh' 44*63d4e48fSSadaf Ebrahimitrue; RUNNER_TRUE=$? 45*63d4e48fSSadaf Ebrahimifalse; RUNNER_FALSE=$? 46*63d4e48fSSadaf Ebrahimi 47*63d4e48fSSadaf Ebrahimirunner_warn() { echo "runner:WARN $*" >&2; } 48*63d4e48fSSadaf Ebrahimirunner_error() { echo "runner:ERROR $*" >&2; } 49*63d4e48fSSadaf Ebrahimirunner_fatal() { echo "runner:FATAL $*" >&2; exit 1; } 50*63d4e48fSSadaf Ebrahimi 51*63d4e48fSSadaf Ebrahimirunner_usage() { 52*63d4e48fSSadaf Ebrahimi echo "usage: ${RUNNER_ARGV0} [-e key=val ...] [-s shell(s)] [-t test(s)]" 53*63d4e48fSSadaf Ebrahimi} 54*63d4e48fSSadaf Ebrahimi 55*63d4e48fSSadaf Ebrahimi_runner_tests() { echo ./*${RUNNER_TEST_SUFFIX} |sed 's#\./##g'; } 56*63d4e48fSSadaf Ebrahimi_runner_testName() { 57*63d4e48fSSadaf Ebrahimi # shellcheck disable=SC1117 58*63d4e48fSSadaf Ebrahimi _runner_testName_=`expr "${1:-}" : "\(.*\)${RUNNER_TEST_SUFFIX}"` 59*63d4e48fSSadaf Ebrahimi if [ -n "${_runner_testName_}" ]; then 60*63d4e48fSSadaf Ebrahimi echo "${_runner_testName_}" 61*63d4e48fSSadaf Ebrahimi else 62*63d4e48fSSadaf Ebrahimi echo 'unknown' 63*63d4e48fSSadaf Ebrahimi fi 64*63d4e48fSSadaf Ebrahimi unset _runner_testName_ 65*63d4e48fSSadaf Ebrahimi} 66*63d4e48fSSadaf Ebrahimi 67*63d4e48fSSadaf Ebrahimimain() { 68*63d4e48fSSadaf Ebrahimi # Find and load versions library. 69*63d4e48fSSadaf Ebrahimi for _runner_dir_ in . ${LIB_DIR:-lib}; do 70*63d4e48fSSadaf Ebrahimi if [ -r "${_runner_dir_}/versions" ]; then 71*63d4e48fSSadaf Ebrahimi _runner_lib_dir_="${_runner_dir_}" 72*63d4e48fSSadaf Ebrahimi break 73*63d4e48fSSadaf Ebrahimi fi 74*63d4e48fSSadaf Ebrahimi done 75*63d4e48fSSadaf Ebrahimi [ -n "${_runner_lib_dir_}" ] || runner_fatal 'Unable to find versions library.' 76*63d4e48fSSadaf Ebrahimi . "${_runner_lib_dir_}/versions" || runner_fatal 'Unable to load versions library.' 77*63d4e48fSSadaf Ebrahimi unset _runner_dir_ _runner_lib_dir_ 78*63d4e48fSSadaf Ebrahimi 79*63d4e48fSSadaf Ebrahimi # Process command line flags. 80*63d4e48fSSadaf Ebrahimi env='' 81*63d4e48fSSadaf Ebrahimi while getopts 'e:hs:t:' opt; do 82*63d4e48fSSadaf Ebrahimi case ${opt} in 83*63d4e48fSSadaf Ebrahimi e) # set an environment variable 84*63d4e48fSSadaf Ebrahimi key=`expr "${OPTARG}" : '\([^=]*\)='` 85*63d4e48fSSadaf Ebrahimi val=`expr "${OPTARG}" : '[^=]*=\(.*\)'` 86*63d4e48fSSadaf Ebrahimi # shellcheck disable=SC2166 87*63d4e48fSSadaf Ebrahimi if [ -z "${key}" -o -z "${val}" ]; then 88*63d4e48fSSadaf Ebrahimi runner_usage 89*63d4e48fSSadaf Ebrahimi exit 1 90*63d4e48fSSadaf Ebrahimi fi 91*63d4e48fSSadaf Ebrahimi eval "${key}='${val}'" 92*63d4e48fSSadaf Ebrahimi eval "export ${key}" 93*63d4e48fSSadaf Ebrahimi env="${env:+${env} }${key}" 94*63d4e48fSSadaf Ebrahimi ;; 95*63d4e48fSSadaf Ebrahimi h) runner_usage; exit 0 ;; # help output 96*63d4e48fSSadaf Ebrahimi s) shells=${OPTARG} ;; # list of shells to run 97*63d4e48fSSadaf Ebrahimi t) tests=${OPTARG} ;; # list of tests to run 98*63d4e48fSSadaf Ebrahimi *) runner_usage; exit 1 ;; 99*63d4e48fSSadaf Ebrahimi esac 100*63d4e48fSSadaf Ebrahimi done 101*63d4e48fSSadaf Ebrahimi shift "`expr ${OPTIND} - 1`" 102*63d4e48fSSadaf Ebrahimi 103*63d4e48fSSadaf Ebrahimi # Fill shells and/or tests. 104*63d4e48fSSadaf Ebrahimi shells=${shells:-${RUNNER_SHELLS}} 105*63d4e48fSSadaf Ebrahimi [ -z "${tests}" ] && tests=`_runner_tests` 106*63d4e48fSSadaf Ebrahimi 107*63d4e48fSSadaf Ebrahimi # Error checking. 108*63d4e48fSSadaf Ebrahimi if [ -z "${tests}" ]; then 109*63d4e48fSSadaf Ebrahimi runner_error 'no tests found to run; exiting' 110*63d4e48fSSadaf Ebrahimi exit 1 111*63d4e48fSSadaf Ebrahimi fi 112*63d4e48fSSadaf Ebrahimi 113*63d4e48fSSadaf Ebrahimi cat <<EOF 114*63d4e48fSSadaf Ebrahimi#------------------------------------------------------------------------------ 115*63d4e48fSSadaf Ebrahimi# System data. 116*63d4e48fSSadaf Ebrahimi# 117*63d4e48fSSadaf Ebrahimi 118*63d4e48fSSadaf Ebrahimi$ uname -mprsv 119*63d4e48fSSadaf Ebrahimi`uname -mprsv` 120*63d4e48fSSadaf Ebrahimi 121*63d4e48fSSadaf EbrahimiOS Name: `versions_osName` 122*63d4e48fSSadaf EbrahimiOS Version: `versions_osVersion` 123*63d4e48fSSadaf Ebrahimi 124*63d4e48fSSadaf Ebrahimi### Test run info. 125*63d4e48fSSadaf Ebrahimishells: ${shells} 126*63d4e48fSSadaf Ebrahimitests: ${tests} 127*63d4e48fSSadaf EbrahimiEOF 128*63d4e48fSSadaf Ebrahimifor key in ${env}; do 129*63d4e48fSSadaf Ebrahimi eval "echo \"${key}=\$${key}\"" 130*63d4e48fSSadaf Ebrahimidone 131*63d4e48fSSadaf Ebrahimi 132*63d4e48fSSadaf Ebrahimi# Run tests. 133*63d4e48fSSadaf Ebrahimirunner_passing_=${RUNNER_TRUE} 134*63d4e48fSSadaf Ebrahimifor shell in ${shells}; do 135*63d4e48fSSadaf Ebrahimi echo 136*63d4e48fSSadaf Ebrahimi 137*63d4e48fSSadaf Ebrahimi cat <<EOF 138*63d4e48fSSadaf Ebrahimi 139*63d4e48fSSadaf Ebrahimi#------------------------------------------------------------------------------ 140*63d4e48fSSadaf Ebrahimi# Running the test suite with ${shell}. 141*63d4e48fSSadaf Ebrahimi# 142*63d4e48fSSadaf EbrahimiEOF 143*63d4e48fSSadaf Ebrahimi 144*63d4e48fSSadaf Ebrahimi # Check for existence of shell. 145*63d4e48fSSadaf Ebrahimi shell_bin=${shell} 146*63d4e48fSSadaf Ebrahimi shell_name='' 147*63d4e48fSSadaf Ebrahimi shell_present=${RUNNER_FALSE} 148*63d4e48fSSadaf Ebrahimi case ${shell} in 149*63d4e48fSSadaf Ebrahimi ash) 150*63d4e48fSSadaf Ebrahimi shell_bin=`command -v busybox` 151*63d4e48fSSadaf Ebrahimi [ $? -eq "${RUNNER_TRUE}" ] && shell_present="${RUNNER_TRUE}" 152*63d4e48fSSadaf Ebrahimi shell_bin="${shell_bin:+${shell_bin} }ash" 153*63d4e48fSSadaf Ebrahimi shell_name=${shell} 154*63d4e48fSSadaf Ebrahimi ;; 155*63d4e48fSSadaf Ebrahimi *) 156*63d4e48fSSadaf Ebrahimi [ -x "${shell_bin}" ] && shell_present="${RUNNER_TRUE}" 157*63d4e48fSSadaf Ebrahimi shell_name=`basename "${shell}"` 158*63d4e48fSSadaf Ebrahimi ;; 159*63d4e48fSSadaf Ebrahimi esac 160*63d4e48fSSadaf Ebrahimi if [ "${shell_present}" -eq "${RUNNER_FALSE}" ]; then 161*63d4e48fSSadaf Ebrahimi runner_warn "unable to run tests with the ${shell_name} shell" 162*63d4e48fSSadaf Ebrahimi continue 163*63d4e48fSSadaf Ebrahimi fi 164*63d4e48fSSadaf Ebrahimi 165*63d4e48fSSadaf Ebrahimi shell_version=`versions_shellVersion "${shell}"` 166*63d4e48fSSadaf Ebrahimi 167*63d4e48fSSadaf Ebrahimi echo "shell name: ${shell_name}" 168*63d4e48fSSadaf Ebrahimi echo "shell version: ${shell_version}" 169*63d4e48fSSadaf Ebrahimi 170*63d4e48fSSadaf Ebrahimi # Execute the tests. 171*63d4e48fSSadaf Ebrahimi for t in ${tests}; do 172*63d4e48fSSadaf Ebrahimi echo 173*63d4e48fSSadaf Ebrahimi echo "--- Executing the '`_runner_testName "${t}"`' test suite. ---" 174*63d4e48fSSadaf Ebrahimi # ${shell_bin} needs word splitting. 175*63d4e48fSSadaf Ebrahimi # shellcheck disable=SC2086 176*63d4e48fSSadaf Ebrahimi ( exec ${shell_bin} "./${t}" 2>&1; ) 177*63d4e48fSSadaf Ebrahimi shell_passing=$? 178*63d4e48fSSadaf Ebrahimi if [ "${shell_passing}" -ne "${RUNNER_TRUE}" ]; then 179*63d4e48fSSadaf Ebrahimi runner_warn "${shell_bin} not passing" 180*63d4e48fSSadaf Ebrahimi fi 181*63d4e48fSSadaf Ebrahimi test "${runner_passing_}" -eq ${RUNNER_TRUE} -a ${shell_passing} -eq ${RUNNER_TRUE} 182*63d4e48fSSadaf Ebrahimi runner_passing_=$? 183*63d4e48fSSadaf Ebrahimi done 184*63d4e48fSSadaf Ebrahimi done 185*63d4e48fSSadaf Ebrahimi return ${runner_passing_} 186*63d4e48fSSadaf Ebrahimi} 187*63d4e48fSSadaf Ebrahimi 188*63d4e48fSSadaf Ebrahimi# Execute main() if this is run in standalone mode (i.e. not from a unit test). 189*63d4e48fSSadaf Ebrahimiif [ -z "${SHUNIT_VERSION}" ]; then 190*63d4e48fSSadaf Ebrahimi main "$@" 191*63d4e48fSSadaf Ebrahimifi 192