From dabaff03992c102c395314629f63ce93a2c1bd3a Mon Sep 17 00:00:00 2001 From: thing1 Date: Tue, 1 Apr 2025 18:10:15 +0000 Subject: init commit --- elpa/evil-1.15.0/evil-tests.el | 9386 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 9386 insertions(+) create mode 100644 elpa/evil-1.15.0/evil-tests.el (limited to 'elpa/evil-1.15.0/evil-tests.el') diff --git a/elpa/evil-1.15.0/evil-tests.el b/elpa/evil-1.15.0/evil-tests.el new file mode 100644 index 0000000..ff896a5 --- /dev/null +++ b/elpa/evil-1.15.0/evil-tests.el @@ -0,0 +1,9386 @@ +;; evil-tests.el --- unit tests for Evil -*- coding: utf-8 -*- + +;; Author: Vegard Øye +;; Maintainer: Vegard Øye + +;; Version: 1.15.0 + +;; +;; This file is NOT part of GNU Emacs. + +;;; License: + +;; This file is part of Evil. +;; +;; Evil 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. +;; +;; Evil 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 Evil. If not, see . + +;;; Commentary: + +;; This file is for developers. It runs some tests on Evil. +;; To load it, run the Makefile target "make test" or add +;; the following lines to .emacs: +;; +;; (setq evil-tests-run nil) ; set to t to run tests immediately +;; (global-set-key [f12] 'evil-tests-run) ; hotkey +;; (require 'evil-tests) +;; +;; Loading this file enables profiling on Evil. The current numbers +;; can be displayed with `elp-results'. The Makefile target +;; "make profiler" shows profiling results in the terminal on the +;; basis of running all tests. +;; +;; To write a test, use `ert-deftest' and specify a :tags value of at +;; least '(evil). The test may inspect the output of functions given +;; certain input, or it may execute a key sequence in a temporary +;; buffer and investigate the results. For the latter approach, the +;; macro `evil-test-buffer' creates a temporary buffer in Normal +;; state. String descriptors initialize and match the contents of +;; the buffer: +;; +;; (ert-deftest evil-test () +;; :tags '(evil) +;; (evil-test-buffer +;; "[T]his creates a test buffer." ; cursor on "T" +;; ("w") ; key sequence +;; "This [c]reates a test buffer."))) ; cursor moved to "c" +;; +;; The initial state, the cursor syntax, etc., can be changed +;; with keyword arguments. See the documentation string of +;; `evil-test-buffer' for more details. +;; +;; This file is NOT part of Evil itself. + +(require 'cl-lib) +(require 'elp) +(require 'ert) +(require 'evil) +(require 'evil-test-helpers) + +;;; Code: + +(defvar evil-tests-run nil + "*Run Evil tests.") + +(defvar evil-tests-profiler nil + "*Profile Evil tests.") + +(defun evil-tests-initialize (&optional tests profiler interactive) + (setq profiler (or profiler evil-tests-profiler)) + (when (listp profiler) + (setq profiler (car profiler))) + (when profiler + (setq evil-tests-profiler t) + (setq profiler + (or (cdr (assq profiler + '((call . elp-sort-by-call-count) + (average . elp-sort-by-average-time) + (total . elp-sort-by-total-time)))))) + (setq elp-sort-by-function (or profiler 'elp-sort-by-call-count)) + (elp-instrument-package "evil")) + (if interactive + (if (y-or-n-p-with-timeout "Run tests? " 2 t) + (evil-tests-run tests interactive) + (message "You can run the tests at any time \ +with `M-x evil-tests-run'")) + (evil-tests-run tests))) + +(defun evil-tests-run (&optional tests interactive) + "Run Evil tests." + (interactive '(nil t)) + (let ((elp-use-standard-output (not interactive))) + (setq tests + (or (null tests) + `(or ,@(mapcar #'(lambda (test) + (or (null test) + (and (memq test '(evil t)) t) + `(or (tag ,test) + ,(format "^%s$" test)))) + tests)))) + (cond + (interactive + (ert-run-tests-interactively tests) + (when evil-tests-profiler + (elp-results))) + (evil-tests-profiler + (ert-run-tests-batch tests) + (elp-results)) + (t + ;; We would like to use `ert-run-tests-batch-and-exit' + ;; Unfortunately it doesn't work outside of batch mode, and we + ;; can't use batch mode because we have tests that need windows. + ;; Instead, run the tests interactively, copy the results to a + ;; text file, and then exit with an appropriate code. + (setq attempt-stack-overflow-recovery nil + attempt-orderly-shutdown-on-fatal-signal nil) + (unwind-protect + (progn + (ert-run-tests-interactively tests) + (with-current-buffer "*ert*" + (append-to-file (point-min) (point-max) "test-results.txt") + (kill-emacs (if (zerop (ert-stats-completed-unexpected ert--results-stats)) 0 1)))) + (unwind-protect + (progn + (append-to-file "Error running tests\n" nil "test-results.txt") + (append-to-file (backtrace-to-string (backtrace-get-frames 'backtrace)) nil "test-results.txt")) + (kill-emacs 2))))))) + +(defun evil-tests-profiler (&optional force) + "Profile Evil tests." + (when (or evil-tests-profiler force) + (setq evil-tests-profiler t) + (elp-instrument-package "evil"))) + +;;; States + +(defun evil-test-local-mode-enabled () + "Verify that `evil-local-mode' is enabled properly" + (ert-info ("Set the mode variable to t") + (should (eq evil-local-mode t))) + (ert-info ("Refresh `emulation-mode-map-alist'") + (should (memq 'evil-mode-map-alist emulation-mode-map-alists))) + (ert-info ("Create a buffer-local value for `evil-mode-map-alist'") + (should (assq 'evil-mode-map-alist (buffer-local-variables)))) + (ert-info ("Initialize buffer-local keymaps") + (should (assq 'evil-normal-state-local-map (buffer-local-variables))) + (should (keymapp evil-normal-state-local-map)) + (should (assq 'evil-emacs-state-local-map (buffer-local-variables))) + (should (keymapp evil-emacs-state-local-map))) + (ert-info ("Don't add buffer-local entries to the default value") + (should-not (rassq evil-normal-state-local-map + (default-value 'evil-mode-map-alist))) + (should-not (rassq evil-emacs-state-local-map + (default-value 'evil-mode-map-alist))))) + +(defun evil-test-local-mode-disabled () + "Verify that `evil-local-mode' is disabled properly" + (ert-info ("Set the mode variable to nil") + (should-not evil-local-mode)) + (ert-info ("Disable all states") + (evil-test-no-states))) + +(defun evil-test-no-states () + "Verify that all states are disabled" + (ert-info ("Set `evil-state' to nil") + (should-not evil-state)) + (ert-info ("Disable all state keymaps") + (dolist (state (mapcar #'car evil-state-properties) t) + (should-not (evil-state-property state :mode t)) + (should-not (memq (evil-state-property state :keymap t) + (current-active-maps))) + (should-not (evil-state-property state :local t)) + (should-not (memq (evil-state-property state :local-keymap t) + (current-active-maps))) + (dolist (map (evil-state-auxiliary-keymaps state)) + (should-not (memq map (current-active-maps))))))) + +(ert-deftest evil-test-toggle-local-mode () + "Toggle `evil-local-mode'" + :tags '(evil state) + (with-temp-buffer + (ert-info ("Enable `evil-local-mode'") + (evil-local-mode 1) + (evil-test-local-mode-enabled)) + (ert-info ("Disable `evil-local-mode'") + (evil-local-mode -1) + (evil-test-local-mode-disabled)))) + +(defun evil-test-change-state (state) + "Change state to STATE and check keymaps" + (let (mode keymap local-mode local-keymap tag) + (evil-change-state state) + (setq mode (evil-state-property state :mode) + keymap (evil-state-property state :keymap t) + local-mode (evil-state-property state :local) + local-keymap (evil-state-property state :local-keymap t) + tag (evil-state-property state :tag t)) + (when (functionp tag) + (setq tag (funcall tag))) + (ert-info ("Update `evil-state'") + (should (eq evil-state state))) + (ert-info ("Ensure `evil-local-mode' is enabled") + (evil-test-local-mode-enabled)) + (ert-info ("Enable state modes") + (should (symbol-value mode)) + (should (symbol-value local-mode))) + (ert-info ("Push state keymaps to the top") + (evil-test-state-keymaps state)) + (ert-info ("Refresh mode line tag") + (should (equal evil-mode-line-tag tag))))) + +(defun evil-test-state-keymaps (state) + "Verify that STATE's keymaps are pushed to the top" + (let ((actual (evil-state-keymaps state)) + (expected `((,(evil-state-property state :local) + . , (evil-state-property state :local-keymap t)) + (,(evil-state-property state :mode) + . ,(evil-state-property state :keymap t))))) + ;; additional keymaps inherited with :enable + (cond + ((eq state 'operator) + (setq expected + `((evil-operator-shortcut-mode + . ,evil-operator-shortcut-map) + (evil-operator-state-local-minor-mode + . ,evil-operator-state-local-map) + (evil-operator-state-minor-mode + . ,evil-operator-state-map) + (evil-motion-state-local-minor-mode + . ,evil-motion-state-local-map) + (evil-motion-state-minor-mode + . ,evil-motion-state-map) + (evil-normal-state-local-minor-mode + . ,evil-normal-state-local-map) + (evil-normal-state-minor-mode + . ,evil-normal-state-map))))) + (let ((actual (butlast actual (- (length actual) + (length expected))))) + (should (equal actual expected)) + (dolist (map actual) + (setq map (cdr-safe map)) + (should (keymapp map)))))) + +(ert-deftest evil-test-exit-normal-state () + "Enter Normal state and then disable all states" + :tags '(evil state) + (with-temp-buffer + (evil-test-change-state 'normal) + (evil-normal-state -1) + (evil-test-no-states))) + +(ert-deftest evil-test-change-states () + "Change between Normal state, Emacs state and Operator-Pending state" + :tags '(evil state) + (with-temp-buffer + (evil-test-change-state 'normal) + (evil-test-change-state 'emacs) + (evil-test-change-state 'normal) + (evil-test-change-state 'operator) + (evil-test-change-state 'normal) + (evil-test-change-state 'emacs) + (evil-test-change-state 'replace) + (evil-test-change-state 'normal))) + +(ert-deftest evil-test-change-to-previous-state () + "Change to some state and back." + :tags '(evil state) + (with-temp-buffer + (evil-test-change-state 'normal) + (evil-test-change-state 'visual) + (evil-test-change-state 'emacs) + (evil-change-to-previous-state) + (should (eq evil-state 'visual)) + (evil-change-to-previous-state) + (should (eq evil-state 'normal)))) + +(ert-deftest evil-test-enter-normal-state-disabled () + "Enter Normal state even if `evil-local-mode' is disabled" + :tags '(evil state) + (with-temp-buffer + (evil-local-mode -1) + (evil-test-local-mode-disabled) + (evil-test-change-state 'normal))) + +(ert-deftest evil-test-execute-in-normal-state () + "Test `evil-execute-in-normal-state'." + :tags '(evil) + (ert-info ("Execute normal state command in insert state") + (evil-test-buffer + "[a]bcdef\n" + ("I") + (should (evil-insert-state-p)) + ("\C-ox") + (ert-info ("Should return to insert state") + (should (evil-insert-state-p))) + "[b]cdef\n" + ("\C-oA") + (ert-info ("Should return to insert state after insert state command") + (should (evil-insert-state-p))) + ("bcdef[]\n")) + (ert-info ("Cursor is placed correctly afterwards") + (evil-test-buffer + :state insert + "abcdefg[]" + ("\C-o~") + "abcdefG[]") + (evil-test-buffer + :state insert + "abcdefg[]" + ("\C-ozz") + "abcdefg[]") + (evil-test-buffer + :state insert + "abc[]defg" + ("\C-o$") + "abcdefg[]") + (evil-test-buffer + :state insert + "abcdefg[]" + ("\C-o^") + "[]abcdefg") + (evil-test-buffer + :state insert + "abcdefg[]" + ("\C-oi") + "abcdef[]g") + (evil-test-buffer + "line1\nli[n]e2" + ("ma" "kA" "\C-o`a") + "line1\nli[]ne2")) + (ert-info ("Can enter replace state and stay in it") + (evil-test-buffer + :state insert + "abc[]defg" + ("\C-oRfoo") + "abcfoog")) + (ert-info ("Insert count is ignored") + (evil-test-buffer + "[]" + ("2i" "abcdef" "\C-o~" "g" [escape]) + "abcdeF[g]")) + (ert-info ("Can execute evil-repeat in normal state") + (evil-test-buffer + ;; Although this is the same in vim, text inserted after the temporary + ;; normal command is not recorded for repetition, which is a subtle + ;; (but arguably more useful) difference + :state insert + "ab[]cfg" + ("\C-o~de\C-o.") + "abCdeF[]g")))) + +(defun evil-test-suppress-keymap (state) + "Verify that `self-insert-command' is suppressed in STATE" + (evil-test-buffer + ";; This buffer is for notes." + (evil-test-change-state state) + ;; TODO: this should be done better + (ert-info ("Disable the state's own keymaps so that the +suppression keymap comes first") + (setq evil-operator-state-minor-mode nil + evil-operator-state-local-minor-mode nil)) + (should (eq (key-binding "Q") #'undefined)) + (ert-info ("Don't insert text") + ;; may or may not signal an error, depending on batch mode + (condition-case nil + (execute-kbd-macro "QQQ") + (error nil)) + (should (string= (buffer-substring 1 4) ";; "))))) + +(ert-deftest evil-test-emacs-state-suppress-keymap () + "`self-insert-command' works in Emacs state" + :tags '(evil state) + (should-error (evil-test-suppress-keymap 'emacs))) + +(ert-deftest evil-test-normal-state-suppress-keymap () + "No `self-insert-command' in Normal state" + :tags '(evil state) + (evil-test-suppress-keymap 'normal)) + +(ert-deftest evil-test-operator-state-suppress-keymap () + "Operator-Pending state should inherit suppression +of `self-insert-command' from Normal state" + :tags '(evil state) + (evil-test-suppress-keymap 'operator)) + +(ert-deftest evil-test-operator-state-shortcut-keymap () + "Enable shortcut keymap in Operator-Pending state" + :tags '(evil state) + (evil-test-buffer + (ert-info ("Activate `evil-operator-shortcut-map' in \ +Operator-Pending state") + (evil-test-change-state 'operator) + (should (rassq evil-operator-shortcut-map + (evil-state-keymaps 'operator))) + (should (keymapp evil-operator-shortcut-map)) + (should evil-operator-shortcut-mode) + (should (memq evil-operator-shortcut-map + (current-active-maps)))) + (ert-info ("Deactivate `evil-operator-shortcut-map' \ +outside Operator-Pending state") + (evil-test-change-state 'emacs) + (should-not evil-operator-shortcut-mode) + (should-not (memq evil-operator-shortcut-map + (current-active-maps)))) + (ert-info ("Reset `evil-operator-shortcut-map' \ +when entering Operator-Pending state") + (define-key evil-operator-shortcut-map "f" 'foo) + (should (eq (lookup-key evil-operator-shortcut-map "f") + 'foo)) + (evil-test-change-state 'operator) + (should-not (eq (lookup-key evil-operator-shortcut-map "f") + 'foo))) + (ert-info ("Reset `evil-operator-shortcut-map' \ +when exiting Operator-Pending state") + (define-key evil-operator-shortcut-map "b" 'bar) + (should (eq (lookup-key evil-operator-shortcut-map "b") + 'bar)) + (evil-test-change-state 'emacs) + (should-not (eq (lookup-key evil-operator-shortcut-map "b") + 'bar))))) + +(ert-deftest evil-test-auxiliary-maps () + "Test auxiliary keymaps" + :tags '(evil state) + (let ((map (make-sparse-keymap)) aux) + (ert-info ("Create a new auxiliary keymap") + (evil-define-key 'normal map "f" 'foo) + (setq aux (evil-get-auxiliary-keymap map 'normal)) + (should (evil-auxiliary-keymap-p aux)) + (should (eq (lookup-key aux "f") 'foo))) + (ert-info ("Add to auxiliary keymap") + (evil-define-key 'normal map "b" 'bar) + (should (eq (lookup-key aux "f") 'foo)) + (should (eq (lookup-key aux "b") 'bar))))) + +(ert-deftest evil-test-global-local-map-binding () + "Test use of `evil-define-key' for binding in global maps." + :tags '(evil state) + (let ((evil-normal-state-map (copy-keymap evil-normal-state-map)) + (evil-normal-state-local-map + (when (keymapp evil-normal-state-local-map) + (copy-keymap evil-normal-state-local-map))) + (global-map (copy-keymap global-map)) + (orig-local-map + (when (keymapp (current-local-map)) + (copy-keymap (current-local-map)))) + (map (or (current-local-map) (make-sparse-keymap)))) + (use-local-map map) + (ert-info ("Bind in a global state map") + (evil-define-key 'normal 'global "f" 'foo) + (should (eq (lookup-key evil-normal-state-map "f") 'foo))) + (ert-info ("Bind in a local state map") + (evil-define-key 'normal 'local "f" 'foo) + (should (eq (lookup-key evil-normal-state-local-map "f") 'foo))) + (ert-info ("Bind in the global map") + (evil-define-key nil 'global "b" 'bar) + (should (eq (lookup-key global-map "b") 'bar))) + (ert-info ("Bind in the local map") + (evil-define-key nil 'local "b" 'bar) + (should (eq (lookup-key (current-local-map) "b") 'bar))) + (use-local-map orig-local-map))) + +;;; Type system + +(ert-deftest evil-test-exclusive-type () + "Expand and contract the `line' type" + :tags '(evil type) + (evil-test-buffer + ";; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + (let* ((first-line 1) + (second-line (progn + (forward-line) + (point))) + (third-line (progn + (forward-line) + (point)))) + (ert-info ("Return the beginning and end unchanged \ +if they are the same") + (should (equal (evil-normalize 1 1 'exclusive) + (list 1 1 'exclusive)))) + (ert-info ("expand to `inclusive' if the end position \ +is at the beginning of a line") + (should (equal (evil-normalize (1+ first-line) second-line 'exclusive) + (list (1+ first-line) (1- second-line) 'inclusive + :expanded t)))) + (ert-info ("expand to `line' if both the beginning and end \ +are at the beginning of a line") + (should (equal (evil-normalize first-line second-line 'exclusive) + (list first-line second-line 'line + :expanded t)))) + (ert-info ("Measure as the strict difference between the end \ +and the beginning") + (should (string= (evil-describe 1 1 'exclusive) + "0 characters")) + (should (string= (evil-describe 1 2 'exclusive) + "1 character")) + (should (string= (evil-describe 5 2 'exclusive) + "3 characters")))))) + +(ert-deftest evil-test-inclusive-type () + "Expand and contract the `inclusive' type" + :tags '(evil type) + (evil-test-buffer + ";; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + (ert-info ("Include the ending character") + (should (equal (evil-expand 1 1 'inclusive) + '(1 2 inclusive :expanded t)))) + (ert-info ("Don't mind if positions are in wrong order") + (should (equal (evil-expand 5 2 'inclusive) + '(2 6 inclusive :expanded t)))) + (ert-info ("Exclude the ending character when contracting") + (should (equal (evil-contract 1 2 'inclusive) + '(1 1 inclusive :expanded nil)))) + (ert-info ("Don't mind positions' order when contracting") + (should (equal (evil-contract 6 2 'inclusive) + '(2 5 inclusive :expanded nil)))) + (ert-info ("Measure as one more than the difference") + (should (string= (evil-describe 1 1 'inclusive) + "1 character")) + (should (string= (evil-describe 5 2 'inclusive) + "4 characters"))))) + +(ert-deftest evil-test-line-type () + "Expand the `line' type" + :tags '(evil type) + (evil-test-buffer + ";; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + (let* ((first-line 1) + (second-line (progn + (forward-line) + (point))) + (third-line (progn + (forward-line) + (point)))) + (ert-info ("Expand to the whole first line") + (should (equal (evil-expand first-line first-line 'line) + (list first-line second-line 'line :expanded t))) + (should (string= (evil-describe first-line first-line 'line) + "1 line"))) + (ert-info ("Expand to the two first lines") + (should (equal (evil-expand first-line second-line 'line) + (list first-line third-line 'line :expanded t))) + (should (string= (evil-describe first-line second-line 'line) + "2 lines")))))) + +(ert-deftest evil-test-block-type () + "Expand and contract the `block' type" + :tags '(evil type) + (evil-test-buffer + ";; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + (let* ((first-line 1) + (second-line (progn + (forward-line) + (point))) + (third-line (progn + (forward-line) + (point)))) + (ert-info ("Expand to a 1x1 block") + (should (equal (evil-expand 1 1 'block) + (list 1 2 'block :expanded t))) + (should (string= (evil-describe 1 1 'block) + "1 row and 1 column"))) + (ert-info ("Expand to a 2x1 block") + (should (equal (evil-expand first-line second-line 'block) + (list first-line (1+ second-line) 'block :expanded t))) + (should (string= (evil-describe first-line second-line 'block) + "2 rows and 1 column"))) + (ert-info ("Expand to a 3x2 block") + (should (equal (evil-expand first-line (1+ third-line) 'block) + (list first-line (1+ (1+ third-line)) + 'block :expanded t))) + (should (string= (evil-describe first-line (1+ third-line) 'block) + "3 rows and 2 columns"))) + (ert-info ("Contract to a 0x0 rectangle") + (should (equal (evil-contract 1 2 'block) + (list 1 1 'block :expanded nil)))) + (ert-info ("Contract to a 2x0 rectangle") + (should (equal (evil-contract first-line (1+ second-line) 'block) + (list first-line second-line 'block :expanded nil)))) + (ert-info ("Contract to a 3x1 rectangle") + (should (equal (evil-contract first-line (1+ (1+ third-line)) 'block) + (list first-line (1+ third-line) + 'block :expanded nil))))))) + +(ert-deftest evil-test-type-transform () + "Test `evil-transform'" + :tags '(evil type) + (evil-test-buffer + ";; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + (ert-info ("Return positions unchanged when passed nil \ +for TYPE or TRANSFORM") + (should (equal (evil-transform nil 1 2 'block) + '(1 2 block))) + (should (equal (evil-transform :expand 1 2 nil) + '(1 2))) + (should (equal (evil-transform nil 1 2 nil) + '(1 2)))) + (ert-info ("Accept markers, but return positions") + (should (equal (evil-transform :expand + (move-marker (make-marker) 1) 1 + 'inclusive) + '(1 2 inclusive :expanded t))) + (should (equal (evil-transform nil (move-marker (make-marker) 1) 2 + nil) + '(1 2)))))) + +(ert-deftest evil-test-type-modifiers () + "Test type modifiers like \"dv}\"" + :tags '(evil type) + (ert-info ("Change `inclusive' motions to `exclusive'") + (evil-test-buffer + "[A]bove some line" + ("dve") + "[e] some line")) + (ert-info ("Change `exclusive' motions to `inclusive'") + (evil-test-buffer + "Above [s]ome line + +Below some empty line" + ("dv}") + "Above[ ] +Below some empty line")) + (ert-info ("Change type to `line'") + (evil-test-buffer + "Above [s]ome line + +Below some empty line" + ("dV}") + "Below [s]ome empty line"))) + +;;; Insertion + +(ert-deftest evil-test-insert () + "Test `evil-insert'" + :tags '(evil insert) + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save" + ("ievil rulz " [escape]) + ";; evil rulz[ ]This buffer is for notes you don't want to save")) + +(ert-deftest evil-test-append () + "Test `evil-append'" + :tags '(evil insert) + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save" + ("aevil rulz " [escape]) + ";; Tevil rulz[ ]his buffer is for notes you don't want to save")) + +(ert-deftest evil-test-visual-append () + "Test `evil-append' from visual state" + :tags '(evil insert) + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save" + ("veA_evil rulz " [escape]) + ";; This_evil rulz[ ] buffer is for notes you don't want to save")) + +(ert-deftest evil-test-open-above () + "Test `evil-open-above'" + :tags '(evil insert) + (evil-test-buffer + ";; This buffer is for notes you don't want to save, +\[;]; and for Lisp evaluation." + ("Oabc\ndef" [escape]) + ";; This buffer is for notes you don't want to save, +abc +de[f] +;; and for Lisp evaluation.") + (ert-info ("Open empty line") + (evil-test-buffer + "(let (var)\n [t]est)\n" + (emacs-lisp-mode) + ("O" [escape]) + "(let (var)\n[\n] test)\n")) + (ert-info ("Open non-empty line") + (evil-test-buffer + "(let (var)\n [t]est)\n" + (emacs-lisp-mode) + ("Odo-it" [escape]) + "(let (var)\n do-i[t]\n test)\n"))) + +(ert-deftest evil-test-open-below () + "Test `evil-open-below'" + :tags '(evil insert) + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save, +;; and for Lisp evaluation." + ("oabc\ndef" [escape]) + ";; This buffer is for notes you don't want to save, +abc +de[f] +;; and for Lisp evaluation.") + (ert-info ("Open empty line") + (evil-test-buffer + "[(]let (var)\n test)\n" + (emacs-lisp-mode) + ("o" [escape]) + "(let (var)\n[\n] test)\n")) + (ert-info ("Open non-empty line") + (evil-test-buffer + "[(]let (var)\n test)\n" + (emacs-lisp-mode) + ("odo-it" [escape]) + "(let (var)\n do-i[t]\n test)\n")) + (let ((evil-auto-indent t)) + (ert-info ("With count") + (evil-test-buffer + "[(]and a\n c)\n" + (emacs-lisp-mode) + ("3ob" [escape]) + "(and a\n b\n b\n [b]\n c)\n")))) + +(ert-deftest evil-test-open-below-folded () + "Test `evil-open-below' on folded lines" + :tags '(evil insert) + (evil-test-buffer + "[l]ine1\n\n(let ()\n var)\n\nlast line\n" + (emacs-lisp-mode) + (hs-minor-mode 1) + ("zm2joABC" [escape]) + "line1\n\n(let ()\n var)\nAB[C]\n\nlast line\n")) + +(ert-deftest evil-test-insert-line () + "Test `evil-insert-line'" + :tags '(evil insert) + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save" + ("Ievil rulz " [escape]) + "evil rulz[ ];; This buffer is for notes you don't want to save")) + +(ert-deftest evil-test-append-line () + "Test `evil-append-line'" + :tags '(evil insert) + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save" + ("Aevil rulz " [escape]) + ";; This buffer is for notes you don't want to saveevil rulz[ ]")) + +(ert-deftest evil-test-insert-digraph () + "Test `evil-insert-digraph'" + :tags '(evil insert) + (ert-info ("Predefined digraph") + (evil-test-buffer + ("i\C-kae") + "æ[]")) + (ert-info ("Custom digraph") + (let ((evil-digraphs-table-user '(((?a ?o) . ?å)))) + (evil-test-buffer + ("i\C-kao") + "å[]"))) + (ert-info ("Digraph in replace state") + (evil-test-buffer + "ab[c]defgh" + ("R\C-kc,") + "abç[d]efgh") + (ert-info ("with count") + (evil-test-buffer + "abc[d]efgh" + ("R\C-u3\C-kd*") + "abcδδδ[g]h")))) + +;;; Repeat system + +(ert-deftest evil-test-normalize-repeat-info () + "Test `evil-normalize-repeat-info'" + :tags '(evil repeat) + (ert-info ("Single array") + (should (equal (evil-normalize-repeat-info + '("abc")) + '([?a ?b ?c]))) + (should (equal (evil-normalize-repeat-info + '("\M-f")) + (list (kbd "M-f"))))) + (ert-info ("Single symbol") + (should (equal (evil-normalize-repeat-info + '(SYM)) + '(SYM)))) + (ert-info ("Arrays only") + (should (equal (evil-normalize-repeat-info + '("abc" [XX YY] "def")) + '([?a ?b ?c XX YY ?d ?e ?f])))) + (ert-info ("Several symbols") + (should (equal (evil-normalize-repeat-info + '(BEG MID END)) + '(BEG MID END)))) + (ert-info ("Arrays with symbol at the beginning") + (should (equal (evil-normalize-repeat-info + '(BEG "abc" [XX YY] "def")) + '(BEG [?a ?b ?c XX YY ?d ?e ?f])))) + (ert-info ("Arrays with symbol at the end") + (should (equal (evil-normalize-repeat-info + '("abc" [XX YY] "def" END)) + '([?a ?b ?c XX YY ?d ?e ?f] END)))) + (ert-info ("Arrays with symbol in the middle") + (should (equal (evil-normalize-repeat-info + '("abc" [XX YY] MID "def" )) + '([?a ?b ?c XX YY] MID [?d ?e ?f])))) + (ert-info ("Concatenate arrays with several symbols") + (should (equal (evil-normalize-repeat-info + '(BEG "abc" [XX YY] MID "def" END)) + '(BEG [?a ?b ?c XX YY] MID [?d ?e ?f] END))))) + +(defun evil-test-repeat-info (keys &optional recorded) + "Execute a sequence of keys and verify that `evil-repeat-ring' +records them correctly. KEYS is the sequence of keys to execute. +RECORDED is the expected sequence of recorded events. +If nil, KEYS is used." + (execute-kbd-macro keys) + (should (equal (evil-normalize-repeat-info (ring-ref evil-repeat-ring 0)) + (list (vconcat (or recorded keys)))))) + +(ert-deftest evil-test-normal-repeat-info-simple-command () + "Save key-sequence after simple editing command in Normal state" + :tags '(evil repeat) + (evil-test-buffer + "[T]his is a test buffer" + (ert-info ("Call simple command without count") + (evil-test-repeat-info "x")) + (ert-info ("Call simple command with count 3") + (evil-test-repeat-info "3x")))) + +(ert-deftest evil-test-normal-repeat-info-char-command () + "Save key-sequence after editing command with character in Normal state" + :tags '(evil repeat) + (evil-test-buffer + "[T]his is a test buffer" + (ert-info ("Call command with character argument without count") + (evil-test-repeat-info "r5")) + (ert-info ("Call command with character argument with count 12") + (evil-test-repeat-info "12rX")))) + +(ert-deftest evil-test-insert-repeat-info () + "Save key-sequence after Insert state" + :tags '(evil repeat) + (evil-test-buffer + (ert-info ("Insert text without count") + (evil-test-repeat-info (vconcat "iABC" [escape]))) + (ert-info ("Insert text with count 42") + (evil-test-repeat-info (vconcat "42iABC" [escape]))))) + +(ert-deftest evil-test-repeat () + "Repeat several editing commands" + :tags '(evil repeat) + (ert-info ("Repeat replace") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save" + ("rX") + "[X]; This buffer is for notes you don't want to save" + ([right right] ".") + "X;[X]This buffer is for notes you don't want to save")) + (ert-info ("Repeat replace with count") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save" + ("2rX") + "X[X] This buffer is for notes you don't want to save" + ([right right] ".") + "XX X[X]is buffer is for notes you don't want to save")) + (ert-info ("Repeat replace without count with a new count") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save" + ("rX") + "[X]; This buffer is for notes you don't want to save" + ([right right] "13.") + "X;XXXXXXXXXXXX[X]is for notes you don't want to save")) + (ert-info ("Repeat replace with count replacing original count") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save" + ("10rX") + "XXXXXXXXX[X]ffer is for notes you don't want to save" + ([right right] "20.") + "XXXXXXXXXXfXXXXXXXXXXXXXXXXXXX[X] don't want to save")) + (ert-info ("Repeat movement in Insert state") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save" + ("i(\M-f)" [escape]) + ";; (This[)] buffer is for notes you don't want to save" + ("w.") + ";; (This) (buffer[)] is for notes you don't want to save"))) + +(ert-deftest evil-test-repeat-register () + "Test repeating a register command." + :tags '(evil repeat) + (evil-test-buffer + "[l]ine 1\nline 2\nline 3\nline 4\n" + ("\"addyy\"aP") + "[l]ine 1\nline 2\nline 3\nline 4\n" + (".") + "[l]ine 1\nline 1\nline 2\nline 3\nline 4\n")) + +(ert-deftest evil-test-repeat-numeric-register () + "Test repeating a command with a numeric register." + :tags '(evil repeat) + (evil-test-buffer + "[l]ine 1\nline 2\nline 3\nline 4\nline 5\n" + ("dd...") + "[l]ine 5\n" + ("\"1P") + "[l]ine 4\nline 5\n" + (".") + "[l]ine 3\nline 4\nline 5\n" + (".") + "[l]ine 2\nline 3\nline 4\nline 5\n" + (".") + "[l]ine 1\nline 2\nline 3\nline 4\nline 5\n")) + +(ert-deftest evil-test-cmd-replace-char () + "Calling `evil-replace-char' should replace characters" + :tags '(evil repeat) + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save" + ("r5") + "[5]; This buffer is for notes you don't want to save" + ("3rX") + "XX[X]This buffer is for notes you don't want to save") + (ert-info ("Replace digraph") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save" + ("r e'") + "[é]; This buffer is for notes you don't want to save" + ("3r c*") + "ξξ[ξ]This buffer is for notes you don't want to save")) + (ert-info ("Replacing \\n should insert only one newline") + (evil-test-buffer + "(setq var xxx [y]yy zzz)\n" + (emacs-lisp-mode) + (setq indent-tabs-mode nil) + ("2r\n") + "(setq var xxx \n [y] zzz)\n"))) + +(ert-deftest evil-test-insert-with-count () + "Test `evil-insert' with repeat count" + :tags '(evil repeat) + (evil-test-buffer + ";; [T]his buffer is for notes" + ("2ievil rulz " [escape]) + ";; evil rulz evil rulz[ ]This buffer is for notes")) + +(ert-deftest evil-test-repeat-insert () + "Test repeating of `evil-insert'" + :tags '(evil repeat) + (ert-info ("Repeat insert") + (evil-test-buffer + "[;]; This buffer is for notes" + ("iABC" [escape]) + "AB[C];; This buffer is for notes" + ("..") + "ABABAB[C]CC;; This buffer is for notes")) + (ert-info ("Repeat insert with count") + (evil-test-buffer + "[;]; This buffer is for notes" + ("2iABC" [escape]) + "ABCAB[C];; This buffer is for notes" + ("..") + "ABCABABCABABCAB[C]CC;; This buffer is for notes")) + (ert-info ("Repeat insert with repeat count") + (evil-test-buffer + "[;]; This buffer is for notes" + ("iABC" [escape]) + "AB[C];; This buffer is for notes" + ("11.") + "ABABCABCABCABCABCABCABCABCABCABCAB[C]C;; This buffer is for notes")) + (ert-info ("Repeat insert with count with repeat with count") + (evil-test-buffer + "[;]; This buffer is for notes" + ("10iABC" [escape]) + "ABCABCABCABCABCABCABCABCABCAB[C];; This buffer is for notes" + ("11.") + "ABCABCABCABCABCABCABCABCABCABABCABCABCABCABCABCABCABCABCABCAB[C]C;; \ +This buffer is for notes"))) + +(ert-deftest evil-test-repeat-error () + "Test whether repeat returns to normal state in case of an error." + (evil-test-buffer + "[l]ine 1\nline 2\nline 3\nline 4" + ("ixxx" [down] [down] [left] [left] [left] "yyy" [escape]) + "xxxline 1\nline 2\nyy[y]line 3\nline 4" + (should-error (execute-kbd-macro "j^.")) + (should (evil-normal-state-p)) + ("^") + "xxxline 1\nline 2\nyyyline 3\n[x]xxline 4")) + +(ert-deftest evil-test-quoted-insert () + "Test evil-quoted-insert in replace state." + (ert-info ("Simple replace C-v") + (evil-test-buffer + "ab[c]defg" + ("R\C-vx") + "abx[d]efg")) + (ert-info ("Control char replace C-v") + (evil-test-buffer + "ab[c]defg" + ("R\C-v\C-g") + "ab[d]efg")) + (ert-info ("C-v with count") + (evil-test-buffer + "ab[c]defg" + ("R\C-u3\C-vx") + "abxxx[f]g")) + (ert-info ("C-v with count near eol") + (evil-test-buffer + "abcde[f]g" + ("R\C-u3\C-vx") + "abcdexxx[]")) + (ert-info ("C-v in replace can be backspaced") + (evil-test-buffer + "ab[c]defg" + ("R\C-u3\C-vx" [backspace]) + "abxx[e]fg"))) + +(ert-deftest evil-test-repeat-quoted-insert () + "Test whether `quoted-insert' can be repeated." + (ert-info ("Insert C-v") + (evil-test-buffer + "lin[e] 1\nline 2\nline 3\n" + ("i\C-v\C-v" [escape]) + "lin[]e 1\nline 2\nline 3\n")) + (ert-info ("Insert ESC") + (evil-test-buffer + "lin[e] 1\nline 2\nline 3\n" + ("i\C-v" [escape escape]) + "lin[]e 1\nline 2\nline 3\n")) + (ert-info ("Block insert C-v") + (evil-test-buffer + "lin[e] 1\nline 2\nline 3\n" + ("gg\C-vGI\C-v\C-v" [escape]) + "[]line 1\nline 2\nline 3\n"))) + +(ert-deftest evil-test-insert-vcount () + "Test `evil-insert' with vertical repeating" + :tags '(evil repeat) + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer. + +;; Below the empty line." + (define-key evil-normal-state-local-map "i" + #'(lambda (count) + (interactive "p") + (evil-insert count 5))) + ("2iABC" [escape]) + "\ +;; ABCAB[C]This buffer is for notes you don't want to save. +;; ABCABCIf you want to create a file, visit that file with C-x C-f, +;; ABCABCthen enter the text in that file's own buffer. + ABCABC +;; ABCABCBelow the empty line.")) + +(ert-deftest evil-test-append-with-count () + "Test `evil-append' with repeat count" + :tags '(evil repeat) + (evil-test-buffer + ";; [T]his buffer is for notes" + ("2aevil rulz " [escape]) + ";; Tevil rulz evil rulz[ ]his buffer is for notes")) + +(ert-deftest evil-test-repeat-append () + "Test repeating of `evil-append'" + :tags '(evil repeat) + (ert-info ("Repeat insert") + (evil-test-buffer + "[;]; This buffer is for notes" + ("aABC" [escape]) + ";AB[C]; This buffer is for notes" + ("..") + ";ABCABCAB[C]; This buffer is for notes")) + (ert-info ("Repeat insert with count") + (evil-test-buffer + "[;]; This buffer is for notes" + ("2aABC" [escape]) + ";ABCAB[C]; This buffer is for notes" + ("..") + ";ABCABCABCABCABCAB[C]; This buffer is for notes")) + (ert-info ("Repeat insert with repeat count") + (evil-test-buffer + "[;]; This buffer is for notes" + ("aABC" [escape]) + ";AB[C]; This buffer is for notes" + ("11.") + ";ABCABCABCABCABCABCABCABCABCABCABCAB[C]; This buffer is for notes")) + (ert-info ("Repeat insert with count with repeat with count") + (evil-test-buffer + "[;]; This buffer is for notes" + ("10aABC" [escape]) + ";ABCABCABCABCABCABCABCABCABCAB[C]; This buffer is for notes" + ("11.") + ";ABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCAB[C]; \ +This buffer is for notes"))) + +(ert-deftest evil-test-append-vcount () + "Test `evil-append' with vertical repeating" + :tags '(evil repeat) + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer. + +;; Below the empty line." + (define-key evil-normal-state-local-map "a" + #'(lambda (count) + (interactive "p") + (evil-append count 5))) + ("2aABC" [escape]) + "\ +;; TABCAB[C]his buffer is for notes you don't want to save. +;; IABCABCf you want to create a file, visit that file with C-x C-f, +;; tABCABChen enter the text in that file's own buffer. + ABCABC +;; BABCABCelow the empty line.")) + +(ert-deftest evil-test-open-above-with-count () + "Test `evil-open-above' with repeat count" + :tags '(evil repeat) + (evil-test-buffer + ";; This buffer is for notes you don't want to save, +\[;]; and for Lisp evaluation." + ("2Oevil\nrulz" [escape]) + ";; This buffer is for notes you don't want to save, +evil\nrulz\nevil\nrul[z] +;; and for Lisp evaluation.")) + +(ert-deftest evil-test-repeat-open-above () + "Test repeating of `evil-open-above'" + :tags '(evil repeat) + (ert-info ("Repeat insert") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save." + ("Oevil\nrulz" [escape]) + "evil\nrul[z] +;; This buffer is for notes you don't want to save." + ("..") + "evil\nevil\nevil\nrul[z]\nrulz\nrulz +;; This buffer is for notes you don't want to save.")) + (ert-info ("Repeat insert with count") + (evil-test-buffer + ";; This buffer is for notes you don't want to save." + ("2Oevil\nrulz" [escape]) + "evil\nrulz\nevil\nrul[z] +;; This buffer is for notes you don't want to save." + ("..") + "evil\nrulz\nevil\nevil\nrulz\nevil\nevil\nrulz\nevil\nrul[z]\nrulz\nrulz +;; This buffer is for notes you don't want to save.")) + (ert-info ("Repeat insert with repeat count") + (evil-test-buffer + ";; This buffer is for notes you don't want to save." + ("Oevil\nrulz" [escape]) + "evil\nrul[z]\n;; This buffer is for notes you don't want to save." + ("2.") + "evil\nevil\nrulz\nevil\nrul[z]\nrulz +;; This buffer is for notes you don't want to save.")) + (ert-info ("Repeat insert with count with repeat with count") + (evil-test-buffer + ";; This buffer is for notes you don't want to save." + ("2Oevil\nrulz" [escape]) + "evil\nrulz\nevil\nrul[z] +;; This buffer is for notes you don't want to save." + ("3.") + "evil\nrulz\nevil\nevil\nrulz\nevil\nrulz\nevil\nrul[z]\nrulz +;; This buffer is for notes you don't want to save."))) + +(ert-deftest evil-test-open-below-with-count () + "Test insertion of `evil-open-below' with repeat count" + :tags '(evil repeat) + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save, +;; and for Lisp evaluation." + ("2oevil\nrulz" [escape]) + ";; This buffer is for notes you don't want to save, +evil\nrulz\nevil\nrul[z] +;; and for Lisp evaluation.")) + +(ert-deftest evil-test-repeat-open-below () + "Test repeating `evil-open-below'" + :tags '(evil repeat) + (ert-info ("Repeat insert") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save, +;; and for Lisp evaluation." + ("oevil\nrulz" [escape]) + ";; This buffer is for notes you don't want to save, +evil\nrul[z]\n;; and for Lisp evaluation." + ("..") + ";; This buffer is for notes you don't want to save, +evil\nrulz\nevil\nrulz\nevil\nrul[z] +;; and for Lisp evaluation.")) + (ert-info ("Repeat insert with count") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save, +;; and for Lisp evaluation." + ("2oevil\nrulz" [escape]) + ";; This buffer is for notes you don't want to save, +evil\nrulz\nevil\nrul[z] +;; and for Lisp evaluation." + ("..") + ";; This buffer is for notes you don't want to save, +evil\nrulz\nevil\nrulz\nevil\nrulz\nevil\nrulz\nevil\nrulz\nevil\nrul[z] +;; and for Lisp evaluation.")) + (ert-info ("Repeat insert with repeat count") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save, +;; and for Lisp evaluation." + ("oevil\nrulz" [escape]) + ";; This buffer is for notes you don't want to save, +evil\nrul[z]\n;; and for Lisp evaluation." + ("2.") + ";; This buffer is for notes you don't want to save, +evil\nrulz\nevil\nrulz\nevil\nrul[z] +;; and for Lisp evaluation.")) + (ert-info ("Repeat insert with count with repeat with count") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save, +;; and for Lisp evaluation." + ("2oevil\nrulz" [escape]) + ";; This buffer is for notes you don't want to save, +evil\nrulz\nevil\nrul[z] +;; and for Lisp evaluation." + ("3.") + ";; This buffer is for notes you don't want to save, +evil\nrulz\nevil\nrulz\nevil\nrulz\nevil\nrulz\nevil\nrul[z] +;; and for Lisp evaluation."))) + +(ert-deftest evil-test-insert-line-with-count () + "Test `evil-insert-line' with repeat count" + :tags '(evil repeat) + (evil-test-buffer + ";; [T]his buffer is for notes" + ("2Ievil rulz " [escape]) + "evil rulz evil rulz[ ];; This buffer is for notes")) + +(ert-deftest evil-test-repeat-insert-line () + "Test repeating of `evil-insert-line'" + :tags '(evil repeat) + (ert-info ("Repeat insert") + (evil-test-buffer + ";; This buffer is for note[s]" + ("IABC" [escape]) + "AB[C];; This buffer is for notes" + ("..") + "AB[C]ABCABC;; This buffer is for notes")) + (ert-info ("Repeat insert with count") + (evil-test-buffer + ";; This buffer is for note[s]" + ("2IABC" [escape]) + "ABCAB[C];; This buffer is for notes" + ("..") + "ABCAB[C]ABCABCABCABC;; This buffer is for notes")) + (ert-info ("Repeat insert with repeat count") + (evil-test-buffer + ";; This buffer is for note[s]" + ("IABC" [escape]) + "AB[C];; This buffer is for notes" + ("11.") + "ABCABCABCABCABCABCABCABCABCABCAB[C]ABC;; This buffer is for notes")) + (ert-info ("Repeat insert with count with repeat with count") + (evil-test-buffer + ";; This buffer is for note[s]" + ("10IABC" [escape]) + "ABCABCABCABCABCABCABCABCABCAB[C];; This buffer is for notes" + ("11.") + "ABCABCABCABCABCABCABCABCABCABCAB[C]ABCABCABCABCABCABCABCABCABCABC;; This buffer is for notes"))) + +(ert-deftest evil-test-insert-line-vcount () + "Test `evil-insert-line' with vertical repeating" + :tags '(evil repeat) + (evil-test-buffer + "int[ ]main(int argc, char** argv) +{ + printf(\"Hello world\\n\"); + return EXIT_SUCCESS; +}" + (define-key evil-normal-state-local-map "I" + #'(lambda (count) + (interactive "p") + (evil-insert-line count 4))) + ("2IABC" [escape]) + "ABCABCint main(int argc, char** argv) +ABCABC{ + ABCABCprintf(\"Hello world\\n\"); + ABCABCreturn EXIT_SUCCESS; +}")) + +(ert-deftest evil-test-append-line-with-count () + "Test `evil-append-line' with repeat count" + :tags '(evil repeat) + (evil-test-buffer + ";; [T]his buffer is for notes." + ("2Aevil rulz " [escape]) + ";; This buffer is for notes.evil rulz evil rulz[ ]")) + +(ert-deftest evil-test-repeat-append-line () + "Test repeating of `evil-append-line'" + :tags '(evil repeat) + (ert-info ("Repeat insert") + (evil-test-buffer + ";; [T]his buffer is for notes." + ("AABC" [escape]) + ";; This buffer is for notes.AB[C]" + ("..") + ";; This buffer is for notes.ABCABCAB[C]")) + (ert-info ("Repeat insert with count") + (evil-test-buffer + ";; [T]his buffer is for notes." + ("2AABC" [escape]) + ";; This buffer is for notes.ABCAB[C]" + ("..") + ";; This buffer is for notes.ABCABCABCABCABCAB[C]")) + (ert-info ("Repeat insert with repeat count") + (evil-test-buffer + ";; [T]his buffer is for notes." + ("AABC" [escape]) + ";; This buffer is for notes.ABC" + ("11.") + ";; This buffer is for notes.ABCABCABCABCABCABCABCABCABCABCABCAB[C]")) + (ert-info ("Repeat insert with count with repeat with count") + (evil-test-buffer + ";; [T]his buffer is for notes." + ("10AABC" [escape]) + ";; This buffer is for notes.ABCABCABCABCABCABCABCABCABCAB[C]" + ("11.") + ";; This buffer is for notes.ABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCABCAB[C]"))) + +(ert-deftest evil-test-append-line-vcount () + "Test `evil-append-line' with vertical repeating" + :tags '(evil repeat) + (evil-test-buffer + "int[ ]main(int argc, char** argv) +{ + printf(\"Hello world\\n\"); + return EXIT_SUCCESS; +}" + (define-key evil-normal-state-local-map "A" + #'(lambda (count) + (interactive "p") + (evil-append-line count 4))) + ("2AABC" [escape]) + "int main(int argc, char** argv)ABCAB[C] +{ABCABC + printf(\"Hello world\\n\");ABCABC + return EXIT_SUCCESS;ABCABC +}")) + +(ert-deftest evil-test-repeat-by-change () + "Test repeating by tracking changes for completion commands" + :tags '(evil repeat) + (let ((line-move-visual nil) + (change (evil-define-command nil () + :repeat change + (interactive) + (delete-char 5) + (insert "BEGIN\n") + (save-excursion + (insert "\nEND\n"))))) + (evil-test-buffer + ";; [T]his buffer is for notes." + (define-key evil-insert-state-local-map (kbd "C-c C-p") change) + ("iABC " (kbd "C-c C-p") "BODY" [escape]) + ";; ABC BEGIN +BOD[Y] +END +buffer is for notes." + (".") + ";; ABC BEGIN +BODABC BEGIN +BOD[Y] +END + +buffer is for notes."))) + +(ert-deftest evil-test-repeat-kill-buffer () + "Test safe-guard preventing buffers from being deleted +when repeating a command" + :tags '(evil repeat) + (ert-info ("Test killing works for direct calls \ +to `evil-execute-repeat-info'") + (evil-test-buffer + "[;]; This buffer is for notes." + (setq evil-repeat-ring (make-ring 10)) + (ring-insert evil-repeat-ring '((kill-buffer nil))) + (evil-execute-repeat-info (ring-ref evil-repeat-ring 0)) + (should-not (looking-at ";; This")))) + (ert-info ("Verify an error is raised when using \ +the `evil-repeat' command") + (evil-test-buffer + "[;]; This buffer is for notes." + (setq evil-repeat-ring (make-ring 10)) + (ring-insert evil-repeat-ring '((kill-buffer nil))) + (evil-execute-repeat-info (ring-ref evil-repeat-ring 0)) + (should-error (call-interactively #'evil-repeat))))) + +(ert-deftest evil-test-repeat-pop () + "Test `repeat-pop'." + :tags '(evil repeat) + (ert-info ("Test repeat-pop") + (evil-test-buffer + ";; [T]his buffer is for notes." + (setq evil-repeat-ring (make-ring 10)) + ("iABC" [escape] "aXYZ" [escape]) + ";; ABCXY[Z]This buffer is for notes." + (".") + ";; ABCXYZXY[Z]This buffer is for notes.")) + (ert-info ("Test repeat-pop") + (evil-test-buffer + ";; [T]his buffer is for notes." + (setq evil-repeat-ring (make-ring 10)) + ("iABC" [escape] "aXYZ" [escape]) + ";; ABCXY[Z]This buffer is for notes." + ("." (kbd "C-.")) + ";; ABCXYAB[C]ZThis buffer is for notes.")) + (ert-info ("Test repeat-pop-next") + (evil-test-buffer + ";; [T]his buffer is for notes." + (setq evil-repeat-ring (make-ring 10)) + ("iABC" [escape] "aXYZ" [escape]) + ";; ABCXY[Z]This buffer is for notes." + ("." (kbd "C-.") (kbd "M-.")) + ";; ABCXYZXY[Z]This buffer is for notes.")) + (ert-info ("Test repeat-pop after non-change") + (evil-test-buffer + ";; [T]his buffer is for notes." + (setq evil-repeat-ring (make-ring 10)) + ("iABC" [escape] "a" [escape] "aXYZ" [escape]) + ";; ABCXY[Z]This buffer is for notes." + ("." (kbd "C-.") (kbd "C-.")) + ";; ABCXYAB[C]ZThis buffer is for notes."))) + +(ert-deftest evil-test-ESC-repeat-normal-state () + "Test if ESC is not been recorded in normal state." + :tags '(evil repeat) + (ert-info ("Test normal ESC") + (evil-test-buffer + ";;[ ]This buffer is for notes." + (setq evil-repeat-ring (make-ring 10)) + (should (= (ring-length evil-repeat-ring) 0)) + ("aABC" [escape]) + ";; AB[C]This buffer is for notes." + (should (= (ring-length evil-repeat-ring) 1)) + (".") + ";; ABCAB[C]This buffer is for notes." + ([escape]) + (should (= (ring-length evil-repeat-ring) 1)) + (".") + ";; ABCABCAB[C]This buffer is for notes."))) + +(ert-deftest evil-test-abort-operator-repeat () + "Test if ESC in operator-state cancels recording of repeation." + :tags '(evil repeat) + (let ((inhibit-quit t)) + (ert-info ("Test ESC") + (evil-test-buffer + ";;[ ]This buffer is for notes." + (setq evil-repeat-ring (make-ring 10)) + (should (= (ring-length evil-repeat-ring) 0)) + ("aABC" [escape]) + ";; AB[C]This buffer is for notes." + (should (= (ring-length evil-repeat-ring) 1)) + (".") + ";; ABCAB[C]This buffer is for notes." + ("d" [escape]) + (should (= (ring-length evil-repeat-ring) 1)) + (".") + ";; ABCABCAB[C]This buffer is for notes.")))) + +(ert-deftest evil-test-repeat-with-find-char () + "Ensure that repeating find-char commands doesn't change `evil-last-find'" + :tags '(evil repeat) + (evil-test-buffer + "[b]ar baz bat" + ("dfa" "fb") + "r [b]az bat" + (".") + "r [z] bat" + (";") + "r z [b]at")) + +(ert-deftest evil-test-repeat-visual-char () + "Test repeat of character visual mode command." + :tags '(evil repeat) + (ert-info ("Test repeat on same line") + (evil-test-buffer + ";; [T]his buffer is for notes." + ("v3lcABC" [escape]) + ";; AB[C] buffer is for notes." + ("ww.") + ";; ABC buffer AB[C]or notes.")) + (ert-info ("Test repeat on several lines") + (evil-test-buffer + ";; This [b]uffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer. +" + ("vj^eerX") + ";; This XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +XXXX[X] you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer. +" + ("2gg^3w.") + ";; This XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +XXXXX you want XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +XXXX[X]en enter the text in that file's own buffer. +"))) + +(ert-deftest evil-test-repeat-visual-line () + "Test repeat of linewise visual mode command." + :tags '(evil repeat) + (ert-info ("Test repeat on several lines") + (evil-test-buffer + ";; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter th[e] text in that file's own buffer. + +;; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer. +" + ("VkcNew Text" [escape]) + ";; This buffer is for notes you don't want to save. +New Tex[t] + +;; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer. +" + ("jj.") + ";; This buffer is for notes you don't want to save. +New Text + +New Tex[t] +;; then enter the text in that file's own buffer. +"))) + +(ert-deftest evil-test-repeat-visual-block () + "Test repeat of block visual mode command." + :tags '(evil repeat) + (ert-info ("Test repeat on several lines") + (evil-test-buffer + ";; This [b]uffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer. +;; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer. +" + ((kbd "C-v") "3j2lrQ") + ";; This [Q]QQfer is for notes you don't want to save. +;; If yoQQQant to create a file, visit that file with C-x C-f, +;; then QQQer the text in that file's own buffer. +;; This QQQfer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer. +" + ("2j3w.") + ";; This QQQfer is for notes you don't want to save. +;; If yoQQQant to create a file, visit that file with C-x C-f, +;; then QQQer the text [Q]QQthat file's own buffer. +;; This QQQfer is for nQQQs you don't want to save. +;; If you want to creatQQQ file, visit that file with C-x C-f, +;; then enter the text QQQthat file's own buffer. +"))) + +(ert-deftest evil-visual-block-append () + "Test appending in visual block." + :tags '(evil visual insert) + (ert-info ("Simple append") + (evil-test-buffer + "l[i]ne 1\nline 2\nline 3\n" + ((kbd "C-v") "jjllAXXX" [escape]) + "lineXX[X] 1\nlineXXX 2\nlineXXX 3\n")) + (ert-info ("Append after empty lines") + (evil-test-buffer + "line 1l[i]ne 1\nline 2\nline 3line 3\n" + (setq indent-tabs-mode nil) + ((kbd "C-v") "jjllAXXX" [escape]) + "line 1lineXX[X] 1\nline 2 XXX\nline 3lineXXX 3\n")) + (ert-info ("Append after empty first line") + (evil-test-buffer + "l[i]ne 1line 1\nline 2\nline 3line 3line 3\n" + (setq indent-tabs-mode nil) + ((kbd "C-v") "jj3feAXXX" [escape]) + "line 1line 1 XX[X]\nline 2 XXX\nline 3line 3lineXXX 3\n")) + (ert-info ("Append after end of lines") + (evil-test-buffer + "line 1l[i]ne 1line 1\nline 2\nline 3line 3\n" + (setq indent-tabs-mode nil) + ((kbd "C-v") "jj$AXXX" [escape]) + "line 1line 1line 1XX[X]\nline 2XXX\nline 3line 3XXX\n"))) + +(ert-deftest evil-test-repeat-digraph () + "Test repeat of insertion of a digraph." + :tags '(evil digraph repeat) + (evil-test-buffer + "Line with ['] several apostrophes ', yeah." + ("s" (kbd "C-k") "'9" [escape]) + "Line with [’] several apostrophes ', yeah." + ("f'.") + "Line with ’ several apostrophes [’], yeah.")) + +;;; Operators + +(ert-deftest evil-test-keypress-parser () + "Test `evil-keypress-parser'" + :tags '(evil operator) + (evil-test-buffer + :state operator + (ert-info ("Read from the keyboard unless INPUT is given") + (evil-test-buffer + :state operator + (let ((unread-command-events '(?d))) + (should (equal (evil-keypress-parser) + '(evil-delete nil))) + (should (equal (evil-keypress-parser '(?d)) + '(evil-delete nil)))))) + (ert-info ("Read remainder from the keyboard if INPUT is incomplete") + (let ((unread-command-events '(?d))) + (should (equal (evil-keypress-parser '(?2)) + '(evil-delete 2))))) + (ert-info ("Handle counts not starting with zero") + (should (equal (evil-keypress-parser '(?2 ?d)) + '(evil-delete 2))) + (should (equal (evil-keypress-parser '(?2 ?0 ?d)) + '(evil-delete 20))) + (should (equal (evil-keypress-parser '(?2 ?0 ?2 ?d)) + '(evil-delete 202))) + (should (equal (evil-keypress-parser '(?4 ?0 ?4 ?g ??)) + '(evil-rot13 404)))) + (ert-info ("Treat 0 as a motion") + (should (equal + (evil-keypress-parser '(?0)) + '(evil-beginning-of-line nil)))) + (ert-info ("Handle keyboard macros") + (evil-test-buffer + (define-key evil-motion-state-local-map (kbd "W") (kbd "w")) + (should (equal (evil-keypress-parser '(?W)) + '(evil-forward-word-begin nil))))))) + +(ert-deftest evil-test-invert-char () + "Test `evil-invert-char'" + :tags '(evil operator) + (evil-test-buffer + ";; [T]his buffer is for notes." + ("~") + ";; t[h]is buffer is for notes.") + (evil-test-buffer + ";; <[T]his> buffer is for notes." + ("~") + ";; [t]HIS buffer is for notes.") + (evil-test-buffer + :visual block + ";; <[T]his buffer is for notes, +;; and >for Lisp evaluation." + ("~") + ";; [t]HIS buffer is for notes, +;; AND for Lisp evaluation.")) + +(ert-deftest evil-test-rot13 () + "Test `evil-rot13'" + :tags '(evil operator) + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save." + ("g?" [M-right]) + ";; [G]uvf buffer is for notes you don't want to save.")) + +(ert-deftest evil-test-rot13-with-count () + "Test `evil-rot13' with count argument" + :tags '(evil operator) + (ert-info ("Count before operator") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save." + ("2g?" [M-right]) + ";; [G]uvf ohssre is for notes you don't want to save.")) + (ert-info ("Count before motion") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save." + ("g?2" [M-right]) + ";; [G]uvf ohssre is for notes you don't want to save.")) + (ert-info ("Count before operator and motion") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save." + ("3g?2" [M-right]) + ";; [G]uvf ohssre vf sbe abgrf lbh don't want to save.")) + (ert-info ("Count exceeding buffer boundaries") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save." + ("g?200" [right]) + ";; [G]uvf ohssre vf sbe abgrf lbh qba'g jnag gb fnir."))) + +(ert-deftest evil-test-rot13-repeat () + "Test repeating of `evil-rot13'" + :tags '(evil operator) + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save." + ("g?" [M-right] [M-right]) + ";; Guvf[ ]buffer is for notes you don't want to save." + (".") + ";; Guvf[ ]ohssre is for notes you don't want to save.")) + +(ert-deftest evil-test-rot13-repeat-with-count () + "Test repeating of `evil-rot13' with new count" + :tags '(evil operator) + (ert-info ("Count before operator") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save." + ("2g?" [M-right]) + ";; [G]uvf ohssre is for notes you don't want to save." + ("3.") + ";; [T]his buffer vf for notes you don't want to save.")) + (ert-info ("Count before motion") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save." + ("g?2" [M-right]) + ";; [G]uvf ohssre is for notes you don't want to save." + ("3.") + ";; [T]his buffer vf for notes you don't want to save.")) + (ert-info ("Count before operator and motion") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save." + ("3g?2" [M-right]) + ";; [G]uvf ohssre vf sbe abgrf lbh don't want to save." + ("4.") + ";; [T]his buffer is for abgrf lbh don't want to save."))) + +(ert-deftest evil-test-operator-delete () + "Test deleting text" + :tags '(evil operator) + (ert-info ("Delete characters") + (evil-test-buffer + ";; [T]his buffer is for notes." + ("dl") + ";; [h]is buffer is for notes." + ("d1l") + ";; [i]s buffer is for notes." + ("1dl") + ";; [s] buffer is for notes." + ("1d1l") + ";; [ ]buffer is for notes." + ("d2l") + ";; [u]ffer is for notes." + ("2dl") + ";; [f]er is for notes." + ("d4l") + ";; [i]s for notes." + ("4dl") + ";; [o]r notes." + ("2d2l") + ";; [o]tes.")) + (ert-info ("Delete current line") + (ert-info ("With `evil-start-of-line' `nil'") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save, +;; and for Lisp evaluation." + ("dd") + ";; [a]nd for Lisp evaluation.") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save, +;; and for Lisp evaluation." + ("d1d") + ";; [a]nd for Lisp evaluation.") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save, +;; and for Lisp evaluation." + ("1dd") + ";; [a]nd for Lisp evaluation.") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save, +;; and for Lisp evaluation." + ("1d1d") + ";; [a]nd for Lisp evaluation.")) + (ert-info ("With `evil-start-of-line' `t'") + (let ((evil-start-of-line t)) + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save, +;; and for Lisp evaluation." + ("dd") + "[;]; and for Lisp evaluation.") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save, +;; and for Lisp evaluation." + ("d1d") + "[;]; and for Lisp evaluation.") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save, +;; and for Lisp evaluation." + ("1dd") + "[;]; and for Lisp evaluation.") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save, +;; and for Lisp evaluation." + ("1d1d") + "[;]; and for Lisp evaluation.")))) + (ert-info ("Delete two lines") + (ert-info ("With `evil-start-of-line' `nil'") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + ("d2d") + ";; [t]hen enter the text in that file's own buffer.") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + ("2dd") + ";; [t]hen enter the text in that file's own buffer.") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + ("dj") + ";; [t]hen enter the text in that file's own buffer.") + (evil-test-buffer + ";; This buffer is for notes you don't want to save. +;; [I]f you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + ("dk") + ";; [t]hen enter the text in that file's own buffer.")) + (ert-info ("With `evil-start-of-line' `t'") + (let ((evil-start-of-line t)) + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + ("d2d") + "[;]; then enter the text in that file's own buffer.") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + ("2dd") + "[;]; then enter the text in that file's own buffer.") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + ("dj") + "[;]; then enter the text in that file's own buffer.") + (evil-test-buffer + ";; This buffer is for notes you don't want to save. +;; [I]f you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + ("dk") + "[;]; then enter the text in that file's own buffer."))))) + +(evil-define-motion evil-test-square-motion (count) + "Test motion for selecting a square." + :type block + (let ((column (current-column))) + (forward-line (1- count)) + (move-to-column (+ column count -1)))) + +(ert-deftest evil-test-yank () + "Test `evil-yank'" + :tags '(evil operator yank) + (ert-info ("Yank characters") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save." + ("y2e") + (should (string= (current-kill 0) "This buffer")))) + (ert-info ("Yank lines") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + ("yj") + (should (string= (current-kill 0) + (buffer-substring (point-min) + (1+ (line-end-position 2))))) + (should (eq (car-safe (get-text-property 0 'yank-handler + (current-kill 0))) + 'evil-yank-line-handler))) + (evil-test-buffer + ";; This buffer is for notes you don't want to save. +\[;]; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + ("y5j") + (should + (string= (current-kill 0) + (concat (buffer-substring (line-beginning-position 1) + (point-max)) + "\n"))) + (should (eq (car-safe (get-text-property 0 'yank-handler + (current-kill 0))) + 'evil-yank-line-handler)))) + (ert-info ("Yank rectangle") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) + ("y3s") + (should (string= (current-kill 0) "Thi\nIf \nthe")) + (should (eq (car-safe (get-text-property 0 'yank-handler + (current-kill 0))) + 'evil-yank-block-handler)))) + (ert-info (":yank, then paste") + (evil-test-buffer + "a\n[b]\nc\nd\n" + (":yank" [return] "p") + "a\nb\nb\nc\nd\n")) + (ert-info (":yank with COUNT") + (evil-test-buffer + "a\n[b]\nc\nd\n" + (":yank 2" [return] "p") + "a\nb\nb\nc\nc\nd\n")) + (ert-info (":yank with COUNT in visual state") + (evil-test-buffer + "a\n\nd\ne\nf\n" + (":yank 3" [return] "p") + "a\nb\nc\nd\ne\nc\nd\ne\nf\n")) + (ert-info (":yank with REGISTER") + (evil-test-buffer + "a\n[b]\nc\nd\n" + (":yank r") ;; yank into the 'r' register + "a\nb\nc\nd\n" + ;; check the 'r' register contains the yanked text + (should (string= (substring-no-properties (evil-get-register ?r)) "b\n")))) + (ert-info (":yank with REGISTER and COUNT") + (evil-test-buffer + "a\n[b]\nc\nd\ne\nf\n" + (":yank r 3") + "a\nb\nc\nd\ne\nf\n" + (should (string= (substring-no-properties (evil-get-register ?r)) "b\nc\nd\n")))) + (ert-info (":yank with range yanks without moving point") + (evil-test-buffer + "[a]\nb\nc\nd\ne\n" + (":4y" [return] "p") + "a\n[d]\nb\nc\nd\ne\n") + (evil-test-buffer + "[a]\nb\nc\nd\ne\n" + (":+4y" [return] "p") + "a\n[e]\nb\nc\nd\ne\n"))) + +(ert-deftest evil-test-delete () + "Test `evil-delete'" + :tags '(evil operator delete) + (ert-info ("Delete characters") + (evil-test-buffer + ";; This buffer is for notes you don't want to save[.]" + ("x") + ";; This buffer is for notes you don't want to sav[e]" + (goto-char 4) + ";; [T]his buffer is for notes you don't want to save" + ("d2e") + ";; [ ]is for notes you don't want to save" + (should (string= (current-kill 0) "This buffer")) + ("P") + ";; This buffe[r] is for notes you don't want to save")) + (ert-info ("Delete lines") + (ert-info ("With `evil-start-of-line' `nil'") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + ("2dd") + ";; [t]hen enter the text in that file's own buffer." + ("P") + "[;]; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer.")) + (ert-info ("With `evil-start-of-line' `t'") + (let ((evil-start-of-line t)) + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + ("2dd") + "[;]; then enter the text in that file's own buffer." + ("P") + "[;]; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer.")))) + (ert-info ("Delete last line") + (evil-test-buffer + ";; This buffer is for notes you don't want to save. +;; [I]f you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + ("2dd") + ";; [T]his buffer is for notes you don't want to save.")) + (ert-info ("Delete last empty line") + (evil-test-buffer + "line 1\nline 2\n\n[]" + ("dd") + "line 1\nline 2\n[]")) + (ert-info ("Delete rectangle") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) + ("d3s") + "[T]his buffer is for notes you don't want to save. +If you want to create a file, visit that file with C-x C-f, +then enter the text in that file's own buffer.")) + (ert-info (":delete") + (evil-test-buffer + "a\n[b]\nc\nd\n" + (":delete") + "a\nc\nd\n")) + (ert-info (":delete with COUNT") + (evil-test-buffer + "a\n[b]\nc\nd\n" + (":delete 2") + "a\nd\n")) + (ert-info (":delete with COUNT in visual state") + (evil-test-buffer + "a\n\nd\ne\nf\n" + (":delete 3") + "a\nb\nf\n")) + (ert-info (":delete with REGISTER") + (evil-test-buffer + "a\n[b]\nc\nd\n" + (":delete r") ;; delete into the 'r' register + "a\nc\nd\n" + ;; check the 'r' register contains the deleted text + (should (string= (substring-no-properties (evil-get-register ?r)) "b\n")))) + (ert-info (":delete with REGISTER and COUNT") + (evil-test-buffer + "a\n[b]\nc\nd\ne\nf\n" + (":delete r 3") + "a\ne\nf\n" + (should (string= (substring-no-properties (evil-get-register ?r)) "b\nc\nd\n")))) + (ert-info ("Charwise multiple whole line delete becomes linewise") + (evil-test-buffer + "1\n[2]\n3\n4" + ("d2w") + "1\n[4]"))) + +(ert-deftest evil-test-delete-line () + "Test `evil-delete-line'" + :tags '(evil operator) + (ert-info ("Delete to end of line") + (evil-test-buffer + ";; This buffer is for notes[ ]you don't want to save." + ("D") + ";; This buffer is for note[s]")) + (ert-info ("Act linewise on character selection") + (evil-test-buffer + ";; This is for notes, +and for Lisp evaluation." + ("D") + "[a]nd for Lisp evaluation.")) + (ert-info ("Act on each line of block selection") + (evil-test-buffer + :visual block + ";; This buffer is for ." + ("D") + ";; This buffer is for[ ] +;; and for Lisp evalua")) + (ert-info ("Yank full block with block selection") + (evil-test-buffer + :visual block + "line1 le3 line3\n" + ("D") + "line1 [l]\nline2 l\nline3 l\n" + ("0P") + "ine1 line1 line1line1 l +ine2 line2 l +ine3 line3 line3 l\n"))) + +(ert-deftest evil-test-delete-folded () + "Test `evil-delete' on folded lines." + :tags '(evil operator) + (ert-info ("Delete folded lines") + (evil-test-buffer + "[l]ine1\n\n(let ()\n var)\n\n(let ()\n var2)\n" + (emacs-lisp-mode) + (hs-minor-mode 1) + ("zm2jdd") + "line1\n\n[\n](let ()\n var2)\n")) + (ert-info ("Delete folded lines with count") + (evil-test-buffer + "[l]ine1\n\n(let ()\n var)\n\n(let ()\n var2)\n\nlast line\n" + (emacs-lisp-mode) + (hs-minor-mode 1) + ("zm2j3dd") + "line1\n\n[\n]last line\n"))) + +(ert-deftest evil-test-delete-backward-word () + "Test `evil-delete-backward-word' in insert & replace states." + :tags '(evil) + (ert-info ("evil-delete-backward-word in insert state") + (let ((evil-backspace-join-lines t)) + (evil-test-buffer + "abc def\n ghi j[k]l\n" + ("i" (kbd "C-w")) + "abc def\n ghi [k]l\n" + ((kbd "C-w")) + "abc def\n [k]l\n" + ((kbd "C-w")) + "abc def\n[k]l\n" + ((kbd "C-w")) + "abc def[k]l\n")) + (let (evil-backspace-join-lines) + (evil-test-buffer + "abc def\n[k]l\n" + (should-error (execute-kbd-macro (concat "i" (kbd "C-w")))) + "abc def\n[k]l\n"))) + (ert-info ("evil-delete-backward-word in replace state") + (evil-test-buffer + "alpha bravo [c]harlie delta" + ("R" "one two") + "alpha bravo one two[ ]delta" + ("\C-w") + "alpha bravo one [l]ie delta" + ("\C-w") + "alpha bravo [c]harlie delta" + ("\C-w") + "alpha [b]ravo charlie delta"))) + +(ert-deftest evil-test-delete-back-to-indentation () + "Test `evil-delete-back-to-indentation' in insert & replace states." + :tags '(evil) + (let ((evil-backspace-join-lines t)) + (evil-test-buffer + "abc def\n ghi j[k]l\n" + ("i" (call-interactively #'evil-delete-back-to-indentation)) + "abc def\n [k]l\n" + (left-char 2) + "abc def\n [ ] kl\n" + (call-interactively #'evil-delete-back-to-indentation) + "abc def\n[ ] kl\n" + (call-interactively #'evil-delete-back-to-indentation) + "abc def[ ] kl\n")) + (let (evil-backspace-join-lines) + (evil-test-buffer + "abc def\n[k]l\n" + (should-error + (progn + (execute-kbd-macro "i") + (call-interactively #'evil-delete-back-to-indentation))) + "abc def\n[k]l\n")) + (ert-info ("Delete back to indentation in replace state") + (evil-test-buffer + " alpha [b]ravo charlie" + ("R" "delta") + " alpha delta[ ]charlie" + (evil-delete-back-to-indentation) + " [a]lpha bravo charlie"))) + +(ert-deftest evil-test-change () + "Test `evil-change'" + :tags '(evil operator) + (ert-info ("Change characters") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save." + ("c2eABC" [escape]) + ";; AB[C] is for notes you don't want to save." + (should (string= (current-kill 0) "This buffer")) + ("p") + ";; ABCThis buffe[r] is for notes you don't want to save.")) + (ert-info ("Change lines") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + ("2ccABCLINE\nDEFLINE" [escape]) + "ABCLINE +DEFLIN[E] +;; then enter the text in that file's own buffer." + ("p") + "ABCLINE +DEFLINE +\[;]; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer.")) + (ert-info ("Change last line") + (evil-test-buffer + ";; This buffer is for notes you don't want to save. +;; [I]f you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + ("2ccABC" [escape]) + ";; This buffer is for notes you don't want to save. +AB[C]")) + (ert-info ("C changes whole line in visual characterwise and linewise states") + (evil-test-buffer + "Two lines [s]hould suffice +for this test." + ("veC" "all gone!") + "all gone![] +for this test.") + (evil-test-buffer + "Two lines [w]ill be fine +for this test too." + ("VjC" "all gone!") + "all gone![]")) + (ert-info ("C clears the visual blockwise selection, and all text to the right") + (evil-test-buffer + "Two [l]ines will be fine for +the tests here as well." + ("\C-vjeC") + "Two [] +the ")) + (ert-info ("S clears the whole line in normal mode, and all lines touched by visual selection") + (evil-test-buffer + "Two lines [s]hould suffice +for this test." + ("S" "all gone!") + "all gone![] +for this test.") + (evil-test-buffer + "Two lines [s]hould suffice +for this test." + ("vS" "all gone!") + "all gone![] +for this test.") + (evil-test-buffer + "Two lines [s]hould suffice +for this test." + ("VjS" "all gone!") + "all gone![]") + (evil-test-buffer + "Two lines [s]hould suffice +for this test." + ("\C-VjS" "all gone!") + "all gone![]")) + (ert-info ("R behaves the same as S in visual modes") + (evil-test-buffer + "Two lines [s]hould suffice +for this test." + ("vR" "all gone!") + "all gone![] +for this test.")) + (ert-info ("Change rectangle") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) + ("c3sABC" [escape]) + "AB[C]This buffer is for notes you don't want to save. +ABCIf you want to create a file, visit that file with C-x C-f, +ABCthen enter the text in that file's own buffer."))) + +(ert-deftest evil-maybe-remove-spaces-test () + "Test maybe removing (indentation) spaces after some commands when making a clear line." + :tags '(evil operator) + (ert-info ("changing the line and returning to normal mode removes spaces") + (evil-test-buffer + (emacs-lisp-mode) + ("i(one two" [return] "three" [return] "four" [return] "five" [escape] "?three" [return]) + "(one two + [t]hree + four + five" + ("cc" "new line" [escape] "+") + "(one two + new line + [f]our + five" + ("cc" [escape]) + "(one two + new line +[] + five"))) + +(ert-deftest evil-test-change-word () + "Test changing words" + :tags '(evil operator) + (ert-info ("Non-word") + (evil-test-buffer + "[;]; This buffer is for notes." + ("cwABC" [escape]) + "AB[C] This buffer is for notes.")) + (ert-info ("Word") + (evil-test-buffer + ";; [T]his buffer is for notes." + ("cwABC" [escape]) + ";; AB[C] buffer is for notes.")) + (ert-info ("Single character") + (evil-test-buffer + "[;] This buffer is for notes." + ("cwABC" [escape]) + "AB[C] This buffer is for notes.")) + (ert-info ("Whitespace") + (evil-test-buffer + "This[ ]is a test\n" + ("cwABC" [escape]) + "ThisAB[C]is a test\n"))) + +(ert-deftest evil-test-join () + "Test `evil-join'" + :tags '(evil join operator) + (ert-info ("Simple") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f." + ("J") + ";; This buffer is for notes you don't want to save.[ ]\ +;; If you want to create a file, visit that file with C-x C-f.")) + (ert-info ("Visual") + (evil-test-buffer + :visual line + "<;; [T]his buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f.>" + ("J") + ";; This buffer is for notes you don't want to save.[ ]\ +;; If you want to create a file, visit that file with C-x C-f.")) + (ert-info ("Join with count") + (evil-test-buffer + "[l]ine 1\nline 2\nline 3\nline 4" + (":join 3") + "line 1 line 2 line 3\nline 4")) + (ert-info ("Join with bang and count") + (evil-test-buffer + "[l]ine 1\nline 2\nline 3\nline 4" + (":join! 3") + "line 1line 2line 3\nline 4")) + (ert-info ("Join with bang and count, exceeding end-of-buffer") + (evil-test-buffer + "[l]ine 1\nline 2\nline 3\nline 4" + (":join! 10") + "line 1line 2line 3line 4")) + (ert-info ("Join with count 1 should be the same as without count") + (evil-test-buffer + "[l]ine 1\nline 2\nline 3\nline 4" + (":join 1") + "line 1 line 2\nline 3\nline 4")) + (ert-info ("Join with count 2 should be the same as with count 1") + (evil-test-buffer + "[l]ine 1\nline 2\nline 3\nline 4" + (":join 2") + "line 1 line 2\nline 3\nline 4")) + (ert-info ("Join with count and single line range") + (evil-test-buffer + "[l]ine 1\nline 2\nline 3\nline 4" + (":2join 3") + "line 1\nline 2 line 3 line 4")) + (ert-info ("Join with count and range") + (evil-test-buffer + "[l]ine 1\nline 2\nline 3\nline 4" + (":1,2join 3") + "line 1\nline 2 line 3 line 4")) + (ert-info ("Join with count, range and bang") + (evil-test-buffer + "[l]ine 1\nline 2\nline 3\nline 4" + (":1,2join! 3") + "line 1\nline 2line 3line 4")) + (ert-info ("Join with range") + (evil-test-buffer + "[l]ine 1\nline 2\nline 3\nline 4" + (":1,3join") + "line 1 line 2 line 3\nline 4")) + ) + +(ert-deftest evil-test-substitute () + "Test `evil-substitute'" + :tags '(evil operator) + (ert-info ("Simple") + (evil-test-buffer + ";; [T]his buffer is for notes." + ("5sABC" [escape]) + ";; AB[C]buffer is for notes.")) + (ert-info ("On empty line") + (evil-test-buffer + "Above some line +\[] +Below some empty line" + ("5sABC" [escape]) + "Above some line +AB[C] +Below some empty line"))) + +(ert-deftest evil-test-shift () + "Test `evil-shift-right' and `evil-shift-left'." + :tags '(evil operator) + (let ((evil-shift-width 4) + indent-tabs-mode) + (ert-info ("Shift linewise") + (ert-info ("With `evil-start-of-line' `nil'") + (evil-test-buffer + "[l]ine 1\nline 2\nline 3\n" + ("Vj>") + "[ ] line 1\n line 2\nline 3\n")) + (ert-info ("With `evil-start-of-line' `t'") + (let ((evil-start-of-line t)) + (evil-test-buffer + "[l]ine 1\nline 2\nline 3\n" + ("Vj>") + " [l]ine 1\n line 2\nline 3\n")))) + (ert-info ("Shift char selection on whole line") + (ert-info ("With `evil-start-of-line' `nil'") + (evil-test-buffer + "[l]ine 1\nline 2\nline 3\n" + ("v$>") + " line [1]\nline 2\nline 3\n")) + (ert-info ("With `evil-start-of-line' `t'") + (let ((evil-start-of-line t)) + (evil-test-buffer + "[l]ine 1\nline 2\nline 3\n" + ("v$>") + " [l]ine 1\nline 2\nline 3\n")))) + (ert-info ("Shift visual with count") + (ert-info ("With `evil-start-of-line' `nil'") + (evil-test-buffer + "[l]ine 1\nline 2\nline 3\n" + ("Vj3>") + "[ ] line 1\n line 2\nline 3\n" + ("Vj2<") + "[ ] line 1\n line 2\nline 3\n")) + (ert-info ("With `evil-start-of-line' `t'") + (let ((evil-start-of-line t)) + (evil-test-buffer + "[l]ine 1\nline 2\nline 3\n" + ("Vj3>") + " [l]ine 1\n line 2\nline 3\n" + ("Vj2<") + " [l]ine 1\n line 2\nline 3\n")))) + (ert-info ("Shift in insert state") + (evil-test-buffer + "line 1\nl[i]ne 2\nline 3\n" + ("i\C-t\C-t") + "line 1\n l[i]ne 2\nline 3\n" + ("\C-d") + "line 1\n l[i]ne 2\nline 3\n")) + (ert-info ("Delete all indentation in insert state") + (evil-test-buffer + "line1\n sometext[ ]" + ("a" "somemore" "0\C-d") + "line1\nsometext somemore[]")))) + +;;; Paste + +(ert-deftest evil-test-paste-before () + "Test `evil-paste-before'" + :tags '(evil paste) + (ert-info ("Paste characters") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save, +;; and for Lisp evaluation." + ("y2ej0") + ";; This buffer is for notes you don't want to save, +\[;]; and for Lisp evaluation." + ("P") + ";; This buffer is for notes you don't want to save, +This buffe[r];; and for Lisp evaluation.")) + (ert-info ("Paste characters with count") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save, +;; and for Lisp evaluation." + ("y2ej0") + ";; This buffer is for notes you don't want to save, +\[;]; and for Lisp evaluation." + ("3P") + ";; This buffer is for notes you don't want to save, +This bufferThis bufferThis buffe[r];; and for Lisp evaluation.")) + (ert-info ("Paste characters at end-of-buffer") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save, +;; and for Lisp evaluation." + ("y2eG$") + ";; This buffer is for notes you don't want to save, +;; and for Lisp evaluation[.]" + ("2P") + ";; This buffer is for notes you don't want to save, +;; and for Lisp evaluationThis bufferThis buffe[r].")) + (ert-info ("Paste lines") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save, +;; and for Lisp evaluation." + ("2yyP") + "[;]; This buffer is for notes you don't want to save, +;; and for Lisp evaluation. +;; This buffer is for notes you don't want to save, +;; and for Lisp evaluation.")) + (ert-info ("Paste lines with count") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save, +;; and for Lisp evaluation." + ("2yy2P") + "[;]; This buffer is for notes you don't want to save, +;; and for Lisp evaluation. +;; This buffer is for notes you don't want to save, +;; and for Lisp evaluation. +;; This buffer is for notes you don't want to save, +;; and for Lisp evaluation.")) + (ert-info ("Paste lines at end-of-buffer") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save, +;; and for Lisp evaluation." + ("2yyG$") + ";; This buffer is for notes you don't want to save, +;; and for Lisp evaluation[.]" + ("2P") + ";; This buffer is for notes you don't want to save, +\[;]; This buffer is for notes you don't want to save, +;; and for Lisp evaluation. +;; This buffer is for notes you don't want to save, +;; and for Lisp evaluation. +;; and for Lisp evaluation.")) + (ert-info ("Paste block") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) + ("3ysP") + "[;]; ;; This buffer is for notes you don't want to save. +;; ;; If you want to create a file, visit that file with C-x C-f, +;; ;; then enter the text in that file's own buffer.")) + (ert-info ("Paste block with count") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) + ("3ys2P") + "[;]; ;; ;; This buffer is for notes you don't want to save. +;; ;; ;; If you want to create a file, visit that file with C-x C-f, +;; ;; ;; then enter the text in that file's own buffer.")) + (ert-info ("Paste block with empty line") + (evil-test-buffer + "[;]; Above some line + +;; Below some empty line" + (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) + ("3ys2P") + "[;]; ;; ;; Above some line + \n\ +;; ;; ;; Below some empty line")) + (ert-info ("Paste block crossing end of buffer") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) + ("3ysj") + ";; This buffer is for notes you don't want to save. +\[;]; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + ("P") + ";; This buffer is for notes you don't want to save. +\[;]; ;; If you want to create a file, visit that file with C-x C-f, +;; ;; then enter the text in that file's own buffer. +;;")) + (ert-info ("Paste block at end-of-line") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) + ("3ys$") + ";; This buffer is for notes you don't want to save[.] +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + ("p") + ";; This buffer is for notes you don't want to save.[;]; +;; If you want to create a file, visit that file wi;; th C-x C-f, +;; then enter the text in that file's own buffer. ;;"))) + +(ert-deftest evil-test-paste-after () + "Test `evil-paste-after'" + :tags '(evil paste) + (ert-info ("Paste characters") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save, +;; and for Lisp evaluation." + ("y2ej0") + ";; This buffer is for notes you don't want to save, +\[;]; and for Lisp evaluation." + ("p") + ";; This buffer is for notes you don't want to save, +;This buffe[r]; and for Lisp evaluation.")) + (ert-info ("Paste characters with count") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save, +;; and for Lisp evaluation." + ("y2ej0") + ";; This buffer is for notes you don't want to save, +\[;]; and for Lisp evaluation." + ("3p") + ";; This buffer is for notes you don't want to save, +;This bufferThis bufferThis buffe[r]; and for Lisp evaluation.")) + (ert-info ("Paste characters at end-of-buffer") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save, +;; and for Lisp evaluation." + ("y2eG$") + ";; This buffer is for notes you don't want to save, +;; and for Lisp evaluation[.]" + ("2p") + ";; This buffer is for notes you don't want to save, +;; and for Lisp evaluation.This bufferThis buffe[r]")) + (ert-info ("Paste lines") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save, +;; and for Lisp evaluation." + ("2yyp") + ";; This buffer is for notes you don't want to save, +\[;]; This buffer is for notes you don't want to save, +;; and for Lisp evaluation. +;; and for Lisp evaluation.")) + (ert-info ("Paste lines with count") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save, +;; and for Lisp evaluation." + ("2yy2p") + ";; This buffer is for notes you don't want to save, +\[;]; This buffer is for notes you don't want to save, +;; and for Lisp evaluation. +;; This buffer is for notes you don't want to save, +;; and for Lisp evaluation. +;; and for Lisp evaluation.")) + (ert-info ("Paste lines at end-of-buffer") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save, +;; and for Lisp evaluation." + ("2yyG$") + ";; This buffer is for notes you don't want to save, +;; and for Lisp evaluation[.]" + ("2p") + ";; This buffer is for notes you don't want to save, +;; and for Lisp evaluation. +\[;]; This buffer is for notes you don't want to save, +;; and for Lisp evaluation. +;; This buffer is for notes you don't want to save, +;; and for Lisp evaluation.")) + (ert-info ("Paste block") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) + ("3ysp") + ";[;]; ; This buffer is for notes you don't want to save. +;;; ; If you want to create a file, visit that file with C-x C-f, +;;; ; then enter the text in that file's own buffer.")) + (ert-info ("Paste block with count") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) + ("3ys2p") + ";[;]; ;; ; This buffer is for notes you don't want to save. +;;; ;; ; If you want to create a file, visit that file with C-x C-f, +;;; ;; ; then enter the text in that file's own buffer.")) + (ert-info ("Paste block with empty line") + (evil-test-buffer + "[;]; Above some line + +;; Below some empty line" + (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) + ("3ys2p") + ";;; ;; ; Above some line + +;;; ;; ; Below some empty line")) + (ert-info ("Paste block crossing end of buffer") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) + ("3ysj") + ";; This buffer is for notes you don't want to save. +\[;]; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + ("p") + ";; This buffer is for notes you don't want to save. +;;; ; If you want to create a file, visit that file with C-x C-f, +;;; ; then enter the text in that file's own buffer. + ;;")) + (ert-info ("Paste block at end-of-line") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) + ("3ys$") + ";; This buffer is for notes you don't want to save[.] +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + ("p") + ";; This buffer is for notes you don't want to save.;; +;; If you want to create a file, visit that file wi;; th C-x C-f, +;; then enter the text in that file's own buffer. ;;")) + (ert-info ("Paste preserves preceding text properties") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + (put-text-property (point) (line-end-position) 'font-lock-face 'warning) + ("yyp") + ";; This buffer is for notes you don't want to save. +[;]; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + (should (equal (get-text-property (point-min) 'font-lock-face) 'warning))))) + +(ert-deftest evil-test-paste-pop-before () + "Test `evil-paste-pop' after `evil-paste-before'" + :tags '(evil paste) + (ert-info ("Paste") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) + ("y2e2yyy3sj") + ";; This buffer is for notes you don't want to save. +\[;]; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + ("P") + ";; This buffer is for notes you don't want to save. +\[;]; ;; If you want to create a file, visit that file with C-x C-f, +;; ;; then enter the text in that file's own buffer. +;;")) + (ert-info ("Single pop") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) + ("y2e2yyy3sjP\C-p") + ";; This buffer is for notes you don't want to save. +\[;]; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer.")) + (ert-info ("Two pops") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) + ("y2e2yyy3sjP\C-p\C-p") + ";; This buffer is for notes you don't want to save. +;; Thi[s];; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer.")) + (ert-info ("Pop with count") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) + ("y2e2yyy3sjP2\C-p") + ";; This buffer is for notes you don't want to save. +;; Thi[s];; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer.")) + (ert-info ("Single pop-next") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) + ("y2e2yyy3sjP2\C-p\C-n") + ";; This buffer is for notes you don't want to save. +\[;]; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer.")) + (ert-info ("Pop-next with count") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) + ("y2e2yyy3sjP\C-p\C-p2\C-n") + ";; This buffer is for notes you don't want to save. +\[;]; ;; If you want to create a file, visit that file with C-x C-f, +;; ;; then enter the text in that file's own buffer. +;;"))) + +(ert-deftest evil-test-paste-pop-after () + "Test `evil-paste-pop' after `evil-paste-after'" + :tags '(evil paste) + (ert-info ("Paste") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) + ("y2e2yyy3sj") + ";; This buffer is for notes you don't want to save. +\[;]; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + ("p") + ";; This buffer is for notes you don't want to save. +;[;]; ; If you want to create a file, visit that file with C-x C-f, +;;; ; then enter the text in that file's own buffer. + ;;")) + (ert-info ("Single pop") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) + ("y2e2yyy3sjp\C-p") + ";; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +\[;]; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer.")) + (ert-info ("Two pops") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) + ("y2e2yyy3sjp\C-p\C-p") + ";; This buffer is for notes you don't want to save. +;;; Thi[s]; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer.")) + (ert-info ("Pop with count") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) + ("y2e2yyy3sjp2\C-p") + ";; This buffer is for notes you don't want to save. +;;; Thi[s]; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer.")) + (ert-info ("Single pop-next") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) + ("y2e2yyy3sjp2\C-p\C-n") + ";; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +\[;]; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer.")) + (ert-info ("Pop-next with count") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) + ("y2e2yyy3sjp\C-p\C-p2\C-n") + ";; This buffer is for notes you don't want to save. +;[;]; ; If you want to create a file, visit that file with C-x C-f, +;;; ; then enter the text in that file's own buffer. + ;;"))) + +(ert-deftest evil-test-paste-pop-without-undo () + "Test `evil-paste-pop' with undo disabled" + :tags '(evil paste) + (ert-info ("Pop-next with count without undo") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + (setq buffer-undo-list t) + (define-key evil-operator-state-local-map "s" 'evil-test-square-motion) + ("y2e2yyy3sjP\C-p\C-p2\C-n") + ";; This buffer is for notes you don't want to save. +\[;]; ;; If you want to create a file, visit that file with C-x C-f, +;; ;; then enter the text in that file's own buffer. +;;"))) + +(ert-deftest evil-test-visual-paste () + "Test `evil-paste-before' and `evil-paste-after' in Visual state" + :tags '(evil paste) + (evil-test-buffer + ";; This buffer is for notes you don't want to save. +;; [I]f you want to create a file, visit that file with C-x C-f." + ("yyk") + ";; [T]his buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f." + ("VP") + "[;]; If you want to create a file, visit that file with C-x C-f. +;; If you want to create a file, visit that file with C-x C-f.") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f." + ("yyj") + ";; This buffer is for notes you don't want to save. +;; [I]f you want to create a file, visit that file with C-x C-f." + ("Vp") + ";; This buffer is for notes you don't want to save. +\[;]; This buffer is for notes you don't want to save.") + (ert-info ("Visual-paste from register 3") + ;; This behaviour deviates from vim, which populates registers 1-9 with + ;; deleted text only, not yanked text. This is an aspect of `evil-yank's + ;; use of the emacs kill-ring, so is consistent with non-visual paste. + (evil-test-buffer + "[w]ord1a word1b word1c word1d +word2a word2b word2c word2d" + ("yiwwyiwwyiw") + "word1a word1b [w]ord1c word1d +word2a word2b word2c word2d" + ("+viw\"3p") + "word1a word1b word1c word1d +word1[a] word2b word2c word2d")) + (ert-info ("Visual-paste respects `evil-kill-on-visual-paste'") + (evil-test-buffer + "[w]ord1 word2 word3" + (setq evil-kill-on-visual-paste nil) + ("yewyew") + "word1 word2 [w]ord3" + ("ve\"2p") + "word1 word2 word[1]" + ("o\C-r\"") + "word1 word2 word1 +word2[]") + (evil-test-buffer + "[w]ord1 word2 word3" + (setq evil-kill-on-visual-paste t) + ("yewyew") + "word1 word2 [w]ord3" + ("ve\"2p") + "word1 word2 word[1]" + ("o\C-r\"") + "word1 word2 word1 +word3[]")) + (ert-info ("Visual-paste from `=' register") + (evil-test-buffer + "foo" + ("viw" "\"=p(* 6 7)" [return]) + "4[2]")) + (ert-info ("Blockwise visual paste (of charwise text) with count") + (evil-test-buffer + "[a]bc\n123\n123\n123" + ("ye" "jl" "\C-vG" "2p") + "abc\n1[a]bcabc3\n1abcabc3\n1abcabc3" + ("gv") ;; Test point & mark are stored correctly + "abc\n13")) + (ert-info ("Blockwise visual paste of linewise text") + (evil-test-buffer + "[a]bc\n123\n123\n123" + ("yy" "jl" "\C-vG" "p") + "abc\n1\nabc\n3\n1\nabc\n3\n1\nabc\n3"))) + +(ert-deftest evil-test-visual-paste-pop () + "Test `evil-paste-pop' after visual paste." + :tags '(evil paste) + (ert-info ("Visual-char paste, char paste") + (evil-test-buffer + "[w]ord1a word1b word1c\nword2a word2b\nword3a word3b word3c word3d\n" + ("yiwyywyiw^jw") + "word1a word1b word1c\nword2a [w]ord2b\nword3a word3b word3c word3d\n" + ("viwp") + "word1a word1b word1c\nword2a word1[b]\nword3a word3b word3c word3d\n")) + (ert-info ("Visual-char paste, char paste, line pop") + (evil-test-buffer + "[w]ord1a word1b word1c\nword2a word2b\nword3a word3b word3c word3d\n" + ("yiwyywyiw^jw") + "word1a word1b word1c\nword2a [w]ord2b\nword3a word3b word3c word3d\n" + ("viwp\C-p") + "word1a word1b word1c\nword2a \n[w]ord1a word1b word1c\n\nword3a word3b word3c word3d\n")) + (ert-info ("Visual-char paste, char paste, line pop, char pop") + (evil-test-buffer + "[w]ord1a word1b word1c\nword2a word2b\nword3a word3b word3c word3d\n" + ("yiwyywyiw^jw") + "word1a word1b word1c\nword2a [w]ord2b\nword3a word3b word3c word3d\n" + ("viwp\C-p\C-p") + "word1a word1b word1c\nword2a word1[a]\nword3a word3b word3c word3d\n")) + (ert-info ("Visual-line paste, char paste") + (evil-test-buffer + "[w]ord1a word1b word1c\nword2a word2b\nword3a word3b word3c word3d\n" + ("yiwyywyiw^j") + "word1a word1b word1c\n[w]ord2a word2b\nword3a word3b word3c word3d\n" + ("Vp") + "word1a word1b word1c\nword1[b]word3a word3b word3c word3d\n")) + (ert-info ("Visual-line paste, char paste, line pop") + (evil-test-buffer + "[w]ord1a word1b word1c\nword2a word2b\nword3a word3b word3c word3d\n" + ("yiwyywyiw^j") + "word1a word1b word1c\n[w]ord2a word2b\nword3a word3b word3c word3d\n" + ("Vp\C-p") + "word1a word1b word1c\n[w]ord1a word1b word1c\nword3a word3b word3c word3d\n")) + (ert-info ("Visual-line paste, char paste, line pop, char pop") + (evil-test-buffer + "[w]ord1a word1b word1c\nword2a word2b\nword3a word3b word3c word3d\n" + ("yiwyywyiw^j") + "word1a word1b word1c\n[w]ord2a word2b\nword3a word3b word3c word3d\n" + ("Vp\C-p\C-p") + "word1a word1b word1c\nword1[a]word3a word3b word3c word3d\n"))) + +(ert-deftest evil-test-register () + "Test yanking and pasting to and from register." + :tags '(evil yank paste) + (ert-info ("simple lower case register") + (evil-test-buffer + "[f]oo\n" + ("\"ayw\"aP") + "fo[o]foo\n" + ("\"ayy\"aP") + "[f]oofoo\nfoofoo\n")) + (ert-info ("upper case register") + (evil-test-buffer + "[f]oo\n" + ("\"ayw\"Ayw\"aP") + "foofo[o]foo\n" + ("\"ayy\"Ayy\"aP") + "[f]oofoofoo\nfoofoofoo\nfoofoofoo\n")) + (ert-info ("upper case register and lines") + (evil-test-buffer + "[l]ine 1\nline 2\nline 3\nline 4\n" + ("\"a2Yjj\"A2Y\"aP") + "line 1\nline 2\n[l]ine 1\nline 2\nline 3\nline 4\nline 3\nline 4\n" + ("8G\"ap") + "line 1\nline 2\nline 1\nline 2\nline 3\nline 4\nline 3\nline 4\n[l]ine 1\nline 2\nline 3\nline 4\n")) + (ert-info ("yank with count") + (evil-test-buffer + "[l]ine 1\nline 2\nline 3\n" + ("\"a2yw\"aP") + "line [1]line 1\nline 2\nline 3\n" + ("\"a2yy\"aP") + "[l]ine 1line 1\nline 2\nline 1line 1\nline 2\nline 3\n")) + (dolist (module '(evil-search isearch)) + (evil-select-search-module 'evil-search-module module) + (ert-info ((format "special register / (module: %s)" module)) + (evil-test-buffer + "[f]oo bar\n" + ("/bar" [return] "0i\C-r/") + "bar[f]oo bar\n"))) + (ert-info ("special register :") + (evil-test-buffer + "[f]oo bar\n" + (":noh\ni\C-r:"))) + (ert-info ("Paste from register during change to register") + (evil-test-buffer + "[a]lpha beta" + ("\"ayiw" "w" "\"bciw" "\C-ra") + "alpha alpha[]")) + (ert-info ("Paste from register in replace state") + (evil-test-buffer + "[a]lpha bravo charlie" + ("yiw" "w" "R" "\C-r0") + "alpha alpha[ ]charlie" + ([backspace] [backspace] [backspace]) + "alpha al[a]vo charlie"))) + +(ert-deftest evil-test-last-insert-register () + "Test last insertion register." + (evil-test-buffer + "[l]ine 1\n" + ("GiABC" [escape]) + "line 1\nAB[C]" + ("go\".P") + "AB[C]line 1\nABC")) + +(ert-deftest evil-test-zero-register () + "\"0 contains the last text that was yanked without specificying a register." + (evil-test-buffer + "[l]ine 1\nline 2\n" + ("yy\"0p") + "line 1\n[l]ine 1\nline 2\n" + ("j\"ayy\"0p") + "line 1\nline 1\nline 2\n[l]ine 1\n" ; yanked line 2 to "a, so "0 is still line 1 + ("kdd\"0p") + "line 1\nline 1\nline 1\n[l]ine 1\n")) + +(ert-deftest evil-test-=-register () + "\"= is not really a register . It inserts the result of evaluating some elisp" + (ert-info ("Can eval elisp, and can fetch default (last) result") + (evil-test-buffer + :state insert + "8x8= []" + ("\C-r=(* 8 8)" [return]) + "8x8= 64" + ([return] "16x4= \C-r=" [return]) + "8x8= 64 +16x4= 64")) + + (ert-info ("Can eval infix math, and can use register at prompt") + (evil-test-buffer + "[5]0/10 * 100 = " + ("\"nyt=" "A\C-r=" "\C-rn" [return]) + "50/10 * 100 = 500"))) + +(ert-deftest evil-test-ex-put () + "evil-ex-put inserts text linewise, regardless of yank-handler" + (ert-info ("Can put linewise text from default register, by line number") + (evil-test-buffer + "[L]orem ipsum dolor sit amet +consectetur adipiscing elit +sed do eiusmod tempor incididunt" + ("yy:2put" [return]) + "Lorem ipsum dolor sit amet +consectetur adipiscing elit +[L]orem ipsum dolor sit amet +sed do eiusmod tempor incididunt")) + + (ert-info ("Can put blockwise text from letter register, backwards") + (evil-test-buffer + "Lorem ipsum [d]olor sit amet +consectetur adipiscing elit +sed do eiusmod tempor incididunt" + ("\C-vje\"xy" "bye" "Vj" ":put! x" [return]) + "Lorem ipsum dolor sit amet +dolor sit +[a]dipiscing +consectetur adipiscing elit +sed do eiusmod tempor incididunt")) + + (ert-info ("Can supply args and put from = register") + (evil-test-buffer + "[L]ine one." + (":put = (* 6 7)" [return]) + "Line one. +[4]2"))) + +(ert-deftest evil-test-align () + "Test `evil-align-left', `evil-align-right' and `evil-align-center'." + :tags '(evil operator) + (evil-without-display + (let ((fill-column 70) + indent-tabs-mode) + (evil-test-buffer + "before\n[l]ine 1\nthis is line number 2\nline number 3\nafter\n" + (":.,+2ri" [return] (kbd "M-x") "untabify" [return]) + "before\n [l]ine 1\n this is line number 2\n line number 3\nafter\n" + (":.,+2ri 60" [return] (kbd "M-x") "untabify" [return]) + "before\n [l]ine 1\n this is line number 2\n line number 3\nafter\n" + (":.,+2le" [return] (kbd "M-x") "untabify" [return]) + "before\n[l]ine 1\nthis is line number 2\nline number 3\nafter\n" + (":.,+2le 10" [return]) + "before\n [l]ine 1\n this is line number 2\n line number 3\nafter\n" + (":.,+2ce" [return] (kbd "M-x") "untabify" [return]) + "before\n [l]ine 1\n this is line number 2\n line number 3\nafter\n" + (":.,+2ce 40" [return] (kbd "M-x") "untabify" [return]) + "before\n [l]ine 1\n this is line number 2\n line number 3\nafter\n")))) + +;;; Motions + +(ert-deftest evil-test-forward-char () + "Test `evil-forward-char' motion" + :tags '(evil motion) + (ert-info ("Simple") + (evil-test-buffer + "[;]; This buffer is for notes." + ("l") + ";[;] This buffer is for notes.")) + (ert-info ("End of line") + (let ((evil-cross-lines t) + (evil-move-beyond-eol nil)) + (evil-test-buffer + ";; This buffer is for notes[,] +;; and for Lisp evaluation." + ("l") + ";; This buffer is for notes, +\[;]; and for Lisp evaluation."))) + (ert-info ("With count") + (evil-test-buffer + "[;]; This buffer is for notes." + ("12l") + ";; This buff[e]r is for notes.")) + (ert-info ("End of line") + (evil-test-buffer + ";; This buffer is for notes[.]" + (should-error (execute-kbd-macro "l")) + (should-error (execute-kbd-macro "10l")))) + (ert-info ("Until end-of-line") + (evil-test-buffer + "[;]; This buffer is for notes." + ("100l") + ";; This buffer is for notes[.]")) + (ert-info ("On empty line") + (evil-test-buffer + "Above some line +\[] +Below some empty line" + (should-error (execute-kbd-macro "l")) + (should-error (execute-kbd-macro "42l"))))) + +(ert-deftest evil-test-backward-char () + "Test `evil-backward-char' motion" + :tags '(evil motion) + (ert-info ("Simple") + (evil-test-buffer + ";; This[ ]buffer is for notes." + ("h") + ";; Thi[s] buffer is for notes.")) + (ert-info ("With count") + (evil-test-buffer + ";; This[ ]buffer is for notes." + ("3h") + ";; T[h]is buffer is for notes.")) + (ert-info ("Beginning of line") + (evil-test-buffer + "[;]; This buffer is for notes." + (should-error (execute-kbd-macro "h")) + (should-error (execute-kbd-macro "10h")))) + (ert-info ("Until beginning-of-line") + (evil-test-buffer + ";; This[ ]buffer is for notes." + ("100h") + "[;]; This buffer is for notes.")) + (ert-info ("On empty line") + (evil-test-buffer + "Above some line +\[] +Below some empty line" + (should-error (execute-kbd-macro "h")) + (should-error (execute-kbd-macro "42h"))))) + +(ert-deftest evil-test-previous-line () + "Test `evil-previous-line' motion" + :tags '(evil motion) + (ert-info ("Simple") + (evil-test-buffer + ";; This buffer is for notes you don't want to save, +;; [a]nd for Lisp evaluation." + ("k") + ";; [T]his buffer is for notes you don't want to save, +;; and for Lisp evaluation.")) + (ert-info ("With count") + (evil-test-buffer + ";; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; [t]hen enter the text in that file's own buffer." + ("2k") + ";; [T]his buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer.")) + (ert-info ("Until beginning of buffer") + (evil-test-buffer + ";; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; [t]hen enter the text in that file's own buffer." + ("100k") + ";; [T]his buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer.")) + (ert-info ("At beginning of buffer") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save." + (should-error (execute-kbd-macro "k")) + (should-error (execute-kbd-macro "42k"))))) + +(ert-deftest evil-test-next-line () + "Test `evil-next-line' motion" + :tags '(evil motion) + (ert-info ("Simple") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save, +;; and for Lisp evaluation." + ("j") + ";; This buffer is for notes you don't want to save, +;; [a]nd for Lisp evaluation.")) + (ert-info ("With count") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + ("2j") + ";; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; [t]hen enter the text in that file's own buffer.")) + (ert-info ("Until end of buffer") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + ("100j") + ";; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; [t]hen enter the text in that file's own buffer.")) + (ert-info ("At end of buffer") + (evil-test-buffer + ";; This buffer is for notes you don't want to [s]ave." + (should-error (execute-kbd-macro "j")) + (should-error (execute-kbd-macro "42j"))))) + +(ert-deftest evil-test-next+previous-preserve-column () + "Test `evil-previous-line' and `evil-next-line' preserve the column." + :tags '(evil motion) + (ert-info ("Simple") + (evil-test-buffer + "ab[c]\nabcdef\n\nabcd\n" + ("j") + "abc\nab[c]def\n\nabcd\n") + (evil-test-buffer + "ab[c]\nabcdef\n\nabcd\n" + ("jj") + "abc\nabcdef\n[\n]abcd\n") + (evil-test-buffer + "ab[c]\nabcdef\n\nabcd\n" + ("jjj") + "abc\nabcdef\n\nab[c]d\n") + (evil-test-buffer + "ab[c]\nabcdef\n\nabcd\n" + ("jjjk") + "abc\nabcdef\n[\n]abcd\n") + (evil-test-buffer + "ab[c]\nabcdef\n\nabcd\n" + ("jjjkk") + "abc\nab[c]def\n\nabcd\n"))) + +(ert-deftest evil-test-other-commands-preserve-column () + "Test other comamnds preserve the column, when appropriate." + :tags '(evil motion) + (ert-info ("evil-goto-line can preserve column") + (let ((evil-start-of-line nil)) + (evil-test-buffer + "Shor[t] line +Average line +The longest line" + ("2G") + "Short line +Aver[a]ge line +The longest line" + ("$G") + "Short line +Average line +The longest lin[e]" + ("hgg") + "Short lin[e] +Average line +The longest line"))) + + (ert-info ("evil-goto-line respects evil-start-of-line") + (let ((evil-start-of-line t)) + (evil-test-buffer + "foo\n[b]ar" + ("$ggj") + "foo\n[b]ar"))) + + (ert-info ("N% (`evil-jump-item' with count) can preserve column") + (let ((evil-start-of-line nil)) + (evil-test-buffer + "Short line +Average line +The lo[n]gest line" + ("5%") + "Short [l]ine +Average line +The longest line" + ("$90%") + "Short line +Average line +The longest lin[e]")))) + +(ert-deftest evil-test-beginning-of-line () + "Test `evil-beginning-of-line' motion" + :tags '(evil motion) + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save." + ("0") + "[;]; This buffer is for notes you don't want to save." + ("0") + "[;]; This buffer is for notes you don't want to save.")) + +(ert-deftest evil-test-end-of-line () + "Test `evil-end-of-line' motion" + :tags '(evil motion) + (ert-info ("Simple") + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save." + ("$") + ";; This buffer is for notes you don't want to save[.]" + ("$") + ";; This buffer is for notes you don't want to save[.]")) + (ert-info ("Don't delete blank lines") + (evil-test-buffer + "Above some line +\[] +Below some empty line" + ("d$") + "Above some line +\[] +Below some empty line"))) + +(ert-deftest evil-test-percentage-of-line () + "Test `evil-percentage-of-line' motion" + :tags '(evil motion) + (evil-test-buffer + "[0]123456789" + ("gM") + "01234[5]6789" + ("10gM") + "0[1]23456789" + ("85gM") + "01234567[8]9")) + +(ert-deftest evil-test-first-non-blank () + "Test `evil-first-non-blank' motion" + :tags '(evil motion) + (evil-test-buffer + "\ + printf(\"Hello world\\n\")[;] + return EXIT_SUCCESS;" + ("^") + "\ + [p]rintf(\"Hello world\\n\"); + return EXIT_SUCCESS;" + ("j^") + "\ + printf(\"Hello world\\n\"); + [r]eturn EXIT_SUCCESS;")) + +(ert-deftest evil-test-last-non-blank () + "Test `evil-last-non-blank' motion" + :tags '(evil motion) + (evil-test-buffer + "[i]nt main(int argc, char** argv) \n\ +{ + printf(\"Hello world\\n\"); + return EXIT_SUCCESS; +}" + ("g_") + "int main(int argc, char** argv[)] \n\ +{ + printf(\"Hello world\\n\"); + return EXIT_SUCCESS; +}" + ("jjg_") + "int main(int argc, char** argv) \n\ +{ + printf(\"Hello world\\n\")[;] + return EXIT_SUCCESS; +}")) + +(ert-deftest evil-test-goto-first-line () + "Test `evil-goto-first-line' motion" + :tags '(evil motion) + (ert-info ("With `evil-start-of-line' `nil'") + (evil-test-buffer + "[i]nt main(int argc, char** argv) +{ + printf(\"Hello world\\n\"); + return EXIT_SUCCESS; +}" + ("3gg") + "int main(int argc, char** argv) +{ +[ ] printf(\"Hello world\\n\"); + return EXIT_SUCCESS; +}" + ("gg") + "[i]nt main(int argc, char** argv) +{ + printf(\"Hello world\\n\"); + return EXIT_SUCCESS; +}" + ("100gg") + "int main(int argc, char** argv) +{ + printf(\"Hello world\\n\"); + return EXIT_SUCCESS; +\[}]")) + (ert-info ("With `evil-start-of-line' `nil'") + (let ((evil-start-of-line t)) + (evil-test-buffer + "[i]nt main(int argc, char** argv) +{ + printf(\"Hello world\\n\"); + return EXIT_SUCCESS; +}" + ("3gg") + "int main(int argc, char** argv) +{ + [p]rintf(\"Hello world\\n\"); + return EXIT_SUCCESS; +}" + ("gg") + "[i]nt main(int argc, char** argv) +{ + printf(\"Hello world\\n\"); + return EXIT_SUCCESS; +}" + ("100gg") + "int main(int argc, char** argv) +{ + printf(\"Hello world\\n\"); + return EXIT_SUCCESS; +\[}]")))) + +(ert-deftest evil-test-goto-line () + "Test `evil-goto-line' motion" + :tags '(evil motion) + (ert-info ("With `evil-start-of-line' `t'") + (let ((evil-start-of-line t)) + (evil-test-buffer + "[i]nt main(int argc, char** argv) +{ + printf(\"Hello world\\n\"); + return EXIT_SUCCESS; +}" + ("G") + "int main(int argc, char** argv) +{ + printf(\"Hello world\\n\"); + return EXIT_SUCCESS; +\[}]" + ("3G") + "int main(int argc, char** argv) +{ + [p]rintf(\"Hello world\\n\"); + return EXIT_SUCCESS; +}" + ("100G") + "int main(int argc, char** argv) +{ + printf(\"Hello world\\n\"); + return EXIT_SUCCESS; +\[}]"))) + (ert-info ("With `evil-start-of-line' `nil'") + (evil-test-buffer + "[i]nt main(int argc, char** argv) +{ + printf(\"Hello world\\n\"); + return EXIT_SUCCESS; +}" + ("G") + "int main(int argc, char** argv) +{ + printf(\"Hello world\\n\"); + return EXIT_SUCCESS; +\[}]" + ("3G") + "int main(int argc, char** argv) +{ +[ ] printf(\"Hello world\\n\"); + return EXIT_SUCCESS; +}" + ("100G") + "int main(int argc, char** argv) +{ + printf(\"Hello world\\n\"); + return EXIT_SUCCESS; +\[}]"))) + +(ert-deftest evil-test-goto-char () + "Test `evil-goto-char' motion and ex command." + :tags '(evil motion ex) + (evil-test-buffer + "[W]e only need a short buffer for this test" + (":goto 9") + "We only [n]eed a short buffer for this test" + (":goto") + "[W]e only need a short buffer for this test" + ("16go") + "We only need a [s]hort buffer for this test" + ("go") + "[W]e only need a short buffer for this test" + (evil-goto-char 24) + "We only need a short bu[f]fer for this test")) + +(ert-deftest evil-test-operator-0 () + "Test motion \"0\" with an operator." + :tags '(evil motion) + (evil-test-buffer + ";; [T]his buffer is for notes." + ("d0") + "[T]his buffer is for notes.")) + +(ert-deftest evil-test-forward-not-word () + "Test `evil-forward-not-thing'" + :tags '(evil motion) + (evil-test-buffer + "[ ] aa,," + (evil-forward-not-thing 'evil-word) + " [a]a,,")) + +;; TODO: test Visual motions and window motions +(ert-deftest evil-test-forward-word-begin () + "Test `evil-forward-word-begin'" + :tags '(evil motion) + (ert-info ("Non-word") + (evil-test-buffer + "[;]; This buffer is for notes." + ("w") + ";; [T]his buffer is for notes.")) + (ert-info ("Simple") + (evil-test-buffer + ";; [T]his buffer is for notes." + ("w") + ";; This [b]uffer is for notes.")) + (ert-info ("With count") + (evil-test-buffer + ";; [T]his buffer is for notes." + ("3w") + ";; This buffer is [f]or notes.")) + (ert-info ("With count on whitespace") + (evil-test-buffer + ";;[ ]This buffer is for notes." + ("3w") + ";; This buffer [i]s for notes.")) + (ert-info ("Empty line") + (evil-test-buffer + "Above some line +\[] +Below some empty line" + ("w") + "Above some line + +\[B]elow some empty line") + (evil-test-buffer + "[A]bove + +Below some empty line" + ("dw") + "[] + +Below some empty line" + ("dw") + "[] +Below some empty line" + ("dw") + "[B]elow some empty line") + (evil-test-buffer + "[A]bove + + Below some empty line with leading whitespace" + ("dw") + "[] + + Below some empty line with leading whitespace" + ("dw") + "[] + Below some empty line with leading whitespace" + ("dw") + " [B]elow some empty line") + (evil-test-buffer + "Some line with trailing whitespace [ ] \n next line\n" + ("dw") + "Some line with trailing whitespace [ ]\n next line\n") + (evil-test-buffer + "[A]\n" + ("dw") + "[]\n")) + (ert-info ("End of buffer") + (evil-test-buffer + ";; [T]his buffer is for notes." + ("100w") + ";; This buffer is for notes[.]" + (should-error (execute-kbd-macro "w")) + (should-error (execute-kbd-macro "10w")))) + (ert-info ("Before last character in buffer") + (evil-test-buffer + "fo[o]." + ("w") + "foo[.]") + (evil-test-buffer + "fo[o] " + ("w") + "foo[ ]") + (evil-test-buffer + "[ ]e" + ("w") + " [e]"))) + +(ert-deftest evil-test-forward-word-end () + "Test `evil-forward-word-end'" + :tags '(evil motion) + (ert-info ("Non-word") + (evil-test-buffer + "[;]; This buffer is for notes." + ("e") + ";[;] This buffer is for notes.")) + (ert-info ("Simple") + (evil-test-buffer + ";; [T]his buffer is for notes." + ("e") + ";; Thi[s] buffer is for notes.")) + (ert-info ("With count") + (evil-test-buffer + ";; [T]his buffer is for notes." + ("3e") + ";; This buffer i[s] for notes.")) + (ert-info ("With count on whitespace") + (evil-test-buffer + ";;[ ]This buffer is for notes." + ("3e") + ";; This buffer i[s] for notes.")) + (ert-info ("Delete") + (evil-test-buffer + ";; This[-]buffer-is-for-notes." + ("de") + ";; This[-]is-for-notes.")) + (ert-info ("Empty line") + (evil-test-buffer + "Above some line +\[] +Below some empty line" + ("e") + "Above some line + +Belo[w] some empty line")) + (ert-info ("End of buffer") + (evil-test-buffer + ";; [T]his buffer is for notes." + ("100e") + ";; This buffer is for notes[.]" + (should-error (execute-kbd-macro "e")) + (should-error (execute-kbd-macro "10e")))) + ;; In Vim, "de" may delete two words rather than one + ;; if the first word is only one letter. In Evil, + ;; "de" always deletes one word. + (ert-info ("Delete a single-letter word") + (evil-test-buffer + "a [b] c" + ("de") + "a [ ]c"))) + +(ert-deftest evil-test-backward-word-begin () + "Test `evil-backward-word-begin'" + :tags '(evil motion) + (ert-info ("Simple") + (evil-test-buffer + ";; This buffer is for notes[.]" + ("b") + ";; This buffer is for [n]otes.")) + (ert-info ("With count") + (evil-test-buffer + ";; This buffer is for notes[.]" + ("2b") + ";; This buffer is [f]or notes.")) + (ert-info ("Empty line") + (evil-test-buffer + "Above some line +\[] +Below some empty line" + ("b") + "Above some [l]ine + +Below some empty line")) + (ert-info ("With count on whitespace") + (evil-test-buffer + ";; This buffer is for[ ]notes." + ("2b") + ";; This buffer [i]s for notes.")) + (ert-info ("Beginning of buffer") + (evil-test-buffer + ";; This buffer is for notes[.]" + ("100b") + "[;]; This buffer is for notes." + (should-error (execute-kbd-macro "b")) + (should-error (execute-kbd-macro "10b"))))) + +(ert-deftest evil-test-backward-word-end () + "Test `evil-backward-word-end'" + :tags '(evil motion) + (ert-info ("Simple") + (evil-test-buffer + ";; This buffer is for notes[.]" + ("ge") + ";; This buffer is for note[s].")) + (ert-info ("With count") + (evil-test-buffer + ";; This buffer is for notes[.]" + ("2ge") + ";; This buffer is fo[r] notes.")) + (ert-info ("Empty line") + (evil-test-buffer + "Above some line +\[] +Below some empty line" + ("ge") + "Above some lin[e] + +Below some empty line")) + (ert-info ("With count on whitespace") + (evil-test-buffer + ";; This buffer is for[ ]notes." + ("2ge") + ";; This buffer i[s] for notes.")) + (ert-info ("Beginning of buffer") + (evil-test-buffer + ";; This buffer is for notes[.]" + ("100ge") + "[;]; This buffer is for notes." + (should-error (execute-kbd-macro "ge")) + (should-error (execute-kbd-macro "10ge"))))) + +(ert-deftest evil-test-forward-word-begin-cjk () + "Test `evil-forward-word-begin' on CJK words" + :tags '(evil motion cjk) + (ert-info ("Latin / numeric") + (evil-test-buffer + "[a]bcd1234" + ("w") + "abcd123[4]")) + (ert-info ("Latin / Kanji") + (evil-test-buffer + "[a]bcd漢字" + ("w") + "abcd[漢]字")) + (ert-info ("Latin / Hiragana") + (evil-test-buffer + "[a]bcdひらがな" + ("w") + "abcd[ひ]らがな")) + (ert-info ("Latin / Katakana") + (evil-test-buffer + "[a]bcdカタカナ" + ("w") + "abcd[カ]タカナ")) + (ert-info ("Latin / half-width Katakana") + (evil-test-buffer + "[a]bcdカタカナ" + ("w") + "abcdカタカ[ナ]")) + (ert-info ("Latin / full-width alphabet") + (evil-test-buffer + "[a]bcdABC" + ("w") + "abcdAB[C]")) + (ert-info ("Latin / full-width numeric") + (evil-test-buffer + "[a]bcd123" + ("w") + "abcd12[3]")) + (ert-info ("Latin / Hangul") + (evil-test-buffer + "[a]bcd한글" + ("w") + "abcd[한]글")) + (ert-info ("numeric / Latin") + (evil-test-buffer + "[1]234abcd" + ("w") + "1234abc[d]")) + (ert-info ("numeric / Kanji") + (evil-test-buffer + "[1]234漢字" + ("w") + "1234[漢]字")) + (ert-info ("numeric / Hiragana") + (evil-test-buffer + "[1]234ひらがな" + ("w") + "1234[ひ]らがな")) + (ert-info ("numeric / Katakana") + (evil-test-buffer + "[1]234カタカナ" + ("w") + "1234[カ]タカナ")) + (ert-info ("numeric / half-width Katakana") + (evil-test-buffer + "[1]234カタカナ" + ("w") + "1234カタカ[ナ]")) + (ert-info ("numeric / full-width alphabet") + (evil-test-buffer + "[1]234ABC" + ("w") + "1234AB[C]")) + (ert-info ("numeric / full-width numeric") + (evil-test-buffer + "[1]234123" + ("w") + "123412[3]")) + (ert-info ("numeric / Hangul") + (evil-test-buffer + "[1]234한글" + ("w") + "1234[한]글")) + (ert-info ("Kanji / Latin") + (evil-test-buffer + "[漢]字abcd" + ("w") + "漢字[a]bcd")) + (ert-info ("Kanji / numeric") + (evil-test-buffer + "[漢]字1234" + ("w") + "漢字[1]234")) + (ert-info ("Kanji / Hiragana") + (evil-test-buffer + "[漢]字ひらがな" + ("w") + "漢字[ひ]らがな")) + (ert-info ("Kanji / Katakana") + (evil-test-buffer + "[漢]字カタカナ" + ("w") + "漢字[カ]タカナ")) + (ert-info ("Kanji / half-width Katakana") + (evil-test-buffer + "[漢]字カタカナ" + ("w") + "漢字[カ]タカナ")) + (ert-info ("Kanji / full-width alphabet") + (evil-test-buffer + "[漢]字ABC" + ("w") + "漢字[A]BC")) + (ert-info ("Kanji / full-width numeric") + (evil-test-buffer + "[漢]字123" + ("w") + "漢字[1]23")) + (ert-info ("Kanji / Hangul") + (evil-test-buffer + "[漢]字한글" + ("w") + "漢字[한]글")) + (ert-info ("Hiragana / Latin") + (evil-test-buffer + "[ひ]らがなabcd" + ("w") + "ひらがな[a]bcd")) + (ert-info ("Hiragana / numeric") + (evil-test-buffer + "[ひ]らがな1234" + ("w") + "ひらがな[1]234")) + (ert-info ("Hiragana / Kanji") + (evil-test-buffer + "[ひ]らがな漢字" + ("w") + "ひらがな[漢]字")) + (ert-info ("Hiragana / Katakana") + (evil-test-buffer + "[ひ]らがなカタカナ" + ("w") + "ひらがな[カ]タカナ")) + (ert-info ("Hiragana / half-width Katakana") + (evil-test-buffer + "[ひ]らがなカタカナ" + ("w") + "ひらがな[カ]タカナ")) + (ert-info ("Hiragana / full-width alphabet") + (evil-test-buffer + "[ひ]らがなABC" + ("w") + "ひらがな[A]BC")) + (ert-info ("Hiragana / full-width numeric") + (evil-test-buffer + "[ひ]らがな123" + ("w") + "ひらがな[1]23")) + (ert-info ("Hiragana / Hangul") + (evil-test-buffer + "[ひ]らがな한글" + ("w") + "ひらがな[한]글")) + (ert-info ("Katakana / Latin") + (evil-test-buffer + "[カ]タカナabcd" + ("w") + "カタカナ[a]bcd")) + (ert-info ("Katakana / numeric") + (evil-test-buffer + "[カ]タカナ1234" + ("w") + "カタカナ[1]234")) + (ert-info ("Katakana / Kanji") + (evil-test-buffer + "[カ]タカナ漢字" + ("w") + "カタカナ[漢]字")) + (ert-info ("Katakana / Hiragana") + (evil-test-buffer + "[カ]タカナひらがな" + ("w") + "カタカナ[ひ]らがな")) + (ert-info ("Katakana / half-width Katakana") + (evil-test-buffer + "[カ]タカナカタカナ" + ("w") + "カタカナ[カ]タカナ")) + (ert-info ("Katakana / full-width alphabet") + (evil-test-buffer + "[カ]タカナABC" + ("w") + "カタカナ[A]BC")) + (ert-info ("Katakana / full-width numeric") + (evil-test-buffer + "[カ]タカナ123" + ("w") + "カタカナ[1]23")) + (ert-info ("Katakana / Hangul") + (evil-test-buffer + "[カ]タカナ한글" + ("w") + "カタカナ[한]글")) + (ert-info ("half-width Katakana / Latin") + (evil-test-buffer + "[カ]タカナabcd" + ("w") + "カタカナabc[d]")) + (ert-info ("half-width Katakana / numeric") + (evil-test-buffer + "[カ]タカナ1234" + ("w") + "カタカナ123[4]")) + (ert-info ("half-width Katakana / Kanji") + (evil-test-buffer + "[カ]タカナ漢字" + ("w") + "カタカナ[漢]字")) + (ert-info ("half-width Katakana / Hiragana") + (evil-test-buffer + "[カ]タカナひらがな" + ("w") + "カタカナ[ひ]らがな")) + (ert-info ("half-width Katakana / Katakana") + (evil-test-buffer + "[カ]タカナカタカナ" + ("w") + "カタカナ[カ]タカナ")) + (ert-info ("half-width Katakana / full-width alphabet") + (evil-test-buffer + "[カ]タカナABC" + ("w") + "カタカナAB[C]")) + (ert-info ("half-width Katakana / full-width numeric") + (evil-test-buffer + "[カ]タカナ123" + ("w") + "カタカナ12[3]")) + (ert-info ("half-width Katakana / Hangul") + (evil-test-buffer + "[カ]タカナ한글" + ("w") + "カタカナ[한]글")) + (ert-info ("full-width alphabet / Latin") + (evil-test-buffer + "[A]BCabcd" + ("w") + "ABCabc[d]")) + (ert-info ("full-width alphabet / numeric") + (evil-test-buffer + "[A]BC1234" + ("w") + "ABC123[4]")) + (ert-info ("full-width alphabet / Kanji") + (evil-test-buffer + "[A]BC漢字" + ("w") + "ABC[漢]字")) + (ert-info ("full-width alphabet / Hiragana") + (evil-test-buffer + "[A]BCひらがな" + ("w") + "ABC[ひ]らがな")) + (ert-info ("full-width alphabet / Katakana") + (evil-test-buffer + "[A]BCカタカナ" + ("w") + "ABC[カ]タカナ")) + (ert-info ("full-width alphabet / half-width Katakana") + (evil-test-buffer + "[A]BCカタカナ" + ("w") + "ABCカタカ[ナ]")) + (ert-info ("full-width alphabet / full-width numeric") + (evil-test-buffer + "[A]BC123" + ("w") + "ABC12[3]")) + (ert-info ("full-width alphabet / Hangul") + (evil-test-buffer + "[A]BC한글" + ("w") + "ABC[한]글")) + (ert-info ("full-width numeric / Latin") + (evil-test-buffer + "[1]23abcd" + ("w") + "123abc[d]")) + (ert-info ("full-width numeric / numeric") + (evil-test-buffer + "[1]231234" + ("w") + "123123[4]")) + (ert-info ("full-width numeric / Kanji") + (evil-test-buffer + "[1]23漢字" + ("w") + "123[漢]字")) + (ert-info ("full-width numeric / Hiragana") + (evil-test-buffer + "[1]23ひらがな" + ("w") + "123[ひ]らがな")) + (ert-info ("full-width numeric / Katakana") + (evil-test-buffer + "[1]23カタカナ" + ("w") + "123[カ]タカナ")) + (ert-info ("full-width numeric / half-width Katakana") + (evil-test-buffer + "[1]23カタカナ" + ("w") + "123カタカ[ナ]")) + (ert-info ("full-width numeric / full-width alphabet") + (evil-test-buffer + "[1]23ABC" + ("w") + "123AB[C]")) + (ert-info ("full-width numeric / Hangul") + (evil-test-buffer + "[1]23한글" + ("w") + "123[한]글")) + (ert-info ("Hangul / Latin") + (evil-test-buffer + "[한]글abcd" + ("w") + "한글[a]bcd")) + (ert-info ("Hangul / numeric") + (evil-test-buffer + "[한]글1234" + ("w") + "한글[1]234")) + (ert-info ("Hangul / Kanji") + (evil-test-buffer + "[한]글漢字" + ("w") + "한글[漢]字")) + (ert-info ("Hangul / Hiragana") + (evil-test-buffer + "[한]글ひらがな" + ("w") + "한글[ひ]らがな")) + (ert-info ("Hangul / Katakana") + (evil-test-buffer + "[한]글カタカナ" + ("w") + "한글[カ]タカナ")) + (ert-info ("Hangul / half-width Katakana") + (evil-test-buffer + "[한]글カタカナ" + ("w") + "한글[カ]タカナ")) + (ert-info ("Hangul / full-width alphabet") + (evil-test-buffer + "[한]글ABC" + ("w") + "한글[A]BC")) + (ert-info ("Hangul / full-width numeric") + (evil-test-buffer + "[한]글123" + ("w") + "한글[1]23"))) + +(ert-deftest evil-test-forward-word-end-cjk () + "Test `evil-forward-word-end' on CJK words" + :tags '(evil motion cjk) + (ert-info ("Latin / numeric") + (evil-test-buffer + "[a]bcd1234" + ("e") + "abcd123[4]")) + (ert-info ("Latin / Kanji") + (evil-test-buffer + "[a]bcd漢字" + ("e") + "abc[d]漢字")) + (ert-info ("Latin / Hiragana") + (evil-test-buffer + "[a]bcdひらがな" + ("e") + "abc[d]ひらがな")) + (ert-info ("Latin / Katakana") + (evil-test-buffer + "[a]bcdカタカナ" + ("e") + "abc[d]カタカナ")) + (ert-info ("Latin / half-width Katakana") + (evil-test-buffer + "[a]bcdカタカナ" + ("e") + "abcdカタカ[ナ]")) + (ert-info ("Latin / full-width alphabet") + (evil-test-buffer + "[a]bcdABC" + ("e") + "abcdAB[C]")) + (ert-info ("Latin / full-width numeric") + (evil-test-buffer + "[a]bcd123" + ("e") + "abcd12[3]")) + (ert-info ("Latin / Hangul") + (evil-test-buffer + "[a]bcd한글" + ("e") + "abc[d]한글")) + (ert-info ("numeric / Latin") + (evil-test-buffer + "[1]234abcd" + ("e") + "1234abc[d]")) + (ert-info ("numeric / Kanji") + (evil-test-buffer + "[1]234漢字" + ("e") + "123[4]漢字")) + (ert-info ("numeric / Hiragana") + (evil-test-buffer + "[1]234ひらがな" + ("e") + "123[4]ひらがな")) + (ert-info ("numeric / Katakana") + (evil-test-buffer + "[1]234カタカナ" + ("e") + "123[4]カタカナ")) + (ert-info ("numeric / half-width Katakana") + (evil-test-buffer + "[1]234カタカナ" + ("e") + "1234カタカ[ナ]")) + (ert-info ("numeric / full-width alphabet") + (evil-test-buffer + "[1]234ABC" + ("e") + "1234AB[C]")) + (ert-info ("numeric / full-width numeric") + (evil-test-buffer + "[1]234123" + ("e") + "123412[3]")) + (ert-info ("numeric / Hangul") + (evil-test-buffer + "[1]234한글" + ("e") + "123[4]한글")) + (ert-info ("Kanji / Latin") + (evil-test-buffer + "[漢]字abcd" + ("e") + "漢[字]abcd")) + (ert-info ("Kanji / numeric") + (evil-test-buffer + "[漢]字1234" + ("e") + "漢[字]1234")) + (ert-info ("Kanji / Hiragana") + (evil-test-buffer + "[漢]字ひらがな" + ("e") + "漢[字]ひらがな")) + (ert-info ("Kanji / Katakana") + (evil-test-buffer + "[漢]字カタカナ" + ("e") + "漢[字]カタカナ")) + (ert-info ("Kanji / half-width Katakana") + (evil-test-buffer + "[漢]字カタカナ" + ("e") + "漢[字]カタカナ")) + (ert-info ("Kanji / full-width alphabet") + (evil-test-buffer + "[漢]字ABC" + ("e") + "漢[字]ABC")) + (ert-info ("Kanji / full-width numeric") + (evil-test-buffer + "[漢]字123" + ("e") + "漢[字]123")) + (ert-info ("Kanji / Hangul") + (evil-test-buffer + "[漢]字한글" + ("e") + "漢[字]한글")) + (ert-info ("Hiragana / Latin") + (evil-test-buffer + "[ひ]らがなabcd" + ("e") + "ひらが[な]abcd")) + (ert-info ("Hiragana / numeric") + (evil-test-buffer + "[ひ]らがな1234" + ("e") + "ひらが[な]1234")) + (ert-info ("Hiragana / Kanji") + (evil-test-buffer + "[ひ]らがな漢字" + ("e") + "ひらが[な]漢字")) + (ert-info ("Hiragana / Katakana") + (evil-test-buffer + "[ひ]らがなカタカナ" + ("e") + "ひらが[な]カタカナ")) + (ert-info ("Hiragana / half-width Katakana") + (evil-test-buffer + "[ひ]らがなカタカナ" + ("e") + "ひらが[な]カタカナ")) + (ert-info ("Hiragana / full-width alphabet") + (evil-test-buffer + "[ひ]らがなABC" + ("e") + "ひらが[な]ABC")) + (ert-info ("Hiragana / full-width numeric") + (evil-test-buffer + "[ひ]らがな123" + ("e") + "ひらが[な]123")) + (ert-info ("Hiragana / Hangul") + (evil-test-buffer + "[ひ]らがな한글" + ("e") + "ひらが[な]한글")) + (ert-info ("Katakana / Latin") + (evil-test-buffer + "[カ]タカナabcd" + ("e") + "カタカ[ナ]abcd")) + (ert-info ("Katakana / numeric") + (evil-test-buffer + "[カ]タカナ1234" + ("e") + "カタカ[ナ]1234")) + (ert-info ("Katakana / Kanji") + (evil-test-buffer + "[カ]タカナ漢字" + ("e") + "カタカ[ナ]漢字")) + (ert-info ("Katakana / Hiragana") + (evil-test-buffer + "[カ]タカナひらがな" + ("e") + "カタカ[ナ]ひらがな")) + (ert-info ("Katakana / half-width Katakana") + (evil-test-buffer + "[カ]タカナカタカナ" + ("e") + "カタカ[ナ]カタカナ")) + (ert-info ("Katakana / full-width alphabet") + (evil-test-buffer + "[カ]タカナABC" + ("e") + "カタカ[ナ]ABC")) + (ert-info ("Katakana / full-width numeric") + (evil-test-buffer + "[カ]タカナ123" + ("e") + "カタカ[ナ]123")) + (ert-info ("Katakana / Hangul") + (evil-test-buffer + "[カ]タカナ한글" + ("e") + "カタカ[ナ]한글")) + (ert-info ("half-width Katakana / Latin") + (evil-test-buffer + "[カ]タカナabcd" + ("e") + "カタカナabc[d]")) + (ert-info ("half-width Katakana / numeric") + (evil-test-buffer + "[カ]タカナ1234" + ("e") + "カタカナ123[4]")) + (ert-info ("half-width Katakana / Kanji") + (evil-test-buffer + "[カ]タカナ漢字" + ("e") + "カタカ[ナ]漢字")) + (ert-info ("half-width Katakana / Hiragana") + (evil-test-buffer + "[カ]タカナひらがな" + ("e") + "カタカ[ナ]ひらがな")) + (ert-info ("half-width Katakana / Katakana") + (evil-test-buffer + "[カ]タカナカタカナ" + ("e") + "カタカ[ナ]カタカナ")) + (ert-info ("half-width Katakana / full-width alphabet") + (evil-test-buffer + "[カ]タカナABC" + ("e") + "カタカナAB[C]")) + (ert-info ("half-width Katakana / full-width numeric") + (evil-test-buffer + "[カ]タカナ123" + ("e") + "カタカナ12[3]")) + (ert-info ("half-width Katakana / Hangul") + (evil-test-buffer + "[カ]タカナ한글" + ("e") + "カタカ[ナ]한글")) + (ert-info ("full-width alphabet / Latin") + (evil-test-buffer + "[A]BCabcd" + ("e") + "ABCabc[d]")) + (ert-info ("full-width alphabet / numeric") + (evil-test-buffer + "[A]BC1234" + ("e") + "ABC123[4]")) + (ert-info ("full-width alphabet / Kanji") + (evil-test-buffer + "[A]BC漢字" + ("e") + "AB[C]漢字")) + (ert-info ("full-width alphabet / Hiragana") + (evil-test-buffer + "[A]BCひらがな" + ("e") + "AB[C]ひらがな")) + (ert-info ("full-width alphabet / Katakana") + (evil-test-buffer + "[A]BCカタカナ" + ("e") + "AB[C]カタカナ")) + (ert-info ("full-width alphabet / half-width Katakana") + (evil-test-buffer + "[A]BCカタカナ" + ("e") + "ABCカタカ[ナ]")) + (ert-info ("full-width alphabet / full-width numeric") + (evil-test-buffer + "[A]BC123" + ("e") + "ABC12[3]")) + (ert-info ("full-width alphabet / Hangul") + (evil-test-buffer + "[A]BC한글" + ("e") + "AB[C]한글")) + (ert-info ("full-width numeric / Latin") + (evil-test-buffer + "[1]23abcd" + ("e") + "123abc[d]")) + (ert-info ("full-width numeric / numeric") + (evil-test-buffer + "[1]231234" + ("e") + "123123[4]")) + (ert-info ("full-width numeric / Kanji") + (evil-test-buffer + "[1]23漢字" + ("e") + "12[3]漢字")) + (ert-info ("full-width numeric / Hiragana") + (evil-test-buffer + "[1]23ひらがな" + ("e") + "12[3]ひらがな")) + (ert-info ("full-width numeric / Katakana") + (evil-test-buffer + "[1]23カタカナ" + ("e") + "12[3]カタカナ")) + (ert-info ("full-width numeric / half-width Katakana") + (evil-test-buffer + "[1]23カタカナ" + ("e") + "123カタカ[ナ]")) + (ert-info ("full-width numeric / full-width alphabet") + (evil-test-buffer + "[1]23ABC" + ("e") + "123AB[C]")) + (ert-info ("full-width numeric / Hangul") + (evil-test-buffer + "[1]23한글" + ("e") + "12[3]한글")) + (ert-info ("Hangul / Latin") + (evil-test-buffer + "[한]글abcd" + ("e") + "한[글]abcd")) + (ert-info ("Hangul / numeric") + (evil-test-buffer + "[한]글1234" + ("e") + "한[글]1234")) + (ert-info ("Hangul / Kanji") + (evil-test-buffer + "[한]글漢字" + ("e") + "한[글]漢字")) + (ert-info ("Hangul / Hiragana") + (evil-test-buffer + "[한]글ひらがな" + ("e") + "한[글]ひらがな")) + (ert-info ("Hangul / Katakana") + (evil-test-buffer + "[한]글カタカナ" + ("e") + "한[글]カタカナ")) + (ert-info ("Hangul / half-width Katakana") + (evil-test-buffer + "[한]글カタカナ" + ("e") + "한[글]カタカナ")) + (ert-info ("Hangul / full-width alphabet") + (evil-test-buffer + "[한]글ABC" + ("e") + "한[글]ABC")) + (ert-info ("Hangul / full-width numeric") + (evil-test-buffer + "[한]글123" + ("e") + "한[글]123"))) + +(ert-deftest evil-test-backword-word-begin-cjk () + "Test `evil-backward-word-begin' on CJK words" + :tags '(evil motion cjk) + (ert-info ("Latin / numeric") + (evil-test-buffer + "abcd123[4]" + ("b") + "[a]bcd1234")) + (ert-info ("Latin / Kanji") + (evil-test-buffer + "abcd漢[字]" + ("b") + "abcd[漢]字")) + (ert-info ("Latin / Hiragana") + (evil-test-buffer + "abcdひらが[な]" + ("b") + "abcd[ひ]らがな")) + (ert-info ("Latin / Katakana") + (evil-test-buffer + "abcdカタカ[ナ]" + ("b") + "abcd[カ]タカナ")) + (ert-info ("Latin / half-width Katakana") + (evil-test-buffer + "abcdカタカ[ナ]" + ("b") + "[a]bcdカタカナ")) + (ert-info ("Latin / full-width alphabet") + (evil-test-buffer + "abcdAB[C]" + ("b") + "[a]bcdABC")) + (ert-info ("Latin / full-width numeric") + (evil-test-buffer + "abcd12[3]" + ("b") + "[a]bcd123")) + (ert-info ("Latin / Hangul") + (evil-test-buffer + "abcd한[글]" + ("b") + "abcd[한]글")) + (ert-info ("numeric / Latin") + (evil-test-buffer + "1234abc[d]" + ("b") + "[1]234abcd")) + (ert-info ("numeric / Kanji") + (evil-test-buffer + "1234漢[字]" + ("b") + "1234[漢]字")) + (ert-info ("numeric / Hiragana") + (evil-test-buffer + "1234ひらが[な]" + ("b") + "1234[ひ]らがな")) + (ert-info ("numeric / Katakana") + (evil-test-buffer + "1234カタカ[ナ]" + ("b") + "1234[カ]タカナ")) + (ert-info ("numeric / half-width Katakana") + (evil-test-buffer + "1234カタカ[ナ]" + ("b") + "[1]234カタカナ")) + (ert-info ("numeric / full-width alphabet") + (evil-test-buffer + "1234AB[C]" + ("b") + "[1]234ABC")) + (ert-info ("numeric / full-width numeric") + (evil-test-buffer + "123412[3]" + ("b") + "[1]234123")) + (ert-info ("numeric / Hangul") + (evil-test-buffer + "1234한[글]" + ("b") + "1234[한]글")) + (ert-info ("Kanji / Latin") + (evil-test-buffer + "漢字abc[d]" + ("b") + "漢字[a]bcd")) + (ert-info ("Kanji / numeric") + (evil-test-buffer + "漢字123[4]" + ("b") + "漢字[1]234")) + (ert-info ("Kanji / Hiragana") + (evil-test-buffer + "漢字ひらが[な]" + ("b") + "漢字[ひ]らがな")) + (ert-info ("Kanji / Katakana") + (evil-test-buffer + "漢字カタカ[ナ]" + ("b") + "漢字[カ]タカナ")) + (ert-info ("Kanji / half-width Katakana") + (evil-test-buffer + "漢字カタカ[ナ]" + ("b") + "漢字[カ]タカナ")) + (ert-info ("Kanji / full-width alphabet") + (evil-test-buffer + "漢字AB[C]" + ("b") + "漢字[A]BC")) + (ert-info ("Kanji / full-width numeric") + (evil-test-buffer + "漢字12[3]" + ("b") + "漢字[1]23")) + (ert-info ("Kanji / Hangul") + (evil-test-buffer + "漢字한[글]" + ("b") + "漢字[한]글")) + (ert-info ("Hiragana / Latin") + (evil-test-buffer + "ひらがなabc[d]" + ("b") + "ひらがな[a]bcd")) + (ert-info ("Hiragana / numeric") + (evil-test-buffer + "ひらがな123[4]" + ("b") + "ひらがな[1]234")) + (ert-info ("Hiragana / Kanji") + (evil-test-buffer + "ひらがな漢[字]" + ("b") + "ひらがな[漢]字")) + (ert-info ("Hiragana / Katakana") + (evil-test-buffer + "ひらがなカタカ[ナ]" + ("b") + "ひらがな[カ]タカナ")) + (ert-info ("Hiragana / half-width Katakana") + (evil-test-buffer + "ひらがなカタカ[ナ]" + ("b") + "ひらがな[カ]タカナ")) + (ert-info ("Hiragana / full-width alphabet") + (evil-test-buffer + "ひらがなAB[C]" + ("b") + "ひらがな[A]BC")) + (ert-info ("Hiragana / full-width numeric") + (evil-test-buffer + "ひらがな12[3]" + ("b") + "ひらがな[1]23")) + (ert-info ("Hiragana / Hangul") + (evil-test-buffer + "ひらがな한[글]" + ("b") + "ひらがな[한]글")) + (ert-info ("Katakana / Latin") + (evil-test-buffer + "カタカナabc[d]" + ("b") + "カタカナ[a]bcd")) + (ert-info ("Katakana / numeric") + (evil-test-buffer + "カタカナ123[4]" + ("b") + "カタカナ[1]234")) + (ert-info ("Katakana / Kanji") + (evil-test-buffer + "カタカナ漢[字]" + ("b") + "カタカナ[漢]字")) + (ert-info ("Katakana / Hiragana") + (evil-test-buffer + "カタカナひらが[な]" + ("b") + "カタカナ[ひ]らがな")) + (ert-info ("Katakana / half-width Katakana") + (evil-test-buffer + "カタカナカタカ[ナ]" + ("b") + "カタカナ[カ]タカナ")) + (ert-info ("Katakana / full-width alphabet") + (evil-test-buffer + "カタカナAB[C]" + ("b") + "カタカナ[A]BC")) + (ert-info ("Katakana / full-width numeric") + (evil-test-buffer + "カタカナ12[3]" + ("b") + "カタカナ[1]23")) + (ert-info ("Katakana / Hangul") + (evil-test-buffer + "カタカナ한[글]" + ("b") + "カタカナ[한]글")) + (ert-info ("half-width Katakana / Latin") + (evil-test-buffer + "カタカナabc[d]" + ("b") + "[カ]タカナabcd")) + (ert-info ("half-width Katakana / numeric") + (evil-test-buffer + "カタカナ123[4]" + ("b") + "[カ]タカナ1234")) + (ert-info ("half-width Katakana / Kanji") + (evil-test-buffer + "カタカナ漢[字]" + ("b") + "カタカナ[漢]字")) + (ert-info ("half-width Katakana / Hiragana") + (evil-test-buffer + "カタカナひらが[な]" + ("b") + "カタカナ[ひ]らがな")) + (ert-info ("half-width Katakana / Katakana") + (evil-test-buffer + "カタカナカタカ[ナ]" + ("b") + "カタカナ[カ]タカナ")) + (ert-info ("half-width Katakana / full-width alphabet") + (evil-test-buffer + "カタカナAB[C]" + ("b") + "[カ]タカナABC")) + (ert-info ("half-width Katakana / full-width numeric") + (evil-test-buffer + "カタカナ12[3]" + ("b") + "[カ]タカナ123")) + (ert-info ("half-width Katakana / Hangul") + (evil-test-buffer + "カタカナ한[글]" + ("b") + "カタカナ[한]글")) + (ert-info ("full-width alphabet / Latin") + (evil-test-buffer + "ABCabc[d]" + ("b") + "[A]BCabcd")) + (ert-info ("full-width alphabet / numeric") + (evil-test-buffer + "ABC123[4]" + ("b") + "[A]BC1234")) + (ert-info ("full-width alphabet / Kanji") + (evil-test-buffer + "ABC漢[字]" + ("b") + "ABC[漢]字")) + (ert-info ("full-width alphabet / Hiragana") + (evil-test-buffer + "ABCひらが[な]" + ("b") + "ABC[ひ]らがな")) + (ert-info ("full-width alphabet / Katakana") + (evil-test-buffer + "ABCカタカ[ナ]" + ("b") + "ABC[カ]タカナ")) + (ert-info ("full-width alphabet / half-width Katakana") + (evil-test-buffer + "ABCカタカ[ナ]" + ("b") + "[A]BCカタカナ")) + (ert-info ("full-width alphabet / full-width numeric") + (evil-test-buffer + "ABC12[3]" + ("b") + "[A]BC123")) + (ert-info ("full-width alphabet / Hangul") + (evil-test-buffer + "ABC한[글]" + ("b") + "ABC[한]글")) + (ert-info ("full-width numeric / Latin") + (evil-test-buffer + "123abc[d]" + ("b") + "[1]23abcd")) + (ert-info ("full-width numeric / numeric") + (evil-test-buffer + "123123[4]" + ("b") + "[1]231234")) + (ert-info ("full-width numeric / Kanji") + (evil-test-buffer + "123漢[字]" + ("b") + "123[漢]字")) + (ert-info ("full-width numeric / Hiragana") + (evil-test-buffer + "123ひらが[な]" + ("b") + "123[ひ]らがな")) + (ert-info ("full-width numeric / Katakana") + (evil-test-buffer + "123カタカ[ナ]" + ("b") + "123[カ]タカナ")) + (ert-info ("full-width numeric / half-width Katakana") + (evil-test-buffer + "123カタカ[ナ]" + ("b") + "[1]23カタカナ")) + (ert-info ("full-width numeric / full-width alphabet") + (evil-test-buffer + "123AB[C]" + ("b") + "[1]23ABC")) + (ert-info ("full-width numeric / Hangul") + (evil-test-buffer + "123한[글]" + ("b") + "123[한]글")) + (ert-info ("Hangul / Latin") + (evil-test-buffer + "한글abc[d]" + ("b") + "한글[a]bcd")) + (ert-info ("Hangul / numeric") + (evil-test-buffer + "한글123[4]" + ("b") + "한글[1]234")) + (ert-info ("Hangul / Kanji") + (evil-test-buffer + "한글漢[字]" + ("b") + "한글[漢]字")) + (ert-info ("Hangul / Hiragana") + (evil-test-buffer + "한글ひらが[な]" + ("b") + "한글[ひ]らがな")) + (ert-info ("Hangul / Katakana") + (evil-test-buffer + "한글カタカ[ナ]" + ("b") + "한글[カ]タカナ")) + (ert-info ("Hangul / half-width Katakana") + (evil-test-buffer + "한글カタカ[ナ]" + ("b") + "한글[カ]タカナ")) + (ert-info ("Hangul / full-width alphabet") + (evil-test-buffer + "한글AB[C]" + ("b") + "한글[A]BC")) + (ert-info ("Hangul / full-width numeric") + (evil-test-buffer + "한글12[3]" + ("b") + "한글[1]23"))) + +(ert-deftest evil-test-backword-word-end-cjk () + "Test `evil-backward-word-end' on CJK words" + :tags '(evil motion cjk) + (ert-info ("Latin / numeric") + (evil-test-buffer + "abcd123[4]" + ("ge") + "[a]bcd1234")) + (ert-info ("Latin / Kanji") + (evil-test-buffer + "abcd漢[字]" + ("ge") + "abc[d]漢字")) + (ert-info ("Latin / Hiragana") + (evil-test-buffer + "abcdひらが[な]" + ("ge") + "abc[d]ひらがな")) + (ert-info ("Latin / Katakana") + (evil-test-buffer + "abcdカタカ[ナ]" + ("ge") + "abc[d]カタカナ")) + (ert-info ("Latin / half-width Katakana") + (evil-test-buffer + "abcdカタカ[ナ]" + ("ge") + "[a]bcdカタカナ")) + (ert-info ("Latin / full-width alphabet") + (evil-test-buffer + "abcdAB[C]" + ("ge") + "[a]bcdABC")) + (ert-info ("Latin / full-width numeric") + (evil-test-buffer + "abcd12[3]" + ("ge") + "[a]bcd123")) + (ert-info ("Latin / Hangul") + (evil-test-buffer + "abcd한[글]" + ("ge") + "abc[d]한글")) + (ert-info ("numeric / Latin") + (evil-test-buffer + "1234abc[d]" + ("ge") + "[1]234abcd")) + (ert-info ("numeric / Kanji") + (evil-test-buffer + "1234漢[字]" + ("ge") + "123[4]漢字")) + (ert-info ("numeric / Hiragana") + (evil-test-buffer + "1234ひらが[な]" + ("ge") + "123[4]ひらがな")) + (ert-info ("numeric / Katakana") + (evil-test-buffer + "1234カタカ[ナ]" + ("ge") + "123[4]カタカナ")) + (ert-info ("numeric / half-width Katakana") + (evil-test-buffer + "1234カタカ[ナ]" + ("ge") + "[1]234カタカナ")) + (ert-info ("numeric / full-width alphabet") + (evil-test-buffer + "1234AB[C]" + ("ge") + "[1]234ABC")) + (ert-info ("numeric / full-width numeric") + (evil-test-buffer + "123412[3]" + ("ge") + "[1]234123")) + (ert-info ("numeric / Hangul") + (evil-test-buffer + "1234한[글]" + ("ge") + "123[4]한글")) + (ert-info ("Kanji / Latin") + (evil-test-buffer + "漢字abc[d]" + ("ge") + "漢[字]abcd")) + (ert-info ("Kanji / numeric") + (evil-test-buffer + "漢字123[4]" + ("ge") + "漢[字]1234")) + (ert-info ("Kanji / Hiragana") + (evil-test-buffer + "漢字ひらが[な]" + ("ge") + "漢[字]ひらがな")) + (ert-info ("Kanji / Katakana") + (evil-test-buffer + "漢字カタカ[ナ]" + ("ge") + "漢[字]カタカナ")) + (ert-info ("Kanji / half-width Katakana") + (evil-test-buffer + "漢字カタカ[ナ]" + ("ge") + "漢[字]カタカナ")) + (ert-info ("Kanji / full-width alphabet") + (evil-test-buffer + "漢字AB[C]" + ("ge") + "漢[字]ABC")) + (ert-info ("Kanji / full-width numeric") + (evil-test-buffer + "漢字12[3]" + ("ge") + "漢[字]123")) + (ert-info ("Kanji / Hangul") + (evil-test-buffer + "漢字한[글]" + ("ge") + "漢[字]한글")) + (ert-info ("Hiragana / Latin") + (evil-test-buffer + "ひらがなabc[d]" + ("ge") + "ひらが[な]abcd")) + (ert-info ("Hiragana / numeric") + (evil-test-buffer + "ひらがな123[4]" + ("ge") + "ひらが[な]1234")) + (ert-info ("Hiragana / Kanji") + (evil-test-buffer + "ひらがな漢[字]" + ("ge") + "ひらが[な]漢字")) + (ert-info ("Hiragana / Katakana") + (evil-test-buffer + "ひらがなカタカ[ナ]" + ("ge") + "ひらが[な]カタカナ")) + (ert-info ("Hiragana / half-width Katakana") + (evil-test-buffer + "ひらがなカタカ[ナ]" + ("ge") + "ひらが[な]カタカナ")) + (ert-info ("Hiragana / full-width alphabet") + (evil-test-buffer + "ひらがなAB[C]" + ("ge") + "ひらが[な]ABC")) + (ert-info ("Hiragana / full-width numeric") + (evil-test-buffer + "ひらがな12[3]" + ("ge") + "ひらが[な]123")) + (ert-info ("Hiragana / Hangul") + (evil-test-buffer + "ひらがな한[글]" + ("ge") + "ひらが[な]한글")) + (ert-info ("Katakana / Latin") + (evil-test-buffer + "カタカナabc[d]" + ("ge") + "カタカ[ナ]abcd")) + (ert-info ("Katakana / numeric") + (evil-test-buffer + "カタカナ123[4]" + ("ge") + "カタカ[ナ]1234")) + (ert-info ("Katakana / Kanji") + (evil-test-buffer + "カタカナ漢[字]" + ("ge") + "カタカ[ナ]漢字")) + (ert-info ("Katakana / Hiragana") + (evil-test-buffer + "カタカナひらが[な]" + ("ge") + "カタカ[ナ]ひらがな")) + (ert-info ("Katakana / half-width Katakana") + (evil-test-buffer + "カタカナカタカ[ナ]" + ("ge") + "カタカ[ナ]カタカナ")) + (ert-info ("Katakana / full-width alphabet") + (evil-test-buffer + "カタカナAB[C]" + ("ge") + "カタカ[ナ]ABC")) + (ert-info ("Katakana / full-width numeric") + (evil-test-buffer + "カタカナ12[3]" + ("ge") + "カタカ[ナ]123")) + (ert-info ("Katakana / Hangul") + (evil-test-buffer + "カタカナ한[글]" + ("ge") + "カタカ[ナ]한글")) + (ert-info ("half-width Katakana / Latin") + (evil-test-buffer + "カタカナabc[d]" + ("ge") + "[カ]タカナabcd")) + (ert-info ("half-width Katakana / numeric") + (evil-test-buffer + "カタカナ123[4]" + ("ge") + "[カ]タカナ1234")) + (ert-info ("half-width Katakana / Kanji") + (evil-test-buffer + "カタカナ漢[字]" + ("ge") + "カタカ[ナ]漢字")) + (ert-info ("half-width Katakana / Hiragana") + (evil-test-buffer + "カタカナひらが[な]" + ("ge") + "カタカ[ナ]ひらがな")) + (ert-info ("half-width Katakana / Katakana") + (evil-test-buffer + "カタカナカタカ[ナ]" + ("ge") + "カタカ[ナ]カタカナ")) + (ert-info ("half-width Katakana / full-width alphabet") + (evil-test-buffer + "カタカナAB[C]" + ("ge") + "[カ]タカナABC")) + (ert-info ("half-width Katakana / full-width numeric") + (evil-test-buffer + "カタカナ12[3]" + ("ge") + "[カ]タカナ123")) + (ert-info ("half-width Katakana / Hangul") + (evil-test-buffer + "カタカナ한[글]" + ("ge") + "カタカ[ナ]한글")) + (ert-info ("full-width alphabet / Latin") + (evil-test-buffer + "ABCabc[d]" + ("ge") + "[A]BCabcd")) + (ert-info ("full-width alphabet / numeric") + (evil-test-buffer + "ABC123[4]" + ("ge") + "[A]BC1234")) + (ert-info ("full-width alphabet / Kanji") + (evil-test-buffer + "ABC漢[字]" + ("ge") + "AB[C]漢字")) + (ert-info ("full-width alphabet / Hiragana") + (evil-test-buffer + "ABCひらが[な]" + ("ge") + "AB[C]ひらがな")) + (ert-info ("full-width alphabet / Katakana") + (evil-test-buffer + "ABCカタカ[ナ]" + ("ge") + "AB[C]カタカナ")) + (ert-info ("full-width alphabet / half-width Katakana") + (evil-test-buffer + "ABCカタカ[ナ]" + ("ge") + "[A]BCカタカナ")) + (ert-info ("full-width alphabet / full-width numeric") + (evil-test-buffer + "ABC12[3]" + ("ge") + "[A]BC123")) + (ert-info ("full-width alphabet / Hangul") + (evil-test-buffer + "ABC한[글]" + ("ge") + "AB[C]한글")) + (ert-info ("full-width numeric / Latin") + (evil-test-buffer + "123abc[d]" + ("ge") + "[1]23abcd")) + (ert-info ("full-width numeric / numeric") + (evil-test-buffer + "123123[4]" + ("ge") + "[1]231234")) + (ert-info ("full-width numeric / Kanji") + (evil-test-buffer + "123漢[字]" + ("ge") + "12[3]漢字")) + (ert-info ("full-width numeric / Hiragana") + (evil-test-buffer + "123ひらが[な]" + ("ge") + "12[3]ひらがな")) + (ert-info ("full-width numeric / Katakana") + (evil-test-buffer + "123カタカ[ナ]" + ("ge") + "12[3]カタカナ")) + (ert-info ("full-width numeric / half-width Katakana") + (evil-test-buffer + "123カタカ[ナ]" + ("ge") + "[1]23カタカナ")) + (ert-info ("full-width numeric / full-width alphabet") + (evil-test-buffer + "123AB[C]" + ("ge") + "[1]23ABC")) + (ert-info ("full-width numeric / Hangul") + (evil-test-buffer + "123한[글]" + ("ge") + "12[3]한글")) + (ert-info ("Hangul / Latin") + (evil-test-buffer + "한글abc[d]" + ("ge") + "한[글]abcd")) + (ert-info ("Hangul / numeric") + (evil-test-buffer + "한글123[4]" + ("ge") + "한[글]1234")) + (ert-info ("Hangul / Kanji") + (evil-test-buffer + "한글漢[字]" + ("ge") + "한[글]漢字")) + (ert-info ("Hangul / Hiragana") + (evil-test-buffer + "한글ひらが[な]" + ("ge") + "한[글]ひらがな")) + (ert-info ("Hangul / Katakana") + (evil-test-buffer + "한글カタカ[ナ]" + ("ge") + "한[글]カタカナ")) + (ert-info ("Hangul / half-width Katakana") + (evil-test-buffer + "한글カタカ[ナ]" + ("ge") + "한[글]カタカナ")) + (ert-info ("Hangul / full-width alphabet") + (evil-test-buffer + "한글AB[C]" + ("ge") + "한[글]ABC")) + (ert-info ("Hangul / full-width numeric") + (evil-test-buffer + "한글12[3]" + ("ge") + "한[글]123"))) + +(ert-deftest evil-test-forward-paragraph () + "Test `evil-forward-paragraph'" + :tags '(evil motion) + (ert-info ("Simple") + (evil-test-buffer + "[A]bove some line + +Below some empty line" + ("}") + "Above some line +\[] +Below some empty line")) + (ert-info ("With count") + (evil-test-buffer + "[A]bove some line + +Below some empty line" + ("2}") + "Above some line + +Below some empty lin[e]")) + (ert-info ("End of buffer") + (evil-test-buffer + "[B]elow some empty line" + ("100}") + "Below some empty lin[e]" + (should-error (execute-kbd-macro "}")) + (should-error (execute-kbd-macro "42}")))) + (ert-info ("End of buffer with newline") + (evil-test-buffer + "[B]elow some empty line\n\n" + ("100}") + "Below some empty line\n\n[]" + (should-error (execute-kbd-macro "}")) + (should-error (execute-kbd-macro "42}"))))) + +(ert-deftest evil-test-backward-paragraph () + "Test `evil-backward-paragraph'" + :tags '(evil motion) + (ert-info ("Simple") + (evil-test-buffer + "Above some line + +Below some empty lin[e]" + ("{") + "Above some line +\[] +Below some empty line")) + (ert-info ("With count") + (evil-test-buffer + "Above some line + +Below some empty lin[e]" + ("2{") + "[A]bove some line + +Below some empty line")) + (ert-info ("Beginning of buffer") + (evil-test-buffer + "Above some line + +Below some empty lin[e]" + ("100{") + "[A]bove some line + +Below some empty line" + (should-error (execute-kbd-macro "{")) + (should-error (execute-kbd-macro "42{")))) + (ert-info ("Beginning of buffer with newlines") + (evil-test-buffer + "\n\nAbove some line + +Below some empty lin[e]" + ("100{") + "[]\n\nAbove some line + +Below some empty line" + (should-error (execute-kbd-macro "{")) + (should-error (execute-kbd-macro "42{"))))) + +(ert-deftest evil-test-forward-sentence () + "Test `evil-forward-sentence'" + :tags '(evil motion) + (ert-info ("Simple") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save, +;; and for Lisp evaluation. If you want to create a file, +;; visit that file with C-x C-f. + +Below some empty line." + (")") + ";; This buffer is for notes you don't want to save, +;; and for Lisp evaluation. [I]f you want to create a file, +;; visit that file with C-x C-f. + +Below some empty line." + (")") + ";; This buffer is for notes you don't want to save, +;; and for Lisp evaluation. If you want to create a file, +;; visit that file with C-x C-f. +\[] +Below some empty line." + (")") + ";; This buffer is for notes you don't want to save, +;; and for Lisp evaluation. If you want to create a file, +;; visit that file with C-x C-f. + +\[B]elow some empty line.")) + (ert-info ("With count") + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save, +;; and for Lisp evaluation. If you want to create a file, +;; visit that file with C-x C-f. + +Below some empty line." + ("2)") + ";; This buffer is for notes you don't want to save, +;; and for Lisp evaluation. If you want to create a file, +;; visit that file with C-x C-f. +\[] +Below some empty line." + ("2)") + ";; This buffer is for notes you don't want to save, +;; and for Lisp evaluation. If you want to create a file, +;; visit that file with C-x C-f. + +Below some empty line[.]")) + (ert-info ("End of buffer") + (evil-test-buffer + "[B]elow some empty line." + ("100)") + "Below some empty line[.]" + (should-error (execute-kbd-macro ")")) + (should-error (execute-kbd-macro "42)")))) + (ert-info ("End of buffer with newline") + (evil-test-buffer + "[B]elow some empty line.\n\n" + (")") + "Below some empty line.\n[\n]" + (")") + "Below some empty line.\n\n[]" + (should-error (execute-kbd-macro ")")) + (should-error (execute-kbd-macro "42)"))))) + +(ert-deftest evil-test-backward-sentence () + "Test `evil-backward-sentence'" + :tags '(evil motion) + (ert-info ("Simple") + (evil-test-buffer + ";; This buffer is for notes you don't want to save, +;; and for Lisp evaluation. If you want to create a file, +;; visit that file with C-x C-f. + +Below some empty line[.]" + ("(") + ";; This buffer is for notes you don't want to save, +;; and for Lisp evaluation. If you want to create a file, +;; visit that file with C-x C-f. + +\[B]elow some empty line." + ("(") + ";; This buffer is for notes you don't want to save, +;; and for Lisp evaluation. If you want to create a file, +;; visit that file with C-x C-f. +\[] +Below some empty line." + ("(") + ";; This buffer is for notes you don't want to save, +;; and for Lisp evaluation. [I]f you want to create a file, +;; visit that file with C-x C-f. + +Below some empty line." + ("(") + "[;]; This buffer is for notes you don't want to save, +;; and for Lisp evaluation. If you want to create a file, +;; visit that file with C-x C-f. + +Below some empty line.")) + (ert-info ("With count") + (evil-test-buffer + ";; This buffer is for notes you don't want to save, +;; and for Lisp evaluation. If you want to create a file, +;; visit that file with C-x C-f. + +Below some empty line[.]" + ("2(") + ";; This buffer is for notes you don't want to save, +;; and for Lisp evaluation. If you want to create a file, +;; visit that file with C-x C-f. +\[] +Below some empty line." + ("2(") + "[;]; This buffer is for notes you don't want to save, +;; and for Lisp evaluation. If you want to create a file, +;; visit that file with C-x C-f. + +Below some empty line.")) + (ert-info ("Beginning of buffer") + (evil-test-buffer + ";; This buffer is for notes you don't want to save[.]" + ("100(") + "[;]; This buffer is for notes you don't want to save." + (should-error (execute-kbd-macro "(")) + (should-error (execute-kbd-macro "42(")))) + (ert-info ("Beginning of buffer with newlines") + (evil-test-buffer + "\n\n;; This buffer is for notes you don't want to save[.]" + ("100(") + "[]\n\n;; This buffer is for notes you don't want to save." + (should-error (execute-kbd-macro "(")) + (should-error (execute-kbd-macro "42("))))) + +(ert-deftest evil-test-find-char () + "Test `evil-find-char'" + :tags '(evil motion) + (ert-info ("Simple") + (evil-test-buffer + "[;]; This buffer is for notes." + ("fT") + ";; [T]his buffer is for notes.")) + (ert-info ("With count") + (evil-test-buffer + "[;]; This buffer is for notes." + ("2fe") + ";; This buffer is for not[e]s.")) + (ert-info ("Repeat") + (evil-test-buffer + "[;]; This buffer is for notes." + ("fe;") + ";; This buffer is for not[e]s.")) + (ert-info ("Repeat backward") + (evil-test-buffer + "[;]; This buffer is for notes." + ("2fe,") + ";; This buff[e]r is for notes.")) + (ert-info ("No match") + (evil-test-buffer + "[;]; This buffer is for notes." + (should-error (execute-kbd-macro "fL")))) + (ert-info ("End of line") + (let ((evil-cross-lines t)) + (evil-test-buffer + "[;]; This buffer is for notes, +;; and for Lisp evaluation." + ("fL") + ";; This buffer is for notes, +;; and for [L]isp evaluation."))) + (ert-info ("Empty line") + (evil-test-buffer + "[] +This buffer is for notes." + (should-error (execute-kbd-macro "fT"))))) + +(ert-deftest evil-test-find-char-backward () + "Test `evil-find-char-backward'" + :tags '(evil motion) + (ert-info ("Simple") + (evil-test-buffer + ";; This buffer is for notes[.]" + ("FT") + ";; [T]his buffer is for notes.")) + (ert-info ("With count") + (evil-test-buffer + ";; This buffer is for notes[.]" + ("2Fe") + ";; This buff[e]r is for notes.")) + (ert-info ("Repeat") + (evil-test-buffer + ";; This buffer is for notes[.]" + ("Fe;") + ";; This buff[e]r is for notes.")) + (ert-info ("Repeat backward") + (evil-test-buffer + ";; This buffer is for notes[.]" + ("2Fe,") + ";; This buffer is for not[e]s.")) + (ert-info ("No match") + (evil-test-buffer + ";; This buffer is for notes[.]" + (should-error (execute-kbd-macro "FL")))) + (ert-info ("End of line") + (let ((evil-cross-lines t)) + (evil-test-buffer + ";; This buffer is for notes, +;; and for Lisp evaluation[.]" + ("FT") + ";; [T]his buffer is for notes, +;; and for Lisp evaluation.")))) + +(ert-deftest evil-test-find-digraph-char () + "Test evil-read-digraph-char while finding char." + :tags '(evil motion) + (ert-info ("Find digraph char") + (evil-test-buffer + "a[b]cde∀g" + ("f\C-kFA") + "abcde[∀]g"))) + +(ert-deftest evil-test-find-char-to () + "Test `evil-find-char-to'" + :tags '(evil motion) + (ert-info ("Simple") + (evil-test-buffer + "[;]; This buffer is for notes." + ("tT") + ";;[ ]This buffer is for notes.")) + (ert-info ("With count") + (evil-test-buffer + "[;]; This buffer is for notes." + ("2te") + ";; This buffer is for no[t]es.")) + (ert-info ("Repeat") + (evil-test-buffer + "[;]; This buffer is for notes." + ("tel;") + ";; This buffer is for no[t]es.")) + (ert-info ("Repeat backward") + (evil-test-buffer + "[;]; This buffer is for notes." + ("2te,") + ";; This buffe[r] is for notes.")) + (ert-info ("Repeat should skip adjacent character") + (let ((evil-repeat-find-to-skip-next t)) + (evil-test-buffer + "[a]aaxaaaxaaaxaaa" + ("tx;") + "aaaxaa[a]xaaaxaaa" + (";") + "aaaxaaaxaa[a]xaaa" + (",") + "aaaxaaax[a]aaxaaa" + (",") + "aaax[a]aaxaaaxaaa"))) + (ert-info ("Repeat should NOT skip adjacent character") + (let ((evil-repeat-find-to-skip-next nil)) + (evil-test-buffer + "[a]aaxaaaxaaaxaaa" + ("tx;") + "aa[a]xaaaxaaaxaaa"))) + (ert-info ("No match") + (evil-test-buffer + "[;]; This buffer is for notes." + (should-error (execute-kbd-macro "tL")))) + (ert-info ("End of line") + (let ((evil-cross-lines t)) + (evil-test-buffer + "[;]; This buffer is for notes, +;; and for Lisp evaluation." + ("tL") + ";; This buffer is for notes, +;; and for[ ]Lisp evaluation.")))) + +(ert-deftest evil-test-find-char-to-backward () + "Test `evil-find-char-to-backward'" + :tags '(evil motion) + (ert-info ("Simple") + (evil-test-buffer + ";; This buffer is for notes[.]" + ("TT") + ";; T[h]is buffer is for notes.")) + (ert-info ("With count") + (evil-test-buffer + ";; This buffer is for notes[.]" + ("2Te") + ";; This buffe[r] is for notes.")) + (ert-info ("Repeat") + (evil-test-buffer + ";; This buffer is for notes[.]" + ("Teh;") + ";; This buffe[r] is for notes.")) + (ert-info ("Repeat backward") + (evil-test-buffer + ";; This buffer is for notes[.]" + ("2Te,") + ";; This buffer is for no[t]es.")) + (ert-info ("Repeat should skip adjacent character") + (let ((evil-repeat-find-to-skip-next t)) + (evil-test-buffer + "aaaxaaaxaaaxaa[a]" + ("Tx;") + "aaaxaaax[a]aaxaaa" + (";") + "aaax[a]aaxaaaxaaa" + (",") + "aaaxaa[a]xaaaxaaa" + (",") + "aaaxaaaxaa[a]xaaa"))) + (ert-info ("Repeat should NOT skip adjacent character") + (let ((evil-repeat-find-to-skip-next nil)) + (evil-test-buffer + "aaaxaaaxaaaxaa[a]" + ("Tx;") + "aaaxaaaxaaax[a]aa"))) + (ert-info ("No match") + (evil-test-buffer + ";; This buffer is for notes[.]" + (should-error (execute-kbd-macro "TL")))) + (ert-info ("End of line") + (let ((evil-cross-lines t)) + (evil-test-buffer + ";; This buffer is for notes, +;; and for Lisp evaluation[.]" + ("TT") + ";; T[h]is buffer is for notes, +;; and for Lisp evaluation.")))) + +(ert-deftest evil-test-jump-item () + "Test `evil-jump-item'" + :tags '(evil motion) + (ert-info ("Simple") + (evil-test-buffer + "int main[(]int argc, char** argv)" + ("%") + "int main(int argc, char** argv[)]" + ("%") + "int main[(]int argc, char** argv)")) + (ert-info ("Before parenthesis") + (evil-test-buffer + "[i]nt main(int argc, char** argv)" + ("%") + "int main(int argc, char** argv[)]" + ("5h") + "int main(int argc, char**[ ]argv)" + ("%") + "int main[(]int argc, char** argv)")) + (ert-info ("Over several lines") + (evil-test-buffer + "int main(int argc, char** argv) +\[{] + printf(\"Hello world\\n\"); + return EXIT_SUCCESS; +}" + ("%") + "int main(int argc, char** argv) +{ + printf(\"Hello world\\n\"); + return EXIT_SUCCESS; +\[}]")) + (ert-info ("On line without parenthesis") + (evil-test-buffer + "[#]include " + (should-error (execute-kbd-macro "%")))) + (ert-info ("Before unmatched opening parenthesies") + (evil-test-buffer + "x[x]xx ( yyyyy () zzzz" + (should-error (execute-kbd-macro "%")) + "x[x]xx ( yyyyy () zzzz")) + (ert-info ("Before unmatched closing parenthesies") + (evil-test-buffer + "x[x]xx ) yyyyy () zzzz" + (should-error (execute-kbd-macro "%")) + "x[x]xx ) yyyyy () zzzz")) + + (ert-info ("At the end of the line") + (evil-test-buffer + "[p]ublic void foo(String bar) {\n blabla;\n}\n" + ("v$%") + "public void foo(String bar) {\n blabla;\n[}]\n"))) + +(ert-deftest evil-test-unmatched-paren () + "Test `evil-previous-open-paren' and `evil-next-close-paren'" + :tags '(evil motion) + (ert-info ("Simple") + (evil-test-buffer + "foo ( { ( [b]ar ) baz } )" + ("[(") + "foo ( { [(] bar ) baz } )" + ("])") + "foo ( { ( bar [)] baz } )" + ("[(") + "foo ( { [(] bar ) baz } )" + ("[(") + "foo [(] { ( bar ) baz } )" + ("f)])") + "foo ( { ( bar ) baz } [)]")) + (ert-info ("With count") + (evil-test-buffer + "foo ( { ( [b]ar ) baz } )" + ("2[(") + "foo [(] { ( bar ) baz } )") + (evil-test-buffer + "foo ( { ( [b]ar ) baz } )" + ("2])") + "foo ( { ( bar ) baz } [)]"))) + +(ert-deftest evil-test-next-mark () + "Test `evil-next-mark', `evil-previous-mark'" + :tags '(evil motion) + (ert-info ("Can move to next mark, next mark line, +previous mark and previous mark line") + (evil-test-buffer + "[a]lpha bravo +charlie delta echo +foxtrot golf hotel +india juliet" + ("ma" "w" "mb" "w" + "mc" "w" "md" "w" "me" "w" + "mf" "w" "mg" "w" "mh" "w" + "mi" "w" "mj") + "alpha bravo +charlie delta echo +foxtrot golf hotel +india [j]uliet" + ("3]`") + "alpha bravo +[c]harlie delta echo +foxtrot golf hotel +india juliet" + ("]'") + "alpha bravo +charlie delta echo +[f]oxtrot golf hotel +india juliet" + ("[`") + "alpha bravo +charlie delta [e]cho +foxtrot golf hotel +india juliet" + ("2['") + "alpha bravo +charlie delta echo +foxtrot golf hotel +[i]ndia juliet"))) + +(ert-deftest evil-set-col-0-mark-test () + "Test `evil-set-col-0-mark' ex command" + :tags '(evil ex) + (evil-test-buffer + "Lin[e] 1 +Line 2" + (":mark k" [return] "G" "`k") + "[L]ine 1 +Line 2")) + +(ert-deftest evil-delete-marks-test () + "Test `evil-delete-marks' ex command" + :tags '(evil ex) + (ert-info ("Can delete marks") + (evil-test-buffer + "[O]ne line is enough if we use backtick to navigate" + ("mO" "w" "ml" "w" "mi" "$b" "m4") + "One line is enough if we use backtick to [n]avigate" + ("`O") + "[O]ne line is enough if we use backtick to navigate" + (":delm O" [return] "`i") + "One line [i]s enough if we use backtick to navigate" + (error user-error "`O") + "One line [i]s enough if we use backtick to navigate" + ("`4") + "One line is enough if we use backtick to [n]avigate" + (":delm h-m" [return]) + (error user-error "`i") + "One line is enough if we use backtick to [n]avigate"))) + +(ert-deftest evil-test-flyspell-motions () + "Test flyspell motions" + :tags '(evil motion) + (skip-unless (executable-find "aspell")) + (ert-info ("Simple") + (evil-test-buffer + "[I] cannt tpye for lyfe" + (flyspell-mode) + (flyspell-buffer) + ("]s") + "I [c]annt tpye for lyfe" + ("]s") + "I cannt [t]pye for lyfe" + ("]s") + "I cannt tpye for [l]yfe" + ("]s") + "I [c]annt tpye for lyfe" + ("[s") + "I cannt tpye for [l]yfe" + ("[s") + "I cannt [t]pye for lyfe")) + (ert-info ("With count") + (evil-test-buffer + "[I] cannt tpye for lyfe" + (flyspell-mode) + (flyspell-buffer) + ("2]s") + "I cannt [t]pye for lyfe" + ("2]s") + "I [c]annt tpye for lyfe" + ("2[s") + "I cannt [t]pye for lyfe" + ("2[s") + "I cannt tpye for [l]yfe")) + (ert-info ("With evil-search-wrap disabled") + (let (evil-search-wrap) + (evil-test-buffer + "[I] cannt tpye for lyfe" + (flyspell-mode) + (flyspell-buffer) + ("]s") + "I [c]annt tpye for lyfe" + ("]s") + "I cannt [t]pye for lyfe" + ("]s") + "I cannt tpye for [l]yfe" + ("]s") + "I cannt tpye for [l]yfe"))) + (ert-info ("One mistake") + (evil-test-buffer + "[I]'m almst there..." + (flyspell-mode) + (flyspell-buffer) + ("]s") + "I'm [a]lmst there..." + ("]s") + "I'm [a]lmst there...")) + (ert-info ("No mistakes") + (evil-test-buffer + "[I]'ve learned to type!" + (flyspell-mode) + (flyspell-buffer) + ("]s") + "[I]'ve learned to type!" + ("[s") + "[I]'ve learned to type!"))) + +;;; Text objects + +(ert-deftest evil-test-text-object () + "Test `evil-define-text-object'" + :tags '(evil text-object) + (let ((object (evil-define-text-object nil (count &optional beg end type) + (let ((sel (and beg end (evil-range beg end)))) + (when (and sel (> count 0)) (forward-char 1)) + (let ((range (if (< count 0) + (list (- (point) 3) (point)) + (list (point) (+ (point) 3))))) + (if sel + (evil-range-union range sel) + range)))))) + (ert-info ("Select three characters after point") + (evil-test-buffer + :state operator + ";; [T]his buffer is for notes." + (should (equal (funcall object 1) '(4 7 inclusive))))) + (ert-info ("Select three characters before point") + (evil-test-buffer + :state operator + ";; [T]his buffer is for notes." + (should (equal (funcall object -1) '(1 4 inclusive))))) + (ert-info ("Select three characters after selection") + (evil-test-buffer + ";; buffer is for notes." + (call-interactively object) + ";; ffer is for notes.")) + (ert-info ("Select three characters before selection") + (evil-test-buffer + ";; <[T]his> buffer is for notes." + (call-interactively object) + "<[;]; This> buffer is for notes.")) + (ert-info ("Delete three characters after point") + (evil-test-buffer + "[;]; This buffer is for notes." + (define-key evil-operator-state-local-map "io" object) + ("dio") + "[T]his buffer is for notes.")))) + +(ert-deftest evil-test-word-objects () + "Test `evil-inner-word' and `evil-a-word'" + :tags '(evil text-object) + (ert-info ("Select a word") + (evil-test-buffer + ";; [T]his buffer is for notes." + ("viw") + ";; buffer is for notes.") + (evil-test-buffer + ";; [T]his buffer is for notes." + ("vaw") + ";; buffer is for notes.") + (evil-test-buffer + ";; Thi[s] buffer is for notes." + ("viw") + ";; buffer is for notes.") + (evil-test-buffer + ";; Thi[s] buffer is for notes." + ("vaw") + ";; buffer is for notes.")) + (ert-info ("Select two words") + (ert-info ("Include whitespace on this side") + (evil-test-buffer + ";;< Thi[s]> buffer is for notes." + ("aw") + ";;< This buffe[r]> is for notes.") + (evil-test-buffer + ";; This <[b]uffer >is for notes." + ("aw") + ";; <[T]his buffer >is for notes.")) + (ert-info ("Include whitespace on the other side") + (evil-test-buffer + ";; buffer is for notes." + ("aw") + ";; is for notes.") + (evil-test-buffer + ";; This<[ ]buffer> is for notes." + ("aw") + ";;<[ ]This buffer> is for notes."))) + (ert-info ("select first visual word") + (evil-test-buffer + "([a])" + ("viw") + "(<[a]>)")) + (ert-info ("Deleting whitespace is confined to the line") + (evil-test-buffer + "foo\n [ ] bar" + ("diw") + "foo\n[b]ar") + (evil-test-buffer + "foo\n [ ] bar" + ("diW") + "foo\n[b]ar"))) + +(ert-deftest evil-test-word-objects-cjk () + "Test `evil-inner-word' and `evil-a-word' on CJK words" + :tags '(evil text-object cjk) + (ert-info ("Select a word") + (evil-test-buffer + "[a]bcd1234" + ("viw") + "") + (evil-test-buffer + "[a]bcd1234" + ("vaw") + "") + (evil-test-buffer + "[a]bcd漢字" + ("viw") + "漢字") + (evil-test-buffer + "[a]bcd漢字" + ("vaw") + "漢字") + (evil-test-buffer + "[a]bcdひらがな" + ("viw") + "ひらがな") + (evil-test-buffer + "[a]bcdひらがな" + ("vaw") + "ひらがな") + (evil-test-buffer + "[a]bcdカタカナ" + ("viw") + "カタカナ") + (evil-test-buffer + "[a]bcdカタカナ" + ("vaw") + "カタカナ") + (evil-test-buffer + "[a]bcdカタカナ" + ("viw") + "") + (evil-test-buffer + "[a]bcdカタカナ" + ("vaw") + "") + (evil-test-buffer + "[a]bcdABC" + ("viw") + "") + (evil-test-buffer + "[a]bcdABC" + ("vaw") + "") + (evil-test-buffer + "[a]bcd123" + ("viw") + "") + (evil-test-buffer + "[a]bcd123" + ("vaw") + "") + (evil-test-buffer + "[a]bcd한글" + ("viw") + "한글") + (evil-test-buffer + "[a]bcd한글" + ("vaw") + "한글") + (evil-test-buffer + "[1]234abcd" + ("viw") + "<1234abc[d]>") + (evil-test-buffer + "[1]234abcd" + ("vaw") + "<1234abc[d]>") + (evil-test-buffer + "[1]234漢字" + ("viw") + "<123[4]>漢字") + (evil-test-buffer + "[1]234漢字" + ("vaw") + "<123[4]>漢字") + (evil-test-buffer + "[1]234ひらがな" + ("viw") + "<123[4]>ひらがな") + (evil-test-buffer + "[1]234ひらがな" + ("vaw") + "<123[4]>ひらがな") + (evil-test-buffer + "[1]234カタカナ" + ("viw") + "<123[4]>カタカナ") + (evil-test-buffer + "[1]234カタカナ" + ("vaw") + "<123[4]>カタカナ") + (evil-test-buffer + "[1]234カタカナ" + ("viw") + "<1234カタカ[ナ]>") + (evil-test-buffer + "[1]234カタカナ" + ("vaw") + "<1234カタカ[ナ]>") + (evil-test-buffer + "[1]234ABC" + ("viw") + "<1234AB[C]>") + (evil-test-buffer + "[1]234ABC" + ("vaw") + "<1234AB[C]>") + (evil-test-buffer + "[1]234123" + ("viw") + "<123412[3]>") + (evil-test-buffer + "[1]234123" + ("vaw") + "<123412[3]>") + (evil-test-buffer + "[1]234한글" + ("viw") + "<123[4]>한글") + (evil-test-buffer + "[1]234한글" + ("vaw") + "<123[4]>한글") + (evil-test-buffer + "[漢]字abcd" + ("viw") + "<漢[字]>abcd") + (evil-test-buffer + "[漢]字abcd" + ("vaw") + "<漢[字]>abcd") + (evil-test-buffer + "[漢]字1234" + ("viw") + "<漢[字]>1234") + (evil-test-buffer + "[漢]字1234" + ("vaw") + "<漢[字]>1234") + (evil-test-buffer + "[漢]字ひらがな" + ("viw") + "<漢[字]>ひらがな") + (evil-test-buffer + "[漢]字ひらがな" + ("vaw") + "<漢[字]>ひらがな") + (evil-test-buffer + "[漢]字カタカナ" + ("viw") + "<漢[字]>カタカナ") + (evil-test-buffer + "[漢]字カタカナ" + ("vaw") + "<漢[字]>カタカナ") + (evil-test-buffer + "[漢]字カタカナ" + ("viw") + "<漢[字]>カタカナ") + (evil-test-buffer + "[漢]字カタカナ" + ("vaw") + "<漢[字]>カタカナ") + (evil-test-buffer + "[漢]字ABC" + ("viw") + "<漢[字]>ABC") + (evil-test-buffer + "[漢]字ABC" + ("vaw") + "<漢[字]>ABC") + (evil-test-buffer + "[漢]字123" + ("viw") + "<漢[字]>123") + (evil-test-buffer + "[漢]字123" + ("vaw") + "<漢[字]>123") + (evil-test-buffer + "[漢]字한글" + ("viw") + "<漢[字]>한글") + (evil-test-buffer + "[漢]字한글" + ("vaw") + "<漢[字]>한글") + (evil-test-buffer + "[ひ]らがなabcd" + ("viw") + "<ひらが[な]>abcd") + (evil-test-buffer + "[ひ]らがなabcd" + ("vaw") + "<ひらが[な]>abcd") + (evil-test-buffer + "[ひ]らがな1234" + ("viw") + "<ひらが[な]>1234") + (evil-test-buffer + "[ひ]らがな1234" + ("vaw") + "<ひらが[な]>1234") + (evil-test-buffer + "[ひ]らがな漢字" + ("viw") + "<ひらが[な]>漢字") + (evil-test-buffer + "[ひ]らがな漢字" + ("vaw") + "<ひらが[な]>漢字") + (evil-test-buffer + "[ひ]らがなカタカナ" + ("viw") + "<ひらが[な]>カタカナ") + (evil-test-buffer + "[ひ]らがなカタカナ" + ("vaw") + "<ひらが[な]>カタカナ") + (evil-test-buffer + "[ひ]らがなカタカナ" + ("viw") + "<ひらが[な]>カタカナ") + (evil-test-buffer + "[ひ]らがなカタカナ" + ("vaw") + "<ひらが[な]>カタカナ") + (evil-test-buffer + "[ひ]らがなABC" + ("viw") + "<ひらが[な]>ABC") + (evil-test-buffer + "[ひ]らがなABC" + ("vaw") + "<ひらが[な]>ABC") + (evil-test-buffer + "[ひ]らがな123" + ("viw") + "<ひらが[な]>123") + (evil-test-buffer + "[ひ]らがな123" + ("vaw") + "<ひらが[な]>123") + (evil-test-buffer + "[ひ]らがな한글" + ("viw") + "<ひらが[な]>한글") + (evil-test-buffer + "[ひ]らがな한글" + ("vaw") + "<ひらが[な]>한글") + (evil-test-buffer + "[カ]タカナabcd" + ("viw") + "<カタカ[ナ]>abcd") + (evil-test-buffer + "[カ]タカナabcd" + ("vaw") + "<カタカ[ナ]>abcd") + (evil-test-buffer + "[カ]タカナ1234" + ("viw") + "<カタカ[ナ]>1234") + (evil-test-buffer + "[カ]タカナ1234" + ("vaw") + "<カタカ[ナ]>1234") + (evil-test-buffer + "[カ]タカナ漢字" + ("viw") + "<カタカ[ナ]>漢字") + (evil-test-buffer + "[カ]タカナ漢字" + ("vaw") + "<カタカ[ナ]>漢字") + (evil-test-buffer + "[カ]タカナひらがな" + ("viw") + "<カタカ[ナ]>ひらがな") + (evil-test-buffer + "[カ]タカナひらがな" + ("vaw") + "<カタカ[ナ]>ひらがな") + (evil-test-buffer + "[カ]タカナカタカナ" + ("viw") + "<カタカ[ナ]>カタカナ") + (evil-test-buffer + "[カ]タカナカタカナ" + ("vaw") + "<カタカ[ナ]>カタカナ") + (evil-test-buffer + "[カ]タカナABC" + ("viw") + "<カタカ[ナ]>ABC") + (evil-test-buffer + "[カ]タカナABC" + ("vaw") + "<カタカ[ナ]>ABC") + (evil-test-buffer + "[カ]タカナ123" + ("viw") + "<カタカ[ナ]>123") + (evil-test-buffer + "[カ]タカナ123" + ("vaw") + "<カタカ[ナ]>123") + (evil-test-buffer + "[カ]タカナ한글" + ("viw") + "<カタカ[ナ]>한글") + (evil-test-buffer + "[カ]タカナ한글" + ("vaw") + "<カタカ[ナ]>한글") + (evil-test-buffer + "[カ]タカナabcd" + ("viw") + "<カタカナabc[d]>") + (evil-test-buffer + "[カ]タカナabcd" + ("vaw") + "<カタカナabc[d]>") + (evil-test-buffer + "[カ]タカナ1234" + ("viw") + "<カタカナ123[4]>") + (evil-test-buffer + "[カ]タカナ1234" + ("vaw") + "<カタカナ123[4]>") + (evil-test-buffer + "[カ]タカナ漢字" + ("viw") + "<カタカ[ナ]>漢字") + (evil-test-buffer + "[カ]タカナ漢字" + ("vaw") + "<カタカ[ナ]>漢字") + (evil-test-buffer + "[カ]タカナひらがな" + ("viw") + "<カタカ[ナ]>ひらがな") + (evil-test-buffer + "[カ]タカナひらがな" + ("vaw") + "<カタカ[ナ]>ひらがな") + (evil-test-buffer + "[カ]タカナカタカナ" + ("viw") + "<カタカ[ナ]>カタカナ") + (evil-test-buffer + "[カ]タカナカタカナ" + ("vaw") + "<カタカ[ナ]>カタカナ") + (evil-test-buffer + "[カ]タカナABC" + ("viw") + "<カタカナAB[C]>") + (evil-test-buffer + "[カ]タカナABC" + ("vaw") + "<カタカナAB[C]>") + (evil-test-buffer + "[カ]タカナ123" + ("viw") + "<カタカナ12[3]>") + (evil-test-buffer + "[カ]タカナ123" + ("vaw") + "<カタカナ12[3]>") + (evil-test-buffer + "[カ]タカナ한글" + ("viw") + "<カタカ[ナ]>한글") + (evil-test-buffer + "[カ]タカナ한글" + ("vaw") + "<カタカ[ナ]>한글") + (evil-test-buffer + "[A]BCabcd" + ("viw") + "<ABCabc[d]>") + (evil-test-buffer + "[A]BCabcd" + ("vaw") + "<ABCabc[d]>") + (evil-test-buffer + "[A]BC1234" + ("viw") + "<ABC123[4]>") + (evil-test-buffer + "[A]BC1234" + ("vaw") + "<ABC123[4]>") + (evil-test-buffer + "[A]BC漢字" + ("viw") + "<AB[C]>漢字") + (evil-test-buffer + "[A]BC漢字" + ("vaw") + "<AB[C]>漢字") + (evil-test-buffer + "[A]BCひらがな" + ("viw") + "<AB[C]>ひらがな") + (evil-test-buffer + "[A]BCひらがな" + ("vaw") + "<AB[C]>ひらがな") + (evil-test-buffer + "[A]BCカタカナ" + ("viw") + "<AB[C]>カタカナ") + (evil-test-buffer + "[A]BCカタカナ" + ("vaw") + "<AB[C]>カタカナ") + (evil-test-buffer + "[A]BCカタカナ" + ("viw") + "<ABCカタカ[ナ]>") + (evil-test-buffer + "[A]BCカタカナ" + ("vaw") + "<ABCカタカ[ナ]>") + (evil-test-buffer + "[A]BC123" + ("viw") + "<ABC12[3]>") + (evil-test-buffer + "[A]BC123" + ("vaw") + "<ABC12[3]>") + (evil-test-buffer + "[A]BC한글" + ("viw") + "<AB[C]>한글") + (evil-test-buffer + "[A]BC한글" + ("vaw") + "<AB[C]>한글") + (evil-test-buffer + "[1]23abcd" + ("viw") + "<123abc[d]>") + (evil-test-buffer + "[1]23abcd" + ("vaw") + "<123abc[d]>") + (evil-test-buffer + "[1]231234" + ("viw") + "<123123[4]>") + (evil-test-buffer + "[1]231234" + ("vaw") + "<123123[4]>") + (evil-test-buffer + "[1]23漢字" + ("viw") + "<12[3]>漢字") + (evil-test-buffer + "[1]23漢字" + ("vaw") + "<12[3]>漢字") + (evil-test-buffer + "[1]23ひらがな" + ("viw") + "<12[3]>ひらがな") + (evil-test-buffer + "[1]23ひらがな" + ("vaw") + "<12[3]>ひらがな") + (evil-test-buffer + "[1]23カタカナ" + ("viw") + "<12[3]>カタカナ") + (evil-test-buffer + "[1]23カタカナ" + ("vaw") + "<12[3]>カタカナ") + (evil-test-buffer + "[1]23カタカナ" + ("viw") + "<123カタカ[ナ]>") + (evil-test-buffer + "[1]23カタカナ" + ("vaw") + "<123カタカ[ナ]>") + (evil-test-buffer + "[1]23ABC" + ("viw") + "<123AB[C]>") + (evil-test-buffer + "[1]23ABC" + ("vaw") + "<123AB[C]>") + (evil-test-buffer + "[1]23한글" + ("viw") + "<12[3]>한글") + (evil-test-buffer + "[1]23한글" + ("vaw") + "<12[3]>한글") + (evil-test-buffer + "[한]글abcd" + ("viw") + "<한[글]>abcd") + (evil-test-buffer + "[한]글abcd" + ("vaw") + "<한[글]>abcd") + (evil-test-buffer + "[한]글1234" + ("viw") + "<한[글]>1234") + (evil-test-buffer + "[한]글1234" + ("vaw") + "<한[글]>1234") + (evil-test-buffer + "[한]글漢字" + ("viw") + "<한[글]>漢字") + (evil-test-buffer + "[한]글漢字" + ("vaw") + "<한[글]>漢字") + (evil-test-buffer + "[한]글ひらがな" + ("viw") + "<한[글]>ひらがな") + (evil-test-buffer + "[한]글ひらがな" + ("vaw") + "<한[글]>ひらがな") + (evil-test-buffer + "[한]글カタカナ" + ("viw") + "<한[글]>カタカナ") + (evil-test-buffer + "[한]글カタカナ" + ("vaw") + "<한[글]>カタカナ") + (evil-test-buffer + "[한]글カタカナ" + ("viw") + "<한[글]>カタカナ") + (evil-test-buffer + "[한]글カタカナ" + ("vaw") + "<한[글]>カタカナ") + (evil-test-buffer + "[한]글ABC" + ("viw") + "<한[글]>ABC") + (evil-test-buffer + "[한]글ABC" + ("vaw") + "<한[글]>ABC") + (evil-test-buffer + "[한]글123" + ("viw") + "<한[글]>123") + (evil-test-buffer + "[한]글123" + ("vaw") + "<한[글]>123"))) + +(ert-deftest evil-test-paragraph-objects () + "Test `evil-inner-paragraph' and `evil-a-paragraph'" + :tags '(evil text-object) + (ert-info ("Select a paragraph with point at beginning") + (evil-test-buffer + "[;]; This buffer is for notes, +;; and for Lisp evaluation. + +;; This buffer is for notes, +;; and for Lisp evaluation." + ("vap") + "<;; This buffer is for notes, +;; and for Lisp evaluation. +\[]\n>\ +;; This buffer is for notes, +;; and for Lisp evaluation.")) + (ert-info ("Select a paragraph with point at last line") + (evil-test-buffer + ";; This buffer is for notes, +\[;]; and for Lisp evaluation. + +;; This buffer is for notes, +;; and for Lisp evaluation." + ("vap") + "<;; This buffer is for notes, +;; and for Lisp evaluation. +\[]\n>\ +;; This buffer is for notes, +;; and for Lisp evaluation.")) + (ert-info ("Select a paragraph with point after paragraph") + (evil-test-buffer + ";; This buffer is for notes, +;; and for Lisp evaluation. +\[] +;; This buffer is for notes, +;; and for Lisp evaluation." + ("vap") + ";; This buffer is for notes, +;; and for Lisp evaluation. +< +;; This buffer is for notes, +;; and for Lisp evaluation[.]>")) + (ert-info ("Select inner paragraph") + (evil-test-buffer + "[;]; This buffer is for notes, +;; and for Lisp evaluation. + +;; This buffer is for notes, +;; and for Lisp evaluation." + ("vip") + "<;; This buffer is for notes, +;; and for Lisp evaluation.[] +> +;; This buffer is for notes, +;; and for Lisp evaluation.") + (evil-test-buffer + ";; This buffer is for notes, +\[;]; and for Lisp evaluation. + +;; This buffer is for notes, +;; and for Lisp evaluation." + ("vip") + "<;; This buffer is for notes, +;; and for Lisp evaluation.[] +> +;; This buffer is for notes, +;; and for Lisp evaluation.") + (evil-test-buffer + ";; This buffer is for notes, +;; and for Lisp evaluation. +\[] +;; This buffer is for notes, +;; and for Lisp evaluation." + ("vip") + ";; This buffer is for notes, +;; and for Lisp evaluation. +< +;; This buffer is for notes, +;; and for Lisp evaluation[.]>"))) + +(ert-deftest evil-test-quote-objects () + "Test `evil-inner-single-quote' and `evil-a-single-quote'" + :tags '(evil text-object) + (ert-info ("Select text inside of '...'") + (evil-test-buffer + "This is 'a [t]est' for quote objects." + ("vi'") + "This is '' for quote objects.") + (evil-test-buffer + "This is \"a '[t]est'\" for quote objects." + ("vi'") + "This is \"a ''\" for quote objects.")) + (ert-info ("Select text including enclosing quotes") + (evil-test-buffer + "This is 'a [t]est' for quote objects." + ("v2i'") + "This is <'a test[']> for quote objects.")) + (ert-info ("Select text including enclosing quotes and following space") + (evil-test-buffer + "This is 'a [t]est' for quote objects." + ("va'") + "This is <'a test'[ ]>for quote objects.")) + (ert-info ("Select text including enclosing quotes and previous space") + (evil-test-buffer + "This is 'a [t]est'. For quote objects." + ("va'") + "This is< 'a test[']>. For quote objects.")) + (ert-info ("Select text on opening quote") + (evil-test-buffer + "This is [\"]a test\". For \"quote\" objects." + (emacs-lisp-mode) + ("va\"") + "This is< \"a test[\"]>. For \"quote\" objects.")) + (ert-info ("Select text on closing quote") + (evil-test-buffer + "This is \"a test[\"]. For \"quote\" objects." + (emacs-lisp-mode) + ("va\"") + "This is< \"a test[\"]>. For \"quote\" objects.")) + (ert-info ("Delete text from outside") + (evil-test-buffer + "Th[i]s is \"a test\". For \"quote\" objects." + (emacs-lisp-mode) + ("da\"") + "This is[.] For \"quote\" objects.")) + (ert-info ("Operator on empty quotes") + (evil-test-buffer + "This is [a]n \"\" empty quote" + (emacs-lisp-mode) + ("ci\"XXX" [escape]) + "This is an \"XX[X]\" empty quote"))) + +(ert-deftest evil-test-paren-objects () + "Test `evil-inner-paren', etc." + :tags '(evil text-object) + (ert-info ("Select inner text") + (evil-test-buffer + "[(]aaa)" + (emacs-lisp-mode) ; syntax + ("vi(") + "()") + (evil-test-buffer + "(aaa[)]" + (emacs-lisp-mode) + ("vi(") + "()") + (ert-info ("Next to outer delimiter") + (evil-test-buffer + "([(]aaa))" + (emacs-lisp-mode) + ("vi(") + "(())") + (evil-test-buffer + "((aaa[)])" + (emacs-lisp-mode) + ("vi(") + "(())"))) + (ert-info ("Select double inner parentheses") + (evil-test-buffer + "([(]word))" + ("dib") + "(())") + (evil-test-buffer + "[(](word))" + ("dib") + "()") + (evil-test-buffer + "((word[)])" + ("dib") + "(())") + (evil-test-buffer + "((word)[)]" + ("dib") + "()")) + (ert-info ("Select double outer parentheses") + (evil-test-buffer + "a([(]word))b" + ("dab") + "a()b") + (evil-test-buffer + "a[(](word))b" + ("dab") + "ab") + (evil-test-buffer + "a((word[)])b" + ("dab") + "a()b") + (evil-test-buffer + "a((word)[)]b" + ("dab") + "ab")) + (ert-info ("Select parentheses inside strings") + (evil-test-buffer + "(aaa \"b(b[b]b)\" aa)" + (emacs-lisp-mode) + ("va(") + "(aaa \"b<(bbb[)]>\" aa)")) + (ert-info ("Break out of empty strings") + (evil-test-buffer + "(aaa \"bb[b]b\" aa)" + (emacs-lisp-mode) + ("va(") + "<(aaa \"bbbb\" aa[)]>")) + (ert-info ("Select inner parentheses around strings") + (evil-test-buffer + "((\"t[e]st\"))\n" + (emacs-lisp-mode) + ("vib") + "((<\"test[\"]>))\n" + ("ib") + "(<(\"test\"[)]>)\n") + (evil-test-buffer + "( ( \"t[e]st\" ) )\n" + (emacs-lisp-mode) + ("vib") + "( (< \"test\"[ ]>) )\n" + ("ib") + "(< ( \"test\" )[ ]>)\n") + (evil-test-buffer + "((\"t[e]st\"))\n" + (emacs-lisp-mode) + ("vhhib") + "((<[\"]test\">))\n" + ("ib") + "(<[(]\"test\")>)\n") + (evil-test-buffer + "( ( \"t[e]st\" ) )\n" + (emacs-lisp-mode) + ("vhhib") + "( (<[ ]\"test\" >) )\n" + ("ib") + "(<[ ]( \"test\" ) >)\n")) + (ert-info ("Select outer parentheses around strings") + (evil-test-buffer + "((\"t[e]st\"))\n" + (emacs-lisp-mode) + ("vab") + "(<(\"test\"[)]>)\n" + ("ab") + "<((\"test\")[)]>\n") + (evil-test-buffer + "( ( \"t[e]st\" ) )\n" + (emacs-lisp-mode) + ("vab") + "( <( \"test\" [)]> )\n" + ("ab") + "<( ( \"test\" ) [)]>\n") + (evil-test-buffer + "((\"t[e]st\"))\n" + (emacs-lisp-mode) + ("vhhab") + "(<[(]\"test\")>)\n" + ("ab") + "<[(](\"test\"))>\n") + (evil-test-buffer + "( ( \"t[e]st\" ) )\n" + (emacs-lisp-mode) + ("vhhab") + "( <[(] \"test\" )> )\n" + ("ab") + "<[(] ( \"test\" ) )>\n") + (evil-test-buffer + "(([\"]\"))\n" + ("dab") + "([)]\n")) + (ert-info ("Select inner paren on different lines") + (evil-test-buffer + "for (auto i : vector) { + if (cond) { + do_[s]omething(); + } +}" + ("vi}") + "for (auto i : vector) { + if (cond) { +< do_something();[\n]> }\n}" + ("i}") + "for (auto i : vector) { +< if (cond) { + do_something(); + }[\n]>}")) + (ert-info ("Enlarge to smallest complete surrounding") + (evil-test-buffer + "for (auto i : vector) { + if (comething(); + } +}" + ("i}") + "for (auto i : vector) { +< if (cond) { + do_something(); + }[\n]>}")) + (ert-info ("yank on blocks is turned linewise") + (evil-test-buffer + "{\n [f]oo();\n}\n" + ("yiBp") + "{\n foo();\n [f]oo();\n}\n")) + (ert-info ("exclusive like if ending at bol") + (evil-test-buffer + "(defun foo ()\n[ ] (insert \"bar\")\n )\n" + ("cibx" [escape]) + "([x]\n )\n")) + (ert-info ("Operator on empty parentheses") + (evil-test-buffer + "a([(]))b" + ("cibx" [escape]) + "a(([x]))b") + (evil-test-buffer + "a(([)])b" + ("cibx" [escape]) + "a(([x]))b"))) + +(ert-deftest evil-test-forces-linewise-text-objects () + "Test `evil-text-object-change-visual-type' option." + :tags '(evil text-object) + (let ((evil-text-object-change-visual-type t)) + (ert-info ("Change visual type") + (evil-test-buffer + " function(opts) { + this.var1 = something(); + [t]his.var2 = something_else(); + return something_nasty(); + } +" + ("Vi}") + " function(opts) { +< this.var1 = something(); + this.var2 = something_else(); + return something_nasty();[ +]> } +" + (should (eq (evil-visual-type) 'inclusive))))) + (let ((evil-text-object-change-visual-type nil)) + (ert-info ("Change visual type keeping linewise") + (evil-test-buffer + " function(opts) { + this.var1 = something(); + [t]his.var2 = something_else(); + return something_nasty(); + } +" + ("Vi}") + " function(opts) { +< this.var1 = something(); + this.var2 = something_else(); + return something_nasty();\n> } +" + (should (eq (evil-visual-type) 'line))))) + (let ((evil-text-object-change-visual-type nil)) + (ert-info ("Linewise outer block") + (evil-test-buffer + " function(opts) { + this.var1 = something(); + [t]his.var2 = something_else(); + return something_nasty(); + } +" + ("Va}") + "< function(opts) { + this.var1 = something(); + this.var2 = something_else(); + return something_nasty(); + } +>" + (should (eq (evil-visual-type) 'line))))) + (ert-info ("Forced motion type should change text object type") + (evil-test-buffer + "for (int i=0; i<10; i++) { + if ([c]ond) { + do_something(); + } +}" + ("dVi}") + "for (int i=0; i<10; i++) { +\[}]"))) + +(ert-deftest evil-test-tag-objects () + "Test `evil-inner-tag', etc." + :tags '(evil text-object) + (ert-info ("Handle nested tags") + (evil-test-buffer + :visual-start "{" + :visual-end "}" + "

f[o]o bar

" + ("vit") + "

{fo[o]} bar

")) + (ert-info ("Break out of tags") + (evil-test-buffer + :visual-start "{" + :visual-end "}" + "bbbb" + ("vit") + "{bbb[b]}") + (evil-test-buffer + :visual-start "{" + :visual-end "}" + "bbbb" + ("vat") + "{bbbb]}")) + (ert-info ("Handle quoted strings tags") + (evil-test-buffer + :visual-start "{" + :visual-end "}" + " + +
+\[ ] +

+UPDATE +

+

+test hello Creative Commons +

+
+ + +" + ("vit") + " + +
{\n \n

+UPDATE +

+

+test hello Creative Commons +

[\n]}
+ + +")) + (ert-info ("Handle js arrow fns") + (evil-test-buffer + :visual-start "«" + :visual-end "»" + "" + ("vit") + ""))) + +;;; Visual state + +(defun evil-test-visual-select (selection &optional mark point) + "Verify that TYPE is selected correctly" + (let ((type (evil-visual-type selection))) + (evil-visual-make-selection mark point type) + (ert-info ("Activate region unless SELECTION is `block'") + (cond + ((eq selection 'block) + (should (mark t)) + (should-not (region-active-p)) + (should-not transient-mark-mode)) + (t + (should (mark)) + (should (region-active-p))))) + (ert-info ("Refresh Visual markers") + (should (= (evil-range-beginning (evil-expand (point) (mark) type)) + evil-visual-beginning)) + (should (= (evil-range-end (evil-expand (point) (mark) type)) + evil-visual-end)) + (should (eq (evil-visual-type) type)) + (should (eq evil-visual-direction + (if (< (point) (mark)) -1 1)))))) + +(ert-deftest evil-test-visual-refresh () + "Test `evil-visual-refresh'" + :tags '(evil visual) + (evil-test-buffer + ";; [T]his buffer is for notes." + (evil-visual-refresh nil nil 'inclusive) + (should (= evil-visual-beginning 4)) + (should (= evil-visual-end 5))) + (evil-test-buffer + ";; [T]his buffer is for notes." + (let ((evil-visual-region-expanded t)) + (evil-visual-refresh nil nil 'inclusive) + (should (= evil-visual-beginning 4)) + (should (= evil-visual-end 4))))) + +(ert-deftest evil-test-visual-exchange () + "Test `exchange-point-and-mark' in Visual character selection" + :tags '(evil visual) + (evil-test-buffer + ";; <[T]his> buffer is for notes you don't want to save, +;; and for Lisp evaluation." + ("o") + (should (region-active-p)) + ";; buffer is for notes you don't want to save, +;; and for Lisp evaluation.")) + +(ert-deftest evil-test-visual-char () + "Test Visual character selection" + :tags '(evil visual) + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save, +;; and for Lisp evaluation." + (evil-test-visual-select 'char) + ";; <[T]>his buffer is for notes you don't want to save, +;; and for Lisp evaluation." + ("e") + ";; buffer is for notes you don't want to save, +;; and for Lisp evaluation." + ("o") + ";; <[T]his> buffer is for notes you don't want to save, +;; and for Lisp evaluation." + ("d") + ";; [ ]buffer is for notes you don't want to save, +;; and for Lisp evaluation." + ("vV") + "<;; [ ]buffer is for notes you don't want to save,\n>\ +;; and for Lisp evaluation.") + (ert-info ("Test `evil-want-visual-char-semi-exclusive") + (let ((evil-want-visual-char-semi-exclusive t)) + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save, +;; and for Lisp evaluation. +;; And a third line." + ("v") + "<[;]>; This buffer is for notes you don't want to save, +;; and for Lisp evaluation. +;; And a third line." + ("$") + "<;; This buffer is for notes you don't want to save,>[ +];; and for Lisp evaluation. +;; And a third line." + ("^jj") + "<;; This buffer is for notes you don't want to save, +;; and for Lisp evaluation.\n>[;]; And a third line.")))) + +(ert-deftest evil-test-visual-line () + "Test Visual line selection" + :tags '(evil visual) + (evil-test-buffer + ";; [T]his buffer is for notes you don't want to save, +;; and for Lisp evaluation." + (evil-test-visual-select 'line) + "<;; [T]his buffer is for notes you don't want to save,\n>\ +;; and for Lisp evaluation." + ("e") + "<;; Thi[s] buffer is for notes you don't want to save,\n>\ +;; and for Lisp evaluation." + ("o") + "<;; [T]his buffer is for notes you don't want to save,\n>\ +;; and for Lisp evaluation." + ("d") + ";; [a]nd for Lisp evaluation.")) + +(ert-deftest evil-test-visual-block () + "Test Visual block selection" + :tags '(evil visual) + (evil-test-buffer + "[;]; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + (evil-test-visual-select 'block) + "<[;]>; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; then enter the text in that file's own buffer." + ("jjll") + "<;; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;;[ ]>then enter the text in that file's own buffer." + ("O") + ";; [;]; then enter the text in that file's own buffer." + ("o") + ";;[ ];; then enter the text in that file's own buffer." + ("O") + "<[;]; This buffer is for notes you don't want to save. +;; If you want to create a file, visit that file with C-x C-f, +;; >then enter the text in that file's own buffer." + ("d") + "This buffer is for notes you don't want to save. +If you want to create a file, visit that file with C-x C-f, +then enter the text in that file's own buffer.") + (ert-info ("Visual block can select over lines of different length") + (evil-test-buffer + "Short [l]ine +A much longer line +A medium line +Tiny ln" + ("\C-v$jd") + "Short[ ] +A much +A medium line +Tiny ln" + ("jj\C-v" [end] "jd") + "Short +A much +A me[d] +Tiny "))) + +(ert-deftest evil-test-visual-restore () + "Test restoring a previous selection" + :tags '(evil visual) + (ert-info ("Start a characterwise selection \ +if no previous selection") + (evil-test-buffer + ";; [T]his buffer is for notes." + ("gv") + ";; <[T]>his buffer is for notes.")) + (ert-info ("Restore characterwise selection") + (evil-test-buffer + ";; <[T]his> buffer is for notes." + ([escape] "gv") + ";; <[T]his> buffer is for notes.")) + (ert-info ("Restore linewise selection") + (evil-test-buffer + :visual line + "<;; [T]his buffer is for notes.>" + ([escape] "gv") + "<;; [T]his buffer is for notes.>")) + (ert-info ("Restore blockwise selection") + (evil-test-buffer + :visual block + "<;; This buffer is for notes, +;;[ ]>and for Lisp evaluation." + ([escape] "gv") + "<;; This buffer is for notes, +;;[ ]>and for Lisp evaluation.") + (ert-info ("After paste shifts initially selected text") + (evil-test-buffer + :visual block + "<1\n2\n[3]>" + ("yP") + "[1]1\n22\n33" + ("gvr*") + "[*]1\n*2\n*3"))) + (ert-info ("Restore linewise visually-pasted selection") + (evil-test-buffer + "[a]lpha bravo\ncharlie delta +echo foxtrot\ngolf hotel" + ("2yy" "++" "Vp" "gv") + "alpha bravo\ncharlie delta +golf hotel"))) + +;;; Replace state + +(ert-deftest evil-test-replacement () + "Test replacing consecutive characters" + :tags '(evil replace) + (ert-info ("Replace and restore consecutive characters") + (evil-test-buffer + ";; [T]his buffer is for notes" + ("Rfoo") + ";; foo[s] buffer is for notes" + ([backspace backspace backspace]) + ";; [T]his buffer is for notes")) + (ert-info ("Replace and restore consecutive characters beyond eol") + (evil-test-buffer + ";; [T]his buffer is for notes" + ("wwwwRxxxxxxx") + ";; This buffer is for xxxxxxx[]" + ([backspace backspace backspace backspace backspace backspace backspace]) + ";; This buffer is for [n]otes")) + (ert-info ("Replace from line below and restore") + (define-key evil-replace-state-map (kbd "C-e") 'evil-copy-from-below) + (evil-test-buffer + ";; [f]oo bar\n;; qux quux" + ("R\C-e\C-e\C-e") + ";; qux[ ]bar\n;; qux quux" + ([backspace backspace backspace]) + ";; [f]oo bar\n;; qux quux") + (define-key evil-replace-state-map (kbd "C-e") nil)) + (ert-info ("Replace from line above and restore") + (define-key evil-replace-state-map (kbd "C-y") 'evil-copy-from-above) + (evil-test-buffer + ";; foo bar\n;; [q]ux quux" + ("R\C-y\C-y\C-y") + ";; foo bar\n;; foo[ ]quux" + ([backspace backspace backspace]) + ";; foo bar\n;; [q]ux quux") + (define-key evil-replace-state-map (kbd "C-y") nil))) + +;;; Ex + +(ert-deftest evil-test-ex-parse () + "Test `evil-ex-parse'" + :tags '(evil ex) + (should (equal (evil-ex-parse "5,2cmd arg") + '(evil-ex-call-command + (evil-ex-range + (evil-ex-line (string-to-number "5") nil) + (evil-ex-line (string-to-number "2") nil)) + "cmd" + "arg"))) + (should (equal (evil-ex-parse "5,2cmd !arg") + '(evil-ex-call-command + (evil-ex-range + (evil-ex-line (string-to-number "5") nil) + (evil-ex-line (string-to-number "2") nil)) + "cmd" + "!arg"))) + (should (equal (evil-ex-parse "5,2 arg") + '(evil-ex-call-command + (evil-ex-range + (evil-ex-line (string-to-number "5") nil) + (evil-ex-line (string-to-number "2") nil)) + "arg" + nil))) + (should (equal (evil-ex-parse "+1,+2t-1") + '(evil-ex-call-command + (evil-ex-range + (evil-ex-line + nil + (+ (evil-ex-signed-number + (intern "+") + (string-to-number "1")))) + (evil-ex-line + nil + (+ (evil-ex-signed-number + (intern "+") + (string-to-number "2"))))) + "t" + "-1")))) + +(ert-deftest evil-test-ex-parse-ranges () + "Test parsing of ranges" + :tags '(evil ex) + (should (equal (evil-ex-parse "%" nil 'range) + '(evil-ex-full-range))) + (should (equal (evil-ex-parse "*" nil 'range) + '(evil-ex-last-visual-range))) + (should (equal (evil-ex-parse "5,27" nil 'range) + '(evil-ex-range + (evil-ex-line (string-to-number "5") nil) + (evil-ex-line (string-to-number "27") nil)))) + (should (equal (evil-ex-parse "5,$" nil 'range) + '(evil-ex-range + (evil-ex-line (string-to-number "5") nil) + (evil-ex-line (evil-ex-last-line) nil)))) + (should (equal (evil-ex-parse "5,'x" nil 'range) + '(evil-ex-range + (evil-ex-line (string-to-number "5") nil) + (evil-ex-line (evil-ex-marker "x") nil)))) + (should (equal (evil-ex-parse "`x,`y" nil 'range) + '(evil-ex-char-marker-range "x" "y"))) + (should (equal (evil-ex-parse "`[,`]" nil 'range) + '(evil-ex-char-marker-range "[" "]"))) + (should (equal (evil-ex-parse "5,+" nil 'range) + '(evil-ex-range + (evil-ex-line (string-to-number "5") nil) + (evil-ex-line + nil (+ (evil-ex-signed-number (intern "+") nil)))))) + (should (equal (evil-ex-parse "5,-" nil 'range) + '(evil-ex-range + (evil-ex-line (string-to-number "5") nil) + (evil-ex-line + nil (+ (evil-ex-signed-number (intern "-") nil)))))) + (should (equal (evil-ex-parse "5,4+2-7-3+10-" nil 'range) + '(evil-ex-range + (evil-ex-line (string-to-number "5") nil) + (evil-ex-line + (string-to-number "4") + (+ (evil-ex-signed-number + (intern "+") (string-to-number "2")) + (evil-ex-signed-number + (intern "-") (string-to-number "7")) + (evil-ex-signed-number + (intern "-") (string-to-number "3")) + (evil-ex-signed-number + (intern "+") (string-to-number "10")) + (evil-ex-signed-number (intern "-") nil)))))) + (should (equal (evil-ex-parse ".-2,4+2-7-3+10-" nil 'range) + '(evil-ex-range + (evil-ex-line + (evil-ex-current-line) + (+ (evil-ex-signed-number + (intern "-") (string-to-number "2")))) + (evil-ex-line + (string-to-number "4") + (+ (evil-ex-signed-number + (intern "+") (string-to-number "2")) + (evil-ex-signed-number + (intern "-") (string-to-number "7")) + (evil-ex-signed-number + (intern "-") (string-to-number "3")) + (evil-ex-signed-number + (intern "+") (string-to-number "10")) + (evil-ex-signed-number + (intern "-") nil)))))) + (should (equal (evil-ex-parse "'a-2,$-10" nil 'range) + '(evil-ex-range + (evil-ex-line + (evil-ex-marker "a") + (+ (evil-ex-signed-number + (intern "-") (string-to-number "2")))) + (evil-ex-line + (evil-ex-last-line) + (+ (evil-ex-signed-number + (intern "-") (string-to-number "10"))))))) + (should (equal (evil-ex-parse "'[,']" nil 'range) + '(evil-ex-range + (evil-ex-line + (evil-ex-marker "[") + nil) + (evil-ex-line + (evil-ex-marker "]") + nil)))) + (should (equal (evil-ex-parse "'{,'}" nil 'range) + '(evil-ex-range + (evil-ex-line + (evil-ex-marker "{") + nil) + (evil-ex-line + (evil-ex-marker "}") + nil)))) + (should (equal (evil-ex-parse "'(,')" nil 'range) + '(evil-ex-range + (evil-ex-line + (evil-ex-marker "(") + nil) + (evil-ex-line + (evil-ex-marker ")") + nil)))) + (should (equal (evil-ex-parse ",']" nil 'range) + '(evil-ex-range + (evil-ex-current-line) + (evil-ex-line + (evil-ex-marker "]") + nil)))) + (should (equal (evil-ex-parse ";']" nil 'range) + '(evil-ex-range + (evil-ex-current-line) + (evil-ex-line + (evil-ex-marker "]") + nil)))) + (should (equal (evil-ex-parse ".+42" nil 'range) + '(evil-ex-range + (evil-ex-line + (evil-ex-current-line) + (+ (evil-ex-signed-number + (intern "+") (string-to-number "42")))) + nil)))) + +(ert-deftest evil-test-ex-parse-emacs-commands () + "Test parsing of Emacs commands" + :tags '(evil ex) + (should (equal (evil-ex-parse "ido-mode") + '(evil-ex-call-command nil "ido-mode" nil))) + (should (equal (evil-ex-parse "yas/reload-all") + '(evil-ex-call-command nil "yas/reload-all" nil))) + (should (equal (evil-ex-parse "mu4e") + '(evil-ex-call-command nil "mu4e" nil))) + (should (equal (evil-ex-parse "make-frame") + '(evil-ex-call-command nil "make-frame" nil)))) + +(ert-deftest evil-text-ex-search-offset () + "Test for addresses like /base//pattern/" + :tags '(evil ex) + (ert-info ("without base") + (evil-test-buffer + "[l]ine 1\naaa\nbbb\naaa\nccc\nddd" + (":/aaa/d") + "line 1\nbbb\naaa\nccc\nddd")) + (ert-info ("with base") + (evil-test-buffer + "[l]ine 1\naaa\nbbb\naaa\nccc\nddd" + (":/bbb//aaa/d") + "line 1\naaa\nbbb\nccc\nddd")) + (ert-info ("range without base") + (evil-test-buffer + "[l]ine 1\naaa\nbbb\naaa\nccc\nddd\nccc\neee\n" + (":/aaa/;/ccc/d") + "line 1\nddd\nccc\neee\n")) + (ert-info ("range with base") + (evil-test-buffer + "[l]ine 1\naaa\nbbb\naaa\nccc\nddd\nccc\neee\n" + (":/bbb//aaa/;/ddd//ccc/d") + "line 1\naaa\nbbb\neee\n"))) + +(ert-deftest evil-test-ex-goto-line () + "Test if :number moves point to a certain line" + :tags '(evil ex) + (ert-info ("Move to line") + (let ((evil-start-of-line t)) + (evil-test-buffer + :visual line + "1\n 2\n [ ]3\n 4\n 5\n" + (":4" [return]) + "1\n 2\n 3\n [4]\n 5\n" + (":2" [return]) + "1\n [2]\n 3\n 4\n 5\n")))) + +(ert-deftest evil-test-ex-repeat () + "Test :@: command." + :tags '(evil ex) + (evil-without-display + (ert-info ("Repeat in current line") + (evil-test-buffer + "[a]bcdef\nabcdef\nabcdef" + (":s/[be]/X/g" [return]) + "[a]XcdXf\nabcdef\nabcdef" + ("jj:@:" [return]) + "aXcdXf\nabcdef\n[a]XcdXf")) + (ert-info ("Repeat in specified line") + (evil-test-buffer + "[a]bcdef\nabcdef\nabcdef" + (":s/[be]/X/g" [return]) + "[a]XcdXf\nabcdef\nabcdef" + (":3@:" [return]) + "aXcdXf\nabcdef\n[a]XcdXf")) + (ert-info ("Double repeat, first without then with specified line") + (evil-test-buffer + "[a]bcdef\nabcdef\nabcdef" + (":s/[be]/X/" [return]) + "[a]Xcdef\nabcdef\nabcdef" + ("jj:@:" [return] ":1@:" [return]) + "[a]XcdXf\nabcdef\naXcdef")))) + +(ert-deftest evil-test-ex-repeat2 () + "Test @: command." + :tags '(evil ex) + (evil-without-display + (ert-info ("Repeat in current line") + (evil-test-buffer + "[a]bcdef\nabcdef\nabcdef" + (":s/[be]/X" [return]) + "[a]Xcdef\nabcdef\nabcdef" + ("jj@:") + "aXcdef\nabcdef\n[a]Xcdef")) + (ert-info ("Repeat with count in current line") + (evil-test-buffer + "[a]bcdef\nabcdef\nabcdef" + (":s/[be]/X" [return]) + "[a]Xcdef\nabcdef\nabcdef" + ("jj2@:") + "aXcdef\nabcdef\n[a]XcdXf")) + (ert-info ("Do not record dot repeat") + (evil-test-buffer + "" + ("OAAAAAA" [escape] "^") + "[A]AAAAA\n" + (":s/A/X" [return]) + "[X]AAAAA\n" + ("@:") + "[X]XAAAA\n" + (".") + "AAAAAA\nXXAAAA\n")))) + +(ert-deftest evil-test-ex-visual-char-range () + "Test visual character ranges in ex state." + :tags '(evil ex visual) + (evil-without-display + (ert-info ("No character range, inclusive") + (let ((evil-visual-char 'inclusive) + evil-ex-visual-char-range) + (evil-test-buffer + "li[n]e 1\nline 2\nline 3\nline 4\n" + ("vjll:d" [return]) + "line 3\nline 4\n"))) + (ert-info ("No character range, exclusive") + (let ((evil-visual-char 'inclusive) + evil-ex-visual-char-range) + (evil-test-buffer + "li[n]e 1\nline 2\nline 3\nline 4\n" + ("vjll:d" [return]) + "line 3\nline 4\n"))) + (ert-info ("Character range, inclusive") + (let ((evil-visual-char 'inclusive) + (evil-ex-visual-char-range t)) + (evil-test-buffer + "li[n]e 1\nline 2\nline 3\nline 4\n" + ("vjll:d" [return]) + "li2\nline 3\nline 4\n"))) + (ert-info ("Character range, exclusive") + (let ((evil-visual-char 'exclusive) + (evil-ex-visual-char-range t)) + (evil-test-buffer + "li[n]e 1\nline 2\nline 3\nline 4\n" + ("vjll:d" [return]) + "li 2\nline 3\nline 4\n"))))) + +(ert-deftest evil-test-ex-substitute-replacement () + "Test `evil-ex-substitute' with special replacements." + :tags '(evil ex search) + (ert-info ("Substitute upper first on first match in line") + (evil-test-buffer + "[x]xx foo bar foo bar foo bar" + (":s/\\(foo\\|bar\\)/\\u\\1" [return]) + "[x]xx Foo bar foo bar foo bar")) + (ert-info ("Substitute upper first on first match in line with confirm") + (evil-test-buffer + "[x]xx foo bar foo bar foo bar" + (":s/\\(foo\\|bar\\)/\\u\\1/c" [return] "y") + "[x]xx Foo bar foo bar foo bar")) + (ert-info ("Substitute upper first on whole line") + (evil-test-buffer + "[x]xx foo bar foo bar foo bar" + (":s/\\(foo\\|bar\\)/\\u\\1/g" [return]) + "[x]xx Foo Bar Foo Bar Foo Bar")) + (ert-info ("Substitute upper first on whole line") + (evil-test-buffer + "[x]xx foo bar foo bar foo bar" + (":s/\\(foo\\|bar\\)/\\u\\1/gc" [return] "yynyyn") + "[x]xx Foo Bar foo Bar Foo bar")) + (ert-info ("Substitute upper/lower on first match in line") + (evil-test-buffer + "[x]xx foo BAR foo BAR foo BAR" + (":s/\\(f[[:alpha:]]*\\>\\)\\s-*\\(b[[:alpha:]]*\\>\\)/\\L\\2_\\e\\U\\1" [return]) + "[x]xx bar_FOO foo BAR foo BAR")) + (ert-info ("Substitute upper/lower on first match in line with confirm") + (evil-test-buffer + "[x]xx foo BAR foo BAR foo BAR" + (":s/\\(f[[:alpha:]]*\\>\\)\\s-*\\(b[[:alpha:]]*\\>\\)/\\L\\2_\\e\\U\\1/c" [return] "y") + "[x]xx bar_FOO foo BAR foo BAR")) + (ert-info ("Substitute upper/lower on whole line") + (evil-test-buffer + "[x]xx foo BAR foo BAR foo BAR" + (":s/\\(f[[:alpha:]]*\\>\\)\\s-*\\(b[[:alpha:]]*\\>\\)/\\L\\2_\\e\\U\\1/g" [return]) + "[x]xx bar_FOO bar_FOO bar_FOO")) + (ert-info ("Substitute upper/lower on whole line") + (evil-test-buffer + "[x]xx foo BAR foo BAR foo BAR" + (":s/\\(f[[:alpha:]]*\\>\\)\\s-*\\(b[[:alpha:]]*\\>\\)/\\L\\2_\\e\\U\\1/gc" [return] "yny") + "[x]xx bar_FOO foo BAR bar_FOO")) + (ert-info ("Substitute with escaped characters in replacement") + (evil-test-buffer + "[a]bcXdefXghiXjkl\n" + (":s/X/\\|\\/\\|/g" [return]) + "[a]bc|/|def|/|ghi|/|jkl\n")) + (ert-info ("Substitute with register") + (evil-test-buffer + "[a]bc\niiiXiiiXiiiXiii\n" + ("\"ayiwj:s/X/\\=@a/g" [return]) + "abc\n[i]iiabciiiabciiiabciii\n")) + (ert-info ("Substitute newlines") + (evil-test-buffer + "[a]bc\ndef\nghi\n" + (":%s/\n/z/" [return]) + "[a]bczdefzghiz")) + (ert-info ("Substitute newlines with g flag") + (evil-test-buffer + "[a]bc\ndef\nghi\n" + (":%s/\n/z/g" [return]) + "[a]bczdefzghiz")) + (ert-info ("Substitute newlines without newline in regexp") + (evil-test-buffer + "[A]BC\nDEF\nGHI\n" + (":%s/[^]]*/z/" [return]) + "Z")) + (ert-info ("Substitute n flag does not replace") + (evil-test-buffer + "[a]bc\naef\nahi\n" + (":%s/a//n" [return]) + "[a]bc\naef\nahi\n")) + (ert-info ("Substitute n flag does not replace with g flag") + (evil-test-buffer + "[a]bc\naef\nahi\n" + (":%s/a//gn" [return]) + "[a]bc\naef\nahi\n")) + (ert-info ("Substitute $ does not loop infinitely") + (evil-test-buffer + "[a]bc\ndef\nghi" + (":%s/$/ END/g" [return]) + "abc END\ndef END\n[g]hi END")) + (ert-info ("Substitute the zero-length beginning of line character") + (evil-test-buffer + "[a]bc\ndef\nghi" + (":s/^/ #/" [return]) + " [#]abc\ndef\nghi")) + (ert-info ("Substitute the zero-length beginning of line character with g flag") + (evil-test-buffer + "[a]bc\ndef\nghi" + (":s/^/ #/g" [return]) + " [#]abc\ndef\nghi")) + (ert-info ("Use Substitute to delete individual characters") + (evil-test-buffer + "[x]xyxxz" + (":%s/x//g" [return]) + "[y]z")) + (ert-info ("Substitute doesn't match final empty line") + (evil-test-buffer + "abc\n[d]ef\n\nghi" + (":s/$/4") + "abc\n[d]ef4\n\nghi") + (evil-test-buffer + "abc\n[d]ef\n\nghi" + (":s/f\\w*/4") + "abc\n[d]e4\n\nghi"))) + +(ert-deftest evil-test-ex-repeat-substitute-replacement () + "Test `evil-ex-substitute' with repeating of previous substitutions." + :tags '(evil ex search) + (ert-info ("Repeat previous pattern") + (evil-select-search-module 'evil-search-module 'evil-search) + (evil-test-buffer + "[x]xx foo bar foo bar foo bar" + (":s/foo/AAA" [return]) + "[x]xx AAA bar foo bar foo bar" + (":s//BBB" [return]) + "[x]xx AAA bar BBB bar foo bar" + ("/bar" [return] ":s//CCC" [return]) + "[x]xx AAA CCC BBB bar foo bar" + (":s/ar/XX" [return]) + "[x]xx AAA CCC BBB bXX foo bar" + (":s//YY" [return]) + "[x]xx AAA CCC BBB bXX foo bYY")) + (ert-info ("Repeat previous replacement") + (evil-test-buffer + "[x]xx foo bar foo bar foo bar" + (":s/foo/AAA" [return]) + "[x]xx AAA bar foo bar foo bar" + (":s/bar/~" [return]) + "[x]xx AAA AAA foo bar foo bar")) + (ert-info ("Repeat with previous flags") + (evil-test-buffer + "[x]xx foo bar foo bar foo bar" + (":s/foo/AAA/g" [return]) + "[x]xx AAA bar AAA bar AAA bar" + (":s/bar/BBB/&" [return]) + "[x]xx AAA BBB AAA BBB AAA BBB")) + (ert-info ("Repeat previous substitute without flags") + (evil-select-search-module 'evil-search-module 'evil-search) + (evil-test-buffer + "[x]xx foo bar foo bar foo bar\nxxx foo bar foo bar foo bar" + (":s/foo/AAA/g" [return]) + "[x]xx AAA bar AAA bar AAA bar\nxxx foo bar foo bar foo bar" + ("j:s" [return]) + "xxx AAA bar AAA bar AAA bar\n[x]xx AAA bar foo bar foo bar" + ("/bar" [return] ":s" [return]) + "xxx AAA bar AAA bar AAA bar\n[x]xx AAA bar AAA bar foo bar") + (evil-test-buffer + "[x]xx foo bar foo bar foo bar\nxxx foo bar foo bar foo bar" + (":s/foo/AAA/g" [return]) + "[x]xx AAA bar AAA bar AAA bar\nxxx foo bar foo bar foo bar" + ("j&") + "xxx AAA bar AAA bar AAA bar\n[x]xx AAA bar foo bar foo bar") + (evil-test-buffer + "[x]xx foo bar foo bar foo bar\nxxx foo bar foo bar foo bar" + (":s/foo/AAA/g" [return]) + "[x]xx AAA bar AAA bar AAA bar\nxxx foo bar foo bar foo bar" + ("j:&" [return]) + "xxx AAA bar AAA bar AAA bar\n[x]xx AAA bar foo bar foo bar")) + (ert-info ("Repeat previous substitute with the same flags") + (evil-test-buffer + "[x]xx foo bar foo bar foo bar\nxxx foo bar foo bar foo bar" + (":s/foo/AAA/g" [return]) + "[x]xx AAA bar AAA bar AAA bar\nxxx foo bar foo bar foo bar" + ("j:s//~/&" [return]) + "xxx AAA bar AAA bar AAA bar\n[x]xx AAA bar AAA bar AAA bar") + (evil-test-buffer + "[x]xx foo bar foo bar foo bar\nxxx foo bar foo bar foo bar" + (":s/foo/AAA/g" [return]) + "[x]xx AAA bar AAA bar AAA bar\nxxx foo bar foo bar foo bar" + ("j:&&" [return]) + "xxx AAA bar AAA bar AAA bar\n[x]xx AAA bar AAA bar AAA bar")) + (ert-info ("Repeat previous substitute with new flags") + (evil-test-buffer + "[x]xx foo bar foo bar foo bar\nxxx foo bar foo bar foo bar" + (":s/foo/AAA" [return]) + "[x]xx AAA bar foo bar foo bar\nxxx foo bar foo bar foo bar" + ("j:s g" [return]) + "xxx AAA bar foo bar foo bar\n[x]xx AAA bar AAA bar AAA bar") + (evil-test-buffer + "[x]xx foo bar foo bar foo bar\nxxx foo bar foo bar foo bar" + (":s/foo/AAA" [return]) + "[x]xx AAA bar foo bar foo bar\nxxx foo bar foo bar foo bar" + ("j:& g" [return]) + "xxx AAA bar foo bar foo bar\n[x]xx AAA bar AAA bar AAA bar")) + (ert-info ("Repeat with previous search pattern") + (evil-select-search-module 'evil-search-module 'evil-search) + (evil-test-buffer + "[x]xx foo bar foo bar foo bar\nxxx foo bar foo bar foo bar" + (":s/foo/AAA" [return]) + "[x]xx AAA bar foo bar foo bar\nxxx foo bar foo bar foo bar" + ("/bar" [return]) + "xxx AAA [b]ar foo bar foo bar\nxxx foo bar foo bar foo bar" + (":2s rg" [return]) + "xxx AAA bar foo bar foo bar\n[x]xx foo AAA foo AAA foo AAA") + (evil-test-buffer + "[x]xx foo bar foo bar foo bar\nxxx foo bar foo bar foo bar" + (":s/foo/AAA" [return]) + "[x]xx AAA bar foo bar foo bar\nxxx foo bar foo bar foo bar" + ("/bar" [return]) + "xxx AAA [b]ar foo bar foo bar\nxxx foo bar foo bar foo bar" + (":2~ g" [return]) + "xxx AAA bar foo bar foo bar\n[x]xx foo AAA foo AAA foo AAA")) + (ert-info ("Repeat previous substitute globally") + (evil-test-buffer + "[x]xx foo bar foo bar foo bar\nxxx foo bar foo bar foo bar" + (":s/foo/AAA/g" [return]) + "[x]xx AAA bar AAA bar AAA bar\nxxx foo bar foo bar foo bar" + ("g&") + "xxx AAA bar AAA bar AAA bar\n[x]xx AAA bar AAA bar AAA bar"))) + +(ert-deftest evil-test-ex-regex-without-case () + "Test `evil-ex-regex-without-case'" + :tags '(evil ex search) + (should (equal (evil-ex-regex-without-case "cdeCDE") + "cdeCDE")) + (should (equal (evil-ex-regex-without-case "\\ccde\\CCDE") + "cdeCDE")) + (should (equal (evil-ex-regex-without-case "\\\\ccde\\\\CCDE") + "\\\\ccde\\\\CCDE")) + (should (equal (evil-ex-regex-without-case "\\\\\\ccde\\\\\\CCDE") + "\\\\cde\\\\CDE"))) + +(ert-deftest evil-test-ex-regex-case () + "Test `evil-ex-regex-case'" + :tags '(evil ex search) + (should (equal (evil-ex-regex-case "cde" 'smart) 'insensitive)) + (should (equal (evil-ex-regex-case "cDe" 'smart) 'sensitive)) + (should (equal (evil-ex-regex-case "cde" 'sensitive) 'sensitive)) + (should (equal (evil-ex-regex-case "cde" 'insensitive) 'insensitive)) + (should (equal (evil-ex-regex-case "\\ccde" 'smart) 'insensitive)) + (should (equal (evil-ex-regex-case "\\cCde" 'smart) 'insensitive)) + (should (equal (evil-ex-regex-case "\\Ccde" 'smart) 'sensitive)) + (should (equal (evil-ex-regex-case "\\CCde" 'smart) 'sensitive)) + (should (equal (evil-ex-regex-case "\\ccd\\Ce" 'smart) 'insensitive)) + (should (equal (evil-ex-regex-case "\\cCd\\Ce" 'smart) 'insensitive)) + (should (equal (evil-ex-regex-case "\\Ccd\\ce" 'smart) 'sensitive)) + (should (equal (evil-ex-regex-case "\\CCd\\ce" 'smart) 'sensitive))) + +(ert-deftest evil-test-ex-search () + "Test evil internal search." + :tags '(evil ex search) + (evil-without-display + (evil-select-search-module 'evil-search-module 'evil-search) + (ert-info ("Test smart case insensitive") + (evil-test-buffer + "[s]tart you YOU You you YOU You" + ("/you" [return]) + "start [y]ou YOU You you YOU You" + ("n") + "start you [Y]OU You you YOU You" + ("n") + "start you YOU [Y]ou you YOU You" + ("n") + "start you YOU You [y]ou YOU You")) + (ert-info ("Test smart case sensitive") + (evil-test-buffer + "[s]tart you YOU You you YOU You" + ("/You" [return]) + "start you YOU [Y]ou you YOU You" + ("n") + "start you YOU You you YOU [Y]ou")) + (ert-info ("Test insensitive") + (evil-test-buffer + "[s]tart you YOU You you YOU You" + ("/\\cyou" [return]) + "start [y]ou YOU You you YOU You" + ("n") + "start you [Y]OU You you YOU You" + ("n") + "start you YOU [Y]ou you YOU You" + ("n") + "start you YOU You [y]ou YOU You")) + (ert-info ("Test sensitive") + (evil-test-buffer + "[s]tart you YOU You you YOU You" + ("/\\Cyou" [return]) + "start [y]ou YOU You you YOU You" + ("n") + "start you YOU You [y]ou YOU You")) + (ert-info ("Test failing search does not move point") + (evil-test-buffer + "foo [f]oo foo\nbar bar2 bar\nbaz baz baz\n" + (error search-failed "/foofoo" [return]) + "foo [f]oo foo\nbar bar2 bar\nbaz baz baz\n" + ("/bar2" [return]) + "foo foo foo\nbar [b]ar2 bar\nbaz baz baz\n" + ("dw") + "foo foo foo\nbar [b]ar\nbaz baz baz\n" + (error search-failed "n") + "foo foo foo\nbar [b]ar\nbaz baz baz\n" + (error search-failed "N") + "foo foo foo\nbar [b]ar\nbaz baz baz\n")) + (ert-info ("Test search for newline") + (evil-test-buffer + "[s]tart\nline 2\nline 3\n\n" + ("/\\n" [return]) + "star[t]\nline 2\nline 3\n\n" + ("n") + "start\nline [2]\nline 3\n\n" + ("n") + "start\nline 2\nline [3]\n\n" + ("n") + "start\nline 2\nline 3\n[]\n")) + (ert-info ("Can paste from register in ex-search") + (evil-test-buffer + "Alpha [b]ravo charlie alpha bravo delta bravo delta" + ("\"bye" "w") + "Alpha bravo [c]harlie alpha bravo delta bravo delta" + ("/\C-rb" [return]) + "Alpha bravo charlie alpha [b]ravo delta bravo delta" + ("w/\C-r\C-o" [return]) + "Alpha bravo charlie alpha bravo delta bravo [d]elta")))) + +(ert-deftest evil-test-ex-search-offset () + "Test search offsets." + :tags '(evil ex search) + (evil-without-display + (evil-select-search-module 'evil-search-module 'evil-search) + (ert-info ("Test line offsets") + (evil-test-buffer + "[f]oo foo\nbar bar\nbaz baz\nAnother line\nAnd yet another line" + ("/bar/2") + "foo foo\nbar bar\nbaz baz\n[A]nother line\nAnd yet another line" + ("?bar?-") + "[f]oo foo\nbar bar\nbaz baz\nAnother line\nAnd yet another line" + ("/r bar/") + "foo foo\nba[r] bar\nbaz baz\nAnother line\nAnd yet another line")) + (ert-info ("Test end offsets") + (evil-test-buffer + "[f]oo foo\nbar bar\nbaz baz\nAnother line\nAnd yet another line" + ("/bar/e") + "foo foo\nba[r] bar\nbaz baz\nAnother line\nAnd yet another line" + ("/baz/e+2") + "foo foo\nbar bar\nbaz [b]az\nAnother line\nAnd yet another line" + ("/line/e-1") + "foo foo\nbar bar\nbaz baz\nAnother li[n]e\nAnd yet another line")) + (ert-info ("Test begin offsets") + (evil-test-buffer + "[f]oo foo\nbar bar\nbaz baz\nAnother line\nAnd yet another line" + ("/bar/b") + "foo foo\n[b]ar bar\nbaz baz\nAnother line\nAnd yet another line" + ("/baz/b+2") + "foo foo\nbar bar\nba[z] baz\nAnother line\nAnd yet another line" + ("/line/b-") + "foo foo\nbar bar\nbaz baz\nAnother[ ]line\nAnd yet another line")) + (ert-info ("Test search-next with offset") + (evil-test-buffer + "[f]oo foo\nbar bar\nbaz baz\nAnother line\nAnd yet another line" + ("/ ba/+1" [return]) + "foo foo\nbar bar\n[b]az baz\nAnother line\nAnd yet another line" + ("n") + "foo foo\nbar bar\nbaz baz\n[A]nother line\nAnd yet another line")) + (ert-info ("Test search next after /$") + (evil-test-buffer + "[l]ine 1\nline 2\n\n\line 4\n" + ("/$" [return]) + "line [1]\nline 2\n\n\line 4\n" + ("n") + "line 1\nline [2]\n\n\line 4\n" + ("n") + "line 1\nline 2\n[\n]\line 4\n" + ("n") + "line 1\nline 2\n\n\line [4]\n")))) + +(ert-deftest evil-test-ex-search-pattern-offset () + "Test pattern offsets." + :tags '(evil ex search) + (evil-without-display + (evil-select-search-module 'evil-search-module 'evil-search) + (ert-info ("Test simple pattern offsets") + (evil-test-buffer + "[f]oo foo\nbar bar\nfoo foo\nbaz baz\nAnother line\nAnd yet another line" + ("/bar/;/foo" [return]) + "foo foo\nbar bar\n[f]oo foo\nbaz baz\nAnother line\nAnd yet another line")) + (ert-info ("Test simple pattern offsets in backward direction") + (evil-test-buffer + "[f]oo foo\nbar bar\nfoo foo\nbaz baz\nAnother line\nAnd yet another line" + ("/bar/;?foo" [return]) + "foo [f]oo\nbar bar\nfoo foo\nbaz baz\nAnother line\nAnd yet another line")) + (ert-info ("Ensure second pattern is used for search repeat") + (evil-test-buffer + "[f]oo foo\nbar bar\nfoo foo\nbaz baz\nAnother line\nAnd yet another line" + ("/bar/;?foo" [return] "n") + "foo foo\nbar bar\n[f]oo foo\nbaz baz\nAnother line\nAnd yet another line")))) + +(ert-deftest evil-test-ex-search-repeat () + "Test repeat of search." + :tags '(evil ex search) + (evil-without-display + (evil-select-search-module 'evil-search-module 'evil-search) + (ert-info ("Test repeat of simple pattern") + (evil-test-buffer + "[f]oo foo\nbar bar\nbaz baz\nAnother line\nAnd yet another line" + ("/bar" [return] "/" [return]) + "foo foo\nbar [b]ar\nbaz baz\nAnother line\nAnd yet another line")) + (ert-info ("Test repeat of simple pattern with new offset") + (evil-test-buffer + "[f]oo foo\nbar bar\nbaz baz\nAnother line\nAnd yet another line" + ("/bar" [return] "//e" [return]) + "foo foo\nbar ba[r]\nbaz baz\nAnother line\nAnd yet another line")) + (ert-info ("Test repeat of pattern with offset") + (evil-test-buffer + "[f]oo foo\nbar bar\nbaz baz\nAnother line\nAnd yet another line" + ("/bar/e" [return] "/" [return]) + "foo foo\nbar ba[r]\nbaz baz\nAnother line\nAnd yet another line")) + (ert-info ("Test repeat of pattern with offset without offset") + (evil-test-buffer + "[f]oo foo\nbar bar\nbaz baz\nAnother line\nAnd yet another line" + ("/bar/e" [return] "//" [return]) + "foo foo\nbar [b]ar\nbaz baz\nAnother line\nAnd yet another line")) + (ert-info ("Test repeat of pattern with offset with new offset") + (evil-test-buffer + "[f]oo foo\nbar bar\nbaz baz\nAnother line\nAnd yet another line" + ("/bar/e" [return] "//b+1" [return]) + "foo foo\nbar b[a]r\nbaz baz\nAnother line\nAnd yet another line")) + (ert-info ("Test repeat of pattern in the same search") + (evil-test-buffer + "[a]lpha bravo charlie delta charlie alpha bravo alpha" + ("/charlie/;/") + "alpha bravo charlie delta [c]harlie alpha bravo alpha" + ("/alpha/;//") + "alpha bravo charlie delta charlie alpha bravo [a]lpha" + ("?charlie?;?") + "alpha bravo [c]harlie delta charlie alpha bravo alpha") + (ert-info ("including when switching direction") + (evil-test-buffer + "[a]lpha bravo charlie delta charlie alpha bravo alpha" + ("/bravo/;?") + "alpha bravo charlie delta charlie alpha [b]ravo alpha" + ("?alpha?;//") + "alpha bravo charlie delta charlie alpha bravo [a]lpha"))))) + +(ert-deftest evil-test-ex-search-word () + "Test search for word under point." + :tags '(evil ex search) + (evil-without-display + (evil-select-search-module 'evil-search-module 'evil-search) + (setq evil-ex-search-history nil) + (evil-test-buffer + "so[m]e text with a strange word +and here some other stuff +maybe we need one line more with some text\n" + (setq evil-symbol-word-search nil) + ("*") + "some text with a strange word +and here [s]ome other stuff +maybe we need one line more with some text\n" + ("n") + "some text with a strange word +and here some other stuff +maybe we need one line more with [s]ome text\n" + (ert-info ("Search history") + (should (equal evil-ex-search-history '("\\")))) + ("*") + "[s]ome text with a strange word +and here some other stuff +maybe we need one line more with some text\n" + (ert-info ("Search history with double pattern") + (should (equal evil-ex-search-history '("\\"))))) + (ert-info ("Test unbounded search") + (evil-select-search-module 'evil-search-module 'evil-search) + (setq evil-ex-search-history nil) + (evil-test-buffer + "[s]ymbol\n(defun my-symbolfunc ())\n(defvar my-symbolvar)\nanother symbol\n" + ("*") + (setq evil-symbol-word-search nil) + "symbol\n(defun my-symbolfunc ())\n(defvar my-symbolvar)\nanother [s]ymbol\n" + ("ggg*") + "symbol\n(defun my-[s]ymbolfunc ())\n(defvar my-symbolvar)\nanother symbol\n" + (should (equal evil-ex-search-history '("symbol" "\\"))) + ("n") + "symbol\n(defun my-symbolfunc ())\n(defvar my-[s]ymbolvar)\nanother symbol\n")) + (ert-info ("Test symbol search") + (evil-select-search-module 'evil-search-module 'evil-search) + (evil-test-buffer + "(defun my-s[y]mbol-func ())\n(defvar my-symbol-var)\n(my-symbol-func)\n(setq my-symbol-func2 (my-symbol-func))\n" + (setq evil-symbol-word-search t) + ("*") + "(defun my-symbol-func ())\n(defvar my-symbol-var)\n([m]y-symbol-func)\n(setq my-symbol-func2 (my-symbol-func))\n" + ("n") + "(defun my-symbol-func ())\n(defvar my-symbol-var)\n(my-symbol-func)\n(setq my-symbol-func2 ([m]y-symbol-func))\n")) + (ert-info ("Test with non-nil `evil-ex-search-vim-style-regexp'") + (evil-select-search-module 'evil-search-module 'evil-search) + (let ((evil-ex-search-vim-style-regexp t) + (evil-magic 'very-magic)) + (evil-test-buffer + "[a]lpha bravo alpha charlie alpha" + ("*") + "alpha bravo [a]lpha charlie alpha" + ("/" [return]) + "alpha bravo alpha charlie [a]lpha"))))) + +(ert-deftest evil-test-ex-search-motion () + :tags '(evil ex search) + (evil-without-display + (evil-select-search-module 'evil-search-module 'evil-search) + (ert-info ("Ex forward search, as a motion, can be repeated") + (evil-test-buffer + "alpha [b]ravo charlie delta golf hotel charlie india" + ("c/charlie" [return] "replacement " [escape] "4w.") + "alpha replacement charlie delta golf replacement[ ]charlie india")))) + +(ert-deftest evil-test-ex-search-next+previous-match () + :tags '(evil ex search) + (evil-without-display + (evil-select-search-module 'evil-search-module 'evil-search) + (ert-info ("evil-next-match in normal state") + (evil-test-buffer + "[b]ravo charlie delta charlie alpha charlie bravo" + ("/charlie" [return] "e") + "bravo charli[e] delta charlie alpha charlie bravo" + ("gn") + "bravo delta charlie alpha charlie bravo" + ([escape] "b") + "bravo [c]harlie delta charlie alpha charlie bravo" + ("gn") + "bravo delta charlie alpha charlie bravo" + ([escape] "w") + "bravo charlie [d]elta charlie alpha charlie bravo" + ("gn") + "bravo charlie delta alpha charlie bravo" + ([escape] "^") + "[b]ravo charlie delta charlie alpha charlie bravo" + ("3gn") + "bravo charlie delta charlie alpha bravo")) + (ert-info ("evil-previous-match in normal state") + (evil-test-buffer + "[b]ravo charlie delta charlie alpha charlie bravo" + ("/charlie" [return] "e") + "bravo charli[e] delta charlie alpha charlie bravo" + ("$gN") + "bravo charlie delta charlie alpha <[c]harlie> bravo" + ([escape] "gN") + "bravo charlie delta charlie alpha <[c]harlie> bravo" + ([escape] "e" "2gN") + "bravo charlie delta <[c]harlie> alpha charlie bravo")) + (ert-info ("evil-next-match in visual state") + (evil-test-buffer + "[b]ravo charlie delta charlie alpha charlie bravo" + ("/charlie" [return] "e") + "bravo charli[e] delta charlie alpha charlie bravo" + ("gn") + "bravo delta charlie alpha charlie bravo" + ("gn") + "bravo alpha charlie bravo" + ("o") + "bravo <[c]harlie delta charlie> alpha charlie bravo" + ("gn") + "bravo charli<[e] delta charlie> alpha charlie bravo" + ([escape] "^v2gn") + " alpha charlie bravo")) + (ert-info ("evil-previous-match in visual state") + (evil-test-buffer + "bravo charlie delta charlie alpha charlie brav[o]" + ("?charlie" [return]) + "bravo charlie delta charlie alpha [c]harlie bravo" + ("gN") + "bravo charlie delta charlie alpha <[c]harlie> bravo" + ("gN") + "bravo charlie delta <[c]harlie alpha charlie> bravo" + ("o") + "bravo charlie delta bravo" + ("gN") + "bravo charlie delta harlie bravo" + ([escape] "$v2gN") + "bravo charlie delta <[c]harlie alpha charlie bravo>")) + (ert-info ("evil-match in operator state") + (evil-test-buffer + "[b]ravo charlie delta charlie alpha charlie bravo" + ("/charlie" [return]) + "bravo [c]harlie delta charlie alpha charlie bravo" + ("cgn" "foo" [escape]) + "bravo fo[o] delta charlie alpha charlie bravo" + (".") + "bravo foo delta fo[o] alpha charlie bravo" + ("$cgN" "bar" [escape]) + "bravo foo delta foo alpha ba[r] bravo")) + (ert-info ("Unfound evil ex next match doesn't move cursor") + (evil-test-buffer + "[a]lpha bravo" + (should-error (execute-kbd-macro "/zulu")) + "[a]lpha bravo" + (should-error (execute-kbd-macro "gn")) + "[a]lpha bravo")))) + +(ert-deftest evil-test-isearch-word () + "Test isearch for word under point." + :tags '(evil isearch) + (evil-without-display + (evil-select-search-module 'evil-search-module 'isearch) + (evil-test-buffer + "so[m]e text with a strange word +and here some other stuff +maybe we need one line more with some text\n" + (setq evil-symbol-word-search nil) + ("*") + "some text with a strange word +and here [s]ome other stuff +maybe we need one line more with some text\n" + ("n") + "some text with a strange word +and here some other stuff +maybe we need one line more with [s]ome text\n" + ("*") + "[s]ome text with a strange word +and here some other stuff +maybe we need one line more with some text\n") + (ert-info ("Test unbounded search") + (evil-select-search-module 'evil-search-module 'isearch) + (evil-test-buffer + "[s]ymbol\n(defun my-symbolfunc ())\n(defvar my-symbolvar)\nanother symbol\n" + (setq evil-symbol-word-search nil) + ("*") + "symbol\n(defun my-symbolfunc ())\n(defvar my-symbolvar)\nanother [s]ymbol\n" + ("ggg*") + "symbol\n(defun my-[s]ymbolfunc ())\n(defvar my-symbolvar)\nanother symbol\n" + ("n") + "symbol\n(defun my-symbolfunc ())\n(defvar my-[s]ymbolvar)\nanother symbol\n")) + (ert-info ("Test symbol search") + (evil-select-search-module 'evil-search-module 'isearch) + (evil-test-buffer + "(defun my-s[y]mbol-func ())\n(defvar my-symbol-var)\n(my-symbol-func)\n(setq my-symbol-func2 (my-symbol-func))\n" + (setq evil-symbol-word-search t) + ("*") + "(defun my-symbol-func ())\n(defvar my-symbol-var)\n([m]y-symbol-func)\n(setq my-symbol-func2 (my-symbol-func))\n" + ("n") + "(defun my-symbol-func ())\n(defvar my-symbol-var)\n(my-symbol-func)\n(setq my-symbol-func2 ([m]y-symbol-func))\n")))) + +(ert-deftest evil-test-read () + "Test of `evil-read'" + :tags '(evil ex) + (evil-without-display + (ert-info ("Test insertion of file with trailing newline") + (evil-with-temp-file name + "temp file 1\ntemp file 2\n" + (ert-info ("At first line") + (evil-test-buffer + "[l]ine 1\nline 2" + ((vconcat ":read " name [return])) + "line 1\n[t]emp file 1\ntemp file 2\nline 2")) + (ert-info ("At last line") + (evil-test-buffer + "line 1\n[l]ine 2" + ((vconcat ":read " name [return])) + "line 1\nline 2\n[t]emp file 1\ntemp file 2\n")) + (ert-info ("After specified line number") + (evil-test-buffer + "[l]ine 1\nline 2\nline 3\nline 4\line 5" + ((vconcat ":3read " name [return])) + "line 1\nline 2\nline 3\n[t]emp file 1\ntemp file 2\nline 4\line 5")) + (ert-info ("After specified line 0") + (evil-test-buffer + "line 1\nline [2]\nline 3\nline 4\line 5" + ((vconcat ":0read " name [return])) + "[t]emp file 1\ntemp file 2\nline 1\nline 2\nline 3\nline 4\line 5")))) + (ert-info ("Test insertion of file without trailing newline") + (evil-with-temp-file name + "temp file 1\ntemp file 2" + (evil-test-buffer + "[l]ine 1\nline 2" + ((vconcat ":read " name [return])) + "line 1\n[t]emp file 1\ntemp file 2\nline 2"))) + (ert-info ("Test insertion of shell command") + (ert-info ("with space") + (evil-test-buffer + "[l]line 1\nline 2" + (":read !echo cmd line 1" [return]) + "line 1\n[c]md line 1\nline 2")) + (ert-info ("without space") + (evil-test-buffer + "[l]line 1\nline 2" + (":read!echo cmd line 1" [return]) + "line 1\n[c]md line 1\nline 2"))) + (ert-info ("Test substitution of % in shell commands") + (evil-with-temp-file name + "3\n2\n1\n" + (evil-test-buffer + ((vconcat ":e " name [return])) + "[3]\n2\n1\n" + ((vconcat ":read !echo %" [return])) + ((vconcat ":w " [return])) + (file name (concat "3\n" + (buffer-file-name) "\n" + "2\n" + "1\n"))))) + (ert-info ("Ensure that point ends up at the last line of shell output, if any") + (evil-with-temp-file name + "3\n2\n1\n" + (evil-test-buffer + "[l]ine 1\nline 2" + ((vconcat ":read !cat " name [return])) + "line 1\n3\n2\n[1]\nline 2"))) + (ert-info ("Test insertion of shell command without trailing newline") + (ert-info ("with space") + (evil-test-buffer + "[l]line 1\nline 2" + (":read !echo -n cmd line 1" [return]) + "line 1\n[c]md line 1\nline 2")) + (ert-info ("without space") + (evil-test-buffer + "[l]line 1\nline 2" + (":read!echo -n cmd line 1" [return]) + "line 1\n[c]md line 1\nline 2"))))) + +(ert-deftest evil-test-shell-command () + "Test `evil-shell-command'." + (ert-info ("ex shell command") + (evil-test-buffer + "[l]ine 5\nline 4\nline 3\nline 2\nline 1\n" + (":2,3!sort" [return]) + "line 5\n[l]ine 3\nline 4\nline 2\nline 1\n")) + (ert-info ("shell command operator with count") + (evil-test-buffer + "line 5\n[l]ine 4\nline 3\nline 2\nline 1\n" + ("2!!sort" [return]) + "line 5\n[l]ine 3\nline 4\nline 2\nline 1\n")) + (ert-info ("shell command operator with motion") + (evil-test-buffer + "line 5\n[l]ine 4\nline 3\nline 2\nline 1\n" + ("!jsort" [return]) + "line 5\n[l]ine 3\nline 4\nline 2\nline 1\n")) + (ert-info ("shell command operator with backward motion") + (evil-test-buffer + "line 5\nline 4\n[l]ine 3\nline 2\nline 1\n" + ("!ksort" [return]) + "line 5\n[l]ine 3\nline 4\nline 2\nline 1\n")) + (ert-info ("shell command operator with visual selection") + (evil-test-buffer + "line 5\n[l]ine 4\nline 3\nline 2\nline 1\n" + ("vj!sort" [return]) + "line 5\n[l]ine 3\nline 4\nline 2\nline 1\n"))) + +(ert-deftest evil-test-global () + "Test `evil-ex-global'." + :tags '(evil ex global) + (ert-info ("global delete") + (evil-test-buffer + "[n]o 1\nno 2\nno 3\nyes 4\nno 5\nno 6\nno 7\n" + (":g/yes/d" [return]) + "no 1\nno 2\nno 3\n[n]o 5\nno 6\nno 7\n")) + (ert-info ("global substitute") + (evil-test-buffer + "[n]o 1\nno 2\nno 3\nyes 4\nno 5\nno 6\nno 7\n" + (":g/no/s/[3-6]/x" [return]) + "no 1\nno 2\nno x\nyes 4\nno x\nno x\n[n]o 7\n" + ("u") + "no 1\nno 2\nno [3]\nyes 4\nno 5\nno 6\nno 7\n")) + (ert-info ("global substitute with trailing slash") + (evil-test-buffer + "[n]o 1\nno 2\nno 3\nyes 4\nno 5\nno 6\nno 7\n" + (":g/no/s/[3-6]/x/" [return]) + "no 1\nno 2\nno x\nyes 4\nno x\nno x\n[n]o 7\n" + ("u") + "no 1\nno 2\nno [3]\nyes 4\nno 5\nno 6\nno 7\n")) + (evil-select-search-module 'evil-search-module 'evil-search) + (ert-info ("global use last match if none given, with evil-search") + (evil-test-buffer + "[n]o 1\nno 2\nno 3\nyes 4\nno 5\nno 6\nno 7\n" + ("/yes" [return]) + "no 1\nno 2\nno 3\nyes 4\nno 5\nno 6\nno 7\n" + (":g//d" [return]) + "no 1\nno 2\nno 3\n[n]o 5\nno 6\nno 7\n" + (":v//d" [return]) + "")) + (evil-select-search-module 'evil-search-module 'isearch) + (ert-info ("global use last match if none given, with isearch") + (evil-test-buffer + "[n]o 1\nno 2\nno 3\nisearch 4\nno 5\nno 6\nno 7\n" + ("/isearch" [return]) + "no 1\nno 2\nno 3\nisearch 4\nno 5\nno 6\nno 7\n" + (":g//d" [return]) + "no 1\nno 2\nno 3\n[n]o 5\nno 6\nno 7\n" + (":v//d" [return]) + "")) + (ert-info (":global should take into account evil-ex-search-case") + (evil-with-both-search-modules + (let ((evil-ex-search-case 'sensitive)) + (evil-test-buffer + "this\nThis\n" + (":g/this/d" [return]) + "This\n")) + (let ((evil-ex-search-case 'insensitive)) + (evil-test-buffer + "this\nThis\n" + (":g/this/d" [return]) + "")) + (let ((evil-ex-search-case 'smart)) + (evil-test-buffer + "this\nThis\n" + (":g/this/d" [return]) + "") + (evil-test-buffer + "this\nThis\n" + (":g/This/d" [return]) + "this\n")))) + (ert-info (":global should transform vim-style regexp when appropriate") + (let ((evil-ex-search-vim-style-regexp t)) + (evil-test-buffer + "a\n1\nb\n2\nc\n3\n" + (":g/\\d/>") + "a\n 1\nb\n 2\nc\n 3\n")))) + +(ert-deftest evil-test-normal () + "Test `evil-ex-normal'." + :tags '(evil ex) + (let (evil-want-fine-undo) + (evil-test-buffer + "[l]ine 1\nline 2\nline 3\nline 4\nline 5\n" + (":normal lxIABC" [escape] "AXYZ" [return]) + "ABClne 1XY[Z]\nline 2\nline 3\nline 4\nline 5\n" + (":3,4normal lxIABC" [escape] "AXYZ" [return]) + "ABClne 1XYZ\nline 2\nABClne 3XYZ\nABClne 4XY[Z]\nline 5\n" + ("u") + "ABClne 1XYZ\nline 2\nl[i]ne 3\nline 4\nline 5\n"))) + +(ert-deftest evil-test-copy () + :tags '(evil ex) + "Test `evil-copy'." + (ert-info ("Copy to last line") + (evil-test-buffer + "[l]ine1\nline2\nline3\nline4\nline5\n" + (":2,3copy$") + "line1\nline2\nline3\nline4\nline5\nline2\n[l]ine3\n")) + (ert-info ("Copy to last incomplete line") + (evil-test-buffer + "[l]ine1\nline2\nline3\nline4\nline5" + (":2,3copy$") + "line1\nline2\nline3\nline4\nline5\nline2\n[l]ine3\n")) + (ert-info ("Copy incomplete line to last incomplete line") + (evil-test-buffer + "[l]ine1\nline2\nline3\nline4\nline5" + (":4,5copy$") + "line1\nline2\nline3\nline4\nline5\nline4\n[l]ine5\n")) + (ert-info ("Copy to first line") + (evil-test-buffer + "[l]ine1\nline2\nline3\nline4\nline5\n" + (":2,3copy0") + "line2\n[l]ine3\nline1\nline2\nline3\nline4\nline5\n")) + (ert-info ("Copy to intermediate line") + (evil-test-buffer + "[l]ine1\nline2\nline3\nline4\nline5\n" + (":2,4copy2") + "line1\nline2\nline2\nline3\n[l]ine4\nline3\nline4\nline5\n")) + (ert-info ("Copy to current line") + (evil-test-buffer + "line1\nline2\nline3\nli[n]e4\nline5\n" + (":2,4copy.") + "line1\nline2\nline3\nline4\nline2\nline3\n[l]ine4\nline5\n"))) + +(ert-deftest evil-test-move () + :tags '(evil ex) + "Test `evil-move'." + (ert-info ("Move to last line") + (evil-test-buffer + "[l]ine1\nline2\nline3\nline4\nline5\n" + (":2,3move$") + "line1\nline4\nline5\nline2\n[l]ine3\n")) + (ert-info ("Move to last incomplete line") + (evil-test-buffer + "[l]ine1\nline2\nline3\nline4\nline5" + (":2,3move$") + "line1\nline4\nline5\nline2\n[l]ine3\n")) + (ert-info ("Move incomplete line to last incomplete line") + (evil-test-buffer + "[l]ine1\nline2\nline3\nline4\nline5" + (":4,5move$") + "line1\nline2\nline3\nline4\n[l]ine5\n")) + (ert-info ("Move to first line") + (evil-test-buffer + "[l]ine1\nline2\nline3\nline4\nline5\n" + (":2,3move0") + "line2\n[l]ine3\nline1\nline4\nline5\n")) + (ert-info ("Move to intermediate line") + (evil-test-buffer + "[l]ine1\nline2\nline3\nline4\nline5\n" + (":2,4move2") + "line1\nline2\nline3\n[l]ine4\nline5\n")) + (ert-info ("Move to other line") + (evil-test-buffer + "[l]ine1\nline2\nline3\nline4\nline5\n" + (":2,3move4") + "line1\nline4\nline2\n[l]ine3\nline5\n")) + (ert-info ("Move to current line") + (evil-test-buffer + "line1\nline2\nline3\nli[n]e4\nline5\n" + (":2,4move.") + "line1\nline2\nline3\n[l]ine4\nline5\n")) + (ert-info ("Move to backwards line, searching forwards (wrapping around)") + (evil-test-buffer + " +Target +Other line +[S]ource +" + (":move/Target/") + " +Target +[S]ource +Other line +")) + (ert-info ("Move to forwards line, searching backwards (wrapping around)") + (evil-test-buffer + " +Target +[O]ther line +Source +" + (":move?Source?") + " +Target +Source +[O]ther line +")) + (ert-info ("Move with global (classic line reversal)") + (evil-test-buffer + "5\n4\n3\n2\n1\n" + (":g/^/m0") + "1\n2\n3\n4\n5\n") + (ert-info ("... and visual selection") + (evil-test-buffer + "<5\n4\n3\n2\n[1]>\n" + (":g/^/m0") + "1\n2\n3\n4\n5\n")) + (ert-info ("... and no last blank line") + (evil-test-buffer + "5\n4\n3\n2\n1" + (":g/^/m0") + "1\n2\n3\n4\n5")))) + +(ert-deftest evil-test-write () + :tags '(evil ex) + "Test `evil-write'." + (ert-info ("Write open file") + (evil-with-temp-file filename "line1\nline2\nline3\n" + (evil-test-buffer + ((vconcat ":e " filename [return])) + "[l]ine1\nline2\nline3\n" + ("Galine4\nline5\n" [escape]) + "line1\nline2\nline3\nline4\nline5\n" + (":w") + (file filename "line1\nline2\nline3\nline4\nline5\n")))) + (ert-info ("Write current buffer to new file") + (let ((filename (make-temp-file "evil-test-write"))) + (evil-test-buffer + "[l]ine1\nline2\nline3\nline4\nline5\n" + (delete-file filename) + ((vconcat ":w " filename [return])) + (file filename "line1\nline2\nline3\nline4\nline5\n") + (delete-file filename)))) + (ert-info ("Write part of a buffer") + (let ((filename (make-temp-file "evil-test-write"))) + (evil-test-buffer + "[l]ine1\nline2\nline3\nline4\nline5\n" + (delete-file filename) + ((vconcat ":2,3w " filename [return])) + (file filename "line2\nline3\n") + (delete-file filename)))) + (ert-info ("Appending a file") + (let ((filename (make-temp-file "evil-test-write"))) + (evil-test-buffer + "[l]ine1\nline2\nline3\nline4\nline5\n" + (delete-file filename) + ((vconcat ":4w " filename [return])) + (file filename "line4\n") + ((vconcat ":1,2w >>" filename [return])) + (file filename "line4\nline1\nline2\n") + ((vconcat ":w >> " filename [return])) + (file filename + "line4\nline1\nline2\nline1\nline2\nline3\nline4\nline5\n") + (delete-file filename))))) + +(ert-deftest evil-test-ex-sort () + :tags '(evil ex) + "Text ex command :sort `evil-ex-sort`." + (ert-info ("Plain sort") + (evil-test-buffer + "[z]zyy\ntest\ntEst\ntesT\nTEST\ntest\n" + (":sort") + "[T]EST\ntEst\ntesT\ntest\ntest\nzzyy\n")) + (ert-info ("Reverse sort") + (evil-test-buffer + "[z]zyy\ntest\ntEst\ntesT\nTEST\ntest\n" + (":sort!") + "[z]zyy\ntest\ntest\ntesT\ntEst\nTEST\n")) + (ert-info ("case insensitive") + (evil-test-buffer + "[z]zyy\ntest\ntEst\ntesT\nTEST\ntest\n" + (":sort i") + "[t]est\ntEst\ntesT\nTEST\ntest\nzzyy\n")) + (ert-info ("unique") + (evil-test-buffer + "[z]zyy\ntest\ntEst\ntesT\nTEST\ntest\n" + (":sort u") + "[T]EST\ntEst\ntesT\ntest\nzzyy\n")) + (ert-info ("case insensitive and unique") + (evil-test-buffer + "[z]zyy\ntest\ntEst\ntesT\nTEST\ntest\n" + (":sort iu") + "[t]est\nzzyy\n"))) + +;;; Command line window + +(ert-deftest evil-test-command-window-ex () + "Test command line window for ex commands" + (skip-unless (not noninteractive)) + (let (evil-ex-history) + (evil-test-buffer + "[f]oo foo foo" + (":s/foo/bar" [return]) + "[b]ar foo foo" + (":s/foo/baz" [return]) + "[b]ar baz foo" + ("q:") + "s/foo/bar\ns/foo/baz\n[]\n" + ("kk:s/bar/quz" [return]) + "[s]/foo/quz\ns/foo/baz\n" + ("fzrx") + "s/foo/qu[x]\ns/foo/baz\n" + ([return]) + "[b]ar baz qux" + (should (equal (car evil-ex-history) + "s/foo/qux"))))) + +(ert-deftest evil-test-command-window-recursive () + "Test that recursive command windows shouldn't be allowed" + (skip-unless (not noninteractive)) + (let ((evil-command-window-height 0)) + (evil-test-buffer + "[f]oo foo foo" + (":s/foo/bar" [return]) + ("q:") + (should-error (execute-kbd-macro "q:"))))) + +(ert-deftest evil-test-command-window-noop () + "Test that executing a blank command does nothing" + (skip-unless (not noninteractive)) + (evil-test-buffer + "[f]oo foo foo" + ("q:") + "[]\n" + ([return]) + "[f]oo foo foo")) + +(ert-deftest evil-test-command-window-multiple () + "Test that multiple command line windows can't be visible at the same time" + (skip-unless (not noninteractive)) + (let ((evil-command-window-height 0)) + (evil-test-buffer + "[f]oo foo foo" + ("q:") + (let ((num-windows (length (window-list)))) + (select-window (previous-window)) + (execute-kbd-macro "q:") + (should (= (length (window-list)) num-windows)))))) + +(defmacro evil-with-both-search-modules (&rest body) + `(mapc (lambda (search-module) + (setq evil-search-forward-history nil + evil-search-backward-history nil + evil-ex-search-history nil) + (evil-select-search-module 'evil-search-module search-module) + ,@body) + '(isearch evil-search))) + +(ert-deftest evil-test-command-window-search-history () + "Test command window with forward and backward search history" + (skip-unless (not noninteractive)) + (let ((evil-search-module 'isearch)) + (evil-test-buffer + "[f]oo bar baz qux one two three four" + ("/qux" [return]) + "foo bar baz [q]ux one two three four" + ("/three" [return]) + "foo bar baz qux one two [t]hree four" + ("?bar" [return]) + "foo [b]ar baz qux one two three four" + ("/four" [return]) + "foo bar baz qux one two three [f]our" + ("?baz" [return]) + "foo bar [b]az qux one two three four" + ("q/") + "qux\nthree\nfour\n[]\n" + ("k" [return]) + "foo bar baz qux one two three [f]our" + ("0N") + "foo bar baz qux one two three [f]our" + ("q?") + "bar\nbaz\n[]\n" + ("k$rr" [return]) + "foo [b]ar baz qux one two three four" + (should-error + (progn (execute-kbd-macro "q/iNOT THERE") + (execute-kbd-macro [return]))) + "foo [b]ar baz qux one two three four"))) + +(ert-deftest evil-test-command-window-search-word () + "Test command window history when searching for word under cursor" + (skip-unless (not noninteractive)) + (let ((evil-search-module 'isearch)) + (evil-test-buffer + "[f]oo bar foo bar foo" + ("**") + "foo bar foo bar [f]oo" + ("B#") + "foo [b]ar foo bar foo" + ("q/k" [return]) + "foo bar [f]oo bar foo" + ("q?k" [return]) + "foo [b]ar foo bar foo"))) + +;;; Utilities + +(ert-deftest evil-test-parser () + "Test `evil-parser'" + (let ((grammar '((number "[0-9]+" #'string-to-number) + (plus "\\+" #'intern) + (minus "-" #'intern) + (operator + plus + minus) + (sign + ((\? operator) #'$1)) + (signed-number + (sign number)) + (inc + (number #'(lambda (n) (1+ n)))) + (expr + (number operator number) + ("2" #'"1+1")) + (epsilon nil)))) + (ert-info ("Nothing") + (should (equal (evil-parser "1+2" nil grammar t) + nil)) + (should (equal (evil-parser "1+2" nil grammar) + '(nil . "1+2"))) + (should (equal (evil-parser "1+2" 'epsilon grammar t) + nil)) + (should (equal (evil-parser "1+2" 'epsilon grammar) + '(nil . "1+2")))) + (ert-info ("Strings") + (should (equal (evil-parser "1" 'number grammar t) + '((string-to-number "1")))) + (should (equal (evil-parser "11" 'number grammar) + '((string-to-number "11") . "")))) + (ert-info ("Sequences") + (should (equal (evil-parser "1" '(number) grammar t) + '((list (string-to-number "1"))))) + (should (equal (evil-parser "1+2" '(number operator number) grammar t) + '((list + (string-to-number "1") + (intern "+") + (string-to-number "2")))))) + (ert-info ("Symbols") + (should (equal (evil-parser "+" 'plus grammar t) + '((intern "+")))) + (should (equal (evil-parser "+" 'operator grammar t) + '((intern "+")))) + (should (equal (evil-parser "1" 'number grammar t) + '((string-to-number "1"))))) + (ert-info ("Whitespace") + (should (equal (evil-parser " 1" 'number grammar t) + '((string-to-number "1"))))) + (ert-info ("One or more") + (should (equal (evil-parser "1 2 3" '(+ number) grammar t) + '((list + (string-to-number "1") + (string-to-number "2") + (string-to-number "3"))))) + (should (equal (evil-parser "1 2 3" '(* number) grammar t) + '((list + (string-to-number "1") + (string-to-number "2") + (string-to-number "3"))))) + (should (equal (evil-parser "1 2 3" '(\? number) grammar) + '((string-to-number "1") . " 2 3"))) + (should (equal (evil-parser "1 2 3" '(\? number number) grammar) + '((list + (string-to-number "1") + (string-to-number "2")) + . " 3"))) + (should (equal (evil-parser "1 2 3" '(number (\? number)) grammar) + '((list + (string-to-number "1") + (string-to-number "2")) + . " 3"))) + (should (equal (evil-parser "1 2 3" '(number (\? number number)) grammar) + '((list + (string-to-number "1") + (list + (string-to-number "2") + (string-to-number "3"))) + . ""))) + (should (equal (evil-parser "1 a 3" '(number (\? number)) grammar) + '((list + (string-to-number "1") + nil) + . " a 3"))) + (should (equal (evil-parser "1" 'signed-number grammar t t) + '((signed-number (sign "") (number "1")) . "")))) + (ert-info ("Lookahead") + (should (equal (evil-parser "foobar" '("foo" (& "bar")) grammar) + '((list "foo") . "bar"))) + (should (equal (evil-parser "foobar" '("foo" (! "bar")) grammar) + nil)) + (should (equal (evil-parser "foobar" '("foo" (& "baz")) grammar) + nil)) + (should (equal (evil-parser "foobar" '("foo" (! "baz")) grammar) + '((list "foo") . "bar")))) + (ert-info ("Semantic actions") + (should (equal (evil-parser "1" 'inc grammar t) + '((funcall (lambda (n) + (1+ n)) + (string-to-number "1"))))) + (should (equal (evil-parser "1+1" 'expr grammar t) + '((list + (string-to-number "1") + (intern "+") + (string-to-number "1"))))) + (should (equal (evil-parser "2" 'expr grammar t) + '((list (string-to-number "1") + (intern "+") + (string-to-number "1")))))))) + +(ert-deftest evil-test-delimited-arguments () + "Test `evil-delimited-arguments'" + :tags '(evil util) + (ert-info ("Any number of arguments") + (should (equal (evil-delimited-arguments "/a/b/c/") + '("a" "b" "c"))) + (should (equal (evil-delimited-arguments "/a/b/c") + '("a" "b" "c"))) + (should (equal (evil-delimited-arguments "/a/b//") + '("a" "b" ""))) + (should (equal (evil-delimited-arguments "/a///") + '("a" "" ""))) + (should (equal (evil-delimited-arguments "/a/ ") + '("a" " "))) + (should (equal (evil-delimited-arguments "/a/") + '("a"))) + (should (equal (evil-delimited-arguments "//b//") + '("" "b" ""))) + (should (equal (evil-delimited-arguments "/a//c") + '("a" "" "c"))) + (should (equal (evil-delimited-arguments "////") + '("" "" ""))) + (should (equal (evil-delimited-arguments "/") + nil)) + (should (equal (evil-delimited-arguments " ") + nil)) + (should (equal (evil-delimited-arguments "") + nil))) + (ert-info ("Two arguments") + (should (equal (evil-delimited-arguments "/a/b/c" 2) + '("a" "b/c"))) + (should (equal (evil-delimited-arguments "/a/b/" 2) + '("a" "b"))) + (should (equal (evil-delimited-arguments "/a/b" 2) + '("a" "b"))) + (should (equal (evil-delimited-arguments "/a//" 2) + '("a" ""))) + (should (equal (evil-delimited-arguments "/a/ " 2) + '("a" " "))) + (should (equal (evil-delimited-arguments "/a/" 2) + '("a" nil))) + (should (equal (evil-delimited-arguments "/a" 2) + '("a" nil))) + (should (equal (evil-delimited-arguments " " 2) + '(nil nil))) + (should (equal (evil-delimited-arguments "" 2) + '(nil nil)))) + (ert-info ("One argument") + (should (equal (evil-delimited-arguments "/a/b/c" 1) + '("a/b/c"))) + (should (equal (evil-delimited-arguments "/a/ " 1) + '("a"))) + (should (equal (evil-delimited-arguments "/a/" 1) + '("a"))) + (should (equal (evil-delimited-arguments "/a" 1) + '("a"))) + (should (equal (evil-delimited-arguments "/" 1) + '(nil))) + (should (equal (evil-delimited-arguments " " 1) + '(nil))) + (should (equal (evil-delimited-arguments "" 1) + '(nil)))) + (ert-info ("Zero arguments") + (should (equal (evil-delimited-arguments "/a" 0) + nil)) + (should (equal (evil-delimited-arguments "/" 0) + nil)) + (should (equal (evil-delimited-arguments " " 0) + nil)) + (should (equal (evil-delimited-arguments "" 0) + nil)))) + +(ert-deftest evil-test-concat-charsets () + "Test `evil-concat-charsets'" + :tags '(evil util) + (ert-info ("Bracket") + (should (equal (evil-concat-charsets "abc" "]def") + "]abcdef"))) + (ert-info ("Complement") + (should (equal (evil-concat-charsets "^abc" "def") + "^abcdef")) + (should (equal (evil-concat-charsets "^abc" "^def") + "^abcdef"))) + (ert-info ("Hyphen") + (should (equal (evil-concat-charsets "abc" "-def") + "-abcdef")) + (should (equal (evil-concat-charsets "^abc" "-def") + "^-abcdef"))) + (ert-info ("Newline") + (should (equal (evil-concat-charsets "^ \t\r\n" "[:word:]_") + "^ \t\r\n[:word:]_")))) + +(ert-deftest evil-test-properties () + "Test `evil-get-property' and `evil-put-property'" + :tags '(evil util) + (let (alist) + (ert-info ("Set properties") + (evil-put-property 'alist 'wibble :foo t) + (should (equal alist '((wibble . (:foo t))))) + (evil-put-property 'alist 'wibble :bar nil) + (should (equal alist '((wibble . (:foo t :bar nil))))) + (evil-put-property 'alist 'wobble :foo nil :bar nil :baz t) + (should (equal alist '((wobble . (:foo nil :bar nil :baz t)) + (wibble . (:foo t :bar nil)))))) + (ert-info ("Get properties") + (should (evil-get-property alist 'wibble :foo)) + (should-not (evil-get-property alist 'wibble :bar)) + (should-not (evil-get-property alist 'wobble :foo)) + (should-not (evil-get-property alist 'wibble :baz)) + (should (equal (evil-get-property alist t :foo) + '((wibble . t) (wobble . nil)))) + (should (equal (evil-get-property alist t :bar) + '((wibble . nil) (wobble . nil)))) + (should (equal (evil-get-property alist t :baz) + '((wobble . t))))))) + +(ert-deftest evil-test-filter-list () + "Test `evil-filter-list'" + :tags '(evil util) + (ert-info ("Return filtered list") + (should (equal (evil-filter-list #'null '(nil)) nil)) + (should (equal (evil-filter-list #'null '(nil 1)) '(1))) + (should (equal (evil-filter-list #'null '(nil 1 2 nil)) '(1 2))) + (should (equal (evil-filter-list #'null '(nil nil 1)) '(1))) + (should (equal (evil-filter-list #'null '(nil 1 nil 2 nil 3)) + '(1 2 3)))) + (ert-info ("Remove matches by side-effect when possible") + (let (list) + (setq list '(1 nil)) + (evil-filter-list #'null list) + (should (equal list '(1))) + + (setq list '(1 nil nil)) + (evil-filter-list #'null list) + (should (equal list '(1))) + + (setq list '(1 nil nil 2)) + (evil-filter-list #'null list) + (should (equal list '(1 2))) + + (setq list '(1 nil 2 nil 3)) + (evil-filter-list #'null list) + (should (equal list '(1 2 3)))))) + +(ert-deftest evil-test-concat-lists () + "Test `evil-concat-lists' and `evil-concat-alists'" + :tags '(evil util) + (ert-info ("Remove duplicates across lists") + (should (equal (evil-concat-lists + nil '(a b) '(b c)) + '(a b c)))) + (ert-info ("Remove duplicates inside lists") + (should (equal (evil-concat-lists + '(a a b) nil '(b c) nil) + '(a b c)))) + (ert-info ("Remove duplicate associations") + (should (equal (evil-concat-alists + '((a . b)) '((a . c))) + '((a . c)))) + (should-not (equal (evil-concat-lists + '((a . b)) '((a . c))) + '((a . b)))))) + +(ert-deftest evil-test-sort () + "Test `evil-sort' and `evil-swap'" + :tags '(evil util) + (let (a b c d) + (ert-info ("Two elements") + (setq a 2 b 1) + (evil-sort a b) + (should (= a 1)) + (should (= b 2)) + (evil-swap a b) + (should (= a 2)) + (should (= b 1))) + (ert-info ("Three elements") + (setq a 3 b 1 c 2) + (evil-sort a b c) + (should (= a 1)) + (should (= b 2)) + (should (= c 3))) + (ert-info ("Four elements") + (setq a 4 b 3 c 2 d 1) + (evil-sort a b c d) + (should (= a 1)) + (should (= b 2)) + (should (= c 3)) + (should (= d 4))))) + +(ert-deftest evil-test-read-key () + "Test `evil-read-key'" + :tags '(evil util) + (let ((unread-command-events '(?A))) + (ert-info ("Prevent downcasing in `this-command-keys'") + (should (eq (evil-read-key) ?A)) + (should (equal (this-command-keys) "A"))))) + +(ert-deftest evil-test-extract-count () + "Test `evil-extract-count'" + :tags '(evil util) + (evil-test-buffer + (ert-info ("Exact without count") + (should (equal (evil-extract-count "x") + (list nil 'evil-delete-char "x" nil))) + (should (equal (evil-extract-count "g0") + (list nil 'evil-beginning-of-visual-line "g0" nil)))) + + (ert-info ("Exact with count") + (should (equal (evil-extract-count "420x") + (list 420 'evil-delete-char "x" nil))) + (should (equal (evil-extract-count (vconcat "420" [M-right])) + (list 420 (key-binding [M-right]) (vconcat [M-right]) nil))) + (should (equal (evil-extract-count "2301g0") + (list 2301 'evil-beginning-of-visual-line "g0" nil)))) + + (ert-info ("Extra elements without count") + (should (equal (evil-extract-count "xAB") + (list nil 'evil-delete-char "x" "AB"))) + (should (equal (evil-extract-count "g0CD") + (list nil 'evil-beginning-of-visual-line "g0" "CD")))) + + (ert-info ("Extra elements with count") + (should (equal (evil-extract-count "420xAB") + (list 420 'evil-delete-char "x" "AB"))) + (should (equal (evil-extract-count "2301g0CD") + (list 2301 'evil-beginning-of-visual-line "g0" "CD")))) + + (ert-info ("Exact \"0\" count") + (should (equal (evil-extract-count "0") + (list nil 'evil-beginning-of-line + "0" nil)))) + + (ert-info ("Extra elements and \"0\"") + (should (equal (evil-extract-count "0XY") + (list nil 'evil-beginning-of-line + "0" "XY")))) + + (ert-info ("Count only") + (should-error (evil-extract-count "1230"))) + + (ert-info ("Unknown command") + (should-error (evil-extract-count "°")) + (should-error (evil-extract-count "12°"))))) + +(ert-deftest evil-transform-vim-style-regexp () + "Test `evil-transform-vim-style-regexp'" + (dolist (repl '((?s . "[[:space:]]") + (?S . "[^[:space:]]") + (?d . "[[:digit:]]") + (?D . "[^[:digit:]]") + (?x . "[[:xdigit:]]") + (?X . "[^[:xdigit:]]") + (?o . "[0-7]") + (?O . "[^0-7]") + (?a . "[[:alpha:]]") + (?A . "[^[:alpha:]]") + (?l . "[a-z]") + (?L . "[^a-z]") + (?u . "[A-Z]") + (?U . "[^A-Z]") + (?y . "\\s") + (?Y . "\\S") + (?w . "\\w") + (?W . "\\W"))) + (ert-info ((format "Test transform from '\\%c' to '%s'" + (car repl) (cdr repl))) + (should (equal (evil-transform-vim-style-regexp + (concat "xxx\\" + (char-to-string (car repl)) + "\\" + (char-to-string (car repl)) + "\\\\" + (char-to-string (car repl)) + "\\\\\\" + (char-to-string (car repl)) + "yyy")) + (concat "xxx" + (cdr repl) + (cdr repl) + "\\\\" + (char-to-string (car repl)) + "\\\\" + (cdr repl) + "yyy")))))) + +;;; Advice + +(ert-deftest evil-test-eval-last-sexp () + "Test advised `evil-last-sexp'" + :tags '(evil advice) + (ert-info ("Normal state") + (evil-test-buffer + "(+ 1 (+ 2 3[)])" + ("1" (kbd "C-x C-e")) + "(+ 1 (+ 2 35[)])")) + (ert-info ("Insert state") + (evil-test-buffer + "(+ 1 (+ 2 3[)])" + ("i" (kbd "C-u") (kbd "C-x C-e") [escape]) + "(+ 1 (+ 2 3[3]))")) + (ert-info ("Emacs state") + (evil-test-buffer + "(+ 1 (+ 2 3[)])" + ((kbd "C-z") (kbd "C-u") (kbd "C-x C-e")) + "(+ 1 (+ 2 33[)])"))) + +;;; ESC + +(ert-deftest evil-test-esc-count () + "Test if prefix-argument is transfered for key sequences with meta-key" + :tags '(evil esc) + (unless noninteractive + (ert-info ("Test M-") + (evil-test-buffer + "[A]BC DEF GHI JKL MNO" + ("3" (kbd "ESC ")) + "ABC DEF GHI[ ]JKL MNO")) + (ert-info ("Test shell-command") + (evil-test-buffer + "[A]BC DEF GHI JKL MNO" + ("1" (kbd "ESC !") "echo TEST" [return]) + "[T]EST\nABC DEF GHI JKL MNO")))) + +(when (or evil-tests-profiler evil-tests-run) + (evil-tests-initialize)) + +(ert-deftest evil-test-black-hole-register () + :tags '(evil) + (ert-info ("Test \"_ on delete word") + (evil-test-buffer + "[E]vil evil is awesome." + ("dw\"_dwP") + "Evil[ ]is awesome.")) + (ert-info ("Test \"_ on delete line") + (evil-test-buffer + "[T]his line is a keeper!\nThis line is not." + ("dd\"_ddP") + "[T]his line is a keeper!")) + (ert-info ("Test \"_ on delete region") + (evil-test-buffer + "!\nThis line is not." + ("d\gg\"_dGP") + "This region is a keepe[r]"))) + +(ert-deftest evil-test-pasteable-macros () + "Test if we can yank and paste macros containing + " + :tags '(evil) + (ert-info ("Execute yanked macro") + (evil-test-buffer + "[i]foo\e" + ("\"qd$@q\"qp" + "fooifoo\e"))) + (ert-info ("Paste recorded marco") + (evil-test-buffer + "" + (evil-set-register ?q (vconcat "ifoo" [escape])) + ("@q\"qp") + "fooifoo\e"))) + +(ert-deftest evil-test-forward-symbol () + :tags '(evil) + (ert-info ("Test symbol deletion") + (evil-test-buffer + "(test [t]his (hello there) with dao)" + ("dao") + "(test [(]hello there) with dao)")) + (ert-info ("Test symbol motion") + (evil-test-buffer + "(test[ ](hello there) with dao)" + (should (eq 0 (forward-evil-symbol 1))) + "(test ([h]ello there) with dao)" + (should (eq 0 (forward-evil-symbol 1))) + "(test (hello[ ]there) with dao)")) + (ert-info ("Test dio on whitespace") + (evil-test-buffer + "(test[ ]dio with whitespace)" + ("dio") + "(test[d]io with whitespace)")) + (ert-info ("Test dao/dio with empty lines") + (evil-test-buffer + "there are two lines in this file\n[\n]and some whitespace between them" + ("dao") + "there are two lines in this file\n[a]nd some whitespace between them") + (evil-test-buffer + "here are another two lines\n[\n]with a blank line between them" + ("dio") + "here are another two lines\n[w]ith a blank line between them")) + (ert-info ("Test dao/dio with empty lines and punctuation") + (evil-test-buffer + "These two lines \n[\n]!have punctuation on them" + ("dao") + "These two lines \n[!]have punctuation on them"))) + +(ert-deftest evil-test-jump () + :tags '(evil jumps) + (let ((evil--jumps-buffer-targets "\\*\\(new\\|scratch\\|test\\)\\*")) + (ert-info ("Test jumping backward and forward in a single buffer") + (evil-test-buffer + "[z] z z z z z z z z z" + ("/z" [return]) + "z [z] z z z z z z z z" + ("nnnn") + "z z z z z [z] z z z z" + ("\C-o") + "z z z z [z] z z z z z" + ("\C-o") + "z z z [z] z z z z z z" + ("\C-i\C-i") + "z z z z z [z] z z z z")) + (ert-info ("Test jumping backward and forward with counts") + (evil-test-buffer + "[z] z z z z z z z z z" + ("/z" [return] "nnnn") + "z z z z z [z] z z z z" + ("3\C-o") + "z z [z] z z z z z z z" + ("2\C-i") + "z z z z [z] z z z z z" + )) + (ert-info ("Jump list branches off when new jump is set") + (evil-test-buffer + "[z] z z z z z z z" + ("/z" [return] "nnnn4\C-o") ;; adds a bunch of jumps after the 2nd z + "z [z] z z z z z z" + ("/z" [return]) ;; sets a new jump, list should be reset + "z z [z] z z z z z" + ("\C-o") + "z [z] z z z z z z" + ("3\C-i") ;; even after jumping forward 3 times it can't get past the 3rd z + "z z [z] z z z z z")) + (ert-info ("Jump across files") + (let ((temp-file (make-temp-file "evil-test-"))) + (unwind-protect + (evil-test-buffer + "[z] z z z z z z" + ("\M-x" "find-file" [return] temp-file [return] "inew buffer" [escape]) + "new buffe[r]" + ("\C-o") + "[z] z z z z z z" + ("\C-i") + "new buffe[r]") + (delete-file temp-file) + (with-current-buffer (get-file-buffer temp-file) + (set-buffer-modified-p nil)) + (kill-buffer (get-file-buffer temp-file))))))) + +(ert-deftest evil-test-find-file () + :tags '(evil jumps) + (ert-info ("Find file at point (normal state)") + (evil-with-temp-file file-name "" + (evil-test-buffer + (vconcat "i" file-name [escape]) + (should (not (equal file-name (buffer-file-name (current-buffer))))) + ("gf") + (should (equal file-name (buffer-file-name (current-buffer))))))) + (ert-info ("Find file at point (visual state)") + (evil-with-temp-file file-name "" + (evil-test-buffer + (vconcat "iuser@localhost:" file-name "$" [escape]) + (should (not (equal file-name (buffer-file-name (current-buffer))))) + ("0f:lvt$gf") + (should (equal file-name (buffer-file-name (current-buffer))))))) + (ert-info ("Find file at point with line number") + (let* ((line-number 3) + (file-content (make-string (* 2 line-number) ?\n))) + (evil-with-temp-file file-name (insert file-content) + (evil-test-buffer + (vconcat "i" file-name (format ":%d" line-number) [escape]) + (should (and (not (equal file-name (buffer-file-name (current-buffer)))) + (not (equal line-number (line-number-at-pos))))) + ("gF") + (should (and (equal file-name (buffer-file-name (current-buffer))) + (equal line-number (line-number-at-pos)))))))) + (ert-info ("Find file at point with line and column numbers") + (let* ((line-number 3) + (column-number 5) + (file-content (mapconcat 'identity + (make-list (* 2 line-number) + (make-string (* 2 column-number) ?\s)) + "\n"))) + (evil-with-temp-file file-name (insert file-content) + (evil-test-buffer + (vconcat "i" file-name (format ":%d:%d" line-number column-number) [escape]) + (should (and (not (equal file-name (buffer-file-name (current-buffer)))) + (not (equal line-number (line-number-at-pos))) + (not (equal column-number (current-column))))) + ("gF") + (should (and (equal file-name (buffer-file-name (current-buffer))) + (equal line-number (line-number-at-pos)) + (equal column-number (1+ (current-column)))))))))) + +(ert-deftest evil-test-jump-buffers () + :tags '(evil jumps) + (skip-unless nil) + (ert-info ("Test jumping backward and forward across buffers") + (evil-test-buffer + "[z] z z z z z z z z z" + (":new" [return] "inew buffer" [escape]) + "new buffe[r]" + ("\C-o") + "[z] z z z z z z z z z" + ("\C-i") + "new buffe[r]"))) + +(ert-deftest evil-test-abbrev-expand () + :tags '(evil abbrev) + (ert-info ("Test abbrev expansion on insert state exit") + (define-abbrev-table 'global-abbrev-table + '(("undef" "undefined"))) ; add global abbrev + (evil-test-buffer + "foo unde[f] bar" + (abbrev-mode) + ("a" [escape]) + "foo undefine[d] bar") ; 'undef' should be expanded + (evil-test-buffer + "foo unde[f] bar" + ("a" [escape]) + "foo unde[f] bar") ; 'undef' shouldn't be expanded, + ; abbrev-mode is not enabled + (evil-test-buffer + "fo[o] undef bar" + (abbrev-mode) + ("a" [escape]) + "fo[o] undef bar") ; 'foo' shouldn't be expanded, + ; it's not an abbrev + (kill-all-abbrevs) ; remove all abbrevs + (evil-test-buffer + "foo unde[f] bar" + (abbrev-mode) + ("a" [escape]) + "foo unde[f] bar") ; 'undef' shouldn't be expanded, + ; it's not an abbrev + (setq abbrevs-changed nil))) + +(ert-deftest evil-test-text-object-macro () + :tags '(evil abbrev) + (ert-info ("Test pipe character and other delimiters as object delimiters") + ;; This is the macro that broke after pull #747. + (defmacro evil-test-define-and-bind-text-object (name key start-regex end-regex) + (let ((inner-name (make-symbol (concat "evil-inner-" name))) + (outer-name (make-symbol (concat "evil-a-" name)))) + `(progn + (evil-define-text-object ,inner-name (count &optional beg end type) + (evil-select-paren ,start-regex ,end-regex beg end type count nil)) + (evil-define-text-object ,outer-name (count &optional beg end type) + (evil-select-paren ,start-regex ,end-regex beg end type count t)) + (define-key evil-inner-text-objects-map ,key #',inner-name) + (define-key evil-outer-text-objects-map ,key #',outer-name)))) + (evil-test-define-and-bind-text-object "pipe" "|" "|" "|") + (evil-test-define-and-bind-text-object "rackety" "#" "#|" "|#") + + (evil-test-buffer + "#|this i[s] a test #|with rackety|# multiline + and nestable comments|#" + ("vi#") + "#||#") + (evil-test-buffer + "| foo | aoe[u] | bar |" + ("vi|") + "| foo |< aoeu >| bar |" + ("a|") + "| foo <| aoeu |> bar |" + ("a|") + "<| foo | aoeu | bar |>") + (evil-test-buffer + "| foo | aoe[u] | bar |" + ("ci|testing" [escape]) + "| foo |testing| bar |"))) + +(ert-deftest evil-test-undo-kbd-macro () + "Test if evil can undo the changes made by a keyboard macro +when an error stops the execution of the macro" + :tags '(evil undo kbd-macro) + (ert-info ("When kbd-macro goes to the end of buffer") + (evil-test-buffer + "[l]ine 1\nline 2\nline 3\nline 4" + (evil-set-register ?q "jdd") + ("jdd") + (should-error (execute-kbd-macro "2@q")) + ("uu") + "line 1\n[l]ine 2\nline 3\nline 4")) + (ert-info ("When kbd-macro goes to the end of line") + (evil-test-buffer + "[f]ofof" + (evil-set-register ?q "lx") + ("lx") + (should-error (execute-kbd-macro "2@q")) + ("uu") + "f[o]fof")) + (ert-info ("When kbd-macro goes to the beginning of buffer") + (evil-test-buffer + "line 1\nline 2\n[l]ine 3" + (evil-set-register ?q "kx") + ("kx") + (should-error (execute-kbd-macro "2@q")) + ("uu") + "line 1\n[l]ine 2\nline 3"))) + +(ert-deftest evil-test-visual-update-x-selection () + "Test `evil-visual-update-x-selection'." + :tags '(evil) + (ert-info ("Buffer argument isn't a live buffer") + ;; create buffer in normal mode, so we don't try to actually copy anything to + ;; the X selection. + (let ((buf (evil-test-buffer-from-string "foobar"))) + (kill-buffer buf) + ;; should not raise an "Selecting deleted buffer" error + (evil-visual-update-x-selection buf)))) + +;;; Core + +(ert-deftest evil-test-initial-state () + "Test `evil-initial-state'" + :tags '(evil core) + (define-derived-mode test-1-mode prog-mode "Test1") + (define-derived-mode test-2-mode test-1-mode "Test2") + (evil-set-initial-state 'test-1-mode 'insert) + (ert-info ("Check default state") + (should (eq (evil-initial-state 'prog-mode 'normal) 'normal))) + (ert-info ("Basic functionality 1") + (should (eq (evil-initial-state 'test-1-mode) 'insert))) + (ert-info ("Basic functionality 2") + (evil-test-buffer + "abc\ndef\n" + (test-1-mode) + (should (eq evil-state 'insert)))) + (ert-info ("Inherit initial state from a parent") + (evil-test-buffer + "abc\ndef\n" + (test-2-mode) + (should (eq evil-state 'insert)))) + (evil-set-initial-state 'test-1-mode nil) + (ert-info ("Check for inheritance loops") + (evil-test-buffer + "abc\ndef\n" + (unwind-protect + (let ((major-mode 'test-2-mode)) + (put 'test-1-mode 'derived-mode-parent 'test-2-mode) + ;; avoid triggering all of the hooks here, some of which might get + ;; caught in loops depending on the environment. settings major-mode + ;; is sufficient for `evil-initial-state-for-buffer' to work. + (should-error (evil-initial-state-for-buffer))) + (put 'test-1-mode 'derived-mode-parent 'prog-mode)))) + (defalias 'test-1-alias-mode 'test-1-mode) + (define-derived-mode test-3-mode test-1-alias-mode "Test3") + (evil-set-initial-state 'test-1-mode 'insert) + (ert-info ("Check inheritance from major mode aliases") + "abc\ndef\n" + (test-3-mode) + (should (eq evil-state 'insert)))) + +(provide 'evil-tests) + +;;; evil-tests.el ends here -- cgit v1.2.3