test-ido-completing-read+-with-flx-ido.el 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. ;;; -*- lexical-binding: t -*-
  2. ;; This file contains tests specifically for ido-cr+ interoperating
  3. ;; with flx-ido. These tests were split out from the main test file,
  4. ;; which unfortunately means that they brought a lot of the
  5. ;; scaffolding from the main test file with them. This might get
  6. ;; cleaned up at a later date. Putting these in a separate file is
  7. ;; necessary so that the main test suite can be both with and without
  8. ;; flx-ido loaded.
  9. (require 'ido)
  10. (require 'flx-ido)
  11. (require 'minibuf-eldef)
  12. (require 'ido-completing-read+)
  13. (require 'buttercup)
  14. (require 'cl-lib)
  15. (require 'with-simulated-input)
  16. (defun collection-as-function (collection)
  17. "Return a function equivalent to COLLECTION.
  18. The returned function will work equivalently to COLLECTION when
  19. passed to `all-completions' and `try-completion'."
  20. (completion-table-dynamic (lambda (string) (all-completions string collection))))
  21. (defun shadow-var (var &optional temp-value)
  22. "Shadow the value of VAR.
  23. This will push the current value of VAR to VAR's
  24. `shadowed-values' property, and then set it to TEMP-VALUE. To
  25. reverse this process, call `unshadow-var' on VAR. Vars can
  26. be shadowed recursively, and must be unshadowed once for each
  27. shadowing in order to restore the original value. You can think
  28. of shadowing as dynamic binding with `let', but with manual
  29. control over when bindings start and end.
  30. If VAR is a Custom variable (see `custom-variable-p'), it will be
  31. set using `customize-set-variable', and if TEMP-VALUE is nil it
  32. will be replaces with VAR's standard value.
  33. Other variables will be set with `set-default', and a TEMP-VALUE
  34. of nil will not be treated specially.
  35. `shadow-var' only works on variables declared as special (i.e.
  36. using `defvar' or similar). It will not work on lexically bound
  37. variables."
  38. (unless (special-variable-p var)
  39. (error "Cannot shadow lexical var `%s'" var))
  40. (let* ((use-custom (custom-variable-p var))
  41. (setter (if use-custom 'customize-set-variable 'set-default))
  42. (temp-value (or temp-value
  43. (and use-custom
  44. (eval (car (get var 'standard-value)))))))
  45. ;; Push the current value on the stack
  46. (push (symbol-value var) (get var 'shadowed-values))
  47. (funcall setter var temp-value)))
  48. (defun var-shadowed-p (var)
  49. "Return non-nil if VAR is shadowed by `shadow-var'."
  50. ;; We don't actually want to return that list if it's non-nil.
  51. (and (get var 'shadowed-values) t))
  52. (defun unshadow-var (var)
  53. "Reverse the last call to `shadow-var' on VAR."
  54. (if (var-shadowed-p var)
  55. (let* ((use-custom (custom-variable-p var))
  56. (setter (if use-custom 'customize-set-variable 'set-default))
  57. (value (pop (get var 'shadowed-values))))
  58. (funcall setter var value))
  59. (error "Var is not shadowed: %s" var)))
  60. (defun fully-unshadow-var (var)
  61. "Reverse *all* calls to `shadow-var' on VAR."
  62. (when (var-shadowed-p var)
  63. (let* ((use-custom (custom-variable-p var))
  64. (setter (if use-custom 'customize-set-variable 'set-default))
  65. (value (car (last (get var 'shadowed-values)))))
  66. (put var 'shadowed-values nil)
  67. (funcall setter var value))))
  68. (defun fully-unshadow-all-vars (&optional vars)
  69. "Reverse *all* calls to `shadow-var' on VARS.
  70. If VARS is nil, unshadow *all* variables."
  71. (if vars
  72. (mapc #'fully-unshadow-var vars)
  73. (mapatoms #'fully-unshadow-var))
  74. nil)
  75. (defmacro shadow-vars (varlist)
  76. "Shadow a list of vars with new values.
  77. VARLIST describes the variables to be shadowed with the same
  78. syntax as `let'.
  79. See `shadow-var'."
  80. (declare (indent 0))
  81. (cl-loop
  82. with var = nil
  83. with value = nil
  84. for binding in varlist
  85. if (symbolp binding)
  86. do (setq var binding
  87. value nil)
  88. else
  89. do (setq var (car binding)
  90. value (cadr binding))
  91. collect `(shadow-var ',var ,value) into exprs
  92. finally return `(progn ,@exprs)))
  93. (defmacro unshadow-vars (vars)
  94. "Un-shadow a list of VARS.
  95. This is a macro for consistency with `shadow-vars', but it will
  96. also accept a quoted list for the sake of convenience."
  97. (declare (indent 0))
  98. (when (eq (car vars) 'quote)
  99. (setq vars (eval vars)))
  100. `(mapc #'unshadow-var ',vars))
  101. (describe "Within the `ido-completing-read+' package"
  102. ;; Reset all of these variables to their standard values before each
  103. ;; test, saving the previous values for later restoration.
  104. (before-each
  105. (shadow-vars
  106. ((ido-mode t)
  107. (ido-ubiquitous-mode t)
  108. (ido-cr+-debug-mode t)
  109. ido-cr+-auto-update-blacklist
  110. ido-cr+-fallback-function
  111. ido-cr+-max-items
  112. ido-cr+-function-blacklist
  113. ido-cr+-function-whitelist
  114. ido-cr+-nil-def-alternate-behavior-list
  115. ido-cr+-replace-completely
  116. ido-confirm-unique-completion
  117. ido-enable-flex-matching
  118. ido-enable-dot-prefix
  119. flx-ido-mode
  120. (minibuffer-electric-default-mode t)))
  121. ;; Suppress all messages during tests
  122. (spy-on 'message))
  123. ;; Restore the saved values after each test
  124. (after-each
  125. (fully-unshadow-all-vars))
  126. (describe "the `ido-completing-read+' function"
  127. (describe "with dynamic collections"
  128. (before-all
  129. (setq my-dynamic-collection
  130. (completion-table-dynamic
  131. (lambda (text)
  132. (cond
  133. ;; Sub-completions for "hello"
  134. ((s-prefix-p "hello" text)
  135. '("hello" "hello-world" "hello-everyone" "hello-universe"))
  136. ;; Sub-completions for "goodbye"
  137. ((s-prefix-p "goodbye" text)
  138. '("goodbye" "goodbye-world" "goodbye-everyone" "goodbye-universe"))
  139. ;; General completions
  140. (t
  141. '("hello" "goodbye" "helicopter" "helium" "goodness" "goodwill")))))))
  142. (after-all
  143. (setq my-dynamic-collection nil))
  144. (before-each
  145. (setq ido-enable-flex-matching t
  146. ido-confirm-unique-completion nil)
  147. (spy-on 'ido-cr+-update-dynamic-collection
  148. :and-call-through))
  149. (describe "with flx-ido-mode"
  150. (before-each
  151. (flx-ido-mode 1)
  152. (flx-ido-reset))
  153. (it "should allow selection of dynamically-added completions"
  154. (expect
  155. (with-simulated-input "hello-w RET"
  156. (ido-completing-read+ "Say something: " my-dynamic-collection))
  157. :to-equal "hello-world")
  158. (expect 'ido-cr+-update-dynamic-collection
  159. :to-have-been-called))
  160. (it "should allow ido flex-matching of dynamically-added completions"
  161. (expect
  162. (with-simulated-input "hello-ld RET"
  163. (ido-completing-read+ "Say something: " my-dynamic-collection))
  164. :to-equal
  165. "hello-world")
  166. (expect 'ido-cr+-update-dynamic-collection
  167. :to-have-been-called))
  168. (it "should do a dynamic update when pressing TAB"
  169. (expect
  170. (with-simulated-input "h TAB -ld RET"
  171. (ido-completing-read+ "Say something: " my-dynamic-collection))
  172. :to-equal
  173. "hello-world")
  174. (expect 'ido-cr+-update-dynamic-collection
  175. :to-have-been-called))
  176. (it "should do a dynamic update when idle"
  177. (expect
  178. (with-simulated-input
  179. '("h"
  180. (wsi-simulate-idle-time (1+ ido-cr+-dynamic-update-idle-time))
  181. "-ld RET")
  182. (ido-completing-read+ "Say something: " my-dynamic-collection))
  183. :to-equal
  184. "hello-world")
  185. (expect 'ido-cr+-update-dynamic-collection
  186. :to-have-been-called))
  187. (it "should do a dynamic update when there is only one match remaining"
  188. (expect
  189. (with-simulated-input "hell-ld RET"
  190. (ido-completing-read+ "Say something: " my-dynamic-collection))
  191. :to-equal
  192. "hello-world")
  193. (expect 'ido-cr+-update-dynamic-collection
  194. :to-have-been-called))
  195. (it "should not exit with a unique match if new matches are dynamically added"
  196. (expect
  197. (with-simulated-input '("hell TAB -ld RET")
  198. (ido-completing-read+ "Say something: " my-dynamic-collection))
  199. :to-equal
  200. "hello-world")
  201. (expect 'ido-cr+-update-dynamic-collection
  202. :to-have-been-called))
  203. (it "should exit with a match that is still unique after dynamic updating"
  204. (expect
  205. (with-simulated-input '("helic TAB")
  206. (ido-completing-read+ "Say something: " my-dynamic-collection))
  207. :to-equal
  208. "helicopter")
  209. (expect 'ido-cr+-update-dynamic-collection
  210. :to-have-been-called))
  211. (it "should respect `ido-restrict-to-matches' when doing dynamic updates"
  212. (let ((collection
  213. (list "aaa-ddd-ggg" "aaa-eee-ggg" "aaa-fff-ggg"
  214. "bbb-ddd-ggg" "bbb-eee-ggg" "bbb-fff-ggg"
  215. "ccc-ddd-ggg" "ccc-eee-ggg" "ccc-fff-ggg"
  216. "aaa-ddd-hhh" "aaa-eee-hhh" "aaa-fff-hhh"
  217. "bbb-ddd-hhh" "bbb-eee-hhh" "bbb-fff-hhh"
  218. "ccc-ddd-hhh" "ccc-eee-hhh" "ccc-fff-hhh"
  219. "aaa-ddd-iii" "aaa-eee-iii" "aaa-fff-iii"
  220. "bbb-ddd-iii" "bbb-eee-iii" "bbb-fff-iii"
  221. "ccc-ddd-iii" "ccc-eee-iii" "ccc-fff-iii")))
  222. ;; Test the internal function
  223. (expect
  224. (ido-cr+-apply-restrictions
  225. collection
  226. (list (cons nil "bbb")
  227. (cons nil "eee")))
  228. :to-equal '("bbb-eee-ggg" "bbb-eee-hhh" "bbb-eee-iii"))
  229. ;; First verify it without a dynamic collection
  230. (expect
  231. (with-simulated-input "eee C-SPC bbb C-SPC ggg RET"
  232. (ido-completing-read+
  233. "Pick: " collection nil t nil nil (car collection)))
  234. :to-equal "bbb-eee-ggg")
  235. ;; Now test the same with a dynamic collection
  236. (expect
  237. (with-simulated-input "eee C-SPC bbb C-SPC ggg RET"
  238. (ido-completing-read+
  239. "Pick: " (collection-as-function collection) nil t nil nil (car collection)))
  240. :to-equal "bbb-eee-ggg")))))))
  241. ;;; test-ido-completing-read+.el ends here