aboutsummaryrefslogtreecommitdiff
path: root/tests/test-chime-edge-coverage.el
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-05-11 04:50:45 -0500
committerCraig Jennings <c@cjennings.net>2026-05-11 04:50:45 -0500
commit21ec114def7df9aa61e43e8f2cee484ded772e72 (patch)
treebcce37275249879f5fb32d879e19126efdacf2d4 /tests/test-chime-edge-coverage.el
parenta11f554fd533f2139cf6b9e592388a5385d4462b (diff)
downloadchime-21ec114def7df9aa61e43e8f2cee484ded772e72.tar.gz
chime-21ec114def7df9aa61e43e8f2cee484ded772e72.zip
test: close coverage gaps to 99.88% line coverage
Five new test files cover branches the per-function suites missed: the day-wide notification pipeline, the jump-to-event navigation path (including the org-show-entry fallback for Org < 9.6), chime--stop's process-interrupt branch, chime--start's debug log, and the two async error branches in chime--fetch-and-process. The edge-coverage file mops up scattered one-line fallbacks: the day-wide-notification "today" path, the tooltip placeholder pass-through, timestamp-parse's no-context error message, log-silently's mid-line newline insert, the validation :error count, and record-async-failure's chime-debug hook. Line coverage on chime.el goes from 97.1% to 99.88%, 823 of 824 coverable lines. The one remaining line is a pcase _ fallback the preceding regex can't reach.
Diffstat (limited to 'tests/test-chime-edge-coverage.el')
-rw-r--r--tests/test-chime-edge-coverage.el174
1 files changed, 174 insertions, 0 deletions
diff --git a/tests/test-chime-edge-coverage.el b/tests/test-chime-edge-coverage.el
new file mode 100644
index 0000000..1325e77
--- /dev/null
+++ b/tests/test-chime-edge-coverage.el
@@ -0,0 +1,174 @@
+;;; test-chime-edge-coverage.el --- Cover edge branches surfaced by coverage gaps -*- 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:
+
+;; Small focused tests that exercise specific branches missed by the
+;; per-function suites. Each test points at the line range it covers
+;; so future readers can correlate quickly.
+
+;;; Code:
+
+(require 'test-bootstrap (expand-file-name "test-bootstrap.el"))
+(require 'testutil-time (expand-file-name "testutil-time.el"))
+(require 'cl-lib)
+
+;;;; chime--day-wide-notification-text fallback (chime.el ~ "t branch")
+
+(ert-deftest test-chime-day-wide-notification-text-future-event-uses-today-fallback ()
+ "Boundary: a future event reaches the cond's `t' fallback when no advance notice is configured."
+ (let* ((future-time (test-time-tomorrow-at 10 0))
+ (timestamp (test-timestamp-string future-time t))
+ (event (chime--make-event (list (cons timestamp nil))
+ "Future Event"
+ '((0 . medium))))
+ (chime-day-wide-advance-notice nil))
+ (should (string= "Future Event is due or scheduled today"
+ (chime--day-wide-notification-text event)))))
+
+;;;; chime--format-event-for-tooltip pcase fallback
+
+(ert-deftest test-chime-format-event-for-tooltip-unknown-placeholder-passes-through ()
+ "Boundary: unknown %X placeholders fall through the pcase and are kept as-is."
+ (let* ((time (test-time-today-at 14 30))
+ (timestamp (test-timestamp-string time))
+ (chime-tooltip-event-format "%t %T %u %X %Z")
+ (result (chime--format-event-for-tooltip timestamp 30 "Meeting")))
+ (should (string-match-p "%X" result))
+ (should (string-match-p "%Z" result))))
+
+;;;; chime--build-upcoming-events-list show-all-day-p=nil branch
+
+(ert-deftest test-chime-build-upcoming-events-list-filters-day-wide-when-not-shown ()
+ "Normal: when SHOW-ALL-DAY-P is nil, the call routes through `chime--filter-day-wide-events'."
+ (let* ((now (test-time-now))
+ (timed-time (test-time-at 0 1 0))
+ (timed-ts (test-timestamp-string timed-time))
+ (all-day-ts (test-timestamp-string now t))
+ (event (chime--make-event
+ (list (cons timed-ts timed-time)
+ (cons all-day-ts nil))
+ "Mixed Event"
+ '((0 . medium))))
+ (lookahead 1440))
+ (let ((with-all (chime--build-upcoming-events-list (list event) now lookahead t))
+ (without-all (chime--build-upcoming-events-list (list event) now lookahead nil)))
+ (should (= 1 (length with-all)))
+ (should (= 1 (length without-all)))
+ ;; Both pick the timed entry as soonest; the branch coverage is the
+ ;; point of this test.
+ (should (equal (nth 1 (car with-all))
+ (nth 1 (car without-all)))))))
+
+;;;; chime--timestamp-parse error path without context arg
+
+(ert-deftest test-chime-timestamp-parse-error-without-context-omits-context-suffix ()
+ "Error: when CONTEXT is nil, the failure message omits the in '...' suffix."
+ (let ((captured nil))
+ (cl-letf (((symbol-function 'org-parse-time-string)
+ (lambda (&rest _) (error "synthetic parse failure")))
+ ((symbol-function 'message)
+ (lambda (fmt &rest args)
+ (push (apply #'format fmt args) captured))))
+ (should (null (chime--timestamp-parse "<2026-05-11 Mon 09:30>"))))
+ (let ((joined (mapconcat #'identity captured "\n")))
+ (should (string-match-p "Failed to parse timestamp" joined))
+ ;; No "in '...': " suffix when context is nil.
+ (should-not (string-match-p " in '" joined)))))
+
+(ert-deftest test-chime-timestamp-parse-error-with-context-includes-context-suffix ()
+ "Error: when CONTEXT is non-nil, the failure message includes the in '...' suffix."
+ (let ((captured nil))
+ (cl-letf (((symbol-function 'org-parse-time-string)
+ (lambda (&rest _) (error "synthetic parse failure")))
+ ((symbol-function 'message)
+ (lambda (fmt &rest args)
+ (push (apply #'format fmt args) captured))))
+ (should (null (chime--timestamp-parse "<2026-05-11 Mon 09:30>"
+ "ContextEvent"))))
+ (let ((joined (mapconcat #'identity captured "\n")))
+ (should (string-match-p "in 'ContextEvent'" joined)))))
+
+;;;; chime--extract-gcal-timestamps drawer without :END:
+
+(ert-deftest test-chime-extract-gcal-timestamps-drawer-without-end-returns-empty ()
+ "Boundary: drawer without a closing :END: yields no timestamps and does not error.
+Exercises the `(point)' fallback branch in the drawer-end computation."
+ (let* ((future (test-time-tomorrow-at 9 30))
+ (ts (test-timestamp-string future))
+ (content (format "* Meeting
+:org-gcal:
+%s
+" ts)))
+ (with-temp-buffer
+ (org-mode)
+ (insert content)
+ (goto-char (point-min))
+ (should (null (chime--extract-gcal-timestamps "Meeting"))))))
+
+;;;; chime--display-validation-results :error branch
+
+(ert-deftest test-chime-display-validation-results-counts-error-results ()
+ "Normal: results with :error severity get counted into the summary."
+ (let ((messages nil)
+ (chime-validation-summary-format "errs=%d%s warns=%d%s"))
+ (cl-letf (((symbol-function 'message)
+ (lambda (fmt &rest args)
+ (push (apply #'format fmt args) messages))))
+ (chime--display-validation-results
+ '((:error "first failed" "first detail")
+ (:error "second failed" "second detail")
+ (:warning "third soft" "third detail")
+ (:ok "fourth ok" nil))))
+ (should (member "errs=2s warns=1" (nreverse messages)))))
+
+;;;; chime--record-async-failure with chime-debug feature loaded
+
+(ert-deftest test-chime-record-async-failure-calls-debug-logger-when-feature-loaded ()
+ "Normal: when the chime-debug feature is loaded, the debug logger is invoked."
+ (let ((logged nil)
+ (chime--consecutive-async-failures 0)
+ (chime-max-consecutive-failures 0)
+ (chime-modeline-no-events-text " ⏰")
+ (chime-modeline-string nil))
+ (cl-letf (((symbol-function 'featurep)
+ (lambda (feat &rest _) (eq feat 'chime-debug)))
+ ((symbol-function 'chime--debug-log-async-error)
+ (lambda (err) (setq logged err)))
+ ((symbol-function 'force-mode-line-update) (lambda (&optional _))))
+ (chime--record-async-failure '(error "boom") "Async error"))
+ (should (equal '(error "boom") logged))))
+
+;;;; chime--log-silently mid-line branch (point not at BOL)
+
+(ert-deftest test-chime-log-silently-inserts-leading-newline-when-not-at-bol ()
+ "Boundary: when *Messages* tail is mid-line, log-silently inserts a leading newline."
+ (with-current-buffer (get-buffer-create "*Messages*")
+ (let ((inhibit-read-only t))
+ (goto-char (point-max))
+ (insert "no-newline-prefix")
+ (let ((pos-before (point-max)))
+ (chime--log-silently "edge-coverage")
+ (goto-char pos-before)
+ ;; The inserted newline separates the two strings.
+ (should (looking-at "\n"))
+ (should (search-forward "edge-coverage" nil t))))))
+
+(provide 'test-chime-edge-coverage)
+;;; test-chime-edge-coverage.el ends here