;;; test-pearl-mapping.el --- Tests for pearl mapping helpers -*- 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: ;; Unit tests for the pure mapping helpers in pearl.el: ;; Linear state <-> org keyword, the cached TODO-states regex, and ;; Linear priority -> org cookie / readable name. ;;; Code: (require 'test-bootstrap (expand-file-name "test-bootstrap.el")) ;; A small, explicit mapping used across the state tests so cases don't ;; depend on the package default. (defmacro test-pearl--with-mapping (mapping &rest body) "Run BODY with the state mapping bound to MAPPING and the cache cleared." (declare (indent 1)) `(let ((pearl-state-to-todo-mapping ,mapping) (pearl-todo-states-pattern nil) (pearl--todo-states-pattern-source nil)) ,@body)) ;; pearl--map-linear-state-to-org (the static name->keyword lookup) was removed ;; in the keyword-cycle save: the keyword is now always the slug of the state ;; name (`pearl--state-name-to-keyword'), matching the workspace-derived #+TODO ;; header, and the keyword->state-id direction resolves through the team's ;; states (`pearl--resolve-keyword-to-state'), not a flat mapping. The mapping ;; alist itself survives only as the source for `pearl--get-todo-states-pattern' ;; (tested below). ;;; pearl--get-todo-states-pattern (ert-deftest test-pearl-get-todo-states-pattern-builds-alternation () "The pattern is the org keywords joined with regex alternation." (test-pearl--with-mapping '(("Todo" . "TODO") ("In Progress" . "IN-PROGRESS") ("Done" . "DONE")) (should (string-equal "TODO\\|IN-PROGRESS\\|DONE" (pearl--get-todo-states-pattern))))) (ert-deftest test-pearl-get-todo-states-pattern-empty-mapping () "An empty mapping yields an empty pattern string." (test-pearl--with-mapping '() (should (string-equal "" (pearl--get-todo-states-pattern))))) (ert-deftest test-pearl-get-todo-states-pattern-recomputes-after-mapping-change () "The cached pattern is recomputed when the mapping changes mid-session. Regression for the stale-cache bug: a once-populated pattern must not outlive a change to `pearl-state-to-todo-mapping'." (test-pearl--with-mapping '(("Todo" . "TODO") ("Done" . "DONE")) (should (string-equal "TODO\\|DONE" (pearl--get-todo-states-pattern))) ;; Change the mapping after the pattern has been cached. (setq pearl-state-to-todo-mapping '(("Todo" . "TODO") ("In Progress" . "DOING") ("Done" . "DONE"))) (should (string-equal "TODO\\|DOING\\|DONE" (pearl--get-todo-states-pattern))))) ;;; pearl--map-linear-priority-to-org (ert-deftest test-pearl-map-linear-priority-to-org-known-values () "Linear priorities 1-4 map to org cookies A-D." (should (string-equal "[#A]" (pearl--map-linear-priority-to-org 1))) (should (string-equal "[#B]" (pearl--map-linear-priority-to-org 2))) (should (string-equal "[#C]" (pearl--map-linear-priority-to-org 3))) (should (string-equal "[#D]" (pearl--map-linear-priority-to-org 4)))) (ert-deftest test-pearl-map-linear-priority-to-org-none-no-cookie () "Priority 0 (No priority) maps to no cookie, distinct from Medium's [#C]." (should (string-equal "" (pearl--map-linear-priority-to-org 0)))) (ert-deftest test-pearl-map-linear-priority-to-org-nil-and-unknown-no-cookie () "A nil or out-of-range priority maps to no cookie." (should (string-equal "" (pearl--map-linear-priority-to-org nil))) (should (string-equal "" (pearl--map-linear-priority-to-org 99)))) ;;; pearl--get-linear-priority-name (ert-deftest test-pearl-get-linear-priority-name-known-values () "Linear priorities 1-4 have readable names." (should (string-equal "Urgent" (pearl--get-linear-priority-name 1))) (should (string-equal "High" (pearl--get-linear-priority-name 2))) (should (string-equal "Medium" (pearl--get-linear-priority-name 3))) (should (string-equal "Low" (pearl--get-linear-priority-name 4)))) (ert-deftest test-pearl-get-linear-priority-name-none-and-unknown () "Zero (None), nil, and out-of-range priorities read as None." (should (string-equal "None" (pearl--get-linear-priority-name 0))) (should (string-equal "None" (pearl--get-linear-priority-name nil))) (should (string-equal "None" (pearl--get-linear-priority-name 99)))) ;;; pearl-get-priorities (ert-deftest test-pearl-get-priorities-returns-fixed-alist () "The priority list maps the five Linear priority names to their integers." (let ((priorities (pearl-get-priorities))) (should (equal 0 (cdr (assoc "No priority" priorities)))) (should (equal 1 (cdr (assoc "Urgent" priorities)))) (should (equal 2 (cdr (assoc "High" priorities)))) (should (equal 3 (cdr (assoc "Medium" priorities)))) (should (equal 4 (cdr (assoc "Low" priorities)))))) (provide 'test-pearl-mapping) ;;; test-pearl-mapping.el ends here