aboutsummaryrefslogtreecommitdiff
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
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
-rw-r--r--Makefile4
-rw-r--r--tests/test-integration-drill-session-simple-workflow-integration-test.el348
-rw-r--r--tests/test-org-drill-determine-next-interval-sm2.el307
-rw-r--r--tests/test-org-drill-entry-p.el182
-rw-r--r--tests/test-org-drill-part-of-drill-entry-p.el231
-rw-r--r--tests/test-org-drill.el (renamed from tests/org-drill-test.el)0
6 files changed, 1071 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index 4ed36a4..b4ece5d 100644
--- a/Makefile
+++ b/Makefile
@@ -26,7 +26,9 @@ endif
# Test directories and files
TEST_DIR = tests
-UNIT_TESTS = $(filter-out $(TEST_DIR)/%-integration-test.el, $(wildcard $(TEST_DIR)/*-test.el))
+# Match test-*.el pattern, excluding integration tests
+UNIT_TESTS = $(filter-out $(TEST_DIR)/%integration-test.el, \
+ $(wildcard $(TEST_DIR)/test-*.el))
INTEGRATION_TESTS = $(wildcard $(TEST_DIR)/*-integration-test.el)
ALL_TESTS = $(UNIT_TESTS) $(INTEGRATION_TESTS)
diff --git a/tests/test-integration-drill-session-simple-workflow-integration-test.el b/tests/test-integration-drill-session-simple-workflow-integration-test.el
new file mode 100644
index 0000000..9e839a2
--- /dev/null
+++ b/tests/test-integration-drill-session-simple-workflow-integration-test.el
@@ -0,0 +1,348 @@
+;;; test-integration-drill-session-simple-workflow-integration-test.el --- Integration test for basic drill workflow
+
+;;; Commentary:
+;; Integration test for the basic org-drill workflow, testing how
+;; components work together:
+;;
+;; 1. Entry detection (org-drill-entry-p)
+;; 2. Entry enumeration (org-drill-map-entries)
+;; 3. Data retrieval (org-drill-get-item-data)
+;; 4. Scheduling algorithm (org-drill-determine-next-interval-sm2)
+;; 5. Data storage (org-drill-store-item-data)
+;;
+;; This test uses actual org-mode buffers with drill entries to verify
+;; the complete workflow from entry detection through scheduling.
+
+;;; Code:
+
+(require 'ert)
+(require 'assess)
+(require 'org-drill)
+
+;;; Test Data
+
+(defconst test-integration-simple-workflow-basic-entries
+ "#+TITLE: Basic Drill Session Test
+
+* First Card :drill:
+:PROPERTIES:
+:DRILL_LAST_INTERVAL: 4
+:DRILL_REPEATS_SINCE_FAIL: 2
+:DRILL_TOTAL_REPEATS: 5
+:DRILL_FAILURE_COUNT: 1
+:DRILL_AVERAGE_QUALITY: 3.8
+:DRILL_EASE: 2.5
+:END:
+
+Question: What is 2+2?
+
+Answer: 4
+
+* Second Card :drill:
+:PROPERTIES:
+:DRILL_LAST_INTERVAL: 10
+:DRILL_REPEATS_SINCE_FAIL: 4
+:DRILL_TOTAL_REPEATS: 4
+:DRILL_FAILURE_COUNT: 0
+:DRILL_AVERAGE_QUALITY: 4.5
+:DRILL_EASE: 2.6
+:END:
+
+Question: What is the capital of France?
+
+Answer: Paris
+
+* Not a drill card
+
+This heading has no drill tag, so it should be ignored.
+
+* Third Card :drill:
+:PROPERTIES:
+:DRILL_LAST_INTERVAL: 1
+:DRILL_REPEATS_SINCE_FAIL: 1
+:DRILL_TOTAL_REPEATS: 3
+:DRILL_FAILURE_COUNT: 2
+:DRILL_AVERAGE_QUALITY: 2.3
+:DRILL_EASE: 2.0
+:END:
+
+Question: What is the largest planet?
+
+Answer: Jupiter
+"
+ "Basic drill entries with varying scheduling data.")
+
+(defconst test-integration-simple-workflow-new-entries
+ "#+TITLE: New Drill Entries Test
+
+* Brand New Card :drill:
+
+Question: What is Emacs?
+
+Answer: A powerful text editor.
+
+* Another New Card :drill:
+
+Question: What is org-mode?
+
+Answer: An Emacs mode for note-taking and organization.
+"
+ "New drill entries with no scheduling data.")
+
+;;; Helper Functions
+
+(defun test-integration-simple-workflow--with-drill-buffer (content callback)
+ "Execute CALLBACK in temporary org-mode buffer with drill CONTENT."
+ (with-temp-buffer
+ (org-mode)
+ (insert content)
+ (goto-char (point-min))
+ (funcall callback)))
+
+(defun test-integration-simple-workflow--count-drill-entries (content)
+ "Count number of drill entries in CONTENT."
+ (test-integration-simple-workflow--with-drill-buffer
+ content
+ (lambda ()
+ (length (org-drill-map-entries (lambda () (point)) 'file nil)))))
+
+;;; Normal Cases - Entry Detection
+
+(ert-deftest test-integration-simple-workflow-normal-detect-multiple-entries ()
+ "Test that multiple drill entries are detected in a file.
+Should find exactly 3 drill entries, ignoring non-drill headings."
+ (let ((count (test-integration-simple-workflow--count-drill-entries
+ test-integration-simple-workflow-basic-entries)))
+ (should (= count 3))))
+
+(ert-deftest test-integration-simple-workflow-normal-detect-new-entries ()
+ "Test detection of new drill entries without scheduling data."
+ (let ((count (test-integration-simple-workflow--count-drill-entries
+ test-integration-simple-workflow-new-entries)))
+ (should (= count 2))))
+
+;;; Normal Cases - Entry Data Retrieval
+
+(ert-deftest test-integration-simple-workflow-normal-retrieve-entry-data ()
+ "Test retrieving scheduling data from drill entry.
+Should correctly parse all DRILL_* properties."
+ (test-integration-simple-workflow--with-drill-buffer
+ test-integration-simple-workflow-basic-entries
+ (lambda ()
+ ;; Find first drill entry
+ (re-search-forward "^\\* First Card :drill:")
+ (beginning-of-line)
+ (let ((data (org-drill-get-item-data)))
+ ;; Verify structure: (last-interval repeats failures total-repeats meanq ease)
+ (should (listp data))
+ (should (= (length data) 6))
+ ;; Verify values match properties
+ (should (= (nth 0 data) 4)) ; DRILL_LAST_INTERVAL
+ (should (= (nth 1 data) 2)) ; DRILL_REPEATS_SINCE_FAIL
+ (should (= (nth 2 data) 1)) ; DRILL_FAILURE_COUNT
+ (should (= (nth 3 data) 5)) ; DRILL_TOTAL_REPEATS
+ (should (= (nth 4 data) 3.8)) ; DRILL_AVERAGE_QUALITY
+ (should (= (nth 5 data) 2.5)) ; DRILL_EASE
+ ))))
+
+(ert-deftest test-integration-simple-workflow-normal-retrieve-new-entry-data ()
+ "Test retrieving data from new entry with no properties.
+Should return default values for new items."
+ (test-integration-simple-workflow--with-drill-buffer
+ test-integration-simple-workflow-new-entries
+ (lambda ()
+ ;; Find first drill entry
+ (re-search-forward "^\\* Brand New Card :drill:")
+ (beginning-of-line)
+ (let ((data (org-drill-get-item-data)))
+ ;; Verify structure exists
+ (should (listp data))
+ (should (= (length data) 6))
+ ;; New items should have sensible defaults (or nil)
+ (should (or (null (nth 0 data)) (numberp (nth 0 data)))) ; last-interval
+ (should (numberp (nth 1 data))) ; repeats
+ (should (numberp (nth 2 data))) ; failures
+ (should (numberp (nth 3 data))) ; total-repeats
+ ;; meanq (nth 4) can be nil for new items
+ ;; ease (nth 5) can be nil for new items
+ ))))
+
+;;; Normal Cases - Scheduling Algorithm Integration
+
+(ert-deftest test-integration-simple-workflow-normal-schedule-from-entry-data ()
+ "Test that entry data can be fed to scheduling algorithm.
+Verifies integration between data retrieval and SM2 algorithm."
+ (test-integration-simple-workflow--with-drill-buffer
+ test-integration-simple-workflow-basic-entries
+ (lambda ()
+ ;; Find second drill entry (good performance history)
+ (re-search-forward "^\\* Second Card :drill:")
+ (beginning-of-line)
+ (cl-destructuring-bind (last-interval repeats failures total-repeats meanq ease)
+ (org-drill-get-item-data)
+ ;; Simulate quality rating of 4 (good recall)
+ (let* ((quality 4)
+ (result (org-drill-determine-next-interval-sm2
+ last-interval repeats ease quality
+ failures meanq total-repeats))
+ (next-interval (nth 0 result))
+ (new-repeats (nth 1 result))
+ (new-ease (nth 2 result)))
+ ;; Verify scheduling result makes sense
+ (should (> next-interval last-interval)) ; Interval should increase
+ (should (= new-repeats (1+ repeats))) ; Repeats incremented
+ (should (numberp new-ease)) ; EF calculated
+ )))))
+
+(ert-deftest test-integration-simple-workflow-normal-schedule-failed-recall ()
+ "Test scheduling when card is failed.
+Verifies that failure handling works correctly in integrated workflow."
+ (test-integration-simple-workflow--with-drill-buffer
+ test-integration-simple-workflow-basic-entries
+ (lambda ()
+ ;; Find third drill entry (struggling item)
+ (re-search-forward "^\\* Third Card :drill:")
+ (beginning-of-line)
+ (cl-destructuring-bind (last-interval repeats failures total-repeats meanq ease)
+ (org-drill-get-item-data)
+ ;; Simulate complete failure (quality 0)
+ (let* ((quality 0)
+ (result (org-drill-determine-next-interval-sm2
+ last-interval repeats ease quality
+ failures meanq total-repeats))
+ (next-interval (nth 0 result))
+ (new-repeats (nth 1 result))
+ (new-failures (nth 3 result)))
+ ;; Verify failure handling
+ (should (= next-interval -1)) ; Failed cards get -1
+ (should (= new-repeats 1)) ; Repeats reset to 1
+ (should (= new-failures (1+ failures)))))))) ; Failure count incremented
+
+;;; Normal Cases - Data Storage Integration
+
+(ert-deftest test-integration-simple-workflow-normal-store-item-data ()
+ "Test that scheduling results can be stored back to entry.
+Verifies org-drill-store-item-data updates properties correctly."
+ (test-integration-simple-workflow--with-drill-buffer
+ test-integration-simple-workflow-basic-entries
+ (lambda ()
+ ;; Find first drill entry
+ (re-search-forward "^\\* First Card :drill:")
+ (beginning-of-line)
+
+ ;; Get original data
+ (cl-destructuring-bind (last-interval repeats failures total-repeats meanq ease)
+ (org-drill-get-item-data)
+
+ ;; Calculate new scheduling data
+ (let* ((quality 5) ; Perfect recall
+ (result (org-drill-determine-next-interval-sm2
+ last-interval repeats ease quality
+ failures meanq total-repeats))
+ (next-interval (nth 0 result))
+ (new-repeats (nth 1 result))
+ (new-ease (nth 2 result))
+ (new-failures (nth 3 result))
+ (new-meanq (nth 4 result))
+ (new-total (nth 5 result)))
+
+ ;; Store new data
+ (org-drill-store-item-data next-interval new-repeats new-failures
+ new-total new-meanq new-ease)
+
+ ;; Verify data was stored (properties exist and are valid)
+ (should (org-entry-get (point) "DRILL_LAST_INTERVAL"))
+ (should (org-entry-get (point) "DRILL_REPEATS_SINCE_FAIL"))
+ (should (org-entry-get (point) "DRILL_FAILURE_COUNT"))
+ (should (org-entry-get (point) "DRILL_TOTAL_REPEATS"))
+ (should (org-entry-get (point) "DRILL_AVERAGE_QUALITY"))
+ (should (org-entry-get (point) "DRILL_EASE"))
+
+ ;; Verify values are numeric and match expectations
+ (should (= (string-to-number (org-entry-get (point) "DRILL_REPEATS_SINCE_FAIL"))
+ new-repeats))
+ (should (= (string-to-number (org-entry-get (point) "DRILL_FAILURE_COUNT"))
+ new-failures))
+ (should (= (string-to-number (org-entry-get (point) "DRILL_TOTAL_REPEATS"))
+ new-total))
+ )))))
+
+;;; Boundary Cases - Edge Conditions
+
+(ert-deftest test-integration-simple-workflow-boundary-empty-file ()
+ "Test drill entry detection in empty file.
+Should handle empty files gracefully."
+ (let ((count (test-integration-simple-workflow--count-drill-entries "")))
+ (should (= count 0))))
+
+(ert-deftest test-integration-simple-workflow-boundary-no-drill-entries ()
+ "Test file with headings but no drill tags."
+ (let* ((content "* Heading One\n\nContent.\n\n* Heading Two\n\nMore content.\n")
+ (count (test-integration-simple-workflow--count-drill-entries content)))
+ (should (= count 0))))
+
+(ert-deftest test-integration-simple-workflow-boundary-mixed-drill-and-non-drill ()
+ "Test that drill and non-drill entries are correctly distinguished."
+ (test-integration-simple-workflow--with-drill-buffer
+ test-integration-simple-workflow-basic-entries
+ (lambda ()
+ (let ((drill-count 0)
+ (non-drill-count 0))
+ ;; Count drill entries
+ (goto-char (point-min))
+ (while (re-search-forward "^\\* " nil t)
+ (beginning-of-line)
+ (if (org-drill-entry-p)
+ (cl-incf drill-count)
+ (cl-incf non-drill-count))
+ (forward-line))
+ (should (= drill-count 3))
+ (should (= non-drill-count 1))))))
+
+;;; Integration - Complete Workflow Simulation
+
+(ert-deftest test-integration-simple-workflow-integration-complete-review-cycle ()
+ "Test complete review cycle: detect -> retrieve -> schedule -> store.
+Simulates reviewing a card and verifies all components work together."
+ (test-integration-simple-workflow--with-drill-buffer
+ test-integration-simple-workflow-basic-entries
+ (lambda ()
+ ;; Step 1: Detect drill entries
+ (let ((entries (org-drill-map-entries (lambda () (point)) 'file nil)))
+ (should (= (length entries) 3))
+
+ ;; Step 2: Navigate to first entry
+ (goto-char (car entries))
+ (should (org-drill-entry-p))
+
+ ;; Step 3: Retrieve current data
+ (cl-destructuring-bind (last-interval repeats failures total-repeats meanq ease)
+ (org-drill-get-item-data)
+ (should (numberp last-interval))
+ (should (numberp repeats))
+
+ ;; Step 4: Simulate review with quality 4
+ (let* ((quality 4)
+ (result (org-drill-determine-next-interval-sm2
+ last-interval repeats ease quality
+ failures meanq total-repeats))
+ (next-interval (nth 0 result))
+ (new-repeats (nth 1 result))
+ (new-ease (nth 2 result))
+ (new-failures (nth 3 result))
+ (new-meanq (nth 4 result))
+ (new-total (nth 5 result)))
+
+ ;; Step 5: Store results
+ (org-drill-store-item-data next-interval new-repeats new-failures
+ new-total new-meanq new-ease)
+
+ ;; Step 6: Verify data persisted
+ (let ((retrieved-data (org-drill-get-item-data)))
+ (should (= (nth 0 retrieved-data) (floor next-interval)))
+ (should (= (nth 1 retrieved-data) new-repeats))
+ (should (= (nth 2 retrieved-data) new-failures))
+ (should (= (nth 3 retrieved-data) new-total)))))))))
+
+(provide 'test-integration-drill-session-simple-workflow-integration-test)
+;;; test-integration-drill-session-simple-workflow-integration-test.el ends here
diff --git a/tests/test-org-drill-determine-next-interval-sm2.el b/tests/test-org-drill-determine-next-interval-sm2.el
new file mode 100644
index 0000000..abb7a0b
--- /dev/null
+++ b/tests/test-org-drill-determine-next-interval-sm2.el
@@ -0,0 +1,307 @@
+;;; test-org-drill-determine-next-interval-sm2.el --- Tests for SM2 algorithm
+
+;;; Commentary:
+;; Unit tests for org-drill-determine-next-interval-sm2, the SuperMemo 2 (SM2)
+;; spaced repetition algorithm implementation.
+;;
+;; The SM2 algorithm calculates the next review interval based on:
+;; - Last interval (days since last review)
+;; - Number of successful repeats (n)
+;; - Easiness factor (EF) - modified by recall quality
+;; - Quality of recall (0-5 scale)
+;; - Failure count and statistics
+;;
+;; Function signature:
+;; (org-drill-determine-next-interval-sm2 last-interval n ef quality
+;; failures meanq total-repeats)
+;;
+;; Returns: (INTERVAL REPEATS EF FAILURES MEAN TOTAL-REPEATS OFMATRIX)
+
+;;; Code:
+
+(require 'ert)
+(require 'assess)
+(require 'org-drill)
+
+;;; Test Data and Constants
+
+;; Default SM2 parameters
+(defconst test-sm2-default-ef 2.5
+ "Default easiness factor for new items.")
+
+(defconst test-sm2-min-ef 1.3
+ "Minimum easiness factor (SM2 floor).")
+
+;;; Helper Functions
+
+(defun test-sm2--extract-interval (result)
+ "Extract interval from SM2 result list."
+ (nth 0 result))
+
+(defun test-sm2--extract-repeats (result)
+ "Extract repeats from SM2 result list."
+ (nth 1 result))
+
+(defun test-sm2--extract-ef (result)
+ "Extract easiness factor from SM2 result list."
+ (nth 2 result))
+
+(defun test-sm2--extract-failures (result)
+ "Extract failures from SM2 result list."
+ (nth 3 result))
+
+(defun test-sm2--extract-meanq (result)
+ "Extract mean quality from SM2 result list."
+ (nth 4 result))
+
+(defun test-sm2--extract-total-repeats (result)
+ "Extract total repeats from SM2 result list."
+ (nth 5 result))
+
+;;; Normal Cases - Successful Reviews
+
+(ert-deftest test-org-drill-determine-next-interval-sm2-normal-first-review-quality-4 ()
+ "Test first successful review with quality 4.
+First review (n=1) should return interval of 1 day."
+ (let* ((result (org-drill-determine-next-interval-sm2 0 1 nil 4 0 nil 0))
+ (interval (test-sm2--extract-interval result))
+ (repeats (test-sm2--extract-repeats result))
+ (ef (test-sm2--extract-ef result)))
+ (should (= interval 1))
+ (should (= repeats 2))
+ (should ef))) ; EF should be calculated
+
+(ert-deftest test-org-drill-determine-next-interval-sm2-normal-second-review-quality-4 ()
+ "Test second successful review with quality 4.
+Second review (n=2) should return interval of 6 days (no random noise)."
+ (let ((org-drill-add-random-noise-to-intervals-p nil))
+ (let* ((result (org-drill-determine-next-interval-sm2 1 2 2.5 4 0 nil 0))
+ (interval (test-sm2--extract-interval result))
+ (repeats (test-sm2--extract-repeats result)))
+ (should (= interval 6))
+ (should (= repeats 3)))))
+
+(ert-deftest test-org-drill-determine-next-interval-sm2-normal-third-review-quality-4 ()
+ "Test third successful review with quality 4.
+Third review (n=3) uses formula: last-interval * EF."
+ (let ((org-drill-add-random-noise-to-intervals-p nil))
+ (let* ((ef 2.5)
+ (last-interval 6)
+ (result (org-drill-determine-next-interval-sm2 last-interval 3 ef 4 0 nil 0))
+ (interval (test-sm2--extract-interval result))
+ (new-ef (test-sm2--extract-ef result)))
+ ;; Interval should be approximately last-interval * new-ef
+ (should (> interval last-interval))
+ (should (= (test-sm2--extract-repeats result) 4)))))
+
+(ert-deftest test-org-drill-determine-next-interval-sm2-normal-quality-5-perfect-recall ()
+ "Test review with perfect recall (quality 5).
+Quality 5 should increase EF and result in longer intervals."
+ (let ((org-drill-add-random-noise-to-intervals-p nil))
+ (let* ((result (org-drill-determine-next-interval-sm2 10 3 2.5 5 0 nil 0))
+ (ef (test-sm2--extract-ef result)))
+ ;; Quality 5 should maintain or increase EF
+ (should (>= ef 2.5)))))
+
+(ert-deftest test-org-drill-determine-next-interval-sm2-normal-quality-3-adequate-recall ()
+ "Test review with adequate recall (quality 3).
+Quality 3 should maintain relatively stable EF."
+ (let ((org-drill-add-random-noise-to-intervals-p nil))
+ (let* ((result (org-drill-determine-next-interval-sm2 10 3 2.5 3 0 nil 0))
+ (ef (test-sm2--extract-ef result)))
+ ;; Quality 3 should result in moderate EF
+ (should (> ef test-sm2-min-ef))
+ (should (< ef 2.5))))) ; EF likely decreases slightly
+
+;;; Normal Cases - Failed Reviews
+
+(ert-deftest test-org-drill-determine-next-interval-sm2-normal-failure-quality-0 ()
+ "Test failed review with quality 0.
+Quality 0 (<= org-drill-failure-quality) should reset interval to -1."
+ (let* ((result (org-drill-determine-next-interval-sm2 10 3 2.5 0 0 nil 0))
+ (interval (test-sm2--extract-interval result))
+ (repeats (test-sm2--extract-repeats result))
+ (ef (test-sm2--extract-ef result))
+ (failures (test-sm2--extract-failures result)))
+ (should (= interval -1))
+ (should (= repeats 1)) ; Reset to 1
+ (should (= ef 2.5)) ; EF unchanged on failure
+ (should (= failures 1)))) ; Failure count incremented
+
+(ert-deftest test-org-drill-determine-next-interval-sm2-normal-failure-quality-1 ()
+ "Test failed review with quality 1.
+Quality 1 (<= org-drill-failure-quality) should reset interval."
+ (let* ((result (org-drill-determine-next-interval-sm2 15 5 2.6 1 2 3.5 10))
+ (interval (test-sm2--extract-interval result))
+ (ef (test-sm2--extract-ef result))
+ (failures (test-sm2--extract-failures result)))
+ (should (= interval -1))
+ (should (= ef 2.6)) ; EF unchanged
+ (should (= failures 3)))) ; Previous failures + 1
+
+(ert-deftest test-org-drill-determine-next-interval-sm2-normal-failure-quality-2 ()
+ "Test failed review with quality 2.
+Quality 2 (= org-drill-failure-quality default) should reset interval."
+ (let* ((result (org-drill-determine-next-interval-sm2 10 3 2.5 2 0 nil 0))
+ (interval (test-sm2--extract-interval result)))
+ (should (= interval -1))))
+
+;;; Boundary Cases - Default Values
+
+(ert-deftest test-org-drill-determine-next-interval-sm2-boundary-nil-ef-uses-default ()
+ "Test that nil EF defaults to 2.5."
+ (let* ((result (org-drill-determine-next-interval-sm2 0 1 nil 4 0 nil 0))
+ (ef (test-sm2--extract-ef result)))
+ (should ef) ; EF should be set (modified from default 2.5)
+ (should (> ef 0))))
+
+(ert-deftest test-org-drill-determine-next-interval-sm2-boundary-zero-n-becomes-one ()
+ "Test that n=0 is treated as n=1."
+ (let* ((result (org-drill-determine-next-interval-sm2 0 0 2.5 4 0 nil 0))
+ (interval (test-sm2--extract-interval result))
+ (repeats (test-sm2--extract-repeats result)))
+ (should (= interval 1)) ; First review interval
+ (should (= repeats 2)))) ; n incremented from 1 to 2
+
+(ert-deftest test-org-drill-determine-next-interval-sm2-boundary-nil-meanq-uses-quality ()
+ "Test that nil meanq initializes to current quality."
+ (let* ((quality 4)
+ (result (org-drill-determine-next-interval-sm2 0 1 2.5 quality 0 nil 0))
+ (meanq (test-sm2--extract-meanq result)))
+ (should (= meanq quality))))
+
+;;; Boundary Cases - Quality Extremes
+
+(ert-deftest test-org-drill-determine-next-interval-sm2-boundary-quality-5-maximum ()
+ "Test maximum quality (5) - perfect recall."
+ (let ((org-drill-add-random-noise-to-intervals-p nil))
+ (let* ((result (org-drill-determine-next-interval-sm2 1 2 2.5 5 0 nil 0))
+ (interval (test-sm2--extract-interval result)))
+ (should (= interval 6))))) ; Second review with quality 5
+
+(ert-deftest test-org-drill-determine-next-interval-sm2-boundary-quality-0-minimum ()
+ "Test minimum quality (0) - complete failure."
+ (let* ((result (org-drill-determine-next-interval-sm2 10 3 2.5 0 0 nil 0))
+ (interval (test-sm2--extract-interval result)))
+ (should (= interval -1)))) ; Failed review
+
+;;; Boundary Cases - Repeat Count
+
+(ert-deftest test-org-drill-determine-next-interval-sm2-boundary-n-equals-1 ()
+ "Test first successful review (n=1) returns interval of 1."
+ (let* ((result (org-drill-determine-next-interval-sm2 0 1 2.5 4 0 nil 0))
+ (interval (test-sm2--extract-interval result)))
+ (should (= interval 1))))
+
+(ert-deftest test-org-drill-determine-next-interval-sm2-boundary-n-equals-2-no-noise ()
+ "Test second review (n=2) with no random noise.
+Should return interval of 6 days regardless of quality (if passing)."
+ (let ((org-drill-add-random-noise-to-intervals-p nil))
+ (let* ((result (org-drill-determine-next-interval-sm2 1 2 2.5 4 0 nil 0))
+ (interval (test-sm2--extract-interval result)))
+ (should (= interval 6)))))
+
+(ert-deftest test-org-drill-determine-next-interval-sm2-boundary-n-equals-2-with-noise ()
+ "Test second review (n=2) with random noise enabled.
+Interval should vary by quality, with quality 5 having highest base interval (6)."
+ (let ((org-drill-add-random-noise-to-intervals-p t))
+ (let* ((result-q5 (org-drill-determine-next-interval-sm2 1 2 2.5 5 0 nil 0))
+ (result-q4 (org-drill-determine-next-interval-sm2 1 2 2.5 4 0 nil 0))
+ (result-q3 (org-drill-determine-next-interval-sm2 1 2 2.5 3 0 nil 0))
+ (interval-q5 (test-sm2--extract-interval result-q5))
+ (interval-q4 (test-sm2--extract-interval result-q4))
+ (interval-q3 (test-sm2--extract-interval result-q3)))
+ ;; Base intervals before noise are: Q5=6, Q4=4, Q3=3
+ ;; After random noise, verify intervals are positive and roughly in expected ranges
+ (should (> interval-q5 0))
+ (should (> interval-q4 0))
+ (should (> interval-q3 0))
+ ;; Quality 5 base interval (6) should generally be higher than quality 3 base (3)
+ ;; even with noise applied
+ (should (> interval-q5 2)))))
+
+;;; Boundary Cases - Mean Quality Calculation
+
+(ert-deftest test-org-drill-determine-next-interval-sm2-boundary-meanq-weighted-average ()
+ "Test that meanq is correctly calculated as weighted average.
+meanq = (quality + meanq * total-repeats) / (total-repeats + 1)"
+ (let* ((quality 4)
+ (meanq 3.0)
+ (total-repeats 10)
+ (result (org-drill-determine-next-interval-sm2 10 3 2.5 quality 0 meanq total-repeats))
+ (new-meanq (test-sm2--extract-meanq result))
+ (expected-meanq (/ (+ quality (* meanq total-repeats 1.0))
+ (1+ total-repeats))))
+ (should (< (abs (- new-meanq expected-meanq)) 0.0001)))) ; Floating point comparison
+
+;;; Boundary Cases - EF Modification
+
+(ert-deftest test-org-drill-determine-next-interval-sm2-boundary-ef-minimum-floor ()
+ "Test that EF floor of 1.3 is applied to input EF when it's below 1.3.
+If input EF < 1.3, org-drill-modify-e-factor returns 1.3 exactly."
+ (let* ((result (org-drill-determine-next-interval-sm2 10 3 1.0 4 0 nil 0))
+ (ef (test-sm2--extract-ef result)))
+ ;; Input EF was 1.0 < 1.3, so it should be raised to 1.3 first,
+ ;; then modified based on quality 4 (which increases EF)
+ (should (>= ef 1.3))))
+
+;;; Boundary Cases - Total Repeats
+
+(ert-deftest test-org-drill-determine-next-interval-sm2-boundary-total-repeats-increments ()
+ "Test that total-repeats is always incremented by 1."
+ (let* ((total-repeats 42)
+ (result (org-drill-determine-next-interval-sm2 10 3 2.5 4 0 3.5 total-repeats))
+ (new-total (test-sm2--extract-total-repeats result)))
+ (should (= new-total (1+ total-repeats)))))
+
+;;; Return Value Structure
+
+(ert-deftest test-org-drill-determine-next-interval-sm2-normal-return-value-structure ()
+ "Test that return value has correct structure.
+Should return 7-element list: (INTERVAL REPEATS EF FAILURES MEAN TOTAL-REPEATS OFMATRIX)"
+ (let ((result (org-drill-determine-next-interval-sm2 10 3 2.5 4 0 3.5 10)))
+ (should (listp result))
+ (should (= (length result) 7))
+ ;; Verify first 6 elements are numbers
+ (should (numberp (nth 0 result))) ; interval
+ (should (numberp (nth 1 result))) ; repeats
+ (should (numberp (nth 2 result))) ; ef
+ (should (numberp (nth 3 result))) ; failures
+ (should (numberp (nth 4 result))) ; meanq
+ (should (numberp (nth 5 result))) ; total-repeats
+ ;; 7th element (index 6) is OFMATRIX - can be nil or a matrix
+ ;; Just verify list has 7 elements (already checked above)
+ ))
+
+;;; Algorithm Verification
+
+(ert-deftest test-org-drill-determine-next-interval-sm2-algorithm-ef-increases-with-quality ()
+ "Test that higher quality results in higher EF (or maintains it).
+Quality 5 should result in EF >= initial EF."
+ (let* ((initial-ef 2.5)
+ (result (org-drill-determine-next-interval-sm2 10 3 initial-ef 5 0 nil 0))
+ (new-ef (test-sm2--extract-ef result)))
+ (should (>= new-ef initial-ef))))
+
+(ert-deftest test-org-drill-determine-next-interval-sm2-algorithm-ef-decreases-with-low-quality ()
+ "Test that low quality results in decreased EF.
+Quality 3 should result in EF < initial EF."
+ (let* ((initial-ef 2.5)
+ (result (org-drill-determine-next-interval-sm2 10 3 initial-ef 3 0 nil 0))
+ (new-ef (test-sm2--extract-ef result)))
+ (should (< new-ef initial-ef))))
+
+(ert-deftest test-org-drill-determine-next-interval-sm2-algorithm-interval-grows-exponentially ()
+ "Test that intervals grow approximately exponentially for consistent quality.
+Third review interval should be significantly larger than second."
+ (let ((org-drill-add-random-noise-to-intervals-p nil))
+ (let* ((ef 2.5)
+ (result-2nd (org-drill-determine-next-interval-sm2 1 2 ef 4 0 nil 0))
+ (interval-2nd (test-sm2--extract-interval result-2nd))
+ (ef-2nd (test-sm2--extract-ef result-2nd))
+ (result-3rd (org-drill-determine-next-interval-sm2 interval-2nd 3 ef-2nd 4 0 nil 1))
+ (interval-3rd (test-sm2--extract-interval result-3rd)))
+ (should (> interval-3rd (* interval-2nd 1.5)))))) ; Significant growth
+
+(provide 'test-org-drill-determine-next-interval-sm2)
+;;; test-org-drill-determine-next-interval-sm2.el ends here
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
diff --git a/tests/test-org-drill-part-of-drill-entry-p.el b/tests/test-org-drill-part-of-drill-entry-p.el
new file mode 100644
index 0000000..c9a09b8
--- /dev/null
+++ b/tests/test-org-drill-part-of-drill-entry-p.el
@@ -0,0 +1,231 @@
+;;; test-org-drill-part-of-drill-entry-p.el --- Tests for org-drill-part-of-drill-entry-p
+
+;;; Commentary:
+;; Unit tests for org-drill-part-of-drill-entry-p, which determines if point
+;; is at a drill entry heading OR within a subheading that inherits the drill tag.
+;;
+;; This function differs from org-drill-entry-p in that it checks BOTH:
+;; 1. Direct drill tag on current heading (via org-drill-entry-p)
+;; 2. Inherited drill tag from parent headings (via org-get-tags)
+
+;;; Code:
+
+(require 'ert)
+(require 'assess)
+(require 'org-drill)
+
+;;; Test Data
+
+(defconst test-org-drill-part-of-drill-entry-p-parent-drill
+ "* Parent heading :drill:
+
+Parent content.
+
+** Child heading
+
+Child content.
+
+*** Grandchild heading
+
+Grandchild content."
+ "Drill entry with nested children that inherit the tag.")
+
+(defconst test-org-drill-part-of-drill-entry-p-no-drill
+ "* Parent heading
+
+Parent content.
+
+** Child heading
+
+Child content."
+ "Headings without drill tag.")
+
+(defconst test-org-drill-part-of-drill-entry-p-child-has-drill
+ "* Parent heading
+
+Parent content.
+
+** Child heading :drill:
+
+Child content."
+ "Child has drill tag, parent doesn't.")
+
+(defconst test-org-drill-part-of-drill-entry-p-deep-nesting
+ "* Level 1 :drill:
+
+Content 1.
+
+** Level 2
+
+Content 2.
+
+*** Level 3
+
+Content 3.
+
+**** Level 4
+
+Content 4."
+ "Deeply nested structure with drill tag on top level.")
+
+;;; Helper Functions
+
+(defun test-org-drill-part-of-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-part-of-drill-entry-p-normal-at-parent-returns-true ()
+ "Test that function returns true when at parent heading with drill tag."
+ (test-org-drill-part-of-drill-entry-p--with-org-buffer
+ test-org-drill-part-of-drill-entry-p-parent-drill
+ (lambda ()
+ ;; Point at parent heading
+ (should (org-drill-part-of-drill-entry-p)))))
+
+(ert-deftest test-org-drill-part-of-drill-entry-p-normal-at-child-returns-true ()
+ "Test that function returns true when at child heading that inherits drill tag."
+ (test-org-drill-part-of-drill-entry-p--with-org-buffer
+ test-org-drill-part-of-drill-entry-p-parent-drill
+ (lambda ()
+ ;; Move to child heading
+ (re-search-forward "^\\*\\* Child heading")
+ (beginning-of-line)
+ (should (org-drill-part-of-drill-entry-p)))))
+
+(ert-deftest test-org-drill-part-of-drill-entry-p-normal-no-drill-returns-nil ()
+ "Test that function returns nil when no drill tag present or inherited."
+ (test-org-drill-part-of-drill-entry-p--with-org-buffer
+ test-org-drill-part-of-drill-entry-p-no-drill
+ (lambda ()
+ (should-not (org-drill-part-of-drill-entry-p)))))
+
+(ert-deftest test-org-drill-part-of-drill-entry-p-normal-child-not-parent-has-drill ()
+ "Test when child has drill tag but parent doesn't.
+Child heading itself should return true."
+ (test-org-drill-part-of-drill-entry-p--with-org-buffer
+ test-org-drill-part-of-drill-entry-p-child-has-drill
+ (lambda ()
+ ;; Move to child heading with drill tag
+ (re-search-forward "^\\*\\* Child heading")
+ (beginning-of-line)
+ (should (org-drill-part-of-drill-entry-p)))))
+
+(ert-deftest test-org-drill-part-of-drill-entry-p-normal-parent-no-drill-returns-nil ()
+ "Test that parent without drill tag returns nil."
+ (test-org-drill-part-of-drill-entry-p--with-org-buffer
+ test-org-drill-part-of-drill-entry-p-child-has-drill
+ (lambda ()
+ ;; At parent heading (no drill tag)
+ (should-not (org-drill-part-of-drill-entry-p)))))
+
+;;; Boundary Cases
+
+(ert-deftest test-org-drill-part-of-drill-entry-p-boundary-grandchild-inherits ()
+ "Test that grandchild heading inherits drill tag from grandparent."
+ (test-org-drill-part-of-drill-entry-p--with-org-buffer
+ test-org-drill-part-of-drill-entry-p-parent-drill
+ (lambda ()
+ ;; Move to grandchild heading
+ (re-search-forward "^\\*\\*\\* Grandchild heading")
+ (beginning-of-line)
+ (should (org-drill-part-of-drill-entry-p)))))
+
+(ert-deftest test-org-drill-part-of-drill-entry-p-boundary-deep-nesting-all-inherit ()
+ "Test that deeply nested headings all inherit drill tag.
+All levels 2, 3, and 4 should return true."
+ (test-org-drill-part-of-drill-entry-p--with-org-buffer
+ test-org-drill-part-of-drill-entry-p-deep-nesting
+ (lambda ()
+ ;; Test level 2
+ (re-search-forward "^\\*\\* Level 2")
+ (beginning-of-line)
+ (should (org-drill-part-of-drill-entry-p))
+
+ ;; Test level 3
+ (re-search-forward "^\\*\\*\\* Level 3")
+ (beginning-of-line)
+ (should (org-drill-part-of-drill-entry-p))
+
+ ;; Test level 4
+ (re-search-forward "^\\*\\*\\*\\* Level 4")
+ (beginning-of-line)
+ (should (org-drill-part-of-drill-entry-p)))))
+
+(ert-deftest test-org-drill-part-of-drill-entry-p-boundary-point-in-child-body ()
+ "Test behavior when point is in child body text.
+Should still detect inherited drill tag."
+ (test-org-drill-part-of-drill-entry-p--with-org-buffer
+ test-org-drill-part-of-drill-entry-p-parent-drill
+ (lambda ()
+ ;; Move to child body content
+ (re-search-forward "Child content")
+ (beginning-of-line)
+ (should (org-drill-part-of-drill-entry-p)))))
+
+(ert-deftest test-org-drill-part-of-drill-entry-p-boundary-empty-child-heading ()
+ "Test child heading with no content still inherits drill tag."
+ (test-org-drill-part-of-drill-entry-p--with-org-buffer
+ "* Parent :drill:\n** Child\n"
+ (lambda ()
+ (re-search-forward "^\\*\\* Child")
+ (beginning-of-line)
+ (should (org-drill-part-of-drill-entry-p)))))
+
+;;; Error Cases
+
+(ert-deftest test-org-drill-part-of-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-part-of-drill-entry-p))))
+
+(ert-deftest test-org-drill-part-of-drill-entry-p-error-no-headings ()
+ "Test behavior in buffer with only text, no headings."
+ (test-org-drill-part-of-drill-entry-p--with-org-buffer
+ "Just some text without any headings."
+ (lambda ()
+ (should-not (org-drill-part-of-drill-entry-p)))))
+
+(ert-deftest test-org-drill-part-of-drill-entry-p-error-point-before-first-heading ()
+ "Test behavior when point is before any headings."
+ (test-org-drill-part-of-drill-entry-p--with-org-buffer
+ "Some preamble text\n\n* Heading :drill:\n\nContent"
+ (lambda ()
+ ;; Point at preamble
+ (goto-char (point-min))
+ (should-not (org-drill-part-of-drill-entry-p)))))
+
+;;; Comparison Tests (org-drill-entry-p vs org-drill-part-of-drill-entry-p)
+
+(ert-deftest test-org-drill-part-of-drill-entry-p-comparison-child-differs ()
+ "Test that org-drill-entry-p and org-drill-part-of-drill-entry-p differ at child.
+At child heading: entry-p returns nil, part-of returns true."
+ (test-org-drill-part-of-drill-entry-p--with-org-buffer
+ test-org-drill-part-of-drill-entry-p-parent-drill
+ (lambda ()
+ ;; Move to child heading
+ (re-search-forward "^\\*\\* Child heading")
+ (beginning-of-line)
+ ;; org-drill-entry-p should be nil (no direct tag)
+ (should-not (org-drill-entry-p))
+ ;; org-drill-part-of-drill-entry-p should be true (inherited tag)
+ (should (org-drill-part-of-drill-entry-p)))))
+
+(ert-deftest test-org-drill-part-of-drill-entry-p-comparison-parent-same ()
+ "Test that both functions return true at parent heading with drill tag."
+ (test-org-drill-part-of-drill-entry-p--with-org-buffer
+ test-org-drill-part-of-drill-entry-p-parent-drill
+ (lambda ()
+ ;; At parent heading
+ (should (org-drill-entry-p))
+ (should (org-drill-part-of-drill-entry-p)))))
+
+(provide 'test-org-drill-part-of-drill-entry-p)
+;;; test-org-drill-part-of-drill-entry-p.el ends here
diff --git a/tests/org-drill-test.el b/tests/test-org-drill.el
index 4765a99..4765a99 100644
--- a/tests/org-drill-test.el
+++ b/tests/test-org-drill.el