测试命令行参数解析 - Common Lisp

问题描述 投票:0回答:2

使用 fiveam 测试包,我想测试由 main.lisp 脚本处理的 CLI 参数的解析。但是,解析参数的主函数不接受任何参数。因此,我想知道以下内容, 在我的案例中测试命令行解析的最佳实践是什么?

  • 我应该在运行时修改测试函数中的命令行参数吗?
  • 或者,修改 main.lisp 中的 main 函数,使其将 CLI 参数作为参数。

如果是这样,我应该如何实施?我如何测试 main-missing-arg-p() 中的 main 函数,就像我将使用“--interface wlo1”作为参数执行程序一样?

main.lisp,

(in-package :cl-user)
(defpackage kafar
  (:use :cl)
  (:export main))

(in-package :kafar)
;;; CLI Parser

(opts:define-opts
  (:name :port
   :description "port on the loopback interface on which the proxy server shall run. Recommended: 1080"
   :short #\p
   :long "port"
   :required t
   :arg-parser #'parse-integer
  )
  (:name :interface
   :description "name of the interface kafar shall listen on"
   :short #\i
   :required t
   :long "interface"
   :arg-parser #'identity)
  (:name :help
   :description "print this help text"
   :short #\h
   :long "help"))

(defun unknown-option (condition)
  ...)

(defun missing-arg (condition)
  ...)

(defmacro when-option ((options opt) &body body)
  `...)

(defun main ()
(multiple-value-bind (options free-args)
    (handler-case
        (handler-bind ((opts:unknown-option #'unknown-option))
          (opts:get-opts))
      (opts:missing-arg (condition)
        (format t "fatal: option ~s needs an argument!~%"
                (opts:option condition))
        (uiop:quit))
      (opts:arg-parser-failed (condition)
        (format t "fatal: cannot parse ~s as argument of ~s.~%"
                (opts:raw-arg condition)
                (opts:option condition))
        (uiop:quit))
      ...
    (when-option (options :port)
    (let ((interfacei (getf options :interface))
          (porti (getf options :port)))
          (kafar/proxy:proxy-server porti interfacei))
    (uiop:quit)
    )))

test-main.lisp:

(in-package :kafar/tests)

;;; Testing Proxy server
(def-suite* parse-suite
    :description "Test parsing of CLI arguments"
    :in kafar-suite)

;; test the stdout without arguments
(test main-help
    ; call main function without aguments
    (print (unix-opts:argv)) ; => ("sbcl")
    (let ((output (with-output-to-string (*error-output*) (kafar:main))))
      (is (string= "warning: missing required options: \"--port\", \"--interface\"" output))))

;; test stderr missing port argument
(test main-missing-arg-p
  ; define interface argument, not define port argument
  ;Potentially modify (unix-opts:argv) (sb-ext:*posix-argv*) such that they would be equal to ("sbcl" "--interface 80")
  ; call main function (handling CLI argument parsing)
  )

我在shell中执行如下测试,

sbcl --non-interactive --eval "(progn (ql:quickload '(fiveam usocket nibbles unix-opts trivial-coverage)) (asdf:load-asd (merge-pathnames \"kafar.asd\" (uiop:getcwd))) (asdf:test-system 'kafar/coverage))"
lisp common-lisp sbcl
2个回答
1
投票

您可以使用不起眼的对象模式 (https://martinfowler.com/bliki/HumbleObject.html),这实际上涉及将接收到的 cmd 行参数传递给您能够测试的另一个函数。您可以决定是按原样传递参数,还是定义一个契约来转换参数。无论如何,了解“unix-opts”将如何传递参数是很重要的。


1
投票

使用您的

opts:define-opts
子句,您可以通过将参数列在列表中来测试参数
get-opts

CL-USER> (opts:get-opts '("--interface" "wlo1"))
; Evaluation aborted on #<UNIX-OPTS:MISSING-REQUIRED-OPTION {10024637C3}>.

所以我会让

main
分成
run
entry
函数,第一个接受参数列表,第二个是程序的入口点,它调用
run
(opts:argv)
.

© www.soinside.com 2019 - 2024. All rights reserved.