diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/test-org-noter-config--generate-notes-template.el | 62 | ||||
| -rw-r--r-- | tests/test-org-noter-config--predicates.el | 125 | ||||
| -rw-r--r-- | tests/test-org-noter-config--preferred-split.el | 52 | ||||
| -rw-r--r-- | tests/test-org-noter-config--title-to-slug.el | 50 |
4 files changed, 289 insertions, 0 deletions
diff --git a/tests/test-org-noter-config--generate-notes-template.el b/tests/test-org-noter-config--generate-notes-template.el new file mode 100644 index 00000000..c4638fa7 --- /dev/null +++ b/tests/test-org-noter-config--generate-notes-template.el @@ -0,0 +1,62 @@ +;;; test-org-noter-config--generate-notes-template.el --- Tests for cj/org-noter--generate-notes-template -*- lexical-binding: t; -*- + +;;; Commentary: +;; Tests for `cj/org-noter--generate-notes-template'. The function +;; produces an org-roam-shaped buffer template with a generated UUID, +;; ROAM_REFS / NOTER_DOCUMENT pointing at the document path, and the +;; title in #+title and #+CATEGORY. `org-id-uuid' is mocked at the +;; boundary so the test is deterministic. + +;;; Code: + +(require 'ert) +(require 'cl-lib) + +(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory)) +(require 'user-constants) +(require 'keybindings) +(require 'org-noter-config) + +(defmacro test-org-noter-config--with-uuid (uuid &rest body) + "Run BODY with `org-id-uuid' returning UUID." + (declare (indent 1) (debug t)) + `(cl-letf (((symbol-function 'org-id-uuid) (lambda () ,uuid))) + ,@body)) + +(ert-deftest test-org-noter-config-generate-template-includes-id-property () + "Normal: template includes the supplied UUID in the :ID: property." + (test-org-noter-config--with-uuid "deadbeef-1234" + (let ((text (cj/org-noter--generate-notes-template + "The Pragmatic Programmer" "/books/pragmatic.pdf"))) + (should (string-match-p ":ID: deadbeef-1234" text))))) + +(ert-deftest test-org-noter-config-generate-template-roam-refs-and-noter-document () + "Normal: ROAM_REFS and NOTER_DOCUMENT both point at the document path." + (test-org-noter-config--with-uuid "x" + (let ((text (cj/org-noter--generate-notes-template + "Title" "/books/file.pdf"))) + (should (string-match-p ":ROAM_REFS: /books/file\\.pdf" text)) + (should (string-match-p ":NOTER_DOCUMENT: /books/file\\.pdf" text))))) + +(ert-deftest test-org-noter-config-generate-template-title-and-category () + "Normal: #+title shows the title with prefix; #+CATEGORY uses the title." + (test-org-noter-config--with-uuid "x" + (let ((text (cj/org-noter--generate-notes-template + "Anaphora Studies" "/x"))) + (should (string-match-p "^#\\+title: Notes on Anaphora Studies$" text)) + (should (string-match-p "^#\\+CATEGORY: Anaphora Studies$" text))))) + +(ert-deftest test-org-noter-config-generate-template-includes-readingnotes-tag () + "Boundary: the FILETAGS line carries the :ReadingNotes: tag." + (test-org-noter-config--with-uuid "x" + (let ((text (cj/org-noter--generate-notes-template "T" "/x"))) + (should (string-match-p "^#\\+FILETAGS: :ReadingNotes:$" text))))) + +(ert-deftest test-org-noter-config-generate-template-ends-with-notes-heading () + "Boundary: the template ends with a top-level Notes heading." + (test-org-noter-config--with-uuid "x" + (let ((text (cj/org-noter--generate-notes-template "T" "/x"))) + (should (string-match-p "\\* Notes\n\\'" text))))) + +(provide 'test-org-noter-config--generate-notes-template) +;;; test-org-noter-config--generate-notes-template.el ends here diff --git a/tests/test-org-noter-config--predicates.el b/tests/test-org-noter-config--predicates.el new file mode 100644 index 00000000..09fbe3e8 --- /dev/null +++ b/tests/test-org-noter-config--predicates.el @@ -0,0 +1,125 @@ +;;; test-org-noter-config--predicates.el --- Tests for the org-noter-config predicates -*- lexical-binding: t; -*- + +;;; Commentary: +;; Tests for the predicate helpers in org-noter-config.el: +;; cj/org-noter--in-document-p, cj/org-noter--in-notes-file-p, +;; cj/org-noter--session-active-p, and cj/org-noter--get-document-path +;; (mode-dispatch helper). +;; +;; Mocks are at the boundary: derived-mode-p for mode dispatch, +;; org-entry-get for the NOTER_DOCUMENT lookup. The tests don't load +;; pdf-view or nov; they only need the symbols recognised by +;; derived-mode-p. + +;;; Code: + +(require 'ert) +(require 'cl-lib) + +(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory)) +(require 'user-constants) +(require 'keybindings) +(require 'org-noter-config) + +;; Forward-declare and initialise so cl-letf on symbol-value works. +(defvar org-noter--session nil) +(defvar nov-file-name nil) + +(defmacro test-org-noter-config--with-mode (mode &rest body) + "Run BODY with `derived-mode-p' returning MODE for any matching arg. +MODE may be a symbol or nil; nil means \"not derived from anything we ask\"." + (declare (indent 1) (debug t)) + `(cl-letf (((symbol-function 'derived-mode-p) + (lambda (&rest modes) (and ,mode (memq ,mode modes))))) + ,@body)) + +;;; cj/org-noter--in-document-p + +(ert-deftest test-org-noter-config-in-document-p-true-in-pdf-view () + "Normal: pdf-view-mode buffer counts as a document." + (test-org-noter-config--with-mode 'pdf-view-mode + (should (cj/org-noter--in-document-p)))) + +(ert-deftest test-org-noter-config-in-document-p-true-in-nov () + "Normal: nov-mode buffer counts as a document." + (test-org-noter-config--with-mode 'nov-mode + (should (cj/org-noter--in-document-p)))) + +(ert-deftest test-org-noter-config-in-document-p-false-in-org () + "Boundary: org-mode buffer is not a document." + (test-org-noter-config--with-mode 'org-mode + (should-not (cj/org-noter--in-document-p)))) + +(ert-deftest test-org-noter-config-in-document-p-false-in-fundamental () + "Boundary: a fundamental-mode buffer is not a document." + (test-org-noter-config--with-mode nil + (should-not (cj/org-noter--in-document-p)))) + +;;; cj/org-noter--in-notes-file-p + +(ert-deftest test-org-noter-config-in-notes-file-p-true-when-noter-document-set () + "Normal: org-mode + NOTER_DOCUMENT property → notes file." + (test-org-noter-config--with-mode 'org-mode + (cl-letf (((symbol-function 'org-entry-get) + (lambda (_pos prop) + (when (equal prop "NOTER_DOCUMENT") "/some/doc.pdf")))) + (should (cj/org-noter--in-notes-file-p))))) + +(ert-deftest test-org-noter-config-in-notes-file-p-false-when-no-property () + "Boundary: org-mode without NOTER_DOCUMENT property → not a notes file." + (test-org-noter-config--with-mode 'org-mode + (cl-letf (((symbol-function 'org-entry-get) (lambda (&rest _) nil))) + (should-not (cj/org-noter--in-notes-file-p))))) + +(ert-deftest test-org-noter-config-in-notes-file-p-false-outside-org () + "Boundary: non-org buffers are never notes files even with the property." + (test-org-noter-config--with-mode 'pdf-view-mode + (cl-letf (((symbol-function 'org-entry-get) + (lambda (_pos prop) + (when (equal prop "NOTER_DOCUMENT") "/some/doc.pdf")))) + (should-not (cj/org-noter--in-notes-file-p))))) + +;;; cj/org-noter--session-active-p + +(ert-deftest test-org-noter-config-session-active-p-true-when-session-set () + "Normal: session-active when org-noter--session is non-nil." + (cl-letf (((symbol-value 'org-noter--session) 'fake-session)) + (should (cj/org-noter--session-active-p)))) + +(ert-deftest test-org-noter-config-session-active-p-false-when-nil () + "Boundary: session-active is nil when org-noter--session is nil." + (cl-letf (((symbol-value 'org-noter--session) nil)) + (should-not (cj/org-noter--session-active-p)))) + +;;; cj/org-noter--get-document-path + +(ert-deftest test-org-noter-config-get-document-path-pdf-uses-buffer-file-name () + "Normal: PDF mode returns `buffer-file-name'." + (test-org-noter-config--with-mode 'pdf-view-mode + (cl-letf (((symbol-function 'buffer-file-name) + (lambda (&optional _) "/books/file.pdf"))) + (should (equal "/books/file.pdf" (cj/org-noter--get-document-path)))))) + +(ert-deftest test-org-noter-config-get-document-path-nov-uses-nov-file-name () + "Normal: nov-mode returns `nov-file-name'." + (test-org-noter-config--with-mode 'nov-mode + (cl-letf (((symbol-value 'nov-file-name) "/books/book.epub")) + (should (equal "/books/book.epub" (cj/org-noter--get-document-path)))))) + +(ert-deftest test-org-noter-config-get-document-path-other-mode-returns-nil () + "Boundary: a non-document mode returns nil." + (test-org-noter-config--with-mode 'org-mode + (should-not (cj/org-noter--get-document-path)))) + +;;; cj/org-noter--extract-document-title + +(ert-deftest test-org-noter-config-extract-document-title-strips-extension () + "Normal: extract-document-title returns the basename without extension." + (test-org-noter-config--with-mode 'pdf-view-mode + (cl-letf (((symbol-function 'buffer-file-name) + (lambda (&optional _) "/books/the-pragmatic-programmer.pdf"))) + (should (equal "the-pragmatic-programmer" + (cj/org-noter--extract-document-title)))))) + +(provide 'test-org-noter-config--predicates) +;;; test-org-noter-config--predicates.el ends here diff --git a/tests/test-org-noter-config--preferred-split.el b/tests/test-org-noter-config--preferred-split.el new file mode 100644 index 00000000..c99d63f4 --- /dev/null +++ b/tests/test-org-noter-config--preferred-split.el @@ -0,0 +1,52 @@ +;;; test-org-noter-config--preferred-split.el --- Tests for cj/org-noter--preferred-split -*- lexical-binding: t; -*- + +;;; Commentary: +;; Tests for `cj/org-noter--preferred-split'. The function returns +;; `horizontal-split' when the frame's width-to-height ratio exceeds +;; 1.4, otherwise `vertical-split'. Tests mock the frame-pixel-* +;; primitives to walk the threshold from both sides. + +;;; Code: + +(require 'ert) +(require 'cl-lib) + +(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory)) +(require 'user-constants) +(require 'keybindings) +(require 'org-noter-config) + +(defmacro test-org-noter-config--with-frame-size (width height &rest body) + "Run BODY with `frame-pixel-width' / `frame-pixel-height' mocked to WIDTH and HEIGHT." + (declare (indent 2) (debug t)) + `(cl-letf (((symbol-function 'frame-pixel-width) (lambda (&optional _) ,width)) + ((symbol-function 'frame-pixel-height) (lambda (&optional _) ,height))) + ,@body)) + +(ert-deftest test-org-noter-config-preferred-split-wide-returns-horizontal () + "Normal: a 16:9 wide frame returns horizontal-split (side-by-side)." + (test-org-noter-config--with-frame-size 1920 1080 + (should (eq 'horizontal-split (cj/org-noter--preferred-split))))) + +(ert-deftest test-org-noter-config-preferred-split-tall-returns-vertical () + "Normal: a tall portrait frame returns vertical-split (stacked)." + (test-org-noter-config--with-frame-size 800 1200 + (should (eq 'vertical-split (cj/org-noter--preferred-split))))) + +(ert-deftest test-org-noter-config-preferred-split-square-returns-vertical () + "Boundary: a square frame is below the 1.4 threshold; returns vertical." + (test-org-noter-config--with-frame-size 1000 1000 + (should (eq 'vertical-split (cj/org-noter--preferred-split))))) + +(ert-deftest test-org-noter-config-preferred-split-just-above-threshold-horizontal () + "Boundary: a width-to-height ratio of 1.5 returns horizontal." + (test-org-noter-config--with-frame-size 1500 1000 + (should (eq 'horizontal-split (cj/org-noter--preferred-split))))) + +(ert-deftest test-org-noter-config-preferred-split-just-below-threshold-vertical () + "Boundary: a width-to-height ratio of 1.3 returns vertical." + (test-org-noter-config--with-frame-size 1300 1000 + (should (eq 'vertical-split (cj/org-noter--preferred-split))))) + +(provide 'test-org-noter-config--preferred-split) +;;; test-org-noter-config--preferred-split.el ends here diff --git a/tests/test-org-noter-config--title-to-slug.el b/tests/test-org-noter-config--title-to-slug.el new file mode 100644 index 00000000..3122086d --- /dev/null +++ b/tests/test-org-noter-config--title-to-slug.el @@ -0,0 +1,50 @@ +;;; test-org-noter-config--title-to-slug.el --- Tests for cj/org-noter--title-to-slug -*- lexical-binding: t; -*- + +;;; Commentary: +;; Tests for `cj/org-noter--title-to-slug'. The function lowercases its +;; input, replaces every run of non-alphanumeric characters with a +;; single hyphen, and trims leading/trailing hyphens. It's used to +;; turn a book title into a filename-safe slug. + +;;; Code: + +(require 'ert) + +(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory)) +(require 'user-constants) +(require 'keybindings) +(require 'org-noter-config) + +(ert-deftest test-org-noter-config-title-to-slug-multi-word () + "Normal: a multi-word title becomes hyphen-separated lowercase." + (should (equal "the-pragmatic-programmer" + (cj/org-noter--title-to-slug "The Pragmatic Programmer")))) + +(ert-deftest test-org-noter-config-title-to-slug-single-word () + "Normal: a single-word lowercase title is unchanged." + (should (equal "anaphora" (cj/org-noter--title-to-slug "anaphora")))) + +(ert-deftest test-org-noter-config-title-to-slug-mixed-punctuation () + "Boundary: punctuation is collapsed into single hyphens." + (should (equal "godel-escher-bach" + (cj/org-noter--title-to-slug "Godel, Escher, Bach!")))) + +(ert-deftest test-org-noter-config-title-to-slug-leading-trailing-non-alnum () + "Boundary: leading and trailing non-alnum runs are trimmed." + (should (equal "title" + (cj/org-noter--title-to-slug " ...title!?? ")))) + +(ert-deftest test-org-noter-config-title-to-slug-collapses-multiple-non-alnum () + "Boundary: a run of non-alnum chars in the middle becomes one hyphen." + (should (equal "a-b" (cj/org-noter--title-to-slug "a --- b")))) + +(ert-deftest test-org-noter-config-title-to-slug-numbers-preserved () + "Boundary: digits are preserved as-is." + (should (equal "1984" (cj/org-noter--title-to-slug "1984")))) + +(ert-deftest test-org-noter-config-title-to-slug-empty-string () + "Error: empty input yields empty string." + (should (equal "" (cj/org-noter--title-to-slug "")))) + +(provide 'test-org-noter-config--title-to-slug) +;;; test-org-noter-config--title-to-slug.el ends here |
