Search code examples
unit-testinglispelisporg-mode

How to test a function in lisp and emacs


How can I assert that 2012/08 (instead of Aug 2012) is returned from this function?

Thus I can start learning lisp on the job/with the function itself until the output satisfies.

I know some python unit testing (pytest) and am looking for something similar for lisp. However, my first attempt[0] C-c eval-buffer fails with Invalid function: "<2012-08-12 Mon>"

(assert (= (org-cv-utils-org-timestamp-to-shortdate ("<2012-08-12 Mon>")) "Aug 2012"))

(defun org-cv-utils-org-timestamp-to-shortdate (date_str)
"Format orgmode timestamp DATE_STR  into a short form date.
Other strings are just returned unmodified

e.g. <2012-08-12 Mon> => Aug 2012
today => today"
  (if (string-match (org-re-timestamp 'active) date_str)
      (let* ((abbreviate 't)
             (dte (org-parse-time-string date_str))
             (month (nth 4 dte))
             (year (nth 5 dte))) ;;'(02 07 2015)))
        (concat
         (calendar-month-name month abbreviate) " " (number-to-string year)))
    date_str))

[0] https://www.emacswiki.org/emacs/UnitTesting


Solution

  • (assert (= (org-cv-utils-org-timestamp-to-shortdate ("<2012-08-12 Mon>")) 
               "Aug 2012"))
    
    (defun org-cv-utils-org-timestamp-to-shortdate (...) ...)
    
    1. statements are executed in sequence, which means your function will only be defined after the assertion is evaluated. This is a problem because the assertion calls that function. You should reorder your code to test it after the function is defined.

    2. you cannot compare strings with =, if you call describe-function (C-h f) for =, you'll see that = is a numerical comparison (in fact, numbers or markers). For strings you need to use string=.

    3. In a normal evaluation context, ie. not in a macro or a special form, the following is read as a function call:

      ("<2012-08-12 Mon>")
      

      Parentheses are meaningful, the above form says: call function "<2012-08-12 Mon>" with zero arguments. This is not what you want, there is no need to add parentheses here around the string.