#!/bin/bash # Assert that a program can be derived from the ASG as expected. # # See `./README.md` for more information. set -euo pipefail mypath=$(dirname "$0") . "$mypath/../../conf.sh" # Performing this check within `<()` below won't cause a failure. : "${P_XMLLINT?}" # conf.sh tamer-flag-or-exit-ok wip-asg-derived-xmli run-test() { local name="${1?Missing test name}" local dir="${2?Missing dir}" shift 2 rm -f "$dir/"*.log header "$dir" "$name" "test-$name" "$dir" "$@" || { local ret=$? echo ' [FAIL]' return "$ret" } echo ' [ OK ]' } timed-tamec() { local dir="${1?Missing directory name}" local in="${2?Missing input filename}" local out="${3?Missing output filename}" dir="${dir%/}" # strip trailing slash, if any (just to style output) local -i ret=0 # /usr/bin/time does not have high enough precision # This won't be wholly accurate because time is spent in shell, # but it'll be close enough. local -i start_ns=$(date +%s%N) command time -f "%F/%Rfault %I/%Oio %Mrss %c/%wctx \n%C" -o "$dir/time.log" \ "${TAMER_PATH_TAMEC?}" -o "$dir/$out" --emit xmlo "$dir/$in" \ &> "$dir/tamec-$out.log" \ || ret=$? local -i end_ns=$(date +%s%N) local -i elapsed_ms=$(( (end_ns - start_ns) / 1000000 )) # First line will be "Command exited with non-zero status N" on failure. # The last line will be '%C' above. # So, we want the second-to-last line. # # Newline omission is intentional. printf "<%3dms %s" "$elapsed_ms" "$(tail -n2 "$dir/time.log" | head -n1)" return "$ret" } header() { # allocate enough space based on the path we'll output local -i mypath_len=${#mypath} local -i dirlen=$((mypath_len + 12)) # newline intentionally omitted printf "%-${dirlen}s %-20s " "$@" } # Derive a program from `src.xml` and verify that it meets our expectations. # # This test is inherently fragile, as it will break any time we perform # certain types of optimizations or change internal representations. _But # that is intended._ We want to be well aware of such changes in derivation # so that we can judge whether it needs adjustment. test-derive-from-src() { local dir="${1?Missing directory name}" timed-tamec "$dir" src.xml out.xmli || return diff <("$P_XMLLINT" --format "$dir/expected.xml" || echo 'ERR expected.xml') \ <("$P_XMLLINT" --format "$dir/out.xmli" || echo 'ERR out.xmli') \ &> "$dir/diff.log" } # Having taken `A` and derived `B`, we should be able to take `B` and derive # `C`, where `B` and `C` are equivalent programs. # # That is, this derivation should be transitively equivalent and reach a # fixpoint on the second derivation. This serves as a sanity check to # ensure that the program we generated makes sense to our own system. # # Note that, in the future, we'll have to strip handoff metadata # (`preproc:*` data) from the output so that it will be accepted by TAMER. test-fixpoint() { local dir="${1?Missing directory name}" timed-tamec "$dir" out.xmli out-2.xmli || return diff <("$P_XMLLINT" --format "$dir/expected.xml" || echo 'ERR expected.xml') \ <("$P_XMLLINT" --format "$dir/out-2.xmli" || echo 'ERR out.xmli') \ &> "$dir/diff.log" } main() { local -a fail=() for dir in "$mypath"/*/; do run-test derive-from-src "$dir" && run-test fixpoint "$dir" \ || fail=("${fail[@]}" "$dir") done test -z "${fail[@]}" || { cat << EOF !!! TEST FAILED tamec: $TAMER_PATH_TAMEC note: The compiler output and diff between the expected and given data are below. Both files are formatted with \`xmllint\` automatically. EOF for dir in "${fail[@]}"; do echo echo ",=====[ $dir logs ]======" echo "|" cat "$dir/"*.log | sed 's/^/| /' echo "|" echo "\`====[ end $dir logs ]====" done exit 1 } } main "$@"