diff options
| author | Alan Mackenzie | 2017-02-12 10:59:03 +0000 |
|---|---|---|
| committer | Alan Mackenzie | 2017-02-12 10:59:03 +0000 |
| commit | f4d5b687150810129b7a1d5b006e31ccf82b691b (patch) | |
| tree | 4229b13800349032697daae3904dc3773e6b7a80 /test/lisp/kmacro-tests.el | |
| parent | d5514332d4a6092673ce1f78fadcae0c57f7be64 (diff) | |
| parent | 148100d98319499f0ac6f57b8be08cbd14884a5c (diff) | |
| download | emacs-comment-cache.tar.gz emacs-comment-cache.zip | |
Merge branch 'master' into comment-cachecomment-cache
Diffstat (limited to 'test/lisp/kmacro-tests.el')
| -rw-r--r-- | test/lisp/kmacro-tests.el | 890 |
1 files changed, 890 insertions, 0 deletions
diff --git a/test/lisp/kmacro-tests.el b/test/lisp/kmacro-tests.el new file mode 100644 index 00000000000..5124cbbf962 --- /dev/null +++ b/test/lisp/kmacro-tests.el | |||
| @@ -0,0 +1,890 @@ | |||
| 1 | ;;; kmacro-tests.el --- Tests for kmacro.el -*- lexical-binding: t; -*- | ||
| 2 | |||
| 3 | ;; Copyright (C) 2017 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | ;; Author: Gemini Lasswell <gazally@runbox.com> | ||
| 6 | |||
| 7 | ;; This file is part of GNU Emacs. | ||
| 8 | |||
| 9 | ;; GNU Emacs is free software: you can redistribute it and/or modify | ||
| 10 | ;; it under the terms of the GNU General Public License as published by | ||
| 11 | ;; the Free Software Foundation, either version 3 of the License, or | ||
| 12 | ;; (at your option) any later version. | ||
| 13 | |||
| 14 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 15 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | ;; GNU General Public License for more details. | ||
| 18 | |||
| 19 | ;; You should have received a copy of the GNU General Public License | ||
| 20 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. | ||
| 21 | |||
| 22 | ;;; Commentary: | ||
| 23 | |||
| 24 | ;;; Code: | ||
| 25 | |||
| 26 | (require 'kmacro) | ||
| 27 | (require 'ert) | ||
| 28 | (require 'ert-x) | ||
| 29 | |||
| 30 | ;;; Test fixtures: | ||
| 31 | |||
| 32 | (defmacro kmacro-tests-with-kmacro-clean-slate (&rest body) | ||
| 33 | "Create a clean environment for a kmacro test BODY to run in." | ||
| 34 | (declare (debug (body))) | ||
| 35 | `(cl-letf* ((kmacro-execute-before-append t) | ||
| 36 | (kmacro-ring-max 8) | ||
| 37 | (kmacro-repeat-no-prefix t) | ||
| 38 | (kmacro-call-repeat-key nil) | ||
| 39 | (kmacro-call-repeat-with-arg nil) | ||
| 40 | |||
| 41 | (kbd-macro-termination-hook nil) | ||
| 42 | (defining-kbd-macro nil) | ||
| 43 | (executing-kbd-macro nil) | ||
| 44 | (executing-kbd-macro-index 0) | ||
| 45 | (last-kbd-macro nil) | ||
| 46 | |||
| 47 | (kmacro-ring nil) | ||
| 48 | |||
| 49 | (kmacro-counter 0) | ||
| 50 | (kmacro-default-counter-format "%d") | ||
| 51 | (kmacro-counter-format "%d") | ||
| 52 | (kmacro-counter-format-start "%d") | ||
| 53 | (kmacro-counter-value-start 0) | ||
| 54 | (kmacro-last-counter 0) | ||
| 55 | (kmacro-initial-counter-value nil) | ||
| 56 | |||
| 57 | (kmacro-tests-macros nil) | ||
| 58 | (kmacro-tests-events nil) | ||
| 59 | (kmacro-tests-sequences nil)) | ||
| 60 | (advice-add 'end-kbd-macro :after #'kmacro-tests-end-macro-advice) | ||
| 61 | (advice-add 'read-event :around #'kmacro-tests-read-event-advice ) | ||
| 62 | (advice-add 'read-key-sequence :around #'kmacro-tests-read-key-sequence-advice) | ||
| 63 | (unwind-protect | ||
| 64 | (ert-with-test-buffer (:name "") | ||
| 65 | (switch-to-buffer (current-buffer)) | ||
| 66 | ,@body) | ||
| 67 | (advice-remove 'read-key-sequence #'kmacro-tests-read-key-sequence-advice) | ||
| 68 | (advice-remove 'read-event #'kmacro-tests-read-event-advice) | ||
| 69 | (advice-remove 'end-kbd-macro #'kmacro-tests-end-macro-advice)))) | ||
| 70 | |||
| 71 | (defmacro kmacro-tests-deftest (name _args docstring &rest keys-and-body) | ||
| 72 | "Define a kmacro unit test. | ||
| 73 | NAME is the name of the test, _ARGS should be nil, and DOCSTRING | ||
| 74 | is required. To avoid having to duplicate ert's keyword parsing | ||
| 75 | here, its keywords and values (if any) must be inside a list | ||
| 76 | after the docstring, preceding the body, here combined with the | ||
| 77 | body in KEYS-AND-BODY." | ||
| 78 | (declare (debug (&define name sexp stringp | ||
| 79 | [&optional (&rest &or [keywordp sexp])] | ||
| 80 | def-body)) | ||
| 81 | (doc-string 3) | ||
| 82 | (indent 2)) | ||
| 83 | |||
| 84 | (let* ((keys (when (and (listp (car keys-and-body)) | ||
| 85 | (keywordp (caar keys-and-body))) | ||
| 86 | (car keys-and-body))) | ||
| 87 | (body (if keys (cdr keys-and-body) | ||
| 88 | keys-and-body))) | ||
| 89 | `(ert-deftest ,name () | ||
| 90 | ,docstring ,@keys | ||
| 91 | (kmacro-tests-with-kmacro-clean-slate ,@body)))) | ||
| 92 | |||
| 93 | (defvar kmacro-tests-keymap | ||
| 94 | (let ((map (make-sparse-keymap))) | ||
| 95 | (dotimes (i 26) | ||
| 96 | (define-key map (string (+ ?a i)) 'self-insert-command)) | ||
| 97 | (dotimes (i 10) | ||
| 98 | (define-key map (string (+ ?0 i)) 'self-insert-command)) | ||
| 99 | ;; Define a few key sequences of different lengths. | ||
| 100 | (dolist (item '(("\C-a" . beginning-of-line) | ||
| 101 | ("\C-b" . backward-char) | ||
| 102 | ("\C-e" . end-of-line) | ||
| 103 | ("\C-f" . forward-char) | ||
| 104 | ("\C-r" . isearch-backward) | ||
| 105 | ("\C-u" . universal-argument) | ||
| 106 | ("\C-w" . kill-region) | ||
| 107 | ("\C-SPC" . set-mark-command) | ||
| 108 | ("\M-w" . kill-ring-save) | ||
| 109 | ("\M-x" . execute-extended-command) | ||
| 110 | ("\C-cd" . downcase-word) | ||
| 111 | ("\C-cxu" . upcase-word) | ||
| 112 | ("\C-cxq" . quoted-insert) | ||
| 113 | ("\C-cxi" . kmacro-insert-counter) | ||
| 114 | ("\C-x\C-k" . kmacro-keymap))) | ||
| 115 | (define-key map (car item) (cdr item))) | ||
| 116 | map) | ||
| 117 | "Keymap to use for testing keyboard macros. | ||
| 118 | This is used to obtain consistent results even if tests are run | ||
| 119 | in an environment with rebound keys.") | ||
| 120 | |||
| 121 | (defvar kmacro-tests-events nil | ||
| 122 | "Input events used by the kmacro test in progress.") | ||
| 123 | |||
| 124 | (defun kmacro-tests-read-event-advice (orig-func &rest args) | ||
| 125 | "Pop and return an event from `kmacro-tests-events'. | ||
| 126 | Return the result of calling ORIG-FUNC with ARGS if | ||
| 127 | `kmacro-tests-events' is empty, or if a keyboard macro is | ||
| 128 | running." | ||
| 129 | (if (or executing-kbd-macro (null kmacro-tests-events)) | ||
| 130 | (apply orig-func args) | ||
| 131 | (pop kmacro-tests-events))) | ||
| 132 | |||
| 133 | (defvar kmacro-tests-sequences nil | ||
| 134 | "Input sequences used by the kmacro test in progress.") | ||
| 135 | |||
| 136 | (defun kmacro-tests-read-key-sequence-advice (orig-func &rest args) | ||
| 137 | "Pop and return a string from `kmacro-tests-sequences'. | ||
| 138 | Return the result of calling ORIG-FUNC with ARGS if | ||
| 139 | `kmacro-tests-sequences' is empty, or if a keyboard macro is | ||
| 140 | running." | ||
| 141 | (if (or executing-kbd-macro (null kmacro-tests-sequences)) | ||
| 142 | (apply orig-func args) | ||
| 143 | (pop kmacro-tests-sequences))) | ||
| 144 | |||
| 145 | (defvar kmacro-tests-macros nil | ||
| 146 | "Keyboard macros (in vector form) used by the kmacro test in progress.") | ||
| 147 | |||
| 148 | (defun kmacro-tests-end-macro-advice (&rest _args) | ||
| 149 | "Pop a macro from `kmacro-tests-macros' and assign it to `last-kbd-macro'. | ||
| 150 | If `kmacro-tests-macros' is empty, do nothing." | ||
| 151 | (when kmacro-tests-macros | ||
| 152 | (setq last-kbd-macro (pop kmacro-tests-macros)))) | ||
| 153 | |||
| 154 | ;;; Some more powerful expectations: | ||
| 155 | |||
| 156 | (defmacro kmacro-tests-should-insert (value &rest body) | ||
| 157 | "Verify that VALUE is inserted by the execution of BODY. | ||
| 158 | Execute BODY, then check that the string VALUE was inserted | ||
| 159 | into the current buffer at point." | ||
| 160 | (declare (debug (stringp body)) | ||
| 161 | (indent 1)) | ||
| 162 | (let ((g-p (cl-gensym)) | ||
| 163 | (g-bsize (cl-gensym))) | ||
| 164 | `(let ((,g-p (point)) | ||
| 165 | (,g-bsize (buffer-size))) | ||
| 166 | ,@body | ||
| 167 | (should (equal (buffer-substring ,g-p (point)) ,value)) | ||
| 168 | (should (equal (- (buffer-size) ,g-bsize) (length ,value)))))) | ||
| 169 | |||
| 170 | (defmacro kmacro-tests-should-match-message (value &rest body) | ||
| 171 | "Verify that a message matching VALUE is issued while executing BODY. | ||
| 172 | Execute BODY, and then if there is not a regexp match between | ||
| 173 | VALUE and any text written to *Messages* during the execution, | ||
| 174 | cause the current test to fail." | ||
| 175 | (declare (debug (form body)) | ||
| 176 | (indent 1)) | ||
| 177 | (let ((g-captured-messages (cl-gensym))) | ||
| 178 | `(ert-with-message-capture ,g-captured-messages | ||
| 179 | ,@body | ||
| 180 | (should (string-match-p ,value ,g-captured-messages))))) | ||
| 181 | |||
| 182 | ;;; Tests: | ||
| 183 | |||
| 184 | (kmacro-tests-deftest kmacro-tests-test-insert-counter-01-nil () | ||
| 185 | "`kmacro-insert-counter' adds one to macro counter with nil arg." | ||
| 186 | (kmacro-tests-should-insert "0" | ||
| 187 | (kmacro-tests-simulate-command '(kmacro-insert-counter nil))) | ||
| 188 | (kmacro-tests-should-insert "1" | ||
| 189 | (kmacro-tests-simulate-command '(kmacro-insert-counter nil)))) | ||
| 190 | |||
| 191 | (kmacro-tests-deftest kmacro-tests-test-insert-counter-02-int () | ||
| 192 | "`kmacro-insert-counter' increments by value of list argument." | ||
| 193 | (kmacro-tests-should-insert "0" | ||
| 194 | (kmacro-tests-simulate-command '(kmacro-insert-counter 2))) | ||
| 195 | (kmacro-tests-should-insert "2" | ||
| 196 | (kmacro-tests-simulate-command '(kmacro-insert-counter 3))) | ||
| 197 | (kmacro-tests-should-insert "5" | ||
| 198 | (kmacro-tests-simulate-command '(kmacro-insert-counter nil)))) | ||
| 199 | |||
| 200 | (kmacro-tests-deftest kmacro-tests-test-insert-counter-03-list () | ||
| 201 | "`kmacro-insert-counter' doesn't increment when given universal argument." | ||
| 202 | (kmacro-tests-should-insert "0" | ||
| 203 | (kmacro-tests-simulate-command '(kmacro-insert-counter (16)))) | ||
| 204 | (kmacro-tests-should-insert "0" | ||
| 205 | (kmacro-tests-simulate-command '(kmacro-insert-counter (4))))) | ||
| 206 | |||
| 207 | (kmacro-tests-deftest kmacro-tests-test-insert-counter-04-neg () | ||
| 208 | "`kmacro-insert-counter' decrements with '- prefix argument" | ||
| 209 | (kmacro-tests-should-insert "0" | ||
| 210 | (kmacro-tests-simulate-command '(kmacro-insert-counter -))) | ||
| 211 | (kmacro-tests-should-insert "-1" | ||
| 212 | (kmacro-tests-simulate-command '(kmacro-insert-counter nil)))) | ||
| 213 | |||
| 214 | (kmacro-tests-deftest kmacro-tests-test-start-format-counter () | ||
| 215 | "`kmacro-insert-counter' uses start value and format." | ||
| 216 | (kmacro-tests-simulate-command '(kmacro-set-counter 10)) | ||
| 217 | (kmacro-tests-should-insert "10" | ||
| 218 | (kmacro-tests-simulate-command '(kmacro-insert-counter nil))) | ||
| 219 | (kmacro-tests-should-insert "11" | ||
| 220 | (kmacro-tests-simulate-command '(kmacro-insert-counter nil))) | ||
| 221 | (kmacro-set-format "c=%s") | ||
| 222 | (kmacro-tests-simulate-command '(kmacro-set-counter 50)) | ||
| 223 | (kmacro-tests-should-insert "c=50" | ||
| 224 | (kmacro-tests-simulate-command '(kmacro-insert-counter nil)))) | ||
| 225 | |||
| 226 | (kmacro-tests-deftest kmacro-tests-test-start-macro-when-defining-macro () | ||
| 227 | "Starting a macro while defining a macro does not start a second macro." | ||
| 228 | (kmacro-tests-simulate-command '(kmacro-start-macro nil)) | ||
| 229 | ;; We should now be in the macro-recording state. | ||
| 230 | (should defining-kbd-macro) | ||
| 231 | (should-not last-kbd-macro) | ||
| 232 | ;; Calling it again should leave us in the same state. | ||
| 233 | (kmacro-tests-simulate-command '(kmacro-start-macro nil)) | ||
| 234 | (should defining-kbd-macro) | ||
| 235 | (should-not last-kbd-macro)) | ||
| 236 | |||
| 237 | |||
| 238 | (kmacro-tests-deftest kmacro-tests-set-macro-counter-while-defining () | ||
| 239 | "Use of the prefix arg with kmacro-start sets kmacro-counter." | ||
| 240 | ;; Give kmacro-start-macro an argument. | ||
| 241 | (kmacro-tests-simulate-command '(kmacro-start-macro 5)) | ||
| 242 | (should defining-kbd-macro) | ||
| 243 | ;; Verify that the counter is set to that value. | ||
| 244 | (kmacro-tests-should-insert "5" | ||
| 245 | (kmacro-tests-simulate-command '(kmacro-insert-counter nil))) | ||
| 246 | ;; Change it while defining a macro. | ||
| 247 | (kmacro-tests-simulate-command '(kmacro-set-counter 1)) | ||
| 248 | (kmacro-tests-should-insert "1" | ||
| 249 | (kmacro-tests-simulate-command '(kmacro-insert-counter nil))) | ||
| 250 | ;; Using universal arg to to set counter should reset to starting value. | ||
| 251 | (kmacro-tests-simulate-command '(kmacro-set-counter (4)) '(4)) | ||
| 252 | (kmacro-tests-should-insert "5" | ||
| 253 | (kmacro-tests-simulate-command '(kmacro-insert-counter nil)))) | ||
| 254 | |||
| 255 | |||
| 256 | (kmacro-tests-deftest kmacro-tests-start-insert-counter-appends-to-macro () | ||
| 257 | "Use of the universal arg appends to the previous macro." | ||
| 258 | (let ((kmacro-tests-macros (list (string-to-vector "hello")))) | ||
| 259 | ;; Start recording a macro. | ||
| 260 | (kmacro-tests-simulate-command '(kmacro-start-macro-or-insert-counter nil)) | ||
| 261 | ;; Make sure we are recording. | ||
| 262 | (should defining-kbd-macro) | ||
| 263 | ;; Call it again and it should insert the counter. | ||
| 264 | (kmacro-tests-should-insert "0" | ||
| 265 | (kmacro-tests-simulate-command '(kmacro-start-macro-or-insert-counter nil))) | ||
| 266 | ;; We should still be in the recording state. | ||
| 267 | (should defining-kbd-macro) | ||
| 268 | ;; End recording with repeat count. | ||
| 269 | (kmacro-tests-simulate-command '(kmacro-end-or-call-macro 3)) | ||
| 270 | ;; Recording should be finished. | ||
| 271 | (should-not defining-kbd-macro) | ||
| 272 | ;; Now use prefix arg to append to the previous macro. | ||
| 273 | ;; This should run the previous macro first. | ||
| 274 | (kmacro-tests-should-insert "hello" | ||
| 275 | (kmacro-tests-simulate-command | ||
| 276 | '(kmacro-start-macro-or-insert-counter (4)))) | ||
| 277 | ;; Verify that the recording state has changed. | ||
| 278 | (should (equal defining-kbd-macro 'append)))) | ||
| 279 | |||
| 280 | (kmacro-tests-deftest kmacro-tests-end-call-macro-prefix-args () | ||
| 281 | "kmacro-end-call-macro changes behavior based on prefix arg." | ||
| 282 | ;; "Record" two macros. | ||
| 283 | (dotimes (i 2) | ||
| 284 | (kmacro-tests-define-macro (vconcat (format "macro #%d" (1+ i))))) | ||
| 285 | ;; With no prefix arg, it should call the second macro. | ||
| 286 | (kmacro-tests-should-insert "macro #2" | ||
| 287 | (kmacro-tests-simulate-command '(kmacro-end-or-call-macro nil))) | ||
| 288 | ;; With universal arg, it should call the first one. | ||
| 289 | (kmacro-tests-should-insert "macro #1" | ||
| 290 | (kmacro-tests-simulate-command '(kmacro-end-or-call-macro (4))))) | ||
| 291 | |||
| 292 | (kmacro-tests-deftest kmacro-tests-end-and-call-macro () | ||
| 293 | "Keyboard command to end and call macro works under various conditions." | ||
| 294 | ;; First, try it with no macro to record. | ||
| 295 | (setq kmacro-tests-macros '("")) | ||
| 296 | (kmacro-tests-simulate-command '(kmacro-start-macro nil)) | ||
| 297 | (condition-case err | ||
| 298 | (kmacro-tests-simulate-command '(kmacro-end-and-call-macro 2) 2) | ||
| 299 | (error (should (string= (cadr err) | ||
| 300 | "No kbd macro has been defined")))) | ||
| 301 | |||
| 302 | ;; Check that it stopped defining and that no macro was recorded. | ||
| 303 | (should-not defining-kbd-macro) | ||
| 304 | (should-not last-kbd-macro) | ||
| 305 | |||
| 306 | ;; Now try it while not recording, but first record a non-nil macro. | ||
| 307 | (kmacro-tests-define-macro "macro") | ||
| 308 | (kmacro-tests-should-insert "macro" | ||
| 309 | (kmacro-tests-simulate-command '(kmacro-end-and-call-macro nil)))) | ||
| 310 | |||
| 311 | (kmacro-tests-deftest kmacro-tests-end-and-call-macro-mouse () | ||
| 312 | "Commands to end and call macro work under various conditions. | ||
| 313 | This is a regression test for Bug#24992." | ||
| 314 | (:expected-result :failed) | ||
| 315 | (cl-letf (((symbol-function #'mouse-set-point) #'ignore)) | ||
| 316 | ;; First, try it with no macro to record. | ||
| 317 | (setq kmacro-tests-macros '("")) | ||
| 318 | (kmacro-tests-simulate-command '(kmacro-start-macro nil)) | ||
| 319 | (condition-case err | ||
| 320 | (kmacro-tests-simulate-command '(kmacro-end-call-mouse 2) 2) | ||
| 321 | (error (should (string= (cadr err) | ||
| 322 | "No kbd macro has been defined")))) | ||
| 323 | |||
| 324 | ;; Check that it stopped defining and that no macro was recorded. | ||
| 325 | (should-not defining-kbd-macro) | ||
| 326 | (should-not last-kbd-macro) | ||
| 327 | |||
| 328 | ;; Now try it while not recording, but first record a non-nil macro. | ||
| 329 | (kmacro-tests-define-macro "macro") | ||
| 330 | (kmacro-tests-should-insert "macro" | ||
| 331 | (kmacro-tests-simulate-command '(kmacro-end-call-mouse nil))))) | ||
| 332 | |||
| 333 | (kmacro-tests-deftest kmacro-tests-call-macro-hint-and-repeat () | ||
| 334 | "`kmacro-call-macro' gives hint in Messages and sets up repeat keymap. | ||
| 335 | This is a regression test for: Bug#3412, Bug#11817." | ||
| 336 | (kmacro-tests-define-macro [?m]) | ||
| 337 | (let ((kmacro-call-repeat-key t) | ||
| 338 | (kmacro-call-repeat-with-arg t) | ||
| 339 | (overriding-terminal-local-map overriding-terminal-local-map) | ||
| 340 | (last-input-event ?e)) | ||
| 341 | (message "") ; Clear the echo area. (Bug#3412) | ||
| 342 | (kmacro-tests-should-match-message "Type e to repeat macro" | ||
| 343 | (kmacro-tests-should-insert "mmmmmm" | ||
| 344 | (cl-letf (((symbol-function #'this-single-command-keys) (lambda () | ||
| 345 | [?\C-x ?e]))) | ||
| 346 | (kmacro-call-macro 3)) | ||
| 347 | ;; Check that it set up for repeat, and run the repeat. | ||
| 348 | (funcall (lookup-key overriding-terminal-local-map "e")))))) | ||
| 349 | |||
| 350 | (kmacro-tests-deftest | ||
| 351 | kmacro-tests-run-macro-command-recorded-in-macro () | ||
| 352 | "No infinite loop if `kmacro-end-and-call-macro' is recorded in the macro. | ||
| 353 | \(Bug#15126)" | ||
| 354 | (:expected-result :failed) | ||
| 355 | (ert-skip "Skipping due to Bug#24921 (an ERT bug)") | ||
| 356 | (kmacro-tests-define-macro (vconcat "foo" [return] "\M-x" | ||
| 357 | "kmacro-end-and-call-macro")) | ||
| 358 | (use-local-map kmacro-tests-keymap) | ||
| 359 | (kmacro-tests-simulate-command '(kmacro-end-and-call-macro nil))) | ||
| 360 | |||
| 361 | |||
| 362 | (kmacro-tests-deftest kmacro-tests-test-ring-2nd-commands () | ||
| 363 | "2nd macro in ring is displayed and executed normally and on repeat." | ||
| 364 | (use-local-map kmacro-tests-keymap) | ||
| 365 | ;; Record one macro, with count. | ||
| 366 | (push (vconcat "\C-cxi" "\C-u\C-cxi") kmacro-tests-macros) | ||
| 367 | (kmacro-tests-simulate-command '(kmacro-start-macro 1)) | ||
| 368 | (kmacro-tests-simulate-command '(kmacro-end-macro nil)) | ||
| 369 | ;; Check that execute and display do nothing with no 2nd macro. | ||
| 370 | (kmacro-tests-should-insert "" | ||
| 371 | (kmacro-tests-simulate-command '(kmacro-call-ring-2nd nil))) | ||
| 372 | (kmacro-tests-should-match-message "Only one keyboard macro defined" | ||
| 373 | (kmacro-tests-simulate-command '(kmacro-view-ring-2nd))) | ||
| 374 | ;; Record another one, with format. | ||
| 375 | (kmacro-set-format "=%d=") | ||
| 376 | (kmacro-tests-define-macro (vconcat "bar")) | ||
| 377 | ;; Execute the first one, mocked up to insert counter. | ||
| 378 | ;; Should get default format. | ||
| 379 | (kmacro-tests-should-insert "11" | ||
| 380 | (kmacro-tests-simulate-command '(kmacro-call-ring-2nd nil))) | ||
| 381 | ;; Now display the 2nd ring macro and check result. | ||
| 382 | (kmacro-tests-should-match-message "C-c x i C-u C-c x i" | ||
| 383 | (kmacro-view-ring-2nd))) | ||
| 384 | |||
| 385 | (kmacro-tests-deftest kmacro-tests-fill-ring-and-rotate () | ||
| 386 | "Macro ring can shift one way, shift the other way, swap and pop." | ||
| 387 | (cl-letf ((kmacro-ring-max 4)) | ||
| 388 | ;; Record enough macros that the first one drops off the history. | ||
| 389 | (dotimes (n (1+ kmacro-ring-max)) | ||
| 390 | (kmacro-tests-define-macro (make-vector (1+ n) (+ ?a n)))) | ||
| 391 | ;; Cycle the ring and check that #2 comes up. | ||
| 392 | (kmacro-tests-should-match-message "2*b" | ||
| 393 | (kmacro-tests-simulate-command '(kmacro-cycle-ring-next nil))) | ||
| 394 | ;; Execute the current macro and check arguments. | ||
| 395 | (kmacro-tests-should-insert "bbbb" | ||
| 396 | (kmacro-call-macro 2 t)) | ||
| 397 | ;; Cycle the ring the other way; #5 expected. | ||
| 398 | (kmacro-tests-should-match-message "5*e" (kmacro-cycle-ring-previous nil)) | ||
| 399 | ;; Swapping the top two should give #4. | ||
| 400 | (kmacro-tests-should-match-message "4*d" (kmacro-swap-ring)) | ||
| 401 | ;; Delete the top and expect #5. | ||
| 402 | (kmacro-tests-should-match-message "5*e" (kmacro-delete-ring-head)))) | ||
| 403 | |||
| 404 | |||
| 405 | (kmacro-tests-deftest kmacro-tests-test-ring-commands-when-no-macros () | ||
| 406 | "Ring commands give appropriate message when no macros exist." | ||
| 407 | (dolist (cmd '((kmacro-cycle-ring-next nil) | ||
| 408 | (kmacro-cycle-ring-previous nil) | ||
| 409 | (kmacro-swap-ring) | ||
| 410 | (kmacro-delete-ring-head) | ||
| 411 | (kmacro-view-ring-2nd) | ||
| 412 | (kmacro-call-ring-2nd nil) | ||
| 413 | (kmacro-view-macro))) | ||
| 414 | (kmacro-tests-should-match-message "No keyboard macro defined" | ||
| 415 | (kmacro-tests-simulate-command cmd)))) | ||
| 416 | |||
| 417 | (kmacro-tests-deftest kmacro-tests-repeat-on-last-key () | ||
| 418 | "Kmacro commands can be run in sequence without prefix keys." | ||
| 419 | (let* ((prefix (where-is-internal 'kmacro-keymap nil t)) | ||
| 420 | ;; Make a sequence of events to run. | ||
| 421 | ;; Comments are expected output of mock macros | ||
| 422 | ;; on the first and second run of the sequence (see below). | ||
| 423 | (events (mapcar #'kmacro-tests-get-kmacro-key | ||
| 424 | '(kmacro-end-or-call-macro-repeat ;c / b | ||
| 425 | kmacro-end-or-call-macro-repeat ;c / b | ||
| 426 | kmacro-call-ring-2nd-repeat ;b / a | ||
| 427 | kmacro-cycle-ring-next | ||
| 428 | kmacro-end-or-call-macro-repeat ;a / a | ||
| 429 | kmacro-cycle-ring-previous | ||
| 430 | kmacro-end-or-call-macro-repeat ;c / b | ||
| 431 | kmacro-delete-ring-head | ||
| 432 | kmacro-end-or-call-macro-repeat ;b / a | ||
| 433 | ))) | ||
| 434 | (kmacro-tests-macros (list [?a] [?b] [?c])) | ||
| 435 | ;; What we want kmacro to see as keyboard command sequence | ||
| 436 | (first-event (seq-concatenate | ||
| 437 | 'vector | ||
| 438 | prefix | ||
| 439 | (vector (kmacro-tests-get-kmacro-key | ||
| 440 | 'kmacro-end-or-call-macro-repeat))))) | ||
| 441 | (cl-letf | ||
| 442 | ;; standardize repeat options | ||
| 443 | ((kmacro-repeat-no-prefix t) | ||
| 444 | (kmacro-call-repeat-key t) | ||
| 445 | (kmacro-call-repeat-with-arg nil)) | ||
| 446 | ;; "Record" two macros | ||
| 447 | (dotimes (_n 2) | ||
| 448 | (kmacro-tests-simulate-command '(kmacro-start-macro nil)) | ||
| 449 | (kmacro-tests-simulate-command '(kmacro-end-macro nil))) | ||
| 450 | ;; Start recording #3 | ||
| 451 | (kmacro-tests-simulate-command '(kmacro-start-macro nil)) | ||
| 452 | |||
| 453 | ;; Set up pending keyboard events and a fresh buffer | ||
| 454 | ;; kmacro-set-counter is not one of the repeating kmacro | ||
| 455 | ;; commands so it should end the sequence. | ||
| 456 | (let* ((end-key (kmacro-tests-get-kmacro-key 'kmacro-set-counter)) | ||
| 457 | (kmacro-tests-events (append events (list end-key)))) | ||
| 458 | (cl-letf (((symbol-function #'this-single-command-keys) | ||
| 459 | (lambda () first-event))) | ||
| 460 | (use-local-map kmacro-tests-keymap) | ||
| 461 | (kmacro-tests-should-insert "ccbacb" | ||
| 462 | ;; End #3 and launch loop to read events. | ||
| 463 | (kmacro-end-or-call-macro-repeat nil)))) | ||
| 464 | |||
| 465 | ;; `kmacro-edit-macro-repeat' should also stop the sequence, | ||
| 466 | ;; so run it again with that at the end. | ||
| 467 | (let* ((end-key (kmacro-tests-get-kmacro-key 'kmacro-edit-macro-repeat)) | ||
| 468 | (kmacro-tests-events (append events (list end-key)))) | ||
| 469 | (cl-letf (((symbol-function #'edit-kbd-macro) #'ignore) | ||
| 470 | ((symbol-function #'this-single-command-keys) | ||
| 471 | (lambda () first-event))) | ||
| 472 | (use-local-map kmacro-tests-keymap) | ||
| 473 | (kmacro-tests-should-insert "bbbbbaaba" | ||
| 474 | (kmacro-end-or-call-macro-repeat 3))))))) | ||
| 475 | |||
| 476 | (kmacro-tests-deftest kmacro-tests-repeat-view-and-run () | ||
| 477 | "Kmacro view cycles through ring and executes macro just viewed." | ||
| 478 | (let* ((prefix (where-is-internal 'kmacro-keymap nil t)) | ||
| 479 | (kmacro-tests-events | ||
| 480 | (mapcar #'kmacro-tests-get-kmacro-key | ||
| 481 | (append (make-list 5 'kmacro-view-macro-repeat) | ||
| 482 | '(kmacro-end-or-call-macro-repeat | ||
| 483 | kmacro-set-counter)))) | ||
| 484 | ;; Make kmacro see this as keyboard command sequence. | ||
| 485 | (first-event (seq-concatenate | ||
| 486 | 'vector | ||
| 487 | prefix | ||
| 488 | (vector (kmacro-tests-get-kmacro-key | ||
| 489 | 'kmacro-view-macro-repeat)))) | ||
| 490 | ;; Construct a regexp to match the messages which should be | ||
| 491 | ;; produced by repeated view-repeats. | ||
| 492 | (macros-regexp (apply #'concat | ||
| 493 | (mapcar (lambda (c) (format ".+%s\n" c)) | ||
| 494 | '("d" "c" "b" "a" "d" "c"))))) | ||
| 495 | (cl-letf ((kmacro-repeat-no-prefix t) | ||
| 496 | (kmacro-call-repeat-key t) | ||
| 497 | (kmacro-call-repeat-with-arg nil) | ||
| 498 | ((symbol-function #'this-single-command-keys) (lambda () | ||
| 499 | first-event))) | ||
| 500 | ;; "Record" some macros. | ||
| 501 | (dotimes (n 4) | ||
| 502 | (kmacro-tests-define-macro (make-vector 1 (+ ?a n)))) | ||
| 503 | |||
| 504 | (use-local-map kmacro-tests-keymap) | ||
| 505 | ;; 6 views (the direct call plus the 5 in events) should | ||
| 506 | ;; cycle through the ring and get to the second-to-last | ||
| 507 | ;; macro defined. | ||
| 508 | (kmacro-tests-should-insert "c" | ||
| 509 | (kmacro-tests-should-match-message macros-regexp | ||
| 510 | (kmacro-tests-simulate-command '(kmacro-view-macro-repeat nil))))))) | ||
| 511 | |||
| 512 | (kmacro-tests-deftest kmacro-tests-bind-to-key-when-recording () | ||
| 513 | "Bind to key doesn't bind a key during macro recording." | ||
| 514 | (cl-letf ((global-map global-map) | ||
| 515 | (saved-binding (key-binding "\C-a")) | ||
| 516 | (kmacro-tests-sequences (list "\C-a"))) | ||
| 517 | (kmacro-tests-simulate-command '(kmacro-start-macro 1)) | ||
| 518 | (kmacro-bind-to-key nil) | ||
| 519 | (should (eq saved-binding (key-binding "\C-a"))))) | ||
| 520 | |||
| 521 | (kmacro-tests-deftest kmacro-tests-name-or-bind-to-key-when-no-macro () | ||
| 522 | "Bind to key, symbol or register fails when when no macro exists." | ||
| 523 | (should-error (kmacro-bind-to-key nil)) | ||
| 524 | (should-error (kmacro-name-last-macro 'kmacro-tests-symbol-for-test)) | ||
| 525 | (should-error (kmacro-to-register))) | ||
| 526 | |||
| 527 | (kmacro-tests-deftest kmacro-tests-bind-to-key-bad-key-sequence () | ||
| 528 | "Bind to key fails to bind to ^G." | ||
| 529 | (let ((global-map global-map) | ||
| 530 | (saved-binding (key-binding "\C-g")) | ||
| 531 | (kmacro-tests-sequences (list "\C-g"))) | ||
| 532 | (kmacro-tests-define-macro [1]) | ||
| 533 | (kmacro-bind-to-key nil) | ||
| 534 | (should (eq saved-binding (key-binding "\C-g"))))) | ||
| 535 | |||
| 536 | (kmacro-tests-deftest kmacro-tests-bind-to-key-with-key-sequence-in-use () | ||
| 537 | "Bind to key respects yes-or-no-p when given already bound key sequence." | ||
| 538 | (kmacro-tests-define-macro (vconcat "abaab")) | ||
| 539 | (let ((global-map global-map) | ||
| 540 | (map (make-sparse-keymap)) | ||
| 541 | (kmacro-tests-sequences (make-list 2 "\C-hi"))) | ||
| 542 | (define-key map "\C-hi" 'info) | ||
| 543 | (use-local-map map) | ||
| 544 | ;; Try the command with yes-or-no-p set up to say no. | ||
| 545 | (cl-letf (((symbol-function #'yes-or-no-p) | ||
| 546 | (lambda (prompt) | ||
| 547 | (should (string-match-p "info" prompt)) | ||
| 548 | (should (string-match-p "C-h i" prompt)) | ||
| 549 | nil))) | ||
| 550 | (kmacro-bind-to-key nil)) | ||
| 551 | |||
| 552 | (should (equal (where-is-internal 'info nil t) | ||
| 553 | (vconcat "\C-hi"))) | ||
| 554 | ;; Try it again with yes. | ||
| 555 | (cl-letf (((symbol-function #' yes-or-no-p) | ||
| 556 | (lambda (_prompt) t))) | ||
| 557 | (kmacro-bind-to-key nil)) | ||
| 558 | |||
| 559 | (should-not (equal (where-is-internal 'info global-map t) | ||
| 560 | (vconcat "\C-hi"))) | ||
| 561 | (use-local-map nil) | ||
| 562 | (kmacro-tests-should-insert "abaab" | ||
| 563 | (funcall (key-binding "\C-hi"))))) | ||
| 564 | |||
| 565 | (kmacro-tests-deftest kmacro-tests-kmacro-bind-to-single-key () | ||
| 566 | "Bind to key uses C-x C-k A when asked to bind to A." | ||
| 567 | (let ((global-map global-map) | ||
| 568 | (kmacro-tests-macros (list (string-to-vector "\C-cxi")))) | ||
| 569 | (use-local-map kmacro-tests-keymap) | ||
| 570 | |||
| 571 | ;; Record a macro with counter and format set. | ||
| 572 | (kmacro-set-format "<%d>") | ||
| 573 | (kmacro-tests-simulate-command '(kmacro-start-macro-or-insert-counter 5)) | ||
| 574 | (kmacro-tests-simulate-command '(kmacro-end-macro nil)) | ||
| 575 | |||
| 576 | (let ((kmacro-tests-sequences (list "A"))) | ||
| 577 | (kmacro-bind-to-key nil)) | ||
| 578 | |||
| 579 | ;; Record a second macro with different counter and format. | ||
| 580 | (kmacro-set-format "%d") | ||
| 581 | (kmacro-tests-define-macro [2]) | ||
| 582 | |||
| 583 | ;; Check the bound key and run it and verify correct counter | ||
| 584 | ;; and format. | ||
| 585 | (should (equal (string-to-vector "\C-cxi") | ||
| 586 | (car (kmacro-extract-lambda | ||
| 587 | (key-binding "\C-x\C-kA"))))) | ||
| 588 | (kmacro-tests-should-insert "<5>" | ||
| 589 | (funcall (key-binding "\C-x\C-kA"))))) | ||
| 590 | |||
| 591 | (kmacro-tests-deftest kmacro-tests-name-last-macro-unable-to-bind () | ||
| 592 | "Name last macro won't bind to symbol which is already bound." | ||
| 593 | (kmacro-tests-define-macro [1]) | ||
| 594 | ;; Set up a test symbol which looks like a function. | ||
| 595 | (setplist 'kmacro-tests-symbol-for-test nil) | ||
| 596 | (fset 'kmacro-tests-symbol-for-test #'ignore) | ||
| 597 | (should-error (kmacro-name-last-macro 'kmacro-tests-symbol-for-test)) | ||
| 598 | ;; The empty string symbol also can't be bound. | ||
| 599 | (should-error (kmacro-name-last-macro (make-symbol "")))) | ||
| 600 | |||
| 601 | (kmacro-tests-deftest kmacro-tests-name-last-macro-bind-and-rebind () | ||
| 602 | "Name last macro can rebind a symbol it binds." | ||
| 603 | ;; Make sure our symbol is unbound. | ||
| 604 | (when (fboundp 'kmacro-tests-symbol-for-test) | ||
| 605 | (fmakunbound 'kmacro-tests-symbol-for-test)) | ||
| 606 | (setplist 'kmacro-tests-symbol-for-test nil) | ||
| 607 | ;; Make two macros and bind them to the same symbol. | ||
| 608 | (dotimes (i 2) | ||
| 609 | (kmacro-tests-define-macro (make-vector (1+ i) (+ ?a i))) | ||
| 610 | (kmacro-name-last-macro 'kmacro-tests-symbol-for-test) | ||
| 611 | (should (fboundp 'kmacro-tests-symbol-for-test))) | ||
| 612 | |||
| 613 | ;; Now run the function bound to the symbol. Result should be the | ||
| 614 | ;; second macro. | ||
| 615 | (kmacro-tests-should-insert "bb" | ||
| 616 | (kmacro-tests-simulate-command '(kmacro-tests-symbol-for-test)))) | ||
| 617 | |||
| 618 | (kmacro-tests-deftest kmacro-tests-store-in-register () | ||
| 619 | "Macro can be stored in and retrieved from a register." | ||
| 620 | (use-local-map kmacro-tests-keymap) | ||
| 621 | ;; Save and restore register 200 so we can use it for the test. | ||
| 622 | (let ((saved-reg-contents (get-register 200))) | ||
| 623 | (unwind-protect | ||
| 624 | (progn | ||
| 625 | ;; Define a macro, and save it to a register. | ||
| 626 | (kmacro-tests-define-macro (vconcat "a\C-a\C-cxu")) | ||
| 627 | (kmacro-to-register 200) | ||
| 628 | ;; Then make a new different macro. | ||
| 629 | (kmacro-tests-define-macro (vconcat "bb\C-a\C-cxu")) | ||
| 630 | ;; When called from the register, result should be first macro. | ||
| 631 | (kmacro-tests-should-insert "AAA" | ||
| 632 | (kmacro-tests-simulate-command '(jump-to-register 200 3) 3)) | ||
| 633 | (kmacro-tests-should-insert "a C-a C-c x u" | ||
| 634 | (kmacro-tests-simulate-command '(insert-register 200 t) '(4)))) | ||
| 635 | (set-register 200 saved-reg-contents)))) | ||
| 636 | |||
| 637 | (kmacro-tests-deftest kmacro-tests-step-edit-act () | ||
| 638 | "Step-edit steps-through a macro with act and act-repeat." | ||
| 639 | (kmacro-tests-run-step-edit "he\C-u2lo" | ||
| 640 | :events (make-list 6 'act) | ||
| 641 | :result "hello" | ||
| 642 | :macro-result "he\C-u2lo") | ||
| 643 | |||
| 644 | (kmacro-tests-run-step-edit "f\C-aoo\C-abar" | ||
| 645 | :events (make-list 5 'act-repeat) | ||
| 646 | :result "baroof" | ||
| 647 | :macro-result "f\C-aoo\C-abar")) | ||
| 648 | |||
| 649 | (kmacro-tests-deftest kmacro-tests-step-edit-skip () | ||
| 650 | "Step-editing can skip parts of macro." | ||
| 651 | (kmacro-tests-run-step-edit "ofoofff" | ||
| 652 | :events '(skip skip-keep skip-keep skip-keep | ||
| 653 | skip-rest) | ||
| 654 | :result "" | ||
| 655 | :macro-result "foo")) | ||
| 656 | |||
| 657 | (kmacro-tests-deftest kmacro-tests-step-edit-quit () | ||
| 658 | "Quit while step-editing leaves macro unchanged." | ||
| 659 | (kmacro-tests-run-step-edit "bar" | ||
| 660 | :events '(help insert skip help quit) | ||
| 661 | :sequences '("f" "o" "o" "\C-j") | ||
| 662 | :result "foo" | ||
| 663 | :macro-result "bar")) | ||
| 664 | |||
| 665 | (kmacro-tests-deftest kmacro-tests-step-insert () | ||
| 666 | "Step edit can insert in macro." | ||
| 667 | (kmacro-tests-run-step-edit "fbazbop" | ||
| 668 | :events '(insert act insert-1 act-repeat) | ||
| 669 | :sequences '("o" "o" "\C-a" "\C-j" "\C-e") | ||
| 670 | :result "foobazbop" | ||
| 671 | :macro-result "oo\C-af\C-ebazbop")) | ||
| 672 | |||
| 673 | (kmacro-tests-deftest kmacro-tests-step-edit-replace-digit-argument () | ||
| 674 | "Step-edit replace can replace a numeric argument in a macro. | ||
| 675 | This is a regression for item 1 in Bug#24991." | ||
| 676 | (:expected-result :failed) | ||
| 677 | (kmacro-tests-run-step-edit "\C-u3b\C-a\C-cxu" | ||
| 678 | :events '(act replace automatic) | ||
| 679 | :sequences '("8" "x" "\C-j") | ||
| 680 | :result "XXXXXXXX" | ||
| 681 | :macro-result "\C-u8x\C-a\C-cxu")) | ||
| 682 | |||
| 683 | (kmacro-tests-deftest kmacro-tests-step-edit-replace () | ||
| 684 | "Step-edit replace and replace-1 can replace parts of a macro." | ||
| 685 | (kmacro-tests-run-step-edit "a\C-a\C-cxu" | ||
| 686 | :events '(act act replace) | ||
| 687 | :sequences '("b" "c" "\C-j") | ||
| 688 | :result "bca" | ||
| 689 | :macro-result "a\C-abc") | ||
| 690 | (kmacro-tests-run-step-edit "a\C-a\C-cxucd" | ||
| 691 | :events '(act replace-1 automatic) | ||
| 692 | :sequences '("b") | ||
| 693 | :result "abcd" | ||
| 694 | :macro-result "ab\C-cxucd") | ||
| 695 | (kmacro-tests-run-step-edit "by" | ||
| 696 | :events '(act replace) | ||
| 697 | :sequences '("a" "r" "\C-j") | ||
| 698 | :result "bar" | ||
| 699 | :macro-result "bar")) | ||
| 700 | |||
| 701 | (kmacro-tests-deftest kmacro-tests-step-edit-append () | ||
| 702 | "Step edit append inserts after point, and append-end inserts at end." | ||
| 703 | (kmacro-tests-run-step-edit "f-b" | ||
| 704 | :events '(append append-end) | ||
| 705 | :sequences '("o" "o" "\C-j" "a" "r" "\C-j") | ||
| 706 | :result "foo-bar" | ||
| 707 | :macro-result "foo-bar") | ||
| 708 | (kmacro-tests-run-step-edit "x" | ||
| 709 | :events '(append) | ||
| 710 | :sequences '("\C-a" "\C-cxu" "\C-e" "y" "\C-j") | ||
| 711 | :result "Xy" | ||
| 712 | :macro-result "x\C-a\C-cxu\C-ey")) | ||
| 713 | |||
| 714 | (kmacro-tests-deftest kmacro-tests-append-end-at-end-appends () | ||
| 715 | "Append-end when already at end of macro appends to end of macro. | ||
| 716 | This is a regression for item 2 in Bug#24991." | ||
| 717 | (:expected-result :failed) | ||
| 718 | (kmacro-tests-run-step-edit "x" | ||
| 719 | :events '(append-end) | ||
| 720 | :sequences '("\C-a" "\C-cxu" "\C-e" "y" "\C-j") | ||
| 721 | :result "Xy" | ||
| 722 | :macro-result "x\C-a\C-cxu\C-ey")) | ||
| 723 | |||
| 724 | |||
| 725 | (kmacro-tests-deftest kmacro-tests-step-edit-skip-entire () | ||
| 726 | "Skipping a whole macro in step-edit leaves macro unchanged. | ||
| 727 | This is a regression for item 3 in Bug#24991." | ||
| 728 | (:expected-result :failed) | ||
| 729 | (kmacro-tests-run-step-edit "xyzzy" | ||
| 730 | :events '(skip-rest) | ||
| 731 | :result "" | ||
| 732 | :macro-result "xyzzy")) | ||
| 733 | |||
| 734 | (kmacro-tests-deftest kmacro-tests-step-edit-step-through-negative-argument () | ||
| 735 | "Step edit works on macros using negative universal argument. | ||
| 736 | This is a regression for item 4 in Bug#24991." | ||
| 737 | (:expected-result :failed) | ||
| 738 | (kmacro-tests-run-step-edit "boo\C-u-\C-cu" | ||
| 739 | :events '(act-repeat automatic) | ||
| 740 | :result "BOO" | ||
| 741 | :macro-result "boo\C-u-\C-cd")) | ||
| 742 | |||
| 743 | (kmacro-tests-deftest kmacro-tests-step-edit-with-quoted-insert () | ||
| 744 | "Stepping through a macro that uses quoted insert leaves macro unchanged. | ||
| 745 | This is a regression for item 5 in Bug#24991." | ||
| 746 | (:expected-result :failed) | ||
| 747 | (let ((read-quoted-char-radix 8)) | ||
| 748 | (kmacro-tests-run-step-edit "\C-cxq17051i there" | ||
| 749 | :events '(act automatic) | ||
| 750 | :result "ḩi there" | ||
| 751 | :macro-result "\C-cxq17051i there") | ||
| 752 | (kmacro-tests-run-step-edit "g\C-cxq17051i" | ||
| 753 | :events '(act insert-1 automatic) | ||
| 754 | :sequences '("-") | ||
| 755 | :result "g-ḩi" | ||
| 756 | :macro-result "g-\C-cxq17051i"))) | ||
| 757 | |||
| 758 | (kmacro-tests-deftest kmacro-tests-step-edit-can-replace-meta-keys () | ||
| 759 | "Replacing C-w with M-w produces the expected result. | ||
| 760 | This is a regression for item 7 in Bug#24991." | ||
| 761 | (:expected-result :failed) | ||
| 762 | (kmacro-tests-run-step-edit "abc\C-b\C-b\C-SPC\C-f\C-w\C-e\C-y" | ||
| 763 | :events '(act-repeat act-repeat | ||
| 764 | act-repeat act-repeat | ||
| 765 | replace automatic) | ||
| 766 | :sequences '("\M-w" "\C-j") | ||
| 767 | :result "abcb" | ||
| 768 | :macro-result "abc\C-b\C-b\C-SPC\C-f\M-w\C-e\C-y") | ||
| 769 | (kmacro-tests-should-insert "abcb" (kmacro-call-macro nil))) | ||
| 770 | |||
| 771 | (kmacro-tests-deftest kmacro-tests-step-edit-ignores-qr-map-commands () | ||
| 772 | "Unimplemented commands from `query-replace-map' are ignored." | ||
| 773 | (kmacro-tests-run-step-edit "yep" | ||
| 774 | :events '(edit-replacement | ||
| 775 | act-and-show act-and-exit | ||
| 776 | delete-and-edit | ||
| 777 | recenter backup | ||
| 778 | scroll-up scroll-down | ||
| 779 | scroll-other-window | ||
| 780 | scroll-other-window-down | ||
| 781 | exit-prefix | ||
| 782 | act act act) | ||
| 783 | :result "yep" | ||
| 784 | :macro-result "yep")) | ||
| 785 | |||
| 786 | (kmacro-tests-deftest | ||
| 787 | kmacro-tests-step-edit-edits-macro-with-extended-command () | ||
| 788 | "Step-editing a macro which uses the minibuffer can change the macro." | ||
| 789 | (let ((mac (vconcat [?\M-x] "eval-expression" '[return] | ||
| 790 | "(insert-char (+ ?a \C-e" [?1] "))" '[return])) | ||
| 791 | (mac-after (vconcat [?\M-x] "eval-expression" '[return] | ||
| 792 | "(insert-char (+ ?a \C-e" [?2] "))" '[return]))) | ||
| 793 | |||
| 794 | (kmacro-tests-run-step-edit mac | ||
| 795 | :events '(act act-repeat | ||
| 796 | act act-repeat act | ||
| 797 | replace-1 act-repeat act) | ||
| 798 | :sequences '("2") | ||
| 799 | :result "c" | ||
| 800 | :macro-result mac-after))) | ||
| 801 | |||
| 802 | (kmacro-tests-deftest kmacro-tests-step-edit-step-through-isearch () | ||
| 803 | "Step-editing can edit a macro which uses `isearch-backward' (Bug#22488)." | ||
| 804 | (:expected-result :failed) | ||
| 805 | (let ((mac (vconcat "test Input" '[return] | ||
| 806 | [?\C-r] "inp" '[return] "\C-cxu")) | ||
| 807 | (mac-after (vconcat "test input" '[return] | ||
| 808 | [?\C-r] "inp" '[return] "\C-cd"))) | ||
| 809 | |||
| 810 | (kmacro-tests-run-step-edit mac | ||
| 811 | :events '(act-repeat act act | ||
| 812 | act-repeat act | ||
| 813 | replace-1) | ||
| 814 | :sequences '("\C-cd") | ||
| 815 | :result "test input\n" | ||
| 816 | :macro-result mac-after))) | ||
| 817 | |||
| 818 | (kmacro-tests-deftest kmacro-tests-step-edit-cleans-up-hook () | ||
| 819 | "Step-editing properly cleans up `post-command-hook.' (Bug #18708)" | ||
| 820 | (:expected-result :failed) | ||
| 821 | (let (post-command-hook) | ||
| 822 | (setq-local post-command-hook '(t)) | ||
| 823 | (kmacro-tests-run-step-edit "x" | ||
| 824 | :events '(act) | ||
| 825 | :result "x" | ||
| 826 | :macro-result "x") | ||
| 827 | (kmacro-tests-simulate-command '(beginning-of-line)))) | ||
| 828 | |||
| 829 | (cl-defun kmacro-tests-run-step-edit | ||
| 830 | (macro &key events sequences result macro-result) | ||
| 831 | "Set up and run a test of `kmacro-step-edit-macro'. | ||
| 832 | |||
| 833 | Run `kmacro-step-edit-macro' with MACRO defined as a keyboard macro | ||
| 834 | and `read-event' and `read-key-sequence' set up to return items from | ||
| 835 | EVENTS and SEQUENCES respectively. SEQUENCES may be nil, but | ||
| 836 | EVENTS should not be. EVENTS should be a list of symbols bound | ||
| 837 | in `kmacro-step-edit-map' or `query-replace' map, and this function | ||
| 838 | will do the keymap lookup for you. SEQUENCES should contain | ||
| 839 | return values for `read-key-sequence'. | ||
| 840 | |||
| 841 | Before running the macro, the current buffer will be erased. | ||
| 842 | RESULT is the string that should be inserted during the | ||
| 843 | step-editing process, and MACRO-RESULT is the expected value of | ||
| 844 | `last-kbd-macro' after the editing is complete." | ||
| 845 | |||
| 846 | (let* ((kmacro-tests-events (mapcar #'kmacro-tests-get-kmacro-step-edit-key events)) | ||
| 847 | (kmacro-tests-sequences sequences)) | ||
| 848 | |||
| 849 | (kmacro-tests-define-macro (string-to-vector macro)) | ||
| 850 | (use-local-map kmacro-tests-keymap) | ||
| 851 | (erase-buffer) | ||
| 852 | (kmacro-step-edit-macro) | ||
| 853 | (when result | ||
| 854 | (should (equal result (buffer-string)))) | ||
| 855 | (when macro-result | ||
| 856 | (should (equal last-kbd-macro (string-to-vector macro-result)))))) | ||
| 857 | |||
| 858 | ;;; Utilities: | ||
| 859 | |||
| 860 | (defun kmacro-tests-simulate-command (command &optional arg) | ||
| 861 | "Call `ert-simulate-command' after setting `current-prefix-arg'. | ||
| 862 | Sets `current-prefix-arg' to ARG if it is non-nil, otherwise to | ||
| 863 | the second element of COMMAND, before executing COMMAND using | ||
| 864 | `ert-simulate-command'." | ||
| 865 | (let ((current-prefix-arg (or arg (cadr command)))) | ||
| 866 | (ert-simulate-command command))) | ||
| 867 | |||
| 868 | (defun kmacro-tests-define-macro (mac) | ||
| 869 | "Define MAC as a keyboard macro using kmacro commands." | ||
| 870 | (push mac kmacro-tests-macros) | ||
| 871 | (kmacro-tests-simulate-command '(kmacro-start-macro nil)) | ||
| 872 | (should defining-kbd-macro) | ||
| 873 | (kmacro-tests-simulate-command '(kmacro-end-macro nil)) | ||
| 874 | (should (equal mac last-kbd-macro))) | ||
| 875 | |||
| 876 | (defun kmacro-tests-get-kmacro-key (sym) | ||
| 877 | "Look up kmacro command SYM in kmacro's keymap. | ||
| 878 | Return the integer key value found." | ||
| 879 | (aref (where-is-internal sym kmacro-keymap t) 0)) | ||
| 880 | |||
| 881 | (defun kmacro-tests-get-kmacro-step-edit-key (sym) | ||
| 882 | "Return the first key bound to SYM in `kmacro-step-edit-map'." | ||
| 883 | (let ((where (aref (where-is-internal sym kmacro-step-edit-map t) 0))) | ||
| 884 | (if (consp where) | ||
| 885 | (car where) | ||
| 886 | where))) | ||
| 887 | |||
| 888 | (provide 'kmacro-tests) | ||
| 889 | |||
| 890 | ;;; kmacro-tests.el ends here | ||