# vim: ts=4 sw=4 expandtab ft=sh # # Shell functions used to run the recompilation tests. # # Set a limit of ten minutes for each command. If a command takes that long, # it is almost certainly in an infinite loop. ulimit -t 600 # Set variables `main_module' and `modules' describing the test being run. # Copy in the initial versions of the test files. test_module () { echo "executing shell function test_module $@" if test "$#" = 0 then echo "usage: test_module main_module other_modules" exit 1 fi main_module="$1" modules="$*" echo Testing ${main_module} for module in ${modules} do rm -f "${module}.m" cp "${module}.m.1" "${module}.m" # The module.m. files are the only ones that should be edited. chmod -w ${module}.m done rm -f "${main_module}.res" touch "${main_module}.res" # XXX Avoid producing output files with the same timestamp as # the input source file. The up-to-date check for the output file # in recompilation_check.m checks that the output file's timestamp # is strictly greater than the input file's, so it will recompile # if they are the same. # # This won't be a problem in practice, unless for some reason a user # decides to have mmake invoked by their editor automatically after # each edit. If a file takes less than a second to compile, recompiling it # all the time won't be noticeable. However, the recompilation will affect # the `--verbose-recompilation' messages, which we compare to the expected # output, so we need to avoid it here. sleep 1 } # Simulate a user editing the file. update_module () { # echo "executing shell function update_module $@" if test "$#" != 2 then echo "usage: update_module module_name version" exit 1 fi module="$1" module_version="$2" # GNU make only considers a file out of date if a dependency's timestamp # is strictly greater than the file's timestamp. We need to make sure # that the `.c' file is out of date with respect to the `.m' file. sleep 1 rm -f "${module}.m" cp "${module}.m.${module_version}" "${module}.m" chmod -w "${module}.m" # See comment in test_module(). sleep 1 } mmake_depend () { # echo "executing shell function mmake_depend $@" eval mmake ${mmakeopts} "${main_module}.depend" || exit 1 } # Build the test, then run it and compare the output. mmake_test () { # echo "executing shell function mmake_test $@" if test "$#" != 2 then echo "** usage: mmake_test output_file_version should_{fail,succeed}" exit 1 fi output_file_version="$1" should="$2" # XXX This is a hacky way of testing for Java grades. # echo "mmakeopts=${mmakeopts}" case "${mmakeopts}" in *java*) target=${main_module}.classes run_target="java ${main_module}" ;; *) target=${main_module} run_target="./${main_module}" ;; esac case "${should}" in should_succeed) eval mmake ${mmakeopts} "${target}" case "$?" in 0) ${run_target} > "${main_module}.out" compare_files "${main_module}.exp.${output_file_version}" \ "${main_module}.out" ;; *) echo "** Error: mmake ${mmakeopts} ${target} failed" \ "(it was expected to succeed)" exit 1 ;; esac ;; should_fail) # If the compilation is supposed to fail, then we suppress # the mmake output, to avoid burying genuine failures in a sea # of expected failures in the nightly test logs. The `-k' option # to mmake avoids differences in the output when using # parallel mmakes. eval mmake ${mmakeopts} -k "${target}" \ > "${main_module}.failing_make_output" 2>&1 case "$?" in 0) echo "** Error: mmake ${mmakeopts} ${target} succeeded" \ "(it was expected to fail)" exit 1 ;; *) ;; esac ;; *) echo "** Error: bad should ${should}" exit 1 ;; esac } # Compare the output file with the expected output file, generating # the expected output file if (a) it doesn't exist and (b) runtests was given # the --generate-missing-exp-files option. compare_files () { if test "$#" != 2 then echo "** usage: compare_files expected_file result_file" exit 1 fi exp_file="$1" res_file="$2" if test -f "${exp_file}" then if diff ${DIFF_OPTS-"-c"} "${exp_file}" "${res_file}" \ >> "${main_module}.res" then : else echo "** Error: ${exp_file} and ${res_file} differ." exit 1 fi else if test "${generate_missing_exp_files}" = true then echo "** WARNING: generating ${exp_file}" cp "${res_file}" "${exp_file}" else echo "** Error: ${exp_file} not found" exit 1 fi fi } check_err_file () { # echo "executing shell function check_err_file $@" if test "$#" != 2 then echo "** usage: check_err_file module message_file_version" fi module="$1" error_file_version="$2" # In `.hl*' grades, the compiler sometimes puts an extra line in # the `.err' file ("foo.h has CHANGED"). Filter it out here. # Also filter out any references to the directories created by the # `--use-subdirs' option. sed -e '/has CHANGED/d' -e 's/Mercury\/.*\///g' "${module}.err" \ > "${module}.err2" mv "${module}.err2" "${module}.err" compare_files "${module}.err_exp.${error_file_version}" "${module}.err" } cleanup_test () { # echo "executing shell function cleanup_test $@" # XXX "${cleanup}" does not seem to be set to "true" *anywhere*. case "${cleanup}" in true) eval mmake ${mmakeopts} "${main_module}.realclean" for module in ${modules} do rm -f "${module}.m" done ;; esac }