summaryrefslogtreecommitdiff
path: root/test/lisp/erc/erc-tests.el
diff options
context:
space:
mode:
Diffstat (limited to 'test/lisp/erc/erc-tests.el')
-rw-r--r--test/lisp/erc/erc-tests.el681
1 files changed, 673 insertions, 8 deletions
diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el
index 60b3da2317f..4971d0e194f 100644
--- a/test/lisp/erc/erc-tests.el
+++ b/test/lisp/erc/erc-tests.el
@@ -21,7 +21,7 @@
;;; Code:
-(require 'ert)
+(require 'ert-x)
(require 'erc)
(require 'erc-ring)
(require 'erc-networks)
@@ -48,6 +48,27 @@
(cl-letf (((symbol-function 'read-string) (lambda (&rest _) "1d")))
(should (equal (erc--read-time-period "foo: ") 86400))))
+(ert-deftest erc--meta--backend-dependencies ()
+ (with-temp-buffer
+ (insert-file-contents-literally
+ (concat (file-name-sans-extension (symbol-file 'erc)) ".el"))
+ (let ((beg (search-forward ";; Defined in erc-backend"))
+ (end (search-forward "\n\n"))
+ vars)
+ (save-excursion
+ (save-restriction
+ (narrow-to-region beg end)
+ (goto-char (point-min))
+ (with-syntax-table lisp-data-mode-syntax-table
+ (condition-case _
+ (while (push (cadr (read (current-buffer))) vars))
+ (end-of-file)))))
+ (should (= (point) end))
+ (dolist (var vars)
+ (setq var (concat "\\_<" (symbol-name var) "\\_>"))
+ (ert-info (var)
+ (should (save-excursion (search-forward-regexp var nil t))))))))
+
(ert-deftest erc-with-all-buffers-of-server ()
(let (proc-exnet
proc-onet
@@ -114,6 +135,207 @@
(should (get-buffer "#spam"))
(kill-buffer "#spam")))
+(defun erc-tests--send-prep ()
+ ;; Caller should probably shadow `erc-insert-modify-hook' or
+ ;; populate user tables for erc-button.
+ (erc-mode)
+ (insert "\n\n")
+ (setq erc-input-marker (make-marker)
+ erc-insert-marker (make-marker))
+ (set-marker erc-insert-marker (point-max))
+ (erc-display-prompt)
+ (should (= (point) erc-input-marker)))
+
+(defun erc-tests--set-fake-server-process (&rest args)
+ (setq erc-server-process
+ (apply #'start-process (car args) (current-buffer) args))
+ (set-process-query-on-exit-flag erc-server-process nil))
+
+(ert-deftest erc-hide-prompt ()
+ (let (erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook)
+
+ (with-current-buffer (get-buffer-create "ServNet")
+ (erc-tests--send-prep)
+ (goto-char erc-insert-marker)
+ (should (looking-at-p (regexp-quote erc-prompt)))
+ (erc-tests--set-fake-server-process "sleep" "1")
+ (set-process-sentinel erc-server-process #'ignore)
+ (setq erc-network 'ServNet)
+ (set-process-query-on-exit-flag erc-server-process nil))
+
+ (with-current-buffer (get-buffer-create "#chan")
+ (erc-tests--send-prep)
+ (goto-char erc-insert-marker)
+ (should (looking-at-p (regexp-quote erc-prompt)))
+ (setq erc-server-process (buffer-local-value 'erc-server-process
+ (get-buffer "ServNet"))
+ erc-default-recipients '("#chan")))
+
+ (with-current-buffer (get-buffer-create "bob")
+ (erc-tests--send-prep)
+ (goto-char erc-insert-marker)
+ (should (looking-at-p (regexp-quote erc-prompt)))
+ (setq erc-server-process (buffer-local-value 'erc-server-process
+ (get-buffer "ServNet"))
+ erc-default-recipients '("bob")))
+
+ (ert-info ("Value: t (default)")
+ (should (eq erc-hide-prompt t))
+ (with-current-buffer "ServNet"
+ (should (= (point) erc-insert-marker))
+ (erc--hide-prompt erc-server-process)
+ (should (string= ">" (get-text-property (point) 'display))))
+
+ (with-current-buffer "#chan"
+ (goto-char erc-insert-marker)
+ (should (string= ">" (get-text-property (point) 'display)))
+ (should (memq #'erc--unhide-prompt-on-self-insert pre-command-hook))
+ (goto-char erc-input-marker)
+ (ert-simulate-command '(self-insert-command 1 ?/))
+ (goto-char erc-insert-marker)
+ (should-not (get-text-property (point) 'display))
+ (should-not (memq #'erc--unhide-prompt-on-self-insert
+ pre-command-hook)))
+
+ (with-current-buffer "bob"
+ (goto-char erc-insert-marker)
+ (should (string= ">" (get-text-property (point) 'display)))
+ (should (memq #'erc--unhide-prompt-on-self-insert pre-command-hook))
+ (goto-char erc-input-marker)
+ (ert-simulate-command '(self-insert-command 1 ?/))
+ (goto-char erc-insert-marker)
+ (should-not (get-text-property (point) 'display))
+ (should-not (memq #'erc--unhide-prompt-on-self-insert
+ pre-command-hook)))
+
+ (with-current-buffer "ServNet"
+ (should (get-text-property erc-insert-marker 'display))
+ (should (memq #'erc--unhide-prompt-on-self-insert pre-command-hook))
+ (erc--unhide-prompt)
+ (should-not (memq #'erc--unhide-prompt-on-self-insert
+ pre-command-hook))
+ (should-not (get-text-property erc-insert-marker 'display))))
+
+ (ert-info ("Value: server")
+ (setq erc-hide-prompt '(server))
+ (with-current-buffer "ServNet"
+ (erc--hide-prompt erc-server-process)
+ (should (string= ">" (get-text-property erc-insert-marker 'display))))
+
+ (with-current-buffer "#chan"
+ (should-not (get-text-property erc-insert-marker 'display)))
+
+ (with-current-buffer "bob"
+ (should-not (get-text-property erc-insert-marker 'display)))
+
+ (with-current-buffer "ServNet"
+ (erc--unhide-prompt)
+ (should-not (get-text-property erc-insert-marker 'display))))
+
+ (ert-info ("Value: channel")
+ (setq erc-hide-prompt '(channel))
+ (with-current-buffer "ServNet"
+ (erc--hide-prompt erc-server-process)
+ (should-not (get-text-property erc-insert-marker 'display)))
+
+ (with-current-buffer "bob"
+ (should-not (get-text-property erc-insert-marker 'display)))
+
+ (with-current-buffer "#chan"
+ (should (string= ">" (get-text-property erc-insert-marker 'display)))
+ (erc--unhide-prompt)
+ (should-not (get-text-property erc-insert-marker 'display))))
+
+ (ert-info ("Value: query")
+ (setq erc-hide-prompt '(query))
+ (with-current-buffer "ServNet"
+ (erc--hide-prompt erc-server-process)
+ (should-not (get-text-property erc-insert-marker 'display)))
+
+ (with-current-buffer "bob"
+ (should (string= ">" (get-text-property erc-insert-marker 'display)))
+ (erc--unhide-prompt)
+ (should-not (get-text-property erc-insert-marker 'display)))
+
+ (with-current-buffer "#chan"
+ (should-not (get-text-property erc-insert-marker 'display))))
+
+ (ert-info ("Value: nil")
+ (setq erc-hide-prompt nil)
+ (with-current-buffer "ServNet"
+ (erc--hide-prompt erc-server-process)
+ (should-not (get-text-property erc-insert-marker 'display)))
+
+ (with-current-buffer "bob"
+ (should-not (get-text-property erc-insert-marker 'display)))
+
+ (with-current-buffer "#chan"
+ (should-not (get-text-property erc-insert-marker 'display))
+ (erc--unhide-prompt) ; won't blow up when prompt already showing
+ (should-not (get-text-property erc-insert-marker 'display))))
+
+ (when noninteractive
+ (kill-buffer "#chan")
+ (kill-buffer "bob")
+ (kill-buffer "ServNet"))))
+
+(ert-deftest erc--switch-to-buffer ()
+ (defvar erc-modified-channels-alist) ; lisp/erc/erc-track.el
+
+ (let ((proc (start-process "aNet" (current-buffer) "true"))
+ (erc-modified-channels-alist `(("fake") (,(messages-buffer))))
+ (inhibit-message noninteractive)
+ (completion-fail-discreetly t) ; otherwise ^G^G printed to .log file
+ ;;
+ erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook)
+
+ (with-current-buffer (get-buffer-create "server")
+ (erc-mode)
+ (set-process-buffer (setq erc-server-process proc) (current-buffer))
+ (set-process-query-on-exit-flag erc-server-process nil)
+ (with-current-buffer (get-buffer-create "#chan")
+ (erc-mode)
+ (setq erc-server-process proc))
+ (with-current-buffer (get-buffer-create "#foo")
+ (erc-mode)
+ (setq erc-server-process proc))
+
+ (ert-info ("Channel #chan selectable from server buffer")
+ (ert-simulate-keys (list ?# ?c ?h ?a ?n ?\C-m)
+ (should (string= "#chan" (erc--switch-to-buffer))))))
+
+ (ert-info ("Channel #foo selectable from non-ERC buffer")
+ (ert-simulate-keys (list ?# ?f ?o ?o ?\C-m)
+ (should (string= "#foo" (erc--switch-to-buffer)))))
+
+ (ert-info ("Default selectable")
+ (ert-simulate-keys (list ?\C-m)
+ (should (string= "*Messages*" (erc--switch-to-buffer)))))
+
+ (ert-info ("Extant but non-ERC buffer not selectable")
+ (get-buffer-create "#fake") ; not ours
+ (ert-simulate-keys (kbd "#fake C-m C-a C-k C-m")
+ ;; Initial query fails ~~~~~~^; clearing input accepts default
+ (should (string= "*Messages*" (erc--switch-to-buffer)))))
+
+ (with-current-buffer (get-buffer-create "other")
+ (erc-mode)
+ (setq erc-server-process (start-process "bNet" (current-buffer) "true"))
+ (set-process-query-on-exit-flag erc-server-process nil))
+
+ (ert-info ("Foreign ERC buffer not selectable")
+ (ert-simulate-keys (kbd "other C-m C-a C-k C-m")
+ (with-current-buffer "server"
+ (should (string= "*Messages*" (erc--switch-to-buffer))))))
+
+ (ert-info ("Any ERC-buffer selectable from non-ERC buffer")
+ (should-not (eq major-mode 'erc-mode))
+ (ert-simulate-keys (list ?o ?t ?h ?e ?r ?\C-m)
+ (should (string= "other" (erc--switch-to-buffer)))))
+
+ (dolist (b '("server" "other" "#chan" "#foo" "#fake"))
+ (kill-buffer b))))
+
(ert-deftest erc-lurker-maybe-trim ()
(let (erc-lurker-trim-nicks
(erc-lurker-ignore-chars "_`"))
@@ -127,6 +349,147 @@
(setq erc-lurker-ignore-chars "_-`") ; set of chars, not character alts
(should (string= "nick" (erc-lurker-maybe-trim "nick-_`")))))
+(ert-deftest erc--parse-isupport-value ()
+ (should (equal (erc--parse-isupport-value "a,b") '("a" "b")))
+ (should (equal (erc--parse-isupport-value "a,b,c") '("a" "b" "c")))
+
+ (should (equal (erc--parse-isupport-value "abc") '("abc")))
+ (should (equal (erc--parse-isupport-value "\\x20foo") '(" foo")))
+ (should (equal (erc--parse-isupport-value "foo\\x20") '("foo ")))
+ (should (equal (erc--parse-isupport-value "a\\x20b\\x20c") '("a b c")))
+ (should (equal (erc--parse-isupport-value "a\\x20b\\x20c\\x20") '("a b c ")))
+ (should (equal (erc--parse-isupport-value "\\x20a\\x20b\\x20c") '(" a b c")))
+ (should (equal (erc--parse-isupport-value "a\\x20\\x20c") '("a c")))
+ (should (equal (erc--parse-isupport-value "\\x20\\x20\\x20") '(" ")))
+ (should (equal (erc--parse-isupport-value "\\x5Co/") '("\\o/")))
+ (should (equal (erc--parse-isupport-value "\\x7F,\\x19") '("\\x7F" "\\x19")))
+ (should (equal (erc--parse-isupport-value "a\\x2Cb,c") '("a,b" "c"))))
+
+(ert-deftest erc--get-isupport-entry ()
+ (let ((erc--isupport-params (make-hash-table))
+ (erc-server-parameters '(("FOO" . "1") ("BAR") ("BAZ" . "A,B,C")))
+ (items (lambda ()
+ (cl-loop for k being the hash-keys of erc--isupport-params
+ using (hash-values v) collect (cons k v)))))
+
+ (should-not (erc--get-isupport-entry 'FAKE))
+ (should-not (erc--get-isupport-entry 'FAKE 'single))
+ (should (zerop (hash-table-count erc--isupport-params)))
+
+ (should (equal (erc--get-isupport-entry 'BAR) '(BAR)))
+ (should-not (erc--get-isupport-entry 'BAR 'single))
+ (should (= 1 (hash-table-count erc--isupport-params)))
+
+ (should (equal (erc--get-isupport-entry 'BAZ) '(BAZ "A" "B" "C")))
+ (should (equal (erc--get-isupport-entry 'BAZ 'single) "A"))
+ (should (= 2 (hash-table-count erc--isupport-params)))
+
+ (should (equal (erc--get-isupport-entry 'FOO 'single) "1"))
+ (should (equal (erc--get-isupport-entry 'FOO) '(FOO "1")))
+
+ (should (equal (funcall items)
+ '((BAR . --empty--) (BAZ "A" "B" "C") (FOO "1"))))))
+
+(ert-deftest erc-server-005 ()
+ (let* ((hooked 0)
+ (verify #'ignore)
+ (hook (lambda (_ _) (funcall verify) (cl-incf hooked)))
+ (erc-server-005-functions (list #'erc-server-005 hook #'ignore))
+ erc-server-parameters
+ erc--isupport-params
+ erc-timer-hook
+ calls
+ args
+ parsed)
+
+ (cl-letf (((symbol-function 'erc-display-message)
+ (lambda (_ _ _ line) (push line calls))))
+
+ (ert-info ("Baseline")
+ (setq args '("tester" "BOT=B" "EXCEPTS" "PREFIX=(ov)@+" "are supp...")
+ parsed (make-erc-response :command-args args :command "005"))
+
+ (setq verify
+ (lambda ()
+ (should (equal erc-server-parameters
+ '(("PREFIX" . "(ov)@+") ("EXCEPTS")
+ ("BOT" . "B"))))
+ (should (zerop (hash-table-count erc--isupport-params)))
+ (should (equal "(ov)@+" (erc--get-isupport-entry 'PREFIX t)))
+ (should (equal '(EXCEPTS) (erc--get-isupport-entry 'EXCEPTS)))
+ (should (equal "B" (erc--get-isupport-entry 'BOT t)))
+ (should (string= (pop calls)
+ "BOT=B EXCEPTS PREFIX=(ov)@+ are supp..."))
+ (should (equal args (erc-response.command-args parsed)))))
+
+ (erc-call-hooks nil parsed))
+
+ (ert-info ("Negated, updated")
+ (setq args '("tester" "-EXCEPTS" "-FAKE" "PREFIX=(ohv)@%+" "are su...")
+ parsed (make-erc-response :command-args args :command "005"))
+
+ (setq verify
+ (lambda ()
+ (should (equal erc-server-parameters
+ '(("PREFIX" . "(ohv)@%+") ("BOT" . "B"))))
+ (should (string= (pop calls)
+ "-EXCEPTS -FAKE PREFIX=(ohv)@%+ are su..."))
+ (should (equal "(ohv)@%+" (erc--get-isupport-entry 'PREFIX t)))
+ (should (equal "B" (erc--get-isupport-entry 'BOT t)))
+ (should-not (erc--get-isupport-entry 'EXCEPTS))
+ (should (equal args (erc-response.command-args parsed)))))
+
+ (erc-call-hooks nil parsed))
+ (should (= hooked 2)))))
+
+(ert-deftest erc-downcase ()
+ (let ((erc--isupport-params (make-hash-table)))
+
+ (puthash 'PREFIX '("(ov)@+") erc--isupport-params)
+ (puthash 'BOT '("B") erc--isupport-params)
+
+ (ert-info ("ascii")
+ (puthash 'CASEMAPPING '("ascii") erc--isupport-params)
+ (should (equal (erc-downcase "Bob[m]`") "bob[m]`"))
+ (should (equal (erc-downcase "Tilde~") "tilde~" ))
+ (should (equal (erc-downcase "\\O/") "\\o/" )))
+
+ (ert-info ("rfc1459")
+ (puthash 'CASEMAPPING '("rfc1459") erc--isupport-params)
+ (should (equal (erc-downcase "Bob[m]`") "bob{m}`" ))
+ (should (equal (erc-downcase "Tilde~") "tilde^" ))
+ (should (equal (erc-downcase "\\O/") "|o/" )))
+
+ (ert-info ("rfc1459-strict")
+ (puthash 'CASEMAPPING '("rfc1459-strict") erc--isupport-params)
+ (should (equal (erc-downcase "Bob[m]`") "bob{m}`"))
+ (should (equal (erc-downcase "Tilde~") "tilde~" ))
+ (should (equal (erc-downcase "\\O/") "|o/" )))))
+
+(ert-deftest erc--valid-local-channel-p ()
+ (ert-info ("Local channels not supported")
+ (let ((erc--isupport-params (make-hash-table)))
+ (puthash 'CHANTYPES '("#") erc--isupport-params)
+ (should-not (erc--valid-local-channel-p "#chan"))
+ (should-not (erc--valid-local-channel-p "&local"))))
+ (ert-info ("Local channels supported")
+ (let ((erc--isupport-params (make-hash-table)))
+ (puthash 'CHANTYPES '("&#") erc--isupport-params)
+ (should-not (erc--valid-local-channel-p "#chan"))
+ (should (erc--valid-local-channel-p "&local")))))
+
+(ert-deftest erc--target-from-string ()
+ (should (equal (erc--target-from-string "#chan")
+ #s(erc--target-channel "#chan" \#chan)))
+
+ (should (equal (erc--target-from-string "Bob")
+ #s(erc--target "Bob" bob)))
+
+ (let ((erc--isupport-params (make-hash-table)))
+ (puthash 'CHANTYPES '("&#") erc--isupport-params)
+ (should (equal (erc--target-from-string "&Bitlbee")
+ #s(erc--target-channel-local "&Bitlbee" &bitlbee)))))
+
(ert-deftest erc-ring-previous-command-base-case ()
(ert-info ("Create ring when nonexistent and do nothing")
(let (erc-input-ring
@@ -140,14 +503,10 @@
(ert-deftest erc-ring-previous-command ()
(with-current-buffer (get-buffer-create "*#fake*")
(erc-mode)
- (insert "\n\n")
+ (erc-tests--send-prep)
+ (setq-local erc-last-input-time 0)
(should-not (local-variable-if-set-p 'erc-send-completed-hook))
(set (make-local-variable 'erc-send-completed-hook) nil) ; skip t (globals)
- (setq erc-input-marker (make-marker)
- erc-insert-marker (make-marker))
- (set-marker erc-insert-marker (point-max))
- (erc-display-prompt)
- (should (= (point) erc-input-marker))
;; Just in case erc-ring-mode is already on
(setq-local erc-pre-send-functions nil)
(add-hook 'erc-pre-send-functions #'erc-add-to-input-ring)
@@ -207,8 +566,9 @@
(erc-log-irc-protocol ":irc.gnu.org 001 tester :Welcome")
(erc-log-irc-protocol ":irc.gnu.org 002 tester :Your host is irc.gnu.org")
(setq erc-network 'FooNet)
+ (setq erc-networks--id (erc-networks--id-create nil))
(erc-log-irc-protocol ":irc.gnu.org 422 tester :MOTD missing")
- (setq erc-network 'BarNet)
+ (setq erc-networks--id (erc-networks--id-create 'BarNet))
(erc-log-irc-protocol ":irc.gnu.org 221 tester +i")
(set-process-query-on-exit-flag erc-server-process nil)))
(with-current-buffer "*erc-protocol*"
@@ -228,4 +588,309 @@
(kill-buffer "*erc-protocol*")
(should-not erc-debug-irc-protocol)))
+(ert-deftest erc--input-line-delim-regexp ()
+ (let ((p erc--input-line-delim-regexp))
+ ;; none
+ (should (equal '("a" "b") (split-string "a\r\nb" p)))
+ (should (equal '("a" "b") (split-string "a\nb" p)))
+ (should (equal '("a" "b") (split-string "a\rb" p)))
+
+ ;; one
+ (should (equal '("") (split-string "" p)))
+ (should (equal '("a" "" "b") (split-string "a\r\rb" p)))
+ (should (equal '("a" "" "b") (split-string "a\n\rb" p)))
+ (should (equal '("a" "" "b") (split-string "a\n\nb" p)))
+ (should (equal '("a" "" "b") (split-string "a\r\r\nb" p)))
+ (should (equal '("a" "" "b") (split-string "a\n\r\nb" p)))
+ (should (equal '("a" "") (split-string "a\n" p)))
+ (should (equal '("a" "") (split-string "a\r" p)))
+ (should (equal '("a" "") (split-string "a\r\n" p)))
+ (should (equal '("" "b") (split-string "\nb" p)))
+ (should (equal '("" "b") (split-string "\rb" p)))
+ (should (equal '("" "b") (split-string "\r\nb" p)))
+
+ ;; two
+ (should (equal '("" "") (split-string "\r" p)))
+ (should (equal '("" "") (split-string "\n" p)))
+ (should (equal '("" "") (split-string "\r\n" p)))
+
+ ;; three
+ (should (equal '("" "" "") (split-string "\r\r" p)))
+ (should (equal '("" "" "") (split-string "\n\n" p)))
+ (should (equal '("" "" "") (split-string "\n\r" p)))))
+
+(ert-deftest erc--blank-in-multiline-input-p ()
+ (let ((check (lambda (s)
+ (erc--blank-in-multiline-input-p
+ (split-string s erc--input-line-delim-regexp)))))
+
+ (ert-info ("With `erc-send-whitespace-lines'")
+ (let ((erc-send-whitespace-lines t))
+ (should (funcall check ""))
+ (should-not (funcall check "\na"))
+ (should-not (funcall check "/msg a\n")) ; real /cmd
+ (should-not (funcall check "a\n\nb")) ; "" allowed
+ (should-not (funcall check "/msg a\n\nb")) ; non-/cmd
+ (should-not (funcall check " "))
+ (should-not (funcall check "\t"))
+ (should-not (funcall check "a\nb"))
+ (should-not (funcall check "a\n "))
+ (should-not (funcall check "a\n \t"))
+ (should-not (funcall check "a\n \f"))
+ (should-not (funcall check "a\n \nb"))
+ (should-not (funcall check "a\n \t\nb"))
+ (should-not (funcall check "a\n \f\nb"))))
+
+ (should (funcall check ""))
+ (should (funcall check " "))
+ (should (funcall check "\t"))
+ (should (funcall check "a\n\nb"))
+ (should (funcall check "a\n\nb"))
+ (should (funcall check "a\n "))
+ (should (funcall check "a\n \t"))
+ (should (funcall check "a\n \f"))
+ (should (funcall check "a\n \nb"))
+ (should (funcall check "a\n \t\nb"))
+
+ (should-not (funcall check "a\rb"))
+ (should-not (funcall check "a\nb"))
+ (should-not (funcall check "a\r\nb"))))
+
+(defun erc-tests--with-process-input-spy (test)
+ (with-current-buffer (get-buffer-create "FakeNet")
+ (let* ((erc-pre-send-functions
+ (remove #'erc-add-to-input-ring erc-pre-send-functions)) ; for now
+ (inhibit-message noninteractive)
+ (erc-server-current-nick "tester")
+ (erc-last-input-time 0)
+ erc-accidental-paste-threshold-seconds
+ erc-send-modify-hook
+ ;;
+ calls)
+ (cl-letf (((symbol-function 'erc-process-input-line)
+ (lambda (&rest r) (push r calls)))
+ ((symbol-function 'erc-server-buffer)
+ (lambda () (current-buffer))))
+ (erc-tests--send-prep)
+ (funcall test (lambda () (pop calls)))))
+ (when noninteractive (kill-buffer))))
+
+(ert-deftest erc--check-prompt-input-functions ()
+ (erc-tests--with-process-input-spy
+ (lambda (next)
+
+ (ert-info ("Errors when point not in prompt area") ; actually just dings
+ (insert "/msg #chan hi")
+ (forward-line -1)
+ (let ((e (should-error (erc-send-current-line))))
+ (should (equal "Point is not in the input area" (cadr e))))
+ (goto-char (point-max))
+ (ert-info ("Input remains untouched")
+ (should (save-excursion (erc-bol) (looking-at "/msg #chan hi")))))
+
+ (ert-info ("Errors when no process running")
+ (let ((e (should-error (erc-send-current-line))))
+ (should (equal "ERC: No process running" (cadr e))))
+ (ert-info ("Input remains untouched")
+ (should (save-excursion (erc-bol) (looking-at "/msg #chan hi")))))
+
+ (ert-info ("Errors when line contains empty newline")
+ (erc-bol)
+ (delete-region (point) (point-max))
+ (insert "one\n")
+ (let ((e (should-error (erc-send-current-line))))
+ (should (equal "Blank line - ignoring..." (cadr e))))
+ (goto-char (point-max))
+ (ert-info ("Input remains untouched")
+ (should (save-excursion (goto-char erc-input-marker)
+ (looking-at "one\n")))))
+
+ (should (= 0 erc-last-input-time))
+ (should-not (funcall next)))))
+
+;; These also indirectly tests `erc-send-input'
+
+(ert-deftest erc-send-current-line ()
+ (erc-tests--with-process-input-spy
+ (lambda (next)
+ (erc-tests--set-fake-server-process "sleep" "1")
+ (should (= 0 erc-last-input-time))
+
+ (ert-info ("Simple command")
+ (insert "/msg #chan hi")
+ (erc-send-current-line)
+ (ert-info ("Prompt restored")
+ (forward-line 0)
+ (should (looking-at-p erc-prompt)))
+ (ert-info ("Input cleared")
+ (erc-bol)
+ (should (eq (point) (point-max))))
+ ;; Commands are forced (no flood protection)
+ (should (equal (funcall next) '("/msg #chan hi\n" t nil))))
+
+ (ert-info ("Simple non-command")
+ (insert "hi")
+ (erc-send-current-line)
+ (should (eq (point) (point-max)))
+ (should (save-excursion (forward-line -1)
+ (search-forward "<tester> hi")))
+ ;; Non-ommands are forced only when `erc-flood-protect' is nil
+ (should (equal (funcall next) '("hi\n" nil t))))
+
+ (should (consp erc-last-input-time)))))
+
+(ert-deftest erc-send-whitespace-lines ()
+ (erc-tests--with-process-input-spy
+ (lambda (next)
+ (erc-tests--set-fake-server-process "sleep" "1")
+ (setq-local erc-send-whitespace-lines t)
+
+ (ert-info ("Multiline hunk with blank line correctly split")
+ (insert "one\n\ntwo")
+ (erc-send-current-line)
+ (ert-info ("Prompt restored")
+ (forward-line 0)
+ (should (looking-at-p erc-prompt)))
+ (ert-info ("Input cleared")
+ (erc-bol)
+ (should (eq (point) (point-max))))
+ (should (equal (funcall next) '("two\n" nil t)))
+ (should (equal (funcall next) '("\n" nil t)))
+ (should (equal (funcall next) '("one\n" nil t))))
+
+ (ert-info ("Multiline hunk with trailing newline filtered")
+ (insert "hi\n")
+ (erc-send-current-line)
+ (ert-info ("Input cleared")
+ (erc-bol)
+ (should (eq (point) (point-max))))
+ (should (equal (funcall next) '("hi\n" nil t)))
+ (should-not (funcall next)))
+
+ (ert-info ("Multiline hunk with trailing carriage filtered")
+ (insert "hi\r")
+ (erc-send-current-line)
+ (ert-info ("Input cleared")
+ (erc-bol)
+ (should (eq (point) (point-max))))
+ (should (equal (funcall next) '("hi\n" nil t)))
+ (should-not (funcall next)))
+
+ (ert-info ("Multiline command with trailing blank filtered")
+ (pcase-dolist (`(,p . ,q)
+ '(("/a b\r" "/a b\n") ("/a b\n" "/a b\n")
+ ("/a b\n\n" "/a b\n") ("/a b\r\n" "/a b\n")
+ ("a b\nc\n\n" "c\n" "a b\n")
+ ("/a b\nc\n\n" "c\n" "/a b\n")
+ ("/a b\n\nc\n\n" "c\n" "\n" "/a b\n")))
+ (insert p)
+ (erc-send-current-line)
+ (erc-bol)
+ (should (eq (point) (point-max)))
+ (while q
+ (should (equal (funcall next) (list (pop q) nil t))))
+ (should-not (funcall next))))
+
+ (ert-info ("Multiline hunk with trailing whitespace not filtered")
+ (insert "there\n ")
+ (erc-send-current-line)
+ (should (equal (funcall next) '(" \n" nil t)))
+ (should (equal (funcall next) '("there\n" nil t)))
+ (should-not (funcall next))))))
+
+(ert-deftest erc--check-prompt-input-for-excess-lines ()
+ (ert-info ("Without `erc-inhibit-multiline-input'")
+ (should-not erc-inhibit-multiline-input)
+ (should-not (erc--check-prompt-input-for-excess-lines "" '("a" "b"))))
+
+ (ert-info ("With `erc-inhibit-multiline-input' as t (2)")
+ (let ((erc-inhibit-multiline-input t))
+ (should-not (erc--check-prompt-input-for-excess-lines "" '("a")))
+ (should-not (erc--check-prompt-input-for-excess-lines "" '("a" "")))
+ (should (erc--check-prompt-input-for-excess-lines "" '("a" "b")))))
+
+ (ert-info ("With `erc-inhibit-multiline-input' as 3")
+ (let ((erc-inhibit-multiline-input 3))
+ (should-not (erc--check-prompt-input-for-excess-lines "" '("a" "b")))
+ (should-not (erc--check-prompt-input-for-excess-lines "" '("a" "b" "")))
+ (should (erc--check-prompt-input-for-excess-lines "" '("a" "b" "c")))))
+
+ (ert-info ("With `erc-ask-about-multiline-input'")
+ (let ((erc-inhibit-multiline-input t)
+ (erc-ask-about-multiline-input t))
+ (ert-simulate-keys '(?n ?\r ?y ?\r)
+ (should (erc--check-prompt-input-for-excess-lines "" '("a" "b")))
+ (should-not (erc--check-prompt-input-for-excess-lines "" '("a" "b")))))
+ (should-not erc-ask-about-multiline-input)))
+
+;; The point of this test is to ensure output is handled identically
+;; regardless of whether a command handler is summoned.
+
+(ert-deftest erc-process-input-line ()
+ (let (erc-server-last-sent-time
+ erc-server-flood-queue
+ (orig-erc-cmd-MSG (symbol-function 'erc-cmd-MSG))
+ (erc-default-recipients '("#chan"))
+ calls)
+ (with-temp-buffer
+ (cl-letf (((symbol-function 'erc-cmd-MSG)
+ (lambda (line)
+ (push line calls)
+ (funcall orig-erc-cmd-MSG line)))
+ ((symbol-function 'erc-server-buffer)
+ (lambda () (current-buffer)))
+ ((symbol-function 'erc-server-process-alive)
+ (lambda () t))
+ ((symbol-function 'erc-server-send-queue)
+ #'ignore))
+
+ (ert-info ("Dispatch to user command handler")
+
+ (ert-info ("Baseline")
+ (erc-process-input-line "/msg #chan hi\n")
+ (should (equal (pop calls) " #chan hi"))
+ (should (equal (pop erc-server-flood-queue)
+ '("PRIVMSG #chan :hi\r\n" . utf-8))))
+
+ (ert-info ("Quote preserves line intact")
+ (erc-process-input-line "/QUOTE FAKE foo bar\n")
+ (should (equal (pop erc-server-flood-queue)
+ '("FAKE foo bar\r\n" . utf-8))))
+
+ (ert-info ("Unknown command respected")
+ (erc-process-input-line "/FAKE foo bar\n")
+ (should (equal (pop erc-server-flood-queue)
+ '("FAKE foo bar\r\n" . utf-8))))
+
+ (ert-info ("Spaces preserved")
+ (erc-process-input-line "/msg #chan hi you\n")
+ (should (equal (pop calls) " #chan hi you"))
+ (should (equal (pop erc-server-flood-queue)
+ '("PRIVMSG #chan :hi you\r\n" . utf-8))))
+
+ (ert-info ("Empty line honored")
+ (erc-process-input-line "/msg #chan\n")
+ (should (equal (pop calls) " #chan"))
+ (should (equal (pop erc-server-flood-queue)
+ '("PRIVMSG #chan :\r\n" . utf-8)))))
+
+ (ert-info ("Implicit cmd via `erc-send-input-line-function'")
+
+ (ert-info ("Baseline")
+ (erc-process-input-line "hi\n")
+ (should (equal (pop erc-server-flood-queue)
+ '("PRIVMSG #chan :hi\r\n" . utf-8))))
+
+ (ert-info ("Spaces preserved")
+ (erc-process-input-line "hi you\n")
+ (should (equal (pop erc-server-flood-queue)
+ '("PRIVMSG #chan :hi you\r\n" . utf-8))))
+
+ (ert-info ("Empty line transmitted with injected-space kludge")
+ (erc-process-input-line "\n")
+ (should (equal (pop erc-server-flood-queue)
+ '("PRIVMSG #chan : \r\n" . utf-8))))
+
+ (should-not calls))))))
+
;;; erc-tests.el ends here