# # bats-support - Supporting library for Bats test helpers # # Written in 2016 by Zoltan Tombol # # To the extent possible under law, the author(s) have dedicated all # copyright and related and neighboring rights to this software to the # public domain worldwide. This software is distributed without any # warranty. # # You should have received a copy of the CC0 Public Domain Dedication # along with this software. If not, see # . # # # output.bash # ----------- # # Private functions implementing output formatting. Used by public # helper functions. # # Print a message to the standard error. When no parameters are # specified, the message is read from the standard input. # # Globals: # none # Arguments: # $@ - [=STDIN] message # Returns: # none # Inputs: # STDIN - [=$@] message # Outputs: # STDERR - message batslib_err() { { if (( $# > 0 )); then echo "$@" else PATH="$BATS_SAVED_PATH" command cat - fi } >&2 } # Count the number of lines in the given string. # # TODO(ztombol): Fix tests and remove this note after #93 is resolved! # NOTE: Due to a bug in Bats, `batslib_count_lines "$output"' does not # give the same result as `${#lines[@]}' when the output contains # empty lines. # See PR #93 (https://github.com/sstephenson/bats/pull/93). # # Globals: # none # Arguments: # $1 - string # Returns: # none # Outputs: # STDOUT - number of lines batslib_count_lines() { local -i n_lines=0 local line while IFS='' read -r line || [[ -n $line ]]; do (( ++n_lines )) done < <(printf '%s' "$1") echo "$n_lines" } # Determine whether all strings are single-line. # # Globals: # none # Arguments: # $@ - strings # Returns: # 0 - all strings are single-line # 1 - otherwise batslib_is_single_line() { for string in "$@"; do (( $(batslib_count_lines "$string") > 1 )) && return 1 done return 0 } # Determine the length of the longest key that has a single-line value. # # This function is useful in determining the correct width of the key # column in two-column format when some keys may have multi-line values # and thus should be excluded. # # Globals: # none # Arguments: # $odd - key # $even - value of the previous key # Returns: # none # Outputs: # STDOUT - length of longest key batslib_get_max_single_line_key_width() { local -i max_len=-1 while (( $# != 0 )); do local -i key_len="${#1}" batslib_is_single_line "$2" && (( key_len > max_len )) && max_len="$key_len" shift 2 done echo "$max_len" } # Print key-value pairs in two-column format. # # Keys are displayed in the first column, and their corresponding values # in the second. To evenly line up values, the key column is fixed-width # and its width is specified with the first parameter (possibly computed # using `batslib_get_max_single_line_key_width'). # # Globals: # none # Arguments: # $1 - width of key column # $even - key # $odd - value of the previous key # Returns: # none # Outputs: # STDOUT - formatted key-value pairs batslib_print_kv_single() { local -ir col_width="$1"; shift while (( $# != 0 )); do printf '%-*s : %s\n' "$col_width" "$1" "$2" shift 2 done } # Print key-value pairs in multi-line format. # # The key is displayed first with the number of lines of its # corresponding value in parenthesis. Next, starting on the next line, # the value is displayed. For better readability, it is recommended to # indent values using `batslib_prefix'. # # Globals: # none # Arguments: # $odd - key # $even - value of the previous key # Returns: # none # Outputs: # STDOUT - formatted key-value pairs batslib_print_kv_multi() { while (( $# != 0 )); do printf '%s (%d lines):\n' "$1" "$( batslib_count_lines "$2" )" printf '%s\n' "$2" shift 2 done } # Print all key-value pairs in either two-column or multi-line format # depending on whether all values are single-line. # # If all values are single-line, print all pairs in two-column format # with the specified key column width (identical to using # `batslib_print_kv_single'). # # Otherwise, print all pairs in multi-line format after indenting values # with two spaces for readability (identical to using `batslib_prefix' # and `batslib_print_kv_multi') # # Globals: # none # Arguments: # $1 - width of key column (for two-column format) # $even - key # $odd - value of the previous key # Returns: # none # Outputs: # STDOUT - formatted key-value pairs batslib_print_kv_single_or_multi() { local -ir width="$1"; shift local -a pairs=( "$@" ) local -a values=() local -i i for (( i=1; i < ${#pairs[@]}; i+=2 )); do values+=( "${pairs[$i]}" ) done if batslib_is_single_line "${values[@]}"; then batslib_print_kv_single "$width" "${pairs[@]}" else local -i i for (( i=1; i < ${#pairs[@]}; i+=2 )); do pairs[$i]="$( batslib_prefix < <(printf '%s' "${pairs[$i]}") )" done batslib_print_kv_multi "${pairs[@]}" fi } # Prefix each line read from the standard input with the given string. # # Globals: # none # Arguments: # $1 - [= ] prefix string # Returns: # none # Inputs: # STDIN - lines # Outputs: # STDOUT - prefixed lines batslib_prefix() { local -r prefix="${1:- }" local line while IFS='' read -r line || [[ -n $line ]]; do printf '%s%s\n' "$prefix" "$line" done } # Mark select lines of the text read from the standard input by # overwriting their beginning with the given string. # # Usually the input is indented by a few spaces using `batslib_prefix' # first. # # Globals: # none # Arguments: # $1 - marking string # $@ - indices (zero-based) of lines to mark # Returns: # none # Inputs: # STDIN - lines # Outputs: # STDOUT - lines after marking batslib_mark() { local -r symbol="$1"; shift # Sort line numbers. set -- $( sort -nu <<< "$( printf '%d\n' "$@" )" ) local line local -i idx=0 while IFS='' read -r line || [[ -n $line ]]; do if (( ${1:--1} == idx )); then printf '%s\n' "${symbol}${line:${#symbol}}" shift else printf '%s\n' "$line" fi (( ++idx )) done } # Enclose the input text in header and footer lines. # # The header contains the given string as title. The output is preceded # and followed by an additional newline to make it stand out more. # # Globals: # none # Arguments: # $1 - title # Returns: # none # Inputs: # STDIN - text # Outputs: # STDOUT - decorated text batslib_decorate() { echo echo "-- $1 --" PATH="$BATS_SAVED_PATH" command cat - echo '--' echo }