ERT,由于必须被视为相同的不同符号,相等测试失败

时间:2012-11-26 17:28:21

标签: unit-testing emacs elisp ert

所以,我正在努力熟悉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))))

但如果有更好的方法,我会更高兴。

3 个答案:

答案 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。这足以避免您的问题。