作为学习Racket宏系统的练习,我一直在实施基于C++ catch framework的单元测试框架。该框架的一个特点是,如果我写这样的支票:
CHECK(x == y); // (check x y)
当违反检查时,错误消息将打印出x和y的值,即使使用的宏是完全通用的,不像其他测试框架要求你使用像CHECK_EQUALS,CHECK_GREATER等宏。这是可能的通过涉及表达式模板和运算符重载的一些hackery。
在我看来,在Racket中你应该能够做得更好。在C ++版本中,宏不能看到子表达式内部,所以如果你写了类似的东西:
CHECK(f(x, g(y)) == z); // (check (= (f x (g y)) z))
当违反检查时,您只能找到等号的左侧和右侧的值,而不是x,y或g(y)的值。在球拍中,我希望应该可以递归到子表达式并打印一个显示评估每个步骤的树。
问题是我不知道最好的方法是:
实现这一目标的最佳或至少是惯用的方法是什么?
答案 0 :(得分:2)
这是让你入门的东西。
<input type="button" />
输出:
<form id="form" method="post" action="xxxxx.php">
答案 1 :(得分:2)
打印所有内容的替代方法是为应显示的内容添加标记。这是一个简单的草图:
#lang racket
(require racket/stxparam)
(define-syntax-parameter ?
(λ(stx) (raise-syntax-error '? "can only be used in a `test' context")))
(define-syntax-rule (test expr)
(let ([log '()])
(define (log! stuff) (set! log (cons stuff log)))
(syntax-parameterize ([? (syntax-rules ()
[(_ E) (let ([r E]) (log! `(E => ,r)) r)])])
(unless expr
(printf "Test failure: ~s\n" 'expr)
(for ([l (in-list (reverse log))])
(for-each display
`(" " ,@(add-between (map ~s l) " ") "\n")))))))
(define x 11)
(define y 22)
(test (equal? (? (* (? x) 2)) (? y)))
(test (equal? (? (* (? x) 3)) (? y)))
导致此输出:
Test failure: (equal? (? (* (? x) 3)) (? y))
x => 11
(* (? x) 3) => 33
y => 22