Skip to content

CgMethodConstructor refactoring #677

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ package org.utbot.framework.codegen
import org.utbot.framework.DEFAULT_CONCRETE_EXECUTION_TIMEOUT_IN_CHILD_PROCESS_MS
import org.utbot.framework.codegen.model.constructor.builtin.mockitoClassId
import org.utbot.framework.codegen.model.constructor.builtin.ongoingStubbingClassId
import org.utbot.framework.codegen.model.constructor.util.argumentsClassId
import org.utbot.framework.codegen.model.tree.CgClassId
import org.utbot.framework.plugin.api.BuiltinClassId
import org.utbot.framework.plugin.api.ClassId
import org.utbot.framework.plugin.api.CodeGenerationSettingBox
import org.utbot.framework.plugin.api.CodeGenerationSettingItem
import org.utbot.framework.plugin.api.MethodId
import org.utbot.framework.plugin.api.TypeParameters
import org.utbot.framework.plugin.api.isolateCommandLineArgumentsToArgumentFile
import org.utbot.framework.plugin.api.util.booleanArrayClassId
import org.utbot.framework.plugin.api.util.booleanClassId
Expand All @@ -28,6 +30,7 @@ import org.utbot.framework.plugin.api.util.shortArrayClassId
import org.utbot.framework.plugin.api.util.voidClassId
import java.io.File
import org.utbot.framework.plugin.api.util.longClassId
import org.utbot.framework.plugin.api.util.objectArrayClassId
import org.utbot.framework.plugin.api.util.voidWrapperClassId

data class TestClassFile(val packageName: String, val imports: List<Import>, val testClass: String)
Expand Down Expand Up @@ -184,6 +187,7 @@ sealed class TestFramework(
abstract val methodSourceAnnotationId: ClassId
abstract val methodSourceAnnotationFqn: String
abstract val nestedClassesShouldBeStatic: Boolean
abstract val argListClassId: ClassId

val assertEquals by lazy { assertionId("assertEquals", objectClassId, objectClassId) }

Expand Down Expand Up @@ -304,6 +308,28 @@ object TestNg : TestFramework(displayName = "TestNG") {

override val nestedClassesShouldBeStatic = true

override val argListClassId: ClassId
get() {
val outerArrayId = Array<Array<Any?>?>::class.id
val innerArrayId = BuiltinClassId(
name = objectArrayClassId.name,
simpleName = objectArrayClassId.simpleName,
canonicalName = objectArrayClassId.canonicalName,
packageName = objectArrayClassId.packageName,
elementClassId = objectClassId,
typeParameters = TypeParameters(listOf(objectClassId))
)

return BuiltinClassId(
name = outerArrayId.name,
simpleName = outerArrayId.simpleName,
canonicalName = outerArrayId.canonicalName,
packageName = outerArrayId.packageName,
elementClassId = innerArrayId,
typeParameters = TypeParameters(listOf(innerArrayId))
)
}

@OptIn(ExperimentalStdlibApi::class)
override fun getRunTestsCommand(
executionInvoke: String,
Expand Down Expand Up @@ -349,14 +375,21 @@ object TestNg : TestFramework(displayName = "TestNG") {
}

object Junit4 : TestFramework("JUnit4") {
private val parametrizedTestsNotSupportedError: Nothing
get() = error("Parametrized tests are not supported for JUnit4")

override val mainPackage: String = JUNIT4_PACKAGE
override val testAnnotation = "@$mainPackage.Test"
override val testAnnotationFqn: String = "$mainPackage.Test"

override val parameterizedTestAnnotation = "Parameterized tests are not supported for JUnit4"
override val parameterizedTestAnnotationFqn = "Parameterized tests are not supported for JUnit4"
override val methodSourceAnnotation = "Parameterized tests are not supported for JUnit4"
override val methodSourceAnnotationFqn = "Parameterized tests are not supported for JUnit4"
override val parameterizedTestAnnotation
get() = parametrizedTestsNotSupportedError
override val parameterizedTestAnnotationFqn
get() = parametrizedTestsNotSupportedError
override val methodSourceAnnotation
get() = parametrizedTestsNotSupportedError
override val methodSourceAnnotationFqn
get() = parametrizedTestsNotSupportedError

override val testAnnotationId = BuiltinClassId(
name = "$JUNIT4_PACKAGE.Test",
Expand Down Expand Up @@ -390,6 +423,9 @@ object Junit4 : TestFramework("JUnit4") {

override val nestedClassesShouldBeStatic = true

override val argListClassId: ClassId
get() = parametrizedTestsNotSupportedError

@OptIn(ExperimentalStdlibApi::class)
override fun getRunTestsCommand(
executionInvoke: String,
Expand Down Expand Up @@ -514,6 +550,18 @@ object Junit5 : TestFramework("JUnit5") {

override val nestedClassesShouldBeStatic = false

override val argListClassId: ClassId
get() {
val arrayListId = java.util.ArrayList::class.id
return BuiltinClassId(
name = arrayListId.name,
simpleName = arrayListId.simpleName,
canonicalName = arrayListId.canonicalName,
packageName = arrayListId.packageName,
typeParameters = TypeParameters(listOf(argumentsClassId))
)
}

private const val junitVersion = "1.7.1" // TODO read it from gradle.properties
private const val platformJarName: String = "junit-platform-console-standalone-$junitVersion.jar"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,15 @@ package org.utbot.framework.codegen.model.constructor.tree
import org.utbot.common.PathUtil
import org.utbot.framework.assemble.assemble
import org.utbot.framework.codegen.ForceStaticMocking
import org.utbot.framework.codegen.Junit4
import org.utbot.framework.codegen.Junit5
import org.utbot.framework.codegen.ParametrizedTestSource
import org.utbot.framework.codegen.RuntimeExceptionTestsBehaviour.PASS
import org.utbot.framework.codegen.TestNg
import org.utbot.framework.codegen.model.constructor.CgMethodTestSet
import org.utbot.framework.codegen.model.constructor.builtin.closeMethodIdOrNull
import org.utbot.framework.codegen.model.constructor.builtin.forName
import org.utbot.framework.codegen.model.constructor.builtin.getClass
import org.utbot.framework.codegen.model.constructor.builtin.getTargetException
import org.utbot.framework.codegen.model.constructor.builtin.invoke
import org.utbot.framework.codegen.model.constructor.builtin.newInstance
import org.utbot.framework.codegen.model.constructor.builtin.setArrayElement
import org.utbot.framework.codegen.model.constructor.context.CgContext
import org.utbot.framework.codegen.model.constructor.context.CgContextOwner
import org.utbot.framework.codegen.model.constructor.util.CgComponents
Expand All @@ -26,9 +22,9 @@ import org.utbot.framework.codegen.model.constructor.util.classCgClassId
import org.utbot.framework.codegen.model.constructor.util.needExpectedDeclaration
import org.utbot.framework.codegen.model.constructor.util.overridesEquals
import org.utbot.framework.codegen.model.constructor.util.plus
import org.utbot.framework.codegen.model.constructor.util.setArgumentsArrayElement
import org.utbot.framework.codegen.model.constructor.util.typeCast
import org.utbot.framework.codegen.model.tree.CgAllocateArray
import org.utbot.framework.codegen.model.tree.CgAnnotation
import org.utbot.framework.codegen.model.tree.CgArrayElementAccess
import org.utbot.framework.codegen.model.tree.CgClassId
import org.utbot.framework.codegen.model.tree.CgDeclaration
Expand Down Expand Up @@ -69,7 +65,6 @@ import org.utbot.framework.codegen.model.tree.buildParameterizedTestDataProvider
import org.utbot.framework.codegen.model.tree.buildTestMethod
import org.utbot.framework.codegen.model.tree.convertDocToCg
import org.utbot.framework.codegen.model.tree.toStatement
import org.utbot.framework.codegen.model.util.at
import org.utbot.framework.codegen.model.util.canBeSetIn
import org.utbot.framework.codegen.model.util.equalTo
import org.utbot.framework.codegen.model.util.get
Expand Down Expand Up @@ -116,7 +111,6 @@ import org.utbot.framework.plugin.api.UtVoidModel
import org.utbot.framework.plugin.api.onFailure
import org.utbot.framework.plugin.api.onSuccess
import org.utbot.framework.plugin.api.util.booleanClassId
import org.utbot.framework.plugin.api.util.builtinStaticMethodId
import org.utbot.framework.plugin.api.util.doubleArrayClassId
import org.utbot.framework.plugin.api.util.doubleClassId
import org.utbot.framework.plugin.api.util.doubleWrapperClassId
Expand All @@ -137,7 +131,6 @@ import org.utbot.framework.plugin.api.util.isPrimitiveWrapper
import org.utbot.framework.plugin.api.util.isRefType
import org.utbot.framework.plugin.api.util.jClass
import org.utbot.framework.plugin.api.util.kClass
import org.utbot.framework.plugin.api.util.methodId
import org.utbot.framework.plugin.api.util.objectArrayClassId
import org.utbot.framework.plugin.api.util.objectClassId
import org.utbot.framework.plugin.api.util.stringClassId
Expand Down Expand Up @@ -1317,7 +1310,7 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
return withDataProviderScope {
dataProviderMethod(dataProviderMethodName) {
val argListLength = testSet.executions.size
val argListVariable = createArgList(argListLength)
val argListVariable = testFrameworkManager.createArgList(argListLength, "argList")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should not pass "argList" as an argument. Just use "argList" inside of createArgList() method like it was done before.


emptyLine()

Expand Down Expand Up @@ -1432,161 +1425,15 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
CgAllocateArray(objectArrayClassId, objectClassId, arguments.size)
}
for ((i, argument) in arguments.withIndex()) {
setArgumentsArrayElement(argsArray, i, argument)
}
when (testFramework) {
Junit5 -> {
+argsVariable[addToListMethodId](
argumentsClassId[argumentsMethodId](argsArray)
)
}
TestNg -> {
setArgumentsArrayElement(argsVariable, executionIndex, argsArray)
}
Junit4 -> error("Parameterized tests are not supported for JUnit4")
}
}

/**
* Sets an element of arguments array in parameterized test,
* if test framework represents arguments as array.
*/
private fun setArgumentsArrayElement(array: CgVariable, index: Int, value: CgExpression) {
when (array.type) {
objectClassId -> {
+java.lang.reflect.Array::class.id[setArrayElement](array, index, value)
}
else -> array.at(index) `=` value
setArgumentsArrayElement(argsArray, i, argument, this)
}
testFrameworkManager.passArgumentsToArgsVariable(argsVariable, argsArray, executionIndex)
}

/**
* Creates annotations for data provider method in parameterized tests
* depending on test framework.
*/
private fun createDataProviderAnnotations(dataProviderMethodName: String?): MutableList<CgAnnotation> =
when (testFramework) {
Junit5 -> mutableListOf()
TestNg -> mutableListOf(
annotation(
testFramework.methodSourceAnnotationId,
listOf("name" to CgLiteral(stringClassId, dataProviderMethodName))
),
)
Junit4 -> error("Parameterized tests are not supported for JUnit4")
}

/**
* Creates declaration of argList collection in parameterized tests.
*/
private fun createArgList(length: Int): CgVariable {
val argListName = "argList"
return when (testFramework) {
Junit5 ->
newVar(argListClassId, argListName) {
val constructor = ConstructorId(argListClassId, emptyList())
constructor.invoke()
}
TestNg ->
newVar(argListClassId, argListName) {
CgAllocateArray(argListClassId, Array<Any>::class.java.id, length)
}
Junit4 -> error("Parameterized tests are not supported for JUnit4")
}
}

/**
* Creates a [ClassId] for arguments collection.
*/
private val argListClassId: ClassId
get() = when (testFramework) {
Junit5 -> {
val arrayListId = java.util.ArrayList::class.id
BuiltinClassId(
name = arrayListId.name,
simpleName = arrayListId.simpleName,
canonicalName = arrayListId.canonicalName,
packageName = arrayListId.packageName,
typeParameters = TypeParameters(listOf(argumentsClassId))
)
}
TestNg -> {
val outerArrayId = Array<Array<Any?>?>::class.id
val innerArrayId = BuiltinClassId(
name = objectArrayClassId.name,
simpleName = objectArrayClassId.simpleName,
canonicalName = objectArrayClassId.canonicalName,
packageName = objectArrayClassId.packageName,
elementClassId = objectClassId,
typeParameters = TypeParameters(listOf(objectClassId))
)

BuiltinClassId(
name = outerArrayId.name,
simpleName = outerArrayId.simpleName,
canonicalName = outerArrayId.canonicalName,
packageName = outerArrayId.packageName,
elementClassId = innerArrayId,
typeParameters = TypeParameters(listOf(innerArrayId))
)
}
Junit4 -> error("Parameterized tests are not supported for JUnit4")
}


/**
* A [MethodId] to add an item into [ArrayList].
*/
private val addToListMethodId: MethodId
get() = methodId(
classId = ArrayList::class.id,
name = "add",
returnType = booleanClassId,
arguments = arrayOf(Object::class.id),
)

/**
* A [ClassId] of class `org.junit.jupiter.params.provider.Arguments`
*/
private val argumentsClassId: BuiltinClassId
get() = BuiltinClassId(
name = "org.junit.jupiter.params.provider.Arguments",
simpleName = "Arguments",
canonicalName = "org.junit.jupiter.params.provider.Arguments",
packageName = "org.junit.jupiter.params.provider"
)

/**
* A [MethodId] to call JUnit Arguments method.
*/
private val argumentsMethodId: BuiltinMethodId
get() = builtinStaticMethodId(
classId = argumentsClassId,
name = "arguments",
returnType = argumentsClassId,
// vararg of Objects
arguments = arrayOf(objectArrayClassId)
)

private fun containsFailureExecution(testSet: CgMethodTestSet) =
testSet.executions.any { it.result is UtExecutionFailure }


private fun collectParameterizedTestAnnotations(dataProviderMethodName: String?): Set<CgAnnotation> =
when (testFramework) {
Junit5 -> setOf(
annotation(testFramework.parameterizedTestAnnotationId),
annotation(testFramework.methodSourceAnnotationId, "${outerMostTestClass.canonicalName}#$dataProviderMethodName"),
)
TestNg -> setOf(
annotation(
testFramework.parameterizedTestAnnotationId,
listOf("dataProvider" to CgLiteral(stringClassId, dataProviderMethodName))
),
)
Junit4 -> error("Parameterized tests are not supported for JUnit4")
}

private fun testMethod(
methodName: String,
displayName: String?,
Expand All @@ -1596,26 +1443,13 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
body: () -> Unit,
): CgTestMethod {
collectedMethodAnnotations += if (parameterized) {
collectParameterizedTestAnnotations(dataProviderMethodName)
testFrameworkManager.collectParameterizedTestAnnotations(dataProviderMethodName)
} else {
setOf(annotation(testFramework.testAnnotationId))
}

/* Add a short test's description depending on the test framework type:
DisplayName annotation in case of JUni5, and description argument to Test annotation in case of TestNG.
*/
if (displayName != null) {
when (testFramework) {
is Junit5 -> {
displayName.let { testFrameworkManager.addDisplayName(it) }
}
is TestNg -> {
testFrameworkManager.addTestDescription(displayName)
}
else -> {
// nothing
}
}
displayName?.let {
testFrameworkManager.addTestDescription(displayName)
}

val result = currentExecution!!.result
Expand Down Expand Up @@ -1676,12 +1510,12 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
private fun dataProviderMethod(dataProviderMethodName: String, body: () -> Unit): CgParameterizedTestDataProviderMethod {
return buildParameterizedTestDataProviderMethod {
name = dataProviderMethodName
returnType = argListClassId
returnType = testFramework.argListClassId
statements = block(body)
// Exceptions and annotations assignment must run after the statements block is build,
// because we collect info about exceptions and required annotations while building the statements
exceptions += collectedExceptions
annotations += createDataProviderAnnotations(dataProviderMethodName)
annotations += testFrameworkManager.createDataProviderAnnotations(dataProviderMethodName)
}
}

Expand Down
Loading