mbland / go-script-bash

Framework for writing modular, discoverable, testable Bash scripts
ISC License
95 stars 16 forks source link

File assertions overwrite the value of the `output` and `lines` variables #242

Open nkakouros opened 6 years ago

nkakouros commented 6 years ago

Due diligence

Framework, Bash, and operating system version information

_GO_CORE_VERSION:         v1.7.0
BASH_VERSION:             4.4.19(1)-release
OSTYPE:                   linux-gnu
_GO_PLATFORM_ID:          arch
_GO_PLATFORM_VERSION_ID:

Description

The function __assert_file that is used by file assertion functions sets the output and lines variables to the content of the file under test in order to take advantage of the other "regular" assert_ functions that operate on these variables. In a test, however, this does not allow the use of a "regular" assertion after a file assertion. For instance, the following will fail:

@test 'demo' {
  run 'ls /'
  assert_file_matches '/etc/passwd' 'root'
  assert_output_matches 'etc'
}

I tried to add around the main body of __assert_file an additional step of storing the output and lines variables if they are already set and then putting back their original values just before __assert_file exits (commented out lines below):

__assert_file() {
  local assertion="$1"
  local file_path="$2"
  shift 2
  local constraints=("$@")

  # if [[ "${output-GO_SCRIPT_UNDEFINED}" != 'GO_SCRIPT_UNDEFINED' ]]; then
  #   old_output="$output"
  #   old_lines=("${lines[@]}")
  # fi

  if ! set_bats_output_and_lines_from_file "$file_path"; then
    return '1'
  fi

  if [[ "$assertion" == 'assert_matches' ]]; then
    if [[ "$#" -ne '1' ]]; then
      printf 'ERROR: %s takes exactly two arguments\n' "${FUNCNAME[1]}" >&2
      return '1'
    fi
    constraints=("$1" "$output" "The content of '$file_path'")
  fi

  "$assertion" "${constraints[@]}"

  # if [[ "${old_output-GO_SCRIPT_UNDEFINED}" != 'GO_SCRIPT_UNDEFINED' ]]; then
    # output="$old_output"
    # lines=("${old_lines[@]}")
  # fi
}

This works but some tests in tests/assertions.bats fail because they rely on the current behavior.

There are two workarounds this without the above change. First option, a test that uses the assert_file_* functions can store output somewhere safe before calling the assert_file_* function.

The second option would be to simply reorder the checks in the test function, so that file assertions go always last. In the above sample test, assert_output_matches should go before assert_file_matches. But this might be a bit counter-intuitive, depending on the application.

Both options require that the behavior is documented so that the developer knows what to do. But to me the best solution seems to be to fix __assert_lines.