#!/usr/bin/env bash

# Copyright 2018 Steven Bosnick
#
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE-2.0 or
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
# option. This file may not be copied, modified, or distributed
# except according to those terms

# Usage: runtests [kcov_base_dir]
#
# Runs all of the tests in the test suite and check that the succ*.rs 
# test succeed and the fail*.rs tests fail. The tests are run by calling
# rustc with the appropriate arguments on the succ*.rs and fail*.rs files
# (individually).
#
# runtests should be run from the base of the luther project.
#
# The kcov_base_dir optional argument provides the outdir argument for
# kcov. If this argument is provided then runtests will invoke rustc
# running under kcov. If the argument is not provided then runtests will
# invoice rustc directly.
#
# When runtests is running in the kcov mode it does not comfirm the exit
# status of rustc.

set -e
shopt -s nullglob

function initialize {
    base_dir=target/debug
    test_dir=luther-derive/testsuite
    out_dir_base="${base_dir}/testsuite"
    kcov_base_dir=$1
    exit_code=0
}

function check_directories {
    if ! [[ -d ${base_dir} && -d ${test_dir} ]]; then
        echo "Unable to locate ${base_dir} and ${test_dir}."
        echo "$0 should be executed from the base directory of the luther crate."
        exit 2
    fi
}

function set_rustc_args {
    local dep_dir="${base_dir}/deps"
    local libluther="${base_dir}/libluther.rlib"
    local libluther_derive="${base_dir}/libluther_derive.so"
    rustc_args=(-L "dependency=${dep_dir}"
               --extern "luther=${libluther}"
               --extern "luther_derive=${libluther_derive}")
}

function create_base_build_directory {
    if [[ -d "${out_dir_base}" ]]; then
        rm -r "${out_dir_base}"
    fi
    mkdir "${out_dir_base}"
}

function create_kcov_base_dir {
    if ! [[ -z ${kcov_base_dir} ]]; then
        if [[ -d ${kcov_base_dir} ]]; then
            rm -r "${kcov_base_dir}"
        fi
        mkdir "${kcov_base_dir}"
    fi
}

function check_exit_code {
    if [[ $1 != 0 && $2 == "succ" ]]; then
        echo Unexpected failure compiling "${file}"
        exit_code=1
    elif [[ $1 == 0 && $2 == "fail" ]]; then
        echo Unexpected sucess compiling "${file}"
        exit_code=1
    fi
}

function run_one_test {
    set +e

    local out_dir=$1
    local file=$2
    local succ_fail=$3

    if [[ -z ${kcov_base_dir} ]]; then
        rustc "${rustc_args[@]}" --out-dir "${out_dir}" "${file}"
        check_exit_code $? $succ_fail
    else
        kcov --include-path=. --exclude-line=COV_EXCL_LINE --exclude-region=COV_EXCL_START:COV_EXCL_END "${kcov_base_dir}" rustc "${rustc_args[@]}" --out-dir "${out_dir}" "${file}"
    fi

    set -e
}

function run_tests {
    for file in ${test_dir}/$1*.rs ; do
        # setup the out_dir
        local out_dir="${out_dir_base}/$(basename "${file}" .rs)"
        mkdir "${out_dir}"

        # run rustc
        run_one_test "${out_dir}" "${file}" "$1"
    done
}

function main {
    initialize "$@"
    check_directories
    set_rustc_args
    create_base_build_directory
    create_kcov_base_dir
    run_tests "succ"
    run_tests "fail" 
    exit ${exit_code}
}

main "$@"
