1

I'd like to mock a function for a unit test that I'm writing. I want the mocked function to count how many times it was called but I'm having issues related to the scope of the count variable.

Here is an example of what I'm trying to do:

;; Assumes lexical-binding is t

(defvar example-settings nil)

(defun function-to-test ()
  (funcall (car example-settings)))

(let* ((function-to-mock-call-cnt 0)
       (example-settings
        '((lambda ()
            (setq function-to-mock-call-cnt
                  (1+ function-to-mock-call-cnt))))))
  (function-to-test)
  function-to-mock-call-cnt)

However, this fails with the error void-variable.

Can someone help me understand why this doesn't work?

8
  • 2
    The binding for var org-agenda-bulk-custom-functions is to a quoted list. Those lambdas aren't defined as functions there - the (lambda...) for each is just a list. How do you expect the lexical bindings of those 3 vars to be captured in those lambdas as functions? You might just try using #' in front of each (lambda...). Otherwise, you might need to use a backquote for the ``org-agenda...` var value, and use commas to insert the lambdas, so they're interpreted at that time (or compile time), to pick up those lexical args. Someone else will no doubt have a better explanation/solution.
    – Drew
    Feb 18, 2021 at 2:56
  • 1
    I don't get the error you get: I get Invalid bulk action: P - but then, I don't have the patch in my Org mode. After updating my Org mode to latest, I get (void-function org-test-agenda--kill-all-agendas) when I run the above code, but still no complaints about those variables.
    – NickD
    Feb 18, 2021 at 3:45
  • @Drew thanks, that's exactly it. Once I used back quoting it solved the issue and your explanation makes perfect sense as to why. I plan on updating the question with a smaller more clear example now that I know what the issue is.
    – kfoley
    Feb 18, 2021 at 13:45
  • @NickD - sorry about that, it's dependent on some of the org mode testing functions. I've got the answer based on Drew's comment and will clarify the question for those who have a similar issue.
    – kfoley
    Feb 18, 2021 at 13:48
  • @Drew - question has been clarified with a minimal example, if you want to answer with the back quote solution I'll gladly accept.
    – kfoley
    Feb 18, 2021 at 14:03

1 Answer 1

1

The binding for variable example-settings is to a quoted list. The lambda form (lambda...) in that list isn't defined as a function there it's just a list.

You can't expect the lexical binding of variable function-to-mock-call-cnt to be captured within that lambda - nothing indicates to Emacs that the list (lambda...) is a function.

You can instead use a function such as list or use a backquote with a comma:

(example-settings
  (list (lambda ()
          (setq function-to-mock-call-cnt
                (1+ function-to-mock-call-cnt))))))

or

(example-settings
  `(,(lambda ()
       (setq function-to-mock-call-cnt
             (1+ function-to-mock-call-cnt))))))
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.