aboutsummaryrefslogtreecommitdiff
path: root/testiere.lisp
diff options
context:
space:
mode:
Diffstat (limited to 'testiere.lisp')
-rw-r--r--testiere.lisp36
1 files changed, 31 insertions, 5 deletions
diff --git a/testiere.lisp b/testiere.lisp
index 3ec8a03..ea22b80 100644
--- a/testiere.lisp
+++ b/testiere.lisp
@@ -2,8 +2,6 @@
(in-package #:testiere)
-(defun stub-names (stubs) (mapcar 'first stubs))
-
(defun build-test (name spec)
(match spec
((list :fails inputs)
@@ -17,6 +15,9 @@
(,condition (c) (declare (ignore c)) t)
(condition (c) (declare (ignore c)) nil))))
+ ((list* :program function-name args)
+ `(funcall ',function-name ,@args))
+
((list* :with-stubs redefs more-specs)
(let* ((assoc-vars
(loop for (stub-name . more) in redefs
@@ -59,6 +60,34 @@
(list (mapcar (lambda (spec) (build-test name spec)) specs)
(append before after))))))
+(defmacro with-stub ((name lambda-list &body body) &body forms)
+ "Runs forms in a context where NAME is temporarily rebound to a
+different function. If NAME is not FBOUNDP then it is temporarily
+defined."
+ (let ((cached (gensym)))
+ `(let ((,cached
+ (when (fboundp ',name)
+ (fdefinition ',name))))
+ (unwind-protect
+ (progn
+ (setf (fdefinition ',name)
+ (lambda ,lambda-list ,@body))
+ ,@forms)
+ (if ,cached
+ (setf (fdefinition ',name)
+ ,cached)
+ (fmakunbound ',name))))))
+
+(defmacro with-stubs (redefinitions &body forms)
+ "Like WITH-STUB, but REDEFINITIONS is a list of (NAME LAMBDA-LIST
+. BODY) list, suitable for defining a function."
+ (loop
+ with inner = `(progn ,@forms)
+ for (name lambda-list . body) in (reverse redefinitions)
+ do (setf inner `(with-stub (,name ,lambda-list ,@body)
+ ,inner))
+ finally (return inner)))
+
(defmacro defun/t (name lambda-list &body body)
"Like regular DEFUN, but with embedded unit tests. If those tests
@@ -82,6 +111,3 @@
-
-
-