diff options
| author | Craig Jennings <c@cjennings.net> | 2025-11-13 11:45:30 -0600 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2025-11-13 11:45:30 -0600 |
| commit | 1618ff6b2cfe463ee225f11c2772712f8243c6d3 (patch) | |
| tree | 06b72938645c722e30064e5fe00c6001e547c23b /tests | |
| parent | cf182d001f66164232b8735bad43eb07121109c6 (diff) | |
| download | org-drill-1618ff6b2cfe463ee225f11c2772712f8243c6d3.tar.gz org-drill-1618ff6b2cfe463ee225f11c2772712f8243c6d3.zip | |
test: Add Phase 2 card type tests
- Add unit tests for simple card type (11 tests)
- Add unit tests for twosided card type (11 tests)
- Add unit tests for hide1cloze card type (4 tests)
Total: 91 tests (80 unit + 11 integration), all passing
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/test-card-type-hide1cloze.el | 47 | ||||
| -rw-r--r-- | tests/test-card-type-simple.el | 213 | ||||
| -rw-r--r-- | tests/test-card-type-twosided.el | 218 |
3 files changed, 478 insertions, 0 deletions
diff --git a/tests/test-card-type-hide1cloze.el b/tests/test-card-type-hide1cloze.el new file mode 100644 index 0000000..d203c4f --- /dev/null +++ b/tests/test-card-type-hide1cloze.el @@ -0,0 +1,47 @@ +;;; test-card-type-hide1cloze.el --- Tests for hide1cloze card type + +;;; Commentary: +;; Tests for the hide1cloze card type in org-drill. + +;;; Code: + +(require 'ert) +(require 'assess) +(require 'org-drill) + +;;; Normal Cases - Card Recognition + +(ert-deftest test-card-type-hide1cloze-normal-card-type-property () + "Test that hide1cloze cards have correct DRILL_CARD_TYPE property." + (with-temp-buffer + (org-mode) + (insert "* Basic Cloze Card :drill:\n:PROPERTIES:\n:DRILL_CARD_TYPE: hide1cloze\n:END:\n\nThe capital of France is Paris.\n") + (goto-char (point-min)) + (should (org-drill-entry-p)) + (should (equal "hide1cloze" (org-entry-get (point) "DRILL_CARD_TYPE"))))) + +(ert-deftest test-card-type-hide1cloze-normal-has-presentation-function () + "Test that hide1cloze card type has correct presentation function." + (let ((entry (assoc "hide1cloze" org-drill-card-type-alist))) + (should entry) + (should (eq (cadr entry) 'org-drill-present-multicloze-hide1)))) + +(ert-deftest test-card-type-hide1cloze-normal-multicloze-alias () + "Test that multicloze is an alias for hide1cloze." + (let ((hide1-entry (assoc "hide1cloze" org-drill-card-type-alist)) + (multi-entry (assoc "multicloze" org-drill-card-type-alist))) + (should hide1-entry) + (should multi-entry) + (should (eq (cadr hide1-entry) (cadr multi-entry))) + (should (eq (cadr multi-entry) 'org-drill-present-multicloze-hide1)))) + +(ert-deftest test-card-type-hide1cloze-normal-different-from-show1cloze () + "Test that hide1cloze and show1cloze use different functions." + (let ((hide1-fn (cadr (assoc "hide1cloze" org-drill-card-type-alist))) + (show1-fn (cadr (assoc "show1cloze" org-drill-card-type-alist)))) + (should-not (eq hide1-fn show1-fn)) + (should (eq hide1-fn 'org-drill-present-multicloze-hide1)) + (should (eq show1-fn 'org-drill-present-multicloze-show1)))) + +(provide 'test-card-type-hide1cloze) +;;; test-card-type-hide1cloze.el ends here diff --git a/tests/test-card-type-simple.el b/tests/test-card-type-simple.el new file mode 100644 index 0000000..5770883 --- /dev/null +++ b/tests/test-card-type-simple.el @@ -0,0 +1,213 @@ +;;; test-card-type-simple.el --- Tests for simple card type + +;;; Commentary: +;; Tests for the simple card type in org-drill. +;; +;; Simple cards are the default card type. They show the question +;; (entry body) and hide subheadings. The answer is revealed in +;; subheadings or can be specified in DRILL_ANSWER property. +;; +;; Card type: nil or "simple" +;; Presentation function: org-drill-present-simple-card + +;;; Code: + +(require 'ert) +(require 'assess) +(require 'org-drill) + +;;; Test Data + +(defconst test-card-type-simple-basic-card + "* Simple Card :drill: + +Question: What is the capital of France? + +** Answer + +Paris +" + "Basic simple card with question and answer in subheading.") + +(defconst test-card-type-simple-with-property + "* Simple Card with Property :drill: +:PROPERTIES: +:DRILL_CARD_TYPE: simple +:DRILL_ANSWER: The answer is 42 +:END: + +Question: What is the meaning of life? +" + "Simple card with DRILL_ANSWER property.") + +(defconst test-card-type-simple-multiple-subheadings + "* Card with Multiple Subheadings :drill: + +Main question content here. + +** First Answer + +First part of answer. + +** Second Answer + +Second part of answer. + +** Notes + +Additional notes that should be hidden. +" + "Simple card with multiple subheadings.") + +(defconst test-card-type-simple-no-answer + "* Card without Answer :drill: + +Just a question, no answer subheading. +" + "Simple card with no answer subheading.") + +;;; Helper Functions + +(defun test-card-type-simple--with-card (content callback) + "Execute CALLBACK in temp buffer with drill card CONTENT." + (with-temp-buffer + (org-mode) + (insert content) + (goto-char (point-min)) + (funcall callback))) + +(defun test-card-type-simple--card-has-type-p (card-type) + "Check if current entry has CARD-TYPE." + (let ((entry-type (org-entry-get (point) "DRILL_CARD_TYPE" t))) + (or (and (null card-type) (null entry-type)) + (equal card-type entry-type)))) + +;;; Normal Cases - Card Recognition + +(ert-deftest test-card-type-simple-normal-default-card-type () + "Test that cards without DRILL_CARD_TYPE are treated as simple cards." + (test-card-type-simple--with-card + test-card-type-simple-basic-card + (lambda () + (should (org-drill-entry-p)) + (should (null (org-entry-get (point) "DRILL_CARD_TYPE")))))) + +(ert-deftest test-card-type-simple-normal-explicit-simple-type () + "Test card with explicit 'simple' type in DRILL_CARD_TYPE property." + (test-card-type-simple--with-card + test-card-type-simple-with-property + (lambda () + (should (org-drill-entry-p)) + (should (equal "simple" (org-entry-get (point) "DRILL_CARD_TYPE")))))) + +(ert-deftest test-card-type-simple-normal-has-presentation-function () + "Test that simple card type has correct presentation function registered." + (let ((simple-entry (assoc "simple" org-drill-card-type-alist)) + (nil-entry (assoc nil org-drill-card-type-alist))) + ;; Both nil and "simple" should map to org-drill-present-simple-card + (should simple-entry) + (should nil-entry) + (should (eq (cadr simple-entry) 'org-drill-present-simple-card)) + (should (eq (cadr nil-entry) 'org-drill-present-simple-card)))) + +;;; Normal Cases - Card Structure + +(ert-deftest test-card-type-simple-normal-single-answer-subheading () + "Test simple card with single answer subheading." + (test-card-type-simple--with-card + test-card-type-simple-basic-card + (lambda () + (should (org-drill-entry-p)) + ;; Should have at least one subheading + (save-excursion + (org-back-to-heading) + (let ((has-subheading nil)) + (org-map-entries + (lambda () (setq has-subheading t)) + nil 'tree) + (should has-subheading)))))) + +(ert-deftest test-card-type-simple-normal-multiple-answer-subheadings () + "Test simple card with multiple subheadings." + (test-card-type-simple--with-card + test-card-type-simple-multiple-subheadings + (lambda () + (should (org-drill-entry-p)) + ;; Count subheadings + (save-excursion + (org-back-to-heading) + (let ((subheading-count 0)) + (org-map-entries + (lambda () + (when (> (org-current-level) 1) + (cl-incf subheading-count))) + nil 'tree) + (should (>= subheading-count 3))))))) + +;;; Normal Cases - DRILL_ANSWER Property + +(ert-deftest test-card-type-simple-normal-drill-answer-property () + "Test simple card with DRILL_ANSWER property." + (test-card-type-simple--with-card + test-card-type-simple-with-property + (lambda () + (should (org-drill-entry-p)) + (let ((answer (org-entry-get (point) "DRILL_ANSWER"))) + (should answer) + (should (string-match-p "42" answer)))))) + +;;; Boundary Cases + +(ert-deftest test-card-type-simple-boundary-no-answer-subheading () + "Test simple card without answer subheading. +Card should still be valid, answer would come from DRILL_ANSWER property." + (test-card-type-simple--with-card + test-card-type-simple-no-answer + (lambda () + (should (org-drill-entry-p)) + ;; No subheadings + (save-excursion + (org-back-to-heading) + (let ((has-subheading nil)) + (org-map-entries + (lambda () + (when (> (org-current-level) 1) + (setq has-subheading t))) + nil 'tree) + (should-not has-subheading)))))) + +(ert-deftest test-card-type-simple-boundary-empty-question () + "Test simple card with empty question body." + (let ((content "* Empty Question :drill:\n\n** Answer\n\nSome answer\n")) + (test-card-type-simple--with-card + content + (lambda () + (should (org-drill-entry-p)))))) + +(ert-deftest test-card-type-simple-boundary-very-long-question () + "Test simple card with very long question text." + (let* ((long-text (make-string 5000 ?x)) + (content (format "* Long Question :drill:\n\n%s\n\n** Answer\n\nYes\n" long-text))) + (test-card-type-simple--with-card + content + (lambda () + (should (org-drill-entry-p)))))) + +;;; Card Type Lookup + +(ert-deftest test-card-type-simple-normal-card-type-lookup () + "Test that card type lookup works for simple cards." + (let ((presentation-fn (cadr (assoc nil org-drill-card-type-alist)))) + (should (eq presentation-fn 'org-drill-present-simple-card))) + (let ((presentation-fn (cadr (assoc "simple" org-drill-card-type-alist)))) + (should (eq presentation-fn 'org-drill-present-simple-card)))) + +(ert-deftest test-card-type-simple-normal-default-vs-explicit () + "Test that default (nil) and explicit 'simple' type behave identically." + (let ((default-fn (cadr (assoc nil org-drill-card-type-alist))) + (explicit-fn (cadr (assoc "simple" org-drill-card-type-alist)))) + (should (eq default-fn explicit-fn)) + (should (eq default-fn 'org-drill-present-simple-card)))) + +(provide 'test-card-type-simple) +;;; test-card-type-simple.el ends here diff --git a/tests/test-card-type-twosided.el b/tests/test-card-type-twosided.el new file mode 100644 index 0000000..cda508f --- /dev/null +++ b/tests/test-card-type-twosided.el @@ -0,0 +1,218 @@ +;;; test-card-type-twosided.el --- Tests for two-sided card type + +;;; Commentary: +;; Tests for the two-sided card type in org-drill. +;; +;; Two-sided cards have two subheadings representing two "sides" of a card. +;; When presented, one of the first two subheadings is randomly chosen +;; and shown as the question, while the other serves as the answer. +;; +;; Card type: "twosided" +;; Presentation function: org-drill-present-two-sided-card + +;;; Code: + +(require 'ert) +(require 'assess) +(require 'org-drill) + +;;; Test Data + +(defconst test-card-type-twosided-basic-card + "* Two-Sided Card :drill: +:PROPERTIES: +:DRILL_CARD_TYPE: twosided +:END: + +** Side 1 + +English: Apple + +** Side 2 + +Spanish: Manzana +" + "Basic two-sided card for vocabulary.") + +(defconst test-card-type-twosided-with-extra-sides + "* Card with Extra Sides :drill: +:PROPERTIES: +:DRILL_CARD_TYPE: twosided +:END: + +** Side A + +First side content. + +** Side B + +Second side content. + +** Side C + +Third side (should not be shown in two-sided mode). + +** Side D + +Fourth side (should not be shown in two-sided mode). +" + "Two-sided card with more than 2 subheadings.") + +(defconst test-card-type-twosided-single-side + "* Card with Single Side :drill: +:PROPERTIES: +:DRILL_CARD_TYPE: twosided +:END: + +** Only Side + +Only one subheading present. +" + "Two-sided card with only one subheading.") + +(defconst test-card-type-twosided-empty-sides + "* Card with Empty Sides :drill: +:PROPERTIES: +:DRILL_CARD_TYPE: twosided +:END: + +** Side 1 + +** Side 2 + +" + "Two-sided card with empty side content.") + +;;; Helper Functions + +(defun test-card-type-twosided--with-card (content callback) + "Execute CALLBACK in temp buffer with drill card CONTENT." + (with-temp-buffer + (org-mode) + (insert content) + (goto-char (point-min)) + (funcall callback))) + +(defun test-card-type-twosided--count-subheadings () + "Count number of level-2 subheadings under current entry." + (save-excursion + (org-back-to-heading) + (let ((count 0) + (end (save-excursion (org-end-of-subtree t t)))) + (while (and (re-search-forward "^\\*\\* " end t)) + (cl-incf count)) + count))) + +;;; Normal Cases - Card Recognition + +(ert-deftest test-card-type-twosided-normal-card-type-property () + "Test that two-sided cards have correct DRILL_CARD_TYPE property." + (test-card-type-twosided--with-card + test-card-type-twosided-basic-card + (lambda () + (should (org-drill-entry-p)) + (should (equal "twosided" (org-entry-get (point) "DRILL_CARD_TYPE")))))) + +(ert-deftest test-card-type-twosided-normal-has-presentation-function () + "Test that twosided card type has correct presentation function registered." + (let ((entry (assoc "twosided" org-drill-card-type-alist))) + (should entry) + (should (eq (cadr entry) 'org-drill-present-two-sided-card)))) + +(ert-deftest test-card-type-twosided-normal-drill-empty-p-flag () + "Test that twosided card type has drill-empty-p flag set. +This allows two-sided cards to be presented even if main body is empty." + (let ((entry (assoc "twosided" org-drill-card-type-alist))) + (should entry) + ;; Fourth element is drill-empty-p flag + (should (nth 3 entry)))) + +;;; Normal Cases - Card Structure + +(ert-deftest test-card-type-twosided-normal-two-subheadings () + "Test two-sided card with exactly two subheadings." + (test-card-type-twosided--with-card + test-card-type-twosided-basic-card + (lambda () + (should (org-drill-entry-p)) + (should (= 2 (test-card-type-twosided--count-subheadings)))))) + +(ert-deftest test-card-type-twosided-normal-more-than-two-subheadings () + "Test two-sided card with more than two subheadings. +Only first two should be used for presentation." + (test-card-type-twosided--with-card + test-card-type-twosided-with-extra-sides + (lambda () + (should (org-drill-entry-p)) + (should (> (test-card-type-twosided--count-subheadings) 2))))) + +;;; Boundary Cases + +(ert-deftest test-card-type-twosided-boundary-single-subheading () + "Test two-sided card with only one subheading. +Should still be a valid card, though not ideal." + (test-card-type-twosided--with-card + test-card-type-twosided-single-side + (lambda () + (should (org-drill-entry-p)) + (should (= 1 (test-card-type-twosided--count-subheadings)))))) + +(ert-deftest test-card-type-twosided-boundary-empty-side-content () + "Test two-sided card where sides have no content." + (test-card-type-twosided--with-card + test-card-type-twosided-empty-sides + (lambda () + (should (org-drill-entry-p)) + (should (= 2 (test-card-type-twosided--count-subheadings)))))) + +(ert-deftest test-card-type-twosided-boundary-no-main-body () + "Test two-sided card with no main body content. +This is valid because twosided has drill-empty-p flag." + (let ((content "* No Body :drill:\n:PROPERTIES:\n:DRILL_CARD_TYPE: twosided\n:END:\n\n** A\n\nContent A\n\n** B\n\nContent B\n")) + (test-card-type-twosided--with-card + content + (lambda () + (should (org-drill-entry-p)) + (should (equal "twosided" (org-entry-get (point) "DRILL_CARD_TYPE"))))))) + +;;; Card Type Semantics + +(ert-deftest test-card-type-twosided-normal-vocabulary-use-case () + "Test typical vocabulary card use case. +Two sides for word translation pairs." + (test-card-type-twosided--with-card + test-card-type-twosided-basic-card + (lambda () + (should (org-drill-entry-p)) + ;; Verify both sides exist + (let ((sides nil)) + (save-excursion + (org-back-to-heading) + (while (re-search-forward "^\\*\\* " nil t) + (let ((heading-text (buffer-substring + (point) + (line-end-position)))) + (push heading-text sides)))) + (should (= 2 (length sides))) + (should (member "Side 1" sides)) + (should (member "Side 2" sides)))))) + +(ert-deftest test-card-type-twosided-normal-concept-definition-use-case () + "Test concept/definition card use case." + (let ((content "* Concept Card :drill:\n:PROPERTIES:\n:DRILL_CARD_TYPE: twosided\n:END:\n\n** Concept\n\nPolymorphism\n\n** Definition\n\nAbility of different objects to respond to same message in different ways.\n")) + (test-card-type-twosided--with-card + content + (lambda () + (should (org-drill-entry-p)) + (should (= 2 (test-card-type-twosided--count-subheadings))))))) + +(ert-deftest test-card-type-twosided-normal-different-from-simple () + "Test that twosided is registered differently from simple." + (let ((twosided-fn (cadr (assoc "twosided" org-drill-card-type-alist))) + (simple-fn (cadr (assoc "simple" org-drill-card-type-alist)))) + (should-not (eq twosided-fn simple-fn)) + (should (eq twosided-fn 'org-drill-present-two-sided-card)) + (should (eq simple-fn 'org-drill-present-simple-card)))) + +(provide 'test-card-type-twosided) +;;; test-card-type-twosided.el ends here |
