2 # tapview - a TAP (Test Anything Protocol) viewer in pure POSIX shell
4 # Copyright by Eric S. Raymond
6 # This code is intended to be embedded in your project. The author
7 # grants permission for it to be distributed under the prevailing
8 # license of your project if you choose, provided that license is
9 # OSD-compliant; otherwise the following SPDX tag incorporates a
10 # license by reference.
12 # SPDX-License-Identifier: BSD-2-Clause
15 # A newer version may be available at https://gitlab.com/esr/tapview
24 # shellcheck disable=SC2039
25 printf '%s' "$1" # https://www.etalabs.net/sh_tricks.html
29 report="${report}${1}\n"
33 # Terminate dot display and bail out with error
34 if [ "${testcount}" -gt 0 ]
38 report="${report}${1}\n"
53 # shellcheck disable=SC2086
54 context_get () { printenv "ctx_${1}${depth}"; }
55 context_set () { export "ctx_${1}${depth}=${2}"; }
60 context_set test_before_plan no
61 context_set test_after_plan no
68 if [ "$(context_get count)" -gt 0 ] && [ -z "$(context_get plan)" ]
70 ship_line "Missing a plan at line ${ln}."
72 elif [ "$(context_get test_before_plan)" = "yes" ] && [ "$(context_get test_after_plan)" = "yes" ]
74 ship_line "A plan line may only be placed before or after all tests."
76 elif [ "$(context_get plan)" != "" ] && [ "$(context_get expect)" -gt "$(context_get count)" ]
78 ship_line "Expected $(context_get expect) tests but only ${testcount} ran."
90 if expr "$line" : "Bail out!" >/dev/null
96 # Use the current indent to choose a scope level
97 indent=$(expr "$line" : '[ ]*')
98 if [ "${indent}" -lt "${depth}" ]
102 elif [ "${indent}" -gt "${depth}" ]
107 # Process a plan line
108 if expr "$line" : '[ ]*1\.\.[0-9][0-9]*' >/dev/null
110 if [ "$(context_get plan)" != "" ]
112 ship_error "tapview: cannot have more than one plan line."
114 if expr "$line" : ".* *SKIP" >/dev/null || expr "$line" : ".* *skip" >/dev/null
118 exit 1 # Not specified in the standard whether this should exit 1 or 0
120 context_set plan "${line}"
121 context_set expect "$(expr "$line" : '[ ]*1\.\.\([0-9][0-9]*\)')"
123 elif expr "$line" : '[ ]*[0-9][0-9]*\.\.[0-9][0-9]*' >/dev/null
125 echo "Ill-formed plan line at ${ln}"
128 # Check for out-of-order test point numbers with the sequence (TAP 14)
129 testpoint=$(expr "$line" : '.*ok *\([0-9][0-9]*\)')
130 if [ "${testpoint}" != "" ] && [ "$(context_get expect)" != "" ] && [ "${testpoint}" -gt "$(context_get expect)" ]
132 ship_error "tapview: testpoint number ${testpoint} is out of range for plan $(context_get plan)."
135 if expr "$line" : "[ ]*ok" >/dev/null
137 context_set count $(($(context_get count) + 1))
138 testcount=$((testcount + 1))
139 if [ "$(context_get plan)" = "" ]
141 context_set test_before_plan yes
143 context_set test_after_plan yes
145 if expr "$line" : "[^#]* # *TODO" >/dev/null || expr "$line" : "[^#]* # *todo" >/dev/null
149 todocount=$((todocount + 1))
150 if expr "$line" : "[^#]*#[^ ]" >/dev/null
152 ship_line "Suspicious comment leader at ${ln}"
154 elif expr "$line" : "[^#]* # *SKIP" >/dev/null || expr "$line" : "[^#]* # *skip" >/dev/null
158 skipcount=$((skipcount + 1))
159 if expr "$line" : "[^#]*#[^ ]" >/dev/null
161 ship_line "Suspicious comment leader at ${ln}"
169 # Process a not-ok line
170 if expr "$line" : "[ ]*not ok" >/dev/null
172 context_set count $(($(context_get count) + 1))
173 testcount=$((testcount + 1))
174 if [ "$(context_get plan)" = "" ]
176 context_set test_before_plan yes
178 context_set test_after_plan yes
180 if expr "$line" : "[^#]* # *SKIP" >/dev/null || expr "$line" : "[^#]* # *skip" >/dev/null
184 skipcount=$((skipcount + 1))
185 if expr "$line" : "[^#]* #[^ ]" >/dev/null
187 ship_line "Suspicious comment leader at lime ${ln}"
191 if expr "$line" : "[^#]* # *TODO" >/dev/null || expr "$line" : "[^#]* # *todo" >/dev/null
193 ship_char ${TODO_NOT_OK}
195 todocount=$((todocount + 1))
196 if expr "$line" : "[^#]* #[^ ]" >/dev/null
198 ship_line "Suspicious comment leader at line ${ln}"
205 failcount=$((failcount + 1))
207 if [ "$(context_get bail)" = yes ]
209 ship_line "Bailing out on line ${ln} due to +bail pragma."
214 # Process a TAP 14 pragma
215 if expr "$line" : "pragma" >/dev/null
218 # shellcheck disable=SC2086
221 +bail) context_set bail yes;;
222 -bail) context_set bail yes;;
223 +strict) context_set strict yes;;
224 -strict) context_set strict yes;;
225 *) ship_line "Pragma '$line' ignored";;
230 # shellcheck disable=SC2166
231 if [ "${state}" = "yaml" ]
234 if expr "$line" : '[ ]*\.\.\.' >/dev/null
240 elif expr "$line" : "[ ]*---" >/dev/null
246 # Ignore blank lines and comments
247 if [ -z "$line" ] || expr "$line" : '[ ]+$' >/dev/null || expr "$line" : "#" >/dev/null
251 # Any line that is not a valid plan, test result, pragma,
252 # or comment lands here.
253 if [ "$(context_get strict)" = yes ]
255 ship_line "Bailing out on line ${ln} due to +strict pragma"
266 report="${report}${testcount} tests, ${failcount} failures"
267 if [ "$todocount" != 0 ]
269 report="${report}, ${todocount} TODOs"
271 if [ "$skipcount" != 0 ]
273 report="${report}, ${skipcount} SKIPs"