--- /dev/null
+*.lisp diff=lisp
interest.
+# GENERIC FUNCTIONS
+
+Since behaviour isn't bound to classes, but to generic functions,
+creating new classes on the fly isn't particularly interesting.
+
+We provide the form `PROGM` to bind a number of methods during the
+execution of its contained body:
+
+ > (progm
+ > '((baz NIL (list)))
+ > '((lambda (list) list))
+ > ...)
+
+For example:
+
+ > (defclass foo () ())
+ > (defgeneric baz (foo)
+ (:method ((foo foo))
+ 42))
+ > (progm '((baz NIL (list)))
+ '((lambda (list) list))
+ (values (baz (make-instance 'foo)) (baz '(1 2 3))))
+ > => 42
+ > => (1 2 3)
+
+
# UTILITIES
`DFLET` dynamically rebinds functions similar to `FLET`:
> => 23
> (OR) => 42, if FOO was inlined
-
[1]: http://common-lisp.net/project/closer/closer-mop.html
--- /dev/null
+;;; -*- mode: lisp; syntax: common-lisp; coding: utf-8-unix; package: cl-user; -*-
+
+(in-package #:cl-user)
+\f
+(asdf:defsystem #:cl-mock-tests
+ :description "Tests for CL-MOCK"
+ :author "Olof-Joachim Frahm <olof@macrolet.net>"
+ :license "Simplified BSD License"
+ :version "0.0.1"
+ #+asdf-unicode :encoding #+asdf-unicode :utf-8
+ :depends-on (#:cl-mock #:fiveam)
+ :serial T
+ :components ((:module "tests"
+ :components
+ ((:file "package")
+ (:file "suite")
+ (:file "functions")
+ (:file "facade")
+ (:file "methods")))))
\ No newline at end of file
;;; -*- mode: lisp; syntax: common-lisp; coding: utf-8-unix; package: cl-user; -*-
(in-package #:cl-user)
-
+\f
(asdf:defsystem #:cl-mock
:description "Mocking library"
- :description "Mocking (generic) functions."
+ :long-description "Mocking library to test plain and generic functions."
:author "Olof-Joachim Frahm <olof@macrolet.net>"
:license "Simplified BSD License"
- :depends-on (#:closer-mop #:alexandria)
+ :version "0.0.1"
+ #+asdf-unicode :encoding #+asdf-unicode :utf-8
+ :depends-on (#:closer-mop #:alexandria #:arnesi)
:in-order-to ((asdf:test-op (asdf:load-op #:cl-mock-tests)))
:perform (asdf:test-op :after (op c)
(funcall (find-symbol (symbol-name '#:run!) '#:fiveam)
(find-symbol (symbol-name '#:cl-mock) '#:cl-mock-tests)))
:serial T
- :components ((:module "src"
+ :components ((:static-file "README.md")
+ (:module "src"
:components
((:file "package")
(:file "functions")
(:file "mock")
(:file "methods")
(:file "facade")))))
-
-(asdf:defsystem #:cl-mock-tests
- :depends-on (#:cl-mock #:fiveam)
- :serial T
- :components ((:module "tests"
- :components
- ((:file "package")
- (:file "suite")
- (:file "functions")
- (:file "facade")
- (:file "methods")))))
;;; -*- mode: lisp; syntax: common-lisp; coding: utf-8-unix; package: cl-mock; -*-
(in-package #:cl-mock)
-
+\f
;;; syntactic sugar for defining the mock interactions
(defun make-lambda-pattern (literal-pattern)
;;; -*- mode: lisp; syntax: common-lisp; coding: utf-8-unix; package: cl-mock; -*-
(in-package #:cl-mock)
-
+\f
;;; dynamic rebinding of functions
(defun maybe-fdefinition (name)
;;; -*- mode: lisp; syntax: common-lisp; coding: utf-8-unix; package: cl-mock; -*-
(in-package #:cl-mock)
-
+\f
;;; mocking of generic methods and objects
(defun find-methods (methods)
;;; -*- mode: lisp; syntax: common-lisp; coding: utf-8-unix; package: cl-mock; -*-
(in-package #:cl-mock)
-
+\f
;;; mocking of regular functions
(defstruct mock-bindings
+ "Contains a set of mocked functions and their behaviour."
mocks)
(defvar *previous*)
be recorded and returned as the second return value, else NIL."
(let* ((mocks (mock-bindings-mocks mock-bindings))
(functions (mapcar #'car mocks))
- (previous (mapcar #'maybe-fdefinition functions))
- invocations)
- (call-with-function-bindings
- functions
- (mapcar (lambda (binding previous &aux (name (car binding)) (cases (cdr binding)))
- (lambda (&rest args)
- (when recordp
- (push (cons name args) invocations))
- (find-and-invoke-mock previous cases args)))
- mocks previous)
- (lambda ()
- (values
- (funcall function)
- (nreverse invocations)))
- previous)))
+ (previous (mapcar #'maybe-fdefinition functions)))
+ (with-collector (invocations)
+ (call-with-function-bindings
+ functions
+ (mapcar (lambda (binding previous &aux (name (car binding)) (cases (cdr binding)))
+ (lambda (&rest args)
+ (when recordp
+ (invocations (cons name args)))
+ (find-and-invoke-mock previous cases args)))
+ mocks previous)
+ (lambda ()
+ (values
+ (funcall function)
+ (invocations)))
+ previous))))
(defun register-mock (mock-bindings name)
"Registers a mocked function under NAME. The mocked function will
;;; -*- mode: lisp; syntax: common-lisp; coding: utf-8-unix; package: cl-user; -*-
(in-package #:cl-user)
-
+\f
(defpackage #:cl-mock
(:use #:closer-common-lisp #:alexandria)
+ (:import-from #:arnesi #:with-collector)
(:export ;;; regular functions
#:progf
#:dflet
;;; -*- mode: lisp; syntax: common-lisp; coding: utf-8-unix; package: cl-mock-tests; -*-
(in-package #:cl-mock-tests)
-
+\f
(in-suite cl-mock)
(def-test call-with-mocks.empty ()
;;; -*- mode: lisp; syntax: common-lisp; coding: utf-8-unix; package: cl-mock-tests; -*-
(in-package #:cl-mock-tests)
-
+\f
(in-suite cl-mock)
(def-test progf.calls-binding ()
;;; -*- mode: lisp; syntax: common-lisp; coding: utf-8-unix; package: cl-mock-tests; -*-
(in-package #:cl-mock-tests)
-
+\f
(in-suite cl-mock)
(defclass foo ()
'((baz NIL (list)))
'((lambda (list) list))
(is (equal '(1 2 3) (baz '(1 2 3))))
- (signals error (equal T (baz T)))
- (is (equal 42 (baz (make-instance 'foo))))))
+ (signals error (eq T (baz T)))
+ (is (eql 42 (baz (make-instance 'foo))))))
+
+(def-test gf.overwrite ()
+ (progm
+ '((baz NIL (foo)))
+ '((lambda (foo) 23))
+ (is (eql 23 (baz (make-instance 'foo)))))
+ (is (eql 42 (baz (make-instance 'foo)))))
;;; -*- mode: lisp; syntax: common-lisp; coding: utf-8-unix; package: cl-user; -*-
(in-package #:cl-user)
-
+\f
(defpackage #:cl-mock-tests
(:use #:cl #:cl-mock #:fiveam)
- (:import-from #:cl-mock #:call-with-mocks #:progm #:make-mock-bindings #:if-called #:when-called))
+ (:import-from
+ #:cl-mock
+ #:call-with-mocks
+ #:progm
+ #:make-mock-bindings
+ #:if-called
+ #:when-called
+ #:call-previous
+ #:register-mock))
(in-package #:cl-mock-tests)
-
+\f
(def-suite cl-mock)