mirror of
https://github.com/jimeh/stub.sh.git
synced 2026-02-19 13:46:40 +00:00
Initial commit
This commit is contained in:
83
README.md
Normal file
83
README.md
Normal file
@@ -0,0 +1,83 @@
|
||||
# stub.sh
|
||||
|
||||
A set of stubbing helpers for use in bash script tests. Supports stubbing and
|
||||
restoring both binaries and bash functions.
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
Put `stub.sh` in your project, source it into your tests. For detailed
|
||||
examples, why not have a look at the [tests][] for stub.sh itself?
|
||||
|
||||
[tests]: https://github.com/jimeh/stub.sh/tree/master/test
|
||||
|
||||
### Examples
|
||||
|
||||
Stubbing binaries:
|
||||
|
||||
```bash
|
||||
source "stub.sh"
|
||||
uname #=> Darwin
|
||||
stub uname
|
||||
uname #=> uname stub:
|
||||
uname -r #=> uname stub: -r
|
||||
restore uname
|
||||
uname #=> Darwin
|
||||
```
|
||||
|
||||
Stubbing bash functions:
|
||||
|
||||
```bash
|
||||
source "stub.sh"
|
||||
my-name-is() { echo "My name is $@."; }
|
||||
my-name-is Edward #=> Edward
|
||||
stub my-name-is
|
||||
my-name-is Edward #=> my-name-is stub: Edward
|
||||
restore my-name-is
|
||||
my-name-is Edward #=> Edward
|
||||
```
|
||||
|
||||
|
||||
## Function Reference
|
||||
|
||||
- `stub`: Basic stubbing command. Will echo a default message to STDOUT.
|
||||
Arguments:
|
||||
- `$1`: Name of command to stub
|
||||
- `$2`: When set to "STDERR", echo to STDERR instead of STDOUT.
|
||||
- `stub_and_echo`: Stub given command and echo a custom string to STDOUT.
|
||||
Arguments:
|
||||
- `$1`: Name of command to stub.
|
||||
- `$2`: String to echo when stub is called.
|
||||
- `$3`: When set to "STDERR", echo to STDERR instead of STDOUT.
|
||||
- `stub_and_eval`: Stub given command and execute custom commands via eval.
|
||||
Arguments:
|
||||
- `$1`: Name of command to stub.
|
||||
- `$2`: String to eval when stub is called.
|
||||
- `restore`: Restores use of original binary/function that was stubbed.
|
||||
Arguments:
|
||||
- `$1`: Name of command to restore.
|
||||
|
||||
|
||||
## License
|
||||
|
||||
(The MIT license)
|
||||
|
||||
Copyright (c) 2014 Jim Myhrberg.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
105
stub.sh
Normal file
105
stub.sh
Normal file
@@ -0,0 +1,105 @@
|
||||
# !/usr/bin/env bash
|
||||
# stub.sh 1.0.0 - stubbing helpers for simplifying bash script tests.
|
||||
# Copyright (c) 2014 Jim Myhrberg.
|
||||
#
|
||||
# https://github.com/jimeh/stub.sh
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
# IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
|
||||
# Stub given command, echoing a default stub message.
|
||||
#
|
||||
# Arguments:
|
||||
# - $1: Name of command to stub.
|
||||
# - $2: When set to "STDERR", echo to STDERR instead of STDOUT.
|
||||
#
|
||||
#
|
||||
stub() {
|
||||
stub_and_echo "$1" "$1 stub: \$@" "$2"
|
||||
}
|
||||
|
||||
|
||||
# Stub given command, and echo given string.
|
||||
#
|
||||
# Arguments:
|
||||
# - $1: Name of command to stub.
|
||||
# - $2: String to echo when stub is called.
|
||||
# - $3: When set to "STDERR", echo to STDERR instead of STDOUT.
|
||||
#
|
||||
stub_and_echo() {
|
||||
if [ "$3" == "STDERR" ]; then local redirect=" 1>&2"; fi
|
||||
stub_and_eval "$1" "echo \"$2\"$redirect"
|
||||
}
|
||||
|
||||
|
||||
# Stub given command, and executes given string with eval.
|
||||
#
|
||||
# Arguments:
|
||||
# - $1: Name of command to stub.
|
||||
# - $2: String to eval when stub is called.
|
||||
#
|
||||
stub_and_eval() {
|
||||
local cmd="$1"
|
||||
|
||||
# If stubbing a function, store non-stubbed copy of it required for restore.
|
||||
if [ -n "$(command -v "$cmd")" ]; then
|
||||
if [[ "$(type "$cmd" | head -1)" == *"is a function" ]]; then
|
||||
local source="$(type "$cmd" | tail -n +2)"
|
||||
source="${source/$cmd/non_stubbed_${cmd}}"
|
||||
eval "$source"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Use a function to keep track of if the command is stubbed, as variable
|
||||
# names doesn't support the "-" character, while function names do.
|
||||
eval "$(echo -e "${cmd}_is_stubbed() {\n return 0\n}")"
|
||||
|
||||
# Create the stub.
|
||||
eval "$(echo -e "${cmd}() {\n $2\n}")"
|
||||
}
|
||||
|
||||
|
||||
# Restore the original command/function that was stubbed.
|
||||
#
|
||||
# Arguments:
|
||||
# - $1: Name of command to restore.
|
||||
#
|
||||
restore() {
|
||||
local cmd="$1"
|
||||
|
||||
# Don't do anything if the command isn't currently stubbed.
|
||||
if [[ "$(type "${cmd}_is_stubbed" 2>&1)" == *"not found"* ]]; then
|
||||
return 0;
|
||||
fi
|
||||
|
||||
# Remove stub functions.
|
||||
unset -f "${cmd}_is_stubbed"
|
||||
unset -f "$cmd"
|
||||
|
||||
# If stub was for a function, restore the original function.
|
||||
if type "non_stubbed_${cmd}" &>/dev/null; then
|
||||
if [[ "$(type "non_stubbed_${cmd}" | head -1)" == *"is a function" ]]; then
|
||||
local source="$(type "non_stubbed_$cmd" | tail -n +2)"
|
||||
source="${source/non_stubbed_${cmd}/$cmd}"
|
||||
eval "$source"
|
||||
unset -f "non_stubbed_${cmd}"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
34
test.sh
Executable file
34
test.sh
Executable file
@@ -0,0 +1,34 @@
|
||||
#! /usr/bin/env bash
|
||||
|
||||
resolve_link() {
|
||||
$(type -p greadlink readlink | head -1) $1
|
||||
}
|
||||
|
||||
abs_dirname() {
|
||||
local cwd="$(pwd)"
|
||||
local path="$1"
|
||||
|
||||
while [ -n "$path" ]; do
|
||||
cd "${path%/*}"
|
||||
local name="${path##*/}"
|
||||
path="$(resolve_link "$name" || true)"
|
||||
done
|
||||
|
||||
pwd
|
||||
cd "$cwd"
|
||||
}
|
||||
|
||||
|
||||
testdir="$(abs_dirname "$0")/test"
|
||||
testfiles="$(find "$testdir" -name "*-test.sh")"
|
||||
|
||||
RET=0
|
||||
for testfile in $testfiles; do
|
||||
echo ""
|
||||
echo "running: ${testfile/#$(dirname "$testdir")\//}"
|
||||
cd "$(dirname "$testfile")"
|
||||
"$testfile"
|
||||
if [ "$?" != "0" ]; then RET=1; fi
|
||||
done
|
||||
echo ""
|
||||
exit $RET
|
||||
139
test/assert.sh
Normal file
139
test/assert.sh
Normal file
@@ -0,0 +1,139 @@
|
||||
#!/bin/bash
|
||||
# assert.sh 1.0 - bash unit testing framework
|
||||
# Copyright (C) 2009, 2010, 2011, 2012 Robert Lehmann
|
||||
#
|
||||
# http://github.com/lehmannro/assert.sh
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
export DISCOVERONLY=${DISCOVERONLY:-}
|
||||
export DEBUG=${DEBUG:-}
|
||||
export STOP=${STOP:-}
|
||||
export INVARIANT=${INVARIANT:-}
|
||||
|
||||
args="$(getopt -n "$0" -l verbose,help,stop,discover,invariant vhxdi $*)" \
|
||||
|| exit -1
|
||||
for arg in $args; do
|
||||
case "$arg" in
|
||||
-h)
|
||||
echo "$0 [-vxid] [--verbose] [--stop] [--invariant] [--discover]"
|
||||
echo "`sed 's/./ /g' <<< "$0"` [-h] [--help]"
|
||||
exit 0;;
|
||||
--help)
|
||||
cat <<EOF
|
||||
Usage: $0 [options]
|
||||
Language-agnostic unit tests for subprocesses.
|
||||
|
||||
Options:
|
||||
-v, --verbose generate output for every individual test case
|
||||
-x, --stop stop running tests after the first failure
|
||||
-i, --invariant do not measure timings to remain invariant between runs
|
||||
-d, --discover collect test suites only, do not run any tests
|
||||
-h show brief usage information and exit
|
||||
--help show this help message and exit
|
||||
EOF
|
||||
exit 0;;
|
||||
-v|--verbose)
|
||||
DEBUG=1;;
|
||||
-x|--stop)
|
||||
STOP=1;;
|
||||
-i|--invariant)
|
||||
INVARIANT=1;;
|
||||
-d|--discover)
|
||||
DISCOVERONLY=1;;
|
||||
esac
|
||||
done
|
||||
|
||||
printf -v _indent "\n\t" # local format helper
|
||||
|
||||
_assert_reset() {
|
||||
tests_ran=0
|
||||
tests_failed=0
|
||||
tests_errors=()
|
||||
tests_starttime="$(date +%s.%N)" # seconds_since_epoch.nanoseconds
|
||||
}
|
||||
|
||||
assert_end() {
|
||||
# assert_end [suite ..]
|
||||
tests_endtime="$(date +%s.%N)"
|
||||
tests="$tests_ran ${*:+$* }tests"
|
||||
[[ -n "$DISCOVERONLY" ]] && echo "collected $tests." && _assert_reset && return
|
||||
[[ -n "$DEBUG" ]] && echo
|
||||
[[ -z "$INVARIANT" ]] && report_time=" in $(bc \
|
||||
<<< "${tests_endtime%.N} - ${tests_starttime%.N}" \
|
||||
| sed -e 's/\.\([0-9]\{0,3\}\)[0-9]*/.\1/' -e 's/^\./0./')s" \
|
||||
|| report_time=
|
||||
|
||||
if [[ "$tests_failed" -eq 0 ]]; then
|
||||
echo "all $tests passed$report_time."
|
||||
else
|
||||
for error in "${tests_errors[@]}"; do echo "$error"; done
|
||||
echo "$tests_failed of $tests failed$report_time."
|
||||
fi
|
||||
tests_failed_previous=$tests_failed
|
||||
_assert_reset
|
||||
return $tests_failed_previous
|
||||
}
|
||||
|
||||
assert() {
|
||||
# assert <command> <expected stdout> [stdin]
|
||||
(( tests_ran++ ))
|
||||
[[ -n "$DISCOVERONLY" ]] && return
|
||||
# printf required for formatting
|
||||
printf -v expected "x${2:-}" # x required to overwrite older results
|
||||
result="$(eval 2>/dev/null $1 <<< ${3:-})"
|
||||
# Note: $expected is already decorated
|
||||
if [[ "x$result" == "$expected" ]]; then
|
||||
[[ -n "$DEBUG" ]] && echo -n .
|
||||
return
|
||||
fi
|
||||
[[ -n "$DEBUG" ]] && echo -n X
|
||||
result="$(sed -e :a -e '$!N;s/\n/\\n/;ta' <<< "$result")"
|
||||
[[ -z "$result" ]] && result="nothing" || result="\"$result\""
|
||||
[[ -z "$2" ]] && expected="nothing" || expected="\"$2\""
|
||||
failure="expected $expected${_indent}got $result"
|
||||
report="test #$tests_ran \"$1${3:+ <<< $3}\" failed:${_indent}$failure"
|
||||
tests_errors[$tests_failed]="$report"
|
||||
(( tests_failed++ ))
|
||||
if [[ -n "$STOP" ]]; then
|
||||
[[ -n "$DEBUG" ]] && echo
|
||||
echo "$report"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
assert_raises() {
|
||||
# assert_raises <command> <expected code> [stdin]
|
||||
(( tests_ran++ ))
|
||||
[[ -n "$DISCOVERONLY" ]] && return
|
||||
(eval $1 <<< ${3:-}) > /dev/null 2>&1
|
||||
status=$?
|
||||
expected=${2:-0}
|
||||
if [[ "$status" -eq "$expected" ]]; then
|
||||
[[ -n "$DEBUG" ]] && echo -n .
|
||||
return
|
||||
fi
|
||||
[[ -n "$DEBUG" ]] && echo -n X
|
||||
failure="program terminated with code $status instead of $expected"
|
||||
report="test #$tests_ran \"$1${3:+ <<< $3}\" failed:${_indent}$failure"
|
||||
tests_errors[$tests_failed]="$report"
|
||||
(( tests_failed++ ))
|
||||
if [[ -n "$STOP" ]]; then
|
||||
[[ -n "$DEBUG" ]] && echo
|
||||
echo "$report"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
_assert_reset
|
||||
47
test/restore-test.sh
Executable file
47
test/restore-test.sh
Executable file
@@ -0,0 +1,47 @@
|
||||
#! /usr/bin/env bash
|
||||
source "test-helper.sh"
|
||||
|
||||
#
|
||||
# restore() tests.
|
||||
#
|
||||
|
||||
|
||||
# Stubbing and restoring a bash function.
|
||||
my-name-is() { echo "My name is $@."; }
|
||||
assert "my-name-is Edward Elric" "My name is Edward Elric."
|
||||
|
||||
stub "my-name-is"
|
||||
assert "my-name-is Edward Elric" "my-name-is stub: Edward Elric"
|
||||
|
||||
restore "my-name-is"
|
||||
assert "my-name-is Edward Elric" "My name is Edward Elric."
|
||||
|
||||
|
||||
# Stubbing and restoring a executable file.
|
||||
actual_uname="$(uname)"
|
||||
stub "uname"
|
||||
assert "uname" "uname stub: "
|
||||
assert "uname -a" "uname stub: -a"
|
||||
|
||||
restore "uname"
|
||||
assert "uname" "$actual_uname"
|
||||
|
||||
|
||||
# Stubbing and restoring something that doesn't exist.
|
||||
assert_raises "cowabunga-dude" 127
|
||||
stub "cowabunga-dude"
|
||||
assert_raises "cowabunga-dude" 0
|
||||
restore "cowabunga-dude"
|
||||
assert_raises "cowabunga-dude" 127
|
||||
|
||||
|
||||
# Attempting to restore a function that wasn't stubbed.
|
||||
my-name-is() { echo "My name is $@."; }
|
||||
assert "my-name-is Edward Elric" "My name is Edward Elric."
|
||||
|
||||
restore "my-name-is"
|
||||
assert "my-name-is Edward Elric" "My name is Edward Elric."
|
||||
|
||||
|
||||
# End of tests.
|
||||
assert_end "restore()"
|
||||
40
test/stub-test.sh
Executable file
40
test/stub-test.sh
Executable file
@@ -0,0 +1,40 @@
|
||||
#! /usr/bin/env bash
|
||||
source "test-helper.sh"
|
||||
|
||||
#
|
||||
# stub() tests.
|
||||
#
|
||||
|
||||
|
||||
# Stubbing a bash function.
|
||||
my-name-is() { echo "My name is $@."; }
|
||||
assert "my-name-is Edward Elric" "My name is Edward Elric."
|
||||
|
||||
stub "my-name-is"
|
||||
assert "my-name-is" "my-name-is stub: "
|
||||
assert "my-name-is Edward" "my-name-is stub: Edward"
|
||||
assert "my-name-is Edward Elric" "my-name-is stub: Edward Elric"
|
||||
unset -f my-name-is
|
||||
|
||||
|
||||
# Stubbing a executable file.
|
||||
stub "uname"
|
||||
assert "uname" "uname stub: "
|
||||
assert "uname -h" "uname stub: -h"
|
||||
unset -f uname
|
||||
|
||||
|
||||
# Redirect stub output to STDERR.
|
||||
my-name-is() { echo "My name is $@."; }
|
||||
stub "my-name-is" STDERR
|
||||
assert "my-name-is Edward" ""
|
||||
assert "my-name-is Edward 2>&1" "my-name-is stub: Edward"
|
||||
|
||||
|
||||
# Stubbing something that doesn't exist.
|
||||
stub "cowabunga-dude"
|
||||
assert "cowabunga-dude yeah dude" "cowabunga-dude stub: yeah dude"
|
||||
|
||||
|
||||
# End of tests.
|
||||
assert_end "stub()"
|
||||
41
test/stub_and_echo-test.sh
Executable file
41
test/stub_and_echo-test.sh
Executable file
@@ -0,0 +1,41 @@
|
||||
#! /usr/bin/env bash
|
||||
source "test-helper.sh"
|
||||
|
||||
#
|
||||
# stub_and_echo() tests.
|
||||
#
|
||||
|
||||
|
||||
# Stubbing a bash function.
|
||||
my-name-is() { echo "My name is $@."; }
|
||||
assert "my-name-is Edward Elric" "My name is Edward Elric."
|
||||
|
||||
stub_and_echo "my-name-is" "Hohenheim"
|
||||
assert "my-name-is" "Hohenheim"
|
||||
assert "my-name-is Edward" "Hohenheim"
|
||||
assert "my-name-is Edward Elric" "Hohenheim"
|
||||
unset -f my-name-is
|
||||
|
||||
|
||||
# Stubbing a executable file.
|
||||
stub_and_echo "uname" "State Alchemist"
|
||||
assert "uname" "State Alchemist"
|
||||
assert "uname -h" "State Alchemist"
|
||||
unset -f uname
|
||||
|
||||
|
||||
# Redirect stub output to STDERR.
|
||||
my-name-is() { echo "My name is $@."; }
|
||||
stub_and_echo "my-name-is" "Hohenheim" STDERR
|
||||
assert "my-name-is Edward" ""
|
||||
assert "my-name-is Edward 2>&1" "Hohenheim"
|
||||
|
||||
|
||||
# Stubbing something that doesn't exist.
|
||||
stub_and_echo "cowabunga-dude" "Surf's up dude :D"
|
||||
assert "cowabunga-dude" "Surf's up dude :D"
|
||||
assert "cowabunga-dude yeah dude" "Surf's up dude :D"
|
||||
|
||||
|
||||
# End of tests.
|
||||
assert_end "stub_and_echo()"
|
||||
34
test/stub_and_eval-test.sh
Executable file
34
test/stub_and_eval-test.sh
Executable file
@@ -0,0 +1,34 @@
|
||||
#! /usr/bin/env bash
|
||||
source "test-helper.sh"
|
||||
|
||||
#
|
||||
# stub_and_eval() tests.
|
||||
#
|
||||
|
||||
|
||||
# Stubbing a bash function.
|
||||
my-name-is() { echo "My name is $@."; }
|
||||
assert "my-name-is Edward Elric" "My name is Edward Elric."
|
||||
|
||||
stub_and_eval "my-name-is" "date +%Y"
|
||||
assert "my-name-is" "$(date +%Y)"
|
||||
assert "my-name-is Edward" "$(date +%Y)"
|
||||
assert "my-name-is Edward Elric" "$(date +%Y)"
|
||||
unset -f my-name-is
|
||||
|
||||
|
||||
# Stubbing a executable file.
|
||||
stub_and_eval "uname" "date +%Y"
|
||||
assert "uname" "$(date +%Y)"
|
||||
assert "uname -h" "$(date +%Y)"
|
||||
unset -f uname
|
||||
|
||||
|
||||
# Stubbing something that doesn't exist.
|
||||
stub_and_eval "cowabunga-dude" "date +%Y"
|
||||
assert "cowabunga-dude" "$(date +%Y)"
|
||||
assert "cowabunga-dude yeah dude" "$(date +%Y)"
|
||||
|
||||
|
||||
# End of tests.
|
||||
assert_end "stub_and_eval()"
|
||||
9
test/test-helper.sh
Normal file
9
test/test-helper.sh
Normal file
@@ -0,0 +1,9 @@
|
||||
[ -n "$TEST_DEBUG" ] && set -x
|
||||
|
||||
# Set testroot variable.
|
||||
testroot="$(dirname "$BASH_SOURCE")"
|
||||
|
||||
# Include assert.sh testing library.
|
||||
source "$testroot/assert.sh"
|
||||
source "$testroot/../stub.sh"
|
||||
|
||||
Reference in New Issue
Block a user