# approvals.bash v0.5.1 # # Interactive approval testing for Bash. # github.com/DannyBen/approvals.bash # # shellcheck disable=SC2059 # Disabling SC2059 (quoted format string) because we use dynamic format strings approve() {

local expected approval approval_file actual cmd
approvals_dir=${APPROVALS_DIR:=approvals}

cmd=$1
last_exit_code=0
actual=$(eval "$cmd" 2>&1) || last_exit_code=$?
if [[ -v allow_diff_regex && "$allow_diff_regex" ]]; then
  actual=$(echo "$actual" | sed -E "s/$allow_diff_regex/*/g")
  unset allow_diff_regex
fi
approval=$(printf "%b" "$cmd" | tr -s -c "[:alnum:]" _)
approval_file="$approvals_dir/${2:-"$approval"}"

[[ -d "$approvals_dir" ]] || mkdir "$approvals_dir"

if [[ -f "$approval_file" ]]; then
  expected=$(cat "$approval_file")
else
  printf -- "$new_diff_string\n" "$cmd"
  printf "%b\n" "$actual"
  printf -- "$new_diff_string\n" "$cmd"
  expected="$actual"
  user_approval "$cmd" "$actual" "$approval_file"
  return
fi

if [[ "$(printf "%b" "$actual")" = "$(printf "%b" "$expected")" ]]; then
  pass "$cmd"
else
  printf -- "$changed_diff_string\n" "$cmd"
  $diff_cmd <(printf "%b" "$expected\n") <(printf "%b" "$actual\n") | tail -n +4
  printf -- "$changed_diff_string\n" "$cmd"
  user_approval "$cmd" "$actual" "$approval_file"
fi

}

allow_diff() {

allow_diff_regex="$1"

}

describe() {

printf "$describe_string\n" "$*"

}

context() {

printf "$context_string\n" "$*"

}

it() {

printf "$it_string\n" "$*"

}

fail() {

printf "$fail_string\n" "$*"
exit 1

}

pass() {

printf "$pass_string\n" "$*"
return 0

}

expect_exit_code() {

if [[ $last_exit_code == "$1" ]]; then
  pass "exit $last_exit_code"
else
  fail "expected exit code $1, got $last_exit_code"
fi

}

# Private

print_in_color() {

local color="$1"
shift
if [[ -z ${NO_COLOR+x} ]]; then
  printf "$color%b\e[0m\n" "$*"
else
  printf "%b\n" "$*"
fi

}

red() { print_in_color “e[31m” “$*”; } green() { print_in_color “e[32m” “$*”; } yellow() { print_in_color “e[33m” “$*”; } blue() { print_in_color “e[34m” “$*”; } magenta() { print_in_color “e[35m” “$*”; } cyan() { print_in_color “e[36m” “$*”; } bold() { print_in_color “e[1m” “$*”; } underlined() { print_in_color “e[4m” “$*”; } red_bold() { print_in_color “e[1;31m” “$*”; } green_bold() { print_in_color “e[1;32m” “$*”; } yellow_bold() { print_in_color “e[1;33m” “$*”; } blue_bold() { print_in_color “e[1;34m” “$*”; } magenta_bold() { print_in_color “e[1;35m” “$*”; } cyan_bold() { print_in_color “e[1;36m” “$*”; } red_underlined() { print_in_color “e[4;31m” “$*”; } green_underlined() { print_in_color “e[4;32m” “$*”; } yellow_underlined() { print_in_color “e[4;33m” “$*”; } blue_underlined() { print_in_color “e[4;34m” “$*”; } magenta_underlined() { print_in_color “e[4;35m” “$*”; } cyan_underlined() { print_in_color “e[4;36m” “$*”; }

user_approval() {

local cmd="$1"
local actual="$2"
local approval_file="$3"

if [[ -v CI || -v GITHUB_ACTIONS ]] && [[ -z "${AUTO_APPROVE+x}" ]]; then
  fail "$cmd"
fi

if [[ -v AUTO_APPROVE ]]; then
  response=a
else
  echo
  printf "$approval_string"
  response=$(bash -c "read -n 1 key; echo \$key")
  printf "\b%.s" $(seq 1 $((${#approval_string} + 1)))
fi

if [[ $response =~ [Aa] ]]; then
  printf "%b\n" "$actual" >"$approval_file"
  pass "$cmd"
else
  fail "$cmd"
fi

}

onexit() {

exitcode=$?
if [[ "$exitcode" == 0 ]]; then
  printf "$exit_success_string\n" "$0"
else
  printf "$exit_failed_string\n" "$0"
fi
echo
exit $exitcode

}

onerror() {

fail "caller: $(caller)"

}

set -e trap 'onexit' EXIT trap 'onerror' ERR

describe_string=“$(bold ▌ describe) %s” context_string=“$(bold ▌ context) %s” it_string=“$(bold ▌ it) %s” fail_string=“ $(red_bold failed) %s” pass_string=“ $(green approved) %s” exit_success_string=“$(green ▌ exit) $(bold %s finished successfully)” exit_failed_string=“$(red_bold ▌ exit) $(bold %s finished with errors)” new_diff_string=“────┤ $(yellow new): $(bold %s) ├────” changed_diff_string=“────┤ $(blue changed): $(bold %s) ├────” approval_string=“pprove? ”

if diff –help | grep – –color >/dev/null 2>&1; then

diff_cmd="diff --unified --color=always"

else

diff_cmd="diff --unified"

fi