#!/usr/bin/env bash
export GUILE_AUTO_COMPILE=0

if [ -z "$srcdir" ]; then
    echo >&2 "the \`srcdir' variable needs to be set to this script's location"
    exit 1
fi

source ${srcdir}/test-util


# run `scribbu genre ...'
# usage: run_genre var_to_rcv_stdout var_to_rcv_stderr var_to_rcv_status args...
# for instance:
#     run_genre out err stat foo bar splat
# will execute `scribbu genre foo bar splat'; on return the process'
# stdout will be in `out', stderr in `err', and exit status in `stat'. Note
# that due to quoting issues, any `'' or ``' characters will have been
# replaced with `:'.
function run_genre()
{
    local __stdout=$1
    local __stderr=$2
    local __status=$3
    shift 3

    verbose `pwd`
    verbose ${genre_scribbu_dir}/scribbu -L ${srcdir}/../scheme genre $@
    # Cf. https://stackoverflow.com/questions/11027679/store-capture-stdout-and-stderr-in-different-variables-bash
    local t_std
    local t_err
    local t_stat
    eval "$(${genre_scribbu_dir}/scribbu -L ${srcdir}/../scheme genre $@ \
    2> >(t_err=$(cat); typeset -p t_err) \
     > >(t_std=$(cat); typeset -p t_std) ); t_stat=$?"

    eval "$__stdout='$(echo $t_std|tr \' :|tr \` :)'"
    eval "$__stderr='$(echo $t_err|tr \' :|tr \` :)'"
    eval "$__status='$t_stat'"

    verbose $t_stat
    printf '=%.0s' $(seq 1 $genre_cols) >&3
    verbose "$t_std"
    printf '=%.0s' $(seq 1 $genre_cols) >&3
	echo "$t_err"
    printf '=%.0s' $(seq 1 $genre_cols) >&3
}

###########################################################################
# tests
###########################################################################

function smoke_tests()
{
    local out
    local err
    local stat

    # can we get a help message?
    run_genre out err stat -h

    [ $stat -eq 0 ] || fail "smoke_tests: non-zero status for -h"
    [ -z "$err" ] || fail "smoke_tests: non-nil stderr for -h"
    [ -n "$out" ] || fail "smoke_tests: empty stdout for -h"

    here=`pwd`
    set_testdir ${srcdir} $genre_testdir smoke_tests id3v2.3.tag

    # id3v2.3.tag has a TCON frame of "Pop", no ID3v1 tag
    run_genre out err stat -c -C -g alternativ id3v2.3.tag
    [ $stat -eq 0 ] || fail "smoke_tests: non-zero status for -g"
    [ -z "$err" ] || fail "smoke_tests: non-nil stderr for -g"
    [ -z "$out" ] || fail "smoke_tests: non-nil stdout for -g"
    tcon=$(${genre_scribbu_dir}/scribbu dump id3v2.3.tag|grep -F TCON)
    [ "$tcon" = "TCON: Alternative" ] || fail "smoke_tests: wrong TCON: $tcon"
    v1=$(${genre_scribbu_dir}/scribbu dump id3v2.3.tag|grep -F ID3v1:)
    stat=$?
    [ $stat -eq 0 ] || fail "smoke_tests: failed to add ID3v1 tag"
    test -f id3v2.3.tag.1 && fail "Ooops-- backup copy was made (1)"

    run_genre out err stat -c -C -w 40 id3v2.3.tag
    [ $stat -eq 0 ] || fail "smoke_tests: non-zero status for -w"
    [ -z "$err" ] || fail "smoke_tests: non-nil stderr for -w"
    [ -z "$out" ] || fail "smoke_tests: non-nil stdout for -w"
    tcon=$(${genre_scribbu_dir}/scribbu dump id3v2.3.tag|grep -F TCON)
    [ "$tcon" = "TCON: AlternRock" ] || fail "smoke_tests: wrong TCON: $tcon"
    v1=$(${genre_scribbu_dir}/scribbu dump id3v2.3.tag|grep -E '^AlternRock')
    stat=$?
    [ $stat -eq 0 ] || fail "smoke_tests: bad ID3v1 genre"
    test -f id3v2.3.tag.1 && fail "Ooops-- backup copy was made (2)"

    run_genre out err stat -c -C -b -G Alt-Rock id3v2.3.tag
    test $stat -eq 0 || fail "smoke_tests: non-zero status for -G"
    test -z "$err" || fail "smoke_tests: non-nil stderr for -G"
    test -z "$out" || fail "smoke_tests: non-nil stdout for -G"
    tcon=$(${genre_scribbu_dir}/scribbu dump id3v2.3.tag|grep -F TCON)
    [ "$tcon" = "TCON: Alt-Rock" ] || fail "smoke_tests: wrong TCON: $tcon"
    v1=$(${genre_scribbu_dir}/scribbu dump id3v2.3.tag|grep -F ID3v1:)
    stat=$?
    test $stat -eq 0 || fail "smoke_tests: failed to add ID3v1 tag"
    # "Art Rock" is the closest match to "Alt-Rock"-- the ID3v1 genre
    # should have been set to this (unfortunately)
    art_rock=$(${genre_scribbu_dir}/scribbu dump id3v2.3.tag|grep -F 'Art Rock')
    stat=$?
    test $stat -eq 0 || fail "smoke_tests: wrong ID3v1 genre(?)"
    test -f id3v2.3.tag.1 || fail "Ooops-- backup copy was not made"

    #######################################################################
    # test tag scoping
    #######################################################################

    # -2 should leave the ID3v1 genre
    run_genre out err stat -2 -w 0 id3v2.3.tag
    test $stat -eq 0 || fail "smoke_tests: non-zero status for -2"
    art_rock=$(${genre_scribbu_dir}/scribbu dump id3v2.3.tag|grep -F 'Art Rock')
    stat=$?
    test $stat -eq 0 || fail "smoke_tests: non-zero -2 changed ID31"

    # TCON is now Blues
    # genre is Art Rock

    # -1 should leave out the TCON
    run_genre out err stat -1 -w 2 id3v2.3.tag
    test $stat -eq 0 || fail "smoke_tests: non-zero status for -1"
    tcon=$(${genre_scribbu_dir}/scribbu dump id3v2.3.tag|grep -F TCON)
    test "$tcon" = "TCON: Blues" || fail "smoke_tests: changed ID3v2"
    country=$(${genre_scribbu_dir}/scribbu dump id3v2.3.tag|grep -F 'Country')
    stat=$?
    test $stat -eq 0 || fail "smoke_tests: wrong ID3v1 genre"

    # TCON is Blues
    # genre is now Country

    # scope by ID3v2 tag
    run_genre out err stat -t 0 -w 6 id3v2.3.tag
    test $stat -eq 0 || fail "smoke_tests: non-zero status for -t"
    tcon=$(${genre_scribbu_dir}/scribbu dump id3v2.3.tag|grep -F TCON)
    test "$tcon" = "TCON: Grunge" || fail "smoke_tests: wrong TCON: $tcon"
    grunge=$(${genre_scribbu_dir}/scribbu dump id3v2.3.tag|grep -E '^Grunge')
    stat=$?
    test $stat -eq 0 || fail "smoke_tests: wrong ID3v1 genre"

    # finally, check on -W
    run_genre out err stat genre -W
    test $stat -eq 0 || fail "smoke_tests: non-zero status for -W"

    clean_testdir $here $genre_testdir smoke_tests
}

function negative_tests
{
    local out
    local err
    local stat

    here=`pwd`
    set_testdir ${srcdir} $genre_testdir negative_tests id3v2.3.tag

    # exactly one of -w, -g & -G must be given;
    # give none
    run_genre out err stat -c -b id3v2.3.tag
    test $stat -ne 0 || fail "negative_tests: none of -w, -g & -G given should fail"
    test -n "$err" || fail "negative_tests: none of -w, -g & -G given should produce an eror message"
    test -z "$out" || fail "negative_tests: none of -w, -g & -G given should produce no output"

    # give two
    run_genre out err stat -c -b -w 0 -g Alternative id3v2.3.tag
    test $stat -ne 0 || fail "negative_tests: two of -w, -g & -G given should fail (1)"
    test -n "$err" || fail "negative_tests: two of -w, -g & -G given should produce an eror message (1)"
    test -z "$out" || fail "negative_tests: two of -w, -g & -G given should produce no output (1)"

    # give two
    run_genre out err stat -c -b -w 0 -G Alternative id3v2.3.tag
    test $stat -ne 0 || fail "negative_tests: two of -w, -g & -G given should fail (2)"
    test -n "$err" || fail "negative_tests: two of -w, -g & -G given should produce an eror message (2)"
    test -z "$out" || fail "negative_tests: two of -w, -g & -G given should produce no output (2)"

    # give two
    run_genre out err stat -c -b -g Alt-Rock -G Alternative id3v2.3.tag
    test $stat -ne 0 || fail "negative_tests: two of -w, -g & -G given should fail (3)"
    test -n "$err" || fail "negative_tests: two of -w, -g & -G given should produce an eror message (3)"
    test -z "$out" || fail "negative_tests: two of -w, -g & -G given should produce no output (3)"

    # give three
    run_genre out err stat -c -b -w 0 -g Alt-Rock -G Alternative id3v2.3.tag
    test $stat -ne 0 || fail "negative_tests: three of -w, -g & -G given should fail"
    test -n "$err" || fail "negative_tests: three of -w, -g & -G given should produce an eror message"
    test -z "$out" || fail "negative_tests: three of -w, -g & -G given should produce no output"

    # -t & -1
    run_genre out err stat -w 8 -1 -t 2 id3v2.3.tag
    test $stat -ne 0 || fail "negative_tests: -1 & -t should fail"
    test -n "$err" || fail "negative_tests: -1 & -t should produce an eror message"
    test -z "$out" || fail "negative_tests: -1 & -t should produce no output"

    # -c & -a
    run_genre out err stat -w 8 -a -c id3v2.3.tag
    test $stat -ne 0 || fail "negative_tests: -a & -A should fail"
    test -n "$err" || fail "negative_tests: -a & -A should produce an eror message"
    test -z "$out" || fail "negative_tests: -a & -A should produce no output"

    clean_testdir $here $genre_testdir negative_tests
}

function test_id3v2_copy_bug()
{
    local out
    local err
    local stat

    here=`pwd`
    set_testdir ${srcdir} $genre_testdir id3v2_copy_bug la-mer.mp3

    run_genre out err stat -a -C -g "Trip-Hop" la-mer.mp3
    test $stat -eq 0 || fail "id3v2_copy_bug: failed to run scribbu genre"

    grunge=$(${genre_scribbu_dir}/scribbu dump -1 la-mer.mp3|grep -E '^ID3v1: Lemongrass - La Mer')
    stat=$?
    test $stat -eq 0 || fail "id3v2_copy_bug: wrong ID3v1 artist & title"

    clean_testdir $here $genre_testdir id3v2_copy_bug
}

###########################################################################
#                          parse options & run tests                      #
###########################################################################

genre_builddir=../src
genre_cols=$(tput cols)
genre_debug=no
genre_help=no
genre_nargs=0
genre_scribbu_dir=../src
genre_testdir=./test-genre-tmp
genre_verbose=no
genre_prev_option=
for genre_option
do
    # If the previous option required an argument, assign it now.
    if test -n "$genre_prev_option"; then
        eval $genre_prev_option=\$genre_option
        genre_prev_option=
        genre_nargs=$(($genre_nargs+1))
        continue
    fi

    # Parse out the argument option in $genre_option, if present.
    case $genre_option in
        *=?*) genre_optarg=$(expr "X$genre_option" : '[^=]*=\(.*\)') ;;
        *=)   genre_optarg= ;;
        *)    genre_optarg=yes ;;
    esac

    # Options are handled here:
    case $genre_option in
        -d | --de | --deb | --debu | --debug)
            genre_debug=yes;;
        -h | --he | --hel | --help)
            genre_help=yes;;
        -v | --ve | --ver | --verb | --verbo | --verbose)
            genre_verbose=yes;;
        *)
            cat >&2 <<EOF
Unrecognized option \`$genre_option'.
Try \`$0 --help' for more information.
EOF
            exit 2;;
    esac

done

if test "$genre_help" == "yes"; then
    cat <<EOF
\`$0' -- test the \`genre' sub-command

Tests for \`scribbu genre'; part of the scribbu test suite.
EOF
fi

if test "$genre_verbose" == "yes"; then
    exec 3>&1
else
    exec 3> /dev/null
fi

if test "$genre_debug" == "yes"; then
    set -x
fi

# Both must be absolute in order for `make-distcheck' to work
genre_scribbu_dir=`cd "$genre_scribbu_dir"; pwd`
[ -d "$genre_testdir" ] || mkdir -p "$genre_testdir"
genre_testdir=`cd "$genre_testdir"; pwd`
smoke_tests
negative_tests
test_id3v2_copy_bug
