#!/bin/bash
# THIS FILE IS PART OF THE CYLC SUITE ENGINE.
# Copyright (C) 2008-2019 NIWA & British Crown (Met Office) & Contributors.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# NAME
#     test_header
#
# SYNOPSIS
#     . lib/bash/test_header
#
# DESCRIPTION
#     Interface for constructing tests under a TAP harness (the "prove"
#     command).
#
# FUNCTIONS
#     set_test_number N
#         echo a total number of tests for TAP to read.
#     ok TEST_NAME
#         echo a TAP OK message for TEST_NAME.
#     fail TEST_NAME
#         echo a TAP fail message for TEST_NAME.
#     run_ok TEST_NAME COMMAND ...
#         Run COMMAND with any following options/arguments and store stdout
#         and stderr in TEST_NAME.stdout and TEST_NAME.stderr.
#         This is expected to have a return code of 0, which ok's the test.
#     run_fail TEST_NAME COMMAND ...
#         Run COMMAND with any following options/arguments and store stdout
#         and stderr in TEST_NAME.stdout and TEST_NAME.stderr.
#         This is expected to have a non-zero return code, which ok's the test.
#     cmp_ok FILE_TEST [FILE_CONTROL]
#         Compare FILE_TEST with a file or stdin given by FILE_CONTROL
#         (stdin if FILE_CONTROL is "-" or missing). If $TEST_DEBUG_CMP
#         is set, show differences using xxdiff.
#     grep_ok PATTERN FILE
#         Run "grep -q PATTERN FILE".
#     exists_ok FILE
#         Test that FILE exists
#     exists_fail FILE
#         Test that FILE does not exist
#     skip_tests N SKIP_REASON
#         echo "ok $((++T)) # skip SKIP_REASON" N times, where the number to skip.
#-------------------------------------------------------------------------------
set -eu

FAILURES=0
SIGNALS="EXIT INT"
TEST_DIR=
FINALLY() {
    for S in ${SIGNALS}; do
        trap '' "$S"
    done
    if [[ -n "${TEST_DIR}" ]]; then
        cd ~
        rm -rf "${TEST_DIR}"
    fi
    if ((FAILURES > 0)); then
        echo -e "\n    stdout and stderr stored in: ${TEST_LOG_DIR}" >&2
    fi
}
for S in ${SIGNALS}; do
    # shellcheck disable=SC2064
    trap "FINALLY ${S}" "${S}"
done

TEST_NUMBER=0

set_test_number() {
    echo "1..$1"
}

ok() {
    echo "ok $((++TEST_NUMBER)) - $*"
}

fail() {
    ((++FAILURES))
    echo "not ok $((++TEST_NUMBER)) - $*"
}

run_ok() {
    local TEST_NAME="$1"
    shift 1
    if ! "$@" 1>"${TEST_NAME}.stdout" 2>"${TEST_NAME}.stderr"; then
        fail "${TEST_NAME}"
        mkdir -p "${TEST_LOG_DIR}"
        cp "${TEST_NAME}.stdout" "${TEST_LOG_DIR}/${TEST_NAME}.stdout"
        cp "${TEST_NAME}.stderr" "${TEST_LOG_DIR}/${TEST_NAME}.stderr"
        return
    fi
    ok "${TEST_NAME}"
}

run_fail() {
    local TEST_NAME="$1"
    shift 1
    if "$@" 1>"${TEST_NAME}.stdout" 2>"${TEST_NAME}.stderr"; then
        fail "${TEST_NAME}"
        mkdir -p "${TEST_LOG_DIR}"
        cp "${TEST_NAME}.stdout" "${TEST_LOG_DIR}/${TEST_NAME}.stdout"
        cp "${TEST_NAME}.stderr" "${TEST_LOG_DIR}/${TEST_NAME}.stderr"
        return
    fi
    ok "${TEST_NAME}"
}

cmp_ok() {
    local FILE_TEST="$1"
    local FILE_CONTROL="${2:--}"
    local TEST_NAME
    TEST_NAME="$(basename "${FILE_TEST}")-cmp-ok"
    if diff -u "${FILE_TEST}" "${FILE_CONTROL}" >&2; then
        ok "${TEST_NAME}"
        return
    fi
    fail "${TEST_NAME}"
}

grep_ok() {
    local BRE="$1"
    local FILE="$2"
    local TEST_NAME
    TEST_NAME="$(basename "${FILE}")-grep-ok"
    if grep -q -e "${BRE}" "${FILE}"; then
        ok "${TEST_NAME}"
        return
    fi
    fail "${TEST_NAME}"
}

exists_ok() {
    local FILE="$1"
    local TEST_NAME
    TEST_NAME="$(basename "${FILE}")-file-exists-ok"
    if [[ -a "${FILE}" ]]; then
        ok "${TEST_NAME}"
        return
    fi
    fail "${TEST_NAME}"
}

exists_fail() {
    local FILE=$1
    local TEST_NAME
    TEST_NAME="$(basename "${FILE}")-file-exists-fail"
    if [[ ! -a "${FILE}" ]]; then
        ok "${TEST_NAME}"
        return
    fi
    fail "${TEST_NAME}"
}

skip() {
    local N_TO_SKIP="$1"
    shift 1
    local COUNT=0
    while ((COUNT++ < N_TO_SKIP)); do
        echo "ok $((++TEST_NUMBER)) # skip $*"
    done
}

install_test() {
    local ORIG_TEST_NAME SNAME NEW_TEST_NAME
    ORIG_TEST_NAME="${2:-${TEST_NAME_BASE}}"
    SNAME="$(tr '/' '_' <<<"${TEST_SOURCE_DIR##*tests/}")"
    NEW_TEST_NAME="$(date -u +%Y%m%d%H%M%S)_parse_test_${SNAME}_${1}"
    NTDIR="${TEST_DIR}/${NEW_TEST_NAME}/"
    mkdir "${NTDIR}"
    if [[ -d "${TEST_SOURCE_DIR}/${ORIG_TEST_NAME}" ]]; then
        cp -r "${TEST_SOURCE_DIR}/${ORIG_TEST_NAME}" "${NTDIR}"
    else
        mkdir "${NTDIR}/${ORIG_TEST_NAME}"
    fi
    cd "${NTDIR}/${ORIG_TEST_NAME}"
}

TEST_NAME_BASE="$(basename "$0" '.t')"
TEST_SOURCE_DIR="$(cd "$(dirname "$0")" && pwd)"
PATH="${TEST_SOURCE_DIR}/bin:${PATH}"
TEST_DIR="$(mktemp -d)"
cd "${TEST_DIR}"
TEST_LOG_DIR="${TMPDIR:-/tmp}/parsec-tests/$(basename "${TEST_SOURCE_DIR}")"

set +e
