;;; test-pearl-list-comments.el --- Tests for comments in the bulk list -*- lexical-binding: t; -*- ;; Copyright (C) 2026 Craig Jennings ;; Author: Craig Jennings ;; This program is free software: you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with this program. If not, see . ;;; Commentary: ;; Tests for rendering comments in the bulk issue list: the per-issue cap ;; (`pearl--cap-issue-list-comments'), the `💬 shown/total' marker ;; (`pearl--comment-count-marker', the Comments heading), and the way the ;; append locator tolerates the marked heading so a later add-comment finds the ;; existing subtree instead of creating a second one. ;;; Code: (require 'test-bootstrap (expand-file-name "test-bootstrap.el")) (defun test-pearl--comments (n) "Return N comment plists, newest-first (createdAt descending), as the fetch returns." (let (out) (dotimes (i n) ;; i=0 is the newest; pad the index so string< orders correctly (push (list :id (format "c%02d" (- n i)) :author "A" :created-at (format "2026-05-%02dT00:00:00.000Z" (- n i)) :body (format "comment %d" (- n i))) out)) (nreverse out))) ;;; --cap-issue-list-comments (ert-deftest test-pearl-cap-comments-under-shown () "Fewer comments than the shown cap keeps them all with an exact total." (let ((pearl-list-comments-shown 5) (pearl-list-comments-count-cap 25)) (let ((out (pearl--cap-issue-list-comments (list :id "u" :comments (test-pearl--comments 3))))) (should (= 3 (length (plist-get out :comments)))) (should (equal '(:shown 3 :total 3 :overflow nil) (plist-get out :comment-count)))))) (ert-deftest test-pearl-cap-comments-over-shown-under-cap () "More than the shown cap but within the count cap: show 5, total exact." (let ((pearl-list-comments-shown 5) (pearl-list-comments-count-cap 25)) (let ((out (pearl--cap-issue-list-comments (list :id "u" :comments (test-pearl--comments 18))))) (should (= 5 (length (plist-get out :comments)))) (should (equal '(:shown 5 :total 18 :overflow nil) (plist-get out :comment-count)))))) (ert-deftest test-pearl-cap-comments-over-count-cap-overflows () "More than the count cap: total pins to the cap and overflows." (let ((pearl-list-comments-shown 5) (pearl-list-comments-count-cap 25)) ;; the fetch pulls cap+1 = 26 to detect overflow (let ((out (pearl--cap-issue-list-comments (list :id "u" :comments (test-pearl--comments 26))))) (should (= 5 (length (plist-get out :comments)))) (should (equal '(:shown 5 :total 25 :overflow t) (plist-get out :comment-count)))))) (ert-deftest test-pearl-cap-comments-none-unchanged () "An issue with no fetched comments is returned untouched, with no marker." (let ((issue (list :id "u" :comments nil))) (let ((out (pearl--cap-issue-list-comments issue))) (should-not (plist-get out :comments)) (should-not (plist-get out :comment-count))))) (ert-deftest test-pearl-cap-comments-keeps-the-newest () "The cap keeps the newest `shown' comments (input arrives newest-first)." (let ((pearl-list-comments-shown 3) (pearl-list-comments-count-cap 25)) (let* ((out (pearl--cap-issue-list-comments (list :id "u" :comments (test-pearl--comments 7)))) (ids (mapcar (lambda (c) (plist-get c :id)) (plist-get out :comments)))) ;; newest three are c07, c06, c05 (the head of the newest-first list) (should (equal '("c07" "c06" "c05") ids))))) ;;; --comment-count-marker (ert-deftest test-pearl-comment-count-marker-forms () "The marker renders shown/total, with a `+' past the cap and nothing for nil." (should (string= " 💬 5/18" (pearl--comment-count-marker '(:shown 5 :total 18 :overflow nil)))) (should (string= " 💬 5/25+" (pearl--comment-count-marker '(:shown 5 :total 25 :overflow t)))) (should (string= " 💬 3/3" (pearl--comment-count-marker '(:shown 3 :total 3 :overflow nil)))) (should (string= "" (pearl--comment-count-marker nil)))) ;;; --format-comments with a marker (ert-deftest test-pearl-format-comments-renders-marker-and-order () "With count-info the Comments heading carries the marker; bodies honor the sort order." (let* ((pearl-comment-sort-order 'newest-first) (comments (test-pearl--comments 5)) ; newest-first as fetched (out (pearl--format-comments comments '(:shown 5 :total 12 :overflow nil)))) (should (string-match-p "^\\*\\*\\* Comments 💬 5/12$" out)) ;; newest (comment 5) renders before oldest (comment 1) (should (< (string-match "comment 5\\b" out) (string-match "comment 1\\b" out))))) (ert-deftest test-pearl-format-comments-no-marker-without-count () "Without count-info (the single-issue thread), the heading has no marker." (let ((out (pearl--format-comments (test-pearl--comments 2)))) (should (string-match-p "^\\*\\*\\* Comments$" out)))) ;;; the marked heading is still found by the append locator (ert-deftest test-pearl-append-finds-marked-comments-heading () "Adding a comment to an issue whose Comments heading carries a marker reuses it." (let ((pearl-state-to-todo-mapping '(("Todo" . "TODO"))) (pearl-list-comments-shown 5) (pearl-list-comments-count-cap 25)) (let ((entry (pearl--format-issue-as-org-entry (pearl--cap-issue-list-comments (list :id "a" :identifier "ENG-1" :title "issue" :priority 3 :state '(:name "Todo") :comments (test-pearl--comments 8)))))) (with-temp-buffer (insert entry) (org-mode) (goto-char (point-min)) ;; the rendered Comments heading carries the marker (should (re-search-forward "^\\*\\*\\* Comments 💬 5/8$" nil t)) (goto-char (point-min)) (re-search-forward "issue") (pearl--append-comment-to-issue '(:id "cnew" :author "Z" :created-at "2026-06-01T00:00:00.000Z" :body "appended")) ;; exactly one Comments heading, and the new comment landed under it (goto-char (point-min)) (should (re-search-forward "^\\*\\*\\* Comments" nil t)) (should-not (re-search-forward "^\\*\\*\\* Comments" nil t)) (should (string-match-p "appended" (buffer-string))))))) (provide 'test-pearl-list-comments) ;;; test-pearl-list-comments.el ends here