diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index ed2ec7999b..99c45731f2 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -43,6 +43,8 @@ This is useful to find duplicated sections in XML files. * [#2472](https://github.com/pmd/pmd/issues/2472): \[java] JavaCharStream throws an Error on invalid escape * java-bestpractices * [#2288](https://github.com/pmd/pmd/issues/2288): \[java] JUnitTestsShouldIncludeAssert: Add support for Hamcrest MatcherAssert.assertThat +* java-codestyle + * [#2476](https://github.com/pmd/pmd/pull/2476): \[java] MethodNamingConventions - Add support for JUnit 5 method naming * java-errorprone * [#2477](https://github.com/pmd/pmd/issues/2477): \[java] JUnitSpelling false-positive for JUnit5/4 tests * swift @@ -75,6 +77,7 @@ definitive API. * [#2465](https://github.com/pmd/pmd/pull/2465): \[dependencies] Upgrade hamcrest, mockito and JUnit - [Artem Krosheninnikov](https://github.com/KroArtem) * [#2469](https://github.com/pmd/pmd/pull/2469): \[apex] fix false positive unused variable if only a method is called - [Gwilym Kuiper](https://github.com/gwilymatgearset) * [#2475](https://github.com/pmd/pmd/pull/2475): \[swift] Swift 4.2-5.2 support - [kenji21](https://github.com/kenji21) +* [#2476](https://github.com/pmd/pmd/pull/2476): \[java] MethodNamingConventions - Add support for JUnit 5 method naming - [Bruno Ritz](https://github.com/birdflier) * [#2478](https://github.com/pmd/pmd/pull/2478): \[java] New rule: LiteralsFirstInComparisons - [John-Teng](https://github.com/John-Teng) * [#2479](https://github.com/pmd/pmd/pull/2479): \[java] False positive with Hamcrest's assertThat - [andreoss](https://github.com/andreoss) * [#2481](https://github.com/pmd/pmd/pull/2481): \[java] Fix JUnitSpellingRule false positive - [Artem Krosheninnikov](https://github.com/KroArtem) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/MethodNamingConventionsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/MethodNamingConventionsRule.java index b805a0cabc..bf1117150d 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/MethodNamingConventionsRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/MethodNamingConventionsRule.java @@ -35,6 +35,7 @@ public class MethodNamingConventionsRule extends AbstractNamingConventionRule nativeRegex = defaultProp("native").build(); private final PropertyDescriptor junit3Regex = defaultProp("JUnit 3 test").defaultValue("test[A-Z0-9][a-zA-Z0-9]*").build(); private final PropertyDescriptor junit4Regex = defaultProp("JUnit 4 test").build(); + private final PropertyDescriptor junit5Regex = defaultProp("JUnit 5 test").build(); public MethodNamingConventionsRule() { @@ -45,6 +46,11 @@ public class MethodNamingConventionsRule extends AbstractNamingConventionRule imports = n.getRoot().findChildrenOfType(ASTImportDeclaration.class); + for (ASTImportDeclaration importDecl : imports) { + if (n.hasImageEqualTo(importDecl.getImportedSimpleName())) { + // found the import, compare the full names + return clazzName.equals(importDecl.getImportedName()); + } + } + } + + // fall back on using the simple name of the class only if (clazzName.equals(n.getImage()) || clazzName.endsWith("." + n.getImage())) { return true; } diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/typeresolution/TypeHelperTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/typeresolution/TypeHelperTest.java index e0a744135d..d70f3f806a 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/typeresolution/TypeHelperTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/typeresolution/TypeHelperTest.java @@ -18,6 +18,8 @@ import org.junit.rules.ExpectedException; import net.sourceforge.pmd.lang.java.ast.ASTAnnotationTypeDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTMarkerAnnotation; +import net.sourceforge.pmd.lang.java.ast.ASTName; import net.sourceforge.pmd.lang.java.ast.TypeNode; import net.sourceforge.pmd.lang.java.symboltable.BaseNonParserTest; import net.sourceforge.pmd.lang.java.typeresolution.internal.NullableClassLoader; @@ -78,6 +80,24 @@ public class TypeHelperTest extends BaseNonParserTest { assertIsA(klass, Object.class); } + /** + * If we don't have the annotation on the classpath, + * we should resolve the full name via the import, if possible + * and compare then. Only after that, we should compare the + * simple names. + */ + @Test + public void testIsAFallbackAnnotationSimpleNameImport() { + ASTName annotation = java.parse("package org; import foo.Stuff; @Stuff public class FooBar {}") + .getFirstDescendantOfType(ASTMarkerAnnotation.class).getFirstChildOfType(ASTName.class); + + Assert.assertNull(annotation.getType()); + Assert.assertTrue(TypeHelper.isA(annotation, "foo.Stuff")); + Assert.assertFalse(TypeHelper.isA(annotation, "other.Stuff")); + // if the searched class name is not fully qualified, then the search should still be successfull + Assert.assertTrue(TypeHelper.isA(annotation, "Stuff")); + } + private void assertIsA(TypeNode node, Class type) { Assert.assertTrue("TypeHelper::isA with class arg: " + type.getCanonicalName(), TypeHelper.isA(node, type)); diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/MethodNamingConventions.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/MethodNamingConventions.xml index c494c196af..f5aa5bbd63 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/MethodNamingConventions.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/MethodNamingConventions.xml @@ -150,31 +150,83 @@ public class MethodNamingConventions implements SomeInterface { ]]> + JUnit 4 test detection [a-z][A-Za-z]*Test 2 - 12,16 + 8,12 The JUnit 4 test method name 'testGetBestTeam' doesn't match '[a-z][A-Za-z]*Test' The JUnit 4 test method name 'getBestTeam' doesn't match '[a-z][A-Za-z]*Test' + - @Test // note that this is also a junit 3 test, but the junit4 rule applies + + JUnit 4 test detection without proper auxclasspath + 1 + 8 + + The JUnit 4 test method name 'get_best_team' doesn't match '[a-z][a-zA-Z0-9]*' + + + + + + JUnit 5 test detection + [a-z][A-Za-z]*Test + 2 + 5,9 + + The JUnit 5 test method name 'testGetBestTeam' doesn't match '[a-z][A-Za-z]*Test' + The JUnit 5 test method name 'getBestTeam' doesn't match '[a-z][A-Za-z]*Test' + + + + + + false negative with apache commons logging + 1 + diff --git a/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTst.java b/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTst.java index 512eff922d..1c9529b0e5 100644 --- a/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTst.java +++ b/pmd-test/src/main/java/net/sourceforge/pmd/testframework/RuleTst.java @@ -274,6 +274,20 @@ public abstract class RuleTst { if (isUseAuxClasspath) { // configure the "auxclasspath" option for unit testing p.getConfiguration().prependClasspath("."); + } else { + // simple class loader, that doesn't delegate to parent. + // this allows us in the tests to simulate PMD run without + // auxclasspath, not even the classes from the test dependencies + // will be found. + p.getConfiguration().setClassLoader(new ClassLoader() { + @Override + protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + if (name.startsWith("java.") || name.startsWith("javax.")) { + return super.loadClass(name, resolve); + } + throw new ClassNotFoundException(name); + } + }); } RuleContext ctx = new RuleContext(); ctx.setReport(report);