diff options
Diffstat (limited to 'test/lisp/electric-tests.el')
-rw-r--r-- | test/lisp/electric-tests.el | 430 |
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 |