;;; spine-book-model-test.el — ERT tests for spine-book-model (require 'ert) (require 'cl-lib) (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))) (defconst spine-book-model-test--uow (cl-find "8c1e-uow" (spine-books) :key (lambda (b) (plist-get b :id)) :test #'equal) "Use of Weapons fixture.") (defconst spine-book-model-test--aj (cl-find "3a1b-aj" (spine-books) :key (lambda (b) (plist-get b :id)) :test #'equal) "Ancillary Justice fixture.") (defconst spine-book-model-test--pir (cl-find "5e8d-pir" (spine-books) :key (lambda (b) (plist-get b :id)) :test #'equal) "Piranesi fixture.") (ert-deftest spine-book-model-title-strips-todo () "Title has TODO prefix stripped." (let ((model (spine-book-model spine-book-model-test--uow))) (should (equal (ht-get model "title") "Use of Weapons")))) (ert-deftest spine-book-model-status-reading () "READING book has status_class reading." (let ((model (spine-book-model spine-book-model-test--uow))) (should (equal (ht-get model "status_class") "reading")) (should (equal (ht-get model "status_label") "Reading")))) (ert-deftest spine-book-model-status-read () "READ book has status_class read." (let ((model (spine-book-model spine-book-model-test--aj))) (should (equal (ht-get model "status_class") "read")) (should (equal (ht-get model "status_label") "Read")))) (ert-deftest spine-book-model-status-want () "WANT book has status_class want." (let ((model (spine-book-model spine-book-model-test--pir))) (should (equal (ht-get model "status_class") "want")) (should (equal (ht-get model "status_label") "Want")))) (ert-deftest spine-book-model-author () "Author is passed through." (let ((model (spine-book-model spine-book-model-test--uow))) (should (equal (ht-get model "author") "Iain M. Banks")))) (ert-deftest spine-book-model-meta-with-format-and-date () "Meta includes format and date when both present." (let ((model (spine-book-model spine-book-model-test--uow))) (should (string-match "started.*audiobook" (ht-get model "meta"))))) (ert-deftest spine-book-model-format-active () "Format list has correct active flag." (let* ((model (spine-book-model spine-book-model-test--uow)) (formats (ht-get model "formats"))) (should (= (length formats) 3)) (should (equal (ht-get (nth 0 formats) "label") "Hardcover")) (should-not (ht-get (nth 0 formats) "active")) (should (equal (ht-get (nth 1 formats) "label") "eBook")) (should-not (ht-get (nth 1 formats) "active")) (should (equal (ht-get (nth 2 formats) "label") "Audiobook")) (should (ht-get (nth 2 formats) "active")))) (ert-deftest spine-book-model-notes () "Notes are mapped correctly." (let* ((model (spine-book-model spine-book-model-test--uow)) (notes (ht-get model "notes"))) (should (= (length notes) 3)) (should (equal (ht-get (nth 0 notes) "date") "2026-03-02")) (should (equal (ht-get (nth 0 notes) "text") "The two-track structure is doing something I can't name yet.")))) (ert-deftest spine-book-model-recommendation () "Recommendation includes initials, by, and note." (let* ((model (spine-book-model spine-book-model-test--uow)) (rec (ht-get model "recommendation"))) (should rec) (should (equal (ht-get rec "initials") "P")) (should (equal (ht-get rec "by") "Priya")) (should (string-match "Player of Games" (ht-get rec "note"))))) (ert-deftest spine-book-model-no-recommendation () "No recommendation when rec_by absent." (let ((model (spine-book-model spine-book-model-test--aj))) (should-not (ht-get model "recommendation")))) (ert-deftest spine-book-model-no-todo-prefix () "Book with no TODO prefix shows title as-is and empty status." (let* ((books (spine-books)) (tcm (cl-find "b2c1-tcm" books :key (lambda (b) (plist-get b :id)) :test #'equal))) (should tcm) (let ((model (spine-book-model tcm))) (should (equal (ht-get model "title") "The Checklist Manifesto")) (should (equal (ht-get model "status_class") "")) (should (equal (ht-get model "status_label") ""))))) (ert-deftest spine-book-model-has-date-no-format () "Has date but no format → meta shows started date only." (let* ((books (spine-books)) (tcm (cl-find "b2c1-tcm" books :key (lambda (b) (plist-get b :id)) :test #'equal))) (should tcm) (let ((model (spine-book-model tcm))) (should (equal (ht-get model "meta") "started 15 Jun"))))) (ert-deftest spine-book-model-back-url () "back_url links to index with this book's id." (let ((model (spine-book-model spine-book-model-test--uow))) (should (equal (ht-get model "back_url") "/index?id=8c1e-uow"))))