1

I'm trying to unit test some bash scripts. One of my functions returns 1 as a false value, which I can use in if tests like

foo() {
  return 0
}

if foo; then
  echo "Passed"
fi

This is really handy for writing clean code.

However when trying to unit test this code using shunit2, the assertFalse assertion needs a string value to test.

I've got around this by writing tests like this:

test_foo() {
  local result="$(foo; echo $?)"
  assertFalse "$result"
}

but this fails when foo returns 1. The echo $? seems to be echoing an empty string, rather than the actual return code.

Any idea what's going on?

edit

This only seems to occur when set -e is set. No idea why though.

Alex Harvey
  • 14,494
  • 5
  • 61
  • 97
Michael Allen
  • 5,712
  • 3
  • 38
  • 63

3 Answers3

2

With set -e, the subshell

(foo; echo $?)

exits if foo fails—and in this case exits immediately after foo returns— so echo $? is never executed.

As a side note, some people dislike set -e (and there are good reasons for that, that you'll discover by reading the link).

gniourf_gniourf
  • 44,650
  • 9
  • 93
  • 104
0

I understand that your test function should look like:

test_foo() {
  local result="$(foo; echo $?)"
  assertFalse "[ $result == 0 ]"
}

AssertFalse Usage:

assertFalse [message] condition

You can find usage Here

Tiago Lopo
  • 7,619
  • 1
  • 30
  • 51
  • 1
    In the doc you link: _The condition can be as simple as a shell false value (the value `1` -- equivalent to `${SHUNIT_FALSE}`)._ So that's clearly not an issue. – gniourf_gniourf Feb 11 '15 at 23:26
  • I disagree, OP assumes the $result is empty when it's probably just failing assertFalse, remeber for shell `1` = `false` – Tiago Lopo Feb 11 '15 at 23:29
  • I missed his edit about -e `:D` getting late here, time to go to bed. good night! – Tiago Lopo Feb 11 '15 at 23:32
-5

Try this code:

if [ foo == 0 ]
then
   echo "passed"
else
   echo "error"
fi
HADID
  • 21
  • 1
  • 5
  • 2
    Sorry dude but that's not correct. `[` is a function that accepts parameters and returns the correct error or success code (`>0` or `0` respectively). If a function already returns a code then you can simply execute it directly in your `if`. – Michael Allen Feb 11 '15 at 23:13
  • 1
    Also, `==` is invalid inside of POSIX test (`[ ]`); POSIX specifies `=` as the comparison operator; `==` is an extension provided by some shells, but the standard doesn't mandate its existence, so using it is a needless loss of compatibility. – Charles Duffy Feb 11 '15 at 23:17
  • what is the type of your parameters? -- int, str? – HADID Feb 11 '15 at 23:18
  • In the case of `if foo; then`, `foo` is a command (in the case of this question, a function). What the `if` branches on is that command's exit status. That exit status is necessarily numeric. – Charles Duffy Feb 11 '15 at 23:19
  • 1
    ...so, `[ ]` is not part of the `if` syntax, but is just a built-in command (with behavior similar to that of any other command -- no special parser extensions) that `if` can run and check the exit status of. – Charles Duffy Feb 11 '15 at 23:23
  • `[` is a (built-in) *command*, not a function (though it's used in much the same way). – Keith Thompson Feb 11 '15 at 23:27
  • 1
    `[ foo == 0 ]` (even on shells which support `==` -- which, as described above, is not guaranteed by POSIX) always returns false, as it runs a string comparison between the strings `"foo"` and `"0"`, which aren't identical. It does **not** run the function named `foo` and compare its exit status to 0, which is what the user is trying to accomplish. As such, even as edited, this answer is entirely wrong. – Charles Duffy Feb 12 '15 at 04:31