diff options
| author | Craig Jennings <c@cjennings.net> | 2026-05-11 04:50:45 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-05-11 04:50:45 -0500 |
| commit | 21ec114def7df9aa61e43e8f2cee484ded772e72 (patch) | |
| tree | bcce37275249879f5fb32d879e19126efdacf2d4 /tests/test-chime-edge-coverage.el | |
| parent | a11f554fd533f2139cf6b9e592388a5385d4462b (diff) | |
| download | chime-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.el | 174 |
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 |
