This repository has been archived on 2022-05-13. You can view files and clone it, but cannot push or open issues or pull requests.
chronometrist/tests/chronometrist-tests.org

489 lines
19 KiB
Org Mode
Raw Normal View History

#+PROPERTY: header-args :tangle yes :load yes :comments link
2021-12-02 12:12:21 +00:00
#+BEGIN_SRC emacs-lisp :load no :tangle no
(setq nameless-current-name "chronometrist")
#+END_SRC
* Setup
** test-file-path-stem
#+BEGIN_SRC emacs-lisp
2021-10-14 03:45:43 +00:00
(defvar chronometrist-test-file-path-stem
(format "%stest" (file-name-directory (or load-file-name default-directory))))
#+END_SRC
2021-10-14 03:45:43 +00:00
2021-12-23 15:03:22 +00:00
** test-backends
=chronometrist-test-backend= is just here till I finish writing the tests for a single backend. Will tackle how to apply the same tests to different backends afterwards - possibly with a [[#chronometrist-ert-deftest][wrapper macro]] around =ert-deftest=.
#+BEGIN_SRC emacs-lisp
2021-10-14 03:45:43 +00:00
(defvar chronometrist-test-backend
2021-12-23 15:03:22 +00:00
(make-instance 'chronometrist-plist-group-backend :path chronometrist-test-file-path-stem))
(defun chronometrist-make-test-backends ()
2021-12-23 15:03:22 +00:00
(cl-loop for backend in '(chronometrist-plist-backend chronometrist-plist-group-backend)
collect (make-instance backend :path chronometrist-test-file-path-stem)))
(defvar chronometrist-test-backends (chronometrist-make-test-backends))
#+END_SRC
** test-first-record
#+BEGIN_SRC emacs-lisp
(defvar chronometrist-test-first-record
'(:name "Programming"
:start "2018-01-01T00:00:00+0530"
:stop "2018-01-01T01:00:00+0530"))
#+END_SRC
** test-latest-record
#+BEGIN_SRC emacs-lisp
(defvar chronometrist-test-latest-record
'(:name "Programming"
:tags (reading)
:book "Smalltalk-80: The Language and Its Implementation"
:start "2020-05-10T16:33:17+0530"
:stop "2020-05-10T17:10:48+0530"))
#+END_SRC
2021-12-26 08:59:51 +00:00
** test-records
#+BEGIN_SRC emacs-lisp
(defvar chronometrist-test-records
'((:name "Programming"
:start "2018-01-01T00:00:00+0530"
:stop "2018-01-01T01:00:00+0530")
(:name "Swimming"
:start "2018-01-01T02:00:00+0530"
:stop "2018-01-01T03:00:00+0530")
(:name "Cooking"
:start "2018-01-01T04:00:00+0530"
:stop "2018-01-01T05:00:00+0530")
(:name "Guitar"
:start "2018-01-01T06:00:00+0530"
:stop "2018-01-01T07:00:00+0530")
(:name "Cycling"
:start "2018-01-01T08:00:00+0530"
:stop "2018-01-01T09:00:00+0530")
(:name "Programming"
:start "2018-01-02T23:00:00+0530"
:stop "2018-01-03T01:00:00+0530")
(:name "Cooking"
:start "2018-01-03T23:00:00+0530"
:stop "2018-01-04T01:00:00+0530")
(:name "Programming"
:tags (bug-hunting)
:project "Chronometrist"
:component "goals"
:start "2020-05-09T20:03:25+0530"
:stop "2020-05-09T20:05:55+0530")
(:name "Arrangement/new edition"
:tags (new edition)
:song "Songs of Travel"
:composer "Vaughan Williams, Ralph"
:start "2020-05-10T00:04:14+0530"
:stop "2020-05-10T00:25:48+0530")
(:name "Guitar"
:tags (classical warm-up)
:start "2020-05-10T15:41:14+0530"
:stop "2020-05-10T15:55:42+0530")
(:name "Guitar"
:tags (classical solo)
:start "2020-05-10T16:00:00+0530"
:stop "2020-05-10T16:30:00+0530")
(:name "Programming"
:tags (reading)
:book "Smalltalk-80: The Language and Its Implementation"
:start "2020-05-10T16:33:17+0530"
:stop "2020-05-10T17:10:48+0530")))
#+END_SRC
** cleanup
#+BEGIN_SRC emacs-lisp
(cl-defgeneric chronometrist-backend-test-cleanup (backend)
"Delete any files created by BACKEND during testing.")
(cl-defmethod chronometrist-backend-test-cleanup ((backend chronometrist-elisp-sexp-backend))
2022-01-13 16:20:28 +00:00
(with-slots (file hash-table) backend
(when file
(when (file-exists-p file)
(delete-file file))
(with-current-buffer (get-file-buffer file)
;; (erase-buffer)
;; Unsuccessful attempt to inhibit "Delete excess backup versions of <file>?" prompts
(defvar delete-old-versions)
(let ((delete-old-versions t))
(set-buffer-modified-p nil)
2022-01-13 16:20:28 +00:00
(kill-buffer))))
(setf hash-table (clrhash hash-table))))
(cl-defmethod chronometrist-backend-test-cleanup :after ((backend t))
(setf chronometrist-test-backends (chronometrist-make-test-backends)))
#+END_SRC
** ert-deftest :macro:
:PROPERTIES:
:CUSTOM_ID: chronometrist-ert-deftest
:END:
#+BEGIN_SRC emacs-lisp
(defmacro chronometrist-ert-deftest (name backend-var &rest test-forms)
"Generate test groups containing TEST-FORMS for each backend.
BACKEND-VAR is bound to each backend in
`chronometrist-test-backends'. TEST-FORMS are passed to
`ert-deftest'."
(declare (indent defun) (debug t))
(cl-loop for backend in chronometrist-test-backends collect
(let* ((backend-name (string-remove-suffix
"-backend"
(string-remove-prefix "chronometrist"
(symbol-name
(eieio-object-class-name backend)))))
(test-name (concat "chronometrist-" (symbol-name name) backend-name)))
`(ert-deftest ,(intern test-name) ()
(let ((,backend-var ,backend))
(unwind-protect
(progn ,@test-forms)
;; cleanup - remove test backend file
(chronometrist-backend-test-cleanup ,backend)))))
into test-groups
finally return (cons 'progn test-groups)))
#+END_SRC
* Tests
** common
*** current-task
2022-01-13 17:15:03 +00:00
:PROPERTIES:
:CUSTOM_ID: tests-common-current-task
:END:
#+BEGIN_SRC emacs-lisp
2022-01-12 08:43:04 +00:00
(chronometrist-ert-deftest current-task b
2022-01-13 16:24:06 +00:00
;; (message "current-task test - hash-table-count %s" (hash-table-count (chronometrist-backend-hash-table b)))
2022-01-12 08:43:04 +00:00
(chronometrist-create-file b)
(should (not (chronometrist-current-task b)))
(chronometrist-insert b (list :name "Test" :start (chronometrist-format-time-iso8601)))
(should (equal "Test" (chronometrist-current-task b)))
(chronometrist-remove-last b)
(should (not (chronometrist-current-task b))))
#+END_SRC
2021-11-17 20:46:45 +00:00
*** plist-p
2022-01-13 17:15:03 +00:00
:PROPERTIES:
:CUSTOM_ID: tests-common-plist-p
:END:
2021-11-17 20:46:45 +00:00
#+BEGIN_SRC emacs-lisp
(ert-deftest chronometrist-plist-p ()
(should (eq t (chronometrist-plist-p '(:a 1 :b 2))))
(should (eq nil (chronometrist-plist-p '(0 :a 1 :b 2))))
(should (eq nil (chronometrist-plist-p '(:a 1 :b 2 3))))
(should (not (chronometrist-plist-p nil))))
#+END_SRC
2021-12-02 12:12:21 +00:00
*** plists-split-p
2022-01-13 17:15:03 +00:00
:PROPERTIES:
:CUSTOM_ID: tests-common-plists-split-p
:END:
2021-12-02 12:12:21 +00:00
#+BEGIN_SRC emacs-lisp
(ert-deftest chronometrist-plists-split-p ()
(should
(chronometrist-plists-split-p
'(:name "Cooking"
:recipe "whole wheat penne rigate in arrabbiata sauce"
:start "2021-11-30T23:01:10+0530"
:stop "2021-12-01T00:00:00+0530")
'(:name "Cooking"
:recipe "whole wheat penne rigate in arrabbiata sauce"
:start "2021-12-01T00:00:00+0530"
:stop "2021-12-01T00:06:22+0530")))
;; without :stop
(should
(chronometrist-plists-split-p
'(:name "Cooking"
:recipe "whole wheat penne rigate in arrabbiata sauce"
:start "2021-11-30T23:01:10+0530"
:stop "2021-12-01T00:00:00+0530")
'(:name "Cooking"
:recipe "whole wheat penne rigate in arrabbiata sauce"
:start "2021-12-01T00:00:00+0530")))
;; difference in time
(should
(not (chronometrist-plists-split-p
'(:name "Cooking"
:recipe "whole wheat penne rigate in arrabbiata sauce"
:start "2021-11-30T23:01:10+0530"
:stop "2021-12-01T00:00:00+0530")
'(:name "Cooking"
:recipe "whole wheat penne rigate in arrabbiata sauce"
:start "2021-12-01T00:00:01+0530"
:stop "2021-12-01T00:06:22+0530"))))
;; difference in key-values
(should
(not (chronometrist-plists-split-p
'(:name "Cooking"
:recipe "whole wheat penne rigate in arrabbiata sauce"
:start "2021-11-30T23:01:10+0530"
:stop "2021-12-01T00:00:00+0530")
'(:name "Cooking"
:start "2021-12-01T00:00:00+0530"
:stop "2021-12-01T00:06:22+0530")))))
#+END_SRC
** data structures
*** list-tasks
#+BEGIN_SRC emacs-lisp
2022-01-13 16:23:13 +00:00
(chronometrist-ert-deftest list-tasks b
;; (message "list-tasks test - hash-table-count %s" (hash-table-count (chronometrist-backend-hash-table b)))
(chronometrist-create-file b)
(let ((task-list (chronometrist-list-tasks b)))
(should (listp task-list))
(should (seq-every-p #'stringp task-list))))
#+END_SRC
2021-11-17 20:46:45 +00:00
** time functions
2022-01-13 16:24:51 +00:00
*** format-duration-long :pure:
2021-11-17 20:46:45 +00:00
#+BEGIN_SRC emacs-lisp
(ert-deftest chronometrist-format-duration-long ()
(should (equal (chronometrist-format-duration-long 5) ""))
(should (equal (chronometrist-format-duration-long 65) "1 minute"))
(should (equal (chronometrist-format-duration-long 125) "2 minutes"))
(should (equal (chronometrist-format-duration-long 3605) "1 hour"))
(should (equal (chronometrist-format-duration-long 3660) "1 hour, 1 minute"))
(should (equal (chronometrist-format-duration-long 3725) "1 hour, 2 minutes"))
(should (equal (chronometrist-format-duration-long 7200) "2 hours"))
(should (equal (chronometrist-format-duration-long 7260) "2 hours, 1 minute"))
(should (equal (chronometrist-format-duration-long 7320) "2 hours, 2 minutes")))
#+END_SRC
** plist pretty-printing
[[file:../elisp/chronometrist.org::#program-pretty-printer][source]]
2021-11-17 20:46:45 +00:00
*** plist-group-p
#+BEGIN_SRC emacs-lisp
(ert-deftest chronometrist-plist-group-p ()
2021-12-01 11:38:57 +00:00
(should (eq t (chronometrist-plist-group-p '(symbol (:a 1 :b 2)))))
2021-11-17 20:46:45 +00:00
(should (eq t (chronometrist-plist-group-p '("string" (:a 1 :b 2)))))
(should (not (chronometrist-plist-group-p nil)))
(should (not (chronometrist-plist-group-p '("string")))))
#+END_SRC
*** plist-pp-to-string
#+BEGIN_SRC emacs-lisp
(ert-deftest chronometrist-pp-to-string ()
(should
(equal
(chronometrist-pp-to-string
'(:name "Task"
:tags (foo bar)
:comment ((70 . "baz")
"zot"
(16 . "frob")
(20 20 "quux"))
:start "2020-06-25T19:27:57+0530"
:stop "2020-06-25T19:43:30+0530"))
(concat
"(:name \"Task\"\n"
" :tags (foo bar)\n"
" :comment ((70 . \"baz\")\n"
" \"zot\"\n"
" (16 . \"frob\")\n"
" (20 20 \"quux\"))\n"
" :start \"2020-06-25T19:27:57+0530\"\n"
" :stop \"2020-06-25T19:43:30+0530\")")))
(should
(equal
(chronometrist-pp-to-string
'(:name "Singing"
:tags (classical solo)
:piece ((:composer "Gioachino Rossini"
:name "Il barbiere di Siviglia"
:aria ("All'idea di quel metallo" "Dunque io son"))
(:composer "Ralph Vaughan Williams"
:name "Songs of Travel"
:movement ((4 . "Youth and Love")
(5 . "In Dreams")
(7 . "Wither Must I Wander?")))
(:composer "Ralph Vaughan Williams"
:name "Merciless Beauty"
:movement 1)
(:composer "Franz Schubert"
:name "Winterreise"
:movement ((1 . "Gute Nacht")
(2 . "Die Wetterfahne")
(4 . "Erstarrung"))))
:start "2020-11-01T12:01:20+0530"
:stop "2020-11-01T13:08:32+0530"))
(concat
"(:name \"Singing\"\n"
" :tags (classical solo)\n"
" :piece ((:composer \"Gioachino Rossini\"\n"
" :name \"Il barbiere di Siviglia\"\n"
" :aria (\"All'idea di quel metallo\" \"Dunque io son\"))\n"
" (:composer \"Ralph Vaughan Williams\"\n"
" :name \"Songs of Travel\"\n"
" :movement ((4 . \"Youth and Love\")\n"
" (5 . \"In Dreams\")\n"
" (7 . \"Wither Must I Wander?\")))\n"
" (:composer \"Ralph Vaughan Williams\"\n"
" :name \"Merciless Beauty\"\n"
" :movement 1)\n"
" (:composer \"Franz Schubert\"\n"
" :name \"Winterreise\"\n"
" :movement ((1 . \"Gute Nacht\")\n"
" (2 . \"Die Wetterfahne\")\n"
" (4 . \"Erstarrung\"))))\n"
" :start \"2020-11-01T12:01:20+0530\"\n"
" :stop \"2020-11-01T13:08:32+0530\")")))
(should (equal
(chronometrist-pp-to-string
'(:name "Cooking"
:tags (lunch)
:recipe (:name "moong-masoor ki dal"
:url "https://www.mirchitales.com/moong-masoor-dal-red-and-yellow-lentil-curry/")
:start "2020-09-23T15:22:39+0530"
:stop "2020-09-23T16:29:49+0530"))
(concat
"(:name \"Cooking\"\n"
" :tags (lunch)\n"
" :recipe (:name \"moong-masoor ki dal\"\n"
" :url \"https://www.mirchitales.com/moong-masoor-dal-red-and-yellow-lentil-curry/\")\n"
" :start \"2020-09-23T15:22:39+0530\"\n"
" :stop \"2020-09-23T16:29:49+0530\")")))
(should (equal
(chronometrist-pp-to-string
'(:name "Exercise"
:tags (warm-up)
:start "2018-11-21T15:35:04+0530"
:stop "2018-11-21T15:38:41+0530"
:comment ("stretching" (25 10 "push-ups"))))
(concat
"(:name \"Exercise\"\n"
" :tags (warm-up)\n"
" :start \"2018-11-21T15:35:04+0530\"\n"
" :stop \"2018-11-21T15:38:41+0530\"\n"
" :comment (\"stretching\" (25 10 \"push-ups\")))")))
(should (equal
(chronometrist-pp-to-string
'(:name "Guitar"
:tags (classical)
:warm-up ((right-hand-patterns "pima" "piam" "pmia" "pmai" "pami" "paim"))
:start "2021-09-28T17:49:18+0530"
:stop "2021-09-28T17:53:49+0530"))
(concat
"(:name \"Guitar\"\n"
" :tags (classical)\n"
" :warm-up ((right-hand-patterns \"pima\" \"piam\" \"pmia\" \"pmai\" \"pami\" \"paim\"))\n"
" :start \"2021-09-28T17:49:18+0530\"\n"
" :stop \"2021-09-28T17:53:49+0530\")")))
(should (equal
(chronometrist-pp-to-string
'(:name "Cooking"
:tags (lunch)
:recipe ("urad dhuli"
(:name "brown rice"
:brand "Dawat quick-cooking"
:quantity "40% of steel measuring glass"
:water "2× dry rice"))
:start "2021-11-07T14:40:45+0530"
:stop "2021-11-07T15:28:13+0530"))
(concat
"(:name \"Cooking\"\n"
" :tags (lunch)\n"
" :recipe (\"urad dhuli\"\n"
" (:name \"brown rice\"\n"
" :brand \"Dawat quick-cooking\"\n"
" :quantity \"40% of steel measuring glass\"\n"
" :water \"2× dry rice\"))\n"
" :start \"2021-11-07T14:40:45+0530\"\n"
" :stop \"2021-11-07T15:28:13+0530\")"))))
#+END_SRC
** backend
2021-12-23 15:03:22 +00:00
Situations
1. no file
2. empty file
3. non-empty file with no records
4. single record
* active
* inactive
* active, day-crossing
* inactive, day-crossing
5. multiple records
6. +[plist-group] latest plist is split+ (covered in #4)
2021-12-23 15:03:22 +00:00
Tests to be added -
1. to-hash-table
2. to-file
The order of these tests is important - the last test for each case is one which moves into the next case.
*** create-file
2022-01-13 17:15:03 +00:00
:PROPERTIES:
:CUSTOM_ID: tests-backend-create-file
:END:
#+BEGIN_SRC emacs-lisp
(chronometrist-ert-deftest create-file b
2022-01-13 16:24:06 +00:00
;; (message "create-file test - hash-table-count %s" (hash-table-count (chronometrist-backend-hash-table b)))
;; * file does not exist *
(should (chronometrist-create-file b))
;; * file exists but has no records *
(should (not (chronometrist-create-file b))))
#+END_SRC
*** latest-date-records
#+BEGIN_SRC emacs-lisp
(chronometrist-ert-deftest latest-date-records b
2022-01-13 16:24:06 +00:00
;; (message "latest-date-records test - hash-table-count %s" (hash-table-count (chronometrist-backend-hash-table b)))
(let ((plist-1 (cl-first chronometrist-test-records))
(plist-2 (cl-second chronometrist-test-records))
(today-ts (chronometrist-date-ts)))
;; * file does not exist *
(should-error (chronometrist-latest-date-records b))
(should (chronometrist-create-file b))
;; (message "latest-date-records: %S" (chronometrist-latest-date-records b))
;; * file exists but has no records *
(should (not (chronometrist-latest-date-records b)))
(should (chronometrist-insert b plist-1))
;; * backend has a single active record *
;; * backend has a single inactive record *
;; * backend has a single active day-crossing record *
;; * backend has a single inactive day-crossing record *
;; * backend has two records and one is active *
;; * backend has two records and both are inactive *
;; * backend has two day-crossing records and one is active *
;; * backend has two day-crossing records and both are inactive *
))
#+END_SRC
*** insert
#+BEGIN_SRC emacs-lisp
(chronometrist-ert-deftest insert b
2022-01-13 16:24:06 +00:00
;; (message "insert test - hash-table-count %s" (hash-table-count (chronometrist-backend-hash-table b)))
2022-01-14 16:18:32 +00:00
(let* ((plist1 (list :name "Test" :start (chronometrist-format-time-iso8601)))
(plist2 (append plist1 (list :stop (chronometrist-format-time-iso8601)))))
;; * file does not exist *
2022-01-14 16:18:32 +00:00
(should-error (chronometrist-insert b plist1))
(should (chronometrist-create-file b))
;; * file exists but has no records *
2022-01-14 16:18:32 +00:00
(should (chronometrist-insert b plist1))
(should (equal (progn (chronometrist-reset-backend b)
(chronometrist-latest-date-records b))
(list (chronometrist-date-iso) plist1)))
;; * backend has a single active record *
2022-01-14 16:18:32 +00:00
(should (chronometrist-replace-last b plist2))
(should (equal (progn (chronometrist-reset-backend b)
(chronometrist-latest-date-records b))
(list (chronometrist-date-iso) plist2)))
;; * backend has a single inactive record *
;; * backend has a single active day-crossing record *
;; * backend has a single inactive day-crossing record *
;; * backend has two records and one is active *
;; * backend has two records and both are inactive *
;; * backend has two day-crossing records and one is active *
;; * backend has two day-crossing records and both are inactive *
))
#+END_SRC
2022-01-13 16:24:51 +00:00
* Local Variables
# Local Variables:
# delete-old-versions: t
# End: