# vim: set filetype=sh :
#        file: tstlib
#   copyright: Bernd Schumacher <bernd.schumacher@hpe.com> (2007-2021)
#     license: GNU General Public License, version 3
# description: internal test library for shellia
[ -f ia.basic ] && . ./ia.basic || . /usr/share/shellia/ia.basic

LANG=C
ECHO="/bin/echo"

oneline()
{
  gawk '{if(NR!=1)printf("\\n");printf("%s",$0,NR)}END{printf("\n")}'
}

# check <comment> [-u <cmd>] [-i <input>] [-s <shell>] [--sshd2222] <cmd> <expected>
# Description: run a command and verify the result
#   <comment>   a comment that will be displayed in the result of the check
#   -s <shell>  use shell <shell>
#   --sshd2222  only run <cmd> if sshd2222 should work
#               (test before with: if ./sshd2222 should-work; then ...)
#   --sshd2222-opts like --sshd2222 but also
#               add option "--sshopts <sshopts>" to <cmd>
#               (<sshopts> will be calculated with "./sshd2222 options")
#   -u <cmd>    command <cmd> will be called
#   <expected>  the expected output of <cmd>
# If the check fails, the following messag is displayed
help="$(cat <<END
# the following diagnostic output is created (remove with "make clean")
#   exp     contains what is expected
#   res     contains the result that does not match exp
#   res.org Original result before it was uniformed to match exp
#   r4s     the result in the form used in test.* files
END
)"
check()
{
  local input
  local shell
  local unify
  local cmd
  local output
  local comment
  local sshd2222

  #${ECHO} "DEBUG check: #=<$#> 1=<$1> 2=<$2> 3=<$3> 4=<$4> 5=<$5>" >&2
  comment="$1"
  shift

  input=""
  shell=""
  unify="cat"
  sshd2222=""
  sshd2222opts=""
  while [ $# -ne 2 ]; do
    if [ "$1" = "-u" ]; then
      unify="$2"
      shift 2
    elif [ "$1" = "-i" ]; then
      input="$2"
      shift 2
    elif [ "$1" = "-s" ]; then
      shell="$2"
      shift 2
    elif [ "$1" = "--sshd2222" ]; then
      sshd2222="$1"
      shift
    elif [ "$1" = "--sshd2222-opts" ]; then
      sshd2222="$1"
      if ./sshd2222 should-work; then
        sshd2222opts="$(./sshd2222 options)"
      fi
      shift
    else
      ${ECHO} "ERROR internal error check: unknown option <$1>" >&2
      exit 1
    fi
  done

  cmd="$1"
  [ "$shell" -a -f "$(${ECHO} "$cmd" | gawk '{print $1}')" ] && cmd="$shell $cmd"
  [ "$input" ] && cmd="$input | $cmd"

  ${ECHO} "DEBUG check: cmd=<$cmd> (see files res.cmd and res.org)"
  timeformat="\nreal=%E user=%U sys=%S exit=%x"
  # /usr/bin/time may produce the message "Command exited with non-zero status x"
  if [ "$sshd2222" ]; then
    if ! ./sshd2222 should-work; then
      ${ECHO} "WARN $comment => no test, because sshd2222 is not possible" | oneline
      return
    fi
  fi

  [ "$sshd2222opts" ] && cmd="$cmd --sshopts \"$sshd2222opts\""

  # create res.cmd to manually recreate output
  cat <<END >res.cmd
#!/bin/sh
# created by tsttlib:check()
# run it from shellia/src directory
timeformat="$(/bin/echo "$timeformat"|ia_easy_backslash --quote)"
cmd="$(/bin/echo "$cmd"|ia_easy_backslash --quote)"
unify="$(/bin/echo "$unify"|ia_easy_backslash --quote)"
{ timeout 60 /usr/bin/time -f "\$timeformat" sh -c "\$cmd"; } 2>&1 | tee res.org | eval "\$unify"
END
  chmod 755 res.cmd

  output="$( { timeout 60 /usr/bin/time -f "$timeformat" sh -c "$cmd"; } 2>&1 | tee res.org | eval "$unify" )"
  if [ $(cat res.org | wc -l) -gt 5000 ]; then
    output="res.org is too long (try res.cmd)"
  else
    time="$(${ECHO} "$output" | tail -1)"
    output="$(${ECHO} "$output" | head -n -1)"
    ${ECHO} "$time $comment \"$cmd\"" | head -1 >>timelist
  fi

  ${ECHO}
  if [ "$output" = "$2" ]; then
    ${ECHO} "OK $comment \"$cmd\" => \"$output\"" | oneline
  else
    ${ECHO} "ERROR $comment \"$cmd\" => \"$output\" (expected:\"$2\")" | oneline
    ${ECHO} "$2" | sed -e "s/\\n/
/g" >exp
    ${ECHO} "$output" | sed -e "s/\\n/
/g" >res
    /bin/echo "$output" | ia_easy_backslash |
      sed -e "1 s/^/\"/" | tac | sed -e "1 s/$/\"/" | tac >r4s
    ${ECHO} "The Test result is not what was expected. A Fix is needed."
    ${ECHO} "$help"
    exit 1
  fi
}

set_ia_x()
{
  local traceoff
  traceoff="{ set +x; } 2>/dev/null"
  sed -e "s|^\(\s*ia\>\).*|\1 -x|" -e "s|^\(\s\+\)\(eval \"\$ia_init\".*\)|\1$traceoff\n\1\2|"
}


quote="'"
SED_del_quote_in_trace="-e \"/+\+ /s/${quote}//g\""
SED_del_redirect_in_trace="-e \"/^|*+\+ \([1-9]\|\)>\s*\S\+\s*$/d\""
SED_del_ia_restore_return_in_trace="-e \"/^|*+\+ ia_restore_return$/{N;/\n|*+\+ return/{d}}\""
SED_command_not_found="sed -e \"s/.*: not:\( command\| inaccessible or\|\) not found/: not: not found/\""
GREP_pop_var_context="grep -v -e \": pop_var_context: head of shell_variables not a function context\""
# GREP_pop_var_context first seen 2022/09/18 in Bug#1020200: shellia: FTBS
UNIFY_mksh="grep -v -e \"^|*+\+ set +x$\" | \
sed -e \"s/+ typeset/+ local/\" \
-e \"s/\(+.*\) \+$/\1/\" \
$SED_del_quote_in_trace \
$SED_del_redirect_in_trace \
$SED_del_ia_restore_return_in_trace \
-e \"/+ ia_save_return/d\" \
-e \"s/^mksh: //\""
UNIFY_bash="$GREP_pop_var_context | \
sed -e \"s/+\+ /+ /\" \
$SED_del_quote_in_trace"
UNIFY_posh="grep -v -e \"^+ 2> /dev/null $\" | \
sed $SED_del_redirect_in_trace"
UNIFY_mktemp="sed -e \"s/\/tmp\/tmp\.\S\+/\/tmp\/tmp.mktemp/g\""
UNIFY_busybox="sed \
$SED_del_quote_in_trace"

# Use_locallib is needed in hello_world examples.
# To keep them easy, they read /usr/share/shellia/ia* libs.
# This libs will be available after installation of shellia.
use_locallib()
{
  cat $cmd | sed -e "s|^. /usr/share/shellia/ia|. ./ia|" > $cmd.tmp.locallib
  cmd="$cmd.tmp.locallib"
  chmod 755 $cmd
}

# temporary changes to overcome bugs
bug913718_unify()
{
  # bug#913718
  if [ "$shell" = "posh" ]; then
    if [ "$1" ]; then
      eval "$1=\"\$$1 |
sed \\\"s/.tmp.no_set-u//\\\"\""
    else
      ${ECHO} "sed \"s/.tmp.no_set-u//\""
    fi
  fi
}

bug913718_cmd()
{
  # bug#913718
  if [ "$shell" = "posh" ]; then
    cat $cmd | sed "/^set -u/ d" > $cmd.tmp.no_set-u
    cmd="$cmd.tmp.no_set-u"
    chmod 755 $cmd
  fi
}
