123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598 |
- ;;; electric-tests.el --- tests for electric.el
- ;; Copyright (C) 2013-2017 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
- ;; 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,
- ;; 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 <http://www.gnu.org/licenses/>.
- ;;; Commentary:
- ;; Tests for Electric Pair mode.
- ;; TODO: Add tests for other Electric-* functionality
- ;;; Code:
- (require 'ert)
- (require 'ert-x)
- (require 'electric)
- (require 'elec-pair)
- (require 'cl-lib)
- (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)))
- (electric-pair-mode -1)
- (electric-layout-mode -1)
- (electric-indent-mode -1)
- (unwind-protect
- (funcall fn)
- (electric-pair-mode saved-electric)
- (electric-indent-mode saved-indent)
- (electric-layout-mode saved-layout))))
- (defmacro save-electric-modes (&rest body)
- (declare (indent defun) (debug t))
- `(call-with-saved-electric-modes #'(lambda () ,@body)))
- (defun electric-pair-test-for (fixture where char expected-string
- expected-point mode bindings fixture-fn)
- (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])))))
- (should (equal (buffer-substring-no-properties (point-min) (point-max))
- expected-string))
- (should (equal (point)
- expected-point))))
- (eval-when-compile
- (defun electric-pair-define-test-form (name fixture
- char
- pos
- expected-string
- expected-point
- skip-pair-string
- prefix
- suffix
- extra-desc
- mode
- bindings
- fixture-fn)
- (let* ((expected-string-and-point
- (if skip-pair-string
- (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))))
- (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)))
- `(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)
- (electric-pair-test-for ,fixture
- ,(1+ pos)
- ,char
- ,expected-string
- ,expected-point
- ',mode
- ,bindings
- ,fixture-fn)))))
- (cl-defmacro define-electric-pair-test
- (name fixture
- input
- &key
- skip-pair-string
- expected-string
- expected-point
- bindings
- (modes '(quote (ruby-mode c++-mode)))
- (test-in-comments t)
- (test-in-strings t)
- (test-in-code t)
- (fixture-fn #'(lambda ()
- (electric-pair-mode 1))))
- `(progn
- ,@(cl-loop
- for mode in (eval modes) ;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))))
- ""
- "-in-comments")))
- (if test-in-strings
- `(("\"" "\"" "-in-strings")))
- (if test-in-code
- `(("" "" ""))))
- append
- (cl-loop
- for char across input
- for pos from 0
- unless (eq char ?-)
- collect (electric-pair-define-test-form
- name
- fixture
- (aref input pos)
- pos
- expected-string
- expected-point
- skip-pair-string
- prefix
- suffix
- extra-desc
- mode
- bindings
- fixture-fn))))))
- ;;; Basic pairs and skips
- ;;;
- (define-electric-pair-test balanced-situation
- " (()) " "(((((((" :skip-pair-string "ppppppp"
- :modes '(ruby-mode))
- (define-electric-pair-test too-many-openings
- " ((()) " "(((((((" :skip-pair-string "ppppppp")
- (define-electric-pair-test too-many-closings
- " (())) " "(((((((" :skip-pair-string "------p")
- (define-electric-pair-test too-many-closings-2
- "() ) " "---(---" :skip-pair-string "-------")
- (define-electric-pair-test too-many-closings-3
- ")() " "(------" :skip-pair-string "-------")
- (define-electric-pair-test balanced-autoskipping
- " (()) " "---))--" :skip-pair-string "---ss--")
- (define-electric-pair-test too-many-openings-autoskipping
- " ((()) " "----))-" :skip-pair-string "-------")
- (define-electric-pair-test too-many-closings-autoskipping
- " (())) " "---)))-" :skip-pair-string "---sss-")
- ;;; Mixed parens
- ;;;
- (define-electric-pair-test mixed-paren-1
- " ()] " "-(-(---" :skip-pair-string "-p-p---")
- (define-electric-pair-test mixed-paren-2
- " [() " "-(-()--" :skip-pair-string "-p-ps--")
- (define-electric-pair-test mixed-paren-3
- " (]) " "-(-()--" :skip-pair-string "---ps--")
- (define-electric-pair-test mixed-paren-4
- " ()] " "---)]--" :skip-pair-string "---ss--")
- (define-electric-pair-test mixed-paren-5
- " [() " "----(--" :skip-pair-string "----p--")
- (define-electric-pair-test find-matching-different-paren-type
- " ()] " "-[-----" :skip-pair-string "-------")
- (define-electric-pair-test find-matching-different-paren-type-inside-list
- "( ()]) " "-[-----" :skip-pair-string "-------")
- (define-electric-pair-test ignore-different-nonmatching-paren-type
- "( ()]) " "-(-----" :skip-pair-string "-p-----")
- (define-electric-pair-test autopair-keep-least-amount-of-mixed-unbalance
- "( ()] " "-(-----" :skip-pair-string "-p-----")
- (define-electric-pair-test dont-autopair-to-resolve-mixed-unbalance
- "( ()] " "-[-----" :skip-pair-string "-------")
- (define-electric-pair-test autopair-so-as-not-to-worsen-unbalance-situation
- "( (]) " "-[-----" :skip-pair-string "-p-----")
- (define-electric-pair-test skip-over-partially-balanced
- " [([]) " "-----)---" :skip-pair-string "-----s---")
- (define-electric-pair-test only-skip-over-at-least-partially-balanced-stuff
- " [([()) " "-----))--" :skip-pair-string "-----s---")
- ;;; Quotes
- ;;;
- (define-electric-pair-test pair-some-quotes-skip-others
- " \"\" " "-\"\"-----" :skip-pair-string "-ps------"
- :test-in-strings nil
- :bindings `((electric-pair-text-syntax-table
- . ,prog-mode-syntax-table)))
- (define-electric-pair-test skip-single-quotes-in-ruby-mode
- " '' " "--'-" :skip-pair-string "--s-"
- :modes '(ruby-mode)
- :test-in-comments nil
- :test-in-strings nil
- :bindings `((electric-pair-text-syntax-table
- . ,prog-mode-syntax-table)))
- (define-electric-pair-test leave-unbalanced-quotes-alone
- " \"' " "-\"'-" :skip-pair-string "----"
- :modes '(ruby-mode)
- :test-in-strings nil
- :bindings `((electric-pair-text-syntax-table
- . ,prog-mode-syntax-table)))
- (define-electric-pair-test leave-unbalanced-quotes-alone-2
- " \"\\\"' " "-\"--'-" :skip-pair-string "------"
- :modes '(ruby-mode)
- :test-in-strings nil
- :bindings `((electric-pair-text-syntax-table
- . ,prog-mode-syntax-table)))
- (define-electric-pair-test leave-unbalanced-quotes-alone-3
- " foo\\''" "'------" :skip-pair-string "-------"
- :modes '(ruby-mode)
- :test-in-strings nil
- :bindings `((electric-pair-text-syntax-table
- . ,prog-mode-syntax-table)))
- (define-electric-pair-test inhibit-if-strings-mismatched
- "\"foo\"\"bar" "\""
- :expected-string "\"\"foo\"\"bar"
- :expected-point 2
- :test-in-strings nil
- :bindings `((electric-pair-text-syntax-table
- . ,prog-mode-syntax-table)))
- (define-electric-pair-test inhibit-in-mismatched-string-inside-ruby-comments
- "foo\"\"
- #
- # \"bar\"
- # \" \"
- # \"
- #
- baz\"\""
- "\""
- :modes '(ruby-mode)
- :test-in-strings nil
- :test-in-comments nil
- :expected-point 19
- :expected-string
- "foo\"\"
- #
- # \"bar\"\"
- # \" \"
- # \"
- #
- baz\"\""
- :fixture-fn #'(lambda () (goto-char (point-min)) (search-forward "bar")))
- (define-electric-pair-test inhibit-in-mismatched-string-inside-c-comments
- "foo\"\"/*
- \"bar\"
- \" \"
- \"
- */baz\"\""
- "\""
- :modes '(c-mode)
- :test-in-strings nil
- :test-in-comments nil
- :expected-point 18
- :expected-string
- "foo\"\"/*
- \"bar\"\"
- \" \"
- \"
- */baz\"\""
- :fixture-fn #'(lambda () (goto-char (point-min)) (search-forward "bar")))
- ;;; More quotes, but now don't bind `electric-pair-text-syntax-table'
- ;;; to `prog-mode-syntax-table'. Use the defaults for
- ;;; `electric-pair-pairs' and `electric-pair-text-pairs'.
- ;;;
- (define-electric-pair-test pairing-skipping-quotes-in-code
- " \"\" " "-\"\"-----" :skip-pair-string "-ps------"
- :test-in-strings nil
- :test-in-comments nil)
- (define-electric-pair-test skipping-quotes-in-comments
- " \"\" " "--\"-----" :skip-pair-string "--s------"
- :test-in-strings nil)
- ;;; Skipping over whitespace
- ;;;
- (define-electric-pair-test whitespace-jumping
- " ( ) " "--))))---" :expected-string " ( ) " :expected-point 8
- :bindings '((electric-pair-skip-whitespace . t)))
- (define-electric-pair-test whitespace-chomping
- " ( ) " "--)------" :expected-string " () " :expected-point 4
- :bindings '((electric-pair-skip-whitespace . chomp)))
- (define-electric-pair-test whitespace-chomping-2
- " ( \n\t\t\n ) " "--)------" :expected-string " () " :expected-point 4
- :bindings '((electric-pair-skip-whitespace . chomp))
- :test-in-comments nil)
- (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)
- (define-electric-pair-test whitespace-skipping-for-quotes-not-outside
- " \" \"" "\"-----" :expected-string "\"\" \" \""
- :expected-point 2
- :bindings '((electric-pair-skip-whitespace . chomp))
- :test-in-strings nil
- :test-in-code t
- :test-in-comments nil)
- (define-electric-pair-test whitespace-skipping-for-quotes-only-inside
- " \" \"" "---\"--" :expected-string " \"\""
- :expected-point 5
- :bindings '((electric-pair-skip-whitespace . chomp))
- :test-in-strings nil
- :test-in-code t
- :test-in-comments nil)
- (define-electric-pair-test whitespace-skipping-quotes-not-without-proper-syntax
- " \" \"" "---\"--" :expected-string " \"\"\" \""
- :expected-point 5
- :modes '(text-mode)
- :bindings '((electric-pair-skip-whitespace . chomp))
- :test-in-strings nil
- :test-in-code t
- :test-in-comments nil)
- ;;; Pairing arbitrary characters
- ;;;
- (define-electric-pair-test angle-brackets-everywhere
- "<>" "<>" :skip-pair-string "ps"
- :bindings '((electric-pair-pairs . ((?\< . ?\>)))))
- (define-electric-pair-test angle-brackets-everywhere-2
- "(<>" "-<>" :skip-pair-string "-ps"
- :bindings '((electric-pair-pairs . ((?\< . ?\>)))))
- (defvar electric-pair-test-angle-brackets-table
- (let ((table (make-syntax-table prog-mode-syntax-table)))
- (modify-syntax-entry ?\< "(>" table)
- (modify-syntax-entry ?\> ")<`" table)
- table))
- (define-electric-pair-test angle-brackets-pair
- "<>" "<" :expected-string "<><>" :expected-point 2
- :test-in-code nil
- :bindings `((electric-pair-text-syntax-table
- . ,electric-pair-test-angle-brackets-table)))
- (define-electric-pair-test angle-brackets-skip
- "<>" "->" :expected-string "<>" :expected-point 3
- :test-in-code nil
- :bindings `((electric-pair-text-syntax-table
- . ,electric-pair-test-angle-brackets-table)))
- (define-electric-pair-test pair-backtick-and-quote-in-comments
- ";; " "---`" :expected-string ";; `'" :expected-point 5
- :test-in-comments nil
- :test-in-strings nil
- :modes '(emacs-lisp-mode)
- :bindings '((electric-pair-text-pairs . ((?\` . ?\')))))
- (define-electric-pair-test skip-backtick-and-quote-in-comments
- ";; `foo'" "-------'" :expected-string ";; `foo'" :expected-point 9
- :test-in-comments nil
- :test-in-strings nil
- :modes '(emacs-lisp-mode)
- :bindings '((electric-pair-text-pairs . ((?\` . ?\')))))
- (define-electric-pair-test pair-backtick-and-quote-in-strings
- "\"\"" "-`" :expected-string "\"`'\"" :expected-point 3
- :test-in-comments nil
- :test-in-strings nil
- :modes '(emacs-lisp-mode)
- :bindings '((electric-pair-text-pairs . ((?\` . ?\')))))
- (define-electric-pair-test skip-backtick-and-quote-in-strings
- "\"`'\"" "--'" :expected-string "\"`'\"" :expected-point 4
- :test-in-comments nil
- :test-in-strings nil
- :modes '(emacs-lisp-mode)
- :bindings '((electric-pair-text-pairs . ((?\` . ?\')))))
- (define-electric-pair-test skip-backtick-and-quote-in-strings-2
- " \"`'\"" "----'" :expected-string " \"`'\"" :expected-point 6
- :test-in-comments nil
- :test-in-strings nil
- :modes '(emacs-lisp-mode)
- :bindings '((electric-pair-text-pairs . ((?\` . ?\')))))
- ;;; `js-mode' has `electric-layout-rules' for '{ and '}
- ;;;
- (define-electric-pair-test js-mode-braces
- "" "{" :expected-string "{}" :expected-point 2
- :modes '(js-mode)
- :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)))
- (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)))
- ;;; Backspacing
- ;;; TODO: better tests
- ;;;
- (ert-deftest electric-pair-backspace-1 ()
- (save-electric-modes
- (with-temp-buffer
- (insert "()")
- (goto-char 2)
- (electric-pair-delete-pair 1)
- (should (equal "" (buffer-string))))))
- ;;; Electric newlines between pairs
- ;;; TODO: better tests
- (ert-deftest electric-pair-open-extra-newline ()
- (save-electric-modes
- (with-temp-buffer
- (c-mode)
- (electric-pair-mode 1)
- (electric-indent-mode 1)
- (insert "int main {}")
- (backward-char 1)
- (let ((c-basic-offset 4))
- (newline 1 t)
- (should (equal "int main {\n \n}"
- (buffer-string)))
- (should (equal (point) (- (point-max) 2)))))))
- ;;; Autowrapping
- ;;;
- (define-electric-pair-test autowrapping-1
- "foo" "(" :expected-string "(foo)" :expected-point 2
- :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)))
- (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)))
- (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)))
- (define-electric-pair-test autowrapping-5
- "foo" "\"" :expected-string "\"foo\"" :expected-point 2
- :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)))
- (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)))
- ;;; Electric quotes
- (define-electric-pair-test electric-quote-string
- "" "'" :expected-string "'" :expected-point 2
- :fixture-fn #'electric-quote-local-mode
- :bindings '((electric-quote-string . t))
- :test-in-comments nil :test-in-strings nil)
- (provide 'electric-tests)
- ;;; electric-tests.el ends here
|