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

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