#!/bin/bash
set -e

echo-with-color () {
    color="$1"; shift;
    if [ -t 1 ]; then
        echo -e "\\e[${color}m$*\\e[0m"
    else
        echo "$@"
    fi
}
echo-red    () { echo-with-color 31 "$@"; }

die() {
    echo-red "$@"
    exit 1
}

docker-interrupt() {
    echo-red "Got interrupt, sending SIGTERM to docker process $dockerprocess"
    kill -s SIGTERM "$dockerprocess"
    exit 2
}

docker-wrapper() {
    greeting="$1"
    shift
    trap docker-interrupt INT
    docker "$@" &
    dockerprocess=$!
    echo "$greeting: Docker process $dockerprocess started"
    if ! wait "$dockerprocess"; then echo "$greeting: Docker process $dockerprocess failed"; die; fi
    echo "$greeting: Docker process $dockerprocess done"
}

generate-tests() {
    count="$1"
    [ 1 -le "$count" ] || die COUNT must be a positive integer.
    COUNT="$count" make generate-tests
}

internal-generate-tests() {
    count="$1"
    [ 1 -le "$count" ] || die COUNT must be a positive integer.
    docker-wrapper "Generating $count tests" run --rm -v "$(pwd)/testcases":/home/user/testcases --init "$(cat test-runner.iid)" generate-tests "$count"
}

internal-get-run-tests-deps() {
    find testcases/ -maxdepth 1 -name '*.sh' |
        sed -r 's/\.sh/.results\/success/'
}

internal-get-ci-deps() {
    cases=$(mktemp)
    find testcases/ -maxdepth 1 -name '*.sh' > "$cases"
    failcases=$(mktemp)
    sed -r '/^(#|$)/d;s/^/testcases\//;s/$/.sh/' < tests-expected-to-fail > "$failcases"
    grep -vFf "$failcases" "$cases" | sed -r 's/\.sh/.results\/success/'
    grep -Ff  "$failcases" "$cases" | sed -r 's/\.sh/.results\/fail/'
    rm "$cases" "$failcases"
}

generate-tests-locally() {
    count="$1"
    [ 1 -le "$count" ] || die COUNT must be a positive integer.
    which sbcl || die Requires sbcl installed.
    PATH="$(pwd)/container-scripts:$PATH" container-scripts/generate-tests "$count"
}

number_of_processors="$(nproc)"

run-tests() {
    make -j "$number_of_processors" -k -l "$number_of_processors" -s run-tests
}

ci() {
    make -j "$number_of_processors" -k -l "$number_of_processors" -s ci
}

run-one-test() {
    testname="$1"
    [ -n "$testname" ] || die NAME must be given.
    [ -e "testcases/$testname.sh" ] || die "testcases/$testname.sh" does not exist.
    if grep -E "^${testname}\$" tests-expected-to-fail >/dev/null; then
        make "testcases/${testname}.results/fail"
    else
        make "testcases/${testname}.results/success"
    fi
}

IS_TTY=no
if [ -t 1 ]; then IS_TTY=yes; fi
internal-run-one-test() {
    testname="$1"
    expectation="$2"
    [ -n "$testname" ] || die NAME must be given.
    [ -e "testcases/$testname.sh" ] || die "testcases/$testname.sh" does not exist.
    docker-wrapper "Test $testname" run --rm -v "$(pwd)/testcases":/home/user/testcases --init "$(cat test-runner.iid)" run-test "$testname" "$expectation" "$IS_TTY"
}

clean-results() {
    rm -rf test-runner.iid testcases/*.results
}

remove-generated-testcases() {
    rm -rf testcases/generated-*
}

show-help() {
    cat <<EOF
Usage:

  ./script run-tests                    # Run test suite.

  ./script ci                           # Run test suite for CI.
                                        # This checks that the tests mentioned
                                        # in ./tests-expected-to-fail fails and
                                        # that the rest succeeds.

  ./script run-one-test NAME            # Run one test.
                                        # NAME can for example be "001".

  ./script clean-results                # Clean up test results.
                                        # Generated test cases will remain.

  ./script remove-generated-testcases   # Delete all generated test cases.

  ./script generate-tests COUNT         # Generate new test cases.
                                        # COUNT can for example be "100".

  ./script generate-tests-locally COUNT # As above, except don't use docker.
EOF
}

[ "$0" == "./script" ] || die Must be called as ./script from the same directory

if [ -n "$1" ]; then
    "$@"
else
    show-help
fi
