summaryrefslogtreecommitdiff
path: root/test/lisp/erc
diff options
context:
space:
mode:
Diffstat (limited to 'test/lisp/erc')
-rw-r--r--test/lisp/erc/erc-nicks-tests.el269
-rw-r--r--test/lisp/erc/erc-track-tests.el262
-rw-r--r--test/lisp/erc/resources/erc-tests-common.el43
3 files changed, 571 insertions, 3 deletions
diff --git a/test/lisp/erc/erc-nicks-tests.el b/test/lisp/erc/erc-nicks-tests.el
index 08080d249d5..c865a902a0e 100644
--- a/test/lisp/erc/erc-nicks-tests.el
+++ b/test/lisp/erc/erc-nicks-tests.el
@@ -30,8 +30,11 @@
;;; Code:
-(require 'ert-x)
(require 'erc-nicks)
+(require 'ert-x)
+(eval-and-compile
+ (let ((load-path (cons (ert-resource-directory) load-path)))
+ (require 'erc-tests-common)))
;; This function replicates the behavior of older "invert" strategy
;; implementations from EmacsWiki, etc. The values for the lower and
@@ -568,4 +571,268 @@
(should (equal erc-nicks--colors-rejects '(t)))))
+(declare-function erc-track-modified-channels "erc-track" ())
+
+(defun erc-nicks-tests--track-faces (test)
+ (require 'erc-track)
+ (defvar erc-modified-channels-alist)
+ (defvar erc-track--normal-faces)
+
+ (erc-tests-common-make-server-buf)
+ (erc-nicks-mode +1)
+
+ (let ((erc-modules (cons 'nicks erc-modules))
+ ;; Pretend these faces were added in response-handling during
+ ;; insertion modification by buttonizing hooks. See
+ ;; `erc-nicks--highlight-button'.
+ (add-face (lambda (face)
+ (erc-nicks--remember-face-for-track ; speaker
+ (list face 'erc-nick-default-face))
+ (erc-nicks--remember-face-for-track ; mention
+ (list face 'erc-default-face))))
+ ;;
+ bob-face alice-face assert-result)
+
+ (with-current-buffer (erc--open-target "#chan")
+ (should erc-nicks-mode)
+ (should (setq bob-face (erc-nicks--get-face "bob" "bob@foonet")))
+ (should (setq alice-face (erc-nicks--get-face "alice" "alice@foonet")))
+
+ (erc-tests-common-track-modified-channels-sans-setup
+
+ (lambda (set-faces)
+
+ (setq assert-result ; fixture binds `erc-modified-channels-alist'
+ (lambda (result)
+ (should (equal (alist-get (current-buffer)
+ erc-modified-channels-alist)
+ result))))
+
+ (funcall test set-faces assert-result add-face
+ bob-face alice-face)))))
+
+ (erc-tests-common-kill-buffers))
+
+(ert-deftest erc-nicks-track-faces/prioritize ()
+ (should (eq erc-nicks-track-faces 'prioritize))
+ (erc-nicks-tests--track-faces
+ (lambda (set-faces assert-result add-face bob-face alice-face)
+
+ (defvar erc-track--alt-normals-function)
+ (should erc-track--alt-normals-function)
+
+ (funcall add-face bob-face)
+ (funcall add-face alice-face)
+
+ ;; Simulate a JOIN.
+ (funcall set-faces '(erc-notice-face))
+ (erc-track-modified-channels)
+ (funcall assert-result '(1 . erc-notice-face))
+
+ ;; Someone speaks, and the mode-line changes to a `nicks' owned
+ ;; composite face for the speaker.
+ (funcall set-faces `(erc-timestamp-face
+ (,bob-face erc-nick-default-face)
+ erc-default-face))
+ (erc-track-modified-channels)
+ (funcall assert-result `(2 ,bob-face erc-nick-default-face))
+
+ ;; That same someone speaks, and the mode-line indicator changes to
+ ;; another "normal" face in the message body.
+ (funcall set-faces `(erc-timestamp-face
+ (,bob-face erc-nick-default-face)
+ erc-default-face))
+ (erc-track-modified-channels)
+ (funcall assert-result '(3 . erc-default-face))
+
+ ;; And yet again, which results in the indicator going back to one.
+ (funcall set-faces `(erc-timestamp-face
+ (,bob-face erc-nick-default-face)
+ erc-default-face))
+ (erc-track-modified-channels)
+ (funcall assert-result `(4 ,bob-face erc-nick-default-face))
+
+ ;; Now the same person mentions another server user, resulting in a
+ ;; change to *that* `nicks' owned face because it appears later in
+ ;; the message content (timestamp is last).
+ (funcall set-faces `(erc-timestamp-face
+ (,alice-face erc-default-face)
+ (,bob-face erc-nick-default-face)
+ erc-default-face))
+ (erc-track-modified-channels)
+ (funcall assert-result `(5 ,alice-face erc-default-face))
+
+ ;; The mentioned user replies, mentioning the mentioner. But
+ ;; instead of the normal "normals" processing preferring the ranked
+ ;; `erc-default-face', the `erc-nicks-track-faces' logic kicks in
+ ;; via `erc-track--alt-normals-function' and provides a `nicks'
+ ;; owned replacement.
+ (funcall set-faces `(erc-timestamp-face
+ (,bob-face erc-default-face)
+ (,alice-face erc-nick-default-face)
+ erc-default-face))
+ (erc-track-modified-channels)
+ (funcall assert-result `(6 ,bob-face erc-default-face))
+
+ ;; Finally, another notice arrives.
+ (funcall set-faces '(erc-notice-face))
+ (erc-track-modified-channels)
+ (funcall assert-result '(7 . erc-notice-face)))))
+
+(ert-deftest erc-nicks-track-faces/defer ()
+ (should (eq erc-nicks-track-faces 'prioritize))
+ (let ((erc-nicks-track-faces 'defer))
+ (erc-nicks-tests--track-faces
+ (lambda (set-faces assert-result add-face bob-face alice-face)
+
+ (funcall add-face bob-face)
+ (funcall add-face alice-face)
+
+ ;; Simulate a JOIN.
+ (funcall set-faces '(erc-notice-face))
+ (erc-track-modified-channels)
+ (funcall assert-result '(1 . erc-notice-face))
+
+ ;; Someone speaks, and the mode-line indicator changes to the
+ ;; highest ranked face in the message. (All `nicks' owned faces
+ ;; are unranked).
+ (funcall set-faces `(erc-timestamp-face
+ (,bob-face erc-nick-default-face)
+ erc-default-face))
+ (erc-track-modified-channels)
+ (funcall assert-result `(2 . erc-default-face))
+
+ ;; That same someone speaks, and the mode-line indicator changes
+ ;; to a `nicks' owned face. It first reaches for the highest
+ ;; ranked face in the message but then applies the "normals"
+ ;; rules, resulting in a promoted alternate.
+ (funcall set-faces `(erc-timestamp-face
+ (,bob-face erc-nick-default-face)
+ erc-default-face))
+ (erc-track-modified-channels)
+ (funcall assert-result `(3 ,bob-face erc-nick-default-face))
+
+ ;; And yet again, which results in the indicator going back to one.
+ (funcall set-faces `(erc-timestamp-face
+ (,bob-face erc-nick-default-face)
+ erc-default-face))
+ (erc-track-modified-channels)
+ (funcall assert-result '(4 . erc-default-face))
+
+ ;; The same person mentions another server user, resulting in a
+ ;; change to that `nicks' owned face because the logic from
+ ;; 3. again applies.
+ (funcall set-faces `(erc-timestamp-face
+ (,alice-face erc-default-face)
+ (,bob-face erc-nick-default-face)
+ erc-default-face))
+ (erc-track-modified-channels)
+ (funcall assert-result `(5 ,alice-face erc-default-face))
+
+ ;; The mentioned user replies, mentioning the mentioner.
+ ;; However, the `nicks' module does not intercede in the decision
+ ;; making to overrule the ranked nominee.
+ (funcall set-faces `(erc-timestamp-face
+ (,bob-face erc-default-face)
+ (,alice-face erc-nick-default-face)
+ erc-default-face))
+ (erc-track-modified-channels)
+ (funcall assert-result '(6 . erc-default-face))
+
+ ;; Finally, another notice arrives.
+ (funcall set-faces '(erc-notice-face))
+ (erc-track-modified-channels)
+ (funcall assert-result '(7 . erc-notice-face))))))
+
+(ert-deftest erc-nicks-track-faces/nil ()
+ (should (eq erc-nicks-track-faces 'prioritize))
+ (let (erc-nicks-track-faces)
+ (erc-nicks-tests--track-faces
+ (lambda (set-faces assert-result _ bob-face alice-face)
+
+ (defvar erc-track--face-reject-function)
+ (should erc-track--face-reject-function)
+
+ ;; Simulate a JOIN.
+ (funcall set-faces '(erc-notice-face))
+ (erc-track-modified-channels)
+ (funcall assert-result '(1 . erc-notice-face))
+
+ ;; Someone speaks, and the mode-line indicator changes to the
+ ;; only ranked face in the message.
+ (funcall set-faces `(erc-timestamp-face
+ (,bob-face erc-nick-default-face)
+ erc-default-face))
+ (erc-track-modified-channels)
+ (funcall assert-result `(2 . erc-default-face))
+
+ ;; That same someone speaks, and since no other "normals" exist
+ ;; in the message, the indicator is not updated.
+ (funcall set-faces `(erc-timestamp-face
+ (,bob-face erc-nick-default-face)
+ erc-default-face))
+ (erc-track-modified-channels)
+ (funcall assert-result '(3 . erc-default-face))
+
+ ;; Now the same person mentions another server user, but the same
+ ;; logic applies, and the indicator is not updated.
+ (funcall set-faces `(erc-timestamp-face
+ (,alice-face erc-default-face)
+ (,bob-face erc-nick-default-face)
+ erc-default-face))
+ (erc-track-modified-channels)
+ (funcall assert-result `(4 . erc-default-face))
+
+ ;; Finally, another notice arrives.
+ (funcall set-faces '(erc-notice-face))
+ (erc-track-modified-channels)
+ (funcall assert-result '(5 . erc-notice-face))))))
+
+(ert-deftest erc-nicks-track-faces/t ()
+ (should (eq erc-nicks-track-faces 'prioritize))
+ (let ((erc-nicks-track-faces t))
+ (erc-nicks-tests--track-faces
+ (lambda (set-faces assert-result add-face bob-face alice-face)
+
+ (defvar erc-track--alt-normals-function)
+ (should erc-track--alt-normals-function)
+
+ (funcall add-face bob-face)
+ (funcall add-face alice-face)
+
+ ;; Simulate a JOIN.
+ (funcall set-faces '(erc-notice-face))
+ (erc-track-modified-channels)
+ (funcall assert-result '(1 . erc-notice-face))
+
+ ;; Someone speaks, and the mode-line indicator changes to that
+ ;; someone's `nicks'-owned face.
+ (funcall set-faces `(erc-timestamp-face
+ (,bob-face erc-nick-default-face)
+ erc-default-face))
+ (erc-track-modified-channels)
+ (funcall assert-result `(2 ,bob-face erc-nick-default-face))
+
+ ;; That same someone speaks, and though one other "normal" exists
+ ;; in the message, `erc-default-face', no update occurs.
+ (funcall set-faces `(erc-timestamp-face
+ (,bob-face erc-nick-default-face)
+ erc-default-face))
+ (erc-track-modified-channels)
+ (funcall assert-result `(3 ,bob-face erc-nick-default-face))
+
+ ;; Another server user speaks, mentioning the previous speaker,
+ ;; and the indicator is updated to reflect the new speaker.
+ (funcall set-faces `(erc-timestamp-face
+ (,bob-face erc-default-face) ; bob:
+ (,alice-face erc-nick-default-face) ; <alice>
+ erc-default-face))
+ (erc-track-modified-channels)
+ (funcall assert-result `(4 ,alice-face erc-nick-default-face))
+
+ ;; Finally, another notice arrives.
+ (funcall set-faces '(erc-notice-face))
+ (erc-track-modified-channels)
+ (funcall assert-result '(5 . erc-notice-face))))))
+
;;; erc-nicks-tests.el ends here
diff --git a/test/lisp/erc/erc-track-tests.el b/test/lisp/erc/erc-track-tests.el
index 8149138a971..c830c8b2016 100644
--- a/test/lisp/erc/erc-track-tests.el
+++ b/test/lisp/erc/erc-track-tests.el
@@ -227,6 +227,13 @@
(defun erc-track-tests--select-mode-line-face (ranked normals cases)
(setq normals (map-into (mapcar (lambda (f) (cons f t)) normals)
'(hash-table :test equal)))
+
+ (setq ranked (cons (map-into (mapcar (let ((i 0))
+ (lambda (f) (cons f (cl-incf i))))
+ ranked)
+ '(hash-table :test equal))
+ ranked))
+
(pcase-dolist (`(,want ,cur-face ,new-faces) cases)
(ert-info ((format "Observed: {cur: %S, new: %S, want: %S}"
@@ -235,8 +242,8 @@
(mapcar (lambda (f) (cons f t)) new-faces)
'(hash-table :test equal))
(reverse new-faces)))
- (should (equal want (funcall #'erc-track--select-mode-line-face
- cur-face new-faces ranked normals))))))
+ (should (equal want (erc-track--select-mode-line-face
+ cur-face new-faces ranked normals))))))
;; The main difference between these variants is that with the above,
;; when given alternating lines like
@@ -410,4 +417,255 @@
(when noninteractive
(kill-buffer))))
+(defun erc-track-tests--modified-channels/baseline (set-faces)
+ ;; Simulate a JOIN, PART, etc. that's displayed in `erc-notice-face'.
+ (funcall set-faces '(erc-notice-face))
+ (erc-track-modified-channels)
+ (should (equal (alist-get (current-buffer) erc-modified-channels-alist)
+ '(1 . erc-notice-face)))
+
+ ;; Someone speaks, and the mode-line face goes from ERC's generic
+ ;; "notice" face, `erc-notice-face', to the first face in the
+ ;; inserted message that outranks it, which happens to be the
+ ;; `button' module's composite face for buttonized speakers:
+ ;; (erc-button-nick-default-face erc-nick-default-face). It
+ ;; outranks both the previous occupant, `erc-notice-face', and its
+ ;; one cohabitant in the message text, `erc-default-face', in
+ ;; `erc-track-faces-priority-list'. Note that in the following
+ ;; list, `erc-default-face' appears first because it's used for the
+ ;; opening speaker bracket "<". The timestamp appears last because
+ ;; it's a right-sided stamp appended to the message body.
+ (funcall set-faces '(erc-timestamp-face
+ (erc-button-nick-default-face erc-nick-default-face)
+ erc-default-face))
+ (erc-track-modified-channels)
+ (should (equal (alist-get (current-buffer) erc-modified-channels-alist)
+ '(2 erc-button-nick-default-face erc-nick-default-face)))
+
+ ;; The speaker speaks again immediately, and the segment changes to
+ ;; `erc-default-face', which appears later in the message, as
+ ;; normal body text. This happens because both `erc-default-face'
+ ;; and (erc-button-nick-default-face erc-nick-default-face) appear
+ ;; in `erc-track-faces-normal-list', meaning the lower-ranked
+ ;; former can replace the higher-ranked latter in the mode-line for
+ ;; the purpose of indicating channel activity.
+ (funcall set-faces '(erc-timestamp-face
+ (erc-button-nick-default-face erc-nick-default-face)
+ erc-default-face))
+ (erc-track-modified-channels)
+ (should (equal (alist-get (current-buffer) erc-modified-channels-alist)
+ '(3 . erc-default-face)))
+
+ ;; Note: if (erc-button-nick-default-face erc-nick-default-face)
+ ;; were removed from `erc-track-faces-priority-list' but kept in
+ ;; `erc-track-faces-normal-list', then replaying the sequence would
+ ;; result in the previous two results being switched:
+ ;; `erc-default-face' would replace `erc-notice-face' before being
+ ;; replaced by the buttonized composite.
+
+ ;; The speaker speaks yet again, and the segment goes back to the
+ ;; higher ranking face.
+ (funcall set-faces '(erc-timestamp-face
+ (erc-button-nick-default-face erc-nick-default-face)
+ erc-default-face))
+ (erc-track-modified-channels)
+ (should (equal (alist-get (current-buffer) erc-modified-channels-alist)
+ '(4 erc-button-nick-default-face erc-nick-default-face)))
+
+ ;; Finally, another notice arrives. Although lower ranked, it also
+ ;; appears in `erc-track-faces-normal-list' and so is eligible to
+ ;; replace the incumbent.
+ (funcall set-faces '(erc-notice-face))
+ (erc-track-modified-channels)
+ (should (equal (alist-get (current-buffer) erc-modified-channels-alist)
+ '(5 . erc-notice-face))))
+
+(ert-deftest erc-track-modified-channels/baseline ()
+ (erc-tests-common-track-modified-channels
+ #'erc-track-tests--modified-channels/baseline))
+
+(ert-deftest erc-track-modified-channels/baseline/mention ()
+ (erc-tests-common-track-modified-channels
+ (lambda (set-faces)
+ ;; Note: these messages don't have timestamps.
+
+ ;; Simulate a JOIN, PART, etc. that's displayed in `erc-notice-face'.
+ (funcall set-faces '(erc-notice-face))
+ (erc-track-modified-channels)
+ (should (equal (alist-get (current-buffer) erc-modified-channels-alist)
+ '(1 . erc-notice-face)))
+
+ ;; Someone speaks, mentioning someone else, and the mode-line
+ ;; changes to (erc-button-nick-default-face erc-nick-default-face)
+ ;; rather than (erc-button-nick-default-face erc-default-face)
+ ;; based on their rankings in `erc-track-faces-priority-list'.
+ (funcall set-faces '((erc-button-nick-default-face erc-default-face)
+ (erc-button-nick-default-face erc-nick-default-face)
+ erc-default-face))
+ (erc-track-modified-channels)
+ (should (equal (alist-get (current-buffer) erc-modified-channels-alist)
+ '(2 erc-button-nick-default-face erc-nick-default-face)))
+
+ ;; Someone else speaks, again with a mention and additional body text.
+ (funcall set-faces '((erc-button-nick-default-face erc-default-face)
+ (erc-button-nick-default-face erc-nick-default-face)
+ erc-default-face))
+ (erc-track-modified-channels)
+ (should (equal (alist-get (current-buffer) erc-modified-channels-alist)
+ '(3 erc-button-nick-default-face erc-default-face)))
+
+ ;; And yet again, which results in the indicator going back to one.
+ (funcall set-faces '((erc-button-nick-default-face erc-default-face)
+ (erc-button-nick-default-face erc-nick-default-face)
+ erc-default-face))
+ (erc-track-modified-channels)
+ (should (equal (alist-get (current-buffer) erc-modified-channels-alist)
+ '(4 erc-button-nick-default-face erc-nick-default-face)))
+
+ ;; Finally, another notice arrives.
+ (funcall set-faces '(erc-notice-face))
+ (erc-track-modified-channels)
+ (should (equal (alist-get (current-buffer) erc-modified-channels-alist)
+ '(5 . erc-notice-face))))))
+
+;; The compat-oriented option `erc-track-ignore-normal-contenders-p'
+;; blinds track to `erc-track-faces-normal-list' for certain consecutive
+;; messages with an identical face makeup.
+(ert-deftest erc-track-modified-channels/baseline/ignore ()
+ (let ((erc-track-ignore-normal-contenders-p t))
+ (erc-tests-common-track-modified-channels
+ (lambda (set-faces)
+ ;; Simulate a JOIN, PART, etc. that's displayed in `erc-notice-face'.
+ (funcall set-faces '(erc-notice-face))
+ (erc-track-modified-channels)
+ (should (equal (alist-get (current-buffer) erc-modified-channels-alist)
+ '(1 . erc-notice-face)))
+
+ ;; Someone speaks, and the mode-line indicator's face changes to
+ ;; that of a buttonized speaker.
+ (funcall set-faces
+ '(erc-timestamp-face
+ (erc-button-nick-default-face erc-nick-default-face)
+ erc-default-face))
+ (erc-track-modified-channels)
+ (should (equal (alist-get (current-buffer) erc-modified-channels-alist)
+ '(2 erc-button-nick-default-face erc-nick-default-face)))
+
+ ;; The speaker speaks again immediately, and the segment doesn't
+ ;; change.
+ (funcall set-faces
+ '(erc-timestamp-face
+ (erc-button-nick-default-face erc-nick-default-face)
+ erc-default-face))
+ (erc-track-modified-channels)
+ (should (equal (alist-get (current-buffer) erc-modified-channels-alist)
+ '(3 erc-button-nick-default-face erc-nick-default-face)))
+
+ ;; Finally, another notice arrives.
+ (funcall set-faces '(erc-notice-face))
+ (erc-track-modified-channels)
+ (should (equal (alist-get (current-buffer) erc-modified-channels-alist)
+ '(4 . erc-notice-face)))))))
+
+;; Compat-oriented option `erc-track-ignore-normal-contenders-p'.
+(ert-deftest erc-track-modified-channels/baseline/mention/ignore ()
+ (let ((erc-track-ignore-normal-contenders-p t))
+ (erc-tests-common-track-modified-channels
+ (lambda (set-faces)
+
+ ;; Simulate a JOIN, PART, etc. that's displayed in `erc-notice-face'.
+ (funcall set-faces '(erc-notice-face))
+ (erc-track-modified-channels)
+ (should (equal (alist-get (current-buffer) erc-modified-channels-alist)
+ '(1 . erc-notice-face)))
+
+ ;; Someone speaks, and the mode-line indicator's face changes to
+ ;; that of a buttonized speaker.
+ (funcall set-faces
+ '((erc-button-nick-default-face erc-default-face)
+ (erc-button-nick-default-face erc-nick-default-face)
+ erc-default-face))
+ (erc-track-modified-channels)
+ (should (equal (alist-get (current-buffer) erc-modified-channels-alist)
+ '(2 erc-button-nick-default-face erc-nick-default-face)))
+
+ ;; Someone else speaks, again with a mention and additional body
+ ;; text, but the indicator stays the same.
+ (funcall set-faces
+ '((erc-button-nick-default-face erc-default-face)
+ (erc-button-nick-default-face erc-nick-default-face)
+ erc-default-face))
+ (erc-track-modified-channels)
+ (should (equal (alist-get (current-buffer) erc-modified-channels-alist)
+ '(3 erc-button-nick-default-face erc-nick-default-face)))
+
+ ;; Finally, another notice arrives.
+ (funcall set-faces '(erc-notice-face))
+ (erc-track-modified-channels)
+ (should (equal (alist-get (current-buffer) erc-modified-channels-alist)
+ '(4 . erc-notice-face)))))))
+
+;; Option `erc-track-priority-faces-only' does not affect the behavior
+;; of the baseline "normals" scenario because all faces appear in
+;; `erc-track-faces-priority-list'.
+(ert-deftest erc-track-modified-channels/priority-only-all/baseline ()
+ (let ((erc-track-priority-faces-only 'all))
+ (erc-tests-common-track-modified-channels
+ #'erc-track-tests--modified-channels/baseline)))
+
+;; This test simulates a common configuration that combines an
+;; `erc-track-faces-priority-list' removed of `erc-notice-face' with
+;; `erc-track-priority-faces-only' being `all'. It also features in the
+;; sample configuration in ERC's manual.
+(ert-deftest erc-track-modified-channels/priority-only-all/sans-notice ()
+ (let ((erc-track-priority-faces-only 'all)
+ (erc-track-faces-priority-list
+ (remq 'erc-notice-face erc-track-faces-priority-list)))
+
+ (erc-tests-common-track-modified-channels
+ (lambda (set-faces)
+ ;; Note: these messages don't have timestamps.
+
+ ;; Simulate a message normally displayed in `erc-notice-face',
+ ;; which has been removed from `erc-track-faces-priority-list'.
+ (funcall set-faces '(erc-notice-face))
+ (erc-track-modified-channels)
+ (should-not (alist-get (current-buffer) erc-modified-channels-alist))
+
+ ;; Someone speaks, mentioning someone else, and the mode-line
+ ;; changes to the buttonized speaker face rather than the
+ ;; buttonized mention face, due to their respective ranks.
+ (funcall set-faces
+ '((erc-button-nick-default-face erc-default-face)
+ (erc-button-nick-default-face erc-nick-default-face)
+ erc-default-face))
+ (erc-track-modified-channels)
+ (should (equal (alist-get (current-buffer) erc-modified-channels-alist)
+ '(1 erc-button-nick-default-face erc-nick-default-face)))
+
+ ;; Someone else speaks, again with a mention and additional body text.
+ (funcall set-faces
+ '((erc-button-nick-default-face erc-default-face)
+ (erc-button-nick-default-face erc-nick-default-face)
+ erc-default-face))
+ (erc-track-modified-channels)
+ (should (equal (alist-get (current-buffer) erc-modified-channels-alist)
+ '(2 erc-button-nick-default-face erc-default-face)))
+
+ ;; And yet again, which results in the indicator going back to one.
+ (funcall set-faces
+ '((erc-button-nick-default-face erc-default-face)
+ (erc-button-nick-default-face erc-nick-default-face)
+ erc-default-face))
+ (erc-track-modified-channels)
+ (should (equal (alist-get (current-buffer) erc-modified-channels-alist)
+ '(3 erc-button-nick-default-face erc-nick-default-face)))
+
+ ;; Finally, another notice arrives, which is ignored.
+ (funcall set-faces '(erc-notice-face))
+ (erc-track-modified-channels)
+ (should (equal (alist-get (current-buffer) erc-modified-channels-alist)
+ '(3 erc-button-nick-default-face
+ erc-nick-default-face)))))))
+
;;; erc-track-tests.el ends here
diff --git a/test/lisp/erc/resources/erc-tests-common.el b/test/lisp/erc/resources/erc-tests-common.el
index 1cd54a1f715..91654467dae 100644
--- a/test/lisp/erc/resources/erc-tests-common.el
+++ b/test/lisp/erc/resources/erc-tests-common.el
@@ -330,4 +330,47 @@ interspersing \"-l\" between members."
(set-process-query-on-exit-flag proc t)
proc))
+(declare-function erc-track--setup "erc-track" ())
+
+(defun erc-tests-common-track-modified-channels (test)
+ (erc-tests-common-prep-for-insertion)
+ (setq erc--target (erc--target-from-string "#chan"))
+ (erc-tests-common-track-modified-channels-sans-setup test))
+
+(defun erc-tests-common-track-modified-channels-sans-setup (test)
+ "Provide a fixture for testing `erc-track-modified-channels'.
+Call function TEST with another function that sets the mocked return
+value of `erc-track--collect-faces-in' to the given argument, a list of
+faces in the reverse order they appear in an inserted message."
+ (defvar erc-modified-channels-alist)
+ (defvar erc-modified-channels-object)
+ (defvar erc-track--attn-faces)
+ (defvar erc-track--normal-faces)
+ (defvar erc-track--priority-faces)
+ (defvar erc-track-faces-normal-list)
+ (defvar erc-track-faces-priority-list)
+ (defvar erc-track-mode)
+
+ (cl-letf* ((erc-track-mode t)
+ (erc-modified-channels-alist nil)
+ (erc-modified-channels-object erc-modified-channels-object)
+ (faces ())
+ ((symbol-function 'force-mode-line-update) #'ignore)
+ ((symbol-function 'erc-faces-in) (lambda (_) faces))
+ ((symbol-function 'erc-track--collect-faces-in)
+ (lambda ()
+ (cons (map-into (mapcar (lambda (f) (cons f t)) faces)
+ '(hash-table :test equal))
+ faces))))
+ (erc-track--setup)
+
+ ;; Faces from `erc-track--attn-faces' prepended.
+ (should (= (+ (length erc-track--attn-faces)
+ (length erc-track-faces-priority-list))
+ (hash-table-count erc-track--priority-faces)))
+ (should (= (length erc-track-faces-normal-list)
+ (hash-table-count erc-track--normal-faces)))
+
+ (funcall test (lambda (arg) (setq faces arg)))))
+
(provide 'erc-tests-common)