emacs-elpa-diffs
[Top][All Lists]
Advanced

[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)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]