Существует ли фреймворк для насмешек / недоработок для Common Lisp? - PullRequest
11 голосов
/ 01 ноября 2010

Есть ли для Common Lisp фреймворк / заглушка?

EmacsLispMock выглядит великолепно, но это фреймворк Emacs для lisp, и я ищу что-то, что можно использовать из Common Lisp.

Есть предложения?

Ответы [ 7 ]

4 голосов
/ 03 ноября 2010

Следующее должно делать то, что вы ищете

(defmacro with-replaced-function (fdef &rest body)
  (let ((oldf (gensym))
        (result (gensym))
        (name (car fdef))
        (args (cadr fdef))
        (rbody (cddr fdef)))
    `(let ((,oldf (symbol-function ',name)))
       (setf (symbol-function ',name) (lambda ,args ,@rbody))
       (let ((,result (progn ,@body)))
         (setf (symbol-function ',name) ,oldf)
         ,result))))

(defmacro show (x)
  `(format t "~a --> ~a~%"
           ',x ,x))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defun foo (x y) (+ x y))

(defun bar (x) (foo x (* x 2)))

(show (bar 42))

(show (with-replaced-function (foo (x y) (* x y))
                              (bar 42)))

(show (bar 42))

Макрос просто сохраняет функцию, указанную в данный момент символом, и заменяет ее предоставленной реализацией заглушки. В конце кадра функция восстанавливается до исходного значения.

Возможно, имеет смысл добавить защиту от нелокальных выходов из тела.

Обратите внимание, что очевидно, что изменение определения функции не будет работать, если вызов функции был встроен компилятором. CL имеет специальное объявление NOTINLINE , которое можно использовать для предотвращения этой проблемы.

2 голосов
/ 18 ноября 2010

Как указывает Райнер, компилятор файлов иногда включает функции, что означает, что изменение определения функции не будет иметь никакого эффекта в местах, где функция была встроена.

Изменение определения имени функции также не заменит использование функции в качестве литерального объекта, например, если вы сохранили # 'my-stubbed-function в переменной где-то.

Однаков некоторых реализациях lisp вы можете определить оболочки функций или воспользоваться советом для достижения этого: например, Allegro CL имеет fwrappers .В SBCL вы могли бы использовать TRACE с нестандартной функцией: break и пользовательской * invoke-debugger-hook *, и я уверен, что в других реализациях lisp будет нечто подобное.

Iне думайте, что кто-нибудь упаковал эти методы в библиотеку.Ты мог быть первым!(И это было бы здорово. Я бы хотел использовать что-то вроде этого.)

1 голос
/ 05 апреля 2015

Я написал библиотеку с макросом, очень похожим на ответ @ 6502 (with-mocked-functions), но немного более общим. Он также предоставляет with-added-methods, который позволяет вам писать фиктивные методы для ограниченной динамической области. Вы можете найти его здесь: https://github.com/bytecurry/bytecurry.mocks

1 голос
/ 02 ноября 2010

Разве это не самый простой способ сделать это?

> (defun b () 'original)
B
> (setf f #'b)
#<Compiled-function B #xC2C1546>
> (defun a () (funcall f))
A
> (a)
ORIGINAL
> (setf f #'(lambda () 'stub))
#<Anonymous Function #xC2D990E>
> (a)
STUB
> (setf f #'b)
#<Compiled-function B #xC2C1546>
> (a)
ORIGINAL
1 голос
/ 01 ноября 2010

Вам не нужен фреймворк для насмешек в CL.

Просто создайте новый CLOS, производный от вашего класса, с методами ovverides для того, что вы хотите заглушки / макеты, и все готово.

Что касается заглушки, почему бы просто не переопределить функцию?

0 голосов
/ 20 сентября 2017

Несколько лет спустя, есть.У нас есть cl-mock и mockingbird в Quicklisp.

(ql:quickload :mockingbird)

Этот также позволяет проверить, была ли вызвана функция, если так, сколько раз ис какими аргументами и возможно заглушить отдельные методы.

0 голосов
/ 03 ноября 2010

Вы можете попытаться обернуть переопределение функции внутри макроса

(defmacro with-fun (origfn mockfn &body body)
  `(let ((it ,origfn))
      (setf ,origfn ,mockfn)
     ,@body
      (setf ,origfn ,it)))

Это всего лишь идея, и вам придется реализовать такой макрос.Вы можете использовать Google для реализации profile, которая делает именно это, заменяет одну функцию другой и добавляет информацию о профилировании.Вы можете заимствовать некоторые идеи оттуда.

...