emacs-ipython-notebook/test/test-func.el
dickmao 0490031ec8 Sane File Navigation
As emacs users we prefer and have the luxury of fuzzy file navigation
via ido and projectile.  From a notebook or notebooklist buffer, the commands

`C-c C-f` ein:file-open
`C-c C-o` ein:notebook-open

offer an ido alternative to point and click navigation.

To populate the ido lists, retrieving the content hierarchy is on by
default.  Two custom variables determine how wide and deep the content query
probes (currently at 2 levels deep and 6 directories wide).  Set both
to zero to turn off.

tkf half finished code to quickly go from local file buffers to notebook
mode via `C-c C-z` or `C-c C-o`.  This is now possible.  EIN will
start the server from a suitable parent directory of the visited file.

Enable ido completion for `notebooklist-login`.

Remove the albatross `ein-loaddefs.el` in favor of more standard
`ein-autoloads.el` that is not git tracked.

Convenience `make install` from git source (local alternative to
melpa).
2018-10-26 18:40:19 -04:00

229 lines
11 KiB
EmacsLisp

(eval-when-compile (require 'cl))
(require 'ert)
(require 'ein-notebooklist)
(require 'ein-jupyter)
(require 'wid-edit)
(require 'ein-testing)
(require 'ein-testing-cell)
(let ((backend (getenv "EL_REQUEST_BACKEND")))
(when (and backend (not (equal backend "")))
(setq request-backend (intern backend))
(message "Using request-backend = %S" request-backend)))
(defvar *ein:testing-notebook-name* nil
"This is the name of the notebook the server creates for this test. It could be Untitled.ipynb or if that was already there, Untitled1.ipynb, etc.")
(setq message-log-max t)
(defun ein:testing-get-notebook (url-or-port &rest paths)
(ein:log 'debug "TESTING-GET-NOTEBOOK start")
(ein:notebooklist-open* url-or-port)
(ein:testing-wait-until (lambda () (and (bufferp (get-buffer (format ein:notebooklist-buffer-name-template url-or-port)))
(ein:notebooklist-get-buffer url-or-port))))
(with-current-buffer (ein:notebooklist-get-buffer url-or-port)
(prog1 (ein:notebook-get-opened-notebook url-or-port (apply #'ein:glom-paths paths))
(ein:log 'debug "TESTING-GET-NOTEBOOK end"))))
(defun ein:testing-get-untitled0-or-create (url-or-port &optional path)
(ein:log 'debug "TESTING-GET-UNTITLED0-OR-CREATE start")
(let ((notebook (ein:testing-get-notebook url-or-port path *ein:testing-notebook-name*)))
(if notebook
(progn (ein:log 'debug
"TESTING-GET-UNTITLED0-OR-CREATE notebook already exists")
notebook)
(ein:log 'debug
"TESTING-GET-UNTITLED0-OR-CREATE creating notebook")
(lexical-let (done-p
(kernelspec (ein:get-kernelspec url-or-port "default")))
(ein:notebooklist-new-notebook url-or-port kernelspec path
(lambda (notebook created)
(setq *ein:testing-notebook-name*
(ein:$notebook-notebook-name notebook))
(setq done-p t)))
(ein:testing-wait-until (lambda () done-p))
(prog1
(ein:testing-get-notebook url-or-port path *ein:testing-notebook-name*)
(with-current-buffer (ein:notebooklist-get-buffer url-or-port)
(deferred:sync! (ein:notebooklist-reload nil t)))
(ein:log 'debug "TESTING-GET-UNTITLED0-OR-CREATE end"))))))
(defvar ein:notebooklist-after-open-hook nil)
(defadvice ein:notebooklist-open--finish
(after ein:testing-notebooklist-open--finish activate)
"Advice to add `ein:notebooklist-after-open-hook'."
(run-hooks 'ein:notebooklist-after-open-hook))
;; (ert-deftest 00-jupyter-start-server ()
;; (ein:log 'verbose "ERT TESTING-JUPYTER-START-SERVER start")
;; (condition-case err
;; (ein:testing-start-server)
;; (error (ein:log 'verbose "ERT TESTING-JUPYTER-START-SERVER error when launching: %s" err)
;; (sit-for 10)
;; (ein:jupyter-server-login-and-open)))
;; (should (processp %ein:jupyter-server-session%))
;; (ein:log 'verbose "ERT TESTING-JUPYTER-START-SERVER end"))
(ert-deftest 01-open-notebooklist ()
(ein:log 'verbose "ERT OPEN-NOTEBOOKLIST start")
(ein:notebooklist-open* *ein:testing-port*)
(ein:testing-wait-until
(lambda ()
(ein:notebooklist-get-buffer *ein:testing-port*)))
(with-current-buffer (ein:notebooklist-get-buffer *ein:testing-port*)
(should (eql major-mode 'ein:notebooklist-mode))))
(ert-deftest 00-query-kernelspecs ()
(ein:log 'info "ERT QUERY-KERNELSPECS")
(ein:log 'info (format "ERT QUERY-KERNELSPECS: Pre-query kernelspec count %s." (hash-table-count *ein:kernelspecs*)))
(should (>= (hash-table-count *ein:kernelspecs*) 1))
(ein:log 'info (format "ERT QUERY-KERNELSPECS: Post-query kernelspec %S." (ein:need-kernelspecs *ein:testing-port*))))
(ert-deftest 10-get-untitled0-or-create ()
(ein:log 'verbose "ERT TESTING-GET-UNTITLED0-OR-CREATE start")
(let ((notebook (ein:testing-get-untitled0-or-create *ein:testing-port*)))
(ein:testing-wait-until
(lambda () (ein:aand (ein:$notebook-kernel notebook)
(ein:kernel-live-p it))))
(with-current-buffer (ein:notebook-buffer notebook)
(should (equal (ein:$notebook-notebook-name ein:%notebook%)
*ein:testing-notebook-name*))))
(ein:log 'verbose "ERT TESTING-GET-UNTITLED0-OR-CREATE end"))
(ert-deftest 20-delete-untitled0 ()
(ein:log 'verbose "----------------------------------")
(ein:log 'verbose "ERT TESTING-DELETE-UNTITLED0 start")
(with-current-buffer (ein:notebooklist-get-buffer *ein:testing-port*)
(let ((notebook (ein:testing-get-untitled0-or-create *ein:testing-port*)))
(should (member (ein:url *ein:testing-port* (ein:$notebook-notebook-path notebook))
(ein:notebooklist-list-paths "notebook")))
(ein:log 'verbose "ERT TESTING-DELETE-UNTITLED0 deleting notebook")
(ein:notebooklist-delete-notebook (ein:$notebook-notebook-path notebook))
(deferred:sync! (ein:notebooklist-reload ein:%notebooklist% t))
(should-not (member (ein:url *ein:testing-port* (ein:$notebook-notebook-path notebook)) (ein:notebooklist-list-paths "notebook")))))
(ein:log 'verbose "ERT TESTING-DELETE-UNTITLED0 end"))
(ert-deftest 11-notebook-execute-current-cell-simple ()
(let ((notebook (ein:testing-get-untitled0-or-create *ein:testing-port*)))
(ein:testing-wait-until
(lambda () (ein:aand (ein:$notebook-kernel notebook)
(ein:kernel-live-p it))))
(with-current-buffer (ein:notebook-buffer notebook)
(call-interactively #'ein:worksheet-insert-cell-below)
(insert "a = 100\na")
(let ((cell (call-interactively #'ein:worksheet-execute-cell)))
(ein:testing-wait-until (lambda () (not (slot-value cell 'running)))))
;; (message "%s" (buffer-string))
(save-excursion
(should (search-forward-regexp "Out \\[[0-9]+\\]" nil t))
(should (search-forward "100" nil t))))))
(defun ein:testing-image-type (image)
"Return the type of IMAGE.
See the definition of `create-image' for how it works."
(assert (and (listp image) (eq (car image) 'image)) nil
"%S is not an image." image)
(plist-get (cdr image) :type))
(ert-deftest 12-notebook-execute-current-cell-pyout-image ()
(let ((notebook (ein:testing-get-untitled0-or-create *ein:testing-port*)))
(ein:testing-wait-until
(lambda () (ein:aand (ein:$notebook-kernel notebook)
(ein:kernel-live-p it))))
(with-current-buffer (ein:notebook-buffer notebook)
(call-interactively #'ein:worksheet-insert-cell-below)
;; Use IPython.core.display rather than IPython.display to
;; test it with older (< 0.13) IPython.
(insert (concat "from IPython.core.display import SVG\n"
(format "SVG(data=\"\"\"%s\"\"\")"
ein:testing-example-svg)))
(let ((cell (call-interactively #'ein:worksheet-execute-cell)))
;; It seems in this case, watching `:running' does not work
;; well sometimes. Probably "output reply" (iopub) comes
;; before "execute reply" in this case.
(ein:testing-wait-until (lambda () (slot-value cell 'outputs)))
;; This cell has only one input
(should (= (length (oref cell :outputs)) 1))
;; This output is a SVG image
(let ((out (nth 0 (oref cell :outputs))))
(should (equal (plist-get out :output_type) "execute_result"))
(should (plist-get out :svg))))
;; Check the actual output in the buffer:
(save-excursion
(should (search-forward-regexp "Out \\[[0-9]+\\]" nil t))
(should (= (forward-line) 0))
(if (image-type-available-p 'svg)
(let ((image (get-text-property (point) 'display)))
(should (eq (ein:testing-image-type image) 'svg)))
(ein:log 'info
"Skipping image check as SVG image type is not available."))))))
(ert-deftest 13-notebook-execute-current-cell-stream ()
(let ((notebook (ein:testing-get-untitled0-or-create *ein:testing-port*)))
(ein:testing-wait-until
(lambda () (ein:aand (ein:$notebook-kernel notebook)
(ein:kernel-live-p it))))
(with-current-buffer (ein:notebook-buffer notebook)
(call-interactively #'ein:worksheet-insert-cell-below)
(insert "print('Hello')")
(let ((cell (call-interactively #'ein:worksheet-execute-cell)))
(ein:testing-wait-until (lambda () (not (oref cell :running)))
))
(save-excursion
(should-not (search-forward-regexp "Out \\[[0-9]+\\]" nil t))
(should (search-forward-regexp "^Hello$" nil t))))))
(ert-deftest 14-notebook-execute-current-cell-question ()
:expected-result (if (eq system-type 'darwin) t :passed)
(let ((notebook (ein:testing-get-untitled0-or-create *ein:testing-port*)))
(ein:testing-wait-until
(lambda () (ein:aand (ein:$notebook-kernel notebook)
(ein:kernel-live-p it))))
(with-current-buffer (ein:notebook-buffer notebook)
(call-interactively #'ein:worksheet-insert-cell-below)
(insert "range?")
(let ((cell (call-interactively #'ein:worksheet-execute-cell)))
(ein:testing-wait-until (lambda () (and (not (oref cell :running))
(ein:$notebook-pager notebook)
(get-buffer (ein:$notebook-pager notebook))))))
(with-current-buffer (get-buffer (ein:$notebook-pager notebook))
(should (search-forward "Docstring:"))))))
(ert-deftest 15-notebook-request-help ()
(let ((notebook (ein:testing-get-untitled0-or-create *ein:testing-port*)))
(ein:testing-wait-until
(lambda () (ein:aand (ein:$notebook-kernel notebook)
(ein:kernel-live-p it))))
(with-current-buffer (ein:notebook-buffer notebook)
(call-interactively #'ein:worksheet-insert-cell-below)
(let ((pager-name (ein:$notebook-pager ein:%notebook%)))
(ein:aif (get-buffer pager-name)
(kill-buffer it))
(insert "file")
(call-interactively #'ein:pytools-request-help)
;; Pager buffer will be created when got the response
(ein:testing-wait-until
(lambda () (get-buffer pager-name)))
(with-current-buffer (get-buffer pager-name)
(should (search-forward "Docstring:")))))))
(ert-deftest 30-testing-jupyter-stop-server ()
(ein:log 'verbose "ERT TESTING-JUPYTER-STOP-SERVER start")
(let ((notebook (ein:testing-get-untitled0-or-create *ein:testing-port*)))
(ein:testing-wait-until
(lambda () (ein:aand (ein:$notebook-kernel notebook)
(ein:kernel-live-p it))))
(ein:jupyter-server-stop t ein:testing-dump-file-server)
(cl-flet ((orphans-find (pid) (search (ein:$kernel-kernel-id (ein:$notebook-kernel notebook)) (alist-get 'args (process-attributes pid)))))
(should-not (loop repeat 10
with orphans = (seq-filter #'orphans-find
(list-system-processes))
until (and (null orphans) (ein:jupyter-server-process))
do (sleep-for 0 1000)
(setq orphans (seq-filter #'orphans-find (list-system-processes)))
finally return orphans))))
(ein:log 'verbose "ERT TESTING-JUPYTER-STOP-SERVER end"))