Skip to content

Go. Maps support #2114

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 6 commits into from
Apr 10, 2023
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
22 changes: 11 additions & 11 deletions utbot-go/go-samples/simple/samples_go_ut_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,39 +92,39 @@ func TestIsIdentityByUtGoFuzzer3(t *testing.T) {
}

func TestBinaryWithNonNilErrorByUtGoFuzzer1(t *testing.T) {
actualVal, actualErr := Binary([]int{1}, 2, 0, -1)
actualVal, actualErr := Binary(nil, 2, 0, -1)

assertMultiple := assert.New(t)
assertMultiple.Equal(-1, actualVal)
assertMultiple.ErrorContains(actualErr, "target not found in array")
}

func TestBinaryByUtGoFuzzer2(t *testing.T) {
actualVal, actualErr := Binary([]int{9223372036854775807, -1, -1, -1, -1}, 9223372036854775807, 0, 1)
func TestBinaryWithNonNilErrorByUtGoFuzzer2(t *testing.T) {
actualVal, actualErr := Binary([]int{1, 1, 0}, 2, 1, 1)

assertMultiple := assert.New(t)
assertMultiple.Equal(0, actualVal)
assertMultiple.Nil(actualErr)
assertMultiple.Equal(-1, actualVal)
assertMultiple.ErrorContains(actualErr, "target not found in array")
}

func TestBinaryWithNonNilErrorByUtGoFuzzer3(t *testing.T) {
actualVal, actualErr := Binary([]int{1, 17592186044417, 257, 1125899906842625}, -9223372036854775808, 1, 2)
actualVal, actualErr := Binary([]int{1, 1, 0}, -9214364837600034814, 1, 1)

assertMultiple := assert.New(t)
assertMultiple.Equal(-1, actualVal)
assertMultiple.ErrorContains(actualErr, "target not found in array")
}

func TestBinaryWithNonNilErrorByUtGoFuzzer4(t *testing.T) {
actualVal, actualErr := Binary([]int{-1, -1, -1, -1, 9223372036854775807}, 9223372036854775807, 0, 1)
actualVal, actualErr := Binary([]int{9223372036854775807, 9223372036854775807, 1, 9223372036854775807, -9223372036854775808}, 9223372036854775807, -1, 1)

assertMultiple := assert.New(t)
assertMultiple.Equal(-1, actualVal)
assertMultiple.ErrorContains(actualErr, "target not found in array")
assertMultiple.Equal(0, actualVal)
assertMultiple.Nil(actualErr)
}

func TestBinaryPanicsByUtGoFuzzer(t *testing.T) {
assert.PanicsWithError(t, "runtime error: index out of range [-4611686018427387905]", func() { Binary([]int{1}, 2, -9223372036854775808, -1) })
assert.PanicsWithError(t, "runtime error: index out of range [-4611686018427387905]", func() { Binary(nil, 2, -9223372036854775808, -1) })
}

func TestStringSearchByUtGoFuzzer1(t *testing.T) {
Expand Down Expand Up @@ -155,4 +155,4 @@ func TestStringSearchByUtGoFuzzer5(t *testing.T) {
actualVal := StringSearch("ABC")

assert.Equal(t, true, actualVal)
}
}
26 changes: 26 additions & 0 deletions utbot-go/go-samples/simple/supported_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,3 +262,29 @@ type S struct {
func StructWithFieldsOfNamedTypes(s S) S {
return s
}

func Map(table map[string]int) map[string]int {
return table
}

func MapOfStructures(table map[Structure]Structure) map[Structure]Structure {
return table
}

func MapOfSliceOfInt(table map[string][]int) map[string][]int {
return table
}

func MapOfNamedType(table map[int]Type) map[int]Type {
return table
}

func MapOfNamedSlice(table map[uint]NS) map[uint]NS {
return table
}

type NM map[string]NA

func NamedMap(n NM) NM {
return n
}
88 changes: 62 additions & 26 deletions utbot-go/go-samples/simple/supported_types_go_ut_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,27 +108,27 @@ func TestUintPtrByUtGoFuzzer(t *testing.T) {
}

func TestFloat32ByUtGoFuzzer(t *testing.T) {
actualVal := Float32(0.24053639)
actualVal := Float32(0.59754527)

assert.Equal(t, float32(0.24053639), actualVal)
assert.Equal(t, float32(0.59754527), actualVal)
}

func TestFloat64ByUtGoFuzzer(t *testing.T) {
actualVal := Float64(0.6063452159973596)
actualVal := Float64(0.7815346320453048)

assert.Equal(t, 0.6063452159973596, actualVal)
assert.Equal(t, 0.7815346320453048, actualVal)
}

func TestComplex64ByUtGoFuzzer(t *testing.T) {
actualVal := Complex64(complex(0.30905056, 0.30905056))
actualVal := Complex64(complex(0.25277615, 0.25277615))

assert.Equal(t, complex(float32(0.30905056), float32(0.30905056)), actualVal)
assert.Equal(t, complex(float32(0.25277615), float32(0.25277615)), actualVal)
}

func TestComplex128ByUtGoFuzzer(t *testing.T) {
actualVal := Complex128(complex(0.5504370051176339, 0.5504370051176339))
actualVal := Complex128(complex(0.3851891847407185, 0.3851891847407185))

assert.Equal(t, complex(0.5504370051176339, 0.5504370051176339), actualVal)
assert.Equal(t, complex(0.3851891847407185, 0.3851891847407185), actualVal)
}

func TestByteByUtGoFuzzer(t *testing.T) {
Expand Down Expand Up @@ -210,12 +210,12 @@ func TestArrayOfArrayOfStructsByUtGoFuzzer(t *testing.T) {
}

func TestArrayOfSliceOfUintByUtGoFuzzer(t *testing.T) {
actualVal := ArrayOfSliceOfUint([5][]uint{{}, {}, {}, {}, {}})
actualVal := ArrayOfSliceOfUint([5][]uint{nil, nil, nil, nil, nil})

assert.Equal(t, [5][]uint{{}, {}, {}, {}, {}}, actualVal)
assert.Equal(t, [5][]uint{nil, nil, nil, nil, nil}, actualVal)
}

func TestReturnErrorOrNilByUtGoFuzzer1(t *testing.T) {
func TestReturnErrorOrNilWithNonNilErrorByUtGoFuzzer1(t *testing.T) {
actualErr := returnErrorOrNil(0)

assert.Nil(t, actualErr)
Expand All @@ -240,21 +240,21 @@ func TestExternalStructWithAliasByUtGoFuzzer(t *testing.T) {
}

func TestSliceOfIntByUtGoFuzzer(t *testing.T) {
actualVal := SliceOfInt([]int{-1})
actualVal := SliceOfInt(nil)

assert.Equal(t, []int{-1}, actualVal)
assert.Nil(t, actualVal)
}

func TestSliceOfUintPtrByUtGoFuzzer(t *testing.T) {
actualVal := SliceOfUintPtr([]uintptr{0})
actualVal := SliceOfUintPtr(nil)

assert.Equal(t, []uintptr{0}, actualVal)
assert.Nil(t, actualVal)
}

func TestSliceOfStringByUtGoFuzzer(t *testing.T) {
actualVal := SliceOfString([]string{"hello"})
actualVal := SliceOfString(nil)

assert.Equal(t, []string{"hello"}, actualVal)
assert.Nil(t, actualVal)
}

func TestSliceOfStructsByUtGoFuzzer(t *testing.T) {
Expand All @@ -270,15 +270,15 @@ func TestSliceOfStructsWithNanByUtGoFuzzer(t *testing.T) {
}

func TestSliceOfSliceOfByteByUtGoFuzzer(t *testing.T) {
actualVal := SliceOfSliceOfByte([][]byte{{}})
actualVal := SliceOfSliceOfByte([][]byte{nil})

assert.Equal(t, [][]byte{{}}, actualVal)
assert.Equal(t, [][]byte{nil}, actualVal)
}

func TestSliceOfSliceOfStructsByUtGoFuzzer(t *testing.T) {
actualVal := SliceOfSliceOfStructs([][]Structure{{}})
actualVal := SliceOfSliceOfStructs([][]Structure{nil})

assert.Equal(t, [][]Structure{{}}, actualVal)
assert.Equal(t, [][]Structure{nil}, actualVal)
}

func TestSliceOfArrayOfIntByUtGoFuzzer(t *testing.T) {
Expand All @@ -294,7 +294,7 @@ func TestExportedStructWithEmbeddedUnexportedStructByUtGoFuzzer(t *testing.T) {
}

func TestNamedTypeByUtGoFuzzer(t *testing.T) {
actualVal := NamedType(Type(0))
actualVal := NamedType(0)

assert.Equal(t, Type(0), actualVal)
}
Expand Down Expand Up @@ -324,13 +324,49 @@ func TestNamedArrayByUtGoFuzzer(t *testing.T) {
}

func TestNamedSliceByUtGoFuzzer(t *testing.T) {
actualVal := NamedSlice(NS{-1, 9223372036854775807, 9223372036854775807, 1, 9223372036854775807})
actualVal := NamedSlice(NS(nil))

assert.Equal(t, NS{-1, 9223372036854775807, 9223372036854775807, 1, 9223372036854775807}, actualVal)
assert.Nil(t, actualVal)
}

func TestStructWithFieldsOfNamedTypesByUtGoFuzzer(t *testing.T) {
actualVal := StructWithFieldsOfNamedTypes(S{T: T{{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}}, NS: NS{9223372036854775807, 1, 0, -9223372036854775808, 9223372036854775807}})
actualVal := StructWithFieldsOfNamedTypes(S{T: T{{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}}, NS: NS(nil)})

assert.Equal(t, S{T: T{{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}}, NS: NS{9223372036854775807, 1, 0, -9223372036854775808, 9223372036854775807}}, actualVal)
assert.Equal(t, S{T: T{{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}}, NS: NS(nil)}, actualVal)
}

func TestMapByUtGoFuzzer(t *testing.T) {
actualVal := Map(nil)

assert.Nil(t, actualVal)
}

func TestMapOfStructuresByUtGoFuzzer(t *testing.T) {
actualVal := MapOfStructures(map[Structure]Structure{Structure{}: {}})

assert.Equal(t, map[Structure]Structure{Structure{}: {}}, actualVal)
}

func TestMapOfSliceOfIntByUtGoFuzzer(t *testing.T) {
actualVal := MapOfSliceOfInt(map[string][]int{"hello": {}})

assert.Equal(t, map[string][]int{"hello": {}}, actualVal)
}

func TestMapOfNamedTypeByUtGoFuzzer(t *testing.T) {
actualVal := MapOfNamedType(map[int]Type{-1: 255})

assert.Equal(t, map[int]Type{-1: 255}, actualVal)
}

func TestMapOfNamedSliceByUtGoFuzzer(t *testing.T) {
actualVal := MapOfNamedSlice(nil)

assert.Nil(t, actualVal)
}

func TestNamedMapByUtGoFuzzer(t *testing.T) {
actualVal := NamedMap(NM(nil))

assert.Nil(t, actualVal)
}
34 changes: 9 additions & 25 deletions utbot-go/src/main/kotlin/org/utbot/go/GoEngine.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,11 @@ import mu.KotlinLogging
import org.utbot.fuzzing.BaseFeedback
import org.utbot.fuzzing.Control
import org.utbot.fuzzing.utils.Trie
import org.utbot.go.api.GoUtExecutionResult
import org.utbot.go.api.GoUtFunction
import org.utbot.go.api.GoUtFuzzedFunction
import org.utbot.go.api.GoUtPanicFailure
import org.utbot.go.framework.api.go.GoPackage
import org.utbot.go.worker.GoWorker
import org.utbot.go.worker.convertRawExecutionResultToExecutionResult
import org.utbot.go.worker.RawExecutionResult

val logger = KotlinLogging.logger {}

Expand All @@ -21,24 +19,18 @@ class GoEngine(
private val functionUnderTest: GoUtFunction,
private val aliases: Map<GoPackage, String?>,
private val intSize: Int,
private val eachExecutionTimeoutMillis: Long,
private val timeoutExceededOrIsCanceled: () -> Boolean,
) {
var numberOfFunctionExecutions: Int = 0

fun fuzzing(): Flow<Pair<GoUtFuzzedFunction, GoUtExecutionResult>> = flow {
fun fuzzing(): Flow<Pair<GoUtFuzzedFunction, RawExecutionResult>> = flow {
var attempts = 0
val attemptsLimit = Int.MAX_VALUE
if (functionUnderTest.parameters.isEmpty()) {
worker.sendFuzzedParametersValues(functionUnderTest, emptyList(), emptyMap())
val rawExecutionResult = worker.receiveRawExecutionResult()
val executionResult = convertRawExecutionResultToExecutionResult(
rawExecutionResult,
functionUnderTest.resultTypes,
intSize,
eachExecutionTimeoutMillis,
)
val fuzzedFunction = GoUtFuzzedFunction(functionUnderTest, emptyList())
emit(fuzzedFunction to executionResult)
emit(fuzzedFunction to rawExecutionResult)
} else {
val notCoveredLines = (1..functionUnderTest.numberOfAllStatements).toMutableSet()
runGoFuzzing(functionUnderTest, intSize) { description, values ->
Expand All @@ -48,28 +40,20 @@ class GoEngine(
val fuzzedFunction = GoUtFuzzedFunction(functionUnderTest, values)
worker.sendFuzzedParametersValues(functionUnderTest, values, aliases)
val rawExecutionResult = worker.receiveRawExecutionResult()
val executionResult = convertRawExecutionResultToExecutionResult(
rawExecutionResult,
functionUnderTest.resultTypes,
intSize,
eachExecutionTimeoutMillis,
)
if (executionResult.trace.isEmpty()) {
numberOfFunctionExecutions++
if (rawExecutionResult.trace.isEmpty()) {
logger.error { "Coverage is empty for [${functionUnderTest.name}] with $values}" }
if (executionResult is GoUtPanicFailure) {
logger.error { "Execution completed with panic: ${executionResult.panicValue}" }
}
return@runGoFuzzing BaseFeedback(result = Trie.emptyNode(), control = Control.PASS)
}
val trieNode = description.tracer.add(executionResult.trace.map { GoInstruction(it) })
val trieNode = description.tracer.add(rawExecutionResult.trace.map { GoInstruction(it) })
if (trieNode.count > 1) {
if (++attempts >= attemptsLimit) {
return@runGoFuzzing BaseFeedback(result = Trie.emptyNode(), control = Control.STOP)
}
return@runGoFuzzing BaseFeedback(result = trieNode, control = Control.CONTINUE)
}
if (notCoveredLines.removeAll(executionResult.trace.toSet())) {
emit(fuzzedFunction to executionResult)
if (notCoveredLines.removeAll(rawExecutionResult.trace.toSet())) {
emit(fuzzedFunction to rawExecutionResult)
}
BaseFeedback(result = trieNode, control = Control.CONTINUE)
}
Expand Down
1 change: 1 addition & 0 deletions utbot-go/src/main/kotlin/org/utbot/go/GoLanguage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ fun goDefaultValueProviders() = listOf(
GoPrimitivesValueProvider,
GoArrayValueProvider,
GoSliceValueProvider,
GoMapValueProvider,
GoStructValueProvider,
GoConstantValueProvider,
GoNamedValueProvider,
Expand Down
21 changes: 21 additions & 0 deletions utbot-go/src/main/kotlin/org/utbot/go/api/GoTypesApi.kt
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,27 @@ class GoSliceTypeId(
override fun hashCode(): Int = elementTypeId.hashCode()
}

class GoMapTypeId(
name: String, val keyTypeId: GoTypeId, elementTypeId: GoTypeId,
) : GoTypeId(name, elementTypeId = elementTypeId) {
override val canonicalName: String = "map[${keyTypeId.canonicalName}]${elementTypeId.canonicalName}"

override fun getRelativeName(destinationPackage: GoPackage, aliases: Map<GoPackage, String?>): String {
val keyType = keyTypeId.getRelativeName(destinationPackage, aliases)
val elementType = elementTypeId!!.getRelativeName(destinationPackage, aliases)
return "map[$keyType]$elementType"
}

override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is GoMapTypeId) return false

return keyTypeId == other.keyTypeId && elementTypeId == other.elementTypeId
}

override fun hashCode(): Int = 31 * keyTypeId.hashCode() + elementTypeId.hashCode()
}

class GoInterfaceTypeId(name: String) : GoTypeId(name) {
override val canonicalName: String = name

Expand Down
Loading