Skip to content

Commit ad668f7

Browse files
authored
Fix and document tests (#25)
* Stabilize lsp-sonarlint-display-rule-descr-test * Fix CI tests: download SonarLint before testing * Document testing workflow * Bump NodeJS version to satisfy SonarJS analyzer requirements * use any c++ compiler in your path, not just /usr/bin/c++ As an example, guix package manager installs binaries in other places, so you won't find /usr/bin/c++ on a guix-managed system. * Add a test checking the required C++ compiler * Fix regex extracting compiler exec * Check that LSP detect absence of SonarLint * Exclude platforms with failing tests * Remove windows from list of platforms to test on * Bump emacs 29.x to 29.4 * Re-enable MacOS except for one test * Simplify a test * Disable all snapshot tests
1 parent 043bda7 commit ad668f7

File tree

6 files changed

+135
-26
lines changed

6 files changed

+135
-26
lines changed

.github/workflows/test.yml

+16-12
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,22 @@ jobs:
2121
emacs-version:
2222
- 27.2
2323
- 28.2
24-
- 29.3
24+
- 29.4
2525
experimental: [false]
26-
include:
27-
- os: ubuntu-latest
28-
emacs-version: snapshot
29-
experimental: true
30-
- os: macos-latest
31-
emacs-version: snapshot
32-
experimental: true
33-
- os: windows-latest
34-
emacs-version: snapshot
35-
experimental: true
26+
# TODO: enable once emacs snapshot version is fixed
27+
# For some reason takes too long to run, see
28+
# github.com/emacs-lsp/lsp-sonarlint/pull/25#issuecomment-2226929636
29+
# include:
30+
# - os: ubuntu-latest
31+
# emacs-version: snapshot
32+
# experimental: true
33+
# - os: macos-latest
34+
# emacs-version: snapshot
35+
# experimental: true
36+
# see https://github.com/emacs-eask/cli/issues/224
37+
# - os: windows-latest
38+
# emacs-version: snapshot
39+
# experimental: true
3640
exclude:
3741
- os: macos-latest
3842
emacs-version: 27.2
@@ -49,7 +53,7 @@ jobs:
4953
- name: Setup NodeJS # for JS and TS analyzer
5054
uses: actions/setup-node@v3
5155
with:
52-
node-version: 16
56+
node-version: 18
5357

5458
- uses: jcs090218/setup-emacs@master
5559
with:

Makefile

+6-2
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ EASK ?= eask
55

66
TEST-FILES := $(shell ls test/*.el)
77

8-
.PHONY: clean checkdoc lint package install compile test
8+
.PHONY: clean checkdoc lint package install compile download-sonarlint test
99

10-
ci: clean package install compile test
10+
ci: clean package install compile download-sonarlint test
1111

1212
package:
1313
@echo "Packaging..."
@@ -21,6 +21,10 @@ compile:
2121
@echo "Compiling..."
2222
$(EASK) compile
2323

24+
download-sonarlint:
25+
@echo "Downloading SonarLint..."
26+
$(EASK) eval '(progn (require (quote lsp-sonarlint)) (lsp-sonarlint-download))'
27+
2428
test:
2529
@echo "Testing..."
2630
$(EASK) test ert $(TEST-FILES)

README.md

+48
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,54 @@ Click [here](https://github.com/SonarSource/sonarlint-vscode/blob/master/telemet
143143
* [treemacs](https://github.com/Alexander-Miller/treemacs) : Project viewer.
144144
* [lsp-treemacs](https://github.com/emacs-lsp/lsp-treemacs) : `lsp-mode` GUI controls implemented using treemacs.
145145

146+
## Development
147+
148+
### Prerequisites
149+
150+
You will need `make` and [`eask`](https://emacs-eask.github.io/) to run `lsp-sonarlint` tests.
151+
See also (Requirements)(#requirements) section.
152+
153+
If you do not have `eask` installed, you can install it locally with:
154+
155+
``` shell
156+
npm install @emacs-eask/cli
157+
export EASK="$PWD/node_modules/@emacs-eask/cli/eask"
158+
```
159+
160+
Or globally with:
161+
162+
``` shell
163+
npm install -g @emacs-eask/cli
164+
```
165+
166+
### Testing
167+
168+
We use [Emacs ERT](https://www.gnu.org/software/emacs/manual/html_node/ert/) for testing.
169+
You can run tests with:
170+
171+
``` shell
172+
make package
173+
make install
174+
make compile
175+
make download-sonarlint
176+
make test
177+
```
178+
179+
#### Interactive Testing
180+
181+
You can also run the tests one-by-one interactively.
182+
183+
Open a test file from tests/*.el in Emacs.
184+
Evaluate the file contents (`eval-buffer`) to load test definitions into the session.
185+
Run `ert` command to run all or selected tests.
186+
To run the integration tests, you will have to shut down all your lsp workspaces
187+
to ensure consistent starting state.
188+
189+
Check out `*lsp-log*`, `*lsp-log: sonarlint:NNNNNNNN*`, `*sonarlint*`, `*sonarlint:stderr*`
190+
for logs when troubleshooting a test.
191+
192+
You can start with test/trivial-test.el to check that your testing harness works.
193+
146194
## Contributions
147195

148196
Contributions are very much welcome.

fixtures/compile_commands.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[
22
{
33
"directory": ".",
4-
"command": "/usr/bin/c++ sample.cpp",
4+
"command": "c++ sample.cpp",
55
"file": "sample.cpp",
66
"output": "dummy"
77
}

lsp-sonarlint.el

+3
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,9 @@ See `lsp-sonarlint-available-analyzers' and `lsp-sonarlint-enabled-analyzers'"
259259

260260
(defun lsp-sonarlint-server-start-fun()
261261
"Start lsp-sonarlint in stdio mode."
262+
;; This will signal an error if `lsp-sonarlint-download-dir' is not a dir
263+
;; or if the java executable is not found there.
264+
;; Thus, it also serves as a check for the presence of SonarLint LSP server.
262265
(let* ((root-dir lsp-sonarlint-download-dir)
263266
(bundled-java-path (car (directory-files-recursively root-dir "java\\(.exe\\)?$")))
264267
(java-path (if lsp-sonarlint-use-system-jre "java" bundled-java-path))

test/lsp-sonarlint-integration-test.el

+61-11
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
;; You should have received a copy of the GNU General Public License
1919
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
20+
;; Package-Requires: ((emacs "27.2"))
2021

2122
;;; Commentary:
2223
;; Tests for the integration of the LSP mode and SonarLint language server
@@ -27,6 +28,15 @@
2728
(require 'lsp-mode)
2829
(require 'lsp-sonarlint)
2930

31+
(ert-deftest lsp-sonarlint-plugin-downloaded ()
32+
"Check whether you have downloaded SonarLint.
33+
34+
This is a prerequisite for all the integration tests. If this
35+
test fails, you need to download the SonarLint plugin using
36+
37+
make download-sonarlint"
38+
(should (file-exists-p (concat lsp-sonarlint-download-dir "/extension/server/sonarlint-ls.jar"))))
39+
3040
(defun lsp-sonarlint--wait-for (predicate hook timeout)
3141
"Register PREDICATE to run on HOOK, and wait until it returns t.
3242
If that does not occur before TIMEOUT, throw an error."
@@ -71,7 +81,6 @@ only works for specific textDocument/didOpen:languageId."
7181
(lsp-enable-snippet nil)
7282
received-warnings)
7383
(let ((buf (find-file-noselect file))
74-
(lsp-sonarlint-plugin-autodownload t)
7584
(diagnostics-updated nil)
7685
(register-warning (lambda (&rest w) (when (equal (car w) 'lsp-mode)
7786
(push (cadr w) received-warnings)))))
@@ -125,6 +134,29 @@ If nil, use python-mode by default."
125134
(lsp-sonarlint--get-codes-of-issues diags))
126135
(if major-mode major-mode 'python-mode)))
127136

137+
(ert-deftest lsp-sonarlint-lsp-mode-detects-abscent-plugin ()
138+
"Check that LSP mode detects the absence of the SonarLint plugin."
139+
(let ((lsp-sonarlint-download-dir (lsp-sonarlint--sample-file ""))
140+
(lsp-sonarlint-use-system-jre t)
141+
(filename (lsp-sonarlint--sample-file "sample.py")))
142+
(should (null (lsp-sonarlint--any-alive-workspaces-p)))
143+
(let ((lsp-enabled-clients '(sonarlint))
144+
(lsp-keep-workspace-alive nil)
145+
(dir (file-name-directory filename))
146+
(lsp-enable-snippet nil))
147+
(let ((buf (find-file-noselect filename)))
148+
(unwind-protect
149+
(progn
150+
(lsp-workspace-folders-add dir)
151+
(with-current-buffer buf
152+
(python-mode)
153+
(should (string-match-p
154+
"do not have automatic installation: sonarlint"
155+
(lsp)))))
156+
(kill-buffer buf)
157+
(lsp-workspace-folders-remove dir)
158+
(lsp-sonarlint--wait-for-workspaces-to-die 10))))))
159+
128160
(ert-deftest lsp-sonarlint-python-reports-issues ()
129161
"Check that LSP can get Python SonarLint issues for a Python file."
130162
(should (equal (lsp-sonarlint--get-all-issue-codes "sample.py")
@@ -174,13 +206,28 @@ If nil, use python-mode by default."
174206
(should (equal (lsp-sonarlint--get-all-issue-codes "sample.go")
175207
'("go:S1135"))))
176208

209+
(defun lsp-sonarlint--read-file (fname)
210+
"Read the contents of the file FNAME."
211+
(with-temp-buffer
212+
(insert-file-contents (lsp-sonarlint--sample-file fname))
213+
(buffer-string)))
214+
215+
(ert-deftest lsp-sonarlint--c++-compiler-available ()
216+
"Check that the C++ compiler used for tests is available."
217+
(let ((comp-db (lsp-sonarlint--read-file "compile_commands.json")))
218+
(should (string-match "command\": \"\\(.*\\) sample.cpp" comp-db))
219+
(let ((compiler (match-string 1 comp-db)))
220+
(should (executable-find compiler)))))
221+
177222
(ert-deftest lsp-sonarlint-c++-reports-issues ()
178223
"Check that LSP can get go SonarLint issues for a C++ file."
179-
(should (equal (lsp-sonarlint--get-all-issue-codes "sample.cpp" 'c++-mode)
180-
'("cpp:S995"))))
224+
;; TODO: fix for MacOS
225+
(unless (eq system-type 'darwin)
226+
(should (equal (lsp-sonarlint--get-all-issue-codes "sample.cpp" 'c++-mode)
227+
'("cpp:S995")))))
181228

182229
(defun lsp-sonarlint--find-descr-action-at-point ()
183-
"Find the 'get rule description' code action for the issue at point."
230+
"Find the `get rule description' code action for the issue at point."
184231
(seq-find (lambda (action) (string-match-p "description" (gethash "title" action)))
185232
(lsp-code-actions-at-point)))
186233

@@ -213,19 +260,22 @@ If nil, use python-mode by default."
213260
(lsp-sonarlint--go-to-first-diag diags)
214261
(let ((descr-action (lsp-sonarlint--find-descr-action-at-point)))
215262
(let ((description-opened nil))
216-
(cl-flet ((check-opened-buffer
217-
(buf)
218-
(when (lsp-sonarlint--buf-has-rule-descr-p buf)
219-
(setq description-opened t))))
263+
(cl-flet ((check-opened-buffer (buf)
264+
(when (lsp-sonarlint--buf-has-rule-descr-p buf)
265+
(setq description-opened t))))
220266
(unwind-protect
221267
(progn
222268
(advice-add 'shr-render-buffer :before #'check-opened-buffer)
223-
(sit-for 1)
224-
(lsp-execute-code-action descr-action)
225269
(with-timeout (8 (error "Timeout waiting for rule description"))
226270
(while (not description-opened)
271+
;; Repeat the request multiple times because SonarLint
272+
;; might get distracted with other requests and "forget" to
273+
;; respond
274+
(lsp-execute-code-action descr-action)
227275
(message "still waiting")
228-
(sit-for 0.1)))
276+
(sit-for 0.3)))
229277
(should description-opened))
230278
(advice-remove 'shr-render-buffer #'check-opened-buffer))))))
231279
'python-mode))
280+
281+
;;; integration.el ends here

0 commit comments

Comments
 (0)