diff options
| -rw-r--r-- | test/lisp/progmodes/eglot-tests.el | 197 |
1 files 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 @@ | |||
| 47 | (require 'tramp) | 47 | (require 'tramp) |
| 48 | (require 'ert-x) ; ert-simulate-command | 48 | (require 'ert-x) ; ert-simulate-command |
| 49 | (require 'edebug) | 49 | (require 'edebug) |
| 50 | (require 'python) ; some tests use pylsp | ||
| 51 | (require 'cc-mode) ; c-mode-hook | 50 | (require 'cc-mode) ; c-mode-hook |
| 52 | (require 'company nil t) | 51 | (require 'company nil t) |
| 53 | (require 'yasnippet nil t) | 52 | (require 'yasnippet nil t) |
| @@ -122,8 +121,6 @@ then restored." | |||
| 122 | ,(format "HOME=%s" | 121 | ,(format "HOME=%s" |
| 123 | (expand-file-name (format "~%s" (user-login-name))))) | 122 | (expand-file-name (format "~%s" (user-login-name))))) |
| 124 | process-environment)) | 123 | process-environment)) |
| 125 | ;; Prevent "Can't guess python-indent-offset ..." messages. | ||
| 126 | (python-indent-guess-indent-offset-verbose . nil) | ||
| 127 | (eglot-server-initialized-hook | 124 | (eglot-server-initialized-hook |
| 128 | (lambda (server) (push server new-servers)))) | 125 | (lambda (server) (push server new-servers)))) |
| 129 | (setq created-files (mapcan #'eglot--make-file-or-dir file-specs)) | 126 | (setq created-files (mapcan #'eglot--make-file-or-dir file-specs)) |
| @@ -551,90 +548,101 @@ then restored." | |||
| 551 | (should (equal (buffer-string) | 548 | (should (equal (buffer-string) |
| 552 | "int bar() {return 42;} int main() {return bar();}"))))) | 549 | "int bar() {return 42;} int main() {return bar();}"))))) |
| 553 | 550 | ||
| 551 | (defun eglot--wait-for-clangd () | ||
| 552 | (eglot--sniffing (:server-notifications s-notifs) | ||
| 553 | (should (eglot--tests-connect)) | ||
| 554 | (eglot--wait-for (s-notifs 20) (&key method &allow-other-keys) | ||
| 555 | (string= method "textDocument/publishDiagnostics")))) | ||
| 556 | |||
| 554 | (ert-deftest eglot-test-basic-completions () | 557 | (ert-deftest eglot-test-basic-completions () |
| 555 | "Test basic autocompletion in a python LSP." | 558 | "Test basic autocompletion in a clangd LSP." |
| 556 | (skip-unless (executable-find "pylsp")) | 559 | (skip-unless (executable-find "clangd")) |
| 557 | (eglot--with-fixture | 560 | (eglot--with-fixture |
| 558 | `(("project" . (("something.py" . "import sys\nsys.exi")))) | 561 | `(("project" . (("coiso.c" . "#include <stdio.h>\nint main () {fprin")))) |
| 559 | (with-current-buffer | 562 | (with-current-buffer |
| 560 | (eglot--find-file-noselect "project/something.py") | 563 | (eglot--find-file-noselect "project/coiso.c") |
| 561 | (should (eglot--tests-connect)) | 564 | (eglot--sniffing (:server-notifications s-notifs) |
| 565 | (eglot--wait-for-clangd) | ||
| 566 | (eglot--wait-for (s-notifs 20) (&key method &allow-other-keys) | ||
| 567 | (string= method "textDocument/publishDiagnostics"))) | ||
| 562 | (goto-char (point-max)) | 568 | (goto-char (point-max)) |
| 563 | (completion-at-point) | 569 | (completion-at-point) |
| 564 | (should (looking-back "sys.exit"))))) | 570 | (message (buffer-string)) |
| 571 | (should (looking-back "fprintf.?"))))) | ||
| 565 | 572 | ||
| 566 | (ert-deftest eglot-test-non-unique-completions () | 573 | (ert-deftest eglot-test-non-unique-completions () |
| 567 | "Test completion resulting in 'Complete, but not unique'." | 574 | "Test completion resulting in 'Complete, but not unique'." |
| 568 | (skip-unless (executable-find "pylsp")) | 575 | (skip-unless (executable-find "clangd")) |
| 569 | (eglot--with-fixture | 576 | (eglot--with-fixture |
| 570 | '(("project" . (("something.py" . "foo=1\nfoobar=2\nfoo")))) | 577 | `(("project" . (("coiso.c" . |
| 578 | ,(concat "int foo; int fooey;" | ||
| 579 | "int main() {foo"))))) | ||
| 571 | (with-current-buffer | 580 | (with-current-buffer |
| 572 | (eglot--find-file-noselect "project/something.py") | 581 | (eglot--find-file-noselect "project/coiso.c") |
| 573 | (should (eglot--tests-connect)) | 582 | (eglot--wait-for-clangd) |
| 574 | (goto-char (point-max)) | 583 | (goto-char (point-max)) |
| 575 | (completion-at-point)) | 584 | (completion-at-point) |
| 576 | ;; FIXME: `current-message' doesn't work here :-( | 585 | ;; FIXME: `current-message' doesn't work here :-( |
| 577 | (with-current-buffer (messages-buffer) | 586 | (with-current-buffer (messages-buffer) |
| 578 | (save-excursion | 587 | (save-excursion |
| 579 | (goto-char (point-max)) | 588 | (goto-char (point-max)) |
| 580 | (forward-line -1) | 589 | (forward-line -1) |
| 581 | (should (looking-at "Complete, but not unique")))))) | 590 | (should (looking-at "Complete, but not unique"))))))) |
| 582 | 591 | ||
| 583 | (ert-deftest eglot-test-basic-xref () | 592 | (ert-deftest eglot-test-basic-xref () |
| 584 | "Test basic xref functionality in a python LSP." | 593 | "Test basic xref functionality in a clangd LSP." |
| 585 | (skip-unless (executable-find "pylsp")) | 594 | (skip-unless (executable-find "clangd")) |
| 586 | (eglot--with-fixture | 595 | (eglot--with-fixture |
| 587 | `(("project" . (("something.py" . "def foo(): pass\ndef bar(): foo()")))) | 596 | `(("project" . (("coiso.c" . |
| 597 | ,(concat "int foo=42; int fooey;" | ||
| 598 | "int main() {foo=82;}"))))) | ||
| 588 | (with-current-buffer | 599 | (with-current-buffer |
| 589 | (eglot--find-file-noselect "project/something.py") | 600 | (eglot--find-file-noselect "project/coiso.c") |
| 590 | (should (eglot--tests-connect)) | 601 | (should (eglot--tests-connect)) |
| 591 | (search-forward "bar(): f") | 602 | (search-forward "{foo") |
| 592 | (call-interactively 'xref-find-definitions) | 603 | (call-interactively 'xref-find-definitions) |
| 593 | (should (looking-at "foo(): pass"))))) | 604 | (should (looking-at "foo=42"))))) |
| 594 | 605 | ||
| 595 | (defvar eglot--test-python-buffer | 606 | (defvar eglot--test-c-buffer |
| 596 | "\ | 607 | "\ |
| 597 | def foobarquux(a, b, c=True): pass | 608 | void foobarquux(int a, int b, int c){}; |
| 598 | def foobazquuz(d, e, f): pass | 609 | void foobazquuz(int a, int b, int f){}; |
| 610 | int main() { | ||
| 599 | ") | 611 | ") |
| 600 | 612 | ||
| 601 | (declare-function yas-minor-mode nil) | 613 | (declare-function yas-minor-mode nil) |
| 602 | 614 | ||
| 603 | (ert-deftest eglot-test-snippet-completions () | 615 | (ert-deftest eglot-test-snippet-completions () |
| 604 | "Test simple snippet completion in a python LSP." | 616 | "Test simple snippet completion in a clangd LSP." |
| 605 | (skip-unless (and (executable-find "pylsp") | 617 | (skip-unless (and (executable-find "clangd") |
| 606 | (functionp 'yas-minor-mode))) | 618 | (functionp 'yas-minor-mode))) |
| 607 | (eglot--with-fixture | 619 | (eglot--with-fixture |
| 608 | `(("project" . (("something.py" . ,eglot--test-python-buffer)))) | 620 | `(("project" . (("coiso.c" . ,eglot--test-c-buffer)))) |
| 609 | (with-current-buffer | 621 | (with-current-buffer |
| 610 | (eglot--find-file-noselect "project/something.py") | 622 | (eglot--find-file-noselect "project/coiso.c") |
| 611 | (yas-minor-mode 1) | 623 | (yas-minor-mode 1) |
| 612 | (let ((eglot-workspace-configuration | 624 | (eglot--wait-for-clangd) |
| 613 | `((:pylsp . (:plugins (:jedi_completion (:include_params t))))))) | ||
| 614 | (should (eglot--tests-connect))) | ||
| 615 | (goto-char (point-max)) | 625 | (goto-char (point-max)) |
| 616 | (insert "foobar") | 626 | (insert "foobar") |
| 617 | (completion-at-point) | 627 | (completion-at-point) |
| 618 | (should (looking-back "foobarquux(")) | 628 | (should (looking-back "foobarquux(")) |
| 619 | (should (looking-at "a, b)"))))) | 629 | (should (looking-at "int a, int b, int c)"))))) |
| 620 | 630 | ||
| 621 | (defvar company-candidates) | 631 | (defvar company-candidates) |
| 622 | (declare-function company-mode nil) | 632 | (declare-function company-mode nil) |
| 623 | (declare-function company-complete nil) | 633 | (declare-function company-complete nil) |
| 624 | 634 | ||
| 625 | (ert-deftest eglot-test-snippet-completions-with-company () | 635 | (ert-deftest eglot-test-snippet-completions-with-company () |
| 626 | "Test simple snippet completion in a python LSP." | 636 | "Test simple snippet completion in a clangd LSP." |
| 627 | (skip-unless (and (executable-find "pylsp") | 637 | (skip-unless (and (executable-find "clangd") |
| 628 | (functionp 'yas-minor-mode) | 638 | (functionp 'yas-minor-mode) |
| 629 | (functionp 'company-complete))) | 639 | (functionp 'company-complete))) |
| 630 | (eglot--with-fixture | 640 | (eglot--with-fixture |
| 631 | `(("project" . (("something.py" . ,eglot--test-python-buffer)))) | 641 | `(("project" . (("coiso.c" . ,eglot--test-c-buffer)))) |
| 632 | (with-current-buffer | 642 | (with-current-buffer |
| 633 | (eglot--find-file-noselect "project/something.py") | 643 | (eglot--find-file-noselect "project/coiso.c") |
| 634 | (yas-minor-mode 1) | 644 | (yas-minor-mode 1) |
| 635 | (let ((eglot-workspace-configuration | 645 | (eglot--wait-for-clangd) |
| 636 | `((:pylsp . (:plugins (:jedi_completion (:include_params t))))))) | ||
| 637 | (should (eglot--tests-connect))) | ||
| 638 | (goto-char (point-max)) | 646 | (goto-char (point-max)) |
| 639 | (insert "foo") | 647 | (insert "foo") |
| 640 | (company-mode) | 648 | (company-mode) |
| @@ -642,98 +650,63 @@ def foobazquuz(d, e, f): pass | |||
| 642 | (should (looking-back "fooba")) | 650 | (should (looking-back "fooba")) |
| 643 | (should (= 2 (length company-candidates))) | 651 | (should (= 2 (length company-candidates))) |
| 644 | ;; this last one is brittle, since there it is possible that | 652 | ;; this last one is brittle, since there it is possible that |
| 645 | ;; pylsp will change the representation of this candidate | 653 | ;; clangd will change the representation of this candidate |
| 646 | (should (member "foobazquuz(d, e, f)" company-candidates))))) | 654 | (should (member "foobazquuz(int a, int b, int f)" company-candidates))))) |
| 647 | 655 | ||
| 648 | (ert-deftest eglot-test-eldoc-after-completions () | 656 | (ert-deftest eglot-test-eldoc-after-completions () |
| 649 | "Test documentation echo in a python LSP." | 657 | "Test documentation echo in a clangd LSP." |
| 650 | (skip-unless (executable-find "pylsp")) | 658 | (skip-unless (executable-find "clangd")) |
| 651 | (eglot--with-fixture | 659 | (eglot--with-fixture |
| 652 | `(("project" . (("something.py" . "import sys\nsys.exi")))) | 660 | `(("project" . (("coiso.c" . "#include <stdio.h>\nint main () {fprin")))) |
| 653 | (with-current-buffer | 661 | (with-current-buffer |
| 654 | (eglot--find-file-noselect "project/something.py") | 662 | (eglot--find-file-noselect "project/coiso.c") |
| 655 | (should (eglot--tests-connect)) | 663 | (eglot--wait-for-clangd) |
| 656 | (goto-char (point-max)) | 664 | (goto-char (point-max)) |
| 657 | (completion-at-point) | 665 | (completion-at-point) |
| 658 | (should (looking-back "sys.exit")) | 666 | (message (buffer-string)) |
| 659 | (should (string-match "^exit" (eglot--tests-force-full-eldoc)))))) | 667 | (should (looking-back "fprintf(?")) |
| 668 | (unless (= (char-before) ?\()) (insert "()") (backward-char) | ||
| 669 | (eglot--signal-textDocument/didChange) | ||
| 670 | (should (string-match "^fprintf" (eglot--tests-force-full-eldoc)))))) | ||
| 660 | 671 | ||
| 661 | (ert-deftest eglot-test-multiline-eldoc () | 672 | (ert-deftest eglot-test-multiline-eldoc () |
| 662 | "Test if suitable amount of lines of hover info are shown." | 673 | "Test Eldoc documentation from multiple osurces." |
| 663 | (skip-unless (executable-find "pylsp")) | 674 | (skip-unless (executable-find "clangd")) |
| 664 | (eglot--with-fixture | 675 | (eglot--with-fixture |
| 665 | `(("project" . (("hover-first.py" . "from datetime import datetime")))) | 676 | `(("project" . (("coiso.c" . |
| 677 | "#include <stdio.h>\nint main () {fprintf(blergh);}")))) | ||
| 666 | (with-current-buffer | 678 | (with-current-buffer |
| 667 | (eglot--find-file-noselect "project/hover-first.py") | 679 | (eglot--find-file-noselect "project/coiso.c") |
| 668 | (should (eglot--tests-connect)) | 680 | (search-forward "fprintf(ble") |
| 669 | (goto-char (point-max)) | 681 | (eglot--wait-for-clangd) |
| 670 | ;; one-line | 682 | (flymake-start nil t) ;; thing brings in the "unknown identifier blergh" |
| 671 | (let* ((eldoc-echo-area-use-multiline-p t) | 683 | (let* ((captured-message (eglot--tests-force-full-eldoc))) |
| 672 | (captured-message (eglot--tests-force-full-eldoc))) | 684 | ;; check for signature and error message in the result |
| 673 | (should (string-match "datetim" captured-message)) | 685 | (should (string-match "fprintf" captured-message)) |
| 686 | (should (string-match "blergh" captured-message)) | ||
| 674 | (should (cl-find ?\n captured-message)))))) | 687 | (should (cl-find ?\n captured-message)))))) |
| 675 | 688 | ||
| 676 | (ert-deftest eglot-test-single-line-eldoc () | 689 | (ert-deftest eglot-test-formatting () |
| 677 | "Test if suitable amount of lines of hover info are shown." | 690 | "Test formatting in the clangd server." |
| 678 | (skip-unless (executable-find "pylsp")) | ||
| 679 | (eglot--with-fixture | ||
| 680 | `(("project" . (("hover-first.py" . "from datetime import datetime")))) | ||
| 681 | (with-current-buffer | ||
| 682 | (eglot--find-file-noselect "project/hover-first.py") | ||
| 683 | (should (eglot--tests-connect)) | ||
| 684 | (goto-char (point-max)) | ||
| 685 | ;; one-line | ||
| 686 | (let* ((eldoc-echo-area-use-multiline-p nil) | ||
| 687 | (captured-message (eglot--tests-force-full-eldoc))) | ||
| 688 | (should (string-match "datetim" captured-message)) | ||
| 689 | (should (not (cl-find ?\n eldoc-last-message))))))) | ||
| 690 | |||
| 691 | (ert-deftest eglot-test-python-autopep-formatting () | ||
| 692 | "Test formatting in the pylsp python LSP. | ||
| 693 | pylsp prefers autopep over yafp, despite its README stating the contrary." | ||
| 694 | ;; Beware, default autopep rules can change over time, which may | 691 | ;; Beware, default autopep rules can change over time, which may |
| 695 | ;; affect this test. | 692 | ;; affect this test. |
| 696 | (skip-unless (and (executable-find "pylsp") | 693 | (skip-unless (executable-find "clangd")) |
| 697 | (executable-find "autopep8"))) | ||
| 698 | (eglot--with-fixture | ||
| 699 | `(("project" . (("something.py" . "def a():pass\n\ndef b():pass")))) | ||
| 700 | (with-current-buffer | ||
| 701 | (eglot--find-file-noselect "project/something.py") | ||
| 702 | (should (eglot--tests-connect)) | ||
| 703 | ;; Try to format just the second line | ||
| 704 | (search-forward "b():pa") | ||
| 705 | (eglot-format (line-beginning-position) (line-end-position)) | ||
| 706 | (should (looking-at "ss")) | ||
| 707 | (should | ||
| 708 | (or (string= (buffer-string) "def a():pass\n\n\ndef b(): pass\n") | ||
| 709 | ;; autopep8 2.0.0 (pycodestyle: 2.9.1) | ||
| 710 | (string= (buffer-string) "def a():pass\n\ndef b(): pass"))) | ||
| 711 | ;; now format the whole buffer | ||
| 712 | (eglot-format-buffer) | ||
| 713 | (should | ||
| 714 | (string= (buffer-string) "def a(): pass\n\n\ndef b(): pass\n"))))) | ||
| 715 | |||
| 716 | (ert-deftest eglot-test-python-yapf-formatting () | ||
| 717 | "Test formatting in the pylsp python LSP." | ||
| 718 | (skip-unless (and (executable-find "pylsp") | ||
| 719 | (not (executable-find "autopep8")) | ||
| 720 | (or (executable-find "yapf") | ||
| 721 | (executable-find "yapf3")))) | ||
| 722 | (eglot--with-fixture | 694 | (eglot--with-fixture |
| 723 | `(("project" . (("something.py" . "def a():pass\ndef b():pass")))) | 695 | `(("project" . (("coiso.c" . ,(concat "#include <stdio.h>\n" |
| 696 | "int main(){fprintf(blergh);}" | ||
| 697 | "int ble{\n\nreturn 0;}"))))) | ||
| 724 | (with-current-buffer | 698 | (with-current-buffer |
| 725 | (eglot--find-file-noselect "project/something.py") | 699 | (eglot--find-file-noselect "project/coiso.c") |
| 726 | (should (eglot--tests-connect)) | 700 | (eglot--wait-for-clangd) |
| 701 | (forward-line) | ||
| 727 | ;; Try to format just the second line | 702 | ;; Try to format just the second line |
| 728 | (search-forward "b():pa") | ||
| 729 | (eglot-format (line-beginning-position) (line-end-position)) | 703 | (eglot-format (line-beginning-position) (line-end-position)) |
| 730 | (should (looking-at "ss")) | 704 | (should (looking-at "int main() { fprintf(blergh); }")) |
| 731 | (should | 705 | ;; ;; now format the whole buffer |
| 732 | (string= (buffer-string) "def a():pass\n\n\ndef b():\n pass\n")) | ||
| 733 | ;; now format the whole buffer | ||
| 734 | (eglot-format-buffer) | 706 | (eglot-format-buffer) |
| 735 | (should | 707 | (should |
| 736 | (string= (buffer-string) "def a():\n pass\n\n\ndef b():\n pass\n"))))) | 708 | (string= (buffer-string) |
| 709 | "#include <stdio.h>\nint main() { fprintf(blergh); }\nint ble { return 0; }"))))) | ||
| 737 | 710 | ||
| 738 | (ert-deftest eglot-test-rust-on-type-formatting () | 711 | (ert-deftest eglot-test-rust-on-type-formatting () |
| 739 | "Test textDocument/onTypeFormatting against rust-analyzer." | 712 | "Test textDocument/onTypeFormatting against rust-analyzer." |