[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/buttercup 548df0d 030/340: Spies: Other tracking propertie
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/buttercup 548df0d 030/340: Spies: Other tracking properties. |
Date: |
Thu, 16 Dec 2021 14:58:58 -0500 (EST) |
branch: elpa/buttercup
commit 548df0db2cca32ca6c20f48f3f62c59e6627ba4f
Author: Jorgen Schaefer <contact@jorgenschaefer.de>
Commit: Jorgen Schaefer <contact@jorgenschaefer.de>
Spies: Other tracking properties.
---
README.md | 113 ++++++++++++++++++++++++++++++++
buttercup-test.el | 190 ++++++++++++++++++++++++++++--------------------------
buttercup.el | 67 ++++++++++++++++---
3 files changed, 270 insertions(+), 100 deletions(-)
diff --git a/README.md b/README.md
index 03c3f87..f56d3b2 100644
--- a/README.md
+++ b/README.md
@@ -452,6 +452,119 @@ will `signal` the specified value as an error.
:to-throw 'error))))
```
+### Other tracking properties
+
+Every call to a spy is tracked and exposed using the `spy-calls`
+accessor.
+
+`spy-calls-any` returns `nil` if the spy has not been called at all,
+and then `t` once at least one call happens. `spy-calls-count` returns
+the number of times the spy was called. `spy-calls-args-for` returns
+the arguments passed to a given call (by index). `spy-calls-all-args`
+returns the arguments to all calls. `spy-calls-all` returns the
+current buffer and arguments passed to all calls.
+`spy-calls-most-recent` returns the current buffer and arguments for
+the most recent call. `spy-calls-first` returns the current buffer and
+arguments for the first call.
+
+Finally, `spy-calls-reset` clears all tracking for a spy.
+
+```Lisp
+(describe "A spy"
+ (let (set-foo foo)
+ (before-each
+ (fset 'set-foo (lambda (val &rest ignored)
+ (setq foo val)))
+ (spy-on 'set-foo))
+
+ (it "tracks if it was called at all"
+ (expect (spy-calls-any 'set-foo)
+ :to-equal
+ nil)
+
+ (set-foo 5)
+
+ (expect (spy-calls-any 'set-foo)
+ :to-equal
+ t))
+
+ (it "tracks the number of times it was called"
+ (expect (spy-calls-count 'set-foo)
+ :to-equal
+ 0)
+
+ (set-foo 2)
+ (set-foo 3)
+
+ (expect (spy-calls-count 'set-foo)
+ :to-equal
+ 2))
+
+ (it "tracks the arguments of each call"
+ (set-foo 123)
+ (set-foo 456 "baz")
+
+ (expect (spy-calls-args-for 'set-foo 0)
+ :to-equal
+ '(123))
+
+ (expect (spy-calls-args-for 'set-foo 1)
+ :to-equal
+ '(456 "baz")))
+
+ (it "tracks the arguments of all calls"
+ (set-foo 123)
+ (set-foo 456 "baz")
+
+ (expect (spy-calls-all-args 'set-foo)
+ :to-equal
+ '((123)
+ (456 "baz"))))
+
+ (it "can provide the context and arguments to all calls"
+ (set-foo 123)
+
+ (expect (spy-calls-all 'set-foo)
+ :to-equal
+ `(,(make-spy-context :current-buffer (current-buffer)
+ :args '(123)
+ :return-value nil))))
+
+ (it "has a shortcut to the most recent call"
+ (set-foo 123)
+ (set-foo 456 "baz")
+
+ (expect (spy-calls-most-recent 'set-foo)
+ :to-equal
+ (make-spy-context :current-buffer (current-buffer)
+ :args '(456 "baz")
+ :return-value nil)))
+
+ (it "has a shortcut to the first call"
+ (set-foo 123)
+ (set-foo 456 "baz")
+
+ (expect (spy-calls-first 'set-foo)
+ :to-equal
+ (make-spy-context :current-buffer (current-buffer)
+ :args '(123)
+ :return-value nil)))
+
+ (it "can be reset"
+ (set-foo 123)
+ (set-foo 456 "baz")
+
+ (expect (spy-calls-any 'set-foo)
+ :to-be
+ t)
+
+ (spy-calls-reset 'set-foo)
+
+ (expect (spy-calls-any 'set-foo)
+ :to-be
+ nil))))
+```
+
## Test Runners
diff --git a/buttercup-test.el b/buttercup-test.el
index fc8d10c..c361a0b 100644
--- a/buttercup-test.el
+++ b/buttercup-test.el
@@ -328,103 +328,113 @@
;;;;;;;;;
;;; Spies
-(defun test-function (a b)
- (+ a b))
-
-(describe "The `spy-on' function"
- (it "replaces a symbol's function slot"
- (spy-on 'test-function)
- (expect (test-function 1 2) :to-be nil))
-
- (it "restores the old value after a spec run"
- (expect (test-function 1 2) :to-equal 3)))
-
-(describe "The :to-have-been-called matcher"
- (before-each
- (spy-on 'test-function))
-
- (it "returns false if the spy was not called"
- (expect (buttercup--apply-matcher :to-have-been-called '(test-function))
- :to-be
- nil))
-
- (it "returns true if the spy was called at all"
- (test-function 1 2 3)
- (expect (buttercup--apply-matcher :to-have-been-called '(test-function))
- :to-be
- t)))
-
-(describe "The :to-have-been-called-with matcher"
- (before-each
- (spy-on 'test-function))
-
- (it "returns false if the spy was not called at all"
- (expect (buttercup--apply-matcher
- :to-have-been-called-with '(test-function 1 2 3))
- :to-be
- nil))
-
- (it "returns false if the spy was called with different arguments"
- (test-function 3 2 1)
- (expect (buttercup--apply-matcher
- :to-have-been-called-with '(test-function 1 2 3))
- :to-be
- nil))
-
- (it "returns true if the spy was called with those arguments"
- (test-function 1 2 3)
- (expect (buttercup--apply-matcher
- :to-have-been-called-with '(test-function 1 2 3))
- :to-be
- t)))
-
-(describe "The :and-call-through keyword functionality"
- (before-each
- (spy-on 'test-function :and-call-through))
-
- (it "tracks calls to the function"
- (test-function 42 23)
-
- (expect 'test-function :to-have-been-called))
-
- (it "passes the arguments to the original function"
- (expect (test-function 2 3)
- :to-equal
- 5)))
+(describe "The Spy "
+ (let (test-function)
+ (before-each
+ (fset 'test-function (lambda (a b)
+ (+ a b))))
+
+ (describe "`spy-on' function"
+ (it "replaces a symbol's function slot"
+ (spy-on 'test-function)
+ (expect (test-function 1 2) :to-be nil))
+
+ (it "restores the old value after a spec run"
+ (expect (test-function 1 2) :to-equal 3)))
+
+ (describe ":to-have-been-called matcher"
+ (before-each
+ (spy-on 'test-function))
+
+ (it "returns false if the spy was not called"
+ (expect (buttercup--apply-matcher :to-have-been-called
+ '(test-function))
+ :to-be
+ nil))
+
+ (it "returns true if the spy was called at all"
+ (test-function 1 2 3)
+ (expect (buttercup--apply-matcher :to-have-been-called
+ '(test-function))
+ :to-be
+ t)))
+
+ (describe ":to-have-been-called-with matcher"
+ (before-each
+ (spy-on 'test-function))
+
+ (it "returns false if the spy was not called at all"
+ (expect (buttercup--apply-matcher
+ :to-have-been-called-with '(test-function 1 2 3))
+ :to-be
+ nil))
+
+ (it "returns false if the spy was called with different arguments"
+ (test-function 3 2 1)
+ (expect (buttercup--apply-matcher
+ :to-have-been-called-with '(test-function 1 2 3))
+ :to-be
+ nil))
+
+ (it "returns true if the spy was called with those arguments"
+ (test-function 1 2 3)
+ (expect (buttercup--apply-matcher
+ :to-have-been-called-with '(test-function 1 2 3))
+ :to-be
+ t)))
+
+ (describe ":and-call-through keyword functionality"
+ (before-each
+ (spy-on 'test-function :and-call-through))
+
+ (it "tracks calls to the function"
+ (test-function 42 23)
+
+ (expect 'test-function :to-have-been-called))
+
+ (it "passes the arguments to the original function"
+ (expect (test-function 2 3)
+ :to-equal
+ 5)))
-(describe "The :and-return-value keyword functionality"
- (before-each
- (spy-on 'test-function :and-return-value 23))
+ (describe ":and-return-value keyword functionality"
+ (before-each
+ (spy-on 'test-function :and-return-value 23))
- (it "tracks calls to the function"
- (test-function 42 23)
+ (it "tracks calls to the function"
+ (test-function 42 23)
- (expect 'test-function :to-have-been-called))
+ (expect 'test-function :to-have-been-called))
- (it "returns the specified value"
- (expect (test-function 2 3)
- :to-equal
- 23)))
+ (it "returns the specified value"
+ (expect (test-function 2 3)
+ :to-equal
+ 23)))
-(describe "The :and-call-fake keyword functionality"
- (before-each
- (spy-on 'test-function :and-call-fake (lambda (a b) 1001)))
+ (describe ":and-call-fake keyword functionality"
+ (before-each
+ (spy-on 'test-function :and-call-fake (lambda (a b) 1001)))
- (it "tracks calls to the function"
- (test-function 42 23)
+ (it "tracks calls to the function"
+ (test-function 42 23)
- (expect 'test-function :to-have-been-called))
+ (expect 'test-function :to-have-been-called))
- (it "returns the specified value"
- (expect (test-function 2 3)
- :to-equal
- 1001)))
+ (it "returns the specified value"
+ (expect (test-function 2 3)
+ :to-equal
+ 1001)))
-(describe "The :and-throw-error keyword functionality"
- (before-each
- (spy-on 'test-function :and-throw-error 'error))
+ (describe ":and-throw-error keyword functionality"
+ (before-each
+ (spy-on 'test-function :and-throw-error 'error))
- (it "throws an error when called"
- (expect (lambda () (test-function 1 2))
- :to-throw
- 'error "Stubbed error")))
+ (it "throws an error when called"
+ (expect (lambda () (test-function 1 2))
+ :to-throw
+ 'error "Stubbed error")))
+
+
+
+ )
+ )
diff --git a/buttercup.el b/buttercup.el
index d02bc07..0885be6 100644
--- a/buttercup.el
+++ b/buttercup.el
@@ -368,29 +368,42 @@ A disabled spec is not run."
(defvar buttercup--spy-calls (make-hash-table :test 'eq
:weakness 'key))
+(cl-defstruct spy-context
+ args
+ return-value
+ current-buffer)
+
(defun spy-on (symbol &optional keyword arg)
(let ((old-value (symbol-function symbol))
(new-value nil))
(cond
((eq keyword :and-call-through)
(setq new-value (lambda (&rest args)
- (buttercup--spy-add-call new-value args)
- (apply old-value args))))
+ (let ((return-value (apply old-value args)))
+ (buttercup--spy-add-call new-value
+ args
+ return-value)
+ return-value))))
((eq keyword :and-return-value)
(setq new-value (lambda (&rest args)
- (buttercup--spy-add-call new-value args)
+ (buttercup--spy-add-call new-value
+ args
+ arg)
arg)))
((eq keyword :and-call-fake)
(setq new-value (lambda (&rest args)
- (buttercup--spy-add-call new-value args)
- (apply arg args))))
+ (let ((return-value (apply arg args)))
+ (buttercup--spy-add-call new-value
+ args
+ return-value)
+ return-value))))
((eq keyword :and-throw-error)
(setq new-value (lambda (&rest args)
- (buttercup--spy-add-call new-value args)
+ (buttercup--spy-add-call new-value args nil)
(signal arg "Stubbed error"))))
((not keyword)
(setq new-value (lambda (&rest args)
- (buttercup--spy-add-call new-value args)
+ (buttercup--spy-add-call new-value args nil)
nil))))
(fset symbol new-value)
(buttercup--add-cleanup (lambda () (fset symbol old-value)))))
@@ -402,10 +415,12 @@ A disabled spec is not run."
(append buttercup--cleanup-forms
(list function)))))
-(defun buttercup--spy-add-call (spy args)
+(defun buttercup--spy-add-call (spy args return-value)
(puthash spy
(append (buttercup--spy-calls spy)
- (list args))
+ (list (make-spy-context :current-buffer (current-buffer)
+ :args args
+ :return-value return-value)))
buttercup--spy-calls))
(defun buttercup--spy-calls (spy)
@@ -423,11 +438,43 @@ A disabled spec is not run."
(let* ((spy (if (symbolp spy)
(symbol-function spy)
spy))
- (calls (buttercup--spy-calls spy)))
+ (calls (mapcar 'spy-context-args (buttercup--spy-calls spy))))
(if (member args calls)
t
nil)))
+(defun spy-calls-any (spy)
+ (if (buttercup--spy-calls (symbol-function spy))
+ t
+ nil))
+
+(defun spy-calls-count (spy)
+ (length (buttercup--spy-calls (symbol-function spy))))
+
+(defun spy-calls-args-for (spy index)
+ (let ((context (elt (buttercup--spy-calls (symbol-function spy))
+ index)))
+ (if context
+ (spy-context-args context)
+ nil)))
+
+(defun spy-calls-all-args (spy)
+ (mapcar 'spy-context-args (buttercup--spy-calls (symbol-function spy))))
+
+(defun spy-calls-all (spy)
+ (buttercup--spy-calls (symbol-function spy)))
+
+(defun spy-calls-most-recent (spy)
+ (car (last (buttercup--spy-calls (symbol-function spy)))))
+
+(defun spy-calls-first (spy)
+ (car (buttercup--spy-calls (symbol-function spy))))
+
+(defun spy-calls-reset (spy)
+ (puthash (symbol-function spy)
+ nil
+ buttercup--spy-calls))
+
;; (let* ((buttercup--descriptions (cons description
;; buttercup--descriptions))
;; (debugger (lambda (&rest args)
- [nongnu] branch elpa/buttercup created (now 108d229), ELPA Syncer, 2021/12/16
- [nongnu] elpa/buttercup e10955c 001/340: Initial commit., ELPA Syncer, 2021/12/16
- [nongnu] elpa/buttercup 67df4b1 012/340: Remove Cask file. It's unused., ELPA Syncer, 2021/12/16
- [nongnu] elpa/buttercup 548df0d 030/340: Spies: Other tracking properties.,
ELPA Syncer <=
- [nongnu] elpa/buttercup b1bcedc 032/340: Add docstrings where missing., ELPA Syncer, 2021/12/16
- [nongnu] elpa/buttercup 821cfa6 005/340: Comment separating built-in matchers from the rest., ELPA Syncer, 2021/12/16
- [nongnu] elpa/buttercup 8e30284 024/340: Disabled suites, pending specs., ELPA Syncer, 2021/12/16
- [nongnu] elpa/buttercup 89c00aa 009/340: Makefile: Make the emacs command configurable, ELPA Syncer, 2021/12/16
- [nongnu] elpa/buttercup 7e20ff1 021/340: ROADMAP.md: New file., ELPA Syncer, 2021/12/16
- [nongnu] elpa/buttercup 764d6aa 020/340: Tests for the it macro and buttercup-it function., ELPA Syncer, 2021/12/16
- [nongnu] elpa/buttercup d5572a6 034/340: Refactoring of the cleanup code., ELPA Syncer, 2021/12/16
- [nongnu] elpa/buttercup b75b3e9 036/340: Add a discovery test runner., ELPA Syncer, 2021/12/16
- [nongnu] elpa/buttercup 7eecb96 038/340: Remove commented-out backtrace code from buttercup.el., ELPA Syncer, 2021/12/16
- [nongnu] elpa/buttercup 3483449 045/340: Typo fix., ELPA Syncer, 2021/12/16