Merge branch 'master' into new-properties-framework

This commit is contained in:
Clément Fournier
2018-11-16 02:29:33 +01:00
15 changed files with 335 additions and 80 deletions
+1 -1
View File
@@ -411,7 +411,7 @@ in a single method makes its behaviour hard to read and change.
Cyclomatic complexity assesses the complexity of a method by counting the number of decision points in a method,
plus one for the method entry. Decision points are places where the control flow jumps to another place in the
program. As such, they include all control flow statements, such as `if`, `while`, `for`, and `case`. For more
details on the calculation, see the documentation of the [Cyclo metric](/pmd_java_metrics_index.html#cyclomatic-complexity-cyclo).
details on the calculation, see the documentation of the [Cyclo metric](pmd_java_metrics_index.html#cyclomatic-complexity-cyclo).
Generally, numbers ranging from 1-4 denote low complexity, 5-7 denote moderate complexity, 8-10 denote
high complexity, and 11+ is very high complexity. By default, this rule reports methods with a complexity >= 10.
+38 -11
View File
@@ -20,40 +20,65 @@ This is a {{ site.pmd.release_type }} release.
verifies that numeric literals over a given length (4 chars by default, but configurable) are using
underscores every 3 digits for readability. The rule only applies to Java 7+ codebases.
#### Modified Rules
* The Java rule {% rule "java/bestpractices/JUnitTestsShouldIncludeAssert" %} (`java-bestpractices`)
now also detects [Soft Assertions](https://github.com/joel-costigliola/assertj-core).
### Fixed Issues
* all
* [#1284](https://github.com/pmd/pmd/issues/1284): \[doc] Keep record of every currently deprecated API
* all
* [#1318](https://github.com/pmd/pmd/issues/1318): \[test] Kotlin DSL to ease test writing
* [#1341](https://github.com/pmd/pmd/issues/1341): \[doc] Documentation Error with Regex Properties
* java
* [#1460](https://github.com/pmd/pmd/issues/1460): \[java] Intermittent PMD failure : PMD processing errors while no violations reported
* java-codestyle
* [#1232](https://github.com/pmd/pmd/issues/1232): \[java] Detector for large numbers not separated by _
* [#1372](https://github.com/pmd/pmd/issues/1372): \[java] false positive for UselessQualifiedThis
* [#1435](https://github.com/pmd/pmd/issues/1435): \[java] JUnitTestsShouldIncludeAssert: Support AssertJ soft assertions
### API Changes
* The implementation of the adapters for the XPath engines Saxon and Jaxen (package `net.sourceforge.pmd.lang.ast.xpath`)
are now deprecated. They'll be moved to an internal package come 7.0.0. Only `Attribute` remains public API.
#### Properties framework
The properties framework is about to get a lifting, and for that reason, the following APIs are
now deprecated until 7.0.0. The proposed changes to the API are described [on the wiki](https://github.com/pmd/pmd/wiki/Property-framework-7-0-0)
* Several classes and interfaces from the properties framework are now deprecated and will be removed with 7.0.0.
* MethodProperty, FloatProperty, FileProperty, TypeProperty and their multi-valued counterparts
* `MethodProperty`, `FloatProperty`, `FileProperty`, `TypeProperty` and their multi-valued counterparts
are discontinued for lack of a use-case, and will probably not be replaced with 7.0.0.
Users of FloatProperty should consider using a DoubleProperty.
* EnumeratedPropertyDescriptor, NumericPropertyDescriptor, PackagedPropertyDescriptor, and the related builders
(in net.sourceforge.pmd.properties.builders) will be removed. In the future, these interfaces won't be around
Users of `FloatProperty` should consider using a `DoubleProperty`.
* `EnumeratedPropertyDescriptor`, `NumericPropertyDescriptor`, `PackagedPropertyDescriptor`, and the related builders
(in `net.sourceforge.pmd.properties.builders`) will be removed. In the future, these interfaces won't be around
but their functionality will, under another form. The related methods `PropertyTypeId#isPropertyNumeric` and
`PropertyTypeId#isPropertyPackaged` are also deprecated.
* All classes of net.sourceforge.pmd.properties.modules are deprecated and will be removed. They were
never intended as public api.
* The classes PropertyDescriptorField, PropertyDescriptorBuilderConversionWrapper, and the methods
* The classes `PropertyDescriptorField`, `PropertyDescriptorBuilderConversionWrapper`, and the methods
`PropertyDescriptor#attributeValuesById`, `PropertyDescriptor#isDefinedExternally` and `PropertyTypeId#getFactory` are deprecated with no
intended replacement. These were used to read and write properties to and from XML, and were never
intended as public API.
* The class ValueParserConstants is deprecated with no intended replacement, it was not intended as
public API.
* The method `PropertyDescriptor#preferredRowCount` is deprecated with no intended replacement. It was
never implemented, and does not belong in this interface.
* The class `ValueParserConstants` and the interface `ValueParser` are deprecated with no intended replacement,
they were not intended as public API.
* Methods from `PropertyDescriptor`:
* `preferredRowCount` is deprecated with no intended replacement. It was never implemented, and does not belong
in this interface. The methods `uiOrder` and `compareTo` are deprecated for the same reason. These methods mix presentation logic
with business logic and are not necessary for PropertyDescriptors to work. `PropertyDescriptor` will not
extend `Comparable<PropertyDescriptor>` anymore come 7.0.0.
* The method `PropertyDescriptor#propertyErrorFor` is deprecated and will be removed with no intended
replacement. It's really just a shortcut for `prop.errorFor(rule.getProperty(prop))`.
* `T valueFrom(String)` and `String asDelimitedString(T)` are deprecated and will be removed. These were
used to serialize and deserialize properties to/from a string, but 7.0.0 will introduce a more flexible
XML syntax which will make them obsolete.
* `isMultiValue` and `type` are deprecated and won't be replaced. The new XML syntax will remove the need
for a divide between multi- and single-value properties, and will allow arbitrary types to be represented.
Since arbitrary types may be represented, `type` will become obsolete as it can't represent generic types,
which will nevertheless be representable with the XML syntax. It was only used for documentation, but a
new way to document these properties exhaustively will be added with 7.0.0.
* `errorFor` is deprecated as its return type will be changed to `Optional<String>` with the shift to Java 8.
### External Contributions
@@ -61,6 +86,8 @@ This is a {{ site.pmd.release_type }} release.
* [#1424](https://github.com/pmd/pmd/pull/1424): \[doc] #1341 Updating Regex Values in default Value Property - [avishvat](https://github.com/vishva007)
* [#1428](https://github.com/pmd/pmd/pull/1428): \[core] Upgrading JCommander from 1.48 to 1.72 - [Thunderforge](https://github.com/Thunderforge)
* [#1430](https://github.com/pmd/pmd/pull/1430): \[doc] Who really knows regex? - [Dem Pilafian](https://github.com/dpilafian)
* [#1434](https://github.com/pmd/pmd/pull/1434): \[java] JUnitTestsShouldIncludeAssert: Recognize AssertJ soft assertions as valid assert statements - [Loïc Ledoyen](https://github.com/ledoyen)
* [#1464](https://github.com/pmd/pmd/pull/1464): \[doc] Fix XSS on documentation web page - [Maxime Robert](https://github.com/marob)
{% endtocmaker %}
@@ -16,12 +16,6 @@ import net.sourceforge.pmd.annotation.InternalApi;
* any associated GUIs. While concrete descriptor instances are static and immutable they provide validation,
* serialization, and default values for any specific datatypes.
*
* <p>This interface is primarily specialized according to whether the property is multi-valued or single-valued, see
* {@link SingleValuePropertyDescriptor} and {@link MultiValuePropertyDescriptor}.
*
* <p>Several interfaces further specialize the behaviour of descriptors to accommodate specific types of descriptors,
* see {@link NumericPropertyDescriptor} and {@link EnumeratedPropertyDescriptor}.
*
* <h1>Upcoming API changes to the properties framework: see https://github.com/pmd/pmd/issues/1415</h1>
*
* @param <T> type of the property's value. This is a list type for multi-valued properties.
@@ -48,31 +42,6 @@ public interface PropertyDescriptor<T> extends Comparable<PropertyDescriptor<?>>
String description();
/**
* Denotes the value datatype. For multi value properties, this is not the List class but the list's component
* class.
*
* @return Class literal of the value type
*/
// TODO Type is used only to document the expected value format, but generic arguments are erased.
// This will become a problem when we remove the divide between multi-/single-value properties and
// let users make properties out of any type they want.
// We'll probably have to remove this method and find another solution to document the expected format.
Class<?> type();
/**
* Returns whether the property is multi-valued, i.e. an array of strings,
*
* <p>As unary property rule properties will return a value of one, you must use the get/setProperty accessors when
* working with the actual values. When working with multi-value properties then the get/setProperties accessors
* must be used.</p>
*
* @return boolean
*/
boolean isMultiValue();
/**
* Default value to use when the user hasn't specified one or when they wish to revert to a known-good state.
*
@@ -88,8 +57,39 @@ public interface PropertyDescriptor<T> extends Comparable<PropertyDescriptor<?>>
* @param value The value to check.
*
* @return A diagnostic message.
*
* @deprecated PMD 7.0.0 will change the return type to {@code Optional<String>}
*/
String errorFor(T value);
@Deprecated
String errorFor(T value); // TODO Java 1.8 make optional
/**
* Denotes the value datatype. For multi value properties, this is not the List class but the list's component
* class.
*
* @return Class literal of the value type
*
* @deprecated This method is mainly used for documentation, but will not prove general enough
* to support PMD 7.0.0's improved property types.
*/
@Deprecated
Class<?> type();
/**
* Returns whether the property is multi-valued, i.e. an array of strings,
*
* <p>As unary property rule properties will return a value of one, you must use the get/setProperty accessors when
* working with the actual values. When working with multi-value properties then the get/setProperties accessors
* must be used.</p>
*
* @return boolean
*
* @deprecated The hard divide between multi- and single-value properties will be removed with 7.0.0
*/
@Deprecated
boolean isMultiValue();
/**
@@ -97,24 +97,34 @@ public interface PropertyDescriptor<T> extends Comparable<PropertyDescriptor<?>>
* edit property values. If the value returned has a non-zero fractional part then this is can be used to place
* adjacent fields on the same row.
*
* <p>Example:<br> name -&gt; 0.0 description 1.0 minValue -&gt; 2.0 maxValue -&gt; 2.1 </p> ..would have their
* fields placed like:<br>
* @return The relative order compared to other properties of the same rule
*
* <code>name: [ ] description: [ ] minimum: [ ] maximum: [ ]</code>
*
* @return float
* @deprecated This method confuses the presentation layer and the business logic. The order of the
* property in a UI is irrelevant to the functioning of the property in PMD. With PMD 7.0.0, this
* method will be removed. UI and documentation tools will decide on their own convention.
*/
@Deprecated
float uiOrder();
/**
* @deprecated Comparing property descriptors is not useful within PMD
*/
@Deprecated
@Override
int compareTo(PropertyDescriptor<?> o);
/**
* Returns the value represented by this string.
*
* @param propertyString The string to parse
*
* @return The value represented by the string
* @throws IllegalArgumentException if the given string cannot be parsed
* @deprecated PMD 7.0.0 will use a more powerful scheme to represent values than
* simple strings, this method won't be general enough
*/
@Deprecated
T valueFrom(String propertyString) throws IllegalArgumentException;
@@ -124,7 +134,11 @@ public interface PropertyDescriptor<T> extends Comparable<PropertyDescriptor<?>>
* @param value Object
*
* @return String
*
* @deprecated PMD 7.0.0 will use a more powerful scheme to represent values than
* simple strings, this method won't be general enough
*/
@Deprecated
String asDelimitedString(T value);
@@ -134,8 +148,10 @@ public interface PropertyDescriptor<T> extends Comparable<PropertyDescriptor<?>>
*
* @param rule Rule
*
* @return String
* @deprecated Used nowhere, and fails if the rule doesn't define the property descriptor
* A better solution will be added on property source
*/
@Deprecated
String propertyErrorFor(Rule rule);
@@ -4,12 +4,17 @@
package net.sourceforge.pmd.properties;
import net.sourceforge.pmd.annotation.InternalApi;
/**
* Parses a value from a string.
*
* @param <U> The type of the value to parse
*/
// FUTURE @FunctionalInterface
@Deprecated
@InternalApi
public interface ValueParser<U> {
/**
@@ -63,8 +63,10 @@ public abstract class PropertyDescriptorBuilder<E, T extends PropertyDescriptorB
* @param f The UI order
*
* @return The same builder
* @deprecated See {@link PropertyDescriptor#uiOrder()}
*/
@SuppressWarnings("unchecked")
@Deprecated
public T uiOrder(float f) {
this.uiOrder = f;
return (T) this;
+5
View File
@@ -176,5 +176,10 @@
<artifactId>ant-testutil</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
@@ -20,6 +20,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
import net.sourceforge.pmd.lang.java.ast.ASTReferenceType;
import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression;
import net.sourceforge.pmd.lang.java.rule.AbstractJUnitRule;
import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration;
import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper;
import net.sourceforge.pmd.lang.symboltable.NameDeclaration;
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
@@ -39,10 +40,12 @@ public class JUnitTestsShouldIncludeAssertRule extends AbstractJUnitRule {
public Object visit(ASTMethodDeclaration method, Object data) {
if (isJUnitMethod(method, data)) {
if (!isExpectAnnotated(method.jjtGetParent())) {
Map<String, VariableNameDeclaration> variables = getVariables(method);
Scope classScope = method.getScope().getParent();
Map<String, List<NameOccurrence>> expectables = getRuleAnnotatedExpectedExceptions(classScope);
if (!containsExpectOrAssert(method.getBlock(), expectables)) {
if (!containsExpectOrAssert(method.getBlock(), expectables, variables)) {
addViolation(data, method);
}
}
@@ -50,24 +53,35 @@ public class JUnitTestsShouldIncludeAssertRule extends AbstractJUnitRule {
return data;
}
private boolean containsExpectOrAssert(Node n, Map<String, List<NameOccurrence>> expectables) {
private boolean containsExpectOrAssert(Node n,
Map<String, List<NameOccurrence>> expectables,
Map<String, VariableNameDeclaration> variables) {
if (n instanceof ASTStatementExpression) {
if (isExpectStatement((ASTStatementExpression) n, expectables)
|| isAssertOrFailStatement((ASTStatementExpression) n)
|| isVerifyStatement((ASTStatementExpression) n)) {
|| isVerifyStatement((ASTStatementExpression) n)
|| isSoftAssertionStatement((ASTStatementExpression) n, variables)) {
return true;
}
} else {
for (int i = 0; i < n.jjtGetNumChildren(); i++) {
Node c = n.jjtGetChild(i);
if (containsExpectOrAssert(c, expectables)) {
if (containsExpectOrAssert(c, expectables, variables)) {
return true;
}
}
}
return false;
}
private Map<String, VariableNameDeclaration> getVariables(ASTMethodDeclaration method) {
Map<String, VariableNameDeclaration> variables = new HashMap<>();
for (VariableNameDeclaration vnd : method.getScope().getDeclarations(VariableNameDeclaration.class).keySet()) {
variables.put(vnd.getName(), vnd);
}
return variables;
}
/**
* Gets a list of NameDeclarations for all the fields that have type
* ExpectedException and have a Rule annotation.
@@ -189,4 +203,30 @@ public class JUnitTestsShouldIncludeAssertRule extends AbstractJUnitRule {
}
return false;
}
private boolean isSoftAssertionStatement(ASTStatementExpression expression,
Map<String, VariableNameDeclaration> variables) {
if (expression != null) {
ASTPrimaryExpression pe = expression.getFirstChildOfType(ASTPrimaryExpression.class);
if (pe != null) {
Node name = pe.getFirstDescendantOfType(ASTName.class);
if (name != null) {
String img = name.getImage();
if (img.indexOf(".") == -1) {
return false;
}
String[] tokens = img.split("\\.");
String methodName = tokens[1];
boolean methodIsAssertAll = "assertAll".equals(methodName);
String varName = tokens[0];
boolean variableTypeIsSoftAssertion = variables.containsKey(varName)
&& TypeHelper.isA(variables.get(varName), "org.assertj.core.api.AbstractSoftAssertions");
return methodIsAssertAll && variableTypeIsSoftAssertion;
}
}
}
return false;
}
}
@@ -118,7 +118,9 @@ public class VariableNameDeclaration extends AbstractNameDeclaration implements
if (typeNode != null) {
return typeNode.getType();
}
return null;
// if there is no type node, then return the type of the declarator id.
// this might be a inferred type
return getDeclaratorId().getType();
}
@Override
@@ -54,23 +54,29 @@ public final class TypeHelper {
private static Class<?> loadClassWithNodeClassloader(final TypeNode n, final String clazzName) {
if (n.getType() != null) {
try {
ClassLoader classLoader = n.getType().getClassLoader();
if (classLoader == null) {
// Using the system classloader then
classLoader = ClassLoader.getSystemClassLoader();
}
// If the requested type is in the classpath, using the same classloader should work
return ClassUtils.getClass(classLoader, clazzName);
} catch (final ClassNotFoundException ignored) {
// The requested type is not on the auxclasspath. This might happen, if the type node
// is probed for a specific type (e.g. is is a JUnit5 Test Annotation class).
// Failing to resolve clazzName does not necessarily indicate an incomplete auxclasspath.
} catch (final LinkageError expected) {
// We found the class but it's invalid / incomplete. This may be an incomplete auxclasspath
// if it was a NoClassDefFoundError. TODO : Report it?
return loadClass(n.getType().getClassLoader(), clazzName);
}
return null;
}
private static Class<?> loadClass(final ClassLoader nullableClassLoader, final String clazzName) {
try {
ClassLoader classLoader = nullableClassLoader;
if (classLoader == null) {
// Using the system classloader then
classLoader = ClassLoader.getSystemClassLoader();
}
// If the requested type is in the classpath, using the same classloader should work
return ClassUtils.getClass(classLoader, clazzName);
} catch (ClassNotFoundException ignored) {
// The requested type is not on the auxclasspath. This might happen, if the type node
// is probed for a specific type (e.g. is is a JUnit5 Test Annotation class).
// Failing to resolve clazzName does not necessarily indicate an incomplete auxclasspath.
} catch (final LinkageError expected) {
// We found the class but it's invalid / incomplete. This may be an incomplete auxclasspath
// if it was a NoClassDefFoundError. TODO : Report it?
}
return null;
@@ -133,4 +139,15 @@ public final class TypeHelper {
return clazz.isAssignableFrom(type);
}
public static boolean isA(TypedNameDeclaration vnd, String className) {
Class<?> type = vnd.getType();
if (type != null) {
Class<?> clazz = loadClass(type.getClassLoader(), className);
if (clazz != null) {
return clazz.isAssignableFrom(type);
}
}
return false;
}
}
@@ -7,17 +7,17 @@ package net.sourceforge.pmd.lang.java.typeresolution.typedefinition;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.lang3.ArrayUtils;
public abstract class JavaTypeDefinition implements TypeDefinition {
// contains non-generic and raw EXACT types
private static final Map<Class<?>, JavaTypeDefinition> CLASS_EXACT_TYPE_DEF_CACHE = new HashMap<>();
private static final Map<Class<?>, JavaTypeDefinition> CLASS_EXACT_TYPE_DEF_CACHE = new ConcurrentHashMap<>();
private final TypeDefinitionType definitionType;
@@ -410,7 +410,7 @@ in a single method makes its behaviour hard to read and change.
Cyclomatic complexity assesses the complexity of a method by counting the number of decision points in a method,
plus one for the method entry. Decision points are places where the control flow jumps to another place in the
program. As such, they include all control flow statements, such as `if`, `while`, `for`, and `case`. For more
details on the calculation, see the documentation of the [Cyclo metric](/pmd_java_metrics_index.html#cyclomatic-complexity-cyclo).
details on the calculation, see the documentation of the [Cyclo metric](pmd_java_metrics_index.html#cyclomatic-complexity-cyclo).
Generally, numbers ranging from 1-4 denote low complexity, 5-7 denote moderate complexity, 8-10 denote
high complexity, and 11+ is very high complexity. By default, this rule reports methods with a complexity >= 10.
@@ -20,7 +20,6 @@ import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
public abstract class STBBaseTst {
protected ASTCompilationUnit acu;
protected SymbolFacade stb;
protected void parseCode(final String code) {
parseCode(code, LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getDefaultVersion());
@@ -34,8 +33,9 @@ public abstract class STBBaseTst {
final LanguageVersionHandler languageVersionHandler = languageVersion.getLanguageVersionHandler();
acu = (ASTCompilationUnit) languageVersionHandler.getParser(languageVersionHandler.getDefaultParserOptions())
.parse(null, new StringReader(code));
stb = new SymbolFacade();
stb.initializeWith(acu);
languageVersionHandler.getQualifiedNameResolutionFacade(STBBaseTst.class.getClassLoader()).start(acu);
languageVersionHandler.getSymbolFacade(STBBaseTst.class.getClassLoader()).start(acu);
languageVersionHandler.getTypeResolutionFacade(STBBaseTst.class.getClassLoader()).start(acu);
}
// Note: If you're using Eclipse or some other IDE to run this test, you
@@ -8,6 +8,8 @@ import static net.sourceforge.pmd.lang.java.ParserTstUtil.getNodes;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.junit.Test;
@@ -85,6 +87,61 @@ public class VariableNameDeclarationTest extends STBBaseTst {
assertEquals("String", ((TypedNameDeclaration) decl).getTypeImage());
}
@Test
public void testVarKeywordTypeImage() {
parseCode(TEST6);
NameDeclaration decl = acu.findDescendantsOfType(ASTVariableDeclaratorId.class).get(0).getScope()
.getDeclarations().keySet().iterator().next();
assertEquals("java.util.ArrayList", ((TypedNameDeclaration) decl).getType().getName());
// since the type is inferred, there is no type image
assertEquals(null, ((TypedNameDeclaration) decl).getTypeImage());
}
@Test
public void testVarKeywordWithPrimitiveTypeImage() {
parseCode(TEST7);
NameDeclaration decl = acu.findDescendantsOfType(ASTVariableDeclaratorId.class).get(0).getScope()
.getDeclarations().keySet().iterator().next();
assertEquals("long", ((TypedNameDeclaration) decl).getType().getName());
// since the type is inferred, there is no type image
assertEquals(null, ((TypedNameDeclaration) decl).getTypeImage());
}
@Test
public void testVarKeywordWithIndirectReference() {
parseCode(TEST8);
Iterator<NameDeclaration> nameDeclarationIterator = acu.findDescendantsOfType(ASTVariableDeclaratorId.class).get(0).getScope()
.getDeclarations().keySet().iterator();
nameDeclarationIterator.next(); // first variable 'bar'
NameDeclaration decl = nameDeclarationIterator.next(); // second variable 'foo'
assertEquals("java.lang.String", ((TypedNameDeclaration) decl).getType().getName());
// since the type is inferred, there is no type image
assertEquals(null, ((TypedNameDeclaration) decl).getTypeImage());
}
@Test
public void testLamdaParameterTypeImage() {
parseCode(TEST9);
List<ASTVariableDeclaratorId> variableDeclaratorIds = acu.findDescendantsOfType(
ASTVariableDeclaratorId.class,
true
);
List<VariableNameDeclaration> nameDeclarations = new ArrayList<>();
for (ASTVariableDeclaratorId variableDeclaratorId : variableDeclaratorIds) {
nameDeclarations.add(variableDeclaratorId.getNameDeclaration());
}
assertEquals("Map", nameDeclarations.get(0).getTypeImage()); // variable 'bar'
assertEquals(null, nameDeclarations.get(1).getTypeImage()); // variable 'key'
assertEquals(null, nameDeclarations.get(2).getTypeImage()); // variable 'value'
// variable 'foo'
assertEquals("foo", nameDeclarations.get(3).getName());
assertEquals("long", nameDeclarations.get(3).getType().getName());
// since the type is inferred, there is no type image
assertEquals(null, nameDeclarations.get(3).getTypeImage());
}
private static final String EXCEPTION_PARAMETER = "public class Test { { try {} catch(Exception ie) {} } }";
@@ -101,6 +158,20 @@ public class VariableNameDeclarationTest extends STBBaseTst {
+ PMD.EOL + " }" + PMD.EOL + "}";
public static final String TEST5 = "public class Foo {" + PMD.EOL + " void foo(String x) {}" + PMD.EOL + "}";
public static final String TEST6 = "import java.util.ArrayList; public class Foo {" + PMD.EOL + " void foo() {" + PMD.EOL
+ " var bar = new ArrayList<String>(\"param\");" + PMD.EOL + " }" + PMD.EOL + "}";
public static final String TEST7 = "public class Foo {" + PMD.EOL + " void foo() {" + PMD.EOL + " var bar = 42L;"
+ PMD.EOL + " }" + PMD.EOL + "}";
public static final String TEST8 = "public class Foo {" + PMD.EOL + " void foo() {" + PMD.EOL
+ " var bar = \"test\";" + PMD.EOL + " var foo = bar;" + PMD.EOL + " }" + PMD.EOL + "}";
public static final String TEST9 = "public class Foo {" + PMD.EOL + " void foo() {" + PMD.EOL
+ " Map<String, Object> bar = new HashMap<>();" + PMD.EOL + " bar.forEach((key, value) -> {" + PMD.EOL
+ " if (value instanceof String) {" + PMD.EOL + " var foo = 42L;" + PMD.EOL
+ " System.out.println(value);" + PMD.EOL + " }" + PMD.EOL + " });" + PMD.EOL + " }" + PMD.EOL + "}";
public static junit.framework.Test suite() {
return new junit.framework.JUnit4TestAdapter(VariableNameDeclarationTest.class);
}
@@ -429,6 +429,71 @@ class Style {
public void moveOutOfBoundsFrom() {
doSomething();
}
}]]></code>
</test-code>
<test-code>
<description>#1435 Treat AssertJ soft assertions as assert expressions</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import org.assertj.core.api.SoftAssertions;
import org.junit.jupiter.api.Test;
class FooTest {
@Test
void testFoo() {
var softly = new SoftAssertions();
softly.assertThat("doesn't matter").isEqualTo("doesn't matter");
softly.assertAll();
}
@Test
void testBar() {
SoftAssertions softly = new SoftAssertions();
softly.assertThat("doesn't matter").isEqualTo("doesn't matter");
softly.assertAll();
}
}]]></code>
</test-code>
<test-code>
<description>#1435 Treat AssertJ soft assertions as assert expressions - missing assertAll</description>
<expected-problems>2</expected-problems>
<expected-linenumbers>7,13</expected-linenumbers>
<code><![CDATA[
import org.assertj.core.api.SoftAssertions;
import org.junit.jupiter.api.Test;
class FooTest {
@Test
void testFoo() {
var softly = new SoftAssertions();
softly.assertThat("doesn't matter").isEqualTo("doesn't matter");
}
@Test
void testBar() {
SoftAssertions softly = new SoftAssertions();
softly.assertThat("doesn't matter").isEqualTo("doesn't matter");
}
}]]></code>
</test-code>
<test-code>
<description>#1435 Treat AssertJ soft assertion rule for JUnit 4 as assert expressions</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import org.assertj.core.api.JUnitSoftAssertions;
import org.junit.Test;
public class FooTest {
@Rule
public final JUnitSoftAssertions softly = new JUnitSoftAssertions();
@Test
void testFoo() {
softly.assertThat("doesn't matter").isEqualTo("doesn't matter");
}
}]]></code>
</test-code>
</test-data>
+5
View File
@@ -936,6 +936,11 @@ Additionally it includes CPD, the copy-paste-detector. CPD finds duplicated code
<artifactId>system-rules</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.11.0</version>
</dependency>
<!-- TEST DEPENDENCIES -->