|
| 1 | +# |
| 2 | +# batslib.bash |
| 3 | +# ------------ |
| 4 | +# |
| 5 | +# The Standard Library is a collection of test helpers intended to |
| 6 | +# simplify testing. It contains the following types of test helpers. |
| 7 | +# |
| 8 | +# - Assertions are functions that perform a test and output relevant |
| 9 | +# information on failure to help debugging. They return 1 on failure |
| 10 | +# and 0 otherwise. |
| 11 | +# |
| 12 | +# All output is formatted for readability using the functions of |
| 13 | +# `output.bash' and sent to the standard error. |
| 14 | +# |
| 15 | + |
| 16 | +source "${BATS_LIB}/batslib/output.bash" |
| 17 | + |
| 18 | + |
| 19 | +######################################################################## |
| 20 | +# ASSERTIONS |
| 21 | +######################################################################## |
| 22 | + |
| 23 | +# Fail and display an error message. The message is specified either by |
| 24 | +# positional parameters or on the standard input (by piping or |
| 25 | +# redirection). |
| 26 | +# |
| 27 | +# Globals: |
| 28 | +# none |
| 29 | +# Arguments: |
| 30 | +# $@ - [opt = STDIN] message to display |
| 31 | +# Returns: |
| 32 | +# 1 - always |
| 33 | +# Inputs: |
| 34 | +# STDIN - [opt = $@] message to display |
| 35 | +# Outputs: |
| 36 | +# STDERR - error message |
| 37 | +flunk() { |
| 38 | + (( $# == 0 )) && batslib_err || batslib_err "$@" |
| 39 | + return 1 |
| 40 | +} |
| 41 | + |
| 42 | +# Fail and display the given condition if it evaluates to false. Only |
| 43 | +# simple commands can be used in the expression given to `assert'. |
| 44 | +# Compound commands, such as `[[', are not supported. |
| 45 | +# |
| 46 | +# Globals: |
| 47 | +# none |
| 48 | +# Arguments: |
| 49 | +# $@ - condition to evaluate |
| 50 | +# Returns: |
| 51 | +# 0 - condition evaluated to TRUE |
| 52 | +# 1 - condition evaluated to FALSE |
| 53 | +# Outputs: |
| 54 | +# STDERR - failed condition, on failure |
| 55 | +assert() { |
| 56 | + if ! "$@"; then |
| 57 | + echo "condition : $@" | batslib_decorate 'assertion failed' | flunk |
| 58 | + fi |
| 59 | +} |
| 60 | + |
| 61 | +# Fail and display an error message if the two parameters, expected and |
| 62 | +# actual value respectively, do not equal. The error message contains |
| 63 | +# both parameters. |
| 64 | +# |
| 65 | +# Globals: |
| 66 | +# none |
| 67 | +# Arguments: |
| 68 | +# $1 - expected value |
| 69 | +# $2 - actual value |
| 70 | +# Returns: |
| 71 | +# 0 - expected equals actual value |
| 72 | +# 1 - otherwise |
| 73 | +# Outputs: |
| 74 | +# STDERR - expected and actual value, on failure |
| 75 | +assert_equal() { |
| 76 | + if [[ $1 != "$2" ]]; then |
| 77 | + batslib_print_kv_single_or_multi 8 \ |
| 78 | + 'expected' "$1" \ |
| 79 | + 'actual' "$2" \ |
| 80 | + | batslib_decorate 'values do not equal' \ |
| 81 | + | flunk |
| 82 | + fi |
| 83 | +} |
| 84 | + |
| 85 | +# Fail and display an error message if `$output' does not equal the |
| 86 | +# expected output as specified either by the first positional parameter |
| 87 | +# or on the standard input (by piping or redirection). The error message |
| 88 | +# contains the expected and the actual output. |
| 89 | +# |
| 90 | +# Globals: |
| 91 | +# output |
| 92 | +# Arguments: |
| 93 | +# $1 - [opt = STDIN] expected output |
| 94 | +# Returns: |
| 95 | +# 0 - expected equals actual output |
| 96 | +# 1 - otherwise |
| 97 | +# Inputs: |
| 98 | +# STDIN - [opt = $1] expected output |
| 99 | +# Outputs: |
| 100 | +# STDERR - expected and actual output, on failure |
| 101 | +assert_output() { |
| 102 | + local expected |
| 103 | + (( $# == 0 )) && expected="$(cat -)" || expected="$1" |
| 104 | + if [[ $expected != "$output" ]]; then |
| 105 | + batslib_print_kv_single_or_multi 8 \ |
| 106 | + 'expected' "$expected" \ |
| 107 | + 'actual' "$output" \ |
| 108 | + | batslib_decorate 'output differs' \ |
| 109 | + | flunk |
| 110 | + fi |
| 111 | +} |
| 112 | + |
| 113 | +# Fail and display an error message if `$status' is not zero. The error |
| 114 | +# message contains `$status' and `$output'. |
| 115 | +# |
| 116 | +# Optionally, if the status check passed, `$output' can be tested |
| 117 | +# against the first positional parameter as expected output. If the |
| 118 | +# output check fails the error message contains the expected and the |
| 119 | +# actual output. |
| 120 | +# |
| 121 | +# Globals: |
| 122 | +# status |
| 123 | +# output |
| 124 | +# Arguments: |
| 125 | +# $1 - [opt] expected output |
| 126 | +# Returns: |
| 127 | +# 0 - status and, optionally, output check passed |
| 128 | +# 1 - otherwise |
| 129 | +# Outputs: |
| 130 | +# STDERR - `$status' and `$output', if status check fails |
| 131 | +# expected and actual output, if output check fails |
| 132 | +assert_success() { |
| 133 | + (( $# > 0 )) && local -r expected="$1" |
| 134 | + if (( status != 0 )); then |
| 135 | + { local -ir width=6 |
| 136 | + batslib_print_kv_single "$width" 'status' "$status" |
| 137 | + batslib_print_kv_single_or_multi "$width" 'output' "$output" |
| 138 | + } | batslib_decorate 'command failed' \ |
| 139 | + | flunk |
| 140 | + elif (( $# > 0 )) && [[ $output != "$1" ]]; then |
| 141 | + batslib_print_kv_single_or_multi 8 \ |
| 142 | + 'expected' "$expected" \ |
| 143 | + 'actual' "$output" \ |
| 144 | + | batslib_decorate 'command succeeded, but output differs' \ |
| 145 | + | flunk |
| 146 | + fi |
| 147 | +} |
| 148 | + |
| 149 | +# Fail and display `$output' if `$status' is zero. |
| 150 | +# |
| 151 | +# Optionally, if the status check passed, `$output' can be tested |
| 152 | +# against the first positional parameter as expected output. If the |
| 153 | +# output check fails the error message contains the expected and the |
| 154 | +# actual output. |
| 155 | +# |
| 156 | +# Globals: |
| 157 | +# status |
| 158 | +# output |
| 159 | +# Arguments: |
| 160 | +# $1 - [opt] expected output |
| 161 | +# Returns: |
| 162 | +# 0 - status and, optionally, output check passed |
| 163 | +# 1 - otherwise |
| 164 | +# Outputs: |
| 165 | +# STDERR - `$output', if status check fails |
| 166 | +# expected and actual output, if output check fails |
| 167 | +assert_failure() { |
| 168 | + if (( status == 0 )); then |
| 169 | + batslib_print_kv_single_or_multi 6 'output' "$output" \ |
| 170 | + | batslib_decorate 'command succeeded, but it was expected to fail' \ |
| 171 | + | flunk |
| 172 | + elif (( $# > 0 )) && [[ $output != "$1" ]]; then |
| 173 | + batslib_print_kv_single_or_multi 8 \ |
| 174 | + 'expected' "$1" \ |
| 175 | + 'actual' "$output" \ |
| 176 | + | batslib_decorate 'command failed as expected, but output differs' \ |
| 177 | + | flunk |
| 178 | + fi |
| 179 | +} |
| 180 | + |
| 181 | +# Fail and display an error message if `${lines[@]}' does not contain |
| 182 | +# the expected line. The error message contains the expected line and |
| 183 | +# `$output'. |
| 184 | +# |
| 185 | +# Optionally, if two positional parameters are specified, the expected |
| 186 | +# line is only sought in the line whose index is given in the first |
| 187 | +# parameter. In this case, the error message contains the line index, |
| 188 | +# and the expected and actual line at the given index. |
| 189 | +# |
| 190 | +# Globals: |
| 191 | +# lines |
| 192 | +# output |
| 193 | +# Arguments: |
| 194 | +# $1 - [opt] zero-based index of line to match against |
| 195 | +# $2 - line to look for |
| 196 | +# Returns: |
| 197 | +# 0 - line found |
| 198 | +# 1 - otherwise |
| 199 | +# Outputs: |
| 200 | +# STDERR - expected line and `$output', on failure |
| 201 | +# index, expected and actual line at index, on failure |
| 202 | +assert_line() { |
| 203 | + if (( $# > 1 )); then |
| 204 | + local -ir idx="$1" |
| 205 | + local -r line="$2" |
| 206 | + |
| 207 | + if [[ ${lines[$idx]} != "$line" ]]; then |
| 208 | + batslib_print_kv_single 8 \ |
| 209 | + 'index' "$idx" \ |
| 210 | + 'expected' "$line" \ |
| 211 | + 'actual' "${lines[$idx]}" \ |
| 212 | + | batslib_decorate 'line differs' \ |
| 213 | + | flunk |
| 214 | + fi |
| 215 | + else |
| 216 | + local -r line="$1" |
| 217 | + local temp_line |
| 218 | + |
| 219 | + for temp_line in "${lines[@]}"; do |
| 220 | + [[ $temp_line == "$line" ]] && return 0 |
| 221 | + done |
| 222 | + { local -ar single=( |
| 223 | + 'line' "$line" |
| 224 | + ) |
| 225 | + local -ar may_be_multi=( |
| 226 | + 'output' "$output" |
| 227 | + ) |
| 228 | + local -ir width="$( batslib_get_max_single_line_key_width \ |
| 229 | + "${single[@]}" "${may_be_multi[@]}" )" |
| 230 | + batslib_print_kv_single "$width" "${single[@]}" |
| 231 | + batslib_print_kv_single_or_multi "$width" "${may_be_multi[@]}" |
| 232 | + } | batslib_decorate 'line is not in output' \ |
| 233 | + | flunk |
| 234 | + fi |
| 235 | +} |
| 236 | + |
| 237 | +# Fail and display an error message if `${lines[@]}' contains the given |
| 238 | +# line. The error message contains the unexpected line, its index in |
| 239 | +# `$output', and `$output'. |
| 240 | +# |
| 241 | +# Optionally, if two positional parameters are specified, the unexpected |
| 242 | +# line is only sought in the line whose index is given in the first |
| 243 | +# parameter. In this case, the error message contains the line index, |
| 244 | +# and the unexpected line. |
| 245 | +# |
| 246 | +# Globals: |
| 247 | +# lines |
| 248 | +# output |
| 249 | +# Arguments: |
| 250 | +# $1 - [opt] zero-based index of line to match against |
| 251 | +# $2 - line to look for |
| 252 | +# Returns: |
| 253 | +# 0 - line not found |
| 254 | +# 1 - otherwise |
| 255 | +# Outputs: |
| 256 | +# STDERR - unexpected line, its index and `$output', on failure |
| 257 | +# index and unexpected line, on failure |
| 258 | +refute_line() { |
| 259 | + if (( $# > 1 )); then |
| 260 | + local -ir idx="$1" |
| 261 | + local -r line="$2" |
| 262 | + |
| 263 | + if [[ ${lines[$idx]} == "$line" ]]; then |
| 264 | + batslib_print_kv_single 5 \ |
| 265 | + 'index' "$idx" \ |
| 266 | + 'line' "$line" \ |
| 267 | + | batslib_decorate 'line should differ from expected' \ |
| 268 | + | flunk |
| 269 | + fi |
| 270 | + else |
| 271 | + local -r line="$1" |
| 272 | + |
| 273 | + local idx |
| 274 | + for (( idx = 0; idx < ${#lines[@]}; ++idx )); do |
| 275 | + if [[ ${lines[$idx]} == "$line" ]]; then |
| 276 | + { local -ar single=( |
| 277 | + 'line' "$line" |
| 278 | + 'index' "$idx" |
| 279 | + ) |
| 280 | + local -a may_be_multi=( |
| 281 | + 'output' "$output" |
| 282 | + ) |
| 283 | + local -ir width="$( batslib_get_max_single_line_key_width \ |
| 284 | + "${single[@]}" "${may_be_multi[@]}" )" |
| 285 | + batslib_print_kv_single "$width" "${single[@]}" |
| 286 | + if batslib_is_single_line "${may_be_multi[1]}"; then |
| 287 | + batslib_print_kv_single "$width" "${may_be_multi[@]}" |
| 288 | + else |
| 289 | + may_be_multi[1]="$( printf '%s' "${may_be_multi[1]}" \ |
| 290 | + | batslib_prefix \ |
| 291 | + | batslib_mark '>' "$idx" )" |
| 292 | + batslib_print_kv_multi "${may_be_multi[@]}" |
| 293 | + fi |
| 294 | + } | batslib_decorate 'line should not be in output' \ |
| 295 | + | flunk |
| 296 | + return 1 |
| 297 | + fi |
| 298 | + done |
| 299 | + fi |
| 300 | +} |
0 commit comments