diff --git a/.version b/.version deleted file mode 100644 index f9fe6b4..0000000 --- a/.version +++ /dev/null @@ -1 +0,0 @@ -2.5b diff --git a/LICENSE b/LICENSE deleted file mode 100644 index cf8e84f..0000000 --- a/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -MIT License - -Copyright (c) 2020 Brandon Rozek -Copyright (c) 2019 Sławomir Śledź - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/README.md b/README.md index 15673cd..541e92e 100644 --- a/README.md +++ b/README.md @@ -1,293 +1 @@ -# Introduction - -This is a fork of [ssledz's fun.sh library](https://github.com/ssledz/bash-fun). - -This is mainly for my own personal use cases. So I would recommend using ssledz's version instead. -I mainly worked towards getting this library to mostly pass shellcheck, removed some functionality, -and name deconflicted some of the functions with what I had in my system. -# Quick start - -```bash -#!/bin/bash -. <(test -e fun.sh || curl -Ls https://raw.githubusercontent.com/brandon-rozek/bash-fun/master/src/fun.sh > fun.sh; cat fun.sh) - -seq 1 4 | sum -``` - -# Functions overview -||||||| -|------|------|------|------|------|------| -|**list_append**|**divide**|**take_while**| -|**list_drop**|**drop_while**|**factorial**|**filter**|**foldl**| -|**isint**|**isempty**|**isfile**|**isnonzerofile**|**isreadable**|**iswritable**| -|**isdir**|**list_join**|**lambda**|**list_last**|**list_head**|**list**| -|**list_tail**|**list_zip**|**list_map**| -|**mod**|**multiply**|**not**| -|**add**|**list_prepend**|**product**|**ret**| -|**revers**|**revers_str**|**scanl**|**splitc**|**strip**| -|**stripl**|**stripr**|**subtract**|**sum**|**take**| -|**tup**|**unlist**|**λ**| - - -## *list/unlist* - -```bash -$ list 1 2 3 -1 -2 -3 - -$ list 1 2 3 4 5 | unlist -1 2 3 4 5 -``` - -## *list_take/list_drop/list_tail/list_head/list_last* - -```bash -$ list 1 2 3 4 | list_drop 2 -3 -4 - -$ list 1 2 3 4 5 | list_head -1 - -$ list 1 2 3 4 | list_tail -2 -3 -4 - -$ list 1 2 3 4 5 | list_last -5 - -$ list 1 2 3 4 5 | list_take 2 -1 -2 -``` - -## *join* - -```bash -$ list 1 2 3 4 5 | list_join , -1,2,3,4,5 -``` - -## *map* - -```bash -$ seq 1 5 | list_map λ a . 'echo $((a + 5))' -6 -7 -8 -9 -10 - -$ list a b s d e | list_map λ a . 'echo $a$(echo $a | tr a-z A-Z)' -aA -bB -sS -dD -eE - -$ list 1 2 3 | list_map tee -1 -2 -3 -``` -## *filter* - -```bash -$ seq 1 10 | filter even -2 -4 -6 -8 -10 -``` - -## *foldl/foldr* - -```bash -$ list a b c d | foldl λ acc el . 'echo -n $acc-$el' -a-b-c-d -``` - -```bash -$ seq 1 4 | foldl λ acc el . 'echo $(($acc + $el))' -10 -``` - -```bash -$ seq 1 4 | foldl λ acc el . 'echo $(multiply $(($acc + 1)) $el)' -64 # 1 + (1 + 1) * 2 + (4 + 1) * 3 + (15 + 1) * 4 = 64 -``` - -## *tup/tupx/tupl/tupr* - -```bash -$ tup a 1 -(a,1) - -$ tup 'foo bar' 1 'one' 2 -(foo bar,1,one,2) - -$ tup , 1 3 -(,,1,3) -``` - -```bash -$ echo tup a 1 | tupl -a - -$ echo tup a 1 | tupr -1 - -$ tup 'foo bar' 1 'one' 2 | tupl -foo bar - -$ tup 'foo bar' 1 'one' 2 | tupr -2 -``` - -## *list_zip* - -```bash -$ list a b c d e f | list_zip $(seq 1 10) -(a,1) -(b,2) -(c,3) -(d,4) -(e,5) -(f,6) -``` - -```bash -$ list a b c d e f | list_zip $(seq 1 10) | list_last | tupr -6 -``` - -## *not/isint/isempty* - -```bash -$ isint 42 -true - -$ list blah | isint -false - -$ not true -false - -$ not "isint 777" -false - -$ list 1 2 "" c d 6 | filter λ a . 'isint $a' -1 -2 -6 - -$ list 1 2 "" c d 6 | filter λ a . 'not "isempty $a"' -1 -2 -c -d -6 -``` - -## *isfile/isnonzerofile/isreadable/iswritable/isdir* - -```bash -$ touch /tmp/foo - -$ isfile /tmp/foo -true - -$ not iswritable / -true - -$ files="/etc/passwd /etc/sudoers /tmp /tmp/foo /no_such_file" - -$ list $files | filter λ a . 'isfile $a' -/etc/passwd -/etc/sudoers -/tmp/foo - -$ list $files | filter λ a . 'isdir $a' -/tmp - -$ list $files | filter λ a . 'isreadable $a' -/etc/passwd -/tmp -/tmp/foo - -$ list $files | filter λ a . 'iswritable $a' -/tmp -/tmp/foo - -$ list $files | filter λ a . 'isnonzerofile $a' -/etc/passwd -/etc/sudoers -/tmp - -$ list $files | filter λ a . 'not isfile $a' -/tmp -/no_such_file -``` -## *scanl* - -```bash -$ seq 1 5 | scanl lambda acc el . 'echo $(($acc + $el))' -1 -3 -6 -10 -15 -``` - -```bash -$ seq 1 5 | scanl lambda a b . 'echo $(($a + $b))' | list_last -15 -``` - -# Examples - -```bash -processNames() { - - uppercase() { - local str=$1 - echo $(tr 'a-z' 'A-Z' <<< ${str:0:1})${str:1} - } - - list $@ \ - | filter λ name . '[[ ${#name} -gt 1 ]] && ret true || ret false' \ - | list_map λ name . 'uppercase $name' \ - | foldl λ acc el . 'echo $acc,$el' - -} - -processNames adam monika s slawek d daniel Bartek j k -``` - -```bash -Adam,Monika,Slawek,Daniel,Bartek -``` - -# Running tests -TODO: Need to change the tests here -```bash -cd test -./test_runner -``` - -# Contribution guidelines - -Feel free to ask questions in chat, open issues, or contribute by creating pull requests. - -In order to create a pull request -* checkout master branch -* introduce your changes & bump version -* submit pull request - -# Resources -* [Inspiration](https://quasimal.com/posts/2012-05-21-funsh.html) -* [Functional Programming in Bash](https://medium.com/@joydeepubuntu/functional-programming-in-bash-145b6db336b7) +# bash-fun \ No newline at end of file diff --git a/examples/example.sh b/examples/example.sh index c30c455..a2dbba8 100755 --- a/examples/example.sh +++ b/examples/example.sh @@ -1,29 +1,30 @@ #!/bin/bash + source ../src/fun.sh seq 1 4 | sum seq 1 4 | product factorial 4 seq 1 4 | scanl lambda a b . 'echo $(add $a $b)' -echo map multiply -seq 1 4 | list_map lambda a . 'echo $(multiply $a 2)' -echo map minus -seq 1 4 | list_map lambda a . 'echo $(minus $a 2)' +echo map mul +seq 1 4 | map lambda a . 'echo $(mul $a 2)' +echo map sub +seq 1 4 | map lambda a . 'echo $(sub $a 2)' echo map add -seq 1 4 | list_map lambda a . 'echo $(add $a 2)' -echo map divide -seq 1 4 | list_map lambda a . 'echo $(divide $a 2)' -echo list_map mod -seq 1 4 | list_map lambda a . 'echo $(mod $a 2)' +seq 1 4 | map lambda a . 'echo $(add $a 2)' +echo map div +seq 1 4 | map lambda a . 'echo $(div $a 2)' +echo map mod +seq 1 4 | map lambda a . 'echo $(mod $a 2)' echo 'list & head' -list 1 2 3 4 5 | list_head -list {1..2} | list_append {3..4} | list_prepend {99..102} +list 1 2 3 4 5 | head +list {1..2} | append {3..4} | prepend {99..102} list {1..2} | unlist -list {1..10} | list_head -list {1..10} | list_drop 7 -list {1..10} | list_take 3 -list {1..10} | list_last -list {1..10} | list_map λ a . 'echo $(multiply $a 2)' +list {1..10} | head +list {1..10} | drop 7 +list {1..10} | take 3 +list {1..10} | last +list {1..10} | map λ a . 'echo $(mul $a 2)' id() { λ x . '$x' @@ -37,32 +38,12 @@ foobar() { list {1,2,3} | foobar -echo -n abcdefg | revers_str # gfedcba -echo -n abcdefg | splitc | list_join , # a,b,c,d,e,f,g -echo -n abcdefg | splitc | revers | list_join , # g,f,e,d,c,b,a +echo -n abcdefg | revers_str # gfedcba +echo -n abcdefg | splitc | join , '[' ']' # [a,b,c,d,e,f,g] +echo -n abcdefg | splitc | revers | join , '[' ']' # [g,f,e,d,c,b,a] -list {1..10} | filter lambda a . '[[ $(mod $a 2) -eq 0 ]] && ret true || ret false' | list_join , # 2,4,6,8,10 +echo -n ' abcdefg' | splitc | foldr lambda a b . 'echo $a$b' # gfedcba -list a b c d | foldl lambda acc el . 'echo -n $acc-$el' -seq 1 4 | foldl lambda acc el . 'echo $(($acc + $el))' +echo 'ls' | try λ cmd status ret . 'echo $cmd [$status]; echo $ret' -#1 - 2 - 3 - 4 -seq 1 4 | foldl lambda acc el . 'echo $(($acc - $el))' - -#1 + (1 + 1) * 2 + (4 + 1) * 3 + (15 + 1) * 4 = 64 -seq 1 4 | foldl lambda acc el . 'echo $(multiply $(($acc + 1)) $el)' - -tup a 1 -tup a 1 | tupl -tup a 1 | tupr - -list a b c d e f | list_zip $(seq 1 10) - -echo -list a b c d e f | list_zip $(seq 1 10) | list_last | tupr - -seq 1 5 | scanl lambda a b . 'echo $(($a + $b))' -seq 1 5 | scanl lambda a b . 'echo $(($a + $b))' | list_last - -seq 2 3 | list_map lambda a . 'seq 1 $a' | list_join , -list a b c | list_map lambda a . 'echo $a; echo $a | tr a-z A-z' | list_join , +list {1..10} | filter lambda a . '[[ $(mod $a 2) -eq 0 ]] && ret true || ret false' | join , '[' ']' # [2,4,6,8,10] diff --git a/src/fun.sh b/src/fun.sh old mode 100644 new mode 100755 index 533dd10..263b7f3 --- a/src/fun.sh +++ b/src/fun.sh @@ -1,553 +1,236 @@ -#!/bin/sh +#!/bin/bash + +drop() { + command tail -n +$(($1 + 1)) +} + +take() { + command head -n ${1} +} + +tail() { + drop 1 +} + +head() { + take 1 +} + +last() { + command tail -n 1 +} -############################################### -## List Functions -############################################### list() { - for i in "$@"; do - echo "$i" - done + for i in "$@"; do + echo "$i" + done } unlist() { - xargs + cat - | xargs } -# Drop the first n items of a list. -list_drop() { - command tail -n +$(($1 + 1)) +append() { + cat - + list "$@" } -# Take the first n items of a list. -list_take() { - command head -n "$1" +prepend() { + list "$@" + cat - } -# Take the 'tail' of a list. -# Otherwise known as dropping the first element. -list_tail() { - list_drop 1 -} -# Take only the first element of the list. -list_head() { - list_take 1 -} - -# Take the last element of the list. -list_last() { - command tail -n 1 -} - -# Add the contents of standard input -# to the end of the list. -list_append() { - cat - - list "$@" -} - -# Add the contents of standard input -# to the beginning of the list. -list_prepend() { - list "$@" - cat - -} - -############################################### -## Lambdas and Lists -############################################### -# Defines an anonymous function. lambda() { - # shellcheck disable=2039 - local expression - lam() { - # shellcheck disable=2039 - local arg - while [ $# -gt 0 ]; do - arg="$1" - shift - if [ "$arg" = '.' ]; then - echo "$@" - return - else - echo "read $arg;" - fi - done - } - expression=$(lam "$@") - eval "$expression" + lam() { + local arg + while [[ $# -gt 0 ]]; do + arg="$1" + shift + if [[ $arg = '.' ]]; then + echo "$@" + return + else + echo "read $arg;" + fi + done + } + + eval $(lam "$@") + } -# Same as lambda. -# shellcheck disable=2039 λ() { - lambda "$@" + lambda "$@" } -# Print the number of arguments a lambda takes. -# shellcheck disable=2039 -λ_num_args() { - # Calculates the number of arguments a lambda takes - minus "$#" 3 +map() { + local x + while read x; do + echo "$x" | "$@" + done } -# Perform an operation to each -# element(s) of a list provided -# through standard input. -list_map() { - # shellcheck disable=2039 - local x - # shellcheck disable=2039 - local i - # shellcheck disable=2039 - local arguments - # shellcheck disable=2039 - local num_args - if [ "$1" = "λ" ] || [ "$1" = "lambda" ]; then - num_args=$(λ_num_args "$@") - while read -r x; do - arguments="$x" - i=2 - while [ $i -le "$num_args" ] ; do - read -r x - arguments="$arguments $x" - i=$(add $i 1) - done - # We want to word split arguments, so no quotes - eval "list $arguments" | "$@" - done - else # Do not know the arity, assume 1 - while read -r x; do - echo "$x" | "$@" - done - fi -} - -# Perform a binary operation on a list -# where one element is the accumulation -# of the results so far. -# Ex: seq 3 | foldl lambda a b . 'minus $a $b' -# First is (1 - 2 = -1) then (-1 - 3 = -4). foldl() { - # shellcheck disable=2039 - local acc - read -r acc - while read -r elem; do - acc=$({ echo "$acc"; echo "$elem"; } | "$@" ) - done - echo "$acc" + local f="$@" + local acc + read acc + while read elem; do + acc="$({ echo $acc; echo $elem; } | $f )" + done + echo "$acc" +} + +foldr() { + local f="$@" + local acc + read acc + + foldrr() { + local elem + read elem && acc=$(foldrr) + acc="$({ echo $acc; echo $elem; } | $f )" + echo "$acc" + } + + foldrr } -# Constructs a list where each element -# is the foldl of the 0th-ith elements of -# the list. scanl() { - # shellcheck disable=2039 - local acc - read -r acc + local f="$@" + local acc + read acc + echo $acc + while read elem; do + acc="$({ echo $acc; echo $elem; } | $f )" echo "$acc" - while read -r elem; do - acc=$({ echo "$acc"; echo "$elem"; } | "$@" ) - echo "$acc" - done + done } -# Drops any elements of the list where the -# function performed on it evaluates to false. -filter() { - # shellcheck disable=2039 - local x - while read -r x; do - ret=$(echo "$x" | "$@") - if_then "$ret" "echo $x" - done -} - -# Keep taking elements until a certain condition -# is false. -take_while() { - # shellcheck disable=2039 - local x - # shellcheck disable=2039 - local condition - while read -r x; do - condition="$(echo "$x" | "$@")" - if_then_else "$condition" "echo $x" "break" - done -} - -# Keep dropping elements until a certain condition -# is false. -drop_while() { - # shellcheck disable=2039 - local x - while read -r x; do - condition="$(echo "$x" | "$@")" - if_then_else "$condition" 'do_nothing' 'break' - done - if_then "[ -n $x ]" "{ echo $x; cat -; }" -} - - -############################################### -## Arithmetic Functions -############################################### -multiply() { - # shellcheck disable=2039 - local a - # shellcheck disable=2039 - local b - a=$1 - if [ $# -lt 2 ] ; then - read -r b - else - b=$2 - fi - isint "$a" > /dev/null && \ - isint "$b" > /dev/null && \ - echo $((a * b)) +mul() { + ( set -f; echo $(($1 * $2)) ) } add() { - # shellcheck disable=2039 - local a - # shellcheck disable=2039 - local b - a=$1 - if [ $# -lt 2 ] ; then - read -r b - else - b=$2 - fi - isint "$a" > /dev/null && \ - isint "$b" > /dev/null && \ - echo $((a + b)) + echo $(($1 + $2)) } -minus() { - # shellcheck disable=2039 - local a - # shellcheck disable=2039 - local b - a=$1 - if [ $# -lt 2 ] ; then - b=$1 - read -r a - else - b=$2 - fi - isint "$a" > /dev/null && \ - isint "$b" > /dev/null && \ - echo $((a - b)) +sub() { + echo $(($1 - $2)) } -divide() { - # shellcheck disable=2039 - local a - # shellcheck disable=2039 - local b - a=$1 - if [ $# -lt 2 ] ; then - b=$1 - read -r a - else - b=$2 - fi - isint "$a" > /dev/null && \ - isint "$b" > /dev/null && \ - echo $((a / b)) +div() { + echo $(($1 / $2)) } mod() { - # shellcheck disable=2039 - local a - # shellcheck disable=2039 - local b - a=$1 - if [ $# -lt 2 ] ; then - b=$1 - read -r a - else - b=$2 - fi - isint "$a" > /dev/null && \ - isint "$b" > /dev/null && \ - echo $((a % b)) + echo $(($1 % $2)) } -even() { - # shellcheck disable=2039 - local n - # shellcheck disable=2039 - local result - # shellcheck disable=2039 - local result_code - if [ $# -lt 1 ] ; then - read -r n - else - n=$1 - fi - result=$(mod "$n" 2) - result_code=$? - if [ $result_code -ne 0 ] ; then - ret false - else - result_to_bool "[ $result = 0 ]" - fi -} - -odd() { - not even -} - -less_than() { - # shellcheck disable=2039 - local n - read -r n - if isint "$n" > /dev/null && \ - [ "$n" -lt "$1" ] ; then - ret true - else - ret false - fi -} sum() { - foldl lambda a b . "add \$a \$b" + foldl lambda a b . 'echo $(($a + $b))' } product() { - foldl lambda a b . "multiply \$a \$b" + foldl lambda a b . 'echo $(mul $a $b)' } factorial() { - seq 1 "$1" | product + seq 1 $1 | product } -############################################### -## String Operations -############################################### -# Splits a string into a list where each element -# is one character. splitc() { - sed 's/./\n&/g' | list_tail + cat - | sed 's/./&\n/g' } -# Takes a list and creates a string where -# each element is seperated by a delimiter. -list_join() { - # shellcheck disable=2039 - local delim - delim=$1 - foldl lambda a b . "echo \$a$delim\$b" +join() { + local delim=$1 + local pref=$2 + local suff=$3 + echo $pref$(cat - | foldl lambda a b . 'echo $a$delim$b')$suff } -# Split a string into a list -# by a specified delimeter -str_split() { - sed "s/$1/\n/g" -} - -# Reverses a list. revers() { - # shellcheck disable=2039 - local result - # shellcheck disable=2039 - local n - while read -r n; do - result="$n\n$result" - done - echo "$result" + foldl lambda a b . 'append $b $a' } -# Reverses a string revers_str() { - splitc | revers | list_join + cat - | splitc | revers | join } -# Removes multiple occurences of -# a single character from the beginning -# of the list. -lstrip() { - # shellcheck disable=2039 - local c - if [ $# -eq 0 ] ; then - c=" " - else - c="$1" - fi - sed "s/^$c*//g" -} - -# Removes multiple occurences of -# a single character from the end -# of the list. -rstrip() { - # shellcheck disable=2039 - local c - if [ $# -eq 0 ] ; then - c=" " - else - c="$1" - fi - sed "s/$c*$//g" -} - -# Removes multiple occurences of -# a single character from the beginning -# and end of the list. -strip() { - lstrip "$@" | rstrip "$@" -} - -############################################### -## Tuple Functions -############################################### - -# Creates a tuple, which is a string with -# multiple elements seperated by a comma, -# and it begins with a ( and ends with a ). -tup() { - # shellcheck disable=2039 - local args - # shellcheck disable=2039 - local result - if [ $# -eq 0 ]; then - args=$(unlist) - eval "tup $args" - else - result=$(list "$@" | list_join ,) - echo "($result)" - fi -} - -# Takes a tuple and outputs it as a list -tup_to_list() { - local li - local f - local la - li=$(str_split ",") - - # Remove '(' from the first element - f=$(echo "$li" | list_head) - f=$(echo "$f" | sed 's/^(//') - - la=$(echo "$li" | list_last) - # If there is only one element in the list - # Remove ')' from the only element - if [ "$(echo "$la" | cut -c1)" = "(" ]; then - f=$(echo "$f" | sed "s/)$//") - echo "$f" - # If there is more than one element in the list - # Remove ')' from the last element - else - la=$(echo "$la" | sed "s/)$//") - # Remove the first and last element from li - li=$(echo "$li" | list_tail | sed '$d') - # Print the list - { echo "$f"; echo "$li"; echo "$la"; } - fi -} - -# Takes the first element of the tuple -tupl() { - tup_to_list | list_head -} - -# Takes the last element of the tuple -tupr() { - tup_to_list | list_last -} - - -# Takes each element from a list in standard -# input and matches it with a list provided -# as the argument to this function. -# The result is a list of 2-tuples. -list_zip() { - # shellcheck disable=2039 - local l - l=$(list "$@") - while read -r x; do - y=$(echo "$l" | list_take 1) - tup "$x" "$y" - l=$(echo "$l" | list_drop 1) - done -} - -############################################### -## Logic Based Functions -############################################### - -if_then() { - # shellcheck disable=2039 - local result - eval "$1" - result=$? - if [ $result -eq 0 ] ; then - eval "$2" - fi -} - -if_then_else() { - # shellcheck disable=2039 - local result - eval "$1" - result=$? - if [ $result -eq 0 ] ; then - eval "$2" - else - eval "$3" - fi -} - -result_to_bool() { - if_then_else "$1" 'ret true' 'ret false' -} - -not() { - if_then_else "$1 > /dev/null" "ret false" "ret true" +try() { + local f="$@" + local cmd=$(cat -) + ret="$(2>&1 $cmd)" + local status=$? + list "$cmd" $status $(list $ret | join \#) | $f } ret() { - echo "$@" - "$@" + echo $1 } -do_nothing() { - echo > /dev/null +filter() { + local x + while read x; do + ret=$(echo "$x" | "$@") + $ret && echo $x + done } - -############################################### -## Useful utility functions -############################################### - -isint() { - result_to_bool "echo \"$1\" | grep -Eq '^-?[0-9]+$'" +strip() { + local arg=$1 + cat - | map lambda l . 'ret ${l##'$arg'}' | map lambda l . 'ret ${l%%'$arg'}' } -isempty() { - result_to_bool "[ -z \"$1\" ]" +buff() { + local cnt=-1 + for x in $@; do + [[ $x = '.' ]] && break + cnt=$(add $cnt 1) + done + local args='' + local i=$cnt + while read arg; do + [[ $i -eq 0 ]] && list $args | "$@" && i=$cnt && args='' + args="$args $arg" + i=$(sub $i 1) + done + [[ ! -z $args ]] && list $args | "$@" } -isfile() { - result_to_bool "[ -f \"$1\" ]" +tup() { + list "$@" | join , '(' ')' } -isnonzerofile() { - result_to_bool "[ -s \"$1\" ]" +tupx() { + if [[ $# -eq 1 ]]; then + local arg + read arg + tupx "$1" "$arg" + else + local n=$1 + shift + list "$@" | strip '\(' | strip '\)' | unlist | cut -d',' -f${n} + fi } -isreadable() { - result_to_bool "[ -r \"$1\" ]" +tupl() { + tupx 1 "$@" } -iswritable() { - result_to_bool "[ -w \"$1\" ]" +tupr() { + tupx 2 "$@" } -isdir() { - result_to_bool "[ -d \"$1\" ]" +zip() { + local list=$* + cat - | while read x; do + y=$(list $list | take 1) + tup $x $y + list=$(list $list | drop 1) + done } + diff --git a/test/append_test.sh b/test/append_test.sh deleted file mode 100755 index 2ee28fc..0000000 --- a/test/append_test.sh +++ /dev/null @@ -1,15 +0,0 @@ -#! /bin/bash - -testAppendToEmptyList() { - assertEquals 4 "$(list | list_append 4)" -} - -testAppendToOneElementList() { - assertEquals "1 4" "$(list 1 | list_append 4 | unlist)" -} - -testAppendToList() { - assertEquals "1 2 3 4 5 4" "$(list 1 2 3 4 5 | list_append 4 | unlist)" -} - -. ./shunit2-init.sh \ No newline at end of file diff --git a/test/drop_test.sh b/test/drop_test.sh deleted file mode 100755 index 7195d48..0000000 --- a/test/drop_test.sh +++ /dev/null @@ -1,23 +0,0 @@ -#! /bin/bash - -testDrop9From10() { - assertEquals 10 $(list {1..10} | list_drop 9) -} - -testDrop8From10() { - assertEquals "9 10" "$(list {1..10} | list_drop 8 | unlist)" -} - -testDropAll() { - assertEquals "" "$(list {1..10} | list_drop 10)" -} - -testDropMoreThanAvailable() { - assertEquals "" "$(list {1..10} | list_drop 15)" -} - -testDropZero() { - assertEquals "1 2 3 4 5 6 7 8 9 10" "$(list {1..10} | list_drop 0 | unlist)" -} - -. ./shunit2-init.sh \ No newline at end of file diff --git a/test/head_test.sh b/test/head_test.sh deleted file mode 100755 index 0293890..0000000 --- a/test/head_test.sh +++ /dev/null @@ -1,16 +0,0 @@ -#! /bin/bash - -testLHeadFromList() { - assertEquals 1 $(list {1..10} | list_head) - assertEquals 5 $(list 5 6 7 | list_head) -} - -testLHeadFromOneElementList() { - assertEquals 1 $(list 1 | list_head) -} - -testLHeadFromEmptyList() { - assertEquals "" "$(list | list_head)" -} - -. ./shunit2-init.sh diff --git a/test/lambda_test.sh b/test/lambda_test.sh deleted file mode 100755 index 4f05094..0000000 --- a/test/lambda_test.sh +++ /dev/null @@ -1,38 +0,0 @@ -#! /bin/bash - -testLambdaNoArguments_ifNoInput() { - assertEquals 'Hi there' "$(echo | lambda . 'echo Hi there')" -} - -testLambdaNoArguments_ifSomeInputArguments() { - assertEquals 'Hi there' "$(echo 'xx\nyy\nzz' | lambda . 'echo Hi there')" -} - -testLambdaOneArgument() { - identity() { - lambda x . '$x' - } - assertEquals "hi there !" "$(identity <<< 'echo hi there !')" - assertEquals 3 $(lambda x . 'echo $(($x + 1))' <<< '2') - assertEquals "hi there !" "$(λ x . 'echo $x' <<< 'hi there !')" -} - -testLambdaSymbolTwoArguments() { - assertEquals 3 $(echo -e '1\n2' | lambda x y . 'echo $(($x + $y))') - assertEquals 5 $(echo -e '7\n2' | λ x y . 'echo $(($x - $y))') -} - -testLambdaSymbolManyArguments() { - assertEquals 5 $(echo -e '1\n2\n3\n4\n5' | lambda a b c d e . 'echo $(($a + $b + $c + $d - $e))') -} - -testLambdaSymbolManyArguments_ifInsufficientNumberOfArgumentsInLambda() { - assertEquals 6 $(echo -e '1\n2\n3\n4\n5' | lambda a b c . 'echo $(($a + $b + $c))') -} - -testLambdaSymbolManyArguments_ifInsufficientNumberOfInputArguments() { - echo -e '1\n2' | lambda a b c d e . 'echo $(($a + $b + $c + $d + $e))' 2> /dev/null \ - && fail "There should be syntax error" -} - -. ./shunit2-init.sh \ No newline at end of file diff --git a/test/last_test.sh b/test/last_test.sh deleted file mode 100755 index e10ec36..0000000 --- a/test/last_test.sh +++ /dev/null @@ -1,16 +0,0 @@ -#! /bin/bash - -testLastFromList() { - assertEquals 10 $(list {1..10} | list_last) - assertEquals 7 $(list 5 6 7 | list_last) -} - -testLastFromOneElementList() { - assertEquals 1 $(list 1 | list_last) -} - -testLastFromEmptyList() { - assertEquals "" "$(list | list_last)" -} - -. ./shunit2-init.sh \ No newline at end of file diff --git a/test/lib/shflags b/test/lib/shflags deleted file mode 100644 index 70cdea4..0000000 --- a/test/lib/shflags +++ /dev/null @@ -1,1222 +0,0 @@ -# vim:et:ft=sh:sts=2:sw=2 -# -# Copyright 2008-2017 Kate Ward. All Rights Reserved. -# Released under the Apache License 2.0 license. -# http://www.apache.org/licenses/LICENSE-2.0 -# -# shFlags -- Advanced command-line flag library for Unix shell scripts. -# https://github.com/kward/shflags -# -# Author: kate.ward@forestent.com (Kate Ward) -# -# This module implements something like the gflags library available -# from https://github.com/gflags/gflags. -# -# FLAG TYPES: This is a list of the DEFINE_*'s that you can do. All flags take -# a name, default value, help-string, and optional 'short' name (one-letter -# name). Some flags have other arguments, which are described with the flag. -# -# DEFINE_string: takes any input, and interprets it as a string. -# -# DEFINE_boolean: does not take any arguments. Say --myflag to set -# FLAGS_myflag to true, or --nomyflag to set FLAGS_myflag to false. For short -# flags, passing the flag on the command-line negates the default value, i.e. -# if the default is true, passing the flag sets the value to false. -# -# DEFINE_float: takes an input and interprets it as a floating point number. As -# shell does not support floats per-se, the input is merely validated as -# being a valid floating point value. -# -# DEFINE_integer: takes an input and interprets it as an integer. -# -# SPECIAL FLAGS: There are a few flags that have special meaning: -# --help (or -?) prints a list of all the flags in a human-readable fashion -# --flagfile=foo read flags from foo. (not implemented yet) -# -- as in getopt(), terminates flag-processing -# -# EXAMPLE USAGE: -# -# -- begin hello.sh -- -# #! /bin/sh -# . ./shflags -# DEFINE_string name 'world' "somebody's name" n -# FLAGS "$@" || exit $? -# eval set -- "${FLAGS_ARGV}" -# echo "Hello, ${FLAGS_name}." -# -- end hello.sh -- -# -# $ ./hello.sh -n Kate -# Hello, Kate. -# -# CUSTOMIZABLE BEHAVIOR: -# -# A script can override the default 'getopt' command by providing the path to -# an alternate implementation by defining the FLAGS_GETOPT_CMD variable. -# -# NOTES: -# -# * Not all systems include a getopt version that supports long flags. On these -# systems, only short flags are recognized. - -#============================================================================== -# shFlags -# -# Shared attributes: -# flags_error: last error message -# flags_output: last function output (rarely valid) -# flags_return: last return value -# -# __flags_longNames: list of long names for all flags -# __flags_shortNames: list of short names for all flags -# __flags_boolNames: list of boolean flag names -# -# __flags_opts: options parsed by getopt -# -# Per-flag attributes: -# FLAGS_: contains value of flag named 'flag_name' -# __flags__default: the default flag value -# __flags__help: the flag help string -# __flags__short: the flag short name -# __flags__type: the flag type -# -# Notes: -# - lists of strings are space separated, and a null value is the '~' char. -# -### ShellCheck (http://www.shellcheck.net/) -# $() are not fully portable (POSIX != portable). -# shellcheck disable=SC2006 -# [ p -a q ] are well defined enough (vs [ p ] && [ q ]). -# shellcheck disable=SC2166 - -# Return if FLAGS already loaded. -[ -n "${FLAGS_VERSION:-}" ] && return 0 -FLAGS_VERSION='1.2.3pre' - -# Return values that scripts can use. -FLAGS_TRUE=0 -FLAGS_FALSE=1 -FLAGS_ERROR=2 - -# Logging levels. -FLAGS_LEVEL_DEBUG=0 -FLAGS_LEVEL_INFO=1 -FLAGS_LEVEL_WARN=2 -FLAGS_LEVEL_ERROR=3 -FLAGS_LEVEL_FATAL=4 -__FLAGS_LEVEL_DEFAULT=${FLAGS_LEVEL_WARN} - -# Determine some reasonable command defaults. -__FLAGS_EXPR_CMD='expr --' -__FLAGS_UNAME_S=`uname -s` -if [ "${__FLAGS_UNAME_S}" = 'BSD' ]; then - __FLAGS_EXPR_CMD='gexpr --' -else - _flags_output_=`${__FLAGS_EXPR_CMD} 2>&1` - if [ $? -eq ${FLAGS_TRUE} -a "${_flags_output_}" = '--' ]; then - # We are likely running inside BusyBox. - __FLAGS_EXPR_CMD='expr' - fi - unset _flags_output_ -fi - -# Commands a user can override if desired. -FLAGS_EXPR_CMD=${FLAGS_EXPR_CMD:-${__FLAGS_EXPR_CMD}} -FLAGS_GETOPT_CMD=${FLAGS_GETOPT_CMD:-getopt} - -# Specific shell checks. -if [ -n "${ZSH_VERSION:-}" ]; then - setopt |grep "^shwordsplit$" >/dev/null - if [ $? -ne ${FLAGS_TRUE} ]; then - _flags_fatal 'zsh shwordsplit option is required for proper zsh operation' - fi - if [ -z "${FLAGS_PARENT:-}" ]; then - _flags_fatal "zsh does not pass \$0 through properly. please declare' \ -\"FLAGS_PARENT=\$0\" before calling shFlags" - fi -fi - -# Can we use built-ins? -( echo "${FLAGS_TRUE#0}"; ) >/dev/null 2>&1 -if [ $? -eq ${FLAGS_TRUE} ]; then - __FLAGS_USE_BUILTIN=${FLAGS_TRUE} -else - __FLAGS_USE_BUILTIN=${FLAGS_FALSE} -fi - - -# -# Constants. -# - -# Reserved flag names. -__FLAGS_RESERVED_LIST=' ARGC ARGV ERROR FALSE GETOPT_CMD HELP PARENT TRUE ' -__FLAGS_RESERVED_LIST="${__FLAGS_RESERVED_LIST} VERSION " - -# Determined getopt version (standard or enhanced). -__FLAGS_GETOPT_VERS_STD=0 -__FLAGS_GETOPT_VERS_ENH=1 - -# shellcheck disable=SC2120 -_flags_getopt_vers() { - _flags_getopt_cmd_=${1:-${FLAGS_GETOPT_CMD}} - case "`${_flags_getopt_cmd_} -lfoo '' --foo 2>&1`" in - ' -- --foo') echo ${__FLAGS_GETOPT_VERS_STD} ;; - ' --foo --') echo ${__FLAGS_GETOPT_VERS_ENH} ;; - # Unrecognized output. Assuming standard getopt version. - *) echo ${__FLAGS_GETOPT_VERS_STD} ;; - esac - unset _flags_getopt_cmd_ -} -# shellcheck disable=SC2119 -__FLAGS_GETOPT_VERS=`_flags_getopt_vers` - -# getopt optstring lengths -__FLAGS_OPTSTR_SHORT=0 -__FLAGS_OPTSTR_LONG=1 - -__FLAGS_NULL='~' - -# Flag info strings. -__FLAGS_INFO_DEFAULT='default' -__FLAGS_INFO_HELP='help' -__FLAGS_INFO_SHORT='short' -__FLAGS_INFO_TYPE='type' - -# Flag lengths. -__FLAGS_LEN_SHORT=0 -__FLAGS_LEN_LONG=1 - -# Flag types. -__FLAGS_TYPE_NONE=0 -__FLAGS_TYPE_BOOLEAN=1 -__FLAGS_TYPE_FLOAT=2 -__FLAGS_TYPE_INTEGER=3 -__FLAGS_TYPE_STRING=4 - -# Set the constants readonly. -__flags_constants=`set |awk -F= '/^FLAGS_/ || /^__FLAGS_/ {print $1}'` -for __flags_const in ${__flags_constants}; do - # Skip certain flags. - case ${__flags_const} in - FLAGS_HELP) continue ;; - FLAGS_PARENT) continue ;; - esac - # Set flag readonly. - if [ -z "${ZSH_VERSION:-}" ]; then - readonly "${__flags_const}" - continue - fi - case ${ZSH_VERSION} in - [123].*) readonly "${__flags_const}" ;; - *) readonly -g "${__flags_const}" ;; # Declare readonly constants globally. - esac -done -unset __flags_const __flags_constants - -# -# Internal variables. -# - -# Space separated lists. -__flags_boolNames=' ' # Boolean flag names. -__flags_longNames=' ' # Long flag names. -__flags_shortNames=' ' # Short flag names. -__flags_definedNames=' ' # Defined flag names (used for validation). - -__flags_columns='' # Screen width in columns. -__flags_level=0 # Default logging level. -__flags_opts='' # Temporary storage for parsed getopt flags. - -#------------------------------------------------------------------------------ -# Private functions. -# - -# Logging functions. -_flags_debug() { - [ ${__flags_level} -le ${FLAGS_LEVEL_DEBUG} ] || return - echo "flags:DEBUG $*" >&2 -} -_flags_info() { - [ ${__flags_level} -le ${FLAGS_LEVEL_INFO} ] || return - echo "flags:INFO $*" >&2 -} -_flags_warn() { - [ ${__flags_level} -le ${FLAGS_LEVEL_WARN} ] || return - echo "flags:WARN $*" >&2 -} -_flags_error() { - [ ${__flags_level} -le ${FLAGS_LEVEL_ERROR} ] || return - echo "flags:ERROR $*" >&2 -} -_flags_fatal() { - [ ${__flags_level} -le ${FLAGS_LEVEL_FATAL} ] || return - echo "flags:FATAL $*" >&2 - exit ${FLAGS_ERROR} -} - -# Get the logging level. -flags_loggingLevel() { echo ${__flags_level}; } - -# Set the logging level. -# -# Args: -# _flags_level_: integer: new logging level -# Returns: -# nothing -flags_setLoggingLevel() { - [ $# -ne 1 ] && _flags_fatal "flags_setLevel(): logging level missing" - _flags_level_=$1 - [ "${_flags_level_}" -ge "${FLAGS_LEVEL_DEBUG}" \ - -a "${_flags_level_}" -le "${FLAGS_LEVEL_FATAL}" ] \ - || _flags_fatal "Invalid logging level '${_flags_level_}' specified." - __flags_level=$1 - unset _flags_level_ -} - -# Define a flag. -# -# Calling this function will define the following info variables for the -# specified flag: -# FLAGS_flagname - the name for this flag (based upon the long flag name) -# __flags__default - the default value -# __flags_flagname_help - the help string -# __flags_flagname_short - the single letter alias -# __flags_flagname_type - the type of flag (one of __FLAGS_TYPE_*) -# -# Args: -# _flags_type_: integer: internal type of flag (__FLAGS_TYPE_*) -# _flags_name_: string: long flag name -# _flags_default_: default flag value -# _flags_help_: string: help string -# _flags_short_: string: (optional) short flag name -# Returns: -# integer: success of operation, or error -_flags_define() { - if [ $# -lt 4 ]; then - flags_error='DEFINE error: too few arguments' - flags_return=${FLAGS_ERROR} - _flags_error "${flags_error}" - return ${flags_return} - fi - - _flags_type_=$1 - _flags_name_=$2 - _flags_default_=$3 - _flags_help_=${4:-§} # Special value '§' indicates no help string provided. - _flags_short_=${5:-${__FLAGS_NULL}} - - _flags_debug "type:${_flags_type_} name:${_flags_name_}" \ - "default:'${_flags_default_}' help:'${_flags_help_}'" \ - "short:${_flags_short_}" - - _flags_return_=${FLAGS_TRUE} - _flags_usName_="`_flags_underscoreName "${_flags_name_}"`" - - # Check whether the flag name is reserved. - _flags_itemInList "${_flags_usName_}" "${__FLAGS_RESERVED_LIST}" - if [ $? -eq ${FLAGS_TRUE} ]; then - flags_error="flag name (${_flags_name_}) is reserved" - _flags_return_=${FLAGS_ERROR} - fi - - # Require short option for getopt that don't support long options. - if [ ${_flags_return_} -eq ${FLAGS_TRUE} \ - -a "${__FLAGS_GETOPT_VERS}" -ne "${__FLAGS_GETOPT_VERS_ENH}" \ - -a "${_flags_short_}" = "${__FLAGS_NULL}" ] - then - flags_error="short flag required for (${_flags_name_}) on this platform" - _flags_return_=${FLAGS_ERROR} - fi - - # Check for existing long name definition. - if [ ${_flags_return_} -eq ${FLAGS_TRUE} ]; then - if _flags_itemInList "${_flags_usName_}" "${__flags_definedNames}"; then - flags_error="definition for ([no]${_flags_name_}) already exists" - _flags_warn "${flags_error}" - _flags_return_=${FLAGS_FALSE} - fi - fi - - # Check for existing short name definition. - if [ ${_flags_return_} -eq ${FLAGS_TRUE} \ - -a "${_flags_short_}" != "${__FLAGS_NULL}" ] - then - if _flags_itemInList "${_flags_short_}" "${__flags_shortNames}"; then - flags_error="flag short name (${_flags_short_}) already defined" - _flags_warn "${flags_error}" - _flags_return_=${FLAGS_FALSE} - fi - fi - - # Handle default value. Note, on several occasions the 'if' portion of an - # if/then/else contains just a ':' which does nothing. A binary reversal via - # '!' is not done because it does not work on all shells. - if [ ${_flags_return_} -eq ${FLAGS_TRUE} ]; then - case ${_flags_type_} in - ${__FLAGS_TYPE_BOOLEAN}) - if _flags_validBool "${_flags_default_}"; then - case ${_flags_default_} in - true|t|0) _flags_default_=${FLAGS_TRUE} ;; - false|f|1) _flags_default_=${FLAGS_FALSE} ;; - esac - else - flags_error="invalid default flag value '${_flags_default_}'" - _flags_return_=${FLAGS_ERROR} - fi - ;; - - ${__FLAGS_TYPE_FLOAT}) - if _flags_validFloat "${_flags_default_}"; then - : - else - flags_error="invalid default flag value '${_flags_default_}'" - _flags_return_=${FLAGS_ERROR} - fi - ;; - - ${__FLAGS_TYPE_INTEGER}) - if _flags_validInt "${_flags_default_}"; then - : - else - flags_error="invalid default flag value '${_flags_default_}'" - _flags_return_=${FLAGS_ERROR} - fi - ;; - - ${__FLAGS_TYPE_STRING}) ;; # Everything in shell is a valid string. - - *) - flags_error="unrecognized flag type '${_flags_type_}'" - _flags_return_=${FLAGS_ERROR} - ;; - esac - fi - - if [ ${_flags_return_} -eq ${FLAGS_TRUE} ]; then - # Store flag information. - eval "FLAGS_${_flags_usName_}='${_flags_default_}'" - eval "__flags_${_flags_usName_}_${__FLAGS_INFO_TYPE}=${_flags_type_}" - eval "__flags_${_flags_usName_}_${__FLAGS_INFO_DEFAULT}=\ -\"${_flags_default_}\"" - eval "__flags_${_flags_usName_}_${__FLAGS_INFO_HELP}=\"${_flags_help_}\"" - eval "__flags_${_flags_usName_}_${__FLAGS_INFO_SHORT}='${_flags_short_}'" - - # append flag names to name lists - __flags_shortNames="${__flags_shortNames}${_flags_short_} " - __flags_longNames="${__flags_longNames}${_flags_name_} " - [ "${_flags_type_}" -eq "${__FLAGS_TYPE_BOOLEAN}" ] && \ - __flags_boolNames="${__flags_boolNames}no${_flags_name_} " - - # Append flag names to defined names for later validation checks. - __flags_definedNames="${__flags_definedNames}${_flags_usName_} " - [ "${_flags_type_}" -eq "${__FLAGS_TYPE_BOOLEAN}" ] && \ - __flags_definedNames="${__flags_definedNames}no${_flags_usName_} " - fi - - flags_return=${_flags_return_} - unset _flags_default_ _flags_help_ _flags_name_ _flags_return_ \ - _flags_short_ _flags_type_ _flags_usName_ - [ ${flags_return} -eq ${FLAGS_ERROR} ] && _flags_error "${flags_error}" - return ${flags_return} -} - -# Underscore a flag name by replacing dashes with underscores. -# -# Args: -# unnamed: string: log flag name -# Output: -# string: underscored name -_flags_underscoreName() { - echo "$1" |tr '-' '_' -} - -# Return valid getopt options using currently defined list of long options. -# -# This function builds a proper getopt option string for short (and long) -# options, using the current list of long options for reference. -# -# Args: -# _flags_optStr: integer: option string type (__FLAGS_OPTSTR_*) -# Output: -# string: generated option string for getopt -# Returns: -# boolean: success of operation (always returns True) -_flags_genOptStr() { - _flags_optStrType_=$1 - - _flags_opts_='' - - for _flags_name_ in ${__flags_longNames}; do - _flags_usName_="`_flags_underscoreName "${_flags_name_}"`" - _flags_type_="`_flags_getFlagInfo "${_flags_usName_}" "${__FLAGS_INFO_TYPE}"`" - [ $? -eq ${FLAGS_TRUE} ] || _flags_fatal 'call to _flags_type_ failed' - case ${_flags_optStrType_} in - ${__FLAGS_OPTSTR_SHORT}) - _flags_shortName_="`_flags_getFlagInfo \ - "${_flags_usName_}" "${__FLAGS_INFO_SHORT}"`" - if [ "${_flags_shortName_}" != "${__FLAGS_NULL}" ]; then - _flags_opts_="${_flags_opts_}${_flags_shortName_}" - # getopt needs a trailing ':' to indicate a required argument. - [ "${_flags_type_}" -ne "${__FLAGS_TYPE_BOOLEAN}" ] && \ - _flags_opts_="${_flags_opts_}:" - fi - ;; - - ${__FLAGS_OPTSTR_LONG}) - _flags_opts_="${_flags_opts_:+${_flags_opts_},}${_flags_name_}" - # getopt needs a trailing ':' to indicate a required argument - [ "${_flags_type_}" -ne "${__FLAGS_TYPE_BOOLEAN}" ] && \ - _flags_opts_="${_flags_opts_}:" - ;; - esac - done - - echo "${_flags_opts_}" - unset _flags_name_ _flags_opts_ _flags_optStrType_ _flags_shortName_ \ - _flags_type_ _flags_usName_ - return ${FLAGS_TRUE} -} - -# Returns flag details based on a flag name and flag info. -# -# Args: -# string: underscored flag name -# string: flag info (see the _flags_define function for valid info types) -# Output: -# string: value of dereferenced flag variable -# Returns: -# integer: one of FLAGS_{TRUE|FALSE|ERROR} -_flags_getFlagInfo() { - # Note: adding gFI to variable names to prevent naming conflicts with calling - # functions - _flags_gFI_usName_=$1 - _flags_gFI_info_=$2 - - # Example: given argument usName (underscored flag name) of 'my_flag', and - # argument info of 'help', set the _flags_infoValue_ variable to the value of - # ${__flags_my_flag_help}, and see if it is non-empty. - _flags_infoVar_="__flags_${_flags_gFI_usName_}_${_flags_gFI_info_}" - _flags_strToEval_="_flags_infoValue_=\"\${${_flags_infoVar_}:-}\"" - eval "${_flags_strToEval_}" - if [ -n "${_flags_infoValue_}" ]; then - # Special value '§' indicates no help string provided. - [ "${_flags_gFI_info_}" = ${__FLAGS_INFO_HELP} \ - -a "${_flags_infoValue_}" = '§' ] && _flags_infoValue_='' - flags_return=${FLAGS_TRUE} - else - # See if the _flags_gFI_usName_ variable is a string as strings can be - # empty... - # Note: the DRY principle would say to have this function call itself for - # the next three lines, but doing so results in an infinite loop as an - # invalid _flags_name_ will also not have the associated _type variable. - # Because it doesn't (it will evaluate to an empty string) the logic will - # try to find the _type variable of the _type variable, and so on. Not so - # good ;-) - # - # Example cont.: set the _flags_typeValue_ variable to the value of - # ${__flags_my_flag_type}, and see if it equals '4'. - _flags_typeVar_="__flags_${_flags_gFI_usName_}_${__FLAGS_INFO_TYPE}" - _flags_strToEval_="_flags_typeValue_=\"\${${_flags_typeVar_}:-}\"" - eval "${_flags_strToEval_}" - # shellcheck disable=SC2154 - if [ "${_flags_typeValue_}" = "${__FLAGS_TYPE_STRING}" ]; then - flags_return=${FLAGS_TRUE} - else - flags_return=${FLAGS_ERROR} - flags_error="missing flag info variable (${_flags_infoVar_})" - fi - fi - - echo "${_flags_infoValue_}" - unset _flags_gFI_usName_ _flags_gfI_info_ _flags_infoValue_ _flags_infoVar_ \ - _flags_strToEval_ _flags_typeValue_ _flags_typeVar_ - [ ${flags_return} -eq ${FLAGS_ERROR} ] && _flags_error "${flags_error}" - return ${flags_return} -} - -# Check for presence of item in a list. -# -# Passed a string (e.g. 'abc'), this function will determine if the string is -# present in the list of strings (e.g. ' foo bar abc '). -# -# Args: -# _flags_str_: string: string to search for in a list of strings -# unnamed: list: list of strings -# Returns: -# boolean: true if item is in the list -_flags_itemInList() { - _flags_str_=$1 - shift - - case " ${*:-} " in - *\ ${_flags_str_}\ *) flags_return=${FLAGS_TRUE} ;; - *) flags_return=${FLAGS_FALSE} ;; - esac - - unset _flags_str_ - return ${flags_return} -} - -# Returns the width of the current screen. -# -# Output: -# integer: width in columns of the current screen. -_flags_columns() { - if [ -z "${__flags_columns}" ]; then - if eval stty size >/dev/null 2>&1; then - # stty size worked :-) - # shellcheck disable=SC2046 - set -- `stty size` - __flags_columns="${2:-}" - fi - fi - if [ -z "${__flags_columns}" ]; then - if eval tput cols >/dev/null 2>&1; then - # shellcheck disable=SC2046 - set -- `tput cols` - __flags_columns="${1:-}" - fi - fi - echo "${__flags_columns:-80}" -} - -# Validate a boolean. -# -# Args: -# _flags__bool: boolean: value to validate -# Returns: -# bool: true if the value is a valid boolean -_flags_validBool() { - _flags_bool_=$1 - - flags_return=${FLAGS_TRUE} - case "${_flags_bool_}" in - true|t|0) ;; - false|f|1) ;; - *) flags_return=${FLAGS_FALSE} ;; - esac - - unset _flags_bool_ - return ${flags_return} -} - -# Validate a float. -# -# Args: -# _flags_float_: float: value to validate -# Returns: -# bool: true if the value is a valid integer -_flags_validFloat() { - flags_return=${FLAGS_FALSE} - [ -n "$1" ] || return ${flags_return} - _flags_float_=$1 - - if _flags_validInt "${_flags_float_}"; then - flags_return=${FLAGS_TRUE} - elif _flags_useBuiltin; then - _flags_float_whole_=${_flags_float_%.*} - _flags_float_fraction_=${_flags_float_#*.} - if _flags_validInt "${_flags_float_whole_:-0}" -a \ - _flags_validInt "${_flags_float_fraction_}"; then - flags_return=${FLAGS_TRUE} - fi - unset _flags_float_whole_ _flags_float_fraction_ - else - flags_return=${FLAGS_TRUE} - case ${_flags_float_} in - -*) # Negative floats. - _flags_test_=`${FLAGS_EXPR_CMD} "${_flags_float_}" :\ - '\(-[0-9]*\.[0-9]*\)'` - ;; - *) # Positive floats. - _flags_test_=`${FLAGS_EXPR_CMD} "${_flags_float_}" :\ - '\([0-9]*\.[0-9]*\)'` - ;; - esac - [ "${_flags_test_}" != "${_flags_float_}" ] && flags_return=${FLAGS_FALSE} - unset _flags_test_ - fi - - unset _flags_float_ _flags_float_whole_ _flags_float_fraction_ - return ${flags_return} -} - -# Validate an integer. -# -# Args: -# _flags_int_: integer: value to validate -# Returns: -# bool: true if the value is a valid integer -_flags_validInt() { - flags_return=${FLAGS_FALSE} - [ -n "$1" ] || return ${flags_return} - _flags_int_=$1 - - case ${_flags_int_} in - -*.*) ;; # Ignore negative floats (we'll invalidate them later). - -*) # Strip possible leading negative sign. - if _flags_useBuiltin; then - _flags_int_=${_flags_int_#-} - else - _flags_int_=`${FLAGS_EXPR_CMD} "${_flags_int_}" : '-\([0-9][0-9]*\)'` - fi - ;; - esac - - case ${_flags_int_} in - *[!0-9]*) flags_return=${FLAGS_FALSE} ;; - *) flags_return=${FLAGS_TRUE} ;; - esac - - unset _flags_int_ - return ${flags_return} -} - -# Parse command-line options using the standard getopt. -# -# Note: the flag options are passed around in the global __flags_opts so that -# the formatting is not lost due to shell parsing and such. -# -# Args: -# @: varies: command-line options to parse -# Returns: -# integer: a FLAGS success condition -_flags_getoptStandard() { - flags_return=${FLAGS_TRUE} - _flags_shortOpts_=`_flags_genOptStr ${__FLAGS_OPTSTR_SHORT}` - - # Check for spaces in passed options. - for _flags_opt_ in "$@"; do - # Note: the silliness with the x's is purely for ksh93 on Ubuntu 6.06. - _flags_match_=`echo "x${_flags_opt_}x" |sed 's/ //g'` - if [ "${_flags_match_}" != "x${_flags_opt_}x" ]; then - flags_error='the available getopt does not support spaces in options' - flags_return=${FLAGS_ERROR} - break - fi - done - - if [ ${flags_return} -eq ${FLAGS_TRUE} ]; then - __flags_opts=`getopt "${_flags_shortOpts_}" "$@" 2>&1` - _flags_rtrn_=$? - if [ ${_flags_rtrn_} -ne ${FLAGS_TRUE} ]; then - _flags_warn "${__flags_opts}" - flags_error='unable to parse provided options with getopt.' - flags_return=${FLAGS_ERROR} - fi - fi - - unset _flags_match_ _flags_opt_ _flags_rtrn_ _flags_shortOpts_ - return ${flags_return} -} - -# Parse command-line options using the enhanced getopt. -# -# Note: the flag options are passed around in the global __flags_opts so that -# the formatting is not lost due to shell parsing and such. -# -# Args: -# @: varies: command-line options to parse -# Returns: -# integer: a FLAGS success condition -_flags_getoptEnhanced() { - flags_return=${FLAGS_TRUE} - _flags_shortOpts_=`_flags_genOptStr ${__FLAGS_OPTSTR_SHORT}` - _flags_boolOpts_=`echo "${__flags_boolNames}" \ - |sed 's/^ *//;s/ *$//;s/ /,/g'` - _flags_longOpts_=`_flags_genOptStr ${__FLAGS_OPTSTR_LONG}` - - __flags_opts=`${FLAGS_GETOPT_CMD} \ - -o "${_flags_shortOpts_}" \ - -l "${_flags_longOpts_},${_flags_boolOpts_}" \ - -- "$@" 2>&1` - _flags_rtrn_=$? - if [ ${_flags_rtrn_} -ne ${FLAGS_TRUE} ]; then - _flags_warn "${__flags_opts}" - flags_error='unable to parse provided options with getopt.' - flags_return=${FLAGS_ERROR} - fi - - unset _flags_boolOpts_ _flags_longOpts_ _flags_rtrn_ _flags_shortOpts_ - return ${flags_return} -} - -# Dynamically parse a getopt result and set appropriate variables. -# -# This function does the actual conversion of getopt output and runs it through -# the standard case structure for parsing. The case structure is actually quite -# dynamic to support any number of flags. -# -# Args: -# argc: int: original command-line argument count -# @: varies: output from getopt parsing -# Returns: -# integer: a FLAGS success condition -_flags_parseGetopt() { - _flags_argc_=$1 - shift - - flags_return=${FLAGS_TRUE} - - if [ "${__FLAGS_GETOPT_VERS}" -ne "${__FLAGS_GETOPT_VERS_ENH}" ]; then - # The @$ must be unquoted as it needs to be re-split. - # shellcheck disable=SC2068 - set -- $@ - else - # Note the quotes around the `$@' -- they are essential! - eval set -- "$@" - fi - - # Provide user with the number of arguments to shift by later. - # NOTE: the FLAGS_ARGC variable is obsolete as of 1.0.3 because it does not - # properly give user access to non-flag arguments mixed in between flag - # arguments. Its usage was replaced by FLAGS_ARGV, and it is being kept only - # for backwards compatibility reasons. - FLAGS_ARGC=`_flags_math "$# - 1 - ${_flags_argc_}"` - export FLAGS_ARGC - - # Handle options. note options with values must do an additional shift. - while true; do - _flags_opt_=$1 - _flags_arg_=${2:-} - _flags_type_=${__FLAGS_TYPE_NONE} - _flags_name_='' - - # Determine long flag name. - case "${_flags_opt_}" in - --) shift; break ;; # Discontinue option parsing. - - --*) # Long option. - if _flags_useBuiltin; then - _flags_opt_=${_flags_opt_#*--} - else - _flags_opt_=`${FLAGS_EXPR_CMD} "${_flags_opt_}" : '--\(.*\)'` - fi - _flags_len_=${__FLAGS_LEN_LONG} - if _flags_itemInList "${_flags_opt_}" "${__flags_longNames}"; then - _flags_name_=${_flags_opt_} - else - # Check for negated long boolean version. - if _flags_itemInList "${_flags_opt_}" "${__flags_boolNames}"; then - if _flags_useBuiltin; then - _flags_name_=${_flags_opt_#*no} - else - _flags_name_=`${FLAGS_EXPR_CMD} "${_flags_opt_}" : 'no\(.*\)'` - fi - _flags_type_=${__FLAGS_TYPE_BOOLEAN} - _flags_arg_=${__FLAGS_NULL} - fi - fi - ;; - - -*) # Short option. - if _flags_useBuiltin; then - _flags_opt_=${_flags_opt_#*-} - else - _flags_opt_=`${FLAGS_EXPR_CMD} "${_flags_opt_}" : '-\(.*\)'` - fi - _flags_len_=${__FLAGS_LEN_SHORT} - if _flags_itemInList "${_flags_opt_}" "${__flags_shortNames}"; then - # Yes. Match short name to long name. Note purposeful off-by-one - # (too high) with awk calculations. - _flags_pos_=`echo "${__flags_shortNames}" \ - |awk 'BEGIN{RS=" ";rn=0}$0==e{rn=NR}END{print rn}' \ - e="${_flags_opt_}"` - _flags_name_=`echo "${__flags_longNames}" \ - |awk 'BEGIN{RS=" "}rn==NR{print $0}' rn="${_flags_pos_}"` - fi - ;; - esac - - # Die if the flag was unrecognized. - if [ -z "${_flags_name_}" ]; then - flags_error="unrecognized option (${_flags_opt_})" - flags_return=${FLAGS_ERROR} - break - fi - - # Set new flag value. - _flags_usName_=`_flags_underscoreName "${_flags_name_}"` - [ ${_flags_type_} -eq ${__FLAGS_TYPE_NONE} ] && \ - _flags_type_=`_flags_getFlagInfo \ - "${_flags_usName_}" ${__FLAGS_INFO_TYPE}` - case ${_flags_type_} in - ${__FLAGS_TYPE_BOOLEAN}) - if [ ${_flags_len_} -eq ${__FLAGS_LEN_LONG} ]; then - if [ "${_flags_arg_}" != "${__FLAGS_NULL}" ]; then - eval "FLAGS_${_flags_usName_}=${FLAGS_TRUE}" - else - eval "FLAGS_${_flags_usName_}=${FLAGS_FALSE}" - fi - else - _flags_strToEval_="_flags_val_=\ -\${__flags_${_flags_usName_}_${__FLAGS_INFO_DEFAULT}}" - eval "${_flags_strToEval_}" - # shellcheck disable=SC2154 - if [ "${_flags_val_}" -eq ${FLAGS_FALSE} ]; then - eval "FLAGS_${_flags_usName_}=${FLAGS_TRUE}" - else - eval "FLAGS_${_flags_usName_}=${FLAGS_FALSE}" - fi - fi - ;; - - ${__FLAGS_TYPE_FLOAT}) - if _flags_validFloat "${_flags_arg_}"; then - eval "FLAGS_${_flags_usName_}='${_flags_arg_}'" - else - flags_error="invalid float value (${_flags_arg_})" - flags_return=${FLAGS_ERROR} - break - fi - ;; - - ${__FLAGS_TYPE_INTEGER}) - if _flags_validInt "${_flags_arg_}"; then - eval "FLAGS_${_flags_usName_}='${_flags_arg_}'" - else - flags_error="invalid integer value (${_flags_arg_})" - flags_return=${FLAGS_ERROR} - break - fi - ;; - - ${__FLAGS_TYPE_STRING}) - eval "FLAGS_${_flags_usName_}='${_flags_arg_}'" - ;; - esac - - # Handle special case help flag. - if [ "${_flags_usName_}" = 'help' ]; then - # shellcheck disable=SC2154 - if [ "${FLAGS_help}" -eq ${FLAGS_TRUE} ]; then - flags_help - flags_error='help requested' - flags_return=${FLAGS_FALSE} - break - fi - fi - - # Shift the option and non-boolean arguments out. - shift - [ "${_flags_type_}" != ${__FLAGS_TYPE_BOOLEAN} ] && shift - done - - # Give user back non-flag arguments. - FLAGS_ARGV='' - while [ $# -gt 0 ]; do - FLAGS_ARGV="${FLAGS_ARGV:+${FLAGS_ARGV} }'$1'" - shift - done - - unset _flags_arg_ _flags_len_ _flags_name_ _flags_opt_ _flags_pos_ \ - _flags_strToEval_ _flags_type_ _flags_usName_ _flags_val_ - return ${flags_return} -} - -# Perform some path using built-ins. -# -# Args: -# $@: string: math expression to evaluate -# Output: -# integer: the result -# Returns: -# bool: success of math evaluation -_flags_math() { - if [ $# -eq 0 ]; then - flags_return=${FLAGS_FALSE} - elif _flags_useBuiltin; then - # Variable assignment is needed as workaround for Solaris Bourne shell, - # which cannot parse a bare $((expression)). - # shellcheck disable=SC2016 - _flags_expr_='$(($@))' - eval echo ${_flags_expr_} - flags_return=$? - unset _flags_expr_ - else - eval expr "$@" - flags_return=$? - fi - - return ${flags_return} -} - -# Cross-platform strlen() implementation. -# -# Args: -# _flags_str: string: to determine length of -# Output: -# integer: length of string -# Returns: -# bool: success of strlen evaluation -_flags_strlen() { - _flags_str_=${1:-} - - if [ -z "${_flags_str_}" ]; then - flags_output=0 - elif _flags_useBuiltin; then - flags_output=${#_flags_str_} - else - flags_output=`${FLAGS_EXPR_CMD} "${_flags_str_}" : '.*'` - fi - flags_return=$? - - unset _flags_str_ - echo "${flags_output}" - return ${flags_return} -} - -# Use built-in helper function to enable unit testing. -# -# Args: -# None -# Returns: -# bool: true if built-ins should be used -_flags_useBuiltin() { return ${__FLAGS_USE_BUILTIN}; } - -#------------------------------------------------------------------------------ -# public functions -# -# A basic boolean flag. Boolean flags do not take any arguments, and their -# value is either 1 (false) or 0 (true). For long flags, the false value is -# specified on the command line by prepending the word 'no'. With short flags, -# the presence of the flag toggles the current value between true and false. -# Specifying a short boolean flag twice on the command results in returning the -# value back to the default value. -# -# A default value is required for boolean flags. -# -# For example, lets say a Boolean flag was created whose long name was 'update' -# and whose short name was 'x', and the default value was 'false'. This flag -# could be explicitly set to 'true' with '--update' or by '-x', and it could be -# explicitly set to 'false' with '--noupdate'. -DEFINE_boolean() { _flags_define ${__FLAGS_TYPE_BOOLEAN} "$@"; } - -# Other basic flags. -DEFINE_float() { _flags_define ${__FLAGS_TYPE_FLOAT} "$@"; } -DEFINE_integer() { _flags_define ${__FLAGS_TYPE_INTEGER} "$@"; } -DEFINE_string() { _flags_define ${__FLAGS_TYPE_STRING} "$@"; } - -# Parse the flags. -# -# Args: -# unnamed: list: command-line flags to parse -# Returns: -# integer: success of operation, or error -FLAGS() { - # Define a standard 'help' flag if one isn't already defined. - [ -z "${__flags_help_type:-}" ] && \ - DEFINE_boolean 'help' false 'show this help' 'h' - - # Parse options. - if [ $# -gt 0 ]; then - if [ "${__FLAGS_GETOPT_VERS}" -ne "${__FLAGS_GETOPT_VERS_ENH}" ]; then - _flags_getoptStandard "$@" - else - _flags_getoptEnhanced "$@" - fi - flags_return=$? - else - # Nothing passed; won't bother running getopt. - __flags_opts='--' - flags_return=${FLAGS_TRUE} - fi - - if [ ${flags_return} -eq ${FLAGS_TRUE} ]; then - _flags_parseGetopt $# "${__flags_opts}" - flags_return=$? - fi - - [ ${flags_return} -eq ${FLAGS_ERROR} ] && _flags_fatal "${flags_error}" - return ${flags_return} -} - -# This is a helper function for determining the 'getopt' version for platforms -# where the detection isn't working. It simply outputs debug information that -# can be included in a bug report. -# -# Args: -# none -# Output: -# debug info that can be included in a bug report -# Returns: -# nothing -flags_getoptInfo() { - # Platform info. - _flags_debug "uname -a: `uname -a`" - _flags_debug "PATH: ${PATH}" - - # Shell info. - if [ -n "${BASH_VERSION:-}" ]; then - _flags_debug 'shell: bash' - _flags_debug "BASH_VERSION: ${BASH_VERSION}" - elif [ -n "${ZSH_VERSION:-}" ]; then - _flags_debug 'shell: zsh' - _flags_debug "ZSH_VERSION: ${ZSH_VERSION}" - fi - - # getopt info. - ${FLAGS_GETOPT_CMD} >/dev/null - _flags_getoptReturn=$? - _flags_debug "getopt return: ${_flags_getoptReturn}" - _flags_debug "getopt --version: `${FLAGS_GETOPT_CMD} --version 2>&1`" - - unset _flags_getoptReturn -} - -# Returns whether the detected getopt version is the enhanced version. -# -# Args: -# none -# Output: -# none -# Returns: -# bool: true if getopt is the enhanced version -flags_getoptIsEnh() { - test "${__FLAGS_GETOPT_VERS}" -eq "${__FLAGS_GETOPT_VERS_ENH}" -} - -# Returns whether the detected getopt version is the standard version. -# -# Args: -# none -# Returns: -# bool: true if getopt is the standard version -flags_getoptIsStd() { - test "${__FLAGS_GETOPT_VERS}" -eq "${__FLAGS_GETOPT_VERS_STD}" -} - -# This is effectively a 'usage()' function. It prints usage information and -# exits the program with ${FLAGS_FALSE} if it is ever found in the command line -# arguments. Note this function can be overridden so other apps can define -# their own --help flag, replacing this one, if they want. -# -# Args: -# none -# Returns: -# integer: success of operation (always returns true) -flags_help() { - if [ -n "${FLAGS_HELP:-}" ]; then - echo "${FLAGS_HELP}" >&2 - else - echo "USAGE: ${FLAGS_PARENT:-$0} [flags] args" >&2 - fi - if [ -n "${__flags_longNames}" ]; then - echo 'flags:' >&2 - for flags_name_ in ${__flags_longNames}; do - flags_flagStr_='' - flags_boolStr_='' - flags_usName_=`_flags_underscoreName "${flags_name_}"` - - flags_default_=`_flags_getFlagInfo \ - "${flags_usName_}" ${__FLAGS_INFO_DEFAULT}` - flags_help_=`_flags_getFlagInfo \ - "${flags_usName_}" ${__FLAGS_INFO_HELP}` - flags_short_=`_flags_getFlagInfo \ - "${flags_usName_}" ${__FLAGS_INFO_SHORT}` - flags_type_=`_flags_getFlagInfo \ - "${flags_usName_}" ${__FLAGS_INFO_TYPE}` - - [ "${flags_short_}" != "${__FLAGS_NULL}" ] && \ - flags_flagStr_="-${flags_short_}" - - if [ "${__FLAGS_GETOPT_VERS}" -eq "${__FLAGS_GETOPT_VERS_ENH}" ]; then - [ "${flags_short_}" != "${__FLAGS_NULL}" ] && \ - flags_flagStr_="${flags_flagStr_}," - # Add [no] to long boolean flag names, except the 'help' flag. - [ "${flags_type_}" -eq ${__FLAGS_TYPE_BOOLEAN} \ - -a "${flags_usName_}" != 'help' ] && \ - flags_boolStr_='[no]' - flags_flagStr_="${flags_flagStr_}--${flags_boolStr_}${flags_name_}:" - fi - - case ${flags_type_} in - ${__FLAGS_TYPE_BOOLEAN}) - if [ "${flags_default_}" -eq ${FLAGS_TRUE} ]; then - flags_defaultStr_='true' - else - flags_defaultStr_='false' - fi - ;; - ${__FLAGS_TYPE_FLOAT}|${__FLAGS_TYPE_INTEGER}) - flags_defaultStr_=${flags_default_} ;; - ${__FLAGS_TYPE_STRING}) flags_defaultStr_="'${flags_default_}'" ;; - esac - flags_defaultStr_="(default: ${flags_defaultStr_})" - - flags_helpStr_=" ${flags_flagStr_} ${flags_help_:+${flags_help_} }${flags_defaultStr_}" - _flags_strlen "${flags_helpStr_}" >/dev/null - flags_helpStrLen_=${flags_output} - flags_columns_=`_flags_columns` - - if [ "${flags_helpStrLen_}" -lt "${flags_columns_}" ]; then - echo "${flags_helpStr_}" >&2 - else - echo " ${flags_flagStr_} ${flags_help_}" >&2 - # Note: the silliness with the x's is purely for ksh93 on Ubuntu 6.06 - # because it doesn't like empty strings when used in this manner. - flags_emptyStr_="`echo \"x${flags_flagStr_}x\" \ - |awk '{printf "%"length($0)-2"s", ""}'`" - flags_helpStr_=" ${flags_emptyStr_} ${flags_defaultStr_}" - _flags_strlen "${flags_helpStr_}" >/dev/null - flags_helpStrLen_=${flags_output} - - if [ "${__FLAGS_GETOPT_VERS}" -eq "${__FLAGS_GETOPT_VERS_STD}" \ - -o "${flags_helpStrLen_}" -lt "${flags_columns_}" ]; then - # Indented to match help string. - echo "${flags_helpStr_}" >&2 - else - # Indented four from left to allow for longer defaults as long flag - # names might be used too, making things too long. - echo " ${flags_defaultStr_}" >&2 - fi - fi - done - fi - - unset flags_boolStr_ flags_default_ flags_defaultStr_ flags_emptyStr_ \ - flags_flagStr_ flags_help_ flags_helpStr flags_helpStrLen flags_name_ \ - flags_columns_ flags_short_ flags_type_ flags_usName_ - return ${FLAGS_TRUE} -} - -# Reset shflags back to an uninitialized state. -# -# Args: -# none -# Returns: -# nothing -flags_reset() { - for flags_name_ in ${__flags_longNames}; do - flags_usName_=`_flags_underscoreName "${flags_name_}"` - flags_strToEval_="unset FLAGS_${flags_usName_}" - for flags_type_ in \ - ${__FLAGS_INFO_DEFAULT} \ - ${__FLAGS_INFO_HELP} \ - ${__FLAGS_INFO_SHORT} \ - ${__FLAGS_INFO_TYPE} - do - flags_strToEval_=\ -"${flags_strToEval_} __flags_${flags_usName_}_${flags_type_}" - done - eval "${flags_strToEval_}" - done - - # Reset internal variables. - __flags_boolNames=' ' - __flags_longNames=' ' - __flags_shortNames=' ' - __flags_definedNames=' ' - - # Reset logging level back to default. - flags_setLoggingLevel ${__FLAGS_LEVEL_DEFAULT} - - unset flags_name_ flags_type_ flags_strToEval_ flags_usName_ -} - -# -# Initialization -# - -# Set the default logging level. -flags_setLoggingLevel ${__FLAGS_LEVEL_DEFAULT} diff --git a/test/lib/shlib b/test/lib/shlib deleted file mode 100644 index a843043..0000000 --- a/test/lib/shlib +++ /dev/null @@ -1,39 +0,0 @@ -# vim:et:ft=sh:sts=2:sw=2 -# -# Copyright 2008 Kate Ward. All Rights Reserved. -# Released under the LGPL (GNU Lesser General Public License). -# -# Author: kate.ward@forestent.com (Kate Ward) -# -# Library of shell functions. - -# Convert a relative path into it's absolute equivalent. -# -# This function will automatically prepend the current working directory if the -# path is not already absolute. It then removes all parent references (../) to -# reconstruct the proper absolute path. -# -# Args: -# shlib_path_: string: relative path -# Outputs: -# string: absolute path -shlib_relToAbsPath() -{ - shlib_path_=$1 - - # prepend current directory to relative paths - echo "${shlib_path_}" |grep '^/' >/dev/null 2>&1 \ - || shlib_path_="${PWD}/${shlib_path_}" - - # clean up the path. if all seds supported true regular expressions, then - # this is what it would be: - shlib_old_=${shlib_path_} - while true; do - shlib_new_=`echo "${shlib_old_}" |sed 's/[^/]*\/\.\.\/*//;s/\/\.\//\//'` - [ "${shlib_old_}" = "${shlib_new_}" ] && break - shlib_old_=${shlib_new_} - done - echo "${shlib_new_}" - - unset shlib_path_ shlib_old_ shlib_new_ -} diff --git a/test/lib/versions b/test/lib/versions deleted file mode 100755 index 95eebd3..0000000 --- a/test/lib/versions +++ /dev/null @@ -1,251 +0,0 @@ -#! /bin/sh -# vim:et:ft=sh:sts=2:sw=2 -# -# Versions determines the versions of all installed shells. -# -# Copyright 2008-2017 Kate Ward. All Rights Reserved. -# Released under the Apache 2.0 License. -# -# Author: kate.ward@forestent.com (Kate Ward) -# https://github.com/kward/shlib -# -# This library provides reusable functions that determine actual names and -# versions of installed shells and the OS. The library can also be run as a -# script if set executable. -# -# Disable checks that aren't fully portable (POSIX != portable). -# shellcheck disable=SC2006 - -ARGV0=`basename "$0"` -LSB_RELEASE='/etc/lsb-release' -VERSIONS_SHELLS="ash /bin/bash /bin/dash /bin/ksh /bin/pdksh /bin/sh /bin/zsh" - -true; TRUE=$? -false; FALSE=$? -ERROR=2 - -UNAME_R=`uname -r` -UNAME_S=`uname -s` - -__versions_haveStrings=${ERROR} - -versions_osName() { - os_name_='unrecognized' - os_system_=${UNAME_S} - os_release_=${UNAME_R} - case ${os_system_} in - CYGWIN_NT-*) os_name_='Cygwin' ;; - Darwin) - os_name_=`/usr/bin/sw_vers -productName` - os_version_=`versions_osVersion` - case ${os_version_} in - 10.4|10.4.[0-9]*) os_name_='Mac OS X Tiger' ;; - 10.5|10.5.[0-9]*) os_name_='Mac OS X Leopard' ;; - 10.6|10.6.[0-9]*) os_name_='Mac OS X Snow Leopard' ;; - 10.7|10.7.[0-9]*) os_name_='Mac OS X Lion' ;; - 10.8|10.8.[0-9]*) os_name_='Mac OS X Mountain Lion' ;; - 10.9|10.9.[0-9]*) os_name_='Mac OS X Mavericks' ;; - 10.10|10.10.[0-9]*) os_name_='Mac OS X Yosemite' ;; - 10.11|10.11.[0-9]*) os_name_='Mac OS X El Capitan' ;; - 10.12|10.12.[0-9]*) os_name_='macOS Sierra' ;; - 10.13|10.13.[0-9]*) os_name_='macOS High Sierra' ;; - *) os_name_='macOS' ;; - esac - ;; - FreeBSD) os_name_='FreeBSD' ;; - Linux) os_name_='Linux' ;; - SunOS) - if grep 'OpenSolaris' /etc/release >/dev/null; then - os_name_='OpenSolaris' - else - os_name_='Solaris' - fi - ;; - esac - - echo ${os_name_} - unset os_name_ os_system_ os_release_ os_version_ -} - -versions_osVersion() { - os_version_='unrecognized' - os_system_=${UNAME_S} - os_release_=${UNAME_R} - case ${os_system_} in - CYGWIN_NT-*) - os_version_=`expr "${os_release_}" : '\([0-9]*\.[0-9]\.[0-9]*\).*'` - ;; - Darwin) - os_version_=`/usr/bin/sw_vers -productVersion` - ;; - FreeBSD) - os_version_=`expr "${os_release_}" : '\([0-9]*\.[0-9]*\)-.*'` - ;; - Linux) - if [ -r '/etc/os-release' ]; then - os_version_=`awk -F= '$1~/PRETTY_NAME/{print $2}' /etc/os-release \ - |sed 's/"//g'` - elif [ -r '/etc/redhat-release' ]; then - os_version_=`cat /etc/redhat-release` - elif [ -r '/etc/SuSE-release' ]; then - os_version_=`head -n 1 /etc/SuSE-release` - elif [ -r "${LSB_RELEASE}" ]; then - if grep -q 'DISTRIB_ID=Ubuntu' "${LSB_RELEASE}"; then - # shellcheck disable=SC2002 - os_version_=`cat "${LSB_RELEASE}" \ - |awk -F= '$1~/DISTRIB_DESCRIPTION/{print $2}' \ - |sed 's/"//g;s/ /-/g'` - fi - fi - ;; - SunOS) - if grep 'OpenSolaris' /etc/release >/dev/null; then - os_version_=`grep 'OpenSolaris' /etc/release |awk '{print $2"("$3")"}'` - else - major_=`echo "${os_release_}" |sed 's/[0-9]*\.\([0-9]*\)/\1/'` - minor_=`grep Solaris /etc/release |sed 's/[^u]*\(u[0-9]*\).*/\1/'` - os_version_="${major_}${minor_}" - fi - ;; - esac - - echo "${os_version_}" - unset os_name_ os_release_ os_version_ major_ minor_ -} - -versions_shellVersion() { - shell_=$1 - - shell_present_=${FALSE} - case "${shell_}" in - ash) - [ -x '/bin/busybox' ] && shell_present_=${TRUE} - ;; - *) - [ -x "${shell_}" ] && shell_present_=${TRUE} - ;; - esac - if [ ${shell_present_} -eq ${FALSE} ]; then - echo 'not installed' - return ${FALSE} - fi - - version_='' - case ${shell_} in - */sh) - # TODO(kward): fix this - ## this could be one of any number of shells. try until one fits. - #version_=`versions_shell_bash ${shell_}` - ## dash cannot be self determined yet - #[ -z "${version_}" ] && version_=`versions_shell_ksh ${shell_}` - ## pdksh is covered in versions_shell_ksh() - #[ -z "${version_}" ] && version_=`versions_shell_zsh ${shell_}` - ;; - ash) version_=`versions_shell_ash "${shell_}"` ;; - */bash) version_=`versions_shell_bash "${shell_}"` ;; - */dash) - # simply assuming Ubuntu Linux until somebody comes up with a better - # test. the following test will return an empty string if dash is not - # installed. - version_=`versions_shell_dash` - ;; - */ksh) version_=`versions_shell_ksh "${shell_}"` ;; - */pdksh) version_=`versions_shell_pdksh "${shell_}"` ;; - */zsh) version_=`versions_shell_zsh "${shell_}"` ;; - *) version_='invalid' - esac - - echo "${version_:-unknown}" - unset shell_ version_ -} - -# The ash shell is included in BusyBox. -versions_shell_ash() { - busybox --help |head -1 |sed 's/BusyBox v\([0-9.]*\) .*/\1/' -} - -versions_shell_bash() { - $1 --version 2>&1 |grep 'GNU bash' |sed 's/.*version \([^ ]*\).*/\1/' -} - -versions_shell_dash() { - eval dpkg >/dev/null 2>&1 - [ $? -eq 127 ] && return # return if dpkg not found - - dpkg -l |grep ' dash ' |awk '{print $3}' -} - -versions_shell_ksh() { - versions_shell_=$1 - versions_version_='' - - # Try a few different ways to figure out the version. - if versions_version_=`${versions_shell_} --version : 2>&1`; then - versions_version_=`echo "${versions_version_}" \ - |sed 's/.*\([0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\).*/\1/'` - fi - if [ -z "${versions_version_}" ]; then - _versions_have_strings - versions_version_=`strings "${versions_shell_}" 2>&1 \ - |grep Version \ - |sed 's/^.*Version \(.*\)$/\1/;s/ s+ \$$//;s/ /-/g'` - fi - if [ -z "${versions_version_}" ]; then - versions_version_=`versions_shell_pdksh "${versions_shell_}"` - fi - - echo "${versions_version_}" - unset versions_shell_ versions_version_ -} - -versions_shell_pdksh() { - _versions_have_strings - strings "$1" 2>&1 \ - |grep 'PD KSH' \ - |sed -e 's/.*PD KSH \(.*\)/\1/;s/ /-/g' -} - -versions_shell_zsh() { - versions_shell_=$1 - - # Try a few different ways to figure out the version. - # shellcheck disable=SC2016 - versions_version_=`echo 'echo ${ZSH_VERSION}' |${versions_shell_}` - - if [ -z "${versions_version_}" ]; then - versions_version_=`${versions_shell_} --version 2>&1 |awk '{print $2}'` - fi - - echo "${versions_version_}" - unset versions_shell_ versions_version_ -} - -# Determine if the 'strings' binary installed. -_versions_have_strings() { - [ ${__versions_haveStrings} -ne ${ERROR} ] && return - if eval strings /dev/null >/dev/null 2>&1; then - __versions_haveStrings=${TRUE} - return - fi - - echo 'WARN: strings not installed. try installing binutils?' >&2 - __versions_haveStrings=${FALSE} -} - -versions_main() { - # Treat unset variables as an error. - set -u - - os_name=`versions_osName` - os_version=`versions_osVersion` - echo "os: ${os_name} version: ${os_version}" - - for shell in ${VERSIONS_SHELLS}; do - shell_version=`versions_shellVersion "${shell}"` - echo "shell: ${shell} version: ${shell_version}" - done -} - -if [ "${ARGV0}" = 'versions' ]; then - versions_main "$@" -fi diff --git a/test/list_test.sh b/test/list_test.sh deleted file mode 100755 index ce40d55..0000000 --- a/test/list_test.sh +++ /dev/null @@ -1,25 +0,0 @@ -#! /bin/bash - -testListFromOneElement() { - assertEquals 1 $(list 1) -} - -testListFromEmpty() { - assertEquals "" "$(list)" -} - -testListUnlist() { - assertEquals "1 3 6" "$(list 1 3 6 | unlist)" -} - -testList() { - list=$(cat < /dev/null \ - && fail "There should be syntax error, because map is an one argument operation" -} - -testFlatMap() { - assertEquals "1 2 3 2 3 3" "$(list {1..3} | list_map lambda x . 'seq $x 3' | unlist)" - assertEquals "d e h l l l o o r w" "$(list hello world | list_map lambda x . 'command fold -w 1 <<< $x' | sort | unlist)" -} - -. ./shunit2-init.sh \ No newline at end of file diff --git a/test/predicates_test.sh b/test/predicates_test.sh deleted file mode 100755 index 5e96337..0000000 --- a/test/predicates_test.sh +++ /dev/null @@ -1,52 +0,0 @@ -#! /bin/bash - -testIsint() { - assertEquals 'true' $(isint 1) - assertEquals 'true' $(isint -1) - assertEquals 'false' $(isint a) - assertEquals 'false' $(isint "") - assertEquals '1 2 3 4 5' "$(list 1 a 2 b 3 c 4 d 5 e | filter lambda x . 'isint $x' | unlist )" - assertEquals '1 2' "$(list 1 a 2 b 3 c 4 d 5 e | filter lambda x . '($(isint $x) && [[ $x -le 2 ]] && ret true) || ret false ' | unlist )" - - assertEquals 'false' $(not "isint 1") - assertEquals 'true' $(not "isint a") -} - -testIsempty() { - assertEquals 'true' $(isempty "") - assertEquals 'false' $(isempty a) - - assertEquals 'true' $(not "isempty a") - assertEquals 'false' $(not "isempty \"\"") -} - -testIsfile() { - f=$(mktemp) - - assertEquals 'true' $(isfile $f) - assertEquals 'false' $(isfile $f.xxx) - assertEquals 'false' $(isfile "") - assertEquals 'true' $(not "isfile $f.xxx") - - assertEquals 'false' $(isnonzerofile $f) - echo hello world >$f - assertEquals 'true' $(isnonzerofile $f) - - assertEquals 'true' $(iswritable $f) - chmod 400 $f - assertEquals 'false' $(iswritable $f) - - assertEquals 'true' $(isreadable $f) - chmod 200 $f - assertEquals 'false' $(isreadable $f) - - chmod 600 $f - rm $f -} - -testIsdir() { - assertEquals 'true' $(isdir .) - assertEquals 'false' $(isdir sir_not_appearing_in_this_film) -} - -. ./shunit2-init.sh diff --git a/test/prepend_test.sh b/test/prepend_test.sh deleted file mode 100755 index 491a56e..0000000 --- a/test/prepend_test.sh +++ /dev/null @@ -1,15 +0,0 @@ -#! /bin/bash - -testPrependToEmptyList() { - assertEquals 4 "$(list | list_prepend 4)" -} - -testPrependToOneElementList() { - assertEquals "4 1" "$(list 1 | list_prepend 4 | unlist)" -} - -testPrependToList() { - assertEquals "4 1 2 3 4 5" "$(list 1 2 3 4 5 | list_prepend 4 | unlist)" -} - -. ./shunit2-init.sh \ No newline at end of file diff --git a/test/shunit2 b/test/shunit2 deleted file mode 100755 index bdd79e8..0000000 --- a/test/shunit2 +++ /dev/null @@ -1,1137 +0,0 @@ -#! /bin/sh -# vim:et:ft=sh:sts=2:sw=2 -# -# Copyright 2008-2018 Kate Ward. All Rights Reserved. -# Released under the Apache 2.0 license. -# -# shUnit2 -- Unit testing framework for Unix shell scripts. -# https://github.com/kward/shunit2 -# -# Author: kate.ward@forestent.com (Kate Ward) -# -# shUnit2 is a xUnit based unit test framework for Bourne shell scripts. It is -# based on the popular JUnit unit testing framework for Java. -# -# $() are not fully portable (POSIX != portable). -# shellcheck disable=SC2006 -# expr may be antiquated, but it is the only solution in some cases. -# shellcheck disable=SC2003 -# Commands are purposely escaped so they can be mocked outside shUnit2. -# shellcheck disable=SC1001,SC1012 - -# Return if shunit2 already loaded. -\[ -n "${SHUNIT_VERSION:-}" ] && exit 0 -SHUNIT_VERSION='2.1.7' - -# Return values that scripts can use. -SHUNIT_TRUE=0 -SHUNIT_FALSE=1 -SHUNIT_ERROR=2 - -# Logging functions. -_shunit_warn() { - echo "${__shunit_ansi_yellow}shunit2:WARN${__shunit_ansi_none} $*" >&2 -} -_shunit_error() { - echo "${__shunit_ansi_red}shunit2:ERROR${__shunit_ansi_none} $*" >&2 -} -_shunit_fatal() { - echo "${__shunit_ansi_red}shunit2:FATAL${__shunit_ansi_none} $*" >&2 - exit ${SHUNIT_ERROR} -} - -# Determine some reasonable command defaults. -__SHUNIT_UNAME_S=`uname -s` -case "${__SHUNIT_UNAME_S}" in - BSD) __SHUNIT_CMD_EXPR='gexpr' ;; - *) __SHUNIT_CMD_EXPR='expr' ;; -esac - -__SHUNIT_CMD_ECHO_ESC='echo -e' -# shellcheck disable=SC2039 -\[ "`echo -e test`" = '-e test' ] && __SHUNIT_CMD_ECHO_ESC='echo' - -# Commands a user can override if needed. -SHUNIT_CMD_EXPR=${SHUNIT_CMD_EXPR:-${__SHUNIT_CMD_EXPR}} - -# Enable color output. Options are 'never', 'always', or 'auto'. -SHUNIT_COLOR=${SHUNIT_COLOR:-auto} - -# Specific shell checks. -if \[ -n "${ZSH_VERSION:-}" ]; then - setopt |grep "^shwordsplit$" >/dev/null - if \[ $? -ne ${SHUNIT_TRUE} ]; then - _shunit_fatal 'zsh shwordsplit option is required for proper operation' - fi - if \[ -z "${SHUNIT_PARENT:-}" ]; then - _shunit_fatal "zsh does not pass \$0 through properly. please declare \ -\"SHUNIT_PARENT=\$0\" before calling shUnit2" - fi -fi - -# -# Constants -# - -__SHUNIT_MODE_SOURCED='sourced' -__SHUNIT_MODE_STANDALONE='standalone' -__SHUNIT_PARENT=${SHUNIT_PARENT:-$0} - -# ANSI colors. -__SHUNIT_ANSI_NONE='\033[0m' -__SHUNIT_ANSI_RED='\033[1;31m' -__SHUNIT_ANSI_GREEN='\033[1;32m' -__SHUNIT_ANSI_YELLOW='\033[1;33m' -__SHUNIT_ANSI_CYAN='\033[1;36m' - -# Set the constants readonly. -__shunit_constants=`set |grep '^__SHUNIT_' |cut -d= -f1` -echo "${__shunit_constants}" |grep '^Binary file' >/dev/null && \ - __shunit_constants=`set |grep -a '^__SHUNIT_' |cut -d= -f1` -for __shunit_const in ${__shunit_constants}; do - if \[ -z "${ZSH_VERSION:-}" ]; then - readonly "${__shunit_const}" - else - case ${ZSH_VERSION} in - [123].*) readonly "${__shunit_const}" ;; - *) readonly -g "${__shunit_const}" # Declare readonly constants globally. - esac - fi -done -unset __shunit_const __shunit_constants - -# -# Internal variables. -# - -# Variables. -__shunit_lineno='' # Line number of executed test. -__shunit_mode=${__SHUNIT_MODE_SOURCED} # Operating mode. -__shunit_reportGenerated=${SHUNIT_FALSE} # Is report generated. -__shunit_script='' # Filename of unittest script (standalone mode). -__shunit_skip=${SHUNIT_FALSE} # Is skipping enabled. -__shunit_suite='' # Suite of tests to execute. - -# ANSI colors (populated by _shunit_configureColor()). -__shunit_ansi_none='' -__shunit_ansi_red='' -__shunit_ansi_green='' -__shunit_ansi_yellow='' -__shunit_ansi_cyan='' - -# Counts of tests. -__shunit_testSuccess=${SHUNIT_TRUE} -__shunit_testsTotal=0 -__shunit_testsPassed=0 -__shunit_testsFailed=0 - -# Counts of asserts. -__shunit_assertsTotal=0 -__shunit_assertsPassed=0 -__shunit_assertsFailed=0 -__shunit_assertsSkipped=0 - -# -# Macros. -# - -# shellcheck disable=SC2016,SC2089 -_SHUNIT_LINENO_='eval __shunit_lineno=""; if \[ "${1:-}" = "--lineno" ]; then \[ -n "$2" ] && __shunit_lineno="[$2] "; shift 2; fi' - -#----------------------------------------------------------------------------- -# Assertion functions. -# - -# Assert that two values are equal to one another. -# -# Args: -# message: string: failure message [optional] -# expected: string: expected value -# actual: string: actual value -# Returns: -# integer: success (TRUE/FALSE/ERROR constant) -assertEquals() { - # shellcheck disable=SC2090 - ${_SHUNIT_LINENO_} - if \[ $# -lt 2 -o $# -gt 3 ]; then - _shunit_error "assertEquals() requires two or three arguments; $# given" - _shunit_assertFail - return ${SHUNIT_ERROR} - fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} - - shunit_message_=${__shunit_lineno} - if \[ $# -eq 3 ]; then - shunit_message_="${shunit_message_}$1" - shift - fi - shunit_expected_=$1 - shunit_actual_=$2 - - shunit_return=${SHUNIT_TRUE} - if \[ "${shunit_expected_}" = "${shunit_actual_}" ]; then - _shunit_assertPass - else - failNotEquals "${shunit_message_}" "${shunit_expected_}" "${shunit_actual_}" - shunit_return=${SHUNIT_FALSE} - fi - - unset shunit_message_ shunit_expected_ shunit_actual_ - return ${shunit_return} -} -# shellcheck disable=SC2016,SC2034 -_ASSERT_EQUALS_='eval assertEquals --lineno "${LINENO:-}"' - -# Assert that two values are not equal to one another. -# -# Args: -# message: string: failure message [optional] -# expected: string: expected value -# actual: string: actual value -# Returns: -# integer: success (TRUE/FALSE/ERROR constant) -assertNotEquals() { - # shellcheck disable=SC2090 - ${_SHUNIT_LINENO_} - if \[ $# -lt 2 -o $# -gt 3 ]; then - _shunit_error "assertNotEquals() requires two or three arguments; $# given" - _shunit_assertFail - return ${SHUNIT_ERROR} - fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} - - shunit_message_=${__shunit_lineno} - if \[ $# -eq 3 ]; then - shunit_message_="${shunit_message_}$1" - shift - fi - shunit_expected_=$1 - shunit_actual_=$2 - - shunit_return=${SHUNIT_TRUE} - if \[ "${shunit_expected_}" != "${shunit_actual_}" ]; then - _shunit_assertPass - else - failSame "${shunit_message_}" "$@" - shunit_return=${SHUNIT_FALSE} - fi - - unset shunit_message_ shunit_expected_ shunit_actual_ - return ${shunit_return} -} -# shellcheck disable=SC2016,SC2034 -_ASSERT_NOT_EQUALS_='eval assertNotEquals --lineno "${LINENO:-}"' - -# Assert that a value is null (i.e. an empty string) -# -# Args: -# message: string: failure message [optional] -# actual: string: actual value -# Returns: -# integer: success (TRUE/FALSE/ERROR constant) -assertNull() { - # shellcheck disable=SC2090 - ${_SHUNIT_LINENO_} - if \[ $# -lt 1 -o $# -gt 2 ]; then - _shunit_error "assertNull() requires one or two arguments; $# given" - _shunit_assertFail - return ${SHUNIT_ERROR} - fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} - - shunit_message_=${__shunit_lineno} - if \[ $# -eq 2 ]; then - shunit_message_="${shunit_message_}$1" - shift - fi - assertTrue "${shunit_message_}" "[ -z '$1' ]" - shunit_return=$? - - unset shunit_message_ - return ${shunit_return} -} -# shellcheck disable=SC2016,SC2034 -_ASSERT_NULL_='eval assertNull --lineno "${LINENO:-}"' - -# Assert that a value is not null (i.e. a non-empty string) -# -# Args: -# message: string: failure message [optional] -# actual: string: actual value -# Returns: -# integer: success (TRUE/FALSE/ERROR constant) -assertNotNull() { - # shellcheck disable=SC2090 - ${_SHUNIT_LINENO_} - if \[ $# -gt 2 ]; then # allowing 0 arguments as $1 might actually be null - _shunit_error "assertNotNull() requires one or two arguments; $# given" - _shunit_assertFail - return ${SHUNIT_ERROR} - fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} - - shunit_message_=${__shunit_lineno} - if \[ $# -eq 2 ]; then - shunit_message_="${shunit_message_}$1" - shift - fi - shunit_actual_=`_shunit_escapeCharactersInString "${1:-}"` - test -n "${shunit_actual_}" - assertTrue "${shunit_message_}" $? - shunit_return=$? - - unset shunit_actual_ shunit_message_ - return ${shunit_return} -} -# shellcheck disable=SC2016,SC2034 -_ASSERT_NOT_NULL_='eval assertNotNull --lineno "${LINENO:-}"' - -# Assert that two values are the same (i.e. equal to one another). -# -# Args: -# message: string: failure message [optional] -# expected: string: expected value -# actual: string: actual value -# Returns: -# integer: success (TRUE/FALSE/ERROR constant) -assertSame() { - # shellcheck disable=SC2090 - ${_SHUNIT_LINENO_} - if \[ $# -lt 2 -o $# -gt 3 ]; then - _shunit_error "assertSame() requires two or three arguments; $# given" - _shunit_assertFail - return ${SHUNIT_ERROR} - fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} - - shunit_message_=${__shunit_lineno} - if \[ $# -eq 3 ]; then - shunit_message_="${shunit_message_}$1" - shift - fi - assertEquals "${shunit_message_}" "$1" "$2" - shunit_return=$? - - unset shunit_message_ - return ${shunit_return} -} -# shellcheck disable=SC2016,SC2034 -_ASSERT_SAME_='eval assertSame --lineno "${LINENO:-}"' - -# Assert that two values are not the same (i.e. not equal to one another). -# -# Args: -# message: string: failure message [optional] -# expected: string: expected value -# actual: string: actual value -# Returns: -# integer: success (TRUE/FALSE/ERROR constant) -assertNotSame() { - # shellcheck disable=SC2090 - ${_SHUNIT_LINENO_} - if \[ $# -lt 2 -o $# -gt 3 ]; then - _shunit_error "assertNotSame() requires two or three arguments; $# given" - _shunit_assertFail - return ${SHUNIT_ERROR} - fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} - - shunit_message_=${__shunit_lineno} - if \[ $# -eq 3 ]; then - shunit_message_="${shunit_message_:-}$1" - shift - fi - assertNotEquals "${shunit_message_}" "$1" "$2" - shunit_return=$? - - unset shunit_message_ - return ${shunit_return} -} -# shellcheck disable=SC2016,SC2034 -_ASSERT_NOT_SAME_='eval assertNotSame --lineno "${LINENO:-}"' - -# Assert that a value or shell test condition is true. -# -# In shell, a value of 0 is true and a non-zero value is false. Any integer -# value passed can thereby be tested. -# -# Shell supports much more complicated tests though, and a means to support -# them was needed. As such, this function tests that conditions are true or -# false through evaluation rather than just looking for a true or false. -# -# The following test will succeed: -# assertTrue 0 -# assertTrue "[ 34 -gt 23 ]" -# The following test will fail with a message: -# assertTrue 123 -# assertTrue "test failed" "[ -r '/non/existent/file' ]" -# -# Args: -# message: string: failure message [optional] -# condition: string: integer value or shell conditional statement -# Returns: -# integer: success (TRUE/FALSE/ERROR constant) -assertTrue() { - # shellcheck disable=SC2090 - ${_SHUNIT_LINENO_} - if \[ $# -lt 1 -o $# -gt 2 ]; then - _shunit_error "assertTrue() takes one or two arguments; $# given" - _shunit_assertFail - return ${SHUNIT_ERROR} - fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} - - shunit_message_=${__shunit_lineno} - if \[ $# -eq 2 ]; then - shunit_message_="${shunit_message_}$1" - shift - fi - shunit_condition_=$1 - - # See if condition is an integer, i.e. a return value. - shunit_match_=`expr "${shunit_condition_}" : '\([0-9]*\)'` - shunit_return=${SHUNIT_TRUE} - if \[ -z "${shunit_condition_}" ]; then - # Null condition. - shunit_return=${SHUNIT_FALSE} - elif \[ -n "${shunit_match_}" -a "${shunit_condition_}" = "${shunit_match_}" ] - then - # Possible return value. Treating 0 as true, and non-zero as false. - \[ "${shunit_condition_}" -ne 0 ] && shunit_return=${SHUNIT_FALSE} - else - # Hopefully... a condition. - ( eval "${shunit_condition_}" ) >/dev/null 2>&1 - \[ $? -ne 0 ] && shunit_return=${SHUNIT_FALSE} - fi - - # Record the test. - if \[ ${shunit_return} -eq ${SHUNIT_TRUE} ]; then - _shunit_assertPass - else - _shunit_assertFail "${shunit_message_}" - fi - - unset shunit_message_ shunit_condition_ shunit_match_ - return ${shunit_return} -} -# shellcheck disable=SC2016,SC2034 -_ASSERT_TRUE_='eval assertTrue --lineno "${LINENO:-}"' - -# Assert that a value or shell test condition is false. -# -# In shell, a value of 0 is true and a non-zero value is false. Any integer -# value passed can thereby be tested. -# -# Shell supports much more complicated tests though, and a means to support -# them was needed. As such, this function tests that conditions are true or -# false through evaluation rather than just looking for a true or false. -# -# The following test will succeed: -# assertFalse 1 -# assertFalse "[ 'apples' = 'oranges' ]" -# The following test will fail with a message: -# assertFalse 0 -# assertFalse "test failed" "[ 1 -eq 1 -a 2 -eq 2 ]" -# -# Args: -# message: string: failure message [optional] -# condition: string: integer value or shell conditional statement -# Returns: -# integer: success (TRUE/FALSE/ERROR constant) -assertFalse() { - # shellcheck disable=SC2090 - ${_SHUNIT_LINENO_} - if \[ $# -lt 1 -o $# -gt 2 ]; then - _shunit_error "assertFalse() quires one or two arguments; $# given" - _shunit_assertFail - return ${SHUNIT_ERROR} - fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} - - shunit_message_=${__shunit_lineno} - if \[ $# -eq 2 ]; then - shunit_message_="${shunit_message_}$1" - shift - fi - shunit_condition_=$1 - - # See if condition is an integer, i.e. a return value. - shunit_match_=`expr "${shunit_condition_}" : '\([0-9]*\)'` - shunit_return=${SHUNIT_TRUE} - if \[ -z "${shunit_condition_}" ]; then - # Null condition. - shunit_return=${SHUNIT_FALSE} - elif \[ -n "${shunit_match_}" -a "${shunit_condition_}" = "${shunit_match_}" ] - then - # Possible return value. Treating 0 as true, and non-zero as false. - \[ "${shunit_condition_}" -eq 0 ] && shunit_return=${SHUNIT_FALSE} - else - # Hopefully... a condition. - ( eval "${shunit_condition_}" ) >/dev/null 2>&1 - \[ $? -eq 0 ] && shunit_return=${SHUNIT_FALSE} - fi - - # Record the test. - if \[ "${shunit_return}" -eq "${SHUNIT_TRUE}" ]; then - _shunit_assertPass - else - _shunit_assertFail "${shunit_message_}" - fi - - unset shunit_message_ shunit_condition_ shunit_match_ - return "${shunit_return}" -} -# shellcheck disable=SC2016,SC2034 -_ASSERT_FALSE_='eval assertFalse --lineno "${LINENO:-}"' - -#----------------------------------------------------------------------------- -# Failure functions. -# - -# Records a test failure. -# -# Args: -# message: string: failure message [optional] -# Returns: -# integer: success (TRUE/FALSE/ERROR constant) -fail() { - # shellcheck disable=SC2090 - ${_SHUNIT_LINENO_} - if \[ $# -gt 1 ]; then - _shunit_error "fail() requires zero or one arguments; $# given" - return ${SHUNIT_ERROR} - fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} - - shunit_message_=${__shunit_lineno} - if \[ $# -eq 1 ]; then - shunit_message_="${shunit_message_}$1" - shift - fi - - _shunit_assertFail "${shunit_message_}" - - unset shunit_message_ - return ${SHUNIT_FALSE} -} -# shellcheck disable=SC2016,SC2034 -_FAIL_='eval fail --lineno "${LINENO:-}"' - -# Records a test failure, stating two values were not equal. -# -# Args: -# message: string: failure message [optional] -# expected: string: expected value -# actual: string: actual value -# Returns: -# integer: success (TRUE/FALSE/ERROR constant) -failNotEquals() { - # shellcheck disable=SC2090 - ${_SHUNIT_LINENO_} - if \[ $# -lt 2 -o $# -gt 3 ]; then - _shunit_error "failNotEquals() requires one or two arguments; $# given" - return ${SHUNIT_ERROR} - fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} - - shunit_message_=${__shunit_lineno} - if \[ $# -eq 3 ]; then - shunit_message_="${shunit_message_}$1" - shift - fi - shunit_expected_=$1 - shunit_actual_=$2 - - _shunit_assertFail "${shunit_message_:+${shunit_message_} }expected:<${shunit_expected_}> but was:<${shunit_actual_}>" - - unset shunit_message_ shunit_expected_ shunit_actual_ - return ${SHUNIT_FALSE} -} -# shellcheck disable=SC2016,SC2034 -_FAIL_NOT_EQUALS_='eval failNotEquals --lineno "${LINENO:-}"' - -# Records a test failure, stating two values should have been the same. -# -# Args: -# message: string: failure message [optional] -# expected: string: expected value -# actual: string: actual value -# Returns: -# integer: success (TRUE/FALSE/ERROR constant) -failSame() -{ - # shellcheck disable=SC2090 - ${_SHUNIT_LINENO_} - if \[ $# -lt 2 -o $# -gt 3 ]; then - _shunit_error "failSame() requires two or three arguments; $# given" - return ${SHUNIT_ERROR} - fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} - - shunit_message_=${__shunit_lineno} - if \[ $# -eq 3 ]; then - shunit_message_="${shunit_message_}$1" - shift - fi - - _shunit_assertFail "${shunit_message_:+${shunit_message_} }expected not same" - - unset shunit_message_ - return ${SHUNIT_FALSE} -} -# shellcheck disable=SC2016,SC2034 -_FAIL_SAME_='eval failSame --lineno "${LINENO:-}"' - -# Records a test failure, stating two values were not equal. -# -# This is functionally equivalent to calling failNotEquals(). -# -# Args: -# message: string: failure message [optional] -# expected: string: expected value -# actual: string: actual value -# Returns: -# integer: success (TRUE/FALSE/ERROR constant) -failNotSame() { - # shellcheck disable=SC2090 - ${_SHUNIT_LINENO_} - if \[ $# -lt 2 -o $# -gt 3 ]; then - _shunit_error "failNotEquals() requires one or two arguments; $# given" - return ${SHUNIT_ERROR} - fi - _shunit_shouldSkip && return ${SHUNIT_TRUE} - - shunit_message_=${__shunit_lineno} - if \[ $# -eq 3 ]; then - shunit_message_="${shunit_message_}$1" - shift - fi - failNotEquals "${shunit_message_}" "$1" "$2" - shunit_return=$? - - unset shunit_message_ - return ${shunit_return} -} -# shellcheck disable=SC2016,SC2034 -_FAIL_NOT_SAME_='eval failNotSame --lineno "${LINENO:-}"' - -#----------------------------------------------------------------------------- -# Skipping functions. -# - -# Force remaining assert and fail functions to be "skipped". -# -# This function forces the remaining assert and fail functions to be "skipped", -# i.e. they will have no effect. Each function skipped will be recorded so that -# the total of asserts and fails will not be altered. -# -# Args: -# None -startSkipping() { __shunit_skip=${SHUNIT_TRUE}; } - -# Resume the normal recording behavior of assert and fail calls. -# -# Args: -# None -endSkipping() { __shunit_skip=${SHUNIT_FALSE}; } - -# Returns the state of assert and fail call skipping. -# -# Args: -# None -# Returns: -# boolean: (TRUE/FALSE constant) -isSkipping() { return ${__shunit_skip}; } - -#----------------------------------------------------------------------------- -# Suite functions. -# - -# Stub. This function should contains all unit test calls to be made. -# -# DEPRECATED (as of 2.1.0) -# -# This function can be optionally overridden by the user in their test suite. -# -# If this function exists, it will be called when shunit2 is sourced. If it -# does not exist, shunit2 will search the parent script for all functions -# beginning with the word 'test', and they will be added dynamically to the -# test suite. -# -# This function should be overridden by the user in their unit test suite. -# Note: see _shunit_mktempFunc() for actual implementation -# -# Args: -# None -#suite() { :; } # DO NOT UNCOMMENT THIS FUNCTION - -# Adds a function name to the list of tests schedule for execution. -# -# This function should only be called from within the suite() function. -# -# Args: -# function: string: name of a function to add to current unit test suite -suite_addTest() { - shunit_func_=${1:-} - - __shunit_suite="${__shunit_suite:+${__shunit_suite} }${shunit_func_}" - __shunit_testsTotal=`expr ${__shunit_testsTotal} + 1` - - unset shunit_func_ -} - -# Stub. This function will be called once before any tests are run. -# -# Common one-time environment preparation tasks shared by all tests can be -# defined here. -# -# This function should be overridden by the user in their unit test suite. -# Note: see _shunit_mktempFunc() for actual implementation -# -# Args: -# None -#oneTimeSetUp() { :; } # DO NOT UNCOMMENT THIS FUNCTION - -# Stub. This function will be called once after all tests are finished. -# -# Common one-time environment cleanup tasks shared by all tests can be defined -# here. -# -# This function should be overridden by the user in their unit test suite. -# Note: see _shunit_mktempFunc() for actual implementation -# -# Args: -# None -#oneTimeTearDown() { :; } # DO NOT UNCOMMENT THIS FUNCTION - -# Stub. This function will be called before each test is run. -# -# Common environment preparation tasks shared by all tests can be defined here. -# -# This function should be overridden by the user in their unit test suite. -# Note: see _shunit_mktempFunc() for actual implementation -# -# Args: -# None -#setUp() { :; } # DO NOT UNCOMMENT THIS FUNCTION - -# Note: see _shunit_mktempFunc() for actual implementation -# Stub. This function will be called after each test is run. -# -# Common environment cleanup tasks shared by all tests can be defined here. -# -# This function should be overridden by the user in their unit test suite. -# Note: see _shunit_mktempFunc() for actual implementation -# -# Args: -# None -#tearDown() { :; } # DO NOT UNCOMMENT THIS FUNCTION - -#------------------------------------------------------------------------------ -# Internal shUnit2 functions. -# - -# Create a temporary directory to store various run-time files in. -# -# This function is a cross-platform temporary directory creation tool. Not all -# OSes have the `mktemp` function, so one is included here. -# -# Args: -# None -# Outputs: -# string: the temporary directory that was created -_shunit_mktempDir() { - # Try the standard `mktemp` function. - ( exec mktemp -dqt shunit.XXXXXX 2>/dev/null ) && return - - # The standard `mktemp` didn't work. Use our own. - # shellcheck disable=SC2039 - if \[ -r '/dev/urandom' -a -x '/usr/bin/od' ]; then - _shunit_random_=`/usr/bin/od -vAn -N4 -tx4 "${_shunit_file_}" -#! /bin/sh -exit ${SHUNIT_TRUE} -EOF - \chmod +x "${_shunit_file_}" - done - - unset _shunit_file_ -} - -# Final cleanup function to leave things as we found them. -# -# Besides removing the temporary directory, this function is in charge of the -# final exit code of the unit test. The exit code is based on how the script -# was ended (e.g. normal exit, or via Ctrl-C). -# -# Args: -# name: string: name of the trap called (specified when trap defined) -_shunit_cleanup() { - _shunit_name_=$1 - - case ${_shunit_name_} in - EXIT) _shunit_signal_=0 ;; - INT) _shunit_signal_=2 ;; - TERM) _shunit_signal_=15 ;; - *) - _shunit_error "unrecognized trap value (${_shunit_name_})" - _shunit_signal_=0 - ;; - esac - - # Do our work. - \rm -fr "${__shunit_tmpDir}" - - # Exit for all non-EXIT signals. - if \[ "${_shunit_name_}" != 'EXIT' ]; then - _shunit_warn "trapped and now handling the (${_shunit_name_}) signal" - # Disable EXIT trap. - trap 0 - # Add 128 to signal and exit. - exit "`expr "${_shunit_signal_}" + 128`" - elif \[ ${__shunit_reportGenerated} -eq ${SHUNIT_FALSE} ] ; then - _shunit_assertFail 'Unknown failure encountered running a test' - _shunit_generateReport - exit ${SHUNIT_ERROR} - fi - - unset _shunit_name_ _shunit_signal_ -} - -# configureOutput based on user preferences, e.g. color. -# -# Args: -# color: string: color mode (one of `always`, `auto`, or `none`). -_shunit_configureColor() { - _shunit_color_=${SHUNIT_FALSE} # By default, no color. - case $1 in - 'always') _shunit_color_=${SHUNIT_TRUE} ;; - 'auto') - ( exec tput >/dev/null 2>&1 ) # Check for existence of tput command. - if [ $? -lt 127 ]; then - _shunit_tput_=`tput colors` - # shellcheck disable=SC2166,SC2181 - [ $? -eq 0 -a "${_shunit_tput_}" -ge 16 ] && _shunit_color_=${SHUNIT_TRUE} - fi - ;; - 'none') ;; - *) _shunit_fatal "unrecognized SHUNIT_COLOR option '${SHUNIT_COLOR}'" ;; - esac - - case ${_shunit_color_} in - ${SHUNIT_TRUE}) - __shunit_ansi_none=${__SHUNIT_ANSI_NONE} - __shunit_ansi_red=${__SHUNIT_ANSI_RED} - __shunit_ansi_green=${__SHUNIT_ANSI_GREEN} - __shunit_ansi_yellow=${__SHUNIT_ANSI_YELLOW} - __shunit_ansi_cyan=${__SHUNIT_ANSI_CYAN} - ;; - ${SHUNIT_FALSE}) - __shunit_ansi_none='' - __shunit_ansi_red='' - __shunit_ansi_green='' - __shunit_ansi_yellow='' - __shunit_ansi_cyan='' - ;; - esac - - unset _shunit_color_ _shunit_tput_ -} - -# The actual running of the tests happens here. -# -# Args: -# None -_shunit_execSuite() { - for _shunit_test_ in ${__shunit_suite}; do - __shunit_testSuccess=${SHUNIT_TRUE} - - # disable skipping - endSkipping - - # execute the per-test setup function - setUp - - # execute the test - echo "${_shunit_test_}" - eval "${_shunit_test_}" - - # execute the per-test tear-down function - tearDown - - # update stats - if \[ ${__shunit_testSuccess} -eq ${SHUNIT_TRUE} ]; then - __shunit_testsPassed=`expr ${__shunit_testsPassed} + 1` - else - __shunit_testsFailed=`expr ${__shunit_testsFailed} + 1` - fi - done - - unset _shunit_test_ -} - -# Generates the user friendly report with appropriate OK/FAILED message. -# -# Args: -# None -# Output: -# string: the report of successful and failed tests, as well as totals. -_shunit_generateReport() { - _shunit_ok_=${SHUNIT_TRUE} - - # If no exit code was provided one, determine an appropriate one. - \[ "${__shunit_testsFailed}" -gt 0 \ - -o ${__shunit_testSuccess} -eq ${SHUNIT_FALSE} ] \ - && _shunit_ok_=${SHUNIT_FALSE} - - echo - _shunit_msg_="Ran ${__shunit_ansi_cyan}${__shunit_testsTotal}${__shunit_ansi_none}" - if \[ "${__shunit_testsTotal}" -eq 1 ]; then - ${__SHUNIT_CMD_ECHO_ESC} "${_shunit_msg_} test." - else - ${__SHUNIT_CMD_ECHO_ESC} "${_shunit_msg_} tests." - fi - - _shunit_failures_='' - _shunit_skipped_='' - \[ ${__shunit_assertsFailed} -gt 0 ] \ - && _shunit_failures_="failures=${__shunit_assertsFailed}" - \[ ${__shunit_assertsSkipped} -gt 0 ] \ - && _shunit_skipped_="skipped=${__shunit_assertsSkipped}" - - if \[ ${_shunit_ok_} -eq ${SHUNIT_TRUE} ]; then - _shunit_msg_="${__shunit_ansi_green}OK${__shunit_ansi_none}" - \[ -n "${_shunit_skipped_}" ] \ - && _shunit_msg_="${_shunit_msg_} (${__shunit_ansi_yellow}${_shunit_skipped_}${__shunit_ansi_none})" - else - _shunit_msg_="${__shunit_ansi_red}FAILED${__shunit_ansi_none}" - _shunit_msg_="${_shunit_msg_} (${__shunit_ansi_red}${_shunit_failures_}${__shunit_ansi_none}" - \[ -n "${_shunit_skipped_}" ] \ - && _shunit_msg_="${_shunit_msg_},${__shunit_ansi_yellow}${_shunit_skipped_}${__shunit_ansi_none}" - _shunit_msg_="${_shunit_msg_})" - fi - - echo - ${__SHUNIT_CMD_ECHO_ESC} "${_shunit_msg_}" - __shunit_reportGenerated=${SHUNIT_TRUE} - - unset _shunit_failures_ _shunit_msg_ _shunit_ok_ _shunit_skipped_ -} - -# Test for whether a function should be skipped. -# -# Args: -# None -# Returns: -# boolean: whether the test should be skipped (TRUE/FALSE constant) -_shunit_shouldSkip() { - \[ ${__shunit_skip} -eq ${SHUNIT_FALSE} ] && return ${SHUNIT_FALSE} - _shunit_assertSkip -} - -# Records a successful test. -# -# Args: -# None -_shunit_assertPass() { - __shunit_assertsPassed=`expr ${__shunit_assertsPassed} + 1` - __shunit_assertsTotal=`expr ${__shunit_assertsTotal} + 1` -} - -# Records a test failure. -# -# Args: -# message: string: failure message to provide user -_shunit_assertFail() { - __shunit_testSuccess=${SHUNIT_FALSE} - __shunit_assertsFailed=`expr "${__shunit_assertsFailed}" + 1` - __shunit_assertsTotal=`expr "${__shunit_assertsTotal}" + 1` - - \[ $# -gt 0 ] && ${__SHUNIT_CMD_ECHO_ESC} \ - "${__shunit_ansi_red}ASSERT:${__shunit_ansi_none}$*" -} - -# Records a skipped test. -# -# Args: -# None -_shunit_assertSkip() { - __shunit_assertsSkipped=`expr "${__shunit_assertsSkipped}" + 1` - __shunit_assertsTotal=`expr "${__shunit_assertsTotal}" + 1` -} - -# Prepare a script filename for sourcing. -# -# Args: -# script: string: path to a script to source -# Returns: -# string: filename prefixed with ./ (if necessary) -_shunit_prepForSourcing() { - _shunit_script_=$1 - case "${_shunit_script_}" in - /*|./*) echo "${_shunit_script_}" ;; - *) echo "./${_shunit_script_}" ;; - esac - unset _shunit_script_ -} - -# Escape a character in a string. -# -# Args: -# c: string: unescaped character -# s: string: to escape character in -# Returns: -# string: with escaped character(s) -_shunit_escapeCharInStr() { - \[ -n "$2" ] || return # No point in doing work on an empty string. - - # Note: using shorter variable names to prevent conflicts with - # _shunit_escapeCharactersInString(). - _shunit_c_=$1 - _shunit_s_=$2 - - - # Escape the character. - # shellcheck disable=SC1003,SC2086 - echo ''${_shunit_s_}'' |sed 's/\'${_shunit_c_}'/\\\'${_shunit_c_}'/g' - - unset _shunit_c_ _shunit_s_ -} - -# Escape a character in a string. -# -# Args: -# str: string: to escape characters in -# Returns: -# string: with escaped character(s) -_shunit_escapeCharactersInString() { - \[ -n "$1" ] || return # No point in doing work on an empty string. - - _shunit_str_=$1 - - # Note: using longer variable names to prevent conflicts with - # _shunit_escapeCharInStr(). - for _shunit_char_ in '"' '$' "'" '`'; do - _shunit_str_=`_shunit_escapeCharInStr "${_shunit_char_}" "${_shunit_str_}"` - done - - echo "${_shunit_str_}" - unset _shunit_char_ _shunit_str_ -} - -# Extract list of functions to run tests against. -# -# Args: -# script: string: name of script to extract functions from -# Returns: -# string: of function names -_shunit_extractTestFunctions() { - _shunit_script_=$1 - - # Extract the lines with test function names, strip of anything besides the - # function name, and output everything on a single line. - _shunit_regex_='^[ ]*(function )*test[A-Za-z0-9_]* *\(\)' - # shellcheck disable=SC2196 - egrep "${_shunit_regex_}" "${_shunit_script_}" \ - |sed 's/^[^A-Za-z0-9_]*//;s/^function //;s/\([A-Za-z0-9_]*\).*/\1/g' \ - |xargs - - unset _shunit_regex_ _shunit_script_ -} - -#------------------------------------------------------------------------------ -# Main. -# - -# Determine the operating mode. -if \[ $# -eq 0 ]; then - __shunit_script=${__SHUNIT_PARENT} - __shunit_mode=${__SHUNIT_MODE_SOURCED} -else - __shunit_script=$1 - \[ -r "${__shunit_script}" ] || \ - _shunit_fatal "unable to read from ${__shunit_script}" - __shunit_mode=${__SHUNIT_MODE_STANDALONE} -fi - -# Create a temporary storage location. -__shunit_tmpDir=`_shunit_mktempDir` - -# Provide a public temporary directory for unit test scripts. -# TODO(kward): document this. -SHUNIT_TMPDIR="${__shunit_tmpDir}/tmp" -\mkdir "${SHUNIT_TMPDIR}" - -# Setup traps to clean up after ourselves. -trap '_shunit_cleanup EXIT' 0 -trap '_shunit_cleanup INT' 2 -trap '_shunit_cleanup TERM' 15 - -# Create phantom functions to work around issues with Cygwin. -_shunit_mktempFunc -PATH="${__shunit_tmpDir}:${PATH}" - -# Make sure phantom functions are executable. This will bite if `/tmp` (or the -# current `$TMPDIR`) points to a path on a partition that was mounted with the -# 'noexec' option. The noexec command was created with `_shunit_mktempFunc()`. -noexec 2>/dev/null || _shunit_fatal \ - 'Please declare TMPDIR with path on partition with exec permission.' - -# We must manually source the tests in standalone mode. -if \[ "${__shunit_mode}" = "${__SHUNIT_MODE_STANDALONE}" ]; then - # shellcheck disable=SC1090 - . "`_shunit_prepForSourcing \"${__shunit_script}\"`" -fi - -# Configure default output coloring behavior. -_shunit_configureColor "${SHUNIT_COLOR}" - -# Execute the oneTimeSetUp function (if it exists). -oneTimeSetUp - -# Execute the suite function defined in the parent test script. -# DEPRECATED as of 2.1.0. -suite - -# If no suite function was defined, dynamically build a list of functions. -if \[ -z "${__shunit_suite}" ]; then - shunit_funcs_=`_shunit_extractTestFunctions "${__shunit_script}"` - for shunit_func_ in ${shunit_funcs_}; do - suite_addTest "${shunit_func_}" - done -fi -unset shunit_func_ shunit_funcs_ - -_shunit_execSuite -oneTimeTearDown -_shunit_generateReport - -# That's it folks. -\[ "${__shunit_testsFailed}" -eq 0 ] -exit $? diff --git a/test/shunit2-init.sh b/test/shunit2-init.sh deleted file mode 100644 index 68c42ca..0000000 --- a/test/shunit2-init.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -oneTimeSetUp() { - . ../src/fun.sh -} - -# Load shUnit2. -. ./shunit2 \ No newline at end of file diff --git a/test/tail_test.sh b/test/tail_test.sh deleted file mode 100755 index f6c11e6..0000000 --- a/test/tail_test.sh +++ /dev/null @@ -1,15 +0,0 @@ -#! /bin/bash - -testLTailFrom10() { - assertEquals "2 3 4 5 6 7 8 9 10" "$(list {1..10} | list_tail | unlist)" -} - -testLTailFromOneElementList() { - assertEquals "" "$(list 1 | list_tail)" -} - -testLTailFromEmptyList() { - assertEquals "" "$(list | list_tail)" -} - -. ./shunit2-init.sh diff --git a/test/take_test.sh b/test/take_test.sh deleted file mode 100755 index 5b0cb49..0000000 --- a/test/take_test.sh +++ /dev/null @@ -1,23 +0,0 @@ -#! /bin/bash - -testTake9From10() { - assertEquals "1 2 3 4 5 6 7 8 9" "$(list {1..10} | list_take 9 | unlist)" -} - -testTake8From10() { - assertEquals "1 2 3 4 5 6 7 8" "$(list {1..10} | list_take 8 | unlist)" -} - -testTakeAll() { - assertEquals "1 2 3 4 5 6 7 8 9 10" "$(list {1..10} | list_take 10 | unlist)" -} - -testTakeMoreThanAvailable() { - assertEquals "1 2 3 4 5 6 7 8 9 10" "$(list {1..10} | list_take 15 | unlist)" -} - -testTakeZero() { - assertEquals "" "$(list {1..10} | list_take 0 | unlist)" -} - -. ./shunit2-init.sh \ No newline at end of file diff --git a/test/test_runner b/test/test_runner deleted file mode 100755 index 441fb4e..0000000 --- a/test/test_runner +++ /dev/null @@ -1,163 +0,0 @@ -#! /bin/sh -# vim:et:ft=sh:sts=2:sw=2 -# -# Unit test suite runner. -# -# Copyright 2008-2017 Kate Ward. All Rights Reserved. -# Released under the Apache 2.0 license. -# -# Author: kate.ward@forestent.com (Kate Ward) -# https://github.com/kward/shlib -# -# This script runs all the unit tests that can be found, and generates a nice -# report of the tests. -# -### ShellCheck (http://www.shellcheck.net/) -# Disable source following. -# shellcheck disable=SC1090,SC1091 -# expr may be antiquated, but it is the only solution in some cases. -# shellcheck disable=SC2003 - -# Return if test_runner already loaded. -[ -z "${RUNNER_LOADED:-}" ] || return 0 -RUNNER_LOADED=0 - -RUNNER_ARGV0=$(basename "$0") -RUNNER_SHELLS='/bin/bash' -RUNNER_TEST_SUFFIX='_test.sh' - -runner_warn() { echo "runner:WARN $*" >&2; } -runner_error() { echo "runner:ERROR $*" >&2; } -runner_fatal() { echo "runner:FATAL $*" >&2; exit 1; } - -runner_usage() { - echo "usage: ${RUNNER_ARGV0} [-e key=val ...] [-s shell(s)] [-t test(s)]" -} - -_runner_tests() { echo ./*${RUNNER_TEST_SUFFIX} |sed 's#./##g'; } -_runner_testName() { - # shellcheck disable=SC1117 - _runner_testName_=$(expr "${1:-}" : "\(.*\)${RUNNER_TEST_SUFFIX}") - if [ -n "${_runner_testName_}" ]; then - echo "${_runner_testName_}" - else - echo 'unknown' - fi - unset _runner_testName_ -} - -main() { - # Find and load versions library. - for _runner_dir_ in . ${LIB_DIR:-lib}; do - if [ -r "${_runner_dir_}/versions" ]; then - _runner_lib_dir_="${_runner_dir_}" - break - fi - done - [ -n "${_runner_lib_dir_}" ] || runner_fatal 'Unable to find versions library.' - . "${_runner_lib_dir_}/versions" || runner_fatal 'Unable to load versions library.' - unset _runner_dir_ _runner_lib_dir_ - - # Process command line flags. - env='' - while getopts 'e:hs:t:' opt; do - case ${opt} in - e) # set an environment variable - key=$(expr "${OPTARG}" : '\([^=]*\)=') - val=$(expr "${OPTARG}" : '[^=]*=\(.*\)') - # shellcheck disable=SC2166 - if [ -z "${key}" -o -z "${val}" ]; then - runner_usage - exit 1 - fi - eval "${key}='${val}'" - eval "export ${key}" - env="${env:+${env} }${key}" - ;; - h) runner_usage; exit 0 ;; # help output - s) shells=${OPTARG} ;; # list of shells to run - t) tests=${OPTARG} ;; # list of tests to run - *) runner_usage; exit 1 ;; - esac - done - shift "$(expr ${OPTIND} - 1)" - - # Fill shells and/or tests. - shells=${shells:-${RUNNER_SHELLS}} - tests=${tests:-$(_runner_tests)} - - # Error checking. - if [ -z "${tests}" ]; then - runner_error 'no tests found to run; exiting' - exit 1 - fi - - cat <&1; ) - done - done -} - -# Execute main() if this is run in standalone mode (i.e. not from a unit test). -[ -z "${SHUNIT_VERSION}" ] && main "$@" diff --git a/test/tup_test.sh b/test/tup_test.sh deleted file mode 100755 index 71f1b05..0000000 --- a/test/tup_test.sh +++ /dev/null @@ -1,40 +0,0 @@ -#! /bin/bash - -testTupIfEmpty() { - assertEquals '()' $(tup '') -} - -testTupIfOneElement() { - assertEquals '(1)' $(tup 1) - assertEquals '(")' $(tup '"') - assertEquals "(')" $(tup "'") - assertEquals "(,)" $(tup ",") - assertEquals "(,,)" $(tup ",,") - assertEquals "(()" $(tup "(") - assertEquals "())" $(tup ")") -} - -testTupHappyPath() { - assertEquals '(1,2,3,4,5)' $(tup 1 2 3 4 5) - assertEquals '(a-1,b-2,c-3)' $(tup 'a-1' 'b-2' 'c-3') - assertEquals '(a b,c d e,f)' "$(tup 'a b' 'c d e' 'f')" -} - -testTupxIfZeroIndex() { - assertEquals '' "$(tup 1 3 | tupx 0 2>/dev/null)" -} - -testTupl() { - assertEquals '4' "$(tup 4 5 | tupl)" - assertEquals '4' "$(tup 4 5 6 | tupl)" - assertEquals '6' "$(tup 6 | tupl)" - assertEquals 'foo bar' "$(tup 'foo bar' 1 'one' 2 | tupl)" -} - -testTupr() { - assertEquals '5' "$(tup 4 5 | tupr)" - assertEquals '5' "$(tup 1 4 5 | tupr)" - assertEquals '5' "$(tup 5 | tupr)" -} - -. ./shunit2-init.sh diff --git a/test/unlist_test.sh b/test/unlist_test.sh deleted file mode 100755 index 235f344..0000000 --- a/test/unlist_test.sh +++ /dev/null @@ -1,21 +0,0 @@ -#! /bin/bash - -testUnlistFromList() { - list=$(cat <