diff options
author | Dave Reisner <dreisner@archlinux.org> | 2012-04-08 12:32:17 -0400 |
---|---|---|
committer | Dan McGee <dan@archlinux.org> | 2012-04-24 08:38:36 -0500 |
commit | 8679cd68d825bfe28ba0c833494c415bcfa6d8f6 (patch) | |
tree | 2da70a05c56a457262a4ff68446c788d3829131b /test | |
parent | 1eb6a9cbfef4f0ad5151b4850d81141b7a535be6 (diff) | |
download | pacman-8679cd68d825bfe28ba0c833494c415bcfa6d8f6.tar.xz |
scripts/library: introduce parseopts
This will replace our current options parser used in pacman-key,
makepkg, and ideally elsewhere. It follows heuristics closer to that of
GNU getopt long (and thus pacman itself), with the exception that it
does not allow for options with optional arguments. Due to the way this
parser will be used, this sort of functionality will not be needed.
Instead of relying on eval+set, options are normalized into an array,
OPTRET, which callers should expect to be populated after returning from
parseopts. This avoids problems with quotes and spaces in arguments,
assuming that the user quotes properly when passing into the
application.
A new test harness for parseopts is added in test/scripts.
Signed-off-by: Dave Reisner <dreisner@archlinux.org>
Diffstat (limited to 'test')
-rw-r--r-- | test/scripts/Makefile.am | 9 | ||||
-rwxr-xr-x | test/scripts/parseopts_test.sh | 138 |
2 files changed, 147 insertions, 0 deletions
diff --git a/test/scripts/Makefile.am b/test/scripts/Makefile.am new file mode 100644 index 00000000..b949e880 --- /dev/null +++ b/test/scripts/Makefile.am @@ -0,0 +1,9 @@ +check_SCRIPTS = \ + parseopts_test.sh + +noinst_SCRIPTS = $(check_SCRIPTS) + +EXTRA_DIST = \ + $(check_SCRIPTS) + +# vim:set ts=2 sw=2 noet: diff --git a/test/scripts/parseopts_test.sh b/test/scripts/parseopts_test.sh new file mode 100755 index 00000000..b5c07b5d --- /dev/null +++ b/test/scripts/parseopts_test.sh @@ -0,0 +1,138 @@ +#!/bin/bash + +declare -i testcount=0 pass=0 fail=0 + +# source the library function +if [[ -z $1 || ! -f $1 ]]; then + printf "error: path to parseopts library not provided or does not exist\n" + exit 1 +fi +. "$1" + +if ! type -t parseopts >/dev/null; then + printf 'parseopts function not found\n' + exit 1 +fi + +# borrow opts from makepkg +OPT_SHORT="AcdefFghiLmop:rRsV" +OPT_LONG=('allsource' 'asroot' 'ignorearch' 'check' 'clean:' 'cleanall' 'nodeps' + 'noextract' 'force' 'forcever:' 'geninteg' 'help' 'holdver' + 'install' 'key:' 'log' 'nocolor' 'nobuild' 'nocheck' 'nosign' 'pkg:' 'rmdeps' + 'repackage' 'skipinteg' 'sign' 'source' 'syncdeps' 'version' 'config:' + 'noconfirm' 'noprogressbar') + +parse() { + local result=$1 tokencount=$2; shift 2 + + (( ++testcount )) + parseopts "$OPT_SHORT" "${OPT_LONG[@]}" -- "$@" 2>/dev/null + test_result "$result" "$tokencount" "$*" "${OPTRET[@]}" + unset OPTRET +} + +test_result() { + local result=$1 tokencount=$2 input=$3; shift 3 + + if [[ $result = "$*" ]] && (( tokencount == $# )); then + (( ++pass )) + else + printf '[TEST %3s]: FAIL\n' "$testcount" + printf ' input: %s\n' "$input" + printf ' output: %s (%s tokens)\n' "$*" "$#" + printf ' expected: %s (%s tokens)\n' "$result" "$tokencount" + echo + (( ++fail )) + fi +} + +summarize() { + if (( !fail )); then + printf 'All %s tests successful\n' "$testcount" + exit 0 + else + printf '%s of %s tests failed\n' "$fail" "$testcount" + exit 1 + fi +} +trap 'summarize' EXIT + +printf 'Beginning parseopts tests\n' + +# usage: parse <expected result> <token count> test-params... +# a failed parse will match only the end of options marker '--' + +# no options +parse '--' 1 + +# short options +parse '-s -r --' 3 -s -r + +# short options, no spaces +parse '-s -r --' 3 -sr + +# short opt missing an opt arg +parse '--' 1 -s -p + +# short opt with an opt arg +parse '-p PKGBUILD -L --' 4 -p PKGBUILD -L + +# short opt with an opt arg, no space +parse '-p PKGBUILD --' 3 -pPKGBUILD + +# valid shortopts as a long opt +parse '--' 1 --sir + +# long opt wiht no optarg +parse '--log --' 2 --log + +# long opt with missing optarg +parse '--' 1 -sr --pkg + +# long opt with optarg +parse '--pkg foo --' 3 --pkg foo + +# long opt with optarg with whitespace +parse '--pkg foo bar -- baz' 4 --pkg "foo bar" baz + +# long opt with optarg with = +parse '--pkg foo=bar -- baz' 4 --pkg foo=bar baz + +# long opt with explicit optarg +parse '--pkg bar -- foo baz' 5 foo --pkg=bar baz + +# long opt with explicit optarg, with whitespace +parse '--pkg foo bar -- baz' 4 baz --pkg="foo bar" + +# long opt with explicit optarg that doesn't take optarg +parse '--' 1 --force=always -s + +# long opt with explicit optarg with = +parse '--pkg foo=bar --' 3 --pkg=foo=bar + +# explicit end of options with options after +parse '-s -r -- foo bar baz' 6 -s -r -- foo bar baz + +# non-option parameters mixed in with options +parse '-s -r -- foo baz' 5 -s foo baz -r + +# optarg with whitespace +parse '-p foo bar -s --' 4 -p'foo bar' -s + +# non-option parameter with whitespace +parse '-i -- foo bar' 3 -i 'foo bar' + +# successful stem match (opt has no arg) +parse '--nocolor --' 2 --nocol + +# successful stem match (opt has arg) +parse '--config foo --' 3 --conf foo + +# ambiguous long opt +parse '--' 1 '--for' + +# exact match on a possible stem (--force & --forcever) +parse '--force --' 2 --force + +# exact match on possible stem (opt has optarg) +parse '--clean foo --' 3 --clean=foo |