# To be sourced by shell scripts in the test suite.

# This software is part of the SBCL system. See the README file for
# more information.
#
# While most of SBCL is derived from the CMU CL system, the test
# files (like this one) were written from scratch after the fork
# from CMU CL.
#
# This software is in the public domain and is provided with
# absolutely no warranty. See the COPYING and CREDITS files for
# more information.

# Before sbcl-1.0.13 or so, we set up some environment variables to
# the absolute (POSIX) pathname naming the SBCL runtime, core, and
# home; but this runs afoul of the Bourne shell's repeated
# tokenization of its inputs, so now we use some shell functions.
. ../sbcl-pwd.sh
sbcl_pwd

# Make the shell bomb out whenever an unset shell variable is used.
# Note that scripts may toggle this if necessary.
set -u

# Initialize variables.
set -a # export all variables at assignment-time.
# Note: any script that uses the variables that name files should
# quote them (with double quotes), to contend with whitespace.
SBCL_HOME="${TEST_SBCL_HOME:-$SBCL_PWD/../obj/sbcl-home}"
SBCL_CORE="${TEST_SBCL_CORE:-$SBCL_PWD/../output/sbcl.core}"
# On Windows, the runtime is sbcl.exe; on Unix, it's sbcl
if [ -f "$SBCL_PWD/../src/runtime/sbcl.exe" ]; then
    SBCL_RUNTIME="${TEST_SBCL_RUNTIME:-$SBCL_PWD/../src/runtime/sbcl.exe}"
else
    SBCL_RUNTIME="${TEST_SBCL_RUNTIME:-$SBCL_PWD/../src/runtime/sbcl}"
fi
SBCL_ARGS="${TEST_SBCL_ARGS:---disable-ldb --noinform --no-sysinit --no-userinit --noprint --disable-debugger}"


# Tests should probably not care about their own name.
script_basename=`basename $0`
# Scripts that use this variable should quote it.
TEST_FILESTEM=`basename "${script_basename}" | sed -e 's/\.sh$//' -e 's/\./-/g'`

TEST_DIRECTORY="${SBCL_PWD}/${TEST_FILESTEM}-$$"
export TEST_DIRECTORY

# "Ten four" is the closest numerical slang I can find to "OK", so
# it's the Unix status value that we expect from a successful test.
# (Of course, zero is the usual success value, but we don't want to
# use that because SBCL returns that by default, so we might think
# we passed a test when in fact some error caused us to exit SBCL
# in a weird unexpected way. In contrast, 104 is unlikely to be
# returned unless we exit through the intended explicit "test
# successful" path.
EXIT_TEST_WIN=104
# Shell scripts in this test suite also return 104, so we need a
# convention for distinguishing successful execution of SBCL in one of
# our scripts.
EXIT_LISP_WIN=52
# Any test that exits with status 1 is an explicit failure.
EXIT_LOSE=1

LANG=C
LC_ALL=C
set +a

run_sbcl () (
    set -u
    if [ $# -gt 0 ]; then
	"$SBCL_RUNTIME" --lose-on-corruption --core "$SBCL_CORE" $SBCL_ARGS --eval "(setf sb-ext:*evaluator-mode* :${TEST_SBCL_EVALUATOR_MODE:-compile})" "$@"
    else
	"$SBCL_RUNTIME" --lose-on-corruption --core "$SBCL_CORE" $SBCL_ARGS --eval "(setf sb-ext:*evaluator-mode* :${TEST_SBCL_EVALUATOR_MODE:-compile})"
    fi
)

run_sbcl_with_args () (
    set -u
    "$SBCL_RUNTIME" --lose-on-corruption --core "$SBCL_CORE" "$@"
)

run_sbcl_with_core () (
    set -u
    core="$1"
    shift
    if [ $# -gt 0 ]; then
	"$SBCL_RUNTIME" --lose-on-corruption --core "$core" "$@"
    else
	"$SBCL_RUNTIME" --lose-on-corruption --core "$core" $SBCL_ARGS --eval "(setf sb-ext:*evaluator-mode* :${TEST_SBCL_EVALUATOR_MODE:-compile})"
    fi
)

# Most tests that run an SBCL have to check whether the child's exit
# status.  Our convention is that SBCL exits with status
# $EXIT_LISP_WIN to indicate a successful run; but some tests can't do
# this (e.g., ones that end in S-L-A-D), or need to indicate some
# other ways of succeeding.  So this routine takes a test name, the
# exit status of the child, and then an arbitrary number extra
# arguments that will be treated as status-code/message pairs for
# unusual successful ways for the inferior SBCL to exit.  If the exit
# code of the SBCL isn't found in the status-codes, the calling script
# will exit with a failure code.
check_status_maybe_lose () {
    testname=$1
    status=$2
    lose=1
    if [ $status = $EXIT_LISP_WIN ]; then
	echo "test $testname ok"
	lose=0
    else
	shift; shift;
	while [ $# -gt 0 ]; do
	    if [ $status = $1 ]; then
		shift;
		echo "test $testname ok $1"
		lose=0
		break
	    fi
	    shift; shift
	done
    fi
    if [ $lose = 1 ]; then
        echo "test $testname failed: $status"
	exit $EXIT_LOSE
    fi
    unset lose
    unset status
    unset testname
}

# Picking an output dir is delayed until actually needed.
# In particular we can't read "$SBCL_SOFTWARE_TYPE" until after test-util
# assigns it into the environment, but this script is also sourced
# by run-tests.sh itself, which means that test-util hasn't done its thing.
#
pick_random_output_dir() {
    # Avoid writing into the source tree as much as possible.
    if [ "$SBCL_SOFTWARE_TYPE" != OpenBSD ]; then
        # Don't try to run sbcl from /tmp on openbsd as it's unlikely to be
        # mounted with wxallowed
        # If a test doesn't create an executable core, it would work to use /tmp,
        # but this utility is unaware of the intent of each test.
        # This means that some tests might flake our, and/or leave junk in your tree.
        base_dir=${TMPDIR:-/tmp}
    else
        base_dir="$SBCL_PWD"
    fi
    TEST_DIRECTORY="${base_dir}/${TEST_FILESTEM}-$$"
}

# Not every test needs to touch the file system, but enough do to have
# them consistently do so in subdirectories.  Note that such tests
# should not change their exit action, or do so only very carefully.
use_test_subdirectory () { # not a "subdirectory" now, but don't feel like renaming
    if test -d "$TEST_DIRECTORY"
    then
        cleanup_test_subdirectory
    fi
    pick_random_output_dir
    mkdir "$TEST_DIRECTORY"
    cd "$TEST_DIRECTORY"
    trap "cleanup_test_subdirectory" EXIT
}

# FIXME: Is it really true that a test must alter the source tree? How pathetic.
# In particular, failures can occur in the :READDIR/DIRENT-NAME test of sb-posix
# when using parallel-exec, because "run-sbcl-test-NNNN" randomly appears
# in either the SB-POSIX:READDIR call or CL:DIRECTORY but not both.
use_test_subdirectory_in_source_tree () { # DON'T USE THIS!
    if test -d "$TEST_DIRECTORY"
    then
        cleanup_test_subdirectory
    fi
    mkdir "$TEST_DIRECTORY"
    cd "$TEST_DIRECTORY"
    trap "cleanup_test_subdirectory" EXIT
}

# Do the above but without changing the current directory
create_test_subdirectory () {
    if test -d "$TEST_DIRECTORY"
    then
        cleanup_test_subdirectory
    fi
    pick_random_output_dir
    mkdir "$TEST_DIRECTORY"
    trap "cleanup_test_subdirectory" EXIT
}

cleanup_test_subdirectory () {
    cd "$SBCL_PWD"
    ( set -f; rm -r "$TEST_DIRECTORY" )
}
