aboutsummaryrefslogtreecommitdiff
path: root/tests/test-pearl-heading.el
blob: 2675518996fe7c89f7768edc2f444658e18e158d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
;;; test-pearl-heading.el --- Tests for heading title rendering -*- lexical-binding: t; -*-

;; Copyright (C) 2026 Craig Jennings

;; Author: Craig Jennings <c@cjennings.net>

;; 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 <http://www.gnu.org/licenses/>.

;;; Commentary:

;; Tests for the heading title transforms: smart title case
;; (`pearl--title-case'), the identifier prefix (`pearl--heading-with-identifier'
;; / `pearl--strip-identifier-prefix'), and the way `--format-issue-as-org-entry'
;; renders them while keeping `LINEAR-TITLE-SHA256' over the bare displayed
;; title so an unedited heading is a no-op on title sync.

;;; Code:

(require 'test-bootstrap (expand-file-name "test-bootstrap.el"))

;;; --title-case

(ert-deftest test-pearl-title-case-capitalizes-significant-words ()
  "Significant words are capitalized; minor words mid-title stay lowercase."
  (should (string= "Fix the Refresh Bug" (pearl--title-case "fix the refresh bug")))
  (should (string= "A Tale of Two Cities" (pearl--title-case "a tale of two cities"))))

(ert-deftest test-pearl-title-case-edges-capitalize-minor-words ()
  "A minor word that is first or last is still capitalized."
  (should (string= "Of Mice and Men" (pearl--title-case "of mice and men")))
  (should (string= "What Is It For" (pearl--title-case "what is it for"))))

(ert-deftest test-pearl-title-case-preserves-existing-uppercase ()
  "A word that already has an uppercase letter (acronym, identifier) is left as-is."
  (should (string= "API Rate Limits" (pearl--title-case "API rate limits")))
  (should (string= "GraphQL and You" (pearl--title-case "GraphQL and you"))))

(ert-deftest test-pearl-title-case-boundaries ()
  "Empty, single-word, and extra-whitespace inputs behave."
  (should (string= "" (pearl--title-case "")))
  (should (string= "Bug" (pearl--title-case "bug")))
  (should (string= "Fix the Bug" (pearl--title-case "fix   the  bug"))))

(ert-deftest test-pearl-title-case-leaves-inner-punctuation-alone ()
  "Only the first letter is upcased, so an apostrophe or hyphen mid-word is intact."
  (should (string= "Don't Panic" (pearl--title-case "don't panic")))
  (should (string= "Re-run the Task" (pearl--title-case "re-run the task"))))

;;; --heading-with-identifier / --strip-identifier-prefix

(ert-deftest test-pearl-heading-identifier-prefix-roundtrips ()
  "Adding then stripping the identifier prefix is the identity."
  (let ((pearl-show-identifier-in-heading t))
    (let ((h (pearl--heading-with-identifier "Fix the Bug" "SE-401")))
      (should (string= "SE-401: Fix the Bug" h))
      (should (string= "Fix the Bug" (pearl--strip-identifier-prefix h "SE-401"))))))

(ert-deftest test-pearl-heading-identifier-prefix-disabled ()
  "With prefixing off, the title is returned unchanged."
  (let ((pearl-show-identifier-in-heading nil))
    (should (string= "Fix the Bug"
                     (pearl--heading-with-identifier "Fix the Bug" "SE-401")))))

(ert-deftest test-pearl-strip-identifier-prefix-empty-or-absent ()
  "Stripping is a no-op when the identifier is empty or not at the front."
  (should (string= "Fix the Bug" (pearl--strip-identifier-prefix "Fix the Bug" "")))
  (should (string= "Fix the Bug" (pearl--strip-identifier-prefix "Fix the Bug" nil)))
  ;; an identifier that only appears mid-title is not stripped
  (should (string= "see SE-9: later"
                   (pearl--strip-identifier-prefix "see SE-9: later" "SE-9"))))

;;; rendering on / off

(ert-deftest test-pearl-format-heading-defaults-prefix-and-title-case ()
  "By default the heading carries the identifier prefix and a title-cased title."
  (let ((pearl-show-identifier-in-heading t)
        (pearl-title-case-headings t))
    (let ((out (pearl--format-issue-as-org-entry
                '(:id "u" :identifier "SE-401" :title "fix the refresh bug"
                  :priority 2 :state (:name "Todo")))))
      (should (string-match-p "^\\*\\* TODO \\[#B\\] SE-401: Fix the Refresh Bug$" out)))))

(ert-deftest test-pearl-format-heading-both-toggles-off-renders-verbatim ()
  "With both toggles off, the heading is the bracket-stripped raw title, no prefix."
  (let ((pearl-show-identifier-in-heading nil)
        (pearl-title-case-headings nil))
    (let ((out (pearl--format-issue-as-org-entry
                '(:id "u" :identifier "SE-401" :title "fix the refresh bug"
                  :priority 2 :state (:name "Todo")))))
      (should (string-match-p "^\\*\\* TODO \\[#B\\] fix the refresh bug$" out)))))

(ert-deftest test-pearl-format-title-hash-is-over-displayed-title-no-prefix ()
  "The title hash is over the displayed (cased) title without the identifier prefix.
That is what makes a fetch + unedited heading a no-op on title sync."
  (let ((pearl-show-identifier-in-heading t)
        (pearl-title-case-headings t))
    (let ((out (pearl--format-issue-as-org-entry
                '(:id "u" :identifier "SE-401" :title "fix the refresh bug"
                  :priority 2 :state (:name "Todo")))))
      (should (string-match-p
               (format "^:LINEAR-TITLE-SHA256: +%s$"
                       (secure-hash 'sha256 "Fix the Refresh Bug"))
               out)))))

(provide 'test-pearl-heading)
;;; test-pearl-heading.el ends here