aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorJim Porter2022-03-08 17:07:26 -0800
committerEli Zaretskii2022-04-17 10:27:39 +0300
commitbbb92dde01ec3fc46b24247fb2d181a21dbcc40a (patch)
tree46c8eaede0f5d432d447fefb768338f9e847ef4a /test
parent265f4ef70233c4708cbbdeb1850541570c40fdd6 (diff)
downloademacs-bbb92dde01ec3fc46b24247fb2d181a21dbcc40a.tar.gz
emacs-bbb92dde01ec3fc46b24247fb2d181a21dbcc40a.zip
Add unit tests and documentation for Eshell pattern-based globs
* lisp/eshell/em-glob.el (eshell-extended-glob): Fix docstring. (eshell-glob-entries): Refer to '**/' in error (technically, '**' can end a glob, but it means the same thing as '*'). (Bug#54470) * test/lisp/eshell/em-glob-tests.el: New file. * doc/misc/eshell.texi (Globbing): Document pattern-based globs.
Diffstat (limited to 'test')
-rw-r--r--test/lisp/eshell/em-glob-tests.el171
1 files changed, 171 insertions, 0 deletions
diff --git a/test/lisp/eshell/em-glob-tests.el b/test/lisp/eshell/em-glob-tests.el
new file mode 100644
index 00000000000..9976b32ffe7
--- /dev/null
+++ b/test/lisp/eshell/em-glob-tests.el
@@ -0,0 +1,171 @@
1;;; em-glob-tests.el --- em-glob test suite -*- lexical-binding:t -*-
2
3;; Copyright (C) 2022 Free Software Foundation, Inc.
4
5;; This file is part of GNU Emacs.
6
7;; GNU Emacs is free software: you can redistribute it and/or modify
8;; it under the terms of the GNU General Public License as published by
9;; the Free Software Foundation, either version 3 of the License, or
10;; (at your option) any later version.
11
12;; GNU Emacs is distributed in the hope that it will be useful,
13;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15;; GNU General Public License for more details.
16
17;; You should have received a copy of the GNU General Public License
18;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
19
20;;; Commentary:
21
22;; Tests for Eshell's glob expansion.
23
24;;; Code:
25
26(require 'ert)
27(require 'em-glob)
28
29(defmacro with-fake-files (files &rest body)
30 "Evaluate BODY forms, pretending that FILES exist on the filesystem.
31FILES is a list of file names that should be reported as
32appropriate by `file-name-all-completions'. Any file name
33component ending in \"symlink\" is treated as a symbolic link."
34 (declare (indent 1))
35 `(cl-letf (((symbol-function 'file-name-all-completions)
36 (lambda (file directory)
37 (cl-assert (string= file ""))
38 (setq directory (expand-file-name directory))
39 `("./" "../"
40 ,@(delete-dups
41 (remq nil
42 (mapcar
43 (lambda (file)
44 (setq file (expand-file-name file))
45 (when (string-prefix-p directory file)
46 (replace-regexp-in-string
47 "/.*" "/"
48 (substring file (length directory)))))
49 ,files))))))
50 ((symbol-function 'file-symlink-p)
51 (lambda (file)
52 (string-suffix-p "symlink" file))))
53 ,@body))
54
55;;; Tests:
56
57(ert-deftest em-glob-test/match-any-string ()
58 "Test that \"*\" pattern matches any string."
59 (with-fake-files '("a.el" "b.el" "c.txt" "dir/a.el")
60 (should (equal (eshell-extended-glob "*.el")
61 '("a.el" "b.el")))))
62
63(ert-deftest em-glob-test/match-any-character ()
64 "Test that \"?\" pattern matches any character."
65 (with-fake-files '("a.el" "b.el" "ccc.el" "d.txt" "dir/a.el")
66 (should (equal (eshell-extended-glob "?.el")
67 '("a.el" "b.el")))))
68
69(ert-deftest em-glob-test/match-recursive ()
70 "Test that \"**/\" recursively matches directories."
71 (with-fake-files '("a.el" "b.el" "ccc.el" "d.txt" "dir/a.el" "dir/sub/a.el"
72 "dir/symlink/a.el" "symlink/a.el" "symlink/sub/a.el")
73 (should (equal (eshell-extended-glob "**/a.el")
74 '("a.el" "dir/a.el" "dir/sub/a.el")))))
75
76(ert-deftest em-glob-test/match-recursive-follow-symlinks ()
77 "Test that \"***/\" recursively matches directories, following symlinks."
78 (with-fake-files '("a.el" "b.el" "ccc.el" "d.txt" "dir/a.el" "dir/sub/a.el"
79 "dir/symlink/a.el" "symlink/a.el" "symlink/sub/a.el")
80 (should (equal (eshell-extended-glob "***/a.el")
81 '("a.el" "dir/a.el" "dir/sub/a.el" "dir/symlink/a.el"
82 "symlink/a.el" "symlink/sub/a.el")))))
83
84(ert-deftest em-glob-test/match-recursive-mixed ()
85 "Test combination of \"**/\" and \"***/\"."
86 (with-fake-files '("dir/a.el" "dir/sub/a.el" "dir/sub2/a.el"
87 "dir/symlink/a.el" "dir/sub/symlink/a.el" "symlink/a.el"
88 "symlink/sub/a.el" "symlink/sub/symlink/a.el")
89 (should (equal (eshell-extended-glob "**/sub/***/a.el")
90 '("dir/sub/a.el" "dir/sub/symlink/a.el")))
91 (should (equal (eshell-extended-glob "***/sub/**/a.el")
92 '("dir/sub/a.el" "symlink/sub/a.el")))))
93
94(ert-deftest em-glob-test/match-character-set-individual ()
95 "Test \"[...]\" for individual characters."
96 (with-fake-files '("a.el" "b.el" "c.el" "d.el" "dir/a.el")
97 (should (equal (eshell-extended-glob "[ab].el")
98 '("a.el" "b.el")))
99 (should (equal (eshell-extended-glob "[^ab].el")
100 '("c.el" "d.el")))))
101
102(ert-deftest em-glob-test/match-character-set-range ()
103 "Test \"[...]\" for character ranges."
104 (with-fake-files '("a.el" "b.el" "c.el" "d.el" "dir/a.el")
105 (should (equal (eshell-extended-glob "[a-c].el")
106 '("a.el" "b.el" "c.el")))
107 (should (equal (eshell-extended-glob "[^a-c].el")
108 '("d.el")))))
109
110(ert-deftest em-glob-test/match-character-set-class ()
111 "Test \"[...]\" for character classes."
112 (with-fake-files '("1.el" "a.el" "b.el" "c.el" "dir/a.el")
113 (should (equal (eshell-extended-glob "[[:alpha:]].el")
114 '("a.el" "b.el" "c.el")))
115 (should (equal (eshell-extended-glob "[^[:alpha:]].el")
116 '("1.el")))))
117
118(ert-deftest em-glob-test/match-character-set-mixed ()
119 "Test \"[...]\" with multiple kinds of members at once."
120 (with-fake-files '("1.el" "a.el" "b.el" "c.el" "d.el" "dir/a.el")
121 (should (equal (eshell-extended-glob "[ac-d[:digit:]].el")
122 '("1.el" "a.el" "c.el" "d.el")))
123 (should (equal (eshell-extended-glob "[^ac-d[:digit:]].el")
124 '("b.el")))))
125
126(ert-deftest em-glob-test/match-group-alternative ()
127 "Test \"(x|y)\" matches either \"x\" or \"y\"."
128 (with-fake-files '("em-alias.el" "em-banner.el" "esh-arg.el" "misc.el"
129 "test/em-xtra.el")
130 (should (equal (eshell-extended-glob "e(m|sh)-*.el")
131 '("em-alias.el" "em-banner.el" "esh-arg.el")))))
132
133(ert-deftest em-glob-test/match-n-or-more-characters ()
134 "Test that \"x#\" and \"x#\" match zero or more instances of \"x\"."
135 (with-fake-files '("h.el" "ha.el" "hi.el" "hii.el" "dir/hi.el")
136 (should (equal (eshell-extended-glob "hi#.el")
137 '("h.el" "hi.el" "hii.el")))
138 (should (equal (eshell-extended-glob "hi##.el")
139 '("hi.el" "hii.el")))))
140
141(ert-deftest em-glob-test/match-n-or-more-groups ()
142 "Test that \"(x)#\" and \"(x)#\" match zero or more instances of \"(x)\"."
143 (with-fake-files '("h.el" "ha.el" "hi.el" "hii.el" "dir/hi.el")
144 (should (equal (eshell-extended-glob "hi#.el")
145 '("h.el" "hi.el" "hii.el")))
146 (should (equal (eshell-extended-glob "hi##.el")
147 '("hi.el" "hii.el")))))
148
149(ert-deftest em-glob-test/match-n-or-more-character-sets ()
150 "Test that \"[x]#\" and \"[x]#\" match zero or more instances of \"[x]\"."
151 (with-fake-files '("w.el" "wh.el" "wha.el" "whi.el" "whaha.el" "dir/wha.el")
152 (should (equal (eshell-extended-glob "w[ah]#.el")
153 '("w.el" "wh.el" "wha.el" "whaha.el")))
154 (should (equal (eshell-extended-glob "w[ah]##.el")
155 '("wh.el" "wha.el" "whaha.el")))))
156
157(ert-deftest em-glob-test/match-x-but-not-y ()
158 "Test that \"x~y\" matches \"x\" but not \"y\"."
159 (with-fake-files '("1" "12" "123" "42" "dir/1")
160 (should (equal (eshell-extended-glob "[[:digit:]]##~4?")
161 '("1" "12" "123")))))
162
163(ert-deftest em-glob-test/no-matches ()
164 "Test behavior when a glob fails to match any files."
165 (with-fake-files '("foo.el" "bar.el")
166 (should (equal (eshell-extended-glob "*.txt")
167 "*.txt"))
168 (let ((eshell-error-if-no-glob t))
169 (should-error (eshell-extended-glob "*.txt")))))
170
171;; em-glob-tests.el ends here