Compare commits
5 Commits
Author | SHA1 | Date |
---|---|---|
contrapunctus | 68c5a356c5 | |
contrapunctus | a532c0b1c4 | |
contrapunctus | d7198f9932 | |
contrapunctus | 687b5f169c | |
contrapunctus | be1a158db4 |
1
TODO.org
1
TODO.org
|
@ -290,6 +290,7 @@ Some options and ideas -
|
|||
* Actually, are transformers really necessary? It could be done with a function inserted by =chronometrist-goal= into =chronometrist-mode-hook=. The function itself would become a little more complex, but it would remove the two transformer lists + the =call-transformers= dependency from the code. =chronometrist-mode-hook= is required either way, to set up =chronometrist-goal=.
|
||||
+ Turns out, they are. We set =tabulated-list-entries= to a function. To modify the value, we must hook into that function in some way. =tabulated-list-format= could be modified in a regular hook, but it feels more consistent to make it a transformer too 🤔
|
||||
8. [ ] Ugly code - =chronometrist-print-non-tabular=; =insert-text-button= can be replaced with =make-text-button=
|
||||
9. [ ] Duplication in tests for saving and restoring user state when run interactively
|
||||
|
||||
** Documentation [0%]
|
||||
1. [ ] Move usage and customization sections to manual.org
|
||||
|
|
|
@ -210,7 +210,7 @@ HISTORY-TABLE must be a hash table. (see `chronometrist-tags-history')"
|
|||
(chronometrist-history-prep task history-table))
|
||||
#+END_SRC
|
||||
**** tests
|
||||
#+BEGIN_SRC emacs-lisp :tangle chronometrist-key-values-tests.el :load test
|
||||
#+BEGIN_SRC emacs-lisp :tangle ../tests/chronometrist-key-values-tests.el :load test
|
||||
(ert-deftest chronometrist-tags-history ()
|
||||
(progn
|
||||
(clrhash chronometrist-tags-history)
|
||||
|
@ -371,7 +371,7 @@ HISTORY-TABLE must be a hash table (see `chronometrist-key-history')."
|
|||
(chronometrist-history-prep task history-table))
|
||||
#+END_SRC
|
||||
**** tests
|
||||
#+BEGIN_SRC emacs-lisp :tangle chronometrist-key-values-tests.el :load test
|
||||
#+BEGIN_SRC emacs-lisp :tangle ../tests/chronometrist-key-values-tests.el :load test
|
||||
(ert-deftest chronometrist-key-history ()
|
||||
(progn
|
||||
(clrhash chronometrist-key-history)
|
||||
|
@ -419,7 +419,7 @@ HISTORY-TABLE must be a hash table. (see `chronometrist-value-history')"
|
|||
history-table))
|
||||
#+END_SRC
|
||||
**** tests
|
||||
#+BEGIN_SRC emacs-lisp :tangle chronometrist-key-values-tests.el :load test
|
||||
#+BEGIN_SRC emacs-lisp :tangle ../tests/chronometrist-key-values-tests.el :load test
|
||||
(ert-deftest chronometrist-value-history ()
|
||||
(progn
|
||||
(clrhash chronometrist-value-history)
|
||||
|
|
|
@ -183,7 +183,7 @@ TS must be a ts struct (see `ts.el')."
|
|||
(chronometrist-plist-remove plist :name :tags :start :stop))
|
||||
|
||||
(defun chronometrist-plist-p (list)
|
||||
"Return non-nil if LIST is a property list, i.e. (:KEYWORD VALUE ...)"
|
||||
"Return non-nil if LIST is a property list, i.e. (:KEYWORD VALUE ...)."
|
||||
(while (consp list)
|
||||
(setq list (if (and (keywordp (car list))
|
||||
(consp (cdr list)))
|
||||
|
@ -238,7 +238,9 @@ that point is after the first opening parenthesis."
|
|||
|
||||
(cl-defun chronometrist-plist-pp-buffer (&optional inside-sublist-p)
|
||||
"Recursively indent the alist, plist, or a list of plists after point.
|
||||
The list must be on a single line, as emitted by `prin1'."
|
||||
The list must be on a single line, as emitted by `prin1'.
|
||||
INSIDE-SUBLIST-P, if non-nil, means point is inside a sublist
|
||||
value."
|
||||
(if (not (looking-at-p (rx (or ")" line-end))))
|
||||
(let ((sexp (save-excursion (read (current-buffer)))))
|
||||
(cond
|
||||
|
@ -268,7 +270,9 @@ The list must be on a single line, as emitted by `prin1'."
|
|||
(forward-char)))))
|
||||
|
||||
(defun chronometrist-plist-pp-buffer-plist (&optional inside-sublist-p)
|
||||
"Indent a single plist after point."
|
||||
"Indent a single plist after point.
|
||||
INSIDE-SUBLIST-P, if non-nil, means point is inside a sublist
|
||||
value."
|
||||
(down-list)
|
||||
(let ((left-indent (1- (chronometrist-plist-pp-column)))
|
||||
(right-indent (chronometrist-plist-pp-longest-keyword-length))
|
||||
|
@ -373,7 +377,7 @@ STREAM (which is the value of `current-buffer')."
|
|||
|
||||
(defmacro chronometrist-loop-file (_for expr _in file &rest loop-clauses)
|
||||
"`cl-loop' LOOP-CLAUSES over s-expressions in FILE, in reverse.
|
||||
VAR is bound to each s-expression."
|
||||
EXPR is bound to each s-expression."
|
||||
(declare (indent defun)
|
||||
(debug nil)
|
||||
;; FIXME
|
||||
|
|
|
@ -396,6 +396,10 @@ But I discovered that if I do that, =package-lint= says - =error: Couldn't parse
|
|||
(defvar chronometrist-mode-map)
|
||||
(require 'subr-x))
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC emacs-lisp :tangle ../tests/chronometrist-tests.el :load test
|
||||
(require 'chronometrist)
|
||||
#+END_SRC
|
||||
** Common
|
||||
*** custom group :custom:group:
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
|
@ -419,7 +423,7 @@ file.")
|
|||
"Return the name of the currently clocked-in task, or nil if not clocked in."
|
||||
(chronometrist-sexp-current-task))
|
||||
#+END_SRC
|
||||
*** format-time :function:
|
||||
*** format-duration :function:
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(cl-defun chronometrist-format-duration (seconds &optional (blank (make-string 3 ?\s)))
|
||||
"Format SECONDS as a string suitable for display in Chronometrist buffers.
|
||||
|
@ -439,6 +443,27 @@ supplied, 3 spaces are used."
|
|||
(format "%02d" s))))
|
||||
(concat h m s)))))
|
||||
#+END_SRC
|
||||
**** tests
|
||||
#+BEGIN_SRC emacs-lisp :tangle ../tests/chronometrist-tests.el :load test
|
||||
(ert-deftest chronometrist-format-duration ()
|
||||
(should
|
||||
(equal (chronometrist-format-duration 0) " -"))
|
||||
(should
|
||||
(equal (chronometrist-format-duration 1) " 1"))
|
||||
(should
|
||||
(equal (chronometrist-format-duration 10) " 10"))
|
||||
(should
|
||||
(equal (chronometrist-format-duration 70) " 1:10"))
|
||||
(should
|
||||
(equal (chronometrist-format-duration (+ (* 10 60) 10))
|
||||
" 10:10"))
|
||||
(should
|
||||
(equal (chronometrist-format-duration (+ (* 1 60 60) (* 10 60) 10))
|
||||
" 1:10:10"))
|
||||
(should
|
||||
(equal (chronometrist-format-duration (+ (* 10 60 60) (* 10 60) 10))
|
||||
"10:10:10")))
|
||||
#+END_SRC
|
||||
*** file-empty-p :reader:
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun chronometrist-common-file-empty-p (file)
|
||||
|
@ -524,6 +549,30 @@ TS must be a ts struct (see `ts.el')."
|
|||
do (ts-decf (ts-day ts))
|
||||
finally return ts))
|
||||
#+END_SRC
|
||||
|
||||
**** tests
|
||||
#+BEGIN_SRC emacs-lisp :tangle ../tests/chronometrist-tests.el :load test
|
||||
(ert-deftest chronometrist-previous-week-start ()
|
||||
(let ((chronometrist-report-week-start-day "Sunday")
|
||||
(ts (chronometrist-iso-date-to-ts "2018-09-02")))
|
||||
(should (ts= (chronometrist-previous-week-start
|
||||
(chronometrist-iso-date-to-ts "2018-09-01"))
|
||||
(chronometrist-iso-date-to-ts "2018-08-26")))
|
||||
(should (ts= ts (chronometrist-previous-week-start
|
||||
(chronometrist-iso-date-to-ts "2018-09-02"))))
|
||||
(should (ts= ts (chronometrist-previous-week-start
|
||||
(chronometrist-iso-date-to-ts "2018-09-03"))))
|
||||
(should (ts= ts (chronometrist-previous-week-start
|
||||
(chronometrist-iso-date-to-ts "2018-09-04"))))
|
||||
(should (ts= ts (chronometrist-previous-week-start
|
||||
(chronometrist-iso-date-to-ts "2018-09-05"))))
|
||||
(should (ts= ts (chronometrist-previous-week-start
|
||||
(chronometrist-iso-date-to-ts "2018-09-06"))))
|
||||
(should (ts= ts (chronometrist-previous-week-start
|
||||
(chronometrist-iso-date-to-ts "2018-09-07"))))
|
||||
(should (ts= ts (chronometrist-previous-week-start
|
||||
(chronometrist-iso-date-to-ts "2018-09-08"))))))
|
||||
#+END_SRC
|
||||
*** plist-remove :function:
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun chronometrist-plist-remove (plist &rest keys)
|
||||
|
@ -537,12 +586,14 @@ TS must be a ts struct (see `ts.el')."
|
|||
plist))
|
||||
#+END_SRC
|
||||
**** tests
|
||||
#+BEGIN_SRC emacs-lisp :tangle chronometrist-tests.el :load test
|
||||
#+BEGIN_SRC emacs-lisp :tangle ../tests/chronometrist-tests.el :load test
|
||||
(ert-deftest chronometrist-plist-remove ()
|
||||
(should
|
||||
|
||||
(equal (chronometrist-plist-remove '(:a 1 :b 2 :c 3 :d 4) :a)
|
||||
'(:b 2 :c 3 :d 4)))
|
||||
(should
|
||||
|
||||
(equal (chronometrist-plist-remove '(:a 1 :b 2 :c 3 :d 4) :b)
|
||||
'(:a 1 :c 3 :d 4)))
|
||||
(should
|
||||
|
@ -577,7 +628,7 @@ TS must be a ts struct (see `ts.el')."
|
|||
*** plist-p :function:
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun chronometrist-plist-p (list)
|
||||
"Return non-nil if LIST is a property list, i.e. (:KEYWORD VALUE ...)"
|
||||
"Return non-nil if LIST is a property list, i.e. (:KEYWORD VALUE ...)."
|
||||
(while (consp list)
|
||||
(setq list (if (and (keywordp (car list))
|
||||
(consp (cdr list)))
|
||||
|
@ -586,7 +637,7 @@ TS must be a ts struct (see `ts.el')."
|
|||
(null list))
|
||||
#+END_SRC
|
||||
**** tests
|
||||
#+BEGIN_SRC emacs-lisp :tangle chronometrist-tests.el :load test
|
||||
#+BEGIN_SRC emacs-lisp :tangle ../tests/chronometrist-tests.el :load test
|
||||
(ert-deftest plist-p ()
|
||||
(should (eq t (chronometrist-plist-p '(:a 1 :b 2))))
|
||||
(should (eq nil (chronometrist-plist-p '(0 :a 1 :b 2))))
|
||||
|
@ -669,7 +720,9 @@ It might help to make =inside-sublist-p= an integer representing depth, instead
|
|||
#+BEGIN_SRC emacs-lisp
|
||||
(cl-defun chronometrist-plist-pp-buffer (&optional inside-sublist-p)
|
||||
"Recursively indent the alist, plist, or a list of plists after point.
|
||||
The list must be on a single line, as emitted by `prin1'."
|
||||
The list must be on a single line, as emitted by `prin1'.
|
||||
INSIDE-SUBLIST-P, if non-nil, means point is inside a sublist
|
||||
value."
|
||||
(if (not (looking-at-p (rx (or ")" line-end))))
|
||||
(let ((sexp (save-excursion (read (current-buffer)))))
|
||||
(cond
|
||||
|
@ -699,7 +752,7 @@ The list must be on a single line, as emitted by `prin1'."
|
|||
(forward-char)))))
|
||||
#+END_SRC
|
||||
**** tests
|
||||
#+BEGIN_SRC emacs-lisp :tangle chronometrist-tests.el :load test
|
||||
#+BEGIN_SRC emacs-lisp :tangle ../tests/chronometrist-tests.el :load test
|
||||
(ert-deftest plist-pp-buffer ()
|
||||
(should
|
||||
(equal
|
||||
|
@ -797,7 +850,9 @@ The list must be on a single line, as emitted by `prin1'."
|
|||
*** buffer-plist :writer:
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defun chronometrist-plist-pp-buffer-plist (&optional inside-sublist-p)
|
||||
"Indent a single plist after point."
|
||||
"Indent a single plist after point.
|
||||
INSIDE-SUBLIST-P, if non-nil, means point is inside a sublist
|
||||
value."
|
||||
(down-list)
|
||||
(let ((left-indent (1- (chronometrist-plist-pp-column)))
|
||||
(right-indent (chronometrist-plist-pp-longest-keyword-length))
|
||||
|
@ -894,7 +949,7 @@ The reasons I like this format are -
|
|||
|
||||
*** tests
|
||||
:PROPERTIES:
|
||||
:header-args: :tangle chronometrist-tests.el
|
||||
:header-args: :tangle ../tests/chronometrist-tests.el
|
||||
:END:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp :load test
|
||||
|
@ -902,7 +957,7 @@ The reasons I like this format are -
|
|||
(make-temp-file
|
||||
"chronometrist-test-" nil ".sexp"
|
||||
(with-output-to-string
|
||||
(mapcar
|
||||
(mapc
|
||||
(lambda (plist)
|
||||
;; to use this, we'd have to move `chronometrist-plist-pp' before this
|
||||
;; definition, and I'm perfectly content with where it is
|
||||
|
@ -970,6 +1025,7 @@ Boilerplate for updating state between file operations in tests.
|
|||
(list :last (chronometrist-file-hash :before-last nil)
|
||||
:rest (chronometrist-file-hash nil :before-last t)))))
|
||||
#+END_SRC
|
||||
|
||||
*** chronometrist-file :custom:variable:
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defcustom chronometrist-file
|
||||
|
@ -1025,7 +1081,7 @@ STREAM (which is the value of `current-buffer')."
|
|||
#+BEGIN_SRC emacs-lisp
|
||||
(defmacro chronometrist-loop-file (_for expr _in file &rest loop-clauses)
|
||||
"`cl-loop' LOOP-CLAUSES over s-expressions in FILE, in reverse.
|
||||
VAR is bound to each s-expression."
|
||||
EXPR is bound to each s-expression."
|
||||
(declare (indent defun)
|
||||
(debug nil)
|
||||
;; FIXME
|
||||
|
@ -1169,7 +1225,7 @@ This is meant to be run in `chronometrist-file' when using the s-expression back
|
|||
(sort it #'string-lessp)))
|
||||
#+END_SRC
|
||||
**** tests
|
||||
#+BEGIN_SRC emacs-lisp :tangle chronometrist-tests.el :load test
|
||||
#+BEGIN_SRC emacs-lisp :tangle ../tests/chronometrist-tests.el :load test
|
||||
(ert-deftest task-list ()
|
||||
(let ((task-list (chronometrist-task-list)))
|
||||
(should (listp task-list))
|
||||
|
@ -1233,7 +1289,7 @@ in `chronometrist-file' describing the region for which HASH was calculated."
|
|||
(list start end)))))
|
||||
#+END_SRC
|
||||
**** tests
|
||||
#+BEGIN_SRC emacs-lisp :tangle chronometrist-tests.el :load test
|
||||
#+BEGIN_SRC emacs-lisp :tangle ../tests/chronometrist-tests.el :load test
|
||||
(ert-deftest file-hash ()
|
||||
(-let* ((chronometrist-file chronometrist-test-file)
|
||||
((last-start last-end)
|
||||
|
@ -1312,7 +1368,7 @@ Return
|
|||
:modify))))
|
||||
#+END_SRC
|
||||
**** tests
|
||||
#+BEGIN_SRC emacs-lisp :tangle chronometrist-tests.el :load test
|
||||
#+BEGIN_SRC emacs-lisp :tangle ../tests/chronometrist-tests.el :load test
|
||||
(ert-deftest chronometrist-file-change-type ()
|
||||
(let* ((chronometrist-file chronometrist-test-file)
|
||||
(test-contents (with-current-buffer (find-file-noselect chronometrist-file)
|
||||
|
@ -1363,6 +1419,7 @@ Return
|
|||
(current-buffer))
|
||||
(save-buffer))
|
||||
(chronometrist-tests--change-type-and-update chronometrist--file-state)))))
|
||||
;; restore test file contents
|
||||
(with-current-buffer (find-file-noselect chronometrist-file)
|
||||
(delete-region (point-min) (point-max))
|
||||
(insert test-contents)
|
||||
|
@ -1529,7 +1586,7 @@ Return value is a ts struct (see `ts.el')."
|
|||
(chronometrist-iso-timestamp-to-ts timestamp))))
|
||||
#+END_SRC
|
||||
**** tests
|
||||
#+BEGIN_SRC emacs-lisp :tangle chronometrist-tests.el :load test
|
||||
#+BEGIN_SRC emacs-lisp :tangle ../tests/chronometrist-tests.el :load test
|
||||
(ert-deftest chronometrist-apply-time ()
|
||||
(should
|
||||
(equal (ts-format "%FT%T%z" (chronometrist-apply-time "01:02:03" "2021-02-17T01:20:18+0530"))
|
||||
|
@ -1563,7 +1620,7 @@ Return a list of two events if EVENT was split, else nil."
|
|||
#+END_SRC
|
||||
|
||||
**** tests
|
||||
#+BEGIN_SRC emacs-lisp :tangle chronometrist-tests.el :load test
|
||||
#+BEGIN_SRC emacs-lisp :tangle ../tests/chronometrist-tests.el :load test
|
||||
(ert-deftest chronometrist-events-maybe-split ()
|
||||
(should
|
||||
(null (chronometrist-events-maybe-split
|
||||
|
@ -1682,6 +1739,47 @@ The return value is seconds, as an integer."
|
|||
;; no events for this task on TS, i.e. no time spent
|
||||
0)))
|
||||
#+END_SRC
|
||||
**** tests
|
||||
#+BEGIN_SRC emacs-lisp :tangle ../tests/chronometrist-tests.el :load test
|
||||
(ert-deftest chronometrist-task-time-one-day ()
|
||||
(let ((chronometrist-file-old chronometrist-file)
|
||||
(chronometrist-file chronometrist-test-file)
|
||||
(chronometrist--file-state-old chronometrist--file-state)
|
||||
(chronometrist-events-old chronometrist-events)
|
||||
(ts-1 (chronometrist-iso-date-to-ts "2018-01-01"))
|
||||
(ts-2 (chronometrist-iso-date-to-ts "2018-01-02"))
|
||||
(ts-3 (chronometrist-iso-date-to-ts "2018-01-03"))
|
||||
(1-hour 3600))
|
||||
(chronometrist-events-populate)
|
||||
(unwind-protect
|
||||
(progn
|
||||
(should
|
||||
(equal (chronometrist-task-time-one-day "Programming" ts-1)
|
||||
1-hour))
|
||||
(should
|
||||
(equal (chronometrist-task-time-one-day "Swimming" ts-1)
|
||||
1-hour))
|
||||
(should
|
||||
(equal (chronometrist-task-time-one-day "Cooking" ts-1)
|
||||
1-hour))
|
||||
(should
|
||||
(equal (chronometrist-task-time-one-day "Guitar" ts-1)
|
||||
1-hour))
|
||||
(should
|
||||
(equal (chronometrist-task-time-one-day "Cycling" ts-1)
|
||||
1-hour))
|
||||
(should
|
||||
(equal (chronometrist-task-time-one-day "Programming" ts-2)
|
||||
1-hour))
|
||||
(should
|
||||
(equal (chronometrist-task-time-one-day "Programming" ts-3)
|
||||
1-hour)))
|
||||
(setq chronometrist-file chronometrist-file-old
|
||||
chronometrist--file-state chronometrist--file-state-old)
|
||||
;; Not sure why simply assigning `chronometrist-events-old' did not restore
|
||||
;; the value - it seems to work in `chronometrist-file-change-type'
|
||||
(chronometrist-events-populate))))
|
||||
#+END_SRC
|
||||
*** active-time-one-day :reader:
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(defvar chronometrist-task-list)
|
||||
|
@ -1829,7 +1927,7 @@ Return a list in the form
|
|||
:stop ,stop-time)))))
|
||||
#+END_SRC
|
||||
**** tests
|
||||
#+BEGIN_SRC emacs-lisp :tangle chronometrist-tests.el :load test
|
||||
#+BEGIN_SRC emacs-lisp :tangle ../tests/chronometrist-tests.el :load test
|
||||
(ert-deftest chronometrist-midnight-spanning-p ()
|
||||
(should
|
||||
(null
|
||||
|
@ -3156,7 +3254,7 @@ ARG must be either tags (a list of symbols) or a plist."
|
|||
#+END_SRC
|
||||
|
||||
***** tests
|
||||
#+BEGIN_SRC emacs-lisp :tangle chronometrist-tests.el :load test
|
||||
#+BEGIN_SRC emacs-lisp :tangle ../tests/chronometrist-tests.el :load test
|
||||
(ert-deftest chronometrist-details-row-helper ()
|
||||
(let ((tags '(a b c))
|
||||
(plist '(:a 1 :b 2 :c 3)))
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
(: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")
|
|
@ -1,42 +0,0 @@
|
|||
;;; -*- lexical-binding: t; -*-
|
||||
(require 'buttercup)
|
||||
(require 'chronometrist)
|
||||
|
||||
(describe
|
||||
"chronometrist-format-time"
|
||||
(it "works with lists"
|
||||
(expect (chronometrist-format-time 0)
|
||||
:to-equal " -")
|
||||
(expect (chronometrist-format-time 1)
|
||||
:to-equal " 1")
|
||||
(expect (chronometrist-format-time 10)
|
||||
:to-equal " 10")
|
||||
(expect (chronometrist-format-time 70)
|
||||
:to-equal " 1:10")
|
||||
(expect (chronometrist-format-time (+ (* 10 60) ;; 10 minutes
|
||||
10)) ;; 10 seconds
|
||||
:to-equal " 10:10")
|
||||
(expect (chronometrist-format-time (+ (* 1 60 60) ;; 1 hour
|
||||
(* 10 60) ;; 10 minutes
|
||||
10)) ;; 10 seconds
|
||||
:to-equal " 1:10:10")
|
||||
(expect (chronometrist-format-time (+ (* 10 60 60) ;; 10 hours
|
||||
(* 10 60) ;; 10 minutes
|
||||
10)) ;; 10 seconds
|
||||
:to-equal "10:10:10")))
|
||||
|
||||
(describe
|
||||
"chronometrist-previous-week-start"
|
||||
:var ((chronometrist-report-week-start-day "Sunday")
|
||||
(ts (chronometrist-iso-date->ts "2018-09-02")))
|
||||
(it "should work with Sundays"
|
||||
(should (ts= (chronometrist-previous-week-start
|
||||
(chronometrist-iso-date->ts "2018-09-01"))
|
||||
(chronometrist-iso-date->ts "2018-08-26")))
|
||||
(should (ts= ts (chronometrist-previous-week-start (chronometrist-iso-date->ts "2018-09-02"))))
|
||||
(should (ts= ts (chronometrist-previous-week-start (chronometrist-iso-date->ts "2018-09-03"))))
|
||||
(should (ts= ts (chronometrist-previous-week-start (chronometrist-iso-date->ts "2018-09-04"))))
|
||||
(should (ts= ts (chronometrist-previous-week-start (chronometrist-iso-date->ts "2018-09-05"))))
|
||||
(should (ts= ts (chronometrist-previous-week-start (chronometrist-iso-date->ts "2018-09-06"))))
|
||||
(should (ts= ts (chronometrist-previous-week-start (chronometrist-iso-date->ts "2018-09-07"))))
|
||||
(should (ts= ts (chronometrist-previous-week-start (chronometrist-iso-date->ts "2018-09-08"))))))
|
|
@ -1,87 +0,0 @@
|
|||
(require 'buttercup)
|
||||
(require 'chronometrist-key-values)
|
||||
|
||||
(describe
|
||||
"chronometrist-plist-remove"
|
||||
(it "works with one key"
|
||||
(expect (chronometrist-plist-remove '(:a 1 :b 2 :c 3 :d 4)
|
||||
:a)
|
||||
:to-equal '(:b 2 :c 3 :d 4))
|
||||
(expect (chronometrist-plist-remove '(:a 1 :b 2 :c 3 :d 4)
|
||||
:b)
|
||||
:to-equal '(:a 1 :c 3 :d 4))
|
||||
(expect (chronometrist-plist-remove '(:a 1 :b 2 :c 3 :d 4)
|
||||
:c)
|
||||
:to-equal '(:a 1 :b 2 :d 4))
|
||||
(expect (chronometrist-plist-remove '(:a 1 :b 2 :c 3 :d 4)
|
||||
:d)
|
||||
:to-equal '(:a 1 :b 2 :c 3)))
|
||||
(it "works with multiple keys"
|
||||
(expect (chronometrist-plist-remove '(:a 1 :b 2 :c 3 :d 4)
|
||||
:a :b)
|
||||
:to-equal '(:c 3 :d 4))
|
||||
(expect (chronometrist-plist-remove '(:a 1 :b 2 :c 3 :d 4)
|
||||
:a :d)
|
||||
:to-equal '(:b 2 :c 3))
|
||||
(expect (chronometrist-plist-remove '(:a 1 :b 2 :c 3 :d 4)
|
||||
:c :d)
|
||||
:to-equal '(:a 1 :b 2))
|
||||
(expect (chronometrist-plist-remove '(:a 1 :b 2 :c 3 :d 4)
|
||||
:a :b :c :d)
|
||||
:to-equal nil))
|
||||
(it "works with keys in any order"
|
||||
(expect (chronometrist-plist-remove '(:a 1 :b 2 :c 3 :d 4)
|
||||
:d :a)
|
||||
:to-equal '(:b 2 :c 3))))
|
||||
|
||||
(describe
|
||||
"chronometrist-tags-history"
|
||||
(before-all
|
||||
(setq chronometrist-file "tests/test.sexp")
|
||||
(chronometrist-events-populate)
|
||||
(chronometrist-tags-history-populate chronometrist-events chronometrist-tags-history))
|
||||
(it "should have 3 hash keys"
|
||||
(expect (hash-table-count chronometrist-tags-history)
|
||||
:to-be 3)
|
||||
(expect (cl-loop for task being the hash-keys of chronometrist-tags-history
|
||||
always (stringp task))
|
||||
:to-be t))
|
||||
(it "should have lists as hash values"
|
||||
(expect (gethash "Guitar" chronometrist-tags-history)
|
||||
:to-equal '((classical solo)
|
||||
(classical warm-up)))
|
||||
(expect (gethash "Programming" chronometrist-tags-history)
|
||||
:to-equal '((reading) (bug-hunting)))))
|
||||
|
||||
(describe
|
||||
"chronometrist-key-history"
|
||||
(before-all
|
||||
(setq chronometrist-file "tests/test.sexp")
|
||||
(chronometrist-events-populate)
|
||||
(setq chronometrist-task-list (chronometrist-tasks-from-table))
|
||||
(chronometrist-key-history-populate chronometrist-events chronometrist-key-history))
|
||||
(it "should have 6 hash keys"
|
||||
(expect (hash-table-count chronometrist-key-history)
|
||||
:to-be 6))
|
||||
(it "should store multiple values"
|
||||
(expect (length (gethash "Programming" chronometrist-key-history))
|
||||
:to-be 3)
|
||||
(expect (length (gethash "Arrangement/new edition" chronometrist-key-history))
|
||||
:to-be 2)))
|
||||
|
||||
(describe
|
||||
"chronometrist-value-history"
|
||||
(before-all
|
||||
(setq chronometrist-file "tests/test.sexp")
|
||||
(chronometrist-events-populate)
|
||||
(chronometrist-value-history-populate chronometrist-events chronometrist-value-history))
|
||||
(it "should have 5 hash keys"
|
||||
(expect (hash-table-count chronometrist-value-history)
|
||||
:to-be 5)
|
||||
(expect (cl-loop for task being the hash-keys of chronometrist-value-history
|
||||
always (stringp task))
|
||||
:to-be t)))
|
||||
|
||||
;; Local Variables:
|
||||
;; nameless-current-name: "chronometrist"
|
||||
;; End:
|
|
@ -0,0 +1,35 @@
|
|||
(ert-deftest chronometrist-tags-history ()
|
||||
(progn
|
||||
(clrhash chronometrist-tags-history)
|
||||
(cl-loop for task in '("Guitar" "Programming") do
|
||||
(chronometrist-tags-history-populate task chronometrist-tags-history "test.sexp")))
|
||||
(should
|
||||
(= (hash-table-count chronometrist-tags-history) 2))
|
||||
(should
|
||||
(cl-loop for task being the hash-keys of chronometrist-tags-history
|
||||
always (stringp task)))
|
||||
(should
|
||||
(equal (gethash "Guitar" chronometrist-tags-history)
|
||||
'((classical solo)
|
||||
(classical warm-up))))
|
||||
(should
|
||||
(equal (gethash "Programming" chronometrist-tags-history)
|
||||
'((reading) (bug-hunting)))))
|
||||
|
||||
(ert-deftest chronometrist-key-history ()
|
||||
(progn
|
||||
(clrhash chronometrist-key-history)
|
||||
(cl-loop for task in '("Programming" "Arrangement/new edition") do
|
||||
(chronometrist-key-history-populate task chronometrist-key-history "test.sexp")))
|
||||
(should (= (hash-table-count chronometrist-key-history) 2))
|
||||
(should (= (length (gethash "Programming" chronometrist-key-history)) 3))
|
||||
(should (= (length (gethash "Arrangement/new edition" chronometrist-key-history)) 2)))
|
||||
|
||||
(ert-deftest chronometrist-value-history ()
|
||||
(progn
|
||||
(clrhash chronometrist-value-history)
|
||||
(chronometrist-value-history-populate chronometrist-value-history "test.sexp"))
|
||||
(should (= (hash-table-count chronometrist-value-history) 5))
|
||||
(should
|
||||
(cl-loop for task being the hash-keys of chronometrist-value-history
|
||||
always (stringp task))))
|
|
@ -1,105 +0,0 @@
|
|||
;; -*- lexical-binding: t; -*-
|
||||
(require 'buttercup)
|
||||
(require 'chronometrist)
|
||||
|
||||
(describe "chronometrist-plist-pp-buffer"
|
||||
:var ((buffer (find-file-noselect "tests/plist-pp-test.sexp")))
|
||||
(it "indents plists nicely"
|
||||
(expect
|
||||
(chronometrist-plist-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"))
|
||||
:to-equal
|
||||
(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\")\n"))
|
||||
(expect
|
||||
(chronometrist-plist-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"))
|
||||
:to-equal
|
||||
(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\")"))
|
||||
(expect
|
||||
(chronometrist-plist-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"))
|
||||
:to-equal
|
||||
(concat
|
||||
"(: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\")"))
|
||||
(expect
|
||||
(chronometrist-plist-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"))))
|
||||
:to-equal
|
||||
(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\")))"))))
|
||||
|
||||
;; Local Variables:
|
||||
;; nameless-current-name: "chronometrist"
|
||||
;; End:
|
|
@ -1,37 +0,0 @@
|
|||
;; -*- lexical-binding: t; -*-
|
||||
(require 'buttercup)
|
||||
(require 'ts)
|
||||
(require 'chronometrist)
|
||||
|
||||
(describe "chronometrist-task-time-one-day"
|
||||
:var ((ts-1 (chronometrist-iso-date->ts "2018-01-01"))
|
||||
(ts-2 (chronometrist-iso-date->ts "2018-01-02"))
|
||||
(ts-3 (chronometrist-iso-date->ts "2018-01-03"))
|
||||
(1-hour 3600))
|
||||
(before-all
|
||||
(setq chronometrist-file-old chronometrist-file
|
||||
chronometrist-file "tests/test.sexp")
|
||||
(chronometrist-events-populate))
|
||||
(after-all
|
||||
(setq chronometrist-file chronometrist-file-old))
|
||||
(it "returns the time spent in one day, in seconds"
|
||||
(expect (chronometrist-task-time-one-day "Programming" ts-1)
|
||||
:to-equal 1-hour)
|
||||
(expect (chronometrist-task-time-one-day "Swimming" ts-1)
|
||||
:to-equal 1-hour)
|
||||
(expect (chronometrist-task-time-one-day "Cooking" ts-1)
|
||||
:to-equal 1-hour)
|
||||
(expect (chronometrist-task-time-one-day "Guitar" ts-1)
|
||||
:to-equal 1-hour)
|
||||
(expect (chronometrist-task-time-one-day "Cycling" ts-1)
|
||||
:to-equal 1-hour))
|
||||
|
||||
(it "works with midnight-crossing events"
|
||||
(expect (chronometrist-task-time-one-day "Programming" ts-2)
|
||||
:to-equal 1-hour)
|
||||
(expect (chronometrist-task-time-one-day "Programming" ts-3)
|
||||
:to-equal 1-hour)))
|
||||
|
||||
;; Local Variables:
|
||||
;; nameless-current-name: "chronometrist"
|
||||
;; End:
|
|
@ -0,0 +1,418 @@
|
|||
(require 'chronometrist)
|
||||
|
||||
(ert-deftest chronometrist-format-duration ()
|
||||
(should
|
||||
(equal (chronometrist-format-duration 0) " -"))
|
||||
(should
|
||||
(equal (chronometrist-format-duration 1) " 1"))
|
||||
(should
|
||||
(equal (chronometrist-format-duration 10) " 10"))
|
||||
(should
|
||||
(equal (chronometrist-format-duration 70) " 1:10"))
|
||||
(should
|
||||
(equal (chronometrist-format-duration (+ (* 10 60) 10))
|
||||
" 10:10"))
|
||||
(should
|
||||
(equal (chronometrist-format-duration (+ (* 1 60 60) (* 10 60) 10))
|
||||
" 1:10:10"))
|
||||
(should
|
||||
(equal (chronometrist-format-duration (+ (* 10 60 60) (* 10 60) 10))
|
||||
"10:10:10")))
|
||||
|
||||
(ert-deftest chronometrist-previous-week-start ()
|
||||
(let ((chronometrist-report-week-start-day "Sunday")
|
||||
(ts (chronometrist-iso-date-to-ts "2018-09-02")))
|
||||
(should (ts= (chronometrist-previous-week-start
|
||||
(chronometrist-iso-date-to-ts "2018-09-01"))
|
||||
(chronometrist-iso-date-to-ts "2018-08-26")))
|
||||
(should (ts= ts (chronometrist-previous-week-start
|
||||
(chronometrist-iso-date-to-ts "2018-09-02"))))
|
||||
(should (ts= ts (chronometrist-previous-week-start
|
||||
(chronometrist-iso-date-to-ts "2018-09-03"))))
|
||||
(should (ts= ts (chronometrist-previous-week-start
|
||||
(chronometrist-iso-date-to-ts "2018-09-04"))))
|
||||
(should (ts= ts (chronometrist-previous-week-start
|
||||
(chronometrist-iso-date-to-ts "2018-09-05"))))
|
||||
(should (ts= ts (chronometrist-previous-week-start
|
||||
(chronometrist-iso-date-to-ts "2018-09-06"))))
|
||||
(should (ts= ts (chronometrist-previous-week-start
|
||||
(chronometrist-iso-date-to-ts "2018-09-07"))))
|
||||
(should (ts= ts (chronometrist-previous-week-start
|
||||
(chronometrist-iso-date-to-ts "2018-09-08"))))))
|
||||
|
||||
(ert-deftest chronometrist-plist-remove ()
|
||||
(should
|
||||
|
||||
(equal (chronometrist-plist-remove '(:a 1 :b 2 :c 3 :d 4) :a)
|
||||
'(:b 2 :c 3 :d 4)))
|
||||
(should
|
||||
|
||||
(equal (chronometrist-plist-remove '(:a 1 :b 2 :c 3 :d 4) :b)
|
||||
'(:a 1 :c 3 :d 4)))
|
||||
(should
|
||||
(equal (chronometrist-plist-remove '(:a 1 :b 2 :c 3 :d 4) :c)
|
||||
'(:a 1 :b 2 :d 4)))
|
||||
(should
|
||||
(equal (chronometrist-plist-remove '(:a 1 :b 2 :c 3 :d 4) :d)
|
||||
'(:a 1 :b 2 :c 3)))
|
||||
(should
|
||||
(equal (chronometrist-plist-remove '(:a 1 :b 2 :c 3 :d 4) :a :b)
|
||||
'(:c 3 :d 4)))
|
||||
(should
|
||||
(equal (chronometrist-plist-remove '(:a 1 :b 2 :c 3 :d 4) :a :d)
|
||||
'(:b 2 :c 3)))
|
||||
(should
|
||||
(equal (chronometrist-plist-remove '(:a 1 :b 2 :c 3 :d 4) :c :d)
|
||||
'(:a 1 :b 2)))
|
||||
(should (equal
|
||||
(chronometrist-plist-remove '(:a 1 :b 2 :c 3 :d 4) :a :b :c :d)
|
||||
nil))
|
||||
(should
|
||||
(equal (chronometrist-plist-remove '(:a 1 :b 2 :c 3 :d 4) :d :a)
|
||||
'(:b 2 :c 3))))
|
||||
|
||||
(ert-deftest 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)))))
|
||||
|
||||
(ert-deftest plist-pp-buffer ()
|
||||
(should
|
||||
(equal
|
||||
(chronometrist-plist-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-plist-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-plist-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-plist-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\")))"))))
|
||||
|
||||
(defvar chronometrist-test-file
|
||||
(make-temp-file
|
||||
"chronometrist-test-" nil ".sexp"
|
||||
(with-output-to-string
|
||||
(mapc
|
||||
(lambda (plist)
|
||||
;; to use this, we'd have to move `chronometrist-plist-pp' before this
|
||||
;; definition, and I'm perfectly content with where it is
|
||||
;; right now
|
||||
(chronometrist-plist-pp plist) (princ "\n\n")
|
||||
;; (print plist) (princ "\n")
|
||||
)
|
||||
'((: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"))))))
|
||||
|
||||
(defmacro chronometrist-tests--change-type-and-update (state)
|
||||
`(prog1 (chronometrist-file-change-type ,state)
|
||||
(setq ,state
|
||||
(list :last (chronometrist-file-hash :before-last nil)
|
||||
:rest (chronometrist-file-hash nil :before-last t)))))
|
||||
|
||||
(ert-deftest task-list ()
|
||||
(let ((task-list (chronometrist-task-list)))
|
||||
(should (listp task-list))
|
||||
(should (seq-every-p #'stringp task-list))))
|
||||
|
||||
(ert-deftest file-hash ()
|
||||
(-let* ((chronometrist-file chronometrist-test-file)
|
||||
((last-start last-end)
|
||||
(chronometrist-file-hash :before-last nil))
|
||||
((rest-start rest-end rest-hash)
|
||||
(chronometrist-file-hash nil :before-last t)))
|
||||
(message "chronometrist - file-hash test - file path is %s"
|
||||
chronometrist-test-file)
|
||||
(should (= 1 rest-start))
|
||||
(should (= 1254 rest-end))
|
||||
(should (= 1256 last-start))
|
||||
(should (= 1426 last-end))))
|
||||
|
||||
(ert-deftest chronometrist-file-change-type ()
|
||||
(let* ((chronometrist-file chronometrist-test-file)
|
||||
(test-contents (with-current-buffer (find-file-noselect chronometrist-file)
|
||||
(buffer-substring (point-min) (point-max))))
|
||||
(chronometrist--file-state-old chronometrist--file-state)
|
||||
(chronometrist--file-state (list :last (chronometrist-file-hash :before-last nil)
|
||||
:rest (chronometrist-file-hash nil :before-last t)))
|
||||
(chronometrist-events-old chronometrist-events))
|
||||
(chronometrist-events-populate)
|
||||
(unwind-protect
|
||||
(progn
|
||||
(should
|
||||
(eq nil (chronometrist-file-change-type chronometrist--file-state)))
|
||||
(should
|
||||
(eq :append
|
||||
(progn
|
||||
(chronometrist-sexp-new
|
||||
'(:name "Append Test"
|
||||
:start "2021-02-01T13:06:46+0530"
|
||||
:stop "2021-02-01T13:06:49+0530"))
|
||||
(chronometrist-tests--change-type-and-update chronometrist--file-state))))
|
||||
(should
|
||||
(eq :modify
|
||||
(progn
|
||||
(chronometrist-sexp-replace-last
|
||||
'(:name "Modify Test"
|
||||
:tags (some tags)
|
||||
:start "2021-02-01T13:06:46+0530"
|
||||
:stop "2021-02-01T13:06:49+0530"))
|
||||
(chronometrist-tests--change-type-and-update chronometrist--file-state))))
|
||||
(should
|
||||
(eq :remove
|
||||
(progn
|
||||
(chronometrist-sexp-in-file chronometrist-file
|
||||
(goto-char (point-max))
|
||||
(backward-list 1)
|
||||
(chronometrist-sexp-delete-list 1)
|
||||
(save-buffer))
|
||||
(chronometrist-tests--change-type-and-update chronometrist--file-state))))
|
||||
(should
|
||||
(eq t
|
||||
(progn
|
||||
(chronometrist-sexp-in-file chronometrist-file
|
||||
(goto-char (point-min))
|
||||
(chronometrist-plist-pp '(:name "Other Change Test"
|
||||
:start "2021-02-02T17:39:40+0530"
|
||||
:stop "2021-02-02T17:39:44+0530")
|
||||
(current-buffer))
|
||||
(save-buffer))
|
||||
(chronometrist-tests--change-type-and-update chronometrist--file-state)))))
|
||||
;; restore test file contents
|
||||
(with-current-buffer (find-file-noselect chronometrist-file)
|
||||
(delete-region (point-min) (point-max))
|
||||
(insert test-contents)
|
||||
(save-buffer))
|
||||
(setq chronometrist--file-state chronometrist--file-state-old
|
||||
chronometrist-events chronometrist-events-old))))
|
||||
|
||||
(ert-deftest chronometrist-apply-time ()
|
||||
(should
|
||||
(equal (ts-format "%FT%T%z" (chronometrist-apply-time "01:02:03" "2021-02-17T01:20:18+0530"))
|
||||
"2021-02-17T01:02:03+0530")))
|
||||
|
||||
(ert-deftest chronometrist-events-maybe-split ()
|
||||
(should
|
||||
(null (chronometrist-events-maybe-split
|
||||
'(:name "Task"
|
||||
:start "2021-02-17T01:33:12+0530"
|
||||
:stop "2021-02-17T01:56:08+0530"))))
|
||||
(should
|
||||
(equal (chronometrist-events-maybe-split
|
||||
'(:name "Guitar"
|
||||
:tags (classical warm-up)
|
||||
:start "2021-02-12T23:45:21+0530"
|
||||
:stop "2021-02-13T00:03:46+0530"))
|
||||
'((:name "Guitar"
|
||||
:tags (classical warm-up)
|
||||
:start "2021-02-12T23:45:21+0530"
|
||||
:stop "2021-02-13T00:00:00+0530")
|
||||
(:name "Guitar"
|
||||
:tags (classical warm-up)
|
||||
:start "2021-02-13T00:00:00+0530"
|
||||
:stop "2021-02-13T00:03:46+0530")))))
|
||||
|
||||
(ert-deftest chronometrist-task-time-one-day ()
|
||||
(let ((chronometrist-file-old chronometrist-file)
|
||||
(chronometrist-file chronometrist-test-file)
|
||||
(chronometrist--file-state-old chronometrist--file-state)
|
||||
(chronometrist-events-old chronometrist-events)
|
||||
(ts-1 (chronometrist-iso-date-to-ts "2018-01-01"))
|
||||
(ts-2 (chronometrist-iso-date-to-ts "2018-01-02"))
|
||||
(ts-3 (chronometrist-iso-date-to-ts "2018-01-03"))
|
||||
(1-hour 3600))
|
||||
(chronometrist-events-populate)
|
||||
(unwind-protect
|
||||
(progn
|
||||
(should
|
||||
(equal (chronometrist-task-time-one-day "Programming" ts-1)
|
||||
1-hour))
|
||||
(should
|
||||
(equal (chronometrist-task-time-one-day "Swimming" ts-1)
|
||||
1-hour))
|
||||
(should
|
||||
(equal (chronometrist-task-time-one-day "Cooking" ts-1)
|
||||
1-hour))
|
||||
(should
|
||||
(equal (chronometrist-task-time-one-day "Guitar" ts-1)
|
||||
1-hour))
|
||||
(should
|
||||
(equal (chronometrist-task-time-one-day "Cycling" ts-1)
|
||||
1-hour))
|
||||
(should
|
||||
(equal (chronometrist-task-time-one-day "Programming" ts-2)
|
||||
1-hour))
|
||||
(should
|
||||
(equal (chronometrist-task-time-one-day "Programming" ts-3)
|
||||
1-hour)))
|
||||
(setq chronometrist-file chronometrist-file-old
|
||||
chronometrist--file-state chronometrist--file-state-old)
|
||||
;; Not sure why simply assigning `chronometrist-events-old' did not restore
|
||||
;; the value - it seems to work in `chronometrist-file-change-type'
|
||||
(chronometrist-events-populate))))
|
||||
|
||||
(ert-deftest chronometrist-midnight-spanning-p ()
|
||||
(should
|
||||
(null
|
||||
(chronometrist-midnight-spanning-p "2021-02-17T01:33:12+0530"
|
||||
"2021-02-17T01:56:08+0530"
|
||||
"00:00:00")))
|
||||
(should
|
||||
(equal
|
||||
(chronometrist-midnight-spanning-p "2021-02-19T23:45:36+0530"
|
||||
"2021-02-20T00:18:40+0530"
|
||||
"00:00:00")
|
||||
'((:start "2021-02-19T23:45:36+0530"
|
||||
:stop "2021-02-20T00:00:00+0530")
|
||||
(:start "2021-02-20T00:00:00+0530"
|
||||
:stop "2021-02-20T00:18:40+0530"))))
|
||||
(should
|
||||
(equal
|
||||
(chronometrist-midnight-spanning-p "2021-02-19T23:45:36+0530"
|
||||
"2021-02-20T03:18:40+0530"
|
||||
"01:20:30")
|
||||
'((:start "2021-02-19T23:45:36+0530"
|
||||
:stop "2021-02-20T01:20:30+0530")
|
||||
(:start "2021-02-20T01:20:30+0530"
|
||||
:stop "2021-02-20T03:18:40+0530")))))
|
||||
|
||||
(ert-deftest chronometrist-details-row-helper ()
|
||||
(let ((tags '(a b c))
|
||||
(plist '(:a 1 :b 2 :c 3)))
|
||||
(let ((chronometrist-details-display-tags nil)
|
||||
(chronometrist-details-display-key-values nil))
|
||||
(should (equal (chronometrist-details-rows-helper tags) ""))
|
||||
(should (equal (chronometrist-details-rows-helper plist) "")))
|
||||
(let ((chronometrist-details-display-tags "%s")
|
||||
(chronometrist-details-display-key-values "%s"))
|
||||
(should (equal (chronometrist-details-rows-helper nil) ""))
|
||||
(should (equal (chronometrist-details-rows-helper nil) ""))
|
||||
(should (equal (chronometrist-details-rows-helper tags)
|
||||
"a b c"))
|
||||
(should (equal (chronometrist-details-rows-helper plist)
|
||||
"1 2 3")))))
|
Reference in New Issue