aboutsummaryrefslogtreecommitdiff
path: root/tests/test-system-defaults--warning-display-dead-buffer.el
blob: 48c7797efdf2160bb1d02d98667d1e483c5744de (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
;;; test-system-defaults--warning-display-dead-buffer.el --- Dead-buffer guard on deferred warnings -*- lexical-binding: t; -*-

;;; Commentary:
;; Emacs 31.1's warnings.el defers daemon-startup warnings into a one-shot
;; `after-make-frame-functions' closure that calls `warning--display-buffer'
;; on the first client frame with the *Warnings* buffer object it captured at
;; warning time.  If anything killed that buffer in between, `display-buffer'
;; signals inside `make-frame', server.el swallows the error as
;; "-window-system-unsupported", and emacsclient silently retries on $DISPLAY:
;; the session's first frame lands on XWayland.
;;
;; The root fix keeps *Warnings* alive (undead-buffers.el).  This is the
;; defense in depth: `cj/warning--display-buffer-if-live' wraps
;; `warning--display-buffer' so a dead buffer is skipped rather than passed
;; on.  Load happens once in the shared sandbox (testutil-system-defaults.el);
;; `warning--display-buffer' only exists from Emacs 31, so the end-to-end case
;; skips on older builds while the pure-function cases always run.

;;; Code:

(require 'ert)
(add-to-list 'load-path (expand-file-name "tests" user-emacs-directory))
(require 'testutil-system-defaults)

(test-system-defaults--with-load-environment
  (test-system-defaults--load))

(defun test-system-defaults--recording-orig ()
  "Return (ORIG . CALLS) where ORIG records every argument into CALLS."
  (let ((calls (list nil)))
    (cons (lambda (buffer)
            (push buffer (car calls))
            'displayed)
          calls)))

;;; Normal Cases

(ert-deftest test-system-defaults-warning-guard-passes-live-buffer-through ()
  "Normal: a live buffer reaches the original and its value is returned."
  (let* ((rec (test-system-defaults--recording-orig))
         (buf (generate-new-buffer " *warning-guard-live*")))
    (unwind-protect
        (progn
          (should (eq 'displayed
                      (cj/warning--display-buffer-if-live (car rec) buf)))
          (should (equal (list buf) (car (cdr rec)))))
      (kill-buffer buf))))

(ert-deftest test-system-defaults-warning-guard-is-installed ()
  "Normal: loading system-defaults installs the guard on the deferred display.
From Emacs 31 the advised symbol must actually be defined: pending advice on
an undefined symbol would still count as installed, so a rename upstream
would otherwise silently disable the backstop."
  (should (advice-member-p #'cj/warning--display-buffer-if-live
                           'warning--display-buffer))
  (when (>= emacs-major-version 31)
    (should (fboundp 'warning--display-buffer))))

(ert-deftest test-system-defaults-warning-guard-resolves-live-buffer-name ()
  "Normal: a live buffer's name is resolved and passed through as the buffer."
  (let* ((rec (test-system-defaults--recording-orig))
         (buf (generate-new-buffer " *warning-guard-named*")))
    (unwind-protect
        (progn
          (should (eq 'displayed
                      (cj/warning--display-buffer-if-live
                       (car rec) (buffer-name buf))))
          (should (equal (list buf) (car (cdr rec)))))
      (kill-buffer buf))))

;;; Boundary Cases

(ert-deftest test-system-defaults-warning-guard-skips-killed-buffer ()
  "Boundary: a killed buffer never reaches the original; result is nil."
  (let* ((rec (test-system-defaults--recording-orig))
         (buf (generate-new-buffer " *warning-guard-dead*")))
    (kill-buffer buf)
    (should-not (cj/warning--display-buffer-if-live (car rec) buf))
    (should-not (car (cdr rec)))))

(ert-deftest test-system-defaults-warning-guard-end-to-end-dead-buffer-does-not-signal ()
  "Boundary: the real deferred display survives a dead buffer.
Mirrors the live failure: a string condition in `display-buffer-alist' is
what `buffer-match-p' tripped over when the buffer name came back nil."
  (skip-unless (fboundp 'warning--display-buffer))
  (let ((buf (generate-new-buffer "*Warnings*"))
        (display-buffer-alist '(("^ \\*test-guard\\*" display-buffer-no-window))))
    (kill-buffer buf)
    (should-not (warning--display-buffer buf))))

;;; Error Cases

(ert-deftest test-system-defaults-warning-guard-rejects-non-buffer ()
  "Error: nil, or a name that resolves to no buffer, is skipped without a signal."
  (let ((rec (test-system-defaults--recording-orig))
        (missing " *warning-guard-no-such-buffer*"))
    (when (get-buffer missing) (kill-buffer missing))
    (should-not (cj/warning--display-buffer-if-live (car rec) nil))
    (should-not (cj/warning--display-buffer-if-live (car rec) missing))
    (should-not (car (cdr rec)))))

(provide 'test-system-defaults--warning-display-dead-buffer)
;;; test-system-defaults--warning-display-dead-buffer.el ends here