[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/elpa 49fb02f 135/139: Use RLS in Travis CI and add actu
From: |
João Távora |
Subject: |
[elpa] externals/elpa 49fb02f 135/139: Use RLS in Travis CI and add actual tests |
Date: |
Mon, 14 May 2018 09:53:50 -0400 (EDT) |
branch: externals/elpa
commit 49fb02fc1c838da6c4764d498540115c85acbdff
Author: João Távora <address@hidden>
Commit: João Távora <address@hidden>
Use RLS in Travis CI and add actual tests
Also run a hook when connected
* eglot-tests.el (eglot--with-dirs-and-files)
(eglot--make-file-or-dirs, eglot--call-with-dirs-and-files)
(eglot--find-file-noselect): New helpers.
(auto-detect-running-server, auto-reconnect): New actual tests.
* eglot.el (eglot-connect): Run hook when connected
(eglot-connect-hook): New variable
* .travis.yml: Use rust stable and install rls
* README.md: Update mention of automated tests
---
.travis.yml | 9 +++-
README.md | 3 +-
eglot-tests.el | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
eglot.el | 3 ++
4 files changed, 140 insertions(+), 3 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 7a89327..2f0db4c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,5 +1,7 @@
-language: generic
+language: rust
sudo: false
+rust:
+ - stable
env:
global:
@@ -13,7 +15,10 @@ install:
# Configure $PATH: Emacs installed to /tmp/emacs
- export PATH=/tmp/emacs/bin:${PATH}
- emacs --version
-
+ # Install RLS
+ - rustup update
+ - rustup component add rls-preview rust-analysis rust-src
+
script:
- make check
diff --git a/README.md b/README.md
index 4683951..e5a2394 100644
--- a/README.md
+++ b/README.md
@@ -162,7 +162,8 @@ Under the hood:
- Project support doesn't need `projectile.el`, uses Emacs's `project.el`
- Requires the upcoming Emacs 26
- Contained in one file
-- Its missing tests! This is *not good*
+- Has automated tests that check against actual LSP servers
+
[lsp]: https://microsoft.github.io/language-server-protocol/
[rls]: https://github.com/rust-lang-nursery/rls
diff --git a/eglot-tests.el b/eglot-tests.el
index 0f29519..119d873 100644
--- a/eglot-tests.el
+++ b/eglot-tests.el
@@ -24,9 +24,137 @@
;;; Code:
(require 'eglot)
+(require 'cl-lib)
(require 'ert)
+;; Helpers
+
+(defmacro eglot--with-dirs-and-files (dirs &rest body)
+ (declare (indent defun) (debug t))
+ `(eglot--call-with-dirs-and-files
+ ,dirs #'(lambda () ,@body)))
+
+(defun eglot--make-file-or-dirs (ass)
+ (let ((file-or-dir-name (car ass))
+ (content (cdr ass)))
+ (cond ((listp content)
+ (make-directory file-or-dir-name 'parents)
+ (let ((default-directory (concat default-directory "/"
file-or-dir-name)))
+ (mapc #'eglot--make-file-or-dirs content)))
+ ((stringp content)
+ (with-temp-buffer
+ (insert content)
+ (write-region nil nil file-or-dir-name nil 'nomessage)))
+ (t
+ (message "[yas] oops don't know this content")))))
+
+(defun eglot--call-with-dirs-and-files (dirs fn)
+ (let* ((default-directory (make-temp-file "eglot--fixture" t))
+ new-buffers new-processes)
+ (with-temp-message ""
+ (unwind-protect
+ (let ((find-file-hook
+ (cons (lambda () (push (current-buffer) new-buffers))
+ find-file-hook))
+ (eglot-connect-hook
+ (lambda (proc) (push proc new-processes))))
+ (mapc #'eglot--make-file-or-dirs dirs)
+ (funcall fn))
+ (eglot--message "Killing buffers %s, deleting %s, killing %s"
+ (mapconcat #'buffer-name new-buffers ", ")
+ default-directory
+ new-processes)
+ (delete-directory default-directory 'recursive)
+ (let ((eglot-autoreconnect nil))
+ (mapc #'eglot-shutdown
+ (cl-remove-if-not #'process-live-p new-processes)))
+ (mapc #'kill-buffer new-buffers)))))
+
+(cl-defmacro eglot--with-test-timeout (timeout &body body)
+ (declare (indent 1) (debug t))
+ `(eglot--call-with-test-timeout ,timeout (lambda () ,@body)))
+
+(defun eglot--call-with-test-timeout (timeout fn)
+ (let* ((tag (make-symbol "tag"))
+ (timed-out (make-symbol "timeout"))
+ (timer )
+ (eglot-request-timeout 1)
+ (retval))
+ (unwind-protect
+ (setq retval
+ (catch tag
+ (setq timer
+ (run-with-timer timeout nil
+ (lambda () (throw tag timed-out))))
+ (funcall fn)))
+ (cancel-timer timer)
+ (when (eq retval timed-out)
+ (error "Test timeout!")))))
+
+(defun eglot--find-file-noselect (file &optional noerror)
+ (unless (or noerror
+ (file-readable-p file)) (error "%s does not exist" file))
+ (find-file-noselect file))
+
+
+;; `rust-mode' is not a part of emacs. So define these two shims which
+;; should be more than enough for testing
+(unless (functionp 'rust-mode)
+ (define-derived-mode rust-mode prog-mode "Rust"))
+(add-to-list 'auto-mode-alist '("\\.rs\\'" . rust-mode))
+
+
(ert-deftest dummy () "A dummy test" (should t))
+(ert-deftest auto-detect-running-server ()
+ "Visit a file and M-x eglot, then visit a neighbour. "
+ (let (proc)
+ (eglot--with-test-timeout 2
+ (eglot--with-dirs-and-files
+ '(("project" . (("coiso.rs" . "bla")
+ ("merdix.rs" . "bla")))
+ ("anotherproject" . (("cena.rs" . "bla"))))
+ (with-current-buffer
+ (eglot--find-file-noselect "project/coiso.rs")
+ (setq proc
+ (eglot 'rust-mode `(transient . ,default-directory)
+ '("rls")))
+ (should (eglot--current-process)))
+ (with-current-buffer
+ (eglot--find-file-noselect "project/merdix.rs")
+ (should (eglot--current-process))
+ (should (eq (eglot--current-process) proc)))
+ (with-current-buffer
+ (eglot--find-file-noselect "anotherproject/cena.rs")
+ (should-error (eglot--current-process-or-lose)))))))
+
+(ert-deftest auto-reconnect ()
+ "Start a server. Kill it. Watch it reconnect."
+ (let (proc
+ (eglot-autoreconnect 1))
+ (eglot--with-test-timeout 3
+ (eglot--with-dirs-and-files
+ '(("project" . (("coiso.rs" . "bla")
+ ("merdix.rs" . "bla"))))
+ (with-current-buffer
+ (eglot--find-file-noselect "project/coiso.rs")
+ (setq proc
+ (eglot 'rust-mode `(transient . ,default-directory)
+ '("rls")))
+ ;; In 1.2 seconds > `eglot-autoreconnect' kill servers. We
+ ;; should have a automatic reconnection.
+ (run-with-timer 1.2 nil (lambda () (delete-process proc)))
+ (while (process-live-p proc) (accept-process-output nil 0.5))
+ (should (eglot--current-process))
+ ;; Now try again too quickly
+ (setq proc (eglot--current-process))
+ (run-with-timer 0.5 nil (lambda () (delete-process proc)))
+ (while (process-live-p proc) (accept-process-output nil 0.5))
+ (should (not (eglot--current-process))))))))
+
(provide 'eglot-tests)
;;; eglot-tests.el ends here
+
+;; Local Variables:
+;; checkdoc-force-docstrings-flag: nil
+;; End:
diff --git a/eglot.el b/eglot.el
index 3d5d492..4477242 100644
--- a/eglot.el
+++ b/eglot.el
@@ -217,6 +217,8 @@ CONTACT is as `eglot--contact'. Returns a process object."
:publishDiagnostics `(:relatedInformation :json-false))
:experimental (eglot--obj)))
+(defvar eglot-connect-hook nil "Hook run after connecting in
`eglot--connect'.")
+
(defun eglot--connect (project managed-major-mode short-name contact
interactive)
"Connect for PROJECT, MANAGED-MAJOR-MODE, SHORT-NAME and CONTACT.
INTERACTIVE is t if inside interactive call."
@@ -238,6 +240,7 @@ INTERACTIVE is t if inside interactive call."
(null eglot-autoreconnect)))))))
(setf (eglot--short-name proc) short-name)
(push proc (gethash project eglot--processes-by-project))
+ (run-hook-with-args 'eglot-connect-hook proc)
(erase-buffer)
(read-only-mode t)
(cl-destructuring-bind (&key capabilities)
- [elpa] externals/elpa 24466a9 096/139: When killing server, always wait 3 seconds, (continued)
- [elpa] externals/elpa 24466a9 096/139: When killing server, always wait 3 seconds, João Távora, 2018/05/14
- [elpa] externals/elpa 3a6c637 099/139: Support textDocument/rename, João Távora, 2018/05/14
- [elpa] externals/elpa 458bc69 110/139: More correctly setup rust-mode-related autoloads, João Távora, 2018/05/14
- [elpa] externals/elpa 3dcbc30 109/139: Add minimal headers, commentary and autoloads, João Távora, 2018/05/14
- [elpa] externals/elpa 581608f 115/139: Resist server failure during synchronous requests, João Távora, 2018/05/14
- [elpa] externals/elpa 41f5922 137/139: Now send willSaveWaitUntil, João Távora, 2018/05/14
- [elpa] externals/elpa 05c67ee 112/139: Adjust flymake integration, João Távora, 2018/05/14
- [elpa] externals/elpa f89f859 114/139: Simplify mode-line updating logic, João Távora, 2018/05/14
- [elpa] externals/elpa 0625b6c 123/139: (eglot--xref-make): Fix Use of cl-destructuring-bind., João Távora, 2018/05/14
- [elpa] externals/elpa 56cf02d 126/139: Rework autoreconnection logic, João Távora, 2018/05/14
- [elpa] externals/elpa 49fb02f 135/139: Use RLS in Travis CI and add actual tests,
João Távora <=
- [elpa] externals/elpa 29f58a6 127/139: Get rid of catch/loop/throw idiom (suggested by Thien-Thi Nguyen), João Távora, 2018/05/14
- [elpa] externals/elpa 418412b 131/139: Fix copyright header. Obviously not since 2003, João Távora, 2018/05/14
- [elpa] externals/elpa 54fc885 113/139: More RLS-specifics: update Flymake diags when indexing done, João Távora, 2018/05/14
- [elpa] externals/elpa 8a80fb7 105/139: Simplify `eglot-shutdown`, João Távora, 2018/05/14
- [elpa] externals/elpa d40f9ac 094/139: Half-decent imenu support via textDocument/documentSymbol, João Távora, 2018/05/14
- [elpa] externals/elpa 42177d0 107/139: New "deferred requests" that wait until server is ready, João Távora, 2018/05/14
- [elpa] externals/elpa ef80455 121/139: Support :completionItem/resolve, João Távora, 2018/05/14
- [elpa] externals/elpa 77856c2 130/139: Reinstate the catch/loop/throw idiom in eglot-request, João Távora, 2018/05/14
- [elpa] externals/elpa d1cdcf1 119/139: Friendlier M-x eglot, João Távora, 2018/05/14
- [elpa] externals/elpa 4c0bfc3 139/139: Support didChangeWatchedFiles with dynamic registration, João Távora, 2018/05/14