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