diff --git a/java-checks-test-sources/default/src/main/java/checks/InstantConversionsCheckSample.java b/java-checks-test-sources/default/src/main/java/checks/DateTimeConversionsCheckSample.java
similarity index 99%
rename from java-checks-test-sources/default/src/main/java/checks/InstantConversionsCheckSample.java
rename to java-checks-test-sources/default/src/main/java/checks/DateTimeConversionsCheckSample.java
index 175c2100106..d4b6dcc19b0 100644
--- a/java-checks-test-sources/default/src/main/java/checks/InstantConversionsCheckSample.java
+++ b/java-checks-test-sources/default/src/main/java/checks/DateTimeConversionsCheckSample.java
@@ -16,7 +16,7 @@
import java.time.ZonedDateTime;
import java.time.temporal.TemporalAccessor;
-public class InstantConversionsCheckSample {
+public class DateTimeConversionsCheckSample {
private Instant instant;
private TemporalAccessor temporalAccessor;
diff --git a/java-checks/src/main/java/org/sonar/java/checks/InstantConversionsCheck.java b/java-checks/src/main/java/org/sonar/java/checks/DateTimeConversionsCheck.java
similarity index 97%
rename from java-checks/src/main/java/org/sonar/java/checks/InstantConversionsCheck.java
rename to java-checks/src/main/java/org/sonar/java/checks/DateTimeConversionsCheck.java
index 5836a8db5ac..f7fee6daeee 100644
--- a/java-checks/src/main/java/org/sonar/java/checks/InstantConversionsCheck.java
+++ b/java-checks/src/main/java/org/sonar/java/checks/DateTimeConversionsCheck.java
@@ -29,7 +29,7 @@
import org.sonar.plugins.java.api.tree.TypeCastTree;
@Rule(key = "S8220")
-public class InstantConversionsCheck extends AbstractMethodDetection implements JavaVersionAwareVisitor {
+public class DateTimeConversionsCheck extends AbstractMethodDetection implements JavaVersionAwareVisitor {
private static final String INSTANT = "java.time.Instant";
private static final String TEMPORAL_ACCESSOR = "java.time.temporal.TemporalAccessor";
diff --git a/java-checks/src/main/java/org/sonar/java/filters/ExpectedExceptionFilter.java b/java-checks/src/main/java/org/sonar/java/filters/ExpectedExceptionFilter.java
index 6028ccdfaf8..5242e85d48e 100644
--- a/java-checks/src/main/java/org/sonar/java/filters/ExpectedExceptionFilter.java
+++ b/java-checks/src/main/java/org/sonar/java/filters/ExpectedExceptionFilter.java
@@ -19,11 +19,9 @@
import java.util.List;
import java.util.Optional;
import java.util.Set;
-import org.sonar.java.checks.InstantConversionsCheck;
-import org.sonar.java.checks.helpers.MethodTreeUtils;
+import org.sonar.java.checks.DateTimeConversionsCheck;
import org.sonar.java.model.ExpressionUtils;
import org.sonar.plugins.java.api.JavaCheck;
-import org.sonar.plugins.java.api.semantic.MethodMatchers;
import org.sonar.plugins.java.api.semantic.Type;
import org.sonar.plugins.java.api.tree.AnnotationTree;
import org.sonar.plugins.java.api.tree.Arguments;
@@ -39,198 +37,211 @@
import org.sonar.plugins.java.api.tree.TypeTree;
import org.sonar.plugins.java.api.tree.UnionTypeTree;
-import static org.sonar.java.checks.helpers.UnitTestUtils.isTryCatchFail;
+import static org.sonar.java.checks.helpers.MethodTreeUtils.consecutiveMethodInvocation;
+/**
+ * A filter to deactivate rules that catch expressions raising specific exceptions in contexts where these exceptions are expected.
+ *
+ * This filter is willingly broad and works directly with type and method names rather than their types, to be resilient even in the face of missing semantic information.
+ *
+ */
public class ExpectedExceptionFilter extends BaseTreeVisitorIssueFilter {
- private static final String ASSERTJ_ASSERTIONS = "org.assertj.core.api.Assertions";
-
- private static final MethodMatchers ASSERT_THROWS_MATCHER = MethodMatchers.create()
- .ofTypes("org.junit.Assert", "org.junit.jupiter.api.Assertions", "org.testng.Assert", "org.testng.AssertJUnit")
- .names("assertThrows", "assertThrowsExactly", "expectThrows")
- .withAnyParameters()
- .build();
-
- private static final MethodMatchers ASSERTJ_CATCH_THROWABLE_OF_TYPE = MethodMatchers.create()
- .ofTypes(ASSERTJ_ASSERTIONS)
- .names("catchThrowableOfType")
- .addParametersMatcher("org.assertj.core.api.ThrowableAssert$ThrowingCallable", "java.lang.Class")
- .build();
-
- private static final MethodMatchers ASSERTJ_ASSERT_CODE = MethodMatchers.create()
- .ofTypes(ASSERTJ_ASSERTIONS)
- .names("assertThatCode", "assertThatThrownBy")
- .withAnyParameters()
- .build();
-
- private static final MethodMatchers ASSERTJ_EXCEPTION_OF_TYPE = MethodMatchers.create()
- .ofTypes(ASSERTJ_ASSERTIONS, "org.assertj.core.api.BDDAssertions")
- .names("assertThatExceptionOfType", "thenExceptionOfType")
- .addParametersMatcher("java.lang.Class")
- .build();
-
- private static final MethodMatchers ASSERTJ_TYPED_EXCEPTION = MethodMatchers.create()
- .ofTypes(ASSERTJ_ASSERTIONS, "org.assertj.core.api.BDDAssertions")
- .names("assertThatException", "assertThatRuntimeException", "thenException", "thenRuntimeException")
- .withAnyParameters()
- .build();
-
- private static final MethodMatchers ASSERTJ_IS_THROWN_BY = MethodMatchers.create()
- .ofTypes("org.assertj.core.api.ThrowableTypeAssert")
- .names("isThrownBy")
- .addParametersMatcher("org.assertj.core.api.ThrowableAssert$ThrowingCallable")
- .build();
-
- private static final MethodMatchers ASSERTJ_INSTANCE_OF_PREDICATES = MethodMatchers.create()
- .ofSubTypes("org.assertj.core.api.Assert")
- .names("isInstanceOf", "isInstanceOfAny")
- .withAnyParameters()
- .build();
-
- private static final MethodMatchers ASSERTJ_EXACT_INSTANCE_OF_PREDICATES = MethodMatchers.create()
- .ofSubTypes("org.assertj.core.api.Assert")
- .names("isExactlyInstanceOf", "isOfAnyClassIn")
- .withAnyParameters()
- .build();
-
- private static final String DATE_TIME_EXCEPTION = "java.time.DateTimeException";
-
- private static final Set DATE_TIME_EXCEPTION_SUPERTYPES = Set.of(
- "java.lang.RuntimeException",
- "java.lang.Exception",
- "java.lang.Throwable"
+ private static final Set DATE_TIME_EXCEPTION_TYPES = Set.of(
+ "DateTimeException",
+ "DateTimeParseException",
+ "RuntimeException",
+ "Exception",
+ "Throwable"
+ );
+
+ private static final Set ASSERT_THROWS_METHODS = Set.of(
+ "assertThrows",
+ "assertThrowsExactly",
+ "expectThrows"
+ );
+
+ private static final Set ASSERT_CODE_METHODS = Set.of(
+ "assertThatCode",
+ "assertThatThrownBy"
+ );
+
+ private static final Set INSTANCEOF_METHODS = Set.of(
+ "isInstanceOf",
+ "isInstanceOfAny",
+ "isExactlyInstanceOf",
+ "isOfAnyClassIn"
+ );
+
+ private static final Set ASSERT_EXCEPTION_METHODS = Set.of(
+ "assertThatException",
+ "assertThatRuntimeException",
+ "thenException",
+ "thenRuntimeException"
+ );
+
+ private static final Set ASSERT_OF_TYPE_METHODS = Set.of(
+ "assertThatExceptionOfType",
+ "thenExceptionOfType"
);
@Override
public Set> filteredRules() {
- return Set.of(InstantConversionsCheck.class);
+ return Set.of(DateTimeConversionsCheck.class);
}
@Override
public void visitMethod(MethodTree tree) {
- if (hasExpectedDateTimeExceptionAnnotation(tree.modifiers().annotations())) {
- excludeLines(tree, InstantConversionsCheck.class);
+ if (containsExpectedExceptions(tree.modifiers().annotations(), DATE_TIME_EXCEPTION_TYPES)) {
+ excludeLines(tree, DateTimeConversionsCheck.class);
}
super.visitMethod(tree);
}
@Override
public void visitTryStatement(TryStatementTree tree) {
- if (isTryCatchFailExpectingDateTimeException(tree)) {
- excludeLines(tree.block(), InstantConversionsCheck.class);
+ if (catchesExpectedException(tree, DATE_TIME_EXCEPTION_TYPES)) {
+ excludeLines(tree.block(), DateTimeConversionsCheck.class);
}
super.visitTryStatement(tree);
}
@Override
public void visitMethodInvocation(MethodInvocationTree tree) {
- excludeExpectedDateTimeExceptionIssues(tree);
+ excludeExpectedExceptions(tree, DATE_TIME_EXCEPTION_TYPES, DateTimeConversionsCheck.class);
super.visitMethodInvocation(tree);
}
- private void excludeExpectedDateTimeExceptionIssues(MethodInvocationTree mit) {
- if (ASSERT_THROWS_MATCHER.matches(mit)) {
- excludeAssertThrowsExecutableForDateTimeException(mit);
- } else if (ASSERTJ_CATCH_THROWABLE_OF_TYPE.matches(mit) && isDateTimeExceptionClass(mit.arguments().get(1), false)) {
- excludeLines(mit.arguments().get(0), InstantConversionsCheck.class);
- } else if (ASSERTJ_ASSERT_CODE.matches(mit)) {
- MethodTreeUtils.subsequentMethodInvocation(mit, ASSERTJ_INSTANCE_OF_PREDICATES).ifPresent(subsequentMit -> {
- if (hasDateTimeExceptionType(subsequentMit.arguments(), false)) {
- excludeLines(mit.arguments().get(0), InstantConversionsCheck.class);
- }
- });
- MethodTreeUtils.subsequentMethodInvocation(mit, ASSERTJ_EXACT_INSTANCE_OF_PREDICATES).ifPresent(subsequentMit -> {
- if (hasDateTimeExceptionType(subsequentMit.arguments(), true)) {
- excludeLines(mit.arguments().get(0), InstantConversionsCheck.class);
- }
- });
- } else if (ASSERTJ_TYPED_EXCEPTION.matches(mit) || (ASSERTJ_EXCEPTION_OF_TYPE.matches(mit) && isDateTimeExceptionClass(mit.arguments().get(0), false))) {
- MethodTreeUtils.subsequentMethodInvocation(mit, ASSERTJ_IS_THROWN_BY).ifPresent(subsequentMit ->
- excludeLines(subsequentMit.arguments().get(0), InstantConversionsCheck.class)
- );
+ /**
+ * Filter a given rule for parts of a method invocation expression when it expects a given set of exception types.
+ */
+ private void excludeExpectedExceptions(MethodInvocationTree tree, Set expectedExceptions, Class extends JavaCheck> filteredRule) {
+ String methodName = tree.methodSymbol().name();
+ Arguments arguments = tree.arguments();
+ if (ASSERT_THROWS_METHODS.contains(methodName) && arguments.size() >= 2) {
+ excludeFromAssertThrows(arguments, expectedExceptions, filteredRule);
+ } else if ("catchThrowableOfType".equals(methodName) && arguments.size() > 1 && containsExpectedExceptions(arguments.get(1), expectedExceptions)) {
+ excludeLines(arguments.get(0), filteredRule);
+ } else if (ASSERT_CODE_METHODS.contains(methodName)) {
+ excludeFromAssertCode(tree, arguments, expectedExceptions, filteredRule);
+ } else if (ASSERT_EXCEPTION_METHODS.contains(methodName) ||
+ (ASSERT_OF_TYPE_METHODS.contains(methodName) && !arguments.isEmpty() && containsExpectedExceptions(arguments.get(0), expectedExceptions))) {
+ excludeIsThrownBy(tree, filteredRule);
}
}
- private void excludeAssertThrowsExecutableForDateTimeException(MethodInvocationTree mit) {
- Arguments arguments = mit.arguments();
- if (arguments.size() < 2) {
- return;
- }
+ private void excludeFromAssertThrows(Arguments arguments, Set expectedExceptions, Class extends JavaCheck> filteredRule) {
int expectedTypeIndex = firstArgumentIsMessage(arguments) ? 1 : 0;
int executableIndex = expectedTypeIndex + 1;
- if (arguments.size() > executableIndex && isDateTimeExceptionClass(arguments.get(expectedTypeIndex), "assertThrowsExactly".equals(mit.methodSymbol().name()))) {
- excludeLines(arguments.get(executableIndex), InstantConversionsCheck.class);
+ if (arguments.size() > executableIndex && containsExpectedExceptions(arguments.get(expectedTypeIndex), expectedExceptions)) {
+ excludeLines(arguments.get(executableIndex), filteredRule);
}
}
- private static boolean firstArgumentIsMessage(Arguments arguments) {
- return arguments.size() >= 3 && arguments.get(0).symbolType().is("java.lang.String");
+ private void excludeFromAssertCode(MethodInvocationTree tree, Arguments arguments, Set expectedExceptions, Class extends JavaCheck> filteredRule) {
+ subsequentMethodInvocation(tree, INSTANCEOF_METHODS).ifPresent(mit -> {
+ if (!arguments.isEmpty() && mit.arguments().stream().anyMatch(expression -> containsExpectedExceptions(expression, expectedExceptions))) {
+ excludeLines(arguments.get(0), filteredRule);
+ }
+ });
}
- private static boolean isTryCatchFailExpectingDateTimeException(TryStatementTree tryStatement) {
- return isTryCatchFail(tryStatement.block()) && tryStatement.catches().stream().anyMatch(ExpectedExceptionFilter::isDateTimeExceptionCatch);
+ private void excludeIsThrownBy(MethodInvocationTree tree, Class extends JavaCheck> filteredRule) {
+ subsequentMethodInvocation(tree, Set.of("isThrownBy")).ifPresent(mit -> {
+ Arguments mitArguments = mit.arguments();
+ if (!mitArguments.isEmpty()) {
+ excludeLines(mitArguments.get(0), filteredRule);
+ }
+ });
}
- private static boolean isDateTimeException(Type type, boolean exact) {
- return type.isSubtypeOf(DATE_TIME_EXCEPTION) || (!exact && DATE_TIME_EXCEPTION_SUPERTYPES.stream().anyMatch(type::is));
+ /**
+ * Check if a list of annotations contains a {@code Test} annotation expecting specific exception types.
+ */
+ private static boolean containsExpectedExceptions(List annotations, Set expectedExceptions) {
+ return annotations.stream()
+ .anyMatch(annotation ->
+ "Test".equals(annotation.symbolType().name()) && containsExpectedExceptions(annotation.arguments(), expectedExceptions)
+ );
}
- private static boolean isDateTimeExceptionClass(ExpressionTree expression, boolean exact) {
- if (expression.is(Tree.Kind.NEW_ARRAY)) {
- return ((NewArrayTree) expression).initializers().stream()
- .anyMatch(initializer -> isDateTimeExceptionClass(initializer, exact));
+ /**
+ * Check if a {@code Test} annotation has an {@code expected} or {@code expectedException} argument matching a set of expected exception types.
+ */
+ private static boolean containsExpectedExceptions(Arguments arguments, Set expectedExceptions) {
+ return arguments.stream()
+ .filter(ExpectedExceptionFilter::isExpectedExceptionArgument)
+ .anyMatch(argument -> containsExpectedExceptions(annotationValue(argument), expectedExceptions));
+ }
+
+ /**
+ * Check that an annotation argument is an {@code expected} or {@code expectedException} attribute.
+ */
+ private static boolean isExpectedExceptionArgument(ExpressionTree expression) {
+ String annotationAttributeName = ExpressionUtils.annotationAttributeName(expression);
+ return "expected".equals(annotationAttributeName) || "expectedExceptions".equals(annotationAttributeName);
+ }
+
+ /**
+ * Check if an expression contains a given exception type.
+ */
+ private static boolean containsExpectedExceptions(ExpressionTree expression, Set expectedExceptions) {
+ if (expression instanceof NewArrayTree newArray) {
+ return newArray.initializers().stream()
+ .anyMatch(initializer -> containsExpectedExceptions(initializer, expectedExceptions));
}
- return classLiteralType(expression)
- .map(type -> isDateTimeException(type, exact))
- .orElse(false);
+ return classLiteralType(expression).map(type -> expectedExceptions.contains(type.name())).orElse(false);
+ }
+
+ /**
+ * Get the value of an annotation attribute.
+ */
+ private static ExpressionTree annotationValue(ExpressionTree expression) {
+ return expression.is(Tree.Kind.ASSIGNMENT) ? ((AssignmentExpressionTree) expression).expression() : expression;
}
+ /**
+ * Extract the type name of a class literal expression.
+ */
private static Optional classLiteralType(ExpressionTree expression) {
- if (expression.is(Tree.Kind.MEMBER_SELECT)) {
- MemberSelectExpressionTree memberSelect = (MemberSelectExpressionTree) expression;
- if ("class".equals(memberSelect.identifier().name())) {
- return Optional.of(memberSelect.expression().symbolType());
- }
+ if (expression instanceof MemberSelectExpressionTree memberSelect && "class".equals(memberSelect.identifier().name())) {
+ return Optional.of(memberSelect.expression().symbolType());
}
return Optional.empty();
}
- private static boolean isDateTimeExceptionCatch(CatchTree catchTree) {
+ /**
+ * Check if a try statement catches a set of expected exception types.
+ */
+ private static boolean catchesExpectedException(TryStatementTree tryStatement, Set expectedExceptions) {
+ return tryStatement.catches().stream()
+ .anyMatch(catchTree -> catchesExpectedExceptions(catchTree, expectedExceptions));
+ }
+
+ private static boolean catchesExpectedExceptions(CatchTree catchTree, Set expectedExceptions) {
return exceptionTypes(catchTree.parameter().type()).stream()
- .anyMatch(type -> isDateTimeException(type.symbolType(), false));
+ .anyMatch(type -> expectedExceptions.contains(type.symbolType().name()));
}
private static List exceptionTypes(TypeTree typeTree) {
- if (typeTree.is(Tree.Kind.UNION_TYPE)) {
- return ((UnionTypeTree) typeTree).typeAlternatives();
+ if (typeTree instanceof UnionTypeTree unionType) {
+ return unionType.typeAlternatives();
}
return List.of(typeTree);
}
- private static boolean hasExpectedDateTimeExceptionAnnotation(List annotations) {
- return annotations.stream().anyMatch(annotation -> {
- Type annotationType = annotation.annotationType().symbolType();
- if (annotationType.is("org.junit.Test")) {
- return hasExpectedDateTimeExceptionArgument(annotation, "expected");
- } else if (annotationType.is("org.testng.annotations.Test")) {
- return hasExpectedDateTimeExceptionArgument(annotation, "expectedExceptions");
- }
- return false;
- });
- }
-
- private static boolean hasExpectedDateTimeExceptionArgument(AnnotationTree annotation, String attributeName) {
- return annotation.arguments().stream()
- .filter(argument -> attributeName.equals(ExpressionUtils.annotationAttributeName(argument)))
- .anyMatch(argument -> isDateTimeExceptionClass(annotationValue(argument), false));
- }
-
- private static ExpressionTree annotationValue(ExpressionTree expression) {
- return expression.is(Tree.Kind.ASSIGNMENT) ? ((AssignmentExpressionTree) expression).expression() : expression;
+ private static boolean firstArgumentIsMessage(Arguments arguments) {
+ return arguments.size() >= 3 && arguments.get(0).symbolType().is("java.lang.String");
}
- private static boolean hasDateTimeExceptionType(List expressions, boolean exact) {
- return expressions.stream().anyMatch(expression -> isDateTimeExceptionClass(expression, exact));
+ /**
+ * Get the next chained method invocation whose identifier matches a set of expected method names.
+ */
+ private static Optional subsequentMethodInvocation(MethodInvocationTree tree, Set expectedMethodNames) {
+ return consecutiveMethodInvocation(tree)
+ .map(consecutiveMethod ->
+ expectedMethodNames.contains(consecutiveMethod.methodSymbol().name()) ?
+ consecutiveMethod : subsequentMethodInvocation(consecutiveMethod, expectedMethodNames).orElse(null));
}
}
diff --git a/java-checks/src/test/files/filters/ExpectedExceptionFilter.java b/java-checks/src/test/files/filters/ExpectedExceptionFilter.java
index 312a3582d08..5fce44a726d 100644
--- a/java-checks/src/test/files/filters/ExpectedExceptionFilter.java
+++ b/java-checks/src/test/files/filters/ExpectedExceptionFilter.java
@@ -65,7 +65,7 @@ void junit5AssertThrowsExpectedBroadException() {
org.junit.jupiter.api.Assertions.assertThrows(() -> LocalDate.from(instant)); // NoIssue
org.junit.jupiter.api.Assertions.assertThrowsExactly(DateTimeException.class, () -> LocalDateTime.from(instant)); // NoIssue
org.junit.jupiter.api.Assertions.assertThrowsExactly(DateTimeParseException.class, () -> LocalDateTime.from(instant)); // NoIssue
- org.junit.jupiter.api.Assertions.assertThrowsExactly(RuntimeException.class, () -> LocalDateTime.from(instant)); // WithIssue
+ org.junit.jupiter.api.Assertions.assertThrowsExactly(RuntimeException.class, () -> LocalDateTime.from(instant)); // NoIssue
}
@org.junit.jupiter.api.Test
@@ -93,9 +93,9 @@ void testngExpectThrows() {
void assertjAssertThatThrownBy() {
org.assertj.core.api.Assertions.assertThatThrownBy(() -> Instant.from(date)).isInstanceOf(DateTimeException.class); // NoIssue
org.assertj.core.api.Assertions.assertThatThrownBy(() -> Instant.from(date)).isInstanceOf(RuntimeException.class); // NoIssue
- org.assertj.core.api.Assertions.assertThatThrownBy(() -> Instant.from(date)).isInstanceOf(IllegalArgumentException.class); // WithIssue
- org.assertj.core.api.Assertions.assertThatThrownBy(() -> Instant.from(date)).isExactlyInstanceOf(RuntimeException.class); // WithIssue
+ org.assertj.core.api.Assertions.assertThatThrownBy(() -> Instant.from(date)).isExactlyInstanceOf(RuntimeException.class); // NoIssue
org.assertj.core.api.Assertions.assertThatThrownBy(() -> Instant.from(date)).isExactlyInstanceOf(DateTimeException.class); // NoIssue
+ org.assertj.core.api.Assertions.assertThatThrownBy(() -> Instant.from(date)).isInstanceOf(IllegalArgumentException.class); // WithIssue
}
@org.junit.jupiter.api.Test
@@ -112,6 +112,7 @@ void assertjExceptionOfType() {
@org.junit.jupiter.api.Test
void assertjCatchThrowableOfType() {
org.assertj.core.api.Assertions.catchThrowableOfType(() -> OffsetTime.from(instant), DateTimeException.class); // NoIssue
+ org.assertj.core.api.Assertions.catchThrowableOfType(() -> Instant.from(date), IllegalArgumentException.class); // WithIssue
}
@org.junit.jupiter.api.Test
@@ -151,6 +152,50 @@ void tryCatchFail() {
} catch (DateTimeException | IllegalArgumentException e) {
// expected
}
+
+ try {
+ LocalDate.from(instant); // NoIssue
+ } catch (DateTimeException e) {
+ // expected
+ }
+ }
+
+ // When semantic information is missing, the filter should conservatively activate.
+ @Test(expected = RuntimeException.class)
+ void expectedMethodAnnotationWithoutSemantics() {
+ Instant.from(date); // NoIssue
+ }
+
+ @Test(expectedExceptions = DateTimeException.class)
+ void expectedExceptionsMethodAnnotationWithoutSemantics() {
+ Instant.from(date); // NoIssue
+ }
+
+ @Test
+ void methodInvocationsWithoutSemantics() {
+ // Here too, the filter should activate even though no semantic information is available.
+ assertThrows(DateTimeException.class, () -> LocalDate.from(instant)); // NoIssue
+ assertThatThrownBy(() -> Instant.from(date)).isInstanceOf(DateTimeException.class); // NoIssue
+ assertThatExceptionOfType(DateTimeException.class).isThrownBy(() -> ZonedDateTime.from(dateTime)); // NoIssue
+ assertThatExceptionOfType(IllegalArgumentException.class).isThrownBy(() -> ZonedDateTime.from(dateTime)); // WithIssue
+ assertThatIllegalArgumentException().isThrownBy(() -> Instant.from(date)); // WithIssue
+ thenRuntimeException().isThrownBy(() -> Instant.from(date)); // NoIssue
+ }
+
+ @Test(expected = DateTimeException)
+ void wrongExpectedType() {
+ Instant.from(date); // WithIssue
+ }
+
+ @Test(expect = DateTimeException.class)
+ void wrongAnnotationAttribute() {
+ Instant.from(date); // WithIssue
+ }
+
+ @Test
+ void wrongAssertMethodSignature() {
+ assertThrows(Instant.from(date)); // WithIssue
+ catchThrowableOfType(Instant.from(date)); // WithIssue
}
}
diff --git a/java-checks/src/test/java/org/sonar/java/checks/InstantConversionsCheckTest.java b/java-checks/src/test/java/org/sonar/java/checks/DateTimeConversionsCheckTest.java
similarity index 84%
rename from java-checks/src/test/java/org/sonar/java/checks/InstantConversionsCheckTest.java
rename to java-checks/src/test/java/org/sonar/java/checks/DateTimeConversionsCheckTest.java
index e7ecfdb8e60..2b99e62c0e6 100644
--- a/java-checks/src/test/java/org/sonar/java/checks/InstantConversionsCheckTest.java
+++ b/java-checks/src/test/java/org/sonar/java/checks/DateTimeConversionsCheckTest.java
@@ -21,13 +21,13 @@
import static org.sonar.java.checks.verifier.TestUtils.mainCodeSourcesPath;
-class InstantConversionsCheckTest {
+class DateTimeConversionsCheckTest {
@Test
void test() {
CheckVerifier.newVerifier()
- .onFile(mainCodeSourcesPath("checks/InstantConversionsCheckSample.java"))
- .withCheck(new InstantConversionsCheck())
+ .onFile(mainCodeSourcesPath("checks/DateTimeConversionsCheckSample.java"))
+ .withCheck(new DateTimeConversionsCheck())
.verifyIssues();
}
}
diff --git a/java-checks/src/test/java/org/sonar/java/filters/ExpectedExceptionFilterTest.java b/java-checks/src/test/java/org/sonar/java/filters/ExpectedExceptionFilterTest.java
index e6c18c8fc06..4d2e67a007f 100644
--- a/java-checks/src/test/java/org/sonar/java/filters/ExpectedExceptionFilterTest.java
+++ b/java-checks/src/test/java/org/sonar/java/filters/ExpectedExceptionFilterTest.java
@@ -26,4 +26,11 @@ void test() {
.verify("src/test/files/filters/ExpectedExceptionFilter.java", new ExpectedExceptionFilter());
}
+ @Test
+ void test_without_semantics() {
+ FilterVerifier.newInstance()
+ .withoutSemantic()
+ .verify("src/test/files/filters/ExpectedExceptionFilter.java", new ExpectedExceptionFilter());
+ }
+
}