shellspec/shellspec

View on GitHub
libexec/shellspec-executor.sh

Summary

Maintainability
Test Coverage
F
0%
#!/bin/sh
#shellcheck disable=SC2004

set -eu

# Close the file descriptor for time command
exec 2>&3

# shellcheck source=lib/libexec/executor.sh
. "${SHELLSPEC_LIB:-./lib}/libexec/executor.sh"

if [ "$SHELLSPEC_KCOV" ]; then
  # shellcheck source=lib/libexec/kcov-executor.sh
  . "${SHELLSPEC_LIB:-./lib}/libexec/kcov-executor.sh"
elif [ "$SHELLSPEC_WORKERS" -gt 0 ]; then
  # shellcheck source=lib/libexec/parallel-executor.sh
  . "${SHELLSPEC_LIB:-./lib}/libexec/parallel-executor.sh"
else
  # shellcheck source=lib/libexec/serial-executor.sh
  . "${SHELLSPEC_LIB:-./lib}/libexec/serial-executor.sh"
fi
use constants trim
load grammar

translator() {
  translator="$SHELLSPEC_LIBEXEC/shellspec-translate.sh"
  eval "$SHELLSPEC_SHELL" "\"$translator\"" ${1+'"$@"'}
}

error_handler() {
  "$SHELLSPEC_TRAP" 'show_break_point' INT

  specfile='' lineno='' errors='' error_handler_status=0

  while IFS= read -r line; do
    case $line in
      ${SYN}shellspec_marker:*)
        if [ "$errors" ]; then
          detect_unexpected_error "$specfile" "$lineno" "$errors"
          errors=''
        fi
        line=${line#"$SYN"shellspec_marker:}
        specfile=${line% *} lineno=${line##* }
        ;;
      Syntax\ error:*) putsn "${LF}${line}"; error_handler_status=1 ;;
      # Workaround for posh 0.6.13 when executed as a background process
      *internal\ error:\ j_async:\ bad\ nzombie*) ;;
      # Workaround for loksh <= 6.7.2 when executed as a background process
      *internal\ error:\ j_set_async:\ bad\ nzombie*) ;;
      # Workaround for ksh with kcov
      *version*sh*AT\&T\ Research*) ;;
      # Workaround for ksh 2020 with kcov
      kcov:\ error:\ *is\ not\ an\ integer*) ;;
      *) errors="${errors}${line}${LF}" error_handler_status=1
    esac
  done

  if [ "$error_handler_status" -ne 0 ]; then
    detect_unexpected_error "$specfile" "$lineno" "$errors"
  fi
  return $error_handler_status
}

show_break_point() {
  abort "${LF}Break at ${specfile:-}:${lineno:-}" 2>&4
}

detect_unexpected_error() {
  puts "$3"

  case $2 in
    ---) set -- "$1" '' ;;
    BOF) set -- "$1" 1  "$3" ;;
    EOF) return 0 ;; # no error
  esac

  if [ "$2" ]; then
    range=$(detect_range "$2" < "$1")
    if [ "$3" ]; then
      putsn "${LF}Unexpected output to stderr occurred at line $range in '$1'"
    else
      putsn "${LF}Unexpected exit at line $range in '$1'"
    fi
  else
    [ "$1" ] && set -- " occurred in '$1'"
    putsn "${LF}Unexpected error occurred (syntax error?)$1"
  fi
  nap
}

is_separetor_statement() {
  is_begin_block "$1" || is_end_block "$1" || is_oneline_example "$1"
}

detect_range() {
  lineno_begin=$1 lineno_end='' lineno=0
  while IFS= read -r line || [ "$line" ]; do
    trim line "$line"
    line=${line%% *} lineno=$(($lineno + 1))
    [ "$lineno" -lt "$1" ] && continue
    if is_separetor_statement "$line" ; then
      [ "$lineno" -ne "$1" ] && lineno_end=$(($lineno - 1)) && break
      lineno_begin=$lineno
    fi
  done
  echo "${lineno_begin}-${lineno_end:-$lineno}"
}

set +e
( ( ( ( (
  ( set -e; exec 3>&- 4>&- 5>&-; executor "$@" ) ) 2>&1 >&4; echo $? >&5 ) \
  | ( set -e; error_handler ) >&3; echo $? >&5 ) 5>&1) \
  | (
      read -r xs1 && [ "$xs1" -ne 0 ] && exit "$xs1"
      read -r xs2 && [ "$xs2" -ne 0 ] && exit "$xs2"
      exit 0
    )
) 4>&1