Skip to content

Commit 105f9ed

Browse files
SONARJAVA-5973 Improve testkit tool to be able to use specific dependencies for tests (#5401)
1 parent ba48ab2 commit 105f9ed

8 files changed

Lines changed: 131 additions & 8 deletions

File tree

java-checks-test-sources/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
<execution>
5252
<id>copy</id>
5353
<phase>test-compile</phase>
54+
<inherited>false</inherited>
5455
<goals>
5556
<goal>copy</goal>
5657
</goals>

java-checks-test-sources/test-classpath-reader/src/main/java/org/sonar/java/test/classpath/TestClasspathUtils.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ public final class TestClasspathUtils {
4848
public static final Module JAVA_17_MODULE = new Module("java-checks-test-sources/java-17");
4949
public static final Module SPRING_32_MODULE = new Module("java-checks-test-sources/spring-3.2");
5050
public static final Module SPRING_WEB_40_MODULE = new Module("java-checks-test-sources/spring-web-4.0");
51+
private static final Path testJarsPath = Path.of("java-checks-test-sources/target/test-jars");
52+
53+
public static List<File> getTestJars(List<String> jars) {
54+
return jars.stream().map(name -> testJarsPath.resolve(name + ".jar").toFile()).toList();
55+
}
5156

5257
public static class Module {
5358
private final String relativePath;

java-checks-testkit/src/main/java/org/sonar/java/checks/verifier/CheckVerifier.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,31 @@ static CheckVerifier newInternalVerifier() {
129129
*/
130130
CheckVerifier withClassPath(Collection<File> classpath);
131131

132+
/**
133+
* Defines the libraries to add to the classpath.
134+
* Usually used when the code of the test files requires the knowledge of a particular set
135+
* of libraries or java compiled classes.
136+
* <p>
137+
* <strong>Note:</strong> The JAR files must be pre-downloaded using the {@code maven-dependency-plugin}
138+
* configured in {@code java-checks-test-sources/pom.xml}. The plugin's {@code copy} execution
139+
* (phase: {@code test-compile}) downloads dependencies to {@code target/test-jars} directory.
140+
* Add new dependencies as {@code artifactItem} entries in the plugin configuration.
141+
*
142+
* @param jarsToAdd a collection of jar names (without extensions) to add to the classpath
143+
* @return the verifier configured to use the dependencies provided as arguments to change the classpath
144+
*/
145+
CheckVerifier addJarsToClasspath(String... jarsToAdd);
146+
147+
/**
148+
* Defines the libraries to remove from the classpath.
149+
* Usually used when the code of the test files requires the knowledge of a particular set
150+
* of libraries or java compiled classes.
151+
*
152+
* @param jarsToRemove a collection of jar names (without extensions) to remove from the classpath
153+
* @return the verifier configured to use the dependencies provided as arguments to change the classpath
154+
*/
155+
CheckVerifier removeJarsFromClasspath(String... jarsToRemove);
156+
132157
/**
133158
* Defines the java version syntax to be used for the verification. Usually used when the code of the
134159
* test files explicitly target a given version (e.g. java 7) where a particular syntax/API has been introduced.

java-checks-testkit/src/main/java/org/sonar/java/checks/verifier/internal/InternalCheckVerifier.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,16 @@ public InternalCheckVerifier withClassPath(Collection<File> classpath) {
126126
return this;
127127
}
128128

129+
@Override
130+
public CheckVerifier addJarsToClasspath(String... jarsToAdd) {
131+
throw new UnsupportedOperationException("Not implemented!");
132+
}
133+
134+
@Override
135+
public CheckVerifier removeJarsFromClasspath(String... jarsToRemove) {
136+
throw new UnsupportedOperationException("Not implemented!");
137+
}
138+
129139
@Beta
130140
public InternalCheckVerifier withCustomIssueVerifier(Consumer<Set<AnalyzerMessage>> customIssueVerifier) {
131141
requiresNull(this.customIssueVerifier, "custom issue verifier");

java-checks-testkit/src/main/java/org/sonar/java/checks/verifier/internal/JavaCheckVerifier.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ public static JavaCheckVerifier newInstance() {
7878

7979
private List<JavaFileScanner> checks = null;
8080
private List<File> classpath = null;
81+
private List<String> jarsToAdd = new ArrayList<>();
82+
private List<String> jarsToRemove = new ArrayList<>();
83+
@VisibleForTesting
84+
List<File> actualClasspath = null;
8185
private JavaVersion javaVersion = null;
8286
private boolean inAndroidContext = false;
8387
private List<InputFile> files = null;
@@ -96,7 +100,6 @@ private MultiFileVerifier createVerifier() {
96100
MultiFileVerifier verifier = MultiFileVerifier.create(Paths.get(files.get(0).uri()), UTF_8);
97101

98102
JavaVersion actualVersion = javaVersion == null ? DEFAULT_JAVA_VERSION : javaVersion;
99-
List<File> actualClasspath = classpath == null ? TestClasspathUtils.DEFAULT_MODULE.getClassPath() : classpath;
100103

101104
List<JavaFileScanner> visitors = new ArrayList<>(checks);
102105
CommentLinesVisitor commentLinesVisitor = new CommentLinesVisitor();
@@ -107,6 +110,7 @@ private MultiFileVerifier createVerifier() {
107110
.withSonarComponents(sonarComponents)
108111
.withAndroidContext(inAndroidContext);
109112
if (!withoutSemantic) {
113+
setActualClasspath();
110114
visitorsBridgeBuilder.enableSemanticWithProjectClasspath(actualClasspath);
111115
}
112116

@@ -135,6 +139,13 @@ private MultiFileVerifier createVerifier() {
135139
return verifier;
136140
}
137141

142+
private void setActualClasspath() {
143+
List<File> newClasspath = classpath == null ? new ArrayList<>(TestClasspathUtils.DEFAULT_MODULE.getClassPath()) : classpath;
144+
jarsToRemove.forEach(f -> newClasspath.removeIf(file -> file.getName().contains(f)));
145+
newClasspath.addAll(TestClasspathUtils.getTestJars(jarsToAdd));
146+
actualClasspath = Collections.unmodifiableList(newClasspath);
147+
}
148+
138149
private static void addIssues(JavaFileScannerContextForTests scannerContext, MultiFileVerifier verifier) {
139150
scannerContext.getIssues().forEach(issue -> {
140151
if (!issue.getInputComponent().isFile()) {
@@ -232,6 +243,18 @@ public CheckVerifier withClassPath(Collection<File> classpath) {
232243
return this;
233244
}
234245

246+
@Override
247+
public CheckVerifier addJarsToClasspath(String... jarsToAdd) {
248+
this.jarsToAdd.addAll(Arrays.asList(jarsToAdd));
249+
return this;
250+
}
251+
252+
@Override
253+
public CheckVerifier removeJarsFromClasspath(String... jarsToRemove) {
254+
this.jarsToRemove.addAll(Arrays.asList(jarsToRemove));
255+
return this;
256+
}
257+
235258
@Override
236259
public CheckVerifier withJavaVersion(int javaVersionAsInt) {
237260
requiresNull(javaVersion, "java version");

java-checks-testkit/src/test/java/org/sonar/java/checks/verifier/internal/InternalCheckVerifierTest.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1067,4 +1067,32 @@ void compilationUnitModifier_not_supported() {
10671067
.hasMessage("Method not implemented, feel free to implement.");
10681068
}
10691069

1070+
@Test
1071+
void addJarsToClasspath_not_supported() {
1072+
InternalCheckVerifier checkVerifier = InternalCheckVerifier.newInstance()
1073+
.onFile(TEST_FILE);
1074+
1075+
Throwable e = catchThrowable(() -> {
1076+
checkVerifier.addJarsToClasspath("testng-7.5.1");
1077+
});
1078+
1079+
assertThat(e)
1080+
.isInstanceOf(UnsupportedOperationException.class)
1081+
.hasMessage("Not implemented!");
1082+
}
1083+
1084+
@Test
1085+
void removeJarsFromClasspath_not_supported() {
1086+
InternalCheckVerifier checkVerifier = InternalCheckVerifier.newInstance()
1087+
.onFile(TEST_FILE);
1088+
1089+
Throwable e = catchThrowable(() -> {
1090+
checkVerifier.removeJarsFromClasspath("testng-7.12.0");
1091+
});
1092+
1093+
assertThat(e)
1094+
.isInstanceOf(UnsupportedOperationException.class)
1095+
.hasMessage("Not implemented!");
1096+
}
1097+
10701098
}

java-checks-testkit/src/test/java/org/sonar/java/checks/verifier/internal/JavaCheckVerifierTest.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,4 +419,40 @@ void succeeding_check_on_both_files_should_make_verifier_succeed() {
419419
.onFiles(CheckVerifierTestUtils.TEST_FILE, CheckVerifierTestUtils.TEST_FILE_2)
420420
.verifyNoIssues());
421421
}
422+
423+
@Test
424+
void addJarsToClasspath_modifies_classpath() {
425+
JavaCheckVerifier dummyVerifier = JavaCheckVerifier.newInstance();
426+
dummyVerifier.withCheck(NO_EFFECT_CHECK)
427+
.onFile(TEST_FILE)
428+
.verifyNoIssues();
429+
int initialSize = dummyVerifier.actualClasspath.size();
430+
assertThat(dummyVerifier.actualClasspath.stream().map(File::getName)).noneMatch(n -> n.equals("testng-7.5.1.jar"));
431+
432+
dummyVerifier = JavaCheckVerifier.newInstance();
433+
dummyVerifier.addJarsToClasspath("testng-7.5.1");
434+
dummyVerifier.withCheck(NO_EFFECT_CHECK)
435+
.onFile(TEST_FILE)
436+
.verifyNoIssues();
437+
assertThat(dummyVerifier.actualClasspath).hasSize(initialSize + 1);
438+
assertThat(dummyVerifier.actualClasspath.stream().map(File::getName)).anyMatch(n -> n.equals("testng-7.5.1.jar"));
439+
}
440+
441+
@Test
442+
void removeJarsFromClasspath_modifies_classpath() {
443+
JavaCheckVerifier dummyVerifier = JavaCheckVerifier.newInstance();
444+
dummyVerifier.withCheck(NO_EFFECT_CHECK)
445+
.onFile(TEST_FILE)
446+
.verifyNoIssues();
447+
int initialSize = dummyVerifier.actualClasspath.size();
448+
assertThat(dummyVerifier.actualClasspath.stream().map(File::getName)).anyMatch(n -> n.equals("testng-7.12.0.jar"));
449+
450+
dummyVerifier = JavaCheckVerifier.newInstance();
451+
dummyVerifier.removeJarsFromClasspath("testng-7.12.0");
452+
dummyVerifier.withCheck(NO_EFFECT_CHECK)
453+
.onFile(TEST_FILE)
454+
.verifyNoIssues();
455+
assertThat(dummyVerifier.actualClasspath).hasSize(initialSize - 1);
456+
assertThat(dummyVerifier.actualClasspath.stream().map(File::getName)).noneMatch(n -> n.equals("testng-7.12.0.jar"));
457+
}
422458
}

java-checks/src/test/java/org/sonar/java/checks/tests/AssertionsWithoutMessageCheckTest.java

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,9 @@
1818

1919
import org.junit.jupiter.api.Test;
2020
import org.sonar.java.checks.verifier.CheckVerifier;
21-
import org.sonar.java.checks.verifier.FilesUtils;
2221
import org.sonar.java.test.classpath.TestClasspathUtils;
2322

2423
import java.io.File;
25-
import java.nio.file.Path;
2624
import java.util.ArrayList;
2725
import java.util.List;
2826

@@ -42,14 +40,11 @@ void test_Testng77() {
4240

4341
@Test
4442
void test_Testng75() {
45-
List<File> classPath = new ArrayList<>(TestClasspathUtils.DEFAULT_MODULE.getClassPath());
46-
classPath.removeIf(file -> file.getName().contains("testng"));
47-
List<File> list = FilesUtils.getFilesRecursively(Path.of("..", "java-checks-test-sources", "target/test-jars"), "jar");
48-
classPath.addAll(list);
4943
CheckVerifier.newVerifier()
5044
.onFile(testCodeSourcesPath("checks/tests/AssertionsWithoutMessageCheckSample_Testng75.java"))
5145
.withCheck(new AssertionsWithoutMessageCheck())
52-
.withClassPath(classPath)
46+
.addJarsToClasspath("testng-7.5.1")
47+
.removeJarsFromClasspath("testng-7.12.0")
5348
.verifyNoIssues();
5449
}
5550
}

0 commit comments

Comments
 (0)