#!/bin/sh
# Copyright 2016 Red Hat, Inc.
# Part of clufter project
# Licensed under GPLv2+ (a copy included | http://gnu.org/licenses/gpl-2.0.txt)

# Specific tests can be specified as per [1], e.g.:
#    tests.filter.XMLTraverse.testXSLTTemplate
# If nothing specified, auto-discovery is in place -> all the tests.
# ---
# [1] http://docs.python.org/2/library/unittest.html#command-line-interface

NORUN=1
. ./run-check "$(dirname "${0}")/run-check"

die () { echo "$@"; exit 127; }

stop=$(printf "\033\[0m")
blue=$(printf "\033[01;34m") red=$(printf "\033[01;31m")
green=$(printf "\033[01;32m") cyan=$(printf "\033[01;36m")
magenta=$(printf "\033[01;35m")
TAIL='2>&1 | sed \
    -e "s/\(^\|[^A-Za-z]\)\(OK\)/\1${blue}\2${stop}/"      \
    -e "s/\(^\|[^A-Za-z]\)\(FAILED.*\)/\1${red}\2${stop}/" \
    -e "s/\(^\|[^A-Za-z]\)\(ok\)/\1${green}\2${stop}/"     \
    -e "s/^\(\(FAIL\|ERROR\):.*\)/${magenta}\1${stop}/"    \
    -e "s/\(^\|[^A-Za-z]\)\(FAIL\)/\1${red}\2${stop}/"     \
    -e "s/\(^\|[^A-Za-z]\)\(ERROR\)/\1${red}\2${stop}/"    \
    -e "s/^\(Ran [1-9][0-9]*.*\)/${cyan}\1${stop}/"'

if ${PYTHONEXEC} -c "import sys; sys.exit(sys.version_info[:2] < (2,7))"; then
    CMD="-m unittest"
elif ${PYTHONEXEC} -c "import sys; sys.exit(sys.version_info[:2] < (2,6))"; then
    # pre-2.7 unittest doesn't offer test discovery, use external unittest2
    CMD="-m unittest2.__main__"  # see http://bugs.python.org/issue2751
else
    die "Unsupported Python version: $(
         ${PYTHONEXEC} -c "import sys; sys.write(sys.version_info[:2])")"
fi
DEBUG="env LOGLEVEL=WARNING"
PGR=${PAGER:-less}
VERBOSE=1
RUNCHECK=1
COVERAGE=0
ACC=
while [ $# -gt 0 ]; do
    case "$1" in
        -a)  # alternative && all
            ret=0
            for f in tests/[!_]*.py; do
                ${PYTHONEXEC} "$f" >/dev/null 2>&1 \
                  && echo OK \
                  || { echo FAIL; ret=1; }
            done
            exit ${ret}
            ;;
        -c)
            COVERAGE=1
            ;;
        -d)
            DEBUG=
            ;;
        -n)
            RUNCHECK=0
            ;;
        -N)
            CMD=nosetests
            ;;
        -q)
            VERBOSE=0
            ;;
        -p)
            TAIL="${TAIL} 2>&1 | ${PGR}"  # bash: " |& ${PGR}"
            ;;
        -t)
            TAIL=
            ;;
        tests.*)
            ACC="${ACC} $1"
            ;;
        *)
            ACC="${ACC} tests.$1"
            ;;
    esac
    shift
done


# nosetests fallback
CMDTEST=${CMD}
case "${CMD}" in -m*) CMDTEST="${PYTHONEXEC} ${CMD}";; esac
eval "${CMDTEST} -h >/dev/null 2>/dev/null"
[ "$?" -ne 1 ] || {
  [ "${CMD}" != "nosetests" ] && which nosetests >/dev/null 2>/dev/null \
  && CMD=nosetests
} || die 'no testing framework found (resort to running particular *.py files?)'

[ "${COVERAGE}" -eq 0 ] || {
  [ "${CMD}" = "nosetests" ] \
  && CMD="${CMD} --with-coverage" \
  || {
    which coverage2 >/dev/null 2>/dev/null \
    && CMD="${PYTHONEXEC} $(which coverage2) run ${CMD}" \
    || CMD="${PYTHONEXEC} $(which coverage) run ${CMD}"
  }
}

case "${CMD}" in -m*) CMD="${PYTHONEXEC} ${CMD}";;
                 nosetests*) CMD="${CMD} -s";; esac

# "--verbose" game because of "Alternative Usage: unit2 discover [options]"
[ -n "${ACC}" ] \
&& { RUNCHECK=0; [ "${VERBOSE}" -eq 0 ] || ACC="--verbose ${ACC}"; } \
|| case "${CMD}" in
  nosetests*)
    [ ! -f "__init__.py" ] || die "nosetests doesn't support repo dir structure"
    # --collect-only --all-modules tests?
    ACC="tests/*.py tests/*/*.py"
    [ "${VERBOSE}" -eq 0 ] || ACC="--verbose ${ACC}"
    ;;
  *)
    ACC="discover -s tests -p '*.py'"
    [ "${VERBOSE}" -eq 0 ] || ACC="${ACC} --verbose"
    ;;
esac

echo "${CMD} ${ACC}"

[ -t 0 ] || TAIL=

# signal-based harness to catch non-zero retval while isolating PWD changes
# in the subshell
ret=0
trap 'ret=1' USR1
(
    cd "$(dirname "$0")"; cd __project__ 2>/dev/null || :
    eval "{ ${DEBUG} ${CMD} ${ACC}; [ \$? -eq 0 ] || kill -USR1 \$\$; } ${TAIL}"
)

[ "${RUNCHECK}" -eq 0 ] || { run_checks; } || ret=$((ret+$?))

f() { echo "EXIT STATUS: $1"; return $1; }; f ${ret}
