From a8401979d2bddc8bcc41c1f1312f20111952821d Mon Sep 17 00:00:00 2001 From: Egor Kulikov Date: Mon, 3 Oct 2022 16:29:53 +0300 Subject: [PATCH 1/4] Try to fix memory leak in CgFieldStateManager --- .../codegen/model/constructor/tree/CgMethodConstructor.kt | 6 +++--- .../codegen/model/constructor/util/CgComponents.kt | 7 +------ 2 files changed, 4 insertions(+), 9 deletions(-) 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 ba3b5b5a9e..d0a6f1a739 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 @@ -148,7 +148,6 @@ import java.lang.reflect.ParameterizedType private const val DEEP_EQUALS_MAX_DEPTH = 5 // TODO move it to plugin settings? internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by context, - CgFieldStateManager by CgComponents.getFieldStateManagerBy(context), CgCallableAccessManager by CgComponents.getCallableAccessManagerBy(context), CgStatementConstructor by CgComponents.getStatementConstructorBy(context) { @@ -1275,6 +1274,7 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c rememberInitialStaticFields(statics) val stateAnalyzer = ExecutionStateAnalyzer(execution) val modificationInfo = stateAnalyzer.findModifiedFields() + val fieldStateManager = CgFieldStateManagerImpl(context) // TODO: move such methods to another class and leave only 2 public methods: remember initial and final states val mainBody = { substituteStaticFields(statics) @@ -1288,10 +1288,10 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c val name = paramNames[executableId]?.get(index) methodArguments += variableConstructor.getOrCreateVariable(param, name) } - rememberInitialEnvironmentState(modificationInfo) + fieldStateManager.rememberInitialEnvironmentState(modificationInfo) recordActualResult() generateResultAssertions() - rememberFinalEnvironmentState(modificationInfo) + fieldStateManager.rememberFinalEnvironmentState(modificationInfo) generateFieldStateAssertions() } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/util/CgComponents.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/util/CgComponents.kt index f31c528fb6..ac439b9650 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/util/CgComponents.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/util/CgComponents.kt @@ -35,11 +35,7 @@ internal object CgComponents { is TestNg -> testFrameworkManagers.getOrPut(context) { TestNgManager(context) } } - fun getMockFrameworkManagerBy(context: CgContext) = - mockFrameworkManagers.getOrPut(context) { MockFrameworkManager(context) } - - fun getFieldStateManagerBy(context: CgContext) = - fieldStateManagers.getOrPut(context) { CgFieldStateManagerImpl(context) } + fun getMockFrameworkManagerBy(context: CgContext) = mockFrameworkManagers.getOrPut(context) { MockFrameworkManager(context) } fun getVariableConstructorBy(context: CgContext) = variableConstructors.getOrPut(context) { CgVariableConstructor(context) } @@ -51,7 +47,6 @@ internal object CgComponents { private val callableAccessManagers: MutableMap = mutableMapOf() private val testFrameworkManagers: MutableMap = mutableMapOf() private val mockFrameworkManagers: MutableMap = mutableMapOf() - private val fieldStateManagers: MutableMap = mutableMapOf() private val variableConstructors: MutableMap = mutableMapOf() private val methodConstructors: MutableMap = mutableMapOf() From eac63700871c6bc21a7037b6a5ae491859f98d7e Mon Sep 17 00:00:00 2001 From: Egor Kulikov Date: Mon, 3 Oct 2022 17:06:05 +0300 Subject: [PATCH 2/4] Removed unused testClassConstructors --- .../framework/codegen/model/constructor/util/CgComponents.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/util/CgComponents.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/util/CgComponents.kt index ac439b9650..01275f80fc 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/util/CgComponents.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/util/CgComponents.kt @@ -40,7 +40,6 @@ internal object CgComponents { fun getVariableConstructorBy(context: CgContext) = variableConstructors.getOrPut(context) { CgVariableConstructor(context) } fun getMethodConstructorBy(context: CgContext) = methodConstructors.getOrPut(context) { CgMethodConstructor(context) } - fun getTestClassConstructorBy(context: CgContext) = testClassConstructors.getOrPut(context) { CgTestClassConstructor(context) } private val nameGenerators: MutableMap = mutableMapOf() private val statementConstructors: MutableMap = mutableMapOf() @@ -50,5 +49,4 @@ internal object CgComponents { private val variableConstructors: MutableMap = mutableMapOf() private val methodConstructors: MutableMap = mutableMapOf() - private val testClassConstructors: MutableMap = mutableMapOf() } \ No newline at end of file From 9442d380e5d28a674dd5aa9194a96dbc120e4d5d Mon Sep 17 00:00:00 2001 From: Egor Kulikov Date: Mon, 3 Oct 2022 19:14:28 +0300 Subject: [PATCH 3/4] Make CgContext much more thin --- .../codegen/model/constructor/context/CgContext.kt | 7 +++++-- .../codegen/model/constructor/tree/CgMethodConstructor.kt | 7 ------- .../model/constructor/tree/CgTestClassConstructor.kt | 6 +++++- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/context/CgContext.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/context/CgContext.kt index 12f399c48a..308bab95bc 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/context/CgContext.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/context/CgContext.kt @@ -215,7 +215,10 @@ internal interface CgContextOwner { var statesCache: EnvironmentFieldStateCache - var allExecutions: List + /** + * Result models required to create generic execution in parametrized tests. + */ + var successfulExecutionsModels: List fun block(init: () -> Unit): Block { val prevBlock = currentBlock @@ -463,7 +466,7 @@ internal data class CgContext( ) : CgContextOwner { override lateinit var statesCache: EnvironmentFieldStateCache override lateinit var actual: CgVariable - override lateinit var allExecutions: List + override lateinit var successfulExecutionsModels: List /** * This property cannot be accessed outside of test class file scope 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 d0a6f1a739..dffc0200eb 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 @@ -936,13 +936,6 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c } private fun collectExecutionsResultFields() { - val successfulExecutionsModels = allExecutions - .filter { - it.result is UtExecutionSuccess - }.map { - (it.result as UtExecutionSuccess).model - } - for (model in successfulExecutionsModels) { when (model) { is UtCompositeModel -> { diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgTestClassConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgTestClassConstructor.kt index 6a5197c0d2..369a32d16b 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgTestClassConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgTestClassConstructor.kt @@ -32,6 +32,7 @@ import org.utbot.framework.codegen.model.constructor.TestClassModel import org.utbot.framework.codegen.model.tree.CgAuxiliaryClass import org.utbot.framework.codegen.model.tree.CgUtilEntity import org.utbot.framework.plugin.api.ClassId +import org.utbot.framework.plugin.api.UtExecutionSuccess import org.utbot.framework.plugin.api.util.description import org.utbot.framework.plugin.api.util.humanReadableName import org.utbot.framework.plugin.api.util.kClass @@ -124,7 +125,10 @@ internal class CgTestClassConstructor(val context: CgContext) : return null } - allExecutions = testSet.executions + successfulExecutionsModels = testSet + .executions + .filter { it.result is UtExecutionSuccess } + .map { (it.result as UtExecutionSuccess).model } val (methodUnderTest, _, _, clustersInfo) = testSet val regions = mutableListOf>() From 7b2c46662470d92391f521c09a8a94b61779d9f4 Mon Sep 17 00:00:00 2001 From: Egor Kulikov Date: Tue, 4 Oct 2022 11:09:25 +0300 Subject: [PATCH 4/4] Clear content related maps before the processing of new test class --- .../tree/CgCallableAccessManager.kt | 7 +- .../constructor/tree/CgFieldStateManager.kt | 7 +- .../constructor/tree/CgMethodConstructor.kt | 19 +- .../tree/CgTestClassConstructor.kt | 165 ++++++------------ .../constructor/tree/CgVariableConstructor.kt | 13 +- .../constructor/tree/MockFrameworkManager.kt | 4 +- .../constructor/tree/TestFrameworkManager.kt | 7 +- .../constructor/tree/TestsGenerationReport.kt | 111 ++++++++++++ .../model/constructor/util/CgComponents.kt | 52 ------ .../util/CgStatementConstructor.kt | 6 +- 10 files changed, 206 insertions(+), 185 deletions(-) create mode 100644 utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/TestsGenerationReport.kt delete mode 100644 utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/util/CgComponents.kt diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgCallableAccessManager.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgCallableAccessManager.kt index 83ea4197f3..2c73f18281 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgCallableAccessManager.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgCallableAccessManager.kt @@ -13,7 +13,8 @@ import org.utbot.framework.codegen.model.constructor.builtin.setAccessible 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.tree.CgCallableAccessManagerImpl.FieldAccessorSuitability.* -import org.utbot.framework.codegen.model.constructor.util.CgComponents +import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.getStatementConstructorBy +import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.getVariableConstructorBy import org.utbot.framework.codegen.model.constructor.util.getAmbiguousOverloadsOf import org.utbot.framework.codegen.model.constructor.util.importIfNeeded import org.utbot.framework.codegen.model.constructor.util.isUtil @@ -85,9 +86,9 @@ interface CgCallableAccessManager { internal class CgCallableAccessManagerImpl(val context: CgContext) : CgCallableAccessManager, CgContextOwner by context { - private val statementConstructor by lazy { CgComponents.getStatementConstructorBy(context) } + private val statementConstructor by lazy { getStatementConstructorBy(context) } - private val variableConstructor by lazy { CgComponents.getVariableConstructorBy(context) } + private val variableConstructor by lazy { getVariableConstructorBy(context) } override operator fun CgExpression?.get(methodId: MethodId): CgIncompleteMethodCall = CgIncompleteMethodCall(methodId, this) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgFieldStateManager.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgFieldStateManager.kt index 5be6fd9c3e..2bb300557b 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgFieldStateManager.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgFieldStateManager.kt @@ -4,7 +4,8 @@ import org.utbot.framework.codegen.model.constructor.builtin.forName import org.utbot.framework.codegen.model.constructor.builtin.getArrayElement 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.tree.CgTestClassConstructor.CgComponents.getCallableAccessManagerBy +import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.getStatementConstructorBy import org.utbot.framework.codegen.model.constructor.util.CgFieldState import org.utbot.framework.codegen.model.constructor.util.CgStatementConstructor import org.utbot.framework.codegen.model.constructor.util.FieldStateCache @@ -44,8 +45,8 @@ internal interface CgFieldStateManager { internal class CgFieldStateManagerImpl(val context: CgContext) : CgContextOwner by context, CgFieldStateManager, - CgCallableAccessManager by CgComponents.getCallableAccessManagerBy(context), - CgStatementConstructor by CgComponents.getStatementConstructorBy(context) { + CgCallableAccessManager by getCallableAccessManagerBy(context), + CgStatementConstructor by getStatementConstructorBy(context) { override fun rememberInitialEnvironmentState(info: StateModificationInfo) { rememberThisInstanceState(info, FieldState.INITIAL) 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 dffc0200eb..1fdd1de474 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 @@ -15,7 +15,12 @@ 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.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.tree.CgTestClassConstructor.CgComponents.getCallableAccessManagerBy +import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.getMockFrameworkManagerBy +import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.getNameGeneratorBy +import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.getStatementConstructorBy +import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.getTestFrameworkManagerBy +import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.getVariableConstructorBy import org.utbot.framework.codegen.model.constructor.util.CgStatementConstructor import org.utbot.framework.codegen.model.constructor.util.EnvironmentFieldStateCache import org.utbot.framework.codegen.model.constructor.util.FieldStateCache @@ -148,14 +153,14 @@ import java.lang.reflect.ParameterizedType private const val DEEP_EQUALS_MAX_DEPTH = 5 // TODO move it to plugin settings? internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by context, - CgCallableAccessManager by CgComponents.getCallableAccessManagerBy(context), - CgStatementConstructor by CgComponents.getStatementConstructorBy(context) { + CgCallableAccessManager by getCallableAccessManagerBy(context), + CgStatementConstructor by getStatementConstructorBy(context) { - private val nameGenerator = CgComponents.getNameGeneratorBy(context) - private val testFrameworkManager = CgComponents.getTestFrameworkManagerBy(context) + private val nameGenerator = getNameGeneratorBy(context) + private val testFrameworkManager = getTestFrameworkManagerBy(context) - private val variableConstructor = CgComponents.getVariableConstructorBy(context) - private val mockFrameworkManager = CgComponents.getMockFrameworkManagerBy(context) + private val variableConstructor = getVariableConstructorBy(context) + private val mockFrameworkManager = getMockFrameworkManagerBy(context) private val floatDelta: Float = 1e-6f private val doubleDelta = 1e-6 diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgTestClassConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgTestClassConstructor.kt index 369a32d16b..34b876307e 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgTestClassConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgTestClassConstructor.kt @@ -1,15 +1,26 @@ package org.utbot.framework.codegen.model.constructor.tree -import org.utbot.common.appendHtmlLine +import org.utbot.framework.codegen.Junit4 +import org.utbot.framework.codegen.Junit5 import org.utbot.framework.codegen.ParametrizedTestSource +import org.utbot.framework.codegen.TestNg import org.utbot.framework.codegen.model.constructor.CgMethodTestSet +import org.utbot.framework.codegen.model.constructor.TestClassModel import org.utbot.framework.codegen.model.constructor.builtin.TestClassUtilMethodProvider 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.name.CgNameGenerator +import org.utbot.framework.codegen.model.constructor.name.CgNameGeneratorImpl +import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.clearContextRelatedStorage +import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.getMethodConstructorBy +import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.getNameGeneratorBy +import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.getStatementConstructorBy +import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.getTestFrameworkManagerBy import org.utbot.framework.codegen.model.constructor.util.CgStatementConstructor -import org.utbot.framework.codegen.model.tree.CgMethod +import org.utbot.framework.codegen.model.constructor.util.CgStatementConstructorImpl +import org.utbot.framework.codegen.model.tree.CgAuxiliaryClass import org.utbot.framework.codegen.model.tree.CgExecutableUnderTestCluster +import org.utbot.framework.codegen.model.tree.CgMethod import org.utbot.framework.codegen.model.tree.CgParameterDeclaration import org.utbot.framework.codegen.model.tree.CgRegion import org.utbot.framework.codegen.model.tree.CgSimpleRegion @@ -18,33 +29,32 @@ import org.utbot.framework.codegen.model.tree.CgTestClass import org.utbot.framework.codegen.model.tree.CgTestClassFile import org.utbot.framework.codegen.model.tree.CgTestMethod import org.utbot.framework.codegen.model.tree.CgTestMethodCluster -import org.utbot.framework.codegen.model.tree.CgTestMethodType.* import org.utbot.framework.codegen.model.tree.CgTripleSlashMultilineComment +import org.utbot.framework.codegen.model.tree.CgUtilEntity import org.utbot.framework.codegen.model.tree.CgUtilMethod import org.utbot.framework.codegen.model.tree.buildTestClass import org.utbot.framework.codegen.model.tree.buildTestClassBody import org.utbot.framework.codegen.model.tree.buildTestClassFile import org.utbot.framework.codegen.model.visitor.importUtilMethodDependencies +import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.ExecutableId import org.utbot.framework.plugin.api.MethodId -import org.utbot.framework.plugin.api.UtMethodTestSet -import org.utbot.framework.codegen.model.constructor.TestClassModel -import org.utbot.framework.codegen.model.tree.CgAuxiliaryClass -import org.utbot.framework.codegen.model.tree.CgUtilEntity -import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.UtExecutionSuccess +import org.utbot.framework.plugin.api.UtMethodTestSet import org.utbot.framework.plugin.api.util.description import org.utbot.framework.plugin.api.util.humanReadableName -import org.utbot.framework.plugin.api.util.kClass -import kotlin.reflect.KClass internal class CgTestClassConstructor(val context: CgContext) : CgContextOwner by context, - CgStatementConstructor by CgComponents.getStatementConstructorBy(context) { + CgStatementConstructor by getStatementConstructorBy(context) { + + init { + clearContextRelatedStorage() + } - private val methodConstructor = CgComponents.getMethodConstructorBy(context) - private val nameGenerator = CgComponents.getNameGeneratorBy(context) - private val testFrameworkManager = CgComponents.getTestFrameworkManagerBy(context) + private val methodConstructor = getMethodConstructorBy(context) + private val nameGenerator = getNameGeneratorBy(context) + private val testFrameworkManager = getTestFrameworkManagerBy(context) private val testsGenerationReport: TestsGenerationReport = TestsGenerationReport() @@ -279,106 +289,45 @@ internal class CgTestClassConstructor(val context: CgContext) : */ private val CgMethodTestSet.allErrors: Map get() = errors + codeGenerationErrors.getOrDefault(this, mapOf()) -} -typealias MethodGeneratedTests = MutableMap> -typealias ErrorsCount = Map - -data class TestsGenerationReport( - val executables: MutableSet = mutableSetOf(), - var successfulExecutions: MethodGeneratedTests = mutableMapOf(), - var timeoutExecutions: MethodGeneratedTests = mutableMapOf(), - var failedExecutions: MethodGeneratedTests = mutableMapOf(), - var crashExecutions: MethodGeneratedTests = mutableMapOf(), - var errors: MutableMap = mutableMapOf() -) { - val classUnderTest: KClass<*> - get() = executables.firstOrNull()?.classId?.kClass - ?: error("No executables found in test report") - - val initialWarnings: MutableList<() -> String> = mutableListOf() - val hasWarnings: Boolean - get() = initialWarnings.isNotEmpty() - - val detailedStatistics: String - get() = buildString { - appendHtmlLine("Class: ${classUnderTest.qualifiedName}") - val testMethodsStatistic = executables.map { it.countTestMethods() } - val errors = executables.map { it.countErrors() } - val overallErrors = errors.sum() - - appendHtmlLine("Successful test methods: ${testMethodsStatistic.sumBy { it.successful }}") - appendHtmlLine( - "Failing because of unexpected exception test methods: ${testMethodsStatistic.sumBy { it.failing }}" - ) - appendHtmlLine( - "Failing because of exceeding timeout test methods: ${testMethodsStatistic.sumBy { it.timeout }}" - ) - appendHtmlLine( - "Failing because of possible JVM crash test methods: ${testMethodsStatistic.sumBy { it.crashes }}" - ) - appendHtmlLine("Not generated because of internal errors test methods: $overallErrors") + internal object CgComponents { + /** + * Clears all stored data for current [CgContext]. + * As far as context is created per class under test, + * no related data is required after it's processing. + */ + fun clearContextRelatedStorage() { + nameGenerators.clear() + statementConstructors.clear() + callableAccessManagers.clear() + testFrameworkManagers.clear() + mockFrameworkManagers.clear() + variableConstructors.clear() + methodConstructors.clear() } - fun addMethodErrors(testSet: CgMethodTestSet, errors: Map) { - this.errors[testSet.executableId] = errors - } - - fun addTestsByType(testSet: CgMethodTestSet, testMethods: List) { - with(testSet.executableId) { - executables += this - - testMethods.forEach { - when (it.type) { - SUCCESSFUL -> updateExecutions(it, successfulExecutions) - FAILING -> updateExecutions(it, failedExecutions) - TIMEOUT -> updateExecutions(it, timeoutExecutions) - CRASH -> updateExecutions(it, crashExecutions) - PARAMETRIZED -> { - // Parametrized tests are not supported in the tests report yet - // TODO JIRA:1507 - } - } - } - } - } - - fun toString(isShort: Boolean): String = buildString { - appendHtmlLine("Target: ${classUnderTest.qualifiedName}") - if (initialWarnings.isNotEmpty()) { - initialWarnings.forEach { appendHtmlLine(it()) } - appendHtmlLine() - } + private val nameGenerators: MutableMap = mutableMapOf() + private val statementConstructors: MutableMap = mutableMapOf() + private val callableAccessManagers: MutableMap = mutableMapOf() + private val testFrameworkManagers: MutableMap = mutableMapOf() + private val mockFrameworkManagers: MutableMap = mutableMapOf() - val testMethodsStatistic = executables.map { it.countTestMethods() } - val overallTestMethods = testMethodsStatistic.sumBy { it.count } + private val variableConstructors: MutableMap = mutableMapOf() + private val methodConstructors: MutableMap = mutableMapOf() - appendHtmlLine("Overall test methods: $overallTestMethods") + fun getNameGeneratorBy(context: CgContext) = nameGenerators.getOrPut(context) { CgNameGeneratorImpl(context) } + fun getCallableAccessManagerBy(context: CgContext) = callableAccessManagers.getOrPut(context) { CgCallableAccessManagerImpl(context) } + fun getStatementConstructorBy(context: CgContext) = statementConstructors.getOrPut(context) { CgStatementConstructorImpl(context) } - if (!isShort) { - appendHtmlLine(detailedStatistics) + fun getTestFrameworkManagerBy(context: CgContext) = when (context.testFramework) { + is Junit4 -> testFrameworkManagers.getOrPut(context) { Junit4Manager(context) } + is Junit5 -> testFrameworkManagers.getOrPut(context) { Junit5Manager(context) } + is TestNg -> testFrameworkManagers.getOrPut(context) { TestNgManager(context) } } - } - - override fun toString(): String = toString(false) - - private fun ExecutableId.countTestMethods(): TestMethodStatistic = TestMethodStatistic( - testMethodsNumber(successfulExecutions), - testMethodsNumber(failedExecutions), - testMethodsNumber(timeoutExecutions), - testMethodsNumber(crashExecutions) - ) - - private fun ExecutableId.countErrors(): Int = errors.getOrDefault(this, emptyMap()).values.sum() - private fun ExecutableId.testMethodsNumber(executables: MethodGeneratedTests): Int = - executables.getOrDefault(this, emptySet()).size - - private fun ExecutableId.updateExecutions(it: CgTestMethod, executions: MethodGeneratedTests) { - executions.getOrPut(this) { mutableSetOf() } += it - } - - private data class TestMethodStatistic(val successful: Int, val failing: Int, val timeout: Int, val crashes: Int) { - val count: Int = successful + failing + timeout + crashes + fun getMockFrameworkManagerBy(context: CgContext) = mockFrameworkManagers.getOrPut(context) { MockFrameworkManager(context) } + fun getVariableConstructorBy(context: CgContext) = variableConstructors.getOrPut(context) { CgVariableConstructor(context) } + fun getMethodConstructorBy(context: CgContext) = methodConstructors.getOrPut(context) { CgMethodConstructor(context) } } } + diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgVariableConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgVariableConstructor.kt index b2d038536c..6f13d036ba 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgVariableConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgVariableConstructor.kt @@ -5,7 +5,10 @@ import org.utbot.framework.codegen.model.constructor.builtin.forName 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 +import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.getCallableAccessManagerBy +import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.getMockFrameworkManagerBy +import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.getNameGeneratorBy +import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.getStatementConstructorBy import org.utbot.framework.codegen.model.constructor.util.CgStatementConstructor import org.utbot.framework.codegen.model.constructor.util.MAX_ARRAY_INITIALIZER_SIZE import org.utbot.framework.codegen.model.constructor.util.arrayInitializer @@ -73,11 +76,11 @@ import org.utbot.framework.plugin.api.util.wrapperByPrimitive @Suppress("unused") internal class CgVariableConstructor(val context: CgContext) : CgContextOwner by context, - CgCallableAccessManager by CgComponents.getCallableAccessManagerBy(context), - CgStatementConstructor by CgComponents.getStatementConstructorBy(context) { + CgCallableAccessManager by getCallableAccessManagerBy(context), + CgStatementConstructor by getStatementConstructorBy(context) { - private val nameGenerator = CgComponents.getNameGeneratorBy(context) - private val mockFrameworkManager = CgComponents.getMockFrameworkManagerBy(context) + private val nameGenerator = getNameGeneratorBy(context) + private val mockFrameworkManager = getMockFrameworkManagerBy(context) /** * Take already created CgValue or construct either a new [CgVariable] or new [CgLiteral] for the given model. diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/MockFrameworkManager.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/MockFrameworkManager.kt index 0dedf99d57..9660ab1347 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/MockFrameworkManager.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/MockFrameworkManager.kt @@ -20,7 +20,7 @@ import org.utbot.framework.codegen.model.constructor.builtin.thenReturnMethodId import org.utbot.framework.codegen.model.constructor.builtin.whenMethodId 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.tree.CgTestClassConstructor.CgComponents.getVariableConstructorBy import org.utbot.framework.codegen.model.constructor.util.CgStatementConstructor import org.utbot.framework.codegen.model.constructor.util.CgStatementConstructorImpl import org.utbot.framework.codegen.model.constructor.util.hasAmbiguousOverloadsOf @@ -70,7 +70,7 @@ internal abstract class CgVariableConstructorComponent(val context: CgContext) : CgCallableAccessManager by CgCallableAccessManagerImpl(context), CgStatementConstructor by CgStatementConstructorImpl(context) { - val variableConstructor: CgVariableConstructor by lazy { CgComponents.getVariableConstructorBy(context) } + val variableConstructor: CgVariableConstructor by lazy { getVariableConstructorBy(context) } fun mockitoArgumentMatchersFor(executable: ExecutableId): Array = executable.parameters.map { 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 576440dfc3..fcc8ee0200 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 @@ -7,7 +7,8 @@ import org.utbot.framework.codegen.model.constructor.TestClassContext import org.utbot.framework.codegen.model.constructor.builtin.forName 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.tree.CgTestClassConstructor.CgComponents.getCallableAccessManagerBy +import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.getStatementConstructorBy 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 @@ -51,7 +52,7 @@ import java.util.concurrent.TimeUnit @Suppress("MemberVisibilityCanBePrivate") internal abstract class TestFrameworkManager(val context: CgContext) : CgContextOwner by context, - CgCallableAccessManager by CgComponents.getCallableAccessManagerBy(context) { + CgCallableAccessManager by getCallableAccessManagerBy(context) { val assertions = context.testFramework.assertionsClass @@ -79,7 +80,7 @@ internal abstract class TestFrameworkManager(val context: CgContext) // all data providers should be placed in the outermost class. protected abstract val dataProviderMethodsHolder: TestClassContext - protected val statementConstructor = CgComponents.getStatementConstructorBy(context) + protected val statementConstructor = getStatementConstructorBy(context) abstract val annotationForNestedClasses: CgAnnotation? diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/TestsGenerationReport.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/TestsGenerationReport.kt new file mode 100644 index 0000000000..606ef293af --- /dev/null +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/TestsGenerationReport.kt @@ -0,0 +1,111 @@ +package org.utbot.framework.codegen.model.constructor.tree + +import org.utbot.common.appendHtmlLine +import org.utbot.framework.codegen.model.constructor.CgMethodTestSet +import org.utbot.framework.codegen.model.tree.CgTestMethod +import org.utbot.framework.codegen.model.tree.CgTestMethodType +import org.utbot.framework.plugin.api.ExecutableId +import org.utbot.framework.plugin.api.util.kClass +import kotlin.reflect.KClass + +typealias MethodGeneratedTests = MutableMap> +typealias ErrorsCount = Map + +data class TestsGenerationReport( + val executables: MutableSet = mutableSetOf(), + var successfulExecutions: MethodGeneratedTests = mutableMapOf(), + var timeoutExecutions: MethodGeneratedTests = mutableMapOf(), + var failedExecutions: MethodGeneratedTests = mutableMapOf(), + var crashExecutions: MethodGeneratedTests = mutableMapOf(), + var errors: MutableMap = mutableMapOf() +) { + val classUnderTest: KClass<*> + get() = executables.firstOrNull()?.classId?.kClass + ?: error("No executables found in test report") + + val initialWarnings: MutableList<() -> String> = mutableListOf() + val hasWarnings: Boolean + get() = initialWarnings.isNotEmpty() + + val detailedStatistics: String + get() = buildString { + appendHtmlLine("Class: ${classUnderTest.qualifiedName}") + val testMethodsStatistic = executables.map { it.countTestMethods() } + val errors = executables.map { it.countErrors() } + val overallErrors = errors.sum() + + appendHtmlLine("Successful test methods: ${testMethodsStatistic.sumBy { it.successful }}") + appendHtmlLine( + "Failing because of unexpected exception test methods: ${testMethodsStatistic.sumBy { it.failing }}" + ) + appendHtmlLine( + "Failing because of exceeding timeout test methods: ${testMethodsStatistic.sumBy { it.timeout }}" + ) + appendHtmlLine( + "Failing because of possible JVM crash test methods: ${testMethodsStatistic.sumBy { it.crashes }}" + ) + appendHtmlLine("Not generated because of internal errors test methods: $overallErrors") + } + + fun addMethodErrors(testSet: CgMethodTestSet, errors: Map) { + this.errors[testSet.executableId] = errors + } + + fun addTestsByType(testSet: CgMethodTestSet, testMethods: List) { + with(testSet.executableId) { + executables += this + + testMethods.forEach { + when (it.type) { + CgTestMethodType.SUCCESSFUL -> updateExecutions(it, successfulExecutions) + CgTestMethodType.FAILING -> updateExecutions(it, failedExecutions) + CgTestMethodType.TIMEOUT -> updateExecutions(it, timeoutExecutions) + CgTestMethodType.CRASH -> updateExecutions(it, crashExecutions) + CgTestMethodType.PARAMETRIZED -> { + // Parametrized tests are not supported in the tests report yet + // TODO JIRA:1507 + } + } + } + } + } + + fun toString(isShort: Boolean): String = buildString { + appendHtmlLine("Target: ${classUnderTest.qualifiedName}") + if (initialWarnings.isNotEmpty()) { + initialWarnings.forEach { appendHtmlLine(it()) } + appendHtmlLine() + } + + val testMethodsStatistic = executables.map { it.countTestMethods() } + val overallTestMethods = testMethodsStatistic.sumBy { it.count } + + appendHtmlLine("Overall test methods: $overallTestMethods") + + if (!isShort) { + appendHtmlLine(detailedStatistics) + } + } + + override fun toString(): String = toString(false) + + private fun ExecutableId.countTestMethods(): TestMethodStatistic = TestMethodStatistic( + testMethodsNumber(successfulExecutions), + testMethodsNumber(failedExecutions), + testMethodsNumber(timeoutExecutions), + testMethodsNumber(crashExecutions) + ) + + private fun ExecutableId.countErrors(): Int = errors.getOrDefault(this, emptyMap()).values.sum() + + private fun ExecutableId.testMethodsNumber(executables: MethodGeneratedTests): Int = + executables.getOrDefault(this, emptySet()).size + + private fun ExecutableId.updateExecutions(it: CgTestMethod, executions: MethodGeneratedTests) { + executions.getOrPut(this) { mutableSetOf() } += it + } + + private data class TestMethodStatistic(val successful: Int, val failing: Int, val timeout: Int, val crashes: Int) { + val count: Int = successful + failing + timeout + crashes + } +} \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/util/CgComponents.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/util/CgComponents.kt deleted file mode 100644 index 01275f80fc..0000000000 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/util/CgComponents.kt +++ /dev/null @@ -1,52 +0,0 @@ -package org.utbot.framework.codegen.model.constructor.util - -import org.utbot.framework.codegen.Junit4 -import org.utbot.framework.codegen.Junit5 -import org.utbot.framework.codegen.TestNg -import org.utbot.framework.codegen.model.constructor.context.CgContext -import org.utbot.framework.codegen.model.constructor.name.CgNameGenerator -import org.utbot.framework.codegen.model.constructor.name.CgNameGeneratorImpl -import org.utbot.framework.codegen.model.constructor.tree.CgCallableAccessManager -import org.utbot.framework.codegen.model.constructor.tree.CgCallableAccessManagerImpl -import org.utbot.framework.codegen.model.constructor.tree.CgMethodConstructor -import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor -import org.utbot.framework.codegen.model.constructor.tree.CgVariableConstructor -import org.utbot.framework.codegen.model.constructor.tree.CgFieldStateManager -import org.utbot.framework.codegen.model.constructor.tree.CgFieldStateManagerImpl -import org.utbot.framework.codegen.model.constructor.tree.Junit4Manager -import org.utbot.framework.codegen.model.constructor.tree.Junit5Manager -import org.utbot.framework.codegen.model.constructor.tree.MockFrameworkManager -import org.utbot.framework.codegen.model.constructor.tree.TestFrameworkManager -import org.utbot.framework.codegen.model.constructor.tree.TestNgManager - -// TODO: probably rewrite it to delegates so that we could write 'val testFrameworkManager by CgComponents' etc. -internal object CgComponents { - fun getNameGeneratorBy(context: CgContext) = nameGenerators.getOrPut(context) { CgNameGeneratorImpl(context) } - - fun getCallableAccessManagerBy(context: CgContext) = - callableAccessManagers.getOrPut(context) { CgCallableAccessManagerImpl(context) } - - fun getStatementConstructorBy(context: CgContext) = - statementConstructors.getOrPut(context) { CgStatementConstructorImpl(context) } - - fun getTestFrameworkManagerBy(context: CgContext) = when (context.testFramework) { - is Junit4 -> testFrameworkManagers.getOrPut(context) { Junit4Manager(context) } - is Junit5 -> testFrameworkManagers.getOrPut(context) { Junit5Manager(context) } - is TestNg -> testFrameworkManagers.getOrPut(context) { TestNgManager(context) } - } - - fun getMockFrameworkManagerBy(context: CgContext) = mockFrameworkManagers.getOrPut(context) { MockFrameworkManager(context) } - - fun getVariableConstructorBy(context: CgContext) = variableConstructors.getOrPut(context) { CgVariableConstructor(context) } - - fun getMethodConstructorBy(context: CgContext) = methodConstructors.getOrPut(context) { CgMethodConstructor(context) } - - private val nameGenerators: MutableMap = mutableMapOf() - private val statementConstructors: MutableMap = mutableMapOf() - private val callableAccessManagers: MutableMap = mutableMapOf() - private val testFrameworkManagers: MutableMap = mutableMapOf() - private val mockFrameworkManagers: MutableMap = mutableMapOf() - - private val variableConstructors: MutableMap = mutableMapOf() - private val methodConstructors: MutableMap = mutableMapOf() -} \ No newline at end of file diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/util/CgStatementConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/util/CgStatementConstructor.kt index 53f7742726..5908cd6d27 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/util/CgStatementConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/util/CgStatementConstructor.kt @@ -59,6 +59,8 @@ import fj.data.Either import org.utbot.framework.codegen.model.constructor.builtin.getDeclaredConstructor import org.utbot.framework.codegen.model.constructor.builtin.getDeclaredField import org.utbot.framework.codegen.model.constructor.builtin.getDeclaredMethod +import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.getCallableAccessManagerBy +import org.utbot.framework.codegen.model.constructor.tree.CgTestClassConstructor.CgComponents.getNameGeneratorBy import org.utbot.framework.codegen.model.tree.CgArrayInitializer import org.utbot.framework.codegen.model.tree.CgGetJavaClass import org.utbot.framework.codegen.model.tree.CgIsInstance @@ -187,9 +189,9 @@ interface CgStatementConstructor { internal class CgStatementConstructorImpl(context: CgContext) : CgStatementConstructor, CgContextOwner by context, - CgCallableAccessManager by CgComponents.getCallableAccessManagerBy(context) { + CgCallableAccessManager by getCallableAccessManagerBy(context) { - private val nameGenerator = CgComponents.getNameGeneratorBy(context) + private val nameGenerator = getNameGeneratorBy(context) override fun createDeclarationForNewVarAndUpdateVariableScopeOrGetExistingVariable( baseType: ClassId,