diff --git a/utbot-greyboxfuzzer/src/main/kotlin/org/utbot/greyboxfuzzer/GreyBoxFuzzer.kt b/utbot-greyboxfuzzer/src/main/kotlin/org/utbot/greyboxfuzzer/GreyBoxFuzzer.kt index 8d3ef81250..2ccf05838c 100644 --- a/utbot-greyboxfuzzer/src/main/kotlin/org/utbot/greyboxfuzzer/GreyBoxFuzzer.kt +++ b/utbot-greyboxfuzzer/src/main/kotlin/org/utbot/greyboxfuzzer/GreyBoxFuzzer.kt @@ -41,6 +41,7 @@ class GreyBoxFuzzer( private val timeOfStart = System.currentTimeMillis() private val percentageOfTimeBudgetToChangeMode = 25 private val logger = KotlinLogging.logger {} + private val classMutator = Mutator() init { GenericsInfoFactory.disableCache() @@ -97,7 +98,7 @@ class GreyBoxFuzzer( regenerateThis = false } else if (Random.getTrue(60)) { logger.debug { "Trying to mutate this instance" } - thisInstancesHistory += Mutator.mutateThisInstance( + thisInstancesHistory += classMutator.mutateThisInstance( thisInstancesHistory.last(), classFieldsUsedByFunc.toList(), generatorContext @@ -207,7 +208,7 @@ class GreyBoxFuzzer( val randomSeed = seeds.getRandomWeightedSeed() logger.debug { "Random seed params = ${randomSeed.parameters}" } val mutatedSeed = - Mutator.mutateSeed( + classMutator.mutateSeed( randomSeed, GreyBoxFuzzerGeneratorsAndSettings.sourceOfRandomness, GreyBoxFuzzerGeneratorsAndSettings.genStatus diff --git a/utbot-greyboxfuzzer/src/main/kotlin/org/utbot/greyboxfuzzer/generator/DataGenerator.kt b/utbot-greyboxfuzzer/src/main/kotlin/org/utbot/greyboxfuzzer/generator/DataGenerator.kt index c37101f6ee..199130bbbe 100644 --- a/utbot-greyboxfuzzer/src/main/kotlin/org/utbot/greyboxfuzzer/generator/DataGenerator.kt +++ b/utbot-greyboxfuzzer/src/main/kotlin/org/utbot/greyboxfuzzer/generator/DataGenerator.kt @@ -29,7 +29,7 @@ object DataGenerator { ): UtModel { val classId = parameterTypeContext.rawClass.id logger.debug { "Trying to generate UtModel of type ${classId.name} 3 times" } - var generatedInstance: UtModel? = null + var generatedInstance: UtModel? repeat(3) { generatedInstance = try { diff --git a/utbot-greyboxfuzzer/src/main/kotlin/org/utbot/greyboxfuzzer/generator/userclasses/UserClassGenerator.kt b/utbot-greyboxfuzzer/src/main/kotlin/org/utbot/greyboxfuzzer/generator/userclasses/UserClassGenerator.kt index 2a11c8c697..7d5c3987d3 100644 --- a/utbot-greyboxfuzzer/src/main/kotlin/org/utbot/greyboxfuzzer/generator/userclasses/UserClassGenerator.kt +++ b/utbot-greyboxfuzzer/src/main/kotlin/org/utbot/greyboxfuzzer/generator/userclasses/UserClassGenerator.kt @@ -164,7 +164,7 @@ class UserClassGenerator : ComponentizedGenerator(Any::class.java) { val resolvedJavaType = parameterTypeContext!!.generics.resolveType(parameterTypeContext!!.type()) val gctx = resolvedJavaType.createGenericsContext(clazz!!) if (clazz == randomFieldDeclaringClass) { - return Mutator.regenerateFieldWithContext(gctx, cachedUtModel, randomField, generatorContext)?.let { + return Mutator().regenerateFieldWithContext(gctx, cachedUtModel, randomField, generatorContext)?.let { mutatedFields[randomField] = it.second it.first } ?: cachedUtModel @@ -184,7 +184,7 @@ class UserClassGenerator : ComponentizedGenerator(Any::class.java) { clazz!!, chain.map { it!! }.reversed().drop(1) ) ?: return cachedUtModel - return Mutator.regenerateFieldWithContext(genericsContext, cachedUtModel, randomField, generatorContext) + return Mutator().regenerateFieldWithContext(genericsContext, cachedUtModel, randomField, generatorContext) ?.let { mutatedFields[randomField] = it.second it.first diff --git a/utbot-greyboxfuzzer/src/main/kotlin/org/utbot/greyboxfuzzer/generator/userclasses/generator/InterfaceImplementationsInstanceGenerator.kt b/utbot-greyboxfuzzer/src/main/kotlin/org/utbot/greyboxfuzzer/generator/userclasses/generator/InterfaceImplementationsInstanceGenerator.kt index 39f22141ed..2d9557681f 100644 --- a/utbot-greyboxfuzzer/src/main/kotlin/org/utbot/greyboxfuzzer/generator/userclasses/generator/InterfaceImplementationsInstanceGenerator.kt +++ b/utbot-greyboxfuzzer/src/main/kotlin/org/utbot/greyboxfuzzer/generator/userclasses/generator/InterfaceImplementationsInstanceGenerator.kt @@ -3,7 +3,6 @@ package org.utbot.greyboxfuzzer.generator.userclasses.generator import org.utbot.common.isAbstract -import org.utbot.greyboxfuzzer.generator.DataGenerator import org.utbot.greyboxfuzzer.generator.QuickCheckExtensions import org.utbot.greyboxfuzzer.util.* import org.utbot.greyboxfuzzer.util.logger @@ -11,6 +10,9 @@ import org.utbot.framework.plugin.api.* import org.utbot.framework.plugin.api.util.executableId import org.utbot.framework.plugin.api.util.id import org.utbot.framework.plugin.api.util.objectClassId +import org.utbot.greyboxfuzzer.generator.GreyBoxFuzzerGeneratorsAndSettings.generatorRepository +import org.utbot.greyboxfuzzer.generator.getOrProduceGenerator +import org.utbot.greyboxfuzzer.generator.userclasses.UserClassGenerator import org.utbot.greyboxfuzzer.quickcheck.generator.GenerationStatus import org.utbot.greyboxfuzzer.quickcheck.generator.GeneratorContext import org.utbot.greyboxfuzzer.quickcheck.internal.ParameterTypeContext @@ -30,6 +32,9 @@ class InterfaceImplementationsInstanceGenerator( override fun generate(): UtModel { //Try to generate with statics with some probability val clazz = resolvedType.toClass() ?: return UtNullModel(objectClassId) + if (clazz.name.contains("HttpOutputMessage")) { + println() + } if (Random.getTrue(50)) { try { StaticsBasedInstanceGenerator( @@ -47,10 +52,20 @@ class InterfaceImplementationsInstanceGenerator( } } val genericsContext = - QuickCheckExtensions.getRandomImplementerGenericContext(clazz, resolvedType)// ?: return UtNullModel(clazz.id) - if (genericsContext == null || Random.getTrue(30)) { - return generateMock(clazz, resolvedType, typeContext, generatorContext) + QuickCheckExtensions.getRandomImplementerGenericContext( + clazz, + resolvedType + )// ?: return UtNullModel(clazz.id) + logger.debug { "Implementer of ${clazz.name}! It is a ${genericsContext?.currentClass()?.name}" } + if (genericsContext == null || Random.getTrue(5)) { + logger.debug { "Generate mock anyway" } + return try { + generateMock(clazz, resolvedType, typeContext, generatorContext) + } catch (e: Throwable) { + UtNullModel(clazz.id) + } } + logger.debug { "Trying to generate implementer ${genericsContext.currentClass().name}" } val resUtModel = ClassesInstanceGenerator( genericsContext.currentClass(), @@ -79,13 +94,22 @@ class InterfaceImplementationsInstanceGenerator( ) else -> resUtModel } - .let { - if (it is UtNullModel && Random.getTrue(50)) generateMock( - clazz, - resolvedType, - typeContext, - generatorContext - ) else it + .let { + if (it is UtNullModel && Random.getTrue(50)) { + try { + generateMock( + clazz, + resolvedType, + typeContext, + generatorContext + ) + }catch (e: Throwable) { + it + } + } + else { + it + } } } @@ -95,33 +119,45 @@ class InterfaceImplementationsInstanceGenerator( typeContext: GenericsContext, generatorContext: GeneratorContext ): UtModel { + logger.debug { "Mock generation" } if (!clazz.isInterface) return UtNullModel(clazz.id) val sootClazz = clazz.toSootClass() ?: return UtNullModel(clazz.id) val constructor = generatorContext.utModelConstructor val allNeededInterfaces = clazz.methods.map { it.declaringClass }.filter { it != clazz }.toSet() - val chainToGenericsContext = allNeededInterfaces.map { cl -> - val chain = cl.toSootClass() - ?.getImplementersOfWithChain() - ?.filter { it.contains(sootClazz) } - ?.map { it.dropLastWhile { it != sootClazz } } - ?.minByOrNull { it.size } - ?.map { it.toJavaClass() } - if (chain == null || chain.any { it == null }) { - null - } else { - cl to QuickCheckExtensions.buildGenericsContextForInterfaceParent( - resolvedType, - clazz, - chain.map { it!! }.reversed().drop(1) - ) - } - } - val allChainToGenericsContext = chainToGenericsContext + (clazz to typeContext) + val allChainToGenericsContext = allNeededInterfaces.map { it to ParameterTypeContext.forClass(it).generics } + (clazz to typeContext) +// if (allNeededInterfaces.all { it.typeParameters.isEmpty() }) { +// allNeededInterfaces.map { it to ParameterTypeContext.forType(it).generics } +// } else { +// //TODO debug this +// val chainToGenericsContext = allNeededInterfaces.map { cl -> +// val chain = cl.toSootClass() +// ?.getImplementersOfWithChain(onlyConcreteClasses = false, allowNotOnlyStdLib = true) +// ?.filter { it.contains(sootClazz) } +// ?.map { it.dropLastWhile { it != sootClazz } } +// ?.minByOrNull { it.size } +// ?.map { it.toJavaClass() } +// if (chain == null || chain.any { it == null }) { +// null +// } else { +// cl to QuickCheckExtensions.buildGenericsContextForInterfaceParent( +// resolvedType, +// clazz, +// chain.map { it!! }.reversed().drop(1) +// ) +// } +// } +// chainToGenericsContext + (clazz to typeContext) +// } + //val allChainToGenericsContext = chainToGenericsContext + (clazz to typeContext) val mocks = clazz.methods .filter { it.isAbstract } .associateTo(mutableMapOf()) { method -> val genericsContextForMethod = - allChainToGenericsContext.find { it!!.first == method.declaringClass }?.second + try { + allChainToGenericsContext.find { it!!.first == method.declaringClass }?.second + } catch (e: Throwable) { + null + } val methodReturnType = if (genericsContextForMethod != null) { genericsContextForMethod.method(method).resolveReturnType().let { @@ -133,13 +169,7 @@ class InterfaceImplementationsInstanceGenerator( val parameterTypeContext = ParameterTypeContext.forType(methodReturnType, genericsContextForMethod) val generatedUtModelWithReturnType = try { - DataGenerator.generateUtModel( - parameterTypeContext, - depth, - generatorContext, - sourceOfRandomness, - generationStatus - ) + generateUtModelForMock(parameterTypeContext, depth, generatorContext, sourceOfRandomness, generationStatus) } catch (_: Throwable) { UtNullModel(methodReturnType.toClass()!!.id) } @@ -148,6 +178,34 @@ class InterfaceImplementationsInstanceGenerator( return UtCompositeModel(constructor.computeUnusedIdAndUpdate(), clazz.id, isMock = true, mocks = mocks) } + private fun generateUtModelForMock( + parameterTypeContext: ParameterTypeContext, + depth: Int = 0, + generatorContext: GeneratorContext, + random: SourceOfRandomness, + status: GenerationStatus + ): UtModel { + val classId = parameterTypeContext.rawClass.id + logger.debug { "Trying to generate UtModel of type ${classId.name} 3 times" } + if (parameterTypeContext.getAllSubParameterTypeContexts(sourceOfRandomness).any { it.rawClass.isInterface }) { + return UtNullModel(classId) + } + var generatedInstance: UtModel? + repeat(3) { + generatedInstance = + try { + val generator = + generatorRepository.getOrProduceGenerator(parameterTypeContext, generatorContext, depth) + ?: return@repeat + generator.generateImpl(random, status) + } catch (_: Throwable) { + null + } + generatedInstance?.let { if (it !is UtNullModel) return it } + } + return UtNullModel(classId) + } + // private fun buildGenericsContextForInterfaceParent(resolvedType: Type, clazz: Class<*>, parentChain: List>): GenericsContext? { // val generics = mutableListOf>>() // var curClass = clazz diff --git a/utbot-greyboxfuzzer/src/main/kotlin/org/utbot/greyboxfuzzer/mutator/Mutator.kt b/utbot-greyboxfuzzer/src/main/kotlin/org/utbot/greyboxfuzzer/mutator/Mutator.kt index 781151d66a..6f7251ac50 100644 --- a/utbot-greyboxfuzzer/src/main/kotlin/org/utbot/greyboxfuzzer/mutator/Mutator.kt +++ b/utbot-greyboxfuzzer/src/main/kotlin/org/utbot/greyboxfuzzer/mutator/Mutator.kt @@ -17,7 +17,7 @@ import java.lang.reflect.Field import java.lang.reflect.Modifier import kotlin.random.Random -object Mutator { +class Mutator { fun mutateSeed(seed: Seed, sourceOfRandomness: SourceOfRandomness, genStatus: GenerationStatus): Seed { val seedCopy = seed.copy() diff --git a/utbot-greyboxfuzzer/src/main/kotlin/org/utbot/greyboxfuzzer/util/ReflectionUtils.kt b/utbot-greyboxfuzzer/src/main/kotlin/org/utbot/greyboxfuzzer/util/ReflectionUtils.kt index 62d3759eaa..199e0a6580 100644 --- a/utbot-greyboxfuzzer/src/main/kotlin/org/utbot/greyboxfuzzer/util/ReflectionUtils.kt +++ b/utbot-greyboxfuzzer/src/main/kotlin/org/utbot/greyboxfuzzer/util/ReflectionUtils.kt @@ -228,6 +228,17 @@ val ParameterizedTypeImpl.actualTypeArgumentsRecursive: List return res } +fun Class<*>.isFromSameJar(other: Class<*>) = + try { + val thisJar = + this.getResource('/' + this.name.replace('.', '/') + ".class")?.path?.substringBefore(".jar!") ?: "1" + val otherJar = + other.getResource('/' + other.name.replace('.', '/') + ".class")?.path?.substringBefore(".jar!") ?: "2" + thisJar == otherJar + } catch (e: Throwable) { + false + } + //fun Parameter.replaceUnresolvedGenericsToRandomTypes() { // val allUnresolvedTypesInType = (this.parameterizedType as? ParameterizedTypeImpl) diff --git a/utbot-greyboxfuzzer/src/main/kotlin/org/utbot/greyboxfuzzer/util/SootUtils.kt b/utbot-greyboxfuzzer/src/main/kotlin/org/utbot/greyboxfuzzer/util/SootUtils.kt index 19c68f6819..0af0ce2cfa 100644 --- a/utbot-greyboxfuzzer/src/main/kotlin/org/utbot/greyboxfuzzer/util/SootUtils.kt +++ b/utbot-greyboxfuzzer/src/main/kotlin/org/utbot/greyboxfuzzer/util/SootUtils.kt @@ -22,12 +22,12 @@ import java.lang.reflect.Method import kotlin.reflect.KFunction import kotlin.reflect.jvm.javaMethod -fun SootClass.getImplementersOfWithChain(): List> { +fun SootClass.getImplementersOfWithChain(onlyConcreteClasses: Boolean = true, allowNotOnlyStdLib: Boolean = false): List> { this.checkLevel(SootClass.HIERARCHY) // if (!this.isInterface && !this.isAbstract) { // throw RuntimeException("interfaced needed; got $this") // } - val hierarchy = Hierarchy() + val thisAsJavaClass = this.toJavaClass() ?: return emptyList() val res = mutableListOf(mutableListOf(this)) val queue = ArrayDeque() queue.add(this) @@ -35,14 +35,15 @@ fun SootClass.getImplementersOfWithChain(): List> { val curSootClass = queue.removeFirst() val implementers = if (curSootClass.isInterface) { - hierarchy.getDirectImplementersOf(curSootClass) - .filter { it.interfaces.contains(curSootClass) } + hierarchy.getDirectSubinterfacesOf(curSootClass) + Scene.v().classes.filter { it.interfaces.contains(curSootClass) } + .filter { it.interfaces.contains(curSootClass) } //+ hierarchy.getDirectSubinterfacesOf(curSootClass) } else { - hierarchy.getDirectSubclassesOf(curSootClass) + Scene.v().classes.filter { it.superclassOrNull == curSootClass } + //hierarchy.getDirectSubclassesOf(curSootClass) } if (implementers.isEmpty()) continue val oldLists = res.removeIfAndReturnRemovedElements { it.last() == curSootClass } - if (curSootClass.isConcrete) { + if (curSootClass.isConcrete || !onlyConcreteClasses) { oldLists.forEach { res.add(it.toMutableList()) } } for (implementer in implementers) { @@ -51,12 +52,14 @@ fun SootClass.getImplementersOfWithChain(): List> { } } return res.filter { - val isJavaStdLibClass = it.last().javaPackageName.startsWith("java") - val isFromSameProject = it.last().javaPackageName.contains(this.javaPackageName) || this.javaPackageName.contains(it.last().javaPackageName) + val isJavaStdLibClass = it.last().javaPackageName.startsWith("java") || allowNotOnlyStdLib + val isFromSameProject = it.last().toJavaClass()?.isFromSameJar(thisAsJavaClass) ?: false + //it.last().javaPackageName.contains(this.javaPackageName) || this.javaPackageName.contains(it.last().javaPackageName) val isFromSamePackage = it.last().javaPackageName == this.javaPackageName val isSupportedPackage = isJavaStdLibClass || isFromSameProject val isAccessible = it.last().isPublic || (!it.last().isPublic && isFromSamePackage) - it.all { !it.toString().contains("$") } && isAccessible && it.last().isConcrete && isSupportedPackage + val isConcrete = !onlyConcreteClasses || it.last().isConcrete + it.all { !it.toString().contains("$") } && isAccessible && isConcrete && isSupportedPackage } } diff --git a/utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/model/constructor/visitor/CgPythonRenderer.kt b/utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/model/constructor/visitor/CgPythonRenderer.kt index 7dc3fed93a..edfdc85e44 100644 --- a/utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/model/constructor/visitor/CgPythonRenderer.kt +++ b/utbot-python/src/main/kotlin/org/utbot/python/framework/codegen/model/constructor/visitor/CgPythonRenderer.kt @@ -47,6 +47,7 @@ import org.utbot.framework.codegen.domain.models.CgStatement import org.utbot.framework.codegen.domain.models.CgSwitchCase import org.utbot.framework.codegen.domain.models.CgSwitchCaseLabel import org.utbot.framework.codegen.domain.models.CgTestMethod +import org.utbot.framework.codegen.domain.models.CgMockMethod import org.utbot.framework.codegen.domain.models.CgThisInstance import org.utbot.framework.codegen.domain.models.CgTripleSlashMultilineComment import org.utbot.framework.codegen.domain.models.CgTryCatch @@ -310,6 +311,8 @@ internal class CgPythonRenderer( print(")") } + override fun renderMethodSignature(element: CgMockMethod): Unit = renderMethodSignature(element) + override fun renderMethodSignature(element: CgErrorTestMethod) { print("def ") print(element.name)