Skip to content

Commit 821098a

Browse files
authored
Go. Fix tests generation for functions with infinity loop (#1911)
* fix GoFileCodeBuilder * Refactor Go code * Fix infinity loop * Fix
1 parent 9d2b31b commit 821098a

File tree

12 files changed

+259
-173
lines changed

12 files changed

+259
-173
lines changed

utbot-go/src/main/kotlin/org/utbot/go/gocodeanalyzer/AnalysisResults.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,4 @@ internal data class AnalysisResult(
115115
val notFoundFunctionsNames: List<String>
116116
)
117117

118-
internal data class AnalysisResults(val intSize: Int, val results: List<AnalysisResult>)
118+
internal data class AnalysisResults(val results: List<AnalysisResult>, val intSize: Int, val maxTraceLength: Int)

utbot-go/src/main/kotlin/org/utbot/go/gocodeanalyzer/GoSourceCodeAnalyzer.kt

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ object GoSourceCodeAnalyzer {
2323
val notFoundFunctionsNames: List<String>
2424
)
2525

26+
data class GoSourceCodeAnalyzerResult(
27+
val analysisResults: Map<GoUtFile, GoSourceFileAnalysisResult>,
28+
val intSize: Int,
29+
val maxTraceLength: Int,
30+
)
31+
2632
/**
2733
* Takes map from absolute paths of Go source files to names of their selected functions.
2834
*
@@ -31,7 +37,7 @@ object GoSourceCodeAnalyzer {
3137
fun analyzeGoSourceFilesForFunctions(
3238
targetFunctionsNamesBySourceFiles: Map<String, List<String>>,
3339
goExecutableAbsolutePath: String
34-
): Pair<Map<GoUtFile, GoSourceFileAnalysisResult>, Int> {
40+
): GoSourceCodeAnalyzerResult {
3541
val analysisTargets = AnalysisTargets(
3642
targetFunctionsNamesBySourceFiles.map { (absoluteFilePath, targetFunctionsNames) ->
3743
AnalysisTarget(absoluteFilePath, targetFunctionsNames)
@@ -67,7 +73,8 @@ object GoSourceCodeAnalyzer {
6773
)
6874
val analysisResults = parseFromJsonOrFail<AnalysisResults>(analysisResultsFile)
6975
val intSize = analysisResults.intSize
70-
return analysisResults.results.map { analysisResult ->
76+
val maxTraceLength = analysisResults.maxTraceLength
77+
return GoSourceCodeAnalyzerResult(analysisResults.results.map { analysisResult ->
7178
GoUtFile(analysisResult.absoluteFilePath, analysisResult.sourcePackage) to analysisResult
7279
}.associateBy({ (sourceFile, _) -> sourceFile }) { (sourceFile, analysisResult) ->
7380
val functions = analysisResult.analyzedFunctions.map { analyzedFunction ->
@@ -106,7 +113,7 @@ object GoSourceCodeAnalyzer {
106113
analysisResult.notSupportedFunctionsNames,
107114
analysisResult.notFoundFunctionsNames
108115
)
109-
} to intSize
116+
}, intSize, maxTraceLength)
110117
} finally {
111118
// TODO correctly?
112119
analysisTargetsFile.delete()

utbot-go/src/main/kotlin/org/utbot/go/logic/AbstractGoUtTestsGenerationController.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ abstract class AbstractGoUtTestsGenerationController {
1414
isCanceled: () -> Boolean = { false }
1515
) {
1616
if (!onSourceCodeAnalysisStart(selectedFunctionsNamesBySourceFiles)) return
17-
val (analysisResults, intSize) = GoSourceCodeAnalyzer.analyzeGoSourceFilesForFunctions(
17+
val (analysisResults, intSize, maxTraceLength) = GoSourceCodeAnalyzer.analyzeGoSourceFilesForFunctions(
1818
selectedFunctionsNamesBySourceFiles,
1919
testsGenerationConfig.goExecutableAbsolutePath
2020
)
@@ -32,6 +32,7 @@ abstract class AbstractGoUtTestsGenerationController {
3232
sourceFile,
3333
functions,
3434
intSize,
35+
maxTraceLength,
3536
testsGenerationConfig.goExecutableAbsolutePath,
3637
testsGenerationConfig.eachFunctionExecutionTimeoutMillis
3738
) { index -> isCanceled() || System.currentTimeMillis() - (startTimeMillis + (index + 1) * functionTimeoutStepMillis) > 0 }

utbot-go/src/main/kotlin/org/utbot/go/logic/GoTestCasesGenerator.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ object GoTestCasesGenerator {
2828
sourceFile: GoUtFile,
2929
functions: List<GoUtFunction>,
3030
intSize: Int,
31+
maxTraceLength: Int,
3132
goExecutableAbsolutePath: String,
3233
eachExecutionTimeoutMillis: Long,
3334
connectionTimeoutMillis: Long = 10000,
@@ -52,6 +53,7 @@ object GoTestCasesGenerator {
5253
functions,
5354
eachExecutionTimeoutMillis,
5455
serverSocket.localPort,
56+
maxTraceLength,
5557
imports
5658
)
5759
fileWithModifiedFunctions = GoWorkerCodeGenerationHelper.createFileWithModifiedFunctions(

utbot-go/src/main/kotlin/org/utbot/go/simplecodegeneration/GoFileCodeBuilder.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ class GoFileCodeBuilder(
2424
}
2525

2626
fun buildCodeString(): String {
27+
if (importLines.isEmpty()) {
28+
return "$packageLine\n\n${topLevelElements.joinToString(separator = "\n\n")}"
29+
}
2730
return "$packageLine\n\n$importLines\n\n${topLevelElements.joinToString(separator = "\n\n")}"
2831
}
2932

utbot-go/src/main/kotlin/org/utbot/go/simplecodegeneration/GoTestCasesCodeGenerator.kt

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,28 +18,29 @@ object GoTestCasesCodeGenerator {
1818

1919
fun generateTestCasesFileCode(sourceFile: GoUtFile, testCases: List<GoUtFuzzedFunctionTestCase>): String {
2020
val destinationPackage = sourceFile.sourcePackage
21-
if (testCases.isEmpty() || testCases.all { it.executionResult is GoUtTimeoutExceeded }) {
22-
return GoFileCodeBuilder(destinationPackage, emptySet()).buildCodeString()
23-
}
24-
val requiredPackages = mutableSetOf<GoPackage>()
25-
testCases.forEach { testCase ->
26-
testCase.parametersValues.forEach {
27-
requiredPackages += it.getRequiredPackages(destinationPackage)
28-
}
29-
when (val executionResult = testCase.executionResult) {
30-
is GoUtExecutionCompleted -> executionResult.models.forEach {
21+
val imports = if (testCases.isEmpty() || testCases.all { it.executionResult is GoUtTimeoutExceeded }) {
22+
emptySet()
23+
} else {
24+
val requiredPackages = mutableSetOf<GoPackage>()
25+
testCases.forEach { testCase ->
26+
testCase.parametersValues.forEach {
3127
requiredPackages += it.getRequiredPackages(destinationPackage)
3228
}
29+
when (val executionResult = testCase.executionResult) {
30+
is GoUtExecutionCompleted -> executionResult.models.forEach {
31+
requiredPackages += it.getRequiredPackages(destinationPackage)
32+
}
3333

34-
is GoUtPanicFailure -> requiredPackages += executionResult.panicValue.getRequiredPackages(
35-
destinationPackage
36-
)
34+
is GoUtPanicFailure -> requiredPackages += executionResult.panicValue.getRequiredPackages(
35+
destinationPackage
36+
)
37+
}
3738
}
38-
}
3939

40-
val imports = GoImportsResolver.resolveImportsBasedOnRequiredPackages(
41-
requiredPackages, destinationPackage, alwaysRequiredImports
42-
)
40+
GoImportsResolver.resolveImportsBasedOnRequiredPackages(
41+
requiredPackages, destinationPackage, alwaysRequiredImports
42+
)
43+
}
4344
val fileBuilder = GoFileCodeBuilder(destinationPackage, imports)
4445
val aliases = imports.associate { (goPackage, alias) -> goPackage to alias }
4546
val goUtModelToCodeConverter = GoUtModelToCodeConverter(destinationPackage, aliases)

utbot-go/src/main/kotlin/org/utbot/go/worker/GoCodeTemplates.kt

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,6 @@ import org.utbot.go.framework.api.go.GoPackage
55

66
object GoCodeTemplates {
77

8-
val traces = """
9-
var __traces__ []int
10-
""".trimIndent()
11-
128
private val testInputStruct = """
139
type __TestInput__ struct {
1410
FunctionName string `json:"functionName"`
@@ -354,7 +350,7 @@ object GoCodeTemplates {
354350
TimeoutExceeded bool `json:"timeoutExceeded"`
355351
RawResultValues []__RawValue__ `json:"rawResultValues"`
356352
PanicMessage *__RawPanicMessage__ `json:"panicMessage"`
357-
Trace []int `json:"trace"`
353+
Trace []uint16 `json:"trace"`
358354
}
359355
""".trimIndent()
360356

@@ -491,20 +487,24 @@ object GoCodeTemplates {
491487
}
492488
""".trimIndent()
493489

494-
private val executeFunctionFunction = """
490+
private fun executeFunctionFunction(maxTraceLength: Int) = """
495491
func __executeFunction__(
496-
timeoutMillis time.Duration, wrappedFunction func() []__RawValue__,
492+
timeout time.Duration, arguments []reflect.Value, wrappedFunction func([]reflect.Value) []__RawValue__,
497493
) __RawExecutionResult__ {
498-
ctxWithTimeout, cancel := context.WithTimeout(context.Background(), timeoutMillis)
494+
ctxWithTimeout, cancel := context.WithTimeout(context.Background(), timeout)
499495
defer cancel()
500496
497+
trace := make([]uint16, 0, $maxTraceLength)
498+
501499
done := make(chan __RawExecutionResult__, 1)
502500
go func() {
503501
executionResult := __RawExecutionResult__{
504502
TimeoutExceeded: false,
505503
RawResultValues: []__RawValue__{},
506504
PanicMessage: nil,
505+
Trace: []uint16{},
507506
}
507+
508508
panicked := true
509509
defer func() {
510510
panicMessage := recover()
@@ -526,11 +526,12 @@ object GoCodeTemplates {
526526
ImplementsError: implementsError,
527527
}
528528
}
529-
executionResult.Trace = __traces__
529+
executionResult.Trace = trace
530530
done <- executionResult
531531
}()
532532
533-
resultValues := wrappedFunction()
533+
argumentsWithTrace := append(arguments, reflect.ValueOf(&trace))
534+
resultValues := wrappedFunction(argumentsWithTrace)
534535
executionResult.RawResultValues = resultValues
535536
panicked = false
536537
}()
@@ -543,7 +544,7 @@ object GoCodeTemplates {
543544
TimeoutExceeded: true,
544545
RawResultValues: []__RawValue__{},
545546
PanicMessage: nil,
546-
Trace: __traces__,
547+
Trace: trace,
547548
}
548549
}
549550
}
@@ -603,9 +604,7 @@ object GoCodeTemplates {
603604

604605
private val convertParsedJsonToRawValueFunction = """
605606
//goland:noinspection GoPreferNilSlice
606-
func __convertParsedJsonToRawValue__(p map[string]interface{}) (__RawValue__, error) {
607-
rawValue := p
608-
607+
func __convertParsedJsonToRawValue__(rawValue map[string]interface{}) (__RawValue__, error) {
609608
typeName, ok := rawValue["type"]
610609
if !ok {
611610
return nil, fmt.Errorf("every rawValue must contain field 'type'")
@@ -769,7 +768,8 @@ object GoCodeTemplates {
769768
fun getTopLevelHelperStructsAndFunctionsForWorker(
770769
structTypes: Set<GoStructTypeId>,
771770
destinationPackage: GoPackage,
772-
aliases: Map<GoPackage, String?>
771+
aliases: Map<GoPackage, String?>,
772+
maxTraceLength: Int,
773773
) = listOf(
774774
testInputStruct,
775775
rawValueInterface,
@@ -788,7 +788,7 @@ object GoCodeTemplates {
788788
checkErrorFunction,
789789
convertFloat64ValueToStringFunction,
790790
convertReflectValueToRawValueFunction,
791-
executeFunctionFunction,
791+
executeFunctionFunction(maxTraceLength),
792792
wrapResultValuesForWorkerFunction,
793793
convertRawValuesToReflectValuesFunction,
794794
parseJsonToFunctionNameAndRawValuesFunction,

utbot-go/src/main/kotlin/org/utbot/go/worker/GoWorkerCodeGenerationHelper.kt

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,22 @@ internal object GoWorkerCodeGenerationHelper {
3434
functions: List<GoUtFunction>,
3535
eachExecutionTimeoutMillis: Long,
3636
port: Int,
37+
maxTraceLength: Int,
3738
imports: Set<GoImport>
3839
): File {
3940
val fileToExecuteName = createFileToExecuteName(sourceFile)
4041
val sourceFileDir = File(sourceFile.absoluteDirectoryPath)
4142
val fileToExecute = sourceFileDir.resolve(fileToExecuteName)
4243

4344
val fileToExecuteGoCode =
44-
generateWorkerTestFileGoCode(sourceFile, functions, eachExecutionTimeoutMillis, port, imports)
45+
generateWorkerTestFileGoCode(
46+
sourceFile,
47+
functions,
48+
eachExecutionTimeoutMillis,
49+
port,
50+
maxTraceLength,
51+
imports
52+
)
4553
fileToExecute.writeText(fileToExecuteGoCode)
4654
return fileToExecute
4755
}
@@ -72,6 +80,7 @@ internal object GoWorkerCodeGenerationHelper {
7280
functions: List<GoUtFunction>,
7381
eachExecutionTimeoutMillis: Long,
7482
port: Int,
83+
maxTraceLength: Int,
7584
imports: Set<GoImport>
7685
): String {
7786
val destinationPackage = sourceFile.sourcePackage
@@ -87,7 +96,8 @@ internal object GoWorkerCodeGenerationHelper {
8796
GoCodeTemplates.getTopLevelHelperStructsAndFunctionsForWorker(
8897
structTypes,
8998
destinationPackage,
90-
aliases
99+
aliases,
100+
maxTraceLength,
91101
) + workerTestFunctionCode
92102
)
93103

@@ -101,7 +111,7 @@ internal object GoWorkerCodeGenerationHelper {
101111
}
102112
val fileCodeBuilder = GoFileCodeBuilder(destinationPackage, imports)
103113
fileCodeBuilder.addTopLevelElements(
104-
listOf(GoCodeTemplates.traces) + functions.map { it.modifiedFunctionForCollectingTraces }
114+
functions.map { it.modifiedFunctionForCollectingTraces }
105115
)
106116
return fileCodeBuilder.buildCodeString()
107117
}
@@ -114,12 +124,12 @@ internal object GoWorkerCodeGenerationHelper {
114124
con, err := net.Dial("tcp", ":$port")
115125
__checkErrorAndExit__(err)
116126
117-
defer func(con net.Conn) {
127+
defer func() {
118128
err := con.Close()
119129
if err != nil {
120130
__checkErrorAndExit__(err)
121131
}
122-
}(con)
132+
}()
123133
124134
jsonDecoder := json.NewDecoder(con)
125135
for {
@@ -142,8 +152,7 @@ internal object GoWorkerCodeGenerationHelper {
142152
panic(fmt.Sprintf("no function with that name: %s", funcName))
143153
}
144154
145-
executionResult := __executeFunction__($eachExecutionTimeoutMillis*time.Millisecond, func() []__RawValue__ {
146-
__traces__ = make([]int, 0, 100)
155+
executionResult := __executeFunction__($eachExecutionTimeoutMillis*time.Millisecond, arguments, func(arguments []reflect.Value) []__RawValue__ {
147156
return __wrapResultValuesForUtBotGoWorker__(function.Call(arguments))
148157
})
149158

utbot-go/src/main/resources/go_source_code_analyzer/analysis_results.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ type AnalysisResult struct {
8888
}
8989

9090
type AnalysisResults struct {
91-
IntSize int `json:"intSize"`
92-
Results []AnalysisResult `json:"results"`
91+
Results []AnalysisResult `json:"results"`
92+
IntSize int `json:"intSize"`
93+
MaxTraceLength int `json:"maxTraceLength"`
9394
}

0 commit comments

Comments
 (0)