Skip to content

Commit fa774da

Browse files
committed
Improve default mock answers of unmockable types (arrays and sealed interfaces)
1 parent 6c224c5 commit fa774da

File tree

1 file changed

+18
-9
lines changed

1 file changed

+18
-9
lines changed

utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/constructors/InstrumentationContextAwareValueConstructor.kt

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ import org.utbot.instrumentation.instrumentation.execution.mock.InstanceMockCont
5151
import org.utbot.instrumentation.instrumentation.execution.mock.MethodMockController
5252
import org.utbot.instrumentation.instrumentation.execution.mock.MockController
5353
import org.utbot.instrumentation.process.runSandbox
54-
import java.lang.reflect.Method
5554
import java.lang.reflect.Modifier
5655
import java.security.AccessController
5756
import java.security.PrivilegedAction
@@ -130,6 +129,14 @@ class InstrumentationContextAwareValueConstructor(
130129
}
131130
}
132131

132+
/**
133+
* Use this method if you need to use [construct], while being in a sandbox.
134+
*
135+
* Permission elevation is required, because [construct] heavily uses reflection and Mockito.
136+
*/
137+
private fun constructPrivileged(model: UtModel): UtConcreteValue<*> =
138+
AccessController.doPrivileged(PrivilegedAction { construct(model) })
139+
133140
/**
134141
* Constructs an Enum<*> instance by model, uses reference-equality cache.
135142
*/
@@ -242,24 +249,26 @@ class InstrumentationContextAwareValueConstructor(
242249
with(invocation.method) {
243250
mockedExecutables.getOrPut(executableId) {
244251
detectedMockingCandidates.add(executableId)
245-
val answerModel = generateNewAnswerModel()
252+
var answerModel = generateNewAnswerModel(executableId)
253+
val answerValue = runCatching { constructPrivileged(answerModel) }.getOrElse {
254+
// fallback is used, so we still get some value (null) for types
255+
// that can't be mocked, e.g. arrays and sealed interfaces
256+
answerModel = executableId.returnType.defaultValueModel()
257+
constructPrivileged(answerModel)
258+
}
246259

247260
MockedExecutable(
248261
executableId = executableId,
249-
answerValues = listOf(
250-
// `construct()` heavily uses reflection and Mockito,
251-
// so it can't run in sandbox and we need to elevate permissions
252-
AccessController.doPrivileged(PrivilegedAction { construct(answerModel) })
253-
.value.takeUnless { it == Unit }
254-
),
262+
// `Unit` is replaced with `null`, because in Java `void` methods actually return `null`
263+
answerValues = listOf(answerValue.value.takeUnless { it == Unit }),
255264
answerModels = listOf(answerModel)
256265
)
257266
}.nextAnswer()
258267
}
259268
}
260269
}
261270

262-
private fun Method.generateNewAnswerModel() =
271+
private fun generateNewAnswerModel(executableId: ExecutableId) =
263272
executableId.returnType.defaultValueModel().takeUnless { it.isNull() } ?: when (executableId.returnType) {
264273
// mockito can't mock `String` and `Class`
265274
stringClassId -> UtNullModel(stringClassId)

0 commit comments

Comments
 (0)