Skip to content
Merged
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 @@ -24,6 +24,7 @@ import org.utbot.framework.plugin.api.UtMethodTestSet
import org.utbot.framework.codegen.model.constructor.TestClassModel
import org.utbot.framework.codegen.model.tree.CgDocRegularStmt
import org.utbot.framework.codegen.model.tree.CgDocumentationComment
import java.util.*

class CodeGenerator(
private val classUnderTest: ClassId,
Expand Down Expand Up @@ -147,20 +148,20 @@ sealed class UtilClassKind(
/**
* Contains comments specifying the version and the kind of util class being generated and
*/
val utilClassDocumentation: CgDocumentationComment
get() = CgDocumentationComment(
fun utilClassDocumentation(codegenLanguage: CodegenLanguage): CgDocumentationComment
= CgDocumentationComment(
listOf(
CgDocRegularStmt(utilClassKindCommentText),
CgDocRegularStmt("$UTIL_CLASS_VERSION_COMMENT_PREFIX${utilClassVersion}"),
CgDocRegularStmt("$UTIL_CLASS_VERSION_COMMENT_PREFIX${utilClassVersion(codegenLanguage)}"),
)
)

/**
* The version of util class being generated.
* For more details see [UtilClassFileMethodProvider.UTIL_CLASS_VERSION].
*/
val utilClassVersion: String
get() = UtilClassFileMethodProvider.UTIL_CLASS_VERSION
fun utilClassVersion(codegenLanguage: CodegenLanguage): String
= UtilClassFileMethodProvider(codegenLanguage).UTIL_CLASS_VERSION

/**
* The text of comment specifying the kind of util class.
Expand All @@ -175,15 +176,21 @@ sealed class UtilClassKind(
/**
* A kind of regular UtUtils class. "Regular" here means that this class does not use a mock framework.
*/
object RegularUtUtils : UtilClassKind(UtilClassFileMethodProvider, mockFrameworkUsed = false, priority = 0) {
class RegularUtUtils(val codegenLanguage: CodegenLanguage) :
UtilClassKind(
UtilClassFileMethodProvider(codegenLanguage),
mockFrameworkUsed = false,
priority = 0,
) {
override val utilClassKindCommentText: String
get() = "This is a regular UtUtils class (without mock framework usage)"
}

/**
* A kind of UtUtils class that uses a mock framework. At the moment the framework is Mockito.
*/
object UtUtilsWithMockito : UtilClassKind(UtilClassFileMethodProvider, mockFrameworkUsed = true, priority = 1) {
class UtUtilsWithMockito(val codegenLanguage: CodegenLanguage) :
UtilClassKind(UtilClassFileMethodProvider(codegenLanguage), mockFrameworkUsed = true, priority = 1) {
override val utilClassKindCommentText: String
get() = "This is UtUtils class with Mockito support"
}
Expand All @@ -197,7 +204,7 @@ sealed class UtilClassKind(
* @return the text of the generated util class file.
*/
fun getUtilClassText(codegenLanguage: CodegenLanguage): String {
val utilClassFile = CgUtilClassConstructor.constructUtilsClassFile(this)
val utilClassFile = CgUtilClassConstructor.constructUtilsClassFile(this, codegenLanguage)
val renderer = CgAbstractRenderer.makeRenderer(this, codegenLanguage)
utilClassFile.accept(renderer)
return renderer.toString()
Expand All @@ -212,10 +219,13 @@ sealed class UtilClassKind(
*/
const val UTIL_CLASS_VERSION_COMMENT_PREFIX = "UtUtils class version: "

fun utilClassKindByCommentOrNull(comment: String): UtilClassKind? {
fun utilClassKindByCommentOrNull(
comment: String,
codegenLanguage: CodegenLanguage)
: UtilClassKind? {
return when (comment) {
RegularUtUtils.utilClassKindCommentText -> RegularUtUtils
UtUtilsWithMockito.utilClassKindCommentText -> UtUtilsWithMockito
RegularUtUtils(codegenLanguage).utilClassKindCommentText -> RegularUtUtils(codegenLanguage)
UtUtilsWithMockito(codegenLanguage).utilClassKindCommentText -> UtUtilsWithMockito(codegenLanguage)
else -> null
}
}
Expand All @@ -228,24 +238,27 @@ sealed class UtilClassKind(
internal fun fromCgContextOrNull(context: CgContext): UtilClassKind? {
if (context.requiredUtilMethods.isEmpty()) return null
if (!context.mockFrameworkUsed) {
return RegularUtUtils
return RegularUtUtils(context.codegenLanguage)
}
return when (context.mockFramework) {
MockFramework.MOCKITO -> UtUtilsWithMockito
MockFramework.MOCKITO -> UtUtilsWithMockito(context.codegenLanguage)
// in case we will add any other mock frameworks, newer Kotlin compiler versions
// will report a non-exhaustive 'when', so we will not forget to support them here as well
}
}

const val UT_UTILS_PACKAGE_NAME = "org.utbot.runtime.utils"
const val UT_UTILS_CLASS_NAME = "UtUtils"
const val UT_UTILS_BASE_PACKAGE_NAME = "org.utbot.runtime.utils"
const val UT_UTILS_INSTANCE_NAME = "UtUtils"
const val PACKAGE_DELIMITER = "."

/**
* List of package names of UtUtils class.
* See whole package name at [UT_UTILS_PACKAGE_NAME].
* List of package name components of UtUtils class.
* See whole package name at [UT_UTILS_BASE_PACKAGE_NAME].
*/
val utilsPackages: List<String>
get() = UT_UTILS_PACKAGE_NAME.split(PACKAGE_DELIMITER)
fun utilsPackageNames(codegenLanguage: CodegenLanguage): List<String>
= UT_UTILS_BASE_PACKAGE_NAME.split(PACKAGE_DELIMITER) + codegenLanguage.name.lowercase(Locale.getDefault())

fun utilsPackageFullName(codegenLanguage: CodegenLanguage): String
= utilsPackageNames(codegenLanguage).joinToString { PACKAGE_DELIMITER }
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package org.utbot.framework.codegen.model.constructor.builtin

import org.utbot.framework.codegen.MockitoStaticMocking
import org.utbot.framework.codegen.model.UtilClassKind.Companion.PACKAGE_DELIMITER
import org.utbot.framework.codegen.model.UtilClassKind.Companion.UT_UTILS_BASE_PACKAGE_NAME
import org.utbot.framework.codegen.model.constructor.util.arrayTypeOf
import org.utbot.framework.codegen.model.constructor.util.utilMethodId
import org.utbot.framework.codegen.model.tree.CgClassId
import org.utbot.framework.codegen.model.visitor.utilMethodTextById
import org.utbot.framework.plugin.api.BuiltinClassId
import org.utbot.framework.plugin.api.BuiltinConstructorId
import org.utbot.framework.plugin.api.ClassId
import org.utbot.framework.plugin.api.CodegenLanguage
import org.utbot.framework.plugin.api.MethodId
import org.utbot.framework.plugin.api.util.baseStreamClassId
import org.utbot.framework.plugin.api.util.booleanClassId
Expand Down Expand Up @@ -253,11 +256,12 @@ internal abstract class UtilMethodProvider(val utilClassId: ClassId) {

/**
* This provider represents an util class file that is generated and put into the user's test module.
* The generated class is UtUtils (its id is defined at [utUtilsClassId]).
* The generated class is UtUtils (its id is defined at [utJavaUtilsClassId] or [utKotlinUtilsClassId]).
*
* Content of this util class may be different (due to mocks in deepEquals), but the methods (and their ids) are the same.
*/
internal object UtilClassFileMethodProvider : UtilMethodProvider(utUtilsClassId) {
internal class UtilClassFileMethodProvider(language: CodegenLanguage)
: UtilMethodProvider(selectUtilClassId(language)) {
/**
* This property contains the current version of util class.
* This version will be written to the util class file inside a comment.
Expand All @@ -270,14 +274,27 @@ internal object UtilClassFileMethodProvider : UtilMethodProvider(utUtilsClassId)
*
* **IMPORTANT** if you make any changes to util methods (see [utilMethodTextById]), do not forget to update this version.
*/
const val UTIL_CLASS_VERSION = "1.0"
val UTIL_CLASS_VERSION = "2.0"
}

internal class TestClassUtilMethodProvider(testClassId: ClassId) : UtilMethodProvider(testClassId)

internal val utUtilsClassId: ClassId
internal fun selectUtilClassId(codegenLanguage: CodegenLanguage): ClassId =
when (codegenLanguage) {
CodegenLanguage.JAVA -> utJavaUtilsClassId
CodegenLanguage.KOTLIN -> utKotlinUtilsClassId
}

internal val utJavaUtilsClassId: ClassId
get() = BuiltinClassId(
canonicalName = UT_UTILS_BASE_PACKAGE_NAME + PACKAGE_DELIMITER + "java" + PACKAGE_DELIMITER + "UtUtils",
simpleName = "UtUtils",
isFinal = true,
)

internal val utKotlinUtilsClassId: ClassId
get() = BuiltinClassId(
canonicalName = "org.utbot.runtime.utils.UtUtils",
canonicalName = UT_UTILS_BASE_PACKAGE_NAME + PACKAGE_DELIMITER + "kotlin" + PACKAGE_DELIMITER + "UtUtils",
simpleName = "UtUtils",
isFinal = true,
isKotlinObject = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ internal data class CgContext(
*/
override val utilMethodProvider: UtilMethodProvider
get() = if (generateUtilClassFile) {
UtilClassFileMethodProvider
UtilClassFileMethodProvider(codegenLanguage)
} else {
TestClassUtilMethodProvider(outerMostTestClass)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package org.utbot.framework.codegen.model.constructor.tree

import org.utbot.framework.codegen.model.CodeGenerator
import org.utbot.framework.codegen.model.UtilClassKind
import org.utbot.framework.codegen.model.constructor.builtin.utUtilsClassId
import org.utbot.framework.codegen.model.constructor.builtin.selectUtilClassId
import org.utbot.framework.codegen.model.constructor.builtin.utJavaUtilsClassId
import org.utbot.framework.codegen.model.constructor.builtin.utKotlinUtilsClassId
import org.utbot.framework.codegen.model.tree.CgAuxiliaryClass
import org.utbot.framework.codegen.model.tree.CgAuxiliaryNestedClassesRegion
import org.utbot.framework.codegen.model.tree.CgClassFile
Expand All @@ -11,21 +13,26 @@ import org.utbot.framework.codegen.model.tree.CgUtilMethod
import org.utbot.framework.codegen.model.tree.buildClass
import org.utbot.framework.codegen.model.tree.buildClassBody
import org.utbot.framework.codegen.model.tree.buildClassFile
import org.utbot.framework.plugin.api.CodegenLanguage

/**
* This class is used to construct a file containing an util class UtUtils.
* The util class is constructed when the argument `generateUtilClassFile` in the [CodeGenerator] is true.
*/
internal object CgUtilClassConstructor {
fun constructUtilsClassFile(utilClassKind: UtilClassKind): CgClassFile {
fun constructUtilsClassFile(
utilClassKind: UtilClassKind,
codegenLanguage: CodegenLanguage,
): CgClassFile {
val utilMethodProvider = utilClassKind.utilMethodProvider
val utilsClassId = selectUtilClassId(codegenLanguage)
return buildClassFile {
// imports are empty, because we use fully qualified classes and static methods,
// so they will be imported once IDEA reformatting action has worked
declaredClass = buildClass {
id = utUtilsClassId
body = buildClassBody(utUtilsClassId) {
documentation = utilClassKind.utilClassDocumentation
id = utilsClassId
body = buildClassBody(utilsClassId) {
documentation = utilClassKind.utilClassDocumentation(codegenLanguage)
staticDeclarationRegions += CgStaticsRegion("Util methods", utilMethodProvider.utilMethodIds.map { CgUtilMethod(it) })
nestedClassRegions += CgAuxiliaryNestedClassesRegion(
nestedClasses = listOf(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package org.utbot.framework.codegen.model.visitor

import org.utbot.framework.codegen.model.UtilClassKind
import org.utbot.framework.codegen.model.UtilClassKind.Companion.UT_UTILS_PACKAGE_NAME
import org.utbot.framework.codegen.model.UtilClassKind.Companion.utilsPackageFullName
import org.utbot.framework.codegen.model.constructor.builtin.UtilMethodProvider
import org.utbot.framework.codegen.model.constructor.builtin.utUtilsClassId
import org.utbot.framework.codegen.model.constructor.builtin.selectUtilClassId
import org.utbot.framework.codegen.model.constructor.builtin.utJavaUtilsClassId
import org.utbot.framework.codegen.model.constructor.builtin.utKotlinUtilsClassId
import org.utbot.framework.codegen.model.constructor.context.CgContext
import org.utbot.framework.plugin.api.ClassId
import org.utbot.framework.plugin.api.CodegenLanguage
Expand Down Expand Up @@ -46,8 +48,8 @@ internal class CgRendererContext(
shouldOptimizeImports = false,
importedClasses = emptySet(),
importedStaticMethods = emptySet(),
classPackageName = UT_UTILS_PACKAGE_NAME,
generatedClass = utUtilsClassId,
classPackageName = utilsPackageFullName(language),
generatedClass = selectUtilClassId(language),
utilMethodProvider = utilClassKind.utilMethodProvider,
codegenLanguage = language,
mockFrameworkUsed = utilClassKind.mockFrameworkUsed,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import org.utbot.framework.codegen.TestFramework
import org.utbot.framework.codegen.model.CodeGenerator
import org.utbot.framework.codegen.model.CodeGeneratorResult
import org.utbot.framework.codegen.model.UtilClassKind
import org.utbot.framework.codegen.model.UtilClassKind.Companion.UT_UTILS_CLASS_NAME
import org.utbot.framework.codegen.model.UtilClassKind.Companion.UT_UTILS_INSTANCE_NAME
import org.utbot.framework.plugin.api.CodegenLanguage
import org.utbot.framework.plugin.api.ExecutableId
import org.utbot.framework.plugin.api.MockFramework
Expand Down Expand Up @@ -171,7 +171,7 @@ class TestCodeGeneratorPipeline(private val testFrameworkConfiguration: TestFram
}

private fun UtilClassKind.writeUtilClassToFile(buildDirectory: Path, language: CodegenLanguage): File {
val utilClassFile = File(buildDirectory.toFile(), "$UT_UTILS_CLASS_NAME${language.extension}")
val utilClassFile = File(buildDirectory.toFile(), "$UT_UTILS_INSTANCE_NAME${language.extension}")
val utilClassText = getUtilClassText(language)
return writeFile(utilClassText, utilClassFile)
}
Expand Down
Loading