diff --git a/.cirrus/modules/qa.star b/.cirrus/modules/qa.star
index 7e3ba392f..9400c6883 100644
--- a/.cirrus/modules/qa.star
+++ b/.cirrus/modules/qa.star
@@ -14,7 +14,7 @@ load(
"mkdir_orchestrator_home_script",
)
-QA_PLUGIN_GRADLE_TASK = "its:plugin:tests:integrationTest"
+QA_PLUGIN_GRADLE_TASK = "its:plugin:integrationTest"
QA_RULING_GRADLE_TASK = "its:ruling:integrationTest"
QA_QUBE_LATEST_RELEASE = "LATEST_RELEASE"
diff --git a/README.md b/README.md
index e2ae9d0ae..c8ff329e7 100644
--- a/README.md
+++ b/README.md
@@ -91,7 +91,7 @@ Before running any of the integration tests make sure the submodules are checked
#### Plugin Test
The "Plugin Test" is an additional integration test that verifies plugin features such as metric calculation, coverage, etc. To launch it:
```shell
-./gradlew its:plugin:tests:integrationTest
+./gradlew its:plugin:integrationTest
```
#### Ruling Test
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index b9f9ace36..4c6a6fb39 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -4,8 +4,8 @@ sonar-plugin-api = "10.13.0.2560"
sonarqube = "10.7.0.96327"
sonar-scanner-gradle = "5.1.0.4882"
sonar-orchestrator = "5.0.0.2065"
-sonarlint = "9.8.0.76914"
-slf4j = "1.7.36"
+sonarlint = "10.9.0.79478"
+slf4j = "2.0.16"
sslr = "1.24.0.633"
junit = "5.11.3"
assertj = "3.26.3"
@@ -19,6 +19,7 @@ jsr305 = "3.0.2"
maven-project = "2.2.1"
junit-platform = "1.11.3"
staxmate = "2.0.1"
+awaitility = "4.2.2"
[libraries]
sonar-analyzer-commons = { module = "org.sonarsource.analyzer-commons:sonar-analyzer-commons", version.ref = "sonar-commons" }
@@ -32,8 +33,9 @@ sonar-testing-harness = { module = "org.sonarsource.sonarqube:sonar-testing-harn
sonar-ws = { module = "org.sonarsource.sonarqube:sonar-ws", version.ref = "sonarqube" }
sonar-scanner-gradle = { module = "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin", version.ref = "sonar-scanner-gradle" }
sonar-orchestrator-junit5 = { module = "org.sonarsource.orchestrator:sonar-orchestrator-junit5", version.ref = "sonar-orchestrator" }
-sonarlint-core = { module = "org.sonarsource.sonarlint.core:sonarlint-core", version.ref = "sonarlint" }
-sonarlint-plugin-api = { module = "org.sonarsource.sonarlint.core:sonarlint-plugin-api", version.ref = "sonarlint" }
+sonar-lint-core = { module = "org.sonarsource.sonarlint.core:sonarlint-core", version.ref = "sonarlint" }
+sonar-lint-rpc-java-client = { module = "org.sonarsource.sonarlint.core:sonarlint-rpc-java-client", version.ref = "sonarlint" }
+sonar-lint-rpc-impl = { module = "org.sonarsource.sonarlint.core:sonarlint-rpc-impl", version.ref = "sonarlint" }
slf4j-api = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" }
sslr-core = { module = "org.sonarsource.sslr:sslr-core", version.ref = "sslr" }
sslr-toolkit = { module = "org.sonarsource.sslr:sslr-toolkit", version.ref = "sslr" }
@@ -50,6 +52,7 @@ jsr305 = { module = "com.google.code.findbugs:jsr305", version.ref = "jsr305" }
maven-project = { module = "org.apache.maven:maven-project", version.ref = "maven-project" }
junit-platform = { module = "org.junit.platform:junit-platform-suite", version.ref = "junit-platform" }
staxmate = { module = "org.codehaus.staxmate:staxmate", version.ref = "staxmate" }
+awaitility = { module = "org.awaitility:awaitility", version.ref = "awaitility"}
[plugins]
spotless = { id = "com.diffplug.spotless", version.ref = "spotless-gradle" }
diff --git a/its/plugin/tests/build.gradle.kts b/its/plugin/build.gradle.kts
similarity index 73%
rename from its/plugin/tests/build.gradle.kts
rename to its/plugin/build.gradle.kts
index d882521ca..fdd2f6c88 100644
--- a/its/plugin/tests/build.gradle.kts
+++ b/its/plugin/build.gradle.kts
@@ -7,18 +7,22 @@ plugins {
description = "PHP :: Integration Tests :: Plugin"
dependencies {
- "integrationTestImplementation"(project(":sonar-php-plugin", configuration = "shadow"))
+ "integrationTestCompileOnly"(project(":sonar-php-plugin", configuration = "shadow"))
"integrationTestImplementation"(libs.sonar.orchestrator.junit5)
- "integrationTestImplementation"(libs.junit.platform)
- "integrationTestImplementation"(libs.sonar.ws)
- "integrationTestImplementation"(libs.sonarlint.core)
- "integrationTestImplementation"(libs.sonarlint.plugin.api)
"integrationTestImplementation"(libs.sonar.plugin.api)
+ "integrationTestImplementation"(libs.sonar.ws)
+ "integrationTestImplementation"(libs.sonar.lint.core)
+ "integrationTestImplementation"(libs.sonar.lint.rpc.java.client)
+ "integrationTestImplementation"(libs.sonar.lint.rpc.impl)
+ "integrationTestImplementation"(libs.junit.platform)
"integrationTestImplementation"(libs.junit.jupiter)
"integrationTestImplementation"(libs.assertj.core)
+ "integrationTestImplementation"(libs.awaitility)
"integrationTestCompileOnly"(libs.jsr305)
}
+val integrationTest by sourceSets.integrationTest
+
(tasks["integrationTest"] as Test).filter {
setIncludePatterns("Tests")
}
diff --git a/its/plugin/tests/src/integrationTest/java/com/sonar/it/php/CpdTokenTest.java b/its/plugin/src/integrationTest/java/com/sonar/it/php/CpdTokenTest.java
similarity index 100%
rename from its/plugin/tests/src/integrationTest/java/com/sonar/it/php/CpdTokenTest.java
rename to its/plugin/src/integrationTest/java/com/sonar/it/php/CpdTokenTest.java
diff --git a/its/plugin/tests/src/integrationTest/java/com/sonar/it/php/CustomRulesTest.java b/its/plugin/src/integrationTest/java/com/sonar/it/php/CustomRulesTest.java
similarity index 100%
rename from its/plugin/tests/src/integrationTest/java/com/sonar/it/php/CustomRulesTest.java
rename to its/plugin/src/integrationTest/java/com/sonar/it/php/CustomRulesTest.java
diff --git a/its/plugin/tests/src/integrationTest/java/com/sonar/it/php/FrameworkDetectionPHPTest.java b/its/plugin/src/integrationTest/java/com/sonar/it/php/FrameworkDetectionPHPTest.java
similarity index 100%
rename from its/plugin/tests/src/integrationTest/java/com/sonar/it/php/FrameworkDetectionPHPTest.java
rename to its/plugin/src/integrationTest/java/com/sonar/it/php/FrameworkDetectionPHPTest.java
diff --git a/its/plugin/tests/src/integrationTest/java/com/sonar/it/php/NoSonarTest.java b/its/plugin/src/integrationTest/java/com/sonar/it/php/NoSonarTest.java
similarity index 100%
rename from its/plugin/tests/src/integrationTest/java/com/sonar/it/php/NoSonarTest.java
rename to its/plugin/src/integrationTest/java/com/sonar/it/php/NoSonarTest.java
diff --git a/its/plugin/tests/src/integrationTest/java/com/sonar/it/php/NonPhpProjectTest.java b/its/plugin/src/integrationTest/java/com/sonar/it/php/NonPhpProjectTest.java
similarity index 100%
rename from its/plugin/tests/src/integrationTest/java/com/sonar/it/php/NonPhpProjectTest.java
rename to its/plugin/src/integrationTest/java/com/sonar/it/php/NonPhpProjectTest.java
diff --git a/its/plugin/tests/src/integrationTest/java/com/sonar/it/php/PHPIntegrationTest.java b/its/plugin/src/integrationTest/java/com/sonar/it/php/PHPIntegrationTest.java
similarity index 100%
rename from its/plugin/tests/src/integrationTest/java/com/sonar/it/php/PHPIntegrationTest.java
rename to its/plugin/src/integrationTest/java/com/sonar/it/php/PHPIntegrationTest.java
diff --git a/its/plugin/tests/src/integrationTest/java/com/sonar/it/php/PHPTest.java b/its/plugin/src/integrationTest/java/com/sonar/it/php/PHPTest.java
similarity index 100%
rename from its/plugin/tests/src/integrationTest/java/com/sonar/it/php/PHPTest.java
rename to its/plugin/src/integrationTest/java/com/sonar/it/php/PHPTest.java
diff --git a/its/plugin/tests/src/integrationTest/java/com/sonar/it/php/PHPUnitTest.java b/its/plugin/src/integrationTest/java/com/sonar/it/php/PHPUnitTest.java
similarity index 100%
rename from its/plugin/tests/src/integrationTest/java/com/sonar/it/php/PHPUnitTest.java
rename to its/plugin/src/integrationTest/java/com/sonar/it/php/PHPUnitTest.java
diff --git a/its/plugin/tests/src/integrationTest/java/com/sonar/it/php/PhpStanReportTest.java b/its/plugin/src/integrationTest/java/com/sonar/it/php/PhpStanReportTest.java
similarity index 100%
rename from its/plugin/tests/src/integrationTest/java/com/sonar/it/php/PhpStanReportTest.java
rename to its/plugin/src/integrationTest/java/com/sonar/it/php/PhpStanReportTest.java
diff --git a/its/plugin/tests/src/integrationTest/java/com/sonar/it/php/PsalmReportTest.java b/its/plugin/src/integrationTest/java/com/sonar/it/php/PsalmReportTest.java
similarity index 100%
rename from its/plugin/tests/src/integrationTest/java/com/sonar/it/php/PsalmReportTest.java
rename to its/plugin/src/integrationTest/java/com/sonar/it/php/PsalmReportTest.java
diff --git a/its/plugin/src/integrationTest/java/com/sonar/it/php/SonarLintTest.java b/its/plugin/src/integrationTest/java/com/sonar/it/php/SonarLintTest.java
new file mode 100644
index 000000000..544d1d170
--- /dev/null
+++ b/its/plugin/src/integrationTest/java/com/sonar/it/php/SonarLintTest.java
@@ -0,0 +1,182 @@
+/*
+ * SonarQube PHP Plugin
+ * Copyright (C) 2010-2024 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package com.sonar.it.php;
+
+import com.sonar.it.php.utils.MockSonarLintRpcClientDelegate;
+import com.sonar.it.php.utils.SonarLintUtils;
+import java.io.IOException;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.time.Duration;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.stream.Stream;
+import org.awaitility.Awaitility;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.io.TempDir;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.sonarsource.sonarlint.core.rpc.client.ClientJsonRpcLauncher;
+import org.sonarsource.sonarlint.core.rpc.client.SonarLintRpcClientDelegate;
+import org.sonarsource.sonarlint.core.rpc.impl.BackendJsonRpcLauncher;
+import org.sonarsource.sonarlint.core.rpc.protocol.SonarLintRpcServer;
+import org.sonarsource.sonarlint.core.rpc.protocol.backend.analysis.AnalyzeFilesParams;
+import org.sonarsource.sonarlint.core.rpc.protocol.backend.analysis.AnalyzeFilesResponse;
+import org.sonarsource.sonarlint.core.rpc.protocol.backend.file.DidUpdateFileSystemParams;
+import org.sonarsource.sonarlint.core.rpc.protocol.backend.initialize.HttpConfigurationDto;
+import org.sonarsource.sonarlint.core.rpc.protocol.backend.initialize.InitializeParams;
+import org.sonarsource.sonarlint.core.rpc.protocol.common.ClientFileDto;
+import org.sonarsource.sonarlint.core.serverconnection.FileUtils;
+
+import static com.sonar.it.php.utils.SonarLintUtils.ENABLED_LANGUAGES;
+import static com.sonar.it.php.utils.SonarLintUtils.IT_CLIENT_INFO;
+import static com.sonar.it.php.utils.SonarLintUtils.IT_TELEMETRY_ATTRIBUTES;
+import static com.sonar.it.php.utils.SonarLintUtils.toMap;
+import static java.util.Collections.emptyList;
+import static java.util.Collections.emptyMap;
+import static java.util.Collections.emptySet;
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Inspiration:
+ * sonarlint-core StandaloneTests.java
+ */
+public class SonarLintTest {
+ public static final Path BASE_DIR = Paths.get("projects/sonarlint");
+ private static final String CONFIG_SCOPE_ID = "my-ide-project-name";
+
+ @TempDir
+ private static Path sonarUserHome;
+
+ private static SonarLintRpcServer backend;
+ private static SonarLintRpcClientDelegate client;
+
+ @BeforeAll
+ static void prepare() throws IOException, ExecutionException, InterruptedException {
+ startBackend();
+ }
+
+ @AfterEach
+ void reset() {
+ ((MockSonarLintRpcClientDelegate) client).getRaisedIssues().clear();
+ }
+
+ @AfterAll
+ static void cleanup() throws InterruptedException, ExecutionException, TimeoutException {
+ backend.shutdown().get(1_000, TimeUnit.MILLISECONDS);
+ FileUtils.deleteRecursively(sonarUserHome);
+ }
+
+ private static SonarLintRpcClientDelegate newMockSonarLintClient() {
+ return new MockSonarLintRpcClientDelegate();
+ }
+
+ @ParameterizedTest
+ @MethodSource
+ void shouldRaiseIssue(Path inputFile) {
+ var analyzeResponse = analyzeFile(CONFIG_SCOPE_ID, inputFile);
+
+ assertThat(analyzeResponse.getFailedAnalysisFiles()).isEmpty();
+ // it could happen that the notification is not yet received while the analysis request is finished.
+ Awaitility.await().atMost(Duration.ofMillis(200)).untilAsserted(
+ () -> assertThat(((MockSonarLintRpcClientDelegate) client).getRaisedIssues(CONFIG_SCOPE_ID)).hasSize(3));
+ }
+
+ static List shouldRaiseIssue() {
+ return provideTestFiles();
+ }
+
+ private static List provideTestFiles() {
+ List testFiles;
+
+ try (Stream pathStream = Files.list(BASE_DIR)) {
+ testFiles = pathStream
+ .map(Path::getFileName)
+ .map(BASE_DIR::resolve)
+ .toList();
+ } catch (IOException e) {
+ throw new AssertionError("Can not load test files from " + BASE_DIR, e);
+ }
+
+ if (testFiles.isEmpty()) {
+ throw new AssertionError("There are no test files provided");
+ }
+
+ return testFiles;
+ }
+
+ private static AnalyzeFilesResponse analyzeFile(String configScopeId, Path filePath, String... properties) {
+ var fileUri = filePath.toUri();
+ backend.getFileService().didUpdateFileSystem(
+ new DidUpdateFileSystemParams(List.of(), List.of(
+ new ClientFileDto(fileUri, filePath, configScopeId, false, null, filePath.toAbsolutePath(), null, null, true))));
+
+ return backend.getAnalysisService().analyzeFiles(
+ new AnalyzeFilesParams(configScopeId, UUID.randomUUID(), List.of(fileUri), toMap(properties), System.currentTimeMillis()))
+ .join();
+ }
+
+ static void startBackend() throws IOException, ExecutionException, InterruptedException {
+ var clientToServerOutputStream = new PipedOutputStream();
+ var clientToServerInputStream = new PipedInputStream(clientToServerOutputStream);
+
+ var serverToClientOutputStream = new PipedOutputStream();
+ var serverToClientInputStream = new PipedInputStream(serverToClientOutputStream);
+ client = newMockSonarLintClient();
+ new BackendJsonRpcLauncher(clientToServerInputStream, serverToClientOutputStream);
+ var clientLauncher = new ClientJsonRpcLauncher(serverToClientInputStream, clientToServerOutputStream, client);
+ backend = clientLauncher.getServerProxy();
+
+ var featureFlags = SonarLintUtils.featureFlagsForStandaloneMode();
+ backend.initialize(
+ new InitializeParams(
+ IT_CLIENT_INFO,
+ IT_TELEMETRY_ATTRIBUTES,
+ HttpConfigurationDto.defaultConfig(),
+ null,
+ featureFlags,
+ sonarUserHome.resolve("storage"),
+ sonarUserHome.resolve("work"),
+ Set.of(Tests.PHP_PLUGIN_LOCATION.getFile().toPath()),
+ emptyMap(),
+ ENABLED_LANGUAGES,
+ emptySet(),
+ emptySet(),
+ emptyList(),
+ emptyList(),
+ sonarUserHome.toString(),
+ Map.of(),
+ false,
+ null,
+ false,
+ null))
+ .get();
+ }
+}
diff --git a/its/plugin/tests/src/integrationTest/java/com/sonar/it/php/SuppressWarningsTest.java b/its/plugin/src/integrationTest/java/com/sonar/it/php/SuppressWarningsTest.java
similarity index 100%
rename from its/plugin/tests/src/integrationTest/java/com/sonar/it/php/SuppressWarningsTest.java
rename to its/plugin/src/integrationTest/java/com/sonar/it/php/SuppressWarningsTest.java
diff --git a/its/plugin/tests/src/integrationTest/java/com/sonar/it/php/Tests.java b/its/plugin/src/integrationTest/java/com/sonar/it/php/Tests.java
similarity index 96%
rename from its/plugin/tests/src/integrationTest/java/com/sonar/it/php/Tests.java
rename to its/plugin/src/integrationTest/java/com/sonar/it/php/Tests.java
index 1e4fb210f..741377f7e 100644
--- a/its/plugin/tests/src/integrationTest/java/com/sonar/it/php/Tests.java
+++ b/its/plugin/src/integrationTest/java/com/sonar/it/php/Tests.java
@@ -59,7 +59,7 @@ class Tests {
public static final String PHP_INI_SENSOR_NAME = "Analyzer for \"php.ini\" files";
- public static final FileLocation PHP_PLUGIN_LOCATION = FileLocation.byWildcardFilename(new File("../../../sonar-php-plugin/build/libs"), "sonar-php-plugin-*-all.jar");
+ public static final FileLocation PHP_PLUGIN_LOCATION = FileLocation.byWildcardFilename(new File("../../sonar-php-plugin/build/libs"), "sonar-php-plugin-*-all.jar");
public static final String SCANNER_VERSION = "6.1.0.4477";
private static final Pattern DEBUG_AND_INFO_LOG_LINE_PATTERN = Pattern.compile("\\d{2}:\\d{2}:\\d{2}\\.\\d{3}\\s(INFO|DEBUG)\\s.*");
@@ -74,7 +74,7 @@ class Tests {
.restoreProfileAtStartup(FileLocation.ofClasspath(RESOURCE_DIRECTORY + "drupal_profile.xml"))
.restoreProfileAtStartup(FileLocation.ofClasspath(RESOURCE_DIRECTORY + "no_rules.xml"))
// Custom rules plugin
- .addPlugin(FileLocation.byWildcardFilename(new File("../../../php-custom-rules-plugin/build/libs"), "php-custom-rules-plugin-*-all.jar"))
+ .addPlugin(FileLocation.byWildcardFilename(new File("../../php-custom-rules-plugin/build/libs"), "php-custom-rules-plugin-*-all.jar"))
.restoreProfileAtStartup(FileLocation.ofClasspath(RESOURCE_DIRECTORY + "profile-php-custom-rules.xml"))
.restoreProfileAtStartup(FileLocation.ofClasspath(RESOURCE_DIRECTORY + "nosonar.xml"))
.restoreProfileAtStartup(FileLocation.ofClasspath(RESOURCE_DIRECTORY + "sleep.xml"))
@@ -125,8 +125,8 @@ static Double getMeasureAsDouble(String componentKey, String metricKey) {
@CheckForNull
static Components.Component getComponent(String projectKey, String componentKey) {
List components = newWsClient().components().tree(new TreeRequest()
- .setComponent(projectKey)
- .setQ(componentKey))
+ .setComponent(projectKey)
+ .setQ(componentKey))
.getComponentsList();
return components.size() == 1 ? components.get(0) : null;
}
diff --git a/its/plugin/src/integrationTest/java/com/sonar/it/php/utils/MockSonarLintRpcClientDelegate.java b/its/plugin/src/integrationTest/java/com/sonar/it/php/utils/MockSonarLintRpcClientDelegate.java
new file mode 100644
index 000000000..b09d3639e
--- /dev/null
+++ b/its/plugin/src/integrationTest/java/com/sonar/it/php/utils/MockSonarLintRpcClientDelegate.java
@@ -0,0 +1,233 @@
+/*
+ * SonarQube PHP Plugin
+ * Copyright (C) 2010-2024 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package com.sonar.it.php.utils;
+
+import java.net.URI;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.CancellationException;
+import org.sonarsource.sonarlint.core.rpc.client.ConfigScopeNotFoundException;
+import org.sonarsource.sonarlint.core.rpc.client.ConnectionNotFoundException;
+import org.sonarsource.sonarlint.core.rpc.client.SonarLintCancelChecker;
+import org.sonarsource.sonarlint.core.rpc.client.SonarLintRpcClientDelegate;
+import org.sonarsource.sonarlint.core.rpc.protocol.backend.config.binding.BindingSuggestionDto;
+import org.sonarsource.sonarlint.core.rpc.protocol.backend.tracking.TaintVulnerabilityDto;
+import org.sonarsource.sonarlint.core.rpc.protocol.client.analysis.RawIssueDto;
+import org.sonarsource.sonarlint.core.rpc.protocol.client.binding.AssistBindingParams;
+import org.sonarsource.sonarlint.core.rpc.protocol.client.binding.AssistBindingResponse;
+import org.sonarsource.sonarlint.core.rpc.protocol.client.binding.NoBindingSuggestionFoundParams;
+import org.sonarsource.sonarlint.core.rpc.protocol.client.connection.AssistCreatingConnectionParams;
+import org.sonarsource.sonarlint.core.rpc.protocol.client.connection.AssistCreatingConnectionResponse;
+import org.sonarsource.sonarlint.core.rpc.protocol.client.connection.ConnectionSuggestionDto;
+import org.sonarsource.sonarlint.core.rpc.protocol.client.event.DidReceiveServerHotspotEvent;
+import org.sonarsource.sonarlint.core.rpc.protocol.client.fix.FixSuggestionDto;
+import org.sonarsource.sonarlint.core.rpc.protocol.client.hotspot.HotspotDetailsDto;
+import org.sonarsource.sonarlint.core.rpc.protocol.client.http.GetProxyPasswordAuthenticationResponse;
+import org.sonarsource.sonarlint.core.rpc.protocol.client.http.ProxyDto;
+import org.sonarsource.sonarlint.core.rpc.protocol.client.http.X509CertificateDto;
+import org.sonarsource.sonarlint.core.rpc.protocol.client.issue.IssueDetailsDto;
+import org.sonarsource.sonarlint.core.rpc.protocol.client.log.LogParams;
+import org.sonarsource.sonarlint.core.rpc.protocol.client.message.MessageType;
+import org.sonarsource.sonarlint.core.rpc.protocol.client.message.ShowSoonUnsupportedMessageParams;
+import org.sonarsource.sonarlint.core.rpc.protocol.client.progress.ReportProgressParams;
+import org.sonarsource.sonarlint.core.rpc.protocol.client.progress.StartProgressParams;
+import org.sonarsource.sonarlint.core.rpc.protocol.client.smartnotification.ShowSmartNotificationParams;
+import org.sonarsource.sonarlint.core.rpc.protocol.client.telemetry.TelemetryClientLiveAttributesResponse;
+import org.sonarsource.sonarlint.core.rpc.protocol.common.ClientFileDto;
+import org.sonarsource.sonarlint.core.rpc.protocol.common.Either;
+import org.sonarsource.sonarlint.core.rpc.protocol.common.TokenDto;
+import org.sonarsource.sonarlint.core.rpc.protocol.common.UsernamePasswordDto;
+
+/**
+ * Inspiration:
+ * sonarlint-core MockSonarLintRpcClientDelegate.java
+ */
+public class MockSonarLintRpcClientDelegate implements SonarLintRpcClientDelegate {
+ private final Map> raisedIssues = new HashMap<>();
+
+ public List getRaisedIssues(String configurationScopeId) {
+ var issues = raisedIssues.get(configurationScopeId);
+ return issues != null ? issues : List.of();
+ }
+
+ public Map> getRaisedIssues() {
+ return raisedIssues;
+ }
+
+ @Override
+ public void didRaiseIssue(String configurationScopeId, UUID analysisId, RawIssueDto rawIssue) {
+ raisedIssues.computeIfAbsent(configurationScopeId, k -> new ArrayList<>()).add(rawIssue);
+ }
+
+ @Override
+ public void suggestBinding(Map> suggestionsByConfigScope) {
+
+ }
+
+ @Override
+ public void suggestConnection(Map> suggestionsByConfigScope) {
+
+ }
+
+ @Override
+ public void openUrlInBrowser(URL url) {
+
+ }
+
+ @Override
+ public void showMessage(MessageType type, String text) {
+
+ }
+
+ @Override
+ public void log(LogParams params) {
+ System.out.println(params);
+ }
+
+ @Override
+ public void showSoonUnsupportedMessage(ShowSoonUnsupportedMessageParams params) {
+
+ }
+
+ @Override
+ public void showSmartNotification(ShowSmartNotificationParams params) {
+
+ }
+
+ @Override
+ public String getClientLiveDescription() {
+ return "";
+ }
+
+ @Override
+ public void showHotspot(String configurationScopeId, HotspotDetailsDto hotspotDetails) {
+
+ }
+
+ @Override
+ public void showIssue(String configurationScopeId, IssueDetailsDto issueDetails) {
+
+ }
+
+ @Override
+ public void showFixSuggestion(String configurationScopeId, String issueKey, FixSuggestionDto fixSuggestion) {
+
+ }
+
+ @Override
+ public AssistCreatingConnectionResponse assistCreatingConnection(AssistCreatingConnectionParams params, SonarLintCancelChecker cancelChecker) throws CancellationException {
+ throw new CancellationException("Unsupported in ITS");
+ }
+
+ @Override
+ public AssistBindingResponse assistBinding(AssistBindingParams params, SonarLintCancelChecker cancelChecker) throws CancellationException {
+ throw new CancellationException("Unsupported in ITS");
+ }
+
+ @Override
+ public void startProgress(StartProgressParams params) throws UnsupportedOperationException {
+
+ }
+
+ @Override
+ public void reportProgress(ReportProgressParams params) {
+
+ }
+
+ @Override
+ public void didSynchronizeConfigurationScopes(Set configurationScopeIds) {
+
+ }
+
+ @Override
+ public Either getCredentials(String connectionId) throws ConnectionNotFoundException {
+ throw new ConnectionNotFoundException();
+ }
+
+ @Override
+ public List selectProxies(URI uri) {
+ return List.of(ProxyDto.NO_PROXY);
+ }
+
+ @Override
+ public GetProxyPasswordAuthenticationResponse getProxyPasswordAuthentication(String host, int port, String protocol, String prompt, String scheme, URL targetHost) {
+ return new GetProxyPasswordAuthenticationResponse("", "");
+ }
+
+ @Override
+ public boolean checkServerTrusted(List chain, String authType) {
+ return false;
+ }
+
+ @Override
+ public void didReceiveServerHotspotEvent(DidReceiveServerHotspotEvent params) {
+
+ }
+
+ @Override
+ public String matchSonarProjectBranch(String configurationScopeId, String mainBranchName, Set allBranchesNames, SonarLintCancelChecker cancelChecker)
+ throws ConfigScopeNotFoundException {
+ return mainBranchName;
+ }
+
+ public boolean matchProjectBranch(String configurationScopeId, String branchNameToMatch, SonarLintCancelChecker cancelChecker) throws ConfigScopeNotFoundException {
+ return true;
+ }
+
+ @Override
+ public void didChangeMatchedSonarProjectBranch(String configScopeId, String newMatchedBranchName) {
+
+ }
+
+ @Override
+ public TelemetryClientLiveAttributesResponse getTelemetryLiveAttributes() {
+ System.err.println("Telemetry should be disabled in ITs");
+ throw new CancellationException("Telemetry should be disabled in ITs");
+ }
+
+ @Override
+ public void didChangeTaintVulnerabilities(String configurationScopeId, Set closedTaintVulnerabilityIds, List addedTaintVulnerabilities,
+ List updatedTaintVulnerabilities) {
+
+ }
+
+ @Override
+ public List listFiles(String configScopeId) {
+ return List.of();
+ }
+
+ @Override
+ public void noBindingSuggestionFound(NoBindingSuggestionFoundParams params) {
+ }
+
+ @Override
+ public void didChangeAnalysisReadiness(Set configurationScopeIds, boolean areReadyForAnalysis) {
+
+ }
+
+ public void clear() {
+ raisedIssues.clear();
+ }
+}
diff --git a/its/plugin/src/integrationTest/java/com/sonar/it/php/utils/SonarLintUtils.java b/its/plugin/src/integrationTest/java/com/sonar/it/php/utils/SonarLintUtils.java
new file mode 100644
index 000000000..5df8b2917
--- /dev/null
+++ b/its/plugin/src/integrationTest/java/com/sonar/it/php/utils/SonarLintUtils.java
@@ -0,0 +1,65 @@
+/*
+ * SonarQube PHP Plugin
+ * Copyright (C) 2010-2024 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package com.sonar.it.php.utils;
+
+import com.google.common.base.Preconditions;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import org.sonarsource.sonarlint.core.rpc.protocol.backend.initialize.ClientConstantInfoDto;
+import org.sonarsource.sonarlint.core.rpc.protocol.backend.initialize.FeatureFlagsDto;
+import org.sonarsource.sonarlint.core.rpc.protocol.backend.initialize.TelemetryClientConstantAttributesDto;
+import org.sonarsource.sonarlint.core.rpc.protocol.common.Language;
+
+import static java.util.Collections.emptyMap;
+
+public class SonarLintUtils {
+ public static final Set ENABLED_LANGUAGES = EnumSet.of(Language.PHP);
+ public static final ClientConstantInfoDto IT_CLIENT_INFO = new ClientConstantInfoDto("clientName", "integrationTests");
+ public static final TelemetryClientConstantAttributesDto IT_TELEMETRY_ATTRIBUTES = new TelemetryClientConstantAttributesDto(
+ "SonarLint ITs", "SonarLint ITs", "1.2.3", "4.5.6", emptyMap());
+
+ public static FeatureFlagsDto featureFlagsForStandaloneMode() {
+ return new FeatureFlagsDto(
+ true,
+ true,
+ true,
+ false,
+ true,
+ true,
+ false,
+ true,
+ false,
+ false);
+ }
+
+ public static Map toMap(String[] keyValues) {
+ Preconditions.checkArgument(keyValues.length % 2 == 0, "Must be an even number of key/values");
+ Map map = new HashMap<>();
+ var index = 0;
+ while (index < keyValues.length) {
+ var key = keyValues[index++];
+ var value = keyValues[index++];
+ map.put(key, value);
+ }
+ return map;
+ }
+}
diff --git a/its/plugin/tests/src/integrationTest/resources/com/sonar/it/php/drupal_profile.xml b/its/plugin/src/integrationTest/resources/com/sonar/it/php/drupal_profile.xml
similarity index 100%
rename from its/plugin/tests/src/integrationTest/resources/com/sonar/it/php/drupal_profile.xml
rename to its/plugin/src/integrationTest/resources/com/sonar/it/php/drupal_profile.xml
diff --git a/its/plugin/tests/src/integrationTest/resources/com/sonar/it/php/no_rules.xml b/its/plugin/src/integrationTest/resources/com/sonar/it/php/no_rules.xml
similarity index 100%
rename from its/plugin/tests/src/integrationTest/resources/com/sonar/it/php/no_rules.xml
rename to its/plugin/src/integrationTest/resources/com/sonar/it/php/no_rules.xml
diff --git a/its/plugin/tests/src/integrationTest/resources/com/sonar/it/php/nosonar.xml b/its/plugin/src/integrationTest/resources/com/sonar/it/php/nosonar.xml
similarity index 100%
rename from its/plugin/tests/src/integrationTest/resources/com/sonar/it/php/nosonar.xml
rename to its/plugin/src/integrationTest/resources/com/sonar/it/php/nosonar.xml
diff --git a/its/plugin/tests/src/integrationTest/resources/com/sonar/it/php/profile-php-custom-rules.xml b/its/plugin/src/integrationTest/resources/com/sonar/it/php/profile-php-custom-rules.xml
similarity index 100%
rename from its/plugin/tests/src/integrationTest/resources/com/sonar/it/php/profile-php-custom-rules.xml
rename to its/plugin/src/integrationTest/resources/com/sonar/it/php/profile-php-custom-rules.xml
diff --git a/its/plugin/tests/src/integrationTest/resources/com/sonar/it/php/profile.xml b/its/plugin/src/integrationTest/resources/com/sonar/it/php/profile.xml
similarity index 100%
rename from its/plugin/tests/src/integrationTest/resources/com/sonar/it/php/profile.xml
rename to its/plugin/src/integrationTest/resources/com/sonar/it/php/profile.xml
diff --git a/its/plugin/tests/src/integrationTest/resources/com/sonar/it/php/sleep.xml b/its/plugin/src/integrationTest/resources/com/sonar/it/php/sleep.xml
similarity index 100%
rename from its/plugin/tests/src/integrationTest/resources/com/sonar/it/php/sleep.xml
rename to its/plugin/src/integrationTest/resources/com/sonar/it/php/sleep.xml
diff --git a/its/plugin/tests/src/integrationTest/java/com/sonar/it/php/SonarLintTest.java b/its/plugin/tests/src/integrationTest/java/com/sonar/it/php/SonarLintTest.java
deleted file mode 100644
index 256810421..000000000
--- a/its/plugin/tests/src/integrationTest/java/com/sonar/it/php/SonarLintTest.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * SonarQube PHP Plugin
- * Copyright (C) 2010-2024 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package com.sonar.it.php;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URI;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.List;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.io.TempDir;
-import org.sonarsource.sonarlint.core.StandaloneSonarLintEngineImpl;
-import org.sonarsource.sonarlint.core.analysis.api.ClientInputFile;
-import org.sonarsource.sonarlint.core.client.api.common.analysis.Issue;
-import org.sonarsource.sonarlint.core.client.api.standalone.StandaloneAnalysisConfiguration;
-import org.sonarsource.sonarlint.core.client.api.standalone.StandaloneGlobalConfiguration;
-import org.sonarsource.sonarlint.core.client.api.standalone.StandaloneSonarLintEngine;
-import org.sonarsource.sonarlint.core.commons.Language;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-class SonarLintTest {
-
- @TempDir
- public static File tempDirectory;
-
- private static StandaloneSonarLintEngine sonarlintEngine;
-
- private static Path baseDir;
-
- @BeforeAll
- static void prepare() {
- StandaloneGlobalConfiguration sonarLintConfig = StandaloneGlobalConfiguration.builder()
- .addPlugin(Tests.PHP_PLUGIN_LOCATION.getFile().toPath())
- .addEnabledLanguage(Language.PHP)
- .setSonarLintUserHome(tempDirectory.toPath())
- .setLogOutput((formattedMessage, level) -> {
- /* Don't pollute logs */
- })
- .build();
- sonarlintEngine = new StandaloneSonarLintEngineImpl(sonarLintConfig);
- baseDir = tempDirectory.toPath();
- }
-
- @AfterAll
- static void stop() {
- sonarlintEngine.stop();
- }
-
- @Test
- void shouldRaiseIssues() throws IOException {
- Path filePath = Tests.projectDirectoryFor("sonarlint").toPath().resolve("Math.php");
- filePath = Files.copy(filePath, baseDir.resolve("Math.php"));
- ClientInputFile inputFile = prepareInputFile(filePath, false);
-
- List issues = new ArrayList<>();
- StandaloneAnalysisConfiguration configuration = StandaloneAnalysisConfiguration.builder()
- .setBaseDir(baseDir)
- .addInputFile(inputFile)
- .build();
- sonarlintEngine.analyze(configuration, issues::add, null, null);
-
- assertThat(issues).hasSize(3);
- }
-
- private ClientInputFile prepareInputFile(Path filePath, final boolean isTest) {
- return createInputFile(filePath, isTest);
- }
-
- private ClientInputFile createInputFile(final Path path, final boolean isTest) {
- return new ClientInputFile() {
-
- @Override
- public String getPath() {
- return path.toString();
- }
-
- @Override
- public boolean isTest() {
- return isTest;
- }
-
- @Override
- public Charset getCharset() {
- return StandardCharsets.UTF_8;
- }
-
- @Override
- public G getClientObject() {
- return null;
- }
-
- @Override
- public String contents() throws IOException {
- return new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
- }
-
- @Override
- public String relativePath() {
- return path.toString();
- }
-
- @Override
- public URI uri() {
- return path.toUri();
- }
-
- @Override
- public InputStream inputStream() throws IOException {
- return Files.newInputStream(path);
- }
-
- };
- }
-
-}
diff --git a/settings.gradle.kts b/settings.gradle.kts
index f19d56e52..618efa2bb 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -35,7 +35,7 @@ include(":sonar-php-plugin")
include(":php-frontend")
include(":php-checks")
include(":php-custom-rules-plugin")
-include(":its:plugin:tests")
+include(":its:plugin")
include(":its:ruling")
gradle.allprojects {