test-ido-completing-read+.el 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730
  1. ;;; -*- lexical-binding: t -*-
  2. (require 'ido)
  3. (require 'ido-completing-read+)
  4. (require 'buttercup)
  5. (require 'cl-lib)
  6. (require 'with-simulated-input)
  7. (defun collection-as-function (collection)
  8. "Return a function equivalent to COLLECTION.
  9. The returned function will work equivalently to COLLECTION when
  10. passed to `all-completions' and `try-completion'."
  11. (completion-table-dynamic (lambda (string) (all-completions string collection))))
  12. (defun shadow-var (var &optional temp-value)
  13. "Shadow the value of VAR.
  14. This will push the current value of VAR to VAR's
  15. `shadowed-values' property, and then set it to TEMP-VALUE. To
  16. reverse this process, call `unshadow-var' on VAR. Vars can
  17. be shadowed recursively, and must be unshadowed once for each
  18. shadowing in order to restore the original value. You can think
  19. of shadowing as dynamic binding with `let', but with manual
  20. control over when bindings start and end.
  21. If VAR is a Custom variable (see `custom-variable-p'), it will be
  22. set using `customize-set-variable', and if TEMP-VALUE is nil it
  23. will be replaces with VAR's standard value.
  24. Other variables will be set with `set-default', and a TEMP-VALUE
  25. of nil will not be treated specially.
  26. `shadow-var' only works on variables declared as special (i.e.
  27. using `defvar' or similar). It will not work on lexically bound
  28. variables."
  29. (unless (special-variable-p var)
  30. (error "Cannot shadow lexical var `%s'" var))
  31. (let* ((use-custom (custom-variable-p var))
  32. (setter (if use-custom 'customize-set-variable 'set-default))
  33. (temp-value (or temp-value
  34. (and use-custom
  35. (eval (car (get var 'standard-value)))))))
  36. ;; Push the current value on the stack
  37. (push (symbol-value var) (get var 'shadowed-values))
  38. (funcall setter var temp-value)))
  39. (defun var-shadowed-p (var)
  40. "Return non-nil if VAR is shadowed by `shadow-var'."
  41. ;; We don't actually want to return that list if it's non-nil.
  42. (and (get var 'shadowed-values) t))
  43. (defun unshadow-var (var)
  44. "Reverse the last call to `shadow-var' on VAR."
  45. (if (var-shadowed-p var)
  46. (let* ((use-custom (custom-variable-p var))
  47. (setter (if use-custom 'customize-set-variable 'set-default))
  48. (value (pop (get var 'shadowed-values))))
  49. (funcall setter var value))
  50. (error "Var is not shadowed: %s" var)))
  51. (defun fully-unshadow-var (var)
  52. "Reverse *all* calls to `shadow-var' on VAR."
  53. (when (var-shadowed-p var)
  54. (let* ((use-custom (custom-variable-p var))
  55. (setter (if use-custom 'customize-set-variable 'set-default))
  56. (value (car (last (get var 'shadowed-values)))))
  57. (put var 'shadowed-values nil)
  58. (funcall setter var value))))
  59. (defun fully-unshadow-all-vars (&optional vars)
  60. "Reverse *all* calls to `shadow-var' on VARS.
  61. If VARS is nil, unshadow *all* variables."
  62. (if vars
  63. (mapc #'fully-unshadow-var vars)
  64. (mapatoms #'fully-unshadow-var))
  65. nil)
  66. (defmacro shadow-vars (varlist)
  67. "Shadow a list of vars with new values.
  68. VARLIST describes the variables to be shadowed with the same
  69. syntax as `let'.
  70. See `shadow-var'."
  71. (declare (indent 0))
  72. (cl-loop
  73. with var = nil
  74. with value = nil
  75. for binding in varlist
  76. if (symbolp binding)
  77. do (setq var binding
  78. value nil)
  79. else
  80. do (setq var (car binding)
  81. value (cadr binding))
  82. collect `(shadow-var ',var ,value) into exprs
  83. finally return `(progn ,@exprs)))
  84. (defmacro unshadow-vars (vars)
  85. "Un-shadow a list of VARS.
  86. This is a macro for consistency with `shadow-vars', but it will
  87. also accept a quoted list for the sake of convenience."
  88. (declare (indent 0))
  89. (when (eq (car vars) 'quote)
  90. (setq vars (eval vars)))
  91. `(mapc #'unshadow-var ',vars))
  92. (cl-defmacro expect-error (expr &key (error-symbol 'error))
  93. "Shortcut for `(expect (lambda () ...) :to-throw)'"
  94. `(expect (lambda () ,expr) :to-throw ',error-symbol))
  95. (describe "Within the `ido-completing-read+' package"
  96. ;; Reset all of these variables to their standard values before each
  97. ;; test, saving the previous values for later restoration.
  98. (before-each
  99. (shadow-vars
  100. ((ido-mode t)
  101. (ido-ubiquitous-mode t)
  102. ido-cr+-debug-mode
  103. ido-cr+-auto-update-blacklist
  104. ido-cr+-fallback-function
  105. ido-cr+-max-items
  106. ido-cr+-function-blacklist
  107. ido-cr+-function-whitelist
  108. ido-cr+-nil-def-alternate-behavior-list
  109. ido-cr+-replace-completely
  110. ido-confirm-unique-completion
  111. ido-enable-flex-matching)))
  112. ;; Restore the saved values after each test
  113. (after-each
  114. (fully-unshadow-all-vars))
  115. (describe "the `ido-completing-read+' function"
  116. (it "should complete with a matching item on RET"
  117. (expect
  118. (with-simulated-input "g RET"
  119. (ido-completing-read+ "Prompt: " '("blue" "yellow" "green")))
  120. :to-equal "green"))
  121. (it "should complete with the first match when multiple matches are available"
  122. (expect
  123. (with-simulated-input "b RET"
  124. (ido-completing-read+ "Prompt: " '("brown" "blue" "yellow" "green")))
  125. :to-equal "brown"))
  126. (it "should allow <left> and <right> to cycle completions, with wrap-around"
  127. (expect
  128. (with-simulated-input "b <right> <right> <right> <right> <left> RET"
  129. (ido-completing-read+ "Prompt: " '("brown" "blue" "yellow" "green")))
  130. :to-equal
  131. "blue"))
  132. (it "should return \"\" when RET or C-j is pressed on an empty input even when REQUIRE-MATCH is non-nil"
  133. ;; No REQUIRE-MATCH
  134. (expect
  135. (with-simulated-input "RET"
  136. (ido-completing-read+ "Prompt: " '("blue" "yellow" "green")))
  137. :to-equal "blue")
  138. (expect
  139. (with-simulated-input "C-j"
  140. (ido-completing-read+ "Prompt: " '("blue" "yellow" "green")))
  141. :to-equal "")
  142. ;; Again, with REQUIRE-MATCH
  143. (expect
  144. (with-simulated-input "RET"
  145. (ido-completing-read+ "Prompt: " '("blue" "yellow" "green") nil t))
  146. :to-equal "")
  147. (expect
  148. (with-simulated-input "C-j"
  149. (ido-completing-read+ "Prompt: " '("blue" "yellow" "green") nil t))
  150. :to-equal ""))
  151. ;; Verify that DEF works, whether or not it is an element of
  152. ;; COLLECTION
  153. (it "should accept all the same forms of DEF as `completing-read-default'"
  154. (expect
  155. (with-simulated-input "RET"
  156. (ido-completing-read+ "Prompt: " '("blue" "yellow" "green") nil nil nil nil "green"))
  157. :to-equal "green")
  158. (expect
  159. (with-simulated-input "RET"
  160. (ido-completing-read+ "Prompt: " '("blue" "yellow" "green") nil t nil nil "green"))
  161. :to-equal "green")
  162. (expect
  163. (with-simulated-input "RET"
  164. (ido-completing-read+ "Prompt: " '("blue" "yellow" "brown") nil nil nil nil "brown"))
  165. :to-equal "brown")
  166. (expect
  167. (with-simulated-input "RET"
  168. (ido-completing-read+ "Prompt: " '("blue" "yellow" "brown") nil t nil nil "brown"))
  169. :to-equal "brown")
  170. (expect
  171. (with-simulated-input "RET"
  172. (ido-completing-read+ "Prompt: " '("blue" "yellow" "brown") nil t nil nil '("brown" "green")))
  173. :to-equal "brown"))
  174. ;; Verify that INITIAL-INPUT works
  175. (it "should work with INITIAL-INPUT"
  176. (expect
  177. (with-simulated-input "RET"
  178. (ido-completing-read+ "Prompt: " '("blue" "yellow" "green") nil nil "gr"))
  179. :to-equal "green"))
  180. ;; Verify that INITIAL-INPUT and DEF don't interfere with each other
  181. (it "should properly handle both INITIAL-INPUT and DEF at the same time"
  182. (expect
  183. (with-simulated-input "RET"
  184. (ido-completing-read+ "Prompt: " '("blue" "yellow" "green") nil nil "gr" nil "blue"))
  185. :to-equal "green")
  186. (expect
  187. (with-simulated-input "DEL DEL RET"
  188. (ido-completing-read+ "Prompt: " '("blue" "yellow" "green") nil nil "gr" nil "blue"))
  189. :to-equal "blue"))
  190. ;; Verify that ido-cr+ works on function collections
  191. (it "should work when COLLECTION is a function"
  192. (expect
  193. (with-simulated-input "g RET"
  194. (ido-completing-read+ "Prompt: " (collection-as-function '("blue" "yellow" "green"))))
  195. :to-equal "green"))
  196. (describe "when `ido-cr+-max-items' is set"
  197. (it "should not trigger a fallback for small collections"
  198. (expect
  199. (with-simulated-input "g RET"
  200. (ido-completing-read+ "Prompt: " '("blue" "yellow" "green")))
  201. :to-equal "green"))
  202. (it "should trigger a fallback for large collections"
  203. (expect
  204. ;; With max-items negative, all collections are considered "too
  205. ;; large"
  206. (let ((ido-cr+-max-items -1))
  207. (with-simulated-input "g RET"
  208. (ido-completing-read+ "Prompt: " '("blue" "yellow" "green"))))
  209. :to-equal "g")))
  210. (describe "when REQUIRE-MATCH is non-nil"
  211. (it "should still allow exiting with an empty string if DEF is nil"
  212. (expect
  213. (with-simulated-input "C-j"
  214. (ido-completing-read+
  215. "Prompt: "
  216. '("bluebird" "blues" "bluegrass" "blueberry" "yellow ""green") nil t))
  217. :to-equal ""))
  218. ;; "C-j" should NOT be allowed to return an empty string if
  219. ;; require-match and default are both non-nil.
  220. (it "should not alow exiting with an empty string if DEF is non-nil"
  221. (expect
  222. (lambda ()
  223. (with-simulated-input "C-j"
  224. (ido-completing-read+
  225. "Prompt: "
  226. '("bluebird" "blues" "bluegrass" "blueberry" "yellow ""green") nil t nil nil "yellow")))
  227. :to-throw))
  228. (it "shouldn't allow C-j to select an ambiguous match"
  229. (expect
  230. (lambda ()
  231. (with-simulated-input "b C-j C-j C-j"
  232. (ido-completing-read+
  233. "Prompt: "
  234. '("bluebird" "blues" "bluegrass" "blueberry" "yellow ""green") nil t)))
  235. :to-throw)
  236. ;; First press of C-j should complete to "blue" after the
  237. ;; first b, but then get stuck on the choice for the second b.
  238. (expect
  239. (lambda ()
  240. (with-simulated-input "b C-j b C-j C-j"
  241. (ido-completing-read+
  242. "Prompt: "
  243. '("bluebird" "blues" "bluegrass" "blueberry" "yellow ""green") nil t)))
  244. :to-throw))
  245. (it "should allow exiting with an unambiguous match"
  246. (expect
  247. (with-simulated-input "b C-j b C-j e C-j C-j"
  248. (ido-completing-read+
  249. "Prompt: "
  250. '("bluebird" "blues" "bluegrass" "blueberry" "yellow" "green") nil t))
  251. :to-equal "blueberry")
  252. ;; The "C-j" should complete to "bluegrass" and return, because
  253. ;; `ido-confirm-unique-completion is nil.
  254. (expect
  255. (with-simulated-input "b l u e g C-j"
  256. (ido-completing-read+
  257. "Prompt: "
  258. '("bluebird" "blues" "bluegrass" "blueberry" "yellow ""green") nil t))
  259. :to-equal "bluegrass"))
  260. (it "should require an extra C-j to exit when `ido-confirm-unique-completion' is non-nil"
  261. (setq ido-confirm-unique-completion t)
  262. ;; Now the first "C-j" should complete to "bluegrass" but should
  263. ;; not return.
  264. (expect
  265. (lambda ()
  266. (with-simulated-input "b l u e g C-j"
  267. (ido-completing-read+
  268. "Prompt: "
  269. '("bluebird" "blues" "bluegrass" "blueberry" "yellow ""green") nil t)))
  270. :to-throw)
  271. ;; The first "C-j" should complete to "bluegrass", and the second
  272. ;; should return.
  273. (expect
  274. (with-simulated-input "b l u e g C-j C-j"
  275. (ido-completing-read+
  276. "Prompt: "
  277. '("bluebird" "blues" "bluegrass" "blueberry" "yellow ""green") nil t))
  278. :to-equal "bluegrass"))
  279. ;; Finally, a test for the expected wrong behavior without
  280. ;; ido-cr+. If ido.el ever fixes this bug, it will cause this test
  281. ;; to fail as a signal that the workaround can be phased out.
  282. (it "should return a non-match when ordinary `ido-completing-read' is used"
  283. (expect
  284. (with-simulated-input "b C-j"
  285. (ido-completing-read
  286. "Prompt: "
  287. '("bluebird" "blues" "bluegrass" "blueberry" "yellow ""green") nil t))
  288. :to-equal "b")))
  289. (describe "with manual fallback shortcuts"
  290. (it "should not fall back when C-b or C-f is used in the middle of the input"
  291. (expect
  292. ;; C-b/f not at beginning/end of input should not fall back
  293. (with-simulated-input "g C-b C-f RET"
  294. (ido-completing-read+ "Prompt: " '("blue" "yellow" "green")))
  295. :to-equal "green"))
  296. (it "should fall back on C-f at end of input"
  297. (expect
  298. ;; C-f at end of input should fall back
  299. (with-simulated-input "g C-f RET"
  300. (ido-completing-read+ "Prompt: " '("blue" "yellow" "green")))
  301. :to-equal "g"))
  302. (it "should not fall back from repeated C-b that hits the start of input"
  303. (expect
  304. ;; Repeated C-b should not fall back
  305. (with-simulated-input "g C-b C-b C-b C-b RET"
  306. (ido-completing-read+ "Prompt: " '("blue" "yellow" "green")))
  307. :to-equal "green"))
  308. (it "should fall back on C-b at beginning of input (if previous action was not C-b)"
  309. (expect
  310. ;; C-b at beginning of line should fall back (if previous action
  311. ;; was not also C-b)
  312. (with-simulated-input "g C-b x DEL C-b RET"
  313. (ido-completing-read+ "Prompt: " '("blue" "yellow" "green")))
  314. :to-equal "g")))
  315. (describe "with a work workaround for an bug with `ido-enable-dot-prefix'"
  316. ;; See https://debbugs.gnu.org/cgi/bugreport.cgi?bug=26997
  317. ;; for more information on this bug.
  318. (before-each
  319. (setq ido-enable-dot-prefix t))
  320. (it "should not throw an error when `ido-enable-dot-prefix' is non-nil and \"\" is in the collection"
  321. (expect
  322. (with-simulated-input "RET"
  323. (ido-completing-read+ "Pick: " '("" "aaa" "aab" "aac")))
  324. :to-equal "")
  325. (expect
  326. (with-simulated-input "a a b RET"
  327. (ido-completing-read+ "Pick: " '("" "aaa" "aab" "aac")))
  328. :to-equal "aab")))
  329. (describe "with dynamic collections"
  330. (before-all
  331. (setq my-dynamic-collection
  332. (completion-table-dynamic
  333. (lambda (text)
  334. (cond
  335. ;; Sub-completions for "hello"
  336. ((s-prefix-p "hello" text)
  337. '("hello" "hello-world" "hello-everyone" "hello-universe"))
  338. ;; Sub-completions for "goodbye"
  339. ((s-prefix-p "goodbye" text)
  340. '("goodbye" "goodbye-world" "goodbye-everyone" "goodbye-universe"))
  341. ;; General completions
  342. (t
  343. '("hello" "goodbye" "helicopter" "helium" "goodness" "goodwill")))))))
  344. (after-all
  345. (setq my-dynamic-collection nil))
  346. (before-each
  347. (setq ido-enable-flex-matching t
  348. ido-confirm-unique-completion nil)
  349. (spy-on 'ido-cr+-update-dynamic-collection
  350. :and-call-through))
  351. (it "should allow selection of dynamically-added completions"
  352. (expect
  353. (with-simulated-input "hello- RET"
  354. (ido-completing-read+ "Say something: " my-dynamic-collection))
  355. :to-equal "hello-world")
  356. (expect 'ido-cr+-update-dynamic-collection
  357. :to-have-been-called))
  358. (it "should allow ido flex-matching of dynamically-added completions"
  359. (expect
  360. (with-simulated-input "hello-ld RET"
  361. (ido-completing-read+ "Say something: " my-dynamic-collection))
  362. :to-equal
  363. "hello-world")
  364. (expect 'ido-cr+-update-dynamic-collection
  365. :to-have-been-called))
  366. (it "should do a dynamic update when pressing TAB"
  367. (expect
  368. (with-simulated-input "h TAB -ld RET"
  369. (ido-completing-read+ "Say something: " my-dynamic-collection))
  370. :to-equal
  371. "hello-world")
  372. (expect 'ido-cr+-update-dynamic-collection
  373. :to-have-been-called))
  374. (it "should do a dynamic update when idle"
  375. (expect
  376. (with-simulated-input
  377. '("h"
  378. (wsi-simulate-idle-time (1+ ido-cr+-dynamic-update-idle-time))
  379. "-ld RET")
  380. (ido-completing-read+ "Say something: " my-dynamic-collection))
  381. :to-equal
  382. "hello-world")
  383. (expect 'ido-cr+-update-dynamic-collection
  384. :to-have-been-called))
  385. (it "should do a dynamic update when there is only one match remaining"
  386. (expect
  387. (with-simulated-input "hell-ld RET"
  388. (ido-completing-read+ "Say something: " my-dynamic-collection))
  389. :to-equal
  390. "hello-world")
  391. (expect 'ido-cr+-update-dynamic-collection
  392. :to-have-been-called))
  393. (it "should not exit with a unique match if new matches are dynamically added"
  394. (expect
  395. (with-simulated-input '("hell TAB -ld RET")
  396. (ido-completing-read+ "Say something: " my-dynamic-collection))
  397. :to-equal
  398. "hello-world")
  399. (expect 'ido-cr+-update-dynamic-collection
  400. :to-have-been-called))
  401. (it "should exit with a match that is still unique after dynamic updating"
  402. (expect
  403. (with-simulated-input '("helic TAB")
  404. (ido-completing-read+ "Say something: " my-dynamic-collection))
  405. :to-equal
  406. "helicopter")
  407. (expect 'ido-cr+-update-dynamic-collection
  408. :to-have-been-called)))
  409. (describe "with unusual inputs"
  410. (it "should accept a COLLECTION of symbols"
  411. (expect
  412. (with-simulated-input "g RET"
  413. (ido-completing-read+ "Prompt: " '(blue yellow green)))
  414. :to-equal "green"))
  415. (it "should accept a mix of strings and symbols in COLLECTION"
  416. (expect
  417. (with-simulated-input "g RET"
  418. (ido-completing-read+ "Prompt: " '(blue "yellow" green)))
  419. :to-equal "green"))
  420. (it "should accept symbols in DEF"
  421. (expect
  422. (with-simulated-input "RET"
  423. (ido-completing-read+ "Prompt: " '("blue" "yellow" "brown") nil t nil nil '(brown "green")))
  424. :to-equal "brown"))
  425. (it "should accept an alist COLLECTION"
  426. (expect
  427. (with-simulated-input "RET"
  428. (ido-completing-read+
  429. "Prompt: "
  430. '(("blue" . blue-value)
  431. ("yellow" . yellow-value)
  432. (green . green-value))
  433. nil nil nil nil "green"))
  434. :to-equal "green"))
  435. (it "should accept a hash table COLLECTION"
  436. (expect
  437. (with-simulated-input "RET"
  438. (let ((collection (make-hash-table)))
  439. (puthash "blue" 'blue-value collection)
  440. (puthash "yellow" 'yellow-value collection)
  441. (puthash 'green 'green-value collection)
  442. (ido-completing-read+ "Prompt: " collection nil nil nil nil "green")))
  443. :to-equal "green"))
  444. (it "should accept an obarray COLLECTION"
  445. (expect
  446. (with-simulated-input "forward-char RET"
  447. (ido-completing-read+ "Prompt: " obarray #'commandp
  448. t nil nil "backward-char"))
  449. :to-equal "forward-char"))))
  450. (describe "ido-ubiquitous-mode"
  451. ;; Set up a test command that calls `completing-read'
  452. (before-all
  453. (setf (symbol-function 'test-command)
  454. (lambda ()
  455. (interactive)
  456. (completing-read "Prompt: " '("blue" "yellow" "green")))))
  457. ;; Delete the test command
  458. (after-all
  459. (setf (symbol-function 'test-command) nil))
  460. ;; Verify that the mode can be activated
  461. (it "should enable itself properly"
  462. (expect
  463. (progn
  464. (ido-ubiquitous-mode 1)
  465. (with-simulated-input "g RET"
  466. (command-execute 'test-command)))
  467. :to-equal "green"))
  468. (it "should disable itself properly"
  469. (expect
  470. (progn
  471. (ido-ubiquitous-mode 0)
  472. (with-simulated-input "g RET"
  473. (command-execute 'test-command)))
  474. :to-equal "g"))
  475. (describe "with `ido-cr+-function-blacklist'"
  476. (before-all
  477. (setf (symbol-function 'blacklisted-command)
  478. (lambda (arg)
  479. (interactive (list (completing-read "Prompt: " '("blue" "yellow" "green"))))
  480. arg)
  481. (symbol-function 'blacklisted-function)
  482. (lambda ()
  483. (completing-read "Prompt: " '("blue" "yellow" "green")))
  484. (symbol-function 'cmd-that-calls-blacklisted-function)
  485. (lambda ()
  486. (interactive)
  487. (funcall 'blacklisted-function))
  488. (symbol-function 'blacklisted-collection)
  489. (collection-as-function '("blue" "yellow" "green"))))
  490. (after-all
  491. (setf (symbol-function 'blacklisted-command) nil
  492. (symbol-function 'blacklisted-function) nil
  493. (symbol-function 'cmd-that-calls-blacklisted-function) nil
  494. (symbol-function 'blacklisted-collection) nil))
  495. ;; First verify that they work normally before blacklisting them
  496. (describe "when the blacklist is empty"
  497. (it "should not affect a non-blacklisted command"
  498. (expect
  499. (with-simulated-input "g RET"
  500. (call-interactively 'blacklisted-command))
  501. :to-equal "green"))
  502. (it "should not affect a non-blacklisted function"
  503. (expect
  504. (with-simulated-input "g RET"
  505. (call-interactively 'cmd-that-calls-blacklisted-function))
  506. :to-equal "green"))
  507. (it "should not affect a non-blacklisted collection"
  508. (expect
  509. (with-simulated-input "g RET"
  510. (ido-completing-read+ "Prompt: " 'blacklisted-collection))
  511. :to-equal "green")))
  512. (describe "when the specified functions are blacklisted"
  513. (before-each
  514. (setq ido-cr+-function-blacklist
  515. (append '(blacklisted-command
  516. blacklisted-function
  517. blacklisted-collection)
  518. ido-cr+-function-blacklist)))
  519. (it "should prevent ido in a blacklisted command"
  520. (expect
  521. (with-simulated-input "g RET"
  522. (call-interactively 'blacklisted-command))
  523. :to-equal "g"))
  524. (it "should prevent ido in a blacklisted function"
  525. (expect
  526. (with-simulated-input "g RET"
  527. (call-interactively 'cmd-that-calls-blacklisted-function))
  528. :to-equal "g"))
  529. (it "should prevent ido with a blacklisted collection"
  530. (expect
  531. (with-simulated-input "g RET"
  532. (ido-completing-read+ "Prompt: " 'blacklisted-collection))
  533. :to-equal "g"))))
  534. (describe "with `ido-cr+-function-whitelist'"
  535. (before-all
  536. (setf (symbol-function 'whitelisted-command)
  537. (lambda (arg)
  538. (interactive
  539. (list
  540. (completing-read "Prompt: " '("blue" "yellow" "green"))))
  541. arg)
  542. (symbol-function 'whitelisted-function)
  543. (lambda ()
  544. (completing-read "Prompt: " '("blue" "yellow" "green")))
  545. (symbol-function 'cmd-that-calls-whitelisted-function)
  546. (lambda ()
  547. (interactive)
  548. (funcall 'whitelisted-function))
  549. (symbol-function 'whitelisted-collection)
  550. (lambda (string pred action)
  551. (complete-with-action action '("blue" "yellow" "green") string pred))))
  552. (after-all
  553. (setf (symbol-function 'whitelisted-command) nil
  554. (symbol-function 'whitelisted-function) nil
  555. (symbol-function 'cmd-that-calls-whitelisted-function) nil
  556. (symbol-function 'whitelisted-collection) nil))
  557. (describe "when the whitelist is inactive (i.e. everything is whitelisted)"
  558. (before-each
  559. (setq ido-cr+-function-whitelist nil))
  560. (it "should enable ido in a command"
  561. (expect
  562. (with-simulated-input "g RET"
  563. (call-interactively 'whitelisted-command))
  564. :to-equal "green"))
  565. (it "should enable ido in a function"
  566. (expect
  567. (with-simulated-input "g RET"
  568. (call-interactively 'cmd-that-calls-whitelisted-function))
  569. :to-equal "green"))
  570. (it "should enable ido for a collection"
  571. (expect
  572. (with-simulated-input "g RET"
  573. (ido-completing-read+ "Prompt: " 'whitelisted-collection))
  574. :to-equal "green")))
  575. (describe "when the specified functions are whitelisted"
  576. (before-each
  577. (setq ido-cr+-function-whitelist
  578. (append '(whitelisted-command
  579. whitelisted-function
  580. whitelisted-collection)
  581. ido-cr+-function-whitelist)))
  582. (it "should enable ido in a whitelisted command"
  583. (expect
  584. (with-simulated-input "g RET"
  585. (call-interactively 'whitelisted-command))
  586. :to-equal "green"))
  587. (it "should enable ido in a whitelisted function"
  588. (expect
  589. (with-simulated-input "g RET"
  590. (call-interactively 'cmd-that-calls-whitelisted-function))
  591. :to-equal "green"))
  592. (it "should enable ido for a whitelisted collection"
  593. (expect
  594. (with-simulated-input "g RET"
  595. (ido-completing-read+ "Prompt: " 'whitelisted-collection))
  596. :to-equal "green")))
  597. (describe "when the whitelist is active but empty (i.e. nothing whitelisted)"
  598. (before-each
  599. (setq ido-cr+-function-whitelist (list nil)))
  600. (it "should prevent ido in a command"
  601. (expect
  602. (with-simulated-input "g RET"
  603. (call-interactively 'whitelisted-command))
  604. :to-equal "g"))
  605. (it "should prevent ido in a function"
  606. (expect
  607. (with-simulated-input "g RET"
  608. (call-interactively 'cmd-that-calls-whitelisted-function))
  609. :to-equal "g"))
  610. (it "should prevent ido for a collection"
  611. (expect
  612. (with-simulated-input "g RET"
  613. (ido-completing-read+ "Prompt: " 'whitelisted-collection))
  614. :to-equal "g"))))
  615. (describe "with `ido-cr+-nil-def-alternate-behavior-list'"
  616. (before-all
  617. (setf (symbol-function 'def-nil-command)
  618. (lambda (arg)
  619. (interactive
  620. (list
  621. (completing-read "Prompt: " '("blue" "yellow" "green") nil t)))
  622. arg)
  623. (symbol-function 'def-nil-function)
  624. (lambda ()
  625. (completing-read "Prompt: " '("blue" "yellow" "green") nil t))
  626. (symbol-function 'cmd-that-calls-def-nil-function)
  627. (lambda ()
  628. (interactive)
  629. (funcall 'def-nil-function))
  630. (symbol-function 'def-nil-collection)
  631. (lambda (string pred action)
  632. (complete-with-action action '("blue" "yellow" "green") string pred))))
  633. (after-all
  634. (setf (symbol-function 'def-nil-command) nil
  635. (symbol-function 'def-nil-function) nil
  636. (symbol-function 'cmd-that-calls-def-nil-function) nil
  637. (symbol-function 'def-nil-collection) nil))
  638. (describe "when the specified functions are not in the list"
  639. (before-each
  640. (setq ido-cr+-nil-def-alternate-behavior-list nil))
  641. (it "should use empty string default in a command"
  642. (expect
  643. (with-simulated-input "RET"
  644. (call-interactively 'def-nil-command))
  645. :to-equal ""))
  646. (it "should use empty string default in a function"
  647. (expect
  648. (with-simulated-input "RET"
  649. (call-interactively 'cmd-that-calls-def-nil-function))
  650. :to-equal ""))
  651. (it "should use empty string default for a collection"
  652. (expect
  653. (with-simulated-input "RET"
  654. (ido-completing-read+ "Prompt: " 'def-nil-collection nil t))
  655. :to-equal "")))
  656. (describe "when the specified functions are in the list"
  657. (before-each
  658. (setq ido-cr+-nil-def-alternate-behavior-list
  659. (append '(def-nil-command
  660. def-nil-function
  661. def-nil-collection)
  662. ido-cr+-nil-def-alternate-behavior-list)))
  663. (it "should not use empty string default in a command"
  664. (expect
  665. (with-simulated-input "RET"
  666. (call-interactively 'def-nil-command))
  667. :to-equal "blue"))
  668. (it "should not use empty string default in a function"
  669. (expect
  670. (with-simulated-input "RET"
  671. (call-interactively 'cmd-that-calls-def-nil-function))
  672. :to-equal "blue"))
  673. (it "should not use empty string default for a collection"
  674. (expect
  675. (with-simulated-input "RET"
  676. (ido-completing-read+ "Prompt: " 'def-nil-collection nil t))
  677. :to-equal "blue"))))))
  678. ;; (defun ido-cr+-run-all-tests ()
  679. ;; (interactive)
  680. ;; (ert "^ido-cr\\+-"))
  681. ;;; test-ido-completing-read+.el ends here