;;; test-pearl-single-issue.el --- Tests for the single-issue source -*- 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 the single-issue source: `pearl--issue-source' (id/identifier -> ;; source plist), the `#+LINEAR-SOURCE' round-trip for that plist, ;; `pearl--fetch-and-render-issue' (fetch one issue and render it like every ;; other source), and `pearl-open-issue-by-id' (the jump-by-identifier command). ;; The async fetch and the render boundary are stubbed at their seams. ;;; Code: (require 'test-bootstrap (expand-file-name "test-bootstrap.el")) ;;; pearl--issue-source (ert-deftest test-pearl-issue-source-builds-plist () "An id + identifier builds a `:type issue' source named by the identifier." (let ((s (pearl--issue-source "u1" "ENG-7"))) (should (eq 'issue (plist-get s :type))) (should (string= "u1" (plist-get s :id))) (should (string= "ENG-7" (plist-get s :identifier))) (should (string= "ENG-7" (plist-get s :name))))) (ert-deftest test-pearl-issue-source-name-falls-back-to-id () "With no identifier the source name falls back to the id, never nil." (let ((s (pearl--issue-source "u1" nil))) (should (string= "u1" (plist-get s :name))))) (ert-deftest test-pearl-issue-source-round-trips-through-header () "The issue source survives `#+LINEAR-SOURCE' serialization and read-back." (let* ((s (pearl--issue-source "u1" "ENG-7")) (back (car (read-from-string (pearl--linear-source-string s))))) (should (equal s back)))) ;;; pearl--fetch-and-render-issue (ert-deftest test-pearl-fetch-and-render-issue-renders-one () "A fetched node renders through the shared query-result boundary as one issue, tagged with an issue source built from the node's own id and identifier." (let ((node '((id . "u1") (identifier . "ENG-7") (title . "A bug"))) captured) (cl-letf (((symbol-function 'pearl--fetch-issue-async) (lambda (_ref cb) (funcall cb node))) ((symbol-function 'pearl--render-query-result) (lambda (result source) (setq captured (list result source))))) (pearl--fetch-and-render-issue "ENG-7") (should captured) (let ((result (nth 0 captured)) (source (nth 1 captured))) (should (equal (list node) (pearl--query-result-issues result))) (should (eq 'issue (plist-get source :type))) (should (string= "u1" (plist-get source :id))) (should (string= "ENG-7" (plist-get source :identifier))))))) (ert-deftest test-pearl-fetch-and-render-issue-missing-does-not-render () "A `:missing' result reports and renders nothing (no buffer rewrite)." (let (rendered) (cl-letf (((symbol-function 'pearl--fetch-issue-async) (lambda (_ref cb) (funcall cb :missing))) ((symbol-function 'pearl--render-query-result) (lambda (&rest _) (setq rendered t))) ((symbol-function 'message) (lambda (&rest _) nil))) (pearl--fetch-and-render-issue "ENG-404") (should-not rendered)))) (ert-deftest test-pearl-fetch-and-render-issue-error-does-not-render () "An `:error' result reports and renders nothing." (let (rendered) (cl-letf (((symbol-function 'pearl--fetch-issue-async) (lambda (_ref cb) (funcall cb :error))) ((symbol-function 'pearl--render-query-result) (lambda (&rest _) (setq rendered t))) ((symbol-function 'message) (lambda (&rest _) nil))) (pearl--fetch-and-render-issue "ENG-7") (should-not rendered)))) ;;; pearl-open-issue-by-id (ert-deftest test-pearl-open-issue-by-id-forwards-trimmed-ref () "The command trims the typed ref and forwards it to the fetch/render path." (let (got) (cl-letf (((symbol-function 'pearl--require-account-context) #'ignore) ((symbol-function 'pearl--progress) (lambda (&rest _) nil)) ((symbol-function 'pearl--fetch-and-render-issue) (lambda (ref) (setq got ref)))) (pearl-open-issue-by-id " ENG-7 ") (should (string= "ENG-7" got))))) (ert-deftest test-pearl-open-issue-by-id-rejects-empty () "An empty/whitespace identifier is a `user-error', not a fetch." (let (fetched) (cl-letf (((symbol-function 'pearl--require-account-context) #'ignore) ((symbol-function 'pearl--fetch-and-render-issue) (lambda (&rest _) (setq fetched t)))) (should-error (pearl-open-issue-by-id " ") :type 'user-error) (should-not fetched)))) (provide 'test-pearl-single-issue) ;;; test-pearl-single-issue.el ends here