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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739
  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. (it "should respect `ido-restrict-to-matches' when doing dynamic updates"
  403. ;; First verify it without a dynamic collection
  404. (expect
  405. (with-simulated-input "aa C-SPC b RET"
  406. (completing-read
  407. "Pick: "
  408. '(aaa aab aac bba bbb bbc cca ccb ccc)
  409. nil t nil nil "aaa"))
  410. :to-equal "aab")
  411. ;; Now test the same with a dynamic collection
  412. (expect
  413. (with-simulated-input "aa C-SPC b RET"
  414. (completing-read
  415. "Pick: "
  416. (collection-as-function '(aaa aab aac bba bbb bbc cca ccb ccc))
  417. nil t nil nil "aaa"))
  418. :to-equal "aab")))
  419. (describe "with unusual inputs"
  420. (it "should accept a COLLECTION of symbols"
  421. (expect
  422. (with-simulated-input "g RET"
  423. (ido-completing-read+ "Prompt: " '(blue yellow green)))
  424. :to-equal "green"))
  425. (it "should accept a mix of strings and symbols in COLLECTION"
  426. (expect
  427. (with-simulated-input "g RET"
  428. (ido-completing-read+ "Prompt: " '(blue "yellow" green)))
  429. :to-equal "green"))
  430. (it "should accept symbols in DEF"
  431. (expect
  432. (with-simulated-input "RET"
  433. (ido-completing-read+ "Prompt: " '("blue" "yellow" "brown") nil t nil nil '(brown "green")))
  434. :to-equal "brown"))
  435. (it "should accept an alist COLLECTION"
  436. (expect
  437. (with-simulated-input "RET"
  438. (ido-completing-read+
  439. "Prompt: "
  440. '(("blue" . blue-value)
  441. ("yellow" . yellow-value)
  442. (green . green-value))
  443. nil nil nil nil "green"))
  444. :to-equal "green"))
  445. (it "should accept a hash table COLLECTION"
  446. (expect
  447. (with-simulated-input "RET"
  448. (let ((collection (make-hash-table)))
  449. (puthash "blue" 'blue-value collection)
  450. (puthash "yellow" 'yellow-value collection)
  451. (puthash 'green 'green-value collection)
  452. (ido-completing-read+ "Prompt: " collection nil nil nil nil "green")))
  453. :to-equal "green"))
  454. (it "should accept an obarray COLLECTION"
  455. (expect
  456. (with-simulated-input "forward-char RET"
  457. (ido-completing-read+ "Prompt: " obarray #'commandp
  458. t nil nil "backward-char"))
  459. :to-equal "forward-char"))))
  460. (describe "ido-ubiquitous-mode"
  461. ;; Set up a test command that calls `completing-read'
  462. (before-all
  463. (setf (symbol-function 'test-command)
  464. (lambda ()
  465. (interactive)
  466. (completing-read "Prompt: " '("blue" "yellow" "green")))))
  467. ;; Delete the test command
  468. (after-all
  469. (setf (symbol-function 'test-command) nil))
  470. ;; Verify that the mode can be activated
  471. (it "should enable itself properly"
  472. (expect
  473. (progn
  474. (ido-ubiquitous-mode 1)
  475. (with-simulated-input "g RET"
  476. (command-execute 'test-command)))
  477. :to-equal "green"))
  478. (it "should disable itself properly"
  479. (expect
  480. (progn
  481. (ido-ubiquitous-mode 0)
  482. (with-simulated-input "g RET"
  483. (command-execute 'test-command)))
  484. :to-equal "g"))
  485. (describe "with `ido-cr+-function-blacklist'"
  486. (before-all
  487. (setf (symbol-function 'blacklisted-command)
  488. (lambda (arg)
  489. (interactive (list (completing-read "Prompt: " '("blue" "yellow" "green"))))
  490. arg)
  491. (symbol-function 'blacklisted-function)
  492. (lambda ()
  493. (completing-read "Prompt: " '("blue" "yellow" "green")))
  494. (symbol-function 'cmd-that-calls-blacklisted-function)
  495. (lambda ()
  496. (interactive)
  497. (funcall 'blacklisted-function))
  498. (symbol-function 'blacklisted-collection)
  499. (collection-as-function '("blue" "yellow" "green"))))
  500. (after-all
  501. (setf (symbol-function 'blacklisted-command) nil
  502. (symbol-function 'blacklisted-function) nil
  503. (symbol-function 'cmd-that-calls-blacklisted-function) nil
  504. (symbol-function 'blacklisted-collection) nil))
  505. ;; First verify that they work normally before blacklisting them
  506. (describe "when the blacklist is empty"
  507. (it "should not affect a non-blacklisted command"
  508. (expect
  509. (with-simulated-input "g RET"
  510. (call-interactively 'blacklisted-command))
  511. :to-equal "green"))
  512. (it "should not affect a non-blacklisted function"
  513. (expect
  514. (with-simulated-input "g RET"
  515. (call-interactively 'cmd-that-calls-blacklisted-function))
  516. :to-equal "green"))
  517. (it "should not affect a non-blacklisted collection"
  518. (expect
  519. (with-simulated-input "g RET"
  520. (ido-completing-read+ "Prompt: " 'blacklisted-collection))
  521. :to-equal "green")))
  522. (describe "when the specified functions are blacklisted"
  523. (before-each
  524. (setq ido-cr+-function-blacklist
  525. (append '(blacklisted-command
  526. blacklisted-function
  527. blacklisted-collection)
  528. ido-cr+-function-blacklist)))
  529. (it "should prevent ido in a blacklisted command"
  530. (expect
  531. (with-simulated-input "g RET"
  532. (call-interactively 'blacklisted-command))
  533. :to-equal "g"))
  534. (it "should prevent ido in a blacklisted function"
  535. (expect
  536. (with-simulated-input "g RET"
  537. (call-interactively 'cmd-that-calls-blacklisted-function))
  538. :to-equal "g"))
  539. (it "should prevent ido with a blacklisted collection"
  540. (expect
  541. (with-simulated-input "g RET"
  542. (ido-completing-read+ "Prompt: " 'blacklisted-collection))
  543. :to-equal "g"))))
  544. (describe "with `ido-cr+-function-whitelist'"
  545. (before-all
  546. (setf (symbol-function 'whitelisted-command)
  547. (lambda (arg)
  548. (interactive
  549. (list
  550. (completing-read "Prompt: " '("blue" "yellow" "green"))))
  551. arg)
  552. (symbol-function 'whitelisted-function)
  553. (lambda ()
  554. (completing-read "Prompt: " '("blue" "yellow" "green")))
  555. (symbol-function 'cmd-that-calls-whitelisted-function)
  556. (lambda ()
  557. (interactive)
  558. (funcall 'whitelisted-function))
  559. (symbol-function 'whitelisted-collection)
  560. (lambda (string pred action)
  561. (complete-with-action action '("blue" "yellow" "green") string pred))))
  562. (after-all
  563. (setf (symbol-function 'whitelisted-command) nil
  564. (symbol-function 'whitelisted-function) nil
  565. (symbol-function 'cmd-that-calls-whitelisted-function) nil
  566. (symbol-function 'whitelisted-collection) nil))
  567. (describe "when the whitelist is inactive (i.e. everything is whitelisted)"
  568. (before-each
  569. (setq ido-cr+-function-whitelist nil))
  570. (it "should enable ido in a command"
  571. (expect
  572. (with-simulated-input "g RET"
  573. (call-interactively 'whitelisted-command))
  574. :to-equal "green"))
  575. (it "should enable ido in a function"
  576. (expect
  577. (with-simulated-input "g RET"
  578. (call-interactively 'cmd-that-calls-whitelisted-function))
  579. :to-equal "green"))
  580. (it "should enable ido for a collection"
  581. (expect
  582. (with-simulated-input "g RET"
  583. (ido-completing-read+ "Prompt: " 'whitelisted-collection))
  584. :to-equal "green")))
  585. (describe "when the specified functions are whitelisted"
  586. (before-each
  587. (setq ido-cr+-function-whitelist
  588. (append '(whitelisted-command
  589. whitelisted-function
  590. whitelisted-collection)
  591. ido-cr+-function-whitelist)))
  592. (it "should enable ido in a whitelisted command"
  593. (expect
  594. (with-simulated-input "g RET"
  595. (call-interactively 'whitelisted-command))
  596. :to-equal "green"))
  597. (it "should enable ido in a whitelisted function"
  598. (expect
  599. (with-simulated-input "g RET"
  600. (call-interactively 'cmd-that-calls-whitelisted-function))
  601. :to-equal "green"))
  602. (it "should enable ido for a whitelisted collection"
  603. (expect
  604. (with-simulated-input "g RET"
  605. (ido-completing-read+ "Prompt: " 'whitelisted-collection))
  606. :to-equal "green")))
  607. (describe "when the whitelist is active but empty (i.e. nothing whitelisted)"
  608. (before-each
  609. (setq ido-cr+-function-whitelist (list nil)))
  610. (it "should prevent ido in a command"
  611. (expect
  612. (with-simulated-input "g RET"
  613. (call-interactively 'whitelisted-command))
  614. :to-equal "g"))
  615. (it "should prevent ido in a function"
  616. (expect
  617. (with-simulated-input "g RET"
  618. (call-interactively 'cmd-that-calls-whitelisted-function))
  619. :to-equal "g"))
  620. (it "should prevent ido for a collection"
  621. (expect
  622. (with-simulated-input "g RET"
  623. (ido-completing-read+ "Prompt: " 'whitelisted-collection))
  624. :to-equal "g"))))
  625. (describe "with `ido-cr+-nil-def-alternate-behavior-list'"
  626. (before-all
  627. (setf (symbol-function 'def-nil-command)
  628. (lambda (arg)
  629. (interactive
  630. (list
  631. (completing-read "Prompt: " '("blue" "yellow" "green") nil t)))
  632. arg)
  633. (symbol-function 'def-nil-function)
  634. (lambda ()
  635. (completing-read "Prompt: " '("blue" "yellow" "green") nil t))
  636. (symbol-function 'cmd-that-calls-def-nil-function)
  637. (lambda ()
  638. (interactive)
  639. (funcall 'def-nil-function))
  640. (symbol-function 'def-nil-collection)
  641. (lambda (string pred action)
  642. (complete-with-action action '("blue" "yellow" "green") string pred))))
  643. (after-all
  644. (setf (symbol-function 'def-nil-command) nil
  645. (symbol-function 'def-nil-function) nil
  646. (symbol-function 'cmd-that-calls-def-nil-function) nil
  647. (symbol-function 'def-nil-collection) nil))
  648. (describe "when the specified functions are not in the list"
  649. (before-each
  650. (setq ido-cr+-nil-def-alternate-behavior-list nil))
  651. (it "should use empty string default in a command"
  652. (expect
  653. (with-simulated-input "RET"
  654. (call-interactively 'def-nil-command))
  655. :to-equal ""))
  656. (it "should use empty string default in a function"
  657. (expect
  658. (with-simulated-input "RET"
  659. (call-interactively 'cmd-that-calls-def-nil-function))
  660. :to-equal ""))
  661. (it "should use empty string default for a collection"
  662. (expect
  663. (with-simulated-input "RET"
  664. (ido-completing-read+ "Prompt: " 'def-nil-collection nil t))
  665. :to-equal "")))
  666. (describe "when the specified functions are in the list"
  667. (before-each
  668. (setq ido-cr+-nil-def-alternate-behavior-list
  669. (append '(def-nil-command
  670. def-nil-function
  671. def-nil-collection)
  672. ido-cr+-nil-def-alternate-behavior-list)))
  673. (it "should not use empty string default in a command"
  674. (expect
  675. (with-simulated-input "RET"
  676. (call-interactively 'def-nil-command))
  677. :to-equal "blue"))
  678. (it "should not use empty string default in a function"
  679. (expect
  680. (with-simulated-input "RET"
  681. (call-interactively 'cmd-that-calls-def-nil-function))
  682. :to-equal "blue"))
  683. (it "should not use empty string default for a collection"
  684. (expect
  685. (with-simulated-input "RET"
  686. (ido-completing-read+ "Prompt: " 'def-nil-collection nil t))
  687. :to-equal "blue"))))))
  688. ;; (defun ido-cr+-run-all-tests ()
  689. ;; (interactive)
  690. ;; (ert "^ido-cr\\+-"))
  691. ;;; test-ido-completing-read+.el ends here