Skip to content

Commit edc482a

Browse files
sofurihafeVassiliy-Kudryashov
authored andcommitted
Minimize exceptions in signature (#418)
* Minimize exceptions in test methods signatures
1 parent fd9e7ec commit edc482a

File tree

14 files changed

+67
-40
lines changed

14 files changed

+67
-40
lines changed

utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/UtExecutionResult.kt

-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ data class UtExecutionSuccess(val model: UtModel) : UtExecutionResult() {
1111

1212
sealed class UtExecutionFailure : UtExecutionResult() {
1313
abstract val exception: Throwable
14-
val isCheckedException get() = !(exception is RuntimeException || exception is Error)
1514
}
1615

1716
data class UtOverflowFailure(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package org.utbot.framework.plugin.api.util
2+
3+
val Throwable.description
4+
get() = message?.replace('\n', '\t') ?: "<Throwable with empty message>"
5+
6+
val Throwable.isCheckedException
7+
get() = !(this is RuntimeException || this is Error)
8+
9+
val Class<*>.isCheckedException
10+
get() = !(RuntimeException::class.java.isAssignableFrom(this) || Error::class.java.isAssignableFrom(this))

utbot-framework/src/main/kotlin/org/utbot/engine/UtBotSymbolicEngine.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ import org.utbot.framework.plugin.api.util.id
154154
import org.utbot.framework.plugin.api.util.jClass
155155
import org.utbot.framework.plugin.api.util.signature
156156
import org.utbot.framework.plugin.api.util.utContext
157-
import org.utbot.framework.util.description
157+
import org.utbot.framework.plugin.api.util.description
158158
import org.utbot.framework.util.executableId
159159
import org.utbot.fuzzer.FuzzedMethodDescription
160160
import org.utbot.fuzzer.ModelProvider

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/context/CgContext.kt

+24-5
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ import org.utbot.framework.plugin.api.UtMethod
4646
import org.utbot.framework.plugin.api.UtModel
4747
import org.utbot.framework.plugin.api.UtReferenceModel
4848
import org.utbot.framework.plugin.api.UtTestCase
49-
import org.utbot.framework.plugin.api.util.executableId
5049
import java.util.IdentityHashMap
5150
import kotlinx.collections.immutable.PersistentList
5251
import kotlinx.collections.immutable.PersistentMap
@@ -55,6 +54,11 @@ import kotlinx.collections.immutable.persistentListOf
5554
import kotlinx.collections.immutable.persistentMapOf
5655
import kotlinx.collections.immutable.persistentSetOf
5756
import org.utbot.framework.codegen.model.constructor.builtin.streamsDeepEqualsMethodId
57+
import org.utbot.framework.plugin.api.util.executableId
58+
import org.utbot.framework.plugin.api.util.id
59+
import org.utbot.framework.plugin.api.util.isCheckedException
60+
import org.utbot.framework.plugin.api.util.isSubtypeOf
61+
import org.utbot.framework.plugin.api.util.jClass
5862

5963
/**
6064
* Interface for all code generation context aware entities
@@ -232,7 +236,22 @@ internal interface CgContextOwner {
232236
currentExecutable = method.callable.executableId
233237
}
234238

235-
fun addException(exception: ClassId) {
239+
fun addExceptionIfNeeded(exception: ClassId) {
240+
if (exception !is BuiltinClassId) {
241+
require(exception isSubtypeOf Throwable::class.id) {
242+
"Class $exception which is not a Throwable was passed"
243+
}
244+
245+
val isUnchecked = !exception.jClass.isCheckedException
246+
val alreadyAdded =
247+
collectedExceptions.any { existingException -> exception isSubtypeOf existingException }
248+
249+
if (isUnchecked || alreadyAdded) return
250+
251+
collectedExceptions
252+
.removeIf { existingException -> existingException isSubtypeOf exception }
253+
}
254+
236255
if (collectedExceptions.add(exception)) {
237256
importIfNeeded(exception)
238257
}
@@ -416,9 +435,9 @@ internal data class CgContext(
416435
val simpleName = testClassCustomName ?: "${createTestClassName(classUnderTest.name)}Test"
417436
val name = "$packagePrefix$simpleName"
418437
BuiltinClassId(
419-
name = name,
420-
canonicalName = name,
421-
simpleName = simpleName
438+
name = name,
439+
canonicalName = name,
440+
simpleName = simpleName
422441
)
423442
}
424443

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgCallableAccessManager.kt

+10-11
Original file line numberDiff line numberDiff line change
@@ -127,15 +127,12 @@ internal class CgCallableAccessManagerImpl(val context: CgContext) : CgCallableA
127127
//Builtin methods does not have jClass, so [methodId.method] will crash on it,
128128
//so we need to collect required exceptions manually from source codes
129129
if (methodId is BuiltinMethodId) {
130-
methodId.findExceptionTypes().forEach { addException(it) }
130+
methodId.findExceptionTypes().forEach { addExceptionIfNeeded(it) }
131131
return
132132
}
133-
//If [InvocationTargetException] is thrown manually in test, we need
134-
// to add "throws Throwable" and other exceptions are not required so on.
133+
135134
if (methodId == getTargetException) {
136-
collectedExceptions.clear()
137-
addException(Throwable::class.id)
138-
return
135+
addExceptionIfNeeded(Throwable::class.id)
139136
}
140137

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

151-
methodId.method.exceptionTypes.forEach { addException(it.id) }
148+
methodId.method.exceptionTypes.forEach { addExceptionIfNeeded(it.id) }
152149
}
153150

154151
private fun newConstructorCall(constructorId: ConstructorId) {
155152
importIfNeeded(constructorId.classId)
156153
for (exception in constructorId.exceptions) {
157-
addException(exception)
154+
addExceptionIfNeeded(exception)
158155
}
159156
}
160157

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

@@ -167,9 +166,9 @@ internal class CgCallableAccessManagerImpl(val context: CgContext) : CgCallableA
167166
getStaticFieldValueMethodId,
168167
getFieldValueMethodId,
169168
setStaticFieldMethodId,
170-
setFieldMethodId,
171-
createInstanceMethodId,
172-
getUnsafeInstanceMethodId -> setOf(Exception::class.id)
169+
setFieldMethodId -> setOf(IllegalAccessException::class.id, NoSuchFieldException::class.id)
170+
createInstanceMethodId -> setOf(Exception::class.id)
171+
getUnsafeInstanceMethodId -> setOf(ClassNotFoundException::class.id, NoSuchFieldException::class.id, IllegalAccessException::class.id)
173172
createArrayMethodId -> setOf(ClassNotFoundException::class.id)
174173
deepEqualsMethodId,
175174
arraysDeepEqualsMethodId,

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgMethodConstructor.kt

+11-7
Original file line numberDiff line numberDiff line change
@@ -1300,14 +1300,15 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c
13001300
utTestCase: UtTestCase,
13011301
dataProviderMethodName: String
13021302
): CgParameterizedTestDataProviderMethod {
1303-
val parametersStatements = mutableListOf<CgStatement>()
1303+
val dataProviderStatements = mutableListOf<CgStatement>()
1304+
val dataProviderExceptions = mutableSetOf<ClassId>()
13041305

13051306
val argListLength = utTestCase.executions.size
13061307
val argListDeclaration = createArgList(argListLength)
13071308
val argListVariable = argListDeclaration.variable
13081309

1309-
parametersStatements += argListDeclaration
1310-
parametersStatements += CgEmptyLine()
1310+
dataProviderStatements += argListDeclaration
1311+
dataProviderStatements += CgEmptyLine()
13111312

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

13491350
//create a block for current test case
1350-
parametersStatements += innerBlock(
1351+
dataProviderStatements += innerBlock(
13511352
{},
13521353
block(executionArgumentsBody)
13531354
+ createArgumentsCallRepresentation(execIndex, argListVariable, arguments)
13541355
)
1356+
1357+
dataProviderExceptions += collectedExceptions
13551358
}
13561359
}
13571360

1358-
parametersStatements.addEmptyLineIfNeeded()
1359-
parametersStatements += CgReturnStatement(argListVariable)
1361+
dataProviderStatements.addEmptyLineIfNeeded()
1362+
dataProviderStatements += CgReturnStatement(argListVariable)
13601363

13611364
return buildParameterizedTestDataProviderMethod {
13621365
name = dataProviderMethodName
13631366
returnType = argListClassId()
1364-
statements = parametersStatements
1367+
statements = dataProviderStatements
13651368
annotations = createDataProviderAnnotations(dataProviderMethodName)
1369+
exceptions = dataProviderExceptions
13661370
}
13671371
}
13681372

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgTestClassConstructor.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import org.utbot.framework.codegen.model.visitor.importUtilMethodDependencies
2626
import org.utbot.framework.plugin.api.MethodId
2727
import org.utbot.framework.plugin.api.UtMethod
2828
import org.utbot.framework.plugin.api.UtTestCase
29-
import org.utbot.framework.util.description
29+
import org.utbot.framework.plugin.api.util.description
3030
import kotlin.reflect.KClass
3131

3232
internal class CgTestClassConstructor(val context: CgContext) :

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/tree/Builders.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,10 @@ class CgParameterizedTestDataProviderBuilder : CgMethodBuilder<CgParameterizedTe
101101
override val parameters: List<CgParameterDeclaration> = mutableListOf()
102102
override lateinit var statements: List<CgStatement>
103103
override lateinit var annotations: MutableList<CgAnnotation>
104-
override val exceptions: MutableSet<ClassId> = mutableSetOf()
104+
override lateinit var exceptions: MutableSet<ClassId>
105105
override var documentation: CgDocumentationComment = CgDocumentationComment(emptyList())
106106

107-
override fun build() = CgParameterizedTestDataProviderMethod(name, statements, returnType, annotations)
107+
override fun build() = CgParameterizedTestDataProviderMethod(name, statements, returnType, annotations, exceptions)
108108
}
109109

110110
fun buildParameterizedTestDataProviderMethod(

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/tree/CgElement.kt

+1-2
Original file line numberDiff line numberDiff line change
@@ -223,9 +223,8 @@ class CgParameterizedTestDataProviderMethod(
223223
override val statements: List<CgStatement>,
224224
override val returnType: ClassId,
225225
override val annotations: List<CgAnnotation>,
226+
override val exceptions: Set<ClassId>,
226227
) : CgMethod(isStatic = true) {
227-
override val exceptions: Set<ClassId> = emptySet()
228-
229228
override val parameters: List<CgParameterDeclaration> = emptyList()
230229
override val documentation: CgDocumentationComment = CgDocumentationComment(emptyList())
231230
override val requiredFields: List<CgParameterDeclaration> = emptyList()

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/CgJavaRenderer.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,8 @@ internal class CgJavaRenderer(context: CgContext, printer: CgPrinter = CgPrinter
213213
//we do not have a good string representation for two-dimensional array, so this strange if-else is required
214214
val returnType =
215215
if (element.returnType.simpleName == "Object[][]") "java.lang.Object[][]" else "${element.returnType}"
216-
print("public static $returnType ${element.name}() throws Exception")
216+
print("public static $returnType ${element.name}()")
217+
renderExceptions(element)
217218
}
218219

219220
override fun visit(element: CgInnerBlock) {

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/visitor/UtilMethods.kt

+1-2
Original file line numberDiff line numberDiff line change
@@ -329,8 +329,7 @@ fun createInstance(language: CodegenLanguage): String =
329329
when (language) {
330330
CodegenLanguage.JAVA -> {
331331
"""
332-
private static Object createInstance(String className)
333-
throws ClassNotFoundException, NoSuchMethodException, NoSuchFieldException, IllegalAccessException, InvocationTargetException {
332+
private static Object createInstance(String className) throws Exception {
334333
Class<?> clazz = Class.forName(className);
335334
return Class.forName("sun.misc.Unsafe").getDeclaredMethod("allocateInstance", Class.class)
336335
.invoke(getUnsafeInstance(), clazz);

utbot-framework/src/main/kotlin/org/utbot/framework/util/ThrowableUtils.kt

-4
This file was deleted.

utbot-framework/src/test/kotlin/org/utbot/framework/codegen/BaseTestCodeGeneratorPipeline.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import org.utbot.framework.plugin.api.UtMethod
1616
import org.utbot.framework.plugin.api.UtTestCase
1717
import org.utbot.framework.plugin.api.util.UtContext
1818
import org.utbot.framework.plugin.api.util.withUtContext
19-
import org.utbot.framework.util.description
19+
import org.utbot.framework.plugin.api.util.description
2020
import kotlin.reflect.KClass
2121
import mu.KotlinLogging
2222
import org.junit.jupiter.api.Assertions.assertTrue

utbot-summary/src/main/kotlin/org/utbot/summary/TagGenerator.kt

+3-2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import org.utbot.framework.plugin.api.UtImplicitlyThrownException
1010
import org.utbot.framework.plugin.api.UtOverflowFailure
1111
import org.utbot.framework.plugin.api.UtTestCase
1212
import org.utbot.framework.plugin.api.UtTimeoutException
13+
import org.utbot.framework.plugin.api.util.isCheckedException
1314
import org.utbot.summary.UtSummarySettings.MIN_NUMBER_OF_EXECUTIONS_FOR_CLUSTERING
1415
import org.utbot.summary.clustering.MatrixUniqueness
1516
import org.utbot.summary.clustering.SplitSteps
@@ -146,8 +147,8 @@ enum class ClusterKind {
146147

147148
private fun UtExecutionResult.clusterKind() = when (this) {
148149
is UtExecutionSuccess -> ClusterKind.SUCCESSFUL_EXECUTIONS
149-
is UtImplicitlyThrownException -> if (this.isCheckedException) ClusterKind.CHECKED_EXCEPTIONS else ClusterKind.ERROR_SUITE
150-
is UtExplicitlyThrownException -> if (this.isCheckedException) ClusterKind.CHECKED_EXCEPTIONS else ClusterKind.EXPLICITLY_THROWN_UNCHECKED_EXCEPTIONS
150+
is UtImplicitlyThrownException -> if (this.exception.isCheckedException) ClusterKind.CHECKED_EXCEPTIONS else ClusterKind.ERROR_SUITE
151+
is UtExplicitlyThrownException -> if (this.exception.isCheckedException) ClusterKind.CHECKED_EXCEPTIONS else ClusterKind.EXPLICITLY_THROWN_UNCHECKED_EXCEPTIONS
151152
is UtOverflowFailure -> ClusterKind.OVERFLOWS
152153
is UtTimeoutException -> ClusterKind.TIMEOUTS
153154
is UtConcreteExecutionFailure -> ClusterKind.CRASH_SUITE

0 commit comments

Comments
 (0)