#! /bin/sh # vim:et:ft=sh:sts=2:sw=2 # # shFlags unit test for the flag definition methods # # 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/shflags # ### ShellCheck (http://www.shellcheck.net/) # Disable source following. # shellcheck disable=SC1090,SC1091 # TODO(kward): assert on FLAGS errors # TODO(kward): testNonStandardIFS() # Exit immediately if a pipeline or subshell exits with a non-zero status. #set -e # Treat unset variables as an error. set -u # These variables will be overridden by the test helpers. setvar returnF = ""${TMPDIR:-/tmp}/return"" setvar stdoutF = ""${TMPDIR:-/tmp}/STDOUT"" setvar stderrF = ""${TMPDIR:-/tmp}/STDERR"" # Load test helpers. source ./shflags_test_helpers proc testGetoptStandard { _flags_getoptStandard '-b' >"${stdoutF}" 2>"${stderrF}" setvar rslt = ""$? assertTrue "didn't parse valid flag 'b'" ${rslt} th_showOutput ${rslt} ${stdoutF} ${stderrF} _flags_getoptStandard '-x' >"${stdoutF}" 2>"${stderrF}" assertFalse "parsed invalid flag 'x'" $? } proc testGetoptEnhanced { flags_getoptIsEnh || return _flags_getoptEnhanced '-b' >"${stdoutF}" 2>"${stderrF}" assertTrue "didn't parse valid flag 'b'" $? _flags_getoptEnhanced '--bool' >"${stdoutF}" 2>"${stderrF}" assertTrue "didn't parse valid flag 'bool'" $? _flags_getoptEnhanced '-x' >"${stdoutF}" 2>"${stderrF}" assertFalse "parsed invalid flag 'x'" $? _flags_getoptEnhanced '--xyz' >"${stdoutF}" 2>"${stderrF}" assertFalse "parsed invalid flag 'xyz'" $? } proc testValidBoolsShort { FLAGS -b >"${stdoutF}" 2>"${stderrF}" setvar r3turn = ""$? assertTrue "-b) FLAGS returned a non-zero result (${r3turn})" ${r3turn} setvar value = ${FLAGS_bool:-} assertTrue "-b) boolean was not true (${value})." ${value} assertFalse '-b) expected no output to STDERR' "[ -s '${stderrF}' ]" test ${r3turn} -eq ${FLAGS_TRUE} -a ! -s ${stderrF} th_showOutput $? ${stdoutF} ${stderrF} DEFINE_boolean bool2 true '2nd boolean' B FLAGS >"${stdoutF}" 2>"${stderrF}" setvar r3turn = ""$? assertTrue "-B) FLAGS returned a non-zero result (${r3turn})" ${r3turn} setvar value = ${FLAGS_bool2:-} assertTrue "-B) boolean was not true (${value})" ${value} assertFalse '-B) expected no output to STDERR' "[ -s '${stderrF}' ]" test ${r3turn} -eq ${FLAGS_TRUE} -a ! -s ${stderrF} th_showOutput $? ${stdoutF} ${stderrF} FLAGS -B >"${stdoutF}" 2>"${stderrF}" setvar r3turn = ""$? assertTrue "-B) FLAGS returned a non-zero result (${r3turn})" ${r3turn} setvar value = ${FLAGS_bool2:-} assertFalse "-B) boolean was not false (${value})" ${value} assertFalse '-B) expected no output to STDERR' "[ -s '${stderrF}' ]" test ${r3turn} -eq ${FLAGS_TRUE} -a ! -s ${stderrF} th_showOutput $? ${stdoutF} ${stderrF} } # TODO(kate): separate into multiple functions to reflect correct usage proc testValidBoolsLong { flags_getoptIsEnh || return # Note: the default value of bool is 'false'. # Leave flag false. FLAGS --nobool >"${stdoutF}" 2>"${stderrF}" setvar r3turn = ""$? assertTrue "FLAGS returned a non-zero result (${r3turn})" ${r3turn} assertFalse '--noXX flag resulted in true value.' ${FLAGS_bool:-} assertFalse 'expected no output to STDERR' "[ -s '${stderrF}' ]" th_showOutput ${r3turn} ${stdoutF} ${stderrF} # Flip flag true. FLAGS --bool >"${stdoutF}" 2>"${stderrF}" setvar r3turn = ""$? assertTrue "FLAGS returned a non-zero result (${r3turn})" ${r3turn} assertTrue '--XX flag resulted in false value.' ${FLAGS_bool:-} assertFalse 'expected no output to STDERR' "[ -s '${stderrF}' ]" th_showOutput ${r3turn} ${stdoutF} ${stderrF} # Flip flag back false. FLAGS --nobool >"${stdoutF}" 2>"${stderrF}" setvar r3turn = ""$? assertTrue "FLAGS returned a non-zero result (${r3turn})" ${r3turn} assertFalse '--noXX flag resulted in true value.' ${FLAGS_bool:-} assertFalse 'expected no output to STDERR' "[ -s '${stderrF}' ]" th_showOutput ${r3turn} ${stdoutF} ${stderrF} } proc testValidFloats { _testValidFloats '-f' flags_getoptIsEnh || return _testValidFloats '--float' } proc _testValidFloats { setvar flag = "$1" for value in ${TH_FLOAT_VALID} { FLAGS ${flag} ${value} >"${stdoutF}" 2>"${stderrF}" setvar r3turn = ""$? assertTrue "FLAGS ${flag} ${value} returned non-zero result (${r3turn})" \ ${r3turn} # shellcheck disable=SC2154 assertEquals "float (${flag} ${value}) test failed." ${value} ${FLAGS_float} assertFalse 'expected no output to STDERR' "[ -s '${stderrF}' ]" th_showOutput ${r3turn} ${stdoutF} ${stderrF} } } proc testInvalidFloats { _testInvalidFloats '-f' flags_getoptIsEnh || return _testInvalidFloats '--float' } proc _testInvalidFloats { setvar flag = "$1" for value in ${TH_FLOAT_INVALID} { th_clearReturn shell { FLAGS ${flag} ${value} >"${stdoutF}" 2>"${stderrF}" echo $? >"${returnF}" } assertFalse "FLAGS (${value}) returned a zero result" $(th_queryReturn) assertFalse 'expected no output to STDOUT' "[ -s '${stdoutF}' ]" assertTrue 'expected output to STDERR' "[ -s '${stderrF}' ]" } } proc testValidIntegers { _testValidIntegers '-i' flags_getoptIsEnh || return _testValidIntegers '--int' } proc _testValidIntegers { setvar flag = "$1" for value in ${TH_INT_VALID} { FLAGS ${flag} ${value} >"${stdoutF}" 2>"${stderrF}" setvar r3turn = ""$? assertTrue "FLAGS (${value}) returned a non-zero result (${r3turn})" ${r3turn} # shellcheck disable=SC2154 assertEquals "integer (${value}) test failed." ${value} ${FLAGS_int} assertFalse 'expected no output to STDERR' "[ -s '${stderrF}' ]" th_showOutput ${r3turn} ${stdoutF} ${stderrF} } } proc testInvalidIntegers { _testInvalidIntegers '-i' flags_getoptIsEnh || return _testInvalidIntegers '--int' } proc _testInvalidIntegers { setvar flag = "$1" for value in ${TH_INT_INVALID} { th_clearReturn shell { FLAGS ${flag} ${value} >"${stdoutF}" 2>"${stderrF}" echo $? >"${returnF}" } assertFalse "invalid integer (${value}) test returned success." $(th_queryReturn) assertFalse 'expected no output to STDOUT' "[ -s '${stdoutF}' ]" assertTrue 'expected output to STDERR' "[ -s '${stderrF}' ]" } } proc testValidStrings { _testValidStrings -s single_word if flags_getoptIsEnh { _testValidStrings --str single_word _testValidStrings --str 'string with spaces' } } proc _testValidStrings { setvar flag = "$1" setvar value = "$2" FLAGS ${flag} ${value} >"${stdoutF}" 2>"${stderrF}" setvar r3turn = ""$? assertTrue "'FLAGS ${flag} ${value}' returned a non-zero result (${r3turn})" \ ${r3turn} # shellcheck disable=SC2154 assertEquals "string (${value}) test failed." ${value} ${FLAGS_str} if test ${r3turn} -eq ${FLAGS_TRUE} { assertFalse 'expected no output to STDERR' "[ -s '${stderrF}' ]" } else { # Validate that an error is thrown for unsupported getopt uses. assertFatalMsg '.* spaces in options' } th_showOutput ${r3turn} ${stdoutF} ${stderrF} } proc testMultipleFlags { _testMultipleFlags '-b' '-i' '-f' '-s' flags_getoptIsEnh || return _testMultipleFlags '--bool' '--int' '--float' '--str' } proc _testMultipleFlags { setvar boolFlag = "$1" setvar intFlag = "$2" setvar floatFlag = "$3" setvar strFlag = "$4" FLAGS \ ${boolFlag} \ ${intFlag} 567 \ ${floatFlag} 123.45678 \ ${strFlag} 'some_string' \ >"${stdoutF}" 2>"${stderrF}" setvar r3turn = ""$? assertTrue "use of multiple flags returned a non-zero result" ${r3turn} assertTrue 'boolean test failed.' ${FLAGS_bool} assertNotSame 'float test failed.' 0 ${FLAGS_float} assertNotSame 'integer test failed.' 0 ${FLAGS_int} assertNotSame 'string test failed.' '' ${FLAGS_str} assertFalse 'expected no output to STDERR' "[ -s '${stderrF}' ]" th_showOutput ${r3turn} ${stdoutF} ${stderrF} } proc _testNonFlagArgs { setvar argc = "$1" shift FLAGS @ARGV >"${stdoutF}" 2>"${stderrF}" setvar r3turn = ""$? assertTrue 'parse returned non-zero value.' ${r3turn} th_showOutput ${r3turn} ${stdoutF} ${stderrF} eval set -- ${FLAGS_ARGV} assertEquals 'wrong count of argv arguments returned.' ${argc} $Argc assertEquals 'wrong count of argc arguments returned.' 0 ${FLAGS_ARGC} } proc testSingleNonFlagArg { _testNonFlagArgs 1 argOne } proc testMultipleNonFlagArgs { _testNonFlagArgs 3 argOne argTwo arg3 } proc testMultipleNonFlagStringArgsWithSpaces { flags_getoptIsEnh || return _testNonFlagArgs 3 argOne 'arg two' arg3 } proc testFlagsWithEquals { flags_getoptIsEnh || return FLAGS --str='str_flag' 'non_flag' >"${stdoutF}" 2>"${stderrF}" assertTrue 'FLAGS returned a non-zero result' $? assertEquals 'string flag not set properly' 'str_flag' ${FLAGS_str} th_showOutput ${r3turn} ${stdoutF} ${stderrF} eval set -- ${FLAGS_ARGV} assertEquals 'wrong count of argv arguments returned.' 1 $Argc assertEquals 'wrong count of argc arguments returned.' 1 ${FLAGS_ARGC} } proc testComplicatedCommandLineStandard { flags_getoptIsEnh && return # Note: standard getopt stops parsing after first non-flag argument, which # results in the remaining flags being treated as arguments instead. FLAGS -i 1 non_flag_1 -s 'two' non_flag_2 -f 3 non_flag_3 \ >"${stdoutF}" 2>"${stderrF}" setvar r3turn = ""$? assertTrue 'FLAGS returned a non-zero result' ${r3turn} assertEquals 'failed int test' 1 ${FLAGS_int} th_showOutput ${r3turn} ${stdoutF} ${stderrF} eval set -- ${FLAGS_ARGV} assertEquals 'incorrect number of argv values' 7 $Argc } proc testComplicatedCommandLineEnhanced { flags_getoptIsEnh || return FLAGS -i 1 non_flag_1 --str='two' non_flag_2 --float 3 'non flag 3' \ >"${stdoutF}" 2>"${stderrF}" setvar r3turn = ""$? assertTrue 'FLAGS returned a non-zero result' ${r3turn} assertEquals 'failed int test' 1 ${FLAGS_int} assertEquals 'failed str test' 'two' ${FLAGS_str} assertEquals 'failed float test' 3 ${FLAGS_float} th_showOutput ${r3turn} ${stdoutF} ${stderrF} eval set -- ${FLAGS_ARGV} assertEquals 'incorrect number of argv values' 3 $Argc } proc oneTimeSetUp { th_oneTimeSetUp if flags_getoptIsStd { th_warn 'Standard version of getopt found. Enhanced tests will be skipped.' } else { th_warn 'Enhanced version of getopt found. Standard tests will be skipped.' } } proc setUp { DEFINE_boolean bool false 'boolean test' 'b' DEFINE_float float 0.0 'float test' 'f' DEFINE_integer int 0 'integer test' 'i' DEFINE_string str '' 'string test' 's' } proc tearDown { flags_reset } # Load and run shUnit2. # shellcheck disable=SC2034 test -n ${ZSH_VERSION:-} && setvar SHUNIT_PARENT = "$0" source "${TH_SHUNIT}"