org-clock: Fix regression in Clock table

* lisp/org-clock.el (org-clocktable-write-default): Do not raise an
  error when :maxlevel is 0.  Small refactoring.

* testing/lisp/test-org-clock.el (test-org-clock/clocktable): Split
into ...
(test-org-clock/clocktable/ranges):
(test-org-clock/clocktable/tags):
(test-org-clock/clocktable/scope):
(test-org-clock/clocktable/maxlevel):
(test-org-clock/clocktable/formula): ... these.  Add tests.

This fixes regression introduced in ccf832e83.

Reported-by: Christoph LANGE <math.semantic.web@gmail.com>
<http://permalink.gmane.org/gmane.emacs.orgmode/112091>
This commit is contained in:
Nicolas Goaziou 2017-02-13 21:24:40 +01:00
parent 990fd09ca8
commit b897ab7223
2 changed files with 305 additions and 202 deletions

View File

@ -2458,36 +2458,32 @@ from the dynamic block definition."
(multifile (plist-get params :multifile)) (multifile (plist-get params :multifile))
(block (plist-get params :block)) (block (plist-get params :block))
(sort (plist-get params :sort)) (sort (plist-get params :sort))
(header (plist-get params :header)) (header (plist-get params :header))
(narrow (plist-get params :narrow))
(ws (or (plist-get params :wstart) 1)) (ws (or (plist-get params :wstart) 1))
(ms (or (plist-get params :mstart) 1)) (ms (or (plist-get params :mstart) 1))
(link (plist-get params :link)) (link (plist-get params :link))
(maxlevel (or (plist-get params :maxlevel) 3))
(emph (plist-get params :emphasize))
(level-p (plist-get params :level))
(org-time-clocksum-use-effort-durations (org-time-clocksum-use-effort-durations
(plist-get params :effort-durations)) (plist-get params :effort-durations))
(maxlevel (or (plist-get params :maxlevel) 3))
(emph (plist-get params :emphasize))
(compact? (plist-get params :compact))
(narrow (or (plist-get params :narrow) (and compact? '40!)))
(level? (and (not compact?) (plist-get params :level)))
(timestamp (plist-get params :timestamp)) (timestamp (plist-get params :timestamp))
(properties (plist-get params :properties)) (properties (plist-get params :properties))
(ntcol (max 1 (or (plist-get params :tcolumns) 100))) (ntcol (if compact? 1
(indent (plist-get params :indent)) (max 1 (or (plist-get params :tcolumns) 100))))
(indent (or compact? (plist-get params :indent)))
(formula (plist-get params :formula)) (formula (plist-get params :formula))
(case-fold-search t) (case-fold-search t)
range-text total-time tbl level hlc range-text total-time recalc narrow-cut-p)
file-time entries entry headline
recalc narrow-cut-p)
;; Implement abbreviations ;; Some consistency test for parameters.
(when (plist-get params :compact)
(setq level nil indent t narrow (or narrow '40!) ntcol 1))
;; Some consistency test for parameters
(unless (integerp ntcol) (unless (integerp ntcol)
(setq params (plist-put params :tcolumns (setq ntcol 100)))) (setq params (plist-put params :tcolumns (setq ntcol 100))))
(when (and narrow (integerp narrow) link) (when (and narrow (integerp narrow) link)
;; We cannot have both integer narrow and link ;; We cannot have both integer narrow and link.
(message (message
"Using hard narrowing in clocktable to allow for links") "Using hard narrowing in clocktable to allow for links")
(setq narrow (intern (format "%d!" narrow)))) (setq narrow (intern (format "%d!" narrow))))
@ -2505,19 +2501,19 @@ from the dynamic block definition."
narrow)))) narrow))))
(when block (when block
;; Get the range text for the header ;; Get the range text for the header.
(setq range-text (nth 2 (org-clock-special-range block nil t ws ms)))) (setq range-text (nth 2 (org-clock-special-range block nil t ws ms))))
;; Compute the total time ;; Compute the total time.
(setq total-time (apply '+ (mapcar 'cadr tables))) (setq total-time (apply #'+ (mapcar #'cadr tables)))
;; Now we need to output this tsuff ;; Now we need to output this tsuff.
(goto-char ipos) (goto-char ipos)
;; Insert the text *before* the actual table ;; Insert the text *before* the actual table.
(insert-before-markers (insert-before-markers
(or header (or header
;; Format the standard header ;; Format the standard header.
(concat (concat
"#+CAPTION: " "#+CAPTION: "
(nth 9 lwords) " [" (nth 9 lwords) " ["
@ -2531,104 +2527,109 @@ from the dynamic block definition."
;; Insert the narrowing line ;; Insert the narrowing line
(when (and narrow (integerp narrow) (not narrow-cut-p)) (when (and narrow (integerp narrow) (not narrow-cut-p))
(insert-before-markers (insert-before-markers
"|" ; table line starter "|" ;table line starter
(if multifile "|" "") ; file column, maybe (if multifile "|" "") ;file column, maybe
(if level-p "|" "") ; level column, maybe (if level? "|" "") ;level column, maybe
(if timestamp "|" "") ; timestamp column, maybe (if timestamp "|" "") ;timestamp column, maybe
(if properties (make-string (length properties) ?|) "") ;properties columns, maybe (if properties (make-string (length properties) ?|) "") ;properties columns, maybe
(format "<%d>| |\n" narrow))) ; headline and time columns (format "<%d>| |\n" narrow))) ; headline and time columns
;; Insert the table header line ;; Insert the table header line
(insert-before-markers (insert-before-markers
"|" ; table line starter "|" ;table line starter
(if multifile (concat (nth 1 lwords) "|") "") ; file column, maybe (if multifile (concat (nth 1 lwords) "|") "") ;file column, maybe
(if level-p (concat (nth 2 lwords) "|") "") ; level column, maybe (if level? (concat (nth 2 lwords) "|") "") ;level column, maybe
(if timestamp (concat (nth 3 lwords) "|") "") ; timestamp column, maybe (if timestamp (concat (nth 3 lwords) "|") "") ;timestamp column, maybe
(if properties (concat (mapconcat 'identity properties "|") "|") "") ;properties columns, maybe (if properties ;properties columns, maybe
(concat (mapconcat #'identity properties "|") "|")
"")
(nth 4 lwords) "|" ;headline (nth 4 lwords) "|" ;headline
(nth 5 lwords) "|" ;time column (nth 5 lwords) "|" ;time column
(make-string (1- (min maxlevel (or ntcol 100))) ?|) (make-string (max 0 (1- (min maxlevel (or ntcol 100))))
?|) ;other time columns
(if (eq formula '%) "%|\n" "\n")) (if (eq formula '%) "%|\n" "\n"))
;; Insert the total time in the table ;; Insert the total time in the table
(insert-before-markers (insert-before-markers
"|-\n" ; a hline "|-\n" ;a hline
"|" ; table line starter "|" ;table line starter
(if multifile (concat "| " (nth 6 lwords) " ") "") (if multifile (concat "| " (nth 6 lwords) " ") "")
; file column, maybe ;file column, maybe
(if level-p "|" "") ; level column, maybe (if level? "|" "") ;level column, maybe
(if timestamp "|" "") ; timestamp column, maybe (if timestamp "|" "") ;timestamp column, maybe
(make-string (length properties) ?|) ; properties columns, maybe (make-string (length properties) ?|) ;properties columns, maybe
(concat (format org-clock-total-time-cell-format (nth 7 lwords)) "| ") ; instead of a headline (concat (format org-clock-total-time-cell-format (nth 7 lwords))
"| ")
(format org-clock-total-time-cell-format (format org-clock-total-time-cell-format
(org-minutes-to-clocksum-string (or total-time 0))) ;time (org-minutes-to-clocksum-string (or total-time 0))) ;time
"|" "|"
(make-string (1- (min maxlevel (or ntcol 100))) ?|) (make-string (max 0 (1- (min maxlevel (or ntcol 100)))) ?|)
(cond ((not (eq formula '%)) "") (cond ((not (eq formula '%)) "")
((or (not total-time) (= total-time 0)) "0.0|") ((or (not total-time) (= total-time 0)) "0.0|")
(t "100.0|")) (t "100.0|"))
"\n") "\n")
;; Now iterate over the tables and insert the data ;; Now iterate over the tables and insert the data but only if any
;; but only if any time has been collected ;; time has been collected.
(when (and total-time (> total-time 0)) (when (and total-time (> total-time 0))
(pcase-dolist (`(,file-name ,file-time ,entries) tables)
(while (setq tbl (pop tables))
;; now tbl is the table resulting from one file.
(setq file-time (nth 1 tbl))
(when (or (and file-time (> file-time 0)) (when (or (and file-time (> file-time 0))
(not (plist-get params :fileskip0))) (not (plist-get params :fileskip0)))
(insert-before-markers "|-\n") ; a hline because a new file starts (insert-before-markers "|-\n") ;hline at new file
;; First the file time, if we have multiple files ;; First the file time, if we have multiple files.
(when multifile (when multifile
;; Summarize the time collected from this file ;; Summarize the time collected from this file.
(insert-before-markers (insert-before-markers
(format (concat "| %s %s | %s%s" (format (concat "| %s %s | %s%s"
(format org-clock-file-time-cell-format (nth 8 lwords)) (format org-clock-file-time-cell-format
(nth 8 lwords))
" | *%s*|\n") " | *%s*|\n")
(file-name-nondirectory (car tbl)) (file-name-nondirectory file-name)
(if level-p "| " "") ; level column, maybe (if level? "| " "") ;level column, maybe
(if timestamp "| " "") ; timestamp column, maybe (if timestamp "| " "") ;timestamp column, maybe
(if properties (make-string (length properties) ?|) "") ;properties columns, maybe (if properties ;properties columns, maybe
(org-minutes-to-clocksum-string (nth 1 tbl))))) ; the time (make-string (length properties) ?|)
"")
(org-minutes-to-clocksum-string file-time)))) ;time
;; Get the list of node entries and iterate over it ;; Get the list of node entries and iterate over it
(setq entries (nth 2 tbl)) (when (> maxlevel 0)
(while (setq entry (pop entries)) (pcase-dolist (`(,level ,headline ,ts ,time . ,props) entries)
(setq level (car entry) (when narrow-cut-p
headline (nth 1 entry) (setq headline
hlc (if emph (or (cdr (assoc level hlchars)) "") "")) (if (and (string-match
(when narrow-cut-p (format "\\`%s\\'" org-bracket-link-regexp)
(if (and (string-match (concat "\\`" org-bracket-link-regexp headline)
"\\'") (match-end 3))
headline) (format "[[%s][%s]]"
(match-end 3)) (match-string 1 headline)
(setq headline (org-shorten-string (match-string 3 headline)
(format "[[%s][%s]]" narrow))
(match-string 1 headline) (org-shorten-string headline narrow))))
(org-shorten-string (match-string 3 headline) (let ((hlc (if emph (or (cdr (assoc level hlchars)) "") "")))
narrow))) (insert-before-markers
(setq headline (org-shorten-string headline narrow)))) "|" ;start the table line
(insert-before-markers (if multifile "|" "") ;free space for file name column?
"|" ; start the table line (if level? (format "%d|" level) "") ;level, maybe
(if multifile "|" "") ; free space for file name column? (if timestamp (concat ts "|") "") ;timestamp, maybe
(if level-p (format "%d|" (car entry)) "") ; level, maybe (if properties ;properties columns, maybe
(if timestamp (concat (nth 2 entry) "|") "") ; timestamp, maybe (concat (mapconcat (lambda (p)
(if properties (or (cdr (assoc p props)) ""))
(concat properties
(mapconcat "|")
(lambda (p) (or (cdr (assoc p (nth 4 entry))) "")) "|")
properties "|") "|") "") ;properties columns, maybe "")
(if indent (org-clocktable-indent-string level) "") ; indentation (if indent ;indentation
hlc headline hlc "|" ; headline (org-clocktable-indent-string level)
(make-string (1- (min ntcol level)) ?|) ; empty fields for higher levels "")
hlc (org-minutes-to-clocksum-string (nth 3 entry)) hlc ; time hlc headline hlc "|" ;headline
(make-string (1+ (- maxlevel level)) ?|) (make-string (1- (min ntcol level)) ?|) ;empty fields for higher levels
(if (eq formula '%) hlc (org-minutes-to-clocksum-string time) hlc ; time
(format "%.1f |" (* 100 (/ (nth 3 entry) (float total-time)))) (make-string (1+ (- maxlevel level)) ?|)
"") (if (eq formula '%)
"\n" ; close line (format "%.1f |" (* 100 (/ time (float total-time))))
))))) "")
"\n")))))))
(delete-char -1) (delete-char -1)
(cond (cond
;; Possibly rescue old formula? ;; Possibly rescue old formula?
@ -2644,12 +2645,12 @@ from the dynamic block definition."
(setq recalc t)) (setq recalc t))
(t (t
(user-error "Invalid :formula parameter in clocktable"))) (user-error "Invalid :formula parameter in clocktable")))
;; Back to beginning, align the table, recalculate if necessary ;; Back to beginning, align the table, recalculate if necessary.
(goto-char ipos) (goto-char ipos)
(skip-chars-forward "^|") (skip-chars-forward "^|")
(org-table-align) (org-table-align)
(when org-hide-emphasis-markers (when org-hide-emphasis-markers
;; we need to align a second time ;; We need to align a second time.
(org-table-align)) (org-table-align))
(when sort (when sort
(save-excursion (save-excursion

View File

@ -47,16 +47,16 @@ range. INPUT2 can be omitted if clock hasn't finished yet.
Return the clock line as a string." Return the clock line as a string."
(let* ((beg (org-test-clock-create-timestamp input1 t t)) (let* ((beg (org-test-clock-create-timestamp input1 t t))
(end (and input2 (org-test-clock-create-timestamp input2 t t))) (end (and input2 (org-test-clock-create-timestamp input2 t t)))
(sec-diff (and input2 (floor (- (org-time-string-to-seconds end) (sec-diff (and input2 (floor (- (org-time-string-to-seconds end)
(org-time-string-to-seconds beg)))))) (org-time-string-to-seconds beg))))))
(concat org-clock-string " " beg (concat org-clock-string " " beg
(when end (when end
(concat "--" end " => " (concat "--" end " => "
(format "%2d:%02d" (format "%2d:%02d"
(/ sec-diff 3600) (/ sec-diff 3600)
(/ (mod sec-diff 3600) 60)))) (/ (mod sec-diff 3600) 60))))
"\n"))) "\n")))
(defun test-org-clock-clocktable-contents-at-point (options) (defun test-org-clock-clocktable-contents-at-point (options)
"Return contents of a clocktable at point. "Return contents of a clocktable at point.
@ -89,119 +89,119 @@ contents. The clocktable doesn't appear in the buffer."
(should-not (should-not
(org-test-with-temp-text "* H" (org-test-with-temp-text "* H"
(let ((org-clock-into-drawer nil) (let ((org-clock-into-drawer nil)
(org-log-into-drawer nil)) (org-log-into-drawer nil))
(org-clock-into-drawer)))) (org-clock-into-drawer))))
(should-not (should-not
(org-test-with-temp-text "* H" (org-test-with-temp-text "* H"
(let ((org-clock-into-drawer nil) (let ((org-clock-into-drawer nil)
(org-log-into-drawer t)) (org-log-into-drawer t))
(org-clock-into-drawer)))) (org-clock-into-drawer))))
(should-not (should-not
(org-test-with-temp-text "* H" (org-test-with-temp-text "* H"
(let ((org-clock-into-drawer nil) (let ((org-clock-into-drawer nil)
(org-log-into-drawer "BAR")) (org-log-into-drawer "BAR"))
(org-clock-into-drawer)))) (org-clock-into-drawer))))
;; When `org-clock-into-drawer' is a string, use it ;; When `org-clock-into-drawer' is a string, use it
;; unconditionally. ;; unconditionally.
(should (should
(equal "FOO" (equal "FOO"
(org-test-with-temp-text "* H" (org-test-with-temp-text "* H"
(let ((org-clock-into-drawer "FOO") (let ((org-clock-into-drawer "FOO")
(org-log-into-drawer nil)) (org-log-into-drawer nil))
(org-clock-into-drawer))))) (org-clock-into-drawer)))))
(should (should
(equal "FOO" (equal "FOO"
(org-test-with-temp-text "* H" (org-test-with-temp-text "* H"
(let ((org-clock-into-drawer "FOO") (let ((org-clock-into-drawer "FOO")
(org-log-into-drawer t)) (org-log-into-drawer t))
(org-clock-into-drawer))))) (org-clock-into-drawer)))))
(should (should
(equal "FOO" (equal "FOO"
(org-test-with-temp-text "* H" (org-test-with-temp-text "* H"
(let ((org-clock-into-drawer "FOO") (let ((org-clock-into-drawer "FOO")
(org-log-into-drawer "BAR")) (org-log-into-drawer "BAR"))
(org-clock-into-drawer))))) (org-clock-into-drawer)))))
;; When `org-clock-into-drawer' is an integer, return it. ;; When `org-clock-into-drawer' is an integer, return it.
(should (should
(= 1 (= 1
(org-test-with-temp-text "* H" (org-test-with-temp-text "* H"
(let ((org-clock-into-drawer 1) (let ((org-clock-into-drawer 1)
(org-log-into-drawer nil)) (org-log-into-drawer nil))
(org-clock-into-drawer))))) (org-clock-into-drawer)))))
(should (should
(= 1 (= 1
(org-test-with-temp-text "* H" (org-test-with-temp-text "* H"
(let ((org-clock-into-drawer 1) (let ((org-clock-into-drawer 1)
(org-log-into-drawer t)) (org-log-into-drawer t))
(org-clock-into-drawer))))) (org-clock-into-drawer)))))
(should (should
(= 1 (= 1
(org-test-with-temp-text "* H" (org-test-with-temp-text "* H"
(let ((org-clock-into-drawer 1) (let ((org-clock-into-drawer 1)
(org-log-into-drawer "BAR")) (org-log-into-drawer "BAR"))
(org-clock-into-drawer))))) (org-clock-into-drawer)))))
;; Otherwise, any non-nil value defaults to `org-log-into-drawer' or ;; Otherwise, any non-nil value defaults to `org-log-into-drawer' or
;; "LOGBOOK" if it is nil. ;; "LOGBOOK" if it is nil.
(should (should
(equal "LOGBOOK" (equal "LOGBOOK"
(org-test-with-temp-text "* H" (org-test-with-temp-text "* H"
(let ((org-clock-into-drawer t) (let ((org-clock-into-drawer t)
(org-log-into-drawer nil)) (org-log-into-drawer nil))
(org-clock-into-drawer))))) (org-clock-into-drawer)))))
(should (should
(equal "LOGBOOK" (equal "LOGBOOK"
(org-test-with-temp-text "* H" (org-test-with-temp-text "* H"
(let ((org-clock-into-drawer t) (let ((org-clock-into-drawer t)
(org-log-into-drawer t)) (org-log-into-drawer t))
(org-clock-into-drawer))))) (org-clock-into-drawer)))))
(should (should
(equal "FOO" (equal "FOO"
(org-test-with-temp-text "* H" (org-test-with-temp-text "* H"
(let ((org-clock-into-drawer t) (let ((org-clock-into-drawer t)
(org-log-into-drawer "FOO")) (org-log-into-drawer "FOO"))
(org-clock-into-drawer))))) (org-clock-into-drawer)))))
;; A non-nil "CLOCK_INTO_DRAWER" property overrides ;; A non-nil "CLOCK_INTO_DRAWER" property overrides
;; `org-clock-into-drawer' value. ;; `org-clock-into-drawer' value.
(should (should
(equal "LOGBOOK" (equal "LOGBOOK"
(org-test-with-temp-text (org-test-with-temp-text
"* H\n:PROPERTIES:\n:CLOCK_INTO_DRAWER: t\n:END:" "* H\n:PROPERTIES:\n:CLOCK_INTO_DRAWER: t\n:END:"
(let ((org-clock-into-drawer nil) (let ((org-clock-into-drawer nil)
(org-log-into-drawer nil)) (org-log-into-drawer nil))
(org-clock-into-drawer))))) (org-clock-into-drawer)))))
(should (should
(equal "FOO" (equal "FOO"
(org-test-with-temp-text (org-test-with-temp-text
"* H\n:PROPERTIES:\n:CLOCK_INTO_DRAWER: FOO\n:END:" "* H\n:PROPERTIES:\n:CLOCK_INTO_DRAWER: FOO\n:END:"
(let ((org-clock-into-drawer nil) (let ((org-clock-into-drawer nil)
(org-log-into-drawer nil)) (org-log-into-drawer nil))
(org-clock-into-drawer))))) (org-clock-into-drawer)))))
(should-not (should-not
(org-test-with-temp-text (org-test-with-temp-text
"* H\n:PROPERTIES:\n:CLOCK_INTO_DRAWER: nil\n:END:" "* H\n:PROPERTIES:\n:CLOCK_INTO_DRAWER: nil\n:END:"
(let ((org-clock-into-drawer t) (let ((org-clock-into-drawer t)
(org-log-into-drawer nil)) (org-log-into-drawer nil))
(org-clock-into-drawer)))) (org-clock-into-drawer))))
;; "CLOCK_INTO_DRAWER" can be inherited. ;; "CLOCK_INTO_DRAWER" can be inherited.
(should (should
(equal "LOGBOOK" (equal "LOGBOOK"
(org-test-with-temp-text (org-test-with-temp-text
"* H\n:PROPERTIES:\n:CLOCK_INTO_DRAWER: t\n:END:\n** H2<point>" "* H\n:PROPERTIES:\n:CLOCK_INTO_DRAWER: t\n:END:\n** H2<point>"
(let ((org-clock-into-drawer nil) (let ((org-clock-into-drawer nil)
(org-log-into-drawer nil)) (org-log-into-drawer nil))
(org-clock-into-drawer))))) (org-clock-into-drawer)))))
(should (should
(equal "FOO" (equal "FOO"
(org-test-with-temp-text (org-test-with-temp-text
"* H\n:PROPERTIES:\n:CLOCK_INTO_DRAWER: FOO\n:END:\n** H2<point>" "* H\n:PROPERTIES:\n:CLOCK_INTO_DRAWER: FOO\n:END:\n** H2<point>"
(let ((org-clock-into-drawer nil) (let ((org-clock-into-drawer nil)
(org-log-into-drawer nil)) (org-log-into-drawer nil))
(org-clock-into-drawer))))) (org-clock-into-drawer)))))
(should-not (should-not
(org-test-with-temp-text (org-test-with-temp-text
"* H\n:PROPERTIES:\n:CLOCK_INTO_DRAWER: nil\n:END:\n** H2<point>" "* H\n:PROPERTIES:\n:CLOCK_INTO_DRAWER: nil\n:END:\n** H2<point>"
(let ((org-clock-into-drawer t) (let ((org-clock-into-drawer t)
(org-log-into-drawer nil)) (org-log-into-drawer nil))
(org-clock-into-drawer))))) (org-clock-into-drawer)))))
(ert-deftest test-org-clock/drawer-name () (ert-deftest test-org-clock/drawer-name ()
@ -211,64 +211,64 @@ contents. The clocktable doesn't appear in the buffer."
(should-not (should-not
(org-test-with-temp-text "* H" (org-test-with-temp-text "* H"
(let ((org-clock-into-drawer nil) (let ((org-clock-into-drawer nil)
(org-log-into-drawer nil)) (org-log-into-drawer nil))
(org-clock-drawer-name)))) (org-clock-drawer-name))))
(should-not (should-not
(org-test-with-temp-text "* H" (org-test-with-temp-text "* H"
(let ((org-clock-into-drawer nil) (let ((org-clock-into-drawer nil)
(org-log-into-drawer t)) (org-log-into-drawer t))
(org-clock-drawer-name)))) (org-clock-drawer-name))))
(should-not (should-not
(org-test-with-temp-text "* H" (org-test-with-temp-text "* H"
(let ((org-clock-into-drawer nil) (let ((org-clock-into-drawer nil)
(org-log-into-drawer "FOO")) (org-log-into-drawer "FOO"))
(org-clock-drawer-name)))) (org-clock-drawer-name))))
;; A string value for `org-clock-into-drawer' means to use it ;; A string value for `org-clock-into-drawer' means to use it
;; unconditionally. ;; unconditionally.
(should (should
(equal "FOO" (equal "FOO"
(org-test-with-temp-text "* H" (org-test-with-temp-text "* H"
(let ((org-clock-into-drawer "FOO") (let ((org-clock-into-drawer "FOO")
(org-log-into-drawer nil)) (org-log-into-drawer nil))
(org-clock-drawer-name))))) (org-clock-drawer-name)))))
(should (should
(equal "FOO" (equal "FOO"
(org-test-with-temp-text "* H" (org-test-with-temp-text "* H"
(let ((org-clock-into-drawer "FOO") (let ((org-clock-into-drawer "FOO")
(org-log-into-drawer t)) (org-log-into-drawer t))
(org-clock-drawer-name))))) (org-clock-drawer-name)))))
(should (should
(equal "FOO" (equal "FOO"
(org-test-with-temp-text "* H" (org-test-with-temp-text "* H"
(let ((org-clock-into-drawer "FOO") (let ((org-clock-into-drawer "FOO")
(org-log-into-drawer "BAR")) (org-log-into-drawer "BAR"))
(org-clock-drawer-name))))) (org-clock-drawer-name)))))
;; When the value in `org-clock-into-drawer' is a number, re-use ;; When the value in `org-clock-into-drawer' is a number, re-use
;; `org-log-into-drawer' or use default "LOGBOOK" value. ;; `org-log-into-drawer' or use default "LOGBOOK" value.
(should (should
(equal "FOO" (equal "FOO"
(org-test-with-temp-text "* H" (org-test-with-temp-text "* H"
(let ((org-clock-into-drawer 1) (let ((org-clock-into-drawer 1)
(org-log-into-drawer "FOO")) (org-log-into-drawer "FOO"))
(org-clock-drawer-name))))) (org-clock-drawer-name)))))
(should (should
(equal "LOGBOOK" (equal "LOGBOOK"
(org-test-with-temp-text "* H" (org-test-with-temp-text "* H"
(let ((org-clock-into-drawer 1) (let ((org-clock-into-drawer 1)
(org-log-into-drawer t)) (org-log-into-drawer t))
(org-clock-drawer-name))))) (org-clock-drawer-name)))))
(should (should
(equal "LOGBOOK" (equal "LOGBOOK"
(org-test-with-temp-text "* H" (org-test-with-temp-text "* H"
(let ((org-clock-into-drawer 1) (let ((org-clock-into-drawer 1)
(org-log-into-drawer nil)) (org-log-into-drawer nil))
(org-clock-drawer-name)))))) (org-clock-drawer-name))))))
;;; Clocktable ;;; Clocktable
(ert-deftest test-org-clock/clocktable () (ert-deftest test-org-clock/clocktable/ranges ()
"Test clocktable specifications." "Test ranges in Clock table."
;; Relative time: Previous two days. ;; Relative time: Previous two days.
(should (should
(equal (equal
@ -280,7 +280,7 @@ contents. The clocktable doesn't appear in the buffer."
| Foo | | 8:00 | | Foo | | 8:00 |
" "
(org-test-with-temp-text (org-test-with-temp-text
"* Relative times in clocktable\n** Foo\n<point>" "* Relative times in clocktable\n** Foo\n<point>"
(insert (org-test-clock-create-clock "-3d 8:00" "-3d 12:00")) (insert (org-test-clock-create-clock "-3d 8:00" "-3d 12:00"))
(insert (org-test-clock-create-clock "-2d 15:00" "-2d 18:00")) (insert (org-test-clock-create-clock "-2d 15:00" "-2d 18:00"))
(insert (org-test-clock-create-clock "-1d 8:00" "-1d 13:00")) (insert (org-test-clock-create-clock "-1d 8:00" "-1d 13:00"))
@ -297,7 +297,7 @@ contents. The clocktable doesn't appear in the buffer."
| Foo | | 6:00 | | Foo | | 6:00 |
" "
(org-test-with-temp-text (org-test-with-temp-text
"* Relative times in clocktable\n** Foo\n<point>" "* Relative times in clocktable\n** Foo\n<point>"
(insert (org-test-clock-create-clock "-2d 15:00" "-2d 18:00")) (insert (org-test-clock-create-clock "-2d 15:00" "-2d 18:00"))
(insert (org-test-clock-create-clock "-1d 8:00" "-1d 13:00")) (insert (org-test-clock-create-clock "-1d 8:00" "-1d 13:00"))
(insert (org-test-clock-create-clock ". 1:00" ". 2:00")) (insert (org-test-clock-create-clock ". 1:00" ". 2:00"))
@ -314,11 +314,14 @@ contents. The clocktable doesn't appear in the buffer."
| Foo | | 6:00 | | Foo | | 6:00 |
" "
(org-test-with-temp-text (org-test-with-temp-text
"* Relative times in clocktable\n** Foo\n<point>" "* Relative times in clocktable\n** Foo\n<point>"
(insert (org-test-clock-create-clock "-10y 15:00" "-10y 18:00")) (insert (org-test-clock-create-clock "-10y 15:00" "-10y 18:00"))
(insert (org-test-clock-create-clock "-2d 15:00" "-2d 18:00")) (insert (org-test-clock-create-clock "-2d 15:00" "-2d 18:00"))
(test-org-clock-clocktable-contents-at-point (test-org-clock-clocktable-contents-at-point
":block untilnow :indent nil")))) ":block untilnow :indent nil")))))
(ert-deftest test-org-clock/clocktable/tags ()
"Test \":tags\" parameter in Clock table."
;; Test tag filtering. ;; Test tag filtering.
(should (should
(equal (equal
@ -334,7 +337,10 @@ contents. The clocktable doesn't appear in the buffer."
(insert (org-test-clock-create-clock ". 2:00" ". 4:00")) (insert (org-test-clock-create-clock ". 2:00" ". 4:00"))
(goto-line 2) (goto-line 2)
(test-org-clock-clocktable-contents-at-point (test-org-clock-clocktable-contents-at-point
":tags \"tag\" :indent nil")))) ":tags \"tag\" :indent nil")))))
(ert-deftest test-org-clock/clocktable/scope ()
"Test \":scope\" parameter in Clock table."
;; Test `file-with-archives' scope. In particular, preserve "TBLFM" ;; Test `file-with-archives' scope. In particular, preserve "TBLFM"
;; line, and ignore "file" column. ;; line, and ignore "file" column.
(should (should
@ -346,7 +352,7 @@ contents. The clocktable doesn't appear in the buffer."
| Test | 704d 9:01 | foo | | Test | 704d 9:01 | foo |
" "
(org-test-with-temp-text-in-file (org-test-with-temp-text-in-file
"* Test "* Test
CLOCK: [2012-03-29 Thu 16:40]--[2014-03-04 Thu 00:41] => 16905:01 CLOCK: [2012-03-29 Thu 16:40]--[2014-03-04 Thu 00:41] => 16905:01
#+BEGIN: clocktable :scope file-with-archives #+BEGIN: clocktable :scope file-with-archives
@ -359,7 +365,103 @@ CLOCK: [2012-03-29 Thu 16:40]--[2014-03-04 Thu 00:41] => 16905:01
(forward-line 2) (forward-line 2)
(buffer-substring-no-properties (buffer-substring-no-properties
(point) (progn (goto-char (point-max)) (point) (progn (goto-char (point-max))
(line-beginning-position -1)))))) (line-beginning-position -1)))))))
(ert-deftest test-org-clock/clocktable/maxlevel ()
"Test \":maxlevel\" parameter in Clock table."
(should
(equal "| Headline | Time | | |
|--------------+--------+------+---|
| *Total time* | *6:00* | | |
|--------------+--------+------+---|
| Foo | 6:00 | | |
| \\_ Bar | | 2:00 | |
"
(org-test-with-temp-text
"
* Foo
CLOCK: [2016-12-28 Wed 11:09]--[2016-12-28 Wed 15:09] => 4:00
** Bar
CLOCK: [2016-12-28 Wed 13:09]--[2016-12-28 Wed 15:09] => 2:00
* Report
<point>#+BEGIN: clocktable :maxlevel 3
#+END:"
(org-update-dblock)
(buffer-substring-no-properties
(line-beginning-position 3)
(progn (goto-char (point-max))
(line-beginning-position))))))
(should
(equal "| Headline | Time | |
|--------------+--------+------|
| *Total time* | *6:00* | |
|--------------+--------+------|
| Foo | 6:00 | |
| \\_ Bar | | 2:00 |
"
(org-test-with-temp-text
"
* Foo
CLOCK: [2016-12-28 Wed 11:09]--[2016-12-28 Wed 15:09] => 4:00
** Bar
CLOCK: [2016-12-28 Wed 13:09]--[2016-12-28 Wed 15:09] => 2:00
* Report
<point>#+BEGIN: clocktable :maxlevel 2
#+END:"
(org-update-dblock)
(buffer-substring-no-properties
(line-beginning-position 3)
(progn (goto-char (point-max))
(line-beginning-position))))))
(should
(equal "| Headline | Time |
|--------------+--------|
| *Total time* | *6:00* |
|--------------+--------|
| Foo | 6:00 |
"
(org-test-with-temp-text
"
* Foo
CLOCK: [2016-12-28 Wed 11:09]--[2016-12-28 Wed 15:09] => 4:00
** Bar
CLOCK: [2016-12-28 Wed 13:09]--[2016-12-28 Wed 15:09] => 2:00
* Report
<point>#+BEGIN: clocktable :maxlevel 1
#+END:"
(org-update-dblock)
(buffer-substring-no-properties
(line-beginning-position 3)
(progn (goto-char (point-max))
(line-beginning-position))))))
;; Special ":maxlevel 0" case: only report total file time.
(should
(equal "| Headline | Time |
|--------------+--------|
| *Total time* | *6:00* |
|--------------+--------|
"
(org-test-with-temp-text
"
* Foo
CLOCK: [2016-12-28 Wed 11:09]--[2016-12-28 Wed 15:09] => 4:00
** Bar
CLOCK: [2016-12-28 Wed 13:09]--[2016-12-28 Wed 15:09] => 2:00
* Report
<point>#+BEGIN: clocktable :maxlevel 0
#+END:"
(org-update-dblock)
(buffer-substring-no-properties
(line-beginning-position 3)
(progn (goto-char (point-max))
(line-beginning-position)))))))
(ert-deftest test-org-clock/clocktable/formula ()
"Test \":formula\" parameter in Clock table."
;; Test ":formula %". Handle various duration formats. ;; Test ":formula %". Handle various duration formats.
(should (should
(equal (equal
@ -371,7 +473,7 @@ CLOCK: [2012-03-29 Thu 16:40]--[2014-03-04 Thu 00:41] => 16905:01
| Bar | 2:00 | 33.3 | | Bar | 2:00 | 33.3 |
" "
(org-test-with-temp-text (org-test-with-temp-text
"* Foo "* Foo
CLOCK: [2016-12-28 Wed 11:09]--[2016-12-28 Wed 15:09] => 4:00 CLOCK: [2016-12-28 Wed 11:09]--[2016-12-28 Wed 15:09] => 4:00
* Bar * Bar
CLOCK: [2016-12-28 Wed 13:09]--[2016-12-28 Wed 15:09] => 2:00 CLOCK: [2016-12-28 Wed 13:09]--[2016-12-28 Wed 15:09] => 2:00
@ -382,7 +484,7 @@ CLOCK: [2012-03-29 Thu 16:40]--[2014-03-04 Thu 00:41] => 16905:01
" "
(org-update-dblock) (org-update-dblock)
(buffer-substring-no-properties (line-beginning-position 3) (buffer-substring-no-properties (line-beginning-position 3)
(line-beginning-position 9))))) (line-beginning-position 9)))))
(should (should
(equal (equal
"| Headline | Time | % | "| Headline | Time | % |
@ -393,7 +495,7 @@ CLOCK: [2012-03-29 Thu 16:40]--[2014-03-04 Thu 00:41] => 16905:01
| Bar | 2:00 | 7.1 | | Bar | 2:00 | 7.1 |
" "
(org-test-with-temp-text (org-test-with-temp-text
" "
* Foo * Foo
CLOCK: [2016-12-27 Wed 13:09]--[2016-12-28 Wed 15:09] => 26:00 CLOCK: [2016-12-27 Wed 13:09]--[2016-12-28 Wed 15:09] => 26:00
* Bar * Bar
@ -403,7 +505,7 @@ CLOCK: [2012-03-29 Thu 16:40]--[2014-03-04 Thu 00:41] => 16905:01
#+END:" #+END:"
(org-update-dblock) (org-update-dblock)
(buffer-substring-no-properties (line-beginning-position 3) (buffer-substring-no-properties (line-beginning-position 3)
(line-beginning-position 9)))))) (line-beginning-position 9))))))
(provide 'test-org-clock) (provide 'test-org-clock)
;;; test-org-clock.el end here ;;; test-org-clock.el end here