emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/eglot 49fb02f 135/139: Use RLS in Travis CI and add act


From: João Távora
Subject: [elpa] externals/eglot 49fb02f 135/139: Use RLS in Travis CI and add actual tests
Date: Mon, 14 May 2018 09:55:11 -0400 (EDT)

branch: externals/eglot
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)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]