1 ;;; yasnippet-tests.el --- some yasnippet tests -*- lexical-binding: t -*-
3 ;; Copyright (C) 2012, 2013, 2014, 2015 Free Software Foundation, Inc.
5 ;; Author: João Távora <joaot@siscog.pt>
6 ;; Keywords: emulations, convenience
8 ;; This program is free software; you can redistribute it and/or modify
9 ;; it under the terms of the GNU General Public License as published by
10 ;; the Free Software Foundation, either version 3 of the License, or
11 ;; (at your option) any later version.
13 ;; This program is distributed in the hope that it will be useful,
14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ;; GNU General Public License for more details.
18 ;; You should have received a copy of the GNU General Public License
19 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
23 ;; Test basic snippet mechanics and the loading system
35 (defun yas--buffer-contents ()
36 (buffer-substring-no-properties (point-min) (point-max)))
38 (ert-deftest field-navigation ()
41 (yas-expand-snippet "${1:brother} from another ${2:mother}")
42 (should (string= (yas--buffer-contents)
43 "brother from another mother"))
45 (should (looking-at "brother"))
46 (ert-simulate-command '(yas-next-field-or-maybe-expand))
47 (should (looking-at "mother"))
48 (ert-simulate-command '(yas-prev-field))
49 (should (looking-at "brother"))))
51 (ert-deftest simple-mirror ()
54 (yas-expand-snippet "${1:brother} from another $1")
55 (should (string= (yas--buffer-contents)
56 "brother from another brother"))
57 (yas-mock-insert "bla")
58 (should (string= (yas--buffer-contents)
59 "bla from another bla"))))
61 (ert-deftest mirror-with-transformation ()
64 (yas-expand-snippet "${1:brother} from another ${1:$(upcase yas-text)}")
65 (should (string= (yas--buffer-contents)
66 "brother from another BROTHER"))
67 (yas-mock-insert "bla")
68 (should (string= (yas--buffer-contents)
69 "bla from another BLA"))))
71 (ert-deftest mirror-with-transformation-and-autofill ()
72 "Test interaction of autofill with mirror transforms"
73 (let ((words "one two three four five")
76 (c-mode) ; In `c-mode' filling comments works by narrowing.
80 (yas-expand-snippet "/* $0\n */")
81 (yas-mock-insert words)
82 (setq filled-words (delete-and-extract-region (point-min) (point-max)))
83 (yas-expand-snippet "/* $1\n */\n$2$2")
84 (should (string= (yas--buffer-contents)
86 (yas-mock-insert words)
87 (should (string= (yas--buffer-contents)
88 (concat filled-words "\n"))))))
91 (ert-deftest primary-field-transformation ()
94 (let ((snippet "${1:$$(upcase yas-text)}${1:$(concat \"bar\" yas-text)}"))
95 (yas-expand-snippet snippet)
96 (should (string= (yas--buffer-contents) "bar"))
97 (yas-mock-insert "foo")
98 (should (string= (yas--buffer-contents) "FOObarFOO")))))
100 (ert-deftest nested-placeholders-kill-superfield ()
103 (yas-expand-snippet "brother from ${2:another ${3:mother}}!")
104 (should (string= (yas--buffer-contents)
105 "brother from another mother!"))
106 (yas-mock-insert "bla")
107 (should (string= (yas--buffer-contents)
108 "brother from bla!"))))
110 (ert-deftest nested-placeholders-use-subfield ()
113 (yas-expand-snippet "brother from ${2:another ${3:mother}}!")
114 (ert-simulate-command '(yas-next-field-or-maybe-expand))
115 (yas-mock-insert "bla")
116 (should (string= (yas--buffer-contents)
117 "brother from another bla!"))))
119 (ert-deftest mirrors-adjacent-to-fields-with-nested-mirrors ()
122 (yas-expand-snippet "<%= f.submit \"${1:Submit}\"${2:$(and (yas-text) \", :disable_with => '\")}${2:$1ing...}${2:$(and (yas-text) \"'\")} %>")
123 (should (string= (yas--buffer-contents)
124 "<%= f.submit \"Submit\", :disable_with => 'Submiting...' %>"))
125 (yas-mock-insert "Send")
126 (should (string= (yas--buffer-contents)
127 "<%= f.submit \"Send\", :disable_with => 'Sending...' %>"))))
129 (ert-deftest deep-nested-mirroring-issue-351 ()
132 (yas-expand-snippet "${1:FOOOOOOO}${2:$1}${3:$2}${4:$3}")
133 (yas-mock-insert "abc")
134 (should (string= (yas--buffer-contents) "abcabcabcabc"))))
136 (ert-deftest delete-numberless-inner-snippet-issue-562 ()
139 (yas-expand-snippet "${3:${test}bla}$0${2:ble}")
140 (ert-simulate-command '(yas-next-field-or-maybe-expand))
141 (should (looking-at "testblable"))
142 (ert-simulate-command '(yas-next-field-or-maybe-expand))
143 (ert-simulate-command '(yas-skip-and-clear-or-delete-char))
144 (should (looking-at "ble"))
145 (should (null (yas--snippets-at-point)))))
147 (ert-deftest ignore-trailing-whitespace ()
150 (insert "# key: foo\n# --\nfoo")
151 (yas--parse-template))
153 (insert "# key: foo \n# --\nfoo")
154 (yas--parse-template)))))
156 ;; (ert-deftest in-snippet-undo ()
158 ;; (yas-minor-mode 1)
159 ;; (yas-expand-snippet "brother from ${2:another ${3:mother}}!")
160 ;; (ert-simulate-command '(yas-next-field-or-maybe-expand))
161 ;; (yas-mock-insert "bla")
162 ;; (ert-simulate-command '(undo))
163 ;; (should (string= (yas--buffer-contents)
164 ;; "brother from another mother!"))))
166 (ert-deftest dont-clear-on-partial-deletion-issue-515 ()
167 "Ensure fields are not cleared when user doesn't really mean to."
170 (yas-expand-snippet "my ${1:kid brother} from another ${2:mother}")
172 (ert-simulate-command '(kill-word 1))
173 (ert-simulate-command '(delete-char 1))
175 (should (string= (yas--buffer-contents)
176 "my brother from another mother"))
177 (should (looking-at "brother"))
179 (ert-simulate-command '(yas-next-field))
180 (should (looking-at "mother"))
181 (ert-simulate-command '(yas-prev-field))
182 (should (looking-at "brother"))))
184 (ert-deftest do-clear-on-yank-issue-515 ()
185 "A yank should clear an unmodified field."
188 (yas-expand-snippet "my ${1:kid brother} from another ${2:mother}")
189 (yas-mock-yank "little sibling")
190 (should (string= (yas--buffer-contents)
191 "my little sibling from another mother"))
192 (ert-simulate-command '(yas-next-field))
193 (ert-simulate-command '(yas-prev-field))
194 (should (looking-at "little sibling"))))
196 (ert-deftest basic-indentation ()
200 (set (make-local-variable 'yas-indent-line) 'auto)
201 (set (make-local-variable 'yas-also-auto-indent-first-line) t)
202 (yas-expand-snippet "def ${1:method}${2:(${3:args})}\n$0\nend")
203 ;; Note that empty line is not indented.
204 (should (string= "def method(args)
206 end" (buffer-string)))
207 (cl-loop repeat 3 do (ert-simulate-command '(yas-next-field)))
208 (yas-mock-insert (make-string (random 5) ?\ )) ; purposedly mess up indentation
209 (yas-expand-snippet "class << ${self}\n $0\nend")
210 (ert-simulate-command '(yas-next-field))
211 (should (string= "def method(args)
215 end" (buffer-string)))
216 (should (= 4 (current-column)))))
218 (ert-deftest navigate-a-snippet-with-multiline-mirrors-issue-665 ()
219 "In issue 665, a multi-line mirror is attempted.
221 Indentation doesn't (yet) happen on these mirrors, but let this
222 test guard against any misnavigations that might be introduced by
223 an incorrect implementation of mirror auto-indentation"
227 (yas-expand-snippet "def initialize(${1:params})\n$2${1:$(
228 mapconcat #'(lambda (arg)
229 (format \"@%s = %s\" arg arg))
230 (split-string yas-text \", \")
232 (yas-mock-insert "bla, ble, bli")
233 (ert-simulate-command '(yas-next-field))
234 (let ((expected (mapconcat #'identity
236 "[[:blank:]]*@ble = ble"
237 "[[:blank:]]*@bli = bli")
239 (should (looking-at expected))
240 (yas-mock-insert "blo")
241 (ert-simulate-command '(yas-prev-field))
242 (ert-simulate-command '(yas-next-field))
243 (should (looking-at (concat "blo" expected))))))
246 ;;; Snippet expansion and character escaping
247 ;;; Thanks to @zw963 (Billy) for the testing
249 (ert-deftest escape-dollar ()
252 (yas-expand-snippet "bla\\${1:bla}ble")
253 (should (string= (yas--buffer-contents) "bla${1:bla}ble"))))
255 (ert-deftest escape-closing-brace ()
258 (yas-expand-snippet "bla${1:bla\\}}ble")
259 (should (string= (yas--buffer-contents) "blabla}ble"))
260 (should (string= (yas-field-value 1) "bla}"))))
262 (ert-deftest escape-backslashes ()
265 (yas-expand-snippet "bla\\ble")
266 (should (string= (yas--buffer-contents) "bla\\ble"))))
268 (ert-deftest escape-backquotes ()
271 (yas-expand-snippet "bla`(upcase \"foo\\`bar\")`ble")
272 (should (string= (yas--buffer-contents) "blaFOO`BARble"))))
274 (ert-deftest escape-some-elisp-with-strings ()
275 "elisp with strings and unbalance parens inside it"
278 ;; The rules here is: to output a literal `"' you need to escape
279 ;; it with one backslash. You don't need to escape them in
281 (yas-expand-snippet "soon \\\"`(concat (upcase \"(my arms\")\"\\\" were all around her\")`")
282 (should (string= (yas--buffer-contents) "soon \"(MY ARMS\" were all around her"))))
284 (ert-deftest escape-some-elisp-with-backslashes ()
287 ;; And the rule here is: to output a literal `\' inside a string
288 ;; inside embedded elisp you need a total of six `\'
289 (yas-expand-snippet "bla`(upcase \"hey\\\\\\yo\")`ble")
290 (should (string= (yas--buffer-contents) "blaHEY\\YOble"))))
292 (ert-deftest be-careful-when-escaping-in-yas-selected-text ()
295 (let ((yas-selected-text "He\\\\o world!"))
296 (yas-expand-snippet "Look ma! `(yas-selected-text)`")
297 (should (string= (yas--buffer-contents) "Look ma! He\\\\o world!")))
298 (yas-exit-all-snippets)
300 (let ((yas-selected-text "He\"o world!"))
301 (yas-expand-snippet "Look ma! `(yas-selected-text)`")
302 (should (string= (yas--buffer-contents) "Look ma! He\"o world!")))
303 (yas-exit-all-snippets)
305 (let ((yas-selected-text "He\"\)\\o world!"))
306 (yas-expand-snippet "Look ma! `(yas-selected-text)`")
307 (should (string= (yas--buffer-contents) "Look ma! He\"\)\\o world!")))
308 (yas-exit-all-snippets)
311 (ert-deftest be-careful-when-escaping-in-yas-selected-text-2 ()
314 (let ((yas-selected-text "He)}o world!"))
315 (yas-expand-snippet "Look ma! ${1:`(yas-selected-text)`} OK?")
316 (should (string= (yas--buffer-contents) "Look ma! He)}o world! OK?")))))
318 (ert-deftest example-for-issue-271 ()
321 (let ((yas-selected-text "aaa")
322 (snippet "if ${1:condition}\n`yas-selected-text`\nelse\n$3\nend"))
323 (yas-expand-snippet snippet)
325 (yas-mock-insert "bbb")
326 (should (string= (yas--buffer-contents) "if condition\naaa\nelse\nbbb\nend")))))
328 (defmacro yas--with-font-locked-temp-buffer (&rest body)
329 "Like `with-temp-buffer', but ensure `font-lock-mode'."
330 (declare (indent 0) (debug t))
331 (let ((temp-buffer (make-symbol "temp-buffer")))
332 ;; NOTE: buffer name must not start with a space, otherwise
333 ;; `font-lock-mode' doesn't turn on.
334 `(let ((,temp-buffer (generate-new-buffer "*yas-temp*")))
335 (with-current-buffer ,temp-buffer
336 ;; pretend we're interactive so `font-lock-mode' turns on
337 (let ((noninteractive nil)
338 ;; turn on font locking after major mode change
339 (change-major-mode-after-body-hook #'font-lock-mode))
341 (progn (require 'font-lock)
342 ;; turn on font locking before major mode change
345 (and (buffer-name ,temp-buffer)
346 (kill-buffer ,temp-buffer))))))))
348 (defmacro yas-saving-variables (&rest body)
349 `(yas-call-with-saving-variables #'(lambda () ,@body)))
351 (defmacro yas-with-snippet-dirs (dirs &rest body)
352 (declare (indent defun))
353 `(yas-call-with-snippet-dirs ,dirs
357 (ert-deftest example-for-issue-474 ()
358 (yas--with-font-locked-temp-buffer
361 (insert "#include <foo>\n")
362 (let ((yas-good-grace nil)) (yas-expand-snippet "`\"TODO: \"`"))
363 (should (string= (yas--buffer-contents) "#include <foo>\nTODO: "))))
365 (ert-deftest example-for-issue-404 ()
366 (yas--with-font-locked-temp-buffer
369 (insert "#include <foo>\n")
370 (let ((yas-good-grace nil)) (yas-expand-snippet "main"))
371 (should (string= (yas--buffer-contents) "#include <foo>\nmain"))))
373 (ert-deftest example-for-issue-404-c-mode ()
374 (yas--with-font-locked-temp-buffer
377 (insert "#include <foo>\n")
378 (let ((yas-good-grace nil)) (yas-expand-snippet "main"))
379 (should (string= (yas--buffer-contents) "#include <foo>\nmain"))))
381 (ert-deftest middle-of-buffer-snippet-insertion ()
385 (save-excursion (insert "end"))
386 (yas-expand-snippet "-middle-")
387 (should (string= (yas--buffer-contents) "beginning-middle-end"))))
389 (ert-deftest another-example-for-issue-271 ()
390 ;; expect this to fail in batch mode since `region-active-p' doesn't
391 ;; used by `yas-expand-snippet' doesn't make sense in that context.
393 :expected-result (if noninteractive
398 (let ((snippet "\\${${1:1}:`yas-selected-text`}"))
402 (yas-expand-snippet snippet)
403 (should (string= (yas--buffer-contents) "aaa${1:bbb}ccc")))))
405 (ert-deftest string-match-with-subregexp-in-embedded-elisp ()
408 ;; the rule here is: To use regexps in embedded `(elisp)` expressions, write
409 ;; it like you would normal elisp, i.e. no need to escape the backslashes.
410 (let ((snippet "`(if (string-match \"foo\\\\(ba+r\\\\)foo\" \"foobaaaaaaaaaarfoo\")
413 (yas-expand-snippet snippet))
414 (should (string= (yas--buffer-contents) "ok"))))
416 (ert-deftest string-match-with-subregexp-in-mirror-transformations ()
419 ;; the rule here is: To use regexps in embedded `(elisp)` expressions,
420 ;; escape backslashes once, i.e. to use \\( \\) constructs, write \\\\( \\\\).
421 (let ((snippet "$1${1:$(if (string-match \"foo\\\\\\\\(ba+r\\\\\\\\)baz\" yas-text)
424 (yas-expand-snippet snippet)
425 (should (string= (yas--buffer-contents) "fail"))
426 (yas-mock-insert "foobaaar")
427 (should (string= (yas--buffer-contents) "foobaaarfail"))
428 (yas-mock-insert "baz")
429 (should (string= (yas--buffer-contents) "foobaaarbazok")))))
434 (ert-deftest protection-overlay-no-cheating ()
435 "Protection overlays at the very end of the buffer are dealt
436 with by cheatingly inserting a newline!
438 TODO: correct this bug!"
439 :expected-result :failed
442 (yas-expand-snippet "${2:brother} from another ${1:mother}")
443 (should (string= (yas--buffer-contents)
444 "brother from another mother") ;; no newline should be here!
448 (defvar yas--foobarbaz)
450 ;; See issue #497. To understand this test, follow the example of the
451 ;; `yas-key-syntaxes' docstring.
453 (ert-deftest complicated-yas-key-syntaxes ()
455 (yas-saving-variables
456 (yas-with-snippet-dirs
457 '((".emacs.d/snippets"
459 ("foo-barbaz" . "# condition: yas--foobarbaz\n# --\nOKfoo-barbazOK")
460 ("barbaz" . "# condition: yas--barbaz\n# --\nOKbarbazOK")
462 ("'quote" . "OKquoteOK"))))
466 (let ((yas-key-syntaxes '("w" "w_")))
467 (let ((yas--barbaz t))
468 (yas-should-expand '(("foo-barbaz" . "foo-OKbarbazOK")
469 ("barbaz" . "OKbarbazOK"))))
470 (let ((yas--foobarbaz t))
471 (yas-should-expand '(("foo-barbaz" . "OKfoo-barbazOK"))))
472 (let ((yas-key-syntaxes
473 (cons #'(lambda (_start-point)
474 (unless (looking-back "-")
479 (yas-should-expand '(("foo-barbaz" . "foo-barOKbazOK")))))
480 (let ((yas-key-syntaxes '(yas-try-key-from-whitespace)))
481 (yas-should-expand '(("xxx\n'quote" . "xxx\nOKquoteOK")
482 ("xxx 'quote" . "xxx OKquoteOK"))))
483 (let ((yas-key-syntaxes '(yas-shortest-key-until-whitespace))
484 (yas--foobarbaz t) (yas--barbaz t))
485 (yas-should-expand '(("foo-barbaz" . "foo-barOKbazOK")))
486 (setq yas-key-syntaxes '(yas-longest-key-from-whitespace))
487 (yas-should-expand '(("foo-barbaz" . "OKfoo-barbazOK")
488 ("foo " . "foo "))))))))
493 (defun yas--call-with-temporary-redefinitions (function
494 &rest function-names-and-overriding-functions)
495 (let* ((overrides (remove-if-not #'(lambda (fdef)
496 (fboundp (first fdef)))
497 function-names-and-overriding-functions))
498 (definition-names (mapcar #'first overrides))
499 (overriding-functions (mapcar #'second overrides))
500 (saved-functions (mapcar #'symbol-function definition-names)))
501 ;; saving all definitions before overriding anything ensures FDEFINITION
502 ;; errors don't cause accidental permanent redefinitions.
504 (cl-labels ((set-fdefinitions (names functions)
505 (loop for name in names
508 (set-fdefinitions definition-names overriding-functions)
509 (unwind-protect (funcall function)
510 (set-fdefinitions definition-names saved-functions)))))
512 (defmacro yas--with-temporary-redefinitions (fdefinitions &rest body)
513 ;; "Temporarily (but globally) redefine each function in FDEFINITIONS.
514 ;; E.g.: (yas--with-temporary-redefinitions ((foo (x) ...)
516 ;; ;; code that eventually calls foo, bar of (setf foo)
518 ;; FIXME: This is hideous! Better use defadvice (or at least letf).
519 `(yas--call-with-temporary-redefinitions
521 ,@(mapcar #'(lambda (thingy)
522 `(list ',(first thingy)
523 (lambda ,@(rest thingy))))
526 (defmacro yas-with-overriden-buffer-list (&rest body)
527 (let ((saved-sym (make-symbol "yas--buffer-list")))
528 `(let ((,saved-sym (symbol-function 'buffer-list)))
529 (yas--with-temporary-redefinitions
531 (remove-if #'(lambda (buf)
532 (with-current-buffer buf
533 (eq major-mode 'lisp-interaction-mode)))
534 (funcall ,saved-sym))))
538 (defmacro yas-with-some-interesting-snippet-dirs (&rest body)
539 `(yas-saving-variables
540 (yas-with-overriden-buffer-list
541 (yas-with-snippet-dirs
542 '((".emacs.d/snippets"
544 (".yas-parents" . "cc-mode")
545 ("printf" . "printf($1);")) ;; notice the overriding for issue #281
546 ("emacs-lisp-mode" ("ert-deftest" . "(ert-deftest ${1:name} () $0)"))
547 ("lisp-interaction-mode" (".yas-parents" . "emacs-lisp-mode")))
550 (".yas-parents" . "c++-mode")
551 ("printf" . "printf"))
552 ("cc-mode" ("def" . "# define"))
553 ("emacs-lisp-mode" ("dolist" . "(dolist)"))
554 ("lisp-interaction-mode" ("sc" . "brother from another mother"))))
557 (ert-deftest snippet-lookup ()
558 "Test `yas-lookup-snippet'."
559 (yas-with-some-interesting-snippet-dirs
560 (yas-reload-all 'no-jit)
561 (should (equal (yas-lookup-snippet "printf" 'c-mode) "printf($1);"))
562 (should (equal (yas-lookup-snippet "def" 'c-mode) "# define"))
563 (should-not (yas-lookup-snippet "no such snippet" nil 'noerror))
564 (should-not (yas-lookup-snippet "printf" 'emacs-lisp-mode 'noerror))))
566 (ert-deftest basic-jit-loading ()
567 "Test basic loading and expansion of snippets"
568 (yas-with-some-interesting-snippet-dirs
570 (yas--basic-jit-loading-1)))
572 (ert-deftest basic-jit-loading-with-compiled-snippets ()
573 "Test basic loading and expansion of compiled snippets"
574 (yas-with-some-interesting-snippet-dirs
577 (yas--with-temporary-redefinitions ((yas--load-directory-2
579 (ert-fail "yas--load-directory-2 shouldn't be called when snippets have been compiled")))
581 (yas--basic-jit-loading-1))))
583 (ert-deftest visiting-compiled-snippets ()
584 "Test snippet visiting for compiled snippets."
585 (yas-with-some-interesting-snippet-dirs
587 (yas-reload-all 'no-jit) ; must be loaded for `yas-lookup-snippet' to work.
588 (yas--with-temporary-redefinitions ((find-file-noselect
590 (throw 'yas-snippet-file filename)))
591 (should (string-suffix-p
593 (catch 'yas-snippet-file
594 (yas--visit-snippet-file-1
595 (yas--lookup-snippet-1 "def" 'cc-mode))))))))
597 (ert-deftest loading-with-cyclic-parenthood ()
598 "Test loading when cyclic parenthood is setup."
599 (yas-saving-variables
600 (yas-with-snippet-dirs '((".emacs.d/snippets"
602 (".yas-parents" . "cc-mode"))
604 (".yas-parents" . "yet-another-c-mode and-that-one"))
605 ("yet-another-c-mode"
606 (".yas-parents" . "c-mode and-also-this-one lisp-interaction-mode"))))
609 (let* ((major-mode 'c-mode)
615 ;; prog-mode doesn't exist in emacs 24.3
616 ,@(if (fboundp 'prog-mode)
619 lisp-interaction-mode))
620 (observed (yas--modes-to-activate)))
621 (should (equal major-mode (car observed)))
622 (should (equal (sort expected #'string<) (sort observed #'string<))))))))
624 (ert-deftest extra-modes-parenthood ()
625 "Test activation of parents of `yas--extra-modes'."
626 (yas-saving-variables
627 (yas-with-snippet-dirs '((".emacs.d/snippets"
629 (".yas-parents" . "cc-mode"))
630 ("yet-another-c-mode"
631 (".yas-parents" . "c-mode and-also-this-one lisp-interaction-mode"))))
634 (yas-activate-extra-mode 'c-mode)
635 (yas-activate-extra-mode 'yet-another-c-mode)
636 (yas-activate-extra-mode 'and-that-one)
637 (let* ((expected-first `(and-that-one
641 (expected-rest `(cc-mode
642 ;; prog-mode doesn't exist in emacs 24.3
643 ,@(if (fboundp 'prog-mode)
647 lisp-interaction-mode))
648 (observed (yas--modes-to-activate)))
649 (should (equal expected-first
650 (cl-subseq observed 0 (length expected-first))))
651 (should (equal (sort expected-rest #'string<)
652 (sort (cl-subseq observed (length expected-first)) #'string<))))))))
654 (defalias 'yas--phony-c-mode 'c-mode)
656 (ert-deftest issue-492-and-494 ()
657 (define-derived-mode yas--test-mode yas--phony-c-mode "Just a test mode")
658 (yas-with-snippet-dirs '((".emacs.d/snippets"
662 (let* ((major-mode 'yas--test-mode)
664 ,@(if (fboundp 'prog-mode)
668 (observed (yas--modes-to-activate)))
669 (should (null (cl-set-exclusive-or expected observed)))
670 (should (= (length expected)
671 (length observed)))))))
673 (define-derived-mode yas--test-mode c-mode "Just a test mode")
674 (define-derived-mode yas--another-test-mode c-mode "Another test mode")
676 (ert-deftest issue-504-tricky-jit ()
677 (yas-with-snippet-dirs
678 '((".emacs.d/snippets"
679 ("yas--another-test-mode"
680 (".yas-parents" . "yas--test-mode"))
682 (let ((b (with-current-buffer (generate-new-buffer "*yas-test*")
683 (yas--another-test-mode)
688 (should (= 0 (hash-table-count yas--scheduled-jit-loads))))
691 (defun yas--basic-jit-loading-1 ()
693 (should (= 4 (hash-table-count yas--scheduled-jit-loads)))
694 (should (= 0 (hash-table-count yas--tables)))
695 (lisp-interaction-mode)
697 (should (= 2 (hash-table-count yas--scheduled-jit-loads)))
698 (should (= 2 (hash-table-count yas--tables)))
699 (should (= 1 (hash-table-count (yas--table-uuidhash (gethash 'lisp-interaction-mode yas--tables)))))
700 (should (= 2 (hash-table-count (yas--table-uuidhash (gethash 'emacs-lisp-mode yas--tables)))))
701 (yas-should-expand '(("sc" . "brother from another mother")
702 ("dolist" . "(dolist)")
703 ("ert-deftest" . "(ert-deftest name () )")))
706 (should (= 0 (hash-table-count yas--scheduled-jit-loads)))
707 (should (= 4 (hash-table-count yas--tables)))
708 (should (= 1 (hash-table-count (yas--table-uuidhash (gethash 'c-mode yas--tables)))))
709 (should (= 1 (hash-table-count (yas--table-uuidhash (gethash 'cc-mode yas--tables)))))
710 (yas-should-expand '(("printf" . "printf();")
711 ("def" . "# define")))
712 (yas-should-not-expand '("sc" "dolist" "ert-deftest"))))
717 (defmacro yas-with-even-more-interesting-snippet-dirs (&rest body)
718 `(yas-saving-variables
719 (yas-with-snippet-dirs
720 `((".emacs.d/snippets"
722 (".yas-make-groups" . "")
723 ("printf" . "printf($1);")
725 ("fnprintf" . "fprintf($1);")
726 ("snprintf" . "snprintf($1);"))
728 ("strcmp" . "strecmp($1);")
729 ("strcasecmp" . "strcasecmp($1);")))
730 ("lisp-interaction-mode"
731 ("ert-deftest" . "# group: barbar\n# --\n(ert-deftest ${1:name} () $0)"))
733 ("a-guy" . "# uuid: 999\n# --\nyo!")
734 ("a-sir" . "# uuid: 12345\n# --\nindeed!")
735 ("a-lady" . "# uuid: 54321\n# --\noh-la-la!")
736 ("a-beggar" . "# uuid: 0101\n# --\narrrgh!")
737 ("an-outcast" . "# uuid: 666\n# --\narrrgh!")
738 (".yas-setup.el" . , (pp-to-string
739 '(yas-define-menu 'fancy-mode
740 '((yas-ignore-item "0101")
743 ((yas-item "12345")))
744 (yas-submenu "ladies"
745 ((yas-item "54321"))))
749 (ert-deftest test-yas-define-menu ()
750 (let ((yas-use-menu t))
751 (yas-with-even-more-interesting-snippet-dirs
752 (yas-reload-all 'no-jit)
753 (let ((menu (cdr (gethash 'fancy-mode yas--menu-table))))
754 (should (eql 4 (length menu)))
755 (dolist (item '("a-guy" "a-beggar"))
756 (should (find item menu :key #'third :test #'string=)))
757 (should-not (find "an-outcast" menu :key #'third :test #'string=))
758 (dolist (submenu '("sirs" "ladies"))
761 (find submenu menu :key #'third :test #'string=)))))
764 (ert-deftest test-group-menus ()
765 "Test group-based menus using .yas-make-groups and the group directive"
766 (let ((yas-use-menu t))
767 (yas-with-even-more-interesting-snippet-dirs
768 (yas-reload-all 'no-jit)
769 ;; first the subdir-based groups
771 (let ((menu (cdr (gethash 'c-mode yas--menu-table))))
772 (should (eql 3 (length menu)))
773 (dolist (item '("printf" "foo-group-a" "foo-group-b"))
774 (should (find item menu :key #'third :test #'string=)))
775 (dolist (submenu '("foo-group-a" "foo-group-b"))
778 (find submenu menu :key #'third :test #'string=))))))
779 ;; now group directives
781 (let ((menu (cdr (gethash 'lisp-interaction-mode yas--menu-table))))
782 (should (eql 1 (length menu)))
783 (should (find "barbar" menu :key #'third :test #'string=))
786 (find "barbar" menu :key #'third :test #'string=))))))))
788 (ert-deftest test-group-menus-twisted ()
789 "Same as similarly named test, but be mean.
792 (let ((yas-use-menu t))
793 (yas-with-even-more-interesting-snippet-dirs
794 ;; add a group directive conflicting with the subdir and watch
797 (insert "# group: foo-group-c\n# --\nstrecmp($1)")
798 (write-region nil nil (concat (first (yas-snippet-dirs))
799 "/c-mode/foo-group-b/strcmp")))
800 (yas-reload-all 'no-jit)
801 (let ((menu (cdr (gethash 'c-mode yas--menu-table))))
802 (should (eql 4 (length menu)))
803 (dolist (item '("printf" "foo-group-a" "foo-group-b" "foo-group-c"))
804 (should (find item menu :key #'third :test #'string=)))
805 (dolist (submenu '("foo-group-a" "foo-group-b" "foo-group-c"))
808 (find submenu menu :key #'third :test #'string=))))))
809 ;; delete the .yas-make-groups file and watch behaviour
811 (delete-file (concat (first (yas-snippet-dirs))
812 "/c-mode/.yas-make-groups"))
813 (yas-reload-all 'no-jit)
814 (let ((menu (cdr (gethash 'c-mode yas--menu-table))))
815 (should (eql 5 (length menu))))
816 ;; Change a group directive and reload
818 (let ((menu (cdr (gethash 'lisp-interaction-mode yas--menu-table))))
819 (should (find "barbar" menu :key #'third :test #'string=)))
822 (insert "# group: foofoo\n# --\n(ert-deftest ${1:name} () $0)")
823 (write-region nil nil (concat (first (yas-snippet-dirs))
824 "/lisp-interaction-mode/ert-deftest")))
825 (yas-reload-all 'no-jit)
826 (let ((menu (cdr (gethash 'lisp-interaction-mode yas--menu-table))))
827 (should (eql 1 (length menu)))
828 (should (find "foofoo" menu :key #'third :test #'string=))
831 (find "foofoo" menu :key #'third :test #'string=))))))))
834 ;;; The infamous and problematic tab keybinding
836 (ert-deftest test-yas-tab-binding ()
839 (should (not (eq (key-binding (yas--read-keybinding "<tab>")) 'yas-expand)))
841 (should (eq (key-binding (yas--read-keybinding "<tab>")) 'yas-expand))
842 (yas-expand-snippet "$1 $2 $3")
843 (should (eq (key-binding [(tab)]) 'yas-next-field-or-maybe-expand))
844 (should (eq (key-binding (kbd "TAB")) 'yas-next-field-or-maybe-expand))
845 (should (eq (key-binding [(shift tab)]) 'yas-prev-field))
846 (should (eq (key-binding [backtab]) 'yas-prev-field))))
848 (ert-deftest test-rebindings ()
851 (define-key yas-minor-mode-map [tab] nil)
852 (define-key yas-minor-mode-map (kbd "TAB") nil)
853 (define-key yas-minor-mode-map (kbd "SPC") 'yas-expand)
856 (should (not (eq (key-binding (yas--read-keybinding "TAB")) 'yas-expand)))
857 (should (eq (key-binding (yas--read-keybinding "SPC")) 'yas-expand))
859 (should (not (eq (key-binding (yas--read-keybinding "TAB")) 'yas-expand)))
860 (should (eq (key-binding (yas--read-keybinding "SPC")) 'yas-expand))))
861 ;; FIXME: actually should restore to whatever saved values where there.
863 (define-key yas-minor-mode-map [tab] 'yas-expand)
864 (define-key yas-minor-mode-map (kbd "TAB") 'yas-expand)
865 (define-key yas-minor-mode-map (kbd "SPC") nil)))
867 (ert-deftest test-yas-in-org ()
871 (should (eq (key-binding [(tab)]) 'yas-expand))
872 (should (eq (key-binding (kbd "TAB")) 'yas-expand))))
874 (ert-deftest test-yas-activate-extra-modes ()
875 "Given a symbol, `yas-activate-extra-mode' should be able to
876 add the snippets associated with the given mode."
878 (yas-saving-variables
879 (yas-with-snippet-dirs
880 '((".emacs.d/snippets"
884 ("car" . "(car )"))))
888 (yas-activate-extra-mode 'markdown-mode)
889 (should (eq 'markdown-mode (car yas--extra-modes)))
890 (yas-should-expand '(("_" . "_Text_ ")))
891 (yas-should-expand '(("car" . "(car )")))
892 (yas-deactivate-extra-mode 'markdown-mode)
893 (should-not (eq 'markdown-mode (car yas--extra-modes)))
894 (yas-should-not-expand '("_"))
895 (yas-should-expand '(("car" . "(car )")))))))
900 (defun yas-should-expand (keys-and-expansions)
901 (dolist (key-and-expansion keys-and-expansions)
902 (yas-exit-all-snippets)
904 (insert (car key-and-expansion))
905 (let ((yas-fallback-behavior nil))
906 (ert-simulate-command '(yas-expand)))
907 (unless (string= (yas--buffer-contents) (cdr key-and-expansion))
908 (ert-fail (format "\"%s\" should have expanded to \"%s\" but got \"%s\""
909 (car key-and-expansion)
910 (cdr key-and-expansion)
911 (yas--buffer-contents)))))
912 (yas-exit-all-snippets))
914 (defun yas-should-not-expand (keys)
916 (yas-exit-all-snippets)
919 (let ((yas-fallback-behavior nil))
920 (ert-simulate-command '(yas-expand)))
921 (unless (string= (yas--buffer-contents) key)
922 (ert-fail (format "\"%s\" should have stayed put, but instead expanded to \"%s\""
924 (yas--buffer-contents))))))
926 (defun yas-mock-insert (string)
927 (dotimes (i (length string))
928 (let ((last-command-event (aref string i)))
929 (ert-simulate-command '(self-insert-command 1)))))
931 (defun yas-mock-yank (string)
932 (let ((interprogram-paste-function (lambda () string)))
933 (ert-simulate-command '(yank nil))))
935 (defun yas-make-file-or-dirs (ass)
936 (let ((file-or-dir-name (car ass))
938 (cond ((listp content)
939 (make-directory file-or-dir-name 'parents)
940 (let ((default-directory (concat default-directory "/" file-or-dir-name)))
941 (mapc #'yas-make-file-or-dirs content)))
945 (write-region nil nil file-or-dir-name nil 'nomessage)))
947 (message "[yas] oops don't know this content")))))
950 (defun yas-variables ()
952 (mapatoms #'(lambda (sym)
953 (if (and (string-match "^yas-[^/]" (symbol-name sym))
958 (defun yas-call-with-saving-variables (fn)
959 (let* ((vars (yas-variables))
960 (saved-values (mapcar #'symbol-value vars)))
963 (loop for var in vars
964 for saved in saved-values
965 do (set var saved)))))
967 (defun yas-call-with-snippet-dirs (dirs fn)
968 (let* ((default-directory (make-temp-file "yasnippet-fixture" t))
969 (yas-snippet-dirs (mapcar #'car dirs)))
970 (with-temp-message ""
973 (mapc #'yas-make-file-or-dirs dirs)
975 (when (>= emacs-major-version 24)
976 (delete-directory default-directory 'recursive))))))
980 (unless (fboundp 'special-mode)
981 ;; FIXME: Why provide this default definition here?!?
982 (defalias 'special-mode 'fundamental))
984 (unless (fboundp 'string-suffix-p)
985 ;; introduced in Emacs 24.4
986 (defun string-suffix-p (suffix string &optional ignore-case)
987 "Return non-nil if SUFFIX is a suffix of STRING.
988 If IGNORE-CASE is non-nil, the comparison is done without paying
989 attention to case differences."
990 (let ((start-pos (- (length string) (length suffix))))
991 (and (>= start-pos 0)
992 (eq t (compare-strings suffix nil nil
993 string start-pos nil ignore-case))))))
995 ;;; btw to test this in emacs22 mac osx:
996 ;;; curl -L -O https://github.com/mirrors/emacs/raw/master/lisp/emacs-lisp/ert.el
997 ;;; curl -L -O https://github.com/mirrors/emacs/raw/master/lisp/emacs-lisp/ert-x.el
998 ;;; /usr/bin/emacs -nw -Q -L . -l yasnippet-tests.el --batch -e ert
1001 (put 'yas-saving-variables 'edebug-form-spec t)
1002 (put 'yas-with-snippet-dirs 'edebug-form-spec t)
1003 (put 'yas-with-overriden-buffer-list 'edebug-form-spec t)
1004 (put 'yas-with-some-interesting-snippet-dirs 'edebug-form-spec t)
1007 (put 'yas--with-temporary-redefinitions 'lisp-indent-function 1)
1008 (put 'yas--with-temporary-redefinitions 'edebug-form-spec '((&rest (defun*)) cl-declarations body))
1013 (provide 'yasnippet-tests)
1015 ;; indent-tabs-mode: nil
1016 ;; byte-compile-warnings: (not cl-functions)
1018 ;;; yasnippet-tests.el ends here