Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 88808fc

Browse files
UnitTestBot Go. Constants extraction (#1852)
* Do constants collecting * Add GoConstantValueProvider to use constants to generate test cases (only for ints now) * Use constants in fuzzing for all primitive types except complex numbers and bool. Fix float constants
1 parent a647725 commit 88808fc

File tree

14 files changed

+334
-79
lines changed

14 files changed

+334
-79
lines changed

‎utbot-go/src/main/kotlin/org/utbot/go/GoEngine.kt‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ val logger = KotlinLogging.logger {}
2525
class GoEngine(
2626
private val functionUnderTest: GoUtFunction,
2727
private val sourceFile: GoUtFile,
28+
private val intSize: Int,
2829
private val goExecutableAbsolutePath: String,
2930
private val eachExecutionTimeoutsMillisConfig: EachExecutionTimeoutsMillisConfig,
3031
private val timeoutExceededOrIsCanceled: () -> Boolean,
@@ -91,13 +92,14 @@ class GoEngine(
9192
val executionResult = convertRawExecutionResultToExecutionResult(
9293
rawExecutionResult,
9394
functionUnderTest.resultTypes,
95+
intSize,
9496
eachExecutionTimeoutsMillisConfig[functionUnderTest],
9597
)
9698
val fuzzedFunction = GoUtFuzzedFunction(functionUnderTest, emptyList())
9799
emit(fuzzedFunction to executionResult)
98100
} else {
99101
val aliases = imports.filter { it.alias != null }.associate { it.goPackage to it.alias }
100-
runGoFuzzing(functionUnderTest) { description, values ->
102+
runGoFuzzing(functionUnderTest, intSize) { description, values ->
101103
if (timeoutExceededOrIsCanceled()) {
102104
return@runGoFuzzing BaseFeedback(result = Trie.emptyNode(), control = Control.STOP)
103105
}
@@ -107,6 +109,7 @@ class GoEngine(
107109
val executionResult = convertRawExecutionResultToExecutionResult(
108110
rawExecutionResult,
109111
functionUnderTest.resultTypes,
112+
intSize,
110113
eachExecutionTimeoutsMillisConfig[functionUnderTest],
111114
)
112115
if (executionResult.trace.isEmpty()) {

‎utbot-go/src/main/kotlin/org/utbot/go/GoLanguage.kt‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ import org.utbot.go.api.GoUtFunction
66
import org.utbot.go.framework.api.go.GoTypeId
77
import org.utbot.go.framework.api.go.GoUtModel
88
import org.utbot.go.fuzzer.providers.GoArrayValueProvider
9+
import org.utbot.go.fuzzer.providers.GoConstantValueProvider
910
import org.utbot.go.fuzzer.providers.GoPrimitivesValueProvider
1011
import org.utbot.go.fuzzer.providers.GoStructValueProvider
1112

1213

1314
fun goDefaultValueProviders() = listOf(
14-
GoPrimitivesValueProvider, GoArrayValueProvider, GoStructValueProvider
15+
GoPrimitivesValueProvider, GoArrayValueProvider, GoStructValueProvider, GoConstantValueProvider
1516
)
1617

1718
class GoInstruction(
@@ -20,13 +21,15 @@ class GoInstruction(
2021

2122
class GoDescription(
2223
val methodUnderTest: GoUtFunction,
23-
val tracer: Trie<GoInstruction, *>
24+
val tracer: Trie<GoInstruction, *>,
25+
val intSize: Int
2426
) : Description<GoTypeId>(methodUnderTest.parameters.map { it.type }.toList())
2527

2628
suspend fun runGoFuzzing(
2729
methodUnderTest: GoUtFunction,
30+
intSize: Int,
2831
providers: List<ValueProvider<GoTypeId, GoUtModel, GoDescription>> = goDefaultValueProviders(),
2932
exec: suspend (description: GoDescription, values: List<GoUtModel>) -> BaseFeedback<Trie.Node<GoInstruction>, GoTypeId, GoUtModel>
3033
) {
31-
BaseFuzzing(providers, exec).fuzz(GoDescription(methodUnderTest, Trie(GoInstruction::lineNumber)))
34+
BaseFuzzing(providers, exec).fuzz(GoDescription(methodUnderTest, Trie(GoInstruction::lineNumber), intSize))
3235
}

‎utbot-go/src/main/kotlin/org/utbot/go/api/GoUtFunctionApi.kt‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ data class GoUtFunction(
2121
val parameters: List<GoUtFunctionParameter>,
2222
val resultTypes: List<GoTypeId>,
2323
val requiredImports: List<GoImport>,
24+
val constants: Map<GoTypeId, List<Any>>,
2425
val modifiedFunctionForCollectingTraces: String,
2526
val numberOfAllStatements: Int,
2627
val sourceFile: GoUtFile

‎utbot-go/src/main/kotlin/org/utbot/go/api/util/GoTypesApiUtil.kt‎

Lines changed: 56 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,20 @@ val goComplex64TypeId = GoPrimitiveTypeId("complex64")
1414
val goFloat32TypeId = GoPrimitiveTypeId("float32")
1515
val goFloat64TypeId = GoPrimitiveTypeId("float64")
1616

17-
val goIntTypeId = GoPrimitiveTypeId("int")
17+
val goInt8TypeId = GoPrimitiveTypeId("int8")
1818
val goInt16TypeId = GoPrimitiveTypeId("int16")
1919
val goInt32TypeId = GoPrimitiveTypeId("int32")
20+
val goIntTypeId = GoPrimitiveTypeId("int")
2021
val goInt64TypeId = GoPrimitiveTypeId("int64")
21-
val goInt8TypeId = GoPrimitiveTypeId("int8")
2222

2323
val goRuneTypeId = GoPrimitiveTypeId("rune") // = int32
2424
val goStringTypeId = GoPrimitiveTypeId("string")
2525

26-
val goUintTypeId = GoPrimitiveTypeId("uint")
26+
val goUint8TypeId = GoPrimitiveTypeId("uint8")
2727
val goUint16TypeId = GoPrimitiveTypeId("uint16")
2828
val goUint32TypeId = GoPrimitiveTypeId("uint32")
29+
val goUintTypeId = GoPrimitiveTypeId("uint")
2930
val goUint64TypeId = GoPrimitiveTypeId("uint64")
30-
val goUint8TypeId = GoPrimitiveTypeId("uint8")
3131
val goUintPtrTypeId = GoPrimitiveTypeId("uintptr")
3232

3333
val goPrimitives = setOf(
@@ -52,6 +52,25 @@ val goPrimitives = setOf(
5252
goUintPtrTypeId,
5353
)
5454

55+
val goSupportedConstantTypes = setOf(
56+
goByteTypeId,
57+
goFloat32TypeId,
58+
goFloat64TypeId,
59+
goIntTypeId,
60+
goInt8TypeId,
61+
goInt16TypeId,
62+
goInt32TypeId,
63+
goInt64TypeId,
64+
goRuneTypeId,
65+
goStringTypeId,
66+
goUintTypeId,
67+
goUint8TypeId,
68+
goUint16TypeId,
69+
goUint32TypeId,
70+
goUint64TypeId,
71+
goUintPtrTypeId,
72+
)
73+
5574
val GoTypeId.isPrimitiveGoType: Boolean
5675
get() = this in goPrimitives
5776

@@ -69,27 +88,40 @@ val GoPrimitiveTypeId.neverRequiresExplicitCast: Boolean
6988

7089
/**
7190
* This method is useful for converting the string representation of a Go value to its more accurate representation.
72-
* For example, to build more proper GoUtPrimitiveModel-s with GoFuzzedFunctionsExecutor.
73-
* Note, that for now such conversion is not required and is done for convenience only.
74-
*
75-
* About corresponding types: int and uint / uintptr types sizes in Go are platform dependent,
76-
* but are supposed to fit in Long and ULong respectively.
7791
*/
78-
val GoPrimitiveTypeId.correspondingKClass: KClass<out Any>
79-
get() = when (this) {
80-
goByteTypeId, goUint8TypeId -> UByte::class
81-
goBoolTypeId -> Boolean::class
82-
goFloat32TypeId -> Float::class
83-
goFloat64TypeId -> Double::class
84-
goInt16TypeId -> Short::class
85-
goInt32TypeId, goRuneTypeId -> Int::class
86-
goIntTypeId, goInt64TypeId -> Long::class
87-
goInt8TypeId -> Byte::class
88-
goStringTypeId -> String::class
89-
goUint32TypeId -> UInt::class
90-
goUint16TypeId -> UShort::class
91-
goUintTypeId, goUint64TypeId, goUintPtrTypeId -> ULong::class
92-
else -> String::class // default way to hold GoUtPrimitiveModel's value is to use String
92+
private fun GoPrimitiveTypeId.correspondingKClass(intSize: Int): KClass<out Any> = when (this) {
93+
goBoolTypeId -> Boolean::class
94+
goFloat32TypeId -> Float::class
95+
goFloat64TypeId -> Double::class
96+
goInt8TypeId -> Byte::class
97+
goInt16TypeId -> Short::class
98+
goInt32TypeId, goRuneTypeId -> Int::class
99+
goIntTypeId -> if (intSize == 32) Int::class else Long::class
100+
goInt64TypeId -> Long::class
101+
goStringTypeId -> String::class
102+
goUint8TypeId, goByteTypeId -> UByte::class
103+
goUint16TypeId -> UShort::class
104+
goUint32TypeId -> UInt::class
105+
goUintTypeId -> if (intSize == 32) UInt::class else ULong::class
106+
goUint64TypeId -> ULong::class
107+
goUintPtrTypeId -> if (intSize == 32) UInt::class else ULong::class
108+
else -> String::class // default way to hold GoUtPrimitiveModel's value is to use String
109+
}
110+
111+
fun rawValueOfGoPrimitiveTypeToValue(typeId: GoPrimitiveTypeId, rawValue: String, intSize: Int): Any =
112+
when (typeId.correspondingKClass(intSize)) {
113+
UByte::class -> rawValue.toUByte()
114+
Boolean::class -> rawValue.toBoolean()
115+
Float::class -> rawValue.toFloat()
116+
Double::class -> rawValue.toDouble()
117+
Int::class -> rawValue.toInt()
118+
Short::class -> rawValue.toShort()
119+
Long::class -> rawValue.toLong()
120+
Byte::class -> rawValue.toByte()
121+
UInt::class -> rawValue.toUInt()
122+
UShort::class -> rawValue.toUShort()
123+
ULong::class -> rawValue.toULong()
124+
else -> rawValue
93125
}
94126

95127
fun GoTypeId.goDefaultValueModel(): GoUtModel = when (this) {
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
package org.utbot.go.fuzzer.providers
2+
3+
import org.utbot.fuzzing.Seed
4+
import org.utbot.fuzzing.ValueProvider
5+
import org.utbot.fuzzing.seeds.BitVectorValue
6+
import org.utbot.fuzzing.seeds.IEEE754Value
7+
import org.utbot.fuzzing.seeds.StringValue
8+
import org.utbot.go.GoDescription
9+
import org.utbot.go.api.GoPrimitiveTypeId
10+
import org.utbot.go.api.GoUtPrimitiveModel
11+
import org.utbot.go.api.util.*
12+
import org.utbot.go.framework.api.go.GoTypeId
13+
import org.utbot.go.framework.api.go.GoUtModel
14+
15+
object GoConstantValueProvider : ValueProvider<GoTypeId, GoUtModel, GoDescription> {
16+
override fun accept(type: GoTypeId): Boolean = type in goSupportedConstantTypes
17+
18+
override fun generate(description: GoDescription, type: GoTypeId): Sequence<Seed<GoTypeId, GoUtModel>> = sequence {
19+
type.let { it as GoPrimitiveTypeId }.also { primitiveType ->
20+
val constants = description.methodUnderTest.constants
21+
val intSize = description.intSize
22+
val primitives: List<Seed<GoTypeId, GoUtModel>> = (constants[primitiveType] ?: emptyList()).mapNotNull {
23+
when (primitiveType) {
24+
goRuneTypeId, goIntTypeId, goInt8TypeId, goInt16TypeId, goInt32TypeId, goInt64TypeId ->
25+
when (primitiveType) {
26+
goInt8TypeId -> Seed.Known(BitVectorValue.fromValue(it)) { obj: BitVectorValue ->
27+
GoUtPrimitiveModel(
28+
obj.toByte(),
29+
primitiveType
30+
)
31+
}
32+
33+
goInt16TypeId -> Seed.Known(BitVectorValue.fromValue(it)) { obj: BitVectorValue ->
34+
GoUtPrimitiveModel(
35+
obj.toShort(),
36+
primitiveType
37+
)
38+
}
39+
40+
goInt32TypeId, goRuneTypeId -> Seed.Known(BitVectorValue.fromValue(it)) { obj: BitVectorValue ->
41+
GoUtPrimitiveModel(
42+
obj.toInt(),
43+
primitiveType
44+
)
45+
}
46+
47+
goIntTypeId -> Seed.Known(BitVectorValue.fromValue(it)) { obj: BitVectorValue ->
48+
GoUtPrimitiveModel(
49+
if (intSize == 32) obj.toInt() else obj.toLong(),
50+
primitiveType
51+
)
52+
}
53+
54+
goInt64TypeId -> Seed.Known(BitVectorValue.fromValue(it)) { obj: BitVectorValue ->
55+
GoUtPrimitiveModel(
56+
obj.toLong(),
57+
primitiveType
58+
)
59+
}
60+
61+
else -> return@sequence
62+
}
63+
64+
goByteTypeId, goUintTypeId, goUintPtrTypeId, goUint8TypeId, goUint16TypeId, goUint32TypeId, goUint64TypeId ->
65+
when (primitiveType) {
66+
goByteTypeId, goUint8TypeId -> {
67+
val uint8AsLong = (it as UByte).toLong()
68+
Seed.Known(BitVectorValue.fromValue(uint8AsLong)) { obj: BitVectorValue ->
69+
GoUtPrimitiveModel(
70+
obj.toUByte(),
71+
primitiveType
72+
)
73+
}
74+
}
75+
76+
goUint16TypeId -> {
77+
val uint16AsLong = (it as UShort).toLong()
78+
Seed.Known(BitVectorValue.fromValue(uint16AsLong)) { obj: BitVectorValue ->
79+
GoUtPrimitiveModel(
80+
obj.toUShort(),
81+
primitiveType
82+
)
83+
}
84+
}
85+
86+
goUint32TypeId -> {
87+
val uint32AsLong = (it as UInt).toLong()
88+
Seed.Known(BitVectorValue.fromValue(uint32AsLong)) { obj: BitVectorValue ->
89+
GoUtPrimitiveModel(
90+
obj.toUInt(),
91+
primitiveType
92+
)
93+
}
94+
}
95+
96+
goUintTypeId, goUintPtrTypeId -> {
97+
val uintAsLong = if (intSize == 32) (it as UInt).toLong() else (it as ULong).toLong()
98+
Seed.Known(BitVectorValue.fromValue(uintAsLong)) { obj: BitVectorValue ->
99+
GoUtPrimitiveModel(
100+
if (intSize == 32) obj.toUInt() else obj.toULong(),
101+
primitiveType
102+
)
103+
}
104+
}
105+
106+
goUint64TypeId -> {
107+
val uint64AsLong = (it as ULong).toLong()
108+
Seed.Known(BitVectorValue.fromValue(uint64AsLong)) { obj: BitVectorValue ->
109+
GoUtPrimitiveModel(
110+
obj.toULong(),
111+
primitiveType
112+
)
113+
}
114+
}
115+
116+
else -> return@sequence
117+
}
118+
119+
goFloat32TypeId -> Seed.Known(IEEE754Value.fromValue(it)) { obj: IEEE754Value ->
120+
GoUtPrimitiveModel(
121+
obj.toFloat(),
122+
primitiveType
123+
)
124+
}
125+
126+
goFloat64TypeId -> Seed.Known(IEEE754Value.fromValue(it)) { obj: IEEE754Value ->
127+
GoUtPrimitiveModel(
128+
obj.toDouble(),
129+
primitiveType
130+
)
131+
}
132+
133+
goStringTypeId -> Seed.Known(StringValue(it as String)) { obj: StringValue ->
134+
GoUtPrimitiveModel(
135+
obj.value,
136+
primitiveType
137+
)
138+
}
139+
140+
else -> null
141+
}
142+
}
143+
144+
primitives.forEach { seed ->
145+
yield(seed)
146+
}
147+
}
148+
}
149+
}

‎utbot-go/src/main/kotlin/org/utbot/go/fuzzer/providers/GoPrimitivesValueProvider.kt‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,15 @@ import org.utbot.go.api.util.*
1212
import org.utbot.go.framework.api.go.GoTypeId
1313
import org.utbot.go.framework.api.go.GoUtModel
1414
import java.util.*
15-
import kotlin.properties.Delegates
1615

1716
object GoPrimitivesValueProvider : ValueProvider<GoTypeId, GoUtModel, GoDescription> {
18-
var intSize by Delegates.notNull<Int>()
1917
private val random = Random(0)
2018

2119
override fun accept(type: GoTypeId): Boolean = type in goPrimitives
2220

2321
override fun generate(description: GoDescription, type: GoTypeId): Sequence<Seed<GoTypeId, GoUtModel>> =
2422
sequence {
23+
val intSize = description.intSize
2524
type.let { it as GoPrimitiveTypeId }.also { primitiveType ->
2625
val primitives: List<Seed<GoTypeId, GoUtModel>> = when (primitiveType) {
2726
goBoolTypeId -> listOf(
@@ -148,8 +147,8 @@ object GoPrimitivesValueProvider : ValueProvider<GoTypeId, GoUtModel, GoDescript
148147
else -> emptyList()
149148
}
150149

151-
primitives.forEach { fuzzedValue ->
152-
yield(fuzzedValue)
150+
primitives.forEach { seed ->
151+
yield(seed)
153152
}
154153
}
155154
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /