mirror of
https://github.com/github/codeql.git
synced 2025-12-19 02:13:17 +01:00
364 lines
10 KiB
Plaintext
364 lines
10 KiB
Plaintext
/**
|
|
* Provides classes and predicates for working with test classes and methods.
|
|
*/
|
|
|
|
import Type
|
|
import Member
|
|
import semmle.code.java.frameworks.JUnitAnnotations
|
|
|
|
/** The Java class `junit.framework.TestCase`. */
|
|
class TypeJUnitTestCase extends RefType {
|
|
TypeJUnitTestCase() { this.hasQualifiedName("junit.framework", "TestCase") }
|
|
}
|
|
|
|
/** The Java interface `junit.framework.Test`. */
|
|
class TypeJUnitTest extends RefType {
|
|
TypeJUnitTest() { this.hasQualifiedName("junit.framework", "Test") }
|
|
}
|
|
|
|
/** The Java class `junit.framework.TestSuite`. */
|
|
class TypeJUnitTestSuite extends RefType {
|
|
TypeJUnitTestSuite() { this.hasQualifiedName("junit.framework", "TestSuite") }
|
|
}
|
|
|
|
/** A JUnit 3.8 test class. */
|
|
class JUnit38TestClass extends Class {
|
|
JUnit38TestClass() { exists(TypeJUnitTestCase tc | this.hasSupertype+(tc)) }
|
|
}
|
|
|
|
/** A JUnit 3.8 `tearDown` method. */
|
|
class TearDownMethod extends Method {
|
|
TearDownMethod() {
|
|
this.hasName("tearDown") and
|
|
this.hasNoParameters() and
|
|
this.getReturnType().hasName("void") and
|
|
exists(Method m | m.getDeclaringType() instanceof TypeJUnitTestCase | this.overrides*(m))
|
|
}
|
|
}
|
|
|
|
private class TestRelatedAnnotation extends Annotation {
|
|
TestRelatedAnnotation() {
|
|
this.getType()
|
|
.getPackage()
|
|
.hasName([
|
|
"org.testng.annotations", "org.junit", "org.junit.runner", "org.junit.jupiter.api",
|
|
"org.junit.jupiter.params"
|
|
])
|
|
}
|
|
}
|
|
|
|
private class TestRelatedMethod extends Method {
|
|
TestRelatedMethod() { this.getAnAnnotation() instanceof TestRelatedAnnotation }
|
|
}
|
|
|
|
/**
|
|
* A class detected to be a test class, either because it or one of its super-types
|
|
* and/or enclosing types contains a test method or method with a unit-test-related
|
|
* annotation.
|
|
*/
|
|
class TestClass extends Class {
|
|
TestClass() {
|
|
this instanceof JUnit38TestClass or
|
|
exists(TestMethod m | m.getDeclaringType() = this) or
|
|
exists(TestRelatedMethod m | m.getDeclaringType() = this) or
|
|
this.getASourceSupertype() instanceof TestClass or
|
|
this.getEnclosingType() instanceof TestClass
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A class that is likely a test class. That is either a definite test class, or
|
|
* a class whose name, package, or location suggests that it might be a test class.
|
|
*/
|
|
class LikelyTestClass extends Class {
|
|
LikelyTestClass() {
|
|
this instanceof TestClass or
|
|
this.getName().toLowerCase().matches("%test%") or
|
|
this.getPackage().getName().toLowerCase().matches("%test%") or
|
|
this.getLocation().getFile().getAbsolutePath().matches("%/src/test/java%")
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A test method declared within a JUnit 3.8 test class.
|
|
*/
|
|
class JUnit3TestMethod extends Method {
|
|
JUnit3TestMethod() {
|
|
this.isPublic() and
|
|
this.getDeclaringType() instanceof JUnit38TestClass and
|
|
this.getName().matches("test%") and
|
|
this.getReturnType().hasName("void") and
|
|
this.hasNoParameters()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A JUnit 3.8 test suite method.
|
|
*/
|
|
class JUnit3TestSuite extends Method {
|
|
JUnit3TestSuite() {
|
|
this.isPublic() and
|
|
this.isStatic() and
|
|
(
|
|
this.getDeclaringType() instanceof JUnit38TestClass or
|
|
this.getDeclaringType().getAnAncestor() instanceof TypeJUnitTestSuite
|
|
) and
|
|
this.hasName("suite") and
|
|
this.getReturnType() instanceof TypeJUnitTest and
|
|
this.hasNoParameters()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A JUnit test method that is annotated with the `org.junit.Test` annotation.
|
|
*/
|
|
class JUnit4TestMethod extends Method {
|
|
JUnit4TestMethod() { this.getAnAnnotation().getType().hasQualifiedName("org.junit", "Test") }
|
|
}
|
|
|
|
/**
|
|
* A JUnit test method that is annotated with the `org.junit.jupiter.api.Test` annotation.
|
|
*/
|
|
class JUnitJupiterTestMethod extends Method {
|
|
JUnitJupiterTestMethod() {
|
|
this.getAnAnnotation().getType().hasQualifiedName("org.junit.jupiter.api", "Test")
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A JUnit `@Ignore` annotation.
|
|
*/
|
|
class JUnitIgnoreAnnotation extends Annotation {
|
|
JUnitIgnoreAnnotation() { this.getType().hasQualifiedName("org.junit", "Ignore") }
|
|
}
|
|
|
|
/**
|
|
* A method which, directly or indirectly, is treated as ignored by JUnit due to a `@Ignore`
|
|
* annotation.
|
|
*/
|
|
class JUnitIgnoredMethod extends Method {
|
|
JUnitIgnoredMethod() {
|
|
this.getAnAnnotation() instanceof JUnitIgnoreAnnotation
|
|
or
|
|
exists(Class c | c = this.getDeclaringType() |
|
|
c.getAnAnnotation() instanceof JUnitIgnoreAnnotation
|
|
)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* An annotation in TestNG.
|
|
*/
|
|
class TestNGAnnotation extends Annotation {
|
|
TestNGAnnotation() { this.getType().getPackage().hasName("org.testng.annotations") }
|
|
}
|
|
|
|
/**
|
|
* An annotation of type `org.test.ng.annotations.Test`.
|
|
*/
|
|
class TestNGTestAnnotation extends TestNGAnnotation {
|
|
TestNGTestAnnotation() { this.getType().hasName("Test") }
|
|
}
|
|
|
|
/**
|
|
* A TestNG test method, annotated with the `org.testng.annotations.Test` annotation.
|
|
*/
|
|
class TestNGTestMethod extends Method {
|
|
TestNGTestMethod() { this.getAnAnnotation() instanceof TestNGTestAnnotation }
|
|
|
|
/**
|
|
* Identify a possible `DataProvider` for this method, if the annotation includes a `dataProvider`
|
|
* value.
|
|
*/
|
|
TestNGDataProviderMethod getADataProvider() {
|
|
exists(TestNGTestAnnotation testAnnotation |
|
|
testAnnotation = this.getAnAnnotation() and
|
|
// The data provider must have the same name as the referenced data provider
|
|
result.getDataProviderName() = testAnnotation.getStringValue("dataProvider")
|
|
|
|
|
// Either the data provider should be on the current class, or a supertype
|
|
this.getDeclaringType().getAnAncestor() = result.getDeclaringType()
|
|
or
|
|
// Or the data provider class should be declared
|
|
result.getDeclaringType() = testAnnotation.getTypeValue("dataProviderClass")
|
|
)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Any method detected to be a test method of a common testing framework,
|
|
* including JUnit and TestNG.
|
|
*/
|
|
class TestMethod extends Method {
|
|
TestMethod() {
|
|
this instanceof JUnit3TestMethod or
|
|
this instanceof JUnit4TestMethod or
|
|
this instanceof JUnitJupiterTestMethod or
|
|
this instanceof TestNGTestMethod
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A method that is likely a test method.
|
|
*/
|
|
class LikelyTestMethod extends Method {
|
|
LikelyTestMethod() {
|
|
this.getDeclaringType() instanceof LikelyTestClass
|
|
or
|
|
this instanceof TestMethod
|
|
or
|
|
this instanceof LikelyJunitTest
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A `Method` that is public, has no parameters,
|
|
* has a "void" return type, AND either has a name that starts with "test" OR
|
|
* has an annotation that ends with "Test"
|
|
*/
|
|
class LikelyJunitTest extends Method {
|
|
LikelyJunitTest() {
|
|
this.isPublic() and
|
|
this.getReturnType().hasName("void") and
|
|
this.hasNoParameters() and
|
|
(
|
|
this.getName().matches("JUnit%") or
|
|
this.getName().matches("test%") or
|
|
this.getAnAnnotation().getType().getName().matches("%Test")
|
|
)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A TestNG annotation used to mark a method that runs "before".
|
|
*/
|
|
class TestNGBeforeAnnotation extends TestNGAnnotation {
|
|
TestNGBeforeAnnotation() { this.getType().getName().matches("Before%") }
|
|
}
|
|
|
|
/**
|
|
* A TestNG annotation used to mark a method that runs "after".
|
|
*/
|
|
class TestNGAfterAnnotation extends TestNGAnnotation {
|
|
TestNGAfterAnnotation() { this.getType().getName().matches("After%") }
|
|
}
|
|
|
|
/**
|
|
* An annotation of type `org.testng.annotations.DataProvider` which is applied to methods to mark
|
|
* them as data provider methods for TestNG.
|
|
*/
|
|
class TestNGDataProviderAnnotation extends TestNGAnnotation {
|
|
TestNGDataProviderAnnotation() { this.getType().hasName("DataProvider") }
|
|
}
|
|
|
|
/**
|
|
* An annotation of type `org.testng.annotations.Factory` which is applied to methods to mark
|
|
* them as factory methods for TestNG.
|
|
*/
|
|
class TestNGFactoryAnnotation extends TestNGAnnotation {
|
|
TestNGFactoryAnnotation() { this.getType().hasName("Factory") }
|
|
}
|
|
|
|
/**
|
|
* An annotation of type `org.testng.annotations.Listeners` which is applied to classes to define
|
|
* which listeners apply to them.
|
|
*/
|
|
class TestNGListenersAnnotation extends TestNGAnnotation {
|
|
TestNGListenersAnnotation() { this.getType().hasName("Listeners") }
|
|
|
|
/**
|
|
* Gets a listener defined in this annotation.
|
|
*/
|
|
TestNGListenerImpl getAListener() { result = this.getATypeArrayValue("value") }
|
|
}
|
|
|
|
/**
|
|
* A concrete implementation class of one or more of the TestNG listener interfaces.
|
|
*/
|
|
class TestNGListenerImpl extends Class {
|
|
TestNGListenerImpl() { this.getAnAncestor().hasQualifiedName("org.testng", "ITestNGListener") }
|
|
}
|
|
|
|
/**
|
|
* A method annotated with `org.testng.annotations.DataProvider` marking it as a data provider method
|
|
* for TestNG.
|
|
*
|
|
* This data provider method can be referenced by "name", and used by the test framework to provide
|
|
* an instance of a particular value when running a test method.
|
|
*/
|
|
class TestNGDataProviderMethod extends Method {
|
|
TestNGDataProviderMethod() { this.getAnAnnotation() instanceof TestNGDataProviderAnnotation }
|
|
|
|
/**
|
|
* Gets the name associated with this data provider.
|
|
*/
|
|
string getDataProviderName() {
|
|
result =
|
|
this.getAnAnnotation()
|
|
.(TestNGDataProviderAnnotation)
|
|
.getValue("name")
|
|
.(StringLiteral)
|
|
.getValue()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A constructor or method annotated with `org.testng.annotations.Factory` marking it as a factory
|
|
* for TestNG.
|
|
*
|
|
* This factory callable is used to generate instances of parameterized test classes.
|
|
*/
|
|
class TestNGFactoryCallable extends Callable {
|
|
TestNGFactoryCallable() { this.getAnAnnotation() instanceof TestNGFactoryAnnotation }
|
|
}
|
|
|
|
/**
|
|
* A class that will be run using the `org.junit.runners.Parameterized` JUnit runner.
|
|
*/
|
|
class ParameterizedJUnitTest extends Class {
|
|
ParameterizedJUnitTest() {
|
|
this.getAnAnnotation()
|
|
.(RunWithAnnotation)
|
|
.getRunner()
|
|
.(Class)
|
|
.hasQualifiedName("org.junit.runners", "Parameterized")
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A `@Category` annotation on a class or method, that categorizes the annotated test.
|
|
*/
|
|
class JUnitCategoryAnnotation extends Annotation {
|
|
JUnitCategoryAnnotation() {
|
|
this.getType().hasQualifiedName("org.junit.experimental.categories", "Category")
|
|
}
|
|
|
|
/**
|
|
* One of the categories that this test is categorized as.
|
|
*/
|
|
Type getACategory() {
|
|
exists(TypeLiteral literal, Expr value |
|
|
value = this.getValue("value") and
|
|
(
|
|
literal = value or
|
|
literal = value.(ArrayCreationExpr).getInit().getAnInit()
|
|
)
|
|
|
|
|
result = literal.getReferencedType()
|
|
)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A test class that will be run with theories.
|
|
*/
|
|
class JUnitTheoryTest extends Class {
|
|
JUnitTheoryTest() {
|
|
this.getAnAnnotation()
|
|
.(RunWithAnnotation)
|
|
.getRunner()
|
|
.(Class)
|
|
.hasQualifiedName("org.junit.experimental.theories", "Theories")
|
|
}
|
|
}
|