128128# ```
129129# FIXME(ztombol): Display `${lines[@]}' instead of `$output'!
130130assert_line () {
131+ __assert_line " $@ "
132+ }
133+
134+ # assert_stderr_line
135+ # ===========
136+ #
137+ # Summary: Fail if the expected line is not found in the stderr (default) or at a specific line number.
138+ #
139+ # Usage: assert_stderr_line [-n index] [-p | -e] [--] <expected>
140+ #
141+ # Options:
142+ # -n, --index <idx> Match the <idx>th line
143+ # -p, --partial Match if `expected` is a substring of `$stderr` or line <idx>
144+ # -e, --regexp Treat `expected` as an extended regular expression
145+ # <expected> The expected line string, substring, or regular expression
146+ #
147+ # IO:
148+ # STDERR - details, on failure
149+ # error message, on error
150+ # Globals:
151+ # stderr
152+ # stderr_lines
153+ # Returns:
154+ # 0 - if matching line found
155+ # 1 - otherwise
156+ #
157+ # Similarly to `assert_stderr`, this function verifies that a command or function produces the expected stderr.
158+ # (It is the logical complement of `refute_stderr_line`.)
159+ # It checks that the expected line appears in the stderr (default) or at a specific line number.
160+ # Matching can be literal (default), partial or regular expression.
161+ #
162+ assert_stderr_line () {
163+ __assert_line " $@ "
164+ }
165+
166+ __assert_line () {
167+ local -r caller=${FUNCNAME[1]}
131168 local -i is_match_line=0
132169 local -i is_mode_partial=0
133170 local -i is_mode_regexp=0
134- : " ${lines?} "
171+
172+ if [[ " ${caller} " == " assert_line" ]]; then
173+ local -ar stream_lines=(" ${lines[@]} " )
174+ local -r stream_type=output
175+ elif [[ " ${caller} " == " assert_stderr_line" ]]; then
176+ local -ar stream_lines=(" ${stderr_lines[@]} " )
177+ local -r stream_type=stderr
178+ else
179+ # Coding error: unknown caller
180+ :
181+ fi
135182
136183 # Handle options.
137184 while (( $# > 0 )) ; do
138185 case " $1 " in
139186 -n|--index)
140187 if (( $# < 2 )) || ! [[ $2 =~ ^-? ([0-9]| [1-9][0-9]+)$ ]]; then
141188 echo " \` --index' requires an integer argument: \` $2 '" \
142- | batslib_decorate ' ERROR: assert_line ' \
189+ | batslib_decorate " ERROR: ${caller} " \
143190 | fail
144191 return $?
145192 fi
@@ -156,7 +203,7 @@ assert_line() {
156203
157204 if (( is_mode_partial )) && (( is_mode_regexp )) ; then
158205 echo " \` --partial' and \` --regexp' are mutually exclusive" \
159- | batslib_decorate ' ERROR: assert_line ' \
206+ | batslib_decorate " ERROR: ${caller} " \
160207 | fail
161208 return $?
162209 fi
@@ -166,7 +213,7 @@ assert_line() {
166213
167214 if (( is_mode_regexp == 1 )) && [[ ' ' =~ $expected ]] || (( $? == 2 )) ; then
168215 echo " Invalid extended regular expression: \` $expected '" \
169- | batslib_decorate ' ERROR: assert_line ' \
216+ | batslib_decorate " ERROR: ${caller} " \
170217 | fail
171218 return $?
172219 fi
@@ -175,73 +222,73 @@ assert_line() {
175222 if (( is_match_line )) ; then
176223 # Specific line.
177224 if (( is_mode_regexp )) ; then
178- if ! [[ ${lines [$idx]} =~ $expected ]]; then
225+ if ! [[ ${stream_lines [$idx]} =~ $expected ]]; then
179226 batslib_print_kv_single 6 \
180227 ' index' " $idx " \
181228 ' regexp' " $expected " \
182- ' line' " ${lines [$idx]} " \
229+ ' line' " ${stream_lines [$idx]} " \
183230 | batslib_decorate ' regular expression does not match line' \
184231 | fail
185232 fi
186233 elif (( is_mode_partial )) ; then
187- if [[ ${lines [$idx]} != * " $expected " * ]]; then
234+ if [[ ${stream_lines [$idx]} != * " $expected " * ]]; then
188235 batslib_print_kv_single 9 \
189236 ' index' " $idx " \
190237 ' substring' " $expected " \
191- ' line' " ${lines [$idx]} " \
238+ ' line' " ${stream_lines [$idx]} " \
192239 | batslib_decorate ' line does not contain substring' \
193240 | fail
194241 fi
195242 else
196- if [[ ${lines [$idx]} != " $expected " ]]; then
243+ if [[ ${stream_lines [$idx]} != " $expected " ]]; then
197244 batslib_print_kv_single 8 \
198245 ' index' " $idx " \
199246 ' expected' " $expected " \
200- ' actual' " ${lines [$idx]} " \
247+ ' actual' " ${stream_lines [$idx]} " \
201248 | batslib_decorate ' line differs' \
202249 | fail
203250 fi
204251 fi
205252 else
206- # Contained in output.
253+ # Contained in output/error stream .
207254 if (( is_mode_regexp )) ; then
208255 local -i idx
209- for (( idx = 0 ; idx < ${# lines [@]} ; ++ idx )) ; do
210- [[ ${lines [$idx]} =~ $expected ]] && return 0
256+ for (( idx = 0 ; idx < ${# stream_lines [@]} ; ++ idx )) ; do
257+ [[ ${stream_lines [$idx]} =~ $expected ]] && return 0
211258 done
212259 { local -ar single=( ' regexp' " $expected " )
213- local -ar may_be_multi=( ' output ' " $output " )
260+ local -ar may_be_multi=( " ${stream_type} " " ${ ! stream_type} " )
214261 local -ir width=" $( batslib_get_max_single_line_key_width " ${single[@]} " " ${may_be_multi[@]} " ) "
215262 batslib_print_kv_single " $width " " ${single[@]} "
216263 batslib_print_kv_single_or_multi " $width " " ${may_be_multi[@]} "
217264 } \
218- | batslib_decorate ' no output line matches regular expression' \
265+ | batslib_decorate " no ${stream_type} line matches regular expression" \
219266 | fail
220267 elif (( is_mode_partial )) ; then
221268 local -i idx
222- for (( idx = 0 ; idx < ${# lines [@]} ; ++ idx )) ; do
223- [[ ${lines [$idx]} == * " $expected " * ]] && return 0
269+ for (( idx = 0 ; idx < ${# stream_lines [@]} ; ++ idx )) ; do
270+ [[ ${stream_lines [$idx]} == * " $expected " * ]] && return 0
224271 done
225272 { local -ar single=( ' substring' " $expected " )
226- local -ar may_be_multi=( ' output ' " $output " )
273+ local -ar may_be_multi=( " ${stream_type} " " ${ ! stream_type} " )
227274 local -ir width=" $( batslib_get_max_single_line_key_width " ${single[@]} " " ${may_be_multi[@]} " ) "
228275 batslib_print_kv_single " $width " " ${single[@]} "
229276 batslib_print_kv_single_or_multi " $width " " ${may_be_multi[@]} "
230277 } \
231- | batslib_decorate ' no output line contains substring' \
278+ | batslib_decorate " no ${stream_type} line contains substring" \
232279 | fail
233280 else
234281 local -i idx
235- for (( idx = 0 ; idx < ${# lines [@]} ; ++ idx )) ; do
236- [[ ${lines [$idx]} == " $expected " ]] && return 0
282+ for (( idx = 0 ; idx < ${# stream_lines [@]} ; ++ idx )) ; do
283+ [[ ${stream_lines [$idx]} == " $expected " ]] && return 0
237284 done
238285 { local -ar single=( ' line' " $expected " )
239- local -ar may_be_multi=( ' output ' " $output " )
286+ local -ar may_be_multi=( " ${stream_type} " " ${ ! stream_type} " )
240287 local -ir width=" $( batslib_get_max_single_line_key_width " ${single[@]} " " ${may_be_multi[@]} " ) "
241288 batslib_print_kv_single " $width " " ${single[@]} "
242289 batslib_print_kv_single_or_multi " $width " " ${may_be_multi[@]} "
243290 } \
244- | batslib_decorate ' output does not contain line' \
291+ | batslib_decorate " ${stream_type} does not contain line" \
245292 | fail
246293 fi
247294 fi
0 commit comments