• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Simple test harness infrastructure
2#
3# Copyright 2005 by Rob Landley
4
5# This file defines two main functions, "testcmd" and "optional". The
6# first performs a test, the second enables/disables tests based on
7# configuration options.
8
9# The following environment variables enable optional behavior in "testing":
10#    DEBUG - Show every command run by test script.
11#    VERBOSE - Print the diff -u of each failed test case.
12#              If equal to "fail", stop after first failed test.
13#              "nopass" to not show successful tests
14#
15# The "testcmd" function takes five arguments:
16#	$1) Description to display when running command
17#	$2) Command line arguments to command
18#	$3) Expected result (on stdout)
19#	$4) Data written to file "input"
20#	$5) Data written to stdin
21#
22# The "testing" function is like testcmd but takes a complete command line
23# (I.E. you have to include the command name.) The variable $C is an absolute
24# path to the command being tested, which can bypass shell builtins.
25#
26# The exit value of testcmd is the exit value of the command it ran.
27#
28# The environment variable "FAILCOUNT" contains a cumulative total of the
29# number of failed tests.
30#
31# The "optional" function is used to skip certain tests (by setting the
32# environment variable SKIP), ala:
33#   optional CFG_THINGY
34#
35# The "optional" function checks the environment variable "OPTIONFLAGS",
36# which is either empty (in which case it always clears SKIP) or
37# else contains a colon-separated list of features (in which case the function
38# clears SKIP if the flag was found, or sets it to 1 if the flag was not found).
39
40export FAILCOUNT=0
41export SKIP=
42
43# Helper functions
44
45# Check config to see if option is enabled, set SKIP if not.
46
47SHOWPASS=PASS
48SHOWFAIL=FAIL
49SHOWSKIP=SKIP
50
51if tty -s <&1
52then
53  SHOWPASS="$(echo -e "\033[1;32m${SHOWPASS}\033[0m")"
54  SHOWFAIL="$(echo -e "\033[1;31m${SHOWFAIL}\033[0m")"
55  SHOWSKIP="$(echo -e "\033[1;33m${SHOWSKIP}\033[0m")"
56fi
57
58optional()
59{
60  option=`printf %s "$OPTIONFLAGS" | egrep "(^|:)$1(:|\$)"`
61  # Not set?
62  if [ -z "$1" ] || [ -z "$OPTIONFLAGS" ] || [ ${#option} -ne 0 ]
63  then
64    SKIP=""
65    return
66  fi
67  SKIP=1
68}
69
70skipnot()
71{
72  if [ -z "$VERBOSE" ]
73  then
74    eval "$@" 2>/dev/null
75  else
76    eval "$@"
77  fi
78  [ $? -eq 0 ] || SKIPNEXT=1
79}
80
81toyonly()
82{
83  IS_TOYBOX="$("$C" --version 2>/dev/null)"
84  [ "${IS_TOYBOX/toybox/}" == "$IS_TOYBOX" ] && SKIPNEXT=1
85
86  "$@"
87}
88
89wrong_args()
90{
91  if [ $# -ne 5 ]
92  then
93    printf "%s\n" "Test $NAME has the wrong number of arguments ($# $*)" >&2
94    exit
95  fi
96}
97
98# The testing function
99
100testing()
101{
102  NAME="$CMDNAME $1"
103  wrong_args "$@"
104
105  [ -z "$1" ] && NAME=$2
106
107  [ -n "$DEBUG" ] && set -x
108
109  if [ -n "$SKIP" -o -n "$SKIP_HOST" -a -n "$TEST_HOST" -o -n "$SKIPNEXT" ]
110  then
111    [ ! -z "$VERBOSE" ] && printf "%s\n" "$SHOWSKIP: $NAME"
112    unset SKIPNEXT
113    return 0
114  fi
115
116  echo -ne "$3" > expected
117  echo -ne "$4" > input
118  echo -ne "$5" | ${EVAL:-eval} -- "$2" > actual
119  RETVAL=$?
120
121  # Catch segfaults
122  [ $RETVAL -gt 128 ] && [ $RETVAL -lt 255 ] &&
123    echo "exited with signal (or returned $RETVAL)" >> actual
124  DIFF="$(diff -au${NOSPACE:+w} expected actual)"
125  if [ ! -z "$DIFF" ]
126  then
127    FAILCOUNT=$(($FAILCOUNT+1))
128    printf "%s\n" "$SHOWFAIL: $NAME"
129    if [ -n "$VERBOSE" ]
130    then
131      [ ! -z "$4" ] && printf "%s\n" "echo -ne \"$4\" > input"
132      printf "%s\n" "echo -ne '$5' |$EVAL $2"
133      printf "%s\n" "$DIFF"
134      [ "$VERBOSE" == fail ] && exit 1
135    fi
136  else
137    [ "$VERBOSE" != "nopass" ] && printf "%s\n" "$SHOWPASS: $NAME"
138  fi
139  rm -f input expected actual
140
141  [ -n "$DEBUG" ] && set +x
142
143  return 0
144}
145
146testcmd()
147{
148  wrong_args "$@"
149
150  X="$1"
151  [ -z "$X" ] && X="$CMDNAME $2"
152  testing "$X" "\"$C\" $2" "$3" "$4" "$5"
153}
154
155# Recursively grab an executable and all the libraries needed to run it.
156# Source paths beginning with / will be copied into destpath, otherwise
157# the file is assumed to already be there and only its library dependencies
158# are copied.
159
160mkchroot()
161{
162  [ $# -lt 2 ] && return
163
164  echo -n .
165
166  dest=$1
167  shift
168  for i in "$@"
169  do
170    [ "${i:0:1}" == "/" ] || i=$(which $i)
171    [ -f "$dest/$i" ] && continue
172    if [ -e "$i" ]
173    then
174      d=`echo "$i" | grep -o '.*/'` &&
175      mkdir -p "$dest/$d" &&
176      cat "$i" > "$dest/$i" &&
177      chmod +x "$dest/$i"
178    else
179      echo "Not found: $i"
180    fi
181    mkchroot "$dest" $(ldd "$i" | egrep -o '/.* ')
182  done
183}
184
185# Set up a chroot environment and run commands within it.
186# Needed commands listed on command line
187# Script fed to stdin.
188
189dochroot()
190{
191  mkdir tmpdir4chroot
192  mount -t ramfs tmpdir4chroot tmpdir4chroot
193  mkdir -p tmpdir4chroot/{etc,sys,proc,tmp,dev}
194  cp -L testing.sh tmpdir4chroot
195
196  # Copy utilities from command line arguments
197
198  echo -n "Setup chroot"
199  mkchroot tmpdir4chroot $*
200  echo
201
202  mknod tmpdir4chroot/dev/tty c 5 0
203  mknod tmpdir4chroot/dev/null c 1 3
204  mknod tmpdir4chroot/dev/zero c 1 5
205
206  # Copy script from stdin
207
208  cat > tmpdir4chroot/test.sh
209  chmod +x tmpdir4chroot/test.sh
210  chroot tmpdir4chroot /test.sh
211  umount -l tmpdir4chroot
212  rmdir tmpdir4chroot
213}
214