diff options
| author | Jim Porter | 2022-03-19 12:41:13 -0700 |
|---|---|---|
| committer | Eli Zaretskii | 2022-04-17 10:28:23 +0300 |
| commit | 6358cbc21a816ac95c2e6e22e087ccd3736874bc (patch) | |
| tree | 991f8731ca91f51f1c87380132b03b793c42c8ba /test | |
| parent | bbb92dde01ec3fc46b24247fb2d181a21dbcc40a (diff) | |
| download | emacs-6358cbc21a816ac95c2e6e22e087ccd3736874bc.tar.gz emacs-6358cbc21a816ac95c2e6e22e087ccd3736874bc.zip | |
Add unit tests and documentation for Eshell predicates/modifiers
* lisp/eshell/esh-cmd.el (eshell-eval-argument): New function.
* lisp/eshell/esh-util.el (eshell-file-attributes): Pass original
value of FILE to 'file-attributes'.
* lisp/eshell/em-pred.el (eshell-predicate-alist): Change socket char
to '=', since 's' conflicts with setuid.
(eshell-modifier-alist): Fix 'E' (eval) modifier by using
'eshell-eval-argument'. Also improve performance of 'O' (reversed
sort) modifier.
(eshell-modifier-help-string): Fix documentation of global
substitution modifier.
(eshell-pred-substitute): Fix infinite loop in some global
substitutions.
(eshell-join-members): Fix joining with implicit " " delimiter.
(Bug#54470)
* test/lisp/eshell/em-pred-tests.el: New file.
* doc/misc/eshell.texi (Argument Predication): New section.
Diffstat (limited to 'test')
| -rw-r--r-- | test/lisp/eshell/em-pred-tests.el | 521 |
1 files changed, 521 insertions, 0 deletions
diff --git a/test/lisp/eshell/em-pred-tests.el b/test/lisp/eshell/em-pred-tests.el new file mode 100644 index 00000000000..74dad9f8b87 --- /dev/null +++ b/test/lisp/eshell/em-pred-tests.el | |||
| @@ -0,0 +1,521 @@ | |||
| 1 | ;;; em-pred-tests.el --- em-pred 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 argument predicates/modifiers. | ||
| 23 | |||
| 24 | ;;; Code: | ||
| 25 | |||
| 26 | (require 'ert) | ||
| 27 | (require 'esh-mode) | ||
| 28 | (require 'eshell) | ||
| 29 | |||
| 30 | (require 'eshell-tests-helpers | ||
| 31 | (expand-file-name "eshell-tests-helpers" | ||
| 32 | (file-name-directory (or load-file-name | ||
| 33 | default-directory)))) | ||
| 34 | |||
| 35 | (defvar eshell-test-value nil) | ||
| 36 | |||
| 37 | (defun eshell-eval-predicate (initial-value predicate) | ||
| 38 | "Evaluate PREDICATE on INITIAL-VALUE, returning the result. | ||
| 39 | PREDICATE is an Eshell argument predicate/modifier." | ||
| 40 | (let ((eshell-test-value initial-value)) | ||
| 41 | (with-temp-eshell | ||
| 42 | (eshell-insert-command | ||
| 43 | (format "setq eshell-test-value $eshell-test-value(%s)" predicate))) | ||
| 44 | eshell-test-value)) | ||
| 45 | |||
| 46 | (defun eshell-parse-file-name-attributes (file) | ||
| 47 | "Parse a fake FILE name to determine its attributes. | ||
| 48 | Fake file names are file names beginning with \"/fake/\". This | ||
| 49 | allows defining file names for fake files with various properties | ||
| 50 | to query via predicates. Attributes are written as a | ||
| 51 | comma-separate list of ATTR=VALUE pairs as the file's base name, | ||
| 52 | like: | ||
| 53 | |||
| 54 | /fake/type=-,modes=0755.el | ||
| 55 | |||
| 56 | The following attributes are recognized: | ||
| 57 | |||
| 58 | * \"type\": A single character describing the file type; | ||
| 59 | accepts the same values as the first character of the file | ||
| 60 | modes in `ls -l'. | ||
| 61 | * \"modes\": The file's permission modes, in octal. | ||
| 62 | * \"links\": The number of links to this file. | ||
| 63 | * \"uid\": The UID of the file's owner. | ||
| 64 | * \"gid\": The UID of the file's group. | ||
| 65 | * \"atime\": The time the file was last accessed, in seconds | ||
| 66 | since the UNIX epoch. | ||
| 67 | * \"mtime\": As \"atime\", but for modification time. | ||
| 68 | * \"ctime\": As \"atime\", but for inode change time. | ||
| 69 | * \"size\": The file's size in bytes." | ||
| 70 | (mapcar (lambda (i) | ||
| 71 | (pcase (split-string i "=") | ||
| 72 | (`("modes" ,modes) | ||
| 73 | (cons 'modes (string-to-number modes 8))) | ||
| 74 | (`(,(and (or "links" "uid" "gid" "size") key) ,value) | ||
| 75 | (cons (intern key) (string-to-number value))) | ||
| 76 | (`(,(and (or "atime" "mtime" "ctime") key) ,value) | ||
| 77 | (cons (intern key) (time-convert (string-to-number value)))) | ||
| 78 | (`(,key ,value) | ||
| 79 | (cons (intern key) value)) | ||
| 80 | (_ (error "invalid format %S" i)))) | ||
| 81 | (split-string (file-name-base file) ","))) | ||
| 82 | |||
| 83 | (defmacro eshell-partial-let-func (overrides &rest body) | ||
| 84 | "Temporarily bind to FUNCTION-NAMEs and evaluate BODY. | ||
| 85 | This is roughly analogous to advising functions, but only does so | ||
| 86 | while BODY is executing, and only calls NEW-FUNCTION if its first | ||
| 87 | argument is a string beginning with \"/fake/\". | ||
| 88 | |||
| 89 | This allows selectively overriding functions to test file | ||
| 90 | properties with fake files without altering the functions' | ||
| 91 | behavior for real files. | ||
| 92 | |||
| 93 | \(fn ((FUNCTION-NAME NEW-FUNCTION) ...) BODY...)" | ||
| 94 | (declare (indent 1)) | ||
| 95 | `(cl-letf | ||
| 96 | ,(mapcar | ||
| 97 | (lambda (override) | ||
| 98 | (let ((orig-function (symbol-function (car override)))) | ||
| 99 | `((symbol-function #',(car override)) | ||
| 100 | (lambda (file &rest rest) | ||
| 101 | (apply | ||
| 102 | (if (and (stringp file) (string-prefix-p "/fake/" file)) | ||
| 103 | ,(cadr override) | ||
| 104 | ,orig-function) | ||
| 105 | file rest))))) | ||
| 106 | overrides) | ||
| 107 | ,@body)) | ||
| 108 | |||
| 109 | (defmacro eshell-with-file-attributes-from-name (&rest body) | ||
| 110 | "Temporarily override file attribute functions and evaluate BODY." | ||
| 111 | (declare (indent 0)) | ||
| 112 | `(eshell-partial-let-func | ||
| 113 | ((file-attributes | ||
| 114 | (lambda (file &optional _id-format) | ||
| 115 | (let ((attrs (eshell-parse-file-name-attributes file))) | ||
| 116 | (list (equal (alist-get 'type attrs) "d") | ||
| 117 | (or (alist-get 'links attrs) 1) | ||
| 118 | (or (alist-get 'uid attrs) 0) | ||
| 119 | (or (alist-get 'gid attrs) 0) | ||
| 120 | (or (alist-get 'atime attrs) nil) | ||
| 121 | (or (alist-get 'mtime attrs) nil) | ||
| 122 | (or (alist-get 'ctime attrs) nil) | ||
| 123 | (or (alist-get 'size attrs) 0) | ||
| 124 | (format "%s---------" (or (alist-get 'type attrs) "-")) | ||
| 125 | nil 0 0)))) | ||
| 126 | (file-modes | ||
| 127 | (lambda (file _nofollow) | ||
| 128 | (let ((attrs (eshell-parse-file-name-attributes file))) | ||
| 129 | (or (alist-get 'modes attrs) 0)))) | ||
| 130 | (file-exists-p #'always) | ||
| 131 | (file-regular-p | ||
| 132 | (lambda (file) | ||
| 133 | (let ((attrs (eshell-parse-file-name-attributes file))) | ||
| 134 | (member (or (alist-get 'type attrs) "-") '("-" "l"))))) | ||
| 135 | (file-symlink-p | ||
| 136 | (lambda (file) | ||
| 137 | (let ((attrs (eshell-parse-file-name-attributes file))) | ||
| 138 | (equal (alist-get 'type attrs) "l")))) | ||
| 139 | (file-executable-p | ||
| 140 | (lambda (file) | ||
| 141 | (let ((attrs (eshell-parse-file-name-attributes file))) | ||
| 142 | ;; For simplicity, just return whether the file is | ||
| 143 | ;; world-executable. | ||
| 144 | (= (logand (or (alist-get 'modes attrs) 0) 1) 1))))) | ||
| 145 | ,@body)) | ||
| 146 | |||
| 147 | ;;; Tests: | ||
| 148 | |||
| 149 | |||
| 150 | ;; Argument predicates | ||
| 151 | |||
| 152 | (ert-deftest em-pred-test/predicate-file-types () | ||
| 153 | "Test file type predicates." | ||
| 154 | (eshell-with-file-attributes-from-name | ||
| 155 | (let ((files (mapcar (lambda (i) (format "/fake/type=%s" i)) | ||
| 156 | '("b" "c" "d/" "p" "s" "l" "-")))) | ||
| 157 | (should (equal (eshell-eval-predicate files "%") | ||
| 158 | '("/fake/type=b" "/fake/type=c"))) | ||
| 159 | (should (equal (eshell-eval-predicate files "%b") '("/fake/type=b"))) | ||
| 160 | (should (equal (eshell-eval-predicate files "%c") '("/fake/type=c"))) | ||
| 161 | (should (equal (eshell-eval-predicate files "/") '("/fake/type=d/"))) | ||
| 162 | (should (equal (eshell-eval-predicate files ".") '("/fake/type=-"))) | ||
| 163 | (should (equal (eshell-eval-predicate files "p") '("/fake/type=p"))) | ||
| 164 | (should (equal (eshell-eval-predicate files "=") '("/fake/type=s"))) | ||
| 165 | (should (equal (eshell-eval-predicate files "@") '("/fake/type=l")))))) | ||
| 166 | |||
| 167 | (ert-deftest em-pred-test/predicate-executable () | ||
| 168 | "Test that \"*\" matches only regular, non-symlink executable files." | ||
| 169 | (eshell-with-file-attributes-from-name | ||
| 170 | (let ((files '("/fake/modes=0777" "/fake/modes=0666" | ||
| 171 | "/fake/type=d,modes=0777" "/fake/type=l,modes=0777"))) | ||
| 172 | (should (equal (eshell-eval-predicate files "*") | ||
| 173 | '("/fake/modes=0777")))))) | ||
| 174 | |||
| 175 | (defmacro em-pred-test--file-modes-deftest (name mode-template predicates | ||
| 176 | &optional docstring) | ||
| 177 | "Define NAME as a file-mode test. | ||
| 178 | MODE-TEMPLATE is a format string to convert an integer from 0 to | ||
| 179 | 7 to an octal file mode. PREDICATES is a list of strings for the | ||
| 180 | read, write, and execute predicates to query the file's modes." | ||
| 181 | (declare (indent 4) (doc-string 4)) | ||
| 182 | `(ert-deftest ,name () | ||
| 183 | ,docstring | ||
| 184 | (eshell-with-file-attributes-from-name | ||
| 185 | (let ((file-template (concat "/fake/modes=" ,mode-template))) | ||
| 186 | (cl-flet ((make-files (perms) | ||
| 187 | (mapcar (lambda (i) (format file-template i)) | ||
| 188 | perms))) | ||
| 189 | (pcase-let ((files (make-files (number-sequence 0 7))) | ||
| 190 | (`(,read ,write ,exec) ,predicates)) | ||
| 191 | (should (equal (eshell-eval-predicate files read) | ||
| 192 | (make-files '(4 5 6 7)))) | ||
| 193 | (should (equal (eshell-eval-predicate files (concat "^" read)) | ||
| 194 | (make-files '(0 1 2 3)))) | ||
| 195 | (should (equal (eshell-eval-predicate files write) | ||
| 196 | (make-files '(2 3 6 7)))) | ||
| 197 | (should (equal (eshell-eval-predicate files (concat "^" write)) | ||
| 198 | (make-files '(0 1 4 5)))) | ||
| 199 | (should (equal (eshell-eval-predicate files exec) | ||
| 200 | (make-files '(1 3 5 7)))) | ||
| 201 | (should (equal (eshell-eval-predicate files (concat "^" exec)) | ||
| 202 | (make-files '(0 2 4 6)))))))))) | ||
| 203 | |||
| 204 | (em-pred-test--file-modes-deftest em-pred-test/predicate-file-modes-owner | ||
| 205 | "0%o00" '("r" "w" "x") | ||
| 206 | "Test predicates for file permissions for the owner.") | ||
| 207 | |||
| 208 | (em-pred-test--file-modes-deftest em-pred-test/predicate-file-modes-group | ||
| 209 | "00%o0" '("A" "I" "E") | ||
| 210 | "Test predicates for file permissions for the group.") | ||
| 211 | |||
| 212 | (em-pred-test--file-modes-deftest em-pred-test/predicate-file-modes-world | ||
| 213 | "000%o" '("R" "W" "X") | ||
| 214 | "Test predicates for file permissions for the world.") | ||
| 215 | |||
| 216 | (em-pred-test--file-modes-deftest em-pred-test/predicate-file-modes-flags | ||
| 217 | "%o000" '("s" "S" "t") | ||
| 218 | "Test predicates for \"s\" (setuid), \"S\" (setgid), and \"t\" (sticky).") | ||
| 219 | |||
| 220 | (ert-deftest em-pred-test/predicate-effective-uid () | ||
| 221 | "Test that \"U\" matches files owned by the effective UID." | ||
| 222 | (eshell-with-file-attributes-from-name | ||
| 223 | (cl-letf (((symbol-function 'user-uid) (lambda () 1))) | ||
| 224 | (let ((files '("/fake/uid=1" "/fake/uid=2"))) | ||
| 225 | (should (equal (eshell-eval-predicate files "U") | ||
| 226 | '("/fake/uid=1"))))))) | ||
| 227 | |||
| 228 | (ert-deftest em-pred-test/predicate-links () | ||
| 229 | "Test that \"l\" filters by number of links." | ||
| 230 | (eshell-with-file-attributes-from-name | ||
| 231 | (let ((files '("/fake/links=1" "/fake/links=2" "/fake/links=3"))) | ||
| 232 | (should (equal (eshell-eval-predicate files "l1") | ||
| 233 | '("/fake/links=1"))) | ||
| 234 | (should (equal (eshell-eval-predicate files "l+1") | ||
| 235 | '("/fake/links=2" "/fake/links=3"))) | ||
| 236 | (should (equal (eshell-eval-predicate files "l-3") | ||
| 237 | '("/fake/links=1" "/fake/links=2")))))) | ||
| 238 | |||
| 239 | (ert-deftest em-pred-test/predicate-uid () | ||
| 240 | "Test that \"u\" filters by UID/user name." | ||
| 241 | (eshell-with-file-attributes-from-name | ||
| 242 | (let ((files '("/fake/uid=1" "/fake/uid=2")) | ||
| 243 | (user-names '("root" "one" "two"))) | ||
| 244 | (should (equal (eshell-eval-predicate files "u1") | ||
| 245 | '("/fake/uid=1"))) | ||
| 246 | (cl-letf (((symbol-function 'eshell-user-id) | ||
| 247 | (lambda (name) (seq-position user-names name)))) | ||
| 248 | (should (equal (eshell-eval-predicate files "u'one'") | ||
| 249 | '("/fake/uid=1"))) | ||
| 250 | (should (equal (eshell-eval-predicate files "u{one}") | ||
| 251 | '("/fake/uid=1"))))))) | ||
| 252 | |||
| 253 | (ert-deftest em-pred-test/predicate-gid () | ||
| 254 | "Test that \"g\" filters by GID/group name." | ||
| 255 | (eshell-with-file-attributes-from-name | ||
| 256 | (let ((files '("/fake/gid=1" "/fake/gid=2")) | ||
| 257 | (group-names '("root" "one" "two"))) | ||
| 258 | (should (equal (eshell-eval-predicate files "g1") | ||
| 259 | '("/fake/gid=1"))) | ||
| 260 | (cl-letf (((symbol-function 'eshell-group-id) | ||
| 261 | (lambda (name) (seq-position group-names name)))) | ||
| 262 | (should (equal (eshell-eval-predicate files "g'one'") | ||
| 263 | '("/fake/gid=1"))) | ||
| 264 | (should (equal (eshell-eval-predicate files "g{one}") | ||
| 265 | '("/fake/gid=1"))))))) | ||
| 266 | |||
| 267 | (defmacro em-pred-test--time-deftest (name file-attribute predicate | ||
| 268 | &optional docstring) | ||
| 269 | "Define NAME as a file-time test. | ||
| 270 | FILE-ATTRIBUTE is the file's attribute to set (e.g. \"atime\"). | ||
| 271 | PREDICATE is the predicate used to query that attribute." | ||
| 272 | (declare (indent 4) (doc-string 4)) | ||
| 273 | `(ert-deftest ,name () | ||
| 274 | ,docstring | ||
| 275 | (eshell-with-file-attributes-from-name | ||
| 276 | (cl-flet ((make-file (time) | ||
| 277 | (format "/fake/%s=%d" ,file-attribute time))) | ||
| 278 | (let* ((now (time-convert nil 'integer)) | ||
| 279 | (yesterday (- now 86400)) | ||
| 280 | (files (mapcar #'make-file (list now yesterday)))) | ||
| 281 | ;; Test comparison against a number of days. | ||
| 282 | (should (equal (eshell-eval-predicate | ||
| 283 | files (concat ,predicate "-1")) | ||
| 284 | (mapcar #'make-file (list now)))) | ||
| 285 | (should (equal (eshell-eval-predicate | ||
| 286 | files (concat ,predicate "+1")) | ||
| 287 | (mapcar #'make-file (list yesterday)))) | ||
| 288 | (should (equal (eshell-eval-predicate | ||
| 289 | files (concat ,predicate "+2")) | ||
| 290 | nil)) | ||
| 291 | ;; Test comparison against a number of hours. | ||
| 292 | (should (equal (eshell-eval-predicate | ||
| 293 | files (concat ,predicate "h-1")) | ||
| 294 | (mapcar #'make-file (list now)))) | ||
| 295 | (should (equal (eshell-eval-predicate | ||
| 296 | files (concat ,predicate "h+1")) | ||
| 297 | (mapcar #'make-file (list yesterday)))) | ||
| 298 | (should (equal (eshell-eval-predicate | ||
| 299 | files (concat ,predicate "+48")) | ||
| 300 | nil)) | ||
| 301 | ;; Test comparison against another file. | ||
| 302 | (should (equal (eshell-eval-predicate | ||
| 303 | files (format "%s-'%s'" ,predicate (make-file now))) | ||
| 304 | nil)) | ||
| 305 | (should (equal (eshell-eval-predicate | ||
| 306 | files (format "%s+'%s'" ,predicate (make-file now))) | ||
| 307 | (mapcar #'make-file (list yesterday))))))))) | ||
| 308 | |||
| 309 | (em-pred-test--time-deftest em-pred-test/predicate-access-time | ||
| 310 | "atime" "a" | ||
| 311 | "Test that \"a\" filters by access time.") | ||
| 312 | |||
| 313 | (em-pred-test--time-deftest em-pred-test/predicate-modification-time | ||
| 314 | "mtime" "m" | ||
| 315 | "Test that \"m\" filters by change time.") | ||
| 316 | |||
| 317 | (em-pred-test--time-deftest em-pred-test/predicate-change-time | ||
| 318 | "ctime" "c" | ||
| 319 | "Test that \"c\" filters by change time.") | ||
| 320 | |||
| 321 | (ert-deftest em-pred-test/predicate-size () | ||
| 322 | "Test that \"L\" filters by file size." | ||
| 323 | (eshell-with-file-attributes-from-name | ||
| 324 | (let ((files '("/fake/size=0" | ||
| 325 | ;; 1 and 2 KiB. | ||
| 326 | "/fake/size=1024" "/fake/size=2048" | ||
| 327 | ;; 1 and 2 MiB. | ||
| 328 | "/fake/size=1048576" "/fake/size=2097152"))) | ||
| 329 | ;; Size in bytes. | ||
| 330 | (should (equal (eshell-eval-predicate files "L2048") | ||
| 331 | '("/fake/size=2048"))) | ||
| 332 | (should (equal (eshell-eval-predicate files "L+2048") | ||
| 333 | '("/fake/size=1048576" "/fake/size=2097152"))) | ||
| 334 | (should (equal (eshell-eval-predicate files "L-2048") | ||
| 335 | '("/fake/size=0" "/fake/size=1024"))) | ||
| 336 | ;; Size in blocks. | ||
| 337 | (should (equal (eshell-eval-predicate files "Lp4") | ||
| 338 | '("/fake/size=2048"))) | ||
| 339 | (should (equal (eshell-eval-predicate files "Lp+4") | ||
| 340 | '("/fake/size=1048576" "/fake/size=2097152"))) | ||
| 341 | (should (equal (eshell-eval-predicate files "Lp-4") | ||
| 342 | '("/fake/size=0" "/fake/size=1024"))) | ||
| 343 | ;; Size in KiB. | ||
| 344 | (should (equal (eshell-eval-predicate files "Lk2") | ||
| 345 | '("/fake/size=2048"))) | ||
| 346 | (should (equal (eshell-eval-predicate files "Lk+2") | ||
| 347 | '("/fake/size=1048576" "/fake/size=2097152"))) | ||
| 348 | (should (equal (eshell-eval-predicate files "Lk-2") | ||
| 349 | '("/fake/size=0" "/fake/size=1024"))) | ||
| 350 | ;; Size in MiB. | ||
| 351 | (should (equal (eshell-eval-predicate files "LM1") | ||
| 352 | '("/fake/size=1048576"))) | ||
| 353 | (should (equal (eshell-eval-predicate files "LM+1") | ||
| 354 | '("/fake/size=2097152"))) | ||
| 355 | (should (equal (eshell-eval-predicate files "LM-1") | ||
| 356 | '("/fake/size=0" "/fake/size=1024" "/fake/size=2048")))))) | ||
| 357 | |||
| 358 | |||
| 359 | ;; Argument modifiers | ||
| 360 | |||
| 361 | (ert-deftest em-pred-test/modifier-eval () | ||
| 362 | "Test that \":E\" re-evaluates the value." | ||
| 363 | (should (equal (eshell-eval-predicate "${echo hi}" ":E") "hi")) | ||
| 364 | (should (equal (eshell-eval-predicate | ||
| 365 | '("${echo hi}" "$(upcase \"bye\")") ":E") | ||
| 366 | '("hi" "BYE")))) | ||
| 367 | |||
| 368 | (ert-deftest em-pred-test/modifier-downcase () | ||
| 369 | "Test that \":L\" downcases values." | ||
| 370 | (should (equal (eshell-eval-predicate "FOO" ":L") "foo")) | ||
| 371 | (should (equal (eshell-eval-predicate '("FOO" "BAR") ":L") | ||
| 372 | '("foo" "bar")))) | ||
| 373 | |||
| 374 | (ert-deftest em-pred-test/modifier-upcase () | ||
| 375 | "Test that \":U\" upcases values." | ||
| 376 | (should (equal (eshell-eval-predicate "foo" ":U") "FOO")) | ||
| 377 | (should (equal (eshell-eval-predicate '("foo" "bar") ":U") | ||
| 378 | '("FOO" "BAR")))) | ||
| 379 | |||
| 380 | (ert-deftest em-pred-test/modifier-capitalize () | ||
| 381 | "Test that \":C\" capitalizes values." | ||
| 382 | (should (equal (eshell-eval-predicate "foo bar" ":C") "Foo Bar")) | ||
| 383 | (should (equal (eshell-eval-predicate '("foo bar" "baz") ":C") | ||
| 384 | '("Foo Bar" "Baz")))) | ||
| 385 | |||
| 386 | (ert-deftest em-pred-test/modifier-dirname () | ||
| 387 | "Test that \":h\" returns the dirname." | ||
| 388 | (should (equal (eshell-eval-predicate "/path/to/file.el" ":h") "/path/to/")) | ||
| 389 | (should (equal (eshell-eval-predicate | ||
| 390 | '("/path/to/file.el" "/other/path/") ":h") | ||
| 391 | '("/path/to/" "/other/path/")))) | ||
| 392 | |||
| 393 | (ert-deftest em-pred-test/modifier-basename () | ||
| 394 | "Test that \":t\" returns the basename." | ||
| 395 | (should (equal (eshell-eval-predicate "/path/to/file.el" ":t") "file.el")) | ||
| 396 | (should (equal (eshell-eval-predicate | ||
| 397 | '("/path/to/file.el" "/other/path/") ":t") | ||
| 398 | '("file.el" "")))) | ||
| 399 | |||
| 400 | (ert-deftest em-pred-test/modifier-extension () | ||
| 401 | "Test that \":e\" returns the extension." | ||
| 402 | (should (equal (eshell-eval-predicate "/path/to/file.el" ":e") "el")) | ||
| 403 | (should (equal (eshell-eval-predicate | ||
| 404 | '("/path/to/file.el" "/other/path/") ":e") | ||
| 405 | '("el" nil)))) | ||
| 406 | |||
| 407 | (ert-deftest em-pred-test/modifier-sans-extension () | ||
| 408 | "Test that \":r\" returns the file name san extension." | ||
| 409 | (should (equal (eshell-eval-predicate "/path/to/file.el" ":r") | ||
| 410 | "/path/to/file")) | ||
| 411 | (should (equal (eshell-eval-predicate | ||
| 412 | '("/path/to/file.el" "/other/path/") ":r") | ||
| 413 | '("/path/to/file" "/other/path/")))) | ||
| 414 | |||
| 415 | (ert-deftest em-pred-test/modifier-quote () | ||
| 416 | "Test that \":q\" quotes arguments." | ||
| 417 | (should (equal-including-properties | ||
| 418 | (eshell-eval-predicate '("foo" "bar") ":q") | ||
| 419 | (list (eshell-escape-arg "foo") (eshell-escape-arg "bar"))))) | ||
| 420 | |||
| 421 | (ert-deftest em-pred-test/modifier-substitute () | ||
| 422 | "Test that \":s/PAT/REP/\" replaces PAT with REP once." | ||
| 423 | (should (equal (eshell-eval-predicate "bar" ":s/a/*/") "b*r")) | ||
| 424 | (should (equal (eshell-eval-predicate "bar" ":s|a|*|") "b*r")) | ||
| 425 | (should (equal (eshell-eval-predicate '("foo" "bar" "baz") ":s/[ao]/*/") | ||
| 426 | '("f*o" "b*r" "b*z"))) | ||
| 427 | (should (equal (eshell-eval-predicate '("foo" "bar" "baz") ":s|[ao]|*|") | ||
| 428 | '("f*o" "b*r" "b*z")))) | ||
| 429 | |||
| 430 | (ert-deftest em-pred-test/modifier-global-substitute () | ||
| 431 | "Test that \":s/PAT/REP/\" replaces PAT with REP for all occurrences." | ||
| 432 | (should (equal (eshell-eval-predicate "foo" ":gs/a/*/") "foo")) | ||
| 433 | (should (equal (eshell-eval-predicate "foo" ":gs|a|*|") "foo")) | ||
| 434 | (should (equal (eshell-eval-predicate "bar" ":gs/a/*/") "b*r")) | ||
| 435 | (should (equal (eshell-eval-predicate "bar" ":gs|a|*|") "b*r")) | ||
| 436 | (should (equal (eshell-eval-predicate "foo" ":gs/o/O/") "fOO")) | ||
| 437 | (should (equal (eshell-eval-predicate '("foo" "bar" "baz") ":gs/[aeiou]/*/") | ||
| 438 | '("f**" "b*r" "b*z"))) | ||
| 439 | (should (equal (eshell-eval-predicate '("foo" "bar" "baz") ":gs|[aeiou]|*|") | ||
| 440 | '("f**" "b*r" "b*z")))) | ||
| 441 | |||
| 442 | (ert-deftest em-pred-test/modifier-include () | ||
| 443 | "Test that \":i/PAT/\" filters elements to include only ones matching PAT." | ||
| 444 | (should (equal (eshell-eval-predicate "foo" ":i/a/") nil)) | ||
| 445 | (should (equal (eshell-eval-predicate "foo" ":i|a|") nil)) | ||
| 446 | (should (equal (eshell-eval-predicate "bar" ":i/a/") "bar")) | ||
| 447 | (should (equal (eshell-eval-predicate "bar" ":i|a|") "bar")) | ||
| 448 | (should (equal (eshell-eval-predicate '("foo" "bar" "baz") ":i/a/") | ||
| 449 | '("bar" "baz"))) | ||
| 450 | (should (equal (eshell-eval-predicate '("foo" "bar" "baz") ":i|a|") | ||
| 451 | '("bar" "baz")))) | ||
| 452 | |||
| 453 | (ert-deftest em-pred-test/modifier-exclude () | ||
| 454 | "Test that \":x/PAT/\" filters elements to exclude any matching PAT." | ||
| 455 | (should (equal (eshell-eval-predicate "foo" ":x/a/") "foo")) | ||
| 456 | (should (equal (eshell-eval-predicate "foo" ":x|a|") "foo")) | ||
| 457 | (should (equal (eshell-eval-predicate "bar" ":x/a/") nil)) | ||
| 458 | (should (equal (eshell-eval-predicate "bar" ":x|a|") nil)) | ||
| 459 | (should (equal (eshell-eval-predicate '("foo" "bar" "baz") ":x/a/") | ||
| 460 | '("foo"))) | ||
| 461 | (should (equal (eshell-eval-predicate '("foo" "bar" "baz") ":x|a|") | ||
| 462 | '("foo")))) | ||
| 463 | |||
| 464 | (ert-deftest em-pred-test/modifier-split () | ||
| 465 | "Test that \":S\" and \":S/PAT/\" split elements by spaces (or PAT)." | ||
| 466 | (should (equal (eshell-eval-predicate "foo bar baz" ":S") | ||
| 467 | '("foo" "bar" "baz"))) | ||
| 468 | (should (equal (eshell-eval-predicate '("foo bar" "baz") ":S") | ||
| 469 | '(("foo" "bar") ("baz")))) | ||
| 470 | (should (equal (eshell-eval-predicate "foo-bar-baz" ":S/-/") | ||
| 471 | '("foo" "bar" "baz"))) | ||
| 472 | (should (equal (eshell-eval-predicate '("foo-bar" "baz") ":S/-/") | ||
| 473 | '(("foo" "bar") ("baz"))))) | ||
| 474 | |||
| 475 | (ert-deftest em-pred-test/modifier-join () | ||
| 476 | "Test that \":j\" and \":j/DELIM/\" join elements by spaces (or DELIM)." | ||
| 477 | (should (equal (eshell-eval-predicate "foo" ":j") "foo")) | ||
| 478 | (should (equal (eshell-eval-predicate '("foo" "bar" "baz") ":j") | ||
| 479 | "foo bar baz")) | ||
| 480 | (should (equal (eshell-eval-predicate "foo" ":j/-/") "foo")) | ||
| 481 | (should (equal (eshell-eval-predicate '("foo" "bar" "baz") ":j/-/") | ||
| 482 | "foo-bar-baz"))) | ||
| 483 | |||
| 484 | (ert-deftest em-pred-test/modifier-sort () | ||
| 485 | "Test that \":o\" sorts elements in lexicographic order." | ||
| 486 | (should (equal (eshell-eval-predicate "foo" ":o") "foo")) | ||
| 487 | (should (equal (eshell-eval-predicate '("foo" "bar" "baz") ":o") | ||
| 488 | '("bar" "baz" "foo")))) | ||
| 489 | |||
| 490 | (ert-deftest em-pred-test/modifier-sort-reverse () | ||
| 491 | "Test that \":o\" sorts elements in reverse lexicographic order." | ||
| 492 | (should (equal (eshell-eval-predicate "foo" ":O") "foo")) | ||
| 493 | (should (equal (eshell-eval-predicate '("foo" "bar" "baz") ":O") | ||
| 494 | '("foo" "baz" "bar")))) | ||
| 495 | |||
| 496 | (ert-deftest em-pred-test/modifier-unique () | ||
| 497 | "Test that \":u\" filters out duplicate elements." | ||
| 498 | (should (equal (eshell-eval-predicate "foo" ":u") "foo")) | ||
| 499 | (should (equal (eshell-eval-predicate '("foo" "bar" "baz") ":u") | ||
| 500 | '("foo" "bar" "baz"))) | ||
| 501 | (should (equal (eshell-eval-predicate '("foo" "bar" "baz" "foo") ":u") | ||
| 502 | '("foo" "bar" "baz")))) | ||
| 503 | |||
| 504 | (ert-deftest em-pred-test/modifier-reverse () | ||
| 505 | "Test that \":r\" reverses the order of elements." | ||
| 506 | (should (equal (eshell-eval-predicate "foo" ":R") "foo")) | ||
| 507 | (should (equal (eshell-eval-predicate '("foo" "bar" "baz") ":R") | ||
| 508 | '("baz" "bar" "foo")))) | ||
| 509 | |||
| 510 | |||
| 511 | ;; Combinations | ||
| 512 | |||
| 513 | (ert-deftest em-pred-test/combine-predicate-and-modifier () | ||
| 514 | "Test combination of predicates and modifiers." | ||
| 515 | (eshell-with-file-attributes-from-name | ||
| 516 | (let ((files '("/fake/type=-.el" "/fake/type=-.txt" "/fake/type=s.el" | ||
| 517 | "/fake/subdir/type=-.el"))) | ||
| 518 | (should (equal (eshell-eval-predicate files ".:e:u") | ||
| 519 | '("el" "txt")))))) | ||
| 520 | |||
| 521 | ;; em-pred-tests.el ends here | ||