From fc8230f3362b12955152f48565a6c670b4c4cc88 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Fri, 7 Apr 2023 14:55:01 +0100 Subject: [PATCH] Eglot: no more tests based on Pylsp (bug#62694) The functionality under test in eglot.el is exactly the same, but use the clangd server only, as that is used in more tests, and it is much easier to check if it misbehaves or not. Tests pass with clangd version 15. * test/lisp/progmodes/eglot-tests.el (python): Don't require it. (eglot--call-with-fixture): Simplify. (eglot--wait-for-clangd): New helper. (eglot-test-basic-completions) (eglot-test-non-unique-completions, eglot-test-basic-xref) (eglot-test-snippet-completions) (eglot-test-snippet-completions-with-company) (eglot-test-eldoc-after-completions, eglot-test-multiline-eldoc): Use clangd, not pylsp. (eglot-test-formatting): Renamed from eglot-test-python-autopep-formatting. (eglot-test-python-yapf-formatting): Remove. --- test/lisp/progmodes/eglot-tests.el | 197 +++++++++++++---------------- 1 file changed, 85 insertions(+), 112 deletions(-) diff --git a/test/lisp/progmodes/eglot-tests.el b/test/lisp/progmodes/eglot-tests.el index b11ce942b7d..aa0b71a3ae7 100644 --- a/test/lisp/progmodes/eglot-tests.el +++ b/test/lisp/progmodes/eglot-tests.el @@ -47,7 +47,6 @@ (require 'tramp) (require 'ert-x) ; ert-simulate-command (require 'edebug) -(require 'python) ; some tests use pylsp (require 'cc-mode) ; c-mode-hook (require 'company nil t) (require 'yasnippet nil t) @@ -122,8 +121,6 @@ then restored." ,(format "HOME=%s" (expand-file-name (format "~%s" (user-login-name))))) process-environment)) - ;; Prevent "Can't guess python-indent-offset ..." messages. - (python-indent-guess-indent-offset-verbose . nil) (eglot-server-initialized-hook (lambda (server) (push server new-servers)))) (setq created-files (mapcan #'eglot--make-file-or-dir file-specs)) @@ -551,90 +548,101 @@ then restored." (should (equal (buffer-string) "int bar() {return 42;} int main() {return bar();}"))))) +(defun eglot--wait-for-clangd () + (eglot--sniffing (:server-notifications s-notifs) + (should (eglot--tests-connect)) + (eglot--wait-for (s-notifs 20) (&key method &allow-other-keys) + (string= method "textDocument/publishDiagnostics")))) + (ert-deftest eglot-test-basic-completions () - "Test basic autocompletion in a python LSP." - (skip-unless (executable-find "pylsp")) + "Test basic autocompletion in a clangd LSP." + (skip-unless (executable-find "clangd")) (eglot--with-fixture - `(("project" . (("something.py" . "import sys\nsys.exi")))) + `(("project" . (("coiso.c" . "#include \nint main () {fprin")))) (with-current-buffer - (eglot--find-file-noselect "project/something.py") - (should (eglot--tests-connect)) + (eglot--find-file-noselect "project/coiso.c") + (eglot--sniffing (:server-notifications s-notifs) + (eglot--wait-for-clangd) + (eglot--wait-for (s-notifs 20) (&key method &allow-other-keys) + (string= method "textDocument/publishDiagnostics"))) (goto-char (point-max)) (completion-at-point) - (should (looking-back "sys.exit"))))) + (message (buffer-string)) + (should (looking-back "fprintf.?"))))) (ert-deftest eglot-test-non-unique-completions () "Test completion resulting in 'Complete, but not unique'." - (skip-unless (executable-find "pylsp")) + (skip-unless (executable-find "clangd")) (eglot--with-fixture - '(("project" . (("something.py" . "foo=1\nfoobar=2\nfoo")))) + `(("project" . (("coiso.c" . + ,(concat "int foo; int fooey;" + "int main() {foo"))))) (with-current-buffer - (eglot--find-file-noselect "project/something.py") - (should (eglot--tests-connect)) + (eglot--find-file-noselect "project/coiso.c") + (eglot--wait-for-clangd) (goto-char (point-max)) - (completion-at-point)) - ;; FIXME: `current-message' doesn't work here :-( + (completion-at-point) + ;; FIXME: `current-message' doesn't work here :-( (with-current-buffer (messages-buffer) (save-excursion (goto-char (point-max)) (forward-line -1) - (should (looking-at "Complete, but not unique")))))) + (should (looking-at "Complete, but not unique"))))))) (ert-deftest eglot-test-basic-xref () - "Test basic xref functionality in a python LSP." - (skip-unless (executable-find "pylsp")) + "Test basic xref functionality in a clangd LSP." + (skip-unless (executable-find "clangd")) (eglot--with-fixture - `(("project" . (("something.py" . "def foo(): pass\ndef bar(): foo()")))) + `(("project" . (("coiso.c" . + ,(concat "int foo=42; int fooey;" + "int main() {foo=82;}"))))) (with-current-buffer - (eglot--find-file-noselect "project/something.py") + (eglot--find-file-noselect "project/coiso.c") (should (eglot--tests-connect)) - (search-forward "bar(): f") + (search-forward "{foo") (call-interactively 'xref-find-definitions) - (should (looking-at "foo(): pass"))))) + (should (looking-at "foo=42"))))) -(defvar eglot--test-python-buffer +(defvar eglot--test-c-buffer "\ -def foobarquux(a, b, c=True): pass -def foobazquuz(d, e, f): pass +void foobarquux(int a, int b, int c){}; +void foobazquuz(int a, int b, int f){}; +int main() { ") (declare-function yas-minor-mode nil) (ert-deftest eglot-test-snippet-completions () - "Test simple snippet completion in a python LSP." - (skip-unless (and (executable-find "pylsp") + "Test simple snippet completion in a clangd LSP." + (skip-unless (and (executable-find "clangd") (functionp 'yas-minor-mode))) (eglot--with-fixture - `(("project" . (("something.py" . ,eglot--test-python-buffer)))) + `(("project" . (("coiso.c" . ,eglot--test-c-buffer)))) (with-current-buffer - (eglot--find-file-noselect "project/something.py") + (eglot--find-file-noselect "project/coiso.c") (yas-minor-mode 1) - (let ((eglot-workspace-configuration - `((:pylsp . (:plugins (:jedi_completion (:include_params t))))))) - (should (eglot--tests-connect))) + (eglot--wait-for-clangd) (goto-char (point-max)) (insert "foobar") (completion-at-point) (should (looking-back "foobarquux(")) - (should (looking-at "a, b)"))))) + (should (looking-at "int a, int b, int c)"))))) (defvar company-candidates) (declare-function company-mode nil) (declare-function company-complete nil) (ert-deftest eglot-test-snippet-completions-with-company () - "Test simple snippet completion in a python LSP." - (skip-unless (and (executable-find "pylsp") + "Test simple snippet completion in a clangd LSP." + (skip-unless (and (executable-find "clangd") (functionp 'yas-minor-mode) (functionp 'company-complete))) (eglot--with-fixture - `(("project" . (("something.py" . ,eglot--test-python-buffer)))) + `(("project" . (("coiso.c" . ,eglot--test-c-buffer)))) (with-current-buffer - (eglot--find-file-noselect "project/something.py") + (eglot--find-file-noselect "project/coiso.c") (yas-minor-mode 1) - (let ((eglot-workspace-configuration - `((:pylsp . (:plugins (:jedi_completion (:include_params t))))))) - (should (eglot--tests-connect))) + (eglot--wait-for-clangd) (goto-char (point-max)) (insert "foo") (company-mode) @@ -642,98 +650,63 @@ def foobazquuz(d, e, f): pass (should (looking-back "fooba")) (should (= 2 (length company-candidates))) ;; this last one is brittle, since there it is possible that - ;; pylsp will change the representation of this candidate - (should (member "foobazquuz(d, e, f)" company-candidates))))) + ;; clangd will change the representation of this candidate + (should (member "foobazquuz(int a, int b, int f)" company-candidates))))) (ert-deftest eglot-test-eldoc-after-completions () - "Test documentation echo in a python LSP." - (skip-unless (executable-find "pylsp")) + "Test documentation echo in a clangd LSP." + (skip-unless (executable-find "clangd")) (eglot--with-fixture - `(("project" . (("something.py" . "import sys\nsys.exi")))) + `(("project" . (("coiso.c" . "#include \nint main () {fprin")))) (with-current-buffer - (eglot--find-file-noselect "project/something.py") - (should (eglot--tests-connect)) + (eglot--find-file-noselect "project/coiso.c") + (eglot--wait-for-clangd) (goto-char (point-max)) (completion-at-point) - (should (looking-back "sys.exit")) - (should (string-match "^exit" (eglot--tests-force-full-eldoc)))))) + (message (buffer-string)) + (should (looking-back "fprintf(?")) + (unless (= (char-before) ?\()) (insert "()") (backward-char) + (eglot--signal-textDocument/didChange) + (should (string-match "^fprintf" (eglot--tests-force-full-eldoc)))))) (ert-deftest eglot-test-multiline-eldoc () - "Test if suitable amount of lines of hover info are shown." - (skip-unless (executable-find "pylsp")) + "Test Eldoc documentation from multiple osurces." + (skip-unless (executable-find "clangd")) (eglot--with-fixture - `(("project" . (("hover-first.py" . "from datetime import datetime")))) + `(("project" . (("coiso.c" . + "#include \nint main () {fprintf(blergh);}")))) (with-current-buffer - (eglot--find-file-noselect "project/hover-first.py") - (should (eglot--tests-connect)) - (goto-char (point-max)) - ;; one-line - (let* ((eldoc-echo-area-use-multiline-p t) - (captured-message (eglot--tests-force-full-eldoc))) - (should (string-match "datetim" captured-message)) + (eglot--find-file-noselect "project/coiso.c") + (search-forward "fprintf(ble") + (eglot--wait-for-clangd) + (flymake-start nil t) ;; thing brings in the "unknown identifier blergh" + (let* ((captured-message (eglot--tests-force-full-eldoc))) + ;; check for signature and error message in the result + (should (string-match "fprintf" captured-message)) + (should (string-match "blergh" captured-message)) (should (cl-find ?\n captured-message)))))) -(ert-deftest eglot-test-single-line-eldoc () - "Test if suitable amount of lines of hover info are shown." - (skip-unless (executable-find "pylsp")) - (eglot--with-fixture - `(("project" . (("hover-first.py" . "from datetime import datetime")))) - (with-current-buffer - (eglot--find-file-noselect "project/hover-first.py") - (should (eglot--tests-connect)) - (goto-char (point-max)) - ;; one-line - (let* ((eldoc-echo-area-use-multiline-p nil) - (captured-message (eglot--tests-force-full-eldoc))) - (should (string-match "datetim" captured-message)) - (should (not (cl-find ?\n eldoc-last-message))))))) - -(ert-deftest eglot-test-python-autopep-formatting () - "Test formatting in the pylsp python LSP. -pylsp prefers autopep over yafp, despite its README stating the contrary." +(ert-deftest eglot-test-formatting () + "Test formatting in the clangd server." ;; Beware, default autopep rules can change over time, which may ;; affect this test. - (skip-unless (and (executable-find "pylsp") - (executable-find "autopep8"))) - (eglot--with-fixture - `(("project" . (("something.py" . "def a():pass\n\ndef b():pass")))) - (with-current-buffer - (eglot--find-file-noselect "project/something.py") - (should (eglot--tests-connect)) - ;; Try to format just the second line - (search-forward "b():pa") - (eglot-format (line-beginning-position) (line-end-position)) - (should (looking-at "ss")) - (should - (or (string= (buffer-string) "def a():pass\n\n\ndef b(): pass\n") - ;; autopep8 2.0.0 (pycodestyle: 2.9.1) - (string= (buffer-string) "def a():pass\n\ndef b(): pass"))) - ;; now format the whole buffer - (eglot-format-buffer) - (should - (string= (buffer-string) "def a(): pass\n\n\ndef b(): pass\n"))))) - -(ert-deftest eglot-test-python-yapf-formatting () - "Test formatting in the pylsp python LSP." - (skip-unless (and (executable-find "pylsp") - (not (executable-find "autopep8")) - (or (executable-find "yapf") - (executable-find "yapf3")))) + (skip-unless (executable-find "clangd")) (eglot--with-fixture - `(("project" . (("something.py" . "def a():pass\ndef b():pass")))) + `(("project" . (("coiso.c" . ,(concat "#include \n" + "int main(){fprintf(blergh);}" + "int ble{\n\nreturn 0;}"))))) (with-current-buffer - (eglot--find-file-noselect "project/something.py") - (should (eglot--tests-connect)) + (eglot--find-file-noselect "project/coiso.c") + (eglot--wait-for-clangd) + (forward-line) ;; Try to format just the second line - (search-forward "b():pa") (eglot-format (line-beginning-position) (line-end-position)) - (should (looking-at "ss")) - (should - (string= (buffer-string) "def a():pass\n\n\ndef b():\n pass\n")) - ;; now format the whole buffer + (should (looking-at "int main() { fprintf(blergh); }")) + ;; ;; now format the whole buffer (eglot-format-buffer) (should - (string= (buffer-string) "def a():\n pass\n\n\ndef b():\n pass\n"))))) + (string= (buffer-string) + "#include \nint main() { fprintf(blergh); }\nint ble { return 0; }"))))) (ert-deftest eglot-test-rust-on-type-formatting () "Test textDocument/onTypeFormatting against rust-analyzer." -- 2.39.2