Unit testing a bash script manipulating the working directory path bd is a bash script to conveniently jump multiple directory levels up from the current working directory instead of a tedious and possibly inaccurate cd ../../../..

Say, for example, that you are in the directory /home/user/project/src/org/main and you want to jump to project. Instead of counting the necessary levels to jump and typing cd ../../.., you can do bd -s pro (where -s is to match the start of the directory name, in this example "pro" for "project").

I came across this script in another question, and looking at the github repository I decided to jazz it up a little. But before going ahead and refactoring it, I wanted to make sure I'm not breaking anything, so I needed some sort of unit tests as a sane baseline first.

This is the main function in the bd script under testing,
and this is not for code review,
I'm including it here only for your reference in case it helps in some way:

# NOT for code review: the reference implementation under test
newpwd() {
  OLDPWD=$1
  if [ "$2" = "-s" ]
  then
    NEWPWD=`echo $OLDPWD | sed 's|\(.*/'$3'[^/]*/\).*|\1|'`
    index=`echo $NEWPWD | awk '{ print index($0,"/'$3'"); }'`
  elif [ "$2" = "-si" ]
  then
    NEWPWD=`echo $OLDPWD | sed 's|\(.*/'$3'[^/]*/\).*|\1|I'`
    index=`echo $NEWPWD | awk '{ print index(tolower($0),tolower("/'$3'")); }'`
  else
    NEWPWD=`echo $OLDPWD | sed 's|\(.*/'$2'/\).*|\1|'`
    index=`echo $NEWPWD | awk '{ print index($1,"/'$2'/"); }'`
  fi
}


What I'd like reviewed is my implementation of "unit tests" to verify the behavior of the newpwd function inside the bd script:

#!/bin/bash

# loading the "newpwd" function from the bd script, a necessary ugliness for now
. bd nonexistent &gt; /dev/null

success=0
failure=0
total=0

assertEquals() {
    ((total++))
    expected=$1
    actual=$2
    if [[ $expected = $actual ]]; then
        ((success++))
    else
        ((failure++))
        echo "Assertion failed: $expected != $actual" &gt;&amp;2
        caller 0
        echo
    fi
}

sample=/home/user/project/src/org/main/site/utils/file/reader/whatever

# test run with no args
newpwd $sample
assertEquals $sample $NEWPWD
assertEquals 0 $index

# test run with exact match
newpwd $sample src
assertEquals /home/user/project/src/ $NEWPWD
assertEquals 19 $index

# test run with prefix but no -s so not found
newpwd $sample sr
assertEquals $sample $NEWPWD
assertEquals 0 $index

# test run with prefix found
newpwd $sample -s sr
assertEquals /home/user/project/src/ $NEWPWD
assertEquals 19 $index

# test run with prefix not found because case sensitive
newpwd $sample -s Sr
assertEquals $sample $NEWPWD
assertEquals 0 $index

# test run with prefix found thanks to -si
newpwd $sample -si Sr
assertEquals /home/user/project/src/ $NEWPWD
assertEquals 19 $index

sample='/home/user/my project/src'

# test run with space in dirname
newpwd "$sample" -s my
assertEquals '/home/user/my project/' "$NEWPWD"
assertEquals 11 $index

red='\e[0;31m'
green='\e[0;32m'
nocolor='\e[0m'

echo
[[ $failure = 0 ]] &amp;&amp; printf $green || printf $red
echo "Tests run: $total ($success success, $failure failed)"
printf $nocolor
echo


My questions:


Is this easy to read? If not, how to improve it?
Is this a good way to test stuff in Bash? Is there a better way? I'd rather not add external dependencies to the project though, I'm looking for something ultra-light, or a technique
Are there any corner cases I missed?
Any other improvement ideas?
Just 2 cents:


I'd quote the right hand side of the [[ ... = ... ]] to avoid pattern interpretation. Cf.

x=123
y=*2*
[[ $x =  $y  ]] &amp;&amp; echo Equal without quotes
[[ $x = "$y" ]] || echo Not equal with quotes

I like naming the tests. I'd probably add a third parameter to assertEquals and include it in the report. It also improves readability. Inspired by Test::More for Perl.