DarwinAwardWinner / with-simulated-input

Test your interactive elisp functions non-interactively!
GNU General Public License v3.0
38 stars 4 forks source link

Testing helm-projectile-switch-project not working #5

Closed codygman closed 4 years ago

codygman commented 4 years ago

I tried taking the example at the end of #1 that worked for helm org rifle:

(with-simulated-input '("word SPC :tag:" (wsi-simulate-idle-time 1) "RET")
  (helm-org-rifle-occur))

Then using it on helm-projectile-switch-project:

(with-simulated-input '("my-emacs SPC" (wsi-simulate-idle-time 1) "RET")
  (helm-projectile-switch-project))

I did notice that if I make my input something like gibberish SPC instead of my-emacs SPC that definitely doesn't exist then I succesfully? get back nil.

Maybe I misunderstand something, this isn't currently supported, or I need a different idle time.

DarwinAwardWinner commented 4 years ago

I'm not very familiar with helm. Can you explain what each example should do, and what it does wrong instead?

codygman commented 4 years ago

I've made a simpler example that is runnable with just helm and with-simulated-input installed:

  (defun email-helm-example ()
    (helm :sources `((name . "Simple helm names example")
                     (candidates . ,(list "jane" "john"))
                     (action . (lambda (candidate) (helm-marked-candidates))))))

  (string-equal "john" (with-simulated-input '((wsi-simulate-idle-time 1 t) "jo" (wsi-simulate-idle-time 1 t) "RET") (car (email-helm-example))))

In this example I'm simulating myself calling (email-helm-example), waiting one second, typing "jo" where the only remaining candidate is "john", waiting one second, then hitting RET. I expect the returned text to be "john" but instead I get an error of:

Debugger entered--Lisp error: (error "Reached end of simulated input while evaluating bo...")
  signal(error ("Reached end of simulated input while evaluating bo..."))
  error("Reached end of simulated input while evaluating bo...")
  (if (eq result wsi--canary-sym) (error "Reached end of simulated input while evaluating bo...") result)
  (let ((action-map (make-sparse-keymap))) (define-key action-map (kbd next-action-key) 'wsi-run-next-action) (setq thrown-error (catch 'wsi-threw-error (setq result (catch 'wsi-body-finished (let ((overriding-terminal-local-map action-map)) (execute-kbd-macro (kbd full-key-sequence))))) (throw 'wsi-threw-error nil))) (when thrown-error (signal (car thrown-error) (cdr thrown-error))) (if (eq result wsi--canary-sym) (error "Reached end of simulated input while evaluating bo...") result))
  (cl-letf ((action-map (make-sparse-keymap))) (define-key action-map (kbd next-action-key) 'wsi-run-next-action) (setq thrown-error (catch 'wsi-threw-error (setq result (catch 'wsi-body-finished (let ((overriding-terminal-local-map action-map)) (execute-kbd-macro (kbd full-key-sequence))))) (throw 'wsi-threw-error nil))) (when thrown-error (signal (car thrown-error) (cdr thrown-error))) (if (eq result wsi--canary-sym) (error "Reached end of simulated input while evaluating bo...") result))
  (progn (fset 'wsi-run-next-action vnew) (cl-letf ((action-map (make-sparse-keymap))) (define-key action-map (kbd next-action-key) 'wsi-run-next-action) (setq thrown-error (catch 'wsi-threw-error (setq result (catch 'wsi-body-finished (let (...) (execute-kbd-macro ...)))) (throw 'wsi-threw-error nil))) (when thrown-error (signal (car thrown-error) (cdr thrown-error))) (if (eq result wsi--canary-sym) (error "Reached end of simulated input while evaluating bo...") result)))
  (unwind-protect (progn (fset 'wsi-run-next-action vnew) (cl-letf ((action-map (make-sparse-keymap))) (define-key action-map (kbd next-action-key) 'wsi-run-next-action) (setq thrown-error (catch 'wsi-threw-error (setq result (catch 'wsi-body-finished (let ... ...))) (throw 'wsi-threw-error nil))) (when thrown-error (signal (car thrown-error) (cdr thrown-error))) (if (eq result wsi--canary-sym) (error "Reached end of simulated input while evaluating bo...") result))) (fset 'wsi-run-next-action old))
  (let* ((vnew (lambda nil (interactive) (condition-case err (if action-closures (let (...) (funcall next-action)) (error "`with-simulated-input' reached end of action list ...")) (error (throw 'wsi-threw-error err))))) (old (symbol-function 'wsi-run-next-action))) (unwind-protect (progn (fset 'wsi-run-next-action vnew) (cl-letf ((action-map (make-sparse-keymap))) (define-key action-map (kbd next-action-key) 'wsi-run-next-action) (setq thrown-error (catch 'wsi-threw-error (setq result (catch ... ...)) (throw 'wsi-threw-error nil))) (when thrown-error (signal (car thrown-error) (cdr thrown-error))) (if (eq result wsi--canary-sym) (error "Reached end of simulated input while evaluating bo...") result))) (fset 'wsi-run-next-action old)))
  (cl-letf (((symbol-function 'wsi-run-next-action) (lambda nil (interactive) (condition-case err (if action-closures (let (...) (funcall next-action)) (error "`with-simulated-input' reached end of action list ...")) (error (throw 'wsi-threw-error err)))))) (cl-letf ((action-map (make-sparse-keymap))) (define-key action-map (kbd next-action-key) 'wsi-run-next-action) (setq thrown-error (catch 'wsi-threw-error (setq result (catch 'wsi-body-finished (let (...) (execute-kbd-macro ...)))) (throw 'wsi-threw-error nil))) (when thrown-error (signal (car thrown-error) (cdr thrown-error))) (if (eq result wsi--canary-sym) (error "Reached end of simulated input while evaluating bo...") result)))
  (let ((full-key-sequence (cl-loop for action in keylist if (stringp action) collect action into key-sequence-list else collect next-action-key into key-sequence-list finally return (concat next-action-key " " next-action-key " " (mapconcat #'identity key-sequence-list " ") " " next-action-key)))) (cl-letf (((symbol-function 'wsi-run-next-action) (lambda nil (interactive) (condition-case err (if action-closures (let ... ...) (error "`with-simulated-input' reached end of action list ...")) (error (throw ... err)))))) (cl-letf ((action-map (make-sparse-keymap))) (define-key action-map (kbd next-action-key) 'wsi-run-next-action) (setq thrown-error (catch 'wsi-threw-error (setq result (catch 'wsi-body-finished (let ... ...))) (throw 'wsi-threw-error nil))) (when thrown-error (signal (car thrown-error) (cdr thrown-error))) (if (eq result wsi--canary-sym) (error "Reached end of simulated input while evaluating bo...") result))))
  (cl-letf ((full-key-sequence (cl-loop for action in keylist if (stringp action) collect action into key-sequence-list else collect next-action-key into key-sequence-list finally return (concat next-action-key " " next-action-key " " (mapconcat #'identity key-sequence-list " ") " " next-action-key)))) (cl-letf (((symbol-function 'wsi-run-next-action) (lambda nil (interactive) (condition-case err (if action-closures (let ... ...) (error "`with-simulated-input' reached end of action list ...")) (error (throw ... err)))))) (cl-letf ((action-map (make-sparse-keymap))) (define-key action-map (kbd next-action-key) 'wsi-run-next-action) (setq thrown-error (catch 'wsi-threw-error (setq result (catch 'wsi-body-finished (let ... ...))) (throw 'wsi-threw-error nil))) (when thrown-error (signal (car thrown-error) (cdr thrown-error))) (if (eq result wsi--canary-sym) (error "Reached end of simulated input while evaluating bo...") result))))
  (let ((action-closures (cl-loop for action in action-list collect (wsi-make-closure action lexenv)))) (cl-letf ((full-key-sequence (cl-loop for action in keylist if (stringp action) collect action into key-sequence-list else collect next-action-key into key-sequence-list finally return (concat next-action-key " " next-action-key " " (mapconcat #'identity key-sequence-list " ") " " next-action-key)))) (cl-letf (((symbol-function 'wsi-run-next-action) (lambda nil (interactive) (condition-case err (if action-closures ... ...) (error ...))))) (cl-letf ((action-map (make-sparse-keymap))) (define-key action-map (kbd next-action-key) 'wsi-run-next-action) (setq thrown-error (catch 'wsi-threw-error (setq result (catch ... ...)) (throw 'wsi-threw-error nil))) (when thrown-error (signal (car thrown-error) (cdr thrown-error))) (if (eq result wsi--canary-sym) (error "Reached end of simulated input while evaluating bo...") result)))))
  (cl-letf ((action-closures (cl-loop for action in action-list collect (wsi-make-closure action lexenv)))) (cl-letf ((full-key-sequence (cl-loop for action in keylist if (stringp action) collect action into key-sequence-list else collect next-action-key into key-sequence-list finally return (concat next-action-key " " next-action-key " " (mapconcat #'identity key-sequence-list " ") " " next-action-key)))) (cl-letf (((symbol-function 'wsi-run-next-action) (lambda nil (interactive) (condition-case err (if action-closures ... ...) (error ...))))) (cl-letf ((action-map (make-sparse-keymap))) (define-key action-map (kbd next-action-key) 'wsi-run-next-action) (setq thrown-error (catch 'wsi-threw-error (setq result (catch ... ...)) (throw 'wsi-threw-error nil))) (when thrown-error (signal (car thrown-error) (cdr thrown-error))) (if (eq result wsi--canary-sym) (error "Reached end of simulated input while evaluating bo...") result)))))
  (let ((action-list (nconc (list (list 'switch-to-buffer correct-current-buffer) body-form) (cl-loop for action in keylist if (not (stringp action)) collect action) (list end-of-actions-form)))) (cl-letf ((action-closures (cl-loop for action in action-list collect (wsi-make-closure action lexenv)))) (cl-letf ((full-key-sequence (cl-loop for action in keylist if (stringp action) collect action into key-sequence-list else collect next-action-key into key-sequence-list finally return (concat next-action-key " " next-action-key " " (mapconcat ... key-sequence-list " ") " " next-action-key)))) (cl-letf (((symbol-function 'wsi-run-next-action) (lambda nil (interactive) (condition-case err ... ...)))) (cl-letf ((action-map (make-sparse-keymap))) (define-key action-map (kbd next-action-key) 'wsi-run-next-action) (setq thrown-error (catch 'wsi-threw-error (setq result ...) (throw ... nil))) (when thrown-error (signal (car thrown-error) (cdr thrown-error))) (if (eq result wsi--canary-sym) (error "Reached end of simulated input while evaluating bo...") result))))))
  (cl-letf ((action-list (nconc (list (list 'switch-to-buffer correct-current-buffer) body-form) (cl-loop for action in keylist if (not (stringp action)) collect action) (list end-of-actions-form)))) (cl-letf ((action-closures (cl-loop for action in action-list collect (wsi-make-closure action lexenv)))) (cl-letf ((full-key-sequence (cl-loop for action in keylist if (stringp action) collect action into key-sequence-list else collect next-action-key into key-sequence-list finally return (concat next-action-key " " next-action-key " " (mapconcat ... key-sequence-list " ") " " next-action-key)))) (cl-letf (((symbol-function 'wsi-run-next-action) (lambda nil (interactive) (condition-case err ... ...)))) (cl-letf ((action-map (make-sparse-keymap))) (define-key action-map (kbd next-action-key) 'wsi-run-next-action) (setq thrown-error (catch 'wsi-threw-error (setq result ...) (throw ... nil))) (when thrown-error (signal (car thrown-error) (cdr thrown-error))) (if (eq result wsi--canary-sym) (error "Reached end of simulated input while evaluating bo...") result))))))
  (let ((keylist (if (listp keylist) keylist (list keylist)))) (cl-letf ((action-list (nconc (list (list 'switch-to-buffer correct-current-buffer) body-form) (cl-loop for action in keylist if (not (stringp action)) collect action) (list end-of-actions-form)))) (cl-letf ((action-closures (cl-loop for action in action-list collect (wsi-make-closure action lexenv)))) (cl-letf ((full-key-sequence (cl-loop for action in keylist if (stringp action) collect action into key-sequence-list else collect next-action-key into key-sequence-list finally return (concat next-action-key " " next-action-key " " ... " " next-action-key)))) (cl-letf (((symbol-function ...) (lambda nil ... ...))) (cl-letf ((action-map ...)) (define-key action-map (kbd next-action-key) 'wsi-run-next-action) (setq thrown-error (catch ... ... ...)) (when thrown-error (signal ... ...)) (if (eq result wsi--canary-sym) (error "Reached end of simulated input while evaluating bo...") result)))))))
  (cl-letf ((keylist (if (listp keylist) keylist (list keylist)))) (cl-letf ((action-list (nconc (list (list 'switch-to-buffer correct-current-buffer) body-form) (cl-loop for action in keylist if (not (stringp action)) collect action) (list end-of-actions-form)))) (cl-letf ((action-closures (cl-loop for action in action-list collect (wsi-make-closure action lexenv)))) (cl-letf ((full-key-sequence (cl-loop for action in keylist if (stringp action) collect action into key-sequence-list else collect next-action-key into key-sequence-list finally return (concat next-action-key " " next-action-key " " ... " " next-action-key)))) (cl-letf (((symbol-function ...) (lambda nil ... ...))) (cl-letf ((action-map ...)) (define-key action-map (kbd next-action-key) 'wsi-run-next-action) (setq thrown-error (catch ... ... ...)) (when thrown-error (signal ... ...)) (if (eq result wsi--canary-sym) (error "Reached end of simulated input while evaluating bo...") result)))))))
  (let ((keylist '((wsi-simulate-idle-time 1 t) "jo" (wsi-simulate-idle-time 1 t) "RET"))) (cl-letf ((keylist (if (listp keylist) keylist (list keylist)))) (cl-letf ((action-list (nconc (list (list ... correct-current-buffer) body-form) (cl-loop for action in keylist if (not ...) collect action) (list end-of-actions-form)))) (cl-letf ((action-closures (cl-loop for action in action-list collect (wsi-make-closure action lexenv)))) (cl-letf ((full-key-sequence (cl-loop for action in keylist if ... collect action into key-sequence-list else collect next-action-key into key-sequence-list finally return ...))) (cl-letf ((... ...)) (cl-letf (...) (define-key action-map ... ...) (setq thrown-error ...) (when thrown-error ...) (if ... ... result))))))))
  (cl-letf ((keylist '((wsi-simulate-idle-time 1 t) "jo" (wsi-simulate-idle-time 1 t) "RET"))) (cl-letf ((keylist (if (listp keylist) keylist (list keylist)))) (cl-letf ((action-list (nconc (list (list ... correct-current-buffer) body-form) (cl-loop for action in keylist if (not ...) collect action) (list end-of-actions-form)))) (cl-letf ((action-closures (cl-loop for action in action-list collect (wsi-make-closure action lexenv)))) (cl-letf ((full-key-sequence (cl-loop for action in keylist if ... collect action into key-sequence-list else collect next-action-key into key-sequence-list finally return ...))) (cl-letf ((... ...)) (cl-letf (...) (define-key action-map ... ...) (setq thrown-error ...) (when thrown-error ...) (if ... ... result))))))))
  (let ((end-of-actions-form (list 'throw ''wsi-body-finished (list 'quote wsi--canary-sym)))) (cl-letf ((keylist '((wsi-simulate-idle-time 1 t) "jo" (wsi-simulate-idle-time 1 t) "RET"))) (cl-letf ((keylist (if (listp keylist) keylist (list keylist)))) (cl-letf ((action-list (nconc (list ... body-form) (cl-loop for action in keylist if ... collect action) (list end-of-actions-form)))) (cl-letf ((action-closures (cl-loop for action in action-list collect ...))) (cl-letf ((full-key-sequence ...)) (cl-letf (...) (cl-letf ... ... ... ... ...))))))))
  (cl-letf ((end-of-actions-form (list 'throw ''wsi-body-finished (list 'quote wsi--canary-sym)))) (cl-letf ((keylist '((wsi-simulate-idle-time 1 t) "jo" (wsi-simulate-idle-time 1 t) "RET"))) (cl-letf ((keylist (if (listp keylist) keylist (list keylist)))) (cl-letf ((action-list (nconc (list ... body-form) (cl-loop for action in keylist if ... collect action) (list end-of-actions-form)))) (cl-letf ((action-closures (cl-loop for action in action-list collect ...))) (cl-letf ((full-key-sequence ...)) (cl-letf (...) (cl-letf ... ... ... ... ...))))))))
  (let ((body-form '(throw 'wsi-body-finished (progn (car (email-helm-example)))))) (cl-letf ((end-of-actions-form (list 'throw ''wsi-body-finished (list 'quote wsi--canary-sym)))) (cl-letf ((keylist '((wsi-simulate-idle-time 1 t) "jo" (wsi-simulate-idle-time 1 t) "RET"))) (cl-letf ((keylist (if (listp keylist) keylist (list keylist)))) (cl-letf ((action-list (nconc ... ... ...))) (cl-letf ((action-closures ...)) (cl-letf (...) (cl-letf ... ...))))))))
  (cl-letf ((body-form '(throw 'wsi-body-finished (progn (car (email-helm-example)))))) (cl-letf ((end-of-actions-form (list 'throw ''wsi-body-finished (list 'quote wsi--canary-sym)))) (cl-letf ((keylist '((wsi-simulate-idle-time 1 t) "jo" (wsi-simulate-idle-time 1 t) "RET"))) (cl-letf ((keylist (if (listp keylist) keylist (list keylist)))) (cl-letf ((action-list (nconc ... ... ...))) (cl-letf ((action-closures ...)) (cl-letf (...) (cl-letf ... ...))))))))
  (let ((thrown-error nil)) (cl-letf ((body-form '(throw 'wsi-body-finished (progn (car ...))))) (cl-letf ((end-of-actions-form (list 'throw ''wsi-body-finished (list 'quote wsi--canary-sym)))) (cl-letf ((keylist '(... "jo" ... "RET"))) (cl-letf ((keylist (if ... keylist ...))) (cl-letf ((action-list ...)) (cl-letf (...) (cl-letf ... ...))))))))
  (cl-letf ((thrown-error nil)) (cl-letf ((body-form '(throw 'wsi-body-finished (progn (car ...))))) (cl-letf ((end-of-actions-form (list 'throw ''wsi-body-finished (list 'quote wsi--canary-sym)))) (cl-letf ((keylist '(... "jo" ... "RET"))) (cl-letf ((keylist (if ... keylist ...))) (cl-letf ((action-list ...)) (cl-letf (...) (cl-letf ... ...))))))))
  (let ((result wsi--canary-sym)) (cl-letf ((thrown-error nil)) (cl-letf ((body-form '(throw 'wsi-body-finished (progn ...)))) (cl-letf ((end-of-actions-form (list 'throw '... (list ... wsi--canary-sym)))) (cl-letf ((keylist '...)) (cl-letf ((keylist ...)) (cl-letf (...) (cl-letf ... ...))))))))
  (cl-letf ((result wsi--canary-sym)) (cl-letf ((thrown-error nil)) (cl-letf ((body-form '(throw 'wsi-body-finished (progn ...)))) (cl-letf ((end-of-actions-form (list 'throw '... (list ... wsi--canary-sym)))) (cl-letf ((keylist '...)) (cl-letf ((keylist ...)) (cl-letf (...) (cl-letf ... ...))))))))
  (let ((next-action-key (wsi-get-unbound-key))) (cl-letf ((result wsi--canary-sym)) (cl-letf ((thrown-error nil)) (cl-letf ((body-form '(throw ... ...))) (cl-letf ((end-of-actions-form (list ... ... ...))) (cl-letf ((keylist ...)) (cl-letf (...) (cl-letf ... ...))))))))
  (cl-letf ((next-action-key (wsi-get-unbound-key))) (cl-letf ((result wsi--canary-sym)) (cl-letf ((thrown-error nil)) (cl-letf ((body-form '(throw ... ...))) (cl-letf ((end-of-actions-form (list ... ... ...))) (cl-letf ((keylist ...)) (cl-letf (...) (cl-letf ... ...))))))))
  (let ((correct-current-buffer (current-buffer))) (cl-letf ((next-action-key (wsi-get-unbound-key))) (cl-letf ((result wsi--canary-sym)) (cl-letf ((thrown-error nil)) (cl-letf ((body-form '...)) (cl-letf ((end-of-actions-form ...)) (cl-letf (...) (cl-letf ... ...))))))))
  (cl-letf ((correct-current-buffer (current-buffer))) (cl-letf ((next-action-key (wsi-get-unbound-key))) (cl-letf ((result wsi--canary-sym)) (cl-letf ((thrown-error nil)) (cl-letf ((body-form '...)) (cl-letf ((end-of-actions-form ...)) (cl-letf (...) (cl-letf ... ...))))))))
  (let ((lexenv (wsi-current-lexical-environment))) (cl-letf ((correct-current-buffer (current-buffer))) (cl-letf ((next-action-key (wsi-get-unbound-key))) (cl-letf ((result wsi--canary-sym)) (cl-letf ((thrown-error nil)) (cl-letf ((body-form ...)) (cl-letf (...) (cl-letf ... ...))))))))
  (cl-letf ((lexenv (wsi-current-lexical-environment))) (cl-letf ((correct-current-buffer (current-buffer))) (cl-letf ((next-action-key (wsi-get-unbound-key))) (cl-letf ((result wsi--canary-sym)) (cl-letf ((thrown-error nil)) (cl-letf ((body-form ...)) (cl-letf (...) (cl-letf ... ...))))))))
  (cl-letf* ((lexenv (wsi-current-lexical-environment)) (correct-current-buffer (current-buffer)) (next-action-key (wsi-get-unbound-key)) (result wsi--canary-sym) (thrown-error nil) (body-form '(throw 'wsi-body-finished (progn (car (email-helm-example))))) (end-of-actions-form (list 'throw ''wsi-body-finished (list 'quote wsi--canary-sym))) (keylist '((wsi-simulate-idle-time 1 t) "jo" (wsi-simulate-idle-time 1 t) "RET")) (keylist (if (listp keylist) keylist (list keylist))) (action-list (nconc (list (list 'switch-to-buffer correct-current-buffer) body-form) (cl-loop for action in keylist if (not (stringp action)) collect action) (list end-of-actions-form))) (action-closures (cl-loop for action in action-list collect (wsi-make-closure action lexenv))) (full-key-sequence (cl-loop for action in keylist if (stringp action) collect action into key-sequence-list else collect next-action-key into key-sequence-list finally return (concat next-action-key " " next-action-key " " (mapconcat #'identity key-sequence-list " ") " " next-action-key))) ((symbol-function 'wsi-run-next-action) (lambda nil (interactive) (condition-case err (if action-closures (let (...) (funcall next-action)) (error "`with-simulated-input' reached end of action list ...")) (error (throw 'wsi-threw-error err))))) (action-map (make-sparse-keymap))) (define-key action-map (kbd next-action-key) 'wsi-run-next-action) (setq thrown-error (catch 'wsi-threw-error (setq result (catch 'wsi-body-finished (let ((overriding-terminal-local-map action-map)) (execute-kbd-macro (kbd full-key-sequence))))) (throw 'wsi-threw-error nil))) (when thrown-error (signal (car thrown-error) (cdr thrown-error))) (if (eq result wsi--canary-sym) (error "Reached end of simulated input while evaluating bo...") result))
  (with-simulated-input '((wsi-simulate-idle-time 1 t) "jo" (wsi-simulate-idle-time 1 t) "RET") (car (email-helm-example)))
  (string-equal "john" (with-simulated-input '((wsi-simulate-idle-time 1 t) "jo" (wsi-simulate-idle-time 1 t) "RET") (car (email-helm-example))))
  (progn (defun email-helm-example nil (helm :sources `((name . "Simple helm names example") (candidates \, (list "jane" "john")) (action lambda (candidate) (helm-marked-candidates))))) (string-equal "john" (with-simulated-input '((wsi-simulate-idle-time 1 t) "jo" (wsi-simulate-idle-time 1 t) "RET") (car (email-helm-example)))))
  eval((progn (defun email-helm-example nil (helm :sources `((name . "Simple helm names example") (candidates \, (list "jane" "john")) (action lambda (candidate) (helm-marked-candidates))))) (string-equal "john" (with-simulated-input '((wsi-simulate-idle-time 1 t) "jo" (wsi-simulate-idle-time 1 t) "RET") (car (email-helm-example))))) nil)
  org-babel-execute:emacs-lisp("(defun email-helm-example ()\n  (helm :sources `((n..." ((:colname-names) (:rowname-names) (:result-params "replace") (:result-type . value) (:results . "replace") (:exports . "both") (:session . "none") (:cache . "no") (:noweb . "no") (:hlines . "no") (:tangle . "no") (:lexical . "no")))
  #f(compiled-function (&optional arg info params) "Execute the current source code block.\nInsert the results of execution into the buffer.  Source code\nexecution and the collection and formatting of results can be\ncontrolled through a variety of header arguments.\n\nWith prefix argument ARG, force re-execution even if an existing\nresult cached in the buffer would otherwise have been returned.\n\nOptionally supply a value for INFO in the form returned by\n`org-babel-get-src-block-info'.\n\nOptionally supply a value for PARAMS which will be merged with\nthe header arguments specified at the front of the source code\nblock." (interactive nil) #<bytecode 0x93bab5>)(nil ("emacs-lisp" "(defun email-helm-example ()\n  (helm :sources `((n..." ((:colname-names) (:rowname-names) (:result-params "replace") (:result-type . value) (:results . "replace") (:exports . "both") (:lexical . "no") (:tangle . "no") (:hlines . "no") (:noweb . "no") (:cache . "no") (:session . "none")) "" nil 30002 "(ref:%s)") nil)
  ob-async-org-babel-execute-src-block(#f(compiled-function (&optional arg info params) "Execute the current source code block.\nInsert the results of execution into the buffer.  Source code\nexecution and the collection and formatting of results can be\ncontrolled through a variety of header arguments.\n\nWith prefix argument ARG, force re-execution even if an existing\nresult cached in the buffer would otherwise have been returned.\n\nOptionally supply a value for INFO in the form returned by\n`org-babel-get-src-block-info'.\n\nOptionally supply a value for PARAMS which will be merged with\nthe header arguments specified at the front of the source code\nblock." (interactive nil) #<bytecode 0x93bab5>) nil ("emacs-lisp" "(defun email-helm-example ()\n  (helm :sources `((n..." ((:colname-names) (:rowname-names) (:result-params "replace") (:result-type . value) (:results . "replace") (:exports . "both") (:lexical . "no") (:tangle . "no") (:hlines . "no") (:noweb . "no") (:cache . "no") (:session . "none")) "" nil 30002 "(ref:%s)"))
  apply(ob-async-org-babel-execute-src-block #f(compiled-function (&optional arg info params) "Execute the current source code block.\nInsert the results of execution into the buffer.  Source code\nexecution and the collection and formatting of results can be\ncontrolled through a variety of header arguments.\n\nWith prefix argument ARG, force re-execution even if an existing\nresult cached in the buffer would otherwise have been returned.\n\nOptionally supply a value for INFO in the form returned by\n`org-babel-get-src-block-info'.\n\nOptionally supply a value for PARAMS which will be merged with\nthe header arguments specified at the front of the source code\nblock." (interactive nil) #<bytecode 0x93bab5>) (nil ("emacs-lisp" "(defun email-helm-example ()\n  (helm :sources `((n..." ((:colname-names) (:rowname-names) (:result-params "replace") (:result-type . value) (:results . "replace") (:exports . "both") (:lexical . "no") (:tangle . "no") (:hlines . "no") (:noweb . "no") (:cache . "no") (:session . "none")) "" nil 30002 "(ref:%s)")))
  org-babel-execute-src-block(nil ("emacs-lisp" "(defun email-helm-example ()\n  (helm :sources `((n..." ((:colname-names) (:rowname-names) (:result-params "replace") (:result-type . value) (:results . "replace") (:exports . "both") (:lexical . "no") (:tangle . "no") (:hlines . "no") (:noweb . "no") (:cache . "no") (:session . "none")) "" nil 30002 "(ref:%s)"))
  org-ctrl-c-ctrl-c(nil)
  funcall-interactively(org-ctrl-c-ctrl-c nil)
  call-interactively(org-ctrl-c-ctrl-c nil nil)
  command-execute(org-ctrl-c-ctrl-c)

Also, to be sure that with-simulated-input is working fine on my end I verified this works:

(string-equal "green"
          (with-simulated-input "g RET" (ido-completing-read "Prompt: " '("blue" "yellow" "green"))))
codygman commented 4 years ago

Going further, here's a minimal reproduction with use-package and emacs -Q that can be ran like so assuming directories/filenames are the same:

HOME=/tmp emacs -Q -batch --load /tmp/minimal-repro-helm-simulated-input-testing.el

/tmp/minimal-repro-helm-simulated-input-testing.el:

(require 'package)
(setq package-enable-at-startup nil)
(add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/"))
(package-initialize)

;; Bootstrap `use-package'
(unless (package-installed-p 'use-package)
  (package-refresh-contents)
  (package-install 'use-package))

(use-package with-simulated-input :ensure t)
(use-package helm :ensure t :config (helm-mode 1))
(require 'with-simulated-input)

(defun email-helm-example ()
  (helm :sources `((name . "Simple helm names example")
                   (candidates . ,(list "jane" "john"))
                   (action . (lambda (candidate) (helm-marked-candidates))))))

(string-equal "john" (with-simulated-input '((wsi-simulate-idle-time 1 t) "jo" (wsi-simulate-idle-time 1 t) "RET") (car (email-helm-example))))

This gives:

[cody@nixos:~/source/my-emacs-everywhere]$ HOME=/tmp emacs -Q -batch --load /tmp/minimal-repro-helm-simulated-input-testing.el
[Display not ready]

After 0 kbd macro iterations: Reached end of simulated input while evaluating body

So the display is not yet ready? I thought that passing wsi-simulate-idle-time a non-nil ACTUALLY-WAIT would fix that... but I guess I need to either wait longer or differently?

codygman commented 4 years ago

I tried looking to see how org-rifle is doing tests since that is #1 was for originally I think, but it looks like they aren't doing interactive tests like this anymore at least.

codygman commented 4 years ago

I did some searching around for helm display not ready and came across emacs-helm/helm#550 where a similar issue was solved with (setq helm-exit-idle-delay 0). So I tried:

(require 'package)
(setq package-enable-at-startup nil)
(add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/"))
(package-initialize)

;; Bootstrap `use-package'
(unless (package-installed-p 'use-package)
  (package-refresh-contents)
  (package-install 'use-package))

(use-package with-simulated-input :ensure t)
(use-package helm :ensure t :config (helm-mode 1))
(require 'with-simulated-input)

(defun email-helm-example ()
  (helm :sources `((name . "Simple helm names example")
                   (candidates . ,(list "jane" "john"))
                   (action . (lambda (candidate) (helm-marked-candidates))))))

(setq helm-exit-idle-delay 0) ;; new change
(string-equal "john" (with-simulated-input '((wsi-simulate-idle-time 2 t) "jo" (wsi-simulate-idle-time 2 t) "RET") (car (email-helm-example))))

Same error:

[cody@nixos:~/source/my-emacs-everywhere]$ HOME=/tmp emacs -Q -batch --load /tmp/minimal-repro-helm-simulated-input-testing.el
[Display not ready]

After 0 kbd macro iterations: Reached end of simulated input while evaluating body
codygman commented 4 years ago

After reading emacs-helm/helm#2074, I believe the sit-for or wait-for might not allow helm to actually update candidates in the display... maybe?

Specifically after reading:

There is nothing to debug, if you read the previous posts I explain why we have such message "Display not ready". To resume, each time you type something in minibuffer helm update its buffer, if you press RET before update finish helm display a warning and decreasing the value of helm-input-delay to zero is not speeding the helm-update function. Imagine with regular emacs completion you type TAB to have completion and immediately after type RET without looking at the completion results, this is the same with helm, you have to wait completion finish before typing RET to execute default action. Also the speed of completion depends of the actual resources of your computer at the time you are using helm. Users not used to this kind of completion tend to type the exact string in minibuffer and expect (because they typed the exact string) they can type RET immediately after, no you have to wait completion finish. HTH. - https://github.com/emacs-helm/helm/issues/2074#issuecomment-491332913

DarwinAwardWinner commented 4 years ago

Indeed, sit-for doesn't actually make Emacs idle. That's why the function says it simulates idle time. Idle time is simulated by manually accessing the list of idle timers and running the appropriate function. I'm not sure why this isn't good enough for Helm.

DarwinAwardWinner commented 4 years ago

I took a wild guess and found the solution: you need to simulate multiple idle times, presumably because one idle timer from Helm is adding another idle timer. The following should work:

(string-equal
 "john"
 (with-simulated-input
     '("jo"
       (wsi-simulate-idle-time 500)
       (wsi-simulate-idle-time 500)
       "RET")
   (car (helm :sources
          `((name . "Simple helm names example")
        (candidates . ,(list "jane" "john"))
        (action . (lambda (candidate) (helm-marked-candidates))))))))
codygman commented 4 years ago

Thank you for your help, you'll see I've also created an upstream issue in helm since it's not testable.

EDIT:

Whoa! trying that now.

DarwinAwardWinner commented 4 years ago

The question remains whether wsi-simulate-idle-time can learn to simulate idle time better in order to emulate this. I'll have to take some time to look at that and figure out exactly what helm is doing.

DarwinAwardWinner commented 4 years ago

Ok, so helm-read-pattern-maybe sets up an idle timer to run after each input, and that timer's callback calls helm-check-minibuffer-input, which eventually ends up calling helm--reset-update-flag, which adds another idle timer. Because the newly-added timer is set to run at shorter than the current idle time (since helm-exit-idle-delay defaults to 0), the idle simulation logic assumes that it has already been run and skips it. This skipping is required, or else repeating timers could cause an infinite loop. However, when you simulate idle time again, it starts from the beginning of the list of idle timers and picks up the new timer.

I'm not sure there's an easy way to fix this in this package. I think the best solution is just to document that if idle timers are adding idle timers, you need to simulate multiple idle times to make sure they all run.

DarwinAwardWinner commented 4 years ago

Hmm, actually, the idle time simulated logic is supposed to run newly-added idle timers in the past, so theoretically this should already work. There's even a test for it in the test suite. I need to investigate more.

DarwinAwardWinner commented 4 years ago

Wait, no, something more strange is happening here. I think my guess was wrong. If you go back to your original example and delete the first idle time, the code runs without any errors. In other words, the following throws an error:

(string-equal
 "john"
 (with-simulated-input
     '((wsi-simulate-idle-time 100)
       "jo"
       (wsi-simulate-idle-time 100)
       "RET")
   (car (helm :sources `((name . "Simple helm names example")
                   (candidates . ,(list "jane" "john"))
                   (action . (lambda (candidate) (helm-marked-candidates))))))))

And it doesn't matter how many idle times you add before RET, it still throws the error. Meanwhile, this doesn't throw an error:

(string-equal
 "john"
 (with-simulated-input
     '("jo"
       (wsi-simulate-idle-time 100)
       "RET")
   (car (helm :sources `((name . "Simple helm names example")
                   (candidates . ,(list "jane" "john"))
                   (action . (lambda (candidate) (helm-marked-candidates))))))))

I have no idea why an initial simulated idle time would cause helm to throw an error.

codygman commented 4 years ago

I have a working solution, so I guess this could be closed? It depends on whether or not you wish to look further into the initial simulated time causing helm to throw an error.

DarwinAwardWinner commented 4 years ago

I have no idea where to start looking for a solution, and since initial idleness is not a common requirement, I'm going to close it be unless it turns out someone really needs it fixed.

codygman commented 4 years ago

The solution for my initial problem was as follows!

(defun clone-projects-projectile-test ()
  (shell-command-to-string "cd /tmp && git clone --depth 1 https://github.com/jgm/pandoc.git")
  (shell-command-to-string "cd /tmp && git clone --depth 1 git://git-annex.branchable.com/ git-annex")
  (shell-command-to-string "cd /tmp && git clone --depth 1 https://github.com/haskell/haskell-ide-engine.git")
  (should (file-directory-p "/tmp/pandoc"))
  (should (file-directory-p "/tmp/git-annex"))
  (should (file-directory-p "/tmp/haskell-ide-engine")))

(ert-deftest projectile-switch-projects-to-magit-works ()
  ;; find git-annex,haskell-ide-engine, and pandoc projects cloned to /tmp
  (projectile-discover-projects-in-directory "/tmp")
  ;; ensure that we can successfully switch to magit for a given project
  (should (string-equal
   "magit: pandoc"
   (save-excursion
     (with-simulated-input
     '("pan"
       (wsi-simulate-idle-time 0.5)
       "M-g")
       (helm-projectile-switch-project))
     (buffer-name)))))

Thanks for enabling testing like this with your great library! It's difficult for me to ensure my emacs doesn't break between work (osx) and home (linux) and this has already helped me catch quite a few common (mostly loading/bytecode related) mistakes.