Add a testsuite (./testsuite) and dependency-logging command stuff that doesn't
[mgear/mgear.git] / testsuite
diff --git a/testsuite b/testsuite
new file mode 100755 (executable)
index 0000000..3329a66
--- /dev/null
+++ b/testsuite
@@ -0,0 +1,238 @@
+#!/bin/bash
+# Test suite for Mage.
+
+echo "Test suite for Mage"
+
+cd "$(dirname "$0")"
+Z=test-zone
+rm -rf $Z
+mkdir $Z
+cd $Z
+
+#exec 3>&2
+#exec 1>test.log 2>&1
+exec </dev/null
+set -e
+set -o errtrace
+section=Initialization
+trap 'echo; echo "TEST SUITE FAILED in section $section!" >&2' ERR
+#set -x
+
+ln -s ../mage.mk mage.mk
+
+function fail {
+       false
+}
+
+function start_section {
+       section="$1"
+       echo
+       echo "SECTION: $1"
+}
+
+function do_mage {
+       echo "Running: make $*"
+       make "$@" 2>&1 | tee mage.log
+}
+
+function assert_contents {
+       if diff -u - "$1"; then
+               echo "File '$1' looks good."
+       else
+               echo "File '$1' has the wrong contents!"
+               fail
+       fi
+}
+
+# Options can be passed to grep: assert_saw -i override
+function assert_saw {
+       if grep -q "$@" mage.log; then
+               echo "Good, saw '${@:$#}' in build log."
+       else
+               echo "Expected '${@:$#}' in build log but didn't see it!  Log:"
+               cat mage.log
+               fail
+       fi
+}
+function assert_not_saw {
+       if ! grep -q "$@" mage.log; then
+               echo "Good, saw '${@:$#}' in build log."
+       else
+               echo "Did not expect '${@:$#}' in build log but saw it!  Log:"
+               cat mage.log
+               fail
+       fi
+}
+function assert_uptodate {
+       assert_saw "make: \`$1' is up to date."
+}
+function assert_generated {
+       assert_saw "$1.tmp"
+}
+
+function remember_mtime {
+       while [ $# != 0 ]; do
+               eval "orig_mtime_${1//[^A-Za-z]/}=$(stat --format=%Y $1)"
+               shift
+       done
+}
+function assert_touched {
+       mtvar=orig_mtime_${1//[^A-Za-z]/}
+       t1="${!mtvar}"
+       t2="$(stat --format=%Y $1)"
+       echo "Times for '$1': $t1, $t2"
+       if [ "$t1" != "$t2" ]; then
+               echo "Good, '$1' was touched."
+       else
+               echo "Expected '$1' to be touched but it wasn't!"
+               fail
+       fi
+}
+function assert_not_touched {
+       mtvar=orig_mtime_${1//[^A-Za-z]/}
+       t1="${!mtvar}"
+       t2="$(stat --format=%Y $1)"
+       echo "Times for '$1': $t1, $t2"
+       if [ "$t1" == "$t2" ]; then
+               echo "Good, '$1' was not touched."
+       else
+               echo "Expected '$1' to be not touched but it was!"
+               fail
+       fi
+}
+
+# Simple makefile for stripping two kinds of comments.
+# Tests an implicit rule and two competing explicit rules.
+# Watch those dollar signs!
+cat >Makefile <<'EOF'
+include mage.mk
+.SECONDARY:
+include hc-rule.mk
+$(call mg-define-rule,%,%.ssc,sleep 1 && grep 'warn' $$< && sed -e 's_//.*$$$$__' $$< >$$t)
+$(call mg-define-rule,index,index.in,sort $$< >$$t)
+EOF
+cat >hc-rule.mk <<'EOF'
+$(call mg-define-rule,%,%.hc,sed -e 's_#.*$$$$__' $$< >$$t)
+EOF
+
+# Input files.
+cat >foo.hc <<'EOF'
+This is the foo file.
+# You don't get to see this.
+But you do get to see this!
+// Needles: you can lean but you can't hide!
+EOF
+cat >bar.ssc <<'EOF'
+the bar file has a different personality
+// hey there
+# I slip through
+warn: tell me about it!
+EOF
+cat >index.in <<'EOF'
+foo
+bar
+EOF
+
+# Run and make sure the files were compiled correctly.
+
+start_section "Initial full build"
+do_mage foo bar index
+
+assert_contents foo <<'EOF'
+This is the foo file.
+
+But you do get to see this!
+// Needles: you can lean but you can't hide!
+EOF
+assert_contents bar <<'EOF'
+the bar file has a different personality
+
+# I slip through
+warn: tell me about it!
+EOF
+assert_contents index <<'EOF'
+bar
+foo
+EOF
+assert_generated foo
+assert_generated bar
+assert_generated index
+assert_saw "sed -e 's_#.*\$__' foo.hc >foo.tmp"
+assert_saw "sleep 1 && grep 'warn' bar.ssc && sed -e 's_//.*\$__' bar.ssc >bar.tmp"
+assert_saw 'warn: tell me about it!'
+assert_saw sort index.in >index.tmp
+
+# Run it again.  Make sure the warning is replayed and bar isn't overridden due
+# to bar.g accidentally being too old.
+
+start_section "Replay bar warning"
+do_mage foo bar index
+
+assert_uptodate foo
+assert_uptodate bar
+assert_uptodate index
+assert_saw -i '#.*warning.*replay' # Indication of warning replay
+assert_saw 'warn: tell me about it!' # Actual warning
+assert_not_saw -i overrid
+
+# Now override bar and make sure it stays that way and the warning isn't replayed.
+start_section "Override bar"
+sleep 1 # No racy cleanliness
+echo NEWCONTENT >bar
+do_mage bar
+
+assert_saw -i overrid
+assert_contents bar <<<NEWCONTENT
+
+# Change foo.hc and make sure foo is updated properly.
+
+start_section "Change foo.hc"
+sleep 1 # No racy cleanliness
+echo 'look: # Last-minute addition.' >>foo.hc
+do_mage index foo
+
+assert_uptodate index
+assert_generated foo
+assert_contents foo <<'EOF'
+This is the foo file.
+
+But you do get to see this!
+// Needles: you can lean but you can't hide!
+look: 
+EOF
+
+# Change the rule for # comments to strip spaces before a #.
+# Make sure foo is updated properly.
+
+start_section "Command change for % <- %.hc"
+cat >hc-rule.mk <<'EOF'
+$(call mg-define-rule,%,%.hc,sed -e 's_ *#.*$$$$__' $$< >$$t)
+EOF
+do_mage foo
+
+assert_generated foo
+assert_contents foo <<'EOF'
+This is the foo file.
+
+But you do get to see this!
+// Needles: you can lean but you can't hide!
+look:
+EOF
+
+# Remove a space before a # from foo.hc.  This is an inconsequential change.
+# Make sure that foo.g is touched but foo is not.
+
+start_section "Inconsequential change to foo.hc"
+sleep 1 # No racy cleanliness
+remember_mtime foo foo.g
+sed -e '$s/look: /look:/' -i foo.hc
+do_mage foo
+
+assert_generated foo
+assert_touched foo.g
+assert_not_touched foo
+
+cd ..
+rm -rf test-zone
+echo
+echo "TEST SUITE SUCCEEDED"