Skip to content

Commit a9e2fe8

Browse files
zishkazrudolf101
andauthored
Fix return of JavaScript std structures from functions under test (#2167)
* Fix JavaScript Map, Set and Array test generation + imports optimization * Better error handling in ValueUtil.kt * Fix arrays, maps and sets as function return types * Better error handling in ValueUtil.kt * Uncommented crucial code --------- Co-authored-by: Vladislav Kasimov <70969943+rudolf101@users.noreply.github.com>
1 parent d18b2ac commit a9e2fe8

22 files changed

+257
-90
lines changed

utbot-js/samples/arrays.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1+
///region Simple array test
12
function simpleArray(arr) {
23
if (arr[0] === 5) {
34
return 5
45
}
56
return 1
67
}
7-
88
simpleArray([0, 2])
9-
9+
///endregion
10+
///region Array of objects test
1011
class ObjectParameter {
1112

1213
constructor(a) {
@@ -27,4 +28,11 @@ function arrayOfObjects(arr) {
2728

2829
let arr = []
2930
arr[0] = new ObjectParameter(10)
30-
arrayOfObjects(arr)
31+
arrayOfObjects(arr)
32+
///endregion
33+
///region Function returns array test
34+
function returnsArray(num) {
35+
return [num]
36+
}
37+
returnsArray(5)
38+
///endregion

utbot-js/samples/mapStructure.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// Maps in JavaScript are untyped, so only maps with basic key/value types are feasible to support
2+
///region Simple Map test
23
function simpleMap(map, compareValue) {
34
if (map.get("a") === compareValue) {
45
return 5
@@ -8,4 +9,13 @@ function simpleMap(map, compareValue) {
89

910
const map1 = new Map()
1011
map1.set("b", 3.0)
11-
simpleMap(map1, 5)
12+
simpleMap(map1, 5)
13+
///endregion
14+
///region Function returns Map test
15+
function returnsMap(name, value) {
16+
let temp = new Map()
17+
return temp.set(name, value)
18+
}
19+
20+
returnsMap("a", 5)
21+
///endregion

utbot-js/samples/setStructure.js

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
11
// Sets in JavaScript are untyped, so only sets with basic value types are feasible to support
2+
///region Simple Set test
23
function setTest(set, checkValue) {
34
if (set.has(checkValue)) {
4-
return 5
5+
return set
56
}
6-
return 1
7+
return set
78
}
89

910
let s = new Set()
1011
s.add(5)
1112
s.add(6)
12-
setTest(s, 4)
13+
setTest(s, 4)
14+
///endregion
15+
///region Function returns Set test
16+
function returnsSet(num) {
17+
let temp = new Set()
18+
return temp.add(num)
19+
}
20+
21+
returnsSet(5)
22+
///endregion

utbot-js/src/main/kotlin/api/JsTestGenerator.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import fuzzer.JsStatement
1919
import fuzzer.JsTimeoutExecution
2020
import fuzzer.JsValidExecution
2121
import fuzzer.runFuzzing
22+
import java.io.File
23+
import java.util.concurrent.CancellationException
2224
import kotlinx.coroutines.flow.Flow
2325
import kotlinx.coroutines.flow.flow
2426
import mu.KotlinLogging
@@ -54,17 +56,15 @@ import service.TernService
5456
import service.coverage.CoverageMode
5557
import service.coverage.CoverageServiceProvider
5658
import settings.JsDynamicSettings
59+
import settings.JsExportsSettings.endComment
60+
import settings.JsExportsSettings.startComment
5761
import settings.JsTestGenerationSettings.fileUnderTestAliases
5862
import settings.JsTestGenerationSettings.fuzzingThreshold
5963
import settings.JsTestGenerationSettings.fuzzingTimeout
6064
import utils.PathResolver
6165
import utils.constructClass
6266
import utils.data.ResultData
6367
import utils.toJsAny
64-
import java.io.File
65-
import java.util.concurrent.CancellationException
66-
import settings.JsExportsSettings.endComment
67-
import settings.JsExportsSettings.startComment
6868

6969
private val logger = KotlinLogging.logger {}
7070

@@ -214,7 +214,7 @@ class JsTestGenerator(
214214
fuzzedValues: List<UtModel>
215215
): UtExecutionResult {
216216
if (resultData.isError && resultData.rawString == "Timeout") return UtTimeoutException(
217-
TimeoutException(" Timeout in generating test for ${
217+
TimeoutException("Timeout in generating test for ${
218218
execId.parameters
219219
.zip(fuzzedValues)
220220
.joinToString(

utbot-js/src/main/kotlin/api/JsUtModelConstructor.kt

Lines changed: 84 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,20 @@ package api
22

33
import framework.api.js.JsClassId
44
import framework.api.js.JsEmptyClassId
5+
import framework.api.js.JsMethodId
56
import framework.api.js.JsNullModel
67
import framework.api.js.JsPrimitiveModel
78
import framework.api.js.JsUndefinedModel
9+
import framework.api.js.util.defaultJsValueModel
10+
import framework.api.js.util.isJsArray
11+
import framework.api.js.util.isJsMap
12+
import framework.api.js.util.isJsSet
813
import framework.api.js.util.jsErrorClassId
914
import framework.api.js.util.jsUndefinedClassId
1015
import fuzzer.JsIdProvider
1116
import org.utbot.framework.plugin.api.ClassId
17+
import org.utbot.framework.plugin.api.ConstructorId
18+
import org.utbot.framework.plugin.api.UtArrayModel
1219
import org.utbot.framework.plugin.api.UtAssembleModel
1320
import org.utbot.framework.plugin.api.UtExecutableCallModel
1421
import org.utbot.framework.plugin.api.UtModel
@@ -20,10 +27,7 @@ class JsUtModelConstructor : UtModelConstructorInterface {
2027
@Suppress("NAME_SHADOWING")
2128
override fun construct(value: Any?, classId: ClassId): UtModel {
2229
val classId = classId as JsClassId
23-
when (classId) {
24-
jsUndefinedClassId -> return JsUndefinedModel(classId)
25-
jsErrorClassId -> return UtModel(jsErrorClassId)
26-
}
30+
if (classId == jsErrorClassId) return UtModel(jsErrorClassId)
2731
return when (value) {
2832
null -> JsNullModel(classId)
2933
is Byte,
@@ -35,7 +39,9 @@ class JsUtModelConstructor : UtModelConstructorInterface {
3539
is Double,
3640
is String,
3741
is Boolean -> JsPrimitiveModel(value)
38-
42+
is List<*> -> {
43+
constructStructure(classId, value)
44+
}
3945
is Map<*, *> -> {
4046
constructObject(classId, value)
4147
}
@@ -44,6 +50,79 @@ class JsUtModelConstructor : UtModelConstructorInterface {
4450
}
4551
}
4652

53+
private fun constructStructure(classId: JsClassId, values: List<Any?>): UtModel {
54+
return when {
55+
classId.isJsSet -> {
56+
UtAssembleModel(
57+
id = JsIdProvider.createId(),
58+
classId = classId,
59+
modelName = "",
60+
instantiationCall = UtExecutableCallModel(
61+
null,
62+
ConstructorId(classId, emptyList()),
63+
emptyList()
64+
),
65+
modificationsChainProvider = { mutableListOf() }
66+
).apply {
67+
this.modificationsChain as MutableList += values.map { value ->
68+
UtExecutableCallModel(
69+
this,
70+
JsMethodId(
71+
classId = classId,
72+
name = "add",
73+
returnTypeNotLazy = jsUndefinedClassId,
74+
parametersNotLazy = listOf(jsUndefinedClassId)
75+
),
76+
listOf(construct(value, jsUndefinedClassId))
77+
)
78+
}
79+
}
80+
}
81+
classId.isJsArray -> {
82+
UtArrayModel(
83+
id = JsIdProvider.createId(),
84+
classId = classId,
85+
stores = buildMap {
86+
putAll(values.indices.zip(values.map {
87+
construct(it, jsUndefinedClassId)
88+
}))
89+
} as MutableMap<Int, UtModel>,
90+
length = values.size,
91+
constModel = jsUndefinedClassId.defaultJsValueModel()
92+
)
93+
}
94+
classId.isJsMap -> {
95+
UtAssembleModel(
96+
id = JsIdProvider.createId(),
97+
classId = classId,
98+
modelName = "",
99+
instantiationCall = UtExecutableCallModel(
100+
null,
101+
ConstructorId(classId, emptyList()),
102+
emptyList()
103+
),
104+
modificationsChainProvider = { mutableListOf() }
105+
).apply {
106+
this.modificationsChain as MutableList += values.map { value ->
107+
UtExecutableCallModel(
108+
this,
109+
JsMethodId(
110+
classId = classId,
111+
name = "set",
112+
returnTypeNotLazy = jsUndefinedClassId,
113+
parametersNotLazy = listOf(jsUndefinedClassId, jsUndefinedClassId)
114+
),
115+
(value as Pair<Any?, Any?>).toList().map { construct(it, jsUndefinedClassId) }
116+
)
117+
}
118+
}
119+
}
120+
else -> throw UnsupportedOperationException(
121+
"Can't make UtModel from JavaScript structure with ${classId.name} type"
122+
)
123+
}
124+
}
125+
47126
@Suppress("UNCHECKED_CAST")
48127
private fun constructObject(classId: JsClassId, value: Any?): UtModel {
49128
val constructor = classId.allConstructors.first()

utbot-js/src/main/kotlin/framework/api/js/JsApi.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
package framework.api.js
22

33
import framework.api.js.util.toJsClassId
4+
import java.lang.reflect.Modifier
45
import org.utbot.framework.plugin.api.ClassId
56
import org.utbot.framework.plugin.api.ConstructorId
67
import org.utbot.framework.plugin.api.MethodId
78
import org.utbot.framework.plugin.api.UtModel
89
import org.utbot.framework.plugin.api.primitiveModelValueToClassId
9-
import java.lang.reflect.Modifier
1010

1111
open class JsClassId(
1212
private val jsName: String,

utbot-js/src/main/kotlin/framework/api/js/util/JsIdUtil.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,19 +44,19 @@ fun JsClassId.defaultJsValueModel(): UtModel = when (this) {
4444
}
4545

4646
val JsClassId.isJsBasic: Boolean
47-
get() = this in jsBasic || this is JsMultipleClassId
47+
get() = this in jsBasic || this.isJsStdStructure
4848

4949
val JsClassId.isExportable: Boolean
50-
get() = !(this.isJsBasic || this == jsErrorClassId || this.isJsStdStructure)
50+
get() = !(this.isJsBasic || this == jsErrorClassId || this is JsMultipleClassId)
5151

5252
val JsClassId.isClass: Boolean
53-
get() = !(this.isJsBasic || this == jsErrorClassId || this.isJsStdStructure)
53+
get() = !(this.isJsBasic || this == jsErrorClassId || this is JsMultipleClassId)
5454

5555
val JsClassId.isUndefined: Boolean
5656
get() = this == jsUndefinedClassId
5757

5858
val JsClassId.isJsArray: Boolean
59-
get() = this.name == "array" && this.elementClassId is JsClassId
59+
get() = this.name == "Array"
6060

6161
val JsClassId.isJsMap: Boolean
6262
get() = this.name == "Map"

utbot-js/src/main/kotlin/framework/codegen/JsDomain.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
package framework.codegen
22

3-
import org.utbot.framework.plugin.api.BuiltinClassId
4-
import org.utbot.framework.plugin.api.BuiltinMethodId
5-
import org.utbot.framework.plugin.api.ClassId
63
import framework.api.js.JsClassId
74
import framework.api.js.util.jsErrorClassId
85
import framework.api.js.util.jsUndefinedClassId
96
import org.utbot.framework.codegen.domain.Import
107
import org.utbot.framework.codegen.domain.TestFramework
8+
import org.utbot.framework.plugin.api.BuiltinClassId
9+
import org.utbot.framework.plugin.api.BuiltinMethodId
10+
import org.utbot.framework.plugin.api.ClassId
1111
import service.PackageJson
1212

1313

utbot-js/src/main/kotlin/framework/codegen/model/constructor/tree/JsCgMethodConstructor.kt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
package framework.codegen.model.constructor.tree
22

3+
import framework.api.js.JsClassId
4+
import org.utbot.framework.codegen.domain.context.CgContext
5+
import org.utbot.framework.codegen.domain.models.CgTestMethod
6+
import org.utbot.framework.codegen.domain.models.CgTestMethodType
7+
import org.utbot.framework.codegen.domain.models.CgValue
8+
import org.utbot.framework.codegen.domain.models.CgVariable
9+
import org.utbot.framework.codegen.tree.CgMethodConstructor
310
import org.utbot.framework.plugin.api.ConstructorId
411
import org.utbot.framework.plugin.api.ExecutableId
512
import org.utbot.framework.plugin.api.MethodId
613
import org.utbot.framework.plugin.api.UtExecution
7-
import framework.api.js.JsClassId
814
import org.utbot.framework.plugin.api.onFailure
915
import org.utbot.framework.plugin.api.onSuccess
1016
import org.utbot.framework.plugin.api.util.voidClassId
1117
import org.utbot.framework.util.isUnit
12-
import org.utbot.framework.codegen.domain.context.CgContext
13-
import org.utbot.framework.codegen.domain.models.CgTestMethod
14-
import org.utbot.framework.codegen.domain.models.CgTestMethodType
15-
import org.utbot.framework.codegen.domain.models.CgValue
16-
import org.utbot.framework.codegen.domain.models.CgVariable
17-
import org.utbot.framework.codegen.tree.CgMethodConstructor
1818

1919
class JsCgMethodConstructor(ctx: CgContext) : CgMethodConstructor(ctx) {
2020

utbot-js/src/main/kotlin/framework/codegen/model/constructor/tree/JsCgVariableConstructor.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ class JsCgVariableConstructor(ctx: CgContext) : CgVariableConstructor(ctx) {
106106
}
107107

108108
private fun constructArray(arrayModel: UtArrayModel, baseName: String?): CgVariable {
109-
val elementType = arrayModel.classId.elementClassId!! as JsClassId
109+
val elementType = (arrayModel.classId.elementClassId ?: jsUndefinedClassId) as JsClassId
110110
val elementModels = (0 until arrayModel.length).map {
111111
arrayModel.stores.getOrDefault(it, arrayModel.constModel)
112112
}

0 commit comments

Comments
 (0)