#!/bin/sh

# NAME of the file (optional)
NAME=testsuite.sh

print_help() {
    echo "Usage: ./$NAME [options]
    -h | --help         Print this message
    -p | --path:        The path to the myfind exectuable
    -t | --timeout:     Set a custom timeout
    -v:                 Print a summary of the number of successed and failed tests
    -vv:                Print what part of the test failed
    -vvv:               Print the difference on fail
    --verbose <level>:  Give the level of verbose (1, 2 or 3)

    exit codes:
    0: Success
    1: Some test failed
    2: Invalid arguments"
}

NB_TESTS=0
NB_FAILED=0
NB_SUCCESSED=0

RED='\033[1;31m'
GREEN='\033[1;32m'
PURPLE='\033[1;35m'
BLUE='\033[1;34m'
YELLOW='\033[1;33m'
NONE='\033[0m'

# Default value for parameters
# VEROSE level by default
VERBOSE=0
# DIFF command to use.
DIFF='diff --color --unified=0 --label=result --label=reference '
# Default TIMEOUT
TIMEOUT=5
# Default path to the binary to test
EXE="which.sh"
# Name of the binary to test
EXE_NAME="./which.sh"
# Name of the binary reference
REF="which"

while [ $# -ne 0 ]; do
    case "$1" in
    -h | --help)
        print_help
        exit 0
        ;;
    -t | --timeout)
        if [ "$#" -lt 2 ]; then
            echo "$1 missing argument"
            exit 2
        fi
        TIMEOUT="$2"
        shift 2
        ;;
    -p | --path)
        if [ "$#" -lt 2 ]; then
            echo "$1 missing argument"
            exit 2
        fi
        EXE="$2"
        if [ ! -f "$2" ]; then
            echo "$2 wrong binary file. We are here: $PWD"
            exit 2
        fi
        shift 2
        ;;
    -v)
        VERBOSE=1
        shift 1
        ;;
    -vv)
        VERBOSE=2
        shift 1
        ;;
    -vvv)
        VERBOSE=3
        shift 1
        ;;
    --verbose)
        if [ "$#" -lt 2 ]; then
            echo "$1 missing argument"
            exit 2
        fi
        VERBOSE="$2"
        shift 2
        ;;
    *)
        print_help
        exit 2
        ;;
    esac
done

EXP_OUT=exp_out.log
EXP_ERR=exp_err.log
RES_OUT=res_out.log
RES_ERR=res_err.log

Test() {
    touch "$EXP_OUT" "$EXP_ERR" "$RES_OUT" "$RES_ERR"

    NB_TESTS=$((NB_TESTS + 1))
    NAME="$1"
    shift

    $REF $* 1>$EXP_OUT 2>$EXP_ERR
    EXP="$?"
    # Change the name of the REF by the name of the EXE in the errors.
    sed -i -e "s#$REF#$EXE_NAME#g" "$EXP_ERR"

    timeout "$TIMEOUT" "./$EXE" "$@" 1>"$RES_OUT" 2>"$RES_ERR"
    RES="$?"

    if [ "$RES" -eq 124 ] || [ "$EXP" != "$RES" ] || ! cmp -s "$EXP_OUT" "$RES_OUT" || ! cmp -s "$EXP_ERR" "$RES_ERR"; then
        NB_FAILED=$((NB_FAILED + 1))

        if [ "$VERBOSE" -eq 0 ]; then
            return
        fi

        if [ "$RES" -eq 124 ]; then
            printf "%s [%bTIMEOUT (%b%d%b)%b]\n" "$NAME" "$RED" "$YELLOW" "$RED" "$NONE" "$TIMEOUT"
        elif [ "$VERBOSE" -eq 3 ]; then
            printf "%b=============== %s ================\n" "$RED" "$NAME"
            printf "%bDiff Outputs:\n" "$BLUE"
            $DIFF "$RES_OUT" "$EXP_OUT"
            printf "\n%bDiff Errors:\n" "$BLUE"
            $DIFF "$RES_ERR" "$EXP_ERR"
            printf "\n%bReturn values:\n" "$BLUE"
            printf "%bExpected: %b%d%b Got: %b%d\n" "$NONE" "$BLUE" "$EXP" "$NONE" "$RED" "$RES"
            printf "===================================================%b\n" "$NONE"
        elif [ "$VERBOSE" -eq 2 ]; then
            OUT="$NAME    "
            if ! cmp -s "$EXP_OUT" "$RES_OUT"; then
                OUT="$OUT${PURPLE}Output differ. $NONE"
            fi
            if ! cmp -s "$EXP_ERR" "$RES_ERR"; then
                OUT="$OUT${PURPLE}Error differ. $NONE"
            fi
            if [ "$EXP" != "$RES" ]; then
                OUT="${OUT}${PURPLE}Return value differ. ${NONE}"
            fi
            printf "%-40b [%bFAILED%b]\n" "$OUT" "$RED" "$NONE"
        else
            printf "%-40s [%bFAILED%b]\n" "$NAME" "$RED" "$NONE"
        fi
    else
        NB_SUCCESSED=$((NB_SUCCESSED + 1))
        [ "$VERBOSE" -ne 0 ] && printf "%-40s [%bSUCCESS%b]\n" "$NAME" "$GREEN" "$NONE"
    fi

    rm "$EXP_OUT" "$EXP_ERR" "$RES_OUT" "$RES_ERR"
}

Category() {
    [ "$VERBOSE" -ne 0 ] && printf "\n%b---------- %s ----------%b\n" "$BLUE" "$1" "$NONE"
}

# Exemple of a testsuite:
# Category "CategoryName"
# Test "Name of the test" "arg1" "arg2" "arg3"
# Test "Second Test" arg1 arg2
# Category "Second Category"
# Test "You" "got" it

# Insert tests here

Category "Basic tests"
Test "No arguments"
Test "-a only" "-a"
Test "-a after binary" "ls" "-a"
Test "-a after bad binary" "ls" "-a"
Test "bad binary" "bad"
Test "bad binary with -a" "-a" "bad"
Test "good binary" "ls"
Test "good binary with -a" "-a" "ls"

Category "tests"
Test "multiple good binaries" "ls" "cat" "pwd"
Test "multiple bad binaries" "bad" "bad2" "bad3"
Test "multiple good and bad binaries" "ls" "bad" "cat" "bad2" "pwd" "bad3"
Test "binary in current directory" "testsuite.sh"

Category "-a tests"
Test "multiple good binaries" "-a" "ls" "cat" "pwd"
Test "multiple bad binaries" "-a" "bad" "bad2" "bad3"
Test "multiple good and bad binaries" "-a" "ls" "bad" "cat" "bad2" "pwd" "bad3"

# Category "Path empty"
# OLD_PATH="$PATH"
# PATH=""
# Test "No arguments"
# Test "-a only" "-a"
# Test "-a after binary" "ls" "-a"
# Test "good binary" "ls"
# Test "good binary with -a" "-a" "ls"
# Test "bad binary" "bad"
# Test "bad binary with -a" "-a" "bad"
# Test "binary in current directory" "testsuite.sh"
# Test "binary in current directory with -a" "-a" "testsuite.sh"
# PATH="$OLD_PATH"

Category "PATH with current directory"
OLD_PATH="$PATH"
PATH=":$PATH"
Test "No arguments"
Test "-a only" "-a"
Test "-a after binary" "ls" "-a"
Test "good binary" "ls"
Test "good binary with -a" "-a" "ls"
Test "bad binary" "bad"
Test "bad binary with -a" "-a" "bad"
Test "binary in current directory" "testsuite.sh"
Test "binary in current directory with -a" "-a" "testsuite.sh"
PATH="$OLD_PATH"

# End of tests here

[ "$VERBOSE" -ne 0 ] && echo ""

printf "%b[%b====%b] %bSynthese: %bNB_TESTS: %d%b | %bSUCCESS: %d%b | %bFAILED: %d%b\n" \
    "$NONE" "$YELLOW" "$NONE" "$YELLOW" "$PURPLE" "$NB_TESTS" "$NONE" "$GREEN" "$NB_SUCCESSED" "$NONE" "$RED" "$NB_FAILED" "$NONE"

# Exit with 0 if all tests succeded
[ "$NB_TESTS" -eq "$NB_SUCCESSED" ] && exit 0

exit 1
