#!/usr/bin/env bash
#
# This script runs a test protocol on the local pipeline.
# A. Test using pipeline -x with various varaibles wrong
# B. Test run all, default settings (no compression)
# C. Test compress
# D. Test run all, with compression
# E. Test run step X where one source file is missing
# F. Test run step X where one dependent step is not done
#

# load local common.sh - need to run a test in a project
[[ -f common.sh ]] || { echo "ERROR: no local common.sh found - did the setup run OK?"; exit 255; }

unset LOADED_COMMON_PIPELINE_SH

source common.sh || { echo "ERROR: failed loading local common.sh"; exit 255; }

# make sure test log directories are there
TEST_LOG_ROOT=testlogs
TEST_LOG_REFS=$TEST_LOG_ROOT/reference

[[ -d $TEST_LOG_ROOT ]] || mkdir $TEST_LOG_ROOT
[[ -d $TEST_LOG_REFS ]] || mkdir $TEST_LOG_REFS

PRETTY_PRINT=1
reset_attributes

export _TST_NR_TSTS=0
export _TST_NR_OK=0
export _TST_NR_ERROR=0
export _TST_NR_WARN=0

nodate() {
    sed 's/^[0-9]\+\/[0-9]\+\/[0-9]\+ [0-9]\{2\}:[0-9]\{2\}:[0-9]\{2\}[[:space:]]*\(PM\|AM\|\)\s*//';
}

print_status() {
    local ec=$1
    local lbl="$2"
    if [[ $ec -eq 0 ]];then
        ok_status_msg "$lbl"
    elif [[ $ec -eq 1 ]];then
        error_status_msg "$lbl"
    elif [[ $ec -eq 2 ]]; then
        xerror_status_msg "$lbl" "REF MISMATCH"
    fi
    return 0
}

_tst_addok() {
    _TST_NR_OK=$((_TST_NR_OK+1))
    _TST_NR_TSTS=$((_TST_NR_TSTS+1))
}

_tst_adderr() {
    _TST_NR_ERROR=$((_TST_NR_ERROR+1))
    _TST_NR_TSTS=$((_TST_NR_TSTS+1))
}

_tst_add_stats() {
    local ec=$1
    [[ $ec -eq 0 ]] && _tst_addok
    [[ $ec -eq 1 ]] && _tst_adderr
}

tst_print_summary() {
    printf '%-20s %s\n' 'N(tests)' $_TST_NR_TSTS
    printf '%-20s %s\n' 'N(ok)'    $_TST_NR_OK
    printf '%-20s %s\n' 'N(error)' $_TST_NR_ERROR
}

#-----------------------------------------------------------------
# test wrappers
#-----------------------------------------------------------------

# get log files
# if flag = 0 then no reference -> output to /dev/null
# otherwise, use reference
export TST_LOGREF=""
export TST_LOG=""
get_flog() {
    local lbl="$1"
    local flag="$2"
    if [[ "$flag" == '0' ]]; then
        TST_LOG="/dev/null"
        TST_LOGREF=""
    else
        TST_LOG=$TEST_LOG_ROOT/${lbl}.log
        TST_LOGREF=$TEST_LOG_REFS/${lbl}.log
    fi
}

# get result wrt reference file
# requires get_flog to be run before 
get_tst_ref() {
    local ecin=$1
    local ec=0
    [[ ${#TST_LOGREF} -gt 0 ]] || return 0
    [[ -f $TST_LOG ]] || { error_msg 'missing log file <$TST_LOG>'; return 255; }
    
    if [[ -f $TST_LOGREF ]]; then
        diff <(grep -v '#' "$TST_LOGREF" | nodate) <(grep -v '#' "$TST_LOG" | nodate) >& /dev/null
        [[ $? -eq 0 ]] || ec=2
    else
        info_msg "missing reference file : $TST_LOGREF"
        if [[ $ecin -eq 0 ]]; then
            info_msg "copying log file to reference"
            cp -f "$TST_LOG" "$TST_LOGREF"
        else
            warn_msg "NOT copying log file to reference as an error occured in the test"
        fi
    fi
    return $ec
}

# test for:
#  - error code = ecref, if ecref=='+' then test against ec!=0
#  - if flag==1, test wrt reference file
tst_eq() {
    local echk=0
    local ec=0
    local ecref="$1"
    local lbl="$2"
    local flag="$3"
    local cmd=$4
    get_flog "$lbl" "$flag"
    shift
    shift
    shift
    shift
    ( $cmd $lbl $* ) >& "$TST_LOG"
    ec=$?

    # if ec ref is '+' -> ec <> 0
    if [[ "$ecref" == "+" ]]; then
        [[ $ec -ne 0 ]] || echk=1
    else
        [[ $ec -eq $ecref ]] || echk=1
    fi

    get_tst_ref $echk || echk=2

    _tst_add_stats $echk
    print_status $echk $lbl
}

# short cuts
tst_not() {
    tst_eq '+' $*
}

tst_pos() {
    tst_eq 0 $*
}

#-----------------------------------------------------------------

tst_check_setup() {
    local lbl="$1"
    local ec=0
    PRETTY_PRINT=0
    reset_attributes

    pipeline -x
    ec=$?
    
    PRETTY_PRINT=1
    reset_attributes
    return $ec
}

tst_test() {
    local rval=0
    shift
    test $* >& /dev/null
    if [[ $? -eq 0 ]]; then
        echo "TEST OK : test $*"
        rval=0
    else
        echo "TEST FAILED : test $*"
        rval=1
    fi
    return $rval
}

#-----------------------------------------------------------------

tst_set_variable() {
    local var="$1"
    local value="$2"
    eval _TST_SAVE_${var}="${!var}"
    eval ${var}="$value"
}

tst_restore_variable() {
    local var="$1"
    local save=_TST_SAVE_${var}
    eval ${var}="${!save}"
    unset $save
}

tst_setup_with_badvar() {
    local tst="$1"
    local varname="$2"
    local badvalue="$3"
    tst_set_variable $varname "$badvalue"
    $tst check_badvar_${varname} 1 tst_check_setup
    tst_restore_variable $varname
}
echo "Start"
export -f get_flog
export -f get_tst_ref
export -f tst_test
export -f tst_eq
export -f tst_not
export -f tst_pos
export -f tst_check_setup

export CHK_DUMP_LEVEL=2
export ADD_REFS_IF_MISSING=1

#( pipeline -t todo/blabla.todo -x; echo $?; echo $PL_TODO; )
#exit 255
#--------------------------------------------------
# 1. check the full setup
tst_pos check_setup_goodvar 1 tst_check_setup

# 2. change one variable, this should fail
tst_setup_with_badvar tst_not DIR_ORTHOLOGER    "/cannot_read_here"

# 2. change one variable, this should fail
tst_setup_with_badvar tst_not DIR_PROJECT     "/cannot_read_here"

# 2. change one variable, this should fail
tst_setup_with_badvar tst_not SCHEDULER_LABEL "UNDEFINED_SCHEDULER"

# 3. change one variable, this should fail
tst_setup_with_badvar tst_not TMP_DIR_BASE    "/cannot_write_here"
tst_setup_with_badvar tst_not PL_TODO         "/no_todo_file.todo"

# make sure COMPRESS_DATA is set to 1 if not == 0
COMPRESS_DATA=dhfg
setup_compression
tst_eq 0 check_badvar_COMPRESS_DATA 0 tst_test "$COMPRESS_DATA -eq 1"

# 5. change one variable, this should fail
tst_setup_with_badvar tst_not MIN_OVERLAP -10

#--------------------------------------------

echo
tst_print_summary
