aboutsummaryrefslogtreecommitdiff
path: root/tests/test-org-drill-entry-p.el
blob: c298c941beb47d13e0791ca76bf3aeb74a9331e6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
;;; test-org-drill-entry-p.el --- Tests for org-drill-entry-p function

;;; Commentary:
;; Unit tests for org-drill-entry-p, which determines if point is at a
;; drill entry heading (not a subheading within a drill entry).
;;
;; The function checks for the drill tag at the current heading only,
;; not inherited tags. Use org-drill-part-of-drill-entry-p for inherited tags.

;;; Code:

(require 'ert)
(require 'assess)
(require 'org-drill)

;;; Test Data

(defconst test-org-drill-entry-p-simple-entry
  "* Heading with drill tag :drill:

Body content here."
  "Simple drill entry with drill tag on main heading.")

(defconst test-org-drill-entry-p-no-tag
  "* Heading without drill tag

Body content here."
  "Heading without any drill tag.")

(defconst test-org-drill-entry-p-nested-entry
  "* Parent heading :drill:

Parent content.

** Child heading

Child content."
  "Drill entry with nested child heading.")

(defconst test-org-drill-entry-p-multiple-tags
  "* Heading :drill:important:review:

Body with multiple tags."
  "Drill entry with multiple tags including drill.")

(defconst test-org-drill-entry-p-custom-tag
  "* Heading :customtag:

Body with custom tag."
  "Heading with custom tag (not drill).")

;;; Helper Functions

(defun test-org-drill-entry-p--with-org-buffer (content callback)
  "Execute CALLBACK in temporary org-mode buffer with CONTENT."
  (with-temp-buffer
    (org-mode)
    (insert content)
    (goto-char (point-min))
    (funcall callback)))

;;; Normal Cases

(ert-deftest test-org-drill-entry-p-normal-valid-tag-returns-true ()
  "Test that heading with drill tag is identified as drill entry."
  (test-org-drill-entry-p--with-org-buffer
   test-org-drill-entry-p-simple-entry
   (lambda ()
     (should (org-drill-entry-p)))))

(ert-deftest test-org-drill-entry-p-normal-no-tag-returns-nil ()
  "Test that heading without drill tag returns nil."
  (test-org-drill-entry-p--with-org-buffer
   test-org-drill-entry-p-no-tag
   (lambda ()
     (should-not (org-drill-entry-p)))))

(ert-deftest test-org-drill-entry-p-normal-multiple-tags-returns-true ()
  "Test that heading with multiple tags including drill is identified."
  (test-org-drill-entry-p--with-org-buffer
   test-org-drill-entry-p-multiple-tags
   (lambda ()
     (should (org-drill-entry-p)))))

(ert-deftest test-org-drill-entry-p-normal-at-parent-heading-returns-true ()
  "Test that function works when point is at parent drill heading."
  (test-org-drill-entry-p--with-org-buffer
   test-org-drill-entry-p-nested-entry
   (lambda ()
     ;; Point should be at parent heading after goto-char (point-min)
     (should (org-drill-entry-p)))))

;;; Boundary Cases

(ert-deftest test-org-drill-entry-p-boundary-at-child-heading-returns-nil ()
  "Test that child heading of drill entry returns nil.
Only the heading with the actual drill tag should return true."
  (test-org-drill-entry-p--with-org-buffer
   test-org-drill-entry-p-nested-entry
   (lambda ()
     ;; Move to child heading
     (re-search-forward "^\\*\\* Child heading")
     (beginning-of-line)
     (should-not (org-drill-entry-p)))))

(ert-deftest test-org-drill-entry-p-boundary-empty-heading-no-tag-returns-nil ()
  "Test that empty heading without tags returns nil."
  (test-org-drill-entry-p--with-org-buffer
   "* Empty heading\n"
   (lambda ()
     (should-not (org-drill-entry-p)))))

(ert-deftest test-org-drill-entry-p-boundary-heading-with-only-whitespace-tag ()
  "Test heading with whitespace around tags."
  (test-org-drill-entry-p--with-org-buffer
   "* Heading   :drill:   \n\nContent"
   (lambda ()
     (should (org-drill-entry-p)))))

(ert-deftest test-org-drill-entry-p-boundary-custom-tag-not-drill ()
  "Test that custom tag (not drill) returns nil."
  (test-org-drill-entry-p--with-org-buffer
   test-org-drill-entry-p-custom-tag
   (lambda ()
     (should-not (org-drill-entry-p)))))

(ert-deftest test-org-drill-entry-p-boundary-drill-substring-in-other-tag ()
  "Test that drill as substring of another tag does not match.
Tag 'drilling' should not be identified as drill entry."
  (test-org-drill-entry-p--with-org-buffer
   "* Heading :drilling:\n\nContent"
   (lambda ()
     (should-not (org-drill-entry-p)))))

(ert-deftest test-org-drill-entry-p-boundary-case-sensitive-tag ()
  "Test that drill tag matching is case-sensitive.
Tag 'DRILL' should not match 'drill'."
  (test-org-drill-entry-p--with-org-buffer
   "* Heading :DRILL:\n\nContent"
   (lambda ()
     ;; org-mode tags are case-sensitive by default
     (should-not (org-drill-entry-p)))))

;;; Error Cases

(ert-deftest test-org-drill-entry-p-error-point-in-body-text ()
  "Test behavior when point is in body text, not at heading.
Function should check current heading context."
  (test-org-drill-entry-p--with-org-buffer
   test-org-drill-entry-p-simple-entry
   (lambda ()
     ;; Move to body text
     (re-search-forward "Body content")
     (beginning-of-line)
     ;; Even though we're in a drill entry's body, org-drill-entry-p
     ;; checks the current heading when point is in body
     (should (org-drill-entry-p)))))

(ert-deftest test-org-drill-entry-p-error-empty-buffer ()
  "Test behavior in empty buffer.
Should not error, just return nil."
  (with-temp-buffer
    (org-mode)
    (should-not (org-drill-entry-p))))

(ert-deftest test-org-drill-entry-p-error-buffer-without-headings ()
  "Test behavior in buffer with only text, no headings."
  (test-org-drill-entry-p--with-org-buffer
   "Just some text without any headings."
   (lambda ()
     (should-not (org-drill-entry-p)))))

(ert-deftest test-org-drill-entry-p-error-malformed-heading ()
  "Test behavior with malformed heading syntax.
Single asterisk should still work as heading."
  (test-org-drill-entry-p--with-org-buffer
   "* Malformed :drill:\nNo blank line before content"
   (lambda ()
     (should (org-drill-entry-p)))))

(provide 'test-org-drill-entry-p)
;;; test-org-drill-entry-p.el ends here