aboutsummaryrefslogtreecommitdiff
path: root/tests/test-org-drill-entry-p.el
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2025-11-13 11:36:06 -0600
committerCraig Jennings <c@cjennings.net>2025-11-13 11:36:06 -0600
commitcf182d001f66164232b8735bad43eb07121109c6 (patch)
treea70cc6f6d16a2c4cbb67c6850e59728158f3f383 /tests/test-org-drill-entry-p.el
parent87e74a3a6ccf5b05b760e9f8beec9a78886ab076 (diff)
downloadorg-drill-cf182d001f66164232b8735bad43eb07121109c6.tar.gz
org-drill-cf182d001f66164232b8735bad43eb07121109c6.zip
test: Add Phase 1 foundation tests for critical functions
- Add unit tests for org-drill-entry-p (14 tests) - Add unit tests for org-drill-part-of-drill-entry-p (14 tests) - Add unit tests for SM2 scheduling algorithm (23 tests) - Add integration test for basic drill workflow (11 tests) - Update Makefile to support test-*.el naming pattern - Rename org-drill-test.el to test-org-drill.el for consistency Total: 65 tests, all passing
Diffstat (limited to 'tests/test-org-drill-entry-p.el')
-rw-r--r--tests/test-org-drill-entry-p.el182
1 files changed, 182 insertions, 0 deletions
diff --git a/tests/test-org-drill-entry-p.el b/tests/test-org-drill-entry-p.el
new file mode 100644
index 0000000..c298c94
--- /dev/null
+++ b/tests/test-org-drill-entry-p.el
@@ -0,0 +1,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