emacs/test/lisp/erc/erc-nicks-tests.el

839 lines
35 KiB
EmacsLisp

;;; erc-nicks-tests.el --- Tests for erc-nicks -*- lexical-binding:t -*-
;; Copyright (C) 2023-2024 Free Software Foundation, Inc.
;; This file is part of GNU Emacs.
;; GNU Emacs 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.
;; GNU Emacs 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;; Unlike most of ERC's tests, the ones in this file can be run
;; interactively in the same session.
;; TODO:
;;
;; * Add mock session (or scenario) with buffer snapshots, like those
;; in erc-fill-tests.el. (Should probably move helpers to a common
;; library under ./resources.)
;;; Code:
(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
;; upper bounds (0.33 and 0.66) are likewise inherited. See
;; `erc-nicks--invert-classic--dark' below for one reason its results
;; may not be plainly obvious.
(defun erc-nicks-tests--invert-classic (color)
(if (pcase (erc-nicks--bg-mode)
('dark (< (erc-nicks--get-luminance color) (/ 1 3.0)))
('light (> (erc-nicks--get-luminance color) (/ 2 3.0))))
(list (- 1.0 (nth 0 color)) (- 1.0 (nth 1 color)) (- 1.0 (nth 2 color)))
color))
(ert-deftest erc-nicks--get-luminance ()
(should (eql 0.0 (erc-nicks--get-luminance "black")))
(should (eql 1.0 (erc-nicks--get-luminance "white")))
(should (eql 21.0 (/ (+ 0.05 1.0) (+ 0.05 0.0))))
;; RGB floats from a `display-graphic-p' session.
(let ((a (erc-nicks--get-luminance ; #9439ad
'(0.5803921568627451 0.2235294117647059 0.6784313725490196)))
(b (erc-nicks--get-luminance ; #ae54c7
'(0.6823529411764706 0.32941176470588235 0.7803921568627451)))
(c (erc-nicks--get-luminance ; #d19ddf
'(0.8196078431372549 0.615686274509804 0.8745098039215686)))
(d (erc-nicks--get-luminance ; #f5e8f8
'(0.9607843137254902 0.9098039215686274 0.9725490196078431))))
;; Low, med, high contrast comparisons against known values from
;; an external source.
(should (eql 1.42 (/ (round (* 100 (/ (+ 0.05 b) (+ 0.05 a)))) 100.0)))
(should (eql 2.78 (/ (round (* 100 (/ (+ 0.05 c) (+ 0.05 a)))) 100.0)))
(should (eql 5.16 (/ (round (* 100 (/ (+ 0.05 d) (+ 0.05 a)))) 100.0)))))
(ert-deftest erc-nicks-invert--classic ()
(let ((convert (lambda (n) (apply #'color-rgb-to-hex
(erc-nicks-tests--invert-classic
(color-name-to-rgb n))))))
(let ((erc-nicks--bg-mode-value 'dark))
(should (equal (funcall convert "white") "#ffffffffffff"))
(should (equal (funcall convert "black") "#ffffffffffff"))
(should (equal (funcall convert "green") "#0000ffff0000")))
(let ((erc-nicks--bg-mode-value 'light))
(should (equal (funcall convert "white") "#000000000000"))
(should (equal (funcall convert "black") "#000000000000"))
(should (equal (funcall convert "green") "#ffff0000ffff")))))
(ert-deftest erc-nicks--get-contrast ()
(should (= 21.0 (erc-nicks--get-contrast "white" "black")))
(should (= 21.0 (erc-nicks--get-contrast "black" "white")))
(should (= 1.0 (erc-nicks--get-contrast "black" "black")))
(should (= 1.0 (erc-nicks--get-contrast "white" "white"))))
(defun erc-nicks-tests--print-contrast (fn color)
(let* ((erc-nicks-color-adjustments (list fn))
(result (erc-nicks--reduce color))
(start (point)))
(insert (format "%16s%-16s%16s%-16s\n"
(concat color "-")
(concat ">" result)
(concat color " ")
(concat " " result)))
(put-text-property (+ start 32) (+ start 48) 'face
(list :background color :foreground result))
(put-text-property (+ start 48) (+ start 64) 'face
(list :background result :foreground color))
result))
(ert-deftest erc-nicks--invert-classic--light ()
(let ((erc-nicks--bg-luminance 1.0)
(erc-nicks--bg-mode-value 'light)
(show (lambda (c) (erc-nicks-tests--print-contrast
#'erc-nicks-tests--invert-classic c))))
(with-current-buffer (get-buffer-create
"*erc-nicks--invert-classic--light*")
(should (equal "#000000000000" (funcall show "white")))
(should (equal "#000000000000" (funcall show "black")))
(should (equal "#ffff00000000" (funcall show "red")))
(should (equal "#ffff0000ffff" (funcall show "green"))) ; magenta
(should (equal "#00000000ffff" (funcall show "blue")))
(unless noninteractive
(should (equal "#bbbbbbbbbbbb" (funcall show "#bbbbbbbbbbbb")))
(should (equal "#cccccccccccc" (funcall show "#cccccccccccc")))
(should (equal "#222122212221" (funcall show "#dddddddddddd")))
(should (equal "#111011101110" (funcall show "#eeeeeeeeeeee"))))
(when noninteractive
(kill-buffer)))))
;; This shows that the output can be darker (have less contrast) than
;; the input.
(ert-deftest erc-nicks--invert-classic--dark ()
(let ((erc-nicks--bg-luminance 0.0)
(erc-nicks--bg-mode-value 'dark)
(show (lambda (c) (erc-nicks-tests--print-contrast
#'erc-nicks-tests--invert-classic c))))
(with-current-buffer (get-buffer-create
"*erc-nicks--invert-classic--dark*")
(should (equal "#ffffffffffff" (funcall show "white")))
(should (equal "#ffffffffffff" (funcall show "black")))
(should (equal "#0000ffffffff" (funcall show "red"))) ; cyan
(should (equal "#0000ffff0000" (funcall show "green")))
(should (equal "#ffffffff0000" (funcall show "blue"))) ; yellow
(unless noninteractive
(should (equal "#aaaaaaaaaaaa" (funcall show "#555555555555")))
(should (equal "#999999999999" (funcall show "#666666666666")))
(should (equal "#888888888888" (funcall show "#777777777777")))
(should (equal "#777777777777" (funcall show "#888888888888")))
(should (equal "#666666666666" (funcall show "#999999999999")))
(should (equal "#aaaaaaaaaaaa" (funcall show "#aaaaaaaaaaaa"))))
(when noninteractive
(kill-buffer)))))
;; These are the same as the legacy version but work in terms of
;; contrast ratios. Converting the original bounds to contrast ratios
;; (assuming pure white and black backgrounds) gives:
;;
;; min-lum of 0.33 ~~> 1.465
;; max-lum of 0.66 ~~> 7.666
;;
(ert-deftest erc-nicks-invert--light ()
(let ((erc-nicks--bg-luminance 1.0)
(erc-nicks--bg-mode-value 'light)
(erc-nicks-contrast-range '(1.465))
(show (lambda (c) (erc-nicks-tests--print-contrast
#'erc-nicks-invert c))))
(with-current-buffer (get-buffer-create
"*erc-nicks--invert-classic--light*")
(should (equal "#000000000000" (funcall show "white")))
(should (equal "#000000000000" (funcall show "black")))
(should (equal "#ffff00000000" (funcall show "red")))
(should (equal "#ffff0000ffff" (funcall show "green"))) ; magenta
(should (equal "#00000000ffff" (funcall show "blue")))
(unless noninteractive
(should (equal "#bbbbbbbbbbbb" (funcall show "#bbbbbbbbbbbb")))
(should (equal "#cccccccccccc" (funcall show "#cccccccccccc")))
(should (equal "#222122212221" (funcall show "#dddddddddddd")))
(should (equal "#111011101110" (funcall show "#eeeeeeeeeeee"))))
(when noninteractive
(kill-buffer)))))
(ert-deftest erc-nicks-invert--dark ()
(let ((erc-nicks--bg-luminance 0.0)
(erc-nicks--bg-mode-value 'dark)
(erc-nicks-contrast-range '(7.666))
(show (lambda (c) (erc-nicks-tests--print-contrast
#'erc-nicks-invert c))))
(with-current-buffer (get-buffer-create "*erc-nicks-invert--dark*")
(should (equal "#ffffffffffff" (funcall show "white")))
(should (equal "#ffffffffffff" (funcall show "black")))
(should (equal "#0000ffffffff" (funcall show "red"))) ; cyan
(should (equal "#0000ffff0000" (funcall show "green")))
(should (equal "#ffffffff0000" (funcall show "blue"))) ; yellow
(unless noninteractive
(should (equal "#aaaaaaaaaaaa" (funcall show "#555555555555")))
(should (equal "#999999999999" (funcall show "#666666666666")))
(should (equal "#888888888888" (funcall show "#777777777777")))
(should (equal "#888888888888" (funcall show "#888888888888")))
(should (equal "#999999999999" (funcall show "#999999999999"))))
(when noninteractive
(kill-buffer)))))
(ert-deftest erc-nicks-add-contrast ()
(let ((erc-nicks--bg-luminance 1.0)
(erc-nicks--bg-mode-value 'light)
(erc-nicks--fg-rgb '(0.0 0.0 0.0))
(erc-nicks-bg-color "white")
(erc-nicks-contrast-range '(3.5))
(show (lambda (c) (erc-nicks-tests--print-contrast
#'erc-nicks-add-contrast c))))
(with-current-buffer (get-buffer-create "*erc-nicks-add-contrast*")
(should (equal "#893a893a893a" (funcall show "white")))
(should (equal "#893a893a893a" (funcall show "#893a893a893a")))
(should (equal "#000000000000" (funcall show "black")))
(should (equal "#ffff00000000" (funcall show "red")))
(should (equal "#0000a12e0000" (funcall show "green")))
(should (equal "#00000000ffff" (funcall show "blue")))
;; When the input is already near the desired ratio, the result
;; may not be in bounds, only close. But the difference is
;; usually imperceptible.
(unless noninteractive
;; Well inside (light slate gray)
(should (equal "#777788889999" (funcall show "#777788889999")))
;; Slightly outside -> just outside
(should (equal "#7c498bd39b5c" (funcall show "#88889999aaaa")))
;; Just outside -> just inside
(should (equal "#7bcc8b479ac0" (funcall show "#7c498bd39b5c")))
;; Just inside
(should (equal "#7bcc8b479ac0" (funcall show "#7bcc8b479ac0"))))
(when noninteractive
(kill-buffer)))))
(ert-deftest erc-nicks-cap-contrast ()
(should (= 12.5 (cdr erc-nicks-contrast-range)))
(let ((erc-nicks--bg-luminance 1.0)
(erc-nicks--bg-mode-value 'light)
(erc-nicks--fg-rgb '(0.0 0.0 0.0))
(erc-nicks-bg-color "white")
(show (lambda (c) (erc-nicks-tests--print-contrast
#'erc-nicks-cap-contrast c))))
(with-current-buffer (get-buffer-create "*erc-nicks-remove-contrast*")
(should (equal (funcall show "black") "#34e534e534e5" )) ; 21.0 -> 12.14
(should ; 12.32 -> 12.32 (same)
(equal (funcall show "#34e534e534e5") "#34e534e534e5"))
(should (equal (funcall show "white") "#ffffffffffff"))
(unless noninteractive
(should (equal (funcall show "DarkRed") "#8b8b00000000"))
(should (equal (funcall show "DarkGreen") "#000064640000"))
;; 15.29 -> 12.38
(should (equal (funcall show "DarkBlue") "#1cf11cf198b5"))
;; 12.50 -> 12.22
(should (equal (funcall show "#33e033e033e0") "#34ab34ab34ab"))
;; 12.57 -> 12.28
(should (equal (funcall show "#338033803380") "#344c344c344c"))
;; 12.67 -> 12.37
(should (equal (funcall show "#330033003300") "#33cc33cc33cc")))
(when noninteractive
(kill-buffer)))))
(ert-deftest erc-nicks--skip-p ()
;; Baseline
(should-not (erc-nicks--skip-p 'bold nil 10000000))
(should-not (erc-nicks--skip-p '(bold) nil 10000000))
(should-not (erc-nicks--skip-p nil '(bold) 10000000))
(should-not (erc-nicks--skip-p 'bold '(bold) 0))
(should-not (erc-nicks--skip-p '(bold) '(bold) 0))
(should-not (erc-nicks--skip-p 'bold '(foo bold) 0))
(should-not (erc-nicks--skip-p '((:inherit bold)) '(bold) 1))
(should (erc-nicks--skip-p 'bold '(bold) 1))
(should (erc-nicks--skip-p 'bold '(fake bold) 1))
(should (erc-nicks--skip-p 'bold '(foo bar bold) 1))
(should (erc-nicks--skip-p '(bold) '(bold) 1))
(should (erc-nicks--skip-p '((bold)) '(bold) 1))
(should (erc-nicks--skip-p '((((bold)))) '(bold) 1))
(should (erc-nicks--skip-p '(bold) '(foo bold) 1))
(should (erc-nicks--skip-p '(:inherit bold) '((:inherit bold)) 1))
(should (erc-nicks--skip-p '((:inherit bold)) '((:inherit bold)) 1))
(should (erc-nicks--skip-p '(((:inherit bold))) '((:inherit bold)) 1))
;; Composed
(should-not (erc-nicks--skip-p '(italic bold) '(bold) 1))
(should-not (erc-nicks--skip-p '((italic) bold) '(bold) 1))
(should-not (erc-nicks--skip-p '(italic (bold)) '(bold) 1))
(should (erc-nicks--skip-p '(italic bold) '(bold) 2))
(should (erc-nicks--skip-p '((italic) bold) '(bold) 2))
(should (erc-nicks--skip-p '(italic (bold)) '(bold) 2))
(should-not (erc-nicks--skip-p '(italic default bold) '(bold) 2))
(should-not (erc-nicks--skip-p '((default italic) bold) '(bold) 2))
(should-not (erc-nicks--skip-p '(italic (default bold)) '(bold) 2))
(should-not (erc-nicks--skip-p '((default italic) (bold shadow)) '(bold) 2))
(should (erc-nicks--skip-p '((default italic) bold) '(bold) 3))
(should (erc-nicks--skip-p '(italic (default bold)) '(bold) 3))
(should (erc-nicks--skip-p '((default italic) (bold shadow)) '(bold) 3))
(should (erc-nicks--skip-p '(italic (default (bold shadow))) '(bold) 3)))
(ert-deftest erc-nicks--trim ()
(should (equal (erc-nicks--trim "Bob`") "bob"))
(should (equal (erc-nicks--trim "Bob``") "bob"))
;; `erc--casemapping-rfc1459'
(let ((erc-nicks-ignore-chars "^"))
(should (equal (erc-nicks--trim "Bob~") "bob^"))
(should (equal (erc-nicks--trim "Bob^") "bob"))))
(defvar erc-nicks-tests--fake-face-list nil)
;; Since we can't delete faces, mock `face-list' to only return those
;; in `erc-nicks--face-table' created by the current test.
(defun erc-nicks-tests--face-list ()
(let ((table (buffer-local-value 'erc-nicks--face-table
(get-buffer "foonet")))
out)
(maphash (lambda (k v)
(when (member k erc-nicks-tests--fake-face-list)
(push v out)))
table)
(nreverse out)))
(defun erc-nicks-tests--create-session (test alice bob)
(should-not (memq 'nicks erc-modules))
(advice-add 'face-list :override #'erc-nicks-tests--face-list)
(let ((erc-modules (cons 'nicks erc-modules))
(inhibit-message noninteractive)
(erc-nicks-tests--fake-face-list
(list (downcase alice) (downcase bob)))
erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook)
(with-current-buffer
(cl-letf
(((symbol-function 'erc-server-connect)
(lambda (&rest _)
(setq erc-server-process
(start-process "sleep" (current-buffer) "sleep" "1"))
(set-process-query-on-exit-flag erc-server-process nil))))
(erc-open "localhost" 6667 "tester" "Tester" 'connect
nil nil nil nil nil "tester"))
(let ((inhibit-message noninteractive))
(dolist (line (split-string "\
:irc.foonet.org 004 tester irc.foonet.org irc.d abc 123 456
:irc.foonet.org 005 tester NETWORK=foonet :are supported
:irc.foonet.org 376 tester :End of /MOTD command."
"\n"))
(erc-parse-server-response erc-server-process line)))
(with-current-buffer (erc--open-target "#chan")
(erc-update-channel-member
"#chan" alice alice t nil nil nil nil nil "fake" "~u" nil nil t)
(erc-update-channel-member
"#chan" bob bob t nil nil nil nil nil "fake" "~u" nil nil t)
(erc-display-message
nil 'notice (current-buffer)
(concat "This server is in debug mode and is logging all user I/O. "
"Blah " alice " (1) " bob " (2) blah."))
(erc-display-message nil nil (current-buffer)
(erc-format-privmessage bob "Hi Alice" nil t))
(erc-display-message nil nil (current-buffer)
(erc-format-privmessage alice "Hi Bob" nil t)))
(funcall test)
(when noninteractive
(kill-buffer "#chan")
(when (get-buffer " *Custom-Work*")
(kill-buffer " *Custom-Work*"))
(kill-buffer))))
(advice-remove 'face-list #'erc-nicks-tests--face-list))
(ert-deftest erc-nicks-list-faces ()
(erc-nicks-tests--create-session
(lambda ()
(erc-nicks-list-faces)
(let ((table (buffer-local-value 'erc-nicks--face-table
(get-buffer "foonet")))
calls)
(cl-letf (((symbol-function 'erc-nicks--list-faces-help-button-action)
(lambda (&rest r) (push r calls))))
(with-current-buffer "*Faces*"
(set-window-buffer (selected-window) (current-buffer))
(goto-char (point-min))
(ert-info ("Clicking on face link runs action function")
(forward-button 1)
(should (looking-at "erc-nicks-alice1-face"))
(push-button)
(should (eq (car (car calls)) (gethash "alice1" table))))
(ert-info ("Clicking on sample text describes face")
(forward-button 1)
(should (looking-at (rx "#" (+ xdigit))))
(push-button)
(should (search-forward-regexp
(rx "Foreground: #" (group (+ xdigit)) eol)))
(forward-button 2) ; skip Inherit:...
(push-button))
(ert-info ("First entry's sample is rendered correctly")
(let ((hex (match-string 1)))
(should (looking-at (concat "#" hex)))
(goto-char (button-end (point)))
(should (looking-back " foonet"))
(should (eq (button-get (1- (point)) 'face) (car (pop calls))))
(should-not calls)))
(ert-info ("Clicking on another entry's face link runs action")
(forward-button 1)
(should (looking-at "erc-nicks-bob1-face"))
(push-button)
(should (eq (car (car calls)) (gethash "bob1" table))))
(ert-info ("Second entry's sample is rendered correctly")
(forward-button 1)
(should (looking-at (rx "#" (+ xdigit))))
(goto-char (button-end (point)))
(should (looking-back " foonet"))
(should (eq (button-get (1- (point)) 'face) (car (pop calls))))
(should-not calls))
(when noninteractive
(kill-buffer))))))
"Alice1" "Bob1"))
(ert-deftest erc-nicks-customize-face ()
(unless (>= emacs-major-version 28)
(ert-skip "Face link required in customize-face buffers"))
(erc-nicks-tests--create-session
(lambda ()
(erc-nicks-list-faces)
(with-current-buffer "*Faces*"
(set-window-buffer (selected-window) (current-buffer))
(goto-char (point-min))
(ert-info ("Clicking on face link runs action function")
(forward-button 1)
(should (looking-at "erc-nicks-alice2"))
(ert-simulate-keys "y\r"
(call-interactively #'push-button nil)))
(with-current-buffer "*Customize Face: Erc Nicks Alice2@Foonet Face*"
(should (search-forward "Erc Nicks Alice2@Foonet Face" nil t))
(widget-button-press (1- (point))))
(with-current-buffer "*New face erc-nicks-alice2@foonet-face*"
(goto-char (point-min))
(should (search-forward "(use-package erc-nicks" nil t))
(should (search-forward ":foreground \"#" nil t))
(when noninteractive
(kill-buffer)))
(with-current-buffer "*Customize Face: Erc Nicks Alice2@Foonet Face*"
(should (search-forward "Foreground: #" nil t))
(when noninteractive
(kill-buffer)))
(when noninteractive
(kill-buffer))))
"Alice2" "Bob2"))
(ert-deftest erc-nicks--gen-key-from-format-spec ()
(let ((erc-network 'OFTC)
(erc-nicks-key-suffix-format "@%-012n")
(erc-server-current-nick "tester"))
(should (equal (erc-nicks--gen-key-from-format-spec "bob")
"bob@OFTC00000000")))
(let ((erc-network 'Libera.Chat)
(erc-nicks-key-suffix-format "@%-012n")
(erc-server-current-nick "tester"))
(should (equal (erc-nicks--gen-key-from-format-spec "bob")
"bob@Libera.Chat0")))
(let* ((erc-network 'Libera.Chat)
(erc-nicks-key-suffix-format "@%n/%m")
(erc-server-current-nick "tester"))
(should (equal (erc-nicks--gen-key-from-format-spec "bob")
"bob@Libera.Chat/tester"))))
(ert-deftest erc-nicks--create-culled-pool ()
(let ((erc-nicks--bg-luminance 1.0)
(erc-nicks--bg-mode-value 'light)
(erc-nicks--fg-rgb '(0.0 0.0 0.0))
(erc-nicks-bg-color "white")
;;
(erc-nicks--colors-rejects '(t)))
;; Reject
(should-not (erc-nicks--create-culled-pool '(erc-nicks-invert) '("white")))
(should (equal (pop erc-nicks--colors-rejects) "white")) ; too close
(should-not
(erc-nicks--create-culled-pool '(erc-nicks-cap-contrast) '("black")))
(should (equal (pop erc-nicks--colors-rejects) "black")) ; too far
(should-not
(erc-nicks--create-culled-pool '(erc-nicks-ensaturate) '("white")))
(should (equal (pop erc-nicks--colors-rejects) "white")) ; lacks color
(should-not
(erc-nicks--create-culled-pool '(erc-nicks-ensaturate) '("red")))
(should (equal (pop erc-nicks--colors-rejects) "red")) ; too much color
;; Safe
(should (equal (erc-nicks--create-culled-pool '(erc-nicks-invert)
'("black"))
'("black")))
(should (equal (erc-nicks--create-culled-pool '(erc-nicks-add-contrast)
'("black"))
'("black")))
(should (equal (erc-nicks--create-culled-pool '(erc-nicks-cap-contrast)
'("white"))
'("white")))
(let ((erc-nicks-saturation-range '(0.5 . 1.0)))
(should (equal (erc-nicks--create-culled-pool '(erc-nicks-ensaturate)
'("green"))
'("green"))))
(let ((erc-nicks-saturation-range '(0.0 . 0.5)))
(should (equal (erc-nicks--create-culled-pool '(erc-nicks-ensaturate)
'("gray"))
'("gray"))))
(unless noninteractive
(should (equal (erc-nicks--create-culled-pool '(erc-nicks-ensaturate)
'("firebrick"))
'("firebrick"))))
(should (equal erc-nicks--colors-rejects '(t)))))
(ert-deftest erc-nicks--create-coerced-pool ()
(let ((erc-nicks--bg-luminance 1.0)
(erc-nicks--bg-mode-value 'light)
(erc-nicks--fg-rgb '(0.0 0.0 0.0))
(erc-nicks-bg-color "white")
(num-colors (length (defined-colors)))
;;
(erc-nicks--colors-rejects '(t)))
;; Deduplication.
(when (= 8 num-colors)
(should (equal (erc-nicks--create-coerced-pool '(erc-nicks-ensaturate)
'("#ee0000" "#f80000"))
'("red")))
(should (equal (pop erc-nicks--colors-rejects) "#f80000")))
;; "Coercion" in Xterm.
(unless noninteractive
(when (= 665 num-colors)
(pcase-dolist (`(,adjustments ,candidates ,result)
'(((erc-nicks-invert) ("white") ("gray10"))
((erc-nicks-cap-contrast) ("black") ("gray20"))
((erc-nicks-ensaturate) ("white") ("lavenderblush2"))
((erc-nicks-ensaturate) ("red") ("firebrick"))))
(should (equal (erc-nicks--create-coerced-pool adjustments
candidates)
result)))))
(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