sstephenson / bats

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

line 256: BATS_ERROR_STACK_TRACE: bad array subscript #109

Open aw-was-here opened 9 years ago

aw-was-here commented 9 years ago

I've got a unit test I'm writing that is causing bats to crash on OS X Mavericks (bash 3.2.53) with a bad subscript. Some sketchy variable handling in the routine being tested is causing bash to throw up. Here's the relevant code in its entirety:

function hadoop_debug
{
  if [[ -n "${HADOOP_SHELL_SCRIPT_DEBUG}" ]]; then
    echo "DEBUG: $*" 1>&2
  fi
}

function hadoop_add_classpath
{
  # However, with classpath (& JLP), we can do dedupe
  # along with some sanity checking (e.g., missing directories)
  # since we have a better idea of what is legal
  #
  # for wildcard at end, we can
  # at least check the dir exists
  if [[ $1 =~ ^.*\*$ ]]; then
    local mp=$(dirname "$1")
    if [[ ! -d "${mp}" ]]; then
      hadoop_debug "Rejected CLASSPATH: $1 (not a dir)"
      return 1
    fi

    # no wildcard in the middle, so check existence
    # (doesn't matter *what* it is)
  elif [[ ! $1 =~ ^.*\*.*$ ]] && [[ ! -e "$1" ]]; then
    hadoop_debug "Rejected CLASSPATH: $1 (does not exist)"
    return 1
  fi
  if [[ -z "${CLASSPATH}" ]]; then
    CLASSPATH=$1
    hadoop_debug "Initial CLASSPATH=$1"
  elif [[ ":${CLASSPATH}:" != *":$1:"* ]]; then
    if [[ "$2" = "before" ]]; then
      CLASSPATH="$1:${CLASSPATH}"
      hadoop_debug "Prepend CLASSPATH: $1"
    else
      CLASSPATH+=:$1
      hadoop_debug "Append CLASSPATH: $1"
    fi
  else
    hadoop_debug "Dupe CLASSPATH: $1"
  fi
  return 0
}

function hadoop_add_to_classpath_userpath
{
  # Add the user-specified HADOOP_CLASSPATH to the
  # official CLASSPATH env var if HADOOP_USE_CLIENT_CLASSLOADER
  # is not set.
  # Add it first or last depending on if user has
  # set env-var HADOOP_USER_CLASSPATH_FIRST
  # we'll also dedupe it, because we're cool like that.
  #
  declare -a array
  declare -i c=0
  declare -i j
  declare -i i

  if [[ -n "${HADOOP_CLASSPATH}" ]]; then
    # I wonder if Java runs on VMS.
    for i in $(echo "${HADOOP_CLASSPATH}" | tr : '\n'); do
      array[$c]=$i
      ((c=c+1))
    done
    ((j=c-1))

    if [[ -z "${HADOOP_USE_CLIENT_CLASSLOADER}" ]]; then
      if [[ -z "${HADOOP_USER_CLASSPATH_FIRST}" ]]; then
        for ((i=j; i>=0; i--)); do
          hadoop_add_classpath "${array[$i]}" after
        done
      else
        for ((i=0; i<=j; i++)); do
          hadoop_add_classpath "${array[$i]}" before
        done
      fi
    fi
  fi
}

setup() {

  TMP=../../../target/test-dir/bats.$$.${RANDOM}
  mkdir -p ${TMP}
  TMP=$(cd -P -- "${TMP}" >/dev/null && pwd -P)
  export TMP
  TESTBINDIR=$(cd -P -- "$(pwd)" >/dev/null && pwd -P)
  HADOOP_LIBEXEC_DIR=${TESTBINDIR}/../../main/bin
  HADOOP_LIBEXEC_DIR=$(cd -P -- "${HADOOP_LIBEXEC_DIR}" >/dev/null && pwd -P)

  # shellcheck disable=SC2034
  HADOOP_SHELL_SCRIPT_DEBUG=true
  unset HADOOP_CONF_DIR
  unset HADOOP_HOME
  unset HADOOP_PREFIX

  echo "bindir: ${TESTBINDIR}" 2>&1

  mkdir -p "${TMP}"

  # shellcheck disable=SC2034
  QATESTMODE=true

  pushd "${TMP}" >/dev/null
}

teardown() {
  popd >/dev/null
  rm -rf "${TMP}"
}

freetheclasses () {
  local j

  for j in HADOOP_CLASSPATH  \
      HADOOP_USE_CLIENT_CLASSLOADER \
      HADOOP_USER_CLASSPATH_FIRST \
      CLASSPATH; do
      unset ${!j}
  done
}

createdirs () {
  local j

  for j in new old foo bar baz; do
    mkdir -p ${TMP}/${j}
  done
}

@test "hadoop_add_to_classpath_userpath (only)" {
   freetheclasses
   createdirs
   HADOOP_CLASSPATH=${TMP}/new
   hadoop_add_to_classpath_userpath
   [ "${CLASSPATH}" = "${TMP}/new" ]
}
krallin commented 8 years ago

I'm running into a similar issue, albeit with a simpler reproduction:

@test "Bad array subscript" {
  now="$(date)"
  ts="$((now - 3600))"  # 1 hour old
}

Will throw:

not ok 3 Bad array subscript
/usr/local/libexec/bats-exec-test: line 258: BATS_ERROR_STACK_TRACE: bad array subscript

(note: of course, this fails because $(date) isn't actually an integer, but arguably that should cause the test to fail, not crash the test runner)