ibuffer-tests.el 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808
  1. ;;; ibuffer-tests.el --- Test suite. -*- lexical-binding: t -*-
  2. ;; Copyright (C) 2015-2017 Free Software Foundation, Inc.
  3. ;; This file is part of GNU Emacs.
  4. ;; GNU Emacs is free software: you can redistribute it and/or modify
  5. ;; it under the terms of the GNU General Public License as published by
  6. ;; the Free Software Foundation, either version 3 of the License, or
  7. ;; (at your option) any later version.
  8. ;; GNU Emacs is distributed in the hope that it will be useful,
  9. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. ;; GNU General Public License for more details.
  12. ;; You should have received a copy of the GNU General Public License
  13. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  14. ;;; Code:
  15. (require 'ert)
  16. (require 'ibuffer)
  17. (eval-when-compile
  18. (require 'ibuf-macs))
  19. (ert-deftest ibuffer-autoload ()
  20. "Tests to see whether ibuffer has been autoloaded"
  21. (skip-unless (not (featurep 'ibuf-ext)))
  22. (should
  23. (fboundp 'ibuffer-mark-unsaved-buffers))
  24. (should
  25. (autoloadp
  26. (symbol-function
  27. 'ibuffer-mark-unsaved-buffers))))
  28. (ert-deftest ibuffer-test-Bug24997 ()
  29. "Test for http://debbugs.gnu.org/24997 ."
  30. (ibuffer)
  31. (let ((orig ibuffer-filtering-qualifiers))
  32. (unwind-protect
  33. (progn
  34. (setq ibuffer-filtering-qualifiers
  35. '((size-gt . 10)
  36. (used-mode . lisp-interaction-mode)))
  37. (ibuffer-update nil t)
  38. (ignore-errors (ibuffer-decompose-filter))
  39. (should (cdr ibuffer-filtering-qualifiers)))
  40. (setq ibuffer-filtering-qualifiers orig)
  41. (ibuffer-update nil t))))
  42. (ert-deftest ibuffer-test-Bug25000 ()
  43. "Test for http://debbugs.gnu.org/25000 ."
  44. (let ((case-fold-search t)
  45. (buf1 (generate-new-buffer "ibuffer-test-Bug25000-buf1"))
  46. (buf2 (generate-new-buffer "ibuffer-test-Bug25000-buf2")))
  47. (ibuffer)
  48. (unwind-protect
  49. (ibuffer-save-marks
  50. (ibuffer-unmark-all-marks)
  51. (ibuffer-mark-by-name-regexp (buffer-name buf1))
  52. (ibuffer-change-marks ibuffer-marked-char ?L)
  53. (ibuffer-mark-by-name-regexp (buffer-name buf2))
  54. (ibuffer-change-marks ibuffer-marked-char ?l)
  55. (should-not (cdr (ibuffer-buffer-names-with-mark ?l))))
  56. (mapc (lambda (buf) (when (buffer-live-p buf)
  57. (kill-buffer buf))) (list buf1 buf2)))))
  58. (ert-deftest ibuffer-save-filters ()
  59. "Tests that `ibuffer-save-filters' saves in the proper format."
  60. (skip-unless (featurep 'ibuf-ext))
  61. (let ((ibuffer-save-with-custom nil)
  62. (ibuffer-saved-filters nil)
  63. (test1 '((mode . org-mode)
  64. (or (size-gt . 10000)
  65. (and (not (starred-name))
  66. (directory . "\<org\>")))))
  67. (test2 '((or (mode . emacs-lisp-mode) (file-extension . "elc?")
  68. (and (starred-name) (name . "elisp"))
  69. (mode . lisp-interaction-mode))))
  70. (test3 '((size-lt . 100) (derived-mode . prog-mode)
  71. (or (filename . "scratch")
  72. (filename . "bonz")
  73. (filename . "temp")))))
  74. (ibuffer-save-filters "test1" test1)
  75. (should (equal (car ibuffer-saved-filters) (cons "test1" test1)))
  76. (ibuffer-save-filters "test2" test2)
  77. (should (equal (car ibuffer-saved-filters) (cons "test2" test2)))
  78. (should (equal (cadr ibuffer-saved-filters) (cons "test1" test1)))
  79. (ibuffer-save-filters "test3" test3)
  80. (should (equal (car ibuffer-saved-filters) (cons "test3" test3)))
  81. (should (equal (cadr ibuffer-saved-filters) (cons "test2" test2)))
  82. (should (equal (car (cddr ibuffer-saved-filters)) (cons "test1" test1)))
  83. (should (equal (cdr (assoc "test1" ibuffer-saved-filters)) test1))
  84. (should (equal (cdr (assoc "test2" ibuffer-saved-filters)) test2))
  85. (should (equal (cdr (assoc "test3" ibuffer-saved-filters)) test3))))
  86. (ert-deftest ibuffer-test-Bug25058 ()
  87. "Test for http://debbugs.gnu.org/25058 ."
  88. (ibuffer)
  89. (let ((orig-filters ibuffer-saved-filter-groups)
  90. (tmp-filters '(("saved-filters"
  91. ("Shell"
  92. (used-mode . shell-mode))
  93. ("Elisp"
  94. (or
  95. (used-mode . emacs-lisp-mode)
  96. (used-mode . lisp-interaction-mode)))
  97. ("Dired"
  98. (used-mode . dired-mode))
  99. ("Info"
  100. (or
  101. (used-mode . help-mode)
  102. (used-mode . debugger-mode)
  103. (used-mode . Custom-mode)
  104. (used-mode . completion-list-mode)
  105. (name . "\\`[*]Messages[*]\\'")))))))
  106. (unwind-protect
  107. (progn
  108. (setq ibuffer-saved-filter-groups tmp-filters)
  109. (ibuffer-switch-to-saved-filter-groups "saved-filters")
  110. (ibuffer-decompose-filter-group "Elisp")
  111. (ibuffer-filter-disable)
  112. (ibuffer-switch-to-saved-filter-groups "saved-filters")
  113. (should (assoc "Elisp" (cdar ibuffer-saved-filter-groups))))
  114. (setq ibuffer-saved-filter-groups orig-filters)
  115. (ibuffer-awhen (get-buffer "*Ibuffer*")
  116. (and (buffer-live-p it) (kill-buffer it))))))
  117. (ert-deftest ibuffer-test-Bug25042 ()
  118. "Test for http://debbugs.gnu.org/25042 ."
  119. (ibuffer)
  120. (let ((filters ibuffer-filtering-qualifiers))
  121. (unwind-protect
  122. (progn
  123. (ignore-errors ; Mistyped `match-string' instead of `string-match'.
  124. (setq ibuffer-filtering-qualifiers nil)
  125. (ibuffer-filter-by-predicate '(match-string "foo" (buffer-name))))
  126. (should-not ibuffer-filtering-qualifiers))
  127. (setq ibuffer-filtering-qualifiers filters))))
  128. ;; Test Filter Inclusion
  129. (let* (test-buffer-list ; accumulated buffers to clean up
  130. ;; Utility functions without polluting the environment
  131. (set-buffer-mode
  132. (lambda (buffer mode)
  133. "Set BUFFER's major mode to MODE, a mode function, or fundamental."
  134. (with-current-buffer buffer
  135. (funcall (or mode #'fundamental-mode)))))
  136. (set-buffer-contents
  137. (lambda (buffer size include-content)
  138. "Add exactly SIZE bytes to BUFFER, including INCLUDE-CONTENT."
  139. (when (or size include-content)
  140. (let* ((unit "\n")
  141. (chunk "ccccccccccccccccccccccccccccccc\n")
  142. (chunk-size (length chunk))
  143. (size (if (and size include-content (stringp include-content))
  144. (- size (length include-content))
  145. size)))
  146. (unless (or (null size) (> size 0))
  147. (error "size argument must be nil or positive"))
  148. (with-current-buffer buffer
  149. (when include-content
  150. (insert include-content))
  151. (when size
  152. (dotimes (_ (floor size chunk-size))
  153. (insert chunk))
  154. (dotimes (_ (mod size chunk-size))
  155. (insert unit)))
  156. ;; prevent query on cleanup
  157. (set-buffer-modified-p nil))))))
  158. (create-file-buffer
  159. (lambda (prefix &rest args-plist)
  160. "Create a file and buffer with designated properties.
  161. PREFIX is a string giving the beginning of the name, and ARGS-PLIST
  162. is a series of keyword-value pairs, with allowed keywords
  163. :suffix STRING, :size NUMBER, :mode MODE-FUNC, :include-content STRING.
  164. Returns the created buffer."
  165. (let* ((suffix (plist-get args-plist :suffix))
  166. (size (plist-get args-plist :size))
  167. (include (plist-get args-plist :include-content))
  168. (mode (plist-get args-plist :mode))
  169. (file (make-temp-file prefix nil suffix))
  170. (buf (find-file-noselect file t)))
  171. (push buf test-buffer-list) ; record for cleanup
  172. (funcall set-buffer-mode buf mode)
  173. (funcall set-buffer-contents buf size include)
  174. buf)))
  175. (create-non-file-buffer
  176. (lambda (prefix &rest args-plist)
  177. "Create a non-file and buffer with designated properties.
  178. PREFIX is a string giving the beginning of the name, and ARGS-PLIST
  179. is a series of keyword-value pairs, with allowed keywords
  180. :size NUMBER, :mode MODE-FUNC, :include-content STRING.
  181. Returns the created buffer."
  182. (let* ((size (plist-get args-plist :size))
  183. (include (plist-get args-plist :include-content))
  184. (mode (plist-get args-plist :mode))
  185. (buf (generate-new-buffer prefix)))
  186. (push buf test-buffer-list) ; record for cleanup
  187. (funcall set-buffer-mode buf mode)
  188. (funcall set-buffer-contents buf size include)
  189. buf)))
  190. (clean-up
  191. (lambda ()
  192. "Restore all emacs state modified during the tests"
  193. (while test-buffer-list ; created temporary buffers
  194. (let ((buf (pop test-buffer-list)))
  195. (with-current-buffer buf (bury-buffer)) ; ensure not selected
  196. (kill-buffer buf))))))
  197. ;; Tests
  198. (ert-deftest ibuffer-filter-inclusion-1 ()
  199. "Tests inclusion using basic filter combinators with a single buffer."
  200. (skip-unless (featurep 'ibuf-ext))
  201. (unwind-protect
  202. (let ((buf
  203. (funcall create-file-buffer "ibuf-test-1" :size 100
  204. :include-content "One ring to rule them all\n")))
  205. (should (ibuffer-included-in-filters-p buf '((size-gt . 99))))
  206. (should (ibuffer-included-in-filters-p buf '((size-lt . 101))))
  207. (should (ibuffer-included-in-filters-p
  208. buf '((mode . fundamental-mode))))
  209. (should (ibuffer-included-in-filters-p
  210. buf '((content . "ring to rule them all"))))
  211. (should (ibuffer-included-in-filters-p
  212. buf '((and (content . "ring to rule them all")))))
  213. (should (ibuffer-included-in-filters-p
  214. buf '((and (and (content . "ring to rule them all"))))))
  215. (should (ibuffer-included-in-filters-p
  216. buf '((and (and (and (content . "ring to rule them all")))))))
  217. (should (ibuffer-included-in-filters-p
  218. buf '((or (content . "ring to rule them all")))))
  219. (should (ibuffer-included-in-filters-p
  220. buf '((not (not (content . "ring to rule them all"))))))
  221. (should (ibuffer-included-in-filters-p
  222. buf '((and (size-gt . 99)
  223. (content . "ring to rule them all")
  224. (mode . fundamental-mode)
  225. (basename . "\\`ibuf-test-1")))))
  226. (should (ibuffer-included-in-filters-p
  227. buf '((not (or (not (size-gt . 99))
  228. (not (content . "ring to rule them all"))
  229. (not (mode . fundamental-mode))
  230. (not (basename . "\\`ibuf-test-1")))))))
  231. (should (ibuffer-included-in-filters-p
  232. buf '((and (or (size-gt . 99) (size-lt . 10))
  233. (and (content . "ring.*all")
  234. (content . "rule")
  235. (content . "them all")
  236. (content . "One"))
  237. (not (mode . text-mode))
  238. (basename . "\\`ibuf-test-1"))))))
  239. (funcall clean-up)))
  240. (ert-deftest ibuffer-filter-inclusion-2 ()
  241. "Tests inclusion of basic filters in combination on a single buffer."
  242. (skip-unless (featurep 'ibuf-ext))
  243. (unwind-protect
  244. (let ((buf
  245. (funcall create-file-buffer "ibuf-test-2" :size 200
  246. :mode #'text-mode
  247. :include-content "and in the darkness find them\n")))
  248. (should (ibuffer-included-in-filters-p buf '((size-gt . 199))))
  249. (should (ibuffer-included-in-filters-p buf '((size-lt . 201))))
  250. (should (ibuffer-included-in-filters-p buf '((not size-gt . 200))))
  251. (should (ibuffer-included-in-filters-p buf '((not (size-gt . 200)))))
  252. (should (ibuffer-included-in-filters-p
  253. buf '((and (size-gt . 199) (size-lt . 201)))))
  254. (should (ibuffer-included-in-filters-p
  255. buf '((or (size-gt . 199) (size-gt . 201)))))
  256. (should (ibuffer-included-in-filters-p
  257. buf '((or (size-gt . 201) (size-gt . 199)))))
  258. (should (ibuffer-included-in-filters-p
  259. buf '((size-gt . 199) (mode . text-mode)
  260. (content . "darkness find them"))))
  261. (should (ibuffer-included-in-filters-p
  262. buf '((and (size-gt . 199) (mode . text-mode)
  263. (content . "darkness find them")))))
  264. (should (ibuffer-included-in-filters-p
  265. buf '((not (or (not (size-gt . 199)) (not (mode . text-mode))
  266. (not (content . "darkness find them")))))))
  267. (should (ibuffer-included-in-filters-p
  268. buf '((or (size-gt . 200) (content . "darkness find them")
  269. (derived-mode . emacs-lisp-mode)))))
  270. (should-not (ibuffer-included-in-filters-p
  271. buf '((or (size-gt . 200) (content . "rule them all")
  272. (derived-mode . emacs-lisp-mode))))))
  273. (funcall clean-up)))
  274. (ert-deftest ibuffer-filter-inclusion-3 ()
  275. "Tests inclusion with filename filters on specified buffers."
  276. (skip-unless (featurep 'ibuf-ext))
  277. (unwind-protect
  278. (let* ((bufA
  279. (funcall create-file-buffer "ibuf-test-3.a" :size 50
  280. :mode #'text-mode
  281. :include-content "...but a multitude of drops?\n"))
  282. (bufB
  283. (funcall create-non-file-buffer "ibuf-test-3.b" :size 50
  284. :mode #'text-mode
  285. :include-content "...but a multitude of drops?\n"))
  286. (dirA (with-current-buffer bufA default-directory))
  287. (dirB (with-current-buffer bufB default-directory)))
  288. (should (ibuffer-included-in-filters-p
  289. bufA '((basename . "ibuf-test-3"))))
  290. (should (ibuffer-included-in-filters-p
  291. bufA '((basename . "test-3\\.a"))))
  292. (should (ibuffer-included-in-filters-p
  293. bufA '((file-extension . "a"))))
  294. (should (ibuffer-included-in-filters-p
  295. bufA (list (cons 'directory dirA))))
  296. (should-not (ibuffer-included-in-filters-p
  297. bufB '((basename . "ibuf-test-3"))))
  298. (should-not (ibuffer-included-in-filters-p
  299. bufB '((file-extension . "b"))))
  300. (should (ibuffer-included-in-filters-p
  301. bufB (list (cons 'directory dirB))))
  302. (should (ibuffer-included-in-filters-p
  303. bufA '((name . "ibuf-test-3"))))
  304. (should (ibuffer-included-in-filters-p
  305. bufB '((name . "ibuf-test-3")))))
  306. (funcall clean-up)))
  307. (ert-deftest ibuffer-filter-inclusion-4 ()
  308. "Tests inclusion with various filters on a single buffer."
  309. (skip-unless (featurep 'ibuf-ext))
  310. (unwind-protect
  311. (let ((buf
  312. (funcall create-file-buffer "ibuf-test-4"
  313. :mode #'emacs-lisp-mode :suffix ".el"
  314. :include-content "(message \"--%s--\" 'emacs-rocks)\n")))
  315. (should (ibuffer-included-in-filters-p
  316. buf '((file-extension . "el"))))
  317. (should (ibuffer-included-in-filters-p
  318. buf '((derived-mode . prog-mode))))
  319. (should (ibuffer-included-in-filters-p
  320. buf '((used-mode . emacs-lisp-mode))))
  321. (should (ibuffer-included-in-filters-p
  322. buf '((mode . emacs-lisp-mode))))
  323. (with-current-buffer buf (set-buffer-modified-p t))
  324. (should (ibuffer-included-in-filters-p buf '((modified))))
  325. (with-current-buffer buf (set-buffer-modified-p nil))
  326. (should (ibuffer-included-in-filters-p buf '((not modified))))
  327. (should (ibuffer-included-in-filters-p
  328. buf '((and (file-extension . "el")
  329. (derived-mode . prog-mode)
  330. (not modified)))))
  331. (should (ibuffer-included-in-filters-p
  332. buf '((or (file-extension . "tex")
  333. (derived-mode . prog-mode)
  334. (modified)))))
  335. (should (ibuffer-included-in-filters-p
  336. buf '((file-extension . "el")
  337. (derived-mode . prog-mode)
  338. (not modified)))))
  339. (funcall clean-up)))
  340. (ert-deftest ibuffer-filter-inclusion-5 ()
  341. "Tests inclusion with various filters on a single buffer."
  342. (skip-unless (featurep 'ibuf-ext))
  343. (unwind-protect
  344. (let ((buf
  345. (funcall create-non-file-buffer "ibuf-test-5.el"
  346. :mode #'emacs-lisp-mode
  347. :include-content
  348. "(message \"--%s--\" \"It really does!\")\n")))
  349. (should-not (ibuffer-included-in-filters-p
  350. buf '((file-extension . "el"))))
  351. (should (ibuffer-included-in-filters-p
  352. buf '((size-gt . 18))))
  353. (should (ibuffer-included-in-filters-p
  354. buf '((predicate . (lambda ()
  355. (> (- (point-max) (point-min)) 18))))))
  356. (should (ibuffer-included-in-filters-p
  357. buf '((and (mode . emacs-lisp-mode)
  358. (or (starred-name)
  359. (size-gt . 18))
  360. (and (not (size-gt . 100))
  361. (content . "[Ii]t *really does!")
  362. (or (name . "test-5")
  363. (not (filename . "test-5")))))))))
  364. (funcall clean-up)))
  365. (ert-deftest ibuffer-filter-inclusion-6 ()
  366. "Tests inclusion using saved filters and DeMorgan's laws."
  367. (skip-unless (featurep 'ibuf-ext))
  368. (unwind-protect
  369. (let ((buf
  370. (funcall create-non-file-buffer "*ibuf-test-6*" :size 65
  371. :mode #'text-mode))
  372. (buf2
  373. (funcall create-file-buffer "ibuf-test-6a" :suffix ".html"
  374. :mode #'html-mode
  375. :include-content
  376. "<HTML><BODY><H1>Hello, World!</H1></BODY></HTML>")))
  377. (should (ibuffer-included-in-filters-p buf '((starred-name))))
  378. (should-not (ibuffer-included-in-filters-p
  379. buf '((saved . "text document"))))
  380. (should (ibuffer-included-in-filters-p buf2 '((saved . "web"))))
  381. (should (ibuffer-included-in-filters-p
  382. buf2 '((not (and (not (derived-mode . sgml-mode))
  383. (not (derived-mode . css-mode))
  384. (not (mode . javascript-mode))
  385. (not (mode . js2-mode))
  386. (not (mode . scss-mode))
  387. (not (derived-mode . haml-mode))
  388. (not (mode . sass-mode)))))))
  389. (should (ibuffer-included-in-filters-p
  390. buf '((and (starred-name)
  391. (or (size-gt . 50) (filename . "foo"))))))
  392. (should (ibuffer-included-in-filters-p
  393. buf '((not (or (not starred-name)
  394. (and (size-lt . 51)
  395. (not (filename . "foo")))))))))
  396. (funcall clean-up)))
  397. (ert-deftest ibuffer-filter-inclusion-7 ()
  398. "Tests inclusion with various filters on a single buffer."
  399. (skip-unless (featurep 'ibuf-ext))
  400. (unwind-protect
  401. (let ((buf
  402. (funcall create-non-file-buffer "ibuf-test-7"
  403. :mode #'artist-mode)))
  404. (should (ibuffer-included-in-filters-p
  405. buf '((not (starred-name)))))
  406. (should (ibuffer-included-in-filters-p
  407. buf '((not starred-name))))
  408. (should (ibuffer-included-in-filters-p
  409. buf '((not (not (not starred-name))))))
  410. (should (ibuffer-included-in-filters-p
  411. buf '((not (modified)))))
  412. (should (ibuffer-included-in-filters-p
  413. buf '((not modified))))
  414. (should (ibuffer-included-in-filters-p
  415. buf '((not (not (not modified)))))))
  416. (funcall clean-up)))
  417. (ert-deftest ibuffer-filter-inclusion-8 ()
  418. "Tests inclusion with various filters."
  419. (skip-unless (featurep 'ibuf-ext))
  420. (unwind-protect
  421. (let ((bufA
  422. (funcall create-non-file-buffer "ibuf-test-8a"
  423. :mode #'artist-mode))
  424. (bufB (funcall create-non-file-buffer "*ibuf-test-8b*" :size 32))
  425. (bufC (funcall create-file-buffer "ibuf-test8c" :suffix "*"
  426. :size 64))
  427. (bufD (funcall create-file-buffer "*ibuf-test8d" :size 128))
  428. (bufE (funcall create-file-buffer "*ibuf-test8e" :suffix "*<2>"
  429. :size 16))
  430. (bufF (and (funcall create-non-file-buffer "*ibuf-test8f*")
  431. (funcall create-non-file-buffer "*ibuf-test8f*"
  432. :size 8))))
  433. (with-current-buffer bufA (set-buffer-modified-p t))
  434. (should (ibuffer-included-in-filters-p
  435. bufA '((and (not starred-name)
  436. (modified)
  437. (name . "test-8")
  438. (not (size-gt . 100))
  439. (mode . picture-mode)))))
  440. (with-current-buffer bufA (set-buffer-modified-p nil))
  441. (should-not (ibuffer-included-in-filters-p
  442. bufA '((or (starred-name) (visiting-file) (modified)))))
  443. (should (ibuffer-included-in-filters-p
  444. bufB '((and (starred-name)
  445. (name . "test.*8b")
  446. (size-gt . 31)
  447. (not visiting-file)))))
  448. (should (ibuffer-included-in-filters-p
  449. bufC '((and (not (starred-name))
  450. (visiting-file)
  451. (name . "8c[^*]*\\*")
  452. (size-lt . 65)))))
  453. (should (ibuffer-included-in-filters-p
  454. bufD '((and (not (starred-name))
  455. (visiting-file)
  456. (name . "\\`\\*.*test8d")
  457. (size-lt . 129)
  458. (size-gt . 127)))))
  459. (should (ibuffer-included-in-filters-p
  460. bufE '((and (starred-name)
  461. (visiting-file)
  462. (name . "8e.*?\\*<[[:digit:]]+>")
  463. (size-gt . 10)))))
  464. (should (ibuffer-included-in-filters-p
  465. bufF '((and (starred-name)
  466. (not (visiting-file))
  467. (name . "8f\\*<[[:digit:]]>")
  468. (size-lt . 10))))))
  469. (funcall clean-up))))
  470. ;; Test Filter Combination and Decomposition
  471. (let* (ibuffer-to-kill ; if non-nil, kill this buffer at cleanup
  472. (ibuffer-already 'check) ; existing ibuffer buffer to use but not kill
  473. ;; Utility functions without polluting the environment
  474. (get-test-ibuffer
  475. (lambda ()
  476. "Returns a test ibuffer-mode buffer, creating one if necessary.
  477. If a new buffer is created, it is named \"*Test-Ibuffer*\" and is
  478. saved to `ibuffer-to-kill' for later cleanup."
  479. (when (eq ibuffer-already 'check)
  480. (setq ibuffer-already
  481. (catch 'found-buf
  482. (dolist (buf (buffer-list) nil)
  483. (when (with-current-buffer buf
  484. (derived-mode-p 'ibuffer-mode))
  485. (throw 'found-buf buf))))))
  486. (or ibuffer-already
  487. ibuffer-to-kill
  488. (let ((test-ibuf-name "*Test-Ibuffer*"))
  489. (ibuffer nil test-ibuf-name nil t)
  490. (setq ibuffer-to-kill (get-buffer test-ibuf-name))))))
  491. (clean-up
  492. (lambda ()
  493. "Restore all emacs state modified during the tests"
  494. (when ibuffer-to-kill ; created ibuffer
  495. (with-current-buffer ibuffer-to-kill
  496. (set-buffer-modified-p nil)
  497. (bury-buffer))
  498. (kill-buffer ibuffer-to-kill)
  499. (setq ibuffer-to-kill nil))
  500. (when (and ibuffer-already (not (eq ibuffer-already 'check)))
  501. ;; restore existing ibuffer state
  502. (ibuffer-update nil t)))))
  503. ;; Tests
  504. (ert-deftest ibuffer-decompose-filter ()
  505. "Tests `ibuffer-decompose-filter' for and, or, not, and saved."
  506. (skip-unless (featurep 'ibuf-ext))
  507. (unwind-protect
  508. (let ((ibuf (funcall get-test-ibuffer)))
  509. (with-current-buffer ibuf
  510. (let ((ibuffer-filtering-qualifiers nil)
  511. (ibuffer-filter-groups nil)
  512. (filters '((size-gt . 100) (not (starred-name))
  513. (name . "foo"))))
  514. (progn
  515. (push (cons 'or filters) ibuffer-filtering-qualifiers)
  516. (ibuffer-decompose-filter)
  517. (should (equal filters ibuffer-filtering-qualifiers))
  518. (setq ibuffer-filtering-qualifiers nil))
  519. (progn
  520. (push (cons 'and filters) ibuffer-filtering-qualifiers)
  521. (ibuffer-decompose-filter)
  522. (should (equal filters ibuffer-filtering-qualifiers))
  523. (setq ibuffer-filtering-qualifiers nil))
  524. (progn
  525. (push (list 'not (car filters)) ibuffer-filtering-qualifiers)
  526. (ibuffer-decompose-filter)
  527. (should (equal (list (car filters))
  528. ibuffer-filtering-qualifiers))
  529. (setq ibuffer-filtering-qualifiers nil))
  530. (progn
  531. (push (cons 'not (car filters)) ibuffer-filtering-qualifiers)
  532. (ibuffer-decompose-filter)
  533. (should (equal (list (car filters))
  534. ibuffer-filtering-qualifiers))
  535. (setq ibuffer-filtering-qualifiers nil))
  536. (let ((gnus (assoc "gnus" ibuffer-saved-filters)))
  537. (push '(saved . "gnus") ibuffer-filtering-qualifiers)
  538. (ibuffer-decompose-filter)
  539. (should (equal (cdr gnus) ibuffer-filtering-qualifiers))
  540. (ibuffer-decompose-filter)
  541. (should (equal (cdr (cadr gnus)) ibuffer-filtering-qualifiers))
  542. (setq ibuffer-filtering-qualifiers nil))
  543. (when (not (assoc "__unknown__" ibuffer-saved-filters))
  544. (push '(saved . "__uknown__") ibuffer-filtering-qualifiers)
  545. (should-error (ibuffer-decompose-filter) :type 'error)
  546. (setq ibuffer-filtering-qualifiers nil))
  547. (progn
  548. (push (car filters) ibuffer-filtering-qualifiers)
  549. (should-error (ibuffer-decompose-filter) :type 'error)
  550. (setq ibuffer-filtering-qualifiers nil)))))
  551. (funcall clean-up)))
  552. (ert-deftest ibuffer-and-filter ()
  553. "Tests `ibuffer-and-filter' in an Ibuffer buffer."
  554. (skip-unless (featurep 'ibuf-ext))
  555. (unwind-protect
  556. (let ((ibuf (funcall get-test-ibuffer)))
  557. (with-current-buffer ibuf
  558. (let ((ibuffer-filtering-qualifiers nil)
  559. (ibuffer-filter-groups nil)
  560. (filters [(size-gt . 100) (not (starred-name))
  561. (filename . "A") (mode . text-mode)]))
  562. (should-error (ibuffer-and-filter) :type 'error)
  563. (progn
  564. (push (aref filters 1) ibuffer-filtering-qualifiers)
  565. (should-error (ibuffer-and-filter) :type 'error))
  566. (should (progn
  567. (push (aref filters 0) ibuffer-filtering-qualifiers)
  568. (ibuffer-and-filter)
  569. (and (equal (list 'and (aref filters 0) (aref filters 1))
  570. (car ibuffer-filtering-qualifiers))
  571. (null (cdr ibuffer-filtering-qualifiers)))))
  572. (should (progn
  573. (ibuffer-and-filter 'decompose)
  574. (and (equal (aref filters 0)
  575. (pop ibuffer-filtering-qualifiers))
  576. (equal (aref filters 1)
  577. (pop ibuffer-filtering-qualifiers))
  578. (null ibuffer-filtering-qualifiers))))
  579. (should (progn
  580. (push (list 'and (aref filters 2) (aref filters 3))
  581. ibuffer-filtering-qualifiers)
  582. (push (list 'and (aref filters 0) (aref filters 1))
  583. ibuffer-filtering-qualifiers)
  584. (ibuffer-and-filter)
  585. (and (equal (list 'and (aref filters 0) (aref filters 1)
  586. (aref filters 2) (aref filters 3))
  587. (car ibuffer-filtering-qualifiers))
  588. (null (cdr ibuffer-filtering-qualifiers)))))
  589. (pop ibuffer-filtering-qualifiers)
  590. (should (progn
  591. (push (list 'or (aref filters 2) (aref filters 3))
  592. ibuffer-filtering-qualifiers)
  593. (push (list 'and (aref filters 0) (aref filters 1))
  594. ibuffer-filtering-qualifiers)
  595. (ibuffer-and-filter)
  596. (and (equal (list 'and (aref filters 0) (aref filters 1)
  597. (list 'or (aref filters 2)
  598. (aref filters 3)))
  599. (car ibuffer-filtering-qualifiers))
  600. (null (cdr ibuffer-filtering-qualifiers)))))
  601. (pop ibuffer-filtering-qualifiers)
  602. (should (progn
  603. (push (list 'and (aref filters 2) (aref filters 3))
  604. ibuffer-filtering-qualifiers)
  605. (push (list 'or (aref filters 0) (aref filters 1))
  606. ibuffer-filtering-qualifiers)
  607. (ibuffer-and-filter)
  608. (and (equal (list 'and (list 'or (aref filters 0)
  609. (aref filters 1))
  610. (aref filters 2) (aref filters 3))
  611. (car ibuffer-filtering-qualifiers))
  612. (null (cdr ibuffer-filtering-qualifiers)))))
  613. (pop ibuffer-filtering-qualifiers)
  614. (should (progn
  615. (push (list 'or (aref filters 2) (aref filters 3))
  616. ibuffer-filtering-qualifiers)
  617. (push (list 'or (aref filters 0) (aref filters 1))
  618. ibuffer-filtering-qualifiers)
  619. (ibuffer-and-filter)
  620. (and (equal (list 'and
  621. (list 'or (aref filters 0)
  622. (aref filters 1))
  623. (list 'or (aref filters 2)
  624. (aref filters 3)))
  625. (car ibuffer-filtering-qualifiers))
  626. (null (cdr ibuffer-filtering-qualifiers))))))))
  627. (funcall clean-up)))
  628. (ert-deftest ibuffer-or-filter ()
  629. "Tests `ibuffer-or-filter' in an Ibuffer buffer."
  630. (skip-unless (featurep 'ibuf-ext))
  631. (unwind-protect
  632. (let ((ibuf (funcall get-test-ibuffer)))
  633. (with-current-buffer ibuf
  634. (let ((ibuffer-filtering-qualifiers nil)
  635. (ibuffer-filter-groups nil)
  636. (filters [(size-gt . 100) (not (starred-name))
  637. (filename . "A") (mode . text-mode)]))
  638. (should-error (ibuffer-or-filter) :type 'error)
  639. (progn
  640. (push (aref filters 1) ibuffer-filtering-qualifiers)
  641. (should-error (ibuffer-or-filter) :type 'error))
  642. (should (progn
  643. (push (aref filters 0) ibuffer-filtering-qualifiers)
  644. (ibuffer-or-filter)
  645. (and (equal (list 'or (aref filters 0) (aref filters 1))
  646. (car ibuffer-filtering-qualifiers))
  647. (null (cdr ibuffer-filtering-qualifiers)))))
  648. (should (progn
  649. (ibuffer-or-filter 'decompose)
  650. (and (equal (aref filters 0)
  651. (pop ibuffer-filtering-qualifiers))
  652. (equal (aref filters 1)
  653. (pop ibuffer-filtering-qualifiers))
  654. (null ibuffer-filtering-qualifiers))))
  655. (should (progn
  656. (push (list 'or (aref filters 2) (aref filters 3))
  657. ibuffer-filtering-qualifiers)
  658. (push (list 'or (aref filters 0) (aref filters 1))
  659. ibuffer-filtering-qualifiers)
  660. (ibuffer-or-filter)
  661. (and (equal (list 'or (aref filters 0) (aref filters 1)
  662. (aref filters 2) (aref filters 3))
  663. (car ibuffer-filtering-qualifiers))
  664. (null (cdr ibuffer-filtering-qualifiers)))))
  665. (pop ibuffer-filtering-qualifiers)
  666. (should (progn
  667. (push (list 'and (aref filters 2) (aref filters 3))
  668. ibuffer-filtering-qualifiers)
  669. (push (list 'or (aref filters 0) (aref filters 1))
  670. ibuffer-filtering-qualifiers)
  671. (ibuffer-or-filter)
  672. (and (equal (list 'or (aref filters 0) (aref filters 1)
  673. (list 'and (aref filters 2)
  674. (aref filters 3)))
  675. (car ibuffer-filtering-qualifiers))
  676. (null (cdr ibuffer-filtering-qualifiers)))))
  677. (pop ibuffer-filtering-qualifiers)
  678. (should (progn
  679. (push (list 'or (aref filters 2) (aref filters 3))
  680. ibuffer-filtering-qualifiers)
  681. (push (list 'and (aref filters 0) (aref filters 1))
  682. ibuffer-filtering-qualifiers)
  683. (ibuffer-or-filter)
  684. (and (equal (list 'or (list 'and (aref filters 0)
  685. (aref filters 1))
  686. (aref filters 2) (aref filters 3))
  687. (car ibuffer-filtering-qualifiers))
  688. (null (cdr ibuffer-filtering-qualifiers)))))
  689. (pop ibuffer-filtering-qualifiers)
  690. (should (progn
  691. (push (list 'and (aref filters 2) (aref filters 3))
  692. ibuffer-filtering-qualifiers)
  693. (push (list 'and (aref filters 0) (aref filters 1))
  694. ibuffer-filtering-qualifiers)
  695. (ibuffer-or-filter)
  696. (and (equal (list 'or
  697. (list 'and (aref filters 0)
  698. (aref filters 1))
  699. (list 'and (aref filters 2)
  700. (aref filters 3)))
  701. (car ibuffer-filtering-qualifiers))
  702. (null (cdr ibuffer-filtering-qualifiers))))))))
  703. (funcall clean-up))))
  704. (ert-deftest ibuffer-format-qualifier ()
  705. "Tests string recommendation of filter from `ibuffer-format-qualifier'."
  706. (skip-unless (featurep 'ibuf-ext))
  707. (let ((test1 '(mode . org-mode))
  708. (test2 '(size-lt . 100))
  709. (test3 '(derived-mode . prog-mode))
  710. (test4 '(or (size-gt . 10000)
  711. (and (not (starred-name))
  712. (directory . "\\<org\\>"))))
  713. (test5 '(or (filename . "scratch")
  714. (filename . "bonz")
  715. (filename . "temp")))
  716. (test6 '(or (mode . emacs-lisp-mode) (file-extension . "elc?")
  717. (and (starred-name) (name . "elisp"))
  718. (mode . lisp-interaction-mode)))
  719. (description (lambda (q)
  720. (cadr (assq q ibuffer-filtering-alist))))
  721. (tag (lambda (&rest args )
  722. (concat " [" (apply #'concat args) "]"))))
  723. (should (equal (ibuffer-format-qualifier test1)
  724. (funcall tag (funcall description 'mode)
  725. ": " "org-mode")))
  726. (should (equal (ibuffer-format-qualifier test2)
  727. (funcall tag (funcall description 'size-lt)
  728. ": " "100")))
  729. (should (equal (ibuffer-format-qualifier test3)
  730. (funcall tag (funcall description 'derived-mode)
  731. ": " "prog-mode")))
  732. (should (equal (ibuffer-format-qualifier test4)
  733. (funcall tag "OR"
  734. (funcall tag (funcall description 'size-gt)
  735. ": " (format "%s" 10000))
  736. (funcall tag "AND"
  737. (funcall tag "NOT"
  738. (funcall tag
  739. (funcall description
  740. 'starred-name)
  741. ": " "nil"))
  742. (funcall tag
  743. (funcall description 'directory)
  744. ": " "\\<org\\>")))))
  745. (should (equal (ibuffer-format-qualifier test5)
  746. (funcall tag "OR"
  747. (funcall tag (funcall description 'filename)
  748. ": " "scratch")
  749. (funcall tag (funcall description 'filename)
  750. ": " "bonz")
  751. (funcall tag (funcall description 'filename)
  752. ": " "temp"))))
  753. (should (equal (ibuffer-format-qualifier test6)
  754. (funcall tag "OR"
  755. (funcall tag (funcall description 'mode)
  756. ": " "emacs-lisp-mode")
  757. (funcall tag (funcall description 'file-extension)
  758. ": " "elc?")
  759. (funcall tag "AND"
  760. (funcall tag
  761. (funcall description 'starred-name)
  762. ": " "nil")
  763. (funcall tag
  764. (funcall description 'name)
  765. ": " "elisp"))
  766. (funcall tag (funcall description 'mode)
  767. ": " "lisp-interaction-mode"))))))
  768. (ert-deftest ibuffer-unary-operand ()
  769. "Tests `ibuffer-unary-operand': (not cell) or (not . cell) -> cell."
  770. (skip-unless (featurep 'ibuf-ext))
  771. (should (equal (ibuffer-unary-operand '(not . (mode "foo")))
  772. '(mode "foo")))
  773. (should (equal (ibuffer-unary-operand '(not (mode "foo")))
  774. '(mode "foo")))
  775. (should (equal (ibuffer-unary-operand '(not "cdr"))
  776. '("cdr")))
  777. (should (equal (ibuffer-unary-operand '(not)) nil))
  778. (should (equal (ibuffer-unary-operand '(not . a)) 'a)))
  779. (provide 'ibuffer-tests)
  780. ;; ibuffer-tests.el ends here