xl-expectations.l minimal なの
(expect (+ 1 2 3) (returns 6)) => t (expect (concat "foo" "bar") (returns "foobar")) => t (expect (add 1 2 3) (returns 6)) (add 1 2 3) Expected: return 6 Actually: signaled undefined-function. => nil (expect (+ 'foo 'bar) (signals type-error)) => t
expect: example-form &rest expectations
- example-form: 式
- expectations: (returns ...) か (signal ...) を何個でも
- returns: &rest values
- values: 値をいくつか指定、値は評価される、n個目の値が(多値の)n個目に対応、equal で比較される
- signals: condition-type &optional message
- condition-type: コンディション名、クォートしてはいけない、typep で比較される
- message: 指定されていれば si:*condition-string と string= で比較される
- returns: &rest values
fail したら *standard-output* になんか書き出す。戻り値は t or nil。
code
(defstruct behavior source return-values condition) (defmacro inspect (form) (let ((actual (gensym))) `(let ((,actual (make-behavior :source ',form))) (handler-case (setf (behavior-return-values ,actual) (multiple-value-list ,form)) (condition (c) (setf (behavior-condition ,actual) c))) ,actual))) (defun compile-expectation (expectation) `(lambda (actual) ,(case (car expectation) (returns `(if (equal #1=(behavior-return-values actual) (list ,@(cdr expectation))) t (progn (format t "~S~% Expected: return ~S~@{, ~S~}~% Actually: " #4=(behavior-source actual) ,@(cdr expectation)) (if #1# (apply #'format t "returned ~S~@{, ~S~}.~%" #1#) (format t "signaled ~S.~%" (si:*structure-definition-name (si:*structure-definition #2=(behavior-condition actual)))))))) (signals `(if ,(if (null (third expectation)) #3=`(typep #2# ',(second expectation)) `(and #3# (string= (si:*condition-string #2#) ,(third expectation)))) t (progn (format t "~S~% Expected: signal ~S~% Actually: " #4# ',(second expectation)) (if #2# (format t "signaled ~S.~%" (si:*structure-definition-name (si:*structure-definition #2#))) (apply #'format t "returned ~S~@{, ~S~}.~%" #1#))))) (t (error "unknown effect specifier: ~S" expectation))))) (defmacro expect (form &rest expectations) `(let ((actual (inspect ,form))) (every (lambda (expectation) (funcall expectation actual)) (list ,@(mapcar #'compile-expectation expectations))))) #+xyzzy (setf (get 'expect 'lisp-indent-hook) 1)
TODO
- package どうしよう
- report の出力先とかを変更しやすく
- effect (returns とか signals とか)の追加
- spec としてまとめる->まとめて verify
- 値の要件
- save-buffer したときに勝手に verify する
- 話それるけど OSC-do どうしよう