所以,我正在努力熟悉Emacs中的单元测试包ERT。我想测试使用gensym
的宏扩展。我可以确保gensym生成具有相同名称的符号,但它们不是相同的符号,这会导致失败。下面的代码可以让您更好地了解:
(ert-deftest i-test-repreat ()
"Tests the expansion of i-iterate macro, repeat driver."
(require 'i-iterate)
(should
(equal
(macroexpand '(++ (repeat 100) (message "")))
'(let* ((--0 0)) ;; `--0' is a result of a custom-made `gensym'
(while (< --0 100)
(incf --0)
(message "")) nil))))
这是失败的消息:
(list-elt 1
(list-elt 0
(list-elt 0
(different-symbols-with-the-same-name --0 --0))))
很公平,它是一个不同的符号,但预计会如此。我怎样才能让它成功?
修改
这是我到目前为止所能提出的:
(defun i/test-equals-ignore-gensym (a b)
"Tests trees A and B for equality, but considers symbols
equal if their names are equal (this allows symbols generated
by `i-gensym' to pass)."
(or (equal a b)
(cond
((and (null a) (null b)) t)
((and (consp a) (consp b))
(and (i/test-equals-ignore-gensym (car a) (car b))
(i/test-equals-ignore-gensym (cdr a) (cdr b))))
((and (symbolp a) (symbolp b))
(string= (symbol-name a) (symbol-name b)))
((and (atom a) (atom b)) (eql a b))
(t nil))))
(defun i/test-explainer-equal (a b)
"Explains why `i/test-equals-ignore-gensym' failed."
;; TODO: Write our own explanation, this will trigger when
;; necessary, but will not always display the correct message.
(ert--explain-equal-rec a b))
(put 'i/test-equals-ignore-gensym
'ert-explainer 'i/test-explainer-equal)
(ert-deftest i-test-repreat ()
"Tests the expansion of i-iterate macro, repeat driver."
(require 'i-iterate)
(should
(i/test-equals-ignore-gensym
(macroexpand '(++ (repeat 100) (message "")))
'(let* ((--0 0))
(while (< --0 100)
(incf --0)
(message "")) nil))))
但如果有更好的方法,我会更高兴。
答案 0 :(得分:1)
您可以采用不同的方式解决问题:不要检查代码是否符合预期,而只检查代码是否符合您的预期。即运行(++ ...)
表达式并检查输出。
顺便说一下,你想对那些代码块进行的比较被称为“等式模数转换”或仅仅是alpha equivalence
答案 1 :(得分:0)
您可以将实际名称与symbol-name
进行比较。
答案 2 :(得分:0)
如果您在自定义的make-symbol
中使用gensym
,则将make-symbol
替换为intern
会对您有所帮助。所以,
(flet ((make-symbol (&optional prefix) (intern prefix)))
(macroexpand '(++ (repeat 100) (message ""))))
生成类似的代码,其中符号为--0
。这足以避免您的问题。