[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/buttercup 6ad9565 135/340: Fix several edge cases in "spy-
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/buttercup 6ad9565 135/340: Fix several edge cases in "spy-on" |
Date: |
Thu, 16 Dec 2021 14:59:20 -0500 (EST) |
branch: elpa/buttercup
commit 6ad9565cd7adc195f81bdbbc1115a6bd96802a72
Author: Ryan C. Thompson <rct@thompsonclan.org>
Commit: Jorgen Schäfer <Jorgen.Schaefer@gmail.com>
Fix several edge cases in "spy-on"
The "spy-on" function now works on commands and autoloaded functions,
and checks for the right number of arguments for each modifier.
For commands, it preserves the interactive form of the original
command, unless the given replacement overrides it (in which case a
warning is issued). This means that the spy can be executed as a
command in the same way as the original.
For autoloads, "spy-on" simply forces the load to happen so that the
function becomes an ordinary function instead of an autoloaded one.
Finally, all modifiers now check whether the correct number of args
was provided instead of silently ignoring extra ones. In addition, the
argument for ":and-throw-error" now defaults to "error" if a more
specific error type is not specified.
Tests are added for all three features.
This should fix #56 and #103.
Add autoload test
---
buttercup.el | 106 +++++++++++++++++++++++++++++++-----------------
tests/test-buttercup.el | 52 +++++++++++++++++++++++-
2 files changed, 119 insertions(+), 39 deletions(-)
diff --git a/buttercup.el b/buttercup.el
index bf33e83..94efd2c 100644
--- a/buttercup.el
+++ b/buttercup.el
@@ -550,28 +550,54 @@ KEYWORD can have one of the following values:
the original function.
nil -- Track calls, but simply return nil instead of calling
- the original function."
- (cond
- ((eq keyword :and-call-through)
- (let ((orig (symbol-function symbol)))
- (buttercup--spy-on-and-call-fake symbol
- (lambda (&rest args)
- (apply orig args)))))
- ((eq keyword :and-return-value)
- (buttercup--spy-on-and-call-fake symbol
- (lambda (&rest args)
- arg)))
- ((eq keyword :and-call-fake)
- (buttercup--spy-on-and-call-fake symbol
- arg))
- ((eq keyword :and-throw-error)
- (buttercup--spy-on-and-call-fake symbol
- (lambda (&rest args)
- (signal arg "Stubbed error"))))
- (t
- (buttercup--spy-on-and-call-fake symbol
- (lambda (&rest args)
- nil)))))
+ the original function.
+
+If the original function was a command, the generated spy will
+also be a command with the same interactive form, unless
+`:and-call-fake' is used, in which case it is the caller's
+responsibility to ensure ARG is a command."
+ ;; We need to load an autoloaded function before spying on it
+ (when (autoloadp (symbol-function symbol))
+ (autoload-do-load (symbol-function symbol) symbol))
+ (cl-assert (not (autoloadp (symbol-function symbol))))
+ (let* ((orig (symbol-function symbol))
+ (orig-intform (interactive-form orig))
+ (replacement
+ (pcase
+ keyword
+ (:and-call-through
+ (when arg
+ (error "`spy-on' with `:and-call-through' does not take an
ARG"))
+ `(lambda (&rest args)
+ ,orig-intform
+ (apply ',orig args)))
+ (:and-return-value
+ `(lambda (&rest args)
+ ,orig-intform
+ ,arg))
+ (:and-call-fake
+ (let ((replacement-intform (interactive-form arg)))
+ (when (and replacement-intform
+ (not (equal orig-intform replacement-intform)))
+ (display-warning 'buttercup
+ "While spying on `%S': replacement does not
have the same interactive form"))
+ `(lambda (&rest args)
+ ,(or replacement-intform orig-intform)
+ (apply (function ,arg) args))))
+ (:and-throw-error
+ `(lambda (&rest args)
+ ,orig-intform
+ (signal ',(or arg 'error) "Stubbed error")))
+ ;; No keyword: just spy
+ (`nil
+ (when arg
+ (error "`spy-on' with no KEYWORD does not take an ARG."))
+ `(lambda (&rest args)
+ ,orig-intform
+ nil))
+ (_
+ (error "Invalid `spy-on' keyword: `%S'" keyword)))))
+ (buttercup--spy-on-and-call-fake symbol replacement)))
(defun buttercup--spy-on-and-call-fake (spy fake-function)
"Replace the function in symbol SPY with a spy that calls FAKE-FUNCTION."
@@ -592,6 +618,12 @@ KEYWORD can have one of the following values:
:return-value return-value
:current-buffer (current-buffer)))
return-value)))
+ ;; Add the interactive form from `fake-function', if any
+ (when (interactive-form fake-function)
+ (setq this-spy-function
+ `(lambda (&rest args)
+ ,(interactive-form fake-function)
+ (apply ',this-spy-function args))))
this-spy-function))
(defvar buttercup--cleanup-functions nil)
@@ -996,22 +1028,22 @@ Calls either `buttercup-reporter-batch' or
(buttercup--print (buttercup-colorize "\r%s%s\n" 'green)
(make-string (* 2 level) ?\s)
(buttercup-spec-description arg)))
- ((eq (buttercup-spec-status arg) 'failed)
- (buttercup--print (buttercup-colorize "\r%s%s FAILED\n" 'red)
- (make-string (* 2 level) ?\s)
- (buttercup-spec-description arg))
- (setq buttercup-reporter-batch--failures
- (append buttercup-reporter-batch--failures
- (list arg))))
- ((eq (buttercup-spec-status arg) 'pending)
- (if (equal (buttercup-spec-failure-description arg) "SKIPPED")
- (buttercup--print " %s\n" (buttercup-spec-failure-description arg))
- (buttercup--print (buttercup-colorize "\r%s%s %s\n" 'yellow)
+ ((eq (buttercup-spec-status arg) 'failed)
+ (buttercup--print (buttercup-colorize "\r%s%s FAILED\n" 'red)
(make-string (* 2 level) ?\s)
- (buttercup-spec-description arg)
- (buttercup-spec-failure-description arg))))
- (_
- (error "Unknown spec status %s" (buttercup-spec-status arg))))))
+ (buttercup-spec-description arg))
+ (setq buttercup-reporter-batch--failures
+ (append buttercup-reporter-batch--failures
+ (list arg))))
+ ((eq (buttercup-spec-status arg) 'pending)
+ (if (equal (buttercup-spec-failure-description arg) "SKIPPED")
+ (buttercup--print " %s\n" (buttercup-spec-failure-description
arg))
+ (buttercup--print (buttercup-colorize "\r%s%s %s\n" 'yellow)
+ (make-string (* 2 level) ?\s)
+ (buttercup-spec-description arg)
+ (buttercup-spec-failure-description arg))))
+ (_
+ (error "Unknown spec status %s" (buttercup-spec-status arg))))))
(`buttercup-done
(dolist (failed buttercup-reporter-batch--failures)
diff --git a/tests/test-buttercup.el b/tests/test-buttercup.el
index 629f043..805ea8b 100644
--- a/tests/test-buttercup.el
+++ b/tests/test-buttercup.el
@@ -18,6 +18,7 @@
;;; Code:
(require 'buttercup)
+(require 'autoload)
(require 'ert)
;;;;;;;;;;
@@ -510,7 +511,10 @@
;; the function before each test would invalidate those tests.
(before-all
(fset 'test-function (lambda (a b)
- (+ a b))))
+ (+ a b)))
+ (fset 'test-command (lambda ()
+ (interactive)
+ t)))
(describe "`spy-on' function"
(it "replaces a symbol's function slot"
@@ -518,7 +522,51 @@
(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)))
+ (expect (test-function 1 2) :to-equal 3))
+
+ (it "allows a spied-on command to be executed as a command"
+ (spy-on 'test-command)
+ (expect (commandp 'test-command))
+ (expect (lambda () (command-execute 'test-command))
+ :not :to-throw)
+ (expect 'test-command :to-have-been-called))
+
+ (it "can spy on autoloaded functions"
+ (let* ((function-file (make-temp-file "test-file-" nil ".el"))
+ (function-name 'test-autoloaded-function)
+ (defun-form `(defun ,function-name ()
+ "An autoloaded function"
+ :loaded-successfully))
+ (autoload-form (make-autoload defun-form function-file)))
+ (unwind-protect
+ (progn
+ ;; Create the real function in a file
+ (with-temp-file function-file
+ (insert ";; -*-lexical-binding:t-*-\n"
+ (pp-to-string defun-form)))
+ ;; Define the autoload for the function
+ (fmakunbound function-name)
+ (eval autoload-form)
+ (expect (autoloadp (symbol-function function-name)))
+ (spy-on function-name :and-call-through)
+ (expect (not (autoloadp (symbol-function function-name))))
+ (expect (funcall function-name)
+ :to-be :loaded-successfully))
+ (delete-file function-file nil))))
+
+ (it "only accepts ARG for keywords that use it"
+ (expect
+ (lambda () (spy-on 'test-function :and-call-through :arg-not-allowed))
+ :to-throw)
+ (expect
+ (lambda () (spy-on 'test-function nil :arg-not-allowed))
+ :to-throw)
+ (expect
+ (lambda () (spy-on 'test-function :and-throw-error))
+ :not :to-throw)
+ (expect
+ (lambda () (test-function 1 2))
+ :to-throw 'error)))
(describe ":to-have-been-called matcher"
(before-each
- [nongnu] elpa/buttercup cccdedf 334/340: Merge pull request #197 from snogge/omit-traceback, (continued)
- [nongnu] elpa/buttercup cccdedf 334/340: Merge pull request #197 from snogge/omit-traceback, ELPA Syncer, 2021/12/16
- [nongnu] elpa/buttercup bef49f5 323/340: Remove extra newline in error backtrace, ELPA Syncer, 2021/12/16
- [nongnu] elpa/buttercup 6ef715f 328/340: Use buttercup--mark-stackframe to mark the start of test code, ELPA Syncer, 2021/12/16
- [nongnu] elpa/buttercup 2f24a44 338/340: Make formatting of backtrace frames closer to that standard for Emacs, ELPA Syncer, 2021/12/16
- [nongnu] elpa/buttercup f6f9335 337/340: test: Add tests for buttercup-run-discovery, ELPA Syncer, 2021/12/16
- [nongnu] elpa/buttercup 553ff83 103/340: Add :to-have-same-items-as to compare lists as sets., ELPA Syncer, 2021/12/16
- [nongnu] elpa/buttercup 657acef 102/340: Bump version: 1.4 → 1.5, ELPA Syncer, 2021/12/16
- [nongnu] elpa/buttercup 7e8898b 127/340: Implement :to-have-been-called-times matcher (close #90), ELPA Syncer, 2021/12/16
- [nongnu] elpa/buttercup ca09040 130/340: Improve the Makefile, ELPA Syncer, 2021/12/16
- [nongnu] elpa/buttercup a535e51 134/340: Fix a logic error in spy tests, ELPA Syncer, 2021/12/16
- [nongnu] elpa/buttercup 6ad9565 135/340: Fix several edge cases in "spy-on",
ELPA Syncer <=
- [nongnu] elpa/buttercup 389dc43 139/340: Fix a problem with reporter tests suppressing failure messages, ELPA Syncer, 2021/12/16
- [nongnu] elpa/buttercup 929a904 143/340: Implement closure-based expect macro, ELPA Syncer, 2021/12/16
- [nongnu] elpa/buttercup 11d7fdc 148/340: Add "--help" option to buttercup command-line script, ELPA Syncer, 2021/12/16
- [nongnu] elpa/buttercup 4106adc 170/340: Add release script, ELPA Syncer, 2021/12/16
- [nongnu] elpa/buttercup 9b6cc79 177/340: travis: Test on 26.1, ELPA Syncer, 2021/12/16
- [nongnu] elpa/buttercup 0d742b0 187/340: Set failure-description for pending specs, ELPA Syncer, 2021/12/16
- [nongnu] elpa/buttercup 1c50a80 196/340: Fix the buttercup-run tests, ELPA Syncer, 2021/12/16
- [nongnu] elpa/buttercup 810fa6f 197/340: Bump version: 1.15 → 1.16, ELPA Syncer, 2021/12/16
- [nongnu] elpa/buttercup 4459f37 199/340: Add test for :var* argument, ELPA Syncer, 2021/12/16
- [nongnu] elpa/buttercup ff16814 216/340: travis: Always test on xenial, ELPA Syncer, 2021/12/16