|
| 1 | +;;; lsp-sonarlint-secondar-locations-test.el --- Secondary locations tests for Sonarlint LSP client -*- lexical-binding: t; -*- |
| 2 | +;;; |
| 3 | +;; Author: Arseniy Zaostrovnykh |
| 4 | +;; Created: 02 August 2024 |
| 5 | +;; License: GPL-3.0-or-later |
| 6 | +;; |
| 7 | +;; This program is free software; you can redistribute it and/or modify |
| 8 | +;; it under the terms of the GNU General Public License as published by |
| 9 | +;; the Free Software Foundation, either version 3 of the License, or |
| 10 | +;; (at your option) any later version. |
| 11 | + |
| 12 | +;; This program is distributed in the hope that it will be useful, |
| 13 | +;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 15 | +;; GNU General Public License for more details. |
| 16 | + |
| 17 | +;; You should have received a copy of the GNU General Public License |
| 18 | +;; along with this program. If not, see <https://www.gnu.org/licenses/>. |
| 19 | + |
| 20 | +;;; Commentary: |
| 21 | +;; Tests for the display of secondary locations and flow steps for SonarLint issues. |
| 22 | + |
| 23 | +;;; Code: |
| 24 | + |
| 25 | +(require 'lsp-mode) |
| 26 | +(require 'lsp-sonarlint) |
| 27 | +(load-file (expand-file-name "lsp-sonarlint-test-utils.el" |
| 28 | + (file-name-directory (or load-file-name (buffer-file-name))))) |
| 29 | + |
| 30 | +(defvar lsp-sonarlint-test--file-path (lsp-sonarlint-sample-file "secondaries.txt")) |
| 31 | +(defvar lsp-sonarlint-test--file-uri (concat "file://" lsp-sonarlint-test--file-path)) |
| 32 | + |
| 33 | +(defun lsp-sonarlint-test--find-line (file-content line) |
| 34 | + "Find LINE in the multi-line FILE-CONTENT string." |
| 35 | + (let ((lines (split-string file-content "\n")) |
| 36 | + (line-number 1) |
| 37 | + (found nil)) |
| 38 | + (while (and lines (not found)) |
| 39 | + (when (string= (car lines) line) |
| 40 | + (setq found line-number)) |
| 41 | + (setq lines (cdr lines)) |
| 42 | + (setq line-number (1+ line-number))) |
| 43 | + (when (not found) |
| 44 | + (error "Line %s not found" line)) |
| 45 | + found)) |
| 46 | + |
| 47 | + |
| 48 | +(defun lsp-sonarlint-test-range-make (file-content line marker) |
| 49 | + "Create a single-line diagnostics range summary. |
| 50 | +
|
| 51 | +Find LINE in FILE-CONTENT and take that as the line number. |
| 52 | +Set the :from and :to characters to reflect the position of |
| 53 | +`^^^^' in the MARKER. |
| 54 | +
|
| 55 | +Example (suppose line #3 of current buffer is \"full line\"): |
| 56 | +
|
| 57 | +(lsp-test-range-make (buffer-string) |
| 58 | + \"full line\" |
| 59 | + \" ^^^^\") |
| 60 | +
|
| 61 | +-> (:line 3 :from 5 :to 8) |
| 62 | +" |
| 63 | + (let ((line-number (lsp-sonarlint-test--find-line file-content line))) |
| 64 | + (should-not (null line-number)) |
| 65 | + (should (eq (length marker) (length line))) |
| 66 | + (should (string-match "^ *\\(\\^+\\) *$" marker)) |
| 67 | + (list :line line-number :from (match-beginning 1) :to (match-end 1)))) |
| 68 | + |
| 69 | +(defun lsp-sonarlint-test--line-range->ht (range) |
| 70 | + "Convert RANGE to a hash table." |
| 71 | + (lsp-ht ("startLine" (plist-get range :line)) |
| 72 | + ("startLineOffset" (plist-get range :from)) |
| 73 | + ("endLine" (plist-get range :line)) |
| 74 | + ("endLineOffset" (plist-get range :to)) |
| 75 | + ("hash" ""))) |
| 76 | + |
| 77 | +(defun lsp-sonarlint-test--secloc-command (primary secondary-flows) |
| 78 | + "Command for a SonarLint issue with PRIMARY location and SECONDARY-FLOWS. |
| 79 | +
|
| 80 | +A location is a plist with message and line range as follows: |
| 81 | +(:message \"Identical code\" :range (:line 29 :from 4 :to 14)) |
| 82 | +PRIMARY is a location. SECONDARY-FLOWS is a list of lists of |
| 83 | +locations, each list representing a flow. |
| 84 | +
|
| 85 | +Returns a hashtable representing the command as received from |
| 86 | +SonarLint LSP server." |
| 87 | + (lsp-ht ("title" "Show all locations for issue 'cpp:S3923'") |
| 88 | + ("command" "SonarLint.ShowAllLocations") |
| 89 | + ("arguments" |
| 90 | + (vector |
| 91 | + (lsp-ht ("fileUri" lsp-sonarlint-test--file-uri) |
| 92 | + ("message" (plist-get primary :message)) |
| 93 | + ("shouldOpenRuleDescription" t) |
| 94 | + ("severity" "MAJOR") |
| 95 | + ("ruleKey" "cpp:S3923") |
| 96 | + ("flows" |
| 97 | + (apply |
| 98 | + #'vector |
| 99 | + (mapcar |
| 100 | + (lambda (flow) |
| 101 | + (lsp-ht |
| 102 | + ("locations" |
| 103 | + (apply |
| 104 | + #'vector |
| 105 | + (mapcar (lambda (loc) |
| 106 | + (lsp-ht |
| 107 | + ("textRange" |
| 108 | + (lsp-sonarlint-test--line-range->ht |
| 109 | + (plist-get loc :range))) |
| 110 | + ("uri" lsp-sonarlint-test--file-uri) |
| 111 | + ("filePath" lsp-sonarlint-test--file-path) |
| 112 | + ("message" (plist-get loc :message)) |
| 113 | + ("exists" t) |
| 114 | + ("codeMatches" t))) |
| 115 | + flow))))) |
| 116 | + secondary-flows))) |
| 117 | + ("textRange" |
| 118 | + (lsp-sonarlint-test--line-range->ht (plist-get primary :range))) |
| 119 | + ("codeMatches" nil)))))) |
| 120 | + |
| 121 | +(ert-deftest lsp-sonarlint-test--display-secondary-messages () |
| 122 | + "Test that secondary locations are displayed correctly." |
| 123 | + (let ((target-file-buf (find-file-noselect lsp-sonarlint-test--file-path))) |
| 124 | + (with-current-buffer target-file-buf |
| 125 | + (let* ((primary-range (lsp-sonarlint-test-range-make |
| 126 | + (buffer-string) |
| 127 | + " if (param == 0) {" |
| 128 | + " ^^ ")) |
| 129 | + (primary-loc `(:message "Redundant branching" :range ,primary-range)) |
| 130 | + (secondary-range1 |
| 131 | + (lsp-sonarlint-test-range-make (buffer-string) |
| 132 | + " int a = 0;" |
| 133 | + " ^^^^^^^^^^")) |
| 134 | + (sec-flow1 `((:message "Identical code" :range ,secondary-range1))) |
| 135 | + (secondary-range2 |
| 136 | + (lsp-sonarlint-test-range-make (buffer-string) |
| 137 | + " int b = 0;" |
| 138 | + " ^^^^^^^^^^")) |
| 139 | + (sec-flow2 `((:message "Identical code" :range ,secondary-range2))) |
| 140 | + (command (lsp-sonarlint-test--secloc-command |
| 141 | + primary-loc (list sec-flow1 sec-flow2)))) |
| 142 | + (lsp-sonarlint--show-all-locations command) |
| 143 | + (with-current-buffer lsp-sonarlint--secondary-messages-buffer-name |
| 144 | + (should (equal (buffer-string) |
| 145 | + "Redundant branching |
| 146 | +Identical code |
| 147 | +Identical code"))))))) |
| 148 | + |
| 149 | + |
| 150 | +;;; lsp-sonarlint-secondar-locations-test.el ends here |
0 commit comments