#!/usr/bin/env bash

REL_SCRIPT_DIR="`dirname \"$0\"`"
SCRIPT_DIR="`( cd \"$REL_SCRIPT_DIR\" && pwd )`"
PROJECT_DIR="`( cd \"$SCRIPT_DIR/../../..\" && pwd )`"

case "$OSTYPE" in
    darwin*) PLATFORM="OSX" ;;
    linux*)  PLATFORM="LINUX" ;;
    bsd*)    PLATFORM="BSD" ;;
    *)       PLATFORM="UNKNOWN" ;;
esac


test_cli_common()
{
    echo ----------------------------------------
    echo Testing common cli behavior...
    CLI_SCRIPT_NAME=${1:?missing_param}
    CLI_SCRIPT=${2:-$SCRIPT_DIR/../../$CLI_SCRIPT_NAME}
    echo Script: $CLI_SCRIPT

    # should find the minimal help output
    $CLI_SCRIPT 2>&1 < /dev/null | grep -q "Must pipe input or define at least one file\." || {
        $CLI_SCRIPT 2>&1 < /dev/null
        echo "[$CLI_SCRIPT_NAME] Output should be help message."
        exit 1
    }

    # unicode error - only happens in python
    # Note: different exceptions are thrown on different platforms.
    if [[ "$PLATFORM" == "OSX" || "$PLATFORM" == "BSD" || "$PLATFORM" == "LINUX" ]]; then
        $CLI_SCRIPT ../test/resources/unicode-error.js 2>&1 | grep -q "Error while decoding input or encoding output:" || {
            $CLI_SCRIPT ../test/resources/unicode-error.js 2>&1
            echo "[$CLI_SCRIPT_NAME] Output should be unicode error message."
            exit 1
        }
    fi

    $CLI_SCRIPT 2> /dev/null < /dev/null && {
        echo "[$CLI_SCRIPT_NAME (with no parameters)] Return code should be error."
        exit 1
    }

    $CLI_SCRIPT -Z 2> /dev/null && {
        echo "[$CLI_SCRIPT_NAME -Z] Return code for invalid parameter should be error."
        exit 1
    }

    $CLI_SCRIPT -h > /dev/null || {
        echo "[$CLI_SCRIPT_NAME -h] Return code should be success."
        exit 1
    }

    $CLI_SCRIPT -v > /dev/null || {
        echo "[$CLI_SCRIPT_NAME -v] Return code should be success."
        exit 1
    }

    MISSING_FILE="$SCRIPT_DIR/../../../js/bin/missing_file"
    MISSING_FILE_MESSAGE="No such file or directory"
    $CLI_SCRIPT $MISSING_FILE 2> /dev/null && {
        echo "[$CLI_SCRIPT_NAME $MISSING_FILE] Return code should be error."
        exit 1
    }

    $CLI_SCRIPT $MISSING_FILE 2>&1 | grep -q "$MISSING_FILE_MESSAGE" || {
        echo "[$CLI_SCRIPT_NAME $MISSING_FILE] Stderr should have useful message."
        exit 1
    }

    if [ "`$CLI_SCRIPT $MISSING_FILE 2> /dev/null`" != "" ]; then
        echo "[$CLI_SCRIPT_NAME $MISSING_FILE] Stdout should have no text."
        exit 1
    fi
}

setup_temp()
{
    mkdir -p target
    TEST_TEMP=$PWD/`mktemp -d target/test_temp_XXXX`
    echo Created $TEST_TEMP...
}

cleanup()
{
    rm -rf $TEST_TEMP && echo Removed $TEST_TEMP...
    test -z $1 || exit $1
}

test_cli_js_beautify()
{
    echo ----------------------------------------
    echo Testing js-beautify cli behavior...
    CLI_SCRIPT=${1:-$SCRIPT_DIR/../../js-beautify}

    $CLI_SCRIPT $SCRIPT_DIR/../../../js/bin/js-beautify.js > /dev/null || {
        echo "js-beautify output for $SCRIPT_DIR/../../../js/bin/js-beautify.js was expected succeed."
        exit 1
    }

    $CLI_SCRIPT $SCRIPT_DIR/../../../js/bin/css-beautify.js > /dev/null || {
        echo "js-beautify output for $SCRIPT_DIR/../../../js/bin/css-beautify.js was expected succeed."
        exit 1
    }

    setup_temp
    $CLI_SCRIPT -o $TEST_TEMP/js-beautify-file.js $SCRIPT_DIR/../../../js/bin/js-beautify.js && diff $SCRIPT_DIR/../../../js/bin/js-beautify.js $TEST_TEMP/js-beautify-file.js || {
        $CLI_SCRIPT -o $TEST_TEMP/js-beautify-file.js $SCRIPT_DIR/../../../js/bin/js-beautify.js && diff $SCRIPT_DIR/../../../js/bin/js-beautify.js $TEST_TEMP/js-beautify-file.js | cat -t -e
        echo "js-beautify output for $SCRIPT_DIR/../../../js/bin/js-beautify.js was expected to be unchanged."
        cleanup 1
    }

    cat $SCRIPT_DIR/../../../js/bin/js-beautify.js | $CLI_SCRIPT -o $TEST_TEMP/js-beautify-pipe.js - && diff $SCRIPT_DIR/../../../js/bin/js-beautify.js $TEST_TEMP/js-beautify-pipe.js || {
        cat $SCRIPT_DIR/../../../js/bin/js-beautify.js | $CLI_SCRIPT -o $TEST_TEMP/js-beautify-pipe.js - && diff $SCRIPT_DIR/../../../js/bin/js-beautify.js $TEST_TEMP/js-beautify-pipe.js | cat -t -e
        echo "js-beautify output for $SCRIPT_DIR/../../../js/bin/js-beautify.js should have been created in $TEST_TEMP/js-beautify-pipe.js."
        cleanup 1
    }

    $CLI_SCRIPT $SCRIPT_DIR/../../../js/bin/js-beautify.js | diff $SCRIPT_DIR/../../../js/bin/js-beautify.js - || {
        $CLI_SCRIPT $SCRIPT_DIR/../../../js/bin/js-beautify.js | diff $SCRIPT_DIR/../../../js/bin/js-beautify.js - | cat -t -e
        echo "js-beautify output for $SCRIPT_DIR/../../../js/bin/js-beautify.js was expected to be unchanged."
        cleanup 1
    }

    cat $SCRIPT_DIR/../../../js/bin/js-beautify.js | $CLI_SCRIPT | diff $SCRIPT_DIR/../../../js/bin/js-beautify.js - || {
        $CLI_SCRIPT $SCRIPT_DIR/../../../js/bin/js-beautify.js | diff $SCRIPT_DIR/../../../js/bin/js-beautify.js - | cat -t -e
        echo "js-beautify output for $SCRIPT_DIR/../../../js/bin/js-beautify.js was expected to be unchanged."
        cleanup 1
    }

    cat $SCRIPT_DIR/../../../js/bin/js-beautify.js | $CLI_SCRIPT - | diff $SCRIPT_DIR/../../../js/bin/js-beautify.js - || {
        $CLI_SCRIPT $SCRIPT_DIR/../../../js/bin/js-beautify.js | diff $SCRIPT_DIR/../../../js/bin/js-beautify.js - | cat -t -e
        echo "js-beautify output for $SCRIPT_DIR/../../../js/bin/js-beautify.js was expected to be unchanged."
        cleanup 1
    }

    cat $SCRIPT_DIR/../../../js/bin/js-beautify.js | $CLI_SCRIPT -f - | diff $SCRIPT_DIR/../../../js/bin/js-beautify.js - || {
        $CLI_SCRIPT $SCRIPT_DIR/../../../js/bin/js-beautify.js | diff $SCRIPT_DIR/../../../js/bin/js-beautify.js - | cat -t -e
        echo "js-beautify output for $SCRIPT_DIR/../../../js/bin/js-beautify.js was expected to be unchanged."
        cleanup 1
    }

    $CLI_SCRIPT -o $TEST_TEMP/js-beautify.js $SCRIPT_DIR/../../../js/bin/js-beautify.js && diff $SCRIPT_DIR/../../../js/bin/js-beautify.js $TEST_TEMP/js-beautify.js || {
    $CLI_SCRIPT -o $TEST_TEMP/js-beautify.js $SCRIPT_DIR/../../../js/bin/js-beautify.js && diff $SCRIPT_DIR/../../../js/bin/js-beautify.js $TEST_TEMP/js-beautify.js | cat -t -e
        echo "js-beautify output for $SCRIPT_DIR/../../../js/bin/js-beautify.js should have been created in $TEST_TEMP/js-beautify.js."
        cleanup 1
    }


    # ensure new line settings work
    $CLI_SCRIPT -o $TEST_TEMP/js-beautify-n.js -e '\n' $SCRIPT_DIR/../../../js/bin/js-beautify.js
    $CLI_SCRIPT -o $TEST_TEMP/js-beautify-rn.js -e '\r\n' $TEST_TEMP/js-beautify-n.js

    # regression check #1925, short option failed due to string search instead of tuple
    # before fix -n would match inside "--space-after**-n**amed-function"
    $CLI_SCRIPT -o $TEST_TEMP/js-beautify-eof.js -n -f $TEST_TEMP/js-beautify-n.js
    $CLI_SCRIPT -o $TEST_TEMP/js-beautify-eof2.js --end-with-newline -f $TEST_TEMP/js-beautify-n.js
    diff -q $TEST_TEMP/js-beautify-eof.js $TEST_TEMP/js-beautify-eof2.js || {
        diff $TEST_TEMP/js-beautify-eof.js $TEST_TEMP/js-beautify-eof2.js | cat -t -e
        echo "js-beautify output for $TEST_TEMP/js-beautify-eof.js and $TEST_TEMP/js-beautify-eof2.js was expected to be the same."
        cleanup 1
    }

    # ensure eol processed correctly
    $CLI_SCRIPT -o $TEST_TEMP/js-beautify-n-dash.js --indent-size 2 --eol '\n' $TEST_TEMP/js-beautify-n.js
    $CLI_SCRIPT -o $TEST_TEMP/js-beautify-rn-dash.js --indent-size 2 --eol '\r\n' $TEST_TEMP/js-beautify-n.js
    diff -q $TEST_TEMP/js-beautify-n-dash.js $TEST_TEMP/js-beautify-rn-dash.js && {
        diff $TEST_TEMP/js-beautify-n-dash.js $TEST_TEMP/js-beautify-rn-dash.js | cat -t -e
        echo "js-beautify output for $TEST_TEMP/js-beautify-n-dash.js and $TEST_TEMP/js-beautify-rn-dash.js was expected to be different."
        cleanup 1
    }

    diff -q $TEST_TEMP/js-beautify-n.js $TEST_TEMP/js-beautify-rn.js && {
        diff $TEST_TEMP/js-beautify-n.js $TEST_TEMP/js-beautify-rn.js | cat -t -e
        echo "js-beautify output for $TEST_TEMP/js-beautify-n.js and $TEST_TEMP/js-beautify-rn.js was expected to be different."
        cleanup 1
    }

    $CLI_SCRIPT $TEST_TEMP/js-beautify-n.js | diff -q $TEST_TEMP/js-beautify-n.js - || {
        echo "js-beautify output for $TEST_TEMP/js-beautify-n.js was expected to be unchanged."
        cleanup 1
    }

    $CLI_SCRIPT -e 'auto' $TEST_TEMP/js-beautify-rn.js | diff -q $TEST_TEMP/js-beautify-rn.js - || {
        echo "js-beautify output for $TEST_TEMP/js-beautify-rn.js was expected to be unchanged."
        cleanup 1
    }

    # Glob related tests
    cp -r $PROJECT_DIR/js/src  $TEST_TEMP/
    FILE_RCOUNT=$(find $PROJECT_DIR/js/src -name 't*.js' | grep -c .)
    FILE_COUNT=$(ls $PROJECT_DIR/js/src/*.js | grep -c .)

    $CLI_SCRIPT '*/*/missing_file' > /dev/null || {
        echo "[$CLI_SCRIPT_NAME $MISSING_FILE_GLOB] Return code should be success for globs."
        exit 1
    }


    if [ "$FILE_COUNT" != "$(cd $TEST_TEMP && $CLI_SCRIPT 'src/*.js' | grep -c .)" ]; then
        echo "js-beautify output for 'src/*.js' was expected have $FILE_COUNT files."
        echo $(cd $TEST_TEMP && $CLI_SCRIPT 'src/*.js')
        cleanup 1
    fi

    if [ "$FILE_COUNT" != "$(cd $TEST_TEMP && $CLI_SCRIPT --file 'src/*.js' | grep -c .)" ]; then
        echo "js-beautify output for 'src/*.js' was expected have $FILE_COUNT files."
        echo $(cd $TEST_TEMP && $CLI_SCRIPT --file 'src/*.js')
        cleanup 1
    fi

    if [ "$FILE_COUNT" != "$(cd $TEST_TEMP && $CLI_SCRIPT --file 'src/cl?.js' --file 'src/??dex.js' | grep -c .)" ]; then
        echo "js-beautify output for --file 'src/cl?.js' --file 'src/??dex.js' was expected have $FILE_COUNT files."
        echo $(cd $TEST_TEMP && $CLI_SCRIPT --file 'src/cl?.js' --file 'src/??dex.js')
        cleanup 1
    fi

    if [ "1" != "$(cd $TEST_TEMP && $CLI_SCRIPT --file 'src/cl?.js' --file 'src/c??.js' 'src/cli.js'  | grep -c .)" ]; then
        echo "js-beautify output for --file 'src/cl?.js' --file 'src/cl?.js' was expected have 1 file."
        echo $(cd $TEST_TEMP && $CLI_SCRIPT --file 'src/cl?.js' --file 'src/c??.js' 'src/cli.js')
        cleanup 1
    fi

    # recursive wildcard not supported in python 3.4 or less
    # only run this test if the script doesn't report failure.
    $CLI_SCRIPT 'src/**/t*.js' && {
        if [ "$FILE_RCOUNT" != "$(cd $TEST_TEMP && $CLI_SCRIPT 'src/**/t*.js' | grep -c .)" ]; then
            echo "js-beautify output for 'src/**/t*.js' was expected have $FILE_RCOUNT files."
            echo $(cd $TEST_TEMP && $CLI_SCRIPT 'src/**/t*.js')
            cleanup 1
        fi
    }

    # EditorConfig related tests
    cp -r ../js/test/resources/editorconfig $TEST_TEMP/
    $CLI_SCRIPT -o $TEST_TEMP/editorconfig/example.js --end-with-newline --indent-size 4 -e '\n' $TEST_TEMP/editorconfig/example-base.js
    $CLI_SCRIPT -o $TEST_TEMP/editorconfig/example-ec.js --indent-size 2 -e '\n' $TEST_TEMP/editorconfig/example-base.js

    $CLI_SCRIPT -o $TEST_TEMP/editorconfig/cr/example.js --end-with-newline --indent-size 4 -e '\n' $TEST_TEMP/editorconfig/example-base.js
    $CLI_SCRIPT -o $TEST_TEMP/editorconfig/cr/example-ec.js --indent-size 2 -e '\r' $TEST_TEMP/editorconfig/example-base.js

    $CLI_SCRIPT -o $TEST_TEMP/editorconfig/crlf/example.js --end-with-newline --indent-size 4 -e '\n' $TEST_TEMP/editorconfig/example-base.js
    $CLI_SCRIPT -o $TEST_TEMP/editorconfig/crlf/example-ec.js --indent-size 2 -e '\r\n' $TEST_TEMP/editorconfig/example-base.js

    $CLI_SCRIPT -o $TEST_TEMP/editorconfig/error/example.js --end-with-newline --indent-size 4 -e '\n' $TEST_TEMP/editorconfig/example-base.js

    pushd $TEST_TEMP/editorconfig

    cd $TEST_TEMP/editorconfig/error
    $CLI_SCRIPT --editorconfig $TEST_TEMP/js-beautify-n.js \
    > /dev/null || {
        echo "Invalid editorconfig file should not report error (consistent with the EditorConfig)."
        cleanup 1
    }

    $CLI_SCRIPT --editorconfig example.js \
    > /dev/null || {
        echo "Invalid editorconfig file should not report error (consistent with the EditorConfig)."
        cleanup 1
    }

    # TODO: EditorConfig setting should NOT overide cli setting, but that is
    # the current by-design behavior, due to code limitations.

    # file input scenario
    SCENARIO=a
    cd $TEST_TEMP/editorconfig || exit 1
    $CLI_SCRIPT --end-with-newline --indent-size 6 --editorconfig -o example-${SCENARIO}.js example.js \
    && diff -q example-${SCENARIO}.js example-ec.js || {
        echo "EditorConfig setting should overide cli setting."
        diff example-${SCENARIO}.js example-ec.js | cat -t -e
        cleanup 1
    }

    cd $TEST_TEMP/editorconfig/crlf || exit 1
    $CLI_SCRIPT --end-with-newline --indent-size 6 --editorconfig -o example-${SCENARIO}.js example.js \
    && diff -q example-${SCENARIO}.js example-ec.js || {
        echo "EditorConfig setting should overide cli setting."
        diff example-${SCENARIO}.js example-ec.js | cat -t -e
        cleanup 1
    }

    cd $TEST_TEMP/editorconfig/cr || exit 1
    $CLI_SCRIPT --end-with-newline --indent-size 6 --editorconfig -o example-${SCENARIO}.js example.js \
    && diff -q example-${SCENARIO}.js example-ec.js || {
        echo "EditorConfig setting should overide cli setting."
        diff example-${SCENARIO}.js example-ec.js | cat -t -e
        cleanup 1
    }

    # stdin input to stdout scenario
    SCENARIO=b
    cd $TEST_TEMP/editorconfig || exit 1
    echo "cat example.js | $CLI_SCRIPT --end-with-newline --indent-size 6 --editorconfig > example-${SCENARIO}.js"
    cat example.js | $CLI_SCRIPT --end-with-newline --indent-size 6 --editorconfig > example-${SCENARIO}.js \
    && diff -q example-${SCENARIO}.js example-ec.js || {
        echo "EditorConfig setting should overide cli setting."
        diff example-${SCENARIO}.js example-ec.js | cat -t -e
        cleanup 1
    }

    cd $TEST_TEMP/editorconfig/crlf || exit 1
    echo "cat example.js | $CLI_SCRIPT --end-with-newline --indent-size 6 --editorconfig > example-${SCENARIO}.js"
    cat example.js | $CLI_SCRIPT --end-with-newline --indent-size 6 --editorconfig > example-${SCENARIO}.js \
    && diff -q example-${SCENARIO}.js example-ec.js || {
        echo "EditorConfig setting should overide cli setting."
        diff example-${SCENARIO}.js example-ec.js | cat -t -e
        cleanup 1
    }

    cd $TEST_TEMP/editorconfig/cr || exit 1
    echo "cat example.js | $CLI_SCRIPT --end-with-newline --indent-size 6 --editorconfig > example-${SCENARIO}.js"
    cat example.js | $CLI_SCRIPT --end-with-newline --indent-size 6 --editorconfig > example-${SCENARIO}.js \
    && diff -q example-${SCENARIO}.js example-ec.js || {
        echo "EditorConfig setting should overide cli setting."
        diff example-${SCENARIO}.js example-ec.js | cat -t -e
        cleanup 1
    }


    # stdin input to file scenario
    SCENARIO=c
    cd $TEST_TEMP/editorconfig || exit 1
    echo "cat example.js | $CLI_SCRIPT --end-with-newline --indent-size 6 --editorconfig -o example-${SCENARIO}.js"
    cat example.js | $CLI_SCRIPT --end-with-newline --indent-size 6 --editorconfig -o example-${SCENARIO}.js - \
    && diff -q example-${SCENARIO}.js example-ec.js || {
        echo "EditorConfig setting should overide cli setting."
        diff example-${SCENARIO}.js example-ec.js | cat -t -e
        cleanup 1
    }

    cd $TEST_TEMP/editorconfig/crlf || exit 1
    cat example.js | $CLI_SCRIPT --end-with-newline --indent-size 6 --editorconfig -o example-${SCENARIO}.js - \
    && diff -q example-${SCENARIO}.js example-ec.js || {
        echo "EditorConfig setting should overide cli setting."
        diff example-${SCENARIO}.js example-ec.js | cat -t -e
        cleanup 1
    }

    cd $TEST_TEMP/editorconfig/cr || exit 1
    cat example.js | $CLI_SCRIPT --end-with-newline --indent-size 6 --editorconfig -o example-${SCENARIO}.js - \
    && diff -q example-${SCENARIO}.js example-ec.js || {
        echo "EditorConfig setting should overide cli setting."
        diff example-${SCENARIO}.js example-ec.js | cat -t -e
        cleanup 1
    }

    popd
    # End EditorConfig

    # ensure unchanged files are not overwritten
    $CLI_SCRIPT -o $TEST_TEMP/js-beautify.js $SCRIPT_DIR/../../../js/bin/js-beautify.js
    cp -p $TEST_TEMP/js-beautify.js $TEST_TEMP/js-beautify-old.js
    touch $TEST_TEMP/js-beautify.js
    sleep 2
    touch $TEST_TEMP/js-beautify-old.js
    $CLI_SCRIPT -r $TEST_TEMP/js-beautify.js && test $TEST_TEMP/js-beautify.js -nt $TEST_TEMP/js-beautify-old.js && {
        echo "js-beautify should not replace unchanged file $TEST_TEMP/js-beautify.js when using -r"
        cleanup 1
    }

    $CLI_SCRIPT -o $TEST_TEMP/js-beautify.js $TEST_TEMP/js-beautify.js && test $TEST_TEMP/js-beautify.js -nt $TEST_TEMP/js-beautify-old.js && {
        echo "js-beautify should not replace unchanged file $TEST_TEMP/js-beautify.js when using -o and same file name"
        cleanup 1
    }

    $CLI_SCRIPT -o $TEST_TEMP/js-beautify.js $TEST_TEMP/js-beautify-old.js && test $TEST_TEMP/js-beautify.js -nt $TEST_TEMP/js-beautify-old.js && {
        echo "js-beautify should not replace unchanged file $TEST_TEMP/js-beautify.js when using -o and different file name"
        cleanup 1
    }

    $CLI_SCRIPT $SCRIPT_DIR/../../../js/bin/css-beautify.js | diff -q $SCRIPT_DIR/../../../js/bin/css-beautify.js - && {
        echo "js-beautify output for $SCRIPT_DIR/../../../js/bin/css-beautify.js was expected to be different."
        cleanup 1
    }

    #meta-parameter brace_style
    cp ../js/test/resources/example1.js $TEST_TEMP/example.js
    $CLI_SCRIPT --brace-style=invalid $TEST_TEMP/example.js > /dev/null && {
        echo "[$CLI_SCRIPT_NAME --brace-style=invalid $TEST_TEMP/example.js] Return code for invalid brace_style meta-parameter should be error."
        cleanup 1
    }
    $CLI_SCRIPT --brace-style='expand,preserve-inline,invalid' $TEST_TEMP/example.js > /dev/null && {
        echo "[$CLI_SCRIPT_NAME --brace-style=expand,preserve-inline,invalid $TEST_TEMP/example.js] Return code for invalid brace_style meta-parameter should be error."
        cleanup 1
    }
    $CLI_SCRIPT --brace-style=preserve-inline $TEST_TEMP/example.js > /dev/null || {
        echo "[$CLI_SCRIPT_NAME --brace-style=preserve-inline $TEST_TEMP/example.js] Return code for only one part of valid brace_style meta-parameter should be success (uses default where it can)."
        cleanup 1
    }

    cleanup
}

main() {

    test_cli_common js-beautify "$SCRIPT_DIR/../../../tools/python-dev css-beautify"
    test_cli_common js-beautify "$SCRIPT_DIR/../../../tools/python-rel css-beautify"

    test_cli_common js-beautify "$SCRIPT_DIR/../../../tools/python-dev js-beautify"
    test_cli_common js-beautify "$SCRIPT_DIR/../../../tools/python-rel js-beautify"

    test_cli_js_beautify "$SCRIPT_DIR/../../../tools/python-dev js-beautify"

    echo ----------------------------------------
    echo $0 - PASSED.
    echo ----------------------------------------
}

(main $*)
