]> code.delx.au - gnu-emacs-elpa/blobdiff - packages/yasnippet/yasnippet-tests.el
Merge commit 'dea0ba6347f2eb5be310826e7917effb73e1e600'
[gnu-emacs-elpa] / packages / yasnippet / yasnippet-tests.el
index 536fea2776acf342ec738c39588d1251bd3f0946..9bf592f88833b64908c0d47e975a5f702c57d8c6 100644 (file)
@@ -1,6 +1,6 @@
-;;; yasnippet-tests.el --- some yasnippet tests
+;;; yasnippet-tests.el --- some yasnippet tests  -*- lexical-binding: t -*-
 
-;; Copyright (C) 2012  João Távora
+;; Copyright (C) 2012, 2013, 2014  Free Software Foundation, Inc.
 
 ;; Author: João Távora <joaot@siscog.pt>
 ;; Keywords: emulations, convenience
 (require 'yasnippet)
 (require 'ert)
 (require 'ert-x)
+(require 'cl)
 
 \f
 ;;; Snippet mechanics
 
+(defun yas--buffer-contents ()
+  (buffer-substring-no-properties (point-min) (point-max)))
+
 (ert-deftest field-navigation ()
   (with-temp-buffer
     (yas-minor-mode 1)
     (yas-expand-snippet "${1:brother} from another ${2:mother}")
-    (should (string= (buffer-substring-no-properties (point-min) (point-max))
+    (should (string= (yas--buffer-contents)
                      "brother from another mother"))
 
     (should (looking-at "brother"))
   (with-temp-buffer
     (yas-minor-mode 1)
     (yas-expand-snippet "${1:brother} from another $1")
-    (should (string= (buffer-substring-no-properties (point-min) (point-max))
+    (should (string= (yas--buffer-contents)
                      "brother from another brother"))
     (ert-simulate-command `(yas-mock-insert "bla"))
-    (should (string= (buffer-substring-no-properties (point-min) (point-max))
+    (should (string= (yas--buffer-contents)
                      "bla from another bla"))))
 
 (ert-deftest mirror-with-transformation ()
   (with-temp-buffer
     (yas-minor-mode 1)
     (yas-expand-snippet "${1:brother} from another ${1:$(upcase yas-text)}")
-    (should (string= (buffer-substring-no-properties (point-min) (point-max))
+    (should (string= (yas--buffer-contents)
                      "brother from another BROTHER"))
     (ert-simulate-command `(yas-mock-insert "bla"))
-    (should (string= (buffer-substring-no-properties (point-min) (point-max))
+    (should (string= (yas--buffer-contents)
                      "bla from another BLA"))))
 
+(ert-deftest primary-field-transformation ()
+  (with-temp-buffer
+    (yas-minor-mode 1)
+    (let ((snippet "${1:$$(upcase yas/text)}${1:$(concat \"bar\" yas/text)}"))
+      (yas-expand-snippet snippet)
+      (should (string= (yas--buffer-contents) "bar"))
+      (ert-simulate-command `(yas-mock-insert "foo"))
+      (should (string= (yas--buffer-contents) "FOObarFOO")))))
+
 (ert-deftest nested-placeholders-kill-superfield ()
   (with-temp-buffer
     (yas-minor-mode 1)
     (yas-expand-snippet "brother from ${2:another ${3:mother}}!")
-    (should (string= (buffer-substring-no-properties (point-min) (point-max))
+    (should (string= (yas--buffer-contents)
                      "brother from another mother!"))
     (ert-simulate-command `(yas-mock-insert "bla"))
-    (should (string= (buffer-substring-no-properties (point-min) (point-max))
+    (should (string= (yas--buffer-contents)
                      "brother from bla!"))))
 
 (ert-deftest nested-placeholders-use-subfield ()
     (yas-expand-snippet "brother from ${2:another ${3:mother}}!")
     (ert-simulate-command '(yas-next-field-or-maybe-expand))
     (ert-simulate-command `(yas-mock-insert "bla"))
-    (should (string= (buffer-substring-no-properties (point-min) (point-max))
+    (should (string= (yas--buffer-contents)
                      "brother from another bla!"))))
 
+(ert-deftest mirrors-adjacent-to-fields-with-nested-mirrors ()
+  (with-temp-buffer
+    (yas-minor-mode 1)
+    (yas-expand-snippet "<%= f.submit \"${1:Submit}\"${2:$(and (yas-text) \", :disable_with => '\")}${2:$1ing...}${2:$(and (yas-text) \"'\")} %>")
+    (should (string= (yas--buffer-contents)
+                     "<%= f.submit \"Submit\", :disable_with => 'Submiting...' %>"))
+    (ert-simulate-command `(yas-mock-insert "Send"))
+    (should (string= (yas--buffer-contents)
+                     "<%= f.submit \"Send\", :disable_with => 'Sending...' %>"))))
+
+(ert-deftest deep-nested-mirroring-issue-351 ()
+  (with-temp-buffer
+    (yas-minor-mode 1)
+    (yas-expand-snippet "${1:FOOOOOOO}${2:$1}${3:$2}${4:$3}")
+    (ert-simulate-command `(yas-mock-insert "abc"))
+    (should (string= (yas--buffer-contents) "abcabcabcabc"))))
+
 ;; (ert-deftest in-snippet-undo ()
 ;;   (with-temp-buffer
 ;;     (yas-minor-mode 1)
 ;;     (ert-simulate-command '(yas-next-field-or-maybe-expand))
 ;;     (ert-simulate-command `(yas-mock-insert "bla"))
 ;;     (ert-simulate-command '(undo))
-;;     (should (string= (buffer-substring-no-properties (point-min) (point-max))
+;;     (should (string= (yas--buffer-contents)
 ;;                      "brother from another mother!"))))
 
 \f
-;;; Misc tests
+;;; Snippet expansion and character escaping
+;;; Thanks to @zw963 (Billy) for the testing
 ;;;
+(ert-deftest escape-dollar ()
+  (with-temp-buffer
+    (yas-minor-mode 1)
+    (yas-expand-snippet "bla\\${1:bla}ble")
+    (should (string= (yas--buffer-contents) "bla${1:bla}ble"))))
+
+(ert-deftest escape-closing-brace ()
+  (with-temp-buffer
+    (yas-minor-mode 1)
+    (yas-expand-snippet "bla${1:bla\\}}ble")
+    (should (string= (yas--buffer-contents) "blabla}ble"))
+    (should (string= (yas-field-value 1) "bla}"))))
+
+(ert-deftest escape-backslashes ()
+  (with-temp-buffer
+    (yas-minor-mode 1)
+    (yas-expand-snippet "bla\\ble")
+    (should (string= (yas--buffer-contents) "bla\\ble"))))
+
+(ert-deftest escape-backquotes ()
+  (with-temp-buffer
+    (yas-minor-mode 1)
+    (yas-expand-snippet "bla`(upcase \"foo\\`bar\")`ble")
+    (should (string= (yas--buffer-contents) "blaFOO`BARble"))))
+
+(ert-deftest escape-some-elisp-with-strings ()
+  "elisp with strings and unbalance parens inside it"
+  (with-temp-buffer
+    (yas-minor-mode 1)
+    ;; The rules here is: to output a literal `"' you need to escape
+    ;; it with one backslash. You don't need to escape them in
+    ;; embedded elisp.
+    (yas-expand-snippet "soon \\\"`(concat (upcase \"(my arms\")\"\\\" were all around her\")`")
+    (should (string= (yas--buffer-contents) "soon \"(MY ARMS\" were all around her"))))
 
+(ert-deftest escape-some-elisp-with-backslashes ()
+  (with-temp-buffer
+    (yas-minor-mode 1)
+    ;; And the rule here is: to output a literal `\' inside a string
+    ;; inside embedded elisp you need a total of six `\'
+    (yas-expand-snippet "bla`(upcase \"hey\\\\\\yo\")`ble")
+    (should (string= (yas--buffer-contents) "blaHEY\\YOble"))))
+
+(ert-deftest be-careful-when-escaping-in-yas-selected-text ()
+  (with-temp-buffer
+    (yas-minor-mode 1)
+    (let ((yas/selected-text "He\\\\o world!"))
+      (yas-expand-snippet "Look ma! `(yas/selected-text)`")
+      (should (string= (yas--buffer-contents) "Look ma! He\\\\o world!")))
+    (yas-exit-all-snippets)
+    (erase-buffer)
+    (let ((yas/selected-text "He\"o world!"))
+      (yas-expand-snippet "Look ma! `(yas/selected-text)`")
+      (should (string= (yas--buffer-contents) "Look ma! He\"o world!")))
+    (yas-exit-all-snippets)
+    (erase-buffer)
+    (let ((yas/selected-text "He\"\)\\o world!"))
+      (yas-expand-snippet "Look ma! `(yas/selected-text)`")
+      (should (string= (yas--buffer-contents) "Look ma! He\"\)\\o world!")))
+    (yas-exit-all-snippets)
+    (erase-buffer)))
+
+(ert-deftest be-careful-when-escaping-in-yas-selected-text-2 ()
+  (with-temp-buffer
+    (let ((yas/selected-text "He)}o world!"))
+      (yas-expand-snippet "Look ma! ${1:`(yas/selected-text)`} OK?")
+      (should (string= (yas--buffer-contents) "Look ma! He)}o world! OK?")))))
+
+(ert-deftest example-for-issue-271 ()
+  (with-temp-buffer
+    (yas-minor-mode 1)
+    (let ((yas-selected-text "aaa")
+          (snippet "if ${1:condition}\n`yas/selected-text`\nelse\n$3\nend"))
+      (yas-expand-snippet snippet)
+      (yas-next-field)
+      (ert-simulate-command `(yas-mock-insert "bbb"))
+      (should (string= (yas--buffer-contents) "if condition\naaa\nelse\nbbb\nend")))))
+
+(ert-deftest another-example-for-issue-271 ()
+  ;; expect this to fail in batch mode since `region-active-p' doesn't
+  ;; used by `yas-expand-snippet' doesn't make sense in that context.
+  ;;
+  :expected-result (if noninteractive
+                       :failed
+                     :passed)
+  (with-temp-buffer
+    (yas-minor-mode 1)
+    (let ((snippet "\\${${1:1}:`yas/selected-text`}"))
+      (insert "aaabbbccc")
+      (set-mark 4)
+      (goto-char 7)
+      (yas-expand-snippet snippet)
+      (should (string= (yas--buffer-contents) "aaa${1:bbb}ccc")))))
+
+(ert-deftest string-match-with-subregexp-in-embedded-elisp ()
+  (with-temp-buffer
+    (yas-minor-mode 1)
+    ;; the rule here is: To use regexps in embedded `(elisp)` expressions, write
+    ;; it like you would normal elisp, i.e. no need to escape the backslashes.
+    (let ((snippet "`(if (string-match \"foo\\\\(ba+r\\\\)foo\" \"foobaaaaaaaaaarfoo\")
+                         \"ok\"
+                         \"fail\")`"))
+      (yas-expand-snippet snippet))
+    (should (string= (yas--buffer-contents) "ok"))))
+
+(ert-deftest string-match-with-subregexp-in-mirror-transformations ()
+  (with-temp-buffer
+    (yas-minor-mode 1)
+    ;; the rule here is: To use regexps in embedded `(elisp)` expressions,
+    ;; escape backslashes once, i.e. to use \\( \\) constructs, write \\\\( \\\\).
+    (let ((snippet "$1${1:$(if (string-match \"foo\\\\\\\\(ba+r\\\\\\\\)baz\" yas/text)
+                                \"ok\"
+                                \"fail\")}"))
+      (yas-expand-snippet snippet)
+      (should (string= (yas--buffer-contents) "fail"))
+      (ert-simulate-command `(yas-mock-insert "foobaaar"))
+      (should (string= (yas--buffer-contents) "foobaaarfail"))
+      (ert-simulate-command `(yas-mock-insert "baz"))
+      (should (string= (yas--buffer-contents) "foobaaarbazok")))))
+
+\f
+;;; Misc tests
+;;;
 (ert-deftest protection-overlay-no-cheating ()
-  "Protection overlays at the very end of the buffer, are dealt by cheatingly inserting a newline!
+  "Protection overlays at the very end of the buffer are dealt
+  with by cheatingly inserting a newline!
 
 TODO: correct this bug!"
   :expected-result :failed
   (with-temp-buffer
     (yas-minor-mode 1)
     (yas-expand-snippet "${2:brother} from another ${1:mother}")
-    (should (string= (buffer-substring-no-properties (point-min) (point-max))
+    (should (string= (yas--buffer-contents)
                      "brother from another mother") ;; no newline should be here!
             )))
 \f
 ;;; Loading
 ;;;
+(defun yas--call-with-temporary-redefinitions (function
+                                               &rest function-names-and-overriding-functions)
+  (let* ((overrides (remove-if-not #'(lambda (fdef)
+                                       (fboundp (first fdef)))
+                                   function-names-and-overriding-functions))
+         (definition-names (mapcar #'first overrides))
+         (overriding-functions (mapcar #'second overrides))
+         (saved-functions (mapcar #'symbol-function definition-names)))
+    ;; saving all definitions before overriding anything ensures FDEFINITION
+    ;; errors don't cause accidental permanent redefinitions.
+    ;;
+    (labels ((set-fdefinitions (names functions)
+                               (loop for name in names
+                                     for fn in functions
+                                     do (fset name fn))))
+      (set-fdefinitions definition-names overriding-functions)
+      (unwind-protect (funcall function)
+       (set-fdefinitions definition-names saved-functions)))))
+
+(defmacro yas--with-temporary-redefinitions (fdefinitions &rest body)
+  ;; "Temporarily (but globally) redefine each function in FDEFINITIONS.
+  ;; E.g.: (yas--with-temporary-redefinitions ((foo (x) ...)
+  ;;                                           (bar (x) ...))
+  ;;         ;; code that eventually calls foo, bar of (setf foo)
+  ;;         ...)"
+  ;; FIXME: This is hideous!  Better use defadvice (or at least letf).
+  `(yas--call-with-temporary-redefinitions
+    (lambda () ,@body)
+    ,@(mapcar #'(lambda (thingy)
+                  `(list ',(first thingy)
+                         (lambda ,@(rest thingy))))
+              fdefinitions)))
+
+(put 'yas--with-temporary-redefinitions 'lisp-indent-function 1)
+(put 'yas--with-temporary-redefinitions 'edebug-form-spec '((&rest (defun*)) cl-declarations body))
+
+(defmacro yas-with-overriden-buffer-list (&rest body)
+  (let ((saved-sym (make-symbol "yas--buffer-list")))
+    `(let ((,saved-sym (symbol-function 'buffer-list)))
+       (yas--with-temporary-redefinitions
+           ((buffer-list ()
+                         (remove-if #'(lambda (buf)
+                                        (with-current-buffer buf
+                                          (eq major-mode 'lisp-interaction-mode)))
+                                    (funcall ,saved-sym))))
+         ,@body))))
+
 (defmacro yas-with-some-interesting-snippet-dirs (&rest body)
   `(yas-saving-variables
-    (yas-with-snippet-dirs
-     '((".emacs.d/snippets"
-        ("c-mode"
-         (".yas-parents" . "cc-mode")
-         ("printf" . "printf($1);"))
-        ("emacs-lisp-mode" ("ert-deftest" . "(ert-deftest ${1:name} () $0)"))
-        ("lisp-interaction-mode" (".yas-parents" . "emacs-lisp-mode")))
-       ("library/snippets"
-        ("c-mode" (".yas-parents" . "c++-mode"))
-        ("cc-mode" ("def" . "# define"))
-        ("emacs-lisp-mode" ("dolist" . "(dolist)"))
-        ("lisp-interaction-mode" ("sc" . "brother from another mother"))))
-     ,@body)))
+    (yas-with-overriden-buffer-list
+     (yas-with-snippet-dirs
+       '((".emacs.d/snippets"
+          ("c-mode"
+           (".yas-parents" . "cc-mode")
+           ("printf" . "printf($1);"))  ;; notice the overriding for issue #281
+          ("emacs-lisp-mode" ("ert-deftest" . "(ert-deftest ${1:name} () $0)"))
+          ("lisp-interaction-mode" (".yas-parents" . "emacs-lisp-mode")))
+         ("library/snippets"
+          ("c-mode"
+           (".yas-parents" . "c++-mode")
+           ("printf" . "printf"))
+          ("cc-mode" ("def" . "# define"))
+          ("emacs-lisp-mode" ("dolist" . "(dolist)"))
+          ("lisp-interaction-mode" ("sc" . "brother from another mother"))))
+       ,@body))))
 
 (ert-deftest basic-jit-loading ()
   "Test basic loading and expansion of snippets"
@@ -138,13 +342,29 @@ TODO: correct this bug!"
   (yas-with-some-interesting-snippet-dirs
    (yas-reload-all)
    (yas-recompile-all)
-   (flet ((yas--load-directory-2
-           (&rest dummies)
-           (ert-fail "yas--load-directory-2 shouldn't be called when snippets have been compiled")))
+   (yas--with-temporary-redefinitions ((yas--load-directory-2
+                                        (&rest _dummies)
+                                        (ert-fail "yas--load-directory-2 shouldn't be called when snippets have been compiled")))
      (yas-reload-all)
      (yas--basic-jit-loading-1))))
 
-(defun yas--basic-jit-loading-1 (&optional compile)
+(ert-deftest loading-with-cyclic-parenthood ()
+  "Test loading when cyclic parenthood is setup."
+  (yas-saving-variables
+   (yas-with-snippet-dirs '((".emacs.d/snippets"
+                             ("c-mode"
+                              (".yas-parents" . "cc-mode"))
+                             ("cc-mode"
+                              (".yas-parents" . "yet-another-c-mode"))
+                             ("yet-another-c-mode"
+                              (".yas-parents" . "c-mode"))))
+     (yas-reload-all)
+     (condition-case nil
+         (yas--all-parents 'c-mode)
+       (error
+        (ert-fail "cyclic parenthood test failed"))))))
+
+(defun yas--basic-jit-loading-1 ()
   (with-temp-buffer
     (should (= 4 (hash-table-count yas--scheduled-jit-loads)))
     (should (= 0 (hash-table-count yas--tables)))
@@ -173,34 +393,34 @@ TODO: correct this bug!"
 (defmacro yas-with-even-more-interesting-snippet-dirs (&rest body)
   `(yas-saving-variables
     (yas-with-snippet-dirs
-     `((".emacs.d/snippets"
-        ("c-mode"
-         (".yas-make-groups" . "")
-         ("printf" . "printf($1);")
-         ("foo-group-a"
-          ("fnprintf" . "fprintf($1);")
-          ("snprintf" . "snprintf($1);"))
-         ("foo-group-b"
-          ("strcmp" . "strecmp($1);")
-          ("strcasecmp" . "strcasecmp($1);")))
-        ("lisp-interaction-mode"
-         ("ert-deftest" . "# group: barbar\n# --\n(ert-deftest ${1:name} () $0)"))
-        ("fancy-mode"
-         ("a-guy" . "# uuid: 999\n# --\nyo!")
-         ("a-sir" . "# uuid: 12345\n# --\nindeed!")
-         ("a-lady" . "# uuid: 54321\n# --\noh-la-la!")
-         ("a-beggar" . "# uuid: 0101\n# --\narrrgh!")
-         ("an-outcast" . "# uuid: 666\n# --\narrrgh!")
-         (".yas-setup.el" . , (pp-to-string
-                               '(yas-define-menu 'fancy-mode
-                                                 '((yas-ignore-item "0101")
-                                                   (yas-item "999")
-                                                   (yas-submenu "sirs"
-                                                                ((yas-item "12345")))
-                                                   (yas-submenu "ladies"
-                                                                ((yas-item "54321"))))
-                                                 '("666")))))))
-     ,@body)))
+      `((".emacs.d/snippets"
+         ("c-mode"
+          (".yas-make-groups" . "")
+          ("printf" . "printf($1);")
+          ("foo-group-a"
+           ("fnprintf" . "fprintf($1);")
+           ("snprintf" . "snprintf($1);"))
+          ("foo-group-b"
+           ("strcmp" . "strecmp($1);")
+           ("strcasecmp" . "strcasecmp($1);")))
+         ("lisp-interaction-mode"
+          ("ert-deftest" . "# group: barbar\n# --\n(ert-deftest ${1:name} () $0)"))
+         ("fancy-mode"
+          ("a-guy" . "# uuid: 999\n# --\nyo!")
+          ("a-sir" . "# uuid: 12345\n# --\nindeed!")
+          ("a-lady" . "# uuid: 54321\n# --\noh-la-la!")
+          ("a-beggar" . "# uuid: 0101\n# --\narrrgh!")
+          ("an-outcast" . "# uuid: 666\n# --\narrrgh!")
+          (".yas-setup.el" . , (pp-to-string
+                                '(yas-define-menu 'fancy-mode
+                                                  '((yas-ignore-item "0101")
+                                                    (yas-item "999")
+                                                    (yas-submenu "sirs"
+                                                                 ((yas-item "12345")))
+                                                    (yas-submenu "ladies"
+                                                                 ((yas-item "54321"))))
+                                                  '("666")))))))
+      ,@body)))
 
 (ert-deftest test-yas-define-menu ()
   (let ((yas-use-menu t))
@@ -286,9 +506,54 @@ TODO: be meaner"
                 (fourth
                  (find "foofoo" menu :key #'third :test #'string=))))))))
 
+\f
+;;; The infamous and problematic tab keybinding
+;;;
+(ert-deftest test-yas-tab-binding ()
+  (with-temp-buffer
+    (yas-minor-mode -1)
+    (should (not (eq (key-binding (yas--read-keybinding "<tab>")) 'yas-expand)))
+    (yas-minor-mode 1)
+    (should (eq (key-binding (yas--read-keybinding "<tab>")) 'yas-expand))
+    (yas-expand-snippet "$1 $2 $3")
+    (should (eq (key-binding [(tab)]) 'yas-next-field-or-maybe-expand))
+    (should (eq (key-binding (kbd "TAB")) 'yas-next-field-or-maybe-expand))
+    (should (eq (key-binding [(shift tab)]) 'yas-prev-field))
+    (should (eq (key-binding [backtab]) 'yas-prev-field))))
+
+(ert-deftest test-rebindings ()
+  (unwind-protect
+      (progn
+        (define-key yas-minor-mode-map [tab] nil)
+        (define-key yas-minor-mode-map (kbd "TAB") nil)
+        (define-key yas-minor-mode-map (kbd "SPC") 'yas-expand)
+        (with-temp-buffer
+          (yas-minor-mode 1)
+          (should (not (eq (key-binding (yas--read-keybinding "TAB")) 'yas-expand)))
+          (should (eq (key-binding (yas--read-keybinding "SPC")) 'yas-expand))
+          (yas-reload-all)
+          (should (not (eq (key-binding (yas--read-keybinding "TAB")) 'yas-expand)))
+          (should (eq (key-binding (yas--read-keybinding "SPC")) 'yas-expand))))
+    (setcdr yas-minor-mode-map (cdr (yas--init-minor-keymap)))))
+
+(ert-deftest test-yas-in-org ()
+  (with-temp-buffer
+    (org-mode)
+    (yas-minor-mode 1)
+    (should (eq (key-binding [(tab)]) 'yas-expand))
+    (should (eq (key-binding (kbd "TAB")) 'yas-expand))))
+
 \f
 ;;; Helpers
 ;;;
+(defun yas/ert ()
+  (interactive)
+  (with-temp-buffer
+    (yas--with-temporary-redefinitions
+        ((message (&rest _args) nil))
+      (ert t (buffer-name (current-buffer)))
+      (princ (buffer-string)))))
+
 
 (defun yas-should-expand (keys-and-expansions)
   (dolist (key-and-expansion keys-and-expansions)
@@ -297,8 +562,7 @@ TODO: be meaner"
     (insert (car key-and-expansion))
     (let ((yas-fallback-behavior nil))
       (ert-simulate-command '(yas-expand)))
-    (should (string= (buffer-substring-no-properties (point-min) (point-max))
-                       (cdr key-and-expansion))))
+    (should (string= (yas--buffer-contents) (cdr key-and-expansion))))
   (yas-exit-all-snippets))
 
 (defun yas-should-not-expand (keys)
@@ -308,7 +572,7 @@ TODO: be meaner"
     (insert key)
     (let ((yas-fallback-behavior nil))
       (ert-simulate-command '(yas-expand)))
-    (should (string= (buffer-substring-no-properties (point-min) (point-max)) key))))
+    (should (string= (yas--buffer-contents) key))))
 
 (defun yas-mock-insert (string)
   (interactive)
@@ -360,10 +624,11 @@ TODO: be meaner"
           (progn
             (mapc #'yas-make-file-or-dirs dirs)
             (funcall fn))
-        (when (>= emacs-major-version 23)
+        (when (>= emacs-major-version 24)
           (delete-directory default-directory 'recursive))))))
 
 (defmacro yas-with-snippet-dirs (dirs &rest body)
+  (declare (indent defun))
   `(yas-call-with-snippet-dirs ,dirs
                                #'(lambda ()
                                    ,@body)))
@@ -371,7 +636,8 @@ TODO: be meaner"
 ;;; Older emacsen
 ;;;
 (unless (fboundp 'special-mode)
-  (define-minor-mode special-mode "Just a placeholder for something isn't in emacs 22"))
+  ;; FIXME: Why provide this default definition here?!?
+  (defalias 'special-mode 'fundamental))
 
 ;;; btw to test this in emacs22 mac osx:
 ;;; curl -L -O https://github.com/mirrors/emacs/raw/master/lisp/emacs-lisp/ert.el
@@ -381,6 +647,3 @@ TODO: be meaner"
 
 (provide 'yasnippet-tests)
 ;;; yasnippet-tests.el ends here
-;; Local Variables:
-;; lexical-binding: t
-;; End: