Reputation: 333
I have a function do-something
, and a function my-function
of the form :
(defun my-function ((object object))
(if (do-something)
5
6))
do-something
and my-function
are in my-package
package.
In my-package/tests
package, I want to do the following :
(deftest "Test my-function"
(flet ((my-package::do-something ()
t))
(assert-is (my-package::my-function) 5))
(flet ((my-package::do-something ()
nil))
(assert-is (my-package::my-function) 6)))
The goal is to test if my-function
behaves correctly, and I would like to keep it as a function (not a macro), and without injecting functions into via the args. In C I could mess with the linker.
Each time I want to run all the updated code and tests, I do the following in the REPL :
(ql:quickload :my-system)
(asdf:test-sytem :my-system/tests)
But it seems it compiles my-function
, so even if I do an flet
on the do-something
function in the test file, the behaviour does not change.
I would like to programmatically test my-function
, is there a way to do that ?
Upvotes: 1
Views: 105
Reputation: 51501
Functions defined by flet
(or labels
) have lexical scope, i. e., they exist only in the flet
body. It does not affect the dynamic environment.
There is no explicit support for dynamically rebinding functions, but you can use something like this:
(defmacro with-rebound-fun ((name args &body fun-body) &body body)
(let ((saved (gensym)))
`(let ((,saved (symbol-function ',name)))
(setf (symbol-function ',name) (lambda ,args ,@fun-body))
(unwind-protect (progn ,@body)
(setf (symbol-function ',name) ,saved)))))
This is a bit hackish though, and it could break some assumptions an implementation may make about redefining functions. In particular, the symbol might carry additional meta information about the function, which does not get changed. It also will not work where the original function is inlined.
Upvotes: 2