#!/bin/bash -eu

# Author: w0rp <devw0rp@gmail.com>
#
# This script runs tests for the ALE project. The following options are
# accepted:
#
#            -v  Enable verbose output
# --neovim-only  Run tests only for NeoVim
#    --vim-only  Run tests only for Vim

RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'
CURRENT_IMAGE_ID=d5a1b5915b09
IMAGE=w0rp/ale
DOCKER_FLAGS=(--rm -v "$PWD:/testplugin" -v "$PWD/test:/home" -w /testplugin "$IMAGE")
EXIT=0

tests='test/*.vader test/*/*.vader test/*/*/*.vader test/*/*/*.vader'
verbose=0
quiet=0
run_neovim_tests=1
run_vim_tests=1
run_vint=1
run_custom_checks=1

while [ $# -ne 0 ]; do
    case $1 in
    -v)
        verbose=1
        shift
    ;;
    -q)
        quiet=1
        shift
    ;;
    --neovim-only)
        run_vim_tests=0
        run_vint=0
        run_custom_checks=0
        shift
    ;;
    --vim-only)
        run_neovim_tests=0
        run_vint=0
        run_custom_checks=0
        shift
    ;;
    --no-vint)
        run_vint=0
        shift
    ;;
    --no-custom-checks)
        run_custom_checks=0
        shift
    ;;
    --)
        shift
        break
    ;;
    -?*)
        echo "Invalid argument: $1" 1>&2
        exit 1
    ;;
    *)
        break
    ;;
    esac
done

# Allow tests to be passed as arguments.
if [ $# -ne 0 ]; then
    # This doesn't perfectly handle work splitting, but none of our files
    # have spaces in the names.
    tests="$*"
fi

docker images -q w0rp/ale | grep "^$CURRENT_IMAGE_ID" > /dev/null \
    || docker pull "$IMAGE"

function filter-vader-output() {
    # When verbose mode is off, suppress output until Vader starts.
    local start_output="$verbose"
    local filtered_data=''

    while read -r; do
        if ((!start_output)); then
            if [[ "$REPLY" = *'Starting Vader:'* ]]; then
                start_output=1
            else
                continue
            fi
        fi

        if ((quiet)); then
            if [[ "$REPLY" = *'Starting Vader:'* ]]; then
                filtered_data="$REPLY"
            elif [[ "$REPLY" = *'Success/Total'* ]]; then
                success="$(echo -n "$REPLY" | grep -o '[0-9]\+/' | head -n1 | cut -d/ -f1)"
                total="$(echo -n "$REPLY" | grep -o '/[0-9]\+' | head -n1 | cut -d/ -f2)"

                if [ "$success" -lt "$total" ]; then
                    echo "$filtered_data"
                    echo "$REPLY"
                fi

                filtered_data=''
            else
                filtered_data="$filtered_data"$'\n'"$REPLY"
            fi
        else
            echo "$REPLY"
        fi
    done
}

function color-vader-output() {
    while read -r; do
        if [[ "$REPLY" = *'[EXECUTE] (X)'* ]]; then
            echo -en "$RED"
        elif [[ "$REPLY" = *'[EXECUTE]'* ]] || [[ "$REPLY" = *'[  GIVEN]'* ]]; then
            echo -en "$NC"
        fi

        if [[ "$REPLY" = *'Success/Total'* ]]; then
            success="$(echo -n "$REPLY" | grep -o '[0-9]\+/' | head -n1 | cut -d/ -f1)"
            total="$(echo -n "$REPLY" | grep -o '/[0-9]\+' | head -n1 | cut -d/ -f2)"

            if [ "$success" -lt "$total" ]; then
                echo -en "$RED"
            else
                echo -en "$GREEN"
            fi

            echo "$REPLY"
            echo -en "$NC"
        else
            echo "$REPLY"
        fi
    done

    echo -en "$NC"
}

if ((run_neovim_tests)); then
    for vim in $(docker run --rm "$IMAGE" ls /vim-build/bin | grep '^neovim' ); do
        echo
        echo '========================================'
        echo "Running tests for $vim"
        echo '========================================'
        echo

        set -o pipefail
        docker run -it -e VADER_OUTPUT_FILE=/dev/stderr "${DOCKER_FLAGS[@]}" \
            "/vim-build/bin/$vim" -u test/vimrc \
            --headless "+Vader! $tests" | filter-vader-output | color-vader-output || EXIT=$?
        set +o pipefail
    done

    echo
fi

if ((run_vim_tests)); then
    for vim in $(docker run --rm "$IMAGE" ls /vim-build/bin | grep '^vim' ); do
        echo
        echo '========================================'
        echo "Running tests for $vim"
        echo '========================================'
        echo

        set -o pipefail
        docker run -a stderr -e VADER_OUTPUT_FILE=/dev/stderr "${DOCKER_FLAGS[@]}" \
            "/vim-build/bin/$vim" -u test/vimrc \
            "+Vader! $tests" 2>&1 | filter-vader-output | color-vader-output || EXIT=$?
        set +o pipefail
    done

    echo
fi

if ((run_vint)); then
    echo '========================================'
    echo 'Running Vint to lint our code'
    echo '========================================'
    echo 'Vint warnings/errors follow:'
    echo

    set -o pipefail
    docker run -a stdout "${DOCKER_FLAGS[@]}" vint -s . || EXIT=$?
    set +o pipefail
    echo
fi

if ((run_custom_checks)); then
    echo '========================================'
    echo 'Running custom checks'
    echo '========================================'
    echo 'Custom warnings/errors follow:'
    echo

    set -o pipefail
    docker run -a stdout "${DOCKER_FLAGS[@]}" ./custom-checks . || EXIT=$?
    set +o pipefail
    echo

    echo '========================================'
    echo 'Checking for duplicate tags'
    echo '========================================'
    echo 'Duplicate tags follow:'
    echo

    grep --exclude=tags -roh '\*.*\*$' doc | sort | uniq -d || EXIT=$?
fi

exit $EXIT