diff options
| author | F. Jason Park | 2022-03-21 05:40:16 -0700 |
|---|---|---|
| committer | F. Jason Park | 2022-06-30 15:19:53 -0700 |
| commit | f46547294d2684d80bb473bd4c85f273ff661a7d (patch) | |
| tree | 9957e4f497d0588560cad7639441e0b01ca8b123 /test | |
| parent | a9d89d083ac5bf0b9fd5568d42e565aba0b6e13f (diff) | |
| download | emacs-f46547294d2684d80bb473bd4c85f273ff661a7d.tar.gz emacs-f46547294d2684d80bb473bd4c85f273ff661a7d.zip | |
Improve ERC's handling of multiline prompt input
* lisp/erc/erc.el (erc--pre-send-split-functions): Add new internal
hook allowing members to revise individual lines before sending. This
was created with an eye toward possibly exporting it publicly as a
customizable option.
(erc-last-input-time): Tweak meaning of variable to match likely
original intent, which is that it's only updated on successful calls
to `erc-send-current-line'.
(erc--discard-trailing-multiline-nulls): Conditionally truncate list
of lines to be sent, skipping trailing blanks. This constitutes a
behavioral change. But, considering the nature of the bug being
fixed, it is thought to be justified.
(erc--input-split): Add new internal struct containing split input
lines and flag for command detection.
(erc--input-line-delim-regexp): Add regex var for splitting multiline
prompt input.
(erc--blank-in-multiline-p): Add helper for detecting blank lines.
(erc--check-prompt-input-for-multiline-blanks,
erc--check-prompt-input-for-point-in-bounds,
erc--check-prompt-input-for-running-process): New functions to
encapsulate logic for various pre-flight idiot checks.
(erc--check-prompt-input-functions): Add new hook for validating
prompt input prior to clearing it, internal for now.
(erc-send-current-line): Pre-screen for blank lines and bail out if
necessary.
(erc-send-input): Add optional param to skip checking for blank lines.
Call hook `erc--pre-send-split-functions'.
* test/lisp/erc/erc-tests.el (erc-ring-previous-command): Use new test
helper.
(erc--input-line-delim-regexp,
erc--blank-in-multiline-input-p): Add tests.
(erc-tests--send-prep, erc-tests--set-fake-server-process,
erc-tests--with-process-input-spy): Add test helpers.
(erc--check-prompt-input-functions, erc-send-current-line,
erc-send-whitespace-lines): Add tests.
(Bug#54536)
Diffstat (limited to 'test')
| -rw-r--r-- | test/lisp/erc/erc-tests.el | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index afe9cc7b8cb..986988a3356 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el | |||
| @@ -588,6 +588,214 @@ | |||
| 588 | (kill-buffer "*erc-protocol*") | 588 | (kill-buffer "*erc-protocol*") |
| 589 | (should-not erc-debug-irc-protocol))) | 589 | (should-not erc-debug-irc-protocol))) |
| 590 | 590 | ||
| 591 | (ert-deftest erc--input-line-delim-regexp () | ||
| 592 | (let ((p erc--input-line-delim-regexp)) | ||
| 593 | ;; none | ||
| 594 | (should (equal '("a" "b") (split-string "a\r\nb" p))) | ||
| 595 | (should (equal '("a" "b") (split-string "a\nb" p))) | ||
| 596 | (should (equal '("a" "b") (split-string "a\rb" p))) | ||
| 597 | |||
| 598 | ;; one | ||
| 599 | (should (equal '("") (split-string "" p))) | ||
| 600 | (should (equal '("a" "" "b") (split-string "a\r\rb" p))) | ||
| 601 | (should (equal '("a" "" "b") (split-string "a\n\rb" p))) | ||
| 602 | (should (equal '("a" "" "b") (split-string "a\n\nb" p))) | ||
| 603 | (should (equal '("a" "" "b") (split-string "a\r\r\nb" p))) | ||
| 604 | (should (equal '("a" "" "b") (split-string "a\n\r\nb" p))) | ||
| 605 | (should (equal '("a" "") (split-string "a\n" p))) | ||
| 606 | (should (equal '("a" "") (split-string "a\r" p))) | ||
| 607 | (should (equal '("a" "") (split-string "a\r\n" p))) | ||
| 608 | (should (equal '("" "b") (split-string "\nb" p))) | ||
| 609 | (should (equal '("" "b") (split-string "\rb" p))) | ||
| 610 | (should (equal '("" "b") (split-string "\r\nb" p))) | ||
| 611 | |||
| 612 | ;; two | ||
| 613 | (should (equal '("" "") (split-string "\r" p))) | ||
| 614 | (should (equal '("" "") (split-string "\n" p))) | ||
| 615 | (should (equal '("" "") (split-string "\r\n" p))) | ||
| 616 | |||
| 617 | ;; three | ||
| 618 | (should (equal '("" "" "") (split-string "\r\r" p))) | ||
| 619 | (should (equal '("" "" "") (split-string "\n\n" p))) | ||
| 620 | (should (equal '("" "" "") (split-string "\n\r" p))))) | ||
| 621 | |||
| 622 | (ert-deftest erc--blank-in-multiline-input-p () | ||
| 623 | (let ((check (lambda (s) | ||
| 624 | (erc--blank-in-multiline-input-p | ||
| 625 | (split-string s erc--input-line-delim-regexp))))) | ||
| 626 | |||
| 627 | (ert-info ("With `erc-send-whitespace-lines'") | ||
| 628 | (let ((erc-send-whitespace-lines t)) | ||
| 629 | (should (funcall check "")) | ||
| 630 | (should-not (funcall check "\na")) | ||
| 631 | (should-not (funcall check "/msg a\n")) ; real /cmd | ||
| 632 | (should-not (funcall check "a\n\nb")) ; "" allowed | ||
| 633 | (should-not (funcall check "/msg a\n\nb")) ; non-/cmd | ||
| 634 | (should-not (funcall check " ")) | ||
| 635 | (should-not (funcall check "\t")) | ||
| 636 | (should-not (funcall check "a\nb")) | ||
| 637 | (should-not (funcall check "a\n ")) | ||
| 638 | (should-not (funcall check "a\n \t")) | ||
| 639 | (should-not (funcall check "a\n \f")) | ||
| 640 | (should-not (funcall check "a\n \nb")) | ||
| 641 | (should-not (funcall check "a\n \t\nb")) | ||
| 642 | (should-not (funcall check "a\n \f\nb")))) | ||
| 643 | |||
| 644 | (should (funcall check "")) | ||
| 645 | (should (funcall check " ")) | ||
| 646 | (should (funcall check "\t")) | ||
| 647 | (should (funcall check "a\n\nb")) | ||
| 648 | (should (funcall check "a\n\nb")) | ||
| 649 | (should (funcall check "a\n ")) | ||
| 650 | (should (funcall check "a\n \t")) | ||
| 651 | (should (funcall check "a\n \f")) | ||
| 652 | (should (funcall check "a\n \nb")) | ||
| 653 | (should (funcall check "a\n \t\nb")) | ||
| 654 | |||
| 655 | (should-not (funcall check "a\rb")) | ||
| 656 | (should-not (funcall check "a\nb")) | ||
| 657 | (should-not (funcall check "a\r\nb")))) | ||
| 658 | |||
| 659 | (defun erc-tests--with-process-input-spy (test) | ||
| 660 | (with-current-buffer (get-buffer-create "FakeNet") | ||
| 661 | (let* ((erc-pre-send-functions | ||
| 662 | (remove #'erc-add-to-input-ring erc-pre-send-functions)) ; for now | ||
| 663 | (inhibit-message noninteractive) | ||
| 664 | (erc-server-current-nick "tester") | ||
| 665 | (erc-last-input-time 0) | ||
| 666 | erc-accidental-paste-threshold-seconds | ||
| 667 | ;; | ||
| 668 | calls) | ||
| 669 | (cl-letf (((symbol-function 'erc-process-input-line) | ||
| 670 | (lambda (&rest r) (push r calls))) | ||
| 671 | ((symbol-function 'erc-server-buffer) | ||
| 672 | (lambda () (current-buffer)))) | ||
| 673 | (erc-tests--send-prep) | ||
| 674 | (funcall test (lambda () (pop calls))))) | ||
| 675 | (when noninteractive (kill-buffer)))) | ||
| 676 | |||
| 677 | (ert-deftest erc--check-prompt-input-functions () | ||
| 678 | (erc-tests--with-process-input-spy | ||
| 679 | (lambda (next) | ||
| 680 | |||
| 681 | (ert-info ("Errors when point not in prompt area") ; actually just dings | ||
| 682 | (insert "/msg #chan hi") | ||
| 683 | (forward-line -1) | ||
| 684 | (let ((e (should-error (erc-send-current-line)))) | ||
| 685 | (should (equal "Point is not in the input area" (cadr e)))) | ||
| 686 | (goto-char (point-max)) | ||
| 687 | (ert-info ("Input remains untouched") | ||
| 688 | (should (save-excursion (erc-bol) (looking-at "/msg #chan hi"))))) | ||
| 689 | |||
| 690 | (ert-info ("Errors when no process running") | ||
| 691 | (let ((e (should-error (erc-send-current-line)))) | ||
| 692 | (should (equal "ERC: No process running" (cadr e)))) | ||
| 693 | (ert-info ("Input remains untouched") | ||
| 694 | (should (save-excursion (erc-bol) (looking-at "/msg #chan hi"))))) | ||
| 695 | |||
| 696 | (ert-info ("Errors when line contains empty newline") | ||
| 697 | (erc-bol) | ||
| 698 | (delete-region (point) (point-max)) | ||
| 699 | (insert "one\n") | ||
| 700 | (let ((e (should-error (erc-send-current-line)))) | ||
| 701 | (should (equal "Blank line - ignoring..." (cadr e)))) | ||
| 702 | (goto-char (point-max)) | ||
| 703 | (ert-info ("Input remains untouched") | ||
| 704 | (should (save-excursion (goto-char erc-input-marker) | ||
| 705 | (looking-at "one\n"))))) | ||
| 706 | |||
| 707 | (should (= 0 erc-last-input-time)) | ||
| 708 | (should-not (funcall next))))) | ||
| 709 | |||
| 710 | ;; These also indirectly tests `erc-send-input' | ||
| 711 | |||
| 712 | (ert-deftest erc-send-current-line () | ||
| 713 | (erc-tests--with-process-input-spy | ||
| 714 | (lambda (next) | ||
| 715 | (erc-tests--set-fake-server-process "sleep" "1") | ||
| 716 | (should (= 0 erc-last-input-time)) | ||
| 717 | |||
| 718 | (ert-info ("Simple command") | ||
| 719 | (insert "/msg #chan hi") | ||
| 720 | (erc-send-current-line) | ||
| 721 | (ert-info ("Prompt restored") | ||
| 722 | (forward-line 0) | ||
| 723 | (should (looking-at-p erc-prompt))) | ||
| 724 | (ert-info ("Input cleared") | ||
| 725 | (erc-bol) | ||
| 726 | (should (eq (point) (point-max)))) | ||
| 727 | ;; Commands are forced (no flood protection) | ||
| 728 | (should (equal (funcall next) '("/msg #chan hi\n" t nil)))) | ||
| 729 | |||
| 730 | (ert-info ("Simple non-command") | ||
| 731 | (insert "hi") | ||
| 732 | (erc-send-current-line) | ||
| 733 | (should (eq (point) (point-max))) | ||
| 734 | (should (save-excursion (forward-line -1) | ||
| 735 | (search-forward "<tester> hi"))) | ||
| 736 | ;; Non-ommands are forced only when `erc-flood-protect' is nil | ||
| 737 | (should (equal (funcall next) '("hi\n" nil t)))) | ||
| 738 | |||
| 739 | (should (consp erc-last-input-time))))) | ||
| 740 | |||
| 741 | (ert-deftest erc-send-whitespace-lines () | ||
| 742 | (erc-tests--with-process-input-spy | ||
| 743 | (lambda (next) | ||
| 744 | (erc-tests--set-fake-server-process "sleep" "1") | ||
| 745 | (setq-local erc-send-whitespace-lines t) | ||
| 746 | |||
| 747 | (ert-info ("Multiline hunk with blank line correctly split") | ||
| 748 | (insert "one\n\ntwo") | ||
| 749 | (erc-send-current-line) | ||
| 750 | (ert-info ("Prompt restored") | ||
| 751 | (forward-line 0) | ||
| 752 | (should (looking-at-p erc-prompt))) | ||
| 753 | (ert-info ("Input cleared") | ||
| 754 | (erc-bol) | ||
| 755 | (should (eq (point) (point-max)))) | ||
| 756 | (should (equal (funcall next) '("two\n" nil t))) | ||
| 757 | (should (equal (funcall next) '("\n" nil t))) | ||
| 758 | (should (equal (funcall next) '("one\n" nil t)))) | ||
| 759 | |||
| 760 | (ert-info ("Multiline hunk with trailing newline filtered") | ||
| 761 | (insert "hi\n") | ||
| 762 | (erc-send-current-line) | ||
| 763 | (ert-info ("Input cleared") | ||
| 764 | (erc-bol) | ||
| 765 | (should (eq (point) (point-max)))) | ||
| 766 | (should (equal (funcall next) '("hi\n" nil t))) | ||
| 767 | (should-not (funcall next))) | ||
| 768 | |||
| 769 | (ert-info ("Multiline hunk with trailing carriage filtered") | ||
| 770 | (insert "hi\r") | ||
| 771 | (erc-send-current-line) | ||
| 772 | (ert-info ("Input cleared") | ||
| 773 | (erc-bol) | ||
| 774 | (should (eq (point) (point-max)))) | ||
| 775 | (should (equal (funcall next) '("hi\n" nil t))) | ||
| 776 | (should-not (funcall next))) | ||
| 777 | |||
| 778 | (ert-info ("Multiline command with trailing blank filtered") | ||
| 779 | (pcase-dolist (`(,p . ,q) | ||
| 780 | '(("/a b\r" "/a b\n") ("/a b\n" "/a b\n") | ||
| 781 | ("/a b\n\n" "/a b\n") ("/a b\r\n" "/a b\n") | ||
| 782 | ("a b\nc\n\n" "c\n" "a b\n") | ||
| 783 | ("/a b\nc\n\n" "c\n" "/a b\n") | ||
| 784 | ("/a b\n\nc\n\n" "c\n" "\n" "/a b\n"))) | ||
| 785 | (insert p) | ||
| 786 | (erc-send-current-line) | ||
| 787 | (erc-bol) | ||
| 788 | (should (eq (point) (point-max))) | ||
| 789 | (while q | ||
| 790 | (should (equal (funcall next) (list (pop q) nil t)))) | ||
| 791 | (should-not (funcall next)))) | ||
| 792 | |||
| 793 | (ert-info ("Multiline hunk with trailing whitespace not filtered") | ||
| 794 | (insert "there\n ") | ||
| 795 | (erc-send-current-line) | ||
| 796 | (should (equal (funcall next) '(" \n" nil t))) | ||
| 797 | (should (equal (funcall next) '("there\n" nil t))) | ||
| 798 | (should-not (funcall next)))))) | ||
| 591 | 799 | ||
| 592 | ;; The point of this test is to ensure output is handled identically | 800 | ;; The point of this test is to ensure output is handled identically |
| 593 | ;; regardless of whether a command handler is summoned. | 801 | ;; regardless of whether a command handler is summoned. |