From eea6b68ecd0b5eddc33a4a79c30482e336903106 Mon Sep 17 00:00:00 2001 From: Ivan Volkov Date: Fri, 5 Aug 2022 18:56:13 +0300 Subject: [PATCH 1/2] Refactored CgMethodConstructor --- .../org/utbot/framework/codegen/Domain.kt | 51 ++++- .../constructor/tree/CgMethodConstructor.kt | 184 +----------------- .../constructor/tree/TestFrameworkManager.kt | 156 ++++++++++++--- .../constructor/util/ConstructorUtils.kt | 61 ++++++ 4 files changed, 250 insertions(+), 202 deletions(-) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/Domain.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/Domain.kt index 744d9f9795..122fb4e281 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/Domain.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/Domain.kt @@ -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 @@ -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, val testClass: String) @@ -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) } @@ -304,6 +308,28 @@ object TestNg : TestFramework(displayName = "TestNG") { override val nestedClassesShouldBeStatic = true + override val argListClassId: ClassId + get() { + val outerArrayId = Array?>::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, @@ -349,14 +375,16 @@ object TestNg : TestFramework(displayName = "TestNG") { } object Junit4 : TestFramework("JUnit4") { + private val parametrizedTestsNotSupportedError: Nothing = 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 = parametrizedTestsNotSupportedError + override val parameterizedTestAnnotationFqn = parametrizedTestsNotSupportedError + override val methodSourceAnnotation = parametrizedTestsNotSupportedError + override val methodSourceAnnotationFqn = parametrizedTestsNotSupportedError override val testAnnotationId = BuiltinClassId( name = "$JUNIT4_PACKAGE.Test", @@ -390,6 +418,9 @@ object Junit4 : TestFramework("JUnit4") { override val nestedClassesShouldBeStatic = true + override val argListClassId: ClassId + get() = parametrizedTestsNotSupportedError + @OptIn(ExperimentalStdlibApi::class) override fun getRunTestsCommand( executionInvoke: String, @@ -514,6 +545,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" diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgMethodConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgMethodConstructor.kt index 4e67cd83b9..58a51db1dd 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgMethodConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgMethodConstructor.kt @@ -3,11 +3,8 @@ 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 @@ -15,7 +12,6 @@ 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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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") emptyLine() @@ -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 = - 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::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?>::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 = - 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?, @@ -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 @@ -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) } } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/TestFrameworkManager.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/TestFrameworkManager.kt index 6fc298dd80..b94ead991b 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/TestFrameworkManager.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/TestFrameworkManager.kt @@ -15,8 +15,13 @@ import org.utbot.framework.codegen.model.constructor.builtin.streamsDeepEqualsMe 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 +import org.utbot.framework.codegen.model.constructor.util.addToListMethodId +import org.utbot.framework.codegen.model.constructor.util.argumentsClassId +import org.utbot.framework.codegen.model.constructor.util.argumentsMethodId import org.utbot.framework.codegen.model.constructor.util.classCgClassId import org.utbot.framework.codegen.model.constructor.util.importIfNeeded +import org.utbot.framework.codegen.model.constructor.util.setArgumentsArrayElement +import org.utbot.framework.codegen.model.tree.CgAllocateArray import org.utbot.framework.codegen.model.tree.CgAnnotation import org.utbot.framework.codegen.model.tree.CgEnumConstantAccess import org.utbot.framework.codegen.model.tree.CgExpression @@ -29,6 +34,7 @@ import org.utbot.framework.codegen.model.tree.CgMultipleArgsAnnotation import org.utbot.framework.codegen.model.tree.CgNamedAnnotationArgument import org.utbot.framework.codegen.model.tree.CgSingleArgAnnotation import org.utbot.framework.codegen.model.tree.CgValue +import org.utbot.framework.codegen.model.tree.CgVariable import org.utbot.framework.codegen.model.util.classLiteralAnnotationArgument import org.utbot.framework.codegen.model.util.isAccessibleFrom import org.utbot.framework.codegen.model.util.resolve @@ -36,6 +42,7 @@ import org.utbot.framework.codegen.model.util.stringLiteral import org.utbot.framework.plugin.api.BuiltinMethodId import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.CodegenLanguage +import org.utbot.framework.plugin.api.ConstructorId import org.utbot.framework.plugin.api.util.booleanArrayClassId import org.utbot.framework.plugin.api.util.byteArrayClassId import org.utbot.framework.plugin.api.util.charArrayClassId @@ -45,6 +52,7 @@ import org.utbot.framework.plugin.api.util.id import org.utbot.framework.plugin.api.util.intArrayClassId import org.utbot.framework.plugin.api.util.longArrayClassId import org.utbot.framework.plugin.api.util.shortArrayClassId +import org.utbot.framework.plugin.api.util.stringClassId import java.util.concurrent.TimeUnit @Suppress("MemberVisibilityCanBePrivate") @@ -169,6 +177,20 @@ internal abstract class TestFrameworkManager(val context: CgContext) // TestNg allows both approaches, we use similar to JUnit5 abstract fun expectException(exception: ClassId, block: () -> Unit) + /** + * Creates annotations for data provider method in parameterized tests + */ + abstract fun createDataProviderAnnotations(dataProviderMethodName: String?): MutableList + + /** + * Creates declaration of argList collection in parameterized tests. + */ + abstract fun createArgList(length: Int, argListName: String): CgVariable + + abstract fun collectParameterizedTestAnnotations(dataProviderMethodName: String?): Set + + abstract fun passArgumentsToArgsVariable(argsVariable: CgVariable, argsArray: CgVariable, executionIndex: Int) + open fun expectTimeout(timeoutMs: Long, block: () -> Unit) {} open fun setTestExecutionTimeout(timeoutMs: Long) { @@ -188,28 +210,26 @@ internal abstract class TestFrameworkManager(val context: CgContext) } } + /** - * Supplements TestNG @Test annotation with a description. - * It looks like @Test(description="...") - * - * Should be used only with TestNG. - * @see issue-576 on GitHub + * Add a short test's description depending on the test framework type: */ - open fun addTestDescription(description: String?) { - if (description == null) return - val testAnnotation = - collectedMethodAnnotations.singleOrNull { it.classId == testFramework.testAnnotationId } - - val descriptionArgument = CgNamedAnnotationArgument("description", stringLiteral(description)) - if (testAnnotation is CgMultipleArgsAnnotation) { - testAnnotation.arguments += descriptionArgument - } else { - collectedMethodAnnotations += CgMultipleArgsAnnotation( - testFramework.testAnnotationId, - mutableListOf(descriptionArgument) - ) - } - } + abstract fun addTestDescription(description: String) +// { +// if (description == null) return +// val testAnnotation = +// collectedMethodAnnotations.singleOrNull { it.classId == testFramework.testAnnotationId } +// +// val descriptionArgument = CgNamedAnnotationArgument("description", stringLiteral(description)) +// if (testAnnotation is CgMultipleArgsAnnotation) { +// testAnnotation.arguments += descriptionArgument +// } else { +// collectedMethodAnnotations += CgMultipleArgsAnnotation( +// testFramework.testAnnotationId, +// mutableListOf(descriptionArgument) +// ) +// } +// } abstract fun disableTestMethod(reason: String) @@ -280,6 +300,52 @@ internal class TestNgManager(context: CgContext) : TestFrameworkManager(context) +assertions[assertThrows](exception.toExceptionClass(), lambda) } + override fun createDataProviderAnnotations(dataProviderMethodName: String?) = + mutableListOf( + statementConstructor.annotation( + testFramework.methodSourceAnnotationId, + listOf("name" to CgLiteral(stringClassId, dataProviderMethodName)) + ), + ) + + override fun createArgList(length: Int, argListName: String) = + statementConstructor.newVar(testFramework.argListClassId, argListName) { + CgAllocateArray(testFramework.argListClassId, Array::class.java.id, length) + } + + override fun collectParameterizedTestAnnotations(dataProviderMethodName: String?) = setOf( + statementConstructor.annotation( + testFramework.parameterizedTestAnnotationId, + listOf("dataProvider" to CgLiteral(stringClassId, dataProviderMethodName)) + ) + ) + + override fun passArgumentsToArgsVariable(argsVariable: CgVariable, argsArray: CgVariable, executionIndex: Int) = + setArgumentsArrayElement(argsVariable, executionIndex, argsArray, statementConstructor) + + /** + * Supplements TestNG @Test annotation with a description. + * It looks like @Test(description="...") + * + * @see issue-576 on GitHub + */ + private fun addDescriptionAnnotation(description: String) { + val testAnnotation = + collectedMethodAnnotations.singleOrNull { it.classId == testFramework.testAnnotationId } + + val descriptionArgument = CgNamedAnnotationArgument("description", stringLiteral(description)) + if (testAnnotation is CgMultipleArgsAnnotation) { + testAnnotation.arguments += descriptionArgument + } else { + collectedMethodAnnotations += CgMultipleArgsAnnotation( + testFramework.testAnnotationId, + mutableListOf(descriptionArgument) + ) + } + } + + override fun addTestDescription(description: String) = addDescriptionAnnotation(description) + override fun disableTestMethod(reason: String) { require(testFramework is TestNg) { "According to settings, TestNg was expected, but got: $testFramework" } @@ -333,8 +399,10 @@ internal class TestNgManager(context: CgContext) : TestFrameworkManager(context) } internal class Junit4Manager(context: CgContext) : TestFrameworkManager(context) { + private val parametrizedTestsNotSupportedError: Nothing = error("Parametrized tests are not supported for JUnit4") + override val dataProviderMethodsHolder - get() = error("Parametrized tests are not supportd for JUnit4") + get() = parametrizedTestsNotSupportedError override val annotationForNestedClasses get() = null @@ -370,6 +438,20 @@ internal class Junit4Manager(context: CgContext) : TestFrameworkManager(context) block() } + override fun createDataProviderAnnotations(dataProviderMethodName: String?) = + parametrizedTestsNotSupportedError + + override fun createArgList(length: Int, argListName: String) = + parametrizedTestsNotSupportedError + + override fun collectParameterizedTestAnnotations(dataProviderMethodName: String?) = + parametrizedTestsNotSupportedError + + override fun passArgumentsToArgsVariable(argsVariable: CgVariable, argsArray: CgVariable, executionIndex: Int) = + parametrizedTestsNotSupportedError + + override fun addTestDescription(description: String) = Unit + override fun disableTestMethod(reason: String) { require(testFramework is Junit4) { "According to settings, JUnit4 was expected, but got: $testFramework" } @@ -389,8 +471,12 @@ internal class Junit5Manager(context: CgContext) : TestFrameworkManager(context) override val dataProviderMethodsHolder get() = outerMostTestClassInfo - override val annotationForNestedClasses - get() = statementConstructor.annotation(Junit5.nestedTestClassAnnotationId) + override val annotationForNestedClasses: CgAnnotation + get() { + require(testFramework is Junit5) { "According to settings, JUnit5 was expected, but got: $testFramework" } + + return statementConstructor.annotation(testFramework.nestedTestClassAnnotationId) + } override val annotationForOuterClasses get() = null @@ -408,6 +494,28 @@ internal class Junit5Manager(context: CgContext) : TestFrameworkManager(context) +assertions[assertThrows](exception.toExceptionClass(), lambda) } + override fun createDataProviderAnnotations(dataProviderMethodName: String?) = mutableListOf() + override fun createArgList(length: Int, argListName: String) = + statementConstructor.newVar(testFramework.argListClassId, argListName) { + val constructor = ConstructorId(testFramework.argListClassId, emptyList()) + constructor.invoke() + } + + override fun collectParameterizedTestAnnotations(dataProviderMethodName: String?) = setOf( + statementConstructor.annotation(testFramework.parameterizedTestAnnotationId), + statementConstructor.annotation( + testFramework.methodSourceAnnotationId, + "${outerMostTestClass.canonicalName}#$dataProviderMethodName" + ) + ) + + override fun passArgumentsToArgsVariable(argsVariable: CgVariable, argsArray: CgVariable, executionIndex: Int) { + +argsVariable[addToListMethodId]( + argumentsClassId[argumentsMethodId](argsArray) + ) + } + + override fun expectTimeout(timeoutMs : Long, block: () -> Unit) { require(testFramework is Junit5) { "According to settings, JUnit5 was expected, but got: $testFramework" } val lambda = statementConstructor.lambda(testFramework.executableClassId) { block() } @@ -443,6 +551,8 @@ internal class Junit5Manager(context: CgContext) : TestFrameworkManager(context) ) } + override fun addTestDescription(description: String) = addDisplayName(description) + override fun disableTestMethod(reason: String) { require(testFramework is Junit5) { "According to settings, JUnit5 was expected, but got: $testFramework" } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/util/ConstructorUtils.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/util/ConstructorUtils.kt index 021e0bccca..a18ece8f96 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/util/ConstructorUtils.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/util/ConstructorUtils.kt @@ -42,9 +42,16 @@ import org.utbot.framework.plugin.api.util.shortClassId import org.utbot.framework.plugin.api.util.underlyingType import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.PersistentSet +import org.utbot.framework.codegen.model.constructor.builtin.setArrayElement +import org.utbot.framework.codegen.model.constructor.tree.CgCallableAccessManager import org.utbot.framework.codegen.model.tree.CgAllocateInitializedArray import org.utbot.framework.codegen.model.tree.CgArrayInitializer +import org.utbot.framework.codegen.model.util.at import org.utbot.framework.plugin.api.util.arrayLikeName +import org.utbot.framework.plugin.api.util.builtinStaticMethodId +import org.utbot.framework.plugin.api.util.methodId +import org.utbot.framework.plugin.api.util.objectArrayClassId +import org.utbot.framework.plugin.api.util.objectClassId internal data class EnvironmentFieldStateCache( val thisInstance: FieldStateCache, @@ -124,6 +131,40 @@ data class ExpressionWithType(val type: ClassId, val expression: CgExpression) val classCgClassId = CgClassId(Class::class.id, typeParameters = WildcardTypeParameter(), isNullable = false) +/** + * A [MethodId] to add an item into [ArrayList]. + */ +internal 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` + */ +internal 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. + */ +internal val argumentsMethodId: BuiltinMethodId + get() = builtinStaticMethodId( + classId = argumentsClassId, + name = "arguments", + returnType = argumentsClassId, + // vararg of Objects + arguments = arrayOf(objectArrayClassId) + ) + internal fun getStaticFieldVariableName(owner: ClassId, path: FieldPath): String { val elements = mutableListOf() elements += owner.simpleName.decapitalize() @@ -221,6 +262,25 @@ internal fun CgContextOwner.typeCast( return CgTypeCast(targetType, expression, isSafetyCast) } +// TODO: Doesn't it work for any array? +/** + * Sets an element of arguments array in parameterized test, + * if test framework represents arguments as array. + */ +internal fun T.setArgumentsArrayElement( + array: CgVariable, + index: Int, + value: CgExpression, + constructor: CgStatementConstructor +) where T : CgContextOwner, T: CgCallableAccessManager { + when (array.type) { + objectClassId -> { + +java.lang.reflect.Array::class.id[setArrayElement](array, index, value) + } + else -> with(constructor) { array.at(index) `=` value } + } +} + @Suppress("unused") internal fun newArrayOf(elementType: ClassId, values: List): CgAllocateInitializedArray { val arrayType = arrayTypeOf(elementType) @@ -230,6 +290,7 @@ internal fun newArrayOf(elementType: ClassId, values: List): CgAll internal fun arrayInitializer(arrayType: ClassId, elementType: ClassId, values: List): CgArrayInitializer = CgArrayInitializer(arrayType, elementType, values) + /** * For a given [elementType] returns a [ClassId] of an array with elements of this type. * For example, for an id of `int` the result will be an id of `int[]`. From 424f4c370e33ed860479c88d42fd5934076e23cc Mon Sep 17 00:00:00 2001 From: Ivan Volkov Date: Fri, 5 Aug 2022 20:47:50 +0300 Subject: [PATCH 2/2] Fixed bug with Nothing properties --- .../org/utbot/framework/codegen/Domain.kt | 15 ++++++++++----- .../constructor/tree/TestFrameworkManager.kt | 18 ++---------------- 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/Domain.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/Domain.kt index 122fb4e281..dd5c6f6350 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/Domain.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/Domain.kt @@ -375,16 +375,21 @@ object TestNg : TestFramework(displayName = "TestNG") { } object Junit4 : TestFramework("JUnit4") { - private val parametrizedTestsNotSupportedError: Nothing = error("Parametrized tests are not supported for 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 = parametrizedTestsNotSupportedError - override val parameterizedTestAnnotationFqn = parametrizedTestsNotSupportedError - override val methodSourceAnnotation = parametrizedTestsNotSupportedError - override val methodSourceAnnotationFqn = parametrizedTestsNotSupportedError + 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", diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/TestFrameworkManager.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/TestFrameworkManager.kt index b94ead991b..f82a00dd57 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/TestFrameworkManager.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/TestFrameworkManager.kt @@ -215,21 +215,6 @@ internal abstract class TestFrameworkManager(val context: CgContext) * Add a short test's description depending on the test framework type: */ abstract fun addTestDescription(description: String) -// { -// if (description == null) return -// val testAnnotation = -// collectedMethodAnnotations.singleOrNull { it.classId == testFramework.testAnnotationId } -// -// val descriptionArgument = CgNamedAnnotationArgument("description", stringLiteral(description)) -// if (testAnnotation is CgMultipleArgsAnnotation) { -// testAnnotation.arguments += descriptionArgument -// } else { -// collectedMethodAnnotations += CgMultipleArgsAnnotation( -// testFramework.testAnnotationId, -// mutableListOf(descriptionArgument) -// ) -// } -// } abstract fun disableTestMethod(reason: String) @@ -399,7 +384,8 @@ internal class TestNgManager(context: CgContext) : TestFrameworkManager(context) } internal class Junit4Manager(context: CgContext) : TestFrameworkManager(context) { - private val parametrizedTestsNotSupportedError: Nothing = error("Parametrized tests are not supported for JUnit4") + private val parametrizedTestsNotSupportedError: Nothing + get() = error("Parametrized tests are not supported for JUnit4") override val dataProviderMethodsHolder get() = parametrizedTestsNotSupportedError