-
Notifications
You must be signed in to change notification settings - Fork 25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make it POSIX #56
Make it POSIX #56
Changes from all commits
2e68296
0890d03
cc6acc9
ecde1bd
ffbd941
ce61f72
f6b601d
5cb698f
247c49e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,41 +1,51 @@ | ||
#!/usr/bin/env bash | ||
VERSION=0.1.2 | ||
examples=0 | ||
failures=0 | ||
test_indent=0 | ||
red="\033[0;31m" | ||
green="\033[0;32m" | ||
norm="\033[0m" | ||
# | ||
: Use one of: bash, dash, or ksh93 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is simply a comment, correct? Is there a reason it begins with a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @hlangeveld A specific reason you left off There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know what I need to do to zsh to make it accept pure POSIX shell. |
||
|
||
indent() { | ||
printf '%*s' $(((test_indent - 1) * 2)) | ||
printf '%*s' $(( (test_indent - 1) * 2)) | ||
} | ||
|
||
# 'echo -e' is not a POSIX feature. | ||
# This helps us to work around that. | ||
echo_needs_minus_e(){ | ||
echo "\010"| (read a; [ ${#a} -ne 1 ]) | ||
} | ||
|
||
if echo_needs_minus_e; then | ||
echoe() { echo -e "$@"; } | ||
else | ||
echoe() { echo "$@"; } | ||
fi | ||
|
||
iecho() { | ||
indent && echo "$@" | ||
indent && echoe "$@" | ||
} | ||
|
||
sanitize() { | ||
IFS= echo -e "$1" | tr '\n' 'n' | tr "'" 'q' | ||
IFS= echoe "$1" | tr '\n' 'n' | tr "'" 'q' | ||
} | ||
|
||
describe() { | ||
((test_indent += 1)) | ||
: $((test_indent += 1)) | ||
iecho "$1" | ||
} | ||
|
||
end() { | ||
((test_indent -= 1)) | ||
: $((test_indent -=1 )) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Whitespace here is inconsistent with the near-identical line 29 above. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see. Will fix. |
||
if [ $test_indent -eq 0 ]; then | ||
[ $failures -eq 0 ] | ||
fi | ||
} | ||
|
||
end_describe() { | ||
iecho "Warning: end_describe will be deprecated in shpec 1.0. Please use end instead." | ||
iecho "Warning: end_describe will be deprecated in shpec 1.0." \ | ||
"Please use end instead." | ||
end | ||
} | ||
|
||
# Beware: POSIX shells are not required to accept | ||
# any identifier as a function name. | ||
|
||
stub_command() { | ||
body="${2:-:}" | ||
eval "$1() { $body; }" | ||
|
@@ -44,97 +54,138 @@ stub_command() { | |
unstub_command() { unset -f "$1"; } | ||
|
||
it() { | ||
((test_indent += 1)) | ||
((examples += 1)) | ||
: $((test_indent += 1)) | ||
: $((examples += 1)) | ||
assertion="$1" | ||
} | ||
|
||
assert() { | ||
case "x$1" in | ||
|
||
xequal ) | ||
print_result "[[ '$(sanitize "$2")' = '$(sanitize "$3")' ]]" "Expected [$2] to equal [$3]";; | ||
|
||
print_result "[ '$(sanitize "$2")' = '$(sanitize "$3")' ]" \ | ||
"Expected [$2] to equal [$3]" | ||
;; | ||
xunequal ) | ||
print_result "[[ '$(sanitize "$2")' != '$(sanitize "$3")' ]]" "Expected [$2] not to equal [$3]";; | ||
|
||
print_result "[ '$(sanitize "$2")' != '$(sanitize "$3")' ]" \ | ||
"Expected [$2] not to equal [$3]" | ||
;; | ||
xgt ) | ||
print_result "[[ $2 -gt $3 ]]" "Expected [$2] to be > [$3]";; | ||
|
||
print_result "[ $2 -gt $3 ]" \ | ||
"Expected [$2] to be > [$3]" | ||
;; | ||
xlt ) | ||
print_result "[[ $2 -lt $3 ]]" "Expected [$2] to be < [$3]";; | ||
|
||
print_result "[ $2 -lt $3 ]" \ | ||
"Expected [$2] to be < [$3]" | ||
;; | ||
xmatch ) | ||
print_result "[[ '$2' =~ $3 ]]" "Expected [$2] to match [$3]";; | ||
|
||
print_result "case '$2' in *$3*) :;; *) false;; esac" \ | ||
"Expected [$2] to match [$3]" | ||
;; | ||
xno_match ) | ||
print_result "[[ ! '$2' =~ $3 ]]" "Expected [$2] not to match [$3]";; | ||
|
||
print_result "case '$2' in *$3*) false ;; *) :;; esac" \ | ||
"Expected [$2] not to match [$3]" | ||
;; | ||
xpresent ) | ||
print_result "[[ -n '$2' ]]" "Expected [$2] to be present";; | ||
|
||
print_result "[ -n '$2' ]" \ | ||
"Expected [$2] to be present" | ||
;; | ||
xblank ) | ||
print_result "[[ -z '$2' ]]" "Expected [$2] to be blank";; | ||
print_result "[ -z '$2' ]" \ | ||
"Expected [$2] to be blank" | ||
;; | ||
|
||
xfile_present ) | ||
print_result "[[ -e $2 ]]" "Expected file [$2] to exist";; | ||
|
||
print_result "[ -e $2 ]" \ | ||
"Expected file [$2] to exist" | ||
;; | ||
xfile_absent ) | ||
print_result "[[ ! -e $2 ]]" "Expected file [$2] not to exist";; | ||
|
||
print_result "[ ! -e $2 ]" \ | ||
"Expected file [$2] not to exist" | ||
;; | ||
xsymlink ) | ||
link="$(readlink $2)" | ||
print_result "[[ '$link' = '$3' ]]" "Expected [$2] to link to [$3], but got [$link]";; | ||
|
||
print_result "[ '$link' = '$3' ]" \ | ||
"Expected [$2] to link to [$3], but got [$link]" | ||
;; | ||
xtest ) | ||
print_result "$2" "Expected $2 to be true";; | ||
|
||
print_result "$2" \ | ||
"Expected $2 to be true" | ||
;; | ||
* ) | ||
if type "$1" 2>/dev/null | grep -q 'function'; then | ||
matcher="$1"; shift | ||
$matcher "$@" | ||
else | ||
print_result false "Error: Unknown matcher [$1]" | ||
fi;; | ||
|
||
fi | ||
;; | ||
esac | ||
} | ||
|
||
print_result() { | ||
if eval "$1"; then | ||
iecho -e "$green$assertion$norm" | ||
iecho "$green$assertion$norm" | ||
else | ||
((failures += 1)) | ||
iecho -e "$red$assertion" | ||
iecho -e "($2)$norm" | ||
: $((failures += 1)) | ||
iecho "$red$assertion" | ||
iecho "($2)$norm" | ||
fi | ||
} | ||
|
||
SHPEC_ROOT=${SHPEC_ROOT:-$([[ -d './shpec' ]] && echo './shpec' || echo '.')} | ||
|
||
case "$1" in | ||
|
||
-v|--version ) | ||
|
||
echo "$VERSION";; | ||
|
||
* ) | ||
|
||
matcher_files="$(find "$SHPEC_ROOT/matchers" -name '*.sh' 2>/dev/null)" | ||
|
||
for matcher_file in $matcher_files; do | ||
. "$matcher_file" | ||
done | ||
|
||
files="${@:-$(find $SHPEC_ROOT -name '*_shpec.sh')}" | ||
|
||
time for file in $files; do | ||
. "$file" | ||
done | ||
|
||
[ $failures -eq 0 ] && color=$green || color=$red | ||
echo -e "${color}${examples} examples, ${failures} failures${norm}" | ||
shpec() { | ||
( | ||
VERSION=0.1.2posix | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's keep the version numbers compliant with semver, i.e. just MAJOR.MINOR.PATCH. I think a minor version bump is appropriate here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I concur, the introduction of the function deserve a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will do. |
||
examples=0 | ||
failures=0 | ||
test_indent=0 | ||
red="\033[0;31m" | ||
green="\033[0;32m" | ||
norm="\033[0m" | ||
|
||
SHPEC_ROOT=${SHPEC_ROOT:-$([ -d './shpec' ] && echo './shpec' || echo '.')} | ||
case "$1" in | ||
( -v | --version ) echo "$VERSION" | ||
;; | ||
( * ) | ||
matcher_files="$( | ||
find "$SHPEC_ROOT/matchers" -name '*.sh' 2>/dev/null | ||
)" | ||
|
||
for matcher_file in $matcher_files; do | ||
. "$matcher_file" | ||
done | ||
|
||
if [ $# -gt 0 ] ; then | ||
: \$1="'$1'" \${#1}="'${#1}'" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you explain this line? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Which line do you refer? (since we get a ten line diff?) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm referring to line 160. Github will always put the comment directly below the line in question. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Line 160, I presume. That is a left over from a 'live comment'.
Therefore it's useful for showing the value of parameters during execution, and will It served its purpose, and should go. |
||
files="${@}" | ||
else | ||
files=$( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please quote this in the same manner as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The two should be the same. I think that either way should work. I've become more confident with $( ... ) constructs, and believe that no quoting is needed in either case. |
||
find $SHPEC_ROOT -name '*_shpec.sh' | ||
) | ||
fi | ||
|
||
for file in $files; do | ||
echo >& 2 "$file" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please remove this line. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed |
||
. "$file" || exit | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you explain the intent behind the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On 04/13/15 04:07, Ryland Herrick wrote:
Hmm... The idea was catching errors in sourcing $file. However, this would also consider any non-zero $failure count I will think about alternatives here, but for now it just Cheers, |
||
done | ||
|
||
[ $failures -eq 0 ] && color=$green || color=$red | ||
echoe "${color}${examples} examples, ${failures} failures${norm}" | ||
|
||
times | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Didn't even know about There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On 04/13/15 04:07, Ryland Herrick wrote:
It's the only thing garantueed to be around. Of course, there's the Even so, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
[ $failures -eq 0 ] | ||
exit | ||
;; | ||
esac | ||
) | ||
} | ||
|
||
[ $failures -eq 0 ] | ||
( | ||
_progname=shpec | ||
_pathname=$( command -v $0 ) | ||
_cmdname=${_pathname##*/} | ||
_main=shpec | ||
|
||
esac | ||
case $_progname in (${_cmdname%.sh}) $_main "$@";; esac | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would you mind explaining exactly how this works? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When we run the 'shpec' script, we want to make sure that the '$0' basename matches the name we've chosen. ( 'shpec' ) It's a variation on idiom that I have used quite a lot. There is a long standing So we need to get rid of the directory path, and we then need to match against So, instead of the external First, Short version, if the name of the script matches 'shpec' or 'shpec.sh', we call the 'shpec' function. |
||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,7 +35,8 @@ describe "shpec" | |
|
||
describe "equality matcher" | ||
it "handles newlines properly" | ||
string_with_newline_char="new\nline" | ||
string_with_newline_char="new | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Was this intentionally changed? This test was added specifically for #23. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On 04/13/15 04:08, Ryland Herrick wrote:
I've added a comment to the issue. POSIX just sees two characters there, not a newline. Bash and ksh support 'ansi-c' strings with the $'...' string notation. I would recommend to use initialised string constants using
If we do this once at the top of
etc., etc. Cheers, |
||
line" | ||
multiline_string='new | ||
line' | ||
assert equal "$multiline_string" "$string_with_newline_char" | ||
|
@@ -64,16 +65,25 @@ line' | |
|
||
describe "passing through to the test builtin" | ||
it "asserts an arbitrary algebraic test" | ||
assert test "[[ 5 -lt 10 ]]" | ||
assert test "[ 5 -lt 10 ]" | ||
end | ||
end | ||
|
||
describe "stubbing commands" | ||
# only bash lets us redefine 'exit', so use 'false' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ce61f72 contains the reasoning behind this test. My preference is to leave that kind of thing in git, and not in the code itself. Additionally, I would say that this initial test is unnecessary; the following two tests cover both the stubbed functionality and the original functionality. If any part of that stub/unstub process fails, one of these commands will indicate so. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On 04/13/15 04:16, Ryland Herrick wrote:
Agreed.
|
||
it "check original working of the stub" | ||
false | ||
assert equal "$?" 1 | ||
end | ||
it "stubs to the null command by default" | ||
stub_command "exit" | ||
exit # doesn't really exit | ||
stub_command "false" | ||
false # doesn't do anything | ||
assert equal "$?" 0 | ||
unstub_command "exit" | ||
unstub_command "false" | ||
end | ||
it "preserves the original working of the stub" | ||
false | ||
assert equal "$?" 1 | ||
end | ||
|
||
it "accepts an optional function body" | ||
|
@@ -108,14 +118,13 @@ line' | |
end | ||
|
||
describe "exit codes" | ||
shpec_cmd="$SHPEC_ROOT/../bin/shpec" | ||
it "returns nonzero if any test fails" | ||
$shpec_cmd $SHPEC_ROOT/etc/failing_example &> /dev/null | ||
shpec $SHPEC_ROOT/etc/failing_example > /dev/null 2>& 1 | ||
assert unequal "$?" "0" | ||
end | ||
|
||
it "returns zero if a suite passes" | ||
$shpec_cmd $SHPEC_ROOT/etc/passing_example &> /dev/null | ||
shpec $SHPEC_ROOT/etc/passing_example > /dev/null 2>& 1 | ||
assert equal "$?" "0" | ||
end | ||
end | ||
|
@@ -133,18 +142,17 @@ line' | |
end | ||
|
||
describe "commandline options" | ||
shpec_cmd="$SHPEC_ROOT/../bin/shpec" | ||
|
||
describe "--version" | ||
it "outputs the current version number" | ||
message="$($shpec_cmd --version)" | ||
message="$(shpec --version)" | ||
assert match "$message" "$(cat $SHPEC_ROOT/../VERSION)" | ||
end | ||
end | ||
|
||
describe "-v" | ||
it "outputs the current version number" | ||
message="$($shpec_cmd -v)" | ||
message="$(shpec -v)" | ||
assert match "$message" "$(cat $SHPEC_ROOT/../VERSION)" | ||
end | ||
end | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this line have a purpose?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A shell script traditionally started with just ': '. Before kernels interpreted the hasbang,
the shell would see if the first character(s) equalled ':' or ': '. In that case it would fork itself and feed itself the script.
I don't know how I ended up adding an empty comment up there.