summaryrefslogtreecommitdiff
path: root/test/lisp/progmodes/elisp-mode-tests.el
diff options
context:
space:
mode:
authorStefan Monnier <monnier@iro.umontreal.ca>2022-09-25 16:15:16 -0400
committerStefan Monnier <monnier@iro.umontreal.ca>2022-09-25 16:15:16 -0400
commit650c20f1ca4e07591a727e1cfcc74b3363d15985 (patch)
tree85d11f6437cde22f410c25e0e5f71a3131ebd07d /test/lisp/progmodes/elisp-mode-tests.el
parent8869332684c2302b5ba1ead4568bbc7ba1c0183e (diff)
parent4b85ae6a24380fb67a3315eaec9233f17a872473 (diff)
downloademacs-650c20f1ca4e07591a727e1cfcc74b3363d15985.tar.gz
emacs-650c20f1ca4e07591a727e1cfcc74b3363d15985.tar.bz2
emacs-650c20f1ca4e07591a727e1cfcc74b3363d15985.zip
Merge 'master' into noverlay
Diffstat (limited to 'test/lisp/progmodes/elisp-mode-tests.el')
-rw-r--r--test/lisp/progmodes/elisp-mode-tests.el471
1 files changed, 400 insertions, 71 deletions
diff --git a/test/lisp/progmodes/elisp-mode-tests.el b/test/lisp/progmodes/elisp-mode-tests.el
index a6c64edeb7f..e73be0db504 100644
--- a/test/lisp/progmodes/elisp-mode-tests.el
+++ b/test/lisp/progmodes/elisp-mode-tests.el
@@ -1,6 +1,6 @@
;;; elisp-mode-tests.el --- Tests for emacs-lisp-mode -*- lexical-binding: t; -*-
-;; Copyright (C) 2015-2017 Free Software Foundation, Inc.
+;; Copyright (C) 2015-2022 Free Software Foundation, Inc.
;; Author: Dmitry Gutov <dgutov@yandex.ru>
;; Author: Stephen Leake <stephen_leake@member.fsf.org>
@@ -23,8 +23,10 @@
;;; Code:
(require 'ert)
+(require 'ert-x)
(require 'xref)
(eval-when-compile (require 'cl-lib))
+(require 'ert-x)
;;; Completion
@@ -107,7 +109,7 @@
(should (member "backup-inhibited" comps))
(should-not (member "backup-buffer" comps))))))
-(ert-deftest elisp-completes-functions-after-let-bindings ()
+(ert-deftest elisp-completes-functions-after-let-bindings-2 ()
(with-temp-buffer
(emacs-lisp-mode)
(insert "(let ((bar 1) (baz 2)) (ba")
@@ -181,6 +183,16 @@
(call-interactively #'eval-last-sexp)
(should (equal (current-message) "66 (#o102, #x42, ?B)"))))))
+;;; eval-defun
+
+(ert-deftest eval-defun-prints-edebug-when-instrumented ()
+ (skip-unless (not noninteractive))
+ (with-temp-buffer
+ (let ((current-prefix-arg '(4)))
+ (erase-buffer) (insert "(defun foo ())") (message nil)
+ (call-interactively #'eval-defun)
+ (should (equal (current-message) "Edebug: foo")))))
+
;;; eldoc
(defun elisp-mode-tests--face-propertized-string (string)
@@ -194,7 +206,7 @@
(dotimes (i 3)
(should
(equal (elisp-mode-tests--face-propertized-string
- (elisp--highlight-function-argument 'foo "(A B C)" (1+ i) "foo: "))
+ (elisp--highlight-function-argument 'foo "(A B C)" (1+ i)))
(propertize (nth i '("A" "B" "C"))
'face 'eldoc-highlight-function-argument)))))
@@ -206,7 +218,7 @@
(cl-flet ((bold-arg (i)
(elisp-mode-tests--face-propertized-string
(elisp--highlight-function-argument
- 'foo "(PROMPT LST &key A B C)" i "foo: "))))
+ 'foo "(PROMPT LST &key A B C)" i))))
(should-not (bold-arg 0))
(progn (forward-sexp) (forward-char))
(should (equal (bold-arg 1) "PROMPT"))
@@ -226,7 +238,7 @@
(cl-flet ((bold-arg (i)
(elisp-mode-tests--face-propertized-string
(elisp--highlight-function-argument
- 'foo "(X &key A B C)" i "foo: "))))
+ 'foo "(X &key A B C)" i))))
(should-not (bold-arg 0))
;; The `:b' specifies positional arg `X'.
(progn (forward-sexp) (forward-char))
@@ -298,20 +310,41 @@
)))
+;; tmp may be on a different filesystem to the tests, but, ehh.
+(defvar xref--case-insensitive
+ (ert-with-temp-directory dir
+ (with-temp-file (expand-file-name "hElLo" dir) "hello")
+ (file-exists-p (expand-file-name "HELLO" dir)))
+ "Non-nil if file system seems to be case-insensitive.")
+
(defun xref-elisp-test-run (xrefs expected-xrefs)
(should (= (length xrefs) (length expected-xrefs)))
(while xrefs
(let* ((xref (pop xrefs))
(expected (pop expected-xrefs))
(expected-xref (or (when (consp expected) (car expected)) expected))
- (expected-source (when (consp expected) (cdr expected))))
+ (expected-source (when (consp expected) (cdr expected)))
+ (xref-file (xref-elisp-location-file (xref-item-location xref)))
+ (expected-file (xref-elisp-location-file
+ (xref-item-location expected-xref))))
+
+ ;; Make sure file names compare as strings.
+ (when (file-name-absolute-p xref-file)
+ (setf (xref-elisp-location-file (xref-item-location xref))
+ (file-truename (xref-elisp-location-file (xref-item-location xref)))))
+ (when (file-name-absolute-p expected-file)
+ (setf (xref-elisp-location-file (xref-item-location expected-xref))
+ (file-truename (xref-elisp-location-file
+ (xref-item-location expected-xref)))))
;; Downcase the filenames for case-insensitive file systems.
- (setf (xref-elisp-location-file (oref xref location))
- (downcase (xref-elisp-location-file (oref xref location))))
+ (when xref--case-insensitive
+ (setf (xref-elisp-location-file (xref-item-location xref))
+ (downcase (xref-elisp-location-file (xref-item-location xref))))
- (setf (xref-elisp-location-file (oref expected-xref location))
- (downcase (xref-elisp-location-file (oref expected-xref location))))
+ (setf (xref-elisp-location-file (xref-item-location expected-xref))
+ (downcase (xref-elisp-location-file
+ (xref-item-location expected-xref)))))
(should (equal xref expected-xref))
@@ -346,10 +379,10 @@ to (xref-elisp-test-descr-to-target xref)."
;; `load-path' has the correct case, so this causes the expected test
;; values to have the wrong case). This is handled in
;; `xref-elisp-test-run'.
-(defconst emacs-test-dir
- (downcase
- (file-truename (file-name-directory
- (or load-file-name (buffer-file-name))))))
+(defvar emacs-test-dir
+ (funcall (if xref--case-insensitive 'downcase 'identity)
+ (file-truename (file-name-directory
+ (or load-file-name (buffer-file-name))))))
;; alphabetical by test name
@@ -374,23 +407,24 @@ to (xref-elisp-test-descr-to-target xref)."
"(cl-defstruct (xref-elisp-location")
))
+(require 'em-xtra)
+(require 'find-dired)
(xref-elisp-deftest find-defs-defalias-defun-el
- (elisp--xref-find-definitions 'Buffer-menu-sort)
+ (elisp--xref-find-definitions 'eshell/ff)
(list
- (xref-make "(defalias Buffer-menu-sort)"
+ (xref-make "(defalias eshell/ff)"
(xref-make-elisp-location
- 'Buffer-menu-sort 'defalias
- (expand-file-name "../../../lisp/buff-menu.elc" emacs-test-dir)))
- (xref-make "(defun tabulated-list-sort)"
+ 'eshell/ff 'defalias
+ (expand-file-name "../../../lisp/eshell/em-xtra.elc"
+ emacs-test-dir)))
+ (xref-make "(defun find-name-dired)"
(xref-make-elisp-location
- 'tabulated-list-sort nil
- (expand-file-name "../../../lisp/emacs-lisp/tabulated-list.el" emacs-test-dir)))
- ))
+ 'find-name-dired nil
+ (expand-file-name "../../../lisp/find-dired.el"
+ emacs-test-dir)))))
;; FIXME: defconst
-;; FIXME: eieio defclass
-
;; Possible ways of defining the default method implementation for a
;; generic function. We declare these here, so we know we cover all
;; cases, and we don't rely on other code not changing.
@@ -402,7 +436,7 @@ to (xref-elisp-test-descr-to-target xref)."
slot-1)
(cl-defgeneric xref-elisp-generic-no-methods (arg1 arg2)
- "doc string generic no-methods"
+ "Doc string generic no-methods."
;; No default implementation, no methods, but fboundp is true for
;; this symbol; it calls cl-no-applicable-method
)
@@ -413,45 +447,52 @@ to (xref-elisp-test-descr-to-target xref)."
;; ‘this’. It passes in interactive tests, so I haven't been able to
;; track down the problem.
(cl-defmethod xref-elisp-generic-no-default ((this xref-elisp-root-type) arg2)
- "doc string generic no-default xref-elisp-root-type"
- "non-default for no-default")
+ "Doc string generic no-default xref-elisp-root-type."
+ "non-default for no-default"
+ (list this arg2)) ; silence byte-compiler
;; defgeneric after defmethod in file to ensure the fallback search
;; method of just looking for the function name will fail.
(cl-defgeneric xref-elisp-generic-no-default (arg1 arg2)
- "doc string generic no-default generic"
+ "Doc string generic no-default generic."
;; No default implementation; this function calls the cl-generic
;; dispatching code.
)
-(cl-defgeneric xref-elisp-generic-co-located-default (arg1 arg2)
- "doc string generic co-located-default"
- "co-located default")
+(with-no-warnings ; FIXME: Make more specific.
+ (cl-defgeneric xref-elisp-generic-co-located-default (arg1 arg2)
+ "Doc string generic co-located-default."
+ "co-located default"))
-(cl-defmethod xref-elisp-generic-co-located-default ((this xref-elisp-root-type) arg2)
- "doc string generic co-located-default xref-elisp-root-type"
- "non-default for co-located-default")
+(with-no-warnings ; FIXME: Make more specific.
+ (cl-defmethod xref-elisp-generic-co-located-default ((this xref-elisp-root-type) arg2)
+ "Doc string generic co-located-default xref-elisp-root-type."
+ "non-default for co-located-default"))
(cl-defgeneric xref-elisp-generic-separate-default (arg1 arg2)
- "doc string generic separate-default"
+ "Doc string generic separate-default."
;; default implementation provided separately
)
(cl-defmethod xref-elisp-generic-separate-default (arg1 arg2)
- "doc string generic separate-default default"
- "separate default")
+ "Doc string generic separate-default default."
+ "separate default"
+ (list arg1 arg2)) ; silence byte-compiler
(cl-defmethod xref-elisp-generic-separate-default ((this xref-elisp-root-type) arg2)
- "doc string generic separate-default xref-elisp-root-type"
- "non-default for separate-default")
+ "Doc string generic separate-default xref-elisp-root-type."
+ "non-default for separate-default"
+ (list this arg2)) ; silence byte-compiler
(cl-defmethod xref-elisp-generic-implicit-generic (arg1 arg2)
- "doc string generic implicit-generic default"
- "default for implicit generic")
+ "Doc string generic implicit-generic default."
+ "default for implicit generic"
+ (list arg1 arg2)) ; silence byte-compiler
(cl-defmethod xref-elisp-generic-implicit-generic ((this xref-elisp-root-type) arg2)
- "doc string generic implicit-generic xref-elisp-root-type"
- "non-default for implicit generic")
+ "Doc string generic implicit-generic xref-elisp-root-type."
+ "non-default for implicit generic"
+ (list this arg2)) ; silence byte-compiler
(xref-elisp-deftest find-defs-defgeneric-no-methods
@@ -577,47 +618,54 @@ to (xref-elisp-test-descr-to-target xref)."
'xref-location-marker nil '(xref-etags-location))
'cl-defmethod
(expand-file-name "../../../lisp/progmodes/etags.el" emacs-test-dir)))
+ (xref-make "(cl-defmethod xref-location-marker ((l xref-etags-apropos-location)))"
+ (xref-make-elisp-location
+ (cl--generic-load-hist-format
+ 'xref-location-marker nil '(xref-etags-apropos-location))
+ 'cl-defmethod
+ (expand-file-name "../../../lisp/progmodes/etags.el" emacs-test-dir)))
))
(xref-elisp-deftest find-defs-defgeneric-eval
- (elisp--xref-find-definitions (eval '(cl-defgeneric stephe-leake-cl-defgeneric ())))
+ (elisp--xref-find-definitions (eval '(cl-defgeneric stephe-leake-cl-defgeneric ()) t))
nil)
;; Define some mode-local overloadable/overridden functions for xref to find
(require 'mode-local)
+(declare-function xref-elisp-overloadable-no-methods-default "elisp-mode-tests")
+(declare-function xref-elisp-overloadable-no-default-default "elisp-mode-tests")
+
(define-overloadable-function xref-elisp-overloadable-no-methods ()
- "doc string overloadable no-methods")
+ "Doc string overloadable no-methods.")
(define-overloadable-function xref-elisp-overloadable-no-default ()
- "doc string overloadable no-default")
+ "Doc string overloadable no-default.")
-;; FIXME: byte compiler complains about unused lexical arguments
-;; generated by this macro.
(define-mode-local-override xref-elisp-overloadable-no-default c-mode
- (start end &optional nonterminal depth returnonerror)
- "doc string overloadable no-default c-mode."
+ (_start _end &optional _nonterminal _depth _returnonerror)
+ "Doc string overloadable no-default c-mode."
"result overloadable no-default c-mode.")
(define-overloadable-function xref-elisp-overloadable-co-located-default ()
- "doc string overloadable co-located-default"
+ "Doc string overloadable co-located-default."
"result overloadable co-located-default.")
(define-mode-local-override xref-elisp-overloadable-co-located-default c-mode
- (start end &optional nonterminal depth returnonerror)
- "doc string overloadable co-located-default c-mode."
+ (_start _end &optional _nonterminal _depth _returnonerror)
+ "Doc string overloadable co-located-default c-mode."
"result overloadable co-located-default c-mode.")
(define-overloadable-function xref-elisp-overloadable-separate-default ()
- "doc string overloadable separate-default.")
+ "Doc string overloadable separate-default.")
(defun xref-elisp-overloadable-separate-default-default ()
- "doc string overloadable separate-default default"
+ "Doc string overloadable separate-default default."
"result overloadable separate-default.")
(define-mode-local-override xref-elisp-overloadable-separate-default c-mode
- (start end &optional nonterminal depth returnonerror)
- "doc string overloadable separate-default c-mode."
+ (_start _end &optional _nonterminal _depth _returnonerror)
+ "Doc string overloadable separate-default c-mode."
"result overloadable separate-default c-mode.")
(xref-elisp-deftest find-defs-define-overload-no-methods
@@ -681,7 +729,7 @@ to (xref-elisp-test-descr-to-target xref)."
(expand-file-name "../../../lisp/progmodes/xref.el" emacs-test-dir)))))
(xref-elisp-deftest find-defs-defun-eval
- (elisp--xref-find-definitions (eval '(defun stephe-leake-defun ())))
+ (elisp--xref-find-definitions (eval '(defun stephe-leake-defun ()) t))
nil)
(xref-elisp-deftest find-defs-defun-c
@@ -718,15 +766,11 @@ to (xref-elisp-test-descr-to-target xref)."
;; Source for both variable and defun is "(define-minor-mode
;; compilation-minor-mode". There is no way to tell that directly from
;; the symbol, but we can use (memq sym minor-mode-list) to detect
-;; that the symbol is a minor mode. See `elisp--xref-find-definitions'
-;; for more comments.
-;;
-;; IMPROVEME: return defvar instead of defun if source near starting
-;; point indicates the user is searching for a variable, not a
-;; function.
+;; that the symbol is a minor mode. In non-filtering mode we only
+;; return the function.
(require 'compile) ;; not loaded by default at test time
(xref-elisp-deftest find-defs-defun-defvar-el
- (elisp--xref-find-definitions 'compilation-minor-mode)
+ (xref-backend-definitions 'elisp "compilation-minor-mode")
(list
(cons
(xref-make "(defun compilation-minor-mode)"
@@ -736,12 +780,27 @@ to (xref-elisp-test-descr-to-target xref)."
"(define-minor-mode compilation-minor-mode")
))
+;; Returning only defvar because source near point indicates the user
+;; is searching for a variable, not a function.
+(xref-elisp-deftest find-defs-minor-defvar-c
+ (with-temp-buffer
+ (emacs-lisp-mode)
+ (insert "(foo overwrite-mode")
+ (xref-backend-definitions 'elisp
+ (xref-backend-identifier-at-point 'elisp)))
+ (list
+ (cons
+ (xref-make "(defvar overwrite-mode)"
+ (xref-make-elisp-location 'overwrite-mode 'defvar "src/buffer.c"))
+ "DEFVAR_PER_BUFFER (\"overwrite-mode\"")
+ ))
+
(xref-elisp-deftest find-defs-defvar-el
- (elisp--xref-find-definitions 'xref--marker-ring)
+ (elisp--xref-find-definitions 'xref--history)
(list
- (xref-make "(defvar xref--marker-ring)"
+ (xref-make "(defvar xref--history)"
(xref-make-elisp-location
- 'xref--marker-ring 'defvar
+ 'xref--history 'defvar
(expand-file-name "../../../lisp/progmodes/xref.el" emacs-test-dir)))
))
@@ -755,7 +814,7 @@ to (xref-elisp-test-descr-to-target xref)."
"DEFVAR_PER_BUFFER (\"default-directory\"")))
(xref-elisp-deftest find-defs-defvar-eval
- (elisp--xref-find-definitions (eval '(defvar stephe-leake-defvar nil)))
+ (elisp--xref-find-definitions (eval '(defvar stephe-leake-defvar nil) t))
nil)
(xref-elisp-deftest find-defs-face-el
@@ -773,7 +832,7 @@ to (xref-elisp-test-descr-to-target xref)."
))
(xref-elisp-deftest find-defs-face-eval
- (elisp--xref-find-definitions (eval '(defface stephe-leake-defface nil "")))
+ (elisp--xref-find-definitions (eval '(defface stephe-leake-defface nil "") t))
nil)
(xref-elisp-deftest find-defs-feature-el
@@ -788,7 +847,7 @@ to (xref-elisp-test-descr-to-target xref)."
))
(xref-elisp-deftest find-defs-feature-eval
- (elisp--xref-find-definitions (eval '(provide 'stephe-leake-feature)))
+ (elisp--xref-find-definitions (eval '(provide 'stephe-leake-feature) t))
nil)
(ert-deftest elisp--preceding-sexp--char-name ()
@@ -797,5 +856,275 @@ to (xref-elisp-test-descr-to-target xref)."
(insert "?\\N{HEAVY CHECK MARK}")
(should (equal (elisp--preceding-sexp) ?\N{HEAVY CHECK MARK}))))
+(defun test--font (form search)
+ (with-temp-buffer
+ (emacs-lisp-mode)
+ (if (stringp form)
+ (insert form)
+ (pp form (current-buffer)))
+ (with-suppressed-warnings ((interactive-only font-lock-debug-fontify))
+ (font-lock-debug-fontify))
+ (goto-char (point-min))
+ (and (re-search-forward search nil t)
+ (get-text-property (match-beginning 1) 'face))))
+
+(ert-deftest test-elisp-font-keywords-1 ()
+ ;; Special form.
+ (should (eq (test--font '(if foo bar) "(\\(if\\)")
+ 'font-lock-keyword-face))
+ ;; Macro.
+ (should (eq (test--font '(when foo bar) "(\\(when\\)")
+ 'font-lock-keyword-face))
+ (should (eq (test--font '(condition-case nil
+ (foo)
+ (error (if a b)))
+ "(\\(if\\)")
+ 'font-lock-keyword-face))
+ (should (eq (test--font '(condition-case nil
+ (foo)
+ (when (if a b)))
+ "(\\(when\\)")
+ 'nil)))
+
+(ert-deftest test-elisp-font-keywords-2 ()
+ (should (eq (test--font '(condition-case nil
+ (foo)
+ (error (when a b)))
+ "(\\(when\\)")
+ 'font-lock-keyword-face)))
+
+(ert-deftest test-elisp-font-keywords-3 ()
+ (should (eq (test--font '(setq a '(if when zot))
+ "(\\(if\\)")
+ nil)))
+
+(ert-deftest test-elisp-font-keywords-4 ()
+ :expected-result :failed ; FIXME bug#43265
+ (should (eq (test--font '(condition-case nil
+ (foo)
+ ((if foo) (when a b)))
+ "(\\(if\\)")
+ nil)))
+
+(ert-deftest test-elisp-font-keywords-5 ()
+ (should (eq (test--font '(condition-case (when a)
+ (foo)
+ (error t))
+ "(\\(when\\)")
+ nil)))
+
+(defmacro elisp-mode-test--with-buffer (text-with-pos &rest body)
+ "Eval BODY with buffer and variables from TEXT-WITH-POS.
+All occurrences of {NAME} are removed from TEXT-WITH-POS and
+the remaining text put in a buffer in `elisp-mode'.
+Each NAME is then bound to its position in the text during the
+evaluation of BODY."
+ (declare (indent 1))
+ (let* ((annot-text (eval text-with-pos t))
+ (pieces nil)
+ (positions nil)
+ (tlen (length annot-text))
+ (ofs 0)
+ (text-ofs 0))
+ (while
+ (and (< ofs tlen)
+ (let ((m (string-match (rx "{" (group (+ (not "}"))) "}")
+ annot-text ofs)))
+ (and m
+ (let ((var (intern (match-string 1 annot-text))))
+ (push (substring annot-text ofs m) pieces)
+ (setq text-ofs (+ text-ofs (- m ofs)))
+ (push (list var (1+ text-ofs)) positions)
+ (setq ofs (match-end 0))
+ t)))))
+ (push (substring annot-text ofs tlen) pieces)
+ (let ((text (apply #'concat (nreverse pieces)))
+ (bindings (nreverse positions)))
+ `(with-temp-buffer
+ (ert-info (,text :prefix "text: ")
+ (emacs-lisp-mode)
+ (insert ,text)
+ (let ,bindings . ,body))))))
+
+(ert-deftest elisp-mode-with-buffer ()
+ ;; Sanity test of macro, also demonstrating how it works.
+ (elisp-mode-test--with-buffer
+ "{a}123{b}45{c}6"
+ (should (equal a 1))
+ (should (equal b 4))
+ (should (equal c 6))
+ (should (equal (buffer-string) "123456"))))
+
+(ert-deftest elisp-mode-infer-namespace ()
+ (elisp-mode-test--with-buffer
+ (concat " ({p1}alphaX {p2}beta {p3}gamma '{p4}delta\n"
+ " #'{p5}epsilon `{p6}zeta `(,{p7}eta ,@{p8}theta))\n")
+ (should (equal (elisp--xref-infer-namespace p1) 'function))
+ (should (equal (elisp--xref-infer-namespace p2) 'maybe-variable))
+ (should (equal (elisp--xref-infer-namespace p3) 'maybe-variable))
+ (should (equal (elisp--xref-infer-namespace p4) 'any))
+ (should (equal (elisp--xref-infer-namespace p5) 'function))
+ (should (equal (elisp--xref-infer-namespace p6) 'any))
+ (should (equal (elisp--xref-infer-namespace p7) 'variable))
+ (should (equal (elisp--xref-infer-namespace p8) 'variable)))
+
+ (elisp-mode-test--with-buffer
+ (concat "(let ({p1}alpha {p2}beta ({p3}gamma {p4}delta))\n"
+ " ({p5}epsilon {p6}zeta)\n"
+ " {p7}eta)\n")
+ (should (equal (elisp--xref-infer-namespace p1) 'variable))
+ (should (equal (elisp--xref-infer-namespace p2) 'variable))
+ (should (equal (elisp--xref-infer-namespace p3) 'variable))
+ (should (equal (elisp--xref-infer-namespace p4) 'variable))
+ (should (equal (elisp--xref-infer-namespace p5) 'function))
+ (should (equal (elisp--xref-infer-namespace p6) 'maybe-variable))
+ (should (equal (elisp--xref-infer-namespace p7) 'variable)))
+
+ (elisp-mode-test--with-buffer
+ (concat "(let (({p1}alpha {p2}beta)\n"
+ " ({p3}gamma ({p4}delta {p5}epsilon)))\n"
+ " ({p6}zeta))\n")
+ (should (equal (elisp--xref-infer-namespace p1) 'variable))
+ (should (equal (elisp--xref-infer-namespace p2) 'variable))
+ (should (equal (elisp--xref-infer-namespace p3) 'variable))
+ (should (equal (elisp--xref-infer-namespace p4) 'function))
+ (should (equal (elisp--xref-infer-namespace p5) 'maybe-variable))
+ (should (equal (elisp--xref-infer-namespace p6) 'function)))
+
+ (elisp-mode-test--with-buffer
+ (concat "(defun {p1}alpha () {p2}beta)\n"
+ "(defface {p3}gamma ...)\n"
+ "(defvar {p4}delta {p5}epsilon)\n"
+ "(function {p6}zeta)\n")
+ (should (equal (elisp--xref-infer-namespace p1) 'function))
+ (should (equal (elisp--xref-infer-namespace p2) 'variable))
+ (should (equal (elisp--xref-infer-namespace p3) 'face))
+ (should (equal (elisp--xref-infer-namespace p4) 'variable))
+ (should (equal (elisp--xref-infer-namespace p5) 'variable))
+ (should (equal (elisp--xref-infer-namespace p6) 'function)))
+
+ (elisp-mode-test--with-buffer
+ (concat "(require '{p1}alpha)\n"
+ "(fboundp '{p2}beta)\n"
+ "(boundp '{p3}gamma)\n"
+ "(facep '{p4}delta)\n"
+ "(define-key map [f1] '{p5}epsilon)\n")
+ (should (equal (elisp--xref-infer-namespace p1) 'feature))
+ (should (equal (elisp--xref-infer-namespace p2) 'function))
+ (should (equal (elisp--xref-infer-namespace p3) 'variable))
+ (should (equal (elisp--xref-infer-namespace p4) 'face))
+ (should (equal (elisp--xref-infer-namespace p5) 'function)))
+
+ (elisp-mode-test--with-buffer
+ (concat "(list {p1}alpha {p2}beta)\n"
+ "(progn {p3}gamma {p4}delta)\n"
+ "(lambda ({p5}epsilon {p6}zeta) {p7}eta)\n")
+ (should (equal (elisp--xref-infer-namespace p1) 'variable))
+ (should (equal (elisp--xref-infer-namespace p2) 'variable))
+ (should (equal (elisp--xref-infer-namespace p3) 'variable))
+ (should (equal (elisp--xref-infer-namespace p4) 'variable))
+ (should (equal (elisp--xref-infer-namespace p5) 'variable))
+ (should (equal (elisp--xref-infer-namespace p6) 'variable))
+ (should (equal (elisp--xref-infer-namespace p7) 'variable)))
+
+ (elisp-mode-test--with-buffer
+ (concat "'({p1}alpha {p2}beta\n"
+ " ({p3}gamma ({p4}delta)))\n")
+ (should (equal (elisp--xref-infer-namespace p1) 'any))
+ (should (equal (elisp--xref-infer-namespace p2) 'any))
+ (should (equal (elisp--xref-infer-namespace p3) 'any))
+ (should (equal (elisp--xref-infer-namespace p4) 'any))))
+
+
+(ert-deftest elisp-shorthand-read-buffer ()
+ (let* ((gsym (downcase (symbol-name (cl-gensym "sh-"))))
+ (shorthand-sname (format "s-%s" gsym))
+ (expected (intern (format "shorthand-longhand-%s" gsym))))
+ (cl-assert (not (intern-soft shorthand-sname)))
+ (should (equal (let ((read-symbol-shorthands
+ '(("s-" . "shorthand-longhand-"))))
+ (with-temp-buffer
+ (insert shorthand-sname)
+ (goto-char (point-min))
+ (read (current-buffer))))
+ expected))
+ (should (not (intern-soft shorthand-sname)))))
+
+(ert-deftest elisp-shorthand-read-from-string ()
+ (let* ((gsym (downcase (symbol-name (cl-gensym "sh-"))))
+ (shorthand-sname (format "s-%s" gsym))
+ (expected (intern (format "shorthand-longhand-%s" gsym))))
+ (cl-assert (not (intern-soft shorthand-sname)))
+ (should (equal (let ((read-symbol-shorthands
+ '(("s-" . "shorthand-longhand-"))))
+ (car (read-from-string shorthand-sname)))
+ expected))
+ (should (not (intern-soft shorthand-sname)))))
+
+(ert-deftest elisp-shorthand-load-a-file ()
+ (let ((test-file (ert-resource-file "simple-shorthand-test.el")))
+ (mapatoms (lambda (s)
+ (when (string-match "^elisp--foo-" (symbol-name s))
+ (unintern s obarray))))
+ (load test-file)
+ (should (intern-soft "elisp--foo-test"))
+ (should-not (intern-soft "f-test"))))
+
+(ert-deftest elisp-shorthand-byte-compile-a-file ()
+
+ (let ((test-file (ert-resource-file "simple-shorthand-test.el"))
+ (byte-compiled (ert-resource-file "simple-shorthand-test.elc")))
+ (mapatoms (lambda (s)
+ (when (string-match "^elisp--foo-" (symbol-name s))
+ (unintern s obarray))))
+ (byte-compile-file test-file)
+ (should-not (intern-soft "f-test"))
+ (should (intern-soft "elisp--foo-test"))
+ (should-not (fboundp (intern-soft "elisp--foo-test")))
+ (load byte-compiled)
+ (should (intern-soft "elisp--foo-test"))
+ (should-not (intern-soft "f-test"))))
+
+(ert-deftest elisp-shorthand-completion-at-point ()
+ (let ((test-file (ert-resource-file "simple-shorthand-test.el")))
+ (load test-file)
+ (with-current-buffer (find-file-noselect test-file)
+ (revert-buffer t t)
+ (goto-char (point-min))
+ (insert "f-test-compl")
+ (completion-at-point)
+ (goto-char (point-min))
+ (should (search-forward "f-test-complete-me" (pos-eol) t))
+ (goto-char (point-min))
+ (should (string= (symbol-name (read (current-buffer)))
+ "elisp--foo-test-complete-me"))
+ (revert-buffer t t))))
+
+(ert-deftest elisp-shorthand-escape ()
+ (let ((test-file (ert-resource-file "simple-shorthand-test.el")))
+ (load test-file)
+ (should (intern-soft "f-test4---"))
+ (should-not (intern-soft "elisp--foo-test4---"))
+ (should (= 84 (funcall (intern-soft "f-test4---"))))
+ (should (unintern "f-test4---"))))
+
+(ert-deftest elisp-dont-shadow-punctuation-only-symbols ()
+ (let* ((shorthanded-form '(/= 42 (-foo 42)))
+ (expected-longhand-form '(/= 42 (fooey-foo 42)))
+ (observed (let ((read-symbol-shorthands
+ '(("-" . "fooey-"))))
+ (car (read-from-string
+ (with-temp-buffer
+ (print shorthanded-form (current-buffer))
+ (buffer-string)))))))
+ (should (equal observed expected-longhand-form))))
+
+(ert-deftest test-indentation ()
+ (ert-test-erts-file (ert-resource-file "elisp-indents.erts"))
+ (ert-test-erts-file (ert-resource-file "flet.erts")
+ (lambda ()
+ (emacs-lisp-mode)
+ (indent-region (point-min) (point-max)))))
+
(provide 'elisp-mode-tests)
;;; elisp-mode-tests.el ends here