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

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