-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Christoph Knoedlseder
committed
Sep 24, 2024
1 parent
d2d81b0
commit 80b4990
Showing
12 changed files
with
455 additions
and
0 deletions.
There are no files selected for viewing
56 changes: 56 additions & 0 deletions
56
src/main/java/de/jsilbereisen/perfumator/engine/detector/perfume/AssertAllDetector.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package de.jsilbereisen.perfumator.engine.detector.perfume; | ||
|
||
import com.github.javaparser.ast.CompilationUnit; | ||
import com.github.javaparser.ast.expr.MethodCallExpr; | ||
import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; | ||
import de.jsilbereisen.perfumator.engine.detector.Detector; | ||
import de.jsilbereisen.perfumator.engine.visitor.MethodCallByNameVisitor; | ||
import de.jsilbereisen.perfumator.model.DetectedInstance; | ||
import de.jsilbereisen.perfumator.model.perfume.Perfume; | ||
import lombok.EqualsAndHashCode; | ||
import org.jetbrains.annotations.NotNull; | ||
import org.jetbrains.annotations.Nullable; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
@EqualsAndHashCode | ||
public class AssertAllDetector implements Detector<Perfume> { | ||
|
||
private Perfume perfume; | ||
|
||
private JavaParserFacade analysisContext; | ||
|
||
private static final String ASSERT_ALL_METHOD_NAME = "assertAll"; | ||
|
||
@Override | ||
public @NotNull List<DetectedInstance<Perfume>> detect(@NotNull CompilationUnit astRoot) { | ||
List<DetectedInstance<Perfume>> detectedInstances = new ArrayList<>(); | ||
List<MethodCallExpr> assertAllMethodCallExpressions = getAssertAllMethodCalls(astRoot); | ||
assertAllMethodCallExpressions | ||
.forEach(callExpr -> detectedInstances.add(DetectedInstance.from(callExpr, perfume, astRoot))); | ||
return detectedInstances; | ||
} | ||
|
||
@Override | ||
public void setConcreteDetectable(@NotNull Perfume concreteDetectable) { | ||
this.perfume = concreteDetectable; | ||
} | ||
|
||
@Override | ||
public void setAnalysisContext(@Nullable JavaParserFacade analysisContext) { | ||
this.analysisContext = analysisContext; | ||
} | ||
|
||
private List<MethodCallExpr> getAssertAllMethodCalls(@NotNull CompilationUnit astRoot) { | ||
MethodCallByNameVisitor methodCallByNameVisitor = new MethodCallByNameVisitor(); | ||
astRoot.accept(methodCallByNameVisitor, null); | ||
List<MethodCallExpr> assertAllMethodCallExpressions = new ArrayList<>(); | ||
for (MethodCallExpr methodCallExpr : methodCallByNameVisitor.getMethodCalls()) { | ||
if (ASSERT_ALL_METHOD_NAME.equals(methodCallExpr.getNameAsString())) { | ||
assertAllMethodCallExpressions.add(methodCallExpr); | ||
} | ||
} | ||
return assertAllMethodCallExpressions; | ||
} | ||
} |
62 changes: 62 additions & 0 deletions
62
...in/java/de/jsilbereisen/perfumator/engine/detector/perfume/ParameterizedTestDetector.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package de.jsilbereisen.perfumator.engine.detector.perfume; | ||
|
||
import com.github.javaparser.ast.CompilationUnit; | ||
import com.github.javaparser.ast.body.MethodDeclaration; | ||
import com.github.javaparser.ast.expr.AnnotationExpr; | ||
import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; | ||
import de.jsilbereisen.perfumator.engine.detector.Detector; | ||
import de.jsilbereisen.perfumator.engine.visitor.MethodDeclarationVisitor; | ||
import de.jsilbereisen.perfumator.model.DetectedInstance; | ||
import de.jsilbereisen.perfumator.model.perfume.Perfume; | ||
import lombok.EqualsAndHashCode; | ||
import org.jetbrains.annotations.NotNull; | ||
import org.jetbrains.annotations.Nullable; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
@EqualsAndHashCode | ||
public class ParameterizedTestDetector implements Detector<Perfume> { | ||
|
||
private Perfume perfume; | ||
|
||
private JavaParserFacade analysisContext; | ||
|
||
private static final String PARAMETERIZED_TEST_IDENTIFIER = "ParameterizedTest"; | ||
|
||
@Override | ||
public @NotNull List<DetectedInstance<Perfume>> detect(@NotNull CompilationUnit astRoot) { | ||
List<DetectedInstance<Perfume>> detectedInstances = new ArrayList<>(); | ||
List<MethodDeclaration> parameterizedTestMethodDeclarations = getParameterizedTestMethodDeclarations(astRoot); | ||
parameterizedTestMethodDeclarations | ||
.forEach(declaration -> detectedInstances.add(DetectedInstance.from(declaration, perfume, astRoot))); | ||
return detectedInstances; | ||
} | ||
|
||
@Override | ||
public void setConcreteDetectable(@NotNull Perfume concreteDetectable) { | ||
perfume = concreteDetectable; | ||
} | ||
|
||
@Override | ||
public void setAnalysisContext(@Nullable JavaParserFacade analysisContext) { | ||
this.analysisContext = analysisContext; | ||
} | ||
|
||
private List<MethodDeclaration> getParameterizedTestMethodDeclarations(@NotNull CompilationUnit astRoot) { | ||
MethodDeclarationVisitor methodDeclarationVisitor = new MethodDeclarationVisitor(); | ||
astRoot.accept(methodDeclarationVisitor, null); | ||
List<MethodDeclaration> parameterizedTestMethodDeclarations = new ArrayList<>(); | ||
for (MethodDeclaration declaration : methodDeclarationVisitor.getMethodDeclarations()) { | ||
boolean hasParameterizedTestAnnotation = declaration.getAnnotations() | ||
.stream() | ||
.map(AnnotationExpr::getNameAsString) | ||
.anyMatch(id -> id.equals(PARAMETERIZED_TEST_IDENTIFIER)); | ||
|
||
if (hasParameterizedTestAnnotation) { | ||
parameterizedTestMethodDeclarations.add(declaration); | ||
} | ||
} | ||
return parameterizedTestMethodDeclarations; | ||
} | ||
} |
57 changes: 57 additions & 0 deletions
57
...va/de/jsilbereisen/perfumator/engine/detector/perfume/SetupAndTeardownMethodDetector.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package de.jsilbereisen.perfumator.engine.detector.perfume; | ||
|
||
import com.github.javaparser.ast.CompilationUnit; | ||
import com.github.javaparser.ast.body.MethodDeclaration; | ||
import com.github.javaparser.ast.expr.AnnotationExpr; | ||
import com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade; | ||
import de.jsilbereisen.perfumator.engine.detector.Detector; | ||
import de.jsilbereisen.perfumator.engine.visitor.MethodDeclarationVisitor; | ||
import de.jsilbereisen.perfumator.model.DetectedInstance; | ||
import de.jsilbereisen.perfumator.model.perfume.Perfume; | ||
import org.jetbrains.annotations.NotNull; | ||
import org.jetbrains.annotations.Nullable; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
public class SetupAndTeardownMethodDetector implements Detector<Perfume> { | ||
|
||
private Perfume perfume; | ||
|
||
private JavaParserFacade analysisContext; | ||
|
||
public static final List<String> TEST_ANNOTATIONS = List.of("BeforeAll", "BeforeEach", "AfterAll", "AfterEach"); | ||
|
||
@Override | ||
public @NotNull List<DetectedInstance<Perfume>> detect(@NotNull CompilationUnit astRoot) { | ||
List<DetectedInstance<Perfume>> detectedInstances = new ArrayList<>(); | ||
List<MethodDeclaration> setupAndTeardownMethods = getSetupAndTeardownMethodDeclarations(astRoot); | ||
setupAndTeardownMethods | ||
.forEach(declaration -> detectedInstances.add(DetectedInstance.from(declaration, perfume, astRoot))); | ||
return detectedInstances; | ||
} | ||
|
||
@Override | ||
public void setConcreteDetectable(@NotNull Perfume concreteDetectable) { | ||
this.perfume = concreteDetectable; | ||
} | ||
|
||
@Override | ||
public void setAnalysisContext(@Nullable JavaParserFacade analysisContext) { | ||
this.analysisContext = analysisContext; | ||
} | ||
|
||
private List<MethodDeclaration> getSetupAndTeardownMethodDeclarations(@NotNull CompilationUnit astRoot) { | ||
MethodDeclarationVisitor methodDeclarationVisitor = new MethodDeclarationVisitor(); | ||
astRoot.accept(methodDeclarationVisitor, null); | ||
List<MethodDeclaration> setupAndTeardownMethodDeclarations = new ArrayList<>(); | ||
for (MethodDeclaration declaration : methodDeclarationVisitor.getMethodDeclarations()) { | ||
for (AnnotationExpr annotation : declaration.getAnnotations()) { | ||
if (TEST_ANNOTATIONS.contains(annotation.getNameAsString())) { | ||
setupAndTeardownMethodDeclarations.add(declaration); | ||
} | ||
} | ||
} | ||
return setupAndTeardownMethodDeclarations; | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
src/main/resources/de/jsilbereisen/perfumator/data/perfumes/Assert_all.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"name": "Assert all", | ||
"description": "By using an assertAll instead of multiple assertThat expressions, the programmer is informed about all results, even though some assertions may fail. In contrast, a failing assertThat would terminate the test execution.", | ||
"detectorClassSimpleName": "AssertAllDetector", | ||
"i18nBaseBundleName": "assertAll", | ||
"sources": null, | ||
"relatedPattern": "SMELL", | ||
"additionalInformation": null | ||
} |
9 changes: 9 additions & 0 deletions
9
src/main/resources/de/jsilbereisen/perfumator/data/perfumes/Parameterized_test.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"name": "Parameterized test", | ||
"description": "Similar tests should be grouped in a single Parameterized test", | ||
"detectorClassSimpleName": "ParameterizedTestDetector", | ||
"i18nBaseBundleName": "parameterizedTests", | ||
"sources": ["https://rules.sonarsource.com/java/RSPEC-5976/"], | ||
"relatedPattern": "SMELL", | ||
"additionalInformation": null | ||
} |
9 changes: 9 additions & 0 deletions
9
src/main/resources/de/jsilbereisen/perfumator/data/perfumes/Setup_and_teardown_methods.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"name": "Setup or teardown method", | ||
"description": "Common setup and teardown tasks should preferably be performed inside methods annotated with either '@BeforeEach', '@BeforeAll', '@AfterEach' or '@AfterAll'. This can greatly reduce the boilerplate code inside individual tests.", | ||
"detectorClassSimpleName": "SetupAndTeardownMethodDetector", | ||
"i18nBaseBundleName": "setupAndTeardownMethod", | ||
"sources": null, | ||
"relatedPattern": "SMELL", | ||
"additionalInformation": null | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package detectors; | ||
|
||
import com.github.javaparser.ast.CompilationUnit; | ||
import de.jsilbereisen.perfumator.engine.detector.Detector; | ||
import de.jsilbereisen.perfumator.engine.detector.perfume.ParameterizedTestDetector; | ||
import de.jsilbereisen.perfumator.model.CodeRange; | ||
import de.jsilbereisen.perfumator.model.DetectedInstance; | ||
import de.jsilbereisen.perfumator.model.perfume.Perfume; | ||
import org.junit.jupiter.api.BeforeAll; | ||
import org.junit.jupiter.api.Test; | ||
import test.AbstractDetectorTest; | ||
|
||
import java.nio.file.Path; | ||
import java.util.List; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
public class AssertAllDetector extends AbstractDetectorTest { | ||
|
||
private static final Path TEST_FILE = DEFAULT_DETECTOR_TEST_FILES_DIR.resolve("ParameterizedTests.java"); | ||
|
||
private static Perfume perfume; | ||
|
||
private static Detector<Perfume> detector; | ||
|
||
private static CompilationUnit ast; | ||
|
||
@BeforeAll | ||
static void init() { | ||
perfume = new Perfume(); | ||
perfume.setName("Parameterized Test"); | ||
|
||
detector = new ParameterizedTestDetector(); | ||
detector.setConcreteDetectable(perfume); | ||
|
||
ast = parseAstForFile(TEST_FILE); | ||
} | ||
|
||
@Test | ||
void detect() { | ||
List<DetectedInstance<Perfume>> detections = detector.detect(ast); | ||
|
||
assertThat(detections).hasSize(1); | ||
|
||
DetectedInstance<Perfume> detection = detections.get(0); | ||
|
||
assertThat(detection.getDetectable()).isEqualTo(perfume); | ||
assertThat(detection.getTypeName()).isEqualTo("ParameterizedTests"); | ||
assertThat(detection.getCodeRanges()).containsExactly(CodeRange.of(21, 5, 25, 5)); | ||
} | ||
} |
51 changes: 51 additions & 0 deletions
51
src/test/java/detectors/ParameterizedTestDetectorTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package detectors; | ||
|
||
import com.github.javaparser.ast.CompilationUnit; | ||
import de.jsilbereisen.perfumator.engine.detector.Detector; | ||
import de.jsilbereisen.perfumator.engine.detector.perfume.AssertAllDetector; | ||
import de.jsilbereisen.perfumator.model.CodeRange; | ||
import de.jsilbereisen.perfumator.model.DetectedInstance; | ||
import de.jsilbereisen.perfumator.model.perfume.Perfume; | ||
import org.junit.jupiter.api.BeforeAll; | ||
import org.junit.jupiter.api.Test; | ||
import test.AbstractDetectorTest; | ||
|
||
import java.nio.file.Path; | ||
import java.util.List; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
class ParameterizedTestDetectorTest extends AbstractDetectorTest { | ||
|
||
private static final Path TEST_FILE = DEFAULT_DETECTOR_TEST_FILES_DIR.resolve("AssertAllPerfume.java"); | ||
|
||
private static Perfume perfume; | ||
|
||
private static Detector<Perfume> detector; | ||
|
||
private static CompilationUnit ast; | ||
|
||
@BeforeAll | ||
static void init() { | ||
perfume = new Perfume(); | ||
perfume.setName("Assert All"); | ||
|
||
detector = new AssertAllDetector(); | ||
detector.setConcreteDetectable(perfume); | ||
|
||
ast = parseAstForFile(TEST_FILE); | ||
} | ||
|
||
@Test | ||
void detect() { | ||
List<DetectedInstance<Perfume>> detections = detector.detect(ast); | ||
|
||
assertThat(detections).hasSize(1); | ||
|
||
DetectedInstance<Perfume> detection = detections.get(0); | ||
|
||
assertThat(detection.getDetectable()).isEqualTo(perfume); | ||
assertThat(detection.getTypeName()).isEqualTo("AssertAllPerfume"); | ||
assertThat(detection.getCodeRanges()).containsExactly(CodeRange.of(16, 9, 21, 9)); | ||
} | ||
} |
65 changes: 65 additions & 0 deletions
65
src/test/java/detectors/SetupAndTeardownMethodDetectorTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package detectors; | ||
|
||
import com.github.javaparser.ast.CompilationUnit; | ||
import de.jsilbereisen.perfumator.engine.detector.Detector; | ||
import de.jsilbereisen.perfumator.engine.detector.perfume.SetupAndTeardownMethodDetector; | ||
import de.jsilbereisen.perfumator.model.CodeRange; | ||
import de.jsilbereisen.perfumator.model.DetectedInstance; | ||
import de.jsilbereisen.perfumator.model.perfume.Perfume; | ||
import org.junit.jupiter.api.BeforeAll; | ||
import org.junit.jupiter.api.Test; | ||
import test.AbstractDetectorTest; | ||
|
||
import java.nio.file.Path; | ||
import java.util.List; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
public class SetupAndTeardownMethodDetectorTest extends AbstractDetectorTest { | ||
private static final Path TEST_FILE = | ||
DEFAULT_DETECTOR_TEST_FILES_DIR.resolve("SetupAndTeardownMethodPerfumes.java"); | ||
|
||
private static Perfume perfume; | ||
|
||
private static Detector<Perfume> detector; | ||
|
||
private static CompilationUnit ast; | ||
|
||
@BeforeAll | ||
static void init() { | ||
perfume = new Perfume(); | ||
perfume.setName("Setup or teardown method"); | ||
|
||
detector = new SetupAndTeardownMethodDetector(); | ||
detector.setConcreteDetectable(perfume); | ||
|
||
ast = parseAstForFile(TEST_FILE); | ||
} | ||
|
||
@Test | ||
void detect() { | ||
List<DetectedInstance<Perfume>> detections = detector.detect(ast); | ||
|
||
assertThat(detections).hasSize(4); | ||
|
||
DetectedInstance<Perfume> beforeAllDetection = detections.get(0); | ||
assertThat(beforeAllDetection.getDetectable()).isEqualTo(perfume); | ||
assertThat(beforeAllDetection.getTypeName()).isEqualTo("SetupAndTeardownMethodPerfumes"); | ||
assertThat(beforeAllDetection.getCodeRanges()).containsExactly(CodeRange.of(12, 5, 15, 5)); | ||
|
||
DetectedInstance<Perfume> beforeEachDetection = detections.get(1); | ||
assertThat(beforeEachDetection.getDetectable()).isEqualTo(perfume); | ||
assertThat(beforeEachDetection.getTypeName()).isEqualTo("SetupAndTeardownMethodPerfumes"); | ||
assertThat(beforeEachDetection.getCodeRanges()).containsExactly(CodeRange.of(17, 5, 20, 5)); | ||
|
||
DetectedInstance<Perfume> afterEachDetection = detections.get(2); | ||
assertThat(afterEachDetection.getDetectable()).isEqualTo(perfume); | ||
assertThat(afterEachDetection.getTypeName()).isEqualTo("SetupAndTeardownMethodPerfumes"); | ||
assertThat(afterEachDetection.getCodeRanges()).containsExactly(CodeRange.of(27, 5, 30, 5)); | ||
|
||
DetectedInstance<Perfume> afterAllDetection = detections.get(3); | ||
assertThat(afterAllDetection.getDetectable()).isEqualTo(perfume); | ||
assertThat(afterAllDetection.getTypeName()).isEqualTo("SetupAndTeardownMethodPerfumes"); | ||
assertThat(afterAllDetection.getCodeRanges()).containsExactly(CodeRange.of(32, 5, 35, 5)); | ||
} | ||
} |
Oops, something went wrong.