mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-06 03:21:12 +07:00
[jvm] IDEA-297743 Convert TestMethodWithoutAssertionInspection to UAST
Also make it work for all test frameworks. GitOrigin-RevId: 9040d77d5dbc4f01085d46a48c4745624348bb00
This commit is contained in:
committed by
intellij-monorepo-bot
parent
c2dd52ccfa
commit
5d65106a85
@@ -18,6 +18,11 @@
|
||||
groupPathKey="jvm.inspections.group.name" groupKey="jvm.inspections.test.frameworks.group.name"
|
||||
key="jvm.inspections.testonly.display.name"
|
||||
implementationClass="com.intellij.codeInspection.test.TestOnlyInspection"/>
|
||||
<localInspection language="UAST" enabledByDefault="false" level="WARNING" shortName="TestMethodWithoutAssertion"
|
||||
groupBundle="messages.JvmAnalysisBundle" bundle="messages.JvmAnalysisBundle"
|
||||
groupPathKey="jvm.inspections.group.name" groupKey="jvm.inspections.test.frameworks.group.name"
|
||||
key="jvm.inspections.test.method.without.assertion.display.name"
|
||||
implementationClass="com.intellij.codeInspection.test.TestMethodWithoutAssertionInspection"/>
|
||||
<localInspection language="UAST" enabledByDefault="true" level="WARNING" shortName="TestFailedLine"
|
||||
groupBundle="messages.JvmAnalysisBundle" bundle="messages.JvmAnalysisBundle"
|
||||
groupPathKey="jvm.inspections.group.name" groupKey="jvm.inspections.test.frameworks.group.name"
|
||||
|
||||
@@ -85,6 +85,9 @@ jvm.inspections.testonly.field.reference=Test-only field is referenced in produc
|
||||
jvm.inspections.testonly.method.call=Test-only method is called in production code
|
||||
jvm.inspections.testonly.visiblefortesting=@VisibleForTesting makes little sense on @TestOnly code
|
||||
|
||||
jvm.inspections.test.method.without.assertion.display.name=Test method without any assertions
|
||||
jvm.inspections.test.method.without.assertion.problem.descriptor=Test method <code>#ref()</code> contains no assertions #loc
|
||||
|
||||
jvm.inspections.junit3.super.teardown.display.name=JUnit 3 'super.tearDown()' is not called from 'finally' block
|
||||
jvm.inspections.junit3.super.teardown.problem.descriptor=<code>#ref()</code> is not called from 'finally' block #loc
|
||||
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.codeInspection.test
|
||||
|
||||
import com.intellij.analysis.JvmAnalysisBundle
|
||||
import com.intellij.codeInspection.AbstractBaseUastLocalInspectionTool
|
||||
import com.intellij.codeInspection.LocalInspectionToolSession
|
||||
import com.intellij.codeInspection.ProblemsHolder
|
||||
import com.intellij.codeInspection.registerUProblem
|
||||
import com.intellij.codeInspection.test.junit.HamcrestCommonClassNames.*
|
||||
import com.intellij.codeInspection.ui.ListTable
|
||||
import com.intellij.codeInspection.ui.ListWrappingTableModel
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.uast.UastHintedVisitorAdapter
|
||||
import com.intellij.util.castSafelyTo
|
||||
import com.intellij.util.ui.CheckBox
|
||||
import com.intellij.util.ui.FormBuilder
|
||||
import com.siyeh.InspectionGadgetsBundle
|
||||
import com.siyeh.ig.junit.JUnitCommonClassNames.*
|
||||
import com.siyeh.ig.psiutils.MethodMatcher
|
||||
import com.siyeh.ig.psiutils.TestUtils
|
||||
import com.siyeh.ig.ui.UiUtils
|
||||
import org.jdom.Element
|
||||
import org.jetbrains.uast.*
|
||||
import org.jetbrains.uast.visitor.AbstractUastNonRecursiveVisitor
|
||||
import org.jetbrains.uast.visitor.AbstractUastVisitor
|
||||
import javax.swing.JComponent
|
||||
|
||||
class TestMethodWithoutAssertionInspection : AbstractBaseUastLocalInspectionTool() {
|
||||
@JvmField
|
||||
var assertKeywordIsAssertion = false
|
||||
|
||||
@JvmField
|
||||
var ignoreIfExceptionThrown = false
|
||||
|
||||
private val methodMatcher = MethodMatcher(false, "assertionMethods")
|
||||
.add(ORG_JUNIT_ASSERT, "assert.*|fail.*")
|
||||
.add(JUNIT_FRAMEWORK_ASSERT, "assert.*|fail.*")
|
||||
.add(ORG_JUNIT_JUPITER_API_ASSERTIONS, "assert.*|fail.*")
|
||||
.add("org.assertj.core.api.Assertions", "assertThat")
|
||||
.add("org.assertj.core.api.WithAssertions", "assertThat")
|
||||
.add("com.google.common.truth.Truth", "assert.*")
|
||||
.add("com.google.common.truth.Truth8", "assert.*")
|
||||
.add("org.mockito.Mockito", "verify.*")
|
||||
.add("org.mockito.InOrder", "verify")
|
||||
.add("org.junit.rules.ExpectedException", "expect.*")
|
||||
.add(ORG_HAMCREST_MATCHER_ASSERT, "assertThat")
|
||||
.add("mockit.Verifications", "Verifications")
|
||||
.finishDefault()
|
||||
|
||||
override fun createOptionsPanel(): JComponent? {
|
||||
val table = ListTable(ListWrappingTableModel(
|
||||
listOf(methodMatcher.classNames, methodMatcher.methodNamePatterns),
|
||||
InspectionGadgetsBundle.message("column.assertion.class.name"),
|
||||
InspectionGadgetsBundle.message("method.name.regex")
|
||||
))
|
||||
val checkBox1 = CheckBox(
|
||||
InspectionGadgetsBundle.message("assert.keyword.is.considered.an.assertion"), this, "assertKeywordIsAssertion"
|
||||
)
|
||||
val checkBox2 = CheckBox(
|
||||
InspectionGadgetsBundle.message("inspection.test.method.without.assertions.exceptions.option"), this, "ignoreIfExceptionThrown"
|
||||
)
|
||||
val title = InspectionGadgetsBundle.message("test.without.assertion.options.choose.class")
|
||||
return FormBuilder()
|
||||
.addComponentFillVertically(UiUtils.createAddRemoveTreeClassChooserPanel(table, title), 0)
|
||||
.addComponent(checkBox1)
|
||||
.addComponent(checkBox2)
|
||||
.panel
|
||||
}
|
||||
|
||||
override fun readSettings(node: Element) {
|
||||
methodMatcher.readSettings(node)
|
||||
super.readSettings(node)
|
||||
}
|
||||
|
||||
override fun writeSettings(node: Element) {
|
||||
methodMatcher.writeSettings(node)
|
||||
super.writeSettings(node)
|
||||
}
|
||||
|
||||
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor =
|
||||
UastHintedVisitorAdapter.create(
|
||||
holder.file.language,
|
||||
TestMethodWithoutAssertionVisitor(holder, methodMatcher, assertKeywordIsAssertion, ignoreIfExceptionThrown),
|
||||
arrayOf(UMethod::class.java),
|
||||
directOnly = true
|
||||
)
|
||||
}
|
||||
|
||||
private class TestMethodWithoutAssertionVisitor(
|
||||
private val holder: ProblemsHolder,
|
||||
private val methodMatcher: MethodMatcher,
|
||||
private val assertKeywordIsAssertion: Boolean,
|
||||
private val ignoreIfExceptionThrown: Boolean
|
||||
) : AbstractUastNonRecursiveVisitor() {
|
||||
override fun visitMethod(node: UMethod): Boolean {
|
||||
val javaMethod = node.javaPsi
|
||||
if (!TestUtils.isTestMethod(javaMethod)) return true
|
||||
if (TestUtils.hasExpectedExceptionAnnotation(javaMethod)) return true
|
||||
if (ignoreIfExceptionThrown && javaMethod.throwsList.referenceElements.isNotEmpty()) return true
|
||||
if (containsAssertion(node)) return true
|
||||
if (lastStatementIsCallToMethodWithAssertion(node)) return true
|
||||
val message = JvmAnalysisBundle.message("jvm.inspections.test.method.without.assertion.problem.descriptor")
|
||||
holder.registerUProblem(node, message)
|
||||
return true
|
||||
}
|
||||
|
||||
private fun lastStatementIsCallToMethodWithAssertion(method: UMethod): Boolean {
|
||||
val lastExpression = when (method.uastBody) {
|
||||
is UBlockExpression -> method.uastBody.castSafelyTo<UBlockExpression>()?.expressions?.lastOrNull()
|
||||
else -> method.uastBody
|
||||
} ?: return false
|
||||
val callExpression = lastExpression.castSafelyTo<UCallExpression>() ?: return false
|
||||
val targetMethod = callExpression.resolve()?.toUElementOfType<UMethod>() ?: return false
|
||||
return containsAssertion(targetMethod)
|
||||
}
|
||||
|
||||
private fun containsAssertion(element: UMethod): Boolean {
|
||||
val visitor = ContainsAssertionVisitor()
|
||||
element.uastBody?.accept(visitor)
|
||||
return visitor.containsAssertion
|
||||
}
|
||||
|
||||
private inner class ContainsAssertionVisitor : AbstractUastVisitor() {
|
||||
var containsAssertion = false
|
||||
|
||||
override fun visitElement(node: UElement): Boolean {
|
||||
if (containsAssertion) return true
|
||||
if (node.sourcePsi is PsiCompiledElement) return true // we don't expect assertions in libraries
|
||||
return false
|
||||
}
|
||||
|
||||
override fun visitObjectLiteralExpression(node: UObjectLiteralExpression): Boolean = visitCallExpression(node)
|
||||
|
||||
override fun visitCallExpression(node: UCallExpression): Boolean {
|
||||
if (containsAssertion) return true
|
||||
if ((assertKeywordIsAssertion && node.methodIdentifier == null && node.methodName == "assert")
|
||||
|| methodMatcher.matches(node.resolve())) {
|
||||
containsAssertion = true
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.intellij.codeInspection.tests.java.test
|
||||
|
||||
import com.intellij.codeInspection.tests.ULanguage
|
||||
import com.intellij.codeInspection.tests.test.TestMethodWithoutAssertionInspectionTestBase
|
||||
|
||||
class JavaTestMethodWithoutAssertionInspectionTest : TestMethodWithoutAssertionInspectionTestBase() {
|
||||
fun `test highlighting for empty method body`() {
|
||||
myFixture.testHighlighting(ULanguage.JAVA, """
|
||||
import junit.framework.TestCase;
|
||||
import org.junit.Test;
|
||||
import org.junit.Assert;
|
||||
|
||||
public class TestMethodWithoutAssertion extends TestCase {
|
||||
public void <warning descr="Test method 'test()' contains no assertions">test</warning>() { }
|
||||
|
||||
@Test
|
||||
public void <warning descr="Test method 'fourOhTest()' contains no assertions">fourOhTest</warning>() { }
|
||||
|
||||
@Test(expected = Exception.class)
|
||||
public void fourOhTestWithExpected() { }
|
||||
}
|
||||
""".trimIndent(), "TestMethodWithoutAssertion")
|
||||
}
|
||||
|
||||
fun `test no highlighting when assertion is present`() {
|
||||
myFixture.testHighlighting(ULanguage.JAVA, """
|
||||
import junit.framework.TestCase;
|
||||
import org.junit.Test;
|
||||
import org.junit.Assert;
|
||||
import mockit.*;
|
||||
|
||||
public class TestMethodWithoutAssertion extends TestCase {
|
||||
@Test
|
||||
public void fourOhTest2() { Assert.assertTrue(true); }
|
||||
|
||||
public void test2() { assertTrue(true); }
|
||||
|
||||
public void test3() { fail(); }
|
||||
|
||||
@Test
|
||||
public void delegateOnly() { check(); }
|
||||
|
||||
@Test
|
||||
public void assertKeyword() { assert true; }
|
||||
|
||||
@Test
|
||||
public void delegateAdditionally() {
|
||||
final int i = 9;
|
||||
check();
|
||||
}
|
||||
|
||||
private void check() { Assert.assertTrue(true); }
|
||||
|
||||
@Test
|
||||
public void testExecuteReverseAcknowledgement(@Mocked final Object messageDAO) {
|
||||
System.out.println(messageDAO);
|
||||
|
||||
new Verifications() { };
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMethodWhichThrowsExceptionOnFailure() throws AssertionError {
|
||||
if (true) throw new AssertionError();
|
||||
}
|
||||
}
|
||||
""".trimIndent(), "TestMethodWithoutAssertion")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.intellij.codeInspection.tests.kotlin.test
|
||||
|
||||
import com.intellij.codeInspection.tests.ULanguage
|
||||
import com.intellij.codeInspection.tests.test.TestMethodWithoutAssertionInspectionTestBase
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.roots.ContentEntry
|
||||
import com.intellij.openapi.roots.ModifiableRootModel
|
||||
import com.intellij.testFramework.LightProjectDescriptor
|
||||
import com.intellij.testFramework.PsiTestUtil
|
||||
import com.intellij.util.PathUtil
|
||||
import java.io.File
|
||||
|
||||
class KotlinTestMethodWithoutAssertionInspectionTest : TestMethodWithoutAssertionInspectionTestBase() {
|
||||
override fun getProjectDescriptor(): LightProjectDescriptor = object : JUnitProjectDescriptor(sdkLevel) {
|
||||
override fun configureModule(module: Module, model: ModifiableRootModel, contentEntry: ContentEntry) {
|
||||
super.configureModule(module, model, contentEntry)
|
||||
val jar = File(PathUtil.getJarPathForClass(JvmStatic::class.java))
|
||||
PsiTestUtil.addLibrary(model, "kotlin-stdlib", jar.parent, jar.name)
|
||||
}
|
||||
}
|
||||
|
||||
fun `test highlighting for empty method body`() {
|
||||
myFixture.testHighlighting(ULanguage.KOTLIN, """
|
||||
import junit.framework.TestCase
|
||||
import org.junit.Test
|
||||
import org.junit.Assert
|
||||
|
||||
class TestMethodWithoutAssertion : TestCase() {
|
||||
public fun <warning descr="Test method 'test()' contains no assertions">test</warning>() { }
|
||||
|
||||
@Test
|
||||
public fun <warning descr="Test method 'fourOhTest()' contains no assertions">fourOhTest</warning>() { }
|
||||
|
||||
@Test(expected = Exception::class)
|
||||
public fun fourOhTestWithExpected() { }
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
fun `test no highlighting when assertion is present`() {
|
||||
myFixture.testHighlighting(ULanguage.KOTLIN, """
|
||||
import junit.framework.TestCase
|
||||
import org.junit.Test
|
||||
import org.junit.Assert
|
||||
import mockit.*
|
||||
|
||||
class TestMethodWithoutAssertion : TestCase() {
|
||||
//@Test
|
||||
//public fun fourOhTest2() { Assert.assertTrue(true) }
|
||||
//
|
||||
//public fun test2() { assertTrue(true) }
|
||||
//
|
||||
//public fun test3() { fail() }
|
||||
|
||||
@Test
|
||||
public fun delegateOnly() { check() }
|
||||
|
||||
@Test
|
||||
public fun delegateAdditionally() {
|
||||
val i = 9
|
||||
println(i)
|
||||
check()
|
||||
}
|
||||
|
||||
private fun check() { Assert.assertTrue(true) }
|
||||
|
||||
@Test
|
||||
public fun testExecuteReverseAcknowledgement(@Mocked messageDAO: Any) {
|
||||
println(messageDAO)
|
||||
|
||||
object : Verifications() { }
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(AssertionError::class)
|
||||
public fun testMethodWhichThrowsExceptionOnFailure() {
|
||||
if (true) throw AssertionError()
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.intellij.codeInspection.tests.test
|
||||
|
||||
import com.intellij.codeInspection.InspectionProfileEntry
|
||||
import com.intellij.codeInspection.test.TestMethodWithoutAssertionInspection
|
||||
import com.intellij.codeInspection.tests.UastInspectionTestBase
|
||||
import com.intellij.codeInspection.tests.test.junit.addJUnit3Library
|
||||
import com.intellij.codeInspection.tests.test.junit.addJUnit4Library
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.roots.ContentEntry
|
||||
import com.intellij.openapi.roots.ModifiableRootModel
|
||||
import com.intellij.pom.java.LanguageLevel
|
||||
import com.intellij.testFramework.LightProjectDescriptor
|
||||
|
||||
abstract class TestMethodWithoutAssertionInspectionTestBase : UastInspectionTestBase() {
|
||||
override val inspection: InspectionProfileEntry = TestMethodWithoutAssertionInspection().apply {
|
||||
assertKeywordIsAssertion = true
|
||||
ignoreIfExceptionThrown = true
|
||||
}
|
||||
|
||||
override fun getProjectDescriptor(): LightProjectDescriptor = JUnitProjectDescriptor(sdkLevel)
|
||||
|
||||
protected open class JUnitProjectDescriptor(languageLevel: LanguageLevel) : ProjectDescriptor(languageLevel) {
|
||||
override fun configureModule(module: Module, model: ModifiableRootModel, contentEntry: ContentEntry) {
|
||||
super.configureModule(module, model, contentEntry)
|
||||
model.addJUnit3Library()
|
||||
model.addJUnit4Library()
|
||||
}
|
||||
}
|
||||
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
myFixture.addClass("""
|
||||
package mockit;
|
||||
public abstract class Verifications {
|
||||
protected Verifications() { }
|
||||
}
|
||||
""".trimIndent())
|
||||
myFixture.addClass("""
|
||||
package mockit;
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Retention(value=RUNTIME)
|
||||
@Target({FIELD,PARAMETER})
|
||||
public @interface Mocked { }
|
||||
""".trimIndent())
|
||||
}
|
||||
}
|
||||
@@ -519,7 +519,6 @@ asserts.without.messages.display.name=Message missing on assertion
|
||||
constant.naming.convention.element.description=Constant
|
||||
constant.with.mutable.field.naming.convention.element.description=Constant with mutable type
|
||||
random.double.for.random.integer.display.name=Using 'Random.nextDouble()' to get random integer
|
||||
test.method.without.assertion.display.name=JUnit test method without any assertions
|
||||
string.buffer.replaceable.by.string.builder.display.name='StringBuffer' may be 'StringBuilder'
|
||||
comparison.of.short.and.char.display.name=Comparison of 'short' and 'char' values
|
||||
unnecessary.fully.qualified.name.display.name=Unnecessary fully qualified name
|
||||
@@ -1063,7 +1062,6 @@ test.case.with.constructor.problem.descriptor=Initialization logic in constructo
|
||||
test.case.with.constructor.problem.descriptor.initializer=Initialization logic in initializer instead of 'setUp()'
|
||||
misordered.assert.equals.arguments.problem.descriptor=Arguments to <code>#ref()</code> in wrong order #loc
|
||||
simplifiable.junit.assertion.problem.descriptor=<code>#ref()</code> can be simplified to ''{0}'' #loc
|
||||
test.method.without.assertion.problem.descriptor=JUnit test method <code>#ref()</code> contains no assertions #loc
|
||||
test.case.with.no.test.methods.problem.descriptor=Test class <code>#ref</code> has no tests #loc
|
||||
deserializable.class.in.secure.context.problem.descriptor=Class <code>#ref</code> may be deserialized, compromising security #loc
|
||||
serializable.class.in.secure.context.problem.descriptor=Class <code>#ref</code> may be serialized, compromising security #loc
|
||||
|
||||
@@ -1389,10 +1389,6 @@
|
||||
key="test.case.with.no.test.methods.display.name" groupBundle="messages.InspectionsBundle"
|
||||
groupKey="group.names.junit.issues" enabledByDefault="false" level="WARNING"
|
||||
implementationClass="com.siyeh.ig.junit.TestCaseWithNoTestMethodsInspection"/>
|
||||
<localInspection groupPath="Java" language="JAVA" suppressId="JUnitTestMethodWithNoAssertions" shortName="TestMethodWithoutAssertion"
|
||||
bundle="messages.InspectionGadgetsBundle" key="test.method.without.assertion.display.name"
|
||||
groupBundle="messages.InspectionsBundle" groupKey="group.names.junit.issues" enabledByDefault="false" level="WARNING"
|
||||
implementationClass="com.siyeh.ig.junit.TestMethodWithoutAssertionInspection"/>
|
||||
<localInspection groupPath="Java" language="JAVA" shortName="UseOfObsoleteAssert" bundle="messages.InspectionGadgetsBundle" key="usage.of.obsolete.assert.display.name"
|
||||
groupBundle="messages.InspectionsBundle" groupKey="group.names.junit.issues" enabledByDefault="false" level="WARNING"
|
||||
implementationClass="com.siyeh.ig.junit.UseOfObsoleteAssertInspection" cleanupTool="true"/>
|
||||
|
||||
@@ -1,205 +0,0 @@
|
||||
/*
|
||||
* Copyright 2003-2021 Dave Griffith, Bas Leijdekkers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.siyeh.ig.junit;
|
||||
|
||||
import com.intellij.codeInspection.ui.ListTable;
|
||||
import com.intellij.codeInspection.ui.ListWrappingTableModel;
|
||||
import com.intellij.openapi.util.InvalidDataException;
|
||||
import com.intellij.openapi.util.WriteExternalException;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.util.ui.CheckBox;
|
||||
import com.intellij.util.ui.FormBuilder;
|
||||
import com.siyeh.InspectionGadgetsBundle;
|
||||
import com.siyeh.ig.BaseInspection;
|
||||
import com.siyeh.ig.BaseInspectionVisitor;
|
||||
import com.siyeh.ig.psiutils.ControlFlowUtils;
|
||||
import com.siyeh.ig.psiutils.MethodMatcher;
|
||||
import com.siyeh.ig.psiutils.TestUtils;
|
||||
import com.siyeh.ig.ui.UiUtils;
|
||||
import org.intellij.lang.annotations.Pattern;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class TestMethodWithoutAssertionInspection extends BaseInspection {
|
||||
|
||||
protected final MethodMatcher methodMatcher;
|
||||
@SuppressWarnings("PublicField") public boolean assertKeywordIsAssertion;
|
||||
@SuppressWarnings("PublicField") public boolean ignoreIfExceptionThrown;
|
||||
|
||||
public TestMethodWithoutAssertionInspection() {
|
||||
methodMatcher = new MethodMatcher(false, "assertionMethods")
|
||||
.add(JUnitCommonClassNames.ORG_JUNIT_ASSERT, "assert.*|fail.*")
|
||||
.add(JUnitCommonClassNames.JUNIT_FRAMEWORK_ASSERT, "assert.*|fail.*")
|
||||
.add(JUnitCommonClassNames.ORG_JUNIT_JUPITER_API_ASSERTIONS, "assert.*|fail.*")
|
||||
.add("org.assertj.core.api.Assertions", "assertThat")
|
||||
.add("org.assertj.core.api.WithAssertions", "assertThat")
|
||||
.add("com.google.common.truth.Truth", "assert.*")
|
||||
.add("com.google.common.truth.Truth8", "assert.*")
|
||||
.add("org.mockito.Mockito", "verify.*")
|
||||
.add("org.mockito.InOrder", "verify")
|
||||
.add("org.junit.rules.ExpectedException", "expect.*")
|
||||
.add("org.hamcrest.MatcherAssert", "assertThat")
|
||||
.add("mockit.Verifications", "Verifications")
|
||||
.finishDefault();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JComponent createOptionsPanel() {
|
||||
final ListTable table = new ListTable(
|
||||
new ListWrappingTableModel(Arrays.asList(methodMatcher.getClassNames(), methodMatcher.getMethodNamePatterns()),
|
||||
InspectionGadgetsBundle.message("column.assertion.class.name"),
|
||||
InspectionGadgetsBundle.message("method.name.regex")));
|
||||
final CheckBox checkBox1 =
|
||||
new CheckBox(InspectionGadgetsBundle.message("assert.keyword.is.considered.an.assertion"), this, "assertKeywordIsAssertion");
|
||||
final CheckBox checkBox2 =
|
||||
new CheckBox(InspectionGadgetsBundle.message("inspection.test.method.without.assertions.exceptions.option"), this, "ignoreIfExceptionThrown");
|
||||
final String title = InspectionGadgetsBundle.message("test.without.assertion.options.choose.class");
|
||||
return new FormBuilder()
|
||||
.addComponentFillVertically(UiUtils.createAddRemoveTreeClassChooserPanel(table, title), 0)
|
||||
.addComponent(checkBox1)
|
||||
.addComponent(checkBox2)
|
||||
.getPanel();
|
||||
}
|
||||
|
||||
@Pattern(VALID_ID_PATTERN)
|
||||
@Override
|
||||
@NotNull
|
||||
public String getID() {
|
||||
return "JUnitTestMethodWithNoAssertions";
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
protected String buildErrorString(Object... infos) {
|
||||
return InspectionGadgetsBundle.message("test.method.without.assertion.problem.descriptor");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readSettings(@NotNull Element element) throws InvalidDataException {
|
||||
super.readSettings(element);
|
||||
methodMatcher.readSettings(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSettings(@NotNull Element element) throws WriteExternalException {
|
||||
methodMatcher.writeSettings(element);
|
||||
super.writeSettings(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseInspectionVisitor buildVisitor() {
|
||||
return new TestMethodWithoutAssertionVisitor();
|
||||
}
|
||||
|
||||
private class TestMethodWithoutAssertionVisitor extends BaseInspectionVisitor {
|
||||
|
||||
@Override
|
||||
public void visitMethod(@NotNull PsiMethod method) {
|
||||
super.visitMethod(method);
|
||||
if (!TestUtils.isJUnitTestMethod(method)) {
|
||||
return;
|
||||
}
|
||||
if (TestUtils.hasExpectedExceptionAnnotation(method)) {
|
||||
return;
|
||||
}
|
||||
if (ignoreIfExceptionThrown && method.getThrowsList().getReferenceElements().length > 0) {
|
||||
return;
|
||||
}
|
||||
if (containsAssertion(method)) {
|
||||
return;
|
||||
}
|
||||
if (lastStatementIsCallToMethodWithAssertion(method)) {
|
||||
return;
|
||||
}
|
||||
registerMethodError(method);
|
||||
}
|
||||
|
||||
private boolean lastStatementIsCallToMethodWithAssertion(PsiMethod method) {
|
||||
final PsiStatement lastStatement = ControlFlowUtils.getLastStatementInBlock(method.getBody());
|
||||
if (!(lastStatement instanceof PsiExpressionStatement)) {
|
||||
return false;
|
||||
}
|
||||
final PsiExpressionStatement expressionStatement = (PsiExpressionStatement)lastStatement;
|
||||
final PsiExpression expression = expressionStatement.getExpression();
|
||||
if (!(expression instanceof PsiMethodCallExpression)) {
|
||||
return false;
|
||||
}
|
||||
final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)expression;
|
||||
final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
|
||||
final PsiExpression qualifierExpression = methodExpression.getQualifierExpression();
|
||||
if (qualifierExpression != null && !(qualifierExpression instanceof PsiThisExpression)) {
|
||||
return false;
|
||||
}
|
||||
final PsiMethod targetMethod = methodCallExpression.resolveMethod();
|
||||
return containsAssertion(targetMethod);
|
||||
}
|
||||
|
||||
private boolean containsAssertion(PsiElement element) {
|
||||
if (element == null) {
|
||||
return false;
|
||||
}
|
||||
final ContainsAssertionVisitor
|
||||
visitor = new ContainsAssertionVisitor();
|
||||
element.accept(visitor);
|
||||
return visitor.containsAssertion();
|
||||
}
|
||||
}
|
||||
|
||||
private class ContainsAssertionVisitor extends JavaRecursiveElementWalkingVisitor {
|
||||
private boolean containsAssertion;
|
||||
|
||||
@Override
|
||||
public void visitElement(@NotNull PsiElement element) {
|
||||
if ((element instanceof PsiCompiledElement)) {
|
||||
// assume no assertions in libraries (prevents assertion in recursive element walking visitor)
|
||||
return;
|
||||
}
|
||||
if (!containsAssertion) {
|
||||
super.visitElement(element);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCallExpression(@NotNull PsiCallExpression call) {
|
||||
if (containsAssertion) {
|
||||
return;
|
||||
}
|
||||
super.visitCallExpression(call);
|
||||
if (methodMatcher.matches(call)) {
|
||||
containsAssertion = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAssertStatement(@NotNull PsiAssertStatement statement) {
|
||||
if (containsAssertion) {
|
||||
return;
|
||||
}
|
||||
super.visitAssertStatement(statement);
|
||||
if (!assertKeywordIsAssertion) {
|
||||
return;
|
||||
}
|
||||
containsAssertion = true;
|
||||
}
|
||||
|
||||
boolean containsAssertion() {
|
||||
return containsAssertion;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
package com.siyeh.igtest.junit;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import org.junit.Test;
|
||||
import org.junit.Assert;
|
||||
import mockit.*;
|
||||
|
||||
public class TestMethodWithoutAssertion extends TestCase
|
||||
{
|
||||
public TestMethodWithoutAssertion()
|
||||
{
|
||||
}
|
||||
|
||||
public void <warning descr="JUnit test method 'test()' contains no assertions">test</warning>()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void <warning descr="JUnit test method 'fourOhTest()' contains no assertions">fourOhTest</warning>()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Test(expected = Exception.class)
|
||||
public void fourOhTestWithExpected()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fourOhTest2()
|
||||
{
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
public void test2()
|
||||
{
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
public void test3()
|
||||
{
|
||||
fail();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void delegateOnly() {
|
||||
check();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void delegateAdditionally() {
|
||||
final int i = 9;
|
||||
check();
|
||||
}
|
||||
|
||||
private void check() {
|
||||
Assert.assertTrue(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecuteReverseAcknowledgement(@Mocked final Object messageDAO) {
|
||||
System.out.println(messageDAO);
|
||||
|
||||
new Verifications() {{
|
||||
messageDAO.toString();
|
||||
}};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMethodWhichThrowsExceptionOnFailure() throws AssertionError {
|
||||
if (true) throw new AssertionError();
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
*/
|
||||
package com.siyeh.ig.junit;
|
||||
|
||||
import com.intellij.codeInspection.InspectionProfileEntry;
|
||||
import com.siyeh.ig.LightJavaInspectionTestCase;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author Bas Leijdekkers
|
||||
*/
|
||||
public class TestMethodWithoutAssertionInspectionTest extends LightJavaInspectionTestCase {
|
||||
|
||||
public void testTestMethodWithoutAssertion() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String[] getEnvironmentClasses() {
|
||||
return new String[] {
|
||||
"package org.junit;" +
|
||||
"import java.lang.annotation.ElementType;" +
|
||||
"import java.lang.annotation.Retention;" +
|
||||
"import java.lang.annotation.RetentionPolicy;" +
|
||||
"import java.lang.annotation.Target;" +
|
||||
"@Retention(RetentionPolicy.RUNTIME)" +
|
||||
"@Target({ElementType.METHOD})" +
|
||||
"public @interface Test {" +
|
||||
" Class<? extends java.lang.Throwable> expected() default org.junit.Test.None.class;" +
|
||||
"}",
|
||||
|
||||
"package org.junit;" +
|
||||
"public class Assert {" +
|
||||
" static public void assertTrue(boolean condition) {}" +
|
||||
"}",
|
||||
|
||||
"package junit.framework;" +
|
||||
"public class Assert {" +
|
||||
" static public void assertTrue(boolean condition) {}" +
|
||||
" static public void fail() {}" +
|
||||
"}",
|
||||
|
||||
"package junit.framework;" +
|
||||
"public abstract class TestCase extends Assert {}",
|
||||
|
||||
"package mockit;" +
|
||||
"public abstract class Verifications {" +
|
||||
" protected Verifications() {}" +
|
||||
"}",
|
||||
|
||||
"package mockit;" +
|
||||
"@java.lang.annotation.Retention(value=RUNTIME)\n" +
|
||||
"@java.lang.annotation.Target(value={FIELD,PARAMETER})" +
|
||||
"public @interface Mocked {}"
|
||||
};
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected InspectionProfileEntry getInspection() {
|
||||
final TestMethodWithoutAssertionInspection inspection = new TestMethodWithoutAssertionInspection();
|
||||
inspection.ignoreIfExceptionThrown = true;
|
||||
return inspection;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user