Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev #26

Open
wants to merge 23 commits into
base: master
Choose a base branch
from
Open

Dev #26

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
8ca07fc
Fix a bug: the parser signals unknown-option for --option when there …
xaxo05 Feb 8, 2019
6e4afde
replace otherwise with t
xaxo05 Feb 11, 2019
767ab3d
Fix command line argument retrieval for Allegro CL
hineios Jan 8, 2020
6c72ab9
- changed alignment of options in descriptions.
Apr 19, 2020
9041fb8
travis should check for ecl
digikar99 May 3, 2020
b570f44
travis change from luismbo/cl-travis to sionescu/cl-travis
digikar99 May 3, 2020
114452c
travis added lib(32)stdc++-7-dev from ubuntu-toolchain-r-test
digikar99 May 3, 2020
1841db8
travis allow failure for ccl32
digikar99 May 3, 2020
9f6ae6e
travis: build status image link update
digikar99 May 22, 2020
1de2e52
using fiveam for testing; added a failing test
digikar99 May 22, 2020
7e7a6f0
travis: disable all except sbcl; load using quicklisp
digikar99 May 22, 2020
b18121c
fiveam: set debug-on-failure debug-on-error to t
digikar99 May 22, 2020
16ba2ef
removed failing case: ls --alm works
digikar99 May 22, 2020
94b4f98
Merge branch 'master' into dev; added ambiguous-option
digikar99 May 22, 2020
543da69
Merge remote-tracking branch 'cage2/improve-align' into dev
digikar99 May 22, 2020
b7a347d
Merge remote-tracking branch 'heneios/master' into dev
digikar99 May 22, 2020
be82a26
added expand-opts https://github.com/libre-man/unix-opts/issues/19
digikar99 May 22, 2020
8f5ea05
unused fiveam and local-nicknames: some impl still do not support
digikar99 May 22, 2020
2bc4d18
unused in-order-to and perform and uiop
digikar99 May 22, 2020
ca3f3d3
get-opts uses options if option-supplied-p
digikar99 May 23, 2020
7f52367
added default https://github.com/libre-man/unix-opts/issues/17
digikar99 May 23, 2020
5cfb260
exported troublesome-option https://github.com/libre-man/unix-opts/is…
digikar99 May 23, 2020
e7e3820
readme build status
digikar99 May 23, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
*.fas
*.fasl
*~
*.o
\#*
27 changes: 20 additions & 7 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
language: lisp
sudo: required

addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- libstdc++-7-dev
- lib32stdc++-7-dev

env:
matrix:
- LISP=abcl
Expand All @@ -10,21 +18,26 @@ env:
- LISP=ccl32
- LISP=clisp
- LISP=clisp32
- LISP=ecl
- LISP=allegro

matrix:
allow_failures:
- env: LISP=ccl32 # issue filed at https://github.com/Clozure/ccl/issues/304

install:
- if [ -x ./install.sh ] && head -2 ./install.sh | grep '^# cl-travis' > /dev/null;
- # installing cl-travis
if [ -x ./install.sh ] && head -2 ./install.sh | grep '^# cl-travis' > /dev/null;
then
./install.sh;
else
curl https://raw.githubusercontent.com/luismbo/cl-travis/master/install.sh | sh;
curl https://raw.githubusercontent.com/sionescu/cl-travis/master/install.sh | sh;
fi

before_script:
- echo "(defsystem :dummy-cl-travis-system)" > ~/lisp/dummy-cl-travis-system.asd

script:
- cl -e '(asdf:load-system :unix-opts-tests)
(unix-opts:run-tests)'
- cl -e '(ql:quickload :unix-opts)
(ql:quickload :unix-opts/tests)
(unix-opts/tests:run)'
[ $? -eq 1 ]

notifications:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Unix-style command line options parser

[![License MIT](https://img.shields.io/badge/license-MIT-green.svg)](http://opensource.org/licenses/MIT)
[![Build Status](https://travis-ci.org/mrkkrp/unix-opts.svg?branch=master)](https://travis-ci.org/mrkkrp/unix-opts)
[![Build Status](https://travis-ci.org/digikar99/unix-opts.svg?branch=master)](https://travis-ci.com/digikar99/unix-opts.svg?branch=master)
[![Quicklisp](http://quickdocs.org/badge/unix-opts.svg)](http://quickdocs.org/unix-opts/)

This is a minimalistic parser of command line options. The main advantage of
Expand Down
216 changes: 151 additions & 65 deletions tests.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -23,40 +23,47 @@
;;; OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
;;; WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

(in-package #:unix-opts)
(defpackage :unix-opts/tests
(:shadowing-import-from :cl :describe)
(:use :cl :unix-opts)
(:export :run))

(define-opts
(in-package :unix-opts/tests)

(opts:define-opts
(:name :grab-int
:description "grab integer INT"
:short #\i
:long "grab-int"
:required t
:arg-parser #'parse-integer
:meta-var "INT")
:description "grab integer INT"
:short #\i
:long "grab-int"
:required t
:arg-parser #'parse-integer
:meta-var "INT")
(:name :grab-str
:description "grab string STR"
:short #\s
:long "grab-str"
:arg-parser #'identity
:meta-var "STR")
:description "grab string STR"
:short #\s
:long "grab-str"
:arg-parser #'identity
:meta-var "STR")
(:name :grab-string
:description "option to cause ambiguity with grab-str as well as help test the print function of opts:describe due to this long description"
:short #\s
:long "grab-string"
:arg-parser #'identity
:default 42)
(:name :flag-a
:description "flag with short form only"
:short #\a)
:description "flag with short form only"
:short #\a)
(:name :flag-b
:description "flag with long form only"
:long "flag-b"))
:description "flag with long form only"
:long "flag-b"))

;;; Here is some variables that we will use and functions to reset them.

(defparameter *unknown-options* nil
"We collect all unknown options here.")

(defparameter *unknown-options* nil "We collect all unknown options here.")
(defparameter *ambiguous-options* nil "We collect all ambiguous options here.")
(defparameter *missing-arg-options* nil
"Options that need an argument, but don't get one.")

(defparameter *malformed-arguments* nil
"Here we collect malformed arguments.")

(defparameter *malformed-arguments* nil "Here we collect malformed arguments.")
(defparameter *missing-required-options*
"Here we collect missing required options.")

Expand All @@ -77,125 +84,204 @@ aspects of the tests."

;;; The tests themselves.

(defun parse-opts (opts &key unknown-option missing-arg arg-parser-failed missing-required)
(defun parse-opts (opts &key unknown-option missing-arg arg-parser-failed
missing-required ambiguous-option)
"Parse OPTS, return results and collect some data in special variables.
Keyword arguments allow to set arguments for `invoke-restart' function. It's
recommended to supply them all if you don't want to end in the debugger."
(reset-state)
(multiple-value-prog1
(handler-bind
((unknown-option
(lambda (c)
(push (option c) *unknown-options*)
(when unknown-option
(apply #'invoke-restart unknown-option))))
(lambda (c)
(push (option c) *unknown-options*)
(when unknown-option
(apply #'invoke-restart unknown-option))))
(ambiguous-option
(lambda (c)
(push (option c) *ambiguous-options*)
(when ambiguous-option
(apply #'invoke-restart ambiguous-option))))
(missing-arg
(lambda (c)
(push (option c) *missing-arg-options*)
(when missing-arg
(apply #'invoke-restart missing-arg))))
(lambda (c)
(push (option c) *missing-arg-options*)
(when missing-arg
(apply #'invoke-restart missing-arg))))
(missing-required-option
(lambda (c)
(push (mapcar #'name (missing-options c)) *missing-required-options*)
(when missing-required
(apply #'invoke-restart missing-required))))
(lambda (c)
;; TODO: Should we export unix-opts::name?
(push (mapcar #'unix-opts::name (missing-options c)) *missing-required-options*)
(when missing-required
(apply #'invoke-restart missing-required))))
(arg-parser-failed
(lambda (c)
(push (raw-arg c) *malformed-arguments*)
(when arg-parser-failed
(apply #'invoke-restart arg-parser-failed)))))
(lambda (c)
(push (raw-arg c) *malformed-arguments*)
(when arg-parser-failed
(apply #'invoke-restart arg-parser-failed)))))
(get-opts opts))
(finish-collecting)))

(defun run-tests ()
"Run Unix-opts tests. Signal failure if any test fails and return NIL
otherwise."
(assert (typep (argv) 'list))
(defun argv-test ()
(assert (typep (opts:argv) 'list)))

(defun unexpected-options-test ()
(assert (typep (handler-case (opts:get-opts '("--grab-int" "10" "--rere"))
(condition (c) c))
'unknown-option))
(assert (typep (handler-case (opts:get-opts '())
(condition (c) c))
'missing-required-option))
(assert (typep (handler-case (opts:get-opts '("--grab-int" "hello"))
(condition (c) c))
'arg-parser-failed))
(assert (typep (handler-case (opts:get-opts '("--grab-int"))
(condition (c) c))
'missing-arg))
;; TODO: Should we error in the following case?
(assert (typep (handler-case (opts:get-opts '("--grab-int" "10" "-a" "11"))
(condition (c) c))
'list)))

(defun miscelleneous-1 ()
(multiple-value-bind (options free-args)
(parse-opts '("--grab-int" "10" "--rere" "11" "-s" "-a" "foo.txt")
:unknown-option '(skip-option)
:missing-arg '(skip-option)
:arg-parser-failed '(skip-option))
(assert (equalp options '(:grab-int 10 :flag-a t)))
(assert (equalp options '(:grab-int 10 :flag-a t
:grab-string 42)))
(assert (equalp free-args '("11" "foo.txt")))
(assert (equalp *unknown-options* '("--rere")))
(assert (equalp *missing-arg-options* '("-s")))
(assert (equalp *malformed-arguments* nil)))
(assert (equalp *malformed-arguments* nil))))

(defun miscelleneous-2 ()
(multiple-value-bind (options free-args)
(parse-opts '("-asri=13" "--flag-b" "--flag-b" "foo.txt" "bar.txt")
:unknown-option '(skip-option)
:missing-arg '(skip-option)
:arg-parser-failed '(skip-option))
(assert (equalp options '(:flag-a t :grab-int 13 :flag-b t :flag-b t)))
(assert (equalp options '(:flag-a t :grab-int 13 :flag-b t :flag-b t
:grab-string 42)))
(assert (equalp free-args '("foo.txt" "bar.txt")))
(assert (equalp *unknown-options* '("-r")))
(assert (equalp *missing-arg-options* '("-s")))
(assert (equalp *malformed-arguments* nil)))
(assert (equalp *malformed-arguments* nil))))

(defun miscelleneous-3 ()
(multiple-value-bind (options free-args)
(parse-opts '("--grab-str=fooba" "-i" "what" "-i" "100" "--roro" "-")
:unknown-option '(skip-option)
:missing-arg '(skip-option)
:arg-parser-failed '(skip-option))
(assert (equalp options '(:grab-str "fooba" :grab-int 100)))
(assert (equalp options '(:grab-str "fooba" :grab-int 100
:grab-string 42)))
(assert (equalp free-args '("-")))
(assert (equalp *unknown-options* '("--roro")))
(assert (equalp *missing-arg-options* nil))
(assert (equalp *malformed-arguments* '("what"))))
(assert (equalp *malformed-arguments* '("what")))))

(defun miscelleneous-4 ()
(multiple-value-bind (options free-args)
(parse-opts '("--foobar" "cat" "-sl") ; very tricky (see restarts)
:unknown-option '(use-value "--grab-int")
:missing-arg '(use-value "my-string")
:arg-parser-failed '(reparse-arg "15"))
(assert (equalp options '(:grab-int 15 :grab-str "my-string"
:grab-int "my-string")))
:grab-int "my-string" ; TODO: should this be the behaviour
:grab-string 42)))
(assert (equalp free-args nil))
(assert (equalp *unknown-options* '("--foobar" "-l")))
(assert (equalp *missing-arg-options* '("-s" "--grab-int")))
(assert (equalp *malformed-arguments* '("cat"))))
(assert (equalp *malformed-arguments* '("cat")))))

(defun miscelleneous-5 ()
(multiple-value-bind (options free-args)
(parse-opts '("--grab-i" "10" "--grab" "14" "--grab-s")
(parse-opts '("--grab-int" "10" "--grab" "14" "--grab-s")
:unknown-option '(skip-option)
:missing-arg '(skip-option)
:arg-parser-failed '(skip-option))
(assert (equalp options '(:grab-int 10)))
:arg-parser-failed '(skip-option)
:ambiguous-option '(skip-option))
(assert (equalp options '(:grab-int 10
:grab-string 42)))
(assert (equalp free-args '("14")))
(assert (equalp *unknown-options* '("--grab")))
(assert (equalp *missing-arg-options* '("--grab-s")))
(assert (equalp *malformed-arguments* nil)))
(assert (null (set-difference *ambiguous-options* '("--grab" "--grab-s")
:test #'equal)))
(assert (equalp *malformed-arguments* nil))))

(defun miscelleneous-6 ()
(multiple-value-bind (options free-args)
(parse-opts '("--grab-int" "15" "--" "--grab-int" "16")
:unknown-option '(skip-option)
:missing-arg '(skip-option)
:arg-parser-failed '(skip-option))
(assert (equalp options '(:grab-int 15)))
(assert (equalp options '(:grab-int 15
:grab-string 42)))
(assert (equalp free-args '("--grab-int" "16")))
(assert (equalp *unknown-options* nil))
(assert (equalp *missing-arg-options* nil))
(assert (equalp *malformed-arguments* nil)))
(assert (equalp *malformed-arguments* nil))))

(defun miscelleneous-7 ()
(multiple-value-bind (options free-args)
(parse-opts '("-s" "5")
:unknown-option '(skip-option)
:missing-arg '(skip-option)
:missing-required '(skip-option)
:arg-parser-failed '(skip-option))
(assert (equalp options '(:grab-str "5")))
(assert (equalp options '(:grab-str "5"
:grab-string 42)))
(assert (equalp free-args '()))
(assert (equalp *missing-required-options* '((:grab-int))))
(assert (equalp *unknown-options* nil))
(assert (equalp *missing-arg-options* nil))
(assert (equalp *malformed-arguments* nil)))
(assert (equalp *malformed-arguments* nil))))

(defun miscelleneous-8 ()
(multiple-value-bind (options free-args)
(parse-opts '("-s" "5")
:unknown-option '(skip-option)
:missing-arg '(skip-option)
:missing-required '(use-value (15))
:arg-parser-failed '(skip-option))
(assert (equalp options '(:grab-str "5" :grab-int 15)))
(assert (equalp options '(:grab-str "5" :grab-int 15
:grab-string 42)))
(assert (equalp free-args '()))
(assert (equalp *missing-required-options* '((:grab-int))))
(assert (equalp *unknown-options* nil))
(assert (equalp *missing-arg-options* nil))
(assert (equalp *malformed-arguments* nil))))

(export 'run-tests)
(defun expand-opts-test ()
(assert (equalp
(macroexpand-1
'(opts:expand-opts
(:help "Show this help text.")
(:port "Port number on which to run the server." #'parse-integer t)
(:swank-port "Port number at which to start swank [default: 8080]" #'parse-integer)
(:debug "Run in debug mode if specified" #'identity)))
'(UNIX-OPTS:DEFINE-OPTS
(:NAME :HELP :DESCRIPTION "Show this help text." :SHORT #\h :REQUIRED NIL
:LONG "help" :ARG-PARSER NIL)
(:NAME :PORT :DESCRIPTION "Port number on which to run the server." :SHORT
#\p :REQUIRED T :LONG "port" :ARG-PARSER #'PARSE-INTEGER)
(:NAME :SWANK-PORT :DESCRIPTION
"Port number at which to start swank [default: 8080]" :SHORT #\s :REQUIRED
NIL :LONG "swank-port" :ARG-PARSER #'PARSE-INTEGER)
(:NAME :DEBUG :DESCRIPTION "Run in debug mode if specified" :SHORT #\d
:REQUIRED NIL :LONG "debug" :ARG-PARSER #'IDENTITY)))))

(defun run ()
(dolist (fn '(argv-test unexpected-options-test
miscelleneous-1
miscelleneous-2
miscelleneous-3
miscelleneous-4
miscelleneous-5
miscelleneous-6
miscelleneous-7
miscelleneous-8
expand-opts-test))
(funcall fn)
(format t "~D ran successfully~%" fn))
(format t "All tests ran successfully!"))
Loading