diff --git a/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/JUnitParameterizedMethodDeclaration.java b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/JUnitParameterizedMethodDeclaration.java new file mode 100644 index 00000000000..4ba2eec526b --- /dev/null +++ b/error-prone-contrib/src/main/java/tech/picnic/errorprone/bugpatterns/JUnitParameterizedMethodDeclaration.java @@ -0,0 +1,48 @@ +package tech.picnic.errorprone.bugpatterns; + +import static com.google.errorprone.BugPattern.LinkType.CUSTOM; +import static com.google.errorprone.BugPattern.SeverityLevel.SUGGESTION; +import static com.google.errorprone.BugPattern.StandardTags.SIMPLIFICATION; +import static com.google.errorprone.matchers.ChildMultiMatcher.MatchType.AT_LEAST_ONE; +import static com.google.errorprone.matchers.Matchers.annotations; +import static com.google.errorprone.matchers.Matchers.isType; +import static tech.picnic.errorprone.bugpatterns.util.Documentation.BUG_PATTERNS_BASE_URL; + +import com.google.auto.service.AutoService; +import com.google.errorprone.BugPattern; +import com.google.errorprone.VisitorState; +import com.google.errorprone.bugpatterns.BugChecker; +import com.google.errorprone.bugpatterns.BugChecker.MethodTreeMatcher; +import com.google.errorprone.matchers.Description; +import com.google.errorprone.matchers.Matcher; +import com.sun.source.tree.MethodTree; + +/** + * A {@link BugChecker} that flags test methods using {@link + * org.junit.jupiter.params.ParameterizedTest} without actually having any arguments. + */ +@AutoService(BugChecker.class) +@BugPattern( + summary = "JUnit parameterized test used without arguments", + link = BUG_PATTERNS_BASE_URL + "JUnitParameterizedMethodDeclaration", + linkType = CUSTOM, + severity = SUGGESTION, + tags = SIMPLIFICATION) +public final class JUnitParameterizedMethodDeclaration extends BugChecker + implements MethodTreeMatcher { + private static final long serialVersionUID = 1L; + private static final Matcher IS_PARAMETERIZED_TEST = + annotations(AT_LEAST_ONE, isType("org.junit.jupiter.params.ParameterizedTest")); + + /** Instantiates a new {@link JUnitParameterizedMethodDeclaration} instance. */ + public JUnitParameterizedMethodDeclaration() {} + + @Override + public Description matchMethod(MethodTree tree, VisitorState state) { + if (IS_PARAMETERIZED_TEST.matches(tree, state) && tree.getParameters().isEmpty()) { + return describeMatch(tree); + } + + return Description.NO_MATCH; + } +} diff --git a/error-prone-contrib/src/test/java/tech/picnic/errorprone/bugpatterns/JUnitParameterizedMethodDeclarationTest.java b/error-prone-contrib/src/test/java/tech/picnic/errorprone/bugpatterns/JUnitParameterizedMethodDeclarationTest.java new file mode 100644 index 00000000000..96ac816dc88 --- /dev/null +++ b/error-prone-contrib/src/test/java/tech/picnic/errorprone/bugpatterns/JUnitParameterizedMethodDeclarationTest.java @@ -0,0 +1,40 @@ +package tech.picnic.errorprone.bugpatterns; + +import com.google.errorprone.CompilationTestHelper; +import org.junit.jupiter.api.Test; + +final class JUnitParameterizedMethodDeclarationTest { + @Test + void identification() { + CompilationTestHelper.newInstance(JUnitParameterizedMethodDeclaration.class, getClass()) + .addSourceLines( + "A.java", + "import org.junit.jupiter.api.AfterAll;", + "import org.junit.jupiter.api.AfterEach;", + "import org.junit.jupiter.api.BeforeAll;", + "import org.junit.jupiter.api.BeforeEach;", + "import org.junit.jupiter.api.Test;", + "import org.junit.jupiter.params.ParameterizedTest;", + "", + "class A {", + " @Test", + " void test() {}", + "", + " @ParameterizedTest", + " // BUG: Diagnostic contains:", + " void badParameterizedTest() {}", + "", + " @ParameterizedTest", + " void goodParameterizedTest(Object someArgument) {}", + "", + " @BeforeEach", + " @BeforeAll", + " @AfterEach", + " @AfterAll", + " void nonTestMethod1() {}", + "", + " void nonTestMethod2() {}", + "}") + .doTest(); + } +}