bbd9a455cd
- Add spine-move-book: move book between shelves by cutting/pasting headline - Add spine-set-status: change TODO keyword (WANT/READING/READ/none) - Add action=shelf and action=status cases to httpd/edit POST handler - Wrap shelf/status selects in forms with onchange auto-submit to /edit - Wire note composer as POST form to /edit with action=note - Redirect all edit POSTs back to /book?id=X - 7 new tests for move-book and set-status (error handling, property preservation)
190 lines
7.3 KiB
EmacsLisp
190 lines
7.3 KiB
EmacsLisp
;;; spine-edit-test.el — ERT tests for spine-edit functions
|
|
|
|
(require 'ert)
|
|
(require 'cl-lib)
|
|
|
|
(setq spine-skip-server-start t)
|
|
(setq spine-org-file (expand-file-name "test-edit-temp.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)))
|
|
|
|
(defun spine-edit-test--setup ()
|
|
"Create a test Org file with one shelf and one book."
|
|
(with-temp-file spine-org-file
|
|
(insert "* Fiction\n** WANT Edit Test Book\n:PROPERTIES:\n:AUTHOR: Test Author\n:ID: test-0001\n:END:\n"))
|
|
t)
|
|
|
|
(defun spine-edit-test--cleanup ()
|
|
"Remove the test Org file."
|
|
(ignore-errors (delete-file spine-org-file)))
|
|
|
|
(ert-deftest spine-add-note-appends ()
|
|
"spine-add-note appends a note with date and text."
|
|
(spine-edit-test--cleanup)
|
|
(unwind-protect
|
|
(progn
|
|
(spine-edit-test--setup)
|
|
(let* ((books (spine-books))
|
|
(book (car books))
|
|
(id (plist-get book :id)))
|
|
(spine-add-note id "Great book!" "2026-06-21")
|
|
(let ((updated (cl-find id (spine-books) :key (lambda (b) (plist-get b :id)) :test #'equal)))
|
|
(should updated)
|
|
(let ((notes (plist-get updated :notes)))
|
|
(should notes)
|
|
(should (equal (caar notes) "2026-06-21"))
|
|
(should (equal (cadar notes) "Great book!"))))))
|
|
(spine-edit-test--cleanup)))
|
|
|
|
(ert-deftest spine-add-note-default-date ()
|
|
"spine-add-note uses today's date when none provided."
|
|
(spine-edit-test--cleanup)
|
|
(unwind-protect
|
|
(progn
|
|
(spine-edit-test--setup)
|
|
(let* ((books (spine-books))
|
|
(book (car books))
|
|
(id (plist-get book :id))
|
|
(today (format-time-string "%Y-%m-%d")))
|
|
(spine-add-note id "Note without date")
|
|
(let ((updated (cl-find id (spine-books) :key (lambda (b) (plist-get b :id)) :test #'equal)))
|
|
(should updated)
|
|
(let ((notes (plist-get updated :notes)))
|
|
(should notes)
|
|
(should (equal (caar notes) today))
|
|
(should (equal (cadar notes) "Note without date"))))))
|
|
(spine-edit-test--cleanup)))
|
|
|
|
(ert-deftest spine-set-rating-sets-rating ()
|
|
"spine-set-rating sets the RATING property."
|
|
(spine-edit-test--cleanup)
|
|
(unwind-protect
|
|
(progn
|
|
(spine-edit-test--setup)
|
|
(let* ((books (spine-books))
|
|
(book (car books))
|
|
(id (plist-get book :id)))
|
|
(spine-set-rating id "4")
|
|
(let ((updated (cl-find id (spine-books) :key (lambda (b) (plist-get b :id)) :test #'equal)))
|
|
(should updated)
|
|
(should (equal (plist-get updated :rating) "4")))))
|
|
(spine-edit-test--cleanup)))
|
|
|
|
(ert-deftest spine-edit-model-actions-include-note-and-rating ()
|
|
"Selected book shows Add note and Set rating actions."
|
|
(spine-edit-test--cleanup)
|
|
(unwind-protect
|
|
(progn
|
|
(spine-edit-test--setup)
|
|
(let* ((books (spine-books))
|
|
(book (car books))
|
|
(id (plist-get book :id))
|
|
(model (spine-index-model books nil id))
|
|
(minibuffer (ht-get model "minibuffer")))
|
|
(should minibuffer)
|
|
(let ((actions (ht-get minibuffer "actions")))
|
|
(should (= (length actions) 2))
|
|
(should (equal (ht-get (nth 0 actions) "label") "Add note"))
|
|
(should (equal (ht-get (nth 1 actions) "label") "Set rating")))))
|
|
(spine-edit-test--cleanup)))
|
|
|
|
(ert-deftest spine-edit-model-no-actions-when-no-selection ()
|
|
"No minibuffer actions when no book is selected."
|
|
(spine-edit-test--cleanup)
|
|
(unwind-protect
|
|
(progn
|
|
(spine-edit-test--setup)
|
|
(let* ((books (spine-books))
|
|
(model (spine-index-model books nil nil)))
|
|
(should-not (ht-get model "minibuffer"))))
|
|
(spine-edit-test--cleanup)))
|
|
|
|
(defun spine-edit-test--two-shelf-setup ()
|
|
"Create a test Org file with two shelves and a book on the first."
|
|
(with-temp-file spine-org-file
|
|
(insert "* Fiction\n** WANT Edit Test Book\n:PROPERTIES:\n:AUTHOR: Test Author\n:ID: test-0001\n:END:\n* Science Fiction\n"))
|
|
t)
|
|
|
|
(ert-deftest spine-move-book-moves-to-target-shelf ()
|
|
"spine-move-book moves the book to the target shelf."
|
|
(spine-edit-test--cleanup)
|
|
(unwind-protect
|
|
(progn
|
|
(spine-edit-test--two-shelf-setup)
|
|
(spine-move-book "test-0001" "Science Fiction")
|
|
(let* ((books (spine-books))
|
|
(book (cl-find "test-0001" books :key (lambda (b) (plist-get b :id)) :test #'equal)))
|
|
(should book)
|
|
(should (equal (plist-get book :shelf) "Science Fiction"))))
|
|
(spine-edit-test--cleanup)))
|
|
|
|
(ert-deftest spine-move-book-keeps-properties ()
|
|
"spine-move-book preserves book properties after move."
|
|
(spine-edit-test--cleanup)
|
|
(unwind-protect
|
|
(progn
|
|
(spine-edit-test--two-shelf-setup)
|
|
(spine-move-book "test-0001" "Science Fiction")
|
|
(let* ((books (spine-books))
|
|
(book (cl-find "test-0001" books :key (lambda (b) (plist-get b :id)) :test #'equal)))
|
|
(should book)
|
|
(should (equal (plist-get book :title) "WANT Edit Test Book"))
|
|
(should (equal (plist-get book :author) "Test Author"))))
|
|
(spine-edit-test--cleanup)))
|
|
|
|
(ert-deftest spine-move-book-errors-on-missing-book ()
|
|
"spine-move-book errors when book not found."
|
|
(spine-edit-test--cleanup)
|
|
(unwind-protect
|
|
(progn
|
|
(spine-edit-test--two-shelf-setup)
|
|
(should-error (spine-move-book "nonexistent" "Science Fiction")))
|
|
(spine-edit-test--cleanup)))
|
|
|
|
(ert-deftest spine-move-book-errors-on-missing-shelf ()
|
|
"spine-move-book errors when target shelf not found."
|
|
(spine-edit-test--cleanup)
|
|
(unwind-protect
|
|
(progn
|
|
(spine-edit-test--two-shelf-setup)
|
|
(should-error (spine-move-book "test-0001" "Nonexistent Shelf")))
|
|
(spine-edit-test--cleanup)))
|
|
|
|
(ert-deftest spine-set-status-changes-todo ()
|
|
"spine-set-status changes the TODO keyword."
|
|
(spine-edit-test--cleanup)
|
|
(unwind-protect
|
|
(progn
|
|
(spine-edit-test--setup)
|
|
(spine-set-status "test-0001" "reading")
|
|
(let* ((books (spine-books))
|
|
(book (cl-find "test-0001" books :key (lambda (b) (plist-get b :id)) :test #'equal)))
|
|
(should book)
|
|
(should (equal (plist-get book :title) "READING Edit Test Book"))))
|
|
(spine-edit-test--cleanup)))
|
|
|
|
(ert-deftest spine-set-status-clears-todo ()
|
|
"spine-set-status with empty string removes TODO keyword."
|
|
(spine-edit-test--cleanup)
|
|
(unwind-protect
|
|
(progn
|
|
(spine-edit-test--setup)
|
|
(spine-set-status "test-0001" "")
|
|
(let* ((books (spine-books))
|
|
(book (cl-find "test-0001" books :key (lambda (b) (plist-get b :id)) :test #'equal)))
|
|
(should book)
|
|
(should (equal (plist-get book :title) "Edit Test Book"))))
|
|
(spine-edit-test--cleanup)))
|
|
|
|
(ert-deftest spine-set-status-errors-on-missing-book ()
|
|
"spine-set-status errors when book not found."
|
|
(spine-edit-test--cleanup)
|
|
(unwind-protect
|
|
(progn
|
|
(spine-edit-test--setup)
|
|
(should-error (spine-set-status "nonexistent" "reading")))
|
|
(spine-edit-test--cleanup)))
|