summaryrefslogtreecommitdiff
path: root/test/lisp/electric-tests.el
diff options
context:
space:
mode:
Diffstat (limited to 'test/lisp/electric-tests.el')
-rw-r--r--test/lisp/electric-tests.el430
1 files changed, 328 insertions, 102 deletions
diff --git a/test/lisp/electric-tests.el b/test/lisp/electric-tests.el
index 7df2449b9eb..d34737e6090 100644
--- a/test/lisp/electric-tests.el
+++ b/test/lisp/electric-tests.el
@@ -1,22 +1,24 @@
-;;; electric-tests.el --- tests for electric.el
+;;; electric-tests.el --- tests for electric.el -*- lexical-binding: t; -*-
-;; Copyright (C) 2013-2017 Free Software Foundation, Inc.
+;; Copyright (C) 2013-2022 Free Software Foundation, Inc.
;; Author: João Távora <joaotavora@gmail.com>
;; Keywords:
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
-;; This program is distributed in the hope that it will be useful,
+;; 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 this program. If not, see <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
@@ -33,7 +35,8 @@
(defun call-with-saved-electric-modes (fn)
(let ((saved-electric (if electric-pair-mode 1 -1))
(saved-layout (if electric-layout-mode 1 -1))
- (saved-indent (if electric-indent-mode 1 -1)))
+ (saved-indent (if electric-indent-mode 1 -1))
+ (blink-paren-function nil))
(electric-pair-mode -1)
(electric-layout-mode -1)
(electric-indent-mode -1)
@@ -45,28 +48,38 @@
(defmacro save-electric-modes (&rest body)
(declare (indent defun) (debug t))
- `(call-with-saved-electric-modes #'(lambda () ,@body)))
+ `(call-with-saved-electric-modes (lambda () ,@body)))
(defun electric-pair-test-for (fixture where char expected-string
- expected-point mode bindings fixture-fn)
+ expected-point mode bindings
+ fixture-fn &optional doc-string)
(with-temp-buffer
- (funcall mode)
- (insert fixture)
- (save-electric-modes
- (let ((last-command-event char)
- (transient-mark-mode 'lambda))
- (goto-char where)
- (funcall fixture-fn)
- (cl-progv
- (mapcar #'car bindings)
- (mapcar #'cdr bindings)
- (call-interactively (key-binding `[,last-command-event])))))
+ (dlet ((python-indent-guess-indent-offset-verbose nil))
+ (funcall mode)
+ (insert fixture)
+ (save-electric-modes
+ (let ((last-command-event char)
+ (transient-mark-mode 'lambda))
+ (goto-char where)
+ (funcall fixture-fn)
+ (cl-progv
+ (mapcar #'car bindings)
+ (mapcar #'cdr bindings)
+ (call-interactively (key-binding `[,last-command-event]))))))
+ (when
+ (and doc-string
+ (not
+ (and
+ (equal (buffer-substring-no-properties (point-min) (point-max))
+ expected-string)
+ (equal (point) expected-point))))
+ (message "\n%s\n" doc-string))
(should (equal (buffer-substring-no-properties (point-min) (point-max))
expected-string))
(should (equal (point)
expected-point))))
-(eval-when-compile
+(eval-and-compile
(defun electric-pair-define-test-form (name fixture
char
pos
@@ -84,46 +97,67 @@
(with-temp-buffer
(cl-progv
;; FIXME: avoid `eval'
- (mapcar #'car (eval bindings))
- (mapcar #'cdr (eval bindings))
- (funcall mode)
- (insert fixture)
- (goto-char (1+ pos))
- (insert char)
- (cond ((eq (aref skip-pair-string pos)
- ?p)
- (insert (cadr (electric-pair-syntax-info char)))
- (backward-char 1))
- ((eq (aref skip-pair-string pos)
- ?s)
- (delete-char -1)
- (forward-char 1)))
- (list
- (buffer-substring-no-properties (point-min) (point-max))
- (point))))
+ (mapcar #'car (eval bindings t))
+ (mapcar #'cdr (eval bindings t))
+ (dlet ((python-indent-guess-indent-offset-verbose nil))
+ (funcall mode)
+ (insert fixture)
+ (goto-char (1+ pos))
+ (insert char)
+ (cond ((eq (aref skip-pair-string pos)
+ ?p)
+ (insert (cadr (electric-pair-syntax-info char)))
+ (backward-char 1))
+ ((eq (aref skip-pair-string pos)
+ ?s)
+ (delete-char -1)
+ (forward-char 1)))
+ (list
+ (buffer-substring-no-properties (point-min) (point-max))
+ (point)))))
(list expected-string expected-point)))
(expected-string (car expected-string-and-point))
(expected-point (cadr expected-string-and-point))
(fixture (format "%s%s%s" prefix fixture suffix))
(expected-string (format "%s%s%s" prefix expected-string suffix))
(expected-point (+ (length prefix) expected-point))
- (pos (+ (length prefix) pos)))
+ (pos (+ (length prefix) pos))
+ (doc-string
+ (format "Electricity test in a `%s' buffer.\n
+Start with point at %d in a %d-char-long buffer
+like this one:
+
+ |%s| (buffer start and end are denoted by `|')
+%s
+%s
+Now press the key for: %c
+
+The buffer's contents should %s:
+
+ |%s|
+
+, and point should be at %d."
+ mode
+ (1+ pos)
+ (length fixture)
+ fixture
+ (if fixture-fn (format "\nNow call this:\n\n%s"
+ (pp-to-string fixture-fn))
+ "")
+ (if bindings (format "\nEnsure the following bindings:\n\n%s"
+ (pp-to-string bindings))
+ "")
+ char
+ (if (string= fixture expected-string) "stay" "become")
+ (string-replace "\n" "\\n" expected-string)
+ expected-point)))
`(ert-deftest ,(intern (format "electric-pair-%s-at-point-%s-in-%s%s"
name
(1+ pos)
mode
extra-desc))
()
- ,(format "With |%s|, try input %c at point %d. \
-Should %s |%s| and point at %d"
- fixture
- char
- (1+ pos)
- (if (string= fixture expected-string)
- "stay"
- "become")
- (replace-regexp-in-string "\n" "\\\\n" expected-string)
- expected-point)
+ ,doc-string
(electric-pair-test-for ,fixture
,(1+ pos)
,char
@@ -131,7 +165,8 @@ Should %s |%s| and point at %d"
,expected-point
',mode
,bindings
- ,fixture-fn)))))
+ ,fixture-fn
+ ,doc-string)))))
(cl-defmacro define-electric-pair-test
(name fixture
@@ -141,31 +176,36 @@ Should %s |%s| and point at %d"
expected-string
expected-point
bindings
- (modes '(quote (ruby-mode c++-mode)))
+ (modes '(quote (ruby-mode js-mode python-mode c-mode)))
(test-in-comments t)
(test-in-strings t)
(test-in-code t)
- (fixture-fn #'(lambda ()
- (electric-pair-mode 1))))
+ ;; The semantics of CL's defmacro "default values" is subtle:
+ ;; contrary to the actual arguments, these are evaluated (and
+ ;; are expected to return the "default form").
+ ;; `fixture-fn' contains a form whose evaluation returns a function.
+ (fixture-fn '#'electric-pair-mode))
`(progn
,@(cl-loop
- for mode in (eval modes) ;FIXME: avoid `eval'
+ for mode in (eval modes t) ;FIXME: avoid `eval'
append
(cl-loop
for (prefix suffix extra-desc) in
(append (if test-in-comments
`((,(with-temp-buffer
- (funcall mode)
- (insert "z")
- (comment-region (point-min) (point-max))
- (buffer-substring-no-properties (point-min)
- (1- (point-max))))
+ (dlet ((python-indent-guess-indent-offset-verbose
+ nil))
+ (funcall mode)
+ (insert "z")
+ (comment-region (point-min) (point-max))
+ (buffer-substring-no-properties (point-min)
+ (1- (point-max)))))
""
"-in-comments")))
(if test-in-strings
- `(("\"" "\"" "-in-strings")))
+ '(("\"" "\"" "-in-strings")))
(if test-in-code
- `(("" "" ""))))
+ '(("" "" ""))))
append
(cl-loop
for char across input
@@ -261,7 +301,7 @@ Should %s |%s| and point at %d"
;;; Quotes
;;;
(define-electric-pair-test pair-some-quotes-skip-others
- " \"\" " "-\"\"-----" :skip-pair-string "-ps------"
+ " \"\" " "-\"\"-\"---" :skip-pair-string "-ps-p----"
:test-in-strings nil
:bindings `((electric-pair-text-syntax-table
. ,prog-mode-syntax-table)))
@@ -324,7 +364,7 @@ baz\"\""
# \"
#
baz\"\""
- :fixture-fn #'(lambda () (goto-char (point-min)) (search-forward "bar")))
+ :fixture-fn (lambda () (goto-char (point-min)) (search-forward "bar")))
(define-electric-pair-test inhibit-in-mismatched-string-inside-c-comments
"foo\"\"/*
@@ -343,7 +383,7 @@ baz\"\""
\" \"
\"
*/baz\"\""
- :fixture-fn #'(lambda () (goto-char (point-min)) (search-forward "bar")))
+ :fixture-fn (lambda () (goto-char (point-min)) (search-forward "bar")))
;;; More quotes, but now don't bind `electric-pair-text-syntax-table'
@@ -375,13 +415,22 @@ baz\"\""
:bindings '((electric-pair-skip-whitespace . chomp))
:test-in-comments nil)
+(ert-deftest electric-pair-whitespace-chomping-2-at-point-4-in-c++-mode-in-strings nil
+ "Check if whitespace chomping works in `c++' unterminated strings."
+ (electric-pair-test-for
+ "\" ( \n \n ) \"" 4 41 "\" () \"" 5 'c++-mode
+ '((electric-pair-skip-whitespace . chomp))
+ (lambda () (electric-pair-mode 1))))
+
(define-electric-pair-test whitespace-chomping-dont-cross-comments
" ( \n\t\t\n ) " "--)------" :expected-string " () \n\t\t\n ) "
:expected-point 4
:bindings '((electric-pair-skip-whitespace . chomp))
:test-in-strings nil
:test-in-code nil
- :test-in-comments t)
+ :test-in-comments t
+ :fixture-fn (lambda () (when (eq major-mode 'c-mode)
+ (c-toggle-comment-style -1))))
(define-electric-pair-test whitespace-skipping-for-quotes-not-outside
" \" \"" "\"-----" :expected-string "\"\" \" \""
@@ -478,27 +527,28 @@ baz\"\""
(define-electric-pair-test js-mode-braces
"" "{" :expected-string "{}" :expected-point 2
:modes '(js-mode)
- :fixture-fn #'(lambda ()
- (electric-pair-mode 1)))
+ :fixture-fn (lambda ()
+ (electric-pair-mode 1)))
+
(define-electric-pair-test js-mode-braces-with-layout
"" "{" :expected-string "{\n\n}" :expected-point 3
:modes '(js-mode)
:test-in-comments nil
:test-in-strings nil
- :fixture-fn #'(lambda ()
- (electric-layout-mode 1)
- (electric-pair-mode 1)))
+ :fixture-fn (lambda ()
+ (electric-layout-mode 1)
+ (electric-pair-mode 1)))
(define-electric-pair-test js-mode-braces-with-layout-and-indent
"" "{" :expected-string "{\n \n}" :expected-point 7
:modes '(js-mode)
:test-in-comments nil
:test-in-strings nil
- :fixture-fn #'(lambda ()
- (electric-pair-mode 1)
- (electric-indent-mode 1)
- (electric-layout-mode 1)))
+ :fixture-fn (lambda ()
+ (electric-pair-mode 1)
+ (electric-indent-mode 1)
+ (electric-layout-mode 1)))
;;; Backspacing
@@ -513,6 +563,24 @@ baz\"\""
(should (equal "" (buffer-string))))))
+;;; Undoing
+(ert-deftest electric-pair-undo-unrelated-state ()
+ "Make sure `electric-pair-mode' does not confuse `undo' (bug#39680)."
+ (with-temp-buffer
+ (buffer-enable-undo)
+ (electric-pair-local-mode)
+ (let ((last-command-event ?\())
+ (ert-simulate-command '(self-insert-command 1)))
+ (undo-boundary)
+ (let ((last-command-event ?a))
+ (ert-simulate-command '(self-insert-command 1)))
+ (undo-boundary)
+ (ert-simulate-command '(undo))
+ (let ((last-command-event ?\())
+ (ert-simulate-command '(self-insert-command 1)))
+ (should (string= (buffer-string) "(())"))))
+
+
;;; Electric newlines between pairs
;;; TODO: better tests
(ert-deftest electric-pair-open-extra-newline ()
@@ -535,55 +603,55 @@ baz\"\""
;;;
(define-electric-pair-test autowrapping-1
"foo" "(" :expected-string "(foo)" :expected-point 2
- :fixture-fn #'(lambda ()
- (electric-pair-mode 1)
- (mark-sexp 1)))
+ :fixture-fn (lambda ()
+ (electric-pair-mode 1)
+ (mark-sexp 1)))
(define-electric-pair-test autowrapping-2
"foo" ")" :expected-string "(foo)" :expected-point 6
- :fixture-fn #'(lambda ()
- (electric-pair-mode 1)
- (mark-sexp 1)))
+ :fixture-fn (lambda ()
+ (electric-pair-mode 1)
+ (mark-sexp 1)))
(define-electric-pair-test autowrapping-3
"foo" ")" :expected-string "(foo)" :expected-point 6
- :fixture-fn #'(lambda ()
- (electric-pair-mode 1)
- (goto-char (point-max))
- (skip-chars-backward "\"")
- (mark-sexp -1)))
+ :fixture-fn (lambda ()
+ (electric-pair-mode 1)
+ (goto-char (point-max))
+ (skip-chars-backward "\"")
+ (mark-sexp -1)))
(define-electric-pair-test autowrapping-4
"foo" "(" :expected-string "(foo)" :expected-point 2
- :fixture-fn #'(lambda ()
- (electric-pair-mode 1)
- (goto-char (point-max))
- (skip-chars-backward "\"")
- (mark-sexp -1)))
+ :fixture-fn (lambda ()
+ (electric-pair-mode 1)
+ (goto-char (point-max))
+ (skip-chars-backward "\"")
+ (mark-sexp -1)))
(define-electric-pair-test autowrapping-5
"foo" "\"" :expected-string "\"foo\"" :expected-point 2
- :fixture-fn #'(lambda ()
- (electric-pair-mode 1)
- (mark-sexp 1)))
+ :fixture-fn (lambda ()
+ (electric-pair-mode 1)
+ (mark-sexp 1)))
(define-electric-pair-test autowrapping-6
"foo" "\"" :expected-string "\"foo\"" :expected-point 6
- :fixture-fn #'(lambda ()
- (electric-pair-mode 1)
- (goto-char (point-max))
- (skip-chars-backward "\"")
- (mark-sexp -1)))
+ :fixture-fn (lambda ()
+ (electric-pair-mode 1)
+ (goto-char (point-max))
+ (skip-chars-backward "\"")
+ (mark-sexp -1)))
(define-electric-pair-test autowrapping-7
"foo" "\"" :expected-string "``foo''" :expected-point 8
:modes '(tex-mode)
:test-in-comments nil
- :fixture-fn #'(lambda ()
- (electric-pair-mode 1)
- (goto-char (point-max))
- (skip-chars-backward "\"")
- (mark-sexp -1)))
+ :fixture-fn (lambda ()
+ (electric-pair-mode 1)
+ (goto-char (point-max))
+ (skip-chars-backward "\"")
+ (mark-sexp -1)))
;;; Electric quotes
@@ -735,6 +803,31 @@ baz\"\""
:bindings '((electric-quote-replace-double . t))
:test-in-comments nil :test-in-strings nil)
+(define-electric-pair-test electric-quote-replace-double-no-context-single
+ " " "-'" :expected-string " ’" :expected-point 3
+ :modes '(text-mode)
+ :fixture-fn #'electric-quote-local-mode
+ :bindings '((electric-quote-replace-double . t))
+ :test-in-comments nil :test-in-strings nil)
+
+(define-electric-pair-test electric-quote-replace-double-escaped-open
+ "foo \\" "-----\"" :expected-string "foo \\“"
+ :expected-point 7 :modes '(emacs-lisp-mode c-mode)
+ :fixture-fn #'electric-quote-local-mode
+ :bindings '((electric-quote-replace-double . t)
+ (electric-quote-comment . t)
+ (electric-quote-string . t))
+ :test-in-comments t :test-in-strings t :test-in-code nil)
+
+(define-electric-pair-test electric-quote-replace-double-escaped-close
+ "foo \\“foo\\" "----------\"" :expected-string "foo \\“foo\\”"
+ :expected-point 12 :modes '(emacs-lisp-mode c-mode)
+ :fixture-fn #'electric-quote-local-mode
+ :bindings '((electric-quote-replace-double . t)
+ (electric-quote-comment . t)
+ (electric-quote-string . t))
+ :test-in-comments t :test-in-strings t :test-in-code nil)
+
;; Simulate ‘markdown-mode’: it sets both ‘comment-start’ and
;; ‘comment-use-syntax’, but derives from ‘text-mode’.
(define-electric-pair-test electric-quote-markdown-in-text
@@ -761,5 +854,138 @@ baz\"\""
:bindings '((comment-start . "<!--") (comment-use-syntax . t))
:test-in-comments nil :test-in-strings nil)
+
+;;; tests for `electric-layout-mode'
+
+(define-derived-mode plainer-c-mode c-mode "pC"
+ "A plainer/saner C-mode with no internal electric machinery."
+ (c-toggle-electric-state -1)
+ (setq-local electric-indent-local-mode-hook nil)
+ (setq-local electric-indent-mode-hook nil)
+ (electric-indent-local-mode 1)
+ (dolist (key '(?\" ?\' ?\{ ?\} ?\( ?\) ?\[ ?\]))
+ (local-set-key (vector key) 'self-insert-command)))
+
+(defun electric-layout-for-c-style-du-jour (inserted)
+ "A function to use in `electric-layout-rules'."
+ (when (memq inserted '(?\{ ?\}))
+ (save-excursion
+ (backward-char 2) (c-point-syntax) (forward-char) ; silly, but needed
+ (c-brace-newlines (c-point-syntax)))))
+
+(ert-deftest electric-layout-plainer-c-mode-use-c-style ()
+ (ert-with-test-buffer ()
+ (plainer-c-mode)
+ (electric-layout-local-mode 1)
+ (electric-pair-local-mode 1)
+ (electric-indent-local-mode 1)
+ (setq-local electric-layout-rules
+ '(electric-layout-for-c-style-du-jour))
+ (insert "int main () ")
+ (let ((last-command-event ?\{))
+ (call-interactively (key-binding `[,last-command-event])))
+ (should (equal (buffer-string) "int main ()\n{\n \n}\n"))))
+
+(ert-deftest electric-layout-int-main-kernel-style ()
+ (ert-with-test-buffer ()
+ (plainer-c-mode)
+ (electric-layout-local-mode 1)
+ (electric-pair-local-mode 1)
+ (electric-indent-local-mode 1)
+ (setq-local electric-layout-rules
+ '((?\{ . (after))
+ (?\} . (before))))
+ (insert "int main () ")
+ (let ((last-command-event ?\{))
+ (call-interactively (key-binding `[,last-command-event])))
+ (should (equal (buffer-string) "int main () {\n \n}"))))
+
+(ert-deftest electric-layout-control-reindentation ()
+ "Same as `electric-layout-int-main-kernel-style', but checking
+Bug#35254."
+ (ert-with-test-buffer ()
+ (plainer-c-mode)
+ (electric-layout-local-mode 1)
+ (electric-pair-local-mode 1)
+ (electric-indent-local-mode 1)
+ (setq-local electric-layout-rules
+ '((?\{ . (after))
+ (?\} . (before))))
+ (insert "int main () ")
+ (let ((last-command-event ?\{))
+ (call-interactively (key-binding `[,last-command-event])))
+ (should (equal (buffer-string) "int main () {\n \n}"))
+ ;; insert an additional newline and check indentation and
+ ;; reindentation
+ (call-interactively 'newline)
+ (should (equal (buffer-string) "int main () {\n\n \n}"))))
+
+(ert-deftest electric-modes-int-main-allman-style ()
+ (ert-with-test-buffer ()
+ (plainer-c-mode)
+ (electric-layout-local-mode 1)
+ (electric-pair-local-mode 1)
+ (electric-indent-local-mode 1)
+ (setq-local electric-layout-rules
+ '((?\{ . (before after))
+ (?\} . (before))))
+ (insert "int main () ")
+ (let ((last-command-event ?\{))
+ (call-interactively (key-binding `[,last-command-event])))
+ (should (equal (buffer-string) "int main ()\n{\n \n}"))))
+
+(ert-deftest electric-pair-mode-newline-between-parens ()
+ (ert-with-test-buffer ()
+ (plainer-c-mode)
+ (electric-layout-local-mode -1) ;; ensure e-l-m mode is off
+ (electric-pair-local-mode 1)
+ (insert-before-markers "int main () {}")
+ (backward-char 1)
+ (let ((last-command-event ?\r))
+ (call-interactively (key-binding `[,last-command-event])))
+ (should (equal (buffer-string) "int main () {\n \n}"))))
+
+(ert-deftest electric-layout-mode-newline-between-parens-without-e-p-m ()
+ (ert-with-test-buffer ()
+ (plainer-c-mode)
+ (electric-layout-local-mode 1)
+ (electric-pair-local-mode -1) ;; ensure e-p-m mode is off
+ (electric-indent-local-mode 1)
+ (setq-local electric-layout-rules
+ '((?\n
+ .
+ (lambda ()
+ (when (eq (save-excursion
+ (skip-chars-backward "\t\s")
+ (char-before (1- (point))))
+ (matching-paren (char-after)))
+ '(after-stay))))))
+ (insert "int main () {}")
+ (backward-char 1)
+ (let ((last-command-event ?\r))
+ (call-interactively (key-binding `[,last-command-event])))
+ (should (equal (buffer-string) "int main () {\n \n}"))))
+
+(ert-deftest electric-layout-mode-newline-between-parens-without-e-p-m-2 ()
+ (ert-with-test-buffer ()
+ (plainer-c-mode)
+ (electric-layout-local-mode 1)
+ (electric-pair-local-mode -1) ;; ensure e-p-m mode is off
+ (electric-indent-local-mode 1)
+ (setq-local electric-layout-rules
+ '((lambda (char)
+ (when (and
+ (eq char ?\n)
+ (eq (save-excursion
+ (skip-chars-backward "\t\s")
+ (char-before (1- (point))))
+ (matching-paren (char-after))))
+ '(after-stay)))))
+ (insert "int main () {}")
+ (backward-char 1)
+ (let ((last-command-event ?\r))
+ (call-interactively (key-binding `[,last-command-event])))
+ (should (equal (buffer-string) "int main () {\n \n}"))))
+
(provide 'electric-tests)
;;; electric-tests.el ends here