Incorporate tapview
authorEric S. Raymond <esr@thyrsus.com>
Fri, 10 Feb 2023 01:10:23 +0000 (20:10 -0500)
committerEric S. Raymond <esr@thyrsus.com>
Fri, 10 Feb 2023 01:10:23 +0000 (20:10 -0500)
test/Makefile
test/tapview [new file with mode: 0755]

index 7b21af033e4783e0c9d3922a806387428b66a887..f735cc70afef8f3c9016df7e8a929ee618dae866 100644 (file)
@@ -2,23 +2,11 @@
 
 PYTHON=python3
 
-# The tests output TAP (Test Anything Proocol)
-# If you have either of these TAP viwers installed,
-# S good ing will happen.
-TAPVIEWER=cat
-ifeq (,$(command -v tapview))
-       TAPVIEWER=tapview
-else
-       ifeq (,$(command -v tappy))
-               TAPVIEWER=tappy
-       endif
-endif
-
 all:
        @echo "With Python 2:"
-       @$(MAKE) -e PYTHON=python2 regress | $(TAPVIEWER)
+       @$(MAKE) -e PYTHON=python2 regress | ./tapview
        @echo "With Python 3:"
-       @$(MAKE) -e PYTHON=python3 regress | $(TAPVIEWER)
+       @$(MAKE) -e PYTHON=python3 regress | ./tapview
        @echo "No diff output is good news."
 
 .SUFFIXES: .log .chk
diff --git a/test/tapview b/test/tapview
new file mode 100755 (executable)
index 0000000..ca984eb
--- /dev/null
@@ -0,0 +1,280 @@
+#! /bin/sh
+# tapview - a TAP (Test Anything Protocol) viewer in pure POSIX shell
+#
+# Copyright by Eric S. Raymond
+#
+# This code is intended to be embedded in your project. The author
+# grants permission for it to be distributed under the prevailing
+# license of your project if you choose, provided that license is
+# OSD-compliant; otherwise the following SPDX tag incorporates a
+# license by reference.
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# This is version 1.6
+# A newer version may be available at https://gitlab.com/esr/tapview
+#
+OK="."
+FAIL="F"
+SKIP="s"
+TODO_NOT_OK="x"
+TODO_OK="u"
+
+ship_char() {
+    # shellcheck disable=SC2039
+    printf '%s' "$1"   # https://www.etalabs.net/sh_tricks.html
+}
+
+ship_line() {
+    report="${report}${1}\n"
+}
+
+ship_error() {
+    # Terminate dot display and bail out with error
+    if [ "${testcount}" -gt 0 ]
+    then
+       echo ""
+    fi
+    report="${report}${1}\n"
+    echo "${report}"
+    exit 1
+}
+
+testcount=0
+failcount=0
+skipcount=0
+todocount=0
+status=0
+report=""
+IFS=""
+ln=0
+state=plaintext
+
+# shellcheck disable=SC2086
+context_get () { printenv "ctx_${1}${depth}"; }
+context_set () { export "ctx_${1}${depth}=${2}"; }
+
+context_push () {
+    context_set plan ""
+    context_set count 0
+    context_set test_before_plan no
+    context_set test_after_plan no
+    context_set expect ""
+    context_set bail no
+    context_set strict no
+}
+
+context_pop () {
+    if [ "$(context_get count)" -gt 0 ] && [ -z "$(context_get plan)" ]
+    then
+       ship_line "Missing a plan at line ${ln}."
+       status=1
+    elif [ "$(context_get test_before_plan)" = "yes" ] && [ "$(context_get test_after_plan)" = "yes" ] 
+    then
+       ship_line "A plan line may only be placed before or after all tests."
+       status=1
+    elif [ "$(context_get plan)" != "" ] && [ "$(context_get expect)" -gt "$(context_get count)" ]
+    then
+       ship_line "Expected $(context_get expect) tests but only ${testcount} ran."
+       status=1
+    fi
+}
+
+depth=0
+context_push
+
+while read -r line
+do
+    ln=$((ln + 1))
+    # Process bailout
+    if expr "$line" : "Bail out!" >/dev/null
+    then
+       ship_line "$line"
+       status=2
+       break
+    fi
+    # Use the current indent to choose a scope level
+    indent=$(expr "$line" : '[         ]*')
+    if [ "${indent}" -lt "${depth}" ]
+    then
+       context_pop
+        depth="${indent}"
+    elif [ "${indent}" -gt "${depth}" ]
+    then
+       depth="${indent}"
+       context_push
+    fi
+    # Process a plan line
+    if expr "$line" : '[       ]*1\.\.[0-9][0-9]*' >/dev/null
+    then
+       if [ "$(context_get plan)" != "" ]
+       then
+           ship_error "tapview: cannot have more than one plan line."
+       fi
+       if expr "$line" : ".* *SKIP" >/dev/null || expr "$line" : ".* *skip" >/dev/null
+       then
+           ship_line "$line"
+           echo "${report}"
+           exit 1      # Not specified in the standard whether this should exit 1 or 0
+       fi
+       context_set plan "${line}"
+       context_set expect "$(expr "$line" : '[         ]*1\.\.\([0-9][0-9]*\)')"
+       continue
+    elif expr "$line" : '[     ]*[0-9][0-9]*\.\.[0-9][0-9]*' >/dev/null
+    then
+        echo "Ill-formed plan line at ${ln}"
+        exit 1
+    fi
+    # Check for out-of-order test point numbers with the sequence (TAP 14)
+    testpoint=$(expr "$line" : '.*ok  *\([0-9][0-9]*\)')
+    if [ "${testpoint}" != "" ] && [ "$(context_get expect)" != "" ] && [ "${testpoint}" -gt "$(context_get expect)" ]
+    then
+       ship_error "tapview: testpoint number ${testpoint} is out of range for plan $(context_get plan)."
+    fi
+    # Process an ok line
+    if expr "$line" : "[       ]*ok" >/dev/null
+    then
+       context_set count $(($(context_get count) + 1)) 
+       testcount=$((testcount + 1))
+       if [ "$(context_get plan)" = "" ]
+       then
+           context_set test_before_plan yes
+       else
+           context_set test_after_plan yes
+       fi
+       if expr "$line" : "[^#]* # *TODO" >/dev/null || expr "$line" : "[^#]* # *todo" >/dev/null
+       then
+           ship_char ${TODO_OK}
+           ship_line "$line"
+           todocount=$((todocount + 1))
+           if expr "$line" : "[^#]*#[^ ]" >/dev/null
+           then
+               ship_line "Suspicious comment leader at ${ln}"
+           fi
+       elif expr "$line" : "[^#]* # *SKIP" >/dev/null || expr "$line" : "[^#]* # *skip" >/dev/null
+       then
+           ship_char ${SKIP}
+           ship_line "$line"
+           skipcount=$((skipcount + 1))
+           if expr "$line" : "[^#]*#[^ ]" >/dev/null
+           then
+               ship_line "Suspicious comment leader at ${ln}"
+           fi
+       else
+           ship_char ${OK}
+       fi
+       state=plaintext
+       continue
+    fi
+    # Process a not-ok line
+    if expr "$line" : "[       ]*not ok" >/dev/null
+    then
+       context_set count $(($(context_get count) + 1)) 
+       testcount=$((testcount + 1))
+       if [ "$(context_get plan)" = "" ]
+       then
+           context_set test_before_plan yes
+       else
+           context_set test_after_plan yes
+       fi
+       if expr "$line" : "[^#]* # *SKIP" >/dev/null || expr "$line" : "[^#]* # *skip" >/dev/null
+       then
+           ship_char "${SKIP}"
+           state=plaintext
+           skipcount=$((skipcount + 1))
+           if expr "$line" : "[^#]* #[^ ]" >/dev/null
+           then
+               ship_line "Suspicious comment leader at lime ${ln}"
+           fi
+           continue
+       fi
+       if expr "$line" : "[^#]* # *TODO" >/dev/null || expr "$line" : "[^#]* # *todo" >/dev/null
+       then
+           ship_char ${TODO_NOT_OK}
+           state=plaintext
+           todocount=$((todocount + 1))
+           if expr "$line" : "[^#]* #[^ ]" >/dev/null
+           then
+               ship_line "Suspicious comment leader at line ${ln}"
+           fi
+           continue
+       fi
+       ship_char "${FAIL}"
+       ship_line "$line"
+       state=plaintext
+       failcount=$((failcount + 1))
+       status=1
+       if [ "$(context_get bail)" = yes ]
+       then
+           ship_line "Bailing out on line ${ln} due to +bail pragma."
+           break
+       fi
+       continue
+    fi
+    # Process a TAP 14 pragma
+    if expr "$line" : "pragma" >/dev/null
+    then
+       unset IFS
+       # shellcheck disable=SC2086
+       set -- $line
+       case "$2" in
+           +bail) context_set bail yes;;
+           -bail) context_set bail yes;;
+           +strict) context_set strict yes;;
+           -strict) context_set strict yes;;
+           *) ship_line "Pragma '$line' ignored";;
+       esac
+       IFS=""
+       continue
+    fi
+    # shellcheck disable=SC2166
+    if [ "${state}" = "yaml" ]
+    then
+       ship_line "$line"
+       if expr "$line" : '[    ]*\.\.\.' >/dev/null
+       then
+           state=plaintext
+       else
+           continue
+       fi
+    elif expr "$line" : "[     ]*---" >/dev/null
+    then
+       ship_line "$line"
+       state=yaml
+       continue
+    fi
+    # Ignore blank lines and comments
+    if [ -z "$line" ] || expr "$line" : '[     ]+$' >/dev/null || expr "$line" : "#" >/dev/null
+    then
+       continue
+    fi
+    # Any line that is not a valid plan, test result, pragma,
+    # or comment lands here.
+    if [ "$(context_get strict)" = yes ]
+    then
+       ship_line "Bailing out on line ${ln} due to +strict pragma"
+       status=1
+       break
+    fi
+done
+
+/bin/echo ""
+
+depth=0
+context_pop
+
+report="${report}${testcount} tests, ${failcount} failures"
+if [ "$todocount" != 0 ]
+then
+    report="${report}, ${todocount} TODOs"
+fi
+if [ "$skipcount" != 0 ]
+then
+    report="${report}, ${skipcount} SKIPs"
+fi
+
+echo "${report}."
+
+exit "${status}"
+
+# end