#!/usr/bin/env bash

set -e

trap 'exit 130' INT

declare here googler quiet ci exitcode

here="$(python3 -c 'import pathlib, sys; print(pathlib.Path(sys.argv[2]).parent.resolve())' -- "$0")"
googler=$here/../googler

quiet=0
ci=0
exitcode=0
while [[ $1 == -* ]]; do
    case $1 in
        --ci)
            ci=1
            quiet=1
            ;;
        -h|--help)
            cat <<'EOF'
Usage: test [options]

Run automated tests of googler(1).

Requires shuf(1) from coreutils and /usr/share/dict/words.

Options:
    --ci
        Same to --quiet, except LF is used instead of CR when printing progress
        information. The reason is that CI logs are typically line buffered, so
        CR won't flush the output, rendering progress info useless.
    -h, --help
        Print this help and exit.
    -q, --quiet
        Suppress googler's output except when a test fails. Some progress info
        is still printed to stderr. Note that without this option, this script
        is rather verbose.

Environment variables:
    NUM_TEST_ITERATIONS
        Number of random tests to run. Default is 100.
    SLEEP_DURATION
        Number of seconds to sleep after each query. Default is 0. You may want
        to set this to avoid being blocked by Google for spamming.
EOF
            exit 1
            ;;
        -q|--quiet)
            quiet=1
            ;;
        *)
            printf '\033[31mError: Unrecognized option %q.\033[0m\n' "$1" >&2
            exit 1
            ;;
    esac
    shift
done

[[ $# -gt 0 ]] && {
    printf '\033[31mError: Unrecognized argument %q.\033[0m\n' "$1" >&2
    exit 1
}

declare num_rand_words
declare -a predefined_wordlist random_wordlist tld_args lang_args

# A UTF-8 wordlist.
predefined_wordlist=('汉语' 'español' 'português' 'ру́сский язы́к' '日本語' '한국어' 'le français')

# Requires shuf(1).
command -v shuf &>/dev/null || {
    printf '\033[31mError: shuf(1) not found.\033[0m\n' >&2
    exit 1
}

num_rand_words=10
random_wordlist=( $(shuf -n $num_rand_words /usr/share/dict/words 2>/dev/null) )
[[ ${#random_wordlist[@]} == $num_rand_words ]] || {
    printf '\033[31mError: Problem reading random words from /usr/share/dict/words.\033[0m\n' >&2
    exit 1
}

# Test googler with the given options, and report error if necessary.
#
# Whether googler's output is suppressed depends on whether the global variable
# quiet is truthy (set by -q, --quiet); when a failure is encountered, the
# global variable exitcode is set to 1, and if quiet was set, the test is rerun
# with output turned on.
test_googler () {
    report_error () {
        local last_status=$?

        declare -g exitcode

        local rerun=0
        [[ $1 == --rerun ]] && {
            rerun=1
            shift
        }

        printf '\033[31mError: googler ' >&2
        printf '%q ' "$@" >&2
        printf 'failed with status %d.\033[0m\n' $last_status >&2
        exitcode=1

        (( rerun )) && { $googler --noprompt -d "$@"; printf '\n\033[33m[Exit status] %d\033[0m\n' $?; } || :
    }

    declare -g quiet
    if (( quiet )); then
        $googler --noprompt -d "$@" &>/dev/null || report_error --rerun "$@"
    else
        printf '\033[34m==> googler ' >&2
        printf '%q ' "$@" >&2
        printf '\033[0m\n' >&2
        $googler --noprompt -d "$@" || report_error "$@"
        echo
    fi
}

# Write a list of configurations to $config_list, and later randomly pick from
# that list. (The reason we don't test them all is that Google would block us
# after thousands of queries.)
declare config_list
config_list="$(mktemp)"
trap 'rm -f "$config_list"' EXIT
for tld in com ar au be br ca ch cz de es 'fi' fr id 'in' it jp kr mx nl ph pl pt ro ru se tw ua uk; do
    [[ $tld != com ]] && tld_args=(-c $tld) || tld_args=()

    for lang in default de en fr hi ja ko zh; do
        [[ $lang != default ]] && lang_args=(-l $lang) || lang_args=()

        # Test single word queries.
        for keyword in "${predefined_wordlist[@]}" "${random_wordlist[@]}"; do
            printf '%s ' "${tld_args[@]}" "${lang_args[@]}" "$keyword"
            echo
        done

        # Test double word queries.
        for (( i = 0; i + 1 < num_rand_words; i += 2 )); do
            printf '%s ' "${tld_args[@]}" "${lang_args[@]}" \
                   "${random_wordlist[i]}" "${random_wordlist[i+1]}"
            echo
        done
    done
done >"$config_list"

declare num_rand_configs
num_rand_configs="${NUM_TEST_ITERATIONS:-100}"
counter=0
while read -r args; do
    (( counter++ )) || :
    printf '\033[32mTest %d/%d\033[0m' $counter $num_rand_configs >&2
    (( quiet && !ci )) && printf '\r' >&2 || printf '\n' >&2
    test_googler $args # explicit word splitting here, yes
    sleep "${SLEEP_DURATION:-0}"
done < <(shuf -n $num_rand_configs "$config_list")

(( exitcode )) || printf '\033[K\033[32mAll passed.\033[0m\n'
exit $exitcode
