# vim:set ft=sh et sw=2 ts=2:
#
# Common config/functions for tests using xtest_setup
#
# Loads shtest_setup, xtest_setup, and sets restrictive environment
# (eg. PATH='', IFS=-).  xwrap function captures nmg logs, and stderr,
# and registers both as 1st/2nd shtest::check_reg_files (for ftest[2])
#
# To use:
#   - source this file
#   - define "xmain()" - return !0 on failure
#   - call xstart "$@"
#
# Provided functions:
#
#   xwrap <cmd> [ <args>... ]
#     Captures nmg logging to $XLOG, stderr to $XERR
#
#   xwrap2 <tag> <cmd> [ <args>...]
#     Same as xwrap, but calls shtest::prefix "<cmd>(<tag>) - " first
#
#   xrm <file> ...
#     Removes <file>s using command -p to avoid PATH
#
#   xread_value <retvar> (<stdin)
#     Reads stdin into <retvar> (verbatim, but strips final newline)
#
#   xread_value2 <retvar> (<stdin)
#     Reads stdin into <retvar> (verbatim, but adds final newline)
#
#   xload_script <file> [ <args>... ]
#     Parse-tests, and sources <file> with <args>, calling xtest::fail with
#     feedback if it exits.
#
#   xstart [ <args>... ]
#     Main entry, returns result of xmain
#
# shellcheck shell=bash disable=SC1090,SC2123

# load common.conf
TEST_COMMON=${TEST_COMMON:-conf/common.conf}
{ [[ -r ${TEST_COMMON} ]] && . "${TEST_COMMON}"; } ||
  { echo >&2 "Unable to load ${TEST_COMMON}"; exit 2; }

{ [[ ${XTEST_SETUP} ]] && . "${XTEST_SETUP}"; } ||
  { echo >&2 "Unable to load xtest_setup"; exit 2; }

[[ $EUID == 0 ]] && xtest::fail "Never run as root!"

# need output directory
[[ $TEST_OUT && -d $TEST_OUT ]] || xtest::fail "\$TEST_OUT is unset/missing!"
[[ $TEST_OUT =~ ^/ ]] && xtest::fail "\$TEST_OUT must be relative!"

NMG_XTEST_BASE=${0##*/}
XLOG="$TEST_OUT/${NMG_XTEST_BASE}.log"
XERR="$TEST_OUT/${NMG_XTEST_BASE}.err"
unset NMG_XTEST_BASE

xwrap() { # <cmd> [ <args>... ]
  local _xcmd=${1-}
  [[ ${_xcmd} ]] || xtest::fail "xwrap: missing <cmd>"
  shift
  "${_xcmd}" &>"${XERR}" 4>"${XLOG}" "$@"
}

xwrap2() { # <tag> <func> [ <args>... ]
  local _xtag=${1-} _xcmd=${2-}
  [[ ${_xcmd} ]] || xtest::fail "xwrap: missing <cmd>"
  shtest::prefix "${_xcmd}(${_xtag}) - "
  shift 2
  "${_xcmd}" &>"${XERR}" 4>"${XLOG}" "$@"
}

xrm() {
  local f
  for f in "$@"; do [[ $f ]] && command -p rm -f "$f"; done
  return 0
}

xread_value() {
  # <retvar> <stdin
  local IFS; unset IFS
  read -r -d '' "$1" || :
}

xread_value2() {
  # <retvar> <stdin
  local REPLY IFS; unset IFS
  read -r -d '' || :
  printf -v "$1" '%s' "${REPLY}"
}

xcat() {
  # <stdin
  local REPLY IFS; unset IFS
  read -r -d '' || printf '%s' "${REPLY}"
}

xnmg::_onexit() { # <rc>
  local rc=${1:-?}

  [[ ${XERR-} && ${XLOG-} ]] || return 0

  [[ -e ${XERR} || -e ${XLOG} ]] && {
    shtest::alert "Tests did not complete: exit ${rc}"

    # early exit (exit, unbound etc) would leave these files, show them
    [[ -s ${XERR} ]] && {
      shtest::alert "==== stdout / stderr ==="
      shtest::alert "$(< "${XERR}")"
    }
    [[ -s ${XLOG} ]] && {
      shtest::alert "==== nmg log ===="
      shtest::alert "$(< "${XLOG}" >&2)"
    }
  }

  # cleanup
  xrm "${XERR}" "${XLOG}"
  return 0
}

xnmg::_xload_check() {
  local xrc="exit 0" IFS; unset IFS

  [[ -s ${XERR}-flag ]] &&
    { read -r -d '' xrc || :; } 2>/dev/null < "${XERR}-flag"
  xrm "${XERR}-flag"

  # everything work?
  [[ ${xrc} == "result 0" && ! -s ${XLOG} && ! -s ${XERR} ]] && return 0

  # nope, cleanup and fail
  shtest::cleanup

  # avoid unexpected exit warning if no errors
  [[ -s ${XLOG} ]] || xrm "${XLOG}"
  [[ -s ${XERR} ]] || xrm "${XERR}"

  [[ ${xrc} == "result 0" ]] && xrc="output/log"

  xtest::fail "  Loading '$1' failed (${xrc})"
}

xload_script() {
  # <file> [ <args>... ]

  [[ -z ${1-} ]] && return 0

  shtest::title "Loading script"

  # ensure includes pass parse test
  shtest::parse "$1" || shtest::fatal

  xrm "${XERR}-flag"
  ( # check for exit/errors
    shtest::reset
    shtest::strict off
    xwrap source "$@"
    echo >"${XERR}-flag" "result $?"
    shtest::cleanup
  ) || echo >"${XERR}-flag" "exit $?"

  xnmg::_xload_check "$1"

  # load script in current subshell
  xwrap source "$@"
  shtest::strict_failed && shtest::fatal "Loading ${1##*/} failed strict test"

  shtest::log "  Script ${1##*/} loaded"

  # reset PATH
  PATH=''
}

xstart() {
  # restrict use of external commands (except those defined in config)
  local PATH=''

  # less noise
  local -x NMG_TAG=''

  # these tests require MOCK_ECHO=1 to check command actions
  local -x MOCK_ECHO=1

  # fd 4 used for logger
  local -x nmg_log_stderr=4
  exec 4>&2

  (
    shtest::add_onexit xnmg::_onexit

    shtest::reg_file "$XLOG"
    shtest::reg_file "$XERR"

    local IFS=-

    shtest::global_whitelist "xwrap"

    xtest::parse_options "$@"

    xmain "$@"
    local rc=$?

    [[ ${IFS} == - ]] || {
      xtest::err "Error: IFS was modified (now '${IFS-}')"
      rc=1
    }
    xrm "${XERR}" "${XLOG}"
    shtest::cleanup

    return ${rc}
  )
  local rc=$?

  xnmg::_onexit "${rc}"
  exec 4>&-

  shtest::cleanup

  return ${rc}
}

# Local Variables:
# mode: sh
# sh-basic-offset: 2
# sh-indentation: 2
# indent-tabs-mode: nil
# End:
