test: add ERT tests for spine-books, fix cl-return-from issue
This commit is contained in:
@@ -85,39 +85,40 @@ Returns nil for empty or missing properties."
|
|||||||
(defun spine-books ()
|
(defun spine-books ()
|
||||||
"Return a list of plists, one per top-level headline in `spine-org-file'.
|
"Return a list of plists, one per top-level headline in `spine-org-file'.
|
||||||
Returns nil if the file is missing or cannot be parsed."
|
Returns nil if the file is missing or cannot be parsed."
|
||||||
(unless (file-exists-p spine-org-file)
|
(if (not (file-exists-p spine-org-file))
|
||||||
(message "spine-books: file not found: %s" spine-org-file)
|
(progn
|
||||||
(cl-return-from spine-books nil))
|
(message "spine-books: file not found: %s" spine-org-file)
|
||||||
(condition-case err
|
nil)
|
||||||
(with-temp-buffer
|
(condition-case err
|
||||||
(insert-file-contents spine-org-file)
|
(with-temp-buffer
|
||||||
(org-mode)
|
(insert-file-contents spine-org-file)
|
||||||
(let ((books nil))
|
(org-mode)
|
||||||
(org-element-map (org-element-parse-buffer 'headline) 'headline
|
(let ((books nil))
|
||||||
(lambda (hl)
|
(org-element-map (org-element-parse-buffer 'headline) 'headline
|
||||||
(when (= (org-element-property :level hl) 1)
|
(lambda (hl)
|
||||||
(let ((pos (org-element-property :begin hl)))
|
(when (= (org-element-property :level hl) 1)
|
||||||
(push (list :id (spine--prop pos "ID")
|
(let ((pos (org-element-property :begin hl)))
|
||||||
:title (org-element-property :title hl)
|
(push (list :id (spine--prop pos "ID")
|
||||||
:status (org-element-property :todo-keyword hl)
|
:title (org-element-property :title hl)
|
||||||
:author (spine--prop pos "AUTHOR")
|
:status (org-element-property :todo-keyword hl)
|
||||||
:isbn (spine--prop pos "ISBN")
|
:author (spine--prop pos "AUTHOR")
|
||||||
:cover (spine--prop pos "COVER")
|
:isbn (spine--prop pos "ISBN")
|
||||||
:format (spine--prop pos "FORMAT")
|
:cover (spine--prop pos "COVER")
|
||||||
:rec_by (spine--prop pos "REC_BY")
|
:format (spine--prop pos "FORMAT")
|
||||||
:rec_note (spine--prop pos "REC_NOTE")
|
:rec_by (spine--prop pos "REC_BY")
|
||||||
:rating (spine--prop pos "RATING")
|
:rec_note (spine--prop pos "REC_NOTE")
|
||||||
:added (spine--prop pos "ADDED")
|
:rating (spine--prop pos "RATING")
|
||||||
:tags (org-element-property :tags hl)
|
:added (spine--prop pos "ADDED")
|
||||||
:notes (spine--extract-notes
|
:tags (org-element-property :tags hl)
|
||||||
(org-element-property :begin hl)
|
:notes (spine--extract-notes
|
||||||
(org-element-property :end hl)))
|
(org-element-property :begin hl)
|
||||||
books)))))
|
(org-element-property :end hl)))
|
||||||
(nreverse books)))
|
books)))))
|
||||||
(error
|
(nreverse books)))
|
||||||
(message "spine-books: failed to parse %s: %s"
|
(error
|
||||||
spine-org-file (error-message-string err))
|
(message "spine-books: failed to parse %s: %s"
|
||||||
nil)))
|
spine-org-file (error-message-string err))
|
||||||
|
nil))))
|
||||||
|
|
||||||
(defvar spine-skip-server-start nil
|
(defvar spine-skip-server-start nil
|
||||||
"When non-nil, do not start the HTTP server.
|
"When non-nil, do not start the HTTP server.
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
;;; spine-books-test.el — ERT tests for spine-books
|
||||||
|
|
||||||
|
(require 'ert)
|
||||||
|
(require 'cl-lib)
|
||||||
|
|
||||||
|
;; Load spine.el without starting the server
|
||||||
|
(setq spine-skip-server-start t)
|
||||||
|
(setq spine-org-file (expand-file-name "sample-books.org"
|
||||||
|
(file-name-directory
|
||||||
|
(directory-file-name
|
||||||
|
(file-name-directory load-file-name)))))
|
||||||
|
(load-file (expand-file-name "../spine.el"
|
||||||
|
(file-name-directory load-file-name)))
|
||||||
|
|
||||||
|
(ert-deftest spine-books-parses-sample ()
|
||||||
|
"spine-books returns correct plists for sample-books.org."
|
||||||
|
(let ((books (spine-books)))
|
||||||
|
(should books)
|
||||||
|
(should (= (length books) 5))))
|
||||||
|
|
||||||
|
(ert-deftest spine-books-first-book-has-all-fields ()
|
||||||
|
"Use of Weapons entry has all expected fields."
|
||||||
|
(let* ((books (spine-books))
|
||||||
|
(uow (cl-find "8c1e-uow" books
|
||||||
|
:key (lambda (b) (plist-get b :id))
|
||||||
|
:test #'equal)))
|
||||||
|
(should uow)
|
||||||
|
(should (equal (plist-get uow :title) "Use of Weapons"))
|
||||||
|
(should (equal (plist-get uow :status) "READING"))
|
||||||
|
(should (equal (plist-get uow :author) "Iain M. Banks"))
|
||||||
|
(should (equal (plist-get uow :isbn) "978-0316029193"))
|
||||||
|
(should (equal (plist-get uow :cover) "covers/use-of-weapons.jpg"))
|
||||||
|
(should (equal (plist-get uow :format) "audiobook"))
|
||||||
|
(should (equal (plist-get uow :rec_by) "Priya"))
|
||||||
|
(should (equal (plist-get uow :rec_note) "If you liked Player of Games, this one will wreck you"))
|
||||||
|
(should (equal (plist-get uow :tags) '("scifi" "literary")))
|
||||||
|
(should (equal (plist-get uow :notes)
|
||||||
|
'(("2026-03-02" "The two-track structure is doing something I can't name yet.")
|
||||||
|
("2026-03-07" "Zakalwe's competence reads as a wound.")
|
||||||
|
("2026-03-09" "The chapter numbering. Oh."))))))
|
||||||
|
|
||||||
|
(ert-deftest spine-books-missing-properties-are-nil ()
|
||||||
|
"Piranesi entry has nil for non-present properties."
|
||||||
|
(let* ((books (spine-books))
|
||||||
|
(pir (cl-find "5e8d-pir" books
|
||||||
|
:key (lambda (b) (plist-get b :id))
|
||||||
|
:test #'equal)))
|
||||||
|
(should pir)
|
||||||
|
(should (equal (plist-get pir :title) "Piranesi"))
|
||||||
|
(should (equal (plist-get pir :status) "WANT"))
|
||||||
|
(should (equal (plist-get pir :author) "Susanna Clarke"))
|
||||||
|
(should-not (plist-get pir :isbn))
|
||||||
|
(should-not (plist-get pir :cover))
|
||||||
|
(should-not (plist-get pir :format))
|
||||||
|
(should-not (plist-get pir :rec_by))
|
||||||
|
(should-not (plist-get pir :rec_note))
|
||||||
|
(should-not (plist-get pir :notes))))
|
||||||
|
|
||||||
|
(ert-deftest spine-books-read-book-has-rating ()
|
||||||
|
"Ancillary Justice has rating 5."
|
||||||
|
(let* ((books (spine-books))
|
||||||
|
(aj (cl-find "3a1b-aj" books
|
||||||
|
:key (lambda (b) (plist-get b :id))
|
||||||
|
:test #'equal)))
|
||||||
|
(should aj)
|
||||||
|
(should (equal (plist-get aj :status) "READ"))
|
||||||
|
(should (equal (plist-get aj :rating) "5"))
|
||||||
|
(should (= (length (plist-get aj :notes)) 3))))
|
||||||
|
|
||||||
|
(ert-deftest spine-books-empty-file-returns-empty-list ()
|
||||||
|
"Empty Org file returns empty list, not nil."
|
||||||
|
(let* ((tmp-file (make-temp-file "spine-test-" nil ".org"))
|
||||||
|
(spine-org-file tmp-file))
|
||||||
|
(unwind-protect
|
||||||
|
(let ((books (spine-books)))
|
||||||
|
(should (listp books))
|
||||||
|
(should (= (length books) 0)))
|
||||||
|
(delete-file tmp-file))))
|
||||||
|
|
||||||
|
(ert-deftest spine-books-missing-file-returns-nil ()
|
||||||
|
"Non-existent file returns nil."
|
||||||
|
(let ((spine-org-file "/tmp/spine-nonexistent-12345.org"))
|
||||||
|
(should-not (spine-books))))
|
||||||
Reference in New Issue
Block a user