Skip to content

Restructuralize code generator #1372

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

Merged
merged 2 commits into from
Nov 15, 2022
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
2 changes: 1 addition & 1 deletion docs/UtUtilsClass.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ As one can see, the comment mentions two characteristics of the `UtUtils` class:
If the generated tests require additional _utility methods_, the
existing `UtUtils` class is upgraded and gets a new version number, which should be defined here:

`org.utbot.framework.codegen.model.constructor.builtin.UtilClassFileMethodProvider.UTIL_CLASS_VERSION`
`org.utbot.framework.codegen.domain.builtin.UtilClassFileMethodProvider.UTIL_CLASS_VERSION`

_2. Mockito support_

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import com.github.ajalt.clikt.parameters.options.*
import com.github.ajalt.clikt.parameters.types.choice
import com.github.ajalt.clikt.parameters.types.long
import mu.KotlinLogging
import org.utbot.framework.codegen.TestFramework
import org.utbot.framework.codegen.domain.TestFramework
import org.utbot.python.PythonMethod
import org.utbot.python.PythonTestGenerationProcessor
import org.utbot.python.PythonTestGenerationProcessor.processTestGeneration
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ import org.utbot.common.PathUtil.toURL
import org.utbot.common.toPath
import org.utbot.engine.Mocker
import org.utbot.framework.UtSettings
import org.utbot.framework.codegen.ForceStaticMocking
import org.utbot.framework.codegen.MockitoStaticMocking
import org.utbot.framework.codegen.NoStaticMocking
import org.utbot.framework.codegen.StaticsMocking
import org.utbot.framework.codegen.model.CodeGenerator
import org.utbot.framework.codegen.testFrameworkByName
import org.utbot.framework.codegen.CodeGenerator
import org.utbot.framework.codegen.domain.ForceStaticMocking
import org.utbot.framework.codegen.domain.MockitoStaticMocking
import org.utbot.framework.codegen.domain.NoStaticMocking
import org.utbot.framework.codegen.domain.StaticsMocking
import org.utbot.framework.codegen.domain.testFrameworkByName
import org.utbot.framework.plugin.api.ClassId
import org.utbot.framework.plugin.api.CodegenLanguage
import org.utbot.framework.plugin.api.ExecutableId
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@
import org.utbot.external.api.TestMethodInfo;
import org.utbot.external.api.UtBotJavaApi;
import org.utbot.external.api.UtModelFactory;
import org.utbot.framework.codegen.ForceStaticMocking;
import org.utbot.framework.codegen.Junit4;
import org.utbot.framework.codegen.MockitoStaticMocking;
import org.utbot.framework.codegen.domain.ForceStaticMocking;
import org.utbot.framework.codegen.domain.Junit4;
import org.utbot.framework.codegen.domain.MockitoStaticMocking;
import org.utbot.framework.plugin.api.*;
import org.utbot.framework.plugin.api.util.UtContext;
import org.utbot.framework.plugin.services.JdkInfoDefaultProvider;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import org.utbot.examples.assemble.DefaultFieldWithDirectAccessor
import org.utbot.examples.assemble.DefaultFieldWithSetter
import org.utbot.examples.assemble.DefaultPackagePrivateField
import org.utbot.examples.assemble.StaticField
import org.utbot.framework.codegen.tree.arrayTypeOf
import org.utbot.framework.plugin.api.ClassId
import org.utbot.framework.plugin.api.ExecutableId
import org.utbot.framework.plugin.api.FieldId
Expand All @@ -58,7 +59,6 @@ import org.utbot.framework.util.SootUtils
import org.utbot.framework.util.instanceCounter
import org.utbot.framework.util.modelIdCounter
import kotlin.reflect.full.functions
import org.utbot.framework.codegen.model.constructor.util.arrayTypeOf

/**
* Test classes must be located in the same folder as [AssembleTestUtils] class.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ package org.utbot.external.api
import org.utbot.common.FileUtil
import org.utbot.common.nameOfPackage
import org.utbot.framework.UtSettings
import org.utbot.framework.codegen.ForceStaticMocking
import org.utbot.framework.codegen.Junit5
import org.utbot.framework.codegen.NoStaticMocking
import org.utbot.framework.codegen.StaticsMocking
import org.utbot.framework.codegen.TestFramework
import org.utbot.framework.codegen.model.CodeGenerator
import org.utbot.framework.codegen.CodeGenerator
import org.utbot.framework.codegen.domain.ForceStaticMocking
import org.utbot.framework.codegen.domain.Junit5
import org.utbot.framework.codegen.domain.NoStaticMocking
import org.utbot.framework.codegen.domain.StaticsMocking
import org.utbot.framework.codegen.domain.TestFramework
import org.utbot.framework.concrete.UtConcreteExecutionData
import org.utbot.framework.concrete.UtConcreteExecutionResult
import org.utbot.framework.concrete.UtExecutionInstrumentation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import org.utbot.common.isPublic
import org.utbot.engine.ResolvedExecution
import org.utbot.engine.ResolvedModels
import org.utbot.framework.UtSettings
import org.utbot.framework.codegen.model.util.isAccessibleFrom
import org.utbot.framework.codegen.util.isAccessibleFrom
import org.utbot.framework.modifications.AnalysisMode.SettersAndDirectAccessors
import org.utbot.framework.modifications.ConstructorAnalyzer
import org.utbot.framework.modifications.ConstructorAssembleInfo
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package org.utbot.framework.codegen

import org.utbot.framework.codegen.domain.ForceStaticMocking
import org.utbot.framework.codegen.domain.HangingTestsTimeout
import org.utbot.framework.codegen.domain.ParametrizedTestSource
import org.utbot.framework.codegen.domain.RuntimeExceptionTestsBehaviour
import org.utbot.framework.codegen.domain.StaticsMocking
import org.utbot.framework.codegen.domain.TestFramework
import org.utbot.framework.codegen.domain.models.CgMethodTestSet
import org.utbot.framework.codegen.domain.models.TestClassModel
import org.utbot.framework.codegen.domain.context.CgContext
import org.utbot.framework.codegen.renderer.CgAbstractRenderer
import org.utbot.framework.codegen.reports.TestsGenerationReport
import org.utbot.framework.codegen.tree.CgTestClassConstructor
import org.utbot.framework.codegen.tree.ututils.UtilClassKind
import org.utbot.framework.codegen.services.language.CgLanguageAssistant
import org.utbot.framework.plugin.api.ClassId
import org.utbot.framework.plugin.api.CodegenLanguage
import org.utbot.framework.plugin.api.ExecutableId
import org.utbot.framework.plugin.api.MockFramework
import org.utbot.framework.plugin.api.UtMethodTestSet

open class CodeGenerator(
val classUnderTest: ClassId,
paramNames: MutableMap<ExecutableId, List<String>> = mutableMapOf(),
generateUtilClassFile: Boolean = false,
testFramework: TestFramework = TestFramework.defaultItem,
mockFramework: MockFramework = MockFramework.defaultItem,
staticsMocking: StaticsMocking = StaticsMocking.defaultItem,
forceStaticMocking: ForceStaticMocking = ForceStaticMocking.defaultItem,
generateWarningsForStaticMocking: Boolean = true,
codegenLanguage: CodegenLanguage = CodegenLanguage.defaultItem,
parameterizedTestSource: ParametrizedTestSource = ParametrizedTestSource.defaultItem,
runtimeExceptionTestsBehaviour: RuntimeExceptionTestsBehaviour = RuntimeExceptionTestsBehaviour.defaultItem,
hangingTestsTimeout: HangingTestsTimeout = HangingTestsTimeout(),
enableTestsTimeout: Boolean = true,
testClassPackageName: String = classUnderTest.packageName,
) {

open var context: CgContext = CgContext(
classUnderTest = classUnderTest,
generateUtilClassFile = generateUtilClassFile,
paramNames = paramNames,
testFramework = testFramework,
mockFramework = mockFramework,
codegenLanguage = codegenLanguage,
cgLanguageAssistant = CgLanguageAssistant.getByCodegenLanguage(codegenLanguage),
parametrizedTestSource = parameterizedTestSource,
staticsMocking = staticsMocking,
forceStaticMocking = forceStaticMocking,
generateWarningsForStaticMocking = generateWarningsForStaticMocking,
runtimeExceptionTestsBehaviour = runtimeExceptionTestsBehaviour,
hangingTestsTimeout = hangingTestsTimeout,
enableTestsTimeout = enableTestsTimeout,
testClassPackageName = testClassPackageName
)

//TODO: we support custom test class name only in utbot-online, probably support them in plugin as well
fun generateAsString(testSets: Collection<UtMethodTestSet>, testClassCustomName: String? = null): String =
generateAsStringWithTestReport(testSets, testClassCustomName).generatedCode

//TODO: we support custom test class name only in utbot-online, probably support them in plugin as well
fun generateAsStringWithTestReport(
testSets: Collection<UtMethodTestSet>,
testClassCustomName: String? = null,
): CodeGeneratorResult {
val cgTestSets = testSets.map { CgMethodTestSet(it) }.toList()
return withCustomContext(testClassCustomName) {
context.withTestClassFileScope {
val astConstructor = CgTestClassConstructor(context)
val renderer = CgAbstractRenderer.makeRenderer(context)
val testClassModel = TestClassModel.fromTestSets(classUnderTest, cgTestSets)

val testClassFile = astConstructor.construct(testClassModel)
testClassFile.accept(renderer)

CodeGeneratorResult(
generatedCode = renderer.toString(),
utilClassKind = UtilClassKind.fromCgContextOrNull(context),
testsGenerationReport = astConstructor.testsGenerationReport
)
}
}
}

/**
* Wrapper function that configures context as needed for utbot-online:
* - turns on imports optimization in code generator
* - passes a custom test class name if there is one
*/
fun <R> withCustomContext(testClassCustomName: String? = null, block: () -> R): R {
val prevContext = context
return try {
context = prevContext.copy(
shouldOptimizeImports = true,
testClassCustomName = testClassCustomName
)
block()
} finally {
context = prevContext
}
}
}

/**
* @property generatedCode the source code of the test class
* @property testsGenerationReport some info about test generation process
* @property utilClassKind the kind of util class if it is required, otherwise - null
*/
data class CodeGeneratorResult(
val generatedCode: String,
val testsGenerationReport: TestsGenerationReport,
// null if no util class needed, e.g. when we are generating utils directly into test class
val utilClassKind: UtilClassKind? = null,
)

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package org.utbot.framework.codegen
package org.utbot.framework.codegen.domain

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.codegen.domain.builtin.mockitoClassId
import org.utbot.framework.codegen.domain.builtin.ongoingStubbingClassId
import org.utbot.framework.codegen.domain.models.CgClassId
import org.utbot.framework.codegen.tree.argumentsClassId
import org.utbot.framework.plugin.api.BuiltinClassId
import org.utbot.framework.plugin.api.ClassId
import org.utbot.framework.plugin.api.CodeGenerationSettingBox
Expand All @@ -30,7 +30,6 @@ 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
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.utbot.framework.codegen.model.constructor.builtin
package org.utbot.framework.codegen.domain.builtin

import org.utbot.framework.plugin.api.BuiltinClassId
import org.utbot.framework.plugin.api.MethodId
import org.utbot.framework.plugin.api.util.booleanClassId
import org.utbot.framework.plugin.api.util.builtinMethodId
import org.utbot.framework.plugin.api.util.builtinStaticMethodId
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.utbot.framework.codegen.model.constructor.builtin
package org.utbot.framework.codegen.domain.builtin

import org.utbot.framework.plugin.api.ClassId
import org.utbot.framework.plugin.api.MethodId
Expand All @@ -19,15 +19,6 @@ import java.lang.reflect.InvocationTargetException
//TODO: these methods are called builtins, but actually are just [MethodId]
//may be fixed in https://github.com/UnitTestBot/UTBotJava/issues/138

internal val reflectionBuiltins: Set<MethodId>
get() = setOf(
setAccessible, invoke, newInstance, getMethodId, forName,
getDeclaredMethod, getDeclaredConstructor, allocateInstance,
getClass, getDeclaredField, isEnumConstant, getFieldName,
equals, getSuperclass, setMethodId, newArrayInstance,
setArrayElement, getArrayElement, getTargetException,
)

internal val setAccessible = methodId(
classId = AccessibleObject::class.id,
name = "setAccessible",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
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
package org.utbot.framework.codegen.domain.builtin

import org.utbot.framework.codegen.domain.MockitoStaticMocking
import org.utbot.framework.codegen.domain.models.CgClassId
import org.utbot.framework.codegen.renderer.utilMethodTextById
import org.utbot.framework.codegen.tree.arrayTypeOf
import org.utbot.framework.codegen.tree.utilMethodId
import org.utbot.framework.codegen.tree.ututils.UtilClassKind.Companion.PACKAGE_DELIMITER
import org.utbot.framework.codegen.tree.ututils.UtilClassKind.Companion.UT_UTILS_BASE_PACKAGE_NAME
import org.utbot.framework.plugin.api.BuiltinClassId
import org.utbot.framework.plugin.api.BuiltinConstructorId
import org.utbot.framework.plugin.api.ClassId
Expand Down
Loading