1 ;;; test-org-colview.el --- Tests for org-colview.el -*- lexical-binding: t; -*-
3 ;; Copyright (C) 2016 Nicolas Goaziou
5 ;; Author: Nicolas Goaziou <mail@nicolasgoaziou.fr>
7 ;; This program is free software; you can redistribute it and/or modify
8 ;; it under the terms of the GNU General Public License as published by
9 ;; the Free Software Foundation, either version 3 of the License, or
10 ;; (at your option) any later version.
12 ;; This program is distributed in the hope that it will be useful,
13 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ;; GNU General Public License for more details.
17 ;; You should have received a copy of the GNU General Public License
18 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
26 (ert-deftest test-org-colview
/get-format
()
27 "Test `org-columns-get-format' specifications."
28 ;; Without any clue, use `org-columns-default-format'.
31 (org-test-with-temp-text "* H"
32 (let ((org-columns-default-format "%A"))
33 (org-columns-get-format)))))
34 ;; If COLUMNS keyword is set, use it.
37 (org-test-with-temp-text "#+COLUMNS: %B\n* H"
38 (let ((org-columns-default-format "%A"))
39 (org-columns-get-format)))))
42 (org-test-with-temp-text "#+columns: %B\n* H"
43 (let ((org-columns-default-format "%A"))
44 (org-columns-get-format)))))
47 (org-test-with-temp-text "* H\n#+COLUMNS: %B"
48 (let ((org-columns-default-format "%A"))
49 (org-columns-get-format)))))
50 ;; When :COLUMNS: property is set somewhere in the tree, use it over
55 (org-test-with-temp-text
56 "#+COLUMNS: %B\n* H\n:PROPERTIES:\n:COLUMNS: %C\n:END:\n** S\n<point>"
57 (let ((org-columns-default-format "%A"))
58 (org-columns-get-format)))))
59 ;; When optional argument is provided, prefer it.
63 (org-test-with-temp-text
64 "#+COLUMNS: %B\n* H\n:PROPERTIES:\n:COLUMNS: %C\n:END:\n** S\n<point>"
65 (let ((org-columns-default-format "%A"))
66 (org-columns-get-format "%D"))))))
68 (ert-deftest test-org-colview
/columns-scope
()
69 "Test `org-columns' scope."
70 ;; Before the first headline, view all document.
74 (org-test-with-temp-text "Top\n* H1\n** H2\n* H3"
75 (let ((org-columns-default-format "%ITEM")) (org-columns))
77 (lambda () (get-char-property (point) 'org-columns-value
))))))
78 ;; When :COLUMNS: is set up in the hierarchy, view tree starting
83 (org-test-with-temp-text
84 "* H1\n** H2\n:PROPERTIES:\n:COLUMNS: %ITEM\n:END:\n*** <point>H3\n* H4"
85 (let ((org-columns-default-format "%ITEM")) (org-columns))
87 (lambda () (get-char-property (point) 'org-columns-value
))))))
88 ;; Otherwise, view tree starting at the current headline.
92 (org-test-with-temp-text "Top\n* H1\n** <point>H2\n*** H3\n* H4"
93 (let ((org-columns-default-format "%ITEM")) (org-columns))
95 (lambda () (get-char-property (point) 'org-columns-value
))))))
96 ;; With a non-nil prefix argument, always view all document.
99 '("H1" "H2" "H3" "H4")
100 (org-test-with-temp-text
101 "* H1\n** H2\n:PROPERTIES:\n:COLUMNS: %ITEM\n:END:\n*** <point>H3\n* H4"
102 (let ((org-columns-default-format "%ITEM")) (org-columns t
))
104 (lambda () (get-char-property (point) 'org-columns-value
))))))
108 (org-test-with-temp-text
109 "Top\n* H1\n** <point>H2\n:PROPERTIES:\n:A: 1\n:END:"
110 (let ((org-columns-default-format "%A{+}")) (org-columns t
))
112 (lambda () (get-char-property (point) 'org-columns-value
)))))))
114 (ert-deftest test-org-colview
/columns-width
()
115 "Test `org-columns' column widths."
116 ;; When a width is specified in the format, use it.
119 (org-test-with-temp-text "* H"
120 (let ((org-columns-default-format "%9ITEM")) (org-columns))
121 (aref org-columns-current-maxwidths
0))))
122 ;; Otherwise, use the width of the largest value in the column.
125 (org-test-with-temp-text
126 "* H\n:PROPERTIES:\n:P: X\n:END:\n** H2\n:PROPERTIES:\n:P: XX\n:END:"
127 (let ((org-columns-default-format "%P")) (org-columns))
128 (aref org-columns-current-maxwidths
0))))
129 ;; If the title is wider than the widest value, use title width
133 (org-test-with-temp-text "* H"
134 (let ((org-columns-default-format "%ITEM")) (org-columns))
135 (aref org-columns-current-maxwidths
0))))
136 ;; Special case: stars do count for ITEM.
139 (org-test-with-temp-text "* Head"
140 (let ((org-columns-default-format "%ITEM")) (org-columns))
141 (aref org-columns-current-maxwidths
0))))
142 ;; Special case: width takes into account link narrowing in ITEM.
146 (org-test-with-temp-text "* [[https://orgmode.org][123]]"
147 (let ((org-columns-default-format "%ITEM")) (org-columns))
148 (cons (get-char-property (point) 'org-columns-value-modified
)
149 (aref org-columns-current-maxwidths
0)))))
150 ;; When a value is too wide for the current column, add ellipses.
151 ;; Take into consideration length of `org-columns-ellipses'.
154 (org-test-with-temp-text "* H\n:PROPERTIES:\n:P: 123456\n:END:"
155 (let ((org-columns-default-format "%5P")
156 (org-columns-ellipses ".."))
158 (org-trim (get-char-property (point) 'display
)))))
161 (org-test-with-temp-text "* H\n:PROPERTIES:\n:P: 123456\n:END:"
162 (let ((org-columns-default-format "%5P")
163 (org-columns-ellipses "…"))
165 (org-trim (get-char-property (point) 'display
))))))
167 (ert-deftest test-org-colview
/columns-summary
()
168 "Test `org-columns' summary types."
169 ;; {+} and {+;format} add numbers.
173 (org-test-with-temp-text
183 (let ((org-columns-default-format "%A{+}")) (org-columns))
184 (get-char-property (point) 'org-columns-value-modified
))))
188 (org-test-with-temp-text
198 (let ((org-columns-default-format "%A{+;%.1f}")) (org-columns))
199 (get-char-property (point) 'org-columns-value-modified
))))
200 ;; {$} is a shortcut for {+;%.2f}.
204 (org-test-with-temp-text
214 (let ((org-columns-default-format "%A{$}")) (org-columns))
215 (get-char-property (point) 'org-columns-value-modified
))))
216 ;; Obey to format string even in leaf values.
220 (org-test-with-temp-text
225 (let ((org-columns-default-format "%A{+;%.1f}")) (org-columns))
226 (get-char-property (point) 'org-columns-value-modified
))))
227 ;; {:} sums times. Plain numbers are hours.
231 (org-test-with-temp-text
241 (let ((org-columns-default-format "%A{:}")) (org-columns))
242 (get-char-property (point) 'org-columns-value-modified
))))
246 (org-test-with-temp-text
256 (let ((org-columns-default-format "%A{:}")) (org-columns))
257 (get-char-property (point) 'org-columns-value-modified
))))
258 ;; {X}, {X/} and {X%} indicate checkbox status.
262 (org-test-with-temp-text
272 (let ((org-columns-default-format "%A{X}")) (org-columns))
273 (get-char-property (point) 'org-columns-value-modified
))))
277 (org-test-with-temp-text
287 (let ((org-columns-default-format "%A{X}")) (org-columns))
288 (get-char-property (point) 'org-columns-value-modified
))))
292 (org-test-with-temp-text
302 (let ((org-columns-default-format "%A{X}")) (org-columns))
303 (get-char-property (point) 'org-columns-value-modified
))))
307 (org-test-with-temp-text
317 (let ((org-columns-default-format "%A{X/}")) (org-columns))
318 (get-char-property (point) 'org-columns-value-modified
))))
322 (org-test-with-temp-text
332 (let ((org-columns-default-format "%A{X%}")) (org-columns))
333 (get-char-property (point) 'org-columns-value-modified
))))
334 ;; {X/} handles recursive summaries.
338 (org-test-with-temp-text
353 (let ((org-columns-default-format "%A{X/}")) (org-columns))
354 (get-char-property (point) 'org-columns-value-modified
))))
358 (org-test-with-temp-text
373 (let ((org-columns-default-format "%A{X/}")) (org-columns))
374 (get-char-property (point) 'org-columns-value-modified
))))
375 ;; {X%} handles recursive summaries.
379 (org-test-with-temp-text
394 (let ((org-columns-default-format "%A{X%}")) (org-columns))
395 (get-char-property (point) 'org-columns-value-modified
))))
399 (org-test-with-temp-text
414 (let ((org-columns-default-format "%A{X%}")) (org-columns))
415 (get-char-property (point) 'org-columns-value-modified
))))
416 ;; {min} is the smallest number in column, {max} the largest one.
417 ;; {mean} is the arithmetic mean of numbers in column.
421 (org-test-with-temp-text
431 (let ((org-columns-default-format "%A{min}")) (org-columns))
432 (get-char-property (point) 'org-columns-value-modified
))))
436 (org-test-with-temp-text
446 (let ((org-columns-default-format "%A{max}")) (org-columns))
447 (get-char-property (point) 'org-columns-value-modified
))))
451 (org-test-with-temp-text
461 (let ((org-columns-default-format "%A{mean}")) (org-columns))
462 (get-char-property (point) 'org-columns-value-modified
))))
463 ;; {:min}, {:max} and {:mean} apply to time values.
467 (org-test-with-temp-text
477 (let ((org-columns-default-format "%A{:min}")) (org-columns))
478 (get-char-property (point) 'org-columns-value-modified
))))
482 (org-test-with-temp-text
492 (let ((org-columns-default-format "%A{:max}")) (org-columns))
493 (get-char-property (point) 'org-columns-value-modified
))))
497 (org-test-with-temp-text
507 (let ((org-columns-default-format "%A{:mean}")) (org-columns))
508 (get-char-property (point) 'org-columns-value-modified
))))
509 ;; {@min}, {@max} and {@mean} apply to ages.
513 (cl-letf (((symbol-function 'current-time
)
516 (org-parse-time-string "<2014-03-04 Tue>")))))
517 (org-test-with-temp-text
527 (let ((org-columns-default-format "%A{@min}")) (org-columns))
528 (get-char-property (point) 'org-columns-value-modified
)))))
532 (cl-letf (((symbol-function 'current-time
)
535 (org-parse-time-string "<2014-03-04 Tue>")))))
536 (org-test-with-temp-text
546 (let ((org-columns-default-format "%A{@max}")) (org-columns))
547 (get-char-property (point) 'org-columns-value-modified
)))))
551 (cl-letf (((symbol-function 'current-time
)
554 (org-parse-time-string "<2014-03-04 Tue>")))))
555 (org-test-with-temp-text
565 (let ((org-columns-default-format "%A{@mean}")) (org-columns))
566 (get-char-property (point) 'org-columns-value-modified
)))))
567 ;; If a time value is expressed as a duration, return a duration.
568 ;; If any of them follows H:MM:SS pattern, use it too. Also handle
569 ;; combinations of duration and H:MM:SS patterns.
573 (org-test-with-temp-text
583 (let ((org-columns-default-format "%A{:}")
584 (org-duration-units '(("d" .
1440) ("h" .
60)))
585 (org-duration-format '(("d" . nil
) (special . h
:mm
))))
587 (get-char-property (point) 'org-columns-value-modified
))))
591 (org-test-with-temp-text
601 (let ((org-columns-default-format "%A{:}")) (org-columns))
602 (get-char-property (point) 'org-columns-value-modified
))))
606 (org-test-with-temp-text
616 (let ((org-columns-default-format "%A{:}")
617 (org-duration-units '(("d" .
1440) ("h" .
60)))
618 (org-duration-format '(("d" . nil
) (special . h
:mm
))))
620 (get-char-property (point) 'org-columns-value-modified
))))
621 ;; @min, @max and @mean also accept regular duration.
625 (org-test-with-temp-text
635 (let ((org-columns-default-format "%A{@min}")) (org-columns))
636 (get-char-property (point) 'org-columns-value-modified
))))
637 ;; {est+} gives a low-high estimate using mean and standard
642 (org-test-with-temp-text
652 (let ((org-columns-default-format "%A{est+}")) (org-columns))
653 (get-char-property (point) 'org-columns-value-modified
))))
654 ;; When using {est+} summary, a single number is understood as
655 ;; a degenerate range.
659 (org-test-with-temp-text
666 (let ((org-columns-default-format "%A{est+}")) (org-columns))
667 (get-char-property (point) 'org-columns-value-modified
))))
668 ;; Allow custom summary types.
672 (org-test-with-temp-text
682 (let ((org-columns-summary-types
683 '(("custom" .
(lambda (s _
) (mapconcat #'identity s
"|")))))
684 (org-columns-default-format "%A{custom}")) (org-columns))
685 (get-char-property (point) 'org-columns-value-modified
))))
686 ;; Allow custom _collect_ for summary types.
690 (org-test-with-temp-text
701 (let ((org-columns-summary-types
702 '(("custom" org-columns--summary-sum
704 (if (equal "1" (org-entry-get nil
(format "%s-OK" p
)))
705 (org-entry-get nil p
)
707 (org-columns-default-format "%A{custom}")) (org-columns))
708 (get-char-property (point) 'org-columns-value-modified
))))
709 ;; Allow custom collect function to be used for different columns
713 (org-test-with-temp-text
727 (let ((org-columns-summary-types
728 '(("custom" org-columns--summary-sum
730 (if (equal "1" (org-entry-get nil
(format "%s-OK" p
)))
731 (org-entry-get nil p
)
733 (org-columns-default-format "%A{custom} %B{custom}")) (org-columns))
734 (list (get-char-property (point) 'org-columns-value-modified
)
735 (get-char-property (1+ (point)) 'org-columns-value-modified
)))))
736 ;; Allow multiple summary types applied to the same property.
740 (org-test-with-temp-text
750 (let ((org-columns-default-format "%A{min} %A{max}")) (org-columns))
751 (list (get-char-property (point) 'org-columns-value-modified
)
752 (get-char-property (1+ (point)) 'org-columns-value-modified
)))))
753 ;; Allow mixing both summarized and non-summarized columns for
754 ;; a property. However, the first column takes precedence and
755 ;; updates the value.
759 (org-test-with-temp-text
772 (let ((org-columns-default-format "%A %A{min}")) (org-columns))
773 (list (get-char-property (point) 'org-columns-value-modified
)
774 (get-char-property (1+ (point)) 'org-columns-value-modified
)))))
778 (org-test-with-temp-text
791 (let ((org-columns-default-format "%A{min} %A")) (org-columns))
792 (list (get-char-property (point) 'org-columns-value-modified
)
793 (get-char-property (1+ (point)) 'org-columns-value-modified
))))))
795 (ert-deftest test-org-colview
/columns-new
()
796 "Test `org-columns-new' specifications."
797 ;; Insert new column at the left of the current one.
799 (equal '("FOO" "ITEM")
800 (org-test-with-temp-text "* H"
801 (let ((org-columns-default-format "%ITEM")) (org-columns))
802 (org-columns-new nil
"FOO" "FOO" nil nil nil
)
803 (list (get-char-property (point) 'org-columns-key
)
804 (get-char-property (1+ (point)) 'org-columns-key
)))))
806 (equal '("ITEM" "FOO" "BAR")
807 (org-test-with-temp-text "* H"
808 (let ((org-columns-default-format "%ITEM %BAR")) (org-columns))
810 (org-columns-new nil
"FOO" "FOO" nil nil nil
)
811 (list (get-char-property (1- (point)) 'org-columns-key
)
812 (get-char-property (point) 'org-columns-key
)
813 (get-char-property (1+ (point)) 'org-columns-key
)))))
814 ;; Update #+COLUMNS keyword if needed.
816 (equal "#+COLUMNS: %FOO %ITEM"
817 (org-test-with-temp-text "#+COLUMNS: %ITEM\n<point>* H"
818 (let ((org-columns-default-format "%ITEM")) (org-columns))
819 (org-columns-new nil
"FOO" "FOO" nil nil nil
)
820 (goto-char (point-min))
821 (buffer-substring-no-properties (point) (line-end-position)))))
823 (equal "#+COLUMNS: %ITEM %FOO %BAR"
824 (org-test-with-temp-text "#+COLUMNS: %ITEM %BAR\n<point>* H"
825 (let ((org-columns-default-format "%ITEM %BAR")) (org-columns))
827 (org-columns-new nil
"FOO" "FOO" nil nil nil
)
828 (goto-char (point-min))
829 (buffer-substring-no-properties (point) (line-end-position)))))
830 ;; Mind case when updating #+COLUMNS.
832 (equal "#+COLUMNS: %ITEM %Foo %BAR"
833 (org-test-with-temp-text "#+COLUMNS: %ITEM %BAR\n<point>* H"
834 (let ((org-columns-default-format "%ITEM %BAR")) (org-columns))
836 (org-columns-new nil
"Foo" "Foo" nil nil nil
)
837 (goto-char (point-min))
838 (buffer-substring-no-properties (point) (line-end-position)))))
840 (equal "#+columns: %ITEM %Foo %BAR"
841 (org-test-with-temp-text "#+columns: %ITEM %BAR\n<point>* H"
842 (let ((org-columns-default-format "%ITEM %BAR")) (org-columns))
844 (org-columns-new nil
"Foo" "Foo" nil nil nil
)
845 (goto-char (point-min))
846 (buffer-substring-no-properties (point) (line-end-position)))))
847 ;; Also update :COLUMNS: properties.
850 (org-test-with-temp-text "* H\n:PROPERTIES:\n:COLUMNS: %ITEM\n:END:"
851 (let ((org-columns-default-format "%ITEM")) (org-columns))
852 (org-columns-new nil
"FOO" "FOO" nil nil nil
)
853 (org-entry-get nil
"COLUMNS"))))
854 ;; If no keyword nor any property is available, insert one.
856 (string-match-p (regexp-quote "#+COLUMNS: %FOO %ITEM")
857 (org-test-with-temp-text "* H"
858 (let ((org-columns-default-format "%ITEM")) (org-columns))
859 (org-columns-new nil
"FOO" "FOO" nil nil nil
)
862 (ert-deftest test-org-colview
/columns-update
()
863 "Test `org-columns-update' specifications."
868 (org-test-with-temp-text
874 (let ((org-columns-default-format "%5A")) (org-columns))
877 (org-columns-update "A")
878 (get-char-property (point-min) 'display
))))
879 ;; Update is case-insensitive.
883 (org-test-with-temp-text
889 (let ((org-columns-default-format "%5A")) (org-columns))
892 (org-columns-update "a")
893 (get-char-property (point-min) 'display
))))
894 ;; Update stored values.
898 (org-test-with-temp-text
904 (let ((org-columns-default-format "%5A")) (org-columns))
907 (org-columns-update "A")
908 (list (get-char-property (point-min) 'org-columns-value
)
909 (get-char-property (point-min) 'org-columns-value-modified
)))))
910 ;; When multiple columns are using the same property, value is
911 ;; updated according to the specifications of the first one.
915 (org-test-with-temp-text
924 (let ((org-columns-default-format "%A{min} %A")) (org-columns))
925 (org-columns-update "A")
926 (org-entry-get nil
"A"))))
930 (org-test-with-temp-text
939 (let ((org-columns-default-format "%A %A{min}")) (org-columns))
940 (org-columns-update "A")
941 (org-entry-get nil
"A"))))
942 ;; Ensure modifications propagate in upper levels even when multiple
943 ;; summary types apply to the same property.
947 (org-test-with-temp-text
958 (goto-char (point-min))
959 (let ((org-columns-default-format "%A{min} %A{max}")) (org-columns)))
961 (org-columns-update "A")
962 (list (get-char-property 1 'org-columns-value
)
963 (get-char-property 2 'org-columns-value-modified
)))))
964 ;; Ensure additional processing is done (e.g., ellipses, special
965 ;; keywords fontification...).
969 (org-test-with-temp-text
975 (let ((org-columns-default-format "%4A")
976 (org-columns-ellipses ".."))
978 (search-forward ":A: ")
979 (insert "very long ")
980 (org-columns-update "A")
981 (get-char-property (point-min) 'display
))))
982 ;; Values obtained from inline tasks are at the same level as those
983 ;; obtained from children of the current node.
984 (when (featurep 'org-inlinetask
)
988 (org-test-with-temp-text
990 *************** Inline task
1000 (let ((org-columns-default-format "%A{min}")
1001 (org-columns-ellipses "..")
1002 (org-inlinetask-min-level 15))
1004 (get-char-property (point-min) 'org-columns-value
)))))
1005 ;; Handle `org-columns-modify-value-for-display-function', even with
1006 ;; multiple titles for the same property.
1008 (equal '("foo" "bar")
1009 (org-test-with-temp-text "* H"
1010 (let ((org-columns-default-format "%ITEM %ITEM(Name)")
1011 (org-columns-modify-value-for-display-function
1012 (lambda (title value
)
1013 (pcase title
("ITEM" "foo") ("Name" "bar") (_ "baz")))))
1015 (list (get-char-property 1 'org-columns-value-modified
)
1016 (get-char-property 2 'org-columns-value-modified
))))))
1018 (ert-deftest test-org-colview
/columns-move-left
()
1019 "Test `org-columns-move-left' specifications."
1020 ;; Error when trying to move the left-most column.
1022 (org-test-with-temp-text "* H"
1023 (let ((org-columns-default-format "%ITEM")) (org-columns))
1024 (org-columns-move-left)))
1025 ;; Otherwise, move column to left and update display.
1028 (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:B: 2\n:END:"
1029 (let ((org-columns-default-format "%A %B")) (org-columns))
1031 (org-columns-move-left)
1032 (list (get-char-property (point) 'org-columns-value
)
1033 (get-char-property (1+ (point)) 'org-columns-value
)))))
1034 ;; Handle multiple columns with the same property.
1037 (org-test-with-temp-text
1047 (let ((org-columns-default-format "%ITEM %A{min} %A{max}"))
1050 (org-columns-move-left)
1051 (list (get-char-property (point) 'org-columns-value
)
1052 (get-char-property (1+ (point)) 'org-columns-value
)))))
1053 ;; Special case: do not update values even if move entails changing
1057 (org-test-with-temp-text
1066 (let ((org-columns-default-format "%A %A{max}"))
1069 (org-columns-move-left)
1070 ;; Since the first column matching a given property
1071 ;; determines how a value is computed, the following
1072 ;; should return "99" instead. However, this behavior is
1073 ;; in practice surprising so we just ignore the value
1074 ;; change. It can be computed later.
1075 (org-entry-get (point) "A")))))
1077 (ert-deftest test-org-colview
/columns-move-right
()
1078 "Test `org-columns-move-right' specifications."
1079 ;; Error when trying to move the right-most column.
1081 (org-test-with-temp-text "* H"
1082 (let ((org-columns-default-format "%ITEM")) (org-columns))
1083 (org-columns-move-right)))
1084 ;; Otherwise, move column to left and update display.
1087 (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:B: 2\n:END:"
1088 (let ((org-columns-default-format "%A %B")) (org-columns))
1089 (org-columns-move-right)
1090 (list (get-char-property (1- (point)) 'org-columns-value
)
1091 (get-char-property (point) 'org-columns-value
)))))
1092 ;; Handle multiple columns with the same property.
1095 (org-test-with-temp-text
1105 (let ((org-columns-default-format "%ITEM %A{min} %A{max}"))
1108 (org-columns-move-right)
1109 (list (get-char-property (1- (point)) 'org-columns-value
)
1110 (get-char-property (point) 'org-columns-value
)))))
1111 ;; Special case: do not update values even if move entails changing
1115 (org-test-with-temp-text
1124 (let ((org-columns-default-format "%A %A{max}"))
1126 (org-columns-move-right)
1127 ;; See `test-org-colview/columns-move-left' for an
1129 (org-entry-get (point) "A")))))
1131 (ert-deftest test-org-colview
/columns-next-allowed-value
()
1132 "Test `org-columns-next-allowed-value' specifications."
1133 ;; Cannot shift "ITEM" property.
1135 (org-test-with-temp-text "* H"
1136 (let ((org-columns-default-format "%ITEM")) (org-columns))
1137 (org-columns-next-allowed-value)))
1138 ;; Throw an error when allowed values are not defined.
1140 (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:"
1141 (let ((org-columns-default-format "%A")) (org-columns))
1142 (org-columns-next-allowed-value)))
1143 ;; Throw an error when there's only one value to select.
1145 (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:A_ALL: 1\n:END:"
1146 (let ((org-columns-default-format "%A")) (org-columns))
1147 (org-columns-next-allowed-value)))
1148 ;; By default select the next allowed value. Where there is no more
1149 ;; value, start again from first possible one.
1152 (org-test-with-temp-text
1153 "* H\n:PROPERTIES:\n:A: 1\n:A_ALL: 1 2 3\n:END:"
1154 (let ((org-columns-default-format "%A")) (org-columns))
1155 (org-columns-next-allowed-value)
1156 (org-entry-get (point) "A"))))
1159 (org-test-with-temp-text
1160 "* H\n:PROPERTIES:\n:A: 2\n:A_ALL: 1 2 3\n:END:"
1161 (let ((org-columns-default-format "%A")) (org-columns))
1162 (org-columns-next-allowed-value)
1163 (org-entry-get (point) "A"))))
1166 (org-test-with-temp-text
1167 "* H\n:PROPERTIES:\n:A: 3\n:A_ALL: 1 2 3\n:END:"
1168 (let ((org-columns-default-format "%A")) (org-columns))
1169 (org-columns-next-allowed-value)
1170 (org-entry-get (point) "A"))))
1171 ;; PREVIOUS argument moves backward.
1174 (org-test-with-temp-text
1175 "* H\n:PROPERTIES:\n:A: 2\n:A_ALL: 1 2 3\n:END:"
1176 (let ((org-columns-default-format "%A")) (org-columns))
1177 (org-columns-next-allowed-value 'previous
)
1178 (org-entry-get (point) "A"))))
1181 (org-test-with-temp-text
1182 "* H\n:PROPERTIES:\n:A: 3\n:A_ALL: 1 2 3\n:END:"
1183 (let ((org-columns-default-format "%A")) (org-columns))
1184 (org-columns-next-allowed-value 'previous
)
1185 (org-entry-get (point) "A"))))
1188 (org-test-with-temp-text
1189 "* H\n:PROPERTIES:\n:A: 1\n:A_ALL: 1 2 3\n:END:"
1190 (let ((org-columns-default-format "%A")) (org-columns))
1191 (org-columns-next-allowed-value 'previous
)
1192 (org-entry-get (point) "A"))))
1193 ;; Select Nth element with optional argument NTH.
1196 (org-test-with-temp-text
1197 "* H\n:PROPERTIES:\n:A: 2\n:A_ALL: 1 2 3\n:END:"
1198 (let ((org-columns-default-format "%A")) (org-columns))
1199 (org-columns-next-allowed-value nil
1)
1200 (org-entry-get (point) "A"))))
1201 ;; If NTH is negative, go backwards, 0 being the last one and -1 the
1205 (org-test-with-temp-text
1206 "* H\n:PROPERTIES:\n:A: 2\n:A_ALL: 1 2 3\n:END:"
1207 (let ((org-columns-default-format "%A")) (org-columns))
1208 (org-columns-next-allowed-value nil
0)
1209 (org-entry-get (point) "A"))))
1212 (org-test-with-temp-text
1213 "* H\n:PROPERTIES:\n:A: 2\n:A_ALL: 1 2 3\n:END:"
1214 (let ((org-columns-default-format "%A")) (org-columns))
1215 (org-columns-next-allowed-value nil -
1)
1216 (org-entry-get (point) "A"))))
1217 ;; Throw an error if NTH is greater than the number of allowed
1220 (org-test-with-temp-text
1221 "* H\n:PROPERTIES:\n:A: 2\n:A_ALL: 1 2 3\n:END:"
1222 (let ((org-columns-default-format "%A")) (org-columns))
1223 (org-columns-next-allowed-value nil
4)
1224 (org-entry-get (point) "A")))
1225 ;; Pathological case: when shifting the value alters the current
1226 ;; heading, make sure all columns are still at their correct
1229 (equal '("H" "" "" "" "TODO")
1230 (let ((org-todo-keywords '((sequence "TODO" "DONE"))))
1231 (org-test-with-temp-text "* H"
1232 (let ((org-columns-default-format "%ITEM %A %B %C %TODO"))
1235 (org-columns-next-allowed-value)
1236 (list (get-char-property (- (point) 4) 'org-columns-value
)
1237 (get-char-property (- (point) 3) 'org-columns-value
)
1238 (get-char-property (- (point) 2) 'org-columns-value
)
1239 (get-char-property (- (point) 1) 'org-columns-value
)
1240 (get-char-property (point) 'org-columns-value
)))))))
1242 (equal '("H" "VERYLONGTODO")
1243 (let ((org-todo-keywords '((sequence "TODO" "VERYLONGTODO"))))
1244 (org-test-with-temp-text "* TODO H"
1245 (let ((org-columns-default-format "%ITEM %TODO"))
1248 (org-columns-next-allowed-value)
1249 (list (get-char-property (- (point) 1) 'org-columns-value
)
1250 (get-char-property (point) 'org-columns-value
))))))))
1256 (ert-deftest test-org-colview
/dblock
()
1257 "Test the column view table."
1260 "#+BEGIN: columnview
1265 (org-test-with-temp-text
1266 "* H\n<point>#+BEGIN: columnview\n#+END:"
1267 (let ((org-columns-default-format "%ITEM")) (org-update-dblock))
1268 (buffer-substring-no-properties (point) (point-max)))))
1271 "#+BEGIN: columnview
1276 (org-test-with-temp-text
1277 "* H\n:PROPERTIES:\n:A: 1\n:END:\n<point>#+BEGIN: columnview\n#+END:"
1278 (let ((org-columns-default-format "%ITEM %A")) (org-update-dblock))
1279 (buffer-substring-no-properties (point) (point-max)))))
1280 ;; Properties are case insensitive.
1283 "#+BEGIN: columnview
1288 (org-test-with-temp-text
1289 "* H\n:PROPERTIES:\n:A: 1\n:END:\n<point>#+BEGIN: columnview\n#+END:"
1290 (let ((org-columns-default-format "%a")) (org-update-dblock))
1291 (buffer-substring-no-properties (point) (point-max)))))
1292 ;; Test titles given to columns.
1295 "#+BEGIN: columnview
1300 (org-test-with-temp-text
1301 "* H\n:PROPERTIES:\n:A: 1\n:END:\n<point>#+BEGIN: columnview\n#+END:"
1302 (let ((org-columns-default-format "%ITEM(Name) %A(Prop)"))
1303 (org-update-dblock))
1304 (buffer-substring-no-properties (point) (point-max)))))
1305 ;; Test `:id' parameter
1308 "#+BEGIN: columnview :id local
1315 (org-test-with-temp-text
1316 "* H1\n<point>#+BEGIN: columnview :id local\n#+END:\n** H1.1\n* H2"
1317 (let ((org-columns-default-format "%ITEM")) (org-update-dblock))
1318 (buffer-substring-no-properties (point) (outline-next-heading)))))
1321 "#+BEGIN: columnview :id global
1329 (org-test-with-temp-text
1330 "\n* H1\n<point>#+BEGIN: columnview :id global\n#+END:\n** H1.1\n* H2"
1331 (let ((org-columns-default-format "%ITEM")) (org-update-dblock))
1332 (buffer-substring-no-properties (point) (outline-next-heading)))))
1333 ;; Test `:hlines' parameter.
1336 "#+BEGIN: columnview :hlines t :id global
1345 (org-test-with-temp-text
1348 <point>#+BEGIN: columnview :hlines t :id global
1352 (let ((org-columns-default-format "%ITEM")) (org-update-dblock))
1353 (buffer-substring-no-properties (point) (outline-next-heading)))))
1356 "#+BEGIN: columnview :hlines 1 :id global
1364 (org-test-with-temp-text
1367 <point>#+BEGIN: columnview :hlines 1 :id global
1371 (let ((org-columns-default-format "%ITEM")) (org-update-dblock))
1372 (buffer-substring-no-properties (point) (outline-next-heading)))))
1375 "#+BEGIN: columnview :hlines 1 :id \"id\"
1382 (org-test-with-temp-text
1385 <point>#+BEGIN: columnview :hlines 1 :id \"id\"
1392 (let ((org-columns-default-format "%ITEM")) (org-update-dblock))
1393 (buffer-substring-no-properties (point) (outline-next-heading)))))
1396 "#+BEGIN: columnview :hlines 1 :id id
1403 (org-test-with-temp-text
1406 <point>#+BEGIN: columnview :hlines 1 :id id
1413 (let ((org-columns-default-format "%ITEM")) (org-update-dblock))
1414 (buffer-substring-no-properties (point) (outline-next-heading)))))
1415 ;; Test `:indent' parameter.
1418 "#+BEGIN: columnview :indent t
1425 (org-test-with-temp-text
1426 "* H1\n<point>#+BEGIN: columnview :indent t\n#+END:\n** H1.1"
1427 (let ((org-columns-default-format "%ITEM")) (org-update-dblock))
1428 (buffer-substring-no-properties (point) (outline-next-heading)))))
1431 "#+BEGIN: columnview :indent t
1438 (org-test-with-temp-text
1439 "* H1\n<point>#+BEGIN: columnview :indent t\n#+END:\n** H1.1"
1440 (let ((org-columns-default-format "%A(Prop) %ITEM(Name)"))
1441 (org-update-dblock))
1442 (buffer-substring-no-properties (point) (outline-next-heading)))))
1443 ;; Test `:vlines' parameter.
1446 "#+BEGIN: columnview :vlines t
1452 (org-test-with-temp-text
1453 "* H\n:PROPERTIES:\n:A: 1\n:END:\n<point>#+BEGIN: columnview :vlines t\n#+END:"
1454 (let ((org-columns-default-format "%ITEM %A")) (org-update-dblock))
1455 (buffer-substring-no-properties (point) (point-max)))))
1456 ;; Test `:skip-empty-rows' parameter.
1459 "#+BEGIN: columnview :skip-empty-rows t
1465 (org-test-with-temp-text
1468 <point>#+BEGIN: columnview :skip-empty-rows t
1474 (let ((org-columns-default-format "%ITEM %A")) (org-update-dblock))
1475 (buffer-substring-no-properties (point) (outline-next-heading)))))
1476 ;; Test `:format' parameter.
1479 "#+BEGIN: columnview :format \"%ITEM(Name)\"
1484 (org-test-with-temp-text
1485 "* H\n<point>#+BEGIN: columnview :format \"%ITEM(Name)\"\n#+END:"
1486 (let ((org-columns-default-format "%ITEM")) (org-update-dblock))
1487 (buffer-substring-no-properties (point) (point-max)))))
1488 ;; When inserting ITEM values, make sure to clean sensitive
1489 ;; contents, like unique targets or forbidden inline src-blocks.
1492 "#+BEGIN: columnview
1497 (org-test-with-temp-text
1498 "* H <<target>> 1\n<point>#+BEGIN: columnview\n#+END:"
1499 (let ((org-columns-default-format "%ITEM")) (org-update-dblock))
1500 (buffer-substring-no-properties (point) (point-max)))))
1503 "#+BEGIN: columnview
1508 (org-test-with-temp-text
1509 "* H src_emacs-lisp{(+ 1 1)} 1\n<point>#+BEGIN: columnview\n#+END:"
1510 (let ((org-columns-default-format "%ITEM")) (org-update-dblock))
1511 (buffer-substring-no-properties (point) (point-max))))))
1513 (provide 'test-org-colview
)
1514 ;;; test-org-colview.el ends here