sstephenson / bats

Bash Automated Testing System
MIT License
7.12k stars 517 forks source link

I have a function isUbuntu #114

Closed xenonpd closed 9 years ago

xenonpd commented 9 years ago
function isUbuntu
{
  if [[ -n $(grep -i ubuntu /etc/issue) ]]
  then
    return 0
  else
    return 1
  fi

Please how do I test the negative case? Even if I embed an eval for isUbuntu inside a function isFalse, your framework picks up the $? == 1 inside the function from that eval and calls it a failure. Please I need to program these negative cases.

xenonpd commented 9 years ago

Please reply to my other email at xeno.campanoli@gmail.com

bittorf commented 9 years ago

so you have to change the file OR have the filename as argument. also, better use this:

isUbuntu() { grep -sqi ubuntu /etc/issue }

ricardo-perezb commented 9 years ago

Within the test implementation you can write:

@test myTest1 {
  isUbuntu && false || true
 }

That will inverse the logic of the function.

mislav commented 9 years ago

@xenonpd That's a very good question.

The problem is that some function test contents of system files, such as /etc/issue, and you can't stub out fake contents of those files as it would require overwriting them (and needing root privileges).

One approach that you could take is change your program to always use a special variable name whenever it's accessing filesystem paths starting at the root directory:

isUbuntu() {
  grep -qi ubuntu "${MYPROGRAM_FAKE_ROOT}/etc/issue" 2>/dev/null
}

Of course, the MYPROGRAM_FAKE_ROOT variable is blank by default. But in test mode, you could set it to a temporary location before starting your program:

MYPROGRAM_FAKE_ROOT="${BATS_TMPDIR}/root"

And then, you can create a fake /etc/issue file to test different variations of how isUbuntu should behave:

mkdir -p "${MYPROGRAM_FAKE_ROOT}/etc"
cat > "${MYPROGRAM_FAKE_ROOT}/etc/issue" <<<"fedora"
run isUbuntu

Of course, call the MYPROGRAM_FAKE_ROOT with a name that's specific to your program, so there's no chance that this variable is actually set in someone's real environment.

etienneq commented 8 years ago

@mislav I think that does not really answer the original question...or at least not completely. I have a similar case were I want to test a function's different return values. If 1 is returned that's intercepted by bats and interpreted as a failure. So it's not about stubbing. Take this example:

isANumber() {
    local number=$1
    return `echo "${number}" | grep -q -P -e "^[0-9]+$"`
}

So I would expect these tests to pass:

@test "test a string" {
    isANumber abc
    [ "$?" -eq 1 ]
}

@test "test a number" {
    isANumber 123
    [ "$?" -eq 0 ]
}

But the first test fails.

mislav commented 8 years ago

@etienneq You should be using run like so:

run isANumber abc
[ "$status" -eq 1 ]

Also, your check for a number could be simpler:

isANumber() {
  [ "${1#-}" -ge 0 ] 2>/dev/null
}
etienneq commented 8 years ago

@mislav In my example isANumber() is not the name of a script but a function inside some script. So calling that function with run produces an error.

The logic of isANumber() is derived from real life code and simplified on purpose for this post. Just think of it as a function that has a range of possible integer return values that I want to test. The logic inside that function should not matter here.