Skip to content

Minimize exceptions in signature #418

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 3 commits into from
Jul 8, 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
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ data class UtExecutionSuccess(val model: UtModel) : UtExecutionResult() {

sealed class UtExecutionFailure : UtExecutionResult() {
abstract val exception: Throwable
val isCheckedException get() = !(exception is RuntimeException || exception is Error)
}

data class UtOverflowFailure(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.utbot.framework.plugin.api.util

val Throwable.description
get() = message?.replace('\n', '\t') ?: "<Throwable with empty message>"

val Throwable.isCheckedException
get() = !(this is RuntimeException || this is Error)

val Class<*>.isCheckedException
get() = !(RuntimeException::class.java.isAssignableFrom(this) || Error::class.java.isAssignableFrom(this))
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ import org.utbot.framework.plugin.api.util.id
import org.utbot.framework.plugin.api.util.jClass
import org.utbot.framework.plugin.api.util.signature
import org.utbot.framework.plugin.api.util.utContext
import org.utbot.framework.util.description
import org.utbot.framework.plugin.api.util.description
import org.utbot.framework.util.executableId
import org.utbot.fuzzer.FuzzedMethodDescription
import org.utbot.fuzzer.ModelProvider
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ import org.utbot.framework.plugin.api.UtMethod
import org.utbot.framework.plugin.api.UtModel
import org.utbot.framework.plugin.api.UtReferenceModel
import org.utbot.framework.plugin.api.UtTestCase
import org.utbot.framework.plugin.api.util.executableId
import java.util.IdentityHashMap
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.PersistentMap
Expand All @@ -55,6 +54,11 @@ import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.persistentMapOf
import kotlinx.collections.immutable.persistentSetOf
import org.utbot.framework.codegen.model.constructor.builtin.streamsDeepEqualsMethodId
import org.utbot.framework.plugin.api.util.executableId
import org.utbot.framework.plugin.api.util.id
import org.utbot.framework.plugin.api.util.isCheckedException
import org.utbot.framework.plugin.api.util.isSubtypeOf
import org.utbot.framework.plugin.api.util.jClass

/**
* Interface for all code generation context aware entities
Expand Down Expand Up @@ -232,7 +236,22 @@ internal interface CgContextOwner {
currentExecutable = method.callable.executableId
}

fun addException(exception: ClassId) {
fun addExceptionIfNeeded(exception: ClassId) {
if (exception !is BuiltinClassId) {
require(exception isSubtypeOf Throwable::class.id) {
"Class $exception which is not a Throwable was passed"
}

val isUnchecked = !exception.jClass.isCheckedException
val alreadyAdded =
collectedExceptions.any { existingException -> exception isSubtypeOf existingException }

if (isUnchecked || alreadyAdded) return

collectedExceptions
.removeIf { existingException -> existingException isSubtypeOf exception }
}

if (collectedExceptions.add(exception)) {
importIfNeeded(exception)
}
Expand Down Expand Up @@ -416,9 +435,9 @@ internal data class CgContext(
val simpleName = testClassCustomName ?: "${createTestClassName(classUnderTest.name)}Test"
val name = "$packagePrefix$simpleName"
BuiltinClassId(
name = name,
canonicalName = name,
simpleName = simpleName
name = name,
canonicalName = name,
simpleName = simpleName
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,15 +127,12 @@ internal class CgCallableAccessManagerImpl(val context: CgContext) : CgCallableA
//Builtin methods does not have jClass, so [methodId.method] will crash on it,
//so we need to collect required exceptions manually from source codes
if (methodId is BuiltinMethodId) {
methodId.findExceptionTypes().forEach { addException(it) }
methodId.findExceptionTypes().forEach { addExceptionIfNeeded(it) }
return
}
//If [InvocationTargetException] is thrown manually in test, we need
// to add "throws Throwable" and other exceptions are not required so on.

if (methodId == getTargetException) {
collectedExceptions.clear()
addException(Throwable::class.id)
return
addExceptionIfNeeded(Throwable::class.id)
}

val methodIsUnderTestAndThrowsExplicitly = methodId == currentExecutable
Expand All @@ -148,16 +145,18 @@ internal class CgCallableAccessManagerImpl(val context: CgContext) : CgCallableA
return
}

methodId.method.exceptionTypes.forEach { addException(it.id) }
methodId.method.exceptionTypes.forEach { addExceptionIfNeeded(it.id) }
}

private fun newConstructorCall(constructorId: ConstructorId) {
importIfNeeded(constructorId.classId)
for (exception in constructorId.exceptions) {
addException(exception)
addExceptionIfNeeded(exception)
}
}

//WARN: if you make changes in the following sets of exceptions,
//don't forget to change them in hardcoded [UtilMethods] as well
private fun BuiltinMethodId.findExceptionTypes(): Set<ClassId> {
if (!this.isUtil) return emptySet()

Expand All @@ -167,9 +166,9 @@ internal class CgCallableAccessManagerImpl(val context: CgContext) : CgCallableA
getStaticFieldValueMethodId,
getFieldValueMethodId,
setStaticFieldMethodId,
setFieldMethodId,
createInstanceMethodId,
getUnsafeInstanceMethodId -> setOf(Exception::class.id)
setFieldMethodId -> setOf(IllegalAccessException::class.id, NoSuchFieldException::class.id)
createInstanceMethodId -> setOf(Exception::class.id)
getUnsafeInstanceMethodId -> setOf(ClassNotFoundException::class.id, NoSuchFieldException::class.id, IllegalAccessException::class.id)
createArrayMethodId -> setOf(ClassNotFoundException::class.id)
deepEqualsMethodId,
arraysDeepEqualsMethodId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1300,14 +1300,15 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
utTestCase: UtTestCase,
dataProviderMethodName: String
): CgParameterizedTestDataProviderMethod {
val parametersStatements = mutableListOf<CgStatement>()
val dataProviderStatements = mutableListOf<CgStatement>()
val dataProviderExceptions = mutableSetOf<ClassId>()

val argListLength = utTestCase.executions.size
val argListDeclaration = createArgList(argListLength)
val argListVariable = argListDeclaration.variable

parametersStatements += argListDeclaration
parametersStatements += CgEmptyLine()
dataProviderStatements += argListDeclaration
dataProviderStatements += CgEmptyLine()

for ((execIndex, execution) in utTestCase.executions.withIndex()) {
withTestMethodScope(execution) {
Expand Down Expand Up @@ -1347,22 +1348,25 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
}

//create a block for current test case
parametersStatements += innerBlock(
dataProviderStatements += innerBlock(
{},
block(executionArgumentsBody)
+ createArgumentsCallRepresentation(execIndex, argListVariable, arguments)
)

dataProviderExceptions += collectedExceptions
}
}

parametersStatements.addEmptyLineIfNeeded()
parametersStatements += CgReturnStatement(argListVariable)
dataProviderStatements.addEmptyLineIfNeeded()
dataProviderStatements += CgReturnStatement(argListVariable)

return buildParameterizedTestDataProviderMethod {
name = dataProviderMethodName
returnType = argListClassId()
statements = parametersStatements
statements = dataProviderStatements
annotations = createDataProviderAnnotations(dataProviderMethodName)
exceptions = dataProviderExceptions
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import org.utbot.framework.codegen.model.visitor.importUtilMethodDependencies
import org.utbot.framework.plugin.api.MethodId
import org.utbot.framework.plugin.api.UtMethod
import org.utbot.framework.plugin.api.UtTestCase
import org.utbot.framework.util.description
import org.utbot.framework.plugin.api.util.description
import kotlin.reflect.KClass

internal class CgTestClassConstructor(val context: CgContext) :
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,10 @@ class CgParameterizedTestDataProviderBuilder : CgMethodBuilder<CgParameterizedTe
override val parameters: List<CgParameterDeclaration> = mutableListOf()
override lateinit var statements: List<CgStatement>
override lateinit var annotations: MutableList<CgAnnotation>
override val exceptions: MutableSet<ClassId> = mutableSetOf()
override lateinit var exceptions: MutableSet<ClassId>
override var documentation: CgDocumentationComment = CgDocumentationComment(emptyList())

override fun build() = CgParameterizedTestDataProviderMethod(name, statements, returnType, annotations)
override fun build() = CgParameterizedTestDataProviderMethod(name, statements, returnType, annotations, exceptions)
}

fun buildParameterizedTestDataProviderMethod(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,9 +223,8 @@ class CgParameterizedTestDataProviderMethod(
override val statements: List<CgStatement>,
override val returnType: ClassId,
override val annotations: List<CgAnnotation>,
override val exceptions: Set<ClassId>,
) : CgMethod(isStatic = true) {
override val exceptions: Set<ClassId> = emptySet()

override val parameters: List<CgParameterDeclaration> = emptyList()
override val documentation: CgDocumentationComment = CgDocumentationComment(emptyList())
override val requiredFields: List<CgParameterDeclaration> = emptyList()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,8 @@ internal class CgJavaRenderer(context: CgContext, printer: CgPrinter = CgPrinter
//we do not have a good string representation for two-dimensional array, so this strange if-else is required
val returnType =
if (element.returnType.simpleName == "Object[][]") "java.lang.Object[][]" else "${element.returnType}"
print("public static $returnType ${element.name}() throws Exception")
print("public static $returnType ${element.name}()")
renderExceptions(element)
}

override fun visit(element: CgInnerBlock) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -329,8 +329,7 @@ fun createInstance(language: CodegenLanguage): String =
when (language) {
CodegenLanguage.JAVA -> {
"""
private static Object createInstance(String className)
throws ClassNotFoundException, NoSuchMethodException, NoSuchFieldException, IllegalAccessException, InvocationTargetException {
private static Object createInstance(String className) throws Exception {
Class<?> clazz = Class.forName(className);
return Class.forName("sun.misc.Unsafe").getDeclaredMethod("allocateInstance", Class.class)
.invoke(getUnsafeInstance(), clazz);
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import org.utbot.framework.plugin.api.UtMethod
import org.utbot.framework.plugin.api.UtTestCase
import org.utbot.framework.plugin.api.util.UtContext
import org.utbot.framework.plugin.api.util.withUtContext
import org.utbot.framework.util.description
import org.utbot.framework.plugin.api.util.description
import kotlin.reflect.KClass
import mu.KotlinLogging
import org.junit.jupiter.api.Assertions.assertTrue
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import org.utbot.framework.plugin.api.UtImplicitlyThrownException
import org.utbot.framework.plugin.api.UtOverflowFailure
import org.utbot.framework.plugin.api.UtTestCase
import org.utbot.framework.plugin.api.UtTimeoutException
import org.utbot.framework.plugin.api.util.isCheckedException
import org.utbot.summary.UtSummarySettings.MIN_NUMBER_OF_EXECUTIONS_FOR_CLUSTERING
import org.utbot.summary.clustering.MatrixUniqueness
import org.utbot.summary.clustering.SplitSteps
Expand Down Expand Up @@ -146,8 +147,8 @@ enum class ClusterKind {

private fun UtExecutionResult.clusterKind() = when (this) {
is UtExecutionSuccess -> ClusterKind.SUCCESSFUL_EXECUTIONS
is UtImplicitlyThrownException -> if (this.isCheckedException) ClusterKind.CHECKED_EXCEPTIONS else ClusterKind.ERROR_SUITE
is UtExplicitlyThrownException -> if (this.isCheckedException) ClusterKind.CHECKED_EXCEPTIONS else ClusterKind.EXPLICITLY_THROWN_UNCHECKED_EXCEPTIONS
is UtImplicitlyThrownException -> if (this.exception.isCheckedException) ClusterKind.CHECKED_EXCEPTIONS else ClusterKind.ERROR_SUITE
is UtExplicitlyThrownException -> if (this.exception.isCheckedException) ClusterKind.CHECKED_EXCEPTIONS else ClusterKind.EXPLICITLY_THROWN_UNCHECKED_EXCEPTIONS
is UtOverflowFailure -> ClusterKind.OVERFLOWS
is UtTimeoutException -> ClusterKind.TIMEOUTS
is UtConcreteExecutionFailure -> ClusterKind.CRASH_SUITE
Expand Down